From ec1fb499e36e15a738d17b16f01cd6ee11c58e9c Mon Sep 17 00:00:00 2001 From: piro Date: Tue, 7 Apr 2009 17:14:09 +0000 Subject: [PATCH] =?UTF-8?q?=E3=82=BF=E3=83=96=E3=81=AE=E6=8A=98=E3=82=8A?= =?UTF-8?q?=E3=81=9F=E3=81=9F=E3=81=BF=E3=82=92=E3=82=A2=E3=83=8B=E3=83=A1?= =?UTF-8?q?=E3=83=BC=E3=82=B7=E3=83=A7=E3=83=B3=E3=81=99=E3=82=8B=E3=82=88?= =?UTF-8?q?=E3=81=86=E3=81=AB=E3=81=97=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://www.cozmixng.org/repos/piro/treestyletab/trunk@4067 599a83e7-65a4-db11-8015-0010dcdd6dc2 --- content/treestyletab/treestyletab.css | 5 +- content/treestyletab/treestyletab.js | 23 ++- content/treestyletab/treestyletabbrowser.js | 156 ++++++++++++++++---- 3 files changed, 149 insertions(+), 35 deletions(-) diff --git a/content/treestyletab/treestyletab.css b/content/treestyletab/treestyletab.css index 2bc77c24..92c945a1 100644 --- a/content/treestyletab/treestyletab.css +++ b/content/treestyletab/treestyletab.css @@ -16,7 +16,7 @@ tabbrowser[treestyletab-allow-subtree-collapse="true"] .tabbrowser-tab[treestyle display: -moz-box; } -tabbrowser[treestyletab-allow-subtree-collapse="true"] .tabbrowser-tab[treestyletab-collapsed="true"], +tabbrowser[treestyletab-allow-subtree-collapse="true"] .tabbrowser-tab[treestyletab-collapsed-done="true"], .tabbrowser-strip[collapsed="true"]+splitter:not([state="collapsed"]), tabbrowser[treestyletab-tabbar-autohide="hidden"] .tabbrowser-strip, tabbrowser[treestyletab-tabbar-autohide="hidden"] .tabbrowser-strip+splitter, @@ -24,7 +24,8 @@ tabbrowser:not([treestyletab-tabbar-autohide="hidden"]) .treestyletab-tabbar-tog #appcontent[ahFull="true"] .tabbrowser-strip[ahHIDE="true"]+splitter /* AutoHide */, tabbrowser[treestyletab-tabbar-fixed="true"] .tabbrowser-strip+splitter { visibility: collapse; -} +} + tabbrowser:not([treestyletab-mode="horizontal"]) .tabbrowser-arrowscrollbox > .scrollbutton-up, tabbrowser:not([treestyletab-mode="horizontal"]) .tabbrowser-arrowscrollbox > .scrollbutton-down-stack, diff --git a/content/treestyletab/treestyletab.js b/content/treestyletab/treestyletab.js index d0a05242..7b12c851 100644 --- a/content/treestyletab/treestyletab.js +++ b/content/treestyletab/treestyletab.js @@ -6,6 +6,8 @@ var TreeStyleTabService = { kINSERT_BEFORE : 'treestyletab-insert-before', kSUBTREE_COLLAPSED : 'treestyletab-subtree-collapsed', kCOLLAPSED : 'treestyletab-collapsed', + kCOLLAPSED_DONE : 'treestyletab-collapsed-done', + kCOLLAPSING : 'treestyletab-collapsing', kTWISTY_HOVER : 'treestyletab-twisty-hover', kNEST : 'treestyletab-nest', kDROP_POSITION : 'treestyletab-drop-position', @@ -93,9 +95,12 @@ var TreeStyleTabService = { kINSERT_FISRT : 0, kINSERT_LAST : 1, - baseLebelMargin : 12, + baseIndent : 12, shouldDetectClickOnIndentSpaces : true, + animationEnabled : true, + indentDelay : 200, + collapseDelay : 150, NSResolver : { lookupNamespaceURI : function(aPrefix) @@ -1032,13 +1037,15 @@ var TreeStyleTabService = { this.processRestoredTabs(); - this.observe(null, 'nsPref:changed', 'extensions.treestyletab.levelMargin'); + this.observe(null, 'nsPref:changed', 'extensions.treestyletab.indent'); this.observe(null, 'nsPref:changed', 'extensions.treestyletab.tabbar.autoHide.mode'); this.observe(null, 'nsPref:changed', 'extensions.treestyletab.clickOnIndentSpaces.enabled'); this.observe(null, 'nsPref:changed', 'browser.link.open_newwindow.restriction.override'); this.observe(null, 'nsPref:changed', 'browser.tabs.loadFolderAndReplace.override'); this.observe(null, 'nsPref:changed', 'extensions.treestyletab.tabbar.style'); this.observe(null, 'nsPref:changed', 'extensions.treestyletab.animation.enabled'); + this.observe(null, 'nsPref:changed', 'extensions.treestyletab.animation.indent.delay'); + this.observe(null, 'nsPref:changed', 'extensions.treestyletab.animation.collapse.delay'); }, initialized : false, @@ -2093,9 +2100,9 @@ catch(e) { var value = this.getPref(aPrefName); switch (aPrefName) { - case 'extensions.treestyletab.levelMargin': - this.baseLebelMargin = value; - this.ObserverService.notifyObservers(null, 'TreeStyleTab:levelMarginModified', value); + case 'extensions.treestyletab.indent': + this.baseIndent = value; + this.ObserverService.notifyObservers(null, 'TreeStyleTab:indentModified', value); break; case 'extensions.treestyletab.tabbar.autoHide.mode': @@ -2148,6 +2155,12 @@ catch(e) { case 'extensions.treestyletab.animation.enabled': this.animationEnabled = value; break; + case 'extensions.treestyletab.animation.indent.delay': + this.indentDelay = value; + break; + case 'extensions.treestyletab.animation.collapse.delay': + this.collapseDelay = value; + break; case 'extensions.treestyletab.tabbar.style': case 'extensions.treestyletab.tabbar.position': diff --git a/content/treestyletab/treestyletabbrowser.js b/content/treestyletab/treestyletabbrowser.js index b6f51654..925ef4df 100644 --- a/content/treestyletab/treestyletabbrowser.js +++ b/content/treestyletab/treestyletabbrowser.js @@ -24,13 +24,29 @@ TreeStyleTabBrowser.prototype = { tabbarResizing : false, - levelMargin : -1, - levelMarginProp : 'margin-left', + indent : -1, + indentProp : 'margin-left', + collapseProp : 'margin-top', positionProp : 'screenY', sizeProp : 'height', invertedPositionProp : 'screenX', invertedSizeProp : 'width', + kVERTICAL_MARGIN_RULES_PATTERN : /margin-(top|bottom):[^;]+;?/g, + kHORIZONTAL_MARGIN_RULES_PATTERN : /margin-(left|right):[^;]+;?/g, + get indentRulesRegExp() + { + return this.isVertical ? + this.kHORIZONTAL_MARGIN_RULES_PATTERN : + this.kVERTICAL_MARGIN_RULES_PATTERN ; + }, + get collapseRulesRegExp() + { + return this.isVertical ? + this.kVERTICAL_MARGIN_RULES_PATTERN : + this.kHORIZONTAL_MARGIN_RULES_PATTERN ; + }, + togglerSize : 0, sensitiveArea : 7, @@ -542,7 +558,7 @@ TreeStyleTabBrowser.prototype = { this.clearTabbarCanvas(); } - this.ObserverService.addObserver(this, 'TreeStyleTab:levelMarginModified', false); + this.ObserverService.addObserver(this, 'TreeStyleTab:indentModified', false); this.ObserverService.addObserver(this, 'TreeStyleTab:collapseExpandAllSubtree', false); this.addPrefListener(this); }, @@ -738,6 +754,7 @@ TreeStyleTabBrowser.prototype = { b.removeAttribute(this.kRESIZING); if (pos & this.kTABBAR_VERTICAL) { + this.collapseProp = 'margin-top'; this.positionProp = 'screenY'; this.sizeProp = 'height'; this.invertedPositionProp = 'screenX'; @@ -778,11 +795,11 @@ TreeStyleTabBrowser.prototype = { b.setAttribute(this.kTABBAR_POSITION, 'right'); if (this.getTreePref('tabbar.invertUI')) { b.setAttribute(this.kUI_INVERTED, 'true'); - this.levelMarginProp = 'margin-right'; + this.indentProp = 'margin-right'; } else { b.removeAttribute(this.kUI_INVERTED); - this.levelMarginProp = 'margin-left'; + this.indentProp = 'margin-left'; } window.setTimeout(function(aWidth) { /* in Firefox 3, the width of the rightside tab bar @@ -800,7 +817,7 @@ TreeStyleTabBrowser.prototype = { else { b.setAttribute(this.kTABBAR_POSITION, 'left'); b.removeAttribute(this.kUI_INVERTED); - this.levelMarginProp = 'margin-left'; + this.indentProp = 'margin-left'; window.setTimeout(function() { b.mTabDropIndicatorBar.setAttribute('ordinal', 1); b.mStrip.setAttribute('ordinal', 10); @@ -812,6 +829,7 @@ TreeStyleTabBrowser.prototype = { } } else { + this.collapseProp = 'margin-left'; this.positionProp = 'screenX'; this.sizeProp = 'width'; this.invertedPositionProp = 'screenY'; @@ -849,7 +867,7 @@ TreeStyleTabBrowser.prototype = { b.removeAttribute(this.kUI_INVERTED); if (pos == this.kTABBAR_BOTTOM) { b.setAttribute(this.kTABBAR_POSITION, 'bottom'); - this.levelMarginProp = 'margin-bottom'; + this.indentProp = 'margin-bottom'; window.setTimeout(function() { b.mTabDropIndicatorBar.setAttribute('ordinal', 1); b.mStrip.setAttribute('ordinal', 30); @@ -860,7 +878,7 @@ TreeStyleTabBrowser.prototype = { } else { b.setAttribute(this.kTABBAR_POSITION, 'top'); - this.levelMarginProp = 'margin-top'; + this.indentProp = 'margin-top'; window.setTimeout(function() { b.mTabDropIndicatorBar.setAttribute('ordinal', 1); b.mStrip.setAttribute('ordinal', 10); @@ -915,7 +933,7 @@ TreeStyleTabBrowser.prototype = { this.tabbarCanvas = null; } - this.ObserverService.removeObserver(this, 'TreeStyleTab:levelMarginModified'); + this.ObserverService.removeObserver(this, 'TreeStyleTab:indentModified'); this.ObserverService.removeObserver(this, 'TreeStyleTab:collapseExpandAllSubtree'); this.removePrefListener(this); @@ -937,8 +955,8 @@ TreeStyleTabBrowser.prototype = { var b = this.mTabBrowser; switch (aTopic) { - case 'TreeStyleTab:levelMarginModified': - if (this.levelMargin > -1) { + case 'TreeStyleTab:indentModified': + if (this.indent > -1) { this.updateAllTabsIndent(); } break; @@ -1376,6 +1394,7 @@ TreeStyleTabBrowser.prototype = { var b = this.mTabBrowser; this.stopTabIndentAnimation(tab); + this.stopTabCollapseAnimation(tab); this.destroyTab(tab); var closeParentBehavior = this.getTreePref('closeParentBehavior'); @@ -2728,13 +2747,13 @@ TreeStyleTabBrowser.prototype = { var b = this.mTabBrowser; if (!aProp) { - aProp = this.getTreePref('enableSubtreeIndent') ? this.levelMarginProp : null ; + aProp = this.getTreePref('enableSubtreeIndent') ? this.indentProp : null ; } - var margin = this.levelMargin < 0 ? this.baseLebelMargin : this.levelMargin ; + var margin = this.indent < 0 ? this.baseIndent : this.indent ; var indent = margin * aLevel; var multirow = this.isMultiRow(); - var topBottom = this.levelMarginProp.match(/top|bottom/); + var topBottom = this.indentProp.match(/top|bottom/); var innerBoxes, j, colors, @@ -2772,6 +2791,7 @@ TreeStyleTabBrowser.prototype = { { this.stopTabIndentAnimation(aTab); + var regexp = this.indentRulesRegExp; if ( !this.animationEnabled || !aProp || @@ -2780,7 +2800,7 @@ TreeStyleTabBrowser.prototype = { aTab.setAttribute( 'style', aTab.getAttribute('style') - .replace(this.kMARGIN_RULES_PATTERN, '')+';'+ + .replace(regexp, '')+';'+ (aProp ? aProp+':'+aIndent+'px !important;' : '' ) ); return; @@ -2788,7 +2808,7 @@ TreeStyleTabBrowser.prototype = { var startIndent = this.getPropertyPixelValue(aTab, aProp); var delta = aIndent - startIndent; - var delay = 200; + var delay = this.indentDelay; var startTime = Date.now(); aTab.__treestyletab__updateTabIndentTimer = window.setInterval(function(aSelf) { var power = Math.min(1, (Date.now() - startTime) / delay); @@ -2798,7 +2818,7 @@ TreeStyleTabBrowser.prototype = { aTab.setAttribute( 'style', aTab.getAttribute('style') - .replace(aSelf.kMARGIN_RULES_PATTERN, '')+';'+ + .replace(regexp, '')+';'+ aProp+':'+indent+'px !important;' ); @@ -2811,15 +2831,15 @@ TreeStyleTabBrowser.prototype = { window.clearInterval(aTab.__treestyletab__updateTabIndentTimer); aTab.__treestyletab__updateTabIndentTimer = null; }, - kMARGIN_RULES_PATTERN : /margin(-[^:]+):[^;]+;?/g, inheritTabIndent : function(aNewTab, aExistingTab) { - var margins = (aExistingTab.getAttribute('style') || '').match(this.kMARGIN_RULES_PATTERN); + var regexp = this.indentRulesRegExp; + var indents = (aExistingTab.getAttribute('style') || '').match(regexp) || []; aNewTab.setAttribute( 'style', aNewTab.getAttribute('style') - .replace(this.kMARGIN_RULES_PATTERN, '')+';'+margins.join(';') + .replace(regexp, '')+';'+indents.join(';') ); }, @@ -2854,24 +2874,24 @@ TreeStyleTabBrowser.prototype = { var nest = tabs[tabs.length-1].getAttribute(this.kNEST); if (!nest) return; - var oldMargin = this.levelMargin; - var indent = (oldMargin < 0 ? this.baseLebelMargin : oldMargin ) * nest; + var oldIndent = this.indent; + var indent = (oldIndent < 0 ? this.baseIndent : oldIndent ) * nest; var maxIndent = ( this.getFirstTab(b).boxObject[this.invertedSizeProp] || b.mTabContainer.boxObject[this.invertedSizeProp] ) * 0.33; - var marginUnit = Math.max(Math.floor(maxIndent / nest), 1); + var indentUnit = Math.max(Math.floor(maxIndent / nest), 1); if (indent > maxIndent) { - this.levelMargin = marginUnit; + this.indent = indentUnit; } else { - this.levelMargin = -1; - if ((this.baseLebelMargin * nest) > maxIndent) - this.levelMargin = marginUnit; + this.indent = -1; + if ((this.baseIndent * nest) > maxIndent) + this.indent = indentUnit; } - if (oldMargin != this.levelMargin) { + if (oldIndent != this.indent) { this.updateAllTabsIndent(); } }, @@ -2983,6 +3003,7 @@ TreeStyleTabBrowser.prototype = { if (!aTab || !this.getParentTab(aTab)) return; this.setTabValue(aTab, this.kCOLLAPSED, aCollapse); + this.updateTabCollapsed(aTab, aCollapse); var event = document.createEvent('Events'); event.initEvent('TreeStyleTabCollapsedStateChange', true, true); @@ -3010,6 +3031,85 @@ TreeStyleTabBrowser.prototype = { this.collapseExpandTab(tabs[i], aCollapse); } }, + updateTabCollapsed : function(aTab, aCollapsed) + { + this.stopTabCollapseAnimation(aTab); + + var regexp = this.collapseRulesRegExp; + if (!this.isVertical || !this.animationEnabled) { + aTab.setAttribute( + 'style', + aTab.getAttribute('style') + .replace(regexp, '') + .replace(this.kOPACITY_RULE_REGEXP, '') + ); + aTab.removeAttribute(this.kCOLLAPSING); + if (aCollapsed) + aTab.setAttribute(this.kCOLLAPSED_DONE, true); + else + aTab.removeAttribute(this.kCOLLAPSED_DONE); + return; + } + + var height = this.getFirstTab(this.mTabBrowser).boxObject.height; + var startMargin = aCollapsed ? 0 : height ; + var endMargin = aCollapsed ? height : 0 ; + var deltaMargin = endMargin - startMargin; + var startOpacity = aCollapsed ? 1 : 0 ; + var endOpacity = aCollapsed ? 0 : 1 ; + var deltaOpacity = endOpacity - startOpacity; + var delay = this.collapseDelay; + var startTime = Date.now(); + var collapseProp = this.collapseProp; + + aTab.setAttribute(this.kCOLLAPSING, true); + aTab.setAttribute( + 'style', + aTab.getAttribute('style') + .replace(regexp, '')+';'+ + collapseProp+': -'+startMargin+'px !important;'+ + 'opacity: '+startOpacity+' !important;' + ); + if (!aCollapsed) aTab.removeAttribute(this.kCOLLAPSED_DONE); + + aTab.__treestyletab__updateTabCollapsedTimer = window.setInterval(function(aSelf) { + var power = Math.min(1, (Date.now() - startTime) / delay); + var powerForStyle = Math.sin(power * 90 * Math.PI / 180); + var margin = (power == 1) ? + endMargin : + startMargin + (deltaMargin * powerForStyle); + var opacity = (power == 1) ? + endOpacity : + startOpacity + (deltaOpacity * powerForStyle); + aTab.setAttribute( + 'style', + aTab.getAttribute('style') + .replace(regexp, '')+';'+ + collapseProp+': -'+margin+'px !important;'+ + 'opacity: '+opacity+' !important;' + ); + + if (power == 1) { + aSelf.stopTabCollapseAnimation(aTab); + aTab.removeAttribute(aSelf.kCOLLAPSING); + aTab.setAttribute( + 'style', + aTab.getAttribute('style') + .replace(regexp, '') + .replace(aSelf.kOPACITY_RULE_REGEXP, '') + ); + if (aCollapsed) + aTab.setAttribute(aSelf.kCOLLAPSED_DONE, true); + } + }, 10, this); + }, + kOPACITY_RULE_REGEXP : /opacity\s*:[^;]+;?/, + stopTabCollapseAnimation : function(aTab) + { + if (!aTab.__treestyletab__updateTabCollapsedTimer) return; + window.clearInterval(aTab.__treestyletab__updateTabCollapsedTimer); + aTab.__treestyletab__updateTabCollapsedTimer = null; + }, collapseExpandTreesIntelligentlyFor : function(aTab) {