GemStone.saveScript('scripts/CodeBrowser.js', function() { var $tabPanel , editor , classCategories = [''] , isDictsTab = true , dictionary , mcPackage , classCategory , klass , isMetaClass = false , superClass , methodFilterBy = 'category' , methodFilter , selector , implementor , isCtrlKeyDown = false ; GemStone.loadCSS('css/CodeBrowser.css'); GemStone.runJsOnce('jsTree/jquery.jstree.js', function() { $.jstree._themes = 'jsTree/themes/'; GemStone.addTab({ id: 'newTab' , label: 'Code Browser' , title: 'Browse Smalltalk classes' , onAdd: onAdd }); }); return; function onAdd(tabPanel) { $tabPanel = tabPanel; $('.divList').keydown(keydown); doLayout(); update(); } // keypress does not capture arrow keys (and other browser overrides) so we use keydown event function keydown(event) { if (event.ctrlKey || event.shiftKey) { return; } if (event.which === 38 || event.which === 40) { upDownKey(event); } return; } function upDownKey(event) { var element = $('.divList:focus')[0]; if (element) { element = $('.selected', element); element = event.which === 38 ? element.prev() : element.next(); if (element) { element.click(); event.preventDefault(); } } return; } function doLayout() { createDictionaryPackageTabs(); createClassesTabs(); createCategoriesVariablesTabs(); createInstanceClassTabs(); fixupTabsCornerStyling(); setupEditor(); return; function prepareTabs($div, onSelect) { var $divList = $('div', $div); $.each($('ul li', $div), function(index) { var id = GemStone.nextId(); $('a', this).attr('href', '#' + id); $($divList[index]).attr('id', id); }); $div.tabs({ select: onSelect }); } function createDictionaryPackageTabs() { prepareTabs( $('.dictPckgTabs', $tabPanel), function(event, ui) { if (setIsDictsTab(0 === ui.index)) { update(); } } ); } function createClassesTabs() { prepareTabs( $('.classesTab', $tabPanel), function(event, ui) { } ); } function createCategoriesVariablesTabs() { prepareTabs( $('.catsVariablesTabs', $tabPanel), function(event, ui) { var filterBy = ['category', 'variable'][ui.index]; if (setMethodFilterBy(filterBy)) { update(); } } ); } function createInstanceClassTabs() { prepareTabs( $('.instanceClassTabs', $tabPanel), function(event, ui) { if (setIsMetaClass(1 === ui.index)) { update(); } } ); } function fixupTabsCornerStyling() { $('.ui-tabs-nav, .ui-tabs-nav > *, .tabs-empty', $tabPanel) .removeClass('ui-corner-all ui-corner-bottom') .addClass('ui-corner-top'); $('.tabs-bottom, .tabs-bottom .ui-tabs-nav, .tabs-bottom .ui-tabs-nav > *', $tabPanel) .removeClass('ui-corner-all ui-corner-top') .addClass('ui-corner-bottom'); } function setupEditor() { GemStone.runJs( 'scripts/editor.js' , { editArea: $('.editArea', $tabPanel) } , function(object) { editor = object; } ); } } function update() { var myRequest = { isDictsTab : isDictsTab , dict : dictionary , mcPackage : mcPackage , classCat : classCategory , klass : klass , isMeta : isMetaClass , superClass : superClass , methodFilterBy : methodFilterBy , methodFilter : methodFilter , selector : selector , implementor : implementor }; // console.trace(); // console.log(myRequest); GemStone.ajax('GET','CodeBrowser', myRequest, gotData); } function gotData(data) { // console.log(data); setMethodFilterListPosition(); fillDictList(); fillPackageList(); fillClassCatTree(); fillClassList(); fillSuperList(); fillMethodFilterList(); fillMethodList(); fillImplementorList(); fillEditArea(); return; function setMethodFilterListPosition() { $('.methodFilterList', $tabPanel) .css('top', $('.catsVariablesTabs', $tabPanel).outerHeight() - 1 + 'px') .css('bottom', $('.instanceClassTabs', $tabPanel).height() + 1 + 'px') ; } function fillDictList() { var items = [] , foundSelection = false; $.each(data.dictList, function(index, value){ items.push('<div title="' + value + '"'); items.push(' class="clickable'); if (value === dictionary) { items.push(' selected'); foundSelection = true; } items.push('">' + value + '</div>'); }); $('.dictList', $tabPanel).empty().append(items.join('')); $('.dictList .clickable', $tabPanel).click(function(event){ if (setDictionary($(this).text())) { update(); } }); GemStone.menu({ selector: $('.dictList .clickable', $tabPanel) , menu: dictionaryListMenu }); if (!foundSelection) { dictionary = null; } } function dictionaryListMenu(element) { return [ { title: 'Menu 1' , action: function() { console.log(['menu1', element]); } } , { title: 'Menu 2' , action: function() { console.log(['menu2', element]); } } ]; } function fillPackageList() { var items = [] , foundSelection = false; $.each(data.packageList, function(index, value){ items.push('<div title="' + value + '"'); items.push(' class="clickable'); if (value === mcPackage) { items.push(' selected'); foundSelection = true; } items.push('">' + value + '</div>'); }); $('.pckgList', $tabPanel).empty().append(items.join('')); $('.pckgList .clickable', $tabPanel).click(function(event){ if (setPackage($(this).text())) { update(); } }); if (!foundSelection) { mcPackage = null; } } function fillClassCatTree() { if (!dictionary) { return } var openNodes = $('.classCats', $tabPanel) .find('li') .map(function(index, element) { return element.id; }) .filter(function() { return $('.classCats', $tabPanel).jstree('is_open', '#' + this); }) , root = { data: 'Categories' , attr: { id: idOfClassCat(null), title: '' } , children: [ ] } ; $.each(data.classCatList, function(i, each) { addCategoryToNode(each, root, null); }); if (!idOfClassCat(classCategory)) { classCategory = null; } if ( root.children.length ) { root.state = 'open'; } $('.classCats', $tabPanel) .jstree({ plugins: [ 'themes', 'json_data', 'ui' ] , themes: { icons: false } , json_data: { data: [ root ] } , ui: { select_limit: 1 , initially_select: [ idOfClassCat(classCategory) ] } }) .bind('select_node.jstree', function(event, data) { var path = $('.classCats', $tabPanel).jstree('get_selected').attr('title'); if (setClassCat(path)) { update(); } }); return; function addCategoryToNode(category, node, parentPath) { var index = category.indexOf('-') , first = category.substring(0, 0 <= index ? index : category.length) , rest = 0 <= index ? category.substring(index + 1) : null , children = node.children , myPath = (parentPath ? parentPath + '-' : '') + first , child ; $.each(children, function(index, each) { if (first === each.data) { child = each; } }); if ( !child ) { var id = idOfClassCat(myPath) , isOpen = false ; $.each(openNodes, function(index, value) { if (value === id) { isOpen = true; } }); child = { data: first , attr: { id: id, title: myPath } , state: (isOpen ? 'open' : null) , children: [ ] }; children.push(child); } if (rest) { addCategoryToNode(rest, child, myPath); } } } function fillClassList() { var items = [] , foundSelection = false ; $.each(data.classList, function(index, value){ items.push('<div title="' + value + '"'); items.push(' class="clickable'); if (klass === value) { foundSelection = true; items.push(' selected'); } items.push('">' + value + '</div>'); }); if (!foundSelection) { klass = null; } $('.classList', $tabPanel).empty().append(items.join('')); $('.classList .clickable', $tabPanel).click(function(){ if (setKlass($(this).text())) { update(); } }); GemStone.menu({ selector: $('.classList .clickable', $tabPanel) , menu: classListMenu }); return; } function classListMenu(element) { var klass = $(element).text(); return [ { title: 'Browse References' , action: function() { GemStone.browseReferencesTo(dictionary, klass); } } , { title: 'File Out Class' , action: function() { alert('Coming soon!'); } } , { title: 'Subclass Creation Template' , action: function() { alert('Coming soon!'); } } , { title: 'Add Missing Accessors' , action: function() { alert('Coming soon!'); } } , { title: 'Remove' , action: function() { if (confirm('Do you want to remove ' + klass + ' from ' + dictionary + '?')) { removeClass(dictionary, klass); } } } , { title: 'Remove Prior Versions' , action: function() { alert('Coming soon!'); } } ]; } function removeClass(aDictName, aKlassName) { var myRequest = { dict: aDictName , klass: aKlassName }; GemStone.ajax('POST','CodeBrowser/removeClass', myRequest, onRemoveClass); return; function onRemoveClass(data) { if (data.error) { alert(data.error); } else { setKlass(); update(); } } } function fillSuperList() { var foundSelection = false; $('.superList', $tabPanel).empty(); var items = []; if (!superClass) { superClass = isMetaClass ? klass + ' class' : klass; } $.each(data.superList, function(index, value){ items.push('<option value="' + value + '"'); items.push(' title="' + value + '"'); if (superClass === value) { foundSelection = true; items.push(' selected'); } items.push('>' + value + '</div>'); }); if ( !foundSelection ) { superClass = null; } $('.superList', $tabPanel).append(items.join('')); $('.superList').change(function(){ if(setSuperClass($(this).val())) { update(); } }); } function fillMethodFilterList() { var foundSelection = false; $('.methodFilterList', $tabPanel).empty(); $.each(data.methodFilterList, function(index,value){ if (methodFilter === value) { foundSelection = true; } }); if ( !foundSelection ) { methodFilter = null; } if ( 0 === data.methodFilterList.length ) { return; } var items = []; items.push('<div title="" class="clickable'); if (!foundSelection) { items.push(' selected'); } items.push('">* * ALL * *</div>'); $.each(data.methodFilterList, function(index,value){ items.push('<div title="' + value + '"'); items.push(' class="clickable'); if (value === methodFilter) { items.push(' selected'); } items.push('">' + value + '</div>'); }); $('.methodFilterList', $tabPanel).append(items.join('')); $('.methodFilterList .clickable', $tabPanel).click(function(){ if (setMethodFilter($(this).text())) { update(); } }); } function fillMethodList() { var foundSelection = false; $('.methodList', $tabPanel).empty(); var items = []; $.each(data.methodList, function(index, value){ items.push('<div'); items.push(' title="' + value + '"'); items.push(' class="clickable'); if (selector === value) { foundSelection = true; items.push(' selected'); } items.push('">' + value + '</div>'); }); if (!foundSelection) { selector = null; } $('.methodList', $tabPanel).append(items.join('')); $('.methodList .clickable', $tabPanel).click(function(){ if (setSelector($(this).text())) { update(); } }); GemStone.menu({ selector: $('.methodList .clickable', $tabPanel) , menu: methodListMenu }); return; } function methodListMenu(element) { var name = $(element).text(); return [ { title: 'Remove Method' , action: function() { if (confirm('Do you want to remove #\'' + name + '\' from ' + klass + (isMetaClass ? ' class' : '') + ' in ' + dictionary + '?')) { removeMethod(dictionary, klass, isMetaClass, name); } } } , { title: 'Browse Implementors' , action: function() { GemStone.browseImplementorsOf(name); } } , { title: 'Browse Implementors of ...' , action: function() { GemStone.browseImplementorsOf(); } } , { title: 'Browse Senders' , action: function() { GemStone.browseSendersOf(name); } } , { title: 'Browse Senders of ...' , action: function() { GemStone.browseSendersOf(); } } ]; function removeMethod(dictName, klassName, isMetaBool, methodName) { var myRequest = { dict: dictName , klass: klassName , isMeta: isMetaBool , name: methodName }; GemStone.ajax('POST','CodeBrowser/removeMethod', myRequest, onRemoveMethod); return; function onRemoveMethod(data) { if (data.error) { alert(data.error); } else { setSelector(); update(); } } console.log([dictName, klassName, isMetaBool, methodName]); } } function fillImplementorList() { var foundSelection = false; $.each(data.implList, function(index,value){ if (implementor === value) { foundSelection = true; } }); if ( !foundSelection ) { implementor = data.implList[data.implList.length - 1]; } $('.implList', $tabPanel).empty(); var items = []; $.each(data.implList, function(index, value){ items.push('<option value="' + value + '"'); items.push(' title="' + value + '"'); if (implementor === value) { items.push(' selected'); } items.push('>' + value + '</div>'); }); $('.implList', $tabPanel).append(items.join('')); $('.implList').change(function(){ if(setImplementor($(this).val())) { update(); } }); } function fillEditArea() { if (!editor) { return; } if (data.method) { editor.setMethod(data.method, onSaveMethod); } else { editor.setCode(data.classDef, onSaveClass); } } } function onSaveClass(data) { setIsDictsTab(true); setDictionary(data.dict); if (!classCategory && classCategory !== data.cat) { setClassCat(''); } setKlass(data.name); update(); } function onSaveMethod(data) { if (setSelector(data)) { update(); } } function isOkayToChange() { return editor ? editor.isOkayToChange() : true; } function idOfClassCat(aString) { if (!aString) { return 'classCat-0'; } var index = classCategories.indexOf(aString); if (-1 === index) { classCategories.push(aString); index = classCategories.length - 1; } return 'classCat-' + index; } function setIsDictsTab(value) { if (isDictsTab === value) { return false; } isDictsTab = value; setDictionary(null); setPackage(null); return true; } function setDictionary(value) { if (dictionary === value) { return false; } if (!isOkayToChange()) { return false; } dictionary = value; setPackage(null); setClassCat(null); return true; } function setPackage(value) { if (mcPackage === value) { return false; } if (!isOkayToChange()) { return false; } mcPackage = value; setDictionary(null); setClassCat(null); return true; } function setClassCat(value) { if (value === '') { return setClassCat(null); } if (classCategory === value) { return false; } if (!isOkayToChange()) { return false; } classCategory = value; setKlass(null); return true; } function setKlass(value) { if (klass === value) { return false; } if (!isOkayToChange()) { return false; } klass = value; setSuperClass(null); setMethodFilter(null); setSelector(null); return true; } function setIsMetaClass(value) { if (isMetaClass === value) { return false; } if (!isOkayToChange()) { return false; } isMetaClass = value; setSuperClass(null); setMethodFilter(null); return true; } function setSuperClass(value) { if (superClass === value) { return false; } if (!isOkayToChange()) { return false; } superClass = value; return true; } function setMethodFilterBy(value) { if (methodFilterBy === value) { return false; } if (!isOkayToChange()) { return false; } methodFilterBy = value; setMethodFilter(null); return true; } function setMethodFilter(value) { if (methodFilter === value) { return false; } if (!isOkayToChange()) { return false; } methodFilter = value; setSelector(null); return true; } function setSelector(value) { if (selector === value) { return false; } if (!isOkayToChange()) { return false; } selector = value; return true; } function setImplementor(value) { if (implementor === value) { return false; } if (!isOkayToChange()) { return false; } implementor = value; return true; } });