From f05b9fdab7469978c98a54dce9fb73b50021a1f4 Mon Sep 17 00:00:00 2001 From: phasefx <phasefx@dcc99617-32d9-48b4-a31d-7c20da2025e4> 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 294b7c5089..4b94d7a865 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 @@ <window id="offline_win" sizemode="maximized" onload="try { my_init(); } catch(E) { alert(E); }" + windowtype="eg_offline" xmlns:html="http://www.w3.org/1999/xhtml" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> 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 2a42d3fb62..7abcd42d21 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 aa53ed70d0..4034662b0e 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<this.controller.view.tabs.childNodes.length; i++) { - var tab = this.controller.view.tabs.childNodes[i]; - if (!tab.hidden && !right_idx) { - right_idx = i; - } + + 'update_all_tab_names' : function() { + var doAccessKeys = !xulG.pref.getBoolPref('open-ils.disable_accesskeys_on_tabs'); + for(var i = 1; i < this.controller.view.tabs.childNodes.length; ++i) { + var tab = this.controller.view.tabs.childNodes[i]; + tab.curindex = i; + tab.label = i + ' ' + tab.origlabel; + if(doAccessKeys && offlineStrings.testString('menu.tab' + i + '.accesskey')) { + tab.accessKey = offlineStrings.getString('menu.tab' + i + '.accesskey'); } - if (!right_idx) { return; } - - // Grab the content - var right_tab = this.controller.view.tabs.childNodes[right_idx]; - var right_panel = this.controller.view.panels.childNodes[ right_idx ]; - - var left_content = left_panel.removeChild( left_panel.firstChild ); - var right_content = right_panel.removeChild( right_panel.firstChild ); - - // Create a wrapper and shuffle the content - var box = params.orient == 'vertical' ? document.createElement('vbox') : document.createElement('hbox'); - box.setAttribute('flex',1); - left_panel.appendChild(box); - box.appendChild(left_content); - var splitter = document.createElement('splitter'); - splitter.appendChild( document.createElement('grippy') ); - box.appendChild(splitter); - box.appendChild(right_content); - - right_tab.hidden = true; - // FIXME: if we really want to combine labels for joined tabs, need to handle the cases where the content dynamically set their tab - // labels with xulG.set_tab_name - left_tab.setAttribute('unadornedlabel', left_tab.getAttribute('unadornedlabel') + ' / ' + right_tab.getAttribute('unadornedlabel')); - left_tab.setAttribute('label', left_tab.getAttribute('label') + ' / ' + right_tab.getAttribute('unadornedlabel')); - - // Re-apply content params, etc. - var left_params = this.preserved_content_params[ left_idx ]; - var right_params = this.preserved_content_params[ right_idx ]; - this.preserved_content_params[ left_idx ] = function() { - try { - left_params(); - right_params(); - } catch(E) { - alert('Error re-applying content params after join_tabs'); - } - }; - this.preserved_content_params[ left_idx ](); - - } catch(E) { - alert('Error in menu.js with join_tabs(): ' + E); } }, - 'find_free_tab' : function() { - var last_not_hidden = -1; - for (var i = 0; i<this.controller.view.tabs.childNodes.length; i++) { - var tab = this.controller.view.tabs.childNodes[i]; - if (!tab.hidden) - last_not_hidden = i; + 'new_tab' : function(url,params,content_params) { + var max_tabs = 0; + try { + var max_tabs = xulG.pref.getIntPref('open-ils.window_max_tabs', max_tabs); } - if (last_not_hidden == this.controller.view.tabs.childNodes.length - 1) - last_not_hidden = -1; - // If the one next to last_not_hidden is hidden, we want it. - // Basically, we fill in tabs after existing tabs for as - // long as possible. - var idx = last_not_hidden + 1; - var candidate = this.controller.view.tabs.childNodes[ idx ]; - if (candidate.hidden) - return idx; - // Alright, find the first hidden then - for (var i = 0; i<this.controller.view.tabs.childNodes.length; i++) { - var tab = this.controller.view.tabs.childNodes[i]; - if (tab.hidden) - return i; + catch (e) {} + if(max_tabs > 0 && this.controller.view.tabs.childNodes.length > max_tabs) return false; + var tab = this.w.document.createElement('tab'); + var panel = this.w.document.createElement('tabpanel'); + var tabscroller = this.controller.view.tabscroller; + this.controller.view.tabs.appendChild(tab); + this.controller.view.panels.appendChild(panel); + tab.curindex = this.controller.view.tabs.childNodes.length - 1; + if(!xulG.pref.getBoolPref('open-ils.disable_accesskeys_on_tabs')) { + if(offlineStrings.testString('menu.tab' + tab.curindex + '.accesskey')) { + tab.accessKey = offlineStrings.getString('menu.tab' + tab.curindex + '.accesskey'); + } } - return -1; - }, - - 'new_tab' : function(url,params,content_params) { - var tc = this.find_free_tab(); - if (tc == -1) { return null; } // 9 tabs max - var tab = this.controller.view.tabs.childNodes[ tc ]; - tab.hidden = false; + var tabs = this.controller.view.tabs; + tab.addEventListener( + 'command', + function() { + try { + tabscroller.ensureElementIsVisible(tab); + netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); + if (panel + && panel.firstChild + && ( panel.firstChild.nodeName == 'iframe' || panel.firstChild.nodeName == 'browser' ) + && panel.firstChild.contentWindow + ) { + var cw = panel.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)); + } + } + , + false + ); if (!content_params) content_params = {}; if (!params) params = {}; if (!params.tab_name) params.tab_name = offlineStrings.getString('menu.new_tab.tab'); if (!params.nofocus) params.focus = true; /* make focus the default */ try { - if (params.focus) this.controller.view.tabs.selectedIndex = tc; - params.index = tc; + if (params.focus) { + this.controller.view.tabs.selectedItem = tab; + tabscroller.ensureElementIsVisible(tab); + } + params.index = tab.curindex; this.set_tab(url,params,content_params); + return true; } catch(E) { this.error.sdump('D_ERROR',E); + return false; } }, @@ -1640,8 +1532,19 @@ main.menu.prototype = { if (params.src) { help_btn.setAttribute('src', params.src); } } }, - 'augment_content_params' : function(idx,tab,params,content_params) { + 'set_tab' : function(url,params,content_params) { var obj = this; + if (!url) url = '/xul/server/'; + if (!url.match(/:\/\//) && !url.match(/^data:/)) url = urls.remote + url; + if (!params) params = {}; + if (!content_params) content_params = {}; + var idx = this.controller.view.tabs.selectedIndex; + if (params && typeof params.index != 'undefined') idx = params.index; + var tab = this.controller.view.tabs.childNodes[ idx ]; + if (params.focus) tab.focus(); + var panel = this.controller.view.panels.childNodes[ idx ]; + while ( panel.lastChild ) panel.removeChild( panel.lastChild ); + content_params.new_tab = function(a,b,c) { return obj.new_tab(a,b,c); }; content_params.set_tab = function(a,b,c) { return obj.set_tab(a,b,c); }; content_params.close_tab = function() { return obj.close_tab(); }; @@ -1650,7 +1553,7 @@ main.menu.prototype = { content_params.volume_item_creator = function(a) { return obj.volume_item_creator(a); }; content_params.get_new_session = function(a) { return obj.get_new_session(a); }; content_params.holdings_maintenance_tab = function(a,b,c) { return obj.holdings_maintenance_tab(a,b,c); }; - content_params.set_tab_name = function(name) { tab.setAttribute('unadornedlabel',name); tab.setAttribute('label',(idx + 1) + ' ' + name); }; + content_params.set_tab_name = function(name) { tab.label = tab.curindex + ' ' + name; tab.origlabel = name; }; content_params.set_help_context = function(params) { return obj.set_help_context(params); }; content_params.open_chrome_window = function(a,b,c) { return xulG.window.open(a,b,c); }; content_params.url_prefix = function(url) { return obj.url_prefix(url); }; @@ -1662,24 +1565,6 @@ main.menu.prototype = { }; content_params.chrome_xulG = xulG; content_params._data = xulG._data; - - return content_params; - }, - 'set_tab' : function(url,params,content_params) { - var obj = this; - if (!url) url = '/xul/server/'; - if (!url.match(/:\/\//) && !url.match(/^data:/)) url = urls.remote + url; - if (!params) params = {}; - if (!content_params) content_params = {}; - var idx = this.controller.view.tabs.selectedIndex; - if (obj.preserved_content_params[idx]) { delete obj.preserved_content_params[ idx ]; } - if (params && typeof params.index != 'undefined') idx = params.index; - var tab = this.controller.view.tabs.childNodes[ idx ]; - if (params.focus) tab.focus(); - var panel = this.controller.view.panels.childNodes[ idx ]; - while ( panel.lastChild ) panel.removeChild( panel.lastChild ); - - content_params = obj.augment_content_params(idx,tab,params,content_params); if (params && params.tab_name) content_params.set_tab_name( params.tab_name ); var frame; @@ -1706,9 +1591,6 @@ main.menu.prototype = { 'passthru_content_params' : content_params, } ); - obj.preserved_content_params[ idx ] = function() { - b.passthru_content_params = content_params; - } } catch(E) { alert(E); } @@ -1718,40 +1600,37 @@ main.menu.prototype = { panel.appendChild(frame); dump('creating iframe with src = ' + url + '\n'); frame.setAttribute('src',url); - obj.preserved_content_params[ idx ] = function() { - try { - netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); - var cw = frame.contentWindow; - if (typeof cw.wrappedJSObject != 'undefined') cw = cw.wrappedJSObject; - cw.IAMXUL = true; - cw.xulG = content_params; - cw.addEventListener( - 'load', - function() { - try { - if (typeof cw.help_context_set_locally == 'undefined') { - 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); - } else if (typeof cw.default_focus == 'function') { - cw.default_focus(); - } - } catch(E) { - obj.error.sdump('D_ERROR', 'main.menu, set_tab, onload: ' + E); + try { + netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); + var cw = frame.contentWindow; + if (typeof cw.wrappedJSObject != 'undefined') cw = cw.wrappedJSObject; + cw.IAMXUL = true; + cw.xulG = content_params; + cw.addEventListener( + 'load', + function() { + try { + if (typeof cw.help_context_set_locally == 'undefined') { + 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); + } else if (typeof cw.default_focus == 'function') { + cw.default_focus(); } - }, - false - ); - } catch(E) { - this.error.sdump('D_ERROR', 'main.menu: ' + E); - } - }; - obj.preserved_content_params[ idx ](); + } catch(E) { + obj.error.sdump('D_ERROR', 'main.menu, set_tab, onload: ' + E); + } + }, + false + ); + } catch(E) { + this.error.sdump('D_ERROR', 'main.menu: ' + E); + } } } catch(E) { this.error.sdump('D_ERROR', 'main.menu:2: ' + E); diff --git a/Open-ILS/xul/staff_client/chrome/content/main/menu_frame.xul b/Open-ILS/xul/staff_client/chrome/content/main/menu_frame.xul index e006e46033..e87e371915 100644 --- a/Open-ILS/xul/staff_client/chrome/content/main/menu_frame.xul +++ b/Open-ILS/xul/staff_client/chrome/content/main/menu_frame.xul @@ -31,6 +31,7 @@ onload="try { my_init(); font_helper(); } catch(E) { alert(E); }" orient="vertical" width="1024" height="740" sizemode="maximized" persist="width height sizemode" title="&staff.main.menu.title;" + windowtype="eg_menu" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> <!-- ///////////////////////////////////////////////////////////////////////////////////////////////////////////// --> @@ -86,6 +87,7 @@ JSAN.use('main.menu'); g.menu = new main.menu(); g.menu.init( { 'server' : g.cgi.param('server'), + 'firstURL' : g.cgi.param('firstURL'), } ); JSAN.use('util.window'); g.window = new util.window(); diff --git a/Open-ILS/xul/staff_client/chrome/content/main/menu_frame_menus.xul b/Open-ILS/xul/staff_client/chrome/content/main/menu_frame_menus.xul index 4b9db590e1..7976274be4 100644 --- a/Open-ILS/xul/staff_client/chrome/content/main/menu_frame_menus.xul +++ b/Open-ILS/xul/staff_client/chrome/content/main/menu_frame_menus.xul @@ -13,8 +13,6 @@ <command id="cmd_new_tab" key="new-tab-key" /> <command id="cmd_close_tab" key="close-tab-key" /> <command id="cmd_close_all_tabs" key="close-all-tabs-key" /> - <command id="cmd_join_tabs_vertical" label="&staff.main.menu.file.join_tabs_vertical.label;" accesskey="&staff.main.menu.file.join_tabs_vertical.accesskey;" /> - <command id="cmd_join_tabs_horizontal" label="&staff.main.menu.file.join_tabs_horizontal.label;" accesskey="&staff.main.menu.file.join_tabs_horizontal.accesskey;" /> <command id="cmd_shutdown" /> <command id="cmd_edit_copy_buckets" /> @@ -201,8 +199,6 @@ <menupopup id="main.menu.file.popup"> <menuitem label="&staff.main.menu.file.new.label;" accesskey="&staff.main.menu.file.new.accesskey;" key="new-window-key" command="cmd_new_window"/> <menuitem label="&staff.main.menu.file.new_tab.label;" accesskey="&staff.main.menu.file.new_tab.accesskey;" key="new-tab-key" command="cmd_new_tab"/> - <menuitem id="join_tabs_menuitem_horizontal" hidden="true" command="cmd_join_tabs_horizontal"/> - <menuitem id="join_tabs_menuitem_vertical" hidden="true" command="cmd_join_tabs_vertical"/> <menuseparator /> <menuitem label="&staff.main.menu.file.close_tab.label;" accesskey="&staff.main.menu.file.close_tab.accesskey;" oldaccesskey="&staff.main.menu.file.close_tab.key;" key="close-tab-key" command="cmd_close_tab"/> <menuitem label="&staff.main.menu.tabs.close;" accesskey="&staff.main.menu.tabs.close.accesskey;" key="close-all-tabs-key" command="cmd_close_all_tabs"/> diff --git a/Open-ILS/xul/staff_client/chrome/content/main/menu_frame_overlay.xul b/Open-ILS/xul/staff_client/chrome/content/main/menu_frame_overlay.xul index faaefd5d94..58bf366dc0 100644 --- a/Open-ILS/xul/staff_client/chrome/content/main/menu_frame_overlay.xul +++ b/Open-ILS/xul/staff_client/chrome/content/main/menu_frame_overlay.xul @@ -16,27 +16,16 @@ <box id="menu_frame_main" flex="1" orient="vertical"> <toolbox id="main_toolbox"/> <tabbox id="main_tabbox" flex="1" eventnode="window" handleCtrlTab="true"> - <tabs id="main_tabs" closebutton="true" onclosetab="g.menu.close_tab()"> - <tab id="tab_1" accesskey="&staff.chrome.menu_frame_overlay.tab1.accesskey;" label="&staff.chrome.menu_frame_overlay.tab1.label;" hidden="true" /> - <tab id="tab_2" accesskey="&staff.chrome.menu_frame_overlay.tab2.accesskey;" label="&staff.chrome.menu_frame_overlay.tab2.label;" hidden="true" /> - <tab id="tab_3" accesskey="&staff.chrome.menu_frame_overlay.tab3.accesskey;" label="&staff.chrome.menu_frame_overlay.tab3.label;" hidden="true" /> - <tab id="tab_4" accesskey="&staff.chrome.menu_frame_overlay.tab4.accesskey;" label="&staff.chrome.menu_frame_overlay.tab4.label;" hidden="true" /> - <tab id="tab_5" accesskey="&staff.chrome.menu_frame_overlay.tab5.accesskey;" label="&staff.chrome.menu_frame_overlay.tab5.label;" hidden="true" /> - <tab id="tab_6" accesskey="&staff.chrome.menu_frame_overlay.tab6.accesskey;" label="&staff.chrome.menu_frame_overlay.tab6.label;" hidden="true" /> - <tab id="tab_7" accesskey="&staff.chrome.menu_frame_overlay.tab7.accesskey;" label="&staff.chrome.menu_frame_overlay.tab7.label;" hidden="true" /> - <tab id="tab_8" accesskey="&staff.chrome.menu_frame_overlay.tab8.accesskey;" label="&staff.chrome.menu_frame_overlay.tab8.label;" hidden="true" /> - <tab id="tab_9" accesskey="&staff.chrome.menu_frame_overlay.tab9.accesskey;" label="&staff.chrome.menu_frame_overlay.tab9.label;" hidden="true" /> - </tabs> + <hbox> + <arrowscrollbox orient="horizontal" id="main_tabs_scrollbox" flex="2"> + <tabs id="main_tabs"> + <tab hidden="true" /> + </tabs> + </arrowscrollbox> + <toolbarbutton id="main_tabs_closebutton" class="tabs-closebutton close-button" oncommand="g.menu.close_tab()" /> + </hbox> <tabpanels id="main_panels" flex="1"> - <tabpanel id="panel_1"><label value="panel_1"/></tabpanel> - <tabpanel id="panel_2"><label value="panel_2"/></tabpanel> - <tabpanel id="panel_3"><label value="panel_3"/></tabpanel> - <tabpanel id="panel_4"><label value="panel_4"/></tabpanel> - <tabpanel id="panel_5"><label value="panel_5"/></tabpanel> - <tabpanel id="panel_6"><label value="panel_6"/></tabpanel> - <tabpanel id="panel_7"><label value="panel_7"/></tabpanel> - <tabpanel id="panel_8"><label value="panel_8"/></tabpanel> - <tabpanel id="panel_9"><label value="panel_9"/></tabpanel> + <tabpanel /> </tabpanels> </tabbox> <statusbar> diff --git a/Open-ILS/xul/staff_client/chrome/locale/en-US/offline.properties b/Open-ILS/xul/staff_client/chrome/locale/en-US/offline.properties index 7fec403dde..d9fa2f595a 100644 --- a/Open-ILS/xul/staff_client/chrome/locale/en-US/offline.properties +++ b/Open-ILS/xul/staff_client/chrome/locale/en-US/offline.properties @@ -267,3 +267,13 @@ printing.nothing_to_reprint=Nothing to re-print printing.prompt_for_external_print_cmd=Enter external print command and parameters (use %receipt.txt% or %receipt.html% as the file containing the print data. Those values will be substituted with the proper path.): printing.print_strategy_saved=Print strategy (%1$s) for %2$s context saved to file system. text_editor.prompt_for_external_cmd=Enter external text editor command and parameters (use %letter.txt% as the file containing the text. This value will be substituted with the proper path.): +menu.tab1.accesskey=1 +menu.tab2.accesskey=2 +menu.tab3.accesskey=3 +menu.tab4.accesskey=4 +menu.tab5.accesskey=5 +menu.tab6.accesskey=6 +menu.tab7.accesskey=7 +menu.tab8.accesskey=8 +menu.tab9.accesskey=9 +menu.tab10.accesskey=0 diff --git a/Open-ILS/xul/staff_client/components/clh.js b/Open-ILS/xul/staff_client/components/clh.js new file mode 100644 index 0000000000..901810371c --- /dev/null +++ b/Open-ILS/xul/staff_client/components/clh.js @@ -0,0 +1,221 @@ +const nsISupports = Components.interfaces.nsISupports; +const nsICategoryManager = Components.interfaces.nsICategoryManager; +const nsIComponentRegistrar = Components.interfaces.nsIComponentRegistrar; +const nsICommandLine = Components.interfaces.nsICommandLine; +const nsICommandLineHandler = Components.interfaces.nsICommandLineHandler; +const nsIFactory = Components.interfaces.nsIFactory; +const nsIModule = Components.interfaces.nsIModule; +const nsIWindowWatcher = Components.interfaces.nsIWindowWatcher; + + +const XUL_STANDALONE = "chrome://open_ils_staff_client/content/circ/offline.xul"; +const XUL_MAIN = "chrome://open_ils_staff_client/content/main/main.xul"; +const WINDOW_STANDALONE = "eg_offline" +const WINDOW_MAIN = "eg_main" + +const clh_contractID = "@mozilla.org/commandlinehandler/general-startup;1?type=egcli"; +const clh_CID = Components.ID("{7e608198-7355-483a-a85a-20322e4ef91a}"); +// category names are sorted alphabetically. Typical command-line handlers use a +// category that begins with the letter "m". +const clh_category = "m-egcli"; + +/** + * Utility functions + */ + +/** + * Opens a chrome window. + * @param aChromeURISpec a string specifying the URI of the window to open. + * @param aArgument an argument to pass to the window (may be null) + */ +function findOrOpenWindow(aWindowType, aChromeURISpec, aName, aArgument) +{ + var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]. + getService(Components.interfaces.nsIWindowMediator); + var targetWindow = wm.getMostRecentWindow(aWindowType); + if (targetWindow != null) { + if(typeof targetWindow.new_tabs == 'function' && aArgument != null) + { + targetWindow.new_tabs(aArgument); + } + else { + targetwindow.focus; + } + } + else { + var params = null; + if (aArgument != null && aArgument.length != 0) + { + params = { "openTabs" : aArgument }; + params.wrappedJSObject = params; + } + var ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]. + getService(Components.interfaces.nsIWindowWatcher); + ww.openWindow(null, aChromeURISpec, aName, + "chrome,resizable,dialog=no", params); + } +} + +/** + * The XPCOM component that implements nsICommandLineHandler. + * It also implements nsIFactory to serve as its own singleton factory. + */ +const myAppHandler = { + /* nsISupports */ + QueryInterface : function clh_QI(iid) + { + if (iid.equals(nsICommandLineHandler) || + iid.equals(nsIFactory) || + iid.equals(nsISupports)) + return this; + + throw Components.results.NS_ERROR_NO_INTERFACE; + }, + + /* nsICommandLineHandler */ + + handle : function clh_handle(cmdLine) + { + // Each of these options is used for opening a new tab, either on login or remote send. + // XULRunner does some sanitize to turn /ilsblah into -ilsblah, for example. + // In addition to the ones here, -ilslogin, -ilsoffline, and -ilsstandalone + // are defined below. + + // With the exception of 'new', 'tab', and 'init', the value is checked for in urls in main.js. + + // NOTE: The option itself should be all lowercase (we .toLowerCase below) + var options = { + '-ilscheckin' : 'XUL_CHECKIN', + '-ilscheckout' : 'XUL_PATRON_BARCODE_ENTRY', + '-ilsnew' : 'new', // 'new' is a special keyword for opening a new window + '-ilstab' : 'tab', // 'tab' is a special keyword for opening a new tab with the default content + '-ilsnew_default' : 'init', // 'init' is a special keyword for opening a new window with an initial default tab + }; + + var inParams = new Array(); + var position = 0; + while (position < cmdLine.length) { + var arg = cmdLine.getArgument(position).toLowerCase(); + if (options[arg] != undefined) { + inParams.push(options[arg]); + cmdLine.removeArguments(position,position); + continue; + } + if (arg == '-ilsurl' && cmdLine.length > position) { + inParams.push(cmdLine.getArgument(position + 1)); + cmdLine.removeArguments(position, position + 1); + continue; + } + position=position + 1; + } + + if (cmdLine.handleFlag("ILSlogin", false) || inParams.length > 0) { + findOrOpenWindow(WINDOW_MAIN, XUL_MAIN, '_blank', inParams); + cmdLine.preventDefault = true; + } + + if (cmdLine.handleFlag("ILSoffline", false) || cmdLine.handleFlag("ILSstandalone", false)) { + findOrOpenWindow(WINDOW_STANDALONE, XUL_STANDALONE, 'Offline', null); + cmdLine.preventDefault = true; + } + }, + + // CHANGEME: change the help info as appropriate, but + // follow the guidelines in nsICommandLineHandler.idl + // specifically, flag descriptions should start at + // character 24, and lines should be wrapped at + // 72 characters with embedded newlines, + // and finally, the string should end with a newline + helpInfo : " -ILScheckin Open an Evergreen checkin tab\n" + + " -ILScheckout Open an Evergreen checkout tab\n" + + " -ILSnew Open a new Evergreen 'menu' window\n" + + " -ILSnew_default Open a new Evergreen 'menu' window,\n" + + " with a 'default' tab\n" + + " -ILStab Open a 'default' tab alone\n" + + " -ILSurl <url> Open the specified url in an Evergreen tab\n" + + " The above six imply -ILSlogin\n" + + " -ILSlogin Open the Evergreen Login window\n" + + " -ILSstandalone Open the Evergreen Standalone interface\n" + + " -ILSoffline Alias for -ILSstandalone\n", + + /* nsIFactory */ + + createInstance : function clh_CI(outer, iid) + { + if (outer != null) + throw Components.results.NS_ERROR_NO_AGGREGATION; + + return this.QueryInterface(iid); + }, + + lockFactory : function clh_lock(lock) + { + /* no-op */ + } +}; + +/** + * The XPCOM glue that implements nsIModule + */ +const myAppHandlerModule = { + /* nsISupports */ + QueryInterface : function mod_QI(iid) + { + if (iid.equals(nsIModule) || + iid.equals(nsISupports)) + return this; + + throw Components.results.NS_ERROR_NO_INTERFACE; + }, + + /* nsIModule */ + getClassObject : function mod_gch(compMgr, cid, iid) + { + if (cid.equals(clh_CID)) + return myAppHandler.QueryInterface(iid); + + throw Components.results.NS_ERROR_NOT_REGISTERED; + }, + + registerSelf : function mod_regself(compMgr, fileSpec, location, type) + { + compMgr.QueryInterface(nsIComponentRegistrar); + + compMgr.registerFactoryLocation(clh_CID, + "myAppHandler", + clh_contractID, + fileSpec, + location, + type); + + var catMan = Components.classes["@mozilla.org/categorymanager;1"]. + getService(nsICategoryManager); + catMan.addCategoryEntry("command-line-handler", + clh_category, + clh_contractID, true, true); + }, + + unregisterSelf : function mod_unreg(compMgr, location, type) + { + compMgr.QueryInterface(nsIComponentRegistrar); + compMgr.unregisterFactoryLocation(clh_CID, location); + + var catMan = Components.classes["@mozilla.org/categorymanager;1"]. + getService(nsICategoryManager); + catMan.deleteCategoryEntry("command-line-handler", clh_category); + }, + + canUnload : function (compMgr) + { + return true; + } +}; + +/* The NSGetModule function is the magic entry point that XPCOM uses to find what XPCOM objects + * this component provides + */ +function NSGetModule(comMgr, fileSpec) +{ + return myAppHandlerModule; +} + diff --git a/Open-ILS/xul/staff_client/server/main/data.xul b/Open-ILS/xul/staff_client/server/main/data.xul index 6ca97b11e0..5d80e27fa4 100644 --- a/Open-ILS/xul/staff_client/server/main/data.xul +++ b/Open-ILS/xul/staff_client/server/main/data.xul @@ -224,17 +224,13 @@ } g.open_menu = function() { - try { - netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); - var mframe = xulG.window.open(urls.XUL_MENU_FRAME - + '?server='+window.escape(xulG.url), - 'main'+xulG.window.window_name_increment(),'chrome,resizable' - ); - delete xulG['_sound']; // This came from util.error but I want menu.js to have its own - mframe.xulG = xulG; // This is the xulG from main.js, with auth, url, and window - } catch(E) { - alert(E); - } + delete xulG['_sound']; + netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); + var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]. + getService(Components.interfaces.nsIWindowMediator); + var eg_main = wm.getMostRecentWindow('eg_main'); + eg_main.openTabs.unshift('init'); + wm.getMostRecentWindow('eg_main').new_tabs(null); } g.data.init(); -- 2.11.0