annotate core/misc/collapse.es6.js @ 0:c75dbcec494b

Initial commit from drush-created site
author Chris Cannam
date Thu, 05 Jul 2018 14:24:15 +0000
parents
children a9cd425dd02b
rev   line source
Chris@0 1 /**
Chris@0 2 * @file
Chris@0 3 * Polyfill for HTML5 details elements.
Chris@0 4 */
Chris@0 5
Chris@0 6 (function ($, Modernizr, Drupal) {
Chris@0 7 /**
Chris@0 8 * The collapsible details object represents a single details element.
Chris@0 9 *
Chris@0 10 * @constructor Drupal.CollapsibleDetails
Chris@0 11 *
Chris@0 12 * @param {HTMLElement} node
Chris@0 13 * The details element.
Chris@0 14 */
Chris@0 15 function CollapsibleDetails(node) {
Chris@0 16 this.$node = $(node);
Chris@0 17 this.$node.data('details', this);
Chris@0 18 // Expand details if there are errors inside, or if it contains an
Chris@0 19 // element that is targeted by the URI fragment identifier.
Chris@0 20 const anchor = location.hash && location.hash !== '#' ? `, ${location.hash}` : '';
Chris@0 21 if (this.$node.find(`.error${anchor}`).length) {
Chris@0 22 this.$node.attr('open', true);
Chris@0 23 }
Chris@0 24 // Initialize and setup the summary,
Chris@0 25 this.setupSummary();
Chris@0 26 // Initialize and setup the legend.
Chris@0 27 this.setupLegend();
Chris@0 28 }
Chris@0 29
Chris@0 30 $.extend(CollapsibleDetails, /** @lends Drupal.CollapsibleDetails */{
Chris@0 31
Chris@0 32 /**
Chris@0 33 * Holds references to instantiated CollapsibleDetails objects.
Chris@0 34 *
Chris@0 35 * @type {Array.<Drupal.CollapsibleDetails>}
Chris@0 36 */
Chris@0 37 instances: [],
Chris@0 38 });
Chris@0 39
Chris@0 40 $.extend(CollapsibleDetails.prototype, /** @lends Drupal.CollapsibleDetails# */{
Chris@0 41
Chris@0 42 /**
Chris@0 43 * Initialize and setup summary events and markup.
Chris@0 44 *
Chris@0 45 * @fires event:summaryUpdated
Chris@0 46 *
Chris@0 47 * @listens event:summaryUpdated
Chris@0 48 */
Chris@0 49 setupSummary() {
Chris@0 50 this.$summary = $('<span class="summary"></span>');
Chris@0 51 this.$node
Chris@0 52 .on('summaryUpdated', $.proxy(this.onSummaryUpdated, this))
Chris@0 53 .trigger('summaryUpdated');
Chris@0 54 },
Chris@0 55
Chris@0 56 /**
Chris@0 57 * Initialize and setup legend markup.
Chris@0 58 */
Chris@0 59 setupLegend() {
Chris@0 60 // Turn the summary into a clickable link.
Chris@0 61 const $legend = this.$node.find('> summary');
Chris@0 62
Chris@0 63 $('<span class="details-summary-prefix visually-hidden"></span>')
Chris@0 64 .append(this.$node.attr('open') ? Drupal.t('Hide') : Drupal.t('Show'))
Chris@0 65 .prependTo($legend)
Chris@0 66 .after(document.createTextNode(' '));
Chris@0 67
Chris@0 68 // .wrapInner() does not retain bound events.
Chris@0 69 $('<a class="details-title"></a>')
Chris@0 70 .attr('href', `#${this.$node.attr('id')}`)
Chris@0 71 .prepend($legend.contents())
Chris@0 72 .appendTo($legend);
Chris@0 73
Chris@0 74 $legend
Chris@0 75 .append(this.$summary)
Chris@0 76 .on('click', $.proxy(this.onLegendClick, this));
Chris@0 77 },
Chris@0 78
Chris@0 79 /**
Chris@0 80 * Handle legend clicks.
Chris@0 81 *
Chris@0 82 * @param {jQuery.Event} e
Chris@0 83 * The event triggered.
Chris@0 84 */
Chris@0 85 onLegendClick(e) {
Chris@0 86 this.toggle();
Chris@0 87 e.preventDefault();
Chris@0 88 },
Chris@0 89
Chris@0 90 /**
Chris@0 91 * Update summary.
Chris@0 92 */
Chris@0 93 onSummaryUpdated() {
Chris@0 94 const text = $.trim(this.$node.drupalGetSummary());
Chris@0 95 this.$summary.html(text ? ` (${text})` : '');
Chris@0 96 },
Chris@0 97
Chris@0 98 /**
Chris@0 99 * Toggle the visibility of a details element using smooth animations.
Chris@0 100 */
Chris@0 101 toggle() {
Chris@0 102 const isOpen = !!this.$node.attr('open');
Chris@0 103 const $summaryPrefix = this.$node.find('> summary span.details-summary-prefix');
Chris@0 104 if (isOpen) {
Chris@0 105 $summaryPrefix.html(Drupal.t('Show'));
Chris@0 106 }
Chris@0 107 else {
Chris@0 108 $summaryPrefix.html(Drupal.t('Hide'));
Chris@0 109 }
Chris@0 110 // Delay setting the attribute to emulate chrome behavior and make
Chris@0 111 // details-aria.js work as expected with this polyfill.
Chris@0 112 setTimeout(() => {
Chris@0 113 this.$node.attr('open', !isOpen);
Chris@0 114 }, 0);
Chris@0 115 },
Chris@0 116 });
Chris@0 117
Chris@0 118 /**
Chris@0 119 * Polyfill HTML5 details element.
Chris@0 120 *
Chris@0 121 * @type {Drupal~behavior}
Chris@0 122 *
Chris@0 123 * @prop {Drupal~behaviorAttach} attach
Chris@0 124 * Attaches behavior for the details element.
Chris@0 125 */
Chris@0 126 Drupal.behaviors.collapse = {
Chris@0 127 attach(context) {
Chris@0 128 if (Modernizr.details) {
Chris@0 129 return;
Chris@0 130 }
Chris@0 131 const $collapsibleDetails = $(context).find('details').once('collapse').addClass('collapse-processed');
Chris@0 132 if ($collapsibleDetails.length) {
Chris@0 133 for (let i = 0; i < $collapsibleDetails.length; i++) {
Chris@0 134 CollapsibleDetails.instances.push(new CollapsibleDetails($collapsibleDetails[i]));
Chris@0 135 }
Chris@0 136 }
Chris@0 137 },
Chris@0 138 };
Chris@0 139
Chris@0 140 /**
Chris@0 141 * Open parent details elements of a targeted page fragment.
Chris@0 142 *
Chris@0 143 * Opens all (nested) details element on a hash change or fragment link click
Chris@0 144 * when the target is a child element, in order to make sure the targeted
Chris@0 145 * element is visible. Aria attributes on the summary
Chris@0 146 * are set by triggering the click event listener in details-aria.js.
Chris@0 147 *
Chris@0 148 * @param {jQuery.Event} e
Chris@0 149 * The event triggered.
Chris@0 150 * @param {jQuery} $target
Chris@0 151 * The targeted node as a jQuery object.
Chris@0 152 */
Chris@0 153 const handleFragmentLinkClickOrHashChange = (e, $target) => {
Chris@0 154 $target.parents('details').not('[open]').find('> summary').trigger('click');
Chris@0 155 };
Chris@0 156
Chris@0 157 /**
Chris@0 158 * Binds a listener to handle fragment link clicks and URL hash changes.
Chris@0 159 */
Chris@0 160 $('body').on('formFragmentLinkClickOrHashChange.details', handleFragmentLinkClickOrHashChange);
Chris@0 161
Chris@0 162 // Expose constructor in the public space.
Chris@0 163 Drupal.CollapsibleDetails = CollapsibleDetails;
Chris@0 164 }(jQuery, Modernizr, Drupal));