mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-11 04:15:43 +00:00
Bug 456088 - Ctrl+Tab revision. r=connor
This commit is contained in:
parent
4678fd9496
commit
f3bd9d7262
@ -341,7 +341,6 @@ pref("browser.tabs.selectOwnerOnClose", true);
|
||||
|
||||
pref("browser.ctrlTab.mostRecentlyUsed", true);
|
||||
pref("browser.ctrlTab.recentlyUsedLimit", 7);
|
||||
pref("browser.ctrlTab.smoothScroll", true);
|
||||
|
||||
// Default bookmark sorting
|
||||
pref("browser.bookmarks.sort.direction", "descending");
|
||||
|
@ -77,12 +77,11 @@ var tabPreviews = {
|
||||
ctx.drawWindow(win, win.scrollX, win.scrollY,
|
||||
snippetWidth, snippetWidth * this.aspectRatio, "rgb(255,255,255)");
|
||||
|
||||
var data = thumbnail.toDataURL("image/jpeg", "quality=60");
|
||||
if (aStore) {
|
||||
aTab.__thumbnail = data;
|
||||
aTab.__thumbnail = thumbnail;
|
||||
aTab.__thumbnail_lastURI = aTab.linkedBrowser.currentURI.spec;
|
||||
}
|
||||
return data;
|
||||
return thumbnail;
|
||||
},
|
||||
handleEvent: function (event) {
|
||||
switch (event.type) {
|
||||
@ -114,8 +113,6 @@ var tabPreviews = {
|
||||
* Ctrl-Tab panel
|
||||
*/
|
||||
var ctrlTab = {
|
||||
visibleCount: 3,
|
||||
_uniqid: 0,
|
||||
get panel () {
|
||||
delete this.panel;
|
||||
return this.panel = document.getElementById("ctrlTab-panel");
|
||||
@ -124,29 +121,18 @@ var ctrlTab = {
|
||||
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 pagesBar () {
|
||||
delete this.pagesBar;
|
||||
return this.pagesBar = document.getElementById("ctrlTab-pages");
|
||||
},
|
||||
get container () {
|
||||
delete this.container;
|
||||
return this.container = document.getElementById("ctrlTab-container");
|
||||
get thumbnails () {
|
||||
delete this.thumbnails;
|
||||
return this.thumbnails = this.panel.getElementsByClassName("ctrlTab-thumbnail");
|
||||
},
|
||||
get rtl () {
|
||||
delete this.rtl;
|
||||
return this.rtl = getComputedStyle(this.panel, "").direction == "rtl";
|
||||
},
|
||||
get iconSize () {
|
||||
delete this.iconSize;
|
||||
return this.iconSize = Math.max(16, Math.round(tabPreviews.height / 5));
|
||||
get columns () {
|
||||
delete this.columns;
|
||||
return this.columns = this.thumbnails.length /
|
||||
this.panel.getElementsByClassName("ctrlTab-row").length;
|
||||
},
|
||||
get closeCharCode () {
|
||||
delete this.closeCharCode;
|
||||
@ -158,24 +144,43 @@ var ctrlTab = {
|
||||
delete this.recentlyUsedLimit;
|
||||
return this.recentlyUsedLimit = gPrefService.getIntPref("browser.ctrlTab.recentlyUsedLimit");
|
||||
},
|
||||
get smoothScroll () {
|
||||
delete this.smoothScroll;
|
||||
return this.smoothScroll = gPrefService.getBoolPref("browser.ctrlTab.smoothScroll");
|
||||
selectedIndex: 0,
|
||||
get selected () this.thumbnails.item(this.selectedIndex),
|
||||
get isOpen () this.panel.state == "open" || this.panel.state == "showing",
|
||||
get tabCount () gBrowser.mTabs.length - (this._closing ? 1 : 0),
|
||||
get pages () Math.ceil(this.tabCount / this.thumbnails.length),
|
||||
get page () this._page || 0,
|
||||
set page (page) {
|
||||
if (page < 0)
|
||||
page = this.pages - 1;
|
||||
else if (page >= this.pages)
|
||||
page = 0;
|
||||
|
||||
if (this.pagesBar.childNodes.length) {
|
||||
this.pagesBar.childNodes[this.page].removeAttribute("selected");
|
||||
this.pagesBar.childNodes[page].setAttribute("selected", "true");
|
||||
}
|
||||
|
||||
this._page = page;
|
||||
this.updatePreviews();
|
||||
return page;
|
||||
},
|
||||
get tabCount () {
|
||||
return gBrowser.mTabs.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);
|
||||
},
|
||||
get isOpen () {
|
||||
return this.panel.state == "open" || this.panel.state == "showing";
|
||||
get tabList () {
|
||||
var list = Array.slice(gBrowser.mTabs);
|
||||
if (this._closing)
|
||||
this.detachTab(this._closing, list);
|
||||
for (let i = 0; i < gBrowser.tabContainer.selectedIndex; i++)
|
||||
list.push(list.shift());
|
||||
if (!this._useTabBarOrder && this.recentlyUsedLimit != 0) {
|
||||
let recentlyUsedTabs = this._recentlyUsedTabs;
|
||||
if (this.recentlyUsedLimit > 0)
|
||||
recentlyUsedTabs = this._recentlyUsedTabs.slice(0, this.recentlyUsedLimit);
|
||||
for (let i = recentlyUsedTabs.length - 1; i >= 0; i--) {
|
||||
list.splice(list.indexOf(recentlyUsedTabs[i]), 1);
|
||||
list.unshift(recentlyUsedTabs[i]);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
},
|
||||
init: function () {
|
||||
if (this._recentlyUsedTabs)
|
||||
@ -200,246 +205,128 @@ var ctrlTab = {
|
||||
|
||||
this.panel.removeEventListener("popuphiding", this, false);
|
||||
document.removeEventListener("keypress", this, false);
|
||||
gBrowser.mTabBox.handleCtrlTab = 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("x", - this.iconSize * .2);
|
||||
icon.setAttribute("y", tabPreviews.height - this.iconSize * 1.2);
|
||||
|
||||
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.setAttribute("onclick", "ctrlTab.pick(this);");
|
||||
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);
|
||||
buildPagesBar: function () {
|
||||
var pages = this.pages;
|
||||
if (pages == 1)
|
||||
pages = 0;
|
||||
while (this.pagesBar.childNodes.length > pages)
|
||||
this.pagesBar.removeChild(this.pagesBar.lastChild);
|
||||
while (this.pagesBar.childNodes.length < pages) {
|
||||
let pointer = document.createElement("spacer");
|
||||
pointer.setAttribute("onclick", "ctrlTab.goToPage(" + this.pagesBar.childNodes.length + ");");
|
||||
pointer.setAttribute("class", "ctrlTab-pagePointer");
|
||||
this.pagesBar.appendChild(pointer);
|
||||
}
|
||||
},
|
||||
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");
|
||||
goToPage: function (aPage, aIndex) {
|
||||
if (this.page != aPage)
|
||||
this.page = aPage;
|
||||
this.selected.removeAttribute("selected");
|
||||
if (aIndex) {
|
||||
this.selectedIndex = aIndex;
|
||||
while (!this.selected || !this.selected.hasAttribute("valid"))
|
||||
this.selectedIndex--;
|
||||
} else {
|
||||
this.selectedIndex = 0;
|
||||
}
|
||||
this.updateSelected();
|
||||
},
|
||||
updatePreviews: function () {
|
||||
var tabs = this.tabList;
|
||||
var offset = this.page * this.thumbnails.length;
|
||||
for (let i = 0; i < this.thumbnails.length; i++)
|
||||
this.updatePreview(this.thumbnails[i], tabs[i + offset]);
|
||||
},
|
||||
updatePreview: function (aThumbnail, aTab) {
|
||||
do {
|
||||
if (aThumbnail._tab) {
|
||||
if (aThumbnail._tab == aTab)
|
||||
break;
|
||||
aThumbnail._tab.removeEventListener("DOMAttrModified", this, false);
|
||||
}
|
||||
aThumbnail._tab = aTab;
|
||||
if (aTab)
|
||||
aTab.addEventListener("DOMAttrModified", this, false);
|
||||
} while (false);
|
||||
|
||||
if (aThumbnail.firstChild)
|
||||
aThumbnail.removeChild(aThumbnail.firstChild);
|
||||
if (aTab) {
|
||||
aThumbnail.appendChild(tabPreviews.get(aTab));
|
||||
aThumbnail.setAttribute("valid", "true");
|
||||
} else {
|
||||
aThumbnail.removeAttribute("valid");
|
||||
}
|
||||
aThumbnail.width = tabPreviews.width;
|
||||
aThumbnail.height = tabPreviews.height;
|
||||
},
|
||||
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;
|
||||
}
|
||||
for (let i = this.thumbnails.length - 1; i >= 0; i--) {
|
||||
if (this.thumbnails[i]._tab == aTab) {
|
||||
this.updatePreview(this.thumbnails[i], aTab);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
scroll: function () {
|
||||
if (!this.smoothScroll) {
|
||||
this.advanceSelected();
|
||||
this.arrangeBoxes();
|
||||
return;
|
||||
}
|
||||
|
||||
this.stopScroll();
|
||||
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;
|
||||
this.advanceSelected();
|
||||
this.arrangeBoxes();
|
||||
case "label":
|
||||
case "crop":
|
||||
if (this.selected._tab == aTab)
|
||||
this.label[aAttrName == "label" ? "value" : aAttrName] = aTab[aAttrName];
|
||||
break;
|
||||
}
|
||||
},
|
||||
advanceSelected: function () {
|
||||
// regardless of visibleCount, the new highlighted tab will be
|
||||
// the first or third-visible tab, depending on whether Shift is pressed
|
||||
var index = ((this.invertDirection ? 0 : 2) + this.offscreenStart + this.tabCount)
|
||||
% this.tabCount;
|
||||
if (index < 2)
|
||||
index += this.tabCount;
|
||||
if (index > this.container.childNodes.length - this.visibleCount + 1)
|
||||
index -= this.tabCount;
|
||||
this.selected = this.container.childNodes[index];
|
||||
},
|
||||
arrangeBoxes: function () {
|
||||
this.addOffscreenBox(this.invertDirection);
|
||||
this.addOffscreenBox(!this.invertDirection);
|
||||
this.selected.removeAttribute("selected");
|
||||
|
||||
// having lots of off-screen boxes reduces 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.tabCount + this.visibleCount + 1 &&
|
||||
!(aAtStart ? this.offscreenStart : this.offscreenEnd)) {
|
||||
let tabs = this.getTabList();
|
||||
let i = aAtStart ?
|
||||
tabs.indexOf(this.container.firstChild._tab) - 1:
|
||||
tabs.indexOf(this.container.lastChild._tab) + 1;
|
||||
i = (i + tabs.length) % tabs.length;
|
||||
this.addPreview(this.addBox(aAtStart), tabs[i]);
|
||||
this.selectedIndex += this.invertDirection ? -1 : 1;
|
||||
if (this.selectedIndex < 0) {
|
||||
this.page--;
|
||||
this.selectedIndex = this.thumbnails.length - 1;
|
||||
while (!this.selected.hasAttribute("valid"))
|
||||
this.selectedIndex--;
|
||||
} else if (this.selectedIndex >= this.thumbnails.length || !this.selected.hasAttribute("valid")) {
|
||||
this.page++;
|
||||
this.selectedIndex = 0;
|
||||
}
|
||||
this.updateSelected();
|
||||
},
|
||||
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;
|
||||
updateSelected: function () {
|
||||
var thumbnail = this.selected;
|
||||
thumbnail.setAttribute("selected", "true");
|
||||
this.label.value = thumbnail._tab.label;
|
||||
this.label.crop = thumbnail._tab.crop;
|
||||
var url = thumbnail._tab.linkedBrowser.currentURI.spec;
|
||||
if (url == "about:blank") {
|
||||
// XXXhack: Passing a space here (and not "")
|
||||
// to make sure the browser implementation would
|
||||
// still consider it a hovered link.
|
||||
url = " ";
|
||||
} else {
|
||||
box.removeAttribute("selected");
|
||||
try {
|
||||
url = decodeURI(url);
|
||||
} catch (e) {}
|
||||
}
|
||||
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 + ")");
|
||||
XULBrowserWindow.setOverLink(url, null);
|
||||
},
|
||||
pick: function (aBox) {
|
||||
this.stopScroll();
|
||||
var selectedTab = (aBox || this.selected)._tab;
|
||||
thumbnailClick: function (event) {
|
||||
switch (event.button) {
|
||||
case 0:
|
||||
this.selectThumbnail(event.currentTarget);
|
||||
break;
|
||||
case 1:
|
||||
gBrowser.removeTab(event.currentTarget._tab);
|
||||
break;
|
||||
}
|
||||
},
|
||||
selectThumbnail: function (aThumbnail) {
|
||||
var selectedTab = (aThumbnail || this.selected)._tab;
|
||||
this.panel.hidePopup();
|
||||
gBrowser.selectedTab = selectedTab;
|
||||
},
|
||||
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);
|
||||
},
|
||||
getTabList: function () {
|
||||
var list = Array.slice(gBrowser.mTabs);
|
||||
for (let i = 0; i < gBrowser.tabContainer.selectedIndex; i++)
|
||||
list.push(list.shift());
|
||||
if (!this._useTabBarOrder && this.recentlyUsedLimit > 0) {
|
||||
let recentlyUsedTabs = this._recentlyUsedTabs.slice(0, this.recentlyUsedLimit);
|
||||
for (let i = recentlyUsedTabs.length - 1; i >= 0; i--) {
|
||||
list.splice(list.indexOf(recentlyUsedTabs[i]), 1);
|
||||
list.unshift(recentlyUsedTabs[i]);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
},
|
||||
attachTab: function (aTab, aPos) {
|
||||
if (aPos == 0)
|
||||
this._recentlyUsedTabs.unshift(aTab);
|
||||
@ -448,37 +335,35 @@ var ctrlTab = {
|
||||
else
|
||||
this._recentlyUsedTabs.push(aTab);
|
||||
},
|
||||
detachTab: function (aTab) {
|
||||
var i = this._recentlyUsedTabs.indexOf(aTab);
|
||||
detachTab: function (aTab, aTabs) {
|
||||
var tabs = aTabs || this._recentlyUsedTabs;
|
||||
var i = tabs.indexOf(aTab);
|
||||
if (i >= 0)
|
||||
this._recentlyUsedTabs.splice(i, 1);
|
||||
tabs.splice(i, 1);
|
||||
},
|
||||
open: function () {
|
||||
if (window.allTabs)
|
||||
allTabs.close();
|
||||
|
||||
this._deferOnTabSelect = [];
|
||||
if (this.invertDirection)
|
||||
this._useTabBarOrder = true;
|
||||
|
||||
this._tabBarHandlesCtrlPageUpDown = gBrowser.mTabBox.handleCtrlPageUpDown;
|
||||
gBrowser.mTabBox.handleCtrlPageUpDown = false;
|
||||
|
||||
document.addEventListener("keyup", this, false);
|
||||
document.addEventListener("keydown", this, false);
|
||||
this.panel.addEventListener("popuphiding", this, false);
|
||||
this.panel.hidden = false;
|
||||
this.panel.width = tabPreviews.width * this.visibleCount;
|
||||
this.panel.width = screen.availWidth * .9;
|
||||
this.panel.openPopupAtScreen(screen.availLeft + (screen.availWidth - this.panel.width) / 2,
|
||||
screen.availTop + (screen.availHeight - this.svgRoot.getAttribute("height")) / 2,
|
||||
screen.availTop + screen.availHeight * .1,
|
||||
false);
|
||||
|
||||
// display $visibleCount tabs, starting with the first or
|
||||
// the second to the last tab, depending on whether Shift is pressed
|
||||
{
|
||||
let tabs = this.getTabList();
|
||||
let index = this.invertDirection ? tabs.length - 2 : 0;
|
||||
for (let i = this.visibleCount; i > 0; i--)
|
||||
this.addPreview(this.addBox(), tabs[index++ % tabs.length]);
|
||||
}
|
||||
|
||||
// regardless of visibleCount, highlight the second-visible tab
|
||||
this.selected = this.container.childNodes[1];
|
||||
this.arrangeBoxes();
|
||||
this.buildPagesBar();
|
||||
this.selectedIndex = 0;
|
||||
this.page = 0;
|
||||
this.advanceSelected();
|
||||
},
|
||||
onKeyPress: function (event) {
|
||||
var isOpen = this.isOpen;
|
||||
@ -489,22 +374,74 @@ var ctrlTab = {
|
||||
propagate = false;
|
||||
this.invertDirection = event.shiftKey;
|
||||
if (isOpen)
|
||||
this.scroll();
|
||||
this.advanceSelected();
|
||||
else if (this.tabCount == 2)
|
||||
gBrowser.selectedTab = this.getTabList()[1];
|
||||
gBrowser.selectedTab = this.tabList[1];
|
||||
else if (this.tabCount > 2)
|
||||
this.open();
|
||||
}
|
||||
break;
|
||||
case event.DOM_VK_UP:
|
||||
if (isOpen) {
|
||||
let index = this.selectedIndex - this.columns;
|
||||
if (index < 0) {
|
||||
this.goToPage(this.page - 1, this.thumbnails.length + index);
|
||||
} else {
|
||||
this.selected.removeAttribute("selected");
|
||||
this.selectedIndex = index;
|
||||
this.updateSelected();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case event.DOM_VK_DOWN:
|
||||
if (isOpen) {
|
||||
let index = this.selectedIndex + this.columns;
|
||||
if (index >= this.thumbnails.length || !this.thumbnails[index].hasAttribute("valid")) {
|
||||
this.goToPage(this.page + 1, this.selectedIndex % this.columns);
|
||||
} else {
|
||||
this.selected.removeAttribute("selected");
|
||||
this.selectedIndex = index;
|
||||
while (!this.selected.hasAttribute("valid"))
|
||||
this.selectedIndex--;
|
||||
this.updateSelected();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case event.DOM_VK_LEFT:
|
||||
if (isOpen) {
|
||||
this.invertDirection = true;
|
||||
this.advanceSelected();
|
||||
}
|
||||
break;
|
||||
case event.DOM_VK_RIGHT:
|
||||
if (isOpen) {
|
||||
this.invertDirection = false;
|
||||
this.advanceSelected();
|
||||
}
|
||||
break;
|
||||
case event.DOM_VK_HOME:
|
||||
if (isOpen)
|
||||
this.goToPage(0);
|
||||
break;
|
||||
case event.DOM_VK_END:
|
||||
if (isOpen)
|
||||
this.goToPage(this.pages - 1, this.thumbnails.length - 1);
|
||||
break;
|
||||
case event.DOM_VK_PAGE_UP:
|
||||
if (isOpen)
|
||||
this.goToPage(this.page - 1);
|
||||
break;
|
||||
case event.DOM_VK_PAGE_DOWN:
|
||||
if (isOpen)
|
||||
this.goToPage(this.page + 1);
|
||||
break;
|
||||
case event.DOM_VK_ESCAPE:
|
||||
if (isOpen)
|
||||
this.panel.hidePopup();
|
||||
break;
|
||||
default:
|
||||
if (isOpen && event.charCode == this.closeCharCode) {
|
||||
this.stopScroll();
|
||||
if (isOpen && event.charCode == this.closeCharCode)
|
||||
gBrowser.removeTab(this.selected._tab);
|
||||
}
|
||||
}
|
||||
if (!propagate) {
|
||||
event.stopPropagation();
|
||||
@ -512,19 +449,23 @@ var ctrlTab = {
|
||||
}
|
||||
},
|
||||
onPopupHiding: function () {
|
||||
this.stopScroll();
|
||||
gBrowser.mTabBox.handleCtrlPageUpDown = this._tabBarHandlesCtrlPageUpDown;
|
||||
document.removeEventListener("keyup", this, false);
|
||||
document.removeEventListener("keydown", this, false);
|
||||
while (this.container.childNodes.length)
|
||||
this.removeBox(this.container.lastChild);
|
||||
this.selected = null;
|
||||
|
||||
this.selected.removeAttribute("selected");
|
||||
if (this.pagesBar.childNodes.length)
|
||||
this.pagesBar.childNodes[this.page].removeAttribute("selected");
|
||||
|
||||
Array.forEach(this.thumbnails, function (thumbnail) {
|
||||
this.updatePreview(thumbnail, null);
|
||||
}, this);
|
||||
|
||||
this.invertDirection = false;
|
||||
this._useTabBarOrder = false;
|
||||
this._uniqid = 0;
|
||||
this.label.value = "";
|
||||
this.setStatusbarValue();
|
||||
this.container.removeAttribute("transform");
|
||||
this.svgRoot.forceRedraw();
|
||||
XULBrowserWindow.setOverLink("", null);
|
||||
this._page = null;
|
||||
|
||||
this._deferOnTabSelect.forEach(this.onTabSelect, this);
|
||||
this._deferOnTabSelect = null;
|
||||
@ -535,6 +476,20 @@ var ctrlTab = {
|
||||
this.attachTab(aTab, 0);
|
||||
}
|
||||
},
|
||||
removeClosingTabFromUI: function (aTab) {
|
||||
this._closing = aTab;
|
||||
if (this.tabCount == 1) {
|
||||
this.panel.hidePopup();
|
||||
} else {
|
||||
this.buildPagesBar();
|
||||
this.updatePreviews();
|
||||
if (!this.selected.hasAttribute("valid"))
|
||||
this.advanceSelected();
|
||||
else
|
||||
this.updateSelected();
|
||||
}
|
||||
this._closing = null;
|
||||
},
|
||||
handleEvent: function (event) {
|
||||
switch (event.type) {
|
||||
case "DOMAttrModified":
|
||||
@ -551,23 +506,9 @@ var ctrlTab = {
|
||||
this.attachTab(event.target, 1);
|
||||
break;
|
||||
case "TabClose":
|
||||
if (this.isOpen) {
|
||||
if (this.tabCount == 2) {
|
||||
// we have two tabs, one is being closed, so the panel isn't needed anymore
|
||||
this.panel.hidePopup();
|
||||
} else {
|
||||
if (event.target == this.selected._tab)
|
||||
this.advanceSelected();
|
||||
this.detachTab(event.target);
|
||||
Array.slice(this.container.childNodes).forEach(function (box) {
|
||||
if (box._tab == event.target) {
|
||||
this.removeBox(box);
|
||||
this.arrangeBoxes();
|
||||
}
|
||||
}, this);
|
||||
}
|
||||
}
|
||||
this.detachTab(event.target);
|
||||
if (this.isOpen)
|
||||
this.removeClosingTabFromUI(event.target);
|
||||
break;
|
||||
case "keypress":
|
||||
this.onKeyPress(event);
|
||||
@ -578,7 +519,7 @@ var ctrlTab = {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
if (event.type == "keyup" && event.keyCode == event.DOM_VK_CONTROL)
|
||||
this.pick();
|
||||
this.selectThumbnail();
|
||||
break;
|
||||
case "popuphiding":
|
||||
this.onPopupHiding();
|
||||
|
@ -1,6 +1,5 @@
|
||||
@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");
|
||||
@namespace html url("http://www.w3.org/1999/xhtml");
|
||||
|
||||
searchbar {
|
||||
-moz-binding: url("chrome://browser/content/search/search.xml#searchbar");
|
||||
@ -99,15 +98,6 @@ window[chromehidden~="toolbar"] toolbar:not(.toolbar-primary):not(.chromeclass-m
|
||||
}
|
||||
|
||||
/* 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);
|
||||
.ctrlTab-thumbnail:not([valid]) {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
@ -240,25 +240,22 @@
|
||||
#endif
|
||||
>
|
||||
<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>
|
||||
<hbox class="ctrlTab-row">
|
||||
<hbox flex="1" pack="center"><hbox class="ctrlTab-thumbnail" onclick="ctrlTab.thumbnailClick(event);"/></hbox>
|
||||
<hbox class="ctrlTab-thumbnail" onclick="ctrlTab.thumbnailClick(event);"/>
|
||||
<hbox flex="1" pack="center"><hbox class="ctrlTab-thumbnail" onclick="ctrlTab.thumbnailClick(event);"/></hbox>
|
||||
</hbox>
|
||||
<hbox class="ctrlTab-row">
|
||||
<hbox flex="1" pack="center"><hbox class="ctrlTab-thumbnail" onclick="ctrlTab.thumbnailClick(event);"/></hbox>
|
||||
<hbox class="ctrlTab-thumbnail" onclick="ctrlTab.thumbnailClick(event);"/>
|
||||
<hbox flex="1" pack="center"><hbox class="ctrlTab-thumbnail" onclick="ctrlTab.thumbnailClick(event);"/></hbox>
|
||||
</hbox>
|
||||
<hbox class="ctrlTab-row">
|
||||
<hbox flex="1" pack="center"><hbox class="ctrlTab-thumbnail" onclick="ctrlTab.thumbnailClick(event);"/></hbox>
|
||||
<hbox class="ctrlTab-thumbnail" onclick="ctrlTab.thumbnailClick(event);"/>
|
||||
<hbox flex="1" pack="center"><hbox class="ctrlTab-thumbnail" onclick="ctrlTab.thumbnailClick(event);"/></hbox>
|
||||
</hbox>
|
||||
<hbox id="ctrlTab-pages"/>
|
||||
</panel>
|
||||
</popupset>
|
||||
|
||||
|
@ -49,7 +49,7 @@ function test() {
|
||||
}
|
||||
assertTabs(2);
|
||||
|
||||
//ctrlTabTest([1], 1, 0);
|
||||
ctrlTabTest([1], 1, 0);
|
||||
|
||||
gBrowser.removeTab(gBrowser.tabContainer.lastChild);
|
||||
|
||||
|
@ -47,7 +47,6 @@
|
||||
|
||||
@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 */
|
||||
@ -1375,22 +1374,35 @@ toolbar[mode="text"] > #window-controls > toolbarbutton > .toolbarbutton-text {
|
||||
/* ::::: Ctrl-Tab Panel ::::: */
|
||||
#ctrlTab-label {
|
||||
font-weight: bold;
|
||||
font-size: 1.5em;
|
||||
text-align: center;
|
||||
margin-top: .5em;
|
||||
margin-bottom: .7em;
|
||||
margin-top: 1em;
|
||||
margin-bottom: 1.5em;
|
||||
}
|
||||
|
||||
svg|*.ctrlTab-thumbnailborder {
|
||||
stroke: ThreeDDarkShadow;
|
||||
stroke-width: .7px;
|
||||
.ctrlTab-thumbnail {
|
||||
margin-bottom: 40px;
|
||||
-moz-box-shadow: 1px 2px 3px ThreeDShadow;
|
||||
}
|
||||
|
||||
.ctrlTab-thumbnail[selected="true"] {
|
||||
-moz-box-shadow: 1px 2px 3px ThreeDShadow, 0 0 10px Highlight, 0 0 20px Highlight, 0 0 25px Highlight, 0 0 30px Highlight;
|
||||
}
|
||||
|
||||
#ctrlTab-pages {
|
||||
display: block;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.ctrlTab-pagePointer {
|
||||
display: inline-block;
|
||||
margin: 0 1em 1em;
|
||||
width: 1.5em;
|
||||
height: 1.5em;
|
||||
-moz-border-radius: .75em;
|
||||
background: ThreeDShadow;
|
||||
}
|
||||
|
||||
svg|*#ctrlTab-fadeGradientTop {
|
||||
stop-color: ThreeDShadow;
|
||||
stop-opacity: .75;
|
||||
}
|
||||
|
||||
svg|*#ctrlTab-fadeGradientBottom {
|
||||
stop-color: -moz-dialog;
|
||||
stop-opacity: 1;
|
||||
.ctrlTab-pagePointer[selected="true"] {
|
||||
background: ThreeDDarkShadow;
|
||||
}
|
||||
|
@ -45,7 +45,6 @@
|
||||
|
||||
@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[chromehidden~="toolbar"][chromehidden~="location"][chromehidden~="directories"] {
|
||||
border-top: 1px solid rgba(0,0,0,0.65);
|
||||
@ -2136,41 +2135,53 @@ tabpanels.plain {
|
||||
/* ::::: Keyboard UI Panel ::::: */
|
||||
.KUI-panel {
|
||||
-moz-appearance: none;
|
||||
background: rgba(0, 0, 0, .8) url(KUI-background.png) repeat-x;
|
||||
background: rgba(68, 68, 68, .9) url(KUI-background.png) repeat-x;
|
||||
color: white;
|
||||
border: 1px solid #ccc;
|
||||
border: 1px solid rgba(255, 255, 255, 0.15);
|
||||
-moz-border-radius: 10px;
|
||||
margin-top: -1px;
|
||||
margin-left: -1px;
|
||||
}
|
||||
|
||||
.KUI-panel[level="top"] {
|
||||
background-color: rgba(68, 68, 68, .5);
|
||||
-moz-window-shadow: none;
|
||||
}
|
||||
|
||||
/* ::::: Ctrl-Tab Panel ::::: */
|
||||
#ctrlTab-panel {
|
||||
margin-top: -20px;
|
||||
border-bottom-width: 9px;
|
||||
-moz-border-bottom-colors: #ccc black black black black black black black black;
|
||||
}
|
||||
|
||||
#ctrlTab-label {
|
||||
font-weight: bold;
|
||||
font-size: 14px;
|
||||
font-size: 1.5em;
|
||||
text-align: center;
|
||||
margin-top: 6px;
|
||||
margin-bottom: 10px;
|
||||
margin-top: 1em;
|
||||
margin-bottom: 1.5em;
|
||||
text-shadow: black 0 0 1em;
|
||||
}
|
||||
|
||||
svg|*.ctrlTab-thumbnailborder {
|
||||
stroke: white;
|
||||
stroke-width: 1px;
|
||||
.ctrlTab-thumbnail {
|
||||
margin-bottom: 40px;
|
||||
-moz-box-shadow: 1px 2px 3px black;
|
||||
}
|
||||
|
||||
svg|*#ctrlTab-fadeGradientTop {
|
||||
stop-color: black;
|
||||
stop-opacity: .5;
|
||||
.ctrlTab-thumbnail[selected="true"] {
|
||||
-moz-box-shadow: 1px 2px 3px black, 0 0 10px white, 0 0 20px rgb(50, 170, 255), 0 0 30px rgb(50, 170, 255);
|
||||
}
|
||||
|
||||
svg|*#ctrlTab-fadeGradientBottom {
|
||||
stop-color: black;
|
||||
stop-opacity: 1;
|
||||
#ctrlTab-pages {
|
||||
display: block;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.ctrlTab-pagePointer {
|
||||
display: inline-block;
|
||||
margin: 0 1em 1em;
|
||||
width: 1.5em;
|
||||
height: 1.5em;
|
||||
-moz-border-radius: .75em;
|
||||
background: rgba(0, 0, 0, .5);
|
||||
border: 1px solid rgba(255, 255, 255, .3);
|
||||
}
|
||||
|
||||
.ctrlTab-pagePointer[selected="true"] {
|
||||
background: rgba(255, 255, 255, .6);
|
||||
}
|
||||
|
@ -96,8 +96,3 @@
|
||||
color: black;
|
||||
text-shadow: white -1px -1px 9px, white -1px 1px 9px, white 1px 1px 9px, white 1px -1px 9px;
|
||||
}
|
||||
|
||||
svg|*#ctrlTab-groundFade:-moz-system-metric(windows-compositor),
|
||||
svg|*.ctrlTab-reflection:-moz-system-metric(windows-compositor) {
|
||||
display: none;
|
||||
}
|
||||
|
@ -45,7 +45,6 @@
|
||||
|
||||
@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 */
|
||||
@ -1993,40 +1992,53 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] {
|
||||
/* ::::: Keyboard UI Panel ::::: */
|
||||
.KUI-panel {
|
||||
-moz-appearance: none;
|
||||
background: rgba(0, 0, 0, .8) url(KUI-background.png) repeat-x;
|
||||
background: rgba(68, 68, 68, .9) url(KUI-background.png) repeat-x;
|
||||
color: white;
|
||||
border: 1px solid #ccc;
|
||||
border: 1px solid rgba(255, 255, 255, 0.15);
|
||||
-moz-border-radius: 10px;
|
||||
margin-top: -1px;
|
||||
margin-left: -1px;
|
||||
}
|
||||
|
||||
/* ::::: Ctrl-Tab Panel ::::: */
|
||||
#ctrlTab-panel {
|
||||
margin-top: -20px;
|
||||
border-bottom-width: 9px;
|
||||
-moz-border-bottom-colors: #ccc black black black black black black black black;
|
||||
.KUI-panel[level="top"] {
|
||||
background-color: rgba(68, 68, 68, .5);
|
||||
-moz-window-shadow: none;
|
||||
}
|
||||
|
||||
/* ::::: Ctrl-Tab Panel ::::: */
|
||||
#ctrlTab-label {
|
||||
font-weight: bold;
|
||||
font-size: 14px;
|
||||
font-size: 1.5em;
|
||||
text-align: center;
|
||||
margin-top: 6px;
|
||||
margin-bottom: 10px;
|
||||
margin-top: 1em;
|
||||
margin-bottom: 1.5em;
|
||||
text-shadow: black 0 0 1em;
|
||||
}
|
||||
|
||||
svg|*.ctrlTab-thumbnailborder {
|
||||
stroke: white;
|
||||
stroke-width: 1px;
|
||||
.ctrlTab-thumbnail {
|
||||
margin-bottom: 40px;
|
||||
-moz-box-shadow: 1px 2px 3px black;
|
||||
}
|
||||
|
||||
svg|*#ctrlTab-fadeGradientTop {
|
||||
stop-color: black;
|
||||
stop-opacity: .5;
|
||||
.ctrlTab-thumbnail[selected="true"] {
|
||||
-moz-box-shadow: 1px 2px 3px black, 0 0 10px white, 0 0 20px rgb(50, 170, 255), 0 0 30px rgb(50, 170, 255);
|
||||
}
|
||||
|
||||
svg|*#ctrlTab-fadeGradientBottom {
|
||||
stop-color: black;
|
||||
stop-opacity: 1;
|
||||
#ctrlTab-pages {
|
||||
display: block;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.ctrlTab-pagePointer {
|
||||
display: inline-block;
|
||||
margin: 0 1em 1em;
|
||||
width: 1.5em;
|
||||
height: 1.5em;
|
||||
-moz-border-radius: .75em;
|
||||
background: rgba(0, 0, 0, .5);
|
||||
border: 1px solid rgba(255, 255, 255, .3);
|
||||
}
|
||||
|
||||
.ctrlTab-pagePointer[selected="true"] {
|
||||
background: rgba(255, 255, 255, .6);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user