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