259 lines
		
	
	
		
			9.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			259 lines
		
	
	
		
			9.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
/**
 | 
						|
 * @file
 | 
						|
 * Block behaviors.
 | 
						|
 */
 | 
						|
 | 
						|
(function ($, window, Drupal, once) {
 | 
						|
  /**
 | 
						|
   * 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 {Document|HTMLElement} context
 | 
						|
       *   A context where one would find checkboxes to summarize.
 | 
						|
       *
 | 
						|
       * @return {string}
 | 
						|
       *   A string with the summary.
 | 
						|
       */
 | 
						|
      function checkboxesSummary(context) {
 | 
						|
        const values = [];
 | 
						|
        const $checkboxes = $(context).find(
 | 
						|
          'input[type="checkbox"]:checked + label',
 | 
						|
        );
 | 
						|
        const il = $checkboxes.length;
 | 
						|
        for (let i = 0; i < il; i++) {
 | 
						|
          values.push($($checkboxes[i]).html());
 | 
						|
        }
 | 
						|
        if (!values.length) {
 | 
						|
          values.push(Drupal.t('Not restricted'));
 | 
						|
        }
 | 
						|
        return values.join(', ');
 | 
						|
      }
 | 
						|
 | 
						|
      $(
 | 
						|
        '[data-drupal-selector="edit-visibility-node-type"], [data-drupal-selector="edit-visibility-entity-bundlenode"], [data-drupal-selector="edit-visibility-language"], [data-drupal-selector="edit-visibility-user-role"], [data-drupal-selector="edit-visibility-response-status"]',
 | 
						|
      ).drupalSetSummary(checkboxesSummary);
 | 
						|
 | 
						|
      $(
 | 
						|
        '[data-drupal-selector="edit-visibility-request-path"]',
 | 
						|
      ).drupalSetSummary((context) => {
 | 
						|
        const $pages = $(context).find(
 | 
						|
          'textarea[name="visibility[request_path][pages]"]',
 | 
						|
        );
 | 
						|
        if (!$pages.length || !$pages[0].value) {
 | 
						|
          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 behavior 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?.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 {Drupal.tableDrag.row} rowObject
 | 
						|
       *   Drupal table drag row dropped.
 | 
						|
       */
 | 
						|
      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').length === 0 ||
 | 
						|
            !$this.next('tr')[0].matches('.draggable')
 | 
						|
          ) {
 | 
						|
            $this.removeClass('region-populated').addClass('region-empty');
 | 
						|
          }
 | 
						|
          // This region has become populated.
 | 
						|
          else if (this.matches('.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 {Drupal.tableDrag.row} rowObject
 | 
						|
       *   Drupal table drag row dropped.
 | 
						|
       */
 | 
						|
      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.element.matches('.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')
 | 
						|
          .each(function () {
 | 
						|
            // 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.
 | 
						|
            this.value = ++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[0].matches(`.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[0].value = regionName;
 | 
						|
        }
 | 
						|
 | 
						|
        updateBlockWeights(table, regionName);
 | 
						|
      };
 | 
						|
 | 
						|
      // Add the behavior to each region select list.
 | 
						|
      $(once('block-region-select', 'select.block-region-select', context)).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 regionMessage = table.find(
 | 
						|
            `.region-${select[0].value}-message`,
 | 
						|
          );
 | 
						|
          const regionItems = regionMessage.nextUntil(
 | 
						|
            '.region-message, .region-title',
 | 
						|
          );
 | 
						|
          if (regionItems.length) {
 | 
						|
            regionItems.last().after(row);
 | 
						|
          }
 | 
						|
          // We found that regionMessage is the last row.
 | 
						|
          else {
 | 
						|
            regionMessage.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, tableDrag.rowObject);
 | 
						|
          // 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, once);
 |