[Pkg-mozext-commits] [tabmixplus] 01/05: Imported Upstream version 0.4.1.2~130918a
David Prévot
taffit at alioth.debian.org
Wed Sep 18 19:57:51 UTC 2013
This is an automated email from the git hooks/post-receive script.
taffit pushed a commit to branch master
in repository tabmixplus.
commit dc250c13b3fb670e726d14af387f8783807defa7
Author: David Prévot <taffit at debian.org>
Date: Wed Sep 18 14:42:33 2013 -0400
Imported Upstream version 0.4.1.2~130918a
---
chrome/content/changecode.js | 231 ++++++++++++--------
chrome/content/click/click.js | 15 +-
chrome/content/extensions/extensions.js | 4 +-
chrome/content/links/contentLinks.js | 26 ++-
chrome/content/links/newTab.xul | 24 +-
chrome/content/links/setup.js | 103 ++++-----
chrome/content/minit/minit.js | 11 +-
chrome/content/minit/tabView.js | 6 -
chrome/content/minit/tablib.js | 115 ++++++----
chrome/content/overlay/browsr.css | 59 +++--
chrome/content/places/places.js | 178 +++------------
chrome/content/preferences/appearance.js | 12 +-
chrome/content/preferences/appearance.xul | 2 +-
chrome/content/preferences/mouse.js | 5 +
chrome/content/preferences/mouse.xul | 28 ++-
chrome/content/preferences/session.js | 2 +
chrome/content/preferences/shortcuts.xml | 2 +-
chrome/content/session/session.js | 81 +++++--
chrome/content/session/sessionStore.js | 27 ++-
chrome/content/tab/scrollbox.xml | 2 +-
chrome/content/tab/tab.js | 192 ++++++++++------
chrome/content/tab/tabbrowser_4.xml | 89 +++++---
chrome/content/tabmix.js | 203 ++++++++++++-----
chrome/content/utils.js | 63 +++---
chrome/skin/app_version/4.0/linux/browser.css | 2 +-
chrome/skin/app_version/4.0/mac/browser.css | 2 +-
chrome/skin/app_version/4.0/win/browser.css | 7 +-
chrome/skin/tab.css | 8 +-
defaults/preferences/tabmix.js | 6 +
install.rdf | 4 +-
modules/AutoReload.jsm | 3 +-
modules/MergeWindows.jsm | 3 +-
modules/Places.jsm | 173 +++++++++++++++
modules/RenameTab.jsm | 6 +-
modules/Services.jsm | 38 +++-
modules/Shortcuts.jsm | 7 +-
.../{SessionManagerAddon.jsm => AddonManager.jsm} | 97 +++++---
modules/extensions/TabGroupsManager.jsm | 7 +-
modules/log.jsm | 146 +++++++++----
39 files changed, 1244 insertions(+), 745 deletions(-)
diff --git a/chrome/content/changecode.js b/chrome/content/changecode.js
index 9979388..edda63c 100644
--- a/chrome/content/changecode.js
+++ b/chrome/content/changecode.js
@@ -1,112 +1,157 @@
+Tabmix._eval = function(name, code) name ? eval(name + " = " + code) : eval("(" + code + ")");
+// Tabmix._eval is on the first line to help us get the right line number
+
// don't use strict for this file
// so we don't evaluat all code as strict mode code
-function Tabmix_ChangeCode(aParams) {
- this.obj = aParams.obj;
- this.fnName = aParams.fnName;
- this.fullName = aParams.fullName;
+// aOptions can be: getter, setter or forceUpdate
+Tabmix.changeCode = function(aParent, aName, aOptions) {
+ let console = TabmixSvc.console;
+ let debugMode = Tabmix._debugMode;
+
+ function ChangeCode(aParams) {
+ this.obj = aParams.obj;
+ this.fnName = aParams.fnName;
+ this.fullName = aParams.fullName;
- let options = aParams.options;
- this.needUpdate = options && options.forceUpdate || false;
+ let options = aParams.options;
+ this.needUpdate = options && options.forceUpdate || false;
- if (options && (options.setter || options.getter)) {
- let type = options.setter ? "__lookupSetter__" : "__lookupGetter__";
- this.value = this.obj[type](this.fnName).toString();
+ if (options && (options.setter || options.getter)) {
+ this.type = options.setter ? "__lookupSetter__" : "__lookupGetter__";
+ this.value = this.obj[this.type](this.fnName).toString();
+ }
+ else if (typeof this.obj[this.fnName] == "function")
+ this.value = this.obj[this.fnName].toString();
+ else
+ this.errMsg = "\n" + this.fullName + " is undefined.";
+ this.notFound = [];
}
- else if (typeof this.obj[this.fnName] == "function")
- this.value = this.obj[this.fnName].toString();
- else
- this.errMsg = "\n" + this.fullName + " is undefined.";
- this.notFound = [];
-}
-Tabmix_ChangeCode.prototype = {
- value: "", errMsg: "",
- _replace: function TMP_utils__replace(substr ,newString, aParams) {
- var silent;
- if (typeof aParams != "undefined") {
- let doReplace, flags;
- if (typeof aParams == "object") {
- doReplace = "check" in aParams ? aParams.check : true;
- flags = aParams.flags;
- silent = aParams.silent
+ ChangeCode.prototype = {
+ value: "", errMsg: "",
+ _replace: function TMP_utils__replace(substr ,newString, aParams) {
+ var silent;
+ if (typeof aParams != "undefined") {
+ let doReplace, flags;
+ if (typeof aParams == "object") {
+ doReplace = "check" in aParams ? aParams.check : true;
+ flags = aParams.flags;
+ silent = aParams.silent
+ }
+ else if (typeof aParams == "boolean") {
+ doReplace = aParams;
+ }
+ if (!doReplace)
+ return this;
+ if (flags && typeof substr == "string")
+ substr = new RegExp(substr.replace(/[{[(\\^.$|?*+\/)\]}]/g, "\\$&"), flags);
}
- else if (typeof aParams == "boolean") {
- doReplace = aParams;
+
+ var exist = typeof(substr) == "string" ? this.value.indexOf(substr) > -1 : substr.test(this.value);
+ if (exist) {
+ this.value = this.value.replace(substr, newString);
+ this.needUpdate = true;
}
- if (!doReplace)
- return this;
- if (flags && typeof substr == "string")
- substr = new RegExp(substr.replace(/[{[(\\^.$|?*+\/)\]}]/g, "\\$&"), flags);
- }
+ else if (!silent)
+ this.notFound.push(substr);
+ return this;
+ },
- var exist = typeof(substr) == "string" ? this.value.indexOf(substr) > -1 : substr.test(this.value);
- if (exist) {
- this.value = this.value.replace(substr, newString);
- this.needUpdate = true;
- }
- else if (!silent)
- this.notFound.push(substr);
- return this;
- },
-
- toCode: function TMP_utils_toCode(aShow, aObj, aName) {
- try {
- if (Tabmix._debugMode) {
- this.value = this.value.replace("{", "{try {") +
- ' catch (ex) {Tabmix.assert(ex, "outer try-catch in ' + (aName || this.fullName) + '");}}';
+ toCode: function TMP_utils_toCode(aShow, aObj, aName) {
+ try {
+ // list of function that we don't warp with try-catch
+ let dontDebug = ["gBrowser.tabContainer._animateTabMove"];
+ if (debugMode && dontDebug.indexOf(this.fullName) == -1) {
+ let excludeReturn = ["TabsInTitlebar._update", "gBrowser._blurTab"];
+ let addReturn = "", re = new RegExp("//.*", "g");
+ if (excludeReturn.indexOf(this.fullName) == -1 &&
+ /return\s.+/.test(this.value.replace(re, "")))
+ addReturn = "\nreturn null\n";
+ this.value = this.value.replace("{", "{try {") +
+ ' catch (ex) {' +
+ ' TabmixSvc.console.assert(ex, "outer try-catch in ' + (aName || this.fullName) + '");}' +
+ addReturn +
+ ' }';
+ }
+ let [obj, fnName] = [aObj || this.obj, aName || this.fnName];
+ if (this.isValidToChange(fnName)) {
+ if (obj)
+ Tabmix.setNewFunction(obj, fnName, Tabmix._eval(null, this.value));
+ else
+ Tabmix._eval(fnName, this.value);
+ }
+ if (aShow)
+ this.show(obj, fnName);
+ } catch (ex) {
+ Components.utils.reportError("Tabmix " + console.callerName() + " failed to change " + this.fullName + "\nError: " + ex.message);
}
+ },
+
+ defineProperty: function(aObj, aName, aCode) {
+ if (!this.type)
+ throw "Tabmix:\n" + this.fullName + " don't have setter or getter";
+
let [obj, fnName] = [aObj || this.obj, aName || this.fnName];
- if (this.isValidToChange(fnName))
- Tabmix.toCode(obj, fnName, this.value);
- if (aShow)
- this.show(obj, fnName);
- } catch (ex) {
- Components.utils.reportError("Tabmix " + Tabmix.callerName() + " failed to change " + this.fullName + "\nError: " + ex.message);
- }
- },
-
- show: function(aObj, aName) {
- if (aObj && aName in aObj)
- Tabmix.show({obj: aObj, name: aName, fullName: this.fullName});
- else if (this.fullName != null)
- Tabmix.show(this.fullName);
- },
-
- isValidToChange: function(aName) {
- var notFoundCount = this.notFound.length;
- if (this.needUpdate && !notFoundCount)
- return true;
- var caller = Tabmix._getCallerNameByIndex(2);
- if (notFoundCount) {
- let str = (notFoundCount > 1 ? "s" : "") + "\n ";
- Tabmix.clog(caller + " was unable to change " + aName + "."
- + (this.errMsg || "\ncan't find string" + str + this.notFound.join("\n "))
- + "\n\nTry Tabmix latest development version from tmp.garyr.net/tab_mix_plus-dev-build.xpi,"
- + "\nReport about this to Tabmix developer at http://tmp.garyr.net/forum/");
- if (Tabmix._debugMode)
- Tabmix.clog(caller + "\nfunction " + aName + " = " + this.value);
+ let descriptor = {enumerable: true, configurable: true}
+
+ let setDescriptor = function(type) {
+ let fnType = "__lookup#ter__".replace("#", type);
+ type = type.toLowerCase();
+ let code = aCode && aCode[type + "ter"] ||
+ this.type == fnType ? this.value : obj[fnType](fnName);
+
+ if (typeof code == "string")
+ descriptor[type] = Tabmix._eval(null, code);
+ else if (typeof code != "undefined")
+ descriptor[type] = code;
+ }.bind(this);
+
+ setDescriptor("Get");
+ setDescriptor("Set");
+
+ Object.defineProperty(obj, fnName, descriptor);
+ },
+
+ show: function(aObj, aName) {
+ if (aObj && aName in aObj)
+ console.show({obj: aObj, name: aName, fullName: this.fullName});
+ else if (this.fullName != null) {
+ let win = typeof window != "undefined" ? window : undefined;
+ console.show(this.fullName, 500, win);
+ }
+ },
+
+ isValidToChange: function(aName) {
+ var notFoundCount = this.notFound.length;
+ if (this.needUpdate && !notFoundCount)
+ return true;
+ var caller = console.getCallerNameByIndex(2);
+ if (notFoundCount) {
+ let str = (notFoundCount > 1 ? "s" : "") + "\n ";
+ console.clog(caller + " was unable to change " + aName + "."
+ + (this.errMsg || "\ncan't find string" + str + this.notFound.join("\n "))
+ + "\n\nTry Tabmix latest development version from tmp.garyr.net/tab_mix_plus-dev-build.xpi,"
+ + "\nReport about this to Tabmix developer at http://tmp.garyr.net/forum/");
+ if (debugMode)
+ console.clog(caller + "\nfunction " + aName + " = " + this.value);
+ }
+ else if (!this.needUpdate && debugMode)
+ console.clog(caller + " no update needed to " + aName);
+ return false;
}
- else if (!this.needUpdate && Tabmix._debugMode)
- Tabmix.clog(caller + " no update needed to " + aName);
- return false;
}
-}
-Tabmix.defineProperty = function(aObj, aName, aCode) {
- for (let [type, val] in Iterator(aCode)) {
- if (typeof val == "string")
- aCode[type] = eval("(" + val + ")");
+ let fnName = aName.split(".").pop();
+ try {
+ return new ChangeCode({obj: aParent, fnName: fnName,
+ fullName: aName, options: aOptions});
+ } catch (ex) {
+ console.clog(console.callerName() + " failed to change " + aName + "\nError: " + ex.message);
+ if (debugMode)
+ console.obj(aObject, "aObject");
}
- Object.defineProperty(aObj, aName, {get: aCode.getter, set: aCode.setter,
- enumerable: true, configurable: true});
-}
-
-Tabmix.toCode = function(aObj, aName, aCodeString) {
- if (aObj)
- this.setNewFunction(aObj, aName, eval("(" + aCodeString + ")"));
- else
- eval(aName + " = " + aCodeString);
+ return null;
}
Tabmix.setNewFunction = function(aObj, aName, aCode) {
diff --git a/chrome/content/click/click.js b/chrome/content/click/click.js
index 44f2655..c54e9af 100644
--- a/chrome/content/click/click.js
+++ b/chrome/content/click/click.js
@@ -20,7 +20,7 @@ var TabmixTabClickOptions = {
var target = aEvent.originalTarget;
var anonid = target.getAttribute("anonid");
this._blockDblClick = aEvent.button == 0 && anonid == "tmp-close-button" ||
- target == gBrowser.tabContainer.mTabsNewtabButton;
+ target.classList.contains("tabs-newtab-button");
// don't do anything if user left click on close tab button , or on any other button on tab or tabbar
if (aEvent.button == 0 && (anonid == "tmp-close-button" || target.localName == "toolbarbutton"))
@@ -290,7 +290,7 @@ var TabmixContext = {
this._closeRightTabs = "context_closeTabsToTheEnd";
}
- if (Tabmix.isVersion(250)) {
+ if (Tabmix._restoreMultipleTabs) {
let multipletablabel = $id("context_undoCloseTab").getAttribute("multipletablabel")
let undoCloseTabMenu = $id("tm-content-undoCloseTab");
undoCloseTabMenu.setAttribute("singletablabel", undoCloseTabMenu.label);
@@ -575,9 +575,11 @@ var TabmixContext = {
var undoClose = Tabmix.prefs.getBoolPref("undoClose");
Tabmix.showItem(undoCloseTabMenu, !contentClick && !gContextMenu.isTextSelected && undoClose && !closeTabsEmpty &&
Tabmix.prefs.getBoolPref("undoCloseTabContent"));
- let closedTabCount = Tabmix.isVersion(250) ? TabmixSvc.ss.getNumberOfTabsClosedLast(window) : 1;
- let visibleLabel = closedTabCount <= 1 ? "singletablabel" : "multipletablabel";
- undoCloseTabMenu.setAttribute("label", undoCloseTabMenu.getAttribute(visibleLabel));
+ if (Tabmix._restoreMultipleTabs) {
+ let closedTabCount = TabmixSvc.ss.getNumberOfTabsClosedLast(window);
+ let visibleLabel = closedTabCount <= 1 ? "singletablabel" : "multipletablabel";
+ undoCloseTabMenu.setAttribute("label", undoCloseTabMenu.getAttribute(visibleLabel));
+ }
var undoCloseListMenu = document.getElementById("tm-content-undoCloseList");
Tabmix.showItem(undoCloseListMenu, !contentClick && !gContextMenu.isTextSelected && undoClose && !closeTabsEmpty &&
@@ -674,7 +676,8 @@ var TabmixContext = {
if (links_urlSecurityCheck(url)) {
if (check)
return false;
- urls.push(url);
+ if (urls.indexOf(url) == -1)
+ urls.push(url);
}
nextEpisode = treeWalker.nextNode();
}
diff --git a/chrome/content/extensions/extensions.js b/chrome/content/extensions/extensions.js
index cea15a5..d74d3f0 100644
--- a/chrome/content/extensions/extensions.js
+++ b/chrome/content/extensions/extensions.js
@@ -280,14 +280,14 @@ var TMP_extensionsCompatibility = {
).toCode();
}
- // fix bug in superDargandGo
+ // fix bug in superDargandGo https://addons.mozilla.org/he/firefox/addon/super-dragandgo/
try {
if ("superDrag" in window && "contentAreaDNDObserver" in window) {
Tabmix.changeCode(contentAreaDNDObserver, "contentAreaDNDObserver.onDrop")._replace(
'document.firstChild.getAttribute("windowtype")',
'window.document.documentElement.getAttribute("windowtype")'
)._replace(
- 'preventBubble()',
+ 'preventBubble()', /* fix bug in superDargandGo */
'stopPropagation()'
).toCode();
}
diff --git a/chrome/content/links/contentLinks.js b/chrome/content/links/contentLinks.js
index f8fe997..13de2ad 100644
--- a/chrome/content/links/contentLinks.js
+++ b/chrome/content/links/contentLinks.js
@@ -154,6 +154,11 @@ Tabmix.contentAreaClick = {
return ["current", true];
}
+ // check this after we check for suppressTabsOnFileDownload
+ // for the case the link have a matche in our list
+ if (typeof event.tabmix_openLinkWithHistory == "boolean")
+ return ["current"];
+
// don't mess with links that have onclick inside iFrame
let onClickInFrame = this._data.onclick && linkNode.ownerDocument.defaultView.frameElement;
@@ -209,6 +214,9 @@ Tabmix.contentAreaClick = {
},
contentLinkClick: function TMP_contentLinkClick(aEvent) {
+ if (typeof aEvent.tabmix_openLinkWithHistory == "boolean")
+ return;
+
if (aEvent.button != 0 || aEvent.shiftKey || aEvent.ctrlKey || aEvent.altKey || aEvent.metaKey)
return;
@@ -246,17 +254,15 @@ Tabmix.contentAreaClick = {
if (isGmail)
return;
- // don't interrupt with noscript
- if ("className" in linkNode && linkNode.className.indexOf("__noscriptPlaceholder__") > -1)
- return;
-
- // fix donwload button on page - http://get.adobe.com/reader/
- if ("className" in linkNode && /download.button/.test(linkNode.className))
- return;
+ if ("className" in linkNode) {
+ // don't interrupt with noscript
+ if (linkNode.className.indexOf("__noscriptPlaceholder__") > -1)
+ return;
- // need to find a way to work here only on links
- if ("className" in linkNode && /button/.test(linkNode.className.toLowerCase()))
- return;
+ // need to find a way to work here only on links
+ if (/button/.test(linkNode.className.toLowerCase()))
+ return;
+ }
// don't interrupt with fastdial links
if ("ownerDocument" in linkNode && Tabmix.isNewTabUrls(linkNode.ownerDocument.documentURI))
diff --git a/chrome/content/links/newTab.xul b/chrome/content/links/newTab.xul
index 017e8e9..856f878 100644
--- a/chrome/content/links/newTab.xul
+++ b/chrome/content/links/newTab.xul
@@ -11,14 +11,15 @@
if (!gGrid.cells)
return;
let win = Tabmix.getTopWin();
+ if (win)
+ win.TMP_Places._titlefrombookmark = Tabmix.prefs.getBoolPref("titlefrombookmark");
gGrid.cells.forEach(function (cell) {
let site = cell.site;
if (!site)
return;
let url = site.url;
let title = site.title || url;
- if (Tabmix.prefs.getBoolPref("titlefrombookmark"))
- title = win.TMP_Places.getTitleFromBookmark(url, title);
+ title = win.TMP_Places.getTitleFromBookmark(url, title);
let tooltip = (title == url ? title : title + "\n" + url);
let link = site._querySelector(".newtab-link");
link.setAttribute("title", tooltip);
@@ -26,15 +27,16 @@
});
}
- XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils", "resource://gre/modules/PlacesUtils.jsm");
- Services.prefs.addObserver("extensions.tabmix.titlefrombookmark", updateTitle, false);
- window.addEventListener("unload", function TMP_removeObserver(aEvent) {
- aEvent.currentTarget.removeEventListener("unload", TMP_removeObserver, false);
- Services.prefs.removeObserver("extensions.tabmix.titlefrombookmark", updateTitle);
- }, false);
-
- if (Tabmix.prefs.getBoolPref("titlefrombookmark"))
- updateTitle();
+ let win = Tabmix.getTopWin()
+ if (win && win.Tabmix && win.Tabmix.initialization.onWindowOpen.initialized) {
+ Services.prefs.addObserver("extensions.tabmix.titlefrombookmark", updateTitle, false);
+ window.addEventListener("unload", function TMP_removeObserver(aEvent) {
+ aEvent.currentTarget.removeEventListener("unload", TMP_removeObserver, false);
+ Services.prefs.removeObserver("extensions.tabmix.titlefrombookmark", updateTitle);
+ }, false);
+ if (Tabmix.prefs.getBoolPref("titlefrombookmark"))
+ updateTitle();
+ }
]]>
</script>
diff --git a/chrome/content/links/setup.js b/chrome/content/links/setup.js
index 3216b24..c75839d 100644
--- a/chrome/content/links/setup.js
+++ b/chrome/content/links/setup.js
@@ -45,37 +45,34 @@ Tabmix.linkHandling_init = function TMP_TBP_init(aWindowType) {
}
/**
- * @brief Force-call the window observer at least one time.
- *
- * @returns Nothing.
- *
* @Theme Vista-aero 3.0.0.91 and BlueSky 3.0.0.91 use TMP_TBP_Startup in stylesheet
* window[onload="TMP_TBP_Startup()"]
*/
function TMP_TBP_Startup() {
- // don't start Tabmix at all if our tabbrowser_4.xml didn't start
- // when ImTranslator extension installed
- if (!Tabmix.initialized) {
- Tabmix.initialized = true;
- if (Tabmix.isVersion(160) && "gBrowserInit" in window)
- gBrowserInit.onLoad();
- else
- BrowserStartup();
- return;
- }
+ let onLoad = Tabmix.initialization.run("beforeBrowserInitOnLoad");
+ if (onLoad)
+ onLoad();
+ else if (Tabmix.isVersion(160) && "gBrowserInit" in window)
+ gBrowserInit.onLoad();
+ else
+ BrowserStartup();
+}
- TabmixSvc.windowStartup.init(window);
+Tabmix.beforeBrowserInitOnLoad = function() {
+ try {
+ TabmixSvc.windowStartup.init(window);
+ } catch (ex) {this.assert(ex);}
try {
// replace old Settings.
// we must call this before any other tabmix function
gTMPprefObserver.updateSettings();
gTMPprefObserver.init();
- } catch (ex) {Tabmix.assert(ex);}
+ } catch (ex) {this.assert(ex);}
try {
var SM = TabmixSessionManager;
- if (Tabmix.isVersion(200)) {
+ if (this.isVersion(200)) {
SM.globalPrivateBrowsing = PrivateBrowsingUtils.permanentPrivateBrowsing;
SM.isWindowPrivate = function SM_isWindowPrivate(aWindow) PrivateBrowsingUtils.isWindowPrivate(aWindow);
// isPrivateWindow is boolean property of this window, user can't change private status of a window
@@ -101,11 +98,11 @@ function TMP_TBP_Startup() {
var fnContainer, TMP_BrowserStartup;
if ("__ezsidebar__BrowserStartup" in window) // need to test this on firefox 16+
[fnContainer, TMP_BrowserStartup] = [window, "__ezsidebar__BrowserStartup"];
- else if (Tabmix.isVersion(160) && "gBrowserInit" in window)
+ else if (this.isVersion(160) && "gBrowserInit" in window)
[fnContainer, TMP_BrowserStartup] = [gBrowserInit, "onLoad"];
else
[fnContainer, TMP_BrowserStartup] = [window, "BrowserStartup"];
- var bowserStartup = Tabmix.changeCode(fnContainer, TMP_BrowserStartup);
+ var bowserStartup = this.changeCode(fnContainer, TMP_BrowserStartup);
// Bug 756313 - Don't load homepage URI before first paint
// moved this code from gBrowserInit.onLoad to gBrowserInit._delayedStartup
@@ -119,24 +116,24 @@ function TMP_TBP_Startup() {
' gBrowser.tabContainer.adjustTabstrip(true, url);' +
' $&' +
' }'
- if (!Tabmix.isVersion(190))
+ if (!this.isVersion(190))
bowserStartup = bowserStartup._replace(swapOldCode, swapNewCode);
- var firstWindow = Tabmix.firstWindowInSession || SM.firstNonPrivateWindow;
+ var firstWindow = this.firstWindowInSession || SM.firstNonPrivateWindow;
var disAllow = SM.isPrivateWindow || TMP_SessionStore.isSessionStoreEnabled() ||
- Tabmix.extensions.sessionManager ||
- Tabmix.isWindowAfterSessionRestore;
- var sessionManager = Tabmix.prefs.getBoolPref("sessions.manager");
+ this.extensions.sessionManager ||
+ this.isWindowAfterSessionRestore;
+ var sessionManager = this.prefs.getBoolPref("sessions.manager");
var resumeSession = sessionManager &&
- Tabmix.prefs.getIntPref("sessions.onStart") < 2;
- var recoverSession = Tabmix.prefs.getBoolPref("sessions.crashRecovery") &&
- Tabmix.prefs.prefHasUserValue("sessions.crashed");
+ this.prefs.getIntPref("sessions.onStart") < 2;
+ var recoverSession = this.prefs.getBoolPref("sessions.crashRecovery") &&
+ this.prefs.prefHasUserValue("sessions.crashed");
SM.doRestore = !disAllow && firstWindow && (recoverSession || resumeSession);
if (SM.doRestore) {
// Prevent the default homepage from loading if we're going to restore a session
- if (Tabmix.isVersion(250)) {
- Tabmix.changeCode(gBrowserInit, "gBrowserInit._getUriToLoad")._replace(
+ if (this.isVersion(240)) {
+ this.changeCode(gBrowserInit, "gBrowserInit._getUriToLoad")._replace(
'sessionStartup.willOverrideHomepage', 'true'
).toCode();
}
@@ -159,14 +156,14 @@ function TMP_TBP_Startup() {
' }' +
'$&'
- if (!Tabmix.isVersion(190)) {
+ if (!this.isVersion(190)) {
bowserStartup = bowserStartup._replace(
'if (window.opener && !window.opener.closed', loadOnStartup
);
}
}
// All-in-One Sidebar 0.7.14 brake Firefox 12.0
- if (Tabmix.isVersion(120) && typeof aios_dominitSidebar == "function") {
+ if (this.isVersion(120) && typeof aios_dominitSidebar == "function") {
bowserStartup = bowserStartup._replace(
'TabsOnTop.syncCommand();',
'TabsOnTop.init();', {silent: true}
@@ -175,12 +172,12 @@ function TMP_TBP_Startup() {
bowserStartup.toCode();
// At the moment we must init TabmixSessionManager before sessionStore.init
- var [obj, fn] = Tabmix.isVersion(160) && "gBrowserInit" in window ?
+ var [obj, fn] = this.isVersion(160) && "gBrowserInit" in window ?
[gBrowserInit, "gBrowserInit._delayedStartup"] :
[window, "delayedStartup"];
- Tabmix.changeCode(obj, fn)._replace(
- 'Services.obs.addObserver', loadOnStartup, {check: Tabmix.isVersion(190) && !!loadOnStartup}
+ this.changeCode(obj, fn)._replace(
+ 'Services.obs.addObserver', loadOnStartup, {check: this.isVersion(190) && !!loadOnStartup}
)._replace(
'Services.obs.addObserver',
'try {' +
@@ -188,14 +185,14 @@ function TMP_TBP_Startup() {
'} catch (ex) {Tabmix.assert(ex);}' +
'$&'
)._replace(
- swapOldCode, swapNewCode, {check: Tabmix.isVersion(190)}
+ swapOldCode, swapNewCode, {check: this.isVersion(190)}
)._replace(
'SessionStore.canRestoreLastSession',
- 'TabmixSessionManager.canRestoreLastSession', {check: Tabmix.isVersion(250) && sessionManager}
+ 'TabmixSessionManager.canRestoreLastSession', {check: this.isVersion(250) && sessionManager}
).toCode();
// look for installed extensions that are incompatible with tabmix
- if (Tabmix.firstWindowInSession && Tabmix.prefs.getBoolPref("disableIncompatible")) {
+ if (this.firstWindowInSession && this.prefs.getBoolPref("disableIncompatible")) {
setTimeout(function checkCompatibility(aWindow) {
let tmp = { };
Components.utils.import("resource://tabmixplus/extensions/CompatibilityCheck.jsm", tmp);
@@ -206,26 +203,18 @@ function TMP_TBP_Startup() {
// add tabmix menu item to tab context menu before menumanipulator and MenuEdit initialize
TabmixContext.buildTabContextMenu();
- TMP_BrowserStartup = fnContainer[TMP_BrowserStartup].bind(fnContainer);
- TMP_BrowserStartup();
+ return fnContainer[TMP_BrowserStartup].bind(fnContainer);
- } catch (ex) {Tabmix.assert(ex);}
+ } catch (ex) {this.assert(ex);}
+
+ return null;
}
// this must run before all
-Tabmix.initialized = false;
Tabmix.beforeStartup = function TMP_beforeStartup(tabBrowser, aTabContainer) {
- this.singleWindowMode = this.prefs.getBoolPref("singleWindow");
- if (this.singleWindowMode) {
- let tmp = { };
- Components.utils.import("resource://tabmixplus/SingleWindowModeUtils.jsm", tmp);
- // don't initialize Tabmix functions for a window that is about to
- // close by SingleWindowModeUtils
- if (tmp.SingleWindowModeUtils.newWindow(window))
- return;
- }
+ if (typeof tabBrowser == "undefined")
+ tabBrowser = gBrowser;
- this.initialized = true;
// return true if all tabs in the window are blank
tabBrowser.isBlankWindow = function() {
for (var i = 0; i < this.tabs.length; i++) {
@@ -274,7 +263,6 @@ Tabmix.beforeStartup = function TMP_beforeStartup(tabBrowser, aTabContainer) {
var tabContainer = aTabContainer || tabBrowser.tabContainer ||
document.getAnonymousElementByAttribute(tabBrowser, "anonid", "tabcontainer");
- TMP_eventListener.init(tabContainer);
// Firefox sessionStore and session manager extension start to add tab before our onWindowOpen run
// so we initialize this before start
// mTabMaxWidth not exist from firefox 4.0
@@ -310,11 +298,6 @@ Tabmix.beforeStartup = function TMP_beforeStartup(tabBrowser, aTabContainer) {
TMP_SessionStore.afterSwitchThemes = true;
TMP_extensionsCompatibility.preInit();
-
- if (this.prefs.prefHasUserValue("enableDebug") &&
- this.prefs.getBoolPref("enableDebug")) {
- this._debugMode = true;
- }
}
Tabmix.adjustTabstrip = function tabContainer_adjustTabstrip(skipUpdateScrollStatus, aUrl) {
@@ -389,3 +372,9 @@ Tabmix.adjustTabstrip = function tabContainer_adjustTabstrip(skipUpdateScrollSta
TabmixTabbar.updateBeforeAndAfter();
}
}
+
+// temporary property for Aurora 25.0a2 users with version before 2013-09-12
+// replace it with Tabmix.isVersion(260) once Firefox 25.0 is out
+XPCOMUtils.defineLazyGetter(Tabmix, "_restoreMultipleTabs", function() {
+ return typeof TabmixSvc.ss.setNumberOfTabsClosedLast == "function"
+});
diff --git a/chrome/content/minit/minit.js b/chrome/content/minit/minit.js
index 8f00308..6032c60 100644
--- a/chrome/content/minit/minit.js
+++ b/chrome/content/minit/minit.js
@@ -1178,10 +1178,15 @@ Tabmix.navToolbox = {
// update physical position
let useTabmixButtons = TabmixTabbar.scrollButtonsMode > TabmixTabbar.SCROLL_BUTTONS_LEFT_RIGHT;
TabmixTabbar.setScrollButtonBox(useTabmixButtons, true, true);
- if (useTabmixButtons && document.getElementById("TabsToolbar").hasAttribute("tabstripoverflow")) {
- let tabStrip = gBrowser.tabContainer.mTabstrip;
- tabStrip._scrollButtonUp.collapsed = tabStrip._scrollButtonDown.collapsed = false;
+ let tabBar = gBrowser.tabContainer;
+ if (useTabmixButtons && tabBar.overflow) {
+ tabBar.mTabstrip._scrollButtonUp.collapsed = false;
+ tabBar.mTabstrip._scrollButtonDown.collapsed = false;
}
}
+
+ // reset tabsNewtabButton and afterTabsButtonsWidth
+ if (typeof privateTab == "object")
+ TMP_eventListener.updateMultiRow(true);
}
}
diff --git a/chrome/content/minit/tabView.js b/chrome/content/minit/tabView.js
index 70050be..96cbe77 100644
--- a/chrome/content/minit/tabView.js
+++ b/chrome/content/minit/tabView.js
@@ -187,12 +187,6 @@
/* ............... TabmixSessionManager TabView Data ............... */
- TabmixSessionManager._sendWindowStateEvent = function SM__sendWindowStateEvent(aType) {
- let event = document.createEvent("Events");
- event.initEvent("SSWindowState" + aType, true, false);
- window.dispatchEvent(event);
- }
-
// aWindow: rdfNodeWindow to read from
TabmixSessionManager._setWindowStateBusy = function SM__setWindowStateBusy(aWindow) {
TMP_SessionStore.initService();
diff --git a/chrome/content/minit/tablib.js b/chrome/content/minit/tablib.js
index 93bcea9..5e5a678 100644
--- a/chrome/content/minit/tablib.js
+++ b/chrome/content/minit/tablib.js
@@ -19,8 +19,7 @@ var tablib = {
// we update this value in TabmixProgressListener.listener.onStateChange
aBrowser.tabmix_allowLoad = !TabmixTabbar.lockallTabs;
Tabmix.changeCode(aBrowser, "browser.loadURIWithFlags")._replace(
- '{',
- '$&' +
+ 'if (!aURI)',
' var newURI, allowLoad = this.tabmix_allowLoad != false || aURI.match(/^javascript:/);' +
' try {' +
' if (!allowLoad) {' +
@@ -39,9 +38,14 @@ var tablib = {
' browser.stop();' +
' browser.tabmix_allowLoad = true;' +
' browser.loadURIWithFlags(aURI, aFlags, aReferrerURI, aCharset, aPostData);' +
- ' return;' +
+ ' return newTab;' +
' }' +
- ' this.tabmix_allowLoad = aURI == "about:blank" || !isLockedTab;'
+ ' this.tabmix_allowLoad = aURI == "about:blank" || !isLockedTab;\n' +
+ ' $&'
+ )._replace(
+ /(\})(\)?)$/,
+ 'return null;\
+ $1$2'
)._replace(
'this.webNavigation.LOAD_FLAGS_FROM_EXTERNAL',
'Ci.nsIWebNavigation.LOAD_FLAGS_FROM_EXTERNAL', {check: "loadTabsProgressively" in window }
@@ -77,7 +81,7 @@ var tablib = {
dontMove = params.dontMove || null;'
)._replace(
't.setAttribute("label", aURI);',
- 't.setAttribute("label", TabmixTabbar.widthFitTitle ? this.mStringBundle.getString("tabs.connecting") : aURI);'
+ 't.setAttribute("label", TabmixTabbar.widthFitTitle && aURI.indexOf("about") != 0 ? this.mStringBundle.getString("tabs.connecting") : aURI);'
)._replace(
't.className = "tabbrowser-tab";',
'$&\
@@ -191,7 +195,11 @@ var tablib = {
Tabmix.changeCode(gBrowser, "gBrowser.getWindowTitleForBrowser")._replace(
'if (!docTitle)',
- 'docTitle = TMP_Places.getTabTitle(this.getTabForBrowser(aBrowser), aBrowser.currentURI.spec, docTitle);\
+ 'let tab = this.getTabForBrowser(aBrowser);\
+ if (tab.hasAttribute("tabmix_changed_label"))\
+ docTitle = tab.getAttribute("tabmix_changed_label");\
+ else\
+ docTitle = TMP_Places.getTabTitle(tab, aBrowser.currentURI.spec, docTitle);\
$&'
).toCode();
@@ -222,6 +230,11 @@ var tablib = {
'if (aTab.label == title',
'if (aTab.hasAttribute("mergeselected"))\
title = "(*) " + title;\
+ if (aTab.hasAttribute("tabmix_changed_label")) {\
+ aTab.removeAttribute("tabmix_changed_label");\
+ if (aTab.label == title && aTab.crop == crop)\
+ tablib.onTabTitleChanged(aTab, title == urlTitle);\
+ }\
$&'
)._replace(
'aTab.crop = crop;',
@@ -236,10 +249,16 @@ var tablib = {
).toCode();
// Follow up bug 887515 - add ability to restore multiple tabs
- if (Tabmix.isVersion(250)) {
+ // bug 914258 backout 887515 changes from Firefox 25
+ if (Tabmix._restoreMultipleTabs) {
Tabmix.changeCode(gBrowser, "gBrowser.removeTabsToTheEndFrom")._replace(
- 'ss.setNumberOfTabsClosedLast(window, numberOfTabsToClose);',
- 'this.setNumberOfTabsClosedLast();'
+ 'let tabs = this.getTabsToTheEndFrom(aTab);',
+ '$&\n'+
+ ' Tabmix.startCountingClosedTabs();'
+ )._replace(
+ '#1.setNumberOfTabsClosedLast(window, numberOfTabsToClose);'.
+ replace("#1", Tabmix.isVersion(260) ? "SessionStore" : "ss"),
+ 'Tabmix.setNumberOfTabsClosedLast();'
).toCode();
}
},
@@ -390,7 +409,7 @@ var tablib = {
'{if(!Tabmix.prefs.getBoolPref("selectTabOnMouseDown") && Tabmix.isCallerInList("' + callerName + '")) return;'
).toCode();
- let _setter = Tabmix.changeCode(tabBar, "gBrowser.tabContainer.visible", {setter: true})._replace(
+ Tabmix.changeCode(tabBar, "gBrowser.tabContainer.visible", {setter: true})._replace(
'this._container.collapsed = !val;',
' if (TabmixTabbar.hideMode == 2)' +
' val = false;' +
@@ -400,11 +419,7 @@ var tablib = {
' bottomToolbox.collapsed = !val;' +
' gTMPprefObserver.updateTabbarBottomPosition();' +
' }'
- );
- Tabmix.defineProperty(tabBar, "visible", {
- getter: tabBar.__lookupGetter__("visible"),
- setter: _setter.value
- });
+ ).defineProperty();
},
@@ -641,7 +656,8 @@ var tablib = {
// if user changed mode to single window mode while having closed window
// make sure that undoCloseWindow will open the closed window in the most recent non-private window
Tabmix.changeCode(window, "undoCloseWindow")._replace(
- 'window = ss.undoCloseWindow(aIndex || 0);',
+ 'window = #1.undoCloseWindow(aIndex || 0);'.
+ replace("#1", Tabmix.isVersion(260) ? "SessionStore" : "ss"),
'{if (Tabmix.singleWindowMode) {\
window = TabmixSvc.version(200) ?\
Tabmix.RecentWindow.getMostRecentBrowserWindow({private: false}) :\
@@ -650,13 +666,13 @@ var tablib = {
if (window) {\
window.focus();\
let index = aIndex || 0;\
- let closedWindows = TabmixSvc.JSON.parse(ss.getClosedWindowData());\
- ss.forgetClosedWindow(index);\
+ let closedWindows = TabmixSvc.JSON.parse(#1.getClosedWindowData());\
+ #1.forgetClosedWindow(index);\
let state = closedWindows.splice(index, 1).shift();\
state = TabmixSvc.JSON.stringify({windows: [state]});\
- ss.setWindowState(window, state, false);\
+ #1.setWindowState(window, state, false);\
}\
- else $&}'
+ else $&}'.replace("#1", Tabmix.isVersion(260) ? "SessionStore" : "ss", "g")
)._replace(
'return window;',
'TabmixSessionManager.notifyClosedWindowsChanged();\
@@ -692,11 +708,8 @@ var tablib = {
).toCode();
Tabmix.changeCode(HistoryMenu.prototype, "HistoryMenu.prototype.populateUndoWindowSubmenu")._replace(
- 'JSON.parse(this._ss.getClosedWindowData());',
- '"parse" in JSON ? JSON.parse(this._ss.getClosedWindowData()) : TabmixSvc.JSON.parse(this._ss.getClosedWindowData());'
- )._replace(
'this._ss',
- 'TabmixSvc.ss', {flags: "g"}
+ 'TabmixSvc.ss', {check: !Tabmix.isVersion(260), flags: "g"}
)._replace(
'this._rootElt.getElementsByClassName("recentlyClosedWindowsMenu")[0];',
'this._rootElt ? this._rootElt.getElementsByClassName("recentlyClosedWindowsMenu")[0] : document.getElementById(arguments[0]);'
@@ -737,6 +750,9 @@ var tablib = {
popup.setAttribute("context", "tm_undocloseWindowContextMenu");
Tabmix.changeCode(window, "switchToTabHavingURI")._replace(
+ 'function switchIfURIInWindow',
+ 'let switchIfURIInWindow = $&', {check: Tabmix._debugMode}
+ )._replace(
'gBrowser.selectedBrowser.loadURI(aURI.spec);',
'{$& \
gBrowser.ensureTabIsVisible(gBrowser.selectedTab);}'
@@ -773,7 +789,7 @@ var tablib = {
// sessionstore duplicateTab failed
if (!newTab)
- retuen;
+ return null;
this.selectedBrowser.focus();
@@ -847,7 +863,8 @@ var tablib = {
else {
aTab._tabmixCopyToWindow = {data: aTabData};
// replaceTabWithWindow not working if there is only one tab in the the window
- window.openDialog(getBrowserURL(), "_blank", "chrome,dialog=no,all", aTab);
+ window.openDialog("chrome://browser/content/browser.xul",
+ "_blank", "chrome,dialog=no,all", aTab);
}
}
@@ -888,8 +905,9 @@ var tablib = {
}
var event = document.createEvent("Events");
- event.initEvent("click", true, true);
- event.getPreventDefault = function () { return false; }
+ event.initEvent("click", true, false);
+ event.tabmix_openLinkWithHistory = true;
+ event.button = 0;
gContextMenu.target.dispatchEvent(event);
newTab = aTab;
@@ -934,12 +952,12 @@ var tablib = {
// remove current tab last
if (!this.mCurrentTab.pinned)
tabs.unshift(tabs.splice(tabs.indexOf(this.mCurrentTab), 1)[0]);
- this.startCountingClosedTabs();
+ Tabmix.startCountingClosedTabs();
tabs.reverse().forEach(function TMP_removeTab(tab) {
if (!tab.pinned)
this.removeTab(tab, {animate: false});
}, this);
- this.setNumberOfTabsClosedLast();
+ Tabmix.setNumberOfTabsClosedLast();
// _handleTabSelect will call mTabstrip.ensureElementIsVisible
}
}
@@ -954,7 +972,7 @@ var tablib = {
if (this.warnAboutClosingTabs(this.closingTabsEnum.GROUP, null, aDomain)) {
var childNodes = this.visibleTabs;
- this.startCountingClosedTabs();
+ Tabmix.startCountingClosedTabs();
for (var i = childNodes.length - 1; i > -1; --i) {
if (childNodes[i] != aTab && !childNodes[i].pinned &&
this.getBrowserForTab(childNodes[i]).currentURI.spec.indexOf(aDomain) != -1)
@@ -964,7 +982,7 @@ var tablib = {
this.removeTab(aTab, {animate: true});
this.ensureTabIsVisible(this.selectedTab);
}
- this.setNumberOfTabsClosedLast();
+ Tabmix.setNumberOfTabsClosedLast();
}
}
@@ -992,12 +1010,12 @@ var tablib = {
let childNodes = this.visibleTabs;
let tabPos = childNodes.indexOf(aTab);
- this.startCountingClosedTabs();
+ Tabmix.startCountingClosedTabs();
for (let i = childNodes.length - 1; i > tabPos; i--) {
if (!childNodes[i].pinned)
this.removeTab(childNodes[i]);
}
- this.setNumberOfTabsClosedLast();
+ Tabmix.setNumberOfTabsClosedLast();
}
}
@@ -1013,12 +1031,12 @@ var tablib = {
let childNodes = this.visibleTabs;
let tabPos = childNodes.indexOf(aTab);
- this.startCountingClosedTabs();
+ Tabmix.startCountingClosedTabs();
for (let i = tabPos - 1; i >= 0; i--) {
if (!childNodes[i].pinned)
this.removeTab(childNodes[i]);
}
- this.setNumberOfTabsClosedLast();
+ Tabmix.setNumberOfTabsClosedLast();
}
}
@@ -1033,12 +1051,12 @@ var tablib = {
var childNodes = this.visibleTabs;
if (TabmixTabbar.visibleRows > 1)
this.tabContainer.updateVerticalTabStrip(true)
- this.startCountingClosedTabs();
+ Tabmix.startCountingClosedTabs();
for (var i = childNodes.length - 1; i >= 0; --i) {
if (childNodes[i] != aTab && !childNodes[i].pinned)
this.removeTab(childNodes[i]);
}
- this.setNumberOfTabsClosedLast();
+ Tabmix.setNumberOfTabsClosedLast();
}
});
@@ -1513,17 +1531,18 @@ var tablib = {
}
// Follow up bug 887515 - add ability to restore multiple tabs
- if (Tabmix.isVersion(250)) {
- gBrowser.startCountingClosedTabs = function() {
+ // bug 914258 backout 887515 changes from Firefox 25
+ if (Tabmix._restoreMultipleTabs) {
+ Tabmix.startCountingClosedTabs = function() {
this.shouldCountClosedTabs = true;
this.numberOfTabsClosedLast = 0;
}
- gBrowser.setNumberOfTabsClosedLast = function(aNum) {
+ Tabmix.setNumberOfTabsClosedLast = function(aNum) {
TabmixSvc.ss.setNumberOfTabsClosedLast(window, aNum || this.numberOfTabsClosedLast);
this.shouldCountClosedTabs = false;
this.numberOfTabsClosedLast = 0;
}
- gBrowser.countClosedTabs = function(aTab) {
+ Tabmix.countClosedTabs = function(aTab) {
if (!this.shouldCountClosedTabs ||
Services.prefs.getIntPref("browser.sessionstore.max_tabs_undo") == 0)
return;
@@ -1537,9 +1556,9 @@ var tablib = {
}
}
else {
- gBrowser.startCountingClosedTabs = function() { }
- gBrowser.setNumberOfTabsClosedLast = function() { }
- gBrowser.countClosedTabs = function() { }
+ Tabmix.startCountingClosedTabs = function() { }
+ Tabmix.setNumberOfTabsClosedLast = function() { }
+ Tabmix.countClosedTabs = function() { }
}
/** DEPRECATED **/
@@ -1576,12 +1595,12 @@ var tablib = {
let width = aTab.boxObject.width;
aTab.removeAttribute("width");
if (width != aTab.boxObject.width)
- TMP_Places.afterTabTitleChanged();
+ TMP_Places.afterTabTitleChanged(true);
if (aTab.hasAttribute("newtab"))
aTab.removeAttribute("newtab");
}
else if (aTab.hasAttribute("fadein"))
- TMP_Places.afterTabTitleChanged();
+ TMP_Places.afterTabTitleChanged(true);
// don't keep unnecessary reference to current tab
if (!TMP_Places.inUpdateBatch)
TMP_Places.currentTab = null;
@@ -1688,7 +1707,7 @@ var tablib = {
// we always show our prompt on Mac
var showPrompt = Tabmix.isPlatform("Mac") || !isAfterFirefoxPrompt();
// get caller caller name and make sure we are not on restart
- var quitType = Tabmix._getCallerNameByIndex(2);
+ var quitType = Tabmix.getCallerNameByIndex(2);
var askBeforSave = quitType != "restartApp" && quitType != "restart";
var isLastWindow = Tabmix.isLastBrowserWindow;
var result = TabmixSessionManager.deinit(isLastWindow, askBeforSave);
diff --git a/chrome/content/overlay/browsr.css b/chrome/content/overlay/browsr.css
index 6b774d8..8d04792 100644
--- a/chrome/content/overlay/browsr.css
+++ b/chrome/content/overlay/browsr.css
@@ -116,21 +116,18 @@ label.text-link, label[onclick] {
visibility: collapse !important;
}
-#TabsToolbar:not([tabstripoverflow]) > #tabmixScrollBox,
+#tabbrowser-tabs:not([overflow="true"]) ~ #tabmixScrollBox,
#tabmixScrollBox[flowing="singlebar"],
#tabmixScrollBox[defaultScrollButtons] {
visibility: collapse;
}
-/*** hide tabs-newtab-button that we don't use
- *
- * we set newtab_side only for left ot right side afterlast position rules are set by Firefox
- *
- ***/
-#tabbrowser-tabs:not([tabmix-visible])[overflow="true"] > .tabbrowser-arrowscrollbox > .tabs-newtab-button,
-#TabsToolbar:not([tabmix-visible])[newTabButton=false] .tabbrowser-arrowscrollbox > .tabs-newtab-button,
-#TabsToolbar:not([tabmix-visible])[disAllowNewtabbutton] .tabbrowser-arrowscrollbox > .tabs-newtab-button,
-#TabsToolbar:not([tabmix-visible])[newtab_side] .tabbrowser-arrowscrollbox > .tabs-newtab-button {
+/*** hide tabs-newtab-button that we don't use ***/
+#TabsToolbar:not([currentset*="privateTab-toolbar-openNewPrivateTab"]) #privateTab-afterTabs-openNewPrivateTab,
+#tabbrowser-tabs[overflow="true"] > .tabbrowser-arrowscrollbox > .tabs-newtab-button,
+#TabsToolbar:not([tabmix-show-newtabbutton]) .tabbrowser-arrowscrollbox > .tabs-newtab-button[command="cmd_newNavigatorTab"],
+#TabsToolbar[tabmix-show-newtabbutton*="side"] .tabbrowser-arrowscrollbox > .tabs-newtab-button {
+ /* using visibility: hidden !important; don't collapse the width and don't collapse padding and border height */
visibility: collapse;
height: 0px !important;
width: 0px;
@@ -139,27 +136,51 @@ label.text-link, label[onclick] {
vertical-align: bottom;
}
-#TabsToolbar:not([newTabButton=false]):not([disAllowNewtabbutton]):not([newtab_side]) >
- #tabbrowser-tabs:not([overflow="true"]) > .tabbrowser-arrowscrollbox > .tabs-newtab-button {
+#TabsToolbar[tabmix-show-newtabbutton="aftertabs"]:not([customizing="true"]) >
+ #tabbrowser-tabs:not([overflow="true"]) > .tabbrowser-arrowscrollbox > .tabs-newtab-button[command="cmd_newNavigatorTab"] {
visibility: visible;
}
-#TabsToolbar[tabmix-visible] .tabbrowser-arrowscrollbox > .tabs-newtab-button { /* look in tabmix.js */
+#TabsToolbar[tabmix-show-newtabbutton="afterTabs-force"] .tabbrowser-arrowscrollbox > .tabs-newtab-button { /* look in tabmix.js */
visibility: visible !important;
}
-#TabsToolbar[newTabButton=true][tabstripoverflow] > #new-tab-button,
-#TabsToolbar[newTabButton=true][disAllowNewtabbutton]:not([tabstripoverflow]):not([newtab_side]) > #new-tab-button,
-#TabsToolbar[newTabButton=true][newtab_side] > #new-tab-button {
+#TabsToolbar[tabmix-show-newtabbutton*="side"] > #new-tab-button {
visibility: visible;
}
/* In vertical tabbar the default rules from chrome://browser/content/browser.css are sufficient */
-#TabsToolbar:not([orient="vertical"]):not([disAllowNewtabbutton]):not([tabstripoverflow]):not([newtab_side]) > #new-tab-button,
-#TabsToolbar[newTabButton=false] > #new-tab-button {
+#TabsToolbar:not([orient="vertical"])[tabmix-show-newtabbutton*="aftertabs"] > #new-tab-button,
+#TabsToolbar:not([tabmix-show-newtabbutton]) > #new-tab-button {
visibility: collapse;
}
+/*** Private-tab compatibility ***/
+#privateTab-afterTabs-openNewPrivateTab {
+ vertical-align: bottom;
+}
+
+#TabsToolbar[currentset*="privateTab-toolbar-openNewPrivateTab"]:not([tabmix-show-newtabbutton])
+ > #tabbrowser-tabs:not([overflow="true"]) > .tabbrowser-arrowscrollbox > .tabs-newtab-button[command="cmd_newNavigatorTab"] {
+ display: none; /* override privateTab visibility: visible !important; */
+}
+
+#TabsToolbar[currentset*="privateTab-toolbar-openNewPrivateTab"][tabmix-show-newtabbutton*="side"]
+ > #tabbrowser-tabs:not([overflow="true"]) > .tabbrowser-arrowscrollbox > .tabs-newtab-button {
+ display: none; /* override privateTab visibility: visible !important; */
+}
+
+#TabsToolbar[currentset*="privateTab-toolbar-openNewPrivateTab"][tabmix-show-newtabbutton*="aftertabs"]
+ > #privateTab-toolbar-openNewPrivateTab {
+ visibility: collapse; /* missing rule form privateTab */
+}
+
+#TabsToolbar[currentset*="privateTab-toolbar-openNewPrivateTab"][tabmix-show-newtabbutton*="aftertabs"]:not([customizing="true"])
+ > #tabbrowser-tabs > .tabbrowser-arrowscrollbox > #privateTab-afterTabs-openNewPrivateTab,
+#TabsToolbar[tabmix-show-newtabbutton*="side"] > #privateTab-toolbar-openNewPrivateTab {
+ visibility: visible;
+}
+
/*** Tab opening animation ***/
.tab-progress-container > .tab-progress:not([fadein]):not([pinned]),
.tab-icon:not([fadein]):not([pinned]) > .tab-protect-icon,
@@ -169,7 +190,7 @@ label.text-link, label[onclick] {
display: none !important;
}
-/* we have display: -moz-box !important; in browsroverlay_base.css
+/* we use display: -moz-box !important;
so display: none !important; is not hide the button */
.tab-close-button:not([fadein]) {
opacity: 0;
diff --git a/chrome/content/places/places.js b/chrome/content/places/places.js
index 6823a6d..aea94e8 100644
--- a/chrome/content/places/places.js
+++ b/chrome/content/places/places.js
@@ -24,7 +24,6 @@ var TMP_Places = {
},
init: function TMP_PC_init() {
- this.initPlacesUIUtils();
this.contextMenu.toggleEventListener(true);
// use tab label for bookmark name when user renamed the tab
@@ -35,12 +34,11 @@ var TMP_Places = {
'TMP_Places.getTabTitle(gBrowser.getTabForBrowser(aBrowser), url.spec) || $&'
).toCode();
- let getter = Tabmix.changeCode(PlacesCommandHook, "uniqueCurrentPages", {getter: true})._replace(
+ Tabmix.changeCode(PlacesCommandHook, "uniqueCurrentPages", {getter: true})._replace(
'URIs.push(tab.linkedBrowser.currentURI);',
'let uri = tab.linkedBrowser.currentURI; \
URIs.push({uri: uri, title: TMP_Places.getTabTitle(tab, uri.spec)});'
- );
- Tabmix.defineProperty(PlacesCommandHook, "uniqueCurrentPages", {getter: getter.value});
+ ).defineProperty();
}
if ("PlacesViewBase" in window && PlacesViewBase.prototype) {
@@ -60,7 +58,7 @@ var TMP_Places = {
// fix small bug when the event is not mouse event
// inverse focus of middle/ctrl/meta clicked bookmarks/history
- // when we are in single window mode set the function to retuen "tab"
+ // when we are in single window mode set the function to return "tab"
Tabmix.changeCode(window, "whereToOpenLink")._replace(
'var middle = !ignoreButton && e.button == 1;',
'var middle = e instanceof MouseEvent && !ignoreButton && e.button == 1;'
@@ -78,9 +76,9 @@ var TMP_Places = {
Tabmix.changeCode(window, "openUILinkIn")._replace(
'params.fromChrome = true;',
'$&' +
+ /* only in use when openUILinkIn called from searchbar.doSearch */
' var tabmixArg = arguments.length > 5 ? arguments[5] : null;' +
' if (tabmixArg) {' +
- ' params.bookMarkId = "bookMarkId" in tabmixArg && tabmixArg.bookMarkId > -1 ? tabmixArg.bookMarkId : null;' +
' if ("backgroundPref" in tabmixArg)' +
' params.inBackground = getBoolPref(tabmixArg.backgroundPref);' +
' }' +
@@ -95,8 +93,7 @@ var TMP_Places = {
Tabmix.changeCode(fnObj, fnName)._replace(
/aRelatedToCurrent\s*= params.relatedToCurrent;/,
'$& \
- var bookMarkId = params.bookMarkId; \
- var backgroundPref = params.backgroundPref;'
+ var bookMarkId = params.bookMarkId;'
)._replace(
'where == "current" && w.gBrowser.selectedTab.pinned',
'$& && !params.suppressTabsOnFileDownload'
@@ -107,9 +104,6 @@ var TMP_Places = {
)._replace(
/Services.ww.openWindow[^;]*;/,
'let newWin = $&\n if (newWin && bookMarkId)\n newWin.bookMarkIds = bookMarkId;'
- )._replace( // we probably don't need this since Firefox 10
- 'aFromChrome ?',
- '$& getBoolPref(backgroundPref) ||'
)._replace(
'w.gBrowser.loadURIWithFlags(url, flags, aReferrerURI, null, aPostData);',
'$&\
@@ -133,141 +127,10 @@ var TMP_Places = {
}
},
- functions: ["_openTabset", "openURINodesInTabs", "openContainerNodeInTabs", "openNodeWithEvent", "_openNodeIn"],
- initPlacesUIUtils: function TMP_PC_initPlacesUIUtils(forceInit) {
- var treeStyleTab = "TreeStyleTabBookmarksService" in window;
- // we enter getURLsForContainerNode into TMP_Places to prevent leakes from PlacesUtils
- if (!this.getURLsForContainerNode && !treeStyleTab) {
- Tabmix.changeCode(PlacesUtils, "PlacesUtils.getURLsForContainerNode")._replace(
- '{uri: child.uri,',
- '{id: child.itemId, uri: child.uri,', {flags: "g"}
- )._replace(
- 'this.', 'PlacesUtils.', {flags: "g"}
- ).toCode(false, TMP_Places, "getURLsForContainerNode");
- }
-
- try {
- let test = PlacesUIUtils._openTabset.toString();
- } catch (ex) {
- if (window.document.documentElement.getAttribute("windowtype") == "navigator:browser") {
- Tabmix.log("Starting with Firefox 21 Imacros 8.3.0 break toString on PlacesUIUtils functions."
- + "\nTabmix can't update PlacesUIUtils to work according to Tabmix preferences, use Imacros 8.3.1 and up.");
- }
- return;
- }
-
- if (!forceInit) {
- if (PlacesUIUtils.tabmix_inited) {
- PlacesUIUtils.tabmix_inited++;
- return;
- }
- PlacesUIUtils.tabmix_inited = 1;
- }
- this._first_instance = true;
- this.functions.forEach(function(aFn) {
- PlacesUIUtils["tabmix_" + aFn] = PlacesUIUtils[aFn];
- });
-
- var treeStyleTab = "TreeStyleTabBookmarksService" in window;
- function updateOpenTabset() {
- var loadTabsCode = "browserWindow.$1.loadTabs(urls, loadInBackground, false);"
- loadTabsCode = loadTabsCode.replace("$1", "gBrowser");
- var openGroup = "browserWindow.TMP_Places.openGroup(urls, ids, where$1);"
- Tabmix.changeCode(PlacesUIUtils, "PlacesUIUtils._openTabset")._replace(
- 'urls = []',
- 'behavior, $&', {check: treeStyleTab}
- )._replace(
- 'var urls = [];',
- '$& var ids = [];', {check: !treeStyleTab}
- )._replace(
- 'urls.push(item.uri);',
- '$& ids.push(item.id);', {check: !treeStyleTab}
- )._replace(
- '"chrome,dialog=no,all", args);',
- '$&\
- browserWindow.bookMarkIds = ids.join("|");'
- )._replace(
- /let openGroupBookmarkBehavior =|TSTOpenGroupBookmarkBehavior =/,
- '$& behavior =', {check: treeStyleTab}
- )._replace(
- loadTabsCode,
- 'var changeWhere = where == "tabshifted" && aEvent.target.localName != "menuitem"; \
- if (changeWhere) where = "current";'
- + openGroup.replace("$1", treeStyleTab ? ", behavior" : "")
- ).toCode();
- }
- if (treeStyleTab) {
- window.setTimeout(function () {updateOpenTabset();}, 0);
- }
- else { // TreeStyleTab not installed
- updateOpenTabset();
-
- Tabmix.changeCode(PlacesUIUtils, "PlacesUIUtils.openURINodesInTabs")._replace(
- 'push({uri: aNodes[i].uri,',
- 'push({id: aNodes[i].itemId, uri: aNodes[i].uri,'
- ).toCode();
-
- Tabmix.changeCode(PlacesUIUtils, "PlacesUIUtils.openContainerNodeInTabs")._replace(
- 'PlacesUtils.getURLsForContainerNode(aNode)',
- 'TMP_Places.getURLsForContainerNode(aNode)'
- ).toCode();
- }
-
- Tabmix.changeCode(PlacesUIUtils, "PlacesUIUtils.openNodeWithEvent")._replace(
- /whereToOpenLink\(aEvent[,\s\w]*\), window/, '$&, aEvent'
- ).toCode();
-
- // Don't change "current" when user click context menu open (callee is PC_doCommand and aWhere is current)
- // we disable the open menu when the tab is lock
- // the 2nd check for aWhere == "current" is for non Firefox code that may call this function
- Tabmix.changeCode(PlacesUIUtils, "PlacesUIUtils._openNodeIn")._replace(
- /(function[^\(]*\([^\)]+)(\))/,
- '$1, TMP_Event$2'
- )._replace(
- 'aWindow.openUILinkIn',
- 'if (TMP_Event) aWhere = TMP_Places.isBookmarklet(aNode.uri) ? "current" : '
- + 'aWindow.TMP_Places.fixWhereToOpen(TMP_Event, aWhere); \
- else if (aWhere == "current" && !TMP_Places.isBookmarklet(aNode.uri)) {\
- let caller = Tabmix._getCallerNameByIndex(2);\
- if (caller != "PC_doCommand")\
- aWhere = aWindow.TMP_Places.fixWhereToOpen(null, aWhere);\
- }\
- if (aWhere == "current") Tabmix.getTopWin().gBrowser.mCurrentBrowser.tabmix_allowLoad = true;\
- $&'
- )._replace(
- 'inBackground:',
- 'bookMarkId: aNode.itemId, initiatingDoc: null,\
- $&'
- ).toCode();
- },
-
deinit: function TMP_PC_deinit() {
- let placesCount = --PlacesUIUtils.tabmix_inited;
- if (this._first_instance || placesCount == 0) {
- this.functions.forEach(function(aFn) {
- PlacesUIUtils[aFn] = PlacesUIUtils["tabmix_" + aFn];
- delete PlacesUIUtils["tabmix_" + aFn];
- });
- this.getURLsForContainerNode = null;
- delete PlacesUIUtils.tabmix_inited;
- }
-
- // when we close the window from which we run eval on PlacesUIUtils
- // we need to do it again on the new window, or else PlacesUtils will be undefined in PlacesUIUtils
- if (this._first_instance) {
- let win = Tabmix.getTopWin() || Services.wm.getMostRecentWindow("Places:Organizer");
- if (win) {
- PlacesUIUtils.tabmix_inited = placesCount;
- win.TMP_Places.initPlacesUIUtils(true);
- }
- }
-
this.stopObserver();
},
- getURLsForContainerNode: null,
- _first_instance: false,
-
// update compatibility with X-notifier(aka WebMail Notifier) 2.9.13+
// object name wmn replace with xnotifier for version 3.0+
getXnotifierFunction: function(aName) {
@@ -483,11 +346,13 @@ var TMP_Places = {
if (title != aTab.label) {
aTab.label = title;
aTab.crop = title != aUrl || aUrl == "about:blank" ? "end" : "center";
+ aTab.setAttribute("tabmix_changed_label", title);
gBrowser._tabAttrModified(aTab);
if (aTab.selected)
gBrowser.updateTitlebar();
if (!aTab.hasAttribute("faviconized"))
aTab.removeAttribute("width");
+ this._tabTitleChanged = true;
return true;
}
return false;
@@ -569,11 +434,14 @@ var TMP_Places = {
return false;
},
- afterTabTitleChanged: function TMP_PC_afterTabTitleChanged() {
+ afterTabTitleChanged: function TMP_PC_afterTabTitleChanged(aChanged) {
+ if (!aChanged && !this._tabTitleChanged)
+ return;
if (this.inUpdateBatch) {
this._tabTitleChanged = true;
return;
}
+ this._tabTitleChanged = false;
TabmixTabbar.updateScrollStatus();
TabmixTabbar.updateBeforeAndAfter();
if (this.currentTab) {
@@ -648,6 +516,7 @@ var TMP_Places = {
}, this);
this.stopObserver();
}
+ this.afterTabTitleChanged();
},
_hasBookmarksObserver: false,
@@ -673,12 +542,15 @@ var TMP_Places = {
let getIndex = function(url) aUrl.indexOf(url) + 1;
Array.forEach(gBrowser.tabs, function(tab) {
let url = tab.linkedBrowser.currentURI.spec;
+ if (this.isUserRenameTab(tab, url))
+ return;
let index = this.applyCallBackOnUrl(url, getIndex);
- if (index && !this.isUserRenameTab(tab, url)) {
+ if (index) {
tab.setAttribute("tabmix_bookmarkId", aItemId[index-1]);
this.setTabTitle(tab, url);
}
}, this);
+ this.afterTabTitleChanged();
},
updateTitleonTabs: function TMP_PC_updateTitleonTabs(aItemId, aRemoved) {
@@ -691,7 +563,7 @@ var TMP_Places = {
let tabs = gBrowser.tabContainer.getElementsByAttribute(ID, batch ? "*" : aItemId);
Array.slice(tabs).forEach(function(tab) {
if (!batch ||
- aItemId.indexOf(parseInt(tab.getAttribute(ID)))) {
+ aItemId.indexOf(parseInt(tab.getAttribute(ID))) > -1) {
tab.removeAttribute(ID);
let url = tab.linkedBrowser.currentURI.spec;
if (!this.isUserRenameTab(tab, url)) {
@@ -702,6 +574,7 @@ var TMP_Places = {
}
}
}, this);
+ this.afterTabTitleChanged();
},
onItemAdded: function TMP_PC_onItemAdded(aItemId, aFolder, aIndex, aItemType, aURI) {
@@ -749,12 +622,8 @@ var TMP_Places = {
this._batchData = {updateIDs:[], add:{ids:[], urls:[]}};
- if (this._tabTitleChanged) {
- this._tabTitleChanged = false;
- this.afterTabTitleChanged(this.currentTab);
- }
- else
- this.currentTab = null;
+ this.afterTabTitleChanged();
+ this.currentTab = null;
},
onItemVisited: function () {},
@@ -817,3 +686,10 @@ TMP_Places.contextMenu = {
}
}
}
+
+/** DEPRECATED **/
+TMP_Places.getTabFixedTitle = function(aBrowser, aUri) {
+ let win = aBrowser.ownerDocument.defaultView;
+ Tabmix.log("TMP_Places.getTabFixedTitle was deprecated\nuse TMP_Places.getTabTitle(tab, url)")
+ return win.TMP_Places.getTabTitle(win.gBrowser.getTabForBrowser(aBrowser), aUri);
+}
diff --git a/chrome/content/preferences/appearance.js b/chrome/content/preferences/appearance.js
index 6e2814e..bd083f9 100644
--- a/chrome/content/preferences/appearance.js
+++ b/chrome/content/preferences/appearance.js
@@ -50,8 +50,10 @@ var gAppearancePane = {
hbox.setAttribute("align","center");
}
- this.toolbarButtons(browserWindow);
gPrefWindow.initPane("paneAppearance");
+ // call this function after initPane
+ // we update some broadcaster that initPane may reset
+ this.toolbarButtons(browserWindow);
},
tabCloseButtonChanged: function() {
@@ -108,14 +110,14 @@ var gAppearancePane = {
onPlate.childNodes[1].hidden = onPlate.childNodes.length > 2;
// Display > Tab bar
- function updateDisabledState(buttonID, itemID) {
+ function updateDisabledState(buttonID, itemID, aEnable) {
let button = aWindow.document.getElementById(buttonID);
let enablePosition = button && button.parentNode == aWindow.gBrowser.tabContainer._container;
gPrefWindow.setDisabled(itemID, !enablePosition || null);
- gPrefWindow.setDisabled("obs_" + itemID, !enablePosition || null);
+ gPrefWindow.setDisabled("obs_" + itemID, !aEnable || !enablePosition || null);
}
- updateDisabledState("new-tab-button", "newTabButton");
- updateDisabledState("alltabs-button", "hideAllTabsButton");
+ updateDisabledState("new-tab-button", "newTabButton", $("pref_newTabButton").value);
+ updateDisabledState("alltabs-button", "hideAllTabsButton", true);
if (this._tabmixCustomizeToolbar) {
delete this._tabmixCustomizeToolbar;
diff --git a/chrome/content/preferences/appearance.xul b/chrome/content/preferences/appearance.xul
index 6458dd9..b98a281 100644
--- a/chrome/content/preferences/appearance.xul
+++ b/chrome/content/preferences/appearance.xul
@@ -150,7 +150,7 @@
<textbox id="maxrow" size="2" maxlength="2" preference="pref_maxrow" type="number" min="2"/>
</hbox>
<checkbox_tmp id="offsetAmountToScroll" label="&offsetAmountToScroll.label;"
- preference="pref_offsetAmountToScroll" style="height: 22px; margin: 2px;"/>
+ preference="pref_offsetAmountToScroll" style="height: 26px;"/>
<checkbox_tmp id="smoothScroll" label="&smoothScroll.label;" preference="pref_smoothScroll"/>
<hbox align="center" id="clickToScroll.scrollDelay">
<label value="&scrolldelay.label;" TSTdisabled="true" observes="obs_smoothScroll"/>
diff --git a/chrome/content/preferences/mouse.js b/chrome/content/preferences/mouse.js
index 8e4e8a5..12f3e07 100644
--- a/chrome/content/preferences/mouse.js
+++ b/chrome/content/preferences/mouse.js
@@ -33,6 +33,7 @@ var gMousePane = {
this.clickTabbar = $("ClickTabbar");
this.clickTabbar.appendChild(this.clickTab.firstChild.cloneNode(true));
this.updatePanelPrefs($("tabclick").selectedIndex);
+ this.updateBroadcaster($("pref_tabbarscrolling").value);
gPrefWindow.initPane("paneMouse");
},
@@ -64,6 +65,10 @@ var gMousePane = {
ensureElementIsVisible: function (aPopup) {
var scrollBox = document.getAnonymousElementByAttribute(aPopup, "class", "popup-internal-box");
scrollBox.ensureElementIsVisible(aPopup.parentNode.selectedItem);
+ },
+
+ updateBroadcaster: function (val) {
+ Tabmix.setItem('obs_tabbarscrolling', 'disabled', val == 2 || null);
}
}
diff --git a/chrome/content/preferences/mouse.xul b/chrome/content/preferences/mouse.xul
index 1f2dfe8..0360772 100644
--- a/chrome/content/preferences/mouse.xul
+++ b/chrome/content/preferences/mouse.xul
@@ -28,7 +28,8 @@
name="extensions.tabmix.mouseOverSelectDelay" type="int"/>
<preference id="pref_tabFlip" name="extensions.tabmix.tabFlip" type="bool"/>
<preference id="pref_tabFlipDelay" name="extensions.tabmix.tabFlipDelay" type="int"/>
- <preference id="pref_tabbarscrolling" name="extensions.tabmix.enableScrollSwitch" type="bool"/>
+ <preference id="pref_tabbarscrolling" name="extensions.tabmix.scrollTabs" type="int"
+ onchange="gMousePane.updateBroadcaster(this.value)"/>
<preference id="pref_reversescrolling" name="extensions.tabmix.reversedScroll" type="bool"/>
<preference id="pref_mouseDownSelect" name="extensions.tabmix.selectTabOnMouseDown"
type="bool" inverted="true"/>
@@ -98,16 +99,25 @@
</groupbox>
<!-- Tabbar Scrolling -->
<groupbox flex="1">
- <caption label="&tabbarscrolling.caption;"/>
+ <caption>
+ <checkbox_tmp id="enableTabsScroll" label="&tabbarscrolling.caption;"
+ preference="pref_tabbarscrolling"
+ onsyncfrompreference="return $('pref_tabbarscrolling').value != 2"
+ onsynctopreference="var val = this.checked ? this.tabbarscrolling : 2;
+ this.tabbarscrolling = $('tabbarscrolling').value;
+ return val;"/>
+ </caption>
<separator class="thin"/>
- <label value="&tabbarscrolling.holdShift.label;"/>
- <radiogroup id="tabbarscrolling" boolean="true" orient="horizontal"
+ <label value="&tabbarscrolling.holdShift.label;" observes="obs_tabbarscrolling"/>
+ <radiogroup id="tabbarscrolling" orient="horizontal"
preference="pref_tabbarscrolling">
- <radio value="true" id="tabbarscrolling-select" label="&tabbarscrolling.selectTab.label;"/>
- <radio value="false" id="tabbarscrolling-default" label="&tabbarscrolling.scrollAllTabs.label;"/>
+ <radio value="1" id="tabbarscrolling-select" label="&tabbarscrolling.selectTab.label;"
+ observes="obs_tabbarscrolling"/>
+ <radio value="0" id="tabbarscrolling-default" label="&tabbarscrolling.scrollAllTabs.label;"
+ observes="obs_tabbarscrolling"/>
</radiogroup>
<checkbox_tmp id="reversescrolling" label="&tabbarscrolling.inverse.label;"
- preference="pref_reversescrolling"/>
+ preference="pref_reversescrolling" observes="obs_tabbarscrolling"/>
</groupbox>
</tabpanel>
<tabpanel align="start">
@@ -188,5 +198,9 @@
<broadcaster id="obs_tabFlip"/>
</broadcasterset>
+ <broadcasterset>
+ <broadcaster id="obs_tabbarscrolling"/>
+ </broadcasterset>
+
</prefpane>
</overlay>
diff --git a/chrome/content/preferences/session.js b/chrome/content/preferences/session.js
index bf9dd22..b237ca9 100644
--- a/chrome/content/preferences/session.js
+++ b/chrome/content/preferences/session.js
@@ -71,6 +71,7 @@ var gSessionPane = {
updatePrefs("browserStartupPage", useSessionManager ? 1 : 3);
}
+ TabmixSvc.sm.settingPreference = true;
if (useSessionManager) {
sessionstorePrefs();
sessionPrefs();
@@ -79,6 +80,7 @@ var gSessionPane = {
sessionPrefs();
sessionstorePrefs()
}
+ TabmixSvc.sm.settingPreference = false;
if (instantApply)
Services.prefs.savePrefFile(null);
diff --git a/chrome/content/preferences/shortcuts.xml b/chrome/content/preferences/shortcuts.xml
index 2d5841d..ab02459 100644
--- a/chrome/content/preferences/shortcuts.xml
+++ b/chrome/content/preferences/shortcuts.xml
@@ -133,7 +133,7 @@
if (!key.modifiers) {
let ns = Ci.nsIDOMKeyEvent;
- // Retuen and Esc blur the edit box
+ // Return and Esc blur the edit box
if (event.keyCode == ns.DOM_VK_RETURN ||
event.keyCode == ns.DOM_VK_ESCAPE) {
this.editBox.blur();
diff --git a/chrome/content/session/session.js b/chrome/content/session/session.js
index d4cfbc4..f6674fe 100644
--- a/chrome/content/session/session.js
+++ b/chrome/content/session/session.js
@@ -335,7 +335,7 @@ var TabmixSessionManager = {
SessionStore.promiseInitialized.then(initializeSM);
}
else {
- let forceInit = !Tabmix.isVersion(250) && this.doRestore
+ let forceInit = !Tabmix.isVersion(250) && this.doRestore;
// make sure sessionstore initialize without restoring pinned tabs
// for Firefox 25+ we block new tab in gbrowser.addtab
if (forceInit)
@@ -446,8 +446,10 @@ var TabmixSessionManager = {
return;
}
- if (Tabmix.isWindowAfterSessionRestore)
- setTimeout(function(){this.onSessionRestored()}.bind(this), 0);
+ if (Tabmix.isWindowAfterSessionRestore) {
+ let self = this;
+ setTimeout(function(){self.onSessionRestored()}, 0);
+ }
else {
// remove extra tab that was opened by SessionStore if last session
// contained pinned tab(s).
@@ -456,7 +458,8 @@ var TabmixSessionManager = {
this.resetTab(tab);
gBrowser.removeTab(tab);
try {
- TabmixSvc.ss.forgetClosedTab(window, 0);
+ if (TMP_ClosedTabs.count)
+ TabmixSvc.ss.forgetClosedTab(window, 0);
} catch(ex) {}
}
if (TabmixSvc.sm.crashed && this.enableBackup)
@@ -1174,10 +1177,11 @@ if (container == "error") { Tabmix.log("wrapContainer error path " + path + "\n"
this.removeAllClosedWindows();
this.saveState();
}
+ let slef = this;
setTimeout(function(){
TMP_ClosedTabs.setButtonDisableState();
- this.toggleRecentlyClosedWindowsButton();
- }.bind(this), 0);
+ slef.toggleRecentlyClosedWindowsButton();
+ }, 0);
break;
case "private-browsing-change-granted":
// Whether we restore the session upon resume will be determined by the
@@ -1495,7 +1499,7 @@ if (container == "error") { Tabmix.log("wrapContainer error path " + path + "\n"
isValidtoSave: function() {
if ( !this.enableManager ) return false;
- if (gBrowser.isBlankWindow()) {
+ if (!this.isWindowValidtoSave()) {
var title = TabmixSvc.getSMString("sm.title");
var msg = TabmixSvc.getSMString("sm.dontSaveBlank.msg");
var buttons = ["", TabmixSvc.setLabel("sm.button.continue")].join("\n");
@@ -1505,6 +1509,13 @@ if (container == "error") { Tabmix.log("wrapContainer error path " + path + "\n"
return true;
},
+ isWindowValidtoSave: function() {
+ if (gBrowser.isBlankWindow())
+ return false;
+ return typeof privateTab != "object" ||
+ Array.some(gBrowser.tabs, function(tab) !privateTab.isTabPrivate(tab));
+ },
+
saveOneOrAll: function(action, path, saveClosedTabs) {
if (this.isPrivateWindow)
return false;
@@ -2474,7 +2485,7 @@ try{
saveOneWindow: function SM_saveOneWindow(path, caller, overwriteWindow, saveClosedTabs) {
// don't save private window or window without any tab
- if (this.isPrivateWindow || gBrowser.isBlankWindow())
+ if (this.isPrivateWindow || !this.isWindowValidtoSave())
return 0;
if (!path) path = this.gSessionPath[0];
if (!caller) caller = "";
@@ -2571,7 +2582,8 @@ try{
// xxx need to fix this to save only history, image and history index
// and save the rest when tab added
tabLoaded: function SM_tabLoaded(aTab) {
- if (!this._inited || !this.enableBackup || aTab.hasAttribute("inrestore"))
+ if (!this._inited || !this.enableBackup ||
+ aTab.hasAttribute("inrestore") || this.isTabPrivate(aTab))
return;
if (gBrowser.isBlankTab(aTab)) return;
// if this window is not in the container add it to the last place
@@ -2587,7 +2599,7 @@ try{
if (!add0_1) add0_1 = 0;
for (var i = aTab._tPos + add0_1; i < gBrowser.tabs.length; i++) {
tab = gBrowser.tabs[i];
- node = (typeof(label) == "undefined") ? this.getNodeForTab(tab) : label + "/" + tab.linkedPanel;
+ node = (typeof(label) != "string") ? this.getNodeForTab(tab) : label + "/" + tab.linkedPanel;
this.setIntLiteral(node, "tabPos", tab._tPos);
}
},
@@ -2600,8 +2612,10 @@ try{
var tabContainer = this.initContainer(this.gThisWinTabs);
var panelPath = this.getNodeForTab(aTab);
var nodeToClose = this.RDFService.GetResource(panelPath);
- this.updateTabPos(aTab); // update _tPos for the tab right to the deleted tab
- if (this.saveClosedtabs) {
+ var privateTab = this.isTabPrivate(aTab);
+ // update _tPos for the tab right to the deleted tab
+ this.updateTabPos(aTab, null, privateTab ? 1 : 0);
+ if (!privateTab && this.saveClosedtabs) {
// move closedtabs to closedtabs container
var closedTabContainer = this.initContainer(this.gThisWinClosedtabs);
var tabExist = true;
@@ -2630,15 +2644,18 @@ try{
// we dont need this function to run before sessionmanager init
if (!this._inited || !this.enableBackup || aTab.hasAttribute("inrestore"))
return;
- if (gBrowser.isBlankTab(aTab))
- return; // dont write blank tab to the file
+ // dont write private or blank tab to the file
+ if (this.isTabPrivate(aTab) || gBrowser.isBlankTab(aTab))
+ return;
this.initSession(this.gSessionPath[0], this.gThisWin);
this.setLiteral(this.getNodeForTab(aTab), "properties", TabmixSessionData.getTabProperties(aTab, true));
this.saveStateDelayed();
},
tabMoved: function SM_tabMoved(aTab, oldPos, newPos) {
- if (!this.enableBackup || aTab.hasAttribute("inrestore")) return;
+ if (!this.enableBackup || aTab.hasAttribute("inrestore") ||
+ this.isTabPrivate(aTab))
+ return;
this.initSession(this.gSessionPath[0], this.gThisWin);
// can't use aTab._tPos after group of tab delete
// we pass old position and new position from TabMove event
@@ -2661,7 +2678,9 @@ try{
// xxx need to find the right event to trigger this function..
tabScrolled: function SM_tabScrolled(aTab) {
- if (!this.enableBackup || aTab.hasAttribute("inrestore")) return;
+ if (!this.enableBackup || aTab.hasAttribute("inrestore") ||
+ this.isTabPrivate(aTab))
+ return;
var aBrowser = gBrowser.getBrowserForTab(aTab);
if (gBrowser.isBlankBrowser(aBrowser)) return;
var bContent = aBrowser.contentWindow;
@@ -2670,7 +2689,11 @@ try{
},
tabSelected: function(needFlush) {
- if (!this.enableBackup || gBrowser.mCurrentTab.hasAttribute("inrestore")) return;
+ if (!this.enableBackup)
+ return;
+ let tab = gBrowser.mCurrentTab;
+ if (tab.hasAttribute("inrestore") || this.isTabPrivate(tab))
+ return;
if (typeof(needFlush) == "undefined") needFlush = false;
this.initSession(this.gSessionPath[0], this.gThisWin);
this.setTabsScroll(); // until i find proper event to update tab scroll do it from here
@@ -2694,6 +2717,22 @@ try{
return this.gThisWinTabs + "/" + aTab.linkedPanel;
},
+ isTabPrivate: function(aTab) {
+ return typeof privateTab == "object" && privateTab.isTabPrivate(aTab);
+ },
+
+ privateTabChanged: function(aEvent) {
+ if (!this.enableBackup || typeof privateTab != "object")
+ return;
+
+ // aEvent.detail: 1 == private, 0 == non-private
+ let tab = aEvent.target;
+ if (aEvent.detail)
+ this.tabClosed(tab);
+ else
+ this.tabLoaded(tab);
+ },
+
saveAllTab: function SM_saveAllTab(winPath, offset, saveBusy) {
var savedTabs = 0 ;
var rdfNodeTabs = this.getResource(winPath, "tabs");
@@ -2712,6 +2751,8 @@ try{
// call from tabloaded, tabClosed, saveAllTab
// xxx add flag what to save : all, history, property, scrollPosition
saveTab: function SM_saveTab(aTab, rdfLabelTabs, tabContainer, needToAppend, offset) {
+ if (this.isTabPrivate(aTab))
+ return false;
var aBrowser = gBrowser.getBrowserForTab(aTab);
if (gBrowser.isBlankBrowser(aBrowser)) return false;
@@ -2752,6 +2793,9 @@ try{
},
saveTabviewTab: function SM_saveTabviewTab(aNode, aTab) {
+ if (!this.enableBackup || aTab.hasAttribute("inrestore") ||
+ this.isTabPrivate(aTab))
+ return;
let data = TabmixSessionData.getTabValue(aTab, "tabview-tab");
if (data != "" && data != "{}")
this.setLiteral(aNode, "tabview-tab", data);
@@ -2932,7 +2976,8 @@ try{
var features = "chrome,all,dialog=no";
if (Tabmix.isVersion(200))
features += aPrivate ? ",private" : ",non-private";
- var newWindow = window.openDialog( getBrowserURL(), "_blank", features, null);
+ var newWindow = window.openDialog("chrome://browser/content/browser.xul",
+ "_blank", features, null);
newWindow.tabmixdata = { path: aPath, caller: aCaller };
},
diff --git a/chrome/content/session/sessionStore.js b/chrome/content/session/sessionStore.js
index 58cd1fd..855ee84 100644
--- a/chrome/content/session/sessionStore.js
+++ b/chrome/content/session/sessionStore.js
@@ -51,8 +51,7 @@ var TMP_SessionStore = {
getTitleFromTabState: function(aTab) {
let tabData = TabmixSvc.JSON.parse(TabmixSvc.ss.getTabState(aTab));
- let activePageData = this.getActiveEntryData(tabData);
- return activePageData.title || activePageData.url;
+ return this.getActiveEntryData(tabData).title;
},
/**
@@ -99,8 +98,8 @@ var TMP_SessionStore = {
*
* @returns Nothing.
*/
- setService: function TMP_ss_setSessionService(msgNo, start, win) {
- if ("tabmix_setSession" in window || Tabmix.prefs.prefHasUserValue("setDefault"))
+ setService: function TMP_ss_setSessionService(msgNo, start) {
+ if (TabmixSvc.sm.settingPreference || Tabmix.prefs.prefHasUserValue("setDefault"))
return;
/*
* From 2008-03-10 we don't set browser.sessionstore.enabled to false anymore
@@ -120,7 +119,7 @@ var TMP_SessionStore = {
return;
}
- window.tabmix_setSession = true;
+ TabmixSvc.sm.settingPreference = true;
// if session manager extension is install disable TMP session manager
if (msgNo == -1 || Tabmix.extensions.sessionManager) {
// update session manager settings accourding to current tabmix settings
@@ -151,7 +150,7 @@ var TMP_SessionStore = {
Services.prefs.setBoolPref(TMP_SS_CRASHRECOVERY, false);
Services.prefs.setBoolPref("browser.sessionstore.resume_from_crash", true);
}
- delete window.tabmix_setSession;
+ TabmixSvc.sm.settingPreference = false;
}
else if (this.isSessionStoreEnabled()) {
// ask the user to choose between TMP session manager and sessionstore
@@ -181,10 +180,10 @@ var TMP_SessionStore = {
Services.prefs.setBoolPref(TMP_SS_MANAGER, false);
Services.prefs.setBoolPref(TMP_SS_CRASHRECOVERY, false);
}
- delete window.tabmix_setSession;
+ TabmixSvc.sm.settingPreference = false;
}
let result = Tabmix.promptService([Tabmix.BUTTON_OK, Tabmix.HIDE_MENUANDTEXT, Tabmix.HIDE_CHECKBOX],
- [title, msg, "", "", buttons], win || window, start ? callBack : null);
+ [title, msg, "", "", buttons], window, start ? callBack : null);
if (!start)
callBack(result);
}
@@ -194,7 +193,7 @@ var TMP_SessionStore = {
if (!Tabmix.isVersion(200))
Services.prefs.setBoolPref("browser.warnOnRestart", false);
Services.prefs.setBoolPref("browser.warnOnQuit", false);
- delete window.tabmix_setSession;
+ TabmixSvc.sm.settingPreference = false;
}
},
@@ -309,14 +308,14 @@ var TMP_ClosedTabs = {
* Get closed tabs count
*/
get count() {
- return TabmixSvc.ss.getClosedTabCount(window);
+ return window.__SSi ? TabmixSvc.ss.getClosedTabCount(window) : 0;
},
/**
* Get closed tabs data
*/
get getClosedTabData() {
- return TabmixSvc.JSON.parse(TabmixSvc.ss.getClosedTabData(window));
+ return window.__SSi ? TabmixSvc.JSON.parse(TabmixSvc.ss.getClosedTabData(window)) : {};
},
getUrl: function ct_getUrl(aTabData) {
@@ -454,7 +453,7 @@ var TMP_ClosedTabs = {
}
// Reset the number of tabs closed last time to the default.
- gBrowser.setNumberOfTabsClosedLast(1);
+ Tabmix.setNumberOfTabsClosedLast(1);
},
removeAllClosedTabs: function () {
@@ -576,7 +575,7 @@ var TMP_ClosedTabs = {
let index = Number(aIndex);
if (isNaN(index)) {
index = 0;
- if (Tabmix.isVersion(250))
+ if (Tabmix._restoreMultipleTabs)
numberOfTabsToUndoClose = TabmixSvc.ss.getNumberOfTabsClosedLast(window);
} else if (0 > index || index >= this.count)
return null;
@@ -588,7 +587,7 @@ var TMP_ClosedTabs = {
tab = this.SSS_undoCloseTab(index, aWhere || "original", true);
// Reset the number of tabs closed last time to the default.
- gBrowser.setNumberOfTabsClosedLast(1);
+ Tabmix.setNumberOfTabsClosedLast(1);
return tab;
}
diff --git a/chrome/content/tab/scrollbox.xml b/chrome/content/tab/scrollbox.xml
index e38e9ef..7f358e0 100644
--- a/chrome/content/tab/scrollbox.xml
+++ b/chrome/content/tab/scrollbox.xml
@@ -427,7 +427,7 @@
}
var tabs = document.getBindingParent(this);
- if (tabs.hasAttribute("multibar")) {
+ if (tabs.hasAttribute("multibar") && tabs.overflow) {
//XXX don't do anything on Linux when hovering last tab and
// we show close button on tab on hover
if (!Tabmix.isPlatform("Linux") || TabmixTabbar.visibleRows == 1 ||
diff --git a/chrome/content/tab/tab.js b/chrome/content/tab/tab.js
index eee14c6..49593fd 100644
--- a/chrome/content/tab/tab.js
+++ b/chrome/content/tab/tab.js
@@ -17,6 +17,16 @@ var TabmixTabbar = {
return gBrowser.tabContainer.getAttribute("flowing") == "multibar";
},
+ isButtonOnTabsToolBar: function(button) {
+ return button && button.parentNode == gBrowser.tabContainer._container;
+ },
+
+ // get privateTab-toolbar-openNewPrivateTab, when the button is on the tabbar
+ newPrivateTabButton: function() {
+ let button = document.getElementById("privateTab-toolbar-openNewPrivateTab");
+ return this.isButtonOnTabsToolBar(button) ? button : null;
+ },
+
updateSettings: function TMP_updateSettings(start) {
if (!gBrowser || Tabmix.prefs.prefHasUserValue("setDefault"))
return;
@@ -132,20 +142,14 @@ var TabmixTabbar = {
tabBar.adjustTabstrip(true);
// show on tabbar
- var showNewTabButton = Tabmix.prefs.getBoolPref("newTabButton");
- let toolBar = gBrowser.tabContainer._container;
let tabstripClosebutton = document.getElementById("tabs-closebutton");
- if (tabstripClosebutton && tabstripClosebutton.parentNode == toolBar)
+ if (this.isButtonOnTabsToolBar(tabstripClosebutton))
tabstripClosebutton.collapsed = Tabmix.prefs.getBoolPref("hideTabBarButton");
let allTabsButton = document.getElementById("alltabs-button");
- if (allTabsButton && allTabsButton.parentNode == toolBar)
+ if (this.isButtonOnTabsToolBar(allTabsButton))
allTabsButton.collapsed = Tabmix.prefs.getBoolPref("hideAllTabsButton");
-
- let newTabButton = document.getElementById("new-tab-button");
- showNewTabButton = showNewTabButton && newTabButton && newTabButton.parentNode == toolBar;
- Tabmix.setItem("TabsToolbar", "newTabButton", showNewTabButton || false);
Tabmix.setItem(tabBar, "tabBarSpace", Tabmix.prefs.getBoolPref("tabBarSpace") || null);
- tabBar._checkNewtabButtonVisibility = isMultiRow && showNewTabButton && Tabmix.prefs.getIntPref("newTabButton.position") == 2;
+ this.setShowNewTabButtonAttr();
var self = this;
if (start)
@@ -160,6 +164,21 @@ var TabmixTabbar = {
}, 50, currentVisible);
},
+ setShowNewTabButtonAttr: function() {
+ let newTabButton = document.getElementById("new-tab-button");
+ let showNewTabButton = Tabmix.prefs.getBoolPref("newTabButton") &&
+ this.isButtonOnTabsToolBar(newTabButton);
+ let position = Tabmix.prefs.getIntPref("newTabButton.position");
+ gTMPprefObserver.setShowNewTabButtonAttr(showNewTabButton, position);
+ },
+
+ showNewTabButtonOnSide: function(aCondition, aValue) {
+ if (Tabmix._show_newtabbutton) {
+ Tabmix.setItem("TabsToolbar", "tabmix-show-newtabbutton",
+ aCondition ? aValue : Tabmix._show_newtabbutton);
+ }
+ },
+
setScrollButtonBox: function TMP_setScrollButtonBox(useTabmixButtons, insertAfterTabs, update) {
let newBox, box = document.getElementById("tabmixScrollBox");
if (useTabmixButtons && !box) {
@@ -873,8 +892,16 @@ var gTMPprefObserver = {
},
dynamicRules: {},
+ insertRule: function(cssText, name) {
+ let index = this.tabStyleSheet.insertRule(cssText,
+ this.tabStyleSheet.cssRules.length);
+ if (name)
+ this.dynamicRules[name] = this.tabStyleSheet.cssRules[index];
+ return index;
+ },
+
createColorRules: function TMP_PO_createColorRules() {
- var bottomBorder, ss = this.tabStyleSheet;
+ var bottomBorder;
this.gradients = { };
if (Tabmix.isVersion(160)) {
this.gradients.body = "linear-gradient(#colorCode, #colorCode)";
@@ -946,39 +973,30 @@ var gTMPprefObserver = {
"{background-image: " + this.gradients.body + " !important;}";
}
- // Charter Toolbar extension add Object.prototype.toJSONString
- // that break the use "for (var rule in styleRules)"
- var rules = ["currentTab", "unloadedTab", "unreadTab", "otherTab", "progressMeter"];
- for (let j = 0; j < rules.length; j++) {
- let rule = rules[j];
+ for (let rule in Iterator(styleRules, true)) {
this.setTabStyles("extensions.tabmix.styles." + rule, true);
var prefValues = this.tabStylePrefs[rule];
if (!prefValues)
continue;
- var newRule, index;
if (rule != "progressMeter") {
- newRule = styleRules[rule].text.replace("#colorCode",prefValues.textColor);
- index = ss.insertRule(newRule, ss.cssRules.length);
- this.dynamicRules[rule] = ss.cssRules[index];
+ let newRule = styleRules[rule].text.replace("#colorCode",prefValues.textColor);
+ this.insertRule(newRule, rule);
}
- newRule = styleRules[rule].bg.replace(/#colorCode/g,prefValues.bgColor);
- index = ss.insertRule(newRule, ss.cssRules.length);
- this.dynamicRules[rule + "bg"] = ss.cssRules[index];
+ let newRule = styleRules[rule].bg.replace(/#colorCode/g,prefValues.bgColor);
+ this.insertRule(newRule, rule + "bg");
if (rule != "progressMeter")
this.toggleTabStyles(rule);
}
if ("bgTabsontop" in styleRules.currentTab) {
// bottom border for selected tab on top is diffrent
let newRule = styleRules.currentTab.bgTabsontop.replace(/#colorCode/g, this.tabStylePrefs["currentTab"].bgColor);
- let index = ss.insertRule(newRule, ss.cssRules.length);
- this.dynamicRules["currentTab" + "bgTabsontop"] = ss.cssRules[index];
+ this.insertRule(newRule, "currentTab" + "bgTabsontop");
}
// rule for controling moz-margin-start when we have pinned tab in multi-row
let marginStart = '#tabbrowser-tabs[positionpinnedtabs] > .tabbrowser-tab[tabmix-firstTabInRow="true"]{-moz-margin-start: 0px;}';
- let index = ss.insertRule(marginStart, ss.cssRules.length);
- this.dynamicRules["tabmix-firstTabInRow"] = ss.cssRules[index];
+ this.insertRule(marginStart, "tabmix-firstTabInRow");
// rule for progress-bar background-image
// move it back to css file when we drop support for Firefox 11-15
@@ -993,7 +1011,7 @@ var gTMPprefObserver = {
backgroundImage = backgroundImage.replace("#2", Tabmix.ltr ? "left" : "rigth").
replace("linear-gradient", "-moz-linear-gradient");
}
- ss.insertRule(backgroundImage, ss.cssRules.length);
+ this.insertRule(backgroundImage);
// for ColorfulTabs 8.0+
// add new rule to adjust selected tab bottom margin
@@ -1002,8 +1020,8 @@ var gTMPprefObserver = {
let padding = Tabmix.getStyle(gBrowser.tabs[0], "paddingBottom");
let newRule = '#tabbrowser-tabs[flowing="multibar"] > .tabbrowser-tab[selected=true]' +
' {margin-bottom: -1px !important; padding-bottom: ' + (padding + 1) + 'px !important;}';
- let index = ss.insertRule(newRule, ss.cssRules.length);
- newRule = ss.cssRules[index];
+ let index = this.insertRule(newRule);
+ newRule = this._tabStyleSheet.cssRules[index];
gBrowser.tabContainer.addEventListener("TabOpen", function TMP_addStyleRule(aEvent) {
gBrowser.tabContainer.removeEventListener("TabOpen", TMP_addStyleRule, true);
let padding = Tabmix.getStyle(aEvent.target, "paddingBottom");
@@ -1013,7 +1031,6 @@ var gTMPprefObserver = {
},
setTabIconMargin: function TMP_PO_setTabIconMargin() {
- var ss = this.tabStyleSheet;
var [sMarginStart, sMarginEnd] = Tabmix.rtl ? ["margin-right", "margin-left"] : ["margin-left", "margin-right"];
var icon = document.getAnonymousElementByAttribute(gBrowser.mCurrentTab, "class", "tab-icon-image");
if (!icon)
@@ -1038,7 +1055,7 @@ var gTMPprefObserver = {
selector + '.tab-reload-icon,' +
selector + '.tab-lock-icon {' +
'-moz-margin-start: %S; -moz-margin-end: %S;}'.replace("%S", marginStart).replace("%S", marginEnd);
- ss.insertRule(iconRule, ss.cssRules.length);
+ this.insertRule(iconRule);
icon.setAttribute("pinned", true);
let _marginStart = style.getPropertyValue(sMarginStart);
let _marginEnd = style.getPropertyValue(sMarginEnd);
@@ -1047,7 +1064,7 @@ var gTMPprefObserver = {
_selector + '.tab-reload-icon,' +
_selector + '.tab-lock-icon {' +
'-moz-margin-start: %S; -moz-margin-end: %S;}'.replace("%S", _marginStart).replace("%S", _marginEnd);
- ss.insertRule(_iconRule, ss.cssRules.length);
+ this.insertRule(_iconRule);
if (!pinned)
icon.removeAttribute("pinned");
@@ -1060,9 +1077,9 @@ var gTMPprefObserver = {
function tabmix_setRule(aRule) {
let newRule = aRule.replace(/%S/g, "tab-icon-image").replace("%PX", marginEnd);
- ss.insertRule(newRule, ss.cssRules.length);
+ this.insertRule(newRule);
newRule = aRule.replace(/%S/g, "tab-lock-icon").replace("%PX", marginEnd);
- ss.insertRule(newRule, ss.cssRules.length);
+ this.insertRule(newRule);
}
iconRule = '.tabbrowser-tabs%favhideclose%[closebuttons-side="left"][closebuttons="alltabs"] > .tabbrowser-tab:not([pinned]):not([protected])%faviconized% .%S ,' +
'.tabbrowser-tabs%favhideclose%[closebuttons-side="left"][closebuttons="activetab"] > .tabbrowser-tab:not([pinned]):not([protected])[selected="true"]%faviconized% .%S {'+
@@ -1080,7 +1097,6 @@ var gTMPprefObserver = {
},
setCloseButtonMargin: function TMP_PO_setCloseButtonMargin() {
- var ss = this.tabStyleSheet;
var [sMarginStart, sMarginEnd] = Tabmix.rtl ? ["margin-right", "margin-left"] : ["margin-left", "margin-right"];
var icon = document.getAnonymousElementByAttribute(gBrowser.mCurrentTab, "button_side", "right") ||
document.getAnonymousElementByAttribute(gBrowser.mCurrentTab, "class", "tab-close-button close-icon always-right");
@@ -1095,7 +1111,7 @@ var gTMPprefObserver = {
let newRule = '.tab-close-button[button_side="left"] {' +
'-moz-margin-start: %PX !important;'.replace("%PX", marginEnd) +
'-moz-margin-end: %PX !important;}'.replace("%PX", marginStart);
- ss.insertRule(newRule, ss.cssRules.length);
+ this.insertRule(newRule);
}
// set right margin to text stack when close button is not right to it
// on default theme the margin is zero, so we set the end margin to be the same as the start margin
@@ -1108,25 +1124,32 @@ var gTMPprefObserver = {
'-moz-margin-end: %PX !important;}'.replace("%PX", textMarginEnd);
if ("faviconize" in window) {
let newRule = iconRule.replace(/%favhideclose%/g, ':not([favhideclose="true"])').replace(/%faviconized%/g, '').replace(/%faviconized1%/g, ':not([faviconized="true"])');
- ss.insertRule(newRule, ss.cssRules.length);
+ this.insertRule(newRule);
newRule = iconRule.replace(/%favhideclose%/g, '[favhideclose="true"]').replace(/%faviconized%/g, ':not([faviconized="true"])').replace(/%faviconized1%/g, ':not([faviconized="true"])');
- ss.insertRule(newRule, ss.cssRules.length);
+ this.insertRule(newRule);
newRule = '.tabbrowser-tab[faviconized="true"][protected]:not([pinned]) {max-width: 36px !important;}';
- ss.insertRule(newRule, ss.cssRules.length);
+ this.insertRule(newRule);
}
else {
let newRule = iconRule.replace(/%favhideclose%/g, '').replace(/%faviconized%/g, '').replace(/%faviconized1%/g, '');
- ss.insertRule(newRule, ss.cssRules.length);
+ this.insertRule(newRule);
}
},
miscellaneousRules: function TMP_PO_miscellaneousRules() {
// height shrink to actual size when the tabbar is in display: block (multi-row)
let newHeight = gBrowser.tabContainer.visibleTabsFirstChild.getBoundingClientRect().height;
- let newRule = '#TabsToolbar:not([newTabButton=false]):not([disAllowNewtabbutton]):not([newtab_side]) >' +
+ let newRule = '#TabsToolbar[tabmix-show-newtabbutton*="aftertabs"] >' +
'#tabbrowser-tabs:not([overflow="true"]) > .tabbrowser-arrowscrollbox[flowing="multibar"]' +
- ' > .tabs-newtab-button {height: #px;}'.replace("#", newHeight);
- this.tabStyleSheet.insertRule(newRule, this.tabStyleSheet.cssRules.length);
+ ' > .tabs-newtab-button[command="cmd_newNavigatorTab"] {height: #px;}'.replace("#", newHeight);
+ this.insertRule(newRule);
+
+ if (!Tabmix.isPlatform("Mac") && !Tabmix.isPlatform("Linux")) {
+ let newRule = '#TabsToolbar[multibar] > .toolbarbutton-1,' +
+ '#TabsToolbar[multibar] > #tabs-closebutton {' +
+ ' height: #px;}'.replace("#", newHeight);
+ this.insertRule(newRule);
+ }
},
addWidthRules: function TMP_PO_addWidthRules() {
@@ -1135,9 +1158,7 @@ var gTMPprefObserver = {
let _max = Services.prefs.getIntPref("browser.tabs.tabMaxWidth");
let _min = Services.prefs.getIntPref("browser.tabs.tabMinWidth");
newRule = newRule.replace("#1" ,_min).replace("#2" ,_max);
- let ss = this.tabStyleSheet;
- let index = ss.insertRule(newRule, ss.cssRules.length);
- this.dynamicRules["width"] = ss.cssRules[index];
+ this.insertRule(newRule, "width");
},
defaultStylePrefs: { currentTab: {italic:false,bold:false,underline:false,text:true,textColor:'rgba(0,0,0,1)',bg:false,bgColor:'rgba(236,233,216,1)'},
@@ -1402,26 +1423,23 @@ var gTMPprefObserver = {
},
changeNewTabButtonSide: function(aPosition) {
- var tabBar = gBrowser.tabContainer;
- tabBar._checkNewtabButtonVisibility = false;
- let newTabButton = document.getElementById("new-tab-button");
- if (newTabButton && newTabButton.parentNode == gBrowser.tabContainer._container) {
- let sideChanged, tabsToolbar = document.getElementById("TabsToolbar");
+ function $(id) document.getElementById(id);
+ let newTabButton = $("new-tab-button");
+ if (TabmixTabbar.isButtonOnTabsToolBar(newTabButton)) {
+ let sideChanged, tabsToolbar = $("TabsToolbar");
let toolBar = Array.slice(tabsToolbar.childNodes);
let buttonIndex = toolBar.indexOf(newTabButton);
let tabsIndex = toolBar.indexOf(gBrowser.tabContainer);
if (aPosition == 0) {
- Tabmix.setItem(tabsToolbar, "newtab_side", "left");
if (buttonIndex > tabsIndex) {
newTabButton.parentNode.insertBefore(newTabButton, gBrowser.tabContainer);
sideChanged = true;
}
}
else {
- Tabmix.setItem(tabsToolbar, "newtab_side", aPosition == 1 ? "right" : null);
if (buttonIndex < tabsIndex) {
let before = gBrowser.tabContainer.nextSibling;
- if (document.getElementById("tabmixScrollBox")) {
+ if ($("tabmixScrollBox")) {
before = before.nextSibling;
tabsIndex++;
}
@@ -1436,16 +1454,54 @@ var gTMPprefObserver = {
tabsToolbar.setAttribute("currentset", cSet.join(","));
document.persist("TabsToolbar", "currentset");
}
- tabBar._checkNewtabButtonVisibility = TabmixTabbar.isMultiRow && Tabmix.prefs.getBoolPref("newTabButton") && aPosition == 2;
- Tabmix.setItem("TabsToolbar", "newTabButton", Tabmix.prefs.getBoolPref("newTabButton"));
- tabBar._rightNewTabButton = newTabButton;
+ let showNewTabButton = Tabmix.prefs.getBoolPref("newTabButton");
+ this.setShowNewTabButtonAttr(showNewTabButton, aPosition);
+ Tabmix.sideNewTabButton = newTabButton;
}
else {
- Tabmix.setItem("TabsToolbar", "newTabButton", false);
- tabBar._rightNewTabButton = null;
+ this.setShowNewTabButtonAttr(false);
+ Tabmix.sideNewTabButton = null;
}
},
+ setShowNewTabButtonAttr: function(aShow, aPosition) {
+ // check new tab button visibility when we are in multi-row and the
+ // preference is to show new-tab-button after last tab
+ gBrowser.tabContainer._checkNewtabButtonVisibility =
+ TabmixTabbar.isMultiRow && ((aShow && aPosition == 2) ||
+ !!TabmixTabbar.newPrivateTabButton());
+
+ /** values for tabmix-show-newtabbutton to show tabs-newtab-button are:
+ * aftertabs - show the button after tabs
+ * aftertabs-force - force the button after tabs to be visible, only to
+ * - make it possible to catch the button width
+ * (Tabmix.getAfterTabsButtonsWidth)
+ * temporary-right-side
+ * - show the button on right side when there is no place
+ * for the button aftertabs in multi-row mode
+ * rigth-side - show the button on right side
+ * left-side - show the button on left side
+ */
+ let attrValue;
+ if (!aShow)
+ attrValue = null;
+ else if (aPosition == 0)
+ attrValue = "left-side";
+ else if (aPosition == 1)
+ attrValue = "right-side";
+ else
+ attrValue = "aftertabs";
+ // we use this value in disAllowNewtabbutton and overflow setters
+ Tabmix._show_newtabbutton = attrValue;
+ if (aShow) {
+ if (gBrowser.tabContainer.overflow)
+ attrValue = "right-side";
+ else if (gBrowser.tabContainer.disAllowNewtabbutton)
+ attrValue = "temporary-right-side";
+ }
+ Tabmix.setItem("TabsToolbar", "tabmix-show-newtabbutton", attrValue);
+ },
+
tabBarPositionChanged: function(aPosition) {
if (aPosition > 1 || (aPosition != 0 && Tabmix.extensions.verticalTabBar)) {
Tabmix.prefs.setIntPref("tabBarPosition", 0);
@@ -1792,6 +1848,12 @@ try {
shortcuts.toggleFLST = "VK_F9";
Tabmix.prefs.setCharPref("shortcuts", TabmixSvc.JSON.stringify(shortcuts));
}
+ // 2013-09-04
+ if (Tabmix.prefs.prefHasUserValue("enableScrollSwitch")) {
+ // enableScrollSwitch non-default value was true that is now 1
+ Tabmix.prefs.setIntPref("scrollTabs", 1);
+ Tabmix.prefs.clearUserPref("enableScrollSwitch");
+ }
// verify valid value
if (Tabmix.prefs.prefHasUserValue("tabs.closeButtons")) {
@@ -1802,8 +1864,7 @@ try {
// 2011-01-22 - verify sessionstore enabled
Services.prefs.clearUserPref("browser.sessionstore.enabled");
- let getVersion = function _getVersion(extensions) {
- let currentVersion = extensions.get("{dc572301-7619-498c-a57d-39143191b318}").version;
+ let getVersion = function _getVersion(currentVersion) {
let oldVersion = Tabmix.prefs.prefHasUserValue("version") ? Tabmix.prefs.getCharPref("version") : "";
let vCompare = function(a, b) Services.vc.compare(a, b) <= 0;
@@ -1833,13 +1894,12 @@ try {
// noting more to do at the moment
}
}
- const Application = Cc["@mozilla.org/fuel/application;1"].getService(Ci.fuelIApplication);
- let wrappedGetVersion = function(extensions) {
+ AddonManager.getAddonByID("{dc572301-7619-498c-a57d-39143191b318}", function(aAddon) {
try {
- getVersion(extensions);
+ getVersion(aAddon.version);
} catch (ex) {Tabmix.assert(ex);}
- }
- Application.getExtensions(wrappedGetVersion);
+ })
+
// block item in tabclicking options that are not in use
this.blockedValues = [];
if (!("SessionSaver" in window && window.SessionSaver.snapBackTab))
diff --git a/chrome/content/tab/tabbrowser_4.xml b/chrome/content/tab/tabbrowser_4.xml
index ed0a074..1d64b34 100644
--- a/chrome/content/tab/tabbrowser_4.xml
+++ b/chrome/content/tab/tabbrowser_4.xml
@@ -318,10 +318,6 @@
document.getAnonymousElementByAttribute(this.mTabstrip._scrollbox, "class", "box-inherit scrollbox-innerbox");
</field>
- <field name="mTabsNewtabButton">
- document.getAnonymousElementByAttribute(this, "class", "tabs-newtab-button");
- </field>
-
<constructor>
<![CDATA[
// add dragover event handler to TabsToolbar to capture dragging over
@@ -364,7 +360,10 @@
* if we set this in field[s] they will reset each time the tabbar binding construct
* by tabbar position change
*/
- this._newTabButtonWidth = 22;
+ Tabmix.afterTabsButtonsWidth = [22];
+ Tabmix.tabsNewtabButton =
+ document.getAnonymousElementByAttribute(this, "command", "cmd_newNavigatorTab");
+ Tabmix._show_newtabbutton = "aftertabs";
let tab = this.firstChild;
tab.setAttribute("flst_id", new Date().getTime());
@@ -382,12 +381,15 @@
if (Tabmix.prefs.getBoolPref("extraIcons.locked"))
this.setAttribute("extraIcons-locked", true);
+ if (Tabmix.prefs.prefHasUserValue("enableDebug") &&
+ Tabmix.prefs.getBoolPref("enableDebug")) {
+ Tabmix._debugMode = true;
+ }
+
if ("linkedBrowser" in tab)
tablib.setLoadURIWithFlags(tab.linkedBrowser);
- try {
- Tabmix.beforeStartup(tabbrowser, this);
- } catch (ex) {Tabmix.assert(ex);}
+ Tabmix.initialization.run("beforeStartup", tabbrowser, this);
]]>
</constructor>
@@ -435,6 +437,7 @@
this._inUpdateVerticalTabStrip = true;
// we must adjustNewtabButtonvisibility before get lastTabRowNumber
this.adjustNewtabButtonvisibility();
+ let visibleRows = TabmixTabbar.visibleRows;
// this.lastTabRowNumber is null when we hide the tabbar
let rows = aReset || this.childNodes.length == 1 ? 1 : (this.lastTabRowNumber || 1);
@@ -468,15 +471,32 @@
if (this.mTabstrip.orient == "vertical")
this.overflow = multibar == "scrollbar";
- // prevent new-tab-button on the right from flickering when new tabs animate is on.
- if (this.disAllowNewtabbutton && Services.prefs.getBoolPref("browser.tabs.animate")) {
- this.disAllowNewtabbutton = false;
- let self = this;
- // after 300ms new tab is fully opened
- setTimeout(function() {self.adjustNewtabButtonvisibility();}, 300);
+ if (!this.overflow) {
+ // prevent new-tab-button on the right from flickering when new tabs animate is on.
+ if (this.disAllowNewtabbutton && Services.prefs.getBoolPref("browser.tabs.animate")) {
+ // after 250ms new tab is fully opened
+ if (!this.adjustNewtabButtonTimeout) {
+ let timeout = 250, callerName = Tabmix.callerName();
+ if (callerName == "onxbloverflow") {
+ let timeFromLastTabOpenedTime = Date.now() - Tabmix._lastTabOpenedTime;
+ if (timeFromLastTabOpenedTime < 250)
+ timeout = 0;
+ }
+ // Don't reset adjustNewtabButtonvisibility if multibar or rows
+ // didn't changed or when we get here from _enterVerticalMode
+ if (callerName != "_enterVerticalMode" &&
+ (multibar != currentMultibar || rows != visibleRows))
+ this.disAllowNewtabbutton = false;
+ let self = this;
+ this.adjustNewtabButtonTimeout = setTimeout(function() {
+ self.adjustNewtabButtonvisibility();
+ self.adjustNewtabButtonTimeout = null;
+ }, timeout);
+ }
+ }
+ else
+ this.adjustNewtabButtonvisibility();
}
- else
- this.adjustNewtabButtonvisibility();
this._inUpdateVerticalTabStrip = false;
return multibar;
@@ -509,7 +529,7 @@
this.setAttribute("overflow", "true");
else
this.removeAttribute("overflow");
- Tabmix.setItem("TabsToolbar", "tabstripoverflow", val || null);
+ TabmixTabbar.showNewTabButtonOnSide(val, "right-side");
}
return val;
]]></setter>
@@ -565,22 +585,24 @@
return;
if (!this._checkNewtabButtonVisibility) {
- this.disAllowNewtabbutton = this.getAttribute("flowing") == "singlebar" &&
- Tabmix.prefs.getBoolPref("newTabButton") &&
- Tabmix.prefs.getIntPref("newTabButton.position") == 2 &&
- this.overflow;
+ TabmixTabbar.showNewTabButtonOnSide(this.overflow, "right-side");
return;
}
+ // when Private-tab enabled/disabled we need to reset
+ // tabsNewtabButton and afterTabsButtonsWidth
+ if (!Tabmix.tabsNewtabButton)
+ Tabmix.getAfterTabsButtonsWidth();
+
var lastTab = this.visibleTabsLastChild;
// button is visible
// A: last tab and the button are in the same row - check if we have room for the button in this row
// B: last tab and the button are NOT in the same row - NG - hide the button
if (!this.disAllowNewtabbutton) {
- let sameRow = TabmixTabbar.inSameRow(lastTab, this.mTabsNewtabButton);
+ let sameRow = TabmixTabbar.inSameRow(lastTab, Tabmix.tabsNewtabButton);
if (sameRow) {
let tabstripEnd = this.mTabstrip.scrollBoxObject.screenX + this.mTabstrip.scrollBoxObject.width;
- let buttonEnd = this.mTabsNewtabButton.boxObject.screenX + this.mTabsNewtabButton.boxObject.width
+ let buttonEnd = Tabmix.tabsNewtabButton.boxObject.screenX + Tabmix.tabsNewtabButton.boxObject.width
this.disAllowNewtabbutton = buttonEnd > tabstripEnd;
}
else
@@ -598,10 +620,20 @@
this.disAllowNewtabbutton = false;
return;
}
+
+ // buttons that are not on TabsToolbar or not visible are null
+ let newTabButtonWidth = function(aOnSide) {
+ let width = 0, privatTabButton = TabmixTabbar.newPrivateTabButton();
+ if (privatTabButton)
+ width += aOnSide ? privatTabButton.boxObject.width : Tabmix.afterTabsButtonsWidth[1];
+ if (Tabmix.sideNewTabButton)
+ width += aOnSide ? Tabmix.sideNewTabButton.boxObject.width : Tabmix.afterTabsButtonsWidth[0];
+ return width;
+ }
let tsbo = this.mTabstrip.scrollBoxObject;
- let tsboEnd = tsbo.screenX + tsbo.width + (this._rightNewTabButton ? this._rightNewTabButton.boxObject.width: 0);
+ let tsboEnd = tsbo.screenX + tsbo.width + newTabButtonWidth(true);
if (TabmixTabbar.inSameRow(lastTab, previousTab)) {
- let buttonEnd = lastTab.boxObject.screenX + lastTab.boxObject.width + this._newTabButtonWidth;
+ let buttonEnd = lastTab.boxObject.screenX + lastTab.boxObject.width + newTabButtonWidth();
this.disAllowNewtabbutton = buttonEnd > tsboEnd;
return;
}
@@ -612,7 +644,7 @@
if (lastTabEnd > tsboEnd)
this.disAllowNewtabbutton = false;
else
- this.disAllowNewtabbutton = lastTabEnd + this._newTabButtonWidth > tsboEnd;
+ this.disAllowNewtabbutton = lastTabEnd + newTabButtonWidth() > tsboEnd;
return;
}
}
@@ -621,11 +653,10 @@
<property name="disAllowNewtabbutton">
<getter><![CDATA[
- return document.getElementById("TabsToolbar").hasAttribute("disAllowNewtabbutton");
+ return document.getElementById("TabsToolbar").getAttribute("tabmix-show-newtabbutton") == "temporary-right-side";
]]></getter>
<setter><![CDATA[
- if (val != this.disAllowNewtabbutton)
- Tabmix.setItem("TabsToolbar", "disAllowNewtabbutton", val || null);
+ TabmixTabbar.showNewTabButtonOnSide(val, "temporary-right-side");
return val;
]]></setter>
</property>
diff --git a/chrome/content/tabmix.js b/chrome/content/tabmix.js
index 7135ea9..afd7e0f 100644
--- a/chrome/content/tabmix.js
+++ b/chrome/content/tabmix.js
@@ -58,10 +58,10 @@ Tabmix.startup = function TMP_startup() {
Tabmix.beforeSessionStoreInit = function TMP_beforeSessionStoreInit() {
if (this.isFirstWindow) {
let tmp = {};
- Cu.import("resource://tabmixplus/extensions/SessionManagerAddon.jsm", tmp);
+ Cu.import("resource://tabmixplus/extensions/AddonManager.jsm", tmp);
TMP_SessionStore.setService(1, true);
}
- this.getNewTabButtonWidth();
+ this.getAfterTabsButtonsWidth();
TabmixSessionManager.init();
}
@@ -121,17 +121,34 @@ Tabmix.sessionInitialized = function() {
// we call this at the start of gBrowserInit._delayedStartup
// if we call it erlier we get this warning:
// XUL box for _moz_generated_content_before element contained an inline #text child
-Tabmix.getNewTabButtonWidth = function TMP_getNewTabButtonWidth() {
+Tabmix.getAfterTabsButtonsWidth = function TMP_getAfterTabsButtonsWidth() {
if (gBrowser.tabContainer.orient == "horizontal") {
let tabBar = gBrowser.tabContainer;
let stripIsHidden = TabmixTabbar.hideMode != 0 && !tabBar.visible;
if (stripIsHidden)
tabBar.visible = true;
- this.setItem("TabsToolbar", "tabmix-visible", true);
- // save mTabsNewtabButton width
+ let tabsToolbar = document.getElementById("TabsToolbar");
+ let showButton = tabsToolbar.getAttribute("tabmix-show-newtabbutton");
+ this.setItem(tabsToolbar, "tabmix-show-newtabbutton", "aftertabs-force");
+ // save tabsNewtabButton width
let lwtheme = document.getElementById("main-window").getAttribute("lwtheme");
- tabBar._newTabButtonWidth = lwtheme ? 31 : tabBar.mTabsNewtabButton.getBoundingClientRect().width;
- this.setItem("TabsToolbar", "tabmix-visible", null);
+ this.tabsNewtabButton =
+ document.getAnonymousElementByAttribute(tabBar, "command", "cmd_newNavigatorTab");
+ let openNewTabRect = this.tabsNewtabButton.getBoundingClientRect();
+ this.afterTabsButtonsWidth = [];
+ this.afterTabsButtonsWidth.push(lwtheme ? 31 : openNewTabRect.width);
+ // when privateTab extension installed add its new tab button width
+ // for the use of adjustNewtabButtonvisibility set tabsNewtabButton to be
+ // the right button
+ let openNewPrivateTab = document.getElementById("privateTab-afterTabs-openNewPrivateTab");
+ if (openNewPrivateTab) {
+ let openNewPrivateTabRect = openNewPrivateTab.getBoundingClientRect();
+ this.afterTabsButtonsWidth.push(openNewPrivateTabRect.width);
+ if (openNewPrivateTabRect.right > openNewTabRect.right)
+ this.tabsNewtabButton = openNewPrivateTab;
+ }
+
+ this.setItem(tabsToolbar, "tabmix-show-newtabbutton", showButton);
if (stripIsHidden)
tabBar.visible = false;
}
@@ -197,14 +214,7 @@ Tabmix.delayedStartup = function TMP_delayedStartup() {
var TMP_eventListener = {
init: function TMP_EL_init() {
window.addEventListener("DOMContentLoaded", this, false);
- },
-
- browserDelayedStartupFinished: function TMP_EL_browserDelayedStartupFinished() {
- // master password dialog can popup before startup when Gmail-manager try to login
- // it can cause load event to fire late, so we get here before onWindowOpen run
- if (!TMP_eventListener._windowInitialized)
- TMP_eventListener.onWindowOpen();
- Tabmix.delayedStartup();
+ window.addEventListener("load", this, false);
},
handleEvent: function TMP_EL_handleEvent(aEvent) {
@@ -231,14 +241,8 @@ var TMP_eventListener = {
this.onTabBarScroll(aEvent);
break;
case "DOMContentLoaded":
- try {
- this.onContentLoaded(aEvent);
- } catch (ex) {Tabmix.assert(ex);}
- break;
case "load":
- try {
- this.onWindowOpen(aEvent);
- } catch (ex) {Tabmix.assert(ex);}
+ this._onLoad(aEvent.type);
break;
case "unload":
this.onWindowClose(aEvent);
@@ -246,6 +250,9 @@ var TMP_eventListener = {
case "fullscreen":
this.onFullScreen(!window.fullScreen);
break;
+ case "PrivateTab:PrivateChanged":
+ TabmixSessionManager.privateTabChanged(aEvent);
+ break;
}
},
@@ -257,20 +264,18 @@ var TMP_eventListener = {
}, handler);
},
- /*
- * we use this event to run this code before load event
- * until TMP version 0.3.8.3 we used to run this code from Tabmix.beforeStartup
- * that called from tabcontainer constractur
- */
- onContentLoaded: function TMP_EL_onContentLoaded() {
- window.removeEventListener("DOMContentLoaded", this, false);
- // don't load tabmix into undock sidebar opened by ezsidebar extension
- var wintype = window.document.documentElement.getAttribute("windowtype");
- if (wintype == "mozilla:sidebar")
- return;
-
- window.addEventListener("load", this, false);
+ // ignore non-browser windows
+ _onLoad: function TMP_EL_onContentLoaded(aType) {
+ window.removeEventListener(aType, this, false);
+ let wintype = window.document.documentElement.getAttribute("windowtype");
+ if (wintype == "navigator:browser")
+ Tabmix.initialization.run(aType == "load" ? "onWindowOpen" :
+ "onContentLoaded");
+ else if (aType != "load")
+ window.removeEventListener("load", this, false);
+ },
+ onContentLoaded: function TMP_EL_onContentLoaded() {
Tabmix.isFirstWindow = Tabmix.numberOfWindows() == 1;
Tabmix.isWindowAfterSessionRestore = TMP_SessionStore._isAfterSessionRestored();
@@ -286,7 +291,7 @@ var TMP_eventListener = {
Tabmix.lazy_import(TabmixSessionManager, "_decode", "Decode", "Decode");
} catch (ex) {Tabmix.assert(ex);}
- this._tabEvents = ["SSTabRestoring",
+ this._tabEvents = ["SSTabRestoring", "PrivateTab:PrivateChanged",
"TabOpen", "TabClose", "TabSelect", "TabMove", "TabUnpinned"];
this.toggleEventListener(gBrowser.tabContainer, this._tabEvents, true);
@@ -312,6 +317,9 @@ var TMP_eventListener = {
if ("_update" in TabsInTitlebar) {
// set option to Prevent double click on Tab-bar from changing window size.
Tabmix.changeCode(TabsInTitlebar, "TabsInTitlebar._update")._replace(
+ 'function $(id)',
+ 'let $ = $&', {check: Tabmix._debugMode}
+ )._replace(
'this._dragBindingAlive',
'$& && Tabmix.prefs.getBoolPref("dblClickTabbar_changesize")'
)._replace(
@@ -361,14 +369,7 @@ var TMP_eventListener = {
}
},
- _windowInitialized: false,
onWindowOpen: function TMP_EL_onWindowOpen() {
- if (this._windowInitialized)
- return;
-
- this._windowInitialized = true;
- window.removeEventListener("load", this, false);
-
window.addEventListener("unload", this, false);
window.addEventListener("fullscreen", this, true);
@@ -452,7 +453,7 @@ var TMP_eventListener = {
Tabmix.setItem(tabsToolbar, "classic40", version);
platform = "xp40";
// check if australis tab shape is implemented in window (bug 738491)
- let australis = document.getElementById("tab-clip-path-outer");
+ let australis = document.getElementById("tab-curve-clip-path-start");
if (australis)
tabBar.setAttribute("australis", true);
}
@@ -660,7 +661,9 @@ var TMP_eventListener = {
}
},
- updateMultiRow: function () {
+ updateMultiRow: function (aReset) {
+ if (aReset)
+ Tabmix.tabsNewtabButton = null;
if (TabmixTabbar.isMultiRow) {
gBrowser.tabContainer.updateVerticalTabStrip();
gBrowser.tabContainer.setFirstTabInRow();
@@ -671,6 +674,7 @@ var TMP_eventListener = {
// Function to catch when new tabs are created and update tab icons if needed
// In addition clicks and doubleclick events are trapped.
onTabOpen: function TMP_EL_onTabOpen(aEvent) {
+ Tabmix._lastTabOpenedTime = Date.now();
var tab = aEvent.target;
this.setTabAttribute(tab);
TMP_LastTab.tabs = null;
@@ -686,20 +690,22 @@ var TMP_eventListener = {
// when more the one tabs opened at once
lastTimeTabOpened: 0,
onTabOpen_delayUpdateTabBar: function TMP_EL_onTabOpen_delayUpdateTabBar(aTab) {
- let tabBar = gBrowser.tabContainer;
- let self = this, newTime = new Date().getTime();
- if (tabBar.overflow || newTime - this.lastTimeTabOpened > 200) {
+ let newTime = Date.now();
+ if (gBrowser.tabContainer.overflow || newTime - this.lastTimeTabOpened > 200) {
this.onTabOpen_updateTabBar(aTab);
this.lastTimeTabOpened = newTime;
}
- else if (!tabBar.TMP_onOpenTimeout) {
- tabBar.TMP_onOpenTimeout = window.setTimeout( function TMP_onOpenTimeout(tab) {
- if (tabBar.TMP_onOpenTimeout) {
- clearTimeout(tabBar.TMP_onOpenTimeout);
- tabBar.TMP_onOpenTimeout = null;
+ else if (!this._onOpenTimeout) {
+ let self = this;
+ let timeout = gBrowser.tabContainer.disAllowNewtabbutton &&
+ Services.prefs.getBoolPref("browser.tabs.animate") ? 0 : 200;
+ this._onOpenTimeout = window.setTimeout( function TMP_onOpenTimeout(tab) {
+ if (self._onOpenTimeout) {
+ clearTimeout(self._onOpenTimeout);
+ self._onOpenTimeout = null;
}
self.onTabOpen_updateTabBar(tab);
- }, 200, aTab);
+ }, timeout, aTab);
}
},
@@ -760,7 +766,7 @@ var TMP_eventListener = {
if (updateNow)
this.onTabClose_updateTabBar(tab);
- gBrowser.countClosedTabs(tab);
+ Tabmix.countClosedTabs(tab);
},
// TGM extension use it
@@ -799,16 +805,16 @@ var TMP_eventListener = {
// and mTabstrip.ensureElementIsVisible
// this class change tab height (by changing the borders)
if (typeof colorfulTabs == "object" && colorfulTabs.standout &&
- tab.className.indexOf("standout") == -1) {
+ !tab.classList.contains("standout")) {
for (let i = 0; i < gBrowser.tabs.length; i++) {
let _tab = gBrowser.tabs[i];
- if (_tab.className.indexOf("standout") > -1) {
- _tab.className = _tab.className.replace(" standout", "");
+ if (_tab.classList.contains("standout")) {
+ _tab.classList.remove("standout");
break;
}
}
- tab.className = tab.className + " standout";
+ tab.classList.add("standout");
}
// update this functions after new tab select
@@ -863,10 +869,16 @@ var TMP_eventListener = {
},
onTabBarScroll: function TMP_EL_onTabBarScroll(aEvent) {
+ var scrollTabs = Tabmix.prefs.getIntPref("scrollTabs");
+ if (scrollTabs > 1) {
+ aEvent.stopPropagation();
+ aEvent.preventDefault();
+ return;
+ }
var tabBar = gBrowser.tabContainer;
tabBar.removeShowButtonAttr();
- var shouldMoveFocus = Tabmix.prefs.getBoolPref("enableScrollSwitch");
+ let shouldMoveFocus = scrollTabs == 1;
if (aEvent.shiftKey)
shouldMoveFocus = !shouldMoveFocus;
var direction = aEvent.detail;
@@ -1039,3 +1051,74 @@ var TMP_eventListener = {
}
}
+
+/**
+ * other extensions can cause delay to some of the events Tabmix uses for
+ * initialization, for each phase call all previous phases that are not
+ * initialized yet
+ */
+Tabmix.initialization = {
+ beforeStartup: {id: 0, obj: "Tabmix"},
+ onContentLoaded: {id: 1, obj: "TMP_eventListener"},
+ beforeBrowserInitOnLoad: {id: 2, obj: "Tabmix"},
+ onWindowOpen: {id: 3, obj: "TMP_eventListener"},
+ delayedStartup: {id: 4, obj: "Tabmix"},
+
+ get isValidWindow() {
+ /**
+ * don't initialize Tabmix functions on this window if one of this is true:
+ * - the window is a popup window
+ * - the window is about to close by SingleWindowModeUtils
+ * - tabbrowser-tabs binding didn't start (i onlly saw it happened
+ * when ImTranslator extension installed)
+ */
+ let chromehidden = document.documentElement.getAttribute("chromehidden");
+ let stopInitialization = chromehidden.indexOf("extrachrome") > -1 ||
+ chromehidden.indexOf("toolbar") > -1;
+ Tabmix.singleWindowMode = Tabmix.prefs.getBoolPref("singleWindow");
+ if (!stopInitialization && Tabmix.singleWindowMode) {
+ let tmp = { };
+ Components.utils.import("resource://tabmixplus/SingleWindowModeUtils.jsm", tmp);
+ stopInitialization = tmp.SingleWindowModeUtils.newWindow(window);
+ }
+
+ if (!stopInitialization) {
+ let tabBrowser = arguments.length > 1 ? arguments[1] : gBrowser;
+ stopInitialization = typeof tabBrowser.tabContainer.setFirstTabInRow != "function";
+ }
+
+ if (stopInitialization) {
+ this.run = function() {}
+ window.removeEventListener("DOMContentLoaded", TMP_eventListener, false);
+ window.removeEventListener("load", TMP_eventListener, false);
+ }
+
+ delete this.isValidWindow;
+ Object.defineProperty(this, "run", {enumerable: false});
+ Object.defineProperty(this, "isValidWindow", {value: !stopInitialization,
+ enumerable: false});
+ return this.isValidWindow;
+ },
+
+ run: function tabmix_initialization_run(aPhase) {
+ if (!this.isValidWindow)
+ return null;
+ let result, currentPhase = this[aPhase].id;
+ for (let [name, phase] in Iterator(this)) {
+ if (phase.id > currentPhase)
+ break;
+ if (!phase.initialized) {
+ phase.initialized = true;
+ try {
+ let obj = window[phase.obj];
+ result = obj[name].apply(obj, Array.slice(arguments, 1));
+ } catch (ex) {
+ Tabmix.assert(ex, phase.obj + "." + name + " failed");
+ }
+ }
+ }
+ return result;
+ }
+}
+
+TMP_eventListener.init();
diff --git a/chrome/content/utils.js b/chrome/content/utils.js
index f29a58d..d3f6ce8 100644
--- a/chrome/content/utils.js
+++ b/chrome/content/utils.js
@@ -1,20 +1,6 @@
"use strict";
var Tabmix = {
- // aOptions can be: getter, setter or forceUpdate
- changeCode: function(aParent, aName, aOptions) {
- let fnName = aName.split(".").pop();
- try {
- return new Tabmix_ChangeCode({obj: aParent, fnName: fnName,
- fullName: aName, options: aOptions});
- } catch (ex) {
- this.clog(Tabmix.callerName() + " failed to change " + aName + "\nError: " + ex.message);
- if (Tabmix._debugMode)
- this.obj(aObject, "aObject");
- }
- return null;
- },
-
get prefs() {
delete this.prefs;
return this.prefs = Services.prefs.getBranch("extensions.tabmix.");
@@ -66,7 +52,7 @@ var Tabmix = {
// so we can open new window
if (!this.getTopWin())
return false;
- return Tabmix.prefs.getBoolPref("singleWindow");
+ return this.prefs.getBoolPref("singleWindow");
},
isNewWindowAllow: function(isPrivate) {
@@ -97,14 +83,18 @@ var Tabmix = {
return;
var self = this;
- XPCOMUtils.defineLazyGetter(aObject, aOldName, function() {
- self.informAboutChangeInTabmix(aOldName, aNewName);
- return self.getObject(window, aNewName);
+ Object.defineProperty(aObject, aOldName, {
+ get: function () {
+ self.informAboutChangeInTabmix(aOldName, aNewName);
+ delete aObject[aOldName];
+ return aObject[aOldName] = self.getObject(window, aNewName);
+ },
+ configurable: true
});
},
informAboutChangeInTabmix: function(aOldName, aNewName) {
- let err = Error(aOldName + " is deprecated in Tabmix since version 0.3.8.5pre.110123a use " + aNewName + " instead.");
+ let err = Error(aOldName + " is deprecated in Tabmix, use " + aNewName + " instead.");
// cut off the first lines, we looking for the function that trigger the getter.
let stack = Error().stack.split("\n").slice(3);
let file = stack[0] ? stack[0].split(":") : null;
@@ -200,6 +190,30 @@ var Tabmix = {
compare: function TMP_utils_compare(a, b, lessThan) {return lessThan ? a < b : a > b;},
itemEnd: function TMP_utils_itemEnd(item, end) {return item.boxObject.screenX + (end ? item.getBoundingClientRect().width : 0);},
+ show: function(aMethod, aDelay, aWindow) {
+ TabmixSvc.console.show(aMethod, aDelay, aWindow || window);
+ },
+
+ // console._removeInternal use this function name to remove it from
+ // caller list
+ __noSuchMethod__: function TMP_console_wrapper(id, args) {
+ if (["changeCode", "setNewFunction", "nonStrictMode"].indexOf(id) > -1) {
+ this.installeChangecode;
+ return this[id].apply(this, args);
+ }
+ if (typeof TabmixSvc.console[id] == "function") {
+ return TabmixSvc.console[id].apply(TabmixSvc.console, args);
+ }
+ TabmixSvc.console.trace("unexpected method " + id);
+ return null;
+ },
+
+ get installeChangecode() {
+ delete this.installeChangecode;
+ Services.scriptloader.loadSubScript("chrome://tabmixplus/content/changecode.js", window);
+ return this.installeChangecode = true;
+ },
+
_init: function() {
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
Components.utils.import("resource://gre/modules/Services.jsm");
@@ -210,17 +224,10 @@ var Tabmix = {
resource + "modules/RecentWindow.jsm");
}
- let tmp = {};
- Components.utils.import("resource://tabmixplus/log.jsm", tmp);
- for (let [fnName, value] in Iterator(tmp.log))
- this[fnName] = typeof value == "function" ? value.bind(this) : value;
-
window.addEventListener("unload", function tabmix_destroy() {
window.removeEventListener("unload", tabmix_destroy, false);
this.destroy();
}.bind(this), false);
-
- Services.scriptloader.loadSubScript("chrome://tabmixplus/content/changecode.js", window);
},
originalFunctions: {},
@@ -228,10 +235,6 @@ var Tabmix = {
this.toCode = null;
this.originalFunctions = null;
delete this.window;
- for (let [id, timer] in Iterator(this._timers)) {
- timer.cancel();
- delete this._timers[id];
- }
}
}
diff --git a/chrome/skin/app_version/4.0/linux/browser.css b/chrome/skin/app_version/4.0/linux/browser.css
index 1c16a13..08989c9 100644
--- a/chrome/skin/app_version/4.0/linux/browser.css
+++ b/chrome/skin/app_version/4.0/linux/browser.css
@@ -26,7 +26,7 @@
}
/* set on linux we need to set vertical alogn even if the button is hidden*/
-.tabbrowser-tabs[multibar] .tabbrowser-arrowscrollbox > .tabs-newtab-button {
+.tabbrowser-tabs[multibar] .tabbrowser-arrowscrollbox > toolbarbutton {
vertical-align: bottom;
}
diff --git a/chrome/skin/app_version/4.0/mac/browser.css b/chrome/skin/app_version/4.0/mac/browser.css
index af44236..d926529 100644
--- a/chrome/skin/app_version/4.0/mac/browser.css
+++ b/chrome/skin/app_version/4.0/mac/browser.css
@@ -31,7 +31,7 @@
margin-top: 1px !important;
}
-.tabbrowser-tabs[multibar=true] .tabbrowser-arrowscrollbox > .tabs-newtab-button {
+.tabbrowser-tabs[multibar=true] .tabbrowser-arrowscrollbox > toolbarbutton {
vertical-align: bottom;
}
diff --git a/chrome/skin/app_version/4.0/win/browser.css b/chrome/skin/app_version/4.0/win/browser.css
index 47142c0..98d93bc 100644
--- a/chrome/skin/app_version/4.0/win/browser.css
+++ b/chrome/skin/app_version/4.0/win/browser.css
@@ -21,12 +21,12 @@
}
/* new tab button after last tab on firefox 4.0 aero */
-#TabsToolbar[tabmix_aero] .tabbrowser-tabs[multibar=true] .tabbrowser-arrowscrollbox > .tabs-newtab-button {
+#TabsToolbar[tabmix_aero] .tabbrowser-tabs[multibar=true] .tabbrowser-arrowscrollbox > toolbarbutton {
vertical-align: bottom;
}
/* enable this rule after bug 738491 australis-tabs-win lands, and move it to diffrent file
-#tabbrowser-tabs[flowing="multibar"]:not([multibar]) > .tabbrowser-arrowscrollbox > .tabs-newtab-button {
+#tabbrowser-tabs[flowing="multibar"]:not([multibar]) > .tabbrowser-arrowscrollbox > toolbarbutton {
vertical-align: bottom;
}
*/
@@ -36,9 +36,8 @@
padding-bottom: 3px;
}
-#TabsToolbar[multibar] > .toolbarbutton-1,
#TabsToolbar[multibar] > #tabs-closebutton {
- height: 26px;
+ padding-top: 5px;
}
/* for TabsToolbar on bottom with windows 7 */
diff --git a/chrome/skin/tab.css b/chrome/skin/tab.css
index 315f93f..48d4cdb 100644
--- a/chrome/skin/tab.css
+++ b/chrome/skin/tab.css
@@ -323,14 +323,14 @@ toolbar[iconsize=small] #btn_sessionmanager[disabled=true], .sessionmanager-icon
}
/* CrystalFox_Qute-BigRedBrent */
-.tabbrowser-tabs[tabmix_skin="CrystalFox"]:not([multibar])[inline=true] .tabbrowser-arrowscrollbox > .tabs-newtab-button,
-.tabbrowser-tabs[tabmix_skin="CrystalFox"][multibar] .tabbrowser-arrowscrollbox > .tabs-newtab-button {
+.tabbrowser-tabs[tabmix_skin="CrystalFox"]:not([multibar])[inline=true] .tabbrowser-arrowscrollbox > toolbarbutton,
+.tabbrowser-tabs[tabmix_skin="CrystalFox"][multibar] .tabbrowser-arrowscrollbox > toolbarbutton {
vertical-align: top;
}
/* BlackFox_V1-Blue */
-.tabbrowser-tabs[tabmix_skin="BlackFox"]:not([multibar])[inline=true] .tabbrowser-arrowscrollbox > .tabs-newtab-button,
-.tabbrowser-tabs[tabmix_skin="BlackFox"][multibar] .tabbrowser-arrowscrollbox > .tabs-newtab-button {
+.tabbrowser-tabs[tabmix_skin="BlackFox"]:not([multibar])[inline=true] .tabbrowser-arrowscrollbox > toolbarbutton,
+.tabbrowser-tabs[tabmix_skin="BlackFox"][multibar] .tabbrowser-arrowscrollbox > toolbarbutton {
vertical-align: top;
}
diff --git a/defaults/preferences/tabmix.js b/defaults/preferences/tabmix.js
index d513c95..13b7824 100644
--- a/defaults/preferences/tabmix.js
+++ b/defaults/preferences/tabmix.js
@@ -106,7 +106,13 @@ pref("extensions.tabmix.tabs.closeButtons.delay", 50);
pref("extensions.tabmix.moveTabOnDragging", true);
pref("extensions.tabmix.useFirefoxDragmark", true);
+/*
pref("extensions.tabmix.enableScrollSwitch", false);
+ replaced by scrollTabs: 0 - scrool tabbar on overflow - default
+ 1 - scroll change selected tab
+ 2 - disable scroll over tabs
+*/
+pref("extensions.tabmix.scrollTabs", 0);
pref("extensions.tabmix.reversedScroll", false);
pref("extensions.tabmix.dblClickTab", 0);
diff --git a/install.rdf b/install.rdf
index 0f9ea38..20d6c27 100644
--- a/install.rdf
+++ b/install.rdf
@@ -5,7 +5,7 @@
<RDF:Description RDF:about="urn:mozilla:install-manifest"
NS1:id="{dc572301-7619-498c-a57d-39143191b318}"
NS1:name="Tab Mix Plus"
- NS1:version="0.4.1.1pre.130821b"
+ NS1:version="0.4.1.2pre.130918a"
NS1:type="2"
NS1:description="Tab browsing with an added boost."
NS1:iconURL="chrome://tabmixplus/skin/tmp.png"
@@ -19,5 +19,5 @@
<RDF:Description RDF:about="rdf:#$n83In3"
NS1:id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}"
NS1:minVersion="11.0"
- NS1:maxVersion="26.0a1" />
+ NS1:maxVersion="27.0a1" />
</RDF:RDF>
diff --git a/modules/AutoReload.jsm b/modules/AutoReload.jsm
index 0d995b7..56f4333 100644
--- a/modules/AutoReload.jsm
+++ b/modules/AutoReload.jsm
@@ -260,7 +260,8 @@ function _observe(aSubject, aTopic, aData) {
if (aTopic == "common-dialog-loaded") {
TabmixSvc.obs.removeObserver(_observe, "common-dialog-loaded");
let icon = aSubject.document.getElementById("info.icon");
- icon.className = icon.className.replace("question-icon" ,"alert-icon");
+ icon.classList.add("alert-icon");
+ icon.classList.remove("question-icon");
}
}
diff --git a/modules/MergeWindows.jsm b/modules/MergeWindows.jsm
index cf8f139..916bbf9 100644
--- a/modules/MergeWindows.jsm
+++ b/modules/MergeWindows.jsm
@@ -102,7 +102,8 @@ let MergeWindows = {
var features = "chrome,all,dialog=no";
if (TabmixSvc.version(200))
features += aPrivate ? ",private" : ",non-private";
- var newWindow = aWindows[0].openDialog(aWindows[0].getBrowserURL(), "_blank", features, null);
+ var newWindow = aWindows[0].openDialog("chrome://browser/content/browser.xul",
+ "_blank", features, null);
let mergePopUps = function _mergePopUps(aEvent) {
newWindow.removeEventListener("SSWindowStateReady", _mergePopUps, false);
this.concatTabsAndMerge(newWindow, aWindows);
diff --git a/modules/Places.jsm b/modules/Places.jsm
new file mode 100644
index 0000000..0b4a20b
--- /dev/null
+++ b/modules/Places.jsm
@@ -0,0 +1,173 @@
+"use strict";
+
+var EXPORTED_SYMBOLS = ["TabmixPlacesUtils"];
+
+const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "Services",
+ "resource://gre/modules/Services.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
+ "resource://gre/modules/PluralForm.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
+ "resource://gre/modules/PrivateBrowsingUtils.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "PlacesUIUtils",
+ "resource:///modules/PlacesUIUtils.jsm");
+
+XPCOMUtils.defineLazyGetter(this, "PlacesUtils", function() {
+ Cu.import("resource://gre/modules/PlacesUtils.jsm");
+ return PlacesUtils;
+});
+
+XPCOMUtils.defineLazyModuleGetter(this,
+ "TabmixSvc", "resource://tabmixplus/Services.jsm");
+
+this.TabmixPlacesUtils = {
+ init: function(aWindow) {
+ PlacesUtilsInternal.init(aWindow);
+ },
+
+ onQuitApplication: function() {
+ PlacesUtilsInternal.onQuitApplication();
+ }
+}
+Object.freeze(TabmixPlacesUtils);
+
+let global = this; // for Firefox 11-14
+let Tabmix = { }
+
+let PlacesUtilsInternal = {
+ _timer: null,
+ _initialized: false,
+
+ init: function(aWindow) {
+ if (this._initialized)
+ return;
+ this._initialized = true;
+
+ Tabmix._debugMode = aWindow.Tabmix._debugMode;
+ Services.scriptloader.loadSubScript("chrome://tabmixplus/content/changecode.js", global);
+
+ this.initPlacesUIUtils(aWindow);
+ },
+
+ onQuitApplication: function () {
+ if (this._timer)
+ this._timer.clear();
+
+ this.functions.forEach(function(aFn) {
+ PlacesUIUtils[aFn] = PlacesUIUtils["tabmix_" + aFn];
+ delete PlacesUIUtils["tabmix_" + aFn];
+ });
+ delete PlacesUIUtils.tabmix_getURLsForContainerNode;
+ },
+
+ functions: ["_openTabset", "openURINodesInTabs", "openContainerNodeInTabs", "openNodeWithEvent", "_openNodeIn"],
+ initPlacesUIUtils: function TMP_PC_initPlacesUIUtils(aWindow) {
+ try {
+ let test = PlacesUIUtils._openTabset.toString();
+ } catch (ex) {
+ if (aWindow.document.documentElement.getAttribute("windowtype") == "navigator:browser") {
+ TabmixSvc.console.log("Starting with Firefox 21 Imacros 8.3.0 break toString on PlacesUIUtils functions."
+ + "\nTabmix can't update PlacesUIUtils to work according to Tabmix preferences, use Imacros 8.3.1 and up.");
+ }
+ return;
+ }
+
+ this.functions.forEach(function(aFn) {
+ PlacesUIUtils["tabmix_" + aFn] = PlacesUIUtils[aFn];
+ });
+
+ var treeStyleTab = "TreeStyleTabBookmarksService" in aWindow;
+ function updateOpenTabset() {
+ let openGroup = " browserWindow.TMP_Places.openGroup(urls, ids, where$1);"
+ Tabmix.changeCode(PlacesUIUtils, "PlacesUIUtils._openTabset")._replace(
+ 'urls = []',
+ 'behavior, $&', {check: treeStyleTab}
+ )._replace(
+ 'var urls = []',
+ '$&, ids = []', {check: !treeStyleTab}
+ )._replace(
+ 'urls.push(item.uri);',
+ '$&\n' +
+ ' ids.push(item.id);', {check: !treeStyleTab}
+ )._replace(
+ '"chrome,dialog=no,all", args);',
+ '$&\n' +
+ ' browserWindow.bookMarkIds = ids.join("|");'
+ )._replace(
+ /let openGroupBookmarkBehavior =|TSTOpenGroupBookmarkBehavior =/,
+ '$& behavior =', {check: treeStyleTab}
+ )._replace(
+ 'browserWindow.gBrowser.loadTabs(urls, loadInBackground, false);',
+ 'var changeWhere = where == "tabshifted" && aEvent.target.localName != "menuitem";\n' +
+ ' if (changeWhere)\n' +
+ ' where = "current";\n' +
+ openGroup.replace("$1", treeStyleTab ? ", behavior" : "")
+ ).toCode();
+ };
+ if (treeStyleTab) {
+ let timer = this._timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
+ timer.initWithCallback(function() {
+ timer.cancel();
+ this._timer = null;
+ updateOpenTabset();
+ }.bind(this), 50, Ci.nsITimer.TYPE_ONE_SHOT);
+ }
+ else { // TreeStyleTab not installed
+ updateOpenTabset();
+
+ Tabmix.changeCode(PlacesUIUtils, "PlacesUIUtils.openURINodesInTabs")._replace(
+ 'push({uri: aNodes[i].uri,',
+ 'push({id: aNodes[i].itemId, uri: aNodes[i].uri,'
+ ).toCode();
+
+ // we enter getURLsForContainerNode into PlacesUIUtils to prevent leakes from PlacesUtils
+ Tabmix.changeCode(PlacesUtils, "PlacesUtils.getURLsForContainerNode")._replace(
+ '{uri: child.uri,',
+ '{id: child.itemId, uri: child.uri,', {flags: "g"}
+ )._replace(
+ 'this.', 'PlacesUtils.', {flags: "g"}
+ ).toCode(false, PlacesUIUtils, "tabmix_getURLsForContainerNode");
+
+ Tabmix.changeCode(PlacesUIUtils, "PlacesUIUtils.openContainerNodeInTabs")._replace(
+ 'PlacesUtils.getURLsForContainerNode(aNode)',
+ 'PlacesUIUtils.tabmix_getURLsForContainerNode(aNode)'
+ ).toCode();
+ }
+
+ Tabmix.changeCode(PlacesUIUtils, "PlacesUIUtils.openNodeWithEvent")._replace(
+ /whereToOpenLink\(aEvent[,\s\w]*\), window/, '$&, aEvent'
+ ).toCode();
+
+ // Don't change "current" when user click context menu open (callee is PC_doCommand and aWhere is current)
+ // we disable the open menu when the tab is lock
+ // the 2nd check for aWhere == "current" is for non Firefox code that may call this function
+ Tabmix.changeCode(PlacesUIUtils, "PlacesUIUtils._openNodeIn")._replace(
+ /(function[^\(]*\([^\)]+)(\))/,
+ '$1, TMP_Event$2' /* event argument exist when this function called from openNodeWithEvent */
+ )._replace(
+ 'aWindow.openUILinkIn',
+ 'let browserWindow = this._getTopBrowserWin();\n' +
+ ' if (browserWindow && typeof browserWindow.TMP_Places == "object") {\n' +
+ ' if (TMP_Event) aWhere = browserWindow.TMP_Places.isBookmarklet(aNode.uri) ? "current" :\n' +
+ ' browserWindow.TMP_Places.fixWhereToOpen(TMP_Event, aWhere);\n' +
+ ' else if (aWhere == "current" && !browserWindow.TMP_Places.isBookmarklet(aNode.uri)) {\n' +
+ ' let caller = browserWindow.Tabmix.getCallerNameByIndex(2);\n' +
+ ' if (caller != "PC_doCommand")\n' +
+ ' aWhere = browserWindow.TMP_Places.fixWhereToOpen(null, aWhere);\n' +
+ ' }\n' +
+ ' }\n' +
+ ' if (browserWindow && aWhere == "current") browserWindow.gBrowser.mCurrentBrowser.tabmix_allowLoad = true;\n' +
+ ' $&'
+ )._replace(
+ 'inBackground:',
+ 'bookMarkId: aNode.itemId, initiatingDoc: null,\n' +
+ ' $&'
+ ).toCode();
+ }
+}
diff --git a/modules/RenameTab.jsm b/modules/RenameTab.jsm
index 1949f35..b345388 100644
--- a/modules/RenameTab.jsm
+++ b/modules/RenameTab.jsm
@@ -23,9 +23,11 @@ let RenameTab = {
this.window.TMP_SessionStore.getTitleFromTabState(aTab) :
browser.contentDocument.title;
this.data.url = browser.currentURI.spec;
- docTitle = this.window.TMP_Places.getTitleFromBookmark(this.data.url,
+ this.data.docTitle = this.window.TMP_Places.getTitleFromBookmark(this.data.url,
docTitle, null, aTab);
- this.data.docTitle = docTitle || gBrowser.mStringBundle.getString("tabs.emptyTabTitle");
+ if (!this.data.docTitle)
+ this.data.docTitle = this.window.isBlankPageURL(this.data.url) ?
+ gBrowser.mStringBundle.getString("tabs.emptyTabTitle") : this.data.url;
this.data.modified = aTab.getAttribute("label-uri") || null;
if (this.data.modified == this.data.url || this.data.modified == "*")
this.data.value = aTab.getAttribute("fixed-label");
diff --git a/modules/Services.jsm b/modules/Services.jsm
index 93851eb..247d3d2 100644
--- a/modules/Services.jsm
+++ b/modules/Services.jsm
@@ -73,6 +73,22 @@ let TabmixSvc = {
return this.direct2dDisabled = false;
},
+ /**
+ * call a callback for all currently opened browser windows
+ * (might miss the most recent one)
+ * @param aFunc
+ * Callback each window is passed to
+ */
+ forEachBrowserWindow: function(aFunc) {
+ let windowsEnum = Services.wm.getEnumerator("navigator:browser");
+ while (windowsEnum.hasMoreElements()) {
+ let window = windowsEnum.getNext();
+ if (!window.closed) {
+ aFunc.call(null, window);
+ }
+ }
+ },
+
// some extensions override native JSON so we use nsIJSON
JSON: {
nsIJSON: null,
@@ -97,7 +113,8 @@ let TabmixSvc = {
},
windowStartup: {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsISupportsWeakReference]),
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
+ Ci.nsISupportsWeakReference]),
_initialized: false,
init: function(aWindow) {
// windowStartup must only be called once for each window
@@ -109,14 +126,23 @@ let TabmixSvc = {
this._initialized = true;
Services.obs.addObserver(this, "browser-delayed-startup-finished", true);
+ Services.obs.addObserver(this, "quit-application", true);
+
+ Cu.import("resource://tabmixplus/Places.jsm");
+ TabmixPlacesUtils.init(aWindow);
},
observe: function(aSubject, aTopic, aData) {
switch (aTopic) {
+ case "quit-application":
+ TabmixPlacesUtils.onQuitApplication();
+ for (let [id, timer] in Iterator(TabmixSvc.console._timers))
+ timer.cancel();
+ break;
case "browser-delayed-startup-finished":
try {
- aSubject.TMP_eventListener.browserDelayedStartupFinished();
- } catch (ex) {log.assert(ex);}
+ aSubject.Tabmix.initialization.run("delayedStartup");
+ } catch (ex) {this.console.assert(ex);}
break;
}
}
@@ -131,7 +157,8 @@ let TabmixSvc = {
delete this.sanitized;
return this.sanitized = TabmixSvc.prefBranch.prefHasUserValue("sessions.sanitized");
},
- private: true
+ private: true,
+ settingPreference: false,
}
}
@@ -145,7 +172,6 @@ XPCOMUtils.defineLazyGetter(TabmixSvc.JSON, "nsIJSON", function() {
*/
XPCOMUtils.defineLazyGetter(TabmixSvc, "prefs", function () {return Services.prefs});
XPCOMUtils.defineLazyGetter(TabmixSvc, "io", function () {return Services.io});
-XPCOMUtils.defineLazyGetter(TabmixSvc, "console", function () {return Services.console});
XPCOMUtils.defineLazyGetter(TabmixSvc, "wm", function () {return Services.wm});
XPCOMUtils.defineLazyGetter(TabmixSvc, "obs", function () {return Services.obs});
XPCOMUtils.defineLazyGetter(TabmixSvc, "prompt", function () {return Services.prompt});
@@ -167,5 +193,5 @@ XPCOMUtils.defineLazyServiceGetter(TabmixSvc, "ss", "@mozilla.org/browser/sessio
XPCOMUtils.defineLazyModuleGetter(TabmixSvc, "FileUtils",
"resource://gre/modules/FileUtils.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "log",
+XPCOMUtils.defineLazyModuleGetter(TabmixSvc, "console",
"resource://tabmixplus/log.jsm");
diff --git a/modules/Shortcuts.jsm b/modules/Shortcuts.jsm
index f1af0fb..9550c14 100644
--- a/modules/Shortcuts.jsm
+++ b/modules/Shortcuts.jsm
@@ -6,7 +6,6 @@ const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
const NS_XUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://tabmixplus/Services.jsm");
-Cu.import("resource://tabmixplus/log.jsm");
let Shortcuts = {
keys: {
@@ -138,7 +137,7 @@ try {
}
this.updatingShortcuts = false;
-} catch (ex) {log.assert(ex);}
+} catch (ex) {TabmixSvc.console.assert(ex);}
},
/* ........ Window Event Handlers .............. */
@@ -159,7 +158,7 @@ try {
let win = aKey.ownerDocument.defaultView;
let command = this.keys[aKey._id].command;
win.TabmixTabClickOptions.doCommand(command, win.gBrowser.selectedTab);
-} catch (ex) {log.assert(ex);}
+} catch (ex) {TabmixSvc.console.assert(ex);}
},
onUnload: function TMP_SC_onUnload(aWindow) {
@@ -269,7 +268,7 @@ try {
shortcuts = JSON.parse(this.prefs.getCharPref("shortcuts"));
} catch (ex) {}
if (shortcuts == null) {
- log.log("failed to read shortcuts preference.\nAll shortcuts was resets to default");
+ TabmixSvc.console.log("failed to read shortcuts preference.\nAll shortcuts was resets to default");
shortcuts = {};
updatePreference = true;
}
diff --git a/modules/extensions/SessionManagerAddon.jsm b/modules/extensions/AddonManager.jsm
similarity index 53%
rename from modules/extensions/SessionManagerAddon.jsm
rename to modules/extensions/AddonManager.jsm
index 1ec79d9..29aa72a 100644
--- a/modules/extensions/SessionManagerAddon.jsm
+++ b/modules/extensions/AddonManager.jsm
@@ -4,32 +4,59 @@
"use strict";
-var EXPORTED_SYMBOLS = ["SessionManagerAddon"];
+var EXPORTED_SYMBOLS = ["TabmixAddonManager"];
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
Cu.import("resource://gre/modules/AddonManager.jsm");
Cu.import("resource://tabmixplus/Services.jsm");
-let TabmixListener = {
+function log(msg) {
+ TabmixSvc.console.log(msg);
+}
+
+// https://addons.mozilla.org/en-US/firefox/addon/private-tab
+let PrivateTab = {
+ id: "privateTab at infocatcher",
+ onEnabled: function() {
+ this._resetNewTabButton();
+ },
+ onDisabled: function() {
+ this._resetNewTabButton();
+ },
+ _resetNewTabButton: function() {
+ TabmixSvc.forEachBrowserWindow(function(aWindow) {
+ aWindow.TMP_eventListener.updateMultiRow(true);
+ });
+ }
+}
+
+let SessionManager = {
id: "{1280606b-2510-4fe0-97ef-9b5a22eafe30}",
- saveTabmixPrefs: function(addon) {
+ init: function() {
+ this._saveTabmixPrefs();
+ try {
+ let tmp = {}
+ Cu.import("chrome://sessionmanager/content/modules/session_manager.jsm", tmp);
+ TabmixSvc.sessionManagerAddonInstalled = true;
+ }
+ catch (ex) {
+ TabmixSvc.sessionManagerAddonInstalled = false;
+ }
+ },
+ _saveTabmixPrefs: function() {
this.manager_enabled = TabmixSvc.prefBranch.getBoolPref("sessions.manager");
this.crashRecovery_enabled = TabmixSvc.prefBranch.getBoolPref("sessions.crashRecovery");
},
- onEnabled: function(addon) {
- if (addon.id != this.id)
- return;
+ onEnabled: function() {
TabmixSvc.sessionManagerAddonInstalled = true;
- this.saveTabmixPrefs();
+ this._saveTabmixPrefs();
let win = TabmixSvc.topWin();
if (win)
win.TMP_SessionStore.setService(-1);
- this.notify(true);
+ this._notify(true);
},
- onDisabled: function(addon) {
- if (addon.id != this.id)
- return;
+ onDisabled: function() {
TabmixSvc.sessionManagerAddonInstalled = false;
if (this.manager_enabled || this.crashRecovery_enabled) {
let win = TabmixSvc.topWin();
@@ -38,15 +65,9 @@ let TabmixListener = {
TabmixSvc.prefBranch.setBoolPref("sessions.manager", this.manager_enabled);
TabmixSvc.prefBranch.setBoolPref("sessions.crashRecovery", this.crashRecovery_enabled);
}
- this.notify(false);
+ this._notify(false);
},
- onInstalled: function(addon) {
- if (addon.id != this.id ||
- !addon.isActive || addon.userDisabled || addon.appDisabled)
- return;
- this.onEnabled(addon);
- },
- notify: function(isActive) {
+ _notify: function(isActive) {
// in preference/session.js we only care when the preference is boolean
let pref = "sessionManagerAddon.isActive";
TabmixSvc.prefBranch.setBoolPref(pref, isActive);
@@ -54,24 +75,38 @@ let TabmixListener = {
}
}
-let SessionManagerAddon = {
+let TabmixListener = {
+ onChange: function(aAddon, aAction) {
+ let id = aAddon.id
+ if (id == SessionManager.id)
+ SessionManager[aAction]();
+ else if (id == PrivateTab.id) {
+ PrivateTab[aAction]();
+ }
+ },
+ onEnabled: function(aAddon) {
+ this.onChange(aAddon, "onEnabled");
+ },
+ onDisabled: function(aAddon) {
+ this.onChange(aAddon, "onDisabled");
+ },
+ onInstalled: function(aAddon) {
+ if (!aAddon.isActive || aAddon.userDisabled || aAddon.appDisabled)
+ return;
+ this.onEnabled(aAddon);
+ }
+}
+
+let TabmixAddonManager = {
initialized: false,
init: function() {
if (this.initialized)
return;
this.initialized = true;
- TabmixListener.saveTabmixPrefs();
- AddonManager.addAddonListener(TabmixListener);
- try {
- let tmp = {}
- Cu.import("chrome://sessionmanager/content/modules/session_manager.jsm", tmp);
- TabmixSvc.sessionManagerAddonInstalled = true;
- }
- catch (ex) {
- TabmixSvc.sessionManagerAddonInstalled = false;
- }
+ SessionManager.init();
+ AddonManager.addAddonListener(TabmixListener);
}
}
-SessionManagerAddon.init();
+TabmixAddonManager.init();
diff --git a/modules/extensions/TabGroupsManager.jsm b/modules/extensions/TabGroupsManager.jsm
index 88bdf46..a911238 100644
--- a/modules/extensions/TabGroupsManager.jsm
+++ b/modules/extensions/TabGroupsManager.jsm
@@ -54,7 +54,7 @@ let TMP_TabGroupsManager = {
let sessionManager = aWindow.TabmixSessionManager;
this.changeCode(sessionManager, "TabmixSessionManager.saveOneWindow")._replace(
'if (caller == "windowbackup")',
- ' this.saveAllGroupsData(null, rdfNodeThisWindow);' +
+ ' try{this.saveAllGroupsData(null, rdfNodeThisWindow);} catch(ex) {Tabmix.assert(ex);}' +
' $&'
).toCode();
@@ -88,7 +88,7 @@ let TMP_TabGroupsManager = {
'}' +
'if (false) {'
)._replace(
- 'if (this.saveClosedtabs)',
+ 'TMP_ClosedTabs.setButtonDisableState();',
' if (_restoreSelect && (overwrite || (!concatenate && !currentTabIsBalnk)))' +
' this.updateSelected(newIndex + _lastSelectedIndex, overwrite || caller=="firstwindowopen" || caller=="windowopenedbytabmix");' +
' $&'
@@ -113,7 +113,8 @@ let TMP_TabGroupsManager = {
// for TabGroupsManager use - don't change function name from tabmixSessionsManager
aWindow.TMP_TabGroupsManager = {}
aWindow.TMP_TabGroupsManager.tabmixSessionsManager = this.tabmixSessionsManager.bind(aWindow);
- aWindow.Tabmix.toCode(sessionManager, "saveAllGroupsData", this._saveAllGroupsData.toString());
+ this.changeCode(this, "TMP_TabGroupsManager._saveAllGroupsData", {forceUpdate: true})
+ .toCode(false, aWindow.TabmixSessionManager, "saveAllGroupsData");
},
// for TabGroupsManager use - don't change function name
diff --git a/modules/log.jsm b/modules/log.jsm
index 9981b5c..515e38f 100644
--- a/modules/log.jsm
+++ b/modules/log.jsm
@@ -1,13 +1,25 @@
"use strict";
-var EXPORTED_SYMBOLS = ["log"];
+var EXPORTED_SYMBOLS = ["console"];
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
+Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://tabmixplus/Services.jsm");
-let log = {
+let gNextID = 1;
+
+let console = {
getObject: function(aWindow, aMethod) {
+ let msg = "";
+ if (!aWindow)
+ msg += "aWindow is undefined";
+ if (typeof aMethod != "string")
+ msg += (msg ? "\n" : "") + "aMethod need to be a string";
+ if (msg) {
+ this.assert(msg);
+ return {toString: function() msg};
+ }
var rootID, methodsList = aMethod.split(".");
if (methodsList[0] == "window")
methodsList.shift();
@@ -16,8 +28,7 @@ let log = {
rootID = methodsList.shift().replace(/getElementById\(|\)|'|"/g , "");
}
try {
- // this.window is only defined when we import this function into Tabmix
- var obj = aWindow || this.window;
+ var obj = aWindow;
if (rootID)
obj = obj.document.getElementById(rootID);
methodsList.forEach(function(aFn) {
@@ -27,7 +38,6 @@ let log = {
return obj || {toString: function() "undefined"};
},
- _nextID: 0,
_timers: {},
show: function(aMethod, aDelay, aWindow) {
try {
@@ -35,21 +45,34 @@ let log = {
aDelay = 500;
let logMethod = function _logMethod() {
- let isObj = typeof aMethod == "object";
- let result = isObj ? aMethod.obj[aMethod.name] :
+ let result = "", isObj = typeof aMethod == "object";
+ if (typeof aMethod != "function") {
+ result = isObj ? aMethod.obj[aMethod.name] :
this.getObject(aWindow, aMethod);
- this.clog((isObj ? aMethod.fullName : aMethod) + " = " + result.toString());
+ result = " = " + result.toString()
+ }
+ this.clog((isObj ? aMethod.fullName : aMethod) + result);
}.bind(this);
if (aDelay >= 0) {
- let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
- let timerID = this._nextID++;
+ let timer = {};
+ timer.__proto__ = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
+ let timerID = gNextID++;
this._timers[timerID] = timer;
- timer.initWithCallback(function() {
- if (timerID in this._timers && this._timers[timerID] === timer)
+ timer.clear = function() {
+ if (timerID in this._timers)
delete this._timers[timerID];
+ timer.cancel();
+ }.bind(this);
+ if (aWindow) {
+ aWindow.addEventListener("unload", function unload() {
+ timer.clear();
+ }, false);
+ }
+ timer.initWithCallback(function() {
+ timer.clear();
logMethod();
- }.bind(this), aDelay, Ci.nsITimer.TYPE_ONE_SHOT);
+ }, aDelay, Ci.nsITimer.TYPE_ONE_SHOT);
}
else
logMethod();
@@ -57,49 +80,54 @@ let log = {
} catch (ex) {this.assert(ex, "Error we can't show " + aMethod + " in Tabmix.show");}
},
- clog: function TMP_clog(aMessage) {
- TabmixSvc.console.logStringMessage("TabMix :\n" + aMessage);
+ clog: function(aMessage) {
+ Services.console.logStringMessage("TabMix :\n" + aMessage);
},
- log: function TMP_log(aMessage, aShowCaller, offset) {
+ log: function TMP_console_log(aMessage, aShowCaller, offset) {
offset = !offset ? 0 : 1;
let names = this._getNames(aShowCaller ? 2 + offset : 1 + offset);
let callerName = names[offset+0];
- let callerCallerName = aShowCaller ? " (caller was " + names[offset+1] + ")" : "";
- TabmixSvc.console.logStringMessage("TabMix " + callerName + callerCallerName + " :\n" + aMessage);
+ let callerCallerName = aShowCaller && names[offset+1] ? " (caller was " + names[offset+1] + ")" : "";
+ Services.console.logStringMessage("TabMix " + callerName + callerCallerName + " :\n" + aMessage);
},
// get functions names from Error().stack
+ // excluding any internal caller (name start with TMP_console_)
_getNames: function(aCount, stack) {
- if (!stack)
- stack = Error().stack.split("\n").slice(1);
- else
- stack = stack.split("\n");
- // cut the secound if it is from our utils
- if (stack[0].indexOf("TMP_") == 0)
- stack.splice(0, 1);
+ stack = this._getStackExcludingInternal(stack);
if (!aCount)
aCount = 1;
else if (aCount < 0)
aCount = stack.length;
let names = [];
- for (let i = 0; i < aCount; i++)
+ for (let i = 0, l = Math.min(aCount, stack.length); i < l; i++)
names.push(this._name(stack[i]));
return names;
},
// get the name of the function that is in the nth place in Error().stack
- // don't include this function in the count
- _getCallerNameByIndex: function TMP_getCallerNameByIndex(aPlace) {
- let stack = Error().stack.split("\n");
- let fn = stack[aPlace + 1];
-
+ // excluding any internal caller in the count
+ getCallerNameByIndex: function(aIndex) {
+ let fn = this._getStackExcludingInternal()[aIndex];
if (fn)
return this._name(fn);
return null;
},
+ _getStackExcludingInternal: function(stack) {
+ if (!stack)
+ stack = Error().stack.split("\n").slice(2);
+ else
+ stack = stack.split("\n");
+ // cut internal callers
+ let re = /TMP_console_.*/;
+ while (stack.length && stack[0].match(re))
+ stack.splice(0, 1);
+ return stack;
+ },
+
// Bug 744842 - don't include actual args in error.stack.toString()
// since Bug 744842 landed the stack string don't have (arg1, arg2....)
// so we can get the name from the start of the string until @
@@ -110,7 +138,7 @@ let log = {
_name: function(fn) {
let name = fn.substr(0, fn.indexOf(this._char))
- if (!name) {
+ if (fn && !name) {
// get file name and line number
let lastIndexOf = fn.lastIndexOf("/");
name = lastIndexOf > -1 ? fn.substr(lastIndexOf+1) : "?";
@@ -125,7 +153,6 @@ let log = {
},
callerName: function() {
-/// return this._getCallerNameByIndex(2);
try {
var name = this._nameFromComponentsStack(Components.stack.caller.caller);
} catch (ex) { }
@@ -133,20 +160,20 @@ let log = {
},
*/
- callerName: function() {
- return this._getCallerNameByIndex(2);
+ callerName: function TMP_console_callerName() {
+ return this.getCallerNameByIndex(1);
},
// return true if the caller name of the calling function is in the
// arguments list
- isCallerInList: function() {
+ isCallerInList: function TMP_console_isCallerInList() {
if (!arguments.length) {
this.assert("no arguments in Tabmix.isCallerInList");
return false;
}
try {
- let callerName = this._getCallerNameByIndex(2);
+ let callerName = this.getCallerNameByIndex(1);
if (!callerName)
return false;
if (typeof arguments[0] == "object")
@@ -170,7 +197,7 @@ options = {
offset; for internal use only true / false default false
}
*/
- obj: function(aObj, aMessage, aDisallowLog, level) {
+ obj: function TMP_console_obj(aObj, aMessage, aDisallowLog, level) {
var offset = typeof level == "string" ? " " : "";
aMessage = aMessage ? offset + aMessage + "\n" : "";
var objS = aObj ? offset + aObj.toString() : offset + "aObj is " + typeof(aObj);
@@ -198,11 +225,38 @@ options = {
if (aDisallowLog)
objS = aMessage + "======================\n" + objS;
else
- this.log(aMessage + "=============== Object Properties ===============\n" + objS, true, 1);
+ this.log(aMessage + "=============== Object Properties ===============\n" + objS, true);
return objS;
},
- assert: function TMP_utils_assert(aError, aMsg) {
+ // RegExp to remove path/to/profile/extensions from filename
+ get _pathRegExp() {
+ delete this._pathRegExp;
+ let folder = TabmixSvc.FileUtils.getDir("ProfD", ["extensions"]);
+ let path = folder.path.replace("\\", "/", "g") + "/";
+ return this._pathRegExp = new RegExp("jar:|file:///|" + path, "g");
+ },
+
+ _formatStack: function(stack) {
+ let lines = [], _char = this._char, re = this._pathRegExp;
+ stack.forEach(function(line) {
+ let atIndex = line.indexOf("@");
+ let columnIndex = line.lastIndexOf(":");
+ let fileName = line.slice(atIndex + 1, columnIndex).split(" -> ").pop();
+ if (fileName) {
+ fileName = decodeURI(fileName).replace(re, "");
+ let lineNumber = parseInt(line.slice(columnIndex + 1));
+ let atIndex = line.indexOf(_char);
+ let name = line.slice(0, atIndex).split("(").shift() || "null";
+ lines.push(' File "' + fileName + '", line ' +
+ lineNumber + ', in ' + name);
+ }
+ });
+
+ return lines.join("\n");
+ },
+
+ assert: function TMP_console_assert(aError, aMsg) {
if (typeof aError.stack != "string") {
this.trace((aMsg || "") + "\n" + aError, 2);
return;
@@ -212,14 +266,12 @@ options = {
let errAt = " at " + names[0];
let location = aError.location ? "\n" + aError.location : "";
let assertionText = "Tabmix Plus ERROR" + errAt + ":\n" + (aMsg ? aMsg + "\n" : "") + aError.message + location;
- let stackText = "\nStack Trace: \n" + decodeURI(aError.stack);
- TabmixSvc.console.logStringMessage(assertionText + stackText);
+ let stackText = "\nStack Trace: \n" + this._formatStack(aError.stack.split("\n"));
+ Services.console.logStringMessage(assertionText + stackText);
},
- trace: function(aMsg, slice) {
- // cut off the first line of the stack trace, because that's just this function.
- let stack = Error().stack.split("\n").slice(slice || 1);
-
- TabmixSvc.console.logStringMessage("Tabmix Trace: " + (aMsg || "") + '\n' + stack.join("\n"));
+ trace: function TMP_console_trace(aMsg) {
+ let stack = this._formatStack(this._getStackExcludingInternal());
+ Services.console.logStringMessage("Tabmix Trace: " + (aMsg || "") + '\n' + stack);
}
}
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-mozext/tabmixplus.git
More information about the Pkg-mozext-commits
mailing list