ui-select
Version:
149 lines (118 loc) • 4.5 kB
JavaScript
// Make multiple matches sortable
uis.directive('uiSelectSort', ['$timeout', 'uiSelectConfig', 'uiSelectMinErr', function($timeout, uiSelectConfig, uiSelectMinErr) {
return {
require: ['^^uiSelect', '^ngModel'],
link: function(scope, element, attrs, ctrls) {
if (scope[attrs.uiSelectSort] === null) {
throw uiSelectMinErr('sort', 'Expected a list to sort');
}
var $select = ctrls[0];
var $ngModel = ctrls[1];
var options = angular.extend({
axis: 'horizontal'
},
scope.$eval(attrs.uiSelectSortOptions));
var axis = options.axis;
var draggingClassName = 'dragging';
var droppingClassName = 'dropping';
var droppingBeforeClassName = 'dropping-before';
var droppingAfterClassName = 'dropping-after';
scope.$watch(function(){
return $select.sortable;
}, function(newValue){
if (newValue) {
element.attr('draggable', true);
} else {
element.removeAttr('draggable');
}
});
element.on('dragstart', function(event) {
element.addClass(draggingClassName);
(event.dataTransfer || event.originalEvent.dataTransfer).setData('text', scope.$index.toString());
});
element.on('dragend', function() {
removeClass(draggingClassName);
});
var move = function(from, to) {
/*jshint validthis: true */
this.splice(to, 0, this.splice(from, 1)[0]);
};
var removeClass = function(className) {
angular.forEach($select.$element.querySelectorAll('.' + className), function(el){
angular.element(el).removeClass(className);
});
};
var dragOverHandler = function(event) {
event.preventDefault();
var offset = axis === 'vertical' ? event.offsetY || event.layerY || (event.originalEvent ? event.originalEvent.offsetY : 0) : event.offsetX || event.layerX || (event.originalEvent ? event.originalEvent.offsetX : 0);
if (offset < (this[axis === 'vertical' ? 'offsetHeight' : 'offsetWidth'] / 2)) {
removeClass(droppingAfterClassName);
element.addClass(droppingBeforeClassName);
} else {
removeClass(droppingBeforeClassName);
element.addClass(droppingAfterClassName);
}
};
var dropTimeout;
var dropHandler = function(event) {
event.preventDefault();
var droppedItemIndex = parseInt((event.dataTransfer || event.originalEvent.dataTransfer).getData('text'), 10);
// prevent event firing multiple times in firefox
$timeout.cancel(dropTimeout);
dropTimeout = $timeout(function() {
_dropHandler(droppedItemIndex);
}, 20);
};
var _dropHandler = function(droppedItemIndex) {
var theList = scope.$eval(attrs.uiSelectSort);
var itemToMove = theList[droppedItemIndex];
var newIndex = null;
if (element.hasClass(droppingBeforeClassName)) {
if (droppedItemIndex < scope.$index) {
newIndex = scope.$index - 1;
} else {
newIndex = scope.$index;
}
} else {
if (droppedItemIndex < scope.$index) {
newIndex = scope.$index;
} else {
newIndex = scope.$index + 1;
}
}
move.apply(theList, [droppedItemIndex, newIndex]);
$ngModel.$setViewValue(Date.now());
scope.$apply(function() {
scope.$emit('uiSelectSort:change', {
array: theList,
item: itemToMove,
from: droppedItemIndex,
to: newIndex
});
});
removeClass(droppingClassName);
removeClass(droppingBeforeClassName);
removeClass(droppingAfterClassName);
element.off('drop', dropHandler);
};
element.on('dragenter', function() {
if (element.hasClass(draggingClassName)) {
return;
}
element.addClass(droppingClassName);
element.on('dragover', dragOverHandler);
element.on('drop', dropHandler);
});
element.on('dragleave', function(event) {
if (event.target != element) {
return;
}
removeClass(droppingClassName);
removeClass(droppingBeforeClassName);
removeClass(droppingAfterClassName);
element.off('dragover', dragOverHandler);
element.off('drop', dropHandler);
});
}
};
}]);