diff --git a/.gitignore b/.gitignore index e18b35d..e51db70 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ build -release.xpi *~ +skin/.DS_Store diff --git a/Makefile b/Makefile index 8c10692..9bc3ac0 100644 --- a/Makefile +++ b/Makefile @@ -3,17 +3,15 @@ SOURCES = \ README.txt \ bootstrap.js \ chrome.manifest \ - groups.jsm \ install.rdf \ - multiselect.jsm \ options.xul \ override-bindings.css \ skin/base.css \ - skin/bindings.css \ - skin/groups.xml \ + skin/dark/dark.css \ + skin/light/light.css \ skin/linux/linux.css \ - skin/osx/closetab-white.png \ - skin/osx/closetab.png \ + skin/osx/closetab-white.svg \ + skin/osx/closetab.svg \ skin/osx/dropmarker.png \ skin/osx/osx.css \ skin/osx/twisty.png \ @@ -21,14 +19,13 @@ SOURCES = \ skin/win7/twisty-collapsed.png \ skin/win7/twisty.png \ skin/win7/win7.css \ - tabdatastore.jsm \ utils.js \ vertical-tabbrowser.xml \ verticaltabs.jsm \ $(NULL) -all: release.xpi +all: VerticalTabs.xpi -release.xpi: $(SOURCES) - rm -f $@ - zip -9r $@ $(SOURCES) +VerticalTabs.xpi: $(SOURCES) + rm -f ./$@ + zip -9r ./$@ $(SOURCES) diff --git a/README.txt b/README.txt index 77e2c39..8771c7c 100644 --- a/README.txt +++ b/README.txt @@ -1,4 +1,4 @@ -Vertical Tabs for Firefox 27 and beyond +Vertical Tabs for Firefox 29 and beyond ======================================= This Firefox add-on arranges tabs in a vertical rather than horizontal @@ -7,9 +7,6 @@ Tree Style Tab add-on. Goals: -* Ability to arrange tabs in groups (instead of arbitrary trees) plus - some group-related features (collapse group, tab previews, etc.) - * Very few other features and hopefully little or no preference settings. Instead a good JavaScript API might be provided for other extensions (e.g. JetPack SDK based) to provide additional features. @@ -19,4 +16,4 @@ Goals: * Readable and maintainable code, taking latest Mozilla practices into account. No eval() hacks. -License: Mozilla Public License Version 1.1 +License: Mozilla Public License Version 2.0 diff --git a/VerticalTabs.xpi b/VerticalTabs.xpi new file mode 100644 index 0000000..12211f0 Binary files /dev/null and b/VerticalTabs.xpi differ diff --git a/bootstrap.js b/bootstrap.js index 62a0622..9871e36 100644 --- a/bootstrap.js +++ b/bootstrap.js @@ -43,6 +43,10 @@ const PREF_BRANCH = "extensions.verticaltabs."; const DEFAULT_PREFS = { "extensions.verticaltabs.width": 250, "extensions.verticaltabs.right": false, + "extensions.verticaltabs.tabsOnTop": false, + "browser.tabs.drawInTitlebar": false, + "extensions.verticaltabs.theme": 'default', + "extensions.verticaltabs.fullscreen": true }; /** diff --git a/groups.jsm b/groups.jsm deleted file mode 100644 index b9edc1d..0000000 --- a/groups.jsm +++ /dev/null @@ -1,596 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Vertical Tabs. - * - * The Initial Developer of the Original Code is - * Philipp von Weitershausen. - * Portions created by the Initial Developer are Copyright (C) 2011 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -/** - * Functionality for grouping tabs. - * - * Groups are implemented as a special kind of tab (see binding in - * group.xml). There are a few advantages and disadvantages to this: - * - * - Groups can be regular children of tabbrowser.tabContainer - * (cf. https://bugzilla.mozilla.org/show_bug.cgi?id=475142). - * - * - The nsISessionStore service takes care of restoring groups and - * their properties. - * - * - But we have to make sure that groups don't behave like tabs at - * all. - */ - -const EXPORTED_SYMBOLS = ["VTGroups"]; -Components.utils.import("resource://verticaltabs/tabdatastore.jsm"); - -const TAB_DROP_TYPE = "application/x-moz-tabbrowser-tab"; - -function VTGroups(tabs) { - this.tabs = tabs; - this.init(); -} -VTGroups.prototype = { - - init: function() { - const tabs = this.tabs; - tabs.VTGroups = this; - - // Restore group and in-group status - tabs.addEventListener('SSTabRestoring', this, true); - - // Updating UI - tabs.addEventListener('TabSelect', this, false); - - // For clicks on the twisty - tabs.addEventListener('click', this, true); - - // For synchronizing group behaviour and tab positioning - tabs.addEventListener('dragover', this, false); - tabs.addEventListener('dragenter', this, false); - tabs.addEventListener('dragleave', this, false); - tabs.addEventListener('dragend', this, false); - tabs.addEventListener('drop', this, false); - tabs.addEventListener('TabMove', this, false); - tabs.addEventListener('TabClose', this, false); - }, - - unload: function() { - const tabs = this.tabs; - delete tabs.VTGroups; - - // Restore group and in-group status - tabs.removeEventListener('SSTabRestoring', this, true); - - // Updating UI - tabs.removeEventListener('TabSelect', this, false); - - // For clicks on the twisty - tabs.removeEventListener('click', this, true); - - // For synchronizing group behaviour and tab positioning - tabs.removeEventListener('dragover', this, false); - tabs.removeEventListener('dragenter', this, false); - tabs.removeEventListener('dragleave', this, false); - tabs.removeEventListener('dragend', this, false); - tabs.removeEventListener('drop', this, false); - tabs.removeEventListener('TabMove', this, false); - tabs.removeEventListener('TabClose', this, false); - }, - - kId: 'verticaltabs-id', - kGroup: 'verticaltabs-group', - kInGroup: 'verticaltabs-ingroup', - kLabel: 'verticaltabs-grouplabel', - kCollapsed: 'verticaltabs-collapsed', - kDropTarget: 'verticaltabs-droptarget', - kDropInGroup: 'verticaltabs-dropingroup', - kDropToNewGroup: 'verticaltabs-droptonewgroup', - kIgnoreMove: 'verticaltabs-ignoremove', - - - /*** Public API ***/ - - /* - * Create a new group tab. If given as an argument, the label is - * applied to the group. Otherwise the label will be made - * editable. - */ - addGroup: function(aLabel) { - let group = this.tabs.tabbrowser.addTab(); - VTTabDataStore.setTabValue(group, this.kGroup, "true"); - - let window = this.tabs.ownerDocument.defaultView; - function makeLabelEditable() { - // XBL bindings aren't applied synchronously. - if (typeof group.editLabel !== "function") { - window.setTimeout(makeLabelEditable, 10); - return; - } - group.editLabel(); - } - - if (aLabel) { - VTTabDataStore.setTabValue(group, this.kLabel, aLabel); - group.groupLabel = aLabel; - } else { - makeLabelEditable(); - } - - return group; - }, - - /* - * Return the child tabs of a given group. The return value is a - * JavaScript Array (not just a NodeList) and is "owned" by the - * caller (e.g. it may be modified). - */ - getChildren: function(aGroup) { - let groupId = this.tabs.VTTabIDs.id(aGroup); - let children = this.tabs.getElementsByAttribute(this.kInGroup, groupId); - // Return a copy - return Array.prototype.slice.call(children); - }, - - _updateCount: function(aGroup) { - let count = this.getChildren(aGroup).length; - - function update() { - if (!aGroup.mCounter) { - let window = aGroup.ownerDocument.defaultView; - window.setTimeout(update, 10); - return; - } - aGroup.mCounter.firstChild.nodeValue = "" + count; - } - update(); - }, - - /* - * Add a tab to a group. This won't physically move the tab - * anywhere, just create the logical connection. - */ - addChild: function(aGroup, aTab) { - // Only groups can have children - if (!this.isGroup(aGroup)) { - return; - } - // We don't allow nested groups - if (this.isGroup(aTab)) { - return; - } - - // Assign a group to the tab. If the tab was in another group - // before, this will simply overwrite the old value. - let groupId = this.tabs.VTTabIDs.id(aGroup); - VTTabDataStore.setTabValue(aTab, this.kInGroup, groupId); - this._updateCount(aGroup); - - // Apply the group's collapsed state to the tab - let collapsed = (VTTabDataStore.getTabValue(aGroup, this.kCollapsed) - == "true"); - this._tabCollapseExpand(aTab, collapsed); - }, - - addChildren: function(aGroup, aTabs) { - for each (let tab in aTabs) { - this.addChild(aGroup, tab); - } - }, - - /* - * Remove a tab from its group. - */ - removeChild: function(aTab) { - let groupId = VTTabDataStore.getTabValue(aTab, this.kInGroup); - if (!groupId) { - return; - } - - VTTabDataStore.deleteTabValue(aTab, this.kInGroup); - let group = this.tabs.VTTabIDs.get(groupId); - if (group) { - this._updateCount(group); - } - }, - - removeChildren: function(aTabs) { - for each (let tab in aTabs) { - this.removeChild(tab); - } - }, - - /* - * Creates a tab from the active selection. - */ - createGroupFromMultiSelect: function() { - let group = this.addGroup(); - let children = this.tabs.VTMultiSelect.getSelected(); - for each (let tab in children) { - // Moving the tabs to the right position is enough, the - // TabMove handler knows the right thing to do. - this.tabs.tabbrowser.moveTabTo(tab, group._tPos+1); - } - this.tabs.VTMultiSelect.clear(); - }, - - /* - * Return true if a given tab is a group tab. - */ - isGroup: function(aTab) { - return (VTTabDataStore.getTabValue(aTab, this.kGroup) == "true"); - }, - - /* - * Toggle collapsed/expanded state of a group tab. - */ - collapseExpand: function(aGroup) { - if (!this.isGroup(aGroup)) { - return; - } - let collapsed = (VTTabDataStore.getTabValue(aGroup, this.kCollapsed) - == "true"); - for each (let tab in this.getChildren(aGroup)) { - this._tabCollapseExpand(tab, !collapsed); - if (!collapsed && tab.selected) { - this.tabs.tabbrowser.selectedTab = aGroup; - } - } - VTTabDataStore.setTabValue(aGroup, this.kCollapsed, !collapsed); - }, - - - /*** Event handlers ***/ - - handleEvent: function(aEvent) { - switch (aEvent.type) { - case "SSTabRestoring": - this.onTabRestoring(aEvent.originalTarget); - return; - case "TabSelect": - this.onTabSelect(aEvent); - return; - case "TabMove": - this.onTabMove(aEvent); - return; - case "TabClose": - this.onTabClose(aEvent); - return; - case "click": - this.onClick(aEvent); - return; - case "dragover": - this.onDragOver(aEvent); - return; - case "dragenter": - this.onDragEnter(aEvent); - return; - case "dragleave": - this.onDragLeave(aEvent); - return; - case "dragend": - this._clearDropTargets(); - return; - case "drop": - this.onDrop(aEvent); - return; - } - }, - - onTabRestoring: function(aTab) { - // Restore tab attributes from session data (this isn't done - // automatically). kId is restored by VTTabIDs. - for each (let attr in [this.kGroup, - this.kInGroup, - this.kLabel, - this.kCollapsed]) { - let value = VTTabDataStore.getTabValue(aTab, attr); - if (value) { - aTab.setAttribute(attr, value); - } - } - - // Restore collapsed state if we belong to a group. - let groupId = VTTabDataStore.getTabValue(aTab, this.kInGroup); - if (!groupId) { - return; - } - - let self = this; - let window = this.tabs.ownerDocument.defaultView; - function restoreCollapsedState() { - // The group tab we belong to may not have been restored yet. - let group = self.tabs.VTTabIDs.get(groupId); - if (group === undefined) { - window.setTimeout(restoreCollapsedState, 10); - return; - } - self._updateCount(group); - let collapsed = (VTTabDataStore.getTabValue(group, self.kCollapsed) - == "true"); - self._tabCollapseExpand(aTab, collapsed); - } - restoreCollapsedState(); - }, - - _tabCollapseExpand: function(aTab, collapsed) { - if (collapsed) { - aTab.classList.add(this.kCollapsed); - } else { - aTab.classList.remove(this.kCollapsed); - } - }, - - onTabSelect: function(aEvent) { - let tab = aEvent.target; - let document = tab.ownerDocument; - let urlbar = document.getElementById("urlbar"); - - let isGroup = this.isGroup(tab); - if (isGroup) { - //TODO l10n - urlbar.placeholder = "Group: " + tab.groupLabel; - } else { - urlbar.placeholder = urlbar.getAttribute("bookmarkhistoryplaceholder"); - // Selecting a tab that's in a collapsed group will expand - // the group. - if (tab.classList.contains(this.kCollapsed)) { - let groupId = VTTabDataStore.getTabValue(tab, this.kInGroup); - if (groupId) { - let group = this.tabs.VTTabIDs.get(groupId); - this.collapseExpand(group); - } - } - } - urlbar.disabled = isGroup; - - //XXX this doesn't quite work: - let buttons = ["reload-button", "home-button", "urlbar", "searchbar"]; - for (let i=0; i < buttons.length; i++) { - let element = document.getElementById(buttons[i]); - element.disabled = isGroup; - } - }, - - onClick: function(aEvent) { - let tab = aEvent.target; - if (tab.localName != "tab") { - return; - } - if (aEvent.originalTarget !== tab.mTwisty) { - return; - } - this.collapseExpand(tab); - }, - - /* - * Remove style from all potential drop targets (usually there - * should only be one...). - */ - _clearDropTargets: function() { - let groups = this.tabs.getElementsByClassName(this.kDropTarget); - // Make a copy of the array before modifying its contents. - groups = Array.prototype.slice.call(groups); - for (let i=0; i < groups.length; i++) { - groups[i].classList.remove(this.kDropTarget); - } - }, - - onDragOver: function(aEvent) { - if (aEvent.target.localName != "tab") { - return; - } - // Potentially remove drop target style - //XXX is this inefficient? - this._clearDropTargets(); - - // Directly dropping on a group or the tab icon: - // Disable drop indicator, mark tab as drop target. - if (this.isGroup(aEvent.target) - || (aEvent.originalTarget.classList - && aEvent.originalTarget.classList.contains("tab-icon-image"))) { - aEvent.target.classList.add(this.kDropTarget); - this.tabs._tabDropIndicator.collapsed = true; - return; - } - - // Find out if the tab's new position would add it to a group. - // If so, mark the group as drop target and indent drop indicator. - let dropindex = this.tabs._getDropIndex(aEvent); - let tab = this.tabs.childNodes[dropindex]; - let groupId = VTTabDataStore.getTabValue(tab, this.kInGroup); - if (!groupId) { - this.tabs._tabDropIndicator.classList.remove(this.kDropInGroup); - return; - } - // Add drop style to the group and the indicator - let group = this.tabs.VTTabIDs.get(groupId); - group.classList.add(this.kDropTarget); - this.tabs._tabDropIndicator.classList.add(this.kDropInGroup); - }, - - onDragEnter: function(aEvent) { - if (aEvent.target.localName != "tab") { - return; - } - // Dragging a tab over a tab's icon changes the icon to the - // "create group" icon. - if (aEvent.originalTarget.classList - && aEvent.originalTarget.classList.contains("tab-icon-image")) { - aEvent.originalTarget.classList.add(this.kDropToNewGroup); - } - }, - - onDragLeave: function(aEvent) { - if (aEvent.target.localName != "tab") { - return; - } - // Change the tab's icon back from the "create group" to - // whatever it was before. - if (aEvent.originalTarget.classList - && aEvent.originalTarget.classList.contains("tab-icon-image")) { - aEvent.originalTarget.classList.remove(this.kDropToNewGroup); - } - }, - - onDrop: function(aEvent) { - this._clearDropTargets(); - let tab = aEvent.target; - - let dt = aEvent.dataTransfer; - let draggedTab = dt.mozGetDataAt(TAB_DROP_TYPE, 0); - if (!this.tabs._isAllowedForDataTransfer(draggedTab)) { - return; - } - - // Dropping a tab on another tab's icon will create a new - // group with those two tabs in it. - if (aEvent.originalTarget.classList - && aEvent.originalTarget.classList.contains("tab-icon-image")) { - let group = this.addGroup(); - this.tabs.tabbrowser.moveTabTo(tab, group._tPos+1); - this.tabs.tabbrowser.moveTabTo(draggedTab, group._tPos+1); - return; - } - - // Dropping on a group will append to that group's children. - if (this.isGroup(tab)) { - if (this.isGroup(draggedTab)) { - // If it's a group we're dropping, merge groups. - this.addChildren(tab, this.getChildren(draggedTab)); - this.tabs.tabbrowser.removeTab(draggedTab); - return; - } - // Dropping onto a collapsed group should select the group. - if (VTTabDataStore.getTabValue(tab, this.kCollapsed) == "true") { - this.tabs.tabbrowser.selectedTab = tab; - } - this.addChild(tab, draggedTab); - } - }, - - onTabMove: function(aEvent) { - let tab = aEvent.target; - if (tab.getAttribute(this.kIgnoreMove) == "true") { - tab.removeAttribute(this.kIgnoreMove); - return; - } - - if (this.isGroup(tab)) { - let newGroup = this._findGroupFromContext(tab); - - // Move group's children. - let children = this.getChildren(tab); - let offset = 0; - if (children.length && children[0]._tPos > tab._tPos) { - offset = 1; - } - for (let i = 0; i < children.length; i++) { - children[i].setAttribute(this.kIgnoreMove, "true"); - this.tabs.tabbrowser.moveTabTo(children[i], - tab._tPos + i + offset); - } - - // If we're being dragged into another group, merge groups. - if (newGroup) { - this.addChildren(newGroup, children); - this.tabs.tabbrowser.removeTab(tab); - } - return; - } - - let group = this._findGroupFromContext(tab); - if (!group) { - this.removeChild(tab); - } else { - this.addChild(group, tab); - } - }, - - - /* - * Determine whether a tab move should result in the tab being - * added to a group (or removed from one). - */ - _findGroupFromContext: function(tab) { - let group; - let nextPos = tab._tPos + 1; - if (nextPos < this.tabs.childNodes.length) { - // If the next tab down the line is in a group, then the - // tab is added to that group. - let next = this.tabs.childNodes[nextPos]; - let groupId = VTTabDataStore.getTabValue(next, this.kInGroup); - group = this.tabs.VTTabIDs.get(groupId); - } else { - // We're moved to the last position, so let's look at the - // previous tab. Is it a group or in a group? - nextPos = tab._tPos - 1; - let prev = this.tabs.childNodes[nextPos]; - if (this.isGroup(prev)) { - group = prev; - } else { - let groupId = VTTabDataStore.getTabValue(prev, this.kInGroup); - group = this.tabs.VTTabIDs.get(groupId); - } - } - return group; - }, - - onTabClose: function(aEvent) { - let tab = aEvent.target; - if (!this.isGroup(tab)) { - this.removeChild(tab); - return; - } - - // If a collapsed group is removed, close its children as - // well. Otherwise just remove their group pointer. - let collapsed = (VTTabDataStore.getTabValue(tab, this.kCollapsed) - == "true"); - let children = this.getChildren(tab); - - if (!collapsed) { - this.removeChildren(children); - return; - } - - let window = tab.ownerDocument.defaultView; - let tabbrowser = this.tabs.tabbrowser; - // Remove children async to avoid confusing tabbrowser.removeTab() - window.setTimeout(function() { - for each (let tab in children) { - tabbrowser.removeTab(tab); - } - }, 10); - } - -}; diff --git a/install.rdf b/install.rdf index 88e87de..ea072ac 100644 --- a/install.rdf +++ b/install.rdf @@ -1,22 +1,25 @@ - verticaltabs@bitops.com + verticaltabs-simplified@mozilla.com 2 true - Vertical Tabs - 29.0pre - https://www.bitops.com/vertical-tabs/ - Vladimir Vukicevic + Vertical Tabs (Simplified) + 0.1 + https://github.com/jdashg/VerticalTabs + Jeff Gilbert + Vlad Vukicevic + Darrin Henein Philipp von Weitershausen (original author) SHIMODA Hiroshi (creator of Tree Style Tab) bb10 (Linux and Windows theme contributions) Frank Yan (various theming fixes) + Rob Campbell (some UI love) {ec8030f7-c20a-464f-9b0e-13a3a9e97384} 29.0a1 - 29.0 + 42.0 diff --git a/multiselect.jsm b/multiselect.jsm deleted file mode 100644 index fdd72ac..0000000 --- a/multiselect.jsm +++ /dev/null @@ -1,217 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Vertical Tabs. - * - * The Initial Developer of the Original Code is - * Philipp von Weitershausen. - * Portions created by the Initial Developer are Copyright (C) 2011 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -/** - * Support for "selecting" multiple tabs. - * - * The idea is to this work for tabs exactly like it does for a - * regular list or tree widget: hold Ctrl/Cmd or Shift and click. - * To make it work in the UI, tabs with multiselect="true" need to be - * styled like selected tabs. - * - * Use getMultiSelect() to obtain a list of selected tabs. For most - * cases this will be the only API you ever need. - */ - -const EXPORTED_SYMBOLS = ["VTMultiSelect"]; - -function VTMultiSelect (tabs) { - this.tabs = tabs; - this.init(); -} -VTMultiSelect.prototype = { - - init: function() { - const tabs = this.tabs; - tabs.VTMultiSelect = this; - tabs.addEventListener("mousedown", this, true); - tabs.addEventListener("TabSelect", this, false); - }, - - unload: function() { - const tabs = this.tabs; - delete tabs.VTMultiSelect; - tabs.removeEventListener("mousedown", this, true); - tabs.removeEventListener("TabSelect", this, false); - }, - - /*** Public API ***/ - - toggleSelect: function(aTab) { - if (aTab.selected) { - // Toggling a selected tab means we have to find another - // tab within the multiselection that we can select instead. - let tab = this.findClosestSelectedTab(aTab); - if (tab) { - // Prevent the tab switch from clearing the multiselection. - tab.setAttribute("multiselect-noclear", "true"); - this.tabs.tabbrowser.selectedTab = tab; - } - return; - } - if (aTab.getAttribute("multiselect") == "true") { - aTab.removeAttribute("multiselect"); - } else { - aTab.setAttribute("multiselect", "true"); - } - }, - - findClosestSelectedTab: function(aTab) { - let selected = this.tabs.getElementsByAttribute("multiselect", "true"); - if (!selected.length) { - return null; - } - return Array.sort(selected, function (a, b) { - return Math.abs(a._tPos - aTab._tPos) - - Math.abs(b._tPos - aTab._tPos); - })[0]; - }, - - spanSelect: function(aBeginTab, aEndTab) { - this.clear(); - let begin = aBeginTab._tPos; - let end = aEndTab._tPos; - if (begin > end) { - [end, begin] = [begin, end]; - } - for (let i=begin; i <= end; i++) { - this.tabs.childNodes[i].setAttribute("multiselect", "true"); - } - }, - - clear: function() { - for (let i=0; i < this.tabs.childNodes.length; i++) { - this.tabs.childNodes[i].removeAttribute("multiselect"); - } - }, - - /* - * Return a list of selected tabs. - */ - getSelected: function() { - let results = []; - for (let i=0; i < this.tabs.childNodes.length; i++) { - let tab = this.tabs.childNodes[i]; - if (tab.selected || (tab.getAttribute("multiselect") == "true")) { - results.push(tab); - } - } - return results; - }, - - /* - * Close all tabs in the multiselection. - */ - closeSelected: function() { - let toclose = this.getSelected(); - this.clear(); - - let tab; - for (let i=0; i < toclose.length; i++) { - tab = toclose[i]; - this.tabs.tabbrowser.removeTab(tab); - } - }, - - /*** Event handlers ***/ - - handleEvent: function(aEvent) { - switch (aEvent.type) { - case "mousedown": - this.onMouseDown(aEvent); - return; - case "TabSelect": - this.onTabSelect(aEvent); - return; - } - }, - - onMouseDown: function(aEvent) { - let tab = aEvent.target; - if (tab.localName != "tab") { - return; - } - if (aEvent.button != 0) { - return; - } - - // Check for Ctrl+click (multiselection). On the Mac it's - // Cmd+click which is represented by metaKey. Ctrl+click won't be - // possible on the Mac because that would be a right click (button 2) - if (aEvent.ctrlKey || aEvent.metaKey) { - this.toggleSelect(tab); - aEvent.stopPropagation(); - return; - } - if (aEvent.shiftKey) { - this.spanSelect(this.tabs.tabbrowser.selectedTab, tab); - aEvent.stopPropagation(); - return; - } - - if (!tab.selected) { - return; - } - if (!tab.mOverCloseButton) { - // Clicking on the already selected tab won't fire a TabSelect - // event, but we still want to deselect any other tabs. - this.clear(); - return; - } - - // Ok, so we're closing the selected tab. That means we have - // to find another tab within the multiselection that we can - // select instead. - let newtab = this.findClosestSelectedTab(tab); - if (!newtab) { - return; - } - // Prevent the tab switch from clearing the multiselection. - newtab.setAttribute("multiselect-noclear", "true"); - this.tabs.tabbrowser.selectedTab = newtab; - }, - - onTabSelect: function(aEvent) { - let tab = aEvent.target; - if (tab.getAttribute("multiselect-noclear") == "true") { - tab.removeAttribute("multiselect"); - tab.removeAttribute("multiselect-noclear"); - return; - } - this.clear(); - } - -}; diff --git a/options.xul b/options.xul index 2d99dc6..eb27b3c 100644 --- a/options.xul +++ b/options.xul @@ -3,4 +3,18 @@ + + + + + + + + + + diff --git a/skin/base.css b/skin/base.css index 3695042..21cd13b 100644 --- a/skin/base.css +++ b/skin/base.css @@ -42,8 +42,8 @@ statuspanel:-moz-locale-dir(ltr):not([mirror]) .statuspanel-inner { } /* Undo a bunch of stuff for app tabs */ -.tabbrowser-tab[pinned] { - position: inherit; +.tabbrowser-tabs[positionpinnedtabs] > .tabbrowser-tab[pinned] { + position: inherit !important; } .tabbrowser-tab[pinned] > .tab-text { display: inherit; @@ -87,6 +87,12 @@ statuspanel:-moz-locale-dir(ltr):not([mirror]) .statuspanel-inner { -moz-padding-start: 0px ! important; } +/* get rid of the tab separator from horizontal tabs */ +.tabbrowser-tab:after, +.tabbrowser-tab:before { + content: none !important; +} + /* Make room for the close/max/min button on the right of the window */ /* XXX this should probably be per-OS, yes? */ /* XXX if I was smarter I'd find a way to make a swoop on the right side of the bar, under the window buttons */ diff --git a/skin/bindings.css b/skin/bindings.css deleted file mode 100644 index 7d4c3d2..0000000 --- a/skin/bindings.css +++ /dev/null @@ -1,3 +0,0 @@ -.tabbrowser-tab[verticaltabs-group] { - -moz-binding: url("resource://verticaltabs/skin/groups.xml"); -} diff --git a/skin/dark/dark.css b/skin/dark/dark.css new file mode 100644 index 0000000..3244726 --- /dev/null +++ b/skin/dark/dark.css @@ -0,0 +1,173 @@ +@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); + +.tab-close-button { + position: absolute; + right: 4px; +} + + +.tabbrowser-tabs { + margin: 0 0 0 0 !important; + padding: 0 !important; + background: transparent !important; + background-color: #424F5A !important; +} + +.tabbrowser-tab { + -moz-box-pack: start; + -moz-box-flex: 0; + -moz-appearance: none !important; + background: transparent !important; + border: 0 !important; + border-radius: 0 !important; + margin: 0 !important; + padding: 1px 0 !important; + height: 28px !important; + min-height: 28px !important; + max-height: 28px !important; + color: #fbfbfb !important; + border-left: 4px solid transparent !important; +} + +.tabbrowser-tab[selected="true"] { + margin: 0 !important; + padding: 1px 0 !important; + background-color: #343F48 !important; + font-weight: normal; + text-shadow: none; + border-left: 4px solid #ff9500 !important; + border-radius: 0 !important; + font-weight: 600 !important; +} +.tabbrowser-tab[selected="true"]:-moz-window-inactive { + background-color: InactiveCaption !important; + color: InactiveCaptionText !important; + /* gnome/gtk/cleartype doesn't seem to have inactive states for selected items, lets try this */ +} + +.tabbrowser-tab:not([selected="true"]):hover { + margin: 0 !important; + padding: 1px 0 !important; + background-color: #5E6972 !important; +} + + +.tabbrowser-tab:not(:hover):not([selected="true"]) .tab-close-button { + visibility: collapse !important; +} + +/* Keep the close button at a safe distance from the tab label. */ +.tab-close-button { + display: -moz-box; + margin-left: 3px !important; + margin-right: 1px !important; +} + +.tab-label { + text-align: left !important; +} + +.tab-label[pinned] { + margin-left: 6px !important; + position: relative !important; +} + +.tab-content { + -moz-margin-start: 0px; + margin-top: 1px; +} + +.tab-icon-image { + padding: 3px; + background-color: #f2f2f2 !important; + border-radius: 2px; + min-height: 22px !important; + min-width: 22px !important; + opacity: 1 !important; +} + +/** Drop indicator for drag'n'drop of tabs - Works OOTB(TM)- Just needs a margin.**/ +.tab-drop-indicator { + margin-top: -11px !important; + margin-bottom: 0 !important; +} + +#TabsToolbar:not(:-moz-lwtheme) { + height: 24px; + border-bottom-left-radius: 0px !important; + box-shadow: none !important; + -moz-appearance: none !important; + border-top: 1px solid rgb(160,160,160) !important; + -moz-border-right-colors: #fcfcfc rgb(154,154,154) !important; + background-color: #f1f1f1 !important; + background-image: none !important; +} + +.verticaltabs-textbox { + margin: 0; +} + +.verticaltabs-counter { + visibility: collapse; +} + +.verticaltabs-droptarget { + background-color: Highlight !important; + color: HighlightText !important; +} + +.verticaltabs-twisty { + cursor: default !important; + margin-left: 1px !important; + margin-right: 2px !important; + -moz-appearance: treetwisty !important; +} +.tabbrowser-tab[verticaltabs-collapsed="true"] .verticaltabs-twisty { + -moz-appearance: treetwistyopen !important; +} + +/*** Link Display ***/ + +.statuspanel-label { + -moz-appearance: tooltip !important; + margin-right: 0px !important; + margin-left: 0px !important; + box-shadow: 8px 3px 0 rgba(0,0,0,.18) !important; /* would otherwise display a transparent pixel on the tooltip's corner */ +} + +.statuspanel-inner { + height: 100% !important; +} + +#main-window[sizemode="normal"]:not([inFullscreen="true"]) .statuspanel-inner { + padding-left: 0px !important; + padding-right: 0px !important; +} + +statuspanel[mirror]:-moz-locale-dir(ltr), +statuspanel[mirror]:-moz-locale-dir(rtl) { + padding: 6px 6px 0px 0px !important; +} + +statuspanel:-moz-locale-dir(ltr):not([mirror]), +statuspanel:-moz-locale-dir(rtl):not([mirror]) { + padding: 0px 0px 0px 4px !important; +} + +statuspanel[mirror]:-moz-locale-dir(ltr) .statuspanel-inner, +statuspanel[mirror]:-moz-locale-dir(rtl) .statuspanel-inner { + margin-top: 8px !important; + margin-bottom: 10px !important; + box-shadow: 5px 5px 0 -4px rgba(0,0,0,.18), 5px 5px 0 -3px rgba(0,0,0,.15), 5px 5px 0 -2px rgba(0,0,0,.12), 5px 5px 0 -1px rgba(0,0,0,.09) !important; + padding: 0px 0px !important; + border-radius: 4px !important; +} + +statuspanel:-moz-locale-dir(ltr):not([mirror]) .statuspanel-inner, +statuspanel:-moz-locale-dir(rtl):not([mirror]) .statuspanel-inner { + margin-top: 14px !important; + margin-bottom: 5px !important; + box-shadow: 5px 5px 0 -4px rgba(0,0,0,.18), 5px 5px 0 -3px rgba(0,0,0,.15), 5px 5px 0 -2px rgba(0,0,0,.12), 5px 5px 0 -1px rgba(0,0,0,.09) !important; + padding: 0px 0px !important; + border-radius: 4px !important; +} diff --git a/skin/groups.xml b/skin/groups.xml deleted file mode 100644 index e6da0e6..0000000 --- a/skin/groups.xml +++ /dev/null @@ -1,137 +0,0 @@ - - - -%tabBrowserDTD; -]> - - - - - - - - - - - &newGroup.label; - - - - 0 - - - - - - document.getAnonymousElementByAttribute(this, "class", "verticaltabs-twisty"); - - - document.getAnonymousElementByAttribute(this, "class", "tab-text"); - - - document.getAnonymousElementByAttribute(this, "class", "verticaltabs-textbox"); - - - document.getAnonymousElementByAttribute(this, "class", "verticaltabs-counter"); - - - - - - - return this.mLabel.firstChild.nodeValue; - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/skin/light/light.css b/skin/light/light.css new file mode 100644 index 0000000..dbde129 --- /dev/null +++ b/skin/light/light.css @@ -0,0 +1,179 @@ +@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); + +.tab-close-button { + position: absolute; + right: 4px; +} + + +.tabbrowser-tabs { + margin: 0 0 0 0 !important; + padding: 0 !important; + background: transparent !important; + background-color: #FBFBFB !important; +} + +.tabbrowser-tab { + -moz-box-pack: start; + -moz-box-flex: 0; + -moz-appearance: none !important; + background: transparent !important; + border: 0 !important; + border-radius: 0 !important; + margin: 0 !important; + padding: 1px 0 !important; + height: 28px !important; + min-height: 28px !important; + max-height: 28px !important; + color: #333333 !important; + border-left: 4px solid transparent !important; +} + +.tabbrowser-tab[selected="true"] { + margin: 0 !important; + padding: 1px 0 !important; + background-color: #dadada !important; + font-weight: normal; + text-shadow: none; + border-left: 4px solid #ff9500 !important; + border-radius: 0 !important; + font-weight: 600 !important; +} +.tabbrowser-tab[selected="true"]:-moz-window-inactive { + background-color: InactiveCaption !important; + color: InactiveCaptionText !important; + /* gnome/gtk/cleartype doesn't seem to have inactive states for selected items, lets try this */ +} + +.tabbrowser-tab:not([selected="true"]):hover { + margin: 0 !important; + padding: 1px 0 !important; + background-color: #ebebeb !important; +} + + +.tabbrowser-tab:not(:hover):not([selected="true"]) .tab-close-button { + visibility: collapse !important; +} + +/* Keep the close button at a safe distance from the tab label. */ +.tab-close-button { + display: -moz-box; + margin-left: 3px !important; + margin-right: 1px !important; +} + +.tab-label { + text-align: left !important; +} + +.tab-label[pinned] { + margin-left: 6px !important; + position: relative !important; +} + +.tab-content { + -moz-margin-start: 0px; + margin-top: 1px; +} + +.tab-icon-image { + padding: 3px; + background-color: transparent !important; + border-radius: 2px; + min-height: 22px !important; + min-width: 22px !important; + opacity: 1 !important; +} + +/** Drop indicator for drag'n'drop of tabs - Works OOTB(TM)- Just needs a margin.**/ +.tab-drop-indicator { + margin-top: -11px !important; + margin-bottom: 0 !important; +} + +#TabsToolbar:not(:-moz-lwtheme) { + height: 24px; + /*margin: 0 -3px -1px 0px !important;*/ + border-bottom-left-radius: 0px !important; + box-shadow: none !important; + -moz-appearance: none !important; + border-top: 1px solid rgb(160,160,160) !important; + /*border-right: 2px solid !important;*/ + -moz-border-right-colors: #fcfcfc rgb(154,154,154) !important; + background-color: #f1f1f1 !important; + background-image: none !important; + /*border-right: 3px solid #a0a0a0 !important; /* 3px to get 1px border :( */*/ +} + + +/* Tab toolbar styling */ + +.verticaltabs-textbox { + margin: 0; +} + +.verticaltabs-counter { + visibility: collapse; +} + +.verticaltabs-droptarget { + background-color: Highlight !important; + color: HighlightText !important; +} + +.verticaltabs-twisty { + cursor: default !important; + margin-left: 1px !important; + margin-right: 2px !important; + -moz-appearance: treetwisty !important; +} +.tabbrowser-tab[verticaltabs-collapsed="true"] .verticaltabs-twisty { + -moz-appearance: treetwistyopen !important; +} + +/*** Link Display ***/ + +.statuspanel-label { + -moz-appearance: tooltip !important; + margin-right: 0px !important; + margin-left: 0px !important; + box-shadow: 8px 3px 0 rgba(0,0,0,.18) !important; /* would otherwise display a transparent pixel on the tooltip's corner */ +} + +.statuspanel-inner { + height: 100% !important; +} + +#main-window[sizemode="normal"]:not([inFullscreen="true"]) .statuspanel-inner { + padding-left: 0px !important; + padding-right: 0px !important; +} + +statuspanel[mirror]:-moz-locale-dir(ltr), +statuspanel[mirror]:-moz-locale-dir(rtl) { + padding: 6px 6px 0px 0px !important; +} + +statuspanel:-moz-locale-dir(ltr):not([mirror]), +statuspanel:-moz-locale-dir(rtl):not([mirror]) { + padding: 0px 0px 0px 4px !important; +} + +statuspanel[mirror]:-moz-locale-dir(ltr) .statuspanel-inner, +statuspanel[mirror]:-moz-locale-dir(rtl) .statuspanel-inner { + margin-top: 8px !important; + margin-bottom: 10px !important; + box-shadow: 5px 5px 0 -4px rgba(0,0,0,.18), 5px 5px 0 -3px rgba(0,0,0,.15), 5px 5px 0 -2px rgba(0,0,0,.12), 5px 5px 0 -1px rgba(0,0,0,.09) !important; + padding: 0px 0px !important; + border-radius: 4px !important; +} + +statuspanel:-moz-locale-dir(ltr):not([mirror]) .statuspanel-inner, +statuspanel:-moz-locale-dir(rtl):not([mirror]) .statuspanel-inner { + margin-top: 14px !important; + margin-bottom: 5px !important; + box-shadow: 5px 5px 0 -4px rgba(0,0,0,.18), 5px 5px 0 -3px rgba(0,0,0,.15), 5px 5px 0 -2px rgba(0,0,0,.12), 5px 5px 0 -1px rgba(0,0,0,.09) !important; + padding: 0px 0px !important; + border-radius: 4px !important; +} diff --git a/skin/linux/linux.css b/skin/linux/linux.css index 455bb28..02a34e7 100644 --- a/skin/linux/linux.css +++ b/skin/linux/linux.css @@ -23,8 +23,7 @@ max-height: 24px !important; } -.tabbrowser-tab[selected="true"], -.tabbrowser-tab[multiselect="true"] { +.tabbrowser-tab[selected="true"] { margin: 0 !important; padding: 1px 0 !important; @@ -34,8 +33,7 @@ font-weight: normal; text-shadow: none; } -.tabbrowser-tab[selected="true"]:-moz-window-inactive, -.tabbrowser-tab[multiselect="true"]:-moz-window-inactive { +.tabbrowser-tab[selected="true"]:-moz-window-inactive { background-color: InactiveCaption !important; color: InactiveCaptionText !important; /* gnome/gtk/cleartype doesn't seem to have inactive states for selected items, lets try this */ @@ -66,34 +64,6 @@ margin-bottom: 0 !important; } - -/* Tab toolbar styling */ - -#verticaltabs-groupbutton { - /* TODO need icon to symbolize tab group */ - list-style-image: url("chrome://browser/skin/Toolbar.png"); - -moz-image-region: rect(0, 234px, 18px, 216px); -} - - -/*** Group related styles ***/ - -.tabbrowser-tab[verticaltabs-ingroup], -.tabbrowser-tab[verticaltabs-ingroup]:hover { - padding-left: 16px !important; -} - -.tabbrowser-tab[verticaltabs-group] { -} - -.tabbrowser-tab[verticaltabs-group] .tab-close-button { - opacity: 1 !important; -} - -.tabbrowser-tab[verticaltabs-group] .tab-text { - padding-left: 3px !important; -} - .verticaltabs-textbox { margin: 0; } @@ -107,16 +77,6 @@ color: HighlightText !important; } -.verticaltabs-dropingroup { - margin-left: 10px !important; -} - -.verticaltabs-droptonewgroup { - /* TODO need icon to symbolize tab group */ - list-style-image: url("chrome://browser/skin/Toolbar.png"); - -moz-image-region: rect(0, 234px, 18px, 216px); -} - .verticaltabs-twisty { cursor: default !important; margin-left: 1px !important; diff --git a/skin/osx/closetab-white.png b/skin/osx/closetab-white.png deleted file mode 100644 index 01a7fca..0000000 Binary files a/skin/osx/closetab-white.png and /dev/null differ diff --git a/skin/osx/closetab-white.svg b/skin/osx/closetab-white.svg new file mode 100644 index 0000000..b288d2e --- /dev/null +++ b/skin/osx/closetab-white.svg @@ -0,0 +1,18 @@ + + + + + + + + + + diff --git a/skin/osx/closetab.png b/skin/osx/closetab.png deleted file mode 100644 index 5dac597..0000000 Binary files a/skin/osx/closetab.png and /dev/null differ diff --git a/skin/osx/closetab.svg b/skin/osx/closetab.svg new file mode 100644 index 0000000..aefae9c --- /dev/null +++ b/skin/osx/closetab.svg @@ -0,0 +1,18 @@ + + + + + + + + + + diff --git a/skin/osx/osx.css b/skin/osx/osx.css index 7917c9b..2d7eb0d 100644 --- a/skin/osx/osx.css +++ b/skin/osx/osx.css @@ -1,33 +1,25 @@ @namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); #nav-bar { - margin-left: 60px; - margin-right: 22px; - margin-top: -22px; - background-image: none !important; - background-color: transparent !important; + box-shadow: none; } -#tab-view-deck { - height: 44px !important; +#nav-bar:-moz-window-inactive { + box-shadow: none; } -/* -#navigator-toolbox { - background-color: red !important; +#tab-view-deck { + height: 44px !important; } -*/ -/* Background colour for the tree sidebar (light blue when window is - active, grey otherwise) */ .tabbrowser-tabs { margin: 0 !important; padding: 0 !important; background: transparent !important; - background-color: #d4dde5 !important; + background-color: #333 !important; } .tabbrowser-tabs:-moz-window-inactive { - background-color: #e8e8e8 !important; + background-color: #333 !important; } .tabbrowser-arrowscrollbox > .arrowscrollbox-scrollbox { @@ -37,13 +29,18 @@ /* Use the splitter to display the border of .tabbrowser-tabs */ #verticaltabs-splitter { - width: 1px !important; - min-width: 1px !important; - background-image: none; - background-color: #404040; + -moz-appearance: none; + background-image: none; + background-color: none; + border: 0; + min-width: 3px; + width: 3px; + -moz-margin-start: -3px; + position: relative; + -moz-border-end: #404040; } #verticaltabs-splitter:-moz-window-inactive { - background-color: #868686; + background-color: transparent; } /* Style tabs themselves. Get rid of most of the initial XUL styling */ @@ -51,7 +48,7 @@ -moz-box-pack: start; -moz-box-flex: 0; -moz-appearance: none !important; - background: transparent !important; + background: #333 !important; -moz-border-top-colors: none !important; -moz-border-bottom-colors: none !important; -moz-border-right-colors: none !important; @@ -59,25 +56,54 @@ -moz-border-radius: 0 !important; -moz-box-align: stretch !important; margin: 0 !important; - padding: 2px 3px 2px 10px !important; - height: 21px !important; /* height including border! */ - min-height: 21px !important; - max-height: 21px !important; + padding: 7px 3px 6px !important; + height: 31px !important; /* height including border! */ + min-height: 31px !important; + max-height: 31px !important; + width: 100% !important; + min-width: 100% !important; + max-width: 100% !important; text-align: left !important; border: none; - border-top: 1px solid transparent !important; - overflow: hidden; /* so that the heigh transition for collapsed works */ + border-top: 1px solid rgba(255, 255, 255,0.05) !important; + border-bottom: 1px solid rgba(0,0,0,0.15) !important; +} + +/* remove curvy tab ends */ +.tab-background-middle, +.tab-background-start, +.tab-background-end { + background-image: none !important; +} + +.tab-background-start[selected=true]::after, +.tab-background-start[selected=true]::before, +.tab-background-start, +.tab-background-end, +.tab-background-end[selected=true]::after, +.tab-background-end[selected=true]::before { + display: none; +} + +/* remove curvy tab ends from hovered background tabs */ +.tabbrowser-tab:hover > .tab-stack > .tab-background:not([selected=true]), +.tabs-newtab-button:hover { + background-image: none !important; +} + +/* remove background tab separators */ +#tabbrowser-tabs[movingtab] > .tabbrowser-tab[beforeselected]:not([last-visible-tab])::after, +.tabbrowser-tab:not([selected]):not([afterselected-visible]):not([afterhovered]):not([first-visible-tab]):not(:hover)::before, +#tabbrowser-tabs:not([overflow]) > .tabbrowser-tab[last-visible-tab]:not([selected]):not([beforehovered]):not(:hover)::after { + background-image: none !important; } -.tabbrowser-tab[selected="true"], -.tabbrowser-tab[multiselect="true"] { - border-top: 1px solid #94A1C0 !important; - background: -moz-linear-gradient(top, #A0B0CF, #7386AB) repeat-x !important; +.tabbrowser-tab[selected="true"] { + background: #222 !important; + } -.tabbrowser-tab[selected="true"]:-moz-window-inactive, -.tabbrowser-tab[multiselect="true"]:-moz-window-inactive { - border-top: 1px solid #979797 !important; - background: -moz-linear-gradient(top, #B4B4B4, #8A8A8A) repeat-x !important; +.tabbrowser-tab[selected="true"]:-moz-window-inactive { + background: #222 !important; } .tab-background-start, .tab-background-middle, .tab-background-end { @@ -95,15 +121,25 @@ -moz-image-region: auto !important; display: -moz-box; margin-left: 3px; - list-style-image: url("resource://verticaltabs/skin/osx/closetab.png"); + margin-top: 1px; + background-image: url("resource://verticaltabs/skin/osx/closetab.svg") !important; + background-position: center right; + background-size: contain; + background-repeat: no-repeat; + list-style-image: none !important; + width: 14px; + height: 14px; opacity: 0.27; /* turn black into #b9b9b9 */ } .tab-close-button:active { opacity: 0.46; /* turn black into #8a8a8a */ } -.tabbrowser-tab[selected="true"] .tab-close-button, -.tabbrowser-tab[multiselect="true"] .tab-close-button { - list-style-image: url("resource://verticaltabs/skin/osx/closetab-white.png"); +.tabbrowser-tab[selected="true"] .tab-close-button { + background-image: url("resource://verticaltabs/skin/osx/closetab-white.svg"); + opacity: 0.8; +} + +.tabbrowser-tab[selected="true"] .tab-close-button:hover { opacity: 1; } @@ -119,6 +155,29 @@ /* Ensure app tab labels are not too close to the icon. */ .tab-label[pinned] { margin: 2px 6px !important; + position: relative !important; +} + +.tabbrowser-tab[pinned]:before { + position: relative !important; +} + +.tabbrowser-tab[pinned][titlechanged] > .tab-stack > .tab-content { + background-image: none !important; +} + +.tabbrowser-tab[pinned][titlechanged] .tab-text { + color: #F1F1F1 !important; +} + +.tabbrowser-tab[pinned][titlechanged]:after { + content: '●' !important; + width: 18px; + height: 10px; + position: absolute !important; + color: #29B4FF; + line-height: 15px; + font-size: 150% !important; } /* Tab label is without special decoration except when selected: then @@ -126,14 +185,14 @@ .tab-text { font-size: 11px; font-weight: normal !important; - color: #000000 !important; + color: #BBB !important; text-shadow: none !important; margin-bottom: 1px; + text-align: left !important; } -.tabbrowser-tab[selected="true"] .tab-text, -.tabbrowser-tab[multiselect="true"] .tab-text { +.tabbrowser-tab[selected="true"] .tab-text { font-weight: bold !important; - color: #ffffff !important; + color: #DDD !important; text-shadow: 0 1px #404040 !important; } @@ -150,17 +209,10 @@ #TabsToolbar[tabsontop="false"]:not(:-moz-lwtheme), #TabsToolbar[tabsontop="false"]:not(:-moz-lwtheme):-moz-window-inactive { background: none; - background-color: transparent; -} - -#verticaltabs-groupbutton { - /* TODO need icon to symbolize tab group */ - list-style-image: url("chrome://browser/skin/Toolbar.png"); - -moz-image-region: rect(0, 280px, 20px, 260px); + background-color: #4C9ED9; } - /* Personas */ .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-start:-moz-lwtheme-brighttext:not([selected="true"]), @@ -172,32 +224,6 @@ background-image: none !important; } - -/*** Group related styles ***/ - -.tabbrowser-tab[verticaltabs-ingroup] { - padding-left: 20px !important; -} - -.tabbrowser-tab[verticaltabs-group] { - padding-top: 1px !important; -} - -.tabbrowser-tab[verticaltabs-group] .tab-close-button { - opacity: 1 !important; -} - -.tabbrowser-tab[verticaltabs-group] .tab-text { - color: #738192 !important; - font-weight: bold !important; - text-transform: uppercase !important; - text-shadow: 0 1px #ffffff !important; -} -.tabbrowser-tab[selected="true"][verticaltabs-group] .tab-text { - color: #ffffff !important; - text-shadow: 0 1px #404040 !important; -} - .verticaltabs-textbox { font-size: 11px; margin: 0 0 0 6px; @@ -238,16 +264,6 @@ /* TODO avoid increasing the overall height */ } -.verticaltabs-dropingroup { - margin-left: 10px !important; -} - -.verticaltabs-droptonewgroup { - /* TODO need icon to symbolize tab group */ - list-style-image: url("chrome://browser/skin/Toolbar.png"); - -moz-image-region: rect(0, 280px, 20px, 260px); -} - .verticaltabs-twisty { list-style-image: url("resource://verticaltabs/skin/osx/twisty.png"); opacity: 0.38; diff --git a/skin/win7/win7.css b/skin/win7/win7.css index 00f4ce5..aacf780 100644 --- a/skin/win7/win7.css +++ b/skin/win7/win7.css @@ -1,9 +1,5 @@ @namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); -#nav-bar { - margin-right: 100px; -} - #verticaltabs-splitter { min-width: 3px !important; width: 3px !important; @@ -61,8 +57,7 @@ background: -moz-linear-gradient(left, gray, #ebf3fd) repeat-y !important; } -.tabbrowser-tab[selected="true"], -.tabbrowser-tab[multiselect="true"] { +.tabbrowser-tab[selected="true"] { /*margin: 0 !important;*/ /*padding: 0 0 0 3px !important;*/ @@ -72,8 +67,7 @@ font-weight: normal; text-shadow: none; } -.tabbrowser-tab[selected="true"]:-moz-window-inactive, -.tabbrowser-tab[multiselect="true"]:-moz-window-inactive { +.tabbrowser-tab[selected="true"]:-moz-window-inactive { border: 1px solid !important; -moz-border-top-colors: #d9d9d9 #fafafb !important; -moz-border-bottom-colors: #d9d9d9 #f0f0f0 !important; @@ -121,7 +115,6 @@ margin-bottom: 0 !important; } - /*** Tab toolbar styling ***/ #browser-border-start { @@ -148,13 +141,6 @@ margin-bottom: 23px !important; border-bottom-left-radius: 4px !important; } -#verticaltabs-groupbutton { - /* TODO need icon to symbolize tab group */ - list-style-image: url("chrome://browser/skin/Toolbar.png"); - -moz-image-region: rect(0, 234px, 18px, 216px); -} - - /* Ensure that content area has a top border */ #navigator-toolbox::after { visibility: visible !important; @@ -182,24 +168,6 @@ margin-bottom: 23px !important; border-bottom-right-radius: 4px !important; } - -/*** Group related styles ***/ - -.tabbrowser-tab[verticaltabs-ingroup], -.tabbrowser-tab[verticaltabs-ingroup]:hover { - padding-left: 16px !important; -} - -.tabbrowser-tab[verticaltabs-group] { -} - -.tabbrowser-tab[verticaltabs-group] .tab-close-button { - opacity: 1 !important; -} - -.tabbrowser-tab[verticaltabs-group] .tab-text { -} - .verticaltabs-textbox { margin: 0; } @@ -217,16 +185,6 @@ margin-bottom: 23px !important; background: -moz-linear-gradient(top, #ebf4fe, #cfe4fe) repeat-x !important; } -.verticaltabs-dropingroup { - margin-left: 10px !important; -} - -.verticaltabs-droptonewgroup { - /* TODO need icon to symbolize tab group */ - list-style-image: url("chrome://browser/skin/Toolbar.png"); - -moz-image-region: rect(0, 234px, 18px, 216px); -} - .verticaltabs-twisty { cursor: default !important; margin-left: 1px !important; diff --git a/tabdatastore.jsm b/tabdatastore.jsm deleted file mode 100644 index 03e5553..0000000 --- a/tabdatastore.jsm +++ /dev/null @@ -1,177 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Tree Style Tab. - * - * The Initial Developer of the Original Code is - * SHIMODA Hiroshi. - * Portions created by the Initial Developer are Copyright (C) 2010 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * SHIMODA Hiroshi - * Philipp von Weitershausen - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ******/ - -/** - * Persistently store tab attributes in the session store service. - * - * Heavily inspired by Tree Style Tab's TreeStyleTabUtils. - */ - -const EXPORTED_SYMBOLS = ["VTTabDataStore", "VTTabIDs"]; -Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); - -var VTTabDataStore = { - - getTabValue: function(aTab, aKey) { - let value = null; - try { - value = this.sessionStore.getTabValue(aTab, aKey); - } catch(ex) { - // Ignore - } - return value; - }, - - setTabValue: function(aTab, aKey, aValue) { - if (!aValue) { - this.deleteTabValue(aTab, aKey); - } - - aTab.setAttribute(aKey, aValue); - try { - this.checkCachedSessionDataExpiration(aTab); - this.sessionStore.setTabValue(aTab, aKey, aValue); - } catch(ex) { - // Ignore - } - }, - - deleteTabValue: function(aTab, aKey) { - aTab.removeAttribute(aKey); - try { - this.checkCachedSessionDataExpiration(aTab); - this.sessionStore.setTabValue(aTab, aKey, ""); - this.sessionStore.deleteTabValue(aTab, aKey); - } catch(ex) { - // Ignore - } - }, - - // workaround for http://piro.sakura.ne.jp/latest/blosxom/mozilla/extension/treestyletab/2009-09-29_debug.htm - checkCachedSessionDataExpiration: function(aTab) { - let data = aTab.linkedBrowser.__SS_data; - if (data && - data._tabStillLoading && - aTab.getAttribute("busy") != "true") - data._tabStillLoading = false; - } -}; -XPCOMUtils.defineLazyServiceGetter(VTTabDataStore, "sessionStore", - "@mozilla.org/browser/sessionstore;1", - "nsISessionStore"); - - -/* - * Assign tabs a persistent unique identifier. - * - * Necessary until https://bugzilla.mozilla.org/show_bug.cgi?id=529477 - * is implemented. - */ - -function VTTabIDs(tabs) { - this.tabs = tabs; - this.init(); -} -VTTabIDs.prototype = { - - init: function() { - const tabs = this.tabs; - tabs.VTTabIDs = this; - tabs.addEventListener("TabOpen", this, true); - tabs.addEventListener("SSTabRestoring", this, true); - for (let i=0; i < tabs.childNodes.length; i++) { - this.initTab(tabs.childNodes[i]); - } - }, - - unload: function unload() { - const tabs = this.tabs; - delete tabs.VTTabIDs; - tabs.removeEventListener("TabOpen", this, true); - tabs.removeEventListener("SSTabRestoring", this, true); - }, - - kId: "verticaltabs-id", - - id: function(aTab) { - return aTab.getAttribute(this.kId); - }, - - get: function(aID) { - let elements = this.tabs.getElementsByAttribute(this.kId, aID); - return elements.length ? elements[0] : undefined; - }, - - /*** Event handlers ***/ - - handleEvent: function(aEvent) { - switch (aEvent.type) { - case "TabOpen": - this.initTab(aEvent.originalTarget); - return; - case "SSTabRestoring": - this.restoreTab(aEvent.originalTarget); - return; - } - }, - - makeNewId: function() { - return this.uuidGen.generateUUID().toString(); - }, - - initTab: function(aTab) { - if (aTab.hasAttribute(this.kId)) { - return; - } - // Assign an ID. This may be temporary if the tab is being restored. - let id = VTTabDataStore.getTabValue(aTab, this.kId) || this.makeNewId(); - VTTabDataStore.setTabValue(aTab, this.kId, id); - }, - - restoreTab: function(aTab) { - // Restore the original ID - let newId = VTTabDataStore.getTabValue(aTab, this.kId); - if (newId) { - aTab.setAttribute(this.kId, newId); - } - } - -}; -XPCOMUtils.defineLazyServiceGetter(VTTabIDs.prototype, "uuidGen", - "@mozilla.org/uuid-generator;1", - "nsIUUIDGenerator"); diff --git a/vertical-tabbrowser.xml b/vertical-tabbrowser.xml index c08c134..8110047 100644 --- a/vertical-tabbrowser.xml +++ b/vertical-tabbrowser.xml @@ -57,9 +57,9 @@ @@ -69,7 +69,7 @@ onclick="checkForMiddleClick(this, event);" onmouseover="document.getBindingParent(this)._enterNewTab();" onmouseout="document.getBindingParent(this)._leaveNewTab();" - tooltiptext="&newTabButton.tooltip;"/> + tooltip="dynamic-shortcut-tooltip"/> @@ -84,15 +84,15 @@ @@ -107,35 +107,35 @@ if (doPosition) { this.setAttribute("positionpinnedtabs", "true"); - if (verticalTabs) { + if (verticalTabs) { let scrollButtonHeight = this.mTabstrip._scrollButtonDown.getBoundingClientRect().height; let paddingStart = this.mTabstrip._scrollbox.style.paddingTop; let height = 0; - + for (let i = numPinned - 1; i >= 0; i--) { let tab = this.childNodes[i]; height += tab.getBoundingClientRect().height; tab.style.marginTop = - (height + scrollButtonHeight + paddingStart) + "px"; } - + this.style.paddingTop = height + paddingStart + "px"; - } else { + } else { let scrollButtonWidth = this.mTabstrip._scrollButtonDown.getBoundingClientRect().width; let paddingStart = this.mTabstrip.scrollboxPaddingStart; let width = 0; - + for (let i = numPinned - 1; i >= 0; i--) { let tab = this.childNodes[i]; width += tab.getBoundingClientRect().width; tab.style.MozMarginStart = - (width + scrollButtonWidth + paddingStart) + "px"; } - + this.style.MozPaddingStart = width + paddingStart + "px"; - } + } } else { this.removeAttribute("positionpinnedtabs"); - if (verticalTabs) { + if (verticalTabs) { for (let i = 0; i < numPinned; i++) { let tab = this.childNodes[i]; tab.style.marginTop = ""; @@ -147,7 +147,7 @@ let tab = this.childNodes[i]; tab.style.MozMarginStart = ""; } - + this.style.MozPaddingStart = ""; } } diff --git a/verticaltabs.jsm b/verticaltabs.jsm index b80f06f..cef8c58 100644 --- a/verticaltabs.jsm +++ b/verticaltabs.jsm @@ -36,9 +36,8 @@ * ***** END LICENSE BLOCK ***** */ Components.utils.import("resource://gre/modules/Services.jsm"); -Components.utils.import("resource://verticaltabs/tabdatastore.jsm"); -Components.utils.import("resource://verticaltabs/multiselect.jsm"); -Components.utils.import("resource://verticaltabs/groups.jsm"); + +let console = (Components.utils.import("resource://gre/modules/devtools/Console.jsm", {})).console; const EXPORTED_SYMBOLS = ["VerticalTabs"]; @@ -56,50 +55,73 @@ function VerticalTabs(window) { this.unloaders = []; this.init(); } -VerticalTabs.prototype = { +VerticalTabs.prototype = { init: function() { this.window.VerticalTabs = this; this.unloaders.push(function() { delete this.window.VerticalTabs; }); + this.sss = Components.classes["@mozilla.org/content/style-sheet-service;1"] + .getService(Components.interfaces.nsIStyleSheetService); + this.ios = Components.classes["@mozilla.org/network/io-service;1"] + .getService(Components.interfaces.nsIIOService); + this.installStylesheet("resource://verticaltabs/override-bindings.css"); - this.installStylesheet("resource://verticaltabs/skin/bindings.css"); this.installStylesheet("resource://verticaltabs/skin/base.css"); - switch (Services.appinfo.OS) { - case "WINNT": - this.installStylesheet("resource://verticaltabs/skin/win7/win7.css"); - break; - case "Darwin": - this.installStylesheet("resource://verticaltabs/skin/osx/osx.css"); - break; - case "Linux": - this.installStylesheet("resource://verticaltabs/skin/linux/linux.css"); - break; - } + this.applyThemeStylesheet(); + this.unloaders.push(this.removeThemeStylesheet); this.rearrangeXUL(); - this.initContextMenu(); this.observeRightPref(); - - let tabs = this.document.getElementById("tabbrowser-tabs"); - this.tabIDs = new VTTabIDs(tabs); - //this.groups = new VTGroups(tabs); - this.unloaders.push(function() { - this.tabIDs.unload(); - //this.groups.unload(); - }); + this.observeThemePref(); }, installStylesheet: function(uri) { - const document = this.document; - let pi = document.createProcessingInstruction( - "xml-stylesheet", "href=\"" + uri + "\" type=\"text/css\""); - document.insertBefore(pi, document.documentElement); - this.unloaders.push(function () { - document.removeChild(pi); - }); + uri = this.ios.newURI(uri, null, null); + this.sss.loadAndRegisterSheet(uri, this.sss.USER_SHEET); + }, + + applyThemeStylesheet: function() { + this.theme = Services.prefs.getCharPref("extensions.verticaltabs.theme"); + this.installStylesheet(this.getThemeStylesheet(this.theme)); + }, + + removeThemeStylesheet: function() { + var uri = this.ios.newURI(this.getThemeStylesheet(this.theme), null, null); + this.sss.unregisterSheet(uri, this.sss.USER_SHEET); + }, + + getThemeStylesheet: function(theme) { + var stylesheet; + switch (theme) { + case "default": + switch(Services.appinfo.OS) { + case "WINNT": + stylesheet = "resource://verticaltabs/skin/win7/win7.css"; + break; + + case "Darwin": + stylesheet = "resource://verticaltabs/skin/osx/osx.css"; + break; + + case "Linux": + stylesheet = "resource://verticaltabs/skin/linux/linux.css"; + break; + } + break; + + case "dark": + stylesheet = "resource://verticaltabs/skin/dark/dark.css"; + break; + + case "light": + stylesheet = "resource://verticaltabs/skin/light/light.css"; + break; + } + + return stylesheet; }, rearrangeXUL: function() { @@ -144,36 +166,21 @@ VerticalTabs.prototype = { // Move the tabs toolbar into the tab strip let toolbar = document.getElementById("TabsToolbar"); + toolbar.setAttribute("collapsed", "false"); // no more vanishing new tab toolbar toolbar._toolbox = null; // reset value set by constructor toolbar.setAttribute("toolboxid", "navigator-toolbox"); leftbox.appendChild(toolbar); - - // Force tabs on bottom (for styling) after backing up the user's - // setting. - try { - Services.prefs.getBoolPref("extensions.verticaltabs.tabsOnTop"); - } catch (ex if (ex.result == Components.results.NS_ERROR_UNEXPECTED)) { - Services.prefs.setBoolPref("extensions.verticaltabs.tabsOnTop", - window.TabsOnTop.enabled); - } + + // Not sure what this does, it and all related code might be unnecessary + /* + window.TabsOnTop = window.TabsOnTop ? window.TabsOnTop : {}; window.TabsOnTop.enabled = false; - // Hide all menu items for tabs on top. - let menu_tabsOnTop = document.getElementById("menu_tabsOnTop"); - menu_tabsOnTop.collapsed = true; - menu_tabsOnTop.nextSibling.collapsed = true; // separator + */ + let toolbar_context_menu = document.getElementById("toolbar-context-menu"); toolbar_context_menu.firstChild.collapsed = true; toolbar_context_menu.firstChild.nextSibling.collapsed = true; // separator - let appmenu_tabsOnTop = document.getElementById("appmenu_toggleTabsOnTop"); - if (appmenu_tabsOnTop) { - appmenu_tabsOnTop.collapsed = true; - } - // Disable the command just to be safe. - let cmd_tabsOnTop = document.getElementById("cmd_ToggleTabsOnTop"); - cmd_tabsOnTop.disabled = true; - // Fix up each individual tab for vertical layout, including - // ones that are opened later on. tabs.addEventListener("TabOpen", this, false); for (let i=0; i < tabs.childNodes.length; i++) { this.initTab(tabs.childNodes[i]); @@ -181,7 +188,11 @@ VerticalTabs.prototype = { this.window.addEventListener("resize", this, false); + this.window.addEventListener("sizemodechange", this, true); + this.unloaders.push(function () { + this.window.removeEventListener("sizemodechange", this, true); + // Move the bottom back to being the next sibling of contentbox. browserbox.insertBefore(bottom, contentbox.nextSibling); @@ -189,10 +200,15 @@ VerticalTabs.prototype = { toolbar._toolbox = null; // reset value set by constructor toolbar.removeAttribute("toolboxid"); let toolbox = document.getElementById("navigator-toolbox"); - toolbox.appendChild(toolbar); + let navbar = document.getElementById("nav-bar"); + //toolbox.appendChild(toolbar); // Restore the tab strip. + toolbox.insertBefore(toolbar, navbar); + let new_tab_button = document.getElementById("new-tab-button"); + + // Put the tabs back up dur toolbar.insertBefore(tabs, new_tab_button); tabs.orient = "horizontal"; tabs.mTabstrip.orient = "horizontal"; @@ -201,16 +217,12 @@ VerticalTabs.prototype = { tabs.removeEventListener("TabOpen", this, false); // Restore tabs on top. + /* window.TabsOnTop.enabled = Services.prefs.getBoolPref( "extensions.verticaltabs.tabsOnTop"); - menu_tabsOnTop.collapsed = false; - menu_tabsOnTop.nextSibling.collapsed = false; // separator + */ toolbar_context_menu.firstChild.collapsed = false; toolbar_context_menu.firstChild.nextSibling.collapsed = false; // separator - if (appmenu_tabsOnTop) { - appmenu_tabsOnTop.collapsed = false; - } - cmd_tabsOnTop.disabled = false; // Restore all individual tabs. for (let i = 0; i < tabs.childNodes.length; i++) { @@ -228,35 +240,24 @@ VerticalTabs.prototype = { }); }, - initContextMenu: function() { - const document = this.document; - const tabs = document.getElementById("tabbrowser-tabs"); - - let closeMultiple = null; - if (this.multiSelect) { - closeMultiple = document.createElementNS(NS_XUL, "menuitem"); - closeMultiple.id = "context_verticalTabsCloseMultiple"; - closeMultiple.setAttribute("label", "Close Selected Tabs"); //TODO l10n - closeMultiple.setAttribute("tbattr", "tabbrowser-multiple"); - closeMultiple.setAttribute( - "oncommand", "gBrowser.tabContainer.VTMultiSelect.closeSelected();"); - tabs.contextMenu.appendChild(closeMultiple); - } - - tabs.contextMenu.addEventListener("popupshowing", this, false); - - this.unloaders.push(function () { - if (closeMultiple) - tabs.contextMenu.removeChild(closeMultiple); - tabs.contextMenu.removeEventListener("popupshowing", this, false); - }); - }, - initTab: function(aTab) { aTab.setAttribute("align", "stretch"); aTab.maxWidth = 65000; aTab.minWidth = 0; }, + + onSizeModeChange: function(aEvent) { + let box = this.document.getElementById("verticaltabs-box"); + let splitter = this.document.getElementById("verticaltabs-splitter"); + if(this.window.windowState == 4 + && Services.prefs.getBoolPref("extensions.verticaltabs.fullscreen")) { + box.style.display = 'none'; + splitter.style.display = 'none'; + } else { + box.style.display = ''; + splitter.style.display = ''; + } + }, setPinnedSizes: function() { let tabs = this.document.getElementById("tabbrowser-tabs"); @@ -285,74 +286,74 @@ VerticalTabs.prototype = { }, observeRightPref: function () { - Services.prefs.addObserver("extensions.verticaltabs.right", this, false); - this.unloaders.push(function () { - Services.prefs.removeObserver("extensions.verticaltabs.right", this, false); - }); + Services.prefs.addObserver("extensions.verticaltabs.right", this, false); + this.unloaders.push(function () { + Services.prefs.removeObserver("extensions.verticaltabs.right", this, false); + }); + }, + + observeThemePref: function() { + Services.prefs.addObserver("extensions.verticaltabs.theme", this, false); + this.unloaders.push(function() { + Services.prefs.removeObserver("extensions.verticaltabs.theme", this, false); + }); }, observe: function (subject, topic, data) { - if (topic != "nsPref:changed" || data != "extensions.verticaltabs.right") { - return; - } - let browserbox = this.document.getElementById("browser"); - if (browserbox.dir != "reverse") { - browserbox.dir = "reverse"; - } else { - browserbox.dir = "normal"; - } + if (topic != "nsPref:changed") { + return; + } + + switch (data) { + case "extensions.verticaltabs.right": + let browserbox = this.document.getElementById("browser"); + if (browserbox.dir != "reverse") { + browserbox.dir = "reverse"; + } else { + browserbox.dir = "normal"; + } + break; + + case "extensions.verticaltabs.theme": + console.log("updating theme"); + this.removeThemeStylesheet(); + this.applyThemeStylesheet(); + break; + } }, unload: function() { - this.unloaders.forEach(function(func) { - func.call(this); - }, this); + this.unloaders.forEach(function(func) { + func.call(this); + }, this); }, /*** Event handlers ***/ handleEvent: function(aEvent) { switch (aEvent.type) { - case "DOMContentLoaded": - this.init(); - return; case "TabOpen": - this.onTabOpen(aEvent); + this.initTab(aEvent.target); this.setPinnedSizes(); return; + case "mouseup": - this.onMouseUp(aEvent); + if (aEvent.target.getAttribute("id") == "verticaltabs-splitter") { + this.onTabbarResized(); + } return; - case "popupshowing": - this.onPopupShowing(aEvent); + + case "DOMContentLoaded": + this.init(); return; + case "resize": this.setPinnedSizes(); return; - } - }, - onTabOpen: function(aEvent) { - this.initTab(aEvent.target); - }, - - onMouseUp: function(aEvent) { - if (aEvent.target.getAttribute("id") == "verticaltabs-splitter") { - this.onTabbarResized(); - } - }, - - onPopupShowing: function(aEvent) { - if (!this.multiSelect) + case "sizemodechange": + this.onSizeModeChange(aEvent); return; - - let closeTabs = this.document.getElementById("context_verticalTabsCloseMultiple"); - let tabs = this.multiSelect.getSelected(); - if (tabs.length > 1) { - closeTabs.disabled = false; - } else { - closeTabs.disabled = true; } - } - + }, };