From f05b9fdab7469978c98a54dce9fb73b50021a1f4 Mon Sep 17 00:00:00 2001 From: phasefx Date: Tue, 5 Oct 2010 20:13:01 +0000 Subject: [PATCH] patch from tsbere to improve tab behavior and to give command-line options for controlling tabs See https://bugs.launchpad.net/evergreen/+bug/625056 git-svn-id: svn://svn.open-ils.org/ILS/trunk@18183 dcc99617-32d9-48b4-a31d-7c20da2025e4 --- .../staff_client/chrome/content/circ/offline.xul | 1 + .../xul/staff_client/chrome/content/main/main.js | 129 ++++++- .../xul/staff_client/chrome/content/main/menu.js | 413 ++++++++------------- .../chrome/content/main/menu_frame.xul | 2 + .../chrome/content/main/menu_frame_menus.xul | 4 - .../chrome/content/main/menu_frame_overlay.xul | 29 +- .../chrome/locale/en-US/offline.properties | 10 + Open-ILS/xul/staff_client/components/clh.js | 221 +++++++++++ Open-ILS/xul/staff_client/server/main/data.xul | 18 +- 9 files changed, 516 insertions(+), 311 deletions(-) create mode 100644 Open-ILS/xul/staff_client/components/clh.js diff --git a/Open-ILS/xul/staff_client/chrome/content/circ/offline.xul b/Open-ILS/xul/staff_client/chrome/content/circ/offline.xul index 294b7c508..4b94d7a86 100644 --- a/Open-ILS/xul/staff_client/chrome/content/circ/offline.xul +++ b/Open-ILS/xul/staff_client/chrome/content/circ/offline.xul @@ -17,6 +17,7 @@ diff --git a/Open-ILS/xul/staff_client/chrome/content/main/main.js b/Open-ILS/xul/staff_client/chrome/content/main/main.js index 2a42d3fb6..7abcd42d2 100644 --- a/Open-ILS/xul/staff_client/chrome/content/main/main.js +++ b/Open-ILS/xul/staff_client/chrome/content/main/main.js @@ -4,6 +4,9 @@ dump('entering main/main.js\n'); var xulG; var offlineStrings; var authStrings; +var openTabs = new Array(); +var tempWindow = null; +var tempFocusWindow = null; function grant_perms(url) { var perms = "UniversalXPConnect UniversalPreferencesWrite UniversalBrowserWrite UniversalPreferencesRead UniversalBrowserRead UniversalFileRead"; @@ -71,10 +74,126 @@ function start_js_shell() { ); }; +function new_tabs(aTabList, aContinue) { + if(aTabList != null) { + openTabs = openTabs.concat(aTabList); + } + if(G.data.session) { // Just add to the list of stuff to open unless we are logged in + netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); + var targetwindow = null; + var focuswindow = null; + var focustab = {'focus' : true}; + if(aContinue == true && tempWindow.closed == false) { + if(tempWindow.g == undefined || tempWindow.g.menu == undefined) { + setTimeout( + function() { + new_tabs(null, true); + }, 300); + return null; + } + targetwindow = tempWindow; + tempWindow = null; + focuswindow = tempFocusWindow; + tempFocusWindow = null; + focustab = {'nofocus' : true}; + } + else if(tempWindow != null) { // In theory, we are waiting on a setTimeout + if(tempWindow.closed == true) // But someone closed our window? + { + tempWindow = null; + tempFocusWindow = null; + } + else + { + return null; + } + } + var newTab; + var firstURL; + var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]. + getService(Components.interfaces.nsIWindowMediator); + // This may look out of place, but this is so we can continue this loop from down below +opentabs: + while(openTabs.length > 0) { + newTab = openTabs.shift(); + if(newTab == 'new' || newTab == 'init') { + if(newTab != 'init' && openTabs.length > 0 && openTabs[0] != 'new') { + firstURL = openTabs.shift(); + if(firstURL != 'tab') { // 'new' followed by 'tab' should be equal to 'init' in functionality, this should do that + if(urls[firstURL]) { + firstURL = urls[firstURL]; + } + firstURL = '&firstURL=' + window.escape(firstURL); + } + else { + firstURL = ''; + } + } + else { + firstURL = ''; + } + targetwindow = xulG.window.open(urls.XUL_MENU_FRAME + + '?server='+window.escape(G.data.server) + firstURL, + '_blank','chrome,resizable' + ); + targetwindow.xulG = xulG; + if (focuswindow == null) { + focuswindow = targetwindow; + } + tempWindow = targetwindow; + tempFocusWindow = focuswindow; + setTimeout( + function() { + new_tabs(null, true); + }, 300); + return null; + } + else { + if(newTab == 'tab') { + newTab = null; + } + else if(urls[newTab]) { + newTab = urls[newTab]; + } + if(targetwindow != null) { // Already have a previous target window? Use it first. + if(targetwindow.g.menu.new_tab(newTab,focustab,null)) { + focustab = {'nofocus' : true}; + continue; + } + } + var enumerator = wm.getEnumerator('eg_menu'); + while(enumerator.hasMoreElements()) { + targetwindow = enumerator.getNext(); + if(targetwindow.g.menu.new_tab(newTab,focustab,null)) { + focustab = {'nofocus' : true}; + if (focuswindow == null) { + focuswindow = targetwindow; + } + continue opentabs; + } + } + // No windows found to add the tab to? Make a new one. + if(newTab == null) { // Were we making a "default" tab? + openTabs.unshift('init'); // 'init' does that for us! + } + else { + openTabs.unshift('new',newTab); + } + } + } + if(focuswindow != null) { + focuswindow.focus(); + } + } +} + function main_init() { dump('entering main_init()\n'); try { clear_the_cache(); + if("arguments" in window && window.arguments.length > 0 && window.arguments[0].wrappedJSObject != undefined && window.arguments[0].wrappedJSObject.openTabs != undefined) { + openTabs = openTabs.concat(window.arguments[0].wrappedJSObject.openTabs); + } // Now we can safely load the strings without the cache getting wiped offlineStrings = document.getElementById('offlineStrings'); @@ -353,15 +472,7 @@ function main_init() { 'command', function() { if (G.data.session) { - try { - //G.data_xul.g.open_menu(); - netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); - var mframe = xulG.window.open(( String(urls.XUL_MENU_FRAME).match(/^chrome:/) ? '' : G.data.server ) + urls.XUL_MENU_FRAME - + '?server='+window.escape(G.data.server), - 'main'+xulG.window.window_name_increment(),'chrome,resizable' - ); - mframe.xulG = xulG; - } catch(E) { alert(E); } + new_tabs(Array('new'), null, null); } else { alert ( offlineStrings.getString('main.new_window_btn.login_first_warning') ); } diff --git a/Open-ILS/xul/staff_client/chrome/content/main/menu.js b/Open-ILS/xul/staff_client/chrome/content/main/menu.js index aa53ed70d..4034662b0 100644 --- a/Open-ILS/xul/staff_client/chrome/content/main/menu.js +++ b/Open-ILS/xul/staff_client/chrome/content/main/menu.js @@ -27,18 +27,6 @@ main.menu = function () { }, false ); - - if (xulG.pref.getBoolPref('open-ils.disable_accesskeys_on_tabs')) { - var tabs = document.getElementById('main_tabs'); - for (var i = 0; i < tabs.childNodes.length; i++) { - tabs.childNodes[i].setAttribute('accesskey',''); - } - } - - if (xulG.pref.getBoolPref('open-ils.enable_join_tabs')) { - document.getElementById('join_tabs_menuitem_vertical').hidden = false; - document.getElementById('join_tabs_menuitem_horizontal').hidden = false; - } } main.menu.prototype = { @@ -145,29 +133,24 @@ main.menu.prototype = { 'cmd_new_window' : [ ['oncommand'], function() { - obj.data.stash_retrieve(); - var mframe = obj.window.open( - obj.url_prefix(urls.XUL_MENU_FRAME) - + '?server='+window.escape(urls.remote), - 'main' + obj.window.window_name_increment(), - 'chrome,resizable'); - netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect'); - mframe.xulG = xulG; - /* This window should get its own objects for these */ - delete mframe.xulG['_data']; + var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]. + getService(Components.interfaces.nsIWindowMediator); + wm.getMostRecentWindow('eg_main').new_tabs(Array('new')); } ], 'cmd_new_tab' : [ ['oncommand'], - function() { obj.new_tab(null,{'focus':true},null); } - ], - 'cmd_join_tabs_vertical' : [ - ['oncommand'], - function() { obj.join_tabs({'orient':'vertical'}); } - ], - 'cmd_join_tabs_horizontal' : [ - ['oncommand'], - function() { obj.join_tabs({'orient':'horizontal'}); } + function() { + if (obj.new_tab(null,{'focus':true},null) == false) + { + if(window.confirm("Sorry, we can't create any more tabs in this window.\nWould you like to create a new tab in another window?")) + { + var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]. + getService(Components.interfaces.nsIWindowMediator); + wm.getMostRecentWindow('eg_main').new_tabs(Array('tab')); + } + } + } ], 'cmd_close_tab' : [ ['oncommand'], @@ -1283,7 +1266,6 @@ main.menu.prototype = { } } ], - }; JSAN.use('util.controller'); @@ -1292,12 +1274,20 @@ main.menu.prototype = { obj.controller.init( { 'window_knows_me_by' : 'g.menu.controller', 'control_map' : cmd_map } ); obj.controller.view.tabbox = window.document.getElementById('main_tabbox'); - obj.controller.view.tabs = obj.controller.view.tabbox.firstChild; - obj.controller.view.panels = obj.controller.view.tabbox.lastChild; - - obj.new_tab(null,{'focus':true},null); - - obj.init_tab_focus_handlers(); + // Despite what the docs say: + // The "tabs" element need not be the first child + // The "panels" element need not be the second/last + // Nor need they be the only ones there. + // Thus, use the IDs for robustness. + obj.controller.view.tabs = window.document.getElementById('main_tabs'); + obj.controller.view.panels = window.document.getElementById('main_panels'); + obj.controller.view.tabscroller = window.document.getElementById('main_tabs_scrollbox'); + if(params['firstURL']) { + obj.new_tab(params['firstURL'],{'focus':true},null); + } + else { + obj.new_tab(null,{'focus':true},null); + } }, 'spawn_search' : function(s) { @@ -1306,55 +1296,11 @@ main.menu.prototype = { obj.new_patron_tab( {}, { 'doit' : 1, 'query' : js2JSON(s) } ); }, - 'init_tab_focus_handlers' : function() { - var obj = this; - for (var i = 0; i < obj.controller.view.tabs.childNodes.length; i++) { - var tab = obj.controller.view.tabs.childNodes[i]; - var panel = obj.controller.view.panels.childNodes[i]; - tab.addEventListener( - 'command', - function(p) { - return function() { - try { - netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); - if (p - && p.firstChild - && ( p.firstChild.nodeName == 'iframe' || p.firstChild.nodeName == 'browser' ) - && p.firstChild.contentWindow - ) { - var cw = p.firstChild.contentWindow; - var help_params = { - 'protocol' : cw.location.protocol, - 'hostname' : cw.location.hostname, - 'port' : cw.location.port, - 'pathname' : cw.location.pathname, - 'src' : '' - }; - obj.set_help_context(help_params); - if (typeof cw.default_focus == 'function') { - cw.default_focus(); - } - } - } catch(E) { - obj.error.sdump('D_ERROR','init_tab_focus_handler: ' + js2JSON(E)); - } - } - }(panel), - false - ); - } - }, - - // We keep a reference to content_params fed to tabs, so if we manipulate the DOM (say, via join_tabs), - // we can re-inject the content_params into the content if needed. We have to watch out for memory leaks - // doing this. - 'preserved_content_params' : {}, - 'close_all_tabs' : function() { var obj = this; try { var count = obj.controller.view.tabs.childNodes.length; - for (var i = 0; i < count; i++) obj.close_tab(); + for (var i = 1; i < count; i++) obj.close_tab(); setTimeout( function(){ obj.controller.view.tabs.firstChild.focus(); }, 0); } catch(E) { obj.error.standard_unexpected_error_alert(offlineStrings.getString('menu.close_all_tabs.error'),E); @@ -1363,154 +1309,100 @@ main.menu.prototype = { 'close_tab' : function (specific_idx) { var idx = specific_idx || this.controller.view.tabs.selectedIndex; - var tab = this.controller.view.tabs.childNodes[idx]; var panel = this.controller.view.panels.childNodes[ idx ]; - while ( panel.lastChild ) panel.removeChild( panel.lastChild ); - if (idx == 0) { - try { - this.controller.view.tabs.advanceSelectedTab(+1); - } catch(E) { - this.error.sdump('D_TAB','failed tabs.advanceSelectedTab(+1):'+js2JSON(E) + '\n'); - try { - this.controller.view.tabs.advanceSelectedTab(-1); - } catch(E) { - this.error.sdump('D_TAB','failed again tabs.advanceSelectedTab(-1):'+ - js2JSON(E) + '\n'); - } - } - } else { - try { - this.controller.view.tabs.advanceSelectedTab(-1); - } catch(E) { - this.error.sdump('D_TAB','failed tabs.advanceSelectedTab(-1):'+js2JSON(E) + '\n'); - try { - this.controller.view.tabs.advanceSelectedTab(+1); - } catch(E) { - this.error.sdump('D_TAB','failed again tabs.advanceSelectedTab(+1):'+ - js2JSON(E) + '\n'); - } - } - + this.controller.view.tabs.removeItemAt(idx); + this.controller.view.panels.removeChild(panel); + if(this.controller.view.tabs.childNodes.length > idx) { + this.controller.view.tabbox.selectedIndex = idx; } - - this.error.sdump('D_TAB','\tnew tabbox.selectedIndex = ' + this.controller.view.tabbox.selectedIndex + '\n'); - - this.controller.view.tabs.childNodes[ idx ].hidden = true; - this.error.sdump('D_TAB','tabs.childNodes[ ' + idx + ' ].hidden = true;\n'); - - // Make sure we keep at least one tab open. - var tab_flag = true; - for (var i = 0; i < this.controller.view.tabs.childNodes.length; i++) { - var tab = this.controller.view.tabs.childNodes[i]; - if (!tab.hidden) - tab_flag = false; + else { + this.controller.view.tabbox.selectedIndex = idx - 1; } - if (tab_flag) { - this.controller.view.tabs.selectedIndex = 0; + this.controller.view.tabscroller.ensureElementIsVisible(this.controller.view.tabs.selectedItem); + this.update_all_tab_names(); + // Make sure we keep at least one tab open. + if(this.controller.view.tabs.childNodes.length == 1) { this.new_tab(); } }, - - 'join_tabs' : function(params) { - try { - if (!params) { params = {}; } - if (!params.orient) { params.orient = 'horizontal'; } - - var left_idx = params.specific_idx || this.controller.view.tabs.selectedIndex; - var left_tab = this.controller.view.tabs.childNodes[left_idx]; - var left_panel = this.controller.view.panels.childNodes[ left_idx ]; - - // Find next not-hidden tab - var right_idx; - for (var i = left_idx + 1; i