123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146 |
- /**
- * @file
- * Polyfill for HTML5 details elements.
- */
- (function ($, Modernizr, Drupal) {
- 'use strict';
- /**
- * 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.
- var anchor = location.hash && location.hash !== '#' ? ', ' + location.hash : '';
- if (this.$node.find('.error' + anchor).length) {
- this.$node.attr('open', true);
- }
- // Initialize and setup the summary,
- this.setupSummary();
- // Initialize and setup the legend.
- this.setupLegend();
- }
- $.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 events and markup.
- *
- * @fires event:summaryUpdated
- *
- * @listens event:summaryUpdated
- */
- setupSummary: function () {
- this.$summary = $('<span class="summary"></span>');
- this.$node
- .on('summaryUpdated', $.proxy(this.onSummaryUpdated, this))
- .trigger('summaryUpdated');
- },
- /**
- * Initialize and setup legend markup.
- */
- setupLegend: function () {
- // Turn the summary into a clickable link.
- var $legend = this.$node.find('> summary');
- $('<span class="details-summary-prefix visually-hidden"></span>')
- .append(this.$node.attr('open') ? Drupal.t('Hide') : Drupal.t('Show'))
- .prependTo($legend)
- .after(document.createTextNode(' '));
- // .wrapInner() does not retain bound events.
- $('<a class="details-title"></a>')
- .attr('href', '#' + this.$node.attr('id'))
- .prepend($legend.contents())
- .appendTo($legend);
- $legend
- .append(this.$summary)
- .on('click', $.proxy(this.onLegendClick, this));
- },
- /**
- * Handle legend clicks.
- *
- * @param {jQuery.Event} e
- * The event triggered.
- */
- onLegendClick: function (e) {
- this.toggle();
- e.preventDefault();
- },
- /**
- * Update summary.
- */
- onSummaryUpdated: function () {
- var text = $.trim(this.$node.drupalGetSummary());
- this.$summary.html(text ? ' (' + text + ')' : '');
- },
- /**
- * Toggle the visibility of a details element using smooth animations.
- */
- toggle: function () {
- var isOpen = !!this.$node.attr('open');
- var $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(function () {
- this.$node.attr('open', !isOpen);
- }.bind(this), 0);
- }
- });
- /**
- * Polyfill HTML5 details element.
- *
- * @type {Drupal~behavior}
- *
- * @prop {Drupal~behaviorAttach} attach
- * Attaches behavior for the details element.
- */
- Drupal.behaviors.collapse = {
- attach: function (context) {
- if (Modernizr.details) {
- return;
- }
- var $collapsibleDetails = $(context).find('details').once('collapse').addClass('collapse-processed');
- if ($collapsibleDetails.length) {
- for (var i = 0; i < $collapsibleDetails.length; i++) {
- CollapsibleDetails.instances.push(new CollapsibleDetails($collapsibleDetails[i]));
- }
- }
- }
- };
- // Expose constructor in the public space.
- Drupal.CollapsibleDetails = CollapsibleDetails;
- })(jQuery, Modernizr, Drupal);
|