Unverified Commit e72233af authored by Lauri Timmanee's avatar Lauri Timmanee
Browse files

Issue #3269082 by longwave, Spokje, mherchel, andregp, kostyashupenko, bnjmnm,...

Issue #3269082 by longwave, Spokje, mherchel, andregp, kostyashupenko, bnjmnm, nod_: Remove HTML5 details collapse polyfill

(cherry picked from commit 9ad91313)
parent 1002797d
Loading
Loading
Loading
Loading
+1 −2
Original line number Diff line number Diff line
@@ -469,10 +469,9 @@ drupal.collapse:
  js:
    misc/details-summarized-content.js: {}
    misc/details-aria.js: {}
    misc/collapse.js: {}
    misc/details.js: {}
  dependencies:
    - core/jquery
    - core/modernizr
    - core/drupal
    - core/drupal.form
    - core/once

core/misc/collapse.js

deleted100644 → 0
+0 −155
Original line number Diff line number Diff line
/**
 * @file
 * Polyfill for HTML5 details elements.
 */

(function ($, Modernizr, Drupal) {
  /**
   * The collapsible details object represents a single details element.
   *
   * @constructor Drupal.CollapsibleDetails
   *
   * @param {HTMLElement} node
   *   The details element.
   */
  function CollapsibleDetails(node) {
    this.$node = $(node);
    this.$node.data('details', this);
    // Expand details if there are errors inside, or if it contains an
    // element that is targeted by the URI fragment identifier.
    const anchor =
      window.location.hash && window.location.hash !== '#'
        ? `, ${window.location.hash}`
        : '';
    if (this.$node.find(`.error${anchor}`).length) {
      this.$node.attr('open', true);
    }
    // Initialize and set up the summary polyfill.
    this.setupSummaryPolyfill();
  }

  $.extend(
    CollapsibleDetails,
    /** @lends Drupal.CollapsibleDetails */ {
      /**
       * Holds references to instantiated CollapsibleDetails objects.
       *
       * @type {Array.<Drupal.CollapsibleDetails>}
       */
      instances: [],
    },
  );

  $.extend(
    CollapsibleDetails.prototype,
    /** @lends Drupal.CollapsibleDetails# */ {
      /**
       * Initialize and setup summary markup.
       */
      setupSummaryPolyfill() {
        // Turn the summary into a clickable link.
        const $summary = this.$node.find('> summary');

        // If this polyfill is in use, the browser does not recognize
        // <summary> as a focusable element. The tabindex is set to -1 so the
        // tabbable library does not incorrectly identify it as tabbable.
        $summary.attr('tabindex', '-1');

        $('<span class="details-summary-prefix visually-hidden"></span>')
          .append(this.$node.attr('open') ? Drupal.t('Hide') : Drupal.t('Show'))
          .prependTo($summary)
          .after(document.createTextNode(' '));

        // .wrapInner() does not retain bound events.
        $('<a class="details-title"></a>')
          .attr('href', `#${this.$node.attr('id')}`)
          .prepend($summary.contents())
          .appendTo($summary);

        $summary
          .append(this.$summary)
          .on('click', $.proxy(this.onSummaryClick, this));
      },

      /**
       * Handle summary clicks.
       *
       * @param {jQuery.Event} e
       *   The event triggered.
       */
      onSummaryClick(e) {
        this.toggle();
        e.preventDefault();
      },

      /**
       * Toggle the visibility of a details element using smooth animations.
       */
      toggle() {
        const isOpen = !!this.$node.attr('open');
        const $summaryPrefix = this.$node.find(
          '> summary span.details-summary-prefix',
        );
        if (isOpen) {
          $summaryPrefix.html(Drupal.t('Show'));
        } else {
          $summaryPrefix.html(Drupal.t('Hide'));
        }
        // Delay setting the attribute to emulate chrome behavior and make
        // details-aria.js work as expected with this polyfill.
        setTimeout(() => {
          this.$node.attr('open', !isOpen);
        }, 0);
      },
    },
  );

  /**
   * Polyfill HTML5 details element.
   *
   * @type {Drupal~behavior}
   *
   * @prop {Drupal~behaviorAttach} attach
   *   Attaches behavior for the details element.
   */
  Drupal.behaviors.collapse = {
    attach(context) {
      if (Modernizr.details) {
        return;
      }
      once('collapse', 'details', context).forEach((detail) => {
        // This class is used for styling purpose only.
        detail.classList.add('collapse-processed');
        CollapsibleDetails.instances.push(new CollapsibleDetails(detail));
      });
    },
  };

  /**
   * Open parent details elements of a targeted page fragment.
   *
   * Opens all (nested) details element on a hash change or fragment link click
   * when the target is a child element, in order to make sure the targeted
   * element is visible. Aria attributes on the summary
   * are set by triggering the click event listener in details-aria.js.
   *
   * @param {jQuery.Event} e
   *   The event triggered.
   * @param {jQuery} $target
   *   The targeted node as a jQuery object.
   */
  const handleFragmentLinkClickOrHashChange = (e, $target) => {
    $target.parents('details').not('[open]').find('> summary').trigger('click');
  };

  /**
   * Binds a listener to handle fragment link clicks and URL hash changes.
   */
  $('body').on(
    'formFragmentLinkClickOrHashChange.details',
    handleFragmentLinkClickOrHashChange,
  );

  // Expose constructor in the public space.
  Drupal.CollapsibleDetails = CollapsibleDetails;
})(jQuery, Modernizr, Drupal);

core/misc/details.js

0 → 100644
+31 −0
Original line number Diff line number Diff line
/**
 * @file
 * Additional functionality for HTML5 details elements.
 */

(function ($) {
  /**
   * Open parent details elements of a targeted page fragment.
   *
   * Opens all (nested) details element on a hash change or fragment link click
   * when the target is a child element, in order to make sure the targeted
   * element is visible. Aria attributes on the summary
   * are set by triggering the click event listener in details-aria.js.
   *
   * @param {jQuery.Event} e
   *   The event triggered.
   * @param {jQuery} $target
   *   The targeted node as a jQuery object.
   */
  const handleFragmentLinkClickOrHashChange = (e, $target) => {
    $target.parents('details').not('[open]').find('> summary').trigger('click');
  };

  /**
   * Binds a listener to handle fragment link clicks and URL hash changes.
   */
  $('body').on(
    'formFragmentLinkClickOrHashChange.details',
    handleFragmentLinkClickOrHashChange,
  );
})(jQuery);
+0 −15
Original line number Diff line number Diff line
@@ -49,21 +49,6 @@ protected function setUp(): void {
    $this->drupalLogin($this->adminUser);
  }

  /**
   * Ensures that vertical-tabs.js is included before collapse.js.
   *
   * Otherwise, collapse.js adds "SHOW" or "HIDE" labels to the tabs.
   */
  public function testJavaScriptOrdering() {
    $this->drupalGet('form_test/vertical-tabs');
    $content = $this->getSession()->getPage()->getContent();
    $position1 = strpos($content, 'core/misc/vertical-tabs.js');
    $position2 = strpos($content, 'core/misc/collapse.js');
    $this->assertNotFalse($position1);
    $this->assertNotFalse($position2);
    $this->assertGreaterThan($position1, $position2, 'vertical-tabs.js is included before collapse.js');
  }

  /**
   * Ensures that vertical tab markup is not shown if user has no tab access.
   */
+0 −1
Original line number Diff line number Diff line
@@ -26,7 +26,6 @@ libraries-override:
    css:
      component:
        css/components/button.css: css/my-button.css
        css/components/collapse-processed.css: css/my-collapse-processed.css
        css/components/container-inline.css: /themes/my_theme/css/my-container-inline.css
        css/components/details.css: /themes/my_theme/css/my-details.css
  # Remove particular library assets.
Loading