decidim-admin 0.0.1.alpha9 → 0.0.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of decidim-admin might be problematic. Click here for more details.

Files changed (119) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +33 -8
  3. data/Rakefile +0 -25
  4. data/app/assets/javascripts/decidim/admin/application.js.es6 +17 -10
  5. data/app/assets/javascripts/decidim/admin/sort_steps.js.es6 +20 -11
  6. data/app/assets/javascripts/decidim/admin/tab_focus.js.es6 +22 -0
  7. data/app/assets/stylesheets/decidim/admin/_forms.scss +10 -0
  8. data/app/assets/stylesheets/decidim/admin/_layout.scss +11 -0
  9. data/app/assets/stylesheets/decidim/admin/_tables.scss +4 -0
  10. data/app/assets/stylesheets/decidim/admin/application.scss +8 -2
  11. data/app/commands/decidim/admin/activate_participatory_process_step.rb +1 -1
  12. data/app/commands/decidim/admin/create_category.rb +44 -0
  13. data/app/commands/decidim/admin/create_feature.rb +48 -0
  14. data/app/commands/decidim/admin/create_participatory_process.rb +3 -6
  15. data/app/commands/decidim/admin/create_participatory_process_admin.rb +51 -0
  16. data/app/commands/decidim/admin/create_participatory_process_attachment.rb +44 -0
  17. data/app/commands/decidim/admin/create_participatory_process_step.rb +3 -3
  18. data/app/commands/decidim/admin/create_scope.rb +38 -0
  19. data/app/commands/decidim/admin/create_static_page.rb +40 -0
  20. data/app/commands/decidim/admin/destroy_category.rb +36 -0
  21. data/app/commands/decidim/admin/destroy_feature.rb +39 -0
  22. data/app/commands/decidim/admin/publish_participatory_process.rb +1 -1
  23. data/app/commands/decidim/admin/reorder_participatory_process_steps.rb +5 -2
  24. data/app/commands/decidim/admin/unpublish_participatory_process.rb +1 -1
  25. data/app/commands/decidim/admin/update_category.rb +48 -0
  26. data/app/commands/decidim/admin/update_organization.rb +49 -0
  27. data/app/commands/decidim/admin/update_participatory_process.rb +2 -2
  28. data/app/commands/decidim/admin/update_participatory_process_attachment.rb +49 -0
  29. data/app/commands/decidim/admin/update_participatory_process_step.rb +1 -1
  30. data/app/commands/decidim/admin/update_scope.rb +43 -0
  31. data/app/commands/decidim/admin/update_static_page.rb +45 -0
  32. data/app/constraints/decidim/admin/organization_dashboard_constraint.rb +5 -1
  33. data/app/controllers/decidim/admin/application_controller.rb +8 -0
  34. data/app/controllers/decidim/admin/categories_controller.rb +90 -0
  35. data/app/controllers/decidim/admin/concerns/participatory_process_admin.rb +31 -0
  36. data/app/controllers/decidim/admin/features_controller.rb +74 -0
  37. data/app/controllers/decidim/admin/organization_controller.rb +40 -0
  38. data/app/controllers/decidim/admin/participatory_process_attachments_controller.rb +84 -0
  39. data/app/controllers/decidim/admin/participatory_process_publications_controller.rb +2 -7
  40. data/app/controllers/decidim/admin/participatory_process_step_activations_controller.rb +6 -8
  41. data/app/controllers/decidim/admin/participatory_process_step_ordering_controller.rb +2 -4
  42. data/app/controllers/decidim/admin/participatory_process_steps_controller.rb +13 -11
  43. data/app/controllers/decidim/admin/participatory_process_user_roles_controller.rb +54 -0
  44. data/app/controllers/decidim/admin/participatory_processes_controller.rb +11 -6
  45. data/app/controllers/decidim/admin/scopes_controller.rb +79 -0
  46. data/app/controllers/decidim/admin/static_pages_controller.rb +94 -0
  47. data/app/forms/decidim/admin/category_form.rb +37 -0
  48. data/app/forms/decidim/admin/feature_form.rb +16 -0
  49. data/app/forms/decidim/admin/organization_form.rb +31 -0
  50. data/app/forms/decidim/admin/participatory_process_attachment_form.rb +19 -0
  51. data/app/forms/decidim/admin/participatory_process_form.rb +4 -7
  52. data/app/forms/decidim/admin/participatory_process_step_form.rb +12 -2
  53. data/app/forms/decidim/admin/participatory_process_user_role_form.rb +15 -0
  54. data/app/forms/decidim/admin/scope_form.rb +24 -0
  55. data/app/forms/decidim/admin/static_page_form.rb +30 -0
  56. data/app/helpers/decidim/admin/application_helper.rb +1 -0
  57. data/app/helpers/decidim/admin/aria_selected_link_to_helper.rb +28 -0
  58. data/app/helpers/decidim/admin/attributes_display_helper.rb +13 -5
  59. data/app/models/decidim/admin/abilities/admin_user.rb +34 -0
  60. data/app/models/decidim/admin/abilities/base.rb +19 -0
  61. data/app/models/decidim/admin/abilities/participatory_process_admin.rb +51 -0
  62. data/app/models/decidim/admin/participatory_process_user_role.rb +14 -0
  63. data/app/queries/decidim/admin/manageable_participatory_processes_for_user.rb +41 -0
  64. data/app/queries/decidim/admin/process_admin_roles_for_process.rb +35 -0
  65. data/app/views/decidim/admin/categories/_form.html.erb +12 -0
  66. data/app/views/decidim/admin/categories/edit.html.erb +9 -0
  67. data/app/views/decidim/admin/categories/index.html.erb +44 -0
  68. data/app/views/decidim/admin/categories/new.html.erb +9 -0
  69. data/app/views/decidim/admin/categories/show.html.erb +14 -0
  70. data/app/views/decidim/admin/features/_feature.html.erb +20 -0
  71. data/app/views/decidim/admin/features/_form.html.erb +3 -0
  72. data/app/views/decidim/admin/features/index.html.erb +23 -0
  73. data/app/views/decidim/admin/features/new.html.erb +9 -0
  74. data/app/views/decidim/admin/organization/_form.html.erb +23 -0
  75. data/app/views/decidim/admin/organization/edit.html.erb +11 -0
  76. data/app/views/decidim/admin/participatory_process_attachments/_form.html.erb +11 -0
  77. data/app/views/decidim/admin/participatory_process_attachments/edit.html.erb +9 -0
  78. data/app/views/decidim/admin/participatory_process_attachments/index.html.erb +37 -0
  79. data/app/views/decidim/admin/participatory_process_attachments/new.html.erb +9 -0
  80. data/app/views/decidim/admin/participatory_process_attachments/show.html.erb +25 -0
  81. data/app/views/decidim/admin/participatory_process_steps/_form.html.erb +2 -2
  82. data/app/views/decidim/admin/participatory_process_steps/edit.html.erb +1 -3
  83. data/app/views/decidim/admin/participatory_process_steps/{_table.html.erb → index.html.erb} +15 -11
  84. data/app/views/decidim/admin/participatory_process_steps/new.html.erb +1 -3
  85. data/app/views/decidim/admin/participatory_process_steps/show.html.erb +1 -4
  86. data/app/views/decidim/admin/participatory_process_user_roles/index.html.erb +34 -0
  87. data/app/views/decidim/admin/participatory_processes/_form.html.erb +2 -2
  88. data/app/views/decidim/admin/participatory_processes/edit.html.erb +13 -3
  89. data/app/views/decidim/admin/participatory_processes/index.html.erb +5 -14
  90. data/app/views/decidim/admin/participatory_processes/show.html.erb +19 -36
  91. data/app/views/decidim/admin/scopes/_form.html.erb +3 -0
  92. data/app/views/decidim/admin/scopes/edit.html.erb +11 -0
  93. data/app/views/decidim/admin/scopes/index.html.erb +38 -0
  94. data/app/views/decidim/admin/scopes/new.html.erb +11 -0
  95. data/app/views/decidim/admin/static_pages/_form.html.erb +13 -0
  96. data/app/views/decidim/admin/static_pages/edit.html.erb +11 -0
  97. data/app/views/decidim/admin/static_pages/index.html.erb +40 -0
  98. data/app/views/decidim/admin/static_pages/new.html.erb +11 -0
  99. data/app/views/decidim/admin/static_pages/show.html.erb +22 -0
  100. data/app/views/layouts/decidim/admin/_application.html.erb +40 -0
  101. data/app/views/layouts/decidim/admin/_sidebar.html.erb +5 -2
  102. data/app/views/layouts/decidim/admin/application.html.erb +3 -40
  103. data/app/views/layouts/decidim/admin/participatory_process.html.erb +54 -0
  104. data/config/i18n-tasks.yml +3 -2
  105. data/config/locales/ca.yml +138 -6
  106. data/config/locales/en.yml +191 -13
  107. data/config/locales/es.yml +139 -7
  108. data/config/routes.rb +23 -1
  109. data/db/migrate/20161102144648_add_admin_participatory_process_user_roles.rb +15 -0
  110. data/db/seeds.rb +21 -0
  111. data/lib/decidim/admin/engine.rb +10 -3
  112. data/lib/decidim/admin/features/base_controller.rb +33 -0
  113. data/lib/decidim/admin/features.rb +10 -0
  114. data/lib/decidim/admin.rb +1 -0
  115. data/vendor/assets/javascripts/html.sortable.js +691 -0
  116. metadata +98 -33
  117. data/LICENSE.txt +0 -619
  118. data/app/models/decidim/admin/abilities/admin.rb +0 -21
  119. data/vendor/assets/javascripts/html.sortable.min.js +0 -2
@@ -0,0 +1,691 @@
1
+ ;(function(root, factory) {
2
+ if (typeof define === 'function' && define.amd) {
3
+ define([], factory);
4
+ } else if (typeof exports === 'object') {
5
+ module.exports = factory();
6
+ } else {
7
+ root.sortable = factory();
8
+ }
9
+ }(this, function() {
10
+ /*
11
+ * HTML5 Sortable library
12
+ * https://github.com/voidberg/html5sortable
13
+ *
14
+ * Original code copyright 2012 Ali Farhadi.
15
+ * This version is mantained by Alexandru Badiu <andu@ctrlz.ro> & Lukas Oppermann <lukas@vea.re>
16
+ * jQuery-independent implementation by Nazar Mokrynskyi <nazar@mokrynskyi.com>
17
+ *
18
+ * Released under the MIT license.
19
+ */
20
+ 'use strict';
21
+ /*
22
+ * variables global to the plugin
23
+ */
24
+ var dragging;
25
+ var draggingHeight;
26
+ var placeholders = [];
27
+ var sortables = [];
28
+ /**
29
+ * Get or set data on element
30
+ * @param {Element} element
31
+ * @param {string} key
32
+ * @param {*} value
33
+ * @return {*}
34
+ */
35
+ var _data = function(element, key, value) {
36
+ if (value === undefined) {
37
+ return element && element.h5s && element.h5s.data && element.h5s.data[key];
38
+ } else {
39
+ element.h5s = element.h5s || {};
40
+ element.h5s.data = element.h5s.data || {};
41
+ element.h5s.data[key] = value;
42
+ }
43
+ };
44
+ /**
45
+ * Remove data from element
46
+ * @param {Element} element
47
+ */
48
+ var _removeData = function(element) {
49
+ if (element.h5s) {
50
+ delete element.h5s.data;
51
+ }
52
+ };
53
+ /**
54
+ * Cross-browser shortcut for actual `Element.matches` method,
55
+ * which has vendor prefix in older browsers
56
+ */
57
+ var matches;
58
+ switch (true) {
59
+ case 'matches' in window.Element.prototype:
60
+ matches = 'matches';
61
+ break;
62
+ case 'mozMatchesSelector' in window.Element.prototype:
63
+ matches = 'mozMatchesSelector';
64
+ break;
65
+ case 'msMatchesSelector' in window.Element.prototype:
66
+ matches = 'msMatchesSelector';
67
+ break;
68
+ case 'webkitMatchesSelector' in window.Element.prototype:
69
+ matches = 'webkitMatchesSelector';
70
+ break;
71
+ }
72
+ /**
73
+ * Filter only wanted nodes
74
+ * @param {Array|NodeList} nodes
75
+ * @param {Array/string} wanted
76
+ * @returns {Array}
77
+ */
78
+ var _filter = function(nodes, wanted) {
79
+ if (!wanted) {
80
+ return Array.prototype.slice.call(nodes);
81
+ }
82
+ var result = [];
83
+ for (var i = 0; i < nodes.length; ++i) {
84
+ if (typeof wanted === 'string' && nodes[i][matches](wanted)) {
85
+ result.push(nodes[i]);
86
+ }
87
+ if (wanted.indexOf(nodes[i]) !== -1) {
88
+ result.push(nodes[i]);
89
+ }
90
+ }
91
+ return result;
92
+ };
93
+ /**
94
+ * @param {Array|Element} element
95
+ * @param {Array|string} event
96
+ * @param {Function} callback
97
+ */
98
+ var _on = function(element, event, callback) {
99
+ if (element instanceof Array) {
100
+ for (var i = 0; i < element.length; ++i) {
101
+ _on(element[i], event, callback);
102
+ }
103
+ return;
104
+ }
105
+ element.addEventListener(event, callback);
106
+ element.h5s = element.h5s || {};
107
+ element.h5s.events = element.h5s.events || {};
108
+ element.h5s.events[event] = callback;
109
+ };
110
+ /**
111
+ * @param {Array|Element} element
112
+ * @param {Array|string} event
113
+ */
114
+ var _off = function(element, event) {
115
+ if (element instanceof Array) {
116
+ for (var i = 0; i < element.length; ++i) {
117
+ _off(element[i], event);
118
+ }
119
+ return;
120
+ }
121
+ if (element.h5s && element.h5s.events && element.h5s.events[event]) {
122
+ element.removeEventListener(event, element.h5s.events[event]);
123
+ delete element.h5s.events[event];
124
+ }
125
+ };
126
+ /**
127
+ * @param {Array|Element} element
128
+ * @param {string} attribute
129
+ * @param {*} value
130
+ */
131
+ var _attr = function(element, attribute, value) {
132
+ if (element instanceof Array) {
133
+ for (var i = 0; i < element.length; ++i) {
134
+ _attr(element[i], attribute, value);
135
+ }
136
+ return;
137
+ }
138
+ element.setAttribute(attribute, value);
139
+ };
140
+ /**
141
+ * @param {Array|Element} element
142
+ * @param {string} attribute
143
+ */
144
+ var _removeAttr = function(element, attribute) {
145
+ if (element instanceof Array) {
146
+ for (var i = 0; i < element.length; ++i) {
147
+ _removeAttr(element[i], attribute);
148
+ }
149
+ return;
150
+ }
151
+ element.removeAttribute(attribute);
152
+ };
153
+ /**
154
+ * @param {Element} element
155
+ * @returns {{left: *, top: *}}
156
+ */
157
+ var _offset = function(element) {
158
+ var rect = element.getClientRects()[0];
159
+ return {
160
+ left: rect.left + window.scrollX,
161
+ top: rect.top + window.scrollY
162
+ };
163
+ };
164
+ /*
165
+ * remove event handlers from items
166
+ * @param {Array|NodeList} items
167
+ */
168
+ var _removeItemEvents = function(items) {
169
+ _off(items, 'dragstart');
170
+ _off(items, 'dragend');
171
+ _off(items, 'selectstart');
172
+ _off(items, 'dragover');
173
+ _off(items, 'dragenter');
174
+ _off(items, 'drop');
175
+ };
176
+ /*
177
+ * Remove event handlers from sortable
178
+ * @param {Element} sortable a single sortable
179
+ */
180
+ var _removeSortableEvents = function(sortable) {
181
+ _off(sortable, 'dragover');
182
+ _off(sortable, 'dragenter');
183
+ _off(sortable, 'drop');
184
+ };
185
+ /*
186
+ * Attach ghost to dataTransfer object
187
+ * @param {Event} original event
188
+ * @param {object} ghost-object with item, x and y coordinates
189
+ */
190
+ var _attachGhost = function(event, ghost) {
191
+ // this needs to be set for HTML5 drag & drop to work
192
+ event.dataTransfer.effectAllowed = 'move';
193
+ event.dataTransfer.setData('text', '');
194
+
195
+ // check if setDragImage method is available
196
+ if (event.dataTransfer.setDragImage) {
197
+ event.dataTransfer.setDragImage(ghost.draggedItem, ghost.x, ghost.y);
198
+ }
199
+ };
200
+ /**
201
+ * _addGhostPos clones the dragged item and adds it as a Ghost item
202
+ * @param {Event} event - the event fired when dragstart is triggered
203
+ * @param {object} ghost - .draggedItem = Element
204
+ */
205
+ var _addGhostPos = function(event, ghost) {
206
+ if (!ghost.x) {
207
+ ghost.x = parseInt(event.pageX - _offset(ghost.draggedItem).left);
208
+ }
209
+ if (!ghost.y) {
210
+ ghost.y = parseInt(event.pageY - _offset(ghost.draggedItem).top);
211
+ }
212
+ return ghost;
213
+ };
214
+ /**
215
+ * _makeGhost decides which way to make a ghost and passes it to attachGhost
216
+ * @param {Element} draggedItem - the item that the user drags
217
+ */
218
+ var _makeGhost = function(draggedItem) {
219
+ return {
220
+ draggedItem: draggedItem
221
+ };
222
+ };
223
+ /**
224
+ * _getGhost constructs ghost and attaches it to dataTransfer
225
+ * @param {Event} event - the original drag event object
226
+ * @param {Element} draggedItem - the item that the user drags
227
+ */
228
+ // TODO: could draggedItem be replaced by event.target in all instances
229
+ var _getGhost = function(event, draggedItem) {
230
+ // add ghost item & draggedItem to ghost object
231
+ var ghost = _makeGhost(draggedItem);
232
+ // attach ghost position
233
+ ghost = _addGhostPos(event, ghost);
234
+ // attach ghost to dataTransfer
235
+ _attachGhost(event, ghost);
236
+ };
237
+ /*
238
+ * Remove data from sortable
239
+ * @param {Element} sortable a single sortable
240
+ */
241
+ var _removeSortableData = function(sortable) {
242
+ _removeData(sortable);
243
+ _removeAttr(sortable, 'aria-dropeffect');
244
+ };
245
+ /*
246
+ * Remove data from items
247
+ * @param {Array|Element} items
248
+ */
249
+ var _removeItemData = function(items) {
250
+ _removeAttr(items, 'aria-grabbed');
251
+ _removeAttr(items, 'draggable');
252
+ _removeAttr(items, 'role');
253
+ };
254
+ /*
255
+ * Check if two lists are connected
256
+ * @param {Element} curList
257
+ * @param {Element} destList
258
+ */
259
+ var _listsConnected = function(curList, destList) {
260
+ if (curList === destList) {
261
+ return true;
262
+ }
263
+ if (_data(curList, 'connectWith') !== undefined) {
264
+ return _data(curList, 'connectWith') === _data(destList, 'connectWith');
265
+ }
266
+ return false;
267
+ };
268
+ var _getHandles = function(items, handle) {
269
+ var result = [];
270
+ var handles;
271
+ if (!handle) {
272
+ return items;
273
+ }
274
+ for (var i = 0; i < items.length; ++i) {
275
+ handles = items[i].querySelectorAll(handle);
276
+ result = result.concat(Array.prototype.slice.call(handles));
277
+ }
278
+ return result;
279
+ };
280
+ /*
281
+ * Destroy the sortable
282
+ * @param {Element} sortableElement a single sortable
283
+ */
284
+ var _destroySortable = function(sortableElement) {
285
+ var opts = _data(sortableElement, 'opts') || {};
286
+ var items = _filter(sortableElement.children, opts.items);
287
+ var handles = _getHandles(items, opts.handle);
288
+ // remove event handlers & data from sortable
289
+ _removeSortableEvents(sortableElement);
290
+ _removeSortableData(sortableElement);
291
+ // remove event handlers & data from items
292
+ _off(handles, 'mousedown');
293
+ _removeItemEvents(items);
294
+ _removeItemData(items);
295
+ };
296
+ /*
297
+ * Enable the sortable
298
+ * @param {Element} sortableElement a single sortable
299
+ */
300
+ var _enableSortable = function(sortableElement) {
301
+ var opts = _data(sortableElement, 'opts');
302
+ var items = _filter(sortableElement.children, opts.items);
303
+ var handles = _getHandles(items, opts.handle);
304
+ _attr(sortableElement, 'aria-dropeffect', 'move');
305
+ _attr(handles, 'draggable', 'true');
306
+ // IE FIX for ghost
307
+ // can be disabled as it has the side effect that other events
308
+ // (e.g. click) will be ignored
309
+ var spanEl = (document || window.document).createElement('span');
310
+ if (typeof spanEl.dragDrop === 'function' && !opts.disableIEFix) {
311
+ _on(handles, 'mousedown', function() {
312
+ if (items.indexOf(this) !== -1) {
313
+ this.dragDrop();
314
+ } else {
315
+ var parent = this.parentElement;
316
+ while (items.indexOf(parent) === -1) {
317
+ parent = parent.parentElement;
318
+ }
319
+ parent.dragDrop();
320
+ }
321
+ });
322
+ }
323
+ };
324
+ /*
325
+ * Disable the sortable
326
+ * @param {Element} sortableElement a single sortable
327
+ */
328
+ var _disableSortable = function(sortableElement) {
329
+ var opts = _data(sortableElement, 'opts');
330
+ var items = _filter(sortableElement.children, opts.items);
331
+ var handles = _getHandles(items, opts.handle);
332
+ _attr(sortableElement, 'aria-dropeffect', 'none');
333
+ _attr(handles, 'draggable', 'false');
334
+ _off(handles, 'mousedown');
335
+ };
336
+ /*
337
+ * Reload the sortable
338
+ * @param {Element} sortableElement a single sortable
339
+ * @description events need to be removed to not be double bound
340
+ */
341
+ var _reloadSortable = function(sortableElement) {
342
+ var opts = _data(sortableElement, 'opts');
343
+ var items = _filter(sortableElement.children, opts.items);
344
+ var handles = _getHandles(items, opts.handle);
345
+ // remove event handlers from items
346
+ _removeItemEvents(items);
347
+ _off(handles, 'mousedown');
348
+ // remove event handlers from sortable
349
+ _removeSortableEvents(sortableElement);
350
+ };
351
+ /**
352
+ * Get position of the element relatively to its sibling elements
353
+ * @param {Element} element
354
+ * @returns {number}
355
+ */
356
+ var _index = function(element) {
357
+ if (!element.parentElement) {
358
+ return 0;
359
+ }
360
+ return Array.prototype.indexOf.call(element.parentElement.children, element);
361
+ };
362
+ /**
363
+ * Whether element is in DOM
364
+ * @param {Element} element
365
+ * @returns {boolean}
366
+ */
367
+ var _attached = function(element) {
368
+ return !!element.parentNode;
369
+ };
370
+ /**
371
+ * Convert HTML string into DOM element
372
+ * @param {Element|string} html
373
+ * @returns {Element}
374
+ */
375
+ var _html2element = function(html) {
376
+ if (typeof html !== 'string') {
377
+ return html;
378
+ }
379
+ var div = document.createElement('div');
380
+ div.innerHTML = html;
381
+ return div.firstChild;
382
+ };
383
+ /**
384
+ * Insert before target
385
+ * @param {Element} target
386
+ * @param {Element} element
387
+ */
388
+ var _before = function(target, element) {
389
+ target.parentElement.insertBefore(
390
+ element,
391
+ target
392
+ );
393
+ };
394
+ /**
395
+ * Insert after target
396
+ * @param {Element} target
397
+ * @param {Element} element
398
+ */
399
+ var _after = function(target, element) {
400
+ target.parentElement.insertBefore(
401
+ element,
402
+ target.nextElementSibling
403
+ );
404
+ };
405
+ /**
406
+ * Detach element from DOM
407
+ * @param {Element} element
408
+ */
409
+ var _detach = function(element) {
410
+ if (element.parentNode) {
411
+ element.parentNode.removeChild(element);
412
+ }
413
+ };
414
+ /**
415
+ * Make native event that can be dispatched afterwards
416
+ * @param {string} name
417
+ * @param {object} detail
418
+ * @returns {CustomEvent}
419
+ */
420
+ var _makeEvent = function(name, detail) {
421
+ var e = document.createEvent('Event');
422
+ if (detail) {
423
+ e.detail = detail;
424
+ }
425
+ e.initEvent(name, false, true);
426
+ return e;
427
+ };
428
+ /**
429
+ * @param {Element} sortableElement
430
+ * @param {CustomEvent} event
431
+ */
432
+ var _dispatchEventOnConnected = function(sortableElement, event) {
433
+ sortables.forEach(function(target) {
434
+ if (_listsConnected(sortableElement, target)) {
435
+ target.dispatchEvent(event);
436
+ }
437
+ });
438
+ };
439
+ /*
440
+ * Public sortable object
441
+ * @param {Array|NodeList} sortableElements
442
+ * @param {object|string} options|method
443
+ */
444
+ var sortable = function(sortableElements, options) {
445
+
446
+ var method = String(options);
447
+
448
+ options = (function(options) {
449
+ var result = {
450
+ connectWith: false,
451
+ placeholder: null,
452
+ // dragImage can be null or a Element
453
+ dragImage: null,
454
+ disableIEFix: false,
455
+ placeholderClass: 'sortable-placeholder',
456
+ draggingClass: 'sortable-dragging',
457
+ hoverClass: false
458
+ };
459
+ for (var option in options) {
460
+ result[option] = options[option];
461
+ }
462
+ return result;
463
+ })(options);
464
+
465
+ if (typeof sortableElements === 'string') {
466
+ sortableElements = document.querySelectorAll(sortableElements);
467
+ }
468
+
469
+ if (sortableElements instanceof window.Element) {
470
+ sortableElements = [sortableElements];
471
+ }
472
+
473
+ sortableElements = Array.prototype.slice.call(sortableElements);
474
+
475
+ /* TODO: maxstatements should be 25, fix and remove line below */
476
+ /*jshint maxstatements:false */
477
+ sortableElements.forEach(function(sortableElement) {
478
+
479
+ if (/enable|disable|destroy/.test(method)) {
480
+ sortable[method](sortableElement);
481
+ return;
482
+ }
483
+
484
+ // get options & set options on sortable
485
+ options = _data(sortableElement, 'opts') || options;
486
+ _data(sortableElement, 'opts', options);
487
+ // reset sortable
488
+ _reloadSortable(sortableElement);
489
+ // initialize
490
+ var items = _filter(sortableElement.children, options.items);
491
+ var index;
492
+ var startParent;
493
+ var placeholder = options.placeholder;
494
+ if (!placeholder) {
495
+ placeholder = document.createElement(
496
+ /^ul|ol$/i.test(sortableElement.tagName) ? 'li' : 'div'
497
+ );
498
+ }
499
+ placeholder = _html2element(placeholder);
500
+ placeholder.classList.add.apply(
501
+ placeholder.classList,
502
+ options.placeholderClass.split(' ')
503
+ );
504
+
505
+ // setup sortable ids
506
+ if (!sortableElement.getAttribute('data-sortable-id')) {
507
+ var id = sortables.length;
508
+ sortables[id] = sortableElement;
509
+ _attr(sortableElement, 'data-sortable-id', id);
510
+ _attr(items, 'data-item-sortable-id', id);
511
+ }
512
+
513
+ _data(sortableElement, 'items', options.items);
514
+ placeholders.push(placeholder);
515
+ if (options.connectWith) {
516
+ _data(sortableElement, 'connectWith', options.connectWith);
517
+ }
518
+
519
+ _enableSortable(sortableElement);
520
+ _attr(items, 'role', 'option');
521
+ _attr(items, 'aria-grabbed', 'false');
522
+
523
+ // Mouse over class
524
+ if (options.hoverClass) {
525
+ var hoverClass = 'sortable-over';
526
+ if (typeof options.hoverClass === 'string') {
527
+ hoverClass = options.hoverClass;
528
+ }
529
+
530
+ _on(items, 'mouseenter', function() {
531
+ this.classList.add(hoverClass);
532
+ });
533
+ _on(items, 'mouseleave', function() {
534
+ this.classList.remove(hoverClass);
535
+ });
536
+ }
537
+
538
+ // Handle drag events on draggable items
539
+ _on(items, 'dragstart', function(e) {
540
+ e.stopImmediatePropagation();
541
+
542
+ if (options.dragImage) {
543
+ _attachGhost(e, {
544
+ draggedItem: options.dragImage,
545
+ x: 0,
546
+ y: 0
547
+ });
548
+ console.log('WARNING: dragImage option is deprecated' +
549
+ ' and will be removed in the future!');
550
+ } else {
551
+ // add transparent clone or other ghost to cursor
552
+ _getGhost(e, this);
553
+ }
554
+ // cache selsection & add attr for dragging
555
+ this.classList.add(options.draggingClass);
556
+ dragging = this;
557
+ _attr(dragging, 'aria-grabbed', 'true');
558
+ // grab values
559
+ index = _index(dragging);
560
+ draggingHeight = parseInt(window.getComputedStyle(dragging).height);
561
+ startParent = this.parentElement;
562
+ // dispatch sortstart event on each element in group
563
+ _dispatchEventOnConnected(sortableElement, _makeEvent('sortstart', {
564
+ item: dragging,
565
+ placeholder: placeholder,
566
+ startparent: startParent
567
+ }));
568
+ });
569
+ // Handle drag events on draggable items
570
+ _on(items, 'dragend', function() {
571
+ var newParent;
572
+ if (!dragging) {
573
+ return;
574
+ }
575
+ // remove dragging attributes and show item
576
+ dragging.classList.remove(options.draggingClass);
577
+ _attr(dragging, 'aria-grabbed', 'false');
578
+ dragging.style.display = dragging.oldDisplay;
579
+ delete dragging.oldDisplay;
580
+
581
+ placeholders.forEach(_detach);
582
+ newParent = this.parentElement;
583
+ _dispatchEventOnConnected(sortableElement, _makeEvent('sortstop', {
584
+ item: dragging,
585
+ startparent: startParent
586
+ }));
587
+ if (index !== _index(dragging) || startParent !== newParent) {
588
+ _dispatchEventOnConnected(sortableElement, _makeEvent('sortupdate', {
589
+ item: dragging,
590
+ index: _filter(newParent.children, _data(newParent, 'items'))
591
+ .indexOf(dragging),
592
+ oldindex: items.indexOf(dragging),
593
+ elementIndex: _index(dragging),
594
+ oldElementIndex: index,
595
+ startparent: startParent,
596
+ endparent: newParent
597
+ }));
598
+ }
599
+ dragging = null;
600
+ draggingHeight = null;
601
+ });
602
+ // Handle drop event on sortable & placeholder
603
+ // TODO: REMOVE placeholder?????
604
+ _on([sortableElement, placeholder], 'drop', function(e) {
605
+ var visiblePlaceholder;
606
+ if (!_listsConnected(sortableElement, dragging.parentElement)) {
607
+ return;
608
+ }
609
+
610
+ e.preventDefault();
611
+ e.stopPropagation();
612
+ visiblePlaceholder = placeholders.filter(_attached)[0];
613
+ _after(visiblePlaceholder, dragging);
614
+ dragging.dispatchEvent(_makeEvent('dragend'));
615
+ });
616
+
617
+ // Handle dragover and dragenter events on draggable items
618
+ var onDragOverEnter = function(e) {
619
+ if (!_listsConnected(sortableElement, dragging.parentElement)) {
620
+ return;
621
+ }
622
+
623
+ e.preventDefault();
624
+ e.stopPropagation();
625
+ e.dataTransfer.dropEffect = 'move';
626
+ if (items.indexOf(this) !== -1) {
627
+ var thisHeight = parseInt(window.getComputedStyle(this).height);
628
+ var placeholderIndex = _index(placeholder);
629
+ var thisIndex = _index(this);
630
+ if (options.forcePlaceholderSize) {
631
+ placeholder.style.height = draggingHeight + 'px';
632
+ }
633
+
634
+ // Check if `this` is bigger than the draggable. If it is, we have to define a dead zone to prevent flickering
635
+ if (thisHeight > draggingHeight) {
636
+ // Dead zone?
637
+ var deadZone = thisHeight - draggingHeight;
638
+ var offsetTop = _offset(this).top;
639
+ if (placeholderIndex < thisIndex &&
640
+ e.pageY < offsetTop + deadZone) {
641
+ return;
642
+ }
643
+ if (placeholderIndex > thisIndex &&
644
+ e.pageY > offsetTop + thisHeight - deadZone) {
645
+ return;
646
+ }
647
+ }
648
+
649
+ if (dragging.oldDisplay === undefined) {
650
+ dragging.oldDisplay = dragging.style.display;
651
+ }
652
+ dragging.style.display = 'none';
653
+ if (placeholderIndex < thisIndex) {
654
+ _after(this, placeholder);
655
+ } else {
656
+ _before(this, placeholder);
657
+ }
658
+ // Intentionally violated chaining, it is more complex otherwise
659
+ placeholders
660
+ .filter(function(element) {return element !== placeholder;})
661
+ .forEach(_detach);
662
+ } else {
663
+ if (placeholders.indexOf(this) === -1 &&
664
+ !_filter(this.children, options.items).length) {
665
+ placeholders.forEach(_detach);
666
+ this.appendChild(placeholder);
667
+ }
668
+ }
669
+ };
670
+ _on(items.concat(sortableElement), 'dragover', onDragOverEnter);
671
+ _on(items.concat(sortableElement), 'dragenter', onDragOverEnter);
672
+ });
673
+
674
+ return sortableElements;
675
+ };
676
+
677
+ sortable.destroy = function(sortableElement) {
678
+ _destroySortable(sortableElement);
679
+ };
680
+
681
+ sortable.enable = function(sortableElement) {
682
+ _enableSortable(sortableElement);
683
+ };
684
+
685
+ sortable.disable = function(sortableElement) {
686
+ _disableSortable(sortableElement);
687
+ };
688
+
689
+
690
+ return sortable;
691
+ }));