%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/browser/nav-history-service;1"] .getService(Components.interfaces.nsIBrowserHistory); document.getAnonymousElementByAttribute(this, "anonid", "tabbox"); document.getAnonymousElementByAttribute(this, "anonid", "panelcontainer"); document.getAnonymousElementByAttribute(this, "anonid", "tbstringbundle"); null null null [] [] new Array() new Array() false false #ifdef XP_MACOSX true #else false #endif false null null false 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._startStalledTimer(); 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 > 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"); this.mTab.removeAttribute("stalled"); this._cancelStalledTimer(); 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 (let i = 0; i < this.mTabBrowser.mProgressListeners.length; i++) { let p = this.mTabBrowser.mProgressListeners[i]; if (p) try { if (!oldBlank) p.onStateChange(aWebProgress, aRequest, aStateFlags, aStatus); // make sure that the visible status of new blank tabs is correctly set else if ("onUpdateCurrentBrowser" in p) p.onUpdateCurrentBrowser(aStateFlags, aStatus, "", 0); } catch (e) { // don't inhibit other listeners Components.utils.reportError(e); } } } for (let i = 0; i < this.mTabBrowser.mTabsProgressListeners.length; i++) { let p = this.mTabBrowser.mTabsProgressListeners[i]; if (p) try { p.onStateChange(this.mBrowser, aWebProgress, aRequest, aStateFlags, aStatus); } catch (e) { // don't inhibit other listeners Components.utils.reportError(e); } } 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) this.mBrowser.userTypedValue = null; // Don't clear the favicon if this onLocationChange was triggered // by a pushState or a replaceState. See bug 550565. if (aWebProgress.DOMWindow == this.mBrowser.contentWindow && aWebProgress.isLoadingDocument && !(this.mBrowser.docShell.loadType & Ci.nsIDocShell.LOAD_CMD_PUSHSTATE)) { this.mBrowser.mIconURL = null; } // changing location, clear out the missing plugins list this.mBrowser.missingPlugins = null; var browserHistory = this.mTabBrowser.mBrowserHistory; if ("lastURI" in this.mBrowser && this.mBrowser.lastURI) browserHistory.unregisterOpenPage(this.mBrowser.lastURI); browserHistory.registerOpenPage(aLocation); if (!this.mBlank) { if (this.mTabBrowser.mCurrentTab == this.mTab) { for (let i = 0; i < this.mTabBrowser.mProgressListeners.length; i++) { let p = this.mTabBrowser.mProgressListeners[i]; if (p) try { p.onLocationChange(aWebProgress, aRequest, aLocation); } catch (e) { // don't inhibit other listeners Components.utils.reportError(e); } } } for (let i = 0; i < this.mTabBrowser.mTabsProgressListeners.length; i++) { let p = this.mTabBrowser.mTabsProgressListeners[i]; if (p) try { p.onLocationChange(this.mBrowser, aWebProgress, aRequest, aLocation); } catch (e) { // don't inhibit other listeners Components.utils.reportError(e); } } } this.mBrowser.lastURI = aLocation; }, onStatusChange : function(aWebProgress, aRequest, aStatus, aMessage) { if (this.mBlank) return; if (this.mTabBrowser.mCurrentTab == this.mTab) { for (let i = 0; i < this.mTabBrowser.mProgressListeners.length; i++) { let p = this.mTabBrowser.mProgressListeners[i]; if (p) try { p.onStatusChange(aWebProgress, aRequest, aStatus, aMessage); } catch (e) { // don't inhibit other listeners Components.utils.reportError(e); } } } for (let i = 0; i < this.mTabBrowser.mTabsProgressListeners.length; i++) { let p = this.mTabBrowser.mTabsProgressListeners[i]; if (p) try { p.onStatusChange(this.mBrowser, aWebProgress, aRequest, aStatus, aMessage); } catch (e) { // don't inhibit other listeners Components.utils.reportError(e); } } this.mMessage = aMessage; }, onSecurityChange : function(aWebProgress, aRequest, aState) { if (this.mTabBrowser.mCurrentTab == this.mTab) { for (let i = 0; i < this.mTabBrowser.mProgressListeners.length; i++) { let p = this.mTabBrowser.mProgressListeners[i]; if (p) try { p.onSecurityChange(aWebProgress, aRequest, aState); } catch (e) { // don't inhibit other listeners Components.utils.reportError(e); } } } for (let i = 0; i < this.mTabBrowser.mTabsProgressListeners.length; i++) { let p = this.mTabBrowser.mTabsProgressListeners[i]; if (p) try { p.onSecurityChange(this.mBrowser, aWebProgress, aRequest, aState); } catch (e) { // don't inhibit other listeners Components.utils.reportError(e); } } }, onRefreshAttempted : function(aWebProgress, aURI, aDelay, aSameURI) { var allowRefresh = true; if (this.mTabBrowser.mCurrentTab == this.mTab) { for (let i = 0; i < this.mTabBrowser.mProgressListeners.length; i++) { let p = this.mTabBrowser.mProgressListeners[i]; if (p && "onRefreshAttempted" in p) { try { if (!p.onRefreshAttempted(aWebProgress, aURI, aDelay, aSameURI)) allowRefresh = false; } catch (e) { // don't inhibit other listeners Components.utils.reportError(e); } } } } for (let i = 0; i < this.mTabBrowser.mTabsProgressListeners.length; i++) { let p = this.mTabBrowser.mTabsProgressListeners[i]; if (p && "onRefreshAttempted" in p) { try { if (!p.onRefreshAttempted(this.mBrowser, aWebProgress, aURI, aDelay, aSameURI)) allowRefresh = false; } catch (e) { // don't inhibit other listeners Components.utils.reportError(e); } } } return allowRefresh; }, 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; }, _startStalledTimer: function () { this._cancelStalledTimer(); this._stalledTimer = setTimeout(function (self) { self.mTab.setAttribute("stalled", "true"); }, 700, this); }, _cancelStalledTimer: function () { if (this._stalledTimer) { clearTimeout(this._stalledTimer); this._stalledTimer = 0; } } }); ]]> sz || req.image.height > sz) return; this.setIcon(aTab, browser.currentURI); } catch (e) { } } } // Use documentURIObject in the check for shouldLoadFavIcon so that we // do the right thing with about:-style error pages. Bug 453442 else if (this.shouldLoadFavIcon(docURIObject)) { var url = docURIObject.prePath + "/favicon.ico"; if (!this.isFailedIcon(url)) this.setIcon(aTab, url); } ]]> 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; ]]> 1 false/true NO var owner = (aURIs.length > 1) || 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}); var tabNum = this.tabContainer.selectedIndex; for (let i = 1; i < aURIs.length; ++i) { let tab = this.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(); } ]]> = 0; --i) { if (this.tabs[i] != aTab) this.removeTab(this.tabs[i]); } } ]]> [] false -1 || this._windowIsClosing) return null; var browser = this.getBrowserForTab(aTab); if (!aTabWillBeMoved) { let ds = browser.docShell; if (ds && ds.contentViewer && !ds.contentViewer.permitUnload()) return null; } var closeWindow = false; var newTab = false; if (this.tabs.length - this._removingTabs.length == 1) { closeWindow = aCloseWindowWithLastTab != null ? aCloseWindowWithLastTab : !window.toolbar.visible || this.tabContainer._closeWindowWithLastTab; // Closing the tab and replacing it with a blank one is notably slower // than closing the window right away. If the caller opts in, take // the fast path. if (closeWindow && aCloseWindowFastpath && this._removingTabs.length == 0 && (this._windowIsClosing = window.closeWindow(true))) return null; newTab = true; } this._removingTabs.push(aTab); this.tabContainer.updateVisibility(); // 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("UIEvent"); evt.initUIEvent("TabClose", true, false, window, aTabWillBeMoved ? 1 : 0); aTab.dispatchEvent(evt); // Remove the tab's filter and progress listener. const filter = this.mTabFilters[aTab._tPos]; browser.webProgress.removeProgressListener(filter); filter.removeProgressListener(this.mTabListeners[aTab._tPos]); this.mTabListeners[aTab._tPos].destroy(); let closedBrowser = this.getBrowserForTab(aTab); if (closedBrowser.currentURI) this.mBrowserHistory.unregisterOpenPage(closedBrowser.currentURI); // We are no longer the primary content area. browser.setAttribute("type", "content-targetable"); // Remove this tab as the owner of any other tabs, since it's going away. Array.forEach(this.tabs, function (tab) { if ("owner" in tab && tab.owner == aTab) // |tab| is a child of the tab we're removing, make it an orphan tab.owner = null; }); return [aTab, closeWindow, newTab]; ]]> this.enterTabbedMode(); this.mTabsProgressListeners.push(aListener); = 0) this.mTabsProgressListeners.splice(pos, 1); ]]> = 0 && aIndex < this.tabs.length && aIndex != this.tabContainer.selectedIndex) this.selectedTab = this.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 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(this.getAttribute("context")); 0 document.getAnonymousElementByAttribute(this, "anonid", "arrowscrollbox"); false document.getAnonymousElementByAttribute(this, "anonid", "tab-drop-indicator"); 350 0 this.mTabClipWidth) this.setAttribute("closebuttons", "alltabs"); else this.setAttribute("closebuttons", "activetab"); break; case 2: case 3: this.setAttribute("closebuttons", "noclose"); 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) {} ]]> this.mTabstrip._scrollButtonDown; tabs[i].boxObject.screenX + tabs[i].boxObject.width / 2) return i; } return tabs.length; ]]> 1) return dt.effectAllowed = "none"; var types = dt.mozTypesAt(0); var sourceNode = null; // tabs are always added as the first type if (types[0] == TAB_DROP_TYPE) { var sourceNode = dt.mozGetDataAt(TAB_DROP_TYPE, 0); if (sourceNode instanceof XULElement && sourceNode.localName == "tab" && (sourceNode.parentNode == this || (sourceNode.ownerDocument.defaultView instanceof ChromeWindow && sourceNode.ownerDocument.documentElement.getAttribute("windowtype") == "navigator:browser"))) { if (sourceNode.parentNode == this && (event.screenX >= sourceNode.boxObject.screenX && event.screenX <= (sourceNode.boxObject.screenX + sourceNode.boxObject.width))) { return dt.effectAllowed = "none"; } return dt.effectAllowed = "copyMove"; } } if (browserDragAndDrop.canDropLink(event)) { // Here we need to do this manually return dt.effectAllowed = dt.dropEffect = "link"; } return dt.effectAllowed = "none"; ]]> = t.boxObject.screenX && event.screenX <= t.boxObject.screenX + t.boxObject.width && event.screenY >= t.boxObject.screenY && event.screenY <= t.boxObject.screenY + t.boxObject.height) this.mTabstrip.ensureElementIsVisible(t); ]]> 1 || !this._closeWindowWithLastTab) this.tabbrowser.removeTab(event.target); event.stopPropagation(); ]]> = this._dragTime + this._dragOverDelay) this.selectedItem = tab; 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; } // ensure we never place the drop indicator beyond our limits if (newMargin < minMargin) newMargin = minMargin; else if (newMargin > maxMargin) newMargin = maxMargin; } 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"; ind.style.marginTop = (-ind.clientHeight) + "px"; ]]> draggedTab._tPos) newIndex--; this.tabbrowser.moveTabTo(draggedTab, newIndex); } } else if (draggedTab) { // swap the dropped tab with a new one we create and then close // it in the other window (making it seem to have moved between // windows) let newIndex = this._getDropIndex(event); let newTab = this.tabbrowser.addTab("about:blank"); let newBrowser = this.tabbrowser.getBrowserForTab(newTab); // Stop the about:blank load newBrowser.stop(); // make sure it has a docshell newBrowser.docShell; this.tabbrowser.moveTabTo(newTab, newIndex); this.tabbrowser.swapBrowsersAndCloseOther(newTab, draggedTab); // We need to select the tab after we've done // swapBrowsersAndCloseOther, so that the updateCurrentBrowser // it triggers will correctly update our URL bar. this.tabbrowser.selectedTab = newTab; } else { let url = browserDragAndDrop.drop(event, { }); // 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; let bgLoad = Services.prefs.getBoolPref("browser.tabs.loadInBackground"); if (event.shiftKey) bgLoad = !bgLoad; let tab = this._getDragTargetTab(event); if (!tab || dropEffect == "copy") { // We're adding a new tab. let newIndex = this._getDropIndex(event); let newTab = this.tabbrowser.loadOneTab(getShortcutOrURI(url), {inBackground: bgLoad}); this.tabbrowser.moveTabTo(newTab, newIndex); } else { // Load in an existing tab. try { this.tabbrowser.getBrowserForTab(tab).loadURI(getShortcutOrURI(url)); if (!bgLoad) this.selectedItem = tab; } catch(ex) { // Just ignore invalid urls } } } ]]> wX && eX < (wX + window.outerWidth)) { let bo = this.mTabstrip.boxObject; // also avoid detaching if the the tab was dropped too close to // the tabbar (half a tab) let endScreenY = bo.screenY + 1.5 * bo.height; let eY = event.screenY; if (eY < endScreenY && eY > window.screenY) return; } var draggedTab = dt.mozGetDataAt(TAB_DROP_TYPE, 0); this.tabbrowser.replaceTabWithWindow(draggedTab); event.stopPropagation(); ]]> 1 && !this._ignoredClick) { this._ignoredClick = true; return; } // Reset the "ignored click" flag this._ignoredClick = false; tabContainer.tabbrowser.removeTab(bindingParent); this._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 self = this; var clickedOnce = false; function enableDblClick(event) { if (event.detail == 1 && !clickedOnce) { clickedOnce = true; return; } setTimeout(function() { self._blockDblClick = false; }, 0); tabContainer.removeEventListener("click", enableDblClick, false); } tabContainer.addEventListener("click", enableDblClick, false); ]]> // for the one-close-button case event.stopPropagation(); event.stopPropagation(); false null 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"); } ]]>