UNPKG

angular-drag-scroll

Version:

Lightweight drag to scroll directive for AngularJS

183 lines (152 loc) 6.98 kB
(function () { 'use strict'; angular .module('ng-drag-scroll', []) .directive('dragScroll', DragScroll); DragScroll.$inject = ['$document', '$window', '$parse']; /* @ngInject */ function DragScroll($document, $window, $parse) { //Usage: //<div drag-scroll>Lorem ipsum dolor sit amet</div> var directive = { restrict: 'A', link: function($scope, $element, $attributes, vm) { var enabled = true; var allowedClickOffset = 5; var pushed = false; var onDragStart = $parse($attributes.onDragStart); var onDragEnd = $parse($attributes.onDragEnd); var axis = $attributes.axis || false; var excludedClasses = $attributes.dragScrollExcludedClasses ? $attributes.dragScrollExcludedClasses.split(',') : []; var startClientX; var startClientY; var lastClientX; var lastClientY; $scope.$watch($attributes.dragScroll, function(newValue) { enabled = newValue !== undefined ? newValue : true; }); // Set event listeners $element.on('mousedown', handleMouseDown); // Set destroy listener $scope.$on('$destroy', destroy); /** * Sets the event listeners for the mouseup and mousedown events */ function setDragListeners () { angular.element($window).on('mouseup', handleMouseUp); angular.element($window).on('mousemove', handleMouseMove); } /** * Removes the event listeners for the mouseup and mousedown events */ function removeDragListeners () { angular.element($window).off('mouseup', handleMouseUp); angular.element($window).off('mousemove', handleMouseMove); } /** * Handles mousedown event * @param {object} e MouseDown event */ function handleMouseDown (e) { if(enabled){ for (var i= 0; i<excludedClasses.length; i++) { if (angular.element(e.target).hasClass(excludedClasses[i])) { return false; } } $scope.$apply(function() { onDragStart($scope); }); // Set mouse drag listeners setDragListeners(); // Set 'pushed' state pushed = true; lastClientX = startClientX = e.clientX; lastClientY = startClientY = e.clientY; clearSelection(); e.preventDefault(); e.stopPropagation(); } } /** * Handles mouseup event * @param {object} e MouseUp event */ function handleMouseUp (e) { if(enabled){ var selectable = (e.target.attributes && 'drag-scroll-text' in e.target.attributes); var withinXConstraints = (e.clientX >= (startClientX - allowedClickOffset) && e.clientX <= (startClientX + allowedClickOffset)); var withinYConstraints = (e.clientY >= (startClientY - allowedClickOffset) && e.clientY <= (startClientY + allowedClickOffset)); // Set 'pushed' state pushed = false; // Check if cursor falls within X and Y axis constraints if(selectable && withinXConstraints && withinYConstraints) { // If so, select the text inside the target element selectText(e.target); } $scope.$apply(function() { onDragEnd($scope); }); removeDragListeners(); } } /** * Handles mousemove event * @param {object} e MouseMove event */ function handleMouseMove (e) { if(enabled){ if (pushed) { if(!axis || axis === 'x') { $element[0].scrollLeft -= (-lastClientX + (lastClientX = e.clientX)); } if(!axis || axis === 'y') { $element[0].scrollTop -= (-lastClientY + (lastClientY = e.clientY)); } } e.preventDefault(); } } /** * Destroys all the event listeners */ function destroy () { $element.off('mousedown', handleMouseDown); angular.element($window).off('mouseup', handleMouseUp); angular.element($window).off('mousemove', handleMouseMove); } /** * Selects text for a specific element * @param {object} element Selected element */ function selectText (element) { var range; if ($window.document.selection) { range = $window.document.body.createTextRange(); range.moveToElementText(element); range.select(); } else if ($window.getSelection) { range = $window.document.createRange(); range.selectNode(element); $window.getSelection().addRange(range); } } /** * Clears text selection */ function clearSelection () { if ($window.getSelection) { if ($window.getSelection().empty) { // Chrome $window.getSelection().empty(); } else if ($window.getSelection().removeAllRanges) { // Firefox $window.getSelection().removeAllRanges(); } } else if ($document.selection) { // IE? $document.selection.empty(); } } } }; return directive; } })();