%tabBrowserDTD; ]> document.getElementById(this.getAttribute("tabcontainer")); this.tabContainer.childNodes; Components.classes["@mozilla.org/docshell/urifixup;1"] .getService(Components.interfaces.nsIURIFixup); Components.classes["@mozilla.org/browser/favicon-service;1"] .getService(Components.interfaces.nsIFaviconService); Components.classes["@mozilla.org/autocomplete/search;1?name=history"] .getService(Components.interfaces.mozIPlacesAutoComplete); document.getAnonymousElementByAttribute(this, "anonid", "tabbox"); document.getAnonymousElementByAttribute(this, "anonid", "panelcontainer"); document.getAnonymousElementByAttribute(this, "anonid", "tbstringbundle"); null null null [] [] [] [] false #ifdef XP_MACOSX true #else false #endif false null null false real JS array let prompts = Array.slice(els); return prompts; }, }; return promptBox; ]]> 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) // We need to add 2 because loadURIWithFlags may have // cancelled a pending load which would have cleared // its anchor scroll detection temporary increment. if (aWebProgress.DOMWindow == this.mBrowser.contentWindow) this.mBrowser.userTypedClear += 2; if (!this.mBlank) { if (!(aStateFlags & nsIWebProgressListener.STATE_RESTORING)) { this.mTab.setAttribute("busy", "true"); this.mTabBrowser.setTabTitleLoading(this.mTab); } if (this.mTab.selected) 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 > 1) this.mBrowser.userTypedClear -= 2; else 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.mTab.removeAttribute("progress"); 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.connecting")) this.mTabBrowser.setTabTitle(this.mTab); if (this.mTab.selected) this.mTabBrowser.mIsBusy = false; } if (oldBlank) { this._callProgressListeners("onUpdateCurrentBrowser", [aStateFlags, aStatus, "", 0], true, false); } else { this._callProgressListeners("onStateChange", [aWebProgress, aRequest, aStateFlags, aStatus], true, false); } this._callProgressListeners("onStateChange", [aWebProgress, aRequest, aStateFlags, aStatus], false); 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) { // OnLocationChange is called for both the top-level content // and the subframes. let topLevel = aWebProgress.DOMWindow == this.mBrowser.contentWindow; if (topLevel) { // The document loaded correctly, clear the value if we should if (this.mBrowser.userTypedClear > 0) this.mBrowser.userTypedValue = null; // Clear out the missing plugins list since it's related to the // previous location. this.mBrowser.missingPlugins = null; // Don't clear the favicon if this onLocationChange was // triggered by a pushState or a replaceState. See bug 550565. if (aWebProgress.isLoadingDocument && !(this.mBrowser.docShell.loadType & Ci.nsIDocShell.LOAD_CMD_PUSHSTATE)) this.mBrowser.mIconURL = null; let autocomplete = this.mTabBrowser._placesAutocomplete; if (this.mBrowser.registeredOpenURI) { autocomplete.unregisterOpenPage(this.mBrowser.registeredOpenURI); delete this.mBrowser.registeredOpenURI; } if (aLocation.spec != "about:blank") { autocomplete.registerOpenPage(aLocation); this.mBrowser.registeredOpenURI = aLocation; } } if (!this.mBlank) { this._callProgressListeners("onLocationChange", [aWebProgress, aRequest, aLocation]); } if (topLevel) this.mBrowser.lastURI = aLocation; }, onStatusChange: function (aWebProgress, aRequest, aStatus, aMessage) { if (this.mBlank) return; this._callProgressListeners("onStatusChange", [aWebProgress, aRequest, aStatus, aMessage]); this.mMessage = aMessage; }, onSecurityChange: function (aWebProgress, aRequest, aState) { this._callProgressListeners("onSecurityChange", [aWebProgress, aRequest, aState]); }, onRefreshAttempted: function (aWebProgress, aURI, aDelay, aSameURI) { return this._callProgressListeners("onRefreshAttempted", [aWebProgress, aURI, aDelay, aSameURI]); }, QueryInterface: function (aIID) { if (aIID.equals(Components.interfaces.nsIWebProgressListener) || aIID.equals(Components.interfaces.nsIWebProgressListener2) || aIID.equals(Components.interfaces.nsISupportsWeakReference) || aIID.equals(Components.interfaces.nsISupports)) return this; throw Components.results.NS_NOINTERFACE; } }); ]]> 1 false/true NO var multiple = aURIs.length > 1; var owner = multiple || aLoadInBackground ? null : this.selectedTab; var firstTabAdded = null; if (aReplace) { try { this.loadURI(aURIs[0], null, null); } catch (e) { // Ignore failure in case a URI is wrong, so we can continue // opening the next ones. } } else firstTabAdded = this.addTab(aURIs[0], {ownerTab: owner, skipAnimation: multiple}); var tabNum = this.tabContainer.selectedIndex; for (let i = 1; i < aURIs.length; ++i) { let tab = this.addTab(aURIs[i], {skipAnimation: true}); if (aReplace) this.moveTabTo(tab, ++tabNum); } if (!aLoadInBackground) { if (firstTabAdded) { // .selectedTab setter focuses the content area this.selectedTab = firstTabAdded; } else window.content.focus(); } ]]> = 0; --i) { if (tabs[i] != aTab && !tabs[i].pinned) this.removeTab(tabs[i]); } } ]]> [] 3 /* don't want lots of concurrent animations */ || aTab.getAttribute("fadein") != "true" /* fade-in transition hasn't been triggered yet */ || window.getComputedStyle(aTab).maxWidth == "0.1px" /* fade-in transition hasn't moved yet */ || !Services.prefs.getBoolPref("browser.tabs.animate")) { this._endRemoveTab(aTab); return; } this._blurTab(aTab); aTab.style.maxWidth = ""; // ensure that fade-out transition happens aTab.removeAttribute("fadein"); setTimeout(function (tab, tabbrowser) { if (tab.parentNode && window.getComputedStyle(tab).maxWidth == "0.1px") { NS_ASSERT(false, "Giving up waiting for the tab closing animation to finish (bug 608589)"); tabbrowser._endRemoveTab(tab); } }, 3000, aTab, this); ]]> false this.mTabsProgressListeners.push(aListener); = 0 && aIndex < tabs.length) this.selectedTab = tabs[aIndex]; if (aEvent) { aEvent.preventDefault(); aEvent.stopPropagation(); } ]]> return this.mTabBox.selectedTab; 0) { this.moveTabTo(this.mCurrentTab, tabPos - 1); this.mCurrentTab.focus(); } else if (this.arrowKeysShouldWrap) this.moveTabToEnd(); ]]> 0) { this.moveTabTo(this.mCurrentTab, 0); this.mCurrentTab.focus(); } ]]> null Application.console.log("enterTabbedMode is an obsolete method and " + "will be removed in a future release."); true this.tabContainer.visible = aShow; return this.tabContainer.visible; # This is a hack to circumvent bug 472020, otherwise the tabs show up on the # right of the newtab button. # This is to ensure anything extensions put here will go before the newtab # button, necessary due to the previous hack. document.getElementById(this.getAttribute("tabbrowser")); this.tabbrowser.mTabBox; document.getElementById("tabContextMenu"); 0 document.getAnonymousElementByAttribute(this, "anonid", "arrowscrollbox"); false document.getAnonymousElementByAttribute(this, "anonid", "tab-drop-indicator"); = this._dragTime + this._dragOverDelay) this.selectedItem = tab; ind.collapsed = true; return; } } var newIndex = this._getDropIndex(event); var scrollRect = tabStrip.scrollClientRect; var rect = this.getBoundingClientRect(); var minMargin = scrollRect.left - rect.left; var maxMargin = Math.min(minMargin + scrollRect.width, scrollRect.right); if (!ltr) [minMargin, maxMargin] = [this.clientWidth - maxMargin, this.clientWidth - minMargin]; var newMargin; if (pixelsToScroll) { // If we are scrolling, put the drop indicator at the edge, // so that it doesn't jump while scrolling. newMargin = (pixelsToScroll > 0) ? maxMargin : minMargin; } else { if (newIndex == this.childNodes.length) { let tabRect = this.childNodes[newIndex-1].getBoundingClientRect(); if (ltr) newMargin = tabRect.right - rect.left; else newMargin = rect.right - tabRect.left; } else { let tabRect = this.childNodes[newIndex].getBoundingClientRect(); if (ltr) newMargin = tabRect.left - rect.left; else newMargin = rect.right - tabRect.right; } } ind.collapsed = false; newMargin += ind.clientWidth / 2; if (!ltr) newMargin *= -1; ind.style.MozTransform = "translate(" + Math.round(newMargin) + "px)"; ind.style.MozMarginStart = (-ind.clientWidth) + "px"; ]]> document.getAnonymousElementByAttribute(this, "anonid", "tab-drag-panel"); null right) transformX += right - tabX - tabWidth - (ltr ? 0 : 1); draggedTab.style.MozTransform = "translate(" + transformX + "px)"; let newIndex = this._getDropIndex(event, draggedTab); let tabAtNewIndex = this.childNodes[newIndex > draggedTab._tPos ? newIndex-1 : newIndex]; this._positionDropIndicator(event, tabAtNewIndex.pinned == draggedTab.pinned); if (newIndex == draggedTab._dragData._dropIndex) return; draggedTab._dragData._dropIndex = newIndex; if (!ltr) tabWidth *= -1; tabs.forEach(function(tab) { if (tab == draggedTab || tab.pinned != draggedTab.pinned) return; else if (tab._tPos < draggedTab._tPos && tab._tPos >= newIndex) tab.style.MozTransform = "translate(" + tabWidth + "px)"; else if (tab._tPos > draggedTab._tPos && tab._tPos < newIndex) tab.style.MozTransform = "translate(" + -tabWidth + "px)"; else tab.style.MozTransform = ""; }); ]]> = win.screenX + win.outerWidth || event.screenY < win.screenY || event.screenY >= win.screenY + win.outerHeight); } if (isEventOutsideWindow(event, data._targetWindow) || Services.ww.activeWindow != data._targetWindow) { // Iterate through browser windows in hopefully front-to-back order. let winEnum = Services.wm.getZOrderDOMWindowEnumerator("navigator:browser", true); let wins = []; while (winEnum.hasMoreElements()) wins.push(winEnum.getNext()); // Work around broken z-order enumerator on Linux. See bug 156333. if (!wins.length) { winEnum = Services.wm.getEnumerator("navigator:browser"); while (winEnum.hasMoreElements()) wins.unshift(winEnum.getNext()); } wins.every(function(win) { if (win.closed || win.windowState == STATE_MINIMIZED || isEventOutsideWindow(event, win)) return true; data._targetWindow = win; win.focus(); // Raise window when cursor moves over it. }); } let detached = (this.getAttribute("drag") == "detach"); let loneTab = (this.childElementCount == 1); let bo = loneTab ? draggedTab.boxObject : this.parentNode.boxObject; // Detach tab if outside window, to the left or right of tab strip, or // at least one tab height above or below it. if (data._targetWindow != window || event.screenX < bo.screenX || event.screenX >= bo.screenX + bo.width || event.screenY < bo.screenY - (detached || loneTab ? 0 : 1) * bo.height || event.screenY >= bo.screenY + (detached || loneTab ? 1 : 2) * bo.height) { if (data._targetWindow != window && data._targetWindow.windowState != STATE_MINIMIZED) { let that = data._targetWindow.gBrowser.tabContainer; let bo = that.parentNode.boxObject; if (event.screenX >= bo.screenX && event.screenX < bo.screenX + bo.width && event.screenY >= bo.screenY && event.screenY < bo.screenY + bo.height) { that._positionDropIndicator(event); data._dropTarget = that; } } let dragPanel = this._tabDragPanel; if (data._dropTarget) dragPanel.setAttribute("target", "true"); else dragPanel.removeAttribute("target"); if (!detached) { this.setAttribute("drag", "detach"); this._clearDragTransforms(); this._tabDropIndicator.collapsed = true; if (draggedTab.style.maxWidth) { data._maxWidth = draggedTab.style.maxWidth; draggedTab.style.maxWidth = ""; } delete data._dropIndex; let label = dragPanel.firstChild; let preview = dragPanel.lastChild; label.value = draggedTab.label; label.width = preview.width = Math.min(outerWidth / 2, screen.availWidth / 5); let aspectRatio = this.tabbrowser.clientWidth / this.tabbrowser.clientHeight; preview.height = Math.min(preview.width / aspectRatio, screen.availHeight / 5); dragPanel.hidden = false; dragPanel.openPopupAtScreen(event.screenX, event.screenY, false); } let width = dragPanel.clientWidth; let [left, top] = this._getAdjustedCoords(event.screenX, event.screenY, width, dragPanel.clientHeight, width / 2, 12, true); dragPanel.moveTo(left, top); return true; } if (detached) { // Otherwise, put tab back in the tab strip. this.setAttribute("drag", "move"); if (data._maxWidth) { draggedTab.style.setProperty("max-width", data._maxWidth, "important"); delete draggedTab._maxWidth; } this.mTabstrip._updateScrollButtonsDisabledState(); this._tabDragPanel.hidePopup(); } ]]> oldIndex) newIndex--; this.removeAttribute("drag"); this._endTabDrag(); if (!draggedTab.pinned && newIndex < this.tabbrowser._numPinnedTabs) this.tabbrowser.pinTab(draggedTab); else if (draggedTab.pinned && newIndex >= this.tabbrowser._numPinnedTabs) this.tabbrowser.unpinTab(draggedTab); else if (Services.prefs.getBoolPref("browser.tabs.animate")) { let difference = 0; // Calculate number of visible tabs between start and destination. if (newIndex != oldIndex) { let tabs = this.tabbrowser.visibleTabs; for (let i = 0; i < tabs.length; i++) { let position = tabs[i]._tPos; if (position <= newIndex && position > oldIndex) difference++; else if (position >= newIndex && position < oldIndex) difference--; } } let displacement = difference * draggedTab.getBoundingClientRect().width; if (window.getComputedStyle(this).direction == "rtl") displacement *= -1; let destination = "translate(" + displacement + "px)"; if (draggedTab.style.MozTransform != destination) { this.setAttribute("drag", "finish"); draggedTab.style.MozTransform = destination; draggedTab.addEventListener("transitionend", function finish(event) { if (event.eventPhase != Event.AT_TARGET || event.propertyName != "-moz-transform") return; draggedTab.removeEventListener("transitionend", finish); draggedTab.removeAttribute("dragged"); let that = draggedTab.parentNode; that.removeAttribute("drag"); that._clearDragTransforms(); that.tabbrowser.moveTabTo(draggedTab, newIndex); }); return; } } draggedTab.removeAttribute("dragged"); this._clearDragTransforms(); this.tabbrowser.moveTabTo(draggedTab, newIndex); ]]> this.tabbrowser.visibleTabs.forEach(function(visibleTab) { visibleTab.style.MozTransform = ""; }); 350 0 this.mTabClipWidth) this.setAttribute("closebuttons", "alltabs"); else this.setAttribute("closebuttons", "activetab"); } break; case 2: case 3: this.setAttribute("closebuttons", "never"); break; } var tabstripClosebutton = document.getElementById("tabs-closebutton"); if (tabstripClosebutton && tabstripClosebutton.parentNode == this._container) tabstripClosebutton.collapsed = this.mCloseButtons != 3; ]]> tabStrip.scrollSize) tabStrip.scrollByPixels(-1); } catch (e) {} ]]> document.getAnonymousElementByAttribute(this, "anonid", "closing-tabs-spacer"); NaN false false false tabs[tabs.length-1]._tPos); var tabWidth = aTab.getBoundingClientRect().width; if (!this._tabDefaultMaxWidth) this._tabDefaultMaxWidth = parseFloat(window.getComputedStyle(aTab).maxWidth); this._lastTabClosedByMouse = true; if (this.getAttribute("overflow") == "true") { // Don't need to do anything if we're in overflow mode and aren't scrolled // all the way to the right, or if we're closing the last tab. if (isEndTab || !this.mTabstrip._scrollButtonDown.disabled) return; // If the tab has an owner that will become the active tab, the owner will // be to the left of it, so we actually want the left tab to slide over. // This can't be done as easily in non-overflow mode, so we don't bother. if (aTab.owner) return; this._expandSpacerBy(tabWidth); } else { // non-overflow mode // Locking is neither in effect nor needed, so let tabs expand normally. if (isEndTab && !this._hasTabTempMaxWidth) return; let numPinned = this.tabbrowser._numPinnedTabs; // Force tabs to stay the same width, unless we're closing the last tab, // which case we need to let them expand just enough so that the overall // tabbar width is the same. if (isEndTab) { let numNormalTabs = tabs.length - numPinned; tabWidth = tabWidth * (numNormalTabs + 1) / numNormalTabs; if (tabWidth > this._tabDefaultMaxWidth) tabWidth = this._tabDefaultMaxWidth; } tabWidth += "px"; for (let i = numPinned; i < tabs.length; i++) { let tab = tabs[i]; tab.style.setProperty("max-width", tabWidth, "important"); if (!isEndTab) { // keep tabs the same width tab.style.MozTransition = "none"; tab.clientTop; // flush styles to skip animation; see bug 649247 tab.style.MozTransition = ""; } } this._hasTabTempMaxWidth = true; window.addEventListener("mouseout", this); } ]]> 0; if (doPosition) { this.setAttribute("positionpinnedtabs", "true"); let scrollButtonWidth = this.mTabstrip._scrollButtonDown.scrollWidth; let paddingStart = this.mTabstrip.scrollboxPaddingStart; let width = 0; for (let i = numPinned - 1; i >= 0; i--) { let tab = this.childNodes[i]; width += tab.scrollWidth; tab.style.MozMarginStart = - (width + scrollButtonWidth + paddingStart) + "px"; } this.style.MozMarginStart = width + paddingStart + "px"; } else { this.removeAttribute("positionpinnedtabs"); for (let i = 0; i < numPinned; i++) { let tab = this.childNodes[i]; tab.style.MozMarginStart = ""; } this.style.MozMarginStart = ""; } this.mTabstrip.ensureElementIsVisible(this.selectedItem, false); ]]> = bo.screenX && aEvent.screenX < bo.screenX + bo.width && aEvent.screenY >= bo.screenY && aEvent.screenY < bo.screenY + bo.height) break; let tabContextMenu = document.getElementById("tabContextMenu"); if (tabContextMenu.state == "open") tabContextMenu.addEventListener("popuphidden", this); else this._unlockTabSizing(); break; case "popuphidden": // Tab context menu was closed. if (aEvent.eventPhase != Event.AT_TARGET) break; aEvent.target.removeEventListener("popuphidden", this); this._unlockTabSizing(); break; case "mousemove": this._handleTabDrag(aEvent); break; case "mouseup": this._handleTabDrop(aEvent); break; case "TabSelect": // Focus was stolen from dragged tab! this._endTabDrag(aEvent); window.focus(); break; case "scroll": // Tab strip was scrolled. this._handleTabDrag(); break; } ]]> this.mTabstrip._scrollButtonDown; boxObject.screenX + boxObject.width * .75) return null; } return tab; ]]> b; let ltr = (window.getComputedStyle(this).direction == "ltr"); let eX = event.screenX; let tabs = this.tabbrowser.visibleTabs; if (draggedTab) { let dist = draggedTab._dragData._dragDistX; let tabX = draggedTab.boxObject.screenX + dist; let draggingRight = dist > 0; if (draggingRight) tabX += draggedTab.boxObject.width; // iterate through app tabs first, since their z-index is higher else if (!draggedTab.pinned) for (let i = 0, numPinned = this.tabbrowser._numPinnedTabs; i < numPinned; i++) if (compare(eX, tabs[i].boxObject.screenX + tabs[i].boxObject.width / 2, ltr)) return i; let i = tabs.indexOf(draggedTab), tab = draggedTab, next; while (next = ltr ^ draggingRight ? tabs[--i] : tabs[++i]) { let x = next.pinned == draggedTab.pinned ? tabX : eX; let middleOfNextTab = next.boxObject.screenX + next.boxObject.width / 2; if (!compare(x, middleOfNextTab, !draggingRight)) break; // ensure an app tab is actually inside the normal tab region if (draggedTab.pinned && !next.pinned && x < this.mTabstrip._scrollButtonUp.boxObject.screenX) break; tab = next; } return tab._tPos + (ltr ^ draggingRight ? 0 : 1); } let tab = this._getDragTargetTab(event); for (let i = tab ? tab._tPos : 0; i < tabs.length; i++) if (compare(eX, tabs[i].boxObject.screenX + tabs[i].boxObject.width / 2, ltr)) return tabs[i]._tPos; return this.childElementCount; ]]> 1) return dt.effectAllowed = "none"; if (browserDragAndDrop.canDropLink(event)) { // Here we need to do this manually return dt.effectAllowed = dt.dropEffect = "link"; } return dt.effectAllowed = "none"; ]]> 1 || !this._closeWindowWithLastTab) this.tabbrowser.removeTab(event.target, {animate: true, byMouse: true}); } else if (event.originalTarget.localName == "box") { BrowserOpenTab(); } else { return; } event.stopPropagation(); ]]> 1 && !this._ignoredClick) { this._ignoredClick = true; return; } // Reset the "ignored click" flag this._ignoredClick = false; tabContainer.tabbrowser.removeTab(bindingParent, {animate: true, byMouse: true}); tabContainer._blockDblClick = true; /* XXXmano hack (see bug 343628): * Since we're removing the event target, if the user * double-clicks this button, the dblclick event will be dispatched * with the tabbar as its event target (and explicit/originalTarget), * which treats that as a mouse gesture for opening a new tab. * In this context, we're manually blocking the dblclick event * (see dblclick handler). */ var clickedOnce = false; function enableDblClick(event) { if (event.detail == 1 && !clickedOnce) { clickedOnce = true; return; } setTimeout(function() { tabContainer._blockDblClick = false; }, 0); tabContainer.removeEventListener("click", enableDblClick, false); } tabContainer.addEventListener("click", enableDblClick, false); ]]> // for the one-close-button case event.stopPropagation(); event.stopPropagation(); return this.getAttribute("pinned") == "true"; return this.getAttribute("hidden") == "true"; false null false var anonid = event.originalTarget.getAttribute("anonid"); if (anonid == "close-button") this.mOverCloseButton = true; var anonid = event.originalTarget.getAttribute("anonid"); if (anonid == "close-button") this.mOverCloseButton = false; this.style.MozUserFocus = ''; this.style.MozUserFocus = 'ignore'; this.clientTop; this.style.MozUserFocus = 'ignore'; this.clientTop; this.style.MozUserFocus = ''; = tabstripBO.screenX && curTabBO.screenX + curTabBO.width <= tabstripBO.screenX + tabstripBO.width) this.childNodes[i].setAttribute("tabIsVisible", "true"); else this.childNodes[i].removeAttribute("tabIsVisible"); } ]]> 0; i--) { let menuItem = this.childNodes[i]; if (menuItem.tab) { menuItem.removeEventListener("command", this, false); menuItem.tab.mCorrespondingMenuitem = null; this.removeChild(menuItem); } } var tabcontainer = gBrowser.tabContainer; tabcontainer.mTabstrip.removeEventListener("scroll", this, false); tabcontainer.removeEventListener("TabOpen", this, false); tabcontainer.removeEventListener("TabAttrModified", this, false); tabcontainer.removeEventListener("TabClose", this, false); ]]> return this.getAttribute("label"); if (this.hasAttribute("mirror")) this.removeAttribute("mirror"); else this.setAttribute("mirror", "true");