Built motion from commit 943eae279.|1.0.24
[motion.git] / public / bower_components / Sortable / ng-sortable.js
1 /**
2  * @author RubaXa <trash@rubaxa.org>
3  * @licence MIT
4  */
5 (function (factory) {
6         'use strict';
7
8         if (typeof define === 'function' && define.amd) {
9                 define(['angular', './Sortable'], factory);
10         }
11         else if (typeof require === 'function' && typeof exports === 'object' && typeof module === 'object') {
12                 require('angular');
13                 factory(angular, require('./Sortable'));
14                 module.exports = 'ng-sortable';
15         }
16         else if (window.angular && window.Sortable) {
17                 factory(angular, Sortable);
18         }
19 })(function (angular, Sortable) {
20         'use strict';
21
22
23         /**
24          * @typedef   {Object}        ngSortEvent
25          * @property  {*}             model      List item
26          * @property  {Object|Array}  models     List of items
27          * @property  {number}        oldIndex   before sort
28          * @property  {number}        newIndex   after sort
29          */
30
31         var expando = 'Sortable:ng-sortable';
32
33         angular.module('ng-sortable', [])
34                 .constant('ngSortableVersion', '0.4.0')
35                 .constant('ngSortableConfig', {})
36                 .directive('ngSortable', ['$parse', 'ngSortableConfig', function ($parse, ngSortableConfig) {
37                         var removed,
38                                 nextSibling,
39                                 getSourceFactory = function getSourceFactory(el, scope) {
40                                         var ngRepeat = [].filter.call(el.childNodes, function (node) {
41                                                 return (
42                                                                 (node.nodeType === 8) &&
43                                                                 (node.nodeValue.indexOf('ngRepeat:') !== -1)
44                                                         );
45                                         })[0];
46
47                                         if (!ngRepeat) {
48                                                 // Without ng-repeat
49                                                 return function () {
50                                                         return null;
51                                                 };
52                                         }
53
54                                         // tests: http://jsbin.com/kosubutilo/1/edit?js,output
55                                         ngRepeat = ngRepeat.nodeValue.match(/ngRepeat:\s*(?:\(.*?,\s*)?([^\s)]+)[\s)]+in\s+([^\s|]+)/);
56
57                                         var itemsExpr = $parse(ngRepeat[2]);
58
59                                         return function () {
60                                                 return itemsExpr(scope.$parent) || [];
61                                         };
62                                 };
63
64
65                         // Export
66                         return {
67                                 restrict: 'AC',
68                                 scope: { ngSortable: "=?" },
69                                 link: function (scope, $el) {
70                                         var el = $el[0],
71                                                 options = angular.extend(scope.ngSortable || {}, ngSortableConfig),
72                                                 watchers = [],
73                                                 getSource = getSourceFactory(el, scope),
74                                                 sortable
75                                         ;
76
77                                         el[expando] = getSource;
78
79                                         function _emitEvent(/**Event*/evt, /*Mixed*/item) {
80                                                 var name = 'on' + evt.type.charAt(0).toUpperCase() + evt.type.substr(1);
81                                                 var source = getSource();
82
83                                                 /* jshint expr:true */
84                                                 options[name] && options[name]({
85                                                         model: item || source[evt.newIndex],
86                                                         models: source,
87                                                         oldIndex: evt.oldIndex,
88                                                         newIndex: evt.newIndex
89                                                 });
90                                         }
91
92
93                                         function _sync(/**Event*/evt) {
94                                                 var items = getSource();
95
96                                                 if (!items) {
97                                                         // Without ng-repeat
98                                                         return;
99                                                 }
100
101                                                 var oldIndex = evt.oldIndex,
102                                                         newIndex = evt.newIndex;
103
104                                                 if (el !== evt.from) {
105                                                         var prevItems = evt.from[expando]();
106
107                                                         removed = prevItems[oldIndex];
108
109                                                         if (evt.clone) {
110                                                                 removed = angular.copy(removed);
111                                                                 prevItems.splice(Sortable.utils.index(evt.clone), 0, prevItems.splice(oldIndex, 1)[0]);
112                                                                 evt.from.removeChild(evt.clone);
113                                                         }
114                                                         else {
115                                                                 prevItems.splice(oldIndex, 1);
116                                                         }
117
118                                                         items.splice(newIndex, 0, removed);
119
120                                                         evt.from.insertBefore(evt.item, nextSibling); // revert element
121                                                 }
122                                                 else {
123                                                         items.splice(newIndex, 0, items.splice(oldIndex, 1)[0]);
124                                                 }
125
126                                                 scope.$apply();
127                                         }
128
129
130                                         sortable = Sortable.create(el, Object.keys(options).reduce(function (opts, name) {
131                                                 opts[name] = opts[name] || options[name];
132                                                 return opts;
133                                         }, {
134                                                 onStart: function (/**Event*/evt) {
135                                                         nextSibling = evt.item.nextSibling;
136                                                         _emitEvent(evt);
137                                                         scope.$apply();
138                                                 },
139                                                 onEnd: function (/**Event*/evt) {
140                                                         _emitEvent(evt, removed);
141                                                         scope.$apply();
142                                                 },
143                                                 onAdd: function (/**Event*/evt) {
144                                                         _sync(evt);
145                                                         _emitEvent(evt, removed);
146                                                         scope.$apply();
147                                                 },
148                                                 onUpdate: function (/**Event*/evt) {
149                                                         _sync(evt);
150                                                         _emitEvent(evt);
151                                                 },
152                                                 onRemove: function (/**Event*/evt) {
153                                                         _emitEvent(evt, removed);
154                                                 },
155                                                 onSort: function (/**Event*/evt) {
156                                                         _emitEvent(evt);
157                                                 }
158                                         }));
159
160                                         $el.on('$destroy', function () {
161                                                 angular.forEach(watchers, function (/** Function */unwatch) {
162                                                         unwatch();
163                                                 });
164
165                                                 sortable.destroy();
166
167                                                 el[expando] = null;
168                                                 el = null;
169                                                 watchers = null;
170                                                 sortable = null;
171                                                 nextSibling = null;
172                                         });
173
174                                         angular.forEach([
175                                                 'sort', 'disabled', 'draggable', 'handle', 'animation', 'group', 'ghostClass', 'filter',
176                                                 'onStart', 'onEnd', 'onAdd', 'onUpdate', 'onRemove', 'onSort'
177                                         ], function (name) {
178                                                 watchers.push(scope.$watch('ngSortable.' + name, function (value) {
179                                                         if (value !== void 0) {
180                                                                 options[name] = value;
181
182                                                                 if (!/^on[A-Z]/.test(name)) {
183                                                                         sortable.option(name, value);
184                                                                 }
185                                                         }
186                                                 }));
187                                         });
188                                 }
189                         };
190                 }]);
191 });