Security update for Core, with self-updated composer
[yaffs-website] / web / core / modules / block / js / block.es6.js
diff --git a/web/core/modules/block/js/block.es6.js b/web/core/modules/block/js/block.es6.js
new file mode 100644 (file)
index 0000000..3d1802a
--- /dev/null
@@ -0,0 +1,222 @@
+/**
+ * @file
+ * Block behaviors.
+ */
+
+(function ($, window, Drupal) {
+  /**
+   * Provide the summary information for the block settings vertical tabs.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches the behavior for the block settings summaries.
+   */
+  Drupal.behaviors.blockSettingsSummary = {
+    attach() {
+      // The drupalSetSummary method required for this behavior is not available
+      // on the Blocks administration page, so we need to make sure this
+      // behavior is processed only if drupalSetSummary is defined.
+      if (typeof $.fn.drupalSetSummary === 'undefined') {
+        return;
+      }
+
+      /**
+       * Create a summary for checkboxes in the provided context.
+       *
+       * @param {HTMLDocument|HTMLElement} context
+       *   A context where one would find checkboxes to summarize.
+       *
+       * @return {string}
+       *   A string with the summary.
+       */
+      function checkboxesSummary(context) {
+        const vals = [];
+        const $checkboxes = $(context).find('input[type="checkbox"]:checked + label');
+        const il = $checkboxes.length;
+        for (let i = 0; i < il; i++) {
+          vals.push($($checkboxes[i]).html());
+        }
+        if (!vals.length) {
+          vals.push(Drupal.t('Not restricted'));
+        }
+        return vals.join(', ');
+      }
+
+      $('[data-drupal-selector="edit-visibility-node-type"], [data-drupal-selector="edit-visibility-language"], [data-drupal-selector="edit-visibility-user-role"]').drupalSetSummary(checkboxesSummary);
+
+      $('[data-drupal-selector="edit-visibility-request-path"]').drupalSetSummary((context) => {
+        const $pages = $(context).find('textarea[name="visibility[request_path][pages]"]');
+        if (!$pages.val()) {
+          return Drupal.t('Not restricted');
+        }
+
+        return Drupal.t('Restricted to certain pages');
+      });
+    },
+  };
+
+  /**
+   * Move a block in the blocks table between regions via select list.
+   *
+   * This behavior is dependent on the tableDrag behavior, since it uses the
+   * objects initialized in that behavior to update the row.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches the tableDrag behaviour for blocks in block administration.
+   */
+  Drupal.behaviors.blockDrag = {
+    attach(context, settings) {
+      // tableDrag is required and we should be on the blocks admin page.
+      if (typeof Drupal.tableDrag === 'undefined' || typeof Drupal.tableDrag.blocks === 'undefined') {
+        return;
+      }
+
+      /**
+       * Function to check empty regions and toggle classes based on this.
+       *
+       * @param {jQuery} table
+       *   The jQuery object representing the table to inspect.
+       * @param {jQuery} rowObject
+       *   The jQuery object representing the table row.
+       */
+      function checkEmptyRegions(table, rowObject) {
+        table.find('tr.region-message').each(function () {
+          const $this = $(this);
+          // If the dragged row is in this region, but above the message row,
+          // swap it down one space.
+          if ($this.prev('tr').get(0) === rowObject.element) {
+            // Prevent a recursion problem when using the keyboard to move rows
+            // up.
+            if ((rowObject.method !== 'keyboard' || rowObject.direction === 'down')) {
+              rowObject.swap('after', this);
+            }
+          }
+          // This region has become empty.
+          if ($this.next('tr').is(':not(.draggable)') || $this.next('tr').length === 0) {
+            $this.removeClass('region-populated').addClass('region-empty');
+          }
+          // This region has become populated.
+          else if ($this.is('.region-empty')) {
+            $this.removeClass('region-empty').addClass('region-populated');
+          }
+        });
+      }
+
+      /**
+       * Function to update the last placed row with the correct classes.
+       *
+       * @param {jQuery} table
+       *   The jQuery object representing the table to inspect.
+       * @param {jQuery} rowObject
+       *   The jQuery object representing the table row.
+       */
+      function updateLastPlaced(table, rowObject) {
+        // Remove the color-success class from new block if applicable.
+        table.find('.color-success').removeClass('color-success');
+
+        const $rowObject = $(rowObject);
+        if (!$rowObject.is('.drag-previous')) {
+          table.find('.drag-previous').removeClass('drag-previous');
+          $rowObject.addClass('drag-previous');
+        }
+      }
+
+      /**
+       * Update block weights in the given region.
+       *
+       * @param {jQuery} table
+       *   Table with draggable items.
+       * @param {string} region
+       *   Machine name of region containing blocks to update.
+       */
+      function updateBlockWeights(table, region) {
+        // Calculate minimum weight.
+        let weight = -Math.round(table.find('.draggable').length / 2);
+        // Update the block weights.
+        table.find(`.region-${region}-message`).nextUntil('.region-title')
+          .find('select.block-weight').val(() =>
+            // Increment the weight before assigning it to prevent using the
+            // absolute minimum available weight. This way we always have an
+            // unused upper and lower bound, which makes manually setting the
+            // weights easier for users who prefer to do it that way.
+             ++weight);
+      }
+
+      const table = $('#blocks');
+      // Get the blocks tableDrag object.
+      const tableDrag = Drupal.tableDrag.blocks;
+      // Add a handler for when a row is swapped, update empty regions.
+      tableDrag.row.prototype.onSwap = function (swappedRow) {
+        checkEmptyRegions(table, this);
+        updateLastPlaced(table, this);
+      };
+
+      // Add a handler so when a row is dropped, update fields dropped into
+      // new regions.
+      tableDrag.onDrop = function () {
+        const dragObject = this;
+        const $rowElement = $(dragObject.rowObject.element);
+        // Use "region-message" row instead of "region" row because
+        // "region-{region_name}-message" is less prone to regexp match errors.
+        const regionRow = $rowElement.prevAll('tr.region-message').get(0);
+        const regionName = regionRow.className.replace(/([^ ]+[ ]+)*region-([^ ]+)-message([ ]+[^ ]+)*/, '$2');
+        const regionField = $rowElement.find('select.block-region-select');
+        // Check whether the newly picked region is available for this block.
+        if (regionField.find(`option[value=${regionName}]`).length === 0) {
+          // If not, alert the user and keep the block in its old region
+          // setting.
+          window.alert(Drupal.t('The block cannot be placed in this region.'));
+          // Simulate that there was a selected element change, so the row is
+          // put back to from where the user tried to drag it.
+          regionField.trigger('change');
+        }
+
+        // Update region and weight fields if the region has been changed.
+        if (!regionField.is(`.block-region-${regionName}`)) {
+          const weightField = $rowElement.find('select.block-weight');
+          const oldRegionName = weightField[0].className.replace(/([^ ]+[ ]+)*block-weight-([^ ]+)([ ]+[^ ]+)*/, '$2');
+          regionField.removeClass(`block-region-${oldRegionName}`).addClass(`block-region-${regionName}`);
+          weightField.removeClass(`block-weight-${oldRegionName}`).addClass(`block-weight-${regionName}`);
+          regionField.val(regionName);
+        }
+
+        updateBlockWeights(table, regionName);
+      };
+
+      // Add the behavior to each region select list.
+      $(context).find('select.block-region-select').once('block-region-select')
+        .on('change', function (event) {
+          // Make our new row and select field.
+          const row = $(this).closest('tr');
+          const select = $(this);
+          // Find the correct region and insert the row as the last in the
+          // region.
+          tableDrag.rowObject = new tableDrag.row(row[0]);
+          const region_message = table.find(`.region-${select[0].value}-message`);
+          const region_items = region_message.nextUntil('.region-message, .region-title');
+          if (region_items.length) {
+            region_items.last().after(row);
+          }
+          // We found that region_message is the last row.
+          else {
+            region_message.after(row);
+          }
+          updateBlockWeights(table, select[0].value);
+          // Modify empty regions with added or removed fields.
+          checkEmptyRegions(table, tableDrag.rowObject);
+          // Update last placed block indication.
+          updateLastPlaced(table, row);
+          // Show unsaved changes warning.
+          if (!tableDrag.changed) {
+            $(Drupal.theme('tableDragChangedWarning')).insertBefore(tableDrag.table).hide().fadeIn('slow');
+            tableDrag.changed = true;
+          }
+          // Remove focus from selectbox.
+          select.trigger('blur');
+        });
+    },
+  };
+}(jQuery, window, Drupal));