corrade-http-templates – Blame information for rev 61
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
61 | office | 1 | import $ from 'jquery' |
2 | import Util from './util' |
||
3 | |||
4 | /** |
||
5 | * -------------------------------------------------------------------------- |
||
6 | * Bootstrap (v4.1.3): modal.js |
||
7 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) |
||
8 | * -------------------------------------------------------------------------- |
||
9 | */ |
||
10 | |||
11 | const Modal = (($) => { |
||
12 | /** |
||
13 | * ------------------------------------------------------------------------ |
||
14 | * Constants |
||
15 | * ------------------------------------------------------------------------ |
||
16 | */ |
||
17 | |||
18 | const NAME = 'modal' |
||
19 | const VERSION = '4.1.3' |
||
20 | const DATA_KEY = 'bs.modal' |
||
21 | const EVENT_KEY = `.${DATA_KEY}` |
||
22 | const DATA_API_KEY = '.data-api' |
||
23 | const JQUERY_NO_CONFLICT = $.fn[NAME] |
||
24 | const ESCAPE_KEYCODE = 27 // KeyboardEvent.which value for Escape (Esc) key |
||
25 | |||
26 | const Default = { |
||
27 | backdrop : true, |
||
28 | keyboard : true, |
||
29 | focus : true, |
||
30 | show : true |
||
31 | } |
||
32 | |||
33 | const DefaultType = { |
||
34 | backdrop : '(boolean|string)', |
||
35 | keyboard : 'boolean', |
||
36 | focus : 'boolean', |
||
37 | show : 'boolean' |
||
38 | } |
||
39 | |||
40 | const Event = { |
||
41 | HIDE : `hide${EVENT_KEY}`, |
||
42 | HIDDEN : `hidden${EVENT_KEY}`, |
||
43 | SHOW : `show${EVENT_KEY}`, |
||
44 | SHOWN : `shown${EVENT_KEY}`, |
||
45 | FOCUSIN : `focusin${EVENT_KEY}`, |
||
46 | RESIZE : `resize${EVENT_KEY}`, |
||
47 | CLICK_DISMISS : `click.dismiss${EVENT_KEY}`, |
||
48 | KEYDOWN_DISMISS : `keydown.dismiss${EVENT_KEY}`, |
||
49 | MOUSEUP_DISMISS : `mouseup.dismiss${EVENT_KEY}`, |
||
50 | MOUSEDOWN_DISMISS : `mousedown.dismiss${EVENT_KEY}`, |
||
51 | CLICK_DATA_API : `click${EVENT_KEY}${DATA_API_KEY}` |
||
52 | } |
||
53 | |||
54 | const ClassName = { |
||
55 | SCROLLBAR_MEASURER : 'modal-scrollbar-measure', |
||
56 | BACKDROP : 'modal-backdrop', |
||
57 | OPEN : 'modal-open', |
||
58 | FADE : 'fade', |
||
59 | SHOW : 'show' |
||
60 | } |
||
61 | |||
62 | const Selector = { |
||
63 | DIALOG : '.modal-dialog', |
||
64 | DATA_TOGGLE : '[data-toggle="modal"]', |
||
65 | DATA_DISMISS : '[data-dismiss="modal"]', |
||
66 | FIXED_CONTENT : '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top', |
||
67 | STICKY_CONTENT : '.sticky-top' |
||
68 | } |
||
69 | |||
70 | /** |
||
71 | * ------------------------------------------------------------------------ |
||
72 | * Class Definition |
||
73 | * ------------------------------------------------------------------------ |
||
74 | */ |
||
75 | |||
76 | class Modal { |
||
77 | constructor(element, config) { |
||
78 | this._config = this._getConfig(config) |
||
79 | this._element = element |
||
80 | this._dialog = element.querySelector(Selector.DIALOG) |
||
81 | this._backdrop = null |
||
82 | this._isShown = false |
||
83 | this._isBodyOverflowing = false |
||
84 | this._ignoreBackdropClick = false |
||
85 | this._scrollbarWidth = 0 |
||
86 | } |
||
87 | |||
88 | // Getters |
||
89 | |||
90 | static get VERSION() { |
||
91 | return VERSION |
||
92 | } |
||
93 | |||
94 | static get Default() { |
||
95 | return Default |
||
96 | } |
||
97 | |||
98 | // Public |
||
99 | |||
100 | toggle(relatedTarget) { |
||
101 | return this._isShown ? this.hide() : this.show(relatedTarget) |
||
102 | } |
||
103 | |||
104 | show(relatedTarget) { |
||
105 | if (this._isTransitioning || this._isShown) { |
||
106 | return |
||
107 | } |
||
108 | |||
109 | if ($(this._element).hasClass(ClassName.FADE)) { |
||
110 | this._isTransitioning = true |
||
111 | } |
||
112 | |||
113 | const showEvent = $.Event(Event.SHOW, { |
||
114 | relatedTarget |
||
115 | }) |
||
116 | |||
117 | $(this._element).trigger(showEvent) |
||
118 | |||
119 | if (this._isShown || showEvent.isDefaultPrevented()) { |
||
120 | return |
||
121 | } |
||
122 | |||
123 | this._isShown = true |
||
124 | |||
125 | this._checkScrollbar() |
||
126 | this._setScrollbar() |
||
127 | |||
128 | this._adjustDialog() |
||
129 | |||
130 | $(document.body).addClass(ClassName.OPEN) |
||
131 | |||
132 | this._setEscapeEvent() |
||
133 | this._setResizeEvent() |
||
134 | |||
135 | $(this._element).on( |
||
136 | Event.CLICK_DISMISS, |
||
137 | Selector.DATA_DISMISS, |
||
138 | (event) => this.hide(event) |
||
139 | ) |
||
140 | |||
141 | $(this._dialog).on(Event.MOUSEDOWN_DISMISS, () => { |
||
142 | $(this._element).one(Event.MOUSEUP_DISMISS, (event) => { |
||
143 | if ($(event.target).is(this._element)) { |
||
144 | this._ignoreBackdropClick = true |
||
145 | } |
||
146 | }) |
||
147 | }) |
||
148 | |||
149 | this._showBackdrop(() => this._showElement(relatedTarget)) |
||
150 | } |
||
151 | |||
152 | hide(event) { |
||
153 | if (event) { |
||
154 | event.preventDefault() |
||
155 | } |
||
156 | |||
157 | if (this._isTransitioning || !this._isShown) { |
||
158 | return |
||
159 | } |
||
160 | |||
161 | const hideEvent = $.Event(Event.HIDE) |
||
162 | |||
163 | $(this._element).trigger(hideEvent) |
||
164 | |||
165 | if (!this._isShown || hideEvent.isDefaultPrevented()) { |
||
166 | return |
||
167 | } |
||
168 | |||
169 | this._isShown = false |
||
170 | const transition = $(this._element).hasClass(ClassName.FADE) |
||
171 | |||
172 | if (transition) { |
||
173 | this._isTransitioning = true |
||
174 | } |
||
175 | |||
176 | this._setEscapeEvent() |
||
177 | this._setResizeEvent() |
||
178 | |||
179 | $(document).off(Event.FOCUSIN) |
||
180 | |||
181 | $(this._element).removeClass(ClassName.SHOW) |
||
182 | |||
183 | $(this._element).off(Event.CLICK_DISMISS) |
||
184 | $(this._dialog).off(Event.MOUSEDOWN_DISMISS) |
||
185 | |||
186 | |||
187 | if (transition) { |
||
188 | const transitionDuration = Util.getTransitionDurationFromElement(this._element) |
||
189 | |||
190 | $(this._element) |
||
191 | .one(Util.TRANSITION_END, (event) => this._hideModal(event)) |
||
192 | .emulateTransitionEnd(transitionDuration) |
||
193 | } else { |
||
194 | this._hideModal() |
||
195 | } |
||
196 | } |
||
197 | |||
198 | dispose() { |
||
199 | $.removeData(this._element, DATA_KEY) |
||
200 | |||
201 | $(window, document, this._element, this._backdrop).off(EVENT_KEY) |
||
202 | |||
203 | this._config = null |
||
204 | this._element = null |
||
205 | this._dialog = null |
||
206 | this._backdrop = null |
||
207 | this._isShown = null |
||
208 | this._isBodyOverflowing = null |
||
209 | this._ignoreBackdropClick = null |
||
210 | this._scrollbarWidth = null |
||
211 | } |
||
212 | |||
213 | handleUpdate() { |
||
214 | this._adjustDialog() |
||
215 | } |
||
216 | |||
217 | // Private |
||
218 | |||
219 | _getConfig(config) { |
||
220 | config = { |
||
221 | ...Default, |
||
222 | ...config |
||
223 | } |
||
224 | Util.typeCheckConfig(NAME, config, DefaultType) |
||
225 | return config |
||
226 | } |
||
227 | |||
228 | _showElement(relatedTarget) { |
||
229 | const transition = $(this._element).hasClass(ClassName.FADE) |
||
230 | |||
231 | if (!this._element.parentNode || |
||
232 | this._element.parentNode.nodeType !== Node.ELEMENT_NODE) { |
||
233 | // Don't move modal's DOM position |
||
234 | document.body.appendChild(this._element) |
||
235 | } |
||
236 | |||
237 | this._element.style.display = 'block' |
||
238 | this._element.removeAttribute('aria-hidden') |
||
239 | this._element.scrollTop = 0 |
||
240 | |||
241 | if (transition) { |
||
242 | Util.reflow(this._element) |
||
243 | } |
||
244 | |||
245 | $(this._element).addClass(ClassName.SHOW) |
||
246 | |||
247 | if (this._config.focus) { |
||
248 | this._enforceFocus() |
||
249 | } |
||
250 | |||
251 | const shownEvent = $.Event(Event.SHOWN, { |
||
252 | relatedTarget |
||
253 | }) |
||
254 | |||
255 | const transitionComplete = () => { |
||
256 | if (this._config.focus) { |
||
257 | this._element.focus() |
||
258 | } |
||
259 | this._isTransitioning = false |
||
260 | $(this._element).trigger(shownEvent) |
||
261 | } |
||
262 | |||
263 | if (transition) { |
||
264 | const transitionDuration = Util.getTransitionDurationFromElement(this._element) |
||
265 | |||
266 | $(this._dialog) |
||
267 | .one(Util.TRANSITION_END, transitionComplete) |
||
268 | .emulateTransitionEnd(transitionDuration) |
||
269 | } else { |
||
270 | transitionComplete() |
||
271 | } |
||
272 | } |
||
273 | |||
274 | _enforceFocus() { |
||
275 | $(document) |
||
276 | .off(Event.FOCUSIN) // Guard against infinite focus loop |
||
277 | .on(Event.FOCUSIN, (event) => { |
||
278 | if (document !== event.target && |
||
279 | this._element !== event.target && |
||
280 | $(this._element).has(event.target).length === 0) { |
||
281 | this._element.focus() |
||
282 | } |
||
283 | }) |
||
284 | } |
||
285 | |||
286 | _setEscapeEvent() { |
||
287 | if (this._isShown && this._config.keyboard) { |
||
288 | $(this._element).on(Event.KEYDOWN_DISMISS, (event) => { |
||
289 | if (event.which === ESCAPE_KEYCODE) { |
||
290 | event.preventDefault() |
||
291 | this.hide() |
||
292 | } |
||
293 | }) |
||
294 | } else if (!this._isShown) { |
||
295 | $(this._element).off(Event.KEYDOWN_DISMISS) |
||
296 | } |
||
297 | } |
||
298 | |||
299 | _setResizeEvent() { |
||
300 | if (this._isShown) { |
||
301 | $(window).on(Event.RESIZE, (event) => this.handleUpdate(event)) |
||
302 | } else { |
||
303 | $(window).off(Event.RESIZE) |
||
304 | } |
||
305 | } |
||
306 | |||
307 | _hideModal() { |
||
308 | this._element.style.display = 'none' |
||
309 | this._element.setAttribute('aria-hidden', true) |
||
310 | this._isTransitioning = false |
||
311 | this._showBackdrop(() => { |
||
312 | $(document.body).removeClass(ClassName.OPEN) |
||
313 | this._resetAdjustments() |
||
314 | this._resetScrollbar() |
||
315 | $(this._element).trigger(Event.HIDDEN) |
||
316 | }) |
||
317 | } |
||
318 | |||
319 | _removeBackdrop() { |
||
320 | if (this._backdrop) { |
||
321 | $(this._backdrop).remove() |
||
322 | this._backdrop = null |
||
323 | } |
||
324 | } |
||
325 | |||
326 | _showBackdrop(callback) { |
||
327 | const animate = $(this._element).hasClass(ClassName.FADE) |
||
328 | ? ClassName.FADE : '' |
||
329 | |||
330 | if (this._isShown && this._config.backdrop) { |
||
331 | this._backdrop = document.createElement('div') |
||
332 | this._backdrop.className = ClassName.BACKDROP |
||
333 | |||
334 | if (animate) { |
||
335 | this._backdrop.classList.add(animate) |
||
336 | } |
||
337 | |||
338 | $(this._backdrop).appendTo(document.body) |
||
339 | |||
340 | $(this._element).on(Event.CLICK_DISMISS, (event) => { |
||
341 | if (this._ignoreBackdropClick) { |
||
342 | this._ignoreBackdropClick = false |
||
343 | return |
||
344 | } |
||
345 | if (event.target !== event.currentTarget) { |
||
346 | return |
||
347 | } |
||
348 | if (this._config.backdrop === 'static') { |
||
349 | this._element.focus() |
||
350 | } else { |
||
351 | this.hide() |
||
352 | } |
||
353 | }) |
||
354 | |||
355 | if (animate) { |
||
356 | Util.reflow(this._backdrop) |
||
357 | } |
||
358 | |||
359 | $(this._backdrop).addClass(ClassName.SHOW) |
||
360 | |||
361 | if (!callback) { |
||
362 | return |
||
363 | } |
||
364 | |||
365 | if (!animate) { |
||
366 | callback() |
||
367 | return |
||
368 | } |
||
369 | |||
370 | const backdropTransitionDuration = Util.getTransitionDurationFromElement(this._backdrop) |
||
371 | |||
372 | $(this._backdrop) |
||
373 | .one(Util.TRANSITION_END, callback) |
||
374 | .emulateTransitionEnd(backdropTransitionDuration) |
||
375 | } else if (!this._isShown && this._backdrop) { |
||
376 | $(this._backdrop).removeClass(ClassName.SHOW) |
||
377 | |||
378 | const callbackRemove = () => { |
||
379 | this._removeBackdrop() |
||
380 | if (callback) { |
||
381 | callback() |
||
382 | } |
||
383 | } |
||
384 | |||
385 | if ($(this._element).hasClass(ClassName.FADE)) { |
||
386 | const backdropTransitionDuration = Util.getTransitionDurationFromElement(this._backdrop) |
||
387 | |||
388 | $(this._backdrop) |
||
389 | .one(Util.TRANSITION_END, callbackRemove) |
||
390 | .emulateTransitionEnd(backdropTransitionDuration) |
||
391 | } else { |
||
392 | callbackRemove() |
||
393 | } |
||
394 | } else if (callback) { |
||
395 | callback() |
||
396 | } |
||
397 | } |
||
398 | |||
399 | // ---------------------------------------------------------------------- |
||
400 | // the following methods are used to handle overflowing modals |
||
401 | // todo (fat): these should probably be refactored out of modal.js |
||
402 | // ---------------------------------------------------------------------- |
||
403 | |||
404 | _adjustDialog() { |
||
405 | const isModalOverflowing = |
||
406 | this._element.scrollHeight > document.documentElement.clientHeight |
||
407 | |||
408 | if (!this._isBodyOverflowing && isModalOverflowing) { |
||
409 | this._element.style.paddingLeft = `${this._scrollbarWidth}px` |
||
410 | } |
||
411 | |||
412 | if (this._isBodyOverflowing && !isModalOverflowing) { |
||
413 | this._element.style.paddingRight = `${this._scrollbarWidth}px` |
||
414 | } |
||
415 | } |
||
416 | |||
417 | _resetAdjustments() { |
||
418 | this._element.style.paddingLeft = '' |
||
419 | this._element.style.paddingRight = '' |
||
420 | } |
||
421 | |||
422 | _checkScrollbar() { |
||
423 | const rect = document.body.getBoundingClientRect() |
||
424 | this._isBodyOverflowing = rect.left + rect.right < window.innerWidth |
||
425 | this._scrollbarWidth = this._getScrollbarWidth() |
||
426 | } |
||
427 | |||
428 | _setScrollbar() { |
||
429 | if (this._isBodyOverflowing) { |
||
430 | // Note: DOMNode.style.paddingRight returns the actual value or '' if not set |
||
431 | // while $(DOMNode).css('padding-right') returns the calculated value or 0 if not set |
||
432 | const fixedContent = [].slice.call(document.querySelectorAll(Selector.FIXED_CONTENT)) |
||
433 | const stickyContent = [].slice.call(document.querySelectorAll(Selector.STICKY_CONTENT)) |
||
434 | |||
435 | // Adjust fixed content padding |
||
436 | $(fixedContent).each((index, element) => { |
||
437 | const actualPadding = element.style.paddingRight |
||
438 | const calculatedPadding = $(element).css('padding-right') |
||
439 | $(element) |
||
440 | .data('padding-right', actualPadding) |
||
441 | .css('padding-right', `${parseFloat(calculatedPadding) + this._scrollbarWidth}px`) |
||
442 | }) |
||
443 | |||
444 | // Adjust sticky content margin |
||
445 | $(stickyContent).each((index, element) => { |
||
446 | const actualMargin = element.style.marginRight |
||
447 | const calculatedMargin = $(element).css('margin-right') |
||
448 | $(element) |
||
449 | .data('margin-right', actualMargin) |
||
450 | .css('margin-right', `${parseFloat(calculatedMargin) - this._scrollbarWidth}px`) |
||
451 | }) |
||
452 | |||
453 | // Adjust body padding |
||
454 | const actualPadding = document.body.style.paddingRight |
||
455 | const calculatedPadding = $(document.body).css('padding-right') |
||
456 | $(document.body) |
||
457 | .data('padding-right', actualPadding) |
||
458 | .css('padding-right', `${parseFloat(calculatedPadding) + this._scrollbarWidth}px`) |
||
459 | } |
||
460 | } |
||
461 | |||
462 | _resetScrollbar() { |
||
463 | // Restore fixed content padding |
||
464 | const fixedContent = [].slice.call(document.querySelectorAll(Selector.FIXED_CONTENT)) |
||
465 | $(fixedContent).each((index, element) => { |
||
466 | const padding = $(element).data('padding-right') |
||
467 | $(element).removeData('padding-right') |
||
468 | element.style.paddingRight = padding ? padding : '' |
||
469 | }) |
||
470 | |||
471 | // Restore sticky content |
||
472 | const elements = [].slice.call(document.querySelectorAll(`${Selector.STICKY_CONTENT}`)) |
||
473 | $(elements).each((index, element) => { |
||
474 | const margin = $(element).data('margin-right') |
||
475 | if (typeof margin !== 'undefined') { |
||
476 | $(element).css('margin-right', margin).removeData('margin-right') |
||
477 | } |
||
478 | }) |
||
479 | |||
480 | // Restore body padding |
||
481 | const padding = $(document.body).data('padding-right') |
||
482 | $(document.body).removeData('padding-right') |
||
483 | document.body.style.paddingRight = padding ? padding : '' |
||
484 | } |
||
485 | |||
486 | _getScrollbarWidth() { // thx d.walsh |
||
487 | const scrollDiv = document.createElement('div') |
||
488 | scrollDiv.className = ClassName.SCROLLBAR_MEASURER |
||
489 | document.body.appendChild(scrollDiv) |
||
490 | const scrollbarWidth = scrollDiv.getBoundingClientRect().width - scrollDiv.clientWidth |
||
491 | document.body.removeChild(scrollDiv) |
||
492 | return scrollbarWidth |
||
493 | } |
||
494 | |||
495 | // Static |
||
496 | |||
497 | static _jQueryInterface(config, relatedTarget) { |
||
498 | return this.each(function () { |
||
499 | let data = $(this).data(DATA_KEY) |
||
500 | const _config = { |
||
501 | ...Default, |
||
502 | ...$(this).data(), |
||
503 | ...typeof config === 'object' && config ? config : {} |
||
504 | } |
||
505 | |||
506 | if (!data) { |
||
507 | data = new Modal(this, _config) |
||
508 | $(this).data(DATA_KEY, data) |
||
509 | } |
||
510 | |||
511 | if (typeof config === 'string') { |
||
512 | if (typeof data[config] === 'undefined') { |
||
513 | throw new TypeError(`No method named "${config}"`) |
||
514 | } |
||
515 | data[config](relatedTarget) |
||
516 | } else if (_config.show) { |
||
517 | data.show(relatedTarget) |
||
518 | } |
||
519 | }) |
||
520 | } |
||
521 | } |
||
522 | |||
523 | /** |
||
524 | * ------------------------------------------------------------------------ |
||
525 | * Data Api implementation |
||
526 | * ------------------------------------------------------------------------ |
||
527 | */ |
||
528 | |||
529 | $(document).on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function (event) { |
||
530 | let target |
||
531 | const selector = Util.getSelectorFromElement(this) |
||
532 | |||
533 | if (selector) { |
||
534 | target = document.querySelector(selector) |
||
535 | } |
||
536 | |||
537 | const config = $(target).data(DATA_KEY) |
||
538 | ? 'toggle' : { |
||
539 | ...$(target).data(), |
||
540 | ...$(this).data() |
||
541 | } |
||
542 | |||
543 | if (this.tagName === 'A' || this.tagName === 'AREA') { |
||
544 | event.preventDefault() |
||
545 | } |
||
546 | |||
547 | const $target = $(target).one(Event.SHOW, (showEvent) => { |
||
548 | if (showEvent.isDefaultPrevented()) { |
||
549 | // Only register focus restorer if modal will actually get shown |
||
550 | return |
||
551 | } |
||
552 | |||
553 | $target.one(Event.HIDDEN, () => { |
||
554 | if ($(this).is(':visible')) { |
||
555 | this.focus() |
||
556 | } |
||
557 | }) |
||
558 | }) |
||
559 | |||
560 | Modal._jQueryInterface.call($(target), config, this) |
||
561 | }) |
||
562 | |||
563 | /** |
||
564 | * ------------------------------------------------------------------------ |
||
565 | * jQuery |
||
566 | * ------------------------------------------------------------------------ |
||
567 | */ |
||
568 | |||
569 | $.fn[NAME] = Modal._jQueryInterface |
||
570 | $.fn[NAME].Constructor = Modal |
||
571 | $.fn[NAME].noConflict = function () { |
||
572 | $.fn[NAME] = JQUERY_NO_CONFLICT |
||
573 | return Modal._jQueryInterface |
||
574 | } |
||
575 | |||
576 | return Modal |
||
577 | })($) |
||
578 | |||
579 | export default Modal |