From 2932d89da78de72496fb7b87d92303b7781e04ac Mon Sep 17 00:00:00 2001 From: SHIMODA Hiroshi Date: Tue, 30 Nov 2010 12:23:08 +0900 Subject: [PATCH] support drag feedback image and multiple drag data for dragging of trees --- content/treestyletab/res/tabsDragUtils.js | 244 ++++++++++++++++++++ content/treestyletab/treestyletab.js | 61 +---- content/treestyletab/treestyletab.xul | 1 + content/treestyletab/treestyletabbrowser.js | 24 +- 4 files changed, 257 insertions(+), 73 deletions(-) create mode 100644 content/treestyletab/res/tabsDragUtils.js diff --git a/content/treestyletab/res/tabsDragUtils.js b/content/treestyletab/res/tabsDragUtils.js new file mode 100644 index 00000000..ca7ed309 --- /dev/null +++ b/content/treestyletab/res/tabsDragUtils.js @@ -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(); +})(); diff --git a/content/treestyletab/treestyletab.js b/content/treestyletab/treestyletab.js index 358cfc0a..1f06f7c8 100644 --- a/content/treestyletab/treestyletab.js +++ b/content/treestyletab/treestyletab.js @@ -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");)/, -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) diff --git a/content/treestyletab/treestyletab.xul b/content/treestyletab/treestyletab.xul index f2f366e2..7692d152 100644 --- a/content/treestyletab/treestyletab.xul +++ b/content/treestyletab/treestyletab.xul @@ -8,6 +8,7 @@ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">