Updated Drupal to 8.6. This goes with the following updates because it's possible...
[yaffs-website] / web / core / modules / block / js / block.es6.js
1 /**
2  * @file
3  * Block behaviors.
4  */
5
6 (function($, window, Drupal) {
7   /**
8    * Provide the summary information for the block settings vertical tabs.
9    *
10    * @type {Drupal~behavior}
11    *
12    * @prop {Drupal~behaviorAttach} attach
13    *   Attaches the behavior for the block settings summaries.
14    */
15   Drupal.behaviors.blockSettingsSummary = {
16     attach() {
17       // The drupalSetSummary method required for this behavior is not available
18       // on the Blocks administration page, so we need to make sure this
19       // behavior is processed only if drupalSetSummary is defined.
20       if (typeof $.fn.drupalSetSummary === 'undefined') {
21         return;
22       }
23
24       /**
25        * Create a summary for checkboxes in the provided context.
26        *
27        * @param {HTMLDocument|HTMLElement} context
28        *   A context where one would find checkboxes to summarize.
29        *
30        * @return {string}
31        *   A string with the summary.
32        */
33       function checkboxesSummary(context) {
34         const vals = [];
35         const $checkboxes = $(context).find(
36           'input[type="checkbox"]:checked + label',
37         );
38         const il = $checkboxes.length;
39         for (let i = 0; i < il; i++) {
40           vals.push($($checkboxes[i]).html());
41         }
42         if (!vals.length) {
43           vals.push(Drupal.t('Not restricted'));
44         }
45         return vals.join(', ');
46       }
47
48       $(
49         '[data-drupal-selector="edit-visibility-node-type"], [data-drupal-selector="edit-visibility-language"], [data-drupal-selector="edit-visibility-user-role"]',
50       ).drupalSetSummary(checkboxesSummary);
51
52       $(
53         '[data-drupal-selector="edit-visibility-request-path"]',
54       ).drupalSetSummary(context => {
55         const $pages = $(context).find(
56           'textarea[name="visibility[request_path][pages]"]',
57         );
58         if (!$pages.val()) {
59           return Drupal.t('Not restricted');
60         }
61
62         return Drupal.t('Restricted to certain pages');
63       });
64     },
65   };
66
67   /**
68    * Move a block in the blocks table between regions via select list.
69    *
70    * This behavior is dependent on the tableDrag behavior, since it uses the
71    * objects initialized in that behavior to update the row.
72    *
73    * @type {Drupal~behavior}
74    *
75    * @prop {Drupal~behaviorAttach} attach
76    *   Attaches the tableDrag behaviour for blocks in block administration.
77    */
78   Drupal.behaviors.blockDrag = {
79     attach(context, settings) {
80       // tableDrag is required and we should be on the blocks admin page.
81       if (
82         typeof Drupal.tableDrag === 'undefined' ||
83         typeof Drupal.tableDrag.blocks === 'undefined'
84       ) {
85         return;
86       }
87
88       /**
89        * Function to check empty regions and toggle classes based on this.
90        *
91        * @param {jQuery} table
92        *   The jQuery object representing the table to inspect.
93        * @param {jQuery} rowObject
94        *   The jQuery object representing the table row.
95        */
96       function checkEmptyRegions(table, rowObject) {
97         table.find('tr.region-message').each(function() {
98           const $this = $(this);
99           // If the dragged row is in this region, but above the message row,
100           // swap it down one space.
101           if ($this.prev('tr').get(0) === rowObject.element) {
102             // Prevent a recursion problem when using the keyboard to move rows
103             // up.
104             if (
105               rowObject.method !== 'keyboard' ||
106               rowObject.direction === 'down'
107             ) {
108               rowObject.swap('after', this);
109             }
110           }
111           // This region has become empty.
112           if (
113             $this.next('tr').is(':not(.draggable)') ||
114             $this.next('tr').length === 0
115           ) {
116             $this.removeClass('region-populated').addClass('region-empty');
117           }
118           // This region has become populated.
119           else if ($this.is('.region-empty')) {
120             $this.removeClass('region-empty').addClass('region-populated');
121           }
122         });
123       }
124
125       /**
126        * Function to update the last placed row with the correct classes.
127        *
128        * @param {jQuery} table
129        *   The jQuery object representing the table to inspect.
130        * @param {jQuery} rowObject
131        *   The jQuery object representing the table row.
132        */
133       function updateLastPlaced(table, rowObject) {
134         // Remove the color-success class from new block if applicable.
135         table.find('.color-success').removeClass('color-success');
136
137         const $rowObject = $(rowObject);
138         if (!$rowObject.is('.drag-previous')) {
139           table.find('.drag-previous').removeClass('drag-previous');
140           $rowObject.addClass('drag-previous');
141         }
142       }
143
144       /**
145        * Update block weights in the given region.
146        *
147        * @param {jQuery} table
148        *   Table with draggable items.
149        * @param {string} region
150        *   Machine name of region containing blocks to update.
151        */
152       function updateBlockWeights(table, region) {
153         // Calculate minimum weight.
154         let weight = -Math.round(table.find('.draggable').length / 2);
155         // Update the block weights.
156         table
157           .find(`.region-${region}-message`)
158           .nextUntil('.region-title')
159           .find('select.block-weight')
160           .val(
161             // Increment the weight before assigning it to prevent using the
162             // absolute minimum available weight. This way we always have an
163             // unused upper and lower bound, which makes manually setting the
164             // weights easier for users who prefer to do it that way.
165             () => ++weight,
166           );
167       }
168
169       const table = $('#blocks');
170       // Get the blocks tableDrag object.
171       const tableDrag = Drupal.tableDrag.blocks;
172       // Add a handler for when a row is swapped, update empty regions.
173       tableDrag.row.prototype.onSwap = function(swappedRow) {
174         checkEmptyRegions(table, this);
175         updateLastPlaced(table, this);
176       };
177
178       // Add a handler so when a row is dropped, update fields dropped into
179       // new regions.
180       tableDrag.onDrop = function() {
181         const dragObject = this;
182         const $rowElement = $(dragObject.rowObject.element);
183         // Use "region-message" row instead of "region" row because
184         // "region-{region_name}-message" is less prone to regexp match errors.
185         const regionRow = $rowElement.prevAll('tr.region-message').get(0);
186         const regionName = regionRow.className.replace(
187           /([^ ]+[ ]+)*region-([^ ]+)-message([ ]+[^ ]+)*/,
188           '$2',
189         );
190         const regionField = $rowElement.find('select.block-region-select');
191         // Check whether the newly picked region is available for this block.
192         if (regionField.find(`option[value=${regionName}]`).length === 0) {
193           // If not, alert the user and keep the block in its old region
194           // setting.
195           window.alert(Drupal.t('The block cannot be placed in this region.'));
196           // Simulate that there was a selected element change, so the row is
197           // put back to from where the user tried to drag it.
198           regionField.trigger('change');
199         }
200
201         // Update region and weight fields if the region has been changed.
202         if (!regionField.is(`.block-region-${regionName}`)) {
203           const weightField = $rowElement.find('select.block-weight');
204           const oldRegionName = weightField[0].className.replace(
205             /([^ ]+[ ]+)*block-weight-([^ ]+)([ ]+[^ ]+)*/,
206             '$2',
207           );
208           regionField
209             .removeClass(`block-region-${oldRegionName}`)
210             .addClass(`block-region-${regionName}`);
211           weightField
212             .removeClass(`block-weight-${oldRegionName}`)
213             .addClass(`block-weight-${regionName}`);
214           regionField.val(regionName);
215         }
216
217         updateBlockWeights(table, regionName);
218       };
219
220       // Add the behavior to each region select list.
221       $(context)
222         .find('select.block-region-select')
223         .once('block-region-select')
224         .on('change', function(event) {
225           // Make our new row and select field.
226           const row = $(this).closest('tr');
227           const select = $(this);
228           // Find the correct region and insert the row as the last in the
229           // region.
230           tableDrag.rowObject = new tableDrag.row(row[0]);
231           const regionMessage = table.find(
232             `.region-${select[0].value}-message`,
233           );
234           const regionItems = regionMessage.nextUntil(
235             '.region-message, .region-title',
236           );
237           if (regionItems.length) {
238             regionItems.last().after(row);
239           }
240           // We found that regionMessage is the last row.
241           else {
242             regionMessage.after(row);
243           }
244           updateBlockWeights(table, select[0].value);
245           // Modify empty regions with added or removed fields.
246           checkEmptyRegions(table, tableDrag.rowObject);
247           // Update last placed block indication.
248           updateLastPlaced(table, row);
249           // Show unsaved changes warning.
250           if (!tableDrag.changed) {
251             $(Drupal.theme('tableDragChangedWarning'))
252               .insertBefore(tableDrag.table)
253               .hide()
254               .fadeIn('slow');
255             tableDrag.changed = true;
256           }
257           // Remove focus from selectbox.
258           select.trigger('blur');
259         });
260     },
261   };
262 })(jQuery, window, Drupal);