mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
b1552b1ab3
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.
317 lines
12 KiB
XML
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>
|