home *** CD-ROM | disk | FTP | other *** search
/ PC World 2005 March / PCWorld_2005-03_cd.bin / komunikace / kmeleon / kmeleon09.exe / toolkit.jar / content / global / bindings / tabbrowser.xml < prev    next >
Extensible Markup Language  |  2004-11-03  |  57KB  |  1,496 lines

  1. <?xml version="1.0"?>
  2.  
  3. <!--
  4.    - The contents of this file are subject to the Mozilla Public
  5.    - License Version 1.1 (the "License"); you may not use this file
  6.    - except in compliance with the License. You may obtain a copy of
  7.    - the License at http://www.mozilla.org/MPL/
  8.    -
  9.    - Software distributed under the License is distributed on an "AS
  10.    - IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  11.    - implied. See the License for the specific language governing
  12.    - rights and limitations under the License.
  13.    -
  14.    - The Original Code is this file as it was released on
  15.    - March 28, 2001.
  16.    -
  17.    - The Initial Developer of the Original Code is Peter Annema.
  18.    - Portions created by Peter Annema are Copyright (C) 2001
  19.    - Peter Annema.  All Rights Reserved.
  20.    -
  21.    - Contributor(s):
  22.    -   David Hyatt <hyatt@netscape.com> (Original Author of <tabbrowser>)
  23.    -
  24.    - Alternatively, the contents of this file may be used under the
  25.    - terms of the GNU General Public License Version 2 or later (the
  26.    - "GPL"), in which case the provisions of the GPL are applicable
  27.    - instead of those above.  If you wish to allow use of your
  28.    - version of this file only under the terms of the GPL and not to
  29.    - allow others to use your version of this file under the MPL,
  30.    - indicate your decision by deleting the provisions above and
  31.    - replace them with the notice and other provisions required by
  32.    - the GPL.  If you do not delete the provisions above, a recipient
  33.    - may use your version of this file under either the MPL or the
  34.    - GPL.
  35.   -->
  36.  
  37. <!DOCTYPE bindings [
  38. <!ENTITY % tabBrowserDTD SYSTEM "chrome://global/locale/tabbrowser.dtd" >
  39. %tabBrowserDTD;
  40. ]>
  41.  
  42. <bindings id="tabBrowserBindings"
  43.           xmlns="http://www.mozilla.org/xbl"
  44.           xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
  45.           xmlns:xbl="http://www.mozilla.org/xbl">
  46.  
  47.   <binding id="tabbrowser">
  48.     <resources>
  49.       <stylesheet src="chrome://global/skin/browser.css"/>
  50.     </resources>
  51.  
  52.     <content>
  53.       <xul:stringbundle src="chrome://global/locale/tabbrowser.properties"/>
  54.       <xul:tabbox flex="1" eventnode="document" xbl:inherits="handleCtrlPageUpDown">
  55.         <xul:hbox class="tabbrowser-strip chromeclass-toolbar" collapsed="true" tooltip="_child" context="_child">
  56.           <xul:tooltip onpopupshowing="event.preventBubble(); if (document.tooltipNode.hasAttribute('label')) { this.setAttribute('label', document.tooltipNode.getAttribute('label')); return true; } return false;"/>
  57.           <xul:menupopup onpopupshowing="this.parentNode.parentNode.parentNode.updatePopupMenu(this);">
  58.             <xul:menuitem label="&closeTab.label;" accesskey="&closeTab.accesskey;"
  59.                           tbattr="tabbrowser-multiple"
  60.                           oncommand="var tabbrowser = this.parentNode.parentNode.parentNode.parentNode;
  61.                                      tabbrowser.removeTab(tabbrowser.mContextTab);"/>
  62.             <xul:menuitem label="&closeOtherTabs.label;" accesskey="&closeOtherTabs.accesskey;"
  63.                           tbattr="tabbrowser-multiple"
  64.                           oncommand="var tabbrowser = this.parentNode.parentNode.parentNode.parentNode;
  65.                                      tabbrowser.removeAllTabsBut(tabbrowser.mContextTab);"/>
  66.             <xul:menuseparator/>
  67.             <xul:menuitem label="&newTab.label;" accesskey="&newTab.accesskey;"
  68.                           xbl:inherits="oncommand=onnewtab"/>
  69.             <xul:menuseparator/>
  70.             <xul:menuitem label="&bookmarkGroup.label;" accesskey="&bookmarkGroup.accesskey;"
  71.                           tbattr="tabbrowser-multiple"
  72.                           xbl:inherits="oncommand=onbookmarkgroup"/>
  73.             <xul:menuseparator/>
  74.             <xul:menuitem label="&reloadTab.label;" accesskey="&reloadTab.accesskey;"
  75.                           oncommand="var tabbrowser = this.parentNode.parentNode.parentNode.parentNode;
  76.                                      tabbrowser.reloadTab(tabbrowser.mContextTab);"/>
  77.             <xul:menuitem label="&reloadAllTabs.label;" accesskey="&reloadAllTabs.accesskey;"
  78.                           tbattr="tabbrowser-multiple"
  79.                           oncommand="var tabbrowser = this.parentNode.parentNode.parentNode.parentNode;
  80.                                      tabbrowser.reloadAllTabs(tabbrowser.mContextTab);"/>
  81.           </xul:menupopup>
  82.  
  83.           <xul:tabs class="tabbrowser-tabs" closebutton="true" flex="1"
  84.                     tooltiptextnew="&newTabButton.tooltip;"
  85.                     setfocus="false"
  86.                     onclick="this.parentNode.parentNode.parentNode.onTabClick(event);"
  87.                     ondragover="nsDragAndDrop.dragOver(event, this.parentNode.parentNode.parentNode);
  88.                                 event.stopPropagation();"
  89.                     ondragdrop="nsDragAndDrop.drop(event, this.parentNode.parentNode.parentNode);
  90.                                 event.stopPropagation();"
  91.                     xbl:inherits="onnewtab"
  92.                     onclosetab="var node = this.parentNode;
  93.                                 while (node.localName != 'tabbrowser')
  94.                                   node = node.parentNode;
  95.                                 node.removeCurrentTab();">
  96.             <xul:tab selected="true" validate="never"
  97.                      onerror="this.parentNode.parentNode.parentNode.parentNode.addToMissedIconCache(this.getAttribute('image'));
  98.                               this.removeAttribute('image');"
  99.                      maxwidth="250" width="0" minwidth="30" flex="100"
  100.                      class="tabbrowser-tab" label="&untitledTab;" crop="end"/>
  101.           </xul:tabs>
  102.         </xul:hbox>
  103.         <xul:tabpanels flex="1" class="plain" selectedIndex="0">
  104.           <xul:browser type="content-primary" xbl:inherits="tooltip=contenttooltip,contextmenu=contentcontextmenu"/>
  105.         </xul:tabpanels>
  106.       </xul:tabbox>
  107.       <children/>
  108.     </content>
  109.     <implementation>
  110.       <field name="mPrefs" readonly="true">
  111.         Components.classes['@mozilla.org/preferences-service;1']
  112.                   .getService(Components.interfaces.nsIPrefService)
  113.                   .getBranch(null);
  114.       </field>
  115.       <field name="mURIFixup" readonly="true">
  116.         Components.classes["@mozilla.org/docshell/urifixup;1"]
  117.                   .getService(Components.interfaces.nsIURIFixup);
  118.       </field>
  119.       <field name="mTabBox">
  120.         document.getAnonymousNodes(this)[1]
  121.       </field>
  122.       <field name="mStrip">
  123.         this.mTabBox.firstChild
  124.       </field>
  125.       <field name="mTabContainer">
  126.         this.mStrip.childNodes[2]
  127.       </field>
  128.       <field name="mPanelContainer">
  129.         this.mTabBox.childNodes[1]
  130.       </field>
  131.       <field name="mStringBundle">
  132.         document.getAnonymousNodes(this)[0]
  133.       </field>
  134.       <field name="mCurrentTab">
  135.         null
  136.       </field>
  137.       <field name="mCurrentBrowser">
  138.         null
  139.       </field>
  140.       <field name="mProgressListeners">
  141.         null
  142.       </field>
  143.       <field name="mTabListeners">
  144.         new Array()
  145.       </field>
  146.       <field name="mTabFilters">
  147.         new Array()
  148.       </field>
  149.       <field name="mTabbedMode">
  150.         false
  151.       </field>
  152.       <field name="mIsBusy">
  153.         false
  154.       </field>
  155.       <field name="mMissedIconCache">
  156.         null
  157.       </field>
  158.       <field name="mContextTab">
  159.         null
  160.       </field>
  161.  
  162.       <!-- A web progress listener object definition for a given tab. -->
  163.       <method name="mTabProgressListener">
  164.         <parameter name="aTab"/>
  165.         <parameter name="aBrowser"/>
  166.         <parameter name="aStartsBlank"/>
  167.         <body>
  168.         <![CDATA[
  169.           return ({
  170.             mTabBrowser: this,
  171.             mTab: aTab,
  172.             mBrowser: aBrowser,
  173.             mBlank: aStartsBlank,
  174.             mIcon: "",
  175.  
  176.             onProgressChange : function (aWebProgress, aRequest,
  177.                                          aCurSelfProgress, aMaxSelfProgress,
  178.                                          aCurTotalProgress, aMaxTotalProgress)
  179.             {
  180.               if (!this.mBlank && this.mTabBrowser.mCurrentTab == this.mTab) {
  181.                 for (var i = 0; i < this.mTabBrowser.mProgressListeners.length; i++) {
  182.                   var p = this.mTabBrowser.mProgressListeners[i];
  183.                   if (p)
  184.                     p.onProgressChange(aWebProgress, aRequest,
  185.                                        aCurSelfProgress, aMaxSelfProgress,
  186.                                        aCurTotalProgress, aMaxTotalProgress);
  187.                 }
  188.               }
  189.             },
  190.  
  191.             onStateChange : function(aWebProgress, aRequest, aStateFlags, aStatus)
  192.             {
  193.               if (!aRequest)
  194.                 return;
  195.  
  196.               var oldBlank = this.mBlank;
  197.  
  198.               const nsIWebProgressListener = Components.interfaces.nsIWebProgressListener;
  199.               const nsIChannel = Components.interfaces.nsIChannel;
  200.  
  201.               if (aStateFlags & nsIWebProgressListener.STATE_START &&
  202.                   aStateFlags & nsIWebProgressListener.STATE_IS_NETWORK) {
  203.                 // It's okay to clear what the user typed when we start
  204.                 // loading a document. If the user types, this flag gets
  205.                 // set to false, if the document load ends without an
  206.                 // onLocationChange, this flag also gets set to false
  207.                 // (so we keep it while switching tabs after failed load
  208.                 if (aWebProgress.DOMWindow == this.mBrowser.contentWindow)
  209.                   this.mBrowser.userTypedClear++;
  210.  
  211.                 if (!this.mBlank) {
  212.                   this.mTab.setAttribute("busy", "true");
  213.                   this.mTab.label = this.mTabBrowser.mStringBundle.getString("tabs.loading");
  214.                   this.mTab.removeAttribute("image");
  215.                   this.mIcon = "";
  216.  
  217.                   if (this.mTabBrowser.mCurrentTab == this.mTab)
  218.                     this.mTabBrowser.mIsBusy = true;
  219.                 }
  220.               }
  221.               else if (aStateFlags & nsIWebProgressListener.STATE_STOP &&
  222.                        aStateFlags & nsIWebProgressListener.STATE_IS_NETWORK) {
  223.                 // The document is done loading, it's okay to clear
  224.                 // the value again.
  225.                 if (aWebProgress.DOMWindow == this.mBrowser.contentWindow)
  226.                   if (this.mBrowser.userTypedClear > 0)
  227.                     this.mBrowser.userTypedClear--;
  228.  
  229.                 if (this.mBlank)
  230.                   this.mBlank = false;
  231.  
  232.                 this.mTab.removeAttribute("busy");
  233.  
  234.                 var location = aRequest.QueryInterface(nsIChannel).URI;
  235.                 if (this.mIcon) {
  236.                   this.mTab.setAttribute("image", this.mIcon);
  237.                   this.mIcon = "";
  238.                 }
  239.                 else if (this.mTabBrowser.shouldLoadFavIcon(location))
  240.                   this.mTabBrowser.loadFavIcon(location, "image", this.mTab);
  241.  
  242.                 if (this.mTab.label == this.mTabBrowser.mStringBundle.getString("tabs.loading"))
  243.                   this.mTabBrowser.setTabTitle(this.mTab);
  244.  
  245.                 if (this.mTabBrowser.mCurrentTab == this.mTab)
  246.                   this.mTabBrowser.mIsBusy = false;
  247.               }
  248.  
  249.               if (!oldBlank && this.mTabBrowser.mCurrentTab == this.mTab) {
  250.                 for (var i = 0; i < this.mTabBrowser.mProgressListeners.length; i++) {
  251.                   var p = this.mTabBrowser.mProgressListeners[i];
  252.                   if (p)
  253.                     p.onStateChange(aWebProgress, aRequest, aStateFlags, aStatus);
  254.                 }
  255.               }
  256.             },
  257.  
  258.             // The first location change is gotoIndex called from mInstallSH,
  259.             // the second one is considered a user action.
  260.             mLocationChangeCount : 0,
  261.  
  262.             onLocationChange : function(aWebProgress, aRequest, aLocation)
  263.             {
  264.               if (this.mLocationChangeCount > 0 ||
  265.                   aLocation.spec != "about:blank")
  266.                 ++this.mLocationChangeCount;
  267.  
  268.               if (this.mLocationChangeCount == 2) {
  269.                 this.mTabBrowser.backBrowserGroup = [];
  270.                 this.mTabBrowser.forwardBrowserGroup = [];
  271.               }
  272.  
  273.               // The document loaded correctly, clear the value if we should
  274.               if (this.mBrowser.userTypedClear > 0)
  275.                 this.mBrowser.userTypedValue = null;
  276.  
  277.               if (!this.mBlank && this.mTabBrowser.mCurrentTab == this.mTab) {
  278.                 for (var i = 0; i < this.mTabBrowser.mProgressListeners.length; i++) {
  279.                   var p = this.mTabBrowser.mProgressListeners[i];
  280.                   if (p)
  281.                     p.onLocationChange(aWebProgress, aRequest, aLocation);
  282.                 }
  283.               }
  284.             },
  285.  
  286.             onStatusChange : function(aWebProgress, aRequest, aStatus, aMessage)
  287.             {
  288.               if (this.mBlank)
  289.                 return;
  290.  
  291.               if (this.mTabBrowser.mCurrentTab == this.mTab) {
  292.                 for (var i = 0; i < this.mTabBrowser.mProgressListeners.length; i++) {
  293.                   var p = this.mTabBrowser.mProgressListeners[i];
  294.                   if (p)
  295.                     p.onStatusChange(aWebProgress, aRequest, aStatus, aMessage);
  296.                 }
  297.               }
  298.             },
  299.  
  300.             onSecurityChange : function(aWebProgress, aRequest, aState)
  301.             {
  302.               if (this.mTabBrowser.mCurrentTab == this.mTab) {
  303.                 for (var i = 0; i < this.mTabBrowser.mProgressListeners.length; i++) {
  304.                   var p = this.mTabBrowser.mProgressListeners[i];
  305.                   if (p)
  306.                     p.onSecurityChange(aWebProgress, aRequest, aState);
  307.                 }
  308.               }
  309.             },
  310.  
  311.             QueryInterface : function(aIID)
  312.             {
  313.               if (aIID.equals(Components.interfaces.nsIWebProgressListener) ||
  314.                   aIID.equals(Components.interfaces.nsISupportsWeakReference) ||
  315.                   aIID.equals(Components.interfaces.nsISupports))
  316.                 return this;
  317.               throw Components.results.NS_NOINTERFACE;
  318.             }
  319.           });
  320.         ]]>
  321.         </body>
  322.       </method>
  323.  
  324.       <method name="mInstallSH">
  325.         <parameter name="aBrowser"/>
  326.         <parameter name="aSH"/>
  327.         <body>
  328.         <![CDATA[
  329.           return ({
  330.             mBrowser: aBrowser,
  331.             mSH: aSH,
  332.  
  333.             onProgressChange : function (aWebProgress, aRequest,
  334.                                          aCurSelfProgress, aMaxSelfProgress,
  335.                                          aCurTotalProgress, aMaxTotalProgress)
  336.             {
  337.             },
  338.  
  339.             onStateChange : function(aWebProgress, aRequest, aStateFlags, aStatus)
  340.             {
  341.               const nsIWebProgressListener = Components.interfaces.nsIWebProgressListener;
  342.               if ((aStateFlags & nsIWebProgressListener.STATE_IS_NETWORK) &&
  343.                   (aStateFlags & nsIWebProgressListener.STATE_STOP)) {
  344.                 function refresh(closure) {
  345.                   closure.mBrowser.webNavigation.sessionHistory = closure.mSH;
  346.                   closure.mBrowser.webProgress.removeProgressListener(closure);
  347.                   delete closure.mBrowser._SHListener;
  348.                   closure.mSH.QueryInterface(Components.interfaces.nsIWebNavigation)
  349.                          .gotoIndex(closure.mSH.index);
  350.                 }
  351.                 setTimeout(refresh, 0, this);
  352.               }
  353.             },
  354.  
  355.             onLocationChange : function(aWebProgress, aRequest, aLocation)
  356.             {
  357.             },
  358.  
  359.             onStatusChange : function(aWebProgress, aRequest, aStatus, aMessage)
  360.             {
  361.             },
  362.  
  363.             onSecurityChange : function(aWebProgress, aRequest, aState)
  364.             {
  365.             },
  366.  
  367.             QueryInterface : function(aIID)
  368.             {
  369.               if (aIID.equals(Components.interfaces.nsIWebProgressListener) ||
  370.                   aIID.equals(Components.interfaces.nsISupportsWeakReference) ||
  371.                   aIID.equals(Components.interfaces.nsISupports))
  372.                 return this;
  373.               throw Components.results.NS_NOINTERFACE;
  374.             }
  375.           });
  376.         ]]>
  377.         </body>
  378.       </method>
  379.  
  380.       <method name="buildFavIconString">
  381.         <parameter name="aURI"/>
  382.         <body>
  383.           <![CDATA[
  384.             var end = (aURI.port == -1) ? "/favicon.ico" : (":" + aURI.port + "/favicon.ico");
  385.             return aURI.scheme + "://" + aURI.host + end;
  386.           ]]>
  387.         </body>
  388.       </method>
  389.  
  390.       <method name="shouldLoadFavIcon">
  391.         <parameter name="aURI"/>
  392.         <body>
  393.           <![CDATA[
  394.             return (aURI && this.mPrefs.getBoolPref("browser.chrome.site_icons") &&
  395.                     this.mPrefs.getBoolPref("browser.chrome.favicons") &&
  396.                     ("schemeIs" in aURI) && (aURI.schemeIs("http") || aURI.schemeIs("https")));
  397.           ]]>
  398.         </body>
  399.       </method>
  400.  
  401.       <method name="loadFavIcon">
  402.         <parameter name="aURI"/>
  403.         <parameter name="aAttr"/>
  404.         <parameter name="aElt"/>
  405.         <body>
  406.           <![CDATA[
  407.             var iconURL = this.buildFavIconString(aURI);
  408.             var entry = this.openCacheEntry(iconURL, Components.interfaces.nsICache.ACCESS_READ);
  409.             if (!entry)
  410.               aElt.setAttribute(aAttr, iconURL);
  411.             else {
  412.               entry.close();
  413.               entry = null;
  414.             }
  415.           ]]>
  416.         </body>
  417.       </method>
  418.  
  419.       <method name="addToMissedIconCache">
  420.         <parameter name="aURI"/>
  421.         <body>
  422.           <![CDATA[
  423.             var entry = this.openCacheEntry(aURI, Components.interfaces.nsICache.ACCESS_READ_WRITE);
  424.             if (!entry)
  425.               return;
  426.  
  427.             if (entry.accessGranted == Components.interfaces.nsICache.ACCESS_WRITE)
  428.               // It's a new entry.  Just write a bit of metadata in to the entry.
  429.               entry.setMetaDataElement("Icon", "Missed");
  430.             entry.markValid();
  431.             entry.close();
  432.           ]]>
  433.         </body>
  434.       </method>
  435.  
  436.       <method name="openCacheEntry">
  437.         <parameter name="key"/>
  438.         <parameter name="access"/>
  439.         <body>
  440.           <![CDATA[
  441.             try {
  442.               if (!this.mMissedIconCache) {
  443.                 var cacheService = Components.classes['@mozilla.org/network/cache-service;1'].getService(Components.interfaces.nsICacheService);
  444.                 this.mMissedIconCache = cacheService.createSession("MissedIconCache", Components.interfaces.nsICache.STORE_ANYWHERE, true);
  445.                 if (!this.mMissedIconCache)
  446.                   return null;
  447.               }
  448.               return this.mMissedIconCache.openCacheEntry(key, access, true);
  449.             }
  450.             catch (e) {
  451.               return null;
  452.             }
  453.           ]]>
  454.         </body>
  455.       </method>
  456.  
  457.       <method name="updateTitlebar">
  458.         <body>
  459.           <![CDATA[
  460.             var newTitle = "";
  461.             var docTitle;
  462.             if (this.docShell.contentViewer)
  463.               docTitle = this.contentTitle;
  464.  
  465.             if (docTitle) {
  466.               newTitle += this.ownerDocument.documentElement.getAttribute("titlepreface");
  467.               newTitle += docTitle;
  468.               newTitle += this.ownerDocument.documentElement.getAttribute("titlemenuseparator");
  469.             }
  470.             newTitle += this.ownerDocument.documentElement.getAttribute("titlemodifier");
  471.             window.title = newTitle;
  472.           ]]>
  473.         </body>
  474.       </method>
  475.  
  476.       <method name="updatePopupMenu">
  477.         <parameter name="aPopupMenu"/>
  478.         <body>
  479.           <![CDATA[
  480.             this.mContextTab = document.popupNode;
  481.             var disabled = this.mPanelContainer.childNodes.length == 1;
  482.             var menuItems = aPopupMenu.getElementsByAttribute("tbattr", "tabbrowser-multiple");
  483.             for (var i = 0; i < menuItems.length; i++)
  484.               menuItems[i].setAttribute("disabled", disabled);
  485.           ]]>
  486.         </body>
  487.       </method>
  488.  
  489.       <method name="updateCurrentBrowser">
  490.         <body>
  491.           <![CDATA[
  492.             var newBrowser = this.mPanelContainer.childNodes[this.mPanelContainer.selectedIndex];
  493.             if (this.mCurrentBrowser) {
  494.               this.mCurrentBrowser.focusedWindow = document.commandDispatcher.focusedWindow;
  495.               this.mCurrentBrowser.focusedElement = document.commandDispatcher.focusedElement;
  496.               this.mCurrentBrowser.setAttribute("type", "content");
  497.             }
  498.  
  499.             newBrowser.setAttribute("type", "content-primary");
  500.             this.mCurrentBrowser = newBrowser;
  501.             this.mCurrentTab = this.selectedTab;
  502.  
  503.             // Update the URL bar.
  504.             var loc = this.mCurrentBrowser.currentURI;
  505.             var webProgress = this.mCurrentBrowser.webProgress;
  506.             var securityUI = this.mCurrentBrowser.securityUI;
  507.             // Remember the current clear state, then set it to false
  508.             // so we don't clear the userTypedValue when just switching
  509.             // tabs. Set it back to its old state after we're done.
  510.             var userTypedClear = this.mCurrentBrowser.userTypedClear;
  511.             this.mCurrentBrowser.userTypedClear = 0;
  512.             var i, p;
  513.             for (i = 0; i < this.mProgressListeners.length; i++) {
  514.               p = this.mProgressListeners[i];
  515.               if (p) {
  516.                 p.onLocationChange(webProgress, null, loc);
  517.                 if (securityUI)
  518.                   p.onSecurityChange(webProgress, null, securityUI.state);
  519.                 var listener = this.mTabListeners[this.mPanelContainer.selectedIndex];
  520.                 if (listener.mIcon)
  521.                   p.onLinkIconAvailable(listener.mIcon);
  522.               }
  523.             }
  524.             this.mCurrentBrowser.userTypedClear = userTypedClear;
  525.  
  526.             // Update the window title.
  527.             this.updateTitlebar();
  528.  
  529.             // If the new tab is busy, and our current state is not busy, then
  530.             // we need to fire a start to all progress listeners.
  531.             const nsIWebProgressListener = Components.interfaces.nsIWebProgressListener;
  532.             if (this.mCurrentTab.hasAttribute("busy") && !this.mIsBusy) {
  533.               this.mIsBusy = true;
  534.               webProgress = this.mCurrentBrowser.webProgress;
  535.               for (i = 0; i < this.mProgressListeners.length; i++) {
  536.                 p = this.mProgressListeners[i];
  537.                 if (p)
  538.                   p.onStateChange(webProgress, null, nsIWebProgressListener.STATE_START | nsIWebProgressListener.STATE_IS_NETWORK, 0);
  539.               }
  540.             }
  541.  
  542.             // If the new tab is not busy, and our current state is busy, then
  543.             // we need to fire a stop to all progress listeners.
  544.             if (!this.mCurrentTab.hasAttribute("busy") && this.mIsBusy) {
  545.               this.mIsBusy = false;
  546.               webProgress = this.mCurrentBrowser.webProgress;
  547.               for (i = 0; i < this.mProgressListeners.length; i++) {
  548.                 p = this.mProgressListeners[i];
  549.                 if (p)
  550.                   p.onStateChange(webProgress, null, nsIWebProgressListener.STATE_STOP | nsIWebProgressListener.STATE_IS_NETWORK, 0);
  551.               }
  552.             }
  553.  
  554.             function setFocus(element) {
  555.               Components.lookupMethod(element, "focus").call(element);
  556.             }
  557.  
  558.             // Focus the previously focused element or window
  559.             document.commandDispatcher.suppressFocusScroll = true;
  560.             if (newBrowser.focusedElement) {
  561.               try {
  562.                 setFocus(newBrowser.focusedElement);
  563.               } catch (e) {
  564.                 setFocus(newBrowser.focusedWindow);
  565.               }
  566.             }
  567.             else if (newBrowser.focusedWindow)
  568.               setFocus(newBrowser.focusedWindow);
  569.             else // new tab, focus our new content area
  570.               setTimeout(setFocus, 0, window.content);
  571.             document.commandDispatcher.suppressFocusScroll = false;
  572.           ]]>
  573.         </body>
  574.       </method>
  575.  
  576.       <method name="onTabClick">
  577.         <parameter name="event"/>
  578.         <body>
  579.           <![CDATA[
  580.             if (event.button != 1 || event.target.localName != 'tab' ||
  581.                 this.mPrefs.getBoolPref("middlemouse.contentLoadURL"))
  582.               return;
  583.  
  584.             this.removeTab(event.target);
  585.             event.stopPropagation();
  586.           ]]>
  587.         </body>
  588.       </method>
  589.  
  590.       <method name="onLinkAdded">
  591.         <parameter name="event"/>
  592.         <body>
  593.           <![CDATA[
  594.             if (!this.mPrefs.getBoolPref("browser.chrome.site_icons"))
  595.               return;
  596.  
  597.             if (!event.originalTarget.rel.match((/(?:^|\s)icon(?:\s|$)/i)))
  598.               return;
  599.  
  600.             // We have an icon.
  601.             var href = event.originalTarget.href;
  602.             if (!href)
  603.               return;
  604.  
  605.             // Verify that the load of this icon is legal.  We use the same
  606.             // content policy that is used for a Web page loading images.
  607.             var contentPolicy = Components.classes['@mozilla.org/layout/content-policy;1'].getService(Components.interfaces.nsIContentPolicy);
  608.             if (!contentPolicy)
  609.               return; // Refuse to load if we can't do a security check.
  610.  
  611.             // Make a URI out of our href.
  612.             var uri = Components.classes['@mozilla.org/network/standard-url;1'].createInstance();
  613.             uri = uri.QueryInterface(Components.interfaces.nsIURI);
  614.  
  615.             var notifyListeners = true;
  616.             var i;
  617.  
  618.             if (this.mTabbedMode) {
  619.               // We need to update a tab.
  620.               for (i = 0; i < this.browsers.length; i++) {
  621.                 if (this.browsers[i].contentDocument == event.originalTarget.ownerDocument) {
  622.                   if (!contentPolicy.shouldLoad(Components.interfaces.nsIContentPolicy.IMAGE,
  623.                                                 uri, event.originalTarget, this.browsers[i].contentWindow))
  624.                     return;
  625.  
  626.                   this.mTabListeners[i].mIcon = href;
  627.                   notifyListeners = (this.browsers[i] == this.mCurrentBrowser);
  628.                   break;
  629.                 }
  630.               }
  631.             }
  632.             else if (this.contentDocument != event.originalTarget.ownerDocument ||
  633.                      !contentPolicy.shouldLoad(Components.interfaces.nsIContentPolicy.IMAGE,
  634.                                                uri, event.originalTarget, this.mCurrentBrowser.contentWindow))
  635.               return;
  636.  
  637.             if (notifyListeners && this.mProgressListeners) {
  638.               for (i = 0; i < this.mProgressListeners.length; i++) {
  639.                 var p = this.mProgressListeners[i];
  640.                 if (p)
  641.                   p.onLinkIconAvailable(href);
  642.               }
  643.             }
  644.           ]]>
  645.         </body>
  646.       </method>
  647.  
  648.       <method name="onTitleChanged">
  649.         <parameter name="evt"/>
  650.         <body>
  651.           <![CDATA[
  652.             if (evt.target != this.contentDocument)
  653.               return;
  654.  
  655.             var i = 0;
  656.             for ( ; i < this.parentNode.childNodes.length; i++) {
  657.               if (this.parentNode.childNodes[i] == this)
  658.                 break;
  659.             }
  660.  
  661.             var tabBrowser = this.parentNode.parentNode.parentNode;
  662.             var tab = tabBrowser.mTabContainer.childNodes[i];
  663.  
  664.             tabBrowser.setTabTitle(tab);
  665.  
  666.             if (tab == tabBrowser.mCurrentTab)
  667.               tabBrowser.updateTitlebar();
  668.           ]]>
  669.         </body>
  670.       </method>
  671.  
  672.       <method name="setTabTitle">
  673.         <parameter name="aTab"/>
  674.         <body>
  675.           <![CDATA[
  676.             var browser = this.getBrowserForTab(aTab);
  677.             var title = browser.contentTitle;
  678.             var crop = "end";
  679.  
  680.             if (!title) {
  681.               if (browser.currentURI.spec) {
  682.                 try {
  683.                   title = this.mURIFixup.createExposableURI(browser.currentURI).spec;
  684.                 }
  685.                 catch(ex) {
  686.                   title = browser.currentURI.spec;
  687.                 }
  688.               }
  689.  
  690.               if (title && title != "about:blank") {
  691.                 // At this point, we now have a URI.
  692.                 // Let's try to unescape it using a character set
  693.                 // in case the URI is not ASCII.
  694.                 try {
  695.                   var characterSet = Components.lookupMethod(browser.contentDocument, 'characterSet')
  696.                                                .call(browser.contentDocument);
  697.                   const textToSubURI = Components.classes["@mozilla.org/intl/texttosuburi;1"]
  698.                                                  .getService(Components.interfaces.nsITextToSubURI);
  699.                   title = textToSubURI.unEscapeNonAsciiURI(characterSet, title);
  700.                 }
  701.                 catch(ex) {
  702.                   // Do nothing.
  703.                 }
  704.  
  705.                 crop = "center";
  706.               } else // Still no title?  Fall back to our untitled string.
  707.                 title = this.mStringBundle.getString("tabs.untitled");
  708.             }
  709.  
  710.             aTab.label = title;
  711.             aTab.setAttribute("crop", crop);
  712.           ]]>
  713.         </body>
  714.       </method>
  715.  
  716.       <method name="setStripVisibilityTo">
  717.         <parameter name="aShow"/>
  718.         <body>
  719.         <![CDATA[
  720.           this.mStrip.collapsed = !aShow;
  721.           if (aShow) {
  722.             if (!this.mTabbedMode)
  723.               this.enterTabbedMode();
  724.           }
  725.         ]]>
  726.         </body>
  727.       </method>
  728.  
  729.       <method name="getStripVisibility">
  730.         <body>
  731.           return !this.mStrip.collapsed;
  732.         </body>
  733.       </method>
  734.  
  735.       <method name="enterTabbedMode">
  736.         <body>
  737.           <![CDATA[
  738.             this.mTabbedMode = true; // Welcome to multi-tabbed mode.
  739.  
  740.             // Get the first tab all hooked up with a title listener.
  741.             this.mCurrentBrowser.addEventListener("DOMTitleChanged", this.onTitleChanged, false);
  742.  
  743.             this.setTabTitle(this.mCurrentTab);
  744.  
  745.             // Hook up our favicon.
  746.             var uri = this.mCurrentBrowser.currentURI;
  747.             if (this.shouldLoadFavIcon(uri))
  748.               this.loadFavIcon(uri, "image", this.mCurrentTab);
  749.  
  750.             var filter;
  751.             if (this.mTabFilters.length > 0) {
  752.               // Use the filter hooked up in our addProgressListener
  753.               filter = this.mTabFilters[0];
  754.             } else {
  755.               // create a filter and hook it up to our first browser
  756.               filter = Components.classes["@mozilla.org/appshell/component/browser-status-filter;1"]
  757.                                  .createInstance(Components.interfaces.nsIWebProgress);
  758.               this.mTabFilters[0] = filter;
  759.               this.mCurrentBrowser.webProgress.addProgressListener(filter, Components.interfaces.nsIWebProgress.NOTIFY_ALL);
  760.             }
  761.  
  762.             // Remove all our progress listeners from the active browser's filter.
  763.             if (this.mProgressListeners) {
  764.               for (var i = 0; i < this.mProgressListeners.length; i++) {
  765.                 var p = this.mProgressListeners[i];
  766.                 if (p)
  767.                   filter.removeProgressListener(p);
  768.               }
  769.             }
  770.  
  771.             // Wire up a progress listener to our filter.
  772.             const listener = this.mTabProgressListener(this.mCurrentTab,
  773.                                                        this.mCurrentBrowser,
  774.                                                        false);
  775.             filter.addProgressListener(listener, Components.interfaces.nsIWebProgress.NOTIFY_ALL);
  776.             this.mTabListeners[0] = listener;
  777.           ]]>
  778.         </body>
  779.       </method>
  780.  
  781.       <method name="addTab">
  782.         <parameter name="aURI"/>
  783.         <parameter name="aReferrerURI"/>
  784.         <parameter name="aCharset"/>
  785.         <body>
  786.           <![CDATA[
  787.             if (!this.mTabbedMode)
  788.               this.enterTabbedMode();
  789.  
  790.             var t = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
  791.                                              "tab");
  792.  
  793.             var blank = (aURI == "about:blank");
  794.  
  795.             if (blank)
  796.               t.setAttribute("label", this.mStringBundle.getString("tabs.untitled"));
  797.             else
  798.               t.setAttribute("label", aURI);
  799.  
  800.             t.setAttribute("crop", "end");
  801.             t.maxWidth = 250;
  802.             t.minWidth = 30;
  803.             t.width = 0;
  804.             t.setAttribute("flex", "100");
  805.             t.setAttribute("validate", "never");
  806.             t.setAttribute("onerror", "this.parentNode.parentNode.parentNode.parentNode.addToMissedIconCache(this.getAttribute('image')); this.removeAttribute('image');");
  807.             this.mTabContainer.appendChild(t);
  808.  
  809.             var b = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
  810.                                              "browser");
  811.             b.setAttribute("type", "content");
  812.             b.setAttribute("contextmenu", this.getAttribute("contentcontextmenu"));
  813.             b.setAttribute("tooltip", this.getAttribute("contenttooltip"));
  814.  
  815.             this.mPanelContainer.appendChild(b);
  816.  
  817.             b.addEventListener("DOMTitleChanged", this.onTitleChanged, false);
  818.  
  819.             if (this.mStrip.collapsed)
  820.               this.setStripVisibilityTo(true);
  821.  
  822.             this.mPrefs.setBoolPref("browser.tabs.forceHide", false);
  823.  
  824.             // wire up a progress listener for the new browser object.
  825.             var position = this.mTabContainer.childNodes.length-1;
  826.             var tabListener = this.mTabProgressListener(t, b, blank);
  827.             const filter = Components.classes["@mozilla.org/appshell/component/browser-status-filter;1"]
  828.                                      .createInstance(Components.interfaces.nsIWebProgress);
  829.             filter.addProgressListener(tabListener, Components.interfaces.nsIWebProgress.NOTIFY_ALL);
  830.             b.webProgress.addProgressListener(filter, Components.interfaces.nsIWebProgress.NOTIFY_ALL);
  831.             this.mTabListeners[position] = tabListener;
  832.             this.mTabFilters[position] = filter;
  833.  
  834.             if (!blank) {
  835.               // pretend the user typed this so it'll be available till
  836.               // the document successfully loads
  837.               b.userTypedValue = aURI;
  838.  
  839.               b.loadURI(aURI, aReferrerURI, aCharset);
  840.             }
  841.  
  842.             return t;
  843.           ]]>
  844.         </body>
  845.       </method>
  846.  
  847.       <method name="removeAllTabsBut">
  848.         <parameter name="aTab"/>
  849.         <body>
  850.           <![CDATA[
  851.             if (aTab.localName != "tab")
  852.               aTab = this.mCurrentTab;
  853.             else
  854.               this.mTabContainer.selectedItem = aTab;
  855.  
  856.             var childNodes = this.mTabContainer.childNodes;
  857.             for (var i = childNodes.length - 1; i >= 0; --i) {
  858.               if (childNodes[i] != aTab)
  859.                 this.removeTab(childNodes[i]);
  860.             }
  861.           ]]>
  862.         </body>
  863.       </method>
  864.  
  865.       <method name="removeCurrentTab">
  866.         <body>
  867.           <![CDATA[
  868.             return this.removeTab(this.mCurrentTab);
  869.           ]]>
  870.         </body>
  871.       </method>
  872.  
  873.       <method name="removeTab">
  874.         <parameter name="aTab"/>
  875.         <body>
  876.           <![CDATA[
  877.             if (aTab.localName != "tab")
  878.               aTab = this.mCurrentTab;
  879.  
  880.             var l = this.mTabContainer.childNodes.length;
  881.             if (l == 1) {
  882.               // hide the tab bar
  883.               this.mPrefs.setBoolPref("browser.tabs.forceHide", true);
  884.               this.setStripVisibilityTo(false);
  885.               return;
  886.             }
  887.  
  888.             var ds = this.getBrowserForTab(aTab).docShell;
  889.  
  890.             if (ds.contentViewer && !ds.contentViewer.permitUnload())
  891.               return;
  892.  
  893.             if (l == 2) {
  894.               var autohide = this.mPrefs.getBoolPref("browser.tabs.autoHide");
  895.               if (autohide)
  896.                 this.setStripVisibilityTo(false);
  897.             }
  898.  
  899.             var index = -1;
  900.             if (this.mCurrentTab == aTab)
  901.               index = this.mPanelContainer.selectedIndex;
  902.             else {
  903.               // Find and locate the tab in our list.
  904.               for (var i = 0; i < l; i++)
  905.                 if (this.mTabContainer.childNodes[i] == aTab)
  906.                   index = i;
  907.             }
  908.  
  909.             // Remove the tab's filter and progress listener.
  910.             const filter = this.mTabFilters[index];
  911.             var oldBrowser = this.mPanelContainer.childNodes[index];
  912.             oldBrowser.webProgress.removeProgressListener(filter);
  913.             filter.removeProgressListener(this.mTabListeners[index]);
  914.             this.mTabFilters.splice(index, 1);
  915.             this.mTabListeners.splice(index, 1);
  916.  
  917.             // Remove our title change listener
  918.             oldBrowser.removeEventListener("DOMTitleChanged", this.onTitleChanged, false);
  919.  
  920.             // We are no longer the primary content area.
  921.             oldBrowser.setAttribute("type", "content");
  922.  
  923.             // Now select the new tab before nuking the old one.
  924.             var currentIndex = this.mPanelContainer.selectedIndex;
  925.  
  926.             var newIndex = -1;
  927.             if (currentIndex > index)
  928.               newIndex = currentIndex-1;
  929.             else if (currentIndex < index)
  930.               newIndex = currentIndex;
  931.             else if (index == l - 1)
  932.               newIndex = index-1;
  933.             else
  934.               newIndex = index;
  935.  
  936.             var oldTab = aTab;
  937.  
  938.             // clean up the before/afterselected attributes before removing the tab
  939.             oldTab.selected = false;
  940.  
  941.             this.mTabContainer.removeChild(oldTab);
  942.             this.mPanelContainer.removeChild(oldBrowser);
  943.  
  944.             // When the current tab is removed select a new tab
  945.             // and fire select events on tabpanels and tabs
  946.             this.mTabContainer.selectedIndex = newIndex;
  947.  
  948.             // When removing a tab to the left of the current tab
  949.             // fix up the panel index without firing any events
  950.             this.mPanelContainer.selectedIndex = newIndex;
  951.           ]]>
  952.         </body>
  953.       </method>
  954.  
  955.       <method name="reloadAllTabs">
  956.         <body>
  957.           <![CDATA[
  958.             var l = this.mPanelContainer.childNodes.length;
  959.             for (var i = 0; i < l; i++) {
  960.               try {
  961.                 this.mPanelContainer.childNodes[i].reload();
  962.               } catch (e) {
  963.                 // ignore failure to reload so others will be reloaded
  964.               }
  965.             }
  966.           ]]>
  967.         </body>
  968.       </method>
  969.  
  970.       <method name="reloadTab">
  971.         <parameter name="aTab"/>
  972.         <body>
  973.           <![CDATA[
  974.             if (aTab.localName != "tab")
  975.               aTab = this.mCurrentTab;
  976.  
  977.             this.getBrowserForTab(aTab).reload();
  978.           ]]>
  979.         </body>
  980.       </method>
  981.  
  982.       <method name="addProgressListener">
  983.         <parameter name="aListener"/>
  984.         <parameter name="aMask"/>
  985.         <body>
  986.           <![CDATA[
  987.             if (!this.mProgressListeners) {
  988.               this.mProgressListeners = [];
  989.               const autoHide = this.mPrefs.getBoolPref("browser.tabs.autoHide");
  990.               const forceHide = this.mPrefs.getBoolPref("browser.tabs.forceHide");
  991.               if (!autoHide && !forceHide)
  992.                 this.setStripVisibilityTo(true);
  993.             }
  994.  
  995.             if (!this.mTabbedMode && this.mProgressListeners.length == 1) {
  996.               // If we are adding a 2nd progress listener, we need to enter tabbed mode
  997.               // because the browser status filter can only handle one progress listener.
  998.               // In tabbed mode, mTabProgressListener is used which will iterate over all listeners.
  999.               this.enterTabbedMode();
  1000.             }
  1001.  
  1002.             this.mProgressListeners.push(aListener);
  1003.  
  1004.             if (!this.mTabbedMode) {
  1005.               // If someone does this:
  1006.               // addProgressListener, removeProgressListener, addProgressListener
  1007.               // don't create a new filter; reuse the existing filter.
  1008.               if (this.mTabFilters.length == 0) {
  1009.                 // hook a filter up to our first browser
  1010.                 const filter = Components.classes["@mozilla.org/appshell/component/browser-status-filter;1"]
  1011.                                          .createInstance(Components.interfaces.nsIWebProgress);
  1012.                 this.mTabFilters[0] = filter;
  1013.                 this.mCurrentBrowser.webProgress.addProgressListener(filter, Components.interfaces.nsIWebProgress.NOTIFY_ALL);
  1014.               }
  1015.  
  1016.               // Directly hook the listener up to the filter for better performance
  1017.               this.mTabFilters[0].addProgressListener(aListener, aMask);
  1018.             }
  1019.           ]]>
  1020.         </body>
  1021.       </method>
  1022.  
  1023.       <method name="removeProgressListener">
  1024.         <parameter name="aListener"/>
  1025.         <body>
  1026.           <![CDATA[
  1027.             if (!this.mProgressListeners) return;
  1028.             for (var i = 0; i < this.mProgressListeners.length; i++) {
  1029.               if (this.mProgressListeners[i] == aListener) {
  1030.                 this.mProgressListeners[i] = null;
  1031.                 break;
  1032.               }
  1033.             }
  1034.  
  1035.             if (!this.mTabbedMode)
  1036.               // Don't forget to remove it from the filter we hooked it up to
  1037.               this.mTabFilters[0].removeProgressListener(aListener);
  1038.          ]]>
  1039.         </body>
  1040.       </method>
  1041.  
  1042.       <method name="getBrowserForTab">
  1043.         <parameter name="aTab"/>
  1044.         <body>
  1045.         <![CDATA[
  1046.           if (this.mCurrentTab == aTab)
  1047.             return this.mCurrentBrowser;
  1048.  
  1049.           for (var i = 0; i < this.mTabContainer.childNodes.length; i++) {
  1050.             if (this.mTabContainer.childNodes[i] == aTab) {
  1051.               return this.mPanelContainer.childNodes[i];
  1052.             }
  1053.           }
  1054.  
  1055.           return null;
  1056.         ]]>
  1057.         </body>
  1058.       </method>
  1059.  
  1060.       <property name="tabContainer">
  1061.         <getter>
  1062.           return this.mTabContainer;
  1063.         </getter>
  1064.       </property>
  1065.  
  1066.       <property name="selectedTab">
  1067.         <getter>
  1068.           return this.mTabBox.selectedTab;
  1069.         </getter>
  1070.         <setter>
  1071.           <![CDATA[
  1072.           // Update the tab
  1073.           this.mTabBox.selectedTab = val;
  1074.           return val;
  1075.           ]]>
  1076.         </setter>
  1077.       </property>
  1078.  
  1079.       <property name="selectedBrowser"
  1080.                 onget="return this.mCurrentBrowser;"
  1081.                 readonly="true"/>
  1082.  
  1083.  
  1084.       <property name="browsers"
  1085.                 onget="return this.mPanelContainer.childNodes;"
  1086.                 readonly="true"/>
  1087.  
  1088.       <!-- Drag and drop observer API -->
  1089.       <!--<method name="onDragStart">
  1090.         <parameter name="aEvent"/>
  1091.         <parameter name="aXferData"/>
  1092.         <parameter name="aDragAction"/>
  1093.         <body/>
  1094.       </method>-->
  1095.  
  1096.       <method name="onDragOver">
  1097.         <parameter name="aEvent"/>
  1098.         <parameter name="aFlavour"/>
  1099.         <parameter name="aDragSession"/>
  1100.         <body>
  1101.         <![CDATA[
  1102.           return; // Just having this makes our feedback correct.
  1103.         ]]>
  1104.         </body>
  1105.       </method>
  1106.  
  1107.       <method name="onDrop">
  1108.         <parameter name="aEvent"/>
  1109.         <parameter name="aXferData"/>
  1110.         <parameter name="aDragSession"/>
  1111.         <body>
  1112.           <![CDATA[
  1113.             var url = transferUtils.retrieveURLFromData(aXferData.data, aXferData.flavour.contentType);
  1114.  
  1115.             // valid urls don't contain spaces ' '; if we have a space it isn't a valid url so bail out
  1116.             if (!url || !url.length || url.indexOf(" ", 0) != -1)
  1117.               return;
  1118.  
  1119.             var bgLoad = this.mPrefs.getBoolPref("browser.tabs.loadInBackground");
  1120.  
  1121.             var tab = null;
  1122.             if (aEvent.originalTarget.localName != "tab") {
  1123.               // We're adding a new tab.
  1124.               tab = this.addTab(getShortcutOrURI(url));
  1125.             }
  1126.             else {
  1127.               // Load in an existing tab.
  1128.               tab = aEvent.originalTarget;
  1129.               this.getBrowserForTab(tab).loadURI(getShortcutOrURI(url));
  1130.             }
  1131.             if (this.mCurrentTab != tab && !bgLoad)
  1132.               this.selectedTab = tab;
  1133.           ]]>
  1134.         </body>
  1135.       </method>
  1136.  
  1137.       <method name="getSupportedFlavours">
  1138.         <body>
  1139.         <![CDATA[
  1140.           var flavourSet = new FlavourSet();
  1141.           flavourSet.appendFlavour("text/x-moz-url");
  1142.           flavourSet.appendFlavour("text/unicode");
  1143.           flavourSet.appendFlavour("application/x-moz-file", "nsIFile");
  1144.           return flavourSet;
  1145.         ]]>
  1146.         </body>
  1147.       </method>
  1148.  
  1149.       <field name="backBrowserGroup">
  1150.         []
  1151.       </field>
  1152.  
  1153.       <field name="forwardBrowserGroup">
  1154.         []
  1155.       </field>
  1156.  
  1157.       <method name="replaceGroup">
  1158.         <parameter name="aGroup"/>
  1159.         <body>
  1160.         <![CDATA[
  1161.           var oldBrowserGroup = [];
  1162.           var oldCount = this.mPanelContainer.childNodes.length;
  1163.           var newCount = aGroup.length;
  1164.           var n = Math.max(oldCount, newCount);
  1165.           for (var i = 0; i < n; ++i) {
  1166.             if (i < newCount) {
  1167.               var data = aGroup[i];
  1168.               if ("sessionHistory" in data) {
  1169.                 this.addTab("about:blank", null);
  1170.                 var browser = this.mPanelContainer.lastChild;
  1171.                 // need to hold on to the listener so it won't go away
  1172.                 // addProgressListener only has a weak pointer to it
  1173.                 browser._SHListener =
  1174.                     this.mInstallSH(browser, aGroup[i].sessionHistory);
  1175.                 browser.webProgress.addProgressListener(browser._SHListener, Components.interfaces.nsIWebProgress.NOTIFY_ALL);
  1176.               } else {
  1177.                 var referrerURI = "referrerURI" in data ? data.referrerURI : null;
  1178.                 this.addTab(data.URI, referrerURI);
  1179.               }
  1180.             }
  1181.             if (i < oldCount) {
  1182.               var browserData = {
  1183.                 sessionHistory : this.mPanelContainer.firstChild.sessionHistory
  1184.               }
  1185.               oldBrowserGroup.push(browserData);
  1186.               this.removeTab(this.mTabContainer.firstChild);
  1187.             }
  1188.           }
  1189.           return oldBrowserGroup;
  1190.         ]]>
  1191.         </body>
  1192.       </method>
  1193.  
  1194.       <method name="appendGroup">
  1195.         <parameter name="aGroup"/>
  1196.         <body>
  1197.         <![CDATA[
  1198.           for (var i in aGroup) {
  1199.             var page = aGroup[i];
  1200.             var referrerURI = "referrerURI" in page ? page.referrerURI : null;
  1201.             this.addTab(page.URI, referrerURI);
  1202.           }
  1203.         ]]>
  1204.         </body>
  1205.       </method>
  1206.  
  1207.       <method name="loadGroup">
  1208.         <parameter name="aGroup"/>
  1209.         <body>
  1210.         <![CDATA[
  1211.           if (aGroup.length == 0)
  1212.             return null;
  1213.  
  1214.           var tab;
  1215.           if (this.mPrefs.getIntPref("browser.tabs.loadGroup") == 0) {
  1216.             var oldCount = this.mTabContainer.childNodes.length;
  1217.             this.appendGroup(aGroup);
  1218.             tab = this.mTabContainer.childNodes[oldCount];
  1219.           } else {
  1220.             this.backBrowserGroup = this.replaceGroup(aGroup);
  1221.             this.forwardBrowserGroup = [];
  1222.             tab = this.mTabContainer.firstChild;
  1223.           }
  1224.           return tab;
  1225.         ]]>
  1226.         </body>
  1227.       </method>
  1228.  
  1229.       <method name="goBackGroup">
  1230.         <body>
  1231.         <![CDATA[
  1232.           this.forwardBrowserGroup = this.replaceGroup(this.backBrowserGroup);
  1233.           this.backBrowserGroup = [];
  1234.         ]]>
  1235.         </body>
  1236.       </method>
  1237.  
  1238.       <method name="goForwardGroup">
  1239.         <body>
  1240.         <![CDATA[
  1241.           this.backBrowserGroup = this.replaceGroup(this.forwardBrowserGroup);
  1242.           this.forwardBrowserGroup = [];
  1243.         ]]>
  1244.         </body>
  1245.       </method>
  1246.  
  1247.       <!-- BEGIN FORWARDED BROWSER PROPERTIES.  IF YOU ADD A PROPERTY TO THE BROWSER ELEMENT
  1248.            MAKE SURE TO ADD IT HERE AS WELL. -->
  1249.       <property name="canGoBack"
  1250.                 onget="return this.backBrowserGroup.length != 0 || this.mCurrentBrowser.canGoBack;"
  1251.                 readonly="true"/>
  1252.  
  1253.       <property name="canGoForward"
  1254.                 onget="return this.forwardBrowserGroup.length != 0 || this.mCurrentBrowser.canGoForward;"
  1255.                 readonly="true"/>
  1256.  
  1257.       <method name="goBack">
  1258.         <body>
  1259.           <![CDATA[
  1260.             if (this.backBrowserGroup.length != 0)
  1261.               return this.goBackGroup();
  1262.  
  1263.             return this.mCurrentBrowser.goBack();
  1264.           ]]>
  1265.         </body>
  1266.       </method>
  1267.  
  1268.       <method name="goForward">
  1269.         <body>
  1270.           <![CDATA[
  1271.             if (this.forwardBrowserGroup.length != 0)
  1272.               return this.goForwardGroup();
  1273.  
  1274.             return this.mCurrentBrowser.goForward();
  1275.           ]]>
  1276.         </body>
  1277.       </method>
  1278.  
  1279.       <method name="reload">
  1280.         <body>
  1281.           <![CDATA[
  1282.             return this.mCurrentBrowser.reload();
  1283.           ]]>
  1284.         </body>
  1285.       </method>
  1286.  
  1287.       <method name="reloadWithFlags">
  1288.         <parameter name="aFlags"/>
  1289.         <body>
  1290.           <![CDATA[
  1291.             return this.mCurrentBrowser.reloadWithFlags(aFlags);
  1292.           ]]>
  1293.         </body>
  1294.       </method>
  1295.  
  1296.       <method name="stop">
  1297.         <body>
  1298.           <![CDATA[
  1299.             return this.mCurrentBrowser.stop();
  1300.           ]]>
  1301.         </body>
  1302.       </method>
  1303.  
  1304.       <!-- throws exception for unknown schemes -->
  1305.       <method name="loadURI">
  1306.         <parameter name="aURI"/>
  1307.         <parameter name="aReferrerURI"/>
  1308.         <parameter name="aCharset"/>
  1309.         <body>
  1310.           <![CDATA[
  1311.             return this.mCurrentBrowser.loadURI(aURI, aReferrerURI, aCharset);
  1312.           ]]>
  1313.         </body>
  1314.       </method>
  1315.  
  1316.       <!-- throws exception for unknown schemes -->
  1317.       <method name="loadURIWithFlags">
  1318.         <parameter name="aURI"/>
  1319.         <parameter name="aFlags"/>
  1320.         <parameter name="aReferrerURI"/>
  1321.         <parameter name="aCharset"/>
  1322.         <body>
  1323.           <![CDATA[
  1324.             return this.mCurrentBrowser.loadURIWithFlags(aURI, aFlags, aReferrerURI, aCharset);
  1325.           ]]>
  1326.         </body>
  1327.       </method>
  1328.  
  1329.       <method name="goHome">
  1330.         <body>
  1331.           <![CDATA[
  1332.             return this.mCurrentBrowser.goHome();
  1333.           ]]>
  1334.         </body>
  1335.       </method>
  1336.  
  1337.       <property name="homePage">
  1338.         <getter>
  1339.           <![CDATA[
  1340.             return this.mCurrentBrowser.homePage;
  1341.           ]]>
  1342.         </getter>
  1343.         <setter>
  1344.           <![CDATA[
  1345.             this.mCurrentBrowser.homePage = val;
  1346.             return val;
  1347.           ]]>
  1348.         </setter>
  1349.       </property>
  1350.  
  1351.       <method name="gotoIndex">
  1352.         <parameter name="aIndex"/>
  1353.         <body>
  1354.           <![CDATA[
  1355.             return this.mCurrentBrowser.gotoIndex(aIndex);
  1356.           ]]>
  1357.         </body>
  1358.       </method>
  1359.  
  1360.       <property name="currentURI"
  1361.                 onget="return this.mCurrentBrowser.currentURI;"
  1362.                 readonly="true"/>
  1363.  
  1364.       <property name="docShell"
  1365.                 onget="return this.mCurrentBrowser.docShell"
  1366.                 readonly="true"/>
  1367.  
  1368.       <property name="webNavigation"
  1369.                 onget="return this.mCurrentBrowser.webNavigation"
  1370.                 readonly="true"/>
  1371.  
  1372.       <property name="webBrowserFind"
  1373.                 readonly="true"
  1374.                 onget="return this.mCurrentBrowser.webBrowserFind"/>
  1375.  
  1376.       <property name="webProgress"
  1377.                 readonly="true"
  1378.                 onget="return this.mCurrentBrowser.webProgress"/>
  1379.  
  1380.       <property name="contentWindow"
  1381.                 readonly="true"
  1382.                 onget="return this.mCurrentBrowser.contentWindow"/>
  1383.  
  1384.       <property name="sessionHistory"
  1385.                 onget="return this.mCurrentBrowser.sessionHistory;"
  1386.                 readonly="true"/>
  1387.  
  1388.       <property name="markupDocumentViewer"
  1389.                 onget="return this.mCurrentBrowser.markupDocumentViewer;"
  1390.                 readonly="true"/>
  1391.  
  1392.       <property name="contentViewerEdit"
  1393.                 onget="return this.mCurrentBrowser.contentViewerEdit;"
  1394.                 readonly="true"/>
  1395.  
  1396.       <property name="contentViewerFile"
  1397.                 onget="return this.mCurrentBrowser.contentViewerFile;"
  1398.                 readonly="true"/>
  1399.  
  1400.       <property name="documentCharsetInfo"
  1401.                 onget="return this.mCurrentBrowser.documentCharsetInfo;"
  1402.                 readonly="true"/>
  1403.  
  1404.       <property name="contentDocument"
  1405.                 onget="return this.mCurrentBrowser.contentDocument;"
  1406.                 readonly="true"/>
  1407.  
  1408.       <property name="contentTitle"
  1409.                 onget="return this.mCurrentBrowser.contentTitle;"
  1410.                 readonly="true"/>
  1411.  
  1412.       <property name="securityUI"
  1413.                 onget="return this.mCurrentBrowser.securityUI;"
  1414.                 readonly="true"/>
  1415.  
  1416.       <property name="userTypedClear"
  1417.                 onget="return this.mCurrentBrowser.userTypedClear;"
  1418.                 onset="return this.mCurrentBrowser.userTypedClear = val;"/>
  1419.  
  1420.       <property name="userTypedValue"
  1421.                 onget="return this.mCurrentBrowser.userTypedValue;"
  1422.                 onset="return this.mCurrentBrowser.userTypedValue = val;"/>
  1423.  
  1424.       <constructor>
  1425.         <![CDATA[
  1426.           this.mCurrentBrowser = this.mPanelContainer.firstChild;
  1427.           this.mCurrentTab = this.mTabContainer.firstChild;
  1428.           this.mTabBox.handleCtrlTab = !/Mac/.test(navigator.platform);
  1429.         ]]>
  1430.       </constructor>
  1431.  
  1432.       <destructor>
  1433.         <![CDATA[
  1434.           for (var i = 0; i < this.mTabListeners.length; ++i) {
  1435.             this.mPanelContainer.childNodes[i].webProgress.removeProgressListener(this.mTabFilters[i]);
  1436.             this.mTabFilters[i].removeProgressListener(this.mTabListeners[i]);
  1437.             this.mTabFilters[i] = null;
  1438.             this.mTabListeners[i] = null;
  1439.             this.mPanelContainer.childNodes[i].removeEventListener("DOMTitleChanged", this.onTitleChanged, false);
  1440.           }
  1441.         ]]>
  1442.       </destructor>
  1443.     </implementation>
  1444.  
  1445.     <handlers>
  1446.       <handler event="select" action="if (event.originalTarget == this.mPanelContainer) this.updateCurrentBrowser();"/>
  1447.  
  1448.       <handler event="DOMLinkAdded" action="this.onLinkAdded(event);"/>
  1449.  
  1450.       <handler event="keypress" modifiers="control" keycode="VK_F4">
  1451.         <![CDATA[
  1452.           if (this.mTabBox.handleCtrlPageUpDown)
  1453.             this.removeCurrentTab();
  1454.         ]]>
  1455.       </handler>
  1456.  
  1457.       <handler event="DOMWindowClose">
  1458.         <![CDATA[
  1459.           if (!event.isTrusted)
  1460.             return;
  1461.  
  1462.           const browsers = this.browsers;
  1463.           if (browsers.length == 1)
  1464.             return;
  1465.           var i = 0;
  1466.           for (; i < browsers.length; ++i) {
  1467.             if (browsers[i].contentWindow == event.target)
  1468.               break;
  1469.           }
  1470.           this.removeTab(this.mTabContainer.childNodes[i]);
  1471.           event.preventDefault();
  1472.         ]]>
  1473.       </handler>
  1474.       <handler event="DOMWillOpenModalDialog">
  1475.         <![CDATA[
  1476.           if (!event.isTrusted)
  1477.             return;
  1478.  
  1479.           // We're about to open a modal dialog, make sure the opening
  1480.           // tab is brought to the front.
  1481.  
  1482.           const browsers = this.browsers;
  1483.           for (var i = 0; i < browsers.length; ++i) {
  1484.             if (browsers[i].contentWindow == event.target) {
  1485.               this.selectedTab = this.mTabContainer.childNodes[i];
  1486.  
  1487.               break;
  1488.             }
  1489.           }
  1490.         ]]>
  1491.       </handler>
  1492.     </handlers>
  1493.   </binding>
  1494.  
  1495. </bindings>
  1496.