mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-02-07 20:03:33 -05:00
Is clearer than just having one large hierarchical object and makes the relationships between the module and its components clearer.
165 lines
5.2 KiB
JavaScript
165 lines
5.2 KiB
JavaScript
(function (Modules) {
|
|
"use strict";
|
|
|
|
function Summary (module) {
|
|
this.module = module;
|
|
this.$el = module.$formGroup.find('.selection-summary');
|
|
this.fieldLabel = module.fieldLabel;
|
|
this.total = module.total;
|
|
this.addContent();
|
|
this.update(module.getSelection());
|
|
}
|
|
Summary.prototype.templates = {
|
|
all: (selection, total, field) => `All ${field}s`,
|
|
some: (selection, total, field) => `${selection} of ${total} ${field}s`,
|
|
none: (selection, total, field) => ({
|
|
"folder": "No folders (only templates outside a folder)",
|
|
"team member": "No team members (only you)"
|
|
}[field] || `No ${field}s`)
|
|
};
|
|
Summary.prototype.addContent = function() {
|
|
this.$text = $(`<p class="selection-summary__text" />`);
|
|
|
|
if (this.fieldLabel === 'folder') { this.$text.addClass('selection-summary__text--folders'); }
|
|
|
|
this.$el.append(this.$text);
|
|
};
|
|
Summary.prototype.update = function(selection) {
|
|
let template;
|
|
|
|
if (selection === this.total) {
|
|
template = 'all';
|
|
} else if (selection > 0) {
|
|
template = 'some';
|
|
} else {
|
|
template = 'none';
|
|
}
|
|
|
|
this.$text.html(this.templates[template](selection, this.total, this.fieldLabel));
|
|
};
|
|
Summary.prototype.bindEvents = function () {
|
|
// take summary out of tab order when focus moves
|
|
this.$el.on('blur', (e) => $(this).attr('tabindex', '-1'));
|
|
};
|
|
|
|
function Footer (module) {
|
|
this.module = module;
|
|
this.fieldLabel = module.fieldLabel;
|
|
this.fieldsetId = module.$fieldset.attr('id');
|
|
this.$el = this.getEl(this.module.expanded);
|
|
this.module.$formGroup.append(this.$el);
|
|
}
|
|
Footer.prototype.buttonContent = {
|
|
change: (fieldLabel) => `Choose ${fieldLabel}s`,
|
|
done: (fieldLabel) => `Done<span class="visuallyhidden"> choosing ${fieldLabel}s</span>`
|
|
};
|
|
Footer.prototype.getEl = function (expanded) {
|
|
const buttonState = expanded ? 'done' : 'change';
|
|
const buttonContent = this.buttonContent[buttonState](this.fieldLabel);
|
|
|
|
return $(`<div class="selection-footer">
|
|
<button
|
|
class="button button-secondary"
|
|
aria-expanded="${expanded ? 'true' : 'false'}"
|
|
aria-controls="${this.fieldsetId}">
|
|
${buttonContent}
|
|
</button>
|
|
</div>`);
|
|
};
|
|
Footer.prototype.update = function (expanded) {
|
|
this.$el.remove();
|
|
this.$el = this.getEl(expanded);
|
|
|
|
this.module.$formGroup.append(this.$el);
|
|
};
|
|
|
|
function CollapsibleCheckboxes () {}
|
|
CollapsibleCheckboxes.prototype._focusTextElement = ($el) => {
|
|
$el
|
|
.attr('tabindex', '-1')
|
|
.focus();
|
|
};
|
|
CollapsibleCheckboxes.prototype.start = function(component) {
|
|
this.$formGroup = $(component);
|
|
this.$fieldset = this.$formGroup.find('fieldset');
|
|
this.$checkboxes = this.$fieldset.find('input[type=checkbox]');
|
|
this.fieldLabel = this.$formGroup.data('fieldLabel');
|
|
this.total = this.$checkboxes.length;
|
|
this.legendText = this.$fieldset.find('legend').text().trim();
|
|
this.expanded = false;
|
|
|
|
this.addHeadingHideLegend();
|
|
|
|
// generate summary and footer
|
|
this.footer = new Footer(this);
|
|
this.summary = new Summary(this);
|
|
|
|
this.$fieldset.before(this.summary.$el);
|
|
|
|
// add custom classes
|
|
this.$formGroup.addClass('selection-wrapper');
|
|
this.$fieldset.addClass('selection-content');
|
|
|
|
// hide checkboxes
|
|
this.$fieldset.hide();
|
|
|
|
this.bindEvents();
|
|
};
|
|
CollapsibleCheckboxes.prototype.getSelection = function() { return this.$checkboxes.filter(':checked').length; };
|
|
CollapsibleCheckboxes.prototype.addHeadingHideLegend = function() {
|
|
const headingLevel = this.$formGroup.data('heading-level') || '2';
|
|
|
|
this.$heading = $(`<h${headingLevel} class="heading-small">${this.legendText}</h${headingLevel}>`);
|
|
this.$fieldset.before(this.$heading);
|
|
|
|
this.$fieldset.find('legend').addClass('visuallyhidden');
|
|
};
|
|
CollapsibleCheckboxes.prototype.expand = function(e) {
|
|
if (e !== undefined) { e.preventDefault(); }
|
|
|
|
if (!this.expanded) {
|
|
this.$fieldset.show();
|
|
this.expanded = true;
|
|
this.summary.update(this.getSelection());
|
|
this.footer.update(this.expanded);
|
|
}
|
|
|
|
// shift focus whether expanded or not
|
|
this._focusTextElement(this.$fieldset);
|
|
};
|
|
CollapsibleCheckboxes.prototype.collapse = function(e) {
|
|
if (e !== undefined) { e.preventDefault(); }
|
|
|
|
if (this.expanded) {
|
|
this.$fieldset.hide();
|
|
this.expanded = false;
|
|
this.summary.update(this.getSelection());
|
|
this.footer.update(this.expanded);
|
|
}
|
|
|
|
// shift focus whether expanded or not
|
|
this._focusTextElement(this.summary.$text);
|
|
};
|
|
CollapsibleCheckboxes.prototype.handleClick = function(e) {
|
|
if (this.expanded) {
|
|
this.collapse(e);
|
|
} else {
|
|
this.expand(e);
|
|
}
|
|
};
|
|
CollapsibleCheckboxes.prototype.handleSelection = function(e) {
|
|
this.summary.update(this.getSelection(), this.total, this.fieldLabel);
|
|
};
|
|
CollapsibleCheckboxes.prototype.bindEvents = function() {
|
|
const self = this;
|
|
|
|
this.$formGroup.on('click', '.button', this.handleClick.bind(this));
|
|
this.$checkboxes.on('click', this.handleSelection.bind(this));
|
|
|
|
this.summary.bindEvents(this);
|
|
};
|
|
|
|
Modules.CollapsibleCheckboxes = CollapsibleCheckboxes;
|
|
|
|
}(window.GOVUK.Modules));
|