Move codes to override behaviors around bookmarks to a JS code module.

Moreover, it reduces use of eval.
This commit is contained in:
YUKI Hiroshi 2016-01-21 18:23:11 +09:00
parent 978bda448d
commit fdc472441b
9 changed files with 594 additions and 525 deletions

View File

@ -1,221 +1,15 @@
Components.utils.import('resource://gre/modules/XPCOMUtils.jsm'); Components.utils.import('resource://gre/modules/XPCOMUtils.jsm');
XPCOMUtils.defineLazyModuleGetter(this, XPCOMUtils.defineLazyModuleGetter(this,
'TreeStyleTabUtils', 'resource://treestyletab-modules/utils.js'); 'TreeStyleTabUtils', 'resource://treestyletab-modules/utils.js');
XPCOMUtils.defineLazyModuleGetter(this,
'TreeStyleTabBookmarksService', 'resource://treestyletab-modules/bookmark.js');
(function() { (function() {
let { ReferenceCounter } = Components.utils.import('resource://treestyletab-modules/ReferenceCounter.js', {}); let { ReferenceCounter } = Components.utils.import('resource://treestyletab-modules/ReferenceCounter.js', {});
let { inherit } = Components.utils.import('resource://treestyletab-modules/lib/inherit.jsm', {}); let { inherit } = Components.utils.import('resource://treestyletab-modules/lib/inherit.jsm', {});
var TreeStyleTabBookmarksService = inherit(TreeStyleTabService, {
get BookmarksService() {
if (!this._BookmarksService) {
this._BookmarksService = Components
.classes['@mozilla.org/browser/nav-bookmarks-service;1']
.getService(Components.interfaces.nsINavBookmarksService);
}
return this._BookmarksService;
},
_BookmarksService : null,
beginAddBookmarksFromTabs : function TSTBMService_beginAddBookmarksFromTabs(aTabs) /* PUBLIC API */
{
if (this._observing) return;
this._observing = true;
aTabs = this.cleanUpTabsArray(aTabs);
this._addingBookmarks = [];
this._addingBookmarkTreeStructure = aTabs.map(function(aTab) {
var parent = this.getParentTab(aTab);
return aTabs.indexOf(parent);
}, this);
this.BookmarksService.addObserver(this, false);
},
endAddBookmarksFromTabs : function TSTBMService_endAddBookmarksFromTabs() /* PUBLIC API */
{
if (!this._observing) return;
this._observing = false;
this.BookmarksService.removeObserver(this);
this.handleNewBookmarksFromTabs(this._addingBookmarks, this._addingBookmarkTreeStructure);
this._addingBookmarks = [];
this._addingBookmarkTreeStructure = [];
},
handleNewBookmarksFromTabs : function TSTBMService_handleNewBookmarksFromTabs(aBookarmks, aTreeStructure)
{
// this is adding bookmark folder from tabs, so ignroe the first item!
if (
aBookarmks.length == aTreeStructure.length+1 &&
this.BookmarksService.getItemType(aBookarmks[0].id) == this.BookmarksService.TYPE_FOLDER
) {
aBookarmks.shift();
}
else if (aBookarmks.length != aTreeStructure.length) {
return;
}
for (let i = 0, maxi = aBookarmks.length; i < maxi; i++)
{
let item = aBookarmks[i];
item.position = this.BookmarksService.getItemIndex(item.id);
}
aBookarmks.sort(function(aA, aB) {
return aA.position - aB.position;
});
for (let i = 0, maxi = aBookarmks.length; i < maxi; i++)
{
let item = aBookarmks[i];
if (this.BookmarksService.getItemType(item.id) != this.BookmarksService.TYPE_BOOKMARK)
continue;
let uri = this.BookmarksService.getBookmarkURI(item.id);
if (/^about:treestyletab-group\b/.test(uri.spec)) {
let title = this.BookmarksService.getItemTitle(item.id);
let folderId = this.BookmarksService.createFolder(item.parent, title, item.position);
this.BookmarksService.removeItem(item.id);
item.id = folderId;
item.isFolder = true;
}
let index = aTreeStructure[i];
let parent = index > -1 ? aBookarmks[index] : null ;
if (parent && (parent.folder || parent).isFolder) {
let folder = parent.isFolder ? parent : parent.folder ;
this.BookmarksService.moveItem(item.id, folder.id, -1);
item.folder = folder;
}
if (parent && !parent.isFolder) {
PlacesUtils.setAnnotationsForItem(item.id, [{
name : this.kPARENT,
value : parent ? parent.id : -1,
expires : PlacesUtils.annotations.EXPIRE_NEVER
}]);
}
}
},
bookmarkTabSubtree : function TSTBMService_bookmarkTabSubtree(aTabOrTabs)
{
var tabs = aTabOrTabs;
if (!Array.isArray(tabs)) {
tabs = [aTabOrTabs];
}
var folderName = (this.isGroupTab(tabs[0], true) || tabs.length == 1) ?
tabs[0].label :
null ;
var b = this.getTabBrowserFromChild(tabs[0]);
var bookmarkedTabs = [];
for (let i = 0, maxi = tabs.length; i < maxi; i++)
{
let tab = tabs[i];
if (!this.isGroupTab(tab, i == 0)) bookmarkedTabs.push(tab);
bookmarkedTabs = bookmarkedTabs.concat(b.treeStyleTab.getDescendantTabs(tab));
}
this.beginAddBookmarksFromTabs(bookmarkedTabs);
try {
window['piro.sakura.ne.jp'].bookmarkMultipleTabs.addBookmarkFor(bookmarkedTabs, folderName);
}
catch(e) {
}
this.endAddBookmarksFromTabs();
},
bookmarkTabSubTree : function() { return this.bookmarkTabSubtree.apply(this, arguments); }, // obsolete, for backward compatibility
getParentItem : function TSTBMService_getParentItem(aId)
{
if (aId < 0) return -1;
var annotations = PlacesUtils.getAnnotationsForItem(aId);
for (let i in annotations)
{
if (annotations[i].name != this.kPARENT) continue;
return parseInt(annotations[i].value);
}
return -1;
},
getTreeStructureFromItems : function TSTBMService_getTreeStructureFromItems(aIDs, aDefaultParentID)
{
/* this returns a result same to getTreeStructureFromTabs().
[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)
*/
if (aDefaultParentID === void(0))
aDefaultParentID = -1;
/* Get array of parents. The index becomes to -1,
if there is NO PARENT or the parent is THE TAB ITSELF. */
var treeStructure = aIDs.map(function(aId, aIndex) {
let id = this.getParentItem(aId);
let index = aIDs.indexOf(id);
return index >= aIndex ? aDefaultParentID : index ;
}, this);
/* Correct patterns like:
[TabA]
[TabB] - this has no parent
[TabC] - TabA's child
to:
[TabA]
[TabB]
[TabC]
*/
treeStructure = treeStructure.reverse();
treeStructure = treeStructure.map(function(aPosition, aIndex) {
if (aIndex > 0 &&
aIndex < treeStructure.length-1 &&
aPosition < 0) {
aPosition = treeStructure[aIndex-1];
}
return aPosition;
});
treeStructure = treeStructure.reverse();
return this.cleanUpTreeStructureArray(treeStructure, aDefaultParentID);
},
// based on PlacesUtils.getURLsForContainerNode()
getItemIdsForContainerNode : function TSTBMService_getItemIdsForContainerNode(aNode)
{
var ids = [];
if (!aNode || !PlacesUtils.nodeIsContainer(aNode)) return ids;
var root = aNode;
if ('getContainerNodeWithOptions' in PlacesUtils) {
root = PlacesUtils.getContainerNodeWithOptions(root, false, true);
}
var oldViewer = root.parentResult.viewer;
var wasOpen = root.containerOpen;
if (!wasOpen) {
if (oldViewer)
root.parentResult.viewer = null;
root.containerOpen = true;
}
for (let i = 0, maxi = root.childCount; i < maxi; ++i)
{
let child = root.getChild(i);
if (PlacesUtils.nodeIsURI(child)) ids.push(child.itemId || -1);
}
if (!wasOpen) {
root.containerOpen = false;
if (oldViewer)
root.parentResult.viewer = oldViewer;
}
return ids;
},
var TreeStyleTabBookmarksUIService = inherit(TreeStyleTabService, {
preInit : function TSTBMService_preInit() preInit : function TSTBMService_preInit()
{ {
window.addEventListener('load', this, false); window.addEventListener('load', this, false);
@ -231,250 +25,35 @@ var TreeStyleTabBookmarksService = inherit(TreeStyleTabService, {
window.addEventListener('unload', this, false); window.addEventListener('unload', this, false);
ReferenceCounter.add('window,unload,TSTBMService,false'); ReferenceCounter.add('window,unload,TSTBMService,false');
if (!('PlacesUIUtils' in window)) return;
if (!PlacesUIUtils.__treestyletab__done) {
var ns = Components.utils.import('resource:///modules/PlacesUIUtils.jsm', {});
var sv = this;
with (ns) {
{
let method = (TreeStyleTabUtils.getTreePref('compatibility.TabUtilities') && PlacesUIUtils.TU__openTabset) ?
'TU__openTabset' :
'_openTabset';
if (PlacesUIUtils.__openbookmarkintab__openTabset)
method = '__openbookmarkintab__openTabset';
TreeStyleTabUtils.doPatching(PlacesUIUtils[method], 'PlacesUIUtils.'+method, function(aName, aSource) {
var patched = eval(aName+' = '+aSource.replace(
/(function[^\(]*\([^\)]+)(\))/,
'$1, aFolderTitle$2'
).replace(
'{',
'{ var TSTTreeStructure = null, TSTPreviousTabs, TSTTreeStructureApplied = true, TSTOpenGroupBookmarkBehavior;'
).replace(
'var urls = [];',
'$& var ids = [];'
).replace(
'urls.push(item.uri);',
'if (item.uri) { $& ids.push(item.id); }'
).replace(
'this.markPageAsTyped(item.uri);',
'if (item.uri) { $& }'
).replace(
/(browserWindow\.(?:getBrowser\(\)|gBrowser)\.loadTabs\([^;]+\);)/,
'var TSTResult = browserWindow.TreeStyleTabBookmarksService.handleTabsOpenProcess(where, aEvent, browserWindow, ids, urls, aFolderTitle);\n' +
'TSTTreeStructure = TSTResult.treeStructure;\n' +
'TSTPreviousTabs = TSTResult.previousTabs;\n' +
'TSTTreeStructureApplied = TSTResult.treeStructureApplied;\n' +
'TSTOpenGroupBookmarkBehavior = TSTResult.behavior;\n' +
'$1'
).replace(
/(\}\)?)$/,
' if (TSTTreeStructure && TSTPreviousTabs) {\n' +
' let tabs = browserWindow.TreeStyleTabService.getNewTabsFromPreviousTabsInfo(browserWindow.gBrowser, TSTPreviousTabs);\n' +
' if (!TSTTreeStructureApplied)\n' +
' browserWindow.TreeStyleTabService.applyTreeStructureToTabs(tabs, TSTTreeStructure, TSTOpenGroupBookmarkBehavior & browserWindow.TreeStyleTabBookmarksService.kGROUP_BOOKMARK_EXPAND_ALL_TREE);\n' +
' if (!loadInBackground) {\n' +
' browserWindow.setTimeout(function() {\n' +
' browserWindow.gBrowser.treeStyleTab.scrollToTabs(tabs);\n' +
' }, browserWindow.gBrowser.treeStyleTab.collapseDuration); // start scroll after expanding animation is finished\n' +
' }\n' +
' }\n' +
'$1'
));
if (TreeStyleTabUtils.getTreePref('compatibility.TabUtilities') && method.indexOf('TU_') > -1)
window[method] = patched;
return patched;
}, 'TreeStyleTab');
}
{
let method = (TreeStyleTabUtils.getTreePref('compatibility.TabUtilities') && PlacesUIUtils.TU_openContainerNodeInTabs) ?
'TU_openContainerNodeInTabs' :
'openContainerNodeInTabs';
TreeStyleTabUtils.doPatching(PlacesUIUtils[method], 'PlacesUIUtils.'+method, function(aName, aSource) {
var patched = eval(aName+' = '+aSource.replace(
/(this\._openTabset\([^\)]+)(\))/,
'{\n' +
' let w = "_getTopBrowserWin" in this ?\n' +
' this._getTopBrowserWin() :\n' +
' "_getCurrentActiveWin" in this ?\n' +
' this._getCurrentActiveWin() :\n' +
' window;\n' +
' let nodes = w.TreeStyleTabBookmarksService.getItemIdsForContainerNode(aNode);\n' +
' for (let i in nodes) {\n' +
' urlsToOpen[i].id = nodes[i];\n' +
' }\n' +
'}\n' +
'$1, aNode.title$2'
));
if (TreeStyleTabUtils.getTreePref('compatibility.TabUtilities') && method.indexOf('TU_') > -1)
window[method] = patched;
return patched;
}, 'TreeStyleTab');
}
{
let method = (TreeStyleTabUtils.getTreePref('compatibility.TabUtilities') && PlacesUIUtils.TU_openURINodesInTabs) ?
'TU_openURINodesInTabs' :
'openURINodesInTabs';
TreeStyleTabUtils.doPatching(PlacesUIUtils[method], 'PlacesUIUtils.'+method, function(aName, aSource) {
var patched = eval(aName+' = '+aSource.replace(
'{',
'{\n' +
' var TSTBS, TSTUtils;\n' +
' {\n'+
' let w = "_getTopBrowserWin" in this ?\n' +
' this._getTopBrowserWin() :\n' +
' "_getCurrentActiveWin" in this ?\n' +
' this._getCurrentActiveWin() :\n' +
' window;\n' +
' TSTBS = w.TreeStyleTabBookmarksService;\n' +
' TSTUtils = w.TreeStyleTabUtils;\n' +
' PlacesUtils = w.PlacesUtils;\n' +
' }'
).replace(
'uri: aNodes[i].uri,',
'id: aNodes[i].itemId, $&'
).replace(
/(this\._openTabset\([^\)]+)(\))/,
'$1,\n' +
' TSTUtils.treeBundle\n' +
' .getFormattedString(\n' +
' PlacesUtils.nodeIsBookmark(aNodes[0]) ?\n' +
' "openSelectedPlaces.bookmarks" :\n' +
' "openSelectedPlaces.history",\n' +
' [aNodes[0].title, aNodes.length]\n' +
' )\n' +
'$2'
));
if (TreeStyleTabUtils.getTreePref('compatibility.TabUtilities') && method.indexOf('TU_') > -1)
window[method] = patched;
return patched;
}, 'TreeStyleTab');
}
PlacesUIUtils.__treestyletab__done = true;
} // end of with
}
if ('PlacesCommandHook' in window && 'bookmarkCurrentPages' in PlacesCommandHook) { if ('PlacesCommandHook' in window && 'bookmarkCurrentPages' in PlacesCommandHook) {
// Bookmark All Tabs // Bookmark All Tabs
TreeStyleTabUtils.doPatching(PlacesCommandHook.bookmarkCurrentPages, 'PlacesCommandHook.bookmarkCurrentPages', function(aName, aSource) { PlacesCommandHook.__treestyletab__bookmarkCurrentPages = PlacesCommandHook.bookmarkCurrentPages;
return eval(aName+' = '+aSource.replace( PlacesCommandHook.bookmarkCurrentPages = function(...aArgs) {
'{', TreeStyleTabBookmarksService.beginAddBookmarksFromTabs((function() {
'{\n' + var tabs = [];
' TreeStyleTabBookmarksService.beginAddBookmarksFromTabs((function() {\n' + var seen = {};
' var tabs = [];\n' + var allTabs = gBrowser.mTabContainer.childNodes;
' var seen = {};\n' + for (let i = 0, maxi = allTabs.length; i < maxi; i++)
' var allTabs = getBrowser().mTabContainer.childNodes;\n' + {
' for (let i = 0, maxi = allTabs.length; i < maxi; i++)\n' + let tab = allTabs[i];
' {\n' + let uri = tab.linkedBrowser.currentURI.spec;
' let tab = allTabs[i];\n' + if (uri in seen)
' let uri = tab.linkedBrowser.currentURI.spec;\n' + continue;
' if (uri in seen) continue;\n' + seen[uri] = true;
' seen[uri] = true;\n' + tabs.push(tab);
' tabs.push(tab);\n' + }
' }\n' + return tabs;
' return tabs;\n' + })());
' })());\n' + try {
' try {' return this.__treestyletab__bookmarkCurrentPages.apply(this, aArgs);
).replace( }
/(\}\)?)$/, finally {
' }\n' + TreeStyleTabBookmarksService.endAddBookmarksFromTabs();
' catch(e) {\n' + }
' }\n' +
' TreeStyleTabBookmarksService.endAddBookmarksFromTabs();\n' +
'$1'
));
}, 'TreeStyleTab');
}
},
handleTabsOpenProcess : function TSTBMService_handleTabsOpenProcess(aWhere, aEvent, aBrowserWindow, aIDs, aURLs, aFolderTitle)
{
var result = {
behavior : undefined,
treeStructure : undefined,
previousTabs : undefined,
treeStructureApplied : false
}; };
if (
aEvent.type != 'drop' &&
aWhere.indexOf('tab') != 0 &&
aEvent.target.id != 'placesContext_openContainer:tabs' &&
aEvent.target.id != 'placesContext_openLinks:tabs' &&
aEvent.target != aEvent.target.parentNode._endOptOpenAllInTabs &&
aEvent.target.getAttribute('openInTabs') != 'true'
)
return result;
var sv = aBrowserWindow.TreeStyleTabBookmarksService;
result.behavior = sv.openGroupBookmarkBehavior();
if (result.behavior & sv.kGROUP_BOOKMARK_SUBTREE) {
let treeStructure = result.behavior & sv.kGROUP_BOOKMARK_DONT_RESTORE_TREE_STRUCTURE ?
null :
sv.getTreeStructureFromItems(aIDs) ;
if (treeStructure) {
let parentTabs = treeStructure.filter(function(aParent) {
return aParent < 0;
});
let haveMultipleTrees = parentTabs.length != treeStructure.length;
if (result.behavior & sv.kGROUP_BOOKMARK_USE_DUMMY) {
let parentCount = 0;
let childCount = 0;
for (let i in treeStructure) {
if (treeStructure[i] == -1)
parentCount++;
else
childCount++;
}
if (
parentCount > 1 &&
(
result.behavior & sv.kGROUP_BOOKMARK_USE_DUMMY_FORCE ||
// when there is any orphan, then all of parents and orphans should be grouped under a dummy tab.
childCount < parentCount
)
) {
aIDs.unshift(-1);
treeStructure = sv.getTreeStructureFromItems(aIDs, 0);
aURLs.unshift(sv.getGroupTabURI({
title: aFolderTitle,
temporary: TreeStyleTabUtils.getTreePref('openGroupBookmark.temporaryGroup')
}));
}
}
else if (!haveMultipleTrees) {
// make the first item parent.
treeStructure = treeStructure.map(function(aParent, aIndex) {
if (aIndex == 0)
return aParent;
if (aParent < 0)
return 0;
return aParent;
});
}
}
result.treeStructure = treeStructure;
result.previousTabs = aBrowserWindow.TreeStyleTabService.getTabsInfo(aBrowserWindow.gBrowser);
if (TreeStyleTabUtils.getTreePref('compatibility.TMP') &&
'TMP_Places' in aBrowserWindow &&
'openGroup' in aBrowserWindow.TMP_Places) {
result.treeStructureApplied = false;
}
else {
sv.readyToOpenNewTabGroup(null, treeStructure, result.behavior & sv.kGROUP_BOOKMARK_EXPAND_ALL_TREE);
result.treeStructureApplied = true;
}
} }
return result;
}, },
destroy : function TSTBMService_destroy() destroy : function TSTBMService_destroy()
{ {
window.removeEventListener('unload', this, false); window.removeEventListener('unload', this, false);
@ -483,22 +62,6 @@ var TreeStyleTabBookmarksService = inherit(TreeStyleTabService, {
ReferenceCounter.remove('window,EVENT_TYPE_TABS_DROP,TSTBMService,false'); ReferenceCounter.remove('window,EVENT_TYPE_TABS_DROP,TSTBMService,false');
}, },
// observer for nsINavBookmarksService
onItemAdded : function TSTBMService_onItemAdded(aID, aFolderID, aPosition)
{
this._addingBookmarks.push({
id : aID,
parent : aFolderID
});
},
onItemRemoved : function TSTBMService_onItemRemoved(aID, aFolderID, aPosition) {},
onItemMoved : function TSTBMService_onItemMoved(aID, aFolderID, aPosition) {},
onItemChanged : function TSTBMService_onItemChanged(aID, aChange, aIsAnnotation, aNewValue) {},
onItemVisited : function TSTBMService_onItemVisited(aID, aHistoryID, aDate) {},
onBeginUpdateBatch : function TSTBMService_onBeginUpdateBatch() {},
onEndUpdateBatch : function TSTBMService_onEndUpdateBatch() {},
_onTabsDrop : function TSTBMService_onTabsDrop(aEvent) _onTabsDrop : function TSTBMService_onTabsDrop(aEvent)
{ {
var tabs = aEvent.detail.tabs; var tabs = aEvent.detail.tabs;
@ -533,7 +96,7 @@ var TreeStyleTabBookmarksService = inherit(TreeStyleTabService, {
}); });
TreeStyleTabBookmarksService.preInit(); TreeStyleTabBookmarksUIService.preInit();
window.TreeStyleTabBookmarksService = TreeStyleTabBookmarksService; window.TreeStyleTabBookmarksUIService = TreeStyleTabBookmarksUIService;
})(); })();

View File

@ -327,13 +327,22 @@ var TreeStyleTabBookmarksServiceEditable = inherit(TreeStyleTabBookmarksService,
}, },
_getSiblingItemsIterator : function TSTBMEditable_getSiblingItemsIterator(aId) _getSiblingItemsIterator : function TSTBMEditable_getSiblingItemsIterator(aId)
{ {
return this._getItemsInFolderIterator(PlacesUtils.bookmarks.getFolderIdForItem(aId)); try {
var folderId = PlacesUtils.bookmarks.getFolderIdForItem(aId);
return this._getItemsInFolderIterator(folderId);
}
catch(e) {
dump('TSTBMEditable_getSiblingItemsIterator('+aId+') failed.\n');
dump(e+'\n');
dump(new Error().stack+'\n');
}
}, },
saveParentFor : function TSTBMEditable_saveParentFor(aId, aJustNow) saveParentFor : function TSTBMEditable_saveParentFor(aId, aJustNow)
{ {
var newParentId = parseInt(this.menulist.value || -1); var newParentId = parseInt(this.menulist.value || -1);
if (this.canceled || newParentId == this.getParentItem(aId)) return; if (this.canceled || newParentId == this.getParentItem(aId))
return;
var itemsIterator = this._getSiblingItemsIterator(aId); var itemsIterator = this._getSiblingItemsIterator(aId);
var items = []; var items = [];

View File

@ -726,6 +726,7 @@ pref("extensions.treestyletab.prefsVersion", 0);
pref("extensions.treestyletab.debug.all", false); pref("extensions.treestyletab.debug.all", false);
pref("extensions.treestyletab.debug.autoHide", false); pref("extensions.treestyletab.debug.autoHide", false);
pref("extensions.treestyletab.debug.base", false); pref("extensions.treestyletab.debug.base", false);
pref("extensions.treestyletab.debug.bookmark", false);
pref("extensions.treestyletab.debug.browser", false); pref("extensions.treestyletab.debug.browser", false);
pref("extensions.treestyletab.debug.browserUIShowHideObserver", false); pref("extensions.treestyletab.debug.browserUIShowHideObserver", false);
pref("extensions.treestyletab.debug.contentBridge", false); pref("extensions.treestyletab.debug.contentBridge", false);

View File

@ -370,10 +370,6 @@ var TreeStyleTabBase = inherit(TreeStyleTabConstants, {
return behavior return behavior
}, },
kDROPLINK_ASK : 0,
kDROPLINK_FIXED : 1 + 2,
kDROPLINK_LOAD : 1,
kDROPLINK_NEWTAB : 2,
openGroupBookmarkBehavior : function TSTBase_openGroupBookmarkBehavior() openGroupBookmarkBehavior : function TSTBase_openGroupBookmarkBehavior()
{ {
@ -409,14 +405,6 @@ var TreeStyleTabBase = inherit(TreeStyleTabConstants, {
} }
return 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() bookmarkDroppedTabsBehavior : function TSTBase_bookmarkDroppedTabsBehavior()
{ {
@ -2282,48 +2270,6 @@ var TreeStyleTabBase = inherit(TreeStyleTabConstants, {
return collapsedStates; 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) applyTreeStructureToTabs : function TSTBase_applyTreeStructureToTabs(aTabs, aTreeStructure, aExpandStates)
{ {
var b = this.getTabBrowserFromChild(aTabs[0]); var b = this.getTabBrowserFromChild(aTabs[0]);
@ -2375,7 +2321,7 @@ var TreeStyleTabBase = inherit(TreeStyleTabConstants, {
getTreeStructureFromTabBrowser : function TSTBase_getTreeStructureFromTabBrowser(aTabBrowser) getTreeStructureFromTabBrowser : function TSTBase_getTreeStructureFromTabBrowser(aTabBrowser)
{ {
return this.getTreeStructureFromTabs(this.getAllTabs(aTabBrowser)); return utils.getTreeStructureFromTabs(this.getAllTabs(aTabBrowser));
}, },
applyTreeStructureToTabBrowser : function TSTBase_applyTreeStructureToTabBrowser(aTabBrowser, aTreeStructure, aExpandAllTree) applyTreeStructureToTabBrowser : function TSTBase_applyTreeStructureToTabBrowser(aTabBrowser, aTreeStructure, aExpandAllTree)

489
modules/bookmark.js Normal file
View File

@ -0,0 +1,489 @@
/* ***** 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) 2016
* the Initial Developer. All Rights Reserved.
*
* Contributor(s): YUKI "Piro" Hiroshi <piro.outsider.reflex@gmail.com>
*
* 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 ******/
var EXPORTED_SYMBOLS = ['TreeStyleTabBookmarksService'];
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
Cu.import('resource:///modules/PlacesUIUtils.jsm');
Cu.import('resource://gre/modules/PlacesUtils.jsm');
Cu.import('resource://treestyletab-modules/lib/inherit.jsm');
Cu.import('resource://treestyletab-modules/constants.js');
XPCOMUtils.defineLazyModuleGetter(this, 'utils', 'resource://treestyletab-modules/utils.js', 'TreeStyleTabUtils');
function mydump(aString) {
if (utils.isDebugging('bookmark'))
dump(aString);
}
var TreeStyleTabBookmarksService = inherit(TreeStyleTabConstants, {
get BookmarksService() {
if (!this._BookmarksService) {
this._BookmarksService = Cc['@mozilla.org/browser/nav-bookmarks-service;1']
.getService(Ci.nsINavBookmarksService);
}
return this._BookmarksService;
},
_BookmarksService : null,
beginAddBookmarksFromTabs : function TSTBMService_beginAddBookmarksFromTabs(aTabs) /* PUBLIC API */
{
if (this._observing ||
!aTabs ||
aTabs.length <= 0)
return;
this._observing = true;
var TST = aTabs[0].ownerDocument.defaultView.TreeStyleTabService;
aTabs = TST.cleanUpTabsArray(aTabs);
this._addingBookmarks = [];
this._addingBookmarkTreeStructure = aTabs.map(function(aTab) {
var parent = TST.getParentTab(aTab);
return aTabs.indexOf(parent);
}, this);
this.BookmarksService.addObserver(this, false);
},
endAddBookmarksFromTabs : function TSTBMService_endAddBookmarksFromTabs() /* PUBLIC API */
{
if (!this._observing)
return;
this._observing = false;
this.BookmarksService.removeObserver(this);
this.handleNewBookmarksFromTabs(this._addingBookmarks, this._addingBookmarkTreeStructure);
this._addingBookmarks = [];
this._addingBookmarkTreeStructure = [];
},
handleNewBookmarksFromTabs : function TSTBMService_handleNewBookmarksFromTabs(aBookarmks, aTreeStructure)
{
// this is adding bookmark folder from tabs, so ignroe the first item!
if (
aBookarmks.length == aTreeStructure.length+1 &&
this.BookmarksService.getItemType(aBookarmks[0].id) == this.BookmarksService.TYPE_FOLDER
) {
aBookarmks.shift();
}
else if (aBookarmks.length != aTreeStructure.length) {
return;
}
for (let i = 0, maxi = aBookarmks.length; i < maxi; i++)
{
let item = aBookarmks[i];
item.position = this.BookmarksService.getItemIndex(item.id);
}
aBookarmks.sort(function(aA, aB) {
return aA.position - aB.position;
});
for (let i = 0, maxi = aBookarmks.length; i < maxi; i++)
{
let item = aBookarmks[i];
if (this.BookmarksService.getItemType(item.id) != this.BookmarksService.TYPE_BOOKMARK)
continue;
let uri = this.BookmarksService.getBookmarkURI(item.id);
if (/^about:treestyletab-group\b/.test(uri.spec)) {
let title = this.BookmarksService.getItemTitle(item.id);
let folderId = this.BookmarksService.createFolder(item.parent, title, item.position);
this.BookmarksService.removeItem(item.id);
item.id = folderId;
item.isFolder = true;
}
let index = aTreeStructure[i];
let parent = index > -1 ? aBookarmks[index] : null ;
if (parent && (parent.folder || parent).isFolder) {
let folder = parent.isFolder ? parent : parent.folder ;
this.BookmarksService.moveItem(item.id, folder.id, -1);
item.folder = folder;
}
if (parent && !parent.isFolder) {
PlacesUtils.setAnnotationsForItem(item.id, [{
name : this.kPARENT,
value : parent ? parent.id : -1,
expires : PlacesUtils.annotations.EXPIRE_NEVER
}]);
}
}
},
bookmarkTabSubtree : function TSTBMService_bookmarkTabSubtree(aTabOrTabs)
{
var tabs = aTabOrTabs;
if (!Array.isArray(tabs)) {
tabs = [aTabOrTabs];
}
if (tabs.length <= 0)
return;
var window = tabs[0].ownerDocument.defaultView;
var TST = window.TreeStyleTabService;
var folderName = (TST.isGroupTab(tabs[0], true) || tabs.length == 1) ?
tabs[0].label :
null ;
var b = TST.getTabBrowserFromChild(tabs[0]);
var bookmarkedTabs = [];
for (let i = 0, maxi = tabs.length; i < maxi; i++)
{
let tab = tabs[i];
if (!TST.isGroupTab(tab, i == 0))
bookmarkedTabs.push(tab);
bookmarkedTabs = bookmarkedTabs.concat(b.treeStyleTab.getDescendantTabs(tab));
}
this.beginAddBookmarksFromTabs(bookmarkedTabs);
try {
window['piro.sakura.ne.jp'].bookmarkMultipleTabs.addBookmarkFor(bookmarkedTabs, folderName);
}
catch(e) {
}
this.endAddBookmarksFromTabs();
},
bookmarkTabSubTree : function() { return this.bookmarkTabSubtree.apply(this, arguments); }, // obsolete, for backward compatibility
getParentItem : function TSTBMService_getParentItem(aId)
{
if (aId < 0) return -1;
var annotations = PlacesUtils.getAnnotationsForItem(aId);
for (let i in annotations)
{
if (annotations[i].name != this.kPARENT) continue;
return parseInt(annotations[i].value);
}
return -1;
},
getTreeStructureFromItems : function TSTBMService_getTreeStructureFromItems(aIDs, aDefaultParentID)
{
/* this returns a result same to utils.getTreeStructureFromTabs().
[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)
*/
if (aDefaultParentID === void(0))
aDefaultParentID = -1;
/* Get array of parents. The index becomes to -1,
if there is NO PARENT or the parent is THE TAB ITSELF. */
var treeStructure = aIDs.map(function(aId, aIndex) {
let id = this.getParentItem(aId);
let index = aIDs.indexOf(id);
return index >= aIndex ? aDefaultParentID : index ;
}, this);
/* Correct patterns like:
[TabA]
[TabB] - this has no parent
[TabC] - TabA's child
to:
[TabA]
[TabB]
[TabC]
*/
treeStructure = treeStructure.reverse();
treeStructure = treeStructure.map(function(aPosition, aIndex) {
if (aIndex > 0 &&
aIndex < treeStructure.length-1 &&
aPosition < 0) {
aPosition = treeStructure[aIndex-1];
}
return aPosition;
});
treeStructure = treeStructure.reverse();
return utils.cleanUpTreeStructureArray(treeStructure, aDefaultParentID);
},
// based on PlacesUtils.getURLsForContainerNode()
getItemIdsForContainerNode : function TSTBMService_getItemIdsForContainerNode(aNode)
{
var ids = [];
if (!aNode || !PlacesUtils.nodeIsContainer(aNode)) return ids;
var root = aNode;
if ('getContainerNodeWithOptions' in PlacesUtils) {
root = PlacesUtils.getContainerNodeWithOptions(root, false, true);
}
var oldViewer = root.parentResult.viewer;
var wasOpen = root.containerOpen;
if (!wasOpen) {
if (oldViewer)
root.parentResult.viewer = null;
root.containerOpen = true;
}
for (let i = 0, maxi = root.childCount; i < maxi; ++i)
{
let child = root.getChild(i);
if (PlacesUtils.nodeIsURI(child)) ids.push(child.itemId || -1);
}
if (!wasOpen) {
root.containerOpen = false;
if (oldViewer)
root.parentResult.viewer = oldViewer;
}
return ids;
},
handleTabsOpenProcess : function TSTBMService_handleTabsOpenProcess(aWhere, aEvent, aBrowserWindow, aIDs, aURLs, aItemsToOpen, aFolderTitle)
{
var result = {
behavior : undefined,
treeStructure : undefined,
previousTabs : undefined,
treeStructureApplied : false
};
if (
aEvent.type != 'drop' &&
aWhere.indexOf('tab') != 0 &&
aEvent.target.id != 'placesContext_openContainer:tabs' &&
aEvent.target.id != 'placesContext_openLinks:tabs' &&
aEvent.target != aEvent.target.parentNode._endOptOpenAllInTabs &&
aEvent.target.getAttribute('openInTabs') != 'true'
)
return result;
var TST = aBrowserWindow.TreeStyleTabService;
result.behavior = TST.openGroupBookmarkBehavior();
if (result.behavior & this.kGROUP_BOOKMARK_SUBTREE) {
mydump('TSTBMService_handleTabsOpenProcess: open as a group\n');
let treeStructure = result.behavior & this.kGROUP_BOOKMARK_DONT_RESTORE_TREE_STRUCTURE ?
null :
this.getTreeStructureFromItems(aIDs) ;
mydump(' treeStructure => '+JSON.stringify(treeStructure)+'\n');
if (treeStructure) {
let parentTabs = treeStructure.filter(function(aParent) {
return aParent < 0;
});
let haveMultipleTrees = parentTabs.length != treeStructure.length;
if (result.behavior & this.kGROUP_BOOKMARK_USE_DUMMY) {
mydump(' trying to use dummy group tab\n');
let parentCount = 0;
let childCount = 0;
for (let i in treeStructure) {
if (treeStructure[i] == -1)
parentCount++;
else
childCount++;
}
mydump(' parentCount: '+parentCount+'\n');
mydump(' childCount: '+childCount+'\n');
if (
parentCount > 1 &&
(
result.behavior & this.kGROUP_BOOKMARK_USE_DUMMY_FORCE ||
// when there is any orphan, then all of parents and orphans should be grouped under a dummy tab.
childCount < parentCount
)
) {
aIDs.unshift(-1);
treeStructure = this.getTreeStructureFromItems(aIDs, 0);
let uri = TST.getGroupTabURI({
title: aFolderTitle,
temporary: utils.getTreePref('openGroupBookmark.temporaryGroup')
});
aURLs.unshift(uri);
aItemsToOpen.unshift({
itemId: -1,
title: aFolderTitle,
uri: uri
})
mydump(' updated treeStructure => '+JSON.stringify(treeStructure)+'\n');
}
}
else if (!haveMultipleTrees) {
// make the first item parent.
treeStructure = treeStructure.map(function(aParent, aIndex) {
if (aIndex == 0)
return aParent;
if (aParent < 0)
return 0;
return aParent;
});
}
}
result.treeStructure = treeStructure;
result.previousTabs = TST.getTabsInfo(aBrowserWindow.gBrowser);
if (utils.getTreePref('compatibility.TMP') &&
'TMP_Places' in aBrowserWindow &&
'openGroup' in aBrowserWindow.TMP_Places) {
result.treeStructureApplied = false;
}
else {
TST.readyToOpenNewTabGroup(null, treeStructure, result.behavior & this.kGROUP_BOOKMARK_EXPAND_ALL_TREE);
result.treeStructureApplied = true;
}
}
return result;
},
// observer for nsINavBookmarksService
onItemAdded : function TSTBMService_onItemAdded(aID, aFolderID, aPosition)
{
this._addingBookmarks.push({
id : aID,
parent : aFolderID
});
},
onItemRemoved : function TSTBMService_onItemRemoved(aID, aFolderID, aPosition) {},
onItemMoved : function TSTBMService_onItemMoved(aID, aFolderID, aPosition) {},
onItemChanged : function TSTBMService_onItemChanged(aID, aChange, aIsAnnotation, aNewValue) {},
onItemVisited : function TSTBMService_onItemVisited(aID, aHistoryID, aDate) {},
onBeginUpdateBatch : function TSTBMService_onBeginUpdateBatch() {},
onEndUpdateBatch : function TSTBMService_onEndUpdateBatch() {}
});
PlacesUIUtils.__treestyletab__openTabset = PlacesUIUtils._openTabset;
PlacesUIUtils._openTabset = function(aItemsToOpen, aEvent, aWindow, ...aArgs) {
mydump('TSTBookmarks_openTabset\n');
var uris = [];
var ids = [];
var nodes = this.__treestyletab__openTabset_rawNodes || [];
aItemsToOpen = aItemsToOpen.filter(function(aItem, aIndex) {
if (aItem.uri) {
uris.push(aItem.uri);
let id = aItem.id;
if (!id && aIndex in nodes)
id = nodes[aIndex].itemId;
ids.push(id);
mydump(' '+aIndex+': '+id+' / '+aItem.uri+'\n');
return true;
}
return false;
});
mydump(' items => '+aItemsToOpen.length+'\n');
var allArgs = [aItemsToOpen, aEvent, aWindow].concat(aArgs);
if (aItemsToOpen.length <= 0)
return this.__treestyletab__openTabset.apply(this, allArgs);
var w = aWindow && aWindow.document.documentElement.getAttribute('windowtype') == 'navigator:browser' ?
aWindow :
this._getTopBrowserWin() ;
var TST = w.TreeStyleTabService;
var BS = TreeStyleTabBookmarksService;
var where = w && w.whereToOpenLink(aEvent, false, true) || 'window';
mydump(' where: '+where+'\n');
if (where === 'window')
return this.__treestyletab__openTabset.apply(this, allArgs);
var result = BS.handleTabsOpenProcess(where, aEvent, w, ids, uris, aItemsToOpen, this.__treestyletab__folderName);
mydump(' result: '+JSON.stringify(result)+'\n');
this.__treestyletab__openTabset.apply(this, allArgs);
var tabs = [];
if (result.treeStructure && result.previousTabs)
tabs = TST.getNewTabsFromPreviousTabsInfo(w.gBrowser, result.previousTabs);
if (!result.treeStructureApplied)
TST.applyTreeStructureToTabs(
tabs,
result.treeStructure,
result.behavior & BS.kGROUP_BOOKMARK_EXPAND_ALL_TREE
);
var loadInBackground = where == 'tabshifted';
if (!loadInBackground) {
// start scroll after expanding animation is finished
w.setTimeout(function() {
w.gBrowser.treeStyleTab.scrollToTabs(tabs);
}, w.gBrowser.treeStyleTab.collapseDuration);
}
};
PlacesUtils.__treestyletab__getURLsForContainerNode = PlacesUtils.getURLsForContainerNode;
PlacesUtils.getURLsForContainerNode = function(aNode, ...aArgs) {
var uris = this.__treestyletab__getURLsForContainerNode.apply(this, [aNode].concat(aArgs));
var nodes = TreeStyleTabBookmarksService.getItemIdsForContainerNode(aNode);
for (let i in nodes) {
uris[i].id = nodes[i];
}
return uris;
};
PlacesUIUtils.__treestyletab__openContainerNodeInTabs = PlacesUIUtils.openContainerNodeInTabs;
PlacesUIUtils.openContainerNodeInTabs = function(aNode, ...aArgs) {
this.__treestyletab__folderName = aNode.title;
try {
return this.__treestyletab__openContainerNodeInTabs.apply(this, [aNode].concat(aArgs));
}
finally {
delete this.__treestyletab__folderName;
}
};
PlacesUIUtils.__treestyletab__openURINodesInTabs = PlacesUIUtils.openURINodesInTabs;
PlacesUIUtils.openURINodesInTabs = function(aNode, ...aArgs) {
try {
this.__treestyletab__openTabset_rawNodes = aNodes;
this.__treestyletab__folderName = utils.treeBundle.getFormattedString(
PlacesUtils.nodeIsBookmark(aNodes[0]) ?
'openSelectedPlaces.bookmarks' :
'openSelectedPlaces.history',
[aNodes[0].title, aNodes.length]
);
return this.__treestyletab__openURINodesInTabs.apply(this, [aNode].concat(aArgs));
}
finally {
delete this.__treestyletab__openTabset_rawNodes;
delete this.__treestyletab__folderName;
}
};

View File

@ -6274,7 +6274,7 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
sourceService.getAllTabs(sourceBrowser).length == aTabs.length sourceService.getAllTabs(sourceBrowser).length == aTabs.length
); );
var newTabs = []; var newTabs = [];
var treeStructure = sourceService.getTreeStructureFromTabs(aTabs); var treeStructure = utils.getTreeStructureFromTabs(aTabs);
// Firefox fails to "move" collapsed tabs. So, expand them first // Firefox fails to "move" collapsed tabs. So, expand them first
// and collapse them after they are moved. // and collapse them after they are moved.
@ -6979,7 +6979,8 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
scrollToTabs : function TSTBrowser_scrollToTabs(aTabs) scrollToTabs : function TSTBrowser_scrollToTabs(aTabs)
{ {
var firstTab = aTabs[0]; var firstTab = aTabs[0];
if (!firstTab.parentNode) // do nothing for closed tab! if (!firstTab ||
!firstTab.parentNode) // do nothing for closed tab!
return; return;
var b = this.mTabBrowser; var b = this.mTabBrowser;

View File

@ -220,6 +220,22 @@ var TreeStyleTabConstants = Object.freeze({
RESTORE_STATE_STRUCTURE_RESTORED : 2, RESTORE_STATE_STRUCTURE_RESTORED : 2,
kDROPLINK_ASK : 0,
kDROPLINK_FIXED : 1 + 2,
kDROPLINK_LOAD : 1,
kDROPLINK_NEWTAB : 2,
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,
CONTENT_SCRIPT : 'chrome://treestyletab/content/content-utils.js', CONTENT_SCRIPT : 'chrome://treestyletab/content/content-utils.js',
CONTENT_SCRIPT_AUTOHIDE : 'chrome://treestyletab/content/content-utils-autohide.js', CONTENT_SCRIPT_AUTOHIDE : 'chrome://treestyletab/content/content-utils-autohide.js',
MESSAGE_TYPE : 'treestyletab', MESSAGE_TYPE : 'treestyletab',

View File

@ -572,7 +572,7 @@ catch(e) {
} }
} }
var treeStructure = sourceService.getTreeStructureFromTabs(draggedTabs); var treeStructure = utils.getTreeStructureFromTabs(draggedTabs);
var newTabs = sv.moveTabsInternal(draggedTabs, { var newTabs = sv.moveTabsInternal(draggedTabs, {
duplicate : aInfo.action & sv.kACTION_DUPLICATE, duplicate : aInfo.action & sv.kACTION_DUPLICATE,

View File

@ -335,6 +335,50 @@ var TreeStyleTabUtils = {
this.isPrefChanging(aKey); this.isPrefChanging(aKey);
}, },
getTreeStructureFromTabs : function TSTUtils_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 TSTUtils_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;
},
/* Pref Listener */ /* Pref Listener */
domains : [ domains : [
'extensions.treestyletab.' 'extensions.treestyletab.'