]>
Commit | Line | Data |
---|---|---|
91e44d91 S |
1 | import Util from './util' |
2 | ||
3 | ||
4 | /** | |
5 | * -------------------------------------------------------------------------- | |
6 | * Bootstrap (v4.0.0-alpha.6): tab.js | |
7 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) | |
8 | * -------------------------------------------------------------------------- | |
9 | */ | |
10 | ||
11 | const Tab = (($) => { | |
12 | ||
13 | ||
14 | /** | |
15 | * ------------------------------------------------------------------------ | |
16 | * Constants | |
17 | * ------------------------------------------------------------------------ | |
18 | */ | |
19 | ||
20 | const NAME = 'tab' | |
21 | const VERSION = '4.0.0-alpha.6' | |
22 | const DATA_KEY = 'bs.tab' | |
23 | const EVENT_KEY = `.${DATA_KEY}` | |
24 | const DATA_API_KEY = '.data-api' | |
25 | const JQUERY_NO_CONFLICT = $.fn[NAME] | |
26 | const TRANSITION_DURATION = 150 | |
27 | ||
28 | const Event = { | |
29 | HIDE : `hide${EVENT_KEY}`, | |
30 | HIDDEN : `hidden${EVENT_KEY}`, | |
31 | SHOW : `show${EVENT_KEY}`, | |
32 | SHOWN : `shown${EVENT_KEY}`, | |
33 | CLICK_DATA_API : `click${EVENT_KEY}${DATA_API_KEY}` | |
34 | } | |
35 | ||
36 | const ClassName = { | |
37 | DROPDOWN_MENU : 'dropdown-menu', | |
38 | ACTIVE : 'active', | |
39 | DISABLED : 'disabled', | |
40 | FADE : 'fade', | |
41 | SHOW : 'show' | |
42 | } | |
43 | ||
44 | const Selector = { | |
45 | A : 'a', | |
46 | LI : 'li', | |
47 | DROPDOWN : '.dropdown', | |
48 | LIST : 'ul:not(.dropdown-menu), ol:not(.dropdown-menu), nav:not(.dropdown-menu)', | |
49 | FADE_CHILD : '> .nav-item .fade, > .fade', | |
50 | ACTIVE : '.active', | |
51 | ACTIVE_CHILD : '> .nav-item > .active, > .active', | |
52 | DATA_TOGGLE : '[data-toggle="tab"], [data-toggle="pill"]', | |
53 | DROPDOWN_TOGGLE : '.dropdown-toggle', | |
54 | DROPDOWN_ACTIVE_CHILD : '> .dropdown-menu .active' | |
55 | } | |
56 | ||
57 | ||
58 | /** | |
59 | * ------------------------------------------------------------------------ | |
60 | * Class Definition | |
61 | * ------------------------------------------------------------------------ | |
62 | */ | |
63 | ||
64 | class Tab { | |
65 | ||
66 | constructor(element) { | |
67 | this._element = element | |
68 | } | |
69 | ||
70 | ||
71 | // getters | |
72 | ||
73 | static get VERSION() { | |
74 | return VERSION | |
75 | } | |
76 | ||
77 | ||
78 | // public | |
79 | ||
80 | show() { | |
81 | if (this._element.parentNode && | |
82 | this._element.parentNode.nodeType === Node.ELEMENT_NODE && | |
83 | $(this._element).hasClass(ClassName.ACTIVE) || | |
84 | $(this._element).hasClass(ClassName.DISABLED)) { | |
85 | return | |
86 | } | |
87 | ||
88 | let target | |
89 | let previous | |
90 | const listElement = $(this._element).closest(Selector.LIST)[0] | |
91 | const selector = Util.getSelectorFromElement(this._element) | |
92 | ||
93 | if (listElement) { | |
94 | previous = $.makeArray($(listElement).find(Selector.ACTIVE)) | |
95 | previous = previous[previous.length - 1] | |
96 | } | |
97 | ||
98 | const hideEvent = $.Event(Event.HIDE, { | |
99 | relatedTarget: this._element | |
100 | }) | |
101 | ||
102 | const showEvent = $.Event(Event.SHOW, { | |
103 | relatedTarget: previous | |
104 | }) | |
105 | ||
106 | if (previous) { | |
107 | $(previous).trigger(hideEvent) | |
108 | } | |
109 | ||
110 | $(this._element).trigger(showEvent) | |
111 | ||
112 | if (showEvent.isDefaultPrevented() || | |
113 | hideEvent.isDefaultPrevented()) { | |
114 | return | |
115 | } | |
116 | ||
117 | if (selector) { | |
118 | target = $(selector)[0] | |
119 | } | |
120 | ||
121 | this._activate( | |
122 | this._element, | |
123 | listElement | |
124 | ) | |
125 | ||
126 | const complete = () => { | |
127 | const hiddenEvent = $.Event(Event.HIDDEN, { | |
128 | relatedTarget: this._element | |
129 | }) | |
130 | ||
131 | const shownEvent = $.Event(Event.SHOWN, { | |
132 | relatedTarget: previous | |
133 | }) | |
134 | ||
135 | $(previous).trigger(hiddenEvent) | |
136 | $(this._element).trigger(shownEvent) | |
137 | } | |
138 | ||
139 | if (target) { | |
140 | this._activate(target, target.parentNode, complete) | |
141 | } else { | |
142 | complete() | |
143 | } | |
144 | } | |
145 | ||
146 | dispose() { | |
147 | $.removeClass(this._element, DATA_KEY) | |
148 | this._element = null | |
149 | } | |
150 | ||
151 | ||
152 | // private | |
153 | ||
154 | _activate(element, container, callback) { | |
155 | const active = $(container).find(Selector.ACTIVE_CHILD)[0] | |
156 | const isTransitioning = callback | |
157 | && Util.supportsTransitionEnd() | |
158 | && (active && $(active).hasClass(ClassName.FADE) | |
159 | || Boolean($(container).find(Selector.FADE_CHILD)[0])) | |
160 | ||
161 | const complete = () => this._transitionComplete( | |
162 | element, | |
163 | active, | |
164 | isTransitioning, | |
165 | callback | |
166 | ) | |
167 | ||
168 | if (active && isTransitioning) { | |
169 | $(active) | |
170 | .one(Util.TRANSITION_END, complete) | |
171 | .emulateTransitionEnd(TRANSITION_DURATION) | |
172 | ||
173 | } else { | |
174 | complete() | |
175 | } | |
176 | ||
177 | if (active) { | |
178 | $(active).removeClass(ClassName.SHOW) | |
179 | } | |
180 | } | |
181 | ||
182 | _transitionComplete(element, active, isTransitioning, callback) { | |
183 | if (active) { | |
184 | $(active).removeClass(ClassName.ACTIVE) | |
185 | ||
186 | const dropdownChild = $(active.parentNode).find( | |
187 | Selector.DROPDOWN_ACTIVE_CHILD | |
188 | )[0] | |
189 | ||
190 | if (dropdownChild) { | |
191 | $(dropdownChild).removeClass(ClassName.ACTIVE) | |
192 | } | |
193 | ||
194 | active.setAttribute('aria-expanded', false) | |
195 | } | |
196 | ||
197 | $(element).addClass(ClassName.ACTIVE) | |
198 | element.setAttribute('aria-expanded', true) | |
199 | ||
200 | if (isTransitioning) { | |
201 | Util.reflow(element) | |
202 | $(element).addClass(ClassName.SHOW) | |
203 | } else { | |
204 | $(element).removeClass(ClassName.FADE) | |
205 | } | |
206 | ||
207 | if (element.parentNode && | |
208 | $(element.parentNode).hasClass(ClassName.DROPDOWN_MENU)) { | |
209 | ||
210 | const dropdownElement = $(element).closest(Selector.DROPDOWN)[0] | |
211 | if (dropdownElement) { | |
212 | $(dropdownElement).find(Selector.DROPDOWN_TOGGLE).addClass(ClassName.ACTIVE) | |
213 | } | |
214 | ||
215 | element.setAttribute('aria-expanded', true) | |
216 | } | |
217 | ||
218 | if (callback) { | |
219 | callback() | |
220 | } | |
221 | } | |
222 | ||
223 | ||
224 | // static | |
225 | ||
226 | static _jQueryInterface(config) { | |
227 | return this.each(function () { | |
228 | const $this = $(this) | |
229 | let data = $this.data(DATA_KEY) | |
230 | ||
231 | if (!data) { | |
232 | data = new Tab(this) | |
233 | $this.data(DATA_KEY, data) | |
234 | } | |
235 | ||
236 | if (typeof config === 'string') { | |
237 | if (data[config] === undefined) { | |
238 | throw new Error(`No method named "${config}"`) | |
239 | } | |
240 | data[config]() | |
241 | } | |
242 | }) | |
243 | } | |
244 | ||
245 | } | |
246 | ||
247 | ||
248 | /** | |
249 | * ------------------------------------------------------------------------ | |
250 | * Data Api implementation | |
251 | * ------------------------------------------------------------------------ | |
252 | */ | |
253 | ||
254 | $(document) | |
255 | .on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function (event) { | |
256 | event.preventDefault() | |
257 | Tab._jQueryInterface.call($(this), 'show') | |
258 | }) | |
259 | ||
260 | ||
261 | /** | |
262 | * ------------------------------------------------------------------------ | |
263 | * jQuery | |
264 | * ------------------------------------------------------------------------ | |
265 | */ | |
266 | ||
267 | $.fn[NAME] = Tab._jQueryInterface | |
268 | $.fn[NAME].Constructor = Tab | |
269 | $.fn[NAME].noConflict = function () { | |
270 | $.fn[NAME] = JQUERY_NO_CONFLICT | |
271 | return Tab._jQueryInterface | |
272 | } | |
273 | ||
274 | return Tab | |
275 | ||
276 | })(jQuery) | |
277 | ||
278 | export default Tab |