annotate core/modules/block/js/block.es6.js @ 19:fa3358dc1485 tip

Add ndrum files
author Chris Cannam
date Wed, 28 Aug 2019 13:14:47 +0100
parents 129ea1e6d783
children
rev   line source
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);