pjs/suite/browser/tabbrowser.xml

1883 строки
69 KiB
XML
Исходник Обычный вид История

2007-04-01 03:03:27 +04:00
<?xml version="1.0"?>
<!-- ***** BEGIN LICENSE BLOCK *****
- Version: MPL 1.1/GPL 2.0/LGPL 2.1
2007-04-01 03:03:27 +04:00
-
- The contents of this file are subject to the Mozilla Public License Version
- 1.1 (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
- http://www.mozilla.org/MPL/
2007-04-01 03:03:27 +04:00
-
- Software distributed under the License is distributed on an "AS IS" basis,
- WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- for the specific language governing rights and limitations under the
- License.
2007-04-01 03:03:27 +04:00
-
- The Original Code is this file as it was released on March 28, 2001.
-
- The Initial Developer of the Original Code is
- Peter Annema.
- Portions created by the Initial Developer are Copyright (C) 2001
- the Initial Developer. All Rights Reserved.
2007-04-01 03:03:27 +04:00
-
- Contributor(s):
- David Hyatt <hyatt@netscape.com> (Original Author of <tabbrowser>)
- Mike Connor <mconnor@steelgryphon.com>
2007-04-01 03:03:27 +04:00
-
- Alternatively, the contents of this file may be used under the terms of
- either of the GNU General Public License Version 2 or later (the "GPL"),
- or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- in which case the provisions of the GPL or the LGPL are applicable instead
- of those above. If you wish to allow use of your version of this file only
- under the terms of either the GPL or the LGPL, and not to allow others to
- use your version of this file under the terms of the MPL, indicate your
- decision by deleting the provisions above and replace them with the notice
- and other provisions required by the GPL or the LGPL. If you do not delete
- the provisions above, a recipient may use your version of this file under
- the terms of any one of the MPL, the GPL or the LGPL.
-
- ***** END LICENSE BLOCK ***** -->
2007-04-01 03:03:27 +04:00
<!DOCTYPE bindings [
<!ENTITY % tabBrowserDTD SYSTEM "chrome://global/locale/tabbrowser.dtd" >
%tabBrowserDTD;
]>
2007-04-01 03:03:27 +04:00
<bindings id="tabBrowserBindings"
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">
2007-04-01 03:07:36 +04:00
2007-04-01 03:03:27 +04:00
<binding id="tabbrowser">
<resources>
<stylesheet src="chrome://global/skin/browser.css"/>
</resources>
<content>
<xul:stringbundle anonid="tbstringbundle" src="chrome://global/locale/tabbrowser.properties"/>
<xul:tabbox anonid="tabbox" flex="1" eventnode="document" xbl:inherits="handleCtrlPageUpDown">
<xul:hbox class="tab-drop-indicator-bar" hidden="true">
<xul:image class="tab-drop-indicator"/>
</xul:hbox>
<xul:hbox class="tabbrowser-strip chromeclass-toolbar" collapsed="true" tooltip="_child" context="_child"
anonid="strip"
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="event.stopPropagation(); if (document.tooltipNode.hasAttribute('label')) { this.setAttribute('label', document.tooltipNode.getAttribute('label')); return true; } return false;"/>
<xul:menupopup onpopupshowing="this.parentNode.parentNode.parentNode.updatePopupMenu(this);">
<xul:menuitem label="&closeTab.label;" accesskey="&closeTab.accesskey;"
tbattr="tabbrowser-multiple"
oncommand="var tabbrowser = this.parentNode.parentNode.parentNode.parentNode;
tabbrowser.removeTab(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="&newTab.label;" accesskey="&newTab.accesskey;"
xbl:inherits="oncommand=onnewtab"/>
<xul:menuseparator/>
<xul:menuitem label="&bookmarkGroup.label;" accesskey="&bookmarkGroup.accesskey;"
tbattr="tabbrowser-multiple"
xbl:inherits="oncommand=onbookmarkgroup"/>
<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:menupopup>
<xul:tabs class="tabbrowser-tabs" closebutton="true" flex="1"
anonid="tabcontainer"
tooltiptextnew="&newTabButton.tooltip;"
setfocus="false"
onclick="this.parentNode.parentNode.parentNode.onTabClick(event);"
xbl:inherits="onnewtab"
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');"
maxwidth="250" width="0" minwidth="30" flex="100"
class="tabbrowser-tab" label="&untitledTab;" crop="end"/>
2007-04-01 03:03:27 +04:00
</xul:tabs>
</xul:hbox>
<xul:tabpanels flex="1" class="plain" selectedIndex="0" anonid="panelcontainer">
<xul:browser type="content-primary" xbl:inherits="tooltip=contenttooltip,contextmenu=contentcontextmenu"/>
2007-04-01 03:03:27 +04:00
</xul:tabpanels>
</xul:tabbox>
<children/>
</content>
<implementation>
<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="mStrip" readonly="true">
document.getAnonymousElementByAttribute(this, "anonid", "strip");
2007-04-01 03:03:27 +04:00
</field>
<field name="mTabContainer" readonly="true">
document.getAnonymousElementByAttribute(this, "anonid", "tabcontainer");
2007-04-01 03:03:27 +04:00
</field>
<field name="mPanelContainer" readonly="true">
document.getAnonymousElementByAttribute(this, "anonid", "panelcontainer");
2007-04-01 03:03:27 +04:00
</field>
<field name="mTabs" readonly="true">
this.mTabContainer.childNodes
2007-04-01 03:03:27 +04:00
</field>
<field name="mStringBundle">
document.getAnonymousElementByAttribute(this, "anonid", "tbstringbundle");
</field>
2007-04-01 03:03:27 +04:00
<field name="mCurrentTab">
null
</field>
<field name="mPreviousTab">
null
</field>
2007-04-01 03:03:27 +04:00
<field name="mCurrentBrowser">
null
</field>
<field name="mProgressListeners">
[]
2007-04-01 03:03:27 +04:00
</field>
<field name="mTabListeners">
new Array()
</field>
<field name="mTabFilters">
new Array()
</field>
2007-04-01 03:03:27 +04:00
<field name="mIsBusy">
false
</field>
<field name="mMissedIconCache">
null
</field>
<field name="mContextTab">
null
</field>
<field name="_keyEventHandler" readonly="true">
<![CDATA[({
tabbrowser: this,
handleEvent: function handleEvent(aEvent) {
if (aEvent.ctrlKey && aEvent.keyCode == KeyEvent.DOM_VK_F4 &&
this.tabbrowser.mTabBox.handleCtrlPageUpDown)
this.tabbrowser.removeCurrentTab();
}
})]]>
</field>
<field name="arrowKeysShouldWrap">
null
</field>
<field name="nextTabNumber">
0
</field>
2007-04-01 03:03:27 +04:00
2007-04-01 03:07:36 +04:00
<!-- A web progress listener object definition for a given tab. -->
2007-04-01 03:03:27 +04:00
<method name="mTabProgressListener">
<parameter name="aTab"/>
<parameter name="aBrowser"/>
<parameter name="aStartsBlank"/>
2007-04-01 03:03:27 +04:00
<body>
<![CDATA[
return ({
mTabBrowser: this,
2007-04-01 03:03:27 +04:00
mTab: aTab,
mBrowser: aBrowser,
mBlank: aStartsBlank,
2007-04-01 03:07:36 +04:00
mIcon: "",
2007-04-01 03:03:27 +04:00
onProgressChange : function (aWebProgress, aRequest,
aCurSelfProgress, aMaxSelfProgress,
2007-04-01 03:07:36 +04:00
aCurTotalProgress, aMaxTotalProgress)
{
if (aMaxTotalProgress > 0)
this.mTab.setAttribute("progress", Math.floor(aCurTotalProgress * 9.9 / aMaxTotalProgress));
if (!this.mBlank && this.mTabBrowser.mCurrentTab == this.mTab) {
2007-04-01 03:03:27 +04:00
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);
}
}
},
2007-04-01 03:07:36 +04:00
2007-04-01 03:03:27 +04:00
onStateChange : function(aWebProgress, aRequest, aStateFlags, aStatus)
{
if (!aRequest)
return;
2007-04-01 03:07:36 +04:00
var oldBlank = this.mBlank;
2007-04-01 03:03:27 +04:00
const nsIWebProgressListener = Components.interfaces.nsIWebProgressListener;
const nsIChannel = Components.interfaces.nsIChannel;
if (aStateFlags & nsIWebProgressListener.STATE_START &&
2007-04-01 03:03:27 +04:00
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 flag gets
// set to false, if the document load ends without an
// onLocationChange, this flag also gets set to false
// (so we keep it while switching tabs after a failed load).
// 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) {
this.mTab.removeAttribute("progress");
this.mTab.setAttribute("busy", "true");
this.mTab.label = this.mTabBrowser.mStringBundle.getString("tabs.loading");
this.mTab.removeAttribute("image");
if (this.mTabBrowser.mCurrentTab == this.mTab)
this.mTabBrowser.mIsBusy = true;
}
2007-04-01 03:03:27 +04:00
}
else if (aStateFlags & nsIWebProgressListener.STATE_STOP &&
aStateFlags & nsIWebProgressListener.STATE_IS_NETWORK) {
// The document is done loading, it's okay to clear
// the value again.
if (aWebProgress.DOMWindow == this.mBrowser.contentWindow)
if (this.mBrowser.userTypedClear > 1)
this.mBrowser.userTypedClear -= 2;
else if (this.mBrowser.userTypedClear > 0)
this.mBrowser.userTypedClear--;
if (this.mBlank)
this.mBlank = false;
2007-04-01 03:07:36 +04:00
this.mTab.removeAttribute("busy");
2007-04-01 03:07:36 +04:00
var location = this.mBrowser.currentURI;
if (this.mIcon) {
this.mTab.setAttribute("image", this.mIcon);
}
else if (this.mBrowser.contentDocument instanceof ImageDocument &&
this.mTabBrowser.mPrefs.getBoolPref("browser.chrome.site_icons")) {
var req = this.mBrowser.contentDocument.imageRequest;
var sz = this.mTabBrowser.mPrefs.getIntPref("browser.chrome.image_icons.max_size");
if (req && req.image.width <= sz && req.image.height <= sz)
this.mTab.setAttribute("image", this.mBrowser.currentURI.spec);
}
else if (this.mTabBrowser.shouldLoadFavIcon(location))
2007-04-01 03:07:36 +04:00
this.mTabBrowser.loadFavIcon(location, "image", this.mTab);
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;
2007-04-01 03:03:27 +04:00
}
if (!oldBlank && this.mTabBrowser.mCurrentTab == this.mTab) {
2007-04-01 03:03:27 +04:00
for (var i = 0; i < this.mTabBrowser.mProgressListeners.length; i++) {
var p = this.mTabBrowser.mProgressListeners[i];
if (p)
p.onStateChange(aWebProgress, aRequest, aStateFlags, aStatus);
}
}
},
// The first location change is gotoIndex called from mInstallSH,
// the second one is considered a user action.
mLocationChangeCount : 0,
2007-04-01 03:03:27 +04:00
2007-04-01 03:07:36 +04:00
onLocationChange : function(aWebProgress, aRequest, aLocation)
{
this.mIcon = "";
if (this.mLocationChangeCount > 0 ||
aLocation.spec != "about:blank")
++this.mLocationChangeCount;
if (this.mLocationChangeCount == 2) {
this.mTabBrowser.backBrowserGroup = [];
this.mTabBrowser.forwardBrowserGroup = [];
}
// The document loaded correctly, clear the value if we should
if (this.mBrowser.userTypedClear > 0)
this.mBrowser.userTypedValue = null;
if (!this.mBlank && this.mTabBrowser.mCurrentTab == this.mTab) {
2007-04-01 03:03:27 +04:00
for (var i = 0; i < this.mTabBrowser.mProgressListeners.length; i++) {
var p = this.mTabBrowser.mProgressListeners[i];
if (p)
p.onLocationChange(aWebProgress, aRequest, aLocation);
}
}
},
2007-04-01 03:07:36 +04:00
onStatusChange : function(aWebProgress, aRequest, aStatus, aMessage)
{
if (this.mBlank)
2007-04-01 03:03:27 +04:00
return;
2007-04-01 03:07:36 +04:00
2007-04-01 03:03:27 +04:00
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);
}
}
},
2007-04-01 03:07:36 +04:00
onSecurityChange : function(aWebProgress, aRequest, aState)
{
if (this.mTabBrowser.mCurrentTab == this.mTab) {
2007-04-01 03:03:27 +04:00
for (var i = 0; i < this.mTabBrowser.mProgressListeners.length; i++) {
var p = this.mTabBrowser.mProgressListeners[i];
if (p)
p.onSecurityChange(aWebProgress, aRequest, aState);
}
}
},
setIcon : function(aURI)
{
this.mIcon = aURI;
if (!this.mTab.hasAttribute("busy"))
this.mTab.setAttribute("image", aURI);
},
2007-04-01 03:03:27 +04:00
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;
}
2007-04-01 03:07:36 +04:00
});
2007-04-01 03:03:27 +04:00
]]>
</body>
</method>
<method name="mInstallSH">
<parameter name="aBrowser"/>
<parameter name="aSH"/>
<body>
<![CDATA[
return ({
mBrowser: aBrowser,
mSH: aSH,
onProgressChange : function (aWebProgress, aRequest,
aCurSelfProgress, aMaxSelfProgress,
2007-04-01 03:07:36 +04:00
aCurTotalProgress, aMaxTotalProgress)
{
},
2007-04-01 03:07:36 +04:00
onStateChange : function(aWebProgress, aRequest, aStateFlags, aStatus)
{
const nsIWebProgressListener = Components.interfaces.nsIWebProgressListener;
if ((aStateFlags & nsIWebProgressListener.STATE_IS_NETWORK) &&
(aStateFlags & nsIWebProgressListener.STATE_STOP)) {
function refresh(closure) {
closure.mBrowser.webNavigation.sessionHistory = closure.mSH;
closure.mBrowser.webProgress.removeProgressListener(closure);
delete closure.mBrowser._SHListener;
closure.mSH.QueryInterface(Components.interfaces.nsIWebNavigation)
.gotoIndex(closure.mSH.index);
}
setTimeout(refresh, 0, this);
}
},
2007-04-01 03:07:36 +04:00
onLocationChange : function(aWebProgress, aRequest, aLocation)
{
},
2007-04-01 03:07:36 +04:00
onStatusChange : function(aWebProgress, aRequest, aStatus, aMessage)
{
},
2007-04-01 03:07:36 +04:00
onSecurityChange : function(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;
}
2007-04-01 03:07:36 +04:00
});
]]>
</body>
</method>
<method name="buildFavIconString">
<parameter name="aURI"/>
<body>
<![CDATA[
try {
aURI = this.mURIFixup.createExposableURI(aURI);
} catch(ex) { }
return aURI.resolve("/favicon.ico");
]]>
</body>
</method>
<method name="shouldLoadFavIcon">
<parameter name="aURI"/>
<body>
<![CDATA[
try {
aURI = this.mURIFixup.createExposableURI(aURI);
} catch(ex) { }
return (aURI && this.mPrefs.getBoolPref("browser.chrome.site_icons") &&
2007-04-01 03:07:36 +04:00
this.mPrefs.getBoolPref("browser.chrome.favicons") &&
("schemeIs" in aURI) && (aURI.schemeIs("http") || aURI.schemeIs("https")));
]]>
</body>
</method>
<method name="loadFavIcon">
<parameter name="aURI"/>
<parameter name="aAttr"/>
<parameter name="aElt"/>
<body>
<![CDATA[
var iconURL = this.buildFavIconString(aURI);
var entry = this.openCacheEntry(iconURL, Components.interfaces.nsICache.ACCESS_READ);
if (!entry)
aElt.setAttribute(aAttr, iconURL);
else {
entry.close();
entry = null;
}
]]>
</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>
2007-04-01 03:03:27 +04:00
<method name="updateTitlebar">
<body>
<![CDATA[
var newTitle = "";
var docTitle;
var docElement = this.ownerDocument.documentElement;
var sep = docElement.getAttribute("titlemenuseparator");
2007-04-01 03:03:27 +04:00
if (this.docShell.contentViewer)
docTitle = this.contentTitle;
2007-04-01 03:07:36 +04:00
2007-04-01 03:03:27 +04:00
if (docTitle) {
newTitle += docElement.getAttribute("titlepreface");
2007-04-01 03:03:27 +04:00
newTitle += docTitle;
newTitle += sep;
2007-04-01 03:03:27 +04:00
}
newTitle += docElement.getAttribute("titlemodifier");
// 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;
2007-04-01 03:03:27 +04:00
]]>
</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>
2007-04-01 03:03:27 +04:00
<method name="updateCurrentBrowser">
<body>
<![CDATA[
// we only want to return to the parent tab if no other
// tabs have been opened and the user hasn't switched tabs
this.mPreviousTab = null;
var newBrowser = this.mPanelContainer.selectedPanel;
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) {
// Clear focus outline before we draw on top of it
this.mCurrentBrowser.focusedElement.blur();
}
this.mCurrentBrowser.setAttribute("type", "content-targetable");
}
2007-04-01 03:07:36 +04:00
2007-04-01 03:03:27 +04:00
newBrowser.setAttribute("type", "content-primary");
this.mCurrentBrowser = newBrowser;
this.mCurrentTab = this.selectedTab;
// Update the URL bar.
var loc = this.mCurrentBrowser.currentURI;
2007-04-01 03:03:27 +04:00
var webProgress = this.mCurrentBrowser.webProgress;
var securityUI = this.mCurrentBrowser.securityUI;
// Remember the current clear state, then set it to false
// so we don't clear the userTypedValue when just switching
// tabs. Set it back to its old state after we're done.
var userTypedClear = this.mCurrentBrowser.userTypedClear;
this.mCurrentBrowser.userTypedClear = 0;
var i, p;
for (i = 0; i < this.mProgressListeners.length; i++) {
p = this.mProgressListeners[i];
if (p) {
2007-04-01 03:03:27 +04:00
p.onLocationChange(webProgress, null, loc);
if (securityUI)
p.onSecurityChange(webProgress, null, securityUI.state);
var listener = this.mTabListeners[this.mTabContainer.selectedIndex];
if (listener.mIcon && 'onLinkIconAvailable' in p)
p.onLinkIconAvailable(listener.mIcon);
}
2007-04-01 03:03:27 +04:00
}
this.mCurrentBrowser.userTypedClear = userTypedClear;
2007-04-01 03:03:27 +04:00
// Update the window title.
this.updateTitlebar();
2007-04-01 03:07:36 +04:00
2007-04-01 03:03:27 +04:00
// 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) {
2007-04-01 03:03:27 +04:00
this.mIsBusy = true;
webProgress = this.mCurrentBrowser.webProgress;
for (i = 0; i < this.mProgressListeners.length; i++) {
p = this.mProgressListeners[i];
2007-04-01 03:03:27 +04:00
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) {
2007-04-01 03:03:27 +04:00
this.mIsBusy = false;
webProgress = this.mCurrentBrowser.webProgress;
for (i = 0; i < this.mProgressListeners.length; i++) {
p = this.mProgressListeners[i];
2007-04-01 03:03:27 +04:00
if (p)
p.onStateChange(webProgress, null, nsIWebProgressListener.STATE_STOP | nsIWebProgressListener.STATE_IS_NETWORK, 0);
}
}
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;
element.focus();
document.commandDispatcher.suppressFocusScroll = false;
}
// Use setTimeout to avoid focus outline ghosting.
setTimeout(setFocus, 0, whatToFocus);
2007-04-01 03:03:27 +04:00
]]>
</body>
</method>
<method name="onTabClick">
<parameter name="event"/>
<body>
<![CDATA[
if (event.button != 1 || event.target.localName != 'tab' ||
this.mPrefs.getBoolPref("middlemouse.contentLoadURL"))
2007-04-01 03:07:36 +04:00
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;
2007-04-01 03:07:36 +04:00
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.
}
2007-04-01 03:07:36 +04:00
// 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 {
secMan.checkLoadURI(origURI, uri,
nsIScriptSecMan.DISALLOW_SCRIPT);
} catch(e) {
return;
}
2007-04-01 03:07:36 +04:00
// Security says okay, now ask content policy
for (var i = 0; i < this.browsers.length; i++) {
if (this.browsers[i].contentDocument == event.originalTarget.ownerDocument) {
if (contentPolicy.shouldLoad(nsIContentPolicy.TYPE_IMAGE,
uri, origURI, event.target,
event.target.type,
null) == nsIContentPolicy.ACCEPT) {
this.mTabListeners[i].setIcon(href);
if (this.browsers[i] == this.mCurrentBrowser)
for each (var p in this.mProgressListeners)
if (p && 'onLinkIconAvailable' in p)
p.onLinkIconAvailable(href);
}
return;
}
}
]]>
</body>
</method>
2007-04-01 03:03:27 +04:00
<method name="onTitleChanged">
<parameter name="evt"/>
<body>
<![CDATA[
if (evt.target != this.contentDocument)
return;
var tabBrowser = this.parentNode.parentNode.parentNode;
var tab = document.getAnonymousElementByAttribute(tabBrowser, "linkedpanel", this.id);
tabBrowser.setTabTitle(tab);
2007-04-01 03:03:27 +04:00
if (tab == tabBrowser.mCurrentTab)
tabBrowser.updateTitlebar();
2007-04-01 03:07:36 +04:00
]]>
2007-04-01 03:03:27 +04:00
</body>
</method>
<method name="setTabTitle">
<parameter name="aTab"/>
<body>
<![CDATA[
var browser = aTab.linkedBrowser;
var title = browser.contentTitle;
var crop = "end";
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.
}
crop = "center";
} else // Still no title? Fall back to our untitled string.
title = this.mStringBundle.getString("tabs.untitled");
}
aTab.label = title;
aTab.setAttribute("crop", crop);
]]>
</body>
</method>
<method name="setStripVisibilityTo">
<parameter name="aShow"/>
<body>
<![CDATA[
this.mStrip.collapsed = !aShow;
]]>
</body>
</method>
<method name="getStripVisibility">
<body>
return !this.mStrip.collapsed;
</body>
</method>
2007-04-01 03:03:27 +04:00
<method name="addTab">
<parameter name="aURI"/>
<parameter name="aReferrerURI"/>
<parameter name="aCharset"/>
<parameter name="aFocusNewTab"/>
2007-04-01 03:03:27 +04:00
<body>
<![CDATA[
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"));
2007-04-01 03:03:27 +04:00
else
t.setAttribute("label", aURI);
2007-04-01 03:07:36 +04:00
t.setAttribute("crop", "end");
t.className = "tabbrowser-tab";
t.maxWidth = 250;
t.minWidth = 30;
t.width = 0;
t.setAttribute("flex", "100");
t.setAttribute("validate", "never");
t.setAttribute("onerror", "this.parentNode.parentNode.parentNode.parentNode.addToMissedIconCache(this.getAttribute('image')); this.removeAttribute('image');");
2007-04-01 03:03:27 +04:00
this.mTabContainer.appendChild(t);
var b = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
2007-04-01 03:07:36 +04:00
"browser");
b.setAttribute("type", "content-targetable");
2007-04-01 03:03:27 +04:00
b.setAttribute("contextmenu", this.getAttribute("contentcontextmenu"));
b.setAttribute("tooltip", this.getAttribute("contenttooltip"));
2007-04-01 03:07:36 +04:00
2007-04-01 03:03:27 +04:00
this.mPanelContainer.appendChild(b);
b.addEventListener("DOMTitleChanged", this.onTitleChanged, false);
2007-04-01 03:07:36 +04:00
this.mStrip.collapsed = false;
this.mPrefs.setBoolPref("browser.tabs.forceHide", false);
2007-04-01 03:07:36 +04:00
2007-04-01 03:03:27 +04:00
// wire up a progress listener for the new browser object.
var position = this.mTabs.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);
2007-04-01 03:03:27 +04:00
this.mTabListeners[position] = tabListener;
this.mTabFilters[position] = filter;
var uniqueId = "panel" + this.nextTabNumber++;
b.id = uniqueId;
t.linkedPanel = uniqueId;
t.linkedBrowser = b;
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;
b.loadURI(aURI, aReferrerURI, aCharset);
}
2007-04-01 03:03:27 +04:00
if (aFocusNewTab) {
var parentTab = this.selectedTab;
this.selectedTab = t;
this.mPreviousTab = parentTab;
}
else
// The user opened a background tab, so updateCurrentBrowser
// won't be called. Explicitly clear the previous tab.
this.mPreviousTab = null;
2007-04-01 03:03:27 +04:00
return t;
]]>
</body>
</method>
<method name="removeAllTabsBut">
<parameter name="aTab"/>
<body>
<![CDATA[
var numTabs = this.mTabs.length;
if (numTabs > 1) {
const closeOtherTabsPref = "browser.tabs.warnOnCloseOther";
var shouldPrompt = this.mPrefs.getBoolPref(closeOtherTabsPref);
var reallyClose = true;
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 - 1; //number of tabs to be removed
var buttonPressed = promptService.confirmEx(window,
bundle.getString('tabs.closeWarningTitle'),
bundle.getFormattedString("tabs.closeWarning", [tabsToClose]),
(promptService.BUTTON_TITLE_IS_STRING * promptService.BUTTON_POS_0)
+ (promptService.BUTTON_TITLE_CANCEL * promptService.BUTTON_POS_1),
bundle.getString('tabs.closeButton'),
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(closeOtherTabsPref, false);
}
if (reallyClose) {
if (aTab.localName != "tab")
aTab = this.mCurrentTab;
else
this.mTabContainer.selectedItem = aTab;
for (var i = this.mTabs.length - 1; i >= 0; --i) {
if (this.mTabs[i] != aTab)
this.removeTab(this.mTabs[i]);
}
}
}
]]>
</body>
</method>
2007-04-01 03:03:27 +04:00
<method name="removeCurrentTab">
<body>
<![CDATA[
return this.removeTab(this.mCurrentTab);
]]>
</body>
</method>
2007-04-01 03:07:36 +04:00
<method name="removeTab">
<parameter name="aTab"/>
<body>
<![CDATA[
if (aTab.localName != "tab")
aTab = this.mCurrentTab;
var l = this.mTabs.length;
if (l == 1) {
// hide the tab bar
this.mPrefs.setBoolPref("browser.tabs.forceHide", true);
this.mStrip.collapsed = true;
return;
}
2007-04-01 03:03:27 +04:00
var ds = aTab.linkedBrowser.docShell;
if (ds.contentViewer && !ds.contentViewer.permitUnload())
return;
if (l == 2) {
if (this.mPrefs.getBoolPref("browser.tabs.autoHide"))
this.mStrip.collapsed = true;
}
2007-04-01 03:03:27 +04:00
var index = this.getTabIndex(aTab);
2007-04-01 03:03:27 +04:00
// Remove the tab's filter and progress listener.
const filter = this.mTabFilters[index];
var oldBrowser = aTab.linkedBrowser;
oldBrowser.webProgress.removeProgressListener(filter);
filter.removeProgressListener(this.mTabListeners[index]);
this.mTabFilters.splice(index, 1);
2007-04-01 03:03:27 +04:00
this.mTabListeners.splice(index, 1);
// Remove our title change listener
oldBrowser.removeEventListener("DOMTitleChanged", this.onTitleChanged, false);
2007-04-01 03:07:36 +04:00
2007-04-01 03:03:27 +04:00
// We are no longer the primary content area.
oldBrowser.setAttribute("type", "content-targetable");
2007-04-01 03:03:27 +04:00
// Now select the new tab before nuking the old one.
var currentIndex = this.mTabContainer.selectedIndex;
2007-04-01 03:07:36 +04:00
var newIndex = -1;
if (currentIndex > index)
newIndex = currentIndex - 1;
else if (currentIndex < index)
newIndex = currentIndex;
else if (index == l - 1)
newIndex = index - 1;
else
newIndex = index;
2007-04-01 03:03:27 +04:00
var oldTab = aTab;
2007-04-01 03:07:36 +04:00
// clean up the before/afterselected attributes before removing the tab
oldTab.selected = false;
// 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.
oldBrowser.destroy();
if (oldBrowser == this.mCurrentBrowser)
this.mCurrentBrowser = null;
2007-04-01 03:03:27 +04:00
this.mTabContainer.removeChild(oldTab);
this.mPanelContainer.removeChild(oldBrowser);
// When the current tab is removed select a new tab
// and fire select events on tabpanels and tabs
if (this.mPreviousTab && (oldTab == this.mCurrentTab))
this.selectedTab = this.mPreviousTab;
else {
this.mTabContainer.selectedIndex = newIndex;
// When removing a tab to the left of the current tab
// fix up the panel index without firing any events
this.mTabBox.selectedPanel = this.selectedTab.linkedBrowser;
// We need to explicitly clear this, because updateCurrentBrowser
// doesn't get called for a background tab
this.mPreviousTab = null;
}
2007-04-01 03:03:27 +04:00
]]>
</body>
</method>
<method name="reloadAllTabs">
<body>
<![CDATA[
var l = this.mPanelContainer.childNodes.length;
for (var i = 0; i < l; i++) {
try {
this.mPanelContainer.childNodes[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;
aTab.linkedBrowser.reload();
]]>
</body>
</method>
2007-04-01 03:03:27 +04:00
<method name="addProgressListener">
<parameter name="aListener"/>
<parameter name="aMask"/>
2007-04-01 03:03:27 +04:00
<body>
<![CDATA[
this.mProgressListeners.push(aListener);
]]>
</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[i] = null;
break;
}
}
]]>
</body>
</method>
<method name="getBrowserForTab">
<parameter name="aTab"/>
<body>
<![CDATA[
if (aTab.localName != "tab")
return null;
return aTab.linkedBrowser;
]]>
</body>
</method>
<method name="getTabIndex">
<parameter name="aTab"/>
<body>
<![CDATA[
for (var i = 0; i < this.mTabs.length; ++i)
if (this.mTabs[i] == aTab)
return i;
throw Components.results.NS_ERROR_ILLEGAL_VALUE;
]]>
</body>
</method>
<property name="tabContainer">
<getter>
return this.mTabContainer;
</getter>
</property>
2007-04-01 03:03:27 +04:00
<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[
var browsers = [];
browsers.item = function(i) {return this[i];}
for (var i = 0; i < this.mTabs.length; i++)
browsers.push(this.mTabs[i].linkedBrowser);
return 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") {
aXferData.data = new TransferData();
var URI = aEvent.target.linkedBrowser.currentURI;
var title = aEvent.target.linkedBrowser.contentTitle || URI.spec;
aXferData.data.addDataForFlavour("text/unicode", URI.spec);
aXferData.data.addDataForFlavour("text/x-moz-url", URI.spec + "\n" + title);
aXferData.data.addDataForFlavour("text/html", '<a href="' + URI.spec + '">' + title + '</a>');
}
]]>
</body>
</method>
<method name="canDrop">
<parameter name="aEvent"/>
<parameter name="aDragSession"/>
<body>
<![CDATA[
if (aDragSession.sourceNode &&
aDragSession.sourceNode.parentNode == this.mTabContainer) {
var newIndex = this.getDropIndex(aEvent);
var tabIndex = this.getTabIndex(aDragSession.sourceNode);
if (newIndex == tabIndex || newIndex == tabIndex + 1)
return false;
}
return true;
]]>
</body>
</method>
<method name="onDragOver">
<parameter name="aEvent"/>
<parameter name="aFlavour"/>
<parameter name="aDragSession"/>
<body>
<![CDATA[
var ib = document.getAnonymousElementByAttribute(this, "class", "tab-drop-indicator-bar");
if (!aDragSession.canDrop) {
ib.hidden = true;
return;
}
var ind = document.getAnonymousElementByAttribute(this, "class", "tab-drop-indicator");
var newIndexOn = aDragSession.sourceNode &&
aDragSession.sourceNode.parentNode == this.mTabContainer ?
-1 : this.getDropOnIndex(aEvent);
var ltr = window.getComputedStyle(this, null).direction == "ltr";
var arrowX, tabBoxObject;
if (newIndexOn != -1) {
tabBoxObject = this.mTabs[newIndexOn].boxObject;
arrowX = tabBoxObject.x + tabBoxObject.width / 2;
}
else {
var newIndexBetween = this.getDropIndex(aEvent);
if (newIndexBetween == this.mTabs.length) {
tabBoxObject = this.mTabs[this.mTabs.length - 1].boxObject;
arrowX = tabBoxObject.x;
if (ltr) // for LTR "after" is on the right-hand side of the tab
arrowX += tabBoxObject.width;
}
else {
tabBoxObject = this.mTabs[newIndexBetween].boxObject;
arrowX = tabBoxObject.x;
if (!ltr) // for RTL "before" is on the right-hand side of the tab
arrowX += tabBoxObject.width;
}
}
if (ltr)
ind.style.marginLeft = (arrowX - this.boxObject.x) + "px";
else
ind.style.marginRight = (this.boxObject.x + this.boxObject.width - arrowX) + "px";
ib.hidden = false;
]]>
</body>
</method>
<method name="onDrop">
<parameter name="aEvent"/>
<parameter name="aXferData"/>
<parameter name="aDragSession"/>
<body>
<![CDATA[
var newIndex = this.getDropIndex(aEvent);
var tabIndex;
if (aDragSession.sourceNode &&
aDragSession.sourceNode.parentNode == this.mTabContainer) {
tabIndex = this.getTabIndex(aDragSession.sourceNode);
if (newIndex > tabIndex)
newIndex--;
this.moveTabTo(tabIndex, newIndex);
} 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;
// Perform a security check before loading the URI
nsDragAndDrop.dragDropSecurityCheck(aEvent, aDragSession, url);
var bgLoad = this.mPrefs.getBoolPref("browser.tabs.loadInBackground");
var tab = null;
tabIndex = this.getDropOnIndex(aEvent);
if (tabIndex != -1) {
// Load in an existing tab
tab = this.mTabs[tabIndex];
tab.linkedBrowser.loadURI(getShortcutOrURI(url));
}
else {
// We're adding a new tab
tab = this.addTab(getShortcutOrURI(url));
if (newIndex != this.mTabs.length - 1)
this.moveTabTo(this.mTabs.length - 1, newIndex);
}
if (this.mCurrentTab != tab && !bgLoad)
this.selectedTab = tab;
}
]]>
</body>
</method>
<method name="onDragExit">
<parameter name="aEvent"/>
<parameter name="aDragSession"/>
<body>
<![CDATA[
var target = aEvent.relatedTarget;
while (target && target != this.mStrip)
target = target.parentNode;
if (target)
return;
document.getAnonymousElementByAttribute(this, "class",
"tab-drop-indicator-bar")
.hidden = true;
]]>
</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>
2007-04-01 03:07:36 +04:00
<method name="moveTabTo">
<parameter name="aSrcIndex"/>
<parameter name="aDestIndex"/>
<body>
<![CDATA[
// for compatibility with extensions
if (typeof(aSrcIndex) != "number")
aSrcIndex = this.getTabIndex(aSrcIndex);
this.mTabFilters.splice(aDestIndex, 0, this.mTabFilters.splice(aSrcIndex, 1)[0]);
this.mTabListeners.splice(aDestIndex, 0, this.mTabListeners.splice(aSrcIndex, 1)[0]);
this.mCurrentTab.selected = false;
if (aDestIndex >= aSrcIndex)
++aDestIndex;
var tab = this.mTabContainer.insertBefore(this.mTabs[aSrcIndex], this.mTabs.item(aDestIndex));
this.mCurrentTab.selected = true;
return tab;
]]>
</body>
</method>
<method name="getDropIndex">
<parameter name="aEvent"/>
<body>
<![CDATA[
for (var i = 0; i < this.mTabs.length; ++i) {
var coord = this.mTabs[i].boxObject.x +
this.mTabs[i].boxObject.width / 2;
if (window.getComputedStyle(this, null).direction == "ltr") {
if (aEvent.clientX < coord)
return i;
} else {
if (aEvent.clientX > coord)
return i;
}
}
return this.mTabs.length;
]]>
</body>
</method>
<method name="getDropOnIndex">
<parameter name="aEvent"/>
<body>
<![CDATA[
for (var i = 0; i < this.mTabs.length; ++i) {
var tabBoxObject = this.mTabs[i].boxObject;
if (aEvent.clientX > tabBoxObject.x + tabBoxObject.width * .25 &&
aEvent.clientX < tabBoxObject.x + tabBoxObject.width * .75)
return i;
}
return -1;
]]>
</body>
</method>
<method name="moveTabLeft">
<body>
<![CDATA[
if (window.getComputedStyle(this, null).direction == "ltr")
this.moveTabBackward();
else
this.moveTabForward();
]]>
</body>
</method>
<method name="moveTabRight">
<body>
<![CDATA[
if (window.getComputedStyle(this, null).direction == "ltr")
this.moveTabForward();
else
this.moveTabBackward();
]]>
</body>
</method>
<method name="moveTabForward">
<body>
<![CDATA[
var tabPos = this.mTabContainer.selectedIndex;
if (tabPos < this.browsers.length - 1) {
this.moveTabTo(tabPos, tabPos + 1);
this.mCurrentTab.focus();
}
else if (this.arrowKeysShouldWrap)
this.moveTabToStart();
]]>
</body>
</method>
<method name="moveTabBackward">
<body>
<![CDATA[
var tabPos = this.mTabContainer.selectedIndex;
if (tabPos > 0) {
this.moveTabTo(tabPos, tabPos - 1);
this.mCurrentTab.focus();
}
else if (this.arrowKeysShouldWrap)
this.moveTabToEnd();
]]>
</body>
</method>
<method name="moveTabToStart">
<body>
<![CDATA[
var tabPos = this.mTabContainer.selectedIndex;
if (tabPos > 0) {
this.moveTabTo(tabPos, 0);
this.mCurrentTab.focus();
}
]]>
</body>
</method>
<method name="moveTabToEnd">
<body>
<![CDATA[
var tabPos = this.mTabContainer.selectedIndex;
if (tabPos < this.browsers.length - 1) {
this.moveTabTo(tabPos, this.browsers.length - 1);
this.mCurrentTab.focus();
}
]]>
</body>
</method>
<field name="backBrowserGroup">
[]
</field>
<field name="forwardBrowserGroup">
[]
</field>
<method name="replaceGroup">
<parameter name="aGroup"/>
<body>
<![CDATA[
var oldBrowserGroup = [];
var oldCount = this.mPanelContainer.childNodes.length;
var newCount = aGroup.length;
var n = Math.max(oldCount, newCount);
for (var i = 0; i < n; ++i) {
if (i < newCount) {
var data = aGroup[i];
if ("sessionHistory" in data) {
this.addTab("about:blank", null);
var browser = this.mPanelContainer.lastChild;
// need to hold on to the listener so it won't go away
// addProgressListener only has a weak pointer to it
browser._SHListener =
this.mInstallSH(browser, aGroup[i].sessionHistory);
browser.webProgress.addProgressListener(browser._SHListener, Components.interfaces.nsIWebProgress.NOTIFY_ALL);
} else {
var referrerURI = "referrerURI" in data ? data.referrerURI : null;
this.addTab(data.URI, referrerURI);
}
}
if (i < oldCount) {
var firstTab = this.mTabContainer.firstChild;
var browserData = {
2007-04-01 03:08:46 +04:00
sessionHistory : firstTab.linkedBrowser.sessionHistory
}
oldBrowserGroup.push(browserData);
this.removeTab(firstTab);
}
}
return oldBrowserGroup;
]]>
</body>
</method>
<method name="appendGroup">
<parameter name="aGroup"/>
<body>
<![CDATA[
for (var i in aGroup) {
var page = aGroup[i];
var referrerURI = "referrerURI" in page ? page.referrerURI : null;
this.addTab(page.URI, referrerURI);
}
]]>
</body>
</method>
<method name="loadGroup">
<parameter name="aGroup"/>
<body>
<![CDATA[
if (aGroup.length == 0)
return null;
var tab;
if (this.mPrefs.getIntPref("browser.tabs.loadGroup") == 0) {
var oldCount = this.mTabs.length;
this.appendGroup(aGroup);
tab = this.mTabs[oldCount];
} else {
this.backBrowserGroup = this.replaceGroup(aGroup);
this.forwardBrowserGroup = [];
tab = this.mTabContainer.firstChild;
}
return tab;
]]>
</body>
</method>
<method name="goBackGroup">
<body>
<![CDATA[
this.forwardBrowserGroup = this.replaceGroup(this.backBrowserGroup);
this.backBrowserGroup = [];
]]>
</body>
</method>
<method name="goForwardGroup">
<body>
<![CDATA[
this.backBrowserGroup = this.replaceGroup(this.forwardBrowserGroup);
this.forwardBrowserGroup = [];
]]>
</body>
</method>
2007-04-01 03:03:27 +04:00
<!-- 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.backBrowserGroup.length != 0 || this.mCurrentBrowser.canGoBack;"
2007-04-01 03:03:27 +04:00
readonly="true"/>
<property name="canGoForward"
onget="return this.forwardBrowserGroup.length != 0 || this.mCurrentBrowser.canGoForward;"
2007-04-01 03:03:27 +04:00
readonly="true"/>
<method name="goBack">
<body>
<![CDATA[
if (this.backBrowserGroup.length != 0)
return this.goBackGroup();
2007-04-01 03:03:27 +04:00
return this.mCurrentBrowser.goBack();
]]>
</body>
</method>
<method name="goForward">
<body>
<![CDATA[
if (this.forwardBrowserGroup.length != 0)
return this.goForwardGroup();
2007-04-01 03:03:27 +04:00
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"/>
2007-04-01 03:03:27 +04:00
<body>
<![CDATA[
return this.mCurrentBrowser.loadURI(aURI, aReferrerURI, aCharset);
2007-04-01 03:03:27 +04:00
]]>
</body>
</method>
<!-- throws exception for unknown schemes -->
<method name="loadURIWithFlags">
<parameter name="aURI"/>
<parameter name="aFlags"/>
<parameter name="aReferrerURI"/>
<parameter name="aCharset"/>
2007-04-01 03:03:27 +04:00
<body>
<![CDATA[
return this.mCurrentBrowser.loadURIWithFlags(aURI, aFlags, aReferrerURI, aCharset);
2007-04-01 03:03:27 +04:00
]]>
</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>
<property name="currentURI"
onget="return this.mCurrentBrowser.currentURI;"
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"/>
2007-04-01 03:03:27 +04:00
<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;"/>
2007-04-01 03:03:27 +04:00
<constructor>
<![CDATA[
this.mCurrentBrowser = this.mPanelContainer.firstChild;
this.mCurrentTab = this.mTabContainer.firstChild;
document.addEventListener("keypress", this._keyEventHandler, false);
this.mTabBox.handleCtrlTab = !/Mac/.test(navigator.platform);
this.arrowKeysShouldWrap = /Mac/.test(navigator.platform);
var uniqueId = "panel" + this.nextTabNumber++;
this.mPanelContainer.childNodes[0].id = uniqueId;
this.mTabs[0].linkedPanel = uniqueId;
this.mTabs[0].linkedBrowser = this.mPanelContainer.childNodes[0];
// Wire up the first title change listener.
this.mCurrentBrowser.addEventListener("DOMTitleChanged", this.onTitleChanged, false);
// Ensure the browser's session history and security UI are wired up
this.mCurrentBrowser.init();
// Wire up the tab's progress listener and filter.
const nsIWebProgress = Components.interfaces.nsIWebProgress;
var tabListener = this.mTabProgressListener(this.mCurrentTab,
this.mCurrentBrowser,
false);
var filter = Components.classes["@mozilla.org/appshell/component/browser-status-filter;1"]
.createInstance(nsIWebProgress);
filter.addProgressListener(tabListener, nsIWebProgress.NOTIFY_ALL);
this.webProgress.addProgressListener(filter,
nsIWebProgress.NOTIFY_ALL);
this.mTabListeners[0] = tabListener;
this.mTabFilters[0] = filter;
if (!this.mPrefs.getBoolPref("browser.tabs.autoHide") &&
!this.mPrefs.getBoolPref("browser.tabs.forceHide") &&
window.toolbar.visible)
this.mStrip.collapsed = false;
]]>
2007-04-01 03:03:27 +04:00
</constructor>
<destructor>
<![CDATA[
for (var i = 0; i < this.mTabListeners.length; ++i) {
this.mPanelContainer.childNodes[i].webProgress.removeProgressListener(this.mTabFilters[i]);
this.mTabFilters[i].removeProgressListener(this.mTabListeners[i]);
this.mTabFilters[i] = null;
this.mTabListeners[i] = null;
this.mPanelContainer.childNodes[i].removeEventListener("DOMTitleChanged", this.onTitleChanged, false);
2007-04-01 03:03:27 +04:00
}
document.removeEventListener("keypress", this._keyEventHandler, false);
2007-04-01 03:03:27 +04:00
]]>
</destructor>
</implementation>
<handlers>
<handler event="select" action="if (event.originalTarget == this.mPanelContainer) this.updateCurrentBrowser();"/>
<handler event="DOMLinkAdded" action="this.onLinkAdded(event);"/>
<handler event="DOMWindowClose">
<![CDATA[
if (!event.isTrusted)
return;
const browsers = this.browsers;
if (browsers.length == 1)
return;
var i = 0;
for (; i < browsers.length; ++i) {
if (browsers[i].contentWindow == event.target)
break;
}
this.removeTab(this.mTabs[i]);
event.preventDefault();
]]>
</handler>
<handler event="DOMWillOpenModalDialog">
<![CDATA[
if (!event.isTrusted)
return;
// We're about to open a modal dialog, make sure the opening
// tab is brought to the front.
const browsers = this.browsers;
for (var i = 0; i < browsers.length; ++i) {
if (browsers[i].contentWindow == event.target.top) {
this.selectedTab = this.mTabs[i];
break;
}
}
]]>
</handler>
<handler event="keypress" keycode="VK_LEFT" modifiers="accel" action="if (event.target == this) { this.moveTabLeft(); event.preventDefault(); }"/>
<handler event="keypress" keycode="VK_RIGHT" modifiers="accel" action="if (event.target == this) { this.moveTabRight(); event.preventDefault(); }"/>
<handler event="keypress" keycode="VK_UP" modifiers="accel" action="if (event.target == this) { this.moveTabBackward(); event.preventDefault(); }"/>
<handler event="keypress" keycode="VK_DOWN" modifiers="accel" action="if (event.target == this) { this.moveTabForward(); event.preventDefault(); }"/>
<handler event="keypress" keycode="VK_HOME" modifiers="accel" action="if (event.target == this) { this.moveTabToStart(); event.preventDefault(); }"/>
<handler event="keypress" keycode="VK_END" modifiers="accel" action="if (event.target == this) { this.moveTabToEnd(); event.preventDefault(); }"/>
</handlers>
2007-04-01 03:03:27 +04:00
</binding>
</bindings>