diff --git a/content/treestyletab/bookmarksOverlay.xul b/content/treestyletab/bookmarksOverlay.xul
index fc4a82bd..bec17360 100644
--- a/content/treestyletab/bookmarksOverlay.xul
+++ b/content/treestyletab/bookmarksOverlay.xul
@@ -1,6 +1,6 @@
-
-
-
-
-
-
+
+
+
+
+
+
diff --git a/content/treestyletab/bookmarksOverlayEditable.css b/content/treestyletab/bookmarksOverlayEditable.css
index c0e783dc..aa018567 100644
--- a/content/treestyletab/bookmarksOverlayEditable.css
+++ b/content/treestyletab/bookmarksOverlayEditable.css
@@ -1,3 +1,3 @@
-#infoBox[minimal="true"] #treestyletab-parent-row {
- visibility: collapse;
-}
+#infoBox[minimal="true"] #treestyletab-parent-row {
+ visibility: collapse;
+}
diff --git a/content/treestyletab/bookmarksOverlayEditable.js b/content/treestyletab/bookmarksOverlayEditable.js
index fcae3690..c11481c0 100644
--- a/content/treestyletab/bookmarksOverlayEditable.js
+++ b/content/treestyletab/bookmarksOverlayEditable.js
@@ -1,365 +1,365 @@
-Components.utils.import('resource://gre/modules/XPCOMUtils.jsm');
-XPCOMUtils.defineLazyModuleGetter(this,
- 'TreeStyleTabUtils', 'resource://treestyletab-modules/utils.js');
-
-(function() {
-let { inherit } = Components.utils.import('resource://treestyletab-modules/lib/inherit.jsm', {});
-var TreeStyleTabBookmarksServiceEditable = inherit(TreeStyleTabBookmarksService, {
-
- instantApply : false,
- canceled : false,
-
- get parentRow()
- {
- return document.getElementById('treestyletab-parent-row');
- },
-
- get menulist()
- {
- return document.getElementById('treestyletab-parent-menulist');
- },
- get popup()
- {
- return document.getElementById('treestyletab-parent-popup');
- },
-
- get separator()
- {
- return document.getElementById('treestyletab-parent-blank-item-separator');
- },
- get blankItem()
- {
- return document.getElementById('treestyletab-parent-blank-item');
- },
-
- get isCreatingMultipleBookmarksInFolder()
- {
- return (
- window.arguments.length &&
- window.arguments[0] &&
- window.arguments[0].type == 'folder'
- );
- },
-
- init : function TSTBMEditable_init()
- {
- if (this.isCreatingMultipleBookmarksInFolder) return;
-
- // main browser window
- if ('StarUI' in window) {
- if ('_doShowEditBookmarkPanel' in StarUI) {
- eval('StarUI._doShowEditBookmarkPanel = '+StarUI._doShowEditBookmarkPanel.toSource().replace(
- '{',
- '{ TreeStyleTabBookmarksServiceEditable.initEditUI();'
- ));
- }
- if ('quitEditMode' in StarUI) {
- eval('StarUI.quitEditMode = '+StarUI.quitEditMode.toSource().replace(
- '{',
- '{ TreeStyleTabBookmarksServiceEditable.saveParentFor(this._itemId);'
- ));
- }
- if ('cancelButtonOnCommand' in StarUI) {
- eval('StarUI.cancelButtonOnCommand = '+StarUI.cancelButtonOnCommand.toSource().replace(
- '{',
- '{ TreeStyleTabBookmarksServiceEditable.canceled = true;'
- ));
- }
- }
-
- // Bookmarks Property dialog
- if ('BookmarkPropertiesPanel' in window) {
- eval('BookmarkPropertiesPanel._endBatch = '+BookmarkPropertiesPanel._endBatch.toSource().replace(
- 'PlacesUIUtils.ptm.endBatch();',
- '$& TreeStyleTabBookmarksServiceEditable.saveParentFor(this._itemId);'
- ));
- }
-
- // Places Organizer (Library)
- if ('PlacesOrganizer' in window) {
- this.instantApply = true;
- }
-
- this.initEditUI();
- },
-
- initEditUI : function TSTBMEditable_initEditUI()
- {
- if (
- this.editUIInitialized ||
- !('gEditItemOverlay' in window) ||
- this.isCreatingMultipleBookmarksInFolder
- )
- return;
-
- var container = document.getElementById('editBookmarkPanelGrid');
- if (!container) return;
-
- container = container.getElementsByTagName('rows')[0];
- var range = document.createRange();
- range.selectNodeContents(container);
- range.collapse(false);
- range.insertNode(range.createContextualFragment(
- ('' +
- ' ' +
- ' ' +
- '
').trim().replace(/>\s+<')));
- range.detach();
- document.getElementById('treestyletab-parent-label').setAttribute('value', TreeStyleTabUtils.treeBundle.getString('bookmarkProperty.parent.label'));
- this.blankItem.setAttribute('label', TreeStyleTabUtils.treeBundle.getString('bookmarkProperty.parent.blank.label'));
-
-
- eval('gEditItemOverlay._showHideRows = '+gEditItemOverlay._showHideRows.toSource().replace(
- /(\}\)?)$/,
- ' TreeStyleTabBookmarksServiceEditable.parentRow.collapsed = this._element("keywordRow").collapsed && this._element("folderRow").collapsed;\n' +
- '$1'
- ));
-
- eval('gEditItemOverlay.initPanel = '+gEditItemOverlay.initPanel.toSource().replace(
- 'if (this._itemType == Ci.nsINavBookmarksService.TYPE_BOOKMARK) {',
- '$& TreeStyleTabBookmarksServiceEditable.initParentMenuList();'
- ));
-
- eval('gEditItemOverlay.onItemMoved = '+gEditItemOverlay.onItemMoved.toSource().replace(
- '{',
- '$& if (aNewParent == this._getFolderIdFromMenuList()) TreeStyleTabBookmarksServiceEditable.initParentMenuList();'
- ));
-
- this.editUIInitialized = true;
- },
- editUIInitialized : false,
-
- initParentMenuList : function TSTBMEditable_initParentMenuList()
- {
- var id = gEditItemOverlay.itemId;
-
- this.menulist.disabled = true;
- this.menulist.setAttribute('label', '...');
-
- var popup = this.popup;
- var range = document.createRange();
- range.selectNodeContents(popup);
- range.setEndBefore(this.separator);
- range.deleteContents();
- range.detach();
-
- this.canceled = false;
-
- // Ignore bookmark in the "unsorted bookmarks" folder, because
- // there can be very large number of bookmarks and they won't be
- // opened as a tree.
- if (PlacesUtils.bookmarks.getFolderIdForItem(id) == PlacesUtils.unfiledBookmarksFolderId)
- return;
-
- this._createSiblingsFragment(id, (function(aSiblingsFragment) {
- var range = document.createRange();
- range.selectNodeContents(popup);
- range.setEndBefore(this.separator);
- range.insertNode(aSiblingsFragment);
- range.detach();
-
- var selected = popup.getElementsByAttribute('selected', 'true')[0];
- this.menulist.disabled = false;
- this.menulist.value = (selected || this.blankItem).getAttribute('value');
- }).bind(this))
- },
- _doProgressively : function TSTBMEditable__doProgressively(aParams)
- {
- var name = aParams.name;
- if (this._doProgressivelyTimers[name])
- window.clearTimeout(this._doProgressivelyTimers[name]);
-
- var interval = 100;
- var step = 10;
- var progressiveIteration = (function() {
- try {
- for (let i = 0; i < step; i++)
- {
- aParams.onProgress();
- }
- this._doProgressivelyTimers[name] = window.setTimeout(progressiveIteration, interval);
- }
- catch(e if e instanceof StopIteration) {
- aParams.onComplete();
- }
- catch(e) {
- Components.utils.reportError(e);
- }
- finally {
- this._doProgressivelyTimers[name] = null;
- }
- }).bind(this);
- this._doProgressivelyTimers[name] = window.setTimeout(progressiveIteration, interval);
- },
- _doProgressivelyTimers : {},
- _createSiblingsFragment : function TSTBMEditable__createSiblingsFragment(aCurrentItem, aCallback)
- {
- var itemsIterator = this._getSiblingItemsIterator(aCurrentItem);
- var items = [];
- this._doProgressively({
- name : '_createSiblingsFragment',
- onProgress : function() {
- items.push(itemsIterator.next());
- },
- onComplete : (function() {
- this._createSiblingsFragmentInternal(aCurrentItem, items, function(aSiblingsFragment) {
- aCallback(aSiblingsFragment);
- });
- }).bind(this)
- });
- },
- _createSiblingsFragmentInternal : function TSTBMEditable_createSiblingsFragmentInternal(aCurrentItem, aItems, aCallback)
- {
- var treeStructure = this.getTreeStructureFromItems(aItems);
-
- var currentIndex = aItems.indexOf(aCurrentItem);
- var selected = treeStructure[currentIndex];
- if (selected > -1) {
- let offset = treeStructure.lastIndexOf(-1, currentIndex);
- let subStructure = treeStructure.slice(offset);
- selected = aItems[selected + offset];
- }
-
- var fragment = document.createDocumentFragment();
-
- var itemsIterator = Iterator(aItems);
- this._doProgressively({
- name : '_createSiblingsFragment',
- onProgress : (function() {
- let [index, id] = itemsIterator.next();
-
- let label = PlacesUtils.bookmarks.getItemTitle(id);
- let menuitem = document.createElement('menuitem');
- menuitem.setAttribute('value', id);
-
- let parent = index;
- let nest = 0;
- let disabled = false;
- while ((parent = treeStructure[parent]) != -1)
- {
- nest++;
- if (parent == currentIndex) disabled = true;
- }
- if (nest)
- menuitem.setAttribute('style', 'padding-left:'+nest+'em');
-
- if (disabled || id == aCurrentItem) {
- menuitem.setAttribute('disabled', true);
- if (id == aCurrentItem)
- label = TreeStyleTabUtils.treeBundle.getFormattedString('bookmarkProperty.parent.current.label', [label]);
- }
- if (id == selected)
- menuitem.setAttribute('selected', true);
-
- menuitem.setAttribute('label', label);
-
- fragment.appendChild(menuitem);
- }).bind(this),
- onComplete : function() {
- aCallback(fragment);
- }
- });
- },
- _getItemsInFolderIterator : function TSTBMEditable_getItemsInFolderIterator(aId)
- {
- var count = 0;
- var item;
- try {
- while((item = PlacesUtils.bookmarks.getIdForItemAt(aId, count++)) != -1)
- {
- try {
- let uri = PlacesUtils.bookmarks.getBookmarkURI(item);
- if (uri.spec.indexOf('place:') != 0)
- yield item;
- }
- catch(e) {
- // this is not a normal bookmark.
- }
- }
- }
- catch(e) {
- }
- },
- _getSiblingItemsIterator : function TSTBMEditable_getSiblingItemsIterator(aId)
- {
- return this._getItemsInFolderIterator(PlacesUtils.bookmarks.getFolderIdForItem(aId));
- },
-
- saveParentFor : function TSTBMEditable_saveParentFor(aId)
- {
- var newParentId = parseInt(this.menulist.value || -1);
- if (this.canceled || newParentId == this.getParentItem(aId)) return;
-
- var itemsIterator = this._getSiblingItemsIterator(aId);
- var items = [];
- this._doProgressively({
- name : '_createSiblingsFragment',
- onProgress : function() {
- items.push(itemsIterator.next());
- },
- onComplete : (function() {
- this._saveParentForInternal(aId, newParentId, items);
- }).bind(this)
- });
- },
- _saveParentForInternal : function TSTBMEditable_saveParentForInternal(aId, aNewParentId, aItems)
- {
- var treeStructure = this.getTreeStructureFromItems(aItems);
-
- var parentIndex = aItems.indexOf(aNewParentId);
- var newIndex;
- if (TreeStyleTabUtils.getTreePref('insertNewChildAt') == this.kINSERT_FISRT) {
- newIndex = treeStructure.indexOf(parentIndex);
- }
- else {
- do {
- newIndex = parentIndex;
- parentIndex = treeStructure.lastIndexOf(parentIndex);
- }
- while (parentIndex > -1);
- newIndex++;
- }
-
- PlacesUtils.setAnnotationsForItem(aId, [{
- name : this.kPARENT,
- value : aNewParentId,
- expires : PlacesUtils.annotations.EXPIRE_NEVER
- }]);
-
- PlacesUtils.bookmarks.moveItem(aId, PlacesUtils.bookmarks.getFolderIdForItem(aId), newIndex);
-
- if (this.instantApply) this.initParentMenuList();
- },
-
- onParentChange : function TSTBMEditable_onParentChange()
- {
- if (!this.instantApply) return;
- this.saveParentFor(gEditItemOverlay.itemId);
- },
-
- handleEvent : function TSTBMEditable_handleEvent(aEvent)
- {
- switch (aEvent.type)
- {
- case 'DOMContentLoaded':
- window.removeEventListener('DOMContentLoaded', this, false);
- this.init();
- break;
- }
- }
-
-});
-
-window.addEventListener('DOMContentLoaded', TreeStyleTabBookmarksServiceEditable, false);
-
-window.TreeStyleTabBookmarksServiceEditable = TreeStyleTabBookmarksServiceEditable;
-})();
+Components.utils.import('resource://gre/modules/XPCOMUtils.jsm');
+XPCOMUtils.defineLazyModuleGetter(this,
+ 'TreeStyleTabUtils', 'resource://treestyletab-modules/utils.js');
+
+(function() {
+let { inherit } = Components.utils.import('resource://treestyletab-modules/lib/inherit.jsm', {});
+var TreeStyleTabBookmarksServiceEditable = inherit(TreeStyleTabBookmarksService, {
+
+ instantApply : false,
+ canceled : false,
+
+ get parentRow()
+ {
+ return document.getElementById('treestyletab-parent-row');
+ },
+
+ get menulist()
+ {
+ return document.getElementById('treestyletab-parent-menulist');
+ },
+ get popup()
+ {
+ return document.getElementById('treestyletab-parent-popup');
+ },
+
+ get separator()
+ {
+ return document.getElementById('treestyletab-parent-blank-item-separator');
+ },
+ get blankItem()
+ {
+ return document.getElementById('treestyletab-parent-blank-item');
+ },
+
+ get isCreatingMultipleBookmarksInFolder()
+ {
+ return (
+ window.arguments.length &&
+ window.arguments[0] &&
+ window.arguments[0].type == 'folder'
+ );
+ },
+
+ init : function TSTBMEditable_init()
+ {
+ if (this.isCreatingMultipleBookmarksInFolder) return;
+
+ // main browser window
+ if ('StarUI' in window) {
+ if ('_doShowEditBookmarkPanel' in StarUI) {
+ eval('StarUI._doShowEditBookmarkPanel = '+StarUI._doShowEditBookmarkPanel.toSource().replace(
+ '{',
+ '{ TreeStyleTabBookmarksServiceEditable.initEditUI();'
+ ));
+ }
+ if ('quitEditMode' in StarUI) {
+ eval('StarUI.quitEditMode = '+StarUI.quitEditMode.toSource().replace(
+ '{',
+ '{ TreeStyleTabBookmarksServiceEditable.saveParentFor(this._itemId);'
+ ));
+ }
+ if ('cancelButtonOnCommand' in StarUI) {
+ eval('StarUI.cancelButtonOnCommand = '+StarUI.cancelButtonOnCommand.toSource().replace(
+ '{',
+ '{ TreeStyleTabBookmarksServiceEditable.canceled = true;'
+ ));
+ }
+ }
+
+ // Bookmarks Property dialog
+ if ('BookmarkPropertiesPanel' in window) {
+ eval('BookmarkPropertiesPanel._endBatch = '+BookmarkPropertiesPanel._endBatch.toSource().replace(
+ 'PlacesUIUtils.ptm.endBatch();',
+ '$& TreeStyleTabBookmarksServiceEditable.saveParentFor(this._itemId);'
+ ));
+ }
+
+ // Places Organizer (Library)
+ if ('PlacesOrganizer' in window) {
+ this.instantApply = true;
+ }
+
+ this.initEditUI();
+ },
+
+ initEditUI : function TSTBMEditable_initEditUI()
+ {
+ if (
+ this.editUIInitialized ||
+ !('gEditItemOverlay' in window) ||
+ this.isCreatingMultipleBookmarksInFolder
+ )
+ return;
+
+ var container = document.getElementById('editBookmarkPanelGrid');
+ if (!container) return;
+
+ container = container.getElementsByTagName('rows')[0];
+ var range = document.createRange();
+ range.selectNodeContents(container);
+ range.collapse(false);
+ range.insertNode(range.createContextualFragment(
+ ('' +
+ ' ' +
+ ' ' +
+ '
').trim().replace(/>\s+<')));
+ range.detach();
+ document.getElementById('treestyletab-parent-label').setAttribute('value', TreeStyleTabUtils.treeBundle.getString('bookmarkProperty.parent.label'));
+ this.blankItem.setAttribute('label', TreeStyleTabUtils.treeBundle.getString('bookmarkProperty.parent.blank.label'));
+
+
+ eval('gEditItemOverlay._showHideRows = '+gEditItemOverlay._showHideRows.toSource().replace(
+ /(\}\)?)$/,
+ ' TreeStyleTabBookmarksServiceEditable.parentRow.collapsed = this._element("keywordRow").collapsed && this._element("folderRow").collapsed;\n' +
+ '$1'
+ ));
+
+ eval('gEditItemOverlay.initPanel = '+gEditItemOverlay.initPanel.toSource().replace(
+ 'if (this._itemType == Ci.nsINavBookmarksService.TYPE_BOOKMARK) {',
+ '$& TreeStyleTabBookmarksServiceEditable.initParentMenuList();'
+ ));
+
+ eval('gEditItemOverlay.onItemMoved = '+gEditItemOverlay.onItemMoved.toSource().replace(
+ '{',
+ '$& if (aNewParent == this._getFolderIdFromMenuList()) TreeStyleTabBookmarksServiceEditable.initParentMenuList();'
+ ));
+
+ this.editUIInitialized = true;
+ },
+ editUIInitialized : false,
+
+ initParentMenuList : function TSTBMEditable_initParentMenuList()
+ {
+ var id = gEditItemOverlay.itemId;
+
+ this.menulist.disabled = true;
+ this.menulist.setAttribute('label', '...');
+
+ var popup = this.popup;
+ var range = document.createRange();
+ range.selectNodeContents(popup);
+ range.setEndBefore(this.separator);
+ range.deleteContents();
+ range.detach();
+
+ this.canceled = false;
+
+ // Ignore bookmark in the "unsorted bookmarks" folder, because
+ // there can be very large number of bookmarks and they won't be
+ // opened as a tree.
+ if (PlacesUtils.bookmarks.getFolderIdForItem(id) == PlacesUtils.unfiledBookmarksFolderId)
+ return;
+
+ this._createSiblingsFragment(id, (function(aSiblingsFragment) {
+ var range = document.createRange();
+ range.selectNodeContents(popup);
+ range.setEndBefore(this.separator);
+ range.insertNode(aSiblingsFragment);
+ range.detach();
+
+ var selected = popup.getElementsByAttribute('selected', 'true')[0];
+ this.menulist.disabled = false;
+ this.menulist.value = (selected || this.blankItem).getAttribute('value');
+ }).bind(this))
+ },
+ _doProgressively : function TSTBMEditable__doProgressively(aParams)
+ {
+ var name = aParams.name;
+ if (this._doProgressivelyTimers[name])
+ window.clearTimeout(this._doProgressivelyTimers[name]);
+
+ var interval = 100;
+ var step = 10;
+ var progressiveIteration = (function() {
+ try {
+ for (let i = 0; i < step; i++)
+ {
+ aParams.onProgress();
+ }
+ this._doProgressivelyTimers[name] = window.setTimeout(progressiveIteration, interval);
+ }
+ catch(e if e instanceof StopIteration) {
+ aParams.onComplete();
+ }
+ catch(e) {
+ Components.utils.reportError(e);
+ }
+ finally {
+ this._doProgressivelyTimers[name] = null;
+ }
+ }).bind(this);
+ this._doProgressivelyTimers[name] = window.setTimeout(progressiveIteration, interval);
+ },
+ _doProgressivelyTimers : {},
+ _createSiblingsFragment : function TSTBMEditable__createSiblingsFragment(aCurrentItem, aCallback)
+ {
+ var itemsIterator = this._getSiblingItemsIterator(aCurrentItem);
+ var items = [];
+ this._doProgressively({
+ name : '_createSiblingsFragment',
+ onProgress : function() {
+ items.push(itemsIterator.next());
+ },
+ onComplete : (function() {
+ this._createSiblingsFragmentInternal(aCurrentItem, items, function(aSiblingsFragment) {
+ aCallback(aSiblingsFragment);
+ });
+ }).bind(this)
+ });
+ },
+ _createSiblingsFragmentInternal : function TSTBMEditable_createSiblingsFragmentInternal(aCurrentItem, aItems, aCallback)
+ {
+ var treeStructure = this.getTreeStructureFromItems(aItems);
+
+ var currentIndex = aItems.indexOf(aCurrentItem);
+ var selected = treeStructure[currentIndex];
+ if (selected > -1) {
+ let offset = treeStructure.lastIndexOf(-1, currentIndex);
+ let subStructure = treeStructure.slice(offset);
+ selected = aItems[selected + offset];
+ }
+
+ var fragment = document.createDocumentFragment();
+
+ var itemsIterator = Iterator(aItems);
+ this._doProgressively({
+ name : '_createSiblingsFragment',
+ onProgress : (function() {
+ let [index, id] = itemsIterator.next();
+
+ let label = PlacesUtils.bookmarks.getItemTitle(id);
+ let menuitem = document.createElement('menuitem');
+ menuitem.setAttribute('value', id);
+
+ let parent = index;
+ let nest = 0;
+ let disabled = false;
+ while ((parent = treeStructure[parent]) != -1)
+ {
+ nest++;
+ if (parent == currentIndex) disabled = true;
+ }
+ if (nest)
+ menuitem.setAttribute('style', 'padding-left:'+nest+'em');
+
+ if (disabled || id == aCurrentItem) {
+ menuitem.setAttribute('disabled', true);
+ if (id == aCurrentItem)
+ label = TreeStyleTabUtils.treeBundle.getFormattedString('bookmarkProperty.parent.current.label', [label]);
+ }
+ if (id == selected)
+ menuitem.setAttribute('selected', true);
+
+ menuitem.setAttribute('label', label);
+
+ fragment.appendChild(menuitem);
+ }).bind(this),
+ onComplete : function() {
+ aCallback(fragment);
+ }
+ });
+ },
+ _getItemsInFolderIterator : function TSTBMEditable_getItemsInFolderIterator(aId)
+ {
+ var count = 0;
+ var item;
+ try {
+ while((item = PlacesUtils.bookmarks.getIdForItemAt(aId, count++)) != -1)
+ {
+ try {
+ let uri = PlacesUtils.bookmarks.getBookmarkURI(item);
+ if (uri.spec.indexOf('place:') != 0)
+ yield item;
+ }
+ catch(e) {
+ // this is not a normal bookmark.
+ }
+ }
+ }
+ catch(e) {
+ }
+ },
+ _getSiblingItemsIterator : function TSTBMEditable_getSiblingItemsIterator(aId)
+ {
+ return this._getItemsInFolderIterator(PlacesUtils.bookmarks.getFolderIdForItem(aId));
+ },
+
+ saveParentFor : function TSTBMEditable_saveParentFor(aId)
+ {
+ var newParentId = parseInt(this.menulist.value || -1);
+ if (this.canceled || newParentId == this.getParentItem(aId)) return;
+
+ var itemsIterator = this._getSiblingItemsIterator(aId);
+ var items = [];
+ this._doProgressively({
+ name : '_createSiblingsFragment',
+ onProgress : function() {
+ items.push(itemsIterator.next());
+ },
+ onComplete : (function() {
+ this._saveParentForInternal(aId, newParentId, items);
+ }).bind(this)
+ });
+ },
+ _saveParentForInternal : function TSTBMEditable_saveParentForInternal(aId, aNewParentId, aItems)
+ {
+ var treeStructure = this.getTreeStructureFromItems(aItems);
+
+ var parentIndex = aItems.indexOf(aNewParentId);
+ var newIndex;
+ if (TreeStyleTabUtils.getTreePref('insertNewChildAt') == this.kINSERT_FISRT) {
+ newIndex = treeStructure.indexOf(parentIndex);
+ }
+ else {
+ do {
+ newIndex = parentIndex;
+ parentIndex = treeStructure.lastIndexOf(parentIndex);
+ }
+ while (parentIndex > -1);
+ newIndex++;
+ }
+
+ PlacesUtils.setAnnotationsForItem(aId, [{
+ name : this.kPARENT,
+ value : aNewParentId,
+ expires : PlacesUtils.annotations.EXPIRE_NEVER
+ }]);
+
+ PlacesUtils.bookmarks.moveItem(aId, PlacesUtils.bookmarks.getFolderIdForItem(aId), newIndex);
+
+ if (this.instantApply) this.initParentMenuList();
+ },
+
+ onParentChange : function TSTBMEditable_onParentChange()
+ {
+ if (!this.instantApply) return;
+ this.saveParentFor(gEditItemOverlay.itemId);
+ },
+
+ handleEvent : function TSTBMEditable_handleEvent(aEvent)
+ {
+ switch (aEvent.type)
+ {
+ case 'DOMContentLoaded':
+ window.removeEventListener('DOMContentLoaded', this, false);
+ this.init();
+ break;
+ }
+ }
+
+});
+
+window.addEventListener('DOMContentLoaded', TreeStyleTabBookmarksServiceEditable, false);
+
+window.TreeStyleTabBookmarksServiceEditable = TreeStyleTabBookmarksServiceEditable;
+})();
diff --git a/content/treestyletab/bookmarksOverlayEditable.xul b/content/treestyletab/bookmarksOverlayEditable.xul
index b22315d6..a3450f5b 100644
--- a/content/treestyletab/bookmarksOverlayEditable.xul
+++ b/content/treestyletab/bookmarksOverlayEditable.xul
@@ -1,5 +1,5 @@
-
-
-
-
-
+
+
+
+
+
diff --git a/content/treestyletab/config.css b/content/treestyletab/config.css
index 1d39b680..d8e0e004 100644
--- a/content/treestyletab/config.css
+++ b/content/treestyletab/config.css
@@ -1,15 +1,15 @@
-@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
-
-[id="extensions.treestyletab.tabbar.style-radiogroup"] radio[src] .radio-icon {
- width: 52px;
- height: 62px;
-}
-
-[id="extensions.treestyletab.twisty.style-radiogroup"] radio[src] .radio-icon {
- width: 24px;
- height: 24px;
-}
-
-arrowscrollbox[overflow="true"] {
- border: 1px inset ThreeDFace;
-}
+@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
+
+[id="extensions.treestyletab.tabbar.style-radiogroup"] radio[src] .radio-icon {
+ width: 52px;
+ height: 62px;
+}
+
+[id="extensions.treestyletab.twisty.style-radiogroup"] radio[src] .radio-icon {
+ width: 24px;
+ height: 24px;
+}
+
+arrowscrollbox[overflow="true"] {
+ border: 1px inset ThreeDFace;
+}
diff --git a/content/treestyletab/config.js b/content/treestyletab/config.js
index 63bfeb26..3f7c9b6e 100644
--- a/content/treestyletab/config.js
+++ b/content/treestyletab/config.js
@@ -1,375 +1,375 @@
-Components.utils.import('resource://gre/modules/Services.jsm');
-
-const XULAppInfo = Services.appinfo;
-const comparator = Services.vc;
-var Prefs = Services.prefs;
-
-Components.utils.import('resource://treestyletab-modules/lib/animationManager.js', {});
-Components.utils.import('resource://treestyletab-modules/lib/prefs.js', {});
-Components.utils.import('resource://treestyletab-modules/lib/namespace.jsm');
-var animationManager = getNamespaceFor('piro.sakura.ne.jp')['piro.sakura.ne.jp'].animationManager;
-var prefs = getNamespaceFor('piro.sakura.ne.jp')['piro.sakura.ne.jp'].prefs;
-
-
-function syncEnabledState(aElement, aEnabled)
-{
- if (typeof aElement == 'string')
- aElement = document.getElementById(aElement);
- if (typeof aEnabled == 'string')
- aEnabled = (new Function('return '+aEnabled)).call(aElement);
-
- aElement.getAttribute('sync-enabled-state-targets')
- .replace(/$\s+|\s+$/g, '')
- .split(/\s+/)
- .map(function(aId) {
- if (!aId)
- return;
- var target = document.getElementById(aId);
- if (aEnabled)
- target.removeAttribute('disabled');
- else
- target.setAttribute('disabled', true);
- });
-}
-
-
-var gGroupBookmarkRadio,
- gGroupBookmarkUnderParent,
- gGroupBookmarkType,
- gGroupBookmarkBehaviorPref;
-
-function ensureGroupBookmarkItems()
-{
- if (gGroupBookmarkBehaviorPref) return;
-
- gGroupBookmarkRadio = document.getElementById('openGroupBookmark-radiogroup');
- gGroupBookmarkUnderParent = document.getElementById('openGroupBookmark.underParent-check');
- gGroupBookmarkType = document.getElementById('openGroupBookmark.subtreeType-menulist');
- gGroupBookmarkBehaviorPref = document.getElementById('extensions.treestyletab.openGroupBookmark.behavior');
-}
-
-function init()
-{
- ensureGroupBookmarkItems();
-
-// sizeToContent();
-}
-
-
-function initAppearancePane()
-{
- onChangeTabbarPosition();
-
- var sidebar = document.getElementById('extensions.treestyletab.tabbar.style-sidebar');
- sidebar.removeAttribute('disabled');
-
- var boxes = [
- document.getElementById('extensions.treestyletab.tabbar.style-arrowscrollbox'),
- document.getElementById('extensions.treestyletab.twisty.style-arrowscrollbox')
- ];
- Array.slice(boxes[0].childNodes).concat(Array.slice(boxes[1].childNodes)).forEach(function(aItem) {
- let start = 0;
- let delta = 200;
- let radian = 90 * Math.PI / 180;
- aItem.style.overflow = 'hidden';
- aItem.width = 0;
- aItem.style.maxWidth = 0;
- let task = function(aTime, aBeginning, aChange, aDuration) {
- var width;
- if (aTime >= aDuration) {
- width = start + delta;
- finished = true;
- }
- else {
- width = start + (delta * Math.sin(aTime / aDuration * radian));
- finished = false;
- }
- aItem.removeAttribute('width');
- aItem.style.maxWidth = parseInt(width)+'px';
-
- var itemBox = aItem.boxObject;
- var parentBox = aItem.parentNode.boxObject;
- if (
- parentBox.screenX > itemBox.screenX ||
- parentBox.screenX + parentBox.width < itemBox.screenX + itemBox.width
- ) {
- aItem.parentNode.setAttribute('overflow', true);
- if (aItem.selected)
- aItem.parentNode.scrollBoxObject.ensureElementIsVisible(aItem);
- }
-
- if (finished) {
- start = null;
- delta = null;
- radian = null;
- aItem = null;
- }
- return finished;
- };
- animationManager.addTask(task, 0, 0, 500, window);
- });
-}
-
-
-var gDropLinksOnRadioSet,
- gGroupBookmarkRadioSet,
- gLastStateIsVertical;
-var gTabbarPlacePositionInitialized = false;
-
-function initTabPane()
-{
- gDropLinksOnTabRadioSet = new RadioSet(
- 'extensions.treestyletab.dropLinksOnTab.behavior',
- 'dropLinksOnTab-radiogroup',
- 'dropLinksOnTab-check',
- 'dropLinksOnTab-deck'
- );
- gGroupBookmarkRadioSet = new RadioSet(
- 'extensions.treestyletab.openGroupBookmark.behavior',
- 'openGroupBookmark-radiogroup',
- 'openGroupBookmark-check',
- 'openGroupBookmark-deck'
- );
-
- var newTabPref = document.getElementById('extensions.treestyletab.autoAttach.newTabButton-box');
- newTabPref.removeAttribute('hidden');
-}
-
-function onSyncGroupBookmarkUIToPref()
-{
- ensureGroupBookmarkItems();
- var behavior = gGroupBookmarkBehaviorPref.value;
- if (behavior & 1) behavior ^= 1;
- if (behavior & 2) behavior ^= 2;
- if (behavior & 4) behavior ^= 4;
- if (behavior & 256) behavior ^= 256;
- if (behavior & 512) behavior ^= 512;
-
- behavior |= parseInt(gGroupBookmarkRadio.value);
-
- if (gGroupBookmarkUnderParent.checked) behavior |= 256;
- if (gGroupBookmarkType.value == 'true') behavior |= 512;
-
- var nodes = [
- gGroupBookmarkUnderParent,
- gGroupBookmarkType,
- gGroupBookmarkType.previousSibling,
- gGroupBookmarkType.nextSibling
- ];
- for (let i = 0, maxi = nodes.length; i < maxi; i++)
- {
- let node = nodes[i];
- if (behavior & 1)
- node.removeAttribute('disabled');
- else
- node.setAttribute('disabled', true);
- }
-
- return behavior;
-}
-
-function onSyncGroupBookmarkPrefToUI()
-{
- ensureGroupBookmarkItems();
- var behavior = gGroupBookmarkBehaviorPref.value & 1 ? 1 :
- gGroupBookmarkBehaviorPref.value & 2 ? 2 :
- gGroupBookmarkBehaviorPref.value & 4 ? 4 :
- 0;
- gGroupBookmarkUnderParent.checked = !!(gGroupBookmarkBehaviorPref.value & 256);
- gGroupBookmarkType.value = gGroupBookmarkBehaviorPref.value & 512 ? 'true' : 'false' ;
- return behavior;
-}
-
-
-function onChangeTabbarPosition()
-{
- var pos = document.getElementById('extensions.treestyletab.tabbar.position-radiogroup').value;
- var invertTab = document.getElementById('extensions.treestyletab.tabbar.invertTab-check');
- var invertTabContents = document.getElementById('extensions.treestyletab.tabbar.invertTabContents-check');
- var invertClosebox = document.getElementById('extensions.treestyletab.tabbar.invertClosebox-check');
-
- invertTab.disabled = pos != 'right';
-// invertTabContents.disabled = pos != 'right';
- invertClosebox.setAttribute('label',
- invertClosebox.getAttribute(
- (pos == 'right' && invertTabContents.checked) ?
- 'label-right' :
- 'label-left'
- )
- );
- if (invertClosebox.checked != document.getElementById('extensions.treestyletab.tabbar.invertClosebox').defaultValue)
- invertClosebox.removeAttribute('collapsed');
- else
- invertClosebox.setAttribute('collapsed', true);
-
- var maxTreeLevelH = document.getElementById('maxTreeLevel-horizontal');
- var maxTreeLevelV = document.getElementById('maxTreeLevel-vertical');
- var collapseCheckH = document.getElementById('extensions.treestyletab.allowSubtreeCollapseExpand.horizontal-check');
- var collapseCheckV = document.getElementById('extensions.treestyletab.allowSubtreeCollapseExpand.vertical-check');
-
- if (pos == 'left' || pos == 'right') {
- maxTreeLevelH.setAttribute('collapsed', true);
- maxTreeLevelV.removeAttribute('collapsed');
- collapseCheckH.setAttribute('collapsed', true);
- collapseCheckV.removeAttribute('collapsed');
- }
- else {
- maxTreeLevelH.removeAttribute('collapsed');
- maxTreeLevelV.setAttribute('collapsed', true);
- collapseCheckH.removeAttribute('collapsed');
- collapseCheckV.setAttribute('collapsed', true);
- }
-
- gTabbarPlacePositionInitialized = true;
-}
-
-function onSyncMaxTreeLevelUIToPref(aTarget, aSetPrefValue)
-{
- aTarget = document.getElementById(aTarget);
- if (aTarget.sync)
- return;
- aTarget.sync = true;
-
- var textbox = aTarget.parentNode.getElementsByTagName('textbox')[0];
- var prefValue = aTarget.checked ? textbox.value : 0 ;
-
- if (aSetPrefValue)
- document.getElementById(aTarget.getAttribute('preference')).value = prefValue;
-
- aTarget.sync = false;
- return prefValue;
-}
-
-function onSyncMaxTreeLevelPrefToUI(aTarget)
-{
- aTarget = document.getElementById(aTarget);
- if (aTarget.sync)
- return;
- aTarget.sync = true;
-
- var pref = document.getElementById(aTarget.getAttribute('preference'));
- var value = pref.value;
- var UIValue = value != 0;
-
- var textbox = aTarget.parentNode.getElementsByTagName('textbox')[0];
-
- if (UIValue)
- textbox.value = value;
-
- syncEnabledState(aTarget, UIValue);
-
- aTarget.sync = false;
- return UIValue;
-}
-
-
-function initAutoHidePane()
-{
- syncEnabledState('extensions.treestyletab.tabbar.autoShow.mousemove-check', 'this.checked');
- syncEnabledState('extensions.treestyletab.tabbar.autoShow.accelKeyDown-check', 'this.checked');
- syncEnabledState('extensions.treestyletab.tabbar.autoShow.feedback-check', 'this.checked');
-}
-
-function onChangeAutoHideMode(aRadioGroup, aTogglePref)
-{
- if (aRadioGroup.value != 0)
- document.getElementById(aTogglePref).value = aRadioGroup.value;
-}
-
-
-function initTreePane()
-{
- syncEnabledState('extensions.treestyletab.closeParentBehavior-radiogroup', 'this.value == 0');
-
- var focusMode = document.getElementById('extensions.treestyletab.focusMode-check');
- var focusModePref = document.getElementById('extensions.treestyletab.focusMode');
- if (focusModePref.value != focusModePref.defaultValue)
- focusMode.removeAttribute('collapsed');
- else
- focusMode.setAttribute('collapsed', true);
-}
-
-
-var gBookmarkDroppedTabsRadioSet,
- gUndoCloseTabSetRadioSet;
-
-function initAdvancedPane()
-{
- gBookmarkDroppedTabsRadioSet = new RadioSet(
- 'extensions.treestyletab.bookmarkDroppedTabs.behavior',
- 'bookmarkDroppedTabs-radiogroup',
- 'bookmarkDroppedTabs-check',
- 'bookmarkDroppedTabs-deck'
- );
-
- gUndoCloseTabSetRadioSet = new RadioSet(
- 'extensions.treestyletab.undoCloseTabSet.behavior',
- 'undoCloseTabSet-radiogroup',
- 'undoCloseTabSet-check',
- 'undoCloseTabSet-deck',
- 1
- );
-}
-
-
-
-function RadioSet(aPref, aRadio, aCheck, aDeck, aAskFlag)
-{
- this.pref = document.getElementById(aPref);
- this.radio = document.getElementById(aRadio);
- this.check = document.getElementById(aCheck);
- this.deck = document.getElementById(aDeck);
- this.backup = this.value || 1;
- this.askValue = aAskFlag;
-
- if (this.askValue ? this.value & this.askValue : this.value == 0 ) {
- this.check.checked = true;
- this.deck.selectedIndex = 0;
- }
- else {
- this.check.checked = false;
- this.deck.selectedIndex = 1;
- }
-}
-RadioSet.prototype = {
- onChange : function(aDontUpdatePref)
- {
- if (this.checked) {
- this.backup = this.value;
- this.deck.selectedIndex = 0;
- if (this.askValue) {
- this.value |= this.askValue;
- }
- else {
- this.value = 0;
- }
- }
- else {
- this.deck.selectedIndex = 1;
- this.value = this.backup;
- if (this.askValue && this.value & this.askValue) {
- this.value ^= this.askValue;
- }
- }
- if (!aDontUpdatePref)
- this.pref.value = this.value;
- },
-
- get checked()
- {
- return this.check.checked;
- },
- set checked(aValue)
- {
- return this.check.checked = aValue;
- },
-
- get value()
- {
- return parseInt(this.radio.value);
- },
- set value(aValue)
- {
- return this.radio.value = aValue;
- }
-};
+Components.utils.import('resource://gre/modules/Services.jsm');
+
+const XULAppInfo = Services.appinfo;
+const comparator = Services.vc;
+var Prefs = Services.prefs;
+
+Components.utils.import('resource://treestyletab-modules/lib/animationManager.js', {});
+Components.utils.import('resource://treestyletab-modules/lib/prefs.js', {});
+Components.utils.import('resource://treestyletab-modules/lib/namespace.jsm');
+var animationManager = getNamespaceFor('piro.sakura.ne.jp')['piro.sakura.ne.jp'].animationManager;
+var prefs = getNamespaceFor('piro.sakura.ne.jp')['piro.sakura.ne.jp'].prefs;
+
+
+function syncEnabledState(aElement, aEnabled)
+{
+ if (typeof aElement == 'string')
+ aElement = document.getElementById(aElement);
+ if (typeof aEnabled == 'string')
+ aEnabled = (new Function('return '+aEnabled)).call(aElement);
+
+ aElement.getAttribute('sync-enabled-state-targets')
+ .replace(/$\s+|\s+$/g, '')
+ .split(/\s+/)
+ .map(function(aId) {
+ if (!aId)
+ return;
+ var target = document.getElementById(aId);
+ if (aEnabled)
+ target.removeAttribute('disabled');
+ else
+ target.setAttribute('disabled', true);
+ });
+}
+
+
+var gGroupBookmarkRadio,
+ gGroupBookmarkUnderParent,
+ gGroupBookmarkType,
+ gGroupBookmarkBehaviorPref;
+
+function ensureGroupBookmarkItems()
+{
+ if (gGroupBookmarkBehaviorPref) return;
+
+ gGroupBookmarkRadio = document.getElementById('openGroupBookmark-radiogroup');
+ gGroupBookmarkUnderParent = document.getElementById('openGroupBookmark.underParent-check');
+ gGroupBookmarkType = document.getElementById('openGroupBookmark.subtreeType-menulist');
+ gGroupBookmarkBehaviorPref = document.getElementById('extensions.treestyletab.openGroupBookmark.behavior');
+}
+
+function init()
+{
+ ensureGroupBookmarkItems();
+
+// sizeToContent();
+}
+
+
+function initAppearancePane()
+{
+ onChangeTabbarPosition();
+
+ var sidebar = document.getElementById('extensions.treestyletab.tabbar.style-sidebar');
+ sidebar.removeAttribute('disabled');
+
+ var boxes = [
+ document.getElementById('extensions.treestyletab.tabbar.style-arrowscrollbox'),
+ document.getElementById('extensions.treestyletab.twisty.style-arrowscrollbox')
+ ];
+ Array.slice(boxes[0].childNodes).concat(Array.slice(boxes[1].childNodes)).forEach(function(aItem) {
+ let start = 0;
+ let delta = 200;
+ let radian = 90 * Math.PI / 180;
+ aItem.style.overflow = 'hidden';
+ aItem.width = 0;
+ aItem.style.maxWidth = 0;
+ let task = function(aTime, aBeginning, aChange, aDuration) {
+ var width;
+ if (aTime >= aDuration) {
+ width = start + delta;
+ finished = true;
+ }
+ else {
+ width = start + (delta * Math.sin(aTime / aDuration * radian));
+ finished = false;
+ }
+ aItem.removeAttribute('width');
+ aItem.style.maxWidth = parseInt(width)+'px';
+
+ var itemBox = aItem.boxObject;
+ var parentBox = aItem.parentNode.boxObject;
+ if (
+ parentBox.screenX > itemBox.screenX ||
+ parentBox.screenX + parentBox.width < itemBox.screenX + itemBox.width
+ ) {
+ aItem.parentNode.setAttribute('overflow', true);
+ if (aItem.selected)
+ aItem.parentNode.scrollBoxObject.ensureElementIsVisible(aItem);
+ }
+
+ if (finished) {
+ start = null;
+ delta = null;
+ radian = null;
+ aItem = null;
+ }
+ return finished;
+ };
+ animationManager.addTask(task, 0, 0, 500, window);
+ });
+}
+
+
+var gDropLinksOnRadioSet,
+ gGroupBookmarkRadioSet,
+ gLastStateIsVertical;
+var gTabbarPlacePositionInitialized = false;
+
+function initTabPane()
+{
+ gDropLinksOnTabRadioSet = new RadioSet(
+ 'extensions.treestyletab.dropLinksOnTab.behavior',
+ 'dropLinksOnTab-radiogroup',
+ 'dropLinksOnTab-check',
+ 'dropLinksOnTab-deck'
+ );
+ gGroupBookmarkRadioSet = new RadioSet(
+ 'extensions.treestyletab.openGroupBookmark.behavior',
+ 'openGroupBookmark-radiogroup',
+ 'openGroupBookmark-check',
+ 'openGroupBookmark-deck'
+ );
+
+ var newTabPref = document.getElementById('extensions.treestyletab.autoAttach.newTabButton-box');
+ newTabPref.removeAttribute('hidden');
+}
+
+function onSyncGroupBookmarkUIToPref()
+{
+ ensureGroupBookmarkItems();
+ var behavior = gGroupBookmarkBehaviorPref.value;
+ if (behavior & 1) behavior ^= 1;
+ if (behavior & 2) behavior ^= 2;
+ if (behavior & 4) behavior ^= 4;
+ if (behavior & 256) behavior ^= 256;
+ if (behavior & 512) behavior ^= 512;
+
+ behavior |= parseInt(gGroupBookmarkRadio.value);
+
+ if (gGroupBookmarkUnderParent.checked) behavior |= 256;
+ if (gGroupBookmarkType.value == 'true') behavior |= 512;
+
+ var nodes = [
+ gGroupBookmarkUnderParent,
+ gGroupBookmarkType,
+ gGroupBookmarkType.previousSibling,
+ gGroupBookmarkType.nextSibling
+ ];
+ for (let i = 0, maxi = nodes.length; i < maxi; i++)
+ {
+ let node = nodes[i];
+ if (behavior & 1)
+ node.removeAttribute('disabled');
+ else
+ node.setAttribute('disabled', true);
+ }
+
+ return behavior;
+}
+
+function onSyncGroupBookmarkPrefToUI()
+{
+ ensureGroupBookmarkItems();
+ var behavior = gGroupBookmarkBehaviorPref.value & 1 ? 1 :
+ gGroupBookmarkBehaviorPref.value & 2 ? 2 :
+ gGroupBookmarkBehaviorPref.value & 4 ? 4 :
+ 0;
+ gGroupBookmarkUnderParent.checked = !!(gGroupBookmarkBehaviorPref.value & 256);
+ gGroupBookmarkType.value = gGroupBookmarkBehaviorPref.value & 512 ? 'true' : 'false' ;
+ return behavior;
+}
+
+
+function onChangeTabbarPosition()
+{
+ var pos = document.getElementById('extensions.treestyletab.tabbar.position-radiogroup').value;
+ var invertTab = document.getElementById('extensions.treestyletab.tabbar.invertTab-check');
+ var invertTabContents = document.getElementById('extensions.treestyletab.tabbar.invertTabContents-check');
+ var invertClosebox = document.getElementById('extensions.treestyletab.tabbar.invertClosebox-check');
+
+ invertTab.disabled = pos != 'right';
+// invertTabContents.disabled = pos != 'right';
+ invertClosebox.setAttribute('label',
+ invertClosebox.getAttribute(
+ (pos == 'right' && invertTabContents.checked) ?
+ 'label-right' :
+ 'label-left'
+ )
+ );
+ if (invertClosebox.checked != document.getElementById('extensions.treestyletab.tabbar.invertClosebox').defaultValue)
+ invertClosebox.removeAttribute('collapsed');
+ else
+ invertClosebox.setAttribute('collapsed', true);
+
+ var maxTreeLevelH = document.getElementById('maxTreeLevel-horizontal');
+ var maxTreeLevelV = document.getElementById('maxTreeLevel-vertical');
+ var collapseCheckH = document.getElementById('extensions.treestyletab.allowSubtreeCollapseExpand.horizontal-check');
+ var collapseCheckV = document.getElementById('extensions.treestyletab.allowSubtreeCollapseExpand.vertical-check');
+
+ if (pos == 'left' || pos == 'right') {
+ maxTreeLevelH.setAttribute('collapsed', true);
+ maxTreeLevelV.removeAttribute('collapsed');
+ collapseCheckH.setAttribute('collapsed', true);
+ collapseCheckV.removeAttribute('collapsed');
+ }
+ else {
+ maxTreeLevelH.removeAttribute('collapsed');
+ maxTreeLevelV.setAttribute('collapsed', true);
+ collapseCheckH.removeAttribute('collapsed');
+ collapseCheckV.setAttribute('collapsed', true);
+ }
+
+ gTabbarPlacePositionInitialized = true;
+}
+
+function onSyncMaxTreeLevelUIToPref(aTarget, aSetPrefValue)
+{
+ aTarget = document.getElementById(aTarget);
+ if (aTarget.sync)
+ return;
+ aTarget.sync = true;
+
+ var textbox = aTarget.parentNode.getElementsByTagName('textbox')[0];
+ var prefValue = aTarget.checked ? textbox.value : 0 ;
+
+ if (aSetPrefValue)
+ document.getElementById(aTarget.getAttribute('preference')).value = prefValue;
+
+ aTarget.sync = false;
+ return prefValue;
+}
+
+function onSyncMaxTreeLevelPrefToUI(aTarget)
+{
+ aTarget = document.getElementById(aTarget);
+ if (aTarget.sync)
+ return;
+ aTarget.sync = true;
+
+ var pref = document.getElementById(aTarget.getAttribute('preference'));
+ var value = pref.value;
+ var UIValue = value != 0;
+
+ var textbox = aTarget.parentNode.getElementsByTagName('textbox')[0];
+
+ if (UIValue)
+ textbox.value = value;
+
+ syncEnabledState(aTarget, UIValue);
+
+ aTarget.sync = false;
+ return UIValue;
+}
+
+
+function initAutoHidePane()
+{
+ syncEnabledState('extensions.treestyletab.tabbar.autoShow.mousemove-check', 'this.checked');
+ syncEnabledState('extensions.treestyletab.tabbar.autoShow.accelKeyDown-check', 'this.checked');
+ syncEnabledState('extensions.treestyletab.tabbar.autoShow.feedback-check', 'this.checked');
+}
+
+function onChangeAutoHideMode(aRadioGroup, aTogglePref)
+{
+ if (aRadioGroup.value != 0)
+ document.getElementById(aTogglePref).value = aRadioGroup.value;
+}
+
+
+function initTreePane()
+{
+ syncEnabledState('extensions.treestyletab.closeParentBehavior-radiogroup', 'this.value == 0');
+
+ var focusMode = document.getElementById('extensions.treestyletab.focusMode-check');
+ var focusModePref = document.getElementById('extensions.treestyletab.focusMode');
+ if (focusModePref.value != focusModePref.defaultValue)
+ focusMode.removeAttribute('collapsed');
+ else
+ focusMode.setAttribute('collapsed', true);
+}
+
+
+var gBookmarkDroppedTabsRadioSet,
+ gUndoCloseTabSetRadioSet;
+
+function initAdvancedPane()
+{
+ gBookmarkDroppedTabsRadioSet = new RadioSet(
+ 'extensions.treestyletab.bookmarkDroppedTabs.behavior',
+ 'bookmarkDroppedTabs-radiogroup',
+ 'bookmarkDroppedTabs-check',
+ 'bookmarkDroppedTabs-deck'
+ );
+
+ gUndoCloseTabSetRadioSet = new RadioSet(
+ 'extensions.treestyletab.undoCloseTabSet.behavior',
+ 'undoCloseTabSet-radiogroup',
+ 'undoCloseTabSet-check',
+ 'undoCloseTabSet-deck',
+ 1
+ );
+}
+
+
+
+function RadioSet(aPref, aRadio, aCheck, aDeck, aAskFlag)
+{
+ this.pref = document.getElementById(aPref);
+ this.radio = document.getElementById(aRadio);
+ this.check = document.getElementById(aCheck);
+ this.deck = document.getElementById(aDeck);
+ this.backup = this.value || 1;
+ this.askValue = aAskFlag;
+
+ if (this.askValue ? this.value & this.askValue : this.value == 0 ) {
+ this.check.checked = true;
+ this.deck.selectedIndex = 0;
+ }
+ else {
+ this.check.checked = false;
+ this.deck.selectedIndex = 1;
+ }
+}
+RadioSet.prototype = {
+ onChange : function(aDontUpdatePref)
+ {
+ if (this.checked) {
+ this.backup = this.value;
+ this.deck.selectedIndex = 0;
+ if (this.askValue) {
+ this.value |= this.askValue;
+ }
+ else {
+ this.value = 0;
+ }
+ }
+ else {
+ this.deck.selectedIndex = 1;
+ this.value = this.backup;
+ if (this.askValue && this.value & this.askValue) {
+ this.value ^= this.askValue;
+ }
+ }
+ if (!aDontUpdatePref)
+ this.pref.value = this.value;
+ },
+
+ get checked()
+ {
+ return this.check.checked;
+ },
+ set checked(aValue)
+ {
+ return this.check.checked = aValue;
+ },
+
+ get value()
+ {
+ return parseInt(this.radio.value);
+ },
+ set value(aValue)
+ {
+ return this.radio.value = aValue;
+ }
+};
diff --git a/content/treestyletab/config.xul b/content/treestyletab/config.xul
index 43ef83a5..0854fa81 100644
--- a/content/treestyletab/config.xul
+++ b/content/treestyletab/config.xul
@@ -1,795 +1,795 @@
-
-
-
-
-
-
-%mainDTD;
-]>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+%mainDTD;
+]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/content/treestyletab/group.xul b/content/treestyletab/group.xul
index 2e53cc03..682e3ab4 100644
--- a/content/treestyletab/group.xul
+++ b/content/treestyletab/group.xul
@@ -1,50 +1,50 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/content/treestyletab/hide-embed.css b/content/treestyletab/hide-embed.css
index 13cb6c2a..6dce1c77 100644
--- a/content/treestyletab/hide-embed.css
+++ b/content/treestyletab/hide-embed.css
@@ -1,5 +1,5 @@
-@namespace url("http://www.w3.org/1999/xhtml");
-
-body > embed[name="plugin"] {
- visibility: hidden !important;
-}
+@namespace url("http://www.w3.org/1999/xhtml");
+
+body > embed[name="plugin"] {
+ visibility: hidden !important;
+}
diff --git a/content/treestyletab/license.txt b/content/treestyletab/license.txt
index eeda95cd..0a245b03 100644
--- a/content/treestyletab/license.txt
+++ b/content/treestyletab/license.txt
@@ -1,35 +1,35 @@
-***** BEGIN LICENSE BLOCK *****
-Version: MPL 1.1/GPL 2.0/LGPL 2.1
-
-The contents of these files are subject to the Mozilla Public License Version
-1.1 (the "License"); you may not use these files 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 YUKI "Piro" Hiroshi.
-Portions created by the Initial Developer are Copyright (C) 2007-2014
-the Initial Developer. All Rights Reserved.
-
-Contributor(s): YUKI "Piro" Hiroshi
- Alice0775 (fixes some compatibility problems)
-
-Alternatively, the contents of these files 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 these files only
-under the terms of either the GPL or the LGPL, and not to allow others to
-use your version of these files 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 these files under
-the terms of any one of the MPL, the GPL or the LGPL.
-
-***** END LICENSE BLOCK *****
+***** BEGIN LICENSE BLOCK *****
+Version: MPL 1.1/GPL 2.0/LGPL 2.1
+
+The contents of these files are subject to the Mozilla Public License Version
+1.1 (the "License"); you may not use these files 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 YUKI "Piro" Hiroshi.
+Portions created by the Initial Developer are Copyright (C) 2007-2014
+the Initial Developer. All Rights Reserved.
+
+Contributor(s): YUKI "Piro" Hiroshi
+ Alice0775 (fixes some compatibility problems)
+
+Alternatively, the contents of these files 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 these files only
+under the terms of either the GPL or the LGPL, and not to allow others to
+use your version of these files 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 these files under
+the terms of any one of the MPL, the GPL or the LGPL.
+
+***** END LICENSE BLOCK *****
diff --git a/content/treestyletab/multipletabConfigOverlay.xul b/content/treestyletab/multipletabConfigOverlay.xul
index d50f2fe4..a2ac3a0c 100644
--- a/content/treestyletab/multipletabConfigOverlay.xul
+++ b/content/treestyletab/multipletabConfigOverlay.xul
@@ -1,22 +1,22 @@
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
diff --git a/content/treestyletab/treestyletab-tmp.css b/content/treestyletab/treestyletab-tmp.css
index a03f5037..8f6b96af 100644
--- a/content/treestyletab/treestyletab-tmp.css
+++ b/content/treestyletab/treestyletab-tmp.css
@@ -1,33 +1,33 @@
-@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
-
-/* hacks for Tab Mix Plus */
-
-:root[treestyletab-enable-compatibility-tmp="true"]
- tabbrowser[treestyletab-mode="vertical"] #vide-bar,
-:root[treestyletab-enable-compatibility-tmp="true"]
- tabbrowser[treestyletab-mode="vertical"] #tabs-scroll-up-down-box,
-:root[treestyletab-enable-compatibility-tmp="true"]
- tabbrowser[treestyletab-mode="vertical"] #alltabs-place-holder,
-:root[treestyletab-enable-compatibility-tmp="true"]
- tabbrowser[treestyletab-mode="vertical"] .tabs-scroll {
- visibility: collapse !important;
-}
-
-:root[treestyletab-enable-compatibility-tmp="true"]
- tabbrowser[treestyletab-mode="vertical"] tabs[flowing] > * .tabs-frame {
- overflow-x: hidden !important;
- overflow-y: auto !important;
-}
-
-:root[treestyletab-enable-compatibility-tmp="true"]
- tabbrowser[treestyletab-mode="vertical"] tabs[flowing] > * .tabs-frame {
- box-flex: 1 !important;
- -moz-box-flex: 1 !important;
-}
-
-.tabbrowser-tab[pinned] > .tab-image-left,
-.tabbrowser-tab[pinned] > .tab-drag-indicator-left,
-.tabbrowser-tab[pinned] > .tab-drag-indicator-right,
-.tabbrowser-tab[pinned] > .tab-image-right {
- display: none;
-}
+@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
+
+/* hacks for Tab Mix Plus */
+
+:root[treestyletab-enable-compatibility-tmp="true"]
+ tabbrowser[treestyletab-mode="vertical"] #vide-bar,
+:root[treestyletab-enable-compatibility-tmp="true"]
+ tabbrowser[treestyletab-mode="vertical"] #tabs-scroll-up-down-box,
+:root[treestyletab-enable-compatibility-tmp="true"]
+ tabbrowser[treestyletab-mode="vertical"] #alltabs-place-holder,
+:root[treestyletab-enable-compatibility-tmp="true"]
+ tabbrowser[treestyletab-mode="vertical"] .tabs-scroll {
+ visibility: collapse !important;
+}
+
+:root[treestyletab-enable-compatibility-tmp="true"]
+ tabbrowser[treestyletab-mode="vertical"] tabs[flowing] > * .tabs-frame {
+ overflow-x: hidden !important;
+ overflow-y: auto !important;
+}
+
+:root[treestyletab-enable-compatibility-tmp="true"]
+ tabbrowser[treestyletab-mode="vertical"] tabs[flowing] > * .tabs-frame {
+ box-flex: 1 !important;
+ -moz-box-flex: 1 !important;
+}
+
+.tabbrowser-tab[pinned] > .tab-image-left,
+.tabbrowser-tab[pinned] > .tab-drag-indicator-left,
+.tabbrowser-tab[pinned] > .tab-drag-indicator-right,
+.tabbrowser-tab[pinned] > .tab-image-right {
+ display: none;
+}
diff --git a/content/treestyletab/treestyletab.css b/content/treestyletab/treestyletab.css
index 5e31618a..dc353f0c 100644
--- a/content/treestyletab/treestyletab.css
+++ b/content/treestyletab/treestyletab.css
@@ -1,691 +1,691 @@
-@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
-@namespace html url("http://www.w3.org/1999/xhtml");
-
-
-/* twisty in tabs */
-.treestyletab-twisty,
-.tabbrowser-tabs:not([treestyletab-allow-subtree-collapse="true"])
- .treestyletab-twisty {
- visibility: hidden;
-}
-.tabbrowser-tabs[treestyletab-mode="vertical"][treestyletab-allow-subtree-collapse="true"]:not([treestyletab-twisty-style="none"])
- .tabbrowser-tab[treestyletab-children][treestyletab-allow-subtree-collapse="true"]
- .treestyletab-twisty,
-.tabbrowser-tabs[treestyletab-mode="horizontal"][treestyletab-allow-subtree-collapse="true"]:not([treestyletab-twisty-style="none"])
- .tabbrowser-tab[treestyletab-children][treestyletab-allow-subtree-collapse="true"]
- .treestyletab-twisty {
- visibility: visible;
-}
-.tabbrowser-tabs[treestyletab-twisty-style="none"]
- .treestyletab-twisty,
-.tabbrowser-tabs[treestyletab-mode="horizontal"]
- .treestyletab-twisty,
-.tabbrowser-tab[pinned="true"]
- .treestyletab-twisty {
- visibility: collapse;
-}
-
-/* collapsed children counter */
-.treestyletab-counter-container {
- display: none;
-}
-.tabbrowser-tabs[treestyletab-allow-subtree-collapse="true"]
- .tabbrowser-tab[treestyletab-children][treestyletab-subtree-collapsed="true"][treestyletab-allow-subtree-collapse="true"]
- .treestyletab-counter-container {
- display: -moz-box;
-}
-
-/* collapse/expand tree of tabs */
-.tabbrowser-tabs[treestyletab-allow-subtree-collapse="true"]
- .tabbrowser-tab[treestyletab-collapsed-done="true"] {
- visibility: collapse;
-}
-
-/* collapse/expand tree of tabs, horizontal stacked tabs */
-.tabbrowser-tabs[treestyletab-allow-subtree-collapse="true"][treestyletab-stack-collapsed-tabs="true"]
- .tabbrowser-tab {
- position: relative;
-}
-.tabbrowser-tabs[treestyletab-allow-subtree-collapse="true"][treestyletab-stack-collapsed-tabs="true"]
- .tabbrowser-tab[treestyletab-collapsed="true"][fadein],
-/**
- * Tab Mix Plus dynamically inserts a CSS rule like
- * "#tabbrowser-tabs > .tabbrowser-tab { ... }" and it unexpectedly
- * expands width of "collapsed" tabs. So, to apply our rule prior than
- * TMP's one, I put the "#tabbrowser-tabs" version also.
- */
-#tabbrowser-tabs[treestyletab-allow-subtree-collapse="true"][treestyletab-stack-collapsed-tabs="true"]
- .tabbrowser-tab[treestyletab-collapsed="true"][fadein] {
- visibility: visible;
- max-width: 20px;
- min-width: 20px;
- width: 20px;
- box-flex: 0;
- -moz-box-flex: 0;
- mask: url("res/tabEffects.svg#fadein-mask");
-}
-.tabbrowser-tabs[treestyletab-allow-subtree-collapse="true"][treestyletab-stack-collapsed-tabs="true"]
- .tabbrowser-tab[treestyletab-collapsed-done="true"] .tab-content > * {
- visibility: collapse;
-}
-
-/* fixed tab bar */
-.tabbrowser-strip[treestyletab-tabbar-fixed="true"]+splitter {
- visibility: collapse;
-}
-
-
-/* tab bar in the DOM-fullscreen mode */
-
-.tabbrowser-tabs[treestyletab-dom-fullscreen-activated="true"],
-.tabbrowser-strip[treestyletab-dom-fullscreen-activated="true"],
-.tabbrowser-strip[treestyletab-dom-fullscreen-activated="true"]+splitter,
-.treestyletab-tabbar-toolbar[treestyletab-dom-fullscreen-activated="true"],
-.treestyletab-tabbar-toolbar[treestyletab-dom-fullscreen-activated="true"] > *,
-tabbrowser[treestyletab-dom-fullscreen-activated-mode="true"][tabcontainer]
- .tabbrowser-strip.treestyletab-tabbar-placeholder,
-tabbrowser[treestyletab-dom-fullscreen-activated-mode="true"][tabcontainer]
- .tabbrowser-strip.treestyletab-tabbar-placeholder+splitter {
- visibility: collapse;
-}
-
-
-/* auto hide tab bar */
-
-.tabbrowser-tabs[treestyletab-tabbar-autohide="hidden"],
-.tabbrowser-strip[treestyletab-tabbar-autohide="hidden"],
-.tabbrowser-strip[treestyletab-tabbar-autohide="hidden"]+splitter,
-.tabbrowser-strip[collapsed="true"] + splitter:not([state="collapsed"]),
-.treestyletab-tabbar-toggler,
-.treestyletab-tabbar-toolbar[treestyletab-tabbar-autohide="hidden"],
-.treestyletab-tabbar-toolbar[treestyletab-tabbar-autohide="hidden"] > *,
-.treestyletab-tabbar-toolbar .treestyletab-splitter,
-#treestyletab-tabbar-resizer-box,
-tabbrowser[treestyletab-tabbar-autohide-mode="1"][tabcontainer]
- .tabbrowser-strip.treestyletab-tabbar-placeholder,
-tabbrowser[treestyletab-tabbar-autohide-mode="1"][tabcontainer]
- .tabbrowser-strip.treestyletab-tabbar-placeholder+splitter {
- visibility: collapse;
-}
-
-tabbrowser[treestyletab-tabbar-autohide-mode="1"][tabcontainer]
- .treestyletab-tabbar-toggler,
-tabbrowser[treestyletab-tabbar-autohide-mode="1"][treestyletab-tabbar-autohide="hidden"]
- .treestyletab-tabbar-toggler,
-.treestyletab-tabbar-toolbar[treestyletab-mode="vertical"][treestyletab-tabbar-autohide][treestyletab-tabbar-autohide-state="expanded"]
- #treestyletab-tabbar-resizer-box,
-.treestyletab-tabbar-toolbar[treestyletab-mode="vertical"][treestyletab-tabbar-autohide][treestyletab-tabbar-autohide-state="expanded"]:not([treestyletab-tabbar-fixed="true"])
- .treestyletab-splitter {
- visibility: visible;
-}
-
-/* put resizer under tabs, and raise up tabs */
-.treestyletab-tabbar-toolbar[treestyletab-mode="vertical"][treestyletab-tabbar-autohide]
- > *,
-.treestyletab-tabbar-toolbar[treestyletab-mode="vertical"][treestyletab-tabbar-autohide]
- > #tabbrowser-tabs,
-.treestyletab-toolbar-inner-box[treestyletab-tabbar-autohide]:not([treestyletab-tabbar-fixed="true"])
- > *,
-.treestyletab-toolbar-inner-box[treestyletab-tabbar-autohide]:not([treestyletab-tabbar-fixed="true"])
- > #tabbrowser-tabs {
- position: relative;
- z-index: 2;
-}
-.treestyletab-tabbar-toolbar[treestyletab-mode="vertical"][treestyletab-tabbar-autohide]
- #treestyletab-tabbar-resizer-box {
- position: absolute;
- bottom: 0;
- left: 0;
- right: 0;
- top: 0;
- z-index: 1;
- line-height: 0 !important; /* to avoid an useless space above the splitter */
- font-size: 0 !important; /* to avoid an useless space above the splitter */
-}
-
-.tabbrowser-tabs[treestyletab-tabbar-autohide]
- .tabs-stack
- > *:first-child
- > :not(html|canvas),
-.tabbrowser-tabs[treestyletab-tabbar-resizing]
- .tabs-stack
- > *:first-child
- > html|canvas {
- display: none !important;
-}
-
-
-#treestyletab-autohide-content-area-screen {
- appearance: none;
- -moz-appearance: none;
- /**
- * Don't make this panel completely transparent, because
- * mousemove event never fire on 100% transparent panel.
- * The color should be a pale white, instead of a pale black,
- * because many websites use white background. Black screen
- * is too glaring for white background websites.
- */
- background: rgba(255, 255, 255, 0.01);
- line-height: 0;
- margin: 0;
- padding: 0;
- -moz-border-bottom-colors: none;
- -moz-border-left-colors: none;
- -moz-border-right-colors: none;
- -moz-border-top-colors: none;
-}
-
-
-/* vertical tab bar */
-
-.tabbrowser-tabs[treestyletab-mode="vertical"]
- .tabbrowser-arrowscrollbox > scrollbox {
- overflow-x: hidden !important;
- overflow-y: auto !important;
-}
-
-.tabbrowser-tabs[treestyletab-mode="vertical"]
- .tabbrowser-arrowscrollbox
- .scrollbox-innerbox {
- box-flex: 1 !important;
- -moz-box-flex: 1 !important;
- box-pack: start !important;
- -moz-box-pack: start !important;
-}
-
-.tabbrowser-tabs[treestyletab-mode="vertical"]
- .tabbrowser-tab,
-toolbar.treestyletab-tabbar-toolbar[treestyletab-mode="vertical"]
- > toolbarbutton,
-toolbar.treestyletab-tabbar-toolbar[treestyletab-mode="vertical"]
- > .treestyletab-toolbar-inner-box > toolbarbutton,
-toolbar.treestyletab-tabbar-toolbar[treestyletab-mode="vertical"]
- > toolbaritem,
-toolbar.treestyletab-tabbar-toolbar[treestyletab-mode="vertical"]
- > .treestyletab-toolbar-inner-box > toolbaritem {
- box-flex: 0 !important;
- -moz-box-flex: 0 !important;
-}
-
-.treestyletab-tabbar-toolbar[treestyletab-mode="vertical"] > toolbarbutton,
-.treestyletab-tabbar-toolbar[treestyletab-mode="vertical"] > toolbarpaletteitem > toolbarbutton {
- max-width: none !important;
-}
-
-/* workaround for https://github.com/piroor/treestyletab/issues/100 */
-.treestyletab-tabbar-toolbar[treestyletab-mode="vertical"] .textbox-input-box {
- box-align: stretch;
- -moz-box-align: stretch;
-}
-
-
-/* leftside vertical tab bar */
-
-tabs.tabbrowser-tabs[treestyletab-tabbar-position="left"][treestyletab-invert-scrollbar="true"]
- .tabbrowser-arrowscrollbox
- > scrollbox {
- direction: rtl;
-}
-tabs.tabbrowser-tabs[treestyletab-tabbar-position="left"][treestyletab-invert-scrollbar="true"]
- .tabbrowser-arrowscrollbox
- > scrollbox
- > .scrollbox-innerbox {
- direction: ltr;
-}
-
-
-/* hide horizontal tab bar UI for vertical tab bar */
-.tabbrowser-tabs[treestyletab-mode="vertical"] .tabbrowser-arrowscrollbox > .scrollbutton-up,
-.tabbrowser-tabs[treestyletab-mode="vertical"] .tabbrowser-arrowscrollbox > .scrollbutton-down:not([treestyletab-notifybgtab-phase]),
-.tabbrowser-tabs[treestyletab-mode="vertical"] .tabs-closebutton-box,
-.tabbrowser-tabs[treestyletab-mode="vertical"] .tab-drop-indicator-bar {
- visibility: collapse !important;
-}
-
-/**
- * Firefox 4.0 finishes opening and closing processes of tabs by its
- * "transitionend" events about max-width property. I think this is very
- * dirty and specific implementation but it won't fixed.
- * (See: https://bugzilla.mozilla.org/show_bug.cgi?id=585417#c3 )
- * So we have to define max-width for both states [fadein] (means "completely
- * opened") and :not([fadein]) (means "in opening/removing process".
- */
-.tabbrowser-tabs[treestyletab-mode="vertical"]
- .tabbrowser-tab:not([pinned]) {
- max-width: 65000px !important;
-}
-.treestyletab-tabbar-toolbar[treestyletab-mode="vertical"]
- .tabbrowser-tab:not([pinned]):not([fadein]) {
- opacity: 0.5 !important;
-}
-.tabbrowser-tabs[treestyletab-mode="vertical"]
- .tabbrowser-tab:not([pinned])[fadein] {
- max-width: 65250px !important;
- min-width: 1px !important;
-}
-.treestyletab-tabbar-toolbar[treestyletab-mode="vertical"][treestyletab-animation-enabled="true"]
- .tabbrowser-tab:not([pinned]):not([fadein])[treestyletab-removed="true"] {
- max-height: 1px !important;
- min-height: 1px !important;
- opacity: 0 !important;
- /**
- * Sometimes "transitionend" event for "max-width" doesn't fire so ghotst
- * tabs are left. To do cleanup process forcedly, we have to re-define new
- * max-width to fire transitionend event.
- */
- max-width: 64000px !important;
-}
-
-/* override toolbar binding */
-/**
- * Don't use :-moz-any() selector to override styles defined by the theme.
- * Normal selectors in default theme is stronger than :-moz-any() even if
- * it includes #TabsToolbar in its subqueries.
- */
-@media all and (-moz-windows-compositor) { /* for winstripe */
- #navigator-toolbox
- > .treestyletab-tabbar-toolbar:not(#toolbar-menubar),
- #navigator-toolbox
- > .treestyletab-tabbar-toolbar:not(#toolbar-menubar):-moz-lwtheme,
- #navigator-toolbox
- > .treestyletab-tabbar-toolbar-ready:not(#toolbar-menubar),
- #navigator-toolbox
- > .treestyletab-tabbar-toolbar-ready:not(#toolbar-menubar):-moz-lwtheme,
- #navigator-toolbox[tabsontop="true"]
- > .treestyletab-tabbar-toolbar:not(#toolbar-menubar),
- #navigator-toolbox[tabsontop="true"]
- > .treestyletab-tabbar-toolbar:not(#toolbar-menubar):-moz-lwtheme,
- #navigator-toolbox[tabsontop="true"]
- > .treestyletab-tabbar-toolbar-ready:not(#toolbar-menubar),
- #navigator-toolbox[tabsontop="true"]
- > .treestyletab-tabbar-toolbar-ready:not(#toolbar-menubar):-moz-lwtheme,
-
- #navigator-toolbox
- > #nav-bar + #customToolbars + #PersonalToolbar[collapsed="true"]
- + .treestyletab-tabbar-toolbar:last-child,
- #navigator-toolbox
- > #nav-bar + #customToolbars + #PersonalToolbar[collapsed="true"]
- + .treestyletab-tabbar-toolbar:not(:last-child),
- #navigator-toolbox
- > #nav-bar + #customToolbars + #PersonalToolbar[collapsed="true"]
- + .treestyletab-tabbar-toolbar[tabsontop="true"]:last-child,
- #navigator-toolbox
- > #nav-bar + #customToolbars + #PersonalToolbar[collapsed="true"]
- + .treestyletab-tabbar-toolbar[tabsontop="true"]:not(:last-child),
- #navigator-toolbox
- > #nav-bar + #customToolbars + #PersonalToolbar[collapsed="true"]
- + .treestyletab-tabbar-toolbar[tabsontop="false"]:last-child,
- #navigator-toolbox
- > #nav-bar + #customToolbars + #PersonalToolbar[collapsed="true"]
- + .treestyletab-tabbar-toolbar[tabsontop="false"]:not(:last-child),
- #navigator-toolbox
- > #nav-bar + #customToolbars + #PersonalToolbar[collapsed="true"]
- + .treestyletab-tabbar-toolbar-ready:last-child,
- #navigator-toolbox
- > #nav-bar + #customToolbars + #PersonalToolbar[collapsed="true"]
- + .treestyletab-tabbar-toolbar-ready:not(:last-child),
- #navigator-toolbox
- > #nav-bar + #customToolbars + #PersonalToolbar[collapsed="true"]
- + .treestyletab-tabbar-toolbar-ready[tabsontop="true"]:last-child,
- #navigator-toolbox
- > #nav-bar + #customToolbars + #PersonalToolbar[collapsed="true"]
- + .treestyletab-tabbar-toolbar-ready[tabsontop="true"]:not(:last-child),
- #navigator-toolbox
- > #nav-bar + #customToolbars + #PersonalToolbar[collapsed="true"]
- + .treestyletab-tabbar-toolbar-ready[tabsontop="false"]:last-child,
- #navigator-toolbox
- > #nav-bar + #customToolbars + #PersonalToolbar[collapsed="true"]
- + .treestyletab-tabbar-toolbar-ready[tabsontop="false"]:not(:last-child),
-
- #navigator-toolbox
- > .treestyletab-tabbar-toolbar:not(#toolbar-menubar):-moz-lwtheme,
- #navigator-toolbox
- > .treestyletab-tabbar-toolbar-ready:not(#toolbar-menubar):-moz-lwtheme,
-
- #navigator-toolbox
- > #nav-bar + #customToolbars + #PersonalToolbar[collapsed="true"]
- + #TabsToolbar:last-child,
- #navigator-toolbox
- > #nav-bar + #customToolbars + #PersonalToolbar[collapsed="true"]
- + #TabsToolbar:not(:last-child),heme,
- #navigator-toolbox
- > #nav-bar + #customToolbars + #PersonalToolbar[collapsed="true"]
- + #TabsToolbar[tabsontop="true"]:last-child,
- #navigator-toolbox
- > #nav-bar + #customToolbars + #PersonalToolbar[collapsed="true"]
- + #TabsToolbar[tabsontop="true"]:not(:last-child),
- #navigator-toolbox
- > #nav-bar + #customToolbars + #PersonalToolbar[collapsed="true"]
- + #TabsToolbar[tabsontop="false"]:last-child,
- #navigator-toolbox
- > #nav-bar + #customToolbars + #PersonalToolbar[collapsed="true"]
- + #TabsToolbar[tabsontop="false"]:not(:last-child),
-
- #navigator-toolbox
- > toolbar:not(#toolbar-menubar):not(#addon-bar):-moz-lwtheme {
- -moz-binding: url(treestyletab.xml#toolbar-drag);
- }
-}
-@media not all and (-moz-windows-compositor) { /* for winstripe */
- #TabsToolbar:not(:-moz-lwtheme):-moz-system-metric(windows-default-theme),
- #TabsToolbar[tabsontop="true"]:not(:-moz-lwtheme):-moz-system-metric(windows-default-theme),
- #navigator-toolbox[tabsontop="false"]
- > toolbar.treestyletab-tabbar-toolbar:not(#toolbar-menubar):not(:-moz-lwtheme):-moz-system-metric(windows-default-theme),
- #navigator-toolbox[tabsontop="false"]
- > toolbar.treestyletab-tabbar-toolbar-ready:not(#toolbar-menubar):not(:-moz-lwtheme):-moz-system-metric(windows-default-theme) {
- -moz-binding: url(treestyletab.xml#toolbar-drag);
- }
-}
-.treestyletab-tabbar-toolbar,
-.treestyletab-tabbar-toolbar-ready,
-/* for gnomestripe */
-#TabsToolbar.treestyletab-tabbar-toolbar:not([autohide="true"]):not(:-moz-lwtheme):-moz-system-metric(menubar-drag),
-#TabsToolbar.treestyletab-tabbar-toolbar:not([autohide="true"])[tabsontop="true"]:not(:-moz-lwtheme):-moz-system-metric(menubar-drag),
-#TabsToolbar.treestyletab-tabbar-toolbar-ready:not([autohide="true"]):not(:-moz-lwtheme):-moz-system-metric(menubar-drag),
-#TabsToolbar.treestyletab-tabbar-toolbar-ready:not([autohide="true"])[tabsontop="true"]:not(:-moz-lwtheme):-moz-system-metric(menubar-drag),
-/* for pinstripe */
-toolbar.treestyletab-tabbar-toolbar:not([nowindowdrag="true"]),
-toolbar.treestyletab-tabbar-toolbar-ready:not([nowindowdrag="true"]),
-/* Hide Caption Titlebar Plus (Smart)
- https://addons.mozilla.org/firefox/addon/hide-caption-titlebar-plus-sma/ */
-#main-window[dz_adv_scroll_via_tabbar="true"] #TabsToolbar {
- -moz-binding: url(treestyletab.xml#toolbar-drag);
-}
-#navigator-toolbox[tabsontop="false"]
- > .treestyletab-tabbar-toolbar,
-#navigator-toolbox[tabsontop="false"]
- > .treestyletab-tabbar-toolbar-ready,
-#navigator-toolbox[tabsontop="false"]
- > .treestyletab-tabbar-toolbar:-moz-lwtheme,
-#navigator-toolbox[tabsontop="false"]
- > .treestyletab-tabbar-toolbar-ready:-moz-lwtheme {
- -moz-binding: url(treestyletab.xml#toolbar);
-}
-
-.treestyletab-tabbar-toolbar:not([treestyletab-tabbar-position="top"]),
-.treestyletab-tabbar-toolbar[treestyletab-tabbar-position="top"]:not([treestyletab-tabbar-fixed="true"]) {
- appearance: none !important;
- -moz-appearance: none !important;
- line-height: 0 !important; /* to avoid an useless space above the tab bar */
- position: fixed !important;
-}
-.treestyletab-tabbar-toolbar:not([treestyletab-tabbar-position="top"])
- .tabbrowser-tabs,
-.treestyletab-tabbar-toolbar[treestyletab-tabbar-position="top"]:not([treestyletab-tabbar-fixed="true"])
- .tabbrowser-tabs {
- overflow: hidden !important;
-}
-
-.treestyletab-tabbar-toolbar toolbaritem {
- overflow: hidden;
-}
-
-
-
-/* animation effects */
-
-.tabbrowser-tabs[treestyletab-animation-enabled="true"][treestyletab-mode="vertical"]
- .tabbrowser-tab:not([treestyletab-collapsed-done="true"]) {
- -moz-transition: margin-left 0.2s ease-out,
- margin-right 0.2s ease-out,
- margin-top 0.15s ease-out,
- opacity 0.15s ease-out,
- min-height 0.15s ease-out,
- max-height 0.15s ease-out,
- min-width 0.15s ease-out /* for Firefox itself */,
- max-width 0.15s ease-out /* for Firefox itself */;
- transition: margin-left 0.2s ease-out,
- margin-right 0.2s ease-out,
- margin-top 0.15s ease-out,
- opacity 0.15s ease-out,
- min-height 0.15s ease-out,
- max-height 0.15s ease-out,
- min-width 0.15s ease-out /* for Firefox itself */,
- max-width 0.15s ease-out /* for Firefox itself */;
-}
-.tabbrowser-tabs[movingtab][treestyletab-animation-enabled="true"][treestyletab-mode="vertical"]
- .tabbrowser-tab:not([treestyletab-collapsed-done="true"]) {
- -moz-transition: margin-left 0.2s ease-out,
- margin-right 0.2s ease-out,
- margin-top 0.15s ease-out,
- opacity 0.15s ease-out,
- min-height 0.15s ease-out,
- max-height 0.15s ease-out,
- min-width 0.15s ease-out /* for Firefox itself */,
- max-width 0.15s ease-out /* for Firefox itself */,
- transform 0.2s ease-out /* for Firefox itself */;
- transition: margin-left 0.2s ease-out,
- margin-right 0.2s ease-out,
- margin-top 0.15s ease-out,
- opacity 0.15s ease-out,
- min-height 0.15s ease-out,
- max-height 0.15s ease-out,
- min-width 0.15s ease-out /* for Firefox itself */,
- max-width 0.15s ease-out /* for Firefox itself */,
- transform 0.2s ease-out /* for Firefox itself */;
-}
-
-.tabbrowser-tabs[treestyletab-animation-enabled="true"]:not([treestyletab-mode="vertical"]):not([treestyletab-tab-inverted="true"])
- .tabbrowser-tab:not([treestyletab-collapsed-done="true"]) {
- -moz-transition: margin-left 0.15s ease-out,
- opacity 0.15s ease-out,
- margin-top 0.2s ease-out,
- min-height 0.15s ease-out,
- max-height 0.15s ease-out,
- min-width 0.15s ease-out /* for Firefox itself */,
- max-width 0.15s ease-out /* for Firefox itself */;
- transition: margin-left 0.15s ease-out,
- opacity 0.15s ease-out,
- margin-top 0.2s ease-out,
- min-height 0.15s ease-out,
- max-height 0.15s ease-out,
- min-width 0.15s ease-out /* for Firefox itself */,
- max-width 0.15s ease-out /* for Firefox itself */;
-}
-.tabbrowser-tabs[movingtab][treestyletab-animation-enabled="true"]:not([treestyletab-mode="vertical"]):not([treestyletab-tab-inverted="true"])
- .tabbrowser-tab:not([treestyletab-collapsed-done="true"]) {
- -moz-transition: margin-left 0.15s ease-out,
- opacity 0.15s ease-out,
- margin-top 0.2s ease-out,
- min-height 0.15s ease-out,
- max-height 0.15s ease-out,
- min-width 0.15s ease-out /* for Firefox itself */,
- max-width 0.15s ease-out /* for Firefox itself */,
- transform 0.2s ease-out /* for Firefox itself */;
- transition: margin-left 0.15s ease-out,
- opacity 0.15s ease-out,
- margin-top 0.2s ease-out,
- min-height 0.15s ease-out,
- max-height 0.15s ease-out,
- min-width 0.15s ease-out /* for Firefox itself */,
- max-width 0.15s ease-out /* for Firefox itself */,
- transform 0.2s ease-out /* for Firefox itself */;
-}
-
-.tabbrowser-tabs[treestyletab-animation-enabled="true"]:not([treestyletab-mode="vertical"])[treestyletab-tab-inverted="true"]
- .tabbrowser-tab:not([treestyletab-collapsed-done="true"]) {
- -moz-transition: margin-left 0.15s ease-out,
- opacity 0.15s ease-out,
- margin-bottom 0.2s ease-out,
- min-height 0.15s ease-out,
- max-height 0.15s ease-out,
- min-width 0.15s ease-out /* for Firefox itself */,
- max-width 0.15s ease-out /* for Firefox itself */;
- transition: margin-left 0.15s ease-out,
- opacity 0.15s ease-out,
- margin-bottom 0.2s ease-out,
- min-height 0.15s ease-out,
- max-height 0.15s ease-out,
- min-width 0.15s ease-out /* for Firefox itself */,
- max-width 0.15s ease-out /* for Firefox itself */;
-}
-.tabbrowser-tabs[movingtab][treestyletab-animation-enabled="true"]:not([treestyletab-mode="vertical"])[treestyletab-tab-inverted="true"]
- .tabbrowser-tab:not([treestyletab-collapsed-done="true"]) {
- -moz-transition: margin-left 0.15s ease-out,
- opacity 0.15s ease-out,
- margin-bottom 0.2s ease-out,
- min-height 0.15s ease-out,
- max-height 0.15s ease-out,
- min-width 0.15s ease-out /* for Firefox itself */,
- max-width 0.15s ease-out /* for Firefox itself */,
- transform 0.2s ease-out /* for Firefox itself */;
- transition: margin-left 0.15s ease-out,
- opacity 0.15s ease-out,
- margin-bottom 0.2s ease-out,
- min-height 0.15s ease-out,
- max-height 0.15s ease-out,
- min-width 0.15s ease-out /* for Firefox itself */,
- max-width 0.15s ease-out /* for Firefox itself */,
- transform 0.2s ease-out /* for Firefox itself */;
-}
-
-
-
-
-/* separating of groups */
-
-/* horizontal tab bar */
-.tabbrowser-tabs[treestyletab-mode="horizontal"] .tabbrowser-tab:not([treestyletab-nest="0"]):not([hidden])
- + .tabbrowser-tab[treestyletab-nest="0"],
-.tabbrowser-tabs[treestyletab-mode="horizontal"] .tabbrowser-tab:not([treestyletab-nest="0"]):not([hidden])
- ~ .tabbrowser-tab[hidden]
- + .tabbrowser-tab[treestyletab-nest="0"],
-.tabbrowser-tabs[treestyletab-mode="horizontal"] .tabbrowser-tab[treestyletab-nest="0"]:not([hidden])
- + .tabbrowser-tab[treestyletab-nest="0"][treestyletab-children],
-.tabbrowser-tabs[treestyletab-mode="horizontal"] .tabbrowser-tab[treestyletab-nest="0"]:not([hidden])
- ~ .tabbrowser-tab[hidden]
- + .tabbrowser-tab[treestyletab-nest="0"][treestyletab-children] {
- margin-left: 0.8em !important;
-}
-
-/* vertical tab bar */
-.tabbrowser-tabs[treestyletab-mode="vertical"][treestyletab-max-tree-level="0"] .tabbrowser-tab:not([treestyletab-nest="0"]):not([hidden])
- + .tabbrowser-tab[treestyletab-nest="0"],
-.tabbrowser-tabs[treestyletab-mode="vertical"][treestyletab-max-tree-level="0"] .tabbrowser-tab:not([treestyletab-nest="0"]):not([hidden])
- ~ .tabbrowser-tab[hidden]
- + .tabbrowser-tab[treestyletab-nest="0"],
-.tabbrowser-tabs[treestyletab-mode="vertical"][treestyletab-max-tree-level="0"] .tabbrowser-tab[treestyletab-nest="0"]:not([hidden])
- + .tabbrowser-tab[treestyletab-nest="0"][treestyletab-children],
-.tabbrowser-tabs[treestyletab-mode="vertical"][treestyletab-max-tree-level="0"] .tabbrowser-tab[treestyletab-nest="0"]:not([hidden])
- ~ .tabbrowser-tab[hidden]
- + .tabbrowser-tab[treestyletab-nest="0"][treestyletab-children] {
- margin-top: 0.8em !important;
-}
-
-
-
-/* compatibility for Firefox features */
-
-/* hide all tabs button (by user's preference) */
-.tabbrowser-tabs[treestyletab-hide-alltabs-button]
- .tabs-alltabs-stack {
- visibility: collapse !important;
-}
-
-/* pinned tabs */
-.tabbrowser-tabs[treestyletab-mode="vertical"] {
- -moz-margin-start: 0 !important;
-}
-
-.tabbrowser-tabs[treestyletab-mode="vertical"]
- .tabbrowser-tab[pinned] {
- /* height: 24px; */
- line-height: 0;
- position: fixed !important;
- /* width: 24px; */
- z-index: 100;
-}
-.tabbrowser-tabs[treestyletab-mode="vertical"][treestyletab-dom-fullscreen-activated="true"]
- .tabbrowser-tab[pinned] {
- z-index: -100;
-}
-
-.tabbrowser-tabs[treestyletab-mode="vertical"]
- .tabbrowser-tab[pinned]:not(.treestyletab-faviconized)
- .tab-label[pinned] {
- width: auto;
-}
-
-/* print preview */
-.tabbrowser-strip[treestyletab-tabbar-fixed="true"]+splitter,
-.tabbrowser-strip[treestyletab-print-preview="true"],
-.tabbrowser-strip[treestyletab-print-preview="true"]+splitter,
-.treestyletab-tabbar-toolbar[treestyletab-print-preview="true"],
-tabbrowser[treestyletab-tabbar-autohide-mode="1"][treestyletab-print-preview="true"]
- .treestyletab-tabbar-toggler {
- visibility: collapse;
-}
-
-/* stylized window (opened by window.open() with features) */
-window[chromehidden~="toolbar"]
- .tabbrowser-strip.treestyletab-tabbar-placeholder,
-window[chromehidden~="toolbar"]
- .tabbrowser-strip.treestyletab-tabbar-placeholder+splitter,
-window[chromehidden~="toolbar"]
- .treestyletab-tabbar-toolbar {
- visibility: collapse;
-}
-
-
-/* full tooltip */
-
-#treestyletab-full-tree-tooltip[popup-shown="true"] {
- -moz-transition: margin-left 0.2s ease-out,
- margin-top 0.2s ease-out,
- max-height 0.2s ease-out,
- max-width 0.2s ease-out;
- transition: margin-left 0.2s ease-out,
- margin-top 0.2s ease-out,
- max-height 0.2s ease-out,
- max-width 0.2s ease-out;
-}
-
-#treestyletab-full-tree-tooltip > arrowscrollbox {
- opacity: 0;
-}
-
-#treestyletab-full-tree-tooltip[popup-shown="true"] > arrowscrollbox {
- -moz-transition: opacity 0.2s ease-out;
- transition: opacity 0.2s ease-out;
- opacity: 1;
-}
-
-
-/* addon compatibility */
-
-/* some themes */
-image.tab-icon {
- display: -moz-stack;
- -moz-binding: url(treestyletab.xml#tab-icon);
-}
-
-/* Tabbrowser Preferences, and some theme */
-.tabbrowser-tabs .tabs-newbutton,
-.tabbrowser-tabs[treestyletab-mode="vertical"] .scrollbutton-up,
-.tabbrowser-tabs[treestyletab-mode="vertical"] .scrollbutton-down {
- max-width: none !important;
-}
-
-/* All-in-One Sidebar */
-#aiostbx-tableft-toolbox:not([incustomisemode="true"]) > toolbar[currentset="__empty"],
-#aiostbx-tableft-toolbox:not([incustomisemode="true"]) > toolbar:not([currentset]),
-#aiostbx-tabright-toolbox:not([incustomisemode="true"]) > toolbar[currentset="__empty"],
-#aiostbx-tabright-toolbox:not([incustomisemode="true"]) > toolbar:not([currentset]) {
- visibility: collapse;
-}
-
-/* AutoHide */
-#appcontent[ahFull="true"] .tabbrowser-strip[ahHIDE="true"]+splitter {
- visibility: collapse;
-}
-
-/* ColorfulTabs */
-:root:not([treestyletab-tabbar-position="top"]) #ctStack,
-:root:not([treestyletab-tabbar-fixed="true"]) #ctStack {
- display: none;
-}
-
-/* Hide Caption Titlebar Plus */
-:root[treestyletab-tabbar-position="top"] #menubar-items[dz_home_mainmenu_floating="true"] {
- z-index: 650000;
-}
+@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
+@namespace html url("http://www.w3.org/1999/xhtml");
+
+
+/* twisty in tabs */
+.treestyletab-twisty,
+.tabbrowser-tabs:not([treestyletab-allow-subtree-collapse="true"])
+ .treestyletab-twisty {
+ visibility: hidden;
+}
+.tabbrowser-tabs[treestyletab-mode="vertical"][treestyletab-allow-subtree-collapse="true"]:not([treestyletab-twisty-style="none"])
+ .tabbrowser-tab[treestyletab-children][treestyletab-allow-subtree-collapse="true"]
+ .treestyletab-twisty,
+.tabbrowser-tabs[treestyletab-mode="horizontal"][treestyletab-allow-subtree-collapse="true"]:not([treestyletab-twisty-style="none"])
+ .tabbrowser-tab[treestyletab-children][treestyletab-allow-subtree-collapse="true"]
+ .treestyletab-twisty {
+ visibility: visible;
+}
+.tabbrowser-tabs[treestyletab-twisty-style="none"]
+ .treestyletab-twisty,
+.tabbrowser-tabs[treestyletab-mode="horizontal"]
+ .treestyletab-twisty,
+.tabbrowser-tab[pinned="true"]
+ .treestyletab-twisty {
+ visibility: collapse;
+}
+
+/* collapsed children counter */
+.treestyletab-counter-container {
+ display: none;
+}
+.tabbrowser-tabs[treestyletab-allow-subtree-collapse="true"]
+ .tabbrowser-tab[treestyletab-children][treestyletab-subtree-collapsed="true"][treestyletab-allow-subtree-collapse="true"]
+ .treestyletab-counter-container {
+ display: -moz-box;
+}
+
+/* collapse/expand tree of tabs */
+.tabbrowser-tabs[treestyletab-allow-subtree-collapse="true"]
+ .tabbrowser-tab[treestyletab-collapsed-done="true"] {
+ visibility: collapse;
+}
+
+/* collapse/expand tree of tabs, horizontal stacked tabs */
+.tabbrowser-tabs[treestyletab-allow-subtree-collapse="true"][treestyletab-stack-collapsed-tabs="true"]
+ .tabbrowser-tab {
+ position: relative;
+}
+.tabbrowser-tabs[treestyletab-allow-subtree-collapse="true"][treestyletab-stack-collapsed-tabs="true"]
+ .tabbrowser-tab[treestyletab-collapsed="true"][fadein],
+/**
+ * Tab Mix Plus dynamically inserts a CSS rule like
+ * "#tabbrowser-tabs > .tabbrowser-tab { ... }" and it unexpectedly
+ * expands width of "collapsed" tabs. So, to apply our rule prior than
+ * TMP's one, I put the "#tabbrowser-tabs" version also.
+ */
+#tabbrowser-tabs[treestyletab-allow-subtree-collapse="true"][treestyletab-stack-collapsed-tabs="true"]
+ .tabbrowser-tab[treestyletab-collapsed="true"][fadein] {
+ visibility: visible;
+ max-width: 20px;
+ min-width: 20px;
+ width: 20px;
+ box-flex: 0;
+ -moz-box-flex: 0;
+ mask: url("res/tabEffects.svg#fadein-mask");
+}
+.tabbrowser-tabs[treestyletab-allow-subtree-collapse="true"][treestyletab-stack-collapsed-tabs="true"]
+ .tabbrowser-tab[treestyletab-collapsed-done="true"] .tab-content > * {
+ visibility: collapse;
+}
+
+/* fixed tab bar */
+.tabbrowser-strip[treestyletab-tabbar-fixed="true"]+splitter {
+ visibility: collapse;
+}
+
+
+/* tab bar in the DOM-fullscreen mode */
+
+.tabbrowser-tabs[treestyletab-dom-fullscreen-activated="true"],
+.tabbrowser-strip[treestyletab-dom-fullscreen-activated="true"],
+.tabbrowser-strip[treestyletab-dom-fullscreen-activated="true"]+splitter,
+.treestyletab-tabbar-toolbar[treestyletab-dom-fullscreen-activated="true"],
+.treestyletab-tabbar-toolbar[treestyletab-dom-fullscreen-activated="true"] > *,
+tabbrowser[treestyletab-dom-fullscreen-activated-mode="true"][tabcontainer]
+ .tabbrowser-strip.treestyletab-tabbar-placeholder,
+tabbrowser[treestyletab-dom-fullscreen-activated-mode="true"][tabcontainer]
+ .tabbrowser-strip.treestyletab-tabbar-placeholder+splitter {
+ visibility: collapse;
+}
+
+
+/* auto hide tab bar */
+
+.tabbrowser-tabs[treestyletab-tabbar-autohide="hidden"],
+.tabbrowser-strip[treestyletab-tabbar-autohide="hidden"],
+.tabbrowser-strip[treestyletab-tabbar-autohide="hidden"]+splitter,
+.tabbrowser-strip[collapsed="true"] + splitter:not([state="collapsed"]),
+.treestyletab-tabbar-toggler,
+.treestyletab-tabbar-toolbar[treestyletab-tabbar-autohide="hidden"],
+.treestyletab-tabbar-toolbar[treestyletab-tabbar-autohide="hidden"] > *,
+.treestyletab-tabbar-toolbar .treestyletab-splitter,
+#treestyletab-tabbar-resizer-box,
+tabbrowser[treestyletab-tabbar-autohide-mode="1"][tabcontainer]
+ .tabbrowser-strip.treestyletab-tabbar-placeholder,
+tabbrowser[treestyletab-tabbar-autohide-mode="1"][tabcontainer]
+ .tabbrowser-strip.treestyletab-tabbar-placeholder+splitter {
+ visibility: collapse;
+}
+
+tabbrowser[treestyletab-tabbar-autohide-mode="1"][tabcontainer]
+ .treestyletab-tabbar-toggler,
+tabbrowser[treestyletab-tabbar-autohide-mode="1"][treestyletab-tabbar-autohide="hidden"]
+ .treestyletab-tabbar-toggler,
+.treestyletab-tabbar-toolbar[treestyletab-mode="vertical"][treestyletab-tabbar-autohide][treestyletab-tabbar-autohide-state="expanded"]
+ #treestyletab-tabbar-resizer-box,
+.treestyletab-tabbar-toolbar[treestyletab-mode="vertical"][treestyletab-tabbar-autohide][treestyletab-tabbar-autohide-state="expanded"]:not([treestyletab-tabbar-fixed="true"])
+ .treestyletab-splitter {
+ visibility: visible;
+}
+
+/* put resizer under tabs, and raise up tabs */
+.treestyletab-tabbar-toolbar[treestyletab-mode="vertical"][treestyletab-tabbar-autohide]
+ > *,
+.treestyletab-tabbar-toolbar[treestyletab-mode="vertical"][treestyletab-tabbar-autohide]
+ > #tabbrowser-tabs,
+.treestyletab-toolbar-inner-box[treestyletab-tabbar-autohide]:not([treestyletab-tabbar-fixed="true"])
+ > *,
+.treestyletab-toolbar-inner-box[treestyletab-tabbar-autohide]:not([treestyletab-tabbar-fixed="true"])
+ > #tabbrowser-tabs {
+ position: relative;
+ z-index: 2;
+}
+.treestyletab-tabbar-toolbar[treestyletab-mode="vertical"][treestyletab-tabbar-autohide]
+ #treestyletab-tabbar-resizer-box {
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ top: 0;
+ z-index: 1;
+ line-height: 0 !important; /* to avoid an useless space above the splitter */
+ font-size: 0 !important; /* to avoid an useless space above the splitter */
+}
+
+.tabbrowser-tabs[treestyletab-tabbar-autohide]
+ .tabs-stack
+ > *:first-child
+ > :not(html|canvas),
+.tabbrowser-tabs[treestyletab-tabbar-resizing]
+ .tabs-stack
+ > *:first-child
+ > html|canvas {
+ display: none !important;
+}
+
+
+#treestyletab-autohide-content-area-screen {
+ appearance: none;
+ -moz-appearance: none;
+ /**
+ * Don't make this panel completely transparent, because
+ * mousemove event never fire on 100% transparent panel.
+ * The color should be a pale white, instead of a pale black,
+ * because many websites use white background. Black screen
+ * is too glaring for white background websites.
+ */
+ background: rgba(255, 255, 255, 0.01);
+ line-height: 0;
+ margin: 0;
+ padding: 0;
+ -moz-border-bottom-colors: none;
+ -moz-border-left-colors: none;
+ -moz-border-right-colors: none;
+ -moz-border-top-colors: none;
+}
+
+
+/* vertical tab bar */
+
+.tabbrowser-tabs[treestyletab-mode="vertical"]
+ .tabbrowser-arrowscrollbox > scrollbox {
+ overflow-x: hidden !important;
+ overflow-y: auto !important;
+}
+
+.tabbrowser-tabs[treestyletab-mode="vertical"]
+ .tabbrowser-arrowscrollbox
+ .scrollbox-innerbox {
+ box-flex: 1 !important;
+ -moz-box-flex: 1 !important;
+ box-pack: start !important;
+ -moz-box-pack: start !important;
+}
+
+.tabbrowser-tabs[treestyletab-mode="vertical"]
+ .tabbrowser-tab,
+toolbar.treestyletab-tabbar-toolbar[treestyletab-mode="vertical"]
+ > toolbarbutton,
+toolbar.treestyletab-tabbar-toolbar[treestyletab-mode="vertical"]
+ > .treestyletab-toolbar-inner-box > toolbarbutton,
+toolbar.treestyletab-tabbar-toolbar[treestyletab-mode="vertical"]
+ > toolbaritem,
+toolbar.treestyletab-tabbar-toolbar[treestyletab-mode="vertical"]
+ > .treestyletab-toolbar-inner-box > toolbaritem {
+ box-flex: 0 !important;
+ -moz-box-flex: 0 !important;
+}
+
+.treestyletab-tabbar-toolbar[treestyletab-mode="vertical"] > toolbarbutton,
+.treestyletab-tabbar-toolbar[treestyletab-mode="vertical"] > toolbarpaletteitem > toolbarbutton {
+ max-width: none !important;
+}
+
+/* workaround for https://github.com/piroor/treestyletab/issues/100 */
+.treestyletab-tabbar-toolbar[treestyletab-mode="vertical"] .textbox-input-box {
+ box-align: stretch;
+ -moz-box-align: stretch;
+}
+
+
+/* leftside vertical tab bar */
+
+tabs.tabbrowser-tabs[treestyletab-tabbar-position="left"][treestyletab-invert-scrollbar="true"]
+ .tabbrowser-arrowscrollbox
+ > scrollbox {
+ direction: rtl;
+}
+tabs.tabbrowser-tabs[treestyletab-tabbar-position="left"][treestyletab-invert-scrollbar="true"]
+ .tabbrowser-arrowscrollbox
+ > scrollbox
+ > .scrollbox-innerbox {
+ direction: ltr;
+}
+
+
+/* hide horizontal tab bar UI for vertical tab bar */
+.tabbrowser-tabs[treestyletab-mode="vertical"] .tabbrowser-arrowscrollbox > .scrollbutton-up,
+.tabbrowser-tabs[treestyletab-mode="vertical"] .tabbrowser-arrowscrollbox > .scrollbutton-down:not([treestyletab-notifybgtab-phase]),
+.tabbrowser-tabs[treestyletab-mode="vertical"] .tabs-closebutton-box,
+.tabbrowser-tabs[treestyletab-mode="vertical"] .tab-drop-indicator-bar {
+ visibility: collapse !important;
+}
+
+/**
+ * Firefox 4.0 finishes opening and closing processes of tabs by its
+ * "transitionend" events about max-width property. I think this is very
+ * dirty and specific implementation but it won't fixed.
+ * (See: https://bugzilla.mozilla.org/show_bug.cgi?id=585417#c3 )
+ * So we have to define max-width for both states [fadein] (means "completely
+ * opened") and :not([fadein]) (means "in opening/removing process".
+ */
+.tabbrowser-tabs[treestyletab-mode="vertical"]
+ .tabbrowser-tab:not([pinned]) {
+ max-width: 65000px !important;
+}
+.treestyletab-tabbar-toolbar[treestyletab-mode="vertical"]
+ .tabbrowser-tab:not([pinned]):not([fadein]) {
+ opacity: 0.5 !important;
+}
+.tabbrowser-tabs[treestyletab-mode="vertical"]
+ .tabbrowser-tab:not([pinned])[fadein] {
+ max-width: 65250px !important;
+ min-width: 1px !important;
+}
+.treestyletab-tabbar-toolbar[treestyletab-mode="vertical"][treestyletab-animation-enabled="true"]
+ .tabbrowser-tab:not([pinned]):not([fadein])[treestyletab-removed="true"] {
+ max-height: 1px !important;
+ min-height: 1px !important;
+ opacity: 0 !important;
+ /**
+ * Sometimes "transitionend" event for "max-width" doesn't fire so ghotst
+ * tabs are left. To do cleanup process forcedly, we have to re-define new
+ * max-width to fire transitionend event.
+ */
+ max-width: 64000px !important;
+}
+
+/* override toolbar binding */
+/**
+ * Don't use :-moz-any() selector to override styles defined by the theme.
+ * Normal selectors in default theme is stronger than :-moz-any() even if
+ * it includes #TabsToolbar in its subqueries.
+ */
+@media all and (-moz-windows-compositor) { /* for winstripe */
+ #navigator-toolbox
+ > .treestyletab-tabbar-toolbar:not(#toolbar-menubar),
+ #navigator-toolbox
+ > .treestyletab-tabbar-toolbar:not(#toolbar-menubar):-moz-lwtheme,
+ #navigator-toolbox
+ > .treestyletab-tabbar-toolbar-ready:not(#toolbar-menubar),
+ #navigator-toolbox
+ > .treestyletab-tabbar-toolbar-ready:not(#toolbar-menubar):-moz-lwtheme,
+ #navigator-toolbox[tabsontop="true"]
+ > .treestyletab-tabbar-toolbar:not(#toolbar-menubar),
+ #navigator-toolbox[tabsontop="true"]
+ > .treestyletab-tabbar-toolbar:not(#toolbar-menubar):-moz-lwtheme,
+ #navigator-toolbox[tabsontop="true"]
+ > .treestyletab-tabbar-toolbar-ready:not(#toolbar-menubar),
+ #navigator-toolbox[tabsontop="true"]
+ > .treestyletab-tabbar-toolbar-ready:not(#toolbar-menubar):-moz-lwtheme,
+
+ #navigator-toolbox
+ > #nav-bar + #customToolbars + #PersonalToolbar[collapsed="true"]
+ + .treestyletab-tabbar-toolbar:last-child,
+ #navigator-toolbox
+ > #nav-bar + #customToolbars + #PersonalToolbar[collapsed="true"]
+ + .treestyletab-tabbar-toolbar:not(:last-child),
+ #navigator-toolbox
+ > #nav-bar + #customToolbars + #PersonalToolbar[collapsed="true"]
+ + .treestyletab-tabbar-toolbar[tabsontop="true"]:last-child,
+ #navigator-toolbox
+ > #nav-bar + #customToolbars + #PersonalToolbar[collapsed="true"]
+ + .treestyletab-tabbar-toolbar[tabsontop="true"]:not(:last-child),
+ #navigator-toolbox
+ > #nav-bar + #customToolbars + #PersonalToolbar[collapsed="true"]
+ + .treestyletab-tabbar-toolbar[tabsontop="false"]:last-child,
+ #navigator-toolbox
+ > #nav-bar + #customToolbars + #PersonalToolbar[collapsed="true"]
+ + .treestyletab-tabbar-toolbar[tabsontop="false"]:not(:last-child),
+ #navigator-toolbox
+ > #nav-bar + #customToolbars + #PersonalToolbar[collapsed="true"]
+ + .treestyletab-tabbar-toolbar-ready:last-child,
+ #navigator-toolbox
+ > #nav-bar + #customToolbars + #PersonalToolbar[collapsed="true"]
+ + .treestyletab-tabbar-toolbar-ready:not(:last-child),
+ #navigator-toolbox
+ > #nav-bar + #customToolbars + #PersonalToolbar[collapsed="true"]
+ + .treestyletab-tabbar-toolbar-ready[tabsontop="true"]:last-child,
+ #navigator-toolbox
+ > #nav-bar + #customToolbars + #PersonalToolbar[collapsed="true"]
+ + .treestyletab-tabbar-toolbar-ready[tabsontop="true"]:not(:last-child),
+ #navigator-toolbox
+ > #nav-bar + #customToolbars + #PersonalToolbar[collapsed="true"]
+ + .treestyletab-tabbar-toolbar-ready[tabsontop="false"]:last-child,
+ #navigator-toolbox
+ > #nav-bar + #customToolbars + #PersonalToolbar[collapsed="true"]
+ + .treestyletab-tabbar-toolbar-ready[tabsontop="false"]:not(:last-child),
+
+ #navigator-toolbox
+ > .treestyletab-tabbar-toolbar:not(#toolbar-menubar):-moz-lwtheme,
+ #navigator-toolbox
+ > .treestyletab-tabbar-toolbar-ready:not(#toolbar-menubar):-moz-lwtheme,
+
+ #navigator-toolbox
+ > #nav-bar + #customToolbars + #PersonalToolbar[collapsed="true"]
+ + #TabsToolbar:last-child,
+ #navigator-toolbox
+ > #nav-bar + #customToolbars + #PersonalToolbar[collapsed="true"]
+ + #TabsToolbar:not(:last-child),heme,
+ #navigator-toolbox
+ > #nav-bar + #customToolbars + #PersonalToolbar[collapsed="true"]
+ + #TabsToolbar[tabsontop="true"]:last-child,
+ #navigator-toolbox
+ > #nav-bar + #customToolbars + #PersonalToolbar[collapsed="true"]
+ + #TabsToolbar[tabsontop="true"]:not(:last-child),
+ #navigator-toolbox
+ > #nav-bar + #customToolbars + #PersonalToolbar[collapsed="true"]
+ + #TabsToolbar[tabsontop="false"]:last-child,
+ #navigator-toolbox
+ > #nav-bar + #customToolbars + #PersonalToolbar[collapsed="true"]
+ + #TabsToolbar[tabsontop="false"]:not(:last-child),
+
+ #navigator-toolbox
+ > toolbar:not(#toolbar-menubar):not(#addon-bar):-moz-lwtheme {
+ -moz-binding: url(treestyletab.xml#toolbar-drag);
+ }
+}
+@media not all and (-moz-windows-compositor) { /* for winstripe */
+ #TabsToolbar:not(:-moz-lwtheme):-moz-system-metric(windows-default-theme),
+ #TabsToolbar[tabsontop="true"]:not(:-moz-lwtheme):-moz-system-metric(windows-default-theme),
+ #navigator-toolbox[tabsontop="false"]
+ > toolbar.treestyletab-tabbar-toolbar:not(#toolbar-menubar):not(:-moz-lwtheme):-moz-system-metric(windows-default-theme),
+ #navigator-toolbox[tabsontop="false"]
+ > toolbar.treestyletab-tabbar-toolbar-ready:not(#toolbar-menubar):not(:-moz-lwtheme):-moz-system-metric(windows-default-theme) {
+ -moz-binding: url(treestyletab.xml#toolbar-drag);
+ }
+}
+.treestyletab-tabbar-toolbar,
+.treestyletab-tabbar-toolbar-ready,
+/* for gnomestripe */
+#TabsToolbar.treestyletab-tabbar-toolbar:not([autohide="true"]):not(:-moz-lwtheme):-moz-system-metric(menubar-drag),
+#TabsToolbar.treestyletab-tabbar-toolbar:not([autohide="true"])[tabsontop="true"]:not(:-moz-lwtheme):-moz-system-metric(menubar-drag),
+#TabsToolbar.treestyletab-tabbar-toolbar-ready:not([autohide="true"]):not(:-moz-lwtheme):-moz-system-metric(menubar-drag),
+#TabsToolbar.treestyletab-tabbar-toolbar-ready:not([autohide="true"])[tabsontop="true"]:not(:-moz-lwtheme):-moz-system-metric(menubar-drag),
+/* for pinstripe */
+toolbar.treestyletab-tabbar-toolbar:not([nowindowdrag="true"]),
+toolbar.treestyletab-tabbar-toolbar-ready:not([nowindowdrag="true"]),
+/* Hide Caption Titlebar Plus (Smart)
+ https://addons.mozilla.org/firefox/addon/hide-caption-titlebar-plus-sma/ */
+#main-window[dz_adv_scroll_via_tabbar="true"] #TabsToolbar {
+ -moz-binding: url(treestyletab.xml#toolbar-drag);
+}
+#navigator-toolbox[tabsontop="false"]
+ > .treestyletab-tabbar-toolbar,
+#navigator-toolbox[tabsontop="false"]
+ > .treestyletab-tabbar-toolbar-ready,
+#navigator-toolbox[tabsontop="false"]
+ > .treestyletab-tabbar-toolbar:-moz-lwtheme,
+#navigator-toolbox[tabsontop="false"]
+ > .treestyletab-tabbar-toolbar-ready:-moz-lwtheme {
+ -moz-binding: url(treestyletab.xml#toolbar);
+}
+
+.treestyletab-tabbar-toolbar:not([treestyletab-tabbar-position="top"]),
+.treestyletab-tabbar-toolbar[treestyletab-tabbar-position="top"]:not([treestyletab-tabbar-fixed="true"]) {
+ appearance: none !important;
+ -moz-appearance: none !important;
+ line-height: 0 !important; /* to avoid an useless space above the tab bar */
+ position: fixed !important;
+}
+.treestyletab-tabbar-toolbar:not([treestyletab-tabbar-position="top"])
+ .tabbrowser-tabs,
+.treestyletab-tabbar-toolbar[treestyletab-tabbar-position="top"]:not([treestyletab-tabbar-fixed="true"])
+ .tabbrowser-tabs {
+ overflow: hidden !important;
+}
+
+.treestyletab-tabbar-toolbar toolbaritem {
+ overflow: hidden;
+}
+
+
+
+/* animation effects */
+
+.tabbrowser-tabs[treestyletab-animation-enabled="true"][treestyletab-mode="vertical"]
+ .tabbrowser-tab:not([treestyletab-collapsed-done="true"]) {
+ -moz-transition: margin-left 0.2s ease-out,
+ margin-right 0.2s ease-out,
+ margin-top 0.15s ease-out,
+ opacity 0.15s ease-out,
+ min-height 0.15s ease-out,
+ max-height 0.15s ease-out,
+ min-width 0.15s ease-out /* for Firefox itself */,
+ max-width 0.15s ease-out /* for Firefox itself */;
+ transition: margin-left 0.2s ease-out,
+ margin-right 0.2s ease-out,
+ margin-top 0.15s ease-out,
+ opacity 0.15s ease-out,
+ min-height 0.15s ease-out,
+ max-height 0.15s ease-out,
+ min-width 0.15s ease-out /* for Firefox itself */,
+ max-width 0.15s ease-out /* for Firefox itself */;
+}
+.tabbrowser-tabs[movingtab][treestyletab-animation-enabled="true"][treestyletab-mode="vertical"]
+ .tabbrowser-tab:not([treestyletab-collapsed-done="true"]) {
+ -moz-transition: margin-left 0.2s ease-out,
+ margin-right 0.2s ease-out,
+ margin-top 0.15s ease-out,
+ opacity 0.15s ease-out,
+ min-height 0.15s ease-out,
+ max-height 0.15s ease-out,
+ min-width 0.15s ease-out /* for Firefox itself */,
+ max-width 0.15s ease-out /* for Firefox itself */,
+ transform 0.2s ease-out /* for Firefox itself */;
+ transition: margin-left 0.2s ease-out,
+ margin-right 0.2s ease-out,
+ margin-top 0.15s ease-out,
+ opacity 0.15s ease-out,
+ min-height 0.15s ease-out,
+ max-height 0.15s ease-out,
+ min-width 0.15s ease-out /* for Firefox itself */,
+ max-width 0.15s ease-out /* for Firefox itself */,
+ transform 0.2s ease-out /* for Firefox itself */;
+}
+
+.tabbrowser-tabs[treestyletab-animation-enabled="true"]:not([treestyletab-mode="vertical"]):not([treestyletab-tab-inverted="true"])
+ .tabbrowser-tab:not([treestyletab-collapsed-done="true"]) {
+ -moz-transition: margin-left 0.15s ease-out,
+ opacity 0.15s ease-out,
+ margin-top 0.2s ease-out,
+ min-height 0.15s ease-out,
+ max-height 0.15s ease-out,
+ min-width 0.15s ease-out /* for Firefox itself */,
+ max-width 0.15s ease-out /* for Firefox itself */;
+ transition: margin-left 0.15s ease-out,
+ opacity 0.15s ease-out,
+ margin-top 0.2s ease-out,
+ min-height 0.15s ease-out,
+ max-height 0.15s ease-out,
+ min-width 0.15s ease-out /* for Firefox itself */,
+ max-width 0.15s ease-out /* for Firefox itself */;
+}
+.tabbrowser-tabs[movingtab][treestyletab-animation-enabled="true"]:not([treestyletab-mode="vertical"]):not([treestyletab-tab-inverted="true"])
+ .tabbrowser-tab:not([treestyletab-collapsed-done="true"]) {
+ -moz-transition: margin-left 0.15s ease-out,
+ opacity 0.15s ease-out,
+ margin-top 0.2s ease-out,
+ min-height 0.15s ease-out,
+ max-height 0.15s ease-out,
+ min-width 0.15s ease-out /* for Firefox itself */,
+ max-width 0.15s ease-out /* for Firefox itself */,
+ transform 0.2s ease-out /* for Firefox itself */;
+ transition: margin-left 0.15s ease-out,
+ opacity 0.15s ease-out,
+ margin-top 0.2s ease-out,
+ min-height 0.15s ease-out,
+ max-height 0.15s ease-out,
+ min-width 0.15s ease-out /* for Firefox itself */,
+ max-width 0.15s ease-out /* for Firefox itself */,
+ transform 0.2s ease-out /* for Firefox itself */;
+}
+
+.tabbrowser-tabs[treestyletab-animation-enabled="true"]:not([treestyletab-mode="vertical"])[treestyletab-tab-inverted="true"]
+ .tabbrowser-tab:not([treestyletab-collapsed-done="true"]) {
+ -moz-transition: margin-left 0.15s ease-out,
+ opacity 0.15s ease-out,
+ margin-bottom 0.2s ease-out,
+ min-height 0.15s ease-out,
+ max-height 0.15s ease-out,
+ min-width 0.15s ease-out /* for Firefox itself */,
+ max-width 0.15s ease-out /* for Firefox itself */;
+ transition: margin-left 0.15s ease-out,
+ opacity 0.15s ease-out,
+ margin-bottom 0.2s ease-out,
+ min-height 0.15s ease-out,
+ max-height 0.15s ease-out,
+ min-width 0.15s ease-out /* for Firefox itself */,
+ max-width 0.15s ease-out /* for Firefox itself */;
+}
+.tabbrowser-tabs[movingtab][treestyletab-animation-enabled="true"]:not([treestyletab-mode="vertical"])[treestyletab-tab-inverted="true"]
+ .tabbrowser-tab:not([treestyletab-collapsed-done="true"]) {
+ -moz-transition: margin-left 0.15s ease-out,
+ opacity 0.15s ease-out,
+ margin-bottom 0.2s ease-out,
+ min-height 0.15s ease-out,
+ max-height 0.15s ease-out,
+ min-width 0.15s ease-out /* for Firefox itself */,
+ max-width 0.15s ease-out /* for Firefox itself */,
+ transform 0.2s ease-out /* for Firefox itself */;
+ transition: margin-left 0.15s ease-out,
+ opacity 0.15s ease-out,
+ margin-bottom 0.2s ease-out,
+ min-height 0.15s ease-out,
+ max-height 0.15s ease-out,
+ min-width 0.15s ease-out /* for Firefox itself */,
+ max-width 0.15s ease-out /* for Firefox itself */,
+ transform 0.2s ease-out /* for Firefox itself */;
+}
+
+
+
+
+/* separating of groups */
+
+/* horizontal tab bar */
+.tabbrowser-tabs[treestyletab-mode="horizontal"] .tabbrowser-tab:not([treestyletab-nest="0"]):not([hidden])
+ + .tabbrowser-tab[treestyletab-nest="0"],
+.tabbrowser-tabs[treestyletab-mode="horizontal"] .tabbrowser-tab:not([treestyletab-nest="0"]):not([hidden])
+ ~ .tabbrowser-tab[hidden]
+ + .tabbrowser-tab[treestyletab-nest="0"],
+.tabbrowser-tabs[treestyletab-mode="horizontal"] .tabbrowser-tab[treestyletab-nest="0"]:not([hidden])
+ + .tabbrowser-tab[treestyletab-nest="0"][treestyletab-children],
+.tabbrowser-tabs[treestyletab-mode="horizontal"] .tabbrowser-tab[treestyletab-nest="0"]:not([hidden])
+ ~ .tabbrowser-tab[hidden]
+ + .tabbrowser-tab[treestyletab-nest="0"][treestyletab-children] {
+ margin-left: 0.8em !important;
+}
+
+/* vertical tab bar */
+.tabbrowser-tabs[treestyletab-mode="vertical"][treestyletab-max-tree-level="0"] .tabbrowser-tab:not([treestyletab-nest="0"]):not([hidden])
+ + .tabbrowser-tab[treestyletab-nest="0"],
+.tabbrowser-tabs[treestyletab-mode="vertical"][treestyletab-max-tree-level="0"] .tabbrowser-tab:not([treestyletab-nest="0"]):not([hidden])
+ ~ .tabbrowser-tab[hidden]
+ + .tabbrowser-tab[treestyletab-nest="0"],
+.tabbrowser-tabs[treestyletab-mode="vertical"][treestyletab-max-tree-level="0"] .tabbrowser-tab[treestyletab-nest="0"]:not([hidden])
+ + .tabbrowser-tab[treestyletab-nest="0"][treestyletab-children],
+.tabbrowser-tabs[treestyletab-mode="vertical"][treestyletab-max-tree-level="0"] .tabbrowser-tab[treestyletab-nest="0"]:not([hidden])
+ ~ .tabbrowser-tab[hidden]
+ + .tabbrowser-tab[treestyletab-nest="0"][treestyletab-children] {
+ margin-top: 0.8em !important;
+}
+
+
+
+/* compatibility for Firefox features */
+
+/* hide all tabs button (by user's preference) */
+.tabbrowser-tabs[treestyletab-hide-alltabs-button]
+ .tabs-alltabs-stack {
+ visibility: collapse !important;
+}
+
+/* pinned tabs */
+.tabbrowser-tabs[treestyletab-mode="vertical"] {
+ -moz-margin-start: 0 !important;
+}
+
+.tabbrowser-tabs[treestyletab-mode="vertical"]
+ .tabbrowser-tab[pinned] {
+ /* height: 24px; */
+ line-height: 0;
+ position: fixed !important;
+ /* width: 24px; */
+ z-index: 100;
+}
+.tabbrowser-tabs[treestyletab-mode="vertical"][treestyletab-dom-fullscreen-activated="true"]
+ .tabbrowser-tab[pinned] {
+ z-index: -100;
+}
+
+.tabbrowser-tabs[treestyletab-mode="vertical"]
+ .tabbrowser-tab[pinned]:not(.treestyletab-faviconized)
+ .tab-label[pinned] {
+ width: auto;
+}
+
+/* print preview */
+.tabbrowser-strip[treestyletab-tabbar-fixed="true"]+splitter,
+.tabbrowser-strip[treestyletab-print-preview="true"],
+.tabbrowser-strip[treestyletab-print-preview="true"]+splitter,
+.treestyletab-tabbar-toolbar[treestyletab-print-preview="true"],
+tabbrowser[treestyletab-tabbar-autohide-mode="1"][treestyletab-print-preview="true"]
+ .treestyletab-tabbar-toggler {
+ visibility: collapse;
+}
+
+/* stylized window (opened by window.open() with features) */
+window[chromehidden~="toolbar"]
+ .tabbrowser-strip.treestyletab-tabbar-placeholder,
+window[chromehidden~="toolbar"]
+ .tabbrowser-strip.treestyletab-tabbar-placeholder+splitter,
+window[chromehidden~="toolbar"]
+ .treestyletab-tabbar-toolbar {
+ visibility: collapse;
+}
+
+
+/* full tooltip */
+
+#treestyletab-full-tree-tooltip[popup-shown="true"] {
+ -moz-transition: margin-left 0.2s ease-out,
+ margin-top 0.2s ease-out,
+ max-height 0.2s ease-out,
+ max-width 0.2s ease-out;
+ transition: margin-left 0.2s ease-out,
+ margin-top 0.2s ease-out,
+ max-height 0.2s ease-out,
+ max-width 0.2s ease-out;
+}
+
+#treestyletab-full-tree-tooltip > arrowscrollbox {
+ opacity: 0;
+}
+
+#treestyletab-full-tree-tooltip[popup-shown="true"] > arrowscrollbox {
+ -moz-transition: opacity 0.2s ease-out;
+ transition: opacity 0.2s ease-out;
+ opacity: 1;
+}
+
+
+/* addon compatibility */
+
+/* some themes */
+image.tab-icon {
+ display: -moz-stack;
+ -moz-binding: url(treestyletab.xml#tab-icon);
+}
+
+/* Tabbrowser Preferences, and some theme */
+.tabbrowser-tabs .tabs-newbutton,
+.tabbrowser-tabs[treestyletab-mode="vertical"] .scrollbutton-up,
+.tabbrowser-tabs[treestyletab-mode="vertical"] .scrollbutton-down {
+ max-width: none !important;
+}
+
+/* All-in-One Sidebar */
+#aiostbx-tableft-toolbox:not([incustomisemode="true"]) > toolbar[currentset="__empty"],
+#aiostbx-tableft-toolbox:not([incustomisemode="true"]) > toolbar:not([currentset]),
+#aiostbx-tabright-toolbox:not([incustomisemode="true"]) > toolbar[currentset="__empty"],
+#aiostbx-tabright-toolbox:not([incustomisemode="true"]) > toolbar:not([currentset]) {
+ visibility: collapse;
+}
+
+/* AutoHide */
+#appcontent[ahFull="true"] .tabbrowser-strip[ahHIDE="true"]+splitter {
+ visibility: collapse;
+}
+
+/* ColorfulTabs */
+:root:not([treestyletab-tabbar-position="top"]) #ctStack,
+:root:not([treestyletab-tabbar-fixed="true"]) #ctStack {
+ display: none;
+}
+
+/* Hide Caption Titlebar Plus */
+:root[treestyletab-tabbar-position="top"] #menubar-items[dz_home_mainmenu_floating="true"] {
+ z-index: 650000;
+}
diff --git a/content/treestyletab/treestyletab.js b/content/treestyletab/treestyletab.js
index e0cfae67..16c30415 100644
--- a/content/treestyletab/treestyletab.js
+++ b/content/treestyletab/treestyletab.js
@@ -1,23 +1,23 @@
-(function() {
- /**
- * On secondary (and later) window, SSWindowStateBusy event can be fired
- * before DOMContentLoad, on "domwindowopened".
- */
- var SSWindowStateBusyListener = function TSTSSWindowStateBusyListener(aEvent) {
- window.removeEventListener(aEvent.type, TSTSSWindowStateBusyListener, false);
- window.__treestyletab__WindowStateBusy = true;
- SSWindowStateBusyListener = undefined;
- };
- window.addEventListener('SSWindowStateBusy', SSWindowStateBusyListener, false);
- window.addEventListener('DOMContentLoad', function onDOMContentLoad(aEvent) {
- window.removeEventListener(aEvent.type, onDOMContentLoad, false);
- if (SSWindowStateBusyListener) {
- window.removeEventListener('SSWindowStateBusy', TSTSSWindowStateBusyListener, false);
- SSWindowStateBusyListener = undefined;
- }
- }, false);
-
- var ns = {};
- Components.utils.import('resource://treestyletab-modules/window.js', ns);
- new ns.TreeStyleTabWindow(window);
-})();
+(function() {
+ /**
+ * On secondary (and later) window, SSWindowStateBusy event can be fired
+ * before DOMContentLoad, on "domwindowopened".
+ */
+ var SSWindowStateBusyListener = function TSTSSWindowStateBusyListener(aEvent) {
+ window.removeEventListener(aEvent.type, TSTSSWindowStateBusyListener, false);
+ window.__treestyletab__WindowStateBusy = true;
+ SSWindowStateBusyListener = undefined;
+ };
+ window.addEventListener('SSWindowStateBusy', SSWindowStateBusyListener, false);
+ window.addEventListener('DOMContentLoad', function onDOMContentLoad(aEvent) {
+ window.removeEventListener(aEvent.type, onDOMContentLoad, false);
+ if (SSWindowStateBusyListener) {
+ window.removeEventListener('SSWindowStateBusy', TSTSSWindowStateBusyListener, false);
+ SSWindowStateBusyListener = undefined;
+ }
+ }, false);
+
+ var ns = {};
+ Components.utils.import('resource://treestyletab-modules/window.js', ns);
+ new ns.TreeStyleTabWindow(window);
+})();
diff --git a/content/treestyletab/treestyletab.xml b/content/treestyletab/treestyletab.xml
index e1edfcd5..ff98e8a8 100644
--- a/content/treestyletab/treestyletab.xml
+++ b/content/treestyletab/treestyletab.xml
@@ -1,54 +1,54 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- document.getAnonymousElementByAttribute(this, 'anonid', 'toolbar-innerbox')
-
-
-
-
-
-
-
-
- document.getAnonymousElementByAttribute(this, 'anonid', 'toolbar-innerbox')
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ document.getAnonymousElementByAttribute(this, 'anonid', 'toolbar-innerbox')
+
+
+
+
+
+
+
+
+ document.getAnonymousElementByAttribute(this, 'anonid', 'toolbar-innerbox')
+
+
+
+
+
diff --git a/content/treestyletab/treestyletab.xul b/content/treestyletab/treestyletab.xul
index 4dafd284..96cfdf1e 100644
--- a/content/treestyletab/treestyletab.xul
+++ b/content/treestyletab/treestyletab.xul
@@ -1,152 +1,152 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/content/treestyletab/windowHelper.js b/content/treestyletab/windowHelper.js
index 242223f1..9335d504 100644
--- a/content/treestyletab/windowHelper.js
+++ b/content/treestyletab/windowHelper.js
@@ -1,599 +1,599 @@
-var TreeStyleTabWindowHelper = {
-
- get service()
- {
- return TreeStyleTabService;
- },
-
- preInit : function TSTWH_preInit()
- {
- var source;
- var target;
- if ('gBrowserInit' in window) {
- if (
- '_delayedStartup' in gBrowserInit &&
- (source = gBrowserInit._delayedStartup.toSource()) &&
- source.indexOf('swapBrowsersAndCloseOther') > -1
- ) {
- target = 'gBrowserInit._delayedStartup';
- }
- }
- if (!target)
- dump('Tree Style Tab: failed to initialize startup function!');
- if (source.indexOf('!MultipleTabService.tearOffSelectedTabsFromRemote()') > -1) {
- eval(target+' = '+source.replace(
- '!MultipleTabService.tearOffSelectedTabsFromRemote()',
- '!TreeStyleTabService.tearOffSubtreeFromRemote() && $&'
- ));
- }
- else if (source.indexOf('gBrowser.swapBrowsersAndCloseOther') > -1) {
- eval(target+' = '+source.replace(
- 'gBrowser.swapBrowsersAndCloseOther(gBrowser.selectedTab, uriToLoad);',
- 'if (!TreeStyleTabService.tearOffSubtreeFromRemote()) { $& }'
- ).replace(
- // Workaround for https://github.com/piroor/treestyletab/issues/741
- // After the function is updated by TST, reassignment of a global variable raises an error like:
- // > System JS : ERROR chrome://treestyletab/content/windowHelper.js line 30 > eval:130 - TypeError: can't redefine non-configurable property 'gBidiUI'
- // If I access it as a property of the global object, the error doesn't appear.
- /([^\.])\bgBidiUI =/,
- '$1window.gBidiUI ='
- ));
- }
-
- eval('nsBrowserAccess.prototype.openURI = '+
- nsBrowserAccess.prototype.openURI.toSource().replace(
- /(switch\s*\(aWhere\))/,
- 'TreeStyleTabService.onBeforeBrowserAccessOpenURI(aOpener, aWhere); $1'
- )
- );
-
- if ('TabsInTitlebar' in window &&
- TabsInTitlebar._update) {
- eval('window.TabsInTitlebar._update = '+
- window.TabsInTitlebar._update.toSource().replace(
- /let fullTabsHeight = /,
- '$& gBrowser.treeStyleTab.position != "top" ? 0 : '
- )
- );
- }
-
- if ('BrowserOpenTab' in window) {
- eval('window.BrowserOpenTab = '+
- window.BrowserOpenTab.toSource().replace(
- 'openUILinkIn(',
- 'gBrowser.treeStyleTab.onBeforeNewTabCommand(); $&'
- )
- );
- }
-
- if ('undoCloseTab' in window) {
- eval('window.undoCloseTab = '+
- window.undoCloseTab.toSource().replace(
- /(\btab\s*=\s*[^\.]+\.undoCloseTab\([^;]+\);)/,
- 'gBrowser.__treestyletab__readyToUndoCloseTab = true;\n' +
- '$1\n' +
- 'tab.__treestyletab__restoredByUndoCloseTab = true;\n' +
- 'delete gBrowser.__treestyletab__readyToUndoCloseTab;'
- )
- );
- }
-
- if ('XULBrowserWindow' in window &&
- 'hideChromeForLocation' in window.XULBrowserWindow) {
- eval('XULBrowserWindow.hideChromeForLocation = '+
- XULBrowserWindow.hideChromeForLocation.toSource().replace(
- '{',
- '{ if (gBrowser.treeStyleTab.isVertical) return false;\n'
- )
- );
- }
-
- let (functions = [
- 'window.duplicateTab.handleLinkClick',
- 'window.duplicatethistab.handleLinkClick',
- 'window.__treestyletab__highlander__origHandleLinkClick',
- 'window.__splitbrowser__handleLinkClick',
- 'window.__ctxextensions__handleLinkClick',
- 'window.handleLinkClick'
- ]) {
- for (let i = 0, maxi = functions.length; i < maxi; i++)
- {
- let func = functions[i];
- let source = this._getFunctionSource(func);
- if (!source || !/^\(?function handleLinkClick/.test(source))
- continue;
- eval(func+' = '+source.replace(
- /(charset\s*:\s*doc\.characterSet\s*)/,
- '$1, event : event, linkNode : linkNode'
- ));
- break;
- }
- }
-
- this.overrideExtensionsPreInit(); // windowHelperHacks.js
- },
-
- onBeforeBrowserInit : function TSTWH_onBeforeBrowserInit()
- {
- this.overrideExtensionsBeforeBrowserInit(); // windowHelperHacks.js
- this.overrideGlobalFunctions();
- },
-
- onAfterBrowserInit : function TSTWH_onAfterBrowserInit()
- {
- this.overrideExtensionsAfterBrowserInit(); // windowHelperHacks.js
- },
-
- updateTabDNDObserver : function TSTWH_updateTabDNDObserver(aObserver)
- {
- var strip = this.service.getTabStrip(aObserver) ||
- gBrowser.mStrip // fallback to the default strip, for Tab Mix Plus;
-
- if (
- aObserver.tabContainer &&
- aObserver.tabContainer.tabbrowser == aObserver
- )
- aObserver = aObserver.tabContainer;
-
- if ('_setEffectAllowedForDataTransfer' in aObserver) {
- eval('aObserver._setEffectAllowedForDataTransfer = '+
- aObserver._setEffectAllowedForDataTransfer.toSource().replace(
- '{',
- '{ var TSTTabBrowser = this instanceof Ci.nsIDOMElement ? (this.tabbrowser || this) : gBrowser ; var TST = TSTTabBrowser.treeStyleTab;'
- ).replace(
- /\.screenX/g, '[TST.screenPositionProp]'
- ).replace(
- /\.width/g, '[TST.sizeProp]'
- ).replace(
- /(return (?:true|dt.effectAllowed = "copyMove");)/,
- 'if (!TST.tabbarDNDObserver.canDropTab(arguments[0])) {\n' +
- ' return dt.effectAllowed = "none";\n' +
- '}\n' +
- '$1'
- ).replace(
- 'sourceNode.parentNode == this &&',
- '$& TST.getTabFromEvent(event) == sourceNode &&'
- )
- );
- }
- },
-
- overrideGlobalFunctions : function TSTWH_overrideGlobalFunctions()
- {
- this.initToolbarItems();
-
- eval('nsContextMenu.prototype.openLinkInTab = '+
- nsContextMenu.prototype.openLinkInTab.toSource().replace(
- '{',
- '{\n' +
- ' TreeStyleTabService.handleNewTabFromCurrent(this.target.ownerDocument.defaultView);'
- )
- );
- eval('nsContextMenu.prototype.openFrameInTab = '+
- nsContextMenu.prototype.openFrameInTab.toSource().replace(
- '{',
- '{\n' +
- ' TreeStyleTabService.handleNewTabFromCurrent(this.target.ownerDocument.defaultView);'
- )
- );
- var viewImageMethod = ('viewImage' in nsContextMenu.prototype) ? 'viewImage' : 'viewMedia' ;
- eval('nsContextMenu.prototype.'+viewImageMethod+' = '+
- nsContextMenu.prototype[viewImageMethod].toSource().replace(
- 'openUILink(',
- 'TreeStyleTabService.onBeforeViewMedia(e, this.target.ownerDocument.defaultView); $&'
- )
- );
- eval('nsContextMenu.prototype.viewBGImage = '+
- nsContextMenu.prototype.viewBGImage.toSource().replace(
- 'openUILink(',
- 'TreeStyleTabService.onBeforeViewMedia(e, this.target.ownerDocument.defaultView); $&'
- )
- );
- eval('nsContextMenu.prototype.addDictionaries = '+
- nsContextMenu.prototype.addDictionaries.toSource().replace(
- 'openUILinkIn(',
- 'TreeStyleTabService.onBeforeOpenLink(where, this.target.ownerDocument.defaultView); $&'
- )
- );
-
- if ('BrowserSearch' in window &&
- '_loadSearch' in BrowserSearch) {
- eval('BrowserSearch._loadSearch = '+
- BrowserSearch._loadSearch.toSource().replace(
- 'openLinkIn(',
- 'TreeStyleTabService.onBeforeBrowserSearch(arguments[0], useNewTab); $&'
- )
- );
- }
-
- if ('openLinkIn' in window) {
- // Bug 1050447 changed this line in Fx 34 to
- // newTab = w.gBrowser.loadOneTab(
- eval('window.openLinkIn = '+
- window.openLinkIn.toSource().replace(
- /((b|newTab = w\.gB)rowser.loadOneTab\()/g,
- 'TreeStyleTabService.onBeforeOpenLinkWithTab(gBrowser.selectedTab, aFromChrome); $1'
- )
- );
- }
-
- let (functions = [
- 'window.permaTabs.utils.wrappedFunctions["window.contentAreaClick"]',
- 'window.__contentAreaClick',
- 'window.__ctxextensions__contentAreaClick',
- 'window.contentAreaClick'
- ]) {
- for (let i = 0, maxi = functions.length; i < maxi; i++)
- {
- let func = functions[i];
- let source = this._getFunctionSource(func);
- if (!source || !/^\(?function contentAreaClick/.test(source))
- continue;
- eval(func+' = '+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,
- 'TreeStyleTabService.onBeforeOpenNewTabByThirdParty(event.target.ownerDocument.defaultView); $1'
- ));
- }
- }
-
- if (window.duplicateTabIn) {
- eval('window.duplicateTabIn = '+
- window.duplicateTabIn.toSource().replace(
- '{',
- '{ gBrowser.treeStyleTab.onBeforeTabDuplicate(aTab, where, delta); '
- )
- );
- }
-
- let (functions = [
- 'permaTabs.utils.wrappedFunctions["window.BrowserHomeClick"]',
- 'window.BrowserHomeClick',
- 'window.BrowserGoHome'
- ]) {
- for (let i = 0, maxi = functions.length; i < maxi; i++)
- {
- let func = functions[i];
- let source = this._getFunctionSource(func);
- if (!source || !/^\(?function (BrowserHomeClick|BrowserGoHome)/.test(source))
- continue;
- eval(func+' = '+source.replace(
- 'gBrowser.loadTabs(',
- 'TreeStyleTabService.readyToOpenNewTabGroup(gBrowser); $&'
- ));
- }
- }
-
- eval('FeedHandler.loadFeed = '+
- FeedHandler.loadFeed.toSource().replace(
- 'openUILink(',
- 'TreeStyleTabService.onBeforeViewMedia(event, gBrowser); $&'
- )
- );
-
- eval('FullScreen.mouseoverToggle = '+
- FullScreen.mouseoverToggle.toSource().replace(
- 'this._isChromeCollapsed = !aShow;',
- 'gBrowser.treeStyleTab.updateFloatingTabbar(gBrowser.treeStyleTab.kTABBAR_UPDATE_BY_FULLSCREEN); $&'
- )
- );
- eval('FullScreen.toggle = '+
- FullScreen.toggle.toSource().replace(
- '{',
- '{ gBrowser.treeStyleTab.onBeforeFullScreenToggle(); '
- )
- );
-
- 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.syncUI) {
- eval('TabsOnTop.syncUI = '+TabsOnTop.syncUI.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_TOGGLE_SIDEBAR);'
- )
- );
- }
- },
- _splitFunctionNames : function TSTWH__splitFunctionNames(aString)
- {
- return String(aString)
- .split(/\s+/)
- .map(function(aString) {
- return aString
- .replace(/\/\*.*\*\//g, '')
- .replace(/\/\/.+$/, '')
- .trim();
- });
- },
- _getFunctionSource : function TSTWH__getFunctionSource(aFunc)
- {
- var func;
- try {
- eval('func = '+aFunc);
- }
- catch(e) {
- return null;
- }
- return func ? func.toSource() : null ;
- },
-
- initToolbarItems : function TSTWH_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\(.+?\);)/,
- 'TreeStyleTabService.onBeforeBrowserSearch(arguments[0]);\n' +
- '$1\n' +
- 'TreeStyleTabService.stopToOpenChildTab();'
- ));
- }
-
- var goButton = document.getElementById('urlbar-go-button');
- if (goButton)
- goButton.parentNode.addEventListener('click', this.service, true);
-
- var tabbar = this.service.getTabStrip(this.service.browser);
- tabbar.addEventListener('click', this.service, true);
-
- var newTabButton = document.getElementById('new-tab-button');
- const nsIDOMNode = Ci.nsIDOMNode;
- if (newTabButton &&
- !(tabbar.compareDocumentPosition(newTabButton) & nsIDOMNode.DOCUMENT_POSITION_CONTAINED_BY))
- newTabButton.parentNode.addEventListener('click', this.service, true);
-
- this.service.updateAllTabsButton(gBrowser);
- },
-
- destroyToolbarItems : function TSTWH_destroyToolbarItems()
- {
- var goButton = document.getElementById('urlbar-go-button');
- if (goButton)
- goButton.parentNode.removeEventListener('click', this, true);
-
- var tabbar = this.service.getTabStrip(this.service.browser);
- tabbar.removeEventListener('click', this.service, true);
-
- var newTabButton = document.getElementById('new-tab-button');
- const nsIDOMNode = Ci.nsIDOMNode;
- if (newTabButton &&
- !(tabbar.compareDocumentPosition(newTabButton) & Ci.nsIDOMNode.DOCUMENT_POSITION_CONTAINED_BY))
- newTabButton.parentNode.removeEventListener('click', this.service, true);
-
- var allTabsButton = document.getElementById('alltabs-button');
- if (allTabsButton && allTabsButton.hasChildNodes())
- allTabsButton.firstChild.setAttribute('position', 'after_end');
- },
-
- initTabbrowserMethods : function TSTWH_initTabbrowserMethods(aTabBrowser)
- {
- var b = aTabBrowser;
-
- let (source = b.moveTabForward.toSource()) {
- eval('b.moveTabForward = '+
- source.replace(
- 'if (nextTab)',
- '(function() {\n' +
- ' if (this.treeStyleTab.hasChildTabs(this.mCurrentTab)) {\n' +
- ' let descendant = this.treeStyleTab.getDescendantTabs(this.mCurrentTab);\n' +
- ' if (descendant.length)\n' +
- ' nextTab = this.treeStyleTab.getNextTab(descendant[descendant.length-1]);\n' +
- ' }\n' +
- '}).call(this);' +
- '$&'
- ).replace(
- /(this.moveTabTo\([^;]+\);)/,
- '(function() {\n' +
- ' let descendant = this.treeStyleTab.getDescendantTabs(nextTab);\n' +
- ' if (descendant.length) {\n' +
- ' nextTab = descendant[descendant.length-1];\n' +
- ' }\n' +
- ' $1\n' +
- '}).call(this);'
- ).replace(
- 'this.moveTabToStart();',
- '(function() {\n' +
- ' this.treeStyleTab.internallyTabMovingCount++;\n' +
- ' let parentTab = this.treeStyleTab.getParentTab(this.mCurrentTab);\n' +
- ' if (parentTab) {\n' +
- ' this.moveTabTo(this.mCurrentTab, this.treeStyleTab.getFirstChildTab(parentTab)._tPos);\n' +
- ' this.mCurrentTab.focus();\n' +
- ' }\n' +
- ' else {\n' +
- ' $&\n' +
- ' }\n' +
- ' this.treeStyleTab.internallyTabMovingCount--;\n' +
- '}).call(this);'
- )
- );
- }
-
- let (source = b.moveTabBackward.toSource()) {
- eval('b.moveTabBackward = '+
- source.replace(
- 'this.moveTabToEnd();',
- '(function() {\n' +
- ' this.treeStyleTab.internallyTabMovingCount++;\n' +
- ' let parentTab = this.treeStyleTab.getParentTab(this.mCurrentTab);\n' +
- ' if (parentTab) {\n' +
- ' this.moveTabTo(this.mCurrentTab, this.treeStyleTab.getLastChildTab(parentTab)._tPos);\n' +
- ' this.mCurrentTab.focus();\n' +
- ' }\n' +
- ' else {\n' +
- ' $&\n' +
- ' }\n' +
- ' this.treeStyleTab.internallyTabMovingCount--;\n' +
- '}).call(this);'
- )
- );
- }
-
- eval('b.loadTabs = '+
- b.loadTabs.toSource().replace(
- 'var tabNum = ',
- 'if (this.treeStyleTab.readiedToAttachNewTabGroup)\n' +
- ' TreeStyleTabService.readyToOpenChildTab(firstTabAdded || this.selectedTab, true);\n' +
- '$&'
- ).replace(
- 'if (!aLoadInBackground)',
- 'if (TreeStyleTabService.checkToOpenChildTab(this))\n' +
- ' TreeStyleTabService.stopToOpenChildTab(this);\n' +
- '$&'
- ).replace(
- 'this.selectedTab = firstTabAdded;',
- 'this.selectedTab = aURIs[0].indexOf("about:treestyletab-group") < 0 ? \n' +
- ' firstTabAdded :\n' +
- ' TreeStyleTabService.getNextTab(firstTabAdded) ;'
- )
- );
-
- if ('_beginRemoveTab' in b) {
- eval('b._beginRemoveTab = '+
- b._beginRemoveTab.toSource().replace(
- 'if (this.tabs.length - this._removingTabs.length == 1) {',
- 'if (this.tabs.length - this._removingTabs.length == 1 || this.treeStyleTab.shouldCloseLastTabSubtreeOf(aTab)) {'
- ).replace(
- 'this._removingTabs.length == 0',
- '(this.treeStyleTab.shouldCloseLastTabSubtreeOf(aTab) || $&)'
- )
- );
- }
-
- eval('b.removeCurrentTab = '+b.removeCurrentTab.toSource().replace(
- '{',
- '{ if (!this.treeStyleTab.warnAboutClosingTabSubtreeOf(this.selectedTab)) return;'
- ));
- },
-
- initTabbarMethods : function TSTWH_initTabbarMethods(aTabBrowser)
- {
- var b = aTabBrowser;
-
- var source = b.mTabContainer.advanceSelectedTab.toSource();
- if (source.indexOf('treeStyleTab.handleAdvanceSelectedTab') < 0) {
- eval('b.mTabContainer.advanceSelectedTab = '+
- source.replace(
- '{',
- '{\n' +
- ' var treeStyleTab = TreeStyleTabService.getTabBrowserFromChild(this).treeStyleTab;\n' +
- ' if (treeStyleTab.handleAdvanceSelectedTab(arguments[0], arguments[1]))\n' +
- ' return;'
- )
- );
- }
-
- source = b.mTabContainer._notifyBackgroundTab.toSource();
- if (source.indexOf('TreeStyleTabService.getTabBrowserFromChild') < 0) {
- eval('b.mTabContainer._notifyBackgroundTab = '+
- source.replace(
- '{',
- '{\n' +
- ' var treeStyleTab = TreeStyleTabService.getTabBrowserFromChild(this).treeStyleTab;\n' +
- ' if (treeStyleTab.scrollToNewTabMode == 0 ||\n' +
- ' treeStyleTab.shouldCancelEnsureElementIsVisible())\n' +
- ' return;'
- ).replace(
- /\.screenX/g, '[treeStyleTab.screenPositionProp]'
- ).replace(
- /\.width/g, '[treeStyleTab.sizeProp]'
- ).replace(
- /\.left/g, '[treeStyleTab.startProp]'
- ).replace(
- /\.right/g, '[treeStyleTab.endProp]'
-
- // replace such codes:
- // tab = {left: tab.left, right: tab.right};
- ).replace(
- /left\s*:/g, 'start:'
- ).replace(
- /right\s*:/g, 'end:'
- ).replace(
- /((tab|selected)\s*=\s*\{\s*start:[^\}]+\})/g,
- '$1; $2[treeStyleTab.startProp] = $2.start; $2[treeStyleTab.endProp] = $2.end;'
-
- ).replace(
- '!selected ||',
- '$& treeStyleTab.scrollToNewTabMode == 1 && '
- ).replace(
- /(\}\)?)$/,
- 'treeStyleTab.notifyBackgroundTab(); $1'
- )
- );
- }
-
- if (b.tabContainer && '_getDropIndex' in b.tabContainer) {
- eval('b.tabContainer._getDropIndex = '+
- b.tabContainer._getDropIndex.toSource().replace(
- /\.screenX/g, '[this.treeStyleTab.screenPositionProp]'
- ).replace(
- /\.width/g, '[this.treeStyleTab.sizeProp]'
- )
- );
- }
-
- /**
- * The default implementation fails to scroll to tab if it is expanding.
- * So we have to inject codes to override its effect.
- */
- let (scrollbox = aTabBrowser.treeStyleTab.scrollBox) {
- let source = scrollbox.ensureElementIsVisible.toSource();
- if (
- source.indexOf('treeStyleTab') < 0 && // not updated yet
- source.indexOf('ensureTabIsVisible') < 0 // not replaced by Tab Mix Plus
- ) {
- eval('scrollbox.ensureElementIsVisible = '+
- source.replace(
- '{',
- '{\n' +
- ' var treeStyleTab = TreeStyleTabService.getTabBrowserFromChild(this).treeStyleTab;\n' +
- ' if (treeStyleTab && treeStyleTab.shouldCancelEnsureElementIsVisible())\n' +
- ' return;\n' +
- ' if (\n' +
- ' treeStyleTab &&\n' +
- ' (arguments.length == 1 || arguments[1])\n' +
- ' )\n' +
- ' return treeStyleTab.scrollToTab(arguments[0]);'
- )
- );
- }
- }
-
- let (popup = document.getElementById('alltabs-popup')) {
- if (popup && '_updateTabsVisibilityStatus' in popup) {
- eval('popup._updateTabsVisibilityStatus = '+
- popup._updateTabsVisibilityStatus.toSource().replace(
- '{',
- '{ var treeStyleTab = gBrowser.treeStyleTab;'
- ).replace(
- /\.screenX/g, '[treeStyleTab.screenPositionProp]'
- ).replace(
- /\.width/g, '[treeStyleTab.sizeProp]'
- )
- );
- }
- }
-
- }
-
-};
-
+var TreeStyleTabWindowHelper = {
+
+ get service()
+ {
+ return TreeStyleTabService;
+ },
+
+ preInit : function TSTWH_preInit()
+ {
+ var source;
+ var target;
+ if ('gBrowserInit' in window) {
+ if (
+ '_delayedStartup' in gBrowserInit &&
+ (source = gBrowserInit._delayedStartup.toSource()) &&
+ source.indexOf('swapBrowsersAndCloseOther') > -1
+ ) {
+ target = 'gBrowserInit._delayedStartup';
+ }
+ }
+ if (!target)
+ dump('Tree Style Tab: failed to initialize startup function!');
+ if (source.indexOf('!MultipleTabService.tearOffSelectedTabsFromRemote()') > -1) {
+ eval(target+' = '+source.replace(
+ '!MultipleTabService.tearOffSelectedTabsFromRemote()',
+ '!TreeStyleTabService.tearOffSubtreeFromRemote() && $&'
+ ));
+ }
+ else if (source.indexOf('gBrowser.swapBrowsersAndCloseOther') > -1) {
+ eval(target+' = '+source.replace(
+ 'gBrowser.swapBrowsersAndCloseOther(gBrowser.selectedTab, uriToLoad);',
+ 'if (!TreeStyleTabService.tearOffSubtreeFromRemote()) { $& }'
+ ).replace(
+ // Workaround for https://github.com/piroor/treestyletab/issues/741
+ // After the function is updated by TST, reassignment of a global variable raises an error like:
+ // > System JS : ERROR chrome://treestyletab/content/windowHelper.js line 30 > eval:130 - TypeError: can't redefine non-configurable property 'gBidiUI'
+ // If I access it as a property of the global object, the error doesn't appear.
+ /([^\.])\bgBidiUI =/,
+ '$1window.gBidiUI ='
+ ));
+ }
+
+ eval('nsBrowserAccess.prototype.openURI = '+
+ nsBrowserAccess.prototype.openURI.toSource().replace(
+ /(switch\s*\(aWhere\))/,
+ 'TreeStyleTabService.onBeforeBrowserAccessOpenURI(aOpener, aWhere); $1'
+ )
+ );
+
+ if ('TabsInTitlebar' in window &&
+ TabsInTitlebar._update) {
+ eval('window.TabsInTitlebar._update = '+
+ window.TabsInTitlebar._update.toSource().replace(
+ /let fullTabsHeight = /,
+ '$& gBrowser.treeStyleTab.position != "top" ? 0 : '
+ )
+ );
+ }
+
+ if ('BrowserOpenTab' in window) {
+ eval('window.BrowserOpenTab = '+
+ window.BrowserOpenTab.toSource().replace(
+ 'openUILinkIn(',
+ 'gBrowser.treeStyleTab.onBeforeNewTabCommand(); $&'
+ )
+ );
+ }
+
+ if ('undoCloseTab' in window) {
+ eval('window.undoCloseTab = '+
+ window.undoCloseTab.toSource().replace(
+ /(\btab\s*=\s*[^\.]+\.undoCloseTab\([^;]+\);)/,
+ 'gBrowser.__treestyletab__readyToUndoCloseTab = true;\n' +
+ '$1\n' +
+ 'tab.__treestyletab__restoredByUndoCloseTab = true;\n' +
+ 'delete gBrowser.__treestyletab__readyToUndoCloseTab;'
+ )
+ );
+ }
+
+ if ('XULBrowserWindow' in window &&
+ 'hideChromeForLocation' in window.XULBrowserWindow) {
+ eval('XULBrowserWindow.hideChromeForLocation = '+
+ XULBrowserWindow.hideChromeForLocation.toSource().replace(
+ '{',
+ '{ if (gBrowser.treeStyleTab.isVertical) return false;\n'
+ )
+ );
+ }
+
+ let (functions = [
+ 'window.duplicateTab.handleLinkClick',
+ 'window.duplicatethistab.handleLinkClick',
+ 'window.__treestyletab__highlander__origHandleLinkClick',
+ 'window.__splitbrowser__handleLinkClick',
+ 'window.__ctxextensions__handleLinkClick',
+ 'window.handleLinkClick'
+ ]) {
+ for (let i = 0, maxi = functions.length; i < maxi; i++)
+ {
+ let func = functions[i];
+ let source = this._getFunctionSource(func);
+ if (!source || !/^\(?function handleLinkClick/.test(source))
+ continue;
+ eval(func+' = '+source.replace(
+ /(charset\s*:\s*doc\.characterSet\s*)/,
+ '$1, event : event, linkNode : linkNode'
+ ));
+ break;
+ }
+ }
+
+ this.overrideExtensionsPreInit(); // windowHelperHacks.js
+ },
+
+ onBeforeBrowserInit : function TSTWH_onBeforeBrowserInit()
+ {
+ this.overrideExtensionsBeforeBrowserInit(); // windowHelperHacks.js
+ this.overrideGlobalFunctions();
+ },
+
+ onAfterBrowserInit : function TSTWH_onAfterBrowserInit()
+ {
+ this.overrideExtensionsAfterBrowserInit(); // windowHelperHacks.js
+ },
+
+ updateTabDNDObserver : function TSTWH_updateTabDNDObserver(aObserver)
+ {
+ var strip = this.service.getTabStrip(aObserver) ||
+ gBrowser.mStrip // fallback to the default strip, for Tab Mix Plus;
+
+ if (
+ aObserver.tabContainer &&
+ aObserver.tabContainer.tabbrowser == aObserver
+ )
+ aObserver = aObserver.tabContainer;
+
+ if ('_setEffectAllowedForDataTransfer' in aObserver) {
+ eval('aObserver._setEffectAllowedForDataTransfer = '+
+ aObserver._setEffectAllowedForDataTransfer.toSource().replace(
+ '{',
+ '{ var TSTTabBrowser = this instanceof Ci.nsIDOMElement ? (this.tabbrowser || this) : gBrowser ; var TST = TSTTabBrowser.treeStyleTab;'
+ ).replace(
+ /\.screenX/g, '[TST.screenPositionProp]'
+ ).replace(
+ /\.width/g, '[TST.sizeProp]'
+ ).replace(
+ /(return (?:true|dt.effectAllowed = "copyMove");)/,
+ 'if (!TST.tabbarDNDObserver.canDropTab(arguments[0])) {\n' +
+ ' return dt.effectAllowed = "none";\n' +
+ '}\n' +
+ '$1'
+ ).replace(
+ 'sourceNode.parentNode == this &&',
+ '$& TST.getTabFromEvent(event) == sourceNode &&'
+ )
+ );
+ }
+ },
+
+ overrideGlobalFunctions : function TSTWH_overrideGlobalFunctions()
+ {
+ this.initToolbarItems();
+
+ eval('nsContextMenu.prototype.openLinkInTab = '+
+ nsContextMenu.prototype.openLinkInTab.toSource().replace(
+ '{',
+ '{\n' +
+ ' TreeStyleTabService.handleNewTabFromCurrent(this.target.ownerDocument.defaultView);'
+ )
+ );
+ eval('nsContextMenu.prototype.openFrameInTab = '+
+ nsContextMenu.prototype.openFrameInTab.toSource().replace(
+ '{',
+ '{\n' +
+ ' TreeStyleTabService.handleNewTabFromCurrent(this.target.ownerDocument.defaultView);'
+ )
+ );
+ var viewImageMethod = ('viewImage' in nsContextMenu.prototype) ? 'viewImage' : 'viewMedia' ;
+ eval('nsContextMenu.prototype.'+viewImageMethod+' = '+
+ nsContextMenu.prototype[viewImageMethod].toSource().replace(
+ 'openUILink(',
+ 'TreeStyleTabService.onBeforeViewMedia(e, this.target.ownerDocument.defaultView); $&'
+ )
+ );
+ eval('nsContextMenu.prototype.viewBGImage = '+
+ nsContextMenu.prototype.viewBGImage.toSource().replace(
+ 'openUILink(',
+ 'TreeStyleTabService.onBeforeViewMedia(e, this.target.ownerDocument.defaultView); $&'
+ )
+ );
+ eval('nsContextMenu.prototype.addDictionaries = '+
+ nsContextMenu.prototype.addDictionaries.toSource().replace(
+ 'openUILinkIn(',
+ 'TreeStyleTabService.onBeforeOpenLink(where, this.target.ownerDocument.defaultView); $&'
+ )
+ );
+
+ if ('BrowserSearch' in window &&
+ '_loadSearch' in BrowserSearch) {
+ eval('BrowserSearch._loadSearch = '+
+ BrowserSearch._loadSearch.toSource().replace(
+ 'openLinkIn(',
+ 'TreeStyleTabService.onBeforeBrowserSearch(arguments[0], useNewTab); $&'
+ )
+ );
+ }
+
+ if ('openLinkIn' in window) {
+ // Bug 1050447 changed this line in Fx 34 to
+ // newTab = w.gBrowser.loadOneTab(
+ eval('window.openLinkIn = '+
+ window.openLinkIn.toSource().replace(
+ /((b|newTab = w\.gB)rowser.loadOneTab\()/g,
+ 'TreeStyleTabService.onBeforeOpenLinkWithTab(gBrowser.selectedTab, aFromChrome); $1'
+ )
+ );
+ }
+
+ let (functions = [
+ 'window.permaTabs.utils.wrappedFunctions["window.contentAreaClick"]',
+ 'window.__contentAreaClick',
+ 'window.__ctxextensions__contentAreaClick',
+ 'window.contentAreaClick'
+ ]) {
+ for (let i = 0, maxi = functions.length; i < maxi; i++)
+ {
+ let func = functions[i];
+ let source = this._getFunctionSource(func);
+ if (!source || !/^\(?function contentAreaClick/.test(source))
+ continue;
+ eval(func+' = '+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,
+ 'TreeStyleTabService.onBeforeOpenNewTabByThirdParty(event.target.ownerDocument.defaultView); $1'
+ ));
+ }
+ }
+
+ if (window.duplicateTabIn) {
+ eval('window.duplicateTabIn = '+
+ window.duplicateTabIn.toSource().replace(
+ '{',
+ '{ gBrowser.treeStyleTab.onBeforeTabDuplicate(aTab, where, delta); '
+ )
+ );
+ }
+
+ let (functions = [
+ 'permaTabs.utils.wrappedFunctions["window.BrowserHomeClick"]',
+ 'window.BrowserHomeClick',
+ 'window.BrowserGoHome'
+ ]) {
+ for (let i = 0, maxi = functions.length; i < maxi; i++)
+ {
+ let func = functions[i];
+ let source = this._getFunctionSource(func);
+ if (!source || !/^\(?function (BrowserHomeClick|BrowserGoHome)/.test(source))
+ continue;
+ eval(func+' = '+source.replace(
+ 'gBrowser.loadTabs(',
+ 'TreeStyleTabService.readyToOpenNewTabGroup(gBrowser); $&'
+ ));
+ }
+ }
+
+ eval('FeedHandler.loadFeed = '+
+ FeedHandler.loadFeed.toSource().replace(
+ 'openUILink(',
+ 'TreeStyleTabService.onBeforeViewMedia(event, gBrowser); $&'
+ )
+ );
+
+ eval('FullScreen.mouseoverToggle = '+
+ FullScreen.mouseoverToggle.toSource().replace(
+ 'this._isChromeCollapsed = !aShow;',
+ 'gBrowser.treeStyleTab.updateFloatingTabbar(gBrowser.treeStyleTab.kTABBAR_UPDATE_BY_FULLSCREEN); $&'
+ )
+ );
+ eval('FullScreen.toggle = '+
+ FullScreen.toggle.toSource().replace(
+ '{',
+ '{ gBrowser.treeStyleTab.onBeforeFullScreenToggle(); '
+ )
+ );
+
+ 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.syncUI) {
+ eval('TabsOnTop.syncUI = '+TabsOnTop.syncUI.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_TOGGLE_SIDEBAR);'
+ )
+ );
+ }
+ },
+ _splitFunctionNames : function TSTWH__splitFunctionNames(aString)
+ {
+ return String(aString)
+ .split(/\s+/)
+ .map(function(aString) {
+ return aString
+ .replace(/\/\*.*\*\//g, '')
+ .replace(/\/\/.+$/, '')
+ .trim();
+ });
+ },
+ _getFunctionSource : function TSTWH__getFunctionSource(aFunc)
+ {
+ var func;
+ try {
+ eval('func = '+aFunc);
+ }
+ catch(e) {
+ return null;
+ }
+ return func ? func.toSource() : null ;
+ },
+
+ initToolbarItems : function TSTWH_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\(.+?\);)/,
+ 'TreeStyleTabService.onBeforeBrowserSearch(arguments[0]);\n' +
+ '$1\n' +
+ 'TreeStyleTabService.stopToOpenChildTab();'
+ ));
+ }
+
+ var goButton = document.getElementById('urlbar-go-button');
+ if (goButton)
+ goButton.parentNode.addEventListener('click', this.service, true);
+
+ var tabbar = this.service.getTabStrip(this.service.browser);
+ tabbar.addEventListener('click', this.service, true);
+
+ var newTabButton = document.getElementById('new-tab-button');
+ const nsIDOMNode = Ci.nsIDOMNode;
+ if (newTabButton &&
+ !(tabbar.compareDocumentPosition(newTabButton) & nsIDOMNode.DOCUMENT_POSITION_CONTAINED_BY))
+ newTabButton.parentNode.addEventListener('click', this.service, true);
+
+ this.service.updateAllTabsButton(gBrowser);
+ },
+
+ destroyToolbarItems : function TSTWH_destroyToolbarItems()
+ {
+ var goButton = document.getElementById('urlbar-go-button');
+ if (goButton)
+ goButton.parentNode.removeEventListener('click', this, true);
+
+ var tabbar = this.service.getTabStrip(this.service.browser);
+ tabbar.removeEventListener('click', this.service, true);
+
+ var newTabButton = document.getElementById('new-tab-button');
+ const nsIDOMNode = Ci.nsIDOMNode;
+ if (newTabButton &&
+ !(tabbar.compareDocumentPosition(newTabButton) & Ci.nsIDOMNode.DOCUMENT_POSITION_CONTAINED_BY))
+ newTabButton.parentNode.removeEventListener('click', this.service, true);
+
+ var allTabsButton = document.getElementById('alltabs-button');
+ if (allTabsButton && allTabsButton.hasChildNodes())
+ allTabsButton.firstChild.setAttribute('position', 'after_end');
+ },
+
+ initTabbrowserMethods : function TSTWH_initTabbrowserMethods(aTabBrowser)
+ {
+ var b = aTabBrowser;
+
+ let (source = b.moveTabForward.toSource()) {
+ eval('b.moveTabForward = '+
+ source.replace(
+ 'if (nextTab)',
+ '(function() {\n' +
+ ' if (this.treeStyleTab.hasChildTabs(this.mCurrentTab)) {\n' +
+ ' let descendant = this.treeStyleTab.getDescendantTabs(this.mCurrentTab);\n' +
+ ' if (descendant.length)\n' +
+ ' nextTab = this.treeStyleTab.getNextTab(descendant[descendant.length-1]);\n' +
+ ' }\n' +
+ '}).call(this);' +
+ '$&'
+ ).replace(
+ /(this.moveTabTo\([^;]+\);)/,
+ '(function() {\n' +
+ ' let descendant = this.treeStyleTab.getDescendantTabs(nextTab);\n' +
+ ' if (descendant.length) {\n' +
+ ' nextTab = descendant[descendant.length-1];\n' +
+ ' }\n' +
+ ' $1\n' +
+ '}).call(this);'
+ ).replace(
+ 'this.moveTabToStart();',
+ '(function() {\n' +
+ ' this.treeStyleTab.internallyTabMovingCount++;\n' +
+ ' let parentTab = this.treeStyleTab.getParentTab(this.mCurrentTab);\n' +
+ ' if (parentTab) {\n' +
+ ' this.moveTabTo(this.mCurrentTab, this.treeStyleTab.getFirstChildTab(parentTab)._tPos);\n' +
+ ' this.mCurrentTab.focus();\n' +
+ ' }\n' +
+ ' else {\n' +
+ ' $&\n' +
+ ' }\n' +
+ ' this.treeStyleTab.internallyTabMovingCount--;\n' +
+ '}).call(this);'
+ )
+ );
+ }
+
+ let (source = b.moveTabBackward.toSource()) {
+ eval('b.moveTabBackward = '+
+ source.replace(
+ 'this.moveTabToEnd();',
+ '(function() {\n' +
+ ' this.treeStyleTab.internallyTabMovingCount++;\n' +
+ ' let parentTab = this.treeStyleTab.getParentTab(this.mCurrentTab);\n' +
+ ' if (parentTab) {\n' +
+ ' this.moveTabTo(this.mCurrentTab, this.treeStyleTab.getLastChildTab(parentTab)._tPos);\n' +
+ ' this.mCurrentTab.focus();\n' +
+ ' }\n' +
+ ' else {\n' +
+ ' $&\n' +
+ ' }\n' +
+ ' this.treeStyleTab.internallyTabMovingCount--;\n' +
+ '}).call(this);'
+ )
+ );
+ }
+
+ eval('b.loadTabs = '+
+ b.loadTabs.toSource().replace(
+ 'var tabNum = ',
+ 'if (this.treeStyleTab.readiedToAttachNewTabGroup)\n' +
+ ' TreeStyleTabService.readyToOpenChildTab(firstTabAdded || this.selectedTab, true);\n' +
+ '$&'
+ ).replace(
+ 'if (!aLoadInBackground)',
+ 'if (TreeStyleTabService.checkToOpenChildTab(this))\n' +
+ ' TreeStyleTabService.stopToOpenChildTab(this);\n' +
+ '$&'
+ ).replace(
+ 'this.selectedTab = firstTabAdded;',
+ 'this.selectedTab = aURIs[0].indexOf("about:treestyletab-group") < 0 ? \n' +
+ ' firstTabAdded :\n' +
+ ' TreeStyleTabService.getNextTab(firstTabAdded) ;'
+ )
+ );
+
+ if ('_beginRemoveTab' in b) {
+ eval('b._beginRemoveTab = '+
+ b._beginRemoveTab.toSource().replace(
+ 'if (this.tabs.length - this._removingTabs.length == 1) {',
+ 'if (this.tabs.length - this._removingTabs.length == 1 || this.treeStyleTab.shouldCloseLastTabSubtreeOf(aTab)) {'
+ ).replace(
+ 'this._removingTabs.length == 0',
+ '(this.treeStyleTab.shouldCloseLastTabSubtreeOf(aTab) || $&)'
+ )
+ );
+ }
+
+ eval('b.removeCurrentTab = '+b.removeCurrentTab.toSource().replace(
+ '{',
+ '{ if (!this.treeStyleTab.warnAboutClosingTabSubtreeOf(this.selectedTab)) return;'
+ ));
+ },
+
+ initTabbarMethods : function TSTWH_initTabbarMethods(aTabBrowser)
+ {
+ var b = aTabBrowser;
+
+ var source = b.mTabContainer.advanceSelectedTab.toSource();
+ if (source.indexOf('treeStyleTab.handleAdvanceSelectedTab') < 0) {
+ eval('b.mTabContainer.advanceSelectedTab = '+
+ source.replace(
+ '{',
+ '{\n' +
+ ' var treeStyleTab = TreeStyleTabService.getTabBrowserFromChild(this).treeStyleTab;\n' +
+ ' if (treeStyleTab.handleAdvanceSelectedTab(arguments[0], arguments[1]))\n' +
+ ' return;'
+ )
+ );
+ }
+
+ source = b.mTabContainer._notifyBackgroundTab.toSource();
+ if (source.indexOf('TreeStyleTabService.getTabBrowserFromChild') < 0) {
+ eval('b.mTabContainer._notifyBackgroundTab = '+
+ source.replace(
+ '{',
+ '{\n' +
+ ' var treeStyleTab = TreeStyleTabService.getTabBrowserFromChild(this).treeStyleTab;\n' +
+ ' if (treeStyleTab.scrollToNewTabMode == 0 ||\n' +
+ ' treeStyleTab.shouldCancelEnsureElementIsVisible())\n' +
+ ' return;'
+ ).replace(
+ /\.screenX/g, '[treeStyleTab.screenPositionProp]'
+ ).replace(
+ /\.width/g, '[treeStyleTab.sizeProp]'
+ ).replace(
+ /\.left/g, '[treeStyleTab.startProp]'
+ ).replace(
+ /\.right/g, '[treeStyleTab.endProp]'
+
+ // replace such codes:
+ // tab = {left: tab.left, right: tab.right};
+ ).replace(
+ /left\s*:/g, 'start:'
+ ).replace(
+ /right\s*:/g, 'end:'
+ ).replace(
+ /((tab|selected)\s*=\s*\{\s*start:[^\}]+\})/g,
+ '$1; $2[treeStyleTab.startProp] = $2.start; $2[treeStyleTab.endProp] = $2.end;'
+
+ ).replace(
+ '!selected ||',
+ '$& treeStyleTab.scrollToNewTabMode == 1 && '
+ ).replace(
+ /(\}\)?)$/,
+ 'treeStyleTab.notifyBackgroundTab(); $1'
+ )
+ );
+ }
+
+ if (b.tabContainer && '_getDropIndex' in b.tabContainer) {
+ eval('b.tabContainer._getDropIndex = '+
+ b.tabContainer._getDropIndex.toSource().replace(
+ /\.screenX/g, '[this.treeStyleTab.screenPositionProp]'
+ ).replace(
+ /\.width/g, '[this.treeStyleTab.sizeProp]'
+ )
+ );
+ }
+
+ /**
+ * The default implementation fails to scroll to tab if it is expanding.
+ * So we have to inject codes to override its effect.
+ */
+ let (scrollbox = aTabBrowser.treeStyleTab.scrollBox) {
+ let source = scrollbox.ensureElementIsVisible.toSource();
+ if (
+ source.indexOf('treeStyleTab') < 0 && // not updated yet
+ source.indexOf('ensureTabIsVisible') < 0 // not replaced by Tab Mix Plus
+ ) {
+ eval('scrollbox.ensureElementIsVisible = '+
+ source.replace(
+ '{',
+ '{\n' +
+ ' var treeStyleTab = TreeStyleTabService.getTabBrowserFromChild(this).treeStyleTab;\n' +
+ ' if (treeStyleTab && treeStyleTab.shouldCancelEnsureElementIsVisible())\n' +
+ ' return;\n' +
+ ' if (\n' +
+ ' treeStyleTab &&\n' +
+ ' (arguments.length == 1 || arguments[1])\n' +
+ ' )\n' +
+ ' return treeStyleTab.scrollToTab(arguments[0]);'
+ )
+ );
+ }
+ }
+
+ let (popup = document.getElementById('alltabs-popup')) {
+ if (popup && '_updateTabsVisibilityStatus' in popup) {
+ eval('popup._updateTabsVisibilityStatus = '+
+ popup._updateTabsVisibilityStatus.toSource().replace(
+ '{',
+ '{ var treeStyleTab = gBrowser.treeStyleTab;'
+ ).replace(
+ /\.screenX/g, '[treeStyleTab.screenPositionProp]'
+ ).replace(
+ /\.width/g, '[treeStyleTab.sizeProp]'
+ )
+ );
+ }
+ }
+
+ }
+
+};
+
diff --git a/content/treestyletab/windowHelperHacks.js b/content/treestyletab/windowHelperHacks.js
index 2fddc7ca..d1e7ae85 100644
--- a/content/treestyletab/windowHelperHacks.js
+++ b/content/treestyletab/windowHelperHacks.js
@@ -1,1484 +1,1484 @@
-Components.utils.import('resource://gre/modules/XPCOMUtils.jsm');
-XPCOMUtils.defineLazyModuleGetter(this,
- 'Services', 'resource://gre/modules/Services.jsm');
-XPCOMUtils.defineLazyModuleGetter(this,
- 'TreeStyleTabUtils', 'resource://treestyletab-modules/utils.js');
-
-TreeStyleTabWindowHelper.extraProperties = [
- TreeStyleTabService.kID,
- TreeStyleTabService.kCOLLAPSED,
- TreeStyleTabService.kSUBTREE_COLLAPSED,
- TreeStyleTabService.kCHILDREN,
- TreeStyleTabService.kPARENT,
- TreeStyleTabService.kANCESTOR,
- TreeStyleTabService.kINSERT_BEFORE,
- TreeStyleTabService.kINSERT_AFTER
-];
-
-TreeStyleTabWindowHelper.overrideExtensionsPreInit = function TSTWH_overrideExtensionsPreInit() {
- var sv = this.service;
-
- // Highlander
- // https://addons.mozilla.org/firefox/addon/4086
- if ('Highlander' in window &&
- TreeStyleTabUtils.getTreePref('compatibility.Highlander')) {
- eval('Highlander.overrideHandleLinkClick = '+
- Highlander.overrideHandleLinkClick.toSource().replace(
- /(var )?origHandleLinkClick/g,
- 'window.__treestyletab__highlander__origHandleLinkClick'
- )
- );
- }
-
- // PermaTabs
- // https://addons.mozilla.org/firefox/addon/2558
- // PermaTabs Mod
- // https://addons.mozilla.org/firefox/addon/7816
- if ('permaTabs' in window &&
- TreeStyleTabUtils.getTreePref('compatibility.PermaTabs')) {
- if ('__init' in permaTabs) {
- // without delay, Firefox crashes on startup.
- eval('permaTabs.__init = '+
- permaTabs.__init.toSource().replace(
- 'aTab.setAttribute(\\"image\\", ',
- 'window.setTimeout(function(aTab, aImage) { aTab.setAttribute(\\"image\\", aImage); }, 100, aTab, '
- )
- );
- }
- if ('showPermaTab' in permaTabs) {
- eval('permaTabs.showPermaTab = '+
- permaTabs.showPermaTab.toSource().replace(
- /(\}\)?)$/,
- '(function(tab, id) {\n' +
- ' if (this.ssWillRestore) return;\n' +
- ' var TST = TreeStyleTabService;\n' +
- ' if (this.TSTRestoredPermaTabsInfo === void(0)) {\n' +
- ' try {\n' +
- ' eval("this.TSTRestoredPermaTabsInfo = "+(TreeStyleTabUtils.getTreePref("permaTabsInfo") || "null"));\n' +
- ' }\n' +
- ' catch(e) {\n' +
- ' }\n' +
- ' }\n' +
- ' if (!this.TSTRestoredPermaTabsInfo) return;\n' +
-
- ' var info = this.TSTRestoredPermaTabsInfo[id];\n' +
- ' if (!info) return;\n' +
-
- ' for (var i in info)\n' +
- ' {\n' +
- ' TST.SessionStore.setTabValue(tab, i, String(info[i]));\n' +
- ' }\n' +
- ' var count = 0;\n' +
- ' window.setTimeout(function onTimeout() {\n' +
- ' var b = TST.getTabBrowserFromChild(tab);\n' +
- ' if (!b.treeStyleTab) {\n' +
- ' if (++count < 50)\n' +
- ' window.setTimeout(onTimeout, 100);\n' +
- ' return;\n' +
- ' }\n' +
- ' b.treeStyleTab.handleRestoredTab(tab);\n' +
- ' }, 0);\n' +
- '}).call(this, tab, id)\n' +
- '$1'
- )
- );
- }
- if ('savePermaTabs' in permaTabs) {
- eval('permaTabs.savePermaTabs = '+
- permaTabs.savePermaTabs.toSource().replace(
- '{',
- '{\n' +
- '(function() {\n' +
- ' var tabsInfo = {};\n' +
- ' var TST = TreeStyleTabService;\n' +
- ' var allTabs = getBrowser().mTabContainer.childNodes;\n' +
- ' for (let i = 0, maxi = allTabs.length; i < maxi; i++)\n' +
- ' {\n' +
- ' let tab = allTabs[i];\n' +
- ' let index = this.getPermaTabLocalIndex(tab);\n' +
- ' if (index < 0) continue;\n' +
- ' let info = {};\n' +
- ' for (let i = 0, maxi = TST.extraProperties.length; i < maxi; i++)\n' +
- ' {\n' +
- ' let property = TST.extraProperties[i];\n' +
- ' info[property] = TST.getTabValue(tab, property);\n' +
- ' }\n' +
- ' tabsInfo[this.permaTabs[index].id] = info;\n' +
- ' }\n' +
- ' TreeStyleTabUtils.setTreePref("permaTabsInfo", tabsInfo.toSource());\n' +
- '}).call(this);'
- )
- );
- }
- }
-
- // Tab Mix Plus
- if (TreeStyleTabUtils.getTreePref('compatibility.TMP')) {
- document.documentElement.setAttribute('treestyletab-enable-compatibility-tmp', true);
- }
- // Tab Mix Plus, SessionStore API
- if (
- TreeStyleTabUtils.getTreePref('compatibility.TMP') &&
- ('TabmixSessionData' in window || 'SessionData' in window)
- ) {
- let sessionData = window.TabmixSessionData || window.SessionData;
- if ('getTabProperties' in sessionData && 'setTabProperties' in sessionData) {
- let prefix = sv.kTMP_SESSION_DATA_PREFIX;
- let sessionManager = window.TabmixSessionManager || window.SessionManager;
- sessionData.tabTSTProperties = this.extraProperties.map(function(aProperty) {
- return prefix+aProperty;
- });
- eval('sessionData.getTabProperties = '+
- sessionData.getTabProperties.toSource().replace(
- 'return tabProperties;',
- ' for (let i = 0, maxi = this.tabTSTProperties.length; i < maxi; i++)\n' +
- ' {\n' +
- ' let property = this.tabTSTProperties[i];\n' +
- ' tabProperties += "|" + property + "=" + encodeURIComponent(aTab.getAttribute(property));\n' +
- ' }\n' +
- '$&'
- )
- );
- eval('sessionData.setTabProperties = '+
- sessionData.setTabProperties.toSource().replace(
- '{',
- '$&\n' +
- ' var TSTProps = tabProperties.split("|");\n' +
- ' tabProperties = TSTProps.shift();\n' +
- ' for (let i = 0, maxi = TSTProps.length; i < maxi; i++)\n' +
- ' {\n' +
- ' let property = TSTProps[i];\n' +
- ' let index = property.indexOf("=");\n' +
- ' let name = property.substring(0, index);\n' +
- ' let value = decodeURIComponent(property.substring(index+1));\n' +
- ' if (name && value)\n' +
- ' aTab.setAttribute(name, value);\n' +
- ' }'
- )
- );
- eval('sessionManager.loadOneTab = '+
- sessionManager.loadOneTab.toSource().replace(
- /(\}\))?$/,
- ' if (gBrowser.treeStyleTab.useTMPSessionAPI)\n' +
- ' gBrowser.treeStyleTab.handleRestoredTab(aTab);\n' +
- '$1'
- )
- );
- let source = tablib.init.toSource().split('gBrowser.restoreTab = ');
- source[1] = source[1].replace(
- 'return newTab;',
- ' if (this.treeStyleTab.useTMPSessionAPI)\n' +
- ' this.treeStyleTab.handleRestoredTab(newTab);\n' +
- '$&'
- );
- eval('tablib.init = '+source.join('gBrowser.restoreTab = '));
- eval('sessionManager.loadOneWindow = '+
- sessionManager.loadOneWindow.toSource().replace(
- 'gBrowser.tabsToLoad = ',
- ' gBrowser.treeStyleTab.resetAllTabs(true, true);\n' +
- ' TreeStyleTabService.restoringTree = true;\n' +
- '$&'
- ).replace(
- /(\}\))?$/,
- 'TreeStyleTabService.restoringTree = false; $1'
- )
- );
- sv.useTMPSessionAPI = true;
- }
- }
-
- // Session Manager
- // https://addons.mozilla.org/firefox/addon/2324
- // We need to initialize TST before Session Manager restores the last session anyway!
- if ('gSessionManager' in window &&
- TreeStyleTabUtils.getTreePref('compatibility.SessionManager')) {
- if ('onLoad_proxy' in gSessionManager &&
- 'onLoad' in gSessionManager) {
- eval('gSessionManager.onLoad = '+gSessionManager.onLoad.toSource().replace(
- '{',
- '{ TreeStyleTabService.init();'
- ));
- }
- if ('load' in gSessionManager) {
- eval('gSessionManager.load = '+gSessionManager.load.toSource().replace(
- 'var tabcount = ',
- ' gBrowser.treeStyleTab.collapseExpandAllSubtree(false, true);\n' +
- ' let (tabs = gBrowser.treeStyleTab.getTabs(gBrowser).slice(1).reverse()) {\n' +
- ' for (let i = 0, maxi = tabs.length; i < maxi; i++)\n' +
- ' {\n' +
- ' let tab = tabs[i];\n' +
- ' gBrowser.removeTab(tab);\n' +
- ' }\n' +
- ' }\n' +
- ' TreeStyleTabService.restoringTree = true;\n' +
- '$&'
- ));
- }
- }
-
- // FullerScreen
- // https://addons.mozilla.org/firefox/addon/4650
- if ('FS_onFullerScreen' in window &&
- TreeStyleTabUtils.getTreePref('compatibility.FullerScreen')) {
- let (functions = 'CheckIfFullScreen,FS_onFullerScreen,FS_onMouseMove'.split(',')) {
- for (let i = 0, maxi = functions.length; i < maxi; i++)
- {
- let func = functions[i];
- if (!(func in window)) continue;
- eval('window.'+func+' = '+window[func].toSource().replace(
- /FS_data.mTabs.(removeAttribute\("moz-collapsed"\)|setAttribute\("moz-collapsed", "true"\));/g,
- 'if (gBrowser.treeStyleTab.currentTabbarPosition == "top") { $& }'
- ));
- }
- }
- }
-
- // TooManyTabs
- // https://addons.mozilla.org/firefox/addon/9429
- if ('tooManyTabs' in window &&
- TreeStyleTabUtils.getTreePref('compatibility.TooManyTabs')) {
- sv.registerExpandTwistyAreaBlocker('tooManyTabs');
- }
-
- // DragNDrop Toolbars
- // https://addons.mozilla.org/firefox/addon/dragndrop-toolbars/
- if ('globDndtb' in window &&
- globDndtb.setTheStuff &&
- TreeStyleTabUtils.getTreePref('compatibility.DragNDropToolbars')) {
- let reinitTabbar = function() {
- TreeStyleTabService.stopRendering();
- gBrowser.treeStyleTab.syncDestroyTabbar();
- window.setTimeout(function() {
- gBrowser.treeStyleTab.syncReinitTabbar();
- TreeStyleTabService.startRendering();
- }, 100);
- };
- globDndtb.__treestyletab__setOrder = globDndtb.setOrder;
- globDndtb.setOrder = function() {
- reinitTabbar();
- return this.__treestyletab__setOrder.apply(this, arguments);
- };
- globDndtb.__treestyletab__setTheStuff = globDndtb.setTheStuff;
- globDndtb.setTheStuff = function() {
- var result = this.__treestyletab__setTheStuff.apply(this, arguments);
- if (this.dndObserver &&
- this.dndObserver.onDrop &&
- !this.dndObserver.__treestyletab__onDrop) {
- this.dndObserver.__treestyletab__onDrop = this.dndObserver.onDrop;
- this.dndObserver.onDrop = function(aEvent, aDropData, aSession) {
- if (document.getElementById(aDropData.data) == gBrowser.treeStyleTab.tabStrip) {
- reinitTabbar();
- }
- return this.__treestyletab__onDrop.apply(this, arguments);
- };
- }
- return result;
- };
- }
-
- // Optimoz Tweaks
- // http://optimoz.mozdev.org/tweaks/
- // https://addons.mozilla.org/firefox/addon/optimoz-tweaks-ja-version/
- if ('mtSidebarStartup' in window &&
- 'mtSidebarShutdown' in window &&
- 'mtPreventHiding' in window &&
- TreeStyleTabUtils.getTreePref('compatibility.OptimozTweaks')) {
- eval('window.mtSidebarStartup = '+window.mtSidebarStartup.toSource().replace(
- '{',
- '{\n' +
- ' document.getElementById("TabsToolbar")\n' +
- ' .addEventListener("mousemove", mtMouseMoveListener, false);'
- ));
- eval('window.mtSidebarShutdown = '+window.mtSidebarShutdown.toSource().replace(
- '{',
- '{\n' +
- ' document.getElementById("TabsToolbar")\n' +
- ' .removeEventListener("mousemove", mtMouseMoveListener, false);'
- ));
- eval('window.mtPreventHiding = '+window.mtPreventHiding.toSource().replace(
- '{',
- '{\n' +
- ' if (TreeStyleTabService.getTabbarFromEvent(arguments[0]))\n' +
- ' return;'
- ));
- }
-
- /**
- * Hide Caption Titlebar Plus (Smart)
- * https://addons.mozilla.org/firefox/addon/hide-caption-titlebar-plus-sma/
- */
- if ('HideCaption' in window &&
- 'do_alter' in HideCaption) {
- eval('HideCaption.do_alter = '+HideCaption.do_alter.toSource().replace(
- 'if (!theSettings) {',
- ' if (!theSettings ||\n' +
- ' gBrowser.treeStyleTab.isVertical) {'
- ));
- }
-
- // Greasemonkey
- // https://addons.mozilla.org/firefox/addon/748
- if (TreeStyleTabUtils.getTreePref('compatibility.Greasemonkey')) {
- try {
- let hitchModule = Components.utils.import('resource://greasemonkey/util/hitch.js', {});
- let hitch = hitchModule.hitch;
- if (hitch.toSource().indexOf('TreeStyleTabService') < 0) {
- let ns = {};
- Components.utils.import('resource://greasemonkey/third-party/getChromeWinForContentWin.js', ns);
- let getChromeWinForContentWin = ns.getChromeWinForContentWin;
- hitchModule.hitch = function(aObject, aMethod) {
- if (typeof aMethod == 'function' &&
- aMethod.toSource().indexOf('function openInTab') > -1) {
- let originalOpenInTab = aMethod;
- /**
- * This function must be replaced on scripts in "chrome:" URL, like this.
- * Otherwise the original openInTab() will raise violation error.
- * Don't move this hack into JS code modules with "resource:" URL.
- */
- aMethod = function openInTab(aSafeContentWindow, aURL, aLoadInBackgtound) {
- let chrome = getChromeWinForContentWin(aSafeContentWindow);
- if (chrome && chrome.TreeStyleTabService)
- chrome.TreeStyleTabService.readyToOpenChildTabNow(aSafeContentWindow);
- return originalOpenInTab.apply(this, arguments);
- };
- }
- return hitch.apply(this, arguments);
- };
- Components.utils.import('resource://greasemonkey/util.js', ns);
- if (ns.GM_util)
- ns.GM_util.hitch = hitchModule.hitch;
- }
- }
- catch(e) {
- dump('Tree Style Tab: failed to patch to Greasemonkey.\n');
- dump(e+'\n');
- }
- }
-};
-
-TreeStyleTabWindowHelper.overrideExtensionsBeforeBrowserInit = function TSTWH_overrideExtensionsBeforeBrowserInit() {
- var sv = this.service;
-
- // Tab Mix Plus
- if (TreeStyleTabUtils.getTreePref('compatibility.TMP') &&
- 'TMP_LastTab' in window) {
- TMP_LastTab.TabBar = gBrowser.mTabContainer;
- }
- if (TreeStyleTabUtils.getTreePref('compatibility.TMP') &&
- 'isTabVisible' in gBrowser.mTabContainer &&
- 'ensureTabIsVisible' in gBrowser.mTabContainer) {
- let replaceHorizontalProps = function replaceHorizontalProps(aString)
- {
- return aString.replace(
- /boxObject\.x/g,
- 'boxObject[posProp]'
- ).replace(
- /boxObject\.screenX/g,
- 'boxObject[screenPosProp]'
- ).replace(
- /boxObject\.width/g,
- 'boxObject[sizeProp]'
- ).replace(
- '{',
- '{\n' +
- ' var posProp = gBrowser.treeStyleTab.isVertical ? "y" : "x" ;\n' +
- ' var screenPosProp = gBrowser.treeStyleTab.isVertical ? "screenY" : "screenX" ;\n' +
- ' var sizeProp = gBrowser.treeStyleTab.isVertical ? "height" : "width" ;'
- )
- }
- eval('gBrowser.mTabContainer.ensureTabIsVisible = '+
- replaceHorizontalProps(gBrowser.mTabContainer.ensureTabIsVisible.toSource().replace(
- 'boxObject.width < 250',
- '$& || gBrowser.treeStyleTab.isVertical'
- ))
- );
- eval('gBrowser.mTabContainer.isTabVisible = '+
- replaceHorizontalProps(gBrowser.mTabContainer.isTabVisible.toSource())
- );
- }
-
- // Tabberwocky
- // https://addons.mozilla.org/firefox/addon/14439
- if ('tabberwocky' in window &&
- TreeStyleTabUtils.getTreePref('compatibility.Tabberwocky')) {
- let listener = {
- handleEvent : function(aEvent)
- {
- switch (aEvent.type)
- {
- case 'TreeStyleTabTabbarPositionChanged':
- var b = aEvent.originalTarget;
- if (b.treeStyleTab.isVertical)
- TreeStyleTabUtils.prefs.setPref('tabberwocky.multirow', false);
- break;
-
- case 'unload':
- document.removeEventListener('TreeStyleTabTabbarPositionChanged', this, false);
- document.removeEventListener('unload', this, false);
- break;
- }
- }
- };
- document.addEventListener('TreeStyleTabTabbarPositionChanged', listener, false);
- document.addEventListener('unload', listener, false);
-
- if ('openSelectedLinks' in tabberwocky) {
- eval('tabberwocky.openSelectedLinks = '+
- tabberwocky.openSelectedLinks.toSource().replace(
- 'links.forEach(',
- ' TreeStyleTabService.readyToOpenChildTab(aFrame, true)\n' +
- '$&'
- ).replace(
- /(\}\)?)$/,
- ' TreeStyleTabService.stopToOpenChildTab(aFrame)\n' +
- '$1'
- )
- );
- }
- }
-};
-
-TreeStyleTabWindowHelper.overrideExtensionsAfterBrowserInit = function TSTWH_overrideExtensionsAfterBrowserInit() {
- var sv = this.service;
-
- // Selection Links
- // https://addons.mozilla.org/firefox/addon/8644
- if ('selectionlinks' in window &&
- 'parseSelection' in selectionlinks &&
- TreeStyleTabUtils.getTreePref('compatibility.SelectionLinks')) {
- eval('selectionlinks.parseSelection = '+
- selectionlinks.parseSelection.toSource().replace(
- /((?:[^\s:;]+.selectedTab\s*=\s*)?([^\s:;]+).addTab\()/g,
- ' if ($2.treeStyleTab)\n' +
- ' $2.treeStyleTab.readyToOpenChildTab(focusedWindow);\n' +
- '$1'
- )
- );
- }
-
-
- // Tab Mix Plus
- if (
- TreeStyleTabUtils.getTreePref('compatibility.TMP') &&
- 'TabmixTabbar' in window
- ) {
- let DNDObserver = 'TMP_tabDNDObserver' in window ? TMP_tabDNDObserver : TabDNDObserver ;
- this.updateTabDNDObserver(DNDObserver);
- eval('DNDObserver.clearDragmark = '+
- DNDObserver.clearDragmark.toSource().replace(
- /(\})(\))?$/,
- 'gBrowser.treeStyleTab.tabbarDNDObserver.clearDropPosition(); $1$2'
- )
- );
- eval('DNDObserver.onDragStart = '+
- DNDObserver.onDragStart.toSource().replace(
- 'event.target.localName != "tab"',
- ' gBrowser.treeStyleTab.tabbarDNDObserver.canDragTabbar(event) ||\n' +
- ' $&'
- )
- );
-
- eval('window.TMP_howToOpen = '+
- window.TMP_howToOpen.toSource().replace(
- /(window.openNewTabWith\()/g,
- 'TreeStyleTabService.readyToOpenChildTab(event.target.ownerDocument.defaultView); $1'
- )
- );
-
- if ('TabmixContext' in window &&
- typeof TabmixContext.openMultipleLinks == 'function') {
- eval('TabmixContext.openMultipleLinks = '+
- TabmixContext.openMultipleLinks.toSource().replace(
- /(TMP_loadTabs\([^\)]+\);)/g,
- 'TreeStyleTabService.readyToOpenChildTab(gBrowser, true); $1 TreeStyleTabService.stopToOpenChildTab(gBrowser);'
- )
- );
- }
-
-
- let listener = {
- handleEvent : function(aEvent)
- {
- switch (aEvent.type)
- {
- case sv.kEVENT_TYPE_TAB_COLLAPSED_STATE_CHANGED:
- TabmixTabbar.updateScrollStatus();
- break;
-
- case sv.kEVENT_TYPE_FOCUS_NEXT_TAB:
- let mode = TreeStyleTabUtils.prefs.getPref('extensions.tabmix.focusTab');
- if (mode != 2 && mode != 5)
- aEvent.preventDefault();
- break;
-
- case 'unload':
- document.removeEventListener(sv.kEVENT_TYPE_TAB_COLLAPSED_STATE_CHANGED, this, false);
- document.removeEventListener(sv.kEVENT_TYPE_FOCUS_NEXT_TAB, this, false);
- document.removeEventListener('unload', this, false);
- break;
- }
- }
- };
- document.addEventListener(sv.kEVENT_TYPE_TAB_COLLAPSED_STATE_CHANGED, listener, false);
- document.addEventListener(sv.kEVENT_TYPE_FOCUS_NEXT_TAB, listener, false);
- document.addEventListener('unload', listener, false);
-
- gBrowser.treeStyleTab.internallyTabMovingCount++; // until "TMmoveTabTo" method is overwritten
- }
-
-
- // Super DragAndGo
- // https://addons.mozilla.org/firefox/addon/137
- if ('superDrag' in window &&
- TreeStyleTabUtils.getTreePref('compatibility.SuperDragAndGo')) {
- eval('superDrag.onDrop = '+
- superDrag.onDrop.toSource().replace(
- /(var newTab = getBrowser\(\).addTab\([^\)]+\);)/g,
- ' if (aDragSession.sourceNode &&\n' +
- ' aDragSession.sourceNode.ownerDocument.defaultView.top == getBrowser().contentWindow)\n' +
- ' TreeStyleTabService.readyToOpenChildTab(getBrowser());\n' +
- ' $1'
- )
- );
- }
-
- // Drag de Go
- // https://addons.mozilla.org/firefox/addon/2918
- if ('ddg_ges' in window &&
- TreeStyleTabUtils.getTreePref('compatibility.DragDeGo')) {
- eval('ddg_ges.Open = '+
- ddg_ges.Open.toSource().replace(
- 'if (mode[1] == "h" || mode[1] == "f") {',
- '$&\n' +
- ' if ("sourceNode" in aData) // only for dragging from the content tarea.\n' +
- ' TreeStyleTabService.readyToOpenChildTab(getBrowser());'
- )
- );
- eval('ddg_ges.Search = '+
- ddg_ges.Search.toSource().replace(
- 'if (mode[1] == "h" || mode[1] == "f") {',
- '$&\n' +
- ' TreeStyleTabService.readyToOpenChildTab(getBrowser());'
- )
- );
- }
-
- // DragIt
- // https://addons.mozilla.org/firefox/addon/dragit-formerly-drag-de-go/
- if ('DragIt' in window &&
- DragIt.tab &&
- DragIt.tab.open &&
- TreeStyleTabUtils.getTreePref('compatibility.DragIt')) {
- eval('DragIt.tab.open = '+
- DragIt.tab.open.toSource().replace(
- 'try {',
- 'try { TreeStyleTabService.readyToOpenChildTabNow(gBrowser);'
- )
- );
- }
-
- // Colorful Tabs
- // https://addons.mozilla.org/firefox/addon/1368
- if ('colorfulTabs' in window &&
- TreeStyleTabUtils.getTreePref('compatibility.ColorfulTabs')) {
- let listener = {
- handleEvent : function(aEvent)
- {
- switch (aEvent.type)
- {
- case 'TabOpen':
- case 'TreeStyleTabAttached':
- case 'TreeStyleTabParted':
- var child = aEvent.originalTarget;
- var parent = aEvent.parentTab;
- if (child && parent) {
- let color = TreeStyleTabService.SessionStore.getTabValue(parent, 'tabClr');
- if (/^\d+,\d+,\d+$/.test(color))
- color = 'rgb('+color+')';
- window.setTimeout(function() {
- colorfulTabs.setColor(child, color);
- }, 0);
- }
- else if (child) {
- TreeStyleTabService.SessionStore.setTabValue(child, 'tabClr', '');
- colorfulTabs.calcTabClr({
- target : child,
- originalTarget : child,
- });
- }
- break;
-
- case 'unload':
- document.removeEventListener('TabOpen', this, false);
- document.removeEventListener('TreeStyleTabAttached', this, false);
- document.removeEventListener('TreeStyleTabParted', this, false);
- document.removeEventListener('unload', this, false);
- break;
- }
- }
- };
- eval('colorfulTabs.show_ctStack = '+
- colorfulTabs.show_ctStack.toSource().replace(
- '.setProperty("display", "-moz-stack", "important")',
- '.display = ""'
- )
- );
- document.addEventListener('TabOpen', listener, false);
- document.addEventListener('TreeStyleTabAttached', listener, false);
- document.addEventListener('TreeStyleTabParted', listener, false);
- document.addEventListener('unload', listener, false);
- }
-
- // FLST (Focus Last Selected Tab)
- // https://addons.mozilla.org/firefox/addon/32
- if ('flst' in window &&
- TreeStyleTabUtils.getTreePref('compatibility.FLST')) {
- TreeStyleTabService.registerTabFocusAllowance(function(aTabBrowser) {
- return !TreeStyleTabUtils.prefs.getPref('extensions.flst.enabled');
- });
- }
-
- // Focus Last Selected Tab 0.9.5.x
- // http://www.gozer.org/mozilla/extensions/
- if (TreeStyleTabUtils.getTreePref('compatibility.FocusLastSelectedTab')) {
- sv.extensions.isAvailable('focuslastselectedtab@gozer.org', { ok : function() {
- TreeStyleTabService.registerTabFocusAllowance(function(aTabBrowser) {
- return !aTabBrowser.selectedTab.hasAttribute('lastselected');
- });
- }});
- }
-
- // LastTab
- // https://addons.mozilla.org/firefox/addon/112
- if ('LastTab' in window &&
- TreeStyleTabUtils.getTreePref('compatibility.LastTab')) {
- TreeStyleTabService.registerTabFocusAllowance(function(aTabBrowser) {
- return !TreeStyleTabUtils.prefs.getPref('extensions.lasttab.focusLastTabOnClose');
- });
- }
-
- // FireGestures
- // https://addons.mozilla.org/firefox/addon/6366
- if ('FireGestures' in window &&
- TreeStyleTabUtils.getTreePref('compatibility.FireGestures')) {
- eval('FireGestures.onExtraGesture = '+
- FireGestures.onExtraGesture.toSource().replace(
- 'case "keypress-stop":',
- '$&\n' +
- ' TreeStyleTabService.readyToOpenChildTab(gBrowser, true);'
- ).replace(
- 'break;case "gesture-timeout":',
- ' TreeStyleTabService.stopToOpenChildTab(gBrowser);\n' +
- '$&'
- )
- );
- eval('FireGestures._performAction = '+
- FireGestures._performAction.toSource().replace(
- 'gBrowser.loadOneTab(',
- ' TreeStyleTabService.readyToOpenChildTab(gBrowser);\n' +
- '$&'
- )
- );
- eval('FireGestures.openURLsInSelection = '+
- FireGestures.openURLsInSelection.toSource().replace(
- 'var tab =',
- ' if (!TreeStyleTabService.checkToOpenChildTab(gBrowser))\n' +
- ' TreeStyleTabService.readyToOpenChildTab(gBrowser, true);\n' +
- '$&'
- ).replace(
- 'if (!flag)',
- ' if (TreeStyleTabService.checkToOpenChildTab(gBrowser))\n' +
- ' TreeStyleTabService.stopToOpenChildTab(gBrowser);\n' +
- '$&'
- )
- );
- eval('FireGestures.handleEvent = '+
- FireGestures.handleEvent.toSource().replace(
- 'gBrowser.loadOneTab(',
- ' TreeStyleTabService.readyToOpenChildTab(gBrowser);\n' +
- '$&'
- )
- );
- }
-
- // Mouse Gestures Redox
- // http://www.mousegestures.org/
- if ('mgBuiltInFunctions' in window &&
- 'mgLinkInTab' in mgBuiltInFunctions &&
- TreeStyleTabUtils.getTreePref('compatibility.MouseGesturesRedox')) {
- eval('mgBuiltInFunctions.mgLinkInTab = '+
- mgBuiltInFunctions.mgLinkInTab.toSource().replace(
- 'var tab',
- 'TreeStyleTabService.readyToOpenChildTab(gBrowser); $&'
- )
- );
- }
-
- // SBM Counter
- // http://miniturbo.org/products/sbmcounter/
- if ('SBMCounter' in window &&
- TreeStyleTabUtils.getTreePref('compatibility.SBMCounter')) {
- eval('SBMCounter.action = '+
- SBMCounter.action.toSource().replace(
- 'gBrowser.selectedTab = gBrowser.addTab',
- 'TreeStyleTabService.readyToOpenChildTab(gBrowser); $&'
- )
- );
- }
-
- // Aging Tabs
- // https://addons.mozilla.org/firefox/addon/3542
- if ('agingTabs' in window &&
- TreeStyleTabUtils.getTreePref('compatibility.AgingTabs')) {
- eval('agingTabs.setColor = '+
- agingTabs.setColor.toSource().replace(
- '{',
- '{ important = true;'
- )
- );
- }
-
- // Snap Links
- // https://addons.mozilla.org/firefox/addon/4336
- // Snap Links Plus
- // http://snaplinks.mozdev.org/
- if (TreeStyleTabUtils.getTreePref('compatibility.SnapLinks')) {
- if ('executeAction' in window &&
- 'openTabs' in window) {
- eval('window.openTabs = '+
- window.openTabs.toSource().replace(
- /((sContent|gBrowser|getBrowser\(\))\.addTab)/,
- 'TreeStyleTabService.readyToOpenChildTab($2); $1'
- )
- );
- }
- if ('SnapLinks' in window &&
- 'OpenTabs' in SnapLinks) {
- eval('SnapLinks.OpenTabs = '+
- SnapLinks.OpenTabs.toSource().replace(
- /((sContent|gBrowser|getBrowser\(\))\.addTab)/,
- 'TreeStyleTabService.readyToOpenChildTab($2); $1'
- )
- );
- }
- }
-
- // Mouseless Browsing
- // https://addons.mozilla.org/firefox/addon/879
- if ('mouselessbrowsing' in window &&
- 'EventHandler' in mouselessbrowsing &&
- TreeStyleTabUtils.getTreePref('compatibility.MouselessBrowsing')) {
- if ('execute' in mouselessbrowsing.EventHandler) {
- eval('mouselessbrowsing.EventHandler.execute = '+
- mouselessbrowsing.EventHandler.execute.toSource().replace(
- '{',
- '{ var Prefs = mlb_common.Prefs;'+
- ' var Utils = mlb_common.Utils;'+
- ' var MlbUtils = mouselessbrowsing.MlbUtils;'
- ).replace(
- /((?:var [^=]+ = )?Utils.openUrlInNewTab\()/g,
- 'TreeStyleTabService.readyToOpenChildTab(); $1'
- )
- );
- }
- if ('openLinkInOtherLocationViaPostfixKey' in mouselessbrowsing.EventHandler) {
- eval('mouselessbrowsing.EventHandler.openLinkInOtherLocationViaPostfixKey = '+
- mouselessbrowsing.EventHandler.openLinkInOtherLocationViaPostfixKey.toSource().replace(
- '{',
- '{ var Prefs = mlb_common.Prefs;'+
- ' var Utils = mlb_common.Utils;'+
- ' var MlbUtils = mouselessbrowsing.MlbUtils;'+
- ' var MlbCommon = mouselessbrowsing.MlbCommon;'+
- ' var ShortcutManager = mlb_common.ShortcutManager;'
- ).replace(
- 'Utils.openUrlInNewTab(',
- 'TreeStyleTabService.readyToOpenChildTab(); $&'
- )
- );
- }
- }
-
- // Linky
- // https://addons.mozilla.org/firefox/addon/425
- if ('LinkyContext' in window &&
- 'prototype' in LinkyContext &&
- TreeStyleTabUtils.getTreePref('compatibility.Linky')) {
- let (methods = 'openLink,openLinks,generateDocument'.split(',')) {
- for (let i = 0, maxi = methods.length; i < maxi; i++)
- {
- let method = methods[i];
- if (!(method in LinkyContext.prototype)) continue;
- eval('LinkyContext.prototype.'+method+' = '+
- LinkyContext.prototype[method].toSource().replace(
- '{',
- '{ TreeStyleTabService.readyToOpenChildTabNow(null, true);'
- )
- );
- }
- }
- }
-
- // QuickDrag
- // https://addons.mozilla.org/firefox/addon/6912
- if ('QuickDrag' in window &&
- '_loadTab' in QuickDrag &&
- TreeStyleTabUtils.getTreePref('compatibility.QuickDrag')) {
- eval('QuickDrag._loadTab = '+
- QuickDrag._loadTab.toSource().replace(
- /(gBrowser.loadOneTab\()/g,
- 'TreeStyleTabService.readyToOpenChildTab(), $1'
- )
- );
- }
-
- // Autohide
- // http://www.krickelkrackel.de/autohide/
- if ('autoHIDE' in window &&
- TreeStyleTabUtils.getTreePref('compatibility.Autohide')) {
- let autoHideEventListener = {
- handleEvent : function(aEvent)
- {
- switch (aEvent.type)
- {
- case 'TreeStyleTabAutoHideStateChanging':
- if (!window.fullScreen) return;
- if (!aEvent.shown) {
- if (
- autoHIDE.statBar &&
- gBrowser.treeStyleTab.currentTabbarPosition == 'bottom' &&
- !TreeStyleTabUtils.prefs.getPref('extensions.autohide.bars.statBar.always') &&
- TreeStyleTabUtils.prefs.getPref('extensions.autohide.bars.statBar')
- ) {
- autoHIDE.statBar.setAttribute('ahHIDE', true);
- }
- }
- else {
- TreeStyleTabService.getTabStrip(gBrowser).removeAttribute('ahHIDE');
- if (
- autoHIDE.statBar &&
- aTabBrowser.treeStyleTab.currentTabbarPosition == 'bottom' &&
- !TreeStyleTabUtils.prefs.getPref('extensions.autohide.bars.statBar.always') &&
- TreeStyleTabUtils.prefs.getPref('extensions.autohide.bars.statBar')
- ) {
- autoHIDE.statBar.removeAttribute('ahHIDE');
- }
- }
- break;
-
- case 'fullscreen':
- var treeStyleTab = gBrowser.treeStyleTab;
- if (gBrowser.treeStyleTab.currentTabbarPosition != 'top') {
- if (window.fullScreen)
- treeStyleTab.autoHide.endForFullScreen();
- else
- treeStyleTab.autoHide.startForFullScreen();
- }
- break;
-
- case 'unload':
- document.removeEventListener('TreeStyleTabAutoHideStateChanging', this, false);
- document.removeEventListener('unload', this, false);
- document.removeEventListener('fullscreen', this, false);
- break;
- }
- }
- };
- document.addEventListener('TreeStyleTabAutoHideStateChanging', autoHideEventListener, false);
- document.addEventListener('fullscreen', autoHideEventListener, false);
- document.addEventListener('unload', autoHideEventListener, false);
-
- if ('MoveContent' in autoHIDE) {
- eval('autoHIDE.MoveContent = '+autoHIDE.MoveContent.toSource().replace(
- /(;)([^;]*\.setPosition\(0, -\s*ah\.delta\);)/,
- '$1\n' +
- ' if (autoHIDE.winUtil)\n' +
- ' autoHIDE.winUtil.setRedraw(false, false);\n' +
- ' $2\n' +
- ' gBrowser.treeStyleTab.autoHide.extraYOffset = ah.delta;\n' +
- ' window.setTimeout(function() {\n' +
- ' gBrowser.treeStyleTab.autoHide.redrawContentArea();\n' +
- ' if (autoHIDE.winUtil)\n' +
- ' autoHIDE.winUtil.setRedraw(true, false);\n' +
- ' }, 0);'
- ).replace(
- /(;)([^;]*\.setPosition\(0, 0\);)/,
- '$1\n' +
- ' if (autoHIDE.winUtil)\n' +
- ' autoHIDE.winUtil.setRedraw(false, false);\n' +
- ' $2\n' +
- ' gBrowser.treeStyleTab.autoHide.extraYOffset = 0;\n' +
- ' window.setTimeout(function() {\n' +
- ' gBrowser.treeStyleTab.autoHide.redrawContentArea();\n' +
- ' if (autoHIDE.winUtil)\n' +
- ' autoHIDE.winUtil.setRedraw(true, false);\n' +
- ' }, 0);'
- ));
- }
- }
-
-
- // Google Toolbar Sidewiki
- if ('sidewikiWindowHandler' in window &&
- window.sidewikiWindowHandler &&
- sidewikiWindowHandler.barsContainer_ &&
- sidewikiWindowHandler.barsContainer_.geometry_ &&
- sidewikiWindowHandler.barsContainer_.geometry_.__proto__.getWindowSizeForDrawers &&
- TreeStyleTabUtils.getTreePref('compatibility.GoogleToolbar.Sidewiki')) {
- let func = sidewikiWindowHandler.barsContainer_.geometry_.__proto__.getWindowSizeForDrawers.toSource();
- if (func.indexOf('treeStyleTab') < 0) {
- eval('sidewikiWindowHandler.barsContainer_.geometry_.__proto__.getWindowSizeForDrawers = '+func.replace(
- 'return {',
- ' if ("treeStyleTab" in this.topLevelDocument_.getElementById("content")) {\n' +
- ' let b = this.topLevelDocument_.getElementById("content");\n' +
- ' let box = b.mPanelContainer.boxObject;\n' +
- ' return {\n' +
- ' height : box.height,\n' +
- ' width : box.width,\n' +
- ' top : box.y,\n' +
- ' left : box.x,\n' +
- ' right : this.topLevelWindow_.innerWidth - box.x - box.width,\n' +
- ' tabBoxHeight : 0\n' +
- ' };\n' +
- ' }\n' +
- '$&'
- ));
- }
- }
-
-
- // Smoothly Close Tabs
- // https://addons.mozilla.org/firefox/addon/71410
- if ('SMOOTHLYCLOSETABS' in window &&
- TreeStyleTabUtils.getTreePref('compatibility.SmoothlyCloseTabs')) {
- let replaceScrollProps = function(aString) {
- return aString.replace(
- /\.scrollWidth/g,
- '[scrollProp]'
- ).replace(
- /"width"/g,
- 'sizeProp'
- ).replace(
- /\.maxWidth/g,
- '[maxSizeProp]'
- ).replace(
- '{',
- '{\n' +
- ' var scrollProp = gBrowser.treeStyleTab.isVertical ? "scrollHeight" : "scrollWidth" ;\n' +
- ' var sizeProp = gBrowser.treeStyleTab.isVertical ? "height" : "width" ;\n' +
- ' var maxSizeProp = gBrowser.treeStyleTab.isVertical ? "maxHeight" : "maxWidth" ;'
- )
- }
- eval('SMOOTHLYCLOSETABS.shrinkTab = '+
- replaceScrollProps(SMOOTHLYCLOSETABS.shrinkTab.toSource())
- );
- eval('SMOOTHLYCLOSETABS.shrinkTabIcon = '+
- replaceScrollProps(SMOOTHLYCLOSETABS.shrinkTabIcon.toSource())
- );
- }
-
- // Super Tab Mode
- // https://addons.mozilla.org/firefox/addon/13288
- if ('stmM' in window &&
- TreeStyleTabUtils.getTreePref('compatibility.STM')) {
- var observer = {
- domain : 'extensions.stm.',
- observe : function(aSubject, aTopic, aData)
- {
- switch (aData)
- {
- case 'extensions.stm.tabBarMultiRows':
- case 'extensions.stm.tabBarPosition':
- if (
- TreeStyleTabUtils.prefs.getPref('extensions.stm.tabBarMultiRows') &&
- TreeStyleTabUtils.prefs.getPref('extensions.stm.tabBarPosition') == 0
- ) {
- TreeStyleTabUtils.prefs.setPref('extensions.stm.tabBarMultiRows.override', false);
- }
- return;
-
- case 'extensions.stm.newTabBtnPos':
- if (TreeStyleTabUtils.prefs.getPref(aData) == 0)
- document.documentElement.removeAttribute(TreeStyleTabService.kHIDE_NEWTAB);
- else
- document.documentElement.setAttribute(TreeStyleTabService.kHIDE_NEWTAB, true);
- return;
- }
- }
- };
- observer.observe(null, null, 'extensions.stm.tabBarMultiRows');
- observer.observe(null, null, 'extensions.stm.newTabBtnPos');
- TreeStyleTabUtils.prefs.addPrefListener(observer);
- document.addEventListener('unload', function onUnload() {
- document.removeEventListener('unload', onUnload, false);
- TreeStyleTabUtils.prefs.removePrefListener(observer);
- }, false);
-
- let warnPref = 'extensions.treestyletab.compatibility.STM.warnForNewTabPosition';
- if (
- TreeStyleTabUtils.prefs.getPref(warnPref) &&
- TreeStyleTabUtils.prefs.getPref('extensions.stm.newTabPosition') != 0
- ) {
- let checked = { value : false };
- if (Services.prompt.confirmEx(
- null,
- TreeStyleTabUtils.treeBundle.getString('compatibility_STM_warning_title'),
- TreeStyleTabUtils.treeBundle.getString('compatibility_STM_warning_text'),
- (Services.prompt.BUTTON_TITLE_IS_STRING * Services.prompt.BUTTON_POS_0) +
- (Services.prompt.BUTTON_TITLE_IS_STRING * Services.prompt.BUTTON_POS_1),
- TreeStyleTabUtils.treeBundle.getString('compatibility_STM_warning_use_TST'),
- TreeStyleTabUtils.treeBundle.getString('compatibility_STM_warning_use_STM'),
- null,
- TreeStyleTabUtils.treeBundle.getString('compatibility_STM_warning_never'),
- checked
- ) == 0) {
- TreeStyleTabUtils.prefs.setPref('extensions.stm.newTabPosition', 0);
- }
- if (checked.value)
- TreeStyleTabUtils.prefs.setPref(warnPref, false);
- }
-
- sv.registerTabFocusAllowance(function(aTabBrowser) {
- return TreeStyleTabUtils.prefs.getPref('extensions.stm.focusAfterCloseTab') == 0;
- });
- }
-
- // Tab Utilities
- // https://addons.mozilla.org/firefox/addon/59961
- if ('tabutils' in window &&
- TreeStyleTabUtils.getTreePref('compatibility.TabUtilities')) {
- TreeStyleTabService.registerTabFocusAllowance(function(aTabBrowser) {
- return TreeStyleTabUtils.prefs.getPref('extensions.tabutils.selectOnClose') == 0;
- });
- }
-
- // Remove New Tab Button
- // https://addons.mozilla.org/firefox/addon/10535
- if (TreeStyleTabUtils.getTreePref('compatibility.RemoveNewTabButton')) {
- sv.extensions.isAvailable('remove-new-tab-button@forerunnerdesigns.com', { ok : function() {
- document.documentElement.setAttribute(TreeStyleTabService.kHIDE_NEWTAB, true);
- }});
- }
-
- // IE Tab Plus
- // https://addons.mozilla.org/firefox/addon/10909/
- if ('IeTab' in window &&
- IeTab.prototype &&
- TreeStyleTabUtils.getTreePref('compatibility.IETabPlus')) {
- if (IeTab.prototype.switchTabEngine)
- eval('IeTab.prototype.switchTabEngine = '+
- IeTab.prototype.switchTabEngine.toSource().replace(
- 'var newTab = ',
- 'TreeStyleTabService.readyToOpenChildTab(); $&'
- )
- );
-
- if (IeTab.prototype.addIeTab)
- eval('IeTab.prototype.addIeTab = '+
- IeTab.prototype.addIeTab.toSource().replace(
- 'var newTab = ',
- 'TreeStyleTabService.readyToOpenChildTab(); $&'
- )
- );
- }
-
- // Locationbar2
- // https://addons.mozilla.org/firefox/addon/locationbar²/
- if ('lb2_alternateStyles' in window &&
- TreeStyleTabUtils.getTreePref('compatibility.Locationbar2')) {
- let listening = false;
- let listener = function(aEvent) {
- switch (aEvent.type)
- {
- case 'unload':
- document.removeEventListener('unload', listener, false);
- document.removeEventListener('beforecustomization', listener, true);
- document.removeEventListener('aftercustomization', listener, false);
- case 'beforecustomization':
- if (gURLBar && listening)
- gURLBar.removeEventListener('click', listener, true);
- listening = false;
- return;
-
- case 'aftercustomization':
- if (gURLBar && !listening) {
- gURLBar.addEventListener('click', listener, true);
- listening = true;
- }
- return;
-
- case 'click':
- if (sv.evaluateXPath(
- 'ancestor-or-self::*['
- +'contains(concat(" ", normalize-space(@class), " "), " textbox-presentation-segment ")'
- +']',
- aEvent.originalTarget,
- Ci.nsIDOMXPathResult.BOOLEAN_TYPE
- ).booleanValue)
- sv.readyToOpenChildTabNow(gBrowser.selectedTab);
- return;
- }
- };
- document.addEventListener('unload', listener, false);
- document.addEventListener('beforecustomization', listener, true);
- document.addEventListener('aftercustomization', listener, false);
- if (gURLBar && !listening) {
- gURLBar.addEventListener('click', listener, true);
- listening = true;
- }
- }
-
- // InstaClick
- // https://addons.mozilla.org/firefox/addon/instaclick/
- if ('instaclick' in window &&
- 'contentAreaClick2' in window.instaclick &&
- TreeStyleTabUtils.getTreePref('compatibility.InstaClick')) {
- eval('instaclick.contentAreaClick2 = '+
- instaclick.contentAreaClick2.toSource().replace(
- 'gBrowser.loadOneTab(',
- 'TreeStyleTabService.readyToOpenChildTab(); $&'
- )
- );
- }
-
- // Duplicate This Tab
- // https://addons.mozilla.org/firefox/addon/duplicate-this-tab/
- if ('duplicatethistab' in window &&
- 'openLinkWithHistory' in window.duplicatethistab &&
- TreeStyleTabUtils.getTreePref('compatibility.DuplicateThisTab')) {
- eval('duplicatethistab.openLinkWithHistory = '+
- duplicatethistab.openLinkWithHistory.toSource().replace(
- 'var newTab = ',
- 'TreeStyleTabService.readyToOpenChildTab(); $&'
- )
- );
- }
-
- // Context Search
- // http://www.cusser.net/extensions/contextsearch/
- if ('contextsearch' in window &&
- 'search' in window.contextsearch &&
- TreeStyleTabUtils.getTreePref('compatibility.ContextSearch')) {
- eval('contextsearch.search = '+
- contextsearch.search.toSource().replace(
- 'var newTab = ',
- 'TreeStyleTabService.readyToOpenChildTab(); $&'
- )
- );
- }
-
- // Tile Tabs
- // https://addons.mozilla.org/firefox/addon/tile-tabs/
- if ('tileTabs' in window &&
- TreeStyleTabUtils.getTreePref('compatibility.TileTabs')) {
- if ('allocateTab' in window.tileTabs)
- eval('tileTabs.allocateTab = '+
- tileTabs.allocateTab.toSource().replace(
- /(tab = gBrowser.addTab)/g,
- 'TreeStyleTabService.readyToOpenNextSiblingTabNow(); $1'
- )
- );
- if ('doClickBrowser' in window.tileTabs)
- eval('tileTabs.doClickBrowser = '+
- tileTabs.doClickBrowser.toSource().replace(
- /(newTab = gBrowser.loadOneTab)/g,
- 'TreeStyleTabService.readyToOpenNextSiblingTabNow(); $1'
- )
- );
- if ('doDropBrowserTile' in window.tileTabs)
- eval('tileTabs.doDropBrowserTile = '+
- tileTabs.doDropBrowserTile.toSource().replace(
- /(tab = gBrowser.loadOneTab)/g,
- 'TreeStyleTabService.readyToOpenNextSiblingTabNow(), $1'
- )
- );
- if ('menuActions' in window.tileTabs)
- eval('tileTabs.menuActions = '+
- tileTabs.menuActions.toSource().replace(
- /(tab = gBrowser.loadOneTab)/g,
- 'TreeStyleTabService.readyToOpenNextSiblingTabNow(), $1'
- )
- );
- if ('applyLayoutString' in window.tileTabs)
- eval('tileTabs.applyLayoutString = '+
- tileTabs.applyLayoutString.toSource().replace(
- /(tab = gBrowser.loadOneTab)/g,
- 'TreeStyleTabService.readyToOpenNextSiblingTabNow(), $1'
- )
- );
- }
-
- window.setTimeout(function(aSelf) {
- aSelf.overrideExtensionsDelayed();
- }, 0, this);
-};
-
-
-TreeStyleTabWindowHelper.overrideExtensionsDelayed = function TSTWH_overrideExtensionsDelayed() {
- var sv = this.service;
-
- // Tab Mix Plus
- if (TreeStyleTabUtils.getTreePref('compatibility.TMP') &&
- 'TabmixTabbar' in window) {
- // correct broken appearance of the first tab
- var t = gBrowser.treeStyleTab.getFirstTab(gBrowser);
- gBrowser.treeStyleTab.initTabAttributes(t);
- gBrowser.treeStyleTab.initTabContentsOrder(t);
-
- eval('gBrowser.openInverseLink = '+
- gBrowser.openInverseLink.toSource().replace(
- /(var newTab)/,
- 'TreeStyleTabService.readyToOpenChildTab(aTab); $1'
- )
- );
-
- eval('gBrowser.TMP_openTabNext = '+
- gBrowser.TMP_openTabNext.toSource().replace(
- 'this.mCurrentTab._tPos + this.tabContainer.nextTab',
- ' (function() {\n' +
- ' var tabs = this.treeStyleTab.getDescendantTabs(this.mCurrentTab);\n' +
- ' if (tabs.length) {\n' +
- ' var index = TreeStyleTabUtils.prefs.getPref("extensions.tabmix.openTabNextInverse") ?\n' +
- ' tabs[tabs.length - 1]._tPos :\n' +
- ' this.mCurrentTab._tPos ;\n' +
- ' if (index < aTab._tPos) index++;\n' +
- ' return index;\n' +
- ' }\n' +
- ' else {\n' +
- ' return ($&);\n' +
- ' }\n' +
- ' }).call(this)'
- )
- );
-
- gBrowser.treeStyleTab.internallyTabMovingCount--;
- }
-
- // Multi Links
- // https://addons.mozilla.org/firefox/addon/13494
- if ('MultiLinks_Wrapper' in window &&
- 'LinksManager' in MultiLinks_Wrapper &&
- 'OpenInNewTabs' in MultiLinks_Wrapper.LinksManager &&
- TreeStyleTabUtils.getTreePref('compatibility.MultiLinks')) {
- eval('MultiLinks_Wrapper.LinksManager.OpenInNewTabs = '+
- MultiLinks_Wrapper.LinksManager.OpenInNewTabs.toSource().replace(
- '{',
- '{\n' +
- ' if (!TreeStyleTabService.checkToOpenChildTab(getBrowser()))\n' +
- ' TreeStyleTabService.readyToOpenChildTab(getBrowser(), true);'
- ).replace(
- /(\}\)?)$/,
- ' if (TreeStyleTabService.checkToOpenChildTab(getBrowser()))\n' +
- ' TreeStyleTabService.stopToOpenChildTab(getBrowser());\n' +
- '$1'
- )
- );
- }
-
- // DomainTab
- // https://addons.mozilla.org/firefox/addon/13906/
- if ('domaintab' in window &&
- 'TMP_howToOpen' in domaintab &&
- TreeStyleTabUtils.getTreePref('compatibility.DomainTab')) {
- eval('domaintab.TMP_howToOpen = '+
- domaintab.TMP_howToOpen.toSource().replace(
- /(domaintab.DT_openNewTabWith\()/g,
- 'TreeStyleTabService.readyToOpenChildTab(); $1'
- )
- );
- }
-
- // Personal Titlebar
- // https://addons.mozilla.org/irefox/addon/personal-titlebar/
- if (document.getElementById('personal-titlebar') &&
- TreeStyleTabUtils.getTreePref('compatibility.PersonalTitlebar')) {
- let titlebar = document.getElementById('titlebar');
- let personalTitlebar = document.getElementById('personal-titlebar');
- let listener = {
- handleEvent : function(aEvent)
- {
- switch (aEvent.type)
- {
- case 'beforecustomization':
- titlebar.removeEventListener('DOMAttrModified', this, true);
- gBrowser.treeStyleTab.destroyTabStrip(personalTitlebar);
- break;
-
- case 'aftercustomization':
- titlebar.addEventListener('DOMAttrModified', this, true);
- break;
-
- case 'DOMAttrModified':
- if (
- aEvent.attrName == 'hidden' &&
- gBrowser.tabContainer.parentNode.id == (aEvent.newValue == 'true' ? 'toolbar-menubar' : 'personal-titlebar' )
- ) {
- TreeStyleTabService.stopRendering();
- gBrowser.treeStyleTab.syncDestroyTabbar();
- window.setTimeout(function() {
- gBrowser.treeStyleTab.syncReinitTabbar();
- TreeStyleTabService.startRendering();
- }, 0);
- }
- break;
-
- case 'unload':
- titlebar.removeEventListener('DOMAttrModified', this, true);
- document.removeEventListener('beforecustomization', this, false);
- document.removeEventListener('aftercustomization', this, false);
- document.removeEventListener('unload', this, false);
- personalTitlebar = null;
- break;
- }
- }
- };
- document.addEventListener('beforecustomization', listener, false);
- document.addEventListener('aftercustomization', listener, false);
- document.addEventListener('unload', listener, false);
- titlebar.addEventListener('DOMAttrModified', listener, true);
- }
-
- // TotalToolbar
- // http://totaltoolbar.mozdev.org/
- let (menu = document.getElementById('tt-toolbar-properties') &&
- TreeStyleTabUtils.getTreePref('compatibility.TotalToolbar')) {
- if (menu) {
- let tabbarToolboxes = ['tt-toolbox-tabright', 'tt-toolbox-tableft']
- .map(document.getElementById, document)
- .filter(function(aToolbox) { return aToolbox; });
- let listener = {
- handleEvent : function(aEvent)
- {
- var sv = TreeStyleTabService;
- switch (aEvent.type)
- {
- case 'command':
- gBrowser.treeStyleTab.updateFloatingTabbar(sv.kTABBAR_UPDATE_BY_WINDOW_RESIZE);
- break;
-
- case 'beforecustomization':
- for (let i = 0, maxi = tabbarToolboxes.length; i < maxi; i++)
- {
- tabbarToolboxes[i].removeAttribute('collapsed');
- }
- break;
-
- case 'aftercustomization':
- for (let i = 0, maxi = tabbarToolboxes.length; i < maxi; i++)
- {
- let toolbox = tabbarToolboxes[i];
- if (!toolbox.firstChild.hasChildNodes())
- toolbox.setAttribute('collapsed', true);
- }
- break;
-
- case 'unload':
- menu.removeEventListener('command', this, true);
- document.removeEventListener('beforecustomization', listener, true);
- document.removeEventListener('aftercustomization', listener, false);
- document.removeEventListener('unload', this, false);
- menu = null;
- break;
- }
- }
- };
- menu.addEventListener('command', listener, false);
- document.addEventListener('beforecustomization', listener, true);
- document.addEventListener('aftercustomization', listener, false);
- document.addEventListener('unload', listener, false);
- for (let i = 0, maxi = tabbarToolboxes.length; i < maxi; i++)
- {
- let toolbox = tabbarToolboxes[i];
- if (!toolbox.firstChild.hasChildNodes())
- toolbox.setAttribute('collapsed', true);
- }
- }
- }
-
- // Tab Control
- // https://addons.mozilla.org/firefox/addon/tab-control/
- if (
- TreeStyleTabUtils.getTreePref('compatibility.TabControl') &&
- 'gTabControl' in window
- ) {
- let listener = {
- handleEvent : function(aEvent)
- {
- switch (aEvent.type)
- {
- case sv.kEVENT_TYPE_FOCUS_NEXT_TAB:
- if (TreeStyleTabUtils.prefs.getPref('tabcontrol.focusLeftOnClose'))
- aEvent.preventDefault();
- break;
-
- case 'unload':
- document.removeEventListener(sv.kEVENT_TYPE_FOCUS_NEXT_TAB, this, false);
- break;
- }
- }
- };
- document.addEventListener(sv.kEVENT_TYPE_FOCUS_NEXT_TAB, listener, false);
- document.addEventListener('unload', listener, false);
- }
-
- // Firefox Sync (Weave)
- // http://www.mozilla.com/en-US/firefox/sync/
- if (
- (
- 'gFxWeaveGlue' in window || // addon
- 'gSyncUI' in window // Firefox 4 built-in
- ) &&
- TreeStyleTabUtils.getTreePref('compatibility.FirefoxSync')
- ) {
- let ns = {};
- try { // 1.4
- Components.utils.import('resource://services-sync/service.js', ns);
- }
- catch(e) { // 1.3
- Components.utils.import('resource://weave/service.js', ns);
- }
- let listener = {
- handleEvent : function(aEvent)
- {
- switch (aEvent.type)
- {
- case 'TabOpen':
- let tab = aEvent.originalTarget
- let b = TreeStyleTabService.getTabBrowserFromChild(tab);
- if (b.selectedTab.linkedBrowser.currentURI.spec != 'about:sync-tabs')
- return;
-
- let service = ns.Service || ns.Weave /* old name */;
- let manager = service.engineManager || service.Engines /* old name */;
- let engine = manager.get('tabs');
-
- let uri = tab.getAttribute('label');
- if (engine.locallyOpenTabMatchesURL(uri))
- return;
-
- for (let [guid, client] in Iterator(engine.getAllClients()))
- {
- if (client.tabs.some(function({ urlHistory }) {
- return urlHistory[0] == uri;
- })) {
- let parent = b.selectedTab;
- window.setTimeout(function() {
- if (tab.parentNode && !b.treeStyleTab.getParentTab(tab))
- b.treeStyleTab.attachTabTo(tab, parent);
- }, 0);
- return;
- }
- }
- return;
-
- case 'unload':
- document.removeEventListener('TabOpen', this, true);
- document.removeEventListener('unload', this, false);
- return;
- }
- }
- };
- document.addEventListener('TabOpen', listener, true);
- document.addEventListener('unload', listener, false);
- }
-
-};
+Components.utils.import('resource://gre/modules/XPCOMUtils.jsm');
+XPCOMUtils.defineLazyModuleGetter(this,
+ 'Services', 'resource://gre/modules/Services.jsm');
+XPCOMUtils.defineLazyModuleGetter(this,
+ 'TreeStyleTabUtils', 'resource://treestyletab-modules/utils.js');
+
+TreeStyleTabWindowHelper.extraProperties = [
+ TreeStyleTabService.kID,
+ TreeStyleTabService.kCOLLAPSED,
+ TreeStyleTabService.kSUBTREE_COLLAPSED,
+ TreeStyleTabService.kCHILDREN,
+ TreeStyleTabService.kPARENT,
+ TreeStyleTabService.kANCESTOR,
+ TreeStyleTabService.kINSERT_BEFORE,
+ TreeStyleTabService.kINSERT_AFTER
+];
+
+TreeStyleTabWindowHelper.overrideExtensionsPreInit = function TSTWH_overrideExtensionsPreInit() {
+ var sv = this.service;
+
+ // Highlander
+ // https://addons.mozilla.org/firefox/addon/4086
+ if ('Highlander' in window &&
+ TreeStyleTabUtils.getTreePref('compatibility.Highlander')) {
+ eval('Highlander.overrideHandleLinkClick = '+
+ Highlander.overrideHandleLinkClick.toSource().replace(
+ /(var )?origHandleLinkClick/g,
+ 'window.__treestyletab__highlander__origHandleLinkClick'
+ )
+ );
+ }
+
+ // PermaTabs
+ // https://addons.mozilla.org/firefox/addon/2558
+ // PermaTabs Mod
+ // https://addons.mozilla.org/firefox/addon/7816
+ if ('permaTabs' in window &&
+ TreeStyleTabUtils.getTreePref('compatibility.PermaTabs')) {
+ if ('__init' in permaTabs) {
+ // without delay, Firefox crashes on startup.
+ eval('permaTabs.__init = '+
+ permaTabs.__init.toSource().replace(
+ 'aTab.setAttribute(\\"image\\", ',
+ 'window.setTimeout(function(aTab, aImage) { aTab.setAttribute(\\"image\\", aImage); }, 100, aTab, '
+ )
+ );
+ }
+ if ('showPermaTab' in permaTabs) {
+ eval('permaTabs.showPermaTab = '+
+ permaTabs.showPermaTab.toSource().replace(
+ /(\}\)?)$/,
+ '(function(tab, id) {\n' +
+ ' if (this.ssWillRestore) return;\n' +
+ ' var TST = TreeStyleTabService;\n' +
+ ' if (this.TSTRestoredPermaTabsInfo === void(0)) {\n' +
+ ' try {\n' +
+ ' eval("this.TSTRestoredPermaTabsInfo = "+(TreeStyleTabUtils.getTreePref("permaTabsInfo") || "null"));\n' +
+ ' }\n' +
+ ' catch(e) {\n' +
+ ' }\n' +
+ ' }\n' +
+ ' if (!this.TSTRestoredPermaTabsInfo) return;\n' +
+
+ ' var info = this.TSTRestoredPermaTabsInfo[id];\n' +
+ ' if (!info) return;\n' +
+
+ ' for (var i in info)\n' +
+ ' {\n' +
+ ' TST.SessionStore.setTabValue(tab, i, String(info[i]));\n' +
+ ' }\n' +
+ ' var count = 0;\n' +
+ ' window.setTimeout(function onTimeout() {\n' +
+ ' var b = TST.getTabBrowserFromChild(tab);\n' +
+ ' if (!b.treeStyleTab) {\n' +
+ ' if (++count < 50)\n' +
+ ' window.setTimeout(onTimeout, 100);\n' +
+ ' return;\n' +
+ ' }\n' +
+ ' b.treeStyleTab.handleRestoredTab(tab);\n' +
+ ' }, 0);\n' +
+ '}).call(this, tab, id)\n' +
+ '$1'
+ )
+ );
+ }
+ if ('savePermaTabs' in permaTabs) {
+ eval('permaTabs.savePermaTabs = '+
+ permaTabs.savePermaTabs.toSource().replace(
+ '{',
+ '{\n' +
+ '(function() {\n' +
+ ' var tabsInfo = {};\n' +
+ ' var TST = TreeStyleTabService;\n' +
+ ' var allTabs = getBrowser().mTabContainer.childNodes;\n' +
+ ' for (let i = 0, maxi = allTabs.length; i < maxi; i++)\n' +
+ ' {\n' +
+ ' let tab = allTabs[i];\n' +
+ ' let index = this.getPermaTabLocalIndex(tab);\n' +
+ ' if (index < 0) continue;\n' +
+ ' let info = {};\n' +
+ ' for (let i = 0, maxi = TST.extraProperties.length; i < maxi; i++)\n' +
+ ' {\n' +
+ ' let property = TST.extraProperties[i];\n' +
+ ' info[property] = TST.getTabValue(tab, property);\n' +
+ ' }\n' +
+ ' tabsInfo[this.permaTabs[index].id] = info;\n' +
+ ' }\n' +
+ ' TreeStyleTabUtils.setTreePref("permaTabsInfo", tabsInfo.toSource());\n' +
+ '}).call(this);'
+ )
+ );
+ }
+ }
+
+ // Tab Mix Plus
+ if (TreeStyleTabUtils.getTreePref('compatibility.TMP')) {
+ document.documentElement.setAttribute('treestyletab-enable-compatibility-tmp', true);
+ }
+ // Tab Mix Plus, SessionStore API
+ if (
+ TreeStyleTabUtils.getTreePref('compatibility.TMP') &&
+ ('TabmixSessionData' in window || 'SessionData' in window)
+ ) {
+ let sessionData = window.TabmixSessionData || window.SessionData;
+ if ('getTabProperties' in sessionData && 'setTabProperties' in sessionData) {
+ let prefix = sv.kTMP_SESSION_DATA_PREFIX;
+ let sessionManager = window.TabmixSessionManager || window.SessionManager;
+ sessionData.tabTSTProperties = this.extraProperties.map(function(aProperty) {
+ return prefix+aProperty;
+ });
+ eval('sessionData.getTabProperties = '+
+ sessionData.getTabProperties.toSource().replace(
+ 'return tabProperties;',
+ ' for (let i = 0, maxi = this.tabTSTProperties.length; i < maxi; i++)\n' +
+ ' {\n' +
+ ' let property = this.tabTSTProperties[i];\n' +
+ ' tabProperties += "|" + property + "=" + encodeURIComponent(aTab.getAttribute(property));\n' +
+ ' }\n' +
+ '$&'
+ )
+ );
+ eval('sessionData.setTabProperties = '+
+ sessionData.setTabProperties.toSource().replace(
+ '{',
+ '$&\n' +
+ ' var TSTProps = tabProperties.split("|");\n' +
+ ' tabProperties = TSTProps.shift();\n' +
+ ' for (let i = 0, maxi = TSTProps.length; i < maxi; i++)\n' +
+ ' {\n' +
+ ' let property = TSTProps[i];\n' +
+ ' let index = property.indexOf("=");\n' +
+ ' let name = property.substring(0, index);\n' +
+ ' let value = decodeURIComponent(property.substring(index+1));\n' +
+ ' if (name && value)\n' +
+ ' aTab.setAttribute(name, value);\n' +
+ ' }'
+ )
+ );
+ eval('sessionManager.loadOneTab = '+
+ sessionManager.loadOneTab.toSource().replace(
+ /(\}\))?$/,
+ ' if (gBrowser.treeStyleTab.useTMPSessionAPI)\n' +
+ ' gBrowser.treeStyleTab.handleRestoredTab(aTab);\n' +
+ '$1'
+ )
+ );
+ let source = tablib.init.toSource().split('gBrowser.restoreTab = ');
+ source[1] = source[1].replace(
+ 'return newTab;',
+ ' if (this.treeStyleTab.useTMPSessionAPI)\n' +
+ ' this.treeStyleTab.handleRestoredTab(newTab);\n' +
+ '$&'
+ );
+ eval('tablib.init = '+source.join('gBrowser.restoreTab = '));
+ eval('sessionManager.loadOneWindow = '+
+ sessionManager.loadOneWindow.toSource().replace(
+ 'gBrowser.tabsToLoad = ',
+ ' gBrowser.treeStyleTab.resetAllTabs(true, true);\n' +
+ ' TreeStyleTabService.restoringTree = true;\n' +
+ '$&'
+ ).replace(
+ /(\}\))?$/,
+ 'TreeStyleTabService.restoringTree = false; $1'
+ )
+ );
+ sv.useTMPSessionAPI = true;
+ }
+ }
+
+ // Session Manager
+ // https://addons.mozilla.org/firefox/addon/2324
+ // We need to initialize TST before Session Manager restores the last session anyway!
+ if ('gSessionManager' in window &&
+ TreeStyleTabUtils.getTreePref('compatibility.SessionManager')) {
+ if ('onLoad_proxy' in gSessionManager &&
+ 'onLoad' in gSessionManager) {
+ eval('gSessionManager.onLoad = '+gSessionManager.onLoad.toSource().replace(
+ '{',
+ '{ TreeStyleTabService.init();'
+ ));
+ }
+ if ('load' in gSessionManager) {
+ eval('gSessionManager.load = '+gSessionManager.load.toSource().replace(
+ 'var tabcount = ',
+ ' gBrowser.treeStyleTab.collapseExpandAllSubtree(false, true);\n' +
+ ' let (tabs = gBrowser.treeStyleTab.getTabs(gBrowser).slice(1).reverse()) {\n' +
+ ' for (let i = 0, maxi = tabs.length; i < maxi; i++)\n' +
+ ' {\n' +
+ ' let tab = tabs[i];\n' +
+ ' gBrowser.removeTab(tab);\n' +
+ ' }\n' +
+ ' }\n' +
+ ' TreeStyleTabService.restoringTree = true;\n' +
+ '$&'
+ ));
+ }
+ }
+
+ // FullerScreen
+ // https://addons.mozilla.org/firefox/addon/4650
+ if ('FS_onFullerScreen' in window &&
+ TreeStyleTabUtils.getTreePref('compatibility.FullerScreen')) {
+ let (functions = 'CheckIfFullScreen,FS_onFullerScreen,FS_onMouseMove'.split(',')) {
+ for (let i = 0, maxi = functions.length; i < maxi; i++)
+ {
+ let func = functions[i];
+ if (!(func in window)) continue;
+ eval('window.'+func+' = '+window[func].toSource().replace(
+ /FS_data.mTabs.(removeAttribute\("moz-collapsed"\)|setAttribute\("moz-collapsed", "true"\));/g,
+ 'if (gBrowser.treeStyleTab.currentTabbarPosition == "top") { $& }'
+ ));
+ }
+ }
+ }
+
+ // TooManyTabs
+ // https://addons.mozilla.org/firefox/addon/9429
+ if ('tooManyTabs' in window &&
+ TreeStyleTabUtils.getTreePref('compatibility.TooManyTabs')) {
+ sv.registerExpandTwistyAreaBlocker('tooManyTabs');
+ }
+
+ // DragNDrop Toolbars
+ // https://addons.mozilla.org/firefox/addon/dragndrop-toolbars/
+ if ('globDndtb' in window &&
+ globDndtb.setTheStuff &&
+ TreeStyleTabUtils.getTreePref('compatibility.DragNDropToolbars')) {
+ let reinitTabbar = function() {
+ TreeStyleTabService.stopRendering();
+ gBrowser.treeStyleTab.syncDestroyTabbar();
+ window.setTimeout(function() {
+ gBrowser.treeStyleTab.syncReinitTabbar();
+ TreeStyleTabService.startRendering();
+ }, 100);
+ };
+ globDndtb.__treestyletab__setOrder = globDndtb.setOrder;
+ globDndtb.setOrder = function() {
+ reinitTabbar();
+ return this.__treestyletab__setOrder.apply(this, arguments);
+ };
+ globDndtb.__treestyletab__setTheStuff = globDndtb.setTheStuff;
+ globDndtb.setTheStuff = function() {
+ var result = this.__treestyletab__setTheStuff.apply(this, arguments);
+ if (this.dndObserver &&
+ this.dndObserver.onDrop &&
+ !this.dndObserver.__treestyletab__onDrop) {
+ this.dndObserver.__treestyletab__onDrop = this.dndObserver.onDrop;
+ this.dndObserver.onDrop = function(aEvent, aDropData, aSession) {
+ if (document.getElementById(aDropData.data) == gBrowser.treeStyleTab.tabStrip) {
+ reinitTabbar();
+ }
+ return this.__treestyletab__onDrop.apply(this, arguments);
+ };
+ }
+ return result;
+ };
+ }
+
+ // Optimoz Tweaks
+ // http://optimoz.mozdev.org/tweaks/
+ // https://addons.mozilla.org/firefox/addon/optimoz-tweaks-ja-version/
+ if ('mtSidebarStartup' in window &&
+ 'mtSidebarShutdown' in window &&
+ 'mtPreventHiding' in window &&
+ TreeStyleTabUtils.getTreePref('compatibility.OptimozTweaks')) {
+ eval('window.mtSidebarStartup = '+window.mtSidebarStartup.toSource().replace(
+ '{',
+ '{\n' +
+ ' document.getElementById("TabsToolbar")\n' +
+ ' .addEventListener("mousemove", mtMouseMoveListener, false);'
+ ));
+ eval('window.mtSidebarShutdown = '+window.mtSidebarShutdown.toSource().replace(
+ '{',
+ '{\n' +
+ ' document.getElementById("TabsToolbar")\n' +
+ ' .removeEventListener("mousemove", mtMouseMoveListener, false);'
+ ));
+ eval('window.mtPreventHiding = '+window.mtPreventHiding.toSource().replace(
+ '{',
+ '{\n' +
+ ' if (TreeStyleTabService.getTabbarFromEvent(arguments[0]))\n' +
+ ' return;'
+ ));
+ }
+
+ /**
+ * Hide Caption Titlebar Plus (Smart)
+ * https://addons.mozilla.org/firefox/addon/hide-caption-titlebar-plus-sma/
+ */
+ if ('HideCaption' in window &&
+ 'do_alter' in HideCaption) {
+ eval('HideCaption.do_alter = '+HideCaption.do_alter.toSource().replace(
+ 'if (!theSettings) {',
+ ' if (!theSettings ||\n' +
+ ' gBrowser.treeStyleTab.isVertical) {'
+ ));
+ }
+
+ // Greasemonkey
+ // https://addons.mozilla.org/firefox/addon/748
+ if (TreeStyleTabUtils.getTreePref('compatibility.Greasemonkey')) {
+ try {
+ let hitchModule = Components.utils.import('resource://greasemonkey/util/hitch.js', {});
+ let hitch = hitchModule.hitch;
+ if (hitch.toSource().indexOf('TreeStyleTabService') < 0) {
+ let ns = {};
+ Components.utils.import('resource://greasemonkey/third-party/getChromeWinForContentWin.js', ns);
+ let getChromeWinForContentWin = ns.getChromeWinForContentWin;
+ hitchModule.hitch = function(aObject, aMethod) {
+ if (typeof aMethod == 'function' &&
+ aMethod.toSource().indexOf('function openInTab') > -1) {
+ let originalOpenInTab = aMethod;
+ /**
+ * This function must be replaced on scripts in "chrome:" URL, like this.
+ * Otherwise the original openInTab() will raise violation error.
+ * Don't move this hack into JS code modules with "resource:" URL.
+ */
+ aMethod = function openInTab(aSafeContentWindow, aURL, aLoadInBackgtound) {
+ let chrome = getChromeWinForContentWin(aSafeContentWindow);
+ if (chrome && chrome.TreeStyleTabService)
+ chrome.TreeStyleTabService.readyToOpenChildTabNow(aSafeContentWindow);
+ return originalOpenInTab.apply(this, arguments);
+ };
+ }
+ return hitch.apply(this, arguments);
+ };
+ Components.utils.import('resource://greasemonkey/util.js', ns);
+ if (ns.GM_util)
+ ns.GM_util.hitch = hitchModule.hitch;
+ }
+ }
+ catch(e) {
+ dump('Tree Style Tab: failed to patch to Greasemonkey.\n');
+ dump(e+'\n');
+ }
+ }
+};
+
+TreeStyleTabWindowHelper.overrideExtensionsBeforeBrowserInit = function TSTWH_overrideExtensionsBeforeBrowserInit() {
+ var sv = this.service;
+
+ // Tab Mix Plus
+ if (TreeStyleTabUtils.getTreePref('compatibility.TMP') &&
+ 'TMP_LastTab' in window) {
+ TMP_LastTab.TabBar = gBrowser.mTabContainer;
+ }
+ if (TreeStyleTabUtils.getTreePref('compatibility.TMP') &&
+ 'isTabVisible' in gBrowser.mTabContainer &&
+ 'ensureTabIsVisible' in gBrowser.mTabContainer) {
+ let replaceHorizontalProps = function replaceHorizontalProps(aString)
+ {
+ return aString.replace(
+ /boxObject\.x/g,
+ 'boxObject[posProp]'
+ ).replace(
+ /boxObject\.screenX/g,
+ 'boxObject[screenPosProp]'
+ ).replace(
+ /boxObject\.width/g,
+ 'boxObject[sizeProp]'
+ ).replace(
+ '{',
+ '{\n' +
+ ' var posProp = gBrowser.treeStyleTab.isVertical ? "y" : "x" ;\n' +
+ ' var screenPosProp = gBrowser.treeStyleTab.isVertical ? "screenY" : "screenX" ;\n' +
+ ' var sizeProp = gBrowser.treeStyleTab.isVertical ? "height" : "width" ;'
+ )
+ }
+ eval('gBrowser.mTabContainer.ensureTabIsVisible = '+
+ replaceHorizontalProps(gBrowser.mTabContainer.ensureTabIsVisible.toSource().replace(
+ 'boxObject.width < 250',
+ '$& || gBrowser.treeStyleTab.isVertical'
+ ))
+ );
+ eval('gBrowser.mTabContainer.isTabVisible = '+
+ replaceHorizontalProps(gBrowser.mTabContainer.isTabVisible.toSource())
+ );
+ }
+
+ // Tabberwocky
+ // https://addons.mozilla.org/firefox/addon/14439
+ if ('tabberwocky' in window &&
+ TreeStyleTabUtils.getTreePref('compatibility.Tabberwocky')) {
+ let listener = {
+ handleEvent : function(aEvent)
+ {
+ switch (aEvent.type)
+ {
+ case 'TreeStyleTabTabbarPositionChanged':
+ var b = aEvent.originalTarget;
+ if (b.treeStyleTab.isVertical)
+ TreeStyleTabUtils.prefs.setPref('tabberwocky.multirow', false);
+ break;
+
+ case 'unload':
+ document.removeEventListener('TreeStyleTabTabbarPositionChanged', this, false);
+ document.removeEventListener('unload', this, false);
+ break;
+ }
+ }
+ };
+ document.addEventListener('TreeStyleTabTabbarPositionChanged', listener, false);
+ document.addEventListener('unload', listener, false);
+
+ if ('openSelectedLinks' in tabberwocky) {
+ eval('tabberwocky.openSelectedLinks = '+
+ tabberwocky.openSelectedLinks.toSource().replace(
+ 'links.forEach(',
+ ' TreeStyleTabService.readyToOpenChildTab(aFrame, true)\n' +
+ '$&'
+ ).replace(
+ /(\}\)?)$/,
+ ' TreeStyleTabService.stopToOpenChildTab(aFrame)\n' +
+ '$1'
+ )
+ );
+ }
+ }
+};
+
+TreeStyleTabWindowHelper.overrideExtensionsAfterBrowserInit = function TSTWH_overrideExtensionsAfterBrowserInit() {
+ var sv = this.service;
+
+ // Selection Links
+ // https://addons.mozilla.org/firefox/addon/8644
+ if ('selectionlinks' in window &&
+ 'parseSelection' in selectionlinks &&
+ TreeStyleTabUtils.getTreePref('compatibility.SelectionLinks')) {
+ eval('selectionlinks.parseSelection = '+
+ selectionlinks.parseSelection.toSource().replace(
+ /((?:[^\s:;]+.selectedTab\s*=\s*)?([^\s:;]+).addTab\()/g,
+ ' if ($2.treeStyleTab)\n' +
+ ' $2.treeStyleTab.readyToOpenChildTab(focusedWindow);\n' +
+ '$1'
+ )
+ );
+ }
+
+
+ // Tab Mix Plus
+ if (
+ TreeStyleTabUtils.getTreePref('compatibility.TMP') &&
+ 'TabmixTabbar' in window
+ ) {
+ let DNDObserver = 'TMP_tabDNDObserver' in window ? TMP_tabDNDObserver : TabDNDObserver ;
+ this.updateTabDNDObserver(DNDObserver);
+ eval('DNDObserver.clearDragmark = '+
+ DNDObserver.clearDragmark.toSource().replace(
+ /(\})(\))?$/,
+ 'gBrowser.treeStyleTab.tabbarDNDObserver.clearDropPosition(); $1$2'
+ )
+ );
+ eval('DNDObserver.onDragStart = '+
+ DNDObserver.onDragStart.toSource().replace(
+ 'event.target.localName != "tab"',
+ ' gBrowser.treeStyleTab.tabbarDNDObserver.canDragTabbar(event) ||\n' +
+ ' $&'
+ )
+ );
+
+ eval('window.TMP_howToOpen = '+
+ window.TMP_howToOpen.toSource().replace(
+ /(window.openNewTabWith\()/g,
+ 'TreeStyleTabService.readyToOpenChildTab(event.target.ownerDocument.defaultView); $1'
+ )
+ );
+
+ if ('TabmixContext' in window &&
+ typeof TabmixContext.openMultipleLinks == 'function') {
+ eval('TabmixContext.openMultipleLinks = '+
+ TabmixContext.openMultipleLinks.toSource().replace(
+ /(TMP_loadTabs\([^\)]+\);)/g,
+ 'TreeStyleTabService.readyToOpenChildTab(gBrowser, true); $1 TreeStyleTabService.stopToOpenChildTab(gBrowser);'
+ )
+ );
+ }
+
+
+ let listener = {
+ handleEvent : function(aEvent)
+ {
+ switch (aEvent.type)
+ {
+ case sv.kEVENT_TYPE_TAB_COLLAPSED_STATE_CHANGED:
+ TabmixTabbar.updateScrollStatus();
+ break;
+
+ case sv.kEVENT_TYPE_FOCUS_NEXT_TAB:
+ let mode = TreeStyleTabUtils.prefs.getPref('extensions.tabmix.focusTab');
+ if (mode != 2 && mode != 5)
+ aEvent.preventDefault();
+ break;
+
+ case 'unload':
+ document.removeEventListener(sv.kEVENT_TYPE_TAB_COLLAPSED_STATE_CHANGED, this, false);
+ document.removeEventListener(sv.kEVENT_TYPE_FOCUS_NEXT_TAB, this, false);
+ document.removeEventListener('unload', this, false);
+ break;
+ }
+ }
+ };
+ document.addEventListener(sv.kEVENT_TYPE_TAB_COLLAPSED_STATE_CHANGED, listener, false);
+ document.addEventListener(sv.kEVENT_TYPE_FOCUS_NEXT_TAB, listener, false);
+ document.addEventListener('unload', listener, false);
+
+ gBrowser.treeStyleTab.internallyTabMovingCount++; // until "TMmoveTabTo" method is overwritten
+ }
+
+
+ // Super DragAndGo
+ // https://addons.mozilla.org/firefox/addon/137
+ if ('superDrag' in window &&
+ TreeStyleTabUtils.getTreePref('compatibility.SuperDragAndGo')) {
+ eval('superDrag.onDrop = '+
+ superDrag.onDrop.toSource().replace(
+ /(var newTab = getBrowser\(\).addTab\([^\)]+\);)/g,
+ ' if (aDragSession.sourceNode &&\n' +
+ ' aDragSession.sourceNode.ownerDocument.defaultView.top == getBrowser().contentWindow)\n' +
+ ' TreeStyleTabService.readyToOpenChildTab(getBrowser());\n' +
+ ' $1'
+ )
+ );
+ }
+
+ // Drag de Go
+ // https://addons.mozilla.org/firefox/addon/2918
+ if ('ddg_ges' in window &&
+ TreeStyleTabUtils.getTreePref('compatibility.DragDeGo')) {
+ eval('ddg_ges.Open = '+
+ ddg_ges.Open.toSource().replace(
+ 'if (mode[1] == "h" || mode[1] == "f") {',
+ '$&\n' +
+ ' if ("sourceNode" in aData) // only for dragging from the content tarea.\n' +
+ ' TreeStyleTabService.readyToOpenChildTab(getBrowser());'
+ )
+ );
+ eval('ddg_ges.Search = '+
+ ddg_ges.Search.toSource().replace(
+ 'if (mode[1] == "h" || mode[1] == "f") {',
+ '$&\n' +
+ ' TreeStyleTabService.readyToOpenChildTab(getBrowser());'
+ )
+ );
+ }
+
+ // DragIt
+ // https://addons.mozilla.org/firefox/addon/dragit-formerly-drag-de-go/
+ if ('DragIt' in window &&
+ DragIt.tab &&
+ DragIt.tab.open &&
+ TreeStyleTabUtils.getTreePref('compatibility.DragIt')) {
+ eval('DragIt.tab.open = '+
+ DragIt.tab.open.toSource().replace(
+ 'try {',
+ 'try { TreeStyleTabService.readyToOpenChildTabNow(gBrowser);'
+ )
+ );
+ }
+
+ // Colorful Tabs
+ // https://addons.mozilla.org/firefox/addon/1368
+ if ('colorfulTabs' in window &&
+ TreeStyleTabUtils.getTreePref('compatibility.ColorfulTabs')) {
+ let listener = {
+ handleEvent : function(aEvent)
+ {
+ switch (aEvent.type)
+ {
+ case 'TabOpen':
+ case 'TreeStyleTabAttached':
+ case 'TreeStyleTabParted':
+ var child = aEvent.originalTarget;
+ var parent = aEvent.parentTab;
+ if (child && parent) {
+ let color = TreeStyleTabService.SessionStore.getTabValue(parent, 'tabClr');
+ if (/^\d+,\d+,\d+$/.test(color))
+ color = 'rgb('+color+')';
+ window.setTimeout(function() {
+ colorfulTabs.setColor(child, color);
+ }, 0);
+ }
+ else if (child) {
+ TreeStyleTabService.SessionStore.setTabValue(child, 'tabClr', '');
+ colorfulTabs.calcTabClr({
+ target : child,
+ originalTarget : child,
+ });
+ }
+ break;
+
+ case 'unload':
+ document.removeEventListener('TabOpen', this, false);
+ document.removeEventListener('TreeStyleTabAttached', this, false);
+ document.removeEventListener('TreeStyleTabParted', this, false);
+ document.removeEventListener('unload', this, false);
+ break;
+ }
+ }
+ };
+ eval('colorfulTabs.show_ctStack = '+
+ colorfulTabs.show_ctStack.toSource().replace(
+ '.setProperty("display", "-moz-stack", "important")',
+ '.display = ""'
+ )
+ );
+ document.addEventListener('TabOpen', listener, false);
+ document.addEventListener('TreeStyleTabAttached', listener, false);
+ document.addEventListener('TreeStyleTabParted', listener, false);
+ document.addEventListener('unload', listener, false);
+ }
+
+ // FLST (Focus Last Selected Tab)
+ // https://addons.mozilla.org/firefox/addon/32
+ if ('flst' in window &&
+ TreeStyleTabUtils.getTreePref('compatibility.FLST')) {
+ TreeStyleTabService.registerTabFocusAllowance(function(aTabBrowser) {
+ return !TreeStyleTabUtils.prefs.getPref('extensions.flst.enabled');
+ });
+ }
+
+ // Focus Last Selected Tab 0.9.5.x
+ // http://www.gozer.org/mozilla/extensions/
+ if (TreeStyleTabUtils.getTreePref('compatibility.FocusLastSelectedTab')) {
+ sv.extensions.isAvailable('focuslastselectedtab@gozer.org', { ok : function() {
+ TreeStyleTabService.registerTabFocusAllowance(function(aTabBrowser) {
+ return !aTabBrowser.selectedTab.hasAttribute('lastselected');
+ });
+ }});
+ }
+
+ // LastTab
+ // https://addons.mozilla.org/firefox/addon/112
+ if ('LastTab' in window &&
+ TreeStyleTabUtils.getTreePref('compatibility.LastTab')) {
+ TreeStyleTabService.registerTabFocusAllowance(function(aTabBrowser) {
+ return !TreeStyleTabUtils.prefs.getPref('extensions.lasttab.focusLastTabOnClose');
+ });
+ }
+
+ // FireGestures
+ // https://addons.mozilla.org/firefox/addon/6366
+ if ('FireGestures' in window &&
+ TreeStyleTabUtils.getTreePref('compatibility.FireGestures')) {
+ eval('FireGestures.onExtraGesture = '+
+ FireGestures.onExtraGesture.toSource().replace(
+ 'case "keypress-stop":',
+ '$&\n' +
+ ' TreeStyleTabService.readyToOpenChildTab(gBrowser, true);'
+ ).replace(
+ 'break;case "gesture-timeout":',
+ ' TreeStyleTabService.stopToOpenChildTab(gBrowser);\n' +
+ '$&'
+ )
+ );
+ eval('FireGestures._performAction = '+
+ FireGestures._performAction.toSource().replace(
+ 'gBrowser.loadOneTab(',
+ ' TreeStyleTabService.readyToOpenChildTab(gBrowser);\n' +
+ '$&'
+ )
+ );
+ eval('FireGestures.openURLsInSelection = '+
+ FireGestures.openURLsInSelection.toSource().replace(
+ 'var tab =',
+ ' if (!TreeStyleTabService.checkToOpenChildTab(gBrowser))\n' +
+ ' TreeStyleTabService.readyToOpenChildTab(gBrowser, true);\n' +
+ '$&'
+ ).replace(
+ 'if (!flag)',
+ ' if (TreeStyleTabService.checkToOpenChildTab(gBrowser))\n' +
+ ' TreeStyleTabService.stopToOpenChildTab(gBrowser);\n' +
+ '$&'
+ )
+ );
+ eval('FireGestures.handleEvent = '+
+ FireGestures.handleEvent.toSource().replace(
+ 'gBrowser.loadOneTab(',
+ ' TreeStyleTabService.readyToOpenChildTab(gBrowser);\n' +
+ '$&'
+ )
+ );
+ }
+
+ // Mouse Gestures Redox
+ // http://www.mousegestures.org/
+ if ('mgBuiltInFunctions' in window &&
+ 'mgLinkInTab' in mgBuiltInFunctions &&
+ TreeStyleTabUtils.getTreePref('compatibility.MouseGesturesRedox')) {
+ eval('mgBuiltInFunctions.mgLinkInTab = '+
+ mgBuiltInFunctions.mgLinkInTab.toSource().replace(
+ 'var tab',
+ 'TreeStyleTabService.readyToOpenChildTab(gBrowser); $&'
+ )
+ );
+ }
+
+ // SBM Counter
+ // http://miniturbo.org/products/sbmcounter/
+ if ('SBMCounter' in window &&
+ TreeStyleTabUtils.getTreePref('compatibility.SBMCounter')) {
+ eval('SBMCounter.action = '+
+ SBMCounter.action.toSource().replace(
+ 'gBrowser.selectedTab = gBrowser.addTab',
+ 'TreeStyleTabService.readyToOpenChildTab(gBrowser); $&'
+ )
+ );
+ }
+
+ // Aging Tabs
+ // https://addons.mozilla.org/firefox/addon/3542
+ if ('agingTabs' in window &&
+ TreeStyleTabUtils.getTreePref('compatibility.AgingTabs')) {
+ eval('agingTabs.setColor = '+
+ agingTabs.setColor.toSource().replace(
+ '{',
+ '{ important = true;'
+ )
+ );
+ }
+
+ // Snap Links
+ // https://addons.mozilla.org/firefox/addon/4336
+ // Snap Links Plus
+ // http://snaplinks.mozdev.org/
+ if (TreeStyleTabUtils.getTreePref('compatibility.SnapLinks')) {
+ if ('executeAction' in window &&
+ 'openTabs' in window) {
+ eval('window.openTabs = '+
+ window.openTabs.toSource().replace(
+ /((sContent|gBrowser|getBrowser\(\))\.addTab)/,
+ 'TreeStyleTabService.readyToOpenChildTab($2); $1'
+ )
+ );
+ }
+ if ('SnapLinks' in window &&
+ 'OpenTabs' in SnapLinks) {
+ eval('SnapLinks.OpenTabs = '+
+ SnapLinks.OpenTabs.toSource().replace(
+ /((sContent|gBrowser|getBrowser\(\))\.addTab)/,
+ 'TreeStyleTabService.readyToOpenChildTab($2); $1'
+ )
+ );
+ }
+ }
+
+ // Mouseless Browsing
+ // https://addons.mozilla.org/firefox/addon/879
+ if ('mouselessbrowsing' in window &&
+ 'EventHandler' in mouselessbrowsing &&
+ TreeStyleTabUtils.getTreePref('compatibility.MouselessBrowsing')) {
+ if ('execute' in mouselessbrowsing.EventHandler) {
+ eval('mouselessbrowsing.EventHandler.execute = '+
+ mouselessbrowsing.EventHandler.execute.toSource().replace(
+ '{',
+ '{ var Prefs = mlb_common.Prefs;'+
+ ' var Utils = mlb_common.Utils;'+
+ ' var MlbUtils = mouselessbrowsing.MlbUtils;'
+ ).replace(
+ /((?:var [^=]+ = )?Utils.openUrlInNewTab\()/g,
+ 'TreeStyleTabService.readyToOpenChildTab(); $1'
+ )
+ );
+ }
+ if ('openLinkInOtherLocationViaPostfixKey' in mouselessbrowsing.EventHandler) {
+ eval('mouselessbrowsing.EventHandler.openLinkInOtherLocationViaPostfixKey = '+
+ mouselessbrowsing.EventHandler.openLinkInOtherLocationViaPostfixKey.toSource().replace(
+ '{',
+ '{ var Prefs = mlb_common.Prefs;'+
+ ' var Utils = mlb_common.Utils;'+
+ ' var MlbUtils = mouselessbrowsing.MlbUtils;'+
+ ' var MlbCommon = mouselessbrowsing.MlbCommon;'+
+ ' var ShortcutManager = mlb_common.ShortcutManager;'
+ ).replace(
+ 'Utils.openUrlInNewTab(',
+ 'TreeStyleTabService.readyToOpenChildTab(); $&'
+ )
+ );
+ }
+ }
+
+ // Linky
+ // https://addons.mozilla.org/firefox/addon/425
+ if ('LinkyContext' in window &&
+ 'prototype' in LinkyContext &&
+ TreeStyleTabUtils.getTreePref('compatibility.Linky')) {
+ let (methods = 'openLink,openLinks,generateDocument'.split(',')) {
+ for (let i = 0, maxi = methods.length; i < maxi; i++)
+ {
+ let method = methods[i];
+ if (!(method in LinkyContext.prototype)) continue;
+ eval('LinkyContext.prototype.'+method+' = '+
+ LinkyContext.prototype[method].toSource().replace(
+ '{',
+ '{ TreeStyleTabService.readyToOpenChildTabNow(null, true);'
+ )
+ );
+ }
+ }
+ }
+
+ // QuickDrag
+ // https://addons.mozilla.org/firefox/addon/6912
+ if ('QuickDrag' in window &&
+ '_loadTab' in QuickDrag &&
+ TreeStyleTabUtils.getTreePref('compatibility.QuickDrag')) {
+ eval('QuickDrag._loadTab = '+
+ QuickDrag._loadTab.toSource().replace(
+ /(gBrowser.loadOneTab\()/g,
+ 'TreeStyleTabService.readyToOpenChildTab(), $1'
+ )
+ );
+ }
+
+ // Autohide
+ // http://www.krickelkrackel.de/autohide/
+ if ('autoHIDE' in window &&
+ TreeStyleTabUtils.getTreePref('compatibility.Autohide')) {
+ let autoHideEventListener = {
+ handleEvent : function(aEvent)
+ {
+ switch (aEvent.type)
+ {
+ case 'TreeStyleTabAutoHideStateChanging':
+ if (!window.fullScreen) return;
+ if (!aEvent.shown) {
+ if (
+ autoHIDE.statBar &&
+ gBrowser.treeStyleTab.currentTabbarPosition == 'bottom' &&
+ !TreeStyleTabUtils.prefs.getPref('extensions.autohide.bars.statBar.always') &&
+ TreeStyleTabUtils.prefs.getPref('extensions.autohide.bars.statBar')
+ ) {
+ autoHIDE.statBar.setAttribute('ahHIDE', true);
+ }
+ }
+ else {
+ TreeStyleTabService.getTabStrip(gBrowser).removeAttribute('ahHIDE');
+ if (
+ autoHIDE.statBar &&
+ aTabBrowser.treeStyleTab.currentTabbarPosition == 'bottom' &&
+ !TreeStyleTabUtils.prefs.getPref('extensions.autohide.bars.statBar.always') &&
+ TreeStyleTabUtils.prefs.getPref('extensions.autohide.bars.statBar')
+ ) {
+ autoHIDE.statBar.removeAttribute('ahHIDE');
+ }
+ }
+ break;
+
+ case 'fullscreen':
+ var treeStyleTab = gBrowser.treeStyleTab;
+ if (gBrowser.treeStyleTab.currentTabbarPosition != 'top') {
+ if (window.fullScreen)
+ treeStyleTab.autoHide.endForFullScreen();
+ else
+ treeStyleTab.autoHide.startForFullScreen();
+ }
+ break;
+
+ case 'unload':
+ document.removeEventListener('TreeStyleTabAutoHideStateChanging', this, false);
+ document.removeEventListener('unload', this, false);
+ document.removeEventListener('fullscreen', this, false);
+ break;
+ }
+ }
+ };
+ document.addEventListener('TreeStyleTabAutoHideStateChanging', autoHideEventListener, false);
+ document.addEventListener('fullscreen', autoHideEventListener, false);
+ document.addEventListener('unload', autoHideEventListener, false);
+
+ if ('MoveContent' in autoHIDE) {
+ eval('autoHIDE.MoveContent = '+autoHIDE.MoveContent.toSource().replace(
+ /(;)([^;]*\.setPosition\(0, -\s*ah\.delta\);)/,
+ '$1\n' +
+ ' if (autoHIDE.winUtil)\n' +
+ ' autoHIDE.winUtil.setRedraw(false, false);\n' +
+ ' $2\n' +
+ ' gBrowser.treeStyleTab.autoHide.extraYOffset = ah.delta;\n' +
+ ' window.setTimeout(function() {\n' +
+ ' gBrowser.treeStyleTab.autoHide.redrawContentArea();\n' +
+ ' if (autoHIDE.winUtil)\n' +
+ ' autoHIDE.winUtil.setRedraw(true, false);\n' +
+ ' }, 0);'
+ ).replace(
+ /(;)([^;]*\.setPosition\(0, 0\);)/,
+ '$1\n' +
+ ' if (autoHIDE.winUtil)\n' +
+ ' autoHIDE.winUtil.setRedraw(false, false);\n' +
+ ' $2\n' +
+ ' gBrowser.treeStyleTab.autoHide.extraYOffset = 0;\n' +
+ ' window.setTimeout(function() {\n' +
+ ' gBrowser.treeStyleTab.autoHide.redrawContentArea();\n' +
+ ' if (autoHIDE.winUtil)\n' +
+ ' autoHIDE.winUtil.setRedraw(true, false);\n' +
+ ' }, 0);'
+ ));
+ }
+ }
+
+
+ // Google Toolbar Sidewiki
+ if ('sidewikiWindowHandler' in window &&
+ window.sidewikiWindowHandler &&
+ sidewikiWindowHandler.barsContainer_ &&
+ sidewikiWindowHandler.barsContainer_.geometry_ &&
+ sidewikiWindowHandler.barsContainer_.geometry_.__proto__.getWindowSizeForDrawers &&
+ TreeStyleTabUtils.getTreePref('compatibility.GoogleToolbar.Sidewiki')) {
+ let func = sidewikiWindowHandler.barsContainer_.geometry_.__proto__.getWindowSizeForDrawers.toSource();
+ if (func.indexOf('treeStyleTab') < 0) {
+ eval('sidewikiWindowHandler.barsContainer_.geometry_.__proto__.getWindowSizeForDrawers = '+func.replace(
+ 'return {',
+ ' if ("treeStyleTab" in this.topLevelDocument_.getElementById("content")) {\n' +
+ ' let b = this.topLevelDocument_.getElementById("content");\n' +
+ ' let box = b.mPanelContainer.boxObject;\n' +
+ ' return {\n' +
+ ' height : box.height,\n' +
+ ' width : box.width,\n' +
+ ' top : box.y,\n' +
+ ' left : box.x,\n' +
+ ' right : this.topLevelWindow_.innerWidth - box.x - box.width,\n' +
+ ' tabBoxHeight : 0\n' +
+ ' };\n' +
+ ' }\n' +
+ '$&'
+ ));
+ }
+ }
+
+
+ // Smoothly Close Tabs
+ // https://addons.mozilla.org/firefox/addon/71410
+ if ('SMOOTHLYCLOSETABS' in window &&
+ TreeStyleTabUtils.getTreePref('compatibility.SmoothlyCloseTabs')) {
+ let replaceScrollProps = function(aString) {
+ return aString.replace(
+ /\.scrollWidth/g,
+ '[scrollProp]'
+ ).replace(
+ /"width"/g,
+ 'sizeProp'
+ ).replace(
+ /\.maxWidth/g,
+ '[maxSizeProp]'
+ ).replace(
+ '{',
+ '{\n' +
+ ' var scrollProp = gBrowser.treeStyleTab.isVertical ? "scrollHeight" : "scrollWidth" ;\n' +
+ ' var sizeProp = gBrowser.treeStyleTab.isVertical ? "height" : "width" ;\n' +
+ ' var maxSizeProp = gBrowser.treeStyleTab.isVertical ? "maxHeight" : "maxWidth" ;'
+ )
+ }
+ eval('SMOOTHLYCLOSETABS.shrinkTab = '+
+ replaceScrollProps(SMOOTHLYCLOSETABS.shrinkTab.toSource())
+ );
+ eval('SMOOTHLYCLOSETABS.shrinkTabIcon = '+
+ replaceScrollProps(SMOOTHLYCLOSETABS.shrinkTabIcon.toSource())
+ );
+ }
+
+ // Super Tab Mode
+ // https://addons.mozilla.org/firefox/addon/13288
+ if ('stmM' in window &&
+ TreeStyleTabUtils.getTreePref('compatibility.STM')) {
+ var observer = {
+ domain : 'extensions.stm.',
+ observe : function(aSubject, aTopic, aData)
+ {
+ switch (aData)
+ {
+ case 'extensions.stm.tabBarMultiRows':
+ case 'extensions.stm.tabBarPosition':
+ if (
+ TreeStyleTabUtils.prefs.getPref('extensions.stm.tabBarMultiRows') &&
+ TreeStyleTabUtils.prefs.getPref('extensions.stm.tabBarPosition') == 0
+ ) {
+ TreeStyleTabUtils.prefs.setPref('extensions.stm.tabBarMultiRows.override', false);
+ }
+ return;
+
+ case 'extensions.stm.newTabBtnPos':
+ if (TreeStyleTabUtils.prefs.getPref(aData) == 0)
+ document.documentElement.removeAttribute(TreeStyleTabService.kHIDE_NEWTAB);
+ else
+ document.documentElement.setAttribute(TreeStyleTabService.kHIDE_NEWTAB, true);
+ return;
+ }
+ }
+ };
+ observer.observe(null, null, 'extensions.stm.tabBarMultiRows');
+ observer.observe(null, null, 'extensions.stm.newTabBtnPos');
+ TreeStyleTabUtils.prefs.addPrefListener(observer);
+ document.addEventListener('unload', function onUnload() {
+ document.removeEventListener('unload', onUnload, false);
+ TreeStyleTabUtils.prefs.removePrefListener(observer);
+ }, false);
+
+ let warnPref = 'extensions.treestyletab.compatibility.STM.warnForNewTabPosition';
+ if (
+ TreeStyleTabUtils.prefs.getPref(warnPref) &&
+ TreeStyleTabUtils.prefs.getPref('extensions.stm.newTabPosition') != 0
+ ) {
+ let checked = { value : false };
+ if (Services.prompt.confirmEx(
+ null,
+ TreeStyleTabUtils.treeBundle.getString('compatibility_STM_warning_title'),
+ TreeStyleTabUtils.treeBundle.getString('compatibility_STM_warning_text'),
+ (Services.prompt.BUTTON_TITLE_IS_STRING * Services.prompt.BUTTON_POS_0) +
+ (Services.prompt.BUTTON_TITLE_IS_STRING * Services.prompt.BUTTON_POS_1),
+ TreeStyleTabUtils.treeBundle.getString('compatibility_STM_warning_use_TST'),
+ TreeStyleTabUtils.treeBundle.getString('compatibility_STM_warning_use_STM'),
+ null,
+ TreeStyleTabUtils.treeBundle.getString('compatibility_STM_warning_never'),
+ checked
+ ) == 0) {
+ TreeStyleTabUtils.prefs.setPref('extensions.stm.newTabPosition', 0);
+ }
+ if (checked.value)
+ TreeStyleTabUtils.prefs.setPref(warnPref, false);
+ }
+
+ sv.registerTabFocusAllowance(function(aTabBrowser) {
+ return TreeStyleTabUtils.prefs.getPref('extensions.stm.focusAfterCloseTab') == 0;
+ });
+ }
+
+ // Tab Utilities
+ // https://addons.mozilla.org/firefox/addon/59961
+ if ('tabutils' in window &&
+ TreeStyleTabUtils.getTreePref('compatibility.TabUtilities')) {
+ TreeStyleTabService.registerTabFocusAllowance(function(aTabBrowser) {
+ return TreeStyleTabUtils.prefs.getPref('extensions.tabutils.selectOnClose') == 0;
+ });
+ }
+
+ // Remove New Tab Button
+ // https://addons.mozilla.org/firefox/addon/10535
+ if (TreeStyleTabUtils.getTreePref('compatibility.RemoveNewTabButton')) {
+ sv.extensions.isAvailable('remove-new-tab-button@forerunnerdesigns.com', { ok : function() {
+ document.documentElement.setAttribute(TreeStyleTabService.kHIDE_NEWTAB, true);
+ }});
+ }
+
+ // IE Tab Plus
+ // https://addons.mozilla.org/firefox/addon/10909/
+ if ('IeTab' in window &&
+ IeTab.prototype &&
+ TreeStyleTabUtils.getTreePref('compatibility.IETabPlus')) {
+ if (IeTab.prototype.switchTabEngine)
+ eval('IeTab.prototype.switchTabEngine = '+
+ IeTab.prototype.switchTabEngine.toSource().replace(
+ 'var newTab = ',
+ 'TreeStyleTabService.readyToOpenChildTab(); $&'
+ )
+ );
+
+ if (IeTab.prototype.addIeTab)
+ eval('IeTab.prototype.addIeTab = '+
+ IeTab.prototype.addIeTab.toSource().replace(
+ 'var newTab = ',
+ 'TreeStyleTabService.readyToOpenChildTab(); $&'
+ )
+ );
+ }
+
+ // Locationbar2
+ // https://addons.mozilla.org/firefox/addon/locationbar²/
+ if ('lb2_alternateStyles' in window &&
+ TreeStyleTabUtils.getTreePref('compatibility.Locationbar2')) {
+ let listening = false;
+ let listener = function(aEvent) {
+ switch (aEvent.type)
+ {
+ case 'unload':
+ document.removeEventListener('unload', listener, false);
+ document.removeEventListener('beforecustomization', listener, true);
+ document.removeEventListener('aftercustomization', listener, false);
+ case 'beforecustomization':
+ if (gURLBar && listening)
+ gURLBar.removeEventListener('click', listener, true);
+ listening = false;
+ return;
+
+ case 'aftercustomization':
+ if (gURLBar && !listening) {
+ gURLBar.addEventListener('click', listener, true);
+ listening = true;
+ }
+ return;
+
+ case 'click':
+ if (sv.evaluateXPath(
+ 'ancestor-or-self::*['
+ +'contains(concat(" ", normalize-space(@class), " "), " textbox-presentation-segment ")'
+ +']',
+ aEvent.originalTarget,
+ Ci.nsIDOMXPathResult.BOOLEAN_TYPE
+ ).booleanValue)
+ sv.readyToOpenChildTabNow(gBrowser.selectedTab);
+ return;
+ }
+ };
+ document.addEventListener('unload', listener, false);
+ document.addEventListener('beforecustomization', listener, true);
+ document.addEventListener('aftercustomization', listener, false);
+ if (gURLBar && !listening) {
+ gURLBar.addEventListener('click', listener, true);
+ listening = true;
+ }
+ }
+
+ // InstaClick
+ // https://addons.mozilla.org/firefox/addon/instaclick/
+ if ('instaclick' in window &&
+ 'contentAreaClick2' in window.instaclick &&
+ TreeStyleTabUtils.getTreePref('compatibility.InstaClick')) {
+ eval('instaclick.contentAreaClick2 = '+
+ instaclick.contentAreaClick2.toSource().replace(
+ 'gBrowser.loadOneTab(',
+ 'TreeStyleTabService.readyToOpenChildTab(); $&'
+ )
+ );
+ }
+
+ // Duplicate This Tab
+ // https://addons.mozilla.org/firefox/addon/duplicate-this-tab/
+ if ('duplicatethistab' in window &&
+ 'openLinkWithHistory' in window.duplicatethistab &&
+ TreeStyleTabUtils.getTreePref('compatibility.DuplicateThisTab')) {
+ eval('duplicatethistab.openLinkWithHistory = '+
+ duplicatethistab.openLinkWithHistory.toSource().replace(
+ 'var newTab = ',
+ 'TreeStyleTabService.readyToOpenChildTab(); $&'
+ )
+ );
+ }
+
+ // Context Search
+ // http://www.cusser.net/extensions/contextsearch/
+ if ('contextsearch' in window &&
+ 'search' in window.contextsearch &&
+ TreeStyleTabUtils.getTreePref('compatibility.ContextSearch')) {
+ eval('contextsearch.search = '+
+ contextsearch.search.toSource().replace(
+ 'var newTab = ',
+ 'TreeStyleTabService.readyToOpenChildTab(); $&'
+ )
+ );
+ }
+
+ // Tile Tabs
+ // https://addons.mozilla.org/firefox/addon/tile-tabs/
+ if ('tileTabs' in window &&
+ TreeStyleTabUtils.getTreePref('compatibility.TileTabs')) {
+ if ('allocateTab' in window.tileTabs)
+ eval('tileTabs.allocateTab = '+
+ tileTabs.allocateTab.toSource().replace(
+ /(tab = gBrowser.addTab)/g,
+ 'TreeStyleTabService.readyToOpenNextSiblingTabNow(); $1'
+ )
+ );
+ if ('doClickBrowser' in window.tileTabs)
+ eval('tileTabs.doClickBrowser = '+
+ tileTabs.doClickBrowser.toSource().replace(
+ /(newTab = gBrowser.loadOneTab)/g,
+ 'TreeStyleTabService.readyToOpenNextSiblingTabNow(); $1'
+ )
+ );
+ if ('doDropBrowserTile' in window.tileTabs)
+ eval('tileTabs.doDropBrowserTile = '+
+ tileTabs.doDropBrowserTile.toSource().replace(
+ /(tab = gBrowser.loadOneTab)/g,
+ 'TreeStyleTabService.readyToOpenNextSiblingTabNow(), $1'
+ )
+ );
+ if ('menuActions' in window.tileTabs)
+ eval('tileTabs.menuActions = '+
+ tileTabs.menuActions.toSource().replace(
+ /(tab = gBrowser.loadOneTab)/g,
+ 'TreeStyleTabService.readyToOpenNextSiblingTabNow(), $1'
+ )
+ );
+ if ('applyLayoutString' in window.tileTabs)
+ eval('tileTabs.applyLayoutString = '+
+ tileTabs.applyLayoutString.toSource().replace(
+ /(tab = gBrowser.loadOneTab)/g,
+ 'TreeStyleTabService.readyToOpenNextSiblingTabNow(), $1'
+ )
+ );
+ }
+
+ window.setTimeout(function(aSelf) {
+ aSelf.overrideExtensionsDelayed();
+ }, 0, this);
+};
+
+
+TreeStyleTabWindowHelper.overrideExtensionsDelayed = function TSTWH_overrideExtensionsDelayed() {
+ var sv = this.service;
+
+ // Tab Mix Plus
+ if (TreeStyleTabUtils.getTreePref('compatibility.TMP') &&
+ 'TabmixTabbar' in window) {
+ // correct broken appearance of the first tab
+ var t = gBrowser.treeStyleTab.getFirstTab(gBrowser);
+ gBrowser.treeStyleTab.initTabAttributes(t);
+ gBrowser.treeStyleTab.initTabContentsOrder(t);
+
+ eval('gBrowser.openInverseLink = '+
+ gBrowser.openInverseLink.toSource().replace(
+ /(var newTab)/,
+ 'TreeStyleTabService.readyToOpenChildTab(aTab); $1'
+ )
+ );
+
+ eval('gBrowser.TMP_openTabNext = '+
+ gBrowser.TMP_openTabNext.toSource().replace(
+ 'this.mCurrentTab._tPos + this.tabContainer.nextTab',
+ ' (function() {\n' +
+ ' var tabs = this.treeStyleTab.getDescendantTabs(this.mCurrentTab);\n' +
+ ' if (tabs.length) {\n' +
+ ' var index = TreeStyleTabUtils.prefs.getPref("extensions.tabmix.openTabNextInverse") ?\n' +
+ ' tabs[tabs.length - 1]._tPos :\n' +
+ ' this.mCurrentTab._tPos ;\n' +
+ ' if (index < aTab._tPos) index++;\n' +
+ ' return index;\n' +
+ ' }\n' +
+ ' else {\n' +
+ ' return ($&);\n' +
+ ' }\n' +
+ ' }).call(this)'
+ )
+ );
+
+ gBrowser.treeStyleTab.internallyTabMovingCount--;
+ }
+
+ // Multi Links
+ // https://addons.mozilla.org/firefox/addon/13494
+ if ('MultiLinks_Wrapper' in window &&
+ 'LinksManager' in MultiLinks_Wrapper &&
+ 'OpenInNewTabs' in MultiLinks_Wrapper.LinksManager &&
+ TreeStyleTabUtils.getTreePref('compatibility.MultiLinks')) {
+ eval('MultiLinks_Wrapper.LinksManager.OpenInNewTabs = '+
+ MultiLinks_Wrapper.LinksManager.OpenInNewTabs.toSource().replace(
+ '{',
+ '{\n' +
+ ' if (!TreeStyleTabService.checkToOpenChildTab(getBrowser()))\n' +
+ ' TreeStyleTabService.readyToOpenChildTab(getBrowser(), true);'
+ ).replace(
+ /(\}\)?)$/,
+ ' if (TreeStyleTabService.checkToOpenChildTab(getBrowser()))\n' +
+ ' TreeStyleTabService.stopToOpenChildTab(getBrowser());\n' +
+ '$1'
+ )
+ );
+ }
+
+ // DomainTab
+ // https://addons.mozilla.org/firefox/addon/13906/
+ if ('domaintab' in window &&
+ 'TMP_howToOpen' in domaintab &&
+ TreeStyleTabUtils.getTreePref('compatibility.DomainTab')) {
+ eval('domaintab.TMP_howToOpen = '+
+ domaintab.TMP_howToOpen.toSource().replace(
+ /(domaintab.DT_openNewTabWith\()/g,
+ 'TreeStyleTabService.readyToOpenChildTab(); $1'
+ )
+ );
+ }
+
+ // Personal Titlebar
+ // https://addons.mozilla.org/irefox/addon/personal-titlebar/
+ if (document.getElementById('personal-titlebar') &&
+ TreeStyleTabUtils.getTreePref('compatibility.PersonalTitlebar')) {
+ let titlebar = document.getElementById('titlebar');
+ let personalTitlebar = document.getElementById('personal-titlebar');
+ let listener = {
+ handleEvent : function(aEvent)
+ {
+ switch (aEvent.type)
+ {
+ case 'beforecustomization':
+ titlebar.removeEventListener('DOMAttrModified', this, true);
+ gBrowser.treeStyleTab.destroyTabStrip(personalTitlebar);
+ break;
+
+ case 'aftercustomization':
+ titlebar.addEventListener('DOMAttrModified', this, true);
+ break;
+
+ case 'DOMAttrModified':
+ if (
+ aEvent.attrName == 'hidden' &&
+ gBrowser.tabContainer.parentNode.id == (aEvent.newValue == 'true' ? 'toolbar-menubar' : 'personal-titlebar' )
+ ) {
+ TreeStyleTabService.stopRendering();
+ gBrowser.treeStyleTab.syncDestroyTabbar();
+ window.setTimeout(function() {
+ gBrowser.treeStyleTab.syncReinitTabbar();
+ TreeStyleTabService.startRendering();
+ }, 0);
+ }
+ break;
+
+ case 'unload':
+ titlebar.removeEventListener('DOMAttrModified', this, true);
+ document.removeEventListener('beforecustomization', this, false);
+ document.removeEventListener('aftercustomization', this, false);
+ document.removeEventListener('unload', this, false);
+ personalTitlebar = null;
+ break;
+ }
+ }
+ };
+ document.addEventListener('beforecustomization', listener, false);
+ document.addEventListener('aftercustomization', listener, false);
+ document.addEventListener('unload', listener, false);
+ titlebar.addEventListener('DOMAttrModified', listener, true);
+ }
+
+ // TotalToolbar
+ // http://totaltoolbar.mozdev.org/
+ let (menu = document.getElementById('tt-toolbar-properties') &&
+ TreeStyleTabUtils.getTreePref('compatibility.TotalToolbar')) {
+ if (menu) {
+ let tabbarToolboxes = ['tt-toolbox-tabright', 'tt-toolbox-tableft']
+ .map(document.getElementById, document)
+ .filter(function(aToolbox) { return aToolbox; });
+ let listener = {
+ handleEvent : function(aEvent)
+ {
+ var sv = TreeStyleTabService;
+ switch (aEvent.type)
+ {
+ case 'command':
+ gBrowser.treeStyleTab.updateFloatingTabbar(sv.kTABBAR_UPDATE_BY_WINDOW_RESIZE);
+ break;
+
+ case 'beforecustomization':
+ for (let i = 0, maxi = tabbarToolboxes.length; i < maxi; i++)
+ {
+ tabbarToolboxes[i].removeAttribute('collapsed');
+ }
+ break;
+
+ case 'aftercustomization':
+ for (let i = 0, maxi = tabbarToolboxes.length; i < maxi; i++)
+ {
+ let toolbox = tabbarToolboxes[i];
+ if (!toolbox.firstChild.hasChildNodes())
+ toolbox.setAttribute('collapsed', true);
+ }
+ break;
+
+ case 'unload':
+ menu.removeEventListener('command', this, true);
+ document.removeEventListener('beforecustomization', listener, true);
+ document.removeEventListener('aftercustomization', listener, false);
+ document.removeEventListener('unload', this, false);
+ menu = null;
+ break;
+ }
+ }
+ };
+ menu.addEventListener('command', listener, false);
+ document.addEventListener('beforecustomization', listener, true);
+ document.addEventListener('aftercustomization', listener, false);
+ document.addEventListener('unload', listener, false);
+ for (let i = 0, maxi = tabbarToolboxes.length; i < maxi; i++)
+ {
+ let toolbox = tabbarToolboxes[i];
+ if (!toolbox.firstChild.hasChildNodes())
+ toolbox.setAttribute('collapsed', true);
+ }
+ }
+ }
+
+ // Tab Control
+ // https://addons.mozilla.org/firefox/addon/tab-control/
+ if (
+ TreeStyleTabUtils.getTreePref('compatibility.TabControl') &&
+ 'gTabControl' in window
+ ) {
+ let listener = {
+ handleEvent : function(aEvent)
+ {
+ switch (aEvent.type)
+ {
+ case sv.kEVENT_TYPE_FOCUS_NEXT_TAB:
+ if (TreeStyleTabUtils.prefs.getPref('tabcontrol.focusLeftOnClose'))
+ aEvent.preventDefault();
+ break;
+
+ case 'unload':
+ document.removeEventListener(sv.kEVENT_TYPE_FOCUS_NEXT_TAB, this, false);
+ break;
+ }
+ }
+ };
+ document.addEventListener(sv.kEVENT_TYPE_FOCUS_NEXT_TAB, listener, false);
+ document.addEventListener('unload', listener, false);
+ }
+
+ // Firefox Sync (Weave)
+ // http://www.mozilla.com/en-US/firefox/sync/
+ if (
+ (
+ 'gFxWeaveGlue' in window || // addon
+ 'gSyncUI' in window // Firefox 4 built-in
+ ) &&
+ TreeStyleTabUtils.getTreePref('compatibility.FirefoxSync')
+ ) {
+ let ns = {};
+ try { // 1.4
+ Components.utils.import('resource://services-sync/service.js', ns);
+ }
+ catch(e) { // 1.3
+ Components.utils.import('resource://weave/service.js', ns);
+ }
+ let listener = {
+ handleEvent : function(aEvent)
+ {
+ switch (aEvent.type)
+ {
+ case 'TabOpen':
+ let tab = aEvent.originalTarget
+ let b = TreeStyleTabService.getTabBrowserFromChild(tab);
+ if (b.selectedTab.linkedBrowser.currentURI.spec != 'about:sync-tabs')
+ return;
+
+ let service = ns.Service || ns.Weave /* old name */;
+ let manager = service.engineManager || service.Engines /* old name */;
+ let engine = manager.get('tabs');
+
+ let uri = tab.getAttribute('label');
+ if (engine.locallyOpenTabMatchesURL(uri))
+ return;
+
+ for (let [guid, client] in Iterator(engine.getAllClients()))
+ {
+ if (client.tabs.some(function({ urlHistory }) {
+ return urlHistory[0] == uri;
+ })) {
+ let parent = b.selectedTab;
+ window.setTimeout(function() {
+ if (tab.parentNode && !b.treeStyleTab.getParentTab(tab))
+ b.treeStyleTab.attachTabTo(tab, parent);
+ }, 0);
+ return;
+ }
+ }
+ return;
+
+ case 'unload':
+ document.removeEventListener('TabOpen', this, true);
+ document.removeEventListener('unload', this, false);
+ return;
+ }
+ }
+ };
+ document.addEventListener('TabOpen', listener, true);
+ document.addEventListener('unload', listener, false);
+ }
+
+};
diff --git a/modules/autoHide.js b/modules/autoHide.js
index 3889c1bc..edd858b7 100644
--- a/modules/autoHide.js
+++ b/modules/autoHide.js
@@ -1,1404 +1,1404 @@
-/* ***** 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 YUKI "Piro" Hiroshi.
- * Portions created by the Initial Developer are Copyright (C) 2010-2014
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s): YUKI "Piro" Hiroshi
- * Tetsuharu OHZEKI
- *
- * 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 ******/
-
-const EXPORTED_SYMBOLS = ['AutoHideBrowser', 'AutoHideWindow'];
-
-const DEBUG = false;
-
-const Cc = Components.classes;
-const Ci = Components.interfaces;
-const Cu = Components.utils;
-
-Cu.import('resource://gre/modules/XPCOMUtils.jsm');
-Cu.import('resource://gre/modules/Services.jsm');
-
-XPCOMUtils.defineLazyModuleGetter(this, 'utils', 'resource://treestyletab-modules/utils.js', 'TreeStyleTabUtils');
-
-XPCOMUtils.defineLazyGetter(this, 'window', function() {
- Cu.import('resource://treestyletab-modules/lib/namespace.jsm');
- return getNamespaceFor('piro.sakura.ne.jp');
-});
-XPCOMUtils.defineLazyGetter(this, 'prefs', function() {
- Cu.import('resource://treestyletab-modules/lib/prefs.js');
- return window['piro.sakura.ne.jp'].prefs;
-});
-
-
-function AutoHideBrowser(aTabBrowser)
-{
- this.init(aTabBrowser);
-}
-AutoHideBrowser.prototype = {
-
- kMODE : 'treestyletab-tabbar-autohide-mode',
- kMODE_DISABLED : 0,
- kMODE_HIDE : 1,
- kMODE_SHRINK : 2,
-
- kAUTOHIDE : 'treestyletab-tabbar-autohide',
-
- kSTATE : 'treestyletab-tabbar-autohide-state',
- kSTATE_HIDDEN : 'hidden',
- kSTATE_EXPANDED : 'expanded',
- kSTATE_SHRUNKEN : 'shrunken',
-
- kSHOWN_BY_UNKNOWN : 0,
- kSHOWN_BY_SHORTCUT : 1 << 0,
- kSHOWN_BY_MOUSEMOVE : 1 << 1,
- kSHOWN_BY_FEEDBACK : 1 << 2,
- kSHOWN_BY_ANY_REASON : (1 << 0) | (1 << 1) | (1 << 2),
- kSHOWHIDE_BY_START : 1 << 3,
- kSHOWHIDE_BY_END : 1 << 4,
- kSHOWHIDE_BY_POSITION_CHANGE : 1 << 5,
- kSHOWHIDE_BY_RESIZE : 1 << 6,
- kSHOWHIDE_BY_API : 1 << 8,
- kHIDDEN_BY_CLICK : 1 << 7,
-
- get mode() /* PUBLIC API */
- {
- var mode = this.browser.getAttribute(this.kMODE);
- return mode ? parseInt(mode) : this.kMODE_DISABLED ;
- },
- set mode(aValue)
- {
- this.browser.setAttribute(this.kMODE, aValue);
- return aValue;
- },
-
- getMode : function AHB_getMode(aTabBrowser)
- {
- var b = aTabBrowser || this.browser;
- var mode = b.getAttribute(this.kMODE);
- return mode ? parseInt(mode) : this.kMODE_DISABLED ;
- },
- getModeForNormal : function AHB_getModeForNormal(aTabBrowser)
- {
- var b = aTabBrowser || this.browser;
- return parseInt(b.getAttribute(this.kMODE+'-normal') || utils.getTreePref('tabbar.autoHide.mode'));
- },
- getModeForFullScreen : function AHB_getModeForFullScreen(aTabBrowser)
- {
- var b = aTabBrowser || this.browser;
- return parseInt(b.getAttribute(this.kMODE+'-fullscreen') || utils.getTreePref('tabbar.autoHide.mode.fullscreen'));
- },
-
- get state()
- {
- return this.browser.getAttribute(this.kSTATE) || this.kSTATE_EXPANDED;
- },
- get expanded()
- {
- return this.state == this.kSTATE_EXPANDED;
- },
- get shrunken()
- {
- return this.state == this.kSTATE_SHRUNKEN;
- },
- get hidden()
- {
- return this.state == this.kSTATE_HIDDEN;
- },
-
- updateMode : function AHB_updateMode()
- {
- this.end();
- // update internal property after the appearance of the tab bar is updated.
- var w = this.window;
- w.setTimeout(function(aSelf) {
- aSelf.mode = (w.fullScreen && prefs.getPref('browser.fullscreen.autohide')) ?
- aSelf.getModeForFullScreen() :
- aSelf.getModeForNormal() ;
- if (aSelf.mode != aSelf.kMODE_DISABLED)
- aSelf.start();
- }, 0, this);
- },
-
- togglerSize : 0,
- sensitiveArea : 7,
- contentAreaScreenEnabled : true,
-
- closeButtonsMode : -1,
- CLOSE_BUTTONS_ONLY_ON_CURRENT_TAB : 0,
- CLOSE_BUTTONS_ON_ALL_TABS : 1,
- CLOSE_BUTTONS_DISABLED : 2,
- CLOSE_BUTTONS_ON_TABBAR : 3,
-
- get XOffset()
- {
- var sv = this.treeStyleTab;
- switch (this.mode)
- {
- case this.kMODE_DISABLED:
- return 0;
-
- case this.kMODE_HIDE:
- let offset = this.width + this.splitterWidth;
- let resizer = this.resizer;
- if (sv.position == 'left') {
- offset += this.togglerSize;
- if (resizer)
- offset += resizer.boxObject.width;
- }
- else if (sv.position == 'right') {
- offset -= this.togglerSize;
- if (resizer)
- offset -= resizer.boxObject.width;
- }
- return offset;
-
- default:
- case this.kMODE_SHRINK:
- return utils.getTreePref('tabbar.width')
- - utils.getTreePref('tabbar.shrunkenWidth');
- }
- },
- get YOffset()
- {
- return this.height;
- },
- extraXOffset : 0,
- extraYOffset : 0,
-
- get currentXOffset()
- {
- var sv = this.treeStyleTab;
- return (
- sv.position == 'left' &&
- this.mode != this.kMODE_DISABLED &&
- this.expanded
- ) ? this.XOffset : 0 ;
- },
- get currentYOffset()
- {
- var sv = this.treeStyleTab;
- return (
- sv.position == 'top' &&
- this.mode != this.kMODE_DISABLED &&
- this.expanded
- ) ? this.YOffset : 0 ;
- },
-
- get screen()
- {
- return this.document.getElementById('treestyletab-autohide-content-area-screen');
- },
- get resizer()
- {
- return this.document.getElementById('treestyletab-tabbar-resizer-splitter');
- },
-
- start : function AHB_start(aReason)
- {
- if (this.enabled) return;
- this.enabled = true;
- aReason = aReason || 0;
-
- var sv = this.treeStyleTab;
- var b = this.browser;
- var w = this.window;
-
- this.screen.hidePopup();
-
- sv.setTabbrowserAttribute(this.kSTATE, this.kSTATE_EXPANDED);
-
- if (!(aReason & this.kSHOWHIDE_BY_API)) {
- b.addEventListener('mousedown', this, true);
- b.addEventListener('mouseup', this, true);
- b.addEventListener('dragover', this, true);
- b.addEventListener('dragleave', this, true);
- sv.tabStrip.addEventListener('mousedown', this, true);
- sv.tabStrip.addEventListener('mouseup', this, true);
- if (this.shouldListenMouseMove)
- this.startListenMouseMove();
- if (b == w.gBrowser && sv.shouldListenKeyEventsForAutoHide)
- w.TreeStyleTabService.startListenKeyEventsFor(sv.LISTEN_FOR_AUTOHIDE);
- this.userActionListening = true;
- }
- w.addEventListener(sv.kEVENT_TYPE_PRINT_PREVIEW_ENTERED, this, false);
- w.addEventListener(sv.kEVENT_TYPE_PRINT_PREVIEW_EXITED, this, false);
-
- this.updateTransparency();
-
- this.showHideInternal(this.kSHOWHIDE_BY_START | aReason);
-
- b.treeStyleTab.fixTooNarrowTabbar();
- },
-
- end : function AHB_end()
- {
- if (!this.enabled) return;
- this.enabled = false;
-
- var sv = this.treeStyleTab;
- var b = this.browser;
- var w = this.window;
-
- this.show(this.kSHOWHIDE_BY_END);
-
- this.screen.hidePopup();
-
- if (this.userActionListening) {
- b.removeEventListener('mousedown', this, true);
- b.removeEventListener('mouseup', this, true);
- b.removeEventListener('dragover', this, true);
- b.removeEventListener('dragleave', this, true);
- sv.tabStrip.removeEventListener('mousedown', this, true);
- sv.tabStrip.removeEventListener('mouseup', this, true);
- this.endListenMouseMove();
- if (b == w.gBrowser)
- w.TreeStyleTabService.endListenKeyEventsFor(sv.LISTEN_FOR_AUTOHIDE);
- this.userActionListening = false;
- }
- w.removeEventListener(sv.kEVENT_TYPE_PRINT_PREVIEW_ENTERED, this, false);
- w.removeEventListener(sv.kEVENT_TYPE_PRINT_PREVIEW_EXITED, this, false);
-
- this.updateTransparency();
-
- sv.removeTabbrowserAttribute(this.kAUTOHIDE);
- sv.removeTabbrowserAttribute(this.kSTATE);
-
- if (sv.isVertical)
- sv.setTabStripAttribute('width', this.widthFromMode);
- },
-
- // fullscreen
-
- startForFullScreen : function AHB_startForFullScreen()
- {
- this.mode = this.getMode();
- this.end();
- this.mode = prefs.getPref('browser.fullscreen.autohide') ?
- this.getModeForFullScreen() :
- this.kMODE_DISABLED ;
- if (this.mode != this.kMODE_DISABLED) {
- this.start();
- this.treeStyleTab.removeTabbrowserAttribute('moz-collapsed');
- }
- },
-
- endForFullScreen : function AHB_endForFullScreen()
- {
- this.mode = this.getModeForFullScreen();
- this.end();
- this.mode = utils.getTreePref('tabbar.autoHide.mode');
- this.treeStyleTab.checkTabsIndentOverflow();
- if (this.mode != this.kMODE_DISABLED)
- this.start();
- },
-
- // mousemove
-
- startListenMouseMove : function AHB_startListenMouseMove()
- {
- if (this.mouseMoveListening) return;
-
- this.browser.addEventListener('mousemove', this, true);
- this.screen.addEventListener('mousemove', this, true);
- this.treeStyleTab.tabStrip.addEventListener('mousemove', this, true);
-
- this.mouseMoveListening = true;
- },
-
- endListenMouseMove : function AHB_endListenMouseMove()
- {
- if (!this.mouseMoveListening) return;
-
- this.browser.removeEventListener('mousemove', this, true);
- this.screen.removeEventListener('mousemove', this, true);
- this.treeStyleTab.tabStrip.removeEventListener('mousemove', this, true);
-
- this.mouseMoveListening = false;
- },
-
- get shouldListenMouseMove()
- {
- return utils.getTreePref('tabbar.autoShow.mousemove');
- },
-
- get shouldListenKeyEventsForAutoHide()
- {
- return utils.getTreePref('tabbar.autoShow.accelKeyDown') ||
- utils.getTreePref('tabbar.autoShow.tabSwitch');
- },
-
- showHideOnMouseMove : function AHB_showHideOnMouseMove(aEvent)
- {
- var position = this.getMousePosition(aEvent);
- if (position == this.MOUSE_POSITION_UNKNOWN)
- return;
-
- this.cancelShowHideOnMouseMove();
- this.showHideContentsAreaScreen();
-
- var sv = this.treeStyleTab;
- var b = this.browser;
- var w = this.window;
-
- var shouldShow = position & this.MOUSE_POSITION_SENSITIVE;
- if (this.expanded) { // currently shown, let's hide it.
- if (shouldShow) {
- this.show(this.kSHOWN_BY_MOUSEMOVE);
- this.cancelDelayedShowForShortcut();
- }
- else if (
- !shouldShow &&
- utils.getTreePref('tabbar.autoShow.mousemove')
- ) {
- this.showHideOnMouseMoveTimer = w.setTimeout(
- function(aSelf) {
- aSelf.cancelDelayedShowForShortcut();
- aSelf.hide(aSelf.kSHOWN_BY_MOUSEMOVE);
- },
- utils.getTreePref('tabbar.autoHide.delay'),
- this
- );
- }
- }
- else if (shouldShow) { // currently shown, let's show it.
- this.showHideOnMouseMoveTimer = w.setTimeout(
- function(aSelf) {
- aSelf.cancelDelayedShowForShortcut();
- aSelf.show(aSelf.kSHOWN_BY_MOUSEMOVE);
- },
- utils.getTreePref('tabbar.autoHide.delay'),
- this
- );
- }
-
- b = null;
- },
- getMousePosition : function AHB_getMousePosition(aEvent)
- {
- var w = this.window;
- if ('gestureInProgress' in w && w.gestureInProgress)
- return this.MOUSE_POSITION_UNKNOWN;
-
- var sv = this.treeStyleTab;
- var b = this.browser;
- var pos = sv.position;
- var box = this.getContentsAreaBox();
-
- var sensitiveArea = this.sensitiveArea;
- if (this.shrunken) {
- let clickable;
- let resizable = !sv.fixed;
- if (resizable &
- this.widthFromMode > 24 &&
- (clickable = this.getNearestClickableBox(aEvent))) {
- /* For resizing of shrunken tab bar and clicking closeboxes,
- we have to shrink sensitive area. */
- sensitiveArea = -(clickable.width + clickable.padding);
- }
- else if (resizable && this.resizer)
- sensitiveArea = -this.resizer.boxObject.width;
- else
- sensitiveArea = 0;
- }
-
- if (
- pos == 'left' ?
- (aEvent.screenX > box.screenX + sensitiveArea) :
- pos == 'right' ?
- (aEvent.screenX < box.screenX + box.width - sensitiveArea) :
- pos == 'bottom' ?
- (aEvent.screenY < box.screenY + box.height - sensitiveArea) :
- (aEvent.screenY > box.screenY + sensitiveArea)
- ) {
- return this.MOUSE_POSITION_OUTSIDE;
- }
-
- if (
- pos == 'left' ?
- (aEvent.screenX <= box.screenX - sensitiveArea) :
- pos == 'right' ?
- (aEvent.screenX >= box.screenX + box.width + sensitiveArea) :
- pos == 'bottom' ?
- (aEvent.screenY >= box.screenY + box.height + sensitiveArea) :
- (aEvent.screenY <= box.screenY - sensitiveArea)
- ) {
- return this.MOUSE_POSITION_INSIDE;
- }
-
- return this.MOUSE_POSITION_NEAR;
- },
- getContentsAreaBox : function AHB_getContentsAreaBox()
- {
- var sv = this.treeStyleTab;
- var b = this.browser;
- var box = b.mCurrentBrowser.boxObject;
- var xoffset = (this.shrunken || this.hidden) ? 0 : this.XOffset ;
- box = {
- screenX : box.screenX + (sv.position == 'left' ? xoffset : 0 ),
- screenY : box.screenY,
- width : box.width - xoffset,
- height : box.height
- };
- return box;
- },
- MOUSE_POSITION_UNKNOWN : 0,
- MOUSE_POSITION_OUTSIDE : (1 << 0),
- MOUSE_POSITION_INSIDE : (1 << 1),
- MOUSE_POSITION_NEAR : (1 << 2),
- MOUSE_POSITION_SENSITIVE : (1 << 1) | (1 << 2),
- getNearestClickableBox : function AHB_getNearestClickableBox(aEvent)
- {
- var sv = this.treeStyleTab;
- var tab = sv.getTabFromCoordinates(aEvent);
- if (!tab)
- return null;
-
- var position = sv.invertedScreenPositionProp;
- var size = sv.invertedSizeProp;
- var coordinate = aEvent[sv.invertedScreenPositionProp];
- var tabbox = tab.boxObject;
-
- var closebox;
- if (this.closeButtonsMode != this.CLOSE_BUTTONS_DISABLED &&
- this.closeButtonsMode != this.CLOSE_BUTTONS_ON_TABBAR &&
- (closebox = sv.getTabClosebox(tab)) &&
- (closebox = closebox.boxObject) &&
- closebox.width && closebox.height) {
- let padding = Math.min(
- closebox[position] - tabbox[position],
- (tabbox[position] + tabbox[size]) - (closebox[position] + closebox[size])
- );
- if (closebox[position] - padding <= coordinate &&
- closebox[position] + closebox[size] + padding >= coordinate)
- return this.cloneBoxObject(closebox, { padding : padding });
- }
-
- var twisty;
- if (sv.canCollapseSubtree(tab) &&
- (twisty = sv.getTabTwisty(tab)) &&
- (twisty = twisty.boxObject) &&
- twisty.width && twisty.height) {
- let padding = Math.min(
- twisty[position] - tabbox[position],
- (tabbox[position] + tabbox[size]) - (twisty[position] + twisty[size])
- );
- if (twisty[position] - padding <= coordinate &&
- twisty[position] + twisty[size] + padding >= coordinate)
- return this.cloneBoxObject(twisty, { padding : padding });
- }
-
- return null;
- },
- cloneBoxObject : function AHB_cloneBoxObject(aBoxObject, aOverride)
- {
- var box = {};
- for (let i in aBoxObject)
- {
- if (typeof aBoxObject[i] != 'function')
- box[i] = aBoxObject[i];
- }
- Object.keys(aOverride).forEach(function(aKey) {
- box[aKey] = aOverride[aKey];
- });
- return box;
- },
-
- cancelShowHideOnMouseMove : function AHB_cancelShowHideOnMouseMove()
- {
- if (this.showHideOnMouseMoveTimer) {
- this.window.clearTimeout(this.showHideOnMouseMoveTimer);
- this.showHideOnMouseMoveTimer = null;
- }
- },
-
- // feedback
-
- showForFeedback : function AHB_showForFeedback()
- {
- if (!this.enabled ||
- !utils.getTreePref('tabbar.autoShow.feedback'))
- return;
-
- var w = this.window;
- if (this.delayedShowForFeedbackTimer) {
- w.clearTimeout(this.delayedShowForFeedbackTimer);
- this.delayedShowForFeedbackTimer = null;
- }
- this.cancelHideForFeedback();
- this.delayedShowForFeedbackTimer = w.setTimeout(
- function(aSelf) {
- aSelf.delayedShowForFeedbackTimer = null;
- aSelf.delayedShowForFeedback();
- },
- 100,
- this
- );
- },
-
- delayedShowForFeedback : function AHB_delayedShowForFeedback()
- {
- this.show(this.kSHOWN_BY_FEEDBACK);
- this.cancelHideForFeedback();
- this.delayedHideTabbarForFeedbackTimer = this.window.setTimeout(
- function(aSelf) {
- aSelf.delayedHideTabbarForFeedbackTimer = null;
- aSelf.hide(aSelf.kSHOWN_BY_FEEDBACK);
- },
- utils.getTreePref('tabbar.autoShow.feedback.delay'),
- this
- );
- },
-
- cancelHideForFeedback : function AHB_cancelHideForFeedback()
- {
- if (this.delayedHideTabbarForFeedbackTimer) {
- this.window.clearTimeout(this.delayedHideTabbarForFeedbackTimer);
- this.delayedHideTabbarForFeedbackTimer = null;
- }
- },
-
- setWidth : function AHB_setWidth(aWidth, aForceExpanded)
- {
- if (aForceExpanded ||
- this.expanded ||
- this.mode != this.kMODE_SHRINK)
- utils.setTreePref('tabbar.width', this.treeStyleTab.maxTabbarWidth(aWidth));
- else
- utils.setTreePref('tabbar.shrunkenWidth', this.treeStyleTab.maxTabbarWidth(aWidth));
- },
-
- updateMenuItem : function AHB_updateMenuItem(aNode)
- {
- if (!aNode) return;
-
- if (this.mode != this.kMODE_DISABLED)
- aNode.setAttribute('checked', true);
- else
- aNode.removeAttribute('checked');
- },
-
- // show/hide tabbar
-
- get width()
- {
- if (this.expanded) {
- this._width = this.treeStyleTab.tabStrip.boxObject.width || this._width;
- }
- return this._width;
- },
- set width(aNewWidth)
- {
- this._width = aNewWidth;
- return this._width;
- },
- _width : 0,
-
- get widthFromMode()
- {
- return (this.shrunken) ?
- utils.getTreePref('tabbar.shrunkenWidth') :
- utils.getTreePref('tabbar.width') ;
- },
- get placeHolderWidthFromMode()
- {
- return (this.mode == this.kMODE_SHRINK) ?
- utils.getTreePref('tabbar.shrunkenWidth') :
- utils.getTreePref('tabbar.width') ;
- },
-
- get height()
- {
- if (this.expanded) {
- this._height = this.treeStyleTab.tabStrip.boxObject.height;
- }
- return this._height;
- },
- set height(aNewHeight)
- {
- this._height = aNewHeight;
- return this._height;
- },
- _height : 0,
-
- get splitterWidth()
- {
- if (this.expanded) {
- var splitter = this.document.getAnonymousElementByAttribute(this.browser, 'class', this.treeStyleTab.kSPLITTER);
- this._splitterWidth = (splitter ? splitter.boxObject.width : 0 );
- }
- return this._splitterWidth;
- },
- set splitterWidth(aNewWidth)
- {
- this._splitterWidth = aNewWidth;
- return this._splitterWidth;
- },
- _splitterWidth : 0,
-
- showHideInternal : function AHB_showHideInternal(aReason)
- {
- var sv = this.treeStyleTab;
- var b = this.browser;
- var pos = sv.position;
-
- aReason = aReason || 0;
-
- if (this.expanded) { // to be hidden or shrunken
- let reason = this.kSHOWN_BY_UNKNOWN;
- if (aReason & this.kSHOWHIDE_BY_API)
- reason = aReason;
- this.onHiding();
- this.showHideReason = reason;
- }
- else { // to be shown or expanded
- this.onShowing();
- this.showHideReason = aReason || this.showHideReason || this.kSHOWN_BY_UNKNOWN;
- }
-
- if (DEBUG) {
- let humanReadableReason =
- (aReason & this.kSHOWN_BY_SHORTCUT ? 'shortcut ' : '' ) +
- (aReason & this.kSHOWN_BY_MOUSEMOVE ? 'mousemove ' : '' ) +
- (aReason & this.kSHOWN_BY_FEEDBACK ? 'feedback ' : '' ) +
- (aReason & this.kSHOWHIDE_BY_START ? 'start ' : '' ) +
- (aReason & this.kSHOWHIDE_BY_END ? 'end ' : '' ) +
- (aReason & this.kSHOWHIDE_BY_POSITION_CHANGE ? 'positionchange ' : '' ) +
- (aReason & this.kSHOWHIDE_BY_RESIZE ? 'resize ' : '' ) +
- (aReason & this.kHIDDEN_BY_CLICK ? 'click ' : '' );
- if (this.expanded)
- dump('autoHide: show by ' + humanReadableReason + '\n');
- else
- dump('autoHide: hide by ' + humanReadableReason + '\n');
- }
-
- this.fireStateChangingEvent();
-
- if (this.expanded)
- sv.setTabbrowserAttribute(this.kAUTOHIDE, 'show');
- b.mTabContainer.adjustTabstrip();
- sv.checkTabsIndentOverflow();
-
- this.window.setTimeout(function(aSelf) {
- aSelf.fireStateChangeEvent();
- aSelf.showHideContentsAreaScreen();
- }, 0, this);
- },
- showHideContentsAreaScreen : function AHB_showHideContentsAreaScreen()
- {
- // this.browser.contentWindow doesn't currently work in e10s
- // mode, use this.browser.mCurrentBrowser.contentWindow as a
- // workaround until bug 1042680 is fixed
- if (
- this.expanded &&
- this.contentAreaScreenEnabled &&
- Services.focus.activeWindow &&
- Services.focus.activeWindow.top == this.window &&
- this.findPluginArea(this.browser.mCurrentBrowser.contentWindow)
- ) {
- let box = this.getContentsAreaBox();
- let style = this.screen.style;
- let width = Math.min(box.width, this.window.screen.availWidth - box.screenX);
- let height = Math.min(box.height, this.window.screen.availHeight - box.screenY);
- style.width = width+'px';
- style.height = height+'px';
- if (this.screen.state == 'open')
- this.screen.moveTo(box.screenX, box.screenY);
- else
- this.screen.openPopupAtScreen(box.screenX, box.screenY, false);
- this.screen.setAttribute('popup-shown', true);
- }
- else {
- this.screen.removeAttribute('popup-shown');
- if (this.screen.state != 'close')
- this.screen.hidePopup();
- }
- },
- findPluginArea : function AHB_findPluginArea(aFrame)
- {
- return aFrame.document.querySelector('embed, object') ||
- Array.some(aFrame.frames, AHB_findPluginArea);
- },
-
- show : function AHB_show(aReason) /* PUBLIC API */
- {
- if (this.showHideReason & this.kSHOWHIDE_BY_API) {
- this.end();
- return;
- }
-
- if (aReason) {
- this.showHideReason |= aReason;
- }
- if (!this.expanded)
- this.showHideInternal();
- },
-
- hide : function AHB_hide(aReason) /* PUBLIC API */
- {
- if (!this.enabled) {
- this.start(aReason | this.kSHOWHIDE_BY_API);
- return;
- }
-
- if (aReason) {
- if (aReason == this.kSHOWN_BY_ANY_REASON)
- this.showHideReason &= ~this.kSHOWN_BY_ANY_REASON;
- else if (this.showHideReason & aReason)
- this.showHideReason ^= aReason;
-
- if (this.showHideReason & this.kSHOWN_BY_ANY_REASON)
- return;
- }
- if (this.expanded)
- this.showHideInternal();
- },
-
- onShowing : function AHB_onShowing()
- {
- var sv = this.treeStyleTab;
- var b = this.browser;
- var pos = sv.position;
-
- sv.setTabbrowserAttribute(this.kSTATE, this.kSTATE_EXPANDED);
-
- switch (this.mode)
- {
- case this.kMODE_DISABLED:
- break;
-
- case this.kMODE_HIDE:
- sv.updateFloatingTabbar(sv.kTABBAR_UPDATE_BY_AUTOHIDE);
- break;
-
- default:
- case this.kMODE_SHRINK:
- if (pos == 'left' || pos == 'right') {
- let width = sv.maxTabbarWidth(utils.getTreePref('tabbar.width'));
- sv.updateFloatingTabbar(sv.kTABBAR_UPDATE_BY_AUTOHIDE);
- }
- break;
- }
- },
-
- onHiding : function AHB_onHiding()
- {
- var sv = this.treeStyleTab;
- var b = this.browser;
- var pos = sv.position;
-
- var box = (sv.tabStripPlaceHolder || sv.tabStrip).boxObject;
-
- this.tabbarHeight = box.height;
- this.width = box.width || this.width;
- var splitter = this.document.getAnonymousElementByAttribute(b, 'class', sv.kSPLITTER);
- this.splitterWidth = (splitter ? splitter.boxObject.width : 0 );
-
- switch (this.mode)
- {
- case this.kMODE_DISABLED:
- sv.setTabbrowserAttribute(this.kAUTOHIDE, 'hidden');
- sv.setTabbrowserAttribute(this.kSTATE, this.kSTATE_HIDDEN);
- break;
-
- case this.kMODE_HIDE:
- sv.updateLastScrollPosition();
- sv.setTabbrowserAttribute(this.kAUTOHIDE, 'hidden');
- sv.setTabbrowserAttribute(this.kSTATE, this.kSTATE_HIDDEN);
- sv.updateFloatingTabbar(sv.kTABBAR_UPDATE_BY_AUTOHIDE);
- break;
-
- default:
- case this.kMODE_SHRINK:
- sv.setTabbrowserAttribute(this.kAUTOHIDE, 'show');
- sv.setTabbrowserAttribute(this.kSTATE, this.kSTATE_SHRUNKEN);
- if (pos == 'left' || pos == 'right')
- sv.setTabStripAttribute('width', utils.getTreePref('tabbar.shrunkenWidth'));
- sv.updateFloatingTabbar(sv.kTABBAR_UPDATE_BY_AUTOHIDE);
- break;
- }
- },
-
- fireStateChangingEvent : function AHB_fireStateChangingEvent()
- {
- var data = {
- shown : this.expanded,
- state : this.state
- };
-
- /* PUBLIC API */
- this.treeStyleTab.fireCustomEvent(this.treeStyleTab.kEVENT_TYPE_AUTO_HIDE_STATE_CHANGING, this.browser, true, false, data);
- // for backward compatibility
- this.treeStyleTab.fireCustomEvent(this.treeStyleTab.kEVENT_TYPE_AUTO_HIDE_STATE_CHANGING.replace(/^nsDOM/, ''), this.browser, true, false, data);
- },
-
- fireStateChangeEvent : function AHB_fireStateChangeEvent()
- {
- var data = {
- shown : this.expanded,
- state : this.state,
- xOffset : this.XOffset,
- yOffset : this.YOffset
- };
-
- /* PUBLIC API */
- this.treeStyleTab.fireCustomEvent(this.treeStyleTab.kEVENT_TYPE_AUTO_HIDE_STATE_CHANGE, this.browser, true, false, data);
- // for backward compatibility
- this.treeStyleTab.fireCustomEvent(this.treeStyleTab.kEVENT_TYPE_AUTO_HIDE_STATE_CHANGE.replace(/^nsDOM/, ''), this.browser, true, false, data);
- },
-
-
-
-
- updateTransparency : function AHB_updateTransparency()
- {
- var sv = this.treeStyleTab;
- sv.updateFloatingTabbar(sv.kTABBAR_UPDATE_BY_APPEARANCE_CHANGE);
- },
-
- // event handling
-
- observe : function AHB_observe(aSubject, aTopic, aData)
- {
- switch (aTopic)
- {
- case 'nsPref:changed':
- this.onPrefChange(aData);
- break;
-
- default:
- break;
- }
- },
-
- domains : [
- 'extensions.treestyletab.',
- 'browser.fullscreen.autohide',
- 'browser.tabs.closeButtons'
- ],
-
- onPrefChange : function AHB_onPrefChange(aPrefName)
- {
- // ignore after destruction
- if (!this.window || !this.window.TreeStyleTabService)
- return;
-
- var value = prefs.getPref(aPrefName);
- switch (aPrefName)
- {
- case 'extensions.treestyletab.tabbar.autoHide.mode':
- if (!this.window.TreeStyleTabService.shouldApplyNewPref) return;
- this.browser.setAttribute(this.kMODE+'-normal', value);
- this.updateMode();
- return;
-
- case 'extensions.treestyletab.tabbar.autoHide.mode.fullscreen':
- if (!this.window.TreeStyleTabService.shouldApplyNewPref) return;
- this.browser.setAttribute(this.kMODE+'-fullscreen', value);
- this.updateMode();
- return;
-
- case 'extensions.treestyletab.tabbar.autoShow.mousemove':
- case 'extensions.treestyletab.tabbar.autoShow.accelKeyDown':
- case 'extensions.treestyletab.tabbar.autoShow.feedback':
- if (this.enabled && this.shouldListenMouseMove)
- this.startListenMouseMove();
- else
- this.endListenMouseMove();
- return;
-
- case 'extensions.treestyletab.tabbar.autoHide.area':
- this.sensitiveArea = value;
- return;
-
- case 'extensions.treestyletab.tabbar.togglerSize':
- this.togglerSize = value;
- var toggler = this.document.getAnonymousElementByAttribute(this.browser, 'class', this.treeStyleTab.kTABBAR_TOGGLER);
- toggler.style.minWidth = toggler.style.minHeight = value+'px';
- if (this.togglerSize <= 0)
- toggler.setAttribute('collapsed', true);
- else
- toggler.removeAttribute('collapsed');
- return;
-
- case 'extensions.treestyletab.tabbar.autoHide.contentAreaScreen.enabled':
- return this.contentAreaScreenEnabled = value;
-
- case 'browser.fullscreen.autohide':
- if (!this.window.fullScreen) return;
- this.end();
- this.mode = value ?
- this.getModeForFullScreen() :
- this.kMODE_DISABLED ;
- if (this.mode != this.kMODE_DISABLED)
- this.start();
- return;
-
- case 'browser.tabs.closeButtons':
- return this.closeButtonsMode = value;
-
- default:
- return;
- }
- },
-
- handleEvent : function AHB_handleEvent(aEvent)
- {
- switch (aEvent.type)
- {
- case 'mousedown':
- return this.onMouseDown(aEvent);
-
- case 'mouseup':
- return this.onMouseUp(aEvent);
-
- case 'mousemove':
- return this.handleMouseMove(aEvent);
-
- case 'TabOpen':
- case 'TabClose':
- return this.showForFeedback();
-
- case 'TabMove':
- if (!this.treeStyleTab.subTreeMovingCount && !this.treeStyleTab.internallyTabMovingCount)
- this.showForFeedback();
- return;
-
- case 'select':
- if (!this.window.TreeStyleTabService.accelKeyPressed)
- this.showForFeedback();
- return;
-
- case 'dragover':
- return this.onDragOver(aEvent);
-
- case 'dragleave':
- return this.onDragLeave(aEvent);
-
- case this.treeStyleTab.kEVENT_TYPE_TABBAR_POSITION_CHANGING:
- this.isResizing = false;
- return;
-
- case this.treeStyleTab.kEVENT_TYPE_TABBAR_POSITION_CHANGED:
- if (this.enabled)
- this.window.setTimeout(function(aSelf) {
- aSelf.show(this.kSHOWHIDE_BY_POSITION_CHANGE);
- aSelf.hide(this.kSHOWHIDE_BY_POSITION_CHANGE);
- }, 0, this);
- this.updateTransparency();
- return;
-
- case this.treeStyleTab.kEVENT_TYPE_TAB_FOCUS_SWITCHING_KEY_DOWN:
- return this.onKeyDown(aEvent.detail.sourceEvent);
-
- case this.treeStyleTab.kEVENT_TYPE_TAB_FOCUS_SWITCHING_START:
- this.cancelDelayedShowForShortcut();
- if (this.enabled &&
- utils.getTreePref('tabbar.autoShow.tabSwitch') &&
- (
- aEvent.detail.scrollDown ||
- aEvent.detail.scrollUp ||
- ( // when you release "shift" key
- this.expanded &&
- aEvent.detail.standBy &&
- aEvent.detail.onlyShiftKey
- )
- ))
- this.show(this.kSHOWN_BY_SHORTCUT);
- return;
-
- case this.treeStyleTab.kEVENT_TYPE_TAB_FOCUS_SWITCHING_END:
- this.cancelDelayedShowForShortcut();
- if (this.enabled)
- this.hide(this.kSHOWN_BY_SHORTCUT);
- return;
-
- case this.treeStyleTab.kEVENT_TYPE_PRINT_PREVIEW_ENTERED:
- this.hide(this.kSHOWHIDE_BY_END);
- this.endListenMouseMove();
- return;
-
- case this.treeStyleTab.kEVENT_TYPE_PRINT_PREVIEW_EXITED:
- if (this.enabled && this.shouldListenMouseMove)
- this.startListenMouseMove();
- return;
- }
- },
-
- onMouseDown : function AHB_onMouseDown(aEvent)
- {
- var sv = this.treeStyleTab;
- var w = this.window;
- if (
- !this.isResizing &&
- sv.evaluateXPath(
- 'ancestor-or-self::*[@class="'+sv.kSPLITTER+'"]',
- aEvent.originalTarget || aEvent.target,
- Ci.nsIDOMXPathResult.BOOLEAN_TYPE
- ).booleanValue
- ) {
- this.isResizing = true;
- sv.setTabbrowserAttribute(sv.kRESIZING, true);
- }
- this.cancelShowHideOnMouseMove();
- if (
- this.enabled &&
- this.expanded &&
- (
- aEvent.originalTarget.ownerDocument != this.document ||
- !sv.getTabBrowserFromChild(aEvent.originalTarget)
- )
- )
- this.hide(this.kHIDDEN_BY_CLICK);
- this.lastMouseDownTarget = aEvent.originalTarget.localName;
- },
-
- onMouseUp : function AHB_onMouseUp(aEvent)
- {
- var sv = this.treeStyleTab;
- if (aEvent.originalTarget &&
- sv.evaluateXPath(
- 'ancestor-or-self::*[@class="'+sv.kSPLITTER+'"]',
- aEvent.originalTarget,
- Ci.nsIDOMXPathResult.BOOLEAN_TYPE
- ).booleanValue) {
- this.isResizing = false;
- sv.removeTabbrowserAttribute(sv.kRESIZING);
- }
- this.cancelShowHideOnMouseMove();
- this.lastMouseDownTarget = null;
- },
-
- handleMouseMove : function AHB_handleMouseMove(aEvent)
- {
- var sv = this.treeStyleTab;
- if (this.isResizing &&
- /^(scrollbar|thumb|slider|scrollbarbutton)$/i.test(this.lastMouseDownTarget))
- return true;
-
- if (
- !aEvent.shiftKey &&
- !sv.isPopupShown() &&
- (
- !this.expanded ||
- this.showHideReason & this.kSHOWN_BY_ANY_REASON
- ) &&
- !this.lastMouseDownTarget
- )
- this.showHideOnMouseMove(aEvent);
- return true;
- },
-
- onDragOver : function AHB_onDragOver(aEvent)
- {
- if (this.expanded)
- return;
-
- var position = this.getMousePosition(aEvent);
- if (!(position & this.MOUSE_POSITION_SENSITIVE))
- return;
-
- var draggedTabs = this.window['piro.sakura.ne.jp'].tabsDragUtils.getSelectedTabs(aEvent);
- if (
- draggedTabs.length ||
- this.treeStyleTab.tabbarDNDObserver.retrieveURLsFromDataTransfer(aEvent.dataTransfer).length
- ) {
- this.show(this.kSHOWN_BY_MOUSEMOVE);
-
- if (this._autoHideOnDragLeaveTimer) {
- this.window.clearTimeout(this._autoHideOnDragLeaveTimer);
- delete this._autoHideOnDragLeaveTimer;
- }
- }
- },
-
- onDragLeave : function AHB_onDragLeave(aEvent)
- {
- if (!this.expanded)
- return;
-
- if (this._autoHideOnDragLeaveTimer)
- this.window.clearTimeout(this._autoHideOnDragLeaveTimer);
-
- var position = this.getMousePosition(aEvent);
- if (position & this.MOUSE_POSITION_SENSITIVE)
- return;
-
- this._autoHideOnDragLeaveTimer = this.window.setTimeout(function(aSelf) {
- delete aSelf._autoHideOnDragLeaveTimer;
- aSelf.hide(aSelf.kSHOWN_BY_MOUSEMOVE);
- }, 100, this);
- },
-
- onKeyDown : function AHB_onKeyDown(aEvent)
- {
- var sv = this.treeStyleTab;
- var b = this.browser;
- var w = this.window;
-
- if (this.delayedShowForShortcutDone)
- this.cancelDelayedShowForShortcut();
-
- if (
- sv.getTabs(b).length > 1 &&
- !aEvent.altKey &&
- w.TreeStyleTabService.accelKeyPressed
- ) {
- if (this.enabled &&
- utils.getTreePref('tabbar.autoShow.accelKeyDown') &&
- !this.delayedAutoShowTimer &&
- !this.delayedShowForShortcutTimer) {
- this.delayedShowForShortcutTimer = w.setTimeout(
- function(aSelf) {
- aSelf.delayedShowForShortcutDone = true;
- aSelf.show(aSelf.kSHOWN_BY_SHORTCUT);
- sv = null;
- b = null;
- },
- utils.getTreePref('tabbar.autoShow.accelKeyDown.delay'),
- this
- );
- this.delayedShowForShortcutDone = false;
- }
- }
- else {
- if (this.enabled)
- this.hide(this.kSHOWN_BY_SHORTCUT);
- }
- },
-
- cancelDelayedShowForShortcut : function AHB_cancelDelayedShowForShortcut()
- {
- if (this.delayedShowForShortcutTimer) {
- this.window.clearTimeout(this.delayedShowForShortcutTimer);
- this.delayedShowForShortcutTimer = null;
- }
- },
-
- delayedShowForShortcutTimer : null,
- delayedShowForShortcutDone : true,
-
- init : function AHB_init(aTabBrowser)
- {
- this.browser = aTabBrowser;
- this.document = aTabBrowser.ownerDocument;
- this.window = this.document.defaultView;
- this.treeStyleTab = aTabBrowser.treeStyleTab;
-
- var sv = this.treeStyleTab;
- var b = this.browser;
-
- this.enabled = false;
- this.mouseMoveListening = false;
- this.showHideReason = this.kSHOWN_BY_UNKNOWN;
- this.lastMouseDownTarget = null;
- this.isResizing = false;
-
- this.showHideOnMouseMoveTimer = null;
- this.delayedShowForFeedbackTimer = null;
-
- b.setAttribute(this.kMODE+'-normal', utils.getTreePref('tabbar.autoHide.mode'));
- b.setAttribute(this.kMODE+'-fullscreen', utils.getTreePref('tabbar.autoHide.mode.fullscreen'));
- prefs.addPrefListener(this);
- this.onPrefChange('browser.tabs.closeButtons');
- this.onPrefChange('extensions.treestyletab.tabbar.autoHide.area');
- this.onPrefChange('extensions.treestyletab.tabbar.togglerSize');
- this.onPrefChange('extensions.treestyletab.tabbar.autoHide.contentAreaScreen.enabled');
- this.window.setTimeout(function(aSelf) {
- aSelf.onPrefChange('extensions.treestyletab.tabbar.autoHide.mode');
- }, 0, this);
-
- b.mTabContainer.addEventListener('TabOpen', this, false);
- b.mTabContainer.addEventListener('TabClose', this, false);
- b.mTabContainer.addEventListener('TabMove', this, false);
- b.mTabContainer.addEventListener('select', this, false);
- b.addEventListener(sv.kEVENT_TYPE_TABBAR_POSITION_CHANGING, this, false);
- b.addEventListener(sv.kEVENT_TYPE_TABBAR_POSITION_CHANGED, this, false);
- b.addEventListener(sv.kEVENT_TYPE_TAB_FOCUS_SWITCHING_KEY_DOWN, this, false);
- b.addEventListener(sv.kEVENT_TYPE_TAB_FOCUS_SWITCHING_START, this, false);
- b.addEventListener(sv.kEVENT_TYPE_TAB_FOCUS_SWITCHING_END, this, false);
- },
-
- destroy : function AHB_destroy()
- {
- this.end();
- prefs.removePrefListener(this);
-
- var sv = this.treeStyleTab;
- var b = this.browser;
- b.mTabContainer.removeEventListener('TabOpen', this, false);
- b.mTabContainer.removeEventListener('TabClose', this, false);
- b.mTabContainer.removeEventListener('TabMove', this, false);
- b.mTabContainer.removeEventListener('select', this, false);
- b.removeEventListener(sv.kEVENT_TYPE_TABBAR_POSITION_CHANGING, this, false);
- b.removeEventListener(sv.kEVENT_TYPE_TABBAR_POSITION_CHANGED, this, false);
- b.removeEventListener(sv.kEVENT_TYPE_TAB_FOCUS_SWITCHING_KEY_DOWN, this, false);
- b.removeEventListener(sv.kEVENT_TYPE_TAB_FOCUS_SWITCHING_START, this, false);
- b.removeEventListener(sv.kEVENT_TYPE_TAB_FOCUS_SWITCHING_END, this, false);
-
- delete this.treeStyleTab;
- delete this.browser;
- delete this.document;
- delete this.window;
- },
-
- saveCurrentState : function AHB_saveCurrentState()
- {
- var b = this.browser;
- var prefs = {
- 'tabbar.autoHide.mode' : this.getModeForNormal(b),
- 'tabbar.autoHide.mode.fullscreen' : this.getModeForFullScreen(b),
- };
- for (var i in prefs)
- {
- if (utils.getTreePref(i) != prefs[i])
- utils.setTreePref(i, prefs[i]);
- }
- }
-
-};
-
-function AutoHideWindow(aWindow)
-{
- this.init(aWindow);
-}
-AutoHideWindow.prototype = {
- get browser()
- {
- return this.treeStyleTab.browser;
- },
-
-// mode
-
- getMode : function AHW_getMode(aTabBrowser)
- {
- var b = aTabBrowser || this.browser;
- var mode = b.getAttribute(AutoHideBrowser.prototype.kMODE);
- return mode ? parseInt(mode) : AutoHideBrowser.prototype.kMODE_DISABLED ;
- },
-
- get mode() /* PUBLIC API */
- {
- var mode = this.getMode();
- if (mode == AutoHideBrowser.prototype.kMODE_SHRINK &&
- this.treeStyleTab.position != 'left' &&
- this.treeStyleTab.position != 'right')
- return AutoHideBrowser.prototype.kMODE_HIDE;
- return mode;
- },
-
- set mode(aValue)
- {
- var b = aTabBrowser || this.browser;
- b.setAttribute(AutoHideBrowser.prototype.kMODE, aValue);
- return aValue;
- },
-
- toggleMode : function AHW_toggleMode(aTabBrowser) /* PUBLIC API */
- {
- var b = aTabBrowser || this.browser;
- var w = this.window;
-
- var key = 'tabbar.autoHide.mode';
- var toggleKey = 'tabbar.autoHide.mode.toggle';
- if (w.fullScreen) {
- key += '.fullscreen';
- toggleKey += '.fullscreen';
- }
-
- var mode = this.getMode(b) == AutoHideBrowser.prototype.kMODE_DISABLED ?
- utils.getTreePref(toggleKey) :
- AutoHideBrowser.prototype.kMODE_DISABLED ;
-
- utils.setTreePref(key, mode);
- b.setAttribute(AutoHideBrowser.prototype.kMODE+'-'+(w.fullScreen ? 'fullscreen' : 'normal' ), mode);
- b.treeStyleTab.autoHide.updateMode();
- },
-
-// for shortcuts
-
- updateKeyListeners : function AHW_updateKeyListeners()
- {
- // ignore after destruction
- if (!this.window || !this.window.TreeStyleTabService)
- return;
-
- if (
- this.getMode() &&
- this.shouldListenKeyEvents
- ) {
- this.treeStyleTab.startListenKeyEventsFor(this.treeStyleTab.LISTEN_FOR_AUTOHIDE);
- }
- else {
- this.treeStyleTab.endListenKeyEventsFor(this.treeStyleTab.LISTEN_FOR_AUTOHIDE);
- }
- var w = this.window;
- w.setTimeout(function() {
- if (w.windowState != Ci.nsIDOMChromeWindow.STATE_NORMAL)
- return;
- var count = 0;
- var resizeTimer = w.setInterval(function(){
- if (w.windowState != Ci.nsIDOMChromeWindow.STATE_NORMAL)
- return w.clearInterval(resizeTimer);
-
- if (++count > 100 || w.innerHeight > 0) {
- w.clearInterval(resizeTimer);
- w.resizeBy(-1,-1);
- w.resizeBy(1,1);
- }
- }, 250);
- }, 0);
- },
-
- get shouldListenKeyEvents()
- {
- return !this.treeStyleTab.ctrlTabPreviewsEnabled &&
- (
- utils.getTreePref('tabbar.autoShow.accelKeyDown') ||
- utils.getTreePref('tabbar.autoShow.tabSwitch') ||
- utils.getTreePref('tabbar.autoShow.feedback')
- );
- },
-
- init : function AHB_init(aWindow)
- {
- this.window = aWindow;
- this.document = aWindow.document;
- this.treeStyleTab = aWindow.TreeStyleTabService;
- },
-
- destroy : function AHB_destroy()
- {
- delete this.treeStyleTab;
- delete this.document;
- delete this.window;
- }
-
-};
-
+/* ***** 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 YUKI "Piro" Hiroshi.
+ * Portions created by the Initial Developer are Copyright (C) 2010-2014
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s): YUKI "Piro" Hiroshi
+ * Tetsuharu OHZEKI
+ *
+ * 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 ******/
+
+const EXPORTED_SYMBOLS = ['AutoHideBrowser', 'AutoHideWindow'];
+
+const DEBUG = false;
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+const Cu = Components.utils;
+
+Cu.import('resource://gre/modules/XPCOMUtils.jsm');
+Cu.import('resource://gre/modules/Services.jsm');
+
+XPCOMUtils.defineLazyModuleGetter(this, 'utils', 'resource://treestyletab-modules/utils.js', 'TreeStyleTabUtils');
+
+XPCOMUtils.defineLazyGetter(this, 'window', function() {
+ Cu.import('resource://treestyletab-modules/lib/namespace.jsm');
+ return getNamespaceFor('piro.sakura.ne.jp');
+});
+XPCOMUtils.defineLazyGetter(this, 'prefs', function() {
+ Cu.import('resource://treestyletab-modules/lib/prefs.js');
+ return window['piro.sakura.ne.jp'].prefs;
+});
+
+
+function AutoHideBrowser(aTabBrowser)
+{
+ this.init(aTabBrowser);
+}
+AutoHideBrowser.prototype = {
+
+ kMODE : 'treestyletab-tabbar-autohide-mode',
+ kMODE_DISABLED : 0,
+ kMODE_HIDE : 1,
+ kMODE_SHRINK : 2,
+
+ kAUTOHIDE : 'treestyletab-tabbar-autohide',
+
+ kSTATE : 'treestyletab-tabbar-autohide-state',
+ kSTATE_HIDDEN : 'hidden',
+ kSTATE_EXPANDED : 'expanded',
+ kSTATE_SHRUNKEN : 'shrunken',
+
+ kSHOWN_BY_UNKNOWN : 0,
+ kSHOWN_BY_SHORTCUT : 1 << 0,
+ kSHOWN_BY_MOUSEMOVE : 1 << 1,
+ kSHOWN_BY_FEEDBACK : 1 << 2,
+ kSHOWN_BY_ANY_REASON : (1 << 0) | (1 << 1) | (1 << 2),
+ kSHOWHIDE_BY_START : 1 << 3,
+ kSHOWHIDE_BY_END : 1 << 4,
+ kSHOWHIDE_BY_POSITION_CHANGE : 1 << 5,
+ kSHOWHIDE_BY_RESIZE : 1 << 6,
+ kSHOWHIDE_BY_API : 1 << 8,
+ kHIDDEN_BY_CLICK : 1 << 7,
+
+ get mode() /* PUBLIC API */
+ {
+ var mode = this.browser.getAttribute(this.kMODE);
+ return mode ? parseInt(mode) : this.kMODE_DISABLED ;
+ },
+ set mode(aValue)
+ {
+ this.browser.setAttribute(this.kMODE, aValue);
+ return aValue;
+ },
+
+ getMode : function AHB_getMode(aTabBrowser)
+ {
+ var b = aTabBrowser || this.browser;
+ var mode = b.getAttribute(this.kMODE);
+ return mode ? parseInt(mode) : this.kMODE_DISABLED ;
+ },
+ getModeForNormal : function AHB_getModeForNormal(aTabBrowser)
+ {
+ var b = aTabBrowser || this.browser;
+ return parseInt(b.getAttribute(this.kMODE+'-normal') || utils.getTreePref('tabbar.autoHide.mode'));
+ },
+ getModeForFullScreen : function AHB_getModeForFullScreen(aTabBrowser)
+ {
+ var b = aTabBrowser || this.browser;
+ return parseInt(b.getAttribute(this.kMODE+'-fullscreen') || utils.getTreePref('tabbar.autoHide.mode.fullscreen'));
+ },
+
+ get state()
+ {
+ return this.browser.getAttribute(this.kSTATE) || this.kSTATE_EXPANDED;
+ },
+ get expanded()
+ {
+ return this.state == this.kSTATE_EXPANDED;
+ },
+ get shrunken()
+ {
+ return this.state == this.kSTATE_SHRUNKEN;
+ },
+ get hidden()
+ {
+ return this.state == this.kSTATE_HIDDEN;
+ },
+
+ updateMode : function AHB_updateMode()
+ {
+ this.end();
+ // update internal property after the appearance of the tab bar is updated.
+ var w = this.window;
+ w.setTimeout(function(aSelf) {
+ aSelf.mode = (w.fullScreen && prefs.getPref('browser.fullscreen.autohide')) ?
+ aSelf.getModeForFullScreen() :
+ aSelf.getModeForNormal() ;
+ if (aSelf.mode != aSelf.kMODE_DISABLED)
+ aSelf.start();
+ }, 0, this);
+ },
+
+ togglerSize : 0,
+ sensitiveArea : 7,
+ contentAreaScreenEnabled : true,
+
+ closeButtonsMode : -1,
+ CLOSE_BUTTONS_ONLY_ON_CURRENT_TAB : 0,
+ CLOSE_BUTTONS_ON_ALL_TABS : 1,
+ CLOSE_BUTTONS_DISABLED : 2,
+ CLOSE_BUTTONS_ON_TABBAR : 3,
+
+ get XOffset()
+ {
+ var sv = this.treeStyleTab;
+ switch (this.mode)
+ {
+ case this.kMODE_DISABLED:
+ return 0;
+
+ case this.kMODE_HIDE:
+ let offset = this.width + this.splitterWidth;
+ let resizer = this.resizer;
+ if (sv.position == 'left') {
+ offset += this.togglerSize;
+ if (resizer)
+ offset += resizer.boxObject.width;
+ }
+ else if (sv.position == 'right') {
+ offset -= this.togglerSize;
+ if (resizer)
+ offset -= resizer.boxObject.width;
+ }
+ return offset;
+
+ default:
+ case this.kMODE_SHRINK:
+ return utils.getTreePref('tabbar.width')
+ - utils.getTreePref('tabbar.shrunkenWidth');
+ }
+ },
+ get YOffset()
+ {
+ return this.height;
+ },
+ extraXOffset : 0,
+ extraYOffset : 0,
+
+ get currentXOffset()
+ {
+ var sv = this.treeStyleTab;
+ return (
+ sv.position == 'left' &&
+ this.mode != this.kMODE_DISABLED &&
+ this.expanded
+ ) ? this.XOffset : 0 ;
+ },
+ get currentYOffset()
+ {
+ var sv = this.treeStyleTab;
+ return (
+ sv.position == 'top' &&
+ this.mode != this.kMODE_DISABLED &&
+ this.expanded
+ ) ? this.YOffset : 0 ;
+ },
+
+ get screen()
+ {
+ return this.document.getElementById('treestyletab-autohide-content-area-screen');
+ },
+ get resizer()
+ {
+ return this.document.getElementById('treestyletab-tabbar-resizer-splitter');
+ },
+
+ start : function AHB_start(aReason)
+ {
+ if (this.enabled) return;
+ this.enabled = true;
+ aReason = aReason || 0;
+
+ var sv = this.treeStyleTab;
+ var b = this.browser;
+ var w = this.window;
+
+ this.screen.hidePopup();
+
+ sv.setTabbrowserAttribute(this.kSTATE, this.kSTATE_EXPANDED);
+
+ if (!(aReason & this.kSHOWHIDE_BY_API)) {
+ b.addEventListener('mousedown', this, true);
+ b.addEventListener('mouseup', this, true);
+ b.addEventListener('dragover', this, true);
+ b.addEventListener('dragleave', this, true);
+ sv.tabStrip.addEventListener('mousedown', this, true);
+ sv.tabStrip.addEventListener('mouseup', this, true);
+ if (this.shouldListenMouseMove)
+ this.startListenMouseMove();
+ if (b == w.gBrowser && sv.shouldListenKeyEventsForAutoHide)
+ w.TreeStyleTabService.startListenKeyEventsFor(sv.LISTEN_FOR_AUTOHIDE);
+ this.userActionListening = true;
+ }
+ w.addEventListener(sv.kEVENT_TYPE_PRINT_PREVIEW_ENTERED, this, false);
+ w.addEventListener(sv.kEVENT_TYPE_PRINT_PREVIEW_EXITED, this, false);
+
+ this.updateTransparency();
+
+ this.showHideInternal(this.kSHOWHIDE_BY_START | aReason);
+
+ b.treeStyleTab.fixTooNarrowTabbar();
+ },
+
+ end : function AHB_end()
+ {
+ if (!this.enabled) return;
+ this.enabled = false;
+
+ var sv = this.treeStyleTab;
+ var b = this.browser;
+ var w = this.window;
+
+ this.show(this.kSHOWHIDE_BY_END);
+
+ this.screen.hidePopup();
+
+ if (this.userActionListening) {
+ b.removeEventListener('mousedown', this, true);
+ b.removeEventListener('mouseup', this, true);
+ b.removeEventListener('dragover', this, true);
+ b.removeEventListener('dragleave', this, true);
+ sv.tabStrip.removeEventListener('mousedown', this, true);
+ sv.tabStrip.removeEventListener('mouseup', this, true);
+ this.endListenMouseMove();
+ if (b == w.gBrowser)
+ w.TreeStyleTabService.endListenKeyEventsFor(sv.LISTEN_FOR_AUTOHIDE);
+ this.userActionListening = false;
+ }
+ w.removeEventListener(sv.kEVENT_TYPE_PRINT_PREVIEW_ENTERED, this, false);
+ w.removeEventListener(sv.kEVENT_TYPE_PRINT_PREVIEW_EXITED, this, false);
+
+ this.updateTransparency();
+
+ sv.removeTabbrowserAttribute(this.kAUTOHIDE);
+ sv.removeTabbrowserAttribute(this.kSTATE);
+
+ if (sv.isVertical)
+ sv.setTabStripAttribute('width', this.widthFromMode);
+ },
+
+ // fullscreen
+
+ startForFullScreen : function AHB_startForFullScreen()
+ {
+ this.mode = this.getMode();
+ this.end();
+ this.mode = prefs.getPref('browser.fullscreen.autohide') ?
+ this.getModeForFullScreen() :
+ this.kMODE_DISABLED ;
+ if (this.mode != this.kMODE_DISABLED) {
+ this.start();
+ this.treeStyleTab.removeTabbrowserAttribute('moz-collapsed');
+ }
+ },
+
+ endForFullScreen : function AHB_endForFullScreen()
+ {
+ this.mode = this.getModeForFullScreen();
+ this.end();
+ this.mode = utils.getTreePref('tabbar.autoHide.mode');
+ this.treeStyleTab.checkTabsIndentOverflow();
+ if (this.mode != this.kMODE_DISABLED)
+ this.start();
+ },
+
+ // mousemove
+
+ startListenMouseMove : function AHB_startListenMouseMove()
+ {
+ if (this.mouseMoveListening) return;
+
+ this.browser.addEventListener('mousemove', this, true);
+ this.screen.addEventListener('mousemove', this, true);
+ this.treeStyleTab.tabStrip.addEventListener('mousemove', this, true);
+
+ this.mouseMoveListening = true;
+ },
+
+ endListenMouseMove : function AHB_endListenMouseMove()
+ {
+ if (!this.mouseMoveListening) return;
+
+ this.browser.removeEventListener('mousemove', this, true);
+ this.screen.removeEventListener('mousemove', this, true);
+ this.treeStyleTab.tabStrip.removeEventListener('mousemove', this, true);
+
+ this.mouseMoveListening = false;
+ },
+
+ get shouldListenMouseMove()
+ {
+ return utils.getTreePref('tabbar.autoShow.mousemove');
+ },
+
+ get shouldListenKeyEventsForAutoHide()
+ {
+ return utils.getTreePref('tabbar.autoShow.accelKeyDown') ||
+ utils.getTreePref('tabbar.autoShow.tabSwitch');
+ },
+
+ showHideOnMouseMove : function AHB_showHideOnMouseMove(aEvent)
+ {
+ var position = this.getMousePosition(aEvent);
+ if (position == this.MOUSE_POSITION_UNKNOWN)
+ return;
+
+ this.cancelShowHideOnMouseMove();
+ this.showHideContentsAreaScreen();
+
+ var sv = this.treeStyleTab;
+ var b = this.browser;
+ var w = this.window;
+
+ var shouldShow = position & this.MOUSE_POSITION_SENSITIVE;
+ if (this.expanded) { // currently shown, let's hide it.
+ if (shouldShow) {
+ this.show(this.kSHOWN_BY_MOUSEMOVE);
+ this.cancelDelayedShowForShortcut();
+ }
+ else if (
+ !shouldShow &&
+ utils.getTreePref('tabbar.autoShow.mousemove')
+ ) {
+ this.showHideOnMouseMoveTimer = w.setTimeout(
+ function(aSelf) {
+ aSelf.cancelDelayedShowForShortcut();
+ aSelf.hide(aSelf.kSHOWN_BY_MOUSEMOVE);
+ },
+ utils.getTreePref('tabbar.autoHide.delay'),
+ this
+ );
+ }
+ }
+ else if (shouldShow) { // currently shown, let's show it.
+ this.showHideOnMouseMoveTimer = w.setTimeout(
+ function(aSelf) {
+ aSelf.cancelDelayedShowForShortcut();
+ aSelf.show(aSelf.kSHOWN_BY_MOUSEMOVE);
+ },
+ utils.getTreePref('tabbar.autoHide.delay'),
+ this
+ );
+ }
+
+ b = null;
+ },
+ getMousePosition : function AHB_getMousePosition(aEvent)
+ {
+ var w = this.window;
+ if ('gestureInProgress' in w && w.gestureInProgress)
+ return this.MOUSE_POSITION_UNKNOWN;
+
+ var sv = this.treeStyleTab;
+ var b = this.browser;
+ var pos = sv.position;
+ var box = this.getContentsAreaBox();
+
+ var sensitiveArea = this.sensitiveArea;
+ if (this.shrunken) {
+ let clickable;
+ let resizable = !sv.fixed;
+ if (resizable &
+ this.widthFromMode > 24 &&
+ (clickable = this.getNearestClickableBox(aEvent))) {
+ /* For resizing of shrunken tab bar and clicking closeboxes,
+ we have to shrink sensitive area. */
+ sensitiveArea = -(clickable.width + clickable.padding);
+ }
+ else if (resizable && this.resizer)
+ sensitiveArea = -this.resizer.boxObject.width;
+ else
+ sensitiveArea = 0;
+ }
+
+ if (
+ pos == 'left' ?
+ (aEvent.screenX > box.screenX + sensitiveArea) :
+ pos == 'right' ?
+ (aEvent.screenX < box.screenX + box.width - sensitiveArea) :
+ pos == 'bottom' ?
+ (aEvent.screenY < box.screenY + box.height - sensitiveArea) :
+ (aEvent.screenY > box.screenY + sensitiveArea)
+ ) {
+ return this.MOUSE_POSITION_OUTSIDE;
+ }
+
+ if (
+ pos == 'left' ?
+ (aEvent.screenX <= box.screenX - sensitiveArea) :
+ pos == 'right' ?
+ (aEvent.screenX >= box.screenX + box.width + sensitiveArea) :
+ pos == 'bottom' ?
+ (aEvent.screenY >= box.screenY + box.height + sensitiveArea) :
+ (aEvent.screenY <= box.screenY - sensitiveArea)
+ ) {
+ return this.MOUSE_POSITION_INSIDE;
+ }
+
+ return this.MOUSE_POSITION_NEAR;
+ },
+ getContentsAreaBox : function AHB_getContentsAreaBox()
+ {
+ var sv = this.treeStyleTab;
+ var b = this.browser;
+ var box = b.mCurrentBrowser.boxObject;
+ var xoffset = (this.shrunken || this.hidden) ? 0 : this.XOffset ;
+ box = {
+ screenX : box.screenX + (sv.position == 'left' ? xoffset : 0 ),
+ screenY : box.screenY,
+ width : box.width - xoffset,
+ height : box.height
+ };
+ return box;
+ },
+ MOUSE_POSITION_UNKNOWN : 0,
+ MOUSE_POSITION_OUTSIDE : (1 << 0),
+ MOUSE_POSITION_INSIDE : (1 << 1),
+ MOUSE_POSITION_NEAR : (1 << 2),
+ MOUSE_POSITION_SENSITIVE : (1 << 1) | (1 << 2),
+ getNearestClickableBox : function AHB_getNearestClickableBox(aEvent)
+ {
+ var sv = this.treeStyleTab;
+ var tab = sv.getTabFromCoordinates(aEvent);
+ if (!tab)
+ return null;
+
+ var position = sv.invertedScreenPositionProp;
+ var size = sv.invertedSizeProp;
+ var coordinate = aEvent[sv.invertedScreenPositionProp];
+ var tabbox = tab.boxObject;
+
+ var closebox;
+ if (this.closeButtonsMode != this.CLOSE_BUTTONS_DISABLED &&
+ this.closeButtonsMode != this.CLOSE_BUTTONS_ON_TABBAR &&
+ (closebox = sv.getTabClosebox(tab)) &&
+ (closebox = closebox.boxObject) &&
+ closebox.width && closebox.height) {
+ let padding = Math.min(
+ closebox[position] - tabbox[position],
+ (tabbox[position] + tabbox[size]) - (closebox[position] + closebox[size])
+ );
+ if (closebox[position] - padding <= coordinate &&
+ closebox[position] + closebox[size] + padding >= coordinate)
+ return this.cloneBoxObject(closebox, { padding : padding });
+ }
+
+ var twisty;
+ if (sv.canCollapseSubtree(tab) &&
+ (twisty = sv.getTabTwisty(tab)) &&
+ (twisty = twisty.boxObject) &&
+ twisty.width && twisty.height) {
+ let padding = Math.min(
+ twisty[position] - tabbox[position],
+ (tabbox[position] + tabbox[size]) - (twisty[position] + twisty[size])
+ );
+ if (twisty[position] - padding <= coordinate &&
+ twisty[position] + twisty[size] + padding >= coordinate)
+ return this.cloneBoxObject(twisty, { padding : padding });
+ }
+
+ return null;
+ },
+ cloneBoxObject : function AHB_cloneBoxObject(aBoxObject, aOverride)
+ {
+ var box = {};
+ for (let i in aBoxObject)
+ {
+ if (typeof aBoxObject[i] != 'function')
+ box[i] = aBoxObject[i];
+ }
+ Object.keys(aOverride).forEach(function(aKey) {
+ box[aKey] = aOverride[aKey];
+ });
+ return box;
+ },
+
+ cancelShowHideOnMouseMove : function AHB_cancelShowHideOnMouseMove()
+ {
+ if (this.showHideOnMouseMoveTimer) {
+ this.window.clearTimeout(this.showHideOnMouseMoveTimer);
+ this.showHideOnMouseMoveTimer = null;
+ }
+ },
+
+ // feedback
+
+ showForFeedback : function AHB_showForFeedback()
+ {
+ if (!this.enabled ||
+ !utils.getTreePref('tabbar.autoShow.feedback'))
+ return;
+
+ var w = this.window;
+ if (this.delayedShowForFeedbackTimer) {
+ w.clearTimeout(this.delayedShowForFeedbackTimer);
+ this.delayedShowForFeedbackTimer = null;
+ }
+ this.cancelHideForFeedback();
+ this.delayedShowForFeedbackTimer = w.setTimeout(
+ function(aSelf) {
+ aSelf.delayedShowForFeedbackTimer = null;
+ aSelf.delayedShowForFeedback();
+ },
+ 100,
+ this
+ );
+ },
+
+ delayedShowForFeedback : function AHB_delayedShowForFeedback()
+ {
+ this.show(this.kSHOWN_BY_FEEDBACK);
+ this.cancelHideForFeedback();
+ this.delayedHideTabbarForFeedbackTimer = this.window.setTimeout(
+ function(aSelf) {
+ aSelf.delayedHideTabbarForFeedbackTimer = null;
+ aSelf.hide(aSelf.kSHOWN_BY_FEEDBACK);
+ },
+ utils.getTreePref('tabbar.autoShow.feedback.delay'),
+ this
+ );
+ },
+
+ cancelHideForFeedback : function AHB_cancelHideForFeedback()
+ {
+ if (this.delayedHideTabbarForFeedbackTimer) {
+ this.window.clearTimeout(this.delayedHideTabbarForFeedbackTimer);
+ this.delayedHideTabbarForFeedbackTimer = null;
+ }
+ },
+
+ setWidth : function AHB_setWidth(aWidth, aForceExpanded)
+ {
+ if (aForceExpanded ||
+ this.expanded ||
+ this.mode != this.kMODE_SHRINK)
+ utils.setTreePref('tabbar.width', this.treeStyleTab.maxTabbarWidth(aWidth));
+ else
+ utils.setTreePref('tabbar.shrunkenWidth', this.treeStyleTab.maxTabbarWidth(aWidth));
+ },
+
+ updateMenuItem : function AHB_updateMenuItem(aNode)
+ {
+ if (!aNode) return;
+
+ if (this.mode != this.kMODE_DISABLED)
+ aNode.setAttribute('checked', true);
+ else
+ aNode.removeAttribute('checked');
+ },
+
+ // show/hide tabbar
+
+ get width()
+ {
+ if (this.expanded) {
+ this._width = this.treeStyleTab.tabStrip.boxObject.width || this._width;
+ }
+ return this._width;
+ },
+ set width(aNewWidth)
+ {
+ this._width = aNewWidth;
+ return this._width;
+ },
+ _width : 0,
+
+ get widthFromMode()
+ {
+ return (this.shrunken) ?
+ utils.getTreePref('tabbar.shrunkenWidth') :
+ utils.getTreePref('tabbar.width') ;
+ },
+ get placeHolderWidthFromMode()
+ {
+ return (this.mode == this.kMODE_SHRINK) ?
+ utils.getTreePref('tabbar.shrunkenWidth') :
+ utils.getTreePref('tabbar.width') ;
+ },
+
+ get height()
+ {
+ if (this.expanded) {
+ this._height = this.treeStyleTab.tabStrip.boxObject.height;
+ }
+ return this._height;
+ },
+ set height(aNewHeight)
+ {
+ this._height = aNewHeight;
+ return this._height;
+ },
+ _height : 0,
+
+ get splitterWidth()
+ {
+ if (this.expanded) {
+ var splitter = this.document.getAnonymousElementByAttribute(this.browser, 'class', this.treeStyleTab.kSPLITTER);
+ this._splitterWidth = (splitter ? splitter.boxObject.width : 0 );
+ }
+ return this._splitterWidth;
+ },
+ set splitterWidth(aNewWidth)
+ {
+ this._splitterWidth = aNewWidth;
+ return this._splitterWidth;
+ },
+ _splitterWidth : 0,
+
+ showHideInternal : function AHB_showHideInternal(aReason)
+ {
+ var sv = this.treeStyleTab;
+ var b = this.browser;
+ var pos = sv.position;
+
+ aReason = aReason || 0;
+
+ if (this.expanded) { // to be hidden or shrunken
+ let reason = this.kSHOWN_BY_UNKNOWN;
+ if (aReason & this.kSHOWHIDE_BY_API)
+ reason = aReason;
+ this.onHiding();
+ this.showHideReason = reason;
+ }
+ else { // to be shown or expanded
+ this.onShowing();
+ this.showHideReason = aReason || this.showHideReason || this.kSHOWN_BY_UNKNOWN;
+ }
+
+ if (DEBUG) {
+ let humanReadableReason =
+ (aReason & this.kSHOWN_BY_SHORTCUT ? 'shortcut ' : '' ) +
+ (aReason & this.kSHOWN_BY_MOUSEMOVE ? 'mousemove ' : '' ) +
+ (aReason & this.kSHOWN_BY_FEEDBACK ? 'feedback ' : '' ) +
+ (aReason & this.kSHOWHIDE_BY_START ? 'start ' : '' ) +
+ (aReason & this.kSHOWHIDE_BY_END ? 'end ' : '' ) +
+ (aReason & this.kSHOWHIDE_BY_POSITION_CHANGE ? 'positionchange ' : '' ) +
+ (aReason & this.kSHOWHIDE_BY_RESIZE ? 'resize ' : '' ) +
+ (aReason & this.kHIDDEN_BY_CLICK ? 'click ' : '' );
+ if (this.expanded)
+ dump('autoHide: show by ' + humanReadableReason + '\n');
+ else
+ dump('autoHide: hide by ' + humanReadableReason + '\n');
+ }
+
+ this.fireStateChangingEvent();
+
+ if (this.expanded)
+ sv.setTabbrowserAttribute(this.kAUTOHIDE, 'show');
+ b.mTabContainer.adjustTabstrip();
+ sv.checkTabsIndentOverflow();
+
+ this.window.setTimeout(function(aSelf) {
+ aSelf.fireStateChangeEvent();
+ aSelf.showHideContentsAreaScreen();
+ }, 0, this);
+ },
+ showHideContentsAreaScreen : function AHB_showHideContentsAreaScreen()
+ {
+ // this.browser.contentWindow doesn't currently work in e10s
+ // mode, use this.browser.mCurrentBrowser.contentWindow as a
+ // workaround until bug 1042680 is fixed
+ if (
+ this.expanded &&
+ this.contentAreaScreenEnabled &&
+ Services.focus.activeWindow &&
+ Services.focus.activeWindow.top == this.window &&
+ this.findPluginArea(this.browser.mCurrentBrowser.contentWindow)
+ ) {
+ let box = this.getContentsAreaBox();
+ let style = this.screen.style;
+ let width = Math.min(box.width, this.window.screen.availWidth - box.screenX);
+ let height = Math.min(box.height, this.window.screen.availHeight - box.screenY);
+ style.width = width+'px';
+ style.height = height+'px';
+ if (this.screen.state == 'open')
+ this.screen.moveTo(box.screenX, box.screenY);
+ else
+ this.screen.openPopupAtScreen(box.screenX, box.screenY, false);
+ this.screen.setAttribute('popup-shown', true);
+ }
+ else {
+ this.screen.removeAttribute('popup-shown');
+ if (this.screen.state != 'close')
+ this.screen.hidePopup();
+ }
+ },
+ findPluginArea : function AHB_findPluginArea(aFrame)
+ {
+ return aFrame.document.querySelector('embed, object') ||
+ Array.some(aFrame.frames, AHB_findPluginArea);
+ },
+
+ show : function AHB_show(aReason) /* PUBLIC API */
+ {
+ if (this.showHideReason & this.kSHOWHIDE_BY_API) {
+ this.end();
+ return;
+ }
+
+ if (aReason) {
+ this.showHideReason |= aReason;
+ }
+ if (!this.expanded)
+ this.showHideInternal();
+ },
+
+ hide : function AHB_hide(aReason) /* PUBLIC API */
+ {
+ if (!this.enabled) {
+ this.start(aReason | this.kSHOWHIDE_BY_API);
+ return;
+ }
+
+ if (aReason) {
+ if (aReason == this.kSHOWN_BY_ANY_REASON)
+ this.showHideReason &= ~this.kSHOWN_BY_ANY_REASON;
+ else if (this.showHideReason & aReason)
+ this.showHideReason ^= aReason;
+
+ if (this.showHideReason & this.kSHOWN_BY_ANY_REASON)
+ return;
+ }
+ if (this.expanded)
+ this.showHideInternal();
+ },
+
+ onShowing : function AHB_onShowing()
+ {
+ var sv = this.treeStyleTab;
+ var b = this.browser;
+ var pos = sv.position;
+
+ sv.setTabbrowserAttribute(this.kSTATE, this.kSTATE_EXPANDED);
+
+ switch (this.mode)
+ {
+ case this.kMODE_DISABLED:
+ break;
+
+ case this.kMODE_HIDE:
+ sv.updateFloatingTabbar(sv.kTABBAR_UPDATE_BY_AUTOHIDE);
+ break;
+
+ default:
+ case this.kMODE_SHRINK:
+ if (pos == 'left' || pos == 'right') {
+ let width = sv.maxTabbarWidth(utils.getTreePref('tabbar.width'));
+ sv.updateFloatingTabbar(sv.kTABBAR_UPDATE_BY_AUTOHIDE);
+ }
+ break;
+ }
+ },
+
+ onHiding : function AHB_onHiding()
+ {
+ var sv = this.treeStyleTab;
+ var b = this.browser;
+ var pos = sv.position;
+
+ var box = (sv.tabStripPlaceHolder || sv.tabStrip).boxObject;
+
+ this.tabbarHeight = box.height;
+ this.width = box.width || this.width;
+ var splitter = this.document.getAnonymousElementByAttribute(b, 'class', sv.kSPLITTER);
+ this.splitterWidth = (splitter ? splitter.boxObject.width : 0 );
+
+ switch (this.mode)
+ {
+ case this.kMODE_DISABLED:
+ sv.setTabbrowserAttribute(this.kAUTOHIDE, 'hidden');
+ sv.setTabbrowserAttribute(this.kSTATE, this.kSTATE_HIDDEN);
+ break;
+
+ case this.kMODE_HIDE:
+ sv.updateLastScrollPosition();
+ sv.setTabbrowserAttribute(this.kAUTOHIDE, 'hidden');
+ sv.setTabbrowserAttribute(this.kSTATE, this.kSTATE_HIDDEN);
+ sv.updateFloatingTabbar(sv.kTABBAR_UPDATE_BY_AUTOHIDE);
+ break;
+
+ default:
+ case this.kMODE_SHRINK:
+ sv.setTabbrowserAttribute(this.kAUTOHIDE, 'show');
+ sv.setTabbrowserAttribute(this.kSTATE, this.kSTATE_SHRUNKEN);
+ if (pos == 'left' || pos == 'right')
+ sv.setTabStripAttribute('width', utils.getTreePref('tabbar.shrunkenWidth'));
+ sv.updateFloatingTabbar(sv.kTABBAR_UPDATE_BY_AUTOHIDE);
+ break;
+ }
+ },
+
+ fireStateChangingEvent : function AHB_fireStateChangingEvent()
+ {
+ var data = {
+ shown : this.expanded,
+ state : this.state
+ };
+
+ /* PUBLIC API */
+ this.treeStyleTab.fireCustomEvent(this.treeStyleTab.kEVENT_TYPE_AUTO_HIDE_STATE_CHANGING, this.browser, true, false, data);
+ // for backward compatibility
+ this.treeStyleTab.fireCustomEvent(this.treeStyleTab.kEVENT_TYPE_AUTO_HIDE_STATE_CHANGING.replace(/^nsDOM/, ''), this.browser, true, false, data);
+ },
+
+ fireStateChangeEvent : function AHB_fireStateChangeEvent()
+ {
+ var data = {
+ shown : this.expanded,
+ state : this.state,
+ xOffset : this.XOffset,
+ yOffset : this.YOffset
+ };
+
+ /* PUBLIC API */
+ this.treeStyleTab.fireCustomEvent(this.treeStyleTab.kEVENT_TYPE_AUTO_HIDE_STATE_CHANGE, this.browser, true, false, data);
+ // for backward compatibility
+ this.treeStyleTab.fireCustomEvent(this.treeStyleTab.kEVENT_TYPE_AUTO_HIDE_STATE_CHANGE.replace(/^nsDOM/, ''), this.browser, true, false, data);
+ },
+
+
+
+
+ updateTransparency : function AHB_updateTransparency()
+ {
+ var sv = this.treeStyleTab;
+ sv.updateFloatingTabbar(sv.kTABBAR_UPDATE_BY_APPEARANCE_CHANGE);
+ },
+
+ // event handling
+
+ observe : function AHB_observe(aSubject, aTopic, aData)
+ {
+ switch (aTopic)
+ {
+ case 'nsPref:changed':
+ this.onPrefChange(aData);
+ break;
+
+ default:
+ break;
+ }
+ },
+
+ domains : [
+ 'extensions.treestyletab.',
+ 'browser.fullscreen.autohide',
+ 'browser.tabs.closeButtons'
+ ],
+
+ onPrefChange : function AHB_onPrefChange(aPrefName)
+ {
+ // ignore after destruction
+ if (!this.window || !this.window.TreeStyleTabService)
+ return;
+
+ var value = prefs.getPref(aPrefName);
+ switch (aPrefName)
+ {
+ case 'extensions.treestyletab.tabbar.autoHide.mode':
+ if (!this.window.TreeStyleTabService.shouldApplyNewPref) return;
+ this.browser.setAttribute(this.kMODE+'-normal', value);
+ this.updateMode();
+ return;
+
+ case 'extensions.treestyletab.tabbar.autoHide.mode.fullscreen':
+ if (!this.window.TreeStyleTabService.shouldApplyNewPref) return;
+ this.browser.setAttribute(this.kMODE+'-fullscreen', value);
+ this.updateMode();
+ return;
+
+ case 'extensions.treestyletab.tabbar.autoShow.mousemove':
+ case 'extensions.treestyletab.tabbar.autoShow.accelKeyDown':
+ case 'extensions.treestyletab.tabbar.autoShow.feedback':
+ if (this.enabled && this.shouldListenMouseMove)
+ this.startListenMouseMove();
+ else
+ this.endListenMouseMove();
+ return;
+
+ case 'extensions.treestyletab.tabbar.autoHide.area':
+ this.sensitiveArea = value;
+ return;
+
+ case 'extensions.treestyletab.tabbar.togglerSize':
+ this.togglerSize = value;
+ var toggler = this.document.getAnonymousElementByAttribute(this.browser, 'class', this.treeStyleTab.kTABBAR_TOGGLER);
+ toggler.style.minWidth = toggler.style.minHeight = value+'px';
+ if (this.togglerSize <= 0)
+ toggler.setAttribute('collapsed', true);
+ else
+ toggler.removeAttribute('collapsed');
+ return;
+
+ case 'extensions.treestyletab.tabbar.autoHide.contentAreaScreen.enabled':
+ return this.contentAreaScreenEnabled = value;
+
+ case 'browser.fullscreen.autohide':
+ if (!this.window.fullScreen) return;
+ this.end();
+ this.mode = value ?
+ this.getModeForFullScreen() :
+ this.kMODE_DISABLED ;
+ if (this.mode != this.kMODE_DISABLED)
+ this.start();
+ return;
+
+ case 'browser.tabs.closeButtons':
+ return this.closeButtonsMode = value;
+
+ default:
+ return;
+ }
+ },
+
+ handleEvent : function AHB_handleEvent(aEvent)
+ {
+ switch (aEvent.type)
+ {
+ case 'mousedown':
+ return this.onMouseDown(aEvent);
+
+ case 'mouseup':
+ return this.onMouseUp(aEvent);
+
+ case 'mousemove':
+ return this.handleMouseMove(aEvent);
+
+ case 'TabOpen':
+ case 'TabClose':
+ return this.showForFeedback();
+
+ case 'TabMove':
+ if (!this.treeStyleTab.subTreeMovingCount && !this.treeStyleTab.internallyTabMovingCount)
+ this.showForFeedback();
+ return;
+
+ case 'select':
+ if (!this.window.TreeStyleTabService.accelKeyPressed)
+ this.showForFeedback();
+ return;
+
+ case 'dragover':
+ return this.onDragOver(aEvent);
+
+ case 'dragleave':
+ return this.onDragLeave(aEvent);
+
+ case this.treeStyleTab.kEVENT_TYPE_TABBAR_POSITION_CHANGING:
+ this.isResizing = false;
+ return;
+
+ case this.treeStyleTab.kEVENT_TYPE_TABBAR_POSITION_CHANGED:
+ if (this.enabled)
+ this.window.setTimeout(function(aSelf) {
+ aSelf.show(this.kSHOWHIDE_BY_POSITION_CHANGE);
+ aSelf.hide(this.kSHOWHIDE_BY_POSITION_CHANGE);
+ }, 0, this);
+ this.updateTransparency();
+ return;
+
+ case this.treeStyleTab.kEVENT_TYPE_TAB_FOCUS_SWITCHING_KEY_DOWN:
+ return this.onKeyDown(aEvent.detail.sourceEvent);
+
+ case this.treeStyleTab.kEVENT_TYPE_TAB_FOCUS_SWITCHING_START:
+ this.cancelDelayedShowForShortcut();
+ if (this.enabled &&
+ utils.getTreePref('tabbar.autoShow.tabSwitch') &&
+ (
+ aEvent.detail.scrollDown ||
+ aEvent.detail.scrollUp ||
+ ( // when you release "shift" key
+ this.expanded &&
+ aEvent.detail.standBy &&
+ aEvent.detail.onlyShiftKey
+ )
+ ))
+ this.show(this.kSHOWN_BY_SHORTCUT);
+ return;
+
+ case this.treeStyleTab.kEVENT_TYPE_TAB_FOCUS_SWITCHING_END:
+ this.cancelDelayedShowForShortcut();
+ if (this.enabled)
+ this.hide(this.kSHOWN_BY_SHORTCUT);
+ return;
+
+ case this.treeStyleTab.kEVENT_TYPE_PRINT_PREVIEW_ENTERED:
+ this.hide(this.kSHOWHIDE_BY_END);
+ this.endListenMouseMove();
+ return;
+
+ case this.treeStyleTab.kEVENT_TYPE_PRINT_PREVIEW_EXITED:
+ if (this.enabled && this.shouldListenMouseMove)
+ this.startListenMouseMove();
+ return;
+ }
+ },
+
+ onMouseDown : function AHB_onMouseDown(aEvent)
+ {
+ var sv = this.treeStyleTab;
+ var w = this.window;
+ if (
+ !this.isResizing &&
+ sv.evaluateXPath(
+ 'ancestor-or-self::*[@class="'+sv.kSPLITTER+'"]',
+ aEvent.originalTarget || aEvent.target,
+ Ci.nsIDOMXPathResult.BOOLEAN_TYPE
+ ).booleanValue
+ ) {
+ this.isResizing = true;
+ sv.setTabbrowserAttribute(sv.kRESIZING, true);
+ }
+ this.cancelShowHideOnMouseMove();
+ if (
+ this.enabled &&
+ this.expanded &&
+ (
+ aEvent.originalTarget.ownerDocument != this.document ||
+ !sv.getTabBrowserFromChild(aEvent.originalTarget)
+ )
+ )
+ this.hide(this.kHIDDEN_BY_CLICK);
+ this.lastMouseDownTarget = aEvent.originalTarget.localName;
+ },
+
+ onMouseUp : function AHB_onMouseUp(aEvent)
+ {
+ var sv = this.treeStyleTab;
+ if (aEvent.originalTarget &&
+ sv.evaluateXPath(
+ 'ancestor-or-self::*[@class="'+sv.kSPLITTER+'"]',
+ aEvent.originalTarget,
+ Ci.nsIDOMXPathResult.BOOLEAN_TYPE
+ ).booleanValue) {
+ this.isResizing = false;
+ sv.removeTabbrowserAttribute(sv.kRESIZING);
+ }
+ this.cancelShowHideOnMouseMove();
+ this.lastMouseDownTarget = null;
+ },
+
+ handleMouseMove : function AHB_handleMouseMove(aEvent)
+ {
+ var sv = this.treeStyleTab;
+ if (this.isResizing &&
+ /^(scrollbar|thumb|slider|scrollbarbutton)$/i.test(this.lastMouseDownTarget))
+ return true;
+
+ if (
+ !aEvent.shiftKey &&
+ !sv.isPopupShown() &&
+ (
+ !this.expanded ||
+ this.showHideReason & this.kSHOWN_BY_ANY_REASON
+ ) &&
+ !this.lastMouseDownTarget
+ )
+ this.showHideOnMouseMove(aEvent);
+ return true;
+ },
+
+ onDragOver : function AHB_onDragOver(aEvent)
+ {
+ if (this.expanded)
+ return;
+
+ var position = this.getMousePosition(aEvent);
+ if (!(position & this.MOUSE_POSITION_SENSITIVE))
+ return;
+
+ var draggedTabs = this.window['piro.sakura.ne.jp'].tabsDragUtils.getSelectedTabs(aEvent);
+ if (
+ draggedTabs.length ||
+ this.treeStyleTab.tabbarDNDObserver.retrieveURLsFromDataTransfer(aEvent.dataTransfer).length
+ ) {
+ this.show(this.kSHOWN_BY_MOUSEMOVE);
+
+ if (this._autoHideOnDragLeaveTimer) {
+ this.window.clearTimeout(this._autoHideOnDragLeaveTimer);
+ delete this._autoHideOnDragLeaveTimer;
+ }
+ }
+ },
+
+ onDragLeave : function AHB_onDragLeave(aEvent)
+ {
+ if (!this.expanded)
+ return;
+
+ if (this._autoHideOnDragLeaveTimer)
+ this.window.clearTimeout(this._autoHideOnDragLeaveTimer);
+
+ var position = this.getMousePosition(aEvent);
+ if (position & this.MOUSE_POSITION_SENSITIVE)
+ return;
+
+ this._autoHideOnDragLeaveTimer = this.window.setTimeout(function(aSelf) {
+ delete aSelf._autoHideOnDragLeaveTimer;
+ aSelf.hide(aSelf.kSHOWN_BY_MOUSEMOVE);
+ }, 100, this);
+ },
+
+ onKeyDown : function AHB_onKeyDown(aEvent)
+ {
+ var sv = this.treeStyleTab;
+ var b = this.browser;
+ var w = this.window;
+
+ if (this.delayedShowForShortcutDone)
+ this.cancelDelayedShowForShortcut();
+
+ if (
+ sv.getTabs(b).length > 1 &&
+ !aEvent.altKey &&
+ w.TreeStyleTabService.accelKeyPressed
+ ) {
+ if (this.enabled &&
+ utils.getTreePref('tabbar.autoShow.accelKeyDown') &&
+ !this.delayedAutoShowTimer &&
+ !this.delayedShowForShortcutTimer) {
+ this.delayedShowForShortcutTimer = w.setTimeout(
+ function(aSelf) {
+ aSelf.delayedShowForShortcutDone = true;
+ aSelf.show(aSelf.kSHOWN_BY_SHORTCUT);
+ sv = null;
+ b = null;
+ },
+ utils.getTreePref('tabbar.autoShow.accelKeyDown.delay'),
+ this
+ );
+ this.delayedShowForShortcutDone = false;
+ }
+ }
+ else {
+ if (this.enabled)
+ this.hide(this.kSHOWN_BY_SHORTCUT);
+ }
+ },
+
+ cancelDelayedShowForShortcut : function AHB_cancelDelayedShowForShortcut()
+ {
+ if (this.delayedShowForShortcutTimer) {
+ this.window.clearTimeout(this.delayedShowForShortcutTimer);
+ this.delayedShowForShortcutTimer = null;
+ }
+ },
+
+ delayedShowForShortcutTimer : null,
+ delayedShowForShortcutDone : true,
+
+ init : function AHB_init(aTabBrowser)
+ {
+ this.browser = aTabBrowser;
+ this.document = aTabBrowser.ownerDocument;
+ this.window = this.document.defaultView;
+ this.treeStyleTab = aTabBrowser.treeStyleTab;
+
+ var sv = this.treeStyleTab;
+ var b = this.browser;
+
+ this.enabled = false;
+ this.mouseMoveListening = false;
+ this.showHideReason = this.kSHOWN_BY_UNKNOWN;
+ this.lastMouseDownTarget = null;
+ this.isResizing = false;
+
+ this.showHideOnMouseMoveTimer = null;
+ this.delayedShowForFeedbackTimer = null;
+
+ b.setAttribute(this.kMODE+'-normal', utils.getTreePref('tabbar.autoHide.mode'));
+ b.setAttribute(this.kMODE+'-fullscreen', utils.getTreePref('tabbar.autoHide.mode.fullscreen'));
+ prefs.addPrefListener(this);
+ this.onPrefChange('browser.tabs.closeButtons');
+ this.onPrefChange('extensions.treestyletab.tabbar.autoHide.area');
+ this.onPrefChange('extensions.treestyletab.tabbar.togglerSize');
+ this.onPrefChange('extensions.treestyletab.tabbar.autoHide.contentAreaScreen.enabled');
+ this.window.setTimeout(function(aSelf) {
+ aSelf.onPrefChange('extensions.treestyletab.tabbar.autoHide.mode');
+ }, 0, this);
+
+ b.mTabContainer.addEventListener('TabOpen', this, false);
+ b.mTabContainer.addEventListener('TabClose', this, false);
+ b.mTabContainer.addEventListener('TabMove', this, false);
+ b.mTabContainer.addEventListener('select', this, false);
+ b.addEventListener(sv.kEVENT_TYPE_TABBAR_POSITION_CHANGING, this, false);
+ b.addEventListener(sv.kEVENT_TYPE_TABBAR_POSITION_CHANGED, this, false);
+ b.addEventListener(sv.kEVENT_TYPE_TAB_FOCUS_SWITCHING_KEY_DOWN, this, false);
+ b.addEventListener(sv.kEVENT_TYPE_TAB_FOCUS_SWITCHING_START, this, false);
+ b.addEventListener(sv.kEVENT_TYPE_TAB_FOCUS_SWITCHING_END, this, false);
+ },
+
+ destroy : function AHB_destroy()
+ {
+ this.end();
+ prefs.removePrefListener(this);
+
+ var sv = this.treeStyleTab;
+ var b = this.browser;
+ b.mTabContainer.removeEventListener('TabOpen', this, false);
+ b.mTabContainer.removeEventListener('TabClose', this, false);
+ b.mTabContainer.removeEventListener('TabMove', this, false);
+ b.mTabContainer.removeEventListener('select', this, false);
+ b.removeEventListener(sv.kEVENT_TYPE_TABBAR_POSITION_CHANGING, this, false);
+ b.removeEventListener(sv.kEVENT_TYPE_TABBAR_POSITION_CHANGED, this, false);
+ b.removeEventListener(sv.kEVENT_TYPE_TAB_FOCUS_SWITCHING_KEY_DOWN, this, false);
+ b.removeEventListener(sv.kEVENT_TYPE_TAB_FOCUS_SWITCHING_START, this, false);
+ b.removeEventListener(sv.kEVENT_TYPE_TAB_FOCUS_SWITCHING_END, this, false);
+
+ delete this.treeStyleTab;
+ delete this.browser;
+ delete this.document;
+ delete this.window;
+ },
+
+ saveCurrentState : function AHB_saveCurrentState()
+ {
+ var b = this.browser;
+ var prefs = {
+ 'tabbar.autoHide.mode' : this.getModeForNormal(b),
+ 'tabbar.autoHide.mode.fullscreen' : this.getModeForFullScreen(b),
+ };
+ for (var i in prefs)
+ {
+ if (utils.getTreePref(i) != prefs[i])
+ utils.setTreePref(i, prefs[i]);
+ }
+ }
+
+};
+
+function AutoHideWindow(aWindow)
+{
+ this.init(aWindow);
+}
+AutoHideWindow.prototype = {
+ get browser()
+ {
+ return this.treeStyleTab.browser;
+ },
+
+// mode
+
+ getMode : function AHW_getMode(aTabBrowser)
+ {
+ var b = aTabBrowser || this.browser;
+ var mode = b.getAttribute(AutoHideBrowser.prototype.kMODE);
+ return mode ? parseInt(mode) : AutoHideBrowser.prototype.kMODE_DISABLED ;
+ },
+
+ get mode() /* PUBLIC API */
+ {
+ var mode = this.getMode();
+ if (mode == AutoHideBrowser.prototype.kMODE_SHRINK &&
+ this.treeStyleTab.position != 'left' &&
+ this.treeStyleTab.position != 'right')
+ return AutoHideBrowser.prototype.kMODE_HIDE;
+ return mode;
+ },
+
+ set mode(aValue)
+ {
+ var b = aTabBrowser || this.browser;
+ b.setAttribute(AutoHideBrowser.prototype.kMODE, aValue);
+ return aValue;
+ },
+
+ toggleMode : function AHW_toggleMode(aTabBrowser) /* PUBLIC API */
+ {
+ var b = aTabBrowser || this.browser;
+ var w = this.window;
+
+ var key = 'tabbar.autoHide.mode';
+ var toggleKey = 'tabbar.autoHide.mode.toggle';
+ if (w.fullScreen) {
+ key += '.fullscreen';
+ toggleKey += '.fullscreen';
+ }
+
+ var mode = this.getMode(b) == AutoHideBrowser.prototype.kMODE_DISABLED ?
+ utils.getTreePref(toggleKey) :
+ AutoHideBrowser.prototype.kMODE_DISABLED ;
+
+ utils.setTreePref(key, mode);
+ b.setAttribute(AutoHideBrowser.prototype.kMODE+'-'+(w.fullScreen ? 'fullscreen' : 'normal' ), mode);
+ b.treeStyleTab.autoHide.updateMode();
+ },
+
+// for shortcuts
+
+ updateKeyListeners : function AHW_updateKeyListeners()
+ {
+ // ignore after destruction
+ if (!this.window || !this.window.TreeStyleTabService)
+ return;
+
+ if (
+ this.getMode() &&
+ this.shouldListenKeyEvents
+ ) {
+ this.treeStyleTab.startListenKeyEventsFor(this.treeStyleTab.LISTEN_FOR_AUTOHIDE);
+ }
+ else {
+ this.treeStyleTab.endListenKeyEventsFor(this.treeStyleTab.LISTEN_FOR_AUTOHIDE);
+ }
+ var w = this.window;
+ w.setTimeout(function() {
+ if (w.windowState != Ci.nsIDOMChromeWindow.STATE_NORMAL)
+ return;
+ var count = 0;
+ var resizeTimer = w.setInterval(function(){
+ if (w.windowState != Ci.nsIDOMChromeWindow.STATE_NORMAL)
+ return w.clearInterval(resizeTimer);
+
+ if (++count > 100 || w.innerHeight > 0) {
+ w.clearInterval(resizeTimer);
+ w.resizeBy(-1,-1);
+ w.resizeBy(1,1);
+ }
+ }, 250);
+ }, 0);
+ },
+
+ get shouldListenKeyEvents()
+ {
+ return !this.treeStyleTab.ctrlTabPreviewsEnabled &&
+ (
+ utils.getTreePref('tabbar.autoShow.accelKeyDown') ||
+ utils.getTreePref('tabbar.autoShow.tabSwitch') ||
+ utils.getTreePref('tabbar.autoShow.feedback')
+ );
+ },
+
+ init : function AHB_init(aWindow)
+ {
+ this.window = aWindow;
+ this.document = aWindow.document;
+ this.treeStyleTab = aWindow.TreeStyleTabService;
+ },
+
+ destroy : function AHB_destroy()
+ {
+ delete this.treeStyleTab;
+ delete this.document;
+ delete this.window;
+ }
+
+};
+
diff --git a/modules/base.js b/modules/base.js
index 9d7249cc..77762ea0 100644
--- a/modules/base.js
+++ b/modules/base.js
@@ -1,2575 +1,2575 @@
-/* ***** 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 YUKI "Piro" Hiroshi.
- * Portions created by the Initial Developer are Copyright (C) 2010-2014
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s): YUKI "Piro" Hiroshi
- * Tetsuharu OHZEKI
- *
- * 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 ******/
-
-const EXPORTED_SYMBOLS = ['TreeStyleTabBase'];
-
-const Cc = Components.classes;
-const Ci = Components.interfaces;
-const Cu = Components.utils;
-
-Cu.import('resource://gre/modules/XPCOMUtils.jsm');
-Cu.import('resource://gre/modules/Services.jsm');
-Cu.import('resource://gre/modules/Timer.jsm');
-Cu.import('resource://treestyletab-modules/lib/inherit.jsm');
-Cu.import('resource://treestyletab-modules/constants.js');
-
-XPCOMUtils.defineLazyGetter(this, 'window', function() {
- Cu.import('resource://treestyletab-modules/lib/namespace.jsm');
- return getNamespaceFor('piro.sakura.ne.jp');
-});
-XPCOMUtils.defineLazyGetter(this, 'prefs', function() {
- Cu.import('resource://treestyletab-modules/lib/prefs.js');
- return window['piro.sakura.ne.jp'].prefs;
-});
-XPCOMUtils.defineLazyGetter(this, 'extensions', function() {
- Cu.import('resource://treestyletab-modules/lib/extensions.js', {});
- return window['piro.sakura.ne.jp'].extensions;
-});
-XPCOMUtils.defineLazyGetter(this, 'animationManager', function() {
- Cu.import('resource://treestyletab-modules/lib/animationManager.js', {});
- return window['piro.sakura.ne.jp'].animationManager;
-});
-XPCOMUtils.defineLazyGetter(this, 'autoScroll', function() {
- Cu.import('resource://treestyletab-modules/lib/autoScroll.js', {});
- return window['piro.sakura.ne.jp'].autoScroll;
-});
-XPCOMUtils.defineLazyModuleGetter(this, 'UninstallationListener',
- 'resource://treestyletab-modules/lib/UninstallationListener.js');
-XPCOMUtils.defineLazyModuleGetter(this, 'Deferred',
- 'resource://treestyletab-modules/lib/jsdeferred.js');
-XPCOMUtils.defineLazyModuleGetter(this, 'confirmWithPopup', 'resource://treestyletab-modules/lib/confirmWithPopup.js');
-XPCOMUtils.defineLazyModuleGetter(this, 'utils', 'resource://treestyletab-modules/utils.js', 'TreeStyleTabUtils');
-
-XPCOMUtils.defineLazyServiceGetter(this, 'SessionStore',
- '@mozilla.org/browser/sessionstore;1', 'nsISessionStore');
-
-if (Services.appinfo.OS === 'WINNT') {
- XPCOMUtils.defineLazyModuleGetter(this, 'AeroPeek',
- 'resource:///modules/WindowsPreviewPerTab.jsm', 'AeroPeek');
-}
-else {
- this.AeroPeek = null;
-}
-
-var TreeStyleTabBase = inherit(TreeStyleTabConstants, {
-
- tabsHash : null,
- inWindowDestoructionProcess : false,
-
-/* base variables */
- baseIndentVertical : 12,
- baseIndentHorizontal : 4,
- shouldDetectClickOnIndentSpaces : true,
-
- smoothScrollEnabled : true,
- smoothScrollDuration : 150,
-
- animationEnabled : true,
- indentDuration : 200,
- collapseDuration : 150,
-
- shouldExpandTwistyArea : true,
-
- scrollToNewTabMode : false,
-
- counterRoleHorizontal : -1,
- counterRoleVertical : -1,
-
- get SessionStore() {
- return SessionStore;
- },
-
- get extensions() { return extensions; },
- get animationManager() { return animationManager; },
- get autoScroll() { return autoScroll; },
- get Deferred() { return Deferred; },
- get AeroPeek() { return AeroPeek; }, // for Windows
-
- init : function TSTBase_init()
- {
- if (this._initialized)
- return;
-
- this.isMac = Services.appinfo.OS == 'Darwin';
-
- this.applyPlatformDefaultPrefs();
- utils.migratePrefs();
-
- prefs.addPrefListener(this);
-
- this.initUninstallationListener();
-
- this.onPrefChange('extensions.treestyletab.indent.vertical');
- this.onPrefChange('extensions.treestyletab.indent.horizontal');
- this.onPrefChange('extensions.treestyletab.clickOnIndentSpaces.enabled');
- this.onPrefChange('browser.tabs.insertRelatedAfterCurrent.override');
- this.onPrefChange('extensions.stm.tabBarMultiRows.override'); // Super Tab Mode
- this.onPrefChange('extensions.treestyletab.tabbar.scroll.smooth');
- this.onPrefChange('extensions.treestyletab.tabbar.scroll.duration');
- this.onPrefChange('extensions.treestyletab.tabbar.scrollToNewTab.mode');
- this.onPrefChange('extensions.treestyletab.tabbar.narrowScrollbar.size');
- this.onPrefChange('browser.tabs.animate');
- this.onPrefChange('extensions.treestyletab.animation.indent.duration');
- this.onPrefChange('extensions.treestyletab.animation.collapse.duration');
- this.onPrefChange('extensions.treestyletab.twisty.expandSensitiveArea');
- this.onPrefChange('extensions.treestyletab.counter.role.horizontal');
- this.onPrefChange('extensions.treestyletab.counter.role.vertical');
-
- try {
- this.overrideExtensions();
- }
- catch(e) {
- dump(e+'\n');
- }
- },
- _initialized : false,
-
- applyPlatformDefaultPrefs : function TSTBase_applyPlatformDefaultPrefs()
- {
- var OS = Services.appinfo.OS;
- var processed = {};
- var originalKeys = prefs.getDescendant('extensions.treestyletab.platform.'+OS);
- for (let i = 0, maxi = originalKeys.length; i < maxi; i++)
- {
- let originalKey = originalKeys[i];
- let key = originalKey.replace('platform.'+OS+'.', '');
- prefs.setDefaultPref(key, prefs.getPref(originalKey));
- processed[key] = true;
- }
- originalKeys = prefs.getDescendant('extensions.treestyletab.platform.default');
- for (let i = 0, maxi = originalKeys.length; i < maxi; i++)
- {
- let originalKey = originalKeys[i];
- let key = originalKey.replace('platform.default.', '');
- if (!(key in processed))
- prefs.setDefaultPref(key, prefs.getPref(originalKey));
- }
- },
-
- initUninstallationListener : function TSTWindow_initUninstallationListener()
- {
- var restorePrefs = function() {
- // Remove pref listener before restore backuped prefs.
- prefs.removePrefListener(this);
-
- let restorePrefs = [
- 'browser.tabs.insertRelatedAfterCurrent',
- 'extensions.stm.tabBarMultiRows' // Super Tab Mode
- ];
- for (let i = 0, maxi = restorePrefs.length; i < maxi; i++)
- {
- let pref = restorePrefs[i];
- let backup = prefs.getPref(pref+'.backup');
- if (backup === null)
- continue;
- // restore user preference.
- prefs.setPref(pref, backup);
- // clear backup pref.
- prefs.clearPref(pref+'.backup');
- }
- }.bind(this);
- new UninstallationListener({
- id : 'treestyletab@piro.sakura.ne.jp',
- onuninstalled : restorePrefs,
- ondisabled : restorePrefs
- });
- },
-
- overrideExtensions : function TSTBase_overrideExtensions()
- {
- // Scriptish
- // https://addons.mozilla.org/firefox/addon/scriptish/
- if (utils.getTreePref('compatibility.Scriptish')) {
- try {
- let tabModule = Cu.import('resource://scriptish/utils/Scriptish_openInTab.js', {});
- let Scriptish_openInTab = tabModule.Scriptish_openInTab;
- tabModule.Scriptish_openInTab = function(aURL, aLoadInBackground, aReuse, aChromeWin, ...aExtraArgs) {
- try {
- aChromeWin.TreeStyleTabService.readyToOpenChildTabNow(aChromeWin.gBrowser);
- }
- catch(e) {
- Cu.reportError(e);
- }
- var allArgs = [aURL, aLoadInBackground, aReuse, aChromeWin].concat(aExtraArgs);
- return Scriptish_openInTab.apply(this, allArgs);
- };
- }
- catch(e) {
- }
- }
- },
-
- updateNarrowScrollbarStyle : function TSTBase_updateNarrowScrollbarStyle()
- {
- const SSS = Cc['@mozilla.org/content/style-sheet-service;1']
- .getService(Ci.nsIStyleSheetService);
-
- if (this.lastAgentSheet &&
- SSS.sheetRegistered(this.lastAgentSheet, SSS.AGENT_SHEET))
- SSS.unregisterSheet(this.lastAgentSheet, SSS.AGENT_SHEET);
-
- const style = 'data:text/css,'+encodeURIComponent(
- ('@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");' +
-
- 'tabs.tabbrowser-tabs[%MODE%="vertical"][%NARROW%="true"]' +
- ' .tabbrowser-arrowscrollbox' +
- ' > scrollbox' +
- ' > scrollbar[orient="vertical"],' +
- 'tabs.tabbrowser-tabs[%MODE%="vertical"][%NARROW%="true"]' +
- ' .tabbrowser-arrowscrollbox' +
- ' > scrollbox' +
- ' > scrollbar[orient="vertical"] * {' +
- ' max-width: %SIZE%;' +
- ' min-width: %SIZE%;' +
- '}' +
-
- 'tabs.tabbrowser-tabs[%MODE%="vertical"][%NARROW%="true"]' +
- ' .tabbrowser-arrowscrollbox' +
- ' > scrollbox' +
- ' > scrollbar[orient="vertical"] {' +
- ' font-size: %SIZE%;' +
- '}' +
-
- 'tabs.tabbrowser-tabs[%MODE%="vertical"][%NARROW%="true"]' +
- ' .tabbrowser-arrowscrollbox' +
- ' > scrollbox' +
- ' > scrollbar[orient="vertical"] * {' +
- ' padding-left: 0;' +
- ' padding-right: 0;' +
- ' margin-left: 0;' +
- ' margin-right: 0;' +
- '}' +
-
- '%FORCE_NARROW_SCROLLBAR%')
- .replace(/%FORCE_NARROW_SCROLLBAR%/g,
- utils.getTreePref('tabbar.narrowScrollbar.overrideSystemAppearance') ?
- this.kOVERRIDE_SYSTEM_SCROLLBAR_APPEARANCE : '' )
- .replace(/%MODE%/g, this.kMODE)
- .replace(/%NARROW%/g, this.kNARROW_SCROLLBAR)
- .replace(/%SIZE%/g, utils.getTreePref('tabbar.narrowScrollbar.size'))
- );
- this.lastAgentSheet = this.makeURIFromSpec(style);
- SSS.loadAndRegisterSheet(this.lastAgentSheet, SSS.AGENT_SHEET);
- },
- kOVERRIDE_SYSTEM_SCROLLBAR_APPEARANCE :
- 'tabs.tabbrowser-tabs[%MODE%="vertical"][%NARROW%="true"]' +
- ' .tabbrowser-arrowscrollbox' +
- ' > scrollbox' +
- ' > scrollbar[orient="vertical"] {' +
- ' appearance: none;' +
- ' -moz-appearance: none;' +
- ' background: ThreeDFace;' +
- ' border: 1px solid ThreeDShadow;' +
- '}',
- lastAgentSheet : null,
-
-/* references to the owner */
-
- get browserWindow()
- {
- return this.topBrowserWindow;
- },
- get topBrowserWindow()
- {
- return Services.wm.getMostRecentWindow('navigator:browser');
- },
-
- get browserWindows()
- {
- var windows = [];
-
- var targets = Services.wm.getZOrderDOMWindowEnumerator('navigator:browser', true);
- // By the bug 156333, we cannot find windows by their Z order on Linux.
- // https://bugzilla.mozilla.org/show_bug.cgi?id=156333
- if (!targets.hasMoreElements())
- targets = Services.wm.getEnumerator('navigator:browser');
-
- while (targets.hasMoreElements())
- {
- let target = targets.getNext()
- .QueryInterface(Ci.nsIDOMWindow);
- windows.push(target);
- }
-
- return windows;
- },
-
- get browser()
- {
- var w = this.browserWindow;
- return !w ? null :
- 'SplitBrowser' in w ? w.SplitBrowser.activeBrowser :
- w.gBrowser ;
- },
-
- get window()
- {
- return this.browser.ownerDocument.defaultView;
- },
-
- get currentDragSession()
- {
- return Cc['@mozilla.org/widget/dragservice;1']
- .getService(Ci.nsIDragService)
- .getCurrentSession();
- },
-
-/* calculated behaviors */
-
- dropLinksOnTabBehavior : function TSTBase_dropLinksOnTabBehavior()
- {
- var behavior = utils.getTreePref('dropLinksOnTab.behavior');
- if (behavior & this.kDROPLINK_FIXED)
- return behavior;
-
- var checked = { value : false };
- var newChildTab = Services.prompt.confirmEx(this.browserWindow,
- utils.treeBundle.getString('dropLinkOnTab.title'),
- utils.treeBundle.getString('dropLinkOnTab.text'),
- (Services.prompt.BUTTON_TITLE_IS_STRING * Services.prompt.BUTTON_POS_0) +
- (Services.prompt.BUTTON_TITLE_IS_STRING * Services.prompt.BUTTON_POS_1),
- utils.treeBundle.getString('dropLinkOnTab.openNewChildTab'),
- utils.treeBundle.getString('dropLinkOnTab.loadInTheTab'),
- null,
- utils.treeBundle.getString('dropLinkOnTab.never'),
- checked
- ) == 0;
-
- behavior = newChildTab ? this.kDROPLINK_NEWTAB : this.kDROPLINK_LOAD ;
- if (checked.value)
- utils.setTreePref('dropLinksOnTab.behavior', behavior);
-
- return behavior
- },
- kDROPLINK_ASK : 0,
- kDROPLINK_FIXED : 1 + 2,
- kDROPLINK_LOAD : 1,
- kDROPLINK_NEWTAB : 2,
-
- openGroupBookmarkBehavior : function TSTBase_openGroupBookmarkBehavior()
- {
- var behavior = utils.getTreePref('openGroupBookmark.behavior');
- if (behavior & this.kGROUP_BOOKMARK_FIXED)
- return behavior;
-
- var dummyTabFlag = behavior & this.kGROUP_BOOKMARK_USE_DUMMY;
-
- var checked = { value : false };
- var button = Services.prompt.confirmEx(this.browserWindow,
- utils.treeBundle.getString('openGroupBookmarkBehavior.title'),
- utils.treeBundle.getString('openGroupBookmarkBehavior.text'),
- (Services.prompt.BUTTON_TITLE_IS_STRING * Services.prompt.BUTTON_POS_0) +
- (Services.prompt.BUTTON_TITLE_IS_STRING * Services.prompt.BUTTON_POS_1),
- utils.treeBundle.getString('openGroupBookmarkBehavior.subTree'),
- utils.treeBundle.getString('openGroupBookmarkBehavior.separate'),
- null,
- utils.treeBundle.getString('openGroupBookmarkBehavior.never'),
- checked
- );
-
- if (button < 0)
- button = 1;
- var behaviors = [
- this.kGROUP_BOOKMARK_SUBTREE | dummyTabFlag,
- this.kGROUP_BOOKMARK_SEPARATE
- ];
- behavior = behaviors[button];
-
- if (checked.value) {
- utils.setTreePref('openGroupBookmark.behavior', behavior);
- }
- return behavior;
- },
- kGROUP_BOOKMARK_ASK : 0,
- kGROUP_BOOKMARK_FIXED : 1 + 2 + 4,
- kGROUP_BOOKMARK_SUBTREE : 1,
- kGROUP_BOOKMARK_SEPARATE : 2,
- kGROUP_BOOKMARK_USE_DUMMY : 256,
- kGROUP_BOOKMARK_USE_DUMMY_FORCE : 1024,
- kGROUP_BOOKMARK_DONT_RESTORE_TREE_STRUCTURE : 512,
- kGROUP_BOOKMARK_EXPAND_ALL_TREE : 2048,
-
- bookmarkDroppedTabsBehavior : function TSTBase_bookmarkDroppedTabsBehavior()
- {
- var behavior = utils.getTreePref('bookmarkDroppedTabs.behavior');
- if (behavior & this.kBOOKMARK_DROPPED_TABS_FIXED)
- return behavior;
-
- var checked = { value : false };
- var button = Services.prompt.confirmEx(this.browserWindow,
- utils.treeBundle.getString('bookmarkDroppedTabs.title'),
- utils.treeBundle.getString('bookmarkDroppedTabs.text'),
- (Services.prompt.BUTTON_TITLE_IS_STRING * Services.prompt.BUTTON_POS_0) +
- (Services.prompt.BUTTON_TITLE_IS_STRING * Services.prompt.BUTTON_POS_1),
- utils.treeBundle.getString('bookmarkDroppedTabs.bookmarkAll'),
- utils.treeBundle.getString('bookmarkDroppedTabs.bookmarkOnlyParent'),
- null,
- utils.treeBundle.getString('bookmarkDroppedTabs.never'),
- checked
- );
-
- if (button < 0)
- button = 1;
- var behaviors = [
- this.kBOOKMARK_DROPPED_TABS_ALL,
- this.kBOOKMARK_DROPPED_TABS_ONLY_PARENT
- ];
- behavior = behaviors[button];
-
- if (checked.value)
- utils.setTreePref('bookmarkDroppedTabs.behavior', behavior);
-
- return behavior;
- },
- kBOOKMARK_DROPPED_TABS_ASK : 0,
- kBOOKMARK_DROPPED_TABS_FIXED : 1 | 2,
- kBOOKMARK_DROPPED_TABS_ALL : 1,
- kBOOKMARK_DROPPED_TABS_ONLY_PARENT : 2,
-
- askUndoCloseTabSetBehavior : function TSTBase_askUndoCloseTabSetBehavior(aRestoredTab, aCount)
- {
- var behavior = this.undoCloseTabSetBehavior;
- if (behavior & this.kUNDO_CLOSE_SET)
- behavior ^= this.kUNDO_CLOSE_SET;
-
- var self = this;
- return confirmWithPopup({
- browser : aRestoredTab.linkedBrowser,
- label : utils.treeBundle.getFormattedString('undoCloseTabSetBehavior.label', [aCount]),
- value : 'treestyletab-undo-close-tree',
- image : 'chrome://treestyletab/content/res/icon.png',
- buttons : [
- utils.treeBundle.getString('undoCloseTabSetBehavior.restoreOnce'),
- utils.treeBundle.getString('undoCloseTabSetBehavior.restoreForever'),
- utils.treeBundle.getString('undoCloseTabSetBehavior.ignoreForever')
- ],
- persistence : -1 // don't hide even if the tab is restored after the panel is shown.
- })
- .next(function(aButtonIndex) {
- if (aButtonIndex < 2) {
- behavior |= self.kUNDO_CLOSE_SET;
- }
- if (aButtonIndex > 0) {
- behavior ^= self.kUNDO_ASK;
- utils.setTreePref('undoCloseTabSet.behavior', behavior);
- }
- return behavior;
- });
- },
- get undoCloseTabSetBehavior()
- {
- return utils.getTreePref('undoCloseTabSet.behavior');
- },
- kUNDO_ASK : 1,
- kUNDO_CLOSE_SET : 2,
- kUNDO_CLOSE_FULL_SET : 256,
-
-/* utilities */
-
- doAndWaitDOMEvent : function TSTBase_doAndWaitDOMEvent(...aArgs)
- {
- var type, target, delay, task;
- for (let i = 0, maxi = aArgs.length; i < maxi; i++)
- {
- let arg = aArgs[i];
- switch(typeof arg)
- {
- case 'string':
- type = arg;
- continue;
-
- case 'number':
- delay = arg;
- continue;
-
- case 'function':
- task = arg;
- continue;
-
- default:
- target = arg;
- continue;
- }
- }
-
- if (!target || !type) {
- if (task)
- task();
- return;
- }
-
- var done = false;
- var listener = function(aEvent) {
- setTimeout(function() {
- done = true;
- }, delay || 0);
- target.removeEventListener(type, listener, false);
- };
-
- if (task)
- Deferred.next(function() {
- try {
- task();
- }
- catch(e) {
- dump(e+'\n');
- target.removeEventListener(type, listener, false);
- done = true;
- }
- }).error(this.defaultDeferredErrorHandler);
-
- target.addEventListener(type, listener, false);
-
- var thread = Components
- .classes['@mozilla.org/thread-manager;1']
- .getService()
- .mainThread;
- while (!done)
- {
- //dump('WAIT '+type+' '+Date.now()+'\n');
- thread.processNextEvent(true);
- }
- },
-
- findOffsetParent : function TSTBase_findOffsetParent(aNode)
- {
- var parent = aNode.parentNode;
- var doc = aNode.ownerDocument || aNode;
- var view = doc.defaultView;
- while (parent && parent instanceof Ci.nsIDOMElement)
- {
- let position = view.getComputedStyle(parent, null).getPropertyValue('position');
- if (position != 'static')
- return parent;
- parent = parent.parentNode;
- }
- return doc.documentElement;
- },
-
- assertBeforeDestruction : function TSTBase_assertBeforeDestruction(aNotDestructed)
- {
- if (aNotDestructed)
- return;
-
- var message = 'ERROR: accessed after destruction!';
- var error = new Error(message);
- dump(message+'\n'+error.stack+'\n');
- throw error;
- },
-
- defaultDeferredErrorHandler : function TSTBase_defaultDeferredErrorHandler(aError)
- {
- if (aError.stack)
- Cu.reportError(aError.message+'\n'+aError.stack);
- else
- Cu.reportError(aError);
- },
-
-// event
-
- isNewTabAction : function TSTBase_isNewTabAction(aEvent)
- {
- return aEvent.button == 1 || (aEvent.button == 0 && this.isAccelKeyPressed(aEvent));
- },
-
- isAccelKeyPressed : function TSTBase_isAccelKeyPressed(aEvent)
- {
- if ( // this is releasing of the accel key!
- (aEvent.type == 'keyup') &&
- (aEvent.keyCode == (this.isMac ? Ci.nsIDOMKeyEvent.DOM_VK_META : Ci.nsIDOMKeyEvent.DOM_VK_CONTROL ))
- ) {
- return false;
- }
- return this.isMac ?
- (aEvent.metaKey || (aEvent.keyCode == Ci.nsIDOMKeyEvent.DOM_VK_META)) :
- (aEvent.ctrlKey || (aEvent.keyCode == Ci.nsIDOMKeyEvent.DOM_VK_CONTROL)) ;
- },
-
- isCopyAction : function TSTBase_isCopyAction(aEvent)
- {
- return this.isAccelKeyPressed(aEvent) ||
- (aEvent.dataTransfer && aEvent.dataTransfer.dropEffect == 'copy');
- },
-
- isEventFiredOnClosebox : function TSTBase_isEventFiredOnClosebox(aEvent)
- {
- return this.evaluateXPath(
- 'ancestor-or-self::*[contains(concat(" ", normalize-space(@class), " "), " tab-close-button ")]',
- aEvent.originalTarget || aEvent.target,
- Ci.nsIDOMXPathResult.BOOLEAN_TYPE
- ).booleanValue;
- },
-
- isEventFiredOnClickable : function TSTBase_isEventFiredOnClickable(aEvent)
- {
- return this.evaluateXPath(
- 'ancestor-or-self::*[contains(" button toolbarbutton scrollbar nativescrollbar popup menupopup panel tooltip splitter textbox ", concat(" ", local-name(), " "))]',
- aEvent.originalTarget,
- Ci.nsIDOMXPathResult.BOOLEAN_TYPE
- ).booleanValue;
- },
-
- isEventFiredOnScrollbar : function TSTBase_isEventFiredOnScrollbar(aEvent)
- {
- return this.evaluateXPath(
- 'ancestor-or-self::*[local-name()="scrollbar" or local-name()="nativescrollbar"]',
- aEvent.originalTarget,
- Ci.nsIDOMXPathResult.BOOLEAN_TYPE
- ).booleanValue;
- },
-
- isEventFiredOnTwisty : function TSTBase_isEventFiredOnTwisty(aEvent)
- {
- var tab = this.getTabFromEvent(aEvent);
- if (!tab ||
- !this.hasChildTabs(tab) ||
- !this.canCollapseSubtree(tab))
- return false;
-
- var twisty = tab.ownerDocument.getAnonymousElementByAttribute(tab, 'class', this.kTWISTY);
- if (!twisty)
- return false;
-
- var box = twisty.boxObject;
- var left = box.screenX;
- var top = box.screenY;
- var right = left + box.width;
- var bottom = top + box.height;
- var favicon = this.getFaviconRect(tab);
- if (!box.width || !box.height) {
- left = favicon.left;
- top = favicon.top;
- right = favicon.right;
- bottom = favicon.bottom;
- }
- else if (
- this.shouldExpandTwistyArea &&
- !this._expandTwistyAreaBlockers.length
- ) {
- left = Math.min(left, favicon.left);
- top = Math.min(top, favicon.top);
- right = Math.max(right, favicon.right);
- bottom = Math.max(bottom, favicon.bottom);
- }
-
- var x = aEvent.screenX;
- var y = aEvent.screenY;
- return (x >= left && x <= right && y >= top && y <= bottom);
- },
- getFaviconRect : function TSTBase_getFaviconRect(aTab)
- {
- var icon = aTab.ownerDocument.getAnonymousElementByAttribute(aTab, 'class', 'tab-icon-image');
- var iconBox = icon.boxObject;
- var iconRect = {
- left : iconBox.screenX,
- top : iconBox.screenY,
- right : iconBox.screenX + iconBox.width,
- bottom : iconBox.screenY + iconBox.height
- };
-
- var throbber = aTab.ownerDocument.getAnonymousElementByAttribute(aTab, 'class', 'tab-throbber');
- var throbberBox = throbber.boxObject;
- var throbberRect = {
- left : throbberBox.screenX,
- top : throbberBox.screenY,
- right : throbberBox.screenX + throbberBox.width,
- bottom : throbberBox.screenY + throbberBox.height
- };
-
- if (!iconBox.width && !iconBox.height)
- return throbberRect;
-
- if (!throbberBox.width && !throbberBox.height)
- return iconRect;
-
- return {
- left : Math.min(throbberRect.left, iconRect.left),
- right : Math.max(throbberRect.right, iconRect.right),
- top : Math.min(throbberRect.top, iconRect.top),
- bottom : Math.max(throbberRect.bottom, iconRect.bottom)
- };
- },
-
- // called with target(nsIDOMEventTarget), document(nsIDOMDocument), type(string) and data(object)
- fireCustomEvent : function TSTBase_fireCustomEvent(...aArgs)
- {
- var target, document, type, data, canBubble, cancelable;
- for (let i = 0, maxi = aArgs.length; i < maxi; i++)
- {
- let arg = aArgs[i];
- if (typeof arg == 'boolean') {
- if (canBubble === void(0))
- canBubble = arg;
- else
- cancelable = arg;
- }
- else if (typeof arg == 'string')
- type = arg;
- else if (arg instanceof Ci.nsIDOMDocument)
- document = arg;
- else if (arg instanceof Ci.nsIDOMEventTarget)
- target = arg;
- else
- data = arg;
- }
- if (!target)
- target = document;
- if (!document)
- document = target.ownerDocument || target;
-
- var event = new this.window.CustomEvent(type, {
- bubbles : canBubble,
- cancelable : cancelable,
- detail : data
- });
- return target.dispatchEvent(event);
- },
-
- registerExpandTwistyAreaBlocker : function TSTBase_registerExpandTwistyAreaBlocker(aBlocker) /* PUBLIC API */
- {
- if (this._expandTwistyAreaBlockers.indexOf(aBlocker) < 0)
- this._expandTwistyAreaBlockers.push(aBlocker);
- },
- _expandTwistyAreaBlockers : [],
-
- registerExpandTwistyAreaAllowance : function TSTBase_registerExpandTwistyAreaAllowance(aAllowance) /* PUBLIC API, obsolete, for backward compatibility */
- {
- this.registerExpandTwistyAreaBlocker(aAllowance.toSource());
- },
-
-// string
-
- makeNewId : function TSTBase_makeNewId()
- {
- return 'tab-<'+Date.now()+'-'+parseInt(Math.random() * 65000)+'>';
- },
-
- makeNewClosedSetId : function TSTBase_makeNewId()
- {
- return 'tabs-closed-set-<'+Date.now()+'-'+parseInt(Math.random() * 65000)+'>';
- },
-
- makeURIFromSpec : function TSTBase_makeURIFromSpec(aURI)
- {
- var newURI;
- aURI = aURI || '';
- if (aURI && String(aURI).indexOf('file:') == 0) {
- var fileHandler = Services.io.getProtocolHandler('file').QueryInterface(Ci.nsIFileProtocolHandler);
- var tempLocalFile = fileHandler.getFileFromURLSpec(aURI);
- newURI = Services.io.newFileURI(tempLocalFile);
- }
- else {
- if (!/^\w+\:/.test(aURI))
- aURI = 'http://'+aURI;
- newURI = Services.io.newURI(aURI, null, null);
- }
- return newURI;
- },
-
- getGroupTabURI : function TSTBase_getGroupTabURI(aOptions)
- {
- aOptions = aOptions || {};
- var parameters = [];
- parameters.push('title=' + encodeURIComponent(aOptions.title || ''));
- parameters.push('temporary=' + !!aOptions.temporary);
- return 'about:treestyletab-group?' + parameters.join('&');
- },
-
-// xpath
-
- NSResolver : {
- lookupNamespaceURI : function(aPrefix)
- {
- switch (aPrefix)
- {
- case 'xul':
- return 'http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul';
- case 'html':
- case 'xhtml':
- return 'http://www.w3.org/1999/xhtml';
- case 'xlink':
- return 'http://www.w3.org/1999/xlink';
- default:
- return '';
- }
- }
- },
-
- evaluateXPath : function TSTBase_evaluateXPath(aExpression, aContext, aType)
- {
- if (!aType)
- aType = Ci.nsIDOMXPathResult.ORDERED_NODE_SNAPSHOT_TYPE;
- try {
- var XPathResult = (aContext.ownerDocument || aContext).evaluate(
- aExpression,
- (aContext || document),
- this.NSResolver,
- aType,
- null
- );
- }
- catch(e) {
- return {
- singleNodeValue : null,
- snapshotLength : 0,
- snapshotItem : function() {
- return null
- }
- };
- }
- return XPathResult;
- },
-
- getArrayFromXPathResult : function TSTBase_getArrayFromXPathResult(aXPathResult)
- {
- var max = aXPathResult.snapshotLength;
- var array = new Array(max);
- if (!max)
- return array;
-
- for (var i = 0; i < max; i++)
- {
- array[i] = aXPathResult.snapshotItem(i);
- }
-
- return array;
- },
-
-/* Session Store API */
-
- getTabValue : function TSTBase_getTabValue(aTab, aKey)
- {
- var value = '';
- try {
- value = SessionStore.getTabValue(aTab, aKey);
- }
- catch(e) {
- }
-
- if (this.useTMPSessionAPI) {
- let TMPValue = aTab.getAttribute(this.kTMP_SESSION_DATA_PREFIX+aKey);
- if (TMPValue)
- value = TMPValue;
- }
-
- return value;
- },
-
- setTabValue : function TSTBase_setTabValue(aTab, aKey, aValue)
- {
- if (!aValue)
- return this.deleteTabValue(aTab, aKey);
-
- aTab.setAttribute(aKey, aValue);
- try {
- this.checkCachedSessionDataExpiration(aTab);
- SessionStore.setTabValue(aTab, aKey, String(aValue));
- }
- catch(e) {
- }
-
- if (this.useTMPSessionAPI)
- aTab.setAttribute(this.kTMP_SESSION_DATA_PREFIX+aKey, aValue);
-
- return aValue;
- },
-
- deleteTabValue : function TSTBase_deleteTabValue(aTab, aKey)
- {
- aTab.removeAttribute(aKey);
- try {
- this.checkCachedSessionDataExpiration(aTab);
- SessionStore.setTabValue(aTab, aKey, '');
- SessionStore.deleteTabValue(aTab, aKey);
- }
- catch(e) {
- }
-
- if (this.useTMPSessionAPI)
- aTab.removeAttribute(this.kTMP_SESSION_DATA_PREFIX+aKey);
- },
-
- // workaround for http://piro.sakura.ne.jp/latest/blosxom/mozilla/extension/treestyletab/2009-09-29_debug.htm
- // This is obsolete for lately Firefox and no need to be updated. See: https://github.com/piroor/treestyletab/issues/508#issuecomment-17526429
- checkCachedSessionDataExpiration : function TSTBase_checkCachedSessionDataExpiration(aTab)
- {
- var data = aTab.linkedBrowser.__SS_data;
- if (data &&
- data._tabStillLoading &&
- aTab.getAttribute('busy') != 'true' &&
- !utils.isTabNeedToBeRestored(aTab))
- data._tabStillLoading = false;
- },
-
- markAsClosedSet : function TSTBase_markAsClosedSet(aTabs) /* PUBLIC API */
- {
- if (!aTabs || aTabs.length <= 1)
- return;
- var id = this.makeNewClosedSetId() + '::' + aTabs.length;
- for (let i = 0, maxi = aTabs.length; i < maxi; i++)
- {
- this.setTabValue(aTabs[i], this.kCLOSED_SET_ID, id);
- }
- },
-
- unmarkAsClosedSet : function TSTBase_unmarkAsClosedSet(aTabs) /* PUBLIC API */
- {
- if (!aTabs || !aTabs.length)
- return;
- for (let i = 0, maxi = aTabs.length; i < maxi; i++)
- {
- this.deleteTabValue(aTabs[i], this.kCLOSED_SET_ID);
- }
- },
-
- useTMPSessionAPI : false,
-
- kTMP_SESSION_DATA_PREFIX : 'tmp-session-data-',
-
-// tab
-
- getTabStrip : function TSTBase_getTabStrip(aTabBrowser)
- {
- if (!(aTabBrowser instanceof Ci.nsIDOMElement))
- return null;
-
- var strip = aTabBrowser.mStrip;
- return (strip && strip instanceof Ci.nsIDOMElement) ?
- strip :
- this.evaluateXPath(
- 'ancestor::xul:toolbar[1]',
- aTabBrowser.tabContainer,
- Ci.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE
- ).singleNodeValue || aTabBrowser.tabContainer.parentNode;
- },
- get tabStrip()
- {
- return this.getTabStrip(this.browser);
- },
-
- getTabContainerBox : function TSTBase_getTabContainerBox(aTabBrowser)
- {
- if (!(aTabBrowser instanceof Ci.nsIDOMElement))
- return null;
-
- var strip = this.getTabStrip(aTabBrowser);
- return strip.treeStyleTabToolbarInnerBox || aTabBrowser.tabContainer;
- },
- get tabContainerBox()
- {
- return this.getTabContainerBox(this.browser);
- },
-
- setTabbrowserAttribute : function TSTBase_setTabbrowserAttribute(aName, aValue, aTabBrowser)
- {
- aTabBrowser = aTabBrowser || this.mTabBrowser || this.browser;
- if (aValue) {
- aTabBrowser.setAttribute(aName, aValue);
- aTabBrowser.mTabContainer.setAttribute(aName, aValue);
- aTabBrowser.treeStyleTab.setTabStripAttribute(aName, aValue);
- }
- else {
- aTabBrowser.removeAttribute(aName);
- aTabBrowser.mTabContainer.removeAttribute(aName);
- aTabBrowser.treeStyleTab.removeTabStripAttribute(aName);
- }
- },
-
- removeTabbrowserAttribute : function TSTBase_removeTabbrowserAttribute(aName, aTabBrowser)
- {
- this.setTabbrowserAttribute(aName, null, aTabBrowser);
- },
-
- setTabStripAttribute : function TSTBase_setTabStripAttribute(aAttr, aValue)
- {
- var strip = this.tabStrip;
- if (!strip)
- return;
- var isFeatureAttribute = aAttr.indexOf('treestyletab-') == 0;
- if (aValue) {
- if (this._tabStripPlaceHolder)
- this._tabStripPlaceHolder.setAttribute(aAttr, aValue);
- if (!this._tabStripPlaceHolder || aAttr != 'ordinal')
- strip.setAttribute(aAttr, aValue);
- if (strip.treeStyleTabToolbarInnerBox)
- strip.treeStyleTabToolbarInnerBox.setAttribute(aAttr, aValue);
- if (isFeatureAttribute) {
- // Only attributes for TST's feature are applied to the root element.
- // (width, height, and other general attributes have to be ignored!)
- strip.ownerDocument.defaultView.setTimeout(function(aSelf) {
- strip.ownerDocument.documentElement.setAttribute(aAttr, aValue);
- }, 10, this);
- }
- }
- else {
- if (this._tabStripPlaceHolder)
- this._tabStripPlaceHolder.removeAttribute(aAttr);
- if (!this._tabStripPlaceHolder || aAttr != 'ordinal')
- strip.removeAttribute(aAttr);
- if (strip.treeStyleTabToolbarInnerBox)
- strip.treeStyleTabToolbarInnerBox.removeAttribute(aAttr);
- if (isFeatureAttribute) {
- strip.ownerDocument.defaultView.setTimeout(function(aSelf) {
- strip.ownerDocument.documentElement.removeAttribute(aAttr);
- }, 10, this);
- }
- }
- },
-
- removeTabStripAttribute : function TSTBase_removeTabStripAttribute(aAttr)
- {
- this.setTabStripAttribute(aAttr, null);
- },
-
- getTabFromChild : function TSTBase_getTabFromChild(aTab)
- {
- return this.evaluateXPath(
- 'ancestor-or-self::xul:tab',
- aTab,
- Ci.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE
- ).singleNodeValue;
- },
-
- getTabFromEvent : function TSTBase_getTabFromEvent(aEvent)
- {
- return this.getTabFromChild(aEvent.originalTarget || aEvent.target);
- },
-
- getNewTabButtonFromEvent : function TSTBase_getNewTabButtonFromEvent(aEvent)
- {
- return this.evaluateXPath(
- 'ancestor-or-self::*['
- +'@id="new-tab-button" or '
- +'contains(concat(" ", normalize-space(@class), " "), " tabs-newtab-button ")'
- +'][1]',
- aEvent.originalTarget,
- Ci.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE
- ).singleNodeValue;
- },
-
- getSplitterFromEvent : function TSTBase_getSplitterFromEvent(aEvent)
- {
- return this.evaluateXPath(
- 'ancestor-or-self::xul:splitter[contains(concat(" ", normalize-space(@class), " "), " '+this.kSPLITTER+' ")]',
- aEvent.originalTarget,
- Ci.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE
- ).singleNodeValue;
- },
-
- isEventFiredOnGrippy : function TSTBase_isEventFiredOnGrippy(aEvent)
- {
- return this.evaluateXPath(
- 'ancestor-or-self::xul:grippy',
- aEvent.originalTarget,
- Ci.nsIDOMXPathResult.BOOLEAN_TYPE
- ).booleanValue;
- },
-
- getTabFromBrowser : function TSTBase_getTabFromBrowser(aBrowser, aTabBrowser)
- {
- var b = aTabBrowser || this.browser;
- var tabs = this.getAllTabs(b);
- for (let i = 0, maxi = tabs.length; i < maxi; i++)
- {
- let tab = tabs[i];
- if (tab.linkedBrowser == aBrowser)
- return tab;
- }
- return null;
- },
-
- getTabFromFrame : function TSTBase_getTabFromFrame(aFrame, aTabBrowser)
- {
- var b = aTabBrowser || this.browser;
- var top = aFrame.top;
- var tabs = this.getAllTabs(b);
- for (let i = 0, maxi = tabs.length; i < maxi; i++)
- {
- let tab = tabs[i];
- if (tab.linkedBrowser.contentWindow == top)
- return tab;
- }
- return null;
- },
-
- getTabbarFromChild : function TSTBase_getTabbarFromChild(aNode)
- {
- return this.evaluateXPath(
- 'ancestor-or-self::*[contains(concat(" ", normalize-space(@class), " "), " tabbrowser-strip ")] | ' +
- 'ancestor-or-self::xul:tabs[@tabbrowser] | ' +
- 'ancestor-or-self::xul:toolbar/child::xul:tabs[@tabbrowser]',
- aNode,
- Ci.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE
- ).singleNodeValue;
- },
- getAncestorTabbarFromChild : function TSTBase_getAncestorTabbarFromChild(aNode)
- {
- return this.evaluateXPath(
- 'ancestor-or-self::*[contains(concat(" ", normalize-space(@class), " "), " tabbrowser-strip ")] | ' +
- 'ancestor-or-self::xul:tabs[@tabbrowser]',
- aNode,
- Ci.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE
- ).singleNodeValue;
- },
-
- getTabbarFromEvent : function TSTBase_getTabbarFromEvent(aEvent)
- {
- return this.getTabbarFromChild(aEvent.originalTarget || aEvent.target);
- },
- getAncestorTabbarFromEvent : function TSTBase_getAncestorTabbarFromEvent(aEvent)
- {
- return this.getAncestorTabbarFromChild(aEvent.originalTarget || aEvent.target);
- },
-
- cleanUpTabsArray : function TSTBase_cleanUpTabsArray(aTabs)
- {
- var newTabs = [];
- for (let i = 0, maxi = aTabs.length; i < maxi; i++)
- {
- let tab = aTabs[i];
- if (!tab || !tab.parentNode)
- continue; // ignore removed tabs
- if (newTabs.indexOf(tab) < 0)
- newTabs.push(tab);
- }
- newTabs.sort(this.sortTabsByOrder);
- return newTabs;
- },
-
- sortTabsByOrder : function TSTBase_sortTabsByOrder(aA, aB)
- {
- return aA._tPos - aB._tPos;
- },
-
- gatherSubtreeMemberTabs : function TSTBase_gatherSubtreeMemberTabs(aTabOrTabs, aOnlyChildren)
- {
- var tabs = aTabOrTabs;
- if (!(tabs instanceof Array)) {
- tabs = [aTabOrTabs];
- }
-
- var b = this.getTabBrowserFromChild(tabs[0]);
- var descendant = [];
- for (var i = 0, maxi = tabs.length; i < maxi; i++)
- {
- descendant = descendant.concat(b.treeStyleTab.getDescendantTabs(tabs[i]));
- }
-
- return this.cleanUpTabsArray(aOnlyChildren ? descendant : tabs.concat(descendant));
- },
-
- splitTabsToSubtrees : function TSTBase_splitTabsToSubtrees(aTabs) /* PUBLIC API */
- {
- var groups = [];
-
- var group = [];
- aTabs = this.cleanUpTabsArray(aTabs);
- for (let i = 0, maxi = aTabs.length; i < maxi; i++)
- {
- let tab = aTabs[i];
- let parent = this.getParentTab(tab);
- if (!parent || group.indexOf(parent) < 0) {
- if (group.length)
- groups.push(group);
- group = [tab];
- }
- else {
- group.push(tab);
- }
- }
- if (group.length)
- groups.push(group);
- return groups;
- },
-
-// tabbrowser
-
- getTabBrowserFromChild : function TSTBase_getTabBrowserFromChild(aTabBrowserChild)
- {
- if (!aTabBrowserChild)
- return null;
-
- if (aTabBrowserChild.__treestyletab__linkedTabBrowser) // tab
- return aTabBrowserChild.__treestyletab__linkedTabBrowser;
-
- if (aTabBrowserChild.localName == 'tabbrowser') // itself
- return aTabBrowserChild;
-
- if (aTabBrowserChild.tabbrowser) // tabs
- return aTabBrowserChild.tabbrowser;
-
- if (aTabBrowserChild.localName == 'toolbar') // tabs toolbar
- return aTabBrowserChild.getElementsByTagName('tabs')[0].tabbrowser;
-
- // tab context menu
- var popup = this.evaluateXPath(
- 'ancestor-or-self::xul:menupopup[@id="tabContextMenu"]',
- aTabBrowserChild,
- Ci.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE
- ).singleNodeValue;
- if (popup && 'TabContextMenu' in aTabBrowserChild.ownerDocument.defaultView)
- return this.getTabBrowserFromChild(aTabBrowserChild.ownerDocument.defaultView.TabContextMenu.contextTab);
-
- var b = this.evaluateXPath(
- 'ancestor::xul:tabbrowser | '+
- 'ancestor::xul:tabs[@tabbrowser] |'+
- 'ancestor::xul:toolbar/descendant::xul:tabs',
- aTabBrowserChild,
- Ci.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE
- ).singleNodeValue;
- return (b && b.tabbrowser) || b;
- },
-
- getTabBrowserFromFrame : function TSTBase_getTabBrowserFromFrame(aFrame)
- {
- var w = this.browserWindow;
- return !w ? null :
- ('SplitBrowser' in w) ? this.getTabBrowserFromChild(w.SplitBrowser.getSubBrowserAndBrowserFromFrame(aFrame.top).browser) :
- this.browser ;
- },
-
- getFrameFromTabBrowserElements : function TSTBase_getFrameFromTabBrowserElements(aFrameOrTabBrowser)
- {
- var frame = aFrameOrTabBrowser;
- if (frame == '[object XULElement]') {
- if (frame.localName == 'tab') {
- frame = frame.linkedBrowser.contentWindow;
- }
- else if (frame.localName == 'browser') {
- frame = frame.contentWindow;
- }
- else {
- frame = this.getTabBrowserFromChild(frame);
- if (!frame)
- return null;
- frame = frame.contentWindow;
- }
- }
- if (!frame)
- frame = this.browser.contentWindow;
-
- return frame;
- },
-
-/* get tab(s) */
-
- getTabById : function TSTBase_getTabById(aId, aTabBrowserChildren)
- {
- if (!aId)
- return null;
-
- if (aTabBrowserChildren && !(aTabBrowserChildren instanceof Ci.nsIDOMNode))
- aTabBrowserChildren = null;
-
- var b = this.getTabBrowserFromChild(aTabBrowserChildren) || this.browser;
-
- if (this.tabsHash) // XPath-less implementation
- return this.tabsHash[aId] || null;
-
- return b.mTabContainer.querySelector('tab['+this.kID+'="'+aId+'"]');
- },
-
- isTabDuplicated : function TSTBase_isTabDuplicated(aTab)
- {
- if (!aTab)
- return false;
- var id = this.getTabValue(aTab, this.kID);
- var b = this.getTabBrowserFromChild(aTab) || this.browser;
- var tabs = b.mTabContainer.querySelectorAll('tab['+this.kID+'="'+id+'"], tab['+this.kID_RESTORING+'="'+id+'"]');
- return tabs.length > 1;
- },
-
- /**
- * Returns all tabs in the current group as an array.
- * It includes tabs hidden by Tab Panorama.
- */
- getAllTabs : function TSTBase_getTabs(aTabBrowserChild)
- {
- var b = this.getTabBrowserFromChild(aTabBrowserChild || this.browser);
- this.assertBeforeDestruction(b && b.mTabContainer);
- return Array.slice(b.mTabContainer.querySelectorAll('tab'));
- },
-
- /**
- * Returns all tabs in the current group as an array.
- * It excludes tabs hidden by Tab Panorama.
- */
- getTabs : function TSTBase_getTabs(aTabBrowserChild)
- {
- var b = this.getTabBrowserFromChild(aTabBrowserChild || this.browser);
- this.assertBeforeDestruction(b && b.mTabContainer);
- return Array.slice(b.mTabContainer.querySelectorAll('tab:not([hidden="true"])'));
- },
-
- getAllTabsArray : function TSTBase_getAllTabsArray(aTabBrowserChild) /* for backward compatibility */
- {
- return this.getAllTabs(aTabBrowserChild);
- },
-
- getTabsArray : function TSTBase_getTabsArray(aTabBrowserChild) /* for backward compatibility */
- {
- return this.getTabs(aTabBrowserChild);
- },
-
- /**
- * Returns the first tab in the current group.
- */
- getFirstTab : function TSTBase_getFirstTab(aTabBrowserChild)
- {
- var b = this.getTabBrowserFromChild(aTabBrowserChild || this.browser);
- this.assertBeforeDestruction(b && b.mTabContainer);
- var tabs = b.visibleTabs;
- return tabs ? tabs[0] : b.mTabContainer.firstChild;
- },
-
- /**
- * Returns the first visible, not collapsed, and not pinned tab.
- */
- getFirstNormalTab : function TSTBase_getFirstNormalTab(aTabBrowserChild)
- {
- var b = this.getTabBrowserFromChild(aTabBrowserChild || this.browser);
- this.assertBeforeDestruction(b && b.mTabContainer);
- return b.mTabContainer.querySelector('tab:not([pinned="true"]):not([hidden="true"])');
- },
-
- /**
- * Returns the last tab in the current group.
- */
- getLastTab : function TSTBase_getLastTab(aTabBrowserChild)
- {
- var b = this.getTabBrowserFromChild(aTabBrowserChild || this.browser);
- this.assertBeforeDestruction(b && b.mTabContainer);
- var tabs = b.visibleTabs;
- return tabs ? tabs[tabs.length-1] : b.mTabContainer.lastChild ;
- },
-
- /**
- * Returns the next tab in the current group.
- */
- getNextTab : function TSTBase_getNextTab(aTab)
- {
- if (!aTab)
- return null;
- var b = this.getTabBrowserFromChild(aTab);
- this.assertBeforeDestruction(b && b.mTabContainer);
- var tabs = b.visibleTabs;
- if (tabs) {
- let index = tabs.indexOf(aTab);
- if (index > -1)
- return tabs.length > index ? tabs[index+1] : null
- }
- var tab = aTab.nextSibling;
- return (tab && tab.localName == 'tab') ? tab : null ;
- },
-
- /**
- * Returns the previous tab in the current group.
- */
- getPreviousTab : function TSTBase_getPreviousTab(aTab)
- {
- if (!aTab)
- return null;
- var b = this.getTabBrowserFromChild(aTab);
- this.assertBeforeDestruction(b && b.mTabContainer);
- var tabs = b.visibleTabs;
- if (tabs) {
- let index = tabs.indexOf(aTab);
- if (index > -1)
- return 0 < index ? tabs[index-1] : null
- }
- var tab = aTab.previousSibling;
- return (tab && tab.localName == 'tab') ? tab : null ;
- },
-
- /**
- * Returns the index of the specified tab, in the current group.
- */
- getTabIndex : function TSTBase_getTabIndex(aTab)
- {
- if (!aTab)
- return -1;
- var b = this.getTabBrowserFromChild(aTab);
- return this.getTabs(b).indexOf(aTab);
- },
-
- /**
- * Returns the next not collapsed tab in the current group.
- */
- getNextVisibleTab : function TSTBase_getNextVisibleTab(aTab)
- {
- if (!aTab)
- return null;
-
- var b = this.getTabBrowserFromChild(aTab);
- if (!this.canCollapseSubtree(b))
- return this.getNextTab(aTab);
-
- var tabs = this.getVisibleTabs(b);
- if (tabs.indexOf(aTab) < 0)
- tabs.push(aTab);
- tabs.sort(this.sortTabsByOrder);
-
- var index = tabs.indexOf(aTab);
- return (index < tabs.length-1) ? tabs[index+1] : null ;
- },
-
- /**
- * Returns the previous not collapsed tab in the current group.
- */
- getPreviousVisibleTab : function TSTBase_getPreviousVisibleTab(aTab)
- {
- if (!aTab)
- return null;
-
- var b = this.getTabBrowserFromChild(aTab);
- if (!this.canCollapseSubtree(b))
- return this.getPreviousTab(aTab);
-
- var tabs = this.getVisibleTabs(b);
- if (tabs.indexOf(aTab) < 0)
- tabs.push(aTab);
- tabs.sort(this.sortTabsByOrder);
-
- var index = tabs.indexOf(aTab);
- return (index > 0) ? tabs[index-1] : null ;
- },
-
- /**
- * Returns the last not collapsed tab in the current group.
- */
- getLastVisibleTab : function TSTBase_getLastVisibleTab(aTabBrowserChild)
- {
- var b = this.getTabBrowserFromChild(aTabBrowserChild || this.browser);
- if (!b)
- return null;
- var tabs = this.getVisibleTabs(b);
- return tabs.length ? tabs[tabs.length-1] : null ;
- },
-
- /**
- * Returns a XPathResult of not collapsed tabs in the current group.
- */
- getVisibleTabs : function TSTBase_getVisibleTabs(aTabBrowserChild) /* OBSOLETE */
- {
- var b = this.getTabBrowserFromChild(aTabBrowserChild || this.browser);
- if (!this.canCollapseSubtree(b))
- return this.getTabs(b);
- return Array.slice(b.mTabContainer.querySelectorAll('tab:not(['+this.kCOLLAPSED+'="true"]):not([hidden="true"])'));
- },
-
- getVisibleTabsArray : function TSTBase_getVisibleTabsArray(aTabBrowserChild) /* for backward compatibility */
- {
- return this.getVisibleTabs(aTabBrowserChild);
- },
-
- /**
- * Returns the index of the specified tab, in the array of not collapsed
- * tabs in the current group.
- */
- getVisibleIndex : function TSTBase_getVisibleIndex(aTab)
- {
- if (!aTab)
- return -1;
- var b = this.getTabBrowserFromChild(aTab);
- return this.getVisibleTabs(b).indexOf(aTab);
- },
-
- /**
- * Returns tabs which are newly opened in the given operation.
- */
- getNewTabsWithOperation : function TSTBase_getNewTabsWithOperation(aOperation, aTabBrowser)
- {
- var previousTabs = this.getTabsInfo(aTabBrowser);
- aOperation.call(this);
- return this.getNewTabsFromPreviousTabsInfo(aTabBrowser, previousTabs);
- },
-
- /**
- * Returns tabs which are newly opened. This requires the "previous state".
- */
- getNewTabsFromPreviousTabsInfo : function TSTBase_getNewTabsFromPreviousTabsInfo(aTabBrowser, aTabsInfo)
- {
- var tabs = this.getTabs(aTabBrowser);
- var currentTabsInfo = this.getTabsInfo(aTabBrowser);
- return tabs.filter(function(aTab, aIndex) {
- return aTabsInfo.indexOf(currentTabsInfo[aIndex]) < 0;
- });
- },
- getTabsInfo : function TSTBase_getTabsInfo(aTabBrowser)
- {
- var tabs = this.getTabs(aTabBrowser);
- return tabs.map(function(aTab) {
- return aTab.getAttribute(this.kID)+'\n'+
- aTab.getAttribute('busy')+'\n'+
- aTab.linkedBrowser.currentURI.spec;
- }, this);
- },
-
-/* notify "ready to open child tab(s)" */
-
- readyToOpenChildTab : function TSTBase_readyToOpenChildTab(aFrameOrTabBrowser, aMultiple, aInsertBefore) /* PUBLIC API */
- {
- if (!utils.getTreePref('autoAttach'))
- return false;
-
- var frame = this.getFrameFromTabBrowserElements(aFrameOrTabBrowser);
- if (!frame)
- return false;
-
- var ownerBrowser = this.getTabBrowserFromFrame(frame);
-
- var parentTab = this.getTabFromFrame(frame, ownerBrowser);
- if (!parentTab || parentTab.getAttribute('pinned') == 'true')
- return false;
-
- ownerBrowser.treeStyleTab.ensureTabInitialized(parentTab);
- var parentId = parentTab.getAttribute(this.kID);
-
- var refId = null;
- if (aInsertBefore) {
- ownerBrowser.treeStyleTab.ensureTabInitialized(parentTab);
- refId = aInsertBefore.getAttribute(this.kID);
- }
-
- dump('Tree Style Tab: new child tab is requested.\n'+new Error().stack+'\n');
-
- ownerBrowser.treeStyleTab.readiedToAttachNewTab = true;
- ownerBrowser.treeStyleTab.readiedToAttachMultiple = aMultiple || false ;
- ownerBrowser.treeStyleTab.multipleCount = aMultiple ? 0 : -1 ;
- ownerBrowser.treeStyleTab.parentTab = parentId;
- ownerBrowser.treeStyleTab.insertBefore = refId;
-
- return true;
- },
- /**
- * Extended version. If you don't know whether a new tab will be actually
- * opened or not (by the command called after TST's API), then use this.
- * This version automatically cancels the "ready" state with delay.
- */
- readyToOpenChildTabNow : function TSTBase_readyToOpenChildTabNow(...aArgs) /* PUBLIC API */
- {
- if (this.readyToOpenChildTab.apply(this, aArgs)) {
- let self = this;
- this.Deferred.next(function() {
- self.stopToOpenChildTab(aArgs[0]);
- }).error(this.defaultDeferredErrorHandler);
- return true;
- }
- return false;
- },
-
- readyToOpenNextSiblingTab : function TSTBase_readyToOpenNextSiblingTab(aFrameOrTabBrowser) /* PUBLIC API */
- {
- var frame = this.getFrameFromTabBrowserElements(aFrameOrTabBrowser);
- if (!frame)
- return false;
-
- var ownerBrowser = this.getTabBrowserFromFrame(frame);
-
- var tab = this.getTabFromFrame(frame, ownerBrowser);
- if (!tab || tab.getAttribute('pinned') == 'true')
- return false;
-
- var parentTab = this.getParentTab(tab);
- var nextTab = this.getNextSiblingTab(tab);
- if (parentTab) {
- /**
- * If the base tab has a parent, open the new tab as a child of
- * the parent tab.
- */
- return this.readyToOpenChildTab(parentTab, false, nextTab);
- }
- else {
- /**
- * Otherwise, open the tab as a new root tab. If there is no
- * tab next to the base tab (in other words, if the tab is the
- * last tab), then do nothing.
- */
- if (!nextTab)
- return;
- ownerBrowser.treeStyleTab.readiedToAttachNewTab = true;
- ownerBrowser.treeStyleTab.parentTab = null;
- ownerBrowser.treeStyleTab.insertBefore = nextTab.getAttribute(this.kID);
- return true;
- }
- },
- /**
- * Extended version. If you don't know whether a new tab will be actually
- * opened or not (by the command called after TST's API), then use this.
- * This version automatically cancels the "ready" state with delay.
- */
- readyToOpenNextSiblingTabNow : function TSTBase_readyToOpenNextSiblingTabNow(...aArgs) /* PUBLIC API */
- {
- if (this.readyToOpenNextSiblingTab.apply(this, aArgs)) {
- let self = this;
- this.Deferred.next(function() {
- self.stopToOpenChildTab(aArgs[0]);
- }).error(this.defaultDeferredErrorHandler);
- return true;
- }
- return false;
- },
-
- readyToOpenNewTabGroup : function TSTBase_readyToOpenNewTabGroup(aFrameOrTabBrowser, aTreeStructure, aExpandAllTree) /* PUBLIC API */
- {
- if (!utils.getTreePref('autoAttach'))
- return false;
-
- var frame = this.getFrameFromTabBrowserElements(aFrameOrTabBrowser);
- if (!frame)
- return false;
-
- this.stopToOpenChildTab(frame);
-
- var ownerBrowser = this.getTabBrowserFromFrame(frame);
- ownerBrowser.treeStyleTab.readiedToAttachNewTabGroup = true;
- ownerBrowser.treeStyleTab.readiedToAttachMultiple = true;
- ownerBrowser.treeStyleTab.multipleCount = 0;
- ownerBrowser.treeStyleTab.treeStructure = aTreeStructure;
- ownerBrowser.treeStyleTab.shouldExpandAllTree = !!aExpandAllTree;
-
- return true;
- },
- /**
- * Extended version. If you don't know whether new tabs will be actually
- * opened or not (by the command called after TST's API), then use this.
- * This version automatically cancels the "ready" state with delay.
- */
- readyToOpenNewTabGroupNow : function TSTBase_readyToOpenNewTabGroupNow(...aArgs) /* PUBLIC API */
- {
-
- if (this.readyToOpenNewTabGroup.apply(this, aArgs)) {
- let self = this;
- this.Deferred.next(function() {
- self.stopToOpenChildTab(aArgs[0]);
- }).error(this.defaultDeferredErrorHandler);
- return true;
- }
- return false;
- },
-
- stopToOpenChildTab : function TSTBase_stopToOpenChildTab(aFrameOrTabBrowser) /* PUBLIC API */
- {
- var frame = this.getFrameFromTabBrowserElements(aFrameOrTabBrowser);
- if (!frame)
- return false;
-
- var ownerBrowser = this.getTabBrowserFromFrame(frame);
- ownerBrowser.treeStyleTab.readiedToAttachNewTab = false;
- ownerBrowser.treeStyleTab.readiedToAttachNewTabGroup = false;
- ownerBrowser.treeStyleTab.readiedToAttachMultiple = false;
- ownerBrowser.treeStyleTab.multipleCount = -1;
- ownerBrowser.treeStyleTab.parentTab = null;
- ownerBrowser.treeStyleTab.insertBefore = null;
- ownerBrowser.treeStyleTab.treeStructure = null;
- ownerBrowser.treeStyleTab.shouldExpandAllTree = false;
-
- return true;
- },
-
- checkToOpenChildTab : function TSTBase_checkToOpenChildTab(aFrameOrTabBrowser) /* PUBLIC API */
- {
- var frame = this.getFrameFromTabBrowserElements(aFrameOrTabBrowser);
- if (!frame)
- return false;
-
- var ownerBrowser = this.getTabBrowserFromFrame(frame);
- return !!(ownerBrowser.treeStyleTab.readiedToAttachNewTab || ownerBrowser.treeStyleTab.readiedToAttachNewTabGroup);
- },
-
- kNEWTAB_DO_NOTHING : -1,
- kNEWTAB_OPEN_AS_ORPHAN : 0,
- kNEWTAB_OPEN_AS_CHILD : 1,
- kNEWTAB_OPEN_AS_SIBLING : 2,
- kNEWTAB_OPEN_AS_NEXT_SIBLING : 3,
- readyToOpenRelatedTabAs : function TSTBase_readyToOpenRelatedTabAs(aBaseTab, aBehavior)
- {
- var frame = this.getFrameFromTabBrowserElements(aBaseTab);
- if (!frame)
- return;
-
- aBaseTab = this.getTabFromFrame(frame, this.getTabBrowserFromFrame(frame));
-
- switch (aBehavior)
- {
- case this.kNEWTAB_OPEN_AS_ORPHAN:
- case this.kNEWTAB_DO_NOTHING:
- default:
- break;
- case this.kNEWTAB_OPEN_AS_CHILD:
- this.readyToOpenChildTabNow(aBaseTab);
- break;
- case this.kNEWTAB_OPEN_AS_SIBLING:
- let (parentTab = this.getParentTab(aBaseTab)) {
- if (parentTab)
- this.readyToOpenChildTabNow(parentTab);
- }
- break;
- case this.kNEWTAB_OPEN_AS_NEXT_SIBLING:
- this.readyToOpenNextSiblingTabNow(aBaseTab);
- break;
- }
- },
-
- handleNewTabFromCurrent : function TSTBase_handleNewTabFromCurrent(aBaseTab)
- {
- this.readyToOpenRelatedTabAs(aBaseTab, utils.getTreePref('autoAttach.fromCurrent'));
- },
-
-/* tree manipulations */
-
- get treeViewEnabled() /* PUBLIC API */
- {
- return this._treeViewEnabled;
- },
- set treeViewEnabled(aValue)
- {
- this._treeViewEnabled = !!aValue;
- Services.obs.notifyObservers(
- window,
- this.kTOPIC_CHANGE_TREEVIEW_AVAILABILITY,
- this._treeViewEnabled
- );
- return aValue;
- },
- _treeViewEnabled : true,
-
- get rootTabs() /* PUBLIC API */
- {
- return Array.slice(this.browser.mTabContainer.querySelectorAll('tab:not(['+this.kNEST+']), tab['+this.kNEST+'=""], tab['+this.kNEST+'="0"]'));
- },
-
- get allRootTabs() /* PUBLIC API */
- {
- return this.rootTabs;
- },
-
- get visibleRootTabs() /* PUBLIC API */
- {
- return this.rootTabs.filter(function(aTab) {
- return !aTab.hidden;
- });
- },
-
- canCollapseSubtree : function TSTBase_canCollapseSubtree(aTabOrTabBrowser) /* PUBLIC API */
- {
- if (aTabOrTabBrowser &&
- aTabOrTabBrowser.localName == 'tab' &&
- aTabOrTabBrowser.getAttribute(this.kALLOW_COLLAPSE) != 'true')
- return false;
-
- var b = this.getTabBrowserFromChild(aTabOrTabBrowser) || this.browser;
- return b && b.getAttribute(this.kALLOW_COLLAPSE) == 'true';
- },
-
- isCollapsed : function TSTBase_isCollapsed(aTab) /* PUBLIC API */
- {
- if (!aTab ||
- !this.canCollapseSubtree(this.getRootTab(aTab)))
- return false;
-
- return aTab.getAttribute(this.kCOLLAPSED) == 'true';
- },
-
- isSubtreeCollapsed : function TSTBase_isSubtreeCollapsed(aTab) /* PUBLIC API */
- {
- if (!aTab || !this.canCollapseSubtree(aTab) || !this.hasChildTabs(aTab))
- return false;
-
- return aTab.getAttribute(this.kSUBTREE_COLLAPSED) == 'true';
- },
-
- shouldCloseTabSubtreeOf : function TSTBase_shouldCloseTabSubtreeOf(aTab)
- {
- return (
- this.hasChildTabs(aTab) &&
- (
- utils.getTreePref('closeParentBehavior') == this.kCLOSE_PARENT_BEHAVIOR_CLOSE_ALL_CHILDREN ||
- this.isSubtreeCollapsed(aTab)
- )
- );
- },
- shouldCloseTabSubTreeOf : function TSTBase_shouldCloseTabSubTreeOf(...aArgs) {
- return this.shouldCloseTabSubtreeOf.apply(this, aArgs);
- }, // obsolete, for backward compatibility
-
- shouldCloseLastTabSubtreeOf : function TSTBase_shouldCloseLastTabSubtreeOf(aTab)
- {
- var b = this.getTabBrowserFromChild(aTab);
- return (
- b &&
- this.shouldCloseTabSubtreeOf(aTab) &&
- this.getDescendantTabs(aTab).length + 1 == this.getAllTabs(b).length
- );
- },
- shouldCloseLastTabSubTreeOf : function TSTBase_shouldCloseLastTabSubTreeOf(...aArgs) {
- return this.shouldCloseLastTabSubtreeOf.apply(this, aArgs);
- }, // obsolete, for backward compatibility
-
- getParentTab : function TSTBase_getParentTab(aTab) /* PUBLIC API */
- {
- if (!aTab)
- return null;
-
- var parent;
- var id = aTab.getAttribute(this.kPARENT);
- if (this.tabsHash) { // XPath-less implementation
- parent = this.getTabById(id);
- if (parent && !parent.parentNode && this.tabsHash) {
- delete this.tabsHash[id];
- parent = null;
- }
- }
- else {
- parent = this.evaluateXPath(
- 'preceding-sibling::xul:tab[@'+this.kID+'="'+id+'"][1]',
- aTab,
- Ci.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE
- ).singleNodeValue;
- }
- return (parent && parent != aTab) ? parent : null ;
- },
-
- getAncestorTabs : function TSTBase_getAncestorTabs(aTab) /* PUBLIC API */
- {
- var tabs = [aTab];
- var parentTab = aTab;
- while (parentTab = this.getParentTab(parentTab))
- {
- if (tabs.indexOf(parentTab) > -1) {
- let message = 'recursive tree detected!\n'+
- tabs.concat([parentTab])
- .reverse().map(function(aTab) {
- return ' '+aTab._tPos+' : '+
- aTab.label+'\n '+
- aTab.getAttribute(this.kID);
- }, this).join('\n');
- dump(message+'\n');
- break;
- }
-
- if (aTab._tPos < parentTab._tPos) {
- let message = 'broken tree detected!\n'+
- tabs.concat([parentTab])
- .reverse().map(function(aTab) {
- return ' '+aTab._tPos+' : '+
- aTab.label+'\n '+
- aTab.getAttribute(this.kID);
- }, this).join('\n');
- dump(message+'\n');
- }
-
- tabs.push(parentTab);
- aTab = parentTab;
- }
- return tabs.slice(1);
- },
-
- getRootTab : function TSTBase_getRootTab(aTab) /* PUBLIC API */
- {
- if (!aTab)
- return null;
-
- if (this.tabsHash) { // XPath-less implementation
- let ancestors = this.getAncestorTabs(aTab);
- return ancestors.length ? ancestors[ancestors.length-1] : aTab ;
- }
-
- return this.evaluateXPath(
- '(self::*[not(@'+this.kPARENT+')] | preceding-sibling::xul:tab[not(@'+this.kPARENT+')])[last()]',
- aTab,
- Ci.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE
- ).singleNodeValue;
- },
-
- getNextSiblingTab : function TSTBase_getNextSiblingTab(aTab) /* PUBLIC API */
- {
- if (!aTab)
- return null;
-
- if (this.tabsHash) { // XPath-less implementation
- let parentTab = this.getParentTab(aTab);
-
- if (!parentTab) {
- let next = aTab;
- do {
- next = next.nextSibling;
- }
- while (next &&
- next.nodeType == Ci.nsIDOMNode.ELEMENT_NODE &&
- this.getParentTab(next));
- return next;
- }
-
- let children = parentTab.getAttribute(this.kCHILDREN);
- if (children) {
- let list = ('|'+children).split('|'+aTab.getAttribute(this.kID));
- list = list.length > 1 ? list[1].split('|') : [] ;
- for (let i = 0, maxi = list.length; i < maxi; i++)
- {
- let firstChild = this.getTabById(list[i], aTab);
- if (firstChild)
- return firstChild;
- }
- }
- return null;
- }
-
- var parent = aTab.getAttribute(this.kPARENT);
- return this.evaluateXPath(
- 'following-sibling::xul:tab['+
- (parent ? '@'+this.kPARENT+'="'+parent+'"' : 'not(@'+this.kPARENT+')' )+
- '][1]',
- aTab,
- Ci.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE
- ).singleNodeValue;
- },
-
- getPreviousSiblingTab : function TSTBase_getPreviousSiblingTab(aTab) /* PUBLIC API */
- {
- if (!aTab)
- return null;
-
- if (this.tabsHash) { // XPath-less implementation
- let parentTab = this.getParentTab(aTab);
-
- if (!parentTab) {
- let prev = aTab;
- do {
- prev = prev.previousSibling;
- }
- while (prev &&
- prev.nodeType == Ci.nsIDOMNode.ELEMENT_NODE &&
- this.getParentTab(prev));
- return prev;
- }
-
- let children = parentTab.getAttribute(this.kCHILDREN);
- if (children) {
- let list = ('|'+children).split('|'+aTab.getAttribute(this.kID))[0].split('|');
- for (let i = list.length-1; i > -1; i--)
- {
- let lastChild = this.getTabById(list[i], aTab);
- if (lastChild)
- return lastChild;
- }
- }
- return null;
- }
-
- var parent = aTab.getAttribute(this.kPARENT);
- return this.evaluateXPath(
- 'preceding-sibling::xul:tab['+
- (parent ? '@'+this.kPARENT+'="'+parent+'"' : 'not(@'+this.kPARENT+')' )+
- '][1]',
- aTab,
- Ci.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE
- ).singleNodeValue;
- },
-
- getSiblingTabs : function TSTBase_getSiblingTabs(aTab) /* PUBLIC API */
- {
- var parent = this.getParentTab(aTab);
-
- var siblings = parent && parent.parentNode ? this.getChildTabs(parent) : this.visibleRootTabs ;
- return siblings.filter(function(aSiblingTab) {
- return aSiblingTab != aTab;
- });
- },
-
- getChildTabs : function TSTBase_getChildTabs(aTab, aAllTabsArray) /* PUBLIC API */
- {
- var tabs = [];
- if (!aTab)
- return tabs;
-
- var children = aTab.getAttribute(this.kCHILDREN);
- if (!children)
- return tabs;
-
- if (aAllTabsArray)
- tabs = aAllTabsArray;
-
- var list = children.split('|');
- for (let i = 0, maxi = list.length; i < maxi; i++)
- {
- let tab = this.getTabById(list[i], aTab);
- if (!tab || tab == aTab)
- continue;
- if (tabs.indexOf(tab) > -1) {
- let message = 'broken (possible recursive) tree detected!\n'+
- tabs.map(function(aTab) {
- return ' '+aTab._tPos+' : '+
- aTab.label+'\n '+
- aTab.getAttribute(this.kID);
- }, this).join('\n');
- dump(message+'\n');
- continue;
- }
- tabs.push(tab);
- if (aAllTabsArray)
- this.getChildTabs(tab, tabs);
- }
-
- return tabs;
- },
-
- hasChildTabs : function TSTBase_hasChildTabs(aTab) /* PUBLIC API */
- {
- if (!aTab)
- return false;
- return aTab.hasAttribute(this.kCHILDREN);
- },
-
- getDescendantTabs : function TSTBase_getDescendantTabs(aTab) /* PUBLIC API */
- {
- var tabs = [];
- this.getChildTabs(aTab, tabs);
- return tabs;
- },
-
- getFirstChildTab : function TSTBase_getFirstChildTab(aTab) /* PUBLIC API */
- {
- if (!aTab)
- return null;
-
- if (this.tabsHash) { // XPath-less implementation
- let children = aTab.getAttribute(this.kCHILDREN);
- let firstChild = null;
- if (children) {
- let list = children.split('|');
- for (let i = 0, maxi = list.length; i < maxi; i++)
- {
- firstChild = this.getTabById(list[i], aTab);
- if (firstChild && firstChild != aTab)
- break;
- }
- }
- return firstChild;
- }
-
- return this.evaluateXPath(
- 'following-sibling::xul:tab[@'+this.kPARENT+'="'+aTab.getAttribute(this.kID)+'"][1]',
- aTab,
- Ci.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE
- ).singleNodeValue;
- },
-
- getLastChildTab : function TSTBase_getLastChildTab(aTab) /* PUBLIC API */
- {
- if (!aTab)
- return null;
-
- if (this.tabsHash) { // XPath-less implementation
- let children = aTab.getAttribute(this.kCHILDREN);
- let lastChild = null;
- if (children) {
- let list = children.split('|');
- for (let i = list.length-1; i > -1; i--)
- {
- lastChild = this.getTabById(list[i], aTab);
- if (lastChild && lastChild != aTab)
- break;
- }
- }
- return lastChild;
- }
-
- return this.evaluateXPath(
- 'following-sibling::xul:tab[@'+this.kPARENT+'="'+aTab.getAttribute(this.kID)+'"][last()]',
- aTab,
- Ci.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE
- ).singleNodeValue;
- },
-
- getLastDescendantTab : function TSTBase_getLastDescendantTab(aTab) /* PUBLIC API */
- {
- if (!aTab)
- return null;
-
- if (this.tabsHash) { // XPath-less implementation
- let tabs = this.getDescendantTabs(aTab);
- return tabs.length ? tabs[tabs.length-1] : null ;
- }
-
- var parent = aTab.getAttribute(this.kPARENT);
- return this.evaluateXPath(
- 'following-sibling::xul:tab['+
- (parent ? '@'+this.kPARENT+'="'+parent+'"' : 'not(@'+this.kPARENT+')' )+
- '][1]/preceding-sibling::xul:tab[1][not(@'+this.kID+'="'+aTab.getAttribute(this.kID)+'")]',
- aTab,
- Ci.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE
- ).singleNodeValue;
- },
-
- collectRootTabs : function TSTBase_collectRootTabs(aTabs) /* PUBLIC API */
- {
- aTabs = Array.slice(aTabs);
- return aTabs.filter(function(aTab) {
- var parent = this.getParentTab(aTab);
- return !parent || aTabs.indexOf(parent) < 0;
- }, this);
- },
-
- getChildIndex : function TSTBase_getChildIndex(aTab, aParent) /* PUBLIC API */
- {
- var parent = this.getParentTab(aTab);
- if (!aParent || !parent || aParent != parent) {
- let tabs = [aTab].concat(this.getAncestorTabs(aTab));
- parent = aTab;
- for (let i = 0, maxi = tabs.length; i < maxi && parent != aParent; i++)
- {
- aTab = parent;
- parent = i < maxi ? tabs[i+1] : null ;
- }
- if (parent != aParent)
- return -1;
- aParent = parent;
- }
-
- if (aParent) {
- let children = aParent.getAttribute(this.kCHILDREN);
- let list = children.split('|');
- let id = aTab.getAttribute(this.kID);
- for (let i = 0, maxi = list.length; i < maxi; i++)
- {
- if (list[i] == id)
- return i;
- }
- return -1;
- }
- else {
- let tabs = this.rootTabs;
- for (let i = 0, maxi = tabs.length; i < maxi; i++)
- {
- if (tabs[i] == aTab)
- return i;
- }
- }
- return -1;
- },
-
- getXOffsetOfTab : function TSTBase_getXOffsetOfTab(aTab)
- {
- var extraCondition = this.canCollapseSubtree(aTab) ?
- '[not(@'+this.kCOLLAPSED+'="true")]' :
- '' ;
-
- return this.evaluateXPath(
- 'sum((self::* | preceding-sibling::xul:tab[not(@hidden="true")]'+extraCondition+')'+
- '/attribute::'+this.kX_OFFSET+')',
- aTab,
- Ci.nsIDOMXPathResult.NUMBER_TYPE
- ).numberValue;
- },
- getYOffsetOfTab : function TSTBase_getYOffsetOfTab(aTab)
- {
- var extraCondition = this.canCollapseSubtree(aTab) ?
- '[not(@'+this.kCOLLAPSED+'="true")]' :
- '';
-
- return this.evaluateXPath(
- 'sum((self::* | preceding-sibling::xul:tab[not(@hidden="true")]'+extraCondition+')'+
- '/attribute::'+this.kY_OFFSET+')',
- aTab,
- Ci.nsIDOMXPathResult.NUMBER_TYPE
- ).numberValue;
- },
- getFutureBoxObject : function TSTBase_getFutureBoxObject(aTab)
- {
- var tabBox = aTab.boxObject;
- var xOffset = this.getXOffsetOfTab(aTab);
- var yOffset = this.getYOffsetOfTab(aTab);
- return {
- width : tabBox.width,
- height : tabBox.height,
- x : tabBox.x + xOffset,
- y : tabBox.y + yOffset,
- screenX : tabBox.screenX + xOffset,
- screenY : tabBox.screenY + yOffset
- };
- },
- getTabActualScreenPosition : function TSTBase_getTabActualScreenPosition(aTab, aOrient)
- {
- aOrient = aOrient || aTab.parentNode.orient;
- return aOrient == 'vertical' ?
- this.getTabActualScreenY(aTab) :
- this.getTabActualScreenX(aTab) ;
- },
- MATRIX_PATTERN : /matrix\((-?\d+),\s*(-?\d+),\s*(-?\d+),\s*(-?\d+),\s*(-?\d+),\s*(-?\d+)\)/,
- getTabActualScreenX : function TSTBase_getTabActualScreenX(aTab)
- {
- var x = aTab.boxObject.screenX;
-
- var w = aTab.ownerDocument.defaultView;
- var transform = w.getComputedStyle(aTab, null).transform;
- var offset = transform && transform.match(this.MATRIX_PATTERN);
- offset = offset ? parseFloat(offset[5]) : 0 ;
-
- return x + offset;
- },
- getTabActualScreenY : function TSTBase_getTabActualScreenY(aTab)
- {
- var y = aTab.boxObject.screenY;
-
- var w = aTab.ownerDocument.defaultView;
- var transform = w.getComputedStyle(aTab, null).transform;
- var offset = transform && transform.match(this.MATRIX_PATTERN);
- offset = offset ? parseFloat(offset[6]) : 0 ;
-
- return y + offset;
- },
-
- isGroupTab : function TSTBase_isGroupTab(aTab, aLazyCheck)
- {
- return (
- (aLazyCheck || aTab.linkedBrowser.sessionHistory.count == 1) &&
- aTab.linkedBrowser.currentURI.spec.indexOf('about:treestyletab-group') == 0
- );
- },
-
- isTemporaryGroupTab : function TSTBase_isTemporaryGroupTab(aTab)
- {
- return (
- this.isGroupTab(aTab, true) &&
- /.*[\?&;]temporary=(?:1|yes|true)/i.test(aTab.linkedBrowser.currentURI.spec)
- );
- },
-
- get pinnedTabsCount()
- {
- return this.browser.mTabContainer.querySelectorAll('tab[pinned="true"]').length;
- },
-
- forceExpandTabs : function TSTBase_forceExpandTabs(aTabs)
- {
- var collapsedStates = aTabs.map(function(aTab) {
- return this.getTabValue(aTab, this.kSUBTREE_COLLAPSED) == 'true';
- }, this);
- for (let i = 0, maxi = aTabs.length; i < maxi; i++)
- {
- let tab = aTabs[i];
- this.collapseExpandSubtree(tab, false, true);
- this.collapseExpandTab(tab, false, true);
- }
- return collapsedStates;
- },
-
- getTreeStructureFromTabs : function TSTBase_getTreeStructureFromTabs(aTabs)
- {
- /* this returns...
- [A] => -1 (parent is not in this tree)
- [B] => 0 (parent is 1st item in this tree)
- [C] => 0 (parent is 1st item in this tree)
- [D] => 2 (parent is 2nd in this tree)
- [E] => -1 (parent is not in this tree, and this creates another tree)
- [F] => 0 (parent is 1st item in this another tree)
- */
- return this.cleanUpTreeStructureArray(
- aTabs.map(function(aTab, aIndex) {
- let tab = this.getParentTab(aTab);
- let index = tab ? aTabs.indexOf(tab) : -1 ;
- return index >= aIndex ? -1 : index ;
- }, this),
- -1
- );
- },
- cleanUpTreeStructureArray : function TSTBase_cleanUpTreeStructureArray(aTreeStructure, aDefaultParent)
- {
- var offset = 0;
- aTreeStructure = aTreeStructure
- .map(function(aPosition, aIndex) {
- return (aPosition == aIndex) ? -1 : aPosition ;
- })
- .map(function(aPosition, aIndex) {
- if (aPosition == -1) {
- offset = aIndex;
- return aPosition;
- }
- return aPosition - offset;
- });
-
- /* The final step, this validates all of values.
- Smaller than -1 is invalid, so it becomes to -1. */
- aTreeStructure = aTreeStructure.map(function(aIndex) {
- return aIndex < -1 ? aDefaultParent : aIndex ;
- }, this);
- return aTreeStructure;
- },
-
- applyTreeStructureToTabs : function TSTBase_applyTreeStructureToTabs(aTabs, aTreeStructure, aExpandStates)
- {
- var b = this.getTabBrowserFromChild(aTabs[0]);
- if (!b)
- return;
- var sv = b.treeStyleTab;
-
- aTabs = aTabs.slice(0, aTreeStructure.length);
- aTreeStructure = aTreeStructure.slice(0, aTabs.length);
-
- aExpandStates = (aExpandStates && typeof aExpandStates == 'object') ?
- aExpandStates :
- aTabs.map(function(aTab) {
- return !!aExpandStates;
- });
- aExpandStates = aExpandStates.slice(0, aTabs.length);
- while (aExpandStates.length < aTabs.length) aExpandStates.push(-1);
-
- var parentTab = null;
- for (let i = 0, maxi = aTabs.length; i < maxi; i++)
- {
- let tab = aTabs[i];
- if (sv.isCollapsed(tab))
- sv.collapseExpandTab(tab, false, true);
- sv.detachTab(tab);
-
- let parentIndexInTree = aTreeStructure[i];
- if (parentIndexInTree < 0) // there is no parent, so this is a new parent!
- parentTab = tab.getAttribute(sv.kID);
-
- let parent = sv.getTabById(parentTab);
- if (parent) {
- let tabs = [parent].concat(sv.getDescendantTabs(parent));
- parent = parentIndexInTree < tabs.length ? tabs[parentIndexInTree] : parent ;
- }
- if (parent) {
- sv.attachTabTo(tab, parent, {
- forceExpand : true,
- dontMove : true
- });
- }
- }
-
- for (let i = aTabs.length-1; i > -1; i--)
- {
- sv.collapseExpandSubtree(aTabs[i], !sv.hasChildTabs(aTabs[i]) || !aExpandStates[i], true);
- }
- },
-
- getTreeStructureFromTabBrowser : function TSTBase_getTreeStructureFromTabBrowser(aTabBrowser)
- {
- return this.getTreeStructureFromTabs(this.getAllTabs(aTabBrowser));
- },
-
- applyTreeStructureToTabBrowser : function TSTBase_applyTreeStructureToTabBrowser(aTabBrowser, aTreeStructure, aExpandAllTree)
- {
- var tabs = this.getAllTabs(aTabBrowser);
- return this.applyTreeStructureToTabs(tabs, aTreeStructure, aExpandAllTree);
- },
-
-/* tabbar position */
-
- get position() /* PUBLIC API */
- {
- return utils.getTreePref('tabbar.position') || 'top';
- },
- set position(aValue)
- {
- var position = String(aValue).toLowerCase();
- if (!position || !/^(top|bottom|left|right)$/.test(position))
- position = 'top';
-
- if (position != utils.getTreePref('tabbar.position'))
- utils.setTreePref('tabbar.position', position);
-
- return aValue;
- },
- get currentTabbarPosition() /* for backward compatibility */
- {
- return this.position;
- },
- set currentTabbarPosition(aValue)
- {
- return this.position = aValue;
- },
-
- getPositionFlag : function TSTBase_getPositionFlag(aPosition)
- {
- aPosition = String(aPosition).toLowerCase();
- return (aPosition == 'left') ? this.kTABBAR_LEFT :
- (aPosition == 'right') ? this.kTABBAR_RIGHT :
- (aPosition == 'bottom') ? this.kTABBAR_BOTTOM :
- this.kTABBAR_TOP;
- },
-
-/* Pref Listener */
-
- domains : [
- 'extensions.treestyletab.',
- 'browser.tabs.animate',
- 'browser.tabs.insertRelatedAfterCurrent',
- 'extensions.stm.tabBarMultiRows' // Super Tab Mode
- ],
-
- observe : function TSTBase_observe(aSubject, aTopic, aData)
- {
- switch (aTopic)
- {
- case 'nsPref:changed':
- this.onPrefChange(aData);
- return;
- }
- },
-
- onPrefChange : function TSTBase_onPrefChange(aPrefName)
- {
- var value = prefs.getPref(aPrefName);
- switch (aPrefName)
- {
- case 'extensions.treestyletab.indent.vertical':
- this.baseIndentVertical = value;
- Services.obs.notifyObservers(null, this.kTOPIC_INDENT_MODIFIED, value);
- return;
- case 'extensions.treestyletab.indent.horizontal':
- this.baseIndentHorizontal = value;
- Services.obs.notifyObservers(null, this.kTOPIC_INDENT_MODIFIED, value);
- return;
-
- case 'extensions.treestyletab.tabbar.width':
- case 'extensions.treestyletab.tabbar.shrunkenWidth':
- return this.updateTabWidthPrefs(aPrefName);
-
- case 'browser.tabs.insertRelatedAfterCurrent':
- case 'extensions.stm.tabBarMultiRows': // Super Tab Mode
- if (this.prefOverriding)
- return;
- aPrefName += '.override';
- prefs.setPref(aPrefName, value);
- case 'browser.tabs.insertRelatedAfterCurrent.override':
- case 'extensions.stm.tabBarMultiRows.override': // Super Tab Mode
- if (prefs.getPref(aPrefName+'.force')) {
- let defaultValue = prefs.getDefaultPref(aPrefName);
- if (value != defaultValue) {
- prefs.setPref(aPrefName, defaultValue);
- return;
- }
- }
- this.prefOverriding = true;
- let (target = aPrefName.replace('.override', '')) {
- let originalValue = prefs.getPref(target);
- if (originalValue !== null && originalValue != value)
- prefs.setPref(target+'.backup', originalValue);
- prefs.setPref(target, prefs.getPref(aPrefName));
- }
- this.prefOverriding = false;
- return;
-
- case 'extensions.treestyletab.clickOnIndentSpaces.enabled':
- return this.shouldDetectClickOnIndentSpaces = prefs.getPref(aPrefName);
-
- case 'extensions.treestyletab.tabbar.scroll.smooth':
- return this.smoothScrollEnabled = value;
- case 'extensions.treestyletab.tabbar.scroll.duration':
- return this.smoothScrollDuration = value;
-
- case 'extensions.treestyletab.tabbar.scrollToNewTab.mode':
- return this.scrollToNewTabMode = value;
-
- case 'extensions.treestyletab.tabbar.narrowScrollbar.size':
- return this.updateNarrowScrollbarStyle();
-
- case 'browser.tabs.animate':
- return this.animationEnabled = value;
- case 'extensions.treestyletab.animation.indent.duration':
- return this.indentDuration = value;
- case 'extensions.treestyletab.animation.collapse.duration':
- return this.collapseDuration = value;
-
- case 'extensions.treestyletab.twisty.expandSensitiveArea':
- return this.shouldExpandTwistyArea = value;
-
- case 'extensions.treestyletab.counter.role.horizontal':
- return this.counterRoleHorizontal = value;
-
- case 'extensions.treestyletab.counter.role.vertical':
- return this.counterRoleVertical = value;
-
- default:
- return;
- }
- },
-
- updateTabWidthPrefs : function TSTBase_updateTabWidthPrefs(aPrefName)
- {
- var expanded = utils.getTreePref('tabbar.width');
- var shrunken = utils.getTreePref('tabbar.shrunkenWidth');
- var originalExpanded = expanded;
- var originalShrunken = shrunken;
- if (aPrefName == 'extensions.treestyletab.tabbar.shrunkenWidth') {
- if (expanded <= shrunken)
- expanded = parseInt(shrunken / this.DEFAULT_SHRUNKEN_WIDTH_RATIO)
- let w = this.browserWindow;
- if (w && expanded > w.gBrowser.boxObject.width) {
- expanded = w.gBrowser.boxObject.width * this.MAX_TABBAR_SIZE_RATIO;
- if (expanded <= shrunken)
- shrunken = parseInt(expanded * this.DEFAULT_SHRUNKEN_WIDTH_RATIO)
- }
- }
- else {
- if (expanded <= shrunken)
- shrunken = parseInt(expanded * this.DEFAULT_SHRUNKEN_WIDTH_RATIO);
- }
- if (expanded != originalExpanded ||
- shrunken != originalShrunken) {
- utils.setTreePref('tabbar.width', Math.max(0, expanded));
- utils.setTreePref('tabbar.shrunkenWidth', Math.max(0, shrunken));
- }
- },
-
- get shouldApplyNewPref()
- {
- return (
- !this.applyOnlyForActiveWindow ||
- this.window == this.topBrowserWindow
- ) &&
- !this.inWindowDestoructionProcess;
- },
-
- applyOnlyForActiveWindow : false,
- setPrefForActiveWindow : function TSTBase_setPrefForActiveWindow(aTask) {
- TreeStyleTabBase.applyOnlyForActiveWindow = true;
- try {
- aTask.call(this);
- }
- finally {
- TreeStyleTabBase.applyOnlyForActiveWindow = false;
- }
- }
-
-});
-
-TreeStyleTabBase.init();
-
+/* ***** 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 YUKI "Piro" Hiroshi.
+ * Portions created by the Initial Developer are Copyright (C) 2010-2014
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s): YUKI "Piro" Hiroshi
+ * Tetsuharu OHZEKI
+ *
+ * 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 ******/
+
+const EXPORTED_SYMBOLS = ['TreeStyleTabBase'];
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+const Cu = Components.utils;
+
+Cu.import('resource://gre/modules/XPCOMUtils.jsm');
+Cu.import('resource://gre/modules/Services.jsm');
+Cu.import('resource://gre/modules/Timer.jsm');
+Cu.import('resource://treestyletab-modules/lib/inherit.jsm');
+Cu.import('resource://treestyletab-modules/constants.js');
+
+XPCOMUtils.defineLazyGetter(this, 'window', function() {
+ Cu.import('resource://treestyletab-modules/lib/namespace.jsm');
+ return getNamespaceFor('piro.sakura.ne.jp');
+});
+XPCOMUtils.defineLazyGetter(this, 'prefs', function() {
+ Cu.import('resource://treestyletab-modules/lib/prefs.js');
+ return window['piro.sakura.ne.jp'].prefs;
+});
+XPCOMUtils.defineLazyGetter(this, 'extensions', function() {
+ Cu.import('resource://treestyletab-modules/lib/extensions.js', {});
+ return window['piro.sakura.ne.jp'].extensions;
+});
+XPCOMUtils.defineLazyGetter(this, 'animationManager', function() {
+ Cu.import('resource://treestyletab-modules/lib/animationManager.js', {});
+ return window['piro.sakura.ne.jp'].animationManager;
+});
+XPCOMUtils.defineLazyGetter(this, 'autoScroll', function() {
+ Cu.import('resource://treestyletab-modules/lib/autoScroll.js', {});
+ return window['piro.sakura.ne.jp'].autoScroll;
+});
+XPCOMUtils.defineLazyModuleGetter(this, 'UninstallationListener',
+ 'resource://treestyletab-modules/lib/UninstallationListener.js');
+XPCOMUtils.defineLazyModuleGetter(this, 'Deferred',
+ 'resource://treestyletab-modules/lib/jsdeferred.js');
+XPCOMUtils.defineLazyModuleGetter(this, 'confirmWithPopup', 'resource://treestyletab-modules/lib/confirmWithPopup.js');
+XPCOMUtils.defineLazyModuleGetter(this, 'utils', 'resource://treestyletab-modules/utils.js', 'TreeStyleTabUtils');
+
+XPCOMUtils.defineLazyServiceGetter(this, 'SessionStore',
+ '@mozilla.org/browser/sessionstore;1', 'nsISessionStore');
+
+if (Services.appinfo.OS === 'WINNT') {
+ XPCOMUtils.defineLazyModuleGetter(this, 'AeroPeek',
+ 'resource:///modules/WindowsPreviewPerTab.jsm', 'AeroPeek');
+}
+else {
+ this.AeroPeek = null;
+}
+
+var TreeStyleTabBase = inherit(TreeStyleTabConstants, {
+
+ tabsHash : null,
+ inWindowDestoructionProcess : false,
+
+/* base variables */
+ baseIndentVertical : 12,
+ baseIndentHorizontal : 4,
+ shouldDetectClickOnIndentSpaces : true,
+
+ smoothScrollEnabled : true,
+ smoothScrollDuration : 150,
+
+ animationEnabled : true,
+ indentDuration : 200,
+ collapseDuration : 150,
+
+ shouldExpandTwistyArea : true,
+
+ scrollToNewTabMode : false,
+
+ counterRoleHorizontal : -1,
+ counterRoleVertical : -1,
+
+ get SessionStore() {
+ return SessionStore;
+ },
+
+ get extensions() { return extensions; },
+ get animationManager() { return animationManager; },
+ get autoScroll() { return autoScroll; },
+ get Deferred() { return Deferred; },
+ get AeroPeek() { return AeroPeek; }, // for Windows
+
+ init : function TSTBase_init()
+ {
+ if (this._initialized)
+ return;
+
+ this.isMac = Services.appinfo.OS == 'Darwin';
+
+ this.applyPlatformDefaultPrefs();
+ utils.migratePrefs();
+
+ prefs.addPrefListener(this);
+
+ this.initUninstallationListener();
+
+ this.onPrefChange('extensions.treestyletab.indent.vertical');
+ this.onPrefChange('extensions.treestyletab.indent.horizontal');
+ this.onPrefChange('extensions.treestyletab.clickOnIndentSpaces.enabled');
+ this.onPrefChange('browser.tabs.insertRelatedAfterCurrent.override');
+ this.onPrefChange('extensions.stm.tabBarMultiRows.override'); // Super Tab Mode
+ this.onPrefChange('extensions.treestyletab.tabbar.scroll.smooth');
+ this.onPrefChange('extensions.treestyletab.tabbar.scroll.duration');
+ this.onPrefChange('extensions.treestyletab.tabbar.scrollToNewTab.mode');
+ this.onPrefChange('extensions.treestyletab.tabbar.narrowScrollbar.size');
+ this.onPrefChange('browser.tabs.animate');
+ this.onPrefChange('extensions.treestyletab.animation.indent.duration');
+ this.onPrefChange('extensions.treestyletab.animation.collapse.duration');
+ this.onPrefChange('extensions.treestyletab.twisty.expandSensitiveArea');
+ this.onPrefChange('extensions.treestyletab.counter.role.horizontal');
+ this.onPrefChange('extensions.treestyletab.counter.role.vertical');
+
+ try {
+ this.overrideExtensions();
+ }
+ catch(e) {
+ dump(e+'\n');
+ }
+ },
+ _initialized : false,
+
+ applyPlatformDefaultPrefs : function TSTBase_applyPlatformDefaultPrefs()
+ {
+ var OS = Services.appinfo.OS;
+ var processed = {};
+ var originalKeys = prefs.getDescendant('extensions.treestyletab.platform.'+OS);
+ for (let i = 0, maxi = originalKeys.length; i < maxi; i++)
+ {
+ let originalKey = originalKeys[i];
+ let key = originalKey.replace('platform.'+OS+'.', '');
+ prefs.setDefaultPref(key, prefs.getPref(originalKey));
+ processed[key] = true;
+ }
+ originalKeys = prefs.getDescendant('extensions.treestyletab.platform.default');
+ for (let i = 0, maxi = originalKeys.length; i < maxi; i++)
+ {
+ let originalKey = originalKeys[i];
+ let key = originalKey.replace('platform.default.', '');
+ if (!(key in processed))
+ prefs.setDefaultPref(key, prefs.getPref(originalKey));
+ }
+ },
+
+ initUninstallationListener : function TSTWindow_initUninstallationListener()
+ {
+ var restorePrefs = function() {
+ // Remove pref listener before restore backuped prefs.
+ prefs.removePrefListener(this);
+
+ let restorePrefs = [
+ 'browser.tabs.insertRelatedAfterCurrent',
+ 'extensions.stm.tabBarMultiRows' // Super Tab Mode
+ ];
+ for (let i = 0, maxi = restorePrefs.length; i < maxi; i++)
+ {
+ let pref = restorePrefs[i];
+ let backup = prefs.getPref(pref+'.backup');
+ if (backup === null)
+ continue;
+ // restore user preference.
+ prefs.setPref(pref, backup);
+ // clear backup pref.
+ prefs.clearPref(pref+'.backup');
+ }
+ }.bind(this);
+ new UninstallationListener({
+ id : 'treestyletab@piro.sakura.ne.jp',
+ onuninstalled : restorePrefs,
+ ondisabled : restorePrefs
+ });
+ },
+
+ overrideExtensions : function TSTBase_overrideExtensions()
+ {
+ // Scriptish
+ // https://addons.mozilla.org/firefox/addon/scriptish/
+ if (utils.getTreePref('compatibility.Scriptish')) {
+ try {
+ let tabModule = Cu.import('resource://scriptish/utils/Scriptish_openInTab.js', {});
+ let Scriptish_openInTab = tabModule.Scriptish_openInTab;
+ tabModule.Scriptish_openInTab = function(aURL, aLoadInBackground, aReuse, aChromeWin, ...aExtraArgs) {
+ try {
+ aChromeWin.TreeStyleTabService.readyToOpenChildTabNow(aChromeWin.gBrowser);
+ }
+ catch(e) {
+ Cu.reportError(e);
+ }
+ var allArgs = [aURL, aLoadInBackground, aReuse, aChromeWin].concat(aExtraArgs);
+ return Scriptish_openInTab.apply(this, allArgs);
+ };
+ }
+ catch(e) {
+ }
+ }
+ },
+
+ updateNarrowScrollbarStyle : function TSTBase_updateNarrowScrollbarStyle()
+ {
+ const SSS = Cc['@mozilla.org/content/style-sheet-service;1']
+ .getService(Ci.nsIStyleSheetService);
+
+ if (this.lastAgentSheet &&
+ SSS.sheetRegistered(this.lastAgentSheet, SSS.AGENT_SHEET))
+ SSS.unregisterSheet(this.lastAgentSheet, SSS.AGENT_SHEET);
+
+ const style = 'data:text/css,'+encodeURIComponent(
+ ('@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");' +
+
+ 'tabs.tabbrowser-tabs[%MODE%="vertical"][%NARROW%="true"]' +
+ ' .tabbrowser-arrowscrollbox' +
+ ' > scrollbox' +
+ ' > scrollbar[orient="vertical"],' +
+ 'tabs.tabbrowser-tabs[%MODE%="vertical"][%NARROW%="true"]' +
+ ' .tabbrowser-arrowscrollbox' +
+ ' > scrollbox' +
+ ' > scrollbar[orient="vertical"] * {' +
+ ' max-width: %SIZE%;' +
+ ' min-width: %SIZE%;' +
+ '}' +
+
+ 'tabs.tabbrowser-tabs[%MODE%="vertical"][%NARROW%="true"]' +
+ ' .tabbrowser-arrowscrollbox' +
+ ' > scrollbox' +
+ ' > scrollbar[orient="vertical"] {' +
+ ' font-size: %SIZE%;' +
+ '}' +
+
+ 'tabs.tabbrowser-tabs[%MODE%="vertical"][%NARROW%="true"]' +
+ ' .tabbrowser-arrowscrollbox' +
+ ' > scrollbox' +
+ ' > scrollbar[orient="vertical"] * {' +
+ ' padding-left: 0;' +
+ ' padding-right: 0;' +
+ ' margin-left: 0;' +
+ ' margin-right: 0;' +
+ '}' +
+
+ '%FORCE_NARROW_SCROLLBAR%')
+ .replace(/%FORCE_NARROW_SCROLLBAR%/g,
+ utils.getTreePref('tabbar.narrowScrollbar.overrideSystemAppearance') ?
+ this.kOVERRIDE_SYSTEM_SCROLLBAR_APPEARANCE : '' )
+ .replace(/%MODE%/g, this.kMODE)
+ .replace(/%NARROW%/g, this.kNARROW_SCROLLBAR)
+ .replace(/%SIZE%/g, utils.getTreePref('tabbar.narrowScrollbar.size'))
+ );
+ this.lastAgentSheet = this.makeURIFromSpec(style);
+ SSS.loadAndRegisterSheet(this.lastAgentSheet, SSS.AGENT_SHEET);
+ },
+ kOVERRIDE_SYSTEM_SCROLLBAR_APPEARANCE :
+ 'tabs.tabbrowser-tabs[%MODE%="vertical"][%NARROW%="true"]' +
+ ' .tabbrowser-arrowscrollbox' +
+ ' > scrollbox' +
+ ' > scrollbar[orient="vertical"] {' +
+ ' appearance: none;' +
+ ' -moz-appearance: none;' +
+ ' background: ThreeDFace;' +
+ ' border: 1px solid ThreeDShadow;' +
+ '}',
+ lastAgentSheet : null,
+
+/* references to the owner */
+
+ get browserWindow()
+ {
+ return this.topBrowserWindow;
+ },
+ get topBrowserWindow()
+ {
+ return Services.wm.getMostRecentWindow('navigator:browser');
+ },
+
+ get browserWindows()
+ {
+ var windows = [];
+
+ var targets = Services.wm.getZOrderDOMWindowEnumerator('navigator:browser', true);
+ // By the bug 156333, we cannot find windows by their Z order on Linux.
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=156333
+ if (!targets.hasMoreElements())
+ targets = Services.wm.getEnumerator('navigator:browser');
+
+ while (targets.hasMoreElements())
+ {
+ let target = targets.getNext()
+ .QueryInterface(Ci.nsIDOMWindow);
+ windows.push(target);
+ }
+
+ return windows;
+ },
+
+ get browser()
+ {
+ var w = this.browserWindow;
+ return !w ? null :
+ 'SplitBrowser' in w ? w.SplitBrowser.activeBrowser :
+ w.gBrowser ;
+ },
+
+ get window()
+ {
+ return this.browser.ownerDocument.defaultView;
+ },
+
+ get currentDragSession()
+ {
+ return Cc['@mozilla.org/widget/dragservice;1']
+ .getService(Ci.nsIDragService)
+ .getCurrentSession();
+ },
+
+/* calculated behaviors */
+
+ dropLinksOnTabBehavior : function TSTBase_dropLinksOnTabBehavior()
+ {
+ var behavior = utils.getTreePref('dropLinksOnTab.behavior');
+ if (behavior & this.kDROPLINK_FIXED)
+ return behavior;
+
+ var checked = { value : false };
+ var newChildTab = Services.prompt.confirmEx(this.browserWindow,
+ utils.treeBundle.getString('dropLinkOnTab.title'),
+ utils.treeBundle.getString('dropLinkOnTab.text'),
+ (Services.prompt.BUTTON_TITLE_IS_STRING * Services.prompt.BUTTON_POS_0) +
+ (Services.prompt.BUTTON_TITLE_IS_STRING * Services.prompt.BUTTON_POS_1),
+ utils.treeBundle.getString('dropLinkOnTab.openNewChildTab'),
+ utils.treeBundle.getString('dropLinkOnTab.loadInTheTab'),
+ null,
+ utils.treeBundle.getString('dropLinkOnTab.never'),
+ checked
+ ) == 0;
+
+ behavior = newChildTab ? this.kDROPLINK_NEWTAB : this.kDROPLINK_LOAD ;
+ if (checked.value)
+ utils.setTreePref('dropLinksOnTab.behavior', behavior);
+
+ return behavior
+ },
+ kDROPLINK_ASK : 0,
+ kDROPLINK_FIXED : 1 + 2,
+ kDROPLINK_LOAD : 1,
+ kDROPLINK_NEWTAB : 2,
+
+ openGroupBookmarkBehavior : function TSTBase_openGroupBookmarkBehavior()
+ {
+ var behavior = utils.getTreePref('openGroupBookmark.behavior');
+ if (behavior & this.kGROUP_BOOKMARK_FIXED)
+ return behavior;
+
+ var dummyTabFlag = behavior & this.kGROUP_BOOKMARK_USE_DUMMY;
+
+ var checked = { value : false };
+ var button = Services.prompt.confirmEx(this.browserWindow,
+ utils.treeBundle.getString('openGroupBookmarkBehavior.title'),
+ utils.treeBundle.getString('openGroupBookmarkBehavior.text'),
+ (Services.prompt.BUTTON_TITLE_IS_STRING * Services.prompt.BUTTON_POS_0) +
+ (Services.prompt.BUTTON_TITLE_IS_STRING * Services.prompt.BUTTON_POS_1),
+ utils.treeBundle.getString('openGroupBookmarkBehavior.subTree'),
+ utils.treeBundle.getString('openGroupBookmarkBehavior.separate'),
+ null,
+ utils.treeBundle.getString('openGroupBookmarkBehavior.never'),
+ checked
+ );
+
+ if (button < 0)
+ button = 1;
+ var behaviors = [
+ this.kGROUP_BOOKMARK_SUBTREE | dummyTabFlag,
+ this.kGROUP_BOOKMARK_SEPARATE
+ ];
+ behavior = behaviors[button];
+
+ if (checked.value) {
+ utils.setTreePref('openGroupBookmark.behavior', behavior);
+ }
+ return behavior;
+ },
+ kGROUP_BOOKMARK_ASK : 0,
+ kGROUP_BOOKMARK_FIXED : 1 + 2 + 4,
+ kGROUP_BOOKMARK_SUBTREE : 1,
+ kGROUP_BOOKMARK_SEPARATE : 2,
+ kGROUP_BOOKMARK_USE_DUMMY : 256,
+ kGROUP_BOOKMARK_USE_DUMMY_FORCE : 1024,
+ kGROUP_BOOKMARK_DONT_RESTORE_TREE_STRUCTURE : 512,
+ kGROUP_BOOKMARK_EXPAND_ALL_TREE : 2048,
+
+ bookmarkDroppedTabsBehavior : function TSTBase_bookmarkDroppedTabsBehavior()
+ {
+ var behavior = utils.getTreePref('bookmarkDroppedTabs.behavior');
+ if (behavior & this.kBOOKMARK_DROPPED_TABS_FIXED)
+ return behavior;
+
+ var checked = { value : false };
+ var button = Services.prompt.confirmEx(this.browserWindow,
+ utils.treeBundle.getString('bookmarkDroppedTabs.title'),
+ utils.treeBundle.getString('bookmarkDroppedTabs.text'),
+ (Services.prompt.BUTTON_TITLE_IS_STRING * Services.prompt.BUTTON_POS_0) +
+ (Services.prompt.BUTTON_TITLE_IS_STRING * Services.prompt.BUTTON_POS_1),
+ utils.treeBundle.getString('bookmarkDroppedTabs.bookmarkAll'),
+ utils.treeBundle.getString('bookmarkDroppedTabs.bookmarkOnlyParent'),
+ null,
+ utils.treeBundle.getString('bookmarkDroppedTabs.never'),
+ checked
+ );
+
+ if (button < 0)
+ button = 1;
+ var behaviors = [
+ this.kBOOKMARK_DROPPED_TABS_ALL,
+ this.kBOOKMARK_DROPPED_TABS_ONLY_PARENT
+ ];
+ behavior = behaviors[button];
+
+ if (checked.value)
+ utils.setTreePref('bookmarkDroppedTabs.behavior', behavior);
+
+ return behavior;
+ },
+ kBOOKMARK_DROPPED_TABS_ASK : 0,
+ kBOOKMARK_DROPPED_TABS_FIXED : 1 | 2,
+ kBOOKMARK_DROPPED_TABS_ALL : 1,
+ kBOOKMARK_DROPPED_TABS_ONLY_PARENT : 2,
+
+ askUndoCloseTabSetBehavior : function TSTBase_askUndoCloseTabSetBehavior(aRestoredTab, aCount)
+ {
+ var behavior = this.undoCloseTabSetBehavior;
+ if (behavior & this.kUNDO_CLOSE_SET)
+ behavior ^= this.kUNDO_CLOSE_SET;
+
+ var self = this;
+ return confirmWithPopup({
+ browser : aRestoredTab.linkedBrowser,
+ label : utils.treeBundle.getFormattedString('undoCloseTabSetBehavior.label', [aCount]),
+ value : 'treestyletab-undo-close-tree',
+ image : 'chrome://treestyletab/content/res/icon.png',
+ buttons : [
+ utils.treeBundle.getString('undoCloseTabSetBehavior.restoreOnce'),
+ utils.treeBundle.getString('undoCloseTabSetBehavior.restoreForever'),
+ utils.treeBundle.getString('undoCloseTabSetBehavior.ignoreForever')
+ ],
+ persistence : -1 // don't hide even if the tab is restored after the panel is shown.
+ })
+ .next(function(aButtonIndex) {
+ if (aButtonIndex < 2) {
+ behavior |= self.kUNDO_CLOSE_SET;
+ }
+ if (aButtonIndex > 0) {
+ behavior ^= self.kUNDO_ASK;
+ utils.setTreePref('undoCloseTabSet.behavior', behavior);
+ }
+ return behavior;
+ });
+ },
+ get undoCloseTabSetBehavior()
+ {
+ return utils.getTreePref('undoCloseTabSet.behavior');
+ },
+ kUNDO_ASK : 1,
+ kUNDO_CLOSE_SET : 2,
+ kUNDO_CLOSE_FULL_SET : 256,
+
+/* utilities */
+
+ doAndWaitDOMEvent : function TSTBase_doAndWaitDOMEvent(...aArgs)
+ {
+ var type, target, delay, task;
+ for (let i = 0, maxi = aArgs.length; i < maxi; i++)
+ {
+ let arg = aArgs[i];
+ switch(typeof arg)
+ {
+ case 'string':
+ type = arg;
+ continue;
+
+ case 'number':
+ delay = arg;
+ continue;
+
+ case 'function':
+ task = arg;
+ continue;
+
+ default:
+ target = arg;
+ continue;
+ }
+ }
+
+ if (!target || !type) {
+ if (task)
+ task();
+ return;
+ }
+
+ var done = false;
+ var listener = function(aEvent) {
+ setTimeout(function() {
+ done = true;
+ }, delay || 0);
+ target.removeEventListener(type, listener, false);
+ };
+
+ if (task)
+ Deferred.next(function() {
+ try {
+ task();
+ }
+ catch(e) {
+ dump(e+'\n');
+ target.removeEventListener(type, listener, false);
+ done = true;
+ }
+ }).error(this.defaultDeferredErrorHandler);
+
+ target.addEventListener(type, listener, false);
+
+ var thread = Components
+ .classes['@mozilla.org/thread-manager;1']
+ .getService()
+ .mainThread;
+ while (!done)
+ {
+ //dump('WAIT '+type+' '+Date.now()+'\n');
+ thread.processNextEvent(true);
+ }
+ },
+
+ findOffsetParent : function TSTBase_findOffsetParent(aNode)
+ {
+ var parent = aNode.parentNode;
+ var doc = aNode.ownerDocument || aNode;
+ var view = doc.defaultView;
+ while (parent && parent instanceof Ci.nsIDOMElement)
+ {
+ let position = view.getComputedStyle(parent, null).getPropertyValue('position');
+ if (position != 'static')
+ return parent;
+ parent = parent.parentNode;
+ }
+ return doc.documentElement;
+ },
+
+ assertBeforeDestruction : function TSTBase_assertBeforeDestruction(aNotDestructed)
+ {
+ if (aNotDestructed)
+ return;
+
+ var message = 'ERROR: accessed after destruction!';
+ var error = new Error(message);
+ dump(message+'\n'+error.stack+'\n');
+ throw error;
+ },
+
+ defaultDeferredErrorHandler : function TSTBase_defaultDeferredErrorHandler(aError)
+ {
+ if (aError.stack)
+ Cu.reportError(aError.message+'\n'+aError.stack);
+ else
+ Cu.reportError(aError);
+ },
+
+// event
+
+ isNewTabAction : function TSTBase_isNewTabAction(aEvent)
+ {
+ return aEvent.button == 1 || (aEvent.button == 0 && this.isAccelKeyPressed(aEvent));
+ },
+
+ isAccelKeyPressed : function TSTBase_isAccelKeyPressed(aEvent)
+ {
+ if ( // this is releasing of the accel key!
+ (aEvent.type == 'keyup') &&
+ (aEvent.keyCode == (this.isMac ? Ci.nsIDOMKeyEvent.DOM_VK_META : Ci.nsIDOMKeyEvent.DOM_VK_CONTROL ))
+ ) {
+ return false;
+ }
+ return this.isMac ?
+ (aEvent.metaKey || (aEvent.keyCode == Ci.nsIDOMKeyEvent.DOM_VK_META)) :
+ (aEvent.ctrlKey || (aEvent.keyCode == Ci.nsIDOMKeyEvent.DOM_VK_CONTROL)) ;
+ },
+
+ isCopyAction : function TSTBase_isCopyAction(aEvent)
+ {
+ return this.isAccelKeyPressed(aEvent) ||
+ (aEvent.dataTransfer && aEvent.dataTransfer.dropEffect == 'copy');
+ },
+
+ isEventFiredOnClosebox : function TSTBase_isEventFiredOnClosebox(aEvent)
+ {
+ return this.evaluateXPath(
+ 'ancestor-or-self::*[contains(concat(" ", normalize-space(@class), " "), " tab-close-button ")]',
+ aEvent.originalTarget || aEvent.target,
+ Ci.nsIDOMXPathResult.BOOLEAN_TYPE
+ ).booleanValue;
+ },
+
+ isEventFiredOnClickable : function TSTBase_isEventFiredOnClickable(aEvent)
+ {
+ return this.evaluateXPath(
+ 'ancestor-or-self::*[contains(" button toolbarbutton scrollbar nativescrollbar popup menupopup panel tooltip splitter textbox ", concat(" ", local-name(), " "))]',
+ aEvent.originalTarget,
+ Ci.nsIDOMXPathResult.BOOLEAN_TYPE
+ ).booleanValue;
+ },
+
+ isEventFiredOnScrollbar : function TSTBase_isEventFiredOnScrollbar(aEvent)
+ {
+ return this.evaluateXPath(
+ 'ancestor-or-self::*[local-name()="scrollbar" or local-name()="nativescrollbar"]',
+ aEvent.originalTarget,
+ Ci.nsIDOMXPathResult.BOOLEAN_TYPE
+ ).booleanValue;
+ },
+
+ isEventFiredOnTwisty : function TSTBase_isEventFiredOnTwisty(aEvent)
+ {
+ var tab = this.getTabFromEvent(aEvent);
+ if (!tab ||
+ !this.hasChildTabs(tab) ||
+ !this.canCollapseSubtree(tab))
+ return false;
+
+ var twisty = tab.ownerDocument.getAnonymousElementByAttribute(tab, 'class', this.kTWISTY);
+ if (!twisty)
+ return false;
+
+ var box = twisty.boxObject;
+ var left = box.screenX;
+ var top = box.screenY;
+ var right = left + box.width;
+ var bottom = top + box.height;
+ var favicon = this.getFaviconRect(tab);
+ if (!box.width || !box.height) {
+ left = favicon.left;
+ top = favicon.top;
+ right = favicon.right;
+ bottom = favicon.bottom;
+ }
+ else if (
+ this.shouldExpandTwistyArea &&
+ !this._expandTwistyAreaBlockers.length
+ ) {
+ left = Math.min(left, favicon.left);
+ top = Math.min(top, favicon.top);
+ right = Math.max(right, favicon.right);
+ bottom = Math.max(bottom, favicon.bottom);
+ }
+
+ var x = aEvent.screenX;
+ var y = aEvent.screenY;
+ return (x >= left && x <= right && y >= top && y <= bottom);
+ },
+ getFaviconRect : function TSTBase_getFaviconRect(aTab)
+ {
+ var icon = aTab.ownerDocument.getAnonymousElementByAttribute(aTab, 'class', 'tab-icon-image');
+ var iconBox = icon.boxObject;
+ var iconRect = {
+ left : iconBox.screenX,
+ top : iconBox.screenY,
+ right : iconBox.screenX + iconBox.width,
+ bottom : iconBox.screenY + iconBox.height
+ };
+
+ var throbber = aTab.ownerDocument.getAnonymousElementByAttribute(aTab, 'class', 'tab-throbber');
+ var throbberBox = throbber.boxObject;
+ var throbberRect = {
+ left : throbberBox.screenX,
+ top : throbberBox.screenY,
+ right : throbberBox.screenX + throbberBox.width,
+ bottom : throbberBox.screenY + throbberBox.height
+ };
+
+ if (!iconBox.width && !iconBox.height)
+ return throbberRect;
+
+ if (!throbberBox.width && !throbberBox.height)
+ return iconRect;
+
+ return {
+ left : Math.min(throbberRect.left, iconRect.left),
+ right : Math.max(throbberRect.right, iconRect.right),
+ top : Math.min(throbberRect.top, iconRect.top),
+ bottom : Math.max(throbberRect.bottom, iconRect.bottom)
+ };
+ },
+
+ // called with target(nsIDOMEventTarget), document(nsIDOMDocument), type(string) and data(object)
+ fireCustomEvent : function TSTBase_fireCustomEvent(...aArgs)
+ {
+ var target, document, type, data, canBubble, cancelable;
+ for (let i = 0, maxi = aArgs.length; i < maxi; i++)
+ {
+ let arg = aArgs[i];
+ if (typeof arg == 'boolean') {
+ if (canBubble === void(0))
+ canBubble = arg;
+ else
+ cancelable = arg;
+ }
+ else if (typeof arg == 'string')
+ type = arg;
+ else if (arg instanceof Ci.nsIDOMDocument)
+ document = arg;
+ else if (arg instanceof Ci.nsIDOMEventTarget)
+ target = arg;
+ else
+ data = arg;
+ }
+ if (!target)
+ target = document;
+ if (!document)
+ document = target.ownerDocument || target;
+
+ var event = new this.window.CustomEvent(type, {
+ bubbles : canBubble,
+ cancelable : cancelable,
+ detail : data
+ });
+ return target.dispatchEvent(event);
+ },
+
+ registerExpandTwistyAreaBlocker : function TSTBase_registerExpandTwistyAreaBlocker(aBlocker) /* PUBLIC API */
+ {
+ if (this._expandTwistyAreaBlockers.indexOf(aBlocker) < 0)
+ this._expandTwistyAreaBlockers.push(aBlocker);
+ },
+ _expandTwistyAreaBlockers : [],
+
+ registerExpandTwistyAreaAllowance : function TSTBase_registerExpandTwistyAreaAllowance(aAllowance) /* PUBLIC API, obsolete, for backward compatibility */
+ {
+ this.registerExpandTwistyAreaBlocker(aAllowance.toSource());
+ },
+
+// string
+
+ makeNewId : function TSTBase_makeNewId()
+ {
+ return 'tab-<'+Date.now()+'-'+parseInt(Math.random() * 65000)+'>';
+ },
+
+ makeNewClosedSetId : function TSTBase_makeNewId()
+ {
+ return 'tabs-closed-set-<'+Date.now()+'-'+parseInt(Math.random() * 65000)+'>';
+ },
+
+ makeURIFromSpec : function TSTBase_makeURIFromSpec(aURI)
+ {
+ var newURI;
+ aURI = aURI || '';
+ if (aURI && String(aURI).indexOf('file:') == 0) {
+ var fileHandler = Services.io.getProtocolHandler('file').QueryInterface(Ci.nsIFileProtocolHandler);
+ var tempLocalFile = fileHandler.getFileFromURLSpec(aURI);
+ newURI = Services.io.newFileURI(tempLocalFile);
+ }
+ else {
+ if (!/^\w+\:/.test(aURI))
+ aURI = 'http://'+aURI;
+ newURI = Services.io.newURI(aURI, null, null);
+ }
+ return newURI;
+ },
+
+ getGroupTabURI : function TSTBase_getGroupTabURI(aOptions)
+ {
+ aOptions = aOptions || {};
+ var parameters = [];
+ parameters.push('title=' + encodeURIComponent(aOptions.title || ''));
+ parameters.push('temporary=' + !!aOptions.temporary);
+ return 'about:treestyletab-group?' + parameters.join('&');
+ },
+
+// xpath
+
+ NSResolver : {
+ lookupNamespaceURI : function(aPrefix)
+ {
+ switch (aPrefix)
+ {
+ case 'xul':
+ return 'http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul';
+ case 'html':
+ case 'xhtml':
+ return 'http://www.w3.org/1999/xhtml';
+ case 'xlink':
+ return 'http://www.w3.org/1999/xlink';
+ default:
+ return '';
+ }
+ }
+ },
+
+ evaluateXPath : function TSTBase_evaluateXPath(aExpression, aContext, aType)
+ {
+ if (!aType)
+ aType = Ci.nsIDOMXPathResult.ORDERED_NODE_SNAPSHOT_TYPE;
+ try {
+ var XPathResult = (aContext.ownerDocument || aContext).evaluate(
+ aExpression,
+ (aContext || document),
+ this.NSResolver,
+ aType,
+ null
+ );
+ }
+ catch(e) {
+ return {
+ singleNodeValue : null,
+ snapshotLength : 0,
+ snapshotItem : function() {
+ return null
+ }
+ };
+ }
+ return XPathResult;
+ },
+
+ getArrayFromXPathResult : function TSTBase_getArrayFromXPathResult(aXPathResult)
+ {
+ var max = aXPathResult.snapshotLength;
+ var array = new Array(max);
+ if (!max)
+ return array;
+
+ for (var i = 0; i < max; i++)
+ {
+ array[i] = aXPathResult.snapshotItem(i);
+ }
+
+ return array;
+ },
+
+/* Session Store API */
+
+ getTabValue : function TSTBase_getTabValue(aTab, aKey)
+ {
+ var value = '';
+ try {
+ value = SessionStore.getTabValue(aTab, aKey);
+ }
+ catch(e) {
+ }
+
+ if (this.useTMPSessionAPI) {
+ let TMPValue = aTab.getAttribute(this.kTMP_SESSION_DATA_PREFIX+aKey);
+ if (TMPValue)
+ value = TMPValue;
+ }
+
+ return value;
+ },
+
+ setTabValue : function TSTBase_setTabValue(aTab, aKey, aValue)
+ {
+ if (!aValue)
+ return this.deleteTabValue(aTab, aKey);
+
+ aTab.setAttribute(aKey, aValue);
+ try {
+ this.checkCachedSessionDataExpiration(aTab);
+ SessionStore.setTabValue(aTab, aKey, String(aValue));
+ }
+ catch(e) {
+ }
+
+ if (this.useTMPSessionAPI)
+ aTab.setAttribute(this.kTMP_SESSION_DATA_PREFIX+aKey, aValue);
+
+ return aValue;
+ },
+
+ deleteTabValue : function TSTBase_deleteTabValue(aTab, aKey)
+ {
+ aTab.removeAttribute(aKey);
+ try {
+ this.checkCachedSessionDataExpiration(aTab);
+ SessionStore.setTabValue(aTab, aKey, '');
+ SessionStore.deleteTabValue(aTab, aKey);
+ }
+ catch(e) {
+ }
+
+ if (this.useTMPSessionAPI)
+ aTab.removeAttribute(this.kTMP_SESSION_DATA_PREFIX+aKey);
+ },
+
+ // workaround for http://piro.sakura.ne.jp/latest/blosxom/mozilla/extension/treestyletab/2009-09-29_debug.htm
+ // This is obsolete for lately Firefox and no need to be updated. See: https://github.com/piroor/treestyletab/issues/508#issuecomment-17526429
+ checkCachedSessionDataExpiration : function TSTBase_checkCachedSessionDataExpiration(aTab)
+ {
+ var data = aTab.linkedBrowser.__SS_data;
+ if (data &&
+ data._tabStillLoading &&
+ aTab.getAttribute('busy') != 'true' &&
+ !utils.isTabNeedToBeRestored(aTab))
+ data._tabStillLoading = false;
+ },
+
+ markAsClosedSet : function TSTBase_markAsClosedSet(aTabs) /* PUBLIC API */
+ {
+ if (!aTabs || aTabs.length <= 1)
+ return;
+ var id = this.makeNewClosedSetId() + '::' + aTabs.length;
+ for (let i = 0, maxi = aTabs.length; i < maxi; i++)
+ {
+ this.setTabValue(aTabs[i], this.kCLOSED_SET_ID, id);
+ }
+ },
+
+ unmarkAsClosedSet : function TSTBase_unmarkAsClosedSet(aTabs) /* PUBLIC API */
+ {
+ if (!aTabs || !aTabs.length)
+ return;
+ for (let i = 0, maxi = aTabs.length; i < maxi; i++)
+ {
+ this.deleteTabValue(aTabs[i], this.kCLOSED_SET_ID);
+ }
+ },
+
+ useTMPSessionAPI : false,
+
+ kTMP_SESSION_DATA_PREFIX : 'tmp-session-data-',
+
+// tab
+
+ getTabStrip : function TSTBase_getTabStrip(aTabBrowser)
+ {
+ if (!(aTabBrowser instanceof Ci.nsIDOMElement))
+ return null;
+
+ var strip = aTabBrowser.mStrip;
+ return (strip && strip instanceof Ci.nsIDOMElement) ?
+ strip :
+ this.evaluateXPath(
+ 'ancestor::xul:toolbar[1]',
+ aTabBrowser.tabContainer,
+ Ci.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE
+ ).singleNodeValue || aTabBrowser.tabContainer.parentNode;
+ },
+ get tabStrip()
+ {
+ return this.getTabStrip(this.browser);
+ },
+
+ getTabContainerBox : function TSTBase_getTabContainerBox(aTabBrowser)
+ {
+ if (!(aTabBrowser instanceof Ci.nsIDOMElement))
+ return null;
+
+ var strip = this.getTabStrip(aTabBrowser);
+ return strip.treeStyleTabToolbarInnerBox || aTabBrowser.tabContainer;
+ },
+ get tabContainerBox()
+ {
+ return this.getTabContainerBox(this.browser);
+ },
+
+ setTabbrowserAttribute : function TSTBase_setTabbrowserAttribute(aName, aValue, aTabBrowser)
+ {
+ aTabBrowser = aTabBrowser || this.mTabBrowser || this.browser;
+ if (aValue) {
+ aTabBrowser.setAttribute(aName, aValue);
+ aTabBrowser.mTabContainer.setAttribute(aName, aValue);
+ aTabBrowser.treeStyleTab.setTabStripAttribute(aName, aValue);
+ }
+ else {
+ aTabBrowser.removeAttribute(aName);
+ aTabBrowser.mTabContainer.removeAttribute(aName);
+ aTabBrowser.treeStyleTab.removeTabStripAttribute(aName);
+ }
+ },
+
+ removeTabbrowserAttribute : function TSTBase_removeTabbrowserAttribute(aName, aTabBrowser)
+ {
+ this.setTabbrowserAttribute(aName, null, aTabBrowser);
+ },
+
+ setTabStripAttribute : function TSTBase_setTabStripAttribute(aAttr, aValue)
+ {
+ var strip = this.tabStrip;
+ if (!strip)
+ return;
+ var isFeatureAttribute = aAttr.indexOf('treestyletab-') == 0;
+ if (aValue) {
+ if (this._tabStripPlaceHolder)
+ this._tabStripPlaceHolder.setAttribute(aAttr, aValue);
+ if (!this._tabStripPlaceHolder || aAttr != 'ordinal')
+ strip.setAttribute(aAttr, aValue);
+ if (strip.treeStyleTabToolbarInnerBox)
+ strip.treeStyleTabToolbarInnerBox.setAttribute(aAttr, aValue);
+ if (isFeatureAttribute) {
+ // Only attributes for TST's feature are applied to the root element.
+ // (width, height, and other general attributes have to be ignored!)
+ strip.ownerDocument.defaultView.setTimeout(function(aSelf) {
+ strip.ownerDocument.documentElement.setAttribute(aAttr, aValue);
+ }, 10, this);
+ }
+ }
+ else {
+ if (this._tabStripPlaceHolder)
+ this._tabStripPlaceHolder.removeAttribute(aAttr);
+ if (!this._tabStripPlaceHolder || aAttr != 'ordinal')
+ strip.removeAttribute(aAttr);
+ if (strip.treeStyleTabToolbarInnerBox)
+ strip.treeStyleTabToolbarInnerBox.removeAttribute(aAttr);
+ if (isFeatureAttribute) {
+ strip.ownerDocument.defaultView.setTimeout(function(aSelf) {
+ strip.ownerDocument.documentElement.removeAttribute(aAttr);
+ }, 10, this);
+ }
+ }
+ },
+
+ removeTabStripAttribute : function TSTBase_removeTabStripAttribute(aAttr)
+ {
+ this.setTabStripAttribute(aAttr, null);
+ },
+
+ getTabFromChild : function TSTBase_getTabFromChild(aTab)
+ {
+ return this.evaluateXPath(
+ 'ancestor-or-self::xul:tab',
+ aTab,
+ Ci.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE
+ ).singleNodeValue;
+ },
+
+ getTabFromEvent : function TSTBase_getTabFromEvent(aEvent)
+ {
+ return this.getTabFromChild(aEvent.originalTarget || aEvent.target);
+ },
+
+ getNewTabButtonFromEvent : function TSTBase_getNewTabButtonFromEvent(aEvent)
+ {
+ return this.evaluateXPath(
+ 'ancestor-or-self::*['
+ +'@id="new-tab-button" or '
+ +'contains(concat(" ", normalize-space(@class), " "), " tabs-newtab-button ")'
+ +'][1]',
+ aEvent.originalTarget,
+ Ci.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE
+ ).singleNodeValue;
+ },
+
+ getSplitterFromEvent : function TSTBase_getSplitterFromEvent(aEvent)
+ {
+ return this.evaluateXPath(
+ 'ancestor-or-self::xul:splitter[contains(concat(" ", normalize-space(@class), " "), " '+this.kSPLITTER+' ")]',
+ aEvent.originalTarget,
+ Ci.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE
+ ).singleNodeValue;
+ },
+
+ isEventFiredOnGrippy : function TSTBase_isEventFiredOnGrippy(aEvent)
+ {
+ return this.evaluateXPath(
+ 'ancestor-or-self::xul:grippy',
+ aEvent.originalTarget,
+ Ci.nsIDOMXPathResult.BOOLEAN_TYPE
+ ).booleanValue;
+ },
+
+ getTabFromBrowser : function TSTBase_getTabFromBrowser(aBrowser, aTabBrowser)
+ {
+ var b = aTabBrowser || this.browser;
+ var tabs = this.getAllTabs(b);
+ for (let i = 0, maxi = tabs.length; i < maxi; i++)
+ {
+ let tab = tabs[i];
+ if (tab.linkedBrowser == aBrowser)
+ return tab;
+ }
+ return null;
+ },
+
+ getTabFromFrame : function TSTBase_getTabFromFrame(aFrame, aTabBrowser)
+ {
+ var b = aTabBrowser || this.browser;
+ var top = aFrame.top;
+ var tabs = this.getAllTabs(b);
+ for (let i = 0, maxi = tabs.length; i < maxi; i++)
+ {
+ let tab = tabs[i];
+ if (tab.linkedBrowser.contentWindow == top)
+ return tab;
+ }
+ return null;
+ },
+
+ getTabbarFromChild : function TSTBase_getTabbarFromChild(aNode)
+ {
+ return this.evaluateXPath(
+ 'ancestor-or-self::*[contains(concat(" ", normalize-space(@class), " "), " tabbrowser-strip ")] | ' +
+ 'ancestor-or-self::xul:tabs[@tabbrowser] | ' +
+ 'ancestor-or-self::xul:toolbar/child::xul:tabs[@tabbrowser]',
+ aNode,
+ Ci.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE
+ ).singleNodeValue;
+ },
+ getAncestorTabbarFromChild : function TSTBase_getAncestorTabbarFromChild(aNode)
+ {
+ return this.evaluateXPath(
+ 'ancestor-or-self::*[contains(concat(" ", normalize-space(@class), " "), " tabbrowser-strip ")] | ' +
+ 'ancestor-or-self::xul:tabs[@tabbrowser]',
+ aNode,
+ Ci.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE
+ ).singleNodeValue;
+ },
+
+ getTabbarFromEvent : function TSTBase_getTabbarFromEvent(aEvent)
+ {
+ return this.getTabbarFromChild(aEvent.originalTarget || aEvent.target);
+ },
+ getAncestorTabbarFromEvent : function TSTBase_getAncestorTabbarFromEvent(aEvent)
+ {
+ return this.getAncestorTabbarFromChild(aEvent.originalTarget || aEvent.target);
+ },
+
+ cleanUpTabsArray : function TSTBase_cleanUpTabsArray(aTabs)
+ {
+ var newTabs = [];
+ for (let i = 0, maxi = aTabs.length; i < maxi; i++)
+ {
+ let tab = aTabs[i];
+ if (!tab || !tab.parentNode)
+ continue; // ignore removed tabs
+ if (newTabs.indexOf(tab) < 0)
+ newTabs.push(tab);
+ }
+ newTabs.sort(this.sortTabsByOrder);
+ return newTabs;
+ },
+
+ sortTabsByOrder : function TSTBase_sortTabsByOrder(aA, aB)
+ {
+ return aA._tPos - aB._tPos;
+ },
+
+ gatherSubtreeMemberTabs : function TSTBase_gatherSubtreeMemberTabs(aTabOrTabs, aOnlyChildren)
+ {
+ var tabs = aTabOrTabs;
+ if (!(tabs instanceof Array)) {
+ tabs = [aTabOrTabs];
+ }
+
+ var b = this.getTabBrowserFromChild(tabs[0]);
+ var descendant = [];
+ for (var i = 0, maxi = tabs.length; i < maxi; i++)
+ {
+ descendant = descendant.concat(b.treeStyleTab.getDescendantTabs(tabs[i]));
+ }
+
+ return this.cleanUpTabsArray(aOnlyChildren ? descendant : tabs.concat(descendant));
+ },
+
+ splitTabsToSubtrees : function TSTBase_splitTabsToSubtrees(aTabs) /* PUBLIC API */
+ {
+ var groups = [];
+
+ var group = [];
+ aTabs = this.cleanUpTabsArray(aTabs);
+ for (let i = 0, maxi = aTabs.length; i < maxi; i++)
+ {
+ let tab = aTabs[i];
+ let parent = this.getParentTab(tab);
+ if (!parent || group.indexOf(parent) < 0) {
+ if (group.length)
+ groups.push(group);
+ group = [tab];
+ }
+ else {
+ group.push(tab);
+ }
+ }
+ if (group.length)
+ groups.push(group);
+ return groups;
+ },
+
+// tabbrowser
+
+ getTabBrowserFromChild : function TSTBase_getTabBrowserFromChild(aTabBrowserChild)
+ {
+ if (!aTabBrowserChild)
+ return null;
+
+ if (aTabBrowserChild.__treestyletab__linkedTabBrowser) // tab
+ return aTabBrowserChild.__treestyletab__linkedTabBrowser;
+
+ if (aTabBrowserChild.localName == 'tabbrowser') // itself
+ return aTabBrowserChild;
+
+ if (aTabBrowserChild.tabbrowser) // tabs
+ return aTabBrowserChild.tabbrowser;
+
+ if (aTabBrowserChild.localName == 'toolbar') // tabs toolbar
+ return aTabBrowserChild.getElementsByTagName('tabs')[0].tabbrowser;
+
+ // tab context menu
+ var popup = this.evaluateXPath(
+ 'ancestor-or-self::xul:menupopup[@id="tabContextMenu"]',
+ aTabBrowserChild,
+ Ci.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE
+ ).singleNodeValue;
+ if (popup && 'TabContextMenu' in aTabBrowserChild.ownerDocument.defaultView)
+ return this.getTabBrowserFromChild(aTabBrowserChild.ownerDocument.defaultView.TabContextMenu.contextTab);
+
+ var b = this.evaluateXPath(
+ 'ancestor::xul:tabbrowser | '+
+ 'ancestor::xul:tabs[@tabbrowser] |'+
+ 'ancestor::xul:toolbar/descendant::xul:tabs',
+ aTabBrowserChild,
+ Ci.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE
+ ).singleNodeValue;
+ return (b && b.tabbrowser) || b;
+ },
+
+ getTabBrowserFromFrame : function TSTBase_getTabBrowserFromFrame(aFrame)
+ {
+ var w = this.browserWindow;
+ return !w ? null :
+ ('SplitBrowser' in w) ? this.getTabBrowserFromChild(w.SplitBrowser.getSubBrowserAndBrowserFromFrame(aFrame.top).browser) :
+ this.browser ;
+ },
+
+ getFrameFromTabBrowserElements : function TSTBase_getFrameFromTabBrowserElements(aFrameOrTabBrowser)
+ {
+ var frame = aFrameOrTabBrowser;
+ if (frame == '[object XULElement]') {
+ if (frame.localName == 'tab') {
+ frame = frame.linkedBrowser.contentWindow;
+ }
+ else if (frame.localName == 'browser') {
+ frame = frame.contentWindow;
+ }
+ else {
+ frame = this.getTabBrowserFromChild(frame);
+ if (!frame)
+ return null;
+ frame = frame.contentWindow;
+ }
+ }
+ if (!frame)
+ frame = this.browser.contentWindow;
+
+ return frame;
+ },
+
+/* get tab(s) */
+
+ getTabById : function TSTBase_getTabById(aId, aTabBrowserChildren)
+ {
+ if (!aId)
+ return null;
+
+ if (aTabBrowserChildren && !(aTabBrowserChildren instanceof Ci.nsIDOMNode))
+ aTabBrowserChildren = null;
+
+ var b = this.getTabBrowserFromChild(aTabBrowserChildren) || this.browser;
+
+ if (this.tabsHash) // XPath-less implementation
+ return this.tabsHash[aId] || null;
+
+ return b.mTabContainer.querySelector('tab['+this.kID+'="'+aId+'"]');
+ },
+
+ isTabDuplicated : function TSTBase_isTabDuplicated(aTab)
+ {
+ if (!aTab)
+ return false;
+ var id = this.getTabValue(aTab, this.kID);
+ var b = this.getTabBrowserFromChild(aTab) || this.browser;
+ var tabs = b.mTabContainer.querySelectorAll('tab['+this.kID+'="'+id+'"], tab['+this.kID_RESTORING+'="'+id+'"]');
+ return tabs.length > 1;
+ },
+
+ /**
+ * Returns all tabs in the current group as an array.
+ * It includes tabs hidden by Tab Panorama.
+ */
+ getAllTabs : function TSTBase_getTabs(aTabBrowserChild)
+ {
+ var b = this.getTabBrowserFromChild(aTabBrowserChild || this.browser);
+ this.assertBeforeDestruction(b && b.mTabContainer);
+ return Array.slice(b.mTabContainer.querySelectorAll('tab'));
+ },
+
+ /**
+ * Returns all tabs in the current group as an array.
+ * It excludes tabs hidden by Tab Panorama.
+ */
+ getTabs : function TSTBase_getTabs(aTabBrowserChild)
+ {
+ var b = this.getTabBrowserFromChild(aTabBrowserChild || this.browser);
+ this.assertBeforeDestruction(b && b.mTabContainer);
+ return Array.slice(b.mTabContainer.querySelectorAll('tab:not([hidden="true"])'));
+ },
+
+ getAllTabsArray : function TSTBase_getAllTabsArray(aTabBrowserChild) /* for backward compatibility */
+ {
+ return this.getAllTabs(aTabBrowserChild);
+ },
+
+ getTabsArray : function TSTBase_getTabsArray(aTabBrowserChild) /* for backward compatibility */
+ {
+ return this.getTabs(aTabBrowserChild);
+ },
+
+ /**
+ * Returns the first tab in the current group.
+ */
+ getFirstTab : function TSTBase_getFirstTab(aTabBrowserChild)
+ {
+ var b = this.getTabBrowserFromChild(aTabBrowserChild || this.browser);
+ this.assertBeforeDestruction(b && b.mTabContainer);
+ var tabs = b.visibleTabs;
+ return tabs ? tabs[0] : b.mTabContainer.firstChild;
+ },
+
+ /**
+ * Returns the first visible, not collapsed, and not pinned tab.
+ */
+ getFirstNormalTab : function TSTBase_getFirstNormalTab(aTabBrowserChild)
+ {
+ var b = this.getTabBrowserFromChild(aTabBrowserChild || this.browser);
+ this.assertBeforeDestruction(b && b.mTabContainer);
+ return b.mTabContainer.querySelector('tab:not([pinned="true"]):not([hidden="true"])');
+ },
+
+ /**
+ * Returns the last tab in the current group.
+ */
+ getLastTab : function TSTBase_getLastTab(aTabBrowserChild)
+ {
+ var b = this.getTabBrowserFromChild(aTabBrowserChild || this.browser);
+ this.assertBeforeDestruction(b && b.mTabContainer);
+ var tabs = b.visibleTabs;
+ return tabs ? tabs[tabs.length-1] : b.mTabContainer.lastChild ;
+ },
+
+ /**
+ * Returns the next tab in the current group.
+ */
+ getNextTab : function TSTBase_getNextTab(aTab)
+ {
+ if (!aTab)
+ return null;
+ var b = this.getTabBrowserFromChild(aTab);
+ this.assertBeforeDestruction(b && b.mTabContainer);
+ var tabs = b.visibleTabs;
+ if (tabs) {
+ let index = tabs.indexOf(aTab);
+ if (index > -1)
+ return tabs.length > index ? tabs[index+1] : null
+ }
+ var tab = aTab.nextSibling;
+ return (tab && tab.localName == 'tab') ? tab : null ;
+ },
+
+ /**
+ * Returns the previous tab in the current group.
+ */
+ getPreviousTab : function TSTBase_getPreviousTab(aTab)
+ {
+ if (!aTab)
+ return null;
+ var b = this.getTabBrowserFromChild(aTab);
+ this.assertBeforeDestruction(b && b.mTabContainer);
+ var tabs = b.visibleTabs;
+ if (tabs) {
+ let index = tabs.indexOf(aTab);
+ if (index > -1)
+ return 0 < index ? tabs[index-1] : null
+ }
+ var tab = aTab.previousSibling;
+ return (tab && tab.localName == 'tab') ? tab : null ;
+ },
+
+ /**
+ * Returns the index of the specified tab, in the current group.
+ */
+ getTabIndex : function TSTBase_getTabIndex(aTab)
+ {
+ if (!aTab)
+ return -1;
+ var b = this.getTabBrowserFromChild(aTab);
+ return this.getTabs(b).indexOf(aTab);
+ },
+
+ /**
+ * Returns the next not collapsed tab in the current group.
+ */
+ getNextVisibleTab : function TSTBase_getNextVisibleTab(aTab)
+ {
+ if (!aTab)
+ return null;
+
+ var b = this.getTabBrowserFromChild(aTab);
+ if (!this.canCollapseSubtree(b))
+ return this.getNextTab(aTab);
+
+ var tabs = this.getVisibleTabs(b);
+ if (tabs.indexOf(aTab) < 0)
+ tabs.push(aTab);
+ tabs.sort(this.sortTabsByOrder);
+
+ var index = tabs.indexOf(aTab);
+ return (index < tabs.length-1) ? tabs[index+1] : null ;
+ },
+
+ /**
+ * Returns the previous not collapsed tab in the current group.
+ */
+ getPreviousVisibleTab : function TSTBase_getPreviousVisibleTab(aTab)
+ {
+ if (!aTab)
+ return null;
+
+ var b = this.getTabBrowserFromChild(aTab);
+ if (!this.canCollapseSubtree(b))
+ return this.getPreviousTab(aTab);
+
+ var tabs = this.getVisibleTabs(b);
+ if (tabs.indexOf(aTab) < 0)
+ tabs.push(aTab);
+ tabs.sort(this.sortTabsByOrder);
+
+ var index = tabs.indexOf(aTab);
+ return (index > 0) ? tabs[index-1] : null ;
+ },
+
+ /**
+ * Returns the last not collapsed tab in the current group.
+ */
+ getLastVisibleTab : function TSTBase_getLastVisibleTab(aTabBrowserChild)
+ {
+ var b = this.getTabBrowserFromChild(aTabBrowserChild || this.browser);
+ if (!b)
+ return null;
+ var tabs = this.getVisibleTabs(b);
+ return tabs.length ? tabs[tabs.length-1] : null ;
+ },
+
+ /**
+ * Returns a XPathResult of not collapsed tabs in the current group.
+ */
+ getVisibleTabs : function TSTBase_getVisibleTabs(aTabBrowserChild) /* OBSOLETE */
+ {
+ var b = this.getTabBrowserFromChild(aTabBrowserChild || this.browser);
+ if (!this.canCollapseSubtree(b))
+ return this.getTabs(b);
+ return Array.slice(b.mTabContainer.querySelectorAll('tab:not(['+this.kCOLLAPSED+'="true"]):not([hidden="true"])'));
+ },
+
+ getVisibleTabsArray : function TSTBase_getVisibleTabsArray(aTabBrowserChild) /* for backward compatibility */
+ {
+ return this.getVisibleTabs(aTabBrowserChild);
+ },
+
+ /**
+ * Returns the index of the specified tab, in the array of not collapsed
+ * tabs in the current group.
+ */
+ getVisibleIndex : function TSTBase_getVisibleIndex(aTab)
+ {
+ if (!aTab)
+ return -1;
+ var b = this.getTabBrowserFromChild(aTab);
+ return this.getVisibleTabs(b).indexOf(aTab);
+ },
+
+ /**
+ * Returns tabs which are newly opened in the given operation.
+ */
+ getNewTabsWithOperation : function TSTBase_getNewTabsWithOperation(aOperation, aTabBrowser)
+ {
+ var previousTabs = this.getTabsInfo(aTabBrowser);
+ aOperation.call(this);
+ return this.getNewTabsFromPreviousTabsInfo(aTabBrowser, previousTabs);
+ },
+
+ /**
+ * Returns tabs which are newly opened. This requires the "previous state".
+ */
+ getNewTabsFromPreviousTabsInfo : function TSTBase_getNewTabsFromPreviousTabsInfo(aTabBrowser, aTabsInfo)
+ {
+ var tabs = this.getTabs(aTabBrowser);
+ var currentTabsInfo = this.getTabsInfo(aTabBrowser);
+ return tabs.filter(function(aTab, aIndex) {
+ return aTabsInfo.indexOf(currentTabsInfo[aIndex]) < 0;
+ });
+ },
+ getTabsInfo : function TSTBase_getTabsInfo(aTabBrowser)
+ {
+ var tabs = this.getTabs(aTabBrowser);
+ return tabs.map(function(aTab) {
+ return aTab.getAttribute(this.kID)+'\n'+
+ aTab.getAttribute('busy')+'\n'+
+ aTab.linkedBrowser.currentURI.spec;
+ }, this);
+ },
+
+/* notify "ready to open child tab(s)" */
+
+ readyToOpenChildTab : function TSTBase_readyToOpenChildTab(aFrameOrTabBrowser, aMultiple, aInsertBefore) /* PUBLIC API */
+ {
+ if (!utils.getTreePref('autoAttach'))
+ return false;
+
+ var frame = this.getFrameFromTabBrowserElements(aFrameOrTabBrowser);
+ if (!frame)
+ return false;
+
+ var ownerBrowser = this.getTabBrowserFromFrame(frame);
+
+ var parentTab = this.getTabFromFrame(frame, ownerBrowser);
+ if (!parentTab || parentTab.getAttribute('pinned') == 'true')
+ return false;
+
+ ownerBrowser.treeStyleTab.ensureTabInitialized(parentTab);
+ var parentId = parentTab.getAttribute(this.kID);
+
+ var refId = null;
+ if (aInsertBefore) {
+ ownerBrowser.treeStyleTab.ensureTabInitialized(parentTab);
+ refId = aInsertBefore.getAttribute(this.kID);
+ }
+
+ dump('Tree Style Tab: new child tab is requested.\n'+new Error().stack+'\n');
+
+ ownerBrowser.treeStyleTab.readiedToAttachNewTab = true;
+ ownerBrowser.treeStyleTab.readiedToAttachMultiple = aMultiple || false ;
+ ownerBrowser.treeStyleTab.multipleCount = aMultiple ? 0 : -1 ;
+ ownerBrowser.treeStyleTab.parentTab = parentId;
+ ownerBrowser.treeStyleTab.insertBefore = refId;
+
+ return true;
+ },
+ /**
+ * Extended version. If you don't know whether a new tab will be actually
+ * opened or not (by the command called after TST's API), then use this.
+ * This version automatically cancels the "ready" state with delay.
+ */
+ readyToOpenChildTabNow : function TSTBase_readyToOpenChildTabNow(...aArgs) /* PUBLIC API */
+ {
+ if (this.readyToOpenChildTab.apply(this, aArgs)) {
+ let self = this;
+ this.Deferred.next(function() {
+ self.stopToOpenChildTab(aArgs[0]);
+ }).error(this.defaultDeferredErrorHandler);
+ return true;
+ }
+ return false;
+ },
+
+ readyToOpenNextSiblingTab : function TSTBase_readyToOpenNextSiblingTab(aFrameOrTabBrowser) /* PUBLIC API */
+ {
+ var frame = this.getFrameFromTabBrowserElements(aFrameOrTabBrowser);
+ if (!frame)
+ return false;
+
+ var ownerBrowser = this.getTabBrowserFromFrame(frame);
+
+ var tab = this.getTabFromFrame(frame, ownerBrowser);
+ if (!tab || tab.getAttribute('pinned') == 'true')
+ return false;
+
+ var parentTab = this.getParentTab(tab);
+ var nextTab = this.getNextSiblingTab(tab);
+ if (parentTab) {
+ /**
+ * If the base tab has a parent, open the new tab as a child of
+ * the parent tab.
+ */
+ return this.readyToOpenChildTab(parentTab, false, nextTab);
+ }
+ else {
+ /**
+ * Otherwise, open the tab as a new root tab. If there is no
+ * tab next to the base tab (in other words, if the tab is the
+ * last tab), then do nothing.
+ */
+ if (!nextTab)
+ return;
+ ownerBrowser.treeStyleTab.readiedToAttachNewTab = true;
+ ownerBrowser.treeStyleTab.parentTab = null;
+ ownerBrowser.treeStyleTab.insertBefore = nextTab.getAttribute(this.kID);
+ return true;
+ }
+ },
+ /**
+ * Extended version. If you don't know whether a new tab will be actually
+ * opened or not (by the command called after TST's API), then use this.
+ * This version automatically cancels the "ready" state with delay.
+ */
+ readyToOpenNextSiblingTabNow : function TSTBase_readyToOpenNextSiblingTabNow(...aArgs) /* PUBLIC API */
+ {
+ if (this.readyToOpenNextSiblingTab.apply(this, aArgs)) {
+ let self = this;
+ this.Deferred.next(function() {
+ self.stopToOpenChildTab(aArgs[0]);
+ }).error(this.defaultDeferredErrorHandler);
+ return true;
+ }
+ return false;
+ },
+
+ readyToOpenNewTabGroup : function TSTBase_readyToOpenNewTabGroup(aFrameOrTabBrowser, aTreeStructure, aExpandAllTree) /* PUBLIC API */
+ {
+ if (!utils.getTreePref('autoAttach'))
+ return false;
+
+ var frame = this.getFrameFromTabBrowserElements(aFrameOrTabBrowser);
+ if (!frame)
+ return false;
+
+ this.stopToOpenChildTab(frame);
+
+ var ownerBrowser = this.getTabBrowserFromFrame(frame);
+ ownerBrowser.treeStyleTab.readiedToAttachNewTabGroup = true;
+ ownerBrowser.treeStyleTab.readiedToAttachMultiple = true;
+ ownerBrowser.treeStyleTab.multipleCount = 0;
+ ownerBrowser.treeStyleTab.treeStructure = aTreeStructure;
+ ownerBrowser.treeStyleTab.shouldExpandAllTree = !!aExpandAllTree;
+
+ return true;
+ },
+ /**
+ * Extended version. If you don't know whether new tabs will be actually
+ * opened or not (by the command called after TST's API), then use this.
+ * This version automatically cancels the "ready" state with delay.
+ */
+ readyToOpenNewTabGroupNow : function TSTBase_readyToOpenNewTabGroupNow(...aArgs) /* PUBLIC API */
+ {
+
+ if (this.readyToOpenNewTabGroup.apply(this, aArgs)) {
+ let self = this;
+ this.Deferred.next(function() {
+ self.stopToOpenChildTab(aArgs[0]);
+ }).error(this.defaultDeferredErrorHandler);
+ return true;
+ }
+ return false;
+ },
+
+ stopToOpenChildTab : function TSTBase_stopToOpenChildTab(aFrameOrTabBrowser) /* PUBLIC API */
+ {
+ var frame = this.getFrameFromTabBrowserElements(aFrameOrTabBrowser);
+ if (!frame)
+ return false;
+
+ var ownerBrowser = this.getTabBrowserFromFrame(frame);
+ ownerBrowser.treeStyleTab.readiedToAttachNewTab = false;
+ ownerBrowser.treeStyleTab.readiedToAttachNewTabGroup = false;
+ ownerBrowser.treeStyleTab.readiedToAttachMultiple = false;
+ ownerBrowser.treeStyleTab.multipleCount = -1;
+ ownerBrowser.treeStyleTab.parentTab = null;
+ ownerBrowser.treeStyleTab.insertBefore = null;
+ ownerBrowser.treeStyleTab.treeStructure = null;
+ ownerBrowser.treeStyleTab.shouldExpandAllTree = false;
+
+ return true;
+ },
+
+ checkToOpenChildTab : function TSTBase_checkToOpenChildTab(aFrameOrTabBrowser) /* PUBLIC API */
+ {
+ var frame = this.getFrameFromTabBrowserElements(aFrameOrTabBrowser);
+ if (!frame)
+ return false;
+
+ var ownerBrowser = this.getTabBrowserFromFrame(frame);
+ return !!(ownerBrowser.treeStyleTab.readiedToAttachNewTab || ownerBrowser.treeStyleTab.readiedToAttachNewTabGroup);
+ },
+
+ kNEWTAB_DO_NOTHING : -1,
+ kNEWTAB_OPEN_AS_ORPHAN : 0,
+ kNEWTAB_OPEN_AS_CHILD : 1,
+ kNEWTAB_OPEN_AS_SIBLING : 2,
+ kNEWTAB_OPEN_AS_NEXT_SIBLING : 3,
+ readyToOpenRelatedTabAs : function TSTBase_readyToOpenRelatedTabAs(aBaseTab, aBehavior)
+ {
+ var frame = this.getFrameFromTabBrowserElements(aBaseTab);
+ if (!frame)
+ return;
+
+ aBaseTab = this.getTabFromFrame(frame, this.getTabBrowserFromFrame(frame));
+
+ switch (aBehavior)
+ {
+ case this.kNEWTAB_OPEN_AS_ORPHAN:
+ case this.kNEWTAB_DO_NOTHING:
+ default:
+ break;
+ case this.kNEWTAB_OPEN_AS_CHILD:
+ this.readyToOpenChildTabNow(aBaseTab);
+ break;
+ case this.kNEWTAB_OPEN_AS_SIBLING:
+ let (parentTab = this.getParentTab(aBaseTab)) {
+ if (parentTab)
+ this.readyToOpenChildTabNow(parentTab);
+ }
+ break;
+ case this.kNEWTAB_OPEN_AS_NEXT_SIBLING:
+ this.readyToOpenNextSiblingTabNow(aBaseTab);
+ break;
+ }
+ },
+
+ handleNewTabFromCurrent : function TSTBase_handleNewTabFromCurrent(aBaseTab)
+ {
+ this.readyToOpenRelatedTabAs(aBaseTab, utils.getTreePref('autoAttach.fromCurrent'));
+ },
+
+/* tree manipulations */
+
+ get treeViewEnabled() /* PUBLIC API */
+ {
+ return this._treeViewEnabled;
+ },
+ set treeViewEnabled(aValue)
+ {
+ this._treeViewEnabled = !!aValue;
+ Services.obs.notifyObservers(
+ window,
+ this.kTOPIC_CHANGE_TREEVIEW_AVAILABILITY,
+ this._treeViewEnabled
+ );
+ return aValue;
+ },
+ _treeViewEnabled : true,
+
+ get rootTabs() /* PUBLIC API */
+ {
+ return Array.slice(this.browser.mTabContainer.querySelectorAll('tab:not(['+this.kNEST+']), tab['+this.kNEST+'=""], tab['+this.kNEST+'="0"]'));
+ },
+
+ get allRootTabs() /* PUBLIC API */
+ {
+ return this.rootTabs;
+ },
+
+ get visibleRootTabs() /* PUBLIC API */
+ {
+ return this.rootTabs.filter(function(aTab) {
+ return !aTab.hidden;
+ });
+ },
+
+ canCollapseSubtree : function TSTBase_canCollapseSubtree(aTabOrTabBrowser) /* PUBLIC API */
+ {
+ if (aTabOrTabBrowser &&
+ aTabOrTabBrowser.localName == 'tab' &&
+ aTabOrTabBrowser.getAttribute(this.kALLOW_COLLAPSE) != 'true')
+ return false;
+
+ var b = this.getTabBrowserFromChild(aTabOrTabBrowser) || this.browser;
+ return b && b.getAttribute(this.kALLOW_COLLAPSE) == 'true';
+ },
+
+ isCollapsed : function TSTBase_isCollapsed(aTab) /* PUBLIC API */
+ {
+ if (!aTab ||
+ !this.canCollapseSubtree(this.getRootTab(aTab)))
+ return false;
+
+ return aTab.getAttribute(this.kCOLLAPSED) == 'true';
+ },
+
+ isSubtreeCollapsed : function TSTBase_isSubtreeCollapsed(aTab) /* PUBLIC API */
+ {
+ if (!aTab || !this.canCollapseSubtree(aTab) || !this.hasChildTabs(aTab))
+ return false;
+
+ return aTab.getAttribute(this.kSUBTREE_COLLAPSED) == 'true';
+ },
+
+ shouldCloseTabSubtreeOf : function TSTBase_shouldCloseTabSubtreeOf(aTab)
+ {
+ return (
+ this.hasChildTabs(aTab) &&
+ (
+ utils.getTreePref('closeParentBehavior') == this.kCLOSE_PARENT_BEHAVIOR_CLOSE_ALL_CHILDREN ||
+ this.isSubtreeCollapsed(aTab)
+ )
+ );
+ },
+ shouldCloseTabSubTreeOf : function TSTBase_shouldCloseTabSubTreeOf(...aArgs) {
+ return this.shouldCloseTabSubtreeOf.apply(this, aArgs);
+ }, // obsolete, for backward compatibility
+
+ shouldCloseLastTabSubtreeOf : function TSTBase_shouldCloseLastTabSubtreeOf(aTab)
+ {
+ var b = this.getTabBrowserFromChild(aTab);
+ return (
+ b &&
+ this.shouldCloseTabSubtreeOf(aTab) &&
+ this.getDescendantTabs(aTab).length + 1 == this.getAllTabs(b).length
+ );
+ },
+ shouldCloseLastTabSubTreeOf : function TSTBase_shouldCloseLastTabSubTreeOf(...aArgs) {
+ return this.shouldCloseLastTabSubtreeOf.apply(this, aArgs);
+ }, // obsolete, for backward compatibility
+
+ getParentTab : function TSTBase_getParentTab(aTab) /* PUBLIC API */
+ {
+ if (!aTab)
+ return null;
+
+ var parent;
+ var id = aTab.getAttribute(this.kPARENT);
+ if (this.tabsHash) { // XPath-less implementation
+ parent = this.getTabById(id);
+ if (parent && !parent.parentNode && this.tabsHash) {
+ delete this.tabsHash[id];
+ parent = null;
+ }
+ }
+ else {
+ parent = this.evaluateXPath(
+ 'preceding-sibling::xul:tab[@'+this.kID+'="'+id+'"][1]',
+ aTab,
+ Ci.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE
+ ).singleNodeValue;
+ }
+ return (parent && parent != aTab) ? parent : null ;
+ },
+
+ getAncestorTabs : function TSTBase_getAncestorTabs(aTab) /* PUBLIC API */
+ {
+ var tabs = [aTab];
+ var parentTab = aTab;
+ while (parentTab = this.getParentTab(parentTab))
+ {
+ if (tabs.indexOf(parentTab) > -1) {
+ let message = 'recursive tree detected!\n'+
+ tabs.concat([parentTab])
+ .reverse().map(function(aTab) {
+ return ' '+aTab._tPos+' : '+
+ aTab.label+'\n '+
+ aTab.getAttribute(this.kID);
+ }, this).join('\n');
+ dump(message+'\n');
+ break;
+ }
+
+ if (aTab._tPos < parentTab._tPos) {
+ let message = 'broken tree detected!\n'+
+ tabs.concat([parentTab])
+ .reverse().map(function(aTab) {
+ return ' '+aTab._tPos+' : '+
+ aTab.label+'\n '+
+ aTab.getAttribute(this.kID);
+ }, this).join('\n');
+ dump(message+'\n');
+ }
+
+ tabs.push(parentTab);
+ aTab = parentTab;
+ }
+ return tabs.slice(1);
+ },
+
+ getRootTab : function TSTBase_getRootTab(aTab) /* PUBLIC API */
+ {
+ if (!aTab)
+ return null;
+
+ if (this.tabsHash) { // XPath-less implementation
+ let ancestors = this.getAncestorTabs(aTab);
+ return ancestors.length ? ancestors[ancestors.length-1] : aTab ;
+ }
+
+ return this.evaluateXPath(
+ '(self::*[not(@'+this.kPARENT+')] | preceding-sibling::xul:tab[not(@'+this.kPARENT+')])[last()]',
+ aTab,
+ Ci.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE
+ ).singleNodeValue;
+ },
+
+ getNextSiblingTab : function TSTBase_getNextSiblingTab(aTab) /* PUBLIC API */
+ {
+ if (!aTab)
+ return null;
+
+ if (this.tabsHash) { // XPath-less implementation
+ let parentTab = this.getParentTab(aTab);
+
+ if (!parentTab) {
+ let next = aTab;
+ do {
+ next = next.nextSibling;
+ }
+ while (next &&
+ next.nodeType == Ci.nsIDOMNode.ELEMENT_NODE &&
+ this.getParentTab(next));
+ return next;
+ }
+
+ let children = parentTab.getAttribute(this.kCHILDREN);
+ if (children) {
+ let list = ('|'+children).split('|'+aTab.getAttribute(this.kID));
+ list = list.length > 1 ? list[1].split('|') : [] ;
+ for (let i = 0, maxi = list.length; i < maxi; i++)
+ {
+ let firstChild = this.getTabById(list[i], aTab);
+ if (firstChild)
+ return firstChild;
+ }
+ }
+ return null;
+ }
+
+ var parent = aTab.getAttribute(this.kPARENT);
+ return this.evaluateXPath(
+ 'following-sibling::xul:tab['+
+ (parent ? '@'+this.kPARENT+'="'+parent+'"' : 'not(@'+this.kPARENT+')' )+
+ '][1]',
+ aTab,
+ Ci.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE
+ ).singleNodeValue;
+ },
+
+ getPreviousSiblingTab : function TSTBase_getPreviousSiblingTab(aTab) /* PUBLIC API */
+ {
+ if (!aTab)
+ return null;
+
+ if (this.tabsHash) { // XPath-less implementation
+ let parentTab = this.getParentTab(aTab);
+
+ if (!parentTab) {
+ let prev = aTab;
+ do {
+ prev = prev.previousSibling;
+ }
+ while (prev &&
+ prev.nodeType == Ci.nsIDOMNode.ELEMENT_NODE &&
+ this.getParentTab(prev));
+ return prev;
+ }
+
+ let children = parentTab.getAttribute(this.kCHILDREN);
+ if (children) {
+ let list = ('|'+children).split('|'+aTab.getAttribute(this.kID))[0].split('|');
+ for (let i = list.length-1; i > -1; i--)
+ {
+ let lastChild = this.getTabById(list[i], aTab);
+ if (lastChild)
+ return lastChild;
+ }
+ }
+ return null;
+ }
+
+ var parent = aTab.getAttribute(this.kPARENT);
+ return this.evaluateXPath(
+ 'preceding-sibling::xul:tab['+
+ (parent ? '@'+this.kPARENT+'="'+parent+'"' : 'not(@'+this.kPARENT+')' )+
+ '][1]',
+ aTab,
+ Ci.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE
+ ).singleNodeValue;
+ },
+
+ getSiblingTabs : function TSTBase_getSiblingTabs(aTab) /* PUBLIC API */
+ {
+ var parent = this.getParentTab(aTab);
+
+ var siblings = parent && parent.parentNode ? this.getChildTabs(parent) : this.visibleRootTabs ;
+ return siblings.filter(function(aSiblingTab) {
+ return aSiblingTab != aTab;
+ });
+ },
+
+ getChildTabs : function TSTBase_getChildTabs(aTab, aAllTabsArray) /* PUBLIC API */
+ {
+ var tabs = [];
+ if (!aTab)
+ return tabs;
+
+ var children = aTab.getAttribute(this.kCHILDREN);
+ if (!children)
+ return tabs;
+
+ if (aAllTabsArray)
+ tabs = aAllTabsArray;
+
+ var list = children.split('|');
+ for (let i = 0, maxi = list.length; i < maxi; i++)
+ {
+ let tab = this.getTabById(list[i], aTab);
+ if (!tab || tab == aTab)
+ continue;
+ if (tabs.indexOf(tab) > -1) {
+ let message = 'broken (possible recursive) tree detected!\n'+
+ tabs.map(function(aTab) {
+ return ' '+aTab._tPos+' : '+
+ aTab.label+'\n '+
+ aTab.getAttribute(this.kID);
+ }, this).join('\n');
+ dump(message+'\n');
+ continue;
+ }
+ tabs.push(tab);
+ if (aAllTabsArray)
+ this.getChildTabs(tab, tabs);
+ }
+
+ return tabs;
+ },
+
+ hasChildTabs : function TSTBase_hasChildTabs(aTab) /* PUBLIC API */
+ {
+ if (!aTab)
+ return false;
+ return aTab.hasAttribute(this.kCHILDREN);
+ },
+
+ getDescendantTabs : function TSTBase_getDescendantTabs(aTab) /* PUBLIC API */
+ {
+ var tabs = [];
+ this.getChildTabs(aTab, tabs);
+ return tabs;
+ },
+
+ getFirstChildTab : function TSTBase_getFirstChildTab(aTab) /* PUBLIC API */
+ {
+ if (!aTab)
+ return null;
+
+ if (this.tabsHash) { // XPath-less implementation
+ let children = aTab.getAttribute(this.kCHILDREN);
+ let firstChild = null;
+ if (children) {
+ let list = children.split('|');
+ for (let i = 0, maxi = list.length; i < maxi; i++)
+ {
+ firstChild = this.getTabById(list[i], aTab);
+ if (firstChild && firstChild != aTab)
+ break;
+ }
+ }
+ return firstChild;
+ }
+
+ return this.evaluateXPath(
+ 'following-sibling::xul:tab[@'+this.kPARENT+'="'+aTab.getAttribute(this.kID)+'"][1]',
+ aTab,
+ Ci.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE
+ ).singleNodeValue;
+ },
+
+ getLastChildTab : function TSTBase_getLastChildTab(aTab) /* PUBLIC API */
+ {
+ if (!aTab)
+ return null;
+
+ if (this.tabsHash) { // XPath-less implementation
+ let children = aTab.getAttribute(this.kCHILDREN);
+ let lastChild = null;
+ if (children) {
+ let list = children.split('|');
+ for (let i = list.length-1; i > -1; i--)
+ {
+ lastChild = this.getTabById(list[i], aTab);
+ if (lastChild && lastChild != aTab)
+ break;
+ }
+ }
+ return lastChild;
+ }
+
+ return this.evaluateXPath(
+ 'following-sibling::xul:tab[@'+this.kPARENT+'="'+aTab.getAttribute(this.kID)+'"][last()]',
+ aTab,
+ Ci.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE
+ ).singleNodeValue;
+ },
+
+ getLastDescendantTab : function TSTBase_getLastDescendantTab(aTab) /* PUBLIC API */
+ {
+ if (!aTab)
+ return null;
+
+ if (this.tabsHash) { // XPath-less implementation
+ let tabs = this.getDescendantTabs(aTab);
+ return tabs.length ? tabs[tabs.length-1] : null ;
+ }
+
+ var parent = aTab.getAttribute(this.kPARENT);
+ return this.evaluateXPath(
+ 'following-sibling::xul:tab['+
+ (parent ? '@'+this.kPARENT+'="'+parent+'"' : 'not(@'+this.kPARENT+')' )+
+ '][1]/preceding-sibling::xul:tab[1][not(@'+this.kID+'="'+aTab.getAttribute(this.kID)+'")]',
+ aTab,
+ Ci.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE
+ ).singleNodeValue;
+ },
+
+ collectRootTabs : function TSTBase_collectRootTabs(aTabs) /* PUBLIC API */
+ {
+ aTabs = Array.slice(aTabs);
+ return aTabs.filter(function(aTab) {
+ var parent = this.getParentTab(aTab);
+ return !parent || aTabs.indexOf(parent) < 0;
+ }, this);
+ },
+
+ getChildIndex : function TSTBase_getChildIndex(aTab, aParent) /* PUBLIC API */
+ {
+ var parent = this.getParentTab(aTab);
+ if (!aParent || !parent || aParent != parent) {
+ let tabs = [aTab].concat(this.getAncestorTabs(aTab));
+ parent = aTab;
+ for (let i = 0, maxi = tabs.length; i < maxi && parent != aParent; i++)
+ {
+ aTab = parent;
+ parent = i < maxi ? tabs[i+1] : null ;
+ }
+ if (parent != aParent)
+ return -1;
+ aParent = parent;
+ }
+
+ if (aParent) {
+ let children = aParent.getAttribute(this.kCHILDREN);
+ let list = children.split('|');
+ let id = aTab.getAttribute(this.kID);
+ for (let i = 0, maxi = list.length; i < maxi; i++)
+ {
+ if (list[i] == id)
+ return i;
+ }
+ return -1;
+ }
+ else {
+ let tabs = this.rootTabs;
+ for (let i = 0, maxi = tabs.length; i < maxi; i++)
+ {
+ if (tabs[i] == aTab)
+ return i;
+ }
+ }
+ return -1;
+ },
+
+ getXOffsetOfTab : function TSTBase_getXOffsetOfTab(aTab)
+ {
+ var extraCondition = this.canCollapseSubtree(aTab) ?
+ '[not(@'+this.kCOLLAPSED+'="true")]' :
+ '' ;
+
+ return this.evaluateXPath(
+ 'sum((self::* | preceding-sibling::xul:tab[not(@hidden="true")]'+extraCondition+')'+
+ '/attribute::'+this.kX_OFFSET+')',
+ aTab,
+ Ci.nsIDOMXPathResult.NUMBER_TYPE
+ ).numberValue;
+ },
+ getYOffsetOfTab : function TSTBase_getYOffsetOfTab(aTab)
+ {
+ var extraCondition = this.canCollapseSubtree(aTab) ?
+ '[not(@'+this.kCOLLAPSED+'="true")]' :
+ '';
+
+ return this.evaluateXPath(
+ 'sum((self::* | preceding-sibling::xul:tab[not(@hidden="true")]'+extraCondition+')'+
+ '/attribute::'+this.kY_OFFSET+')',
+ aTab,
+ Ci.nsIDOMXPathResult.NUMBER_TYPE
+ ).numberValue;
+ },
+ getFutureBoxObject : function TSTBase_getFutureBoxObject(aTab)
+ {
+ var tabBox = aTab.boxObject;
+ var xOffset = this.getXOffsetOfTab(aTab);
+ var yOffset = this.getYOffsetOfTab(aTab);
+ return {
+ width : tabBox.width,
+ height : tabBox.height,
+ x : tabBox.x + xOffset,
+ y : tabBox.y + yOffset,
+ screenX : tabBox.screenX + xOffset,
+ screenY : tabBox.screenY + yOffset
+ };
+ },
+ getTabActualScreenPosition : function TSTBase_getTabActualScreenPosition(aTab, aOrient)
+ {
+ aOrient = aOrient || aTab.parentNode.orient;
+ return aOrient == 'vertical' ?
+ this.getTabActualScreenY(aTab) :
+ this.getTabActualScreenX(aTab) ;
+ },
+ MATRIX_PATTERN : /matrix\((-?\d+),\s*(-?\d+),\s*(-?\d+),\s*(-?\d+),\s*(-?\d+),\s*(-?\d+)\)/,
+ getTabActualScreenX : function TSTBase_getTabActualScreenX(aTab)
+ {
+ var x = aTab.boxObject.screenX;
+
+ var w = aTab.ownerDocument.defaultView;
+ var transform = w.getComputedStyle(aTab, null).transform;
+ var offset = transform && transform.match(this.MATRIX_PATTERN);
+ offset = offset ? parseFloat(offset[5]) : 0 ;
+
+ return x + offset;
+ },
+ getTabActualScreenY : function TSTBase_getTabActualScreenY(aTab)
+ {
+ var y = aTab.boxObject.screenY;
+
+ var w = aTab.ownerDocument.defaultView;
+ var transform = w.getComputedStyle(aTab, null).transform;
+ var offset = transform && transform.match(this.MATRIX_PATTERN);
+ offset = offset ? parseFloat(offset[6]) : 0 ;
+
+ return y + offset;
+ },
+
+ isGroupTab : function TSTBase_isGroupTab(aTab, aLazyCheck)
+ {
+ return (
+ (aLazyCheck || aTab.linkedBrowser.sessionHistory.count == 1) &&
+ aTab.linkedBrowser.currentURI.spec.indexOf('about:treestyletab-group') == 0
+ );
+ },
+
+ isTemporaryGroupTab : function TSTBase_isTemporaryGroupTab(aTab)
+ {
+ return (
+ this.isGroupTab(aTab, true) &&
+ /.*[\?&;]temporary=(?:1|yes|true)/i.test(aTab.linkedBrowser.currentURI.spec)
+ );
+ },
+
+ get pinnedTabsCount()
+ {
+ return this.browser.mTabContainer.querySelectorAll('tab[pinned="true"]').length;
+ },
+
+ forceExpandTabs : function TSTBase_forceExpandTabs(aTabs)
+ {
+ var collapsedStates = aTabs.map(function(aTab) {
+ return this.getTabValue(aTab, this.kSUBTREE_COLLAPSED) == 'true';
+ }, this);
+ for (let i = 0, maxi = aTabs.length; i < maxi; i++)
+ {
+ let tab = aTabs[i];
+ this.collapseExpandSubtree(tab, false, true);
+ this.collapseExpandTab(tab, false, true);
+ }
+ return collapsedStates;
+ },
+
+ getTreeStructureFromTabs : function TSTBase_getTreeStructureFromTabs(aTabs)
+ {
+ /* this returns...
+ [A] => -1 (parent is not in this tree)
+ [B] => 0 (parent is 1st item in this tree)
+ [C] => 0 (parent is 1st item in this tree)
+ [D] => 2 (parent is 2nd in this tree)
+ [E] => -1 (parent is not in this tree, and this creates another tree)
+ [F] => 0 (parent is 1st item in this another tree)
+ */
+ return this.cleanUpTreeStructureArray(
+ aTabs.map(function(aTab, aIndex) {
+ let tab = this.getParentTab(aTab);
+ let index = tab ? aTabs.indexOf(tab) : -1 ;
+ return index >= aIndex ? -1 : index ;
+ }, this),
+ -1
+ );
+ },
+ cleanUpTreeStructureArray : function TSTBase_cleanUpTreeStructureArray(aTreeStructure, aDefaultParent)
+ {
+ var offset = 0;
+ aTreeStructure = aTreeStructure
+ .map(function(aPosition, aIndex) {
+ return (aPosition == aIndex) ? -1 : aPosition ;
+ })
+ .map(function(aPosition, aIndex) {
+ if (aPosition == -1) {
+ offset = aIndex;
+ return aPosition;
+ }
+ return aPosition - offset;
+ });
+
+ /* The final step, this validates all of values.
+ Smaller than -1 is invalid, so it becomes to -1. */
+ aTreeStructure = aTreeStructure.map(function(aIndex) {
+ return aIndex < -1 ? aDefaultParent : aIndex ;
+ }, this);
+ return aTreeStructure;
+ },
+
+ applyTreeStructureToTabs : function TSTBase_applyTreeStructureToTabs(aTabs, aTreeStructure, aExpandStates)
+ {
+ var b = this.getTabBrowserFromChild(aTabs[0]);
+ if (!b)
+ return;
+ var sv = b.treeStyleTab;
+
+ aTabs = aTabs.slice(0, aTreeStructure.length);
+ aTreeStructure = aTreeStructure.slice(0, aTabs.length);
+
+ aExpandStates = (aExpandStates && typeof aExpandStates == 'object') ?
+ aExpandStates :
+ aTabs.map(function(aTab) {
+ return !!aExpandStates;
+ });
+ aExpandStates = aExpandStates.slice(0, aTabs.length);
+ while (aExpandStates.length < aTabs.length) aExpandStates.push(-1);
+
+ var parentTab = null;
+ for (let i = 0, maxi = aTabs.length; i < maxi; i++)
+ {
+ let tab = aTabs[i];
+ if (sv.isCollapsed(tab))
+ sv.collapseExpandTab(tab, false, true);
+ sv.detachTab(tab);
+
+ let parentIndexInTree = aTreeStructure[i];
+ if (parentIndexInTree < 0) // there is no parent, so this is a new parent!
+ parentTab = tab.getAttribute(sv.kID);
+
+ let parent = sv.getTabById(parentTab);
+ if (parent) {
+ let tabs = [parent].concat(sv.getDescendantTabs(parent));
+ parent = parentIndexInTree < tabs.length ? tabs[parentIndexInTree] : parent ;
+ }
+ if (parent) {
+ sv.attachTabTo(tab, parent, {
+ forceExpand : true,
+ dontMove : true
+ });
+ }
+ }
+
+ for (let i = aTabs.length-1; i > -1; i--)
+ {
+ sv.collapseExpandSubtree(aTabs[i], !sv.hasChildTabs(aTabs[i]) || !aExpandStates[i], true);
+ }
+ },
+
+ getTreeStructureFromTabBrowser : function TSTBase_getTreeStructureFromTabBrowser(aTabBrowser)
+ {
+ return this.getTreeStructureFromTabs(this.getAllTabs(aTabBrowser));
+ },
+
+ applyTreeStructureToTabBrowser : function TSTBase_applyTreeStructureToTabBrowser(aTabBrowser, aTreeStructure, aExpandAllTree)
+ {
+ var tabs = this.getAllTabs(aTabBrowser);
+ return this.applyTreeStructureToTabs(tabs, aTreeStructure, aExpandAllTree);
+ },
+
+/* tabbar position */
+
+ get position() /* PUBLIC API */
+ {
+ return utils.getTreePref('tabbar.position') || 'top';
+ },
+ set position(aValue)
+ {
+ var position = String(aValue).toLowerCase();
+ if (!position || !/^(top|bottom|left|right)$/.test(position))
+ position = 'top';
+
+ if (position != utils.getTreePref('tabbar.position'))
+ utils.setTreePref('tabbar.position', position);
+
+ return aValue;
+ },
+ get currentTabbarPosition() /* for backward compatibility */
+ {
+ return this.position;
+ },
+ set currentTabbarPosition(aValue)
+ {
+ return this.position = aValue;
+ },
+
+ getPositionFlag : function TSTBase_getPositionFlag(aPosition)
+ {
+ aPosition = String(aPosition).toLowerCase();
+ return (aPosition == 'left') ? this.kTABBAR_LEFT :
+ (aPosition == 'right') ? this.kTABBAR_RIGHT :
+ (aPosition == 'bottom') ? this.kTABBAR_BOTTOM :
+ this.kTABBAR_TOP;
+ },
+
+/* Pref Listener */
+
+ domains : [
+ 'extensions.treestyletab.',
+ 'browser.tabs.animate',
+ 'browser.tabs.insertRelatedAfterCurrent',
+ 'extensions.stm.tabBarMultiRows' // Super Tab Mode
+ ],
+
+ observe : function TSTBase_observe(aSubject, aTopic, aData)
+ {
+ switch (aTopic)
+ {
+ case 'nsPref:changed':
+ this.onPrefChange(aData);
+ return;
+ }
+ },
+
+ onPrefChange : function TSTBase_onPrefChange(aPrefName)
+ {
+ var value = prefs.getPref(aPrefName);
+ switch (aPrefName)
+ {
+ case 'extensions.treestyletab.indent.vertical':
+ this.baseIndentVertical = value;
+ Services.obs.notifyObservers(null, this.kTOPIC_INDENT_MODIFIED, value);
+ return;
+ case 'extensions.treestyletab.indent.horizontal':
+ this.baseIndentHorizontal = value;
+ Services.obs.notifyObservers(null, this.kTOPIC_INDENT_MODIFIED, value);
+ return;
+
+ case 'extensions.treestyletab.tabbar.width':
+ case 'extensions.treestyletab.tabbar.shrunkenWidth':
+ return this.updateTabWidthPrefs(aPrefName);
+
+ case 'browser.tabs.insertRelatedAfterCurrent':
+ case 'extensions.stm.tabBarMultiRows': // Super Tab Mode
+ if (this.prefOverriding)
+ return;
+ aPrefName += '.override';
+ prefs.setPref(aPrefName, value);
+ case 'browser.tabs.insertRelatedAfterCurrent.override':
+ case 'extensions.stm.tabBarMultiRows.override': // Super Tab Mode
+ if (prefs.getPref(aPrefName+'.force')) {
+ let defaultValue = prefs.getDefaultPref(aPrefName);
+ if (value != defaultValue) {
+ prefs.setPref(aPrefName, defaultValue);
+ return;
+ }
+ }
+ this.prefOverriding = true;
+ let (target = aPrefName.replace('.override', '')) {
+ let originalValue = prefs.getPref(target);
+ if (originalValue !== null && originalValue != value)
+ prefs.setPref(target+'.backup', originalValue);
+ prefs.setPref(target, prefs.getPref(aPrefName));
+ }
+ this.prefOverriding = false;
+ return;
+
+ case 'extensions.treestyletab.clickOnIndentSpaces.enabled':
+ return this.shouldDetectClickOnIndentSpaces = prefs.getPref(aPrefName);
+
+ case 'extensions.treestyletab.tabbar.scroll.smooth':
+ return this.smoothScrollEnabled = value;
+ case 'extensions.treestyletab.tabbar.scroll.duration':
+ return this.smoothScrollDuration = value;
+
+ case 'extensions.treestyletab.tabbar.scrollToNewTab.mode':
+ return this.scrollToNewTabMode = value;
+
+ case 'extensions.treestyletab.tabbar.narrowScrollbar.size':
+ return this.updateNarrowScrollbarStyle();
+
+ case 'browser.tabs.animate':
+ return this.animationEnabled = value;
+ case 'extensions.treestyletab.animation.indent.duration':
+ return this.indentDuration = value;
+ case 'extensions.treestyletab.animation.collapse.duration':
+ return this.collapseDuration = value;
+
+ case 'extensions.treestyletab.twisty.expandSensitiveArea':
+ return this.shouldExpandTwistyArea = value;
+
+ case 'extensions.treestyletab.counter.role.horizontal':
+ return this.counterRoleHorizontal = value;
+
+ case 'extensions.treestyletab.counter.role.vertical':
+ return this.counterRoleVertical = value;
+
+ default:
+ return;
+ }
+ },
+
+ updateTabWidthPrefs : function TSTBase_updateTabWidthPrefs(aPrefName)
+ {
+ var expanded = utils.getTreePref('tabbar.width');
+ var shrunken = utils.getTreePref('tabbar.shrunkenWidth');
+ var originalExpanded = expanded;
+ var originalShrunken = shrunken;
+ if (aPrefName == 'extensions.treestyletab.tabbar.shrunkenWidth') {
+ if (expanded <= shrunken)
+ expanded = parseInt(shrunken / this.DEFAULT_SHRUNKEN_WIDTH_RATIO)
+ let w = this.browserWindow;
+ if (w && expanded > w.gBrowser.boxObject.width) {
+ expanded = w.gBrowser.boxObject.width * this.MAX_TABBAR_SIZE_RATIO;
+ if (expanded <= shrunken)
+ shrunken = parseInt(expanded * this.DEFAULT_SHRUNKEN_WIDTH_RATIO)
+ }
+ }
+ else {
+ if (expanded <= shrunken)
+ shrunken = parseInt(expanded * this.DEFAULT_SHRUNKEN_WIDTH_RATIO);
+ }
+ if (expanded != originalExpanded ||
+ shrunken != originalShrunken) {
+ utils.setTreePref('tabbar.width', Math.max(0, expanded));
+ utils.setTreePref('tabbar.shrunkenWidth', Math.max(0, shrunken));
+ }
+ },
+
+ get shouldApplyNewPref()
+ {
+ return (
+ !this.applyOnlyForActiveWindow ||
+ this.window == this.topBrowserWindow
+ ) &&
+ !this.inWindowDestoructionProcess;
+ },
+
+ applyOnlyForActiveWindow : false,
+ setPrefForActiveWindow : function TSTBase_setPrefForActiveWindow(aTask) {
+ TreeStyleTabBase.applyOnlyForActiveWindow = true;
+ try {
+ aTask.call(this);
+ }
+ finally {
+ TreeStyleTabBase.applyOnlyForActiveWindow = false;
+ }
+ }
+
+});
+
+TreeStyleTabBase.init();
+
diff --git a/modules/browser.js b/modules/browser.js
index fba999cd..9dc4604c 100644
--- a/modules/browser.js
+++ b/modules/browser.js
@@ -1,6812 +1,6812 @@
-/* ***** 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 YUKI "Piro" Hiroshi.
- * Portions created by the Initial Developer are Copyright (C) 2011-2014
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s): YUKI "Piro" Hiroshi
- * wanabe
- * Tetsuharu OHZEKI
- *
- * 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 ******/
-
-const EXPORTED_SYMBOLS = ['TreeStyleTabBrowser'];
-
-const DEBUG = false;
-
-const Cc = Components.classes;
-const Ci = Components.interfaces;
-const Cu = Components.utils;
-
-Cu.import('resource://gre/modules/XPCOMUtils.jsm');
-Cu.import('resource://treestyletab-modules/lib/inherit.jsm');
-
-XPCOMUtils.defineLazyModuleGetter(this, 'Services', 'resource://gre/modules/Services.jsm');
-XPCOMUtils.defineLazyModuleGetter(this, 'utils', 'resource://treestyletab-modules/utils.js', 'TreeStyleTabUtils');
-XPCOMUtils.defineLazyModuleGetter(this, 'FullTooltipManager', 'resource://treestyletab-modules/fullTooltip.js');
-XPCOMUtils.defineLazyModuleGetter(this, 'TabbarDNDObserver', 'resource://treestyletab-modules/tabbarDNDObserver.js');
-XPCOMUtils.defineLazyModuleGetter(this, 'TabpanelDNDObserver', 'resource://treestyletab-modules/tabpanelDNDObserver.js');
-XPCOMUtils.defineLazyModuleGetter(this, 'AutoHideBrowser', 'resource://treestyletab-modules/autoHide.js');
-XPCOMUtils.defineLazyModuleGetter(this, 'BrowserUIShowHideObserver', 'resource://treestyletab-modules/browserUIShowHideObserver.js');
-
-XPCOMUtils.defineLazyGetter(this, 'window', function() {
- Cu.import('resource://treestyletab-modules/lib/namespace.jsm');
- return getNamespaceFor('piro.sakura.ne.jp');
-});
-XPCOMUtils.defineLazyGetter(this, 'prefs', function() {
- Cu.import('resource://treestyletab-modules/lib/prefs.js');
- return window['piro.sakura.ne.jp'].prefs;
-});
-
-Cu.import('resource://treestyletab-modules/window.js');
-
-function TreeStyleTabBrowser(aWindowService, aTabBrowser)
-{
- this.id = Date.now() + '-' + parseInt(Math.random() * 65000);
-
- this.windowService = aWindowService;
- this.window = aWindowService.window;
- this.document = aWindowService.document;
-
- this.mTabBrowser = aTabBrowser;
- aTabBrowser.treeStyleTab = this;
-
- this.tabVisibilityChangedTabs = [];
- this.updateTabsIndentWithDelayTabs = [];
- this.deferredTasks = {};
-
- this.tabVisibilityChangedTabs = [];
- this._updateFloatingTabbarReason = 0;
- this.internallyTabMovingCount = 0;
- this.subTreeMovingCount = 0;
- this.subTreeChildrenMovingCount = 0;
- this._treeViewEnabled = true;
-}
-
-TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
-
- kMENUITEM_RELOADSUBTREE : 'context-item-reloadTabSubtree',
- kMENUITEM_RELOADCHILDREN : 'context-item-reloadDescendantTabs',
- kMENUITEM_REMOVESUBTREE : 'context-item-removeTabSubtree',
- kMENUITEM_REMOVECHILDREN : 'context-item-removeDescendantTabs',
- kMENUITEM_REMOVEALLTABSBUT : 'context-item-removeAllTabsButThisTree',
- kMENUITEM_COLLAPSEEXPAND_SEPARATOR : 'context-separator-collapseExpandAll',
- kMENUITEM_COLLAPSE : 'context-item-collapseAllSubtree',
- kMENUITEM_EXPAND : 'context-item-expandAllSubtree',
- kMENUITEM_AUTOHIDE_SEPARATOR : 'context-separator-toggleAutoHide',
- kMENUITEM_AUTOHIDE : 'context-item-toggleAutoHide',
- kMENUITEM_FIXED : 'context-item-toggleFixed',
- kMENUITEM_BOOKMARKSUBTREE : 'context-item-bookmarkTabSubtree',
-
- kMENUITEM_CLOSE_TABS_TO_END : 'context_closeTabsToTheEnd',
-
- mTabBrowser : null,
-
- indent : -1,
- indentProp : 'margin',
- indentTarget : 'left',
- indentCSSProp : 'margin-left',
- collapseTarget : 'top',
- collapseCSSProp : 'margin-top',
- screenPositionProp : 'screenY',
- offsetProp : 'offsetY',
- translateFunction : 'translateY',
- sizeProp : 'height',
- invertedScreenPositionProp : 'screenX',
- invertedSizeProp : 'width',
- startProp : 'top',
- endProp : 'bottom',
-
- maxTreeLevelPhisical : false,
-
- needRestoreTree : false,
-
-/* elements */
-
- get browser()
- {
- return this.mTabBrowser;
- },
-
- get container()
- {
- if (!this._container) {
- this._container = this.document.getElementById('appcontent');
- }
- return this._container;
- },
- _container : null,
-
- get scrollBox()
- {
- return ( // Tab Mix Plus
- utils.getTreePref('compatibility.TMP') &&
- this.document.getAnonymousElementByAttribute(this.mTabBrowser.mTabContainer, 'class', 'tabs-frame')
- ) ||
- this.mTabBrowser.mTabContainer.mTabstrip;
- },
- get scrollBoxObject()
- {
- var node = this.scrollBox;
- if (node._scrollbox)
- node = node._scrollbox;
- return (node.scrollBoxObject || node.boxObject)
- .QueryInterface(Ci.nsIScrollBoxObject); // for Tab Mix Plus (ensure scrollbox-ed)
- },
-
- get splitter()
- {
- var d = this.document;
- return d.getAnonymousElementByAttribute(this.mTabBrowser, 'class', this.kSPLITTER) ||
- d.getAnonymousElementByAttribute(this.mTabBrowser, 'id', 'tabkit-splitter'); // Tab Kit
- },
-
- get tabStripPlaceHolder()
- {
- return this._tabStripPlaceHolder;
- },
- set tabStripPlaceHolder(value)
- {
- return (this._tabStripPlaceHolder = value);
- },
-
-/* properties */
-
- get maxTreeLevel()
- {
- return this._maxTreeLevel;
- },
- set maxTreeLevel(aValue)
- {
- this._maxTreeLevel = aValue;
- this.setTabbrowserAttribute(this.kMAX_LEVEL, this._maxTreeLevel || '0');
- this.enableSubtreeIndent = this._maxTreeLevel != 0;
- return aValue;
- },
- _maxTreeLevel : -1,
-
- get baseIndent() {
- return this.isVertical ? this.baseIndentVertical : this.baseIndentHorizontal;
- },
-
- get enableSubtreeIndent()
- {
- return this._enableSubtreeIndent;
- },
- set enableSubtreeIndent(aValue)
- {
- this._enableSubtreeIndent = aValue;
- this.setTabbrowserAttribute(this.kINDENTED, this._enableSubtreeIndent ? 'true' : null);
- return aValue;
- },
- _enableSubtreeIndent : true,
-
- get allowSubtreeCollapseExpand()
- {
- return this._allowSubtreeCollapseExpand;
- },
- set allowSubtreeCollapseExpand(aValue)
- {
- this._allowSubtreeCollapseExpand = aValue;
- this.setTabbrowserAttribute(this.kALLOW_COLLAPSE, this._allowSubtreeCollapseExpand ? 'true' : null);
- return aValue;
- },
- _allowSubtreeCollapseExpand : true,
-
- get fixed()
- {
- var orient = this.isVertical ? 'vertical' : 'horizontal' ;
- if (!this.windowService.preInitialized)
- return utils.getTreePref('tabbar.fixed.'+orient);
-
- var b = this.mTabBrowser;
- if (!b)
- return false;
- return b.getAttribute(this.kFIXED+'-'+orient) == 'true';
- },
- set fixed(aValue)
- {
- this.setTabbrowserAttribute(this.kFIXED, aValue || null, this.mTabBrowser);
- return aValue;
- },
- get isFixed() // for backward compatibility
- {
- return this.fixed;
- },
-
- get position() /* PUBLIC API */
- {
- return (
- // Don't touch to the element before it is initialized by XBL constructor.
- (this.windowService.preInitialized && this.browser.getAttribute(this.kTABBAR_POSITION)) ||
- this.base.position
- );
- },
- set position(aValue)
- {
- var position = String(aValue).toLowerCase();
- if (!position || !/^(top|bottom|left|right)$/.test(position))
- position = 'top';
-
- if (position == this.position)
- return position;
-
- if ('UndoTabService' in this.window && this.window.UndoTabService.isUndoable()) {
- var current = this.position;
- var self = this;
- this.window.UndoTabService.doOperation(
- function() {
- self._changeTabbarPosition(position);
- },
- {
- label : utils.treeBundle.getString('undo_changeTabbarPosition_label'),
- name : 'treestyletab-changeTabbarPosition-private',
- data : {
- oldPosition : current,
- newPosition : position,
- target : self.mTabBrowser.id
- }
- }
- );
- }
- else {
- this._changeTabbarPosition(position);
- }
- return position;
- },
- _changeTabbarPosition : function TSTBrowser_changeTabbarPosition(aNewPosition)
- {
- if (this.deferredTasks['_changeTabbarPosition'])
- this.deferredTasks['_changeTabbarPosition'].cancel();
-
- var oldPosition = this.position;
- this.fireTabbarPositionEvent(true, oldPosition, aNewPosition);
-
- this.initTabbar(aNewPosition, oldPosition);
- this.reinitAllTabs();
-
- var self = this;
- (this.deferredTasks['_changeTabbarPosition'] = this.Deferred.next(function() {
- self.checkTabsIndentOverflow();
- self.fireTabbarPositionEvent(false, oldPosition, aNewPosition);
- })).error(this.defaultDeferredErrorHandler).next(function() {
- delete self.deferredTasks['_changeTabbarPosition'];
- });
- },
-
-/* status getters */
-
- get isVertical()
- {
- if (!this.windowService.preInitialized)
- return ['left', 'right'].indexOf(this.position) > -1;
-
- var b = this.mTabBrowser;
- if (!b)
- return false;
-
- if (b.hasAttribute(this.kMODE))
- return b.getAttribute(this.kMODE) == 'vertical';
-
- var box = this.scrollBox || b.mTabContainer ;
- return (box.getAttribute('orient') || this.window.getComputedStyle(box, '').getPropertyValue('-moz-box-orient')) == 'vertical';
- },
-
- get isVisible()
- {
- var bar = this.ownerToolbar;
- var style = this.window.getComputedStyle(bar, '');
- if (style.visibility != 'visible' || style.display == 'none')
- return false;
-
- var box = bar.boxObject;
- return !!(box.width || box.height);
- },
-
- isFloating : true, // for backward compatibility (but this should be removed)
-
- get ownerToolbar()
- {
- return this.evaluateXPath(
- 'ancestor-or-self::xul:toolbar[1]',
- this.mTabBrowser.tabContainer,
- Ci.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE
- ).singleNodeValue;
- },
-
- get canStackTabs()
- {
- return (
- !this.isVertical &&
- this.canCollapseSubtree() &&
- utils.getTreePref('stackCollapsedTabs')
- );
- },
-
- get counterRole()
- {
- return this.isVertical ? this.counterRoleVertical : this.counterRoleHorizontal ;
- },
-
- get isDestroying()
- {
- return !this.mTabBrowser || !this.mTabBrowser.mTabContainer;
- },
-
-/* utils */
-
-/* get tab contents */
-
- getTabLabel : function TSTBrowser_getTabLabel(aTab)
- {
- var d = this.document;
- var label = d.getAnonymousElementByAttribute(aTab, 'class', 'tab-text-stack') || // Mac OS X
- ( // Tab Mix Plus
- utils.getTreePref('compatibility.TMP') &&
- d.getAnonymousElementByAttribute(aTab, 'class', 'tab-text-container')
- ) ||
- d.getAnonymousElementByAttribute(aTab, 'class', 'tab-text tab-label');
- return label;
- },
-
- getTabClosebox : function TSTBrowser_getTabClosebox(aTab)
- {
- var d = this.document;
- var close = ( // Tab Mix Plus
- utils.getTreePref('compatibility.TMP') &&
- d.getAnonymousElementByAttribute(aTab, 'class', 'tab-close-button always-right')
- ) ||
- d.getAnonymousElementByAttribute(aTab, 'anonid', 'close-button') || // with Australis
- d.getAnonymousElementByAttribute(aTab, 'class', 'tab-close-button');
- return close;
- },
-
- getTabTwisty : function TSTBrowser_getTabTwisty(aTab)
- {
- return this.document.getAnonymousElementByAttribute(aTab, 'class', this.kTWISTY);
- },
-
- getTabTwistyAnchorNode : function TSTBrowser_getTabTwistyAnchorNode(aTab)
- {
- return this.document.getAnonymousElementByAttribute(aTab, 'class', 'tab-icon') || // Tab Mix Plus
- this.document.getAnonymousElementByAttribute(aTab, 'class', 'tab-throbber');
- },
-
- getTabFromTabbarEvent : function TSTBrowser_getTabFromTabbarEvent(aEvent)
- {
- if (
- !this.shouldDetectClickOnIndentSpaces ||
- !this.getAncestorTabbarFromEvent(aEvent) ||
- this.isEventFiredOnClickable(aEvent) ||
- this.getSplitterFromEvent(aEvent)
- )
- return null;
- return this.getTabFromCoordinates(aEvent);
- },
- getTabFromCoordinates : function TSTBrowser_getTabFromCoordinates(aCoordinates, aTabs)
- {
- var tab = this.document.elementFromPoint(aCoordinates.clientX, aCoordinates.clientY);
- if (tab && tab.localName == 'tab' && (!aTabs || aTabs.indexOf(tab) > -1))
- return tab;
-
- var positionCoordinate = aCoordinates[this.screenPositionProp];
-
- var tabs = aTabs || this.getTabs(this.mTabBrowser);
- if (!tabs.length ||
- this.getTabActualScreenPosition(tabs[0]) > positionCoordinate ||
- this.getTabActualScreenPosition(tabs[tabs.length-1]) < positionCoordinate)
- return null;
-
- var low = 0;
- var high = tabs.length - 1;
- while (low <= high) {
- let middle = Math.floor((low + high) / 2);
- let position = this.getTabActualScreenPosition(tabs[middle]);
- if (position > positionCoordinate) {
- high = middle - 1;
- }
- else if (position + tabs[middle].boxObject[this.sizeProp] < positionCoordinate) {
- low = middle + 1;
- }
- else {
- return tabs[middle];
- }
- }
- return null;
-/*
- var tab = null;
- this.getTabs(this.mTabBrowser).some(function(aTab) {
- var box = aTab.boxObject;
- if (box[this.screenPositionProp] > positionCoordinate ||
- box[this.screenPositionProp] + box[this.sizeProp] < positionCoordinate) {
- return false;
- }
- tab = aTab;
- return true;
- }, this);
- return tab;
-*/
- },
-
- getNextFocusedTab : function TSTBrowser_getNextFocusedTab(aTab)
- {
- return this.getNextSiblingTab(aTab) ||
- this.getPreviousVisibleTab(aTab);
- },
-
- isTabInViewport : function TSTBrowser_isTabInViewport(aTab)
- {
- if (!this.windowService.preInitialized || !aTab)
- return false;
- if (aTab.getAttribute('pinned') == 'true')
- return true;
- var tabBox = this.getFutureBoxObject(aTab);
- var barBox = this.scrollBox.boxObject;
- return (
- tabBox.screenX >= barBox.screenX &&
- tabBox.screenX + tabBox.width <= barBox.screenX + barBox.width &&
- tabBox.screenY >= barBox.screenY &&
- tabBox.screenY + tabBox.height <= barBox.screenY + barBox.height
- );
- },
-
- isMultiRow : function TSTBrowser_isMultiRow()
- {
- var w = this.window;
- return ('tabberwocky' in w && utils.getTreePref('compatibility.Tabberwocky')) ?
- (prefs.getPref('tabberwocky.multirow') && !this.isVertical) :
- ('TabmixTabbar' in w && utils.getTreePref('compatibility.TMP')) ?
- w.TabmixTabbar.isMultiRow :
- false ;
- },
-
- positionPinnedTabs : function TSTBrowser_positionPinnedTabs(aWidth, aHeight, aJustNow)
- {
- var b = this.mTabBrowser;
- var tabbar = b.tabContainer;
- if (
- !tabbar ||
- !tabbar._positionPinnedTabs ||
- !tabbar.boxObject.width
- )
- return;
-
- var count = this.pinnedTabsCount;
- if (!this.isVertical || !count) {
- this.resetPinnedTabs();
- b.mTabContainer._positionPinnedTabs();
- return;
- }
-
- var tabbarPlaceHolderWidth = this._tabStripPlaceHolder.boxObject.width;
- var tabbarWidth = this.tabStrip.boxObject.width;
-
- var maxWidth = tabbarPlaceHolderWidth || tabbarWidth;
-
- var faviconized = utils.getTreePref('pinnedTab.faviconized');
- var faviconizedSize = tabbar.childNodes[0].boxObject.height;
-
- var width = faviconized ? faviconizedSize : maxWidth ;
- var height = faviconizedSize;
- var maxCol = Math.max(1, Math.floor(maxWidth / width));
- var maxRow = Math.ceil(count / maxCol);
- var col = 0;
- var row = 0;
-
- var baseX = this.tabStrip.boxObject.screenX - this.document.documentElement.boxObject.screenX;
-
- var shrunkenOffset = (this.position == 'right' && tabbarPlaceHolderWidth) ?
- tabbarWidth - tabbarPlaceHolderWidth :
- 0 ;
-
- var removeFaviconizedClassPattern = new RegExp('\\s+'+this.kFAVICONIZED, 'g');
-
- tabbar.style.MozMarginStart = '';
- tabbar.style.setProperty('margin-top', (height * maxRow)+'px', 'important');
- for (let i = 0; i < count; i++)
- {
- let item = tabbar.childNodes[i];
-
- let style = item.style;
- style.MozMarginStart = '';
-
- let transitionStyleBackup = style.transition || style.MozTransition || '';
- if (aJustNow)
- style.MozTransition = style.transition = 'none';
-
- let className = item.className.replace(removeFaviconizedClassPattern, '');
- if (faviconized)
- className += ' '+this.kFAVICONIZED;
- if (className != item.className)
- item.className = className;
-
- style.maxWidth = style.width = width+'px';
- style.setProperty('margin-left', ((width * col) + shrunkenOffset)+'px', 'important');
- style.left = baseX+'px';
- style.right = 'auto';
- style.marginRight = '';
-
- style.setProperty('margin-top', (- height * (maxRow - row))+'px', 'important');
- style.top = style.bottom = '';
-
- if (aJustNow) {
- let key = 'positionPinnedTabs_tab_'+parseInt(Math.random() * 65000);
- (this.deferredTasks[key] = this.Deferred.next(function() { // "transition" must be cleared after the reflow.
- style.MozTransition = style.transition = transitionStyleBackup;
- })).error(this.defaultDeferredErrorHandler).next(function() {
- delete self.deferredTasks[key];
- });
- }
-
- col++;
- if (col >= maxCol) {
- col = 0;
- row++;
- }
- }
- },
- positionPinnedTabsWithDelay : function TSTBrowser_positionPinnedTabsWithDelay(...aArgs)
- {
- if (this.deferredTasks['positionPinnedTabsWithDelay'])
- return;
-
- var lastArgs = this.deferredTasks['positionPinnedTabsWithDelay'] ?
- this.deferredTasks['positionPinnedTabsWithDelay'].__treestyletab__args :
- [null, null, false] ;
- lastArgs[0] = lastArgs[0] || aArgs[0];
- lastArgs[1] = lastArgs[1] || aArgs[1];
- lastArgs[2] = lastArgs[2] || aArgs[2];
-
- var self = this;
- (this.deferredTasks['positionPinnedTabsWithDelay'] = this.Deferred.wait(0).next(function() {
- return self.Deferred.next(function() {
- // do with delay again, after Firefox's reposition was completely finished.
- self.positionPinnedTabs.apply(self, lastArgs);
- });
- })).error(this.defaultDeferredErrorHandler).next(function() {
- delete self.deferredTasks['positionPinnedTabsWithDelay'];
- });
- this.deferredTasks['positionPinnedTabsWithDelay'].__treestyletab__args = lastArgs;
- },
-
- resetPinnedTabs : function TSTBrowser_resetPinnedTabs()
- {
- var b = this.mTabBrowser;
- var tabbar = b.tabContainer;
- tabbar.style.MozMarginStart = tabbar.style.marginTop = '';
- for (var i = 0, count = this.pinnedTabsCount; i < count; i++)
- {
- let style = tabbar.childNodes[i].style;
- style.maxWidth = style.width = style.left = style.right =
- style.MozMarginStart = style.marginLeft = style.marginRight = style.marginTop = '';
- }
- },
-
- updateTabsZIndex : function TSTBrowser_updateTabsZIndex(aStacked)
- {
- var tabs = this.getTabs(this.mTabBrowser);
- var count = tabs.length;
- for (let i = 0; i < count; i++)
- {
- let tab = tabs[i];
- if (aStacked)
- tab.style.zIndex = count * 1000 - i;
- else
- tab.style.zIndex = '';
- }
- },
-
- fixTooNarrowTabbar : function TSTBrowser_fixTooNarrowTabbar()
- {
- /**
- * The tab bar can become smaller than the actual size of the
- * floating tab bar, and then, we cannot resize tab bar by
- * dragging anymore. To avoid this problem, we have to enlarge
- * the tab bar larger than the floating tab bar.
- */
- if (this.isVertical) {
- let key = this.autoHide.expanded ?
- 'tabbar.width' : 'tabbar.shrunkenWidth' ;
- let width = utils.getTreePref(key);
- let minWidth = Math.max(this.MIN_TABBAR_WIDTH, this.scrollBox.boxObject.width);
- if (minWidth > width) {
- this.setPrefForActiveWindow(function() {
- utils.setTreePref(key, minWidth);
- this.updateFloatingTabbar(this.kTABBAR_UPDATE_BY_PREF_CHANGE);
- });
- }
- }
- else {
- let height = utils.getTreePref('tabbar.height');
- let minHeight = Math.max(this.MIN_TABBAR_HEIGHT, this.scrollBox.boxObject.height);
- if (minHeight > height) {
- this.setPrefForActiveWindow(function() {
- utils.setTreePref('tabbar.height', minHeight);
- this.updateFloatingTabbar(this.kTABBAR_UPDATE_BY_PREF_CHANGE);
- });
- }
- }
- },
-
-/* initialize */
-
- init : function TSTBrowser_init()
- {
- this.stopRendering();
-
- var w = this.window;
- var d = this.document;
- var b = this.mTabBrowser;
- b.tabContainer.treeStyleTab = this;
-
- this.tabsHash = {};
-
- if (b.tabContainer.parentNode.localName == 'toolbar')
- b.tabContainer.parentNode.classList.add(this.kTABBAR_TOOLBAR);
-
- /**
- * On secondary (and later) window, SSWindowStateBusy event can be fired
- * before DOMContentLoad, on "domwindowopened".
- */
- this.needRestoreTree = w.__treestyletab__WindowStateBusy || false;
- delete w.__treestyletab__WindowStateBusy;
-
- this._initTabbrowserExtraContents();
-
- var position = this.position;
- this.fireTabbarPositionEvent(this.kEVENT_TYPE_TABBAR_POSITION_CHANGING, 'top', position); /* PUBLIC API */
-
- this.setTabbrowserAttribute(this.kFIXED+'-horizontal', utils.getTreePref('tabbar.fixed.horizontal') ? 'true' : null, b);
- this.setTabbrowserAttribute(this.kFIXED+'-vertical', utils.getTreePref('tabbar.fixed.vertical') ? 'true' : null, b);
- this.setTabStripAttribute(this.kTAB_STRIP_ELEMENT, true);
-
- /**
- * has its custom background color for itself, but it
- * prevents to make transparent background of the vertical tab bar.
- * So, I re-define the background color of content area for
- * es via dynamically generated stylesheet.
- * See:
- * https://bugzilla.mozilla.org/show_bug.cgi?id=558585
- * http://hg.mozilla.org/mozilla-central/rev/e90bdd97d168
- */
- if (b.style.backgroundColor) {
- let color = b.style.backgroundColor;
- let pi = d.createProcessingInstruction(
- 'xml-stylesheet',
- 'type="text/css" href="data:text/css,'+encodeURIComponent(
- ('.tabbrowser-tabbox > tabpanels > notificationbox {\n' +
- ' background-color: %COLOR%;\n' +
- '}').replace(/%COLOR%/, color)
- )+'"'
- );
- d.insertBefore(pi, d.documentElement);
- b.style.backgroundColor = '';
- }
-
- this.initTabbar(null, this.kTABBAR_TOP);
-
- w.addEventListener('resize', this, true);
- w.addEventListener('beforecustomization', this, true);
- w.addEventListener('aftercustomization', this, false);
- w.addEventListener('customizationchange', this, false);
- w.addEventListener(this.kEVENT_TYPE_PRINT_PREVIEW_ENTERED, this, false);
- w.addEventListener(this.kEVENT_TYPE_PRINT_PREVIEW_EXITED, this, false);
- w.addEventListener('tabviewframeinitialized', this, false);
- w.addEventListener(this.kEVENT_TYPE_TAB_FOCUS_SWITCHING_END, this, false);
- w.addEventListener('SSWindowStateBusy', this, false);
-
- b.addEventListener('nsDOMMultipleTabHandlerTabsClosing', this, false);
-
- w['piro.sakura.ne.jp'].tabsDragUtils.initTabBrowser(b);
-
- w.TreeStyleTabWindowHelper.initTabbrowserMethods(b);
- this._initTabbrowserContextMenu();
- w.TreeStyleTabWindowHelper.updateTabDNDObserver(b);
-
- this.getAllTabs(b).forEach(this.initTab, this);
-
- this.onPrefChange('extensions.treestyletab.maxTreeLevel');
- this.onPrefChange('extensions.treestyletab.tabbar.style');
- this.onPrefChange('extensions.treestyletab.twisty.style');
- this.onPrefChange('extensions.treestyletab.showBorderForFirstTab');
- this.onPrefChange('extensions.treestyletab.tabbar.invertTabContents');
- this.onPrefChange('extensions.treestyletab.tabbar.invertClosebox');
- this.onPrefChange('extensions.treestyletab.tabbar.autoShow.mousemove');
- this.onPrefChange('extensions.treestyletab.tabbar.invertScrollbar');
- this.onPrefChange('extensions.treestyletab.tabbar.narrowScrollbar');
- this.onPrefChange('browser.tabs.animate');
-
- Services.obs.addObserver(this, this.kTOPIC_INDENT_MODIFIED, false);
- Services.obs.addObserver(this, this.kTOPIC_COLLAPSE_EXPAND_ALL, false);
- Services.obs.addObserver(this, this.kTOPIC_CHANGE_TREEVIEW_AVAILABILITY, false);
- Services.obs.addObserver(this, 'lightweight-theme-styling-update', false);
- prefs.addPrefListener(this);
-
- // Don't init these ovservers on this point to avoid needless initializations.
- // this.tabbarDNDObserver;
- // this.panelDNDObserver;
- this._readyToInitDNDObservers();
-
- // Init autohide service only if it have to be activated.
- if (this.isAutoHide)
- this.autoHide;
-
- this.updateFloatingTabbar(this.kTABBAR_UPDATE_BY_INITIALIZE);
- this.fixTooNarrowTabbar();
-
- this.fireTabbarPositionEvent(false, 'top', position); /* PUBLIC API */
-
- this.startRendering();
-
- if (this.deferredTasks['init'])
- this.deferredTasks['init'].cancel();
-
- var self = this;
- (this.deferredTasks['init'] = this.Deferred.next(function() {
- // This command is always enabled and the TabsOnTop can be enabled
- // by .updateVisibility().
- // So we have to reset TabsOnTop state on the startup.
- var toggleTabsOnTop = d.getElementById('cmd_ToggleTabsOnTop');
- var TabsOnTop = 'TabsOnTop' in w ? w.TabsOnTop : null ;
- if (TabsOnTop && TabsOnTop.syncUI && toggleTabsOnTop && self.isVertical) {
- toggleTabsOnTop.setAttribute('disabled', true);
- if (TabsOnTop.enabled && TabsOnTop.toggle)
- TabsOnTop.toggle();
- }
- })).error(this.defaultDeferredErrorHandler).next(function() {
- delete self.deferredTasks['init'];
- });
- },
-
- _initTabbrowserExtraContents : function TSTBrowser_initTabbrowserExtraContents()
- {
- var d = this.document;
- var b = this.mTabBrowser;
-
- var toggler = d.getAnonymousElementByAttribute(b, 'class', this.kTABBAR_TOGGLER);
- if (!toggler) {
- toggler = d.createElement('spacer');
- toggler.setAttribute(this.kTAB_STRIP_ELEMENT, true);
- toggler.setAttribute('class', this.kTABBAR_TOGGLER);
- toggler.setAttribute('layer', true); // https://bugzilla.mozilla.org/show_bug.cgi?id=590468
- b.mTabBox.insertBefore(toggler, b.mTabBox.firstChild);
- if (b.mTabDropIndicatorBar == toggler)
- b.mTabDropIndicatorBar = d.getAnonymousElementByAttribute(b, 'class', 'tab-drop-indicator-bar');
- }
-
- var placeHolder = d.getAnonymousElementByAttribute(b, 'anonid', 'strip');
- if (!placeHolder) {
- placeHolder = d.createElement('hbox');
- placeHolder.setAttribute(this.kTAB_STRIP_ELEMENT, true);
- placeHolder.setAttribute('anonid', 'strip');
- placeHolder.setAttribute('class', 'tabbrowser-strip '+this.kTABBAR_PLACEHOLDER);
- placeHolder.setAttribute('layer', true); // https://bugzilla.mozilla.org/show_bug.cgi?id=590468
- b.mTabBox.insertBefore(placeHolder, toggler.nextSibling);
- }
- this.tabStripPlaceHolder = (placeHolder != this.tabStrip) ? placeHolder : null ;
-
- if (this.tabStripPlaceHolder)
- this.tabStripPlaceHolderBoxObserver = new BrowserUIShowHideObserver(this, this.tabStripPlaceHolder.parentNode);
- },
-
- _initTabbrowserContextMenu : function TSTBrowser_initTabbrowserContextMenu()
- {
- var w = this.window;
- var d = this.document;
- var b = this.mTabBrowser;
-
- var tabContextMenu = b.tabContextMenu ||
- d.getAnonymousElementByAttribute(b, 'anonid', 'tabContextMenu');
- tabContextMenu.addEventListener('popupshowing', this, false);
- if (!('MultipleTabService' in w)) {
- w.setTimeout(function(aSelf, aTabBrowser, aPopup) {
- let suffix = '-tabbrowser-'+(aTabBrowser.id || 'instance-'+parseInt(Math.random() * 65000));
- let ids = [
- aSelf.kMENUITEM_RELOADSUBTREE,
- aSelf.kMENUITEM_RELOADCHILDREN,
- aSelf.kMENUITEM_REMOVESUBTREE,
- aSelf.kMENUITEM_REMOVECHILDREN,
- aSelf.kMENUITEM_REMOVEALLTABSBUT,
- aSelf.kMENUITEM_COLLAPSEEXPAND_SEPARATOR,
- aSelf.kMENUITEM_COLLAPSE,
- aSelf.kMENUITEM_EXPAND,
- aSelf.kMENUITEM_AUTOHIDE_SEPARATOR,
- aSelf.kMENUITEM_AUTOHIDE,
- aSelf.kMENUITEM_FIXED,
- aSelf.kMENUITEM_BOOKMARKSUBTREE
- ];
- for (let i = 0, maxi = ids.length; i < maxi; i++)
- {
- let id = ids[i];
- let item = d.getElementById(id).cloneNode(true);
- item.setAttribute('id', item.getAttribute('id')+suffix);
-
- let refNode = void(0);
- let insertAfter = item.getAttribute('multipletab-insertafter');
- if (insertAfter) {
- try {
- eval('refNode = ('+insertAfter+').nextSibling');
- }
- catch(e) {
- }
- }
- let insertBefore = item.getAttribute('multipletab-insertbefore');
- if (refNode === void(0) && insertBefore) {
- try {
- eval('refNode = '+insertBefore);
- }
- catch(e) {
- }
- }
- aPopup.insertBefore(item, refNode || null);
- }
- tabContextMenu = null;
- }, 0, this, b, tabContextMenu);
- }
-
- let closeTabsToEnd = d.getElementById(this.kMENUITEM_CLOSE_TABS_TO_END);
- if (closeTabsToEnd) {
- this._closeTabsToEnd_horizontalLabel = closeTabsToEnd.getAttribute('label');
- this._closeTabsToEnd_horizontalAccesskey = closeTabsToEnd.getAttribute('accesskey');
- }
-
- var removeTabItem = d.getAnonymousElementByAttribute(b, 'id', 'context_closeTab');
- if (removeTabItem) {
- removeTabItem.setAttribute(
- 'oncommand',
- removeTabItem.getAttribute('oncommand').replace(
- /(tabbrowser\.removeTab\(([^\)]+)\))/,
- 'if (tabbrowser.treeStyleTab.warnAboutClosingTabSubtreeOf($2)) $1'
- )
- );
- }
- },
-
- _initTooltipManager : function TSTBrowser_initTooltipManager()
- {
- if (this.tooltipManager)
- return;
-
- this.tooltipManager = new FullTooltipManager(this);
- },
-
- _readyToInitDNDObservers : function TSTBrowser_readyToInitDNDObservers()
- {
- var w = this.window;
- this._DNDObserversInitialized = false;
- w.addEventListener('mouseover', this, true);
- w.addEventListener('dragover', this, true);
- },
-
- _initDNDObservers : function TSTBrowser_initDNDObservers()
- {
- if (this._DNDObserversInitialized)
- return;
-
- this.tabbarDNDObserver;
- this.panelDNDObserver;
-
- var w = this.window;
- w.removeEventListener('mouseover', this, true);
- w.removeEventListener('dragover', this, true);
- this._DNDObserversInitialized = true;
- },
-
- initTab : function TSTBrowser_initTab(aTab)
- {
- if (!aTab.parentNode) // do nothing for closed tab!
- return;
-
- if (!aTab.hasAttribute(this.kID)) {
- let id = this.getTabValue(aTab, this.kID) || this.makeNewId();
- aTab.setAttribute(this.kID, id);
- aTab.setAttribute(this.kID_NEW, id);
- aTab.setAttribute(this.kSUBTREE_COLLAPSED, true);
- aTab.setAttribute(this.kALLOW_COLLAPSE, true);
- let self = this;
- let key = 'initTab_'+id;
- if (this.deferredTasks[key])
- this.deferredTasks[key].cancel();
- (this.deferredTasks[key] = this.Deferred.next(function() {
- // changed by someone!
- if (aTab.getAttribute(self.kID) != id)
- return;
-
- aTab.removeAttribute(this.kID_NEW);
- if (!self.getTabValue(aTab, self.kID)) {
- self.setTabValue(aTab, self.kID, id);
- if (!(id in self.tabsHash))
- self.tabsHash[id] = aTab;
- }
- })).error(this.defaultDeferredErrorHandler).next(function() {
- delete self.deferredTasks[key];
- });
- if (!(id in this.tabsHash))
- this.tabsHash[id] = aTab;
- }
- else {
- // if the tab is restored from session, it can be not-cached.
- let id = aTab.getAttribute(this.kID);
- if (!(id in this.tabsHash))
- this.tabsHash[id] = aTab;
- }
-
- aTab.__treestyletab__linkedTabBrowser = this.mTabBrowser;
-
- if (!aTab.linkedBrowser.__treestyletab__toBeRestored)
- aTab.linkedBrowser.__treestyletab__toBeRestored = utils.isTabNotRestoredYet(aTab);
-
- this.initTabAttributes(aTab);
- this.initTabContents(aTab);
-
- if (!aTab.hasAttribute(this.kNEST))
- aTab.setAttribute(this.kNEST, 0);
- },
-
- isTabInitialized : function TSTBrowser_isTabInitialized(aTab)
- {
- return aTab.getAttribute(this.kID);
- },
-
- ensureTabInitialized : function TSTBrowser_ensureTabInitialized(aTab)
- {
- if (!aTab || this.isTabInitialized(aTab))
- return;
- this.initTab(aTab);
- },
-
- initTabAttributes : function TSTBrowser_initTabAttributes(aTab)
- {
- if (!aTab.parentNode) // do nothing for closed tab!
- return;
-
- var pos = this.position;
- if (pos == 'left' || pos == 'right') {
- aTab.setAttribute('align', 'stretch');
- aTab.removeAttribute('maxwidth');
- aTab.removeAttribute('minwidth');
- aTab.removeAttribute('width');
- aTab.removeAttribute('flex');
- aTab.maxWidth = 65000;
- aTab.minWidth = 0;
- if (utils.getTreePref('compatibility.TMP'))
- aTab.setAttribute('dir', 'ltr'); // Tab Mix Plus
- }
- else {
- aTab.removeAttribute('align');
- aTab.removeAttribute('maxwidth');
- aTab.removeAttribute('minwidth');
- if (utils.getTreePref('compatibility.TMP'))
- aTab.removeAttribute('dir'); // Tab Mix Plus
- }
- },
-
- initTabContents : function TSTBrowser_initTabContents(aTab)
- {
- if (!aTab.parentNode) // do nothing for closed tab!
- return;
-
- var d = this.document;
-
- var twisty = this.getTabTwisty(aTab);
- var anchor = this.getTabTwistyAnchorNode(aTab);
- if (anchor && !twisty) {
- twisty = d.createElement('image');
- twisty.setAttribute('class', this.kTWISTY);
- anchor.parentNode.appendChild(twisty);
- }
-
- var label = this.getTabLabel(aTab);
- var counter = d.getAnonymousElementByAttribute(aTab, 'class', this.kCOUNTER_CONTAINER);
- if (label && !counter) {
- counter = d.createElement('hbox');
- counter.setAttribute('class', this.kCOUNTER_CONTAINER);
-
- let startParen = counter.appendChild(d.createElement('label'));
- startParen.setAttribute('class', this.kCOUNTER_PAREN);
- startParen.setAttribute('value', '(');
-
- let counterLabel = counter.appendChild(d.createElement('label'));
- counterLabel.setAttribute('class', this.kCOUNTER);
- counterLabel.setAttribute('value', '0');
-
- let endParen = counter.appendChild(d.createElement('label'));
- endParen.setAttribute('class', this.kCOUNTER_PAREN);
- endParen.setAttribute('value', ')');
-
- /** XXX
- * Insertion before an anonymous element breaks its "xbl:inherits".
- * For example, "xbl:inherits" of the closebox in a tab (Tab Mix Plus
- * defines it) doesn't work. So, I don't use insertBefore().
- * Instead, the counter will be rearranged by "ordinal" attribute
- * given by initTabContentsOrder().
- */
- // label.parentNode.insertBefore(counter, label.nextSibling);
- label.parentNode.appendChild(counter);
- }
-
- this.initTabContentsOrder(aTab, true);
- },
-
- initTabContentsOrder : function TSTBrowser_initTabContentsOrder(aTab, aForce)
- {
- if (!aTab.parentNode) // do nothing for closed tab!
- return;
-
- var d = this.document;
-
- var namedNodes = {
- label : this.getTabLabel(aTab),
- close : this.getTabClosebox(aTab),
- twistyAnchor : this.getTabTwistyAnchorNode(aTab),
- twisty : this.getTabTwisty(aTab),
- counter : d.getAnonymousElementByAttribute(aTab, 'class', this.kCOUNTER_CONTAINER)
- };
-
- namedNodes.closeAnchor = namedNodes.label;
- if (namedNodes.closeAnchor.parentNode != namedNodes.close.parentNode) {
- let containerFinder = d.createRange();
- containerFinder.selectNode(namedNodes.closeAnchor);
- containerFinder.setEndAfter(namedNodes.close);
- let container = containerFinder.commonAncestorContainer;
- while (namedNodes.closeAnchor.parentNode != container)
- {
- namedNodes.closeAnchor = namedNodes.closeAnchor.parentNode;
- }
- while (namedNodes.close.parentNode != container)
- {
- namedNodes.close = namedNodes.close.parentNode;
- }
- }
-
- namedNodes.counterAnchor = namedNodes.label;
-
- var foundContainers = [];
- var containers = [
- namedNodes.twistyAnchor.parentNode,
- namedNodes.label.parentNode,
- namedNodes.counter.parentNode,
- namedNodes.closeAnchor.parentNode
- ];
- for (let i = 0, maxi = containers.length; i < maxi; i++)
- {
- let container = containers[i];
- if (foundContainers.indexOf(container) > -1)
- continue;
- this.initTabContentsOrderInternal(container, namedNodes, aForce);
- foundContainers.push(container);
- }
- },
- initTabContentsOrderInternal : function TSTBrowser_initTabContentsOrderInternal(aContainer, aNamedNodes, aForce)
- {
- if (this.window.getComputedStyle(aContainer, '').getPropertyValue('-moz-box-orient') == 'vertical')
- return;
-
- var nodes = Array.slice(this.document.getAnonymousNodes(aContainer) || aContainer.childNodes);
-
- // reset order at first!
- for (let i = 0, maxi = nodes.length; i < maxi; i++)
- {
- let node = nodes[i];
- if (node.getAttribute('class') == 'informationaltab-thumbnail-container')
- continue;
- node.setAttribute('ordinal', i);
- }
-
- // after that, rearrange contents
-
- var index = nodes.indexOf(aNamedNodes.close);
- if (index > -1) {
- nodes.splice(index, 1);
- if (this.mTabBrowser.getAttribute(this.kCLOSEBOX_INVERTED) == 'true')
- nodes.splice(nodes.indexOf(aNamedNodes.closeAnchor), 0, aNamedNodes.close);
- else
- nodes.splice(nodes.indexOf(aNamedNodes.closeAnchor)+1, 0, aNamedNodes.close);
- }
-
- index = nodes.indexOf(aNamedNodes.twisty);
- if (index > -1) {
- nodes.splice(index, 1);
- nodes.splice(nodes.indexOf(aNamedNodes.twistyAnchor), 0, aNamedNodes.twisty);
- }
-
- if (this.mTabBrowser.getAttribute(this.kTAB_CONTENTS_INVERTED) == 'true')
- nodes.reverse();
-
- // counter must rightside of the label!
- index = nodes.indexOf(aNamedNodes.counter);
- if (index > -1) {
- nodes.splice(index, 1);
- nodes.splice(nodes.indexOf(aNamedNodes.counterAnchor)+1, 0, aNamedNodes.counter);
- }
-
- var count = nodes.length;
- nodes.reverse();
- for (let i = 0, maxi = nodes.length; i < maxi; i++)
- {
- let node = nodes[i];
- if (node.getAttribute('class') == 'informationaltab-thumbnail-container')
- continue;
- node.setAttribute('ordinal', (count - i + 1) * 100);
- }
-
- if (aForce) {
- /**
- * After the order of contents are changed dynamically,
- * Gecko doesn't re-render them in the new order.
- * Changing of "display" or "position" can fix this problem.
- */
- let shouldHideTemporaryState = (
- 'TabmixTabbar' in this.window || // Tab Mix Plus
- 'InformationalTabService' in this.window // Informational Tab
- );
- for (let i = 0, maxi = nodes.length; i < maxi; i++)
- {
- let node = nodes[i];
- if (shouldHideTemporaryState)
- node.style.visibility = 'hidden';
- node.style.position = 'fixed';
- }
- let key = 'initTabContentsOrderInternal_'+parseInt(Math.random() * 65000);
- (this.deferredTasks[key] = this.Deferred.wait(0.1).next(function() {
- for (let i = 0, maxi = nodes.length; i < maxi; i++)
- {
- let node = nodes[i];
- node.style.position = '';
- if (shouldHideTemporaryState)
- node.style.visibility = '';
- }
- })).error(this.defaultDeferredErrorHandler).next(function() {
- delete self.deferredTasks[key];
- });
- }
- },
-
- updateInvertedTabContentsOrder : function TSTBrowser_updateInvertedTabContentsOrder(aTarget)
- {
- var self = this;
- let key = 'updateInvertedTabContentsOrder_'+parseInt(Math.random() * 65000);
- (this.deferredTasks[key] = this.Deferred.next(function() {
- var b = self.mTabBrowser;
- var tabs = !aTarget ?
- [b.selectedTab] :
- (aTarget instanceof Ci.nsIDOMElement) ?
- [aTarget] :
- (typeof aTarget == 'object' && 'length' in aTarget) ?
- Array.slice(aTarget) :
- self.getAllTabs(b);
- for (let i = 0, maxi = tabs.length; i < maxi; i++)
- {
- self.initTabContentsOrder(tabs[i]);
- }
- })).error(this.defaultDeferredErrorHandler).next(function() {
- delete self.deferredTasks[key];
- });
- },
-
- initTabbar : function TSTBrowser_initTabbar(aNewPosition, aOldPosition)
- {
- var d = this.document;
- var b = this.mTabBrowser;
-
- if (aNewPosition && typeof aNewPosition == 'string')
- aNewPosition = this.getPositionFlag(aNewPosition);
- if (aOldPosition && typeof aOldPosition == 'string')
- aOldPosition = this.getPositionFlag(aOldPosition);
-
- this._startListenTabbarEvents();
- this.window.TreeStyleTabWindowHelper.initTabbarMethods(b);
-
- this.stopRendering();
-
- var pos = aNewPosition || this.getPositionFlag(this.position);
- if (b.getAttribute('id') != 'content' &&
- !utils.getTreePref('tabbar.position.subbrowser.enabled')) {
- pos = this.kTABBAR_TOP;
- }
-
- aOldPosition = aOldPosition || pos;
-
- // We have to use CSS property hack instead, because the stopRendering()
- // doesn't effect on the first time of startup.
- // * This hack works in a "stop"-"start" pair, so, people never see the side effect.
- // * This hack works only when "ordinal" properties are modified.
- // So, this is just for the case: "right" or "bottom" tab bar on the startup.
- if (
- pos != aOldPosition &&
- (
- ((pos & this.kTABBAR_REGULAR) && (aOldPosition & this.kTABBAR_INVERTED)) ||
- ((pos & this.kTABBAR_INVERTED) && (aOldPosition & this.kTABBAR_REGULAR))
- )
- )
- b.style.visibility = 'hidden';
-
- var strip = this.tabStrip;
- var placeHolder = this.tabStripPlaceHolder || strip;
- var splitter = this._ensureNewSplitter();
- var toggler = d.getAnonymousElementByAttribute(b, 'class', this.kTABBAR_TOGGLER);
-
- // Tab Mix Plus
- var scrollFrame, newTabBox, tabBarMode;
- if (utils.getTreePref('compatibility.TMP')) {
- scrollFrame = d.getAnonymousElementByAttribute(b.mTabContainer, 'class', 'tabs-frame') ||
- d.getAnonymousElementByAttribute(b.mTabContainer, 'anonid', 'scroll-tabs-frame');
- newTabBox = d.getAnonymousElementByAttribute(b.mTabContainer, 'id', 'tabs-newbutton-box');
- let newTabButton = d.getElementById('new-tab-button');
- if (newTabButton && newTabButton.parentNode == b.tabContainer._container)
- newTabBox = newTabButton;
- tabBarMode = prefs.getPref('extensions.tabmix.tabBarMode');
- }
-
- // All-in-One Sidebar
- var toolboxContainer = d.getAnonymousElementByAttribute(strip, 'anonid', 'aiostbx-toolbox-tableft');
- if (toolboxContainer)
- toolboxContainer = toolboxContainer.parentNode;
-
- var scrollInnerBox = b.mTabContainer.mTabstrip._scrollbox ?
- d.getAnonymousNodes(b.mTabContainer.mTabstrip._scrollbox)[0] :
- scrollFrame; // Tab Mix Plus
-
- this.removeTabbrowserAttribute(this.kRESIZING, b);
-
- this.removeTabStripAttribute('width');
- b.mPanelContainer.removeAttribute('width');
-
- var delayedPostProcess;
-
- if (pos & this.kTABBAR_VERTICAL) {
- this.collapseTarget = 'top';
- this.screenPositionProp = 'screenY';
- this.offsetProp = 'offsetY';
- this.translateFunction = 'translateY';
- this.sizeProp = 'height';
- this.invertedScreenPositionProp = 'screenX';
- this.invertedSizeProp = 'width';
- this.startProp = 'top';
- this.endProp = 'bottom';
-
- b.mTabBox.orient = splitter.orient = 'horizontal';
- strip.orient =
- placeHolder.orient =
- toggler.orient =
- b.mTabContainer.orient =
- b.mTabContainer.mTabstrip.orient =
- b.mTabContainer.mTabstrip.parentNode.orient = 'vertical';
- b.mTabContainer.setAttribute('align', 'stretch'); // for Mac OS X
- if (scrollInnerBox)
- scrollInnerBox.removeAttribute('flex');
-
- if (utils.getTreePref('compatibility.TMP') && scrollFrame) { // Tab Mix Plus
- d.getAnonymousNodes(scrollFrame)[0].removeAttribute('flex');
- scrollFrame.parentNode.orient =
- scrollFrame.orient = 'vertical';
- if (newTabBox)
- newTabBox.orient = 'horizontal';
- if (tabBarMode == 2)
- prefs.setPref('extensions.tabmix.tabBarMode', 1);
- }
-
- if (toolboxContainer)
- toolboxContainer.orient = 'vertical';
-
- this.setTabbrowserAttribute(this.kMODE, 'vertical');
-
- let width = this.maxTabbarWidth(utils.getTreePref('tabbar.width'), b);
- this.setTabStripAttribute('width', width);
- this.removeTabStripAttribute('height');
- b.mPanelContainer.removeAttribute('height');
-
- if (strip.localName == 'toolbar') {
- let nodes = strip.childNodes;
- for (let i = 0, maxi = nodes.length; i < maxi; i++)
- {
- let node = nodes[i];
- if (node.localName == 'tabs')
- continue;
- if (node.hasAttribute('flex'))
- node.setAttribute('treestyletab-backup-flex', node.getAttribute('flex'));
- node.removeAttribute('flex');
- }
- }
-
- if (pos == this.kTABBAR_RIGHT) {
- this.setTabbrowserAttribute(this.kTABBAR_POSITION, 'right');
- if (utils.getTreePref('tabbar.invertTab')) {
- this.setTabbrowserAttribute(this.kTAB_INVERTED, 'true');
- this.indentTarget = 'right';
- }
- else {
- this.removeTabbrowserAttribute(this.kTAB_INVERTED);
- this.indentTarget = 'left';
- }
- delayedPostProcess = function(aSelf, aTabBrowser, aSplitter, aToggler) {
- /* in Firefox 3, the width of the rightside tab bar
- unexpectedly becomes 0 on the startup. so, we have
- to set the width again. */
- aSelf.setTabStripAttribute('width', width);
- aSelf.setTabStripAttribute('ordinal', 30);
- aSplitter.setAttribute('ordinal', 20);
- aToggler.setAttribute('ordinal', 40);
- aTabBrowser.mPanelContainer.setAttribute('ordinal', 10);
- aSplitter.setAttribute('collapse', 'after');
- };
- }
- else {
- this.setTabbrowserAttribute(this.kTABBAR_POSITION, 'left');
- this.removeTabbrowserAttribute(this.kTAB_INVERTED);
- this.indentTarget = 'left';
- delayedPostProcess = function(aSelf, aTabBrowser, aSplitter, aToggler) {
- aSelf.setTabStripAttribute('ordinal', 10);
- aSplitter.setAttribute('ordinal', 20);
- aToggler.setAttribute('ordinal', 5);
- aTabBrowser.mPanelContainer.setAttribute('ordinal', 30);
- aSplitter.setAttribute('collapse', 'before');
- };
- }
- }
- else {
- this.collapseTarget = 'left';
- this.screenPositionProp = 'screenX';
- this.offsetProp = 'offsetX';
- this.translateFunction = 'translateX';
- this.sizeProp = 'width';
- this.invertedScreenPositionProp = 'screenY';
- this.invertedSizeProp = 'height';
- this.startProp = 'left';
- this.endProp = 'right';
-
- b.mTabBox.orient = splitter.orient = 'vertical';
- strip.orient =
- placeHolder.orient =
- toggler.orient =
- b.mTabContainer.orient =
- b.mTabContainer.mTabstrip.orient =
- b.mTabContainer.mTabstrip.parentNode.orient = 'horizontal';
- b.mTabContainer.removeAttribute('align'); // for Mac OS X
- if (scrollInnerBox)
- scrollInnerBox.setAttribute('flex', 1);
-
- if (utils.getTreePref('compatibility.TMP') && scrollFrame) { // Tab Mix Plus
- d.getAnonymousNodes(scrollFrame)[0].setAttribute('flex', 1);
- scrollFrame.parentNode.orient =
- scrollFrame.orient = 'horizontal';
- if (newTabBox)
- newTabBox.orient = 'vertical';
- }
-
- if (toolboxContainer)
- toolboxContainer.orient = 'horizontal';
-
- this.setTabbrowserAttribute(this.kMODE, utils.getTreePref('tabbar.multirow') ? 'multirow' : 'horizontal');
- this.removeTabbrowserAttribute(this.kTAB_INVERTED);
-
- if (strip.localName == 'toolbar') {
- let nodes = strip.childNodes;
- for (let i = 0, maxi = nodes.length; i < maxi; i++)
- {
- let node = nodes[i];
- if (node.localName == 'tabs')
- continue;
- let flex = node.hasAttribute('treestyletab-backup-flex');
- if (!flex)
- continue;
- node.setAttribute('flex', flex);
- node.removeAttribute('treestyletab-backup-flex');
- }
- }
-
- if (pos == this.kTABBAR_BOTTOM) {
- this.setTabbrowserAttribute(this.kTABBAR_POSITION, 'bottom');
- this.indentTarget = 'bottom';
- delayedPostProcess = function(aSelf, aTabBrowser, aSplitter, aToggler) {
- aSelf.setTabStripAttribute('ordinal', 30);
- aSplitter.setAttribute('ordinal', 20);
- aToggler.setAttribute('ordinal', 40);
- aTabBrowser.mPanelContainer.setAttribute('ordinal', 10);
- };
- }
- else {
- this.setTabbrowserAttribute(this.kTABBAR_POSITION, 'top');
- this.indentTarget = 'top';
- delayedPostProcess = function(aSelf, aTabBrowser, aSplitter, aToggler) {
- aSelf.setTabStripAttribute('ordinal', 10);
- aSplitter.setAttribute('ordinal', 20);
- aToggler.setAttribute('ordinal', 5);
- aTabBrowser.mPanelContainer.setAttribute('ordinal', 30);
- };
- }
- }
-
- var tabs = this.getAllTabs(b);
- for (let i = 0, maxi = tabs.length; i < maxi; i++)
- {
- let tab = tabs[i];
- tab.style.removeProperty(this.indentCSSProp);
- tab.style.removeProperty(this.collapseCSSProp);
- }
-
- this.indentProp = utils.getTreePref('indent.property');
- this.indentCSSProp = this.indentProp+'-'+this.indentTarget;
- this.collapseCSSProp = 'margin-'+this.collapseTarget;
-
- for (let i = 0, maxi = tabs.length; i < maxi; i++)
- {
- let tab = tabs[i];
- this.updateTabCollapsed(tab, tab.getAttribute(this.kCOLLAPSED) == 'true', true);
- }
-
- // for updateTabbarOverflow(), we should reset the "overflow" now.
- b.mTabContainer.removeAttribute('overflow');
- let (container = this.document.getAnonymousElementByAttribute(b.mTabContainer, 'class', 'tabs-container')) {
- if (container)
- container.removeAttribute('overflow');
- }
-
- this.updateTabbarState(false);
-
- if (this.deferredTasks['initTabbar'])
- this.deferredTasks['initTabbar'].cancel();
-
- var self = this;
- (this.deferredTasks['initTabbar'] = this.Deferred.next(function() {
- delayedPostProcess(self, b, splitter, toggler);
- self.updateTabbarOverflow();
- self.updateAllTabsButton(b);
- self.updateAllTabsCount();
- delayedPostProcess = null;
- self.mTabBrowser.style.visibility = '';
-
- var event = d.createEvent('Events');
- event.initEvent(self.kEVENT_TYPE_TABBAR_INITIALIZED, true, false);
- self.mTabBrowser.dispatchEvent(event);
-
- self.startRendering();
- })).error(this.defaultDeferredErrorHandler).next(function() {
- delete self.deferredTasks['initTabbar'];
- });
-
- pos = null;
- scrollFrame = null;
- newTabBox = null
- tabBarMode = null;
- toolboxContainer = null;
- scrollInnerBox = null;
- scrollInnerBox = null;
- },
-
- _startListenTabbarEvents : function TSTBrowser_startListenTabbarEvents()
- {
- var b = this.mTabBrowser;
-
- var tabContainer = b.mTabContainer;
- tabContainer.addEventListener('TabOpen', this, true);
- tabContainer.addEventListener('TabClose', this, true);
- tabContainer.addEventListener('TabMove', this, true);
- tabContainer.addEventListener('TabShow', this, true);
- tabContainer.addEventListener('TabHide', this, true);
- tabContainer.addEventListener('SSTabRestoring', this, true);
- tabContainer.addEventListener('SSTabRestored', this, true);
- tabContainer.addEventListener('TabPinned', this, true);
- tabContainer.addEventListener('TabUnpinned', this, true);
- tabContainer.addEventListener('mouseover', this, true);
- tabContainer.addEventListener('mouseout', this, true);
- tabContainer.addEventListener('dblclick', this, true);
- tabContainer.addEventListener('select', this, true);
- tabContainer.addEventListener('scroll', this, true);
-
- var strip = this.tabStrip;
- strip.addEventListener('MozMouseHittest', this, true); // to block default behaviors of the tab bar
- strip.addEventListener('mousedown', this, true);
- strip.addEventListener('click', this, true);
- strip.addEventListener('DOMMouseScroll', this, true);
-
- this.scrollBox.addEventListener('overflow', this, true);
- this.scrollBox.addEventListener('underflow', this, true);
- },
-
- _ensureNewSplitter : function TSTBrowser__ensureNewSplitter()
- {
- var d = this.document;
- var splitter = this.splitter;
-
- // We always have to re-create splitter, because its "collapse"
- // behavior becomes broken by repositioning of the tab bar.
- if (splitter) {
- try {
- splitter.removeEventListener('mousedown', this.windowService, false);
- splitter.removeEventListener('mouseup', this.windowService, false);
- splitter.removeEventListener('dblclick', this.windowService, false);
- }
- catch(e) {
- }
- let oldSplitter = splitter;
- splitter = oldSplitter.cloneNode(true);
- oldSplitter.parentNode.removeChild(oldSplitter);
- }
- else {
- splitter = d.createElement('splitter');
- splitter.setAttribute(this.kTAB_STRIP_ELEMENT, true);
- splitter.setAttribute('state', 'open');
- splitter.setAttribute('layer', true); // https://bugzilla.mozilla.org/show_bug.cgi?id=590468
- let grippy = d.createElement('grippy')
- grippy.setAttribute(this.kTAB_STRIP_ELEMENT, true);
- // Workaround for https://github.com/piroor/treestyletab/issues/593
- // When you click the grippy...
- // 1. The grippy changes "state" of the splitter from "collapsed"
- // to "open".
- // 2. The splitter changes visibility of the place holder.
- // 3. BrowserUIShowHideObserver detects the change of place
- // holder's visibility and triggers updateFloatingTabbar().
- // 4. updateFloatingTabbar() copies the visibility of the
- // actual tab bar to the place holder. However, the tab bar
- // is still collapsed.
- // 5. As the result, the place holder becomes collapsed and
- // the splitter disappear.
- // So, we have to turn the actual tab bar visible manually
- // when the grippy is clicked.
- let tabContainer = this.mTabBrowser.tabContainer;
- grippy.addEventListener('click', function() {
- tabContainer.ownerDocument.defaultView.setTimeout(function() {
- var visible = grippy.getAttribute('state') != 'collapsed';
- if (visible != tabContainer.visible)
- tabContainer.visible = visible;
- }, 0);
- }, false);
- splitter.appendChild(grippy);
- }
-
- var splitterClass = splitter.getAttribute('class') || '';
- if (splitterClass.indexOf(this.kSPLITTER) < 0)
- splitterClass += (splitterClass ? ' ' : '' ) + this.kSPLITTER;
- splitter.setAttribute('class', splitterClass);
-
- splitter.addEventListener('mousedown', this.windowService, false);
- splitter.addEventListener('mouseup', this.windowService, false);
- splitter.addEventListener('dblclick', this.windowService, false);
-
- var ref = this.mTabBrowser.mPanelContainer;
- ref.parentNode.insertBefore(splitter, ref);
-
- return splitter;
- },
-
- fireTabbarPositionEvent : function TSTBrowser_fireTabbarPositionEvent(aChanging, aOldPosition, aNewPosition)
- {
- if (aOldPosition == aNewPosition)
- return false;
-
- var type = aChanging ? this.kEVENT_TYPE_TABBAR_POSITION_CHANGING : this.kEVENT_TYPE_TABBAR_POSITION_CHANGED;
- var data = {
- oldPosition : aOldPosition,
- newPosition : aNewPosition
- };
-
- /* PUBLIC API */
- this.fireCustomEvent(type, this.mTabBrowser, true, false, data);
- // for backward compatibility
- this.fireCustomEvent(type.replace(/^nsDOM/, ''), this.mTabBrowser, true, false, data);
-
- return true;
- },
-
- updateTabbarState : function TSTBrowser_updateTabbarState(aCancelable)
- {
- if (!this._fireTabbarStateChangingEvent() && aCancelable)
- return;
-
- this.stopRendering();
-
- var self = this;
-
- var w = this.window;
- var d = this.document;
- var b = this.mTabBrowser;
- var orient;
- var toggleTabsOnTop = d.getElementById('cmd_ToggleTabsOnTop');
- var TabsOnTop = 'TabsOnTop' in w ? w.TabsOnTop : null ;
- if (this.isVertical) {
- orient = 'vertical';
- this.fixed = this.fixed; // ensure set to the current orient
- if (toggleTabsOnTop)
- toggleTabsOnTop.setAttribute('disabled', true);
- }
- else {
- orient = 'horizontal';
- if (this.fixed) {
- this.fixed = true; // ensure set to the current orient
- if (!this.isMultiRow()) {
- this.removeTabStripAttribute('height');
- b.mPanelContainer.removeAttribute('height');
- }
- // remove ordinal for "tabs on top" https://bugzilla.mozilla.org/show_bug.cgi?id=544815
- if (this.position == 'top') {
- this.removeTabStripAttribute('ordinal');
- if (TabsOnTop && !this.windowService.isPopupWindow &&
- this.windowService.initialized) {
- let currentState = TabsOnTop.enabled;
- let originalState = utils.getTreePref('tabsOnTop.originalState');
- if (originalState !== null &&
- currentState != originalState &&
- this.windowService.tabsOnTopChangingByUI &&
- !this.windowService.changingTabsOnTop)
- utils.setTreePref('tabsOnTop.originalState', currentState);
- // Workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=555987
- // This should be done when the value of the "ordinal" attribute
- // is modified dynamically. So, we don' have to do it before
- // the browser window is completely initialized.
- TabsOnTop.enabled = !currentState;
- if (this.deferredTasks['updateTabbarState_TabsOnTop'])
- this.deferredTasks['updateTabbarState_TabsOnTop'].cancel();
- (this.deferredTasks['updateTabbarState_TabsOnTop'] = this.Deferred.next(function() {
- TabsOnTop.enabled = currentState;
- })).error(this.defaultDeferredErrorHandler).next(function() {
- delete self.deferredTasks['updateTabbarState_TabsOnTop'];
- });
- }
- }
- }
- else {
- this.fixed = false; // ensure set to the current orient
- this.setTabStripAttribute('height', this.maxTabbarHeight(utils.getTreePref('tabbar.height'), b));
- }
- if (toggleTabsOnTop) {
- if (this.position == 'top')
- toggleTabsOnTop.removeAttribute('disabled');
- else
- toggleTabsOnTop.setAttribute('disabled', true);
- }
- }
-
- if (TabsOnTop && !this.windowService.isPopupWindow) {
- let updateTabsOnTop = function() {
- self.windowService.updateTabsOnTop();
- };
- // TabsOnTop.enabled is always "false" before the browser window is
- // completely initialized. So, we have to check it with delay only
- // on the Startup.
- if (this.initialized)
- updateTabsOnTop();
- else
- this.Deferred.next(updateTabsOnTop);
- }
-
- if (this.deferredTasks['updateTabbarState'])
- this.deferredTasks['updateTabbarState'].cancel();
- (this.deferredTasks['updateTabbarState'] = this.Deferred.next(function() {
- self.updateFloatingTabbar(self.kTABBAR_UPDATE_BY_APPEARANCE_CHANGE);
- self._fireTabbarStateChangedEvent();
- self.startRendering();
- })).error(this.defaultDeferredErrorHandler).next(function() {
- delete self.deferredTasks['updateTabbarState'];
- });
-
- var allowToCollapse = utils.getTreePref('allowSubtreeCollapseExpand.'+orient);
- if (this.allowSubtreeCollapseExpand != allowToCollapse)
- this.collapseExpandAllSubtree(false, false);
- this.allowSubtreeCollapseExpand = allowToCollapse;
-
- this.maxTreeLevel = utils.getTreePref('maxTreeLevel.'+orient);
-
- this.setTabbrowserAttribute(this.kALLOW_STACK, this.canStackTabs ? 'true' : null);
- this.updateTabsZIndex(this.canStackTabs);
-
- if (this.maxTreeLevelPhisical)
- this.promoteTooDeepLevelTabs();
-
- this.updateAllTabsIndent();
- },
-
- _fireTabbarStateChangingEvent : function TSTBrowser_fireTabbarStateChangingEvent()
- {
- var b = this.mTabBrowser;
- var orient = this.isVertical ? 'vertical' : 'horizontal' ;
- var oldState = {
- fixed : this.fixed,
- maxTreeLevel : this.maxTreeLevel,
- indented : this.maxTreeLevel != 0,
- canCollapse : b.getAttribute(this.kALLOW_COLLAPSE) == 'true'
- };
- var newState = {
- fixed : utils.getTreePref('tabbar.fixed.'+orient),
- maxTreeLevel : utils.getTreePref('maxTreeLevel.'+orient),
- indented : utils.getTreePref('maxTreeLevel.'+orient) != 0,
- canCollapse : utils.getTreePref('allowSubtreeCollapseExpand.'+orient)
- };
-
- if (oldState.fixed == newState.fixed &&
- oldState.maxTreeLevel == newState.maxTreeLevel &&
- oldState.indented == newState.indented &&
- oldState.canCollapse == newState.canCollapse)
- return false;
-
- var data = {
- oldState : oldState,
- newState : newState
- };
-
- /* PUBLIC API */
- this.fireCustomEvent(this.kEVENT_TYPE_TABBAR_STATE_CHANGING, this.mTabBrowser, true, false, data);
- // for backward compatibility
- this.fireCustomEvent(this.kEVENT_TYPE_TABBAR_STATE_CHANGING.replace(/^nsDOM/, ''), this.mTabBrowser, true, false, data);
-
- return true;
- },
-
- _fireTabbarStateChangedEvent : function TSTBrowser_fireTabbarStateChangedEvent()
- {
- var b = this.mTabBrowser;
- var state = {
- fixed : this.fixed,
- maxTreeLevel : this.maxTreeLevel,
- indented : this.maxTreeLevel != 0,
- canCollapse : b.getAttribute(this.kALLOW_COLLAPSE) == 'true'
- };
-
- var data = {
- state : state
- };
-
- /* PUBLIC API */
- this.fireCustomEvent(this.kEVENT_TYPE_TABBAR_STATE_CHANGED, this.mTabBrowser, true, false, data);
- // for backward compatibility
- this.fireCustomEvent(this.kEVENT_TYPE_TABBAR_STATE_CHANGED.replace(/^nsDOM/, ''), this.mTabBrowser, true, false, data);
-
- return true;
- },
-
- updateFloatingTabbar : function TSTBrowser_updateFloatingTabbar(aReason)
- {
- var w = this.window;
- if (this._updateFloatingTabbarTimer) {
- w.clearTimeout(this._updateFloatingTabbarTimer);
- this._updateFloatingTabbarTimer = null;
- }
-
- this._updateFloatingTabbarReason |= aReason;
-
- if (this._updateFloatingTabbarReason & this.kTABBAR_UPDATE_NOW) {
- this._updateFloatingTabbarInternal(this._updateFloatingTabbarReason);
- this._updateFloatingTabbarReason = 0;
- }
- else {
- this._updateFloatingTabbarTimer = w.setTimeout(function(aSelf) {
- aSelf._updateFloatingTabbarTimer = null;
- aSelf._updateFloatingTabbarInternal(aSelf._updateFloatingTabbarReason)
- aSelf._updateFloatingTabbarReason = 0;
- }, 0, this);
- }
- },
-
- _updateFloatingTabbarInternal : function TSTBrowser_updateFloatingTabbarInternal(aReason)
- {
- aReason = aReason || this.kTABBAR_UPDATE_BY_UNKNOWN_REASON;
-
- if (DEBUG) {
- let humanReadableReason =
- (aReason & this.kTABBAR_UPDATE_BY_RESET ? 'reset ' : '' ) +
- (aReason & this.kTABBAR_UPDATE_BY_PREF_CHANGE ? 'prefchange ' : '' ) +
- (aReason & this.kTABBAR_UPDATE_BY_APPEARANCE_CHANGE ? 'appearance-change ' : '' ) +
- (aReason & this.kTABBAR_UPDATE_BY_SHOWHIDE_TABBAR ? 'showhide ' : '' ) +
- (aReason & this.kTABBAR_UPDATE_BY_TABBAR_RESIZE ? 'tabbar-resize ' : '' ) +
- (aReason & this.kTABBAR_UPDATE_BY_WINDOW_RESIZE ? 'window-resize ' : '' ) +
- (aReason & this.kTABBAR_UPDATE_BY_FULLSCREEN ? 'fullscreen ' : '' ) +
- (aReason & this.kTABBAR_UPDATE_BY_AUTOHIDE ? 'autohide ' : '' ) +
- (aReason & this.kTABBAR_UPDATE_BY_INITIALIZE ? 'initialize ' : '' ) +
- (aReason & this.kTABBAR_UPDATE_BY_TOGGLE_SIDEBAR ? 'toggle-sidebar ' : '' );
- dump('TSTBrowser_updateFloatingTabbarInternal: ' + humanReadableReason + '\n');
- }
-
- var d = this.document;
-
- // When the tab bar is invisible even if the tab bar is resizing, then
- // now I'm trying to expand the tab bar from collapsed state.
- // Then the tab bar must be shown.
- if (aReason & this.kTABBAR_UPDATE_BY_TABBAR_RESIZE &&
- !this.browser.tabContainer.visible)
- this.browser.tabContainer.visible = true;
-
- var splitter = this.splitter;
- if (splitter.collapsed || splitter.getAttribute('state') != 'collapsed') {
- // Synchronize visibility of the tab bar to the placeholder,
- // because the tab bar can be shown/hidden by someone
- // (Tab Mix Plus, Pale Moon, or some addons).
- this._tabStripPlaceHolder.collapsed =
- splitter.collapsed =
- !this.browser.tabContainer.visible;
- }
-
- var strip = this.tabStrip;
- var collapsed = splitter.collapsed ?
- strip.collapsed :
- splitter.getAttribute('state') == 'collapsed' ;
- var stripStyle = strip.style;
- var tabContainerBox = this.getTabContainerBox(this.mTabBrowser);
- var statusPanel = d.getElementById('statusbar-display');
- var statusPanelStyle = statusPanel ? statusPanel.style : null ;
- var pos = this.position;
- if (pos != 'top' ||
- this.mTabBrowser.getAttribute(this.kFIXED) != 'true') {
- strip.setAttribute('layer', true); // https://bugzilla.mozilla.org/show_bug.cgi?id=590468
-
- if (
- this.autoHide.enabled &&
- this.autoHide.expanded &&
- (aReason & this.kTABBAR_UPDATE_SYNC_TO_PLACEHOLDER) &&
- this.autoHide.mode == this.autoHide.kMODE_SHRINK
- )
- this.autoHide.hide(this.autoHide.kSHOWN_BY_ANY_REASON);
-
- let box = this._tabStripPlaceHolder.boxObject;
- let root = d.documentElement.boxObject;
- let realSize = this.getTabbarPlaceholderSize();
-
- let width = (this.autoHide.expanded && this.isVertical && (aReason & this.kTABBAR_UPDATE_SYNC_TO_TABBAR) ?
- this.maxTabbarWidth(utils.getTreePref('tabbar.width')) :
- 0
- ) || realSize.width;
- let height = (this.autoHide.expanded && !this.isVertical && (aReason & this.kTABBAR_UPDATE_SYNC_TO_TABBAR) ?
- this.maxTabbarHeight(utils.getTreePref('tabbar.height')) :
- 0
- ) || realSize.height;
- let yOffset = pos == 'bottom' ? height - realSize.height : 0 ;
-
- stripStyle.top = (box.screenY - root.screenY + root.y - yOffset)+'px';
- stripStyle.left = pos == 'right' ? '' :
- (box.screenX - root.screenX + root.x)+'px';
- stripStyle.right = pos != 'right' ? '' :
- ((root.screenX + root.width) - (box.screenX + box.width))+'px';
-
- stripStyle.width = (strip.width = tabContainerBox.width = width)+'px';
- stripStyle.height = (strip.height = tabContainerBox.height = height)+'px';
-
- this._updateFloatingTabbarResizer({
- width : width,
- realWidth : realSize.width,
- height : height,
- realHeight : realSize.height
- });
-
- this._lastTabbarPlaceholderSize = realSize;
-
- strip.collapsed = tabContainerBox.collapsed = collapsed;
-
- if (statusPanel && utils.getTreePref('repositionStatusPanel')) {
- let offsetParentBox = this.base.findOffsetParent(statusPanel).boxObject;
- let contentBox = this.mTabBrowser.mPanelContainer.boxObject;
- let chromeMargins = (d.documentElement.getAttribute('chromemargin') || '0,0,0,0').split(',');
- chromeMargins = chromeMargins.map(function(aMargin) { return parseInt(aMargin); });
- statusPanelStyle.marginTop = (pos == 'bottom') ?
- '-moz-calc(0px - ' + (offsetParentBox.height - contentBox.height + chromeMargins[2]) + 'px - 3em)' :
- '' ;
- statusPanelStyle.marginLeft = (contentBox.screenX - offsetParentBox.screenX + chromeMargins[3])+'px';
- statusPanelStyle.marginRight = ((offsetParentBox.screenX + offsetParentBox.width) - (contentBox.screenX + contentBox.width) + chromeMargins[1])+'px';
- statusPanelStyle.maxWidth = this.isVertical ?
- (contentBox.width-5)+'px' : // emulate the margin defined on https://bugzilla.mozilla.org/show_bug.cgi?id=632634
- '' ;
- statusPanel.__treestyletab__repositioned = true;
- }
-
- this.mTabBrowser.tabContainer.setAttribute('context', this.mTabBrowser.tabContextMenu.id);
- }
- else {
- strip.collapsed = tabContainerBox.collapsed = collapsed;
- stripStyle.top = stripStyle.left = stripStyle.right = stripStyle.width = stripStyle.height = '';
-
- if (
- statusPanel &&
- (
- utils.getTreePref('repositionStatusPanel') ||
- statusPanel.__treestyletab__repositioned
- )
- ) {
- statusPanelStyle.marginTop = statusPanelStyle.marginLeft =
- statusPanelStyle.marginRight = statusPanelStyle.maxWidth = '';
- statusPanel.__treestyletab__repositioned = false;
- }
-
- strip.removeAttribute('layer'); // https://bugzilla.mozilla.org/show_bug.cgi?id=590468
-
- this.mTabBrowser.tabContainer.removeAttribute('context');
- }
-
- if (tabContainerBox.boxObject.width)
- this.positionPinnedTabs(null, null, aReason & this.kTABBAR_UPDATE_BY_AUTOHIDE);
- else
- this.positionPinnedTabsWithDelay(null, null, aReason & this.kTABBAR_UPDATE_BY_AUTOHIDE);
-
- if (!collapsed && aReason & this.kTABBAR_UPDATE_BY_AUTOHIDE) {
- let self = this;
- this.Deferred.next(function() {
- self.scrollToTab(self.browser.selectedTab);
- });
- }
- },
- getTabbarPlaceholderSize: function TSTBrowser_getTabbarPlaceholderSize()
- {
- var box = this._tabStripPlaceHolder.boxObject;
- return {
- width: parseInt(this._tabStripPlaceHolder.getAttribute('width') || box.width),
- height: parseInt(this._tabStripPlaceHolder.getAttribute('height') || box.height)
- };
- },
- getExistingTabsCount : function TSTBrowser_getTabsCount()
- {
- return this.getAllTabs(this.mTabBrowser).length - this.mTabBrowser._removingTabs.length;
- },
-
- _updateFloatingTabbarResizer : function TSTBrowser_updateFloatingTabbarResizer(aSize)
- {
- var d = this.document;
-
- var width = aSize.width;
- var realWidth = this.autoHide.mode == this.autoHide.kMODE_HIDE ? 0 : aSize.realWidth ;
- var height = aSize.height;
- var realHeight = this.autoHide.mode == this.autoHide.kMODE_HIDE ? 0 : aSize.realHeight ;
- var pos = this.position;
- var vertical = this.isVertical;
-
- var splitter = d.getElementById('treestyletab-tabbar-resizer-splitter');
- if (!splitter) {
- let box = d.createElement('box');
- box.setAttribute('id', 'treestyletab-tabbar-resizer-box');
- box.setAttribute(this.kTAB_STRIP_ELEMENT, true);
- splitter = d.createElement('splitter');
- splitter.setAttribute(this.kTAB_STRIP_ELEMENT, true);
- splitter.setAttribute('id', 'treestyletab-tabbar-resizer-splitter');
- splitter.setAttribute('class', this.kSPLITTER);
- splitter.setAttribute('onmousedown', 'TreeStyleTabService.handleEvent(event);');
- splitter.setAttribute('onmouseup', 'TreeStyleTabService.handleEvent(event);');
- splitter.setAttribute('ondblclick', 'TreeStyleTabService.handleEvent(event);');
- box.appendChild(splitter);
- this.tabStrip.appendChild(box);
- }
-
- var box = splitter.parentNode;
-
- box.orient = splitter.orient = vertical ? 'horizontal' : 'vertical' ;
- box.width = (width - realWidth) || width;
- box.height = (height - realHeight) || height;
-
- var boxStyle = box.style;
- boxStyle.top = pos == 'top' ? realHeight+'px' : '' ;
- boxStyle.right = pos == 'right' ? realWidth+'px' : '' ;
- boxStyle.left = pos == 'left' ? realWidth+'px' : '' ;
- boxStyle.bottom = pos == 'bottom' ? realHeight+'px' : '' ;
-
- if (vertical) {
- splitter.removeAttribute('width');
- splitter.setAttribute('height', height);
- }
- else {
- splitter.setAttribute('width', width);
- splitter.removeAttribute('height');
- }
-
- var splitterWidth = splitter.boxObject.width;
- var splitterHeight = splitter.boxObject.height;
- var splitterStyle = splitter.style;
- splitterStyle.marginTop = pos == 'bottom' ? (-splitterHeight)+'px' :
- vertical ? '0' :
- box.height+'px' ;
- splitterStyle.marginRight = pos == 'left' ? (-splitterWidth)+'px' :
- !vertical ? '0' :
- box.width+'px' ;
- splitterStyle.marginLeft = pos == 'right' ? (-splitterWidth)+'px' :
- !vertical ? '0' :
- box.width+'px' ;
- splitterStyle.marginBottom = pos == 'top' ? (-splitterHeight)+'px' :
- vertical ? '0' :
- box.height+'px' ;
- },
-
- updateTabbarOverflow : function TSTBrowser_updateTabbarOverflow()
- {
- var d = this.document;
- var b = this.mTabBrowser;
- b.mTabContainer.removeAttribute('overflow');
- var container = d.getAnonymousElementByAttribute(b.mTabContainer, 'class', 'tabs-container') || b.mTabContainer;
-
- if (container != b.mTabContainer)
- container.removeAttribute('overflow');
-
- var scrollBox = this.scrollBox;
- scrollBox = d.getAnonymousElementByAttribute(scrollBox, 'anonid', 'scrollbox');
- if (scrollBox)
- scrollBox = d.getAnonymousNodes(scrollBox)[0];
- if (
- scrollBox &&
- (
- scrollBox.boxObject.width > container.boxObject.width ||
- scrollBox.boxObject.height > container.boxObject.height
- )
- ) {
- b.mTabContainer.setAttribute('overflow', true);
- if (container != b.mTabContainer)
- container.setAttribute('overflow', true);
- }
- else {
- b.mTabContainer.removeAttribute('overflow');
- if (container != b.mTabContainer)
- container.removeAttribute('overflow');
- }
- },
-
- reinitAllTabs : function TSTBrowser_reinitAllTabs(aSouldUpdateCount)
- {
- var tabs = this.getAllTabs(this.mTabBrowser);
- for (let i = 0, maxi = tabs.length; i < maxi; i++)
- {
- let tab = tabs[i];
- this.initTabAttributes(tab);
- this.initTabContents(tab);
- if (aSouldUpdateCount)
- this.updateTabsCount(tab);
- }
- },
-
- destroy : function TSTBrowser_destroy()
- {
- this.animationManager.removeTask(this.smoothScrollTask);
-
- Object.keys(this.deferredTasks).forEach(function(key) {
- if (this.deferredTasks[key].cancel) {
- this.deferredTasks[key].cancel();
- delete this.deferredTasks[key];
- }
- }, this);
-
- this.autoHide.destroy();
- delete this._autoHide;
-
- this._initDNDObservers(); // ensure initialized
- this.tabbarDNDObserver.destroy();
- delete this._tabbarDNDObserver;
- this.panelDNDObserver.destroy();
- delete this._panelDNDObserver;
-
- if (this.tooltipManager) {
- this.tooltipManager.destroy();
- delete this.tooltipManager;
- }
-
- if (this.tabStripPlaceHolderBoxObserver) {
- this.tabStripPlaceHolderBoxObserver.destroy();
- delete this.tabStripPlaceHolderBoxObserver;
- }
-
- var w = this.window;
- var d = this.document;
- var b = this.mTabBrowser;
- delete b.tabContainer.treeStyleTab;
-
- var tabs = this.getAllTabs(b);
- for (let i = 0, maxi = tabs.length; i < maxi; i++)
- {
- let tab = tabs[i];
- this.stopTabIndentAnimation(tab);
- this.stopTabCollapseAnimation(tab);
- this.destroyTab(tab);
- }
-
- this._endListenTabbarEvents();
-
- w.removeEventListener('resize', this, true);
- w.removeEventListener('beforecustomization', this, true);
- w.removeEventListener('aftercustomization', this, false);
- w.removeEventListener('customizationchange', this, false);
- w.removeEventListener(this.kEVENT_TYPE_PRINT_PREVIEW_ENTERED, this, false);
- w.removeEventListener(this.kEVENT_TYPE_PRINT_PREVIEW_EXITED, this, false);
- w.removeEventListener('tabviewframeinitialized', this, false);
- w.removeEventListener(this.kEVENT_TYPE_TAB_FOCUS_SWITCHING_END, this, false);
- w.removeEventListener('SSWindowStateBusy', this, false);
-
- b.removeEventListener('nsDOMMultipleTabHandlerTabsClosing', this, false);
-
- w['piro.sakura.ne.jp'].tabsDragUtils.destroyTabBrowser(b);
-
- var tabContextMenu = b.tabContextMenu ||
- d.getAnonymousElementByAttribute(b, 'anonid', 'tabContextMenu');
- tabContextMenu.removeEventListener('popupshowing', this, false);
-
- if (this.tabbarCanvas) {
- this.tabbarCanvas.parentNode.removeChild(this.tabbarCanvas);
- this.tabbarCanvas = null;
- }
-
- Services.obs.removeObserver(this, this.kTOPIC_INDENT_MODIFIED);
- Services.obs.removeObserver(this, this.kTOPIC_COLLAPSE_EXPAND_ALL);
- Services.obs.removeObserver(this, this.kTOPIC_CHANGE_TREEVIEW_AVAILABILITY);
- Services.obs.removeObserver(this, 'lightweight-theme-styling-update');
- prefs.removePrefListener(this);
-
- delete this.windowService;
- delete this.window;
- delete this.document;
- delete this.mTabBrowser.treeStyleTab;
- delete this.mTabBrowser;
- },
-
- destroyTab : function TSTBrowser_destroyTab(aTab)
- {
- var id = aTab.getAttribute(this.kID);
- if (id in this.tabsHash &&
- aTab == this.tabsHash[id])
- delete this.tabsHash[id];
-
- if (aTab.__treestyletab__checkTabsIndentOverflowOnMouseLeave) {
- this.document.removeEventListener('mouseover', aTab.__treestyletab__checkTabsIndentOverflowOnMouseLeave, true);
- this.document.removeEventListener('mouseout', aTab.__treestyletab__checkTabsIndentOverflowOnMouseLeave, true);
- delete aTab.__treestyletab__checkTabsIndentOverflowOnMouseLeave;
- }
-
- delete aTab.__treestyletab__linkedTabBrowser;
- },
-
- _endListenTabbarEvents : function TSTBrowser_endListenTabbarEvents()
- {
- var b = this.mTabBrowser;
-
- var tabContainer = b.mTabContainer;
- tabContainer.removeEventListener('TabOpen', this, true);
- tabContainer.removeEventListener('TabClose', this, true);
- tabContainer.removeEventListener('TabMove', this, true);
- tabContainer.removeEventListener('TabShow', this, true);
- tabContainer.removeEventListener('TabHide', this, true);
- tabContainer.removeEventListener('SSTabRestoring', this, true);
- tabContainer.removeEventListener('SSTabRestored', this, true);
- tabContainer.removeEventListener('TabPinned', this, true);
- tabContainer.removeEventListener('TabUnpinned', this, true);
- tabContainer.removeEventListener('mouseover', this, true);
- tabContainer.removeEventListener('mouseout', this, true);
- tabContainer.removeEventListener('dblclick', this, true);
- tabContainer.removeEventListener('select', this, true);
- tabContainer.removeEventListener('scroll', this, true);
-
- var strip = this.tabStrip;
- strip.removeEventListener('MozMouseHittest', this, true);
- strip.removeEventListener('mousedown', this, true);
- strip.removeEventListener('click', this, true);
- strip.removeEventListener('DOMMouseScroll', this, true);
-
- this.scrollBox.removeEventListener('overflow', this, true);
- this.scrollBox.removeEventListener('underflow', this, true);
- },
-
- saveCurrentState : function TSTBrowser_saveCurrentState()
- {
- this.autoHide.saveCurrentState();
-
- var b = this.mTabBrowser;
- var floatingBox = this.getTabStrip(b).boxObject;
- var fixedBox = (this.tabStripPlaceHolder || this.getTabStrip(b)).boxObject;
- var prefs = {
- 'tabbar.fixed.horizontal' : b.getAttribute(this.kFIXED+'-horizontal') == 'true',
- 'tabbar.fixed.vertical' : b.getAttribute(this.kFIXED+'-vertical') == 'true',
- 'tabbar.width' : this.isVertical && this.autoHide.expanded && floatingBox.width ? floatingBox.width : void(0),
- 'tabbar.shrunkenWidth' : this.isVertical && !this.autoHide.expanded && fixedBox.width ? fixedBox.width : void(0),
- 'tabbar.height' : !this.isVertical && this.autoHide.expanded && floatingBox.height ? floatingBox.height : void(0)
- };
- for (var i in prefs)
- {
- if (prefs[i] !== void(0) && utils.getTreePref(i) != prefs[i])
- utils.setTreePref(i, prefs[i]);
- }
- this.position = this.position;
- },
-
-/* toolbar customization */
-
- syncDestroyTabbar : function TSTBrowser_syncDestroyTabbar()
- {
- this.stopRendering();
-
- this._lastTreeViewEnabledBeforeDestroyed = this.treeViewEnabled;
- this.treeViewEnabled = false;
- this.maxTreeLevel = 0;
-
- this._lastTabbarPositionBeforeDestroyed = this.position;
- if (this.position != 'top') {
- let self = this;
- this.doAndWaitDOMEvent(
- this.kEVENT_TYPE_TABBAR_POSITION_CHANGED,
- this.window,
- 100,
- function() {
- self.position = 'top';
- }
- );
- }
-
- this.fixed = true;
-
- var tabbar = this.mTabBrowser.tabContainer;
- tabbar.removeAttribute('width');
- tabbar.removeAttribute('height');
- tabbar.removeAttribute('ordinal');
-
- this.removeTabStripAttribute('width');
- this.removeTabStripAttribute('height');
- this.removeTabStripAttribute('ordinal');
- this.removeTabStripAttribute('orient');
-
- var toolbar = this.ownerToolbar;
- this.destroyTabStrip(toolbar);
- toolbar.classList.add(this.kTABBAR_TOOLBAR_READY);
-
- this._endListenTabbarEvents();
-
- this.tabbarDNDObserver.endListenEvents();
-
- this.window.setTimeout(function(aSelf) {
- aSelf.updateCustomizedTabsToolbar();
- }, 100, this);
-
- this.startRendering();
- },
- destroyTabStrip : function TSTBrowser_destroyTabStrip(aTabStrip)
- {
- aTabStrip.classList.remove(this.kTABBAR_TOOLBAR);
- aTabStrip.style.top = aTabStrip.style.left = aTabStrip.style.width = aTabStrip.style.height = '';
- aTabStrip.removeAttribute('height');
- aTabStrip.removeAttribute('width');
- aTabStrip.removeAttribute('ordinal');
- aTabStrip.removeAttribute('orient');
- },
-
- syncReinitTabbar : function TSTBrowser_syncReinitTabbar()
- {
- this.stopRendering();
-
- this.ownerToolbar.classList.add(this.kTABBAR_TOOLBAR);
- this.ownerToolbar.classList.remove(this.kTABBAR_TOOLBAR_READY);
- Array.slice(this.document.querySelectorAll('.'+this.kTABBAR_TOOLBAR_READY_POPUP))
- .forEach(this.safeRemovePopup, this);
-
- var position = this._lastTabbarPositionBeforeDestroyed || this.position;
- delete this._lastTabbarPositionBeforeDestroyed;
-
- var self = this;
- this.doAndWaitDOMEvent(
- this.kEVENT_TYPE_TABBAR_INITIALIZED,
- this.window,
- 100,
- function() {
- self.initTabbar(position, 'top');
- }
- );
- this.reinitAllTabs(true);
-
- this.tabbarDNDObserver.startListenEvents();
-
- this.treeViewEnabled = this._lastTreeViewEnabledBeforeDestroyed;
- delete this._lastTreeViewEnabledBeforeDestroyed;
-
- this.updateFloatingTabbar(this.kTABBAR_UPDATE_BY_RESET);
-
- this.startRendering();
- },
-
- updateCustomizedTabsToolbar : function TSTBrowser_updateCustomizedTabsToolbar()
- {
- var d = this.document;
-
- var newToolbar = this.ownerToolbar;
- newToolbar.classList.add(this.kTABBAR_TOOLBAR_READY);
-
- var oldToolbar = d.querySelector('.'+this.kTABBAR_TOOLBAR_READY);
- if (oldToolbar == newToolbar)
- return;
-
- if (oldToolbar && oldToolbar != newToolbar) {
- this.safeRemovePopup(d.getElementById(oldToolbar.id+'-'+this.kTABBAR_TOOLBAR_READY_POPUP));
- oldToolbar.classList.remove(this.kTABBAR_TOOLBAR_READY);
- }
-
- var id = newToolbar.id+'-'+this.kTABBAR_TOOLBAR_READY_POPUP;
- var panel = d.getElementById(id);
- if (!panel) {
- panel = d.createElement('panel');
- panel.setAttribute('id', id);
- panel.setAttribute('class', this.kTABBAR_TOOLBAR_READY_POPUP);
- panel.setAttribute('noautohide', true);
- panel.setAttribute('onmouseover', 'this.hidePopup()');
- panel.setAttribute('ondragover', 'this.hidePopup()');
- panel.appendChild(d.createElement('label'));
- let position = this._lastTabbarPositionBeforeDestroyed || this.position;
- let label = utils.treeBundle.getString('toolbarCustomizing_tabbar_'+(position == 'left' || position == 'right' ? 'vertical' : 'horizontal' ));
- panel.firstChild.appendChild(d.createTextNode(label));
- d.getElementById('mainPopupSet').appendChild(panel);
- }
- panel.openPopup(newToolbar, 'end_after', 0, 0, false, false);
- },
- safeRemovePopup : function TSTBrowser_safeRemovePopup(aPopup)
- {
- if (!aPopup)
- return;
- if (aPopup.state == 'open') {
- aPopup.addEventListener('popuphidden', function onPopuphidden(aEvent) {
- aPopup.removeEventListener(aEvent.type, onPopuphidden, false);
- aPopup.parentNode.removeChild(aPopup);
- }, false);
- aPopup.hidePopup();
- }
- else {
- aPopup.parentNode.removeChild(aPopup);
- }
- },
-
-/* nsIObserver */
-
- domains : [
- 'extensions.treestyletab.',
- 'browser.tabs.closeButtons',
- 'browser.tabs.closeWindowWithLastTab',
- 'browser.tabs.autoHide',
- 'browser.tabs.animate'
- ],
-
- observe : function TSTBrowser_observe(aSubject, aTopic, aData)
- {
- switch (aTopic)
- {
- case this.kTOPIC_INDENT_MODIFIED:
- if (this.indent > -1)
- this.updateAllTabsIndent();
- return;
-
- case this.kTOPIC_COLLAPSE_EXPAND_ALL:
- if (!aSubject || aSubject == this.window) {
- aData = String(aData);
- this.collapseExpandAllSubtree(
- aData.indexOf('collapse') > -1,
- aData.indexOf('now') > -1
- );
- }
- return;
-
- case 'lightweight-theme-styling-update':
- return this.updateFloatingTabbar(this.kTABBAR_UPDATE_BY_APPEARANCE_CHANGE);
-
- case this.kTOPIC_CHANGE_TREEVIEW_AVAILABILITY:
- return this.treeViewEnabled = (aData != 'false');
-
- case 'nsPref:changed':
- return this.onPrefChange(aData);
-
- default:
- return;
- }
- },
-
- onPrefChange : function TSTBrowser_onPrefChange(aPrefName)
- {
- // ignore after destruction
- if (!this.window || !this.window.TreeStyleTabService)
- return;
-
- var b = this.mTabBrowser;
- var value = prefs.getPref(aPrefName);
- var tabContainer = b.mTabContainer;
- var tabs = this.getAllTabs(b);
- switch (aPrefName)
- {
- case 'extensions.treestyletab.tabbar.position':
- if (this.shouldApplyNewPref)
- this.position = value;
- return;
-
- case 'extensions.treestyletab.tabbar.invertTab':
- case 'extensions.treestyletab.tabbar.multirow':
- this.initTabbar();
- this.updateAllTabsIndent();
- for (let i = 0, maxi = tabs.length; i < maxi; i++)
- {
- this.initTabContents(tabs[i]);
- }
- return;
- case 'extensions.treestyletab.tabbar.invertTabContents':
- this.setTabbrowserAttribute(this.kTAB_CONTENTS_INVERTED, value);
- for (let i = 0, maxi = tabs.length; i < maxi; i++)
- {
- this.initTabContents(tabs[i]);
- }
- return;
-
- case 'extensions.treestyletab.tabbar.invertClosebox':
- this.setTabbrowserAttribute(this.kCLOSEBOX_INVERTED, value);
- for (let i = 0, maxi = tabs.length; i < maxi; i++)
- {
- this.initTabContents(tabs[i]);
- }
- return;
-
- case 'extensions.treestyletab.tabbar.style':
- case 'extensions.treestyletab.tabbar.style.aero':
- this.setTabbarStyle(utils.getTreePref('tabbar.style'));
- value = utils.getTreePref('twisty.style');
- if (value != 'auto')
- return;
- case 'extensions.treestyletab.twisty.style':
- return this.setTwistyStyle(value);
-
- case 'extensions.treestyletab.showBorderForFirstTab':
- return this.setTabbrowserAttribute(this.kFIRSTTAB_BORDER, value);
-
- case 'extensions.treestyletab.tabbar.fixed.horizontal':
- if (!this.shouldApplyNewPref)
- return;
- this.setTabbrowserAttribute(this.kFIXED+'-horizontal', value ? 'true' : null, b);
- case 'extensions.treestyletab.maxTreeLevel.horizontal':
- case 'extensions.treestyletab.allowSubtreeCollapseExpand.horizontal':
- if (!this.isVertical)
- this.updateTabbarState(true);
- return;
-
- case 'extensions.treestyletab.tabbar.fixed.vertical':
- if (!this.shouldApplyNewPref)
- return;
- this.setTabbrowserAttribute(this.kFIXED+'-vertical', value ? 'true' : null, b);
- case 'extensions.treestyletab.maxTreeLevel.vertical':
- case 'extensions.treestyletab.allowSubtreeCollapseExpand.vertical':
- if (this.isVertical)
- this.updateTabbarState(true);
- return;
-
- case 'extensions.treestyletab.tabbar.width':
- case 'extensions.treestyletab.tabbar.shrunkenWidth':
- if (!this.shouldApplyNewPref)
- return;
- if (!this.autoHide.isResizing && this.isVertical) {
- this.removeTabStripAttribute('width');
- this.setTabStripAttribute('width', this.autoHide.placeHolderWidthFromMode);
- this.updateFloatingTabbar(this.kTABBAR_UPDATE_BY_PREF_CHANGE);
- }
- this.checkTabsIndentOverflow();
- return;
-
- case 'extensions.treestyletab.tabbar.height':
- if (!this.shouldApplyNewPref)
- return;
- this._horizontalTabMaxIndentBase = 0;
- this.checkTabsIndentOverflow();
- return;
-
- case 'extensions.treestyletab.tabbar.autoShow.mousemove':
- let (toggler = this.document.getAnonymousElementByAttribute(b, 'class', this.kTABBAR_TOGGLER)) {
- if (toggler) {
- if (value)
- toggler.removeAttribute('hidden');
- else
- toggler.setAttribute('hidden', true);
- }
- }
- return;
-
- case 'extensions.treestyletab.tabbar.invertScrollbar':
- this.setTabbrowserAttribute(this.kINVERT_SCROLLBAR, value);
- this.positionPinnedTabs();
- return;
-
- case 'extensions.treestyletab.tabbar.narrowScrollbar':
- return this.setTabbrowserAttribute(this.kNARROW_SCROLLBAR, value);
-
- case 'extensions.treestyletab.maxTreeLevel.phisical':
- if (this.maxTreeLevelPhisical = value)
- this.promoteTooDeepLevelTabs();
- return;
-
- case 'browser.tabs.animate':
- this.setTabbrowserAttribute(this.kANIMATION_ENABLED,
- prefs.getPref('browser.tabs.animate') !== false
- ? 'true' : null
- );
- return;
-
- case 'browser.tabs.closeButtons':
- case 'browser.tabs.closeWindowWithLastTab':
- return this.updateInvertedTabContentsOrder(true);
-
- case 'browser.tabs.autoHide':
- if (this.getTabs(this.mTabBrowser).length == 1)
- this.updateFloatingTabbar(this.kTABBAR_UPDATE_BY_SHOWHIDE_TABBAR);
- return;
-
- case 'extensions.treestyletab.tabbar.autoHide.mode':
- case 'extensions.treestyletab.tabbar.autoHide.mode.fullscreen':
- return this.autoHide; // ensure initialized
-
- case 'extensions.treestyletab.pinnedTab.faviconized':
- return this.positionPinnedTabsWithDelay();
-
- case 'extensions.treestyletab.counter.role.horizontal':
- if (!this.isVertical) {
- let self = this;
- if (this.deferredTasks[aPrefName])
- this.deferredTasks[aPrefName].cancel();
- (this.deferredTasks[aPrefName] = this.Deferred
- .next(function() { self.updateAllTabsCount(); }))
- .error(this.defaultDeferredErrorHandler).next(function() {
- delete self.deferredTasks[aPrefName];
- });
- }
- return;
- case 'extensions.treestyletab.counter.role.vertical':
- if (this.isVertical) {
- let self = this;
- if (this.deferredTasks[aPrefName])
- this.deferredTasks[aPrefName].cancel();
- (this.deferredTasks[aPrefName] = this.Deferred
- .next(function() { self.updateAllTabsCount(); }))
- .error(this.defaultDeferredErrorHandler).next(function() {
- delete self.deferredTasks[aPrefName];
- });
- }
- return;
-
- default:
- return;
- }
- },
- setTabbarStyle : function TSTBrowser_setTabbarStyle(aStyle)
- {
- if (/^(default|plain|flat|mixed|vertigo|metal|sidebar)(-aero)?$/.test(aStyle))
- aStyle = aStyle.toLowerCase();
-
- if (aStyle.indexOf('default') == 0) { // old name (for compatibility)
- utils.setTreePref('tabbar.style', aStyle = aStyle.replace('default', 'plain'));
- }
-
- if (aStyle) {
- let additionalValues = [];
- if (/^(plain|flat|mixed|vertigo)$/.test(aStyle))
- additionalValues.push('square');
- if (/^(plain|flat|mixed)$/.test(aStyle))
- additionalValues.push('border');
- if (/^(flat|mixed)$/.test(aStyle))
- additionalValues.push('color');
- if (/^(plain|mixed)$/.test(aStyle))
- additionalValues.push('shadow');
- if (utils.getTreePref('tabbar.style.aero'))
- additionalValues.push('aero');
- if (additionalValues.length)
- aStyle = additionalValues.join(' ')+' '+aStyle;
-
- this.setTabbrowserAttribute(this.kSTYLE, aStyle);
- }
- else {
- this.removeTabbrowserAttribute(this.kSTYLE);
- }
- },
- setTwistyStyle : function TSTBrowser_setTwistyStyle(aStyle)
- {
- if (aStyle != 'auto') {
- this.setTabbrowserAttribute(this.kTWISTY_STYLE, aStyle);
- return;
- }
-
- aStyle = 'modern-black';
-
- if (utils.getTreePref('tabbar.style') == 'sidebar') {
- aStyle = 'osx';
- }
- else if (
- prefs.getPref('extensions.informationaltab.thumbnail.enabled') &&
- prefs.getPref('extensions.informationaltab.thumbnail.position') < 100
- ) {
- let self = this;
- this.extensions.isAvailable('informationaltab@piro.sakura.ne.jp', {
- ok : function() {
- aStyle = 'retro';
- self.setTabbrowserAttribute(self.kTWISTY_STYLE, aStyle);
- },
- ng : function() {
- self.setTabbrowserAttribute(self.kTWISTY_STYLE, aStyle);
- }
- });
- return;
- }
-
- this.setTabbrowserAttribute(this.kTWISTY_STYLE, aStyle);
- },
-
-/* DOM Event Handling */
-
- handleEvent : function TSTBrowser_handleEvent(aEvent)
- {
- switch (aEvent.type)
- {
- case 'TabOpen':
- return this.onTabOpen(aEvent);
-
- case 'TabClose':
- return this.onTabClose(aEvent);
-
- case 'TabMove':
- return this.onTabMove(aEvent);
-
- case 'TabShow':
- case 'TabHide':
- return this.onTabVisibilityChanged(aEvent);
-
- case 'SSTabRestoring':
- return this.onTabRestoring(aEvent);
-
- case 'SSTabRestored':
- return this.onTabRestored(aEvent);
-
- case 'TabPinned':
- return this.onTabPinned(aEvent.originalTarget);
-
- case 'TabUnpinned':
- return this.onTabUnpinned(aEvent.originalTarget);
-
- case 'select':
- return this.onTabSelect(aEvent);
-
- case 'click':
- return this.onClick(aEvent);
-
- case 'dblclick':
- return this.onDblClick(aEvent);
-
- case 'MozMouseHittest': // to block default behaviors of the tab bar
- return this.onMozMouseHittest(aEvent);
-
- case 'mousedown':
- return this.onMouseDown(aEvent);
-
- case 'DOMMouseScroll':
- return this.onDOMMouseScroll(aEvent);
-
- case 'scroll':
- return this.onScroll(aEvent);
-
- case 'popupshowing':
- return this.onPopupShowing(aEvent);
-
- case 'popuphiding':
- return this.onPopupHiding(aEvent);
-
- case 'mouseover':
- if (!this.tooltipManager)
- this._initTooltipManager();
- if (!this._DNDObserversInitialized)
- this._initDNDObservers();
- let (tab = aEvent.target) {
- if (tab.__treestyletab__twistyHoverTimer)
- this.window.clearTimeout(tab.__treestyletab__twistyHoverTimer);
- if (this.isEventFiredOnTwisty(aEvent)) {
- tab.setAttribute(this.kTWISTY_HOVER, true);
- tab.__treestyletab__twistyHoverTimer = this.window.setTimeout(function(aSelf) {
- tab.setAttribute(aSelf.kTWISTY_HOVER, true);
- delete tab.__treestyletab__twistyHoverTimer;
- }, 0, this);
- }
- }
- return;
-
- case 'mouseout':
- let (tab = aEvent.target) {
- if (tab.__treestyletab__twistyHoverTimer) {
- this.window.clearTimeout(tab.__treestyletab__twistyHoverTimer);
- delete tab.__treestyletab__twistyHoverTimer;
- }
- tab.removeAttribute(this.kTWISTY_HOVER);
- }
- return;
-
- case 'dragover':
- if (!this.tooltipManager)
- this._initTooltipManager();
- if (!this._DNDObserversInitialized)
- this._initDNDObservers();
- return;
-
- case 'overflow':
- case 'underflow':
- return this.onTabbarOverflow(aEvent);
-
- case 'resize':
- return this.onResize(aEvent);
-
-
- // toolbar customizing
- case 'beforecustomization':
- this.toolbarCustomizing = true;
- return this.syncDestroyTabbar();
- case 'aftercustomization':
- // Ignore it, because 'aftercustomization' fired not
- // following to 'beforecustomization' is invalid.
- // Personal Titlebar addon (or others) fires a fake
- // event on its startup process.
- if (!this.toolbarCustomizing)
- return;
- this.toolbarCustomizing = false;
- return this.syncReinitTabbar();
- case 'customizationchange':
- return this.updateCustomizedTabsToolbar();
-
- case 'tabviewframeinitialized':
- return this.lastTabViewGroup = this.getTabViewGroupId();
-
-
- case this.kEVENT_TYPE_PRINT_PREVIEW_ENTERED:
- return this.onTreeStyleTabPrintPreviewEntered(aEvent);
- case this.kEVENT_TYPE_PRINT_PREVIEW_EXITED:
- return this.onTreeStyleTabPrintPreviewExited(aEvent);
-
-
- case this.kEVENT_TYPE_TAB_FOCUS_SWITCHING_END:
- return this.cancelDelayedExpandOnTabSelect();
-
-
- case 'SSWindowStateBusy':
- return this.needRestoreTree = true;
-
-
- case 'nsDOMMultipleTabHandlerTabsClosing':
- if (!this.onTabsClosing(aEvent))
- aEvent.preventDefault();
- return;
- }
- },
- lastScrollX : -1,
- lastScrollY : -1,
-
- restoreLastScrollPosition : function TSTBrowser_restoreLastScrollPosition()
- {
- if (this.lastScrollX < 0 || this.lastScrollY < 0 || !this.isVisible)
- return;
- var lastX = this.lastScrollX;
- var lastY = this.lastScrollY;
- this.clearLastScrollPosition();
- if (!this.smoothScrollTask &&
- !this.scrollBox._smoothScrollTimer) { // don't restore scroll position if another scroll is already running.
- let x = {}, y = {};
- let scrollBoxObject = this.scrollBoxObject;
- scrollBoxObject.getPosition(x, y);
- if (x.value != lastX || y.value != lastY)
- scrollBoxObject.scrollTo(lastX, lastY);
- }
- },
-
- clearLastScrollPosition : function TSTBrowser_clearLastScrollPosition()
- {
- this.lastScrollX = this.lastScrollY = -1;
- },
-
- updateLastScrollPosition : function TSTBrowser_updateLastScrollPosition()
- {
- if (!this.isVertical || !this.isVisible)
- return;
- var x = {}, y = {};
- var scrollBoxObject = this.scrollBoxObject;
- if (!scrollBoxObject)
- return;
- scrollBoxObject.getPosition(x, y);
- this.lastScrollX = x.value;
- this.lastScrollY = y.value;
- },
-
- cancelPerformingAutoScroll : function TSTBrowser_cancelPerformingAutoScroll(aOnlyCancel)
- {
- if (this.smoothScrollTask) {
- this.animationManager.removeTask(this.smoothScrollTask);
- this.smoothScrollTask = null;
- }
- this.clearLastScrollPosition();
-
- if (this.deferredTasks['cancelPerformingAutoScroll']) {
- this.deferredTasks['cancelPerformingAutoScroll'].cancel();
- delete this.deferredTasks['cancelPerformingAutoScroll'];
- }
-
- if (aOnlyCancel)
- return;
-
- var self = this;
- (this.deferredTasks['cancelPerformingAutoScroll'] = this.Deferred.wait(0.3))
- .next(function() {
- delete self.deferredTasks['cancelPerformingAutoScroll'];
- }).error(this.defaultDeferredErrorHandler);
- },
-
- shouldCancelEnsureElementIsVisible : function TSTBRowser_shouldCancelEnsureElementIsVisible()
- {
- return (
- this.deferredTasks['cancelPerformingAutoScroll'] &&
- (new Error()).stack.indexOf('onxblDOMMouseScroll') < 0
- );
- },
-
- onTabOpen : function TSTBrowser_onTabOpen(aEvent, aTab)
- {
- var tab = aTab || aEvent.originalTarget;
- var b = this.mTabBrowser;
-
- if (this.isTabInitialized(tab))
- return false;
-
- this.initTab(tab);
-
- var hasStructure = this.treeStructure && this.treeStructure.length;
- var pareintIndexInTree = hasStructure ? this.treeStructure.shift() : 0 ;
- var lastRelatedTab = b._lastRelatedTab;
-
- if (this.readiedToAttachNewTab) {
- if (pareintIndexInTree < 0) { // there is no parent, so this is a new parent!
- this.parentTab = tab.getAttribute(this.kID);
- }
-
- let parent = this.getTabById(this.parentTab);
- if (parent) {
- let tabs = [parent].concat(this.getDescendantTabs(parent));
- parent = pareintIndexInTree > -1 && pareintIndexInTree < tabs.length ? tabs[pareintIndexInTree] : parent ;
- }
- if (parent) {
- this.attachTabTo(tab, parent, {
- dontExpand : this.shouldExpandAllTree
- });
- }
-
- let refTab;
- let newIndex = -1;
- if (hasStructure) {
- }
- else if (this.insertBefore &&
- (refTab = this.getTabById(this.insertBefore))) {
- newIndex = refTab._tPos;
- }
- else if (
- parent &&
- utils.getTreePref('insertNewChildAt') == this.kINSERT_FISRT &&
- (this.multipleCount <= 0 || this._addedCountInThisLoop <= 0)
- ) {
- /* 複数の子タブを一気に開く場合、最初に開いたタブだけを
- 子タブの最初の位置に挿入し、続くタブは「最初の開いたタブ」と
- 「元々最初の子だったタブ」との間に挿入していく */
- newIndex = parent._tPos + 1;
- if (refTab = this.getFirstChildTab(parent))
- this.insertBefore = refTab.getAttribute(this.kID);
- }
-
- if (newIndex > -1) {
- if (newIndex > tab._tPos)
- newIndex--;
- this.internallyTabMovingCount++;
- b.moveTabTo(tab, newIndex);
- this.internallyTabMovingCount--;
- }
-
- if (this.shouldExpandAllTree)
- this.collapseExpandSubtree(parent, false);
- }
-
- this._addedCountInThisLoop++;
- if (!this._addedCountClearTimer) {
- this._addedCountClearTimer = this.window.setTimeout(function(aSelf) {
- aSelf._addedCountInThisLoop = 0;
- aSelf._addedCountClearTimer = null;
- }, 0, this);
- }
-
- if (!this.readiedToAttachMultiple) {
- this.stopToOpenChildTab(b);
- }
- else {
- this.multipleCount++;
- }
-
- if (this.animationEnabled) {
- this.updateTabCollapsed(tab, true, true);
- let self = this;
- this.updateTabCollapsed(tab, false, this.windowService.restoringTree, function() {
- /**
- * When the system is too slow, the animation can start after
- * smooth scrolling is finished. The smooth scrolling should be
- * started together with the start of the animation effect.
- */
- self.scrollToNewTab(tab);
- });
- }
- else {
- this.scrollToNewTab(tab);
- }
-
- this.updateInsertionPositionInfo(tab);
-
- if (prefs.getPref('browser.tabs.autoHide'))
- this.updateFloatingTabbar(this.kTABBAR_UPDATE_BY_SHOWHIDE_TABBAR);
-
- if (this.canStackTabs)
- this.updateTabsZIndex(true);
-
- // if there is only one tab and new another tab is opened,
- // closebox appearance is possibly changed.
- var tabs = this.getTabs(b);
- if (tabs.length == 2)
- this.updateInvertedTabContentsOrder(tabs);
-
- /**
- * gBrowser.addTab() resets gBrowser._lastRelatedTab.owner
- * when a new background tab is opened from the current tab,
- * but it will fail with TST because gBrowser.moveTab() (called
- * by TST) clears gBrowser._lastRelatedTab.
- * So, we have to restore gBrowser._lastRelatedTab manually.
- */
- b._lastRelatedTab = lastRelatedTab;
-
- return true;
- },
- _addedCountInThisLoop : 0,
- _addedCountClearTimer : null,
- _checkRestoringWindowTimerOnTabAdded : null,
-
- scrollToNewTab : function TSTBrowser_scrollToNewTab(aTab)
- {
- if (!aTab.parentNode) // do nothing for closed tab!
- return;
-
- if (this.scrollToNewTabMode > 0)
- this.scrollToTab(aTab, this.scrollToNewTabMode < 2);
- },
-
- updateInsertionPositionInfo : function TSTBrowser_updateInsertionPositionInfo(aTab)
- {
- if (!aTab.parentNode) // do nothing for closed tab!
- return;
-
- var prev = this.getPreviousSiblingTab(aTab);
- if (prev) {
- this.setTabValue(aTab, this.kINSERT_AFTER, prev.getAttribute(this.kID));
- this.setTabValue(prev, this.kINSERT_BEFORE, aTab.getAttribute(this.kID));
- }
-
- var next = this.getNextSiblingTab(aTab);
- if (next) {
- this.setTabValue(aTab, this.kINSERT_BEFORE, next.getAttribute(this.kID));
- this.setTabValue(next, this.kINSERT_AFTER, aTab.getAttribute(this.kID));
- }
- },
-
- onTabClose : function TSTBrowser_onTabClose(aEvent)
- {
- var tab = aEvent.originalTarget;
- var d = this.document;
- var b = this.mTabBrowser;
-
- tab.setAttribute(this.kREMOVED, true);
-
- this.stopTabIndentAnimation(tab);
- this.stopTabCollapseAnimation(tab);
-
- var closeParentBehavior = this.getCloseParentBehaviorForTab(tab);
-
- var collapsed = this.isCollapsed(tab);
- if (collapsed)
- this.stopRendering();
-
- var backupAttributes = this._collectBackupAttributes(tab);
- if (DEBUG)
- dump('onTabClose: backupAttributes = '+JSON.stringify(backupAttributes)+'\n');
-
- if (closeParentBehavior == this.kCLOSE_PARENT_BEHAVIOR_CLOSE_ALL_CHILDREN ||
- this.isSubtreeCollapsed(tab))
- this._closeChildTabs(tab);
-
- this._saveAndUpdateReferenceTabsInfo(tab);
-
- var firstChild = this.getFirstChildTab(tab);
-
- this.detachAllChildren(tab, {
- behavior : closeParentBehavior
- });
-
- var nextFocusedTab = null;
- if (firstChild &&
- (closeParentBehavior == this.kCLOSE_PARENT_BEHAVIOR_PROMOTE_ALL_CHILDREN ||
- closeParentBehavior == this.kCLOSE_PARENT_BEHAVIOR_PROMOTE_FIRST_CHILD))
- nextFocusedTab = firstChild;
-
- var toBeClosedTabs = this._collectNeedlessGroupTabs(tab);
-
- var parentTab = this.getParentTab(tab);
- if (parentTab) {
- if (!nextFocusedTab && tab == this.getLastChildTab(parentTab)) {
- if (tab == this.getFirstChildTab(parentTab)) // this is the really last child
- nextFocusedTab = parentTab;
- else
- nextFocusedTab = this.getPreviousSiblingTab(tab);
- }
-
- if (nextFocusedTab && toBeClosedTabs.indexOf(nextFocusedTab) > -1)
- nextFocusedTab = this.getNextFocusedTab(parentTab);
- }
- else if (!nextFocusedTab) {
- nextFocusedTab = this.getNextFocusedTab(tab);
- }
-
- if (nextFocusedTab && toBeClosedTabs.indexOf(nextFocusedTab) > -1)
- nextFocusedTab = this.getNextFocusedTab(nextFocusedTab);
-
- if (nextFocusedTab && nextFocusedTab.hasAttribute(this.kREMOVED))
- nextFocusedTab = null;
-
- this._reserveCloseRelatedTabs(toBeClosedTabs);
-
- this.detachTab(tab, { dontUpdateIndent : true });
-
- this._restoreTabAttributes(tab, backupAttributes);
-
- if (b.selectedTab == tab)
- this._tryMoveFocusFromClosingCurrentTab(nextFocusedTab);
-
- this.updateLastScrollPosition();
-
- this.destroyTab(tab);
-
- if (tab.getAttribute('pinned') == 'true')
- this.positionPinnedTabsWithDelay();
-
- if (prefs.getPref('browser.tabs.autoHide'))
- this.updateFloatingTabbar(this.kTABBAR_UPDATE_BY_SHOWHIDE_TABBAR);
-
- if (this.canStackTabs)
- this.updateTabsZIndex(true);
-
- if (collapsed)
- this.startRendering();
- },
-
- _collectBackupAttributes : function TSTBrowser_collectBackupAttributes(aTab)
- {
- var attributes = {};
-
- if (this.hasChildTabs(aTab)) {
- attributes[this.kCHILDREN] = this.getTabValue(aTab, this.kCHILDREN);
- attributes[this.kSUBTREE_COLLAPSED] = this.getTabValue(aTab, this.kSUBTREE_COLLAPSED);
- }
-
- var ancestors = this.getAncestorTabs(aTab);
- if (ancestors.length) {
- let next = this.getNextSiblingTab(aTab);
- ancestors = ancestors.map(function(aAncestor) {
- if (!next && (next = this.getNextSiblingTab(aAncestor)))
- attributes[this.kINSERT_BEFORE] = next.getAttribute(this.kID);
- return aAncestor.getAttribute(this.kID);
- }, this);
- attributes[this.kANCESTOR] = ancestors.join('|');
- }
-
- return attributes;
- },
-
- _closeChildTabs : function TSTBrowser_closeChildTabs(aTab)
- {
- var tabs = this.getDescendantTabs(aTab);
- if (!this.fireTabSubtreeClosingEvent(aTab, tabs))
- return;
-
- var subtreeCollapsed = this.isSubtreeCollapsed(aTab);
- if (subtreeCollapsed)
- this.stopRendering();
-
- this.markAsClosedSet([aTab].concat(tabs));
-
- tabs.reverse();
- for (let i = 0, maxi = tabs.length; i < maxi; i++)
- {
- this.mTabBrowser.removeTab(tabs[i], { animate : true });
- }
-
- this.fireTabSubtreeClosedEvent(this.mTabBrowser, aTab, tabs);
-
- if (subtreeCollapsed)
- this.startRendering();
- },
-
- _collectNeedlessGroupTabs : function TSTBrowser_collectNeedlessGroupTabs(aTab)
- {
- var tabs = [];
- if (!aTab || !aTab.parentNode)
- return tabs;
-
- var parent = this.getParentTab(aTab);
- var siblings = this.getSiblingTabs(aTab);
- var groupTabs = siblings.filter(function(aTab) {
- return this.isTemporaryGroupTab(aTab);
- }, this);
- var groupTab = (
- groupTabs.length == 1 &&
- siblings.length == 1 &&
- this.hasChildTabs(groupTabs[0])
- ) ? groupTabs[0] : null ;
- if (groupTab)
- tabs.push(groupTab);
-
- var shouldCloseParentTab = (
- parent &&
- this.isTemporaryGroupTab(parent) &&
- this.getDescendantTabs(parent).length == 1
- );
- if (shouldCloseParentTab)
- tabs.push(parent);
-
- return tabs;
- },
-
- _reserveCloseRelatedTabs : function TSTBrowser_reserveCloseRelatedTabs(aTabs)
- {
- if (!aTabs.length)
- return;
-
- var key = 'onTabClose_'+parseInt(Math.random() * 65000);
- var self = this;
- (this.deferredTasks[key] = this.Deferred.next(function() {
- aTabs.forEach(function(aTab) {
- if (aTab.parentNode)
- self.mTabBrowser.removeTab(aTab, { animate : true });
- });
- })).error(this.defaultDeferredErrorHandler).next(function() {
- delete self.deferredTasks[key];
- }).next(function() {
- aTabs = null;
- self = null;
- key = null;
- });
- },
-
- _saveAndUpdateReferenceTabsInfo : function TSTBrowser_saveAndUpdateReferenceTabsInfo(aTab)
- {
- var prev = this.getPreviousSiblingTab(aTab);
- var next = this.getNextSiblingTab(aTab);
- if (prev) {
- this.setTabValue(aTab, this.kINSERT_AFTER, prev.getAttribute(this.kID));
-
- if (next)
- this.setTabValue(prev, this.kINSERT_BEFORE, next.getAttribute(this.kID));
- else
- this.deleteTabValue(prev, this.kINSERT_BEFORE);
- }
- if (next) {
- this.setTabValue(aTab, this.kINSERT_BEFORE, next.getAttribute(this.kID));
-
- if (prev)
- this.setTabValue(next, this.kINSERT_AFTER, prev.getAttribute(this.kID));
- else
- this.deleteTabValue(next, this.kINSERT_AFTER);
- }
- },
-
- _restoreTabAttributes : function TSTBrowser_restoreTabAttributes(aTab, aAttributes)
- {
- for (var i in aAttributes)
- {
- this.setTabValue(aTab, i, aAttributes[i]);
- }
- },
-
- _tryMoveFocusFromClosingCurrentTab : function TSTBrowser_tryMoveFocusFromClosingCurrentTab(aNextFocusedTab)
- {
- if (!aNextFocusedTab || aNextFocusedTab.hidden)
- return;
-
- var currentTab = this.mTabBrowser.selectedTab;
- var d = this.document;
-
- var event = d.createEvent('Events');
- event.initEvent(this.kEVENT_TYPE_FOCUS_NEXT_TAB, true, true);
- var canFocus = currentTab.dispatchEvent(event);
-
- // for backward compatibility
- event = d.createEvent('Events');
- event.initEvent(this.kEVENT_TYPE_FOCUS_NEXT_TAB.replace(/^nsDOM/, ''), true, true);
- canFocus = canFocus && currentTab.dispatchEvent(event);
-
- if (canFocus) {
- this._focusChangedByCurrentTabRemove = true;
- this.mTabBrowser.selectedTab = aNextFocusedTab;
- }
- },
-
- onTabsClosing : function TSTBrowser_onTabsClosing(aEvent)
- {
- var tabs = aEvent.detail && aEvent.detail.tabs ||
- aEvent.getData('tabs') // for backward compatibility;
- var b = this.getTabBrowserFromChild(tabs[0]);
-
- var trees = this.splitTabsToSubtrees(tabs);
- if (trees.some(function(aTabs) {
- return aTabs.length > 1 &&
- !this.fireTabSubtreeClosingEvent(aTabs[0], aTabs);
- }, this))
- return false;
-
- trees.forEach(this.markAsClosedSet, this);
-
- var self = this;
- let key = 'onTabClosing_'+parseInt(Math.random() * 65000);
- (this.deferredTasks[key] = this.Deferred.next(function() {
- for (let i = 0, maxi = trees.length; i < maxi; i++)
- {
- let tabs = trees[i];
- self.fireTabSubtreeClosedEvent(b, tabs[0], tabs);
- }
- })).error(this.defaultDeferredErrorHandler).next(function() {
- delete self.deferredTasks[key];
- });
-
- return true;
- },
-
- onTabMove : function TSTBrowser_onTabMove(aEvent)
- {
- var tab = aEvent.originalTarget;
- var b = this.mTabBrowser;
- tab.__treestyletab__previousPosition = aEvent.detail;
-
- // When the tab was moved before TabOpen event is fired, we have to update manually.
- var newlyOpened = !this.isTabInitialized(tab) && this.onTabOpen(null, tab);
-
- // twisty vanished after the tab is moved!!
- this.initTabContents(tab);
-
- // On Firefox 29, 30 and laters, reopened (restored) tab can be
- // placed in wrong place, because "TabMove" event fires before
- // "SSTabRestoring" event and "kINSERT_BEFORE" information is
- // unexpectedly cleared. So now I simulate the "SSTabRestoring"
- // event here.
- // See: https://github.com/piroor/treestyletab/issues/676#issuecomment-47700158
- if (tab.__SS_extdata) {
- let storedId = tab.__SS_extdata[this.kID]; // getTabValue() doesn't get the value!
- if (storedId && tab.getAttribute(this.kID) != storedId)
- this.onTabRestoring(aEvent);
- }
-
- if (this.hasChildTabs(tab) && !this.subTreeMovingCount) {
- this.moveTabSubtreeTo(tab, tab._tPos);
- }
-
- var parentTab = this.getParentTab(tab);
- if (parentTab && !this.subTreeChildrenMovingCount) {
- this.updateChildrenArray(parentTab);
- }
-
- this.updateTabsCount(tab, true);
-
- var prev = this.getPreviousSiblingTab(tab);
- var next = this.getNextSiblingTab(tab);
-
- if (prev) {
- this.setTabValue(prev, this.kINSERT_BEFORE, tab.getAttribute(this.kID));
- this.setTabValue(tab, this.kINSERT_AFTER, prev.getAttribute(this.kID));
- }
- else
- this.deleteTabValue(tab, this.kINSERT_AFTER);
-
- if (next) {
- this.setTabValue(next, this.kINSERT_AFTER, tab.getAttribute(this.kID));
- this.setTabValue(tab, this.kINSERT_BEFORE, next.getAttribute(this.kID));
- }
- else
- this.deleteTabValue(tab, this.kINSERT_BEFORE);
-
- var old = aEvent.detail;
- if (old > tab._tPos)
- old--;
- var tabs = this.getAllTabs(b);
- old = tabs[old];
-
- prev = this.getPreviousSiblingTab(old);
- next = this.getNextSiblingTab(old);
-
- if (prev) {
- this.setTabValue(prev, this.kINSERT_BEFORE, old.getAttribute(this.kID));
- this.setTabValue(old, this.kINSERT_AFTER, prev.getAttribute(this.kID));
- }
- else
- this.deleteTabValue(old, this.kINSERT_AFTER);
-
- if (next) {
- this.setTabValue(next, this.kINSERT_AFTER, old.getAttribute(this.kID));
- this.setTabValue(old, this.kINSERT_BEFORE, next.getAttribute(this.kID));
- }
- else
- this.deleteTabValue(old, this.kINSERT_BEFORE);
-
- this.positionPinnedTabsWithDelay();
-
- if (this.canStackTabs)
- this.updateTabsZIndex(true);
-
- if (
- this.subTreeMovingCount ||
- this.internallyTabMovingCount ||
- // We don't have to fixup tree structure for a NEW TAB
- // which has already been structured.
- (newlyOpened && this.getParentTab(tab))
- )
- return;
-
- this.attachTabFromPosition(tab, aEvent.detail);
- this.rearrangeTabViewItems(tab);
- },
-
- attachTabFromPosition : function TSTBrowser_attachTabFromPosition(aTab, aOldPosition)
- {
- var parent = this.getParentTab(aTab);
-
- if (aOldPosition === void(0))
- aOldPosition = aTab._tPos;
-
- var pos = this.getChildIndex(aTab, parent);
- var oldPos = this.getChildIndex(this.getAllTabs(this.mTabBrowser)[aOldPosition], parent);
- var delta;
- if (pos == oldPos) { // no move?
- return;
- }
- else if (pos < 0 || oldPos < 0) {
- delta = 2;
- }
- else {
- delta = Math.abs(pos - oldPos);
- }
-
- var prevTab = this.getPreviousTab(aTab);
- var nextTab = this.getNextTab(aTab);
-
- var tabs = this.getDescendantTabs(aTab);
- if (tabs.length) {
- nextTab = this.getNextTab(tabs[tabs.length-1]);
- }
-
- var prevParent = this.getParentTab(prevTab);
- var nextParent = this.getParentTab(nextTab);
-
- var prevLevel = prevTab ? Number(prevTab.getAttribute(this.kNEST)) : -1 ;
- var nextLevel = nextTab ? Number(nextTab.getAttribute(this.kNEST)) : -1 ;
-
- var newParent;
-
- if (!prevTab) { // moved to topmost position
- newParent = null;
- }
- else if (!nextTab) { // moved to last position
- newParent = (delta > 1) ? prevParent : parent ;
- }
- else if (prevParent == nextParent) { // moved into existing tree
- newParent = prevParent;
- }
- else if (prevLevel > nextLevel) { // moved to end of existing tree
- if (this.mTabBrowser.selectedTab != aTab) { // maybe newly opened tab
- newParent = prevParent;
- }
- else { // maybe drag and drop
- var realDelta = Math.abs(aTab._tPos - aOldPosition);
- newParent = realDelta < 2 ? prevParent : (parent || nextParent) ;
- }
- }
- else if (prevLevel < nextLevel) { // moved to first child position of existing tree
- newParent = parent || nextParent;
- }
-
- if (newParent != parent) {
- if (newParent) {
- if (newParent.hidden == aTab.hidden)
- this.attachTabTo(aTab, newParent, { insertBefore : nextTab });
- }
- else {
- this.detachTab(aTab);
- }
- }
- },
-
- updateChildrenArray : function TSTBrowser_updateChildrenArray(aTab)
- {
- if (!aTab.parentNode) // do nothing for closed tab!
- return;
-
- var children = this.getChildTabs(aTab);
- children.sort(this.sortTabsByOrder);
- this.setTabValue(
- aTab,
- this.kCHILDREN,
- children
- .map(function(aItem) {
- return aItem.getAttribute(this.kID);
- }, this)
- .join('|')
- );
- },
-
- // for TabView (Panorama aka Tab Candy)
- rearrangeTabViewItems : function TSTBrowser_rearrangeTabViewItems(aTab)
- {
- if (
- !aTab.parentNode || // do nothing for closed tab!
- !aTab.tabItem ||
- !aTab.tabItem.parent ||
- !aTab.tabItem.parent.reorderTabItemsBasedOnTabOrder
- )
- return;
-
- aTab.tabItem.parent.reorderTabItemsBasedOnTabOrder();
- },
-
- // for TabView (Panorama aka Tab Candy)
- onTabVisibilityChanged : function TSTBrowser_onTabVisibilityChanged(aEvent)
- {
- /**
- * Note: On this timing, we cannot know that which is the reason of this
- * event, by exitting from Panorama or the "Move to Group" command in the
- * context menu on tabs. So, we have to do operations with a delay to compare
- * last and current group which is updated in the next event loop.
- */
-
- var tab = aEvent.originalTarget;
- this.updateInvertedTabContentsOrder(tab);
- this.tabVisibilityChangedTabs.push({
- tab : tab,
- type : aEvent.type
- });
-
- if (this.tabVisibilityChangedTimer) {
- this.window.clearTimeout(this.tabVisibilityChangedTimer);
- this.tabVisibilityChangedTimer = null;
- }
-
- this.tabVisibilityChangedTimer = this.window.setTimeout(function(aSelf) {
- aSelf.tabVisibilityChangedTimer = null;
-
- var tabs = aSelf.tabVisibilityChangedTabs;
- if (!tabs.length)
- return;
-
- // restore tree from bottom safely
- var restoreTabs = tabs.filter(function(aChanged) {
- return aChanged.type == 'TabShow' &&
- aChanged.tab.__treestyletab__restoreState == aSelf.RESTORE_STATE_READY_TO_RESTORE;
- })
- .map(function(aChanged) {
- return aChanged.tab;
- })
- .sort(function(aA, aB) {
- return aB._tPos - aA._tPos;
- })
- .filter(aSelf.restoreOneTab, aSelf);
- for (let i = 0, maxi = restoreTabs.length; i < maxi; i++)
- {
- let tab = restoreTabs[i];
- aSelf.updateInsertionPositionInfo(tab);
- delete tab.__treestyletab__restoreState;
- }
-
- var currentGroupId = aSelf.getTabViewGroupId();
- if (aSelf.lastTabViewGroup && currentGroupId != aSelf.lastTabViewGroup) {
- // We should clear it first, because updateTreeByTabVisibility() never change visibility of tabs.
- aSelf.tabVisibilityChangedTabs = [];
- aSelf.updateTreeByTabVisibility(tabs.map(function(aChanged) { return aChanged.tab; }));
- }
- else {
- // For tabs moved by "Move to Group" command in the context menu on tabs
- var processedTabs = {};
- /**
- * subtreeFollowParentAcrossTabGroups() can change visibility of child tabs, so,
- * we must not clear tabVisibilityChangedTabs here, and we have to use
- * simple "for" loop instead of Array.prototype.forEach.
- */
- for (let i = 0; i < aSelf.tabVisibilityChangedTabs.length; i++)
- {
- let changed = aSelf.tabVisibilityChangedTabs[i];
- let tab = changed.tab;
- if (aSelf.getAncestorTabs(tab).some(function(aTab) {
- return processedTabs[aTab.getAttribute(aSelf.kID)];
- }))
- continue;
- aSelf.subtreeFollowParentAcrossTabGroups(tab);
- processedTabs[tab.getAttribute(aSelf.kID)] = true;
- }
- // now we can clear it!
- aSelf.tabVisibilityChangedTabs = [];
- }
- aSelf.lastTabViewGroup = currentGroupId;
- aSelf.checkTabsIndentOverflow();
- }, 0, this);
- },
- tabVisibilityChangedTimer : null,
- lastTabViewGroup : null,
-
- updateTreeByTabVisibility : function TSTBrowser_updateTreeByTabVisibility(aChangedTabs)
- {
- this.internallyTabMovingCount++;
-
- var allTabs = this.getAllTabs(this.mTabBrowser);
- var normalTabs = allTabs.filter(function(aTab) {
- return !aTab.hasAttribute('pinned');
- });
- aChangedTabs = aChangedTabs || normalTabs;
-
- var shownTabs = aChangedTabs.filter(function(aTab) {
- return !aTab.hidden;
- });
-
- var movingTabToAnotherGroup = !shownTabs.length;
- var switchingGroup = !movingTabToAnotherGroup;
-
- var lastIndex = allTabs.length - 1;
- var lastMovedTab;
- normalTabs = normalTabs.slice(0).reverse();
- for (let i = 0, maxi = normalTabs.length; i < maxi; i++)
- {
- let tab = normalTabs[i];
- let parent = this.getParentTab(tab);
- let attached = false;
- if (parent && (tab.hidden != parent.hidden)) {
- let lastNextTab = null;
- this.getAncestorTabs(tab).some(function(aAncestor) {
- if (aAncestor.hidden == tab.hidden) {
- this.attachTabTo(tab, aAncestor, {
- dontMove : true,
- insertBefore : lastNextTab
- });
- attached = true;
- return true;
- }
- lastNextTab = this.getNextSiblingTab(aAncestor);
- return false;
- }, this);
- if (!attached) {
- this.collapseExpandTab(tab, false, true);
- this.detachTab(tab);
- }
- }
-
- if (aChangedTabs.indexOf(tab) < 0)
- continue;
-
- if (
- switchingGroup &&
- !tab.hidden &&
- !attached &&
- !parent
- ) {
- let prev = this.getPreviousTab(tab);
- let next = this.getNextTab(tab);
- if (
- (prev && aChangedTabs.indexOf(prev) < 0 && !prev.hidden) ||
- (next && aChangedTabs.indexOf(next) < 0 && !next.hidden)
- )
- this.attachTabFromPosition(tab, lastIndex);
- }
-
- if (movingTabToAnotherGroup && tab.hidden) {
- let index = lastMovedTab ? lastMovedTab._tPos - 1 : lastIndex ;
- this.mTabBrowser.moveTabTo(tab, index);
- lastMovedTab = tab;
- }
- }
- this.internallyTabMovingCount--;
- },
-
- subtreeFollowParentAcrossTabGroups : function TSTBrowser_subtreeFollowParentAcrossTabGroups(aParent)
- {
- if (this.tabViewTreeIsMoving)
- return;
-
- var id = this.getTabViewGroupId(aParent);
- if (!id)
- return;
-
- this.tabViewTreeIsMoving = true;
- this.internallyTabMovingCount++;
- var w = this.window;
- var b = this.mTabBrowser;
- var lastCount = this.getAllTabs(b).length - 1;
-
- this.detachTab(aParent);
- b.moveTabTo(aParent, lastCount);
- var descendantTabs = this.getDescendantTabs(aParent);
- for (let i = 0, maxi = descendantTabs.length; i < maxi; i++)
- {
- let tab = descendantTabs[i];
- w.TabView.moveTabTo(tab, id);
- b.moveTabTo(tab, lastCount);
- }
- this.internallyTabMovingCount--;
- this.tabViewTreeIsMoving = false;
- },
- tabViewTreeIsMoving : false,
-
- getTabViewGroupId : function TSTBrowser_getTabViewGroupId(aTab)
- {
- var tab = aTab || this.mTabBrowser.selectedTab;
- var item = tab._tabViewTabItem;
- if (!item)
- return null;
-
- var group = item.parent;
- if (!group)
- return null;
-
- return group.id;
- },
-
- onRestoreTabContentStarted : function TSTBrowser_onRestoreTabContentStarted(aTab)
- {
- aTab.linkedBrowser.__treestyletab__toBeRestored = true;
- },
-
- onTabRestoring : function TSTBrowser_onTabRestoring(aEvent)
- {
- this.restoreTree();
-
- var tab = aEvent.originalTarget;
-
- tab.linkedBrowser.__treestyletab__toBeRestored = false;
- this.handleRestoredTab(tab);
-
- /**
- * Updating of the counter which is used to know how many tabs were
- * restored in a time.
- */
- this.windowService.restoringCount++;
- /**
- * By nsSessionStore.js, the next "SSTabRestoring" event will be fined
- * with "window.setTimeout()" following this "SSTabRestoring" event.
- * So, we have to do "setTimeout()" twice, instead of "Deferred.next()".
- */
- var self = this;
- this.window.setTimeout(function() {
- /**
- * On this timing, the next "SSTabRestoring" is not fired yet.
- * We only register the countdown task for the next event loop.
- */
- let key = 'onTabRestoring_'+parseInt(Math.random() * 65000);
- (self.deferredTasks[key] = self.windowService.Deferred.next(function() {
- /**
- * On this timing, the next "SSTabRestoring" was fired.
- * Now we can decrement the counter.
- */
- self.windowService.restoringCount--;
- })).error(self.defaultDeferredErrorHandler).next(function() {
- delete self.deferredTasks[key];
- });
- }, 0);
-
- if (!tab.selected &&
- this.mTabBrowser.currentURI.spec == 'about:sessionrestore') {
- let frame = this.mTabBrowser.contentWindow;
- frame = frame.wrappedJSObject || frame;
- let tree = frame.document.getElementById('tabList');
- let data = frame.gTreeData;
- if (tree && data) {
- let item = data[tree.currentIndex];
- this.window.setTimeout(function(aSelf, aTab, aTitle, aParent) {
- if (aTab.label== aTitle)
- aSelf.attachTabTo(aTab, aParent);
- }, 0, this, tab, item.label, this.mTabBrowser.selectedTab);
- }
- }
- },
-
- RESTORED_TREE_COLLAPSED_STATE_LAST_STATE : -1,
- RESTORED_TREE_COLLAPSED_STATE_COLLAPSED : 0,
- RESTORED_TREE_COLLAPSED_STATE_EXPANDED : 1,
- RESTORE_STATE_INITIAL : 0,
- RESTORE_STATE_READY_TO_RESTORE : 1,
- RESTORE_STATE_STRUCTURE_RESTORED : 2,
- handleRestoredTab : function TSTBrowser_handleRestoredTab(aTab)
- {
- if (aTab.__treestyletab__restoreState == this.RESTORE_STATE_READY_TO_RESTORE) {
- // this is a hidden tab in the background group, and
- // have to be restored by restoreOneTab() on "TabShown" event.
- this.deleteTabValue(aTab, this.kCLOSED_SET_ID);
- return;
- }
-
- var [id, mayBeDuplicated] = this._restoreTabId(aTab);
- var structureRestored = aTab.__treestyletab__restoreState == this.RESTORE_STATE_STRUCTURE_RESTORED;
- var children = this.getTabValue(aTab, this.kCHILDREN);
- if (
- !structureRestored &&
- (
- !mayBeDuplicated ||
- aTab.getAttribute(this.kCHILDREN) != children
- )
- ) {
- // failsafe
- this.detachAllChildren(aTab, {
- dontUpdateIndent : true,
- dontAnimate : this.windowService.restoringTree
- });
- }
-
- var closeSetId = !structureRestored && this._getCloseSetId(aTab, mayBeDuplicated);
-
- // remove temporary cache
- var currentId = aTab.getAttribute(this.kID);
- if (id != currentId &&
- currentId &&
- currentId in this.tabsHash &&
- this.tabsHash[currentId] == aTab)
- delete this.tabsHash[currentId];
-
- this.setTabValue(aTab, this.kID, id);
- this.tabsHash[id] = aTab;
-
- if (structureRestored) {
- this._fixMissingAttributesFromSessionData(aTab);
- }
- else {
- let isSubtreeCollapsed = this._restoreSubtreeCollapsedState(aTab);
-
- let restoringMultipleTabs = this.windowService.restoringTree;
- let options = {
- dontExpand : restoringMultipleTabs,
- dontUpdateIndent : true,
- dontAnimate : restoringMultipleTabs
- };
- let childTabs = this._restoreChildTabsRelation(aTab, children, mayBeDuplicated, options);
-
- this._restoreTabPositionAndIndent(aTab, childTabs, mayBeDuplicated);
-
- if (closeSetId)
- this.restoreClosedSet(closeSetId, aTab);
-
- if (isSubtreeCollapsed)
- this.collapseExpandSubtree(aTab, isSubtreeCollapsed);
- }
-
- if (mayBeDuplicated) {
- this.clearRedirectionTableWithDelay();
- this.clearRedirectbTabRelationsWithDelay(aTab);
- }
-
- delete aTab.__treestyletab__restoreState;
- },
-
- _restoreTabId : function TSTBrowser_restoreTabId(aTab)
- {
- // kID can be overridden by nsSessionStore. kID_NEW is for failsafe.
- var currentId = aTab.getAttribute(this.kID_NEW) || aTab.getAttribute(this.kID);
- aTab.removeAttribute(this.kID_NEW);
- var restoredId = this.getTabValue(aTab, this.kID);
- var mayBeDuplicated = false;
-
- aTab.setAttribute(this.kID_RESTORING, restoredId);
- if (this.isTabDuplicated(aTab)) {
- mayBeDuplicated = true;
- /**
- * If the tab has its ID as the attribute, then we should use it
- * instead of redirected ID, because the tab has been possibly
- * attached to another tab.
- */
- restoredId = currentId || this.redirectId(restoredId);
- }
- aTab.removeAttribute(this.kID_RESTORING);
-
- return [restoredId || currentId, mayBeDuplicated];
- },
-
- _getCloseSetId : function TSTBrowser_getCloseSetId(aTab, aMayBeDuplicated)
- {
- var closeSetId = null;
- if (!aMayBeDuplicated) {
- closeSetId = this.getTabValue(aTab, this.kCLOSED_SET_ID);
- /**
- * If the tab is not a duplicated but it has a parent, then,
- * it is wrongly attacched by tab moving on restoring.
- * Restoring the old ID (the next statement) breaks the children
- * list of the temporary parent and causes many problems.
- * So, to prevent these problems, I detach the tab from the temporary
- * parent manually.
- * If the ID stored in the session equals to the value of the
- * attribute stored in the element itself, then don't reset the
- * tab, because the restoring session is got from the tab itself.
- * ( like SS.setTabState(tab, SS.getTabState(tab)) )
- */
- if (this.getTabValue(aTab, this.kID) != aTab.getAttribute(this.kID))
- this.resetTab(aTab, false);
- }
- this.deleteTabValue(aTab, this.kCLOSED_SET_ID);
- return closeSetId;
- },
-
- _fixMissingAttributesFromSessionData : function TSTBrowser_fixMissingAttributesFromSessionData(aTab)
- {
- /**
- * By some reasons (ex. persistTabAttribute()), actual state of
- * the tab (attributes) can be lost on SSTabRestoring.
- * For failsafe, we must override actual attributes by stored
- * values.
- */
- var keys = [
- this.kINSERT_BEFORE,
- this.kINSERT_AFTER
- ];
- for (let i = 0, maxi = keys.length; i < maxi; i++)
- {
- let key = keys[i];
- let tab = this.getTabValue(aTab, key);
- if (this.getTabById(tab))
- this.setTabValue(aTab, key, tab);
- }
-
- let parentId = this.getTabValue(aTab, this.kPARENT);
- let parentTab = this.getTabById(parentId);
- if (parentTab && parentTab._tPos < aTab._tPos)
- this.setTabValue(aTab, this.kPARENT, parentId);
- else
- this.deleteTabValue(aTab, this.kPARENT);
-
- let ancestors = [aTab].concat(this.getAncestorTabs(aTab));
- let children = this.getTabValue(aTab, this.kCHILDREN);
- children = children.split('|').filter(function(aChild) {
- let tab = this.getTabById(aChild);
- return tab && ancestors.indexOf(tab) < 0;
- }, this);
- this.setTabValue(aTab, this.kCHILDREN, children.join('|'));
-
- let subtreeCollapsed = this.getTabValue(aTab, this.kSUBTREE_COLLAPSED);
- if (subtreeCollapsed != aTab.getAttribute(this.kSUBTREE_COLLAPSED))
- this.collapseExpandSubtree(aTab, subtreeCollapsed == 'true', true);
- },
-
- _restoreSubtreeCollapsedState : function TSTBrowser_restoreSubtreeCollapsedState(aTab, aCollapsed)
- {
- var shouldCollapse = utils.getTreePref('collapseExpandSubtree.sessionRestore');
-
- if (aCollapsed === void(0))
- aCollapsed = this.getTabValue(aTab, this.kSUBTREE_COLLAPSED) == 'true';
-
- var isSubtreeCollapsed = (
- this.windowService.restoringTree &&
- (
- shouldCollapse == this.RESTORED_TREE_COLLAPSED_STATE_LAST_STATE ?
- aCollapsed :
- shouldCollapse == this.RESTORED_TREE_COLLAPSED_STATE_COLLAPSED
- )
- );
- this.setTabValue(aTab, this.kSUBTREE_COLLAPSED, isSubtreeCollapsed);
- return isSubtreeCollapsed;
- },
-
- _restoreChildTabsRelation : function TSTBrowser_restoreChildTabsRelation(aTab, aChildrenList, aMayBeDuplicated, aOptions)
- {
- var childTabs = [];
- if (!aChildrenList)
- return childTabs;
-
- aTab.removeAttribute(this.kCHILDREN);
-
- aChildrenList = aChildrenList.split('|');
- if (aMayBeDuplicated)
- aChildrenList = aChildrenList.map(function(aChild) {
- return this.redirectId(aChild);
- }, this);
-
- for (let i = 0, maxi = aChildrenList.length; i < maxi; i++)
- {
- let childTab = aChildrenList[i];
- if (childTab && (childTab = this.getTabById(childTab))) {
- let options = aOptions;
- if (options && typeof options == 'function')
- options = options(childTab);
- this.attachTabTo(childTab, aTab, options);
- childTabs.push(childTab);
- }
- }
- aChildrenList = aChildrenList.join('|');
- if (aTab.getAttribute(this.kCHILDREN) == aChildrenList)
- aTab.removeAttribute(this.kCHILDREN_RESTORING);
- else
- aTab.setAttribute(this.kCHILDREN_RESTORING, aChildrenList);
-
- return childTabs;
- },
-
- _restoreTabPositionAndIndent : function TSTBrowser_restoreTabPositionAndIndent(aTab, aChildTabs, aMayBeDuplicated)
- {
- var restoringMultipleTabs = this.windowService.restoringTree;
- var position = this._prepareInsertionPosition(aTab, aMayBeDuplicated);
- var parent = position.parent;
- if (DEBUG)
- dump('handleRestoredTab: found parent = ' + parent+'\n');
- if (parent) {
- aTab.removeAttribute(this.kPARENT);
- parent = this.getTabById(parent);
- if (parent) {
- this.attachTabTo(aTab, parent, {
- dontExpand : restoringMultipleTabs,
- insertBefore : position.next,
- dontUpdateIndent : true,
- dontAnimate : restoringMultipleTabs
- });
- this.updateTabsIndent([aTab], undefined, restoringMultipleTabs);
- this.checkTabsIndentOverflow();
-
- if (parent.getAttribute(this.kCHILDREN_RESTORING))
- this.correctChildTabsOrderWithDelay(parent);
- }
- else {
- this.deleteTabValue(aTab, this.kPARENT);
- }
- }
- else {
- if (aChildTabs.length) {
- this.updateTabsIndent(aChildTabs, undefined, restoringMultipleTabs);
- this.checkTabsIndentOverflow();
- }
- this._restoreTabPosition(aTab, position.next);
- }
- },
-
- _prepareInsertionPosition : function TSTBrowser_prepareInsertionPosition(aTab, aMayBeDuplicated)
- {
- var next = this.getTabValue(aTab, this.kINSERT_BEFORE);
- if (next && aMayBeDuplicated)
- next = this.redirectId(next);
- next = this.getTabById(next);
-
- if (!next) {
- let prev = this.getTabValue(aTab, this.kINSERT_AFTER);
- if (prev && aMayBeDuplicated)
- prev = this.redirectId(prev);
- prev = this.getTabById(prev);
- next = this.getNextSiblingTab(prev);
- }
-
- var ancestors = (this.getTabValue(aTab, this.kANCESTOR) || this.getTabValue(aTab, this.kPARENT)).split('|');
- if (DEBUG)
- dump('handleRestoredTab: ancestors = ' + ancestors+'\n');
- var parent = null;
- for (let i in ancestors)
- {
- if (aMayBeDuplicated)
- ancestors[i] = this.redirectId(ancestors[i]);
- parent = this.getTabById(ancestors[i]);
- if (parent) {
- parent = ancestors[i];
- break;
- }
- }
- this.deleteTabValue(aTab, this.kANCESTOR);
-
- /**
- * If the tab is a duplicated and the tab has already been
- * attached, then reuse current status based on attributes.
- * (Note, if the tab is not a duplicated tab, all attributes
- * have been cleared.)
- */
- if (!parent) {
- parent = aTab.getAttribute(this.kPARENT);
- if (DEBUG)
- dump('handleRestoredTab: parent = ' + parent+'\n');
- if (parent && !next)
- next = this.getNextSiblingTab(aTab);
- }
-
- return {
- parent : parent,
- next : next
- };
- },
-
- _restoreTabPosition : function TSTBrowser_restoreTabPosition(aTab, aNextTab)
- {
- if (!aNextTab)
- aNextTab = this.getNextTab(aTab);
- var parentOfNext = this.getParentTab(aNextTab);
- var newPos = -1;
- if (parentOfNext) {
- let descendants = this.getDescendantTabs(parentOfNext);
- if (descendants.length)
- newPos = descendants[descendants.length-1]._tPos;
- }
- else if (aNextTab) {
- newPos = aNextTab._tPos;
- if (newPos > aTab._tPos)
- newPos--;
- }
- if (newPos > -1)
- this.mTabBrowser.moveTabTo(aTab, newPos);
- },
-
- correctChildTabsOrderWithDelay : function TSTBrowser_correctChildTabsOrderWithDelay(aTab)
- {
- if (aTab.correctChildTabsOrderWithDelayTimer)
- this.window.clearTimeout(aTab.correctChildTabsOrderWithDelayTimer);
-
- aTab.correctChildTabsOrderWithDelayTimer = this.window.setTimeout(function(aSelf) {
- aSelf.correctChildTabsOrder(aTab);
- }, 10, this);
- },
-
- correctChildTabsOrder : function TSTBrowser_correctChildTabsOrder(aTab)
- {
- if (!aTab.parentNode) // do nothing for closed tab!
- return;
-
- var restoringChildren = aTab.getAttribute(this.kCHILDREN_RESTORING);
- if (!restoringChildren) return;
-
- var children = aTab.getAttribute(this.kCHILDREN);
- if (restoringChildren != children) {
- var restoringChildrenIDs = restoringChildren.split('|').reverse();
- for (let i = 0, maxi = restoringChildrenIDs.length; i < maxi; i++)
- {
- let child = this.getTabById(restoringChildrenIDs[i]);
- if (!child)
- continue;
-
- let nextTab = i > 0 ?
- this.getTabById(restoringChildrenIDs[i-1]) :
- this.getNextSiblingTab(aTab) ;
- if (nextTab == this.getNextSiblingTab(child))
- continue;
-
- let newPos = -1;
- if (nextTab) {
- newPos = nextTab._tPos;
- if (newPos > child._tPos)
- newPos--;
- }
- if (newPos > -1)
- this.moveTabSubtreeTo(child, newPos);
- }
- children = aTab.getAttribute(this.kCHILDREN);
- }
-
- if (restoringChildren == children)
- aTab.removeAttribute(this.kCHILDREN_RESTORING);
-
- aTab.correctChildTabsOrderWithDelayTimer = null;
- },
-
- redirectId : function TSTBrowser_redirectId(aId)
- {
- if (!(aId in this._redirectionTable))
- this._redirectionTable[aId] = this.makeNewId();
- return this._redirectionTable[aId];
- },
- _redirectionTable : {},
-
- clearRedirectionTableWithDelay : function TSTBrowser_clearRedirectionTableWithDelay()
- {
- if (this._clearRedirectionTableTimer) {
- this.window.clearTimeout(this._clearRedirectionTableTimer);
- this._clearRedirectionTableTimer = null;
- }
- this._clearRedirectionTableTimer = this.window.setTimeout(function(aSelf) {
- aSelf._redirectionTable = {};
- }, 1000, this);
- },
- _clearRedirectionTableTimer : null,
-
- clearRedirectbTabRelationsWithDelay : function TSTBrowser_clearRedirectbTabRelationsWithDelay(aTab)
- {
- if (aTab._clearRedirectbTabRelationsTimer) {
- this.window.clearTimeout(aTab._clearRedirectbTabRelationsTimer);
- aTab._clearRedirectbTabRelationsTimer = null;
- }
- aTab._clearRedirectbTabRelationsTimer = this.window.setTimeout(function(aSelf) {
- aSelf.clearRedirectbTabRelations(aTab);
- delete aTab._clearRedirectbTabRelationsTimer;
- }, 1500, this);
- },
- clearRedirectbTabRelations : function TSTBrowser_clearRedirectbTabRelations(aTab)
- {
- if (!aTab || !aTab.parentNode)
- return;
-
- var redirectingIds = Object.keys(this._redirectionTable).map(function(aId) {
- return this._redirectionTable[aId];
- }, this);
- var existingIds = this.getAllTabs(this.mTabBrowser).map(function(aTab) {
- return this.getTabValue(aTab, this.kID);
- }, this);
- var validIds = redirectingIds.concat(existingIds);
- validIds = validIds.filter(function(aId) {
- return !!aId;
- });
-
- var ancestors = this.getTabValue(aTab, this.kANCESTORS);
- if (ancestors) {
- ancestors = ancestors.split('|');
- let actualAncestors = this.getAncestorTabs(aTab).map(function(aTab) {
- return aTab.getAttribute(this.kID);
- }, this);
- ancestors = ancestors.filter(function(aAncestor) {
- if (actualAncestors.indexOf(aAncestor) < 0)
- return false;
- else
- return validIds.indexOf(aAncestor) > -1;
- }, this);
- if (ancestors.length)
- this.setTabValue(aTab, this.kANCESTORS, ancestors.join('|'));
- else
- this.deleteTabValue(aTab, this.kANCESTORS);
- }
-
- var children = this.getTabValue(aTab, this.kCHILDREN);
- if (children) {
- children = children.split('|');
- children = children.filter(function(aChild) {
- if (this.getParentTab(this.getTabById(aChild)) != aTab)
- return false;
- else
- return validIds.indexOf(aChild) > -1;
- }, this);
- if (children.length)
- this.setTabValue(aTab, this.kCHILDREN, children.join('|'));
- else
- this.deleteTabValue(aTab, this.kCHILDREN);
- }
-
- var restoringChildren = aTab.getAttribute(this.kCHILDREN_RESTORING);
- if (restoringChildren) {
- restoringChildren = restoringChildren.split('|');
- restoringChildren = restoringChildren.filter(function(aChild) {
- return validIds.indexOf(aChild) > -1;
- }, this);
- if (restoringChildren.length)
- aTab.setAttribute(this.kCHILDREN_RESTORING, restoringChildren.join('|'));
- else
- aTab.removeAttribute(this.kCHILDREN_RESTORING);
- }
- },
-
- restoreClosedSet : function TSTBrowser_restoreClosedSet(aId, aRestoredTab)
- {
- var behavior = this.undoCloseTabSetBehavior;
- if (
- aRestoredTab.__treestyletab__restoredByUndoCloseTab ||
- !this.browser.__treestyletab__readyToUndoCloseTab ||
- this.useTMPSessionAPI ||
- this._restoringClosedSet ||
- !(behavior & this.kUNDO_CLOSE_SET || behavior & this.kUNDO_ASK)
- )
- return;
-
- var indexes = [];
- var items = utils.evalInSandbox('('+this.SessionStore.getClosedTabData(this.window)+')');
- for (let i = 0, maxi = items.length; i < maxi; i++)
- {
- let item = items[i];
- if (item.state.extData &&
- item.state.extData[this.kCLOSED_SET_ID] &&
- item.state.extData[this.kCLOSED_SET_ID] == aId)
- indexes.push(i);
- }
-
- var count = parseInt(aId.split('::')[1]);
-
- if (
- !indexes.length ||
- (
- indexes.length+1 < count &&
- behavior & this.kUNDO_CLOSE_FULL_SET
- )
- )
- return;
-
- if (behavior & this.kUNDO_ASK) {
- let self = this;
- aRestoredTab.addEventListener('SSTabRestoring', function onSSTabRestoring(aEvent) {
- aRestoredTab.removeEventListener(aEvent.type, onSSTabRestoring, false);
- self.askUndoCloseTabSetBehavior(aRestoredTab, indexes.length)
- .next(function(aBehavior) {
- if (aBehavior & self.kUNDO_CLOSE_SET)
- self.doRestoreClosedSet(aRestoredTab, indexes);
- });
- }, false);
- }
- else if (behavior & this.kUNDO_CLOSE_SET) {
- this.doRestoreClosedSet(aRestoredTab, indexes);
- }
- },
-
- doRestoreClosedSet : function TSTBrowser_doRestoreClosedSet(aRestoredTab, aIndexes)
- {
- if (!this.window.PlacesUIUtils._confirmOpenInTabs(aIndexes.length))
- return;
-
- this._restoringClosedSet = true;
- this.stopRendering();
-
- this.windowService.restoringTree = true;
-
- var offset = 0;
- for (let i = 0, maxi = aIndexes.length; i < maxi; i++)
- {
- this.window.undoCloseTab(aIndexes[i] - (offset++));
- }
-
- this.window.setTimeout(function(aSelf, aNextFocused) {
- aSelf.windowService.restoringTree = false;
- aSelf.mTabBrowser.selectedTab = aNextFocused;
- }, 0, this, aRestoredTab || aSelf.mTabBrowser.selectedTab);
-
- this.startRendering();
- this._restoringClosedSet = false;
- },
- _restoringClosedSet : false,
-
- onTabRestored : function TSTBrowser_onTabRestored(aEvent)
- {
- delete aEvent.originalTarget.__treestyletab__restoredByUndoCloseTab;
- },
-
- onTabPinned : function TSTBrowser_onTabPinned(aTab)
- {
- var parentTab = this.getParentTab(aTab);
-
- this.collapseExpandSubtree(aTab, false);
-
- /**
- * Children of the newly pinned tab are possibly
- * moved to the top of the tab bar, by TabMove event
- * from the newly pinned tab. So, we have to
- * reposition unexpectedly moved children.
- */
- if (!parentTab) {
- /**
- * Universal but dangerous logic. "__treestyletab__previousPosition"
- * can be broken by multiple movings.
- */
- let b = this.browser;
- this.internallyTabMovingCount++;
- let children = this.getDescendantTabs(aTab).reverse();
- for (let i = 0, maxi = children.length; i < maxi; i++)
- {
- let childTab = children[i];
- if (childTab.__treestyletab__previousPosition > childTab._tPos)
- b.moveTabTo(childTab, childTab.__treestyletab__previousPosition);
- }
- this.internallyTabMovingCount--;
- }
- else {
- /**
- * Safer logic. This cannot be available for "root" tabs because
- * their children (already moved) have no way to know the anchor
- * position (the next sibling of the pinned tab itself).
- */
- let b = this.browser;
- this.internallyTabMovingCount++;
- let children = this.getChildTabs(aTab).reverse();
- for (let i = 0, maxi = children.length; i < maxi; i++)
- {
- let childTab = children[i];
- if (childTab._tPos < parentTab._tPos)
- b.moveTabTo(childTab, parentTab._tPos);
- }
- this.internallyTabMovingCount--;
- }
-
- this.detachAllChildren(aTab, {
- behavior : this.getCloseParentBehaviorForTab(
- aTab,
- this.kCLOSE_PARENT_BEHAVIOR_PROMOTE_FIRST_CHILD
- )
- });
- this.detachTab(aTab);
-
- this.collapseExpandTab(aTab, false);
- if (this.isVertical)
- this.positionPinnedTabsWithDelay();
- },
-
- onTabUnpinned : function TSTBrowser_onTabUnpinned(aTab)
- {
- var style = aTab.style;
- style.marginLeft = style.marginRight = style.marginTop = '';
-
- this.updateInvertedTabContentsOrder(aTab);
- if (this.isVertical)
- this.positionPinnedTabsWithDelay();
- },
-
- onTabSelect : function TSTBrowser_onTabSelect(aEvent)
- {
- var b = this.mTabBrowser;
- var tab = b.selectedTab
-
- this.cancelDelayedExpandOnTabSelect();
-
- if (
- /**
- * .previewTab() focuses to the tab internally,
- * so we should ignore this event if it is fired from previewTab().
- */
- b._previewMode ||
- /**
- * Ignore selected tabs which is being closed. For example,
- * when a collapsed tree is closed, Firefox unexpectedly gives
- * focus to a collapsed child in the tree.
- */
- (b._removingTabs && b._removingTabs.indexOf(tab) > -1)
- )
- return;
-
- var shouldCollapseExpandNow = utils.getTreePref('autoCollapseExpandSubtreeOnSelect');
- var newActiveTabOptions = {
- canCollapseTree : shouldCollapseExpandNow,
- canExpandTree : shouldCollapseExpandNow
- };
- if (this.isCollapsed(tab)) {
- if (utils.getTreePref('autoExpandSubtreeOnCollapsedChildFocused')) {
- this.getAncestorTabs(tab).forEach(function(aAncestor) {
- this.collapseExpandSubtree(aAncestor, false);
- }, this);
- this.handleNewActiveTab(tab, newActiveTabOptions);
- }
- else {
- b.selectedTab = this.getRootTab(tab);
- }
- }
- else if (
- (
- /**
- * Focus movings by arrow keys should not be handled on TabSelect,
- * because they are already handled by handleAdvanceSelectedTab().
- */
- this.windowService.arrowKeyEventOnTab &&
- this.windowService.arrowKeyEventOnTab.advanceFocus
- ) ||
- (
- /**
- * Focus movings by closing of the old current tab should be handled
- * only when it is activated by user preference expressly.
- */
- this._focusChangedByCurrentTabRemove &&
- !utils.getTreePref('autoCollapseExpandSubtreeOnSelect.onCurrentTabRemove')
- )
- ) {
- // do nothing!
- }
- else if (this.hasChildTabs(tab) && this.isSubtreeCollapsed(tab)) {
- if (
- this._focusChangedByShortcut &&
- this.windowService.accelKeyPressed
- ) {
- if (utils.getTreePref('autoExpandSubtreeOnSelect.whileFocusMovingByShortcut')) {
- newActiveTabOptions.canExpandTree = true;
- newActiveTabOptions.canCollapseTree = (
- newActiveTabOptions.canCollapseTree &&
- utils.getTreePref('autoExpandSubtreeOnSelect.whileFocusMovingByShortcut.collapseOthers')
- );
- let delay = utils.getTreePref('autoExpandSubtreeOnSelect.whileFocusMovingByShortcut.delay');
- if (delay > 0) {
- this._autoExpandOnTabSelectTimer = this.window.setTimeout(function(aSelf) {
- if (tab && tab.parentNode)
- aSelf.handleNewActiveTab(tab, newActiveTabOptions);
- }, delay, this);
- }
- else {
- this.handleNewActiveTab(tab, newActiveTabOptions);
- }
- }
- else if (newActiveTabOptions.canExpandTree) {
- this.windowService.expandTreeAfterKeyReleased(tab);
- }
- }
- else {
- this.handleNewActiveTab(tab, newActiveTabOptions);
- }
- }
-
- this._focusChangedByCurrentTabRemove = false;
- this._focusChangedByShortcut = false;
-
- this.updateInvertedTabContentsOrder();
-
- if (!this.isTabInViewport(tab)) {
- this.scrollToTab(tab);
- aEvent.stopPropagation();
- }
- },
- cancelDelayedExpandOnTabSelect : function TSTBrowser_cancelDelayedExpandOnTabSelect() {
- if (this._autoExpandOnTabSelectTimer) {
- this.window.clearTimeout(this._autoExpandOnTabSelectTimer);
- this._autoExpandOnTabSelectTimer = null;
- }
- },
- handleNewActiveTab : function TSTBrowser_handleNewActiveTab(aTab, aOptions)
- {
- if (this.doingCollapseExpand || !aTab || !aTab.parentNode)
- return;
-
- aOptions = aOptions || {};
-
- if (this._handleNewActiveTabTimer)
- this.window.clearTimeout(this._handleNewActiveTabTimer);
-
- /**
- * First, we wait until all event listeners for the TabSelect
- * event were processed.
- */
- this._handleNewActiveTabTimer = this.window.setTimeout(function(aSelf) {
- aSelf.window.clearTimeout(aSelf._handleNewActiveTabTimer);
- aSelf._handleNewActiveTabTimer = null;
-
- if (aOptions.canExpandTree) {
- if (aOptions.canCollapseTree &&
- utils.getTreePref('autoExpand.intelligently'))
- aSelf.collapseExpandTreesIntelligentlyFor(aTab);
- else
- aSelf.collapseExpandSubtree(aTab, false);
- }
- }, 0, this);
- },
- _handleNewActiveTabTimer : null,
-
- handleAdvanceSelectedTab : function TSTBrowser_handleAdvanceSelectedTab(aDir, aWrap)
- {
- this._focusChangedByShortcut = this.windowService.accelKeyPressed;
-
- if (!this.canCollapseSubtree(this.mTabBrowser.selectedTab) ||
- utils.getTreePref('focusMode') != this.kFOCUS_VISIBLE)
- return false;
-
- if (this.processArrowKeyOnFocusAdvanced())
- return true;
-
- return this.advanceSelectedTab(aDir, aWrap);
- },
-
- processArrowKeyOnFocusAdvanced : function TSTBrowser_processArrowKeyOnFocusAdvanced()
- {
- var event = this.windowService.arrowKeyEventOnTab;
- if (!event)
- return false;
-
- if (
- event.altKey ||
- event.ctrlKey ||
- event.metaKey ||
- event.shiftKey ||
- (this.isVertical ? (event.up || event.down) : (event.left || event.right))
- ) {
- event.advanceFocus = true;
- return false;
- }
-
- var collapse, expand;
- switch (this.position)
- {
- case 'top':
- collapse = event.up;
- expand = event.down;
- break;
-
- case 'bottom':
- collapse = event.down;
- expand = event.up;
- break;
-
- case 'left':
- collapse = event.left;
- expand = event.right;
- break;
-
- case 'right':
- if (utils.getTreePref('tabbar.invertTab')) {
- collapse = event.right;
- expand = event.left;
- }
- else {
- collapse = event.left;
- expand = event.right;
- }
- break;
- }
-
- var tab = this.mTabBrowser.selectedTab;
-
- var collapsed = this.isSubtreeCollapsed(tab);
- if (this.hasChildTabs(tab) && (collapsed ? expand : collapse )) {
- event.collapse = collapse;
- event.expand = expand;
- this.collapseExpandSubtree(tab, !collapsed);
- return true;
- }
-
- var nextSelected;
- if (expand)
- nextSelected = this.getFirstChildTab(tab);
- else if (collapse)
- nextSelected = this.getParentTab(tab);
-
- if (nextSelected) {
- event.advanceFocus = true;
- this.mTabBrowser.selectedTab = nextSelected;
- return true;
- }
-
- return true;
- },
-
- advanceSelectedTab : function TSTBrowser_advanceSelectedTab(aDir, aWrap)
- {
- var tab = this.mTabBrowser.selectedTab;
- var tabbar = this.mTabBrowser.mTabContainer;
-
- var nextTab = (aDir < 0) ? this.getPreviousVisibleTab(tab) : this.getNextVisibleTab(tab) ;
- if (!nextTab && aWrap) {
- let tabs = tabbar.querySelectorAll('tab:not(['+this.kCOLLAPSED+'="true"])');
- nextTab = tabs[aDir < 0 ? tabs.length-1 : 0 ];
- }
- if (nextTab && nextTab != tab)
- tabbar._selectNewTab(nextTab, aDir, aWrap);
-
- return true;
- },
-
- onTabClick : function TSTBrowser_onTabClick(aEvent, aTab)
- {
- aTab = aTab || this.getTabFromEvent(aEvent);
-
- if (aEvent.button == 1) {
- if (!this.warnAboutClosingTabSubtreeOf(aTab)) {
- aEvent.preventDefault();
- aEvent.stopPropagation();
- }
- return;
- }
-
- if (aEvent.button != 0)
- return;
-
- if (this.isEventFiredOnTwisty(aEvent)) {
- if (this.hasChildTabs(aTab) && this.canCollapseSubtree(aTab)) {
- this.manualCollapseExpandSubtree(aTab, aTab.getAttribute(this.kSUBTREE_COLLAPSED) != 'true');
- aEvent.preventDefault();
- aEvent.stopPropagation();
- }
- return;
- }
-
- if (this.isEventFiredOnClosebox(aEvent)) {
- if (!this.warnAboutClosingTabSubtreeOf(aTab)) {
- aEvent.preventDefault();
- aEvent.stopPropagation();
- }
- return;
- }
- },
-
- onClick : function TSTBrowser_onClick(aEvent)
- {
- if (
- aEvent.target.ownerDocument != this.document ||
- aEvent.button != 0 ||
- this.isAccelKeyPressed(aEvent)
- )
- return;
-
- var tab = this.getTabFromEvent(aEvent);
- if (tab) {
- this.onTabClick(aEvent, tab);
- }
- else {
- // click on indented space on the tab bar
- tab = this.getTabFromTabbarEvent(aEvent);
- if (tab)
- this.mTabBrowser.selectedTab = tab;
- }
- },
-
- onDblClick : function TSTBrowser_onDblClick(aEvent)
- {
- let tab = this.getTabFromEvent(aEvent);
- if (tab &&
- this.hasChildTabs(tab) &&
- utils.getTreePref('collapseExpandSubtree.dblclick')) {
- this.manualCollapseExpandSubtree(tab, tab.getAttribute(this.kSUBTREE_COLLAPSED) != 'true');
- aEvent.preventDefault();
- aEvent.stopPropagation();
- }
- },
-
- onMozMouseHittest : function TSTBrowser_onMozMouseHittest(aEvent)
- {
- // block default behaviors of the tab bar (dragging => window move, etc.)
- if (
- !this.getTabFromEvent(aEvent) &&
- !this.isEventFiredOnClickable(aEvent) &&
- (
- this.position != 'top' ||
- aEvent.shiftKey ||
- this.tabbarDNDObserver.canDragTabbar(aEvent)
- )
- )
- aEvent.stopPropagation();
- },
-
- onMouseDown : function TSTBrowser_onMouseDown(aEvent)
- {
- if (this.isEventFiredOnScrollbar(aEvent))
- this.cancelPerformingAutoScroll();
-
- if (
- aEvent.button == 0 &&
- this.isEventFiredOnTwisty(aEvent)
- ) {
- // prevent to select the tab for clicking on twisty
- aEvent.stopPropagation();
- // prevent to focus to the tab element itself
- aEvent.preventDefault();
- }
- else {
- this.onMozMouseHittest(aEvent);
- }
- },
-
- onDOMMouseScroll : function TSTBrowser_onDOMMouseScroll(aEvent)
- {
- this.cancelPerformingAutoScroll();
- },
-
- onScroll : function TSTBrowser_onScroll(aEvent)
- {
- // restore scroll position when a tab is closed.
- this.restoreLastScrollPosition();
- },
-
- onTabbarOverflow : function TSTBrowser_onTabbarOverflow(aEvent)
- {
- var tabs = this.mTabBrowser.mTabContainer;
- var horizontal = tabs.orient == 'horizontal';
- if (horizontal)
- return;
- aEvent.stopPropagation();
- this.positionPinnedTabsWithDelay();
- if (aEvent.detail == 1) {
- /**
- * By horizontal overflow/underflow, Firefox can wrongly
- * removes "overflow" attribute for vertical tab bar.
- * We have to override the result.
- */
- this.updateTabbarOverflow();
- }
- else {
- if (aEvent.type == 'overflow') {
- tabs.setAttribute('overflow', 'true');
- this.scrollBoxObject.ensureElementIsVisible(tabs.selectedItem);
- }
- else {
- tabs.removeAttribute('overflow');
- }
- }
- },
-
- onResize : function TSTBrowser_onResize(aEvent)
- {
- if (
- !aEvent.originalTarget ||
- !(aEvent.originalTarget instanceof Ci.nsIDOMWindow)
- )
- return;
-
- var resizedTopFrame = aEvent.originalTarget.top;
- var isContentResize = resizedTopFrame == this.mTabBrowser.contentWindow;
- var isChromeResize = resizedTopFrame == this.window;
-
- if (isChromeResize && aEvent.originalTarget != resizedTopFrame) {
- // ignore resizing of sub frames in "position:fixed" box
- let target = aEvent.target;
- try {
- let node = target.QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIWebNavigation)
- .QueryInterface(Ci.nsIDocShell)
- .chromeEventHandler;
- let root = node.ownerDocument.documentElement;
- while (node && node != root) {
- if (node.boxObject && !node.boxObject.parentBox) {
- isChromeResize = false;
- break;
- }
- node = node.parentNode;
- }
- }
- catch(e) {
- }
- }
-
- // Ignore events when a background tab raises to the foreground.
- if (isContentResize && this._lastTabbarPlaceholderSize) {
- let newSize = this.getTabbarPlaceholderSize();
- isContentResize =
- newSize.width != this._lastTabbarPlaceholderSize.width ||
- newSize.height != this._lastTabbarPlaceholderSize.height;
- }
-
- if (isContentResize || isChromeResize) {
- this.updateFloatingTabbar(this.kTABBAR_UPDATE_BY_WINDOW_RESIZE);
- this.updateInvertedTabContentsOrder(true);
- this.mTabBrowser.mTabContainer.adjustTabstrip();
- }
- },
-
- onPopupShowing : function TSTBrowser_onPopupShowing(aEvent)
- {
- if (aEvent.target == aEvent.currentTarget)
- this.initTabContextMenu(aEvent);
- },
-
- initTabContextMenu : function TSTBrowser_initTabContextMenu(aEvent)
- {
- var b = this.mTabBrowser;
- var sep, items = {};
-
- var ids = [
- this.kMENUITEM_RELOADSUBTREE,
- this.kMENUITEM_RELOADCHILDREN,
- this.kMENUITEM_REMOVESUBTREE,
- this.kMENUITEM_REMOVECHILDREN,
- this.kMENUITEM_REMOVEALLTABSBUT,
- this.kMENUITEM_COLLAPSE,
- this.kMENUITEM_EXPAND,
- this.kMENUITEM_AUTOHIDE,
- this.kMENUITEM_FIXED,
- this.kMENUITEM_BOOKMARKSUBTREE
- ];
- for (let i = 0, maxi = ids.length; i < maxi; i++)
- {
- let id = ids[i];
- let item = aEvent.currentTarget.querySelector('*[id^="'+id+'"]');
- if (!item)
- continue;
- items[id] = item;
- if (utils.getTreePref('show.'+id))
- item.removeAttribute('hidden');
- else
- item.setAttribute('hidden', true);
- switch (id)
- {
- case this.kMENUITEM_RELOADSUBTREE:
- case this.kMENUITEM_RELOADCHILDREN:
- case this.kMENUITEM_REMOVESUBTREE:
- case this.kMENUITEM_REMOVECHILDREN:
- case this.kMENUITEM_REMOVEALLTABSBUT:
- case this.kMENUITEM_COLLAPSE:
- case this.kMENUITEM_EXPAND:
- case this.kMENUITEM_BOOKMARKSUBTREE:
- this.showHideSubtreeMenuItem(item, [b.mContextTab]);
- continue;
- default:
- continue;
- }
- }
-
- // collapse/expand all
- sep = aEvent.currentTarget.querySelector('menuseparator[id^="'+this.kMENUITEM_COLLAPSEEXPAND_SEPARATOR+'"]');
- let collapseItem = items[this.kMENUITEM_COLLAPSE];
- let expandItem = items[this.kMENUITEM_EXPAND];
- if (this.canCollapseSubtree(b) &&
- b.mTabContainer.querySelector('tab['+this.kCHILDREN+']')) {
- if (collapseItem) {
- if (b.mTabContainer.querySelector('tab['+this.kCHILDREN+']:not(['+this.kSUBTREE_COLLAPSED+'="true"])'))
- collapseItem.removeAttribute('disabled');
- else
- collapseItem.setAttribute('disabled', true);
- }
-
- if (expandItem) {
- if (b.mTabContainer.querySelector('tab['+this.kCHILDREN+']['+this.kSUBTREE_COLLAPSED+'="true"]'))
- expandItem.removeAttribute('disabled');
- else
- expandItem.setAttribute('disabled', true);
- }
- }
- else {
- if (collapseItem)
- collapseItem.setAttribute('hidden', true);
- if (expandItem)
- expandItem.setAttribute('hidden', true);
- }
- if (sep) {
- if (
- (!collapseItem || collapseItem.getAttribute('hidden') == 'true') &&
- (!expandItem || expandItem.getAttribute('hidden') == 'true')
- ) {
- sep.setAttribute('hidden', true);
- }
- else {
- sep.removeAttribute('hidden');
- }
- }
-
- // close all tabs but this tree
- let removeAllTabsBut = items[this.kMENUITEM_REMOVEALLTABSBUT];
- if (removeAllTabsBut) {
- let rootTabs = this.visibleRootTabs;
- if (rootTabs.length == 1 && rootTabs[0] == b.mContextTab)
- removeAllTabsBut.setAttribute('disabled', true);
- else
- removeAllTabsBut.removeAttribute('disabled');
- }
-
- // auto hide
- let autohide = items[this.kMENUITEM_AUTOHIDE];
- if (autohide)
- this.autoHide.updateMenuItem(autohide);
-
- // fix
- let fixedPref;
- let fixedLabel;
- if (this.isVertical) {
- fixedPref = b.getAttribute(this.kFIXED+'-vertical') == 'true';
- fixedLabel = 'label-vertical';
- }
- else {
- fixedPref = b.getAttribute(this.kFIXED+'-horizontal') == 'true';
- fixedLabel = 'label-horizontal';
- }
- let fixed = items[this.kMENUITEM_FIXED];
- if (fixed) {
- fixed.setAttribute('label', fixed.getAttribute(fixedLabel));
- if (fixedPref)
- fixed.setAttribute('checked', true);
- else
- fixed.removeAttribute('checked');
- }
-
- sep = aEvent.currentTarget.querySelector('menuseparator[id^="'+this.kMENUITEM_AUTOHIDE_SEPARATOR+'"]');
- if (sep) {
- if (
- (autohide && autohide.getAttribute('hidden') != 'true') ||
- (fixed && fixed.getAttribute('hidden') != 'true')
- ) {
- sep.removeAttribute('hidden');
- }
- else {
- sep.setAttribute('hidden', true);
- }
- }
-
- let closeTabsToEnd = aEvent.currentTarget.querySelector('*[id^="'+this.kMENUITEM_CLOSE_TABS_TO_END+'"]');
- if (closeTabsToEnd) { // https://bugzilla.mozilla.org/show_bug.cgi?id=866880
- let label, accesskey;
- if (this.isVertical) {
- label = utils.treeBundle.getString('closeTabsToTheEnd_vertical_label');
- accesskey = utils.treeBundle.getString('closeTabsToTheEnd_vertical_accesskey');
- }
- else {
- label = this._closeTabsToEnd_horizontalLabel;
- accesskey = this._closeTabsToEnd_horizontalAccesskey;
- }
- closeTabsToEnd.setAttribute('label', label);
- closeTabsToEnd.setAttribute('accesskey', accesskey);
- }
- },
-
- onTabsOnTopSyncCommand : function TSTBrowser_onTabsOnTopSyncCommand(aEnabled)
- {
- if (
- this.windowService.tabsOnTopChangingByUI ||
- !aEnabled ||
- this.position != 'top' ||
- this.fixed ||
- this.windowService.isPopupWindow
- )
- return;
- this.windowService.tabsOnTopChangingByUI = true;
- var self = this;
- if (this.deferredTasks['onTabsOnTopSyncCommand'])
- this.deferredTasks['onTabsOnTopSyncCommand'].cancel();
- (this.deferredTasks['onTabsOnTopSyncCommand'] = this.Deferred
- .next(function() {
- self.windowService.toggleFixed(self.mTabBrowser);
- }))
- .next(function() {
- if (self.window.TabsOnTop.enabled != aEnabled)
- self.window.TabsOnTop.enabled = aEnabled;
- })
- .error(this.defaultDeferredErrorHandler)
- .next(function() {
- self.windowService.tabsOnTopChangingByUI = false;
- delete self.deferredTasks['onTabsOnTopSyncCommand'];
- });
- },
-
- onBeforeFullScreenToggle : function TSTBrowser_onBeforeFullScreenToggle()
- {
- if (this.position != 'top') {
- var isEnteringFullScreenMode = !this.window.fullScreen;
- // entering to the DOM-fullscreen (ex. YouTube Player)
- if (this.document.mozFullScreen && isEnteringFullScreenMode) {
- this.setTabbrowserAttribute(this.kDOM_FULLSCREEN_ACTIVATED, true);
- }
- else {
- if (this.document.documentElement.getAttribute(this.kDOM_FULLSCREEN_ACTIVATED) != 'true') {
- if (isEnteringFullScreenMode)
- this.autoHide.startForFullScreen();
- else
- this.autoHide.endForFullScreen();
- }
- this.removeTabbrowserAttribute(this.kDOM_FULLSCREEN_ACTIVATED);
- }
- }
- },
-
- onTreeStyleTabPrintPreviewEntered : function TSTBrowser_onTreeStyleTabPrintPreviewEntered(aEvent)
- {
- this.setTabbrowserAttribute(this.kPRINT_PREVIEW, true);
- },
-
- onTreeStyleTabPrintPreviewExited : function TSTBrowser_onTreeStyleTabPrintPreviewExited(aEvent)
- {
- this.removeTabbrowserAttribute(this.kPRINT_PREVIEW);
- },
-
-/* commands */
-
-/* reset */
-
- resetTab : function TSTBrowser_resetTab(aTab, aDetachAllChildren)
- {
- if (!aTab.parentNode) // do nothing for closed tab!
- return;
-
- if (aDetachAllChildren)
- this.detachAllChildren(aTab, {
- dontUpdateIndent : true,
- dontAnimate : true
- });
-
- this.detachTab(aTab, {
- dontUpdateIndent : true,
- dontAnimate : true
- });
-
- this.resetTabState(aTab);
- this.updateTabsIndent([aTab], undefined, true);
- },
-
- resetTabState : function TSTBrowser_resetTabState(aTab)
- {
- if (!aTab.parentNode) // do nothing for closed tab!
- return;
-
- aTab.removeAttribute(this.kID);
- aTab.removeAttribute(this.kID_RESTORING);
- aTab.removeAttribute(this.kPARENT);
- aTab.removeAttribute(this.kCHILDREN);
- aTab.removeAttribute(this.kCHILDREN_RESTORING);
- aTab.removeAttribute(this.kSUBTREE_COLLAPSED);
- aTab.removeAttribute(this.kSUBTREE_EXPANDED_MANUALLY);
- aTab.removeAttribute(this.kCOLLAPSED);
- aTab.removeAttribute(this.kNEST);
- this.updateTabCollapsed(aTab, false, true);
- },
-
- resetAllTabs : function TSTBrowser_resetAllTabs(aDetachAllChildren)
- {
- var tabs = this.getAllTabs(this.mTabBrowser);
- for (let i = 0, maxi = tabs.length; i < maxi; i++)
- {
- this.resetTab(tabs[i], aDetachAllChildren);
- }
- },
-
- resetTabbarSize : function TSTBrowser_resetTabbarSize()
- {
- if (this.isVertical) {
- utils.setTreePref('tabbar.shrunkenWidth', utils.getTreePref('tabbar.shrunkenWidth.default'));
- utils.setTreePref('tabbar.width', utils.getTreePref('tabbar.width.default'));
- }
- else {
- utils.setTreePref('tabbar.height', utils.getTreePref('tabbar.height.default'));
- let tabContainerBox = this.getTabContainerBox(this.mTabBrowser);
- tabContainerBox.removeAttribute('height');
- this._tabStripPlaceHolder.height = tabContainerBox.boxObject.height;
- }
- this.updateFloatingTabbar(this.kTABBAR_UPDATE_BY_RESET);
- },
-
- get treeViewEnabled() /* PUBLIC API */
- {
- return this._treeViewEnabled;
- },
- set treeViewEnabled(aValue)
- {
- var newValue = !!aValue;
- if (newValue == this._treeViewEnabled)
- return aValue;
-
- this._treeViewEnabled = newValue;
- if (this._treeViewEnabled) {
- if (this._lastAllowSubtreeCollapseExpand)
- this.allowSubtreeCollapseExpand = true;
- delete this._lastAllowSubtreeCollapseExpand;
-
- let tabs = this.getAllTabs(this.browser);
- for (let i = 0, maxi = tabs.length; i < maxi; i++)
- {
- let tab = tabs[i];
- if (tab._TSTLastSubtreeCollapsed)
- this.collapseExpandSubtree(tab, true, true);
- if (tab._TSTLastSubtreeExpandedManually)
- this.setTabValue(tab, this.kSUBTREE_EXPANDED_MANUALLY, true);
- delete tab._TSTLastSubtreeCollapsed;
- delete tab._TSTLastSubtreeExpandedManually;
- this.updateTabIndent(tab, 0, true);
- }
- this.updateTabsIndent(this.rootTabs, undefined, true);
- }
- else {
- let tabs = this.getAllTabs(this.browser);
- for (let i = 0, maxi = tabs.length; i < maxi; i++)
- {
- let tab = tabs[i];
- this.updateTabIndent(tab, 0, true);
- tab._TSTLastSubtreeCollapsed = this.isSubtreeCollapsed(tab);
- tab._TSTLastSubtreeExpandedManually = this.getTabValue(tab, this.kSUBTREE_EXPANDED_MANUALLY) == 'true';
- this.collapseExpandSubtree(tab, false, true);
- }
-
- this._lastAllowSubtreeCollapseExpand = this.allowSubtreeCollapseExpand;
- this.allowSubtreeCollapseExpand = false;
- }
- return aValue;
- },
-// _treeViewEnabled : true,
-
-/* attach/detach */
-
- attachTabTo : function TSTBrowser_attachTabTo(aChild, aParent, aInfo) /* PUBLIC API */
- {
- if (!aChild.parentNode || (aParent && !aParent.parentNode)) // do nothing for closed tab!
- return;
-
- aInfo = aInfo || {};
- var newAncestors = [];
-
- if (aParent) {
- newAncestors = [aParent].concat(this.getAncestorTabs(aParent));
- if (this.maxTreeLevelPhisical && this.maxTreeLevel > -1) {
- let level = parseInt(aParent.getAttribute(this.kNEST) || 0) + 1;
- newAncestors.some(function(aAncestor) {
- if (level <= this.maxTreeLevel)
- return true;
- level--;
- return false;
- }, this);
- }
- }
-
- var currentParent;
- if (
- !aChild ||
- !aParent ||
- aChild == aParent ||
- (currentParent = this.getParentTab(aChild)) == aParent ||
- aChild.getAttribute('pinned') == 'true' ||
- aParent.getAttribute('pinned') == 'true'
- ) {
- this.fireAttachedEvent(aChild, aParent);
- return;
- }
-
- // avoid recursive tree
- var ancestors = [aParent].concat(this.getAncestorTabs(aChild));
- if (ancestors.indexOf(aChild) > -1)
- return;
-
- currentParent = ancestors[ancestors.length-1];
- var shouldInheritIndent = (
- !currentParent ||
- (currentParent.getAttribute(this.kNEST) == aParent.getAttribute(this.kNEST))
- );
-
- this.ensureTabInitialized(aChild);
- this.ensureTabInitialized(aParent);
-
- if (!aInfo)
- aInfo = {};
-
- var id = aChild.getAttribute(this.kID);
-
- this.detachTab(aChild, {
- dontUpdateIndent : true
- });
-
- var children = aParent.getAttribute(this.kCHILDREN)
- .split('|').filter(function(aId) {
- return this.getTabById(aId);
- }, this);
-
- var newIndex;
-
- var oldIndex = children.indexOf(id);
- if (oldIndex > -1)
- children.splice(oldIndex, 1);
-
- var insertBefore = aInfo.insertBefore ||
- (aInfo.dontMove ? this.getNextTab(aChild) : null );
- var beforeTab = insertBefore ? insertBefore.getAttribute(this.kID) : null ;
- var beforeIndex;
- if (beforeTab && (beforeIndex = children.indexOf(beforeTab)) > -1) {
- children.splice(beforeIndex, 0, id);
- newIndex = insertBefore._tPos;
- }
- else {
- children.push(id);
- if (aInfo.dontMove && children.length > 1) {
- children = children
- .map(this.getTabById, this)
- .sort(this.sortTabsByOrder)
- .map(function(aTab) {
- return aTab.getAttribute(this.kID);
- }, this);
- }
- let refTab = aParent;
- let descendant = this.getDescendantTabs(aParent);
- if (descendant.length) {
- let lastDescendant = descendant[descendant.length-1];
- /**
- * The last descendant tab can be temporarilly moved
- * upper than the root parent tab, in some cases.
- * (the parent tab is pinned, etc.)
- */
- if (!refTab || lastDescendant._tPos > refTab._tPos)
- refTab = lastDescendant;
- }
- newIndex = refTab._tPos+1;
- }
-
- this.setTabValue(aParent, this.kCHILDREN, children.join('|'));
- this.setTabValue(aChild, this.kPARENT, aParent.getAttribute(this.kID));
-
- this.updateTabsCount(aParent);
- if (shouldInheritIndent && !aInfo.dontUpdateIndent)
- this.inheritTabIndent(aChild, aParent);
-
- if (!aInfo.dontMove) {
- if (newIndex > aChild._tPos)
- newIndex--;
- this.moveTabSubtreeTo(aChild, newIndex);
- }
-
- if (aInfo.forceExpand) {
- this.collapseExpandSubtree(aParent, false, aInfo.dontAnimate);
- }
- else if (!aInfo.dontExpand) {
- if (utils.getTreePref('autoCollapseExpandSubtreeOnAttach') &&
- this.shouldTabAutoExpanded(aParent))
- this.collapseExpandTreesIntelligentlyFor(aParent);
-
- if (utils.getTreePref('autoCollapseExpandSubtreeOnSelect')) {
- newAncestors.forEach(function(aAncestor) {
- if (this.shouldTabAutoExpanded(aAncestor))
- this.collapseExpandSubtree(aAncestor, false, aInfo.dontAnimate);
- }, this);
- }
- else if (this.shouldTabAutoExpanded(aParent)) {
- if (utils.getTreePref('autoExpandSubtreeOnAppendChild')) {
- newAncestors.forEach(function(aAncestor) {
- if (this.shouldTabAutoExpanded(aAncestor))
- this.collapseExpandSubtree(aAncestor, false, aInfo.dontAnimate);
- }, this);
- }
- else
- this.collapseExpandTab(aChild, true, aInfo.dontAnimate);
- }
-
- if (this.isCollapsed(aParent))
- this.collapseExpandTab(aChild, true, aInfo.dontAnimate);
- }
- else if (this.shouldTabAutoExpanded(aParent) ||
- this.isCollapsed(aParent)) {
- this.collapseExpandTab(aChild, true, aInfo.dontAnimate);
- }
-
- if (!aInfo.dontUpdateIndent) {
- this.updateTabsIndent([aChild], undefined, aInfo.dontAnimate);
- this.checkTabsIndentOverflow();
- }
-
- this.promoteTooDeepLevelTabs(aChild);
-
- this.fireAttachedEvent(aChild, aParent);
- },
- fireAttachedEvent : function TSTBrowser_fireAttachedEvent(aChild, aParent)
- {
- var data = {
- parentTab : aParent
- };
-
- /* PUBLIC API */
- this.fireCustomEvent(this.kEVENT_TYPE_ATTACHED, aChild, true, false, data);
- // for backward compatibility
- this.fireCustomEvent(this.kEVENT_TYPE_ATTACHED.replace(/^nsDOM/, ''), aChild, true, false, data);
- },
-
- shouldTabAutoExpanded : function TSTBrowser_shouldTabAutoExpanded(aTab)
- {
- return this.hasChildTabs(aTab) &&
- this.isSubtreeCollapsed(aTab);
- },
-
- detachTab : function TSTBrowser_detachTab(aChild, aInfo) /* PUBLIC API */
- {
- if (!aChild || !aChild.parentNode)
- return;
- if (!aInfo)
- aInfo = {};
-
- var parentTab = this.getParentTab(aChild);
- if (!parentTab)
- return;
-
- var id = aChild.getAttribute(this.kID);
-
- this.setTabValue(
- parentTab,
- this.kCHILDREN,
- parentTab.getAttribute(this.kCHILDREN)
- .split('|')
- .filter(function(aId) {
- return this.getTabById(aId) && aId != id;
- }, this).join('|')
- );
- this.deleteTabValue(aChild, this.kPARENT);
-
- if (!this.hasChildTabs(parentTab))
- this.setTabValue(parentTab, this.kSUBTREE_COLLAPSED, true);
-
- this.updateTabsCount(parentTab);
-
- if (!aInfo.dontUpdateIndent) {
- this.updateTabsIndent([aChild], undefined, aInfo.dontAnimate);
- this.checkTabsIndentOverflow();
- }
-
- var data = {
- parentTab : parentTab
- };
-
- /* PUBLIC API */
- this.fireCustomEvent(this.kEVENT_TYPE_DETACHED, aChild, true, false, data);
- // for backward compatibility
- this.fireCustomEvent(this.kEVENT_TYPE_DETACHED.replace(/^nsDOM/, ''), aChild, true, false, data);
-
- if (this.isTemporaryGroupTab(parentTab) && !this.hasChildTabs(parentTab)) {
- this.window.setTimeout(function(aTabBrowser) {
- if (parentTab.parentNode)
- aTabBrowser.removeTab(parentTab, { animate : true });
- parentTab = null;
- }, 0, this.getTabBrowserFromChild(parentTab));
- }
- },
- partTab : function TSTBrowser_partTab(aChild, aInfo) /* PUBLIC API, for backward compatibility */
- {
- return this.detachTab(aChild, aInfo);
- },
-
- detachAllChildren : function TSTBrowser_detachAllChildren(aTab, aInfo)
- {
- if (!aTab.parentNode) // do nothing for closed tab!
- return;
-
- var children = this.getChildTabs(aTab);
- if (!children.length)
- return;
-
- aInfo = aInfo || {};
- if (!('behavior' in aInfo))
- aInfo.behavior = this.kCLOSE_PARENT_BEHAVIOR_SIMPLY_DETACH_ALL_CHILDREN;
- if (aInfo.behavior == this.kCLOSE_PARENT_BEHAVIOR_CLOSE_ALL_CHILDREN)
- aInfo.behavior = this.kCLOSE_PARENT_BEHAVIOR_PROMOTE_FIRST_CHILD;
-
- var b = this.mTabBrowser;
- var parentTab = this.getParentTab(aTab);
-
- if (
- this.isGroupTab(aTab) &&
- this.getTabs(b).filter(function(aTab) {
- return !b._removingTabs || b._removingTabs.indexOf(aTab) < 0;
- }).length == children.length
- ) {
- aInfo.behavior = this.kCLOSE_PARENT_BEHAVIOR_PROMOTE_ALL_CHILDREN;
- aInfo.dontUpdateIndent = false;
- }
-
- var insertBefore = null;
- if (aInfo.behavior == this.kCLOSE_PARENT_BEHAVIOR_DETACH_ALL_CHILDREN &&
- !utils.getTreePref('closeParentBehavior.moveDetachedTabsToBottom')) {
- insertBefore = this.getNextSiblingTab(this.getRootTab(aTab));
- }
- for (let i = 0, maxi = children.length; i < maxi; i++)
- {
- let tab = children[i];
- if (aInfo.behavior == this.kCLOSE_PARENT_BEHAVIOR_DETACH_ALL_CHILDREN) {
- this.detachTab(tab, aInfo);
- this.moveTabSubtreeTo(tab, insertBefore ? insertBefore._tPos - 1 : this.getLastTab(b)._tPos );
- }
- else if (aInfo.behavior == this.kCLOSE_PARENT_BEHAVIOR_PROMOTE_FIRST_CHILD) {
- this.detachTab(tab, aInfo);
- if (i == 0) {
- if (parentTab) {
- this.attachTabTo(tab, parentTab, inherit(aInfo, {
- dontExpand : true,
- dontMove : true
- }));
- }
- this.collapseExpandSubtree(tab, false);
- this.deleteTabValue(tab, this.kSUBTREE_COLLAPSED);
- }
- else {
- this.attachTabTo(tab, children[0], inherit(aInfo, {
- dontExpand : true,
- dontMove : true
- }));
- }
- }
- else if (aInfo.behavior == this.kCLOSE_PARENT_BEHAVIOR_PROMOTE_ALL_CHILDREN && parentTab) {
- this.attachTabTo(tab, parentTab, inherit(aInfo, {
- dontExpand : true,
- dontMove : true
- }));
- }
- else { // aInfo.behavior == this.kCLOSE_PARENT_BEHAVIOR_SIMPLY_DETACH_ALL_CHILDREN
- this.detachTab(tab, aInfo);
- }
- }
- },
- partAllChildren : function TSTBrowser_partAllChildren(aTab, aInfo) /* for backward compatibility */
- {
- return this.detachAllChildren(aTab, aInfo);
- },
-
- detachTabs : function TSTBrowser_detachTabs(aTabs)
- {
- for (let i = 0, maxi = aTabs.length; i < maxi; i++)
- {
- let tab = aTabs[i];
- if (aTabs.indexOf(this.getParentTab(tab)) > -1)
- continue;
- this.detachAllChildren(tab, {
- behavior : this.getCloseParentBehaviorForTab(
- tab,
- this.kCLOSE_PARENT_BEHAVIOR_PROMOTE_FIRST_CHILD
- )
- });
- }
- },
- partTabs : function TSTBrowser_partTabs(aTabs) /* for backward compatibility */
- {
- return this.detachTabs(aTabs);
- },
-
- getCloseParentBehaviorForTab : function TSTBrowser_getCloseParentBehaviorForTab(aTab, aDefaultBehavior)
- {
- var closeParentBehavior = utils.getTreePref('closeParentBehavior');
- var closeRootBehavior = utils.getTreePref('closeRootBehavior');
-
- var parentTab = this.getParentTab(aTab);
- var behavior = aDefaultBehavior ?
- aDefaultBehavior :
- (!parentTab && closeParentBehavior == this.kCLOSE_PARENT_BEHAVIOR_PROMOTE_ALL_CHILDREN) ?
- closeRootBehavior :
- closeParentBehavior ;
- if (behavior == this.kCLOSE_PARENT_BEHAVIOR_PROMOTE_FIRST_CHILD &&
- parentTab &&
- this.getChildTabs(parentTab).length == 1)
- behavior = this.kCLOSE_PARENT_BEHAVIOR_PROMOTE_ALL_CHILDREN;
-
- return behavior;
- },
-
- updateTabsIndent : function TSTBrowser_updateTabsIndent(aTabs, aLevel, aJustNow)
- {
- if (!aTabs || !aTabs.length || !this._treeViewEnabled)
- return;
-
- if (aLevel === void(0))
- aLevel = this.getAncestorTabs(aTabs[0]).length;
-
- var b = this.mTabBrowser;
- var margin = this.indent < 0 ? this.baseIndent : this.indent ;
- var indent = (this.maxTreeLevel < 0 ? aLevel : Math.min(aLevel, this.maxTreeLevel) ) * margin;
-
- var multirow = this.isMultiRow();
- if (multirow) {
- let maxIndent = parseInt(aTabs[0].boxObject.height / 2);
- indent = Math.min(aLevel * 3, maxIndent);
- }
-
- for (let i = 0, maxi = aTabs.length; i < maxi; i++)
- {
- let tab = aTabs[i];
- if (!tab.parentNode)
- continue; // ignore removed tabs
- this.updateTabIndent(tab, indent, aJustNow);
- tab.setAttribute(this.kNEST, aLevel);
- this.updateCanCollapseSubtree(tab, aLevel);
- this.updateTabsIndent(this.getChildTabs(tab), aLevel+1, aJustNow);
- }
- },
- updateTabsIndentWithDelay : function TSTBrowser_updateTabsIndentWithDelay(aTabs)
- {
- if (this.updateTabsIndentWithDelayTimer)
- this.window.clearTimeout(this.updateTabsIndentWithDelayTimer);
-
- this.updateTabsIndentWithDelayTabs = this.updateTabsIndentWithDelayTabs.concat(aTabs);
- this.updateTabsIndentWithDelayTimer = this.window.setTimeout(function(aSelf) {
- var tabs = [];
- for (let i = 0, maxi = aSelf.updateTabsIndentWithDelayTabs.length; i < maxi; i++)
- {
- let tab = aSelf.updateTabsIndentWithDelayTabs[i];
- if (tabs.indexOf(tab) < 0 && tab.parentNode)
- tabs.push(tab);
- }
- aSelf.updateTabsIndentWithDelayTabs = [];
- aSelf.updateTabsIndent(tabs);
- aSelf.window.clearTimeout(aSelf.updateTabsIndentWithDelayTimer);
- aSelf.updateTabsIndentWithDelayTimer = null;
- tabs = null;
- }, 0, this);
- },
- updateTabsIndentWithDelayTimer : null,
-
- updateTabIndent : function TSTBrowser_updateTabIndent(aTab, aIndent, aJustNow)
- {
- if (!aTab.parentNode) // do nothing for closed tab!
- return;
-
- this.stopTabIndentAnimation(aTab);
-
- if (aTab.hasAttribute('pinned'))
- return;
-
- if (!this.enableSubtreeIndent)
- aIndent = 0;
-
- if (this.isMultiRow()) {
- let colors = '-moz-border-'+this.indentTarget+'-colors:'+(function() {
- var retVal = [];
- for (var i = 1; i < aIndent; i++)
- {
- retVal.push('transparent');
- }
- retVal.push('ThreeDShadow');
- return retVal.length == 1 ? 'none' : retVal.join(' ') ;
- })()+' !important;';
- let boxes = this.document.getAnonymousNodes(aTab);
- for (let i = 0, box = boxes.length; i < maxi; i++)
- {
- let box = boxes[i];
- if (box.nodeType != Node.ELEMENT_NODE)
- continue;
- box.setAttribute(
- 'style',
- box.getAttribute('style')
- .replace(/(-moz-)?border-(top|bottom)(-[^:]*)?.*:[^;]+;?/g, '') +
- '; border-'+this.indentTarget+': solid transparent '+aIndent+'px !important;'+colors
- );
- }
- return;
- }
-
- if (
- !this.animationEnabled ||
- aJustNow ||
- this.indentDuration < 1 ||
- this.isCollapsed(aTab)
- ) {
- aTab.style.setProperty(this.indentCSSProp, aIndent+'px', 'important');
- return;
- }
-
- var self = this;
- var CSSTransitionEnabled = ('transition' in aTab.style || 'MozTransition' in aTab.style);
- if (CSSTransitionEnabled) {
- aTab.__treestyletab__updateTabIndentTask = function(aTime, aBeginning, aChange, aDuration) {
- delete aTab.__treestyletab__updateTabIndentTask;
- if (!self.isDestroying)
- aTab.style.setProperty(self.indentCSSProp, aIndent+'px', 'important');
- return true;
- };
- this.animationManager.addTask(
- aTab.__treestyletab__updateTabIndentTask,
- 0, 0, 1, this.window
- );
- return;
- }
-
- var startIndent = this.getPropertyPixelValue(aTab, this.indentCSSProp);
- var delta = aIndent - startIndent;
- var radian = 90 * Math.PI / 180;
- aTab.__treestyletab__updateTabIndentTask = function(aTime, aBeginning, aChange, aDuration) {
- if (self.isDestroying)
- return true;
- var indent, finished;
- if (aTime >= aDuration) {
- delete aTab.__treestyletab__updateTabIndentTask;
- indent = aIndent;
- finished = true;
- }
- else {
- indent = startIndent + (delta * Math.sin(aTime / aDuration * radian));
- finished = false;
- }
- aTab.style.setProperty(self.indentCSSProp, indent+'px', 'important');
- if (finished) {
- startIndent = null;
- delta = null;
- radian = null;
- self = null;
- aTab = null;
- }
- return finished;
- };
- this.animationManager.addTask(
- aTab.__treestyletab__updateTabIndentTask,
- 0, 0, this.indentDuration, this.window
- );
- },
- stopTabIndentAnimation : function TSTBrowser_stopTabIndentAnimation(aTab)
- {
- if (!aTab.parentNode)
- return; // do nothing for closed tab!
- this.animationManager.removeTask(
- aTab.__treestyletab__updateTabIndentTask
- );
- delete aTab.__treestyletab__updateTabIndentTask;
- },
-
- inheritTabIndent : function TSTBrowser_inheritTabIndent(aNewTab, aExistingTab)
- {
- var indent = this.getPropertyPixelValue(aExistingTab, this.indentCSSProp);
- if (indent)
- aNewTab.style.setProperty(this.indentCSSProp, indent+'px', 'important');
- else
- aNewTab.style.removeProperty(this.indentCSSProp);
- },
-
- updateAllTabsIndent : function TSTBrowser_updateAllTabsIndent(aJustNow)
- {
- this.updateTabsIndent(this.rootTabs, 0, aJustNow);
-// this.checkTabsIndentOverflow();
- },
-
- checkTabsIndentOverflow : function TSTBrowser_checkTabsIndentOverflow(aDelay)
- {
- this.cancelCheckTabsIndentOverflow();
- this.checkTabsIndentOverflowTimer = this.window.setTimeout(function(aSelf) {
- aSelf.checkTabsIndentOverflowTimer = null;
- aSelf.checkTabsIndentOverflowCallback();
- }, aDelay || 100, this);
- },
- cancelCheckTabsIndentOverflow : function TSTBrowser_cancelCheckTabsIndentOverflow()
- {
- if (this.checkTabsIndentOverflowTimer) {
- this.window.clearTimeout(this.checkTabsIndentOverflowTimer);
- this.checkTabsIndentOverflowTimer = null;
- }
- },
- checkTabsIndentOverflowTimer : null,
- checkTabsIndentOverflowCallback : function TSTBrowser_checkTabsIndentOverflowCallback()
- {
- if (!utils.getTreePref('indent.autoShrink')) {
- this.indent = -1;
- return;
- }
-
- var b = this.mTabBrowser;
- var tabbarSize = b.mTabContainer.boxObject[this.invertedSizeProp];
- if (!tabbarSize) // don't update indent for collapsed tab bar
- return;
-
- var tabs = Array.slice(b.mTabContainer.querySelectorAll(
- 'tab['+this.kNEST+']:not(['+this.kNEST+'="0"]):not(['+this.kNEST+'=""])'+
- ':not(['+this.kCOLLAPSED+'="true"])'+
- ':not([hidden="true"])'+
- ':not([collapsed="true"])'
- ));
- if (!tabs.length)
- return;
-
- var self = this;
- tabs.sort(function(aA, aB) { return Number(aA.getAttribute(self.kNEST)) - Number(aB.getAttribute(self.kNEST)); });
- var nest = tabs[tabs.length-1].getAttribute(this.kNEST);
- if (this.maxTreeLevel > -1)
- nest = Math.min(nest, this.maxTreeLevel);
- if (!nest)
- return;
-
- var oldIndent = this.indent;
- var indent = (oldIndent < 0 ? this.baseIndent : oldIndent ) * nest;
- var maxIndentBase = Math.min(
- this.getFirstNormalTab(b).boxObject[this.invertedSizeProp],
- tabbarSize
- );
- var isVertical = this.isVertical;
- if (!isVertical) {
- if (this._horizontalTabMaxIndentBase)
- maxIndentBase = this._horizontalTabMaxIndentBase;
- else
- this._horizontalTabMaxIndentBase = maxIndentBase;
- }
- var maxIndent = maxIndentBase * (isVertical ? 0.33 : 0.5 );
-
- var indentMin = utils.getTreePref(isVertical ? 'indent.min.vertical' : 'indent.min.horizontal');
- var indentUnit = Math.max(Math.floor(maxIndent / nest), indentMin);
- if (indent > maxIndent) {
- this.indent = indentUnit;
- }
- else {
- this.indent = -1;
- if ((this.baseIndent * nest) > maxIndent)
- this.indent = indentUnit;
- }
-
- if (oldIndent != this.indent) {
- this.updateAllTabsIndent();
- }
- },
- _horizontalTabMaxIndentBase : 0,
-
- updateCanCollapseSubtree : function TSTBrowser_updateCanCollapseSubtree(aTab, aLevel)
- {
- if (!aTab.parentNode) // do nothing for closed tab!
- return;
-
- if (
- !aLevel ||
- this.maxTreeLevel < 0 ||
- this.maxTreeLevel > aLevel
- ) {
- aTab.setAttribute(this.kALLOW_COLLAPSE, true);
- this.collapseExpandSubtree(aTab, this.isSubtreeCollapsed(aTab));
- }
- else {
- this.collapseExpandSubtree(aTab, false);
- aTab.removeAttribute(this.kALLOW_COLLAPSE);
- }
- },
-
- updateTabsCount : function TSTBrowser_updateTabsCount(aTab, aDontUpdateAncestor)
- {
- if (!aTab.parentNode) // do nothing for closed tab!
- return;
-
- var count = this.document.getAnonymousElementByAttribute(aTab, 'class', this.kCOUNTER);
- if (count) {
- let value = this.getDescendantTabs(aTab).length;
- if (this.counterRole == this.kCOUNTER_ROLE_ALL_TABS)
- value += 1;
- count.setAttribute('value', value);
- }
- if (!aDontUpdateAncestor) {
- let parent = this.getParentTab(aTab);
- if (parent)
- this.updateTabsCount(parent);
- }
- },
-
- updateAllTabsCount : function TSTBrowser_updateAllTabsCount()
- {
- var tabs = this.rootTabs;
- for (let i = 0, maxi = tabs.length; i < maxi; i++)
- {
- let tab = tabs[i];
- this.updateTabsCount(tab, this);
- }
- },
-
- promoteTooDeepLevelTabs : function TSTBrowser_promoteTooDeepLevelTabs(aParent)
- {
- if (this.maxTreeLevel < 0 || !this.maxTreeLevelPhisical)
- return;
-
- var tabs = aParent ? this.getDescendantTabs(aParent) : this.getAllTabs(this.mTabBrowser) ;
- for (let i = 0, maxi = tabs.length; i < maxi; i++)
- {
- let level = parseInt(tab.getAttribute(this.kNEST) || 0);
- if (level <= this.maxTreeLevel)
- continue;
-
- let parent = this.getParentTab(tab);
- let newParent = this.getParentTab(parent);
- if (this.maxTreeLevel == 0 || !newParent) {
- this.detachTab(aTab);
- }
- else {
- let nextSibling = this.getNextTab(tab);
- this.attachTabTo(tab, newParent, {
- dontMove : true,
- insertBefore : nextSibling
- });
- }
- }
- },
-
-/* move */
-
- moveTabSubtreeTo : function TSTBrowser_moveTabSubtreeTo(aTab, aIndex)
- {
- if (!aTab || !aTab.parentNode)
- return;
-
- var b = this.mTabBrowser;
- this.subTreeMovingCount++;
-
- this.internallyTabMovingCount++;
- b.moveTabTo(aTab, aIndex);
- this.internallyTabMovingCount--;
-
- this.subTreeChildrenMovingCount++;
- this.internallyTabMovingCount++;
- var descendantTabs = this.getDescendantTabs(aTab);
- for (let i = 0, maxi = descendantTabs.length; i < maxi; i++)
- {
- let descendantTab = descendantTabs[i];
- b.moveTabTo(descendantTab, aTab._tPos + i + (aTab._tPos < descendantTab._tPos ? 1 : 0 ));
- }
- this.internallyTabMovingCount--;
- this.subTreeChildrenMovingCount--;
-
- this.subTreeMovingCount--;
- },
- moveTabSubTreeTo : function(...aArgs) {
- return this.moveTabSubtreeTo.apply(this, aArgs);
- }, // obsolete, for backward compatibility
-
- moveTabLevel : function TSTBrowser_moveTabLevel(aEvent)
- {
- var b = this.mTabBrowser;
- var parentTab = this.getParentTab(b.mCurrentTab);
- if (aEvent.keyCode == Ci.nsIDOMKeyEvent.DOM_VK_RIGHT) {
- let prevTab = this.getPreviousSiblingTab(b.mCurrentTab);
- if ((!parentTab && prevTab) ||
- (parentTab && b.mCurrentTab != this.getFirstChildTab(parentTab))) {
- this.attachTabTo(b.mCurrentTab, prevTab);
- b.mCurrentTab.focus();
- return true;
- }
- }
- else if (aEvent.keyCode == Ci.nsIDOMKeyEvent.DOM_VK_LEFT && parentTab) {
- let grandParent = this.getParentTab(parentTab);
- if (grandParent) {
- this.attachTabTo(b.mCurrentTab, grandParent, {
- insertBefore : this.getNextSiblingTab(parentTab)
- });
- b.mCurrentTab.focus();
- return true;
- }
- else {
- let nextTab = this.getNextSiblingTab(parentTab);
- this.detachTab(b.mCurrentTab);
- this.internallyTabMovingCount++;
- if (nextTab) {
- b.moveTabTo(b.mCurrentTab, nextTab._tPos - 1);
- }
- else {
- b.moveTabTo(b.mCurrentTab, this.getLastTab(b)._tPos);
- }
- this.internallyTabMovingCount--;
- b.mCurrentTab.focus();
- return true;
- }
- }
- return false;
- },
-
- /**
- * Imports tabs from another window with their tree structure.
- * aOptions is an optional hash which can have two properties:
- * * duplicate (boolean)
- * * insertBefore (nsIDOMElement)
- */
- importTabs : function TSTBrowser_importTabs(aTabs, aInsertBefore) /* PUBLIC API */
- {
- return this.moveTabsInternal(aTabs, { insertBefore : aInsertBefore });
- },
- duplicateTabs : function TSTBrowser_duplicateTabs(aTabs, aInsertBefore) /* PUBLIC API */
- {
- return this.moveTabsInternal(aTabs, { insertBefore : aInsertBefore, duplicate : true });
- },
- moveTabs : function TSTBrowser_importTabs(aTabs, aInsertBefore) /* PUBLIC API */
- {
- return this.moveTabsInternal(aTabs, { insertBefore : aInsertBefore });
- },
- moveTabsInternal : function TSTBrowser_moveTabsInternal(aTabs, aOptions)
- {
- aOptions = aOptions || {};
-
- var targetBrowser = this.mTabBrowser;
- var sourceWindow = aTabs[0].ownerDocument.defaultView;
- var sourceBrowser = sourceWindow.TreeStyleTabService.getTabBrowserFromChild(aTabs[0]);
- var sourceService = sourceBrowser.treeStyleTab;
-
- // prevent Multiple Tab Handler feature
- targetBrowser.duplicatingSelectedTabs = true;
- targetBrowser.movingSelectedTabs = true;
-
- var shouldClose = (
- !aOptions.duplicate &&
- sourceService.getAllTabs(sourceBrowser).length == aTabs.length
- );
- var newTabs = [];
- var treeStructure = sourceService.getTreeStructureFromTabs(aTabs);
-
- // Firefox fails to "move" collapsed tabs. So, expand them first
- // and collapse them after they are moved.
- var collapsedStates = sourceService.forceExpandTabs(aTabs);;
-
- var shouldResetSelection = (
- aTabs.every(function(aTab) {
- return aTab.getAttribute('multiselected') == 'true';
- }) &&
- (sourceService != this || aOptions.duplicate)
- );
-
- var tabs = this.getTabs(targetBrowser);
- var lastTabIndex = tabs[tabs.length -1]._tPos;
- for (let i in aTabs)
- {
- let tab = aTabs[i];
-
- if (shouldResetSelection) {
- if ('MultipleTabService' in sourceWindow)
- sourceWindow.MultipleTabService.setSelection(tab, false);
- else
- tab.removeAttribute('multiselected');
- }
-
- if (aOptions.duplicate) {
- tab = this.duplicateTabAsOrphan(tab);
- newTabs.push(tab);
- }
- else if (sourceService != this) {
- tab = this.importTab(tab);
- newTabs.push(tab);
- }
-
- if (shouldResetSelection) {
- if ('MultipleTabService' in sourceWindow)
- sourceWindow.MultipleTabService.setSelection(tab, true);
- else
- tab.setAttribute('multiselected', true);
- }
-
- lastTabIndex++;
-
- let newIndex = aOptions.insertBefore ? aOptions.insertBefore._tPos : lastTabIndex ;
- if (aOptions.insertBefore && newIndex > tab._tPos)
- newIndex--;
-
- this.internallyTabMovingCount++;
- targetBrowser.moveTabTo(tab, newIndex);
- this.collapseExpandTab(tab, false, true);
- this.internallyTabMovingCount--;
- }
-
- if (shouldClose)
- sourceService.closeOwner(sourceBrowser);
-
- if (newTabs.length)
- this.applyTreeStructureToTabs(
- newTabs,
- treeStructure,
- collapsedStates.map(function(aCollapsed) {
- return !aCollapsed
- })
- );
-
- for (let i = collapsedStates.length - 1; i > -1; i--)
- {
- sourceService.collapseExpandSubtree(aTabs[i], collapsedStates[i], true);
- }
-
- // Multiple Tab Handler
- targetBrowser.movingSelectedTabs = false;
- targetBrowser.duplicatingSelectedTabs = false;
-
- return newTabs;
- },
-
- importTab : function TSTBrowser_importTab(aTab)
- {
- if (!aTab.parentNode) // do nothing for closed tab!
- return null;
-
- var newTab = this.mTabBrowser.addTab();
- newTab.linkedBrowser.stop();
- newTab.linkedBrowser.docShell;
- this.mTabBrowser.swapBrowsersAndCloseOther(newTab, aTab);
- this.mTabBrowser.setTabTitle(newTab);
- return newTab;
- },
-
- duplicateTabAsOrphan : function TSTBrowser_duplicateTabAsOrphan(aTab)
- {
- if (!aTab.parentNode) // do nothing for closed tab!
- return null;
-
- var newTab = this.mTabBrowser.duplicateTab(aTab);
- this.deleteTabValue(newTab, this.kCHILDREN);
- this.deleteTabValue(newTab, this.kPARENT);
- return newTab;
- },
-
- closeOwner : function TSTBrowser_closeOwner(aTabOwner)
- {
- var w = aTabOwner.ownerDocument.defaultView;
- if (!w)
- return;
- if ('SplitBrowser' in w) {
- if ('getSubBrowserFromChild' in w.SplitBrowser) {
- var subbrowser = w.SplitBrowser.getSubBrowserFromChild(aTabOwner);
- if (subbrowser) {
- subbrowser.close();
- return;
- }
- }
- if (w.SplitBrowser.browsers.length)
- return;
- }
- w.close();
- },
-
-/* collapse/expand */
-
- collapseExpandSubtree : function TSTBrowser_collapseExpandSubtree(aTab, aCollapse, aJustNow) /* PUBLIC API */
- {
- if (!aTab || !aTab.parentNode)
- return;
-
- if (this.isSubtreeCollapsed(aTab) == aCollapse)
- return;
-
- var b = this.mTabBrowser;
- this.doingCollapseExpand = true;
-
- this.setTabValue(aTab, this.kSUBTREE_COLLAPSED, aCollapse);
-
- var expandedTabs = this.getChildTabs(aTab);
- var lastExpandedTabIndex = expandedTabs.length - 1;
- for (let i = 0, maxi = expandedTabs.length; i < maxi; i++)
- {
- let childTab = expandedTabs[i];
- if (!aCollapse && !aJustNow && i == lastExpandedTabIndex) {
- let self = this;
- this.collapseExpandTab(childTab, aCollapse, aJustNow, function() {
- self.scrollToTabSubtree(aTab);
- });
- }
- else
- this.collapseExpandTab(childTab, aCollapse, aJustNow);
- }
-
- if (aCollapse)
- this.deleteTabValue(aTab, this.kSUBTREE_EXPANDED_MANUALLY);
-
- if (utils.getTreePref('indent.autoShrink') &&
- utils.getTreePref('indent.autoShrink.onlyForVisible'))
- this.checkTabsIndentOverflow();
-
- this.doingCollapseExpand = false;
- },
- manualCollapseExpandSubtree : function(aTab, aCollapse, aJustNow)
- {
- this.collapseExpandSubtree(aTab, aCollapse, aJustNow);
- if (!aCollapse)
- this.setTabValue(aTab, this.kSUBTREE_EXPANDED_MANUALLY, true);
-
- if (utils.getTreePref('indent.autoShrink') &&
- utils.getTreePref('indent.autoShrink.onlyForVisible')) {
- this.cancelCheckTabsIndentOverflow();
- if (!aTab.__treestyletab__checkTabsIndentOverflowOnMouseLeave) {
- var self = this;
- var stillOver = false;
- var id = this.getTabValue(aTab, this.kID);
- aTab.__treestyletab__checkTabsIndentOverflowOnMouseLeave = function checkTabsIndentOverflowOnMouseLeave(aEvent, aDelayed) {
- if (aEvent.type == 'mouseover') {
- if (self.evaluateXPath(
- 'ancestor-or-self::*[@' + self.kID + '="' + id + '"]',
- aEvent.originalTarget || aEvent.target,
- Ci.nsIDOMXPathResult.BOOLEAN_TYPE
- ).booleanValue)
- stillOver = true;
- return;
- }
- else if (!aDelayed) {
- if (stillOver) {
- stillOver = false;
- }
- self.Deferred.next(function() {
- checkTabsIndentOverflowOnMouseLeave.call(null, aEvent, true);
- });
- return;
- } else if (stillOver) {
- return;
- }
- var x = aEvent.clientX;
- var y = aEvent.clientY;
- var rect = aTab.getBoundingClientRect();
- if (x > rect.left && x < rect.right && y > rect.top && y < rect.bottom)
- return;
- self.document.removeEventListener('mouseover', aTab.__treestyletab__checkTabsIndentOverflowOnMouseLeave, true);
- self.document.removeEventListener('mouseout', aTab.__treestyletab__checkTabsIndentOverflowOnMouseLeave, true);
- delete aTab.__treestyletab__checkTabsIndentOverflowOnMouseLeave;
- self.checkTabsIndentOverflow();
- };
- this.document.addEventListener('mouseover', aTab.__treestyletab__checkTabsIndentOverflowOnMouseLeave, true);
- this.document.addEventListener('mouseout', aTab.__treestyletab__checkTabsIndentOverflowOnMouseLeave, true);
- }
- }
- },
-
- collapseExpandTab : function TSTBrowser_collapseExpandTab(aTab, aCollapse, aJustNow, aCallbackToRunOnStartAnimation)
- {
- if (!aTab || !aTab.parentNode || !this.getParentTab(aTab))
- return;
-
- this.setTabValue(aTab, this.kCOLLAPSED, aCollapse);
- this.updateTabCollapsed(aTab, aCollapse, aJustNow, aCallbackToRunOnStartAnimation);
-
- var data = {
- collapsed : aCollapse
- };
-
- /* PUBLIC API */
- this.fireCustomEvent(this.kEVENT_TYPE_TAB_COLLAPSED_STATE_CHANGED, aTab, true, false, data);
- // for backward compatibility
- this.fireCustomEvent(this.kEVENT_TYPE_TAB_COLLAPSED_STATE_CHANGED.replace(/^nsDOM/, ''), aTab, true, false, data);
-
- var b = this.mTabBrowser;
- var parent;
- if (aCollapse && aTab == b.selectedTab && (parent = this.getParentTab(aTab))) {
- var newSelection = parent;
- this.getAncestorTabs(aTab).some(function(aAncestor) {
- if (!this.isCollapsed(aAncestor)) {
- newSelection = aAncestor;
- return true;
- }
- return false;
- }, this);
- b.selectedTab = newSelection;
- }
-
- if (!this.isSubtreeCollapsed(aTab)) {
- let tabs = this.getChildTabs(aTab);
- for (let i = 0, maxi = tabs.length; i < maxi; i++)
- {
- this.collapseExpandTab(tabs[i], aCollapse, aJustNow);
- }
- }
- },
- updateTabCollapsed : function TSTBrowser_updateTabCollapsed(aTab, aCollapsed, aJustNow, aCallbackToRunOnStartAnimation)
- {
- if (!aTab.parentNode) // do nothing for closed tab!
- return;
-
- this.stopTabCollapseAnimation(aTab);
-
- aTab.removeAttribute(this.kX_OFFSET);
- aTab.removeAttribute(this.kY_OFFSET);
-
- if (!this.canCollapseSubtree(this.getRootTab(aTab)))
- aCollapsed = false;
-
- aTab.setAttribute(this.kCOLLAPSING_PHASE, aCollapsed ? this.kCOLLAPSING_PHASE_TO_BE_COLLAPSED : this.kCOLLAPSING_PHASE_TO_BE_EXPANDED );
-
- var CSSTransitionEnabled = ('transition' in aTab.style || 'MozTransition' in aTab.style);
-
- var maxMargin;
- var offsetAttr;
- var collapseProp = 'margin-'+this.collapseTarget;
- let (firstTab = this.getFirstNormalTab(this.mTabBrowser)) {
- if (this.isVertical) {
- maxMargin = firstTab.boxObject.height;
- offsetAttr = this.kY_OFFSET;
- if (firstTab.style.height)
- aTab.style.height = firstTab.style.height;
- }
- else {
- maxMargin = firstTab.boxObject.width;
- offsetAttr = this.kX_OFFSET;
- if (firstTab.style.width)
- aTab.style.width = firstTab.style.width;
- }
- }
-
- var startMargin, endMargin, startOpacity, endOpacity;
- if (aCollapsed) {
- startMargin = 0;
- endMargin = maxMargin;
- startOpacity = 1;
- endOpacity = 0;
- if (this.canStackTabs && this.getParentTab(aTab)) {
- endOpacity = 1;
- endMargin = this.kSTACKED_TAB_MARGIN;
- }
- }
- else {
- startMargin = maxMargin;
- endMargin = 0;
- startOpacity = 0;
- endOpacity = 1;
- if (this.canStackTabs && this.getParentTab(aTab)) {
- startOpacity = 1;
- startMargin = this.kSTACKED_TAB_MARGIN;
- }
- }
-
- if (
- !this.animationEnabled ||
- aJustNow ||
- this.collapseDuration < 1 // ||
-// !this.isVertical ||
-// !this.canCollapseSubtree(this.getParentTab(aTab))
- ) {
- if (aCollapsed)
- aTab.setAttribute(this.kCOLLAPSED_DONE, true);
- else
- aTab.removeAttribute(this.kCOLLAPSED_DONE);
- aTab.removeAttribute(this.kCOLLAPSING_PHASE);
-
- // Pinned tabs are positioned by "margin-top", so
- // we must not reset the property for pinned tabs.
- // (However, we still must update "opacity".)
- let pinned = aTab.getAttribute('pinned') == 'true';
- let canExpand = !pinned || this.collapseCSSProp != 'margin-top';
-
- if (CSSTransitionEnabled) {
- if (canExpand)
- aTab.style.setProperty(this.collapseCSSProp, endMargin ? '-'+endMargin+'px' : '', 'important');
-
- if (endOpacity == 0)
- aTab.style.setProperty('opacity', endOpacity == 1 ? '' : endOpacity, 'important');
- else
- aTab.style.removeProperty('opacity');
- }
- else {
- if (canExpand)
- aTab.style.removeProperty(this.collapseCSSProp);
- aTab.style.removeProperty('opacity');
- }
-
- if (aCallbackToRunOnStartAnimation)
- aCallbackToRunOnStartAnimation();
- return;
- }
-
- var deltaMargin = endMargin - startMargin;
- var deltaOpacity = endOpacity - startOpacity;
-
- aTab.style.setProperty(this.collapseCSSProp, startMargin ? '-'+startMargin+'px' : '', 'important');
- aTab.style.setProperty('opacity', startOpacity == 1 ? '' : startOpacity, 'important');
-
- if (!aCollapsed) {
- aTab.setAttribute(offsetAttr, maxMargin);
- aTab.removeAttribute(this.kCOLLAPSED_DONE);
- }
-
- var radian = 90 * Math.PI / 180;
- var self = this;
- var firstFrame = true;
- aTab.__treestyletab__updateTabCollapsedTask = function(aTime, aBeginning, aChange, aDuration) {
- if (self.isDestroying)
- return true;
- if (firstFrame) {
- // The callback must be started before offsetAttr is changed!
- if (aCallbackToRunOnStartAnimation)
- aCallbackToRunOnStartAnimation();
- if (CSSTransitionEnabled) {
- aTab.style.setProperty(self.collapseCSSProp, endMargin ? '-'+endMargin+'px' : '', 'important');
- aTab.style.setProperty('opacity', endOpacity == 1 ? '' : endOpacity, 'important');
- }
- }
- firstFrame = false;
- // If this is the last tab, negative scroll happens.
- // Then, we shouldn't do animation.
- var stopAnimation = false;
- var scrollBox = self.scrollBox;
- if (scrollBox) {
- if (scrollBox._scrollbox)
- scrollBox = scrollBox._scrollbox;
- if ('scrollTop' in scrollBox &&
- (scrollBox.scrollTop < 0 || scrollBox.scrollLeft < 0)) {
- scrollBox.scrollTop = 0;
- scrollBox.scrollLeft = 0;
- stopAnimation = true;
- }
- }
- if (aTime >= aDuration || stopAnimation) {
- delete aTab.__treestyletab__updateTabCollapsedTask;
- if (aCollapsed)
- aTab.setAttribute(self.kCOLLAPSED_DONE, true);
- if (!CSSTransitionEnabled) {
- aTab.style.removeProperty(self.collapseCSSProp);
- aTab.style.removeProperty('opacity');
- }
- aTab.removeAttribute(offsetAttr);
- aTab.removeAttribute(self.kCOLLAPSING_PHASE);
-
- maxMargin = null;
- offsetAttr = null;
- startMargin = null;
- endMargin = null;
- startOpacity = null;
- endOpacity = null;
- deltaMargin = null;
- deltaOpacity = null;
- collapseProp = null;
- radian = null;
- self = null;
- aTab = null;
-
- return true;
- }
- else {
- if (!CSSTransitionEnabled) {
- let power = Math.sin(aTime / aDuration * radian);
- let margin = startMargin + (deltaMargin * power);
- let opacity = startOpacity + (deltaOpacity * power);
- aTab.style.setProperty(self.collapseCSSProp, margin ? '-'+margin+'px' : '', 'important');
- aTab.style.setProperty('opacity', opacity == 1 ? '' : opacity, 'important');
- }
- aTab.setAttribute(offsetAttr, maxMargin);
- return false;
- }
- };
- this.animationManager.addTask(
- aTab.__treestyletab__updateTabCollapsedTask,
- 0, 0, this.collapseDuration, this.window
- );
- },
- kOPACITY_RULE_REGEXP : /opacity\s*:[^;]+;?/,
- kSTACKED_TAB_MARGIN : 15,
- stopTabCollapseAnimation : function TSTBrowser_stopTabCollapseAnimation(aTab)
- {
- if (!aTab.parentNode)
- return; // do nothing for closed tab!
-
- this.animationManager.removeTask(
- aTab.__treestyletab__updateTabCollapsedTask
- );
- },
-
- collapseExpandTreesIntelligentlyFor : function TSTBrowser_collapseExpandTreesIntelligentlyFor(aTab, aJustNow)
- {
- if (!aTab ||
- !aTab.parentNode ||
- this.doingCollapseExpand ||
- !this.canCollapseSubtree(aTab))
- return;
-
- var b = this.mTabBrowser;
- var sameParentTab = this.getParentTab(aTab);
- var expandedAncestors = [aTab].concat(this.getAncestorTabs(aTab))
- .map(function(aAncestor) {
- return aAncestor.getAttribute(this.kID);
- }, this)
- .join('|');
-
- var xpathResult = this.evaluateXPath(
- 'child::xul:tab[@'+this.kCHILDREN+' and not(@'+this.kCOLLAPSED+'="true") and not(@'+this.kSUBTREE_COLLAPSED+'="true") and @'+this.kID+' and not(contains("'+expandedAncestors+'", @'+this.kID+')) and not(@hidden="true")]',
- b.mTabContainer
- );
- for (var i = 0, maxi = xpathResult.snapshotLength; i < maxi; i++)
- {
- let dontCollapse = false;
- let collapseTab = xpathResult.snapshotItem(i);
-
- let parentTab = this.getParentTab(collapseTab);
- if (parentTab) {
- dontCollapse = true;
- if (!this.isSubtreeCollapsed(parentTab)) {
- this.getAncestorTabs(collapseTab).some(function(aAncestor) {
- if (expandedAncestors.indexOf(aAncestor.getAttribute(this.kID)) < 0)
- return false;
- dontCollapse = false;
- return true;
- }, this);
- }
- }
-
- let manuallyExpanded = this.getTabValue(collapseTab, this.kSUBTREE_EXPANDED_MANUALLY) == 'true';
- if (!dontCollapse && !manuallyExpanded)
- this.collapseExpandSubtree(collapseTab, true, aJustNow);
- }
-
- this.collapseExpandSubtree(aTab, false, aJustNow);
- },
-
- collapseExpandAllSubtree : function TSTBrowser_collapseExpandAllSubtree(aCollapse, aJustNow)
- {
- var tabs = this.mTabBrowser.mTabContainer.querySelectorAll(
- 'tab['+this.kID+']['+this.kCHILDREN+']'+
- (
- aCollapse ?
- ':not(['+this.kSUBTREE_COLLAPSED+'="true"])' :
- '['+this.kSUBTREE_COLLAPSED+'="true"]'
- )
- );
- for (var i = 0, maxi = tabs.length; i < maxi; i++)
- {
- this.collapseExpandSubtree(tabs[i], aCollapse, aJustNow);
- }
- },
-
-/* scroll */
-
- scrollTo : function TSTBrowser_scrollTo(aEndX, aEndY)
- {
- if (this.deferredTasks['cancelPerformingAutoScroll'])
- return;
-
- if (this.animationEnabled || this.smoothScrollEnabled) {
- this.smoothScrollTo(aEndX, aEndY);
- }
- else {
- try {
- this.cancelPerformingAutoScroll();
- this.scrollBoxObject.scrollTo(aEndX, aEndY);
- }
- catch(e) {
- }
- }
- },
-
- smoothScrollTo : function TSTBrowser_smoothScrollTo(aEndX, aEndY, aDuration)
- {
- this.cancelPerformingAutoScroll(true);
-
- var b = this.mTabBrowser;
- var scrollBoxObject = this.scrollBoxObject;
- var x = {}, y = {};
- scrollBoxObject.getPosition(x, y);
- var startX = x.value;
- var startY = y.value;
- var deltaX = aEndX - startX;
- var deltaY = aEndY - startY;
-
- var arrowscrollbox = scrollBoxObject.element.parentNode;
- if (
- arrowscrollbox &&
- (
- arrowscrollbox.localName != 'arrowscrollbox' ||
- !('_isScrolling' in arrowscrollbox)
- )
- )
- arrowscrollbox = null;
-
- var radian = 90 * Math.PI / 180;
- var self = this;
- this.smoothScrollTask = function(aTime, aBeginning, aChange, aDuration) {
- if (self.isDestroying)
- return true;
- var scrollBoxObject = self.scrollBoxObject;
- if (aTime >= aDuration || self.deferredTasks['cancelPerformingAutoScroll']) {
- if (!self.deferredTasks['cancelPerformingAutoScroll']) {
- scrollBoxObject.scrollTo(aEndX, aEndY);
-
- /**
- * When there is any expanding tab, we have to retry to scroll.
- * if the scroll box was expanded.
- */
- let oldSize = self._getMaxScrollSize(scrollBoxObject);
- let key = 'smoothScrollTo_'+parseInt(Math.random() * 65000);
- (self.deferredTasks[key] = self.Deferred.next(function() {
- let newSize = self._getMaxScrollSize(scrollBoxObject);
- let lastTab = self.getLastVisibleTab(self.mTabBrowser);
- if (
- // scroll size can be expanded by expanding tabs.
- oldSize[0] < newSize[0] || oldSize[1] < newSize[1] ||
- // there are still animating tabs
- self.getXOffsetOfTab(lastTab) || self.getYOffsetOfTab(lastTab) ||
- self.mTabBrowser.mTabContainer.querySelector('tab['+self.kCOLLAPSING_PHASE+'="'+self.kCOLLAPSING_PHASE_TO_BE_EXPANDED+'"]')
- )
- self.smoothScrollTo(aEndX, aEndY, parseInt(aDuration * 0.5));
- self = null;
- scrollBoxObject = null;
- })).error(self.defaultDeferredErrorHandler).next(function() {
- delete self.deferredTasks[key];
- });
- }
-
- b = null;
- x = null;
- y = null;
- startX = null;
- startY = null;
- radian = null;
- self.smoothScrollTask = null;
-
- return true;
- }
-
- var power = Math.sin(aTime / aDuration * radian);
- var newX = startX + parseInt(deltaX * power);
- var newY = startY + parseInt(deltaY * power);
- scrollBoxObject.scrollTo(newX, newY);
- return false;
- };
- this.animationManager.addTask(
- this.smoothScrollTask,
- 0, 0, this.smoothScrollDuration || aDuration, this.window
- );
- },
- _getMaxScrollSize : function(aScrollBoxObject) {
- var x = {}, y = {};
- aScrollBoxObject.getPosition(x, y);
- var w = {}, h = {};
- aScrollBoxObject.getScrolledSize(w, h);
- var maxX = Math.max(0, w.value - aScrollBoxObject.width);
- var maxY = Math.max(0, h.value - aScrollBoxObject.height);
- return [maxX, maxY];
- },
- smoothScrollTask : null,
-
- scrollToTab : function TSTBrowser_scrollToTab(aTab, aOnlyWhenCurrentTabIsInViewport)
- {
- if (!aTab || !aTab.parentNode || this.isTabInViewport(aTab))
- return;
-
- var b = this.mTabBrowser;
-
- var scrollBoxObject = this.scrollBoxObject;
- var w = {}, h = {};
- try {
- scrollBoxObject.getScrolledSize(w, h);
- }
- catch(e) { // Tab Mix Plus (or others)
- return;
- }
-
- var targetTabBox = this.getFutureBoxObject(aTab);
- var baseTabBox = this.getFirstNormalTab(b).boxObject;
-
- var targetX = (targetTabBox.screenX < scrollBoxObject.screenX) ?
- (targetTabBox.screenX - baseTabBox.screenX) - (targetTabBox.width * 0.5) :
- (targetTabBox.screenX - baseTabBox.screenX) - scrollBoxObject.width + (targetTabBox.width * 1.5) ;
-
- var targetY = (targetTabBox.screenY < scrollBoxObject.screenY) ?
- (targetTabBox.screenY - baseTabBox.screenY) - (targetTabBox.height * 0.5) :
- (targetTabBox.screenY - baseTabBox.screenY) - scrollBoxObject.height + (targetTabBox.height * 1.5) ;
-
- if (aOnlyWhenCurrentTabIsInViewport && b.selectedTab != aTab) {
- let box = b.selectedTab.boxObject;
- if (targetTabBox.screenX - box.screenX + baseTabBox.width > scrollBoxObject.width ||
- targetTabBox.screenY - box.screenY + baseTabBox.height > scrollBoxObject.height)
- return;
- }
-
- this.scrollTo(targetX, targetY);
- },
-
- scrollToTabSubtree : function TSTBrowser_scrollToTabSubtree(aTab)
- {
- if (!aTab.parentNode) // do nothing for closed tab!
- return;
- var b = this.mTabBrowser;
- var descendant = this.getDescendantTabs(aTab);
- var parentTabBox = aTab.boxObject;
-
- var containerPosition = this.tabStrip.boxObject[this.screenPositionProp];
- var containerSize = this.tabStrip.boxObject[this.sizeProp];
- var parentPosition = parentTabBox[this.screenPositionProp];
-
- var lastVisible = aTab;
- for (let i = descendant.length-1; i > -1; i--)
- {
- let tab = descendant[i];
- if (this.isCollapsed(tab))
- continue;
-
- let box = this.getFutureBoxObject(tab);
- if (box[this.screenPositionProp] + box[this.sizeProp] - parentPosition > containerSize)
- continue;
-
- lastVisible = tab;
- break;
- }
-
- if (this.isTabInViewport(aTab) && this.isTabInViewport(lastVisible))
- return;
-
- var lastPosition = lastVisible.boxObject[this.screenPositionProp];
- var tabSize = lastVisible.boxObject[this.sizeProp];
-
- if (lastPosition - parentPosition + tabSize > containerSize - tabSize) { // out of screen
- var endPos = parentPosition - this.getFirstNormalTab(b).boxObject[this.screenPositionProp] - tabSize * 0.5;
- var endX = this.isVertical ? 0 : endPos ;
- var endY = this.isVertical ? endPos : 0 ;
- this.scrollTo(endX, endY);
- }
- else if (!this.isTabInViewport(aTab) && this.isTabInViewport(lastVisible)) {
- this.scrollToTab(aTab);
- }
- else if (this.isTabInViewport(aTab) && !this.isTabInViewport(lastVisible)) {
- this.scrollToTab(lastVisible);
- }
- else if (parentPosition < containerPosition) {
- this.scrollToTab(aTab);
- }
- else {
- this.scrollToTab(lastVisible);
- }
- },
-
- notifyBackgroundTab : function TSTBrowser_notifyBackgroundTab()
- {
- var animateElement = this.mTabBrowser.mTabContainer._animateElement;
- var attrName = this.kBG_NOTIFY_PHASE;
- if (!animateElement)
- return;
-
- if (this.deferredTasks['notifyBackgroundTab'])
- this.deferredTasks['notifyBackgroundTab'].cancel();
-
- if (!animateElement.hasAttribute(attrName))
- animateElement.setAttribute(attrName, 'ready');
-
- var self = this;
- (this.deferredTasks['notifyBackgroundTab'] = this.Deferred
- .next(function() {
- animateElement.setAttribute(attrName, 'notifying');
- }))
- .wait(0.15)
- .next(function() {
- animateElement.setAttribute(attrName, 'finish');
- })
- .wait(1)
- .next(function() {
- animateElement.removeAttribute(attrName);
- })
- .error(this.defaultDeferredErrorHandler).next(function() {
- delete self.deferredTasks['notifyBackgroundTab'];
- });
- },
-
- restoreTree : function TSTBrowser_restoreTree()
- {
- if (!this.needRestoreTree || this.useTMPSessionAPI)
- return;
-
- this.needRestoreTree = false;
-
- if (this.useTMPSessionAPI && prefs.getPref('extensions.tabmix.sessions.manager'))
- return;
-
- var level = utils.getTreePref('restoreTree.level');
-
- var tabs = this.getAllTabs(this.mTabBrowser);
- var tabsToRestore = 0; // it is the number of pending tabs.
- if (utils.SessionStoreInternal &&
- utils.SessionStoreInternal._browserEpochs) {
- let browserEpochs = utils.SessionStoreInternal._browserEpochs;
- tabsToRestore = tabs.filter(function(aTab) {
- return browserEpochs.has(aTab.linkedBrowser.permanentKey);
- }).length;
- }
- else {
- Components.utils.reportError(new Error('There is no property named "_browserEpochs"!!'));
- }
-
- dump('TSTBrowser::restoreTree\n');
- dump(' level = '+level+'\n');
- dump(' tabsToRestore = '+tabsToRestore+'\n');
- if (
- level <= this.kRESTORE_TREE_LEVEL_NONE ||
- tabsToRestore <= 1
- )
- return;
-
- var onlyVisible = level <= this.kRESTORE_TREE_ONLY_VISIBLE;
- tabs = tabs.filter(function(aTab) {
- var toBeRestored = utils.isTabNotRestoredYet(aTab);
- // This cache can be set to false by initTab(), but now we not the correct status.
- // Because this cached status is used by other methods, we must update it now.
- aTab.linkedBrowser.__treestyletab__toBeRestored = toBeRestored;
- return (
- toBeRestored &&
- (!onlyVisible || !aTab.hidden)
- );
- });
- dump(' restoring member tabs = '+tabs.length+'\n');
- if (tabs.length <= 1)
- return;
-
- for (let i = 0, maxi = tabs.length; i < maxi; i++)
- {
- let tab = tabs[i];
- let currentId = tab.getAttribute(this.kID);
- if (this.tabsHash[currentId] == tab)
- delete this.tabsHash[currentId];
-
- this.resetTabState(tab);
-
- tab.setAttribute(this.kID, currentId); // to fallback to it
- let [id, duplicated] = this._restoreTabId(tab);
-
- this.setTabValue(tab, this.kID, id);
- this.tabsHash[id] = tab;
-
- tab.__treestyletab__restoreState = this.RESTORE_STATE_READY_TO_RESTORE;
- tab.__treestyletab__duplicated = duplicated;
- }
-
- this.updateAllTabsIndent(true);
-
- // restore tree from bottom safely
- tabs.reverse()
- .filter(this.restoreOneTab, this)
- .forEach(this.updateInsertionPositionInfo, this);
- },
- restoreOneTab : function TSTBrowser_restoreOneTab(aTab)
- {
- if (aTab.__treestyletab__restoreState != this.RESTORE_STATE_READY_TO_RESTORE)
- return false;
-
- let duplicated = aTab.__treestyletab__duplicated;
-
- let children = this.getTabValue(aTab, this.kCHILDREN);
- if (children) {
- this.deleteTabValue(aTab, this.kCHILDREN);
- let manuallyExpanded = this.getTabValue(aTab, this.kSUBTREE_EXPANDED_MANUALLY) == 'true';
- let subTreeCollapsed = this.getTabValue(aTab, this.kSUBTREE_COLLAPSED) == 'true';
- subTreeCollapsed = this._restoreSubtreeCollapsedState(aTab, subTreeCollapsed);
- let self = this;
- this._restoreChildTabsRelation(aTab, children, duplicated, function(aChild) {
- /**
- * When the child has the reference to the parent tab, attachTabTo()
- * does nothing. To ensure they are correctly related, we have to
- * clear the relation here.
- */
- self.deleteTabValue(aChild, self.kPARENT);
- let refId = self.getTabValue(aChild, self.kINSERT_BEFORE);
- if (refId && duplicated)
- refId = self.redirectId(refId);
- return {
- forceExpand : true, // to prevent to collapse the selected tab
- dontAnimate : true,
- insertBefore : self.getTabById(refId)
- };
- });
- this.collapseExpandSubtree(aTab, subTreeCollapsed, true);
- if (manuallyExpanded && !subTreeCollapsed)
- this.setTabValue(aTab, this.kSUBTREE_EXPANDED_MANUALLY, true);
- else
- this.deleteTabValue(aTab, this.kSUBTREE_EXPANDED_MANUALLY);
- }
-
- delete aTab.__treestyletab__duplicated;
- aTab.__treestyletab__restoreState = this.RESTORE_STATE_STRUCTURE_RESTORED;
- return true
- },
-
-/* sub modules */
-
- get tabbarDNDObserver()
- {
- if (!this._tabbarDNDObserver) {
- this._tabbarDNDObserver = new TabbarDNDObserver(this.mTabBrowser);
- }
- return this._tabbarDNDObserver;
- },
-
- get panelDNDObserver()
- {
- if (!this._panelDNDObserver) {
- this._panelDNDObserver = new TabpanelDNDObserver(this.mTabBrowser);
- }
- return this._panelDNDObserver;
- },
-
-/* proxying for window service */
- _callWindowServiceMethod : function TSTBrowser_callWindowServiceMethod(aName, aArgs)
- {
- return this.windowService[aName].apply(this.windowService, aArgs);
- },
- isPopupShown : function TSTBrowser_isPopupShown(...aArgs) {
- return this._callWindowServiceMethod('isPopupShown', aArgs);
- },
- updateTabsOnTop : function TSTBrowser_updateTabsOnTop(...aArgs) {
- return this._callWindowServiceMethod('updateTabsOnTop', aArgs);
- },
- registerTabFocusAllowance : function TSTBrowser_registerTabFocusAllowance(...aArgs) {
- return this._callWindowServiceMethod('registerTabFocusAllowance', aArgs);
- },
- isPopupShown : function TSTBrowser_isPopupShown(...aArgs) {
- return this._callWindowServiceMethod('isPopupShown', aArgs);
- },
- toggleAutoHide : function TSTBrowser_toggleAutoHide(...aArgs) {
- return this._callWindowServiceMethod('toggleAutoHide', aArgs);
- },
-
-/* show/hide tab bar */
- get autoHide()
- {
- if (!this._autoHide) {
- this._autoHide = new AutoHideBrowser(this.mTabBrowser);
- }
- return this._autoHide;
- },
-
- // for backward compatibility
- get tabbarShown() { return this.autoHide.expanded; },
- set tabbarShown(aValue) { if (aValue) this.autoHide.show(); else this.autoHide.hide(); return aValue; },
- get tabbarExpanded() { return this.autoHide.expanded; },
- set tabbarExpanded(aValue) { return this.tabbarShown = aValue; },
- get tabbarResizing() { return this.autoHide.isResizing; },
- set tabbarResizing(aValue) { return this.autoHide.isResizing = aValue; },
- get togglerSize() { return this.autoHide.togglerSize; },
- set togglerSize(aValue) { return this.autoHide.togglerSize = aValue; },
- get sensitiveArea() { return this.autoHide.sensitiveArea; },
- set sensitiveArea(aValue) { return this.autoHide.sensitiveArea = aValue; },
- get lastMouseDownTarget() { return this.autoHide.lastMouseDownTarget; },
- set lastMouseDownTarget(aValue) { return this.autoHide.lastMouseDownTarget = aValue; },
-
- get tabbarWidth() { return this.autoHide.width; },
- set tabbarWidth(aValue) { return this.autoHide.widthwidth = aValue; },
- get tabbarHeight() { return this.autoHide.height; },
- set tabbarHeight(aValue) { return this.autoHide.height = aValue; },
- get splitterWidth() { return this.autoHide.splitterWidth; },
-
- get autoHideShown() { return this.autoHide.expanded; },
- set autoHideShown(aValue) { return this.tabbarShown = aValue; },
- get autoHideXOffset() { return this.autoHide.XOffset; },
- get autoHideYOffset() { return this.autoHide.YOffset; },
- get autoHideMode() { return this.autoHide.mode; },
- set autoHideMode(aValue) { return this.autoHide.mode = aValue; },
-
- updateAutoHideMode : function TSTBrowser_updateAutoHideMode() { this.autoHide.updateAutoHideMode(); },
- showHideTabbarInternal : function TSTBrowser_showHideTabbarInternal(aReason) { this.autoHide.showHideInternal(aReason); },
- showTabbar : function TSTBrowser_showTabbar(aReason) { this.autoHide.show(aReason); },
- hideTabbar : function TSTBrowser_hideTabbar(aReason) { this.autoHide.hide(aReason); },
- redrawContentArea : function TSTBrowser_redrawContentArea() { this.autoHide.redrawContentArea(); },
- drawTabbarCanvas : function TSTBrowser_drawTabbarCanvas() { this.autoHide.drawBG(); },
- get splitterBorderColor() { this.autoHide.splitterBorderColor; },
- clearTabbarCanvas : function TSTBrowser_clearTabbarCanvas() { this.autoHide.clearBG(); },
- updateTabbarTransparency : function TSTBrowser_updateTabbarTransparency() { this.autoHide.updateTransparency(); },
-
- get autoHideEnabled() { return this.autoHide.enabled; },
- set autoHideEnabled(aValue) { return this.autoHide.enabled = aValue; },
- startAutoHide : function TSTBrowser_startAutoHide() { this.autoHide.start(); },
- endAutoHide : function TSTBrowser_endAutoHide() { this.autoHide.end(); },
- startAutoHideForFullScreen : function TSTBrowser_startAutoHideForFullScreen() { this.autoHide.startForFullScreen(); },
- endAutoHideForFullScreen : function TSTBrowser_endAutoHideForFullScreen() { this.autoHide.endForFullScreen(); },
-
- startListenMouseMove : function TSTBrowser_startListenMouseMove() { this.autoHide.startListenMouseMove(); },
- endListenMouseMove : function TSTBrowser_endListenMouseMove() { this.autoHide.endListenMouseMove(); },
- get shouldListenMouseMove() { return this.autoHide.shouldListenMouseMove; },
- showHideTabbarOnMousemove : function TSTBrowser_showHideTabbarOnMousemove() { this.autoHide.showHideOnMousemove(); },
- cancelShowHideTabbarOnMousemove : function TSTBrowser_cancelShowHideTabbarOnMousemove() { this.autoHide.cancelShowHideOnMousemove(); },
- showTabbarForFeedback : function TSTBrowser_showTabbarForFeedback() { this.autoHide.showForFeedback(); },
- delayedShowTabbarForFeedback : function TSTBrowser_delayedShowTabbarForFeedback() { this.autoHide.delayedShowForFeedback(); },
- cancelHideTabbarForFeedback : function TSTBrowser_cancelHideTabbarForFeedback() { this.autoHide.cancelHideForFeedback(); }
-
-});
-
+/* ***** 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 YUKI "Piro" Hiroshi.
+ * Portions created by the Initial Developer are Copyright (C) 2011-2014
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s): YUKI "Piro" Hiroshi
+ * wanabe
+ * Tetsuharu OHZEKI
+ *
+ * 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 ******/
+
+const EXPORTED_SYMBOLS = ['TreeStyleTabBrowser'];
+
+const DEBUG = false;
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+const Cu = Components.utils;
+
+Cu.import('resource://gre/modules/XPCOMUtils.jsm');
+Cu.import('resource://treestyletab-modules/lib/inherit.jsm');
+
+XPCOMUtils.defineLazyModuleGetter(this, 'Services', 'resource://gre/modules/Services.jsm');
+XPCOMUtils.defineLazyModuleGetter(this, 'utils', 'resource://treestyletab-modules/utils.js', 'TreeStyleTabUtils');
+XPCOMUtils.defineLazyModuleGetter(this, 'FullTooltipManager', 'resource://treestyletab-modules/fullTooltip.js');
+XPCOMUtils.defineLazyModuleGetter(this, 'TabbarDNDObserver', 'resource://treestyletab-modules/tabbarDNDObserver.js');
+XPCOMUtils.defineLazyModuleGetter(this, 'TabpanelDNDObserver', 'resource://treestyletab-modules/tabpanelDNDObserver.js');
+XPCOMUtils.defineLazyModuleGetter(this, 'AutoHideBrowser', 'resource://treestyletab-modules/autoHide.js');
+XPCOMUtils.defineLazyModuleGetter(this, 'BrowserUIShowHideObserver', 'resource://treestyletab-modules/browserUIShowHideObserver.js');
+
+XPCOMUtils.defineLazyGetter(this, 'window', function() {
+ Cu.import('resource://treestyletab-modules/lib/namespace.jsm');
+ return getNamespaceFor('piro.sakura.ne.jp');
+});
+XPCOMUtils.defineLazyGetter(this, 'prefs', function() {
+ Cu.import('resource://treestyletab-modules/lib/prefs.js');
+ return window['piro.sakura.ne.jp'].prefs;
+});
+
+Cu.import('resource://treestyletab-modules/window.js');
+
+function TreeStyleTabBrowser(aWindowService, aTabBrowser)
+{
+ this.id = Date.now() + '-' + parseInt(Math.random() * 65000);
+
+ this.windowService = aWindowService;
+ this.window = aWindowService.window;
+ this.document = aWindowService.document;
+
+ this.mTabBrowser = aTabBrowser;
+ aTabBrowser.treeStyleTab = this;
+
+ this.tabVisibilityChangedTabs = [];
+ this.updateTabsIndentWithDelayTabs = [];
+ this.deferredTasks = {};
+
+ this.tabVisibilityChangedTabs = [];
+ this._updateFloatingTabbarReason = 0;
+ this.internallyTabMovingCount = 0;
+ this.subTreeMovingCount = 0;
+ this.subTreeChildrenMovingCount = 0;
+ this._treeViewEnabled = true;
+}
+
+TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
+
+ kMENUITEM_RELOADSUBTREE : 'context-item-reloadTabSubtree',
+ kMENUITEM_RELOADCHILDREN : 'context-item-reloadDescendantTabs',
+ kMENUITEM_REMOVESUBTREE : 'context-item-removeTabSubtree',
+ kMENUITEM_REMOVECHILDREN : 'context-item-removeDescendantTabs',
+ kMENUITEM_REMOVEALLTABSBUT : 'context-item-removeAllTabsButThisTree',
+ kMENUITEM_COLLAPSEEXPAND_SEPARATOR : 'context-separator-collapseExpandAll',
+ kMENUITEM_COLLAPSE : 'context-item-collapseAllSubtree',
+ kMENUITEM_EXPAND : 'context-item-expandAllSubtree',
+ kMENUITEM_AUTOHIDE_SEPARATOR : 'context-separator-toggleAutoHide',
+ kMENUITEM_AUTOHIDE : 'context-item-toggleAutoHide',
+ kMENUITEM_FIXED : 'context-item-toggleFixed',
+ kMENUITEM_BOOKMARKSUBTREE : 'context-item-bookmarkTabSubtree',
+
+ kMENUITEM_CLOSE_TABS_TO_END : 'context_closeTabsToTheEnd',
+
+ mTabBrowser : null,
+
+ indent : -1,
+ indentProp : 'margin',
+ indentTarget : 'left',
+ indentCSSProp : 'margin-left',
+ collapseTarget : 'top',
+ collapseCSSProp : 'margin-top',
+ screenPositionProp : 'screenY',
+ offsetProp : 'offsetY',
+ translateFunction : 'translateY',
+ sizeProp : 'height',
+ invertedScreenPositionProp : 'screenX',
+ invertedSizeProp : 'width',
+ startProp : 'top',
+ endProp : 'bottom',
+
+ maxTreeLevelPhisical : false,
+
+ needRestoreTree : false,
+
+/* elements */
+
+ get browser()
+ {
+ return this.mTabBrowser;
+ },
+
+ get container()
+ {
+ if (!this._container) {
+ this._container = this.document.getElementById('appcontent');
+ }
+ return this._container;
+ },
+ _container : null,
+
+ get scrollBox()
+ {
+ return ( // Tab Mix Plus
+ utils.getTreePref('compatibility.TMP') &&
+ this.document.getAnonymousElementByAttribute(this.mTabBrowser.mTabContainer, 'class', 'tabs-frame')
+ ) ||
+ this.mTabBrowser.mTabContainer.mTabstrip;
+ },
+ get scrollBoxObject()
+ {
+ var node = this.scrollBox;
+ if (node._scrollbox)
+ node = node._scrollbox;
+ return (node.scrollBoxObject || node.boxObject)
+ .QueryInterface(Ci.nsIScrollBoxObject); // for Tab Mix Plus (ensure scrollbox-ed)
+ },
+
+ get splitter()
+ {
+ var d = this.document;
+ return d.getAnonymousElementByAttribute(this.mTabBrowser, 'class', this.kSPLITTER) ||
+ d.getAnonymousElementByAttribute(this.mTabBrowser, 'id', 'tabkit-splitter'); // Tab Kit
+ },
+
+ get tabStripPlaceHolder()
+ {
+ return this._tabStripPlaceHolder;
+ },
+ set tabStripPlaceHolder(value)
+ {
+ return (this._tabStripPlaceHolder = value);
+ },
+
+/* properties */
+
+ get maxTreeLevel()
+ {
+ return this._maxTreeLevel;
+ },
+ set maxTreeLevel(aValue)
+ {
+ this._maxTreeLevel = aValue;
+ this.setTabbrowserAttribute(this.kMAX_LEVEL, this._maxTreeLevel || '0');
+ this.enableSubtreeIndent = this._maxTreeLevel != 0;
+ return aValue;
+ },
+ _maxTreeLevel : -1,
+
+ get baseIndent() {
+ return this.isVertical ? this.baseIndentVertical : this.baseIndentHorizontal;
+ },
+
+ get enableSubtreeIndent()
+ {
+ return this._enableSubtreeIndent;
+ },
+ set enableSubtreeIndent(aValue)
+ {
+ this._enableSubtreeIndent = aValue;
+ this.setTabbrowserAttribute(this.kINDENTED, this._enableSubtreeIndent ? 'true' : null);
+ return aValue;
+ },
+ _enableSubtreeIndent : true,
+
+ get allowSubtreeCollapseExpand()
+ {
+ return this._allowSubtreeCollapseExpand;
+ },
+ set allowSubtreeCollapseExpand(aValue)
+ {
+ this._allowSubtreeCollapseExpand = aValue;
+ this.setTabbrowserAttribute(this.kALLOW_COLLAPSE, this._allowSubtreeCollapseExpand ? 'true' : null);
+ return aValue;
+ },
+ _allowSubtreeCollapseExpand : true,
+
+ get fixed()
+ {
+ var orient = this.isVertical ? 'vertical' : 'horizontal' ;
+ if (!this.windowService.preInitialized)
+ return utils.getTreePref('tabbar.fixed.'+orient);
+
+ var b = this.mTabBrowser;
+ if (!b)
+ return false;
+ return b.getAttribute(this.kFIXED+'-'+orient) == 'true';
+ },
+ set fixed(aValue)
+ {
+ this.setTabbrowserAttribute(this.kFIXED, aValue || null, this.mTabBrowser);
+ return aValue;
+ },
+ get isFixed() // for backward compatibility
+ {
+ return this.fixed;
+ },
+
+ get position() /* PUBLIC API */
+ {
+ return (
+ // Don't touch to the element before it is initialized by XBL constructor.
+ (this.windowService.preInitialized && this.browser.getAttribute(this.kTABBAR_POSITION)) ||
+ this.base.position
+ );
+ },
+ set position(aValue)
+ {
+ var position = String(aValue).toLowerCase();
+ if (!position || !/^(top|bottom|left|right)$/.test(position))
+ position = 'top';
+
+ if (position == this.position)
+ return position;
+
+ if ('UndoTabService' in this.window && this.window.UndoTabService.isUndoable()) {
+ var current = this.position;
+ var self = this;
+ this.window.UndoTabService.doOperation(
+ function() {
+ self._changeTabbarPosition(position);
+ },
+ {
+ label : utils.treeBundle.getString('undo_changeTabbarPosition_label'),
+ name : 'treestyletab-changeTabbarPosition-private',
+ data : {
+ oldPosition : current,
+ newPosition : position,
+ target : self.mTabBrowser.id
+ }
+ }
+ );
+ }
+ else {
+ this._changeTabbarPosition(position);
+ }
+ return position;
+ },
+ _changeTabbarPosition : function TSTBrowser_changeTabbarPosition(aNewPosition)
+ {
+ if (this.deferredTasks['_changeTabbarPosition'])
+ this.deferredTasks['_changeTabbarPosition'].cancel();
+
+ var oldPosition = this.position;
+ this.fireTabbarPositionEvent(true, oldPosition, aNewPosition);
+
+ this.initTabbar(aNewPosition, oldPosition);
+ this.reinitAllTabs();
+
+ var self = this;
+ (this.deferredTasks['_changeTabbarPosition'] = this.Deferred.next(function() {
+ self.checkTabsIndentOverflow();
+ self.fireTabbarPositionEvent(false, oldPosition, aNewPosition);
+ })).error(this.defaultDeferredErrorHandler).next(function() {
+ delete self.deferredTasks['_changeTabbarPosition'];
+ });
+ },
+
+/* status getters */
+
+ get isVertical()
+ {
+ if (!this.windowService.preInitialized)
+ return ['left', 'right'].indexOf(this.position) > -1;
+
+ var b = this.mTabBrowser;
+ if (!b)
+ return false;
+
+ if (b.hasAttribute(this.kMODE))
+ return b.getAttribute(this.kMODE) == 'vertical';
+
+ var box = this.scrollBox || b.mTabContainer ;
+ return (box.getAttribute('orient') || this.window.getComputedStyle(box, '').getPropertyValue('-moz-box-orient')) == 'vertical';
+ },
+
+ get isVisible()
+ {
+ var bar = this.ownerToolbar;
+ var style = this.window.getComputedStyle(bar, '');
+ if (style.visibility != 'visible' || style.display == 'none')
+ return false;
+
+ var box = bar.boxObject;
+ return !!(box.width || box.height);
+ },
+
+ isFloating : true, // for backward compatibility (but this should be removed)
+
+ get ownerToolbar()
+ {
+ return this.evaluateXPath(
+ 'ancestor-or-self::xul:toolbar[1]',
+ this.mTabBrowser.tabContainer,
+ Ci.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE
+ ).singleNodeValue;
+ },
+
+ get canStackTabs()
+ {
+ return (
+ !this.isVertical &&
+ this.canCollapseSubtree() &&
+ utils.getTreePref('stackCollapsedTabs')
+ );
+ },
+
+ get counterRole()
+ {
+ return this.isVertical ? this.counterRoleVertical : this.counterRoleHorizontal ;
+ },
+
+ get isDestroying()
+ {
+ return !this.mTabBrowser || !this.mTabBrowser.mTabContainer;
+ },
+
+/* utils */
+
+/* get tab contents */
+
+ getTabLabel : function TSTBrowser_getTabLabel(aTab)
+ {
+ var d = this.document;
+ var label = d.getAnonymousElementByAttribute(aTab, 'class', 'tab-text-stack') || // Mac OS X
+ ( // Tab Mix Plus
+ utils.getTreePref('compatibility.TMP') &&
+ d.getAnonymousElementByAttribute(aTab, 'class', 'tab-text-container')
+ ) ||
+ d.getAnonymousElementByAttribute(aTab, 'class', 'tab-text tab-label');
+ return label;
+ },
+
+ getTabClosebox : function TSTBrowser_getTabClosebox(aTab)
+ {
+ var d = this.document;
+ var close = ( // Tab Mix Plus
+ utils.getTreePref('compatibility.TMP') &&
+ d.getAnonymousElementByAttribute(aTab, 'class', 'tab-close-button always-right')
+ ) ||
+ d.getAnonymousElementByAttribute(aTab, 'anonid', 'close-button') || // with Australis
+ d.getAnonymousElementByAttribute(aTab, 'class', 'tab-close-button');
+ return close;
+ },
+
+ getTabTwisty : function TSTBrowser_getTabTwisty(aTab)
+ {
+ return this.document.getAnonymousElementByAttribute(aTab, 'class', this.kTWISTY);
+ },
+
+ getTabTwistyAnchorNode : function TSTBrowser_getTabTwistyAnchorNode(aTab)
+ {
+ return this.document.getAnonymousElementByAttribute(aTab, 'class', 'tab-icon') || // Tab Mix Plus
+ this.document.getAnonymousElementByAttribute(aTab, 'class', 'tab-throbber');
+ },
+
+ getTabFromTabbarEvent : function TSTBrowser_getTabFromTabbarEvent(aEvent)
+ {
+ if (
+ !this.shouldDetectClickOnIndentSpaces ||
+ !this.getAncestorTabbarFromEvent(aEvent) ||
+ this.isEventFiredOnClickable(aEvent) ||
+ this.getSplitterFromEvent(aEvent)
+ )
+ return null;
+ return this.getTabFromCoordinates(aEvent);
+ },
+ getTabFromCoordinates : function TSTBrowser_getTabFromCoordinates(aCoordinates, aTabs)
+ {
+ var tab = this.document.elementFromPoint(aCoordinates.clientX, aCoordinates.clientY);
+ if (tab && tab.localName == 'tab' && (!aTabs || aTabs.indexOf(tab) > -1))
+ return tab;
+
+ var positionCoordinate = aCoordinates[this.screenPositionProp];
+
+ var tabs = aTabs || this.getTabs(this.mTabBrowser);
+ if (!tabs.length ||
+ this.getTabActualScreenPosition(tabs[0]) > positionCoordinate ||
+ this.getTabActualScreenPosition(tabs[tabs.length-1]) < positionCoordinate)
+ return null;
+
+ var low = 0;
+ var high = tabs.length - 1;
+ while (low <= high) {
+ let middle = Math.floor((low + high) / 2);
+ let position = this.getTabActualScreenPosition(tabs[middle]);
+ if (position > positionCoordinate) {
+ high = middle - 1;
+ }
+ else if (position + tabs[middle].boxObject[this.sizeProp] < positionCoordinate) {
+ low = middle + 1;
+ }
+ else {
+ return tabs[middle];
+ }
+ }
+ return null;
+/*
+ var tab = null;
+ this.getTabs(this.mTabBrowser).some(function(aTab) {
+ var box = aTab.boxObject;
+ if (box[this.screenPositionProp] > positionCoordinate ||
+ box[this.screenPositionProp] + box[this.sizeProp] < positionCoordinate) {
+ return false;
+ }
+ tab = aTab;
+ return true;
+ }, this);
+ return tab;
+*/
+ },
+
+ getNextFocusedTab : function TSTBrowser_getNextFocusedTab(aTab)
+ {
+ return this.getNextSiblingTab(aTab) ||
+ this.getPreviousVisibleTab(aTab);
+ },
+
+ isTabInViewport : function TSTBrowser_isTabInViewport(aTab)
+ {
+ if (!this.windowService.preInitialized || !aTab)
+ return false;
+ if (aTab.getAttribute('pinned') == 'true')
+ return true;
+ var tabBox = this.getFutureBoxObject(aTab);
+ var barBox = this.scrollBox.boxObject;
+ return (
+ tabBox.screenX >= barBox.screenX &&
+ tabBox.screenX + tabBox.width <= barBox.screenX + barBox.width &&
+ tabBox.screenY >= barBox.screenY &&
+ tabBox.screenY + tabBox.height <= barBox.screenY + barBox.height
+ );
+ },
+
+ isMultiRow : function TSTBrowser_isMultiRow()
+ {
+ var w = this.window;
+ return ('tabberwocky' in w && utils.getTreePref('compatibility.Tabberwocky')) ?
+ (prefs.getPref('tabberwocky.multirow') && !this.isVertical) :
+ ('TabmixTabbar' in w && utils.getTreePref('compatibility.TMP')) ?
+ w.TabmixTabbar.isMultiRow :
+ false ;
+ },
+
+ positionPinnedTabs : function TSTBrowser_positionPinnedTabs(aWidth, aHeight, aJustNow)
+ {
+ var b = this.mTabBrowser;
+ var tabbar = b.tabContainer;
+ if (
+ !tabbar ||
+ !tabbar._positionPinnedTabs ||
+ !tabbar.boxObject.width
+ )
+ return;
+
+ var count = this.pinnedTabsCount;
+ if (!this.isVertical || !count) {
+ this.resetPinnedTabs();
+ b.mTabContainer._positionPinnedTabs();
+ return;
+ }
+
+ var tabbarPlaceHolderWidth = this._tabStripPlaceHolder.boxObject.width;
+ var tabbarWidth = this.tabStrip.boxObject.width;
+
+ var maxWidth = tabbarPlaceHolderWidth || tabbarWidth;
+
+ var faviconized = utils.getTreePref('pinnedTab.faviconized');
+ var faviconizedSize = tabbar.childNodes[0].boxObject.height;
+
+ var width = faviconized ? faviconizedSize : maxWidth ;
+ var height = faviconizedSize;
+ var maxCol = Math.max(1, Math.floor(maxWidth / width));
+ var maxRow = Math.ceil(count / maxCol);
+ var col = 0;
+ var row = 0;
+
+ var baseX = this.tabStrip.boxObject.screenX - this.document.documentElement.boxObject.screenX;
+
+ var shrunkenOffset = (this.position == 'right' && tabbarPlaceHolderWidth) ?
+ tabbarWidth - tabbarPlaceHolderWidth :
+ 0 ;
+
+ var removeFaviconizedClassPattern = new RegExp('\\s+'+this.kFAVICONIZED, 'g');
+
+ tabbar.style.MozMarginStart = '';
+ tabbar.style.setProperty('margin-top', (height * maxRow)+'px', 'important');
+ for (let i = 0; i < count; i++)
+ {
+ let item = tabbar.childNodes[i];
+
+ let style = item.style;
+ style.MozMarginStart = '';
+
+ let transitionStyleBackup = style.transition || style.MozTransition || '';
+ if (aJustNow)
+ style.MozTransition = style.transition = 'none';
+
+ let className = item.className.replace(removeFaviconizedClassPattern, '');
+ if (faviconized)
+ className += ' '+this.kFAVICONIZED;
+ if (className != item.className)
+ item.className = className;
+
+ style.maxWidth = style.width = width+'px';
+ style.setProperty('margin-left', ((width * col) + shrunkenOffset)+'px', 'important');
+ style.left = baseX+'px';
+ style.right = 'auto';
+ style.marginRight = '';
+
+ style.setProperty('margin-top', (- height * (maxRow - row))+'px', 'important');
+ style.top = style.bottom = '';
+
+ if (aJustNow) {
+ let key = 'positionPinnedTabs_tab_'+parseInt(Math.random() * 65000);
+ (this.deferredTasks[key] = this.Deferred.next(function() { // "transition" must be cleared after the reflow.
+ style.MozTransition = style.transition = transitionStyleBackup;
+ })).error(this.defaultDeferredErrorHandler).next(function() {
+ delete self.deferredTasks[key];
+ });
+ }
+
+ col++;
+ if (col >= maxCol) {
+ col = 0;
+ row++;
+ }
+ }
+ },
+ positionPinnedTabsWithDelay : function TSTBrowser_positionPinnedTabsWithDelay(...aArgs)
+ {
+ if (this.deferredTasks['positionPinnedTabsWithDelay'])
+ return;
+
+ var lastArgs = this.deferredTasks['positionPinnedTabsWithDelay'] ?
+ this.deferredTasks['positionPinnedTabsWithDelay'].__treestyletab__args :
+ [null, null, false] ;
+ lastArgs[0] = lastArgs[0] || aArgs[0];
+ lastArgs[1] = lastArgs[1] || aArgs[1];
+ lastArgs[2] = lastArgs[2] || aArgs[2];
+
+ var self = this;
+ (this.deferredTasks['positionPinnedTabsWithDelay'] = this.Deferred.wait(0).next(function() {
+ return self.Deferred.next(function() {
+ // do with delay again, after Firefox's reposition was completely finished.
+ self.positionPinnedTabs.apply(self, lastArgs);
+ });
+ })).error(this.defaultDeferredErrorHandler).next(function() {
+ delete self.deferredTasks['positionPinnedTabsWithDelay'];
+ });
+ this.deferredTasks['positionPinnedTabsWithDelay'].__treestyletab__args = lastArgs;
+ },
+
+ resetPinnedTabs : function TSTBrowser_resetPinnedTabs()
+ {
+ var b = this.mTabBrowser;
+ var tabbar = b.tabContainer;
+ tabbar.style.MozMarginStart = tabbar.style.marginTop = '';
+ for (var i = 0, count = this.pinnedTabsCount; i < count; i++)
+ {
+ let style = tabbar.childNodes[i].style;
+ style.maxWidth = style.width = style.left = style.right =
+ style.MozMarginStart = style.marginLeft = style.marginRight = style.marginTop = '';
+ }
+ },
+
+ updateTabsZIndex : function TSTBrowser_updateTabsZIndex(aStacked)
+ {
+ var tabs = this.getTabs(this.mTabBrowser);
+ var count = tabs.length;
+ for (let i = 0; i < count; i++)
+ {
+ let tab = tabs[i];
+ if (aStacked)
+ tab.style.zIndex = count * 1000 - i;
+ else
+ tab.style.zIndex = '';
+ }
+ },
+
+ fixTooNarrowTabbar : function TSTBrowser_fixTooNarrowTabbar()
+ {
+ /**
+ * The tab bar can become smaller than the actual size of the
+ * floating tab bar, and then, we cannot resize tab bar by
+ * dragging anymore. To avoid this problem, we have to enlarge
+ * the tab bar larger than the floating tab bar.
+ */
+ if (this.isVertical) {
+ let key = this.autoHide.expanded ?
+ 'tabbar.width' : 'tabbar.shrunkenWidth' ;
+ let width = utils.getTreePref(key);
+ let minWidth = Math.max(this.MIN_TABBAR_WIDTH, this.scrollBox.boxObject.width);
+ if (minWidth > width) {
+ this.setPrefForActiveWindow(function() {
+ utils.setTreePref(key, minWidth);
+ this.updateFloatingTabbar(this.kTABBAR_UPDATE_BY_PREF_CHANGE);
+ });
+ }
+ }
+ else {
+ let height = utils.getTreePref('tabbar.height');
+ let minHeight = Math.max(this.MIN_TABBAR_HEIGHT, this.scrollBox.boxObject.height);
+ if (minHeight > height) {
+ this.setPrefForActiveWindow(function() {
+ utils.setTreePref('tabbar.height', minHeight);
+ this.updateFloatingTabbar(this.kTABBAR_UPDATE_BY_PREF_CHANGE);
+ });
+ }
+ }
+ },
+
+/* initialize */
+
+ init : function TSTBrowser_init()
+ {
+ this.stopRendering();
+
+ var w = this.window;
+ var d = this.document;
+ var b = this.mTabBrowser;
+ b.tabContainer.treeStyleTab = this;
+
+ this.tabsHash = {};
+
+ if (b.tabContainer.parentNode.localName == 'toolbar')
+ b.tabContainer.parentNode.classList.add(this.kTABBAR_TOOLBAR);
+
+ /**
+ * On secondary (and later) window, SSWindowStateBusy event can be fired
+ * before DOMContentLoad, on "domwindowopened".
+ */
+ this.needRestoreTree = w.__treestyletab__WindowStateBusy || false;
+ delete w.__treestyletab__WindowStateBusy;
+
+ this._initTabbrowserExtraContents();
+
+ var position = this.position;
+ this.fireTabbarPositionEvent(this.kEVENT_TYPE_TABBAR_POSITION_CHANGING, 'top', position); /* PUBLIC API */
+
+ this.setTabbrowserAttribute(this.kFIXED+'-horizontal', utils.getTreePref('tabbar.fixed.horizontal') ? 'true' : null, b);
+ this.setTabbrowserAttribute(this.kFIXED+'-vertical', utils.getTreePref('tabbar.fixed.vertical') ? 'true' : null, b);
+ this.setTabStripAttribute(this.kTAB_STRIP_ELEMENT, true);
+
+ /**
+ * has its custom background color for itself, but it
+ * prevents to make transparent background of the vertical tab bar.
+ * So, I re-define the background color of content area for
+ * es via dynamically generated stylesheet.
+ * See:
+ * https://bugzilla.mozilla.org/show_bug.cgi?id=558585
+ * http://hg.mozilla.org/mozilla-central/rev/e90bdd97d168
+ */
+ if (b.style.backgroundColor) {
+ let color = b.style.backgroundColor;
+ let pi = d.createProcessingInstruction(
+ 'xml-stylesheet',
+ 'type="text/css" href="data:text/css,'+encodeURIComponent(
+ ('.tabbrowser-tabbox > tabpanels > notificationbox {\n' +
+ ' background-color: %COLOR%;\n' +
+ '}').replace(/%COLOR%/, color)
+ )+'"'
+ );
+ d.insertBefore(pi, d.documentElement);
+ b.style.backgroundColor = '';
+ }
+
+ this.initTabbar(null, this.kTABBAR_TOP);
+
+ w.addEventListener('resize', this, true);
+ w.addEventListener('beforecustomization', this, true);
+ w.addEventListener('aftercustomization', this, false);
+ w.addEventListener('customizationchange', this, false);
+ w.addEventListener(this.kEVENT_TYPE_PRINT_PREVIEW_ENTERED, this, false);
+ w.addEventListener(this.kEVENT_TYPE_PRINT_PREVIEW_EXITED, this, false);
+ w.addEventListener('tabviewframeinitialized', this, false);
+ w.addEventListener(this.kEVENT_TYPE_TAB_FOCUS_SWITCHING_END, this, false);
+ w.addEventListener('SSWindowStateBusy', this, false);
+
+ b.addEventListener('nsDOMMultipleTabHandlerTabsClosing', this, false);
+
+ w['piro.sakura.ne.jp'].tabsDragUtils.initTabBrowser(b);
+
+ w.TreeStyleTabWindowHelper.initTabbrowserMethods(b);
+ this._initTabbrowserContextMenu();
+ w.TreeStyleTabWindowHelper.updateTabDNDObserver(b);
+
+ this.getAllTabs(b).forEach(this.initTab, this);
+
+ this.onPrefChange('extensions.treestyletab.maxTreeLevel');
+ this.onPrefChange('extensions.treestyletab.tabbar.style');
+ this.onPrefChange('extensions.treestyletab.twisty.style');
+ this.onPrefChange('extensions.treestyletab.showBorderForFirstTab');
+ this.onPrefChange('extensions.treestyletab.tabbar.invertTabContents');
+ this.onPrefChange('extensions.treestyletab.tabbar.invertClosebox');
+ this.onPrefChange('extensions.treestyletab.tabbar.autoShow.mousemove');
+ this.onPrefChange('extensions.treestyletab.tabbar.invertScrollbar');
+ this.onPrefChange('extensions.treestyletab.tabbar.narrowScrollbar');
+ this.onPrefChange('browser.tabs.animate');
+
+ Services.obs.addObserver(this, this.kTOPIC_INDENT_MODIFIED, false);
+ Services.obs.addObserver(this, this.kTOPIC_COLLAPSE_EXPAND_ALL, false);
+ Services.obs.addObserver(this, this.kTOPIC_CHANGE_TREEVIEW_AVAILABILITY, false);
+ Services.obs.addObserver(this, 'lightweight-theme-styling-update', false);
+ prefs.addPrefListener(this);
+
+ // Don't init these ovservers on this point to avoid needless initializations.
+ // this.tabbarDNDObserver;
+ // this.panelDNDObserver;
+ this._readyToInitDNDObservers();
+
+ // Init autohide service only if it have to be activated.
+ if (this.isAutoHide)
+ this.autoHide;
+
+ this.updateFloatingTabbar(this.kTABBAR_UPDATE_BY_INITIALIZE);
+ this.fixTooNarrowTabbar();
+
+ this.fireTabbarPositionEvent(false, 'top', position); /* PUBLIC API */
+
+ this.startRendering();
+
+ if (this.deferredTasks['init'])
+ this.deferredTasks['init'].cancel();
+
+ var self = this;
+ (this.deferredTasks['init'] = this.Deferred.next(function() {
+ // This command is always enabled and the TabsOnTop can be enabled
+ // by .updateVisibility().
+ // So we have to reset TabsOnTop state on the startup.
+ var toggleTabsOnTop = d.getElementById('cmd_ToggleTabsOnTop');
+ var TabsOnTop = 'TabsOnTop' in w ? w.TabsOnTop : null ;
+ if (TabsOnTop && TabsOnTop.syncUI && toggleTabsOnTop && self.isVertical) {
+ toggleTabsOnTop.setAttribute('disabled', true);
+ if (TabsOnTop.enabled && TabsOnTop.toggle)
+ TabsOnTop.toggle();
+ }
+ })).error(this.defaultDeferredErrorHandler).next(function() {
+ delete self.deferredTasks['init'];
+ });
+ },
+
+ _initTabbrowserExtraContents : function TSTBrowser_initTabbrowserExtraContents()
+ {
+ var d = this.document;
+ var b = this.mTabBrowser;
+
+ var toggler = d.getAnonymousElementByAttribute(b, 'class', this.kTABBAR_TOGGLER);
+ if (!toggler) {
+ toggler = d.createElement('spacer');
+ toggler.setAttribute(this.kTAB_STRIP_ELEMENT, true);
+ toggler.setAttribute('class', this.kTABBAR_TOGGLER);
+ toggler.setAttribute('layer', true); // https://bugzilla.mozilla.org/show_bug.cgi?id=590468
+ b.mTabBox.insertBefore(toggler, b.mTabBox.firstChild);
+ if (b.mTabDropIndicatorBar == toggler)
+ b.mTabDropIndicatorBar = d.getAnonymousElementByAttribute(b, 'class', 'tab-drop-indicator-bar');
+ }
+
+ var placeHolder = d.getAnonymousElementByAttribute(b, 'anonid', 'strip');
+ if (!placeHolder) {
+ placeHolder = d.createElement('hbox');
+ placeHolder.setAttribute(this.kTAB_STRIP_ELEMENT, true);
+ placeHolder.setAttribute('anonid', 'strip');
+ placeHolder.setAttribute('class', 'tabbrowser-strip '+this.kTABBAR_PLACEHOLDER);
+ placeHolder.setAttribute('layer', true); // https://bugzilla.mozilla.org/show_bug.cgi?id=590468
+ b.mTabBox.insertBefore(placeHolder, toggler.nextSibling);
+ }
+ this.tabStripPlaceHolder = (placeHolder != this.tabStrip) ? placeHolder : null ;
+
+ if (this.tabStripPlaceHolder)
+ this.tabStripPlaceHolderBoxObserver = new BrowserUIShowHideObserver(this, this.tabStripPlaceHolder.parentNode);
+ },
+
+ _initTabbrowserContextMenu : function TSTBrowser_initTabbrowserContextMenu()
+ {
+ var w = this.window;
+ var d = this.document;
+ var b = this.mTabBrowser;
+
+ var tabContextMenu = b.tabContextMenu ||
+ d.getAnonymousElementByAttribute(b, 'anonid', 'tabContextMenu');
+ tabContextMenu.addEventListener('popupshowing', this, false);
+ if (!('MultipleTabService' in w)) {
+ w.setTimeout(function(aSelf, aTabBrowser, aPopup) {
+ let suffix = '-tabbrowser-'+(aTabBrowser.id || 'instance-'+parseInt(Math.random() * 65000));
+ let ids = [
+ aSelf.kMENUITEM_RELOADSUBTREE,
+ aSelf.kMENUITEM_RELOADCHILDREN,
+ aSelf.kMENUITEM_REMOVESUBTREE,
+ aSelf.kMENUITEM_REMOVECHILDREN,
+ aSelf.kMENUITEM_REMOVEALLTABSBUT,
+ aSelf.kMENUITEM_COLLAPSEEXPAND_SEPARATOR,
+ aSelf.kMENUITEM_COLLAPSE,
+ aSelf.kMENUITEM_EXPAND,
+ aSelf.kMENUITEM_AUTOHIDE_SEPARATOR,
+ aSelf.kMENUITEM_AUTOHIDE,
+ aSelf.kMENUITEM_FIXED,
+ aSelf.kMENUITEM_BOOKMARKSUBTREE
+ ];
+ for (let i = 0, maxi = ids.length; i < maxi; i++)
+ {
+ let id = ids[i];
+ let item = d.getElementById(id).cloneNode(true);
+ item.setAttribute('id', item.getAttribute('id')+suffix);
+
+ let refNode = void(0);
+ let insertAfter = item.getAttribute('multipletab-insertafter');
+ if (insertAfter) {
+ try {
+ eval('refNode = ('+insertAfter+').nextSibling');
+ }
+ catch(e) {
+ }
+ }
+ let insertBefore = item.getAttribute('multipletab-insertbefore');
+ if (refNode === void(0) && insertBefore) {
+ try {
+ eval('refNode = '+insertBefore);
+ }
+ catch(e) {
+ }
+ }
+ aPopup.insertBefore(item, refNode || null);
+ }
+ tabContextMenu = null;
+ }, 0, this, b, tabContextMenu);
+ }
+
+ let closeTabsToEnd = d.getElementById(this.kMENUITEM_CLOSE_TABS_TO_END);
+ if (closeTabsToEnd) {
+ this._closeTabsToEnd_horizontalLabel = closeTabsToEnd.getAttribute('label');
+ this._closeTabsToEnd_horizontalAccesskey = closeTabsToEnd.getAttribute('accesskey');
+ }
+
+ var removeTabItem = d.getAnonymousElementByAttribute(b, 'id', 'context_closeTab');
+ if (removeTabItem) {
+ removeTabItem.setAttribute(
+ 'oncommand',
+ removeTabItem.getAttribute('oncommand').replace(
+ /(tabbrowser\.removeTab\(([^\)]+)\))/,
+ 'if (tabbrowser.treeStyleTab.warnAboutClosingTabSubtreeOf($2)) $1'
+ )
+ );
+ }
+ },
+
+ _initTooltipManager : function TSTBrowser_initTooltipManager()
+ {
+ if (this.tooltipManager)
+ return;
+
+ this.tooltipManager = new FullTooltipManager(this);
+ },
+
+ _readyToInitDNDObservers : function TSTBrowser_readyToInitDNDObservers()
+ {
+ var w = this.window;
+ this._DNDObserversInitialized = false;
+ w.addEventListener('mouseover', this, true);
+ w.addEventListener('dragover', this, true);
+ },
+
+ _initDNDObservers : function TSTBrowser_initDNDObservers()
+ {
+ if (this._DNDObserversInitialized)
+ return;
+
+ this.tabbarDNDObserver;
+ this.panelDNDObserver;
+
+ var w = this.window;
+ w.removeEventListener('mouseover', this, true);
+ w.removeEventListener('dragover', this, true);
+ this._DNDObserversInitialized = true;
+ },
+
+ initTab : function TSTBrowser_initTab(aTab)
+ {
+ if (!aTab.parentNode) // do nothing for closed tab!
+ return;
+
+ if (!aTab.hasAttribute(this.kID)) {
+ let id = this.getTabValue(aTab, this.kID) || this.makeNewId();
+ aTab.setAttribute(this.kID, id);
+ aTab.setAttribute(this.kID_NEW, id);
+ aTab.setAttribute(this.kSUBTREE_COLLAPSED, true);
+ aTab.setAttribute(this.kALLOW_COLLAPSE, true);
+ let self = this;
+ let key = 'initTab_'+id;
+ if (this.deferredTasks[key])
+ this.deferredTasks[key].cancel();
+ (this.deferredTasks[key] = this.Deferred.next(function() {
+ // changed by someone!
+ if (aTab.getAttribute(self.kID) != id)
+ return;
+
+ aTab.removeAttribute(this.kID_NEW);
+ if (!self.getTabValue(aTab, self.kID)) {
+ self.setTabValue(aTab, self.kID, id);
+ if (!(id in self.tabsHash))
+ self.tabsHash[id] = aTab;
+ }
+ })).error(this.defaultDeferredErrorHandler).next(function() {
+ delete self.deferredTasks[key];
+ });
+ if (!(id in this.tabsHash))
+ this.tabsHash[id] = aTab;
+ }
+ else {
+ // if the tab is restored from session, it can be not-cached.
+ let id = aTab.getAttribute(this.kID);
+ if (!(id in this.tabsHash))
+ this.tabsHash[id] = aTab;
+ }
+
+ aTab.__treestyletab__linkedTabBrowser = this.mTabBrowser;
+
+ if (!aTab.linkedBrowser.__treestyletab__toBeRestored)
+ aTab.linkedBrowser.__treestyletab__toBeRestored = utils.isTabNotRestoredYet(aTab);
+
+ this.initTabAttributes(aTab);
+ this.initTabContents(aTab);
+
+ if (!aTab.hasAttribute(this.kNEST))
+ aTab.setAttribute(this.kNEST, 0);
+ },
+
+ isTabInitialized : function TSTBrowser_isTabInitialized(aTab)
+ {
+ return aTab.getAttribute(this.kID);
+ },
+
+ ensureTabInitialized : function TSTBrowser_ensureTabInitialized(aTab)
+ {
+ if (!aTab || this.isTabInitialized(aTab))
+ return;
+ this.initTab(aTab);
+ },
+
+ initTabAttributes : function TSTBrowser_initTabAttributes(aTab)
+ {
+ if (!aTab.parentNode) // do nothing for closed tab!
+ return;
+
+ var pos = this.position;
+ if (pos == 'left' || pos == 'right') {
+ aTab.setAttribute('align', 'stretch');
+ aTab.removeAttribute('maxwidth');
+ aTab.removeAttribute('minwidth');
+ aTab.removeAttribute('width');
+ aTab.removeAttribute('flex');
+ aTab.maxWidth = 65000;
+ aTab.minWidth = 0;
+ if (utils.getTreePref('compatibility.TMP'))
+ aTab.setAttribute('dir', 'ltr'); // Tab Mix Plus
+ }
+ else {
+ aTab.removeAttribute('align');
+ aTab.removeAttribute('maxwidth');
+ aTab.removeAttribute('minwidth');
+ if (utils.getTreePref('compatibility.TMP'))
+ aTab.removeAttribute('dir'); // Tab Mix Plus
+ }
+ },
+
+ initTabContents : function TSTBrowser_initTabContents(aTab)
+ {
+ if (!aTab.parentNode) // do nothing for closed tab!
+ return;
+
+ var d = this.document;
+
+ var twisty = this.getTabTwisty(aTab);
+ var anchor = this.getTabTwistyAnchorNode(aTab);
+ if (anchor && !twisty) {
+ twisty = d.createElement('image');
+ twisty.setAttribute('class', this.kTWISTY);
+ anchor.parentNode.appendChild(twisty);
+ }
+
+ var label = this.getTabLabel(aTab);
+ var counter = d.getAnonymousElementByAttribute(aTab, 'class', this.kCOUNTER_CONTAINER);
+ if (label && !counter) {
+ counter = d.createElement('hbox');
+ counter.setAttribute('class', this.kCOUNTER_CONTAINER);
+
+ let startParen = counter.appendChild(d.createElement('label'));
+ startParen.setAttribute('class', this.kCOUNTER_PAREN);
+ startParen.setAttribute('value', '(');
+
+ let counterLabel = counter.appendChild(d.createElement('label'));
+ counterLabel.setAttribute('class', this.kCOUNTER);
+ counterLabel.setAttribute('value', '0');
+
+ let endParen = counter.appendChild(d.createElement('label'));
+ endParen.setAttribute('class', this.kCOUNTER_PAREN);
+ endParen.setAttribute('value', ')');
+
+ /** XXX
+ * Insertion before an anonymous element breaks its "xbl:inherits".
+ * For example, "xbl:inherits" of the closebox in a tab (Tab Mix Plus
+ * defines it) doesn't work. So, I don't use insertBefore().
+ * Instead, the counter will be rearranged by "ordinal" attribute
+ * given by initTabContentsOrder().
+ */
+ // label.parentNode.insertBefore(counter, label.nextSibling);
+ label.parentNode.appendChild(counter);
+ }
+
+ this.initTabContentsOrder(aTab, true);
+ },
+
+ initTabContentsOrder : function TSTBrowser_initTabContentsOrder(aTab, aForce)
+ {
+ if (!aTab.parentNode) // do nothing for closed tab!
+ return;
+
+ var d = this.document;
+
+ var namedNodes = {
+ label : this.getTabLabel(aTab),
+ close : this.getTabClosebox(aTab),
+ twistyAnchor : this.getTabTwistyAnchorNode(aTab),
+ twisty : this.getTabTwisty(aTab),
+ counter : d.getAnonymousElementByAttribute(aTab, 'class', this.kCOUNTER_CONTAINER)
+ };
+
+ namedNodes.closeAnchor = namedNodes.label;
+ if (namedNodes.closeAnchor.parentNode != namedNodes.close.parentNode) {
+ let containerFinder = d.createRange();
+ containerFinder.selectNode(namedNodes.closeAnchor);
+ containerFinder.setEndAfter(namedNodes.close);
+ let container = containerFinder.commonAncestorContainer;
+ while (namedNodes.closeAnchor.parentNode != container)
+ {
+ namedNodes.closeAnchor = namedNodes.closeAnchor.parentNode;
+ }
+ while (namedNodes.close.parentNode != container)
+ {
+ namedNodes.close = namedNodes.close.parentNode;
+ }
+ }
+
+ namedNodes.counterAnchor = namedNodes.label;
+
+ var foundContainers = [];
+ var containers = [
+ namedNodes.twistyAnchor.parentNode,
+ namedNodes.label.parentNode,
+ namedNodes.counter.parentNode,
+ namedNodes.closeAnchor.parentNode
+ ];
+ for (let i = 0, maxi = containers.length; i < maxi; i++)
+ {
+ let container = containers[i];
+ if (foundContainers.indexOf(container) > -1)
+ continue;
+ this.initTabContentsOrderInternal(container, namedNodes, aForce);
+ foundContainers.push(container);
+ }
+ },
+ initTabContentsOrderInternal : function TSTBrowser_initTabContentsOrderInternal(aContainer, aNamedNodes, aForce)
+ {
+ if (this.window.getComputedStyle(aContainer, '').getPropertyValue('-moz-box-orient') == 'vertical')
+ return;
+
+ var nodes = Array.slice(this.document.getAnonymousNodes(aContainer) || aContainer.childNodes);
+
+ // reset order at first!
+ for (let i = 0, maxi = nodes.length; i < maxi; i++)
+ {
+ let node = nodes[i];
+ if (node.getAttribute('class') == 'informationaltab-thumbnail-container')
+ continue;
+ node.setAttribute('ordinal', i);
+ }
+
+ // after that, rearrange contents
+
+ var index = nodes.indexOf(aNamedNodes.close);
+ if (index > -1) {
+ nodes.splice(index, 1);
+ if (this.mTabBrowser.getAttribute(this.kCLOSEBOX_INVERTED) == 'true')
+ nodes.splice(nodes.indexOf(aNamedNodes.closeAnchor), 0, aNamedNodes.close);
+ else
+ nodes.splice(nodes.indexOf(aNamedNodes.closeAnchor)+1, 0, aNamedNodes.close);
+ }
+
+ index = nodes.indexOf(aNamedNodes.twisty);
+ if (index > -1) {
+ nodes.splice(index, 1);
+ nodes.splice(nodes.indexOf(aNamedNodes.twistyAnchor), 0, aNamedNodes.twisty);
+ }
+
+ if (this.mTabBrowser.getAttribute(this.kTAB_CONTENTS_INVERTED) == 'true')
+ nodes.reverse();
+
+ // counter must rightside of the label!
+ index = nodes.indexOf(aNamedNodes.counter);
+ if (index > -1) {
+ nodes.splice(index, 1);
+ nodes.splice(nodes.indexOf(aNamedNodes.counterAnchor)+1, 0, aNamedNodes.counter);
+ }
+
+ var count = nodes.length;
+ nodes.reverse();
+ for (let i = 0, maxi = nodes.length; i < maxi; i++)
+ {
+ let node = nodes[i];
+ if (node.getAttribute('class') == 'informationaltab-thumbnail-container')
+ continue;
+ node.setAttribute('ordinal', (count - i + 1) * 100);
+ }
+
+ if (aForce) {
+ /**
+ * After the order of contents are changed dynamically,
+ * Gecko doesn't re-render them in the new order.
+ * Changing of "display" or "position" can fix this problem.
+ */
+ let shouldHideTemporaryState = (
+ 'TabmixTabbar' in this.window || // Tab Mix Plus
+ 'InformationalTabService' in this.window // Informational Tab
+ );
+ for (let i = 0, maxi = nodes.length; i < maxi; i++)
+ {
+ let node = nodes[i];
+ if (shouldHideTemporaryState)
+ node.style.visibility = 'hidden';
+ node.style.position = 'fixed';
+ }
+ let key = 'initTabContentsOrderInternal_'+parseInt(Math.random() * 65000);
+ (this.deferredTasks[key] = this.Deferred.wait(0.1).next(function() {
+ for (let i = 0, maxi = nodes.length; i < maxi; i++)
+ {
+ let node = nodes[i];
+ node.style.position = '';
+ if (shouldHideTemporaryState)
+ node.style.visibility = '';
+ }
+ })).error(this.defaultDeferredErrorHandler).next(function() {
+ delete self.deferredTasks[key];
+ });
+ }
+ },
+
+ updateInvertedTabContentsOrder : function TSTBrowser_updateInvertedTabContentsOrder(aTarget)
+ {
+ var self = this;
+ let key = 'updateInvertedTabContentsOrder_'+parseInt(Math.random() * 65000);
+ (this.deferredTasks[key] = this.Deferred.next(function() {
+ var b = self.mTabBrowser;
+ var tabs = !aTarget ?
+ [b.selectedTab] :
+ (aTarget instanceof Ci.nsIDOMElement) ?
+ [aTarget] :
+ (typeof aTarget == 'object' && 'length' in aTarget) ?
+ Array.slice(aTarget) :
+ self.getAllTabs(b);
+ for (let i = 0, maxi = tabs.length; i < maxi; i++)
+ {
+ self.initTabContentsOrder(tabs[i]);
+ }
+ })).error(this.defaultDeferredErrorHandler).next(function() {
+ delete self.deferredTasks[key];
+ });
+ },
+
+ initTabbar : function TSTBrowser_initTabbar(aNewPosition, aOldPosition)
+ {
+ var d = this.document;
+ var b = this.mTabBrowser;
+
+ if (aNewPosition && typeof aNewPosition == 'string')
+ aNewPosition = this.getPositionFlag(aNewPosition);
+ if (aOldPosition && typeof aOldPosition == 'string')
+ aOldPosition = this.getPositionFlag(aOldPosition);
+
+ this._startListenTabbarEvents();
+ this.window.TreeStyleTabWindowHelper.initTabbarMethods(b);
+
+ this.stopRendering();
+
+ var pos = aNewPosition || this.getPositionFlag(this.position);
+ if (b.getAttribute('id') != 'content' &&
+ !utils.getTreePref('tabbar.position.subbrowser.enabled')) {
+ pos = this.kTABBAR_TOP;
+ }
+
+ aOldPosition = aOldPosition || pos;
+
+ // We have to use CSS property hack instead, because the stopRendering()
+ // doesn't effect on the first time of startup.
+ // * This hack works in a "stop"-"start" pair, so, people never see the side effect.
+ // * This hack works only when "ordinal" properties are modified.
+ // So, this is just for the case: "right" or "bottom" tab bar on the startup.
+ if (
+ pos != aOldPosition &&
+ (
+ ((pos & this.kTABBAR_REGULAR) && (aOldPosition & this.kTABBAR_INVERTED)) ||
+ ((pos & this.kTABBAR_INVERTED) && (aOldPosition & this.kTABBAR_REGULAR))
+ )
+ )
+ b.style.visibility = 'hidden';
+
+ var strip = this.tabStrip;
+ var placeHolder = this.tabStripPlaceHolder || strip;
+ var splitter = this._ensureNewSplitter();
+ var toggler = d.getAnonymousElementByAttribute(b, 'class', this.kTABBAR_TOGGLER);
+
+ // Tab Mix Plus
+ var scrollFrame, newTabBox, tabBarMode;
+ if (utils.getTreePref('compatibility.TMP')) {
+ scrollFrame = d.getAnonymousElementByAttribute(b.mTabContainer, 'class', 'tabs-frame') ||
+ d.getAnonymousElementByAttribute(b.mTabContainer, 'anonid', 'scroll-tabs-frame');
+ newTabBox = d.getAnonymousElementByAttribute(b.mTabContainer, 'id', 'tabs-newbutton-box');
+ let newTabButton = d.getElementById('new-tab-button');
+ if (newTabButton && newTabButton.parentNode == b.tabContainer._container)
+ newTabBox = newTabButton;
+ tabBarMode = prefs.getPref('extensions.tabmix.tabBarMode');
+ }
+
+ // All-in-One Sidebar
+ var toolboxContainer = d.getAnonymousElementByAttribute(strip, 'anonid', 'aiostbx-toolbox-tableft');
+ if (toolboxContainer)
+ toolboxContainer = toolboxContainer.parentNode;
+
+ var scrollInnerBox = b.mTabContainer.mTabstrip._scrollbox ?
+ d.getAnonymousNodes(b.mTabContainer.mTabstrip._scrollbox)[0] :
+ scrollFrame; // Tab Mix Plus
+
+ this.removeTabbrowserAttribute(this.kRESIZING, b);
+
+ this.removeTabStripAttribute('width');
+ b.mPanelContainer.removeAttribute('width');
+
+ var delayedPostProcess;
+
+ if (pos & this.kTABBAR_VERTICAL) {
+ this.collapseTarget = 'top';
+ this.screenPositionProp = 'screenY';
+ this.offsetProp = 'offsetY';
+ this.translateFunction = 'translateY';
+ this.sizeProp = 'height';
+ this.invertedScreenPositionProp = 'screenX';
+ this.invertedSizeProp = 'width';
+ this.startProp = 'top';
+ this.endProp = 'bottom';
+
+ b.mTabBox.orient = splitter.orient = 'horizontal';
+ strip.orient =
+ placeHolder.orient =
+ toggler.orient =
+ b.mTabContainer.orient =
+ b.mTabContainer.mTabstrip.orient =
+ b.mTabContainer.mTabstrip.parentNode.orient = 'vertical';
+ b.mTabContainer.setAttribute('align', 'stretch'); // for Mac OS X
+ if (scrollInnerBox)
+ scrollInnerBox.removeAttribute('flex');
+
+ if (utils.getTreePref('compatibility.TMP') && scrollFrame) { // Tab Mix Plus
+ d.getAnonymousNodes(scrollFrame)[0].removeAttribute('flex');
+ scrollFrame.parentNode.orient =
+ scrollFrame.orient = 'vertical';
+ if (newTabBox)
+ newTabBox.orient = 'horizontal';
+ if (tabBarMode == 2)
+ prefs.setPref('extensions.tabmix.tabBarMode', 1);
+ }
+
+ if (toolboxContainer)
+ toolboxContainer.orient = 'vertical';
+
+ this.setTabbrowserAttribute(this.kMODE, 'vertical');
+
+ let width = this.maxTabbarWidth(utils.getTreePref('tabbar.width'), b);
+ this.setTabStripAttribute('width', width);
+ this.removeTabStripAttribute('height');
+ b.mPanelContainer.removeAttribute('height');
+
+ if (strip.localName == 'toolbar') {
+ let nodes = strip.childNodes;
+ for (let i = 0, maxi = nodes.length; i < maxi; i++)
+ {
+ let node = nodes[i];
+ if (node.localName == 'tabs')
+ continue;
+ if (node.hasAttribute('flex'))
+ node.setAttribute('treestyletab-backup-flex', node.getAttribute('flex'));
+ node.removeAttribute('flex');
+ }
+ }
+
+ if (pos == this.kTABBAR_RIGHT) {
+ this.setTabbrowserAttribute(this.kTABBAR_POSITION, 'right');
+ if (utils.getTreePref('tabbar.invertTab')) {
+ this.setTabbrowserAttribute(this.kTAB_INVERTED, 'true');
+ this.indentTarget = 'right';
+ }
+ else {
+ this.removeTabbrowserAttribute(this.kTAB_INVERTED);
+ this.indentTarget = 'left';
+ }
+ delayedPostProcess = function(aSelf, aTabBrowser, aSplitter, aToggler) {
+ /* in Firefox 3, the width of the rightside tab bar
+ unexpectedly becomes 0 on the startup. so, we have
+ to set the width again. */
+ aSelf.setTabStripAttribute('width', width);
+ aSelf.setTabStripAttribute('ordinal', 30);
+ aSplitter.setAttribute('ordinal', 20);
+ aToggler.setAttribute('ordinal', 40);
+ aTabBrowser.mPanelContainer.setAttribute('ordinal', 10);
+ aSplitter.setAttribute('collapse', 'after');
+ };
+ }
+ else {
+ this.setTabbrowserAttribute(this.kTABBAR_POSITION, 'left');
+ this.removeTabbrowserAttribute(this.kTAB_INVERTED);
+ this.indentTarget = 'left';
+ delayedPostProcess = function(aSelf, aTabBrowser, aSplitter, aToggler) {
+ aSelf.setTabStripAttribute('ordinal', 10);
+ aSplitter.setAttribute('ordinal', 20);
+ aToggler.setAttribute('ordinal', 5);
+ aTabBrowser.mPanelContainer.setAttribute('ordinal', 30);
+ aSplitter.setAttribute('collapse', 'before');
+ };
+ }
+ }
+ else {
+ this.collapseTarget = 'left';
+ this.screenPositionProp = 'screenX';
+ this.offsetProp = 'offsetX';
+ this.translateFunction = 'translateX';
+ this.sizeProp = 'width';
+ this.invertedScreenPositionProp = 'screenY';
+ this.invertedSizeProp = 'height';
+ this.startProp = 'left';
+ this.endProp = 'right';
+
+ b.mTabBox.orient = splitter.orient = 'vertical';
+ strip.orient =
+ placeHolder.orient =
+ toggler.orient =
+ b.mTabContainer.orient =
+ b.mTabContainer.mTabstrip.orient =
+ b.mTabContainer.mTabstrip.parentNode.orient = 'horizontal';
+ b.mTabContainer.removeAttribute('align'); // for Mac OS X
+ if (scrollInnerBox)
+ scrollInnerBox.setAttribute('flex', 1);
+
+ if (utils.getTreePref('compatibility.TMP') && scrollFrame) { // Tab Mix Plus
+ d.getAnonymousNodes(scrollFrame)[0].setAttribute('flex', 1);
+ scrollFrame.parentNode.orient =
+ scrollFrame.orient = 'horizontal';
+ if (newTabBox)
+ newTabBox.orient = 'vertical';
+ }
+
+ if (toolboxContainer)
+ toolboxContainer.orient = 'horizontal';
+
+ this.setTabbrowserAttribute(this.kMODE, utils.getTreePref('tabbar.multirow') ? 'multirow' : 'horizontal');
+ this.removeTabbrowserAttribute(this.kTAB_INVERTED);
+
+ if (strip.localName == 'toolbar') {
+ let nodes = strip.childNodes;
+ for (let i = 0, maxi = nodes.length; i < maxi; i++)
+ {
+ let node = nodes[i];
+ if (node.localName == 'tabs')
+ continue;
+ let flex = node.hasAttribute('treestyletab-backup-flex');
+ if (!flex)
+ continue;
+ node.setAttribute('flex', flex);
+ node.removeAttribute('treestyletab-backup-flex');
+ }
+ }
+
+ if (pos == this.kTABBAR_BOTTOM) {
+ this.setTabbrowserAttribute(this.kTABBAR_POSITION, 'bottom');
+ this.indentTarget = 'bottom';
+ delayedPostProcess = function(aSelf, aTabBrowser, aSplitter, aToggler) {
+ aSelf.setTabStripAttribute('ordinal', 30);
+ aSplitter.setAttribute('ordinal', 20);
+ aToggler.setAttribute('ordinal', 40);
+ aTabBrowser.mPanelContainer.setAttribute('ordinal', 10);
+ };
+ }
+ else {
+ this.setTabbrowserAttribute(this.kTABBAR_POSITION, 'top');
+ this.indentTarget = 'top';
+ delayedPostProcess = function(aSelf, aTabBrowser, aSplitter, aToggler) {
+ aSelf.setTabStripAttribute('ordinal', 10);
+ aSplitter.setAttribute('ordinal', 20);
+ aToggler.setAttribute('ordinal', 5);
+ aTabBrowser.mPanelContainer.setAttribute('ordinal', 30);
+ };
+ }
+ }
+
+ var tabs = this.getAllTabs(b);
+ for (let i = 0, maxi = tabs.length; i < maxi; i++)
+ {
+ let tab = tabs[i];
+ tab.style.removeProperty(this.indentCSSProp);
+ tab.style.removeProperty(this.collapseCSSProp);
+ }
+
+ this.indentProp = utils.getTreePref('indent.property');
+ this.indentCSSProp = this.indentProp+'-'+this.indentTarget;
+ this.collapseCSSProp = 'margin-'+this.collapseTarget;
+
+ for (let i = 0, maxi = tabs.length; i < maxi; i++)
+ {
+ let tab = tabs[i];
+ this.updateTabCollapsed(tab, tab.getAttribute(this.kCOLLAPSED) == 'true', true);
+ }
+
+ // for updateTabbarOverflow(), we should reset the "overflow" now.
+ b.mTabContainer.removeAttribute('overflow');
+ let (container = this.document.getAnonymousElementByAttribute(b.mTabContainer, 'class', 'tabs-container')) {
+ if (container)
+ container.removeAttribute('overflow');
+ }
+
+ this.updateTabbarState(false);
+
+ if (this.deferredTasks['initTabbar'])
+ this.deferredTasks['initTabbar'].cancel();
+
+ var self = this;
+ (this.deferredTasks['initTabbar'] = this.Deferred.next(function() {
+ delayedPostProcess(self, b, splitter, toggler);
+ self.updateTabbarOverflow();
+ self.updateAllTabsButton(b);
+ self.updateAllTabsCount();
+ delayedPostProcess = null;
+ self.mTabBrowser.style.visibility = '';
+
+ var event = d.createEvent('Events');
+ event.initEvent(self.kEVENT_TYPE_TABBAR_INITIALIZED, true, false);
+ self.mTabBrowser.dispatchEvent(event);
+
+ self.startRendering();
+ })).error(this.defaultDeferredErrorHandler).next(function() {
+ delete self.deferredTasks['initTabbar'];
+ });
+
+ pos = null;
+ scrollFrame = null;
+ newTabBox = null
+ tabBarMode = null;
+ toolboxContainer = null;
+ scrollInnerBox = null;
+ scrollInnerBox = null;
+ },
+
+ _startListenTabbarEvents : function TSTBrowser_startListenTabbarEvents()
+ {
+ var b = this.mTabBrowser;
+
+ var tabContainer = b.mTabContainer;
+ tabContainer.addEventListener('TabOpen', this, true);
+ tabContainer.addEventListener('TabClose', this, true);
+ tabContainer.addEventListener('TabMove', this, true);
+ tabContainer.addEventListener('TabShow', this, true);
+ tabContainer.addEventListener('TabHide', this, true);
+ tabContainer.addEventListener('SSTabRestoring', this, true);
+ tabContainer.addEventListener('SSTabRestored', this, true);
+ tabContainer.addEventListener('TabPinned', this, true);
+ tabContainer.addEventListener('TabUnpinned', this, true);
+ tabContainer.addEventListener('mouseover', this, true);
+ tabContainer.addEventListener('mouseout', this, true);
+ tabContainer.addEventListener('dblclick', this, true);
+ tabContainer.addEventListener('select', this, true);
+ tabContainer.addEventListener('scroll', this, true);
+
+ var strip = this.tabStrip;
+ strip.addEventListener('MozMouseHittest', this, true); // to block default behaviors of the tab bar
+ strip.addEventListener('mousedown', this, true);
+ strip.addEventListener('click', this, true);
+ strip.addEventListener('DOMMouseScroll', this, true);
+
+ this.scrollBox.addEventListener('overflow', this, true);
+ this.scrollBox.addEventListener('underflow', this, true);
+ },
+
+ _ensureNewSplitter : function TSTBrowser__ensureNewSplitter()
+ {
+ var d = this.document;
+ var splitter = this.splitter;
+
+ // We always have to re-create splitter, because its "collapse"
+ // behavior becomes broken by repositioning of the tab bar.
+ if (splitter) {
+ try {
+ splitter.removeEventListener('mousedown', this.windowService, false);
+ splitter.removeEventListener('mouseup', this.windowService, false);
+ splitter.removeEventListener('dblclick', this.windowService, false);
+ }
+ catch(e) {
+ }
+ let oldSplitter = splitter;
+ splitter = oldSplitter.cloneNode(true);
+ oldSplitter.parentNode.removeChild(oldSplitter);
+ }
+ else {
+ splitter = d.createElement('splitter');
+ splitter.setAttribute(this.kTAB_STRIP_ELEMENT, true);
+ splitter.setAttribute('state', 'open');
+ splitter.setAttribute('layer', true); // https://bugzilla.mozilla.org/show_bug.cgi?id=590468
+ let grippy = d.createElement('grippy')
+ grippy.setAttribute(this.kTAB_STRIP_ELEMENT, true);
+ // Workaround for https://github.com/piroor/treestyletab/issues/593
+ // When you click the grippy...
+ // 1. The grippy changes "state" of the splitter from "collapsed"
+ // to "open".
+ // 2. The splitter changes visibility of the place holder.
+ // 3. BrowserUIShowHideObserver detects the change of place
+ // holder's visibility and triggers updateFloatingTabbar().
+ // 4. updateFloatingTabbar() copies the visibility of the
+ // actual tab bar to the place holder. However, the tab bar
+ // is still collapsed.
+ // 5. As the result, the place holder becomes collapsed and
+ // the splitter disappear.
+ // So, we have to turn the actual tab bar visible manually
+ // when the grippy is clicked.
+ let tabContainer = this.mTabBrowser.tabContainer;
+ grippy.addEventListener('click', function() {
+ tabContainer.ownerDocument.defaultView.setTimeout(function() {
+ var visible = grippy.getAttribute('state') != 'collapsed';
+ if (visible != tabContainer.visible)
+ tabContainer.visible = visible;
+ }, 0);
+ }, false);
+ splitter.appendChild(grippy);
+ }
+
+ var splitterClass = splitter.getAttribute('class') || '';
+ if (splitterClass.indexOf(this.kSPLITTER) < 0)
+ splitterClass += (splitterClass ? ' ' : '' ) + this.kSPLITTER;
+ splitter.setAttribute('class', splitterClass);
+
+ splitter.addEventListener('mousedown', this.windowService, false);
+ splitter.addEventListener('mouseup', this.windowService, false);
+ splitter.addEventListener('dblclick', this.windowService, false);
+
+ var ref = this.mTabBrowser.mPanelContainer;
+ ref.parentNode.insertBefore(splitter, ref);
+
+ return splitter;
+ },
+
+ fireTabbarPositionEvent : function TSTBrowser_fireTabbarPositionEvent(aChanging, aOldPosition, aNewPosition)
+ {
+ if (aOldPosition == aNewPosition)
+ return false;
+
+ var type = aChanging ? this.kEVENT_TYPE_TABBAR_POSITION_CHANGING : this.kEVENT_TYPE_TABBAR_POSITION_CHANGED;
+ var data = {
+ oldPosition : aOldPosition,
+ newPosition : aNewPosition
+ };
+
+ /* PUBLIC API */
+ this.fireCustomEvent(type, this.mTabBrowser, true, false, data);
+ // for backward compatibility
+ this.fireCustomEvent(type.replace(/^nsDOM/, ''), this.mTabBrowser, true, false, data);
+
+ return true;
+ },
+
+ updateTabbarState : function TSTBrowser_updateTabbarState(aCancelable)
+ {
+ if (!this._fireTabbarStateChangingEvent() && aCancelable)
+ return;
+
+ this.stopRendering();
+
+ var self = this;
+
+ var w = this.window;
+ var d = this.document;
+ var b = this.mTabBrowser;
+ var orient;
+ var toggleTabsOnTop = d.getElementById('cmd_ToggleTabsOnTop');
+ var TabsOnTop = 'TabsOnTop' in w ? w.TabsOnTop : null ;
+ if (this.isVertical) {
+ orient = 'vertical';
+ this.fixed = this.fixed; // ensure set to the current orient
+ if (toggleTabsOnTop)
+ toggleTabsOnTop.setAttribute('disabled', true);
+ }
+ else {
+ orient = 'horizontal';
+ if (this.fixed) {
+ this.fixed = true; // ensure set to the current orient
+ if (!this.isMultiRow()) {
+ this.removeTabStripAttribute('height');
+ b.mPanelContainer.removeAttribute('height');
+ }
+ // remove ordinal for "tabs on top" https://bugzilla.mozilla.org/show_bug.cgi?id=544815
+ if (this.position == 'top') {
+ this.removeTabStripAttribute('ordinal');
+ if (TabsOnTop && !this.windowService.isPopupWindow &&
+ this.windowService.initialized) {
+ let currentState = TabsOnTop.enabled;
+ let originalState = utils.getTreePref('tabsOnTop.originalState');
+ if (originalState !== null &&
+ currentState != originalState &&
+ this.windowService.tabsOnTopChangingByUI &&
+ !this.windowService.changingTabsOnTop)
+ utils.setTreePref('tabsOnTop.originalState', currentState);
+ // Workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=555987
+ // This should be done when the value of the "ordinal" attribute
+ // is modified dynamically. So, we don' have to do it before
+ // the browser window is completely initialized.
+ TabsOnTop.enabled = !currentState;
+ if (this.deferredTasks['updateTabbarState_TabsOnTop'])
+ this.deferredTasks['updateTabbarState_TabsOnTop'].cancel();
+ (this.deferredTasks['updateTabbarState_TabsOnTop'] = this.Deferred.next(function() {
+ TabsOnTop.enabled = currentState;
+ })).error(this.defaultDeferredErrorHandler).next(function() {
+ delete self.deferredTasks['updateTabbarState_TabsOnTop'];
+ });
+ }
+ }
+ }
+ else {
+ this.fixed = false; // ensure set to the current orient
+ this.setTabStripAttribute('height', this.maxTabbarHeight(utils.getTreePref('tabbar.height'), b));
+ }
+ if (toggleTabsOnTop) {
+ if (this.position == 'top')
+ toggleTabsOnTop.removeAttribute('disabled');
+ else
+ toggleTabsOnTop.setAttribute('disabled', true);
+ }
+ }
+
+ if (TabsOnTop && !this.windowService.isPopupWindow) {
+ let updateTabsOnTop = function() {
+ self.windowService.updateTabsOnTop();
+ };
+ // TabsOnTop.enabled is always "false" before the browser window is
+ // completely initialized. So, we have to check it with delay only
+ // on the Startup.
+ if (this.initialized)
+ updateTabsOnTop();
+ else
+ this.Deferred.next(updateTabsOnTop);
+ }
+
+ if (this.deferredTasks['updateTabbarState'])
+ this.deferredTasks['updateTabbarState'].cancel();
+ (this.deferredTasks['updateTabbarState'] = this.Deferred.next(function() {
+ self.updateFloatingTabbar(self.kTABBAR_UPDATE_BY_APPEARANCE_CHANGE);
+ self._fireTabbarStateChangedEvent();
+ self.startRendering();
+ })).error(this.defaultDeferredErrorHandler).next(function() {
+ delete self.deferredTasks['updateTabbarState'];
+ });
+
+ var allowToCollapse = utils.getTreePref('allowSubtreeCollapseExpand.'+orient);
+ if (this.allowSubtreeCollapseExpand != allowToCollapse)
+ this.collapseExpandAllSubtree(false, false);
+ this.allowSubtreeCollapseExpand = allowToCollapse;
+
+ this.maxTreeLevel = utils.getTreePref('maxTreeLevel.'+orient);
+
+ this.setTabbrowserAttribute(this.kALLOW_STACK, this.canStackTabs ? 'true' : null);
+ this.updateTabsZIndex(this.canStackTabs);
+
+ if (this.maxTreeLevelPhisical)
+ this.promoteTooDeepLevelTabs();
+
+ this.updateAllTabsIndent();
+ },
+
+ _fireTabbarStateChangingEvent : function TSTBrowser_fireTabbarStateChangingEvent()
+ {
+ var b = this.mTabBrowser;
+ var orient = this.isVertical ? 'vertical' : 'horizontal' ;
+ var oldState = {
+ fixed : this.fixed,
+ maxTreeLevel : this.maxTreeLevel,
+ indented : this.maxTreeLevel != 0,
+ canCollapse : b.getAttribute(this.kALLOW_COLLAPSE) == 'true'
+ };
+ var newState = {
+ fixed : utils.getTreePref('tabbar.fixed.'+orient),
+ maxTreeLevel : utils.getTreePref('maxTreeLevel.'+orient),
+ indented : utils.getTreePref('maxTreeLevel.'+orient) != 0,
+ canCollapse : utils.getTreePref('allowSubtreeCollapseExpand.'+orient)
+ };
+
+ if (oldState.fixed == newState.fixed &&
+ oldState.maxTreeLevel == newState.maxTreeLevel &&
+ oldState.indented == newState.indented &&
+ oldState.canCollapse == newState.canCollapse)
+ return false;
+
+ var data = {
+ oldState : oldState,
+ newState : newState
+ };
+
+ /* PUBLIC API */
+ this.fireCustomEvent(this.kEVENT_TYPE_TABBAR_STATE_CHANGING, this.mTabBrowser, true, false, data);
+ // for backward compatibility
+ this.fireCustomEvent(this.kEVENT_TYPE_TABBAR_STATE_CHANGING.replace(/^nsDOM/, ''), this.mTabBrowser, true, false, data);
+
+ return true;
+ },
+
+ _fireTabbarStateChangedEvent : function TSTBrowser_fireTabbarStateChangedEvent()
+ {
+ var b = this.mTabBrowser;
+ var state = {
+ fixed : this.fixed,
+ maxTreeLevel : this.maxTreeLevel,
+ indented : this.maxTreeLevel != 0,
+ canCollapse : b.getAttribute(this.kALLOW_COLLAPSE) == 'true'
+ };
+
+ var data = {
+ state : state
+ };
+
+ /* PUBLIC API */
+ this.fireCustomEvent(this.kEVENT_TYPE_TABBAR_STATE_CHANGED, this.mTabBrowser, true, false, data);
+ // for backward compatibility
+ this.fireCustomEvent(this.kEVENT_TYPE_TABBAR_STATE_CHANGED.replace(/^nsDOM/, ''), this.mTabBrowser, true, false, data);
+
+ return true;
+ },
+
+ updateFloatingTabbar : function TSTBrowser_updateFloatingTabbar(aReason)
+ {
+ var w = this.window;
+ if (this._updateFloatingTabbarTimer) {
+ w.clearTimeout(this._updateFloatingTabbarTimer);
+ this._updateFloatingTabbarTimer = null;
+ }
+
+ this._updateFloatingTabbarReason |= aReason;
+
+ if (this._updateFloatingTabbarReason & this.kTABBAR_UPDATE_NOW) {
+ this._updateFloatingTabbarInternal(this._updateFloatingTabbarReason);
+ this._updateFloatingTabbarReason = 0;
+ }
+ else {
+ this._updateFloatingTabbarTimer = w.setTimeout(function(aSelf) {
+ aSelf._updateFloatingTabbarTimer = null;
+ aSelf._updateFloatingTabbarInternal(aSelf._updateFloatingTabbarReason)
+ aSelf._updateFloatingTabbarReason = 0;
+ }, 0, this);
+ }
+ },
+
+ _updateFloatingTabbarInternal : function TSTBrowser_updateFloatingTabbarInternal(aReason)
+ {
+ aReason = aReason || this.kTABBAR_UPDATE_BY_UNKNOWN_REASON;
+
+ if (DEBUG) {
+ let humanReadableReason =
+ (aReason & this.kTABBAR_UPDATE_BY_RESET ? 'reset ' : '' ) +
+ (aReason & this.kTABBAR_UPDATE_BY_PREF_CHANGE ? 'prefchange ' : '' ) +
+ (aReason & this.kTABBAR_UPDATE_BY_APPEARANCE_CHANGE ? 'appearance-change ' : '' ) +
+ (aReason & this.kTABBAR_UPDATE_BY_SHOWHIDE_TABBAR ? 'showhide ' : '' ) +
+ (aReason & this.kTABBAR_UPDATE_BY_TABBAR_RESIZE ? 'tabbar-resize ' : '' ) +
+ (aReason & this.kTABBAR_UPDATE_BY_WINDOW_RESIZE ? 'window-resize ' : '' ) +
+ (aReason & this.kTABBAR_UPDATE_BY_FULLSCREEN ? 'fullscreen ' : '' ) +
+ (aReason & this.kTABBAR_UPDATE_BY_AUTOHIDE ? 'autohide ' : '' ) +
+ (aReason & this.kTABBAR_UPDATE_BY_INITIALIZE ? 'initialize ' : '' ) +
+ (aReason & this.kTABBAR_UPDATE_BY_TOGGLE_SIDEBAR ? 'toggle-sidebar ' : '' );
+ dump('TSTBrowser_updateFloatingTabbarInternal: ' + humanReadableReason + '\n');
+ }
+
+ var d = this.document;
+
+ // When the tab bar is invisible even if the tab bar is resizing, then
+ // now I'm trying to expand the tab bar from collapsed state.
+ // Then the tab bar must be shown.
+ if (aReason & this.kTABBAR_UPDATE_BY_TABBAR_RESIZE &&
+ !this.browser.tabContainer.visible)
+ this.browser.tabContainer.visible = true;
+
+ var splitter = this.splitter;
+ if (splitter.collapsed || splitter.getAttribute('state') != 'collapsed') {
+ // Synchronize visibility of the tab bar to the placeholder,
+ // because the tab bar can be shown/hidden by someone
+ // (Tab Mix Plus, Pale Moon, or some addons).
+ this._tabStripPlaceHolder.collapsed =
+ splitter.collapsed =
+ !this.browser.tabContainer.visible;
+ }
+
+ var strip = this.tabStrip;
+ var collapsed = splitter.collapsed ?
+ strip.collapsed :
+ splitter.getAttribute('state') == 'collapsed' ;
+ var stripStyle = strip.style;
+ var tabContainerBox = this.getTabContainerBox(this.mTabBrowser);
+ var statusPanel = d.getElementById('statusbar-display');
+ var statusPanelStyle = statusPanel ? statusPanel.style : null ;
+ var pos = this.position;
+ if (pos != 'top' ||
+ this.mTabBrowser.getAttribute(this.kFIXED) != 'true') {
+ strip.setAttribute('layer', true); // https://bugzilla.mozilla.org/show_bug.cgi?id=590468
+
+ if (
+ this.autoHide.enabled &&
+ this.autoHide.expanded &&
+ (aReason & this.kTABBAR_UPDATE_SYNC_TO_PLACEHOLDER) &&
+ this.autoHide.mode == this.autoHide.kMODE_SHRINK
+ )
+ this.autoHide.hide(this.autoHide.kSHOWN_BY_ANY_REASON);
+
+ let box = this._tabStripPlaceHolder.boxObject;
+ let root = d.documentElement.boxObject;
+ let realSize = this.getTabbarPlaceholderSize();
+
+ let width = (this.autoHide.expanded && this.isVertical && (aReason & this.kTABBAR_UPDATE_SYNC_TO_TABBAR) ?
+ this.maxTabbarWidth(utils.getTreePref('tabbar.width')) :
+ 0
+ ) || realSize.width;
+ let height = (this.autoHide.expanded && !this.isVertical && (aReason & this.kTABBAR_UPDATE_SYNC_TO_TABBAR) ?
+ this.maxTabbarHeight(utils.getTreePref('tabbar.height')) :
+ 0
+ ) || realSize.height;
+ let yOffset = pos == 'bottom' ? height - realSize.height : 0 ;
+
+ stripStyle.top = (box.screenY - root.screenY + root.y - yOffset)+'px';
+ stripStyle.left = pos == 'right' ? '' :
+ (box.screenX - root.screenX + root.x)+'px';
+ stripStyle.right = pos != 'right' ? '' :
+ ((root.screenX + root.width) - (box.screenX + box.width))+'px';
+
+ stripStyle.width = (strip.width = tabContainerBox.width = width)+'px';
+ stripStyle.height = (strip.height = tabContainerBox.height = height)+'px';
+
+ this._updateFloatingTabbarResizer({
+ width : width,
+ realWidth : realSize.width,
+ height : height,
+ realHeight : realSize.height
+ });
+
+ this._lastTabbarPlaceholderSize = realSize;
+
+ strip.collapsed = tabContainerBox.collapsed = collapsed;
+
+ if (statusPanel && utils.getTreePref('repositionStatusPanel')) {
+ let offsetParentBox = this.base.findOffsetParent(statusPanel).boxObject;
+ let contentBox = this.mTabBrowser.mPanelContainer.boxObject;
+ let chromeMargins = (d.documentElement.getAttribute('chromemargin') || '0,0,0,0').split(',');
+ chromeMargins = chromeMargins.map(function(aMargin) { return parseInt(aMargin); });
+ statusPanelStyle.marginTop = (pos == 'bottom') ?
+ '-moz-calc(0px - ' + (offsetParentBox.height - contentBox.height + chromeMargins[2]) + 'px - 3em)' :
+ '' ;
+ statusPanelStyle.marginLeft = (contentBox.screenX - offsetParentBox.screenX + chromeMargins[3])+'px';
+ statusPanelStyle.marginRight = ((offsetParentBox.screenX + offsetParentBox.width) - (contentBox.screenX + contentBox.width) + chromeMargins[1])+'px';
+ statusPanelStyle.maxWidth = this.isVertical ?
+ (contentBox.width-5)+'px' : // emulate the margin defined on https://bugzilla.mozilla.org/show_bug.cgi?id=632634
+ '' ;
+ statusPanel.__treestyletab__repositioned = true;
+ }
+
+ this.mTabBrowser.tabContainer.setAttribute('context', this.mTabBrowser.tabContextMenu.id);
+ }
+ else {
+ strip.collapsed = tabContainerBox.collapsed = collapsed;
+ stripStyle.top = stripStyle.left = stripStyle.right = stripStyle.width = stripStyle.height = '';
+
+ if (
+ statusPanel &&
+ (
+ utils.getTreePref('repositionStatusPanel') ||
+ statusPanel.__treestyletab__repositioned
+ )
+ ) {
+ statusPanelStyle.marginTop = statusPanelStyle.marginLeft =
+ statusPanelStyle.marginRight = statusPanelStyle.maxWidth = '';
+ statusPanel.__treestyletab__repositioned = false;
+ }
+
+ strip.removeAttribute('layer'); // https://bugzilla.mozilla.org/show_bug.cgi?id=590468
+
+ this.mTabBrowser.tabContainer.removeAttribute('context');
+ }
+
+ if (tabContainerBox.boxObject.width)
+ this.positionPinnedTabs(null, null, aReason & this.kTABBAR_UPDATE_BY_AUTOHIDE);
+ else
+ this.positionPinnedTabsWithDelay(null, null, aReason & this.kTABBAR_UPDATE_BY_AUTOHIDE);
+
+ if (!collapsed && aReason & this.kTABBAR_UPDATE_BY_AUTOHIDE) {
+ let self = this;
+ this.Deferred.next(function() {
+ self.scrollToTab(self.browser.selectedTab);
+ });
+ }
+ },
+ getTabbarPlaceholderSize: function TSTBrowser_getTabbarPlaceholderSize()
+ {
+ var box = this._tabStripPlaceHolder.boxObject;
+ return {
+ width: parseInt(this._tabStripPlaceHolder.getAttribute('width') || box.width),
+ height: parseInt(this._tabStripPlaceHolder.getAttribute('height') || box.height)
+ };
+ },
+ getExistingTabsCount : function TSTBrowser_getTabsCount()
+ {
+ return this.getAllTabs(this.mTabBrowser).length - this.mTabBrowser._removingTabs.length;
+ },
+
+ _updateFloatingTabbarResizer : function TSTBrowser_updateFloatingTabbarResizer(aSize)
+ {
+ var d = this.document;
+
+ var width = aSize.width;
+ var realWidth = this.autoHide.mode == this.autoHide.kMODE_HIDE ? 0 : aSize.realWidth ;
+ var height = aSize.height;
+ var realHeight = this.autoHide.mode == this.autoHide.kMODE_HIDE ? 0 : aSize.realHeight ;
+ var pos = this.position;
+ var vertical = this.isVertical;
+
+ var splitter = d.getElementById('treestyletab-tabbar-resizer-splitter');
+ if (!splitter) {
+ let box = d.createElement('box');
+ box.setAttribute('id', 'treestyletab-tabbar-resizer-box');
+ box.setAttribute(this.kTAB_STRIP_ELEMENT, true);
+ splitter = d.createElement('splitter');
+ splitter.setAttribute(this.kTAB_STRIP_ELEMENT, true);
+ splitter.setAttribute('id', 'treestyletab-tabbar-resizer-splitter');
+ splitter.setAttribute('class', this.kSPLITTER);
+ splitter.setAttribute('onmousedown', 'TreeStyleTabService.handleEvent(event);');
+ splitter.setAttribute('onmouseup', 'TreeStyleTabService.handleEvent(event);');
+ splitter.setAttribute('ondblclick', 'TreeStyleTabService.handleEvent(event);');
+ box.appendChild(splitter);
+ this.tabStrip.appendChild(box);
+ }
+
+ var box = splitter.parentNode;
+
+ box.orient = splitter.orient = vertical ? 'horizontal' : 'vertical' ;
+ box.width = (width - realWidth) || width;
+ box.height = (height - realHeight) || height;
+
+ var boxStyle = box.style;
+ boxStyle.top = pos == 'top' ? realHeight+'px' : '' ;
+ boxStyle.right = pos == 'right' ? realWidth+'px' : '' ;
+ boxStyle.left = pos == 'left' ? realWidth+'px' : '' ;
+ boxStyle.bottom = pos == 'bottom' ? realHeight+'px' : '' ;
+
+ if (vertical) {
+ splitter.removeAttribute('width');
+ splitter.setAttribute('height', height);
+ }
+ else {
+ splitter.setAttribute('width', width);
+ splitter.removeAttribute('height');
+ }
+
+ var splitterWidth = splitter.boxObject.width;
+ var splitterHeight = splitter.boxObject.height;
+ var splitterStyle = splitter.style;
+ splitterStyle.marginTop = pos == 'bottom' ? (-splitterHeight)+'px' :
+ vertical ? '0' :
+ box.height+'px' ;
+ splitterStyle.marginRight = pos == 'left' ? (-splitterWidth)+'px' :
+ !vertical ? '0' :
+ box.width+'px' ;
+ splitterStyle.marginLeft = pos == 'right' ? (-splitterWidth)+'px' :
+ !vertical ? '0' :
+ box.width+'px' ;
+ splitterStyle.marginBottom = pos == 'top' ? (-splitterHeight)+'px' :
+ vertical ? '0' :
+ box.height+'px' ;
+ },
+
+ updateTabbarOverflow : function TSTBrowser_updateTabbarOverflow()
+ {
+ var d = this.document;
+ var b = this.mTabBrowser;
+ b.mTabContainer.removeAttribute('overflow');
+ var container = d.getAnonymousElementByAttribute(b.mTabContainer, 'class', 'tabs-container') || b.mTabContainer;
+
+ if (container != b.mTabContainer)
+ container.removeAttribute('overflow');
+
+ var scrollBox = this.scrollBox;
+ scrollBox = d.getAnonymousElementByAttribute(scrollBox, 'anonid', 'scrollbox');
+ if (scrollBox)
+ scrollBox = d.getAnonymousNodes(scrollBox)[0];
+ if (
+ scrollBox &&
+ (
+ scrollBox.boxObject.width > container.boxObject.width ||
+ scrollBox.boxObject.height > container.boxObject.height
+ )
+ ) {
+ b.mTabContainer.setAttribute('overflow', true);
+ if (container != b.mTabContainer)
+ container.setAttribute('overflow', true);
+ }
+ else {
+ b.mTabContainer.removeAttribute('overflow');
+ if (container != b.mTabContainer)
+ container.removeAttribute('overflow');
+ }
+ },
+
+ reinitAllTabs : function TSTBrowser_reinitAllTabs(aSouldUpdateCount)
+ {
+ var tabs = this.getAllTabs(this.mTabBrowser);
+ for (let i = 0, maxi = tabs.length; i < maxi; i++)
+ {
+ let tab = tabs[i];
+ this.initTabAttributes(tab);
+ this.initTabContents(tab);
+ if (aSouldUpdateCount)
+ this.updateTabsCount(tab);
+ }
+ },
+
+ destroy : function TSTBrowser_destroy()
+ {
+ this.animationManager.removeTask(this.smoothScrollTask);
+
+ Object.keys(this.deferredTasks).forEach(function(key) {
+ if (this.deferredTasks[key].cancel) {
+ this.deferredTasks[key].cancel();
+ delete this.deferredTasks[key];
+ }
+ }, this);
+
+ this.autoHide.destroy();
+ delete this._autoHide;
+
+ this._initDNDObservers(); // ensure initialized
+ this.tabbarDNDObserver.destroy();
+ delete this._tabbarDNDObserver;
+ this.panelDNDObserver.destroy();
+ delete this._panelDNDObserver;
+
+ if (this.tooltipManager) {
+ this.tooltipManager.destroy();
+ delete this.tooltipManager;
+ }
+
+ if (this.tabStripPlaceHolderBoxObserver) {
+ this.tabStripPlaceHolderBoxObserver.destroy();
+ delete this.tabStripPlaceHolderBoxObserver;
+ }
+
+ var w = this.window;
+ var d = this.document;
+ var b = this.mTabBrowser;
+ delete b.tabContainer.treeStyleTab;
+
+ var tabs = this.getAllTabs(b);
+ for (let i = 0, maxi = tabs.length; i < maxi; i++)
+ {
+ let tab = tabs[i];
+ this.stopTabIndentAnimation(tab);
+ this.stopTabCollapseAnimation(tab);
+ this.destroyTab(tab);
+ }
+
+ this._endListenTabbarEvents();
+
+ w.removeEventListener('resize', this, true);
+ w.removeEventListener('beforecustomization', this, true);
+ w.removeEventListener('aftercustomization', this, false);
+ w.removeEventListener('customizationchange', this, false);
+ w.removeEventListener(this.kEVENT_TYPE_PRINT_PREVIEW_ENTERED, this, false);
+ w.removeEventListener(this.kEVENT_TYPE_PRINT_PREVIEW_EXITED, this, false);
+ w.removeEventListener('tabviewframeinitialized', this, false);
+ w.removeEventListener(this.kEVENT_TYPE_TAB_FOCUS_SWITCHING_END, this, false);
+ w.removeEventListener('SSWindowStateBusy', this, false);
+
+ b.removeEventListener('nsDOMMultipleTabHandlerTabsClosing', this, false);
+
+ w['piro.sakura.ne.jp'].tabsDragUtils.destroyTabBrowser(b);
+
+ var tabContextMenu = b.tabContextMenu ||
+ d.getAnonymousElementByAttribute(b, 'anonid', 'tabContextMenu');
+ tabContextMenu.removeEventListener('popupshowing', this, false);
+
+ if (this.tabbarCanvas) {
+ this.tabbarCanvas.parentNode.removeChild(this.tabbarCanvas);
+ this.tabbarCanvas = null;
+ }
+
+ Services.obs.removeObserver(this, this.kTOPIC_INDENT_MODIFIED);
+ Services.obs.removeObserver(this, this.kTOPIC_COLLAPSE_EXPAND_ALL);
+ Services.obs.removeObserver(this, this.kTOPIC_CHANGE_TREEVIEW_AVAILABILITY);
+ Services.obs.removeObserver(this, 'lightweight-theme-styling-update');
+ prefs.removePrefListener(this);
+
+ delete this.windowService;
+ delete this.window;
+ delete this.document;
+ delete this.mTabBrowser.treeStyleTab;
+ delete this.mTabBrowser;
+ },
+
+ destroyTab : function TSTBrowser_destroyTab(aTab)
+ {
+ var id = aTab.getAttribute(this.kID);
+ if (id in this.tabsHash &&
+ aTab == this.tabsHash[id])
+ delete this.tabsHash[id];
+
+ if (aTab.__treestyletab__checkTabsIndentOverflowOnMouseLeave) {
+ this.document.removeEventListener('mouseover', aTab.__treestyletab__checkTabsIndentOverflowOnMouseLeave, true);
+ this.document.removeEventListener('mouseout', aTab.__treestyletab__checkTabsIndentOverflowOnMouseLeave, true);
+ delete aTab.__treestyletab__checkTabsIndentOverflowOnMouseLeave;
+ }
+
+ delete aTab.__treestyletab__linkedTabBrowser;
+ },
+
+ _endListenTabbarEvents : function TSTBrowser_endListenTabbarEvents()
+ {
+ var b = this.mTabBrowser;
+
+ var tabContainer = b.mTabContainer;
+ tabContainer.removeEventListener('TabOpen', this, true);
+ tabContainer.removeEventListener('TabClose', this, true);
+ tabContainer.removeEventListener('TabMove', this, true);
+ tabContainer.removeEventListener('TabShow', this, true);
+ tabContainer.removeEventListener('TabHide', this, true);
+ tabContainer.removeEventListener('SSTabRestoring', this, true);
+ tabContainer.removeEventListener('SSTabRestored', this, true);
+ tabContainer.removeEventListener('TabPinned', this, true);
+ tabContainer.removeEventListener('TabUnpinned', this, true);
+ tabContainer.removeEventListener('mouseover', this, true);
+ tabContainer.removeEventListener('mouseout', this, true);
+ tabContainer.removeEventListener('dblclick', this, true);
+ tabContainer.removeEventListener('select', this, true);
+ tabContainer.removeEventListener('scroll', this, true);
+
+ var strip = this.tabStrip;
+ strip.removeEventListener('MozMouseHittest', this, true);
+ strip.removeEventListener('mousedown', this, true);
+ strip.removeEventListener('click', this, true);
+ strip.removeEventListener('DOMMouseScroll', this, true);
+
+ this.scrollBox.removeEventListener('overflow', this, true);
+ this.scrollBox.removeEventListener('underflow', this, true);
+ },
+
+ saveCurrentState : function TSTBrowser_saveCurrentState()
+ {
+ this.autoHide.saveCurrentState();
+
+ var b = this.mTabBrowser;
+ var floatingBox = this.getTabStrip(b).boxObject;
+ var fixedBox = (this.tabStripPlaceHolder || this.getTabStrip(b)).boxObject;
+ var prefs = {
+ 'tabbar.fixed.horizontal' : b.getAttribute(this.kFIXED+'-horizontal') == 'true',
+ 'tabbar.fixed.vertical' : b.getAttribute(this.kFIXED+'-vertical') == 'true',
+ 'tabbar.width' : this.isVertical && this.autoHide.expanded && floatingBox.width ? floatingBox.width : void(0),
+ 'tabbar.shrunkenWidth' : this.isVertical && !this.autoHide.expanded && fixedBox.width ? fixedBox.width : void(0),
+ 'tabbar.height' : !this.isVertical && this.autoHide.expanded && floatingBox.height ? floatingBox.height : void(0)
+ };
+ for (var i in prefs)
+ {
+ if (prefs[i] !== void(0) && utils.getTreePref(i) != prefs[i])
+ utils.setTreePref(i, prefs[i]);
+ }
+ this.position = this.position;
+ },
+
+/* toolbar customization */
+
+ syncDestroyTabbar : function TSTBrowser_syncDestroyTabbar()
+ {
+ this.stopRendering();
+
+ this._lastTreeViewEnabledBeforeDestroyed = this.treeViewEnabled;
+ this.treeViewEnabled = false;
+ this.maxTreeLevel = 0;
+
+ this._lastTabbarPositionBeforeDestroyed = this.position;
+ if (this.position != 'top') {
+ let self = this;
+ this.doAndWaitDOMEvent(
+ this.kEVENT_TYPE_TABBAR_POSITION_CHANGED,
+ this.window,
+ 100,
+ function() {
+ self.position = 'top';
+ }
+ );
+ }
+
+ this.fixed = true;
+
+ var tabbar = this.mTabBrowser.tabContainer;
+ tabbar.removeAttribute('width');
+ tabbar.removeAttribute('height');
+ tabbar.removeAttribute('ordinal');
+
+ this.removeTabStripAttribute('width');
+ this.removeTabStripAttribute('height');
+ this.removeTabStripAttribute('ordinal');
+ this.removeTabStripAttribute('orient');
+
+ var toolbar = this.ownerToolbar;
+ this.destroyTabStrip(toolbar);
+ toolbar.classList.add(this.kTABBAR_TOOLBAR_READY);
+
+ this._endListenTabbarEvents();
+
+ this.tabbarDNDObserver.endListenEvents();
+
+ this.window.setTimeout(function(aSelf) {
+ aSelf.updateCustomizedTabsToolbar();
+ }, 100, this);
+
+ this.startRendering();
+ },
+ destroyTabStrip : function TSTBrowser_destroyTabStrip(aTabStrip)
+ {
+ aTabStrip.classList.remove(this.kTABBAR_TOOLBAR);
+ aTabStrip.style.top = aTabStrip.style.left = aTabStrip.style.width = aTabStrip.style.height = '';
+ aTabStrip.removeAttribute('height');
+ aTabStrip.removeAttribute('width');
+ aTabStrip.removeAttribute('ordinal');
+ aTabStrip.removeAttribute('orient');
+ },
+
+ syncReinitTabbar : function TSTBrowser_syncReinitTabbar()
+ {
+ this.stopRendering();
+
+ this.ownerToolbar.classList.add(this.kTABBAR_TOOLBAR);
+ this.ownerToolbar.classList.remove(this.kTABBAR_TOOLBAR_READY);
+ Array.slice(this.document.querySelectorAll('.'+this.kTABBAR_TOOLBAR_READY_POPUP))
+ .forEach(this.safeRemovePopup, this);
+
+ var position = this._lastTabbarPositionBeforeDestroyed || this.position;
+ delete this._lastTabbarPositionBeforeDestroyed;
+
+ var self = this;
+ this.doAndWaitDOMEvent(
+ this.kEVENT_TYPE_TABBAR_INITIALIZED,
+ this.window,
+ 100,
+ function() {
+ self.initTabbar(position, 'top');
+ }
+ );
+ this.reinitAllTabs(true);
+
+ this.tabbarDNDObserver.startListenEvents();
+
+ this.treeViewEnabled = this._lastTreeViewEnabledBeforeDestroyed;
+ delete this._lastTreeViewEnabledBeforeDestroyed;
+
+ this.updateFloatingTabbar(this.kTABBAR_UPDATE_BY_RESET);
+
+ this.startRendering();
+ },
+
+ updateCustomizedTabsToolbar : function TSTBrowser_updateCustomizedTabsToolbar()
+ {
+ var d = this.document;
+
+ var newToolbar = this.ownerToolbar;
+ newToolbar.classList.add(this.kTABBAR_TOOLBAR_READY);
+
+ var oldToolbar = d.querySelector('.'+this.kTABBAR_TOOLBAR_READY);
+ if (oldToolbar == newToolbar)
+ return;
+
+ if (oldToolbar && oldToolbar != newToolbar) {
+ this.safeRemovePopup(d.getElementById(oldToolbar.id+'-'+this.kTABBAR_TOOLBAR_READY_POPUP));
+ oldToolbar.classList.remove(this.kTABBAR_TOOLBAR_READY);
+ }
+
+ var id = newToolbar.id+'-'+this.kTABBAR_TOOLBAR_READY_POPUP;
+ var panel = d.getElementById(id);
+ if (!panel) {
+ panel = d.createElement('panel');
+ panel.setAttribute('id', id);
+ panel.setAttribute('class', this.kTABBAR_TOOLBAR_READY_POPUP);
+ panel.setAttribute('noautohide', true);
+ panel.setAttribute('onmouseover', 'this.hidePopup()');
+ panel.setAttribute('ondragover', 'this.hidePopup()');
+ panel.appendChild(d.createElement('label'));
+ let position = this._lastTabbarPositionBeforeDestroyed || this.position;
+ let label = utils.treeBundle.getString('toolbarCustomizing_tabbar_'+(position == 'left' || position == 'right' ? 'vertical' : 'horizontal' ));
+ panel.firstChild.appendChild(d.createTextNode(label));
+ d.getElementById('mainPopupSet').appendChild(panel);
+ }
+ panel.openPopup(newToolbar, 'end_after', 0, 0, false, false);
+ },
+ safeRemovePopup : function TSTBrowser_safeRemovePopup(aPopup)
+ {
+ if (!aPopup)
+ return;
+ if (aPopup.state == 'open') {
+ aPopup.addEventListener('popuphidden', function onPopuphidden(aEvent) {
+ aPopup.removeEventListener(aEvent.type, onPopuphidden, false);
+ aPopup.parentNode.removeChild(aPopup);
+ }, false);
+ aPopup.hidePopup();
+ }
+ else {
+ aPopup.parentNode.removeChild(aPopup);
+ }
+ },
+
+/* nsIObserver */
+
+ domains : [
+ 'extensions.treestyletab.',
+ 'browser.tabs.closeButtons',
+ 'browser.tabs.closeWindowWithLastTab',
+ 'browser.tabs.autoHide',
+ 'browser.tabs.animate'
+ ],
+
+ observe : function TSTBrowser_observe(aSubject, aTopic, aData)
+ {
+ switch (aTopic)
+ {
+ case this.kTOPIC_INDENT_MODIFIED:
+ if (this.indent > -1)
+ this.updateAllTabsIndent();
+ return;
+
+ case this.kTOPIC_COLLAPSE_EXPAND_ALL:
+ if (!aSubject || aSubject == this.window) {
+ aData = String(aData);
+ this.collapseExpandAllSubtree(
+ aData.indexOf('collapse') > -1,
+ aData.indexOf('now') > -1
+ );
+ }
+ return;
+
+ case 'lightweight-theme-styling-update':
+ return this.updateFloatingTabbar(this.kTABBAR_UPDATE_BY_APPEARANCE_CHANGE);
+
+ case this.kTOPIC_CHANGE_TREEVIEW_AVAILABILITY:
+ return this.treeViewEnabled = (aData != 'false');
+
+ case 'nsPref:changed':
+ return this.onPrefChange(aData);
+
+ default:
+ return;
+ }
+ },
+
+ onPrefChange : function TSTBrowser_onPrefChange(aPrefName)
+ {
+ // ignore after destruction
+ if (!this.window || !this.window.TreeStyleTabService)
+ return;
+
+ var b = this.mTabBrowser;
+ var value = prefs.getPref(aPrefName);
+ var tabContainer = b.mTabContainer;
+ var tabs = this.getAllTabs(b);
+ switch (aPrefName)
+ {
+ case 'extensions.treestyletab.tabbar.position':
+ if (this.shouldApplyNewPref)
+ this.position = value;
+ return;
+
+ case 'extensions.treestyletab.tabbar.invertTab':
+ case 'extensions.treestyletab.tabbar.multirow':
+ this.initTabbar();
+ this.updateAllTabsIndent();
+ for (let i = 0, maxi = tabs.length; i < maxi; i++)
+ {
+ this.initTabContents(tabs[i]);
+ }
+ return;
+ case 'extensions.treestyletab.tabbar.invertTabContents':
+ this.setTabbrowserAttribute(this.kTAB_CONTENTS_INVERTED, value);
+ for (let i = 0, maxi = tabs.length; i < maxi; i++)
+ {
+ this.initTabContents(tabs[i]);
+ }
+ return;
+
+ case 'extensions.treestyletab.tabbar.invertClosebox':
+ this.setTabbrowserAttribute(this.kCLOSEBOX_INVERTED, value);
+ for (let i = 0, maxi = tabs.length; i < maxi; i++)
+ {
+ this.initTabContents(tabs[i]);
+ }
+ return;
+
+ case 'extensions.treestyletab.tabbar.style':
+ case 'extensions.treestyletab.tabbar.style.aero':
+ this.setTabbarStyle(utils.getTreePref('tabbar.style'));
+ value = utils.getTreePref('twisty.style');
+ if (value != 'auto')
+ return;
+ case 'extensions.treestyletab.twisty.style':
+ return this.setTwistyStyle(value);
+
+ case 'extensions.treestyletab.showBorderForFirstTab':
+ return this.setTabbrowserAttribute(this.kFIRSTTAB_BORDER, value);
+
+ case 'extensions.treestyletab.tabbar.fixed.horizontal':
+ if (!this.shouldApplyNewPref)
+ return;
+ this.setTabbrowserAttribute(this.kFIXED+'-horizontal', value ? 'true' : null, b);
+ case 'extensions.treestyletab.maxTreeLevel.horizontal':
+ case 'extensions.treestyletab.allowSubtreeCollapseExpand.horizontal':
+ if (!this.isVertical)
+ this.updateTabbarState(true);
+ return;
+
+ case 'extensions.treestyletab.tabbar.fixed.vertical':
+ if (!this.shouldApplyNewPref)
+ return;
+ this.setTabbrowserAttribute(this.kFIXED+'-vertical', value ? 'true' : null, b);
+ case 'extensions.treestyletab.maxTreeLevel.vertical':
+ case 'extensions.treestyletab.allowSubtreeCollapseExpand.vertical':
+ if (this.isVertical)
+ this.updateTabbarState(true);
+ return;
+
+ case 'extensions.treestyletab.tabbar.width':
+ case 'extensions.treestyletab.tabbar.shrunkenWidth':
+ if (!this.shouldApplyNewPref)
+ return;
+ if (!this.autoHide.isResizing && this.isVertical) {
+ this.removeTabStripAttribute('width');
+ this.setTabStripAttribute('width', this.autoHide.placeHolderWidthFromMode);
+ this.updateFloatingTabbar(this.kTABBAR_UPDATE_BY_PREF_CHANGE);
+ }
+ this.checkTabsIndentOverflow();
+ return;
+
+ case 'extensions.treestyletab.tabbar.height':
+ if (!this.shouldApplyNewPref)
+ return;
+ this._horizontalTabMaxIndentBase = 0;
+ this.checkTabsIndentOverflow();
+ return;
+
+ case 'extensions.treestyletab.tabbar.autoShow.mousemove':
+ let (toggler = this.document.getAnonymousElementByAttribute(b, 'class', this.kTABBAR_TOGGLER)) {
+ if (toggler) {
+ if (value)
+ toggler.removeAttribute('hidden');
+ else
+ toggler.setAttribute('hidden', true);
+ }
+ }
+ return;
+
+ case 'extensions.treestyletab.tabbar.invertScrollbar':
+ this.setTabbrowserAttribute(this.kINVERT_SCROLLBAR, value);
+ this.positionPinnedTabs();
+ return;
+
+ case 'extensions.treestyletab.tabbar.narrowScrollbar':
+ return this.setTabbrowserAttribute(this.kNARROW_SCROLLBAR, value);
+
+ case 'extensions.treestyletab.maxTreeLevel.phisical':
+ if (this.maxTreeLevelPhisical = value)
+ this.promoteTooDeepLevelTabs();
+ return;
+
+ case 'browser.tabs.animate':
+ this.setTabbrowserAttribute(this.kANIMATION_ENABLED,
+ prefs.getPref('browser.tabs.animate') !== false
+ ? 'true' : null
+ );
+ return;
+
+ case 'browser.tabs.closeButtons':
+ case 'browser.tabs.closeWindowWithLastTab':
+ return this.updateInvertedTabContentsOrder(true);
+
+ case 'browser.tabs.autoHide':
+ if (this.getTabs(this.mTabBrowser).length == 1)
+ this.updateFloatingTabbar(this.kTABBAR_UPDATE_BY_SHOWHIDE_TABBAR);
+ return;
+
+ case 'extensions.treestyletab.tabbar.autoHide.mode':
+ case 'extensions.treestyletab.tabbar.autoHide.mode.fullscreen':
+ return this.autoHide; // ensure initialized
+
+ case 'extensions.treestyletab.pinnedTab.faviconized':
+ return this.positionPinnedTabsWithDelay();
+
+ case 'extensions.treestyletab.counter.role.horizontal':
+ if (!this.isVertical) {
+ let self = this;
+ if (this.deferredTasks[aPrefName])
+ this.deferredTasks[aPrefName].cancel();
+ (this.deferredTasks[aPrefName] = this.Deferred
+ .next(function() { self.updateAllTabsCount(); }))
+ .error(this.defaultDeferredErrorHandler).next(function() {
+ delete self.deferredTasks[aPrefName];
+ });
+ }
+ return;
+ case 'extensions.treestyletab.counter.role.vertical':
+ if (this.isVertical) {
+ let self = this;
+ if (this.deferredTasks[aPrefName])
+ this.deferredTasks[aPrefName].cancel();
+ (this.deferredTasks[aPrefName] = this.Deferred
+ .next(function() { self.updateAllTabsCount(); }))
+ .error(this.defaultDeferredErrorHandler).next(function() {
+ delete self.deferredTasks[aPrefName];
+ });
+ }
+ return;
+
+ default:
+ return;
+ }
+ },
+ setTabbarStyle : function TSTBrowser_setTabbarStyle(aStyle)
+ {
+ if (/^(default|plain|flat|mixed|vertigo|metal|sidebar)(-aero)?$/.test(aStyle))
+ aStyle = aStyle.toLowerCase();
+
+ if (aStyle.indexOf('default') == 0) { // old name (for compatibility)
+ utils.setTreePref('tabbar.style', aStyle = aStyle.replace('default', 'plain'));
+ }
+
+ if (aStyle) {
+ let additionalValues = [];
+ if (/^(plain|flat|mixed|vertigo)$/.test(aStyle))
+ additionalValues.push('square');
+ if (/^(plain|flat|mixed)$/.test(aStyle))
+ additionalValues.push('border');
+ if (/^(flat|mixed)$/.test(aStyle))
+ additionalValues.push('color');
+ if (/^(plain|mixed)$/.test(aStyle))
+ additionalValues.push('shadow');
+ if (utils.getTreePref('tabbar.style.aero'))
+ additionalValues.push('aero');
+ if (additionalValues.length)
+ aStyle = additionalValues.join(' ')+' '+aStyle;
+
+ this.setTabbrowserAttribute(this.kSTYLE, aStyle);
+ }
+ else {
+ this.removeTabbrowserAttribute(this.kSTYLE);
+ }
+ },
+ setTwistyStyle : function TSTBrowser_setTwistyStyle(aStyle)
+ {
+ if (aStyle != 'auto') {
+ this.setTabbrowserAttribute(this.kTWISTY_STYLE, aStyle);
+ return;
+ }
+
+ aStyle = 'modern-black';
+
+ if (utils.getTreePref('tabbar.style') == 'sidebar') {
+ aStyle = 'osx';
+ }
+ else if (
+ prefs.getPref('extensions.informationaltab.thumbnail.enabled') &&
+ prefs.getPref('extensions.informationaltab.thumbnail.position') < 100
+ ) {
+ let self = this;
+ this.extensions.isAvailable('informationaltab@piro.sakura.ne.jp', {
+ ok : function() {
+ aStyle = 'retro';
+ self.setTabbrowserAttribute(self.kTWISTY_STYLE, aStyle);
+ },
+ ng : function() {
+ self.setTabbrowserAttribute(self.kTWISTY_STYLE, aStyle);
+ }
+ });
+ return;
+ }
+
+ this.setTabbrowserAttribute(this.kTWISTY_STYLE, aStyle);
+ },
+
+/* DOM Event Handling */
+
+ handleEvent : function TSTBrowser_handleEvent(aEvent)
+ {
+ switch (aEvent.type)
+ {
+ case 'TabOpen':
+ return this.onTabOpen(aEvent);
+
+ case 'TabClose':
+ return this.onTabClose(aEvent);
+
+ case 'TabMove':
+ return this.onTabMove(aEvent);
+
+ case 'TabShow':
+ case 'TabHide':
+ return this.onTabVisibilityChanged(aEvent);
+
+ case 'SSTabRestoring':
+ return this.onTabRestoring(aEvent);
+
+ case 'SSTabRestored':
+ return this.onTabRestored(aEvent);
+
+ case 'TabPinned':
+ return this.onTabPinned(aEvent.originalTarget);
+
+ case 'TabUnpinned':
+ return this.onTabUnpinned(aEvent.originalTarget);
+
+ case 'select':
+ return this.onTabSelect(aEvent);
+
+ case 'click':
+ return this.onClick(aEvent);
+
+ case 'dblclick':
+ return this.onDblClick(aEvent);
+
+ case 'MozMouseHittest': // to block default behaviors of the tab bar
+ return this.onMozMouseHittest(aEvent);
+
+ case 'mousedown':
+ return this.onMouseDown(aEvent);
+
+ case 'DOMMouseScroll':
+ return this.onDOMMouseScroll(aEvent);
+
+ case 'scroll':
+ return this.onScroll(aEvent);
+
+ case 'popupshowing':
+ return this.onPopupShowing(aEvent);
+
+ case 'popuphiding':
+ return this.onPopupHiding(aEvent);
+
+ case 'mouseover':
+ if (!this.tooltipManager)
+ this._initTooltipManager();
+ if (!this._DNDObserversInitialized)
+ this._initDNDObservers();
+ let (tab = aEvent.target) {
+ if (tab.__treestyletab__twistyHoverTimer)
+ this.window.clearTimeout(tab.__treestyletab__twistyHoverTimer);
+ if (this.isEventFiredOnTwisty(aEvent)) {
+ tab.setAttribute(this.kTWISTY_HOVER, true);
+ tab.__treestyletab__twistyHoverTimer = this.window.setTimeout(function(aSelf) {
+ tab.setAttribute(aSelf.kTWISTY_HOVER, true);
+ delete tab.__treestyletab__twistyHoverTimer;
+ }, 0, this);
+ }
+ }
+ return;
+
+ case 'mouseout':
+ let (tab = aEvent.target) {
+ if (tab.__treestyletab__twistyHoverTimer) {
+ this.window.clearTimeout(tab.__treestyletab__twistyHoverTimer);
+ delete tab.__treestyletab__twistyHoverTimer;
+ }
+ tab.removeAttribute(this.kTWISTY_HOVER);
+ }
+ return;
+
+ case 'dragover':
+ if (!this.tooltipManager)
+ this._initTooltipManager();
+ if (!this._DNDObserversInitialized)
+ this._initDNDObservers();
+ return;
+
+ case 'overflow':
+ case 'underflow':
+ return this.onTabbarOverflow(aEvent);
+
+ case 'resize':
+ return this.onResize(aEvent);
+
+
+ // toolbar customizing
+ case 'beforecustomization':
+ this.toolbarCustomizing = true;
+ return this.syncDestroyTabbar();
+ case 'aftercustomization':
+ // Ignore it, because 'aftercustomization' fired not
+ // following to 'beforecustomization' is invalid.
+ // Personal Titlebar addon (or others) fires a fake
+ // event on its startup process.
+ if (!this.toolbarCustomizing)
+ return;
+ this.toolbarCustomizing = false;
+ return this.syncReinitTabbar();
+ case 'customizationchange':
+ return this.updateCustomizedTabsToolbar();
+
+ case 'tabviewframeinitialized':
+ return this.lastTabViewGroup = this.getTabViewGroupId();
+
+
+ case this.kEVENT_TYPE_PRINT_PREVIEW_ENTERED:
+ return this.onTreeStyleTabPrintPreviewEntered(aEvent);
+ case this.kEVENT_TYPE_PRINT_PREVIEW_EXITED:
+ return this.onTreeStyleTabPrintPreviewExited(aEvent);
+
+
+ case this.kEVENT_TYPE_TAB_FOCUS_SWITCHING_END:
+ return this.cancelDelayedExpandOnTabSelect();
+
+
+ case 'SSWindowStateBusy':
+ return this.needRestoreTree = true;
+
+
+ case 'nsDOMMultipleTabHandlerTabsClosing':
+ if (!this.onTabsClosing(aEvent))
+ aEvent.preventDefault();
+ return;
+ }
+ },
+ lastScrollX : -1,
+ lastScrollY : -1,
+
+ restoreLastScrollPosition : function TSTBrowser_restoreLastScrollPosition()
+ {
+ if (this.lastScrollX < 0 || this.lastScrollY < 0 || !this.isVisible)
+ return;
+ var lastX = this.lastScrollX;
+ var lastY = this.lastScrollY;
+ this.clearLastScrollPosition();
+ if (!this.smoothScrollTask &&
+ !this.scrollBox._smoothScrollTimer) { // don't restore scroll position if another scroll is already running.
+ let x = {}, y = {};
+ let scrollBoxObject = this.scrollBoxObject;
+ scrollBoxObject.getPosition(x, y);
+ if (x.value != lastX || y.value != lastY)
+ scrollBoxObject.scrollTo(lastX, lastY);
+ }
+ },
+
+ clearLastScrollPosition : function TSTBrowser_clearLastScrollPosition()
+ {
+ this.lastScrollX = this.lastScrollY = -1;
+ },
+
+ updateLastScrollPosition : function TSTBrowser_updateLastScrollPosition()
+ {
+ if (!this.isVertical || !this.isVisible)
+ return;
+ var x = {}, y = {};
+ var scrollBoxObject = this.scrollBoxObject;
+ if (!scrollBoxObject)
+ return;
+ scrollBoxObject.getPosition(x, y);
+ this.lastScrollX = x.value;
+ this.lastScrollY = y.value;
+ },
+
+ cancelPerformingAutoScroll : function TSTBrowser_cancelPerformingAutoScroll(aOnlyCancel)
+ {
+ if (this.smoothScrollTask) {
+ this.animationManager.removeTask(this.smoothScrollTask);
+ this.smoothScrollTask = null;
+ }
+ this.clearLastScrollPosition();
+
+ if (this.deferredTasks['cancelPerformingAutoScroll']) {
+ this.deferredTasks['cancelPerformingAutoScroll'].cancel();
+ delete this.deferredTasks['cancelPerformingAutoScroll'];
+ }
+
+ if (aOnlyCancel)
+ return;
+
+ var self = this;
+ (this.deferredTasks['cancelPerformingAutoScroll'] = this.Deferred.wait(0.3))
+ .next(function() {
+ delete self.deferredTasks['cancelPerformingAutoScroll'];
+ }).error(this.defaultDeferredErrorHandler);
+ },
+
+ shouldCancelEnsureElementIsVisible : function TSTBRowser_shouldCancelEnsureElementIsVisible()
+ {
+ return (
+ this.deferredTasks['cancelPerformingAutoScroll'] &&
+ (new Error()).stack.indexOf('onxblDOMMouseScroll') < 0
+ );
+ },
+
+ onTabOpen : function TSTBrowser_onTabOpen(aEvent, aTab)
+ {
+ var tab = aTab || aEvent.originalTarget;
+ var b = this.mTabBrowser;
+
+ if (this.isTabInitialized(tab))
+ return false;
+
+ this.initTab(tab);
+
+ var hasStructure = this.treeStructure && this.treeStructure.length;
+ var pareintIndexInTree = hasStructure ? this.treeStructure.shift() : 0 ;
+ var lastRelatedTab = b._lastRelatedTab;
+
+ if (this.readiedToAttachNewTab) {
+ if (pareintIndexInTree < 0) { // there is no parent, so this is a new parent!
+ this.parentTab = tab.getAttribute(this.kID);
+ }
+
+ let parent = this.getTabById(this.parentTab);
+ if (parent) {
+ let tabs = [parent].concat(this.getDescendantTabs(parent));
+ parent = pareintIndexInTree > -1 && pareintIndexInTree < tabs.length ? tabs[pareintIndexInTree] : parent ;
+ }
+ if (parent) {
+ this.attachTabTo(tab, parent, {
+ dontExpand : this.shouldExpandAllTree
+ });
+ }
+
+ let refTab;
+ let newIndex = -1;
+ if (hasStructure) {
+ }
+ else if (this.insertBefore &&
+ (refTab = this.getTabById(this.insertBefore))) {
+ newIndex = refTab._tPos;
+ }
+ else if (
+ parent &&
+ utils.getTreePref('insertNewChildAt') == this.kINSERT_FISRT &&
+ (this.multipleCount <= 0 || this._addedCountInThisLoop <= 0)
+ ) {
+ /* 複数の子タブを一気に開く場合、最初に開いたタブだけを
+ 子タブの最初の位置に挿入し、続くタブは「最初の開いたタブ」と
+ 「元々最初の子だったタブ」との間に挿入していく */
+ newIndex = parent._tPos + 1;
+ if (refTab = this.getFirstChildTab(parent))
+ this.insertBefore = refTab.getAttribute(this.kID);
+ }
+
+ if (newIndex > -1) {
+ if (newIndex > tab._tPos)
+ newIndex--;
+ this.internallyTabMovingCount++;
+ b.moveTabTo(tab, newIndex);
+ this.internallyTabMovingCount--;
+ }
+
+ if (this.shouldExpandAllTree)
+ this.collapseExpandSubtree(parent, false);
+ }
+
+ this._addedCountInThisLoop++;
+ if (!this._addedCountClearTimer) {
+ this._addedCountClearTimer = this.window.setTimeout(function(aSelf) {
+ aSelf._addedCountInThisLoop = 0;
+ aSelf._addedCountClearTimer = null;
+ }, 0, this);
+ }
+
+ if (!this.readiedToAttachMultiple) {
+ this.stopToOpenChildTab(b);
+ }
+ else {
+ this.multipleCount++;
+ }
+
+ if (this.animationEnabled) {
+ this.updateTabCollapsed(tab, true, true);
+ let self = this;
+ this.updateTabCollapsed(tab, false, this.windowService.restoringTree, function() {
+ /**
+ * When the system is too slow, the animation can start after
+ * smooth scrolling is finished. The smooth scrolling should be
+ * started together with the start of the animation effect.
+ */
+ self.scrollToNewTab(tab);
+ });
+ }
+ else {
+ this.scrollToNewTab(tab);
+ }
+
+ this.updateInsertionPositionInfo(tab);
+
+ if (prefs.getPref('browser.tabs.autoHide'))
+ this.updateFloatingTabbar(this.kTABBAR_UPDATE_BY_SHOWHIDE_TABBAR);
+
+ if (this.canStackTabs)
+ this.updateTabsZIndex(true);
+
+ // if there is only one tab and new another tab is opened,
+ // closebox appearance is possibly changed.
+ var tabs = this.getTabs(b);
+ if (tabs.length == 2)
+ this.updateInvertedTabContentsOrder(tabs);
+
+ /**
+ * gBrowser.addTab() resets gBrowser._lastRelatedTab.owner
+ * when a new background tab is opened from the current tab,
+ * but it will fail with TST because gBrowser.moveTab() (called
+ * by TST) clears gBrowser._lastRelatedTab.
+ * So, we have to restore gBrowser._lastRelatedTab manually.
+ */
+ b._lastRelatedTab = lastRelatedTab;
+
+ return true;
+ },
+ _addedCountInThisLoop : 0,
+ _addedCountClearTimer : null,
+ _checkRestoringWindowTimerOnTabAdded : null,
+
+ scrollToNewTab : function TSTBrowser_scrollToNewTab(aTab)
+ {
+ if (!aTab.parentNode) // do nothing for closed tab!
+ return;
+
+ if (this.scrollToNewTabMode > 0)
+ this.scrollToTab(aTab, this.scrollToNewTabMode < 2);
+ },
+
+ updateInsertionPositionInfo : function TSTBrowser_updateInsertionPositionInfo(aTab)
+ {
+ if (!aTab.parentNode) // do nothing for closed tab!
+ return;
+
+ var prev = this.getPreviousSiblingTab(aTab);
+ if (prev) {
+ this.setTabValue(aTab, this.kINSERT_AFTER, prev.getAttribute(this.kID));
+ this.setTabValue(prev, this.kINSERT_BEFORE, aTab.getAttribute(this.kID));
+ }
+
+ var next = this.getNextSiblingTab(aTab);
+ if (next) {
+ this.setTabValue(aTab, this.kINSERT_BEFORE, next.getAttribute(this.kID));
+ this.setTabValue(next, this.kINSERT_AFTER, aTab.getAttribute(this.kID));
+ }
+ },
+
+ onTabClose : function TSTBrowser_onTabClose(aEvent)
+ {
+ var tab = aEvent.originalTarget;
+ var d = this.document;
+ var b = this.mTabBrowser;
+
+ tab.setAttribute(this.kREMOVED, true);
+
+ this.stopTabIndentAnimation(tab);
+ this.stopTabCollapseAnimation(tab);
+
+ var closeParentBehavior = this.getCloseParentBehaviorForTab(tab);
+
+ var collapsed = this.isCollapsed(tab);
+ if (collapsed)
+ this.stopRendering();
+
+ var backupAttributes = this._collectBackupAttributes(tab);
+ if (DEBUG)
+ dump('onTabClose: backupAttributes = '+JSON.stringify(backupAttributes)+'\n');
+
+ if (closeParentBehavior == this.kCLOSE_PARENT_BEHAVIOR_CLOSE_ALL_CHILDREN ||
+ this.isSubtreeCollapsed(tab))
+ this._closeChildTabs(tab);
+
+ this._saveAndUpdateReferenceTabsInfo(tab);
+
+ var firstChild = this.getFirstChildTab(tab);
+
+ this.detachAllChildren(tab, {
+ behavior : closeParentBehavior
+ });
+
+ var nextFocusedTab = null;
+ if (firstChild &&
+ (closeParentBehavior == this.kCLOSE_PARENT_BEHAVIOR_PROMOTE_ALL_CHILDREN ||
+ closeParentBehavior == this.kCLOSE_PARENT_BEHAVIOR_PROMOTE_FIRST_CHILD))
+ nextFocusedTab = firstChild;
+
+ var toBeClosedTabs = this._collectNeedlessGroupTabs(tab);
+
+ var parentTab = this.getParentTab(tab);
+ if (parentTab) {
+ if (!nextFocusedTab && tab == this.getLastChildTab(parentTab)) {
+ if (tab == this.getFirstChildTab(parentTab)) // this is the really last child
+ nextFocusedTab = parentTab;
+ else
+ nextFocusedTab = this.getPreviousSiblingTab(tab);
+ }
+
+ if (nextFocusedTab && toBeClosedTabs.indexOf(nextFocusedTab) > -1)
+ nextFocusedTab = this.getNextFocusedTab(parentTab);
+ }
+ else if (!nextFocusedTab) {
+ nextFocusedTab = this.getNextFocusedTab(tab);
+ }
+
+ if (nextFocusedTab && toBeClosedTabs.indexOf(nextFocusedTab) > -1)
+ nextFocusedTab = this.getNextFocusedTab(nextFocusedTab);
+
+ if (nextFocusedTab && nextFocusedTab.hasAttribute(this.kREMOVED))
+ nextFocusedTab = null;
+
+ this._reserveCloseRelatedTabs(toBeClosedTabs);
+
+ this.detachTab(tab, { dontUpdateIndent : true });
+
+ this._restoreTabAttributes(tab, backupAttributes);
+
+ if (b.selectedTab == tab)
+ this._tryMoveFocusFromClosingCurrentTab(nextFocusedTab);
+
+ this.updateLastScrollPosition();
+
+ this.destroyTab(tab);
+
+ if (tab.getAttribute('pinned') == 'true')
+ this.positionPinnedTabsWithDelay();
+
+ if (prefs.getPref('browser.tabs.autoHide'))
+ this.updateFloatingTabbar(this.kTABBAR_UPDATE_BY_SHOWHIDE_TABBAR);
+
+ if (this.canStackTabs)
+ this.updateTabsZIndex(true);
+
+ if (collapsed)
+ this.startRendering();
+ },
+
+ _collectBackupAttributes : function TSTBrowser_collectBackupAttributes(aTab)
+ {
+ var attributes = {};
+
+ if (this.hasChildTabs(aTab)) {
+ attributes[this.kCHILDREN] = this.getTabValue(aTab, this.kCHILDREN);
+ attributes[this.kSUBTREE_COLLAPSED] = this.getTabValue(aTab, this.kSUBTREE_COLLAPSED);
+ }
+
+ var ancestors = this.getAncestorTabs(aTab);
+ if (ancestors.length) {
+ let next = this.getNextSiblingTab(aTab);
+ ancestors = ancestors.map(function(aAncestor) {
+ if (!next && (next = this.getNextSiblingTab(aAncestor)))
+ attributes[this.kINSERT_BEFORE] = next.getAttribute(this.kID);
+ return aAncestor.getAttribute(this.kID);
+ }, this);
+ attributes[this.kANCESTOR] = ancestors.join('|');
+ }
+
+ return attributes;
+ },
+
+ _closeChildTabs : function TSTBrowser_closeChildTabs(aTab)
+ {
+ var tabs = this.getDescendantTabs(aTab);
+ if (!this.fireTabSubtreeClosingEvent(aTab, tabs))
+ return;
+
+ var subtreeCollapsed = this.isSubtreeCollapsed(aTab);
+ if (subtreeCollapsed)
+ this.stopRendering();
+
+ this.markAsClosedSet([aTab].concat(tabs));
+
+ tabs.reverse();
+ for (let i = 0, maxi = tabs.length; i < maxi; i++)
+ {
+ this.mTabBrowser.removeTab(tabs[i], { animate : true });
+ }
+
+ this.fireTabSubtreeClosedEvent(this.mTabBrowser, aTab, tabs);
+
+ if (subtreeCollapsed)
+ this.startRendering();
+ },
+
+ _collectNeedlessGroupTabs : function TSTBrowser_collectNeedlessGroupTabs(aTab)
+ {
+ var tabs = [];
+ if (!aTab || !aTab.parentNode)
+ return tabs;
+
+ var parent = this.getParentTab(aTab);
+ var siblings = this.getSiblingTabs(aTab);
+ var groupTabs = siblings.filter(function(aTab) {
+ return this.isTemporaryGroupTab(aTab);
+ }, this);
+ var groupTab = (
+ groupTabs.length == 1 &&
+ siblings.length == 1 &&
+ this.hasChildTabs(groupTabs[0])
+ ) ? groupTabs[0] : null ;
+ if (groupTab)
+ tabs.push(groupTab);
+
+ var shouldCloseParentTab = (
+ parent &&
+ this.isTemporaryGroupTab(parent) &&
+ this.getDescendantTabs(parent).length == 1
+ );
+ if (shouldCloseParentTab)
+ tabs.push(parent);
+
+ return tabs;
+ },
+
+ _reserveCloseRelatedTabs : function TSTBrowser_reserveCloseRelatedTabs(aTabs)
+ {
+ if (!aTabs.length)
+ return;
+
+ var key = 'onTabClose_'+parseInt(Math.random() * 65000);
+ var self = this;
+ (this.deferredTasks[key] = this.Deferred.next(function() {
+ aTabs.forEach(function(aTab) {
+ if (aTab.parentNode)
+ self.mTabBrowser.removeTab(aTab, { animate : true });
+ });
+ })).error(this.defaultDeferredErrorHandler).next(function() {
+ delete self.deferredTasks[key];
+ }).next(function() {
+ aTabs = null;
+ self = null;
+ key = null;
+ });
+ },
+
+ _saveAndUpdateReferenceTabsInfo : function TSTBrowser_saveAndUpdateReferenceTabsInfo(aTab)
+ {
+ var prev = this.getPreviousSiblingTab(aTab);
+ var next = this.getNextSiblingTab(aTab);
+ if (prev) {
+ this.setTabValue(aTab, this.kINSERT_AFTER, prev.getAttribute(this.kID));
+
+ if (next)
+ this.setTabValue(prev, this.kINSERT_BEFORE, next.getAttribute(this.kID));
+ else
+ this.deleteTabValue(prev, this.kINSERT_BEFORE);
+ }
+ if (next) {
+ this.setTabValue(aTab, this.kINSERT_BEFORE, next.getAttribute(this.kID));
+
+ if (prev)
+ this.setTabValue(next, this.kINSERT_AFTER, prev.getAttribute(this.kID));
+ else
+ this.deleteTabValue(next, this.kINSERT_AFTER);
+ }
+ },
+
+ _restoreTabAttributes : function TSTBrowser_restoreTabAttributes(aTab, aAttributes)
+ {
+ for (var i in aAttributes)
+ {
+ this.setTabValue(aTab, i, aAttributes[i]);
+ }
+ },
+
+ _tryMoveFocusFromClosingCurrentTab : function TSTBrowser_tryMoveFocusFromClosingCurrentTab(aNextFocusedTab)
+ {
+ if (!aNextFocusedTab || aNextFocusedTab.hidden)
+ return;
+
+ var currentTab = this.mTabBrowser.selectedTab;
+ var d = this.document;
+
+ var event = d.createEvent('Events');
+ event.initEvent(this.kEVENT_TYPE_FOCUS_NEXT_TAB, true, true);
+ var canFocus = currentTab.dispatchEvent(event);
+
+ // for backward compatibility
+ event = d.createEvent('Events');
+ event.initEvent(this.kEVENT_TYPE_FOCUS_NEXT_TAB.replace(/^nsDOM/, ''), true, true);
+ canFocus = canFocus && currentTab.dispatchEvent(event);
+
+ if (canFocus) {
+ this._focusChangedByCurrentTabRemove = true;
+ this.mTabBrowser.selectedTab = aNextFocusedTab;
+ }
+ },
+
+ onTabsClosing : function TSTBrowser_onTabsClosing(aEvent)
+ {
+ var tabs = aEvent.detail && aEvent.detail.tabs ||
+ aEvent.getData('tabs') // for backward compatibility;
+ var b = this.getTabBrowserFromChild(tabs[0]);
+
+ var trees = this.splitTabsToSubtrees(tabs);
+ if (trees.some(function(aTabs) {
+ return aTabs.length > 1 &&
+ !this.fireTabSubtreeClosingEvent(aTabs[0], aTabs);
+ }, this))
+ return false;
+
+ trees.forEach(this.markAsClosedSet, this);
+
+ var self = this;
+ let key = 'onTabClosing_'+parseInt(Math.random() * 65000);
+ (this.deferredTasks[key] = this.Deferred.next(function() {
+ for (let i = 0, maxi = trees.length; i < maxi; i++)
+ {
+ let tabs = trees[i];
+ self.fireTabSubtreeClosedEvent(b, tabs[0], tabs);
+ }
+ })).error(this.defaultDeferredErrorHandler).next(function() {
+ delete self.deferredTasks[key];
+ });
+
+ return true;
+ },
+
+ onTabMove : function TSTBrowser_onTabMove(aEvent)
+ {
+ var tab = aEvent.originalTarget;
+ var b = this.mTabBrowser;
+ tab.__treestyletab__previousPosition = aEvent.detail;
+
+ // When the tab was moved before TabOpen event is fired, we have to update manually.
+ var newlyOpened = !this.isTabInitialized(tab) && this.onTabOpen(null, tab);
+
+ // twisty vanished after the tab is moved!!
+ this.initTabContents(tab);
+
+ // On Firefox 29, 30 and laters, reopened (restored) tab can be
+ // placed in wrong place, because "TabMove" event fires before
+ // "SSTabRestoring" event and "kINSERT_BEFORE" information is
+ // unexpectedly cleared. So now I simulate the "SSTabRestoring"
+ // event here.
+ // See: https://github.com/piroor/treestyletab/issues/676#issuecomment-47700158
+ if (tab.__SS_extdata) {
+ let storedId = tab.__SS_extdata[this.kID]; // getTabValue() doesn't get the value!
+ if (storedId && tab.getAttribute(this.kID) != storedId)
+ this.onTabRestoring(aEvent);
+ }
+
+ if (this.hasChildTabs(tab) && !this.subTreeMovingCount) {
+ this.moveTabSubtreeTo(tab, tab._tPos);
+ }
+
+ var parentTab = this.getParentTab(tab);
+ if (parentTab && !this.subTreeChildrenMovingCount) {
+ this.updateChildrenArray(parentTab);
+ }
+
+ this.updateTabsCount(tab, true);
+
+ var prev = this.getPreviousSiblingTab(tab);
+ var next = this.getNextSiblingTab(tab);
+
+ if (prev) {
+ this.setTabValue(prev, this.kINSERT_BEFORE, tab.getAttribute(this.kID));
+ this.setTabValue(tab, this.kINSERT_AFTER, prev.getAttribute(this.kID));
+ }
+ else
+ this.deleteTabValue(tab, this.kINSERT_AFTER);
+
+ if (next) {
+ this.setTabValue(next, this.kINSERT_AFTER, tab.getAttribute(this.kID));
+ this.setTabValue(tab, this.kINSERT_BEFORE, next.getAttribute(this.kID));
+ }
+ else
+ this.deleteTabValue(tab, this.kINSERT_BEFORE);
+
+ var old = aEvent.detail;
+ if (old > tab._tPos)
+ old--;
+ var tabs = this.getAllTabs(b);
+ old = tabs[old];
+
+ prev = this.getPreviousSiblingTab(old);
+ next = this.getNextSiblingTab(old);
+
+ if (prev) {
+ this.setTabValue(prev, this.kINSERT_BEFORE, old.getAttribute(this.kID));
+ this.setTabValue(old, this.kINSERT_AFTER, prev.getAttribute(this.kID));
+ }
+ else
+ this.deleteTabValue(old, this.kINSERT_AFTER);
+
+ if (next) {
+ this.setTabValue(next, this.kINSERT_AFTER, old.getAttribute(this.kID));
+ this.setTabValue(old, this.kINSERT_BEFORE, next.getAttribute(this.kID));
+ }
+ else
+ this.deleteTabValue(old, this.kINSERT_BEFORE);
+
+ this.positionPinnedTabsWithDelay();
+
+ if (this.canStackTabs)
+ this.updateTabsZIndex(true);
+
+ if (
+ this.subTreeMovingCount ||
+ this.internallyTabMovingCount ||
+ // We don't have to fixup tree structure for a NEW TAB
+ // which has already been structured.
+ (newlyOpened && this.getParentTab(tab))
+ )
+ return;
+
+ this.attachTabFromPosition(tab, aEvent.detail);
+ this.rearrangeTabViewItems(tab);
+ },
+
+ attachTabFromPosition : function TSTBrowser_attachTabFromPosition(aTab, aOldPosition)
+ {
+ var parent = this.getParentTab(aTab);
+
+ if (aOldPosition === void(0))
+ aOldPosition = aTab._tPos;
+
+ var pos = this.getChildIndex(aTab, parent);
+ var oldPos = this.getChildIndex(this.getAllTabs(this.mTabBrowser)[aOldPosition], parent);
+ var delta;
+ if (pos == oldPos) { // no move?
+ return;
+ }
+ else if (pos < 0 || oldPos < 0) {
+ delta = 2;
+ }
+ else {
+ delta = Math.abs(pos - oldPos);
+ }
+
+ var prevTab = this.getPreviousTab(aTab);
+ var nextTab = this.getNextTab(aTab);
+
+ var tabs = this.getDescendantTabs(aTab);
+ if (tabs.length) {
+ nextTab = this.getNextTab(tabs[tabs.length-1]);
+ }
+
+ var prevParent = this.getParentTab(prevTab);
+ var nextParent = this.getParentTab(nextTab);
+
+ var prevLevel = prevTab ? Number(prevTab.getAttribute(this.kNEST)) : -1 ;
+ var nextLevel = nextTab ? Number(nextTab.getAttribute(this.kNEST)) : -1 ;
+
+ var newParent;
+
+ if (!prevTab) { // moved to topmost position
+ newParent = null;
+ }
+ else if (!nextTab) { // moved to last position
+ newParent = (delta > 1) ? prevParent : parent ;
+ }
+ else if (prevParent == nextParent) { // moved into existing tree
+ newParent = prevParent;
+ }
+ else if (prevLevel > nextLevel) { // moved to end of existing tree
+ if (this.mTabBrowser.selectedTab != aTab) { // maybe newly opened tab
+ newParent = prevParent;
+ }
+ else { // maybe drag and drop
+ var realDelta = Math.abs(aTab._tPos - aOldPosition);
+ newParent = realDelta < 2 ? prevParent : (parent || nextParent) ;
+ }
+ }
+ else if (prevLevel < nextLevel) { // moved to first child position of existing tree
+ newParent = parent || nextParent;
+ }
+
+ if (newParent != parent) {
+ if (newParent) {
+ if (newParent.hidden == aTab.hidden)
+ this.attachTabTo(aTab, newParent, { insertBefore : nextTab });
+ }
+ else {
+ this.detachTab(aTab);
+ }
+ }
+ },
+
+ updateChildrenArray : function TSTBrowser_updateChildrenArray(aTab)
+ {
+ if (!aTab.parentNode) // do nothing for closed tab!
+ return;
+
+ var children = this.getChildTabs(aTab);
+ children.sort(this.sortTabsByOrder);
+ this.setTabValue(
+ aTab,
+ this.kCHILDREN,
+ children
+ .map(function(aItem) {
+ return aItem.getAttribute(this.kID);
+ }, this)
+ .join('|')
+ );
+ },
+
+ // for TabView (Panorama aka Tab Candy)
+ rearrangeTabViewItems : function TSTBrowser_rearrangeTabViewItems(aTab)
+ {
+ if (
+ !aTab.parentNode || // do nothing for closed tab!
+ !aTab.tabItem ||
+ !aTab.tabItem.parent ||
+ !aTab.tabItem.parent.reorderTabItemsBasedOnTabOrder
+ )
+ return;
+
+ aTab.tabItem.parent.reorderTabItemsBasedOnTabOrder();
+ },
+
+ // for TabView (Panorama aka Tab Candy)
+ onTabVisibilityChanged : function TSTBrowser_onTabVisibilityChanged(aEvent)
+ {
+ /**
+ * Note: On this timing, we cannot know that which is the reason of this
+ * event, by exitting from Panorama or the "Move to Group" command in the
+ * context menu on tabs. So, we have to do operations with a delay to compare
+ * last and current group which is updated in the next event loop.
+ */
+
+ var tab = aEvent.originalTarget;
+ this.updateInvertedTabContentsOrder(tab);
+ this.tabVisibilityChangedTabs.push({
+ tab : tab,
+ type : aEvent.type
+ });
+
+ if (this.tabVisibilityChangedTimer) {
+ this.window.clearTimeout(this.tabVisibilityChangedTimer);
+ this.tabVisibilityChangedTimer = null;
+ }
+
+ this.tabVisibilityChangedTimer = this.window.setTimeout(function(aSelf) {
+ aSelf.tabVisibilityChangedTimer = null;
+
+ var tabs = aSelf.tabVisibilityChangedTabs;
+ if (!tabs.length)
+ return;
+
+ // restore tree from bottom safely
+ var restoreTabs = tabs.filter(function(aChanged) {
+ return aChanged.type == 'TabShow' &&
+ aChanged.tab.__treestyletab__restoreState == aSelf.RESTORE_STATE_READY_TO_RESTORE;
+ })
+ .map(function(aChanged) {
+ return aChanged.tab;
+ })
+ .sort(function(aA, aB) {
+ return aB._tPos - aA._tPos;
+ })
+ .filter(aSelf.restoreOneTab, aSelf);
+ for (let i = 0, maxi = restoreTabs.length; i < maxi; i++)
+ {
+ let tab = restoreTabs[i];
+ aSelf.updateInsertionPositionInfo(tab);
+ delete tab.__treestyletab__restoreState;
+ }
+
+ var currentGroupId = aSelf.getTabViewGroupId();
+ if (aSelf.lastTabViewGroup && currentGroupId != aSelf.lastTabViewGroup) {
+ // We should clear it first, because updateTreeByTabVisibility() never change visibility of tabs.
+ aSelf.tabVisibilityChangedTabs = [];
+ aSelf.updateTreeByTabVisibility(tabs.map(function(aChanged) { return aChanged.tab; }));
+ }
+ else {
+ // For tabs moved by "Move to Group" command in the context menu on tabs
+ var processedTabs = {};
+ /**
+ * subtreeFollowParentAcrossTabGroups() can change visibility of child tabs, so,
+ * we must not clear tabVisibilityChangedTabs here, and we have to use
+ * simple "for" loop instead of Array.prototype.forEach.
+ */
+ for (let i = 0; i < aSelf.tabVisibilityChangedTabs.length; i++)
+ {
+ let changed = aSelf.tabVisibilityChangedTabs[i];
+ let tab = changed.tab;
+ if (aSelf.getAncestorTabs(tab).some(function(aTab) {
+ return processedTabs[aTab.getAttribute(aSelf.kID)];
+ }))
+ continue;
+ aSelf.subtreeFollowParentAcrossTabGroups(tab);
+ processedTabs[tab.getAttribute(aSelf.kID)] = true;
+ }
+ // now we can clear it!
+ aSelf.tabVisibilityChangedTabs = [];
+ }
+ aSelf.lastTabViewGroup = currentGroupId;
+ aSelf.checkTabsIndentOverflow();
+ }, 0, this);
+ },
+ tabVisibilityChangedTimer : null,
+ lastTabViewGroup : null,
+
+ updateTreeByTabVisibility : function TSTBrowser_updateTreeByTabVisibility(aChangedTabs)
+ {
+ this.internallyTabMovingCount++;
+
+ var allTabs = this.getAllTabs(this.mTabBrowser);
+ var normalTabs = allTabs.filter(function(aTab) {
+ return !aTab.hasAttribute('pinned');
+ });
+ aChangedTabs = aChangedTabs || normalTabs;
+
+ var shownTabs = aChangedTabs.filter(function(aTab) {
+ return !aTab.hidden;
+ });
+
+ var movingTabToAnotherGroup = !shownTabs.length;
+ var switchingGroup = !movingTabToAnotherGroup;
+
+ var lastIndex = allTabs.length - 1;
+ var lastMovedTab;
+ normalTabs = normalTabs.slice(0).reverse();
+ for (let i = 0, maxi = normalTabs.length; i < maxi; i++)
+ {
+ let tab = normalTabs[i];
+ let parent = this.getParentTab(tab);
+ let attached = false;
+ if (parent && (tab.hidden != parent.hidden)) {
+ let lastNextTab = null;
+ this.getAncestorTabs(tab).some(function(aAncestor) {
+ if (aAncestor.hidden == tab.hidden) {
+ this.attachTabTo(tab, aAncestor, {
+ dontMove : true,
+ insertBefore : lastNextTab
+ });
+ attached = true;
+ return true;
+ }
+ lastNextTab = this.getNextSiblingTab(aAncestor);
+ return false;
+ }, this);
+ if (!attached) {
+ this.collapseExpandTab(tab, false, true);
+ this.detachTab(tab);
+ }
+ }
+
+ if (aChangedTabs.indexOf(tab) < 0)
+ continue;
+
+ if (
+ switchingGroup &&
+ !tab.hidden &&
+ !attached &&
+ !parent
+ ) {
+ let prev = this.getPreviousTab(tab);
+ let next = this.getNextTab(tab);
+ if (
+ (prev && aChangedTabs.indexOf(prev) < 0 && !prev.hidden) ||
+ (next && aChangedTabs.indexOf(next) < 0 && !next.hidden)
+ )
+ this.attachTabFromPosition(tab, lastIndex);
+ }
+
+ if (movingTabToAnotherGroup && tab.hidden) {
+ let index = lastMovedTab ? lastMovedTab._tPos - 1 : lastIndex ;
+ this.mTabBrowser.moveTabTo(tab, index);
+ lastMovedTab = tab;
+ }
+ }
+ this.internallyTabMovingCount--;
+ },
+
+ subtreeFollowParentAcrossTabGroups : function TSTBrowser_subtreeFollowParentAcrossTabGroups(aParent)
+ {
+ if (this.tabViewTreeIsMoving)
+ return;
+
+ var id = this.getTabViewGroupId(aParent);
+ if (!id)
+ return;
+
+ this.tabViewTreeIsMoving = true;
+ this.internallyTabMovingCount++;
+ var w = this.window;
+ var b = this.mTabBrowser;
+ var lastCount = this.getAllTabs(b).length - 1;
+
+ this.detachTab(aParent);
+ b.moveTabTo(aParent, lastCount);
+ var descendantTabs = this.getDescendantTabs(aParent);
+ for (let i = 0, maxi = descendantTabs.length; i < maxi; i++)
+ {
+ let tab = descendantTabs[i];
+ w.TabView.moveTabTo(tab, id);
+ b.moveTabTo(tab, lastCount);
+ }
+ this.internallyTabMovingCount--;
+ this.tabViewTreeIsMoving = false;
+ },
+ tabViewTreeIsMoving : false,
+
+ getTabViewGroupId : function TSTBrowser_getTabViewGroupId(aTab)
+ {
+ var tab = aTab || this.mTabBrowser.selectedTab;
+ var item = tab._tabViewTabItem;
+ if (!item)
+ return null;
+
+ var group = item.parent;
+ if (!group)
+ return null;
+
+ return group.id;
+ },
+
+ onRestoreTabContentStarted : function TSTBrowser_onRestoreTabContentStarted(aTab)
+ {
+ aTab.linkedBrowser.__treestyletab__toBeRestored = true;
+ },
+
+ onTabRestoring : function TSTBrowser_onTabRestoring(aEvent)
+ {
+ this.restoreTree();
+
+ var tab = aEvent.originalTarget;
+
+ tab.linkedBrowser.__treestyletab__toBeRestored = false;
+ this.handleRestoredTab(tab);
+
+ /**
+ * Updating of the counter which is used to know how many tabs were
+ * restored in a time.
+ */
+ this.windowService.restoringCount++;
+ /**
+ * By nsSessionStore.js, the next "SSTabRestoring" event will be fined
+ * with "window.setTimeout()" following this "SSTabRestoring" event.
+ * So, we have to do "setTimeout()" twice, instead of "Deferred.next()".
+ */
+ var self = this;
+ this.window.setTimeout(function() {
+ /**
+ * On this timing, the next "SSTabRestoring" is not fired yet.
+ * We only register the countdown task for the next event loop.
+ */
+ let key = 'onTabRestoring_'+parseInt(Math.random() * 65000);
+ (self.deferredTasks[key] = self.windowService.Deferred.next(function() {
+ /**
+ * On this timing, the next "SSTabRestoring" was fired.
+ * Now we can decrement the counter.
+ */
+ self.windowService.restoringCount--;
+ })).error(self.defaultDeferredErrorHandler).next(function() {
+ delete self.deferredTasks[key];
+ });
+ }, 0);
+
+ if (!tab.selected &&
+ this.mTabBrowser.currentURI.spec == 'about:sessionrestore') {
+ let frame = this.mTabBrowser.contentWindow;
+ frame = frame.wrappedJSObject || frame;
+ let tree = frame.document.getElementById('tabList');
+ let data = frame.gTreeData;
+ if (tree && data) {
+ let item = data[tree.currentIndex];
+ this.window.setTimeout(function(aSelf, aTab, aTitle, aParent) {
+ if (aTab.label== aTitle)
+ aSelf.attachTabTo(aTab, aParent);
+ }, 0, this, tab, item.label, this.mTabBrowser.selectedTab);
+ }
+ }
+ },
+
+ RESTORED_TREE_COLLAPSED_STATE_LAST_STATE : -1,
+ RESTORED_TREE_COLLAPSED_STATE_COLLAPSED : 0,
+ RESTORED_TREE_COLLAPSED_STATE_EXPANDED : 1,
+ RESTORE_STATE_INITIAL : 0,
+ RESTORE_STATE_READY_TO_RESTORE : 1,
+ RESTORE_STATE_STRUCTURE_RESTORED : 2,
+ handleRestoredTab : function TSTBrowser_handleRestoredTab(aTab)
+ {
+ if (aTab.__treestyletab__restoreState == this.RESTORE_STATE_READY_TO_RESTORE) {
+ // this is a hidden tab in the background group, and
+ // have to be restored by restoreOneTab() on "TabShown" event.
+ this.deleteTabValue(aTab, this.kCLOSED_SET_ID);
+ return;
+ }
+
+ var [id, mayBeDuplicated] = this._restoreTabId(aTab);
+ var structureRestored = aTab.__treestyletab__restoreState == this.RESTORE_STATE_STRUCTURE_RESTORED;
+ var children = this.getTabValue(aTab, this.kCHILDREN);
+ if (
+ !structureRestored &&
+ (
+ !mayBeDuplicated ||
+ aTab.getAttribute(this.kCHILDREN) != children
+ )
+ ) {
+ // failsafe
+ this.detachAllChildren(aTab, {
+ dontUpdateIndent : true,
+ dontAnimate : this.windowService.restoringTree
+ });
+ }
+
+ var closeSetId = !structureRestored && this._getCloseSetId(aTab, mayBeDuplicated);
+
+ // remove temporary cache
+ var currentId = aTab.getAttribute(this.kID);
+ if (id != currentId &&
+ currentId &&
+ currentId in this.tabsHash &&
+ this.tabsHash[currentId] == aTab)
+ delete this.tabsHash[currentId];
+
+ this.setTabValue(aTab, this.kID, id);
+ this.tabsHash[id] = aTab;
+
+ if (structureRestored) {
+ this._fixMissingAttributesFromSessionData(aTab);
+ }
+ else {
+ let isSubtreeCollapsed = this._restoreSubtreeCollapsedState(aTab);
+
+ let restoringMultipleTabs = this.windowService.restoringTree;
+ let options = {
+ dontExpand : restoringMultipleTabs,
+ dontUpdateIndent : true,
+ dontAnimate : restoringMultipleTabs
+ };
+ let childTabs = this._restoreChildTabsRelation(aTab, children, mayBeDuplicated, options);
+
+ this._restoreTabPositionAndIndent(aTab, childTabs, mayBeDuplicated);
+
+ if (closeSetId)
+ this.restoreClosedSet(closeSetId, aTab);
+
+ if (isSubtreeCollapsed)
+ this.collapseExpandSubtree(aTab, isSubtreeCollapsed);
+ }
+
+ if (mayBeDuplicated) {
+ this.clearRedirectionTableWithDelay();
+ this.clearRedirectbTabRelationsWithDelay(aTab);
+ }
+
+ delete aTab.__treestyletab__restoreState;
+ },
+
+ _restoreTabId : function TSTBrowser_restoreTabId(aTab)
+ {
+ // kID can be overridden by nsSessionStore. kID_NEW is for failsafe.
+ var currentId = aTab.getAttribute(this.kID_NEW) || aTab.getAttribute(this.kID);
+ aTab.removeAttribute(this.kID_NEW);
+ var restoredId = this.getTabValue(aTab, this.kID);
+ var mayBeDuplicated = false;
+
+ aTab.setAttribute(this.kID_RESTORING, restoredId);
+ if (this.isTabDuplicated(aTab)) {
+ mayBeDuplicated = true;
+ /**
+ * If the tab has its ID as the attribute, then we should use it
+ * instead of redirected ID, because the tab has been possibly
+ * attached to another tab.
+ */
+ restoredId = currentId || this.redirectId(restoredId);
+ }
+ aTab.removeAttribute(this.kID_RESTORING);
+
+ return [restoredId || currentId, mayBeDuplicated];
+ },
+
+ _getCloseSetId : function TSTBrowser_getCloseSetId(aTab, aMayBeDuplicated)
+ {
+ var closeSetId = null;
+ if (!aMayBeDuplicated) {
+ closeSetId = this.getTabValue(aTab, this.kCLOSED_SET_ID);
+ /**
+ * If the tab is not a duplicated but it has a parent, then,
+ * it is wrongly attacched by tab moving on restoring.
+ * Restoring the old ID (the next statement) breaks the children
+ * list of the temporary parent and causes many problems.
+ * So, to prevent these problems, I detach the tab from the temporary
+ * parent manually.
+ * If the ID stored in the session equals to the value of the
+ * attribute stored in the element itself, then don't reset the
+ * tab, because the restoring session is got from the tab itself.
+ * ( like SS.setTabState(tab, SS.getTabState(tab)) )
+ */
+ if (this.getTabValue(aTab, this.kID) != aTab.getAttribute(this.kID))
+ this.resetTab(aTab, false);
+ }
+ this.deleteTabValue(aTab, this.kCLOSED_SET_ID);
+ return closeSetId;
+ },
+
+ _fixMissingAttributesFromSessionData : function TSTBrowser_fixMissingAttributesFromSessionData(aTab)
+ {
+ /**
+ * By some reasons (ex. persistTabAttribute()), actual state of
+ * the tab (attributes) can be lost on SSTabRestoring.
+ * For failsafe, we must override actual attributes by stored
+ * values.
+ */
+ var keys = [
+ this.kINSERT_BEFORE,
+ this.kINSERT_AFTER
+ ];
+ for (let i = 0, maxi = keys.length; i < maxi; i++)
+ {
+ let key = keys[i];
+ let tab = this.getTabValue(aTab, key);
+ if (this.getTabById(tab))
+ this.setTabValue(aTab, key, tab);
+ }
+
+ let parentId = this.getTabValue(aTab, this.kPARENT);
+ let parentTab = this.getTabById(parentId);
+ if (parentTab && parentTab._tPos < aTab._tPos)
+ this.setTabValue(aTab, this.kPARENT, parentId);
+ else
+ this.deleteTabValue(aTab, this.kPARENT);
+
+ let ancestors = [aTab].concat(this.getAncestorTabs(aTab));
+ let children = this.getTabValue(aTab, this.kCHILDREN);
+ children = children.split('|').filter(function(aChild) {
+ let tab = this.getTabById(aChild);
+ return tab && ancestors.indexOf(tab) < 0;
+ }, this);
+ this.setTabValue(aTab, this.kCHILDREN, children.join('|'));
+
+ let subtreeCollapsed = this.getTabValue(aTab, this.kSUBTREE_COLLAPSED);
+ if (subtreeCollapsed != aTab.getAttribute(this.kSUBTREE_COLLAPSED))
+ this.collapseExpandSubtree(aTab, subtreeCollapsed == 'true', true);
+ },
+
+ _restoreSubtreeCollapsedState : function TSTBrowser_restoreSubtreeCollapsedState(aTab, aCollapsed)
+ {
+ var shouldCollapse = utils.getTreePref('collapseExpandSubtree.sessionRestore');
+
+ if (aCollapsed === void(0))
+ aCollapsed = this.getTabValue(aTab, this.kSUBTREE_COLLAPSED) == 'true';
+
+ var isSubtreeCollapsed = (
+ this.windowService.restoringTree &&
+ (
+ shouldCollapse == this.RESTORED_TREE_COLLAPSED_STATE_LAST_STATE ?
+ aCollapsed :
+ shouldCollapse == this.RESTORED_TREE_COLLAPSED_STATE_COLLAPSED
+ )
+ );
+ this.setTabValue(aTab, this.kSUBTREE_COLLAPSED, isSubtreeCollapsed);
+ return isSubtreeCollapsed;
+ },
+
+ _restoreChildTabsRelation : function TSTBrowser_restoreChildTabsRelation(aTab, aChildrenList, aMayBeDuplicated, aOptions)
+ {
+ var childTabs = [];
+ if (!aChildrenList)
+ return childTabs;
+
+ aTab.removeAttribute(this.kCHILDREN);
+
+ aChildrenList = aChildrenList.split('|');
+ if (aMayBeDuplicated)
+ aChildrenList = aChildrenList.map(function(aChild) {
+ return this.redirectId(aChild);
+ }, this);
+
+ for (let i = 0, maxi = aChildrenList.length; i < maxi; i++)
+ {
+ let childTab = aChildrenList[i];
+ if (childTab && (childTab = this.getTabById(childTab))) {
+ let options = aOptions;
+ if (options && typeof options == 'function')
+ options = options(childTab);
+ this.attachTabTo(childTab, aTab, options);
+ childTabs.push(childTab);
+ }
+ }
+ aChildrenList = aChildrenList.join('|');
+ if (aTab.getAttribute(this.kCHILDREN) == aChildrenList)
+ aTab.removeAttribute(this.kCHILDREN_RESTORING);
+ else
+ aTab.setAttribute(this.kCHILDREN_RESTORING, aChildrenList);
+
+ return childTabs;
+ },
+
+ _restoreTabPositionAndIndent : function TSTBrowser_restoreTabPositionAndIndent(aTab, aChildTabs, aMayBeDuplicated)
+ {
+ var restoringMultipleTabs = this.windowService.restoringTree;
+ var position = this._prepareInsertionPosition(aTab, aMayBeDuplicated);
+ var parent = position.parent;
+ if (DEBUG)
+ dump('handleRestoredTab: found parent = ' + parent+'\n');
+ if (parent) {
+ aTab.removeAttribute(this.kPARENT);
+ parent = this.getTabById(parent);
+ if (parent) {
+ this.attachTabTo(aTab, parent, {
+ dontExpand : restoringMultipleTabs,
+ insertBefore : position.next,
+ dontUpdateIndent : true,
+ dontAnimate : restoringMultipleTabs
+ });
+ this.updateTabsIndent([aTab], undefined, restoringMultipleTabs);
+ this.checkTabsIndentOverflow();
+
+ if (parent.getAttribute(this.kCHILDREN_RESTORING))
+ this.correctChildTabsOrderWithDelay(parent);
+ }
+ else {
+ this.deleteTabValue(aTab, this.kPARENT);
+ }
+ }
+ else {
+ if (aChildTabs.length) {
+ this.updateTabsIndent(aChildTabs, undefined, restoringMultipleTabs);
+ this.checkTabsIndentOverflow();
+ }
+ this._restoreTabPosition(aTab, position.next);
+ }
+ },
+
+ _prepareInsertionPosition : function TSTBrowser_prepareInsertionPosition(aTab, aMayBeDuplicated)
+ {
+ var next = this.getTabValue(aTab, this.kINSERT_BEFORE);
+ if (next && aMayBeDuplicated)
+ next = this.redirectId(next);
+ next = this.getTabById(next);
+
+ if (!next) {
+ let prev = this.getTabValue(aTab, this.kINSERT_AFTER);
+ if (prev && aMayBeDuplicated)
+ prev = this.redirectId(prev);
+ prev = this.getTabById(prev);
+ next = this.getNextSiblingTab(prev);
+ }
+
+ var ancestors = (this.getTabValue(aTab, this.kANCESTOR) || this.getTabValue(aTab, this.kPARENT)).split('|');
+ if (DEBUG)
+ dump('handleRestoredTab: ancestors = ' + ancestors+'\n');
+ var parent = null;
+ for (let i in ancestors)
+ {
+ if (aMayBeDuplicated)
+ ancestors[i] = this.redirectId(ancestors[i]);
+ parent = this.getTabById(ancestors[i]);
+ if (parent) {
+ parent = ancestors[i];
+ break;
+ }
+ }
+ this.deleteTabValue(aTab, this.kANCESTOR);
+
+ /**
+ * If the tab is a duplicated and the tab has already been
+ * attached, then reuse current status based on attributes.
+ * (Note, if the tab is not a duplicated tab, all attributes
+ * have been cleared.)
+ */
+ if (!parent) {
+ parent = aTab.getAttribute(this.kPARENT);
+ if (DEBUG)
+ dump('handleRestoredTab: parent = ' + parent+'\n');
+ if (parent && !next)
+ next = this.getNextSiblingTab(aTab);
+ }
+
+ return {
+ parent : parent,
+ next : next
+ };
+ },
+
+ _restoreTabPosition : function TSTBrowser_restoreTabPosition(aTab, aNextTab)
+ {
+ if (!aNextTab)
+ aNextTab = this.getNextTab(aTab);
+ var parentOfNext = this.getParentTab(aNextTab);
+ var newPos = -1;
+ if (parentOfNext) {
+ let descendants = this.getDescendantTabs(parentOfNext);
+ if (descendants.length)
+ newPos = descendants[descendants.length-1]._tPos;
+ }
+ else if (aNextTab) {
+ newPos = aNextTab._tPos;
+ if (newPos > aTab._tPos)
+ newPos--;
+ }
+ if (newPos > -1)
+ this.mTabBrowser.moveTabTo(aTab, newPos);
+ },
+
+ correctChildTabsOrderWithDelay : function TSTBrowser_correctChildTabsOrderWithDelay(aTab)
+ {
+ if (aTab.correctChildTabsOrderWithDelayTimer)
+ this.window.clearTimeout(aTab.correctChildTabsOrderWithDelayTimer);
+
+ aTab.correctChildTabsOrderWithDelayTimer = this.window.setTimeout(function(aSelf) {
+ aSelf.correctChildTabsOrder(aTab);
+ }, 10, this);
+ },
+
+ correctChildTabsOrder : function TSTBrowser_correctChildTabsOrder(aTab)
+ {
+ if (!aTab.parentNode) // do nothing for closed tab!
+ return;
+
+ var restoringChildren = aTab.getAttribute(this.kCHILDREN_RESTORING);
+ if (!restoringChildren) return;
+
+ var children = aTab.getAttribute(this.kCHILDREN);
+ if (restoringChildren != children) {
+ var restoringChildrenIDs = restoringChildren.split('|').reverse();
+ for (let i = 0, maxi = restoringChildrenIDs.length; i < maxi; i++)
+ {
+ let child = this.getTabById(restoringChildrenIDs[i]);
+ if (!child)
+ continue;
+
+ let nextTab = i > 0 ?
+ this.getTabById(restoringChildrenIDs[i-1]) :
+ this.getNextSiblingTab(aTab) ;
+ if (nextTab == this.getNextSiblingTab(child))
+ continue;
+
+ let newPos = -1;
+ if (nextTab) {
+ newPos = nextTab._tPos;
+ if (newPos > child._tPos)
+ newPos--;
+ }
+ if (newPos > -1)
+ this.moveTabSubtreeTo(child, newPos);
+ }
+ children = aTab.getAttribute(this.kCHILDREN);
+ }
+
+ if (restoringChildren == children)
+ aTab.removeAttribute(this.kCHILDREN_RESTORING);
+
+ aTab.correctChildTabsOrderWithDelayTimer = null;
+ },
+
+ redirectId : function TSTBrowser_redirectId(aId)
+ {
+ if (!(aId in this._redirectionTable))
+ this._redirectionTable[aId] = this.makeNewId();
+ return this._redirectionTable[aId];
+ },
+ _redirectionTable : {},
+
+ clearRedirectionTableWithDelay : function TSTBrowser_clearRedirectionTableWithDelay()
+ {
+ if (this._clearRedirectionTableTimer) {
+ this.window.clearTimeout(this._clearRedirectionTableTimer);
+ this._clearRedirectionTableTimer = null;
+ }
+ this._clearRedirectionTableTimer = this.window.setTimeout(function(aSelf) {
+ aSelf._redirectionTable = {};
+ }, 1000, this);
+ },
+ _clearRedirectionTableTimer : null,
+
+ clearRedirectbTabRelationsWithDelay : function TSTBrowser_clearRedirectbTabRelationsWithDelay(aTab)
+ {
+ if (aTab._clearRedirectbTabRelationsTimer) {
+ this.window.clearTimeout(aTab._clearRedirectbTabRelationsTimer);
+ aTab._clearRedirectbTabRelationsTimer = null;
+ }
+ aTab._clearRedirectbTabRelationsTimer = this.window.setTimeout(function(aSelf) {
+ aSelf.clearRedirectbTabRelations(aTab);
+ delete aTab._clearRedirectbTabRelationsTimer;
+ }, 1500, this);
+ },
+ clearRedirectbTabRelations : function TSTBrowser_clearRedirectbTabRelations(aTab)
+ {
+ if (!aTab || !aTab.parentNode)
+ return;
+
+ var redirectingIds = Object.keys(this._redirectionTable).map(function(aId) {
+ return this._redirectionTable[aId];
+ }, this);
+ var existingIds = this.getAllTabs(this.mTabBrowser).map(function(aTab) {
+ return this.getTabValue(aTab, this.kID);
+ }, this);
+ var validIds = redirectingIds.concat(existingIds);
+ validIds = validIds.filter(function(aId) {
+ return !!aId;
+ });
+
+ var ancestors = this.getTabValue(aTab, this.kANCESTORS);
+ if (ancestors) {
+ ancestors = ancestors.split('|');
+ let actualAncestors = this.getAncestorTabs(aTab).map(function(aTab) {
+ return aTab.getAttribute(this.kID);
+ }, this);
+ ancestors = ancestors.filter(function(aAncestor) {
+ if (actualAncestors.indexOf(aAncestor) < 0)
+ return false;
+ else
+ return validIds.indexOf(aAncestor) > -1;
+ }, this);
+ if (ancestors.length)
+ this.setTabValue(aTab, this.kANCESTORS, ancestors.join('|'));
+ else
+ this.deleteTabValue(aTab, this.kANCESTORS);
+ }
+
+ var children = this.getTabValue(aTab, this.kCHILDREN);
+ if (children) {
+ children = children.split('|');
+ children = children.filter(function(aChild) {
+ if (this.getParentTab(this.getTabById(aChild)) != aTab)
+ return false;
+ else
+ return validIds.indexOf(aChild) > -1;
+ }, this);
+ if (children.length)
+ this.setTabValue(aTab, this.kCHILDREN, children.join('|'));
+ else
+ this.deleteTabValue(aTab, this.kCHILDREN);
+ }
+
+ var restoringChildren = aTab.getAttribute(this.kCHILDREN_RESTORING);
+ if (restoringChildren) {
+ restoringChildren = restoringChildren.split('|');
+ restoringChildren = restoringChildren.filter(function(aChild) {
+ return validIds.indexOf(aChild) > -1;
+ }, this);
+ if (restoringChildren.length)
+ aTab.setAttribute(this.kCHILDREN_RESTORING, restoringChildren.join('|'));
+ else
+ aTab.removeAttribute(this.kCHILDREN_RESTORING);
+ }
+ },
+
+ restoreClosedSet : function TSTBrowser_restoreClosedSet(aId, aRestoredTab)
+ {
+ var behavior = this.undoCloseTabSetBehavior;
+ if (
+ aRestoredTab.__treestyletab__restoredByUndoCloseTab ||
+ !this.browser.__treestyletab__readyToUndoCloseTab ||
+ this.useTMPSessionAPI ||
+ this._restoringClosedSet ||
+ !(behavior & this.kUNDO_CLOSE_SET || behavior & this.kUNDO_ASK)
+ )
+ return;
+
+ var indexes = [];
+ var items = utils.evalInSandbox('('+this.SessionStore.getClosedTabData(this.window)+')');
+ for (let i = 0, maxi = items.length; i < maxi; i++)
+ {
+ let item = items[i];
+ if (item.state.extData &&
+ item.state.extData[this.kCLOSED_SET_ID] &&
+ item.state.extData[this.kCLOSED_SET_ID] == aId)
+ indexes.push(i);
+ }
+
+ var count = parseInt(aId.split('::')[1]);
+
+ if (
+ !indexes.length ||
+ (
+ indexes.length+1 < count &&
+ behavior & this.kUNDO_CLOSE_FULL_SET
+ )
+ )
+ return;
+
+ if (behavior & this.kUNDO_ASK) {
+ let self = this;
+ aRestoredTab.addEventListener('SSTabRestoring', function onSSTabRestoring(aEvent) {
+ aRestoredTab.removeEventListener(aEvent.type, onSSTabRestoring, false);
+ self.askUndoCloseTabSetBehavior(aRestoredTab, indexes.length)
+ .next(function(aBehavior) {
+ if (aBehavior & self.kUNDO_CLOSE_SET)
+ self.doRestoreClosedSet(aRestoredTab, indexes);
+ });
+ }, false);
+ }
+ else if (behavior & this.kUNDO_CLOSE_SET) {
+ this.doRestoreClosedSet(aRestoredTab, indexes);
+ }
+ },
+
+ doRestoreClosedSet : function TSTBrowser_doRestoreClosedSet(aRestoredTab, aIndexes)
+ {
+ if (!this.window.PlacesUIUtils._confirmOpenInTabs(aIndexes.length))
+ return;
+
+ this._restoringClosedSet = true;
+ this.stopRendering();
+
+ this.windowService.restoringTree = true;
+
+ var offset = 0;
+ for (let i = 0, maxi = aIndexes.length; i < maxi; i++)
+ {
+ this.window.undoCloseTab(aIndexes[i] - (offset++));
+ }
+
+ this.window.setTimeout(function(aSelf, aNextFocused) {
+ aSelf.windowService.restoringTree = false;
+ aSelf.mTabBrowser.selectedTab = aNextFocused;
+ }, 0, this, aRestoredTab || aSelf.mTabBrowser.selectedTab);
+
+ this.startRendering();
+ this._restoringClosedSet = false;
+ },
+ _restoringClosedSet : false,
+
+ onTabRestored : function TSTBrowser_onTabRestored(aEvent)
+ {
+ delete aEvent.originalTarget.__treestyletab__restoredByUndoCloseTab;
+ },
+
+ onTabPinned : function TSTBrowser_onTabPinned(aTab)
+ {
+ var parentTab = this.getParentTab(aTab);
+
+ this.collapseExpandSubtree(aTab, false);
+
+ /**
+ * Children of the newly pinned tab are possibly
+ * moved to the top of the tab bar, by TabMove event
+ * from the newly pinned tab. So, we have to
+ * reposition unexpectedly moved children.
+ */
+ if (!parentTab) {
+ /**
+ * Universal but dangerous logic. "__treestyletab__previousPosition"
+ * can be broken by multiple movings.
+ */
+ let b = this.browser;
+ this.internallyTabMovingCount++;
+ let children = this.getDescendantTabs(aTab).reverse();
+ for (let i = 0, maxi = children.length; i < maxi; i++)
+ {
+ let childTab = children[i];
+ if (childTab.__treestyletab__previousPosition > childTab._tPos)
+ b.moveTabTo(childTab, childTab.__treestyletab__previousPosition);
+ }
+ this.internallyTabMovingCount--;
+ }
+ else {
+ /**
+ * Safer logic. This cannot be available for "root" tabs because
+ * their children (already moved) have no way to know the anchor
+ * position (the next sibling of the pinned tab itself).
+ */
+ let b = this.browser;
+ this.internallyTabMovingCount++;
+ let children = this.getChildTabs(aTab).reverse();
+ for (let i = 0, maxi = children.length; i < maxi; i++)
+ {
+ let childTab = children[i];
+ if (childTab._tPos < parentTab._tPos)
+ b.moveTabTo(childTab, parentTab._tPos);
+ }
+ this.internallyTabMovingCount--;
+ }
+
+ this.detachAllChildren(aTab, {
+ behavior : this.getCloseParentBehaviorForTab(
+ aTab,
+ this.kCLOSE_PARENT_BEHAVIOR_PROMOTE_FIRST_CHILD
+ )
+ });
+ this.detachTab(aTab);
+
+ this.collapseExpandTab(aTab, false);
+ if (this.isVertical)
+ this.positionPinnedTabsWithDelay();
+ },
+
+ onTabUnpinned : function TSTBrowser_onTabUnpinned(aTab)
+ {
+ var style = aTab.style;
+ style.marginLeft = style.marginRight = style.marginTop = '';
+
+ this.updateInvertedTabContentsOrder(aTab);
+ if (this.isVertical)
+ this.positionPinnedTabsWithDelay();
+ },
+
+ onTabSelect : function TSTBrowser_onTabSelect(aEvent)
+ {
+ var b = this.mTabBrowser;
+ var tab = b.selectedTab
+
+ this.cancelDelayedExpandOnTabSelect();
+
+ if (
+ /**
+ * .previewTab() focuses to the tab internally,
+ * so we should ignore this event if it is fired from previewTab().
+ */
+ b._previewMode ||
+ /**
+ * Ignore selected tabs which is being closed. For example,
+ * when a collapsed tree is closed, Firefox unexpectedly gives
+ * focus to a collapsed child in the tree.
+ */
+ (b._removingTabs && b._removingTabs.indexOf(tab) > -1)
+ )
+ return;
+
+ var shouldCollapseExpandNow = utils.getTreePref('autoCollapseExpandSubtreeOnSelect');
+ var newActiveTabOptions = {
+ canCollapseTree : shouldCollapseExpandNow,
+ canExpandTree : shouldCollapseExpandNow
+ };
+ if (this.isCollapsed(tab)) {
+ if (utils.getTreePref('autoExpandSubtreeOnCollapsedChildFocused')) {
+ this.getAncestorTabs(tab).forEach(function(aAncestor) {
+ this.collapseExpandSubtree(aAncestor, false);
+ }, this);
+ this.handleNewActiveTab(tab, newActiveTabOptions);
+ }
+ else {
+ b.selectedTab = this.getRootTab(tab);
+ }
+ }
+ else if (
+ (
+ /**
+ * Focus movings by arrow keys should not be handled on TabSelect,
+ * because they are already handled by handleAdvanceSelectedTab().
+ */
+ this.windowService.arrowKeyEventOnTab &&
+ this.windowService.arrowKeyEventOnTab.advanceFocus
+ ) ||
+ (
+ /**
+ * Focus movings by closing of the old current tab should be handled
+ * only when it is activated by user preference expressly.
+ */
+ this._focusChangedByCurrentTabRemove &&
+ !utils.getTreePref('autoCollapseExpandSubtreeOnSelect.onCurrentTabRemove')
+ )
+ ) {
+ // do nothing!
+ }
+ else if (this.hasChildTabs(tab) && this.isSubtreeCollapsed(tab)) {
+ if (
+ this._focusChangedByShortcut &&
+ this.windowService.accelKeyPressed
+ ) {
+ if (utils.getTreePref('autoExpandSubtreeOnSelect.whileFocusMovingByShortcut')) {
+ newActiveTabOptions.canExpandTree = true;
+ newActiveTabOptions.canCollapseTree = (
+ newActiveTabOptions.canCollapseTree &&
+ utils.getTreePref('autoExpandSubtreeOnSelect.whileFocusMovingByShortcut.collapseOthers')
+ );
+ let delay = utils.getTreePref('autoExpandSubtreeOnSelect.whileFocusMovingByShortcut.delay');
+ if (delay > 0) {
+ this._autoExpandOnTabSelectTimer = this.window.setTimeout(function(aSelf) {
+ if (tab && tab.parentNode)
+ aSelf.handleNewActiveTab(tab, newActiveTabOptions);
+ }, delay, this);
+ }
+ else {
+ this.handleNewActiveTab(tab, newActiveTabOptions);
+ }
+ }
+ else if (newActiveTabOptions.canExpandTree) {
+ this.windowService.expandTreeAfterKeyReleased(tab);
+ }
+ }
+ else {
+ this.handleNewActiveTab(tab, newActiveTabOptions);
+ }
+ }
+
+ this._focusChangedByCurrentTabRemove = false;
+ this._focusChangedByShortcut = false;
+
+ this.updateInvertedTabContentsOrder();
+
+ if (!this.isTabInViewport(tab)) {
+ this.scrollToTab(tab);
+ aEvent.stopPropagation();
+ }
+ },
+ cancelDelayedExpandOnTabSelect : function TSTBrowser_cancelDelayedExpandOnTabSelect() {
+ if (this._autoExpandOnTabSelectTimer) {
+ this.window.clearTimeout(this._autoExpandOnTabSelectTimer);
+ this._autoExpandOnTabSelectTimer = null;
+ }
+ },
+ handleNewActiveTab : function TSTBrowser_handleNewActiveTab(aTab, aOptions)
+ {
+ if (this.doingCollapseExpand || !aTab || !aTab.parentNode)
+ return;
+
+ aOptions = aOptions || {};
+
+ if (this._handleNewActiveTabTimer)
+ this.window.clearTimeout(this._handleNewActiveTabTimer);
+
+ /**
+ * First, we wait until all event listeners for the TabSelect
+ * event were processed.
+ */
+ this._handleNewActiveTabTimer = this.window.setTimeout(function(aSelf) {
+ aSelf.window.clearTimeout(aSelf._handleNewActiveTabTimer);
+ aSelf._handleNewActiveTabTimer = null;
+
+ if (aOptions.canExpandTree) {
+ if (aOptions.canCollapseTree &&
+ utils.getTreePref('autoExpand.intelligently'))
+ aSelf.collapseExpandTreesIntelligentlyFor(aTab);
+ else
+ aSelf.collapseExpandSubtree(aTab, false);
+ }
+ }, 0, this);
+ },
+ _handleNewActiveTabTimer : null,
+
+ handleAdvanceSelectedTab : function TSTBrowser_handleAdvanceSelectedTab(aDir, aWrap)
+ {
+ this._focusChangedByShortcut = this.windowService.accelKeyPressed;
+
+ if (!this.canCollapseSubtree(this.mTabBrowser.selectedTab) ||
+ utils.getTreePref('focusMode') != this.kFOCUS_VISIBLE)
+ return false;
+
+ if (this.processArrowKeyOnFocusAdvanced())
+ return true;
+
+ return this.advanceSelectedTab(aDir, aWrap);
+ },
+
+ processArrowKeyOnFocusAdvanced : function TSTBrowser_processArrowKeyOnFocusAdvanced()
+ {
+ var event = this.windowService.arrowKeyEventOnTab;
+ if (!event)
+ return false;
+
+ if (
+ event.altKey ||
+ event.ctrlKey ||
+ event.metaKey ||
+ event.shiftKey ||
+ (this.isVertical ? (event.up || event.down) : (event.left || event.right))
+ ) {
+ event.advanceFocus = true;
+ return false;
+ }
+
+ var collapse, expand;
+ switch (this.position)
+ {
+ case 'top':
+ collapse = event.up;
+ expand = event.down;
+ break;
+
+ case 'bottom':
+ collapse = event.down;
+ expand = event.up;
+ break;
+
+ case 'left':
+ collapse = event.left;
+ expand = event.right;
+ break;
+
+ case 'right':
+ if (utils.getTreePref('tabbar.invertTab')) {
+ collapse = event.right;
+ expand = event.left;
+ }
+ else {
+ collapse = event.left;
+ expand = event.right;
+ }
+ break;
+ }
+
+ var tab = this.mTabBrowser.selectedTab;
+
+ var collapsed = this.isSubtreeCollapsed(tab);
+ if (this.hasChildTabs(tab) && (collapsed ? expand : collapse )) {
+ event.collapse = collapse;
+ event.expand = expand;
+ this.collapseExpandSubtree(tab, !collapsed);
+ return true;
+ }
+
+ var nextSelected;
+ if (expand)
+ nextSelected = this.getFirstChildTab(tab);
+ else if (collapse)
+ nextSelected = this.getParentTab(tab);
+
+ if (nextSelected) {
+ event.advanceFocus = true;
+ this.mTabBrowser.selectedTab = nextSelected;
+ return true;
+ }
+
+ return true;
+ },
+
+ advanceSelectedTab : function TSTBrowser_advanceSelectedTab(aDir, aWrap)
+ {
+ var tab = this.mTabBrowser.selectedTab;
+ var tabbar = this.mTabBrowser.mTabContainer;
+
+ var nextTab = (aDir < 0) ? this.getPreviousVisibleTab(tab) : this.getNextVisibleTab(tab) ;
+ if (!nextTab && aWrap) {
+ let tabs = tabbar.querySelectorAll('tab:not(['+this.kCOLLAPSED+'="true"])');
+ nextTab = tabs[aDir < 0 ? tabs.length-1 : 0 ];
+ }
+ if (nextTab && nextTab != tab)
+ tabbar._selectNewTab(nextTab, aDir, aWrap);
+
+ return true;
+ },
+
+ onTabClick : function TSTBrowser_onTabClick(aEvent, aTab)
+ {
+ aTab = aTab || this.getTabFromEvent(aEvent);
+
+ if (aEvent.button == 1) {
+ if (!this.warnAboutClosingTabSubtreeOf(aTab)) {
+ aEvent.preventDefault();
+ aEvent.stopPropagation();
+ }
+ return;
+ }
+
+ if (aEvent.button != 0)
+ return;
+
+ if (this.isEventFiredOnTwisty(aEvent)) {
+ if (this.hasChildTabs(aTab) && this.canCollapseSubtree(aTab)) {
+ this.manualCollapseExpandSubtree(aTab, aTab.getAttribute(this.kSUBTREE_COLLAPSED) != 'true');
+ aEvent.preventDefault();
+ aEvent.stopPropagation();
+ }
+ return;
+ }
+
+ if (this.isEventFiredOnClosebox(aEvent)) {
+ if (!this.warnAboutClosingTabSubtreeOf(aTab)) {
+ aEvent.preventDefault();
+ aEvent.stopPropagation();
+ }
+ return;
+ }
+ },
+
+ onClick : function TSTBrowser_onClick(aEvent)
+ {
+ if (
+ aEvent.target.ownerDocument != this.document ||
+ aEvent.button != 0 ||
+ this.isAccelKeyPressed(aEvent)
+ )
+ return;
+
+ var tab = this.getTabFromEvent(aEvent);
+ if (tab) {
+ this.onTabClick(aEvent, tab);
+ }
+ else {
+ // click on indented space on the tab bar
+ tab = this.getTabFromTabbarEvent(aEvent);
+ if (tab)
+ this.mTabBrowser.selectedTab = tab;
+ }
+ },
+
+ onDblClick : function TSTBrowser_onDblClick(aEvent)
+ {
+ let tab = this.getTabFromEvent(aEvent);
+ if (tab &&
+ this.hasChildTabs(tab) &&
+ utils.getTreePref('collapseExpandSubtree.dblclick')) {
+ this.manualCollapseExpandSubtree(tab, tab.getAttribute(this.kSUBTREE_COLLAPSED) != 'true');
+ aEvent.preventDefault();
+ aEvent.stopPropagation();
+ }
+ },
+
+ onMozMouseHittest : function TSTBrowser_onMozMouseHittest(aEvent)
+ {
+ // block default behaviors of the tab bar (dragging => window move, etc.)
+ if (
+ !this.getTabFromEvent(aEvent) &&
+ !this.isEventFiredOnClickable(aEvent) &&
+ (
+ this.position != 'top' ||
+ aEvent.shiftKey ||
+ this.tabbarDNDObserver.canDragTabbar(aEvent)
+ )
+ )
+ aEvent.stopPropagation();
+ },
+
+ onMouseDown : function TSTBrowser_onMouseDown(aEvent)
+ {
+ if (this.isEventFiredOnScrollbar(aEvent))
+ this.cancelPerformingAutoScroll();
+
+ if (
+ aEvent.button == 0 &&
+ this.isEventFiredOnTwisty(aEvent)
+ ) {
+ // prevent to select the tab for clicking on twisty
+ aEvent.stopPropagation();
+ // prevent to focus to the tab element itself
+ aEvent.preventDefault();
+ }
+ else {
+ this.onMozMouseHittest(aEvent);
+ }
+ },
+
+ onDOMMouseScroll : function TSTBrowser_onDOMMouseScroll(aEvent)
+ {
+ this.cancelPerformingAutoScroll();
+ },
+
+ onScroll : function TSTBrowser_onScroll(aEvent)
+ {
+ // restore scroll position when a tab is closed.
+ this.restoreLastScrollPosition();
+ },
+
+ onTabbarOverflow : function TSTBrowser_onTabbarOverflow(aEvent)
+ {
+ var tabs = this.mTabBrowser.mTabContainer;
+ var horizontal = tabs.orient == 'horizontal';
+ if (horizontal)
+ return;
+ aEvent.stopPropagation();
+ this.positionPinnedTabsWithDelay();
+ if (aEvent.detail == 1) {
+ /**
+ * By horizontal overflow/underflow, Firefox can wrongly
+ * removes "overflow" attribute for vertical tab bar.
+ * We have to override the result.
+ */
+ this.updateTabbarOverflow();
+ }
+ else {
+ if (aEvent.type == 'overflow') {
+ tabs.setAttribute('overflow', 'true');
+ this.scrollBoxObject.ensureElementIsVisible(tabs.selectedItem);
+ }
+ else {
+ tabs.removeAttribute('overflow');
+ }
+ }
+ },
+
+ onResize : function TSTBrowser_onResize(aEvent)
+ {
+ if (
+ !aEvent.originalTarget ||
+ !(aEvent.originalTarget instanceof Ci.nsIDOMWindow)
+ )
+ return;
+
+ var resizedTopFrame = aEvent.originalTarget.top;
+ var isContentResize = resizedTopFrame == this.mTabBrowser.contentWindow;
+ var isChromeResize = resizedTopFrame == this.window;
+
+ if (isChromeResize && aEvent.originalTarget != resizedTopFrame) {
+ // ignore resizing of sub frames in "position:fixed" box
+ let target = aEvent.target;
+ try {
+ let node = target.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIWebNavigation)
+ .QueryInterface(Ci.nsIDocShell)
+ .chromeEventHandler;
+ let root = node.ownerDocument.documentElement;
+ while (node && node != root) {
+ if (node.boxObject && !node.boxObject.parentBox) {
+ isChromeResize = false;
+ break;
+ }
+ node = node.parentNode;
+ }
+ }
+ catch(e) {
+ }
+ }
+
+ // Ignore events when a background tab raises to the foreground.
+ if (isContentResize && this._lastTabbarPlaceholderSize) {
+ let newSize = this.getTabbarPlaceholderSize();
+ isContentResize =
+ newSize.width != this._lastTabbarPlaceholderSize.width ||
+ newSize.height != this._lastTabbarPlaceholderSize.height;
+ }
+
+ if (isContentResize || isChromeResize) {
+ this.updateFloatingTabbar(this.kTABBAR_UPDATE_BY_WINDOW_RESIZE);
+ this.updateInvertedTabContentsOrder(true);
+ this.mTabBrowser.mTabContainer.adjustTabstrip();
+ }
+ },
+
+ onPopupShowing : function TSTBrowser_onPopupShowing(aEvent)
+ {
+ if (aEvent.target == aEvent.currentTarget)
+ this.initTabContextMenu(aEvent);
+ },
+
+ initTabContextMenu : function TSTBrowser_initTabContextMenu(aEvent)
+ {
+ var b = this.mTabBrowser;
+ var sep, items = {};
+
+ var ids = [
+ this.kMENUITEM_RELOADSUBTREE,
+ this.kMENUITEM_RELOADCHILDREN,
+ this.kMENUITEM_REMOVESUBTREE,
+ this.kMENUITEM_REMOVECHILDREN,
+ this.kMENUITEM_REMOVEALLTABSBUT,
+ this.kMENUITEM_COLLAPSE,
+ this.kMENUITEM_EXPAND,
+ this.kMENUITEM_AUTOHIDE,
+ this.kMENUITEM_FIXED,
+ this.kMENUITEM_BOOKMARKSUBTREE
+ ];
+ for (let i = 0, maxi = ids.length; i < maxi; i++)
+ {
+ let id = ids[i];
+ let item = aEvent.currentTarget.querySelector('*[id^="'+id+'"]');
+ if (!item)
+ continue;
+ items[id] = item;
+ if (utils.getTreePref('show.'+id))
+ item.removeAttribute('hidden');
+ else
+ item.setAttribute('hidden', true);
+ switch (id)
+ {
+ case this.kMENUITEM_RELOADSUBTREE:
+ case this.kMENUITEM_RELOADCHILDREN:
+ case this.kMENUITEM_REMOVESUBTREE:
+ case this.kMENUITEM_REMOVECHILDREN:
+ case this.kMENUITEM_REMOVEALLTABSBUT:
+ case this.kMENUITEM_COLLAPSE:
+ case this.kMENUITEM_EXPAND:
+ case this.kMENUITEM_BOOKMARKSUBTREE:
+ this.showHideSubtreeMenuItem(item, [b.mContextTab]);
+ continue;
+ default:
+ continue;
+ }
+ }
+
+ // collapse/expand all
+ sep = aEvent.currentTarget.querySelector('menuseparator[id^="'+this.kMENUITEM_COLLAPSEEXPAND_SEPARATOR+'"]');
+ let collapseItem = items[this.kMENUITEM_COLLAPSE];
+ let expandItem = items[this.kMENUITEM_EXPAND];
+ if (this.canCollapseSubtree(b) &&
+ b.mTabContainer.querySelector('tab['+this.kCHILDREN+']')) {
+ if (collapseItem) {
+ if (b.mTabContainer.querySelector('tab['+this.kCHILDREN+']:not(['+this.kSUBTREE_COLLAPSED+'="true"])'))
+ collapseItem.removeAttribute('disabled');
+ else
+ collapseItem.setAttribute('disabled', true);
+ }
+
+ if (expandItem) {
+ if (b.mTabContainer.querySelector('tab['+this.kCHILDREN+']['+this.kSUBTREE_COLLAPSED+'="true"]'))
+ expandItem.removeAttribute('disabled');
+ else
+ expandItem.setAttribute('disabled', true);
+ }
+ }
+ else {
+ if (collapseItem)
+ collapseItem.setAttribute('hidden', true);
+ if (expandItem)
+ expandItem.setAttribute('hidden', true);
+ }
+ if (sep) {
+ if (
+ (!collapseItem || collapseItem.getAttribute('hidden') == 'true') &&
+ (!expandItem || expandItem.getAttribute('hidden') == 'true')
+ ) {
+ sep.setAttribute('hidden', true);
+ }
+ else {
+ sep.removeAttribute('hidden');
+ }
+ }
+
+ // close all tabs but this tree
+ let removeAllTabsBut = items[this.kMENUITEM_REMOVEALLTABSBUT];
+ if (removeAllTabsBut) {
+ let rootTabs = this.visibleRootTabs;
+ if (rootTabs.length == 1 && rootTabs[0] == b.mContextTab)
+ removeAllTabsBut.setAttribute('disabled', true);
+ else
+ removeAllTabsBut.removeAttribute('disabled');
+ }
+
+ // auto hide
+ let autohide = items[this.kMENUITEM_AUTOHIDE];
+ if (autohide)
+ this.autoHide.updateMenuItem(autohide);
+
+ // fix
+ let fixedPref;
+ let fixedLabel;
+ if (this.isVertical) {
+ fixedPref = b.getAttribute(this.kFIXED+'-vertical') == 'true';
+ fixedLabel = 'label-vertical';
+ }
+ else {
+ fixedPref = b.getAttribute(this.kFIXED+'-horizontal') == 'true';
+ fixedLabel = 'label-horizontal';
+ }
+ let fixed = items[this.kMENUITEM_FIXED];
+ if (fixed) {
+ fixed.setAttribute('label', fixed.getAttribute(fixedLabel));
+ if (fixedPref)
+ fixed.setAttribute('checked', true);
+ else
+ fixed.removeAttribute('checked');
+ }
+
+ sep = aEvent.currentTarget.querySelector('menuseparator[id^="'+this.kMENUITEM_AUTOHIDE_SEPARATOR+'"]');
+ if (sep) {
+ if (
+ (autohide && autohide.getAttribute('hidden') != 'true') ||
+ (fixed && fixed.getAttribute('hidden') != 'true')
+ ) {
+ sep.removeAttribute('hidden');
+ }
+ else {
+ sep.setAttribute('hidden', true);
+ }
+ }
+
+ let closeTabsToEnd = aEvent.currentTarget.querySelector('*[id^="'+this.kMENUITEM_CLOSE_TABS_TO_END+'"]');
+ if (closeTabsToEnd) { // https://bugzilla.mozilla.org/show_bug.cgi?id=866880
+ let label, accesskey;
+ if (this.isVertical) {
+ label = utils.treeBundle.getString('closeTabsToTheEnd_vertical_label');
+ accesskey = utils.treeBundle.getString('closeTabsToTheEnd_vertical_accesskey');
+ }
+ else {
+ label = this._closeTabsToEnd_horizontalLabel;
+ accesskey = this._closeTabsToEnd_horizontalAccesskey;
+ }
+ closeTabsToEnd.setAttribute('label', label);
+ closeTabsToEnd.setAttribute('accesskey', accesskey);
+ }
+ },
+
+ onTabsOnTopSyncCommand : function TSTBrowser_onTabsOnTopSyncCommand(aEnabled)
+ {
+ if (
+ this.windowService.tabsOnTopChangingByUI ||
+ !aEnabled ||
+ this.position != 'top' ||
+ this.fixed ||
+ this.windowService.isPopupWindow
+ )
+ return;
+ this.windowService.tabsOnTopChangingByUI = true;
+ var self = this;
+ if (this.deferredTasks['onTabsOnTopSyncCommand'])
+ this.deferredTasks['onTabsOnTopSyncCommand'].cancel();
+ (this.deferredTasks['onTabsOnTopSyncCommand'] = this.Deferred
+ .next(function() {
+ self.windowService.toggleFixed(self.mTabBrowser);
+ }))
+ .next(function() {
+ if (self.window.TabsOnTop.enabled != aEnabled)
+ self.window.TabsOnTop.enabled = aEnabled;
+ })
+ .error(this.defaultDeferredErrorHandler)
+ .next(function() {
+ self.windowService.tabsOnTopChangingByUI = false;
+ delete self.deferredTasks['onTabsOnTopSyncCommand'];
+ });
+ },
+
+ onBeforeFullScreenToggle : function TSTBrowser_onBeforeFullScreenToggle()
+ {
+ if (this.position != 'top') {
+ var isEnteringFullScreenMode = !this.window.fullScreen;
+ // entering to the DOM-fullscreen (ex. YouTube Player)
+ if (this.document.mozFullScreen && isEnteringFullScreenMode) {
+ this.setTabbrowserAttribute(this.kDOM_FULLSCREEN_ACTIVATED, true);
+ }
+ else {
+ if (this.document.documentElement.getAttribute(this.kDOM_FULLSCREEN_ACTIVATED) != 'true') {
+ if (isEnteringFullScreenMode)
+ this.autoHide.startForFullScreen();
+ else
+ this.autoHide.endForFullScreen();
+ }
+ this.removeTabbrowserAttribute(this.kDOM_FULLSCREEN_ACTIVATED);
+ }
+ }
+ },
+
+ onTreeStyleTabPrintPreviewEntered : function TSTBrowser_onTreeStyleTabPrintPreviewEntered(aEvent)
+ {
+ this.setTabbrowserAttribute(this.kPRINT_PREVIEW, true);
+ },
+
+ onTreeStyleTabPrintPreviewExited : function TSTBrowser_onTreeStyleTabPrintPreviewExited(aEvent)
+ {
+ this.removeTabbrowserAttribute(this.kPRINT_PREVIEW);
+ },
+
+/* commands */
+
+/* reset */
+
+ resetTab : function TSTBrowser_resetTab(aTab, aDetachAllChildren)
+ {
+ if (!aTab.parentNode) // do nothing for closed tab!
+ return;
+
+ if (aDetachAllChildren)
+ this.detachAllChildren(aTab, {
+ dontUpdateIndent : true,
+ dontAnimate : true
+ });
+
+ this.detachTab(aTab, {
+ dontUpdateIndent : true,
+ dontAnimate : true
+ });
+
+ this.resetTabState(aTab);
+ this.updateTabsIndent([aTab], undefined, true);
+ },
+
+ resetTabState : function TSTBrowser_resetTabState(aTab)
+ {
+ if (!aTab.parentNode) // do nothing for closed tab!
+ return;
+
+ aTab.removeAttribute(this.kID);
+ aTab.removeAttribute(this.kID_RESTORING);
+ aTab.removeAttribute(this.kPARENT);
+ aTab.removeAttribute(this.kCHILDREN);
+ aTab.removeAttribute(this.kCHILDREN_RESTORING);
+ aTab.removeAttribute(this.kSUBTREE_COLLAPSED);
+ aTab.removeAttribute(this.kSUBTREE_EXPANDED_MANUALLY);
+ aTab.removeAttribute(this.kCOLLAPSED);
+ aTab.removeAttribute(this.kNEST);
+ this.updateTabCollapsed(aTab, false, true);
+ },
+
+ resetAllTabs : function TSTBrowser_resetAllTabs(aDetachAllChildren)
+ {
+ var tabs = this.getAllTabs(this.mTabBrowser);
+ for (let i = 0, maxi = tabs.length; i < maxi; i++)
+ {
+ this.resetTab(tabs[i], aDetachAllChildren);
+ }
+ },
+
+ resetTabbarSize : function TSTBrowser_resetTabbarSize()
+ {
+ if (this.isVertical) {
+ utils.setTreePref('tabbar.shrunkenWidth', utils.getTreePref('tabbar.shrunkenWidth.default'));
+ utils.setTreePref('tabbar.width', utils.getTreePref('tabbar.width.default'));
+ }
+ else {
+ utils.setTreePref('tabbar.height', utils.getTreePref('tabbar.height.default'));
+ let tabContainerBox = this.getTabContainerBox(this.mTabBrowser);
+ tabContainerBox.removeAttribute('height');
+ this._tabStripPlaceHolder.height = tabContainerBox.boxObject.height;
+ }
+ this.updateFloatingTabbar(this.kTABBAR_UPDATE_BY_RESET);
+ },
+
+ get treeViewEnabled() /* PUBLIC API */
+ {
+ return this._treeViewEnabled;
+ },
+ set treeViewEnabled(aValue)
+ {
+ var newValue = !!aValue;
+ if (newValue == this._treeViewEnabled)
+ return aValue;
+
+ this._treeViewEnabled = newValue;
+ if (this._treeViewEnabled) {
+ if (this._lastAllowSubtreeCollapseExpand)
+ this.allowSubtreeCollapseExpand = true;
+ delete this._lastAllowSubtreeCollapseExpand;
+
+ let tabs = this.getAllTabs(this.browser);
+ for (let i = 0, maxi = tabs.length; i < maxi; i++)
+ {
+ let tab = tabs[i];
+ if (tab._TSTLastSubtreeCollapsed)
+ this.collapseExpandSubtree(tab, true, true);
+ if (tab._TSTLastSubtreeExpandedManually)
+ this.setTabValue(tab, this.kSUBTREE_EXPANDED_MANUALLY, true);
+ delete tab._TSTLastSubtreeCollapsed;
+ delete tab._TSTLastSubtreeExpandedManually;
+ this.updateTabIndent(tab, 0, true);
+ }
+ this.updateTabsIndent(this.rootTabs, undefined, true);
+ }
+ else {
+ let tabs = this.getAllTabs(this.browser);
+ for (let i = 0, maxi = tabs.length; i < maxi; i++)
+ {
+ let tab = tabs[i];
+ this.updateTabIndent(tab, 0, true);
+ tab._TSTLastSubtreeCollapsed = this.isSubtreeCollapsed(tab);
+ tab._TSTLastSubtreeExpandedManually = this.getTabValue(tab, this.kSUBTREE_EXPANDED_MANUALLY) == 'true';
+ this.collapseExpandSubtree(tab, false, true);
+ }
+
+ this._lastAllowSubtreeCollapseExpand = this.allowSubtreeCollapseExpand;
+ this.allowSubtreeCollapseExpand = false;
+ }
+ return aValue;
+ },
+// _treeViewEnabled : true,
+
+/* attach/detach */
+
+ attachTabTo : function TSTBrowser_attachTabTo(aChild, aParent, aInfo) /* PUBLIC API */
+ {
+ if (!aChild.parentNode || (aParent && !aParent.parentNode)) // do nothing for closed tab!
+ return;
+
+ aInfo = aInfo || {};
+ var newAncestors = [];
+
+ if (aParent) {
+ newAncestors = [aParent].concat(this.getAncestorTabs(aParent));
+ if (this.maxTreeLevelPhisical && this.maxTreeLevel > -1) {
+ let level = parseInt(aParent.getAttribute(this.kNEST) || 0) + 1;
+ newAncestors.some(function(aAncestor) {
+ if (level <= this.maxTreeLevel)
+ return true;
+ level--;
+ return false;
+ }, this);
+ }
+ }
+
+ var currentParent;
+ if (
+ !aChild ||
+ !aParent ||
+ aChild == aParent ||
+ (currentParent = this.getParentTab(aChild)) == aParent ||
+ aChild.getAttribute('pinned') == 'true' ||
+ aParent.getAttribute('pinned') == 'true'
+ ) {
+ this.fireAttachedEvent(aChild, aParent);
+ return;
+ }
+
+ // avoid recursive tree
+ var ancestors = [aParent].concat(this.getAncestorTabs(aChild));
+ if (ancestors.indexOf(aChild) > -1)
+ return;
+
+ currentParent = ancestors[ancestors.length-1];
+ var shouldInheritIndent = (
+ !currentParent ||
+ (currentParent.getAttribute(this.kNEST) == aParent.getAttribute(this.kNEST))
+ );
+
+ this.ensureTabInitialized(aChild);
+ this.ensureTabInitialized(aParent);
+
+ if (!aInfo)
+ aInfo = {};
+
+ var id = aChild.getAttribute(this.kID);
+
+ this.detachTab(aChild, {
+ dontUpdateIndent : true
+ });
+
+ var children = aParent.getAttribute(this.kCHILDREN)
+ .split('|').filter(function(aId) {
+ return this.getTabById(aId);
+ }, this);
+
+ var newIndex;
+
+ var oldIndex = children.indexOf(id);
+ if (oldIndex > -1)
+ children.splice(oldIndex, 1);
+
+ var insertBefore = aInfo.insertBefore ||
+ (aInfo.dontMove ? this.getNextTab(aChild) : null );
+ var beforeTab = insertBefore ? insertBefore.getAttribute(this.kID) : null ;
+ var beforeIndex;
+ if (beforeTab && (beforeIndex = children.indexOf(beforeTab)) > -1) {
+ children.splice(beforeIndex, 0, id);
+ newIndex = insertBefore._tPos;
+ }
+ else {
+ children.push(id);
+ if (aInfo.dontMove && children.length > 1) {
+ children = children
+ .map(this.getTabById, this)
+ .sort(this.sortTabsByOrder)
+ .map(function(aTab) {
+ return aTab.getAttribute(this.kID);
+ }, this);
+ }
+ let refTab = aParent;
+ let descendant = this.getDescendantTabs(aParent);
+ if (descendant.length) {
+ let lastDescendant = descendant[descendant.length-1];
+ /**
+ * The last descendant tab can be temporarilly moved
+ * upper than the root parent tab, in some cases.
+ * (the parent tab is pinned, etc.)
+ */
+ if (!refTab || lastDescendant._tPos > refTab._tPos)
+ refTab = lastDescendant;
+ }
+ newIndex = refTab._tPos+1;
+ }
+
+ this.setTabValue(aParent, this.kCHILDREN, children.join('|'));
+ this.setTabValue(aChild, this.kPARENT, aParent.getAttribute(this.kID));
+
+ this.updateTabsCount(aParent);
+ if (shouldInheritIndent && !aInfo.dontUpdateIndent)
+ this.inheritTabIndent(aChild, aParent);
+
+ if (!aInfo.dontMove) {
+ if (newIndex > aChild._tPos)
+ newIndex--;
+ this.moveTabSubtreeTo(aChild, newIndex);
+ }
+
+ if (aInfo.forceExpand) {
+ this.collapseExpandSubtree(aParent, false, aInfo.dontAnimate);
+ }
+ else if (!aInfo.dontExpand) {
+ if (utils.getTreePref('autoCollapseExpandSubtreeOnAttach') &&
+ this.shouldTabAutoExpanded(aParent))
+ this.collapseExpandTreesIntelligentlyFor(aParent);
+
+ if (utils.getTreePref('autoCollapseExpandSubtreeOnSelect')) {
+ newAncestors.forEach(function(aAncestor) {
+ if (this.shouldTabAutoExpanded(aAncestor))
+ this.collapseExpandSubtree(aAncestor, false, aInfo.dontAnimate);
+ }, this);
+ }
+ else if (this.shouldTabAutoExpanded(aParent)) {
+ if (utils.getTreePref('autoExpandSubtreeOnAppendChild')) {
+ newAncestors.forEach(function(aAncestor) {
+ if (this.shouldTabAutoExpanded(aAncestor))
+ this.collapseExpandSubtree(aAncestor, false, aInfo.dontAnimate);
+ }, this);
+ }
+ else
+ this.collapseExpandTab(aChild, true, aInfo.dontAnimate);
+ }
+
+ if (this.isCollapsed(aParent))
+ this.collapseExpandTab(aChild, true, aInfo.dontAnimate);
+ }
+ else if (this.shouldTabAutoExpanded(aParent) ||
+ this.isCollapsed(aParent)) {
+ this.collapseExpandTab(aChild, true, aInfo.dontAnimate);
+ }
+
+ if (!aInfo.dontUpdateIndent) {
+ this.updateTabsIndent([aChild], undefined, aInfo.dontAnimate);
+ this.checkTabsIndentOverflow();
+ }
+
+ this.promoteTooDeepLevelTabs(aChild);
+
+ this.fireAttachedEvent(aChild, aParent);
+ },
+ fireAttachedEvent : function TSTBrowser_fireAttachedEvent(aChild, aParent)
+ {
+ var data = {
+ parentTab : aParent
+ };
+
+ /* PUBLIC API */
+ this.fireCustomEvent(this.kEVENT_TYPE_ATTACHED, aChild, true, false, data);
+ // for backward compatibility
+ this.fireCustomEvent(this.kEVENT_TYPE_ATTACHED.replace(/^nsDOM/, ''), aChild, true, false, data);
+ },
+
+ shouldTabAutoExpanded : function TSTBrowser_shouldTabAutoExpanded(aTab)
+ {
+ return this.hasChildTabs(aTab) &&
+ this.isSubtreeCollapsed(aTab);
+ },
+
+ detachTab : function TSTBrowser_detachTab(aChild, aInfo) /* PUBLIC API */
+ {
+ if (!aChild || !aChild.parentNode)
+ return;
+ if (!aInfo)
+ aInfo = {};
+
+ var parentTab = this.getParentTab(aChild);
+ if (!parentTab)
+ return;
+
+ var id = aChild.getAttribute(this.kID);
+
+ this.setTabValue(
+ parentTab,
+ this.kCHILDREN,
+ parentTab.getAttribute(this.kCHILDREN)
+ .split('|')
+ .filter(function(aId) {
+ return this.getTabById(aId) && aId != id;
+ }, this).join('|')
+ );
+ this.deleteTabValue(aChild, this.kPARENT);
+
+ if (!this.hasChildTabs(parentTab))
+ this.setTabValue(parentTab, this.kSUBTREE_COLLAPSED, true);
+
+ this.updateTabsCount(parentTab);
+
+ if (!aInfo.dontUpdateIndent) {
+ this.updateTabsIndent([aChild], undefined, aInfo.dontAnimate);
+ this.checkTabsIndentOverflow();
+ }
+
+ var data = {
+ parentTab : parentTab
+ };
+
+ /* PUBLIC API */
+ this.fireCustomEvent(this.kEVENT_TYPE_DETACHED, aChild, true, false, data);
+ // for backward compatibility
+ this.fireCustomEvent(this.kEVENT_TYPE_DETACHED.replace(/^nsDOM/, ''), aChild, true, false, data);
+
+ if (this.isTemporaryGroupTab(parentTab) && !this.hasChildTabs(parentTab)) {
+ this.window.setTimeout(function(aTabBrowser) {
+ if (parentTab.parentNode)
+ aTabBrowser.removeTab(parentTab, { animate : true });
+ parentTab = null;
+ }, 0, this.getTabBrowserFromChild(parentTab));
+ }
+ },
+ partTab : function TSTBrowser_partTab(aChild, aInfo) /* PUBLIC API, for backward compatibility */
+ {
+ return this.detachTab(aChild, aInfo);
+ },
+
+ detachAllChildren : function TSTBrowser_detachAllChildren(aTab, aInfo)
+ {
+ if (!aTab.parentNode) // do nothing for closed tab!
+ return;
+
+ var children = this.getChildTabs(aTab);
+ if (!children.length)
+ return;
+
+ aInfo = aInfo || {};
+ if (!('behavior' in aInfo))
+ aInfo.behavior = this.kCLOSE_PARENT_BEHAVIOR_SIMPLY_DETACH_ALL_CHILDREN;
+ if (aInfo.behavior == this.kCLOSE_PARENT_BEHAVIOR_CLOSE_ALL_CHILDREN)
+ aInfo.behavior = this.kCLOSE_PARENT_BEHAVIOR_PROMOTE_FIRST_CHILD;
+
+ var b = this.mTabBrowser;
+ var parentTab = this.getParentTab(aTab);
+
+ if (
+ this.isGroupTab(aTab) &&
+ this.getTabs(b).filter(function(aTab) {
+ return !b._removingTabs || b._removingTabs.indexOf(aTab) < 0;
+ }).length == children.length
+ ) {
+ aInfo.behavior = this.kCLOSE_PARENT_BEHAVIOR_PROMOTE_ALL_CHILDREN;
+ aInfo.dontUpdateIndent = false;
+ }
+
+ var insertBefore = null;
+ if (aInfo.behavior == this.kCLOSE_PARENT_BEHAVIOR_DETACH_ALL_CHILDREN &&
+ !utils.getTreePref('closeParentBehavior.moveDetachedTabsToBottom')) {
+ insertBefore = this.getNextSiblingTab(this.getRootTab(aTab));
+ }
+ for (let i = 0, maxi = children.length; i < maxi; i++)
+ {
+ let tab = children[i];
+ if (aInfo.behavior == this.kCLOSE_PARENT_BEHAVIOR_DETACH_ALL_CHILDREN) {
+ this.detachTab(tab, aInfo);
+ this.moveTabSubtreeTo(tab, insertBefore ? insertBefore._tPos - 1 : this.getLastTab(b)._tPos );
+ }
+ else if (aInfo.behavior == this.kCLOSE_PARENT_BEHAVIOR_PROMOTE_FIRST_CHILD) {
+ this.detachTab(tab, aInfo);
+ if (i == 0) {
+ if (parentTab) {
+ this.attachTabTo(tab, parentTab, inherit(aInfo, {
+ dontExpand : true,
+ dontMove : true
+ }));
+ }
+ this.collapseExpandSubtree(tab, false);
+ this.deleteTabValue(tab, this.kSUBTREE_COLLAPSED);
+ }
+ else {
+ this.attachTabTo(tab, children[0], inherit(aInfo, {
+ dontExpand : true,
+ dontMove : true
+ }));
+ }
+ }
+ else if (aInfo.behavior == this.kCLOSE_PARENT_BEHAVIOR_PROMOTE_ALL_CHILDREN && parentTab) {
+ this.attachTabTo(tab, parentTab, inherit(aInfo, {
+ dontExpand : true,
+ dontMove : true
+ }));
+ }
+ else { // aInfo.behavior == this.kCLOSE_PARENT_BEHAVIOR_SIMPLY_DETACH_ALL_CHILDREN
+ this.detachTab(tab, aInfo);
+ }
+ }
+ },
+ partAllChildren : function TSTBrowser_partAllChildren(aTab, aInfo) /* for backward compatibility */
+ {
+ return this.detachAllChildren(aTab, aInfo);
+ },
+
+ detachTabs : function TSTBrowser_detachTabs(aTabs)
+ {
+ for (let i = 0, maxi = aTabs.length; i < maxi; i++)
+ {
+ let tab = aTabs[i];
+ if (aTabs.indexOf(this.getParentTab(tab)) > -1)
+ continue;
+ this.detachAllChildren(tab, {
+ behavior : this.getCloseParentBehaviorForTab(
+ tab,
+ this.kCLOSE_PARENT_BEHAVIOR_PROMOTE_FIRST_CHILD
+ )
+ });
+ }
+ },
+ partTabs : function TSTBrowser_partTabs(aTabs) /* for backward compatibility */
+ {
+ return this.detachTabs(aTabs);
+ },
+
+ getCloseParentBehaviorForTab : function TSTBrowser_getCloseParentBehaviorForTab(aTab, aDefaultBehavior)
+ {
+ var closeParentBehavior = utils.getTreePref('closeParentBehavior');
+ var closeRootBehavior = utils.getTreePref('closeRootBehavior');
+
+ var parentTab = this.getParentTab(aTab);
+ var behavior = aDefaultBehavior ?
+ aDefaultBehavior :
+ (!parentTab && closeParentBehavior == this.kCLOSE_PARENT_BEHAVIOR_PROMOTE_ALL_CHILDREN) ?
+ closeRootBehavior :
+ closeParentBehavior ;
+ if (behavior == this.kCLOSE_PARENT_BEHAVIOR_PROMOTE_FIRST_CHILD &&
+ parentTab &&
+ this.getChildTabs(parentTab).length == 1)
+ behavior = this.kCLOSE_PARENT_BEHAVIOR_PROMOTE_ALL_CHILDREN;
+
+ return behavior;
+ },
+
+ updateTabsIndent : function TSTBrowser_updateTabsIndent(aTabs, aLevel, aJustNow)
+ {
+ if (!aTabs || !aTabs.length || !this._treeViewEnabled)
+ return;
+
+ if (aLevel === void(0))
+ aLevel = this.getAncestorTabs(aTabs[0]).length;
+
+ var b = this.mTabBrowser;
+ var margin = this.indent < 0 ? this.baseIndent : this.indent ;
+ var indent = (this.maxTreeLevel < 0 ? aLevel : Math.min(aLevel, this.maxTreeLevel) ) * margin;
+
+ var multirow = this.isMultiRow();
+ if (multirow) {
+ let maxIndent = parseInt(aTabs[0].boxObject.height / 2);
+ indent = Math.min(aLevel * 3, maxIndent);
+ }
+
+ for (let i = 0, maxi = aTabs.length; i < maxi; i++)
+ {
+ let tab = aTabs[i];
+ if (!tab.parentNode)
+ continue; // ignore removed tabs
+ this.updateTabIndent(tab, indent, aJustNow);
+ tab.setAttribute(this.kNEST, aLevel);
+ this.updateCanCollapseSubtree(tab, aLevel);
+ this.updateTabsIndent(this.getChildTabs(tab), aLevel+1, aJustNow);
+ }
+ },
+ updateTabsIndentWithDelay : function TSTBrowser_updateTabsIndentWithDelay(aTabs)
+ {
+ if (this.updateTabsIndentWithDelayTimer)
+ this.window.clearTimeout(this.updateTabsIndentWithDelayTimer);
+
+ this.updateTabsIndentWithDelayTabs = this.updateTabsIndentWithDelayTabs.concat(aTabs);
+ this.updateTabsIndentWithDelayTimer = this.window.setTimeout(function(aSelf) {
+ var tabs = [];
+ for (let i = 0, maxi = aSelf.updateTabsIndentWithDelayTabs.length; i < maxi; i++)
+ {
+ let tab = aSelf.updateTabsIndentWithDelayTabs[i];
+ if (tabs.indexOf(tab) < 0 && tab.parentNode)
+ tabs.push(tab);
+ }
+ aSelf.updateTabsIndentWithDelayTabs = [];
+ aSelf.updateTabsIndent(tabs);
+ aSelf.window.clearTimeout(aSelf.updateTabsIndentWithDelayTimer);
+ aSelf.updateTabsIndentWithDelayTimer = null;
+ tabs = null;
+ }, 0, this);
+ },
+ updateTabsIndentWithDelayTimer : null,
+
+ updateTabIndent : function TSTBrowser_updateTabIndent(aTab, aIndent, aJustNow)
+ {
+ if (!aTab.parentNode) // do nothing for closed tab!
+ return;
+
+ this.stopTabIndentAnimation(aTab);
+
+ if (aTab.hasAttribute('pinned'))
+ return;
+
+ if (!this.enableSubtreeIndent)
+ aIndent = 0;
+
+ if (this.isMultiRow()) {
+ let colors = '-moz-border-'+this.indentTarget+'-colors:'+(function() {
+ var retVal = [];
+ for (var i = 1; i < aIndent; i++)
+ {
+ retVal.push('transparent');
+ }
+ retVal.push('ThreeDShadow');
+ return retVal.length == 1 ? 'none' : retVal.join(' ') ;
+ })()+' !important;';
+ let boxes = this.document.getAnonymousNodes(aTab);
+ for (let i = 0, box = boxes.length; i < maxi; i++)
+ {
+ let box = boxes[i];
+ if (box.nodeType != Node.ELEMENT_NODE)
+ continue;
+ box.setAttribute(
+ 'style',
+ box.getAttribute('style')
+ .replace(/(-moz-)?border-(top|bottom)(-[^:]*)?.*:[^;]+;?/g, '') +
+ '; border-'+this.indentTarget+': solid transparent '+aIndent+'px !important;'+colors
+ );
+ }
+ return;
+ }
+
+ if (
+ !this.animationEnabled ||
+ aJustNow ||
+ this.indentDuration < 1 ||
+ this.isCollapsed(aTab)
+ ) {
+ aTab.style.setProperty(this.indentCSSProp, aIndent+'px', 'important');
+ return;
+ }
+
+ var self = this;
+ var CSSTransitionEnabled = ('transition' in aTab.style || 'MozTransition' in aTab.style);
+ if (CSSTransitionEnabled) {
+ aTab.__treestyletab__updateTabIndentTask = function(aTime, aBeginning, aChange, aDuration) {
+ delete aTab.__treestyletab__updateTabIndentTask;
+ if (!self.isDestroying)
+ aTab.style.setProperty(self.indentCSSProp, aIndent+'px', 'important');
+ return true;
+ };
+ this.animationManager.addTask(
+ aTab.__treestyletab__updateTabIndentTask,
+ 0, 0, 1, this.window
+ );
+ return;
+ }
+
+ var startIndent = this.getPropertyPixelValue(aTab, this.indentCSSProp);
+ var delta = aIndent - startIndent;
+ var radian = 90 * Math.PI / 180;
+ aTab.__treestyletab__updateTabIndentTask = function(aTime, aBeginning, aChange, aDuration) {
+ if (self.isDestroying)
+ return true;
+ var indent, finished;
+ if (aTime >= aDuration) {
+ delete aTab.__treestyletab__updateTabIndentTask;
+ indent = aIndent;
+ finished = true;
+ }
+ else {
+ indent = startIndent + (delta * Math.sin(aTime / aDuration * radian));
+ finished = false;
+ }
+ aTab.style.setProperty(self.indentCSSProp, indent+'px', 'important');
+ if (finished) {
+ startIndent = null;
+ delta = null;
+ radian = null;
+ self = null;
+ aTab = null;
+ }
+ return finished;
+ };
+ this.animationManager.addTask(
+ aTab.__treestyletab__updateTabIndentTask,
+ 0, 0, this.indentDuration, this.window
+ );
+ },
+ stopTabIndentAnimation : function TSTBrowser_stopTabIndentAnimation(aTab)
+ {
+ if (!aTab.parentNode)
+ return; // do nothing for closed tab!
+ this.animationManager.removeTask(
+ aTab.__treestyletab__updateTabIndentTask
+ );
+ delete aTab.__treestyletab__updateTabIndentTask;
+ },
+
+ inheritTabIndent : function TSTBrowser_inheritTabIndent(aNewTab, aExistingTab)
+ {
+ var indent = this.getPropertyPixelValue(aExistingTab, this.indentCSSProp);
+ if (indent)
+ aNewTab.style.setProperty(this.indentCSSProp, indent+'px', 'important');
+ else
+ aNewTab.style.removeProperty(this.indentCSSProp);
+ },
+
+ updateAllTabsIndent : function TSTBrowser_updateAllTabsIndent(aJustNow)
+ {
+ this.updateTabsIndent(this.rootTabs, 0, aJustNow);
+// this.checkTabsIndentOverflow();
+ },
+
+ checkTabsIndentOverflow : function TSTBrowser_checkTabsIndentOverflow(aDelay)
+ {
+ this.cancelCheckTabsIndentOverflow();
+ this.checkTabsIndentOverflowTimer = this.window.setTimeout(function(aSelf) {
+ aSelf.checkTabsIndentOverflowTimer = null;
+ aSelf.checkTabsIndentOverflowCallback();
+ }, aDelay || 100, this);
+ },
+ cancelCheckTabsIndentOverflow : function TSTBrowser_cancelCheckTabsIndentOverflow()
+ {
+ if (this.checkTabsIndentOverflowTimer) {
+ this.window.clearTimeout(this.checkTabsIndentOverflowTimer);
+ this.checkTabsIndentOverflowTimer = null;
+ }
+ },
+ checkTabsIndentOverflowTimer : null,
+ checkTabsIndentOverflowCallback : function TSTBrowser_checkTabsIndentOverflowCallback()
+ {
+ if (!utils.getTreePref('indent.autoShrink')) {
+ this.indent = -1;
+ return;
+ }
+
+ var b = this.mTabBrowser;
+ var tabbarSize = b.mTabContainer.boxObject[this.invertedSizeProp];
+ if (!tabbarSize) // don't update indent for collapsed tab bar
+ return;
+
+ var tabs = Array.slice(b.mTabContainer.querySelectorAll(
+ 'tab['+this.kNEST+']:not(['+this.kNEST+'="0"]):not(['+this.kNEST+'=""])'+
+ ':not(['+this.kCOLLAPSED+'="true"])'+
+ ':not([hidden="true"])'+
+ ':not([collapsed="true"])'
+ ));
+ if (!tabs.length)
+ return;
+
+ var self = this;
+ tabs.sort(function(aA, aB) { return Number(aA.getAttribute(self.kNEST)) - Number(aB.getAttribute(self.kNEST)); });
+ var nest = tabs[tabs.length-1].getAttribute(this.kNEST);
+ if (this.maxTreeLevel > -1)
+ nest = Math.min(nest, this.maxTreeLevel);
+ if (!nest)
+ return;
+
+ var oldIndent = this.indent;
+ var indent = (oldIndent < 0 ? this.baseIndent : oldIndent ) * nest;
+ var maxIndentBase = Math.min(
+ this.getFirstNormalTab(b).boxObject[this.invertedSizeProp],
+ tabbarSize
+ );
+ var isVertical = this.isVertical;
+ if (!isVertical) {
+ if (this._horizontalTabMaxIndentBase)
+ maxIndentBase = this._horizontalTabMaxIndentBase;
+ else
+ this._horizontalTabMaxIndentBase = maxIndentBase;
+ }
+ var maxIndent = maxIndentBase * (isVertical ? 0.33 : 0.5 );
+
+ var indentMin = utils.getTreePref(isVertical ? 'indent.min.vertical' : 'indent.min.horizontal');
+ var indentUnit = Math.max(Math.floor(maxIndent / nest), indentMin);
+ if (indent > maxIndent) {
+ this.indent = indentUnit;
+ }
+ else {
+ this.indent = -1;
+ if ((this.baseIndent * nest) > maxIndent)
+ this.indent = indentUnit;
+ }
+
+ if (oldIndent != this.indent) {
+ this.updateAllTabsIndent();
+ }
+ },
+ _horizontalTabMaxIndentBase : 0,
+
+ updateCanCollapseSubtree : function TSTBrowser_updateCanCollapseSubtree(aTab, aLevel)
+ {
+ if (!aTab.parentNode) // do nothing for closed tab!
+ return;
+
+ if (
+ !aLevel ||
+ this.maxTreeLevel < 0 ||
+ this.maxTreeLevel > aLevel
+ ) {
+ aTab.setAttribute(this.kALLOW_COLLAPSE, true);
+ this.collapseExpandSubtree(aTab, this.isSubtreeCollapsed(aTab));
+ }
+ else {
+ this.collapseExpandSubtree(aTab, false);
+ aTab.removeAttribute(this.kALLOW_COLLAPSE);
+ }
+ },
+
+ updateTabsCount : function TSTBrowser_updateTabsCount(aTab, aDontUpdateAncestor)
+ {
+ if (!aTab.parentNode) // do nothing for closed tab!
+ return;
+
+ var count = this.document.getAnonymousElementByAttribute(aTab, 'class', this.kCOUNTER);
+ if (count) {
+ let value = this.getDescendantTabs(aTab).length;
+ if (this.counterRole == this.kCOUNTER_ROLE_ALL_TABS)
+ value += 1;
+ count.setAttribute('value', value);
+ }
+ if (!aDontUpdateAncestor) {
+ let parent = this.getParentTab(aTab);
+ if (parent)
+ this.updateTabsCount(parent);
+ }
+ },
+
+ updateAllTabsCount : function TSTBrowser_updateAllTabsCount()
+ {
+ var tabs = this.rootTabs;
+ for (let i = 0, maxi = tabs.length; i < maxi; i++)
+ {
+ let tab = tabs[i];
+ this.updateTabsCount(tab, this);
+ }
+ },
+
+ promoteTooDeepLevelTabs : function TSTBrowser_promoteTooDeepLevelTabs(aParent)
+ {
+ if (this.maxTreeLevel < 0 || !this.maxTreeLevelPhisical)
+ return;
+
+ var tabs = aParent ? this.getDescendantTabs(aParent) : this.getAllTabs(this.mTabBrowser) ;
+ for (let i = 0, maxi = tabs.length; i < maxi; i++)
+ {
+ let level = parseInt(tab.getAttribute(this.kNEST) || 0);
+ if (level <= this.maxTreeLevel)
+ continue;
+
+ let parent = this.getParentTab(tab);
+ let newParent = this.getParentTab(parent);
+ if (this.maxTreeLevel == 0 || !newParent) {
+ this.detachTab(aTab);
+ }
+ else {
+ let nextSibling = this.getNextTab(tab);
+ this.attachTabTo(tab, newParent, {
+ dontMove : true,
+ insertBefore : nextSibling
+ });
+ }
+ }
+ },
+
+/* move */
+
+ moveTabSubtreeTo : function TSTBrowser_moveTabSubtreeTo(aTab, aIndex)
+ {
+ if (!aTab || !aTab.parentNode)
+ return;
+
+ var b = this.mTabBrowser;
+ this.subTreeMovingCount++;
+
+ this.internallyTabMovingCount++;
+ b.moveTabTo(aTab, aIndex);
+ this.internallyTabMovingCount--;
+
+ this.subTreeChildrenMovingCount++;
+ this.internallyTabMovingCount++;
+ var descendantTabs = this.getDescendantTabs(aTab);
+ for (let i = 0, maxi = descendantTabs.length; i < maxi; i++)
+ {
+ let descendantTab = descendantTabs[i];
+ b.moveTabTo(descendantTab, aTab._tPos + i + (aTab._tPos < descendantTab._tPos ? 1 : 0 ));
+ }
+ this.internallyTabMovingCount--;
+ this.subTreeChildrenMovingCount--;
+
+ this.subTreeMovingCount--;
+ },
+ moveTabSubTreeTo : function(...aArgs) {
+ return this.moveTabSubtreeTo.apply(this, aArgs);
+ }, // obsolete, for backward compatibility
+
+ moveTabLevel : function TSTBrowser_moveTabLevel(aEvent)
+ {
+ var b = this.mTabBrowser;
+ var parentTab = this.getParentTab(b.mCurrentTab);
+ if (aEvent.keyCode == Ci.nsIDOMKeyEvent.DOM_VK_RIGHT) {
+ let prevTab = this.getPreviousSiblingTab(b.mCurrentTab);
+ if ((!parentTab && prevTab) ||
+ (parentTab && b.mCurrentTab != this.getFirstChildTab(parentTab))) {
+ this.attachTabTo(b.mCurrentTab, prevTab);
+ b.mCurrentTab.focus();
+ return true;
+ }
+ }
+ else if (aEvent.keyCode == Ci.nsIDOMKeyEvent.DOM_VK_LEFT && parentTab) {
+ let grandParent = this.getParentTab(parentTab);
+ if (grandParent) {
+ this.attachTabTo(b.mCurrentTab, grandParent, {
+ insertBefore : this.getNextSiblingTab(parentTab)
+ });
+ b.mCurrentTab.focus();
+ return true;
+ }
+ else {
+ let nextTab = this.getNextSiblingTab(parentTab);
+ this.detachTab(b.mCurrentTab);
+ this.internallyTabMovingCount++;
+ if (nextTab) {
+ b.moveTabTo(b.mCurrentTab, nextTab._tPos - 1);
+ }
+ else {
+ b.moveTabTo(b.mCurrentTab, this.getLastTab(b)._tPos);
+ }
+ this.internallyTabMovingCount--;
+ b.mCurrentTab.focus();
+ return true;
+ }
+ }
+ return false;
+ },
+
+ /**
+ * Imports tabs from another window with their tree structure.
+ * aOptions is an optional hash which can have two properties:
+ * * duplicate (boolean)
+ * * insertBefore (nsIDOMElement)
+ */
+ importTabs : function TSTBrowser_importTabs(aTabs, aInsertBefore) /* PUBLIC API */
+ {
+ return this.moveTabsInternal(aTabs, { insertBefore : aInsertBefore });
+ },
+ duplicateTabs : function TSTBrowser_duplicateTabs(aTabs, aInsertBefore) /* PUBLIC API */
+ {
+ return this.moveTabsInternal(aTabs, { insertBefore : aInsertBefore, duplicate : true });
+ },
+ moveTabs : function TSTBrowser_importTabs(aTabs, aInsertBefore) /* PUBLIC API */
+ {
+ return this.moveTabsInternal(aTabs, { insertBefore : aInsertBefore });
+ },
+ moveTabsInternal : function TSTBrowser_moveTabsInternal(aTabs, aOptions)
+ {
+ aOptions = aOptions || {};
+
+ var targetBrowser = this.mTabBrowser;
+ var sourceWindow = aTabs[0].ownerDocument.defaultView;
+ var sourceBrowser = sourceWindow.TreeStyleTabService.getTabBrowserFromChild(aTabs[0]);
+ var sourceService = sourceBrowser.treeStyleTab;
+
+ // prevent Multiple Tab Handler feature
+ targetBrowser.duplicatingSelectedTabs = true;
+ targetBrowser.movingSelectedTabs = true;
+
+ var shouldClose = (
+ !aOptions.duplicate &&
+ sourceService.getAllTabs(sourceBrowser).length == aTabs.length
+ );
+ var newTabs = [];
+ var treeStructure = sourceService.getTreeStructureFromTabs(aTabs);
+
+ // Firefox fails to "move" collapsed tabs. So, expand them first
+ // and collapse them after they are moved.
+ var collapsedStates = sourceService.forceExpandTabs(aTabs);;
+
+ var shouldResetSelection = (
+ aTabs.every(function(aTab) {
+ return aTab.getAttribute('multiselected') == 'true';
+ }) &&
+ (sourceService != this || aOptions.duplicate)
+ );
+
+ var tabs = this.getTabs(targetBrowser);
+ var lastTabIndex = tabs[tabs.length -1]._tPos;
+ for (let i in aTabs)
+ {
+ let tab = aTabs[i];
+
+ if (shouldResetSelection) {
+ if ('MultipleTabService' in sourceWindow)
+ sourceWindow.MultipleTabService.setSelection(tab, false);
+ else
+ tab.removeAttribute('multiselected');
+ }
+
+ if (aOptions.duplicate) {
+ tab = this.duplicateTabAsOrphan(tab);
+ newTabs.push(tab);
+ }
+ else if (sourceService != this) {
+ tab = this.importTab(tab);
+ newTabs.push(tab);
+ }
+
+ if (shouldResetSelection) {
+ if ('MultipleTabService' in sourceWindow)
+ sourceWindow.MultipleTabService.setSelection(tab, true);
+ else
+ tab.setAttribute('multiselected', true);
+ }
+
+ lastTabIndex++;
+
+ let newIndex = aOptions.insertBefore ? aOptions.insertBefore._tPos : lastTabIndex ;
+ if (aOptions.insertBefore && newIndex > tab._tPos)
+ newIndex--;
+
+ this.internallyTabMovingCount++;
+ targetBrowser.moveTabTo(tab, newIndex);
+ this.collapseExpandTab(tab, false, true);
+ this.internallyTabMovingCount--;
+ }
+
+ if (shouldClose)
+ sourceService.closeOwner(sourceBrowser);
+
+ if (newTabs.length)
+ this.applyTreeStructureToTabs(
+ newTabs,
+ treeStructure,
+ collapsedStates.map(function(aCollapsed) {
+ return !aCollapsed
+ })
+ );
+
+ for (let i = collapsedStates.length - 1; i > -1; i--)
+ {
+ sourceService.collapseExpandSubtree(aTabs[i], collapsedStates[i], true);
+ }
+
+ // Multiple Tab Handler
+ targetBrowser.movingSelectedTabs = false;
+ targetBrowser.duplicatingSelectedTabs = false;
+
+ return newTabs;
+ },
+
+ importTab : function TSTBrowser_importTab(aTab)
+ {
+ if (!aTab.parentNode) // do nothing for closed tab!
+ return null;
+
+ var newTab = this.mTabBrowser.addTab();
+ newTab.linkedBrowser.stop();
+ newTab.linkedBrowser.docShell;
+ this.mTabBrowser.swapBrowsersAndCloseOther(newTab, aTab);
+ this.mTabBrowser.setTabTitle(newTab);
+ return newTab;
+ },
+
+ duplicateTabAsOrphan : function TSTBrowser_duplicateTabAsOrphan(aTab)
+ {
+ if (!aTab.parentNode) // do nothing for closed tab!
+ return null;
+
+ var newTab = this.mTabBrowser.duplicateTab(aTab);
+ this.deleteTabValue(newTab, this.kCHILDREN);
+ this.deleteTabValue(newTab, this.kPARENT);
+ return newTab;
+ },
+
+ closeOwner : function TSTBrowser_closeOwner(aTabOwner)
+ {
+ var w = aTabOwner.ownerDocument.defaultView;
+ if (!w)
+ return;
+ if ('SplitBrowser' in w) {
+ if ('getSubBrowserFromChild' in w.SplitBrowser) {
+ var subbrowser = w.SplitBrowser.getSubBrowserFromChild(aTabOwner);
+ if (subbrowser) {
+ subbrowser.close();
+ return;
+ }
+ }
+ if (w.SplitBrowser.browsers.length)
+ return;
+ }
+ w.close();
+ },
+
+/* collapse/expand */
+
+ collapseExpandSubtree : function TSTBrowser_collapseExpandSubtree(aTab, aCollapse, aJustNow) /* PUBLIC API */
+ {
+ if (!aTab || !aTab.parentNode)
+ return;
+
+ if (this.isSubtreeCollapsed(aTab) == aCollapse)
+ return;
+
+ var b = this.mTabBrowser;
+ this.doingCollapseExpand = true;
+
+ this.setTabValue(aTab, this.kSUBTREE_COLLAPSED, aCollapse);
+
+ var expandedTabs = this.getChildTabs(aTab);
+ var lastExpandedTabIndex = expandedTabs.length - 1;
+ for (let i = 0, maxi = expandedTabs.length; i < maxi; i++)
+ {
+ let childTab = expandedTabs[i];
+ if (!aCollapse && !aJustNow && i == lastExpandedTabIndex) {
+ let self = this;
+ this.collapseExpandTab(childTab, aCollapse, aJustNow, function() {
+ self.scrollToTabSubtree(aTab);
+ });
+ }
+ else
+ this.collapseExpandTab(childTab, aCollapse, aJustNow);
+ }
+
+ if (aCollapse)
+ this.deleteTabValue(aTab, this.kSUBTREE_EXPANDED_MANUALLY);
+
+ if (utils.getTreePref('indent.autoShrink') &&
+ utils.getTreePref('indent.autoShrink.onlyForVisible'))
+ this.checkTabsIndentOverflow();
+
+ this.doingCollapseExpand = false;
+ },
+ manualCollapseExpandSubtree : function(aTab, aCollapse, aJustNow)
+ {
+ this.collapseExpandSubtree(aTab, aCollapse, aJustNow);
+ if (!aCollapse)
+ this.setTabValue(aTab, this.kSUBTREE_EXPANDED_MANUALLY, true);
+
+ if (utils.getTreePref('indent.autoShrink') &&
+ utils.getTreePref('indent.autoShrink.onlyForVisible')) {
+ this.cancelCheckTabsIndentOverflow();
+ if (!aTab.__treestyletab__checkTabsIndentOverflowOnMouseLeave) {
+ var self = this;
+ var stillOver = false;
+ var id = this.getTabValue(aTab, this.kID);
+ aTab.__treestyletab__checkTabsIndentOverflowOnMouseLeave = function checkTabsIndentOverflowOnMouseLeave(aEvent, aDelayed) {
+ if (aEvent.type == 'mouseover') {
+ if (self.evaluateXPath(
+ 'ancestor-or-self::*[@' + self.kID + '="' + id + '"]',
+ aEvent.originalTarget || aEvent.target,
+ Ci.nsIDOMXPathResult.BOOLEAN_TYPE
+ ).booleanValue)
+ stillOver = true;
+ return;
+ }
+ else if (!aDelayed) {
+ if (stillOver) {
+ stillOver = false;
+ }
+ self.Deferred.next(function() {
+ checkTabsIndentOverflowOnMouseLeave.call(null, aEvent, true);
+ });
+ return;
+ } else if (stillOver) {
+ return;
+ }
+ var x = aEvent.clientX;
+ var y = aEvent.clientY;
+ var rect = aTab.getBoundingClientRect();
+ if (x > rect.left && x < rect.right && y > rect.top && y < rect.bottom)
+ return;
+ self.document.removeEventListener('mouseover', aTab.__treestyletab__checkTabsIndentOverflowOnMouseLeave, true);
+ self.document.removeEventListener('mouseout', aTab.__treestyletab__checkTabsIndentOverflowOnMouseLeave, true);
+ delete aTab.__treestyletab__checkTabsIndentOverflowOnMouseLeave;
+ self.checkTabsIndentOverflow();
+ };
+ this.document.addEventListener('mouseover', aTab.__treestyletab__checkTabsIndentOverflowOnMouseLeave, true);
+ this.document.addEventListener('mouseout', aTab.__treestyletab__checkTabsIndentOverflowOnMouseLeave, true);
+ }
+ }
+ },
+
+ collapseExpandTab : function TSTBrowser_collapseExpandTab(aTab, aCollapse, aJustNow, aCallbackToRunOnStartAnimation)
+ {
+ if (!aTab || !aTab.parentNode || !this.getParentTab(aTab))
+ return;
+
+ this.setTabValue(aTab, this.kCOLLAPSED, aCollapse);
+ this.updateTabCollapsed(aTab, aCollapse, aJustNow, aCallbackToRunOnStartAnimation);
+
+ var data = {
+ collapsed : aCollapse
+ };
+
+ /* PUBLIC API */
+ this.fireCustomEvent(this.kEVENT_TYPE_TAB_COLLAPSED_STATE_CHANGED, aTab, true, false, data);
+ // for backward compatibility
+ this.fireCustomEvent(this.kEVENT_TYPE_TAB_COLLAPSED_STATE_CHANGED.replace(/^nsDOM/, ''), aTab, true, false, data);
+
+ var b = this.mTabBrowser;
+ var parent;
+ if (aCollapse && aTab == b.selectedTab && (parent = this.getParentTab(aTab))) {
+ var newSelection = parent;
+ this.getAncestorTabs(aTab).some(function(aAncestor) {
+ if (!this.isCollapsed(aAncestor)) {
+ newSelection = aAncestor;
+ return true;
+ }
+ return false;
+ }, this);
+ b.selectedTab = newSelection;
+ }
+
+ if (!this.isSubtreeCollapsed(aTab)) {
+ let tabs = this.getChildTabs(aTab);
+ for (let i = 0, maxi = tabs.length; i < maxi; i++)
+ {
+ this.collapseExpandTab(tabs[i], aCollapse, aJustNow);
+ }
+ }
+ },
+ updateTabCollapsed : function TSTBrowser_updateTabCollapsed(aTab, aCollapsed, aJustNow, aCallbackToRunOnStartAnimation)
+ {
+ if (!aTab.parentNode) // do nothing for closed tab!
+ return;
+
+ this.stopTabCollapseAnimation(aTab);
+
+ aTab.removeAttribute(this.kX_OFFSET);
+ aTab.removeAttribute(this.kY_OFFSET);
+
+ if (!this.canCollapseSubtree(this.getRootTab(aTab)))
+ aCollapsed = false;
+
+ aTab.setAttribute(this.kCOLLAPSING_PHASE, aCollapsed ? this.kCOLLAPSING_PHASE_TO_BE_COLLAPSED : this.kCOLLAPSING_PHASE_TO_BE_EXPANDED );
+
+ var CSSTransitionEnabled = ('transition' in aTab.style || 'MozTransition' in aTab.style);
+
+ var maxMargin;
+ var offsetAttr;
+ var collapseProp = 'margin-'+this.collapseTarget;
+ let (firstTab = this.getFirstNormalTab(this.mTabBrowser)) {
+ if (this.isVertical) {
+ maxMargin = firstTab.boxObject.height;
+ offsetAttr = this.kY_OFFSET;
+ if (firstTab.style.height)
+ aTab.style.height = firstTab.style.height;
+ }
+ else {
+ maxMargin = firstTab.boxObject.width;
+ offsetAttr = this.kX_OFFSET;
+ if (firstTab.style.width)
+ aTab.style.width = firstTab.style.width;
+ }
+ }
+
+ var startMargin, endMargin, startOpacity, endOpacity;
+ if (aCollapsed) {
+ startMargin = 0;
+ endMargin = maxMargin;
+ startOpacity = 1;
+ endOpacity = 0;
+ if (this.canStackTabs && this.getParentTab(aTab)) {
+ endOpacity = 1;
+ endMargin = this.kSTACKED_TAB_MARGIN;
+ }
+ }
+ else {
+ startMargin = maxMargin;
+ endMargin = 0;
+ startOpacity = 0;
+ endOpacity = 1;
+ if (this.canStackTabs && this.getParentTab(aTab)) {
+ startOpacity = 1;
+ startMargin = this.kSTACKED_TAB_MARGIN;
+ }
+ }
+
+ if (
+ !this.animationEnabled ||
+ aJustNow ||
+ this.collapseDuration < 1 // ||
+// !this.isVertical ||
+// !this.canCollapseSubtree(this.getParentTab(aTab))
+ ) {
+ if (aCollapsed)
+ aTab.setAttribute(this.kCOLLAPSED_DONE, true);
+ else
+ aTab.removeAttribute(this.kCOLLAPSED_DONE);
+ aTab.removeAttribute(this.kCOLLAPSING_PHASE);
+
+ // Pinned tabs are positioned by "margin-top", so
+ // we must not reset the property for pinned tabs.
+ // (However, we still must update "opacity".)
+ let pinned = aTab.getAttribute('pinned') == 'true';
+ let canExpand = !pinned || this.collapseCSSProp != 'margin-top';
+
+ if (CSSTransitionEnabled) {
+ if (canExpand)
+ aTab.style.setProperty(this.collapseCSSProp, endMargin ? '-'+endMargin+'px' : '', 'important');
+
+ if (endOpacity == 0)
+ aTab.style.setProperty('opacity', endOpacity == 1 ? '' : endOpacity, 'important');
+ else
+ aTab.style.removeProperty('opacity');
+ }
+ else {
+ if (canExpand)
+ aTab.style.removeProperty(this.collapseCSSProp);
+ aTab.style.removeProperty('opacity');
+ }
+
+ if (aCallbackToRunOnStartAnimation)
+ aCallbackToRunOnStartAnimation();
+ return;
+ }
+
+ var deltaMargin = endMargin - startMargin;
+ var deltaOpacity = endOpacity - startOpacity;
+
+ aTab.style.setProperty(this.collapseCSSProp, startMargin ? '-'+startMargin+'px' : '', 'important');
+ aTab.style.setProperty('opacity', startOpacity == 1 ? '' : startOpacity, 'important');
+
+ if (!aCollapsed) {
+ aTab.setAttribute(offsetAttr, maxMargin);
+ aTab.removeAttribute(this.kCOLLAPSED_DONE);
+ }
+
+ var radian = 90 * Math.PI / 180;
+ var self = this;
+ var firstFrame = true;
+ aTab.__treestyletab__updateTabCollapsedTask = function(aTime, aBeginning, aChange, aDuration) {
+ if (self.isDestroying)
+ return true;
+ if (firstFrame) {
+ // The callback must be started before offsetAttr is changed!
+ if (aCallbackToRunOnStartAnimation)
+ aCallbackToRunOnStartAnimation();
+ if (CSSTransitionEnabled) {
+ aTab.style.setProperty(self.collapseCSSProp, endMargin ? '-'+endMargin+'px' : '', 'important');
+ aTab.style.setProperty('opacity', endOpacity == 1 ? '' : endOpacity, 'important');
+ }
+ }
+ firstFrame = false;
+ // If this is the last tab, negative scroll happens.
+ // Then, we shouldn't do animation.
+ var stopAnimation = false;
+ var scrollBox = self.scrollBox;
+ if (scrollBox) {
+ if (scrollBox._scrollbox)
+ scrollBox = scrollBox._scrollbox;
+ if ('scrollTop' in scrollBox &&
+ (scrollBox.scrollTop < 0 || scrollBox.scrollLeft < 0)) {
+ scrollBox.scrollTop = 0;
+ scrollBox.scrollLeft = 0;
+ stopAnimation = true;
+ }
+ }
+ if (aTime >= aDuration || stopAnimation) {
+ delete aTab.__treestyletab__updateTabCollapsedTask;
+ if (aCollapsed)
+ aTab.setAttribute(self.kCOLLAPSED_DONE, true);
+ if (!CSSTransitionEnabled) {
+ aTab.style.removeProperty(self.collapseCSSProp);
+ aTab.style.removeProperty('opacity');
+ }
+ aTab.removeAttribute(offsetAttr);
+ aTab.removeAttribute(self.kCOLLAPSING_PHASE);
+
+ maxMargin = null;
+ offsetAttr = null;
+ startMargin = null;
+ endMargin = null;
+ startOpacity = null;
+ endOpacity = null;
+ deltaMargin = null;
+ deltaOpacity = null;
+ collapseProp = null;
+ radian = null;
+ self = null;
+ aTab = null;
+
+ return true;
+ }
+ else {
+ if (!CSSTransitionEnabled) {
+ let power = Math.sin(aTime / aDuration * radian);
+ let margin = startMargin + (deltaMargin * power);
+ let opacity = startOpacity + (deltaOpacity * power);
+ aTab.style.setProperty(self.collapseCSSProp, margin ? '-'+margin+'px' : '', 'important');
+ aTab.style.setProperty('opacity', opacity == 1 ? '' : opacity, 'important');
+ }
+ aTab.setAttribute(offsetAttr, maxMargin);
+ return false;
+ }
+ };
+ this.animationManager.addTask(
+ aTab.__treestyletab__updateTabCollapsedTask,
+ 0, 0, this.collapseDuration, this.window
+ );
+ },
+ kOPACITY_RULE_REGEXP : /opacity\s*:[^;]+;?/,
+ kSTACKED_TAB_MARGIN : 15,
+ stopTabCollapseAnimation : function TSTBrowser_stopTabCollapseAnimation(aTab)
+ {
+ if (!aTab.parentNode)
+ return; // do nothing for closed tab!
+
+ this.animationManager.removeTask(
+ aTab.__treestyletab__updateTabCollapsedTask
+ );
+ },
+
+ collapseExpandTreesIntelligentlyFor : function TSTBrowser_collapseExpandTreesIntelligentlyFor(aTab, aJustNow)
+ {
+ if (!aTab ||
+ !aTab.parentNode ||
+ this.doingCollapseExpand ||
+ !this.canCollapseSubtree(aTab))
+ return;
+
+ var b = this.mTabBrowser;
+ var sameParentTab = this.getParentTab(aTab);
+ var expandedAncestors = [aTab].concat(this.getAncestorTabs(aTab))
+ .map(function(aAncestor) {
+ return aAncestor.getAttribute(this.kID);
+ }, this)
+ .join('|');
+
+ var xpathResult = this.evaluateXPath(
+ 'child::xul:tab[@'+this.kCHILDREN+' and not(@'+this.kCOLLAPSED+'="true") and not(@'+this.kSUBTREE_COLLAPSED+'="true") and @'+this.kID+' and not(contains("'+expandedAncestors+'", @'+this.kID+')) and not(@hidden="true")]',
+ b.mTabContainer
+ );
+ for (var i = 0, maxi = xpathResult.snapshotLength; i < maxi; i++)
+ {
+ let dontCollapse = false;
+ let collapseTab = xpathResult.snapshotItem(i);
+
+ let parentTab = this.getParentTab(collapseTab);
+ if (parentTab) {
+ dontCollapse = true;
+ if (!this.isSubtreeCollapsed(parentTab)) {
+ this.getAncestorTabs(collapseTab).some(function(aAncestor) {
+ if (expandedAncestors.indexOf(aAncestor.getAttribute(this.kID)) < 0)
+ return false;
+ dontCollapse = false;
+ return true;
+ }, this);
+ }
+ }
+
+ let manuallyExpanded = this.getTabValue(collapseTab, this.kSUBTREE_EXPANDED_MANUALLY) == 'true';
+ if (!dontCollapse && !manuallyExpanded)
+ this.collapseExpandSubtree(collapseTab, true, aJustNow);
+ }
+
+ this.collapseExpandSubtree(aTab, false, aJustNow);
+ },
+
+ collapseExpandAllSubtree : function TSTBrowser_collapseExpandAllSubtree(aCollapse, aJustNow)
+ {
+ var tabs = this.mTabBrowser.mTabContainer.querySelectorAll(
+ 'tab['+this.kID+']['+this.kCHILDREN+']'+
+ (
+ aCollapse ?
+ ':not(['+this.kSUBTREE_COLLAPSED+'="true"])' :
+ '['+this.kSUBTREE_COLLAPSED+'="true"]'
+ )
+ );
+ for (var i = 0, maxi = tabs.length; i < maxi; i++)
+ {
+ this.collapseExpandSubtree(tabs[i], aCollapse, aJustNow);
+ }
+ },
+
+/* scroll */
+
+ scrollTo : function TSTBrowser_scrollTo(aEndX, aEndY)
+ {
+ if (this.deferredTasks['cancelPerformingAutoScroll'])
+ return;
+
+ if (this.animationEnabled || this.smoothScrollEnabled) {
+ this.smoothScrollTo(aEndX, aEndY);
+ }
+ else {
+ try {
+ this.cancelPerformingAutoScroll();
+ this.scrollBoxObject.scrollTo(aEndX, aEndY);
+ }
+ catch(e) {
+ }
+ }
+ },
+
+ smoothScrollTo : function TSTBrowser_smoothScrollTo(aEndX, aEndY, aDuration)
+ {
+ this.cancelPerformingAutoScroll(true);
+
+ var b = this.mTabBrowser;
+ var scrollBoxObject = this.scrollBoxObject;
+ var x = {}, y = {};
+ scrollBoxObject.getPosition(x, y);
+ var startX = x.value;
+ var startY = y.value;
+ var deltaX = aEndX - startX;
+ var deltaY = aEndY - startY;
+
+ var arrowscrollbox = scrollBoxObject.element.parentNode;
+ if (
+ arrowscrollbox &&
+ (
+ arrowscrollbox.localName != 'arrowscrollbox' ||
+ !('_isScrolling' in arrowscrollbox)
+ )
+ )
+ arrowscrollbox = null;
+
+ var radian = 90 * Math.PI / 180;
+ var self = this;
+ this.smoothScrollTask = function(aTime, aBeginning, aChange, aDuration) {
+ if (self.isDestroying)
+ return true;
+ var scrollBoxObject = self.scrollBoxObject;
+ if (aTime >= aDuration || self.deferredTasks['cancelPerformingAutoScroll']) {
+ if (!self.deferredTasks['cancelPerformingAutoScroll']) {
+ scrollBoxObject.scrollTo(aEndX, aEndY);
+
+ /**
+ * When there is any expanding tab, we have to retry to scroll.
+ * if the scroll box was expanded.
+ */
+ let oldSize = self._getMaxScrollSize(scrollBoxObject);
+ let key = 'smoothScrollTo_'+parseInt(Math.random() * 65000);
+ (self.deferredTasks[key] = self.Deferred.next(function() {
+ let newSize = self._getMaxScrollSize(scrollBoxObject);
+ let lastTab = self.getLastVisibleTab(self.mTabBrowser);
+ if (
+ // scroll size can be expanded by expanding tabs.
+ oldSize[0] < newSize[0] || oldSize[1] < newSize[1] ||
+ // there are still animating tabs
+ self.getXOffsetOfTab(lastTab) || self.getYOffsetOfTab(lastTab) ||
+ self.mTabBrowser.mTabContainer.querySelector('tab['+self.kCOLLAPSING_PHASE+'="'+self.kCOLLAPSING_PHASE_TO_BE_EXPANDED+'"]')
+ )
+ self.smoothScrollTo(aEndX, aEndY, parseInt(aDuration * 0.5));
+ self = null;
+ scrollBoxObject = null;
+ })).error(self.defaultDeferredErrorHandler).next(function() {
+ delete self.deferredTasks[key];
+ });
+ }
+
+ b = null;
+ x = null;
+ y = null;
+ startX = null;
+ startY = null;
+ radian = null;
+ self.smoothScrollTask = null;
+
+ return true;
+ }
+
+ var power = Math.sin(aTime / aDuration * radian);
+ var newX = startX + parseInt(deltaX * power);
+ var newY = startY + parseInt(deltaY * power);
+ scrollBoxObject.scrollTo(newX, newY);
+ return false;
+ };
+ this.animationManager.addTask(
+ this.smoothScrollTask,
+ 0, 0, this.smoothScrollDuration || aDuration, this.window
+ );
+ },
+ _getMaxScrollSize : function(aScrollBoxObject) {
+ var x = {}, y = {};
+ aScrollBoxObject.getPosition(x, y);
+ var w = {}, h = {};
+ aScrollBoxObject.getScrolledSize(w, h);
+ var maxX = Math.max(0, w.value - aScrollBoxObject.width);
+ var maxY = Math.max(0, h.value - aScrollBoxObject.height);
+ return [maxX, maxY];
+ },
+ smoothScrollTask : null,
+
+ scrollToTab : function TSTBrowser_scrollToTab(aTab, aOnlyWhenCurrentTabIsInViewport)
+ {
+ if (!aTab || !aTab.parentNode || this.isTabInViewport(aTab))
+ return;
+
+ var b = this.mTabBrowser;
+
+ var scrollBoxObject = this.scrollBoxObject;
+ var w = {}, h = {};
+ try {
+ scrollBoxObject.getScrolledSize(w, h);
+ }
+ catch(e) { // Tab Mix Plus (or others)
+ return;
+ }
+
+ var targetTabBox = this.getFutureBoxObject(aTab);
+ var baseTabBox = this.getFirstNormalTab(b).boxObject;
+
+ var targetX = (targetTabBox.screenX < scrollBoxObject.screenX) ?
+ (targetTabBox.screenX - baseTabBox.screenX) - (targetTabBox.width * 0.5) :
+ (targetTabBox.screenX - baseTabBox.screenX) - scrollBoxObject.width + (targetTabBox.width * 1.5) ;
+
+ var targetY = (targetTabBox.screenY < scrollBoxObject.screenY) ?
+ (targetTabBox.screenY - baseTabBox.screenY) - (targetTabBox.height * 0.5) :
+ (targetTabBox.screenY - baseTabBox.screenY) - scrollBoxObject.height + (targetTabBox.height * 1.5) ;
+
+ if (aOnlyWhenCurrentTabIsInViewport && b.selectedTab != aTab) {
+ let box = b.selectedTab.boxObject;
+ if (targetTabBox.screenX - box.screenX + baseTabBox.width > scrollBoxObject.width ||
+ targetTabBox.screenY - box.screenY + baseTabBox.height > scrollBoxObject.height)
+ return;
+ }
+
+ this.scrollTo(targetX, targetY);
+ },
+
+ scrollToTabSubtree : function TSTBrowser_scrollToTabSubtree(aTab)
+ {
+ if (!aTab.parentNode) // do nothing for closed tab!
+ return;
+ var b = this.mTabBrowser;
+ var descendant = this.getDescendantTabs(aTab);
+ var parentTabBox = aTab.boxObject;
+
+ var containerPosition = this.tabStrip.boxObject[this.screenPositionProp];
+ var containerSize = this.tabStrip.boxObject[this.sizeProp];
+ var parentPosition = parentTabBox[this.screenPositionProp];
+
+ var lastVisible = aTab;
+ for (let i = descendant.length-1; i > -1; i--)
+ {
+ let tab = descendant[i];
+ if (this.isCollapsed(tab))
+ continue;
+
+ let box = this.getFutureBoxObject(tab);
+ if (box[this.screenPositionProp] + box[this.sizeProp] - parentPosition > containerSize)
+ continue;
+
+ lastVisible = tab;
+ break;
+ }
+
+ if (this.isTabInViewport(aTab) && this.isTabInViewport(lastVisible))
+ return;
+
+ var lastPosition = lastVisible.boxObject[this.screenPositionProp];
+ var tabSize = lastVisible.boxObject[this.sizeProp];
+
+ if (lastPosition - parentPosition + tabSize > containerSize - tabSize) { // out of screen
+ var endPos = parentPosition - this.getFirstNormalTab(b).boxObject[this.screenPositionProp] - tabSize * 0.5;
+ var endX = this.isVertical ? 0 : endPos ;
+ var endY = this.isVertical ? endPos : 0 ;
+ this.scrollTo(endX, endY);
+ }
+ else if (!this.isTabInViewport(aTab) && this.isTabInViewport(lastVisible)) {
+ this.scrollToTab(aTab);
+ }
+ else if (this.isTabInViewport(aTab) && !this.isTabInViewport(lastVisible)) {
+ this.scrollToTab(lastVisible);
+ }
+ else if (parentPosition < containerPosition) {
+ this.scrollToTab(aTab);
+ }
+ else {
+ this.scrollToTab(lastVisible);
+ }
+ },
+
+ notifyBackgroundTab : function TSTBrowser_notifyBackgroundTab()
+ {
+ var animateElement = this.mTabBrowser.mTabContainer._animateElement;
+ var attrName = this.kBG_NOTIFY_PHASE;
+ if (!animateElement)
+ return;
+
+ if (this.deferredTasks['notifyBackgroundTab'])
+ this.deferredTasks['notifyBackgroundTab'].cancel();
+
+ if (!animateElement.hasAttribute(attrName))
+ animateElement.setAttribute(attrName, 'ready');
+
+ var self = this;
+ (this.deferredTasks['notifyBackgroundTab'] = this.Deferred
+ .next(function() {
+ animateElement.setAttribute(attrName, 'notifying');
+ }))
+ .wait(0.15)
+ .next(function() {
+ animateElement.setAttribute(attrName, 'finish');
+ })
+ .wait(1)
+ .next(function() {
+ animateElement.removeAttribute(attrName);
+ })
+ .error(this.defaultDeferredErrorHandler).next(function() {
+ delete self.deferredTasks['notifyBackgroundTab'];
+ });
+ },
+
+ restoreTree : function TSTBrowser_restoreTree()
+ {
+ if (!this.needRestoreTree || this.useTMPSessionAPI)
+ return;
+
+ this.needRestoreTree = false;
+
+ if (this.useTMPSessionAPI && prefs.getPref('extensions.tabmix.sessions.manager'))
+ return;
+
+ var level = utils.getTreePref('restoreTree.level');
+
+ var tabs = this.getAllTabs(this.mTabBrowser);
+ var tabsToRestore = 0; // it is the number of pending tabs.
+ if (utils.SessionStoreInternal &&
+ utils.SessionStoreInternal._browserEpochs) {
+ let browserEpochs = utils.SessionStoreInternal._browserEpochs;
+ tabsToRestore = tabs.filter(function(aTab) {
+ return browserEpochs.has(aTab.linkedBrowser.permanentKey);
+ }).length;
+ }
+ else {
+ Components.utils.reportError(new Error('There is no property named "_browserEpochs"!!'));
+ }
+
+ dump('TSTBrowser::restoreTree\n');
+ dump(' level = '+level+'\n');
+ dump(' tabsToRestore = '+tabsToRestore+'\n');
+ if (
+ level <= this.kRESTORE_TREE_LEVEL_NONE ||
+ tabsToRestore <= 1
+ )
+ return;
+
+ var onlyVisible = level <= this.kRESTORE_TREE_ONLY_VISIBLE;
+ tabs = tabs.filter(function(aTab) {
+ var toBeRestored = utils.isTabNotRestoredYet(aTab);
+ // This cache can be set to false by initTab(), but now we not the correct status.
+ // Because this cached status is used by other methods, we must update it now.
+ aTab.linkedBrowser.__treestyletab__toBeRestored = toBeRestored;
+ return (
+ toBeRestored &&
+ (!onlyVisible || !aTab.hidden)
+ );
+ });
+ dump(' restoring member tabs = '+tabs.length+'\n');
+ if (tabs.length <= 1)
+ return;
+
+ for (let i = 0, maxi = tabs.length; i < maxi; i++)
+ {
+ let tab = tabs[i];
+ let currentId = tab.getAttribute(this.kID);
+ if (this.tabsHash[currentId] == tab)
+ delete this.tabsHash[currentId];
+
+ this.resetTabState(tab);
+
+ tab.setAttribute(this.kID, currentId); // to fallback to it
+ let [id, duplicated] = this._restoreTabId(tab);
+
+ this.setTabValue(tab, this.kID, id);
+ this.tabsHash[id] = tab;
+
+ tab.__treestyletab__restoreState = this.RESTORE_STATE_READY_TO_RESTORE;
+ tab.__treestyletab__duplicated = duplicated;
+ }
+
+ this.updateAllTabsIndent(true);
+
+ // restore tree from bottom safely
+ tabs.reverse()
+ .filter(this.restoreOneTab, this)
+ .forEach(this.updateInsertionPositionInfo, this);
+ },
+ restoreOneTab : function TSTBrowser_restoreOneTab(aTab)
+ {
+ if (aTab.__treestyletab__restoreState != this.RESTORE_STATE_READY_TO_RESTORE)
+ return false;
+
+ let duplicated = aTab.__treestyletab__duplicated;
+
+ let children = this.getTabValue(aTab, this.kCHILDREN);
+ if (children) {
+ this.deleteTabValue(aTab, this.kCHILDREN);
+ let manuallyExpanded = this.getTabValue(aTab, this.kSUBTREE_EXPANDED_MANUALLY) == 'true';
+ let subTreeCollapsed = this.getTabValue(aTab, this.kSUBTREE_COLLAPSED) == 'true';
+ subTreeCollapsed = this._restoreSubtreeCollapsedState(aTab, subTreeCollapsed);
+ let self = this;
+ this._restoreChildTabsRelation(aTab, children, duplicated, function(aChild) {
+ /**
+ * When the child has the reference to the parent tab, attachTabTo()
+ * does nothing. To ensure they are correctly related, we have to
+ * clear the relation here.
+ */
+ self.deleteTabValue(aChild, self.kPARENT);
+ let refId = self.getTabValue(aChild, self.kINSERT_BEFORE);
+ if (refId && duplicated)
+ refId = self.redirectId(refId);
+ return {
+ forceExpand : true, // to prevent to collapse the selected tab
+ dontAnimate : true,
+ insertBefore : self.getTabById(refId)
+ };
+ });
+ this.collapseExpandSubtree(aTab, subTreeCollapsed, true);
+ if (manuallyExpanded && !subTreeCollapsed)
+ this.setTabValue(aTab, this.kSUBTREE_EXPANDED_MANUALLY, true);
+ else
+ this.deleteTabValue(aTab, this.kSUBTREE_EXPANDED_MANUALLY);
+ }
+
+ delete aTab.__treestyletab__duplicated;
+ aTab.__treestyletab__restoreState = this.RESTORE_STATE_STRUCTURE_RESTORED;
+ return true
+ },
+
+/* sub modules */
+
+ get tabbarDNDObserver()
+ {
+ if (!this._tabbarDNDObserver) {
+ this._tabbarDNDObserver = new TabbarDNDObserver(this.mTabBrowser);
+ }
+ return this._tabbarDNDObserver;
+ },
+
+ get panelDNDObserver()
+ {
+ if (!this._panelDNDObserver) {
+ this._panelDNDObserver = new TabpanelDNDObserver(this.mTabBrowser);
+ }
+ return this._panelDNDObserver;
+ },
+
+/* proxying for window service */
+ _callWindowServiceMethod : function TSTBrowser_callWindowServiceMethod(aName, aArgs)
+ {
+ return this.windowService[aName].apply(this.windowService, aArgs);
+ },
+ isPopupShown : function TSTBrowser_isPopupShown(...aArgs) {
+ return this._callWindowServiceMethod('isPopupShown', aArgs);
+ },
+ updateTabsOnTop : function TSTBrowser_updateTabsOnTop(...aArgs) {
+ return this._callWindowServiceMethod('updateTabsOnTop', aArgs);
+ },
+ registerTabFocusAllowance : function TSTBrowser_registerTabFocusAllowance(...aArgs) {
+ return this._callWindowServiceMethod('registerTabFocusAllowance', aArgs);
+ },
+ isPopupShown : function TSTBrowser_isPopupShown(...aArgs) {
+ return this._callWindowServiceMethod('isPopupShown', aArgs);
+ },
+ toggleAutoHide : function TSTBrowser_toggleAutoHide(...aArgs) {
+ return this._callWindowServiceMethod('toggleAutoHide', aArgs);
+ },
+
+/* show/hide tab bar */
+ get autoHide()
+ {
+ if (!this._autoHide) {
+ this._autoHide = new AutoHideBrowser(this.mTabBrowser);
+ }
+ return this._autoHide;
+ },
+
+ // for backward compatibility
+ get tabbarShown() { return this.autoHide.expanded; },
+ set tabbarShown(aValue) { if (aValue) this.autoHide.show(); else this.autoHide.hide(); return aValue; },
+ get tabbarExpanded() { return this.autoHide.expanded; },
+ set tabbarExpanded(aValue) { return this.tabbarShown = aValue; },
+ get tabbarResizing() { return this.autoHide.isResizing; },
+ set tabbarResizing(aValue) { return this.autoHide.isResizing = aValue; },
+ get togglerSize() { return this.autoHide.togglerSize; },
+ set togglerSize(aValue) { return this.autoHide.togglerSize = aValue; },
+ get sensitiveArea() { return this.autoHide.sensitiveArea; },
+ set sensitiveArea(aValue) { return this.autoHide.sensitiveArea = aValue; },
+ get lastMouseDownTarget() { return this.autoHide.lastMouseDownTarget; },
+ set lastMouseDownTarget(aValue) { return this.autoHide.lastMouseDownTarget = aValue; },
+
+ get tabbarWidth() { return this.autoHide.width; },
+ set tabbarWidth(aValue) { return this.autoHide.widthwidth = aValue; },
+ get tabbarHeight() { return this.autoHide.height; },
+ set tabbarHeight(aValue) { return this.autoHide.height = aValue; },
+ get splitterWidth() { return this.autoHide.splitterWidth; },
+
+ get autoHideShown() { return this.autoHide.expanded; },
+ set autoHideShown(aValue) { return this.tabbarShown = aValue; },
+ get autoHideXOffset() { return this.autoHide.XOffset; },
+ get autoHideYOffset() { return this.autoHide.YOffset; },
+ get autoHideMode() { return this.autoHide.mode; },
+ set autoHideMode(aValue) { return this.autoHide.mode = aValue; },
+
+ updateAutoHideMode : function TSTBrowser_updateAutoHideMode() { this.autoHide.updateAutoHideMode(); },
+ showHideTabbarInternal : function TSTBrowser_showHideTabbarInternal(aReason) { this.autoHide.showHideInternal(aReason); },
+ showTabbar : function TSTBrowser_showTabbar(aReason) { this.autoHide.show(aReason); },
+ hideTabbar : function TSTBrowser_hideTabbar(aReason) { this.autoHide.hide(aReason); },
+ redrawContentArea : function TSTBrowser_redrawContentArea() { this.autoHide.redrawContentArea(); },
+ drawTabbarCanvas : function TSTBrowser_drawTabbarCanvas() { this.autoHide.drawBG(); },
+ get splitterBorderColor() { this.autoHide.splitterBorderColor; },
+ clearTabbarCanvas : function TSTBrowser_clearTabbarCanvas() { this.autoHide.clearBG(); },
+ updateTabbarTransparency : function TSTBrowser_updateTabbarTransparency() { this.autoHide.updateTransparency(); },
+
+ get autoHideEnabled() { return this.autoHide.enabled; },
+ set autoHideEnabled(aValue) { return this.autoHide.enabled = aValue; },
+ startAutoHide : function TSTBrowser_startAutoHide() { this.autoHide.start(); },
+ endAutoHide : function TSTBrowser_endAutoHide() { this.autoHide.end(); },
+ startAutoHideForFullScreen : function TSTBrowser_startAutoHideForFullScreen() { this.autoHide.startForFullScreen(); },
+ endAutoHideForFullScreen : function TSTBrowser_endAutoHideForFullScreen() { this.autoHide.endForFullScreen(); },
+
+ startListenMouseMove : function TSTBrowser_startListenMouseMove() { this.autoHide.startListenMouseMove(); },
+ endListenMouseMove : function TSTBrowser_endListenMouseMove() { this.autoHide.endListenMouseMove(); },
+ get shouldListenMouseMove() { return this.autoHide.shouldListenMouseMove; },
+ showHideTabbarOnMousemove : function TSTBrowser_showHideTabbarOnMousemove() { this.autoHide.showHideOnMousemove(); },
+ cancelShowHideTabbarOnMousemove : function TSTBrowser_cancelShowHideTabbarOnMousemove() { this.autoHide.cancelShowHideOnMousemove(); },
+ showTabbarForFeedback : function TSTBrowser_showTabbarForFeedback() { this.autoHide.showForFeedback(); },
+ delayedShowTabbarForFeedback : function TSTBrowser_delayedShowTabbarForFeedback() { this.autoHide.delayedShowForFeedback(); },
+ cancelHideTabbarForFeedback : function TSTBrowser_cancelHideTabbarForFeedback() { this.autoHide.cancelHideForFeedback(); }
+
+});
+
diff --git a/modules/browserUIShowHideObserver.js b/modules/browserUIShowHideObserver.js
index 8a1fd5dc..b65eb69b 100644
--- a/modules/browserUIShowHideObserver.js
+++ b/modules/browserUIShowHideObserver.js
@@ -1,127 +1,127 @@
-/* ***** 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 YUKI "Piro" Hiroshi.
- * Portions created by the Initial Developer are Copyright (C) 2013
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s): YUKI "Piro" Hiroshi
- * Infocatcher
- *
- * 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 ******/
-
-const EXPORTED_SYMBOLS = ['BrowserUIShowHideObserver'];
-
-Components.utils.import('resource://treestyletab-modules/constants.js');
-
-function BrowserUIShowHideObserver(aOwner, aBox) {
- this.owner = aOwner;
- this.box = aBox;
- this.init();
-}
-BrowserUIShowHideObserver.prototype = {
- get MutationObserver()
- {
- var w = this.box.ownerDocument.defaultView;
- return w.MutationObserver || w.MozMutationObserver;
- },
-
- init : function BrowserUIShowHideObserver_onInit()
- {
- if (!this.MutationObserver)
- return;
- this.observer = new this.MutationObserver((function(aMutations, aObserver) {
- this.onMutation(aMutations, aObserver);
- }).bind(this));
- this.observer.observe(this.box, {
- childList : true,
- attributes : true,
- subtree : true,
- attributeFilter : [
- 'hidden',
- 'collapsed',
- 'moz-collapsed', // Used in full screen mode
- 'disablechrome'
- ]
- });
- },
- onMutation : function BrowserUIShowHideObserver_onMutation(aMutations, aObserver)
- {
- aMutations.forEach(function(aMutation) {
- switch (aMutation.type)
- {
- case 'childList':
- if (aMutation.target == this.box)
- this.owner.browser.treeStyleTab.updateFloatingTabbar(TreeStyleTabConstants.kTABBAR_UPDATE_BY_WINDOW_RESIZE);
- return;
-
- case 'attributes':
- this.onAttributeModified(aMutation, aObserver);
- return;
- }
- }, this);
- },
-
- destroy : function BrowserUIShowHideObserver_destroy()
- {
- if (this.observer) {
- this.observer.disconnect();
- delete this.observer;
- }
- delete this.box;
- delete this.owner;
- },
-
- onAttributeModified : function BrowserUIShowHideObserver_onAttributeModified(aMutation, aObserver)
- {
- if (this.handlingAttrChange)
- return;
-
- var TST = this.owner.browser.treeStyleTab;
- if (
- // I must ignore show/hide of elements managed by TST,
- // to avoid infinity loop.
- aMutation.target.hasAttribute(TreeStyleTabConstants.kTAB_STRIP_ELEMENT) &&
- // However, I have to synchronize visibility of the real
- // tab bar and the placeholder's one. If they have
- // different visibility, then the tab bar is shown or
- // hidden by "auto hide tab bar" feature of someone
- // (Pale Moon, Tab Mix Plus, etc.)
- this.owner.browser.tabContainer.visible != TST.tabStripPlaceHolder.collapsed
- )
- return;
-
- this.handlingAttrChange = true;
-
- TST.updateFloatingTabbar(TreeStyleTabConstants.kTABBAR_UPDATE_BY_WINDOW_RESIZE);
-
- var w = this.box.ownerDocument.defaultView;
- w.setTimeout((function() {
- this.handlingAttrChange = false;
- }).bind(this), 10);
- }
-};
+/* ***** 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 YUKI "Piro" Hiroshi.
+ * Portions created by the Initial Developer are Copyright (C) 2013
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s): YUKI "Piro" Hiroshi
+ * Infocatcher
+ *
+ * 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 ******/
+
+const EXPORTED_SYMBOLS = ['BrowserUIShowHideObserver'];
+
+Components.utils.import('resource://treestyletab-modules/constants.js');
+
+function BrowserUIShowHideObserver(aOwner, aBox) {
+ this.owner = aOwner;
+ this.box = aBox;
+ this.init();
+}
+BrowserUIShowHideObserver.prototype = {
+ get MutationObserver()
+ {
+ var w = this.box.ownerDocument.defaultView;
+ return w.MutationObserver || w.MozMutationObserver;
+ },
+
+ init : function BrowserUIShowHideObserver_onInit()
+ {
+ if (!this.MutationObserver)
+ return;
+ this.observer = new this.MutationObserver((function(aMutations, aObserver) {
+ this.onMutation(aMutations, aObserver);
+ }).bind(this));
+ this.observer.observe(this.box, {
+ childList : true,
+ attributes : true,
+ subtree : true,
+ attributeFilter : [
+ 'hidden',
+ 'collapsed',
+ 'moz-collapsed', // Used in full screen mode
+ 'disablechrome'
+ ]
+ });
+ },
+ onMutation : function BrowserUIShowHideObserver_onMutation(aMutations, aObserver)
+ {
+ aMutations.forEach(function(aMutation) {
+ switch (aMutation.type)
+ {
+ case 'childList':
+ if (aMutation.target == this.box)
+ this.owner.browser.treeStyleTab.updateFloatingTabbar(TreeStyleTabConstants.kTABBAR_UPDATE_BY_WINDOW_RESIZE);
+ return;
+
+ case 'attributes':
+ this.onAttributeModified(aMutation, aObserver);
+ return;
+ }
+ }, this);
+ },
+
+ destroy : function BrowserUIShowHideObserver_destroy()
+ {
+ if (this.observer) {
+ this.observer.disconnect();
+ delete this.observer;
+ }
+ delete this.box;
+ delete this.owner;
+ },
+
+ onAttributeModified : function BrowserUIShowHideObserver_onAttributeModified(aMutation, aObserver)
+ {
+ if (this.handlingAttrChange)
+ return;
+
+ var TST = this.owner.browser.treeStyleTab;
+ if (
+ // I must ignore show/hide of elements managed by TST,
+ // to avoid infinity loop.
+ aMutation.target.hasAttribute(TreeStyleTabConstants.kTAB_STRIP_ELEMENT) &&
+ // However, I have to synchronize visibility of the real
+ // tab bar and the placeholder's one. If they have
+ // different visibility, then the tab bar is shown or
+ // hidden by "auto hide tab bar" feature of someone
+ // (Pale Moon, Tab Mix Plus, etc.)
+ this.owner.browser.tabContainer.visible != TST.tabStripPlaceHolder.collapsed
+ )
+ return;
+
+ this.handlingAttrChange = true;
+
+ TST.updateFloatingTabbar(TreeStyleTabConstants.kTABBAR_UPDATE_BY_WINDOW_RESIZE);
+
+ var w = this.box.ownerDocument.defaultView;
+ w.setTimeout((function() {
+ this.handlingAttrChange = false;
+ }).bind(this), 10);
+ }
+};
diff --git a/modules/constants.js b/modules/constants.js
index 0adb08bf..52317f59 100644
--- a/modules/constants.js
+++ b/modules/constants.js
@@ -1,206 +1,206 @@
-/* ***** 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 YUKI "Piro" Hiroshi.
- * Portions created by the Initial Developer are Copyright (C) 2010-2014
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s): YUKI "Piro" Hiroshi
- * Tetsuharu OHZEKI
- *
- * 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 ******/
-
-const EXPORTED_SYMBOLS = ['TreeStyleTabConstants'];
-
-const TreeStyleTabConstants = Object.freeze({
-/* attributes */
- kID : 'treestyletab-id',
- kCHILDREN : 'treestyletab-children',
- kPARENT : 'treestyletab-parent',
- kANCESTOR : 'treestyletab-ancestors',
- kNEST : 'treestyletab-nest',
- kINSERT_BEFORE : 'treestyletab-insert-before',
- kINSERT_AFTER : 'treestyletab-insert-after',
- kCLOSED_SET_ID : 'treestyletab-closed-set-id',
-
- kID_NEW : 'treestyletab-id-new',
- kID_RESTORING : 'treestyletab-id-restoring',
- kCHILDREN_RESTORING : 'treestyletab-children-restoring',
-
- kSUBTREE_COLLAPSED : 'treestyletab-subtree-collapsed',
- kSUBTREE_EXPANDED_MANUALLY : 'treestyletab-subtree-expanded-manually',
- kCOLLAPSED : 'treestyletab-collapsed',
- kCOLLAPSED_DONE : 'treestyletab-collapsed-done',
- kCOLLAPSING_PHASE : 'treestyletab-collapsing-phase',
- kCOLLAPSING_PHASE_TO_BE_COLLAPSED : 'collapse',
- kCOLLAPSING_PHASE_TO_BE_EXPANDED : 'expand',
- kALLOW_COLLAPSE : 'treestyletab-allow-subtree-collapse',
- kALLOW_STACK : 'treestyletab-stack-collapsed-tabs',
- kREMOVED : 'treestyletab-removed',
-
- kX_OFFSET : 'treestyletab-x-offset',
- kY_OFFSET : 'treestyletab-y-offset',
-
- kTABBAR_POSITION : 'treestyletab-tabbar-position',
- kMODE : 'treestyletab-mode',
-
- kHIDE_NEWTAB : 'treestyletab-hide-newtab-button',
- kSTYLE : 'treestyletab-style',
- kFIRSTTAB_BORDER : 'treestyletab-firsttab-border',
- kFIXED : 'treestyletab-tabbar-fixed',
- kRESIZING : 'treestyletab-tabbar-resizing',
- kINDENTED : 'treestyletab-tabs-indented',
- kMAX_LEVEL : 'treestyletab-max-tree-level',
- kPRINT_PREVIEW : 'treestyletab-print-preview',
- kANIMATION_ENABLED : 'treestyletab-animation-enabled',
- kINVERT_SCROLLBAR : 'treestyletab-invert-scrollbar',
- kNARROW_SCROLLBAR : 'treestyletab-narrow-scrollbar',
- kFAVICONIZED : 'treestyletab-faviconized',
- kBG_NOTIFY_PHASE : 'treestyletab-notifybgtab-phase',
- kIGNORE_POPUP_STATE : 'treestyletab-ignore-state',
- kDOM_FULLSCREEN_ACTIVATED : 'treestyletab-dom-fullscreen-activated',
-
- kTAB_INVERTED : 'treestyletab-tab-inverted',
- kTAB_CONTENTS_INVERTED : 'treestyletab-tab-contents-inverted',
- kCLOSEBOX_INVERTED : 'treestyletab-closebox-inverted',
-
- kTWISTY_HOVER : 'treestyletab-twisty-hover',
- kTWISTY_STYLE : 'treestyletab-twisty-style',
-
- kDROP_POSITION : 'treestyletab-drop-position',
- kDRAG_TYPE_TABBAR : 'application/x-moz-treestyletab-tabbrowser-tabbar',
- kDROP_POSITION_UNKNOWN : 'unknown',
- kTABBAR_MOVE_FORCE : 'force',
- kTABBAR_MOVE_NORMAL : 'normal',
-
- kTAB_STRIP_ELEMENT : 'treestyletab-tabstrip-element',
-
-/* classes */
- kTWISTY : 'treestyletab-twisty',
- kCOUNTER : 'treestyletab-counter',
- kCOUNTER_CONTAINER : 'treestyletab-counter-container',
- kCOUNTER_PAREN : 'treestyletab-counter-paren',
- kSPLITTER : 'treestyletab-splitter',
- kTABBAR_TOGGLER : 'treestyletab-tabbar-toggler',
- kTABBAR_PLACEHOLDER : 'treestyletab-tabbar-placeholder',
- kTABBAR_TOOLBAR : 'treestyletab-tabbar-toolbar',
- kTABBAR_TOOLBAR_READY : 'treestyletab-tabbar-toolbar-ready',
- kTABBAR_TOOLBAR_READY_POPUP : 'treestyletab-tabbar-toolbar-ready-popup',
-
-/* event types, topics */
- kEVENT_TYPE_TAB_FOCUS_SWITCHING_KEY_DOWN : 'nsDOMTreeStyleTabFocusSwitchingKeyDown',
- kEVENT_TYPE_TAB_FOCUS_SWITCHING_START : 'nsDOMTreeStyleTabFocusSwitchingStart',
- kEVENT_TYPE_TAB_FOCUS_SWITCHING_END : 'nsDOMTreeStyleTabFocusSwitchingEnd',
- kTAB_FOCUS_SWITCHING_SCROLL_DOWN : (1 << 0),
- kTAB_FOCUS_SWITCHING_SCROLL_UP : (1 << 1),
- kTAB_FOCUS_SWITCHING_STAND_BY : (1 << 2),
- kTAB_FOCUS_SWITCHING_ONLY_SHIFT_KEY : (1 << 3),
- kEVENT_TYPE_SUBTREE_CLOSING : 'nsDOMTreeStyleTabSubtreeClosing',
- kEVENT_TYPE_SUBTREE_CLOSED : 'nsDOMTreeStyleTabSubtreeClosed',
- kEVENT_TYPE_TAB_COLLAPSED_STATE_CHANGED : 'nsDOMTreeStyleTabCollapsedStateChange',
- kEVENT_TYPE_TABBAR_INITIALIZED : 'nsDOMTreeStyleTabTabbarInitialized',
- kEVENT_TYPE_TABBAR_POSITION_CHANGING : 'nsDOMTreeStyleTabTabbarPositionChanging',
- kEVENT_TYPE_TABBAR_POSITION_CHANGED : 'nsDOMTreeStyleTabTabbarPositionChanged',
- kEVENT_TYPE_TABBAR_STATE_CHANGING : 'nsDOMTreeStyleTabTabbarStateChanging',
- kEVENT_TYPE_TABBAR_STATE_CHANGED : 'nsDOMTreeStyleTabTabbarStateChanged',
- kEVENT_TYPE_FOCUS_NEXT_TAB : 'nsDOMTreeStyleTabFocusNextTab',
- kEVENT_TYPE_ATTACHED : 'nsDOMTreeStyleTabAttached',
- kEVENT_TYPE_DETACHED : 'nsDOMTreeStyleTabParted',
-
- kEVENT_TYPE_PRINT_PREVIEW_ENTERED : 'nsDOMTreeStyleTabPrintPreviewEntered',
- kEVENT_TYPE_PRINT_PREVIEW_EXITED : 'nsDOMTreeStyleTabPrintPreviewExited',
- kEVENT_TYPE_AUTO_HIDE_STATE_CHANGING : 'nsDOMTreeStyleTabAutoHideStateChanging',
- kEVENT_TYPE_AUTO_HIDE_STATE_CHANGE : 'nsDOMTreeStyleTabAutoHideStateChange',
-
- kTOPIC_INDENT_MODIFIED : 'TreeStyleTab:indentModified',
- kTOPIC_COLLAPSE_EXPAND_ALL : 'TreeStyleTab:collapseExpandAllSubtree',
- kTOPIC_CHANGE_TREEVIEW_AVAILABILITY : 'TreeStyleTab:changeTreeViewAvailability',
-
-/* other constant values */
- kFOCUS_ALL : 0,
- kFOCUS_VISIBLE : 1,
-
- kDROP_BEFORE : -1,
- kDROP_ON : 0,
- kDROP_AFTER : 1,
-
- kACTION_MOVE : 1 << 0,
- kACTION_STAY : 1 << 1,
- kACTION_DUPLICATE : 1 << 2,
- kACTION_IMPORT : 1 << 3,
- kACTION_NEWTAB : 1 << 4,
- kACTION_ATTACH : 1 << 10,
- kACTION_PART : 1 << 11,
- kACTIONS_FOR_SOURCE : (1 << 0) | (1 << 1),
- kACTIONS_FOR_DESTINATION : (1 << 2) | (1 << 3),
-
- kTABBAR_TOP : 1 << 0,
- kTABBAR_BOTTOM : 1 << 1,
- kTABBAR_LEFT : 1 << 2,
- kTABBAR_RIGHT : 1 << 3,
-
- kTABBAR_HORIZONTAL : (1 << 0) | (1 << 1),
- kTABBAR_VERTICAL : (1 << 2) | (1 << 3),
- kTABBAR_REGULAR : (1 << 0) | (1 << 2),
- kTABBAR_INVERTED : (1 << 3) | (1 << 4),
-
- kINSERT_FISRT : 0,
- kINSERT_LAST : 1,
-
- kTABBAR_UPDATE_BY_UNKNOWN_REASON : (1 << 0),
- kTABBAR_UPDATE_BY_RESET : (1 << 1),
- kTABBAR_UPDATE_BY_PREF_CHANGE : (1 << 2),
- kTABBAR_UPDATE_BY_APPEARANCE_CHANGE : (1 << 3),
- kTABBAR_UPDATE_BY_SHOWHIDE_TABBAR : (1 << 4),
- kTABBAR_UPDATE_BY_TABBAR_RESIZE : (1 << 5),
- kTABBAR_UPDATE_BY_WINDOW_RESIZE : (1 << 6),
- kTABBAR_UPDATE_BY_FULLSCREEN : (1 << 7),
- kTABBAR_UPDATE_BY_AUTOHIDE : (1 << 9),
- kTABBAR_UPDATE_BY_INITIALIZE : (1 << 10),
- kTABBAR_UPDATE_BY_TOGGLE_SIDEBAR : (1 << 11),
- kTABBAR_UPDATE_NOW : (1 << 5) | (1 << 6) | (1 << 9) | (1 << 10),
- kTABBAR_UPDATE_SYNC_TO_TABBAR : (1 << 0) | (1 << 1) | (1 << 2) | (1 << 5) | (1 << 9),
- kTABBAR_UPDATE_SYNC_TO_PLACEHOLDER : (1 << 3) | (1 << 4) | (1 << 6) | (1 << 7) | (1 << 10) | (1 << 11),
-
- kCLOSE_PARENT_BEHAVIOR_PROMOTE_FIRST_CHILD : 3,
- kCLOSE_PARENT_BEHAVIOR_PROMOTE_ALL_CHILDREN : 0,
- kCLOSE_PARENT_BEHAVIOR_DETACH_ALL_CHILDREN : 1,
- kCLOSE_PARENT_BEHAVIOR_SIMPLY_DETACH_ALL_CHILDREN : 4,
- kCLOSE_PARENT_BEHAVIOR_CLOSE_ALL_CHILDREN : 2, // onTabRemoved only
-
- kRESTORE_TREE_LEVEL_NONE : 0,
- kRESTORE_TREE_ONLY_VISIBLE : 1,
- kRESTORE_TREE_ALL : 2,
-
- kCOUNTER_ROLE_ALL_TABS : 1,
- kCOUNTER_ROLE_CONTAINED_TABS : 2,
-
- MAX_TABBAR_SIZE_RATIO : 0.8,
- DEFAULT_SHRUNKEN_WIDTH_RATIO : 0.67,
- MIN_TABBAR_WIDTH : 24,
- MIN_TABBAR_HEIGHT : 24
-});
+/* ***** 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 YUKI "Piro" Hiroshi.
+ * Portions created by the Initial Developer are Copyright (C) 2010-2014
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s): YUKI "Piro" Hiroshi
+ * Tetsuharu OHZEKI
+ *
+ * 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 ******/
+
+const EXPORTED_SYMBOLS = ['TreeStyleTabConstants'];
+
+const TreeStyleTabConstants = Object.freeze({
+/* attributes */
+ kID : 'treestyletab-id',
+ kCHILDREN : 'treestyletab-children',
+ kPARENT : 'treestyletab-parent',
+ kANCESTOR : 'treestyletab-ancestors',
+ kNEST : 'treestyletab-nest',
+ kINSERT_BEFORE : 'treestyletab-insert-before',
+ kINSERT_AFTER : 'treestyletab-insert-after',
+ kCLOSED_SET_ID : 'treestyletab-closed-set-id',
+
+ kID_NEW : 'treestyletab-id-new',
+ kID_RESTORING : 'treestyletab-id-restoring',
+ kCHILDREN_RESTORING : 'treestyletab-children-restoring',
+
+ kSUBTREE_COLLAPSED : 'treestyletab-subtree-collapsed',
+ kSUBTREE_EXPANDED_MANUALLY : 'treestyletab-subtree-expanded-manually',
+ kCOLLAPSED : 'treestyletab-collapsed',
+ kCOLLAPSED_DONE : 'treestyletab-collapsed-done',
+ kCOLLAPSING_PHASE : 'treestyletab-collapsing-phase',
+ kCOLLAPSING_PHASE_TO_BE_COLLAPSED : 'collapse',
+ kCOLLAPSING_PHASE_TO_BE_EXPANDED : 'expand',
+ kALLOW_COLLAPSE : 'treestyletab-allow-subtree-collapse',
+ kALLOW_STACK : 'treestyletab-stack-collapsed-tabs',
+ kREMOVED : 'treestyletab-removed',
+
+ kX_OFFSET : 'treestyletab-x-offset',
+ kY_OFFSET : 'treestyletab-y-offset',
+
+ kTABBAR_POSITION : 'treestyletab-tabbar-position',
+ kMODE : 'treestyletab-mode',
+
+ kHIDE_NEWTAB : 'treestyletab-hide-newtab-button',
+ kSTYLE : 'treestyletab-style',
+ kFIRSTTAB_BORDER : 'treestyletab-firsttab-border',
+ kFIXED : 'treestyletab-tabbar-fixed',
+ kRESIZING : 'treestyletab-tabbar-resizing',
+ kINDENTED : 'treestyletab-tabs-indented',
+ kMAX_LEVEL : 'treestyletab-max-tree-level',
+ kPRINT_PREVIEW : 'treestyletab-print-preview',
+ kANIMATION_ENABLED : 'treestyletab-animation-enabled',
+ kINVERT_SCROLLBAR : 'treestyletab-invert-scrollbar',
+ kNARROW_SCROLLBAR : 'treestyletab-narrow-scrollbar',
+ kFAVICONIZED : 'treestyletab-faviconized',
+ kBG_NOTIFY_PHASE : 'treestyletab-notifybgtab-phase',
+ kIGNORE_POPUP_STATE : 'treestyletab-ignore-state',
+ kDOM_FULLSCREEN_ACTIVATED : 'treestyletab-dom-fullscreen-activated',
+
+ kTAB_INVERTED : 'treestyletab-tab-inverted',
+ kTAB_CONTENTS_INVERTED : 'treestyletab-tab-contents-inverted',
+ kCLOSEBOX_INVERTED : 'treestyletab-closebox-inverted',
+
+ kTWISTY_HOVER : 'treestyletab-twisty-hover',
+ kTWISTY_STYLE : 'treestyletab-twisty-style',
+
+ kDROP_POSITION : 'treestyletab-drop-position',
+ kDRAG_TYPE_TABBAR : 'application/x-moz-treestyletab-tabbrowser-tabbar',
+ kDROP_POSITION_UNKNOWN : 'unknown',
+ kTABBAR_MOVE_FORCE : 'force',
+ kTABBAR_MOVE_NORMAL : 'normal',
+
+ kTAB_STRIP_ELEMENT : 'treestyletab-tabstrip-element',
+
+/* classes */
+ kTWISTY : 'treestyletab-twisty',
+ kCOUNTER : 'treestyletab-counter',
+ kCOUNTER_CONTAINER : 'treestyletab-counter-container',
+ kCOUNTER_PAREN : 'treestyletab-counter-paren',
+ kSPLITTER : 'treestyletab-splitter',
+ kTABBAR_TOGGLER : 'treestyletab-tabbar-toggler',
+ kTABBAR_PLACEHOLDER : 'treestyletab-tabbar-placeholder',
+ kTABBAR_TOOLBAR : 'treestyletab-tabbar-toolbar',
+ kTABBAR_TOOLBAR_READY : 'treestyletab-tabbar-toolbar-ready',
+ kTABBAR_TOOLBAR_READY_POPUP : 'treestyletab-tabbar-toolbar-ready-popup',
+
+/* event types, topics */
+ kEVENT_TYPE_TAB_FOCUS_SWITCHING_KEY_DOWN : 'nsDOMTreeStyleTabFocusSwitchingKeyDown',
+ kEVENT_TYPE_TAB_FOCUS_SWITCHING_START : 'nsDOMTreeStyleTabFocusSwitchingStart',
+ kEVENT_TYPE_TAB_FOCUS_SWITCHING_END : 'nsDOMTreeStyleTabFocusSwitchingEnd',
+ kTAB_FOCUS_SWITCHING_SCROLL_DOWN : (1 << 0),
+ kTAB_FOCUS_SWITCHING_SCROLL_UP : (1 << 1),
+ kTAB_FOCUS_SWITCHING_STAND_BY : (1 << 2),
+ kTAB_FOCUS_SWITCHING_ONLY_SHIFT_KEY : (1 << 3),
+ kEVENT_TYPE_SUBTREE_CLOSING : 'nsDOMTreeStyleTabSubtreeClosing',
+ kEVENT_TYPE_SUBTREE_CLOSED : 'nsDOMTreeStyleTabSubtreeClosed',
+ kEVENT_TYPE_TAB_COLLAPSED_STATE_CHANGED : 'nsDOMTreeStyleTabCollapsedStateChange',
+ kEVENT_TYPE_TABBAR_INITIALIZED : 'nsDOMTreeStyleTabTabbarInitialized',
+ kEVENT_TYPE_TABBAR_POSITION_CHANGING : 'nsDOMTreeStyleTabTabbarPositionChanging',
+ kEVENT_TYPE_TABBAR_POSITION_CHANGED : 'nsDOMTreeStyleTabTabbarPositionChanged',
+ kEVENT_TYPE_TABBAR_STATE_CHANGING : 'nsDOMTreeStyleTabTabbarStateChanging',
+ kEVENT_TYPE_TABBAR_STATE_CHANGED : 'nsDOMTreeStyleTabTabbarStateChanged',
+ kEVENT_TYPE_FOCUS_NEXT_TAB : 'nsDOMTreeStyleTabFocusNextTab',
+ kEVENT_TYPE_ATTACHED : 'nsDOMTreeStyleTabAttached',
+ kEVENT_TYPE_DETACHED : 'nsDOMTreeStyleTabParted',
+
+ kEVENT_TYPE_PRINT_PREVIEW_ENTERED : 'nsDOMTreeStyleTabPrintPreviewEntered',
+ kEVENT_TYPE_PRINT_PREVIEW_EXITED : 'nsDOMTreeStyleTabPrintPreviewExited',
+ kEVENT_TYPE_AUTO_HIDE_STATE_CHANGING : 'nsDOMTreeStyleTabAutoHideStateChanging',
+ kEVENT_TYPE_AUTO_HIDE_STATE_CHANGE : 'nsDOMTreeStyleTabAutoHideStateChange',
+
+ kTOPIC_INDENT_MODIFIED : 'TreeStyleTab:indentModified',
+ kTOPIC_COLLAPSE_EXPAND_ALL : 'TreeStyleTab:collapseExpandAllSubtree',
+ kTOPIC_CHANGE_TREEVIEW_AVAILABILITY : 'TreeStyleTab:changeTreeViewAvailability',
+
+/* other constant values */
+ kFOCUS_ALL : 0,
+ kFOCUS_VISIBLE : 1,
+
+ kDROP_BEFORE : -1,
+ kDROP_ON : 0,
+ kDROP_AFTER : 1,
+
+ kACTION_MOVE : 1 << 0,
+ kACTION_STAY : 1 << 1,
+ kACTION_DUPLICATE : 1 << 2,
+ kACTION_IMPORT : 1 << 3,
+ kACTION_NEWTAB : 1 << 4,
+ kACTION_ATTACH : 1 << 10,
+ kACTION_PART : 1 << 11,
+ kACTIONS_FOR_SOURCE : (1 << 0) | (1 << 1),
+ kACTIONS_FOR_DESTINATION : (1 << 2) | (1 << 3),
+
+ kTABBAR_TOP : 1 << 0,
+ kTABBAR_BOTTOM : 1 << 1,
+ kTABBAR_LEFT : 1 << 2,
+ kTABBAR_RIGHT : 1 << 3,
+
+ kTABBAR_HORIZONTAL : (1 << 0) | (1 << 1),
+ kTABBAR_VERTICAL : (1 << 2) | (1 << 3),
+ kTABBAR_REGULAR : (1 << 0) | (1 << 2),
+ kTABBAR_INVERTED : (1 << 3) | (1 << 4),
+
+ kINSERT_FISRT : 0,
+ kINSERT_LAST : 1,
+
+ kTABBAR_UPDATE_BY_UNKNOWN_REASON : (1 << 0),
+ kTABBAR_UPDATE_BY_RESET : (1 << 1),
+ kTABBAR_UPDATE_BY_PREF_CHANGE : (1 << 2),
+ kTABBAR_UPDATE_BY_APPEARANCE_CHANGE : (1 << 3),
+ kTABBAR_UPDATE_BY_SHOWHIDE_TABBAR : (1 << 4),
+ kTABBAR_UPDATE_BY_TABBAR_RESIZE : (1 << 5),
+ kTABBAR_UPDATE_BY_WINDOW_RESIZE : (1 << 6),
+ kTABBAR_UPDATE_BY_FULLSCREEN : (1 << 7),
+ kTABBAR_UPDATE_BY_AUTOHIDE : (1 << 9),
+ kTABBAR_UPDATE_BY_INITIALIZE : (1 << 10),
+ kTABBAR_UPDATE_BY_TOGGLE_SIDEBAR : (1 << 11),
+ kTABBAR_UPDATE_NOW : (1 << 5) | (1 << 6) | (1 << 9) | (1 << 10),
+ kTABBAR_UPDATE_SYNC_TO_TABBAR : (1 << 0) | (1 << 1) | (1 << 2) | (1 << 5) | (1 << 9),
+ kTABBAR_UPDATE_SYNC_TO_PLACEHOLDER : (1 << 3) | (1 << 4) | (1 << 6) | (1 << 7) | (1 << 10) | (1 << 11),
+
+ kCLOSE_PARENT_BEHAVIOR_PROMOTE_FIRST_CHILD : 3,
+ kCLOSE_PARENT_BEHAVIOR_PROMOTE_ALL_CHILDREN : 0,
+ kCLOSE_PARENT_BEHAVIOR_DETACH_ALL_CHILDREN : 1,
+ kCLOSE_PARENT_BEHAVIOR_SIMPLY_DETACH_ALL_CHILDREN : 4,
+ kCLOSE_PARENT_BEHAVIOR_CLOSE_ALL_CHILDREN : 2, // onTabRemoved only
+
+ kRESTORE_TREE_LEVEL_NONE : 0,
+ kRESTORE_TREE_ONLY_VISIBLE : 1,
+ kRESTORE_TREE_ALL : 2,
+
+ kCOUNTER_ROLE_ALL_TABS : 1,
+ kCOUNTER_ROLE_CONTAINED_TABS : 2,
+
+ MAX_TABBAR_SIZE_RATIO : 0.8,
+ DEFAULT_SHRUNKEN_WIDTH_RATIO : 0.67,
+ MIN_TABBAR_WIDTH : 24,
+ MIN_TABBAR_HEIGHT : 24
+});
diff --git a/modules/fullTooltip.js b/modules/fullTooltip.js
index 1dbdd9c7..0707b754 100644
--- a/modules/fullTooltip.js
+++ b/modules/fullTooltip.js
@@ -1,480 +1,480 @@
-/* ***** 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 YUKI "Piro" Hiroshi.
- * Portions created by the Initial Developer are Copyright (C) 2011-2014
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s): YUKI "Piro" Hiroshi
- * Tetsuharu OHZEKI
- *
- * 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 ******/
-
-const EXPORTED_SYMBOLS = ['FullTooltipManager'];
-
-const Cc = Components.classes;
-const Ci = Components.interfaces;
-
-Components.utils.import('resource://gre/modules/XPCOMUtils.jsm');
-
-Components.utils.import('resource://treestyletab-modules/lib/inherit.jsm');
-Components.utils.import('resource://treestyletab-modules/base.js');
-Components.utils.import('resource://treestyletab-modules/pseudoTreeBuilder.js');
-
-XPCOMUtils.defineLazyModuleGetter(this, 'utils', 'resource://treestyletab-modules/utils.js', 'TreeStyleTabUtils');
-
-XPCOMUtils.defineLazyServiceGetter(this, 'ScreenManager',
- '@mozilla.org/gfx/screenmanager;1', 'nsIScreenManager');
-
-function FullTooltipManager(aOwner)
-{
- this.init(aOwner);
-}
-FullTooltipManager.prototype = inherit(TreeStyleTabBase, {
-
- kTOOLTIP_MODE_DEFAULT : 0,
- kTOOLTIP_MODE_COLLAPSED : 1,
- kTOOLTIP_MODE_ALWAYS : 2,
-
- get window()
- {
- return this.owner.window;
- },
-
- get document()
- {
- return this.owner.document;
- },
-
- get tabTooltip()
- {
- return this.document.getElementById('tabbrowser-tab-tooltip');
- },
-
- get tabFullTooltip()
- {
- return this.document.getElementById('treestyletab-full-tree-tooltip');
- },
-
-
- init : function FTM_init(aOwner)
- {
- this.owner = aOwner;
-
- this.tabTooltip.addEventListener('popupshowing', this, true);
- this.tabTooltip.addEventListener('popuphiding', this, true);
-
- this.tabFullTooltip.addEventListener('click', this, false);
- this.tabFullTooltip.addEventListener(PseudoTreeBuilder.kTAB_LINK_CLICK, this, true);
- this.tabFullTooltip.addEventListener('popupshown', this, true);
- this.tabFullTooltip.addEventListener('popuphidden', this, true);
- },
-
- destroy : function FTM_destroy()
- {
- this.cancel();
- this.stopListenTooltipEvents();
-
- this.tabTooltip.removeEventListener('popupshowing', this, true);
- this.tabTooltip.removeEventListener('popuphiding', this, true);
-
- this.tabFullTooltip.removeEventListener('click', this, false);
- this.tabFullTooltip.removeEventListener(PseudoTreeBuilder.kTAB_LINK_CLICK, this, true);
- this.tabFullTooltip.removeEventListener('popupshown', this, true);
- this.tabFullTooltip.removeEventListener('popuphidden', this, true);
-
- delete this.owner;
- },
-
- handleEvent : function FTM_handleEvent(aEvent)
- {
- switch (aEvent.type)
- {
- case 'click':
- return this.onClick(aEvent);
-
- case PseudoTreeBuilder.kTAB_LINK_CLICK:
- return this.onItemClick(aEvent);
-
- case 'popupshowing':
- return this.onDefaultTooltipShowing(aEvent);
-
- case 'popuphiding':
- return this.onDefaultTooltipHiding(aEvent);
-
- case 'popupshown':
- return this.onShown(aEvent);
-
- case 'popuphidden':
- return this.onHidden(aEvent);
-
- case 'mousemove':
- return this.onTooltipMouseMove(aEvent);
-
- case 'mouseover':
- return this.cancelDelayedHide();
-
- case 'mouseout':
- return this.hideWithDelay();
-
- default:
- return this.onTooltipEvent(aEvent);
- }
- },
-
- getFullTooltipFromEvent : function FTM_getFullTooltipFromEvent(aEvent)
- {
- return this.evaluateXPath(
- 'ancestor-or-self::xul:tooltip[@id="'+this.tabFullTooltip.id+'"]',
- aEvent.target,
- Ci.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE
- ).singleNodeValue;
- },
-
- onClick : function FTM_onClick(aEvent)
- {
- this.tabFullTooltip.hidePopup();
- },
-
- onItemClick : function FTM_onItemClick(aEvent)
- {
- var id = aEvent.detail.id;
- if (id) {
- let tab = this.getTabById(id, this.owner.browser);
- if (tab) {
- let event = aEvent.detail.sourceEvent;
- if (event.button == 1 ||
- (event.button == 0 && this.isAccelKeyPressed(event)))
- this.owner.browser.removeTab(tab);
- else if (event.button != 2)
- this.owner.browser.selectedTab = tab;
- }
- }
- this.tabFullTooltip.hidePopup();
- },
-
- onDefaultTooltipShowing : function FTM_onDefaultTooltipShowing(aEvent)
- {
- this.cancel();
- this.handleDefaultTooltip(aEvent);
- },
-
- onDefaultTooltipHiding : function FTM_onDefaultTooltipHiding(aEvent)
- {
- this.cancel();
- },
-
- onShown : function FTM_onShown(aEvent)
- {
- this.startListenTooltipEvents();
-
- var tooltip = this.tabFullTooltip;
- tooltip.setAttribute('popup-shown', true);
-
- var w = {},
- h = {};
- var box = tooltip.boxObject;
- var scrollBoxObject = tooltip.firstChild.scrollBoxObject;
- scrollBoxObject.getScrolledSize(w, h);
- var currentW = box.width - scrollBoxObject.width + w.value;
- var currentH = box.height - scrollBoxObject.height + h.value;
- var currentX = box.screenX;
- var currentY = box.screenY;
-
- var currentScreen = Cc['@mozilla.org/gfx/screenmanager;1']
- .getService(Ci.nsIScreenManager)
- .screenForRect(box.screenX, box.screenY, box.width, box.height);
- var screenLeft = {},
- screenTop = {},
- screenWidth = {},
- screenHeight = {};
- currentScreen.GetRect(screenLeft, screenTop, screenWidth, screenHeight);
-
- var style = tooltip.style;
- style.maxWidth = screenWidth.value+'px';
- style.maxHeight = screenHeight.value+'px';
- style.minWidth = 0;
- style.minHeight = 0;
- if (currentX + currentW + screenLeft.value >= screenWidth.value)
- style.marginLeft = (Math.max(screenLeft.value, screenWidth.value - currentW) - this.window.screenX)+'px';
- if (currentY + currentH + screenTop.value >= screenHeight.value)
- style.marginTop = (Math.max(screenTop.value, screenHeight.value - currentH) - this.window.screenY)+'px';
- },
-
- onHidden : function FTM_onHidden(aEvent)
- {
- this.tabFullTooltip.removeAttribute('popup-shown');
- this.stopListenTooltipEvents();
- this.clear();
- },
-
- onTooltipMouseMove : function FTM_onTooltipMouseMove(aEvent)
- {
- if (this.getFullTooltipFromEvent(aEvent))
- this.cancelDelayedHide();
- else
- this.hideWithDelay();
- },
-
- onTooltipEvent : function FTM_onTooltipEvent(aEvent)
- {
- if (!this.getFullTooltipFromEvent(aEvent))
- this.hide();
- },
-
- startListenTooltipEvents : function FTM_startListenTooltipEvents()
- {
- if (this.listening)
- return;
- this.window.addEventListener('DOMMouseScroll', this, true);
- this.window.addEventListener('keydown', this, true);
- this.window.addEventListener('mousedown', this, true);
- this.window.addEventListener('mouseup', this, true);
- this.window.addEventListener('dragstart', this, true);
- this.window.addEventListener('mousemove', this, true);
- this.tabFullTooltip.addEventListener('mouseover', this, false);
- this.tabFullTooltip.addEventListener('mouseout', this, false);
- this.listening = true;
- },
-
- stopListenTooltipEvents : function FTM_stopListenTooltipEvents()
- {
- if (!this.listening)
- return;
- this.window.removeEventListener('DOMMouseScroll', this, true);
- this.window.removeEventListener('keydown', this, true);
- this.window.removeEventListener('mousedown', this, true);
- this.window.removeEventListener('mouseup', this, true);
- this.window.removeEventListener('dragstart', this, true);
- this.window.removeEventListener('mousemove', this, true);
- this.tabFullTooltip.removeEventListener('mouseover', this, false);
- this.tabFullTooltip.removeEventListener('mouseout', this, false);
- this.listening = false;
- },
-
-
- handleDefaultTooltip : function FTM_handleDefaultTooltip(aEvent)
- {
- var tab = this.getTabFromChild(this.document.tooltipNode);
- if (!tab || tab.localName != 'tab')
- return;
-
- var label;
- var collapsed = this.isSubtreeCollapsed(tab);
- var mode = utils.getTreePref('tooltip.mode');
-
- var base = parseInt(tab.getAttribute(this.kNEST) || 0);
- var descendant = this.getDescendantTabs(tab);
- var indentPart = ' ';
- var tree = null;
- var fullTooltipExtraLabel = '';
- if (mode > this.kTOOLTIP_MODE_DEFAULT &&
- descendant.length) {
- let tabs = [tab].concat(descendant);
- let tabsToBeListed = tabs.slice(0, Math.max(1, utils.getTreePref('tooltip.maxCount')));
- tree = tabsToBeListed
- .map(function(aTab) {
- let label = aTab.getAttribute('label');
- let indent = '';
- let nest = parseInt(aTab.getAttribute(this.kNEST) || 0) - base;
- for (let i = 0; i < nest; i++)
- {
- indent += indentPart;
- }
- return utils.treeBundle.getFormattedString('tooltip.item.label', [label, indent]);
- }, this)
- .join('\n');
- if (tabs.length != tabsToBeListed.length) {
- tree += '\n'+indentPart+utils.treeBundle.getFormattedString('tooltip.more', [tabs.length-tabsToBeListed.length]);
- }
- }
-
- var shouldShowTree = mode != this.kTOOLTIP_MODE_DEFAULT && (collapsed || mode == this.kTOOLTIP_MODE_ALWAYS);
- if ('mOverCloseButton' in tab && tab.mOverCloseButton) {
- if (descendant.length &&
- (collapsed || utils.getTreePref('closeParentBehavior') == this.kCLOSE_PARENT_BEHAVIOR_CLOSE_ALL_CHILDREN)) {
- label = tree || tab.getAttribute('label');
- label = label && shouldShowTree ?
- utils.treeBundle.getFormattedString('tooltip.closeTree.labeled', [label]) :
- utils.treeBundle.getString('tooltip.closeTree') ;
- fullTooltipExtraLabel = utils.treeBundle.getFormattedString('tooltip.closeTree.labeled', ['%TREE%']).split(/\s*%TREE%\s*/);
- }
- }
- else if (tab.getAttribute(this.kTWISTY_HOVER) == 'true') {
- let key = collapsed ?
- 'tooltip.expandSubtree' :
- 'tooltip.collapseSubtree' ;
- label = tree || tab.getAttribute('label');
- label = label && shouldShowTree ?
- utils.treeBundle.getFormattedString(key+'.labeled', [label]) :
- utils.treeBundle.getString(key) ;
- fullTooltipExtraLabel = utils.treeBundle.getFormattedString(key+'.labeled', ['%TREE%']).split(/\s*%TREE%\s*/);
- }
- else if (shouldShowTree) {
- label = tree;
- }
-
- if (!label)
- return;
-
- aEvent.target.setAttribute('label', label);
- aEvent.stopPropagation();
-
- if (shouldShowTree)
- this.setup(aEvent.target, tab, fullTooltipExtraLabel);
- },
-
-
- /**
- * If the window is maximized, screenX and screenY can be out of
- * visible screen rect. On the other hand,
- * nsIPopupBoxObject#openPopupAtScreen() automatically reposition
- * the popup if it is going to be shown out of the visible screen
- * rect. As the result, the popup will be repositioned unexpectedly
- * if I use the raw screenX and screenY.
- * https://github.com/piroor/treestyletab/issues/302
- * To prevent such a result, I have to calculate valid base position
- * for the popup.
- */
- get windowBasePosition() {
- var screen = ScreenManager.screenForRect(
- this.window.screenX,
- this.window.screenY,
- this.window.outerWidth,
- this.window.outerHeight
- );
- var screenMinX = {},
- screenMinY = {},
- screenMaxX = {},
- screenMaxY = {};
- screen.GetAvailRect(screenMinX, screenMinY, screenMaxX, screenMaxY);
-
- return {
- x: Math.max(this.window.screenX, screenMinX.value),
- y: Math.max(this.window.screenY, screenMinY.value)
- };
- },
-
- setup : function FTM_setup(aBaseTooltip, aTab, aExtraLabels)
- {
- this.cancel();
-
- var delay = utils.getTreePref('tooltip.fullTooltipDelay');
- if (delay < 0)
- return;
-
- this._fullTooltipTimer = this.window.setTimeout(function(aSelf) {
- var basePosition = aSelf.windowBasePosition;
- var box = aBaseTooltip.boxObject;
- var x = box.screenX - basePosition.x;
- var y = box.screenY - basePosition.y;
- var w = box.width;
- var h = box.height;
- aBaseTooltip.hidePopup();
-
- aSelf.fill(aTab, aExtraLabels);
-
- var tooltip = aSelf.tabFullTooltip;
- let (style = tooltip.style) {
- style.marginLeft = x+'px';
- style.marginTop = y+'px';
- style.maxWidth = style.minWidth = w+'px';
- style.maxHeight = style.minHeight = h+'px';
- }
- tooltip.openPopupAtScreen(basePosition.x, basePosition.y, false);
- }, Math.max(delay, 0), this);
- },
-
- cancel : function FTM_destroyFullTooltip()
- {
- if (this._fullTooltipTimer) {
- this.window.clearTimeout(this._fullTooltipTimer);
- this._fullTooltipTimer = null;
- }
- this.hide();
- },
-
- hide : function FTM_hide()
- {
- this.cancelDelayedHide();
- this.tabFullTooltip.hidePopup();
- },
-
-
- hideWithDelay : function FTM_hideWithDelay()
- {
- this.cancelDelayedHide();
- this._delayedHideTimer = this.window.setTimeout(function(aSelf) {
- aSelf.hide();
- }, 500, this);
- },
-
- cancelDelayedHide : function FTM_cancelDelayedHide()
- {
- if (this._delayedHideTimer) {
- this.window.clearTimeout(this._delayedHideTimer);
- this._delayedHideTimer = null;
- }
- },
-
-
- fill : function FTM_fill(aTab, aExtraLabels)
- {
- this.clear();
-
- var tree = PseudoTreeBuilder.build(aTab);
- var root = this.document.createElement('arrowscrollbox');
- root.setAttribute('orient', 'vertical');
- root.setAttribute('flex', 1);
-
- if (aExtraLabels) {
- if (typeof aExtraLabels == 'string')
- aExtraLabels = [aExtraLabels];
- for (let i = 0, maxi = aExtraLabels.length; i < maxi; i++)
- {
- let label = aExtraLabels[i];
- label = label.trim();
- if (!label)
- continue;
- root.appendChild(this.document.createElement('description'))
- .appendChild(this.document.createTextNode(label));
- }
- }
-
- root.insertBefore(tree, root.firstChild && root.firstChild.nextSibling);
-
- this.tabFullTooltip.appendChild(root);
- },
-
- clear : function FTM_clear()
- {
- var range = this.document.createRange();
- range.selectNodeContents(this.tabFullTooltip);
- range.deleteContents();
- range.detach();
- }
-});
+/* ***** 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 YUKI "Piro" Hiroshi.
+ * Portions created by the Initial Developer are Copyright (C) 2011-2014
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s): YUKI "Piro" Hiroshi
+ * Tetsuharu OHZEKI
+ *
+ * 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 ******/
+
+const EXPORTED_SYMBOLS = ['FullTooltipManager'];
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+
+Components.utils.import('resource://gre/modules/XPCOMUtils.jsm');
+
+Components.utils.import('resource://treestyletab-modules/lib/inherit.jsm');
+Components.utils.import('resource://treestyletab-modules/base.js');
+Components.utils.import('resource://treestyletab-modules/pseudoTreeBuilder.js');
+
+XPCOMUtils.defineLazyModuleGetter(this, 'utils', 'resource://treestyletab-modules/utils.js', 'TreeStyleTabUtils');
+
+XPCOMUtils.defineLazyServiceGetter(this, 'ScreenManager',
+ '@mozilla.org/gfx/screenmanager;1', 'nsIScreenManager');
+
+function FullTooltipManager(aOwner)
+{
+ this.init(aOwner);
+}
+FullTooltipManager.prototype = inherit(TreeStyleTabBase, {
+
+ kTOOLTIP_MODE_DEFAULT : 0,
+ kTOOLTIP_MODE_COLLAPSED : 1,
+ kTOOLTIP_MODE_ALWAYS : 2,
+
+ get window()
+ {
+ return this.owner.window;
+ },
+
+ get document()
+ {
+ return this.owner.document;
+ },
+
+ get tabTooltip()
+ {
+ return this.document.getElementById('tabbrowser-tab-tooltip');
+ },
+
+ get tabFullTooltip()
+ {
+ return this.document.getElementById('treestyletab-full-tree-tooltip');
+ },
+
+
+ init : function FTM_init(aOwner)
+ {
+ this.owner = aOwner;
+
+ this.tabTooltip.addEventListener('popupshowing', this, true);
+ this.tabTooltip.addEventListener('popuphiding', this, true);
+
+ this.tabFullTooltip.addEventListener('click', this, false);
+ this.tabFullTooltip.addEventListener(PseudoTreeBuilder.kTAB_LINK_CLICK, this, true);
+ this.tabFullTooltip.addEventListener('popupshown', this, true);
+ this.tabFullTooltip.addEventListener('popuphidden', this, true);
+ },
+
+ destroy : function FTM_destroy()
+ {
+ this.cancel();
+ this.stopListenTooltipEvents();
+
+ this.tabTooltip.removeEventListener('popupshowing', this, true);
+ this.tabTooltip.removeEventListener('popuphiding', this, true);
+
+ this.tabFullTooltip.removeEventListener('click', this, false);
+ this.tabFullTooltip.removeEventListener(PseudoTreeBuilder.kTAB_LINK_CLICK, this, true);
+ this.tabFullTooltip.removeEventListener('popupshown', this, true);
+ this.tabFullTooltip.removeEventListener('popuphidden', this, true);
+
+ delete this.owner;
+ },
+
+ handleEvent : function FTM_handleEvent(aEvent)
+ {
+ switch (aEvent.type)
+ {
+ case 'click':
+ return this.onClick(aEvent);
+
+ case PseudoTreeBuilder.kTAB_LINK_CLICK:
+ return this.onItemClick(aEvent);
+
+ case 'popupshowing':
+ return this.onDefaultTooltipShowing(aEvent);
+
+ case 'popuphiding':
+ return this.onDefaultTooltipHiding(aEvent);
+
+ case 'popupshown':
+ return this.onShown(aEvent);
+
+ case 'popuphidden':
+ return this.onHidden(aEvent);
+
+ case 'mousemove':
+ return this.onTooltipMouseMove(aEvent);
+
+ case 'mouseover':
+ return this.cancelDelayedHide();
+
+ case 'mouseout':
+ return this.hideWithDelay();
+
+ default:
+ return this.onTooltipEvent(aEvent);
+ }
+ },
+
+ getFullTooltipFromEvent : function FTM_getFullTooltipFromEvent(aEvent)
+ {
+ return this.evaluateXPath(
+ 'ancestor-or-self::xul:tooltip[@id="'+this.tabFullTooltip.id+'"]',
+ aEvent.target,
+ Ci.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE
+ ).singleNodeValue;
+ },
+
+ onClick : function FTM_onClick(aEvent)
+ {
+ this.tabFullTooltip.hidePopup();
+ },
+
+ onItemClick : function FTM_onItemClick(aEvent)
+ {
+ var id = aEvent.detail.id;
+ if (id) {
+ let tab = this.getTabById(id, this.owner.browser);
+ if (tab) {
+ let event = aEvent.detail.sourceEvent;
+ if (event.button == 1 ||
+ (event.button == 0 && this.isAccelKeyPressed(event)))
+ this.owner.browser.removeTab(tab);
+ else if (event.button != 2)
+ this.owner.browser.selectedTab = tab;
+ }
+ }
+ this.tabFullTooltip.hidePopup();
+ },
+
+ onDefaultTooltipShowing : function FTM_onDefaultTooltipShowing(aEvent)
+ {
+ this.cancel();
+ this.handleDefaultTooltip(aEvent);
+ },
+
+ onDefaultTooltipHiding : function FTM_onDefaultTooltipHiding(aEvent)
+ {
+ this.cancel();
+ },
+
+ onShown : function FTM_onShown(aEvent)
+ {
+ this.startListenTooltipEvents();
+
+ var tooltip = this.tabFullTooltip;
+ tooltip.setAttribute('popup-shown', true);
+
+ var w = {},
+ h = {};
+ var box = tooltip.boxObject;
+ var scrollBoxObject = tooltip.firstChild.scrollBoxObject;
+ scrollBoxObject.getScrolledSize(w, h);
+ var currentW = box.width - scrollBoxObject.width + w.value;
+ var currentH = box.height - scrollBoxObject.height + h.value;
+ var currentX = box.screenX;
+ var currentY = box.screenY;
+
+ var currentScreen = Cc['@mozilla.org/gfx/screenmanager;1']
+ .getService(Ci.nsIScreenManager)
+ .screenForRect(box.screenX, box.screenY, box.width, box.height);
+ var screenLeft = {},
+ screenTop = {},
+ screenWidth = {},
+ screenHeight = {};
+ currentScreen.GetRect(screenLeft, screenTop, screenWidth, screenHeight);
+
+ var style = tooltip.style;
+ style.maxWidth = screenWidth.value+'px';
+ style.maxHeight = screenHeight.value+'px';
+ style.minWidth = 0;
+ style.minHeight = 0;
+ if (currentX + currentW + screenLeft.value >= screenWidth.value)
+ style.marginLeft = (Math.max(screenLeft.value, screenWidth.value - currentW) - this.window.screenX)+'px';
+ if (currentY + currentH + screenTop.value >= screenHeight.value)
+ style.marginTop = (Math.max(screenTop.value, screenHeight.value - currentH) - this.window.screenY)+'px';
+ },
+
+ onHidden : function FTM_onHidden(aEvent)
+ {
+ this.tabFullTooltip.removeAttribute('popup-shown');
+ this.stopListenTooltipEvents();
+ this.clear();
+ },
+
+ onTooltipMouseMove : function FTM_onTooltipMouseMove(aEvent)
+ {
+ if (this.getFullTooltipFromEvent(aEvent))
+ this.cancelDelayedHide();
+ else
+ this.hideWithDelay();
+ },
+
+ onTooltipEvent : function FTM_onTooltipEvent(aEvent)
+ {
+ if (!this.getFullTooltipFromEvent(aEvent))
+ this.hide();
+ },
+
+ startListenTooltipEvents : function FTM_startListenTooltipEvents()
+ {
+ if (this.listening)
+ return;
+ this.window.addEventListener('DOMMouseScroll', this, true);
+ this.window.addEventListener('keydown', this, true);
+ this.window.addEventListener('mousedown', this, true);
+ this.window.addEventListener('mouseup', this, true);
+ this.window.addEventListener('dragstart', this, true);
+ this.window.addEventListener('mousemove', this, true);
+ this.tabFullTooltip.addEventListener('mouseover', this, false);
+ this.tabFullTooltip.addEventListener('mouseout', this, false);
+ this.listening = true;
+ },
+
+ stopListenTooltipEvents : function FTM_stopListenTooltipEvents()
+ {
+ if (!this.listening)
+ return;
+ this.window.removeEventListener('DOMMouseScroll', this, true);
+ this.window.removeEventListener('keydown', this, true);
+ this.window.removeEventListener('mousedown', this, true);
+ this.window.removeEventListener('mouseup', this, true);
+ this.window.removeEventListener('dragstart', this, true);
+ this.window.removeEventListener('mousemove', this, true);
+ this.tabFullTooltip.removeEventListener('mouseover', this, false);
+ this.tabFullTooltip.removeEventListener('mouseout', this, false);
+ this.listening = false;
+ },
+
+
+ handleDefaultTooltip : function FTM_handleDefaultTooltip(aEvent)
+ {
+ var tab = this.getTabFromChild(this.document.tooltipNode);
+ if (!tab || tab.localName != 'tab')
+ return;
+
+ var label;
+ var collapsed = this.isSubtreeCollapsed(tab);
+ var mode = utils.getTreePref('tooltip.mode');
+
+ var base = parseInt(tab.getAttribute(this.kNEST) || 0);
+ var descendant = this.getDescendantTabs(tab);
+ var indentPart = ' ';
+ var tree = null;
+ var fullTooltipExtraLabel = '';
+ if (mode > this.kTOOLTIP_MODE_DEFAULT &&
+ descendant.length) {
+ let tabs = [tab].concat(descendant);
+ let tabsToBeListed = tabs.slice(0, Math.max(1, utils.getTreePref('tooltip.maxCount')));
+ tree = tabsToBeListed
+ .map(function(aTab) {
+ let label = aTab.getAttribute('label');
+ let indent = '';
+ let nest = parseInt(aTab.getAttribute(this.kNEST) || 0) - base;
+ for (let i = 0; i < nest; i++)
+ {
+ indent += indentPart;
+ }
+ return utils.treeBundle.getFormattedString('tooltip.item.label', [label, indent]);
+ }, this)
+ .join('\n');
+ if (tabs.length != tabsToBeListed.length) {
+ tree += '\n'+indentPart+utils.treeBundle.getFormattedString('tooltip.more', [tabs.length-tabsToBeListed.length]);
+ }
+ }
+
+ var shouldShowTree = mode != this.kTOOLTIP_MODE_DEFAULT && (collapsed || mode == this.kTOOLTIP_MODE_ALWAYS);
+ if ('mOverCloseButton' in tab && tab.mOverCloseButton) {
+ if (descendant.length &&
+ (collapsed || utils.getTreePref('closeParentBehavior') == this.kCLOSE_PARENT_BEHAVIOR_CLOSE_ALL_CHILDREN)) {
+ label = tree || tab.getAttribute('label');
+ label = label && shouldShowTree ?
+ utils.treeBundle.getFormattedString('tooltip.closeTree.labeled', [label]) :
+ utils.treeBundle.getString('tooltip.closeTree') ;
+ fullTooltipExtraLabel = utils.treeBundle.getFormattedString('tooltip.closeTree.labeled', ['%TREE%']).split(/\s*%TREE%\s*/);
+ }
+ }
+ else if (tab.getAttribute(this.kTWISTY_HOVER) == 'true') {
+ let key = collapsed ?
+ 'tooltip.expandSubtree' :
+ 'tooltip.collapseSubtree' ;
+ label = tree || tab.getAttribute('label');
+ label = label && shouldShowTree ?
+ utils.treeBundle.getFormattedString(key+'.labeled', [label]) :
+ utils.treeBundle.getString(key) ;
+ fullTooltipExtraLabel = utils.treeBundle.getFormattedString(key+'.labeled', ['%TREE%']).split(/\s*%TREE%\s*/);
+ }
+ else if (shouldShowTree) {
+ label = tree;
+ }
+
+ if (!label)
+ return;
+
+ aEvent.target.setAttribute('label', label);
+ aEvent.stopPropagation();
+
+ if (shouldShowTree)
+ this.setup(aEvent.target, tab, fullTooltipExtraLabel);
+ },
+
+
+ /**
+ * If the window is maximized, screenX and screenY can be out of
+ * visible screen rect. On the other hand,
+ * nsIPopupBoxObject#openPopupAtScreen() automatically reposition
+ * the popup if it is going to be shown out of the visible screen
+ * rect. As the result, the popup will be repositioned unexpectedly
+ * if I use the raw screenX and screenY.
+ * https://github.com/piroor/treestyletab/issues/302
+ * To prevent such a result, I have to calculate valid base position
+ * for the popup.
+ */
+ get windowBasePosition() {
+ var screen = ScreenManager.screenForRect(
+ this.window.screenX,
+ this.window.screenY,
+ this.window.outerWidth,
+ this.window.outerHeight
+ );
+ var screenMinX = {},
+ screenMinY = {},
+ screenMaxX = {},
+ screenMaxY = {};
+ screen.GetAvailRect(screenMinX, screenMinY, screenMaxX, screenMaxY);
+
+ return {
+ x: Math.max(this.window.screenX, screenMinX.value),
+ y: Math.max(this.window.screenY, screenMinY.value)
+ };
+ },
+
+ setup : function FTM_setup(aBaseTooltip, aTab, aExtraLabels)
+ {
+ this.cancel();
+
+ var delay = utils.getTreePref('tooltip.fullTooltipDelay');
+ if (delay < 0)
+ return;
+
+ this._fullTooltipTimer = this.window.setTimeout(function(aSelf) {
+ var basePosition = aSelf.windowBasePosition;
+ var box = aBaseTooltip.boxObject;
+ var x = box.screenX - basePosition.x;
+ var y = box.screenY - basePosition.y;
+ var w = box.width;
+ var h = box.height;
+ aBaseTooltip.hidePopup();
+
+ aSelf.fill(aTab, aExtraLabels);
+
+ var tooltip = aSelf.tabFullTooltip;
+ let (style = tooltip.style) {
+ style.marginLeft = x+'px';
+ style.marginTop = y+'px';
+ style.maxWidth = style.minWidth = w+'px';
+ style.maxHeight = style.minHeight = h+'px';
+ }
+ tooltip.openPopupAtScreen(basePosition.x, basePosition.y, false);
+ }, Math.max(delay, 0), this);
+ },
+
+ cancel : function FTM_destroyFullTooltip()
+ {
+ if (this._fullTooltipTimer) {
+ this.window.clearTimeout(this._fullTooltipTimer);
+ this._fullTooltipTimer = null;
+ }
+ this.hide();
+ },
+
+ hide : function FTM_hide()
+ {
+ this.cancelDelayedHide();
+ this.tabFullTooltip.hidePopup();
+ },
+
+
+ hideWithDelay : function FTM_hideWithDelay()
+ {
+ this.cancelDelayedHide();
+ this._delayedHideTimer = this.window.setTimeout(function(aSelf) {
+ aSelf.hide();
+ }, 500, this);
+ },
+
+ cancelDelayedHide : function FTM_cancelDelayedHide()
+ {
+ if (this._delayedHideTimer) {
+ this.window.clearTimeout(this._delayedHideTimer);
+ this._delayedHideTimer = null;
+ }
+ },
+
+
+ fill : function FTM_fill(aTab, aExtraLabels)
+ {
+ this.clear();
+
+ var tree = PseudoTreeBuilder.build(aTab);
+ var root = this.document.createElement('arrowscrollbox');
+ root.setAttribute('orient', 'vertical');
+ root.setAttribute('flex', 1);
+
+ if (aExtraLabels) {
+ if (typeof aExtraLabels == 'string')
+ aExtraLabels = [aExtraLabels];
+ for (let i = 0, maxi = aExtraLabels.length; i < maxi; i++)
+ {
+ let label = aExtraLabels[i];
+ label = label.trim();
+ if (!label)
+ continue;
+ root.appendChild(this.document.createElement('description'))
+ .appendChild(this.document.createTextNode(label));
+ }
+ }
+
+ root.insertBefore(tree, root.firstChild && root.firstChild.nextSibling);
+
+ this.tabFullTooltip.appendChild(root);
+ },
+
+ clear : function FTM_clear()
+ {
+ var range = this.document.createRange();
+ range.selectNodeContents(this.tabFullTooltip);
+ range.deleteContents();
+ range.detach();
+ }
+});
diff --git a/modules/fullscreenObserver.js b/modules/fullscreenObserver.js
index f49a032b..368eb87d 100644
--- a/modules/fullscreenObserver.js
+++ b/modules/fullscreenObserver.js
@@ -1,109 +1,109 @@
-/* ***** 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 YUKI "Piro" Hiroshi.
- * Portions created by the Initial Developer are Copyright (C) 2013
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s): YUKI "Piro" Hiroshi
- *
- * 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 ******/
-
-const EXPORTED_SYMBOLS = ['FullscreenObserver'];
-
-Components.utils.import('resource://treestyletab-modules/utils.js');
-
-function FullscreenObserver(aWindow) {
- this.window = aWindow;
- this.init();
-}
-FullscreenObserver.prototype = {
- get MutationObserver()
- {
- var w = this.window;
- return w.MutationObserver || w.MozMutationObserver;
- },
-
- init : function FullscreenObserver_onInit()
- {
- if (!this.MutationObserver)
- return;
- this.observer = new this.MutationObserver((function(aMutations, aObserver) {
- this.onMutation(aMutations, aObserver);
- }).bind(this));
- this.observer.observe(this.window.document.documentElement, {
- attributes : true,
- attributeFilter : ['sizemode']
- });
-
- this.onSizeModeChange();
- },
-
- destroy : function FullscreenObserver_destroy()
- {
- if (this.observer) {
- this.observer.disconnect();
- delete this.observer;
- }
- delete this.window;
- },
-
- onMutation : function FullscreenObserver_onMutation(aMutations, aObserver)
- {
- this.window.setTimeout((function() {
- this.onSizeModeChange();
- }).bind(this), 10);
- },
-
- onSizeModeChange : function FullscreenObserver_onSizeModeChange()
- {
- var w = this.window;
- var d = w.document;
- if (d.documentElement.getAttribute('sizemode') != 'fullscreen')
- return;
-
- if (
- !w.FullScreen.useLionFullScreen && // see https://github.com/piroor/treestyletab/issues/645
- TreeStyleTabUtils.prefs.getPref('browser.fullscreen.autohide') // see https://github.com/piroor/treestyletab/issues/717
- ) {
- let toolbox = w.gNavToolbox;
- toolbox.style.marginTop = -toolbox.getBoundingClientRect().height + 'px';
- }
-
- var windowControls = d.getElementById('window-controls');
- var navigationToolbar = d.getElementById('nav-bar');
- if (!windowControls ||
- !navigationToolbar ||
- windowControls.parentNode == navigationToolbar ||
- (w.gBrowser.treeStyleTab.position == 'top' && w.gBrowser.treeStyleTab.fixed))
- return;
-
- // the location bar is flex=1, so we should not apply it.
- // windowControls.setAttribute('flex', '1');
- navigationToolbar.appendChild(windowControls);
- }
-};
+/* ***** 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 YUKI "Piro" Hiroshi.
+ * Portions created by the Initial Developer are Copyright (C) 2013
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s): YUKI "Piro" Hiroshi
+ *
+ * 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 ******/
+
+const EXPORTED_SYMBOLS = ['FullscreenObserver'];
+
+Components.utils.import('resource://treestyletab-modules/utils.js');
+
+function FullscreenObserver(aWindow) {
+ this.window = aWindow;
+ this.init();
+}
+FullscreenObserver.prototype = {
+ get MutationObserver()
+ {
+ var w = this.window;
+ return w.MutationObserver || w.MozMutationObserver;
+ },
+
+ init : function FullscreenObserver_onInit()
+ {
+ if (!this.MutationObserver)
+ return;
+ this.observer = new this.MutationObserver((function(aMutations, aObserver) {
+ this.onMutation(aMutations, aObserver);
+ }).bind(this));
+ this.observer.observe(this.window.document.documentElement, {
+ attributes : true,
+ attributeFilter : ['sizemode']
+ });
+
+ this.onSizeModeChange();
+ },
+
+ destroy : function FullscreenObserver_destroy()
+ {
+ if (this.observer) {
+ this.observer.disconnect();
+ delete this.observer;
+ }
+ delete this.window;
+ },
+
+ onMutation : function FullscreenObserver_onMutation(aMutations, aObserver)
+ {
+ this.window.setTimeout((function() {
+ this.onSizeModeChange();
+ }).bind(this), 10);
+ },
+
+ onSizeModeChange : function FullscreenObserver_onSizeModeChange()
+ {
+ var w = this.window;
+ var d = w.document;
+ if (d.documentElement.getAttribute('sizemode') != 'fullscreen')
+ return;
+
+ if (
+ !w.FullScreen.useLionFullScreen && // see https://github.com/piroor/treestyletab/issues/645
+ TreeStyleTabUtils.prefs.getPref('browser.fullscreen.autohide') // see https://github.com/piroor/treestyletab/issues/717
+ ) {
+ let toolbox = w.gNavToolbox;
+ toolbox.style.marginTop = -toolbox.getBoundingClientRect().height + 'px';
+ }
+
+ var windowControls = d.getElementById('window-controls');
+ var navigationToolbar = d.getElementById('nav-bar');
+ if (!windowControls ||
+ !navigationToolbar ||
+ windowControls.parentNode == navigationToolbar ||
+ (w.gBrowser.treeStyleTab.position == 'top' && w.gBrowser.treeStyleTab.fixed))
+ return;
+
+ // the location bar is flex=1, so we should not apply it.
+ // windowControls.setAttribute('flex', '1');
+ navigationToolbar.appendChild(windowControls);
+ }
+};
diff --git a/modules/pseudoTreeBuilder.js b/modules/pseudoTreeBuilder.js
index 89571c18..4e3b4e3f 100644
--- a/modules/pseudoTreeBuilder.js
+++ b/modules/pseudoTreeBuilder.js
@@ -1,142 +1,142 @@
-/* ***** 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 YUKI "Piro" Hiroshi.
- * Portions created by the Initial Developer are Copyright (C) 2011-2014
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s): YUKI "Piro" Hiroshi
- * Tetsuharu OHZEKI
- *
- * 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 ******/
-
-const EXPORTED_SYMBOLS = ['PseudoTreeBuilder'];
-
-const Cc = Components.classes;
-const Ci = Components.interfaces;
-
-Components.utils.import('resource://gre/modules/XPCOMUtils.jsm');
-
-XPCOMUtils.defineLazyModuleGetter(this, 'TreeStyleTabBase', 'resource://treestyletab-modules/base.js');
-
-var PseudoTreeBuilder = {
-
- kFAVICON : 'treestyletab-pseudo-tree-favicon',
- kROOTITEM : 'treestyletab-pseudo-tree-root-item',
- kTREEITEM : 'treestyletab-pseudo-tree-item',
- kTREEROW : 'treestyletab-pseudo-tree-row',
- kTREECHILDREN : 'treestyletab-pseudo-tree-children',
-
- kTAB_LINK_CLICK : 'nsDOMTSTPseudoTreeItemClick',
-
- build : function TB_build(aTab)
- {
- if (!aTab)
- return null;
-
- var tree = this.createTabItem(aTab);
-
- var row = tree.querySelector("."+this.kTREEROW);
- if (!row)
- return;
-
- row.className += " "+this.kROOTITEM;
-
- tree.setAttribute('onclick',
- ('var doc = event.target.ownerDocument;\n' +
- 'var label = doc.evaluate(\n' +
- ' "ancestor-or-self::*[local-name()=\'label\' and contains(@class, \'text-link\')][1]",\n' +
- ' event.target,\n' +
- ' null,\n' +
- ' Components.interfaces.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE,\n' +
- ' null\n' +
- ' ).singleNodeValue;\n' +
- 'if (label) {\n' +
- ' var customEvent = new doc.defaultView.CustomEvent(%EVENT_TYPE%, {\n' +
- ' bubbles : true,\n' +
- ' cancelable : true,\n' +
- ' detail : {\n' +
- ' id : label.getAttribute("tab-id"),\n' +
- ' sourceEvent : event\n' +
- ' }\n' +
- ' });\n' +
- ' event.target.dispatchEvent(customEvent);\n' +
- '}').replace('%EVENT_TYPE%', this.kTAB_LINK_CLICK.quote()));
-
- return tree;
- },
-
- createTabItem : function TB_createTabItem(aTab)
- {
- var doc = aTab.ownerDocument;
- var w = doc.defaultView;
-
- var item = doc.createElement('hbox');
- item.setAttribute('class', this.kTREEROW);
-
- var favicon = item.appendChild(doc.createElement('image'));
- favicon.setAttribute('src', aTab.getAttribute('image') || 'chrome://mozapps/skin/places/defaultFavicon.png');
- favicon.setAttribute('class', this.kFAVICON);
-
- var label = item.appendChild(doc.createElement('label'));
- label.setAttribute('value', aTab.label);
- var tooltip = aTab.label;
- var uri = aTab.linkedBrowser.currentURI.spec;
- if (w.isBlankPageURL ? !w.isBlankPageURL(uri) : (uri != 'about:blank')) tooltip += '\n' + uri;
- label.setAttribute('tooltiptext', tooltip);
- label.setAttribute('class', 'text-link '+this.kTREEITEM);
- label.setAttribute('tab-id', TreeStyleTabBase.getTabValue(aTab, TreeStyleTabBase.kID));
-
- var children = this.createTabChildren(aTab);
- if (children) {
- let container = doc.createElement('vbox');
- container.appendChild(item);
- container.appendChild(children);
- return container;
- }
- else {
- return item;
- }
- },
-
- createTabChildren : function TB_createTabChildren(aTab)
- {
- var doc = aTab.ownerDocument;
-
- var children = TreeStyleTabBase.getChildTabs(aTab);
- if (!children.length)
- return null;
-
- var container = doc.createElement('vbox');
- for (let i = 0, maxi = children.length; i < maxi; i++)
- {
- container.appendChild(this.createTabItem(children[i]));
- }
- container.setAttribute('class', this.kTREECHILDREN);
- return container;
- }
-};
+/* ***** 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 YUKI "Piro" Hiroshi.
+ * Portions created by the Initial Developer are Copyright (C) 2011-2014
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s): YUKI "Piro" Hiroshi
+ * Tetsuharu OHZEKI
+ *
+ * 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 ******/
+
+const EXPORTED_SYMBOLS = ['PseudoTreeBuilder'];
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+
+Components.utils.import('resource://gre/modules/XPCOMUtils.jsm');
+
+XPCOMUtils.defineLazyModuleGetter(this, 'TreeStyleTabBase', 'resource://treestyletab-modules/base.js');
+
+var PseudoTreeBuilder = {
+
+ kFAVICON : 'treestyletab-pseudo-tree-favicon',
+ kROOTITEM : 'treestyletab-pseudo-tree-root-item',
+ kTREEITEM : 'treestyletab-pseudo-tree-item',
+ kTREEROW : 'treestyletab-pseudo-tree-row',
+ kTREECHILDREN : 'treestyletab-pseudo-tree-children',
+
+ kTAB_LINK_CLICK : 'nsDOMTSTPseudoTreeItemClick',
+
+ build : function TB_build(aTab)
+ {
+ if (!aTab)
+ return null;
+
+ var tree = this.createTabItem(aTab);
+
+ var row = tree.querySelector("."+this.kTREEROW);
+ if (!row)
+ return;
+
+ row.className += " "+this.kROOTITEM;
+
+ tree.setAttribute('onclick',
+ ('var doc = event.target.ownerDocument;\n' +
+ 'var label = doc.evaluate(\n' +
+ ' "ancestor-or-self::*[local-name()=\'label\' and contains(@class, \'text-link\')][1]",\n' +
+ ' event.target,\n' +
+ ' null,\n' +
+ ' Components.interfaces.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE,\n' +
+ ' null\n' +
+ ' ).singleNodeValue;\n' +
+ 'if (label) {\n' +
+ ' var customEvent = new doc.defaultView.CustomEvent(%EVENT_TYPE%, {\n' +
+ ' bubbles : true,\n' +
+ ' cancelable : true,\n' +
+ ' detail : {\n' +
+ ' id : label.getAttribute("tab-id"),\n' +
+ ' sourceEvent : event\n' +
+ ' }\n' +
+ ' });\n' +
+ ' event.target.dispatchEvent(customEvent);\n' +
+ '}').replace('%EVENT_TYPE%', this.kTAB_LINK_CLICK.quote()));
+
+ return tree;
+ },
+
+ createTabItem : function TB_createTabItem(aTab)
+ {
+ var doc = aTab.ownerDocument;
+ var w = doc.defaultView;
+
+ var item = doc.createElement('hbox');
+ item.setAttribute('class', this.kTREEROW);
+
+ var favicon = item.appendChild(doc.createElement('image'));
+ favicon.setAttribute('src', aTab.getAttribute('image') || 'chrome://mozapps/skin/places/defaultFavicon.png');
+ favicon.setAttribute('class', this.kFAVICON);
+
+ var label = item.appendChild(doc.createElement('label'));
+ label.setAttribute('value', aTab.label);
+ var tooltip = aTab.label;
+ var uri = aTab.linkedBrowser.currentURI.spec;
+ if (w.isBlankPageURL ? !w.isBlankPageURL(uri) : (uri != 'about:blank')) tooltip += '\n' + uri;
+ label.setAttribute('tooltiptext', tooltip);
+ label.setAttribute('class', 'text-link '+this.kTREEITEM);
+ label.setAttribute('tab-id', TreeStyleTabBase.getTabValue(aTab, TreeStyleTabBase.kID));
+
+ var children = this.createTabChildren(aTab);
+ if (children) {
+ let container = doc.createElement('vbox');
+ container.appendChild(item);
+ container.appendChild(children);
+ return container;
+ }
+ else {
+ return item;
+ }
+ },
+
+ createTabChildren : function TB_createTabChildren(aTab)
+ {
+ var doc = aTab.ownerDocument;
+
+ var children = TreeStyleTabBase.getChildTabs(aTab);
+ if (!children.length)
+ return null;
+
+ var container = doc.createElement('vbox');
+ for (let i = 0, maxi = children.length; i < maxi; i++)
+ {
+ container.appendChild(this.createTabItem(children[i]));
+ }
+ container.setAttribute('class', this.kTREECHILDREN);
+ return container;
+ }
+};
diff --git a/modules/tabbarDNDObserver.js b/modules/tabbarDNDObserver.js
index 178c294b..d6f6f61f 100644
--- a/modules/tabbarDNDObserver.js
+++ b/modules/tabbarDNDObserver.js
@@ -1,1324 +1,1324 @@
-/* ***** 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 YUKI "Piro" Hiroshi.
- * Portions created by the Initial Developer are Copyright (C) 2010-2014
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s): YUKI "Piro" Hiroshi
- * Infocatcher
- * Tetsuharu OHZEKI
- *
- * 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 ******/
-
-const EXPORTED_SYMBOLS = ['TabbarDNDObserver'];
-
-const DEBUG = false;
-
-const Cc = Components.classes;
-const Ci = Components.interfaces;
-const Cu = Components.utils;
-
-Cu.import('resource://gre/modules/XPCOMUtils.jsm');
-Cu.import('resource://gre/modules/Services.jsm');
-
-XPCOMUtils.defineLazyModuleGetter(this, 'utils', 'resource://treestyletab-modules/utils.js', 'TreeStyleTabUtils');
-
-XPCOMUtils.defineLazyGetter(this, 'window', function() {
- Cu.import('resource://treestyletab-modules/lib/namespace.jsm');
- return getNamespaceFor('piro.sakura.ne.jp');
-});
-XPCOMUtils.defineLazyGetter(this, 'prefs', function() {
- Cu.import('resource://treestyletab-modules/lib/prefs.js');
- return window['piro.sakura.ne.jp'].prefs;
-});
-
-const TAB_DROP_TYPE = 'application/x-moz-tabbrowser-tab';
-
-const SSS = Cc['@mozilla.org/content/style-sheet-service;1']
- .getService(Ci.nsIStyleSheetService);
-const SecMan = Cc['@mozilla.org/scriptsecuritymanager;1']
- .getService(Ci.nsIScriptSecurityManager);
-
-function TabbarDNDObserver(aTabBrowser)
-{
- this.init(aTabBrowser);
-}
-
-TabbarDNDObserver.prototype = {
-
- readyToStartTabbarDrag : function TabbarDND_readyToStartTabbarDrag()
- {
- var sheet = this.treeStyleTab.makeURIFromSpec('chrome://treestyletab/content/hide-embed.css');
- if (!SSS.sheetRegistered(sheet, SSS.AGENT_SHEET))
- SSS.loadAndRegisterSheet(sheet, SSS.AGENT_SHEET);
- },
-
- readyToEndTabbarDrag : function TabbarDND_readyToEndTabbarDrag()
- {
- var sheet = this.treeStyleTab.makeURIFromSpec('chrome://treestyletab/content/hide-embed.css');
- if (SSS.sheetRegistered(sheet, SSS.AGENT_SHEET))
- SSS.unregisterSheet(sheet, SSS.AGENT_SHEET);
- },
-
- canDragTabbar : function TabbarDND_canDragTabbar(aEvent)
- {
- var sv = this.treeStyleTab;
-
- if (
- sv.evaluateXPath(
- 'ancestor-or-self::*[' +
- 'contains(" scrollbar popup menupopup panel tooltip ", concat(" ", local-name(), " ")) or' +
- '(local-name()="toolbarbutton" and @type="menu")' +
- ']',
- aEvent.originalTarget,
- Ci.nsIDOMXPathResult.BOOLEAN_TYPE
- ).booleanValue ||
- sv.isToolbarCustomizing
- )
- return false;
-
- var tab = sv.getTabFromEvent(aEvent);
- var tabbar = sv.getTabbarFromEvent(aEvent);
- var canDrag = (
- (tab ? aEvent.shiftKey : tabbar ) &&
- (
- aEvent.shiftKey ||
- sv.browser.getAttribute(sv.kFIXED) != 'true'
- )
- );
-
- if (canDrag && !aEvent.shiftKey) {
- let insensitiveArea = utils.getTreePref('tabbar.fixed.insensitiveArea');
- let box = tabbar.boxObject;
- switch (sv.position)
- {
- case 'right':
- if (aEvent.screenX < box.screenX + insensitiveArea)
- canDrag = false;
- break;
-
- case 'left':
- if (aEvent.screenX > box.screenX + box.width - insensitiveArea)
- canDrag = false;
- break;
-
- default:
- case 'top':
- if (aEvent.screenY > box.screenY + box.height - insensitiveArea)
- canDrag = false;
- break;
-
- case 'bottom':
- if (aEvent.screenY < box.screenY + insensitiveArea)
- canDrag = false;
- break;
- }
- }
-
- return canDrag;
- },
-
- canDrop : function TabbarDND_canDrop(aEvent)
- {
- var sv = this.treeStyleTab;
- var tooltip = sv.tabStrip.firstChild;
- if (tooltip &&
- tooltip.localName == 'tooltip' &&
- tooltip.popupBoxObject.popupState != 'closed')
- tooltip.hidePopup();
-
- var dropAction = this.getDropAction(aEvent);
- if ('dataTransfer' in aEvent) {
- var dt = aEvent.dataTransfer;
- if (dropAction.action & sv.kACTION_NEWTAB) {
- dt.effectAllowed = dt.dropEffect = (
- !dropAction.source ? 'link' :
- sv.isCopyAction(aEvent) ? 'copy' :
- 'move'
- );
- }
- }
- return dropAction.canDrop;
- },
-
- canDropTab : function TabbarDND_canDropTab(aEvent)
- {
-try{
- var sv = this.treeStyleTab;
- var b = this.browser;
-
- var session = sv.currentDragSession;
- var node = session.sourceNode;
- var tab = sv.getTabFromChild(node);
- if (!node ||
- !tab ||
- tab.parentNode != b.mTabContainer)
- return true;
-
- tab = sv.getTabFromEvent(aEvent) || sv.getTabFromTabbarEvent(aEvent);
- if (sv.isCollapsed(tab))
- return false;
-
- var info = this.getDropAction(aEvent, session);
- return info.canDrop;
-}
-catch(e) {
- dump('TabbarDND::canDrop\n'+e+'\n');
- return false;
-}
- },
-
- getDropAction : function TabbarDND_getDropAction(aEvent, aDragSession)
- {
- var sv = this.treeStyleTab;
- var b = this.browser;
-
- if (!aDragSession)
- aDragSession = sv.currentDragSession;
-
- var tab = aDragSession ? sv.getTabFromChild(aDragSession.sourceNode) : null ;
- sv.ensureTabInitialized(tab);
-
- var info = this.getDropActionInternal(aEvent, tab);
- info.canDrop = true;
- info.source = tab;
- if (tab) {
- var isCopy = sv.isCopyAction(aEvent);
- if (isCopy && 'duplicateTab' in b) {
- info.action |= sv.kACTION_DUPLICATE;
- }
- if (
- !isCopy &&
- sv.getTabBrowserFromChild(tab) != b &&
- (
- ('duplicateTab' in b)
- )
- ) {
- info.action |= sv.kACTION_IMPORT;
- }
-
- if (info.action & sv.kACTIONS_FOR_DESTINATION) {
- if (info.action & sv.kACTION_MOVE) info.action ^= sv.kACTION_MOVE;
- if (info.action & sv.kACTION_STAY) info.action ^= sv.kACTION_STAY;
- }
-
- if (info.action & sv.kACTION_ATTACH) {
- if (info.parent == tab) {
- info.canDrop = false;
- }
- else {
- var orig = tab;
- tab = info.target;
- while (tab = sv.getParentTab(tab))
- {
- if (tab != orig) continue;
- info.canDrop = false;
- break;
- }
- }
- }
- }
-
- var isInverted = sv.isVertical ? false : b.ownerDocument.defaultView.getComputedStyle(b.parentNode, null).direction == 'rtl';
- if (
- info.target &&
- (
- info.target.hidden ||
- (
- sv.isCollapsed(info.target) &&
- info.position != (isInverted ? sv.kDROP_BEFORE : sv.kDROP_AFTER )
- )
- )
- )
- info.canDrop = false;
-
- return info;
- },
-
- getDropActionInternal : function TabbarDND_getDropActionInternal(aEvent, aSourceTab)
- {
- if (DEBUG) dump('getDropActionInternal: start\n');
- var sv = this.treeStyleTab;
- var b = this.browser;
- var d = this.document;
-
- var tab = sv.getTabFromEvent(aEvent) || sv.getTabFromTabbarEvent(aEvent) || aEvent.target;
- var tabs = sv.getTabs(b);
- var firstTab = sv.getFirstNormalTab(b) || tabs[0];
- var lastTabIndex = tabs.length - 1;
- var isInverted = sv.isVertical ? false : b.ownerDocument.defaultView.getComputedStyle(b.parentNode, null).direction == 'rtl';
- var info = {
- target : null,
- position : null,
- action : null,
- parent : null,
- insertBefore : null,
- event : aEvent
- };
-
- let draggedTab = aEvent.dataTransfer && aEvent.dataTransfer.mozGetDataAt(TAB_DROP_TYPE, 0);
- if (draggedTab && draggedTab._dragData) {
- // "draggedTab._dragData.animDropIndex" means the actual "_tPos"
- // of the drop target, so we have to use the array of all
- // (including hidden) tabs here.
- let tabs = sv.getAllTabs(b);
- let sameTypeUndraggedTabs = tabs.filter(function(aTab) {
- return !aTab._dragData && aTab.pinned == draggedTab.pinned;
- });
- tab = draggedTab.pinned ?
- // pinned tabs cannot be dropped to another pinned tab, so
- // we can use the drop position calculated by "_animateTabMove()".
- tabs[draggedTab._dragData.animDropIndex] :
- // otherwise, we have to find "drop target" tab from screen coordinates.
- sv.getTabFromCoordinates(aEvent, sameTypeUndraggedTabs) ||
- tabs[draggedTab._dragData.animDropIndex] ;
- }
-
- var isTabMoveFromOtherWindow = aSourceTab && aSourceTab.ownerDocument != d;
- var isNewTabAction = !aSourceTab || aSourceTab.ownerDocument != d;
-
- if (!tab || tab.localName != 'tab') {
- if (DEBUG) dump(' not on a tab\n');
- let action = isTabMoveFromOtherWindow ? sv.kACTION_STAY : (sv.kACTION_MOVE | sv.kACTION_PART) ;
- if (isNewTabAction) action |= sv.kACTION_NEWTAB;
- if (aEvent[sv.screenPositionProp] < sv.getTabActualScreenPosition(firstTab)) {
- if (DEBUG) dump(' above the first tab\n');
- info.target = info.parent = info.insertBefore = firstTab;
- info.position = isInverted ? sv.kDROP_AFTER : sv.kDROP_BEFORE ;
- info.action = action;
- return info;
- }
- else if (aEvent[sv.screenPositionProp] > sv.getTabActualScreenPosition(tabs[lastTabIndex]) + tabs[lastTabIndex].boxObject[sv.sizeProp]) {
- if (DEBUG) dump(' below the last tab\n');
- info.target = info.parent = tabs[lastTabIndex];
- info.position = isInverted ? sv.kDROP_BEFORE : sv.kDROP_AFTER ;
- info.action = action;
- return info;
- }
- else {
- let index = b.getNewIndex ?
- b.getNewIndex(aEvent) :
- b.tabContainer._getDropIndex(aEvent) ;
- if (DEBUG) dump(' on the tab '+index+'\n');
- index = Math.min(index, lastTabIndex);
- info.target = tab = tabs[index];
- if (index == tabs[lastTabIndex]._tPos) {
- if (index > 0)
- info.target = tab = tabs[index - 1];
- info.position = sv.kDROP_AFTER;
- if (DEBUG) dump(' => after the last tab\n');
- } else if (index == firstTab._tPos) {
- if (index < lastTabIndex - 1)
- info.target = tab = tabs[index + 1];
- info.position = sv.kDROP_BEFORE;
- if (DEBUG) dump(' => before the first tab\n');
- }
- if (DEBUG) dump(' info.target = ' + info.target._tPos + '\n');
- }
- }
- else {
- if (DEBUG) dump(' on the tab '+tab._tPos+'\n');
- sv.ensureTabInitialized(tab);
- info.target = tab;
- }
-
- /**
- * Basically, tabs should have three areas for dropping of items:
- * [start][center][end], but, pinned tabs couldn't have its tree.
- * So, if a tab is dragged and the target tab is pinned, then, we
- * have to ignore the [center] area.
- */
- var pinned = tab.getAttribute('pinned') == 'true';
- var dropAreasCount = (aSourceTab && pinned) ? 2 : 3 ;
- var screenPositionProp = sv.isVertical && pinned ? sv.invertedScreenPositionProp : sv.screenPositionProp ;
- var sizeProp = sv.isVertical && pinned ? sv.invertedSizeProp : sv.sizeProp ;
- var orient = pinned ? 'horizontal' : null ;
- var boxPos = sv.getTabActualScreenPosition(tab, orient);
- var boxUnit = Math.round(tab.boxObject[sizeProp] / dropAreasCount);
- var eventPosition = aEvent[screenPositionProp];
-// if (this.window['piro.sakura.ne.jp'].tabsDragUtils
-// .canAnimateDraggedTabs(aEvent)) {
-// eventPosition = Math.round(sv.getTabActualScreenPosition(draggedTab) + (tab.boxObject[sizeProp] / 2))
-// }
- if (eventPosition < boxPos + boxUnit) {
- info.position = isInverted ? sv.kDROP_AFTER : sv.kDROP_BEFORE ;
- }
- else if (dropAreasCount == 2 || eventPosition > boxPos + boxUnit + boxUnit) {
- info.position = isInverted ? sv.kDROP_BEFORE : sv.kDROP_AFTER ;
- }
- else {
- info.position = sv.kDROP_ON;
- }
-
- switch (info.position)
- {
- case sv.kDROP_ON:
- if (DEBUG) dump(' position = on the tab\n');
- var visible = sv.getNextVisibleTab(tab);
- info.action = sv.kACTION_STAY | sv.kACTION_ATTACH;
- info.parent = tab;
- info.insertBefore = utils.getTreePref('insertNewChildAt') == sv.kINSERT_FISRT ?
- (sv.getFirstChildTab(tab) || visible) :
- (sv.getNextSiblingTab(tab) || sv.getNextTab(sv.getLastDescendantTab(tab) || tab));
- if (DEBUG && info.insertBefore) dump(' insertBefore = '+info.insertBefore._tPos+'\n');
- break;
-
- case sv.kDROP_BEFORE:
- if (DEBUG) dump(' position = before the tab\n');
-/*
- <= detach from parent, and move
- [TARGET ]
-
- [ ]
- <= attach to the parent of the target, and move
- [TARGET ]
-
- [ ]
- <= attach to the parent of the target, and move
- [TARGET ]
-
- [ ]
- <= attach to the parent of the target (previous tab), and move
- [TARGET]
-*/
- var prevTab = sv.getPreviousVisibleTab(tab);
- if (!prevTab) {
- // allow to drop pinned tab to beside of another pinned tab
- if (aSourceTab && aSourceTab.getAttribute('pinned') == 'true') {
- info.action = sv.kACTION_MOVE;
- info.insertBefore = tab;
- }
- else {
- info.action = sv.kACTION_MOVE | sv.kACTION_PART;
- info.insertBefore = firstTab;
- }
- }
- else {
- var prevLevel = Number(prevTab.getAttribute(sv.kNEST));
- var targetNest = Number(tab.getAttribute(sv.kNEST));
- info.parent = (prevLevel < targetNest) ? prevTab : sv.getParentTab(tab) ;
- info.action = sv.kACTION_MOVE | (info.parent ? sv.kACTION_ATTACH : sv.kACTION_PART );
- info.insertBefore = tab;
- }
- if (DEBUG && info.insertBefore) dump(' insertBefore = '+info.insertBefore._tPos+'\n');
- break;
-
- case sv.kDROP_AFTER:
- if (DEBUG) dump(' position = after the tab\n');
-/*
- [TARGET ]
- <= if the target has a parent, attach to it and and move
-
- [TARGET]
- <= attach to the parent of the target, and move
- [ ]
-
- [TARGET ]
- <= attach to the parent of the target, and move
- [ ]
-
- [TARGET ]
- <= attach to the target, and move
- [ ]
-*/
- var nextTab = sv.getNextVisibleTab(tab);
- if (!nextTab) {
- info.action = sv.kACTION_MOVE | sv.kACTION_ATTACH;
- info.parent = sv.getParentTab(tab);
- }
- else {
- var targetNest = Number(tab.getAttribute(sv.kNEST));
- var nextLevel = Number(nextTab.getAttribute(sv.kNEST));
- info.parent = (targetNest < nextLevel) ? tab : sv.getParentTab(tab) ;
- info.action = sv.kACTION_MOVE | (info.parent ? sv.kACTION_ATTACH : sv.kACTION_PART );
- info.insertBefore = nextTab;
-/*
- [TARGET ]
- <= attach dragged tab to the parent of the target as its next sibling
- [DRAGGED]
-*/
- if (aSourceTab == nextTab) {
- info.action = sv.kACTION_MOVE | sv.kACTION_ATTACH;
- info.parent = sv.getParentTab(tab);
- info.insertBefore = sv.getNextSiblingTab(tab);
- let ancestor = info.parent;
- while (ancestor && !info.insertBefore) {
- info.insertBefore = sv.getNextSiblingTab(ancestor);
- ancestor = sv.getParentTab(ancestor);
- }
- }
- }
- if (DEBUG && info.insertBefore) dump(' insertBefore = '+info.insertBefore._tPos+'\n');
- break;
- }
-
- if (isNewTabAction) info.action |= sv.kACTION_NEWTAB;
-
- return info;
- },
-
- performDrop : function TabbarDND_performDrop(aInfo, aDraggedTab)
- {
- if (DEBUG) dump('performDrop: start\n');
- var sv = this.treeStyleTab;
- var b = this.browser;
- var w = this.window;
-
- var tabsInfo = this.getDraggedTabsInfoFromOneTab(aDraggedTab, aInfo);
- if (!tabsInfo.draggedTab) {
- if (DEBUG) dump(' => no dragged tab\n');
- return false;
- }
-
- var sourceWindow = aDraggedTab.ownerDocument.defaultView;
- var sourceBrowser = sourceWindow.TreeStyleTabService.getTabBrowserFromChild(aDraggedTab);
- var sourceService = sourceBrowser.treeStyleTab;
-
- aDraggedTab = tabsInfo.draggedTab;
- var draggedTabs = tabsInfo.draggedTabs;
- var draggedRoots = sourceService.collectRootTabs(tabsInfo.draggedTabs);
-
-
- var targetBrowser = b;
- var tabs = sv.getTabs(targetBrowser);
-
- var draggedWholeTree = [].concat(draggedRoots);
- for (let i = 0, maxi = draggedRoots.length; i < maxi; i++)
- {
- let root = draggedRoots[i];
- let tabs = sourceService.getDescendantTabs(root);
- for (let i = 0, maxi = tabs.length; i < maxi; i++)
- {
- let tab = tabs[i];
- if (draggedWholeTree.indexOf(tab) < 0)
- draggedWholeTree.push(tab);
- }
- }
-
- var selectedTabs = draggedTabs.filter(function(aTab) {
- return aTab.getAttribute('multiselected') == 'true';
- });
- if (draggedWholeTree.length != selectedTabs.length &&
- selectedTabs.length) {
- draggedTabs = draggedRoots = selectedTabs;
- if (aInfo.action & sv.kACTIONS_FOR_SOURCE)
- sourceService.detachTabs(selectedTabs);
- }
-
- while (aInfo.insertBefore && draggedWholeTree.indexOf(aInfo.insertBefore) > -1)
- {
- aInfo.insertBefore = sv.getNextTab(aInfo.insertBefore);
- }
-
- if (aInfo.action & sv.kACTIONS_FOR_SOURCE) {
- if (aInfo.action & sv.kACTION_PART) {
- this.detachTabsOnDrop(draggedRoots);
- }
- else if (aInfo.action & sv.kACTION_ATTACH) {
- this.attachTabsOnDrop(draggedRoots, aInfo.parent);
- }
- // otherwise, just moved.
-
- if ( // if this move will cause no change...
- sourceBrowser == targetBrowser &&
- sourceService.getNextVisibleTab(draggedTabs[draggedTabs.length-1]) == aInfo.insertBefore
- ) {
- if (DEBUG) dump(' => no change\n');
- // then, do nothing
- return true;
- }
- }
-
- var treeStructure = sourceService.getTreeStructureFromTabs(draggedTabs);
-
- var newTabs = sv.moveTabsInternal(draggedTabs, {
- duplicate : aInfo.action & sv.kACTION_DUPLICATE,
- insertBefore : aInfo.insertBefore
- });
-
- if (newTabs.length && aInfo.action & sv.kACTION_ATTACH)
- this.attachTabsOnDrop(
- newTabs.filter(function(aTab, aIndex) {
- return treeStructure[aIndex] == -1;
- }),
- aInfo.parent
- );
-
- return true;
- },
-
- getDraggedTabsInfoFromOneTab : function TabbarDND_getDraggedTabsInfoFromOneTab(aTab, aInfo)
- {
- aInfo = aInfo || {};
- if (aInfo.draggedTabsInfo)
- return aInfo.draggedTabsInfo;
-
- var sv = this.treeStyleTab;
- var sourceWindow = aTab.ownerDocument.defaultView;
- var sourceBrowser = sourceWindow.TreeStyleTabService.getTabBrowserFromChild(aTab);
- var sourceService = sourceBrowser.treeStyleTab;
-
- aTab = sourceService.getTabFromChild(aTab);
- if (!aTab || !aTab.parentNode) // ignore removed tabs!
- return {
- draggedTab : null,
- draggedTabs : [],
- isMultipleMove : false
- };
-
- var draggedTabs = sourceWindow['piro.sakura.ne.jp'].tabsDragUtils.getSelectedTabs(aTab || sourceBrowser || aInfo.event);
- var isMultipleMove = false;
-
- if (draggedTabs.length > 1) {
- isMultipleMove = true;
- }
- else if (aInfo.action & sv.kACTIONS_FOR_DESTINATION) {
- draggedTabs = [aTab].concat(sourceService.getDescendantTabs(aTab));
- }
-
- return {
- draggedTab : aTab,
- draggedTabs : draggedTabs,
- isMultipleMove : isMultipleMove
- };
- },
-
- attachTabsOnDrop : function TabbarDND_attachTabsOnDrop(aTabs, aParent)
- {
- var b = aTabs[0].ownerDocument.defaultView.TreeStyleTabService.getTabBrowserFromChild(aTabs[0]);
- var sv = b.treeStyleTab;
-
- b.movingSelectedTabs = true; // Multiple Tab Handler
- for (let i = 0, maxi = aTabs.length; i < maxi; i++)
- {
- let tab = aTabs[i];
- if (!tab.parentNode) continue; // ignore removed tabs
- if (aParent)
- sv.attachTabTo(tab, aParent);
- else
- sv.detachTab(tab);
- sv.collapseExpandTab(tab, false);
- }
- b.movingSelectedTabs = false; // Multiple Tab Handler
- },
-
- detachTabsOnDrop : function TabbarDND_detachTabsOnDrop(aTabs)
- {
- var b = aTabs[0].ownerDocument.defaultView.TreeStyleTabService.getTabBrowserFromChild(aTabs[0]);
- var sv = b.treeStyleTab;
-
- b.movingSelectedTabs = true; // Multiple Tab Handler
- for (let i = 0, maxi = aTabs.length; i < maxi; i++)
- {
- let tab = aTabs[i];
- if (!tab.parentNode) continue; // ignore removed tabs
- sv.detachTab(tab);
- sv.collapseExpandTab(tab, false);
- }
- b.movingSelectedTabs = false; // Multiple Tab Handler
- },
-
- clearDropPosition : function TabbarDND_clearDropPosition(aOnFinish)
- {
- var sv = this.treeStyleTab;
- var b = this.browser;
-
- b.visibleTabs.forEach(function(aTab) {
- if (aTab.hasAttribute(sv.kDROP_POSITION))
- aTab.removeAttribute(sv.kDROP_POSITION)
-
- if (aOnFinish) {
- aTab.style.transform = '';
- if ('__treestyletab__opacityBeforeDragged' in aTab) {
- aTab.style.opacity = aTab.__treestyletab__opacityBeforeDragged;
- delete aTab.__treestyletab__opacityBeforeDragged;
- }
- }
- });
-
- if (aOnFinish)
- this.browser.mTabContainer.removeAttribute('movingtab')
- },
-
- isDraggingAllTabs : function TabbarDND_isDraggingAllTabs(aTab, aTabs)
- {
- var sv = this.treeStyleTab;
- var b = this.browser;
-
- var actionInfo = {
- action : sv.kACTIONS_FOR_DESTINATION | sv.kACTION_IMPORT
- };
- var tabsInfo = this.getDraggedTabsInfoFromOneTab(aTab, actionInfo);
- return tabsInfo.draggedTabs.length == (aTabs || sv.getAllTabs(b)).length;
- },
-
- isDraggingAllCurrentTabs : function TabbarDND_isDraggingAllCurrentTabs(aTab)
- {
- return this.isDraggingAllTabs(aTab, this.treeStyleTab.getTabs(this.treeStyleTab.browser));
- },
-
- handleEvent : function TabbarDND_handleEvent(aEvent)
- {
- // ignore drag and drop while toolbar customization
- if (this.treeStyleTab.isToolbarCustomizing)
- return;
-
- switch (aEvent.type)
- {
- case 'dragstart': return this.onDragStart(aEvent);
- case 'dragenter': return this.onDragEnter(aEvent);
- case 'dragleave': return this.onDragLeave(aEvent);
- case 'dragend': return this.onDragEnd(aEvent);
- case 'dragover': return this.onDragOver(aEvent);
- case 'drop': return this.onDrop(aEvent);
- }
- },
-
- onDragStart : function TabbarDND_onDragStart(aEvent)
- {
- if (this.canDragTabbar(aEvent))
- return this.onTabbarDragStart(aEvent);
-
- var tab = this.treeStyleTab.getTabFromEvent(aEvent);
- if (tab)
- return this.onTabDragStart(aEvent, tab);
- },
-
- onTabDragStart : function TabbarDND_onTabDragStart(aEvent, aTab)
- {
- var sv = this.treeStyleTab;
- var w = this.window;
- var actionInfo = {
- action : sv.kACTIONS_FOR_DESTINATION | sv.kACTION_MOVE,
- event : aEvent
- };
- var tabsInfo = this.getDraggedTabsInfoFromOneTab(aTab, actionInfo);
- if (
- tabsInfo.draggedTabs.length <= 1 ||
- Array.some(tabsInfo.draggedTabs, function(aTab) {
- return aTab.getAttribute('multiselected') == 'true'; // if multiselected, it should be handled by other addons (like Multiple Tab Handler)
- })
- )
- return;
-
- w['piro.sakura.ne.jp'].tabsDragUtils.startTabsDrag(aEvent, tabsInfo.draggedTabs);
- },
-
- onTabbarDragStart : function TabbarDND_onTabbarDragStart(aEvent)
- {
- var sv = this.treeStyleTab;
- var dt = aEvent.dataTransfer;
- dt.mozSetDataAt(
- sv.kDRAG_TYPE_TABBAR,
- aEvent.shiftKey ?
- sv.kTABBAR_MOVE_FORCE :
- sv.kTABBAR_MOVE_NORMAL,
- 0
- );
- dt.mozCursor = 'move';
-// var tabbar = sv.browser.mTabContainer;
-// var box = tabbar.boxObject;
-// dt.setDragImage(
-// tabbar,
-// aEvent.screenX - box.screenX,
-// aEvent.screenY - box.screenY
-// );
- // no feedback image, because it's annoying...
- dt.setDragImage(new this.window.Image(), 0, 0);
- aEvent.stopPropagation();
- this.readyToStartTabbarDrag();
- },
-
- onDragEnter : function TabbarDND_onDragEnter(aEvent)
- {
- var sv = this.treeStyleTab;
- var w = this.window;
-
- var dt = aEvent.dataTransfer;
- if (!this.canDrop(aEvent)) {
- dt.effectAllowed = dt.dropEffect = 'none';
- return;
- }
-
- var tab = aEvent.target;
- if (tab.localName != 'tab' ||
- !utils.getTreePref('autoExpand.enabled'))
- return;
-
- w.clearTimeout(this.mAutoExpandTimer);
- w.clearTimeout(this.mAutoExpandTimerNext);
-
- var sourceNode = dt.getData(sv.kDRAG_TYPE_TABBAR+'-node');
- if (aEvent.target == sourceNode)
- return;
-
- var draggedTab = dt.mozGetDataAt(TAB_DROP_TYPE, 0);
- this.mAutoExpandTimerNext = w.setTimeout(function(aSelf, aTarget, aDragged) {
- aSelf.mAutoExpandTimerNext = null;
- aSelf.mAutoExpandTimer = w.setTimeout(
- function() {
- let tab = sv.getTabById(aTarget);
- if (tab &&
- sv.shouldTabAutoExpanded(tab) &&
- tab.getAttribute(sv.kDROP_POSITION) == 'self') {
- let draggedTab = aDragged && sv.getTabById(aDragged);
- if (utils.getTreePref('autoExpand.intelligently')) {
- sv.collapseExpandTreesIntelligentlyFor(tab);
- if (draggedTab)
- aSelf.updateDragData(draggedTab);
- }
- else {
- if (aSelf.mAutoExpandedTabs.indexOf(aTarget) < 0)
- aSelf.mAutoExpandedTabs.push(aTarget);
- sv.collapseExpandSubtree(tab, false);
- if (draggedTab)
- aSelf.updateDragData(draggedTab);
- }
- }
- },
- utils.getTreePref('autoExpand.delay')
- );
- }, 0, this, tab.getAttribute(sv.kID), draggedTab && draggedTab.getAttribute(sv.kID));
-
- tab = null;
- },
- updateDragData : function TabbarDND_updateDragData(aTab)
- {
- if (!aTab || !aTab._dragData) return;
- var sv = this.treeStyleTab;
- var data = aTab._dragData;
- var offsetX = sv.getXOffsetOfTab(aTab);
- var offsetY = sv.getYOffsetOfTab(aTab);
- if ('offsetX' in data) data.offsetX += offsetX;
- if ('screenX' in data) data.screenX += offsetX;
- if ('offsetY' in data) data.offsetY += offsetY;
- if ('screenY' in data) data.screenY += offsetY;
- },
-
- onDragLeave : function TabbarDND_onDragLeave(aEvent)
- {
- this.clearDropPosition();
-
- this.window.clearTimeout(this.mAutoExpandTimer);
- this.mAutoExpandTimer = null;
- },
-
- onDragEnd : function TabbarDND_onDragEnd(aEvent)
- {
- var sv = this.treeStyleTab;
- var dt = aEvent.dataTransfer;
- if (dt.getData(sv.kDRAG_TYPE_TABBAR))
- this.onTabbarDragEnd(aEvent);
- else
- this.onTabDragEnd(aEvent);
- },
-
- onTabDragEnd : function TabbarDND_onTabDragEnd(aEvent)
- {
- var sv = this.treeStyleTab;
- var b = this.browser;
- var d = this.document;
- var w = this.window;
-
- var tabbar = b.mTabContainer;
- var strip = sv.tabStrip;
- var dt = aEvent.dataTransfer;
-
- this.clearDropPosition(true);
- this.collapseAutoExpandedTabs();
-
- if (dt.mozUserCancelled || dt.dropEffect != 'none')
- return;
-
- // prevent handling of this event by the default handler
- aEvent.stopPropagation();
- aEvent.preventDefault();
-
- var eX = aEvent.screenX;
- var eY = aEvent.screenY;
- var x, y, w, h;
-
- // ignore drop on the toolbox
- x = w.screenX;
- y = w.screenY;
- w = w.outerWidth;
- h = d.getElementById('navigator-toolbox').boxObject.height;
- if (eX > x && eX < x + w && eY > y && eY < y + h)
- return;
-
- // ignore drop near the tab bar
- var box = strip.boxObject;
- var ignoreArea = Math.max(16, parseInt(sv.getFirstNormalTab(b).boxObject.height / 2));
- x = box.screenX - (sv.isVertical ? ignoreArea : 0 );
- y = box.screenY - ignoreArea;
- w = box.width + (sv.isVertical ? ignoreArea + ignoreArea : 0 );
- h = box.height + ignoreArea + ignoreArea;
- if (eX > x && eX < x + w && eY > y && eY < y + h)
- return;
-
- var draggedTab = dt.mozGetDataAt(TAB_DROP_TYPE, 0);
- if (this.isDraggingAllCurrentTabs(draggedTab))
- return;
-
- // Respect the behaviour of "Disable detach and tear off tab"
- // https://addons.mozilla.org/firefox/addon/bug489729-disable-detach-and-t/
- if ('bug489729' in this.window &&
- prefs.getPref('extensions.bug489729.disable_detach_tab'))
- return;
-
- if (aEvent.ctrlKey || aEvent.metaKey)
- draggedTab.__treestyletab__toBeDuplicated = true;
-
- b.replaceTabWithWindow(draggedTab);
- },
-
- onTabbarDragEnd : function TabbarDND_onTabbarDragEnd(aEvent)
- {
- var w = this.window;
- w.setTimeout(function(aSelf) {
- aSelf.readyToEndTabbarDrag();
- aSelf.treeStyleTab.removeTabbrowserAttribute(aSelf.treeStyleTab.kDROP_POSITION);
- }, 10, this);
- aEvent.stopPropagation();
- aEvent.preventDefault();
- },
-
- onDragOver : function TabbarDND_onDragOver(aEvent)
- {
- if (this.onTabDragOver(aEvent)) {
- aEvent.stopPropagation();
- aEvent.preventDefault(); // this is required to override default dragover actions!
- }
- },
-
- onTabDragOver : function TabbarDND_onTabDragOver(aEvent)
- {
-try{
- var sv = this.treeStyleTab;
- var b = this.browser;
- var tabbar = b.mTabContainer;
-
- var session = sv.currentDragSession;
- if (sv.isToolbarCustomizing)
- return false;
-
- sv.autoScroll.processAutoScroll(aEvent);
-
- let draggedTab = aEvent.dataTransfer && aEvent.dataTransfer.mozGetDataAt(TAB_DROP_TYPE, 0);
- let dragOverTab = sv.getTabFromEvent(aEvent) || sv.getTabFromTabbarEvent(aEvent) || aEvent.target;
- b.ownerDocument.defaultView['piro.sakura.ne.jp'].tabsDragUtils
- .processTabsDragging(aEvent, {
- canDropOnSelf : !dragOverTab || !dragOverTab.pinned,
- isVertical : (
- b.ownerDocument.defaultView['piro.sakura.ne.jp'].tabsDragUtils.isVertical(b.tabContainer) &&
- (
- (draggedTab && !draggedTab.pinned) ||
- !utils.getTreePref('pinnedTab.faviconized')
- )
- )
- });
-
- /**
- * We must calculate drop action after tabsDragUtils.processTabsDragging(),
- * because the drop position depends on tabs' actual
- * positions (which can be changed by animation effects.)
- */
- var info = this.getDropAction(aEvent, session);
-
- var observer = b;
- if (b.tabContainer && b.tabContainer._setEffectAllowedForDataTransfer)
- observer = b.tabContainer;
-
- // auto-switch for staying on tabs
- if (
- info.position == sv.kDROP_ON &&
- info.target &&
- !info.target.selected &&
- '_dragTime' in observer && '_dragOverDelay' in observer
- ) {
- let time = observer.mDragTime || observer._dragTime || 0;
- let delay = observer.mDragOverDelay || observer._dragOverDelay || 0;
- let effects = observer._setEffectAllowedForDataTransfer(aEvent);
- if (effects == 'link') {
- let now = Date.now();
- if (!time) {
- time = now;
- if ('mDragTime' in observer)
- observer.mDragTime = time;
- else
- observer._dragTime = time;
- }
- if (now >= time + delay)
- b.selectedTab = info.target;
- }
- }
-
- if (
- !info.canDrop ||
- observer._setEffectAllowedForDataTransfer(aEvent) == 'none'
- ) {
- aEvent.dataTransfer.effectAllowed = "none";
- this.clearDropPosition();
- return true;
- }
-
- let indicatorTab = info.target;
- if (sv.isCollapsed(info.target)) {
- let tab = indicatorTab;
- while ((tab = sv.getPreviousTab(tab)) && sv.isCollapsed(tab)) {}
- if (tab) indicatorTab = tab;
- }
-
- let dropPosition = info.position == sv.kDROP_BEFORE ? 'before' :
- info.position == sv.kDROP_AFTER ? 'after' :
- 'self';
- if (indicatorTab != draggedTab &&
- indicatorTab.getAttribute(sv.kDROP_POSITION) != dropPosition) {
- this.clearDropPosition();
- indicatorTab.setAttribute(sv.kDROP_POSITION, dropPosition);
- if (b.ownerDocument.defaultView['piro.sakura.ne.jp'].tabsDragUtils
- .canAnimateDraggedTabs(aEvent)) {
- let newOpacity = dropPosition == 'self' ? 0.35 : 0.75 ; // to prevent the dragged tab hides the drop target itself
- this.window['piro.sakura.ne.jp'].tabsDragUtils.getDraggedTabs(aEvent).forEach(function(aTab) {
- if (!('__treestyletab__opacityBeforeDragged' in aTab))
- aTab.__treestyletab__opacityBeforeDragged = aTab.style.opacity || '';
- aTab.style.opacity = newOpacity;
- });
- }
- }
-
-
- var indicator = b.mTabDropIndicatorBar || b.tabContainer._tabDropIndicator;
- indicator.setAttribute('dragging', (info.position == sv.kDROP_ON || sv.isVertical) ? 'false' : 'true' );
- if (sv.isVertical)
- indicator.collapsed = true;
-
- return (info.position == sv.kDROP_ON || sv.position != 'top')
-}
-catch(e) {
- dump('TabbarDND::onDragOver\n'+e+'\n');
-}
- },
-
- onDrop : function TabbarDND_onDrop(aEvent)
- {
- this.onTabDrop(aEvent);
- this.collapseAutoExpandedTabs();
- },
- collapseAutoExpandedTabs : function TabbarDND_collapseAutoExpandedTabs()
- {
- var sv = this.treeStyleTab;
- if (this.mAutoExpandedTabs.length) {
- if (utils.getTreePref('autoExpand.collapseFinally')) {
- for (let i = 0, maxi = this.mAutoExpandedTabs.length; i < maxi; i++)
- {
- sv.collapseExpandSubtree(sv.getTabById(this.mAutoExpandedTabs[i]), true, true);
- }
- }
- this.mAutoExpandedTabs = [];
- }
- },
-
- onTabDrop : function TSTService_onTabDrop(aEvent)
- {
- var sv = this.treeStyleTab;
- var b = this.browser;
- var w = this.window;
-
- var tabbar = b.mTabContainer;
- var dt = aEvent.dataTransfer;
-
- /**
- * We must calculate drop action before clearing "dragging"
- * state, because the drop position depends on tabs' actual
- * positions (they are applied only while tab dragging.)
- */
- var session = sv.currentDragSession;
- var dropActionInfo = this.getDropAction(aEvent, session);
-
- this.clearDropPosition(true);
- if (tabbar._tabDropIndicator)
- tabbar._tabDropIndicator.collapsed = true;
-
- var draggedTab = dt.mozGetDataAt(TAB_DROP_TYPE, 0);
- if (dt.dropEffect != 'link' && !draggedTab) {
- aEvent.stopPropagation();
- return;
- }
-
- var sourceBrowser = sv.getTabBrowserFromChild(draggedTab);
- if (draggedTab && sourceBrowser != b)
- sourceBrowser.treeStyleTab.tabbarDNDObserver.clearDropPosition(true);
-
- if (draggedTab && this.performDrop(dropActionInfo, draggedTab)) {
- aEvent.stopPropagation();
- return;
- }
-
- // duplicating of tabs
- if (
- draggedTab &&
- (
- dt.dropEffect == 'copy' ||
- sourceBrowser != b
- ) &&
- dropActionInfo.position == sv.kDROP_ON
- ) {
- var beforeTabs = Array.slice(b.mTabContainer.childNodes);
- w.setTimeout(function() {
- var newTabs = Array.slice(b.mTabContainer.childNodes).filter(function(aTab) {
- return beforeTabs.indexOf(aTab) < 0;
- });
- if (newTabs.length)
- sv.attachTabTo(newTabs[0], dropActionInfo.target);
- }, 0);
- return;
- }
-
- if (!draggedTab)
- this.handleLinksOrBookmarks(aEvent, dropActionInfo);
- },
- handleLinksOrBookmarks : function TabbarDND_handleLinksOrBookmarks(aEvent, aDropActionInfo)
- {
- aEvent.stopPropagation();
-
- var uris = this.retrieveURLsFromDataTransfer(aEvent.dataTransfer);
- uris.forEach(function(aURI) {
- if (aURI.indexOf(this.BOOKMARK_FOLDER) != 0)
- this.securityCheck(aURI, aEvent);
- }, this);
-
- var sv = this.treeStyleTab;
- var b = this.browser;
- var w = this.window;
- var self = this;
-
- let bgLoad = prefs.getPref('browser.tabs.loadInBackground');
- if (aEvent.shiftKey) bgLoad = !bgLoad;
-
- let tab = sv.getTabFromEvent(aEvent);
- if (
- !tab ||
- aEvent.dataTransfer.dropEffect == 'copy' ||
- uris.length > 1 ||
- uris[0].indexOf(this.BOOKMARK_FOLDER) == 0
- ) {
- uris.reverse().forEach(function(aURI) {
- if (aURI.indexOf(this.BOOKMARK_FOLDER) == 0) {
- let newTabs = sv.getNewTabsWithOperation(function() {
- var data = aURI.replace(self.BOOKMARK_FOLDER, '');
- data = JSON.parse(data);
- w.PlacesUIUtils._openTabset(data.children, { type : 'drop' }, w, data.title);
- }, b);
- aDropActionInfo.draggedTabsInfo = {
- draggedTabs : newTabs,
- draggedTab : newTabs[0],
- isMultipleMove : newTabs.length > 1
- };
- this.performDrop(aDropActionInfo, newTabs[0]);
- }
- else {
- aURI = utils.getShortcutOrURI(w, aURI);
- this.performDrop(aDropActionInfo, b.loadOneTab(aURI, { inBackground: bgLoad }));
- }
- }, this);
- }
- else {
- let locked = (
- tab.getAttribute('locked') == 'true' || // Tab Mix Plus and others
- tab.getAttribute('isPageLocked') == 'true' // Super Tab Mode
- );
- let loadDroppedLinkToNewChildTab = aDropActionInfo.position != sv.kDROP_ON || locked;
- if (!loadDroppedLinkToNewChildTab &&
- aDropActionInfo.position == sv.kDROP_ON)
- loadDroppedLinkToNewChildTab = sv.dropLinksOnTabBehavior() == sv.kDROPLINK_NEWTAB;
-
- try {
- let uri = utils.getShortcutOrURI(w, uris[0]);
- if (loadDroppedLinkToNewChildTab || locked) {
- this.performDrop(aDropActionInfo, b.loadOneTab(uri, { inBackground: bgLoad }));
- }
- else {
- tab.linkedBrowser.loadURI(uri);
- if (!bgLoad)
- b.selectedTab = tab;
- }
- }
- catch(e) {
- }
- }
- },
- securityCheck : function TabbarDND_securityCheck(aURI, aEvent)
- {
- // See dragDropSecurityCheck() in chrome://global/content/nsDragAndDrop.js
- let session = this.treeStyleTab.currentDragSession;
- if (!session) { //TODO: use some fake nodePrincipal?
- aEvent.stopPropagation();
- throw 'Drop of ' + aURI + ' denied: no drag session.';
- }
- let normalizedURI;
- try {
- normalizedURI = this.treeStyleTab.makeURIFromSpec(aURI);
- }
- catch(e) {
- }
- if (!normalizedURI)
- return;
- let sourceDoc = session.sourceDocument;
- let sourceURI = sourceDoc ? sourceDoc.documentURI : 'file:///' ;
- let principal = sourceDoc ?
- sourceDoc.nodePrincipal :
- SecMan.getSimpleCodebasePrincipal(Services.io.newURI(sourceURI, null, null)) ;
- try {
- if (principal)
- SecMan.checkLoadURIStrWithPrincipal(principal, normalizedURI.spec, Ci.nsIScriptSecurityManager.STANDARD);
- else
- SecMan.checkLoadURIStr(sourceURI, normalizedURI.spec, Ci.nsIScriptSecurityManager.STANDARD);
- }
- catch(e) {
- aEvent.stopPropagation();
- throw 'Drop of ' + aURI + ' denied.';
- }
- },
-
- retrieveURLsFromDataTransfer : function TSTService_retrieveURLsFromDataTransfer(aDataTransfer)
- {
- var urls = [];
- var types = [
- 'text/x-moz-place',
- 'text/uri-list',
- 'text/x-moz-text-internal',
- 'text/x-moz-url',
- 'text/plain',
- 'application/x-moz-file'
- ];
- for (let i = 0; i < types.length; i++) {
- let dataType = types[i];
- for (let i = 0, maxi = aDataTransfer.mozItemCount; i < maxi; i++)
- {
- let urlData = aDataTransfer.mozGetDataAt(dataType, i);
- if (urlData) {
- urls = urls.concat(this.retrieveURLsFromData(urlData, dataType));
- }
- }
- if (urls.length)
- break;
- }
- return urls.filter(function(aURI) {
- return aURI &&
- aURI.length &&
- aURI.indexOf(this.BOOKMARK_FOLDER) == 0 ||
- (
- aURI.indexOf(' ', 0) == -1 &&
- !/^\s*(javascript|data):/.test(aURI)
- );
- }, this);
- },
- BOOKMARK_FOLDER: 'x-moz-place:',
- retrieveURLsFromData : function TSTService_retrieveURLsFromData(aData, aType)
- {
- switch (aType)
- {
- case 'text/x-moz-place':
- let (uri = JSON.parse(aData).uri) {
- if (uri)
- return uri;
- else
- return this.BOOKMARK_FOLDER+aData;
- }
-
- case 'text/uri-list':
- return aData.replace(/\r/g, '\n')
- .replace(/^\#.+$/gim, '')
- .replace(/\n\n+/g, '\n')
- .split('\n');
-
- case 'text/unicode':
- case 'text/plain':
- case 'text/x-moz-text-internal':
- return [aData.trim()];
-
- case 'text/x-moz-url':
- return [((aData instanceof Ci.nsISupportsString) ? aData.toString() : aData)
- .split('\n')[0]];
-
- case 'application/x-moz-file':
- let fileHandler = Services.io.getProtocolHandler('file')
- .QueryInterface(Ci.nsIFileProtocolHandler);
- return [fileHandler.getURLSpecFromFile(aData)];
- }
- return [];
- },
-
- init : function TabbarDND_init(aTabBrowser)
- {
- this.browser = aTabBrowser;
- this.document = aTabBrowser.ownerDocument;
- this.window = this.document.defaultView;
- this.treeStyleTab = aTabBrowser.treeStyleTab;
-
- this.mAutoExpandTimer = null;
- this.mAutoExpandTimerNext = null;
- this.mAutoExpandedTabs = [];
- this.startListenEvents();
- },
-
- startListenEvents : function TabbarDND_startListenEvents()
- {
- var target = this.treeStyleTab.ownerToolbar || this.treeStyleTab.tabStrip;
- target.addEventListener('dragstart', this, true);
- target.addEventListener('dragover', this, true);
- target.addEventListener('dragenter', this, false);
- target.addEventListener('dragleave', this, false);
- target.addEventListener('dragend', this, true);
- target.addEventListener('drop', this, true);
- },
-
- destroy : function TabbarDND_destroy()
- {
- this.endListenEvents();
-
- delete this.treeStyleTab;
- delete this.browser;
- delete this.document;
- delete this.window;
- },
-
- endListenEvents : function TabbarDND_endListenEvents()
- {
- var target = this.treeStyleTab.ownerToolbar || this.treeStyleTab.tabStrip;
- target.removeEventListener('dragstart', this, true);
- target.removeEventListener('dragover', this, true);
- target.removeEventListener('dragenter', this, false);
- target.removeEventListener('dragleave', this, false);
- target.removeEventListener('dragend', this, true);
- target.removeEventListener('drop', this, true);
- }
-
-};
-
+/* ***** 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 YUKI "Piro" Hiroshi.
+ * Portions created by the Initial Developer are Copyright (C) 2010-2014
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s): YUKI "Piro" Hiroshi
+ * Infocatcher
+ * Tetsuharu OHZEKI
+ *
+ * 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 ******/
+
+const EXPORTED_SYMBOLS = ['TabbarDNDObserver'];
+
+const DEBUG = false;
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+const Cu = Components.utils;
+
+Cu.import('resource://gre/modules/XPCOMUtils.jsm');
+Cu.import('resource://gre/modules/Services.jsm');
+
+XPCOMUtils.defineLazyModuleGetter(this, 'utils', 'resource://treestyletab-modules/utils.js', 'TreeStyleTabUtils');
+
+XPCOMUtils.defineLazyGetter(this, 'window', function() {
+ Cu.import('resource://treestyletab-modules/lib/namespace.jsm');
+ return getNamespaceFor('piro.sakura.ne.jp');
+});
+XPCOMUtils.defineLazyGetter(this, 'prefs', function() {
+ Cu.import('resource://treestyletab-modules/lib/prefs.js');
+ return window['piro.sakura.ne.jp'].prefs;
+});
+
+const TAB_DROP_TYPE = 'application/x-moz-tabbrowser-tab';
+
+const SSS = Cc['@mozilla.org/content/style-sheet-service;1']
+ .getService(Ci.nsIStyleSheetService);
+const SecMan = Cc['@mozilla.org/scriptsecuritymanager;1']
+ .getService(Ci.nsIScriptSecurityManager);
+
+function TabbarDNDObserver(aTabBrowser)
+{
+ this.init(aTabBrowser);
+}
+
+TabbarDNDObserver.prototype = {
+
+ readyToStartTabbarDrag : function TabbarDND_readyToStartTabbarDrag()
+ {
+ var sheet = this.treeStyleTab.makeURIFromSpec('chrome://treestyletab/content/hide-embed.css');
+ if (!SSS.sheetRegistered(sheet, SSS.AGENT_SHEET))
+ SSS.loadAndRegisterSheet(sheet, SSS.AGENT_SHEET);
+ },
+
+ readyToEndTabbarDrag : function TabbarDND_readyToEndTabbarDrag()
+ {
+ var sheet = this.treeStyleTab.makeURIFromSpec('chrome://treestyletab/content/hide-embed.css');
+ if (SSS.sheetRegistered(sheet, SSS.AGENT_SHEET))
+ SSS.unregisterSheet(sheet, SSS.AGENT_SHEET);
+ },
+
+ canDragTabbar : function TabbarDND_canDragTabbar(aEvent)
+ {
+ var sv = this.treeStyleTab;
+
+ if (
+ sv.evaluateXPath(
+ 'ancestor-or-self::*[' +
+ 'contains(" scrollbar popup menupopup panel tooltip ", concat(" ", local-name(), " ")) or' +
+ '(local-name()="toolbarbutton" and @type="menu")' +
+ ']',
+ aEvent.originalTarget,
+ Ci.nsIDOMXPathResult.BOOLEAN_TYPE
+ ).booleanValue ||
+ sv.isToolbarCustomizing
+ )
+ return false;
+
+ var tab = sv.getTabFromEvent(aEvent);
+ var tabbar = sv.getTabbarFromEvent(aEvent);
+ var canDrag = (
+ (tab ? aEvent.shiftKey : tabbar ) &&
+ (
+ aEvent.shiftKey ||
+ sv.browser.getAttribute(sv.kFIXED) != 'true'
+ )
+ );
+
+ if (canDrag && !aEvent.shiftKey) {
+ let insensitiveArea = utils.getTreePref('tabbar.fixed.insensitiveArea');
+ let box = tabbar.boxObject;
+ switch (sv.position)
+ {
+ case 'right':
+ if (aEvent.screenX < box.screenX + insensitiveArea)
+ canDrag = false;
+ break;
+
+ case 'left':
+ if (aEvent.screenX > box.screenX + box.width - insensitiveArea)
+ canDrag = false;
+ break;
+
+ default:
+ case 'top':
+ if (aEvent.screenY > box.screenY + box.height - insensitiveArea)
+ canDrag = false;
+ break;
+
+ case 'bottom':
+ if (aEvent.screenY < box.screenY + insensitiveArea)
+ canDrag = false;
+ break;
+ }
+ }
+
+ return canDrag;
+ },
+
+ canDrop : function TabbarDND_canDrop(aEvent)
+ {
+ var sv = this.treeStyleTab;
+ var tooltip = sv.tabStrip.firstChild;
+ if (tooltip &&
+ tooltip.localName == 'tooltip' &&
+ tooltip.popupBoxObject.popupState != 'closed')
+ tooltip.hidePopup();
+
+ var dropAction = this.getDropAction(aEvent);
+ if ('dataTransfer' in aEvent) {
+ var dt = aEvent.dataTransfer;
+ if (dropAction.action & sv.kACTION_NEWTAB) {
+ dt.effectAllowed = dt.dropEffect = (
+ !dropAction.source ? 'link' :
+ sv.isCopyAction(aEvent) ? 'copy' :
+ 'move'
+ );
+ }
+ }
+ return dropAction.canDrop;
+ },
+
+ canDropTab : function TabbarDND_canDropTab(aEvent)
+ {
+try{
+ var sv = this.treeStyleTab;
+ var b = this.browser;
+
+ var session = sv.currentDragSession;
+ var node = session.sourceNode;
+ var tab = sv.getTabFromChild(node);
+ if (!node ||
+ !tab ||
+ tab.parentNode != b.mTabContainer)
+ return true;
+
+ tab = sv.getTabFromEvent(aEvent) || sv.getTabFromTabbarEvent(aEvent);
+ if (sv.isCollapsed(tab))
+ return false;
+
+ var info = this.getDropAction(aEvent, session);
+ return info.canDrop;
+}
+catch(e) {
+ dump('TabbarDND::canDrop\n'+e+'\n');
+ return false;
+}
+ },
+
+ getDropAction : function TabbarDND_getDropAction(aEvent, aDragSession)
+ {
+ var sv = this.treeStyleTab;
+ var b = this.browser;
+
+ if (!aDragSession)
+ aDragSession = sv.currentDragSession;
+
+ var tab = aDragSession ? sv.getTabFromChild(aDragSession.sourceNode) : null ;
+ sv.ensureTabInitialized(tab);
+
+ var info = this.getDropActionInternal(aEvent, tab);
+ info.canDrop = true;
+ info.source = tab;
+ if (tab) {
+ var isCopy = sv.isCopyAction(aEvent);
+ if (isCopy && 'duplicateTab' in b) {
+ info.action |= sv.kACTION_DUPLICATE;
+ }
+ if (
+ !isCopy &&
+ sv.getTabBrowserFromChild(tab) != b &&
+ (
+ ('duplicateTab' in b)
+ )
+ ) {
+ info.action |= sv.kACTION_IMPORT;
+ }
+
+ if (info.action & sv.kACTIONS_FOR_DESTINATION) {
+ if (info.action & sv.kACTION_MOVE) info.action ^= sv.kACTION_MOVE;
+ if (info.action & sv.kACTION_STAY) info.action ^= sv.kACTION_STAY;
+ }
+
+ if (info.action & sv.kACTION_ATTACH) {
+ if (info.parent == tab) {
+ info.canDrop = false;
+ }
+ else {
+ var orig = tab;
+ tab = info.target;
+ while (tab = sv.getParentTab(tab))
+ {
+ if (tab != orig) continue;
+ info.canDrop = false;
+ break;
+ }
+ }
+ }
+ }
+
+ var isInverted = sv.isVertical ? false : b.ownerDocument.defaultView.getComputedStyle(b.parentNode, null).direction == 'rtl';
+ if (
+ info.target &&
+ (
+ info.target.hidden ||
+ (
+ sv.isCollapsed(info.target) &&
+ info.position != (isInverted ? sv.kDROP_BEFORE : sv.kDROP_AFTER )
+ )
+ )
+ )
+ info.canDrop = false;
+
+ return info;
+ },
+
+ getDropActionInternal : function TabbarDND_getDropActionInternal(aEvent, aSourceTab)
+ {
+ if (DEBUG) dump('getDropActionInternal: start\n');
+ var sv = this.treeStyleTab;
+ var b = this.browser;
+ var d = this.document;
+
+ var tab = sv.getTabFromEvent(aEvent) || sv.getTabFromTabbarEvent(aEvent) || aEvent.target;
+ var tabs = sv.getTabs(b);
+ var firstTab = sv.getFirstNormalTab(b) || tabs[0];
+ var lastTabIndex = tabs.length - 1;
+ var isInverted = sv.isVertical ? false : b.ownerDocument.defaultView.getComputedStyle(b.parentNode, null).direction == 'rtl';
+ var info = {
+ target : null,
+ position : null,
+ action : null,
+ parent : null,
+ insertBefore : null,
+ event : aEvent
+ };
+
+ let draggedTab = aEvent.dataTransfer && aEvent.dataTransfer.mozGetDataAt(TAB_DROP_TYPE, 0);
+ if (draggedTab && draggedTab._dragData) {
+ // "draggedTab._dragData.animDropIndex" means the actual "_tPos"
+ // of the drop target, so we have to use the array of all
+ // (including hidden) tabs here.
+ let tabs = sv.getAllTabs(b);
+ let sameTypeUndraggedTabs = tabs.filter(function(aTab) {
+ return !aTab._dragData && aTab.pinned == draggedTab.pinned;
+ });
+ tab = draggedTab.pinned ?
+ // pinned tabs cannot be dropped to another pinned tab, so
+ // we can use the drop position calculated by "_animateTabMove()".
+ tabs[draggedTab._dragData.animDropIndex] :
+ // otherwise, we have to find "drop target" tab from screen coordinates.
+ sv.getTabFromCoordinates(aEvent, sameTypeUndraggedTabs) ||
+ tabs[draggedTab._dragData.animDropIndex] ;
+ }
+
+ var isTabMoveFromOtherWindow = aSourceTab && aSourceTab.ownerDocument != d;
+ var isNewTabAction = !aSourceTab || aSourceTab.ownerDocument != d;
+
+ if (!tab || tab.localName != 'tab') {
+ if (DEBUG) dump(' not on a tab\n');
+ let action = isTabMoveFromOtherWindow ? sv.kACTION_STAY : (sv.kACTION_MOVE | sv.kACTION_PART) ;
+ if (isNewTabAction) action |= sv.kACTION_NEWTAB;
+ if (aEvent[sv.screenPositionProp] < sv.getTabActualScreenPosition(firstTab)) {
+ if (DEBUG) dump(' above the first tab\n');
+ info.target = info.parent = info.insertBefore = firstTab;
+ info.position = isInverted ? sv.kDROP_AFTER : sv.kDROP_BEFORE ;
+ info.action = action;
+ return info;
+ }
+ else if (aEvent[sv.screenPositionProp] > sv.getTabActualScreenPosition(tabs[lastTabIndex]) + tabs[lastTabIndex].boxObject[sv.sizeProp]) {
+ if (DEBUG) dump(' below the last tab\n');
+ info.target = info.parent = tabs[lastTabIndex];
+ info.position = isInverted ? sv.kDROP_BEFORE : sv.kDROP_AFTER ;
+ info.action = action;
+ return info;
+ }
+ else {
+ let index = b.getNewIndex ?
+ b.getNewIndex(aEvent) :
+ b.tabContainer._getDropIndex(aEvent) ;
+ if (DEBUG) dump(' on the tab '+index+'\n');
+ index = Math.min(index, lastTabIndex);
+ info.target = tab = tabs[index];
+ if (index == tabs[lastTabIndex]._tPos) {
+ if (index > 0)
+ info.target = tab = tabs[index - 1];
+ info.position = sv.kDROP_AFTER;
+ if (DEBUG) dump(' => after the last tab\n');
+ } else if (index == firstTab._tPos) {
+ if (index < lastTabIndex - 1)
+ info.target = tab = tabs[index + 1];
+ info.position = sv.kDROP_BEFORE;
+ if (DEBUG) dump(' => before the first tab\n');
+ }
+ if (DEBUG) dump(' info.target = ' + info.target._tPos + '\n');
+ }
+ }
+ else {
+ if (DEBUG) dump(' on the tab '+tab._tPos+'\n');
+ sv.ensureTabInitialized(tab);
+ info.target = tab;
+ }
+
+ /**
+ * Basically, tabs should have three areas for dropping of items:
+ * [start][center][end], but, pinned tabs couldn't have its tree.
+ * So, if a tab is dragged and the target tab is pinned, then, we
+ * have to ignore the [center] area.
+ */
+ var pinned = tab.getAttribute('pinned') == 'true';
+ var dropAreasCount = (aSourceTab && pinned) ? 2 : 3 ;
+ var screenPositionProp = sv.isVertical && pinned ? sv.invertedScreenPositionProp : sv.screenPositionProp ;
+ var sizeProp = sv.isVertical && pinned ? sv.invertedSizeProp : sv.sizeProp ;
+ var orient = pinned ? 'horizontal' : null ;
+ var boxPos = sv.getTabActualScreenPosition(tab, orient);
+ var boxUnit = Math.round(tab.boxObject[sizeProp] / dropAreasCount);
+ var eventPosition = aEvent[screenPositionProp];
+// if (this.window['piro.sakura.ne.jp'].tabsDragUtils
+// .canAnimateDraggedTabs(aEvent)) {
+// eventPosition = Math.round(sv.getTabActualScreenPosition(draggedTab) + (tab.boxObject[sizeProp] / 2))
+// }
+ if (eventPosition < boxPos + boxUnit) {
+ info.position = isInverted ? sv.kDROP_AFTER : sv.kDROP_BEFORE ;
+ }
+ else if (dropAreasCount == 2 || eventPosition > boxPos + boxUnit + boxUnit) {
+ info.position = isInverted ? sv.kDROP_BEFORE : sv.kDROP_AFTER ;
+ }
+ else {
+ info.position = sv.kDROP_ON;
+ }
+
+ switch (info.position)
+ {
+ case sv.kDROP_ON:
+ if (DEBUG) dump(' position = on the tab\n');
+ var visible = sv.getNextVisibleTab(tab);
+ info.action = sv.kACTION_STAY | sv.kACTION_ATTACH;
+ info.parent = tab;
+ info.insertBefore = utils.getTreePref('insertNewChildAt') == sv.kINSERT_FISRT ?
+ (sv.getFirstChildTab(tab) || visible) :
+ (sv.getNextSiblingTab(tab) || sv.getNextTab(sv.getLastDescendantTab(tab) || tab));
+ if (DEBUG && info.insertBefore) dump(' insertBefore = '+info.insertBefore._tPos+'\n');
+ break;
+
+ case sv.kDROP_BEFORE:
+ if (DEBUG) dump(' position = before the tab\n');
+/*
+ <= detach from parent, and move
+ [TARGET ]
+
+ [ ]
+ <= attach to the parent of the target, and move
+ [TARGET ]
+
+ [ ]
+ <= attach to the parent of the target, and move
+ [TARGET ]
+
+ [ ]
+ <= attach to the parent of the target (previous tab), and move
+ [TARGET]
+*/
+ var prevTab = sv.getPreviousVisibleTab(tab);
+ if (!prevTab) {
+ // allow to drop pinned tab to beside of another pinned tab
+ if (aSourceTab && aSourceTab.getAttribute('pinned') == 'true') {
+ info.action = sv.kACTION_MOVE;
+ info.insertBefore = tab;
+ }
+ else {
+ info.action = sv.kACTION_MOVE | sv.kACTION_PART;
+ info.insertBefore = firstTab;
+ }
+ }
+ else {
+ var prevLevel = Number(prevTab.getAttribute(sv.kNEST));
+ var targetNest = Number(tab.getAttribute(sv.kNEST));
+ info.parent = (prevLevel < targetNest) ? prevTab : sv.getParentTab(tab) ;
+ info.action = sv.kACTION_MOVE | (info.parent ? sv.kACTION_ATTACH : sv.kACTION_PART );
+ info.insertBefore = tab;
+ }
+ if (DEBUG && info.insertBefore) dump(' insertBefore = '+info.insertBefore._tPos+'\n');
+ break;
+
+ case sv.kDROP_AFTER:
+ if (DEBUG) dump(' position = after the tab\n');
+/*
+ [TARGET ]
+ <= if the target has a parent, attach to it and and move
+
+ [TARGET]
+ <= attach to the parent of the target, and move
+ [ ]
+
+ [TARGET ]
+ <= attach to the parent of the target, and move
+ [ ]
+
+ [TARGET ]
+ <= attach to the target, and move
+ [ ]
+*/
+ var nextTab = sv.getNextVisibleTab(tab);
+ if (!nextTab) {
+ info.action = sv.kACTION_MOVE | sv.kACTION_ATTACH;
+ info.parent = sv.getParentTab(tab);
+ }
+ else {
+ var targetNest = Number(tab.getAttribute(sv.kNEST));
+ var nextLevel = Number(nextTab.getAttribute(sv.kNEST));
+ info.parent = (targetNest < nextLevel) ? tab : sv.getParentTab(tab) ;
+ info.action = sv.kACTION_MOVE | (info.parent ? sv.kACTION_ATTACH : sv.kACTION_PART );
+ info.insertBefore = nextTab;
+/*
+ [TARGET ]
+ <= attach dragged tab to the parent of the target as its next sibling
+ [DRAGGED]
+*/
+ if (aSourceTab == nextTab) {
+ info.action = sv.kACTION_MOVE | sv.kACTION_ATTACH;
+ info.parent = sv.getParentTab(tab);
+ info.insertBefore = sv.getNextSiblingTab(tab);
+ let ancestor = info.parent;
+ while (ancestor && !info.insertBefore) {
+ info.insertBefore = sv.getNextSiblingTab(ancestor);
+ ancestor = sv.getParentTab(ancestor);
+ }
+ }
+ }
+ if (DEBUG && info.insertBefore) dump(' insertBefore = '+info.insertBefore._tPos+'\n');
+ break;
+ }
+
+ if (isNewTabAction) info.action |= sv.kACTION_NEWTAB;
+
+ return info;
+ },
+
+ performDrop : function TabbarDND_performDrop(aInfo, aDraggedTab)
+ {
+ if (DEBUG) dump('performDrop: start\n');
+ var sv = this.treeStyleTab;
+ var b = this.browser;
+ var w = this.window;
+
+ var tabsInfo = this.getDraggedTabsInfoFromOneTab(aDraggedTab, aInfo);
+ if (!tabsInfo.draggedTab) {
+ if (DEBUG) dump(' => no dragged tab\n');
+ return false;
+ }
+
+ var sourceWindow = aDraggedTab.ownerDocument.defaultView;
+ var sourceBrowser = sourceWindow.TreeStyleTabService.getTabBrowserFromChild(aDraggedTab);
+ var sourceService = sourceBrowser.treeStyleTab;
+
+ aDraggedTab = tabsInfo.draggedTab;
+ var draggedTabs = tabsInfo.draggedTabs;
+ var draggedRoots = sourceService.collectRootTabs(tabsInfo.draggedTabs);
+
+
+ var targetBrowser = b;
+ var tabs = sv.getTabs(targetBrowser);
+
+ var draggedWholeTree = [].concat(draggedRoots);
+ for (let i = 0, maxi = draggedRoots.length; i < maxi; i++)
+ {
+ let root = draggedRoots[i];
+ let tabs = sourceService.getDescendantTabs(root);
+ for (let i = 0, maxi = tabs.length; i < maxi; i++)
+ {
+ let tab = tabs[i];
+ if (draggedWholeTree.indexOf(tab) < 0)
+ draggedWholeTree.push(tab);
+ }
+ }
+
+ var selectedTabs = draggedTabs.filter(function(aTab) {
+ return aTab.getAttribute('multiselected') == 'true';
+ });
+ if (draggedWholeTree.length != selectedTabs.length &&
+ selectedTabs.length) {
+ draggedTabs = draggedRoots = selectedTabs;
+ if (aInfo.action & sv.kACTIONS_FOR_SOURCE)
+ sourceService.detachTabs(selectedTabs);
+ }
+
+ while (aInfo.insertBefore && draggedWholeTree.indexOf(aInfo.insertBefore) > -1)
+ {
+ aInfo.insertBefore = sv.getNextTab(aInfo.insertBefore);
+ }
+
+ if (aInfo.action & sv.kACTIONS_FOR_SOURCE) {
+ if (aInfo.action & sv.kACTION_PART) {
+ this.detachTabsOnDrop(draggedRoots);
+ }
+ else if (aInfo.action & sv.kACTION_ATTACH) {
+ this.attachTabsOnDrop(draggedRoots, aInfo.parent);
+ }
+ // otherwise, just moved.
+
+ if ( // if this move will cause no change...
+ sourceBrowser == targetBrowser &&
+ sourceService.getNextVisibleTab(draggedTabs[draggedTabs.length-1]) == aInfo.insertBefore
+ ) {
+ if (DEBUG) dump(' => no change\n');
+ // then, do nothing
+ return true;
+ }
+ }
+
+ var treeStructure = sourceService.getTreeStructureFromTabs(draggedTabs);
+
+ var newTabs = sv.moveTabsInternal(draggedTabs, {
+ duplicate : aInfo.action & sv.kACTION_DUPLICATE,
+ insertBefore : aInfo.insertBefore
+ });
+
+ if (newTabs.length && aInfo.action & sv.kACTION_ATTACH)
+ this.attachTabsOnDrop(
+ newTabs.filter(function(aTab, aIndex) {
+ return treeStructure[aIndex] == -1;
+ }),
+ aInfo.parent
+ );
+
+ return true;
+ },
+
+ getDraggedTabsInfoFromOneTab : function TabbarDND_getDraggedTabsInfoFromOneTab(aTab, aInfo)
+ {
+ aInfo = aInfo || {};
+ if (aInfo.draggedTabsInfo)
+ return aInfo.draggedTabsInfo;
+
+ var sv = this.treeStyleTab;
+ var sourceWindow = aTab.ownerDocument.defaultView;
+ var sourceBrowser = sourceWindow.TreeStyleTabService.getTabBrowserFromChild(aTab);
+ var sourceService = sourceBrowser.treeStyleTab;
+
+ aTab = sourceService.getTabFromChild(aTab);
+ if (!aTab || !aTab.parentNode) // ignore removed tabs!
+ return {
+ draggedTab : null,
+ draggedTabs : [],
+ isMultipleMove : false
+ };
+
+ var draggedTabs = sourceWindow['piro.sakura.ne.jp'].tabsDragUtils.getSelectedTabs(aTab || sourceBrowser || aInfo.event);
+ var isMultipleMove = false;
+
+ if (draggedTabs.length > 1) {
+ isMultipleMove = true;
+ }
+ else if (aInfo.action & sv.kACTIONS_FOR_DESTINATION) {
+ draggedTabs = [aTab].concat(sourceService.getDescendantTabs(aTab));
+ }
+
+ return {
+ draggedTab : aTab,
+ draggedTabs : draggedTabs,
+ isMultipleMove : isMultipleMove
+ };
+ },
+
+ attachTabsOnDrop : function TabbarDND_attachTabsOnDrop(aTabs, aParent)
+ {
+ var b = aTabs[0].ownerDocument.defaultView.TreeStyleTabService.getTabBrowserFromChild(aTabs[0]);
+ var sv = b.treeStyleTab;
+
+ b.movingSelectedTabs = true; // Multiple Tab Handler
+ for (let i = 0, maxi = aTabs.length; i < maxi; i++)
+ {
+ let tab = aTabs[i];
+ if (!tab.parentNode) continue; // ignore removed tabs
+ if (aParent)
+ sv.attachTabTo(tab, aParent);
+ else
+ sv.detachTab(tab);
+ sv.collapseExpandTab(tab, false);
+ }
+ b.movingSelectedTabs = false; // Multiple Tab Handler
+ },
+
+ detachTabsOnDrop : function TabbarDND_detachTabsOnDrop(aTabs)
+ {
+ var b = aTabs[0].ownerDocument.defaultView.TreeStyleTabService.getTabBrowserFromChild(aTabs[0]);
+ var sv = b.treeStyleTab;
+
+ b.movingSelectedTabs = true; // Multiple Tab Handler
+ for (let i = 0, maxi = aTabs.length; i < maxi; i++)
+ {
+ let tab = aTabs[i];
+ if (!tab.parentNode) continue; // ignore removed tabs
+ sv.detachTab(tab);
+ sv.collapseExpandTab(tab, false);
+ }
+ b.movingSelectedTabs = false; // Multiple Tab Handler
+ },
+
+ clearDropPosition : function TabbarDND_clearDropPosition(aOnFinish)
+ {
+ var sv = this.treeStyleTab;
+ var b = this.browser;
+
+ b.visibleTabs.forEach(function(aTab) {
+ if (aTab.hasAttribute(sv.kDROP_POSITION))
+ aTab.removeAttribute(sv.kDROP_POSITION)
+
+ if (aOnFinish) {
+ aTab.style.transform = '';
+ if ('__treestyletab__opacityBeforeDragged' in aTab) {
+ aTab.style.opacity = aTab.__treestyletab__opacityBeforeDragged;
+ delete aTab.__treestyletab__opacityBeforeDragged;
+ }
+ }
+ });
+
+ if (aOnFinish)
+ this.browser.mTabContainer.removeAttribute('movingtab')
+ },
+
+ isDraggingAllTabs : function TabbarDND_isDraggingAllTabs(aTab, aTabs)
+ {
+ var sv = this.treeStyleTab;
+ var b = this.browser;
+
+ var actionInfo = {
+ action : sv.kACTIONS_FOR_DESTINATION | sv.kACTION_IMPORT
+ };
+ var tabsInfo = this.getDraggedTabsInfoFromOneTab(aTab, actionInfo);
+ return tabsInfo.draggedTabs.length == (aTabs || sv.getAllTabs(b)).length;
+ },
+
+ isDraggingAllCurrentTabs : function TabbarDND_isDraggingAllCurrentTabs(aTab)
+ {
+ return this.isDraggingAllTabs(aTab, this.treeStyleTab.getTabs(this.treeStyleTab.browser));
+ },
+
+ handleEvent : function TabbarDND_handleEvent(aEvent)
+ {
+ // ignore drag and drop while toolbar customization
+ if (this.treeStyleTab.isToolbarCustomizing)
+ return;
+
+ switch (aEvent.type)
+ {
+ case 'dragstart': return this.onDragStart(aEvent);
+ case 'dragenter': return this.onDragEnter(aEvent);
+ case 'dragleave': return this.onDragLeave(aEvent);
+ case 'dragend': return this.onDragEnd(aEvent);
+ case 'dragover': return this.onDragOver(aEvent);
+ case 'drop': return this.onDrop(aEvent);
+ }
+ },
+
+ onDragStart : function TabbarDND_onDragStart(aEvent)
+ {
+ if (this.canDragTabbar(aEvent))
+ return this.onTabbarDragStart(aEvent);
+
+ var tab = this.treeStyleTab.getTabFromEvent(aEvent);
+ if (tab)
+ return this.onTabDragStart(aEvent, tab);
+ },
+
+ onTabDragStart : function TabbarDND_onTabDragStart(aEvent, aTab)
+ {
+ var sv = this.treeStyleTab;
+ var w = this.window;
+ var actionInfo = {
+ action : sv.kACTIONS_FOR_DESTINATION | sv.kACTION_MOVE,
+ event : aEvent
+ };
+ var tabsInfo = this.getDraggedTabsInfoFromOneTab(aTab, actionInfo);
+ if (
+ tabsInfo.draggedTabs.length <= 1 ||
+ Array.some(tabsInfo.draggedTabs, function(aTab) {
+ return aTab.getAttribute('multiselected') == 'true'; // if multiselected, it should be handled by other addons (like Multiple Tab Handler)
+ })
+ )
+ return;
+
+ w['piro.sakura.ne.jp'].tabsDragUtils.startTabsDrag(aEvent, tabsInfo.draggedTabs);
+ },
+
+ onTabbarDragStart : function TabbarDND_onTabbarDragStart(aEvent)
+ {
+ var sv = this.treeStyleTab;
+ var dt = aEvent.dataTransfer;
+ dt.mozSetDataAt(
+ sv.kDRAG_TYPE_TABBAR,
+ aEvent.shiftKey ?
+ sv.kTABBAR_MOVE_FORCE :
+ sv.kTABBAR_MOVE_NORMAL,
+ 0
+ );
+ dt.mozCursor = 'move';
+// var tabbar = sv.browser.mTabContainer;
+// var box = tabbar.boxObject;
+// dt.setDragImage(
+// tabbar,
+// aEvent.screenX - box.screenX,
+// aEvent.screenY - box.screenY
+// );
+ // no feedback image, because it's annoying...
+ dt.setDragImage(new this.window.Image(), 0, 0);
+ aEvent.stopPropagation();
+ this.readyToStartTabbarDrag();
+ },
+
+ onDragEnter : function TabbarDND_onDragEnter(aEvent)
+ {
+ var sv = this.treeStyleTab;
+ var w = this.window;
+
+ var dt = aEvent.dataTransfer;
+ if (!this.canDrop(aEvent)) {
+ dt.effectAllowed = dt.dropEffect = 'none';
+ return;
+ }
+
+ var tab = aEvent.target;
+ if (tab.localName != 'tab' ||
+ !utils.getTreePref('autoExpand.enabled'))
+ return;
+
+ w.clearTimeout(this.mAutoExpandTimer);
+ w.clearTimeout(this.mAutoExpandTimerNext);
+
+ var sourceNode = dt.getData(sv.kDRAG_TYPE_TABBAR+'-node');
+ if (aEvent.target == sourceNode)
+ return;
+
+ var draggedTab = dt.mozGetDataAt(TAB_DROP_TYPE, 0);
+ this.mAutoExpandTimerNext = w.setTimeout(function(aSelf, aTarget, aDragged) {
+ aSelf.mAutoExpandTimerNext = null;
+ aSelf.mAutoExpandTimer = w.setTimeout(
+ function() {
+ let tab = sv.getTabById(aTarget);
+ if (tab &&
+ sv.shouldTabAutoExpanded(tab) &&
+ tab.getAttribute(sv.kDROP_POSITION) == 'self') {
+ let draggedTab = aDragged && sv.getTabById(aDragged);
+ if (utils.getTreePref('autoExpand.intelligently')) {
+ sv.collapseExpandTreesIntelligentlyFor(tab);
+ if (draggedTab)
+ aSelf.updateDragData(draggedTab);
+ }
+ else {
+ if (aSelf.mAutoExpandedTabs.indexOf(aTarget) < 0)
+ aSelf.mAutoExpandedTabs.push(aTarget);
+ sv.collapseExpandSubtree(tab, false);
+ if (draggedTab)
+ aSelf.updateDragData(draggedTab);
+ }
+ }
+ },
+ utils.getTreePref('autoExpand.delay')
+ );
+ }, 0, this, tab.getAttribute(sv.kID), draggedTab && draggedTab.getAttribute(sv.kID));
+
+ tab = null;
+ },
+ updateDragData : function TabbarDND_updateDragData(aTab)
+ {
+ if (!aTab || !aTab._dragData) return;
+ var sv = this.treeStyleTab;
+ var data = aTab._dragData;
+ var offsetX = sv.getXOffsetOfTab(aTab);
+ var offsetY = sv.getYOffsetOfTab(aTab);
+ if ('offsetX' in data) data.offsetX += offsetX;
+ if ('screenX' in data) data.screenX += offsetX;
+ if ('offsetY' in data) data.offsetY += offsetY;
+ if ('screenY' in data) data.screenY += offsetY;
+ },
+
+ onDragLeave : function TabbarDND_onDragLeave(aEvent)
+ {
+ this.clearDropPosition();
+
+ this.window.clearTimeout(this.mAutoExpandTimer);
+ this.mAutoExpandTimer = null;
+ },
+
+ onDragEnd : function TabbarDND_onDragEnd(aEvent)
+ {
+ var sv = this.treeStyleTab;
+ var dt = aEvent.dataTransfer;
+ if (dt.getData(sv.kDRAG_TYPE_TABBAR))
+ this.onTabbarDragEnd(aEvent);
+ else
+ this.onTabDragEnd(aEvent);
+ },
+
+ onTabDragEnd : function TabbarDND_onTabDragEnd(aEvent)
+ {
+ var sv = this.treeStyleTab;
+ var b = this.browser;
+ var d = this.document;
+ var w = this.window;
+
+ var tabbar = b.mTabContainer;
+ var strip = sv.tabStrip;
+ var dt = aEvent.dataTransfer;
+
+ this.clearDropPosition(true);
+ this.collapseAutoExpandedTabs();
+
+ if (dt.mozUserCancelled || dt.dropEffect != 'none')
+ return;
+
+ // prevent handling of this event by the default handler
+ aEvent.stopPropagation();
+ aEvent.preventDefault();
+
+ var eX = aEvent.screenX;
+ var eY = aEvent.screenY;
+ var x, y, w, h;
+
+ // ignore drop on the toolbox
+ x = w.screenX;
+ y = w.screenY;
+ w = w.outerWidth;
+ h = d.getElementById('navigator-toolbox').boxObject.height;
+ if (eX > x && eX < x + w && eY > y && eY < y + h)
+ return;
+
+ // ignore drop near the tab bar
+ var box = strip.boxObject;
+ var ignoreArea = Math.max(16, parseInt(sv.getFirstNormalTab(b).boxObject.height / 2));
+ x = box.screenX - (sv.isVertical ? ignoreArea : 0 );
+ y = box.screenY - ignoreArea;
+ w = box.width + (sv.isVertical ? ignoreArea + ignoreArea : 0 );
+ h = box.height + ignoreArea + ignoreArea;
+ if (eX > x && eX < x + w && eY > y && eY < y + h)
+ return;
+
+ var draggedTab = dt.mozGetDataAt(TAB_DROP_TYPE, 0);
+ if (this.isDraggingAllCurrentTabs(draggedTab))
+ return;
+
+ // Respect the behaviour of "Disable detach and tear off tab"
+ // https://addons.mozilla.org/firefox/addon/bug489729-disable-detach-and-t/
+ if ('bug489729' in this.window &&
+ prefs.getPref('extensions.bug489729.disable_detach_tab'))
+ return;
+
+ if (aEvent.ctrlKey || aEvent.metaKey)
+ draggedTab.__treestyletab__toBeDuplicated = true;
+
+ b.replaceTabWithWindow(draggedTab);
+ },
+
+ onTabbarDragEnd : function TabbarDND_onTabbarDragEnd(aEvent)
+ {
+ var w = this.window;
+ w.setTimeout(function(aSelf) {
+ aSelf.readyToEndTabbarDrag();
+ aSelf.treeStyleTab.removeTabbrowserAttribute(aSelf.treeStyleTab.kDROP_POSITION);
+ }, 10, this);
+ aEvent.stopPropagation();
+ aEvent.preventDefault();
+ },
+
+ onDragOver : function TabbarDND_onDragOver(aEvent)
+ {
+ if (this.onTabDragOver(aEvent)) {
+ aEvent.stopPropagation();
+ aEvent.preventDefault(); // this is required to override default dragover actions!
+ }
+ },
+
+ onTabDragOver : function TabbarDND_onTabDragOver(aEvent)
+ {
+try{
+ var sv = this.treeStyleTab;
+ var b = this.browser;
+ var tabbar = b.mTabContainer;
+
+ var session = sv.currentDragSession;
+ if (sv.isToolbarCustomizing)
+ return false;
+
+ sv.autoScroll.processAutoScroll(aEvent);
+
+ let draggedTab = aEvent.dataTransfer && aEvent.dataTransfer.mozGetDataAt(TAB_DROP_TYPE, 0);
+ let dragOverTab = sv.getTabFromEvent(aEvent) || sv.getTabFromTabbarEvent(aEvent) || aEvent.target;
+ b.ownerDocument.defaultView['piro.sakura.ne.jp'].tabsDragUtils
+ .processTabsDragging(aEvent, {
+ canDropOnSelf : !dragOverTab || !dragOverTab.pinned,
+ isVertical : (
+ b.ownerDocument.defaultView['piro.sakura.ne.jp'].tabsDragUtils.isVertical(b.tabContainer) &&
+ (
+ (draggedTab && !draggedTab.pinned) ||
+ !utils.getTreePref('pinnedTab.faviconized')
+ )
+ )
+ });
+
+ /**
+ * We must calculate drop action after tabsDragUtils.processTabsDragging(),
+ * because the drop position depends on tabs' actual
+ * positions (which can be changed by animation effects.)
+ */
+ var info = this.getDropAction(aEvent, session);
+
+ var observer = b;
+ if (b.tabContainer && b.tabContainer._setEffectAllowedForDataTransfer)
+ observer = b.tabContainer;
+
+ // auto-switch for staying on tabs
+ if (
+ info.position == sv.kDROP_ON &&
+ info.target &&
+ !info.target.selected &&
+ '_dragTime' in observer && '_dragOverDelay' in observer
+ ) {
+ let time = observer.mDragTime || observer._dragTime || 0;
+ let delay = observer.mDragOverDelay || observer._dragOverDelay || 0;
+ let effects = observer._setEffectAllowedForDataTransfer(aEvent);
+ if (effects == 'link') {
+ let now = Date.now();
+ if (!time) {
+ time = now;
+ if ('mDragTime' in observer)
+ observer.mDragTime = time;
+ else
+ observer._dragTime = time;
+ }
+ if (now >= time + delay)
+ b.selectedTab = info.target;
+ }
+ }
+
+ if (
+ !info.canDrop ||
+ observer._setEffectAllowedForDataTransfer(aEvent) == 'none'
+ ) {
+ aEvent.dataTransfer.effectAllowed = "none";
+ this.clearDropPosition();
+ return true;
+ }
+
+ let indicatorTab = info.target;
+ if (sv.isCollapsed(info.target)) {
+ let tab = indicatorTab;
+ while ((tab = sv.getPreviousTab(tab)) && sv.isCollapsed(tab)) {}
+ if (tab) indicatorTab = tab;
+ }
+
+ let dropPosition = info.position == sv.kDROP_BEFORE ? 'before' :
+ info.position == sv.kDROP_AFTER ? 'after' :
+ 'self';
+ if (indicatorTab != draggedTab &&
+ indicatorTab.getAttribute(sv.kDROP_POSITION) != dropPosition) {
+ this.clearDropPosition();
+ indicatorTab.setAttribute(sv.kDROP_POSITION, dropPosition);
+ if (b.ownerDocument.defaultView['piro.sakura.ne.jp'].tabsDragUtils
+ .canAnimateDraggedTabs(aEvent)) {
+ let newOpacity = dropPosition == 'self' ? 0.35 : 0.75 ; // to prevent the dragged tab hides the drop target itself
+ this.window['piro.sakura.ne.jp'].tabsDragUtils.getDraggedTabs(aEvent).forEach(function(aTab) {
+ if (!('__treestyletab__opacityBeforeDragged' in aTab))
+ aTab.__treestyletab__opacityBeforeDragged = aTab.style.opacity || '';
+ aTab.style.opacity = newOpacity;
+ });
+ }
+ }
+
+
+ var indicator = b.mTabDropIndicatorBar || b.tabContainer._tabDropIndicator;
+ indicator.setAttribute('dragging', (info.position == sv.kDROP_ON || sv.isVertical) ? 'false' : 'true' );
+ if (sv.isVertical)
+ indicator.collapsed = true;
+
+ return (info.position == sv.kDROP_ON || sv.position != 'top')
+}
+catch(e) {
+ dump('TabbarDND::onDragOver\n'+e+'\n');
+}
+ },
+
+ onDrop : function TabbarDND_onDrop(aEvent)
+ {
+ this.onTabDrop(aEvent);
+ this.collapseAutoExpandedTabs();
+ },
+ collapseAutoExpandedTabs : function TabbarDND_collapseAutoExpandedTabs()
+ {
+ var sv = this.treeStyleTab;
+ if (this.mAutoExpandedTabs.length) {
+ if (utils.getTreePref('autoExpand.collapseFinally')) {
+ for (let i = 0, maxi = this.mAutoExpandedTabs.length; i < maxi; i++)
+ {
+ sv.collapseExpandSubtree(sv.getTabById(this.mAutoExpandedTabs[i]), true, true);
+ }
+ }
+ this.mAutoExpandedTabs = [];
+ }
+ },
+
+ onTabDrop : function TSTService_onTabDrop(aEvent)
+ {
+ var sv = this.treeStyleTab;
+ var b = this.browser;
+ var w = this.window;
+
+ var tabbar = b.mTabContainer;
+ var dt = aEvent.dataTransfer;
+
+ /**
+ * We must calculate drop action before clearing "dragging"
+ * state, because the drop position depends on tabs' actual
+ * positions (they are applied only while tab dragging.)
+ */
+ var session = sv.currentDragSession;
+ var dropActionInfo = this.getDropAction(aEvent, session);
+
+ this.clearDropPosition(true);
+ if (tabbar._tabDropIndicator)
+ tabbar._tabDropIndicator.collapsed = true;
+
+ var draggedTab = dt.mozGetDataAt(TAB_DROP_TYPE, 0);
+ if (dt.dropEffect != 'link' && !draggedTab) {
+ aEvent.stopPropagation();
+ return;
+ }
+
+ var sourceBrowser = sv.getTabBrowserFromChild(draggedTab);
+ if (draggedTab && sourceBrowser != b)
+ sourceBrowser.treeStyleTab.tabbarDNDObserver.clearDropPosition(true);
+
+ if (draggedTab && this.performDrop(dropActionInfo, draggedTab)) {
+ aEvent.stopPropagation();
+ return;
+ }
+
+ // duplicating of tabs
+ if (
+ draggedTab &&
+ (
+ dt.dropEffect == 'copy' ||
+ sourceBrowser != b
+ ) &&
+ dropActionInfo.position == sv.kDROP_ON
+ ) {
+ var beforeTabs = Array.slice(b.mTabContainer.childNodes);
+ w.setTimeout(function() {
+ var newTabs = Array.slice(b.mTabContainer.childNodes).filter(function(aTab) {
+ return beforeTabs.indexOf(aTab) < 0;
+ });
+ if (newTabs.length)
+ sv.attachTabTo(newTabs[0], dropActionInfo.target);
+ }, 0);
+ return;
+ }
+
+ if (!draggedTab)
+ this.handleLinksOrBookmarks(aEvent, dropActionInfo);
+ },
+ handleLinksOrBookmarks : function TabbarDND_handleLinksOrBookmarks(aEvent, aDropActionInfo)
+ {
+ aEvent.stopPropagation();
+
+ var uris = this.retrieveURLsFromDataTransfer(aEvent.dataTransfer);
+ uris.forEach(function(aURI) {
+ if (aURI.indexOf(this.BOOKMARK_FOLDER) != 0)
+ this.securityCheck(aURI, aEvent);
+ }, this);
+
+ var sv = this.treeStyleTab;
+ var b = this.browser;
+ var w = this.window;
+ var self = this;
+
+ let bgLoad = prefs.getPref('browser.tabs.loadInBackground');
+ if (aEvent.shiftKey) bgLoad = !bgLoad;
+
+ let tab = sv.getTabFromEvent(aEvent);
+ if (
+ !tab ||
+ aEvent.dataTransfer.dropEffect == 'copy' ||
+ uris.length > 1 ||
+ uris[0].indexOf(this.BOOKMARK_FOLDER) == 0
+ ) {
+ uris.reverse().forEach(function(aURI) {
+ if (aURI.indexOf(this.BOOKMARK_FOLDER) == 0) {
+ let newTabs = sv.getNewTabsWithOperation(function() {
+ var data = aURI.replace(self.BOOKMARK_FOLDER, '');
+ data = JSON.parse(data);
+ w.PlacesUIUtils._openTabset(data.children, { type : 'drop' }, w, data.title);
+ }, b);
+ aDropActionInfo.draggedTabsInfo = {
+ draggedTabs : newTabs,
+ draggedTab : newTabs[0],
+ isMultipleMove : newTabs.length > 1
+ };
+ this.performDrop(aDropActionInfo, newTabs[0]);
+ }
+ else {
+ aURI = utils.getShortcutOrURI(w, aURI);
+ this.performDrop(aDropActionInfo, b.loadOneTab(aURI, { inBackground: bgLoad }));
+ }
+ }, this);
+ }
+ else {
+ let locked = (
+ tab.getAttribute('locked') == 'true' || // Tab Mix Plus and others
+ tab.getAttribute('isPageLocked') == 'true' // Super Tab Mode
+ );
+ let loadDroppedLinkToNewChildTab = aDropActionInfo.position != sv.kDROP_ON || locked;
+ if (!loadDroppedLinkToNewChildTab &&
+ aDropActionInfo.position == sv.kDROP_ON)
+ loadDroppedLinkToNewChildTab = sv.dropLinksOnTabBehavior() == sv.kDROPLINK_NEWTAB;
+
+ try {
+ let uri = utils.getShortcutOrURI(w, uris[0]);
+ if (loadDroppedLinkToNewChildTab || locked) {
+ this.performDrop(aDropActionInfo, b.loadOneTab(uri, { inBackground: bgLoad }));
+ }
+ else {
+ tab.linkedBrowser.loadURI(uri);
+ if (!bgLoad)
+ b.selectedTab = tab;
+ }
+ }
+ catch(e) {
+ }
+ }
+ },
+ securityCheck : function TabbarDND_securityCheck(aURI, aEvent)
+ {
+ // See dragDropSecurityCheck() in chrome://global/content/nsDragAndDrop.js
+ let session = this.treeStyleTab.currentDragSession;
+ if (!session) { //TODO: use some fake nodePrincipal?
+ aEvent.stopPropagation();
+ throw 'Drop of ' + aURI + ' denied: no drag session.';
+ }
+ let normalizedURI;
+ try {
+ normalizedURI = this.treeStyleTab.makeURIFromSpec(aURI);
+ }
+ catch(e) {
+ }
+ if (!normalizedURI)
+ return;
+ let sourceDoc = session.sourceDocument;
+ let sourceURI = sourceDoc ? sourceDoc.documentURI : 'file:///' ;
+ let principal = sourceDoc ?
+ sourceDoc.nodePrincipal :
+ SecMan.getSimpleCodebasePrincipal(Services.io.newURI(sourceURI, null, null)) ;
+ try {
+ if (principal)
+ SecMan.checkLoadURIStrWithPrincipal(principal, normalizedURI.spec, Ci.nsIScriptSecurityManager.STANDARD);
+ else
+ SecMan.checkLoadURIStr(sourceURI, normalizedURI.spec, Ci.nsIScriptSecurityManager.STANDARD);
+ }
+ catch(e) {
+ aEvent.stopPropagation();
+ throw 'Drop of ' + aURI + ' denied.';
+ }
+ },
+
+ retrieveURLsFromDataTransfer : function TSTService_retrieveURLsFromDataTransfer(aDataTransfer)
+ {
+ var urls = [];
+ var types = [
+ 'text/x-moz-place',
+ 'text/uri-list',
+ 'text/x-moz-text-internal',
+ 'text/x-moz-url',
+ 'text/plain',
+ 'application/x-moz-file'
+ ];
+ for (let i = 0; i < types.length; i++) {
+ let dataType = types[i];
+ for (let i = 0, maxi = aDataTransfer.mozItemCount; i < maxi; i++)
+ {
+ let urlData = aDataTransfer.mozGetDataAt(dataType, i);
+ if (urlData) {
+ urls = urls.concat(this.retrieveURLsFromData(urlData, dataType));
+ }
+ }
+ if (urls.length)
+ break;
+ }
+ return urls.filter(function(aURI) {
+ return aURI &&
+ aURI.length &&
+ aURI.indexOf(this.BOOKMARK_FOLDER) == 0 ||
+ (
+ aURI.indexOf(' ', 0) == -1 &&
+ !/^\s*(javascript|data):/.test(aURI)
+ );
+ }, this);
+ },
+ BOOKMARK_FOLDER: 'x-moz-place:',
+ retrieveURLsFromData : function TSTService_retrieveURLsFromData(aData, aType)
+ {
+ switch (aType)
+ {
+ case 'text/x-moz-place':
+ let (uri = JSON.parse(aData).uri) {
+ if (uri)
+ return uri;
+ else
+ return this.BOOKMARK_FOLDER+aData;
+ }
+
+ case 'text/uri-list':
+ return aData.replace(/\r/g, '\n')
+ .replace(/^\#.+$/gim, '')
+ .replace(/\n\n+/g, '\n')
+ .split('\n');
+
+ case 'text/unicode':
+ case 'text/plain':
+ case 'text/x-moz-text-internal':
+ return [aData.trim()];
+
+ case 'text/x-moz-url':
+ return [((aData instanceof Ci.nsISupportsString) ? aData.toString() : aData)
+ .split('\n')[0]];
+
+ case 'application/x-moz-file':
+ let fileHandler = Services.io.getProtocolHandler('file')
+ .QueryInterface(Ci.nsIFileProtocolHandler);
+ return [fileHandler.getURLSpecFromFile(aData)];
+ }
+ return [];
+ },
+
+ init : function TabbarDND_init(aTabBrowser)
+ {
+ this.browser = aTabBrowser;
+ this.document = aTabBrowser.ownerDocument;
+ this.window = this.document.defaultView;
+ this.treeStyleTab = aTabBrowser.treeStyleTab;
+
+ this.mAutoExpandTimer = null;
+ this.mAutoExpandTimerNext = null;
+ this.mAutoExpandedTabs = [];
+ this.startListenEvents();
+ },
+
+ startListenEvents : function TabbarDND_startListenEvents()
+ {
+ var target = this.treeStyleTab.ownerToolbar || this.treeStyleTab.tabStrip;
+ target.addEventListener('dragstart', this, true);
+ target.addEventListener('dragover', this, true);
+ target.addEventListener('dragenter', this, false);
+ target.addEventListener('dragleave', this, false);
+ target.addEventListener('dragend', this, true);
+ target.addEventListener('drop', this, true);
+ },
+
+ destroy : function TabbarDND_destroy()
+ {
+ this.endListenEvents();
+
+ delete this.treeStyleTab;
+ delete this.browser;
+ delete this.document;
+ delete this.window;
+ },
+
+ endListenEvents : function TabbarDND_endListenEvents()
+ {
+ var target = this.treeStyleTab.ownerToolbar || this.treeStyleTab.tabStrip;
+ target.removeEventListener('dragstart', this, true);
+ target.removeEventListener('dragover', this, true);
+ target.removeEventListener('dragenter', this, false);
+ target.removeEventListener('dragleave', this, false);
+ target.removeEventListener('dragend', this, true);
+ target.removeEventListener('drop', this, true);
+ }
+
+};
+
diff --git a/modules/tabpanelDNDObserver.js b/modules/tabpanelDNDObserver.js
index 4f19e606..fa7e273a 100644
--- a/modules/tabpanelDNDObserver.js
+++ b/modules/tabpanelDNDObserver.js
@@ -1,168 +1,168 @@
-/* ***** 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 YUKI "Piro" Hiroshi.
- * Portions created by the Initial Developer are Copyright (C) 2010-2013
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s): YUKI "Piro" Hiroshi
- * Tetsuharu OHZEKI
- *
- * 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 ******/
-
-const EXPORTED_SYMBOLS = ['TabpanelDNDObserver'];
-
-const Cc = Components.classes;
-const Ci = Components.interfaces;
-
-Components.utils.import('resource://gre/modules/XPCOMUtils.jsm');
-
-XPCOMUtils.defineLazyModuleGetter(this, 'utils', 'resource://treestyletab-modules/utils.js', 'TreeStyleTabUtils');
-
-
-function TabpanelDNDObserver(aTabBrowser)
-{
- this.init(aTabBrowser);
-}
-
-TabpanelDNDObserver.prototype = {
-
- getDropPosition : function TabpanelDND_getDropPosition(aEvent)
- {
- var box = this.browser.boxObject;
- var W = box.width;
- var H = box.height;
- var X = box.screenX;
- var Y = box.screenY;
- var x = aEvent.screenX - X;
- var y = aEvent.screenY - Y;
-
- if (x > (W * 0.33) &&
- x < (W * 0.66) &&
- y > (H * 0.33) &&
- y < (H * 0.66))
- return 'center';
-
- var isTL = x <= W - (y * W / H);
- var isBL = x <= y * W / H;
- return (isTL && isBL) ? 'left' :
- (isTL && !isBL) ? 'top' :
- (!isTL && isBL) ? 'bottom' :
- 'right' ;
- },
-
- canDrop : function TabpanelDND_canDrop(aEvent)
- {
- var session = this.treeStyleTab.currentDragSession;
- return !!(
- session &&
- session.isDataFlavorSupported(this.treeStyleTab.kDRAG_TYPE_TABBAR) &&
- session.sourceNode &&
- session.sourceNode.ownerDocument == this.document
- );
- },
-
- handleEvent : function TabpanelDND_handleEvent(aEvent)
- {
- // ignore drag and drop while toolbar customization
- if (this.treeStyleTab.isToolbarCustomizing)
- return;
-
- switch (aEvent.type)
- {
- case 'dragleave': return this.onDragLeave(aEvent);
- case 'dragover': return this.onDragOver(aEvent);
- case 'drop': return this.onDrop(aEvent);
- }
- },
-
- onDragLeave : function TabpanelDND_onDragLeave(aEvent)
- {
- if (!this.canDrop(aEvent)) return;
- var sv = this.treeStyleTab;
- if (this.browser.hasAttribute(sv.kDROP_POSITION))
- sv.setTabbrowserAttribute(sv.kDROP_POSITION, sv.kDROP_POSITION_UNKNOWN);
- },
-
- onDragOver : function TabpanelDND_onDragOver(aEvent)
- {
- if (!this.canDrop(aEvent)) return;
- aEvent.preventDefault();
- var sv = this.treeStyleTab;
- sv.setTabbrowserAttribute(sv.kDROP_POSITION, this.getDropPosition(aEvent));
- },
-
- onDrop : function TabpanelDND_onDrop(aEvent)
- {
- if (!this.canDrop(aEvent)) return;
- var sv = this.treeStyleTab;
- var dt = aEvent.dataTransfer;
- var position = this.getDropPosition(aEvent);
- if (position != 'center' &&
- position != sv.position) {
- if (utils.getTreePref('tabbar.fixed.autoCancelOnDrop') &&
- dt.getData(sv.kDRAG_TYPE_TABBAR) != sv.kTABBAR_MOVE_FORCE) {
- let orient = (position == 'left' || position == 'right') ? 'vertical' : 'horizontal' ;
- utils.setTreePref('tabbar.fixed.'+orient, false);
- }
- sv.setPrefForActiveWindow(function() {
- sv.position = sv.base.position = position;
- });
- }
-
- aEvent.preventDefault();
- aEvent.stopPropagation();
- },
-
- init : function TabpanelDND_init(aTabBrowser)
- {
- this.browser = aTabBrowser;
- this.document = aTabBrowser.ownerDocument;
- this.window = this.document.defaultView;
- this.treeStyleTab = aTabBrowser.treeStyleTab;
-
- var b = this.treeStyleTab.mTabBrowser;
- b.mPanelContainer.addEventListener('dragover', this, true);
- b.mPanelContainer.addEventListener('dragleave', this, true);
- b.mPanelContainer.addEventListener('drop', this, true);
- },
-
- destroy : function TabpanelDND_destroy()
- {
- var b = this.treeStyleTab.mTabBrowser;
- b.mPanelContainer.removeEventListener('dragover', this, true);
- b.mPanelContainer.removeEventListener('dragleave', this, true);
- b.mPanelContainer.removeEventListener('drop', this, true);
-
- delete this.treeStyleTab;
- delete this.browser;
- delete this.document;
- delete this.window;
- }
-
-};
-
+/* ***** 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 YUKI "Piro" Hiroshi.
+ * Portions created by the Initial Developer are Copyright (C) 2010-2013
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s): YUKI "Piro" Hiroshi
+ * Tetsuharu OHZEKI
+ *
+ * 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 ******/
+
+const EXPORTED_SYMBOLS = ['TabpanelDNDObserver'];
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+
+Components.utils.import('resource://gre/modules/XPCOMUtils.jsm');
+
+XPCOMUtils.defineLazyModuleGetter(this, 'utils', 'resource://treestyletab-modules/utils.js', 'TreeStyleTabUtils');
+
+
+function TabpanelDNDObserver(aTabBrowser)
+{
+ this.init(aTabBrowser);
+}
+
+TabpanelDNDObserver.prototype = {
+
+ getDropPosition : function TabpanelDND_getDropPosition(aEvent)
+ {
+ var box = this.browser.boxObject;
+ var W = box.width;
+ var H = box.height;
+ var X = box.screenX;
+ var Y = box.screenY;
+ var x = aEvent.screenX - X;
+ var y = aEvent.screenY - Y;
+
+ if (x > (W * 0.33) &&
+ x < (W * 0.66) &&
+ y > (H * 0.33) &&
+ y < (H * 0.66))
+ return 'center';
+
+ var isTL = x <= W - (y * W / H);
+ var isBL = x <= y * W / H;
+ return (isTL && isBL) ? 'left' :
+ (isTL && !isBL) ? 'top' :
+ (!isTL && isBL) ? 'bottom' :
+ 'right' ;
+ },
+
+ canDrop : function TabpanelDND_canDrop(aEvent)
+ {
+ var session = this.treeStyleTab.currentDragSession;
+ return !!(
+ session &&
+ session.isDataFlavorSupported(this.treeStyleTab.kDRAG_TYPE_TABBAR) &&
+ session.sourceNode &&
+ session.sourceNode.ownerDocument == this.document
+ );
+ },
+
+ handleEvent : function TabpanelDND_handleEvent(aEvent)
+ {
+ // ignore drag and drop while toolbar customization
+ if (this.treeStyleTab.isToolbarCustomizing)
+ return;
+
+ switch (aEvent.type)
+ {
+ case 'dragleave': return this.onDragLeave(aEvent);
+ case 'dragover': return this.onDragOver(aEvent);
+ case 'drop': return this.onDrop(aEvent);
+ }
+ },
+
+ onDragLeave : function TabpanelDND_onDragLeave(aEvent)
+ {
+ if (!this.canDrop(aEvent)) return;
+ var sv = this.treeStyleTab;
+ if (this.browser.hasAttribute(sv.kDROP_POSITION))
+ sv.setTabbrowserAttribute(sv.kDROP_POSITION, sv.kDROP_POSITION_UNKNOWN);
+ },
+
+ onDragOver : function TabpanelDND_onDragOver(aEvent)
+ {
+ if (!this.canDrop(aEvent)) return;
+ aEvent.preventDefault();
+ var sv = this.treeStyleTab;
+ sv.setTabbrowserAttribute(sv.kDROP_POSITION, this.getDropPosition(aEvent));
+ },
+
+ onDrop : function TabpanelDND_onDrop(aEvent)
+ {
+ if (!this.canDrop(aEvent)) return;
+ var sv = this.treeStyleTab;
+ var dt = aEvent.dataTransfer;
+ var position = this.getDropPosition(aEvent);
+ if (position != 'center' &&
+ position != sv.position) {
+ if (utils.getTreePref('tabbar.fixed.autoCancelOnDrop') &&
+ dt.getData(sv.kDRAG_TYPE_TABBAR) != sv.kTABBAR_MOVE_FORCE) {
+ let orient = (position == 'left' || position == 'right') ? 'vertical' : 'horizontal' ;
+ utils.setTreePref('tabbar.fixed.'+orient, false);
+ }
+ sv.setPrefForActiveWindow(function() {
+ sv.position = sv.base.position = position;
+ });
+ }
+
+ aEvent.preventDefault();
+ aEvent.stopPropagation();
+ },
+
+ init : function TabpanelDND_init(aTabBrowser)
+ {
+ this.browser = aTabBrowser;
+ this.document = aTabBrowser.ownerDocument;
+ this.window = this.document.defaultView;
+ this.treeStyleTab = aTabBrowser.treeStyleTab;
+
+ var b = this.treeStyleTab.mTabBrowser;
+ b.mPanelContainer.addEventListener('dragover', this, true);
+ b.mPanelContainer.addEventListener('dragleave', this, true);
+ b.mPanelContainer.addEventListener('drop', this, true);
+ },
+
+ destroy : function TabpanelDND_destroy()
+ {
+ var b = this.treeStyleTab.mTabBrowser;
+ b.mPanelContainer.removeEventListener('dragover', this, true);
+ b.mPanelContainer.removeEventListener('dragleave', this, true);
+ b.mPanelContainer.removeEventListener('drop', this, true);
+
+ delete this.treeStyleTab;
+ delete this.browser;
+ delete this.document;
+ delete this.window;
+ }
+
+};
+
diff --git a/modules/themeManager.js b/modules/themeManager.js
index a2f0d614..1cc1105d 100644
--- a/modules/themeManager.js
+++ b/modules/themeManager.js
@@ -1,178 +1,178 @@
-/* ***** 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 YUKI "Piro" Hiroshi.
- * Portions created by the Initial Developer are Copyright (C) 2011-2013
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s): YUKI "Piro" Hiroshi
- * Tetsuharu OHZEKI
- *
- * 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 ******/
-
-const EXPORTED_SYMBOLS = ['TreeStyleTabThemeManager'];
-
-const BASE = 'chrome://treestyletab/skin/';
-
-Components.utils.import('resource://treestyletab-modules/base.js');
-
-function TreeStyleTabThemeManager(aWindow)
-{
- this.window = aWindow;
- this._preLoadImagesForStyleDone = [];
- this._preLoadImagesForStyleDoneImages = [];
-}
-TreeStyleTabThemeManager.prototype = {
- destroy : function()
- {
- delete this.window;
- },
-
- set : function(aStyle, aPosition)
- {
- if (this._lastStyles) {
- for (let i = 0, maxi = this._lastStyles.length; i < maxi; i++)
- {
- let style = this._lastStyles[i];
- style.parentNode.removeChild(style);
- }
- }
- this._lastStyles = null;
-
- var styles = [];
- switch (aStyle)
- {
- default:
- break;
-
- case 'plain':
- case 'flat':
- case 'mixed':
- styles.push(BASE+'square/base.css');
- if (aStyle != 'plain') {
- styles.push(BASE+'square/mixed.css');
- styles.push(BASE+'square/tab-surface.css');
- }
- if (aStyle != 'flat')
- styles.push(BASE+'square/dropshadow.css');
- styles.push(BASE+'platform-styled.css');
- styles.push(BASE+'square/platform.css');
- break;
-
- case 'vertigo':
- styles.push(BASE+'square/base.css');
- styles.push(BASE+'square/vertigo.css');
- styles.push(BASE+'platform-styled.css');
- styles.push(BASE+'square/platform.css');
- break;
-
- case 'metal':
- styles.push(BASE+'metal/base.css');
- styles.push(BASE+'metal/tab.css');
- styles.push(BASE+'metal/aero.css');
- styles.push(BASE+'platform-styled.css');
- styles.push(BASE+'metal/platform.css');
- break;
-
- case 'sidebar':
- styles.push(BASE+'sidebar/sidebar.css');
- styles.push(BASE+'sidebar/aero.css');
- styles.push(BASE+'platform-styled.css');
- break;
- }
-
- if (styles.length) {
- this._lastStyles = styles.map(function(aStyle) {
- var d = this.window.document;
- var pi = d.createProcessingInstruction(
- 'xml-stylesheet',
- 'type="text/css" href="'+aStyle+'"'
- );
- d.insertBefore(pi, d.documentElement);
- return pi;
- }, this);
- this.preloadImages(aStyle, aPosition);
- }
- },
-
- preloadImages : function(aStyle, aPosition)
- {
- var key = aStyle+'-'+aPosition;
- if (!aStyle ||
- this._preLoadImagesForStyleDone.indexOf(key) > -1)
- return;
- this._preLoadImagesForStyleDone.push(key);
-
- var images = key in this._preLoadImages ?
- this._preLoadImages[key] :
- null ;
- if (!images) return;
-
- for (let i = 0, maxi = images.length; i < maxi; i++)
- {
- let image = images[i];
- if (this._preLoadImagesForStyleDoneImages.indexOf(image) > -1)
- continue;
-
- (new this.window.Image()).src = image;
- this._preLoadImagesForStyleDoneImages.push(image);
- }
- },
-
- _preLoadImages : {
- 'metal-left' : [
- BASE+'metal/tab-active-l.png',
- BASE+'metal/tab-inactive-l.png',
- BASE+'metal/tab-active-selected-l.png',
- BASE+'metal/tab-inactive-selected-l.png',
- BASE+'metal/shadow-active-l.png',
- BASE+'metal/shadow-inactive-l.png'
- ].concat(
- [
- BASE+'metal/tab-active-middle.png',
- BASE+'metal/tab-active-middle-selected.png',
- BASE+'metal/tab-inactive-middle.png',
- BASE+'metal/tab-inactive-middle-selected.png'
- ]
- ),
- 'metal-right' : [
- BASE+'metal/tab-active-r.png',
- BASE+'metal/tab-inactive-r.png',
- BASE+'metal/tab-active-selected-r.png',
- BASE+'metal/tab-inactive-selected-r.png',
- BASE+'metal/shadow-active-r.png',
- BASE+'metal/shadow-inactive-r.png'
- ].concat(
- [
- BASE+'metal/tab-active-middle.png',
- BASE+'metal/tab-active-middle-selected.png',
- BASE+'metal/tab-inactive-middle.png',
- BASE+'metal/tab-inactive-middle-selected.png'
- ]
- )
- }
-};
+/* ***** 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 YUKI "Piro" Hiroshi.
+ * Portions created by the Initial Developer are Copyright (C) 2011-2013
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s): YUKI "Piro" Hiroshi
+ * Tetsuharu OHZEKI
+ *
+ * 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 ******/
+
+const EXPORTED_SYMBOLS = ['TreeStyleTabThemeManager'];
+
+const BASE = 'chrome://treestyletab/skin/';
+
+Components.utils.import('resource://treestyletab-modules/base.js');
+
+function TreeStyleTabThemeManager(aWindow)
+{
+ this.window = aWindow;
+ this._preLoadImagesForStyleDone = [];
+ this._preLoadImagesForStyleDoneImages = [];
+}
+TreeStyleTabThemeManager.prototype = {
+ destroy : function()
+ {
+ delete this.window;
+ },
+
+ set : function(aStyle, aPosition)
+ {
+ if (this._lastStyles) {
+ for (let i = 0, maxi = this._lastStyles.length; i < maxi; i++)
+ {
+ let style = this._lastStyles[i];
+ style.parentNode.removeChild(style);
+ }
+ }
+ this._lastStyles = null;
+
+ var styles = [];
+ switch (aStyle)
+ {
+ default:
+ break;
+
+ case 'plain':
+ case 'flat':
+ case 'mixed':
+ styles.push(BASE+'square/base.css');
+ if (aStyle != 'plain') {
+ styles.push(BASE+'square/mixed.css');
+ styles.push(BASE+'square/tab-surface.css');
+ }
+ if (aStyle != 'flat')
+ styles.push(BASE+'square/dropshadow.css');
+ styles.push(BASE+'platform-styled.css');
+ styles.push(BASE+'square/platform.css');
+ break;
+
+ case 'vertigo':
+ styles.push(BASE+'square/base.css');
+ styles.push(BASE+'square/vertigo.css');
+ styles.push(BASE+'platform-styled.css');
+ styles.push(BASE+'square/platform.css');
+ break;
+
+ case 'metal':
+ styles.push(BASE+'metal/base.css');
+ styles.push(BASE+'metal/tab.css');
+ styles.push(BASE+'metal/aero.css');
+ styles.push(BASE+'platform-styled.css');
+ styles.push(BASE+'metal/platform.css');
+ break;
+
+ case 'sidebar':
+ styles.push(BASE+'sidebar/sidebar.css');
+ styles.push(BASE+'sidebar/aero.css');
+ styles.push(BASE+'platform-styled.css');
+ break;
+ }
+
+ if (styles.length) {
+ this._lastStyles = styles.map(function(aStyle) {
+ var d = this.window.document;
+ var pi = d.createProcessingInstruction(
+ 'xml-stylesheet',
+ 'type="text/css" href="'+aStyle+'"'
+ );
+ d.insertBefore(pi, d.documentElement);
+ return pi;
+ }, this);
+ this.preloadImages(aStyle, aPosition);
+ }
+ },
+
+ preloadImages : function(aStyle, aPosition)
+ {
+ var key = aStyle+'-'+aPosition;
+ if (!aStyle ||
+ this._preLoadImagesForStyleDone.indexOf(key) > -1)
+ return;
+ this._preLoadImagesForStyleDone.push(key);
+
+ var images = key in this._preLoadImages ?
+ this._preLoadImages[key] :
+ null ;
+ if (!images) return;
+
+ for (let i = 0, maxi = images.length; i < maxi; i++)
+ {
+ let image = images[i];
+ if (this._preLoadImagesForStyleDoneImages.indexOf(image) > -1)
+ continue;
+
+ (new this.window.Image()).src = image;
+ this._preLoadImagesForStyleDoneImages.push(image);
+ }
+ },
+
+ _preLoadImages : {
+ 'metal-left' : [
+ BASE+'metal/tab-active-l.png',
+ BASE+'metal/tab-inactive-l.png',
+ BASE+'metal/tab-active-selected-l.png',
+ BASE+'metal/tab-inactive-selected-l.png',
+ BASE+'metal/shadow-active-l.png',
+ BASE+'metal/shadow-inactive-l.png'
+ ].concat(
+ [
+ BASE+'metal/tab-active-middle.png',
+ BASE+'metal/tab-active-middle-selected.png',
+ BASE+'metal/tab-inactive-middle.png',
+ BASE+'metal/tab-inactive-middle-selected.png'
+ ]
+ ),
+ 'metal-right' : [
+ BASE+'metal/tab-active-r.png',
+ BASE+'metal/tab-inactive-r.png',
+ BASE+'metal/tab-active-selected-r.png',
+ BASE+'metal/tab-inactive-selected-r.png',
+ BASE+'metal/shadow-active-r.png',
+ BASE+'metal/shadow-inactive-r.png'
+ ].concat(
+ [
+ BASE+'metal/tab-active-middle.png',
+ BASE+'metal/tab-active-middle-selected.png',
+ BASE+'metal/tab-inactive-middle.png',
+ BASE+'metal/tab-inactive-middle-selected.png'
+ ]
+ )
+ }
+};
diff --git a/modules/utils.js b/modules/utils.js
index 8cfb1d82..114ede43 100644
--- a/modules/utils.js
+++ b/modules/utils.js
@@ -1,306 +1,306 @@
-/* ***** 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 YUKI "Piro" Hiroshi.
- * Portions created by the Initial Developer are Copyright (C) 2010-2014
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s): YUKI "Piro" Hiroshi
- * Tetsuharu OHZEKI
- *
- * 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 ******/
-
-"use strict";
-
-let EXPORTED_SYMBOLS = ['TreeStyleTabUtils'];
-
-const Cc = Components.classes;
-const Ci = Components.interfaces;
-const Cu = Components.utils;
-
-Cu.import('resource://gre/modules/XPCOMUtils.jsm');
-Cu.import('resource://treestyletab-modules/constants.js');
-
-XPCOMUtils.defineLazyGetter(this, 'window', function() {
- Cu.import('resource://treestyletab-modules/lib/namespace.jsm');
- return getNamespaceFor('piro.sakura.ne.jp');
-});
-XPCOMUtils.defineLazyGetter(this, 'prefs', function() {
- Cu.import('resource://treestyletab-modules/lib/prefs.js');
- return window['piro.sakura.ne.jp'].prefs;
-});
-XPCOMUtils.defineLazyGetter(this, 'stringBundle', function() {
- Cu.import('resource://treestyletab-modules/lib/stringBundle.js', {});
- return window['piro.sakura.ne.jp'].stringBundle;
-});
-
-XPCOMUtils.defineLazyModuleGetter(this, 'Task',
- 'resource://gre/modules/Task.jsm');
-XPCOMUtils.defineLazyModuleGetter(this, 'TreeStyleTabConstants',
- 'resource://treestyletab-modules/constants.js', 'TreeStyleTabConstants');
-
-const TST_PREF_PREFIX = 'extensions.treestyletab.';
-const TST_PREF_VERSION = 10;
-
-
-let TreeStyleTabUtils = {
-
- get prefs () {
- return prefs;
- },
-
-/* Save/Load Prefs */
-
- getTreePref : function TSTUtils_getTreePref(aPrefstring)
- {
- return prefs.getPref(TST_PREF_PREFIX + aPrefstring);
- },
-
- setTreePref : function TSTUtils_setTreePref(aPrefstring, aNewValue)
- {
- return prefs.setPref(TST_PREF_PREFIX + aPrefstring, aNewValue);
- },
-
- clearTreePref : function TSTUtils_clearTreePref(aPrefstring)
- {
- return prefs.clearPref(TST_PREF_PREFIX + aPrefstring);
- },
-
- migratePrefs : function utils_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:
- 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') ?
- TreeStyleTabConstants.kDROPLINK_ASK :
- this.getTreePref('loadDroppedLinkToNewChildTab') ?
- TreeStyleTabConstants.kDROPLINK_NEWTAB :
- TreeStyleTabConstants.kDROPLINK_LOAD
- );
- this.clearTreePref('loadDroppedLinkToNewChildTab.confirm');
- this.clearTreePref('loadDroppedLinkToNewChildTab');
- }
- if (this.getTreePref('openGroupBookmarkAsTabSubTree') !== null) {
- let behavior = 0;
- if (this.getTreePref('openGroupBookmarkAsTabSubTree.underParent'))
- behavior += TreeStyleTabConstants.kGROUP_BOOKMARK_USE_DUMMY;
- if (!this.getTreePref('openGroupBookmarkBehavior.confirm')) {
- behavior += (
- this.getTreePref('openGroupBookmarkAsTabSubTree') ?
- TreeStyleTabConstants.kGROUP_BOOKMARK_SUBTREE :
- TreeStyleTabConstants.kGROUP_BOOKMARK_SEPARATE
- );
- }
- this.setTreePref('openGroupBookmark.behavior', behavior);
- this.clearTreePref('openGroupBookmarkBehavior.confirm');
- this.clearTreePref('openGroupBookmarkAsTabSubTree');
- this.clearTreePref('openGroupBookmarkAsTabSubTree.underParent');
- }
- case 4:
- let (subTreePrefs = [
- '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'
- ]) {
- for (let i = 0, maxi = subTreePrefs.length; i < maxi; i++)
- {
- let pref = subTreePrefs[i];
- let value = prefs.getPref(pref);
- if (value === null) {
- continue;
- }
- prefs.setPref(pref.replace('SubTree', 'Subtree'), value);
- prefs.clearPref(pref);
- }
- }
- case 5:
- let (behavior = this.getTreePref('openGroupBookmark.behavior')) {
- behavior = behavior | 2048;
- this.setTreePref('openGroupBookmark.behavior', behavior);
- }
- case 6:
- let (
- general = this.getTreePref('autoAttachNewTabsAsChildren'),
- search = this.getTreePref('autoAttachSearchResultAsChildren')
- ) {
- if (general !== null)
- this.setTreePref('autoAttach', general);
- if (search !== null)
- this.setTreePref('autoAttach.searchResult', search);
- }
- case 7:
- let (
- enabled = this.getTreePref('autoCollapseExpandSubtreeOnSelect.whileFocusMovingByShortcut'),
- delay = this.getTreePref('autoCollapseExpandSubtreeOnSelect.whileFocusMovingByShortcut.delay')
- ) {
- if (enabled !== null) {
- this.setTreePref('autoExpandSubtreeOnSelect.whileFocusMovingByShortcut', enabled);
- this.setTreePref('autoExpandSubtreeOnSelect.whileFocusMovingByShortcut.collapseOthers', enabled);
- }
- if (delay !== null)
- this.setTreePref('autoExpandSubtreeOnSelect.whileFocusMovingByShortcut.delay', delay);
- }
- case 8:
- orientalPrefs = orientalPrefs.concat([
- 'extensions.treestyletab.indent',
- 'extensions.treestyletab.indent.min'
- ]);
- case 9:
- let (behavior = this.getTreePref('openGroupBookmark.behavior')) {
- if (behavior & 4) {
- behavior ^= 4;
- behavior |= 1;
- this.setTreePref('openGroupBookmark.behavior', behavior);
- }
- }
- default:
- for (let i = 0, maxi = orientalPrefs.length; i < maxi; i++)
- {
- let pref = orientalPrefs[i];
- let value = prefs.getPref(pref);
- if (value === null) {
- continue;
- }
- prefs.setPref(pref+'.horizontal', value);
- prefs.setPref(pref+'.vertical', value);
- prefs.clearPref(pref);
- }
- break;
- }
- this.setTreePref('prefsVersion', TST_PREF_VERSION);
- },
-
-/* string bundle */
- get treeBundle () {
- return stringBundle.get('chrome://treestyletab/locale/treestyletab.properties');
- },
- get tabbrowserBundle () {
- return stringBundle.get('chrome://browser/locale/tabbrowser.properties');
- },
-
- evalInSandbox : function utils_evalInSandbox(aCode, aOwner)
- {
- try {
- var sandbox = new Cu.Sandbox(aOwner || 'about:blank');
- return Cu.evalInSandbox(aCode, sandbox);
- }
- catch(e) {
- }
- return void(0);
- },
-
-
- isTabNotRestoredYet : function utils_isTabNotRestoredYet(aTab)
- {
- var browser = aTab.linkedBrowser;
- // Firefox 25 and later. See: https://bugzilla.mozilla.org/show_bug.cgi?id=867142
- if (this.TabRestoreStates &&
- this.TabRestoreStates.has(browser))
- return (
- this.TabRestoreStates.isNeedsRestore(browser) ||
- this.TabRestoreStates.isRestoring(browser)
- );
-
- return !!browser.__SS_restoreState;
- },
- isTabNeedToBeRestored : function utils_isTabNeedToBeRestored(aTab)
- {
- var browser = aTab.linkedBrowser;
- // Firefox 25 and later. See: https://bugzilla.mozilla.org/show_bug.cgi?id=867142
- if (this.TabRestoreStates &&
- this.TabRestoreStates.has(browser))
- return this.TabRestoreStates.isNeedsRestore(browser);
-
- return browser.__SS_restoreState == 1;
- },
- get SessionStoreInternal() {
- return this.SessionStoreNS.SessionStoreInternal;
- },
- get TabRestoreStates() {
- return this.SessionStoreNS.TabRestoreStates;
- },
- get SessionStoreNS() {
- if (!this._SessionStoreNS) {
- try {
- // resource://app/modules/sessionstore/SessionStore.jsm ?
- this._SessionStoreNS = Components.utils.import('resource:///modules/sessionstore/SessionStore.jsm', {});
- }
- catch(e) {
- this._SessionStoreNS = {};
- }
- }
- return this._SessionStoreNS;
- },
-
- getShortcutOrURI : function utils_getShortcutOrURI(aBrowserWindow, aURI)
- {
- var done = false;
- aBrowserWindow.getShortcutOrURIAndPostData(aURI, function(aData) {
- aURI = aData.url;
- done = true;
- });
-
- // this should be rewritten in asynchronous style...
- var thread = Cc['@mozilla.org/thread-manager;1'].getService().mainThread;
- while (!done)
- {
- thread.processNextEvent(true);
- }
-
- return aURI;
- }
-};
+/* ***** 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 YUKI "Piro" Hiroshi.
+ * Portions created by the Initial Developer are Copyright (C) 2010-2014
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s): YUKI "Piro" Hiroshi
+ * Tetsuharu OHZEKI
+ *
+ * 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 ******/
+
+"use strict";
+
+let EXPORTED_SYMBOLS = ['TreeStyleTabUtils'];
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+const Cu = Components.utils;
+
+Cu.import('resource://gre/modules/XPCOMUtils.jsm');
+Cu.import('resource://treestyletab-modules/constants.js');
+
+XPCOMUtils.defineLazyGetter(this, 'window', function() {
+ Cu.import('resource://treestyletab-modules/lib/namespace.jsm');
+ return getNamespaceFor('piro.sakura.ne.jp');
+});
+XPCOMUtils.defineLazyGetter(this, 'prefs', function() {
+ Cu.import('resource://treestyletab-modules/lib/prefs.js');
+ return window['piro.sakura.ne.jp'].prefs;
+});
+XPCOMUtils.defineLazyGetter(this, 'stringBundle', function() {
+ Cu.import('resource://treestyletab-modules/lib/stringBundle.js', {});
+ return window['piro.sakura.ne.jp'].stringBundle;
+});
+
+XPCOMUtils.defineLazyModuleGetter(this, 'Task',
+ 'resource://gre/modules/Task.jsm');
+XPCOMUtils.defineLazyModuleGetter(this, 'TreeStyleTabConstants',
+ 'resource://treestyletab-modules/constants.js', 'TreeStyleTabConstants');
+
+const TST_PREF_PREFIX = 'extensions.treestyletab.';
+const TST_PREF_VERSION = 10;
+
+
+let TreeStyleTabUtils = {
+
+ get prefs () {
+ return prefs;
+ },
+
+/* Save/Load Prefs */
+
+ getTreePref : function TSTUtils_getTreePref(aPrefstring)
+ {
+ return prefs.getPref(TST_PREF_PREFIX + aPrefstring);
+ },
+
+ setTreePref : function TSTUtils_setTreePref(aPrefstring, aNewValue)
+ {
+ return prefs.setPref(TST_PREF_PREFIX + aPrefstring, aNewValue);
+ },
+
+ clearTreePref : function TSTUtils_clearTreePref(aPrefstring)
+ {
+ return prefs.clearPref(TST_PREF_PREFIX + aPrefstring);
+ },
+
+ migratePrefs : function utils_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:
+ 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') ?
+ TreeStyleTabConstants.kDROPLINK_ASK :
+ this.getTreePref('loadDroppedLinkToNewChildTab') ?
+ TreeStyleTabConstants.kDROPLINK_NEWTAB :
+ TreeStyleTabConstants.kDROPLINK_LOAD
+ );
+ this.clearTreePref('loadDroppedLinkToNewChildTab.confirm');
+ this.clearTreePref('loadDroppedLinkToNewChildTab');
+ }
+ if (this.getTreePref('openGroupBookmarkAsTabSubTree') !== null) {
+ let behavior = 0;
+ if (this.getTreePref('openGroupBookmarkAsTabSubTree.underParent'))
+ behavior += TreeStyleTabConstants.kGROUP_BOOKMARK_USE_DUMMY;
+ if (!this.getTreePref('openGroupBookmarkBehavior.confirm')) {
+ behavior += (
+ this.getTreePref('openGroupBookmarkAsTabSubTree') ?
+ TreeStyleTabConstants.kGROUP_BOOKMARK_SUBTREE :
+ TreeStyleTabConstants.kGROUP_BOOKMARK_SEPARATE
+ );
+ }
+ this.setTreePref('openGroupBookmark.behavior', behavior);
+ this.clearTreePref('openGroupBookmarkBehavior.confirm');
+ this.clearTreePref('openGroupBookmarkAsTabSubTree');
+ this.clearTreePref('openGroupBookmarkAsTabSubTree.underParent');
+ }
+ case 4:
+ let (subTreePrefs = [
+ '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'
+ ]) {
+ for (let i = 0, maxi = subTreePrefs.length; i < maxi; i++)
+ {
+ let pref = subTreePrefs[i];
+ let value = prefs.getPref(pref);
+ if (value === null) {
+ continue;
+ }
+ prefs.setPref(pref.replace('SubTree', 'Subtree'), value);
+ prefs.clearPref(pref);
+ }
+ }
+ case 5:
+ let (behavior = this.getTreePref('openGroupBookmark.behavior')) {
+ behavior = behavior | 2048;
+ this.setTreePref('openGroupBookmark.behavior', behavior);
+ }
+ case 6:
+ let (
+ general = this.getTreePref('autoAttachNewTabsAsChildren'),
+ search = this.getTreePref('autoAttachSearchResultAsChildren')
+ ) {
+ if (general !== null)
+ this.setTreePref('autoAttach', general);
+ if (search !== null)
+ this.setTreePref('autoAttach.searchResult', search);
+ }
+ case 7:
+ let (
+ enabled = this.getTreePref('autoCollapseExpandSubtreeOnSelect.whileFocusMovingByShortcut'),
+ delay = this.getTreePref('autoCollapseExpandSubtreeOnSelect.whileFocusMovingByShortcut.delay')
+ ) {
+ if (enabled !== null) {
+ this.setTreePref('autoExpandSubtreeOnSelect.whileFocusMovingByShortcut', enabled);
+ this.setTreePref('autoExpandSubtreeOnSelect.whileFocusMovingByShortcut.collapseOthers', enabled);
+ }
+ if (delay !== null)
+ this.setTreePref('autoExpandSubtreeOnSelect.whileFocusMovingByShortcut.delay', delay);
+ }
+ case 8:
+ orientalPrefs = orientalPrefs.concat([
+ 'extensions.treestyletab.indent',
+ 'extensions.treestyletab.indent.min'
+ ]);
+ case 9:
+ let (behavior = this.getTreePref('openGroupBookmark.behavior')) {
+ if (behavior & 4) {
+ behavior ^= 4;
+ behavior |= 1;
+ this.setTreePref('openGroupBookmark.behavior', behavior);
+ }
+ }
+ default:
+ for (let i = 0, maxi = orientalPrefs.length; i < maxi; i++)
+ {
+ let pref = orientalPrefs[i];
+ let value = prefs.getPref(pref);
+ if (value === null) {
+ continue;
+ }
+ prefs.setPref(pref+'.horizontal', value);
+ prefs.setPref(pref+'.vertical', value);
+ prefs.clearPref(pref);
+ }
+ break;
+ }
+ this.setTreePref('prefsVersion', TST_PREF_VERSION);
+ },
+
+/* string bundle */
+ get treeBundle () {
+ return stringBundle.get('chrome://treestyletab/locale/treestyletab.properties');
+ },
+ get tabbrowserBundle () {
+ return stringBundle.get('chrome://browser/locale/tabbrowser.properties');
+ },
+
+ evalInSandbox : function utils_evalInSandbox(aCode, aOwner)
+ {
+ try {
+ var sandbox = new Cu.Sandbox(aOwner || 'about:blank');
+ return Cu.evalInSandbox(aCode, sandbox);
+ }
+ catch(e) {
+ }
+ return void(0);
+ },
+
+
+ isTabNotRestoredYet : function utils_isTabNotRestoredYet(aTab)
+ {
+ var browser = aTab.linkedBrowser;
+ // Firefox 25 and later. See: https://bugzilla.mozilla.org/show_bug.cgi?id=867142
+ if (this.TabRestoreStates &&
+ this.TabRestoreStates.has(browser))
+ return (
+ this.TabRestoreStates.isNeedsRestore(browser) ||
+ this.TabRestoreStates.isRestoring(browser)
+ );
+
+ return !!browser.__SS_restoreState;
+ },
+ isTabNeedToBeRestored : function utils_isTabNeedToBeRestored(aTab)
+ {
+ var browser = aTab.linkedBrowser;
+ // Firefox 25 and later. See: https://bugzilla.mozilla.org/show_bug.cgi?id=867142
+ if (this.TabRestoreStates &&
+ this.TabRestoreStates.has(browser))
+ return this.TabRestoreStates.isNeedsRestore(browser);
+
+ return browser.__SS_restoreState == 1;
+ },
+ get SessionStoreInternal() {
+ return this.SessionStoreNS.SessionStoreInternal;
+ },
+ get TabRestoreStates() {
+ return this.SessionStoreNS.TabRestoreStates;
+ },
+ get SessionStoreNS() {
+ if (!this._SessionStoreNS) {
+ try {
+ // resource://app/modules/sessionstore/SessionStore.jsm ?
+ this._SessionStoreNS = Components.utils.import('resource:///modules/sessionstore/SessionStore.jsm', {});
+ }
+ catch(e) {
+ this._SessionStoreNS = {};
+ }
+ }
+ return this._SessionStoreNS;
+ },
+
+ getShortcutOrURI : function utils_getShortcutOrURI(aBrowserWindow, aURI)
+ {
+ var done = false;
+ aBrowserWindow.getShortcutOrURIAndPostData(aURI, function(aData) {
+ aURI = aData.url;
+ done = true;
+ });
+
+ // this should be rewritten in asynchronous style...
+ var thread = Cc['@mozilla.org/thread-manager;1'].getService().mainThread;
+ while (!done)
+ {
+ thread.processNextEvent(true);
+ }
+
+ return aURI;
+ }
+};
diff --git a/modules/window.js b/modules/window.js
index be05fdbd..e9ec77c3 100644
--- a/modules/window.js
+++ b/modules/window.js
@@ -1,1772 +1,1772 @@
-/* ***** 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 YUKI "Piro" Hiroshi.
- * Portions created by the Initial Developer are Copyright (C) 2012-2014
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s): YUKI "Piro" Hiroshi
- * Tetsuharu OHZEKI
- *
- * 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 ******/
-
-const EXPORTED_SYMBOLS = ['TreeStyleTabWindow'];
-
-const Cc = Components.classes;
-const Ci = Components.interfaces;
-const Cu = Components.utils;
-
-Cu.import('resource://gre/modules/XPCOMUtils.jsm');
-Cu.import('resource://treestyletab-modules/lib/inherit.jsm');
-
-XPCOMUtils.defineLazyGetter(this, 'window', function() {
- Cu.import('resource://treestyletab-modules/lib/namespace.jsm');
- return getNamespaceFor('piro.sakura.ne.jp');
-});
-XPCOMUtils.defineLazyGetter(this, 'prefs', function() {
- Cu.import('resource://treestyletab-modules/lib/prefs.js');
- return window['piro.sakura.ne.jp'].prefs;
-});
-
-XPCOMUtils.defineLazyModuleGetter(this, 'UninstallationListener',
- 'resource://treestyletab-modules/lib/UninstallationListener.js');
-
-XPCOMUtils.defineLazyModuleGetter(this, 'Services', 'resource://gre/modules/Services.jsm');
-
-Cu.import('resource://treestyletab-modules/base.js');
-XPCOMUtils.defineLazyModuleGetter(this, 'TreeStyleTabBrowser', 'resource://treestyletab-modules/browser.js');
-XPCOMUtils.defineLazyModuleGetter(this, 'utils', 'resource://treestyletab-modules/utils.js', 'TreeStyleTabUtils');
-XPCOMUtils.defineLazyModuleGetter(this, 'AutoHideWindow', 'resource://treestyletab-modules/autoHide.js');
-XPCOMUtils.defineLazyModuleGetter(this, 'TreeStyleTabThemeManager', 'resource://treestyletab-modules/themeManager.js');
-XPCOMUtils.defineLazyModuleGetter(this, 'FullscreenObserver', 'resource://treestyletab-modules/fullscreenObserver.js');
-XPCOMUtils.defineLazyModuleGetter(this, 'BrowserUIShowHideObserver', 'resource://treestyletab-modules/browserUIShowHideObserver.js');
-
-function TreeStyleTabWindow(aWindow)
-{
- this.window = aWindow;
- this.document = aWindow.document;
-
- this._restoringTabs = [];
- this._shownPopups = [];
- this.restoringCount = 0;
-
- aWindow.addEventListener('DOMContentLoaded', this, true);
- aWindow.addEventListener('load', this, false);
- aWindow.TreeStyleTabService = this;
-
- XPCOMUtils.defineLazyModuleGetter(aWindow, 'TreeStyleTabBrowser', 'resource://treestyletab-modules/browser.js');
-}
-
-TreeStyleTabWindow.prototype = inherit(TreeStyleTabBase, {
-
- base : TreeStyleTabBase,
-
- window : null,
- document : null,
-
-/* API */
-
- changeTabbarPosition : function TSTWindow_changeTabbarPosition(aNewPosition) /* PUBLIC API (obsolete, for backward compatibility) */
- {
- this.position = aNewPosition;
- },
-
- get position() /* PUBLIC API */
- {
- return this.preInitialized && this.browser.treeStyleTab ?
- this.browser.treeStyleTab.position :
- this.base.position ;
- },
- set position(aValue)
- {
- if ('UndoTabService' in this.window && this.window.UndoTabService.isUndoable()) {
- var current = this.base.position;
- var self = this;
- this.window.UndoTabService.doOperation(
- function() {
- self.base.position = aValue;
- },
- {
- label : utils.treeBundle.getString('undo_changeTabbarPosition_label'),
- name : 'treestyletab-changeTabbarPosition',
- data : {
- oldPosition : current,
- newPosition : aValue
- }
- }
- );
- }
- else {
- this.base.position = aValue;
- }
- return aValue;
- },
-
- undoChangeTabbarPosition : function TSTWindow_undoChangeTabbarPosition() /* PUBLIC API */
- {
- return this.base.undoChangeTabbarPosition();
- },
-
- redoChangeTabbarPosition : function TSTWindow_redoChangeTabbarPosition() /* PUBLIC API */
- {
- return this.base.redoChangeTabbarPosition();
- },
-
- get treeViewEnabled() /* PUBLIC API */
- {
- return this.base.treeViewEnabled;
- },
- set treeViewEnabled(aValue)
- {
- return this.base.treeViewEnabled = aValue;
- },
-
- get useTMPSessionAPI() /* PUBLIC API */
- {
- return this.base.useTMPSessionAPI;
- },
- set useTMPSessionAPI(aValue)
- {
- return this.base.useTMPSessionAPI = aValue;
- },
-
- get browser()
- {
- var w = this.window;
- this.assertBeforeDestruction(w);
- return 'SplitBrowser' in w ? w.SplitBrowser.activeBrowser :
- w.gBrowser ;
- },
-
- get browserToolbox()
- {
- var w = this.window;
- return w.gToolbox || w.gNavToolbox;
- },
-
- get browserBox()
- {
- return this.document.getElementById('browser');
- },
-
- get browserBottomBox()
- {
- return this.document.getElementById('browser-bottombox');
- },
-
- get isPopupWindow()
- {
- return (
- this.document &&
- this.document.documentElement.getAttribute('chromehidden') != '' &&
- !this.window.gBrowser.treeStyleTab.isVisible
- );
- },
-
-/* backward compatibility */
- getTempTreeStyleTab : function TSTWindow_getTempTreeStyleTab(aTabBrowser)
- {
- return aTabBrowser.treeStyleTab || new TreeStyleTabBrowser(this, aTabBrowser);
- },
-
- initTabAttributes : function TSTWindow_initTabAttributes(aTab, aTabBrowser)
- {
- var b = aTabBrowser || this.getTabBrowserFromChild(aTab);
- this.getTempTreeStyleTab(b).initTabAttributes(aTab);
- },
-
- initTabContents : function TSTWindow_initTabContents(aTab, aTabBrowser)
- {
- var b = aTabBrowser || this.getTabBrowserFromChild(aTab);
- this.getTempTreeStyleTab(b).initTabContents(aTab);
- },
-
- initTabContentsOrder : function TSTWindow_initTabContentsOrder(aTab, aTabBrowser)
- {
- var b = aTabBrowser || this.getTabBrowserFromChild(aTab);
- this.getTempTreeStyleTab(b).initTabContentsOrder(aTab);
- },
-
-/* Utilities */
-
- stopRendering : function TSTWindow_stopRendering()
- {
- this.window['piro.sakura.ne.jp'].stopRendering.stop();
- },
- startRendering : function TSTWindow_startRendering()
- {
- this.window['piro.sakura.ne.jp'].stopRendering.start();
- },
-
- getPropertyPixelValue : function TSTWindow_getPropertyPixelValue(aElementOrStyle, aProp)
- {
- var style = aElementOrStyle instanceof Ci.nsIDOMCSSStyleDeclaration ?
- aElementOrStyle :
- this.window.getComputedStyle(aElementOrStyle, null) ;
- return Number(style.getPropertyValue(aProp).replace(/px$/, ''));
- },
-
- get isToolbarCustomizing()
- {
- var toolbox = this.browserToolbox;
- return toolbox && toolbox.customizing;
- },
-
- get maximized()
- {
- var sizemode = this.document.documentElement.getAttribute('sizemode');
- return (
- this.window.fullScreen ||
- this.window.windowState == this.window.STATE_MAXIMIZED ||
- sizemode == 'maximized' ||
- sizemode == 'fullscreen'
- );
- },
-
- maxTabbarWidth : function TSTWindow_maxTabbarWidth(aWidth, aTabBrowser)
- {
- aTabBrowser = aTabBrowser || this.browser;
- var safePadding = 20; // for window border, etc.
- var windowWidth = this.maximized ? this.window.screen.availWidth - safePadding : this.window.outerWidth ;
- var rootWidth = parseInt(this.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 TSTWindow_maxTabbarHeight(aHeight, aTabBrowser)
- {
- aTabBrowser = aTabBrowser || this.browser;
- var safePadding = 20; // for window border, etc.
- var windowHeight = this.maximized ? this.window.screen.availHeight - safePadding : this.window.outerHeight ;
- var rootHeight = parseInt(this.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 TSTWindow_shouldOpenSearchResultAsChild(aTerm)
- {
- aTerm = aTerm.trim();
-
- var mode = utils.getTreePref('autoAttach.searchResult');
- if (mode == this.kSEARCH_RESULT_ATTACH_ALWAYS) {
- return true;
- }
- else if (!aTerm || mode == this.kSEARCH_RESULT_DO_NOT_ATTACH) {
- return false;
- }
-
- var selection = this.window.getBrowserSelection();
- return selection.trim() == aTerm;
- },
- kSEARCH_RESULT_DO_NOT_ATTACH : 0,
- kSEARCH_RESULT_ATTACH_IF_SELECTED : 1,
- kSEARCH_RESULT_ATTACH_ALWAYS : 2,
-
- get isAutoHide()
- {
- return this.window.fullScreen ?
- (
- prefs.getPref('browser.fullscreen.autohide') &&
- utils.getTreePref('tabbar.autoHide.mode.fullscreen')
- ) :
- utils.getTreePref('tabbar.autoHide.mode');
- },
-
- get autoHideWindow()
- {
- if (!this._autoHideWindow) {
- this._autoHideWindow = new AutoHideWindow(this.window);
- }
- return this._autoHideWindow;
- },
-
- get themeManager()
- {
- if (!this._themeManager) {
- this._themeManager = new TreeStyleTabThemeManager(this.window);
- }
- return this._themeManager;
- },
-
-/* Initializing */
-
- preInit : function TSTWindow_preInit()
- {
- if (this.preInitialized)
- return;
- this.preInitialized = true;
-
- var w = this.window;
- w.removeEventListener('DOMContentLoaded', this, true);
- if (w.location.href.indexOf('chrome://browser/content/browser.xul') != 0)
- return;
-
- w.addEventListener('SSTabRestoring', this, true);
-
- w.TreeStyleTabWindowHelper.preInit();
-
- // initialize theme
- this.onPrefChange('extensions.treestyletab.tabbar.style');
- },
- preInitialized : false,
-
- init : function TSTWindow_init()
- {
- var w = this.window;
- w.removeEventListener('load', this, false);
-
- w.addEventListener('unload', this, false);
-
- if (
- w.location.href.indexOf('chrome://browser/content/browser.xul') != 0 ||
- !this.browser
- )
- return;
-
- if (this.initialized)
- return;
-
- if (!this.preInitialized) {
- this.preInit();
- }
- w.removeEventListener('SSTabRestoring', this, true);
-
- var d = this.document;
- d.addEventListener('popupshowing', this, false);
- d.addEventListener('popuphiding', this, true);
- d.addEventListener(this.kEVENT_TYPE_TAB_COLLAPSED_STATE_CHANGED, this, false);
- d.addEventListener(this.kEVENT_TYPE_TABBAR_POSITION_CHANGED, this, false);
- d.addEventListener(this.kEVENT_TYPE_TABBAR_STATE_CHANGED, this, false);
- d.addEventListener(this.kEVENT_TYPE_FOCUS_NEXT_TAB, this, false);
- w.addEventListener('beforecustomization', this, true);
- w.addEventListener('aftercustomization', this, false);
-
- w.messageManager.addMessageListener('SessionStore:restoreTabContentStarted', this);
-
- this.fullscreenObserver = new FullscreenObserver(this.window);
- this.initUIShowHideObserver();
-
- var appcontent = d.getElementById('appcontent');
- appcontent.addEventListener('SubBrowserAdded', this, false);
- appcontent.addEventListener('SubBrowserRemoveRequest', this, false);
-
- w.addEventListener('UIOperationHistoryUndo:TabbarOperations', this, false);
- w.addEventListener('UIOperationHistoryRedo:TabbarOperations', this, false);
-
- prefs.addPrefListener(this);
-
- this.initUninstallationListener();
-
- w.TreeStyleTabWindowHelper.onBeforeBrowserInit();
- this.initTabBrowser(this.browser);
- w.TreeStyleTabWindowHelper.onAfterBrowserInit();
-
- this.processRestoredTabs();
- this.updateTabsOnTop();
-
- // Init autohide service only if it have to be activated.
- if (this.isAutoHide)
- this.onPrefChange('extensions.treestyletab.tabbar.autoHide.mode');
-
- this.onPrefChange('extensions.treestyletab.autoCollapseExpandSubtreeOnSelect.whileFocusMovingByShortcut');
-
- this.initialized = true;
- },
- initialized : false,
-
- initUninstallationListener : function TSTWindow_initUninstallationListener()
- {
- var restorePrefs = function() {
- if (prefs.getPref('extensions.treestyletab.tabsOnTop.originalState')) {
- prefs.clearPref('extensions.treestyletab.tabsOnTop.originalState');
- try {
- this.browser.treeStyleTab.position = 'top';
- }
- catch(e) {
- }
- this.window.TabsOnTop.enabled = true;
- }
- }.bind(this);
- new UninstallationListener({
- id : 'treestyletab@piro.sakura.ne.jp',
- onuninstalled : restorePrefs,
- ondisabled : restorePrefs
- });
- },
-
- initTabBrowser : function TSTWindow_initTabBrowser(aTabBrowser)
- {
- if (aTabBrowser.localName != 'tabbrowser')
- return;
- (new TreeStyleTabBrowser(this, aTabBrowser)).init();
- },
-
- updateAllTabsButton : function TSTWindow_updateAllTabsButton(aTabBrowser)
- {
- var d = this.document;
- aTabBrowser = aTabBrowser || this.browser;
- var allTabsButton = d.getElementById('alltabs-button') ||
- ( // Tab Mix Plus
- utils.getTreePref('compatibility.TMP') &&
- d.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 TSTWindow_updateAllTabsPopup(aEvent)
- {
- if (!utils.getTreePref('enableSubtreeIndent.allTabsPopup'))
- return;
-
- Array.forEach(aEvent.originalTarget.childNodes, function(aItem) {
- if (aItem.classList.contains('alltabs-item') && 'tab' in aItem)
- aItem.style.marginLeft = aItem.tab.getAttribute(this.kNEST) + 'em';
- }, this);
- },
-
- initUIShowHideObserver : function TSTWindow_initUIShowHideObserver()
- {
- this.rootElementObserver = new BrowserUIShowHideObserver(this, this.document.documentElement);
-
- var toolbox = this.browserToolbox;
- if (toolbox)
- this.browserToolboxObserver = new BrowserUIShowHideObserver(this, toolbox);
-
- var browserBox = this.browserBox;
- if (browserBox)
- this.browserBoxObserver = new BrowserUIShowHideObserver(this, browserBox);
-
- var bottomBox = this.browserBottomBox;
- if (bottomBox)
- this.browserBottomBoxObserver = new BrowserUIShowHideObserver(this, bottomBox);
- },
-
- destroy : function TSTWindow_destroy()
- {
- var w = this.window;
- if (this.browser) {
- this.base.inWindowDestoructionProcess = true;
- try {
- w.removeEventListener('unload', this, false);
-
- this.autoHideWindow.destroy();
- delete this._autoHideWindow;
-
- this.themeManager.destroy();
- delete this._themeManager;
-
- this.browser.treeStyleTab.saveCurrentState();
- this.destroyTabBrowser(this.browser);
-
- this.endListenKeyEventsFor(this.LISTEN_FOR_AUTOHIDE);
- this.endListenKeyEventsFor(this.LISTEN_FOR_AUTOEXPAND_BY_FOCUSCHANGE);
-
- let d = this.document;
- d.removeEventListener('popupshowing', this, false);
- d.removeEventListener('popuphiding', this, true);
- d.removeEventListener(this.kEVENT_TYPE_TAB_COLLAPSED_STATE_CHANGED, this, false);
- d.removeEventListener(this.kEVENT_TYPE_TABBAR_POSITION_CHANGED, this, false);
- d.removeEventListener(this.kEVENT_TYPE_TABBAR_STATE_CHANGED, this, false);
- d.removeEventListener(this.kEVENT_TYPE_FOCUS_NEXT_TAB, this, false);
- w.removeEventListener('beforecustomization', this, true);
- w.removeEventListener('aftercustomization', this, false);
-
- w.messageManager.removeMessageListener('SessionStore:restoreTabContentStarted', this);
-
- this.fullscreenObserver.destroy();
- delete this.fullscreenObserver;
-
- this.rootElementObserver.destroy();
- delete this.rootElementObserver;
-
- if (this.browserToolboxObserver) {
- this.browserToolboxObserver.destroy();
- delete this.browserToolboxObserver;
- }
- if (this.browserBoxObserver) {
- this.browserBoxObserver.destroy();
- delete this.browserBoxObserver;
- }
- if (this.browserBottomBoxObserver) {
- this.browserBottomBoxObserver.destroy();
- delete this.browserBottomBoxObserver;
- }
-
- for (let i = 0, maxi = this._tabFocusAllowance.length; i < maxi; i++)
- {
- w.removeEventListener(this.kEVENT_TYPE_FOCUS_NEXT_TAB, this._tabFocusAllowance[i], false);
- }
-
- var appcontent = d.getElementById('appcontent');
- appcontent.removeEventListener('SubBrowserAdded', this, false);
- appcontent.removeEventListener('SubBrowserRemoveRequest', this, false);
-
- w.removeEventListener('UIOperationHistoryUndo:TabbarOperations', this, false);
- w.removeEventListener('UIOperationHistoryRedo:TabbarOperations', this, false);
-
- prefs.removePrefListener(this);
- }
- catch(e) {
- throw e;
- }
- finally {
- this.base.inWindowDestoructionProcess = false;
- }
- }
-
- delete w.TreeStyleTabService;
- delete this.window;
- delete this.document;
- },
-
- destroyTabBrowser : function TSTWindow_destroyTabBrowser(aTabBrowser)
- {
- if (aTabBrowser.localName != 'tabbrowser')
- return;
- aTabBrowser.treeStyleTab.destroy();
- delete aTabBrowser.treeStyleTab;
- },
-
-/* Event Handling */
-
- handleEvent : function TSTWindow_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 'blur':
- return this.simulateKeyRelease();
-
- 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 'click':
- return this.handleNewTabActionOnButton(aEvent);
-
-
- case 'beforecustomization':
- this.window.TreeStyleTabWindowHelper.destroyToolbarItems();
- return;
-
- case 'aftercustomization':
- this.window.TreeStyleTabWindowHelper.initToolbarItems();
- return;
-
-
- 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.position = aEvent.entry.data.oldPosition;
- return;
- case 'treestyletab-changeTabbarPosition-private':
- aEvent.entry.data.target.treeStyleTab.position = aEvent.entry.data.oldPosition;
- return;
- }
- return;
-
- case 'UIOperationHistoryRedo:TabbarOperations':
- switch (aEvent.entry.name)
- {
- case 'treestyletab-changeTabbarPosition':
- this.position = aEvent.entry.data.newPosition;
- return;
- case 'treestyletab-changeTabbarPosition-private':
- aEvent.entry.data.target.treeStyleTab.position = aEvent.entry.data.newPosition;
- return;
- }
- return;
- }
- },
-
- keyEventListening : false,
- keyEventListeningFlags : 0,
-
- LISTEN_FOR_AUTOHIDE : 1,
- LISTEN_FOR_AUTOEXPAND_BY_FOCUSCHANGE : 2,
-
- startListenKeyEventsFor : function TSTWindow_startListenKeyEventsFor(aReason)
- {
- if (this.keyEventListeningFlags & aReason)
- return;
- if (!this.keyEventListening) {
- let w = this.window;
- w.addEventListener('keydown', this, true);
- w.addEventListener('keyup', this, true);
- w.addEventListener('keypress', this, true);
- w.addEventListener('blur', this, true);
- this.keyEventListening = true;
- }
- this.keyEventListeningFlags |= aReason;
- },
-
- endListenKeyEventsFor : function TSTWindow_endListenKeyEventsFor(aReason)
- {
- if (!(this.keyEventListeningFlags & aReason))
- return;
- this.keyEventListeningFlags ^= aReason;
- if (!this.keyEventListeningFlags && this.keyEventListening) {
- let w = this.window;
- w.removeEventListener('keydown', this, true);
- w.removeEventListener('keyup', this, true);
- w.removeEventListener('keypress', this, true);
- w.removeEventListener('blur', this, true);
- this.keyEventListening = false;
- }
- },
-
- onKeyDown : function TSTWindow_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;
-
- var left = aEvent.keyCode == Ci.nsIDOMKeyEvent.DOM_VK_LEFT;
- var right = aEvent.keyCode == Ci.nsIDOMKeyEvent.DOM_VK_RIGHT;
- var up = aEvent.keyCode == Ci.nsIDOMKeyEvent.DOM_VK_UP;
- var down = aEvent.keyCode == Ci.nsIDOMKeyEvent.DOM_VK_DOWN;
- if (
- Services.focus.focusedElement == this.browser.selectedTab &&
- (up || down || left || right)
- )
- this.arrowKeyEventOnTab = {
- keyCode : aEvent.keyCode,
- left : left,
- right : right,
- up : up,
- down : down,
- altKey : aEvent.altKey,
- ctrlKey : aEvent.ctrlKey,
- metaKey : aEvent.metaKey,
- shiftKey : aEvent.shiftKey
- };
-
- var b = this.browser;
- var data = {
- sourceEvent : aEvent
- };
-
- /* PUBLIC API */
- this.fireCustomEvent(this.kEVENT_TYPE_TAB_FOCUS_SWITCHING_KEY_DOWN, b, true, false, data);
- // for backward compatibility
- this.fireCustomEvent(this.kEVENT_TYPE_TAB_FOCUS_SWITCHING_KEY_DOWN.replace(/^nsDOM/, ''), b, true, false, data);
- },
- accelKeyPressed : false,
- arrowKeyEventOnTab : null,
-
- onKeyRelease : function TSTWindow_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;
- this.window.setTimeout(function(aSelf) {
- aSelf.arrowKeyEventOnTab = null;
- }, 10, this);
-
- 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));
-
- var data = {
- scrollDown : scrollDown,
- scrollUp : scrollUp,
- standBy : standBy,
- onlyShiftKey : onlyShiftKey,
- sourceEvent : aEvent
- };
-
- if (
- scrollDown ||
- scrollUp ||
- ( // when you release "shift" key
- standBy && onlyShiftKey
- )
- ) {
- /* PUBLIC API */
- this.fireCustomEvent(this.kEVENT_TYPE_TAB_FOCUS_SWITCHING_START, b, true, false, data);
- // for backward compatibility
- this.fireCustomEvent(this.kEVENT_TYPE_TAB_FOCUS_SWITCHING_START.replace(/^nsDOM/, ''), b, true, false, data);
- return;
- }
-
- if (aEvent.type == 'keypress' ?
- // ignore keypress on Ctrl-R, Ctrl-T, etc.
- aEvent.charCode != 0 :
- // ignore keyup not on the Ctrl key
- aEvent.keyCode != Ci.nsIDOMKeyEvent.DOM_VK_CONTROL
- )
- return;
-
- // when you just release accel key...
-
- /* PUBLIC API */
- let (event) {
- this.fireCustomEvent(this.kEVENT_TYPE_TAB_FOCUS_SWITCHING_END, b, true, false, data);
- // for backward compatibility
- this.fireCustomEvent(this.kEVENT_TYPE_TAB_FOCUS_SWITCHING_END.replace(/^nsDOM/, ''), b, true, false, data);
- }
-
- if (this._tabShouldBeExpandedAfterKeyReleased) {
- let tab = this._tabShouldBeExpandedAfterKeyReleased;
- if (this.hasChildTabs(tab) &&
- this.isSubtreeCollapsed(tab)) {
- this.getTabBrowserFromChild(tab)
- .treeStyleTab
- .collapseExpandTreesIntelligentlyFor(tab);
- }
- }
- this._tabShouldBeExpandedAfterKeyReleased = null;
- },
- // When the window lose its focus, we cannot detect any key-release events.
- // So we have to simulate key-release event manually.
- // See: https://github.com/piroor/treestyletab/issues/654
- simulateKeyRelease : function TSTWindow_simulateKeyRelease()
- {
- if (!this.accelKeyPressed)
- return;
-
- this.accelKeyPressed = false;
- var data = {
- scrollDown : false,
- scrollUp : false,
- standBy : false,
- onlyShiftKey : false,
- sourceEvent : null
- };
- /* PUBLIC API */
- this.fireCustomEvent(this.kEVENT_TYPE_TAB_FOCUS_SWITCHING_END, this.browser, true, false, data);
- // for backward compatibility
- this.fireCustomEvent(this.kEVENT_TYPE_TAB_FOCUS_SWITCHING_END.replace(/^nsDOM/, ''), this.browser, true, false, data);
- },
-
- get shouldListenKeyEventsForAutoExpandByFocusChange()
- {
- return !this.ctrlTabPreviewsEnabled &&
- (
- utils.getTreePref('autoExpandSubtreeOnSelect.whileFocusMovingByShortcut') ||
- utils.getTreePref('autoCollapseExpandSubtreeOnSelect')
- );
- },
-
- get ctrlTabPreviewsEnabled()
- {
- return 'allTabs' in this.window &&
- prefs.getPref('browser.ctrlTab.previews');
- },
-
- receiveMessage : function TSTWindow_receiveMessage(aMessage)
- {
- var browser = aMessage.target;
- var tabbrowser = this.getTabBrowserFromChild(browser);
- if (!tabbrowser)
- return;
- var tab = tabbrowser.treeStyleTab.getTabFromBrowser(browser);
- if (!tab)
- return;
-
- switch (aMessage.name)
- {
- case 'SessionStore:restoreTabContentStarted':
- return tabbrowser.treeStyleTab.onRestoreTabContentStarted(tab);
- }
- },
-
- onTabbarResizeStart : function TSTWindow_onTabbarResizeStart(aEvent)
- {
- if (aEvent.button != 0)
- return;
-
- if (!this.isEventFiredOnGrippy(aEvent))
- 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 TSTWindow_onTabbarResizeEnd(aEvent)
- {
- if (this.tabbarResizeStartWidth < 0)
- return;
-
- var target = aEvent.currentTarget;
- var b = this.getTabBrowserFromChild(target);
-
- aEvent.stopPropagation();
- if ('releaseCapture' in target)
- target.releaseCapture();
-
- target.removeEventListener('mousemove', this, false);
-
- this.tabbarResizeStartWidth = -1;
- this.tabbarResizeStartHeight = -1;
- this.tabbarResizeStartX = -1;
- this.tabbarResizeStartY = -1;
-
- this.Deferred.next(function() {
- b.treeStyleTab.fixTooNarrowTabbar();
- }).error(this.defaultDeferredErrorHandler);
- },
- onTabbarResizing : function TSTWindow_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.position;
- 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.setPrefForActiveWindow(function() {
- utils.setTreePref('tabbar.width', width);
- });
- if (b.treeStyleTab.autoHide.mode == b.treeStyleTab.autoHide.kMODE_SHRINK &&
- b.treeStyleTab.tabStripPlaceHolder)
- b.treeStyleTab.tabStripPlaceHolder.setAttribute('width', utils.getTreePref('tabbar.shrunkenWidth'));
- }
- else {
- this.setPrefForActiveWindow(function() {
- utils.setTreePref('tabbar.shrunkenWidth', width);
- });
- }
- }
- else {
- let delta = aEvent.screenY - this.tabbarResizeStartY;
- height += (pos == 'top' ? delta : -delta );
- this.setPrefForActiveWindow(function() {
- utils.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 TSTWindow_onTabbarReset(aEvent)
- {
- if (aEvent.button != 0)
- return;
- var b = this.getTabBrowserFromChild(aEvent.currentTarget);
- if (b) {
- b.treeStyleTab.resetTabbarSize();
- aEvent.stopPropagation();
- }
- },
-
- onFocusNextTab : function TSTWindow_onFocusNextTab(aEvent)
- {
- var tab = aEvent.originalTarget;
- var b = this.getTabBrowserFromChild(tab);
- if (
- prefs.getPref('browser.tabs.selectOwnerOnClose') &&
- tab.owner &&
- (
- !b._removingTabs ||
- b._removingTabs.indexOf(tab.owner) < 0
- )
- )
- aEvent.preventDefault();
- },
-
- showHideSubtreeMenuItem : function TSTWindow_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(...aArgs) {
- return this.showHideSubtreeMenuItem.apply(this, aArgs);
- }, // obsolete, for backward compatibility
-
- updateAeroPeekPreviews : function TSTWindow_updateAeroPeekPreviews()
- {
- var w = this.window;
- if (
- this.updateAeroPeekPreviewsTimer ||
- !prefs.getPref('browser.taskbar.previews.enable') ||
- !utils.getTreePref('taskbarPreviews.hideCollapsedTabs') ||
- !('Win7Features' in w) ||
- !w.Win7Features ||
- !this.AeroPeek ||
- !this.AeroPeek.windows
- )
- return;
-
- this.updateAeroPeekPreviewsTimer = w.setTimeout(function(aSelf) {
- aSelf.updateAeroPeekPreviewsTimer = null;
- try {
- aSelf.updateAeroPeekPreviewsInternal();
- }
- catch(e) {
- dump(e+'\n');
- aSelf.updateAeroPeekPreviews();
- }
- }, 250, this);
- },
- updateAeroPeekPreviewsTimer : null,
- updateAeroPeekPreviewsInternal : function TSTWindow_updateAeroPeekPreviewsInternal()
- {
- if (
- !prefs.getPref('browser.taskbar.previews.enable') ||
- !utils.getTreePref('taskbarPreviews.hideCollapsedTabs')
- )
- return;
-
- this.AeroPeek.windows.some(function(aTabWindow) {
- if (aTabWindow.win == this.window) {
- let previews = aTabWindow.previews;
- for (let i = 0, maxi = previews.length; i < maxi; i++)
- {
- let preview = previews[i];
- if (!preview)
- continue;
- let tab = preview.controller.wrappedJSObject.tab;
- preview.visible = !this.isCollapsed(tab);
- }
- this.AeroPeek.checkPreviewCount();
- return true;
- }
- return false;
- }, this);
- },
-
- updateTabsOnTop : function TSTWindow_updateTabsOnTop()
- {
- if (
- this.isPopupWindow ||
- this.tabsOnTopChangingByUI ||
- this.tabsOnTopChangingByTST
- )
- return;
-
- var TabsOnTop = this.window.TabsOnTop;
- var TabsInTitlebar = this.window.TabsInTitlebar;
- var isTopTabbar = this.browser.treeStyleTab.position == 'top';
-
- this.tabsOnTopChangingByTST = true;
-
- try {
- if (TabsOnTop) {
- let originalState = utils.getTreePref('tabsOnTop.originalState');
- if (originalState === null) {
- let current = prefs.getDefaultPref('browser.tabs.onTop') === null ?
- TabsOnTop.enabled :
- prefs.getPref('browser.tabs.onTop') ;
- utils.setTreePref('tabsOnTop.originalState', originalState = current);
- }
-
- if (!isTopTabbar || !this.browser.treeStyleTab.fixed) {
- if (TabsOnTop.enabled)
- TabsOnTop.enabled = false;
- }
- else {
- if (TabsOnTop.enabled != originalState)
- TabsOnTop.enabled = originalState;
- utils.clearTreePref('tabsOnTop.originalState');
- }
- }
- if (TabsInTitlebar) {
- let allowed = isTopTabbar && this.browser.treeStyleTab.fixed;
- if (
- (this.window.TabsOnBottom && utils.getTreePref('compatibility.TabsOnBottom')) ||
- ('navbarontop' in this.window && utils.getTreePref('compatibility.NavbarOnTitlebar')) ||
- ('classicthemerestorerjs' in this.window && utils.getTreePref('compatibility.ClassicThemeRestorer'))
- )
- allowed = true;
- TabsInTitlebar.allowedBy('TreeStyleTab-tabsOnTop', allowed);
- }
- }
- finally {
- this.tabsOnTopChangingByTST = false;
- }
- },
-
- onPopupShown : function TSTWindow_onPopupShown(aPopup)
- {
- if (!aPopup.boxObject ||
- this.evaluateXPath(
- 'parent::*/ancestor-or-self::*[local-name()="tooltip" or local-name()="panel" or local-name()="popup" or local-name()="menupopup"]',
- aPopup,
- Ci.nsIDOMXPathResult.BOOLEAN_TYPE
- ).booleanValue)
- return;
-
- this.window.setTimeout(function(aSelf) {
- if ((!aPopup.boxObject.width && !aPopup.boxObject.height) ||
- aPopup.boxObject.popupState == 'closed')
- return;
-
- var id = aPopup.id;
- var item = id && aSelf.document.getElementById(id) ? id : aPopup ;
- var index = aSelf._shownPopups.indexOf(item);
- if (index < 0)
- aSelf._shownPopups.push(item);
- }, 10, this);
- },
-
- onPopupHidden : function TSTWindow_onPopupHidden(aPopup)
- {
- var id = aPopup.id;
- aPopup = id && this.document.getElementById(id) ? id : aPopup ;
- var index = this._shownPopups.indexOf(aPopup);
- if (index > -1)
- this._shownPopups.splice(index, 1);
- },
-
- isPopupShown : function TSTWindow_isPopupShown()
- {
- this._shownPopups = this._shownPopups.filter(function(aItem) {
- if (typeof aItem == 'string')
- aItem = this.document.getElementById(aItem);
- return (
- aItem &&
- aItem.getAttribute(this.kIGNORE_POPUP_STATE) != 'true' &&
- aItem.boxObject &&
- (aItem.boxObject.width || aItem.boxObject.height) &&
- aItem.state != 'closed'
- );
- }, this);
- return this._shownPopups.length > 0;
- },
-
- onBeforeNewTabCommand : function TSTWindow_onBeforeNewTabCommand(aTabBrowser)
- {
- var self = this.windowService || this;
- if (self._clickEventOnNewTabButtonHandled)
- return;
-
- var b = aTabBrowser || this.browser;
- this.readyToOpenRelatedTabAs(b.selectedTab, utils.getTreePref('autoAttach.newTabCommand'));
- },
-
- handleNewTabActionOnButton : function TSTWindow_handleNewTabActionOnButton(aEvent)
- {
- // ignore non new-tab commands (middle click, Ctrl-click)
- if (aEvent.button != 1 && (aEvent.button != 0 || !this.isAccelKeyPressed(aEvent)))
- return;
-
- var newTabButton = this.getNewTabButtonFromEvent(aEvent);
- if (newTabButton) {
- this.readyToOpenRelatedTabAs(this.browser.selectedTab, utils.getTreePref('autoAttach.newTabButton'));
- let self = this.windowService || this;
- self._clickEventOnNewTabButtonHandled = true;
- this.Deferred.next(function() {
- self._clickEventOnNewTabButtonHandled = false;
- });
- }
- else if (aEvent.target.id == 'urlbar-go-button' || aEvent.target.id == 'go-button') {
- this.readyToOpenRelatedTabAs(this.browser.selectedTab, utils.getTreePref('autoAttach.goButton'));
- }
- },
- _clickEventOnNewTabButtonHandled : false,
-
- onBeforeTabDuplicate : function TSTWindow_onBeforeTabDuplicate(aTab, aWhere, aDelta)
- {
- if (aWhere && aWhere.indexOf('tab') != 0)
- return;
-
- var b = this.getTabBrowserFromChild(aTab) || this.browser;
- var behaviorPref = !aDelta ? 'autoAttach.duplicateTabCommand' :
- aDelta < 0 ? 'autoAttach.duplicateTabCommand.back' :
- 'autoAttach.duplicateTabCommand.forward'
- var behavior = utils.getTreePref(behaviorPref);
- this.readyToOpenRelatedTabAs(aTab || b.selectedTab, behavior);
- },
-
- onBeforeOpenLink : function TSTWindow_onBeforeOpenLink(aWhere, aOwner)
- {
- if (aWhere == 'tab' || aWhere == 'tabshifted')
- this.handleNewTabFromCurrent(aOwner);
- },
-
- onBeforeOpenLinkWithTab : function TSTWindow_onBeforeOpenLinkWithTab(aTab, aFromChrome)
- {
- if (!aFromChrome && aTab && !this.checkToOpenChildTab(aTab))
- this.handleNewTabFromCurrent(aTab);
- },
-
- onBeforeOpenNewTabByThirdParty : function TSTWindow_onBeforeOpenNewTabByThirdParty(aOwner)
- {
- if (!this.checkToOpenChildTab(aOwner))
- this.handleNewTabFromCurrent(aOwner);
- },
-
- onBeforeBrowserAccessOpenURI : function TSTWindow_onBeforeBrowserAccessOpenURI(aOpener, aWhere)
- {
- if (aOpener &&
- this.getTabFromFrame(aOpener.top) &&
- aWhere == Ci.nsIBrowserDOMWindow.OPEN_NEWTAB)
- this.handleNewTabFromCurrent(aOpener);
- },
-
- onBeforeViewMedia : function TSTWindow_onBeforeViewMedia(aEvent, aOwner)
- {
- if (String(this.window.whereToOpenLink(aEvent, false, true)).indexOf('tab') == 0)
- this.handleNewTabFromCurrent(aOwner);
- },
-
- onBeforeBrowserSearch : function TSTWindow_onBeforeBrowserSearch(aTerm, aForceNewTab)
- {
- if ((arguments.length == 1 || aForceNewTab) &&
- this.shouldOpenSearchResultAsChild(aTerm))
- this.handleNewTabFromCurrent();
- },
-
-/* Tree Style Tabの初期化が行われる前に復元されたセッションについてツリー構造を復元 */
-
- onTabRestored : function TSTWindow_onTabRestored(aEvent)
- {
- this._restoringTabs.push(aEvent.originalTarget);
- },
-
- processRestoredTabs : function TSTWindow_processRestoredTabs()
- {
- for (let i = 0, maxi = this._restoringTabs.length; i < maxi; i++)
- {
- let tab = this._restoringTabs[i];
- try {
- let b = this.getTabBrowserFromChild(aTab);
- if (b)
- b.treeStyleTab.handleRestoredTab(aTab);
- }
- catch(e) {
- }
- }
- this._restoringTabs = [];
- },
-
-/* Commands */
-
- setTabbarWidth : function TSTWindow_setTabbarWidth(aWidth, aForceExpanded) /* PUBLIC API */
- {
- this.browser.treeStyleTab.autoHide.setWidth(aWidth, aForceExpanded);
- },
-
- setContentWidth : function TSTWindow_setContentWidth(aWidth, aKeepWindowSize) /* PUBLIC API */
- {
- var w = this.window;
- var treeStyleTab = this.browser.treeStyleTab;
- var strip = treeStyleTab.tabStrip;
- var tabbarWidth = treeStyleTab.splitterWidth + (treeStyleTab.isVertical ? strip.boxObject.width : 0 );
- var contentWidth = this.browser.boxObject.width - tabbarWidth;
- if (aKeepWindowSize ||
- w.fullScreen ||
- w.windowState != Ci.nsIDOMChromeWindow.STATE_NORMAL) {
- this.setTabbarWidth(Math.max(10, this.browser.boxObject.width - aWidth));
- }
- else if (tabbarWidth + aWidth <= w.screen.availWidth) {
- w.resizeBy(aWidth - contentWidth, 0);
- }
- else {
- w.resizeBy(w.screen.availWidth - w.outerWidth, 0);
- this.setTabbarWidth(this.browser.boxObject.width - aWidth);
- }
- },
-
- toggleAutoHide : function TSTWindow_toggleAutoHide(aTabBrowser) /* PUBLIC API, for backward compatibility */
- {
- this.autoHideWindow.toggleMode(aTabBrowser || this.browser);
- },
-
- toggleFixed : function TSTWindow_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 || null, b);
- this.setPrefForActiveWindow(function() {
- b.treeStyleTab.fixed = newFixed;
- utils.setTreePref('tabbar.fixed.'+orient, newFixed);
- });
-
- b.treeStyleTab.updateTabbarState();
- },
-
- removeTabSubtree : function TSTWindow_removeTabSubtree(aTabOrTabs, aOnlyChildren)
- {
- var tabs = this.gatherSubtreeMemberTabs(aTabOrTabs, aOnlyChildren);
- if (!this.warnAboutClosingTabs(tabs.length))
- return;
-
- if (aOnlyChildren)
- tabs = this.gatherSubtreeMemberTabs(aTabOrTabs);
-
- var allSubtrees = this.splitTabsToSubtrees(tabs);
- for (let i = 0, maxi = allSubtrees.length; i < maxi; i++)
- {
- let subtreeTabs = allSubtrees[i];
- if (!this.fireTabSubtreeClosingEvent(subtreeTabs[0], subtreeTabs))
- continue;
- let b = this.getTabBrowserFromChild(subtreeTabs[0]);
- if (aOnlyChildren)
- subtreeTabs = subtreeTabs.slice(1);
- if (!subtreeTabs.length)
- continue;
- this.stopRendering();
- this.markAsClosedSet(subtreeTabs);
- for (let i = subtreeTabs.length-1; i > -1; i--)
- {
- b.removeTab(subtreeTabs[i], { animate : true });
- }
- this.startRendering();
- this.fireTabSubtreeClosedEvent(b, subtreeTabs[0], subtreeTabs)
- }
- },
- removeTabSubTree : function(...aArgs) {
- return this.removeTabSubtree.apply(this, aArgs);
- }, // obsolete, for backward compatibility
-
- fireTabSubtreeClosingEvent : function TSTWindow_fireTabSubtreeClosingEvent(aParentTab, aClosedTabs)
- {
- var b = this.getTabBrowserFromChild(aParentTab);
- var data = {
- parent : aParentTab,
- tabs : aClosedTabs
- };
- var canClose = (
- /* PUBLIC API */
- this.fireCustomEvent(this.kEVENT_TYPE_SUBTREE_CLOSING, b, true, true, data) &&
- // for backward compatibility
- this.fireCustomEvent(this.kEVENT_TYPE_SUBTREE_CLOSING.replace(/^nsDOM/, ''), b, true, true, data)
- );
- return canClose;
- },
-
- fireTabSubtreeClosedEvent : function TSTWindow_fireTabSubtreeClosedEvent(aTabBrowser, aParentTab, aClosedTabs)
- {
- aClosedTabs = aClosedTabs.filter(function(aTab) { return !aTab.parentNode; });
- var data = {
- parent : aParentTab,
- tabs : aClosedTabs
- };
-
- /* PUBLIC API */
- this.fireCustomEvent(this.kEVENT_TYPE_SUBTREE_CLOSED, aTabBrowser, true, false, data);
- // for backward compatibility
- this.fireCustomEvent(this.kEVENT_TYPE_SUBTREE_CLOSED.replace(/^nsDOM/, ''), aTabBrowser, true, false, data);
- },
-
- warnAboutClosingTabSubtreeOf : function TSTWindow_warnAboutClosingTabSubtreeOf(aTab)
- {
- if (!this.shouldCloseTabSubtreeOf(aTab))
- return true;
-
- var tabs = [aTab].concat(this.getDescendantTabs(aTab));
- return this.warnAboutClosingTabs(tabs.length);
- },
- warnAboutClosingTabSubTreeOf : function(...aArgs) {
- return this.warnAboutClosingTabSubtreeOf.apply(this, aArgs);
- }, // obsolete, for backward compatibility
-
- warnAboutClosingTabs : function TSTWindow_warnAboutClosingTabs(aTabsCount)
- {
- if (
- aTabsCount <= 1 ||
- !prefs.getPref('browser.tabs.warnOnClose')
- )
- return true;
- var checked = { value:true };
- var w = this.window;
- w.focus();
- var message = w.PluralForm.get(aTabsCount, utils.tabbrowserBundle.getString('tabs.closeWarningMultiple')).replace('#1', aTabsCount);
- var shouldClose = Services.prompt.confirmEx(w,
- utils.tabbrowserBundle.getString('tabs.closeWarningTitle'),
- message,
- (Services.prompt.BUTTON_TITLE_IS_STRING * Services.prompt.BUTTON_POS_0) +
- (Services.prompt.BUTTON_TITLE_CANCEL * Services.prompt.BUTTON_POS_1),
- utils.tabbrowserBundle.getString('tabs.closeButtonMultiple'),
- null, null,
- utils.tabbrowserBundle.getString('tabs.closeWarningPromptMe'),
- checked
- ) == 0;
- if (shouldClose && !checked.value)
- prefs.setPref('browser.tabs.warnOnClose', false);
- return shouldClose;
- },
-
- reloadTabSubtree : function TSTWindow_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(...aArgs) {
- return this.reloadTabSubtree.apply(this, aArgs);
- }, // obsolete, for backward compatibility
-
- createSubtree : function TSTWindow_createSubtree(aTabs)
- {
- var rootTabs = this.getRootTabs(aTabs);
-
- var parent = this.getParentTab(aTabs[0]);
- var next = aTabs[0];
- while (
- (next = this.getNextSiblingTab(next)) &&
- aTabs.indexOf(next) > -1
- );
-
- var b = this.getTabBrowserFromChild(aTabs[0]);
-
- rootTabs.forEach(function(aRootTab) {
- var parentTab = this.getParentTab(aRootTab);
- var descendantTabs = this.getDescendantTabs(aRootTab);
- descendantTabs.reverse().forEach(function(aDescendantTab) {
- var inTargets = aTabs.indexOf(aDescendantTab) > -1;
- var parentInTargets = aTabs.indexOf(this.getParentTab(aDescendantTab)) > -1;
- if (inTargets || (inTargets == parentInTargets))
- return;
- if (parentTab)
- b.treeStyleTab.attachTabTo(aDescendantTab, parentTab, {
- dontExpand : true,
- dontMove : true,
- insertBefore : this.getNextSiblingTab(aRootTab)
- });
- else
- b.treeStyleTab.detachTab(aDescendantTab);
- }, this);
- }, this);
-
- aTabs = rootTabs;
-
- var shouldCreateGroup = aTabs.length > 1 && utils.getTreePref('createSubtree.underParent');
- var root = shouldCreateGroup ?
- b.addTab(this.getGroupTabURI({
- temporary: utils.getTreePref('createSubtree.underParent.temporaryGroup')
- })) :
- aTabs.shift() ;
- var self = this;
- this.Deferred.next(function(self) {
- if (shouldCreateGroup) {
- for (let i = 0, maxi = aTabs.length; i < maxi; i++)
- {
- let tab = aTabs[i];
- b.treeStyleTab.attachTabTo(tab, root);
- b.treeStyleTab.collapseExpandTab(tab, false);
- }
- }
- if (parent) {
- b.treeStyleTab.attachTabTo(root, parent, {
- insertBefore : next
- });
- }
- else if (next) {
- b.treeStyleTab.moveTabSubtreeTo(root, next._tPos);
- }
- }).error(this.defaultDeferredErrorHandler);
- },
- createSubTree : function(...aArgs) {
- return this.createSubtree.apply(this, aArgs);
- }, // obsolete, for backward compatibility
-
- canCreateSubtree : function TSTWindow_canCreateSubtree(aTabs)
- {
- var rootTabs = this.getRootTabs(aTabs);
- if (rootTabs.length == 1) {
- let descendants = this.getDescendantTabs(rootTabs[0]);
- // are they already grouped?
- // if it is a partial selection, I can create new group.
- return (descendants.some(function(aDescendantTab) {
- return aTabs.indexOf(aDescendantTab) < 0;
- }, this));
- }
- return true;
- },
- canCreateSubTree : function(...aArgs) {
- return this.canCreateSubtree.apply(this, aArgs);
- }, // obsolete, for backward compatibility
-
- getRootTabs : function TSTWindow_getRootTabs(aTabs)
- {
- var roots = [];
- if (!aTabs || !aTabs.length)
- return roots;
- aTabs = this.cleanUpTabsArray(aTabs);
- for (let i = 0, maxi = aTabs.length; i < maxi; i++)
- {
- let tab = aTabs[i];
- let parent = this.getParentTab(tab);
- if (parent && aTabs.indexOf(parent) > -1)
- continue;
- roots.push(tab);
- }
- return roots;
- },
-
- collapseExpandAllSubtree : function TSTWindow_collapseExpandAllSubtree(aCollapse)
- {
- Services.obs.notifyObservers(
- this.window,
- this.kTOPIC_COLLAPSE_EXPAND_ALL,
- (aCollapse ? 'collapse' : 'open' )
- );
- },
-
- promoteTab : function TSTWindow_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.detachTab(aTab);
- let index = nextSibling ? nextSibling._tPos : b.mTabContainer.childNodes.length ;
- if (index > aTab._tPos)
- index--;
- b.moveTabTo(aTab, index);
- }
- },
-
- promoteCurrentTab : function TSTWindow_promoteCurrentTab() /* PUBLIC API */
- {
- this.promoteTab(this.browser.selectedTab);
- },
-
- demoteTab : function TSTWindow_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 TSTWindow_demoteCurrentTab() /* PUBLIC API */
- {
- this.demoteTab(this.browser.selectedTab);
- },
-
- expandTreeAfterKeyReleased : function TSTWindow_expandTreeAfterKeyReleased(aTab)
- {
- if (utils.getTreePref('autoCollapseExpandSubtreeOnSelect.whileFocusMovingByShortcut'))
- return;
- this._tabShouldBeExpandedAfterKeyReleased = aTab || null;
- },
- _tabShouldBeExpandedAfterKeyReleased : null,
-
- removeAllTabsBut : function TSTWindow_removeAllTabsBut(aTab)
- {
- var keepTabs = [aTab].concat(this.getDescendantTabs(aTab));
- var b = this.getTabBrowserFromChild(aTab);
- var closeTabs = this.getTabs(b).filter(function(aTab) {
- return keepTabs.indexOf(aTab) < 0 && !aTab.hasAttribute('pinned');
- });
-
- if (!this.warnAboutClosingTabs(closeTabs.length))
- return;
-
- this.stopRendering();
- this.markAsClosedSet(closeTabs);
- var tabs = closeTabs.reverse();
- for (let i = 0, maxi = tabs.length; i < maxi; i++)
- {
- b.removeTab(tabs[i]);
- }
- this.startRendering();
- },
-
- // For backward compatibility. You should use DOM event to block TST's focus handling.
- registerTabFocusAllowance : function TSTWindow_registerTabFocusAllowance(aProcess) /* PUBLIC API */
- {
- var listener = {
- process : aProcess,
- handleEvent : function(aEvent) {
- var tab = aEvent.originalTarget;
- var b = tab.__treestyletab__linkedTabBrowser;
- if (!this.process.call(b.treeStyleTab, b))
- aEvent.preventDefault();
- }
- };
- this.window.addEventListener(this.kEVENT_TYPE_FOCUS_NEXT_TAB, listener, false);
- this._tabFocusAllowance.push(listener);
- },
- _tabFocusAllowance : [],
-
- tearOffSubtreeFromRemote : function TSTWindow_tearOffSubtreeFromRemote()
- {
- var w = this.window;
- var remoteTab = w.arguments[0];
- var remoteWindow = remoteTab.ownerDocument.defaultView;
- var remoteService = remoteWindow.TreeStyleTabService;
- var remoteMultipleTabService = remoteWindow.MultipleTabService;
- if (remoteService.hasChildTabs(remoteTab) ||
- (remoteMultipleTabService && remoteMultipleTabService.isSelected(remoteTab))) {
- let remoteBrowser = remoteService.getTabBrowserFromChild(remoteTab);
- if (remoteBrowser.treeStyleTab.tabbarDNDObserver.isDraggingAllTabs(remoteTab)) {
- w.close();
- }
- else {
- let actionInfo = {
- action : remoteTab.__treestyletab__toBeDuplicated ? this.kACTION_DUPLICATE : this.kACTION_IMPORT
- };
-
- let b = this.browser;
- let blankTab;
- this.Deferred
- .next(function() {
- var blankTab = b.selectedTab;
- b.treeStyleTab.tabbarDNDObserver.performDrop(actionInfo, remoteTab);
- return blankTab;
- })
- .next(function(aBlankTab) {
- b.removeTab(aBlankTab);
- remoteTab = null;
- remoteBrowser = null;
- remoteWindow = null
- remoteService = null;
- remoteMultipleTabService = null;
- })
- .error(this.defaultDeferredErrorHandler);
- }
- return true;
- }
- return false;
- },
- tearOffSubTreeFromRemote : function(...aArgs) {
- return this.tearOffSubtreeFromRemote.apply(this, aArgs);
- }, // obsolete, for backward compatibility
-
- onPrintPreviewEnter : function TSTWindow_onPrintPreviewEnter()
- {
- var d = this.document;
- var event = d.createEvent('Events');
- event.initEvent(this.kEVENT_TYPE_PRINT_PREVIEW_ENTERED, true, false);
- d.documentElement.dispatchEvent(event);
-
- // for backward compatibility
- event = d.createEvent('Events');
- event.initEvent(this.kEVENT_TYPE_PRINT_PREVIEW_ENTERED.replace(/^nsDOM/, ''), true, false);
- d.documentElement.dispatchEvent(event);
- },
-
- onPrintPreviewExit : function TSTWindow_onPrintPreviewExit()
- {
- var d = this.document;
- var event = d.createEvent('Events');
- event.initEvent(this.kEVENT_TYPE_PRINT_PREVIEW_EXITED, true, false);
- d.documentElement.dispatchEvent(event);
-
- // for backward compatibility
- event = d.createEvent('Events');
- event.initEvent(this.kEVENT_TYPE_PRINT_PREVIEW_EXITED.replace(/^nsDOM/, ''), true, false);
- d.documentElement.dispatchEvent(event);
- },
-
- observe : function TSTWindow_observe(aSubject, aTopic, aData)
- {
- switch (aTopic)
- {
- case 'nsPref:changed':
- this.onPrefChange(aData);
- return;
- }
- },
- get restoringTree() {
- if (this._restoringTree || !!this.restoringCount)
- return true;
-
- var count = 0;
- this.browser.visibleTabs.some(function(aTab) {
- if (aTab.linkedBrowser.__treestyletab__toBeRestored)
- count++;
- return count > 1;
- });
- return count > 1;
- },
- set restoringTree(aValue) {
- return this._restoringTree = !!aValue;
- },
- _restoringTree : false,
-
-/* Pref Listener */
-
- domains : [
- 'extensions.treestyletab',
- 'browser.ctrlTab.previews'
- ],
-
- onPrefChange : function TSTWindow_onPrefChange(aPrefName)
- {
- var value = prefs.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 = utils.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(this.window);
- break;
-
- case 'extensions.treestyletab.tabbar.style':
- case 'extensions.treestyletab.tabbar.position':
- this.themeManager.set(prefs.getPref('extensions.treestyletab.tabbar.style'), this.position);
- break;
-
- case 'browser.ctrlTab.previews':
- this.autoHideWindow.updateKeyListeners(this.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;
- }
- }
-
-});
-
+/* ***** 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 YUKI "Piro" Hiroshi.
+ * Portions created by the Initial Developer are Copyright (C) 2012-2014
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s): YUKI "Piro" Hiroshi
+ * Tetsuharu OHZEKI
+ *
+ * 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 ******/
+
+const EXPORTED_SYMBOLS = ['TreeStyleTabWindow'];
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+const Cu = Components.utils;
+
+Cu.import('resource://gre/modules/XPCOMUtils.jsm');
+Cu.import('resource://treestyletab-modules/lib/inherit.jsm');
+
+XPCOMUtils.defineLazyGetter(this, 'window', function() {
+ Cu.import('resource://treestyletab-modules/lib/namespace.jsm');
+ return getNamespaceFor('piro.sakura.ne.jp');
+});
+XPCOMUtils.defineLazyGetter(this, 'prefs', function() {
+ Cu.import('resource://treestyletab-modules/lib/prefs.js');
+ return window['piro.sakura.ne.jp'].prefs;
+});
+
+XPCOMUtils.defineLazyModuleGetter(this, 'UninstallationListener',
+ 'resource://treestyletab-modules/lib/UninstallationListener.js');
+
+XPCOMUtils.defineLazyModuleGetter(this, 'Services', 'resource://gre/modules/Services.jsm');
+
+Cu.import('resource://treestyletab-modules/base.js');
+XPCOMUtils.defineLazyModuleGetter(this, 'TreeStyleTabBrowser', 'resource://treestyletab-modules/browser.js');
+XPCOMUtils.defineLazyModuleGetter(this, 'utils', 'resource://treestyletab-modules/utils.js', 'TreeStyleTabUtils');
+XPCOMUtils.defineLazyModuleGetter(this, 'AutoHideWindow', 'resource://treestyletab-modules/autoHide.js');
+XPCOMUtils.defineLazyModuleGetter(this, 'TreeStyleTabThemeManager', 'resource://treestyletab-modules/themeManager.js');
+XPCOMUtils.defineLazyModuleGetter(this, 'FullscreenObserver', 'resource://treestyletab-modules/fullscreenObserver.js');
+XPCOMUtils.defineLazyModuleGetter(this, 'BrowserUIShowHideObserver', 'resource://treestyletab-modules/browserUIShowHideObserver.js');
+
+function TreeStyleTabWindow(aWindow)
+{
+ this.window = aWindow;
+ this.document = aWindow.document;
+
+ this._restoringTabs = [];
+ this._shownPopups = [];
+ this.restoringCount = 0;
+
+ aWindow.addEventListener('DOMContentLoaded', this, true);
+ aWindow.addEventListener('load', this, false);
+ aWindow.TreeStyleTabService = this;
+
+ XPCOMUtils.defineLazyModuleGetter(aWindow, 'TreeStyleTabBrowser', 'resource://treestyletab-modules/browser.js');
+}
+
+TreeStyleTabWindow.prototype = inherit(TreeStyleTabBase, {
+
+ base : TreeStyleTabBase,
+
+ window : null,
+ document : null,
+
+/* API */
+
+ changeTabbarPosition : function TSTWindow_changeTabbarPosition(aNewPosition) /* PUBLIC API (obsolete, for backward compatibility) */
+ {
+ this.position = aNewPosition;
+ },
+
+ get position() /* PUBLIC API */
+ {
+ return this.preInitialized && this.browser.treeStyleTab ?
+ this.browser.treeStyleTab.position :
+ this.base.position ;
+ },
+ set position(aValue)
+ {
+ if ('UndoTabService' in this.window && this.window.UndoTabService.isUndoable()) {
+ var current = this.base.position;
+ var self = this;
+ this.window.UndoTabService.doOperation(
+ function() {
+ self.base.position = aValue;
+ },
+ {
+ label : utils.treeBundle.getString('undo_changeTabbarPosition_label'),
+ name : 'treestyletab-changeTabbarPosition',
+ data : {
+ oldPosition : current,
+ newPosition : aValue
+ }
+ }
+ );
+ }
+ else {
+ this.base.position = aValue;
+ }
+ return aValue;
+ },
+
+ undoChangeTabbarPosition : function TSTWindow_undoChangeTabbarPosition() /* PUBLIC API */
+ {
+ return this.base.undoChangeTabbarPosition();
+ },
+
+ redoChangeTabbarPosition : function TSTWindow_redoChangeTabbarPosition() /* PUBLIC API */
+ {
+ return this.base.redoChangeTabbarPosition();
+ },
+
+ get treeViewEnabled() /* PUBLIC API */
+ {
+ return this.base.treeViewEnabled;
+ },
+ set treeViewEnabled(aValue)
+ {
+ return this.base.treeViewEnabled = aValue;
+ },
+
+ get useTMPSessionAPI() /* PUBLIC API */
+ {
+ return this.base.useTMPSessionAPI;
+ },
+ set useTMPSessionAPI(aValue)
+ {
+ return this.base.useTMPSessionAPI = aValue;
+ },
+
+ get browser()
+ {
+ var w = this.window;
+ this.assertBeforeDestruction(w);
+ return 'SplitBrowser' in w ? w.SplitBrowser.activeBrowser :
+ w.gBrowser ;
+ },
+
+ get browserToolbox()
+ {
+ var w = this.window;
+ return w.gToolbox || w.gNavToolbox;
+ },
+
+ get browserBox()
+ {
+ return this.document.getElementById('browser');
+ },
+
+ get browserBottomBox()
+ {
+ return this.document.getElementById('browser-bottombox');
+ },
+
+ get isPopupWindow()
+ {
+ return (
+ this.document &&
+ this.document.documentElement.getAttribute('chromehidden') != '' &&
+ !this.window.gBrowser.treeStyleTab.isVisible
+ );
+ },
+
+/* backward compatibility */
+ getTempTreeStyleTab : function TSTWindow_getTempTreeStyleTab(aTabBrowser)
+ {
+ return aTabBrowser.treeStyleTab || new TreeStyleTabBrowser(this, aTabBrowser);
+ },
+
+ initTabAttributes : function TSTWindow_initTabAttributes(aTab, aTabBrowser)
+ {
+ var b = aTabBrowser || this.getTabBrowserFromChild(aTab);
+ this.getTempTreeStyleTab(b).initTabAttributes(aTab);
+ },
+
+ initTabContents : function TSTWindow_initTabContents(aTab, aTabBrowser)
+ {
+ var b = aTabBrowser || this.getTabBrowserFromChild(aTab);
+ this.getTempTreeStyleTab(b).initTabContents(aTab);
+ },
+
+ initTabContentsOrder : function TSTWindow_initTabContentsOrder(aTab, aTabBrowser)
+ {
+ var b = aTabBrowser || this.getTabBrowserFromChild(aTab);
+ this.getTempTreeStyleTab(b).initTabContentsOrder(aTab);
+ },
+
+/* Utilities */
+
+ stopRendering : function TSTWindow_stopRendering()
+ {
+ this.window['piro.sakura.ne.jp'].stopRendering.stop();
+ },
+ startRendering : function TSTWindow_startRendering()
+ {
+ this.window['piro.sakura.ne.jp'].stopRendering.start();
+ },
+
+ getPropertyPixelValue : function TSTWindow_getPropertyPixelValue(aElementOrStyle, aProp)
+ {
+ var style = aElementOrStyle instanceof Ci.nsIDOMCSSStyleDeclaration ?
+ aElementOrStyle :
+ this.window.getComputedStyle(aElementOrStyle, null) ;
+ return Number(style.getPropertyValue(aProp).replace(/px$/, ''));
+ },
+
+ get isToolbarCustomizing()
+ {
+ var toolbox = this.browserToolbox;
+ return toolbox && toolbox.customizing;
+ },
+
+ get maximized()
+ {
+ var sizemode = this.document.documentElement.getAttribute('sizemode');
+ return (
+ this.window.fullScreen ||
+ this.window.windowState == this.window.STATE_MAXIMIZED ||
+ sizemode == 'maximized' ||
+ sizemode == 'fullscreen'
+ );
+ },
+
+ maxTabbarWidth : function TSTWindow_maxTabbarWidth(aWidth, aTabBrowser)
+ {
+ aTabBrowser = aTabBrowser || this.browser;
+ var safePadding = 20; // for window border, etc.
+ var windowWidth = this.maximized ? this.window.screen.availWidth - safePadding : this.window.outerWidth ;
+ var rootWidth = parseInt(this.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 TSTWindow_maxTabbarHeight(aHeight, aTabBrowser)
+ {
+ aTabBrowser = aTabBrowser || this.browser;
+ var safePadding = 20; // for window border, etc.
+ var windowHeight = this.maximized ? this.window.screen.availHeight - safePadding : this.window.outerHeight ;
+ var rootHeight = parseInt(this.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 TSTWindow_shouldOpenSearchResultAsChild(aTerm)
+ {
+ aTerm = aTerm.trim();
+
+ var mode = utils.getTreePref('autoAttach.searchResult');
+ if (mode == this.kSEARCH_RESULT_ATTACH_ALWAYS) {
+ return true;
+ }
+ else if (!aTerm || mode == this.kSEARCH_RESULT_DO_NOT_ATTACH) {
+ return false;
+ }
+
+ var selection = this.window.getBrowserSelection();
+ return selection.trim() == aTerm;
+ },
+ kSEARCH_RESULT_DO_NOT_ATTACH : 0,
+ kSEARCH_RESULT_ATTACH_IF_SELECTED : 1,
+ kSEARCH_RESULT_ATTACH_ALWAYS : 2,
+
+ get isAutoHide()
+ {
+ return this.window.fullScreen ?
+ (
+ prefs.getPref('browser.fullscreen.autohide') &&
+ utils.getTreePref('tabbar.autoHide.mode.fullscreen')
+ ) :
+ utils.getTreePref('tabbar.autoHide.mode');
+ },
+
+ get autoHideWindow()
+ {
+ if (!this._autoHideWindow) {
+ this._autoHideWindow = new AutoHideWindow(this.window);
+ }
+ return this._autoHideWindow;
+ },
+
+ get themeManager()
+ {
+ if (!this._themeManager) {
+ this._themeManager = new TreeStyleTabThemeManager(this.window);
+ }
+ return this._themeManager;
+ },
+
+/* Initializing */
+
+ preInit : function TSTWindow_preInit()
+ {
+ if (this.preInitialized)
+ return;
+ this.preInitialized = true;
+
+ var w = this.window;
+ w.removeEventListener('DOMContentLoaded', this, true);
+ if (w.location.href.indexOf('chrome://browser/content/browser.xul') != 0)
+ return;
+
+ w.addEventListener('SSTabRestoring', this, true);
+
+ w.TreeStyleTabWindowHelper.preInit();
+
+ // initialize theme
+ this.onPrefChange('extensions.treestyletab.tabbar.style');
+ },
+ preInitialized : false,
+
+ init : function TSTWindow_init()
+ {
+ var w = this.window;
+ w.removeEventListener('load', this, false);
+
+ w.addEventListener('unload', this, false);
+
+ if (
+ w.location.href.indexOf('chrome://browser/content/browser.xul') != 0 ||
+ !this.browser
+ )
+ return;
+
+ if (this.initialized)
+ return;
+
+ if (!this.preInitialized) {
+ this.preInit();
+ }
+ w.removeEventListener('SSTabRestoring', this, true);
+
+ var d = this.document;
+ d.addEventListener('popupshowing', this, false);
+ d.addEventListener('popuphiding', this, true);
+ d.addEventListener(this.kEVENT_TYPE_TAB_COLLAPSED_STATE_CHANGED, this, false);
+ d.addEventListener(this.kEVENT_TYPE_TABBAR_POSITION_CHANGED, this, false);
+ d.addEventListener(this.kEVENT_TYPE_TABBAR_STATE_CHANGED, this, false);
+ d.addEventListener(this.kEVENT_TYPE_FOCUS_NEXT_TAB, this, false);
+ w.addEventListener('beforecustomization', this, true);
+ w.addEventListener('aftercustomization', this, false);
+
+ w.messageManager.addMessageListener('SessionStore:restoreTabContentStarted', this);
+
+ this.fullscreenObserver = new FullscreenObserver(this.window);
+ this.initUIShowHideObserver();
+
+ var appcontent = d.getElementById('appcontent');
+ appcontent.addEventListener('SubBrowserAdded', this, false);
+ appcontent.addEventListener('SubBrowserRemoveRequest', this, false);
+
+ w.addEventListener('UIOperationHistoryUndo:TabbarOperations', this, false);
+ w.addEventListener('UIOperationHistoryRedo:TabbarOperations', this, false);
+
+ prefs.addPrefListener(this);
+
+ this.initUninstallationListener();
+
+ w.TreeStyleTabWindowHelper.onBeforeBrowserInit();
+ this.initTabBrowser(this.browser);
+ w.TreeStyleTabWindowHelper.onAfterBrowserInit();
+
+ this.processRestoredTabs();
+ this.updateTabsOnTop();
+
+ // Init autohide service only if it have to be activated.
+ if (this.isAutoHide)
+ this.onPrefChange('extensions.treestyletab.tabbar.autoHide.mode');
+
+ this.onPrefChange('extensions.treestyletab.autoCollapseExpandSubtreeOnSelect.whileFocusMovingByShortcut');
+
+ this.initialized = true;
+ },
+ initialized : false,
+
+ initUninstallationListener : function TSTWindow_initUninstallationListener()
+ {
+ var restorePrefs = function() {
+ if (prefs.getPref('extensions.treestyletab.tabsOnTop.originalState')) {
+ prefs.clearPref('extensions.treestyletab.tabsOnTop.originalState');
+ try {
+ this.browser.treeStyleTab.position = 'top';
+ }
+ catch(e) {
+ }
+ this.window.TabsOnTop.enabled = true;
+ }
+ }.bind(this);
+ new UninstallationListener({
+ id : 'treestyletab@piro.sakura.ne.jp',
+ onuninstalled : restorePrefs,
+ ondisabled : restorePrefs
+ });
+ },
+
+ initTabBrowser : function TSTWindow_initTabBrowser(aTabBrowser)
+ {
+ if (aTabBrowser.localName != 'tabbrowser')
+ return;
+ (new TreeStyleTabBrowser(this, aTabBrowser)).init();
+ },
+
+ updateAllTabsButton : function TSTWindow_updateAllTabsButton(aTabBrowser)
+ {
+ var d = this.document;
+ aTabBrowser = aTabBrowser || this.browser;
+ var allTabsButton = d.getElementById('alltabs-button') ||
+ ( // Tab Mix Plus
+ utils.getTreePref('compatibility.TMP') &&
+ d.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 TSTWindow_updateAllTabsPopup(aEvent)
+ {
+ if (!utils.getTreePref('enableSubtreeIndent.allTabsPopup'))
+ return;
+
+ Array.forEach(aEvent.originalTarget.childNodes, function(aItem) {
+ if (aItem.classList.contains('alltabs-item') && 'tab' in aItem)
+ aItem.style.marginLeft = aItem.tab.getAttribute(this.kNEST) + 'em';
+ }, this);
+ },
+
+ initUIShowHideObserver : function TSTWindow_initUIShowHideObserver()
+ {
+ this.rootElementObserver = new BrowserUIShowHideObserver(this, this.document.documentElement);
+
+ var toolbox = this.browserToolbox;
+ if (toolbox)
+ this.browserToolboxObserver = new BrowserUIShowHideObserver(this, toolbox);
+
+ var browserBox = this.browserBox;
+ if (browserBox)
+ this.browserBoxObserver = new BrowserUIShowHideObserver(this, browserBox);
+
+ var bottomBox = this.browserBottomBox;
+ if (bottomBox)
+ this.browserBottomBoxObserver = new BrowserUIShowHideObserver(this, bottomBox);
+ },
+
+ destroy : function TSTWindow_destroy()
+ {
+ var w = this.window;
+ if (this.browser) {
+ this.base.inWindowDestoructionProcess = true;
+ try {
+ w.removeEventListener('unload', this, false);
+
+ this.autoHideWindow.destroy();
+ delete this._autoHideWindow;
+
+ this.themeManager.destroy();
+ delete this._themeManager;
+
+ this.browser.treeStyleTab.saveCurrentState();
+ this.destroyTabBrowser(this.browser);
+
+ this.endListenKeyEventsFor(this.LISTEN_FOR_AUTOHIDE);
+ this.endListenKeyEventsFor(this.LISTEN_FOR_AUTOEXPAND_BY_FOCUSCHANGE);
+
+ let d = this.document;
+ d.removeEventListener('popupshowing', this, false);
+ d.removeEventListener('popuphiding', this, true);
+ d.removeEventListener(this.kEVENT_TYPE_TAB_COLLAPSED_STATE_CHANGED, this, false);
+ d.removeEventListener(this.kEVENT_TYPE_TABBAR_POSITION_CHANGED, this, false);
+ d.removeEventListener(this.kEVENT_TYPE_TABBAR_STATE_CHANGED, this, false);
+ d.removeEventListener(this.kEVENT_TYPE_FOCUS_NEXT_TAB, this, false);
+ w.removeEventListener('beforecustomization', this, true);
+ w.removeEventListener('aftercustomization', this, false);
+
+ w.messageManager.removeMessageListener('SessionStore:restoreTabContentStarted', this);
+
+ this.fullscreenObserver.destroy();
+ delete this.fullscreenObserver;
+
+ this.rootElementObserver.destroy();
+ delete this.rootElementObserver;
+
+ if (this.browserToolboxObserver) {
+ this.browserToolboxObserver.destroy();
+ delete this.browserToolboxObserver;
+ }
+ if (this.browserBoxObserver) {
+ this.browserBoxObserver.destroy();
+ delete this.browserBoxObserver;
+ }
+ if (this.browserBottomBoxObserver) {
+ this.browserBottomBoxObserver.destroy();
+ delete this.browserBottomBoxObserver;
+ }
+
+ for (let i = 0, maxi = this._tabFocusAllowance.length; i < maxi; i++)
+ {
+ w.removeEventListener(this.kEVENT_TYPE_FOCUS_NEXT_TAB, this._tabFocusAllowance[i], false);
+ }
+
+ var appcontent = d.getElementById('appcontent');
+ appcontent.removeEventListener('SubBrowserAdded', this, false);
+ appcontent.removeEventListener('SubBrowserRemoveRequest', this, false);
+
+ w.removeEventListener('UIOperationHistoryUndo:TabbarOperations', this, false);
+ w.removeEventListener('UIOperationHistoryRedo:TabbarOperations', this, false);
+
+ prefs.removePrefListener(this);
+ }
+ catch(e) {
+ throw e;
+ }
+ finally {
+ this.base.inWindowDestoructionProcess = false;
+ }
+ }
+
+ delete w.TreeStyleTabService;
+ delete this.window;
+ delete this.document;
+ },
+
+ destroyTabBrowser : function TSTWindow_destroyTabBrowser(aTabBrowser)
+ {
+ if (aTabBrowser.localName != 'tabbrowser')
+ return;
+ aTabBrowser.treeStyleTab.destroy();
+ delete aTabBrowser.treeStyleTab;
+ },
+
+/* Event Handling */
+
+ handleEvent : function TSTWindow_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 'blur':
+ return this.simulateKeyRelease();
+
+ 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 'click':
+ return this.handleNewTabActionOnButton(aEvent);
+
+
+ case 'beforecustomization':
+ this.window.TreeStyleTabWindowHelper.destroyToolbarItems();
+ return;
+
+ case 'aftercustomization':
+ this.window.TreeStyleTabWindowHelper.initToolbarItems();
+ return;
+
+
+ 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.position = aEvent.entry.data.oldPosition;
+ return;
+ case 'treestyletab-changeTabbarPosition-private':
+ aEvent.entry.data.target.treeStyleTab.position = aEvent.entry.data.oldPosition;
+ return;
+ }
+ return;
+
+ case 'UIOperationHistoryRedo:TabbarOperations':
+ switch (aEvent.entry.name)
+ {
+ case 'treestyletab-changeTabbarPosition':
+ this.position = aEvent.entry.data.newPosition;
+ return;
+ case 'treestyletab-changeTabbarPosition-private':
+ aEvent.entry.data.target.treeStyleTab.position = aEvent.entry.data.newPosition;
+ return;
+ }
+ return;
+ }
+ },
+
+ keyEventListening : false,
+ keyEventListeningFlags : 0,
+
+ LISTEN_FOR_AUTOHIDE : 1,
+ LISTEN_FOR_AUTOEXPAND_BY_FOCUSCHANGE : 2,
+
+ startListenKeyEventsFor : function TSTWindow_startListenKeyEventsFor(aReason)
+ {
+ if (this.keyEventListeningFlags & aReason)
+ return;
+ if (!this.keyEventListening) {
+ let w = this.window;
+ w.addEventListener('keydown', this, true);
+ w.addEventListener('keyup', this, true);
+ w.addEventListener('keypress', this, true);
+ w.addEventListener('blur', this, true);
+ this.keyEventListening = true;
+ }
+ this.keyEventListeningFlags |= aReason;
+ },
+
+ endListenKeyEventsFor : function TSTWindow_endListenKeyEventsFor(aReason)
+ {
+ if (!(this.keyEventListeningFlags & aReason))
+ return;
+ this.keyEventListeningFlags ^= aReason;
+ if (!this.keyEventListeningFlags && this.keyEventListening) {
+ let w = this.window;
+ w.removeEventListener('keydown', this, true);
+ w.removeEventListener('keyup', this, true);
+ w.removeEventListener('keypress', this, true);
+ w.removeEventListener('blur', this, true);
+ this.keyEventListening = false;
+ }
+ },
+
+ onKeyDown : function TSTWindow_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;
+
+ var left = aEvent.keyCode == Ci.nsIDOMKeyEvent.DOM_VK_LEFT;
+ var right = aEvent.keyCode == Ci.nsIDOMKeyEvent.DOM_VK_RIGHT;
+ var up = aEvent.keyCode == Ci.nsIDOMKeyEvent.DOM_VK_UP;
+ var down = aEvent.keyCode == Ci.nsIDOMKeyEvent.DOM_VK_DOWN;
+ if (
+ Services.focus.focusedElement == this.browser.selectedTab &&
+ (up || down || left || right)
+ )
+ this.arrowKeyEventOnTab = {
+ keyCode : aEvent.keyCode,
+ left : left,
+ right : right,
+ up : up,
+ down : down,
+ altKey : aEvent.altKey,
+ ctrlKey : aEvent.ctrlKey,
+ metaKey : aEvent.metaKey,
+ shiftKey : aEvent.shiftKey
+ };
+
+ var b = this.browser;
+ var data = {
+ sourceEvent : aEvent
+ };
+
+ /* PUBLIC API */
+ this.fireCustomEvent(this.kEVENT_TYPE_TAB_FOCUS_SWITCHING_KEY_DOWN, b, true, false, data);
+ // for backward compatibility
+ this.fireCustomEvent(this.kEVENT_TYPE_TAB_FOCUS_SWITCHING_KEY_DOWN.replace(/^nsDOM/, ''), b, true, false, data);
+ },
+ accelKeyPressed : false,
+ arrowKeyEventOnTab : null,
+
+ onKeyRelease : function TSTWindow_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;
+ this.window.setTimeout(function(aSelf) {
+ aSelf.arrowKeyEventOnTab = null;
+ }, 10, this);
+
+ 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));
+
+ var data = {
+ scrollDown : scrollDown,
+ scrollUp : scrollUp,
+ standBy : standBy,
+ onlyShiftKey : onlyShiftKey,
+ sourceEvent : aEvent
+ };
+
+ if (
+ scrollDown ||
+ scrollUp ||
+ ( // when you release "shift" key
+ standBy && onlyShiftKey
+ )
+ ) {
+ /* PUBLIC API */
+ this.fireCustomEvent(this.kEVENT_TYPE_TAB_FOCUS_SWITCHING_START, b, true, false, data);
+ // for backward compatibility
+ this.fireCustomEvent(this.kEVENT_TYPE_TAB_FOCUS_SWITCHING_START.replace(/^nsDOM/, ''), b, true, false, data);
+ return;
+ }
+
+ if (aEvent.type == 'keypress' ?
+ // ignore keypress on Ctrl-R, Ctrl-T, etc.
+ aEvent.charCode != 0 :
+ // ignore keyup not on the Ctrl key
+ aEvent.keyCode != Ci.nsIDOMKeyEvent.DOM_VK_CONTROL
+ )
+ return;
+
+ // when you just release accel key...
+
+ /* PUBLIC API */
+ let (event) {
+ this.fireCustomEvent(this.kEVENT_TYPE_TAB_FOCUS_SWITCHING_END, b, true, false, data);
+ // for backward compatibility
+ this.fireCustomEvent(this.kEVENT_TYPE_TAB_FOCUS_SWITCHING_END.replace(/^nsDOM/, ''), b, true, false, data);
+ }
+
+ if (this._tabShouldBeExpandedAfterKeyReleased) {
+ let tab = this._tabShouldBeExpandedAfterKeyReleased;
+ if (this.hasChildTabs(tab) &&
+ this.isSubtreeCollapsed(tab)) {
+ this.getTabBrowserFromChild(tab)
+ .treeStyleTab
+ .collapseExpandTreesIntelligentlyFor(tab);
+ }
+ }
+ this._tabShouldBeExpandedAfterKeyReleased = null;
+ },
+ // When the window lose its focus, we cannot detect any key-release events.
+ // So we have to simulate key-release event manually.
+ // See: https://github.com/piroor/treestyletab/issues/654
+ simulateKeyRelease : function TSTWindow_simulateKeyRelease()
+ {
+ if (!this.accelKeyPressed)
+ return;
+
+ this.accelKeyPressed = false;
+ var data = {
+ scrollDown : false,
+ scrollUp : false,
+ standBy : false,
+ onlyShiftKey : false,
+ sourceEvent : null
+ };
+ /* PUBLIC API */
+ this.fireCustomEvent(this.kEVENT_TYPE_TAB_FOCUS_SWITCHING_END, this.browser, true, false, data);
+ // for backward compatibility
+ this.fireCustomEvent(this.kEVENT_TYPE_TAB_FOCUS_SWITCHING_END.replace(/^nsDOM/, ''), this.browser, true, false, data);
+ },
+
+ get shouldListenKeyEventsForAutoExpandByFocusChange()
+ {
+ return !this.ctrlTabPreviewsEnabled &&
+ (
+ utils.getTreePref('autoExpandSubtreeOnSelect.whileFocusMovingByShortcut') ||
+ utils.getTreePref('autoCollapseExpandSubtreeOnSelect')
+ );
+ },
+
+ get ctrlTabPreviewsEnabled()
+ {
+ return 'allTabs' in this.window &&
+ prefs.getPref('browser.ctrlTab.previews');
+ },
+
+ receiveMessage : function TSTWindow_receiveMessage(aMessage)
+ {
+ var browser = aMessage.target;
+ var tabbrowser = this.getTabBrowserFromChild(browser);
+ if (!tabbrowser)
+ return;
+ var tab = tabbrowser.treeStyleTab.getTabFromBrowser(browser);
+ if (!tab)
+ return;
+
+ switch (aMessage.name)
+ {
+ case 'SessionStore:restoreTabContentStarted':
+ return tabbrowser.treeStyleTab.onRestoreTabContentStarted(tab);
+ }
+ },
+
+ onTabbarResizeStart : function TSTWindow_onTabbarResizeStart(aEvent)
+ {
+ if (aEvent.button != 0)
+ return;
+
+ if (!this.isEventFiredOnGrippy(aEvent))
+ 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 TSTWindow_onTabbarResizeEnd(aEvent)
+ {
+ if (this.tabbarResizeStartWidth < 0)
+ return;
+
+ var target = aEvent.currentTarget;
+ var b = this.getTabBrowserFromChild(target);
+
+ aEvent.stopPropagation();
+ if ('releaseCapture' in target)
+ target.releaseCapture();
+
+ target.removeEventListener('mousemove', this, false);
+
+ this.tabbarResizeStartWidth = -1;
+ this.tabbarResizeStartHeight = -1;
+ this.tabbarResizeStartX = -1;
+ this.tabbarResizeStartY = -1;
+
+ this.Deferred.next(function() {
+ b.treeStyleTab.fixTooNarrowTabbar();
+ }).error(this.defaultDeferredErrorHandler);
+ },
+ onTabbarResizing : function TSTWindow_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.position;
+ 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.setPrefForActiveWindow(function() {
+ utils.setTreePref('tabbar.width', width);
+ });
+ if (b.treeStyleTab.autoHide.mode == b.treeStyleTab.autoHide.kMODE_SHRINK &&
+ b.treeStyleTab.tabStripPlaceHolder)
+ b.treeStyleTab.tabStripPlaceHolder.setAttribute('width', utils.getTreePref('tabbar.shrunkenWidth'));
+ }
+ else {
+ this.setPrefForActiveWindow(function() {
+ utils.setTreePref('tabbar.shrunkenWidth', width);
+ });
+ }
+ }
+ else {
+ let delta = aEvent.screenY - this.tabbarResizeStartY;
+ height += (pos == 'top' ? delta : -delta );
+ this.setPrefForActiveWindow(function() {
+ utils.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 TSTWindow_onTabbarReset(aEvent)
+ {
+ if (aEvent.button != 0)
+ return;
+ var b = this.getTabBrowserFromChild(aEvent.currentTarget);
+ if (b) {
+ b.treeStyleTab.resetTabbarSize();
+ aEvent.stopPropagation();
+ }
+ },
+
+ onFocusNextTab : function TSTWindow_onFocusNextTab(aEvent)
+ {
+ var tab = aEvent.originalTarget;
+ var b = this.getTabBrowserFromChild(tab);
+ if (
+ prefs.getPref('browser.tabs.selectOwnerOnClose') &&
+ tab.owner &&
+ (
+ !b._removingTabs ||
+ b._removingTabs.indexOf(tab.owner) < 0
+ )
+ )
+ aEvent.preventDefault();
+ },
+
+ showHideSubtreeMenuItem : function TSTWindow_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(...aArgs) {
+ return this.showHideSubtreeMenuItem.apply(this, aArgs);
+ }, // obsolete, for backward compatibility
+
+ updateAeroPeekPreviews : function TSTWindow_updateAeroPeekPreviews()
+ {
+ var w = this.window;
+ if (
+ this.updateAeroPeekPreviewsTimer ||
+ !prefs.getPref('browser.taskbar.previews.enable') ||
+ !utils.getTreePref('taskbarPreviews.hideCollapsedTabs') ||
+ !('Win7Features' in w) ||
+ !w.Win7Features ||
+ !this.AeroPeek ||
+ !this.AeroPeek.windows
+ )
+ return;
+
+ this.updateAeroPeekPreviewsTimer = w.setTimeout(function(aSelf) {
+ aSelf.updateAeroPeekPreviewsTimer = null;
+ try {
+ aSelf.updateAeroPeekPreviewsInternal();
+ }
+ catch(e) {
+ dump(e+'\n');
+ aSelf.updateAeroPeekPreviews();
+ }
+ }, 250, this);
+ },
+ updateAeroPeekPreviewsTimer : null,
+ updateAeroPeekPreviewsInternal : function TSTWindow_updateAeroPeekPreviewsInternal()
+ {
+ if (
+ !prefs.getPref('browser.taskbar.previews.enable') ||
+ !utils.getTreePref('taskbarPreviews.hideCollapsedTabs')
+ )
+ return;
+
+ this.AeroPeek.windows.some(function(aTabWindow) {
+ if (aTabWindow.win == this.window) {
+ let previews = aTabWindow.previews;
+ for (let i = 0, maxi = previews.length; i < maxi; i++)
+ {
+ let preview = previews[i];
+ if (!preview)
+ continue;
+ let tab = preview.controller.wrappedJSObject.tab;
+ preview.visible = !this.isCollapsed(tab);
+ }
+ this.AeroPeek.checkPreviewCount();
+ return true;
+ }
+ return false;
+ }, this);
+ },
+
+ updateTabsOnTop : function TSTWindow_updateTabsOnTop()
+ {
+ if (
+ this.isPopupWindow ||
+ this.tabsOnTopChangingByUI ||
+ this.tabsOnTopChangingByTST
+ )
+ return;
+
+ var TabsOnTop = this.window.TabsOnTop;
+ var TabsInTitlebar = this.window.TabsInTitlebar;
+ var isTopTabbar = this.browser.treeStyleTab.position == 'top';
+
+ this.tabsOnTopChangingByTST = true;
+
+ try {
+ if (TabsOnTop) {
+ let originalState = utils.getTreePref('tabsOnTop.originalState');
+ if (originalState === null) {
+ let current = prefs.getDefaultPref('browser.tabs.onTop') === null ?
+ TabsOnTop.enabled :
+ prefs.getPref('browser.tabs.onTop') ;
+ utils.setTreePref('tabsOnTop.originalState', originalState = current);
+ }
+
+ if (!isTopTabbar || !this.browser.treeStyleTab.fixed) {
+ if (TabsOnTop.enabled)
+ TabsOnTop.enabled = false;
+ }
+ else {
+ if (TabsOnTop.enabled != originalState)
+ TabsOnTop.enabled = originalState;
+ utils.clearTreePref('tabsOnTop.originalState');
+ }
+ }
+ if (TabsInTitlebar) {
+ let allowed = isTopTabbar && this.browser.treeStyleTab.fixed;
+ if (
+ (this.window.TabsOnBottom && utils.getTreePref('compatibility.TabsOnBottom')) ||
+ ('navbarontop' in this.window && utils.getTreePref('compatibility.NavbarOnTitlebar')) ||
+ ('classicthemerestorerjs' in this.window && utils.getTreePref('compatibility.ClassicThemeRestorer'))
+ )
+ allowed = true;
+ TabsInTitlebar.allowedBy('TreeStyleTab-tabsOnTop', allowed);
+ }
+ }
+ finally {
+ this.tabsOnTopChangingByTST = false;
+ }
+ },
+
+ onPopupShown : function TSTWindow_onPopupShown(aPopup)
+ {
+ if (!aPopup.boxObject ||
+ this.evaluateXPath(
+ 'parent::*/ancestor-or-self::*[local-name()="tooltip" or local-name()="panel" or local-name()="popup" or local-name()="menupopup"]',
+ aPopup,
+ Ci.nsIDOMXPathResult.BOOLEAN_TYPE
+ ).booleanValue)
+ return;
+
+ this.window.setTimeout(function(aSelf) {
+ if ((!aPopup.boxObject.width && !aPopup.boxObject.height) ||
+ aPopup.boxObject.popupState == 'closed')
+ return;
+
+ var id = aPopup.id;
+ var item = id && aSelf.document.getElementById(id) ? id : aPopup ;
+ var index = aSelf._shownPopups.indexOf(item);
+ if (index < 0)
+ aSelf._shownPopups.push(item);
+ }, 10, this);
+ },
+
+ onPopupHidden : function TSTWindow_onPopupHidden(aPopup)
+ {
+ var id = aPopup.id;
+ aPopup = id && this.document.getElementById(id) ? id : aPopup ;
+ var index = this._shownPopups.indexOf(aPopup);
+ if (index > -1)
+ this._shownPopups.splice(index, 1);
+ },
+
+ isPopupShown : function TSTWindow_isPopupShown()
+ {
+ this._shownPopups = this._shownPopups.filter(function(aItem) {
+ if (typeof aItem == 'string')
+ aItem = this.document.getElementById(aItem);
+ return (
+ aItem &&
+ aItem.getAttribute(this.kIGNORE_POPUP_STATE) != 'true' &&
+ aItem.boxObject &&
+ (aItem.boxObject.width || aItem.boxObject.height) &&
+ aItem.state != 'closed'
+ );
+ }, this);
+ return this._shownPopups.length > 0;
+ },
+
+ onBeforeNewTabCommand : function TSTWindow_onBeforeNewTabCommand(aTabBrowser)
+ {
+ var self = this.windowService || this;
+ if (self._clickEventOnNewTabButtonHandled)
+ return;
+
+ var b = aTabBrowser || this.browser;
+ this.readyToOpenRelatedTabAs(b.selectedTab, utils.getTreePref('autoAttach.newTabCommand'));
+ },
+
+ handleNewTabActionOnButton : function TSTWindow_handleNewTabActionOnButton(aEvent)
+ {
+ // ignore non new-tab commands (middle click, Ctrl-click)
+ if (aEvent.button != 1 && (aEvent.button != 0 || !this.isAccelKeyPressed(aEvent)))
+ return;
+
+ var newTabButton = this.getNewTabButtonFromEvent(aEvent);
+ if (newTabButton) {
+ this.readyToOpenRelatedTabAs(this.browser.selectedTab, utils.getTreePref('autoAttach.newTabButton'));
+ let self = this.windowService || this;
+ self._clickEventOnNewTabButtonHandled = true;
+ this.Deferred.next(function() {
+ self._clickEventOnNewTabButtonHandled = false;
+ });
+ }
+ else if (aEvent.target.id == 'urlbar-go-button' || aEvent.target.id == 'go-button') {
+ this.readyToOpenRelatedTabAs(this.browser.selectedTab, utils.getTreePref('autoAttach.goButton'));
+ }
+ },
+ _clickEventOnNewTabButtonHandled : false,
+
+ onBeforeTabDuplicate : function TSTWindow_onBeforeTabDuplicate(aTab, aWhere, aDelta)
+ {
+ if (aWhere && aWhere.indexOf('tab') != 0)
+ return;
+
+ var b = this.getTabBrowserFromChild(aTab) || this.browser;
+ var behaviorPref = !aDelta ? 'autoAttach.duplicateTabCommand' :
+ aDelta < 0 ? 'autoAttach.duplicateTabCommand.back' :
+ 'autoAttach.duplicateTabCommand.forward'
+ var behavior = utils.getTreePref(behaviorPref);
+ this.readyToOpenRelatedTabAs(aTab || b.selectedTab, behavior);
+ },
+
+ onBeforeOpenLink : function TSTWindow_onBeforeOpenLink(aWhere, aOwner)
+ {
+ if (aWhere == 'tab' || aWhere == 'tabshifted')
+ this.handleNewTabFromCurrent(aOwner);
+ },
+
+ onBeforeOpenLinkWithTab : function TSTWindow_onBeforeOpenLinkWithTab(aTab, aFromChrome)
+ {
+ if (!aFromChrome && aTab && !this.checkToOpenChildTab(aTab))
+ this.handleNewTabFromCurrent(aTab);
+ },
+
+ onBeforeOpenNewTabByThirdParty : function TSTWindow_onBeforeOpenNewTabByThirdParty(aOwner)
+ {
+ if (!this.checkToOpenChildTab(aOwner))
+ this.handleNewTabFromCurrent(aOwner);
+ },
+
+ onBeforeBrowserAccessOpenURI : function TSTWindow_onBeforeBrowserAccessOpenURI(aOpener, aWhere)
+ {
+ if (aOpener &&
+ this.getTabFromFrame(aOpener.top) &&
+ aWhere == Ci.nsIBrowserDOMWindow.OPEN_NEWTAB)
+ this.handleNewTabFromCurrent(aOpener);
+ },
+
+ onBeforeViewMedia : function TSTWindow_onBeforeViewMedia(aEvent, aOwner)
+ {
+ if (String(this.window.whereToOpenLink(aEvent, false, true)).indexOf('tab') == 0)
+ this.handleNewTabFromCurrent(aOwner);
+ },
+
+ onBeforeBrowserSearch : function TSTWindow_onBeforeBrowserSearch(aTerm, aForceNewTab)
+ {
+ if ((arguments.length == 1 || aForceNewTab) &&
+ this.shouldOpenSearchResultAsChild(aTerm))
+ this.handleNewTabFromCurrent();
+ },
+
+/* Tree Style Tabの初期化が行われる前に復元されたセッションについてツリー構造を復元 */
+
+ onTabRestored : function TSTWindow_onTabRestored(aEvent)
+ {
+ this._restoringTabs.push(aEvent.originalTarget);
+ },
+
+ processRestoredTabs : function TSTWindow_processRestoredTabs()
+ {
+ for (let i = 0, maxi = this._restoringTabs.length; i < maxi; i++)
+ {
+ let tab = this._restoringTabs[i];
+ try {
+ let b = this.getTabBrowserFromChild(aTab);
+ if (b)
+ b.treeStyleTab.handleRestoredTab(aTab);
+ }
+ catch(e) {
+ }
+ }
+ this._restoringTabs = [];
+ },
+
+/* Commands */
+
+ setTabbarWidth : function TSTWindow_setTabbarWidth(aWidth, aForceExpanded) /* PUBLIC API */
+ {
+ this.browser.treeStyleTab.autoHide.setWidth(aWidth, aForceExpanded);
+ },
+
+ setContentWidth : function TSTWindow_setContentWidth(aWidth, aKeepWindowSize) /* PUBLIC API */
+ {
+ var w = this.window;
+ var treeStyleTab = this.browser.treeStyleTab;
+ var strip = treeStyleTab.tabStrip;
+ var tabbarWidth = treeStyleTab.splitterWidth + (treeStyleTab.isVertical ? strip.boxObject.width : 0 );
+ var contentWidth = this.browser.boxObject.width - tabbarWidth;
+ if (aKeepWindowSize ||
+ w.fullScreen ||
+ w.windowState != Ci.nsIDOMChromeWindow.STATE_NORMAL) {
+ this.setTabbarWidth(Math.max(10, this.browser.boxObject.width - aWidth));
+ }
+ else if (tabbarWidth + aWidth <= w.screen.availWidth) {
+ w.resizeBy(aWidth - contentWidth, 0);
+ }
+ else {
+ w.resizeBy(w.screen.availWidth - w.outerWidth, 0);
+ this.setTabbarWidth(this.browser.boxObject.width - aWidth);
+ }
+ },
+
+ toggleAutoHide : function TSTWindow_toggleAutoHide(aTabBrowser) /* PUBLIC API, for backward compatibility */
+ {
+ this.autoHideWindow.toggleMode(aTabBrowser || this.browser);
+ },
+
+ toggleFixed : function TSTWindow_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 || null, b);
+ this.setPrefForActiveWindow(function() {
+ b.treeStyleTab.fixed = newFixed;
+ utils.setTreePref('tabbar.fixed.'+orient, newFixed);
+ });
+
+ b.treeStyleTab.updateTabbarState();
+ },
+
+ removeTabSubtree : function TSTWindow_removeTabSubtree(aTabOrTabs, aOnlyChildren)
+ {
+ var tabs = this.gatherSubtreeMemberTabs(aTabOrTabs, aOnlyChildren);
+ if (!this.warnAboutClosingTabs(tabs.length))
+ return;
+
+ if (aOnlyChildren)
+ tabs = this.gatherSubtreeMemberTabs(aTabOrTabs);
+
+ var allSubtrees = this.splitTabsToSubtrees(tabs);
+ for (let i = 0, maxi = allSubtrees.length; i < maxi; i++)
+ {
+ let subtreeTabs = allSubtrees[i];
+ if (!this.fireTabSubtreeClosingEvent(subtreeTabs[0], subtreeTabs))
+ continue;
+ let b = this.getTabBrowserFromChild(subtreeTabs[0]);
+ if (aOnlyChildren)
+ subtreeTabs = subtreeTabs.slice(1);
+ if (!subtreeTabs.length)
+ continue;
+ this.stopRendering();
+ this.markAsClosedSet(subtreeTabs);
+ for (let i = subtreeTabs.length-1; i > -1; i--)
+ {
+ b.removeTab(subtreeTabs[i], { animate : true });
+ }
+ this.startRendering();
+ this.fireTabSubtreeClosedEvent(b, subtreeTabs[0], subtreeTabs)
+ }
+ },
+ removeTabSubTree : function(...aArgs) {
+ return this.removeTabSubtree.apply(this, aArgs);
+ }, // obsolete, for backward compatibility
+
+ fireTabSubtreeClosingEvent : function TSTWindow_fireTabSubtreeClosingEvent(aParentTab, aClosedTabs)
+ {
+ var b = this.getTabBrowserFromChild(aParentTab);
+ var data = {
+ parent : aParentTab,
+ tabs : aClosedTabs
+ };
+ var canClose = (
+ /* PUBLIC API */
+ this.fireCustomEvent(this.kEVENT_TYPE_SUBTREE_CLOSING, b, true, true, data) &&
+ // for backward compatibility
+ this.fireCustomEvent(this.kEVENT_TYPE_SUBTREE_CLOSING.replace(/^nsDOM/, ''), b, true, true, data)
+ );
+ return canClose;
+ },
+
+ fireTabSubtreeClosedEvent : function TSTWindow_fireTabSubtreeClosedEvent(aTabBrowser, aParentTab, aClosedTabs)
+ {
+ aClosedTabs = aClosedTabs.filter(function(aTab) { return !aTab.parentNode; });
+ var data = {
+ parent : aParentTab,
+ tabs : aClosedTabs
+ };
+
+ /* PUBLIC API */
+ this.fireCustomEvent(this.kEVENT_TYPE_SUBTREE_CLOSED, aTabBrowser, true, false, data);
+ // for backward compatibility
+ this.fireCustomEvent(this.kEVENT_TYPE_SUBTREE_CLOSED.replace(/^nsDOM/, ''), aTabBrowser, true, false, data);
+ },
+
+ warnAboutClosingTabSubtreeOf : function TSTWindow_warnAboutClosingTabSubtreeOf(aTab)
+ {
+ if (!this.shouldCloseTabSubtreeOf(aTab))
+ return true;
+
+ var tabs = [aTab].concat(this.getDescendantTabs(aTab));
+ return this.warnAboutClosingTabs(tabs.length);
+ },
+ warnAboutClosingTabSubTreeOf : function(...aArgs) {
+ return this.warnAboutClosingTabSubtreeOf.apply(this, aArgs);
+ }, // obsolete, for backward compatibility
+
+ warnAboutClosingTabs : function TSTWindow_warnAboutClosingTabs(aTabsCount)
+ {
+ if (
+ aTabsCount <= 1 ||
+ !prefs.getPref('browser.tabs.warnOnClose')
+ )
+ return true;
+ var checked = { value:true };
+ var w = this.window;
+ w.focus();
+ var message = w.PluralForm.get(aTabsCount, utils.tabbrowserBundle.getString('tabs.closeWarningMultiple')).replace('#1', aTabsCount);
+ var shouldClose = Services.prompt.confirmEx(w,
+ utils.tabbrowserBundle.getString('tabs.closeWarningTitle'),
+ message,
+ (Services.prompt.BUTTON_TITLE_IS_STRING * Services.prompt.BUTTON_POS_0) +
+ (Services.prompt.BUTTON_TITLE_CANCEL * Services.prompt.BUTTON_POS_1),
+ utils.tabbrowserBundle.getString('tabs.closeButtonMultiple'),
+ null, null,
+ utils.tabbrowserBundle.getString('tabs.closeWarningPromptMe'),
+ checked
+ ) == 0;
+ if (shouldClose && !checked.value)
+ prefs.setPref('browser.tabs.warnOnClose', false);
+ return shouldClose;
+ },
+
+ reloadTabSubtree : function TSTWindow_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(...aArgs) {
+ return this.reloadTabSubtree.apply(this, aArgs);
+ }, // obsolete, for backward compatibility
+
+ createSubtree : function TSTWindow_createSubtree(aTabs)
+ {
+ var rootTabs = this.getRootTabs(aTabs);
+
+ var parent = this.getParentTab(aTabs[0]);
+ var next = aTabs[0];
+ while (
+ (next = this.getNextSiblingTab(next)) &&
+ aTabs.indexOf(next) > -1
+ );
+
+ var b = this.getTabBrowserFromChild(aTabs[0]);
+
+ rootTabs.forEach(function(aRootTab) {
+ var parentTab = this.getParentTab(aRootTab);
+ var descendantTabs = this.getDescendantTabs(aRootTab);
+ descendantTabs.reverse().forEach(function(aDescendantTab) {
+ var inTargets = aTabs.indexOf(aDescendantTab) > -1;
+ var parentInTargets = aTabs.indexOf(this.getParentTab(aDescendantTab)) > -1;
+ if (inTargets || (inTargets == parentInTargets))
+ return;
+ if (parentTab)
+ b.treeStyleTab.attachTabTo(aDescendantTab, parentTab, {
+ dontExpand : true,
+ dontMove : true,
+ insertBefore : this.getNextSiblingTab(aRootTab)
+ });
+ else
+ b.treeStyleTab.detachTab(aDescendantTab);
+ }, this);
+ }, this);
+
+ aTabs = rootTabs;
+
+ var shouldCreateGroup = aTabs.length > 1 && utils.getTreePref('createSubtree.underParent');
+ var root = shouldCreateGroup ?
+ b.addTab(this.getGroupTabURI({
+ temporary: utils.getTreePref('createSubtree.underParent.temporaryGroup')
+ })) :
+ aTabs.shift() ;
+ var self = this;
+ this.Deferred.next(function(self) {
+ if (shouldCreateGroup) {
+ for (let i = 0, maxi = aTabs.length; i < maxi; i++)
+ {
+ let tab = aTabs[i];
+ b.treeStyleTab.attachTabTo(tab, root);
+ b.treeStyleTab.collapseExpandTab(tab, false);
+ }
+ }
+ if (parent) {
+ b.treeStyleTab.attachTabTo(root, parent, {
+ insertBefore : next
+ });
+ }
+ else if (next) {
+ b.treeStyleTab.moveTabSubtreeTo(root, next._tPos);
+ }
+ }).error(this.defaultDeferredErrorHandler);
+ },
+ createSubTree : function(...aArgs) {
+ return this.createSubtree.apply(this, aArgs);
+ }, // obsolete, for backward compatibility
+
+ canCreateSubtree : function TSTWindow_canCreateSubtree(aTabs)
+ {
+ var rootTabs = this.getRootTabs(aTabs);
+ if (rootTabs.length == 1) {
+ let descendants = this.getDescendantTabs(rootTabs[0]);
+ // are they already grouped?
+ // if it is a partial selection, I can create new group.
+ return (descendants.some(function(aDescendantTab) {
+ return aTabs.indexOf(aDescendantTab) < 0;
+ }, this));
+ }
+ return true;
+ },
+ canCreateSubTree : function(...aArgs) {
+ return this.canCreateSubtree.apply(this, aArgs);
+ }, // obsolete, for backward compatibility
+
+ getRootTabs : function TSTWindow_getRootTabs(aTabs)
+ {
+ var roots = [];
+ if (!aTabs || !aTabs.length)
+ return roots;
+ aTabs = this.cleanUpTabsArray(aTabs);
+ for (let i = 0, maxi = aTabs.length; i < maxi; i++)
+ {
+ let tab = aTabs[i];
+ let parent = this.getParentTab(tab);
+ if (parent && aTabs.indexOf(parent) > -1)
+ continue;
+ roots.push(tab);
+ }
+ return roots;
+ },
+
+ collapseExpandAllSubtree : function TSTWindow_collapseExpandAllSubtree(aCollapse)
+ {
+ Services.obs.notifyObservers(
+ this.window,
+ this.kTOPIC_COLLAPSE_EXPAND_ALL,
+ (aCollapse ? 'collapse' : 'open' )
+ );
+ },
+
+ promoteTab : function TSTWindow_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.detachTab(aTab);
+ let index = nextSibling ? nextSibling._tPos : b.mTabContainer.childNodes.length ;
+ if (index > aTab._tPos)
+ index--;
+ b.moveTabTo(aTab, index);
+ }
+ },
+
+ promoteCurrentTab : function TSTWindow_promoteCurrentTab() /* PUBLIC API */
+ {
+ this.promoteTab(this.browser.selectedTab);
+ },
+
+ demoteTab : function TSTWindow_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 TSTWindow_demoteCurrentTab() /* PUBLIC API */
+ {
+ this.demoteTab(this.browser.selectedTab);
+ },
+
+ expandTreeAfterKeyReleased : function TSTWindow_expandTreeAfterKeyReleased(aTab)
+ {
+ if (utils.getTreePref('autoCollapseExpandSubtreeOnSelect.whileFocusMovingByShortcut'))
+ return;
+ this._tabShouldBeExpandedAfterKeyReleased = aTab || null;
+ },
+ _tabShouldBeExpandedAfterKeyReleased : null,
+
+ removeAllTabsBut : function TSTWindow_removeAllTabsBut(aTab)
+ {
+ var keepTabs = [aTab].concat(this.getDescendantTabs(aTab));
+ var b = this.getTabBrowserFromChild(aTab);
+ var closeTabs = this.getTabs(b).filter(function(aTab) {
+ return keepTabs.indexOf(aTab) < 0 && !aTab.hasAttribute('pinned');
+ });
+
+ if (!this.warnAboutClosingTabs(closeTabs.length))
+ return;
+
+ this.stopRendering();
+ this.markAsClosedSet(closeTabs);
+ var tabs = closeTabs.reverse();
+ for (let i = 0, maxi = tabs.length; i < maxi; i++)
+ {
+ b.removeTab(tabs[i]);
+ }
+ this.startRendering();
+ },
+
+ // For backward compatibility. You should use DOM event to block TST's focus handling.
+ registerTabFocusAllowance : function TSTWindow_registerTabFocusAllowance(aProcess) /* PUBLIC API */
+ {
+ var listener = {
+ process : aProcess,
+ handleEvent : function(aEvent) {
+ var tab = aEvent.originalTarget;
+ var b = tab.__treestyletab__linkedTabBrowser;
+ if (!this.process.call(b.treeStyleTab, b))
+ aEvent.preventDefault();
+ }
+ };
+ this.window.addEventListener(this.kEVENT_TYPE_FOCUS_NEXT_TAB, listener, false);
+ this._tabFocusAllowance.push(listener);
+ },
+ _tabFocusAllowance : [],
+
+ tearOffSubtreeFromRemote : function TSTWindow_tearOffSubtreeFromRemote()
+ {
+ var w = this.window;
+ var remoteTab = w.arguments[0];
+ var remoteWindow = remoteTab.ownerDocument.defaultView;
+ var remoteService = remoteWindow.TreeStyleTabService;
+ var remoteMultipleTabService = remoteWindow.MultipleTabService;
+ if (remoteService.hasChildTabs(remoteTab) ||
+ (remoteMultipleTabService && remoteMultipleTabService.isSelected(remoteTab))) {
+ let remoteBrowser = remoteService.getTabBrowserFromChild(remoteTab);
+ if (remoteBrowser.treeStyleTab.tabbarDNDObserver.isDraggingAllTabs(remoteTab)) {
+ w.close();
+ }
+ else {
+ let actionInfo = {
+ action : remoteTab.__treestyletab__toBeDuplicated ? this.kACTION_DUPLICATE : this.kACTION_IMPORT
+ };
+
+ let b = this.browser;
+ let blankTab;
+ this.Deferred
+ .next(function() {
+ var blankTab = b.selectedTab;
+ b.treeStyleTab.tabbarDNDObserver.performDrop(actionInfo, remoteTab);
+ return blankTab;
+ })
+ .next(function(aBlankTab) {
+ b.removeTab(aBlankTab);
+ remoteTab = null;
+ remoteBrowser = null;
+ remoteWindow = null
+ remoteService = null;
+ remoteMultipleTabService = null;
+ })
+ .error(this.defaultDeferredErrorHandler);
+ }
+ return true;
+ }
+ return false;
+ },
+ tearOffSubTreeFromRemote : function(...aArgs) {
+ return this.tearOffSubtreeFromRemote.apply(this, aArgs);
+ }, // obsolete, for backward compatibility
+
+ onPrintPreviewEnter : function TSTWindow_onPrintPreviewEnter()
+ {
+ var d = this.document;
+ var event = d.createEvent('Events');
+ event.initEvent(this.kEVENT_TYPE_PRINT_PREVIEW_ENTERED, true, false);
+ d.documentElement.dispatchEvent(event);
+
+ // for backward compatibility
+ event = d.createEvent('Events');
+ event.initEvent(this.kEVENT_TYPE_PRINT_PREVIEW_ENTERED.replace(/^nsDOM/, ''), true, false);
+ d.documentElement.dispatchEvent(event);
+ },
+
+ onPrintPreviewExit : function TSTWindow_onPrintPreviewExit()
+ {
+ var d = this.document;
+ var event = d.createEvent('Events');
+ event.initEvent(this.kEVENT_TYPE_PRINT_PREVIEW_EXITED, true, false);
+ d.documentElement.dispatchEvent(event);
+
+ // for backward compatibility
+ event = d.createEvent('Events');
+ event.initEvent(this.kEVENT_TYPE_PRINT_PREVIEW_EXITED.replace(/^nsDOM/, ''), true, false);
+ d.documentElement.dispatchEvent(event);
+ },
+
+ observe : function TSTWindow_observe(aSubject, aTopic, aData)
+ {
+ switch (aTopic)
+ {
+ case 'nsPref:changed':
+ this.onPrefChange(aData);
+ return;
+ }
+ },
+ get restoringTree() {
+ if (this._restoringTree || !!this.restoringCount)
+ return true;
+
+ var count = 0;
+ this.browser.visibleTabs.some(function(aTab) {
+ if (aTab.linkedBrowser.__treestyletab__toBeRestored)
+ count++;
+ return count > 1;
+ });
+ return count > 1;
+ },
+ set restoringTree(aValue) {
+ return this._restoringTree = !!aValue;
+ },
+ _restoringTree : false,
+
+/* Pref Listener */
+
+ domains : [
+ 'extensions.treestyletab',
+ 'browser.ctrlTab.previews'
+ ],
+
+ onPrefChange : function TSTWindow_onPrefChange(aPrefName)
+ {
+ var value = prefs.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 = utils.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(this.window);
+ break;
+
+ case 'extensions.treestyletab.tabbar.style':
+ case 'extensions.treestyletab.tabbar.position':
+ this.themeManager.set(prefs.getPref('extensions.treestyletab.tabbar.style'), this.position);
+ break;
+
+ case 'browser.ctrlTab.previews':
+ this.autoHideWindow.updateKeyListeners(this.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;
+ }
+ }
+
+});
+