]> git.donarmstrong.com Git - x_full.git/blobdiff - .mozilla/firefox/default/extensions/vertical-tabbar@dark-demon.nm.ru/chrome/vertical-tabbar/content/browser.xbl
add various extensions
[x_full.git] / .mozilla / firefox / default / extensions / vertical-tabbar@dark-demon.nm.ru / chrome / vertical-tabbar / content / browser.xbl
diff --git a/.mozilla/firefox/default/extensions/vertical-tabbar@dark-demon.nm.ru/chrome/vertical-tabbar/content/browser.xbl b/.mozilla/firefox/default/extensions/vertical-tabbar@dark-demon.nm.ru/chrome/vertical-tabbar/content/browser.xbl
new file mode 100644 (file)
index 0000000..ca14bf9
--- /dev/null
@@ -0,0 +1,2358 @@
+<?xml version="1.0"?>
+
+<!DOCTYPE bindings [
+<!ENTITY % tabBrowserDTD SYSTEM "chrome://global/locale/tabbrowser.dtd" >
+%tabBrowserDTD;
+<!ENTITY % globalDTD SYSTEM "chrome://global/locale/global.dtd">
+%globalDTD;
+]>
+
+<bindings id="vertical-tabbar-bindings"
+          xmlns="http://www.mozilla.org/xbl"
+          xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+          xmlns:xbl="http://www.mozilla.org/xbl">
+
+
+
+  <binding id="tabbrowser">
+    <content>
+      <xul:stringbundle anonid="tbstringbundle" src="chrome://global/locale/tabbrowser.properties"/>
+      <xul:tabbox anonid="tabbox" flex="1" eventnode="document" xbl:inherits="handleCtrlPageUpDown"
+                  onselect="if (!('updateCurrentBrowser' in this.parentNode) || event.target.localName != 'tabpanels') return; this.parentNode.updateCurrentBrowser();">
+        <xul:vbox class="tabbrowser-strip" collapsed="true" tooltip="_child" context="_child"
+                  anonid="strip" width="102" orient="vertical"
+                  ondraggesture="nsDragAndDrop.startDrag(event, this.parentNode.parentNode); event.stopPropagation();"
+                  ondragover="nsDragAndDrop.dragOver(event, this.parentNode.parentNode); event.stopPropagation();"
+                  ondragdrop="nsDragAndDrop.drop(event, this.parentNode.parentNode); event.stopPropagation();"
+                  ondragexit="nsDragAndDrop.dragExit(event, this.parentNode.parentNode); event.stopPropagation();">
+          <xul:tooltip onpopupshowing="return this.parentNode.parentNode.parentNode.createTooltip(event);"/>
+          <xul:menupopup anonid="tabContextMenu" onpopupshowing="this.parentNode.parentNode.parentNode.updatePopupMenu(this);">
+            <xul:menuitem label="&newTab.label;" accesskey="&newTab.accesskey;"
+                          xbl:inherits="oncommand=onnewtab"/>
+            <xul:menuseparator/>
+            <xul:menuitem label="&reloadTab.label;" accesskey="&reloadTab.accesskey;"
+                          oncommand="var tabbrowser = this.parentNode.parentNode.parentNode.parentNode;
+                                     tabbrowser.reloadTab(tabbrowser.mContextTab);"/>
+            <xul:menuitem label="&reloadAllTabs.label;" accesskey="&reloadAllTabs.accesskey;"
+                          tbattr="tabbrowser-multiple"
+                          oncommand="var tabbrowser = this.parentNode.parentNode.parentNode.parentNode;
+                                     tabbrowser.reloadAllTabs(tabbrowser.mContextTab);"/>
+            <xul:menuitem label="&closeOtherTabs.label;" accesskey="&closeOtherTabs.accesskey;"
+                          tbattr="tabbrowser-multiple"
+                          oncommand="var tabbrowser = this.parentNode.parentNode.parentNode.parentNode;
+                                     tabbrowser.removeAllTabsBut(tabbrowser.mContextTab);"/>
+            <xul:menuseparator/>
+            <xul:menuitem label="&closeTab.label;" accesskey="&closeTab.accesskey;"
+                          tbattr="tabbrowser-multiple"
+                          oncommand="var tabbrowser = this.parentNode.parentNode.parentNode.parentNode;
+                                     tabbrowser.removeTab(tabbrowser.mContextTab);"/>
+          </xul:menupopup>
+
+          <xul:tabs class="tabbrowser-tabs" flex="1"
+                    anonid="tabcontainer"
+                    setfocus="false"
+                    onclick="this.parentNode.parentNode.parentNode.onTabClick(event);"
+                    xbl:inherits="onnewtab"
+                    ondblclick="this.parentNode.parentNode.parentNode.onTabBarDblClick(event);"
+                    onclosetab="var node = this.parentNode;
+                                while (node.localName != 'tabbrowser')
+                                  node = node.parentNode;
+                                node.removeCurrentTab();">
+            <xul:tab selected="true" validate="never"
+                     onerror="this.parentNode.parentNode.parentNode.parentNode.addToMissedIconCache(this.getAttribute('image'));
+                              this.removeAttribute('image');"
+                      flex="100"
+                     class="tabbrowser-tab" label="&untitledTab;" crop="end"/>
+          </xul:tabs>
+        </xul:vbox>
+        <xul:splitter class="tabbrowser-splitter" collapse="before" resizeafter="closest" resizebefore="closest" ondblclick="this.previousSibling.width=102">
+               <xul:grippy />
+        </xul:splitter>
+        <xul:tabpanels flex="1" class="plain" selectedIndex="0" anonid="panelcontainer">
+          <xul:notificationbox flex="1">
+            <xul:browser flex="1" type="content-primary" message="true" disablehistory="true"
+                         xbl:inherits="tooltip=contenttooltip,contextmenu=contentcontextmenu,autocompletepopup"/>
+          </xul:notificationbox>
+        </xul:tabpanels>
+      </xul:tabbox>
+      <children/>
+    </content>
+    <implementation>
+      <field name="mTabstrip">
+        document.getAnonymousElementByAttribute(this, "anonid", "arrowscrollbox");
+      </field>
+      <field name="mPrefs" readonly="true">
+        Components.classes['@mozilla.org/preferences-service;1']
+                  .getService(Components.interfaces.nsIPrefService)
+                  .getBranch(null);
+      </field>
+      <field name="mURIFixup" readonly="true">
+        Components.classes["@mozilla.org/docshell/urifixup;1"]
+                  .getService(Components.interfaces.nsIURIFixup);
+      </field>
+      <field name="mTabBox" readonly="true">
+        document.getAnonymousElementByAttribute(this, "anonid", "tabbox");
+      </field>
+      <field name="mTabDropIndicatorBar">
+        this.mTabBox.childNodes[0]
+      </field>
+      <field name="mStrip" readonly="true">
+        document.getAnonymousElementByAttribute(this, "anonid", "strip");
+      </field>
+      <field name="mTabContainer" readonly="true">
+        document.getAnonymousElementByAttribute(this, "anonid", "tabcontainer");
+      </field>
+      <field name="mPanelContainer" readonly="true">
+        document.getAnonymousElementByAttribute(this, "anonid", "panelcontainer");
+      </field>
+      <field name="mTabs" readonly="true">
+        this.mTabContainer.childNodes
+      </field>
+      <field name="mStringBundle">
+        document.getAnonymousElementByAttribute(this, "anonid", "tbstringbundle");
+      </field>
+      <field name="mCurrentTab">
+        null
+      </field>
+      <field name="mCurrentBrowser">
+        null
+      </field>
+      <field name="mProgressListeners">
+        []
+      </field>
+      <field name="mTabListeners">
+        new Array()
+      </field>
+      <field name="mTabFilters">
+        new Array()
+      </field>
+      <field name="mTabbedMode">
+        false
+      </field>
+      <field name="mIsBusy">
+        false
+      </field>
+      <field name="mMissedIconCache">
+        null
+      </field>
+      <field name="mContextTab">
+        null
+      </field>
+      <field name="mModalDialogShowing">
+        false
+      </field>
+      <field name="arrowKeysShouldWrap" readonly="true">
+        false
+      </field>
+      <field name="mAddProgressListenerWasCalled">
+        false
+      </field>
+      <field name="_browsers">
+        null
+      </field>
+
+      <field name="_blockDblClick">
+        false
+      </field>
+
+      <method name="getBrowserAtIndex">
+        <parameter name="aIndex"/>
+        <body>
+          <![CDATA[
+            return this.mTabContainer.childNodes[aIndex].linkedBrowser;
+          ]]>
+        </body>
+      </method>
+
+      <method name="getBrowserIndexForDocument">
+        <parameter name="aDocument"/>
+        <body>
+          <![CDATA[
+            for (var i = 0; i < this.mPanelContainer.childNodes.length; i++) {
+              if (this.getBrowserAtIndex(i).contentDocument == aDocument) {
+                return i;
+              }
+            }
+            return -1;
+          ]]>
+        </body>
+      </method>
+
+      <method name="getBrowserForDocument">
+        <parameter name="aDocument"/>
+        <body>
+          <![CDATA[
+            var index = this.getBrowserIndexForDocument(aDocument);
+            if (index < 0)
+              return null;
+            return this.getBrowserAtIndex(index);
+          ]]>
+        </body>
+      </method>
+
+      <method name="getNotificationBox">
+        <parameter name="aBrowser"/>
+        <body>
+          <![CDATA[
+            if (aBrowser)
+              return aBrowser.parentNode;
+            else if (this.mCurrentBrowser)
+              return this.mCurrentBrowser.parentNode;
+            return null;
+          ]]>
+        </body>
+      </method>
+
+      <!-- A web progress listener object definition for a given tab. -->
+      <method name="mTabProgressListener">
+        <parameter name="aTab"/>
+        <parameter name="aBrowser"/>
+        <parameter name="aStartsBlank"/>
+        <body>
+        <![CDATA[
+          return ({
+            mTabBrowser: this,
+            mTab: aTab,
+            mBrowser: aBrowser,
+            mBlank: aStartsBlank,
+            mLastURI: null,
+
+            // cache flags for correct status bar update after tab switching
+            mStateFlags: 0,
+            mStatus: 0,
+            mMessage: "",
+            mTotalProgress: 0,
+
+            // count of open requests (should always be 0 or 1)
+            mRequestCount: 0,
+
+            onProgressChange : function (aWebProgress, aRequest,
+                                         aCurSelfProgress, aMaxSelfProgress,
+                                         aCurTotalProgress, aMaxTotalProgress)
+            {
+              if (!this.mBlank && this.mTabBrowser.mCurrentTab == this.mTab) {
+                for (var i = 0; i < this.mTabBrowser.mProgressListeners.length; i++) {
+                  var p = this.mTabBrowser.mProgressListeners[i];
+                  if (p)
+                    p.onProgressChange(aWebProgress, aRequest,
+                                       aCurSelfProgress, aMaxSelfProgress,
+                                       aCurTotalProgress, aMaxTotalProgress);
+                }
+              }
+
+              this.mTotalProgress = aMaxTotalProgress ? aCurTotalProgress / aMaxTotalProgress : 0;
+            },
+
+            onStateChange : function(aWebProgress, aRequest, aStateFlags, aStatus)
+            {
+              if (!aRequest)
+                return;
+
+              var oldBlank = this.mBlank;
+
+              const nsIWebProgressListener = Components.interfaces.nsIWebProgressListener;
+              const nsIChannel = Components.interfaces.nsIChannel;
+
+              if (aStateFlags & nsIWebProgressListener.STATE_START) {
+                this.mRequestCount++;
+              }
+              else if (aStateFlags & nsIWebProgressListener.STATE_STOP) {
+                const NS_ERROR_UNKNOWN_HOST = 2152398878;
+                if (--this.mRequestCount > 0 && aStatus == NS_ERROR_UNKNOWN_HOST) {
+                  // to prevent bug 235825: wait for the request handled
+                  // by the automatic keyword resolver
+                  return;
+                }
+                // since we (try to) only handle STATE_STOP of the last request,
+                // the count of open requests should now be 0
+                this.mRequestCount = 0;
+              }
+
+              if (aStateFlags & nsIWebProgressListener.STATE_START &&
+                  aStateFlags & nsIWebProgressListener.STATE_IS_NETWORK) {
+                // It's okay to clear what the user typed when we start
+                // loading a document. If the user types, this counter gets
+                // set to zero, if the document load ends without an
+                // onLocationChange, this counter gets decremented
+                // (so we keep it while switching tabs after failed loads)
+                if (aWebProgress.DOMWindow == this.mBrowser.contentWindow)
+                  this.mBrowser.userTypedClear++;
+
+                if (!this.mBlank) {
+                  this.mTab.setAttribute("busy", "true");
+                  this.mTabBrowser.updateIcon(this.mTab);
+                  this.mTabBrowser.setTabTitleLoading(this.mTab);
+
+                  if (this.mTabBrowser.mCurrentTab == this.mTab)
+                    this.mTabBrowser.mIsBusy = true;
+                }
+              }
+              else if (aStateFlags & nsIWebProgressListener.STATE_STOP &&
+                       aStateFlags & nsIWebProgressListener.STATE_IS_NETWORK) {
+                if (aWebProgress.DOMWindow == this.mBrowser.contentWindow) {
+                  // The document is done loading, we no longer want the
+                  // value cleared.
+                  if (this.mBrowser.userTypedClear > 0)
+                    this.mBrowser.userTypedClear--;
+
+                  if (!this.mBrowser.mIconURL)
+                    this.mTabBrowser.useDefaultIcon(this.mTab);
+                }
+
+                if (this.mBlank)
+                  this.mBlank = false;
+
+                this.mTab.removeAttribute("busy");
+                this.mTabBrowser.updateIcon(this.mTab);
+
+                var location = aRequest.QueryInterface(nsIChannel).URI;
+
+                // For keyword URIs clear the user typed value since they will be changed into real URIs
+                if (location.scheme == "keyword")
+                  this.mBrowser.userTypedValue = null;
+
+                if (this.mTab.label == this.mTabBrowser.mStringBundle.getString("tabs.loading"))
+                  this.mTabBrowser.setTabTitle(this.mTab);
+
+                if (this.mTabBrowser.mCurrentTab == this.mTab)
+                  this.mTabBrowser.mIsBusy = false;
+              }
+
+              if (this.mTabBrowser.mCurrentTab == this.mTab) {
+                for (var i = 0; i < this.mTabBrowser.mProgressListeners.length; i++) {
+                  var p = this.mTabBrowser.mProgressListeners[i];
+                  if (p && !oldBlank)
+                    p.onStateChange(aWebProgress, aRequest, aStateFlags, aStatus);
+                  // make sure that the visible status of new blank tabs is correctly set
+                  else if (p && "onUpdateCurrentBrowser" in p)
+                    p.onUpdateCurrentBrowser(aStateFlags, aStatus, "", 0);
+                }
+              }
+
+              if (aStateFlags & (nsIWebProgressListener.STATE_START |
+                                 nsIWebProgressListener.STATE_STOP)) {
+                // reset cached temporary values at beginning and end
+                this.mMessage = "";
+                this.mTotalProgress = 0;
+              }
+              this.mStateFlags = aStateFlags;
+              this.mStatus = aStatus;
+            },
+
+            onLocationChange : function(aWebProgress, aRequest, aLocation)
+            {
+              // The document loaded correctly, clear the value if we should
+              if (this.mBrowser.userTypedClear > 0 && aRequest)
+                this.mBrowser.userTypedValue = null;
+
+              if (aWebProgress.DOMWindow == this.mBrowser.contentWindow &&
+                  aWebProgress.isLoadingDocument)
+                this.mTabBrowser.setIcon(this.mTab, null);
+
+              // changing location, clear out the missing plugins list
+              this.mTab.missingPlugins = null;
+
+              if (!this.mBlank && this.mTabBrowser.mCurrentTab == this.mTab) {
+                for (var i = 0; i < this.mTabBrowser.mProgressListeners.length; i++) {
+                  var p = this.mTabBrowser.mProgressListeners[i];
+                  if (p)
+                    p.onLocationChange(aWebProgress, aRequest, aLocation);
+                }
+              }
+            },
+
+            onStatusChange : function(aWebProgress, aRequest, aStatus, aMessage)
+            {
+              if (this.mBlank)
+                return;
+
+              if (this.mTabBrowser.mCurrentTab == this.mTab) {
+                for (var i = 0; i < this.mTabBrowser.mProgressListeners.length; i++) {
+                  var p = this.mTabBrowser.mProgressListeners[i];
+                  if (p)
+                    p.onStatusChange(aWebProgress, aRequest, aStatus, aMessage);
+                }
+              }
+
+              this.mMessage = aMessage;
+            },
+
+            onSecurityChange : function(aWebProgress, aRequest, aState)
+            {
+              if (this.mTabBrowser.mCurrentTab == this.mTab) {
+                for (var i = 0; i < this.mTabBrowser.mProgressListeners.length; i++) {
+                  var p = this.mTabBrowser.mProgressListeners[i];
+                  if (p)
+                    p.onSecurityChange(aWebProgress, aRequest, aState);
+                }
+              }
+            },
+
+            QueryInterface : function(aIID)
+            {
+              if (aIID.equals(Components.interfaces.nsIWebProgressListener) ||
+                  aIID.equals(Components.interfaces.nsISupportsWeakReference) ||
+                  aIID.equals(Components.interfaces.nsISupports))
+                return this;
+              throw Components.results.NS_NOINTERFACE;
+            }
+          });
+        ]]>
+        </body>
+      </method>
+
+      <method name="setIcon">
+        <parameter name="aTab"/>
+        <parameter name="aURI"/>
+        <body>
+          <![CDATA[
+            var browser = this.getBrowserForTab(aTab);
+            browser.mIconURL = aURI;
+
+            this.updateIcon(aTab);
+
+            for (var i = 0; i < this.mProgressListeners.length; i++) {
+              var p = this.mProgressListeners[i];
+              if ('onLinkIconAvailable' in p)
+                p.onLinkIconAvailable(browser);
+            }
+          ]]>
+        </body>
+      </method>
+
+      <method name="updateIcon">
+        <parameter name="aTab"/>
+        <body>
+          <![CDATA[
+            var browser = this.getBrowserForTab(aTab);
+            if (!aTab.hasAttribute("busy") && browser.mIconURL)
+              aTab.setAttribute("image", browser.mIconURL);
+            else
+              aTab.removeAttribute("image");
+          ]]>
+        </body>
+      </method>
+
+      <method name="shouldLoadFavIcon">
+        <parameter name="aURI"/>
+        <body>
+          <![CDATA[
+            return (aURI && this.mPrefs.getBoolPref("browser.chrome.site_icons") &&
+                    this.mPrefs.getBoolPref("browser.chrome.favicons") &&
+                    ("schemeIs" in aURI) && (aURI.schemeIs("http") || aURI.schemeIs("https")));
+          ]]>
+        </body>
+      </method>
+
+      <method name="useDefaultIcon">
+        <parameter name="aTab"/>
+        <body>
+          <![CDATA[
+            var browser = this.getBrowserForTab(aTab);
+            if (browser.contentDocument instanceof ImageDocument) {
+              if (this.mPrefs.getBoolPref("browser.chrome.site_icons")) {
+                try {
+                  var sz = this.mPrefs.getIntPref("browser.chrome.image_icons.max_size");
+                  if (!sz)
+                    return;
+
+                  var req = browser.contentDocument.imageRequest;
+                  if (!req || !req.image ||
+                      req.image.width > sz ||
+                      req.image.height > sz)
+                    return;
+
+                  this.setIcon(aTab, browser.currentURI.spec);
+                } catch (e) { }
+              }
+            }
+            else if (this.shouldLoadFavIcon(browser.currentURI)) {
+              var url = browser.currentURI.prePath + "/favicon.ico";
+              if (!this.isIconKnownMissing(url))
+                this.setIcon(aTab, url);
+            }
+          ]]>
+        </body>
+      </method>
+
+      <method name="addToMissedIconCache">
+        <parameter name="aURI"/>
+        <body>
+          <![CDATA[
+            var entry = this.openCacheEntry(aURI, Components.interfaces.nsICache.ACCESS_READ_WRITE);
+            if (!entry)
+              return;
+
+            if (entry.accessGranted == Components.interfaces.nsICache.ACCESS_WRITE)
+              // It's a new entry.  Just write a bit of metadata in to the entry.
+              entry.setMetaDataElement("Icon", "Missed");
+            entry.markValid();
+            entry.close();
+          ]]>
+        </body>
+      </method>
+
+      <method name="openCacheEntry">
+        <parameter name="key"/>
+        <parameter name="access"/>
+        <body>
+          <![CDATA[
+            try {
+              if (!this.mMissedIconCache) {
+                var cacheService = Components.classes['@mozilla.org/network/cache-service;1'].getService(Components.interfaces.nsICacheService);
+                this.mMissedIconCache = cacheService.createSession("MissedIconCache", Components.interfaces.nsICache.STORE_ANYWHERE, true);
+                if (!this.mMissedIconCache)
+                  return null;
+              }
+              return this.mMissedIconCache.openCacheEntry(key, access, true);
+            }
+            catch (e) {
+              return null;
+            }
+          ]]>
+        </body>
+      </method>
+
+      <method name="isIconKnownMissing">
+        <parameter name="key"/>
+        <body>
+          <![CDATA[
+            var e = this.openCacheEntry(key, Components.interfaces.nsICache.ACCESS_READ);
+            if (e) {
+                e.close();
+                return true;
+            }
+            return false;
+          ]]>
+        </body>
+      </method>
+
+      <method name="updateTitlebar">
+        <body>
+          <![CDATA[
+            var newTitle = "";
+            var docTitle;
+            var docElement = this.ownerDocument.documentElement;
+            var sep = docElement.getAttribute("titlemenuseparator");
+
+            if (this.docShell.contentViewer)
+              docTitle = this.contentTitle;
+
+            if (!docTitle)
+              docTitle = docElement.getAttribute("titledefault");
+
+            var modifier = docElement.getAttribute("titlemodifier");
+            if (docTitle) {
+              newTitle += docElement.getAttribute("titlepreface");
+              newTitle += docTitle;
+              if (modifier)
+                newTitle += sep;
+            }
+            newTitle += modifier;
+
+            // If location bar is hidden and the URL type supports a host,
+            // add the scheme and host to the title to prevent spoofing.
+            // XXX https://bugzilla.mozilla.org/show_bug.cgi?id=22183#c239
+            // (only for schemes that support a host)
+            try {
+              if (docElement.getAttribute("chromehidden").indexOf("location") != -1) {
+                var uri = this.mURIFixup.createExposableURI(
+                            this.mCurrentBrowser.currentURI);
+                if (uri.host)
+                  newTitle = uri.prePath + sep + newTitle;
+              }
+            } catch (e) {}
+
+            this.ownerDocument.title = newTitle;
+          ]]>
+        </body>
+      </method>
+
+      <method name="updatePopupMenu">
+        <parameter name="aPopupMenu"/>
+        <body>
+          <![CDATA[
+            this.mContextTab = document.popupNode;
+            var disabled = this.mPanelContainer.childNodes.length == 1;
+            var menuItems = aPopupMenu.getElementsByAttribute("tbattr", "tabbrowser-multiple");
+            for (var i = 0; i < menuItems.length; i++)
+              menuItems[i].disabled = disabled;
+          ]]>
+        </body>
+      </method>
+
+      <method name="updateCurrentBrowser">
+        <body>
+          <![CDATA[
+            var newBrowser = this.getBrowserAtIndex(this.mTabContainer.selectedIndex);
+            if (this.mCurrentBrowser == newBrowser)
+              return;
+
+            if (this.mCurrentBrowser) {
+              // Only save the focused element if it is in our content window
+              // or in an ancestor window.
+              var focusedWindow = document.commandDispatcher.focusedWindow;
+              var saveFocus = false;
+
+              if (focusedWindow && focusedWindow.top == window.content) {
+                saveFocus = true;
+              } else {
+                var contentWindow = window;
+
+                while (contentWindow) {
+                  if (contentWindow == focusedWindow) {
+                    saveFocus = true;
+                    break;
+                  }
+
+                  if (contentWindow.parent == contentWindow) {
+                    break;
+                  }
+
+                  contentWindow = contentWindow.parent;
+                }
+              }
+
+              if (saveFocus) {
+                // Preserve the currently-focused element or DOM window for
+                // this tab.
+
+                this.mCurrentBrowser.focusedWindow = focusedWindow;
+                this.mCurrentBrowser.focusedElement = document.commandDispatcher.focusedElement;
+              }
+
+              if (this.mCurrentBrowser.focusedElement instanceof NSHTMLElement || 
+                  this.mCurrentBrowser.focusedElement instanceof XULElement) {
+                // Clear focus outline before we draw on top of it
+                this.mCurrentBrowser.focusedElement.blur();
+              }
+              else {
+                // non-HTML/XUL elements have no blur method, see bug 323805
+                this.mCurrentBrowser.focusedElement = null;
+              }
+              this.mCurrentBrowser.setAttribute("type", "content-targetable");
+            }
+
+            var updatePageReport = false;
+            if ((this.mCurrentBrowser.pageReport && !newBrowser.pageReport) ||
+                (!this.mCurrentBrowser.pageReport && newBrowser.pageReport))
+              updatePageReport = true;
+
+            newBrowser.setAttribute("type", "content-primary");
+            this.mCurrentBrowser = newBrowser;
+            this.mCurrentTab = this.selectedTab;
+
+            if (updatePageReport)
+              this.mCurrentBrowser.updatePageReport();
+
+            // Update the URL bar.
+            var loc = this.mCurrentBrowser.currentURI;
+            if (!loc)
+              loc = ({ spec: "" });
+
+            var webProgress = this.mCurrentBrowser.webProgress;
+            var securityUI = this.mCurrentBrowser.securityUI;
+
+            var i, p;
+            for (i = 0; i < this.mProgressListeners.length; i++) {
+              p = this.mProgressListeners[i];
+              if (p) {
+                p.onLocationChange(webProgress, null, loc);
+                if (securityUI)
+                  p.onSecurityChange(webProgress, null, securityUI.state);
+
+                // make sure that all status indicators are properly updated
+                if ("onUpdateCurrentBrowser" in p) {
+                  var listener = this.mTabListeners[this.mTabContainer.selectedIndex] || null;
+                  if (listener && listener.mStateFlags)
+                    p.onUpdateCurrentBrowser(listener.mStateFlags, listener.mStatus,
+                                             listener.mMessage, listener.mTotalProgress);
+                }
+              }
+            }
+
+            this._fastFind.setDocShell(this.mCurrentBrowser.docShell);
+
+            // Update the window title.
+            this.updateTitlebar();
+
+            // If the new tab is busy, and our current state is not busy, then
+            // we need to fire a start to all progress listeners.
+            const nsIWebProgressListener = Components.interfaces.nsIWebProgressListener;
+            if (this.mCurrentTab.hasAttribute("busy") && !this.mIsBusy) {
+              this.mIsBusy = true;
+              webProgress = this.mCurrentBrowser.webProgress;
+              for (i = 0; i < this.mProgressListeners.length; i++) {
+                p = this.mProgressListeners[i];
+                if (p)
+                  p.onStateChange(webProgress, null, nsIWebProgressListener.STATE_START | nsIWebProgressListener.STATE_IS_NETWORK, 0);
+              }
+            }
+
+            // If the new tab is not busy, and our current state is busy, then
+            // we need to fire a stop to all progress listeners.
+            if (!this.mCurrentTab.hasAttribute("busy") && this.mIsBusy) {
+              this.mIsBusy = false;
+              webProgress = this.mCurrentBrowser.webProgress;
+              for (i = 0; i < this.mProgressListeners.length; i++) {
+                p = this.mProgressListeners[i];
+                if (p)
+                  p.onStateChange(webProgress, null, nsIWebProgressListener.STATE_STOP | nsIWebProgressListener.STATE_IS_NETWORK, 0);
+              }
+            }
+
+            // We've selected the new tab, so go ahead and notify listeners.
+            var event = document.createEvent("Events");
+            event.initEvent("TabSelect", true, false);
+            this.mCurrentTab.dispatchEvent(event);
+
+            if (document.commandDispatcher.focusedElement &&
+                document.commandDispatcher.focusedElement.parentNode ==
+                this.mCurrentTab.parentNode) {
+              // The focus is on a tab in the same tab panel
+              return;  // If focus was on a tab, switching tabs focuses the new tab
+            }
+
+            var whatToFocus = window.content;
+
+            // Focus the previously focused element or window
+            if (newBrowser.focusedElement) {
+              if (newBrowser.focusedElement.parentNode !=
+                  this.mCurrentTab.parentNode) {
+                // Focus the remembered element unless it's in the current tab panel
+                whatToFocus = newBrowser.focusedElement;
+              }
+            }
+            else if (newBrowser.focusedWindow) {
+              whatToFocus = newBrowser.focusedWindow;
+            }
+
+            function setFocus(element) {
+              document.commandDispatcher.suppressFocusScroll = true;
+
+              if (element instanceof Window ||
+                  element instanceof NSHTMLElement || 
+                  element instanceof XULElement) {
+                try {
+                  element.focus();
+                }
+                catch(ex) {
+                  dump("XXXfocus() failed, see bug #348183: ex = " + ex + "\n");
+                }
+              }
+              document.commandDispatcher.suppressFocusScroll = false;
+            }
+
+            // Use setTimeout to avoid focus outline ghosting.
+            setTimeout(setFocus, 0, whatToFocus);
+          ]]>
+        </body>
+      </method>
+
+      <method name="onTabClick">
+        <parameter name="event"/>
+        <body>
+          <![CDATA[
+            if (event.button != 1 || event.target.localName != 'tab')
+              return;
+
+            this.removeTab(event.target);
+            event.stopPropagation();
+          ]]>
+        </body>
+      </method>
+
+      <method name="onLinkAdded">
+        <parameter name="event"/>
+        <body>
+          <![CDATA[
+            if (!this.mPrefs.getBoolPref("browser.chrome.site_icons"))
+              return;
+
+            if (!event.originalTarget.rel.match((/(?:^|\s)icon(?:\s|$)/i)))
+              return;
+
+            // We have an icon.
+            var href = event.originalTarget.href;
+            if (!href)
+              return;
+
+            const nsIContentPolicy = Components.interfaces.nsIContentPolicy;
+            try {
+              var contentPolicy =
+                Components.classes['@mozilla.org/layout/content-policy;1']
+                          .getService(nsIContentPolicy);
+            } catch(e) {
+              return; // Refuse to load if we can't do a security check.
+            }
+
+            // Verify that the load of this icon is legal.
+            // We check first with the security manager
+            const secMan =
+              Components.classes["@mozilla.org/scriptsecuritymanager;1"]
+                        .getService(Components.interfaces.nsIScriptSecurityManager);
+
+            // Get the IOService so we can make URIs
+            const ioService =
+              Components.classes["@mozilla.org/network/io-service;1"]
+                        .getService(Components.interfaces.nsIIOService);
+
+            const targetDoc = event.target.ownerDocument;
+            // Make a URI out of our href.
+            var uri = ioService.newURI(href, targetDoc.characterSet, null);
+
+            var origURI = ioService.newURI(targetDoc.documentURI, targetDoc.characterSet, null);
+
+            const nsIScriptSecMan =
+              Components.interfaces.nsIScriptSecurityManager;
+
+            try {
+              // error pages can load their favicon
+              // to be on the safe side, only allow chrome:// favicons
+              const aboutNeterr = "about:neterror?";
+              if (origURI.spec.substr(0, aboutNeterr.length) != aboutNeterr ||
+                  !uri.schemeIs("chrome"))
+                secMan.checkLoadURI(origURI, uri,
+                                    nsIScriptSecMan.DISALLOW_SCRIPT);
+            } catch(e) {
+              return;
+            }
+
+            // Security says okay, now ask content policy
+            if (contentPolicy.shouldLoad(nsIContentPolicy.TYPE_IMAGE,
+                                         uri, origURI, event.target,
+                                         event.target.type,
+                                         null) != nsIContentPolicy.ACCEPT)
+              return;
+
+            var browserIndex = this.getBrowserIndexForDocument(targetDoc);
+            // no browser? no favicon.
+            if (browserIndex == -1)
+              return;
+
+            var tab = this.mTabContainer.childNodes[browserIndex];
+            this.setIcon(tab, href);
+          ]]>
+        </body>
+      </method>
+
+      <method name="onTitleChanged">
+        <parameter name="evt"/>
+        <body>
+          <![CDATA[
+            if (evt.target != this.contentDocument)
+              return;
+
+            var i = 0;
+            for ( ; i < this.parentNode.parentNode.childNodes.length; i++) {
+              if (this.parentNode.parentNode.childNodes[i].firstChild == this)
+                break;
+            }
+
+            var tabBrowser = this.parentNode.parentNode.parentNode.parentNode;
+
+            var tab = document.getAnonymousElementByAttribute(tabBrowser, "linkedpanel", this.parentNode.id);
+            tabBrowser.setTabTitle(tab);
+
+            if (tab == tabBrowser.mCurrentTab)
+              tabBrowser.updateTitlebar();
+          ]]>
+        </body>
+      </method>
+
+      <method name="setTabTitleLoading">
+        <parameter name="aTab"/>
+        <body>
+          <![CDATA[
+            aTab.label = this.mStringBundle.getString("tabs.loading");
+            aTab.setAttribute("crop", "end");
+          ]]>
+        </body>
+      </method>
+
+      <method name="setTabTitle">
+        <parameter name="aTab"/>
+        <body>
+          <![CDATA[
+            var browser = this.getBrowserForTab(aTab);
+            var title = browser.contentDocument.title;
+
+            if (!title) {
+              if (browser.currentURI.spec) {
+                try {
+                  title = this.mURIFixup.createExposableURI(browser.currentURI).spec;
+                } catch(ex) {
+                  title = browser.currentURI.spec;
+                }
+              }
+
+              if (title && title != "about:blank") {
+                // At this point, we now have a URI.
+                // Let's try to unescape it using a character set
+                // in case the URI is not ASCII.
+                try {
+                  var characterSet = browser.contentDocument.characterSet;
+                  const textToSubURI = Components.classes["@mozilla.org/intl/texttosuburi;1"]
+                                                 .getService(Components.interfaces.nsITextToSubURI);
+                  title = textToSubURI.unEscapeNonAsciiURI(characterSet, title);
+                } catch(ex) { /* Do nothing. */ }
+
+
+              } else // Still no title?  Fall back to our untitled string.
+                title = '\\{0_0}/';
+            }
+
+            aTab.label = title;
+          ]]>
+        </body>
+      </method>
+
+      <method name="setStripVisibilityTo">
+        <parameter name="aShow"/>
+        <body>
+        <![CDATA[
+          this.mStrip.collapsed = !aShow;
+          if (aShow) {
+            // XXXdwh temporary unclean dependency on specific menu items in navigator.xul
+            document.getElementById("menu_closeWindow").hidden = false;
+            document.getElementById("menu_close").setAttribute("label", this.mStringBundle.getString("tabs.closeTab"));
+            if (!this.mTabbedMode)
+              this.enterTabbedMode();
+          }
+          else {
+            // XXXdwh temporary unclean dependency on specific menu items in navigator.xul
+            document.getElementById("menu_closeWindow").hidden = true;
+            document.getElementById("menu_close").setAttribute("label", this.mStringBundle.getString("tabs.close"));
+          }
+        ]]>
+        </body>
+      </method>
+
+      <method name="getStripVisibility">
+        <body>
+          return !this.mStrip.collapsed;
+        </body>
+      </method>
+
+      <method name="enterTabbedMode">
+        <body>
+          <![CDATA[
+            this.mTabbedMode = true; // Welcome to multi-tabbed mode.
+
+            // Get the first tab all hooked up with a title listener and popup blocking listener.
+            this.mCurrentBrowser.addEventListener("DOMTitleChanged", this.onTitleChanged, true);
+
+            var throbberElement = document.getElementById("navigator-throbber");
+            if (throbberElement && throbberElement.hasAttribute("busy")) {
+              this.mCurrentTab.setAttribute("busy", "true");
+              this.mIsBusy = true;
+              this.setTabTitleLoading(this.mCurrentTab);
+              this.updateIcon(this.mCurrentTab);
+            } else {
+              this.setTabTitle(this.mCurrentTab);
+              this.setIcon(this.mCurrentTab, this.mCurrentBrowser.mIconURL);
+            }
+
+            var filter;
+            if (this.mTabFilters.length > 0) {
+              // Use the filter hooked up in our addProgressListener
+              filter = this.mTabFilters[0];
+            } else {
+              // create a filter and hook it up to our first browser
+              filter = Components.classes["@mozilla.org/appshell/component/browser-status-filter;1"]
+                                 .createInstance(Components.interfaces.nsIWebProgress);
+              this.mTabFilters[0] = filter;
+              this.mCurrentBrowser.webProgress.addProgressListener(filter, Components.interfaces.nsIWebProgress.NOTIFY_ALL);
+            }
+
+            // Remove all our progress listeners from the active browser's filter.
+            for (var i = 0; i < this.mProgressListeners.length; i++) {
+              var p = this.mProgressListeners[i];
+              if (p)
+                filter.removeProgressListener(p);
+            }
+
+            // Wire up a progress listener to our filter.
+            const listener = this.mTabProgressListener(this.mCurrentTab,
+                                                       this.mCurrentBrowser,
+                                                       false);
+            filter.addProgressListener(listener, Components.interfaces.nsIWebProgress.NOTIFY_ALL);
+            this.mTabListeners[0] = listener;
+          ]]>
+        </body>
+      </method>
+
+      <method name="loadOneTab">
+        <parameter name="aURI"/>
+        <parameter name="aReferrerURI"/>
+        <parameter name="aCharset"/>
+        <parameter name="aPostData"/>
+        <parameter name="aLoadInBackground"/>
+        <parameter name="aAllowThirdPartyFixup"/>
+        <body>
+          <![CDATA[
+            var bgLoad = (aLoadInBackground != null) ? aLoadInBackground :
+                         this.mPrefs.getBoolPref("browser.tabs.loadInBackground");
+            var owner = bgLoad ? null : this.selectedTab;
+            var tab = this.addTab(aURI, aReferrerURI, aCharset, aPostData, owner,
+                                  aAllowThirdPartyFixup);
+            // Set newly selected tab after quick timeout, otherwise hideous focus problems
+            // can occur when "browser.tabs.loadInBackground" is false and presshell is not ready
+            if (!bgLoad) {
+              function selectNewForegroundTab(browser, tab) {
+                browser.selectedTab = tab;
+              }
+              setTimeout(selectNewForegroundTab, 0, getBrowser(), tab);
+            }
+            if (!bgLoad)
+              this.selectedTab = tab;
+            
+            return tab;
+         ]]>
+        </body>
+      </method>
+
+      <method name="loadTabs">
+        <parameter name="aURIs"/>
+        <parameter name="aLoadInBackground"/>
+        <parameter name="aReplace"/>
+        <body><![CDATA[
+          // The tab selected after this new tab is closed (i.e. the new tab's
+          // "owner") is the next adjacent tab (i.e. not the previously viewed tab)
+          // when several urls are opened here (i.e. closing the first should select
+          // the next of many URLs opened) or if the pref to have UI links opened in
+          // the background is set (i.e. the link is not being opened modally)
+          //
+          // i.e.
+          //    Number of URLs    Load UI Links in BG       Focus Last Viewed?
+          //    == 1              false                     YES
+          //    == 1              true                      NO
+          //    > 1               false/true                NO
+          var owner = (aURIs.length > 1) || aLoadInBackground ? null : gBrowser.selectedTab;
+          var firstTabAdded = null;
+          if (aReplace)
+            this.loadURI(aURIs[0], null, null);
+          else
+            firstTabAdded = gBrowser.addTab(aURIs[0], null, null, null, owner, false);
+
+          var tabNum = this.mTabContainer.selectedIndex;
+          for (var i = 1; i < aURIs.length; ++i) {
+            var tab = gBrowser.addTab(aURIs[i]);
+            if (aReplace)
+              this.moveTabTo(tab, ++tabNum);
+          }
+
+          if (!aLoadInBackground) {
+            if (firstTabAdded) {
+              // .selectedTab setter focuses the content area
+              this.selectedTab = firstTabAdded;
+            }
+            else
+              window.content.focus();
+          }
+        ]]></body>
+      </method>
+
+      <method name="addTab">
+        <parameter name="aURI"/>
+        <parameter name="aReferrerURI"/>
+        <parameter name="aCharset"/>
+        <parameter name="aPostData"/>
+        <parameter name="aOwner"/>
+        <parameter name="aAllowThirdPartyFixup"/>
+        <body>
+          <![CDATA[
+            this._browsers = null; // invalidate cache
+
+            if (!this.mTabbedMode)
+              this.enterTabbedMode();
+
+            // if we're adding tabs, we're past interrupt mode, ditch the owner
+            if (this.mCurrentTab.owner)
+              this.mCurrentTab.owner = null;
+
+            var t = document.createElementNS(
+              "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
+                                             "tab");
+
+            var blank = (aURI == "about:blank");
+
+            if (blank)
+              t.setAttribute("label", this.mStringBundle.getString("tabs.untitled"));
+            else
+              t.setAttribute("label", aURI);
+
+            t.setAttribute("crop", "end");
+            t.minWidth = this.mTabContainer.mTabMinWidth;
+            t.setAttribute("flex", "100");
+            t.setAttribute("validate", "never");
+            t.setAttribute("onerror", "this.parentNode.parentNode.parentNode.parentNode.addToMissedIconCache(this.getAttribute('image')); this.removeAttribute('image');");
+            t.className = "tabbrowser-tab";
+
+            this.mTabContainer.appendChild(t);
+
+            if (document.defaultView
+                        .getComputedStyle(this.mTabContainer, "")
+                        .direction == "rtl") {
+              /* In RTL UI, the tab is visually added to the left side of the
+               * tabstrip. This means the tabstip has to be scrolled back in
+               * order to make sure the same set of tabs is visible before and
+               * after the new tab is added */
+
+            }
+
+            // invalidate cache, because mTabContainer is about to change
+            this._browsers = null; 
+
+            // If this new tab is owned by another, assert that relationship
+            if (aOwner !== undefined && aOwner !== null) {
+              t.owner = aOwner;
+
+              var self = this;
+              function attrChanged(event) {
+                if (event.attrName == "selectedIndex" &&
+                    event.prevValue != event.newValue)
+                  self.resetOwner(parseInt(event.prevValue));
+              }
+              if (!this.mTabChangedListenerAdded) {
+                this.mTabBox.addEventListener("DOMAttrModified", attrChanged, false);
+                this.mTabChangedListenerAdded = true;
+              }
+            }
+
+            var b = document.createElementNS(
+              "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
+                                             "browser");
+            b.setAttribute("type", "content-targetable");
+            b.setAttribute("message", "true");
+            b.setAttribute("contextmenu", this.getAttribute("contentcontextmenu"));
+            b.setAttribute("tooltip", this.getAttribute("contenttooltip"));
+            if (this.hasAttribute("autocompletepopup"))
+              b.setAttribute("autocompletepopup", this.getAttribute("autocompletepopup"));
+
+            // Add the Message and the Browser to the box
+            var notificationbox = document.createElementNS(
+                                    "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
+                                    "notificationbox");
+            notificationbox.setAttribute("flex", "1");
+            notificationbox.appendChild(b);
+            b.setAttribute("flex", "1");
+            this.mPanelContainer.appendChild(notificationbox);
+
+            b.addEventListener("DOMTitleChanged", this.onTitleChanged, true);
+
+            if (this.mStrip.collapsed)
+              this.setStripVisibilityTo(true);
+
+            this.mPrefs.setBoolPref("browser.tabs.forceHide", false);
+
+            // wire up a progress listener for the new browser object.
+            var position = this.mTabContainer.childNodes.length-1;
+            var tabListener = this.mTabProgressListener(t, b, blank);
+            const filter = Components.classes["@mozilla.org/appshell/component/browser-status-filter;1"]
+                                     .createInstance(Components.interfaces.nsIWebProgress);
+            filter.addProgressListener(tabListener, Components.interfaces.nsIWebProgress.NOTIFY_ALL);
+            b.webProgress.addProgressListener(filter, Components.interfaces.nsIWebProgress.NOTIFY_ALL);
+            this.mTabListeners[position] = tabListener;
+            this.mTabFilters[position] = filter;
+
+            b._fastFind = this.fastFind;
+
+            var uniqueId = "panel" + Date.now() + position;
+            this.mPanelContainer.lastChild.id = uniqueId;
+            t.linkedPanel = uniqueId;
+            t.linkedBrowser = b;
+            t._tPos = position;
+            if (t.previousSibling.selected)
+              t.setAttribute("afterselected", true);
+
+            if (!blank) {
+              // pretend the user typed this so it'll be available till
+              // the document successfully loads
+              b.userTypedValue = aURI;
+
+              if (aPostData === undefined)
+                aPostData = null;
+              const nsIWebNavigation = Components.interfaces.nsIWebNavigation;
+              var flags = nsIWebNavigation.LOAD_FLAGS_NONE;
+              if (aAllowThirdPartyFixup) {
+                flags = nsIWebNavigation.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
+              }
+              b.loadURIWithFlags(aURI, flags, aReferrerURI, aCharset, aPostData);
+            }
+
+
+            // Dispatch a new tab notification.  We do this once we're
+            // entirely done, so that things are in a consistent state
+            // even if the event listener opens or closes tabs.
+            var evt = document.createEvent("Events");
+            evt.initEvent("TabOpen", true, false);
+            t.dispatchEvent(evt);
+
+            return t;
+          ]]>
+        </body>
+      </method>
+
+      <method name="warnAboutClosingTabs">
+      <parameter name="aAll"/>
+      <body>
+        <![CDATA[
+          var numTabs = this.mTabContainer.childNodes.length;
+          var reallyClose = true;
+          if (numTabs <= 1)
+            return reallyClose;
+
+          const pref = "browser.tabs.warnOnClose";
+          var shouldPrompt = this.mPrefs.getBoolPref(pref);
+
+          if (shouldPrompt) {
+            var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
+                                          .getService(Components.interfaces.nsIPromptService);
+
+            //default to true: if it were false, we wouldn't get this far
+            var warnOnClose = { value:true };
+            var bundle = this.mStringBundle;
+            var tabsToClose = numTabs;  //number of tabs to be removed
+            if (!aAll)
+              --tabsToClose;
+
+            var messageKey = (tabsToClose == 1) ? "tabs.closeWarningOneTab" : "tabs.closeWarningMultipleTabs";
+            var closeKey = (tabsToClose == 1) ? "tabs.closeButtonOne" : "tabs.closeButtonMultiple";
+            // focus the window before prompting.
+            // this will raise any minimized window, which will 
+            // make it obvious which window the prompt is for and will
+            // solve the problem of windows "obscuring" the prompt.
+            // see bug #350299 for more details
+            window.focus();
+            var buttonPressed = promptService.confirmEx(window,
+                                                        bundle.getString("tabs.closeWarningTitle"),
+                                                        bundle.getFormattedString(messageKey, [tabsToClose]),
+                                                        (promptService.BUTTON_TITLE_IS_STRING * promptService.BUTTON_POS_0)
+                                                        + (promptService.BUTTON_TITLE_CANCEL * promptService.BUTTON_POS_1),
+                                                        bundle.getString(closeKey),
+                                                        null, null,
+                                                        bundle.getString("tabs.closeWarningPromptMe"),
+                                                        warnOnClose);
+            reallyClose = (buttonPressed == 0);
+            // don't set the pref unless they press OK and it's false
+            if (reallyClose && !warnOnClose.value)
+              this.mPrefs.setBoolPref(pref, false);
+          }
+          return reallyClose;
+        ]]>
+      </body>
+      </method>
+
+      <method name="removeAllTabsBut">
+        <parameter name="aTab"/>
+        <body>
+          <![CDATA[
+            if (this.warnAboutClosingTabs(false)) {
+              if (aTab.localName != "tab")
+                aTab = this.mCurrentTab;
+              else
+                this.mTabContainer.selectedItem = aTab;
+
+              var childNodes = this.mTabContainer.childNodes;
+
+              for (var i = childNodes.length - 1; i >= 0; --i) {
+                if (childNodes[i] != aTab)
+                  this.removeTab(childNodes[i]);
+              }
+            }
+          ]]>
+        </body>
+      </method>
+
+      <method name="removeCurrentTab">
+        <body>
+          <![CDATA[
+            return this.removeTab(this.mCurrentTab);
+          ]]>
+        </body>
+      </method>
+
+      <method name="resetOwner">
+        <parameter name="oldIndex"/>
+        <body>
+          <![CDATA[
+            // Reset the owner property, since we're leaving the modally opened
+            // tab for another.
+            if (oldIndex < this.mTabContainer.childNodes.length) {
+              var tab = this.mTabContainer.childNodes[oldIndex];
+              tab.owner = null;
+            }
+          ]]>
+        </body>
+      </method>
+
+      <method name="removeTab">
+        <parameter name="aTab"/>
+        <body>
+          <![CDATA[
+            this._browsers = null; // invalidate cache
+            if (aTab.localName != "tab")
+              aTab = this.mCurrentTab;
+
+            var l = this.mTabContainer.childNodes.length;
+            if (l == 1 && this.mPrefs.getBoolPref("browser.tabs.autoHide")) {
+              // hide the tab bar
+              this.mPrefs.setBoolPref("browser.tabs.forceHide", true);
+              this.setStripVisibilityTo(false);
+              return;
+            }
+
+            var ds = this.getBrowserForTab(aTab).docShell;
+            if (ds.contentViewer && !ds.contentViewer.permitUnload())
+              return;
+
+            // see notes in addTab
+            var _delayedUpdate = function(aTabContainer) {
+            }
+            setTimeout(_delayedUpdate, 0, this.mTabContainer);
+
+            if (l == 1) {
+              // add a new blank tab to replace the one we're about to close
+              // (this ensures that the remaining tab is as good as new)
+              this.addTab("about:blank");
+              l++;
+            };
+            // We're committed to closing the tab now.  
+            // Dispatch a notification.
+            // We dispatch it before any teardown so that event listeners can
+            // inspect the tab that's about to close.
+            var evt = document.createEvent("Events");
+            evt.initEvent("TabClose", true, false);
+            aTab.dispatchEvent(evt);
+
+            var index = -1;
+            if (this.mCurrentTab == aTab)
+              index = this.mTabContainer.selectedIndex;
+            else {
+              // Find and locate the tab in our list.
+              for (var i = 0; i < l; i++)
+                if (this.mTabContainer.childNodes[i] == aTab)
+                  index = i;
+            }
+
+            // Remove the tab's filter and progress listener.
+            const filter = this.mTabFilters[index];
+            var oldBrowser = this.getBrowserAtIndex(index);
+            oldBrowser.webProgress.removeProgressListener(filter);
+            filter.removeProgressListener(this.mTabListeners[index]);
+            this.mTabFilters.splice(index, 1);
+            this.mTabListeners.splice(index, 1);
+
+            // Remove our title change and blocking listeners
+            oldBrowser.removeEventListener("DOMTitleChanged", this.onTitleChanged, true);
+
+            // We are no longer the primary content area.
+            oldBrowser.setAttribute("type", "content-targetable");
+
+            // Get the index of the tab we're removing before unselecting it
+            var currentIndex = this.mTabContainer.selectedIndex;
+
+            var oldTab = aTab;
+
+            // clean up the before/afterselected attributes before removing the tab
+            oldTab.selected = false;
+
+            // Remove this tab as the owner of any other tabs, since it's going away.
+            for (i = 0; i < this.mTabContainer.childNodes.length; ++i) {
+              var tab = this.mTabContainer.childNodes[i];
+              if ("owner" in tab && tab.owner == oldTab)
+                // |tab| is a child of the tab we're removing, make it an orphan
+                tab.owner = null;
+            }
+
+            // Because of the way XBL works (fields just set JS
+            // properties on the element) and the code we have in place
+            // to preserve the JS objects for any elements that have
+            // JS properties set on them, the browser element won't be
+            // destroyed until the document goes away.  So we force a
+            // cleanup ourselves.
+            // This has to happen before we remove the child so that the
+            // XBL implementation of nsIObserver still works.  But
+            // clearing focusedWindow happens below because it gets
+            // reset by updateCurrentBrowser.
+            oldBrowser.destroy();
+
+            // Remove the tab
+            this.mTabContainer.removeChild(oldTab);
+            // invalidate cache, because mTabContainer is about to change
+            this._browsers = null; 
+            this.mPanelContainer.removeChild(oldBrowser.parentNode);
+
+            // Find the tab to select
+            var newIndex = -1;
+            if (currentIndex > index)
+              newIndex = currentIndex-1;
+            else if (currentIndex < index)
+              newIndex = currentIndex;
+            else {
+              if ("owner" in oldTab && oldTab.owner &&
+                  this.mPrefs.getBoolPref("browser.tabs.selectOwnerOnClose")) {
+                for (i = 0; i < this.mTabContainer.childNodes.length; ++i) {
+                  tab = this.mTabContainer.childNodes[i];
+                  if (tab == oldTab.owner) {
+                    newIndex = i;
+                    break;
+                  }
+                }
+              }
+              if (newIndex == -1)
+                newIndex = (index == l - 1) ? index - 1 : index;
+            }
+
+            // Select the new tab
+            this.selectedTab = this.mTabContainer.childNodes[newIndex];
+
+            for (i = oldTab._tPos; i < this.mTabContainer.childNodes.length; i++) {
+              this.mTabContainer.childNodes[i]._tPos = i;
+            }
+            this.mTabBox.selectedPanel = this.getBrowserForTab(this.mCurrentTab).parentNode;
+            this.mCurrentTab.selected = true;
+
+            this.updateCurrentBrowser();
+
+            // see comment above destroy above
+            oldBrowser.focusedWindow = null;
+            oldBrowser.focusedElement = null;
+          ]]>
+        </body>
+      </method>
+
+      <method name="reloadAllTabs">
+        <body>
+          <![CDATA[
+            var l = this.mPanelContainer.childNodes.length;
+            for (var i = 0; i < l; i++) {
+              try {
+                this.getBrowserAtIndex(i).reload();
+              } catch (e) {
+                // ignore failure to reload so others will be reloaded
+              }
+            }
+          ]]>
+        </body>
+      </method>
+
+      <method name="reloadTab">
+        <parameter name="aTab"/>
+        <body>
+          <![CDATA[
+            if (aTab.localName != "tab")
+              aTab = this.mCurrentTab;
+
+            this.getBrowserForTab(aTab).reload();
+          ]]>
+        </body>
+      </method>
+
+      <method name="onTabBarDblClick">
+        <parameter name="aEvent"/>
+        <body>
+          <![CDATA[
+            // See hack note in the tabbrowser-close-button binding
+            if (!this._blockDblClick && aEvent.button == 0 &&
+                aEvent.originalTarget.localName == "box") {
+              // xxx this needs to check that we're in the empty area of the tabstrip
+              var e = document.createEvent("Events");
+              e.initEvent("NewTab", true, true);
+              this.dispatchEvent(e);
+            }
+          ]]>
+        </body>
+      </method>
+
+      <method name="addProgressListener">
+        <parameter name="aListener"/>
+        <parameter name="aMask"/>
+        <body>
+          <![CDATA[
+            if (!this.mAddProgressListenerWasCalled) {
+              this.mAddProgressListenerWasCalled = true;
+              var autoHide = this.mPrefs.getBoolPref("browser.tabs.autoHide");
+              var forceHide = this.mPrefs.getBoolPref("browser.tabs.forceHide");
+              var tabStripHide = !window.toolbar.visible;
+              if (!autoHide && !forceHide && !tabStripHide)
+                this.setStripVisibilityTo(true);
+            }
+
+            if (!this.mTabbedMode && this.mProgressListeners.length == 1) {
+              // If we are adding a 2nd progress listener, we need to enter tabbed mode
+              // because the browser status filter can only handle one progress listener.
+              // In tabbed mode, mTabProgressListener is used which will iterate over all listeners.
+              this.enterTabbedMode();
+            }
+
+            this.mProgressListeners.push(aListener);
+
+            if (!this.mTabbedMode) {
+              // If someone does this:
+              // addProgressListener, removeProgressListener, addProgressListener
+              // don't create a new filter; reuse the existing filter.
+              if (this.mTabFilters.length == 0) {
+                // hook a filter up to our first browser
+                const filter = Components.classes["@mozilla.org/appshell/component/browser-status-filter;1"]
+                                         .createInstance(Components.interfaces.nsIWebProgress);
+                this.mTabFilters[0] = filter;
+                this.mCurrentBrowser.webProgress.addProgressListener(filter, Components.interfaces.nsIWebProgress.NOTIFY_ALL);
+              }
+
+              // Directly hook the listener up to the filter for better performance
+              this.mTabFilters[0].addProgressListener(aListener, aMask);
+            }
+          ]]>
+        </body>
+      </method>
+
+      <method name="removeProgressListener">
+        <parameter name="aListener"/>
+        <body>
+          <![CDATA[
+            for (var i = 0; i < this.mProgressListeners.length; i++) {
+              if (this.mProgressListeners[i] == aListener) {
+                this.mProgressListeners.splice(i, 1);
+                break;
+              }
+            }
+
+            if (!this.mTabbedMode)
+              // Don't forget to remove it from the filter we hooked it up to
+              this.mTabFilters[0].removeProgressListener(aListener);
+         ]]>
+        </body>
+      </method>
+
+      <method name="getBrowserForTab">
+        <parameter name="aTab"/>
+        <body>
+        <![CDATA[
+          return aTab.linkedBrowser;
+        ]]>
+        </body>
+      </method>
+
+      <property name="tabContainer">
+        <getter>
+          return this.mTabContainer;
+        </getter>
+      </property>
+
+      <property name="selectedTab">
+        <getter>
+          return this.mTabBox.selectedTab;
+        </getter>
+        <setter>
+          <![CDATA[
+          // Update the tab
+          this.mTabBox.selectedTab = val;
+          return val;
+          ]]>
+        </setter>
+      </property>
+
+      <property name="selectedBrowser"
+                onget="return this.mCurrentBrowser;"
+                readonly="true"/>
+
+      <property name="browsers" readonly="true">
+       <getter>
+          <![CDATA[
+            if (!this._browsers) {
+              var browsers = [];
+              var i;
+              browsers.item = function(i) {return this[i];}
+              for (i = 0; i < this.mTabContainer.childNodes.length; i++)
+                browsers.push(this.mTabContainer.childNodes[i].linkedBrowser);
+              this._browsers = browsers;
+            }
+            return this._browsers;
+          ]]>
+        </getter>
+      </property>
+
+      <!-- Drag and drop observer API -->
+      <method name="onDragStart">
+        <parameter name="aEvent"/>
+        <parameter name="aXferData"/>
+        <parameter name="aDragAction"/>
+        <body>
+        <![CDATA[
+          if (aEvent.target.localName == "tab" &&
+              aEvent.originalTarget.localName != "toolbarbutton") {
+            aXferData.data = new TransferData();
+
+            var URI = this.getBrowserForTab(aEvent.target).currentURI;
+            if (URI) {
+              aXferData.data.addDataForFlavour("text/x-moz-url", URI.spec + "\n" + aEvent.target.label);
+              aXferData.data.addDataForFlavour("text/unicode", URI.spec);
+              aXferData.data.addDataForFlavour("text/html", '<a href="' + URI.spec + '">' + aEvent.target.label + '</a>');
+            } else {
+              aXferData.data.addDataForFlavour("text/unicode", "about:blank");
+            }
+          }
+        ]]>
+        </body>
+      </method>
+
+      <method name="canDrop">
+        <parameter name="aEvent"/>
+        <parameter name="aDragSession"/>
+        <body>
+          <![CDATA[
+            /*if (aDragSession.sourceNode &&
+                aDragSession.sourceNode.parentNode == this.mTabContainer &&
+                (aEvent.screenX >= aDragSession.sourceNode.boxObject.screenX &&
+                 aEvent.screenX <= (aDragSession.sourceNode.boxObject.screenX +
+                                    aDragSession.sourceNode.boxObject.width)))
+                return false;*/
+            return true;
+          ]]>
+        </body>
+      </method>
+
+      <method name="onDragOver">
+        <parameter name="aEvent"/>
+        <parameter name="aFlavour"/>
+        <parameter name="aDragSession"/>
+        <body>
+          <![CDATA[
+
+          ]]>
+        </body>
+      </method>
+
+      <method name="onDrop">
+        <parameter name="aEvent"/>
+        <parameter name="aXferData"/>
+        <parameter name="aDragSession"/>
+        <body>
+          <![CDATA[
+            if (aDragSession.sourceNode && aDragSession.sourceNode.parentNode == this.mTabContainer) {
+              var newIndex = this.getNewIndex(aEvent);
+              var oldIndex = aDragSession.sourceNode._tPos;
+
+              /*if (newIndex > oldIndex)
+                newIndex--;*/
+              if (newIndex != oldIndex)
+                this.moveTabTo(this.mTabs[oldIndex], newIndex);
+                var tn=this.mTabs[newIndex].label;
+                this.mTabs[newIndex].label= '';
+                this.mTabs[newIndex].label= tn;
+            } else {
+              var url = transferUtils.retrieveURLFromData(aXferData.data, aXferData.flavour.contentType);
+
+              // valid urls don't contain spaces ' '; if we have a space it isn't a valid url.
+              // Also disallow dropping javascript: or data: urls--bail out
+              if (!url || !url.length || url.indexOf(" ", 0) != -1 ||
+                  /^\s*(javascript|data):/.test(url))
+                return;
+
+              this.dragDropSecurityCheck(aEvent, aDragSession, url);
+
+              var bgLoad = true;
+              try {
+                bgLoad = this.mPrefs.getBoolPref("browser.tabs.loadInBackground");
+              }
+              catch (e) { }
+
+              if (aEvent.shiftKey)
+                bgLoad = !bgLoad;
+
+              if (document.getBindingParent(aEvent.originalTarget).localName != "tab") {
+                // We're adding a new tab.
+                this.loadOneTab(getShortcutOrURI(url), null, null, null, bgLoad, false);
+              }
+              else {
+                // Load in an existing tab.
+                var tab = aEvent.target;
+                try {
+                  this.getBrowserForTab(tab).loadURI(getShortcutOrURI(url));
+                  if (this.mCurrentTab != tab && !bgLoad)
+                    this.selectedTab = tab;
+                } catch(ex) {
+                  // Just ignore invalid urls
+                }
+              }
+            }
+          ]]>
+        </body>
+      </method>
+
+      <method name="onDragExit">
+        <parameter name="aEvent"/>
+        <parameter name="aDragSession"/>
+        <body>
+          <![CDATA[
+            if (aDragSession.sourceNode &&
+                aDragSession.sourceNode.parentNode == this.mTabContainer &&
+                aDragSession.canDrop) {
+              var target = aEvent.relatedTarget;
+              while (target && target != this.mStrip)
+                target = target.parentNode;
+              if (target)
+                return;
+            }
+            this.mTabDropIndicatorBar.setAttribute('dragging','false');
+          ]]>
+        </body>
+      </method>
+
+      <method name="getSupportedFlavours">
+        <body>
+        <![CDATA[
+          var flavourSet = new FlavourSet();
+          flavourSet.appendFlavour("text/x-moz-url");
+          flavourSet.appendFlavour("text/unicode");
+          flavourSet.appendFlavour("application/x-moz-file", "nsIFile");
+          return flavourSet;
+        ]]>
+        </body>
+      </method>
+
+      <method name="moveTabTo">
+        <parameter name="aTab"/>
+        <parameter name="aIndex"/>
+        <body>
+        <![CDATA[
+          this._browsers = null; // invalidate cache
+          this.mTabFilters.splice(aIndex, 0, this.mTabFilters.splice(aTab._tPos, 1)[0]);
+          this.mTabListeners.splice(aIndex, 0, this.mTabListeners.splice(aTab._tPos, 1)[0]);
+
+          var oldPosition = aTab._tPos;
+
+          aIndex = aIndex <= aTab._tPos ? aIndex: aIndex+1;
+
+          this.mCurrentTab.selected = false;
+          this.mTabContainer.insertBefore(aTab, this.mTabContainer.childNodes[aIndex]);
+          // invalidate cache, because mTabContainer is about to change
+          this._browsers = null;
+
+          var i;
+          for (i = 0; i < this.mTabContainer.childNodes.length; i++) {
+            this.mTabContainer.childNodes[i]._tPos = i;
+            this.mTabContainer.childNodes[i].selected = false;
+          }
+          this.mCurrentTab.selected = true;
+
+          var evt = document.createEvent("UIEvents");
+          evt.initUIEvent("TabMove", true, false, window, oldPosition);
+          aTab.dispatchEvent(evt);
+
+          return aTab;
+        ]]>
+        </body>
+      </method>
+
+      <method name="getNewIndex">
+        <parameter name="aEvent"/>
+        <body>
+          <![CDATA[
+            var i;
+              for (i = aEvent.target.localName == "tab" ? aEvent.target._tPos : 0; i < this.mTabs.length; i++)
+                if (aEvent.screenY < this.mTabs[i].boxObject.screenY + this.mTabs[i].boxObject.height) 
+                  return i;
+/*            var i;
+            if (window.getComputedStyle(this.parentNode, null).direction == "ltr") {
+              for (i = aEvent.target.localName == "tab" ? aEvent.target._tPos : 0; i < this.mTabs.length; i++)
+                if (aEvent.screenX < this.mTabs[i].boxObject.screenX + this.mTabs[i].boxObject.width / 2) 
+                  return i;
+            } else {
+               for (i = aEvent.target.localName == "tab" ? aEvent.target._tPos : 0; i < this.mTabs.length; i++)
+                if (aEvent.screenX > this.mTabs[i].boxObject.screenX + this.mTabs[i].boxObject.width / 2)
+                  return i;
+            }*/
+
+            return this.mTabs.length;
+          ]]>
+        </body>
+      </method>
+
+
+      <method name="moveTabForward">
+        <body>
+          <![CDATA[
+            var tabPos = this.mCurrentTab._tPos;
+            if (tabPos < this.browsers.length - 1) {
+              this.moveTabTo(this.mCurrentTab, tabPos + 1);
+              this.mCurrentTab.focus();
+            }
+            else if (this.arrowKeysShouldWrap)
+              this.moveTabToStart();
+          ]]>
+        </body>
+      </method>
+
+      <method name="moveTabBackward">
+        <body>
+          <![CDATA[
+            var tabPos = this.mCurrentTab._tPos;
+            if (tabPos > 0) {
+              this.moveTabTo(this.mCurrentTab, tabPos - 1);
+              this.mCurrentTab.focus();
+            }
+            else if (this.arrowKeysShouldWrap)
+              this.moveTabToEnd();
+          ]]>
+        </body>
+      </method>
+
+      <method name="moveTabToStart">
+        <body>
+          <![CDATA[
+            var tabPos = this.mCurrentTab._tPos;
+            if (tabPos > 0) {
+              this.moveTabTo(this.mCurrentTab, 0);
+              this.mCurrentTab.focus();
+            }
+          ]]>
+        </body>
+      </method>
+
+      <method name="moveTabToEnd">
+        <body>
+          <![CDATA[
+            var tabPos = this.mCurrentTab._tPos;
+            if (tabPos < this.browsers.length - 1) {
+              this.moveTabTo(this.mCurrentTab,
+                                        this.browsers.length - 1);
+              this.mCurrentTab.focus();
+            }
+          ]]>
+        </body>
+      </method>
+
+      <method name="moveTabOver">
+        <parameter name="aEvent"/>
+        <body>
+          <![CDATA[
+            var direction = window.getComputedStyle(this.parentNode, null).direction;
+            if ((direction == "ltr" && aEvent.keyCode == KeyEvent.DOM_VK_RIGHT) ||
+                (direction == "rtl" && aEvent.keyCode == KeyEvent.DOM_VK_LEFT))
+              this.moveTabForward();
+            else
+              this.moveTabBackward();
+          ]]>
+        </body>
+      </method>
+
+      <!-- BEGIN FORWARDED BROWSER PROPERTIES.  IF YOU ADD A PROPERTY TO THE BROWSER ELEMENT
+           MAKE SURE TO ADD IT HERE AS WELL. -->
+      <property name="canGoBack"
+                onget="return this.mCurrentBrowser.canGoBack;"
+                readonly="true"/>
+
+      <property name="canGoForward"
+                onget="return this.mCurrentBrowser.canGoForward;"
+                readonly="true"/>
+
+      <method name="goBack">
+        <body>
+          <![CDATA[
+            return this.mCurrentBrowser.goBack();
+          ]]>
+        </body>
+      </method>
+
+      <method name="goForward">
+        <body>
+          <![CDATA[
+            return this.mCurrentBrowser.goForward();
+          ]]>
+        </body>
+      </method>
+
+      <method name="reload">
+        <body>
+          <![CDATA[
+            return this.mCurrentBrowser.reload();
+          ]]>
+        </body>
+      </method>
+
+      <method name="reloadWithFlags">
+        <parameter name="aFlags"/>
+        <body>
+          <![CDATA[
+            return this.mCurrentBrowser.reloadWithFlags(aFlags);
+          ]]>
+        </body>
+      </method>
+
+      <method name="stop">
+        <body>
+          <![CDATA[
+            return this.mCurrentBrowser.stop();
+          ]]>
+        </body>
+      </method>
+
+      <!-- throws exception for unknown schemes -->
+      <method name="loadURI">
+        <parameter name="aURI"/>
+        <parameter name="aReferrerURI"/>
+        <parameter name="aCharset"/>
+        <body>
+          <![CDATA[
+            return this.mCurrentBrowser.loadURI(aURI, aReferrerURI, aCharset);
+          ]]>
+        </body>
+      </method>
+
+      <!-- throws exception for unknown schemes -->
+      <method name="loadURIWithFlags">
+        <parameter name="aURI"/>
+        <parameter name="aFlags"/>
+        <parameter name="aReferrerURI"/>
+        <parameter name="aCharset"/>
+        <body>
+          <![CDATA[
+            return this.mCurrentBrowser.loadURIWithFlags(aURI, aFlags, aReferrerURI, aCharset);
+          ]]>
+        </body>
+      </method>
+
+      <method name="goHome">
+        <body>
+          <![CDATA[
+            return this.mCurrentBrowser.goHome();
+          ]]>
+        </body>
+      </method>
+
+      <property name="homePage">
+        <getter>
+          <![CDATA[
+            return this.mCurrentBrowser.homePage;
+          ]]>
+        </getter>
+        <setter>
+          <![CDATA[
+            this.mCurrentBrowser.homePage = val;
+            return val;
+          ]]>
+        </setter>
+      </property>
+
+      <method name="gotoIndex">
+        <parameter name="aIndex"/>
+        <body>
+          <![CDATA[
+            return this.mCurrentBrowser.gotoIndex(aIndex);
+          ]]>
+        </body>
+      </method>
+
+      <method name="attachFormFill">
+        <body><![CDATA[
+          for (var i = 0; i < this.mPanelContainer.childNodes.length; ++i) {
+            var cb = this.getBrowserAtIndex(i);
+            cb.attachFormFill();
+          }
+        ]]></body>
+      </method>
+
+      <method name="detachFormFill">
+        <body><![CDATA[
+          for (var i = 0; i < this.mPanelContainer.childNodes.length; ++i) {
+            var cb = this.getBrowserAtIndex(i);
+            cb.detachFormFill();
+          }
+        ]]></body>
+      </method>
+
+      <property name="pageReport"
+                onget="return this.mCurrentBrowser.pageReport;"
+                readonly="true"/>
+
+      <property name="currentURI"
+                onget="return this.mCurrentBrowser.currentURI;"
+                readonly="true"/>
+
+      <field name="_fastFind">null</field>
+      <property name="fastFind"
+                readonly="true">
+        <getter>
+        <![CDATA[
+          if (!this._fastFind) {
+            this._fastFind = Components.classes["@mozilla.org/typeaheadfind;1"]
+                                       .createInstance(Components.interfaces.nsITypeAheadFind_MOZILLA_1_8_BRANCH);
+            this._fastFind.init(this.docShell);
+          }
+          return this._fastFind;
+        ]]>
+        </getter>
+      </property>
+
+      <property name="findString"
+                onget="return this.mCurrentBrowser.findString;"
+                readonly="true"/>
+
+      <property name="docShell"
+                onget="return this.mCurrentBrowser.docShell"
+                readonly="true"/>
+
+      <property name="webNavigation"
+                onget="return this.mCurrentBrowser.webNavigation"
+                readonly="true"/>
+
+      <property name="webBrowserFind"
+                readonly="true"
+                onget="return this.mCurrentBrowser.webBrowserFind"/>
+
+      <property name="webProgress"
+                readonly="true"
+                onget="return this.mCurrentBrowser.webProgress"/>
+
+      <property name="contentWindow"
+                readonly="true"
+                onget="return this.mCurrentBrowser.contentWindow"/>
+
+      <property name="sessionHistory"
+                onget="return this.mCurrentBrowser.sessionHistory;"
+                readonly="true"/>
+
+      <property name="markupDocumentViewer"
+                onget="return this.mCurrentBrowser.markupDocumentViewer;"
+                readonly="true"/>
+
+      <property name="contentViewerEdit"
+                onget="return this.mCurrentBrowser.contentViewerEdit;"
+                readonly="true"/>
+
+      <property name="contentViewerFile"
+                onget="return this.mCurrentBrowser.contentViewerFile;"
+                readonly="true"/>
+
+      <property name="documentCharsetInfo"
+                onget="return this.mCurrentBrowser.documentCharsetInfo;"
+                readonly="true"/>
+
+      <property name="contentDocument"
+                onget="return this.mCurrentBrowser.contentDocument;"
+                readonly="true"/>
+
+      <property name="contentTitle"
+                onget="return this.mCurrentBrowser.contentTitle;"
+                readonly="true"/>
+
+      <property name="securityUI"
+                onget="return this.mCurrentBrowser.securityUI;"
+                readonly="true"/>
+
+      <method name="find">
+        <body>
+          <![CDATA[
+            return this.mCurrentBrowser.find();
+          ]]>
+        </body>
+      </method>
+
+      <method name="findAgain">
+        <body>
+          <![CDATA[
+            return this.mCurrentBrowser.findAgain();
+          ]]>
+        </body>
+      </method>
+
+      <method name="findPrevious">
+        <body>
+          <![CDATA[
+            return this.mCurrentBrowser.findPrevious();
+          ]]>
+        </body>
+      </method>
+
+      <method name="dragDropSecurityCheck">
+        <parameter name="aEvent"/>
+        <parameter name="aDragSession"/>
+        <parameter name="aUri"/>
+        <body>
+          <![CDATA[
+            // Do a security check for drag n' drop. Make sure the
+            // source document can load the dragged link.
+            var sourceDoc = aDragSession.sourceDocument;
+
+            if (sourceDoc) {
+              // Strip leading and trailing whitespace, then try to
+              // create a URI from the dropped string. If that
+              // succeeds, we're dropping a URI and we need to do a
+              // security check to make sure the source document can
+              // load the dropped URI. We don't so much care about
+              // creating the real URI here (i.e. encoding differences
+              // etc don't matter), we just want to know if aUri
+              // really is a URI.
+
+              var uriStr = aUri.replace(/^\s*|\s*$/g, '');
+              var uri = null;
+
+              try {
+                uri = Components.classes["@mozilla.org/network/io-service;1"]
+                  .getService(Components.interfaces.nsIIOService)
+                  .newURI(uriStr, null, null);
+              } catch (e) {
+              }
+
+              if (uri) {
+                // aUri is a URI, do the security check.
+                var sourceURI = sourceDoc.documentURI;
+
+                const nsIScriptSecurityManager =
+                  Components.interfaces.nsIScriptSecurityManager;
+                var secMan =
+                  Components.classes["@mozilla.org/scriptsecuritymanager;1"]
+                  .getService(nsIScriptSecurityManager);
+
+                try {
+                  secMan.checkLoadURIStr(sourceURI, uriStr,
+                                         nsIScriptSecurityManager.STANDARD);
+                } catch (e) {
+                  // Stop event propagation right here.
+                  aEvent.stopPropagation();
+
+                  throw "Drop of " + aUri + " denied.";
+                }
+              }
+            }
+          ]]>
+        </body>
+      </method>
+
+      <field name="_keyEventHandler" readonly="true">
+      <![CDATA[({
+        tabbrowser: this,
+        handleEvent: function handleEvent(aEvent) {
+          if (!aEvent.isTrusted) {
+            // Don't let untrusted events mess with tabs.
+            return;
+          }
+
+          if (('shiftKey' in aEvent && aEvent.shiftKey) ||
+              ('altKey' in aEvent && aEvent.altKey))
+            return;
+          if (('ctrlKey' in aEvent && aEvent.ctrlKey) &&
+              !('metaKey' in aEvent && aEvent.metaKey)) {
+            if (aEvent.keyCode == KeyEvent.DOM_VK_F4 &&
+                this.tabbrowser.mTabBox.handleCtrlPageUpDown) {
+              this.tabbrowser.removeCurrentTab();
+
+              aEvent.stopPropagation();
+              aEvent.preventDefault();
+              return;
+            }
+            if (aEvent.target.localName == "tabbrowser") {
+              switch (aEvent.keyCode) {
+                case KeyEvent.DOM_VK_UP:
+                  this.tabbrowser.moveTabBackward();
+                  break;
+                case KeyEvent.DOM_VK_DOWN:
+                  this.tabbrowser.moveTabForward();
+                  break;
+                case KeyEvent.DOM_VK_RIGHT:
+                case KeyEvent.DOM_VK_LEFT:
+                  this.tabbrowser.moveTabOver(aEvent);
+                  break;
+                case KeyEvent.DOM_VK_HOME:
+                  this.tabbrowser.moveTabToStart();
+                  break;
+                case KeyEvent.DOM_VK_END:
+                  this.tabbrowser.moveTabToEnd();
+                  break;
+                default:
+                  // Stop the keypress event for the above keyboard
+                  // shortcuts only.
+                  return;
+              }
+              aEvent.stopPropagation();
+              aEvent.preventDefault();
+            }
+          }
+        }
+      })]]>
+      </field>
+
+      <property name="canFindAgain"
+                onget="return this.mCurrentBrowser.canFindAgain;"
+                readonly="true"/>
+
+      <property name="userTypedClear"
+                onget="return this.mCurrentBrowser.userTypedClear;"
+                onset="return this.mCurrentBrowser.userTypedClear = val;"/>
+
+      <property name="userTypedValue"
+                onget="return this.mCurrentBrowser.userTypedValue;"
+                onset="return this.mCurrentBrowser.userTypedValue = val;"/>
+
+      <property name="forceSyncURLBarUpdate"
+                onget="return this.mModalDialogShowing;"/>
+
+      <method name="createTooltip">
+        <parameter name="event"/>
+        <body>
+          <![CDATA[
+            event.stopPropagation();
+            var tn = document.tooltipNode;
+            if (tn.localName != "tab")
+              return false; // Not a tab, so cancel the tooltip
+            if ("mOverCloseButton" in tn && tn.mOverCloseButton) {
+              event.target.setAttribute("label", tn.getAttribute("closetabtext"));
+              return true;
+            }
+            if (tn.hasAttribute("label")) {
+              event.target.setAttribute("label", tn.getAttribute("label"));
+              return true;
+            }
+            return false;
+          ]]>
+        </body>
+      </method>
+
+      <constructor>
+        <![CDATA[
+               try{this.mStrip.width= this.mPrefs.getIntPref("browser.tabs.width");}catch(ex){};
+
+          this.mCurrentBrowser = this.mPanelContainer.childNodes[0].firstChild;
+          this.mCurrentTab = this.mTabContainer.firstChild;
+          document.addEventListener("keypress", this._keyEventHandler, false);
+
+          var uniqueId = "panel" + Date.now();
+          this.mPanelContainer.childNodes[0].id = uniqueId;
+          this.mTabContainer.childNodes[0].linkedPanel = uniqueId;
+          this.mTabContainer.childNodes[0]._tPos = 0;
+          this.mTabContainer.childNodes[0].linkedBrowser = this.mPanelContainer.childNodes[0].firstChild;
+        ]]>
+      </constructor>
+
+      <destructor>
+        <![CDATA[
+          for (var i = 0; i < this.mTabListeners.length; ++i) {
+            this.getBrowserAtIndex(i).webProgress.removeProgressListener(this.mTabFilters[i]);
+            this.mTabFilters[i].removeProgressListener(this.mTabListeners[i]);
+            this.mTabFilters[i] = null;
+            this.mTabListeners[i] = null;
+            this.getBrowserAtIndex(i).removeEventListener("DOMTitleChanged", this.onTitleChanged, true);
+          }
+          document.removeEventListener("keypress", this._keyEventHandler, false);
+        ]]>
+      </destructor>
+    </implementation>
+
+    <handlers>
+      <handler event="DOMLinkAdded" phase="capturing" action="this.onLinkAdded(event);"/>
+
+      <handler event="DOMWindowClose" phase="capturing">
+        <![CDATA[
+          if (!event.isTrusted)
+            return;
+
+          const browsers = this.mPanelContainer.childNodes;
+          if (browsers.length == 1) {
+            // There's only one browser left. If a window is being
+            // closed and the window is *not* the window in the
+            // browser that's still around, prevent the event's default
+            // action to prevent closing a window that's being closed
+            // already.
+            if (this.getBrowserAtIndex(0).contentWindow != event.target)
+              event.preventDefault();
+
+            return;
+          }
+
+          var i = 0;
+          for (; i < browsers.length; ++i) {
+            if (this.getBrowserAtIndex(i).contentWindow == event.target) {
+              this.removeTab(this.mTabContainer.childNodes[i]);
+              event.preventDefault();
+
+              break;
+            }
+          }
+        ]]>
+      </handler>
+      <handler event="DOMWillOpenModalDialog" phase="capturing">
+        <![CDATA[
+          if (!event.isTrusted)
+            return;
+
+          // We're about to open a modal dialog, make sure the opening
+          // tab is brought to the front.
+
+          var targetTop = event.target.top;
+
+          for (var i = 0; i < browsers.length; ++i) {
+            if (this.getBrowserAtIndex(i).contentWindow == targetTop) {
+              this.mModalDialogShowing = true;
+              this.selectedTab = this.mTabContainer.childNodes[i];
+
+              break;
+            }
+          }
+        ]]>
+      </handler>
+      <handler event="DOMModalDialogClosed" phase="capturing">
+        <![CDATA[
+          if (!event.isTrusted)
+            return;
+
+          this.mModalDialogShowing = false;
+        ]]>
+      </handler>
+      <handler event="resize">
+        <![CDATA[
+               this.mPrefs.setIntPref("browser.tabs.width", this.mStrip.width);
+      ]]>
+      </handler>
+    </handlers>
+  </binding>
+
+  <binding id="tabbrowser-tabs"
+           extends="chrome://global/content/bindings/tabbox.xml#tabs" >
+    <content>
+       <xul:vbox style="overflow-y: auto; overflow-x: hidden;" anonid="arrowscrollbox" flex="1">
+               <children includes="tab"/>
+        </xul:vbox>
+    </content>
+    <handlers>
+       <!--<handler event="dblclick">
+               BrowserOpenTab();
+       </handler>
+       <handler event="click" button="1">
+               if (event.target==this) undoCloseTab();
+       </handler>-->
+    </handlers>
+  </binding>
+
+  <binding id="tabbrowser-tab" display="xul:box" extends="chrome://global/content/bindings/tabbox.xml#tab">
+       <content chromedir="&locale.dir;">
+               <xul:hbox class="tab-mid box-inherit" xbl:inherits="align,dir,pack,orient,selected" flex="1">
+                       <xul:stack flex="1">
+                               <xul:hbox><xul:vbox><xul:image class="tab-icon" xbl:inherits="validate,src=image" /></xul:vbox></xul:hbox>
+                               <xul:description class="tab-text" anonid="tabtext" xbl:inherits="accesskey,crop,disabled" flex="1" >\(0_0)/</xul:description>
+                       </xul:stack>
+                       <!--<xul:label class="tab-text" xbl:inherits="value=label,accesskey,crop,disabled" flex="1"/>-->
+               </xul:hbox>
+       </content>
+
+    <implementation>
+      <field name="mCorrespondingMenuitem">null</field>
+      <constructor>
+       
+      </constructor>
+      <method name="textinit">
+        <body>
+               document.getAnonymousElementByAttribute(this,'anonid','tabtext').textContent= this.label;
+        </body>
+      </method>
+    </implementation>
+
+    <handlers>
+       <handler event="DOMAttrModified"><![CDATA[              if (event.attrName=='label') this.textinit();           ]]></handler>
+    </handlers>
+
+  </binding>
+
+</bindings>