alchemy_cms 7.0.5 → 7.0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (29) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +1 -0
  3. data/CHANGELOG.md +6 -0
  4. data/Gemfile +6 -1
  5. data/alchemy_cms.gemspec +2 -3
  6. data/app/assets/javascripts/alchemy/admin.js +0 -1
  7. data/app/assets/javascripts/alchemy/alchemy.dialog.js.coffee +1 -1
  8. data/app/controllers/alchemy/admin/ingredients_controller.rb +2 -1
  9. data/app/models/alchemy/page/publisher.rb +14 -12
  10. data/app/models/alchemy/page_mutex.rb +31 -0
  11. data/app/models/alchemy/picture/url.rb +9 -1
  12. data/db/migrate/20231113104432_create_page_mutexes.rb +8 -0
  13. data/lib/alchemy/version.rb +1 -1
  14. data/lib/alchemy_cms.rb +0 -1
  15. data/vendor/assets/javascripts/jquery-ui/data.js +45 -0
  16. data/vendor/assets/javascripts/jquery-ui/ie.js +20 -0
  17. data/vendor/assets/javascripts/jquery-ui/keycode.js +51 -0
  18. data/vendor/assets/javascripts/jquery-ui/plugin.js +49 -0
  19. data/vendor/assets/javascripts/jquery-ui/safe-active-element.js +46 -0
  20. data/vendor/assets/javascripts/jquery-ui/safe-blur.js +27 -0
  21. data/vendor/assets/javascripts/jquery-ui/scroll-parent.js +50 -0
  22. data/vendor/assets/javascripts/jquery-ui/unique-id.js +54 -0
  23. data/vendor/assets/javascripts/jquery-ui/version.js +20 -0
  24. data/vendor/assets/javascripts/jquery-ui/widget.js +754 -0
  25. data/vendor/assets/javascripts/jquery-ui/widgets/draggable.js +1268 -0
  26. data/vendor/assets/javascripts/jquery-ui/widgets/mouse.js +241 -0
  27. data/vendor/assets/javascripts/jquery-ui/widgets/sortable.js +1623 -0
  28. data/vendor/assets/javascripts/jquery-ui/widgets/tabs.js +931 -0
  29. metadata +36 -34
@@ -0,0 +1,1623 @@
1
+ //= require jquery-ui/widgets/mouse
2
+ //= require jquery-ui/data
3
+ //= require jquery-ui/ie
4
+ //= require jquery-ui/scroll-parent
5
+ //= require jquery-ui/version
6
+ //= require jquery-ui/widget
7
+
8
+ /*!
9
+ * jQuery UI Sortable 1.13.0
10
+ * http://jqueryui.com
11
+ *
12
+ * Copyright jQuery Foundation and other contributors
13
+ * Released under the MIT license.
14
+ * http://jquery.org/license
15
+ */
16
+
17
+ //>>label: Sortable
18
+ //>>group: Interactions
19
+ //>>description: Enables items in a list to be sorted using the mouse.
20
+ //>>docs: http://api.jqueryui.com/sortable/
21
+ //>>demos: http://jqueryui.com/sortable/
22
+ //>>css.structure: ../../themes/base/sortable.css
23
+
24
+ ( function( factory ) {
25
+ "use strict";
26
+
27
+ if ( typeof define === "function" && define.amd ) {
28
+
29
+ // AMD. Register as an anonymous module.
30
+ define( [
31
+ "jquery",
32
+ "./mouse",
33
+ "../data",
34
+ "../ie",
35
+ "../scroll-parent",
36
+ "../version",
37
+ "../widget"
38
+ ], factory );
39
+ } else {
40
+
41
+ // Browser globals
42
+ factory( jQuery );
43
+ }
44
+ } )( function( $ ) {
45
+ "use strict";
46
+
47
+ return $.widget( "ui.sortable", $.ui.mouse, {
48
+ version: "1.13.0",
49
+ widgetEventPrefix: "sort",
50
+ ready: false,
51
+ options: {
52
+ appendTo: "parent",
53
+ axis: false,
54
+ connectWith: false,
55
+ containment: false,
56
+ cursor: "auto",
57
+ cursorAt: false,
58
+ dropOnEmpty: true,
59
+ forcePlaceholderSize: false,
60
+ forceHelperSize: false,
61
+ grid: false,
62
+ handle: false,
63
+ helper: "original",
64
+ items: "> *",
65
+ opacity: false,
66
+ placeholder: false,
67
+ revert: false,
68
+ scroll: true,
69
+ scrollSensitivity: 20,
70
+ scrollSpeed: 20,
71
+ scope: "default",
72
+ tolerance: "intersect",
73
+ zIndex: 1000,
74
+
75
+ // Callbacks
76
+ activate: null,
77
+ beforeStop: null,
78
+ change: null,
79
+ deactivate: null,
80
+ out: null,
81
+ over: null,
82
+ receive: null,
83
+ remove: null,
84
+ sort: null,
85
+ start: null,
86
+ stop: null,
87
+ update: null
88
+ },
89
+
90
+ _isOverAxis: function( x, reference, size ) {
91
+ return ( x >= reference ) && ( x < ( reference + size ) );
92
+ },
93
+
94
+ _isFloating: function( item ) {
95
+ return ( /left|right/ ).test( item.css( "float" ) ) ||
96
+ ( /inline|table-cell/ ).test( item.css( "display" ) );
97
+ },
98
+
99
+ _create: function() {
100
+ this.containerCache = {};
101
+ this._addClass( "ui-sortable" );
102
+
103
+ //Get the items
104
+ this.refresh();
105
+
106
+ //Let's determine the parent's offset
107
+ this.offset = this.element.offset();
108
+
109
+ //Initialize mouse events for interaction
110
+ this._mouseInit();
111
+
112
+ this._setHandleClassName();
113
+
114
+ //We're ready to go
115
+ this.ready = true;
116
+
117
+ },
118
+
119
+ _setOption: function( key, value ) {
120
+ this._super( key, value );
121
+
122
+ if ( key === "handle" ) {
123
+ this._setHandleClassName();
124
+ }
125
+ },
126
+
127
+ _setHandleClassName: function() {
128
+ var that = this;
129
+ this._removeClass( this.element.find( ".ui-sortable-handle" ), "ui-sortable-handle" );
130
+ $.each( this.items, function() {
131
+ that._addClass(
132
+ this.instance.options.handle ?
133
+ this.item.find( this.instance.options.handle ) :
134
+ this.item,
135
+ "ui-sortable-handle"
136
+ );
137
+ } );
138
+ },
139
+
140
+ _destroy: function() {
141
+ this._mouseDestroy();
142
+
143
+ for ( var i = this.items.length - 1; i >= 0; i-- ) {
144
+ this.items[ i ].item.removeData( this.widgetName + "-item" );
145
+ }
146
+
147
+ return this;
148
+ },
149
+
150
+ _mouseCapture: function( event, overrideHandle ) {
151
+ var currentItem = null,
152
+ validHandle = false,
153
+ that = this;
154
+
155
+ if ( this.reverting ) {
156
+ return false;
157
+ }
158
+
159
+ if ( this.options.disabled || this.options.type === "static" ) {
160
+ return false;
161
+ }
162
+
163
+ //We have to refresh the items data once first
164
+ this._refreshItems( event );
165
+
166
+ //Find out if the clicked node (or one of its parents) is a actual item in this.items
167
+ $( event.target ).parents().each( function() {
168
+ if ( $.data( this, that.widgetName + "-item" ) === that ) {
169
+ currentItem = $( this );
170
+ return false;
171
+ }
172
+ } );
173
+ if ( $.data( event.target, that.widgetName + "-item" ) === that ) {
174
+ currentItem = $( event.target );
175
+ }
176
+
177
+ if ( !currentItem ) {
178
+ return false;
179
+ }
180
+ if ( this.options.handle && !overrideHandle ) {
181
+ $( this.options.handle, currentItem ).find( "*" ).addBack().each( function() {
182
+ if ( this === event.target ) {
183
+ validHandle = true;
184
+ }
185
+ } );
186
+ if ( !validHandle ) {
187
+ return false;
188
+ }
189
+ }
190
+
191
+ this.currentItem = currentItem;
192
+ this._removeCurrentsFromItems();
193
+ return true;
194
+
195
+ },
196
+
197
+ _mouseStart: function( event, overrideHandle, noActivation ) {
198
+
199
+ var i, body,
200
+ o = this.options;
201
+
202
+ this.currentContainer = this;
203
+
204
+ //We only need to call refreshPositions, because the refreshItems call has been moved to
205
+ // mouseCapture
206
+ this.refreshPositions();
207
+
208
+ //Prepare the dragged items parent
209
+ this.appendTo = $( o.appendTo !== "parent" ?
210
+ o.appendTo :
211
+ this.currentItem.parent() );
212
+
213
+ //Create and append the visible helper
214
+ this.helper = this._createHelper( event );
215
+
216
+ //Cache the helper size
217
+ this._cacheHelperProportions();
218
+
219
+ /*
220
+ * - Position generation -
221
+ * This block generates everything position related - it's the core of draggables.
222
+ */
223
+
224
+ //Cache the margins of the original element
225
+ this._cacheMargins();
226
+
227
+ //The element's absolute position on the page minus margins
228
+ this.offset = this.currentItem.offset();
229
+ this.offset = {
230
+ top: this.offset.top - this.margins.top,
231
+ left: this.offset.left - this.margins.left
232
+ };
233
+
234
+ $.extend( this.offset, {
235
+ click: { //Where the click happened, relative to the element
236
+ left: event.pageX - this.offset.left,
237
+ top: event.pageY - this.offset.top
238
+ },
239
+
240
+ // This is a relative to absolute position minus the actual position calculation -
241
+ // only used for relative positioned helper
242
+ relative: this._getRelativeOffset()
243
+ } );
244
+
245
+ // After we get the helper offset, but before we get the parent offset we can
246
+ // change the helper's position to absolute
247
+ // TODO: Still need to figure out a way to make relative sorting possible
248
+ this.helper.css( "position", "absolute" );
249
+ this.cssPosition = this.helper.css( "position" );
250
+
251
+ //Adjust the mouse offset relative to the helper if "cursorAt" is supplied
252
+ if ( o.cursorAt ) {
253
+ this._adjustOffsetFromHelper( o.cursorAt );
254
+ }
255
+
256
+ //Cache the former DOM position
257
+ this.domPosition = {
258
+ prev: this.currentItem.prev()[ 0 ],
259
+ parent: this.currentItem.parent()[ 0 ]
260
+ };
261
+
262
+ // If the helper is not the original, hide the original so it's not playing any role during
263
+ // the drag, won't cause anything bad this way
264
+ if ( this.helper[ 0 ] !== this.currentItem[ 0 ] ) {
265
+ this.currentItem.hide();
266
+ }
267
+
268
+ //Create the placeholder
269
+ this._createPlaceholder();
270
+
271
+ //Get the next scrolling parent
272
+ this.scrollParent = this.placeholder.scrollParent();
273
+
274
+ $.extend( this.offset, {
275
+ parent: this._getParentOffset()
276
+ } );
277
+
278
+ //Set a containment if given in the options
279
+ if ( o.containment ) {
280
+ this._setContainment();
281
+ }
282
+
283
+ if ( o.cursor && o.cursor !== "auto" ) { // cursor option
284
+ body = this.document.find( "body" );
285
+
286
+ // Support: IE
287
+ this.storedCursor = body.css( "cursor" );
288
+ body.css( "cursor", o.cursor );
289
+
290
+ this.storedStylesheet =
291
+ $( "<style>*{ cursor: " + o.cursor + " !important; }</style>" ).appendTo( body );
292
+ }
293
+
294
+ // We need to make sure to grab the zIndex before setting the
295
+ // opacity, because setting the opacity to anything lower than 1
296
+ // causes the zIndex to change from "auto" to 0.
297
+ if ( o.zIndex ) { // zIndex option
298
+ if ( this.helper.css( "zIndex" ) ) {
299
+ this._storedZIndex = this.helper.css( "zIndex" );
300
+ }
301
+ this.helper.css( "zIndex", o.zIndex );
302
+ }
303
+
304
+ if ( o.opacity ) { // opacity option
305
+ if ( this.helper.css( "opacity" ) ) {
306
+ this._storedOpacity = this.helper.css( "opacity" );
307
+ }
308
+ this.helper.css( "opacity", o.opacity );
309
+ }
310
+
311
+ //Prepare scrolling
312
+ if ( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
313
+ this.scrollParent[ 0 ].tagName !== "HTML" ) {
314
+ this.overflowOffset = this.scrollParent.offset();
315
+ }
316
+
317
+ //Call callbacks
318
+ this._trigger( "start", event, this._uiHash() );
319
+
320
+ //Recache the helper size
321
+ if ( !this._preserveHelperProportions ) {
322
+ this._cacheHelperProportions();
323
+ }
324
+
325
+ //Post "activate" events to possible containers
326
+ if ( !noActivation ) {
327
+ for ( i = this.containers.length - 1; i >= 0; i-- ) {
328
+ this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) );
329
+ }
330
+ }
331
+
332
+ //Prepare possible droppables
333
+ if ( $.ui.ddmanager ) {
334
+ $.ui.ddmanager.current = this;
335
+ }
336
+
337
+ if ( $.ui.ddmanager && !o.dropBehaviour ) {
338
+ $.ui.ddmanager.prepareOffsets( this, event );
339
+ }
340
+
341
+ this.dragging = true;
342
+
343
+ this._addClass( this.helper, "ui-sortable-helper" );
344
+
345
+ //Move the helper, if needed
346
+ if ( !this.helper.parent().is( this.appendTo ) ) {
347
+ this.helper.detach().appendTo( this.appendTo );
348
+
349
+ //Update position
350
+ this.offset.parent = this._getParentOffset();
351
+ }
352
+
353
+ //Generate the original position
354
+ this.position = this.originalPosition = this._generatePosition( event );
355
+ this.originalPageX = event.pageX;
356
+ this.originalPageY = event.pageY;
357
+ this.lastPositionAbs = this.positionAbs = this._convertPositionTo( "absolute" );
358
+
359
+ this._mouseDrag( event );
360
+
361
+ return true;
362
+
363
+ },
364
+
365
+ _scroll: function( event ) {
366
+ var o = this.options,
367
+ scrolled = false;
368
+
369
+ if ( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
370
+ this.scrollParent[ 0 ].tagName !== "HTML" ) {
371
+
372
+ if ( ( this.overflowOffset.top + this.scrollParent[ 0 ].offsetHeight ) -
373
+ event.pageY < o.scrollSensitivity ) {
374
+ this.scrollParent[ 0 ].scrollTop =
375
+ scrolled = this.scrollParent[ 0 ].scrollTop + o.scrollSpeed;
376
+ } else if ( event.pageY - this.overflowOffset.top < o.scrollSensitivity ) {
377
+ this.scrollParent[ 0 ].scrollTop =
378
+ scrolled = this.scrollParent[ 0 ].scrollTop - o.scrollSpeed;
379
+ }
380
+
381
+ if ( ( this.overflowOffset.left + this.scrollParent[ 0 ].offsetWidth ) -
382
+ event.pageX < o.scrollSensitivity ) {
383
+ this.scrollParent[ 0 ].scrollLeft = scrolled =
384
+ this.scrollParent[ 0 ].scrollLeft + o.scrollSpeed;
385
+ } else if ( event.pageX - this.overflowOffset.left < o.scrollSensitivity ) {
386
+ this.scrollParent[ 0 ].scrollLeft = scrolled =
387
+ this.scrollParent[ 0 ].scrollLeft - o.scrollSpeed;
388
+ }
389
+
390
+ } else {
391
+
392
+ if ( event.pageY - this.document.scrollTop() < o.scrollSensitivity ) {
393
+ scrolled = this.document.scrollTop( this.document.scrollTop() - o.scrollSpeed );
394
+ } else if ( this.window.height() - ( event.pageY - this.document.scrollTop() ) <
395
+ o.scrollSensitivity ) {
396
+ scrolled = this.document.scrollTop( this.document.scrollTop() + o.scrollSpeed );
397
+ }
398
+
399
+ if ( event.pageX - this.document.scrollLeft() < o.scrollSensitivity ) {
400
+ scrolled = this.document.scrollLeft(
401
+ this.document.scrollLeft() - o.scrollSpeed
402
+ );
403
+ } else if ( this.window.width() - ( event.pageX - this.document.scrollLeft() ) <
404
+ o.scrollSensitivity ) {
405
+ scrolled = this.document.scrollLeft(
406
+ this.document.scrollLeft() + o.scrollSpeed
407
+ );
408
+ }
409
+
410
+ }
411
+
412
+ return scrolled;
413
+ },
414
+
415
+ _mouseDrag: function( event ) {
416
+ var i, item, itemElement, intersection,
417
+ o = this.options;
418
+
419
+ //Compute the helpers position
420
+ this.position = this._generatePosition( event );
421
+ this.positionAbs = this._convertPositionTo( "absolute" );
422
+
423
+ //Set the helper position
424
+ if ( !this.options.axis || this.options.axis !== "y" ) {
425
+ this.helper[ 0 ].style.left = this.position.left + "px";
426
+ }
427
+ if ( !this.options.axis || this.options.axis !== "x" ) {
428
+ this.helper[ 0 ].style.top = this.position.top + "px";
429
+ }
430
+
431
+ //Post events to containers
432
+ this._contactContainers( event );
433
+
434
+ if ( this.innermostContainer !== null ) {
435
+
436
+ //Do scrolling
437
+ if ( o.scroll ) {
438
+ if ( this._scroll( event ) !== false ) {
439
+
440
+ //Update item positions used in position checks
441
+ this._refreshItemPositions( true );
442
+
443
+ if ( $.ui.ddmanager && !o.dropBehaviour ) {
444
+ $.ui.ddmanager.prepareOffsets( this, event );
445
+ }
446
+ }
447
+ }
448
+
449
+ this.dragDirection = {
450
+ vertical: this._getDragVerticalDirection(),
451
+ horizontal: this._getDragHorizontalDirection()
452
+ };
453
+
454
+ //Rearrange
455
+ for ( i = this.items.length - 1; i >= 0; i-- ) {
456
+
457
+ //Cache variables and intersection, continue if no intersection
458
+ item = this.items[ i ];
459
+ itemElement = item.item[ 0 ];
460
+ intersection = this._intersectsWithPointer( item );
461
+ if ( !intersection ) {
462
+ continue;
463
+ }
464
+
465
+ // Only put the placeholder inside the current Container, skip all
466
+ // items from other containers. This works because when moving
467
+ // an item from one container to another the
468
+ // currentContainer is switched before the placeholder is moved.
469
+ //
470
+ // Without this, moving items in "sub-sortables" can cause
471
+ // the placeholder to jitter between the outer and inner container.
472
+ if ( item.instance !== this.currentContainer ) {
473
+ continue;
474
+ }
475
+
476
+ // Cannot intersect with itself
477
+ // no useless actions that have been done before
478
+ // no action if the item moved is the parent of the item checked
479
+ if ( itemElement !== this.currentItem[ 0 ] &&
480
+ this.placeholder[ intersection === 1 ?
481
+ "next" : "prev" ]()[ 0 ] !== itemElement &&
482
+ !$.contains( this.placeholder[ 0 ], itemElement ) &&
483
+ ( this.options.type === "semi-dynamic" ?
484
+ !$.contains( this.element[ 0 ], itemElement ) :
485
+ true
486
+ )
487
+ ) {
488
+
489
+ this.direction = intersection === 1 ? "down" : "up";
490
+
491
+ if ( this.options.tolerance === "pointer" ||
492
+ this._intersectsWithSides( item ) ) {
493
+ this._rearrange( event, item );
494
+ } else {
495
+ break;
496
+ }
497
+
498
+ this._trigger( "change", event, this._uiHash() );
499
+ break;
500
+ }
501
+ }
502
+ }
503
+
504
+ //Interconnect with droppables
505
+ if ( $.ui.ddmanager ) {
506
+ $.ui.ddmanager.drag( this, event );
507
+ }
508
+
509
+ //Call callbacks
510
+ this._trigger( "sort", event, this._uiHash() );
511
+
512
+ this.lastPositionAbs = this.positionAbs;
513
+ return false;
514
+
515
+ },
516
+
517
+ _mouseStop: function( event, noPropagation ) {
518
+
519
+ if ( !event ) {
520
+ return;
521
+ }
522
+
523
+ //If we are using droppables, inform the manager about the drop
524
+ if ( $.ui.ddmanager && !this.options.dropBehaviour ) {
525
+ $.ui.ddmanager.drop( this, event );
526
+ }
527
+
528
+ if ( this.options.revert ) {
529
+ var that = this,
530
+ cur = this.placeholder.offset(),
531
+ axis = this.options.axis,
532
+ animation = {};
533
+
534
+ if ( !axis || axis === "x" ) {
535
+ animation.left = cur.left - this.offset.parent.left - this.margins.left +
536
+ ( this.offsetParent[ 0 ] === this.document[ 0 ].body ?
537
+ 0 :
538
+ this.offsetParent[ 0 ].scrollLeft
539
+ );
540
+ }
541
+ if ( !axis || axis === "y" ) {
542
+ animation.top = cur.top - this.offset.parent.top - this.margins.top +
543
+ ( this.offsetParent[ 0 ] === this.document[ 0 ].body ?
544
+ 0 :
545
+ this.offsetParent[ 0 ].scrollTop
546
+ );
547
+ }
548
+ this.reverting = true;
549
+ $( this.helper ).animate(
550
+ animation,
551
+ parseInt( this.options.revert, 10 ) || 500,
552
+ function() {
553
+ that._clear( event );
554
+ }
555
+ );
556
+ } else {
557
+ this._clear( event, noPropagation );
558
+ }
559
+
560
+ return false;
561
+
562
+ },
563
+
564
+ cancel: function() {
565
+
566
+ if ( this.dragging ) {
567
+
568
+ this._mouseUp( new $.Event( "mouseup", { target: null } ) );
569
+
570
+ if ( this.options.helper === "original" ) {
571
+ this.currentItem.css( this._storedCSS );
572
+ this._removeClass( this.currentItem, "ui-sortable-helper" );
573
+ } else {
574
+ this.currentItem.show();
575
+ }
576
+
577
+ //Post deactivating events to containers
578
+ for ( var i = this.containers.length - 1; i >= 0; i-- ) {
579
+ this.containers[ i ]._trigger( "deactivate", null, this._uiHash( this ) );
580
+ if ( this.containers[ i ].containerCache.over ) {
581
+ this.containers[ i ]._trigger( "out", null, this._uiHash( this ) );
582
+ this.containers[ i ].containerCache.over = 0;
583
+ }
584
+ }
585
+
586
+ }
587
+
588
+ if ( this.placeholder ) {
589
+
590
+ //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately,
591
+ // it unbinds ALL events from the original node!
592
+ if ( this.placeholder[ 0 ].parentNode ) {
593
+ this.placeholder[ 0 ].parentNode.removeChild( this.placeholder[ 0 ] );
594
+ }
595
+ if ( this.options.helper !== "original" && this.helper &&
596
+ this.helper[ 0 ].parentNode ) {
597
+ this.helper.remove();
598
+ }
599
+
600
+ $.extend( this, {
601
+ helper: null,
602
+ dragging: false,
603
+ reverting: false,
604
+ _noFinalSort: null
605
+ } );
606
+
607
+ if ( this.domPosition.prev ) {
608
+ $( this.domPosition.prev ).after( this.currentItem );
609
+ } else {
610
+ $( this.domPosition.parent ).prepend( this.currentItem );
611
+ }
612
+ }
613
+
614
+ return this;
615
+
616
+ },
617
+
618
+ serialize: function( o ) {
619
+
620
+ var items = this._getItemsAsjQuery( o && o.connected ),
621
+ str = [];
622
+ o = o || {};
623
+
624
+ $( items ).each( function() {
625
+ var res = ( $( o.item || this ).attr( o.attribute || "id" ) || "" )
626
+ .match( o.expression || ( /(.+)[\-=_](.+)/ ) );
627
+ if ( res ) {
628
+ str.push(
629
+ ( o.key || res[ 1 ] + "[]" ) +
630
+ "=" + ( o.key && o.expression ? res[ 1 ] : res[ 2 ] ) );
631
+ }
632
+ } );
633
+
634
+ if ( !str.length && o.key ) {
635
+ str.push( o.key + "=" );
636
+ }
637
+
638
+ return str.join( "&" );
639
+
640
+ },
641
+
642
+ toArray: function( o ) {
643
+
644
+ var items = this._getItemsAsjQuery( o && o.connected ),
645
+ ret = [];
646
+
647
+ o = o || {};
648
+
649
+ items.each( function() {
650
+ ret.push( $( o.item || this ).attr( o.attribute || "id" ) || "" );
651
+ } );
652
+ return ret;
653
+
654
+ },
655
+
656
+ /* Be careful with the following core functions */
657
+ _intersectsWith: function( item ) {
658
+
659
+ var x1 = this.positionAbs.left,
660
+ x2 = x1 + this.helperProportions.width,
661
+ y1 = this.positionAbs.top,
662
+ y2 = y1 + this.helperProportions.height,
663
+ l = item.left,
664
+ r = l + item.width,
665
+ t = item.top,
666
+ b = t + item.height,
667
+ dyClick = this.offset.click.top,
668
+ dxClick = this.offset.click.left,
669
+ isOverElementHeight = ( this.options.axis === "x" ) || ( ( y1 + dyClick ) > t &&
670
+ ( y1 + dyClick ) < b ),
671
+ isOverElementWidth = ( this.options.axis === "y" ) || ( ( x1 + dxClick ) > l &&
672
+ ( x1 + dxClick ) < r ),
673
+ isOverElement = isOverElementHeight && isOverElementWidth;
674
+
675
+ if ( this.options.tolerance === "pointer" ||
676
+ this.options.forcePointerForContainers ||
677
+ ( this.options.tolerance !== "pointer" &&
678
+ this.helperProportions[ this.floating ? "width" : "height" ] >
679
+ item[ this.floating ? "width" : "height" ] )
680
+ ) {
681
+ return isOverElement;
682
+ } else {
683
+
684
+ return ( l < x1 + ( this.helperProportions.width / 2 ) && // Right Half
685
+ x2 - ( this.helperProportions.width / 2 ) < r && // Left Half
686
+ t < y1 + ( this.helperProportions.height / 2 ) && // Bottom Half
687
+ y2 - ( this.helperProportions.height / 2 ) < b ); // Top Half
688
+
689
+ }
690
+ },
691
+
692
+ _intersectsWithPointer: function( item ) {
693
+ var verticalDirection, horizontalDirection,
694
+ isOverElementHeight = ( this.options.axis === "x" ) ||
695
+ this._isOverAxis(
696
+ this.positionAbs.top + this.offset.click.top, item.top, item.height ),
697
+ isOverElementWidth = ( this.options.axis === "y" ) ||
698
+ this._isOverAxis(
699
+ this.positionAbs.left + this.offset.click.left, item.left, item.width ),
700
+ isOverElement = isOverElementHeight && isOverElementWidth;
701
+
702
+ if ( !isOverElement ) {
703
+ return false;
704
+ }
705
+
706
+ verticalDirection = this.dragDirection.vertical;
707
+ horizontalDirection = this.dragDirection.horizontal;
708
+
709
+ return this.floating ?
710
+ ( ( horizontalDirection === "right" || verticalDirection === "down" ) ? 2 : 1 ) :
711
+ ( verticalDirection && ( verticalDirection === "down" ? 2 : 1 ) );
712
+
713
+ },
714
+
715
+ _intersectsWithSides: function( item ) {
716
+
717
+ var isOverBottomHalf = this._isOverAxis( this.positionAbs.top +
718
+ this.offset.click.top, item.top + ( item.height / 2 ), item.height ),
719
+ isOverRightHalf = this._isOverAxis( this.positionAbs.left +
720
+ this.offset.click.left, item.left + ( item.width / 2 ), item.width ),
721
+ verticalDirection = this.dragDirection.vertical,
722
+ horizontalDirection = this.dragDirection.horizontal;
723
+
724
+ if ( this.floating && horizontalDirection ) {
725
+ return ( ( horizontalDirection === "right" && isOverRightHalf ) ||
726
+ ( horizontalDirection === "left" && !isOverRightHalf ) );
727
+ } else {
728
+ return verticalDirection && ( ( verticalDirection === "down" && isOverBottomHalf ) ||
729
+ ( verticalDirection === "up" && !isOverBottomHalf ) );
730
+ }
731
+
732
+ },
733
+
734
+ _getDragVerticalDirection: function() {
735
+ var delta = this.positionAbs.top - this.lastPositionAbs.top;
736
+ return delta !== 0 && ( delta > 0 ? "down" : "up" );
737
+ },
738
+
739
+ _getDragHorizontalDirection: function() {
740
+ var delta = this.positionAbs.left - this.lastPositionAbs.left;
741
+ return delta !== 0 && ( delta > 0 ? "right" : "left" );
742
+ },
743
+
744
+ refresh: function( event ) {
745
+ this._refreshItems( event );
746
+ this._setHandleClassName();
747
+ this.refreshPositions();
748
+ return this;
749
+ },
750
+
751
+ _connectWith: function() {
752
+ var options = this.options;
753
+ return options.connectWith.constructor === String ?
754
+ [ options.connectWith ] :
755
+ options.connectWith;
756
+ },
757
+
758
+ _getItemsAsjQuery: function( connected ) {
759
+
760
+ var i, j, cur, inst,
761
+ items = [],
762
+ queries = [],
763
+ connectWith = this._connectWith();
764
+
765
+ if ( connectWith && connected ) {
766
+ for ( i = connectWith.length - 1; i >= 0; i-- ) {
767
+ cur = $( connectWith[ i ], this.document[ 0 ] );
768
+ for ( j = cur.length - 1; j >= 0; j-- ) {
769
+ inst = $.data( cur[ j ], this.widgetFullName );
770
+ if ( inst && inst !== this && !inst.options.disabled ) {
771
+ queries.push( [ typeof inst.options.items === "function" ?
772
+ inst.options.items.call( inst.element ) :
773
+ $( inst.options.items, inst.element )
774
+ .not( ".ui-sortable-helper" )
775
+ .not( ".ui-sortable-placeholder" ), inst ] );
776
+ }
777
+ }
778
+ }
779
+ }
780
+
781
+ queries.push( [ typeof this.options.items === "function" ?
782
+ this.options.items
783
+ .call( this.element, null, { options: this.options, item: this.currentItem } ) :
784
+ $( this.options.items, this.element )
785
+ .not( ".ui-sortable-helper" )
786
+ .not( ".ui-sortable-placeholder" ), this ] );
787
+
788
+ function addItems() {
789
+ items.push( this );
790
+ }
791
+ for ( i = queries.length - 1; i >= 0; i-- ) {
792
+ queries[ i ][ 0 ].each( addItems );
793
+ }
794
+
795
+ return $( items );
796
+
797
+ },
798
+
799
+ _removeCurrentsFromItems: function() {
800
+
801
+ var list = this.currentItem.find( ":data(" + this.widgetName + "-item)" );
802
+
803
+ this.items = $.grep( this.items, function( item ) {
804
+ for ( var j = 0; j < list.length; j++ ) {
805
+ if ( list[ j ] === item.item[ 0 ] ) {
806
+ return false;
807
+ }
808
+ }
809
+ return true;
810
+ } );
811
+
812
+ },
813
+
814
+ _refreshItems: function( event ) {
815
+
816
+ this.items = [];
817
+ this.containers = [ this ];
818
+
819
+ var i, j, cur, inst, targetData, _queries, item, queriesLength,
820
+ items = this.items,
821
+ queries = [ [ typeof this.options.items === "function" ?
822
+ this.options.items.call( this.element[ 0 ], event, { item: this.currentItem } ) :
823
+ $( this.options.items, this.element ), this ] ],
824
+ connectWith = this._connectWith();
825
+
826
+ //Shouldn't be run the first time through due to massive slow-down
827
+ if ( connectWith && this.ready ) {
828
+ for ( i = connectWith.length - 1; i >= 0; i-- ) {
829
+ cur = $( connectWith[ i ], this.document[ 0 ] );
830
+ for ( j = cur.length - 1; j >= 0; j-- ) {
831
+ inst = $.data( cur[ j ], this.widgetFullName );
832
+ if ( inst && inst !== this && !inst.options.disabled ) {
833
+ queries.push( [ typeof inst.options.items === "function" ?
834
+ inst.options.items
835
+ .call( inst.element[ 0 ], event, { item: this.currentItem } ) :
836
+ $( inst.options.items, inst.element ), inst ] );
837
+ this.containers.push( inst );
838
+ }
839
+ }
840
+ }
841
+ }
842
+
843
+ for ( i = queries.length - 1; i >= 0; i-- ) {
844
+ targetData = queries[ i ][ 1 ];
845
+ _queries = queries[ i ][ 0 ];
846
+
847
+ for ( j = 0, queriesLength = _queries.length; j < queriesLength; j++ ) {
848
+ item = $( _queries[ j ] );
849
+
850
+ // Data for target checking (mouse manager)
851
+ item.data( this.widgetName + "-item", targetData );
852
+
853
+ items.push( {
854
+ item: item,
855
+ instance: targetData,
856
+ width: 0, height: 0,
857
+ left: 0, top: 0
858
+ } );
859
+ }
860
+ }
861
+
862
+ },
863
+
864
+ _refreshItemPositions: function( fast ) {
865
+ var i, item, t, p;
866
+
867
+ for ( i = this.items.length - 1; i >= 0; i-- ) {
868
+ item = this.items[ i ];
869
+
870
+ //We ignore calculating positions of all connected containers when we're not over them
871
+ if ( this.currentContainer && item.instance !== this.currentContainer &&
872
+ item.item[ 0 ] !== this.currentItem[ 0 ] ) {
873
+ continue;
874
+ }
875
+
876
+ t = this.options.toleranceElement ?
877
+ $( this.options.toleranceElement, item.item ) :
878
+ item.item;
879
+
880
+ if ( !fast ) {
881
+ item.width = t.outerWidth();
882
+ item.height = t.outerHeight();
883
+ }
884
+
885
+ p = t.offset();
886
+ item.left = p.left;
887
+ item.top = p.top;
888
+ }
889
+ },
890
+
891
+ refreshPositions: function( fast ) {
892
+
893
+ // Determine whether items are being displayed horizontally
894
+ this.floating = this.items.length ?
895
+ this.options.axis === "x" || this._isFloating( this.items[ 0 ].item ) :
896
+ false;
897
+
898
+ if ( this.innermostContainer !== null ) {
899
+ this._refreshItemPositions( fast );
900
+ }
901
+
902
+ var i, p;
903
+
904
+ if ( this.options.custom && this.options.custom.refreshContainers ) {
905
+ this.options.custom.refreshContainers.call( this );
906
+ } else {
907
+ for ( i = this.containers.length - 1; i >= 0; i-- ) {
908
+ p = this.containers[ i ].element.offset();
909
+ this.containers[ i ].containerCache.left = p.left;
910
+ this.containers[ i ].containerCache.top = p.top;
911
+ this.containers[ i ].containerCache.width =
912
+ this.containers[ i ].element.outerWidth();
913
+ this.containers[ i ].containerCache.height =
914
+ this.containers[ i ].element.outerHeight();
915
+ }
916
+ }
917
+
918
+ return this;
919
+ },
920
+
921
+ _createPlaceholder: function( that ) {
922
+ that = that || this;
923
+ var className, nodeName,
924
+ o = that.options;
925
+
926
+ if ( !o.placeholder || o.placeholder.constructor === String ) {
927
+ className = o.placeholder;
928
+ nodeName = that.currentItem[ 0 ].nodeName.toLowerCase();
929
+ o.placeholder = {
930
+ element: function() {
931
+
932
+ var element = $( "<" + nodeName + ">", that.document[ 0 ] );
933
+
934
+ that._addClass( element, "ui-sortable-placeholder",
935
+ className || that.currentItem[ 0 ].className )
936
+ ._removeClass( element, "ui-sortable-helper" );
937
+
938
+ if ( nodeName === "tbody" ) {
939
+ that._createTrPlaceholder(
940
+ that.currentItem.find( "tr" ).eq( 0 ),
941
+ $( "<tr>", that.document[ 0 ] ).appendTo( element )
942
+ );
943
+ } else if ( nodeName === "tr" ) {
944
+ that._createTrPlaceholder( that.currentItem, element );
945
+ } else if ( nodeName === "img" ) {
946
+ element.attr( "src", that.currentItem.attr( "src" ) );
947
+ }
948
+
949
+ if ( !className ) {
950
+ element.css( "visibility", "hidden" );
951
+ }
952
+
953
+ return element;
954
+ },
955
+ update: function( container, p ) {
956
+
957
+ // 1. If a className is set as 'placeholder option, we don't force sizes -
958
+ // the class is responsible for that
959
+ // 2. The option 'forcePlaceholderSize can be enabled to force it even if a
960
+ // class name is specified
961
+ if ( className && !o.forcePlaceholderSize ) {
962
+ return;
963
+ }
964
+
965
+ // If the element doesn't have a actual height or width by itself (without
966
+ // styles coming from a stylesheet), it receives the inline height and width
967
+ // from the dragged item. Or, if it's a tbody or tr, it's going to have a height
968
+ // anyway since we're populating them with <td>s above, but they're unlikely to
969
+ // be the correct height on their own if the row heights are dynamic, so we'll
970
+ // always assign the height of the dragged item given forcePlaceholderSize
971
+ // is true.
972
+ if ( !p.height() || ( o.forcePlaceholderSize &&
973
+ ( nodeName === "tbody" || nodeName === "tr" ) ) ) {
974
+ p.height(
975
+ that.currentItem.innerHeight() -
976
+ parseInt( that.currentItem.css( "paddingTop" ) || 0, 10 ) -
977
+ parseInt( that.currentItem.css( "paddingBottom" ) || 0, 10 ) );
978
+ }
979
+ if ( !p.width() ) {
980
+ p.width(
981
+ that.currentItem.innerWidth() -
982
+ parseInt( that.currentItem.css( "paddingLeft" ) || 0, 10 ) -
983
+ parseInt( that.currentItem.css( "paddingRight" ) || 0, 10 ) );
984
+ }
985
+ }
986
+ };
987
+ }
988
+
989
+ //Create the placeholder
990
+ that.placeholder = $( o.placeholder.element.call( that.element, that.currentItem ) );
991
+
992
+ //Append it after the actual current item
993
+ that.currentItem.after( that.placeholder );
994
+
995
+ //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317)
996
+ o.placeholder.update( that, that.placeholder );
997
+
998
+ },
999
+
1000
+ _createTrPlaceholder: function( sourceTr, targetTr ) {
1001
+ var that = this;
1002
+
1003
+ sourceTr.children().each( function() {
1004
+ $( "<td>&#160;</td>", that.document[ 0 ] )
1005
+ .attr( "colspan", $( this ).attr( "colspan" ) || 1 )
1006
+ .appendTo( targetTr );
1007
+ } );
1008
+ },
1009
+
1010
+ _contactContainers: function( event ) {
1011
+ var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, cur, nearBottom,
1012
+ floating, axis,
1013
+ innermostContainer = null,
1014
+ innermostIndex = null;
1015
+
1016
+ // Get innermost container that intersects with item
1017
+ for ( i = this.containers.length - 1; i >= 0; i-- ) {
1018
+
1019
+ // Never consider a container that's located within the item itself
1020
+ if ( $.contains( this.currentItem[ 0 ], this.containers[ i ].element[ 0 ] ) ) {
1021
+ continue;
1022
+ }
1023
+
1024
+ if ( this._intersectsWith( this.containers[ i ].containerCache ) ) {
1025
+
1026
+ // If we've already found a container and it's more "inner" than this, then continue
1027
+ if ( innermostContainer &&
1028
+ $.contains(
1029
+ this.containers[ i ].element[ 0 ],
1030
+ innermostContainer.element[ 0 ] ) ) {
1031
+ continue;
1032
+ }
1033
+
1034
+ innermostContainer = this.containers[ i ];
1035
+ innermostIndex = i;
1036
+
1037
+ } else {
1038
+
1039
+ // container doesn't intersect. trigger "out" event if necessary
1040
+ if ( this.containers[ i ].containerCache.over ) {
1041
+ this.containers[ i ]._trigger( "out", event, this._uiHash( this ) );
1042
+ this.containers[ i ].containerCache.over = 0;
1043
+ }
1044
+ }
1045
+
1046
+ }
1047
+
1048
+ this.innermostContainer = innermostContainer;
1049
+
1050
+ // If no intersecting containers found, return
1051
+ if ( !innermostContainer ) {
1052
+ return;
1053
+ }
1054
+
1055
+ // Move the item into the container if it's not there already
1056
+ if ( this.containers.length === 1 ) {
1057
+ if ( !this.containers[ innermostIndex ].containerCache.over ) {
1058
+ this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash( this ) );
1059
+ this.containers[ innermostIndex ].containerCache.over = 1;
1060
+ }
1061
+ } else {
1062
+
1063
+ // When entering a new container, we will find the item with the least distance and
1064
+ // append our item near it
1065
+ dist = 10000;
1066
+ itemWithLeastDistance = null;
1067
+ floating = innermostContainer.floating || this._isFloating( this.currentItem );
1068
+ posProperty = floating ? "left" : "top";
1069
+ sizeProperty = floating ? "width" : "height";
1070
+ axis = floating ? "pageX" : "pageY";
1071
+
1072
+ for ( j = this.items.length - 1; j >= 0; j-- ) {
1073
+ if ( !$.contains(
1074
+ this.containers[ innermostIndex ].element[ 0 ], this.items[ j ].item[ 0 ] )
1075
+ ) {
1076
+ continue;
1077
+ }
1078
+ if ( this.items[ j ].item[ 0 ] === this.currentItem[ 0 ] ) {
1079
+ continue;
1080
+ }
1081
+
1082
+ cur = this.items[ j ].item.offset()[ posProperty ];
1083
+ nearBottom = false;
1084
+ if ( event[ axis ] - cur > this.items[ j ][ sizeProperty ] / 2 ) {
1085
+ nearBottom = true;
1086
+ }
1087
+
1088
+ if ( Math.abs( event[ axis ] - cur ) < dist ) {
1089
+ dist = Math.abs( event[ axis ] - cur );
1090
+ itemWithLeastDistance = this.items[ j ];
1091
+ this.direction = nearBottom ? "up" : "down";
1092
+ }
1093
+ }
1094
+
1095
+ //Check if dropOnEmpty is enabled
1096
+ if ( !itemWithLeastDistance && !this.options.dropOnEmpty ) {
1097
+ return;
1098
+ }
1099
+
1100
+ if ( this.currentContainer === this.containers[ innermostIndex ] ) {
1101
+ if ( !this.currentContainer.containerCache.over ) {
1102
+ this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash() );
1103
+ this.currentContainer.containerCache.over = 1;
1104
+ }
1105
+ return;
1106
+ }
1107
+
1108
+ if ( itemWithLeastDistance ) {
1109
+ this._rearrange( event, itemWithLeastDistance, null, true );
1110
+ } else {
1111
+ this._rearrange( event, null, this.containers[ innermostIndex ].element, true );
1112
+ }
1113
+ this._trigger( "change", event, this._uiHash() );
1114
+ this.containers[ innermostIndex ]._trigger( "change", event, this._uiHash( this ) );
1115
+ this.currentContainer = this.containers[ innermostIndex ];
1116
+
1117
+ //Update the placeholder
1118
+ this.options.placeholder.update( this.currentContainer, this.placeholder );
1119
+
1120
+ //Update scrollParent
1121
+ this.scrollParent = this.placeholder.scrollParent();
1122
+
1123
+ //Update overflowOffset
1124
+ if ( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
1125
+ this.scrollParent[ 0 ].tagName !== "HTML" ) {
1126
+ this.overflowOffset = this.scrollParent.offset();
1127
+ }
1128
+
1129
+ this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash( this ) );
1130
+ this.containers[ innermostIndex ].containerCache.over = 1;
1131
+ }
1132
+
1133
+ },
1134
+
1135
+ _createHelper: function( event ) {
1136
+
1137
+ var o = this.options,
1138
+ helper = typeof o.helper === "function" ?
1139
+ $( o.helper.apply( this.element[ 0 ], [ event, this.currentItem ] ) ) :
1140
+ ( o.helper === "clone" ? this.currentItem.clone() : this.currentItem );
1141
+
1142
+ //Add the helper to the DOM if that didn't happen already
1143
+ if ( !helper.parents( "body" ).length ) {
1144
+ this.appendTo[ 0 ].appendChild( helper[ 0 ] );
1145
+ }
1146
+
1147
+ if ( helper[ 0 ] === this.currentItem[ 0 ] ) {
1148
+ this._storedCSS = {
1149
+ width: this.currentItem[ 0 ].style.width,
1150
+ height: this.currentItem[ 0 ].style.height,
1151
+ position: this.currentItem.css( "position" ),
1152
+ top: this.currentItem.css( "top" ),
1153
+ left: this.currentItem.css( "left" )
1154
+ };
1155
+ }
1156
+
1157
+ if ( !helper[ 0 ].style.width || o.forceHelperSize ) {
1158
+ helper.width( this.currentItem.width() );
1159
+ }
1160
+ if ( !helper[ 0 ].style.height || o.forceHelperSize ) {
1161
+ helper.height( this.currentItem.height() );
1162
+ }
1163
+
1164
+ return helper;
1165
+
1166
+ },
1167
+
1168
+ _adjustOffsetFromHelper: function( obj ) {
1169
+ if ( typeof obj === "string" ) {
1170
+ obj = obj.split( " " );
1171
+ }
1172
+ if ( Array.isArray( obj ) ) {
1173
+ obj = { left: +obj[ 0 ], top: +obj[ 1 ] || 0 };
1174
+ }
1175
+ if ( "left" in obj ) {
1176
+ this.offset.click.left = obj.left + this.margins.left;
1177
+ }
1178
+ if ( "right" in obj ) {
1179
+ this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
1180
+ }
1181
+ if ( "top" in obj ) {
1182
+ this.offset.click.top = obj.top + this.margins.top;
1183
+ }
1184
+ if ( "bottom" in obj ) {
1185
+ this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
1186
+ }
1187
+ },
1188
+
1189
+ _getParentOffset: function() {
1190
+
1191
+ //Get the offsetParent and cache its position
1192
+ this.offsetParent = this.helper.offsetParent();
1193
+ var po = this.offsetParent.offset();
1194
+
1195
+ // This is a special case where we need to modify a offset calculated on start, since the
1196
+ // following happened:
1197
+ // 1. The position of the helper is absolute, so it's position is calculated based on the
1198
+ // next positioned parent
1199
+ // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't
1200
+ // the document, which means that the scroll is included in the initial calculation of the
1201
+ // offset of the parent, and never recalculated upon drag
1202
+ if ( this.cssPosition === "absolute" && this.scrollParent[ 0 ] !== this.document[ 0 ] &&
1203
+ $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) {
1204
+ po.left += this.scrollParent.scrollLeft();
1205
+ po.top += this.scrollParent.scrollTop();
1206
+ }
1207
+
1208
+ // This needs to be actually done for all browsers, since pageX/pageY includes this
1209
+ // information with an ugly IE fix
1210
+ if ( this.offsetParent[ 0 ] === this.document[ 0 ].body ||
1211
+ ( this.offsetParent[ 0 ].tagName &&
1212
+ this.offsetParent[ 0 ].tagName.toLowerCase() === "html" && $.ui.ie ) ) {
1213
+ po = { top: 0, left: 0 };
1214
+ }
1215
+
1216
+ return {
1217
+ top: po.top + ( parseInt( this.offsetParent.css( "borderTopWidth" ), 10 ) || 0 ),
1218
+ left: po.left + ( parseInt( this.offsetParent.css( "borderLeftWidth" ), 10 ) || 0 )
1219
+ };
1220
+
1221
+ },
1222
+
1223
+ _getRelativeOffset: function() {
1224
+
1225
+ if ( this.cssPosition === "relative" ) {
1226
+ var p = this.currentItem.position();
1227
+ return {
1228
+ top: p.top - ( parseInt( this.helper.css( "top" ), 10 ) || 0 ) +
1229
+ this.scrollParent.scrollTop(),
1230
+ left: p.left - ( parseInt( this.helper.css( "left" ), 10 ) || 0 ) +
1231
+ this.scrollParent.scrollLeft()
1232
+ };
1233
+ } else {
1234
+ return { top: 0, left: 0 };
1235
+ }
1236
+
1237
+ },
1238
+
1239
+ _cacheMargins: function() {
1240
+ this.margins = {
1241
+ left: ( parseInt( this.currentItem.css( "marginLeft" ), 10 ) || 0 ),
1242
+ top: ( parseInt( this.currentItem.css( "marginTop" ), 10 ) || 0 )
1243
+ };
1244
+ },
1245
+
1246
+ _cacheHelperProportions: function() {
1247
+ this.helperProportions = {
1248
+ width: this.helper.outerWidth(),
1249
+ height: this.helper.outerHeight()
1250
+ };
1251
+ },
1252
+
1253
+ _setContainment: function() {
1254
+
1255
+ var ce, co, over,
1256
+ o = this.options;
1257
+ if ( o.containment === "parent" ) {
1258
+ o.containment = this.helper[ 0 ].parentNode;
1259
+ }
1260
+ if ( o.containment === "document" || o.containment === "window" ) {
1261
+ this.containment = [
1262
+ 0 - this.offset.relative.left - this.offset.parent.left,
1263
+ 0 - this.offset.relative.top - this.offset.parent.top,
1264
+ o.containment === "document" ?
1265
+ this.document.width() :
1266
+ this.window.width() - this.helperProportions.width - this.margins.left,
1267
+ ( o.containment === "document" ?
1268
+ ( this.document.height() || document.body.parentNode.scrollHeight ) :
1269
+ this.window.height() || this.document[ 0 ].body.parentNode.scrollHeight
1270
+ ) - this.helperProportions.height - this.margins.top
1271
+ ];
1272
+ }
1273
+
1274
+ if ( !( /^(document|window|parent)$/ ).test( o.containment ) ) {
1275
+ ce = $( o.containment )[ 0 ];
1276
+ co = $( o.containment ).offset();
1277
+ over = ( $( ce ).css( "overflow" ) !== "hidden" );
1278
+
1279
+ this.containment = [
1280
+ co.left + ( parseInt( $( ce ).css( "borderLeftWidth" ), 10 ) || 0 ) +
1281
+ ( parseInt( $( ce ).css( "paddingLeft" ), 10 ) || 0 ) - this.margins.left,
1282
+ co.top + ( parseInt( $( ce ).css( "borderTopWidth" ), 10 ) || 0 ) +
1283
+ ( parseInt( $( ce ).css( "paddingTop" ), 10 ) || 0 ) - this.margins.top,
1284
+ co.left + ( over ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) -
1285
+ ( parseInt( $( ce ).css( "borderLeftWidth" ), 10 ) || 0 ) -
1286
+ ( parseInt( $( ce ).css( "paddingRight" ), 10 ) || 0 ) -
1287
+ this.helperProportions.width - this.margins.left,
1288
+ co.top + ( over ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) -
1289
+ ( parseInt( $( ce ).css( "borderTopWidth" ), 10 ) || 0 ) -
1290
+ ( parseInt( $( ce ).css( "paddingBottom" ), 10 ) || 0 ) -
1291
+ this.helperProportions.height - this.margins.top
1292
+ ];
1293
+ }
1294
+
1295
+ },
1296
+
1297
+ _convertPositionTo: function( d, pos ) {
1298
+
1299
+ if ( !pos ) {
1300
+ pos = this.position;
1301
+ }
1302
+ var mod = d === "absolute" ? 1 : -1,
1303
+ scroll = this.cssPosition === "absolute" &&
1304
+ !( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
1305
+ $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ?
1306
+ this.offsetParent :
1307
+ this.scrollParent,
1308
+ scrollIsRootNode = ( /(html|body)/i ).test( scroll[ 0 ].tagName );
1309
+
1310
+ return {
1311
+ top: (
1312
+
1313
+ // The absolute mouse position
1314
+ pos.top +
1315
+
1316
+ // Only for relative positioned nodes: Relative offset from element to offset parent
1317
+ this.offset.relative.top * mod +
1318
+
1319
+ // The offsetParent's offset without borders (offset + border)
1320
+ this.offset.parent.top * mod -
1321
+ ( ( this.cssPosition === "fixed" ?
1322
+ -this.scrollParent.scrollTop() :
1323
+ ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod )
1324
+ ),
1325
+ left: (
1326
+
1327
+ // The absolute mouse position
1328
+ pos.left +
1329
+
1330
+ // Only for relative positioned nodes: Relative offset from element to offset parent
1331
+ this.offset.relative.left * mod +
1332
+
1333
+ // The offsetParent's offset without borders (offset + border)
1334
+ this.offset.parent.left * mod -
1335
+ ( ( this.cssPosition === "fixed" ?
1336
+ -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 :
1337
+ scroll.scrollLeft() ) * mod )
1338
+ )
1339
+ };
1340
+
1341
+ },
1342
+
1343
+ _generatePosition: function( event ) {
1344
+
1345
+ var top, left,
1346
+ o = this.options,
1347
+ pageX = event.pageX,
1348
+ pageY = event.pageY,
1349
+ scroll = this.cssPosition === "absolute" &&
1350
+ !( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
1351
+ $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ?
1352
+ this.offsetParent :
1353
+ this.scrollParent,
1354
+ scrollIsRootNode = ( /(html|body)/i ).test( scroll[ 0 ].tagName );
1355
+
1356
+ // This is another very weird special case that only happens for relative elements:
1357
+ // 1. If the css position is relative
1358
+ // 2. and the scroll parent is the document or similar to the offset parent
1359
+ // we have to refresh the relative offset during the scroll so there are no jumps
1360
+ if ( this.cssPosition === "relative" && !( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
1361
+ this.scrollParent[ 0 ] !== this.offsetParent[ 0 ] ) ) {
1362
+ this.offset.relative = this._getRelativeOffset();
1363
+ }
1364
+
1365
+ /*
1366
+ * - Position constraining -
1367
+ * Constrain the position to a mix of grid, containment.
1368
+ */
1369
+
1370
+ if ( this.originalPosition ) { //If we are not dragging yet, we won't check for options
1371
+
1372
+ if ( this.containment ) {
1373
+ if ( event.pageX - this.offset.click.left < this.containment[ 0 ] ) {
1374
+ pageX = this.containment[ 0 ] + this.offset.click.left;
1375
+ }
1376
+ if ( event.pageY - this.offset.click.top < this.containment[ 1 ] ) {
1377
+ pageY = this.containment[ 1 ] + this.offset.click.top;
1378
+ }
1379
+ if ( event.pageX - this.offset.click.left > this.containment[ 2 ] ) {
1380
+ pageX = this.containment[ 2 ] + this.offset.click.left;
1381
+ }
1382
+ if ( event.pageY - this.offset.click.top > this.containment[ 3 ] ) {
1383
+ pageY = this.containment[ 3 ] + this.offset.click.top;
1384
+ }
1385
+ }
1386
+
1387
+ if ( o.grid ) {
1388
+ top = this.originalPageY + Math.round( ( pageY - this.originalPageY ) /
1389
+ o.grid[ 1 ] ) * o.grid[ 1 ];
1390
+ pageY = this.containment ?
1391
+ ( ( top - this.offset.click.top >= this.containment[ 1 ] &&
1392
+ top - this.offset.click.top <= this.containment[ 3 ] ) ?
1393
+ top :
1394
+ ( ( top - this.offset.click.top >= this.containment[ 1 ] ) ?
1395
+ top - o.grid[ 1 ] : top + o.grid[ 1 ] ) ) :
1396
+ top;
1397
+
1398
+ left = this.originalPageX + Math.round( ( pageX - this.originalPageX ) /
1399
+ o.grid[ 0 ] ) * o.grid[ 0 ];
1400
+ pageX = this.containment ?
1401
+ ( ( left - this.offset.click.left >= this.containment[ 0 ] &&
1402
+ left - this.offset.click.left <= this.containment[ 2 ] ) ?
1403
+ left :
1404
+ ( ( left - this.offset.click.left >= this.containment[ 0 ] ) ?
1405
+ left - o.grid[ 0 ] : left + o.grid[ 0 ] ) ) :
1406
+ left;
1407
+ }
1408
+
1409
+ }
1410
+
1411
+ return {
1412
+ top: (
1413
+
1414
+ // The absolute mouse position
1415
+ pageY -
1416
+
1417
+ // Click offset (relative to the element)
1418
+ this.offset.click.top -
1419
+
1420
+ // Only for relative positioned nodes: Relative offset from element to offset parent
1421
+ this.offset.relative.top -
1422
+
1423
+ // The offsetParent's offset without borders (offset + border)
1424
+ this.offset.parent.top +
1425
+ ( ( this.cssPosition === "fixed" ?
1426
+ -this.scrollParent.scrollTop() :
1427
+ ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) )
1428
+ ),
1429
+ left: (
1430
+
1431
+ // The absolute mouse position
1432
+ pageX -
1433
+
1434
+ // Click offset (relative to the element)
1435
+ this.offset.click.left -
1436
+
1437
+ // Only for relative positioned nodes: Relative offset from element to offset parent
1438
+ this.offset.relative.left -
1439
+
1440
+ // The offsetParent's offset without borders (offset + border)
1441
+ this.offset.parent.left +
1442
+ ( ( this.cssPosition === "fixed" ?
1443
+ -this.scrollParent.scrollLeft() :
1444
+ scrollIsRootNode ? 0 : scroll.scrollLeft() ) )
1445
+ )
1446
+ };
1447
+
1448
+ },
1449
+
1450
+ _rearrange: function( event, i, a, hardRefresh ) {
1451
+
1452
+ if ( a ) {
1453
+ a[ 0 ].appendChild( this.placeholder[ 0 ] );
1454
+ } else {
1455
+ i.item[ 0 ].parentNode.insertBefore( this.placeholder[ 0 ],
1456
+ ( this.direction === "down" ? i.item[ 0 ] : i.item[ 0 ].nextSibling ) );
1457
+ }
1458
+
1459
+ //Various things done here to improve the performance:
1460
+ // 1. we create a setTimeout, that calls refreshPositions
1461
+ // 2. on the instance, we have a counter variable, that get's higher after every append
1462
+ // 3. on the local scope, we copy the counter variable, and check in the timeout,
1463
+ // if it's still the same
1464
+ // 4. this lets only the last addition to the timeout stack through
1465
+ this.counter = this.counter ? ++this.counter : 1;
1466
+ var counter = this.counter;
1467
+
1468
+ this._delay( function() {
1469
+ if ( counter === this.counter ) {
1470
+
1471
+ //Precompute after each DOM insertion, NOT on mousemove
1472
+ this.refreshPositions( !hardRefresh );
1473
+ }
1474
+ } );
1475
+
1476
+ },
1477
+
1478
+ _clear: function( event, noPropagation ) {
1479
+
1480
+ this.reverting = false;
1481
+
1482
+ // We delay all events that have to be triggered to after the point where the placeholder
1483
+ // has been removed and everything else normalized again
1484
+ var i,
1485
+ delayedTriggers = [];
1486
+
1487
+ // We first have to update the dom position of the actual currentItem
1488
+ // Note: don't do it if the current item is already removed (by a user), or it gets
1489
+ // reappended (see #4088)
1490
+ if ( !this._noFinalSort && this.currentItem.parent().length ) {
1491
+ this.placeholder.before( this.currentItem );
1492
+ }
1493
+ this._noFinalSort = null;
1494
+
1495
+ if ( this.helper[ 0 ] === this.currentItem[ 0 ] ) {
1496
+ for ( i in this._storedCSS ) {
1497
+ if ( this._storedCSS[ i ] === "auto" || this._storedCSS[ i ] === "static" ) {
1498
+ this._storedCSS[ i ] = "";
1499
+ }
1500
+ }
1501
+ this.currentItem.css( this._storedCSS );
1502
+ this._removeClass( this.currentItem, "ui-sortable-helper" );
1503
+ } else {
1504
+ this.currentItem.show();
1505
+ }
1506
+
1507
+ if ( this.fromOutside && !noPropagation ) {
1508
+ delayedTriggers.push( function( event ) {
1509
+ this._trigger( "receive", event, this._uiHash( this.fromOutside ) );
1510
+ } );
1511
+ }
1512
+ if ( ( this.fromOutside ||
1513
+ this.domPosition.prev !==
1514
+ this.currentItem.prev().not( ".ui-sortable-helper" )[ 0 ] ||
1515
+ this.domPosition.parent !== this.currentItem.parent()[ 0 ] ) && !noPropagation ) {
1516
+
1517
+ // Trigger update callback if the DOM position has changed
1518
+ delayedTriggers.push( function( event ) {
1519
+ this._trigger( "update", event, this._uiHash() );
1520
+ } );
1521
+ }
1522
+
1523
+ // Check if the items Container has Changed and trigger appropriate
1524
+ // events.
1525
+ if ( this !== this.currentContainer ) {
1526
+ if ( !noPropagation ) {
1527
+ delayedTriggers.push( function( event ) {
1528
+ this._trigger( "remove", event, this._uiHash() );
1529
+ } );
1530
+ delayedTriggers.push( ( function( c ) {
1531
+ return function( event ) {
1532
+ c._trigger( "receive", event, this._uiHash( this ) );
1533
+ };
1534
+ } ).call( this, this.currentContainer ) );
1535
+ delayedTriggers.push( ( function( c ) {
1536
+ return function( event ) {
1537
+ c._trigger( "update", event, this._uiHash( this ) );
1538
+ };
1539
+ } ).call( this, this.currentContainer ) );
1540
+ }
1541
+ }
1542
+
1543
+ //Post events to containers
1544
+ function delayEvent( type, instance, container ) {
1545
+ return function( event ) {
1546
+ container._trigger( type, event, instance._uiHash( instance ) );
1547
+ };
1548
+ }
1549
+ for ( i = this.containers.length - 1; i >= 0; i-- ) {
1550
+ if ( !noPropagation ) {
1551
+ delayedTriggers.push( delayEvent( "deactivate", this, this.containers[ i ] ) );
1552
+ }
1553
+ if ( this.containers[ i ].containerCache.over ) {
1554
+ delayedTriggers.push( delayEvent( "out", this, this.containers[ i ] ) );
1555
+ this.containers[ i ].containerCache.over = 0;
1556
+ }
1557
+ }
1558
+
1559
+ //Do what was originally in plugins
1560
+ if ( this.storedCursor ) {
1561
+ this.document.find( "body" ).css( "cursor", this.storedCursor );
1562
+ this.storedStylesheet.remove();
1563
+ }
1564
+ if ( this._storedOpacity ) {
1565
+ this.helper.css( "opacity", this._storedOpacity );
1566
+ }
1567
+ if ( this._storedZIndex ) {
1568
+ this.helper.css( "zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex );
1569
+ }
1570
+
1571
+ this.dragging = false;
1572
+
1573
+ if ( !noPropagation ) {
1574
+ this._trigger( "beforeStop", event, this._uiHash() );
1575
+ }
1576
+
1577
+ //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately,
1578
+ // it unbinds ALL events from the original node!
1579
+ this.placeholder[ 0 ].parentNode.removeChild( this.placeholder[ 0 ] );
1580
+
1581
+ if ( !this.cancelHelperRemoval ) {
1582
+ if ( this.helper[ 0 ] !== this.currentItem[ 0 ] ) {
1583
+ this.helper.remove();
1584
+ }
1585
+ this.helper = null;
1586
+ }
1587
+
1588
+ if ( !noPropagation ) {
1589
+ for ( i = 0; i < delayedTriggers.length; i++ ) {
1590
+
1591
+ // Trigger all delayed events
1592
+ delayedTriggers[ i ].call( this, event );
1593
+ }
1594
+ this._trigger( "stop", event, this._uiHash() );
1595
+ }
1596
+
1597
+ this.fromOutside = false;
1598
+ return !this.cancelHelperRemoval;
1599
+
1600
+ },
1601
+
1602
+ _trigger: function() {
1603
+ if ( $.Widget.prototype._trigger.apply( this, arguments ) === false ) {
1604
+ this.cancel();
1605
+ }
1606
+ },
1607
+
1608
+ _uiHash: function( _inst ) {
1609
+ var inst = _inst || this;
1610
+ return {
1611
+ helper: inst.helper,
1612
+ placeholder: inst.placeholder || $( [] ),
1613
+ position: inst.position,
1614
+ originalPosition: inst.originalPosition,
1615
+ offset: inst.positionAbs,
1616
+ item: inst.currentItem,
1617
+ sender: _inst ? _inst.element : null
1618
+ };
1619
+ }
1620
+
1621
+ } );
1622
+
1623
+ } );