source: imaps-frontend/node_modules/bootstrap/js/src/offcanvas.js

main
Last change on this file was d565449, checked in by stefan toskovski <stefantoska84@…>, 4 weeks ago

Update repo after prototype presentation

  • Property mode set to 100644
File size: 6.6 KB
Line 
1/**
2 * --------------------------------------------------------------------------
3 * Bootstrap offcanvas.js
4 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
5 * --------------------------------------------------------------------------
6 */
7
8import BaseComponent from './base-component.js'
9import EventHandler from './dom/event-handler.js'
10import SelectorEngine from './dom/selector-engine.js'
11import Backdrop from './util/backdrop.js'
12import { enableDismissTrigger } from './util/component-functions.js'
13import FocusTrap from './util/focustrap.js'
14import {
15 defineJQueryPlugin,
16 isDisabled,
17 isVisible
18} from './util/index.js'
19import ScrollBarHelper from './util/scrollbar.js'
20
21/**
22 * Constants
23 */
24
25const NAME = 'offcanvas'
26const DATA_KEY = 'bs.offcanvas'
27const EVENT_KEY = `.${DATA_KEY}`
28const DATA_API_KEY = '.data-api'
29const EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`
30const ESCAPE_KEY = 'Escape'
31
32const CLASS_NAME_SHOW = 'show'
33const CLASS_NAME_SHOWING = 'showing'
34const CLASS_NAME_HIDING = 'hiding'
35const CLASS_NAME_BACKDROP = 'offcanvas-backdrop'
36const OPEN_SELECTOR = '.offcanvas.show'
37
38const EVENT_SHOW = `show${EVENT_KEY}`
39const EVENT_SHOWN = `shown${EVENT_KEY}`
40const EVENT_HIDE = `hide${EVENT_KEY}`
41const EVENT_HIDE_PREVENTED = `hidePrevented${EVENT_KEY}`
42const EVENT_HIDDEN = `hidden${EVENT_KEY}`
43const EVENT_RESIZE = `resize${EVENT_KEY}`
44const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`
45const EVENT_KEYDOWN_DISMISS = `keydown.dismiss${EVENT_KEY}`
46
47const SELECTOR_DATA_TOGGLE = '[data-bs-toggle="offcanvas"]'
48
49const Default = {
50 backdrop: true,
51 keyboard: true,
52 scroll: false
53}
54
55const DefaultType = {
56 backdrop: '(boolean|string)',
57 keyboard: 'boolean',
58 scroll: 'boolean'
59}
60
61/**
62 * Class definition
63 */
64
65class Offcanvas extends BaseComponent {
66 constructor(element, config) {
67 super(element, config)
68
69 this._isShown = false
70 this._backdrop = this._initializeBackDrop()
71 this._focustrap = this._initializeFocusTrap()
72 this._addEventListeners()
73 }
74
75 // Getters
76 static get Default() {
77 return Default
78 }
79
80 static get DefaultType() {
81 return DefaultType
82 }
83
84 static get NAME() {
85 return NAME
86 }
87
88 // Public
89 toggle(relatedTarget) {
90 return this._isShown ? this.hide() : this.show(relatedTarget)
91 }
92
93 show(relatedTarget) {
94 if (this._isShown) {
95 return
96 }
97
98 const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, { relatedTarget })
99
100 if (showEvent.defaultPrevented) {
101 return
102 }
103
104 this._isShown = true
105 this._backdrop.show()
106
107 if (!this._config.scroll) {
108 new ScrollBarHelper().hide()
109 }
110
111 this._element.setAttribute('aria-modal', true)
112 this._element.setAttribute('role', 'dialog')
113 this._element.classList.add(CLASS_NAME_SHOWING)
114
115 const completeCallBack = () => {
116 if (!this._config.scroll || this._config.backdrop) {
117 this._focustrap.activate()
118 }
119
120 this._element.classList.add(CLASS_NAME_SHOW)
121 this._element.classList.remove(CLASS_NAME_SHOWING)
122 EventHandler.trigger(this._element, EVENT_SHOWN, { relatedTarget })
123 }
124
125 this._queueCallback(completeCallBack, this._element, true)
126 }
127
128 hide() {
129 if (!this._isShown) {
130 return
131 }
132
133 const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE)
134
135 if (hideEvent.defaultPrevented) {
136 return
137 }
138
139 this._focustrap.deactivate()
140 this._element.blur()
141 this._isShown = false
142 this._element.classList.add(CLASS_NAME_HIDING)
143 this._backdrop.hide()
144
145 const completeCallback = () => {
146 this._element.classList.remove(CLASS_NAME_SHOW, CLASS_NAME_HIDING)
147 this._element.removeAttribute('aria-modal')
148 this._element.removeAttribute('role')
149
150 if (!this._config.scroll) {
151 new ScrollBarHelper().reset()
152 }
153
154 EventHandler.trigger(this._element, EVENT_HIDDEN)
155 }
156
157 this._queueCallback(completeCallback, this._element, true)
158 }
159
160 dispose() {
161 this._backdrop.dispose()
162 this._focustrap.deactivate()
163 super.dispose()
164 }
165
166 // Private
167 _initializeBackDrop() {
168 const clickCallback = () => {
169 if (this._config.backdrop === 'static') {
170 EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED)
171 return
172 }
173
174 this.hide()
175 }
176
177 // 'static' option will be translated to true, and booleans will keep their value
178 const isVisible = Boolean(this._config.backdrop)
179
180 return new Backdrop({
181 className: CLASS_NAME_BACKDROP,
182 isVisible,
183 isAnimated: true,
184 rootElement: this._element.parentNode,
185 clickCallback: isVisible ? clickCallback : null
186 })
187 }
188
189 _initializeFocusTrap() {
190 return new FocusTrap({
191 trapElement: this._element
192 })
193 }
194
195 _addEventListeners() {
196 EventHandler.on(this._element, EVENT_KEYDOWN_DISMISS, event => {
197 if (event.key !== ESCAPE_KEY) {
198 return
199 }
200
201 if (this._config.keyboard) {
202 this.hide()
203 return
204 }
205
206 EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED)
207 })
208 }
209
210 // Static
211 static jQueryInterface(config) {
212 return this.each(function () {
213 const data = Offcanvas.getOrCreateInstance(this, config)
214
215 if (typeof config !== 'string') {
216 return
217 }
218
219 if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {
220 throw new TypeError(`No method named "${config}"`)
221 }
222
223 data[config](this)
224 })
225 }
226}
227
228/**
229 * Data API implementation
230 */
231
232EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
233 const target = SelectorEngine.getElementFromSelector(this)
234
235 if (['A', 'AREA'].includes(this.tagName)) {
236 event.preventDefault()
237 }
238
239 if (isDisabled(this)) {
240 return
241 }
242
243 EventHandler.one(target, EVENT_HIDDEN, () => {
244 // focus on trigger when it is closed
245 if (isVisible(this)) {
246 this.focus()
247 }
248 })
249
250 // avoid conflict when clicking a toggler of an offcanvas, while another is open
251 const alreadyOpen = SelectorEngine.findOne(OPEN_SELECTOR)
252 if (alreadyOpen && alreadyOpen !== target) {
253 Offcanvas.getInstance(alreadyOpen).hide()
254 }
255
256 const data = Offcanvas.getOrCreateInstance(target)
257 data.toggle(this)
258})
259
260EventHandler.on(window, EVENT_LOAD_DATA_API, () => {
261 for (const selector of SelectorEngine.find(OPEN_SELECTOR)) {
262 Offcanvas.getOrCreateInstance(selector).show()
263 }
264})
265
266EventHandler.on(window, EVENT_RESIZE, () => {
267 for (const element of SelectorEngine.find('[aria-modal][class*=show][class*=offcanvas-]')) {
268 if (getComputedStyle(element).position !== 'fixed') {
269 Offcanvas.getOrCreateInstance(element).hide()
270 }
271 }
272})
273
274enableDismissTrigger(Offcanvas)
275
276/**
277 * jQuery
278 */
279
280defineJQueryPlugin(Offcanvas)
281
282export default Offcanvas
Note: See TracBrowser for help on using the repository browser.