patch from tsbere to improve tab behavior and to give command-line options for contro...
authorphasefx <phasefx@dcc99617-32d9-48b4-a31d-7c20da2025e4>
Tue, 5 Oct 2010 20:13:01 +0000 (20:13 +0000)
committerphasefx <phasefx@dcc99617-32d9-48b4-a31d-7c20da2025e4>
Tue, 5 Oct 2010 20:13:01 +0000 (20:13 +0000)
See https://bugs.launchpad.net/evergreen/+bug/625056

git-svn-id: svn://svn.open-ils.org/ILS/trunk@18183 dcc99617-32d9-48b4-a31d-7c20da2025e4

Open-ILS/xul/staff_client/chrome/content/circ/offline.xul
Open-ILS/xul/staff_client/chrome/content/main/main.js
Open-ILS/xul/staff_client/chrome/content/main/menu.js
Open-ILS/xul/staff_client/chrome/content/main/menu_frame.xul
Open-ILS/xul/staff_client/chrome/content/main/menu_frame_menus.xul
Open-ILS/xul/staff_client/chrome/content/main/menu_frame_overlay.xul
Open-ILS/xul/staff_client/chrome/locale/en-US/offline.properties
Open-ILS/xul/staff_client/components/clh.js [new file with mode: 0644]
Open-ILS/xul/staff_client/server/main/data.xul

index 294b7c5..4b94d7a 100644 (file)
@@ -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">
 
index 2a42d3f..7abcd42 100644 (file)
@@ -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') );
                 }
index aa53ed7..4034662 100644 (file)
@@ -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);
index e006e46..e87e371 100644 (file)
@@ -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();
index 4b9db59..7976274 100644 (file)
@@ -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" />
     <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"/>
index faaefd5..58bf366 100644 (file)
 <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>
index 7fec403..d9fa2f5 100644 (file)
@@ -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 (file)
index 0000000..9018103
--- /dev/null
@@ -0,0 +1,221 @@
+const nsISupports           = Components.interfaces.nsISupports;\r
+const nsICategoryManager    = Components.interfaces.nsICategoryManager;\r
+const nsIComponentRegistrar = Components.interfaces.nsIComponentRegistrar;\r
+const nsICommandLine        = Components.interfaces.nsICommandLine;\r
+const nsICommandLineHandler = Components.interfaces.nsICommandLineHandler;\r
+const nsIFactory            = Components.interfaces.nsIFactory;\r
+const nsIModule             = Components.interfaces.nsIModule;\r
+const nsIWindowWatcher      = Components.interfaces.nsIWindowWatcher;\r
+\r
+\r
+const XUL_STANDALONE = "chrome://open_ils_staff_client/content/circ/offline.xul";\r
+const XUL_MAIN = "chrome://open_ils_staff_client/content/main/main.xul";\r
+const WINDOW_STANDALONE = "eg_offline"\r
+const WINDOW_MAIN = "eg_main"\r
+\r
+const clh_contractID = "@mozilla.org/commandlinehandler/general-startup;1?type=egcli";\r
+const clh_CID = Components.ID("{7e608198-7355-483a-a85a-20322e4ef91a}");\r
+// category names are sorted alphabetically. Typical command-line handlers use a\r
+// category that begins with the letter "m".\r
+const clh_category = "m-egcli";\r
+\r
+/**\r
+ * Utility functions\r
+ */\r
+\r
+/**\r
+ * Opens a chrome window.\r
+ * @param aChromeURISpec a string specifying the URI of the window to open.\r
+ * @param aArgument an argument to pass to the window (may be null)\r
+ */\r
+function findOrOpenWindow(aWindowType, aChromeURISpec, aName, aArgument)\r
+{\r
+  var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"].\r
+    getService(Components.interfaces.nsIWindowMediator);\r
+  var targetWindow = wm.getMostRecentWindow(aWindowType);\r
+  if (targetWindow != null) {\r
+      if(typeof targetWindow.new_tabs == 'function' && aArgument != null)\r
+      {\r
+          targetWindow.new_tabs(aArgument);\r
+      }\r
+      else {\r
+          targetwindow.focus;\r
+      }\r
+  }\r
+  else {\r
+    var params = null;\r
+    if (aArgument != null && aArgument.length != 0)\r
+    {\r
+        params = { "openTabs" : aArgument };\r
+        params.wrappedJSObject = params;\r
+    }\r
+    var ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"].\r
+        getService(Components.interfaces.nsIWindowWatcher);\r
+    ww.openWindow(null, aChromeURISpec, aName,\r
+        "chrome,resizable,dialog=no", params);\r
+  }\r
+}\r
\r
+/**\r
+ * The XPCOM component that implements nsICommandLineHandler.\r
+ * It also implements nsIFactory to serve as its own singleton factory.\r
+ */\r
+const myAppHandler = {\r
+  /* nsISupports */\r
+  QueryInterface : function clh_QI(iid)\r
+  {\r
+    if (iid.equals(nsICommandLineHandler) ||\r
+        iid.equals(nsIFactory) ||\r
+        iid.equals(nsISupports))\r
+      return this;\r
+\r
+    throw Components.results.NS_ERROR_NO_INTERFACE;\r
+  },\r
+\r
+  /* nsICommandLineHandler */\r
+\r
+  handle : function clh_handle(cmdLine)\r
+  {\r
+    // Each of these options is used for opening a new tab, either on login or remote send.\r
+    // XULRunner does some sanitize to turn /ilsblah into -ilsblah, for example.\r
+    // In addition to the ones here, -ilslogin, -ilsoffline, and -ilsstandalone\r
+    // are defined below.\r
+\r
+    // With the exception of 'new', 'tab', and 'init', the value is checked for in urls in main.js.\r
+\r
+    // NOTE: The option itself should be all lowercase (we .toLowerCase below)\r
+    var options = {\r
+    '-ilscheckin' : 'XUL_CHECKIN',\r
+    '-ilscheckout' : 'XUL_PATRON_BARCODE_ENTRY',\r
+    '-ilsnew' : 'new', // 'new' is a special keyword for opening a new window\r
+    '-ilstab' : 'tab', // 'tab' is a special keyword for opening a new tab with the default content\r
+    '-ilsnew_default' : 'init', // 'init' is a special keyword for opening a new window with an initial default tab\r
+    };\r
+\r
+    var inParams = new Array();\r
+       var position = 0;\r
+       while (position < cmdLine.length) {\r
+               var arg = cmdLine.getArgument(position).toLowerCase();\r
+               if (options[arg] != undefined) {\r
+                       inParams.push(options[arg]);\r
+                       cmdLine.removeArguments(position,position);\r
+                       continue;\r
+               }\r
+        if (arg == '-ilsurl' && cmdLine.length > position) {\r
+                 inParams.push(cmdLine.getArgument(position + 1));\r
+                 cmdLine.removeArguments(position, position + 1);\r
+                 continue;\r
+               }\r
+               position=position + 1;\r
+       }\r
+\r
+       if (cmdLine.handleFlag("ILSlogin", false) || inParams.length > 0) {\r
+         findOrOpenWindow(WINDOW_MAIN, XUL_MAIN, '_blank', inParams);\r
+         cmdLine.preventDefault = true;\r
+       }\r
+\r
+    if (cmdLine.handleFlag("ILSoffline", false) || cmdLine.handleFlag("ILSstandalone", false)) {\r
+         findOrOpenWindow(WINDOW_STANDALONE, XUL_STANDALONE, 'Offline', null);\r
+      cmdLine.preventDefault = true;\r
+       }\r
+  },\r
+\r
+  // CHANGEME: change the help info as appropriate, but\r
+  // follow the guidelines in nsICommandLineHandler.idl\r
+  // specifically, flag descriptions should start at\r
+  // character 24, and lines should be wrapped at\r
+  // 72 characters with embedded newlines,\r
+  // and finally, the string should end with a newline\r
+  helpInfo : "  -ILScheckin          Open an Evergreen checkin tab\n" +\r
+             "  -ILScheckout         Open an Evergreen checkout tab\n" +\r
+             "  -ILSnew              Open a new Evergreen 'menu' window\n" +\r
+             "  -ILSnew_default      Open a new Evergreen 'menu' window,\n" +\r
+             "                       with a 'default' tab\n" +\r
+             "  -ILStab              Open a 'default' tab alone\n" +\r
+             "  -ILSurl <url>        Open the specified url in an Evergreen tab\n" +\r
+             "  The above six imply -ILSlogin\n" +\r
+             "  -ILSlogin            Open the Evergreen Login window\n" +\r
+             "  -ILSstandalone       Open the Evergreen Standalone interface\n" +\r
+             "  -ILSoffline          Alias for -ILSstandalone\n",\r
+\r
+  /* nsIFactory */\r
+\r
+  createInstance : function clh_CI(outer, iid)\r
+  {\r
+    if (outer != null)\r
+      throw Components.results.NS_ERROR_NO_AGGREGATION;\r
+\r
+    return this.QueryInterface(iid);\r
+  },\r
+\r
+  lockFactory : function clh_lock(lock)\r
+  {\r
+    /* no-op */\r
+  }\r
+};\r
+\r
+/**\r
+ * The XPCOM glue that implements nsIModule\r
+ */\r
+const myAppHandlerModule = {\r
+  /* nsISupports */\r
+  QueryInterface : function mod_QI(iid)\r
+  {\r
+    if (iid.equals(nsIModule) ||\r
+        iid.equals(nsISupports))\r
+      return this;\r
+\r
+    throw Components.results.NS_ERROR_NO_INTERFACE;\r
+  },\r
+\r
+  /* nsIModule */\r
+  getClassObject : function mod_gch(compMgr, cid, iid)\r
+  {\r
+    if (cid.equals(clh_CID))\r
+      return myAppHandler.QueryInterface(iid);\r
+\r
+    throw Components.results.NS_ERROR_NOT_REGISTERED;\r
+  },\r
+\r
+  registerSelf : function mod_regself(compMgr, fileSpec, location, type)\r
+  {\r
+    compMgr.QueryInterface(nsIComponentRegistrar);\r
+\r
+    compMgr.registerFactoryLocation(clh_CID,\r
+                                    "myAppHandler",\r
+                                    clh_contractID,\r
+                                    fileSpec,\r
+                                    location,\r
+                                    type);\r
+\r
+    var catMan = Components.classes["@mozilla.org/categorymanager;1"].\r
+      getService(nsICategoryManager);\r
+    catMan.addCategoryEntry("command-line-handler",\r
+                            clh_category,\r
+                            clh_contractID, true, true);\r
+  },\r
+\r
+  unregisterSelf : function mod_unreg(compMgr, location, type)\r
+  {\r
+    compMgr.QueryInterface(nsIComponentRegistrar);\r
+    compMgr.unregisterFactoryLocation(clh_CID, location);\r
+\r
+    var catMan = Components.classes["@mozilla.org/categorymanager;1"].\r
+      getService(nsICategoryManager);\r
+    catMan.deleteCategoryEntry("command-line-handler", clh_category);\r
+  },\r
+\r
+  canUnload : function (compMgr)\r
+  {\r
+    return true;\r
+  }\r
+};\r
+\r
+/* The NSGetModule function is the magic entry point that XPCOM uses to find what XPCOM objects\r
+ * this component provides\r
+ */\r
+function NSGetModule(comMgr, fileSpec)\r
+{\r
+  return myAppHandlerModule;\r
+}\r
+\r
index 6ca97b1..5d80e27 100644 (file)
             }
 
             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();