promethee 1.3.2 → 1.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -0
  3. data/app/assets/stylesheets/promethee-edit/_move.sass +6 -4
  4. data/app/views/promethee/_edit.html.erb +14 -6
  5. data/app/views/promethee/components/aside/_edit.define.html.erb +14 -151
  6. data/app/views/promethee/components/aside/_icon.svg +3 -0
  7. data/app/views/promethee/components/column/_edit.define.html.erb +17 -31
  8. data/app/views/promethee/components/column/_icon.svg +3 -0
  9. data/app/views/promethee/components/cover/_edit.define.html.erb +16 -151
  10. data/app/views/promethee/components/cover/_icon.svg +3 -0
  11. data/app/views/promethee/components/image/_edit.define.html.erb +17 -149
  12. data/app/views/promethee/components/image/_icon.svg +3 -0
  13. data/app/views/promethee/components/row/_edit.define.html.erb +14 -150
  14. data/app/views/promethee/components/row/_icon.svg +3 -0
  15. data/app/views/promethee/components/slider/_edit.define.html.erb +14 -150
  16. data/app/views/promethee/components/slider/_edit.inspect.html.erb +43 -1
  17. data/app/views/promethee/components/slider/_edit.move.html.erb +6 -2
  18. data/app/views/promethee/components/slider/_icon.svg +3 -0
  19. data/app/views/promethee/components/text/_edit.define.html.erb +15 -150
  20. data/app/views/promethee/components/text/_icon.svg +3 -0
  21. data/app/views/promethee/components/video/_edit.define.html.erb +14 -29
  22. data/app/views/promethee/components/video/_icon.svg +3 -0
  23. data/app/views/promethee/edit/_move.html.erb +48 -21
  24. data/app/views/promethee/presets/_icon.image-with-text.svg +3 -0
  25. data/app/views/promethee/presets/_image-with-text.html.erb +33 -0
  26. data/app/views/promethee/utils/_summernote-config.html.erb +11 -5
  27. data/lib/promethee/rails/helper.rb +4 -0
  28. data/lib/promethee/rails/version.rb +1 -1
  29. data/vendor/assets/javascripts/ui-sortable.js +683 -0
  30. metadata +14 -3
@@ -2,15 +2,21 @@
2
2
  promethee.constant('summernoteConfig', {
3
3
  disableDragAndDrop: true,
4
4
  callbacks: {
5
+ // Remove text styles on paste
5
6
  onPaste: function(event) {
6
- // Remove text styles on paste
7
+ event.preventDefault();
8
+
9
+ // Get and trim clipboard content as paragraph
7
10
  var paragraph = document.createElement('p');
8
11
  paragraph.textContent = ((event.originalEvent || event).clipboardData || window.clipboardData).getData('Text').trim();
9
- event.preventDefault();
10
12
 
11
- setTimeout(function() {
12
- document.execCommand('insertNode', false, paragraph);
13
- }, 10);
13
+ // Delete selection if anything is selected (expected behaviour on paste)
14
+ if((window.getSelection !== undefined ? window.getSelection() : document.selection.createRange()).toString().length > 0) {
15
+ document.execCommand('delete', false);
16
+ }
17
+
18
+ // Insert trimmed clipboard content as paragraph
19
+ document.execCommand('insertHTML', false, paragraph.outerHTML);
14
20
  }
15
21
  },
16
22
  toolbar: [
@@ -22,6 +22,10 @@ module Promethee::Rails::Helper
22
22
  promethee_partials_for 'utils/_*.html.erb'
23
23
  end
24
24
 
25
+ def promethee_preset_partials
26
+ promethee_partials_for 'presets/_*.html.erb'
27
+ end
28
+
25
29
  # promethee_bem_classes 'promethee-edit__move__droppable', '--{{type}}', '--first'
26
30
  # -> promethee-edit__move__droppable promethee-edit__move__droppable--{{type}} promethee-edit__move__droppable--{{type}}--first"
27
31
  def promethee_bem_classes(*args)
@@ -1,5 +1,5 @@
1
1
  module Promethee
2
2
  module Rails
3
- VERSION = '1.3.2'
3
+ VERSION = '1.3.3'
4
4
  end
5
5
  end
@@ -0,0 +1,683 @@
1
+ /*
2
+ jQuery UI Sortable plugin wrapper
3
+ @param [ui-sortable] {object} Options to pass to $.fn.sortable() merged onto ui.config
4
+ */
5
+ angular
6
+ .module('ui.sortable', [])
7
+ .value('uiSortableConfig', {
8
+ // the default for jquery-ui sortable is "> *", we need to restrict this to
9
+ // ng-repeat items
10
+ // if the user uses
11
+ items: '> [ng-repeat],> [data-ng-repeat],> [x-ng-repeat]'
12
+ })
13
+ .directive('uiSortable', [
14
+ 'uiSortableConfig',
15
+ '$timeout',
16
+ '$log',
17
+ function(uiSortableConfig, $timeout, $log) {
18
+ return {
19
+ require: '?ngModel',
20
+ scope: {
21
+ ngModel: '=',
22
+ uiSortable: '=',
23
+ ////Expression bindings from html.
24
+ create: '&uiSortableCreate',
25
+ // helper:'&uiSortableHelper',
26
+ start: '&uiSortableStart',
27
+ activate: '&uiSortableActivate',
28
+ // sort:'&uiSortableSort',
29
+ // change:'&uiSortableChange',
30
+ // over:'&uiSortableOver',
31
+ // out:'&uiSortableOut',
32
+ beforeStop: '&uiSortableBeforeStop',
33
+ update: '&uiSortableUpdate',
34
+ remove: '&uiSortableRemove',
35
+ receive: '&uiSortableReceive',
36
+ deactivate: '&uiSortableDeactivate',
37
+ stop: '&uiSortableStop'
38
+ },
39
+ link: function(scope, element, attrs, ngModel) {
40
+ var savedNodes;
41
+ var helper;
42
+
43
+ function combineCallbacks(first, second) {
44
+ var firstIsFunc = typeof first === 'function';
45
+ var secondIsFunc = typeof second === 'function';
46
+ if (firstIsFunc && secondIsFunc) {
47
+ return function() {
48
+ first.apply(this, arguments);
49
+ second.apply(this, arguments);
50
+ };
51
+ } else if (secondIsFunc) {
52
+ return second;
53
+ }
54
+ return first;
55
+ }
56
+
57
+ function getSortableWidgetInstance(element) {
58
+ // this is a fix to support jquery-ui prior to v1.11.x
59
+ // otherwise we should be using `element.sortable('instance')`
60
+ var data = element.data('ui-sortable');
61
+ if (
62
+ data &&
63
+ typeof data === 'object' &&
64
+ data.widgetFullName === 'ui-sortable'
65
+ ) {
66
+ return data;
67
+ }
68
+ return null;
69
+ }
70
+
71
+ function setItemChildrenWidth(item) {
72
+ item.children().each(function() {
73
+ var $el = angular.element(this);
74
+
75
+ // Preserve the with of the element
76
+ $el.width($el.width());
77
+ });
78
+ }
79
+
80
+ function dummyHelper(e, item) {
81
+ return item;
82
+ }
83
+
84
+ function patchSortableOption(key, value) {
85
+ if (callbacks[key]) {
86
+ if (key === 'stop') {
87
+ // call apply after stop
88
+ value = combineCallbacks(value, function() {
89
+ scope.$apply();
90
+ });
91
+
92
+ value = combineCallbacks(value, afterStop);
93
+ }
94
+ // wrap the callback
95
+ value = combineCallbacks(callbacks[key], value);
96
+ } else if (wrappers[key]) {
97
+ value = wrappers[key](value);
98
+ }
99
+
100
+ // patch the options that need to have values set
101
+ if (!value && (key === 'items' || key === 'ui-model-items')) {
102
+ value = uiSortableConfig.items;
103
+ }
104
+
105
+ return value;
106
+ }
107
+
108
+ function patchUISortableOptions(
109
+ newOpts,
110
+ oldOpts,
111
+ sortableWidgetInstance
112
+ ) {
113
+ function addDummyOptionKey(value, key) {
114
+ if (!(key in opts)) {
115
+ // add the key in the opts object so that
116
+ // the patch function detects and handles it
117
+ opts[key] = null;
118
+ }
119
+ }
120
+ // for this directive to work we have to attach some callbacks
121
+ angular.forEach(callbacks, addDummyOptionKey);
122
+
123
+ // only initialize it in case we have to
124
+ // update some options of the sortable
125
+ var optsDiff = null;
126
+
127
+ if (oldOpts) {
128
+ // reset deleted options to default
129
+ var defaultOptions;
130
+ angular.forEach(oldOpts, function(oldValue, key) {
131
+ if (!newOpts || !(key in newOpts)) {
132
+ if (key in directiveOpts) {
133
+ if (key === 'ui-floating') {
134
+ opts[key] = 'auto';
135
+ } else {
136
+ opts[key] = patchSortableOption(key, undefined);
137
+ }
138
+ return;
139
+ }
140
+
141
+ if (!defaultOptions) {
142
+ defaultOptions = angular.element.ui.sortable().options;
143
+ }
144
+ var defaultValue = defaultOptions[key];
145
+ defaultValue = patchSortableOption(key, defaultValue);
146
+
147
+ if (!optsDiff) {
148
+ optsDiff = {};
149
+ }
150
+ optsDiff[key] = defaultValue;
151
+ opts[key] = defaultValue;
152
+ }
153
+ });
154
+ }
155
+
156
+ newOpts = angular.extend({}, newOpts);
157
+ // update changed options
158
+ // handle the custom option of the directive first
159
+ angular.forEach(newOpts, function(value, key) {
160
+ if (key in directiveOpts) {
161
+ if (
162
+ key === 'ui-floating' &&
163
+ (value === false || value === true) &&
164
+ sortableWidgetInstance
165
+ ) {
166
+ sortableWidgetInstance.floating = value;
167
+ }
168
+
169
+ if (
170
+ key === 'ui-preserve-size' &&
171
+ (value === false || value === true)
172
+ ) {
173
+ var userProvidedHelper = opts.helper;
174
+ newOpts.helper = function(e, item) {
175
+ if (opts['ui-preserve-size'] === true) {
176
+ setItemChildrenWidth(item);
177
+ }
178
+ return (userProvidedHelper || dummyHelper).apply(
179
+ this,
180
+ arguments
181
+ );
182
+ };
183
+ }
184
+
185
+ opts[key] = patchSortableOption(key, value);
186
+ }
187
+ });
188
+
189
+ // handle the normal option of the directive
190
+ angular.forEach(newOpts, function(value, key) {
191
+ if (key in directiveOpts) {
192
+ // the custom option of the directive are already handled
193
+ return;
194
+ }
195
+
196
+ value = patchSortableOption(key, value);
197
+
198
+ if (!optsDiff) {
199
+ optsDiff = {};
200
+ }
201
+ optsDiff[key] = value;
202
+ opts[key] = value;
203
+ });
204
+
205
+ return optsDiff;
206
+ }
207
+
208
+ function getPlaceholderElement(element) {
209
+ var placeholder = element.sortable('option', 'placeholder');
210
+
211
+ // placeholder.element will be a function if the placeholder, has
212
+ // been created (placeholder will be an object). If it hasn't
213
+ // been created, either placeholder will be false if no
214
+ // placeholder class was given or placeholder.element will be
215
+ // undefined if a class was given (placeholder will be a string)
216
+ if (
217
+ placeholder &&
218
+ placeholder.element &&
219
+ typeof placeholder.element === 'function'
220
+ ) {
221
+ var result = placeholder.element();
222
+ // workaround for jquery ui 1.9.x,
223
+ // not returning jquery collection
224
+ result = angular.element(result);
225
+ return result;
226
+ }
227
+ return null;
228
+ }
229
+
230
+ function getPlaceholderExcludesludes(element, placeholder) {
231
+ // exact match with the placeholder's class attribute to handle
232
+ // the case that multiple connected sortables exist and
233
+ // the placeholder option equals the class of sortable items
234
+ var notCssSelector = opts['ui-model-items'].replace(/[^,]*>/g, '');
235
+ var excludes = element.find(
236
+ '[class="' +
237
+ placeholder.attr('class') +
238
+ '"]:not(' +
239
+ notCssSelector +
240
+ ')'
241
+ );
242
+ return excludes;
243
+ }
244
+
245
+ function hasSortingHelper(element, ui) {
246
+ var helperOption = element.sortable('option', 'helper');
247
+ return (
248
+ helperOption === 'clone' ||
249
+ (typeof helperOption === 'function' &&
250
+ ui.item.sortable.isCustomHelperUsed())
251
+ );
252
+ }
253
+
254
+ function getSortingHelper(element, ui /*, savedNodes*/) {
255
+ var result = null;
256
+ if (
257
+ hasSortingHelper(element, ui) &&
258
+ element.sortable('option', 'appendTo') === 'parent'
259
+ ) {
260
+ // The .ui-sortable-helper element (that's the default class name)
261
+ result = helper;
262
+ }
263
+ return result;
264
+ }
265
+
266
+ // thanks jquery-ui
267
+ function isFloating(item) {
268
+ return (
269
+ /left|right/.test(item.css('float')) ||
270
+ /inline|table-cell/.test(item.css('display'))
271
+ );
272
+ }
273
+
274
+ function getElementContext(elementScopes, element) {
275
+ for (var i = 0; i < elementScopes.length; i++) {
276
+ var c = elementScopes[i];
277
+ if (c.element[0] === element[0]) {
278
+ return c;
279
+ }
280
+ }
281
+ }
282
+
283
+ function afterStop(e, ui) {
284
+ ui.item.sortable._destroy();
285
+ }
286
+
287
+ // return the index of ui.item among the items
288
+ // we can't just do ui.item.index() because there it might have siblings
289
+ // which are not items
290
+ function getItemIndex(item) {
291
+ return item
292
+ .parent()
293
+ .find(opts['ui-model-items'])
294
+ .index(item);
295
+ }
296
+
297
+ var opts = {};
298
+
299
+ // directive specific options
300
+ var directiveOpts = {
301
+ 'ui-floating': undefined,
302
+ 'ui-model-items': uiSortableConfig.items,
303
+ 'ui-preserve-size': undefined
304
+ };
305
+
306
+ var callbacks = {
307
+ create: null,
308
+ start: null,
309
+ activate: null,
310
+ // sort: null,
311
+ // change: null,
312
+ // over: null,
313
+ // out: null,
314
+ beforeStop: null,
315
+ update: null,
316
+ remove: null,
317
+ receive: null,
318
+ deactivate: null,
319
+ stop: null
320
+ };
321
+
322
+ var wrappers = {
323
+ helper: null
324
+ };
325
+
326
+ angular.extend(
327
+ opts,
328
+ directiveOpts,
329
+ uiSortableConfig,
330
+ scope.uiSortable
331
+ );
332
+
333
+ if (!angular.element.fn || !angular.element.fn.jquery) {
334
+ $log.error(
335
+ 'ui.sortable: jQuery should be included before AngularJS!'
336
+ );
337
+ return;
338
+ }
339
+
340
+ function wireUp() {
341
+ // When we add or remove elements, we need the sortable to 'refresh'
342
+ // so it can find the new/removed elements.
343
+ scope.$watchCollection('ngModel', function() {
344
+ // Timeout to let ng-repeat modify the DOM
345
+ $timeout(
346
+ function() {
347
+ // ensure that the jquery-ui-sortable widget instance
348
+ // is still bound to the directive's element
349
+ if (!!getSortableWidgetInstance(element)) {
350
+ element.sortable('refresh');
351
+ }
352
+ },
353
+ 0,
354
+ false
355
+ );
356
+ });
357
+
358
+ callbacks.start = function(e, ui) {
359
+ if (opts['ui-floating'] === 'auto') {
360
+ // since the drag has started, the element will be
361
+ // absolutely positioned, so we check its siblings
362
+ var siblings = ui.item.siblings();
363
+ var sortableWidgetInstance = getSortableWidgetInstance(
364
+ angular.element(e.target)
365
+ );
366
+ sortableWidgetInstance.floating = isFloating(siblings);
367
+ }
368
+
369
+ // Save the starting position of dragged item
370
+ var index = getItemIndex(ui.item);
371
+ ui.item.sortable = {
372
+ model: ngModel.$modelValue[index],
373
+ index: index,
374
+ source: element,
375
+ sourceList: ui.item.parent(),
376
+ sourceModel: ngModel.$modelValue,
377
+ cancel: function() {
378
+ ui.item.sortable._isCanceled = true;
379
+ },
380
+ isCanceled: function() {
381
+ return ui.item.sortable._isCanceled;
382
+ },
383
+ isCustomHelperUsed: function() {
384
+ return !!ui.item.sortable._isCustomHelperUsed;
385
+ },
386
+ _isCanceled: false,
387
+ _isCustomHelperUsed: ui.item.sortable._isCustomHelperUsed,
388
+ _destroy: function() {
389
+ angular.forEach(ui.item.sortable, function(value, key) {
390
+ ui.item.sortable[key] = undefined;
391
+ });
392
+ },
393
+ _connectedSortables: [],
394
+ _getElementContext: function(element) {
395
+ return getElementContext(this._connectedSortables, element);
396
+ }
397
+ };
398
+ };
399
+
400
+ callbacks.activate = function(e, ui) {
401
+ var isSourceContext = ui.item.sortable.source === element;
402
+ var savedNodesOrigin = isSourceContext
403
+ ? ui.item.sortable.sourceList
404
+ : element;
405
+ var elementContext = {
406
+ element: element,
407
+ scope: scope,
408
+ isSourceContext: isSourceContext,
409
+ savedNodesOrigin: savedNodesOrigin
410
+ };
411
+ // save the directive's scope so that it is accessible from ui.item.sortable
412
+ ui.item.sortable._connectedSortables.push(elementContext);
413
+
414
+ // We need to make a copy of the current element's contents so
415
+ // we can restore it after sortable has messed it up.
416
+ // This is inside activate (instead of start) in order to save
417
+ // both lists when dragging between connected lists.
418
+ savedNodes = savedNodesOrigin.contents();
419
+ helper = ui.helper;
420
+
421
+ // If this list has a placeholder (the connected lists won't),
422
+ // don't inlcude it in saved nodes.
423
+ var placeholder = getPlaceholderElement(element);
424
+ if (placeholder && placeholder.length) {
425
+ var excludes = getPlaceholderExcludesludes(
426
+ element,
427
+ placeholder
428
+ );
429
+ savedNodes = savedNodes.not(excludes);
430
+ }
431
+ };
432
+
433
+ callbacks.update = function(e, ui) {
434
+ // Save current drop position but only if this is not a second
435
+ // update that happens when moving between lists because then
436
+ // the value will be overwritten with the old value
437
+ if (!ui.item.sortable.received) {
438
+ ui.item.sortable.dropindex = getItemIndex(ui.item);
439
+ var droptarget = ui.item
440
+ .parent()
441
+ .closest(
442
+ '[ui-sortable], [data-ui-sortable], [x-ui-sortable]'
443
+ );
444
+ ui.item.sortable.droptarget = droptarget;
445
+ ui.item.sortable.droptargetList = ui.item.parent();
446
+
447
+ var droptargetContext = ui.item.sortable._getElementContext(
448
+ droptarget
449
+ );
450
+ ui.item.sortable.droptargetModel =
451
+ droptargetContext.scope.ngModel;
452
+
453
+ // Cancel the sort (let ng-repeat do the sort for us)
454
+ // Don't cancel if this is the received list because it has
455
+ // already been canceled in the other list, and trying to cancel
456
+ // here will mess up the DOM.
457
+ element.sortable('cancel');
458
+ }
459
+
460
+ // Put the nodes back exactly the way they started (this is very
461
+ // important because ng-repeat uses comment elements to delineate
462
+ // the start and stop of repeat sections and sortable doesn't
463
+ // respect their order (even if we cancel, the order of the
464
+ // comments are still messed up).
465
+ var sortingHelper =
466
+ !ui.item.sortable.received &&
467
+ getSortingHelper(element, ui, savedNodes);
468
+ if (sortingHelper && sortingHelper.length) {
469
+ // Restore all the savedNodes except from the sorting helper element.
470
+ // That way it will be garbage collected.
471
+ savedNodes = savedNodes.not(sortingHelper);
472
+ }
473
+ var elementContext = ui.item.sortable._getElementContext(element);
474
+ savedNodes.appendTo(elementContext.savedNodesOrigin);
475
+
476
+ // If this is the target connected list then
477
+ // it's safe to clear the restored nodes since:
478
+ // update is currently running and
479
+ // stop is not called for the target list.
480
+ if (ui.item.sortable.received) {
481
+ savedNodes = null;
482
+ }
483
+
484
+ // If received is true (an item was dropped in from another list)
485
+ // then we add the new item to this list otherwise wait until the
486
+ // stop event where we will know if it was a sort or item was
487
+ // moved here from another list
488
+ if (ui.item.sortable.received && !ui.item.sortable.isCanceled()) {
489
+ scope.$apply(function() {
490
+ ngModel.$modelValue.splice(
491
+ ui.item.sortable.dropindex,
492
+ 0,
493
+ ui.item.sortable.moved
494
+ );
495
+ });
496
+ scope.$emit('ui-sortable:moved', ui);
497
+ }
498
+ };
499
+
500
+ callbacks.stop = function(e, ui) {
501
+ // If the received flag hasn't be set on the item, this is a
502
+ // normal sort, if dropindex is set, the item was moved, so move
503
+ // the items in the list.
504
+ var wasMoved =
505
+ 'dropindex' in ui.item.sortable &&
506
+ !ui.item.sortable.isCanceled();
507
+
508
+ if (wasMoved && !ui.item.sortable.received) {
509
+ scope.$apply(function() {
510
+ ngModel.$modelValue.splice(
511
+ ui.item.sortable.dropindex,
512
+ 0,
513
+ ngModel.$modelValue.splice(ui.item.sortable.index, 1)[0]
514
+ );
515
+ });
516
+ scope.$emit('ui-sortable:moved', ui);
517
+ } else if (
518
+ !wasMoved &&
519
+ !angular.equals(
520
+ element.contents().toArray(),
521
+ savedNodes.toArray()
522
+ )
523
+ ) {
524
+ // if the item was not moved
525
+ // and the DOM element order has changed,
526
+ // then restore the elements
527
+ // so that the ngRepeat's comment are correct.
528
+
529
+ var sortingHelper = getSortingHelper(element, ui, savedNodes);
530
+ if (sortingHelper && sortingHelper.length) {
531
+ // Restore all the savedNodes except from the sorting helper element.
532
+ // That way it will be garbage collected.
533
+ savedNodes = savedNodes.not(sortingHelper);
534
+ }
535
+ var elementContext = ui.item.sortable._getElementContext(
536
+ element
537
+ );
538
+ savedNodes.appendTo(elementContext.savedNodesOrigin);
539
+ }
540
+
541
+ // It's now safe to clear the savedNodes and helper
542
+ // since stop is the last callback.
543
+ savedNodes = null;
544
+ helper = null;
545
+ };
546
+
547
+ callbacks.receive = function(e, ui) {
548
+ // An item was dropped here from another list, set a flag on the
549
+ // item.
550
+ ui.item.sortable.received = true;
551
+ };
552
+
553
+ callbacks.remove = function(e, ui) {
554
+ // Workaround for a problem observed in nested connected lists.
555
+ // There should be an 'update' event before 'remove' when moving
556
+ // elements. If the event did not fire, cancel sorting.
557
+ if (!('dropindex' in ui.item.sortable)) {
558
+ element.sortable('cancel');
559
+ ui.item.sortable.cancel();
560
+ }
561
+
562
+ // Remove the item from this list's model and copy data into item,
563
+ // so the next list can retrive it
564
+ if (!ui.item.sortable.isCanceled()) {
565
+ scope.$apply(function() {
566
+ ui.item.sortable.moved = ngModel.$modelValue.splice(
567
+ ui.item.sortable.index,
568
+ 1
569
+ )[0];
570
+ });
571
+ }
572
+ };
573
+
574
+ // setup attribute handlers
575
+ angular.forEach(callbacks, function(value, key) {
576
+ callbacks[key] = combineCallbacks(callbacks[key], function() {
577
+ var attrHandler = scope[key];
578
+ var attrHandlerFn;
579
+ if (
580
+ typeof attrHandler === 'function' &&
581
+ (
582
+ 'uiSortable' +
583
+ key.substring(0, 1).toUpperCase() +
584
+ key.substring(1)
585
+ ).length &&
586
+ typeof (attrHandlerFn = attrHandler()) === 'function'
587
+ ) {
588
+ attrHandlerFn.apply(this, arguments);
589
+ }
590
+ });
591
+ });
592
+
593
+ wrappers.helper = function(inner) {
594
+ if (inner && typeof inner === 'function') {
595
+ return function(e, item) {
596
+ var oldItemSortable = item.sortable;
597
+ var index = getItemIndex(item);
598
+
599
+ item.sortable = {
600
+ model: ngModel.$modelValue[index],
601
+ index: index,
602
+ source: element,
603
+ sourceList: item.parent(),
604
+ sourceModel: ngModel.$modelValue,
605
+ _restore: function() {
606
+ angular.forEach(item.sortable, function(value, key) {
607
+ item.sortable[key] = undefined;
608
+ });
609
+
610
+ item.sortable = oldItemSortable;
611
+ }
612
+ };
613
+
614
+ var innerResult = inner.apply(this, arguments);
615
+ item.sortable._restore();
616
+ item.sortable._isCustomHelperUsed = item !== innerResult;
617
+ return innerResult;
618
+ };
619
+ }
620
+ return inner;
621
+ };
622
+
623
+ scope.$watchCollection(
624
+ 'uiSortable',
625
+ function(newOpts, oldOpts) {
626
+ // ensure that the jquery-ui-sortable widget instance
627
+ // is still bound to the directive's element
628
+ var sortableWidgetInstance = getSortableWidgetInstance(element);
629
+ if (!!sortableWidgetInstance) {
630
+ var optsDiff = patchUISortableOptions(
631
+ newOpts,
632
+ oldOpts,
633
+ sortableWidgetInstance
634
+ );
635
+
636
+ if (optsDiff) {
637
+ element.sortable('option', optsDiff);
638
+ }
639
+ }
640
+ },
641
+ true
642
+ );
643
+
644
+ patchUISortableOptions(opts);
645
+ }
646
+
647
+ function init() {
648
+ if (ngModel) {
649
+ wireUp();
650
+ } else {
651
+ $log.info('ui.sortable: ngModel not provided!', element);
652
+ }
653
+
654
+ // Create sortable
655
+ element.sortable(opts);
656
+ }
657
+
658
+ function initIfEnabled() {
659
+ if (scope.uiSortable && scope.uiSortable.disabled) {
660
+ return false;
661
+ }
662
+
663
+ init();
664
+
665
+ // Stop Watcher
666
+ initIfEnabled.cancelWatcher();
667
+ initIfEnabled.cancelWatcher = angular.noop;
668
+
669
+ return true;
670
+ }
671
+
672
+ initIfEnabled.cancelWatcher = angular.noop;
673
+
674
+ if (!initIfEnabled()) {
675
+ initIfEnabled.cancelWatcher = scope.$watch(
676
+ 'uiSortable.disabled',
677
+ initIfEnabled
678
+ );
679
+ }
680
+ }
681
+ };
682
+ }
683
+ ]);