diff --git a/content/treestyletab/config.xul b/content/treestyletab/config.xul
index 7e85060b..f7a439f9 100644
--- a/content/treestyletab/config.xul
+++ b/content/treestyletab/config.xul
@@ -15,6 +15,9 @@
name="extensions.treestyletab.adoptChildrenToGrandParentOnRemoveTab"
type="bool"
inverted="true"/>
+
@@ -26,6 +29,9 @@
+
diff --git a/content/treestyletab/treestyletab.js b/content/treestyletab/treestyletab.js
index 3231534f..93d37037 100644
--- a/content/treestyletab/treestyletab.js
+++ b/content/treestyletab/treestyletab.js
@@ -1,10 +1,14 @@
var TreeStyleTabService = {
PREFROOT : 'extensions.treestyletab@piro.sakura.ne.jp',
- kID : 'treestyletab-id',
- kCHILDREN : 'treestyletab-children',
- kPARENT : 'treestyletab-parent',
- kINSERTBEFORE : 'treestyletab-insert-before',
+ kID : 'treestyletab-id',
+ kCHILDREN : 'treestyletab-children',
+ kPARENT : 'treestyletab-parent',
+ kINSERT_BEFORE : 'treestyletab-insert-before',
+ kSUBTREE_COLLAPSED : 'treestyletab-subtree-collapsed',
+ kCOLLAPSED : 'treestyletab-tab-collapsed',
+
+ kTWISTY : 'treestyletab-tab-tree-twisty',
levelMargin : 12,
@@ -52,6 +56,16 @@ var TreeStyleTabService = {
return false;
},
+ isEventFiredOnTwisty : function(aEvent)
+ {
+ var node = aEvent.originalTarget;
+ while (node.getAttribute('class') != this.kTWISTY && node.localName != 'tabs')
+ {
+ node = node.parentNode;
+ }
+ return (node && node.getAttribute('class') == this.kTWISTY) ? true : false ;
+ },
+
get browser()
{
return 'SplitBrowser' ? SplitBrowser.activeBrowser : gBrowser ;
@@ -186,7 +200,7 @@ var TreeStyleTabService = {
},
/* Initializing */
-
+
init : function()
{
if (!('gBrowser' in window)) return;
@@ -223,15 +237,31 @@ var TreeStyleTabService = {
this.initTabBrowser(gBrowser);
},
-
+
initTabBrowser : function(aTabBrowser)
{
aTabBrowser.mTabContainer.addEventListener('TreeStyleTab:TabOpen', this, true);
aTabBrowser.mTabContainer.addEventListener('TabClose', this, true);
aTabBrowser.mTabContainer.addEventListener('TabMove', this, true);
aTabBrowser.mTabContainer.addEventListener('SSTabRestoring', this, true);
+ aTabBrowser.mTabContainer.addEventListener('click', this, true);
+ aTabBrowser.mTabContainer.addEventListener('mousedown', this, true);
+ aTabBrowser.mTabContainer.addEventListener('select', this, true);
aTabBrowser.mPanelContainer.addEventListener('click', this, true);
+ eval('aTabBrowser.mTabContainer.selectNewTab = '+
+ aTabBrowser.mTabContainer.selectNewTab.toSource().replace(
+ /\{/,
+ <>>
+ )
+ );
+
var addTabMethod = 'addTab';
var removeTabMethod = 'removeTab';
@@ -289,11 +319,23 @@ var TreeStyleTabService = {
this.setTabValue(aTab, this.kID, id);
aTab.__treestyletab__linkedTabBrowser = aTabBrowser;
+ this.initTabTwisty(aTab);
+
var event = document.createEvent('Events');
event.initEvent('TreeStyleTab:TabOpen', true, false);
aTab.dispatchEvent(event);
},
-
+
+ initTabTwisty : function(aTab)
+ {
+ if (document.getAnonymousElementByAttribute(aTab, 'class', this.kTWISTY)) return;
+
+ var twisty = document.createElement('toolbarbutton');
+ twisty.setAttribute('class', this.kTWISTY);
+ var icon = document.getAnonymousElementByAttribute(aTab, 'class', 'tab-icon');
+ icon.appendChild(twisty);
+ },
+
destroy : function()
{
this.destroyTabBrowser(gBrowser);
@@ -328,6 +370,9 @@ var TreeStyleTabService = {
aTabBrowser.mTabContainer.removeEventListener('TabClose', this, true);
aTabBrowser.mTabContainer.removeEventListener('TabMove', this, true);
aTabBrowser.mTabContainer.removeEventListener('SSTabRestoring', this, true);
+ aTabBrowser.mTabContainer.removeEventListener('click', this, true);
+ aTabBrowser.mTabContainer.removeEventListener('mousedown', this, true);
+ aTabBrowser.mTabContainer.removeEventListener('select', this, true);
aTabBrowser.mPanelContainer.removeEventListener('click', this, true);
// var tabContextMenu = document.getAnonymousElementByAttribute(aTabBrowser, 'anonid', 'tabContextMenu');
@@ -347,25 +392,30 @@ var TreeStyleTabService = {
{
case 'TreeStyleTab:TabOpen':
this.onTabAdded(aEvent);
- break;
+ return;
case 'TabClose':
this.onTabRemoved(aEvent);
- break;
+ return;
case 'TabMove':
var tab = aEvent.originalTarget;
- var b = this.getTabBrowserFromChildren(tab);
+ this.initTabTwisty(tab); // twisty vanished after the tab is moved!!
+ var b = this.getTabBrowserFromChildren(tab);
if (tab.getAttribute(this.kCHILDREN) && !b.__treestyletab__isSubTreeMoving) {
this.moveTabSubTreeTo(tab, tab._tPos);
}
- break;
+ return;
case 'SSTabRestoring':
this.onTabRestored(aEvent);
- break;
+ return;
case 'click':
+ if (aEvent.target.ownerDocument == document) {
+ this.onTabClick(aEvent);
+ return;
+ }
var isMiddleClick = (
aEvent.button == 1 ||
aEvent.button == 0 && (aEvent.ctrlKey || aEvent.metaKey)
@@ -380,27 +430,40 @@ var TreeStyleTabService = {
b.__treestyletab__readyToAdoptNewTab = true;
b.__treestyletab__parentTab = b.selectedTab.getAttribute(this.kID);
}
- break;
+ return;
+
+ case 'mousedown':
+ this.onTabMouseDown(aEvent);
+ return;
+
+ case 'select':
+ var b = this.getTabBrowserFromChildren(aEvent.currentTarget);
+ var tab = b.selectedTab
+ var p;
+ if (tab.getAttribute(this.kCOLLAPSED) && (p = this.getParentTabOf(tab))) {
+ b.selectedTab = p;
+ }
+ return;
case 'load':
this.init();
- break;
+ return;
case 'unload':
this.destroy();
- break;
+ return;
case 'popupshowing':
// this.showHideMenuItems(aEvent.target);
- break;
+ return;
case 'SubBrowserAdded':
this.initTabBrowser(aEvent.originalTarget.browser);
- break;
+ return;
case 'SubBrowserRemoveRequest':
this.destroyTabBrowser(aEvent.originalTarget.browser);
- break;
+ return;
}
},
@@ -421,8 +484,17 @@ var TreeStyleTabService = {
onTabRemoved : function(aEvent)
{
- var tab = aEvent.originalTarget;
- var b = this.getTabBrowserFromChildren(tab);
+ var tab = aEvent.originalTarget;
+ var b = this.getTabBrowserFromChildren(tab);
+
+ if (tab.getAttribute(this.kSUBTREE_COLLAPSED)) {
+ var descendant = this.getDescendantTabsOf(tab);
+ for (var i = descendant.length-1; i > -1; i--)
+ {
+ b.removeTab(descendant[i]);
+ }
+ }
+
var firstChild = this.getFirstChildTabOf(tab);
var parentTab = this.getParentTabOf(tab);
var nextFocusedTab = null;
@@ -431,7 +503,7 @@ var TreeStyleTabService = {
this.setTabValue(tab, this.kPARENT, parentTab.getAttribute(this.kID));
var next = this.getNextSiblingTabOf(tab);
if (next)
- this.setTabValue(tab, this.kINSERTBEFORE, next.getAttribute(this.kID));
+ this.setTabValue(tab, this.kINSERT_BEFORE, next.getAttribute(this.kID));
}
if (firstChild) {
@@ -490,6 +562,8 @@ var TreeStyleTabService = {
var id = this.getTabValue(tab, this.kID);
this.setTabValue(tab, this.kID, id);
+ var isSubTreeCollapsed = (this.getTabValue(tab, this.kSUBTREE_COLLAPSED) == 'true');
+
var children = this.getTabValue(tab, this.kCHILDREN);
if (children) {
children = children.split('|');
@@ -504,7 +578,7 @@ var TreeStyleTabService = {
}
var parent = this.getTabValue(tab, this.kPARENT);
- var before = this.getTabValue(tab, this.kINSERTBEFORE);
+ var before = this.getTabValue(tab, this.kINSERT_BEFORE);
if (parent && (parent = this.getTabById(parent, b))) {
this.adoptTabTo(tab, parent, (before ? this.getTabById(before, b) : null ), true);
this.deleteTabValue(tab, this.kPARENT);
@@ -513,49 +587,34 @@ var TreeStyleTabService = {
else if (children) {
this.updateTabsIndent(tabs);
}
+
+/*
+ if (isSubTreeCollapsed) {
+ this.collapseExpandTabSubTree(tab, isSubTreeCollapsed);
+ }
+*/
+ },
+
+ onTabMouseDown : function(aEvent)
+ {
+ if (aEvent.button != 0 ||
+ !this.isEventFiredOnTwisty(aEvent))
+ return;
+
+ this.getTabFromEvent(aEvent).__treestyletab__preventSelect = true;
},
onTabClick : function(aEvent)
{
- if (aEvent.button != 0) return;
+ if (aEvent.button != 0 ||
+ !this.isEventFiredOnTwisty(aEvent))
+ return;
var tab = this.getTabFromEvent(aEvent);
- if (tab) {
- var b = this.getTabBrowserFromChildren(tab);
- if (aEvent.shiftKey) {
- var tabs = b.mTabContainer.childNodes;
- var inSelection = false;
- for (var i = 0, maxi = tabs.length; i < maxi; i++)
- {
- if (tabs[i] == b.selectedTab ||
- tabs[i] == tab) {
- inSelection = !inSelection;
- this.setSelection(tabs[i], true);
- }
- else {
- this.setSelection(tabs[i], inSelection);
- }
- }
- aEvent.preventDefault();
- aEvent.stopPropagation();
- return;
- }
- else if (aEvent.ctrlKey || aEvent.metaKey) {
- if (this.tabClickMode != this.TAB_CLICK_MODE_TOGGLE) return;
+ this.collapseExpandTabSubTree(tab, tab.getAttribute(this.kSUBTREE_COLLAPSED) != 'true');
- if (!this.selectionModified && !this.hasSelection())
- this.setSelection(b.selectedTab, true);
-
- this.toggleSelection(tab);
- aEvent.preventDefault();
- aEvent.stopPropagation();
- return;
- }
- }
- if (this.selectionModified && !this.hasSelection())
- this.selectionModified = false;
-
- this.clearSelection();
+ aEvent.preventDefault();
+ aEvent.stopPropagation();
},
/* Tab Utilities */
@@ -786,6 +845,21 @@ var TreeStyleTabService = {
if (newIndex > aChild._tPos) newIndex--;
this.moveTabSubTreeTo(aChild, newIndex);
+ if (aParent.getAttribute(this.kSUBTREE_COLLAPSED) == 'true') {
+ if (this.getPref('extensions.treestyletab.autoExpandSubTreeOnAppendChild')) {
+ var p = aParent;
+ do {
+ this.collapseExpandTabSubTree(p, false);
+ }
+ while (p = this.getParentTabOf(p));
+ }
+ else
+ this.collapseExpandTab(aChild, true);
+ }
+
+ if (aParent.getAttribute(this.kCOLLAPSED) == 'true')
+ this.collapseExpandTab(aChild, true);
+
if (!aDontUpdateIndent) this.updateTabsIndent([aChild]);
},
@@ -829,6 +903,8 @@ var TreeStyleTabService = {
moveTabSubTreeTo : function(aTab, aIndex)
{
+ if (!aTab) return;
+
var b = this.getTabBrowserFromChildren(aTab);
b.__treestyletab__isSubTreeMoving = true;
@@ -842,7 +918,41 @@ var TreeStyleTabService = {
b.__treestyletab__isSubTreeMoving = false;
},
-
+
+ collapseExpandTabSubTree : function(aTab, aCollapse)
+ {
+ if (!aTab) return;
+
+ if (aTab.getAttribute(this.kSUBTREE_COLLAPSED) == String(aCollapse)) return;
+
+ this.setTabValue(aTab, this.kSUBTREE_COLLAPSED, aCollapse);
+
+ var tabs = this.getChildTabsOf(aTab);
+ for (var i = 0, maxi = tabs.length; i < maxi; i++)
+ {
+ this.collapseExpandTab(tabs[i], aCollapse);
+ }
+ },
+
+ collapseExpandTab : function(aTab, aCollapse)
+ {
+ if (!aTab) return;
+
+ this.setTabValue(aTab, this.kCOLLAPSED, aCollapse);
+
+ var b = this.getTabBrowserFromChildren(aTab);
+ var p;
+ if (aTab == b.selectedTab && (p = this.getParentTabOf(aTab))) b.selectedTab = p;
+
+ var isSubTreeCollapsed = (aTab.getAttribute(this.kSUBTREE_COLLAPSED) == 'true');
+ var tabs = this.getChildTabsOf(aTab);
+ for (var i = 0, maxi = tabs.length; i < maxi; i++)
+ {
+ if (!isSubTreeCollapsed)
+ this.collapseExpandTab(tabs[i], aCollapse);
+ }
+ },
+
/* Pref Listener */
domain : 'extensions.treestyletab',
diff --git a/defaults/preferences/treestyletab.js b/defaults/preferences/treestyletab.js
index 7e261b4c..15a39247 100644
--- a/defaults/preferences/treestyletab.js
+++ b/defaults/preferences/treestyletab.js
@@ -1,4 +1,5 @@
pref("extensions.treestyletab.adoptChildrenToGrandParentOnRemoveTab", true);
+pref("extensions.treestyletab.autoExpandSubTreeOnAppendChild", true);
pref("browser.link.open_newwindow.restriction", 0);
diff --git a/locale/en-US/treestyletab/treestyletab.dtd b/locale/en-US/treestyletab/treestyletab.dtd
index 32db06c8..e19d235b 100644
--- a/locale/en-US/treestyletab/treestyletab.dtd
+++ b/locale/en-US/treestyletab/treestyletab.dtd
@@ -5,6 +5,8 @@
+
+
diff --git a/locale/ja/treestyletab/treestyletab.dtd b/locale/ja/treestyletab/treestyletab.dtd
index 4655fde9..0c06f346 100644
--- a/locale/ja/treestyletab/treestyletab.dtd
+++ b/locale/ja/treestyletab/treestyletab.dtd
@@ -5,6 +5,8 @@
+
+
diff --git a/skin/classic/treestyletab/treestyletab.css b/skin/classic/treestyletab/treestyletab.css
index 0494140a..f90aeced 100644
--- a/skin/classic/treestyletab/treestyletab.css
+++ b/skin/classic/treestyletab/treestyletab.css
@@ -1,2 +1,27 @@
@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
+
+.treestyletab-tab-tree-twisty {
+ -moz-appearance: none;
+ margin: -2px -3px -2px -4px;
+ padding: 1px;
+ width: auto;
+ height: auto;
+ border: none;
+ outline: none;
+ background: none;
+ list-style-image: url("tree-twisty-expanded.png");
+}
+
+tab[treestyletab-subtree-collapsed="true"] .treestyletab-tab-tree-twisty {
+ list-style-image: url("tree-twisty-collapsed.png");
+}
+
+tab:not([treestyletab-children]) .treestyletab-tab-tree-twisty {
+ display: none;
+}
+
+tab[treestyletab-tab-collapsed="true"] {
+ visibility: collapse;
+}
+