forked from linagora/openpaas-esn
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2207 in OR/rse from ~SNGODOAN/rse:INBOX-270 to ma…
…ster * commit '2b6df8d348fc918932d808319652b029eeedbb98': INBOX-270 Order list item by date to have stable order when we modifying the list INBOX-270 Drag message/thread to move it to a mailbox INBOX-270 Add method to remove element from list INBOX-270 Add functions to move message/thread to a mailbox INBOX-274 Introduces esn.dragndrop module
- Loading branch information
Showing
19 changed files
with
1,115 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
.esn-drag-tooltip { | ||
transition: top 500ms, left 500ms; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,306 @@ | ||
'use strict'; | ||
|
||
angular.module('esn.dragndrop', ['ng.deviceDetector']) | ||
|
||
.constant('ESN_DRAG_ANIMATION_CLASS', 'esn-drag-tooltip') | ||
.constant('ESN_DRAG_ANIMATION_DURATION', 500) | ||
.constant('ESN_DRAG_DISTANCE_THRESHOLD', 10) | ||
|
||
.factory('esnDragService', function() { | ||
var listeners = {}; | ||
|
||
function addDroppableListener(scopeId, listener) { | ||
listeners[scopeId] = listener; | ||
} | ||
|
||
function removeDroppableListener(scopeId) { | ||
delete listeners[scopeId]; | ||
} | ||
|
||
function onDragStart(data) { | ||
angular.forEach(listeners, function(listener) { | ||
listener.onDragStart(data); | ||
}); | ||
} | ||
|
||
function onDragEnd(data) { | ||
var dropped = false; | ||
|
||
angular.forEach(listeners, function(listener) { | ||
if (listener.onDragEnd(data)) { | ||
dropped = true; | ||
} | ||
}); | ||
|
||
return dropped; | ||
} | ||
|
||
return { | ||
addDroppableListener: addDroppableListener, | ||
removeDroppableListener: removeDroppableListener, | ||
onDragStart: onDragStart, | ||
onDragEnd: onDragEnd | ||
}; | ||
}) | ||
|
||
/** | ||
* | ||
* @example | ||
* <div | ||
* esn-draggable | ||
* esn-drag-message="This message is dragging" | ||
* esn-drag-data="data" | ||
* esn-drag-class="dragging" | ||
* esn-on-drag-start="onDragStart()" | ||
* esn-on-drag-end="onDragEnd($dropped)" | ||
* esn-on-drop-success="onDropSuccess() | ||
* esn-on-drop-failure="onDropFailure()"> | ||
* </div> | ||
*/ | ||
.directive('esnDraggable', function( | ||
$parse, | ||
$document, | ||
$timeout, | ||
deviceDetector, | ||
esnDragService, | ||
ESN_DRAG_ANIMATION_CLASS, | ||
ESN_DRAG_ANIMATION_DURATION, | ||
ESN_DRAG_DISTANCE_THRESHOLD) { | ||
|
||
function link(scope, element, attrs) { | ||
if (deviceDetector.isMobile()) { return; } | ||
|
||
var tooltipElement; | ||
var isDragging = false; | ||
var startX, startY; | ||
var centerX, centerY; | ||
|
||
var esnDragData = $parse(attrs.esnDragData)(scope); | ||
var esnDragClass = attrs.esnDragClass; | ||
var esnOnDragStart = $parse(attrs.esnOnDragStart); | ||
var esnOnDragEnd = $parse(attrs.esnOnDragEnd); | ||
var esnOnDropSuccess = $parse(attrs.esnOnDropSuccess); | ||
var esnOnDropFailure = $parse(attrs.esnOnDropFailure); | ||
|
||
function initTooltip(content) { | ||
tooltipElement = angular.element( | ||
'<div class="tooltip right">' + | ||
'<div class="tooltip-arrow"></div>' + | ||
'<div class="tooltip-inner">' + content + '</div>' + | ||
'</div>'); | ||
|
||
tooltipElement.css('position', 'fixed'); | ||
element.append(tooltipElement); | ||
} | ||
|
||
function setTooltipPosition(top, left) { | ||
tooltipElement.css('top', (top - tooltipElement.height() / 2) + 'px'); | ||
tooltipElement.css('left', left + 'px'); | ||
} | ||
|
||
function showTooltip() { | ||
tooltipElement.css('opacity', 1); | ||
} | ||
|
||
function hideTooltip() { | ||
tooltipElement.css('opacity', 0); | ||
} | ||
|
||
function addDragClass() { | ||
esnDragClass && element.addClass(esnDragClass); | ||
} | ||
|
||
function removeDragClass() { | ||
esnDragClass && element.removeClass(esnDragClass); | ||
} | ||
|
||
function onDragStart(event) { | ||
addDragClass(); | ||
esnOnDragStart(scope); | ||
esnDragService.onDragStart(esnDragData); | ||
|
||
var offset = element.offset(); | ||
|
||
centerX = offset.left + element.width() / 2; | ||
centerY = offset.top + element.height() / 2; | ||
|
||
showTooltip(); | ||
} | ||
|
||
function onDrag(event) { | ||
setTooltipPosition(event.clientY, event.clientX); | ||
} | ||
|
||
function onDragEnd(event) { | ||
removeDragClass(); | ||
|
||
var dropped = esnDragService.onDragEnd({ | ||
onDropSuccess: esnOnDropSuccess.bind(null, scope), | ||
onDropFailure: esnOnDropFailure.bind(null, scope) | ||
}); | ||
|
||
esnOnDragEnd(scope, { $dropped: dropped }); | ||
|
||
if (dropped) { | ||
hideTooltip(); | ||
} else { | ||
tooltipElement.addClass(ESN_DRAG_ANIMATION_CLASS); | ||
setTooltipPosition(centerY, centerX); | ||
|
||
$timeout(function() { | ||
tooltipElement.removeClass(ESN_DRAG_ANIMATION_CLASS); | ||
hideTooltip(); | ||
}, ESN_DRAG_ANIMATION_DURATION, false); | ||
} | ||
|
||
} | ||
|
||
function onMouseMove(event) { | ||
if (isDragging) { | ||
onDrag(event); | ||
} else { | ||
if (Math.abs(event.clientX - startX) > ESN_DRAG_DISTANCE_THRESHOLD || | ||
Math.abs(event.clientY - startY) > ESN_DRAG_DISTANCE_THRESHOLD) { | ||
isDragging = true; | ||
onDragStart(); | ||
onDrag(event); | ||
} | ||
} | ||
} | ||
|
||
function onMouseUp(event) { | ||
if (event.button !== 0) { // right-click | ||
return; | ||
} | ||
|
||
if (isDragging) { | ||
onDragEnd(event); | ||
isDragging = false; | ||
} | ||
|
||
$document.off('mousemove', onMouseMove); | ||
$document.off('mouseup', onMouseUp); | ||
} | ||
|
||
function onMouseDown(event) { | ||
if (event.button !== 0) { // right-click | ||
return; | ||
} | ||
|
||
event.preventDefault(); // to prevent text selection | ||
|
||
isDragging = false; | ||
startX = event.clientX; | ||
startY = event.clientY; | ||
|
||
$document.on('mousemove', onMouseMove); | ||
$document.on('mouseup', onMouseUp); | ||
} | ||
|
||
initTooltip(attrs.esnDragMessage); | ||
hideTooltip(); | ||
|
||
element.attr('draggable', false); // disable native HTML5 drag | ||
element.on('mousedown', onMouseDown); | ||
} | ||
|
||
return { | ||
restrict: 'A', | ||
link: link | ||
}; | ||
}) | ||
|
||
/** | ||
* @example | ||
* <div | ||
* esn-droppable | ||
* esn-droptarget-class="droptarget", | ||
* esn-on-drag-enter="onDragEnter()" | ||
* esn-on-drag-exit="onDragExit()" | ||
* esn-on-drop="onDrop($dragData)", | ||
* esn-is-drop-zone="isDropZone($dragData)"> | ||
* </div> | ||
*/ | ||
.directive('esnDroppable', function( | ||
$parse, | ||
esnDragService, | ||
deviceDetector) { | ||
|
||
function link(scope, element, attrs) { | ||
if (deviceDetector.isMobile()) { return; } | ||
|
||
var $dragData; | ||
var isDropCandidate = false; | ||
var isDropZone = false; | ||
|
||
var esnDroptargetClass = attrs.esnDroptargetClass; | ||
var esnOnDragEnter = $parse(attrs.esnOnDragEnter); | ||
var esnOnDragExit = $parse(attrs.esnOnDragExit); | ||
var esnOnDrop = $parse(attrs.esnOnDrop); | ||
var esnIsDropZone = $parse(attrs.esnIsDropZone); | ||
|
||
function addDroptargetClass() { | ||
esnDroptargetClass && element.addClass(esnDroptargetClass); | ||
} | ||
|
||
function removeDroptargetClass() { | ||
esnDroptargetClass && element.removeClass(esnDroptargetClass); | ||
} | ||
|
||
function onMouseEnter(event) { | ||
addDroptargetClass(); | ||
esnOnDragEnter(scope); | ||
isDropCandidate = true; | ||
} | ||
|
||
function onMouseLeave(event) { | ||
removeDroptargetClass(); | ||
esnOnDragExit(scope); | ||
isDropCandidate = false; | ||
} | ||
|
||
function onDragStart(data) { | ||
$dragData = data; | ||
isDropZone = esnIsDropZone(scope, { $dragData: $dragData }); | ||
|
||
if (isDropZone) { | ||
element.on('mouseenter', onMouseEnter); | ||
element.on('mouseleave', onMouseLeave); | ||
} | ||
} | ||
|
||
function onDragEnd(callbacks) { | ||
if (!isDropZone) { return false; } | ||
|
||
esnOnDragExit(scope); | ||
|
||
element.off('mouseenter', onMouseEnter); | ||
element.off('mouseleave', onMouseLeave); | ||
|
||
if (isDropCandidate) { | ||
isDropCandidate = false; | ||
removeDroptargetClass(); | ||
esnOnDrop(scope, { $dragData: $dragData }) | ||
.then(callbacks.onDropSuccess, callbacks.onDropFailure); | ||
|
||
return true; | ||
} | ||
|
||
return false; | ||
} | ||
|
||
esnDragService.addDroppableListener(scope.$id, { | ||
onDragStart: onDragStart, | ||
onDragEnd: onDragEnd | ||
}); | ||
|
||
scope.$on('$destroy', function() { | ||
esnDragService.removeDroppableListener(scope.$id); | ||
}); | ||
} | ||
|
||
return { | ||
restrict: 'A', | ||
link: link | ||
}; | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
6 changes: 6 additions & 0 deletions
6
modules/linagora.esn.unifiedinbox/frontend/css/modules/listThreads.less
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.