Process animation effect for dragged tabs correctly

This commit is contained in:
Piro / YUKI Hiroshi 2012-10-13 00:37:03 +09:00
parent f090ce14b1
commit 4d19cd75c6
3 changed files with 64 additions and 23 deletions

View File

@ -15,7 +15,7 @@
http://github.com/piroor/fxaddonlibs/blob/master/tabsDragUtils.js http://github.com/piroor/fxaddonlibs/blob/master/tabsDragUtils.js
*/ */
(function() { (function() {
const currentRevision = 20; const currentRevision = 21;
if (!('piro.sakura.ne.jp' in window)) window['piro.sakura.ne.jp'] = {}; if (!('piro.sakura.ne.jp' in window)) window['piro.sakura.ne.jp'] = {};
@ -159,17 +159,17 @@
).replace( ).replace(
/(let tabCenter = [^;]+)\/ 2;/, /(let tabCenter = [^;]+)\/ 2;/,
'$1 / units/*2*/;\n' + // support drop on self '$1 / units/*2*/;\n' + // support drop on self
'let firstTabCenter = tabCenter;\n' + 'let tabLeftCenter = tabCenter;\n' +
'let lastTabCenter = tabScreenX + translateX + tabsWidth - tabWidth / units;' 'let tabRightCenter = tabScreenX + translateX + tabsWidth - tabWidth / units;'
).replace( ).replace(
'tabs[mid] == draggedTab', 'tabs[mid] == draggedTab',
'/* $& */ false' '/* $& */ false'
).replace( ).replace(
'(screenX > tabCenter)', '(screenX > tabCenter)',
'/* $& */ (screenX > lastTabCenter + (aAcceptDropOnSelf ? tabWidth / units : 0 ))' '/* $& */ (screenX > tabRightCenter)'
).replace( ).replace(
'(screenX + boxObject[size] < tabCenter)', '(screenX + boxObject[size] < tabCenter)',
'/* $& */ (screenX + boxObject[size] < firstTabCenter)' '/* $& */ (screenX + boxObject[size] < tabLeftCenter)'
).replace( ).replace(
'-tabWidth : tabWidth', '-tabWidth : tabWidth',
'/* $& */ -tabsWidth : tabsWidth' '/* $& */ -tabsWidth : tabsWidth'
@ -271,8 +271,8 @@
// tab.style.transform = draggedTab.style.transform; // tab.style.transform = draggedTab.style.transform;
// }, this); // }, this);
// let tabCenter = tabScreenX + translateX + tabWidth / units/*2*/; // let tabCenter = tabScreenX + translateX + tabWidth / units/*2*/;
// let firstTabCenter = tabCenter; // let tabLeftCenter = tabCenter;
// let lastTabCenter = tabScreenX + translateX + tabsWidth - tabWidth / units; // let tabRightCenter = tabScreenX + translateX + tabsWidth - tabWidth / units;
// let newIndex = -1; // let newIndex = -1;
// let oldIndex = "animDropIndex" in draggedTab._dragData ? // let oldIndex = "animDropIndex" in draggedTab._dragData ?
// draggedTab._dragData.animDropIndex : draggedTab._tPos; // draggedTab._dragData.animDropIndex : draggedTab._tPos;
@ -287,10 +287,10 @@
// let boxObject = tabs[mid].boxObject; // let boxObject = tabs[mid].boxObject;
// let screenX = boxObject[position]/*.screenX*/ + getTabShift(tabs[mid], oldIndex); // let screenX = boxObject[position]/*.screenX*/ + getTabShift(tabs[mid], oldIndex);
// // if (screenX > tabCenter) { // // if (screenX > tabCenter) {
// if (screenX > lastTabCenter + (aAcceptDropOnSelf ? tabWidth / units : 0 )) { // if (screenX > tabRightCenter) {
// high = mid - 1; // high = mid - 1;
// // } else if (screenX + boxObject.width < tabCenter) { // // } else if (screenX + boxObject.width < tabCenter) {
// } else if (screenX + boxObject[size]/*.width*/ < firstTabCenter) { // } else if (screenX + boxObject[size]/*.width*/ < tabLeftCenter) {
// low = mid + 1; // low = mid + 1;
// } else { // } else {
// newIndex = tabs[mid]._tPos; // newIndex = tabs[mid]._tPos;
@ -360,7 +360,7 @@
navigator.platform.toLowerCase().indexOf('win') < 0) navigator.platform.toLowerCase().indexOf('win') < 0)
dt.mozCursor = 'default'; dt.mozCursor = 'default';
if (this.shouldAnimateDragggedTabs(aEvent)) { if (this.canAnimateDraggedTabs(aEvent)) {
let tabbar = this.getTabbarFromEvent(aEvent); let tabbar = this.getTabbarFromEvent(aEvent);
let tabbarOffsetX = this.getClientX(tabbar.children[0].pinned ? tabbar.children[0] : tabbar ); let tabbarOffsetX = this.getClientX(tabbar.children[0].pinned ? tabbar.children[0] : tabbar );
let tabbarOffsetY = this.getClientY(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; ).singleNodeValue;
return (b && b.tabbrowser) || b; return (b && b.tabbrowser) || b;
}, },
shouldAnimateDragggedTabs: function TDU_shouldAnimateDragggedTabs(aEvent) canAnimateDraggedTabs: function TDU_canAnimateDraggedTabs(aEvent)
{ {
var tabbar = this.getTabbarFromEvent(aEvent); var tabbar = this.getTabbarFromEvent(aEvent);
return tabbar && '_animateTabMove' in tabbar; return tabbar && '_animateTabMove' in tabbar;
}, },
processTabsDragging: function TDU_processTabsDragging(aEvent, aWillDropOnSelf) processTabsDragging: function TDU_processTabsDragging(aEvent, aCanDropOnSelf)
{ {
// Firefox 17 and later // Firefox 17 and later
if (this.shouldAnimateDraggedTabs(aEvent)) { if (this.canAnimateDraggedTabs(aEvent)) {
let tabbar = this.getTabbarFromEvent(aEvent); let tabbar = this.getTabbarFromEvent(aEvent);
let draggedTab = aEvent.dataTransfer && aEvent.dataTransfer.mozGetDataAt(TAB_DROP_TYPE, 0); let draggedTab = aEvent.dataTransfer && aEvent.dataTransfer.mozGetDataAt(TAB_DROP_TYPE, 0);
if (!draggedTab || draggedTab.ownerDocument != tabbar.ownerDocument) return false; if (!draggedTab || draggedTab.ownerDocument != tabbar.ownerDocument) return false;
if (!tabbar.hasAttribute('movingtab')) if (!tabbar.hasAttribute('movingtab'))
tabbar.setAttribute('movingtab', 'true'); tabbar.setAttribute('movingtab', 'true');
if (!aWillDropOnSelf) { tabbar._animateTabMove(aEvent, aCanDropOnSelf);
tabbar._animateTabMove(aEvent);
}
return true; return true;
} }
return false; return false;

View File

@ -2423,6 +2423,35 @@ var TreeStyleTabBase = {
screenY : tabBox.screenY + yOffset 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) isGroupTab : function TSTUtils_isGroupTab(aTab, aLazyCheck)
{ {

View File

@ -270,14 +270,14 @@ catch(e) {
if (DEBUG) dump(' not on a tab\n'); if (DEBUG) dump(' not on a tab\n');
let action = isTabMoveFromOtherWindow ? sv.kACTION_STAY : (sv.kACTION_MOVE | sv.kACTION_PART) ; let action = isTabMoveFromOtherWindow ? sv.kACTION_STAY : (sv.kACTION_MOVE | sv.kACTION_PART) ;
if (isNewTabAction) action |= sv.kACTION_NEWTAB; 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'); if (DEBUG) dump(' above the first tab\n');
info.target = info.parent = info.insertBefore = firstTab; info.target = info.parent = info.insertBefore = firstTab;
info.position = isInverted ? sv.kDROP_AFTER : sv.kDROP_BEFORE ; info.position = isInverted ? sv.kDROP_AFTER : sv.kDROP_BEFORE ;
info.action = action; info.action = action;
return info; 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'); if (DEBUG) dump(' below the last tab\n');
info.target = info.parent = tabs[lastTabIndex]; info.target = info.parent = tabs[lastTabIndex];
info.position = isInverted ? sv.kDROP_BEFORE : sv.kDROP_AFTER ; info.position = isInverted ? sv.kDROP_BEFORE : sv.kDROP_AFTER ;
@ -309,7 +309,7 @@ catch(e) {
var dropAreasCount = (aSourceTab && pinned) ? 2 : 3 ; var dropAreasCount = (aSourceTab && pinned) ? 2 : 3 ;
var screenPositionProp = sv.isVertical && pinned ? sv.invertedScreenPositionProp : sv.screenPositionProp ; var screenPositionProp = sv.isVertical && pinned ? sv.invertedScreenPositionProp : sv.screenPositionProp ;
var sizeProp = sv.isVertical && pinned ? sv.invertedSizeProp : sv.sizeProp ; 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); var boxUnit = Math.round(tab.boxObject[sizeProp] / dropAreasCount);
if (aEvent[screenPositionProp] < boxPos + boxUnit) { if (aEvent[screenPositionProp] < boxPos + boxUnit) {
info.position = isInverted ? sv.kDROP_AFTER : sv.kDROP_BEFORE ; info.position = isInverted ? sv.kDROP_AFTER : sv.kDROP_BEFORE ;
@ -839,6 +839,15 @@ try{
sv.autoScroll.processAutoScroll(aEvent); 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 info = this.getDropAction(aEvent, session);
var observer = b; var observer = b;
@ -894,7 +903,7 @@ try{
this.clearDropPosition(); this.clearDropPosition();
indicatorTab.setAttribute(sv.kDROP_POSITION, dropPosition); indicatorTab.setAttribute(sv.kDROP_POSITION, dropPosition);
if (b.ownerDocument.defaultView['piro.sakura.ne.jp'].tabsDragUtils 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') { if (dropPosition == 'self') {
draggedTab.style.opacity = 0.5; // to prevent the dragged tab hides the drop target itself draggedTab.style.opacity = 0.5; // to prevent the dragged tab hides the drop target itself
} else { } else {
@ -944,13 +953,18 @@ catch(e) {
var tabbar = b.mTabContainer; var tabbar = b.mTabContainer;
var dt = aEvent.dataTransfer; 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); this.clearDropPosition(true);
if (tabbar._tabDropIndicator) if (tabbar._tabDropIndicator)
tabbar._tabDropIndicator.collapsed = true; tabbar._tabDropIndicator.collapsed = true;
var session = sv.currentDragSession;
var dropActionInfo = this.getDropAction(aEvent, session);
var draggedTab; var draggedTab;
if (dt.dropEffect != 'link') { if (dt.dropEffect != 'link') {
draggedTab = dt.mozGetDataAt(TAB_DROP_TYPE, 0); draggedTab = dt.mozGetDataAt(TAB_DROP_TYPE, 0);