UNPKG

3.99 kBJavaScriptView Raw
1'use strict';
2
3import $ from 'jquery';
4import { Motion } from './foundation.util.motion';
5import { Plugin } from './foundation.plugin';
6import { Triggers } from './foundation.util.triggers';
7
8/**
9 * Toggler module.
10 * @module foundation.toggler
11 * @requires foundation.util.motion
12 * @requires foundation.util.triggers
13 */
14
15class Toggler extends Plugin {
16 /**
17 * Creates a new instance of Toggler.
18 * @class
19 * @name Toggler
20 * @fires Toggler#init
21 * @param {Object} element - jQuery object to add the trigger to.
22 * @param {Object} options - Overrides to the default plugin settings.
23 */
24 _setup(element, options) {
25 this.$element = element;
26 this.options = $.extend({}, Toggler.defaults, element.data(), options);
27 this.className = '';
28 this.className = 'Toggler'; // ie9 back compat
29
30 // Triggers init is idempotent, just need to make sure it is initialized
31 Triggers.init($);
32
33 this._init();
34 this._events();
35 }
36
37 /**
38 * Initializes the Toggler plugin by parsing the toggle class from data-toggler, or animation classes from data-animate.
39 * @function
40 * @private
41 */
42 _init() {
43 var input;
44 // Parse animation classes if they were set
45 if (this.options.animate) {
46 input = this.options.animate.split(' ');
47
48 this.animationIn = input[0];
49 this.animationOut = input[1] || null;
50 }
51 // Otherwise, parse toggle class
52 else {
53 input = this.$element.data('toggler');
54 // Allow for a . at the beginning of the string
55 this.className = input[0] === '.' ? input.slice(1) : input;
56 }
57
58 // Add ARIA attributes to triggers
59 var id = this.$element[0].id;
60 $(`[data-open="${id}"], [data-close="${id}"], [data-toggle="${id}"]`)
61 .attr('aria-controls', id);
62 // If the target is hidden, add aria-hidden
63 this.$element.attr('aria-expanded', this.$element.is(':hidden') ? false : true);
64 }
65
66 /**
67 * Initializes events for the toggle trigger.
68 * @function
69 * @private
70 */
71 _events() {
72 this.$element.off('toggle.zf.trigger').on('toggle.zf.trigger', this.toggle.bind(this));
73 }
74
75 /**
76 * Toggles the target class on the target element. An event is fired from the original trigger depending on if the resultant state was "on" or "off".
77 * @function
78 * @fires Toggler#on
79 * @fires Toggler#off
80 */
81 toggle() {
82 this[ this.options.animate ? '_toggleAnimate' : '_toggleClass']();
83 }
84
85 _toggleClass() {
86 this.$element.toggleClass(this.className);
87
88 var isOn = this.$element.hasClass(this.className);
89 if (isOn) {
90 /**
91 * Fires if the target element has the class after a toggle.
92 * @event Toggler#on
93 */
94 this.$element.trigger('on.zf.toggler');
95 }
96 else {
97 /**
98 * Fires if the target element does not have the class after a toggle.
99 * @event Toggler#off
100 */
101 this.$element.trigger('off.zf.toggler');
102 }
103
104 this._updateARIA(isOn);
105 this.$element.find('[data-mutate]').trigger('mutateme.zf.trigger');
106 }
107
108 _toggleAnimate() {
109 var _this = this;
110
111 if (this.$element.is(':hidden')) {
112 Motion.animateIn(this.$element, this.animationIn, function() {
113 _this._updateARIA(true);
114 this.trigger('on.zf.toggler');
115 this.find('[data-mutate]').trigger('mutateme.zf.trigger');
116 });
117 }
118 else {
119 Motion.animateOut(this.$element, this.animationOut, function() {
120 _this._updateARIA(false);
121 this.trigger('off.zf.toggler');
122 this.find('[data-mutate]').trigger('mutateme.zf.trigger');
123 });
124 }
125 }
126
127 _updateARIA(isOn) {
128 this.$element.attr('aria-expanded', isOn ? true : false);
129 }
130
131 /**
132 * Destroys the instance of Toggler on the element.
133 * @function
134 */
135 _destroy() {
136 this.$element.off('.zf.toggler');
137 }
138}
139
140Toggler.defaults = {
141 /**
142 * Tells the plugin if the element should animated when toggled.
143 * @option
144 * @type {boolean}
145 * @default false
146 */
147 animate: false
148};
149
150export {Toggler};