From 4d19cd75c6c763dc5039436f73d1fa02c0e0fad3 Mon Sep 17 00:00:00 2001 From: Piro / YUKI Hiroshi Date: Sat, 13 Oct 2012 00:37:03 +0900 Subject: [PATCH] Process animation effect for dragged tabs correctly --- content/treestyletab/res/tabsDragUtils.js | 30 +++++++++++------------ modules/base.js | 29 ++++++++++++++++++++++ modules/tabbarDNDObserver.js | 28 +++++++++++++++------ 3 files changed, 64 insertions(+), 23 deletions(-) diff --git a/content/treestyletab/res/tabsDragUtils.js b/content/treestyletab/res/tabsDragUtils.js index d0bfa367..fc940baf 100644 --- a/content/treestyletab/res/tabsDragUtils.js +++ b/content/treestyletab/res/tabsDragUtils.js @@ -15,7 +15,7 @@ http://github.com/piroor/fxaddonlibs/blob/master/tabsDragUtils.js */ (function() { - const currentRevision = 20; + const currentRevision = 21; if (!('piro.sakura.ne.jp' in window)) window['piro.sakura.ne.jp'] = {}; @@ -159,17 +159,17 @@ ).replace( /(let tabCenter = [^;]+)\/ 2;/, '$1 / units/*2*/;\n' + // support drop on self - 'let firstTabCenter = tabCenter;\n' + - 'let lastTabCenter = tabScreenX + translateX + tabsWidth - tabWidth / units;' + 'let tabLeftCenter = tabCenter;\n' + + 'let tabRightCenter = tabScreenX + translateX + tabsWidth - tabWidth / units;' ).replace( 'tabs[mid] == draggedTab', '/* $& */ false' ).replace( '(screenX > tabCenter)', - '/* $& */ (screenX > lastTabCenter + (aAcceptDropOnSelf ? tabWidth / units : 0 ))' + '/* $& */ (screenX > tabRightCenter)' ).replace( '(screenX + boxObject[size] < tabCenter)', - '/* $& */ (screenX + boxObject[size] < firstTabCenter)' + '/* $& */ (screenX + boxObject[size] < tabLeftCenter)' ).replace( '-tabWidth : tabWidth', '/* $& */ -tabsWidth : tabsWidth' @@ -271,8 +271,8 @@ // tab.style.transform = draggedTab.style.transform; // }, this); // let tabCenter = tabScreenX + translateX + tabWidth / units/*2*/; -// let firstTabCenter = tabCenter; -// let lastTabCenter = tabScreenX + translateX + tabsWidth - tabWidth / units; +// let tabLeftCenter = tabCenter; +// let tabRightCenter = tabScreenX + translateX + tabsWidth - tabWidth / units; // let newIndex = -1; // let oldIndex = "animDropIndex" in draggedTab._dragData ? // draggedTab._dragData.animDropIndex : draggedTab._tPos; @@ -287,10 +287,10 @@ // let boxObject = tabs[mid].boxObject; // let screenX = boxObject[position]/*.screenX*/ + getTabShift(tabs[mid], oldIndex); // // if (screenX > tabCenter) { -// if (screenX > lastTabCenter + (aAcceptDropOnSelf ? tabWidth / units : 0 )) { +// if (screenX > tabRightCenter) { // high = mid - 1; // // } else if (screenX + boxObject.width < tabCenter) { -// } else if (screenX + boxObject[size]/*.width*/ < firstTabCenter) { +// } else if (screenX + boxObject[size]/*.width*/ < tabLeftCenter) { // low = mid + 1; // } else { // newIndex = tabs[mid]._tPos; @@ -360,7 +360,7 @@ navigator.platform.toLowerCase().indexOf('win') < 0) dt.mozCursor = 'default'; - if (this.shouldAnimateDragggedTabs(aEvent)) { + if (this.canAnimateDraggedTabs(aEvent)) { let tabbar = this.getTabbarFromEvent(aEvent); let tabbarOffsetX = this.getClientX(tabbar.children[0].pinned ? tabbar.children[0] : tabbar ); let tabbarOffsetY = this.getClientY(tabbar.children[0].pinned ? tabbar.children[0] : tabbar ); @@ -484,25 +484,23 @@ ).singleNodeValue; return (b && b.tabbrowser) || b; }, - shouldAnimateDragggedTabs: function TDU_shouldAnimateDragggedTabs(aEvent) + canAnimateDraggedTabs: function TDU_canAnimateDraggedTabs(aEvent) { var tabbar = this.getTabbarFromEvent(aEvent); return tabbar && '_animateTabMove' in tabbar; }, - processTabsDragging: function TDU_processTabsDragging(aEvent, aWillDropOnSelf) + processTabsDragging: function TDU_processTabsDragging(aEvent, aCanDropOnSelf) { // Firefox 17 and later - if (this.shouldAnimateDraggedTabs(aEvent)) { + if (this.canAnimateDraggedTabs(aEvent)) { let tabbar = this.getTabbarFromEvent(aEvent); let draggedTab = aEvent.dataTransfer && aEvent.dataTransfer.mozGetDataAt(TAB_DROP_TYPE, 0); if (!draggedTab || draggedTab.ownerDocument != tabbar.ownerDocument) return false; if (!tabbar.hasAttribute('movingtab')) tabbar.setAttribute('movingtab', 'true'); - if (!aWillDropOnSelf) { - tabbar._animateTabMove(aEvent); - } + tabbar._animateTabMove(aEvent, aCanDropOnSelf); return true; } return false; diff --git a/modules/base.js b/modules/base.js index 8cedccf9..f15ead71 100644 --- a/modules/base.js +++ b/modules/base.js @@ -2423,6 +2423,35 @@ var TreeStyleTabBase = { screenY : tabBox.screenY + yOffset }; }, + getTabActualScreenPosition : function TSTUtils_getTabActualScreenPosition(aTab) + { + return aTab.parentNode.orient == 'vertical' ? + this.getTabActualScreenY(aTab) : + this.getTabActualScreenX(aTab) ; + }, + MATRIX_PATTERN : /matrix\((-?\d+),\s*(-?\d+),\s*(-?\d+),\s*(-?\d+),\s*(-?\d+),\s*(-?\d+)\)/, + getTabActualScreenX : function TSTUtils_getTabActualScreenX(aTab) + { + var x = aTab.boxObject.screenX; + + var w = aTab.ownerDocument.defaultView; + var transform = w.getComputedStyle(aTab, null).transform; + var offset = transform.match(this.MATRIX_PATTERN); + offset = offset ? parseFloat(offset[5]) : 0 ; + + return x + offset; + }, + getTabActualScreenY : function TSTUtils_getTabActualScreenY(aTab) + { + var y = aTab.boxObject.screenY; + + var w = aTab.ownerDocument.defaultView; + var transform = w.getComputedStyle(aTab, null).transform; + var offset = transform.match(this.MATRIX_PATTERN); + offset = offset ? parseFloat(offset[6]) : 0 ; + + return y + offset; + }, isGroupTab : function TSTUtils_isGroupTab(aTab, aLazyCheck) { diff --git a/modules/tabbarDNDObserver.js b/modules/tabbarDNDObserver.js index 543bb17d..d45bd560 100644 --- a/modules/tabbarDNDObserver.js +++ b/modules/tabbarDNDObserver.js @@ -270,14 +270,14 @@ catch(e) { if (DEBUG) dump(' not on a tab\n'); let action = isTabMoveFromOtherWindow ? sv.kACTION_STAY : (sv.kACTION_MOVE | sv.kACTION_PART) ; if (isNewTabAction) action |= sv.kACTION_NEWTAB; - if (aEvent[sv.screenPositionProp] < firstTab.boxObject[sv.screenPositionProp]) { + if (aEvent[sv.screenPositionProp] < sv.getTabActualScreenPosition(firstTab)) { if (DEBUG) dump(' above the first tab\n'); info.target = info.parent = info.insertBefore = firstTab; info.position = isInverted ? sv.kDROP_AFTER : sv.kDROP_BEFORE ; info.action = action; return info; } - else if (aEvent[sv.screenPositionProp] > tabs[lastTabIndex].boxObject[sv.screenPositionProp] + tabs[lastTabIndex].boxObject[sv.sizeProp]) { + else if (aEvent[sv.screenPositionProp] > sv.getTabActualScreenPosition(tabs[lastTabIndex]) + tabs[lastTabIndex].boxObject[sv.sizeProp]) { if (DEBUG) dump(' below the last tab\n'); info.target = info.parent = tabs[lastTabIndex]; info.position = isInverted ? sv.kDROP_BEFORE : sv.kDROP_AFTER ; @@ -309,7 +309,7 @@ catch(e) { var dropAreasCount = (aSourceTab && pinned) ? 2 : 3 ; var screenPositionProp = sv.isVertical && pinned ? sv.invertedScreenPositionProp : sv.screenPositionProp ; var sizeProp = sv.isVertical && pinned ? sv.invertedSizeProp : sv.sizeProp ; - var boxPos = tab.boxObject[screenPositionProp]; + var boxPos = sv.getTabActualScreenPosition(tab); var boxUnit = Math.round(tab.boxObject[sizeProp] / dropAreasCount); if (aEvent[screenPositionProp] < boxPos + boxUnit) { info.position = isInverted ? sv.kDROP_AFTER : sv.kDROP_BEFORE ; @@ -839,6 +839,15 @@ try{ sv.autoScroll.processAutoScroll(aEvent); + var dragOverTab = sv.getTabFromEvent(aEvent) || sv.getTabFromTabbarEvent(aEvent) || aEvent.target; + b.ownerDocument.defaultView['piro.sakura.ne.jp'].tabsDragUtils + .processTabsDragging(aEvent, !dragOverTab || !dragOverTab.pinned); + + /** + * We must calculate drop action after tabsDragUtils.processTabsDragging(), + * because the drop position depends on tabs' actual + * positions (which can be changed by animation effects.) + */ var info = this.getDropAction(aEvent, session); var observer = b; @@ -894,7 +903,7 @@ try{ this.clearDropPosition(); indicatorTab.setAttribute(sv.kDROP_POSITION, dropPosition); if (b.ownerDocument.defaultView['piro.sakura.ne.jp'].tabsDragUtils - .processTabsDragging(aEvent, dropPosition == 'self')) { // Firefox 17 and later + .canAnimateDraggedTabs(aEvent)) { // Firefox 17 and later if (dropPosition == 'self') { draggedTab.style.opacity = 0.5; // to prevent the dragged tab hides the drop target itself } else { @@ -944,13 +953,18 @@ catch(e) { var tabbar = b.mTabContainer; var dt = aEvent.dataTransfer; + /** + * We must calculate drop action before clearing "dragging" + * state, because the drop position depends on tabs' actual + * positions (they are applied only while tab dragging.) + */ + var session = sv.currentDragSession; + var dropActionInfo = this.getDropAction(aEvent, session); + this.clearDropPosition(true); if (tabbar._tabDropIndicator) tabbar._tabDropIndicator.collapsed = true; - var session = sv.currentDragSession; - var dropActionInfo = this.getDropAction(aEvent, session); - var draggedTab; if (dt.dropEffect != 'link') { draggedTab = dt.mozGetDataAt(TAB_DROP_TYPE, 0);