support drag feedback image and multiple drag data for dragging of trees
This commit is contained in:
parent
fedf1f4c5f
commit
2932d89da7
244
content/treestyletab/res/tabsDragUtils.js
Normal file
244
content/treestyletab/res/tabsDragUtils.js
Normal file
@ -0,0 +1,244 @@
|
||||
/*
|
||||
Multiple Tabs Drag and Drop Utilities for Firefox 3.5 or later
|
||||
|
||||
Usage:
|
||||
window['piro.sakura.ne.jp'].tabsDragUtils.initTabBrowser(gBrowser);
|
||||
|
||||
// in dragstart event listener
|
||||
window['piro.sakura.ne.jp'].tabsDragUtils.startTabsDrag(aEvent, aArrayOfTabs);
|
||||
|
||||
license: The MIT License, Copyright (c) 2010 SHIMODA "Piro" Hiroshi
|
||||
http://github.com/piroor/fxaddonlibs/blob/master/license.txt
|
||||
original:
|
||||
http://github.com/piroor/fxaddonlibs/blob/master/tabsDragUtils.js
|
||||
*/
|
||||
(function() {
|
||||
const currentRevision = 1;
|
||||
|
||||
if (!('piro.sakura.ne.jp' in window)) window['piro.sakura.ne.jp'] = {};
|
||||
|
||||
var loadedRevision = 'tabsDragUtils' in window['piro.sakura.ne.jp'] ?
|
||||
window['piro.sakura.ne.jp'].tabsDragUtils.revision :
|
||||
0 ;
|
||||
if (loadedRevision && loadedRevision > currentRevision) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (loadedRevision &&
|
||||
'destroy' in window['piro.sakura.ne.jp'].tabsDragUtils)
|
||||
window['piro.sakura.ne.jp'].tabsDragUtils.destroy();
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
|
||||
var tabsDragUtils = {
|
||||
revision : currentRevision,
|
||||
|
||||
init : function TDU_init()
|
||||
{
|
||||
window.addEventListener('load', this._delayedInit, false);
|
||||
},
|
||||
_delayedInit : function TDU_delayedInit()
|
||||
{
|
||||
window.removeEventListener('load', arguments.callee, false);
|
||||
// BarTap
|
||||
// https://addons.mozilla.org/firefox/addon/67651
|
||||
if ('BarTap' in window &&
|
||||
'writeBarTap' in BarTap) {
|
||||
eval('BarTap.writeBarTap = '+
|
||||
BarTap.writeBarTap.toSource().replace(
|
||||
'bartap = JSON.stringify',
|
||||
'window["piro.sakura.ne.jp"].tabsDragUtils._backupArgumentURI(aURI, aBrowser); $&'
|
||||
)
|
||||
);
|
||||
}
|
||||
delete tabsDragUtils._delayedInit;
|
||||
},
|
||||
destroy : function TDU_destroy()
|
||||
{
|
||||
if (this._delayedInit)
|
||||
window.removeEventListener('load', this._delayedInit, false);
|
||||
},
|
||||
|
||||
initTabBrowser : function TDU_initTabBrowser(aTabBrowser)
|
||||
{
|
||||
var tabDNDObserver = (aTabBrowser.tabContainer && aTabBrowser.tabContainer.tabbrowser == aTabBrowser) ?
|
||||
aTabBrowser.tabContainer : // Firefox 4.0 or later
|
||||
aTabBrowser ; // Firefox 3.5 - 3.6
|
||||
if ('_setEffectAllowedForDataTransfer' in tabDNDObserver &&
|
||||
tabDNDObserver._setEffectAllowedForDataTransfer.toSource().indexOf('tabDragUtils') < 0) {
|
||||
eval('tabDNDObserver._setEffectAllowedForDataTransfer = '+
|
||||
tabDNDObserver._setEffectAllowedForDataTransfer.toSource().replace(
|
||||
'dt.mozItemCount > 1',
|
||||
'$& && !window["piro.sakura.ne.jp"].tabsDragUtils.isTabsDragging(arguments[0])'
|
||||
)
|
||||
);
|
||||
}
|
||||
},
|
||||
destroyTabBrowser : function TDU_destroyTabBrowser(aTabBrowser)
|
||||
{
|
||||
},
|
||||
|
||||
startTabsDrag : function TDU_startTabsDrag(aEvent, aTabs)
|
||||
{
|
||||
var draggedTab = this.getTabFromEvent(aEvent);
|
||||
var tabs = aTabs || [];
|
||||
var index = tabs.indexOf(draggedTab);
|
||||
if (index < 0)
|
||||
return;
|
||||
|
||||
var dt = aEvent.dataTransfer;
|
||||
dt.setDragImage(this.createDragFeedbackImage(tabs), 0, 0);
|
||||
|
||||
tabs.splice(index, 1);
|
||||
tabs.unshift(draggedTab);
|
||||
|
||||
tabs.forEach(function(aTab, aIndex) {
|
||||
dt.mozSetDataAt(TAB_DROP_TYPE, aTab, aIndex);
|
||||
dt.mozSetDataAt('text/x-moz-text-internal', this.getCurrentURIOfTab(aTab), aIndex);
|
||||
}, this);
|
||||
|
||||
dt.mozCursor = 'default';
|
||||
|
||||
aEvent.stopPropagation();
|
||||
},
|
||||
createDragFeedbackImage : function TDU_createDragFeedbackImage(aTabs)
|
||||
{
|
||||
var previews = aTabs.map(function(aTab) {
|
||||
return tabPreviews.capture(aTab, false);
|
||||
}, this);
|
||||
var offset = 16;
|
||||
|
||||
var canvas = document.createElementNS('http://www.w3.org/1999/xhtml', 'canvas');
|
||||
canvas.width = previews[0].width + (offset * aTabs.length);
|
||||
canvas.height = previews[0].height + (offset * aTabs.length);
|
||||
|
||||
var ctx = canvas.getContext('2d');
|
||||
ctx.save();
|
||||
try {
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
previews.forEach(function(aPreview, aIndex) {
|
||||
ctx.drawImage(aPreview, 0, 0);
|
||||
ctx.translate(offset, offset);
|
||||
ctx.globalAlpha = 1 / (aIndex+1);
|
||||
}, this);
|
||||
}
|
||||
catch(e) {
|
||||
}
|
||||
ctx.restore();
|
||||
|
||||
return canvas;
|
||||
},
|
||||
getTabFromEvent : function TDU_getTabFromEvent(aEvent, aReallyOnTab)
|
||||
{
|
||||
var tab = (aEvent.originalTarget || aEvent.target).ownerDocument.evaluate(
|
||||
'ancestor-or-self::*[local-name()="tab"]',
|
||||
aEvent.originalTarget || aEvent.target,
|
||||
null,
|
||||
XPathResult.FIRST_ORDERED_NODE_TYPE,
|
||||
null
|
||||
).singleNodeValue;
|
||||
if (tab || aReallyOnTab)
|
||||
return tab;
|
||||
|
||||
var b = this.getTabBrowserFromChild(aEvent.originalTarget);
|
||||
if (b &&
|
||||
'treeStyleTab' in b &&
|
||||
'getTabFromTabbarEvent' in b.treeStyleTab) { // Tree Style Tab
|
||||
return b.treeStyleTab.getTabFromTabbarEvent(aEvent);
|
||||
}
|
||||
return null;
|
||||
},
|
||||
getTabBrowserFromChild : function TDU_getTabBrowserFromChild(aTabBrowserChild)
|
||||
{
|
||||
if (!aTabBrowserChild)
|
||||
return null;
|
||||
|
||||
if (aTabBrowserChild.localName == 'tabbrowser') // itself
|
||||
return aTabBrowserChild;
|
||||
|
||||
if (aTabBrowserChild.tabbrowser) // tabs, Firefox 4.0 or later
|
||||
return aTabBrowserChild.tabbrowser;
|
||||
|
||||
if (aTabBrowserChild.id == 'TabsToolbar') // tabs toolbar, Firefox 4.0 or later
|
||||
return aTabBrowserChild.getElementsByTagName('tabs')[0].tabbrowser;
|
||||
|
||||
var b = aTabBrowserChild.ownerDocument.evaluate(
|
||||
'ancestor-or-self::*[local-name()="tabbrowser"] | '+
|
||||
'ancestor-or-self::*[local-name()="tabs" and @tabbrowser]',
|
||||
aTabBrowserChild,
|
||||
XPathResult.FIRST_ORDERED_NODE_TYPE
|
||||
).singleNodeValue;
|
||||
return (b && b.tabbrowser) || b;
|
||||
},
|
||||
|
||||
isTabsDragging : function TDU_isTabsDragging(aEvent)
|
||||
{
|
||||
var dt = aEvent.dataTransfer;
|
||||
if (dt.mozItemCount < 1)
|
||||
return false;
|
||||
for (let i = 0, maxi = dt.mozItemCount; i < maxi; i++)
|
||||
{
|
||||
if (Array.slice(dt.mozTypesAt(i)).indexOf(TAB_DROP_TYPE) < 0)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
getDraggedTabs : function TDU_getDraggedTabs(aEvent)
|
||||
{
|
||||
var dt = aEvent.dataTransfer;
|
||||
var tabs = [];
|
||||
if (dt.mozItemCount < 1 ||
|
||||
Array.slice(dt.mozTypesAt(0)).indexOf(TAB_DROP_TYPE) < 0)
|
||||
return tabs;
|
||||
|
||||
for (let i = 0, maxi = dt.mozItemCount; i < maxi; i++)
|
||||
{
|
||||
tabs.push(dt.mozGetDataAt(TAB_DROP_TYPE, i));
|
||||
}
|
||||
return tabs.sort(function(aA, aB) { return aA._tPos - aB._tPos; });
|
||||
},
|
||||
|
||||
getCurrentURIOfTab : function TDU_getCurrentURIOfTab(aTab)
|
||||
{
|
||||
if (aTab.getAttribute('ontap') == 'true') {
|
||||
// If BarTap ( https://addons.mozilla.org/firefox/addon/67651 ) is installed,
|
||||
// currentURI is possibly 'about:blank'. So, we have to get correct URI
|
||||
// from the attribute or the session histrory.
|
||||
var b = aTab.linkedBrowser;
|
||||
try {
|
||||
if (b.hasAttribute(this.kARGUMENT_URI))
|
||||
return b.getAttribute(this.kARGUMENT_URI);
|
||||
}
|
||||
catch(e) {
|
||||
}
|
||||
try {
|
||||
var h = b.sessionHistory;
|
||||
var entry = h.getEntryAtIndex(h.index, false);
|
||||
return entry.URI.spec;
|
||||
}
|
||||
catch(e) {
|
||||
}
|
||||
}
|
||||
// Firefox 4.0-
|
||||
if (aTab.linkedBrowser.__SS_needsRestore) {
|
||||
let data = aTab.linkedBrowser.__SS_data;
|
||||
let entry = data.entries[Math.max(data.index, data.entries.length-1)];
|
||||
return entry.url;
|
||||
}
|
||||
return aTab.linkedBrowser.currentURI.spec;
|
||||
},
|
||||
_backupArgumentURI : function TDU_backupArgumentURI(aURI, aBrowser)
|
||||
{
|
||||
if (aURI) {
|
||||
var uri = (aURI instanceof Ci.nsIURI) ? aURI.spec : aURI ;
|
||||
aBrowser.setAttribute(this.kARGUMENT_URI, uri);
|
||||
}
|
||||
},
|
||||
kARGUMENT_URI : 'tabs-drag-utils-bartap-uri'
|
||||
};
|
||||
|
||||
window['piro.sakura.ne.jp'].tabsDragUtils = tabsDragUtils;
|
||||
tabsDragUtils.init();
|
||||
})();
|
@ -265,6 +265,7 @@ var TreeStyleTabService = {
|
||||
|
||||
|
||||
|
||||
|
||||
behavior += this.kGROUP_BOOKMARK_USE_DUMMY;
|
||||
if (!this.getTreePref('openGroupBookmarkBehavior.confirm')) {
|
||||
behavior += (
|
||||
@ -425,9 +426,6 @@ var TreeStyleTabService = {
|
||||
/\.screenX/g, '[TreeStyleTabService.getTabBrowserFromChild(TSTTabBrowser).treeStyleTab.positionProp]'
|
||||
).replace(
|
||||
/\.width/g, '[TreeStyleTabService.getTabBrowserFromChild(TSTTabBrowser).treeStyleTab.sizeProp]'
|
||||
).replace(
|
||||
'dt.mozItemCount > 1',
|
||||
'$& && !TreeStyleTabService.isTabsDragging(arguments[0])'
|
||||
).replace(
|
||||
/(return (?:true|dt.effectAllowed = "copyMove");)/,
|
||||
<![CDATA[
|
||||
@ -480,6 +478,7 @@ var TreeStyleTabService = {
|
||||
).replace(
|
||||
'document.getBindingParent(aEvent.originalTarget).localName != "tab"',
|
||||
'!TreeStyleTabService.getTabFromEvent(aEvent)'
|
||||
|
||||
).replace(
|
||||
'var tab = aEvent.target;',
|
||||
<![CDATA[$&
|
||||
@ -567,17 +566,6 @@ catch(e) {
|
||||
}
|
||||
},
|
||||
|
||||
isTabsDragging : function TSTService_isTabsDragging(aEvent)
|
||||
{
|
||||
var dt = aEvent.dataTransfer;
|
||||
for (let i = 0, maxi = dt.mozItemCount; i < maxi; i++)
|
||||
{
|
||||
if (Array.slice(dt.mozTypesAt(i)).indexOf(TAB_DROP_TYPE) < 0)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
onTabDragStart : function TSTService_onTabDragStart(aEvent)
|
||||
{
|
||||
var b = this.getTabBrowserFromChild(aEvent.currentTarget);
|
||||
@ -589,51 +577,14 @@ catch(e) {
|
||||
return;
|
||||
|
||||
var actionInfo = {
|
||||
action : this.kACTIONS_FOR_SOURCE,
|
||||
action : this.kACTIONS_FOR_DESTINATION | this.kACTION_MOVE,
|
||||
event : aEvent
|
||||
};
|
||||
var tabsInfo = b.treeStyleTab.getDraggedTabsInfoFromOneTab(actionInfo, tab);
|
||||
if (tabsInfo.draggedTabs.length <= 1)
|
||||
return;
|
||||
|
||||
var index = tabsInfo.draggedTabs.indexOf(tab);
|
||||
if (index > -1) {
|
||||
tabsInfo.draggedTabs.splice(index, 1);
|
||||
tabsInfo.draggedTabs.unshift(tab);
|
||||
}
|
||||
|
||||
if ('MultipleTabService' in window &&
|
||||
'setUpTabsDragData' in MultipleTabService) {
|
||||
MultipleTabService.setUpTabsDragData(aEvent, tabsInfo.draggedTabs);
|
||||
}
|
||||
else {
|
||||
let dt = aEvent.dataTransfer;
|
||||
tabsInfo.draggedTabs.forEach(function(aTab, aIndex) {
|
||||
dt.mozSetDataAt(TAB_DROP_TYPE, aTab, aIndex);
|
||||
dt.mozSetDataAt('text/x-moz-text-internal', this.getCurrentURIOfTab(aTab), aIndex);
|
||||
}, this);
|
||||
}
|
||||
},
|
||||
getCurrentURIOfTab : function TSTService_getCurrentURIOfTab(aTab)
|
||||
{
|
||||
if (aTab.getAttribute('ontap') == 'true') {
|
||||
// If BarTap ( https://addons.mozilla.org/firefox/addon/67651 ) is installed,
|
||||
// currentURI is possibly 'about:blank'. So, we have to get correct URI
|
||||
// from the session histrory.
|
||||
var b = aTab.linkedBrowser;
|
||||
try {
|
||||
var h = b.sessionHistory;
|
||||
var entry = h.getEntryAtIndex(h.index, false);
|
||||
return entry.URI;
|
||||
}
|
||||
catch(e) {
|
||||
}
|
||||
}
|
||||
// Firefox 4.0-
|
||||
if (aTab.linkedBrowser.__SS_needsRestore) {
|
||||
let data = aTab.linkedBrowser.__SS_data;
|
||||
let entry = data.entries[Math.max(data.index, data.entries.length-1)];
|
||||
return this.makeURIFromSpec(entry.url);
|
||||
}
|
||||
return aTab.linkedBrowser.currentURI;
|
||||
window['piro.sakura.ne.jp'].tabsDragUtils.startTabsDrag(aEvent, tabsInfo.draggedTabs);
|
||||
},
|
||||
|
||||
onTabbarDragStart : function TSTService_onTabbarDragStart(aEvent, aTabBrowser)
|
||||
|
@ -8,6 +8,7 @@
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
|
||||
<script src="res/stopRendering.js" type="application/javascript"/>
|
||||
<script src="res/tabsDragUtils.js" type="application/javascript"/>
|
||||
<script src="res/UninstallationListener.js" type="application/javascript"/>
|
||||
|
||||
<script src="treestyletab.js" type="application/javascript"/>
|
||||
|
@ -350,6 +350,8 @@ TreeStyleTabBrowser.prototype = {
|
||||
b.addEventListener('MultipleTabHandlerTabsClosing', this, false);
|
||||
|
||||
|
||||
window['piro.sakura.ne.jp'].tabsDragUtils.initTabBrowser(b);
|
||||
|
||||
|
||||
/* Closing collapsed last tree breaks selected tab.
|
||||
To solve this problem, I override the setter to
|
||||
@ -1641,6 +1643,8 @@ TreeStyleTabBrowser.prototype = {
|
||||
|
||||
b.removeEventListener('MultipleTabHandlerTabsClosing', this, false);
|
||||
|
||||
window['piro.sakura.ne.jp'].tabsDragUtils.destroyTabBrowser(b);
|
||||
|
||||
TreeStyleTabService.destroyTabDNDObserver(b);
|
||||
|
||||
this.tabbarDNDObserver.destroy();
|
||||
@ -3718,12 +3722,7 @@ TreeStyleTabBrowser.prototype = {
|
||||
var sourceBrowser = this.getTabBrowserFromChild(aTab);
|
||||
|
||||
var dt = aInfo.event && aInfo.event.dataTransfer;
|
||||
var isMultipleDragEvent = (
|
||||
dt &&
|
||||
dt.mozItemCount > 1 &&
|
||||
Array.slice(dt.mozTypesAt(0)).indexOf(TAB_DROP_TYPE) > -1
|
||||
);
|
||||
|
||||
var isMultipleDragEvent = window['piro.sakura.ne.jp'].tabsDragUtils.isTabsDragging(aInfo.event);
|
||||
var isMultipleMove = (
|
||||
isMultipleDragEvent ||
|
||||
(
|
||||
@ -3735,7 +3734,7 @@ TreeStyleTabBrowser.prototype = {
|
||||
|
||||
if (isMultipleMove) {
|
||||
draggedTabs = isMultipleDragEvent ?
|
||||
this.getTabsFromDragEvent(aInfo.event) :
|
||||
window['piro.sakura.ne.jp'].tabsDragUtils.getDraggedTabs(aInfo.event) :
|
||||
sourceWindow.MultipleTabService.getSelectedTabs(sourceBrowser);
|
||||
if (!(aInfo.action & this.kACTIONS_FOR_DESTINATION)) {
|
||||
draggedRoots = [];
|
||||
@ -3765,17 +3764,6 @@ TreeStyleTabBrowser.prototype = {
|
||||
};
|
||||
},
|
||||
|
||||
getTabsFromDragEvent : function TSTBrowser_getTabsFromDragEvent(aEvent)
|
||||
{
|
||||
var tabs = [];
|
||||
var dt = aEvent.dataTransfer;
|
||||
for (let i = 0, maxi = dt.mozItemCount; i < maxi; i++)
|
||||
{
|
||||
tabs.push(dt.mozGetDataAt(TAB_DROP_TYPE, i));
|
||||
}
|
||||
return tabs.sort(this.sortTabsByOrder);
|
||||
},
|
||||
|
||||
attachTabsOnDrop : function TSTBrowser_attachTabsOnDrop(aTabs, aParent)
|
||||
{
|
||||
this.mTabBrowser.movingSelectedTabs = true; // Multiple Tab Handler
|
||||
|
Loading…
Reference in New Issue
Block a user