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
*/
(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;

View File

@ -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)
{

View File

@ -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);