2008-07-15 09:11:00 -07:00
|
|
|
/*
|
|
|
|
#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 = {
|
2008-09-19 02:44:15 -07:00
|
|
|
aspectRatio: 0.5625, // 16:9
|
2008-11-04 23:38:13 -08:00
|
|
|
init: function tabPreviews__init() {
|
2008-09-19 02:44:15 -07:00
|
|
|
this.width = Math.ceil(screen.availWidth / 5);
|
2008-07-15 09:11:00 -07:00
|
|
|
this.height = Math.round(this.width * this.aspectRatio);
|
|
|
|
|
|
|
|
gBrowser.tabContainer.addEventListener("TabSelect", this, false);
|
|
|
|
gBrowser.tabContainer.addEventListener("SSTabRestored", this, false);
|
|
|
|
},
|
2008-11-04 23:38:13 -08:00
|
|
|
uninit: function tabPreviews__uninit() {
|
2008-07-15 09:11:00 -07:00
|
|
|
gBrowser.tabContainer.removeEventListener("TabSelect", this, false);
|
|
|
|
gBrowser.tabContainer.removeEventListener("SSTabRestored", this, false);
|
|
|
|
this._selectedTab = null;
|
|
|
|
},
|
2008-11-04 23:38:13 -08:00
|
|
|
get: function tabPreviews__get(aTab) {
|
2008-08-30 17:43:35 -07:00
|
|
|
if (aTab.__thumbnail_lastURI &&
|
|
|
|
aTab.__thumbnail_lastURI != aTab.linkedBrowser.currentURI.spec) {
|
|
|
|
aTab.__thumbnail = null;
|
|
|
|
aTab.__thumbnail_lastURI = null;
|
|
|
|
}
|
2008-07-15 09:11:00 -07:00
|
|
|
return aTab.__thumbnail || this.capture(aTab, !aTab.hasAttribute("busy"));
|
|
|
|
},
|
2008-11-04 23:38:13 -08:00
|
|
|
capture: function tabPreviews__capture(aTab, aStore) {
|
2008-07-15 09:11:00 -07:00
|
|
|
var thumbnail = document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
|
|
|
|
thumbnail.mozOpaque = true;
|
|
|
|
thumbnail.height = this.height;
|
|
|
|
thumbnail.width = this.width;
|
2008-09-19 02:44:15 -07:00
|
|
|
|
2008-07-15 09:11:00 -07:00
|
|
|
var ctx = thumbnail.getContext("2d");
|
2008-09-19 02:44:15 -07:00
|
|
|
var win = aTab.linkedBrowser.contentWindow;
|
|
|
|
var snippetWidth = win.innerWidth * .6;
|
|
|
|
var scale = this.width / snippetWidth;
|
|
|
|
ctx.scale(scale, scale);
|
2008-07-15 09:11:00 -07:00
|
|
|
ctx.drawWindow(win, win.scrollX, win.scrollY,
|
2008-09-19 02:44:15 -07:00
|
|
|
snippetWidth, snippetWidth * this.aspectRatio, "rgb(255,255,255)");
|
|
|
|
|
2008-08-30 17:43:35 -07:00
|
|
|
if (aStore) {
|
2008-11-04 00:19:55 -08:00
|
|
|
aTab.__thumbnail = thumbnail;
|
2008-08-30 17:43:35 -07:00
|
|
|
aTab.__thumbnail_lastURI = aTab.linkedBrowser.currentURI.spec;
|
|
|
|
}
|
2008-11-04 00:19:55 -08:00
|
|
|
return thumbnail;
|
2008-07-15 09:11:00 -07:00
|
|
|
},
|
2008-11-04 23:38:13 -08:00
|
|
|
handleEvent: function tabPreviews__handleEvent(event) {
|
2008-07-15 09:11:00 -07:00
|
|
|
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 = {
|
|
|
|
get panel () {
|
|
|
|
delete this.panel;
|
|
|
|
return this.panel = document.getElementById("ctrlTab-panel");
|
|
|
|
},
|
2008-11-04 23:38:13 -08:00
|
|
|
get searchField () {
|
|
|
|
delete this.searchField;
|
|
|
|
return this.searchField = document.getElementById("ctrlTab-search");
|
2008-07-15 09:11:00 -07:00
|
|
|
},
|
2008-11-04 00:19:55 -08:00
|
|
|
get pagesBar () {
|
|
|
|
delete this.pagesBar;
|
|
|
|
return this.pagesBar = document.getElementById("ctrlTab-pages");
|
2008-07-15 09:11:00 -07:00
|
|
|
},
|
2008-11-04 00:19:55 -08:00
|
|
|
get thumbnails () {
|
|
|
|
delete this.thumbnails;
|
|
|
|
return this.thumbnails = this.panel.getElementsByClassName("ctrlTab-thumbnail");
|
2008-07-15 09:11:00 -07:00
|
|
|
},
|
2008-11-04 00:19:55 -08:00
|
|
|
get columns () {
|
|
|
|
delete this.columns;
|
|
|
|
return this.columns = this.thumbnails.length /
|
|
|
|
this.panel.getElementsByClassName("ctrlTab-row").length;
|
2008-07-15 09:11:00 -07:00
|
|
|
},
|
2008-08-09 03:18:49 -07:00
|
|
|
get closeCharCode () {
|
|
|
|
delete this.closeCharCode;
|
|
|
|
return this.closeCharCode = document.getElementById("key_close")
|
|
|
|
.getAttribute("key")
|
2008-11-04 23:38:13 -08:00
|
|
|
.toLocaleLowerCase().charCodeAt(0);
|
|
|
|
},
|
|
|
|
get findCharCode () {
|
|
|
|
delete this.findCharCode;
|
|
|
|
return this.findCharCode = document.getElementById("key_find")
|
|
|
|
.getAttribute("key")
|
|
|
|
.toLocaleLowerCase().charCodeAt(0);
|
2008-08-09 03:18:49 -07:00
|
|
|
},
|
2008-09-19 02:38:44 -07:00
|
|
|
get recentlyUsedLimit () {
|
|
|
|
delete this.recentlyUsedLimit;
|
|
|
|
return this.recentlyUsedLimit = gPrefService.getIntPref("browser.ctrlTab.recentlyUsedLimit");
|
|
|
|
},
|
2008-11-04 00:19:55 -08:00
|
|
|
selectedIndex: 0,
|
|
|
|
get selected () this.thumbnails.item(this.selectedIndex),
|
|
|
|
get isOpen () this.panel.state == "open" || this.panel.state == "showing",
|
2008-11-04 23:38:13 -08:00
|
|
|
get tabCount () this.tabList.length,
|
|
|
|
|
|
|
|
get sticky () this.panel.hasAttribute("sticky"),
|
|
|
|
set sticky (val) {
|
|
|
|
if (val)
|
|
|
|
this.panel.setAttribute("sticky", "true");
|
|
|
|
else
|
|
|
|
this.panel.removeAttribute("sticky");
|
|
|
|
return val;
|
|
|
|
},
|
|
|
|
|
|
|
|
get pages () Math.ceil(this.tabCount / this.thumbnails.length),
|
|
|
|
get page () this._page || 0,
|
|
|
|
set page (page) {
|
2008-11-04 00:19:55 -08:00
|
|
|
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;
|
2008-07-15 09:11:00 -07:00
|
|
|
},
|
2008-11-04 23:38:13 -08:00
|
|
|
|
2008-11-04 00:19:55 -08:00
|
|
|
get tabList () {
|
2008-11-04 23:38:13 -08:00
|
|
|
if (this._tabList)
|
|
|
|
return this._tabList;
|
|
|
|
|
2008-11-04 00:19:55 -08:00
|
|
|
var list = Array.slice(gBrowser.mTabs);
|
2008-11-04 23:38:13 -08:00
|
|
|
|
2008-11-04 00:19:55 -08:00
|
|
|
if (this._closing)
|
|
|
|
this.detachTab(this._closing, list);
|
2008-11-04 23:38:13 -08:00
|
|
|
|
2008-11-04 00:19:55 -08:00
|
|
|
for (let i = 0; i < gBrowser.tabContainer.selectedIndex; i++)
|
|
|
|
list.push(list.shift());
|
2008-11-04 23:38:13 -08:00
|
|
|
|
2008-11-04 00:19:55 -08:00
|
|
|
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]);
|
|
|
|
}
|
|
|
|
}
|
2008-11-04 23:38:13 -08:00
|
|
|
|
|
|
|
if (this.searchField.value) {
|
|
|
|
list = list.filter(function (tab) {
|
|
|
|
let lowerCaseLabel, uri;
|
|
|
|
for (let i = 0; i < this.length; i++) {
|
|
|
|
if (tab.label.indexOf(this[i]) != -1)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!lowerCaseLabel)
|
|
|
|
lowerCaseLabel = tab.label.toLocaleLowerCase();
|
|
|
|
if (lowerCaseLabel.indexOf(this[i]) != -1)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!uri) {
|
|
|
|
uri = tab.linkedBrowser.currentURI.spec;
|
|
|
|
try {
|
|
|
|
uri = decodeURI(uri);
|
|
|
|
} catch (e) {}
|
|
|
|
}
|
|
|
|
if (uri.indexOf(this[i]) != -1)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}, this.searchField.value.split(/\s+/g));
|
|
|
|
}
|
|
|
|
|
|
|
|
return this._tabList = list;
|
2008-08-09 03:18:49 -07:00
|
|
|
},
|
2008-11-04 23:38:13 -08:00
|
|
|
|
|
|
|
init: function ctrlTab__init() {
|
2008-09-19 02:38:44 -07:00
|
|
|
if (this._recentlyUsedTabs)
|
2008-08-09 03:18:49 -07:00
|
|
|
return;
|
2008-09-19 02:38:44 -07:00
|
|
|
this._recentlyUsedTabs = [gBrowser.selectedTab];
|
2008-08-09 03:18:49 -07:00
|
|
|
|
2008-07-15 09:11:00 -07:00
|
|
|
var tabContainer = gBrowser.tabContainer;
|
|
|
|
tabContainer.addEventListener("TabOpen", this, false);
|
|
|
|
tabContainer.addEventListener("TabSelect", this, false);
|
|
|
|
tabContainer.addEventListener("TabClose", this, false);
|
|
|
|
|
2008-11-04 23:38:13 -08:00
|
|
|
this._handleCtrlTab =
|
|
|
|
gPrefService.getBoolPref("browser.ctrlTab.previews") &&
|
|
|
|
(!gPrefService.prefHasUserValue("browser.ctrlTab.disallowForScreenReaders") ||
|
|
|
|
!gPrefService.getBoolPref("browser.ctrlTab.disallowForScreenReaders"));
|
|
|
|
if (this._handleCtrlTab)
|
|
|
|
gBrowser.mTabBox.handleCtrlTab = false;
|
2008-08-11 02:10:01 -07:00
|
|
|
document.addEventListener("keypress", this, false);
|
2008-07-15 09:11:00 -07:00
|
|
|
},
|
2008-11-04 23:38:13 -08:00
|
|
|
|
|
|
|
uninit: function ctrlTab__uninit() {
|
2008-09-19 02:38:44 -07:00
|
|
|
this._recentlyUsedTabs = null;
|
2008-08-09 03:18:49 -07:00
|
|
|
|
2008-07-15 09:11:00 -07:00
|
|
|
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);
|
2008-11-04 23:38:13 -08:00
|
|
|
this.panel.removeEventListener("popupshown", this, false);
|
|
|
|
this.panel.removeEventListener("popuphidden", this, false);
|
2008-08-11 02:10:01 -07:00
|
|
|
document.removeEventListener("keypress", this, false);
|
2008-11-04 23:38:13 -08:00
|
|
|
if (this._handleCtrlTab)
|
|
|
|
gBrowser.mTabBox.handleCtrlTab = true;
|
2008-11-04 00:19:55 -08:00
|
|
|
},
|
2008-11-04 23:38:13 -08:00
|
|
|
|
|
|
|
search: function ctrlTab__search() {
|
|
|
|
if (this.isOpen) {
|
|
|
|
this._tabList = null;
|
|
|
|
this.buildPagesBar();
|
|
|
|
this.goToPage(0, 0);
|
|
|
|
this.updatePreviews();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
buildPagesBar: function ctrlTab__buildPagesBar() {
|
2008-11-04 00:19:55 -08:00
|
|
|
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);
|
2008-07-15 09:11:00 -07:00
|
|
|
}
|
|
|
|
},
|
2008-11-04 23:38:13 -08:00
|
|
|
|
|
|
|
goToPage: function ctrlTab__goToPage(aPage, aIndex) {
|
|
|
|
this.page = aPage;
|
2008-11-04 00:19:55 -08:00
|
|
|
this.selected.removeAttribute("selected");
|
|
|
|
if (aIndex) {
|
|
|
|
this.selectedIndex = aIndex;
|
|
|
|
while (!this.selected || !this.selected.hasAttribute("valid"))
|
|
|
|
this.selectedIndex--;
|
|
|
|
} else {
|
|
|
|
this.selectedIndex = 0;
|
|
|
|
}
|
|
|
|
this.updateSelected();
|
|
|
|
},
|
2008-11-04 23:38:13 -08:00
|
|
|
|
|
|
|
updatePreviews: function ctrlTab__updatePreviews() {
|
2008-11-04 00:19:55 -08:00
|
|
|
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]);
|
|
|
|
},
|
2008-11-04 23:38:13 -08:00
|
|
|
updatePreview: function ctrlTab__updatePreview(aThumbnail, aTab) {
|
2008-11-04 00:19:55 -08:00
|
|
|
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");
|
2008-11-04 23:38:13 -08:00
|
|
|
aThumbnail.setAttribute("label", aTab.label);
|
|
|
|
aThumbnail.setAttribute("crop", aTab.crop);
|
2008-11-04 00:19:55 -08:00
|
|
|
} else {
|
2008-11-04 23:38:13 -08:00
|
|
|
let placeholder = document.createElement("hbox");
|
|
|
|
placeholder.height = tabPreviews.height;
|
|
|
|
aThumbnail.appendChild(placeholder);
|
2008-11-04 00:19:55 -08:00
|
|
|
aThumbnail.removeAttribute("valid");
|
2008-11-04 23:38:13 -08:00
|
|
|
aThumbnail.setAttribute("label", "placeholder");
|
2008-11-04 00:19:55 -08:00
|
|
|
}
|
|
|
|
aThumbnail.width = tabPreviews.width;
|
2008-07-15 09:11:00 -07:00
|
|
|
},
|
2008-11-04 23:38:13 -08:00
|
|
|
|
|
|
|
tabAttrModified: function ctrlTab__tabAttrModified(aTab, aAttrName) {
|
2008-07-15 09:11:00 -07:00
|
|
|
switch (aAttrName) {
|
2008-11-04 23:38:13 -08:00
|
|
|
case "label":
|
|
|
|
case "crop":
|
2008-07-15 09:11:00 -07:00
|
|
|
case "busy":
|
2008-11-04 00:19:55 -08:00
|
|
|
for (let i = this.thumbnails.length - 1; i >= 0; i--) {
|
|
|
|
if (this.thumbnails[i]._tab == aTab) {
|
|
|
|
this.updatePreview(this.thumbnails[i], aTab);
|
|
|
|
break;
|
2008-07-15 09:11:00 -07:00
|
|
|
}
|
2008-11-04 00:19:55 -08:00
|
|
|
}
|
2008-07-15 09:11:00 -07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
},
|
2008-11-04 23:38:13 -08:00
|
|
|
|
|
|
|
advanceSelected: function ctrlTab__advanceSelected() {
|
2008-11-04 00:19:55 -08:00
|
|
|
this.selected.removeAttribute("selected");
|
|
|
|
|
|
|
|
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;
|
2008-07-15 09:11:00 -07:00
|
|
|
}
|
2008-11-04 00:19:55 -08:00
|
|
|
this.updateSelected();
|
|
|
|
},
|
2008-11-04 23:38:13 -08:00
|
|
|
|
|
|
|
updateSelected: function ctrlTab__updateSelected() {
|
|
|
|
if (this.tabCount)
|
|
|
|
this.selected.setAttribute("selected", "true");
|
2008-07-15 09:11:00 -07:00
|
|
|
},
|
2008-11-04 23:38:13 -08:00
|
|
|
|
|
|
|
selectThumbnail: function ctrlTab__selectThumbnail(aThumbnail) {
|
|
|
|
if (this.tabCount) {
|
|
|
|
this._tabToSelect = (aThumbnail || this.selected)._tab;
|
|
|
|
this.panel.hidePopup();
|
2008-07-15 09:11:00 -07:00
|
|
|
}
|
|
|
|
},
|
2008-11-04 23:38:13 -08:00
|
|
|
|
|
|
|
attachTab: function ctrlTab__attachTab(aTab, aPos) {
|
2008-09-19 02:34:33 -07:00
|
|
|
if (aPos == 0)
|
2008-09-19 02:38:44 -07:00
|
|
|
this._recentlyUsedTabs.unshift(aTab);
|
2008-09-19 02:34:33 -07:00
|
|
|
else if (aPos)
|
2008-09-19 02:38:44 -07:00
|
|
|
this._recentlyUsedTabs.splice(aPos, 0, aTab);
|
2008-07-15 09:11:00 -07:00
|
|
|
else
|
2008-09-19 02:38:44 -07:00
|
|
|
this._recentlyUsedTabs.push(aTab);
|
2008-07-15 09:11:00 -07:00
|
|
|
},
|
2008-11-04 23:38:13 -08:00
|
|
|
detachTab: function ctrlTab__detachTab(aTab, aTabs) {
|
2008-11-04 00:19:55 -08:00
|
|
|
var tabs = aTabs || this._recentlyUsedTabs;
|
|
|
|
var i = tabs.indexOf(aTab);
|
2008-07-15 09:11:00 -07:00
|
|
|
if (i >= 0)
|
2008-11-04 00:19:55 -08:00
|
|
|
tabs.splice(i, 1);
|
2008-07-15 09:11:00 -07:00
|
|
|
},
|
2008-11-04 23:38:13 -08:00
|
|
|
|
|
|
|
open: function ctrlTab__open(aSticky) {
|
|
|
|
if (this.isOpen && this.sticky) {
|
|
|
|
this.panel.hidePopup();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.sticky = !!aSticky;
|
2008-11-04 00:19:55 -08:00
|
|
|
|
2008-08-09 03:18:49 -07:00
|
|
|
this._deferOnTabSelect = [];
|
2008-09-19 02:38:44 -07:00
|
|
|
if (this.invertDirection)
|
|
|
|
this._useTabBarOrder = true;
|
2008-08-09 03:18:49 -07:00
|
|
|
|
2008-11-04 00:19:55 -08:00
|
|
|
this._tabBarHandlesCtrlPageUpDown = gBrowser.mTabBox.handleCtrlPageUpDown;
|
|
|
|
gBrowser.mTabBox.handleCtrlPageUpDown = false;
|
|
|
|
|
2008-11-04 23:38:13 -08:00
|
|
|
document.addEventListener("keyup", this, true);
|
|
|
|
document.addEventListener("keydown", this, true);
|
|
|
|
this.panel.addEventListener("popupshown", this, false);
|
2008-07-15 09:11:00 -07:00
|
|
|
this.panel.addEventListener("popuphiding", this, false);
|
2008-11-04 23:38:13 -08:00
|
|
|
this.panel.addEventListener("popuphidden", this, false);
|
|
|
|
this._prevFocus = document.commandDispatcher.focusedElement ||
|
|
|
|
document.commandDispatcher.focusedWindow;
|
2008-07-15 09:11:00 -07:00
|
|
|
this.panel.hidden = false;
|
2008-11-04 23:38:13 -08:00
|
|
|
this.panel.width = screen.availWidth * .85;
|
|
|
|
this.panel.popupBoxObject.setConsumeRollupEvent(Ci.nsIPopupBoxObject.ROLLUP_CONSUME);
|
2008-07-15 09:11:00 -07:00
|
|
|
this.panel.openPopupAtScreen(screen.availLeft + (screen.availWidth - this.panel.width) / 2,
|
2008-11-04 23:38:13 -08:00
|
|
|
screen.availTop + screen.availHeight * .12,
|
2008-07-15 09:11:00 -07:00
|
|
|
false);
|
2008-11-04 00:19:55 -08:00
|
|
|
this.buildPagesBar();
|
|
|
|
this.selectedIndex = 0;
|
|
|
|
this.page = 0;
|
|
|
|
this.advanceSelected();
|
2008-07-15 09:11:00 -07:00
|
|
|
},
|
2008-11-04 23:38:13 -08:00
|
|
|
|
|
|
|
onKeyPress: function ctrlTab__onKeyPress(event) {
|
2008-08-09 03:18:49 -07:00
|
|
|
var isOpen = this.isOpen;
|
2008-11-04 23:38:13 -08:00
|
|
|
|
2008-11-06 11:20:34 -08:00
|
|
|
if (isOpen &&
|
|
|
|
event.target == this.searchField &&
|
|
|
|
event.keyCode != event.DOM_VK_ESCAPE)
|
2008-11-04 23:38:13 -08:00
|
|
|
return;
|
|
|
|
|
|
|
|
if (isOpen) {
|
|
|
|
event.preventDefault();
|
|
|
|
event.stopPropagation();
|
|
|
|
}
|
|
|
|
|
2008-07-15 09:11:00 -07:00
|
|
|
switch (event.keyCode) {
|
|
|
|
case event.DOM_VK_TAB:
|
2008-11-04 23:38:13 -08:00
|
|
|
if ((event.ctrlKey || this.sticky) && !event.altKey && !event.metaKey) {
|
2008-07-15 09:11:00 -07:00
|
|
|
this.invertDirection = event.shiftKey;
|
2008-11-04 23:38:13 -08:00
|
|
|
if (isOpen) {
|
2008-11-04 00:19:55 -08:00
|
|
|
this.advanceSelected();
|
2008-11-04 23:38:13 -08:00
|
|
|
} else if (this._handleCtrlTab) {
|
|
|
|
event.preventDefault();
|
|
|
|
event.stopPropagation();
|
|
|
|
if (gBrowser.mTabs.length > 2) {
|
|
|
|
this.open();
|
|
|
|
} else if (gBrowser.mTabs.length == 2) {
|
|
|
|
gBrowser.selectedTab = gBrowser.selectedTab.nextSibling ||
|
|
|
|
gBrowser.selectedTab.previousSibling;
|
|
|
|
}
|
|
|
|
}
|
2008-07-15 09:11:00 -07:00
|
|
|
}
|
|
|
|
break;
|
2008-11-04 00:19:55 -08:00
|
|
|
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;
|
2008-11-04 23:38:13 -08:00
|
|
|
case event.DOM_VK_RETURN:
|
|
|
|
if (isOpen && this.sticky)
|
|
|
|
this.selectThumbnail();
|
|
|
|
break;
|
2008-07-15 09:11:00 -07:00
|
|
|
case event.DOM_VK_ESCAPE:
|
|
|
|
if (isOpen)
|
|
|
|
this.panel.hidePopup();
|
|
|
|
break;
|
2008-08-11 02:06:42 -07:00
|
|
|
default:
|
2008-11-04 23:38:13 -08:00
|
|
|
if (isOpen && event.ctrlKey) {
|
|
|
|
switch (event.charCode) {
|
|
|
|
case this.closeCharCode:
|
|
|
|
gBrowser.removeTab(this.selected._tab);
|
|
|
|
break;
|
|
|
|
case this.findCharCode:
|
|
|
|
this.searchField.focus();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2008-07-15 09:11:00 -07:00
|
|
|
}
|
|
|
|
},
|
2008-11-04 23:38:13 -08:00
|
|
|
onPopupHiding: function ctrlTab__onPopupHiding() {
|
2008-11-04 00:19:55 -08:00
|
|
|
gBrowser.mTabBox.handleCtrlPageUpDown = this._tabBarHandlesCtrlPageUpDown;
|
2008-11-04 23:38:13 -08:00
|
|
|
document.removeEventListener("keyup", this, true);
|
|
|
|
document.removeEventListener("keydown", this, true);
|
2008-11-04 00:19:55 -08:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2008-11-04 23:38:13 -08:00
|
|
|
this.searchField.value = "";
|
2008-07-15 09:11:00 -07:00
|
|
|
this.invertDirection = false;
|
2008-11-04 23:38:13 -08:00
|
|
|
this.sticky = false;
|
2008-09-19 02:38:44 -07:00
|
|
|
this._useTabBarOrder = false;
|
2008-11-04 00:19:55 -08:00
|
|
|
this._page = null;
|
2008-11-04 23:38:13 -08:00
|
|
|
this._tabList = null;
|
2008-08-09 03:18:49 -07:00
|
|
|
|
|
|
|
this._deferOnTabSelect.forEach(this.onTabSelect, this);
|
|
|
|
this._deferOnTabSelect = null;
|
2008-11-04 23:38:13 -08:00
|
|
|
|
|
|
|
this._prevFocus.focus();
|
|
|
|
this._prevFocus = null;
|
|
|
|
|
|
|
|
if (this._tabToSelect) {
|
|
|
|
gBrowser.selectedTab = this._tabToSelect;
|
|
|
|
this._tabToSelect = null;
|
|
|
|
}
|
2008-08-09 03:18:49 -07:00
|
|
|
},
|
2008-11-04 23:38:13 -08:00
|
|
|
onTabSelect: function ctrlTab__onTabSelect(aTab) {
|
2008-08-09 03:18:49 -07:00
|
|
|
if (aTab.parentNode) {
|
|
|
|
this.detachTab(aTab);
|
2008-09-19 02:34:33 -07:00
|
|
|
this.attachTab(aTab, 0);
|
2008-08-09 03:18:49 -07:00
|
|
|
}
|
2008-07-15 09:11:00 -07:00
|
|
|
},
|
2008-11-04 23:38:13 -08:00
|
|
|
|
|
|
|
removeClosingTabFromUI: function ctrlTab__removeClosingTabFromUI(aTab) {
|
2008-11-04 00:19:55 -08:00
|
|
|
this._closing = aTab;
|
2008-11-04 23:38:13 -08:00
|
|
|
this._tabList = null;
|
2008-11-04 00:19:55 -08:00
|
|
|
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;
|
|
|
|
},
|
2008-11-04 23:38:13 -08:00
|
|
|
|
|
|
|
handleEvent: function ctrlTab__handleEvent(event) {
|
2008-07-15 09:11:00 -07:00
|
|
|
switch (event.type) {
|
|
|
|
case "DOMAttrModified":
|
|
|
|
this.tabAttrModified(event.target, event.attrName);
|
|
|
|
break;
|
|
|
|
case "TabSelect":
|
2008-08-09 03:18:49 -07:00
|
|
|
if (this.isOpen)
|
|
|
|
// don't change the tab order while the panel is open
|
|
|
|
this._deferOnTabSelect.push(event.target);
|
|
|
|
else
|
|
|
|
this.onTabSelect(event.target);
|
2008-07-15 09:11:00 -07:00
|
|
|
break;
|
|
|
|
case "TabOpen":
|
2008-09-19 02:34:33 -07:00
|
|
|
this.attachTab(event.target, 1);
|
2008-07-15 09:11:00 -07:00
|
|
|
break;
|
|
|
|
case "TabClose":
|
|
|
|
this.detachTab(event.target);
|
2008-11-04 00:19:55 -08:00
|
|
|
if (this.isOpen)
|
|
|
|
this.removeClosingTabFromUI(event.target);
|
2008-07-15 09:11:00 -07:00
|
|
|
break;
|
|
|
|
case "keypress":
|
2008-08-11 02:06:42 -07:00
|
|
|
this.onKeyPress(event);
|
2008-08-09 03:18:49 -07:00
|
|
|
break;
|
2008-08-11 02:06:42 -07:00
|
|
|
case "keydown":
|
2008-07-15 09:11:00 -07:00
|
|
|
case "keyup":
|
2008-11-04 23:38:13 -08:00
|
|
|
if (event.target == this.searchField) {
|
2008-11-11 23:07:49 -08:00
|
|
|
if (event.keyCode == event.DOM_VK_RETURN) {
|
|
|
|
// If there's a pending search, kick it off now.
|
|
|
|
if (this.searchField._timer)
|
|
|
|
this.search();
|
|
|
|
this.selectThumbnail();
|
|
|
|
}
|
2008-11-04 23:38:13 -08:00
|
|
|
} else {
|
|
|
|
// Manually consume the events, as the panel is open but doesn't
|
|
|
|
// necessarily have focus.
|
|
|
|
event.stopPropagation();
|
|
|
|
event.preventDefault();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!this.sticky &&
|
|
|
|
event.type == "keyup" &&
|
|
|
|
event.keyCode == event.DOM_VK_CONTROL)
|
2008-11-04 00:19:55 -08:00
|
|
|
this.selectThumbnail();
|
2008-07-15 09:11:00 -07:00
|
|
|
break;
|
2008-11-04 23:38:13 -08:00
|
|
|
case "popupshown":
|
2008-11-06 10:45:48 -08:00
|
|
|
if (this.sticky && event.target == this.panel)
|
2008-11-04 23:38:13 -08:00
|
|
|
this.searchField.focus();
|
|
|
|
break;
|
2008-07-15 09:11:00 -07:00
|
|
|
case "popuphiding":
|
2008-11-06 10:45:48 -08:00
|
|
|
if (event.target == this.panel)
|
|
|
|
this.onPopupHiding();
|
2008-07-15 09:11:00 -07:00
|
|
|
break;
|
2008-11-04 23:38:13 -08:00
|
|
|
case "popuphidden":
|
2008-11-06 10:45:48 -08:00
|
|
|
if (event.target == this.panel) {
|
|
|
|
// Destroy the widget in order to prevent outdated content
|
|
|
|
// when re-opening the panel.
|
|
|
|
this.panel.hidden = true;
|
|
|
|
}
|
2008-11-04 23:38:13 -08:00
|
|
|
break;
|
2008-07-15 09:11:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|