refactor codes for drag and drop
This commit is contained in:
parent
f661405af0
commit
78dc5ef23c
@ -421,7 +421,7 @@ TreeStyleTabService.overrideExtensionsOnInitAfter = function TSTService_override
|
|||||||
eval('TabDNDObserver.clearDragmark = '+
|
eval('TabDNDObserver.clearDragmark = '+
|
||||||
TabDNDObserver.clearDragmark.toSource().replace(
|
TabDNDObserver.clearDragmark.toSource().replace(
|
||||||
/(\})(\))?$/,
|
/(\})(\))?$/,
|
||||||
'gBrowser.treeStyleTab.clearDropPosition(); $1$2'
|
'gBrowser.treeStyleTab.tabbarDNDObserver.clearDropPosition(); $1$2'
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
if (TabDNDObserver.canDrop) {
|
if (TabDNDObserver.canDrop) {
|
||||||
@ -475,13 +475,13 @@ TreeStyleTabService.overrideExtensionsOnInitAfter = function TSTService_override
|
|||||||
).replace(
|
).replace(
|
||||||
/(var newIndex =)/,
|
/(var newIndex =)/,
|
||||||
<![CDATA[
|
<![CDATA[
|
||||||
if (isTabReorder && TSTTabBrowser.treeStyleTab.performDrop(dropActionInfo, aDragSession.sourceNode))
|
if (isTabReorder && TSTTabBrowser.treeStyleTab.tabbarDNDObserver.performDrop(dropActionInfo, aDragSession.sourceNode))
|
||||||
return;
|
return;
|
||||||
]]>
|
]]>
|
||||||
).replace(
|
).replace(
|
||||||
/(aTab = gBrowser.addTab\(url\));/,
|
/(aTab = gBrowser.addTab\(url\));/,
|
||||||
<![CDATA[
|
<![CDATA[
|
||||||
TSTTabBrowser.treeStyleTab.performDrop(dropActionInfo, $1);
|
TSTTabBrowser.treeStyleTab.tabbarDNDObserver.performDrop(dropActionInfo, $1);
|
||||||
return;
|
return;
|
||||||
]]>
|
]]>
|
||||||
).replace(
|
).replace(
|
||||||
@ -493,7 +493,7 @@ TreeStyleTabService.overrideExtensionsOnInitAfter = function TSTService_override
|
|||||||
dropActionInfo.position != TreeStyleTabService.kDROP_ON ||
|
dropActionInfo.position != TreeStyleTabService.kDROP_ON ||
|
||||||
(TreeStyleTabService.dropLinksOnTabBehavior() & TreeStyleTabService.kDROPLINK_NEWTAB)
|
(TreeStyleTabService.dropLinksOnTabBehavior() & TreeStyleTabService.kDROPLINK_NEWTAB)
|
||||||
) {
|
) {
|
||||||
TSTTabBrowser.treeStyleTab.performDrop(dropActionInfo, TSTTabBrowser.loadOneTab(url, null, null, null, bgLoad, false));
|
TSTTabBrowser.treeStyleTab.tabbarDNDObserver.performDrop(dropActionInfo, TSTTabBrowser.loadOneTab(url, null, null, null, bgLoad, false));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
]]>
|
]]>
|
||||||
|
@ -1581,7 +1581,7 @@ var TreeStyleTabService = {
|
|||||||
if (remoteService.hasChildTabs(remoteTab) ||
|
if (remoteService.hasChildTabs(remoteTab) ||
|
||||||
(remoteMultipleTabService && remoteMultipleTabService.isSelected(remoteTab))) {
|
(remoteMultipleTabService && remoteMultipleTabService.isSelected(remoteTab))) {
|
||||||
var remoteBrowser = remoteService.getTabBrowserFromChild(remoteTab);
|
var remoteBrowser = remoteService.getTabBrowserFromChild(remoteTab);
|
||||||
if (remoteBrowser.treeStyleTab.isDraggingAllTabs(remoteTab)) {
|
if (remoteBrowser.treeStyleTab.tabbarDNDObserver.isDraggingAllTabs(remoteTab)) {
|
||||||
window.close();
|
window.close();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -1590,7 +1590,7 @@ var TreeStyleTabService = {
|
|||||||
};
|
};
|
||||||
window.setTimeout(function() {
|
window.setTimeout(function() {
|
||||||
var blankTab = gBrowser.selectedTab;
|
var blankTab = gBrowser.selectedTab;
|
||||||
gBrowser.treeStyleTab.performDrop(actionInfo, remoteTab);
|
gBrowser.treeStyleTab.tabbarDNDObserver.performDrop(actionInfo, remoteTab);
|
||||||
window.setTimeout(function() {
|
window.setTimeout(function() {
|
||||||
gBrowser.removeTab(blankTab);
|
gBrowser.removeTab(blankTab);
|
||||||
|
|
||||||
|
@ -85,6 +85,16 @@ TreeStyleTabBrowser.prototype = {
|
|||||||
return (this._tabStripPlaceHolder = value);
|
return (this._tabStripPlaceHolder = value);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
get tabbarDNDObserver()
|
||||||
|
{
|
||||||
|
return this._tabbarDNDObserver || (this._tabbarDNDObserver = new TreeStyleTabBrowserTabbarDNDObserver(this));
|
||||||
|
},
|
||||||
|
|
||||||
|
get panelDNDObserver()
|
||||||
|
{
|
||||||
|
return this._panelDNDObserver || (this._panelDNDObserver = new TreeStyleTabBrowserTabpanelDNDObserver(this));
|
||||||
|
},
|
||||||
|
|
||||||
/* utils */
|
/* utils */
|
||||||
|
|
||||||
/* get tab contents */
|
/* get tab contents */
|
||||||
@ -3296,487 +3306,6 @@ TreeStyleTabBrowser.prototype = {
|
|||||||
this.removeTabbrowserAttribute(this.kPRINT_PREVIEW);
|
this.removeTabbrowserAttribute(this.kPRINT_PREVIEW);
|
||||||
},
|
},
|
||||||
|
|
||||||
/* drag and drop */
|
|
||||||
|
|
||||||
get tabbarDNDObserver()
|
|
||||||
{
|
|
||||||
return this._tabbarDNDObserver || (this._tabbarDNDObserver = new TreeStyleTabBrowserTabbarDNDObserver(this));
|
|
||||||
},
|
|
||||||
|
|
||||||
get panelDNDObserver()
|
|
||||||
{
|
|
||||||
return this._panelDNDObserver || (this._panelDNDObserver = new TreeStyleTabBrowserTabpanelDNDObserver(this));
|
|
||||||
},
|
|
||||||
|
|
||||||
getCurrentDragSession : function TSTBrowser_getCurrentDragSession()
|
|
||||||
{
|
|
||||||
return Components
|
|
||||||
.classes['@mozilla.org/widget/dragservice;1']
|
|
||||||
.getService(Components.interfaces.nsIDragService)
|
|
||||||
.getCurrentSession();
|
|
||||||
},
|
|
||||||
|
|
||||||
getDropAction : function TSTBrowser_getDropAction(aEvent, aDragSession)
|
|
||||||
{
|
|
||||||
if (!aDragSession)
|
|
||||||
aDragSession = this.getCurrentDragSession();
|
|
||||||
|
|
||||||
var tab = aDragSession ? this.getTabFromChild(aDragSession.sourceNode) : null ;
|
|
||||||
this.ensureTabInitialized(tab);
|
|
||||||
|
|
||||||
var info = this.getDropActionInternal(aEvent, tab);
|
|
||||||
info.canDrop = true;
|
|
||||||
info.source = tab;
|
|
||||||
if (tab) {
|
|
||||||
var isCopy = this.isCopyAction(aEvent);
|
|
||||||
if (isCopy && 'duplicateTab' in this.mTabBrowser) {
|
|
||||||
info.action |= this.kACTION_DUPLICATE;
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
!isCopy &&
|
|
||||||
this.getTabBrowserFromChild(tab) != this.mTabBrowser &&
|
|
||||||
(
|
|
||||||
('duplicateTab' in this.mTabBrowser) ||
|
|
||||||
('swapBrowsersAndCloseOther' in this.mTabBrowser)
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
info.action |= this.kACTION_IMPORT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (info.action & this.kACTIONS_FOR_DESTINATION) {
|
|
||||||
if (info.action & this.kACTION_MOVE) info.action ^= this.kACTION_MOVE;
|
|
||||||
if (info.action & this.kACTION_STAY) info.action ^= this.kACTION_STAY;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (info.action & this.kACTION_ATTACH) {
|
|
||||||
if (info.parent == tab) {
|
|
||||||
info.canDrop = false;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
var orig = tab;
|
|
||||||
tab = info.target;
|
|
||||||
while (tab = this.getParentTab(tab))
|
|
||||||
{
|
|
||||||
if (tab != orig) continue;
|
|
||||||
info.canDrop = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return info;
|
|
||||||
},
|
|
||||||
|
|
||||||
getDropActionInternal : function TSTBrowser_getDropActionInternal(aEvent, aSourceTab)
|
|
||||||
{
|
|
||||||
var tab = aEvent.target;
|
|
||||||
var b = this.mTabBrowser;
|
|
||||||
var tabs = this.getTabsArray(b);
|
|
||||||
var firstTab = this.getFirstNormalTab(b);
|
|
||||||
var lastTabIndex = tabs.length -1;
|
|
||||||
var isInverted = this.isVertical ? false : window.getComputedStyle(b.parentNode, null).direction == 'rtl';
|
|
||||||
var info = {
|
|
||||||
target : null,
|
|
||||||
position : null,
|
|
||||||
action : null,
|
|
||||||
parent : null,
|
|
||||||
insertBefore : null,
|
|
||||||
event : aEvent
|
|
||||||
};
|
|
||||||
|
|
||||||
var isTabMoveFromOtherWindow = aSourceTab && aSourceTab.ownerDocument != document;
|
|
||||||
var isNewTabAction = !aSourceTab || aSourceTab.ownerDocument != document;
|
|
||||||
|
|
||||||
if (tab.localName != 'tab') {
|
|
||||||
var action = isTabMoveFromOtherWindow ? this.kACTION_STAY : (this.kACTION_MOVE | this.kACTION_PART) ;
|
|
||||||
if (isNewTabAction) action |= this.kACTION_NEWTAB;
|
|
||||||
if (aEvent[this.positionProp] < firstTab.boxObject[this.positionProp]) {
|
|
||||||
info.target = info.parent = info.insertBefore = firstTab;
|
|
||||||
info.position = isInverted ? this.kDROP_AFTER : this.kDROP_BEFORE ;
|
|
||||||
info.action = action;
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
else if (aEvent[this.positionProp] > tabs[lastTabIndex].boxObject[this.positionProp] + tabs[lastTabIndex].boxObject[this.sizeProp]) {
|
|
||||||
info.target = info.parent = tabs[lastTabIndex];
|
|
||||||
info.position = isInverted ? this.kDROP_BEFORE : this.kDROP_AFTER ;
|
|
||||||
info.action = action;
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
let index = b.getNewIndex ?
|
|
||||||
b.getNewIndex(aEvent) :
|
|
||||||
b.tabContainer._getDropIndex(aEvent) ;
|
|
||||||
info.target = tabs[Math.min(index, lastTabIndex)];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.ensureTabInitialized(tab);
|
|
||||||
info.target = tab;
|
|
||||||
}
|
|
||||||
|
|
||||||
var positionProp = this.isVertical && tab.getAttribute('pinned') == 'true' ? this.invertedPositionProp : this.positionProp ;
|
|
||||||
var sizeProp = this.isVertical && tab.getAttribute('pinned') == 'true' ? this.invertedSizeProp : this.sizeProp ;
|
|
||||||
var boxPos = tab.boxObject[positionProp];
|
|
||||||
var boxUnit = Math.round(tab.boxObject[sizeProp] / 3);
|
|
||||||
if (aEvent[positionProp] < boxPos + boxUnit) {
|
|
||||||
info.position = isInverted ? this.kDROP_AFTER : this.kDROP_BEFORE ;
|
|
||||||
}
|
|
||||||
else if (aEvent[positionProp] > boxPos + boxUnit + boxUnit) {
|
|
||||||
info.position = isInverted ? this.kDROP_BEFORE : this.kDROP_AFTER ;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
info.position = this.kDROP_ON;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (info.position)
|
|
||||||
{
|
|
||||||
case this.kDROP_ON:
|
|
||||||
info.action = this.kACTION_STAY | this.kACTION_ATTACH;
|
|
||||||
info.parent = tab;
|
|
||||||
var visible = this.getNextVisibleTab(tab);
|
|
||||||
info.insertBefore = this.getTreePref('insertNewChildAt') == this.kINSERT_FISRT ?
|
|
||||||
(this.getFirstChildTab(tab) || visible) :
|
|
||||||
(this.getNextSiblingTab(tab) || this.getNextTab(this.getLastDescendantTab(tab)) || visible);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case this.kDROP_BEFORE:
|
|
||||||
/*
|
|
||||||
[TARGET ] <EFBFBD>ªpart from parent, and move
|
|
||||||
|
|
||||||
[ ]
|
|
||||||
[TARGET ] <EFBFBD>ªattach to the parent of the target, and move
|
|
||||||
|
|
||||||
[ ]
|
|
||||||
[TARGET ] <EFBFBD>ªattach to the parent of the target, and move
|
|
||||||
|
|
||||||
[ ]
|
|
||||||
[TARGET] <EFBFBD>ªattach to the parent of the target (previous tab), and move
|
|
||||||
*/
|
|
||||||
var prevTab = this.getPreviousVisibleTab(tab);
|
|
||||||
if (!prevTab) {
|
|
||||||
info.action = this.kACTION_MOVE | this.kACTION_PART;
|
|
||||||
info.insertBefore = firstTab;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
var prevLevel = Number(prevTab.getAttribute(this.kNEST));
|
|
||||||
var targetNest = Number(tab.getAttribute(this.kNEST));
|
|
||||||
info.parent = (prevLevel < targetNest) ? prevTab : this.getParentTab(tab) ;
|
|
||||||
info.action = this.kACTION_MOVE | (info.parent ? this.kACTION_ATTACH : this.kACTION_PART );
|
|
||||||
info.insertBefore = tab;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case this.kDROP_AFTER:
|
|
||||||
/*
|
|
||||||
[TARGET ] <EFBFBD>«if the target has a parent, attach to it and and move
|
|
||||||
|
|
||||||
[TARGET] <EFBFBD>«attach to the parent of the target, and move
|
|
||||||
[ ]
|
|
||||||
|
|
||||||
[TARGET ] <EFBFBD>«attach to the parent of the target, and move
|
|
||||||
[ ]
|
|
||||||
|
|
||||||
[TARGET ] <EFBFBD>«attach to the target, and move
|
|
||||||
[ ]
|
|
||||||
*/
|
|
||||||
var nextTab = this.getNextVisibleTab(tab);
|
|
||||||
if (!nextTab) {
|
|
||||||
info.action = this.kACTION_MOVE | this.kACTION_ATTACH;
|
|
||||||
info.parent = this.getParentTab(tab);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
var targetNest = Number(tab.getAttribute(this.kNEST));
|
|
||||||
var nextLevel = Number(nextTab.getAttribute(this.kNEST));
|
|
||||||
info.parent = (targetNest < nextLevel) ? tab : this.getParentTab(tab) ;
|
|
||||||
info.action = this.kACTION_MOVE | (info.parent ? this.kACTION_ATTACH : this.kACTION_PART );
|
|
||||||
info.insertBefore = nextTab;
|
|
||||||
/*
|
|
||||||
[TARGET ] <EFBFBD>«attach dragged tab to the parent of the target as its next sibling
|
|
||||||
[DRAGGED]
|
|
||||||
*/
|
|
||||||
if (aSourceTab == nextTab && this.getDescendantTabs(info.parent).length == 1) {
|
|
||||||
info.action = this.kACTION_MOVE | this.kACTION_ATTACH;
|
|
||||||
info.parent = this.getParentTab(tab);
|
|
||||||
info.insertBefore = this.getNextTab(nextTab);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isNewTabAction) action |= this.kACTION_NEWTAB;
|
|
||||||
|
|
||||||
return info;
|
|
||||||
},
|
|
||||||
|
|
||||||
performDrop : function TSTBrowser_performDrop(aInfo, aDraggedTab)
|
|
||||||
{
|
|
||||||
var tabsInfo = this.getDraggedTabsInfoFromOneTab(aInfo, aDraggedTab);
|
|
||||||
if (!tabsInfo.draggedTab) return false;
|
|
||||||
|
|
||||||
aDraggedTab = tabsInfo.draggedTab;
|
|
||||||
var draggedTabs = tabsInfo.draggedTabs;
|
|
||||||
var draggedRoots = tabsInfo.draggedRoots;
|
|
||||||
|
|
||||||
|
|
||||||
var targetBrowser = this.mTabBrowser;
|
|
||||||
var tabs = this.getTabsArray(targetBrowser);
|
|
||||||
|
|
||||||
var sourceWindow = aDraggedTab.ownerDocument.defaultView;
|
|
||||||
var sourceBrowser = this.getTabBrowserFromChild(aDraggedTab);
|
|
||||||
|
|
||||||
var draggedWholeTree = [].concat(draggedRoots);
|
|
||||||
draggedRoots.forEach(function(aRoot) {
|
|
||||||
draggedWholeTree = draggedWholeTree.concat(this.getDescendantTabs(aRoot));
|
|
||||||
}, this);
|
|
||||||
while (aInfo.insertBefore && draggedWholeTree.indexOf(aInfo.insertBefore) > -1)
|
|
||||||
{
|
|
||||||
aInfo.insertBefore = this.getNextTab(aInfo.insertBefore);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (aInfo.action & this.kACTIONS_FOR_SOURCE) {
|
|
||||||
if (aInfo.action & this.kACTION_PART) {
|
|
||||||
this.partTabsOnDrop(draggedRoots);
|
|
||||||
}
|
|
||||||
else if (aInfo.action & this.kACTION_ATTACH) {
|
|
||||||
this.attachTabsOnDrop(draggedRoots, aInfo.parent);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( // if this move will cause no change...
|
|
||||||
sourceBrowser == targetBrowser &&
|
|
||||||
sourceBrowser.treeStyleTab.getNextVisibleTab(draggedTabs[draggedTabs.length-1]) == aInfo.insertBefore
|
|
||||||
) {
|
|
||||||
// then, do nothing
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// prevent Multiple Tab Handler feature
|
|
||||||
targetBrowser.duplicatingSelectedTabs = true;
|
|
||||||
targetBrowser.movingSelectedTabs = true;
|
|
||||||
|
|
||||||
|
|
||||||
var newRoots = [];
|
|
||||||
var shouldClose = (
|
|
||||||
aInfo.action & this.kACTION_IMPORT &&
|
|
||||||
this.getAllTabsArray(sourceBrowser).length == draggedTabs.length
|
|
||||||
);
|
|
||||||
var oldTabs = [];
|
|
||||||
var newTabs = [];
|
|
||||||
var treeStructure = draggedTabs.map(function(aTab) {
|
|
||||||
var parent = sourceBrowser.treeStyleTab.getParentTab(aTab);
|
|
||||||
return parent ? draggedTabs.indexOf(parent) : -1 ;
|
|
||||||
});
|
|
||||||
|
|
||||||
var parentTabsArray = draggedTabs.map(function(aTab) {
|
|
||||||
return (aInfo.action & this.kACTIONS_FOR_DESTINATION) ?
|
|
||||||
sourceBrowser.treeStyleTab.getParentTab(aTab) : null ;
|
|
||||||
}, this);
|
|
||||||
|
|
||||||
// Firefox fails to "move" collapsed tabs. So, expand them first
|
|
||||||
// and collapse them after they are moved.
|
|
||||||
var collapseExpandState = [];
|
|
||||||
if (aInfo.action & this.kACTION_IMPORT &&
|
|
||||||
'swapBrowsersAndCloseOther' in targetBrowser) {
|
|
||||||
draggedWholeTree.forEach(function(aTab) {
|
|
||||||
collapseExpandState.push(this.getTabValue(aTab, this.kSUBTREE_COLLAPSED) == 'true');
|
|
||||||
this.collapseExpandSubtree(aTab, false, true);
|
|
||||||
this.collapseExpandTab(aTab, false, true);
|
|
||||||
}, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
var lastTabIndex = tabs.length -1;
|
|
||||||
draggedTabs.forEach(function(aTab, aIndex) {
|
|
||||||
var tab = aTab;
|
|
||||||
if (aInfo.action & this.kACTIONS_FOR_DESTINATION) {
|
|
||||||
var parent = parentTabsArray[aIndex];
|
|
||||||
if (tabsInfo.isMultipleMove && 'MultipleTabService' in sourceWindow)
|
|
||||||
sourceWindow.MultipleTabService.setSelection(aTab, false);
|
|
||||||
if (aInfo.action & this.kACTION_IMPORT &&
|
|
||||||
'swapBrowsersAndCloseOther' in targetBrowser) {
|
|
||||||
tab = targetBrowser.addTab();
|
|
||||||
tab.linkedBrowser.stop();
|
|
||||||
tab.linkedBrowser.docShell;
|
|
||||||
targetBrowser.swapBrowsersAndCloseOther(tab, aTab);
|
|
||||||
targetBrowser.setTabTitle(tab);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
tab = targetBrowser.duplicateTab(aTab);
|
|
||||||
this.deleteTabValue(tab, this.kCHILDREN);
|
|
||||||
this.deleteTabValue(tab, this.kPARENT);
|
|
||||||
if (aInfo.action & this.kACTION_IMPORT)
|
|
||||||
oldTabs.push(aTab);
|
|
||||||
}
|
|
||||||
newTabs.push(tab);
|
|
||||||
if (tabsInfo.isMultipleMove && 'MultipleTabService' in window)
|
|
||||||
MultipleTabService.setSelection(tab, true);
|
|
||||||
if (!parent || draggedTabs.indexOf(parent) < 0)
|
|
||||||
newRoots.push(tab);
|
|
||||||
lastTabIndex++;
|
|
||||||
}
|
|
||||||
|
|
||||||
var newIndex = aInfo.insertBefore ? aInfo.insertBefore._tPos : lastTabIndex ;
|
|
||||||
if (aInfo.insertBefore && newIndex > tab._tPos) newIndex--;
|
|
||||||
|
|
||||||
this.internallyTabMovingCount++;
|
|
||||||
targetBrowser.moveTabTo(tab, newIndex);
|
|
||||||
this.collapseExpandTab(tab, false, true);
|
|
||||||
this.internallyTabMovingCount--;
|
|
||||||
|
|
||||||
}, this);
|
|
||||||
|
|
||||||
// close imported tabs from the source browser
|
|
||||||
oldTabs.forEach(function(aTab) {
|
|
||||||
sourceBrowser.removeTab(aTab, { animate : true });
|
|
||||||
});
|
|
||||||
if (shouldClose) this.closeOwner(sourceBrowser);
|
|
||||||
|
|
||||||
// restore tree structure for newly opened tabs
|
|
||||||
newTabs.forEach(function(aTab, aIndex) {
|
|
||||||
var index = treeStructure[aIndex];
|
|
||||||
if (index < 0) return;
|
|
||||||
targetBrowser.treeStyleTab.attachTabTo(aTab, newTabs[index]);
|
|
||||||
});
|
|
||||||
newTabs.reverse();
|
|
||||||
collapseExpandState.reverse();
|
|
||||||
collapseExpandState.forEach(function(aCollapsed, aIndex) {
|
|
||||||
this.collapseExpandSubtree(newTabs[aIndex], aCollapsed, true);
|
|
||||||
}, this);
|
|
||||||
|
|
||||||
if (aInfo.action & this.kACTIONS_FOR_DESTINATION &&
|
|
||||||
aInfo.action & this.kACTION_ATTACH)
|
|
||||||
this.attachTabsOnDrop(newRoots, aInfo.parent);
|
|
||||||
|
|
||||||
// Multiple Tab Handler
|
|
||||||
targetBrowser.movingSelectedTabs = false;
|
|
||||||
targetBrowser.duplicatingSelectedTabs = false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
|
|
||||||
getDraggedTabsInfoFromOneTab : function TSTBrowser_getDraggedTabsInfoFromOneTab(aInfo, aTab)
|
|
||||||
{
|
|
||||||
aTab = this.getTabFromChild(aTab);
|
|
||||||
if (!aTab)
|
|
||||||
return {
|
|
||||||
draggedTab : null,
|
|
||||||
draggedTabs : [],
|
|
||||||
draggedRoots : [],
|
|
||||||
isMultipleMove : false
|
|
||||||
};
|
|
||||||
|
|
||||||
var targetBrowser = this.mTabBrowser;
|
|
||||||
var tabs = this.getTabsArray(targetBrowser);
|
|
||||||
|
|
||||||
var sourceWindow = aTab.ownerDocument.defaultView;
|
|
||||||
var sourceBrowser = this.getTabBrowserFromChild(aTab);
|
|
||||||
|
|
||||||
var draggedTabs = window['piro.sakura.ne.jp'].tabsDragUtils.getSelectedTabs(aInfo.event || sourceBrowser);
|
|
||||||
var draggedRoots = [aTab];
|
|
||||||
var isMultipleMove = false;
|
|
||||||
|
|
||||||
if (draggedTabs.length > 1) {
|
|
||||||
isMultipleMove = true;
|
|
||||||
if (!(aInfo.action & this.kACTIONS_FOR_DESTINATION)) {
|
|
||||||
draggedRoots = [];
|
|
||||||
draggedTabs.forEach(function(aTab) {
|
|
||||||
var parent = aTab,
|
|
||||||
current;
|
|
||||||
do {
|
|
||||||
current = parent;
|
|
||||||
parent = sourceBrowser.treeStyleTab.getParentTab(parent)
|
|
||||||
if (parent && draggedTabs.indexOf(parent) > -1) continue;
|
|
||||||
draggedRoots.push(current);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
while (parent);
|
|
||||||
}, this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (aInfo.action & this.kACTIONS_FOR_DESTINATION) {
|
|
||||||
draggedTabs = [aTab].concat(sourceBrowser.treeStyleTab.getDescendantTabs(aTab));
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
draggedTab : aTab,
|
|
||||||
draggedTabs : draggedTabs,
|
|
||||||
draggedRoots : draggedRoots,
|
|
||||||
isMultipleMove : isMultipleMove
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
attachTabsOnDrop : function TSTBrowser_attachTabsOnDrop(aTabs, aParent)
|
|
||||||
{
|
|
||||||
this.mTabBrowser.movingSelectedTabs = true; // Multiple Tab Handler
|
|
||||||
aTabs.forEach(function(aTab) {
|
|
||||||
if (!aTab.parentNode) return; // ignore removed tabs
|
|
||||||
if (aParent)
|
|
||||||
this.attachTabTo(aTab, aParent);
|
|
||||||
else
|
|
||||||
this.partTab(aTab);
|
|
||||||
this.collapseExpandTab(aTab, false);
|
|
||||||
}, this);
|
|
||||||
this.mTabBrowser.movingSelectedTabs = false; // Multiple Tab Handler
|
|
||||||
},
|
|
||||||
|
|
||||||
partTabsOnDrop : function TSTBrowser_partTabsOnDrop(aTabs)
|
|
||||||
{
|
|
||||||
this.mTabBrowser.movingSelectedTabs = true; // Multiple Tab Handler
|
|
||||||
aTabs.forEach(function(aTab) {
|
|
||||||
if (!aTab.parentNode) return; // ignore removed tabs
|
|
||||||
this.partTab(aTab);
|
|
||||||
this.collapseExpandTab(aTab, false);
|
|
||||||
}, this);
|
|
||||||
this.mTabBrowser.movingSelectedTabs = false; // Multiple Tab Handler
|
|
||||||
},
|
|
||||||
|
|
||||||
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();
|
|
||||||
},
|
|
||||||
|
|
||||||
clearDropPosition : function TSTBrowser_clearDropPosition()
|
|
||||||
{
|
|
||||||
var b = this.mTabBrowser;
|
|
||||||
var xpathResult = this.evaluateXPath(
|
|
||||||
'child::xul:tab[@'+this.kDROP_POSITION+']',
|
|
||||||
b.mTabContainer
|
|
||||||
);
|
|
||||||
for (var i = 0, maxi = xpathResult.snapshotLength; i < maxi; i++)
|
|
||||||
{
|
|
||||||
xpathResult.snapshotItem(i).removeAttribute(this.kDROP_POSITION);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
isDraggingAllTabs : function TSTBrowser_isDraggingAllTabs(aTab, aTabs)
|
|
||||||
{
|
|
||||||
var actionInfo = {
|
|
||||||
action : this.kACTIONS_FOR_DESTINATION | this.kACTION_IMPORT
|
|
||||||
};
|
|
||||||
var tabsInfo = this.getDraggedTabsInfoFromOneTab(actionInfo, aTab);
|
|
||||||
return tabsInfo.draggedTabs.length == (aTabs || this.getAllTabsArray(this.mTabBrowser)).length;
|
|
||||||
},
|
|
||||||
|
|
||||||
isDraggingAllCurrentTabs : function TSTBrowser_isDraggingAllCurrentTabs(aTab)
|
|
||||||
{
|
|
||||||
return this.isDraggingAllTabs(aTab, this.getTabsArray(this.mTabBrowser));
|
|
||||||
},
|
|
||||||
|
|
||||||
/* commands */
|
/* commands */
|
||||||
|
|
||||||
/* reset */
|
/* reset */
|
||||||
|
@ -95,10 +95,10 @@ TreeStyleTabBrowserTabbarDNDObserver.prototype = {
|
|||||||
tooltip.popupBoxObject.popupState != 'closed')
|
tooltip.popupBoxObject.popupState != 'closed')
|
||||||
tooltip.hidePopup();
|
tooltip.hidePopup();
|
||||||
|
|
||||||
var dropAction = sv.getDropAction(aEvent);
|
var dropAction = this.getDropAction(aEvent);
|
||||||
if ('dataTransfer' in aEvent) {
|
if ('dataTransfer' in aEvent) {
|
||||||
var dt = aEvent.dataTransfer;
|
var dt = aEvent.dataTransfer;
|
||||||
if (dropAction.action & this.kACTION_NEWTAB) {
|
if (dropAction.action & sv.kACTION_NEWTAB) {
|
||||||
dt.effectAllowed = dt.dropEffect = (
|
dt.effectAllowed = dt.dropEffect = (
|
||||||
!dropAction.source ? 'link' :
|
!dropAction.source ? 'link' :
|
||||||
sv.isCopyAction(aEvent) ? 'copy' :
|
sv.isCopyAction(aEvent) ? 'copy' :
|
||||||
@ -127,7 +127,7 @@ try{
|
|||||||
if (sv.isCollapsed(tab))
|
if (sv.isCollapsed(tab))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var info = sv.getDropAction(aEvent, session);
|
var info = this.getDropAction(aEvent, session);
|
||||||
return info.canDrop;
|
return info.canDrop;
|
||||||
}
|
}
|
||||||
catch(e) {
|
catch(e) {
|
||||||
@ -136,6 +136,489 @@ catch(e) {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getDropAction : function TSTTabbarDND_getDropAction(aEvent, aDragSession)
|
||||||
|
{
|
||||||
|
var sv = this.mOwner;
|
||||||
|
var b = sv.mTabBrowser;
|
||||||
|
|
||||||
|
if (!aDragSession)
|
||||||
|
aDragSession = sv.getCurrentDragSession();
|
||||||
|
|
||||||
|
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) ||
|
||||||
|
('swapBrowsersAndCloseOther' 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return info;
|
||||||
|
},
|
||||||
|
|
||||||
|
getDropActionInternal : function TSTTabbarDND_getDropActionInternal(aEvent, aSourceTab)
|
||||||
|
{
|
||||||
|
var sv = this.mOwner;
|
||||||
|
var b = sv.mTabBrowser;
|
||||||
|
|
||||||
|
var tab = aEvent.target;
|
||||||
|
var tabs = sv.getTabsArray(b);
|
||||||
|
var firstTab = sv.getFirstNormalTab(b);
|
||||||
|
var lastTabIndex = tabs.length -1;
|
||||||
|
var isInverted = sv.isVertical ? false : window.getComputedStyle(b.parentNode, null).direction == 'rtl';
|
||||||
|
var info = {
|
||||||
|
target : null,
|
||||||
|
position : null,
|
||||||
|
action : null,
|
||||||
|
parent : null,
|
||||||
|
insertBefore : null,
|
||||||
|
event : aEvent
|
||||||
|
};
|
||||||
|
|
||||||
|
var isTabMoveFromOtherWindow = aSourceTab && aSourceTab.ownerDocument != document;
|
||||||
|
var isNewTabAction = !aSourceTab || aSourceTab.ownerDocument != document;
|
||||||
|
|
||||||
|
if (tab.localName != 'tab') {
|
||||||
|
var action = isTabMoveFromOtherWindow ? sv.kACTION_STAY : (sv.kACTION_MOVE | sv.kACTION_PART) ;
|
||||||
|
if (isNewTabAction) action |= sv.kACTION_NEWTAB;
|
||||||
|
if (aEvent[sv.positionProp] < firstTab.boxObject[sv.positionProp]) {
|
||||||
|
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.positionProp] > tabs[lastTabIndex].boxObject[sv.positionProp] + tabs[lastTabIndex].boxObject[sv.sizeProp]) {
|
||||||
|
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) ;
|
||||||
|
info.target = tabs[Math.min(index, lastTabIndex)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sv.ensureTabInitialized(tab);
|
||||||
|
info.target = tab;
|
||||||
|
}
|
||||||
|
|
||||||
|
var positionProp = sv.isVertical && tab.getAttribute('pinned') == 'true' ? sv.invertedPositionProp : sv.positionProp ;
|
||||||
|
var sizeProp = sv.isVertical && tab.getAttribute('pinned') == 'true' ? sv.invertedSizeProp : sv.sizeProp ;
|
||||||
|
var boxPos = tab.boxObject[positionProp];
|
||||||
|
var boxUnit = Math.round(tab.boxObject[sizeProp] / 3);
|
||||||
|
if (aEvent[positionProp] < boxPos + boxUnit) {
|
||||||
|
info.position = isInverted ? sv.kDROP_AFTER : sv.kDROP_BEFORE ;
|
||||||
|
}
|
||||||
|
else if (aEvent[positionProp] > 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:
|
||||||
|
info.action = sv.kACTION_STAY | sv.kACTION_ATTACH;
|
||||||
|
info.parent = tab;
|
||||||
|
var visible = sv.getNextVisibleTab(tab);
|
||||||
|
info.insertBefore = sv.getTreePref('insertNewChildAt') == sv.kINSERT_FISRT ?
|
||||||
|
(sv.getFirstChildTab(tab) || visible) :
|
||||||
|
(sv.getNextSiblingTab(tab) || sv.getNextTab(sv.getLastDescendantTab(tab)) || visible);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case sv.kDROP_BEFORE:
|
||||||
|
/*
|
||||||
|
[TARGET ] <EFBFBD>ªpart from parent, and move
|
||||||
|
|
||||||
|
[ ]
|
||||||
|
[TARGET ] <EFBFBD>ªattach to the parent of the target, and move
|
||||||
|
|
||||||
|
[ ]
|
||||||
|
[TARGET ] <EFBFBD>ªattach to the parent of the target, and move
|
||||||
|
|
||||||
|
[ ]
|
||||||
|
[TARGET] <EFBFBD>ªattach to the parent of the target (previous tab), and move
|
||||||
|
*/
|
||||||
|
var prevTab = sv.getPreviousVisibleTab(tab);
|
||||||
|
if (!prevTab) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case sv.kDROP_AFTER:
|
||||||
|
/*
|
||||||
|
[TARGET ] <EFBFBD>«if the target has a parent, attach to it and and move
|
||||||
|
|
||||||
|
[TARGET] <EFBFBD>«attach to the parent of the target, and move
|
||||||
|
[ ]
|
||||||
|
|
||||||
|
[TARGET ] <EFBFBD>«attach to the parent of the target, and move
|
||||||
|
[ ]
|
||||||
|
|
||||||
|
[TARGET ] <EFBFBD>«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 ] <EFBFBD>«attach dragged tab to the parent of the target as its next sibling
|
||||||
|
[DRAGGED]
|
||||||
|
*/
|
||||||
|
if (aSourceTab == nextTab && sv.getDescendantTabs(info.parent).length == 1) {
|
||||||
|
info.action = sv.kACTION_MOVE | sv.kACTION_ATTACH;
|
||||||
|
info.parent = sv.getParentTab(tab);
|
||||||
|
info.insertBefore = sv.getNextTab(nextTab);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isNewTabAction) action |= sv.kACTION_NEWTAB;
|
||||||
|
|
||||||
|
return info;
|
||||||
|
},
|
||||||
|
|
||||||
|
performDrop : function TSTTabbarDND_performDrop(aInfo, aDraggedTab)
|
||||||
|
{
|
||||||
|
var sv = this.mOwner;
|
||||||
|
var b = sv.mTabBrowser;
|
||||||
|
|
||||||
|
var tabsInfo = this.getDraggedTabsInfoFromOneTab(aInfo, aDraggedTab);
|
||||||
|
if (!tabsInfo.draggedTab) return false;
|
||||||
|
|
||||||
|
aDraggedTab = tabsInfo.draggedTab;
|
||||||
|
var draggedTabs = tabsInfo.draggedTabs;
|
||||||
|
var draggedRoots = tabsInfo.draggedRoots;
|
||||||
|
|
||||||
|
|
||||||
|
var targetBrowser = b;
|
||||||
|
var tabs = sv.getTabsArray(targetBrowser);
|
||||||
|
|
||||||
|
var sourceWindow = aDraggedTab.ownerDocument.defaultView;
|
||||||
|
var sourceBrowser = sv.getTabBrowserFromChild(aDraggedTab);
|
||||||
|
|
||||||
|
var draggedWholeTree = [].concat(draggedRoots);
|
||||||
|
draggedRoots.forEach(function(aRoot) {
|
||||||
|
draggedWholeTree = draggedWholeTree.concat(sv.getDescendantTabs(aRoot));
|
||||||
|
}, this);
|
||||||
|
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.partTabsOnDrop(draggedRoots);
|
||||||
|
}
|
||||||
|
else if (aInfo.action & sv.kACTION_ATTACH) {
|
||||||
|
this.attachTabsOnDrop(draggedRoots, aInfo.parent);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( // if this move will cause no change...
|
||||||
|
sourceBrowser == targetBrowser &&
|
||||||
|
sourceBrowser.treeStyleTab.getNextVisibleTab(draggedTabs[draggedTabs.length-1]) == aInfo.insertBefore
|
||||||
|
) {
|
||||||
|
// then, do nothing
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// prevent Multiple Tab Handler feature
|
||||||
|
targetBrowser.duplicatingSelectedTabs = true;
|
||||||
|
targetBrowser.movingSelectedTabs = true;
|
||||||
|
|
||||||
|
|
||||||
|
var newRoots = [];
|
||||||
|
var shouldClose = (
|
||||||
|
aInfo.action & sv.kACTION_IMPORT &&
|
||||||
|
sv.getAllTabsArray(sourceBrowser).length == draggedTabs.length
|
||||||
|
);
|
||||||
|
var oldTabs = [];
|
||||||
|
var newTabs = [];
|
||||||
|
var treeStructure = draggedTabs.map(function(aTab) {
|
||||||
|
var parent = sourceBrowser.treeStyleTab.getParentTab(aTab);
|
||||||
|
return parent ? draggedTabs.indexOf(parent) : -1 ;
|
||||||
|
});
|
||||||
|
|
||||||
|
var parentTabsArray = draggedTabs.map(function(aTab) {
|
||||||
|
return (aInfo.action & sv.kACTIONS_FOR_DESTINATION) ?
|
||||||
|
sourceBrowser.treeStyleTab.getParentTab(aTab) : null ;
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
// Firefox fails to "move" collapsed tabs. So, expand them first
|
||||||
|
// and collapse them after they are moved.
|
||||||
|
var collapseExpandState = [];
|
||||||
|
if (aInfo.action & sv.kACTION_IMPORT &&
|
||||||
|
'swapBrowsersAndCloseOther' in targetBrowser) {
|
||||||
|
draggedWholeTree.forEach(function(aTab) {
|
||||||
|
collapseExpandState.push(sv.getTabValue(aTab, sv.kSUBTREE_COLLAPSED) == 'true');
|
||||||
|
sv.collapseExpandSubtree(aTab, false, true);
|
||||||
|
sv.collapseExpandTab(aTab, false, true);
|
||||||
|
}, sv);
|
||||||
|
}
|
||||||
|
|
||||||
|
var lastTabIndex = tabs.length -1;
|
||||||
|
draggedTabs.forEach(function(aTab, aIndex) {
|
||||||
|
var tab = aTab;
|
||||||
|
if (aInfo.action & sv.kACTIONS_FOR_DESTINATION) {
|
||||||
|
var parent = parentTabsArray[aIndex];
|
||||||
|
if (tabsInfo.isMultipleMove && 'MultipleTabService' in sourceWindow)
|
||||||
|
sourceWindow.MultipleTabService.setSelection(aTab, false);
|
||||||
|
if (aInfo.action & sv.kACTION_IMPORT &&
|
||||||
|
'swapBrowsersAndCloseOther' in targetBrowser) {
|
||||||
|
tab = targetBrowser.addTab();
|
||||||
|
tab.linkedBrowser.stop();
|
||||||
|
tab.linkedBrowser.docShell;
|
||||||
|
targetBrowser.swapBrowsersAndCloseOther(tab, aTab);
|
||||||
|
targetBrowser.setTabTitle(tab);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
tab = targetBrowser.duplicateTab(aTab);
|
||||||
|
sv.deleteTabValue(tab, sv.kCHILDREN);
|
||||||
|
sv.deleteTabValue(tab, sv.kPARENT);
|
||||||
|
if (aInfo.action & sv.kACTION_IMPORT)
|
||||||
|
oldTabs.push(aTab);
|
||||||
|
}
|
||||||
|
newTabs.push(tab);
|
||||||
|
if (tabsInfo.isMultipleMove && 'MultipleTabService' in window)
|
||||||
|
MultipleTabService.setSelection(tab, true);
|
||||||
|
if (!parent || draggedTabs.indexOf(parent) < 0)
|
||||||
|
newRoots.push(tab);
|
||||||
|
lastTabIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
var newIndex = aInfo.insertBefore ? aInfo.insertBefore._tPos : lastTabIndex ;
|
||||||
|
if (aInfo.insertBefore && newIndex > tab._tPos) newIndex--;
|
||||||
|
|
||||||
|
sv.internallyTabMovingCount++;
|
||||||
|
targetBrowser.moveTabTo(tab, newIndex);
|
||||||
|
sv.collapseExpandTab(tab, false, true);
|
||||||
|
sv.internallyTabMovingCount--;
|
||||||
|
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
// close imported tabs from the source browser
|
||||||
|
oldTabs.forEach(function(aTab) {
|
||||||
|
sourceBrowser.removeTab(aTab, { animate : true });
|
||||||
|
});
|
||||||
|
if (shouldClose)
|
||||||
|
this.closeOwner(sourceBrowser);
|
||||||
|
|
||||||
|
// restore tree structure for newly opened tabs
|
||||||
|
newTabs.forEach(function(aTab, aIndex) {
|
||||||
|
var index = treeStructure[aIndex];
|
||||||
|
if (index < 0) return;
|
||||||
|
sv.attachTabTo(aTab, newTabs[index]);
|
||||||
|
}, sv);
|
||||||
|
newTabs.reverse();
|
||||||
|
collapseExpandState.reverse();
|
||||||
|
collapseExpandState.forEach(function(aCollapsed, aIndex) {
|
||||||
|
sv.collapseExpandSubtree(newTabs[aIndex], aCollapsed, true);
|
||||||
|
}, sv);
|
||||||
|
|
||||||
|
if (aInfo.action & sv.kACTIONS_FOR_DESTINATION &&
|
||||||
|
aInfo.action & sv.kACTION_ATTACH)
|
||||||
|
this.attachTabsOnDrop(newRoots, aInfo.parent);
|
||||||
|
|
||||||
|
// Multiple Tab Handler
|
||||||
|
targetBrowser.movingSelectedTabs = false;
|
||||||
|
targetBrowser.duplicatingSelectedTabs = false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
|
||||||
|
getDraggedTabsInfoFromOneTab : function TSTTabbarDND_getDraggedTabsInfoFromOneTab(aInfo, aTab)
|
||||||
|
{
|
||||||
|
var sv = this.mOwner;
|
||||||
|
var b = sv.mTabBrowser;
|
||||||
|
|
||||||
|
aTab = sv.getTabFromChild(aTab);
|
||||||
|
if (!aTab)
|
||||||
|
return {
|
||||||
|
draggedTab : null,
|
||||||
|
draggedTabs : [],
|
||||||
|
draggedRoots : [],
|
||||||
|
isMultipleMove : false
|
||||||
|
};
|
||||||
|
|
||||||
|
var targetBrowser = b;
|
||||||
|
var tabs = sv.getTabsArray(targetBrowser);
|
||||||
|
|
||||||
|
var sourceWindow = aTab.ownerDocument.defaultView;
|
||||||
|
var sourceBrowser = sv.getTabBrowserFromChild(aTab);
|
||||||
|
|
||||||
|
var draggedTabs = window['piro.sakura.ne.jp'].tabsDragUtils.getSelectedTabs(aInfo.event || sourceBrowser);
|
||||||
|
var draggedRoots = [aTab];
|
||||||
|
var isMultipleMove = false;
|
||||||
|
|
||||||
|
if (draggedTabs.length > 1) {
|
||||||
|
isMultipleMove = true;
|
||||||
|
if (!(aInfo.action & sv.kACTIONS_FOR_DESTINATION)) {
|
||||||
|
draggedRoots = [];
|
||||||
|
draggedTabs.forEach(function(aTab) {
|
||||||
|
var parent = aTab,
|
||||||
|
current;
|
||||||
|
do {
|
||||||
|
current = parent;
|
||||||
|
parent = sourceBrowser.treeStyleTab.getParentTab(parent)
|
||||||
|
if (parent && draggedTabs.indexOf(parent) > -1) continue;
|
||||||
|
draggedRoots.push(current);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
while (parent);
|
||||||
|
}, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (aInfo.action & sv.kACTIONS_FOR_DESTINATION) {
|
||||||
|
draggedTabs = [aTab].concat(sourceBrowser.treeStyleTab.getDescendantTabs(aTab));
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
draggedTab : aTab,
|
||||||
|
draggedTabs : draggedTabs,
|
||||||
|
draggedRoots : draggedRoots,
|
||||||
|
isMultipleMove : isMultipleMove
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
attachTabsOnDrop : function TSTTabbarDND_attachTabsOnDrop(aTabs, aParent)
|
||||||
|
{
|
||||||
|
var sv = this.mOwner;
|
||||||
|
var b = sv.mTabBrowser;
|
||||||
|
|
||||||
|
b.movingSelectedTabs = true; // Multiple Tab Handler
|
||||||
|
aTabs.forEach(function(aTab) {
|
||||||
|
if (!aTab.parentNode) return; // ignore removed tabs
|
||||||
|
if (aParent)
|
||||||
|
sv.attachTabTo(aTab, aParent);
|
||||||
|
else
|
||||||
|
sv.partTab(aTab);
|
||||||
|
sv.collapseExpandTab(aTab, false);
|
||||||
|
}, sv);
|
||||||
|
b.movingSelectedTabs = false; // Multiple Tab Handler
|
||||||
|
},
|
||||||
|
|
||||||
|
partTabsOnDrop : function TSTTabbarDND_partTabsOnDrop(aTabs)
|
||||||
|
{
|
||||||
|
var sv = this.mOwner;
|
||||||
|
var b = sv.mTabBrowser;
|
||||||
|
|
||||||
|
b.movingSelectedTabs = true; // Multiple Tab Handler
|
||||||
|
aTabs.forEach(function(aTab) {
|
||||||
|
if (!aTab.parentNode) return; // ignore removed tabs
|
||||||
|
sv.partTab(aTab);
|
||||||
|
sv.collapseExpandTab(aTab, false);
|
||||||
|
}, sv);
|
||||||
|
b.movingSelectedTabs = false; // Multiple Tab Handler
|
||||||
|
},
|
||||||
|
|
||||||
|
closeOwner : function TSTTabbarDND_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();
|
||||||
|
},
|
||||||
|
|
||||||
|
clearDropPosition : function TSTTabbarDND_clearDropPosition()
|
||||||
|
{
|
||||||
|
var sv = this.mOwner;
|
||||||
|
var b = sv.mTabBrowser;
|
||||||
|
var xpathResult = sv.evaluateXPath(
|
||||||
|
'child::xul:tab[@'+sv.kDROP_POSITION+']',
|
||||||
|
b.mTabContainer
|
||||||
|
);
|
||||||
|
for (var i = 0, maxi = xpathResult.snapshotLength; i < maxi; i++)
|
||||||
|
{
|
||||||
|
xpathResult.snapshotItem(i).removeAttribute(sv.kDROP_POSITION);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
isDraggingAllTabs : function TSTTabbarDND_isDraggingAllTabs(aTab, aTabs)
|
||||||
|
{
|
||||||
|
var sv = this.mOwner;
|
||||||
|
var b = sv.mTabBrowser;
|
||||||
|
|
||||||
|
var actionInfo = {
|
||||||
|
action : sv.kACTIONS_FOR_DESTINATION | sv.kACTION_IMPORT
|
||||||
|
};
|
||||||
|
var tabsInfo = this.getDraggedTabsInfoFromOneTab(actionInfo, aTab);
|
||||||
|
return tabsInfo.draggedTabs.length == (aTabs || sv.getAllTabsArray(b)).length;
|
||||||
|
},
|
||||||
|
|
||||||
|
isDraggingAllCurrentTabs : function TSTTabbarDND_isDraggingAllCurrentTabs(aTab)
|
||||||
|
{
|
||||||
|
return this.isDraggingAllTabs(aTab, this.getTabsArray(this.mOwner.mTabBrowser));
|
||||||
|
},
|
||||||
|
|
||||||
handleEvent : function TSTTabbarDND_handleEvent(aEvent)
|
handleEvent : function TSTTabbarDND_handleEvent(aEvent)
|
||||||
{
|
{
|
||||||
switch (aEvent.type)
|
switch (aEvent.type)
|
||||||
@ -166,7 +649,7 @@ catch(e) {
|
|||||||
action : sv.kACTIONS_FOR_DESTINATION | sv.kACTION_MOVE,
|
action : sv.kACTIONS_FOR_DESTINATION | sv.kACTION_MOVE,
|
||||||
event : aEvent
|
event : aEvent
|
||||||
};
|
};
|
||||||
var tabsInfo = sv.getDraggedTabsInfoFromOneTab(actionInfo, aTab);
|
var tabsInfo = this.getDraggedTabsInfoFromOneTab(actionInfo, aTab);
|
||||||
if (tabsInfo.draggedTabs.length > 1)
|
if (tabsInfo.draggedTabs.length > 1)
|
||||||
window['piro.sakura.ne.jp'].tabsDragUtils.startTabsDrag(aEvent, tabsInfo.draggedTabs);
|
window['piro.sakura.ne.jp'].tabsDragUtils.startTabsDrag(aEvent, tabsInfo.draggedTabs);
|
||||||
},
|
},
|
||||||
@ -246,7 +729,7 @@ catch(e) {
|
|||||||
|
|
||||||
var tabbarFromEvent = sv.getTabbarFromChild(aEvent.relatedTarget);
|
var tabbarFromEvent = sv.getTabbarFromChild(aEvent.relatedTarget);
|
||||||
if (!tabbarFromEvent)
|
if (!tabbarFromEvent)
|
||||||
sv.clearDropPosition();
|
this.clearDropPosition();
|
||||||
|
|
||||||
window.clearTimeout(this.mAutoExpandTimer);
|
window.clearTimeout(this.mAutoExpandTimer);
|
||||||
this.mAutoExpandTimer = null;
|
this.mAutoExpandTimer = null;
|
||||||
@ -271,7 +754,7 @@ catch(e) {
|
|||||||
var strip = sv.tabStrip;
|
var strip = sv.tabStrip;
|
||||||
var dt = aEvent.dataTransfer;
|
var dt = aEvent.dataTransfer;
|
||||||
|
|
||||||
sv.clearDropPosition();
|
this.clearDropPosition();
|
||||||
|
|
||||||
if (dt.mozUserCancelled || dt.dropEffect != 'none')
|
if (dt.mozUserCancelled || dt.dropEffect != 'none')
|
||||||
return;
|
return;
|
||||||
@ -302,7 +785,7 @@ catch(e) {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
var draggedTab = dt.mozGetDataAt(TAB_DROP_TYPE, 0);
|
var draggedTab = dt.mozGetDataAt(TAB_DROP_TYPE, 0);
|
||||||
if (sv.isDraggingAllCurrentTabs(draggedTab))
|
if (this.isDraggingAllCurrentTabs(draggedTab))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
b.replaceTabWithWindow(draggedTab);
|
b.replaceTabWithWindow(draggedTab);
|
||||||
@ -341,7 +824,7 @@ try{
|
|||||||
|
|
||||||
sv.autoScroll.processAutoScroll(aEvent);
|
sv.autoScroll.processAutoScroll(aEvent);
|
||||||
|
|
||||||
var info = sv.getDropAction(aEvent, session);
|
var info = this.getDropAction(aEvent, session);
|
||||||
|
|
||||||
var observer = b;
|
var observer = b;
|
||||||
if (b.tabContainer && b.tabContainer._setEffectAllowedForDataTransfer) // for Firefox 4.0
|
if (b.tabContainer && b.tabContainer._setEffectAllowedForDataTransfer) // for Firefox 4.0
|
||||||
@ -379,7 +862,7 @@ try{
|
|||||||
b.mTabContainer,
|
b.mTabContainer,
|
||||||
XPathResult.FIRST_ORDERED_NODE_TYPE
|
XPathResult.FIRST_ORDERED_NODE_TYPE
|
||||||
).singleNodeValue)
|
).singleNodeValue)
|
||||||
sv.clearDropPosition();
|
this.clearDropPosition();
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!info.canDrop ||
|
!info.canDrop ||
|
||||||
@ -427,13 +910,13 @@ catch(e) {
|
|||||||
var tabbar = b.mTabContainer;
|
var tabbar = b.mTabContainer;
|
||||||
var dt = aEvent.dataTransfer;
|
var dt = aEvent.dataTransfer;
|
||||||
|
|
||||||
sv.clearDropPosition();
|
this.clearDropPosition();
|
||||||
|
|
||||||
if (tabbar._tabDropIndicator) // for Firefox 4 or later
|
if (tabbar._tabDropIndicator) // for Firefox 4 or later
|
||||||
tabbar._tabDropIndicator.collapsed = true;
|
tabbar._tabDropIndicator.collapsed = true;
|
||||||
|
|
||||||
var session = sv.getCurrentDragSession();
|
var session = sv.getCurrentDragSession();
|
||||||
var dropActionInfo = sv.getDropAction(aEvent, session);
|
var dropActionInfo = this.getDropAction(aEvent, session);
|
||||||
|
|
||||||
var draggedTab;
|
var draggedTab;
|
||||||
if (dt.dropEffect != 'link') {
|
if (dt.dropEffect != 'link') {
|
||||||
@ -444,7 +927,7 @@ catch(e) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (draggedTab && sv.performDrop(dropActionInfo, draggedTab)) {
|
if (draggedTab && this.performDrop(dropActionInfo, draggedTab)) {
|
||||||
aEvent.stopPropagation();
|
aEvent.stopPropagation();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -500,7 +983,7 @@ catch(e) {
|
|||||||
|
|
||||||
let tab = sv.getTabFromEvent(aEvent);
|
let tab = sv.getTabFromEvent(aEvent);
|
||||||
if (!tab || dt.dropEffect == 'copy') {
|
if (!tab || dt.dropEffect == 'copy') {
|
||||||
sv.performDrop(dropActionInfo, b.loadOneTab(getShortcutOrURI(url), { inBackground: bgLoad }));
|
this.performDrop(dropActionInfo, b.loadOneTab(getShortcutOrURI(url), { inBackground: bgLoad }));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
let locked = (
|
let locked = (
|
||||||
@ -514,7 +997,7 @@ catch(e) {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
if (loadDroppedLinkToNewChildTab || locked) {
|
if (loadDroppedLinkToNewChildTab || locked) {
|
||||||
sv.performDrop(dropActionInfo, b.loadOneTab(getShortcutOrURI(url), { inBackground: bgLoad }));
|
this.performDrop(dropActionInfo, b.loadOneTab(getShortcutOrURI(url), { inBackground: bgLoad }));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
tab.linkedBrowser.loadURI(getShortcutOrURI(url));
|
tab.linkedBrowser.loadURI(getShortcutOrURI(url));
|
||||||
|
Loading…
Reference in New Issue
Block a user