summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md9
-rw-r--r--bootstrap.js413
-rw-r--r--chrome.manifest2
-rw-r--r--content/skin/overlay-bold.css5
-rw-r--r--content/skin/overlay-small.css8
-rw-r--r--content/skin/overlay.css16
-rw-r--r--install.rdf19
-rwxr-xr-xmake_xpi.sh2
-rw-r--r--options.xul16
-rw-r--r--screenshots/1.pngbin0 -> 10562 bytes
-rw-r--r--screenshots/2.pngbin0 -> 8301 bytes
-rw-r--r--screenshots/3.pngbin0 -> 8478 bytes
-rw-r--r--tablocation.xpibin0 -> 6201 bytes
13 files changed, 490 insertions, 0 deletions
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..32aa8a4
--- /dev/null
+++ b/README.md
@@ -0,0 +1,9 @@
+# tablocation
+
+The firefox addon. Tested on Firefox 38 under Linux.
+
+See the screenshots.
+
+![](/screenshots/1.png?raw=true)
+![](/screenshots/2.png?raw=true)
+![](/screenshots/3.png?raw=true)
diff --git a/bootstrap.js b/bootstrap.js
new file mode 100644
index 0000000..86a8a96
--- /dev/null
+++ b/bootstrap.js
@@ -0,0 +1,413 @@
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+const Cu = Components.utils;
+
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import('resource://gre/modules/devtools/Console.jsm');
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+var consoleService = Cc["@mozilla.org/consoleservice;1"]
+ .getService(Ci.nsIConsoleService);
+var wm = Cc["@mozilla.org/appshell/window-mediator;1"]
+ .getService(Ci.nsIWindowMediator);
+var prefs = Cc["@mozilla.org/preferences-service;1"]
+ .getService(Ci.nsIPrefService)
+ .getBranch("extensions.tablocation.");
+var styleSheetService = Cc["@mozilla.org/content/style-sheet-service;1"]
+ .getService(Ci.nsIStyleSheetService);
+
+var styleSheets = {
+ common: ["chrome://tablocation/skin/overlay.css"],
+ smaller: ["chrome://tablocation/skin/overlay-small.css"],
+ bold: ["chrome://tablocation/skin/overlay-bold.css"]
+};
+
+var LocationPreference = 0;
+var SmallerPreference = false;
+var BoldPreference = false;
+
+var Controller = {
+ bindWindowEvents: function(chromeWindow) {
+ if (chromeWindow._tabLocationBind) {
+ LOG("chromeWindow._tabLocationBind == true");
+ return;
+ }
+
+ chromeWindow._tabLocationBind = true;
+ var gBrowser = chromeWindow.gBrowser;
+ gBrowser.addEventListener('load', Controller.windowLoadListener, true);
+ //gBrowser.addEventListener('readystatechange', Controller.windowLoadListener, true);
+ gBrowser.addEventListener('DOMTitleChanged', Controller.tabsTitleChangedListener, true);
+ gBrowser.addTabsProgressListener(Controller.tabsProgressListener);
+
+ var container = gBrowser.tabContainer;
+ container.addEventListener("TabOpen", Controller.tabOpenListener, false);
+ container.addEventListener("TabMove", Controller.tabMoveListener);
+ container.addEventListener("TabClose", Controller.tabCloseListener);
+ },
+ unbindWindowEvents: function(chromeWindow) {
+ var gBrowser = chromeWindow.gBrowser;
+ gBrowser.removeEventListener('load', Controller.windowLoadListener, true);
+ //gBrowser.removeEventListener('readystatechange', Controller.windowLoadListener, true);
+ gBrowser.removeEventListener('DOMTitleChanged', Controller.tabsTitleChangedListener, true);
+ gBrowser.removeTabsProgressListener(Controller.tabsProgressListener);
+
+ var container = gBrowser.tabContainer;
+ container.removeEventListener("TabOpen", Controller.tabOpenListener);
+ container.removeEventListener("TabMove", Controller.tabMoveListener);
+ container.removeEventListener("TabClose", Controller.tabCloseListener);
+
+ delete chromeWindow._tabLocationBind;
+ },
+
+ // Listeners
+ windowLoadListener: function(e) {
+ Controller.setupWindow(this.ownerGlobal);
+ },
+ tabOpenListener: function(e) {
+ var chromeWindow = e.target.ownerGlobal;
+ var browser = chromeWindow.gBrowser.getBrowserForTab(e.target);
+ var index = chromeWindow.gBrowser.getBrowserIndexForDocument(browser.contentDocument);
+ if (index != -1) {
+ Controller.setupTab(chromeWindow, index);
+ }
+ },
+ tabMoveListener: function(e) {
+ var chromeWindow = e.target.ownerGlobal;
+ var browser = chromeWindow.gBrowser.getBrowserForTab(e.target);
+ var index = chromeWindow.gBrowser.getBrowserIndexForDocument(browser.contentDocument);
+ if (index != -1) {
+ Controller.setupTab(chromeWindow, index, true);
+ }
+ },
+ tabCloseListener: function(e) {
+ var chromeWindow = e.target.ownerGlobal;
+ var browser = chromeWindow.gBrowser.getBrowserForTab(e.target);
+ var index = chromeWindow.gBrowser.getBrowserIndexForDocument(browser.contentDocument);
+ if (index != -1) {
+ //LOG("tabCloseListener: tearing tab down");
+ Controller.tearDownTab(chromeWindow, index, true);
+ }
+ },
+ tabsProgressListener: {
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener, Ci.nsISupportsWeakReference]),
+ onLocationChange: function(aBrowser, aProgress, aRequest, aURI) {
+ var chromeWindow = aBrowser.ownerGlobal;
+ var index = chromeWindow.gBrowser.getBrowserIndexForDocument(aBrowser.contentDocument);
+ if (index == -1) {
+ //LOG("Controller.tabsProgressListener()->onLocationChange(): index == -1");
+ return;
+ }
+ Controller.updateLocation(chromeWindow, index);
+ }
+ },
+ tabsTitleChangedListener: function(e) {
+ var chromeWindow = this.ownerGlobal;
+ var index = chromeWindow.gBrowser.getBrowserIndexForDocument(e.target);
+ var browser = chromeWindow.gBrowser.browsers[index];
+ if (index == -1 || !browser._tabLocationPatched || (e.target.title == '' && browser.contentDocument.documentURI == 'about:blank')) {
+ return;
+ }
+ Controller.updateTitle(chromeWindow, index);
+ },
+
+ // UI functions
+ setupWindow: function(chromeWindow) {
+ var tabsCount = chromeWindow.gBrowser.browsers.length;
+ for (var i = 0; i < tabsCount; i++) {
+ Controller.setupTab(chromeWindow, i);
+ }
+ },
+ setupTab: function(chromeWindow, tabIndex, force) {
+ var browser = chromeWindow.gBrowser.browsers[tabIndex];
+ if (browser._tabLocationPatched && !force) {
+ //LOG("ignore(already) setupTab "+tabIndex);
+ return true;
+ }
+
+ //if (browser.contentDocument.readyState == 'uninitialized') {
+ //LOG("ignore(notready) setupTab "+tabIndex+",readyState:"+browser.contentDocument.readyState);
+ // return false;
+ //}
+
+ //LOG("setupTab:"+tabIndex+",readyState:"+browser.contentDocument.readyState);
+ var ownerDocument = chromeWindow.gBrowser.ownerDocument;
+
+ // Current location and title
+ var loc = getLocation(browser.contentDocument.location), title = browser.contentDocument.title;
+
+ // Get some elements
+ var tab = chromeWindow.gBrowser.tabContainer.childNodes[tabIndex];
+ var label = ownerDocument.getAnonymousElementByAttribute(tab, 'anonid', 'tab-label');
+
+ // DOM manipulations
+ var vbox = createElement(ownerDocument, 'xul:vbox', { orient: 'vertical', flex: 1, anonid: 'tab-label-vbox' });
+ vbox.addEventListener('DOMAttrModified', function(e) {
+ if (e.target != vbox/* && e.target != vbox.firstChild*/) {
+ //LOG("e.target("+e.target.className+") != vbox [ "+e.attrName+" => "+e.newValue+" ]");
+ return;
+ }
+ label.setAttribute(e.attrName, e.newValue);
+ if (tabIndex == 1) {
+ LOG("DOMAttrModified set " + e.attrName + "=" + e.newValue);
+ }
+ });
+ var url = createElement(ownerDocument, 'label', {
+ 'class': 'tab-text tab-url-label',
+ 'xbl:inherits': 'value=visibleLabel,crop,accesskey,fadein,pinned,selected',
+ 'flex': '1',
+ 'anonid': 'tab-url-label',
+ 'role': 'presentation',
+ 'fadein': 'true',
+ 'selected': 'true',
+ 'crop': 'end'
+ });
+ url.setAttribute('value', loc);
+
+ label.parentNode.insertBefore(vbox, label);
+
+ vbox.appendChild(label);
+ vbox.appendChild(url);
+
+ browser._tabLocationPatched = true;
+
+ return true;
+ },
+ updateAllLocations: function() {
+ var windows = wm.getEnumerator("navigator:browser");
+ while (windows.hasMoreElements()) {
+ var chromeWindow = windows.getNext().QueryInterface(Ci.nsIDOMWindow);
+ var tabsCount = chromeWindow.gBrowser.browsers.length;
+ for (var i = 0; i < tabsCount; i++) {
+ Controller.updateLocation(chromeWindow, i);
+ }
+ }
+ },
+ updateLocation: function(chromeWindow, tabIndex) {
+ var ownerDocument = chromeWindow.gBrowser.ownerDocument;
+ var loc = getLocation(chromeWindow.gBrowser.browsers[tabIndex].contentDocument.location);
+ var tab = chromeWindow.gBrowser.tabContainer.childNodes[tabIndex];
+ var url = ownerDocument.getAnonymousElementByAttribute(tab, 'anonid', 'tab-url-label');
+ if (url) {
+ url.setAttribute('value', loc);
+ }
+ },
+ updateTitle: function(chromeWindow, tabIndex) {
+ var ownerDocument = chromeWindow.gBrowser.ownerDocument;
+ var title = chromeWindow.gBrowser.browsers[tabIndex].contentDocument.title;
+ var tab = chromeWindow.gBrowser.tabContainer.childNodes[tabIndex];
+ var label = ownerDocument.getAnonymousElementByAttribute(tab, 'anonid', 'tab-label');
+ if (label) {
+ label.setAttribute('value', title);
+ }
+ },
+ tearDownWindow: function(chromeWindow) {
+ var tabsCount = chromeWindow.gBrowser.browsers.length;
+ for (var i = 0; i < tabsCount; i++) {
+ Controller.tearDownTab(chromeWindow, i);
+ }
+ },
+ tearDownTab: function(chromeWindow, tabIndex) {
+ var browser = chromeWindow.gBrowser.browsers[tabIndex];
+ if (!browser._tabLocationPatched) {
+ //LOG("Controller.tearDownTab() not set up", chromeWindow, tabIndex);
+ return;
+ }
+ var ownerDocument = chromeWindow.gBrowser.ownerDocument;
+
+ var tab = chromeWindow.gBrowser.tabContainer.childNodes[tabIndex];
+ var vbox = ownerDocument.getAnonymousElementByAttribute(tab, 'anonid', 'tab-label-vbox');
+ //LOG("tearDownTab(): deleting vbox now", vbox);
+ vbox.parentNode.insertBefore(vbox.firstChild, vbox);
+ vbox.parentNode.removeChild(vbox);
+
+ delete browser._tabLocationPatched;
+ },
+
+ loadStyles: function(list) {
+ for (var i = 0, len = list.length; i < len; i++) {
+ var styleSheetURI = Services.io.newURI(list[i], null, null);
+ styleSheetService.loadAndRegisterSheet(styleSheetURI, styleSheetService.AUTHOR_SHEET);
+ }
+ },
+ unloadStyles: function(list) {
+ for (var i = 0, len = list.length; i < len; i++) {
+ var styleSheetURI = Services.io.newURI(list[i], null, null);
+ if (styleSheetService.sheetRegistered(styleSheetURI, styleSheetService.AUTHOR_SHEET)) {
+ styleSheetService.unregisterSheet(styleSheetURI, styleSheetService.AUTHOR_SHEET);
+ }
+ }
+ }
+};
+
+var PrefsObserver = {
+ observe: function(subject, topic, data) {
+ if (topic != "nsPref:changed") {
+ return;
+ }
+ switch (data) {
+ case "location":
+ this.updateLocationPreference();
+ break;
+ case "smaller":
+ this.updateSmallerPreference();
+ break;
+ case "bold":
+ this.updateBoldPreference();
+ break;
+ }
+ },
+ updateLocationPreference: function() {
+ var val = prefs.getIntPref("location");
+ if (val != 0 && val != 1) {
+ val = 0;
+ }
+ var prev = LocationPreference;
+ LocationPreference = val;
+ if (val != prev) {
+ Controller.updateAllLocations();
+ }
+ },
+ updateSmallerPreference: function() {
+ var val = prefs.getBoolPref("smaller");
+ var prev = SmallerPreference;
+ SmallerPreference = val;
+ if (val != prev) {
+ Controller[val ? 'loadStyles' : 'unloadStyles'](styleSheets.smaller);
+ }
+ },
+ updateBoldPreference: function() {
+ var val = prefs.getBoolPref("bold");
+ var prev = BoldPreference;
+ BoldPreference = val;
+ if (val != prev) {
+ Controller[val ? 'loadStyles' : 'unloadStyles'](styleSheets.bold);
+ }
+ }
+};
+
+var WindowListener = {
+ onOpenWindow: function(xulWindow) {
+ //LOG("WindowListener.onOpenWindow()");
+ var chromeWindow = xulWindow.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIDOMWindow);
+ chromeWindow.addEventListener("load", function listener() {
+ chromeWindow.removeEventListener("load", listener, false);
+ var domDocument = chromeWindow.document.documentElement;
+ var windowType = domDocument.getAttribute("windowtype");
+ if (windowType == "navigator:browser") {
+ Controller.bindWindowEvents(chromeWindow);
+ //Controller.setupWindow(chromeWindow);
+ }
+ }, false);
+ },
+ onCloseWindow: function(chromeWindow) {
+ // This is not necessary, window will be destroyed anyway..
+ Controller.tearDownWindow(chromeWindow);
+ Controller.unbindWindowEvents(chromeWindow);
+ },
+ onWindowTitleChange: function(chromeWindow, newTitle) {
+ //LOG("onWindowTitleChange()", chromeWindow, newTitle);
+ }
+};
+
+function startup(data, reason) {
+ try {
+ // Load stylesheets
+ Controller.loadStyles(styleSheets.common);
+
+ // Setup UI
+ wm.addListener(WindowListener);
+ if (reason != APP_STARTUP) {
+ var windows = wm.getEnumerator("navigator:browser");
+ while (windows.hasMoreElements()) {
+ var chromeWindow = windows.getNext().QueryInterface(Ci.nsIDOMWindow);
+ var readyState = chromeWindow.document.readyState;
+
+ Controller.bindWindowEvents(chromeWindow);
+ if (readyState == 'complete') {
+ Controller.setupWindow(chromeWindow);
+ }
+ }
+ }
+
+ // Register to receive notifications of preference changes
+ prefs.QueryInterface(Ci.nsIPrefBranch2);
+ prefs.addObserver("", PrefsObserver, false);
+
+ PrefsObserver.updateLocationPreference();
+ PrefsObserver.updateSmallerPreference();
+ PrefsObserver.updateBoldPreference();
+ } catch (e) {
+ LOG("startup() error:", e.message, e.stack);
+ }
+}
+function shutdown(data, reason) {
+ if (reason == APP_SHUTDOWN) {
+ return;
+ }
+
+ // Unload stylesheets
+ Controller.unloadStyles(styleSheets.common);
+ if (SmallerPreference) Controller.unloadStyles(styleSheets.smaller);
+ if (BoldPreference) Controller.unloadStyles(styleSheets.bold);
+
+ // UI
+ var windows = wm.getEnumerator("navigator:browser");
+ while (windows.hasMoreElements()) {
+ var chromeWindow = windows.getNext().QueryInterface(Ci.nsIDOMWindow);
+ Controller.tearDownWindow(chromeWindow);
+ Controller.unbindWindowEvents(chromeWindow);
+ }
+
+ // Remove prefs observer
+ prefs.removeObserver("", PrefsObserver);
+
+ if (reason == ADDON_DISABLE) {
+ Services.obs.notifyObservers(null, "startupcache-invalidate", null);
+ Services.obs.notifyObservers(null, "chrome-flush-caches", null);
+ }
+}
+function install(data, reason) {
+ try {
+ prefs.getIntPref('location');
+ } catch (e) {
+ prefs.setIntPref('location', 0);
+ prefs.setBoolPref('smaller', false);
+ prefs.setBoolPref('bold', false);
+ }
+}
+function uninstall(data, reason) {
+ prefs.deleteBranch("");
+}
+
+function LOG() {
+ var args = Array.prototype.slice.call(arguments);
+ args.unshift("tablocation:");
+ console.log.apply(console, args);
+}
+function createElement(doc, name, attr) {
+ var el = doc.createElement(name);
+ for (var k in attr) {
+ if (attr.hasOwnProperty(k)) {
+ el.setAttribute(k, attr[k]);
+ }
+ }
+ return el;
+}
+function getLocation(loc) {
+ switch (LocationPreference) {
+ case 0:
+ loc = loc.href;
+ break;
+
+ case 1:
+ if (loc.host) {
+ loc = loc.host;
+ } else {
+ loc = loc.href;
+ }
+ break;
+ }
+ return loc;
+}
diff --git a/chrome.manifest b/chrome.manifest
new file mode 100644
index 0000000..0c12a69
--- /dev/null
+++ b/chrome.manifest
@@ -0,0 +1,2 @@
+content tablocation content/
+skin tablocation classic/1.0 content/skin/
diff --git a/content/skin/overlay-bold.css b/content/skin/overlay-bold.css
new file mode 100644
index 0000000..dbed4da
--- /dev/null
+++ b/content/skin/overlay-bold.css
@@ -0,0 +1,5 @@
+@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
+.tab-label {
+ font-weight: bold;
+ color: #222;
+}
diff --git a/content/skin/overlay-small.css b/content/skin/overlay-small.css
new file mode 100644
index 0000000..7a485bd
--- /dev/null
+++ b/content/skin/overlay-small.css
@@ -0,0 +1,8 @@
+@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
+.tab-label {
+ margin-top: -1px !important;
+ font-size: 0.8em;
+}
+.tab-url-label {
+ margin-top: 1px !important;
+}
diff --git a/content/skin/overlay.css b/content/skin/overlay.css
new file mode 100644
index 0000000..8fc72f1
--- /dev/null
+++ b/content/skin/overlay.css
@@ -0,0 +1,16 @@
+@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
+.tab-label {
+ font-size: 0.9em;
+}
+.tab-url-label {
+ -moz-margin-end: 0px;
+ -moz-margin-start: 0px;
+ font-size: 0.7em;
+ color: #777;
+ margin-top: -1px !important;
+ overflow: hidden;
+}
+.tab-url-label:not([fadein]),
+.tabbrowser-tab[pinned] .tab-url-label {
+ display: none;
+}
diff --git a/install.rdf b/install.rdf
new file mode 100644
index 0000000..bf30c7f
--- /dev/null
+++ b/install.rdf
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+ <Description about="urn:mozilla:install-manifest">
+ <em:id>tablocation@ch1p.com</em:id>
+ <em:name>Tab Location</em:name>
+ <em:version>0.2.6</em:version>
+ <em:type>2</em:type>
+ <em:creator>ch1p</em:creator>
+ <em:bootstrap>true</em:bootstrap>
+ <em:targetApplication>
+ <Description>
+ <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
+ <em:minVersion>20</em:minVersion>
+ <em:maxVersion>99.*</em:maxVersion>
+ </Description>
+ </em:targetApplication>
+ </Description>
+</RDF>
diff --git a/make_xpi.sh b/make_xpi.sh
new file mode 100755
index 0000000..516f65f
--- /dev/null
+++ b/make_xpi.sh
@@ -0,0 +1,2 @@
+#!/bin/sh
+zip -r tablocation.xpi * -x make_xpi.sh
diff --git a/options.xul b/options.xul
new file mode 100644
index 0000000..953cefc
--- /dev/null
+++ b/options.xul
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>
+
+<!DOCTYPE mydialog SYSTEM "chrome://fxTabUrls/locale/mydialog.dtd">
+
+<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+<setting pref="extensions.tablocation.location" type="menulist" title="Display location as">
+ <menulist>
+ <menupopup>
+ <menuitem value="0" label="full URL" />
+ <menuitem value="1" label="host" />
+ </menupopup>
+ </menulist>
+</setting>
+<setting pref="extensions.tablocation.smaller" type="bool" title="Smaller tab title"/>
+<setting pref="extensions.tablocation.bold" type="bool" title="Bold tab title"/>
+</vbox>
diff --git a/screenshots/1.png b/screenshots/1.png
new file mode 100644
index 0000000..09fcb20
--- /dev/null
+++ b/screenshots/1.png
Binary files differ
diff --git a/screenshots/2.png b/screenshots/2.png
new file mode 100644
index 0000000..1c9ddb1
--- /dev/null
+++ b/screenshots/2.png
Binary files differ
diff --git a/screenshots/3.png b/screenshots/3.png
new file mode 100644
index 0000000..f16d700
--- /dev/null
+++ b/screenshots/3.png
Binary files differ
diff --git a/tablocation.xpi b/tablocation.xpi
new file mode 100644
index 0000000..dfb24d9
--- /dev/null
+++ b/tablocation.xpi
Binary files differ