drupal/core/misc/collapse.js

114 lines
3.1 KiB
JavaScript

(function ($, Modernizr, Drupal) {
"use strict";
/**
* The collapsible details object represents a single collapsible 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 function.
*/
$.extend(CollapsibleDetails, {
/**
* Holds references to instantiated CollapsibleDetails objects.
*/
instances: []
});
/**
* Extend CollapsibleDetails prototype.
*/
$.extend(CollapsibleDetails.prototype, {
/**
* Initialize and setup summary events and markup.
*/
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)
.on('click', $.proxy(this.onLegendClick, this));
$legend.append(this.$summary);
},
/**
* Handle legend clicks
*/
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'));
}
this.$node.attr('open', !isOpen);
}
});
Drupal.behaviors.collapse = {
attach: function (context) {
if (Modernizr.details) {
return;
}
var $collapsibleDetails = $(context).find('details').once('collapse');
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);