symphonia 2.1.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (188) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +674 -0
  3. data/README.md +16 -0
  4. data/Rakefile +44 -0
  5. data/app/assets/images/bg-checker.png +0 -0
  6. data/app/assets/images/bullet.gif +0 -0
  7. data/app/assets/images/close.png +0 -0
  8. data/app/assets/images/loading.gif +0 -0
  9. data/app/assets/images/next.png +0 -0
  10. data/app/assets/images/prev.png +0 -0
  11. data/app/assets/javascripts/ckeditor/plugins/autogrow/plugin.js +232 -0
  12. data/app/assets/javascripts/ckeditor/plugins/autogrow/samples/autogrow.html +102 -0
  13. data/app/assets/javascripts/ckeditor/plugins/image_chooser/icons/addimage.png +0 -0
  14. data/app/assets/javascripts/ckeditor/plugins/image_chooser/plugin.js +15 -0
  15. data/app/assets/javascripts/symphonia/Sortable.js +1249 -0
  16. data/app/assets/javascripts/symphonia/_core.js +45 -0
  17. data/app/assets/javascripts/symphonia/application.js.erb +147 -0
  18. data/app/assets/javascripts/symphonia/filters.js +44 -0
  19. data/app/assets/javascripts/symphonia/symphonia_bootstrap_dialog.js +136 -0
  20. data/app/assets/javascripts/symphonia/symphonia_ckeditor.js +55 -0
  21. data/app/assets/stylesheets/symphonia/application.css +4 -0
  22. data/app/assets/stylesheets/symphonia/basic.scss +218 -0
  23. data/app/assets/stylesheets/symphonia/filters.scss +19 -0
  24. data/app/assets/stylesheets/symphonia/symphonia_bootstrap.scss +56 -0
  25. data/app/channels/application_cable/channel.rb +5 -0
  26. data/app/controllers/symphonia/accounts_controller.rb +169 -0
  27. data/app/controllers/symphonia/admin_controller.rb +22 -0
  28. data/app/controllers/symphonia/api_controller.rb +64 -0
  29. data/app/controllers/symphonia/application_controller.rb +8 -0
  30. data/app/controllers/symphonia/attachments_controller.rb +37 -0
  31. data/app/controllers/symphonia/filters_controller.rb +23 -0
  32. data/app/controllers/symphonia/images_controller.rb +16 -0
  33. data/app/controllers/symphonia/login_controller.rb +80 -0
  34. data/app/controllers/symphonia/roles_controller.rb +100 -0
  35. data/app/controllers/symphonia/user_sessions_controller.rb +16 -0
  36. data/app/controllers/symphonia/users_controller.rb +168 -0
  37. data/app/helpers/symphonia/application_helper.rb +422 -0
  38. data/app/helpers/symphonia/bootstrap_modal_helper.rb +59 -0
  39. data/app/helpers/symphonia/form_helper.rb +50 -0
  40. data/app/helpers/symphonia/renderer_helper.rb +85 -0
  41. data/app/mailers/symphonia/application_mailer.rb +6 -0
  42. data/app/mailers/symphonia/notifier.rb +42 -0
  43. data/app/models/symphonia/admin_module.rb +18 -0
  44. data/app/models/symphonia/application_record.rb +14 -0
  45. data/app/models/symphonia/attachment.rb +16 -0
  46. data/app/models/symphonia/common_file.rb +9 -0
  47. data/app/models/symphonia/email_preference.rb +5 -0
  48. data/app/models/symphonia/image.rb +46 -0
  49. data/app/models/symphonia/preference.rb +12 -0
  50. data/app/models/symphonia/role.rb +55 -0
  51. data/app/models/symphonia/swagger/error_model.rb +19 -0
  52. data/app/models/symphonia/swagger/responses.rb +27 -0
  53. data/app/models/symphonia/user.rb +141 -0
  54. data/app/models/symphonia/user_session.rb +19 -0
  55. data/app/views/common/403.html.erb +5 -0
  56. data/app/views/common/404.html.erb +2 -0
  57. data/app/views/layouts/symphonia/_modal.html.erb +19 -0
  58. data/app/views/layouts/symphonia/_query.html.erb +51 -0
  59. data/app/views/layouts/symphonia/application.html.erb +45 -0
  60. data/app/views/layouts/symphonia/application.pdf.erb +15 -0
  61. data/app/views/layouts/symphonia/mailer.html.erb +13 -0
  62. data/app/views/symphonia/accounts/_detail.html.erb +65 -0
  63. data/app/views/symphonia/accounts/_form.html.erb +14 -0
  64. data/app/views/symphonia/accounts/edit.html.erb +9 -0
  65. data/app/views/symphonia/accounts/edit.js.erb +5 -0
  66. data/app/views/symphonia/accounts/lost_password.html.erb +6 -0
  67. data/app/views/symphonia/accounts/lost_password.js.erb +3 -0
  68. data/app/views/symphonia/accounts/new_activation.html.erb +11 -0
  69. data/app/views/symphonia/accounts/new_activation.js.erb +6 -0
  70. data/app/views/symphonia/accounts/register.html.erb +20 -0
  71. data/app/views/symphonia/accounts/reset_password.html.erb +18 -0
  72. data/app/views/symphonia/accounts/update.js.erb +1 -0
  73. data/app/views/symphonia/admin/index.html.erb +15 -0
  74. data/app/views/symphonia/attachments/destroy.js.erb +1 -0
  75. data/app/views/symphonia/common/_editable_images_grid.html.erb +12 -0
  76. data/app/views/symphonia/common/_filters.html.erb +23 -0
  77. data/app/views/symphonia/common/_locale_chooser.html.erb +16 -0
  78. data/app/views/symphonia/common/_share_links.html.erb +5 -0
  79. data/app/views/symphonia/filters/options.html.erb +36 -0
  80. data/app/views/symphonia/filters/options.js.erb +9 -0
  81. data/app/views/symphonia/filters/table.html.erb +21 -0
  82. data/app/views/symphonia/login/_form.html.erb +19 -0
  83. data/app/views/symphonia/login/new.html.erb +11 -0
  84. data/app/views/symphonia/login_sessions/new.html.erb +1 -0
  85. data/app/views/symphonia/notifier/activation_user.html.erb +7 -0
  86. data/app/views/symphonia/notifier/activation_user.text.erb +3 -0
  87. data/app/views/symphonia/notifier/reset_password_user.html.erb +7 -0
  88. data/app/views/symphonia/notifier/reset_password_user.text.erb +3 -0
  89. data/app/views/symphonia/notifier/test_mail.html.erb +2 -0
  90. data/app/views/symphonia/notifier/test_mail.text.erb +3 -0
  91. data/app/views/symphonia/notifier/user_change_to_active.html.erb +3 -0
  92. data/app/views/symphonia/notifier/user_change_to_active.text.erb +1 -0
  93. data/app/views/symphonia/notifier/user_registered.html.erb +13 -0
  94. data/app/views/symphonia/notifier/user_registered.text.erb +8 -0
  95. data/app/views/symphonia/roles/_form.html.erb +30 -0
  96. data/app/views/symphonia/roles/edit.html.erb +5 -0
  97. data/app/views/symphonia/roles/index.html.erb +6 -0
  98. data/app/views/symphonia/roles/new.html.erb +4 -0
  99. data/app/views/symphonia/roles/show.html.erb +5 -0
  100. data/app/views/symphonia/users/_form.html.erb +13 -0
  101. data/app/views/symphonia/users/edit.html.erb +26 -0
  102. data/app/views/symphonia/users/edit.js.erb +3 -0
  103. data/app/views/symphonia/users/edit_current.html.erb +7 -0
  104. data/app/views/symphonia/users/index.html.erb +5 -0
  105. data/app/views/symphonia/users/new.html.erb +8 -0
  106. data/app/views/symphonia/users/show.html.erb +63 -0
  107. data/config/locales/cs.yml +233 -0
  108. data/config/locales/en.yml +47 -0
  109. data/config/routes.rb +52 -0
  110. data/db/migrate/20130714140500_create_users.rb +49 -0
  111. data/db/migrate/20130714140501_create_roles.rb +16 -0
  112. data/db/migrate/20130714140502_create_preferences.rb +26 -0
  113. data/db/migrate/20130828175114_create_attachments.rb +20 -0
  114. data/db/migrate/20141213204351_create_admin_modules.rb +20 -0
  115. data/db/seeds.rb +12 -0
  116. data/lib/generators/symphonia/entity_controller/entity_controller_generator.rb +48 -0
  117. data/lib/generators/symphonia/entity_controller/templates/controller.rb +100 -0
  118. data/lib/generators/symphonia/query/query_generator.rb +37 -0
  119. data/lib/generators/symphonia/setup/setup_generator.rb +52 -0
  120. data/lib/generators/symphonia/setup/templates/404.html +26 -0
  121. data/lib/generators/symphonia/setup/templates/500.html +37 -0
  122. data/lib/generators/symphonia/setup/templates/Gemfile +18 -0
  123. data/lib/generators/symphonia/setup/templates/base_layout.html.erb +46 -0
  124. data/lib/generators/symphonia/setup/templates/design.scss +4 -0
  125. data/lib/generators/symphonia/setup/templates/settings.rb +65 -0
  126. data/lib/generators/symphonia/setup/templates/spec_helper.rb +18 -0
  127. data/lib/symphonia/action_cable/connection.rb +31 -0
  128. data/lib/symphonia/admin_constraint.rb +9 -0
  129. data/lib/symphonia/attachable.rb +35 -0
  130. data/lib/symphonia/base_controller.rb +96 -0
  131. data/lib/symphonia/bootstrap_link_render.rb +69 -0
  132. data/lib/symphonia/controller_extensions.rb +200 -0
  133. data/lib/symphonia/engine.rb +137 -0
  134. data/lib/symphonia/form_builder.rb +137 -0
  135. data/lib/symphonia/menu_manager.rb +23 -0
  136. data/lib/symphonia/model_attributes/attribute.rb +137 -0
  137. data/lib/symphonia/model_attributes.rb +102 -0
  138. data/lib/symphonia/model_filters/base.rb +82 -0
  139. data/lib/symphonia/model_filters/boolean_filter.rb +26 -0
  140. data/lib/symphonia/model_filters/date_filter.rb +81 -0
  141. data/lib/symphonia/model_filters/integer_filter.rb +18 -0
  142. data/lib/symphonia/model_filters/select_filter.rb +48 -0
  143. data/lib/symphonia/model_filters/string_filter.rb +18 -0
  144. data/lib/symphonia/model_filters.rb +10 -0
  145. data/lib/symphonia/object.rb +31 -0
  146. data/lib/symphonia/permissions.rb +93 -0
  147. data/lib/symphonia/query.rb +275 -0
  148. data/lib/symphonia/query_columns/attribute_column.rb +43 -0
  149. data/lib/symphonia/query_columns/generic_column.rb +165 -0
  150. data/lib/symphonia/query_columns.rb +8 -0
  151. data/lib/symphonia/spec_helper.rb +4 -0
  152. data/lib/symphonia/user_management.rb +58 -0
  153. data/lib/symphonia/version.rb +4 -0
  154. data/lib/symphonia.rb +20 -0
  155. data/spec/controllers/account_controller_spec.rb +90 -0
  156. data/spec/controllers/admin_controller_spec.rb +35 -0
  157. data/spec/controllers/api_controller_spec.rb +9 -0
  158. data/spec/controllers/filters_controller_spec.rb +35 -0
  159. data/spec/controllers/images_controller_spec.rb +5 -0
  160. data/spec/controllers/login_controller_spec.rb +20 -0
  161. data/spec/controllers/roles_controller_spec.rb +12 -0
  162. data/spec/controllers/users_controller_spec.rb +47 -0
  163. data/spec/factories/factories.rb +52 -0
  164. data/spec/helpers/symphonia/application_helper_spec.rb +62 -0
  165. data/spec/mailers/previews/symphonia/notifier_preview.rb +27 -0
  166. data/spec/mailers/symphonia/notifier_spec.rb +76 -0
  167. data/spec/models/attachment_spec.rb +22 -0
  168. data/spec/models/query/attribute_spec.rb +8 -0
  169. data/spec/models/query/symphonia_query_spec.rb +70 -0
  170. data/spec/models/role_spec.rb +13 -0
  171. data/spec/models/user_spec.rb +10 -0
  172. data/spec/rails_helper.rb +13 -0
  173. data/spec/requests/accounts_spec.rb +118 -0
  174. data/spec/requests/attachments_controller_spec.rb +23 -0
  175. data/spec/requests/login_spec.rb +26 -0
  176. data/spec/requests/roles_spec.rb +10 -0
  177. data/spec/requests/users_spec.rb +50 -0
  178. data/spec/spec_helper.rb +101 -0
  179. data/spec/support/common_file.txt +2 -0
  180. data/spec/support/query.rb +36 -0
  181. data/spec/support/shared.rb +62 -0
  182. data/spec/support/shared_controllers.rb +31 -0
  183. data/spec/support/stub_users.rb +32 -0
  184. data/spec/support/symphonia.jpg +0 -0
  185. data/spec/support/wait_for_ajax.rb +15 -0
  186. data/spec/version_spec.rb +5 -0
  187. data/spec/views/filters/options.html.erb_spec.rb +14 -0
  188. metadata +697 -0
@@ -0,0 +1,1249 @@
1
+ /**!
2
+ * Sortable
3
+ * @author RubaXa <trash@rubaxa.org>
4
+ * @license MIT
5
+ */
6
+
7
+
8
+ (function (factory) {
9
+ "use strict";
10
+
11
+ if (typeof define === "function" && define.amd) {
12
+ define(factory);
13
+ }
14
+ else if (typeof module != "undefined" && typeof module.exports != "undefined") {
15
+ module.exports = factory();
16
+ }
17
+ else if (typeof Package !== "undefined") {
18
+ Sortable = factory(); // export for Meteor.js
19
+ }
20
+ else {
21
+ /* jshint sub:true */
22
+ window["Sortable"] = factory();
23
+ }
24
+ })(function () {
25
+ "use strict";
26
+
27
+ var dragEl,
28
+ parentEl,
29
+ ghostEl,
30
+ cloneEl,
31
+ rootEl,
32
+ nextEl,
33
+
34
+ scrollEl,
35
+ scrollParentEl,
36
+
37
+ lastEl,
38
+ lastCSS,
39
+ lastParentCSS,
40
+
41
+ oldIndex,
42
+ newIndex,
43
+
44
+ activeGroup,
45
+ autoScroll = {},
46
+
47
+ tapEvt,
48
+ touchEvt,
49
+
50
+ moved,
51
+
52
+ /** @const */
53
+ RSPACE = /\s+/g,
54
+
55
+ expando = 'Sortable' + (new Date).getTime(),
56
+
57
+ win = window,
58
+ document = win.document,
59
+ parseInt = win.parseInt,
60
+
61
+ supportDraggable = !!('draggable' in document.createElement('div')),
62
+ supportCssPointerEvents = (function (el) {
63
+ el = document.createElement('x');
64
+ el.style.cssText = 'pointer-events:auto';
65
+ return el.style.pointerEvents === 'auto';
66
+ })(),
67
+
68
+ _silent = false,
69
+
70
+ abs = Math.abs,
71
+ slice = [].slice,
72
+
73
+ touchDragOverListeners = [],
74
+
75
+ _autoScroll = _throttle(function (/**Event*/evt, /**Object*/options, /**HTMLElement*/rootEl) {
76
+ // Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=505521
77
+ if (rootEl && options.scroll) {
78
+ var el,
79
+ rect,
80
+ sens = options.scrollSensitivity,
81
+ speed = options.scrollSpeed,
82
+
83
+ x = evt.clientX,
84
+ y = evt.clientY,
85
+
86
+ winWidth = window.innerWidth,
87
+ winHeight = window.innerHeight,
88
+
89
+ vx,
90
+ vy
91
+ ;
92
+
93
+ // Delect scrollEl
94
+ if (scrollParentEl !== rootEl) {
95
+ scrollEl = options.scroll;
96
+ scrollParentEl = rootEl;
97
+
98
+ if (scrollEl === true) {
99
+ scrollEl = rootEl;
100
+
101
+ do {
102
+ if ((scrollEl.offsetWidth < scrollEl.scrollWidth) ||
103
+ (scrollEl.offsetHeight < scrollEl.scrollHeight)
104
+ ) {
105
+ break;
106
+ }
107
+ /* jshint boss:true */
108
+ } while (scrollEl = scrollEl.parentNode);
109
+ }
110
+ }
111
+
112
+ if (scrollEl) {
113
+ el = scrollEl;
114
+ rect = scrollEl.getBoundingClientRect();
115
+ vx = (abs(rect.right - x) <= sens) - (abs(rect.left - x) <= sens);
116
+ vy = (abs(rect.bottom - y) <= sens) - (abs(rect.top - y) <= sens);
117
+ }
118
+
119
+
120
+ if (!(vx || vy)) {
121
+ vx = (winWidth - x <= sens) - (x <= sens);
122
+ vy = (winHeight - y <= sens) - (y <= sens);
123
+
124
+ /* jshint expr:true */
125
+ (vx || vy) && (el = win);
126
+ }
127
+
128
+
129
+ if (autoScroll.vx !== vx || autoScroll.vy !== vy || autoScroll.el !== el) {
130
+ autoScroll.el = el;
131
+ autoScroll.vx = vx;
132
+ autoScroll.vy = vy;
133
+
134
+ clearInterval(autoScroll.pid);
135
+
136
+ if (el) {
137
+ autoScroll.pid = setInterval(function () {
138
+ if (el === win) {
139
+ win.scrollTo(win.pageXOffset + vx * speed, win.pageYOffset + vy * speed);
140
+ } else {
141
+ vy && (el.scrollTop += vy * speed);
142
+ vx && (el.scrollLeft += vx * speed);
143
+ }
144
+ }, 24);
145
+ }
146
+ }
147
+ }
148
+ }, 30),
149
+
150
+ _prepareGroup = function (options) {
151
+ var group = options.group;
152
+
153
+ if (!group || typeof group != 'object') {
154
+ group = options.group = {name: group};
155
+ }
156
+
157
+ ['pull', 'put'].forEach(function (key) {
158
+ if (!(key in group)) {
159
+ group[key] = true;
160
+ }
161
+ });
162
+
163
+ options.groups = ' ' + group.name + (group.put.join ? ' ' + group.put.join(' ') : '') + ' ';
164
+ }
165
+ ;
166
+
167
+
168
+
169
+ /**
170
+ * @class Sortable
171
+ * @param {HTMLElement} el
172
+ * @param {Object} [options]
173
+ */
174
+ function Sortable(el, options) {
175
+ if (!(el && el.nodeType && el.nodeType === 1)) {
176
+ throw 'Sortable: `el` must be HTMLElement, and not ' + {}.toString.call(el);
177
+ }
178
+
179
+ this.el = el; // root element
180
+ this.options = options = _extend({}, options);
181
+
182
+
183
+ // Export instance
184
+ el[expando] = this;
185
+
186
+
187
+ // Default options
188
+ var defaults = {
189
+ group: Math.random(),
190
+ sort: true,
191
+ disabled: false,
192
+ store: null,
193
+ handle: null,
194
+ scroll: true,
195
+ scrollSensitivity: 30,
196
+ scrollSpeed: 10,
197
+ draggable: /[uo]l/i.test(el.nodeName) ? 'li' : '>*',
198
+ ghostClass: 'sortable-ghost',
199
+ chosenClass: 'sortable-chosen',
200
+ ignore: 'a, img',
201
+ filter: null,
202
+ animation: 0,
203
+ setData: function (dataTransfer, dragEl) {
204
+ dataTransfer.setData('Text', dragEl.textContent);
205
+ },
206
+ dropBubble: false,
207
+ dragoverBubble: false,
208
+ dataIdAttr: 'data-id',
209
+ delay: 0,
210
+ forceFallback: false,
211
+ fallbackClass: 'sortable-fallback',
212
+ fallbackOnBody: false
213
+ };
214
+
215
+
216
+ // Set default options
217
+ for (var name in defaults) {
218
+ !(name in options) && (options[name] = defaults[name]);
219
+ }
220
+
221
+ _prepareGroup(options);
222
+
223
+ // Bind all private methods
224
+ for (var fn in this) {
225
+ if (fn.charAt(0) === '_') {
226
+ this[fn] = this[fn].bind(this);
227
+ }
228
+ }
229
+
230
+ // Setup drag mode
231
+ this.nativeDraggable = options.forceFallback ? false : supportDraggable;
232
+
233
+ // Bind events
234
+ _on(el, 'mousedown', this._onTapStart);
235
+ _on(el, 'touchstart', this._onTapStart);
236
+
237
+ if (this.nativeDraggable) {
238
+ _on(el, 'dragover', this);
239
+ _on(el, 'dragenter', this);
240
+ }
241
+
242
+ touchDragOverListeners.push(this._onDragOver);
243
+
244
+ // Restore sorting
245
+ options.store && this.sort(options.store.get(this));
246
+ }
247
+
248
+
249
+ Sortable.prototype = /** @lends Sortable.prototype */ {
250
+ constructor: Sortable,
251
+
252
+ _onTapStart: function (/** Event|TouchEvent */evt) {
253
+ var _this = this,
254
+ el = this.el,
255
+ options = this.options,
256
+ type = evt.type,
257
+ touch = evt.touches && evt.touches[0],
258
+ target = (touch || evt).target,
259
+ originalTarget = target,
260
+ filter = options.filter;
261
+
262
+
263
+ if (type === 'mousedown' && evt.button !== 0 || options.disabled) {
264
+ return; // only left button or enabled
265
+ }
266
+
267
+ target = _closest(target, options.draggable, el);
268
+
269
+ if (!target) {
270
+ return;
271
+ }
272
+
273
+ // get the index of the dragged element within its parent
274
+ oldIndex = _index(target);
275
+
276
+ // Check filter
277
+ if (typeof filter === 'function') {
278
+ if (filter.call(this, evt, target, this)) {
279
+ _dispatchEvent(_this, originalTarget, 'filter', target, el, oldIndex);
280
+ evt.preventDefault();
281
+ return; // cancel dnd
282
+ }
283
+ }
284
+ else if (filter) {
285
+ filter = filter.split(',').some(function (criteria) {
286
+ criteria = _closest(originalTarget, criteria.trim(), el);
287
+
288
+ if (criteria) {
289
+ _dispatchEvent(_this, criteria, 'filter', target, el, oldIndex);
290
+ return true;
291
+ }
292
+ });
293
+
294
+ if (filter) {
295
+ evt.preventDefault();
296
+ return; // cancel dnd
297
+ }
298
+ }
299
+
300
+
301
+ if (options.handle && !_closest(originalTarget, options.handle, el)) {
302
+ return;
303
+ }
304
+
305
+
306
+ // Prepare `dragstart`
307
+ this._prepareDragStart(evt, touch, target);
308
+ },
309
+
310
+ _prepareDragStart: function (/** Event */evt, /** Touch */touch, /** HTMLElement */target) {
311
+ var _this = this,
312
+ el = _this.el,
313
+ options = _this.options,
314
+ ownerDocument = el.ownerDocument,
315
+ dragStartFn;
316
+
317
+ if (target && !dragEl && (target.parentNode === el)) {
318
+ tapEvt = evt;
319
+
320
+ rootEl = el;
321
+ dragEl = target;
322
+ parentEl = dragEl.parentNode;
323
+ nextEl = dragEl.nextSibling;
324
+ activeGroup = options.group;
325
+
326
+ dragStartFn = function () {
327
+ // Delayed drag has been triggered
328
+ // we can re-enable the events: touchmove/mousemove
329
+ _this._disableDelayedDrag();
330
+
331
+ // Make the element draggable
332
+ dragEl.draggable = true;
333
+
334
+ // Chosen item
335
+ _toggleClass(dragEl, _this.options.chosenClass, true);
336
+
337
+ // Bind the events: dragstart/dragend
338
+ _this._triggerDragStart(touch);
339
+ };
340
+
341
+ // Disable "draggable"
342
+ options.ignore.split(',').forEach(function (criteria) {
343
+ _find(dragEl, criteria.trim(), _disableDraggable);
344
+ });
345
+
346
+ _on(ownerDocument, 'mouseup', _this._onDrop);
347
+ _on(ownerDocument, 'touchend', _this._onDrop);
348
+ _on(ownerDocument, 'touchcancel', _this._onDrop);
349
+
350
+ if (options.delay) {
351
+ // If the user moves the pointer or let go the click or touch
352
+ // before the delay has been reached:
353
+ // disable the delayed drag
354
+ _on(ownerDocument, 'mouseup', _this._disableDelayedDrag);
355
+ _on(ownerDocument, 'touchend', _this._disableDelayedDrag);
356
+ _on(ownerDocument, 'touchcancel', _this._disableDelayedDrag);
357
+ _on(ownerDocument, 'mousemove', _this._disableDelayedDrag);
358
+ _on(ownerDocument, 'touchmove', _this._disableDelayedDrag);
359
+
360
+ _this._dragStartTimer = setTimeout(dragStartFn, options.delay);
361
+ } else {
362
+ dragStartFn();
363
+ }
364
+ }
365
+ },
366
+
367
+ _disableDelayedDrag: function () {
368
+ var ownerDocument = this.el.ownerDocument;
369
+
370
+ clearTimeout(this._dragStartTimer);
371
+ _off(ownerDocument, 'mouseup', this._disableDelayedDrag);
372
+ _off(ownerDocument, 'touchend', this._disableDelayedDrag);
373
+ _off(ownerDocument, 'touchcancel', this._disableDelayedDrag);
374
+ _off(ownerDocument, 'mousemove', this._disableDelayedDrag);
375
+ _off(ownerDocument, 'touchmove', this._disableDelayedDrag);
376
+ },
377
+
378
+ _triggerDragStart: function (/** Touch */touch) {
379
+ if (touch) {
380
+ // Touch device support
381
+ tapEvt = {
382
+ target: dragEl,
383
+ clientX: touch.clientX,
384
+ clientY: touch.clientY
385
+ };
386
+
387
+ this._onDragStart(tapEvt, 'touch');
388
+ }
389
+ else if (!this.nativeDraggable) {
390
+ this._onDragStart(tapEvt, true);
391
+ }
392
+ else {
393
+ _on(dragEl, 'dragend', this);
394
+ _on(rootEl, 'dragstart', this._onDragStart);
395
+ }
396
+
397
+ try {
398
+ if (document.selection) {
399
+ document.selection.empty();
400
+ } else {
401
+ window.getSelection().removeAllRanges();
402
+ }
403
+ } catch (err) {
404
+ }
405
+ },
406
+
407
+ _dragStarted: function () {
408
+ if (rootEl && dragEl) {
409
+ // Apply effect
410
+ _toggleClass(dragEl, this.options.ghostClass, true);
411
+
412
+ Sortable.active = this;
413
+
414
+ // Drag start event
415
+ _dispatchEvent(this, rootEl, 'start', dragEl, rootEl, oldIndex);
416
+ }
417
+ },
418
+
419
+ _emulateDragOver: function () {
420
+ if (touchEvt) {
421
+ if (this._lastX === touchEvt.clientX && this._lastY === touchEvt.clientY) {
422
+ return;
423
+ }
424
+
425
+ this._lastX = touchEvt.clientX;
426
+ this._lastY = touchEvt.clientY;
427
+
428
+ if (!supportCssPointerEvents) {
429
+ _css(ghostEl, 'display', 'none');
430
+ }
431
+
432
+ var target = document.elementFromPoint(touchEvt.clientX, touchEvt.clientY),
433
+ parent = target,
434
+ groupName = ' ' + this.options.group.name + '',
435
+ i = touchDragOverListeners.length;
436
+
437
+ if (parent) {
438
+ do {
439
+ if (parent[expando] && parent[expando].options.groups.indexOf(groupName) > -1) {
440
+ while (i--) {
441
+ touchDragOverListeners[i]({
442
+ clientX: touchEvt.clientX,
443
+ clientY: touchEvt.clientY,
444
+ target: target,
445
+ rootEl: parent
446
+ });
447
+ }
448
+
449
+ break;
450
+ }
451
+
452
+ target = parent; // store last element
453
+ }
454
+ /* jshint boss:true */
455
+ while (parent = parent.parentNode);
456
+ }
457
+
458
+ if (!supportCssPointerEvents) {
459
+ _css(ghostEl, 'display', '');
460
+ }
461
+ }
462
+ },
463
+
464
+
465
+ _onTouchMove: function (/**TouchEvent*/evt) {
466
+ if (tapEvt) {
467
+ // only set the status to dragging, when we are actually dragging
468
+ if (!Sortable.active) {
469
+ this._dragStarted();
470
+ }
471
+
472
+ // as well as creating the ghost element on the document body
473
+ this._appendGhost();
474
+
475
+ var touch = evt.touches ? evt.touches[0] : evt,
476
+ dx = touch.clientX - tapEvt.clientX,
477
+ dy = touch.clientY - tapEvt.clientY,
478
+ translate3d = evt.touches ? 'translate3d(' + dx + 'px,' + dy + 'px,0)' : 'translate(' + dx + 'px,' + dy + 'px)';
479
+
480
+ moved = true;
481
+ touchEvt = touch;
482
+
483
+ _css(ghostEl, 'webkitTransform', translate3d);
484
+ _css(ghostEl, 'mozTransform', translate3d);
485
+ _css(ghostEl, 'msTransform', translate3d);
486
+ _css(ghostEl, 'transform', translate3d);
487
+
488
+ evt.preventDefault();
489
+ }
490
+ },
491
+
492
+ _appendGhost: function () {
493
+ if (!ghostEl) {
494
+ var rect = dragEl.getBoundingClientRect(),
495
+ css = _css(dragEl),
496
+ options = this.options,
497
+ ghostRect;
498
+
499
+ ghostEl = dragEl.cloneNode(true);
500
+
501
+ _toggleClass(ghostEl, options.ghostClass, false);
502
+ _toggleClass(ghostEl, options.fallbackClass, true);
503
+
504
+ _css(ghostEl, 'top', rect.top - parseInt(css.marginTop, 10));
505
+ _css(ghostEl, 'left', rect.left - parseInt(css.marginLeft, 10));
506
+ _css(ghostEl, 'width', rect.width);
507
+ _css(ghostEl, 'height', rect.height);
508
+ _css(ghostEl, 'opacity', '0.8');
509
+ _css(ghostEl, 'position', 'fixed');
510
+ _css(ghostEl, 'zIndex', '100000');
511
+ _css(ghostEl, 'pointerEvents', 'none');
512
+
513
+ options.fallbackOnBody && document.body.appendChild(ghostEl) || rootEl.appendChild(ghostEl);
514
+
515
+ // Fixing dimensions.
516
+ ghostRect = ghostEl.getBoundingClientRect();
517
+ _css(ghostEl, 'width', rect.width * 2 - ghostRect.width);
518
+ _css(ghostEl, 'height', rect.height * 2 - ghostRect.height);
519
+ }
520
+ },
521
+
522
+ _onDragStart: function (/**Event*/evt, /**boolean*/useFallback) {
523
+ var dataTransfer = evt.dataTransfer,
524
+ options = this.options;
525
+
526
+ this._offUpEvents();
527
+
528
+ if (activeGroup.pull == 'clone') {
529
+ cloneEl = dragEl.cloneNode(true);
530
+ _css(cloneEl, 'display', 'none');
531
+ rootEl.insertBefore(cloneEl, dragEl);
532
+ }
533
+
534
+ if (useFallback) {
535
+
536
+ if (useFallback === 'touch') {
537
+ // Bind touch events
538
+ _on(document, 'touchmove', this._onTouchMove);
539
+ _on(document, 'touchend', this._onDrop);
540
+ _on(document, 'touchcancel', this._onDrop);
541
+ } else {
542
+ // Old brwoser
543
+ _on(document, 'mousemove', this._onTouchMove);
544
+ _on(document, 'mouseup', this._onDrop);
545
+ }
546
+
547
+ this._loopId = setInterval(this._emulateDragOver, 50);
548
+ }
549
+ else {
550
+ if (dataTransfer) {
551
+ dataTransfer.effectAllowed = 'move';
552
+ options.setData && options.setData.call(this, dataTransfer, dragEl);
553
+ }
554
+
555
+ _on(document, 'drop', this);
556
+ setTimeout(this._dragStarted, 0);
557
+ }
558
+ },
559
+
560
+ _onDragOver: function (/**Event*/evt) {
561
+ var el = this.el,
562
+ target,
563
+ dragRect,
564
+ revert,
565
+ options = this.options,
566
+ group = options.group,
567
+ groupPut = group.put,
568
+ isOwner = (activeGroup === group),
569
+ canSort = options.sort;
570
+
571
+ if (evt.preventDefault !== void 0) {
572
+ evt.preventDefault();
573
+ !options.dragoverBubble && evt.stopPropagation();
574
+ }
575
+
576
+ moved = true;
577
+
578
+ if (activeGroup && !options.disabled &&
579
+ (isOwner
580
+ ? canSort || (revert = !rootEl.contains(dragEl)) // Reverting item into the original list
581
+ : activeGroup.pull && groupPut && (
582
+ (activeGroup.name === group.name) || // by Name
583
+ (groupPut.indexOf && ~groupPut.indexOf(activeGroup.name)) // by Array
584
+ )
585
+ ) &&
586
+ (evt.rootEl === void 0 || evt.rootEl === this.el) // touch fallback
587
+ ) {
588
+ // Smart auto-scrolling
589
+ _autoScroll(evt, options, this.el);
590
+
591
+ if (_silent) {
592
+ return;
593
+ }
594
+
595
+ target = _closest(evt.target, options.draggable, el);
596
+ dragRect = dragEl.getBoundingClientRect();
597
+
598
+ if (revert) {
599
+ _cloneHide(true);
600
+
601
+ if (cloneEl || nextEl) {
602
+ rootEl.insertBefore(dragEl, cloneEl || nextEl);
603
+ }
604
+ else if (!canSort) {
605
+ rootEl.appendChild(dragEl);
606
+ }
607
+
608
+ return;
609
+ }
610
+
611
+
612
+ if ((el.children.length === 0) || (el.children[0] === ghostEl) ||
613
+ (el === evt.target) && (target = _ghostIsLast(el, evt))
614
+ ) {
615
+
616
+ if (target) {
617
+ if (target.animated) {
618
+ return;
619
+ }
620
+
621
+ targetRect = target.getBoundingClientRect();
622
+ }
623
+
624
+ _cloneHide(isOwner);
625
+
626
+ if (_onMove(rootEl, el, dragEl, dragRect, target, targetRect) !== false) {
627
+ if (!dragEl.contains(el)) {
628
+ el.appendChild(dragEl);
629
+ parentEl = el; // actualization
630
+ }
631
+
632
+ this._animate(dragRect, dragEl);
633
+ target && this._animate(targetRect, target);
634
+ }
635
+ }
636
+ else if (target && !target.animated && target !== dragEl && (target.parentNode[expando] !== void 0)) {
637
+ if (lastEl !== target) {
638
+ lastEl = target;
639
+ lastCSS = _css(target);
640
+ lastParentCSS = _css(target.parentNode);
641
+ }
642
+
643
+
644
+ var targetRect = target.getBoundingClientRect(),
645
+ width = targetRect.right - targetRect.left,
646
+ height = targetRect.bottom - targetRect.top,
647
+ floating = /left|right|inline/.test(lastCSS.cssFloat + lastCSS.display)
648
+ || (lastParentCSS.display == 'flex' && lastParentCSS['flex-direction'].indexOf('row') === 0),
649
+ isWide = (target.offsetWidth > dragEl.offsetWidth),
650
+ isLong = (target.offsetHeight > dragEl.offsetHeight),
651
+ halfway = (floating ? (evt.clientX - targetRect.left) / width : (evt.clientY - targetRect.top) / height) > 0.5,
652
+ nextSibling = target.nextElementSibling,
653
+ moveVector = _onMove(rootEl, el, dragEl, dragRect, target, targetRect),
654
+ after
655
+ ;
656
+
657
+ if (moveVector !== false) {
658
+ _silent = true;
659
+ setTimeout(_unsilent, 30);
660
+
661
+ _cloneHide(isOwner);
662
+
663
+ if (moveVector === 1 || moveVector === -1) {
664
+ after = (moveVector === 1);
665
+ }
666
+ else if (floating) {
667
+ var elTop = dragEl.offsetTop,
668
+ tgTop = target.offsetTop;
669
+
670
+ if (elTop === tgTop) {
671
+ after = (target.previousElementSibling === dragEl) && !isWide || halfway && isWide;
672
+ } else {
673
+ after = tgTop > elTop;
674
+ }
675
+ } else {
676
+ after = (nextSibling !== dragEl) && !isLong || halfway && isLong;
677
+ }
678
+
679
+ if (!dragEl.contains(el)) {
680
+ if (after && !nextSibling) {
681
+ el.appendChild(dragEl);
682
+ } else {
683
+ target.parentNode.insertBefore(dragEl, after ? nextSibling : target);
684
+ }
685
+ }
686
+
687
+ parentEl = dragEl.parentNode; // actualization
688
+
689
+ this._animate(dragRect, dragEl);
690
+ this._animate(targetRect, target);
691
+ }
692
+ }
693
+ }
694
+ },
695
+
696
+ _animate: function (prevRect, target) {
697
+ var ms = this.options.animation;
698
+
699
+ if (ms) {
700
+ var currentRect = target.getBoundingClientRect();
701
+
702
+ _css(target, 'transition', 'none');
703
+ _css(target, 'transform', 'translate3d('
704
+ + (prevRect.left - currentRect.left) + 'px,'
705
+ + (prevRect.top - currentRect.top) + 'px,0)'
706
+ );
707
+
708
+ target.offsetWidth; // repaint
709
+
710
+ _css(target, 'transition', 'all ' + ms + 'ms');
711
+ _css(target, 'transform', 'translate3d(0,0,0)');
712
+
713
+ clearTimeout(target.animated);
714
+ target.animated = setTimeout(function () {
715
+ _css(target, 'transition', '');
716
+ _css(target, 'transform', '');
717
+ target.animated = false;
718
+ }, ms);
719
+ }
720
+ },
721
+
722
+ _offUpEvents: function () {
723
+ var ownerDocument = this.el.ownerDocument;
724
+
725
+ _off(document, 'touchmove', this._onTouchMove);
726
+ _off(ownerDocument, 'mouseup', this._onDrop);
727
+ _off(ownerDocument, 'touchend', this._onDrop);
728
+ _off(ownerDocument, 'touchcancel', this._onDrop);
729
+ },
730
+
731
+ _onDrop: function (/**Event*/evt) {
732
+ var el = this.el,
733
+ options = this.options;
734
+
735
+ clearInterval(this._loopId);
736
+ clearInterval(autoScroll.pid);
737
+ clearTimeout(this._dragStartTimer);
738
+
739
+ // Unbind events
740
+ _off(document, 'mousemove', this._onTouchMove);
741
+
742
+ if (this.nativeDraggable) {
743
+ _off(document, 'drop', this);
744
+ _off(el, 'dragstart', this._onDragStart);
745
+ }
746
+
747
+ this._offUpEvents();
748
+
749
+ if (evt) {
750
+ if (moved) {
751
+ evt.preventDefault();
752
+ !options.dropBubble && evt.stopPropagation();
753
+ }
754
+
755
+ ghostEl && ghostEl.parentNode.removeChild(ghostEl);
756
+
757
+ if (dragEl) {
758
+ if (this.nativeDraggable) {
759
+ _off(dragEl, 'dragend', this);
760
+ }
761
+
762
+ _disableDraggable(dragEl);
763
+
764
+ // Remove class's
765
+ _toggleClass(dragEl, this.options.ghostClass, false);
766
+ _toggleClass(dragEl, this.options.chosenClass, false);
767
+
768
+ if (rootEl !== parentEl) {
769
+ newIndex = _index(dragEl);
770
+
771
+ if (newIndex >= 0) {
772
+ // drag from one list and drop into another
773
+ _dispatchEvent(null, parentEl, 'sort', dragEl, rootEl, oldIndex, newIndex);
774
+ _dispatchEvent(this, rootEl, 'sort', dragEl, rootEl, oldIndex, newIndex);
775
+
776
+ // Add event
777
+ _dispatchEvent(null, parentEl, 'add', dragEl, rootEl, oldIndex, newIndex);
778
+
779
+ // Remove event
780
+ _dispatchEvent(this, rootEl, 'remove', dragEl, rootEl, oldIndex, newIndex);
781
+ }
782
+ }
783
+ else {
784
+ // Remove clone
785
+ cloneEl && cloneEl.parentNode.removeChild(cloneEl);
786
+
787
+ if (dragEl.nextSibling !== nextEl) {
788
+ // Get the index of the dragged element within its parent
789
+ newIndex = _index(dragEl);
790
+
791
+ if (newIndex >= 0) {
792
+ // drag & drop within the same list
793
+ _dispatchEvent(this, rootEl, 'update', dragEl, rootEl, oldIndex, newIndex);
794
+ _dispatchEvent(this, rootEl, 'sort', dragEl, rootEl, oldIndex, newIndex);
795
+ }
796
+ }
797
+ }
798
+
799
+ if (Sortable.active) {
800
+ if (newIndex === null || newIndex === -1) {
801
+ newIndex = oldIndex;
802
+ }
803
+
804
+ _dispatchEvent(this, rootEl, 'end', dragEl, rootEl, oldIndex, newIndex);
805
+
806
+ // Save sorting
807
+ this.save();
808
+ }
809
+ }
810
+
811
+ // Nulling
812
+ rootEl =
813
+ dragEl =
814
+ parentEl =
815
+ ghostEl =
816
+ nextEl =
817
+ cloneEl =
818
+
819
+ scrollEl =
820
+ scrollParentEl =
821
+
822
+ tapEvt =
823
+ touchEvt =
824
+
825
+ moved =
826
+ newIndex =
827
+
828
+ lastEl =
829
+ lastCSS =
830
+
831
+ activeGroup =
832
+ Sortable.active = null;
833
+ }
834
+ },
835
+
836
+
837
+ handleEvent: function (/**Event*/evt) {
838
+ var type = evt.type;
839
+
840
+ if (type === 'dragover' || type === 'dragenter') {
841
+ if (dragEl) {
842
+ this._onDragOver(evt);
843
+ _globalDragOver(evt);
844
+ }
845
+ }
846
+ else if (type === 'drop' || type === 'dragend') {
847
+ this._onDrop(evt);
848
+ }
849
+ },
850
+
851
+
852
+ /**
853
+ * Serializes the item into an array of string.
854
+ * @returns {String[]}
855
+ */
856
+ toArray: function () {
857
+ var order = [],
858
+ el,
859
+ children = this.el.children,
860
+ i = 0,
861
+ n = children.length,
862
+ options = this.options;
863
+
864
+ for (; i < n; i++) {
865
+ el = children[i];
866
+ if (_closest(el, options.draggable, this.el)) {
867
+ order.push(el.getAttribute(options.dataIdAttr) || _generateId(el));
868
+ }
869
+ }
870
+
871
+ return order;
872
+ },
873
+
874
+
875
+ /**
876
+ * Sorts the elements according to the array.
877
+ * @param {String[]} order order of the items
878
+ */
879
+ sort: function (order) {
880
+ var items = {}, rootEl = this.el;
881
+
882
+ this.toArray().forEach(function (id, i) {
883
+ var el = rootEl.children[i];
884
+
885
+ if (_closest(el, this.options.draggable, rootEl)) {
886
+ items[id] = el;
887
+ }
888
+ }, this);
889
+
890
+ order.forEach(function (id) {
891
+ if (items[id]) {
892
+ rootEl.removeChild(items[id]);
893
+ rootEl.appendChild(items[id]);
894
+ }
895
+ });
896
+ },
897
+
898
+
899
+ /**
900
+ * Save the current sorting
901
+ */
902
+ save: function () {
903
+ var store = this.options.store;
904
+ store && store.set(this);
905
+ },
906
+
907
+
908
+ /**
909
+ * For each element in the set, get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree.
910
+ * @param {HTMLElement} el
911
+ * @param {String} [selector] default: `options.draggable`
912
+ * @returns {HTMLElement|null}
913
+ */
914
+ closest: function (el, selector) {
915
+ return _closest(el, selector || this.options.draggable, this.el);
916
+ },
917
+
918
+
919
+ /**
920
+ * Set/get option
921
+ * @param {string} name
922
+ * @param {*} [value]
923
+ * @returns {*}
924
+ */
925
+ option: function (name, value) {
926
+ var options = this.options;
927
+
928
+ if (value === void 0) {
929
+ return options[name];
930
+ } else {
931
+ options[name] = value;
932
+
933
+ if (name === 'group') {
934
+ _prepareGroup(options);
935
+ }
936
+ }
937
+ },
938
+
939
+
940
+ /**
941
+ * Destroy
942
+ */
943
+ destroy: function () {
944
+ var el = this.el;
945
+
946
+ el[expando] = null;
947
+
948
+ _off(el, 'mousedown', this._onTapStart);
949
+ _off(el, 'touchstart', this._onTapStart);
950
+
951
+ if (this.nativeDraggable) {
952
+ _off(el, 'dragover', this);
953
+ _off(el, 'dragenter', this);
954
+ }
955
+
956
+ // Remove draggable attributes
957
+ Array.prototype.forEach.call(el.querySelectorAll('[draggable]'), function (el) {
958
+ el.removeAttribute('draggable');
959
+ });
960
+
961
+ touchDragOverListeners.splice(touchDragOverListeners.indexOf(this._onDragOver), 1);
962
+
963
+ this._onDrop();
964
+
965
+ this.el = el = null;
966
+ }
967
+ };
968
+
969
+
970
+ function _cloneHide(state) {
971
+ if (cloneEl && (cloneEl.state !== state)) {
972
+ _css(cloneEl, 'display', state ? 'none' : '');
973
+ !state && cloneEl.state && rootEl.insertBefore(cloneEl, dragEl);
974
+ cloneEl.state = state;
975
+ }
976
+ }
977
+
978
+
979
+ function _closest(/**HTMLElement*/el, /**String*/selector, /**HTMLElement*/ctx) {
980
+ if (el) {
981
+ ctx = ctx || document;
982
+ selector = selector.split('.');
983
+
984
+ var tag = selector.shift().toUpperCase(),
985
+ re = new RegExp('\\s(' + selector.join('|') + ')(?=\\s)', 'g');
986
+
987
+ do {
988
+ if (
989
+ (tag === '>*' && el.parentNode === ctx) || (
990
+ (tag === '' || el.nodeName.toUpperCase() == tag) &&
991
+ (!selector.length || ((' ' + el.className + ' ').match(re) || []).length == selector.length)
992
+ )
993
+ ) {
994
+ return el;
995
+ }
996
+ }
997
+ while (el !== ctx && (el = el.parentNode));
998
+ }
999
+
1000
+ return null;
1001
+ }
1002
+
1003
+
1004
+ function _globalDragOver(/**Event*/evt) {
1005
+ if (evt.dataTransfer) {
1006
+ evt.dataTransfer.dropEffect = 'move';
1007
+ }
1008
+ evt.preventDefault();
1009
+ }
1010
+
1011
+
1012
+ function _on(el, event, fn) {
1013
+ el.addEventListener(event, fn, false);
1014
+ }
1015
+
1016
+
1017
+ function _off(el, event, fn) {
1018
+ el.removeEventListener(event, fn, false);
1019
+ }
1020
+
1021
+
1022
+ function _toggleClass(el, name, state) {
1023
+ if (el) {
1024
+ if (el.classList) {
1025
+ el.classList[state ? 'add' : 'remove'](name);
1026
+ }
1027
+ else {
1028
+ var className = (' ' + el.className + ' ').replace(RSPACE, ' ').replace(' ' + name + ' ', ' ');
1029
+ el.className = (className + (state ? ' ' + name : '')).replace(RSPACE, ' ');
1030
+ }
1031
+ }
1032
+ }
1033
+
1034
+
1035
+ function _css(el, prop, val) {
1036
+ var style = el && el.style;
1037
+
1038
+ if (style) {
1039
+ if (val === void 0) {
1040
+ if (document.defaultView && document.defaultView.getComputedStyle) {
1041
+ val = document.defaultView.getComputedStyle(el, '');
1042
+ }
1043
+ else if (el.currentStyle) {
1044
+ val = el.currentStyle;
1045
+ }
1046
+
1047
+ return prop === void 0 ? val : val[prop];
1048
+ }
1049
+ else {
1050
+ if (!(prop in style)) {
1051
+ prop = '-webkit-' + prop;
1052
+ }
1053
+
1054
+ style[prop] = val + (typeof val === 'string' ? '' : 'px');
1055
+ }
1056
+ }
1057
+ }
1058
+
1059
+
1060
+ function _find(ctx, tagName, iterator) {
1061
+ if (ctx) {
1062
+ var list = ctx.getElementsByTagName(tagName), i = 0, n = list.length;
1063
+
1064
+ if (iterator) {
1065
+ for (; i < n; i++) {
1066
+ iterator(list[i], i);
1067
+ }
1068
+ }
1069
+
1070
+ return list;
1071
+ }
1072
+
1073
+ return [];
1074
+ }
1075
+
1076
+
1077
+
1078
+ function _dispatchEvent(sortable, rootEl, name, targetEl, fromEl, startIndex, newIndex) {
1079
+ var evt = document.createEvent('Event'),
1080
+ options = (sortable || rootEl[expando]).options,
1081
+ onName = 'on' + name.charAt(0).toUpperCase() + name.substr(1);
1082
+
1083
+ evt.initEvent(name, true, true);
1084
+
1085
+ evt.to = rootEl;
1086
+ evt.from = fromEl || rootEl;
1087
+ evt.item = targetEl || rootEl;
1088
+ evt.clone = cloneEl;
1089
+
1090
+ evt.oldIndex = startIndex;
1091
+ evt.newIndex = newIndex;
1092
+
1093
+ rootEl.dispatchEvent(evt);
1094
+
1095
+ if (options[onName]) {
1096
+ options[onName].call(sortable, evt);
1097
+ }
1098
+ }
1099
+
1100
+
1101
+ function _onMove(fromEl, toEl, dragEl, dragRect, targetEl, targetRect) {
1102
+ var evt,
1103
+ sortable = fromEl[expando],
1104
+ onMoveFn = sortable.options.onMove,
1105
+ retVal;
1106
+
1107
+ evt = document.createEvent('Event');
1108
+ evt.initEvent('move', true, true);
1109
+
1110
+ evt.to = toEl;
1111
+ evt.from = fromEl;
1112
+ evt.dragged = dragEl;
1113
+ evt.draggedRect = dragRect;
1114
+ evt.related = targetEl || toEl;
1115
+ evt.relatedRect = targetRect || toEl.getBoundingClientRect();
1116
+
1117
+ fromEl.dispatchEvent(evt);
1118
+
1119
+ if (onMoveFn) {
1120
+ retVal = onMoveFn.call(sortable, evt);
1121
+ }
1122
+
1123
+ return retVal;
1124
+ }
1125
+
1126
+
1127
+ function _disableDraggable(el) {
1128
+ el.draggable = false;
1129
+ }
1130
+
1131
+
1132
+ function _unsilent() {
1133
+ _silent = false;
1134
+ }
1135
+
1136
+
1137
+ /** @returns {HTMLElement|false} */
1138
+ function _ghostIsLast(el, evt) {
1139
+ var lastEl = el.lastElementChild,
1140
+ rect = lastEl.getBoundingClientRect();
1141
+
1142
+ return ((evt.clientY - (rect.top + rect.height) > 5) || (evt.clientX - (rect.right + rect.width) > 5)) && lastEl; // min delta
1143
+ }
1144
+
1145
+
1146
+ /**
1147
+ * Generate id
1148
+ * @param {HTMLElement} el
1149
+ * @returns {String}
1150
+ * @private
1151
+ */
1152
+ function _generateId(el) {
1153
+ var str = el.tagName + el.className + el.src + el.href + el.textContent,
1154
+ i = str.length,
1155
+ sum = 0;
1156
+
1157
+ while (i--) {
1158
+ sum += str.charCodeAt(i);
1159
+ }
1160
+
1161
+ return sum.toString(36);
1162
+ }
1163
+
1164
+ /**
1165
+ * Returns the index of an element within its parent
1166
+ * @param {HTMLElement} el
1167
+ * @return {number}
1168
+ */
1169
+ function _index(el) {
1170
+ var index = 0;
1171
+
1172
+ if (!el || !el.parentNode) {
1173
+ return -1;
1174
+ }
1175
+
1176
+ while (el && (el = el.previousElementSibling)) {
1177
+ if (el.nodeName.toUpperCase() !== 'TEMPLATE') {
1178
+ index++;
1179
+ }
1180
+ }
1181
+
1182
+ return index;
1183
+ }
1184
+
1185
+ function _throttle(callback, ms) {
1186
+ var args, _this;
1187
+
1188
+ return function () {
1189
+ if (args === void 0) {
1190
+ args = arguments;
1191
+ _this = this;
1192
+
1193
+ setTimeout(function () {
1194
+ if (args.length === 1) {
1195
+ callback.call(_this, args[0]);
1196
+ } else {
1197
+ callback.apply(_this, args);
1198
+ }
1199
+
1200
+ args = void 0;
1201
+ }, ms);
1202
+ }
1203
+ };
1204
+ }
1205
+
1206
+ function _extend(dst, src) {
1207
+ if (dst && src) {
1208
+ for (var key in src) {
1209
+ if (src.hasOwnProperty(key)) {
1210
+ dst[key] = src[key];
1211
+ }
1212
+ }
1213
+ }
1214
+
1215
+ return dst;
1216
+ }
1217
+
1218
+
1219
+ // Export utils
1220
+ Sortable.utils = {
1221
+ on: _on,
1222
+ off: _off,
1223
+ css: _css,
1224
+ find: _find,
1225
+ is: function (el, selector) {
1226
+ return !!_closest(el, selector, el);
1227
+ },
1228
+ extend: _extend,
1229
+ throttle: _throttle,
1230
+ closest: _closest,
1231
+ toggleClass: _toggleClass,
1232
+ index: _index
1233
+ };
1234
+
1235
+
1236
+ /**
1237
+ * Create sortable instance
1238
+ * @param {HTMLElement} el
1239
+ * @param {Object} [options]
1240
+ */
1241
+ Sortable.create = function (el, options) {
1242
+ return new Sortable(el, options);
1243
+ };
1244
+
1245
+
1246
+ // Export
1247
+ Sortable.version = '1.4.2';
1248
+ return Sortable;
1249
+ });