gecko/mobile/chrome/content/tabs.xml
Lucas Rocha b1552b1ab3 Bug 687287 - Fix alignment of close button on inactive tabs (r=mfinkle)
Do not force a width on close button container and let the margins define its size. This allows us to have different clickable areas for the close button on both active and inactive tabs.
2011-09-19 09:44:03 -07:00

317 lines
12 KiB
XML

<?xml version="1.0"?>
<bindings
xmlns="http://www.mozilla.org/xbl"
xmlns:xbl="http://www.mozilla.org/xbl"
xmlns:html="http://www.w3.org/1999/xhtml"
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<binding id="documenttab">
<content observes="bcast_urlbarState">
<xul:vbox anonid="container" class="documenttab-container" left="0" top="0" observes="bcast_urlbarState">
<xul:stack anonid="page" flex="1">
<html:canvas anonid="thumbnail" class="documenttab-thumbnail" left="0" moz-opaque="true" empty="true"
onclick="document.getBindingParent(this)._onClick()" observes="bcast_urlbarState"/>
<xul:hbox anonid="reload" class="documenttab-reload" left="0" top="0" onclick="document.getBindingParent(this)._onUndo();" observes="bcast_urlbarState"/>
<xul:hbox anonid="close-container" class="documenttab-close-container" top="0" align="center" onclick="document.getBindingParent(this)._onClose()" observes="bcast_urlbarState">
<xul:image anonid="close" class="documenttab-close" mousethrough="always" observes="bcast_urlbarState"/>
</xul:hbox>
</xul:stack>
<xul:label anonid="title" crop="end" class="documenttab-title" observes="bcast_urlbarState"/>
</xul:vbox>
</content>
<implementation>
<field name="ignoreUndo">false</field>
<field name="thumbnail" readonly="true">document.getAnonymousElementByAttribute(this, "anonid", "thumbnail");</field>
<field name="_reload" readonly="true">document.getAnonymousElementByAttribute(this, "anonid", "reload");</field>
<field name="_closeContainer" readonly="true">document.getAnonymousElementByAttribute(this, "anonid", "close-container");</field>
<field name="_title" readonly="true">document.getAnonymousElementByAttribute(this, "anonid", "title");</field>
<field name="_container" readonly="true">this.parentNode.parentNode;</field>
<constructor>
<![CDATA[
this.updateTabletLayout(this.thumbnail);
]]>
</constructor>
<method name="updateTabletLayout">
<parameter name="thumbnail"/>
<body>
<![CDATA[
let tabWidth, tabHeight;
if (Util.isTablet()) {
tabWidth = 176;
tabHeight = 110;
} else {
tabWidth = 104;
tabHeight = 65;
}
if (tabWidth != thumbnail.width) {
let reload = this._reload;
let closeContainer = this._closeContainer;
let title = this._title;
thumbnail.width = reload.width = title.width = tabWidth;
thumbnail.height = reload.height = tabHeight;
closeContainer.height = tabHeight;
}
]]>
</body>
</method>
<method name="_onClick">
<body>
<![CDATA[
this._container.selectedTab = this;
let selectFn = new Function("event", this._container.parentNode.getAttribute("onselect"));
selectFn.call(this);
]]>
</body>
</method>
<method name="_onClose">
<body>
<![CDATA[
let callbackFunc = this._container.parentNode.getAttribute(this.hasAttribute("reload") ? "onclosereloadtab" : "onclosetab");
let closeFn = new Function("event", callbackFunc);
closeFn.call(this);
]]>
</body>
</method>
<method name="_onUndo">
<body>
<![CDATA[
let closeFn = new Function("event", this._container.getAttribute("onreloadtab"));
closeFn.call(this);
this._container.removeTab(this);
]]>
</body>
</method>
<method name="updateTitle">
<parameter name="title"/>
<body>
<![CDATA[
this._title.value = title;
]]>
</body>
</method>
<method name="updateThumbnail">
<parameter name="browser"/>
<parameter name="width"/>
<parameter name="height"/>
<body>
<![CDATA[
let thumbnail = this.thumbnail;
// Ensure the thumbnail will have the correct
// dimensions for tablet and phone modes
this.updateTabletLayout(thumbnail);
if (browser.currentURI.spec == "about:blank") {
thumbnail.setAttribute("empty", "true");
return;
}
thumbnail.removeAttribute("empty");
const tabWidth = thumbnail.width;
const tabHeight = thumbnail.height;
let ratio = tabHeight / tabWidth;
if (browser.contentDocumentWidth > 0)
width = Math.min(width, browser.contentDocumentWidth);
if (browser.contentDocumentHeight > 0)
height = Math.min(height, browser.contentDocumentHeight);
let newHeight = width * ratio;
if (height >= newHeight) {
height = newHeight;
} else {
// the browser aspect ratio does not match the tabs aspect ratio
width = height / ratio;
}
// Recreate the canvas as it may be tainted and not useable for remote pages
if (thumbnail.hasAttribute("restored")) {
thumbnail.removeAttribute("restored");
thumbnail = this.thumbnail.cloneNode(false);
this.thumbnail.parentNode.replaceChild(thumbnail, this.thumbnail);
this.thumbnail = thumbnail;
}
let self = this;
let renderer = rendererFactory(browser, thumbnail);
renderer.drawContent(function(ctx, callback) {
ctx.save();
ctx.clearRect(0, 0, tabWidth, tabHeight);
ctx.scale(tabWidth / width, tabHeight / height);
callback(browser, 0, 0, width, height, "white");
ctx.restore();
// We don't have an event for the async drawContent anymore, so hack it
setTimeout(function() {
// Save the thumbnail to the session in case we need to use it in a restore
let data = thumbnail.toDataURL("image/png");
let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
ss.setTabValue(self, "thumbnail", data);
}, 800);
});
]]>
</body>
</method>
</implementation>
</binding>
<binding id="tablist">
<content>
<xul:scrollbox anonid="tabs-scrollbox" class="tabs-scrollbox" flex="1">
<xul:vbox class="tabs-list" anonid="tabs-children" />
</xul:scrollbox>
<xul:box class="tabs-list" anonid="tabs-undo"/>
</content>
<implementation>
<field name="children">document.getAnonymousElementByAttribute(this, "anonid", "tabs-children");</field>
<field name="_scrollbox">document.getAnonymousElementByAttribute(this, "anonid", "tabs-scrollbox");</field>
<field name="_tabsUndo">document.getAnonymousElementByAttribute(this, "anonid", "tabs-undo");</field>
<field name="_selectedTab">null</field>
<!-- Used by the chrome input handler -->
<property name="boxObject"
readonly="true"
onget="return this._scrollbox.boxObject;"/>
<field name="scrollBoxObject">
this.boxObject.QueryInterface(Ci.nsIScrollBoxObject);
</field>
<field name="_closedTab">null</field>
<property name="hasClosedTab" readonly="true" onget="return !!this._closedTab;"/>
<property name="selectedTab" onget="return this._selectedTab;">
<setter>
<![CDATA[
if (this._selectedTab)
this._selectedTab.removeAttribute("selected");
if (val)
val.setAttribute("selected", "true");
this._selectedTab = val;
]]>
</setter>
</property>
<method name="addTab">
<body>
<![CDATA[
let tab = document.createElement("documenttab");
this.children.appendChild(tab);
this._updateWidth();
return tab;
]]>
</body>
</method>
<method name="removeTab">
<parameter name="aTab"/>
<body>
<![CDATA[
let closedTab = this._closedTab;
if (closedTab) {
this._tabsUndo.removeChild(closedTab);
this._closedTab = null;
}
let isEmpty = (aTab.thumbnail && aTab.thumbnail.hasAttribute("empty"));
if (aTab.ignoreUndo || isEmpty) {
this.children.removeChild(aTab);
} else if (!closedTab || closedTab != aTab) {
// duplicate the old thumbnail to the new one because moving the
// tab in the dom clear the canvas
let oldThumbnail = aTab.thumbnail.toDataURL("image/png");
this._tabsUndo.appendChild(aTab);
let thumbnailImg = new Image();
thumbnailImg.onload = function() {
if (aTab.thumbnail)
aTab.thumbnail.getContext("2d").drawImage(thumbnailImg, 0, 0);
};
thumbnailImg.src = oldThumbnail;
aTab.setAttribute("reload", "true");
this._closedTab = aTab;
}
this.resize();
]]>
</body>
</method>
<method name="removeClosedTab">
<body><![CDATA[
if (!this._closedTab)
return;
this.removeTab(this._closedTab);
]]></body>
</method>
<method name="resize">
<body>
<![CDATA[
let container = Rect.fromRect(this.parentNode.getBoundingClientRect());
if (container.height == 0)
return; // Don't try to resize while collapsed.
let element = Rect.fromRect(this._scrollbox.getBoundingClientRect());
let undo = Rect.fromRect(this._tabsUndo.getBoundingClientRect());
let lastChild = Rect.fromRect(this.parentNode.lastChild.getBoundingClientRect());
let height = window.innerHeight - element.top - (lastChild.top - element.bottom) - lastChild.height;
this.children.style.height = height + "px";
this._scrollbox.style.height = height + "px";
this._updateWidth();
]]>
</body>
</method>
<field name="_columnsCount">0</field>
<method name="_updateWidth">
<body>
<![CDATA[
// XXX we can do better than using a constant
const COLUMN_MARGIN = 20;
let firstBox = this.children.firstChild.getBoundingClientRect();
let lastBox = this.children.lastChild.getBoundingClientRect();
// We can't rely on getBoundingClientRect() for this.children height
// it is not synced (sometimes, especially during resize) with the
// style.height rule
let columnsCount = Util.isTablet() ? 1 : Math.ceil(this.children.childNodes.length / Math.floor(parseInt(this.children.style.height) / (firstBox.height + 4)));
if (this._columnsCount != columnsCount && window.innerWidth > 1) { // > 1 to ignore column resizing while the main window is loading
let width = columnsCount * (COLUMN_MARGIN + firstBox.width);
this.children.style.width = width + "px";
// Clamp the sidebar width so it won't overflow the window. Only clamp
// the scrollbox. The children need to be the full width.
if (width > window.innerWidth - firstBox.width)
width = window.innerWidth - firstBox.width;
this._scrollbox.style.width = width + "px";
this._columnsCount = columnsCount;
}
]]>
</body>
</method>
</implementation>
</binding>
</bindings>