var TreeStyleTabService = { /* API */ changeTabbarPosition : function TSTService_changeTabbarPosition(aNewPosition) /* PUBLIC API (obsolete, for backward compatibility) */ { this.currentTabbarPosition = aNewPosition; }, get currentTabbarPosition() /* PUBLIC API */ { return ( // Don't touch to the element before it is initialized by XBL constructor. (this.preInitialized && this.browser.getAttribute(this.kTABBAR_POSITION)) || this.utils.currentTabbarPosition ); }, set currentTabbarPosition(aValue) { if ('UndoTabService' in window && UndoTabService.isUndoable()) { var current = this.utils.currentTabbarPosition; var self = this; UndoTabService.doOperation( function() { self.utils.currentTabbarPosition = aValue; }, { label : self.treeBundle.getString('undo_changeTabbarPosition_label'), name : 'treestyletab-changeTabbarPosition', data : { oldPosition : current, newPosition : aValue } } ); } return this.utils.currentTabbarPosition = aValue; }, undoChangeTabbarPosition : function TSTService_undoChangeTabbarPosition() /* PUBLIC API */ { return this.utils.undoChangeTabbarPosition(); }, redoChangeTabbarPosition : function TSTService_redoChangeTabbarPosition() /* PUBLIC API */ { return this.utils.redoChangeTabbarPosition(); }, get treeViewEnabled() /* PUBLIC API */ { return this.utils.treeViewEnabled; }, set treeViewEnabled(aValue) { return this.utils.treeViewEnabled = aValue; }, get useTMPSessionAPI() /* PUBLIC API */ { return this.utils.useTMPSessionAPI; }, set useTMPSessionAPI(aValue) { return this.utils.useTMPSessionAPI = aValue; }, get browser() { return 'SplitBrowser' in window ? window.SplitBrowser.activeBrowser : window.gBrowser ; }, get shouldApplyNewPref() { return window == this.topBrowserWindow && !this.utils.inWindowDestoructionProcess; }, /* backward compatibility */ getTempTreeStyleTab : function TSTService_getTempTreeStyleTab(aTabBrowser) { return aTabBrowser.treeStyleTab || new TreeStyleTabBrowser(aTabBrowser); }, initTabAttributes : function TSTService_initTabAttributes(aTab, aTabBrowser) { var b = aTabBrowser || this.getTabBrowserFromChild(aTab); this.getTempTreeStyleTab(b).initTabAttributes(aTab); }, initTabContents : function TSTService_initTabContents(aTab, aTabBrowser) { var b = aTabBrowser || this.getTabBrowserFromChild(aTab); this.getTempTreeStyleTab(b).initTabContents(aTab); }, initTabContentsOrder : function TSTService_initTabContentsOrder(aTab, aTabBrowser) { var b = aTabBrowser || this.getTabBrowserFromChild(aTab); this.getTempTreeStyleTab(b).initTabContentsOrder(aTab); }, /* Utilities */ stopRendering : function TSTService_stopRendering() { window['piro.sakura.ne.jp'].stopRendering.stop(); }, startRendering : function TSTService_startRendering() { window['piro.sakura.ne.jp'].stopRendering.start(); }, getPropertyPixelValue : function TSTService_getPropertyPixelValue(aElementOrStyle, aProp) { var style = aElementOrStyle instanceof Components.interfaces.nsIDOMCSSStyleDeclaration ? aElementOrStyle : window.getComputedStyle(aElementOrStyle, null) ; return Number(style.getPropertyValue(aProp).replace(/px$/, '')); }, get isToolbarCustomizing() { var toolbox = window.gToolbox || window.gNavToolbox; return toolbox && toolbox.customizing; }, maxTabbarWidth : function TSTService_maxTabbarWidth(aWidth, aTabBrowser) { aTabBrowser = aTabBrowser || this.browser; var windowWidth = window.outerWidth; var rootWidth = parseInt(document.documentElement.getAttribute('width') || 0); var max = Math.max(windowWidth, rootWidth); return Math.max(0, Math.min(aWidth, max * this.MAX_TABBAR_SIZE_RATIO)); }, maxTabbarHeight : function TSTService_maxTabbarHeight(aHeight, aTabBrowser) { aTabBrowser = aTabBrowser || this.browser; var windowHeight = window.outerHeight; var rootHeight = parseInt(document.documentElement.getAttribute('height') || 0); var max = Math.max(windowHeight, rootHeight); return Math.max(0, Math.min(aHeight, max * this.MAX_TABBAR_SIZE_RATIO)); }, shouldOpenSearchResultAsChild : function TSTService_shouldOpenSearchResultAsChild(aTerm) { var mode = this.getTreePref('autoAttachSearchResultAsChildren'); if (mode == this.kSEARCH_RESULT_ATTACH_ALWAYS) { return true; } else if (!aTerm || mode == this.kSEARCH_RESULT_DO_NOT_ATTACH) { return false; } var w = document.commandDispatcher.focusedWindow; if (!w || w.top != this.browser.contentWindow) w = this.browser.contentWindow; return (function(aWindow) { if (!aWindow || !(aWindow instanceof Components.interfaces.nsIDOMWindow)) return false; var selection = aWindow.getSelection(); if (selection && selection.toString() == aTerm) return true; return aWindow.frames ? Array.slice(aWindow.frames).some(arguments.callee) : false ; })(w); }, kSEARCH_RESULT_DO_NOT_ATTACH : 0, kSEARCH_RESULT_ATTACH_IF_SELECTED : 1, kSEARCH_RESULT_ATTACH_ALWAYS : 2, /* Initializing */ preInit : function TSTService_preInit() { if (this.preInitialized) return; this.preInitialized = true; window.removeEventListener('DOMContentLoaded', this, true); if (location.href.indexOf('chrome://browser/content/browser.xul') != 0) return; window.addEventListener('SSTabRestoring', this, true); var source = window.BrowserStartup.toSource(); if (source.indexOf('!MultipleTabService.tearOffSelectedTabsFromRemote()') > -1) { eval('window.BrowserStartup = '+source.replace( '!MultipleTabService.tearOffSelectedTabsFromRemote()', '!TreeStyleTabService.tearOffSubtreeFromRemote() && $&' )); } else if (source.indexOf('gBrowser.swapBrowsersAndCloseOther') > -1) { eval('window.BrowserStartup = '+source.replace( 'gBrowser.swapBrowsersAndCloseOther(gBrowser.selectedTab, uriToLoad);', 'if (!TreeStyleTabService.tearOffSubtreeFromRemote()) { $& }' )); } eval('nsBrowserAccess.prototype.openURI = '+ nsBrowserAccess.prototype.openURI.toSource().replace( /(switch\s*\(aWhere\))/, ) ); if ('undoCloseTab' in window) { eval('window.undoCloseTab = '+ window.undoCloseTab.toSource().replace( /(\btab\s*=\s*[^\.]+\.undoCloseTab\([^;]+\);)/, ) ); } this.overrideExtensionsPreInit(); // hacks.js this.migratePrefs(); }, preInitialized : false, kPREF_VERSION : 6, migratePrefs : function TSTService_migratePrefs() { // migrate old prefs var orientalPrefs = []; switch (this.getTreePref('prefsVersion')) { case 0: orientalPrefs = orientalPrefs.concat([ 'extensions.treestyletab.tabbar.fixed', 'extensions.treestyletab.enableSubtreeIndent', 'extensions.treestyletab.allowSubtreeCollapseExpand' ]); case 1: orientalPrefs = orientalPrefs.concat([ 'extensions.treestyletab.tabbar.hideAlltabsButton' ]); case 2: if (this.getTreePref('urlbar.loadSameDomainToNewChildTab') !== null) { let value = this.getTreePref('urlbar.loadSameDomainToNewChildTab'); this.setTreePref('urlbar.loadSameDomainToNewTab', value); this.setTreePref('urlbar.loadSameDomainToNewTab.asChild', value); if (value) this.setTreePref('urlbar.loadDifferentDomainToNewTab', value); this.clearTreePref('urlbar.loadSameDomainToNewChildTab'); } case 3: if (this.getTreePref('loadDroppedLinkToNewChildTab') !== null) { this.setTreePref('dropLinksOnTab.behavior', this.getTreePref('loadDroppedLinkToNewChildTab.confirm') ? this.kDROPLINK_ASK : this.getTreePref('loadDroppedLinkToNewChildTab') ? this.kDROPLINK_NEWTAB : this.kDROPLINK_LOAD ); this.clearTreePref('loadDroppedLinkToNewChildTab.confirm'); this.clearTreePref('loadDroppedLinkToNewChildTab'); } if (this.getTreePref('openGroupBookmarkAsTabSubTree') !== null) { let behavior = 0; if (this.getTreePref('openGroupBookmarkAsTabSubTree.underParent')) behavior += this.kGROUP_BOOKMARK_USE_DUMMY; if (!this.getTreePref('openGroupBookmarkBehavior.confirm')) { behavior += ( this.getTreePref('openGroupBookmarkAsTabSubTree') ? this.kGROUP_BOOKMARK_SUBTREE : this.getTreePref('browser.tabs.loadFolderAndReplace') ? this.kGROUP_BOOKMARK_REPLACE : this.kGROUP_BOOKMARK_SEPARATE ); } this.setTreePref('openGroupBookmark.behavior', behavior); this.clearTreePref('openGroupBookmarkBehavior.confirm'); this.clearTreePref('openGroupBookmarkAsTabSubTree'); this.clearTreePref('openGroupBookmarkAsTabSubTree.underParent'); this.setPref('browser.tabs.loadFolderAndReplace', behavior & this.kGROUP_BOOKMARK_REPLACE ? true : false ); } case 4: [ 'extensions.treestyletab.autoCollapseExpandSubTreeOnSelect', 'extensions.treestyletab.autoCollapseExpandSubTreeOnSelect.onCurrentTabRemove', 'extensions.treestyletab.autoCollapseExpandSubTreeOnSelect.whileFocusMovingByShortcut', 'extensions.treestyletab.autoExpandSubTreeOnAppendChild', 'extensions.treestyletab.autoExpandSubTreeOnCollapsedChildFocused', 'extensions.treestyletab.collapseExpandSubTree.dblclick', 'extensions.treestyletab.createSubTree.underParent', 'extensions.treestyletab.show.context-item-reloadTabSubTree', 'extensions.treestyletab.show.context-item-removeTabSubTree', 'extensions.treestyletab.show.context-item-bookmarkTabSubTree', 'extensions.multipletab.show.multipletab-selection-item-removeTabSubTree', 'extensions.multipletab.show.multipletab-selection-item-createSubTree' ].forEach(function(aPref) { var value = this.getPref(aPref); if (value === null) return; this.setPref(aPref.replace('SubTree', 'Subtree'), value); this.clearPref(aPref); }, this); case 5: let (behavior = this.getTreePref('openGroupBookmark.behavior')) { behavior = behavior | 2048; this.setTreePref('openGroupBookmark.behavior', behavior); } default: orientalPrefs.forEach(function(aPref) { let value = this.getPref(aPref); if (value === null) return; this.setPref(aPref+'.horizontal', value); this.setPref(aPref+'.vertical', value); this.clearPref(aPref); }, this); break; } this.setTreePref('prefsVersion', this.kPREF_VERSION); }, init : function TSTService_init() { if (!('gBrowser' in window)) return; if (this.initialized) return; this.initialized = true; if (!this.preInitialized) { this.preInit(); } window.removeEventListener('SSTabRestoring', this, true); window.removeEventListener('load', this, false); window.addEventListener('unload', this, false); document.addEventListener('popupshowing', this, false); document.addEventListener('popuphiding', this, true); document.addEventListener(this.kEVENT_TYPE_TAB_COLLAPSED_STATE_CHANGED, this, false); document.addEventListener(this.kEVENT_TYPE_TABBAR_POSITION_CHANGED, this, false); document.addEventListener(this.kEVENT_TYPE_TABBAR_STATE_CHANGED, this, false); document.addEventListener(this.kEVENT_TYPE_FOCUS_NEXT_TAB, this, false); var appcontent = document.getElementById('appcontent'); appcontent.addEventListener('SubBrowserAdded', this, false); appcontent.addEventListener('SubBrowserRemoveRequest', this, false); window.addEventListener('UIOperationHistoryUndo:TabbarOperations', this, false); window.addEventListener('UIOperationHistoryRedo:TabbarOperations', this, false); this.addPrefListener(this); this.initUninstallationListener(); this.overrideExtensionsOnInitBefore(); // hacks.js this.overrideGlobalFunctions(); this.initTabBrowser(gBrowser); this.overrideExtensionsOnInitAfter(); // hacks.js this.processRestoredTabs(); this.updateTabsOnTop(); this.onPrefChange('extensions.treestyletab.tabbar.autoHide.mode'); this.onPrefChange('extensions.treestyletab.tabbar.style'); this.onPrefChange('extensions.treestyletab.autoCollapseExpandSubtreeOnSelect.whileFocusMovingByShortcut'); }, initialized : false, initUninstallationListener : function TSTService_initUninstallationListener() { var namespace = {}; Components.utils.import( 'resource://treestyletab-modules/lib/prefs.js', namespace ); var prefs = namespace.prefs; namespace = void(0); var restorePrefs = function() { if (!prefs) return; [ 'browser.tabs.loadFolderAndReplace', 'browser.tabs.insertRelatedAfterCurrent', 'extensions.stm.tabBarMultiRows' // Super Tab Mode ].forEach(function(aPref) { var backup = prefs.getPref(aPref+'.backup'); if (backup === null) return; prefs.setPref(aPref+'.override', backup); // we have to set to ".override" pref, to avoid unexpectedly reset by the preference listener. prefs.clearPref(aPref+'.backup'); }); }; new window['piro.sakura.ne.jp'].UninstallationListener({ id : 'treestyletab@piro.sakura.ne.jp', onuninstalled : restorePrefs, ondisabled : restorePrefs }); }, initTabBrowser : function TSTService_initTabBrowser(aTabBrowser) { if (aTabBrowser.localName != 'tabbrowser') return; aTabBrowser.treeStyleTab = new TreeStyleTabBrowser(aTabBrowser); aTabBrowser.treeStyleTab.init(); }, updateTabDNDObserver : function TSTService_updateTabDNDObserver(aObserver) { var strip = this.getTabStrip(aObserver) || gBrowser.mStrip // fallback to the default strip, for Tab Mix Plus; if (aObserver.tabContainer && aObserver.tabContainer.tabbrowser == aObserver) { // Firefox 4.0 or later aObserver = aObserver.tabContainer; } if ('_setEffectAllowedForDataTransfer' in aObserver) { eval('aObserver._setEffectAllowedForDataTransfer = '+ aObserver._setEffectAllowedForDataTransfer.toSource().replace( '{', '{ var TSTTabBrowser = this;' ).replace( /\.screenX/g, '[TreeStyleTabService.getTabBrowserFromChild(TSTTabBrowser).treeStyleTab.positionProp]' ).replace( /\.width/g, '[TreeStyleTabService.getTabBrowserFromChild(TSTTabBrowser).treeStyleTab.sizeProp]' ).replace( /(return (?:true|dt.effectAllowed = "copyMove");)/, ).replace( 'sourceNode.parentNode == this &&', '$& TSTTabBrowser.treeStyleTab.getTabFromEvent(event) == sourceNode &&' ) ); } }, overrideGlobalFunctions : function TSTService_overrideGlobalFunctions() { window.__treestyletab__BrowserCustomizeToolbar = window.BrowserCustomizeToolbar; window.BrowserCustomizeToolbar = function() { TreeStyleTabService.destroyToolbarItems(); window.__treestyletab__BrowserCustomizeToolbar.call(window); }; let (toolbox) { toolbox = document.getElementById('navigator-toolbox'); if (toolbox.customizeDone) { toolbox.__treestyletab__customizeDone = toolbox.customizeDone; toolbox.customizeDone = function(aChanged) { this.__treestyletab__customizeDone(aChanged); TreeStyleTabService.initToolbarItems(); }; } if ('BrowserToolboxCustomizeDone' in window) { window.__treestyletab__BrowserToolboxCustomizeDone = window.BrowserToolboxCustomizeDone; window.BrowserToolboxCustomizeDone = function(aChanged) { window.__treestyletab__BrowserToolboxCustomizeDone.apply(window, arguments); TreeStyleTabService.initToolbarItems(); }; } this.initToolbarItems(); toolbox = null; } eval('nsContextMenu.prototype.openLinkInTab = '+ nsContextMenu.prototype.openLinkInTab.toSource().replace( '{', ) ); eval('nsContextMenu.prototype.openFrameInTab = '+ nsContextMenu.prototype.openFrameInTab.toSource().replace( '{', ) ); var viewImageMethod = ('viewImage' in nsContextMenu.prototype) ? 'viewImage' : 'viewMedia' ; eval('nsContextMenu.prototype.'+viewImageMethod+' = '+ nsContextMenu.prototype[viewImageMethod].toSource().replace( 'openUILink(', ) ); eval('nsContextMenu.prototype.viewBGImage = '+ nsContextMenu.prototype.viewBGImage.toSource().replace( 'openUILink(', ) ); eval('nsContextMenu.prototype.addDictionaries = '+ nsContextMenu.prototype.addDictionaries.toSource().replace( 'openUILinkIn(', ) ); this._splitFunctionNames().some(function(aFunc) { let source = this._getFunctionSource(aFunc); if (!source || !/^\(?function handleLinkClick/.test(source)) return false; eval(aFunc+' = '+source.replace( // for Firefox 3.5 - Firefox 3.6 /(openNewTabWith\()/g, ).replace( // for Firefox 4.0- /(charset\s*:\s*doc\.characterSet\s*)/, '$1, event : event, linkNode : linkNode' )); source = null; return true; }, this); // for Firefox 4.0- if ('openLinkIn' in window) { eval('window.openLinkIn = '+ window.openLinkIn.toSource().replace( 'browser.loadOneTab(', .toString() ) ); } this._splitFunctionNames().forEach(function(aFunc) { let source = this._getFunctionSource(aFunc); if (!source || !/^\(?function contentAreaClick/.test(source)) return; eval(aFunc+' = '+source.replace( // for Tab Utilities, etc. Some addons insert openNewTabWith() to the function. // (calls for the function is not included by Firefox default.) /(openNewTabWith\()/g, )); source = null; }, this); this._splitFunctionNames().forEach(function(aFunc) { let source = this._getFunctionSource(aFunc); if (!source || !/^\(?function (gotoHistoryIndex|BrowserForward|BrowserBack)/.test(source)) return; eval(aFunc+' = '+source.replace( /((?:openUILinkIn|duplicateTabIn)\()/g, )); source = null; }, this); this._splitFunctionNames().forEach(function(aFunc) { let source = this._getFunctionSource(aFunc); if (!source || !/^\(?function (BrowserHomeClick|BrowserGoHome)/.test(source)) return; eval(aFunc+' = '+source.replace( 'gBrowser.loadTabs(', )); source = null; }, this); eval('FeedHandler.loadFeed = '+ FeedHandler.loadFeed.toSource().replace( 'openUILink(', ) ); // Firefox 3 full screen eval('FullScreen._animateUp = '+ FullScreen._animateUp.toSource().replace( // Firefox 3.6 or older /(gBrowser\.mStrip\.boxObject\.height)/, '((gBrowser.treeStyleTab.currentTabbarPosition != "top") ? 0 : $1)' ) ); eval('FullScreen.mouseoverToggle = '+ FullScreen.mouseoverToggle.toSource().replace( // Firefox 4.0 or later 'this._isChromeCollapsed = !aShow;', 'gBrowser.treeStyleTab.updateFloatingTabbar(gBrowser.treeStyleTab.kTABBAR_UPDATE_BY_FULLSCREEN); $&' ).replace( // Firefox 3.6 or older 'gBrowser.mStrip.setAttribute("moz-collapsed", !aShow);', 'if (gBrowser.treeStyleTab.currentTabbarPosition == "top") { $& }' ) ); eval('FullScreen.toggle = '+ FullScreen.toggle.toSource().replace( '{', ) ); if ('PrintUtils' in window) { eval('PrintUtils.printPreview = '+PrintUtils.printPreview.toSource().replace( '{', '{ TreeStyleTabService.onPrintPreviewEnter();' )); eval('PrintUtils.exitPrintPreview = '+PrintUtils.exitPrintPreview.toSource().replace( '{', '{ TreeStyleTabService.onPrintPreviewExit();' )); } if ('TabsOnTop' in window && TabsOnTop.syncCommand) { eval('TabsOnTop.syncCommand = '+TabsOnTop.syncCommand.toSource().replace( /(\}\)?)$/, 'gBrowser.treeStyleTab.onTabsOnTopSyncCommand(enabled); $&' )); } if ('toggleSidebar' in window) { eval('window.toggleSidebar = '+ window.toggleSidebar.toSource().replace( '{', '{ gBrowser.treeStyleTab.updateFloatingTabbar(gBrowser.treeStyleTab.kTABBAR_UPDATE_BY_WINDOW_RESIZE);' ) ); } }, _splitFunctionNames : function TSTService__splitFunctionNames(aString) { return String(aString) .split(/\s+/) .map(function(aString) { return aString .replace(/\/\*.*\*\//g, '') .replace(/\/\/.+$/, '') .replace(/^\s+|\s+$/g, ''); }); }, _getFunctionSource : function TSTService__getFunctionSource(aFunc) { var func; try { eval('func = '+aFunc); } catch(e) { return null; } return func ? func.toSource() : null ; }, initToolbarItems : function TSTService_initToolbarItems() { var searchbar = document.getElementById('searchbar'); if (searchbar && searchbar.doSearch && searchbar.doSearch.toSource().toSource().indexOf('TreeStyleTabService') < 0) { eval('searchbar.doSearch = '+searchbar.doSearch.toSource().replace( /(openUILinkIn\(.+?\);)/, .toString() )); } // for Firefox 4.0 or later this.updateAllTabsButton(gBrowser); }, destroyToolbarItems : function TSTService_destroyToolbarItems() { // Firefox 4.0 or later (restore original position) var allTabsButton = document.getElementById('alltabs-button'); if (allTabsButton && allTabsButton.hasChildNodes()) allTabsButton.firstChild.setAttribute('position', 'after_end'); }, updateAllTabsButton : function TSTService_updateAllTabsButton(aTabBrowser) { aTabBrowser = aTabBrowser || this.browser; var allTabsButton = document.getElementById('alltabs-button') || // Firefox 4.0 or later document.getAnonymousElementByAttribute(aTabBrowser.mTabContainer, 'class', 'tabs-alltabs-button') || // Firefox 3.6 or older ( // Tab Mix Plus this.getTreePref('compatibility.TMP') && document.getAnonymousElementByAttribute(aTabBrowser.mTabContainer, 'anonid', 'alltabs-button') ); if (allTabsButton && allTabsButton.hasChildNodes() && aTabBrowser.treeStyleTab) allTabsButton.firstChild.setAttribute('position', aTabBrowser.treeStyleTab.isVertical ? 'before_start' : 'after_end' ); }, updateAllTabsPopup : function TSTService_updateAllTabsPopup(aEvent) { if (!this.getTreePref('enableSubtreeIndent.allTabsPopup')) return; var items = Array.slice(aEvent.originalTarget.childNodes); var firstItemIndex = 0; // ignore menu items inserted by Weave (Firefox Sync), Tab Utilities, and others. items.forEach(function(aItem, aIndex) { if ( aItem.getAttribute('anonid') || aItem.id || aItem.hidden || aItem.localName != 'menuitem' ) firstItemIndex = aIndex + 1; }); items = items.slice(firstItemIndex); var b = this.getTabBrowserFromChild(aEvent.originalTarget) || gBrowser; this.getTabsArray(b).forEach(function(aTab, aIndex) { items[aIndex].style.paddingLeft = aTab.getAttribute(this.kNEST)+'em'; }, this); }, destroy : function TSTService_destroy() { this.utils.inWindowDestoructionProcess = true; try { window.removeEventListener('unload', this, false); gBrowser.treeStyleTab.saveCurrentState(); this.destroyTabBrowser(gBrowser); this.endListenKeyEventsFor(this.LISTEN_FOR_AUTOHIDE); this.endListenKeyEventsFor(this.LISTEN_FOR_AUTOEXPAND_BY_FOCUSCHANGE); document.removeEventListener('popupshowing', this, false); document.removeEventListener('popuphiding', this, true); document.removeEventListener(this.kEVENT_TYPE_TAB_COLLAPSED_STATE_CHANGED, this, false); document.removeEventListener(this.kEVENT_TYPE_TABBAR_POSITION_CHANGED, this, false); document.removeEventListener(this.kEVENT_TYPE_TABBAR_STATE_CHANGED, this, false); document.removeEventListener(this.kEVENT_TYPE_FOCUS_NEXT_TAB, this, false); this._tabFocusAllowance.forEach(function(aListener) { window.removeEventListener(this.kEVENT_TYPE_FOCUS_NEXT_TAB, aListener, false); }, this); var appcontent = document.getElementById('appcontent'); appcontent.removeEventListener('SubBrowserAdded', this, false); appcontent.removeEventListener('SubBrowserRemoveRequest', this, false); window.removeEventListener('UIOperationHistoryUndo:TabbarOperations', this, false); window.removeEventListener('UIOperationHistoryRedo:TabbarOperations', this, false); this.removePrefListener(this); this.ObserverService.removeObserver(this, 'sessionstore-windows-restored'); } catch(e) { throw e; } finally { this.utils.inWindowDestoructionProcess = false; } }, destroyTabBrowser : function TSTService_destroyTabBrowser(aTabBrowser) { if (aTabBrowser.localName != 'tabbrowser') return; aTabBrowser.treeStyleTab.destroy(); delete aTabBrowser.treeStyleTab; }, /* Event Handling */ handleEvent : function TSTService_handleEvent(aEvent) { switch (aEvent.type) { case 'DOMContentLoaded': return this.preInit(); case 'load': return this.init(); case 'unload': return this.destroy(); case 'SSTabRestoring': return this.onTabRestored(aEvent); case 'popupshowing': this.onPopupShown(aEvent.originalTarget); if ((aEvent.originalTarget.getAttribute('anonid') || aEvent.originalTarget.id) == 'alltabs-popup') this.updateAllTabsPopup(aEvent); return; case 'popuphiding': return this.onPopupHidden(aEvent.originalTarget); case this.kEVENT_TYPE_TAB_COLLAPSED_STATE_CHANGED: return this.updateAeroPeekPreviews(); case this.kEVENT_TYPE_TABBAR_POSITION_CHANGED: case this.kEVENT_TYPE_TABBAR_STATE_CHANGED: return this.updateTabsOnTop(); case this.kEVENT_TYPE_FOCUS_NEXT_TAB: return this.onFocusNextTab(aEvent); case 'keydown': return this.onKeyDown(aEvent); case 'keyup': case 'keypress': return this.onKeyRelease(aEvent); case 'mousedown': return this.onTabbarResizeStart(aEvent); case 'mouseup': return this.onTabbarResizeEnd(aEvent); case 'mousemove': return this.onTabbarResizing(aEvent); case 'dblclick': return this.onTabbarReset(aEvent); case 'SubBrowserAdded': return this.initTabBrowser(aEvent.originalTarget.browser); case 'SubBrowserRemoveRequest': return this.destroyTabBrowser(aEvent.originalTarget.browser); case 'UIOperationHistoryUndo:TabbarOperations': switch (aEvent.entry.name) { case 'treestyletab-changeTabbarPosition': this.currentTabbarPosition = aEvent.entry.data.oldPosition; return; } return; case 'UIOperationHistoryRedo:TabbarOperations': switch (aEvent.entry.name) { case 'treestyletab-changeTabbarPosition': this.currentTabbarPosition = aEvent.entry.data.newPosition; return; } return; } }, keyEventListening : false, keyEventListeningFlags : 0, LISTEN_FOR_AUTOHIDE : 1, LISTEN_FOR_AUTOEXPAND_BY_FOCUSCHANGE : 2, startListenKeyEventsFor : function TSTService_startListenKeyEventsFor(aReason) { if (this.keyEventListeningFlags & aReason) return; if (!this.keyEventListening) { window.addEventListener('keydown', this, true); window.addEventListener('keyup', this, true); window.addEventListener('keypress', this, true); this.keyEventListening = true; } this.keyEventListeningFlags |= aReason; }, endListenKeyEventsFor : function TSTService_endListenKeyEventsFor(aReason) { if (!(this.keyEventListeningFlags & aReason)) return; this.keyEventListeningFlags ^= aReason; if (!this.keyEventListeningFlags && this.keyEventListening) { window.removeEventListener('keydown', this, true); window.removeEventListener('keyup', this, true); window.removeEventListener('keypress', this, true); this.keyEventListening = false; } }, onKeyDown : function TSTService_onKeyDown(aEvent) { /** * On Mac OS X, default accel key is the Command key (metaKey), but * Cmd-Tab is used to switch applications by the OS itself. So Firefox * uses Ctrl-Tab to switch tabs on all platforms. */ // this.accelKeyPressed = this.isAccelKeyPressed(aEvent); this.accelKeyPressed = aEvent.ctrlKey || aEvent.keyCode == Ci.nsIDOMKeyEvent.DOM_VK_CONTROL; /* PUBLIC API */ var b = this.browser; var event = b.ownerDocument.createEvent('Events'); event.initEvent(this.kEVENT_TYPE_TAB_FOCUS_SWITCHING_KEY_DOWN, true, false); event.sourceEvent = aEvent; b.dispatchEvent(event); // for backward compatibility event = b.ownerDocument.createEvent('Events'); event.initEvent(this.kEVENT_TYPE_TAB_FOCUS_SWITCHING_KEY_DOWN.replace(/^nsDOM/, ''), true, false); event.sourceEvent = aEvent; b.dispatchEvent(event); }, accelKeyPressed : false, onKeyRelease : function TSTService_onKeyRelease(aEvent) { var b = this.browser; if (!b || !b.treeStyleTab) return; var sv = b.treeStyleTab; var scrollDown, scrollUp; // this.accelKeyPressed = this.isAccelKeyPressed(aEvent); this.accelKeyPressed = aEvent.ctrlKey || aEvent.keyCode == Ci.nsIDOMKeyEvent.DOM_VK_CONTROL; var standBy = scrollDown = scrollUp = (!aEvent.altKey && this.accelKeyPressed); scrollDown = scrollDown && ( !aEvent.shiftKey && ( aEvent.keyCode == aEvent.DOM_VK_TAB || aEvent.keyCode == aEvent.DOM_VK_PAGE_DOWN ) ); scrollUp = scrollUp && ( aEvent.shiftKey ? (aEvent.keyCode == aEvent.DOM_VK_TAB) : (aEvent.keyCode == aEvent.DOM_VK_PAGE_UP) ); var onlyShiftKey = (!aEvent.shiftKey && aEvent.keyCode == 16 && (aEvent.type == 'keyup' || aEvent.charCode == 0)); if ( scrollDown || scrollUp || ( // when you release "shift" key standBy && onlyShiftKey ) ) { /* PUBLIC API */ let event = b.ownerDocument.createEvent('Events'); event.initEvent(this.kEVENT_TYPE_TAB_FOCUS_SWITCHING_START, true, false); event.scrollDown = scrollDown; event.scrollUp = scrollUp; event.standBy = standBy; event.onlyShiftKey = onlyShiftKey; event.sourceEvent = aEvent; b.dispatchEvent(event); // for backward compatibility event = b.ownerDocument.createEvent('Events'); event.initEvent(this.kEVENT_TYPE_TAB_FOCUS_SWITCHING_START.replace(/^nsDOM/, ''), true, false); event.scrollDown = scrollDown; event.scrollUp = scrollUp; event.standBy = standBy; event.onlyShiftKey = onlyShiftKey; event.sourceEvent = aEvent; b.dispatchEvent(event); return; } // when you just release accel key... /* PUBLIC API */ let (event) { event = document.createEvent('Events'); event.initEvent(this.kEVENT_TYPE_TAB_FOCUS_SWITCHING_END, true, false); event.scrollDown = scrollDown; event.scrollUp = scrollUp; event.standBy = standBy; event.onlyShiftKey = onlyShiftKey; event.sourceEvent = aEvent; b.dispatchEvent(event); // for backward compatibility event = document.createEvent('Events'); event.initEvent(this.kEVENT_TYPE_TAB_FOCUS_SWITCHING_END.replace(/^nsDOM/, ''), true, false); event.scrollDown = scrollDown; event.scrollUp = scrollUp; event.standBy = standBy; event.onlyShiftKey = onlyShiftKey; event.sourceEvent = aEvent; b.dispatchEvent(event); } if (this._tabShouldBeExpandedAfterKeyReleased) { let tab = this._tabShouldBeExpandedAfterKeyReleased; if (this.hasChildTabs(tab) && this.isSubtreeCollapsed(tab)) { this.getTabBrowserFromChild(tab) .treeStyleTab .collapseExpandTreesIntelligentlyFor(tab); } } this._tabShouldBeExpandedAfterKeyReleased = null; }, get shouldListenKeyEventsForAutoExpandByFocusChange() { return !this.ctrlTabPreviewsEnabled && !this.getTreePref('autoCollapseExpandSubtreeOnSelect.whileFocusMovingByShortcut') && this.getTreePref('autoCollapseExpandSubtreeOnSelect'); }, get ctrlTabPreviewsEnabled() { return 'allTabs' in window && this.getPref('browser.ctrlTab.previews'); }, onTabbarResizeStart : function TSTService_onTabbarResizeStart(aEvent) { if (this.isEventFiredOnGrippy(aEvent)) return; aEvent.stopPropagation(); if ('setCapture' in aEvent.currentTarget) aEvent.currentTarget.setCapture(true); aEvent.currentTarget.addEventListener('mousemove', this, false); var b = this.getTabBrowserFromChild(aEvent.currentTarget); var box = aEvent.currentTarget.id == 'treestyletab-tabbar-resizer-splitter' ? this.getTabStrip(b) : b.treeStyleTab.tabStripPlaceHolder || b.tabContainer ; this.tabbarResizeStartWidth = box.boxObject.width; this.tabbarResizeStartHeight = box.boxObject.height; this.tabbarResizeStartX = aEvent.screenX; this.tabbarResizeStartY = aEvent.screenY; }, onTabbarResizeEnd : function TSTService_onTabbarResizeEnd(aEvent) { if (this.tabbarResizeStartWidth < 0) return; aEvent.stopPropagation(); if ('releaseCapture' in aEvent.currentTarget) aEvent.currentTarget.releaseCapture(); aEvent.currentTarget.removeEventListener('mousemove', this, false); this.tabbarResizeStartWidth = -1; this.tabbarResizeStartHeight = -1; this.tabbarResizeStartX = -1; this.tabbarResizeStartY = -1; var b = this.getTabBrowserFromChild(aEvent.currentTarget); }, onTabbarResizing : function TSTService_onTabbarResizing(aEvent) { var target = aEvent.currentTarget; var b = this.getTabBrowserFromChild(target); var expanded = target.id == 'treestyletab-tabbar-resizer-splitter'; if (expanded) aEvent.stopPropagation(); var width = this.tabbarResizeStartWidth; var height = this.tabbarResizeStartHeight; var pos = b.treeStyleTab.currentTabbarPosition; if (b.treeStyleTab.isVertical) { let delta = aEvent.screenX - this.tabbarResizeStartX; width += (pos == 'left' ? delta : -delta ); width = this.maxTabbarWidth(width, b); if (expanded || b.treeStyleTab.autoHide.expanded) { this.setTreePref('tabbar.width', width); if (b.treeStyleTab.autoHide.mode == b.treeStyleTab.autoHide.kMODE_SHRINK && b.treeStyleTab.tabStripPlaceHolder) b.treeStyleTab.tabStripPlaceHolder.setAttribute('width', this.getTreePref('tabbar.shrunkenWidth')); } else { this.setTreePref('tabbar.shrunkenWidth', width); } } else { let delta = aEvent.screenY - this.tabbarResizeStartY; height += (pos == 'top' ? delta : -delta ); this.setTreePref('tabbar.height', this.maxTabbarHeight(height, b)); } b.treeStyleTab.updateFloatingTabbar(this.kTABBAR_UPDATE_BY_TABBAR_RESIZE); }, tabbarResizeStartWidth : -1, tabbarResizeStartHeight : -1, tabbarResizeStartX : -1, tabbarResizeStartY : -1, onTabbarReset : function TSTService_onTabbarReset(aEvent) { var b = this.getTabBrowserFromChild(aEvent.currentTarget); if (b) { b.treeStyleTab.resetTabbarSize(); aEvent.stopPropagation(); } }, onFocusNextTab : function TSTService_onFocusNextTab(aEvent) { var tab = aEvent.target.selectedTab; if ( this.getPref('browser.tabs.selectOwnerOnClose') && tab.owner && ( !aEvent.target._removingTabs || aEvent.target._removingTabs.indexOf(tab.owner) < 0 ) ) aEvent.preventDefault(); }, showHideSubtreeMenuItem : function TSTService_showHideSubtreeMenuItem(aMenuItem, aTabs) { if (!aMenuItem || aMenuItem.getAttribute('hidden') == 'true' || !aTabs || !aTabs.length) return; var hasSubtree = false; for (var i = 0, maxi = aTabs.length; i < maxi; i++) { if (!this.hasChildTabs(aTabs[i])) continue; hasSubtree = true; break; } if (hasSubtree) aMenuItem.removeAttribute('hidden'); else aMenuItem.setAttribute('hidden', true); }, showHideSubTreeMenuItem : function() { return this.showHideSubtreeMenuItem.apply(this, arguments); }, // obsolete, for backward compatibility updateAeroPeekPreviews : function TSTService_updateAeroPeekPreviews() { if ( this.updateAeroPeekPreviewsTimer || !this.getPref('browser.taskbar.previews.enable') || !this.getTreePref('taskbarPreviews.hideCollapsedTabs') || !('Win7Features' in window) || !window.Win7Features || !this.AeroPeek || !this.AeroPeek.windows ) return; this.updateAeroPeekPreviewsTimer = window.setTimeout(function(aSelf) { aSelf.updateAeroPeekPreviewsTimer = null; try { aSelf.updateAeroPeekPreviewsInternal(); } catch(e) { dump(e+'\n'); aSelf.updateAeroPeekPreviews(); } }, 250, this); }, updateAeroPeekPreviewsTimer : null, updateAeroPeekPreviewsInternal : function TSTService_updateAeroPeekPreviewsInternal() { if ( !this.getPref('browser.taskbar.previews.enable') || !this.getTreePref('taskbarPreviews.hideCollapsedTabs') ) return; this.AeroPeek.windows.some(function(aTabWindow) { if (aTabWindow.win == window) { aTabWindow.previews.forEach(function(aPreview) { if (!aPreview) return; var tab = aPreview.controller.wrappedJSObject.tab; aPreview.visible = !this.isCollapsed(tab); }, this); this.AeroPeek.checkPreviewCount(); return true; } return false; }, this); }, updateTabsOnTop : function TSTService_updateTabsOnTop() { if (!('TabsOnTop' in window) || !('enabled' in TabsOnTop)) return; if (!('_tabsOnTopDefaultState' in this)) this._tabsOnTopDefaultState = TabsOnTop.enabled; if (gBrowser.treeStyleTab.currentTabbarPosition != 'top' || !gBrowser.treeStyleTab.isFixed) { if (TabsOnTop.enabled) TabsOnTop.enabled = false; } else if ('_tabsOnTopDefaultState' in this) { if (TabsOnTop.enabled!= this._tabsOnTopDefaultState) TabsOnTop.enabled = this._tabsOnTopDefaultState; delete this._tabsOnTopDefaultState; } }, onPopupShown : function TSTService_onPopupShown(aPopup) { if (!aPopup.boxObject || this.evaluateXPath( 'local-name() = "tooltip" or local-name() ="panel" or '+ 'parent::*/ancestor-or-self::*[local-name()="popup" or local-name()="menupopup"]', aPopup, XPathResult.BOOLEAN_TYPE ).booleanValue) return; window.setTimeout(function(aSelf) { if ((!aPopup.boxObject.width && !aPopup.boxObject.height) || aPopup.boxObject.popupState == 'closed') return; var id = aPopup.id; var item = id && document.getElementById(id) ? id : aPopup ; var index = TreeStyleTabService._shownPopups.indexOf(item); if (index < 0) TreeStyleTabService._shownPopups.push(item); }, 10, this); }, onPopupHidden : function TSTService_onPopupHidden(aPopup) { var id = aPopup.id; aPopup = id && document.getElementById(id) ? id : aPopup ; var index = TreeStyleTabService._shownPopups.indexOf(aPopup); if (index > -1) TreeStyleTabService._shownPopups.splice(index, 1); }, isPopupShown : function TSTService_isPopupShown() { TreeStyleTabService._shownPopups = TreeStyleTabService._shownPopups.filter(function(aItem) { if (typeof aItem == 'string') aItem = document.getElementById(aItem); return aItem && aItem.boxObject && ((aItem.boxObject.width || aItem.boxObject.height) && aItem.state != 'closed'); }); return TreeStyleTabService._shownPopups.length > 0; }, _shownPopups : [], /* Tree Style Tabの初期化が行われる前に復元されたセッションについてツリー構造を復元 */ _restoringTabs : [], onTabRestored : function TSTService_onTabRestored(aEvent) { this._restoringTabs.push(aEvent.originalTarget); }, processRestoredTabs : function TSTService_processRestoredTabs() { this._restoringTabs.forEach(function(aTab) { try { var b = this.getTabBrowserFromChild(aTab); if (b) b.treeStyleTab.restoreStructure(aTab, true); } catch(e) { } }, this); this._restoringTabs = []; }, /* Commands */ setTabbarWidth : function TSTService_setTabbarWidth(aWidth, aForceExpanded) /* PUBLIC API */ { gBrowser.treeStyleTab.autoHide.setWidth(aWidth, aForceExpanded); }, setContentWidth : function TSTService_setContentWidth(aWidth, aKeepWindowSize) /* PUBLIC API */ { var treeStyleTab = gBrowser.treeStyleTab; var strip = treeStyleTab.tabStrip; var tabbarWidth = treeStyleTab.splitterWidth + (treeStyleTab.isVertical ? strip.boxObject.width : 0 ); var contentWidth = gBrowser.boxObject.width - tabbarWidth; if (aKeepWindowSize || window.fullScreen || window.windowState != Components.interfaces.nsIDOMChromeWindow.STATE_NORMAL) { this.setTabbarWidth(Math.max(10, gBrowser.boxObject.width - aWidth)); } else if (tabbarWidth + aWidth <= screen.availWidth) { window.resizeBy(aWidth - contentWidth, 0); } else { window.resizeBy(screen.availWidth - window.outerWidth, 0); this.setTabbarWidth(gBrowser.boxObject.width - aWidth); } }, get autoHideWindow() { if (!this._autoHideWindow) { let ns = {}; Components.utils.import('resource://treestyletab-modules/autoHide.js', ns); this._autoHideWindow = new ns.AutoHideWindow(window); } return this._autoHideWindow; }, toggleAutoHide : function TSTService_toggleAutoHide(aTabBrowser) /* PUBLIC API, for backward compatibility */ { this.autoHideWindow.toggleMode(aTabBrowser || this.browser); }, toggleFixed : function TSTService_toggleFixed(aTabBrowser) /* PUBLIC API */ { var b = aTabBrowser || this.browser; var orient = b.treeStyleTab.isVertical ? 'vertical' : 'horizontal' ; var newFixed = b.getAttribute(this.kFIXED+'-'+orient) != 'true'; this.setTabbrowserAttribute(this.kFIXED+'-'+orient, newFixed ? 'true' : null, b); this.setTreePref('tabbar.fixed.'+orient, newFixed); b.treeStyleTab.updateTabbarState(); }, removeTabSubtree : function TSTService_removeTabSubtree(aTabOrTabs, aOnlyChildren) { var tabs = this.gatherSubtreeMemberTabs(aTabOrTabs, aOnlyChildren); if (!this.warnAboutClosingTabs(tabs.length)) return; if (aOnlyChildren) tabs = this.gatherSubtreeMemberTabs(aTabOrTabs); this.splitTabsToSubtrees(tabs).forEach(function(aTabs) { if (!this.fireTabSubtreeClosingEvent(aTabs[0], aTabs)) return; var b = this.getTabBrowserFromChild(aTabs[0]); if (aOnlyChildren) aTabs = aTabs.slice(1); if (!aTabs.length) return; this.stopRendering(); this.markAsClosedSet(aTabs); for (var i = aTabs.length-1; i > -1; i--) { b.removeTab(aTabs[i], { animate : true }); } this.startRendering(); this.fireTabSubtreeClosedEvent(b, aTabs[0], aTabs) }, this); }, removeTabSubTree : function() { return this.removeTabSubtree.apply(this, arguments); }, // obsolete, for backward compatibility fireTabSubtreeClosingEvent : function TSTService_fireTabSubtreeClosingEvent(aParentTab, aClosedTabs) { /* PUBLIC API */ var event = aParentTab.ownerDocument.createEvent('Events'); event.initEvent(this.kEVENT_TYPE_SUBTREE_CLOSING, true, true); event.parent = aParentTab; event.tabs = aClosedTabs; var canClose = this.getTabBrowserFromChild(aParentTab).dispatchEvent(event); // for backward compatibility event = aParentTab.ownerDocument.createEvent('Events'); event.initEvent(this.kEVENT_TYPE_SUBTREE_CLOSING.replace(/^nsDOM/, ''), true, true); event.parent = aParentTab; event.tabs = aClosedTabs; canClose = canClose && this.getTabBrowserFromChild(aParentTab).dispatchEvent(event); return canClose; }, fireTabSubtreeClosedEvent : function TSTService_fireTabSubtreeClosedEvent(aTabBrowser, aParentTab, aClosedTabs) { aClosedTabs = aClosedTabs.filter(function(aTab) { return !aTab.parentNode; }); /* PUBLIC API */ var event = aTabBrowser.ownerDocument.createEvent('Events'); event.initEvent(this.kEVENT_TYPE_SUBTREE_CLOSED, true, false); event.parent = aParentTab; event.tabs = aClosedTabs; aTabBrowser.dispatchEvent(event); // for backward compatibility event = aTabBrowser.ownerDocument.createEvent('Events'); event.initEvent(this.kEVENT_TYPE_SUBTREE_CLOSED.replace(/^nsDOM/, ''), true, false); event.parent = aParentTab; event.tabs = aClosedTabs; aTabBrowser.dispatchEvent(event); }, warnAboutClosingTabSubtreeOf : function TSTService_warnAboutClosingTabSubtreeOf(aTab) { if (!this.shouldCloseTabSubtreeOf(aTab)) return true; var tabs = [aTab].concat(this.getDescendantTabs(aTab)); return this.warnAboutClosingTabs(tabs.length); }, warnAboutClosingTabSubTreeOf : function() { return this.warnAboutClosingTabSubtreeOf.apply(this, arguments); }, // obsolete, for backward compatibility warnAboutClosingTabs : function TSTService_warnAboutClosingTabs(aTabsCount) { if ( aTabsCount <= 1 || !this.getPref('browser.tabs.warnOnClose') ) return true; var checked = { value:true }; window.focus(); var shouldClose = this.PromptService.confirmEx(window, this.tabbrowserBundle.getString('tabs.closeWarningTitle'), this.tabbrowserBundle.getFormattedString('tabs.closeWarningMultipleTabs', [aTabsCount]), (this.PromptService.BUTTON_TITLE_IS_STRING * this.PromptService.BUTTON_POS_0) + (this.PromptService.BUTTON_TITLE_CANCEL * this.PromptService.BUTTON_POS_1), this.tabbrowserBundle.getString('tabs.closeButtonMultiple'), null, null, this.tabbrowserBundle.getString('tabs.closeWarningPromptMe'), checked ) == 0; if (shouldClose && !checked.value) this.setPref('browser.tabs.warnOnClose', false); return shouldClose; }, reloadTabSubtree : function TSTService_reloadTabSubtree(aTabOrTabs, aOnlyChildren) { var tabs = this.gatherSubtreeMemberTabs(aTabOrTabs, aOnlyChildren); var b = this.getTabBrowserFromChild(tabs[0]); for (var i = tabs.length-1; i > -1; i--) { b.reloadTab(tabs[i]); } }, reloadTabSubTree : function() { return this.reloadTabSubtree.apply(this, arguments); }, // obsolete, for backward compatibility createSubtree : function TSTService_createSubtree(aTabs) { aTabs = this.getRootTabs(aTabs); if (!aTabs.length) return; var b = this.getTabBrowserFromChild(aTabs[0]); var parent = this.getParentTab(aTabs[0]); var next = aTabs[0]; while ( (next = this.getNextSiblingTab(next)) && aTabs.indexOf(next) > -1 ); var root = this.getTreePref('createSubtree.underParent') ? b.addTab(this.getGroupTabURI()) : aTabs.shift() ; window.setTimeout(function(aSelf) { aTabs.forEach(function(aTab) { b.treeStyleTab.attachTabTo(aTab, root); b.treeStyleTab.collapseExpandTab(aTab, false); }, aSelf); if (parent) { b.treeStyleTab.attachTabTo(root, parent, { insertBefore : next }); } else if (next) { b.treeStyleTab.moveTabSubtreeTo(root, next._tPos); } }, 0, this); }, createSubTree : function() { return this.createSubtree.apply(this, arguments); }, // obsolete, for backward compatibility canCreateSubtree : function TSTService_canCreateSubtree(aTabs) { aTabs = this.getRootTabs(aTabs); if (aTabs.length < 2) return false; var lastParent = this.getParentTab(aTabs[0]); for (let i = 1, maxi = aTabs.length-1; i < maxi; i++) { let parent = this.getParentTab(aTabs[i]); if (!lastParent || parent != lastParent) return true; lastParent = parent; } return this.getChildTabs(lastParent).length != aTabs.length; }, canCreateSubTree : function() { return this.canCreateSubtree.apply(this, arguments); }, // obsolete, for backward compatibility getRootTabs : function TSTService_getRootTabs(aTabs) { var roots = []; if (!aTabs || !aTabs.length) return roots; aTabs = this.cleanUpTabsArray(aTabs); aTabs.forEach(function(aTab) { var parent = this.getParentTab(aTab); if (parent && aTabs.indexOf(parent) > -1) return; roots.push(aTab); }, this); return roots; }, collapseExpandAllSubtree : function TSTService_collapseExpandAllSubtree(aCollapse) { this.ObserverService.notifyObservers( window, this.kTOPIC_COLLAPSE_EXPAND_ALL, (aCollapse ? 'collapse' : 'open' ) ); }, promoteTab : function TSTService_promoteTab(aTab) /* PUBLIC API */ { var b = this.getTabBrowserFromChild(aTab); var sv = b.treeStyleTab; var parent = sv.getParentTab(aTab); if (!parent) return; var nextSibling = sv.getNextSiblingTab(parent); var grandParent = sv.getParentTab(parent); if (grandParent) { sv.attachTabTo(aTab, grandParent, { insertBefore : nextSibling }); } else { sv.partTab(aTab); let index = nextSibling ? nextSibling._tPos : b.mTabContainer.childNodes.length ; if (index > aTab._tPos) index--; b.moveTabTo(aTab, index); } }, promoteCurrentTab : function TSTService_promoteCurrentTab() /* PUBLIC API */ { this.promoteTab(this.browser.selectedTab); }, demoteTab : function TSTService_demoteTab(aTab) /* PUBLIC API */ { var b = this.getTabBrowserFromChild(aTab); var sv = b.treeStyleTab; var previous = this.getPreviousSiblingTab(aTab); if (previous) sv.attachTabTo(aTab, previous); }, demoteCurrentTab : function TSTService_demoteCurrentTab() /* PUBLIC API */ { this.demoteTab(this.browser.selectedTab); }, expandTreeAfterKeyReleased : function TSTService_expandTreeAfterKeyReleased(aTab) { if (this.getTreePref('autoCollapseExpandSubtreeOnSelect.whileFocusMovingByShortcut')) return; this._tabShouldBeExpandedAfterKeyReleased = aTab || null; }, _tabShouldBeExpandedAfterKeyReleased : null, removeAllTabsBut : function TSTService_removeAllTabsBut(aTab) { var keepTabs = [aTab].concat(this.getDescendantTabs(aTab)); var b = this.getTabBrowserFromChild(aTab); var closeTabs = this.getTabsArray(b) .filter(function(aTab) { return keepTabs.indexOf(aTab) < 0; }); if (!this.warnAboutClosingTabs(closeTabs.length)) return; this.stopRendering(); this.markAsClosedSet(closeTabs); closeTabs.reverse().forEach(function(aTab) { b.removeTab(aTab); }); this.startRendering(); }, // For backward compatibility. You should use DOM event to block TST's focus handling. registerTabFocusAllowance : function TSTService_registerTabFocusAllowance(aProcess) /* PUBLIC API */ { var listener = { process : aProcess, handleEvent : function(aEvent) { if (!this.process.call(aEvent.target.treeStyleTab, aEvent.target)) aEvent.preventDefault(); } }; window.addEventListener(this.kEVENT_TYPE_FOCUS_NEXT_TAB, listener, false); this._tabFocusAllowance.push(listener); }, _tabFocusAllowance : [], tearOffSubtreeFromRemote : function TSTService_tearOffSubtreeFromRemote() { var remoteTab = window.arguments[0]; var remoteWindow = remoteTab.ownerDocument.defaultView; var remoteService = remoteWindow.TreeStyleTabService; var remoteMultipleTabService = remoteWindow.MultipleTabService; if (remoteService.hasChildTabs(remoteTab) || (remoteMultipleTabService && remoteMultipleTabService.isSelected(remoteTab))) { var remoteBrowser = remoteService.getTabBrowserFromChild(remoteTab); if (remoteBrowser.treeStyleTab.tabbarDNDObserver.isDraggingAllTabs(remoteTab)) { window.close(); } else { var actionInfo = { action : this.kACTIONS_FOR_DESTINATION | this.kACTION_IMPORT }; window.setTimeout(function() { var blankTab = gBrowser.selectedTab; gBrowser.treeStyleTab.tabbarDNDObserver.performDrop(actionInfo, remoteTab); window.setTimeout(function() { gBrowser.removeTab(blankTab); remoteTab = null; remoteBrowser = null; remoteWindow = null remoteService = null; remoteMultipleTabService = null; }, 0); }, 0); } return true; } return false; }, tearOffSubTreeFromRemote : function() { return this.tearOffSubtreeFromRemote.apply(this, arguments); }, // obsolete, for backward compatibility onPrintPreviewEnter : function TSTService_onPrintPreviewEnter() { var event = document.createEvent('Events'); event.initEvent(this.kEVENT_TYPE_PRINT_PREVIEW_ENTERED, true, false); document.documentElement.dispatchEvent(event); // for backward compatibility event = document.createEvent('Events'); event.initEvent(this.kEVENT_TYPE_PRINT_PREVIEW_ENTERED.replace(/^nsDOM/, ''), true, false); document.documentElement.dispatchEvent(event); }, onPrintPreviewExit : function TSTService_onPrintPreviewExit() { var event = document.createEvent('Events'); event.initEvent(this.kEVENT_TYPE_PRINT_PREVIEW_EXITED, true, false); document.documentElement.dispatchEvent(event); // for backward compatibility event = document.createEvent('Events'); event.initEvent(this.kEVENT_TYPE_PRINT_PREVIEW_EXITED.replace(/^nsDOM/, ''), true, false); document.documentElement.dispatchEvent(event); }, observe : function TSTService_observe(aSubject, aTopic, aData) { switch (aTopic) { case 'nsPref:changed': this.onPrefChange(aData); return; case 'sessionstore-windows-restored': if (!this.useTMPSessionAPI) this.restoringTree = this.getRestoringTabsCount() > 1; return; } }, restoringTree : false, getRestoringTabsCount : function TSTService_getRestoringTabsCount() { return this.getAllTabsArray(this.browser) .filter(function(aTab) { var owner = aTab.linkedBrowser; var data = owner.__SS_data || // Firefox 3.6- owner.parentNode.__SS_data; // -Firefox 3.5 return data && data._tabStillLoading; }).length; }, /* Pref Listener */ domains : [ 'extensions.treestyletab', 'browser.ctrlTab.previews' ], onPrefChange : function TSTService_onPrefChange(aPrefName) { var value = this.getPref(aPrefName); switch (aPrefName) { case 'extensions.treestyletab.tabbar.autoHide.mode': // don't set on this time, because appearance of all tabbrowsers are not updated yet. // this.autoHide.mode = this.getTreePref('tabbar.autoHide.mode'); case 'extensions.treestyletab.tabbar.autoShow.accelKeyDown': case 'extensions.treestyletab.tabbar.autoShow.tabSwitch': case 'extensions.treestyletab.tabbar.autoShow.feedback': this.autoHideWindow.updateKeyListeners(window); break; case 'extensions.treestyletab.tabbar.style': case 'extensions.treestyletab.tabbar.position': this.preLoadImagesForStyle([ this.getPref('extensions.treestyletab.tabbar.style'), this.currentTabbarPosition ].join('-')); break; case 'browser.ctrlTab.previews': this.autoHideWindow.updateKeyListeners(window); case 'extensions.treestyletab.autoCollapseExpandSubtreeOnSelect.whileFocusMovingByShortcut': case 'extensions.treestyletab.autoCollapseExpandSubtreeOnSelect': if (this.shouldListenKeyEventsForAutoExpandByFocusChange) this.startListenKeyEventsFor(this.LISTEN_FOR_AUTOEXPAND_BY_FOCUSCHANGE); else this.endListenKeyEventsFor(this.LISTEN_FOR_AUTOEXPAND_BY_FOCUSCHANGE); break; default: break; } }, }; (function() { var namespace = {}; Components.utils.import( 'resource://treestyletab-modules/utils.js', namespace ); TreeStyleTabService.__proto__ = TreeStyleTabService.utils = namespace.TreeStyleTabUtils; TreeStyleTabService.utils.init(); })();