зеркало из https://github.com/mozilla/gecko-dev.git
Bug 395980 - Implement MRU order Ctrl+Tab panel with previews. r=mconnor
This commit is contained in:
Родитель
9b3bae8da4
Коммит
997038bbf3
|
@ -327,6 +327,9 @@ pref("browser.tabs.closeButtons", 1);
|
|||
// false return to the adjacent tab (old default)
|
||||
pref("browser.tabs.selectOwnerOnClose", true);
|
||||
|
||||
pref("browser.ctrlTab.previewsCount", 3);
|
||||
pref("browser.ctrlTab.smoothScroll", true);
|
||||
|
||||
// Default bookmark sorting
|
||||
pref("browser.bookmarks.sort.direction", "descending");
|
||||
pref("browser.bookmarks.sort.resource", "rdf:http://home.netscape.com/NC-rdf#Name");
|
||||
|
|
|
@ -0,0 +1,518 @@
|
|||
/*
|
||||
#ifdef 0
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* 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/
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* The Original Code is Tab Previews.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Mozilla.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2008
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Dão Gottwald <dao@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either 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 *****
|
||||
#endif
|
||||
*/
|
||||
|
||||
/**
|
||||
* Tab previews utility, produces thumbnails
|
||||
*/
|
||||
var tabPreviews = {
|
||||
aspectRatio: 0.6875, // 16:11
|
||||
init: function () {
|
||||
this.width = Math.ceil(screen.availWidth / 7.5);
|
||||
this.height = Math.round(this.width * this.aspectRatio);
|
||||
|
||||
gBrowser.tabContainer.addEventListener("TabSelect", this, false);
|
||||
gBrowser.tabContainer.addEventListener("SSTabRestored", this, false);
|
||||
},
|
||||
uninit: function () {
|
||||
gBrowser.tabContainer.removeEventListener("TabSelect", this, false);
|
||||
gBrowser.tabContainer.removeEventListener("SSTabRestored", this, false);
|
||||
this._selectedTab = null;
|
||||
},
|
||||
get: function (aTab) {
|
||||
return aTab.__thumbnail || this.capture(aTab, !aTab.hasAttribute("busy"));
|
||||
},
|
||||
capture: function (aTab, aStore) {
|
||||
var win = aTab.linkedBrowser.contentWindow;
|
||||
var thumbnail = document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
|
||||
thumbnail.mozOpaque = true;
|
||||
thumbnail.height = this.height;
|
||||
thumbnail.width = this.width;
|
||||
var ctx = thumbnail.getContext("2d");
|
||||
var widthScale = this.width / win.innerWidth;
|
||||
ctx.scale(widthScale, widthScale);
|
||||
ctx.drawWindow(win, win.scrollX, win.scrollY,
|
||||
win.innerWidth, win.innerWidth * this.aspectRatio, "rgb(255,255,255)");
|
||||
var data = thumbnail.toDataURL("image/jpeg", "quality=60");
|
||||
if (aStore)
|
||||
aTab.__thumbnail = data;
|
||||
return data;
|
||||
},
|
||||
handleEvent: function (event) {
|
||||
switch (event.type) {
|
||||
case "TabSelect":
|
||||
if (this._selectedTab &&
|
||||
this._selectedTab.parentNode &&
|
||||
!this._pendingUpdate) {
|
||||
// Generate a thumbnail for the tab that was selected.
|
||||
// The timeout keeps the UI snappy and prevents us from generating thumbnails
|
||||
// for tabs that will be closed. During that timeout, don't generate other
|
||||
// thumbnails in case multiple TabSelect events occur fast in succession.
|
||||
this._pendingUpdate = true;
|
||||
setTimeout(function (self, aTab) {
|
||||
self._pendingUpdate = false;
|
||||
if (aTab.parentNode && !aTab.hasAttribute("busy"))
|
||||
self.capture(aTab, true);
|
||||
}, 2000, this, this._selectedTab);
|
||||
}
|
||||
this._selectedTab = event.target;
|
||||
break;
|
||||
case "SSTabRestored":
|
||||
this.capture(event.target, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Ctrl-Tab panel
|
||||
*/
|
||||
var ctrlTab = {
|
||||
tabs: [],
|
||||
_uniqid: 0,
|
||||
get panel () {
|
||||
delete this.panel;
|
||||
return this.panel = document.getElementById("ctrlTab-panel");
|
||||
},
|
||||
get label () {
|
||||
delete this.label;
|
||||
return this.label = document.getElementById("ctrlTab-label");
|
||||
},
|
||||
get svgRoot () {
|
||||
delete this.svgRoot;
|
||||
|
||||
let (groundFade = document.getElementById("ctrlTab-groundFade")) {
|
||||
groundFade.setAttribute("height", Math.ceil(tabPreviews.height * .25) + 1);
|
||||
groundFade.setAttribute("y", tabPreviews.height + 1);
|
||||
}
|
||||
|
||||
this.svgRoot = document.getElementById("ctrlTab-svgRoot");
|
||||
this.svgRoot.setAttribute("height", tabPreviews.height * 1.25 + 2);
|
||||
return this.svgRoot;
|
||||
},
|
||||
get container () {
|
||||
delete this.container;
|
||||
return this.container = document.getElementById("ctrlTab-container");
|
||||
},
|
||||
get rtl () {
|
||||
delete this.rtl;
|
||||
return this.rtl = getComputedStyle(this.panel, "").direction == "rtl";
|
||||
},
|
||||
get iconSize () {
|
||||
delete this.iconSize;
|
||||
return this.iconSize = Math.round(tabPreviews.height / 4);
|
||||
},
|
||||
get smoothScroll () {
|
||||
delete this.smoothScroll;
|
||||
return this.smoothScroll = gPrefService.getBoolPref("browser.ctrlTab.smoothScroll");
|
||||
},
|
||||
get previewsCount () {
|
||||
delete this.previewsCount;
|
||||
return this.previewsCount = Math.max(gPrefService.getIntPref("browser.ctrlTab.previewsCount"), 3);
|
||||
},
|
||||
get visibleCount () {
|
||||
return Math.min(this.previewsCount, this.tabs.length);
|
||||
},
|
||||
get offscreenStart () {
|
||||
return Array.indexOf(this.container.childNodes, this.selected) - 1;
|
||||
},
|
||||
get offscreenEnd () {
|
||||
return this.container.childNodes.length - this.visibleCount - this.offscreenStart;
|
||||
},
|
||||
get offsetX () {
|
||||
return - tabPreviews.width * (this.rtl ? this.offscreenEnd : this.offscreenStart);
|
||||
},
|
||||
init: function () {
|
||||
var tabContainer = gBrowser.tabContainer;
|
||||
|
||||
Array.forEach(tabContainer.childNodes, function (tab) {
|
||||
this.attachTab(tab, tab == gBrowser.selectedTab);
|
||||
}, this);
|
||||
|
||||
tabContainer.addEventListener("TabOpen", this, false);
|
||||
tabContainer.addEventListener("TabSelect", this, false);
|
||||
tabContainer.addEventListener("TabClose", this, false);
|
||||
|
||||
gBrowser.mTabBox.handleCtrlTab = false;
|
||||
window.addEventListener("keydown", this, true);
|
||||
},
|
||||
uninit: function () {
|
||||
var tabContainer = gBrowser.tabContainer;
|
||||
tabContainer.removeEventListener("TabOpen", this, false);
|
||||
tabContainer.removeEventListener("TabSelect", this, false);
|
||||
tabContainer.removeEventListener("TabClose", this, false);
|
||||
|
||||
this.panel.removeEventListener("popuphiding", this, false);
|
||||
window.removeEventListener("keydown", this, true);
|
||||
},
|
||||
addBox: function (aAtStart) {
|
||||
const SVGNS = "http://www.w3.org/2000/svg";
|
||||
|
||||
var thumbnail = document.createElementNS(SVGNS, "image");
|
||||
thumbnail.setAttribute("class", "ctrlTab-thumbnail");
|
||||
thumbnail.setAttribute("height", tabPreviews.height);
|
||||
thumbnail.setAttribute("width", tabPreviews.width);
|
||||
|
||||
var thumbnail_border = document.createElementNS(SVGNS, "rect");
|
||||
thumbnail_border.setAttribute("class", "ctrlTab-thumbnailborder");
|
||||
thumbnail_border.setAttribute("height", tabPreviews.height);
|
||||
thumbnail_border.setAttribute("width", tabPreviews.width);
|
||||
|
||||
var icon = document.createElementNS(SVGNS, "image");
|
||||
icon.setAttribute("class", "ctrlTab-icon");
|
||||
icon.setAttribute("height", this.iconSize);
|
||||
icon.setAttribute("width", this.iconSize);
|
||||
icon.setAttribute("transform", "skewY(10)");
|
||||
icon.setAttribute("x", - this.iconSize / 3);
|
||||
icon.setAttribute("y", tabPreviews.height * .9 - this.iconSize);
|
||||
|
||||
var thumbnail_and_icon = document.createElementNS(SVGNS, "g");
|
||||
thumbnail_and_icon.appendChild(thumbnail);
|
||||
thumbnail_and_icon.appendChild(thumbnail_border);
|
||||
thumbnail_and_icon.appendChild(icon);
|
||||
|
||||
var reflection = document.createElementNS(SVGNS, "use");
|
||||
reflection.setAttribute("class", "ctrlTab-reflection");
|
||||
var ref_scale = .5;
|
||||
reflection.setAttribute("transform", "scale(1,-" + ref_scale + ")");
|
||||
reflection.setAttribute("y", - ((1 / ref_scale + 1) * tabPreviews.height +
|
||||
(1 / ref_scale) * 2));
|
||||
|
||||
var box = document.createElementNS(SVGNS, "g");
|
||||
box.setAttribute("class", "ctrlTab-box");
|
||||
box.appendChild(thumbnail_and_icon);
|
||||
box.appendChild(reflection);
|
||||
|
||||
if (aAtStart)
|
||||
this.container.insertBefore(box, this.container.firstChild);
|
||||
else
|
||||
this.container.appendChild(box);
|
||||
return box;
|
||||
},
|
||||
removeBox: function (aBox) {
|
||||
this.container.removeChild(aBox);
|
||||
if (!Array.some(this.container.childNodes, function (box) box._tab == aBox._tab))
|
||||
aBox._tab.removeEventListener("DOMAttrModified", this, false);
|
||||
aBox._tab = null;
|
||||
},
|
||||
addPreview: function (aBox, aTab) {
|
||||
const XLinkNS = "http://www.w3.org/1999/xlink";
|
||||
|
||||
aBox._tab = aTab;
|
||||
let (thumbnail = aBox.firstChild.firstChild)
|
||||
thumbnail.setAttributeNS(XLinkNS, "href", tabPreviews.get(aTab));
|
||||
this.updateIcon(aBox);
|
||||
|
||||
aTab.addEventListener("DOMAttrModified", this, false);
|
||||
|
||||
if (!aBox.firstChild.hasAttribute("id")) {
|
||||
// set up reflection
|
||||
this._uniqid++;
|
||||
aBox.firstChild.setAttribute("id", "ctrlTab-preview-" + this._uniqid);
|
||||
aBox.lastChild.setAttributeNS(XLinkNS, "href", "#ctrlTab-preview-" + this._uniqid);
|
||||
}
|
||||
},
|
||||
updateIcon: function (aBox) {
|
||||
const XLinkNS = "http://www.w3.org/1999/xlink";
|
||||
var url = aBox._tab.hasAttribute("busy") ?
|
||||
"chrome://global/skin/icons/loading_16.png" :
|
||||
aBox._tab.getAttribute("image");
|
||||
var icon = aBox.firstChild.lastChild;
|
||||
if (url)
|
||||
icon.setAttributeNS(XLinkNS, "href", url);
|
||||
else
|
||||
icon.removeAttributeNS(XLinkNS, "href");
|
||||
},
|
||||
tabAttrModified: function (aTab, aAttrName) {
|
||||
switch (aAttrName) {
|
||||
case "busy":
|
||||
case "image":
|
||||
Array.forEach(this.container.childNodes, function (box) {
|
||||
if (box._tab == aTab) {
|
||||
if (aAttrName == "busy")
|
||||
this.addPreview(box, aTab);
|
||||
else
|
||||
this.updateIcon(box);
|
||||
}
|
||||
}, this);
|
||||
break;
|
||||
case "label":
|
||||
case "crop":
|
||||
if (!this._scrollTimer) {
|
||||
let boxes = this.container.childNodes;
|
||||
for (let i = boxes.length - 1; i >= 0; i--) {
|
||||
if (boxes[i]._tab == aTab && boxes[i] == this.selected) {
|
||||
this.label[aAttrName == "label" ? "value" : aAttrName] =
|
||||
aTab.getAttribute(aAttrName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
scroll: function () {
|
||||
if (!this.smoothScroll) {
|
||||
this._move = true;
|
||||
this.stopScroll();
|
||||
return;
|
||||
}
|
||||
|
||||
this.stopScroll();
|
||||
this._move = true;
|
||||
let (next = this.invertDirection ? this.selected.previousSibling : this.selected.nextSibling) {
|
||||
this.setStatusbarValue(next);
|
||||
this.label.value = next._tab.label;
|
||||
this.label.crop = next._tab.crop;
|
||||
}
|
||||
|
||||
const FRAME_LENGTH = 40;
|
||||
var x = this.offsetX;
|
||||
var scrollAmounts = let (tenth = tabPreviews.width / (this.invertDirection == this.rtl ? -10 : 10))
|
||||
[3 * tenth, 4 * tenth, 2 * tenth, tenth];
|
||||
|
||||
function processFrame(self, lateness) {
|
||||
lateness += FRAME_LENGTH / 2;
|
||||
do {
|
||||
x += scrollAmounts.shift();
|
||||
lateness -= FRAME_LENGTH;
|
||||
} while (lateness > 0 && scrollAmounts.length);
|
||||
self.container.setAttribute("transform", "translate("+ x +",0)");
|
||||
self.svgRoot.forceRedraw();
|
||||
if (!scrollAmounts.length)
|
||||
self.stopScroll();
|
||||
}
|
||||
|
||||
this._scrollTimer = setInterval(processFrame, FRAME_LENGTH, this);
|
||||
processFrame(this, 0);
|
||||
},
|
||||
stopScroll: function () {
|
||||
if (this._scrollTimer) {
|
||||
clearInterval(this._scrollTimer);
|
||||
this._scrollTimer = 0;
|
||||
}
|
||||
if (this._move)
|
||||
this.updateSelected();
|
||||
},
|
||||
updateSelected: function (aClosing) {
|
||||
var index = 1;
|
||||
if (this._move) {
|
||||
this._move = false;
|
||||
index += this.invertDirection ? -1 : 1;
|
||||
}
|
||||
if (this.selected) {
|
||||
index += this.offscreenStart + this.tabs.length;
|
||||
index %= this.tabs.length;
|
||||
if (index < 2)
|
||||
index += this.tabs.length;
|
||||
if (index > this.container.childNodes.length - this.visibleCount + 1)
|
||||
index -= this.tabs.length;
|
||||
}
|
||||
this.selected = this.container.childNodes[index];
|
||||
|
||||
if (aClosing)
|
||||
return;
|
||||
|
||||
this.addOffscreenBox(this.invertDirection);
|
||||
this.addOffscreenBox(!this.invertDirection);
|
||||
|
||||
// having lots of off-screen boxes reduce the scrolling speed, remove some
|
||||
for (let i = this.offscreenStart; i > 1; i--)
|
||||
this.removeBox(this.container.firstChild);
|
||||
for (let i = this.offscreenEnd; i > 1; i--)
|
||||
this.removeBox(this.container.lastChild);
|
||||
|
||||
this.container.setAttribute("transform", "translate("+ this.offsetX +", 0)");
|
||||
|
||||
for (let i = 0, l = this.container.childNodes.length; i < l; i++)
|
||||
this.arrange(i);
|
||||
},
|
||||
addOffscreenBox: function (aAtStart) {
|
||||
if (this.container.childNodes.length < this.tabs.length + this.visibleCount + 1 &&
|
||||
!(aAtStart ? this.offscreenStart : this.offscreenEnd)) {
|
||||
let i = aAtStart ?
|
||||
this.tabs.indexOf(this.container.firstChild._tab) - 1:
|
||||
this.tabs.indexOf(this.container.lastChild._tab) + 1;
|
||||
i = (i + this.tabs.length) % this.tabs.length;
|
||||
this.addPreview(this.addBox(aAtStart), this.tabs[i]);
|
||||
}
|
||||
},
|
||||
arrange: function (aIndex) {
|
||||
var box = this.container.childNodes[aIndex];
|
||||
var selected = box == this.selected;
|
||||
if (selected) {
|
||||
box.setAttribute("selected", "true");
|
||||
this.setStatusbarValue(box);
|
||||
this.label.value = box._tab.label;
|
||||
this.label.crop = box._tab.crop;
|
||||
} else {
|
||||
box.removeAttribute("selected");
|
||||
}
|
||||
var scale = selected ? 1 : .75;
|
||||
var pos = this.rtl ? this.container.childNodes.length - 1 - aIndex : aIndex;
|
||||
var trans_x = tabPreviews.width * (pos + (1 - scale) / 2) / scale;
|
||||
var trans_y = (tabPreviews.height + 1) * (1 / scale - 1);
|
||||
box.setAttribute("transform", "scale(" + scale + "," + scale + ") " +
|
||||
"translate("+ trans_x + "," + trans_y + ")");
|
||||
},
|
||||
setStatusbarValue: function (aBox) {
|
||||
var value = "";
|
||||
if (aBox) {
|
||||
value = aBox._tab.linkedBrowser.currentURI.spec;
|
||||
if (value == "about:blank") {
|
||||
// XXXhack: Passing a space here (and not "")
|
||||
// to make sure the browser implementation would
|
||||
// still consider it a hovered link.
|
||||
value = " ";
|
||||
} else {
|
||||
try {
|
||||
value = decodeURI(value);
|
||||
} catch (e) {}
|
||||
}
|
||||
}
|
||||
XULBrowserWindow.setOverLink(value, null);
|
||||
},
|
||||
attachTab: function (aTab, aSelected) {
|
||||
if (aSelected)
|
||||
this.tabs.unshift(aTab);
|
||||
else
|
||||
this.tabs.push(aTab);
|
||||
},
|
||||
detachTab: function (aTab) {
|
||||
var i = this.tabs.indexOf(aTab);
|
||||
if (i >= 0)
|
||||
this.tabs.splice(i, 1);
|
||||
},
|
||||
open: function () {
|
||||
window.addEventListener("keyup", this, true);
|
||||
window.addEventListener("keypress", this, true);
|
||||
this.panel.addEventListener("popuphiding", this, false);
|
||||
this.panel.hidden = false;
|
||||
this.panel.width = tabPreviews.width * this.visibleCount;
|
||||
this.panel.openPopupAtScreen(screen.availLeft + (screen.availWidth - this.panel.width) / 2,
|
||||
screen.availTop + (screen.availHeight - this.svgRoot.getAttribute("height")) / 2,
|
||||
false);
|
||||
|
||||
for (let index = this.invertDirection ? this.tabs.length - 2 : 0,
|
||||
i = this.visibleCount; i > 0; i--)
|
||||
this.addPreview(this.addBox(), this.tabs[index++ % this.tabs.length]);
|
||||
this.updateSelected();
|
||||
},
|
||||
onKeyDown: function (event) {
|
||||
var isOpen = this.panel.state == "open" || this.panel.state == "showing";
|
||||
var propagate = !isOpen;
|
||||
switch (event.keyCode) {
|
||||
case event.DOM_VK_TAB:
|
||||
if (event.ctrlKey && !event.altKey && !event.metaKey && this.tabs.length > 1) {
|
||||
propagate = false;
|
||||
this.invertDirection = event.shiftKey;
|
||||
if (isOpen)
|
||||
this.scroll();
|
||||
else if (this.tabs.length == 2)
|
||||
gBrowser.selectedTab = this.tabs[1];
|
||||
else
|
||||
this.open();
|
||||
}
|
||||
break;
|
||||
case event.DOM_VK_ESCAPE:
|
||||
if (isOpen)
|
||||
this.panel.hidePopup();
|
||||
break;
|
||||
}
|
||||
if (!propagate) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
}
|
||||
},
|
||||
onKeyUp: function (event) {
|
||||
if (event.keyCode == event.DOM_VK_CONTROL) {
|
||||
if (this._move)
|
||||
this.updateSelected(true);
|
||||
let selectedTab = this.selected._tab;
|
||||
this.panel.hidePopup();
|
||||
gBrowser.selectedTab = selectedTab;
|
||||
}
|
||||
},
|
||||
onPopupHiding: function () {
|
||||
this.stopScroll();
|
||||
window.removeEventListener("keyup", this, true);
|
||||
window.removeEventListener("keypress", this, true);
|
||||
while (this.container.childNodes.length)
|
||||
this.removeBox(this.container.lastChild);
|
||||
this.selected = null;
|
||||
this.invertDirection = false;
|
||||
this._move = false;
|
||||
this._uniqid = 0;
|
||||
this.label.value = "";
|
||||
this.setStatusbarValue();
|
||||
this.container.removeAttribute("transform");
|
||||
this.svgRoot.forceRedraw();
|
||||
},
|
||||
handleEvent: function (event) {
|
||||
switch (event.type) {
|
||||
case "DOMAttrModified":
|
||||
this.tabAttrModified(event.target, event.attrName);
|
||||
break;
|
||||
case "TabSelect":
|
||||
this.detachTab(event.target);
|
||||
this.attachTab(event.target, true);
|
||||
break;
|
||||
case "TabOpen":
|
||||
this.attachTab(event.target);
|
||||
break;
|
||||
case "TabClose":
|
||||
this.detachTab(event.target);
|
||||
break;
|
||||
case "keydown":
|
||||
this.onKeyDown(event);
|
||||
break;
|
||||
case "keyup":
|
||||
case "keypress":
|
||||
// the panel is open; don't propagate any key events
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
case "keyup":
|
||||
this.onKeyUp(event);
|
||||
break;
|
||||
case "popuphiding":
|
||||
this.onPopupHiding();
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
|
@ -1,3 +1,7 @@
|
|||
@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
|
||||
@namespace svg url("http://www.w3.org/2000/svg");
|
||||
@namespace xlink url("http://www.w3.org/1999/xlink");
|
||||
|
||||
searchbar {
|
||||
-moz-binding: url("chrome://browser/content/search/search.xml#searchbar");
|
||||
}
|
||||
|
@ -82,3 +86,17 @@ window[chromehidden~="toolbar"] toolbar:not(.toolbar-primary):not(.chromeclass-m
|
|||
#navigator-toolbox[inFullscreen="true"] #fullscr-toggler {
|
||||
display: -moz-box;
|
||||
}
|
||||
|
||||
/* Tab Previews */
|
||||
svg|*.ctrlTab-icon:not([xlink|href]) ,
|
||||
svg|*.ctrlTab-thumbnail:not([xlink|href]) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
svg|*.ctrlTab-thumbnailborder {
|
||||
fill: transparent;
|
||||
}
|
||||
|
||||
svg|*.ctrlTab-icon {
|
||||
filter: url(chrome://browser/content/browser.xul#ctrlTab-iconShadow);
|
||||
}
|
||||
|
|
|
@ -1074,6 +1074,9 @@ function delayedStartup()
|
|||
// themselves.
|
||||
gBrowser.addEventListener("command", BrowserOnCommand, false);
|
||||
|
||||
tabPreviews.init();
|
||||
ctrlTab.init();
|
||||
|
||||
// Delayed initialization of the livemarks update timer.
|
||||
// Livemark updates don't need to start until after bookmark UI
|
||||
// such as the toolbar has initialized. Starting 5 seconds after
|
||||
|
@ -1104,6 +1107,9 @@ function delayedStartup()
|
|||
|
||||
function BrowserShutdown()
|
||||
{
|
||||
tabPreviews.uninit();
|
||||
ctrlTab.uninit();
|
||||
|
||||
try {
|
||||
FullZoom.destroy();
|
||||
}
|
||||
|
@ -6139,6 +6145,8 @@ var FeedHandler = {
|
|||
|
||||
#include browser-textZoom.js
|
||||
|
||||
#include browser-tabPreviews.js
|
||||
|
||||
HistoryMenu.toggleRecentlyClosedTabs = function PHM_toggleRecentlyClosedTabs() {
|
||||
// enable/disable the Recently Closed Tabs sub menu
|
||||
var undoPopup = document.getElementById("historyUndoPopup");
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
# Pierre Chanial <chanial@noos.fr>
|
||||
# Dean Tessman <dean_tessman@hotmail.com>
|
||||
# Johnathan Nightingale <johnath@mozilla.com>
|
||||
# Dão Gottwald <dao@mozilla.com>
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
|
@ -61,6 +62,7 @@
|
|||
|
||||
<window id="main-window"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
onload="BrowserStartup()" onunload="BrowserShutdown()" onclose="return WindowIsClosing();"
|
||||
contenttitlesetting="true"
|
||||
|
@ -227,6 +229,29 @@
|
|||
<tooltip id="urlTooltip">
|
||||
<label crop="center" flex="1"/>
|
||||
</tooltip>
|
||||
|
||||
<panel id="ctrlTab-panel" class="KUI-panel" hidden="true">
|
||||
<label id="ctrlTab-label" flex="1"/>
|
||||
<svg:svg id="ctrlTab-svgRoot">
|
||||
<svg:defs>
|
||||
<svg:linearGradient id="ctrlTab-fadeGradient" x1="1" y1="1" x2="1" y2="0">
|
||||
<svg:stop id="ctrlTab-fadeGradientBottom" offset="0"/>
|
||||
<svg:stop id="ctrlTab-fadeGradientTop" offset="1"/>
|
||||
</svg:linearGradient>
|
||||
<svg:filter id="ctrlTab-iconShadow">
|
||||
<svg:feOffset result="shadow" in="SourceAlpha" dx="2" dy="-1"/>
|
||||
<svg:feColorMatrix result="transparent-shadow" in="shadow"
|
||||
values="1 0 0 0 0
|
||||
0 1 0 0 0
|
||||
0 0 1 0 0
|
||||
0 0 0 0.5 0"/>
|
||||
<svg:feBlend in="SourceGraphic" in2="transparent-shadow"/>
|
||||
</svg:filter>
|
||||
</svg:defs>
|
||||
<svg:g id="ctrlTab-container"/>
|
||||
<svg:rect id="ctrlTab-groundFade" fill="url(#ctrlTab-fadeGradient)" width="100%"/>
|
||||
</svg:svg>
|
||||
</panel>
|
||||
</popupset>
|
||||
|
||||
<!-- bookmarks toolbar tooltip -->
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
* Dean Tessman (dean_tessman@hotmail.com)
|
||||
* Blake Ross (blake@cs.stanford.edu)
|
||||
* Pamela Greene (pamg.bugs@gmail.com)
|
||||
* Dao Gottwald (dao@design-noir.de)
|
||||
* Dão Gottwald (dao@mozilla.com)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
|
@ -47,6 +47,7 @@
|
|||
|
||||
@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
|
||||
@namespace html url("http://www.w3.org/1999/xhtml");
|
||||
@namespace svg url("http://www.w3.org/2000/svg");
|
||||
|
||||
#menubar-items {
|
||||
-moz-box-orient: vertical; /* for flex hack */
|
||||
|
@ -1395,3 +1396,26 @@ toolbar[mode="text"] > #window-controls > toolbarbutton > .toolbarbutton-text {
|
|||
list-style-image: url("chrome://browser/skin/Toolbar-small.png");
|
||||
-moz-image-region: rect(0px 16px 16px 0px);
|
||||
}
|
||||
|
||||
/* ::::: Ctrl-Tab Panel ::::: */
|
||||
#ctrlTab-label {
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
margin-top: .5em;
|
||||
margin-bottom: .7em;
|
||||
}
|
||||
|
||||
svg|*.ctrlTab-thumbnailborder {
|
||||
stroke: ThreeDDarkShadow;
|
||||
stroke-width: .7px;
|
||||
}
|
||||
|
||||
svg|*#ctrlTab-fadeGradientTop {
|
||||
stop-color: ThreeDShadow;
|
||||
stop-opacity: .75;
|
||||
}
|
||||
|
||||
svg|*#ctrlTab-fadeGradientBottom {
|
||||
stop-color: -moz-dialog;
|
||||
stop-opacity: 1;
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
* Pierre Chanial (chanial@noos.fr)
|
||||
* Kevin Gerich (kevin@kmgerich.com)
|
||||
* Pamela Greene (pamg.bugs@gmail.com)
|
||||
* Dao Gottwald (dao@design-noir.de)
|
||||
* Dão Gottwald (dao@mozilla.com)
|
||||
* Stephen Horlander (stephen@noved.org)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
|
@ -45,6 +45,7 @@
|
|||
|
||||
@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
|
||||
@namespace html url("http://www.w3.org/1999/xhtml");
|
||||
@namespace svg url("http://www.w3.org/2000/svg");
|
||||
|
||||
#main-window {
|
||||
-moz-binding: url("chrome://global/skin/globalBindings.xml#unifiedWindow");
|
||||
|
@ -2262,3 +2263,48 @@ tabpanels.plain {
|
|||
#download-monitor {
|
||||
list-style-image: url("chrome://mozapps/skin/downloads/downloadStatusIcon.png");
|
||||
}
|
||||
|
||||
/* ::::: Keyboard UI Panel ::::: */
|
||||
.KUI-panel {
|
||||
-moz-appearance: none;
|
||||
background: rgba(0, 0, 0, .8);
|
||||
color: white;
|
||||
border: 3px solid #ccc;
|
||||
-moz-border-top-colors: #ccc #ccc black;
|
||||
-moz-border-right-colors: #ccc #ccc black;
|
||||
-moz-border-bottom-colors: #ccc #ccc black;
|
||||
-moz-border-left-colors: #ccc #ccc black;
|
||||
-moz-border-radius: 10px;
|
||||
margin-top: -3px;
|
||||
margin-left: -3px;
|
||||
}
|
||||
|
||||
/* ::::: Ctrl-Tab Panel ::::: */
|
||||
#ctrlTab-panel {
|
||||
margin-top: -18px;
|
||||
border-bottom-width: 5px;
|
||||
-moz-border-bottom-colors: #ccc #ccc black black black;
|
||||
}
|
||||
|
||||
#ctrlTab-label {
|
||||
font-weight: bold;
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
margin-top: 6px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
svg|*.ctrlTab-thumbnailborder {
|
||||
stroke: white;
|
||||
stroke-width: 1px;
|
||||
}
|
||||
|
||||
svg|*#ctrlTab-fadeGradientTop {
|
||||
stop-color: black;
|
||||
stop-opacity: .5;
|
||||
}
|
||||
|
||||
svg|*#ctrlTab-fadeGradientBottom {
|
||||
stop-color: black;
|
||||
stop-opacity: 1;
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
* Dean Tessman (dean_tessman@hotmail.com)
|
||||
* Blake Ross (blake@cs.stanford.edu)
|
||||
* Pamela Greene (pamg.bugs@gmail.com)
|
||||
* Dao Gottwald (dao@design-noir.de)
|
||||
* Dão Gottwald (dao@mozilla.com)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
|
@ -45,6 +45,7 @@
|
|||
|
||||
@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
|
||||
@namespace html url("http://www.w3.org/1999/xhtml");
|
||||
@namespace svg url("http://www.w3.org/2000/svg");
|
||||
|
||||
#menubar-items {
|
||||
-moz-box-orient: vertical; /* for flex hack */
|
||||
|
@ -2058,3 +2059,48 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] {
|
|||
#nav-bar[iconsize="large"][mode="icons"][currentset$=",search-container"]:-moz-system-metric(windows-default-theme) {
|
||||
-moz-padding-end: 3px;
|
||||
}
|
||||
|
||||
/* ::::: Keyboard UI Panel ::::: */
|
||||
.KUI-panel {
|
||||
-moz-appearance: none;
|
||||
background: rgba(0, 0, 0, .8);
|
||||
color: white;
|
||||
border: 3px solid #ccc;
|
||||
-moz-border-top-colors: #ccc #ccc black;
|
||||
-moz-border-right-colors: #ccc #ccc black;
|
||||
-moz-border-bottom-colors: #ccc #ccc black;
|
||||
-moz-border-left-colors: #ccc #ccc black;
|
||||
-moz-border-radius: 10px;
|
||||
margin-top: -3px;
|
||||
margin-left: -3px;
|
||||
}
|
||||
|
||||
/* ::::: Ctrl-Tab Panel ::::: */
|
||||
#ctrlTab-panel {
|
||||
margin-top: -18px;
|
||||
border-bottom-width: 5px;
|
||||
-moz-border-bottom-colors: #ccc #ccc black black black;
|
||||
}
|
||||
|
||||
#ctrlTab-label {
|
||||
font-weight: bold;
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
margin-top: 6px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
svg|*.ctrlTab-thumbnailborder {
|
||||
stroke: white;
|
||||
stroke-width: 1px;
|
||||
}
|
||||
|
||||
svg|*#ctrlTab-fadeGradientTop {
|
||||
stop-color: black;
|
||||
stop-opacity: .5;
|
||||
}
|
||||
|
||||
svg|*#ctrlTab-fadeGradientBottom {
|
||||
stop-color: black;
|
||||
stop-opacity: 1;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче