1
0
mirror of https://github.com/gryf/pentadactyl-pm.git synced 2026-01-26 23:55:47 +01:00

Lots of rangefinder and Gecko 2 tabbing fixes.

This commit is contained in:
Kris Maglione
2010-08-28 18:02:03 -04:00
parent e3a2df403d
commit 4e40abe6b0
30 changed files with 856 additions and 883 deletions

View File

@@ -43,6 +43,8 @@ const Tabs = Module("tabs", {
setTimeout(function () { dactyl.focusContent(true); }, 10); // just make sure, that no widget has focus
},
get allTabs() Array.slice(config.tabbrowser.tabContainer.childNodes),
/**
* @property {Object} The previously accessed tab or null if no tab
* other than the current one has been accessed.
@@ -59,6 +61,21 @@ const Tabs = Module("tabs", {
yield [i, browsers[i]];
},
/**
* @property {number} The number of tabs in the current window.
*/
get count() config.tabbrowser.mTabs.length,
/**
* @property {Object} The local options store for the current tab.
*/
get options() {
let store = this.localStore;
if (!("options" in store))
store.options = {};
return store.options;
},
/**
* @property {boolean} Whether the tab numbering XBL binding has been
* applied.
@@ -75,20 +92,7 @@ const Tabs = Module("tabs", {
".tabbrowser-tab[busy] > .tab-icon > .tab-icon-image { list-style-image: url('chrome://global/skin/icons/loading_16.png') !important; }");
},
/**
* @property {number} The number of tabs in the current window.
*/
get count() config.tabbrowser.mTabs.length,
/**
* @property {Object} The local options store for the current tab.
*/
get options() {
let store = this.localStore;
if (!("options" in store))
store.options = {};
return store.options;
},
get visibleTabs() config.tabbrowser.visibleTabs || this.allTabs.filter(function (tab) !tab.hidden),
/**
* Returns the local state store for the tab at the specified
@@ -123,37 +127,33 @@ const Tabs = Module("tabs", {
get closedTabs() services.get("json").decode(services.get("sessionStore").getClosedTabData(window)),
/**
* Returns the index of <b>tab</b> or the index of the currently
* selected tab if <b>tab</b> is not specified. This is a 0-based
* index.
* Clones the specified <b>tab</b> and append it to the tab list.
*
* @param {Object} tab A tab from the current tab list.
* @returns {number}
* @param {Object} tab The tab to clone.
* @param {boolean} activate Whether to select the newly cloned tab.
*/
index: function (tab) {
if (tab)
return Array.indexOf(config.tabbrowser.mTabs, tab);
else
return config.tabbrowser.mTabContainer.selectedIndex;
cloneTab: function (tab, activate) {
let newTab = config.tabbrowser.addTab();
Tabs.copyTab(newTab, tab);
if (activate)
config.tabbrowser.mTabContainer.selectedItem = newTab;
return newTab;
},
// TODO: implement filter
/**
* Returns an array of all tabs in the tab list.
* Detaches the specified <b>tab</b> and open it in a new window. If no
* tab is specified the currently selected tab is detached.
*
* @returns {Object[]}
* @param {Object} tab The tab to detach.
*/
// FIXME: why not return the tab element?
// : unused? Remove me.
get: function () {
let buffers = [];
for (let [i, browser] in this.browsers) {
let title = browser.contentTitle || "(Untitled)";
let uri = browser.currentURI.spec;
let number = i + 1;
buffers.push([number, title, uri]);
}
return buffers;
detachTab: function (tab) {
if (!tab)
tab = config.tabbrowser.mTabContainer.selectedItem;
services.get("windowWatcher")
.openWindow(window, window.getBrowserURL(), null, "chrome,dialog=no,all", tab);
},
/**
@@ -171,6 +171,26 @@ const Tabs = Module("tabs", {
return -1;
},
/**
* If TabView exists, returns the Panorama window. If the Panorama
* is has not yet initialized, this function will not return until
* it has.
*
* @returns {Window}
*/
getGroups: function () {
if ("_groups" in this)
return this._groups;
if (window.TabView && TabView._initFrame)
TabView._initFrame();
let iframe = document.getElementById("tab-view");
this._groups = this._groups = iframe ? iframe.contentWindow : null;
if (this._groups)
while (!this._groups.TabItems)
dactyl.threadYield(false, true);
return this._groups;
},
/**
* Returns the tab at the specified <b>index</b> or the currently
* selected tab if <b>index</b> is not specified. This is a 0-based
@@ -180,12 +200,72 @@ const Tabs = Module("tabs", {
* @returns {Object}
*/
getTab: function (index) {
if (index != undefined)
if (index != null)
return config.tabbrowser.mTabs[index];
else
return config.tabbrowser.mCurrentTab;
},
/**
* Returns the index of <b>tab</b> or the index of the currently
* selected tab if <b>tab</b> is not specified. This is a 0-based
* index.
*
* @param {<xul:tab/>} tab A tab from the current tab list.
* @param {boolean} visible Whether to consider only visible tabs.
* @returns {number}
*/
index: function (tab, visible) {
let tabs = this[visible ? "visibleTabs" : "allTabs"];
return tabs.indexOf(tab || config.tabbrowser.mCurrentTab);
},
/**
* @param spec can either be:
* - an absolute integer
* - "" for the current tab
* - "+1" for the next tab
* - "-3" for the tab, which is 3 positions left of the current
* - "$" for the last tab
*/
indexFromSpec: function (spec, wrap) {
if (spec instanceof Node)
return this.allTabs.indexOf(spec);
let tabs = this.visibleTabs;
let position = this.index(null, true);
if (spec == null || spec === "")
return position;
if (typeof spec === "number")
position = spec;
else if (spec === "$")
position = tabs.length - 1;
else if (/^[+-]\d+$/.test(spec))
position += parseInt(spec, 10);
else if (/^\d+$/.test(spec))
position = parseInt(spec, 10);
else
return -1;
if (position >= tabs.length)
position = wrap ? position % tabs.length : tabs.length - 1;
else if (position < 0)
position = wrap ? (position % tabs.length) + tabs.length : 0;
return this.allTabs.indexOf(tabs[position]);
},
/**
* Removes all tabs from the tab list except the specified <b>tab</b>.
*
* @param {Object} tab The tab to keep.
*/
keepOnly: function (tab) {
config.tabbrowser.removeAllTabsBut(tab);
},
/**
* Lists all tabs matching <b>filter</b>.
*
@@ -206,7 +286,7 @@ const Tabs = Module("tabs", {
* list.
*/
move: function (tab, spec, wrap) {
let index = Tabs.indexFromSpec(spec, wrap);
let index = tabs.indexFromSpec(spec, wrap);
config.tabbrowser.moveTabTo(tab, index);
},
@@ -223,96 +303,31 @@ const Tabs = Module("tabs", {
*/
// FIXME: what is quitOnLastTab {1,2} all about then, eh? --djk
remove: function (tab, count, focusLeftTab, quitOnLastTab) {
let removeOrBlankTab = {
Firefox: function (tab) {
if (config.tabbrowser.mTabs.length > 1)
config.tabbrowser.removeTab(tab);
else {
if (buffer.URL != "about:blank" ||
window.getWebNavigation().sessionHistory.count > 0) {
dactyl.open("about:blank", dactyl.NEW_BACKGROUND_TAB);
config.tabbrowser.removeTab(tab);
}
else
dactyl.beep();
}
},
Thunderbird: function (tab) {
if (config.tabbrowser.mTabs.length > 1)
config.tabbrowser.removeTab(tab);
else
dactyl.beep();
},
Songbird: function (tab) {
if (config.tabbrowser.mTabs.length > 1)
config.tabbrowser.removeTab(tab);
else {
if (buffer.URL != "about:blank" || window.getWebNavigation().sessionHistory.count > 0) {
dactyl.open("about:blank", dactyl.NEW_BACKGROUND_TAB);
config.tabbrowser.removeTab(tab);
}
else
dactyl.beep();
}
}
}[config.hostApplication] || function () {};
count = Math.max(count, 1);
if (typeof count != "number" || count < 1)
count = 1;
if (quitOnLastTab >= 1 && config.tabbrowser.mTabs.length <= count) {
if (quitOnLastTab >= 1 && this.count <= count) {
if (dactyl.windows.length > 1)
window.close();
else
dactyl.quit(quitOnLastTab == 2);
return;
}
let index = this.index(tab);
if (focusLeftTab) {
let lastRemovedTab = 0;
for (let i = index; i > index - count && i >= 0; i--) {
removeOrBlankTab(this.getTab(i));
lastRemovedTab = i > 0 ? i : 1;
}
config.tabbrowser.mTabContainer.selectedIndex = lastRemovedTab - 1;
}
else {
let i = index + count - 1;
if (i >= this.count)
i = this.count - 1;
let tabs = this.visibleTabs
if (tabs.indexOf(tab) < 0)
tabs = this.allTabs;
let index = tabs.indexOf(tab);
for (; i >= index; i--)
removeOrBlankTab(this.getTab(i));
config.tabbrowser.mTabContainer.selectedIndex = index;
}
},
let next = index + (focusLeftTab ? -count : count);
if (!(next in tabs))
next = index + (focusLeftTab ? 1 : -1);
if (next in tabs)
config.tabbrowser.mTabContainer.selectedItem = tabs[next];
/**
* Removes all tabs from the tab list except the specified <b>tab</b>.
*
* @param {Object} tab The tab to keep.
*/
keepOnly: function (tab) {
config.tabbrowser.removeAllTabsBut(tab);
},
/**
* Selects the tab at the position specified by <b>spec</b>.
*
* @param {string} spec See {@link Tabs.indexFromSpec}
* @param {boolean} wrap Whether an out of bounds <b>spec</b> causes
* the selection position to wrap around the start/end of the tab
* list.
*/
select: function (spec, wrap) {
let index = Tabs.indexFromSpec(spec, wrap);
// FIXME:
if (index == -1)
dactyl.beep();
if (focusLeftTab)
tabs.slice(Math.max(0, index+1 - count), index+1).forEach(config.removeTab);
else
config.tabbrowser.mTabContainer.selectedIndex = index;
tabs.slice(index, index + count).forEach(config.removeTab);
},
/**
@@ -353,6 +368,40 @@ const Tabs = Module("tabs", {
config.tabbrowser.reloadAllTabs();
},
/**
* Selects the tab at the position specified by <b>spec</b>.
*
* @param {string} spec See {@link Tabs.indexFromSpec}
* @param {boolean} wrap Whether an out of bounds <b>spec</b> causes
* the selection position to wrap around the start/end of the tab
* list.
*/
select: function (spec, wrap) {
let index = tabs.indexFromSpec(spec, wrap);
if (index == -1)
dactyl.beep();
else
config.tabbrowser.mTabContainer.selectedIndex = index;
},
/**
* Selects the alternate tab.
*/
selectAlternateTab: function () {
dactyl.assert(tabs.alternate != null && tabs.getTab() != tabs.alternate,
"E23: No alternate page");
// NOTE: this currently relies on v.tabs.index() returning the
// currently selected tab index when passed null
let index = tabs.index(tabs.alternate);
// TODO: since a tab close is more like a bdelete for us we
// should probably reopen the closed tab when a 'deleted'
// alternate is selected
dactyl.assert(index >= 0, "E86: Buffer does not exist"); // TODO: This should read "Buffer N does not exist"
tabs.select(index);
},
/**
* Stops loading the specified tab.
*
@@ -398,7 +447,7 @@ const Tabs = Module("tabs", {
}
else {
buffer = this._lastBufferSwitchArgs;
if (allowNonUnique === undefined || allowNonUnique == null) // XXX
if (allowNonUnique == null) // XXX
allowNonUnique = this._lastBufferSwitchSpecial;
}
@@ -407,14 +456,12 @@ const Tabs = Module("tabs", {
return;
}
if (!count || count < 1)
count = 1;
if (typeof reverse != "boolean")
reverse = false;
count = Math.max(1, count || 1);
reverse = Boolean(reverse);
let matches = buffer.match(/^(\d+):?/);
if (matches) {
tabs.select(parseInt(matches[1], 10) - 1, false); // make it zero-based
tabs.select(this.allTabs[parseInt(matches[1], 10) - 1], false);
return;
}
@@ -424,8 +471,9 @@ const Tabs = Module("tabs", {
let nbrowsers = config.tabbrowser.browsers.length;
for (let [i, ] in tabs.browsers) {
let index = (i + first) % nbrowsers;
let url = config.tabbrowser.getBrowserAtIndex(index).contentDocument.location.href;
let title = config.tabbrowser.getBrowserAtIndex(index).contentDocument.title.toLowerCase();
let browser = config.tabbrowser.getBrowserAtIndex(index);
let url = browser.contentDocument.location.href;
let title = browser.contentDocument.title.toLowerCase();
if (url == buffer) {
tabs.select(index, false);
return;
@@ -434,71 +482,21 @@ const Tabs = Module("tabs", {
if (url.indexOf(buffer) >= 0 || title.indexOf(lowerBuffer) >= 0)
matches.push(index);
}
if (matches.length == 0)
dactyl.echoerr("E94: No matching buffer for " + buffer);
else if (matches.length > 1 && !allowNonUnique)
dactyl.echoerr("E93: More than one match for " + buffer);
else {
if (reverse) {
let index = (count - 1) % matches.length;
if (reverse)
index = matches.length - count;
while (index < 0)
index += matches.length;
}
else
index = (count - 1) % matches.length;
tabs.select(matches[index], false);
index = Array.indexOf(config.tabbrowser.browsers, matches[index]);
tabs.select(index, false);
}
},
/**
* Clones the specified <b>tab</b> and append it to the tab list.
*
* @param {Object} tab The tab to clone.
* @param {boolean} activate Whether to select the newly cloned tab.
*/
cloneTab: function (tab, activate) {
let newTab = config.tabbrowser.addTab();
Tabs.copyTab(newTab, tab);
if (activate)
config.tabbrowser.mTabContainer.selectedItem = newTab;
return newTab;
},
/**
* Detaches the specified <b>tab</b> and open it in a new window. If no
* tab is specified the currently selected tab is detached.
*
* @param {Object} tab The tab to detach.
*/
detachTab: function (tab) {
if (!tab)
tab = config.tabbrowser.mTabContainer.selectedItem;
services.get("windowWatcher")
.openWindow(window, window.getBrowserURL(), null, "chrome,dialog=no,all", tab);
},
/**
* Selects the alternate tab.
*/
selectAlternateTab: function () {
dactyl.assert(tabs.alternate != null && tabs.getTab() != tabs.alternate,
"E23: No alternate page");
// NOTE: this currently relies on v.tabs.index() returning the
// currently selected tab index when passed null
let index = tabs.index(tabs.alternate);
// TODO: since a tab close is more like a bdelete for us we
// should probably reopen the closed tab when a 'deleted'
// alternate is selected
dactyl.assert(index >= 0, "E86: Buffer does not exist"); // TODO: This should read "Buffer N does not exist"
tabs.select(index);
},
// NOTE: when restarting a session FF selects the first tab and then the
// tab that was selected when the session was created. As a result the
// alternate after a restart is often incorrectly tab 1 when there
@@ -520,41 +518,6 @@ const Tabs = Module("tabs", {
let tabState = services.get("sessionStore").getTabState(from);
services.get("sessionStore").setTabState(to, tabState);
},
/**
* @param spec can either be:
* - an absolute integer
* - "" for the current tab
* - "+1" for the next tab
* - "-3" for the tab, which is 3 positions left of the current
* - "$" for the last tab
*/
indexFromSpec: function (spec, wrap) {
let position = config.tabbrowser.mTabContainer.selectedIndex;
let length = config.tabbrowser.mTabs.length;
let last = length - 1;
if (spec === undefined || spec === "")
return position;
if (typeof spec === "number")
position = spec;
else if (spec === "$")
position = last;
else if (/^[+-]\d+$/.test(spec))
position += parseInt(spec, 10);
else if (/^\d+$/.test(spec))
position = parseInt(spec, 10);
else
return -1;
if (position > last)
position = wrap ? position % length : last;
else if (position < 0)
position = wrap ? (position % length) + length : 0;
return position;
}
}, {
commands: function () {
@@ -1037,7 +1000,7 @@ const Tabs = Module("tabs", {
let pref = "browser.tabStrip.autoHide";
if (options.getPref(pref) == null) // Try for FF 3.0 & 3.1
pref = "browser.tabs.autoHide";
options.safeSetPref(pref, value == 1);
options.safeSetPref(pref, value == 1, "See 'showtabline' option.");
tabStrip.collapsed = false;
}
@@ -1098,8 +1061,10 @@ const Tabs = Module("tabs", {
restriction = 2;
}
options.safeSetPref("browser.link.open_newwindow", open, "See 'popups' option.");
options.safeSetPref("browser.link.open_newwindow.restriction", restriction, "See 'popups' option.");
options.safeSetPref("browser.link.open_newwindow", open,
"See 'popups' option.");
options.safeSetPref("browser.link.open_newwindow.restriction", restriction,
"See 'popups' option.");
return values;
},
completer: function (context) [