Upgraded imagemagick and manually altered pdf to image module to handle changes....
[yaffs-website] / web / modules / contrib / paragraphs / js / paragraphs.dragdrop.js
1 /**
2  * @file
3  * Paragraphs drag and drop handling and integration with the Sortable library.
4  */
5
6 (function ($, Drupal) {
7
8   'use strict';
9
10   /**
11    * jQuery plugin for Sortable
12    *
13    * Registers Sortable under a custom name to prevent a collision with jQuery
14    * UI.
15    *
16    * @param   {Object|String} options
17    * @param   {..*}           [args]
18    * @returns {jQuery|*}
19    */
20   $.fn.paragraphsSortable = function (options) {
21     var retVal,
22       args = arguments;
23
24     this.each(function () {
25       var $el = $(this),
26         sortable = $el.data('sortable');
27
28       if (!sortable && (options instanceof Object || !options)) {
29         sortable = new Sortable(this, options);
30         $el.data('sortable', sortable);
31       }
32
33       if (sortable) {
34         if (options === 'widget') {
35           return sortable;
36         }
37         else if (options === 'destroy') {
38           sortable.destroy();
39           $el.removeData('sortable');
40         }
41         else if (typeof sortable[options] === 'function') {
42           retVal = sortable[options].apply(sortable, [].slice.call(args, 1));
43         }
44         else if (options in sortable.options) {
45           retVal = sortable.option.apply(sortable, args);
46         }
47       }
48     });
49
50     return (retVal === void 0) ? this : retVal;
51   };
52
53
54   Drupal.behaviors.paragraphsDraggable = {
55     attach: function (context) {
56
57       // Initialize drag and drop.
58       $('ul.paragraphs-dragdrop', context).each(function (i, item) {
59         $(item).paragraphsSortable({
60           group: "paragraphs",
61           sort: true,
62           handle: ".tabledrag-handle",
63           onMove: isAllowed,
64           onEnd: handleReorder
65         });
66       });
67
68       /**
69        * Callback to update weight and path information.
70        *
71        * @param evt
72        *   The Sortable event.
73        */
74       function handleReorder(evt) {
75         var $item = $(evt.item);
76         var $parent = $item.closest('.paragraphs-dragdrop');
77         var $children = $parent.children('li');
78         var $srcParent = $(evt.to);
79         var $srcChildren = $srcParent.children('li');
80
81         // Update both the source and target children.
82         updateWeightsAndPath($srcChildren);
83         updateWeightsAndPath($children);
84       }
85
86
87       /**
88        * Update weight and recursively update path of the provided paragraphs.
89        *
90        * @param $items
91        *   Drag and drop items.
92        */
93       function updateWeightsAndPath($items) {
94         $items.each(function (index, value) {
95
96           // Update the weight in the weight of the current element, avoid
97           // matching child weights by selecting the first.
98           var $currentItem = $(value);
99           var $weight = $currentItem.find('.paragraphs-dragdrop__weight:first');
100           $weight.val(index);
101
102           // Update the path of the current element and then update all nested
103           // elements.
104           updatePaths($currentItem, $currentItem.parent());
105           $currentItem.find('> div > ul').each(function () {
106             updateNestedPath(this, index, $currentItem);
107           });
108         })
109       }
110
111       /**
112        * Update the path field based on the parent.
113        *
114        * @param $item
115        *   A list item.
116        * @param $parent
117        *   The parent of the list item.
118        */
119       function updatePaths($item, $parent) {
120         // Select the first path field which is the one from the current
121         // element.
122         var $pathField = $item.find('.paragraphs-dragdrop__path:first');
123         var newPath = $parent.attr('data-paragraphs-dragdrop-path');
124         $pathField.val(newPath);
125       }
126
127       /**
128        * Update nested paragraphs for a field/list.
129        *
130        * @param childList
131        *   The paragraph field/list, parent of the children to be updated.
132        * @param parentIndex
133        *   The index of the parent list item.
134        * @param $parentListItem
135        *   The parent list item.
136        */
137       function updateNestedPath(childList, parentIndex, $parentListItem) {
138
139         var sortablePath = childList.getAttribute('data-paragraphs-dragdrop-path');
140         var newParent = $parentListItem.parent().attr('data-paragraphs-dragdrop-path');
141
142         // Update the data attribute of the list based on the parent index and
143         // list item.
144         sortablePath = newParent + "][" + parentIndex + sortablePath.substr(sortablePath.lastIndexOf("]"));
145         childList.setAttribute('data-paragraphs-dragdrop-path', sortablePath);
146
147         // Now update the children.
148         $(childList).children().each(function (childIndex) {
149           var $childListItem = $(this);
150           updatePaths($childListItem, $(childList), childIndex);
151           $(this).find('> div > ul').each(function () {
152             var nestedChildList = this;
153             updateNestedPath(nestedChildList, childIndex, $childListItem);
154           });
155         });
156       }
157
158
159       /**
160        * Callback to check if a paragraph item can be dropped into a position.
161        *
162        * @param evt
163        *   The Sortable event.
164        * @param originalEvent
165        *   The original Sortable event.
166        *
167        * @returns {boolean|*}
168        *   True if the type is allowed and there is enough room.
169        */
170       function isAllowed(evt, originalEvent) {
171         var dragee = evt.dragged;
172         var target = evt.to;
173         var drageeType = dragee.dataset.paragraphsDragdropBundle;
174         var allowedTypes = target.dataset.paragraphsDragdropAllowedTypes;
175         var hasSameContainer = evt.to === evt.from;
176         return hasSameContainer || (contains(drageeType, allowedTypes) && hasRoom(target));
177       }
178
179       /**
180        * Checks if the target has room.
181        *
182        * @param target
183        *   The target list/paragraph field.
184        *
185        * @returns {boolean}
186        *   True if the field is unlimited or limit is not reached yet.
187        */
188       function hasRoom(target) {
189
190         var cardinality = target.dataset.paragraphsDragdropCardinality;
191         var occupants = target.childNodes.length;
192         var isLimited = parseInt(cardinality, 10) !== -1;
193         var hasRoom = cardinality > occupants;
194
195         return hasRoom || !isLimited;
196       }
197
198       /**
199        * Checks if the paragraph type is allowed in the target type list.
200        *
201        * @param candidate
202        *   The paragraph type.
203        * @param set
204        *   Comma separated list of target types.
205        *
206        * @returns {boolean}
207        *   TRUE if the target type is allowed.
208        */
209       function contains(candidate, set) {
210         set = set.split(',');
211         var l = set.length;
212
213         for(var i = 0; i < l; i++) {
214           if(set[i] === candidate) {
215             return true;
216           }
217         }
218         return false;
219       }
220
221       // Fix for an iOS 10 bug. Binding empty event handler on the touchmove
222       // event.
223       window.addEventListener('touchmove', function () {
224       })
225     }
226   }
227
228 })(jQuery, Drupal);