mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-03-09 04:25:38 +00:00
Bug 582583 - Expose a small, simple UI for 'Undo Closed Tab' [r=mfinkle]
This commit is contained in:
parent
f3b1ddb5d0
commit
3d7c42a6dd
@ -409,6 +409,7 @@ var BrowserUI = {
|
||||
let tabs = document.getElementById("tabs");
|
||||
tabs.addEventListener("TabSelect", this, true);
|
||||
tabs.addEventListener("TabOpen", this, true);
|
||||
window.addEventListener("PanFinished", this, true);
|
||||
|
||||
// listen content messages
|
||||
messageManager.addMessageListener("DOMLinkAdded", this);
|
||||
@ -770,8 +771,8 @@ var BrowserUI = {
|
||||
case "TabOpen":
|
||||
{
|
||||
let [tabsVisibility,,,] = Browser.computeSidebarVisibility();
|
||||
if (!(tabsVisibility == 1.0) && Browser.selectedTab.chromeTab != aEvent.target)
|
||||
NewTabPopup.show(aEvent.target);
|
||||
if (!(tabsVisibility == 1.0) && Browser.selectedTab.chromeTab != aEvent.originalTarget)
|
||||
NewTabPopup.show(aEvent.originalTarget);
|
||||
|
||||
// Workaround to hide the tabstrip if it is partially visible
|
||||
// See bug 524469
|
||||
@ -780,6 +781,11 @@ var BrowserUI = {
|
||||
|
||||
break;
|
||||
}
|
||||
case "PanFinished":
|
||||
let [tabsVisibility,,,] = Browser.computeSidebarVisibility();
|
||||
if (tabsVisibility == 0.0)
|
||||
document.getElementById("tabs").removeClosedTab();
|
||||
break;
|
||||
// Window events
|
||||
case "keypress":
|
||||
if (aEvent.keyCode == aEvent.DOM_VK_ESCAPE)
|
||||
|
@ -18,7 +18,7 @@ browser[remote="true"] {
|
||||
-moz-binding: url("chrome://browser/content/tabs.xml#tablist");
|
||||
}
|
||||
|
||||
box[type="documenttab"] {
|
||||
documenttab {
|
||||
-moz-binding: url("chrome://browser/content/tabs.xml#documenttab");
|
||||
}
|
||||
|
||||
|
@ -211,7 +211,11 @@
|
||||
<spacer class="toolbar-height"/>
|
||||
<!-- Left toolbar -->
|
||||
<vbox id="tabs-container" class="panel-dark" flex="1">
|
||||
<vbox id="tabs" onselect="BrowserUI.selectTab(this);" onclosetab="BrowserUI.closeTab(this)" flex="1"/>
|
||||
<vbox id="tabs" flex="1"
|
||||
onselect="BrowserUI.selectTab(this);"
|
||||
onreloadtab="BrowserUI.undoCloseTab()"
|
||||
onclosetab="BrowserUI.closeTab(this)"
|
||||
onclosereloadtab="this._container.removeTab(this)"/>
|
||||
<hbox id="tabs-controls">
|
||||
<toolbarbutton id="newtab-button" class="button-image" command="cmd_newTab"/>
|
||||
</hbox>
|
||||
|
@ -9,35 +9,51 @@
|
||||
<binding id="documenttab">
|
||||
<content>
|
||||
<xul:stack anonid="page" class="documenttab-container" flex="1">
|
||||
<html:canvas anonid="canvas" class="documenttab-canvas" left="0" width="106" height="64" moz-opaque="true"
|
||||
onclick="document.getBindingParent(this)._onClick()" xbl:inherits="selected"/>
|
||||
<xul:hbox class="documenttab-close-container" left="0" top="10" height="64" width="55" align="center" onclick="document.getBindingParent(this)._close()">
|
||||
<html:canvas anonid="thumbnail" class="documenttab-thumbnail" left="0" width="106" height="64" moz-opaque="true" empty="true"
|
||||
onclick="document.getBindingParent(this)._onClick()"/>
|
||||
<xul:hbox class="documenttab-reload" left="0" top="0" width="122" height="80" onclick="document.getBindingParent(this)._onUndo();"/>
|
||||
<xul:hbox class="documenttab-close-container" left="0" top="10" height="64" width="55" align="center" onclick="document.getBindingParent(this)._onClose()">
|
||||
<xul:image anonid="close" class="documenttab-close" mousethrough="always"/>
|
||||
</xul:hbox>
|
||||
</xul:stack>
|
||||
</content>
|
||||
|
||||
|
||||
<implementation>
|
||||
<field name="thumbnail">document.getAnonymousElementByAttribute(this, "anonid", "thumbnail");</field>
|
||||
<field name="_container">this.parentNode.parentNode;</field>
|
||||
<method name="_onClick">
|
||||
<body>
|
||||
<![CDATA[
|
||||
this.parentNode.selectedTab = this;
|
||||
this._container.selectedTab = this;
|
||||
|
||||
let selectFn = new Function("event", this.parentNode.getAttribute('onselect'));
|
||||
let selectFn = new Function("event", this._container.getAttribute("onselect"));
|
||||
selectFn.call(this);
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
|
||||
<method name="_close">
|
||||
<method name="_onClose">
|
||||
<body>
|
||||
<![CDATA[
|
||||
let closeFn = new Function("event", this.parentNode.getAttribute('onclosetab'));
|
||||
|
||||
let callbackFunc = this._container.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="updateThumbnail">
|
||||
<parameter name="browser"/>
|
||||
<parameter name="width"/>
|
||||
@ -49,9 +65,11 @@
|
||||
|
||||
let ratio = tabHeight / tabWidth;
|
||||
height = width * ratio;
|
||||
|
||||
let thumbnail = this.thumbnail;
|
||||
thumbnail.removeAttribute("empty");
|
||||
|
||||
let canvas = document.getAnonymousElementByAttribute(this, "anonid", "canvas");
|
||||
let renderer = rendererFactory(browser, canvas)
|
||||
let renderer = rendererFactory(browser, thumbnail)
|
||||
renderer.drawContent(function(ctx, callback) {
|
||||
ctx.save();
|
||||
ctx.clearRect(0, 0, tabWidth, tabHeight);
|
||||
@ -66,22 +84,24 @@
|
||||
</binding>
|
||||
|
||||
<binding id="tablist">
|
||||
<content>
|
||||
<xul:vbox anonid="tabs-children" flex="1"/>
|
||||
<xul:box anonid="tabs-undo"/>
|
||||
</content>
|
||||
<implementation>
|
||||
<field name="children">document.getAnonymousElementByAttribute(this, "anonid", "tabs-children");</field>
|
||||
<field name="_tabsUndo">document.getAnonymousElementByAttribute(this, "anonid", "tabs-undo");</field>
|
||||
<field name="_closedTab">null</field>
|
||||
<field name="_selectedTab">null</field>
|
||||
|
||||
<property name="selectedTab">
|
||||
<getter>
|
||||
<![CDATA[
|
||||
return this._selectedTab;
|
||||
]]>
|
||||
</getter>
|
||||
<property name="selectedTab" onget="return this._selectedTab;">
|
||||
<setter>
|
||||
<![CDATA[
|
||||
if (this._selectedTab)
|
||||
this._selectedTab.removeAttribute('selected');
|
||||
this._selectedTab.removeAttribute("selected");
|
||||
|
||||
if (val)
|
||||
val.setAttribute('selected', 'true');
|
||||
val.setAttribute("selected", "true");
|
||||
|
||||
this._selectedTab = val;
|
||||
]]>
|
||||
@ -91,9 +111,8 @@
|
||||
<method name="addTab">
|
||||
<body>
|
||||
<![CDATA[
|
||||
let tab = document.createElement("box");
|
||||
tab.setAttribute("type", "documenttab");
|
||||
this.appendChild(tab);
|
||||
let tab = document.createElement("documenttab");
|
||||
this.children.appendChild(tab);
|
||||
this._updateWidth();
|
||||
return tab;
|
||||
]]>
|
||||
@ -104,21 +123,51 @@
|
||||
<parameter name="aTab"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
this.removeChild(aTab);
|
||||
this._updateWidth();
|
||||
let closedTab = this._closedTab;
|
||||
if (closedTab) {
|
||||
this._tabsUndo.removeChild(closedTab);
|
||||
this._closedTab = null;
|
||||
}
|
||||
|
||||
if (!closedTab || closedTab != aTab) {
|
||||
if (aTab.thumbnail && !aTab.thumbnail.hasAttribute("empty")) {
|
||||
// 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() aTab.thumbnail.getContext("2d").drawImage(thumbnailImg, 0, 0);
|
||||
thumbnailImg.src = oldThumbnail;
|
||||
}
|
||||
else
|
||||
this._tabsUndo.appendChild(aTab);
|
||||
|
||||
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 = this.parentNode.getBoundingClientRect();
|
||||
let element = this.getBoundingClientRect();
|
||||
|
||||
let height = (element.top - container.top) +
|
||||
((container.top + container.height) - (element.top + element.height));
|
||||
this.style.height = height + "px";
|
||||
let element = this.children.getBoundingClientRect();
|
||||
|
||||
let height = (element.top - container.top) + ((container.top + container.height) - (element.top + element.height));
|
||||
this.children.style.height = height + "px";
|
||||
|
||||
this._updateWidth();
|
||||
]]>
|
||||
@ -129,12 +178,12 @@
|
||||
<method name="_updateWidth">
|
||||
<body>
|
||||
<![CDATA[
|
||||
let firstBox = this.firstChild.getBoundingClientRect();
|
||||
let lastBox = this.lastChild.getBoundingClientRect();
|
||||
let columnsCount = Math.ceil(this.childNodes.length / Math.floor(this.style.height / firstBox.height));
|
||||
let firstBox = this.children.firstChild.getBoundingClientRect();
|
||||
let lastBox = this.children.lastChild.getBoundingClientRect();
|
||||
let columnsCount = Math.ceil(this.children.childNodes.length / Math.floor(this.children.style.height / firstBox.height));
|
||||
if (this._columnsCount != columnsCount) {
|
||||
let width = Math.max(lastBox.right - firstBox.left, firstBox.right - lastBox.left);
|
||||
this.style.width = width + "px";
|
||||
this.children.style.width = width + "px";
|
||||
this._columnsCount = columnsCount;
|
||||
}
|
||||
]]>
|
||||
|
@ -1007,7 +1007,7 @@ autocompleteresult.noresults > .autocomplete-item-container {
|
||||
-moz-border-end: 3px solid #262629;
|
||||
}
|
||||
|
||||
#tabs {
|
||||
#tabs > * {
|
||||
display: block;
|
||||
-moz-column-width: 128px;
|
||||
-moz-column-gap: 0;
|
||||
@ -1017,12 +1017,16 @@ autocompleteresult.noresults > .autocomplete-item-container {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
#tabs documenttab:only-child .documenttab-close {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#tabs-controls {
|
||||
margin-top: 8px; /* core spacing */
|
||||
-moz-box-pack: start;
|
||||
}
|
||||
|
||||
box[type="documenttab"] {
|
||||
documenttab {
|
||||
/* display:block allow us to change the line-height, it won't work otherwise */
|
||||
display: block;
|
||||
width: 128px;
|
||||
@ -1030,13 +1034,31 @@ box[type="documenttab"] {
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
.documenttab-canvas {
|
||||
documenttab .documenttab-thumbnail {
|
||||
/* keep the unselected thumbnails aligned with the selected one */
|
||||
border: 8px solid #36373b;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.documenttab-canvas[selected="true"] {
|
||||
documenttab .documenttab-close-container {
|
||||
-moz-margin-end: 65px;
|
||||
}
|
||||
|
||||
documenttab .documenttab-close-container > .documenttab-close {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
list-style-image: url("chrome://browser/skin/images/close-default-40.png");
|
||||
}
|
||||
|
||||
documenttab .documenttab-close-container:hover:active > .documenttab-close {
|
||||
list-style-image: url("chrome://browser/skin/images/close-active-40.png");
|
||||
}
|
||||
|
||||
documenttab .documenttab-reload {
|
||||
display: none;
|
||||
}
|
||||
|
||||
documenttab[selected="true"] .documenttab-thumbnail {
|
||||
border: 8px solid;
|
||||
-moz-border-radius: 3px;
|
||||
-moz-border-top-colors: #8db8d8 #8db8d8 #8db8d8 #8db8d8 #36373b;
|
||||
@ -1045,24 +1067,25 @@ box[type="documenttab"] {
|
||||
-moz-border-left-colors: #8db8d8 #8db8d8 #8db8d8 #8db8d8 #36373b;
|
||||
}
|
||||
|
||||
.documenttab-close-container {
|
||||
-moz-margin-end: 65px;
|
||||
documenttab[reload="true"] .documenttab-thumbnail {
|
||||
border: 8px solid;
|
||||
-moz-border-radius: 3px;
|
||||
-moz-border-top-colors: #262629 #262629 #262629 #262629 #262629 !important;
|
||||
-moz-border-right-colors: #262629 #262629 #262629 #262629 #262629 !important;
|
||||
-moz-border-bottom-colors: #262629 #262629 #262629 #262629 #262629 !important;
|
||||
-moz-border-left-colors: #262629 #262629 #262629 #262629 #262629 !important;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.documenttab-close {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
list-style-image: url("chrome://browser/skin/images/close-default-40.png");
|
||||
}
|
||||
|
||||
hbox:hover:active > .documenttab-close {
|
||||
list-style-image: url("chrome://browser/skin/images/close-active-40.png");
|
||||
}
|
||||
|
||||
box[type="documenttab"]:only-child > stack > hbox > .documenttab-close {
|
||||
documenttab[reload="true"] .documenttab-close-container {
|
||||
display: none;
|
||||
}
|
||||
|
||||
documenttab[reload="true"] .documenttab-reload {
|
||||
background: url("chrome://browser/skin/images/reload-tab.png") no-repeat center center, -moz-radial-gradient(circle, rgba(137,215,21,0.8) 10%, rgba(68,108,17,0) 40%);
|
||||
display: -moz-box;
|
||||
}
|
||||
|
||||
#newtab-button {
|
||||
list-style-image: url("images/newtab-default-64.png");
|
||||
}
|
||||
|
BIN
mobile/themes/core/images/reload-tab.png
Normal file
BIN
mobile/themes/core/images/reload-tab.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
@ -42,6 +42,7 @@ chrome.jar:
|
||||
skin/images/folder-32.png (images/folder-32.png)
|
||||
skin/images/stop-30.png (images/stop-30.png)
|
||||
skin/images/reload-30.png (images/reload-30.png)
|
||||
skin/images/reload-tab.png (images/reload-tab.png)
|
||||
skin/images/alert-addons-30.png (images/alert-addons-30.png)
|
||||
skin/images/alert-downloads-30.png (images/alert-downloads-30.png)
|
||||
skin/images/addons-default-64.png (images/addons-default-64.png)
|
||||
|
Loading…
x
Reference in New Issue
Block a user