administrate-bootstrap-theme 0.1.0 → 0.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +25 -11
- data/Rakefile +10 -14
- data/app/assets/config/administrate-bootstrap-theme_manifest.js +1 -0
- data/app/assets/javascripts/administrate-bootstrap-theme/theme.js +2 -0
- data/app/assets/stylesheets/administrate-bootstrap-theme/_base.scss +17 -1
- data/app/assets/stylesheets/administrate-bootstrap-theme/components/_content_body.scss +17 -3
- data/app/assets/stylesheets/administrate-bootstrap-theme/components/_form.scss +52 -16
- data/app/assets/stylesheets/administrate-bootstrap-theme/theme.scss +12 -0
- data/lib/administrate-bootstrap-theme/engine.rb +2 -0
- data/lib/administrate-bootstrap-theme/version.rb +1 -1
- data/node_modules/bootstrap/js/src/alert.js +141 -0
- data/node_modules/bootstrap/js/src/base-component.js +46 -0
- data/node_modules/bootstrap/js/src/button.js +95 -0
- data/node_modules/bootstrap/js/src/carousel.js +624 -0
- data/node_modules/bootstrap/js/src/collapse.js +410 -0
- data/node_modules/bootstrap/js/src/dom/data.js +57 -0
- data/node_modules/bootstrap/js/src/dom/event-handler.js +331 -0
- data/node_modules/bootstrap/js/src/dom/manipulator.js +80 -0
- data/node_modules/bootstrap/js/src/dom/selector-engine.js +75 -0
- data/node_modules/bootstrap/js/src/dropdown.js +543 -0
- data/node_modules/bootstrap/js/src/modal.js +582 -0
- data/node_modules/bootstrap/js/src/offcanvas.js +279 -0
- data/node_modules/bootstrap/js/src/popover.js +171 -0
- data/node_modules/bootstrap/js/src/scrollspy.js +319 -0
- data/node_modules/bootstrap/js/src/tab.js +220 -0
- data/node_modules/bootstrap/js/src/toast.js +219 -0
- data/node_modules/bootstrap/js/src/tooltip.js +802 -0
- data/node_modules/bootstrap/js/src/util/index.js +253 -0
- data/node_modules/bootstrap/js/src/util/sanitizer.js +127 -0
- data/node_modules/bootstrap/js/src/util/scrollbar.js +70 -0
- data/node_modules/bootstrap/scss/_accordion.scss +116 -0
- data/node_modules/bootstrap/scss/_alert.scss +57 -0
- data/node_modules/bootstrap/scss/_badge.scss +29 -0
- data/node_modules/bootstrap/scss/_breadcrumb.scss +28 -0
- data/node_modules/bootstrap/scss/_button-group.scss +139 -0
- data/node_modules/bootstrap/scss/_buttons.scss +111 -0
- data/node_modules/bootstrap/scss/_card.scss +215 -0
- data/node_modules/bootstrap/scss/_carousel.scss +229 -0
- data/node_modules/bootstrap/scss/_close.scss +40 -0
- data/node_modules/bootstrap/scss/_containers.scss +41 -0
- data/node_modules/bootstrap/scss/_dropdown.scss +246 -0
- data/node_modules/bootstrap/scss/_forms.scss +9 -0
- data/node_modules/bootstrap/scss/_functions.scss +205 -0
- data/node_modules/bootstrap/scss/_grid.scss +22 -0
- data/node_modules/bootstrap/scss/_helpers.scss +7 -0
- data/node_modules/bootstrap/scss/_images.scss +42 -0
- data/node_modules/bootstrap/scss/_list-group.scss +174 -0
- data/node_modules/bootstrap/scss/_mixins.scss +41 -0
- data/node_modules/bootstrap/scss/_modal.scss +237 -0
- data/node_modules/bootstrap/scss/_nav.scss +139 -0
- data/node_modules/bootstrap/scss/_navbar.scss +306 -0
- data/node_modules/bootstrap/scss/_offcanvas.scss +77 -0
- data/node_modules/bootstrap/scss/_pagination.scss +64 -0
- data/node_modules/bootstrap/scss/_popover.scss +158 -0
- data/node_modules/bootstrap/scss/_progress.scss +48 -0
- data/node_modules/bootstrap/scss/_reboot.scss +621 -0
- data/node_modules/bootstrap/scss/_root.scss +16 -0
- data/node_modules/bootstrap/scss/_spinners.scss +69 -0
- data/node_modules/bootstrap/scss/_tables.scss +150 -0
- data/node_modules/bootstrap/scss/_toasts.scss +51 -0
- data/node_modules/bootstrap/scss/_tooltip.scss +115 -0
- data/node_modules/bootstrap/scss/_transitions.scss +21 -0
- data/node_modules/bootstrap/scss/_type.scss +104 -0
- data/node_modules/bootstrap/scss/_utilities.scss +594 -0
- data/node_modules/bootstrap/scss/_variables.scss +1464 -0
- data/node_modules/bootstrap/scss/bootstrap-grid.scss +65 -0
- data/node_modules/bootstrap/scss/bootstrap-reboot.scss +15 -0
- data/node_modules/bootstrap/scss/bootstrap-utilities.scss +18 -0
- data/node_modules/bootstrap/scss/bootstrap.scss +52 -0
- data/node_modules/bootstrap/scss/forms/_floating-labels.scss +61 -0
- data/node_modules/bootstrap/scss/forms/_form-check.scss +152 -0
- data/node_modules/bootstrap/scss/forms/_form-control.scss +219 -0
- data/node_modules/bootstrap/scss/forms/_form-range.scss +91 -0
- data/node_modules/bootstrap/scss/forms/_form-select.scss +67 -0
- data/node_modules/bootstrap/scss/forms/_form-text.scss +11 -0
- data/node_modules/bootstrap/scss/forms/_input-group.scss +121 -0
- data/node_modules/bootstrap/scss/forms/_labels.scss +36 -0
- data/node_modules/bootstrap/scss/forms/_validation.scss +12 -0
- data/node_modules/bootstrap/scss/helpers/_clearfix.scss +3 -0
- data/node_modules/bootstrap/scss/helpers/_colored-links.scss +12 -0
- data/node_modules/bootstrap/scss/helpers/_position.scss +30 -0
- data/node_modules/bootstrap/scss/helpers/_ratio.scss +26 -0
- data/node_modules/bootstrap/scss/helpers/_stretched-link.scss +15 -0
- data/node_modules/bootstrap/scss/helpers/_text-truncation.scss +7 -0
- data/node_modules/bootstrap/scss/helpers/_visually-hidden.scss +8 -0
- data/node_modules/bootstrap/scss/mixins/_alert.scss +11 -0
- data/node_modules/bootstrap/scss/mixins/_border-radius.scss +78 -0
- data/node_modules/bootstrap/scss/mixins/_box-shadow.scss +18 -0
- data/node_modules/bootstrap/scss/mixins/_breakpoints.scss +127 -0
- data/node_modules/bootstrap/scss/mixins/_buttons.scss +133 -0
- data/node_modules/bootstrap/scss/mixins/_caret.scss +64 -0
- data/node_modules/bootstrap/scss/mixins/_clearfix.scss +9 -0
- data/node_modules/bootstrap/scss/mixins/_container.scss +9 -0
- data/node_modules/bootstrap/scss/mixins/_deprecate.scss +10 -0
- data/node_modules/bootstrap/scss/mixins/_forms.scss +134 -0
- data/node_modules/bootstrap/scss/mixins/_gradients.scss +47 -0
- data/node_modules/bootstrap/scss/mixins/_grid.scss +120 -0
- data/node_modules/bootstrap/scss/mixins/_image.scss +16 -0
- data/node_modules/bootstrap/scss/mixins/_list-group.scss +24 -0
- data/node_modules/bootstrap/scss/mixins/_lists.scss +7 -0
- data/node_modules/bootstrap/scss/mixins/_pagination.scss +31 -0
- data/node_modules/bootstrap/scss/mixins/_reset-text.scss +17 -0
- data/node_modules/bootstrap/scss/mixins/_resize.scss +6 -0
- data/node_modules/bootstrap/scss/mixins/_table-variants.scss +21 -0
- data/node_modules/bootstrap/scss/mixins/_text-truncate.scss +8 -0
- data/node_modules/bootstrap/scss/mixins/_transition.scss +26 -0
- data/node_modules/bootstrap/scss/mixins/_utilities.scss +68 -0
- data/node_modules/bootstrap/scss/mixins/_visually-hidden.scss +29 -0
- data/node_modules/bootstrap/scss/utilities/_api.scss +47 -0
- data/node_modules/bootstrap/scss/vendor/_rfs.scss +312 -0
- metadata +106 -19
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* --------------------------------------------------------------------------
|
|
3
|
+
* Bootstrap (v5.0.0-beta3): scrollspy.js
|
|
4
|
+
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
|
5
|
+
* --------------------------------------------------------------------------
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
defineJQueryPlugin,
|
|
10
|
+
getSelectorFromElement,
|
|
11
|
+
getUID,
|
|
12
|
+
isElement,
|
|
13
|
+
typeCheckConfig
|
|
14
|
+
} from './util/index'
|
|
15
|
+
import Data from './dom/data'
|
|
16
|
+
import EventHandler from './dom/event-handler'
|
|
17
|
+
import Manipulator from './dom/manipulator'
|
|
18
|
+
import SelectorEngine from './dom/selector-engine'
|
|
19
|
+
import BaseComponent from './base-component'
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* ------------------------------------------------------------------------
|
|
23
|
+
* Constants
|
|
24
|
+
* ------------------------------------------------------------------------
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
const NAME = 'scrollspy'
|
|
28
|
+
const DATA_KEY = 'bs.scrollspy'
|
|
29
|
+
const EVENT_KEY = `.${DATA_KEY}`
|
|
30
|
+
const DATA_API_KEY = '.data-api'
|
|
31
|
+
|
|
32
|
+
const Default = {
|
|
33
|
+
offset: 10,
|
|
34
|
+
method: 'auto',
|
|
35
|
+
target: ''
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const DefaultType = {
|
|
39
|
+
offset: 'number',
|
|
40
|
+
method: 'string',
|
|
41
|
+
target: '(string|element)'
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const EVENT_ACTIVATE = `activate${EVENT_KEY}`
|
|
45
|
+
const EVENT_SCROLL = `scroll${EVENT_KEY}`
|
|
46
|
+
const EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`
|
|
47
|
+
|
|
48
|
+
const CLASS_NAME_DROPDOWN_ITEM = 'dropdown-item'
|
|
49
|
+
const CLASS_NAME_ACTIVE = 'active'
|
|
50
|
+
|
|
51
|
+
const SELECTOR_DATA_SPY = '[data-bs-spy="scroll"]'
|
|
52
|
+
const SELECTOR_NAV_LIST_GROUP = '.nav, .list-group'
|
|
53
|
+
const SELECTOR_NAV_LINKS = '.nav-link'
|
|
54
|
+
const SELECTOR_NAV_ITEMS = '.nav-item'
|
|
55
|
+
const SELECTOR_LIST_ITEMS = '.list-group-item'
|
|
56
|
+
const SELECTOR_DROPDOWN = '.dropdown'
|
|
57
|
+
const SELECTOR_DROPDOWN_TOGGLE = '.dropdown-toggle'
|
|
58
|
+
|
|
59
|
+
const METHOD_OFFSET = 'offset'
|
|
60
|
+
const METHOD_POSITION = 'position'
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* ------------------------------------------------------------------------
|
|
64
|
+
* Class Definition
|
|
65
|
+
* ------------------------------------------------------------------------
|
|
66
|
+
*/
|
|
67
|
+
|
|
68
|
+
class ScrollSpy extends BaseComponent {
|
|
69
|
+
constructor(element, config) {
|
|
70
|
+
super(element)
|
|
71
|
+
this._scrollElement = this._element.tagName === 'BODY' ? window : this._element
|
|
72
|
+
this._config = this._getConfig(config)
|
|
73
|
+
this._selector = `${this._config.target} ${SELECTOR_NAV_LINKS}, ${this._config.target} ${SELECTOR_LIST_ITEMS}, ${this._config.target} .${CLASS_NAME_DROPDOWN_ITEM}`
|
|
74
|
+
this._offsets = []
|
|
75
|
+
this._targets = []
|
|
76
|
+
this._activeTarget = null
|
|
77
|
+
this._scrollHeight = 0
|
|
78
|
+
|
|
79
|
+
EventHandler.on(this._scrollElement, EVENT_SCROLL, () => this._process())
|
|
80
|
+
|
|
81
|
+
this.refresh()
|
|
82
|
+
this._process()
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Getters
|
|
86
|
+
|
|
87
|
+
static get Default() {
|
|
88
|
+
return Default
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
static get DATA_KEY() {
|
|
92
|
+
return DATA_KEY
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Public
|
|
96
|
+
|
|
97
|
+
refresh() {
|
|
98
|
+
const autoMethod = this._scrollElement === this._scrollElement.window ?
|
|
99
|
+
METHOD_OFFSET :
|
|
100
|
+
METHOD_POSITION
|
|
101
|
+
|
|
102
|
+
const offsetMethod = this._config.method === 'auto' ?
|
|
103
|
+
autoMethod :
|
|
104
|
+
this._config.method
|
|
105
|
+
|
|
106
|
+
const offsetBase = offsetMethod === METHOD_POSITION ?
|
|
107
|
+
this._getScrollTop() :
|
|
108
|
+
0
|
|
109
|
+
|
|
110
|
+
this._offsets = []
|
|
111
|
+
this._targets = []
|
|
112
|
+
this._scrollHeight = this._getScrollHeight()
|
|
113
|
+
|
|
114
|
+
const targets = SelectorEngine.find(this._selector)
|
|
115
|
+
|
|
116
|
+
targets.map(element => {
|
|
117
|
+
const targetSelector = getSelectorFromElement(element)
|
|
118
|
+
const target = targetSelector ? SelectorEngine.findOne(targetSelector) : null
|
|
119
|
+
|
|
120
|
+
if (target) {
|
|
121
|
+
const targetBCR = target.getBoundingClientRect()
|
|
122
|
+
if (targetBCR.width || targetBCR.height) {
|
|
123
|
+
return [
|
|
124
|
+
Manipulator[offsetMethod](target).top + offsetBase,
|
|
125
|
+
targetSelector
|
|
126
|
+
]
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return null
|
|
131
|
+
})
|
|
132
|
+
.filter(item => item)
|
|
133
|
+
.sort((a, b) => a[0] - b[0])
|
|
134
|
+
.forEach(item => {
|
|
135
|
+
this._offsets.push(item[0])
|
|
136
|
+
this._targets.push(item[1])
|
|
137
|
+
})
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
dispose() {
|
|
141
|
+
super.dispose()
|
|
142
|
+
EventHandler.off(this._scrollElement, EVENT_KEY)
|
|
143
|
+
|
|
144
|
+
this._scrollElement = null
|
|
145
|
+
this._config = null
|
|
146
|
+
this._selector = null
|
|
147
|
+
this._offsets = null
|
|
148
|
+
this._targets = null
|
|
149
|
+
this._activeTarget = null
|
|
150
|
+
this._scrollHeight = null
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Private
|
|
154
|
+
|
|
155
|
+
_getConfig(config) {
|
|
156
|
+
config = {
|
|
157
|
+
...Default,
|
|
158
|
+
...(typeof config === 'object' && config ? config : {})
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (typeof config.target !== 'string' && isElement(config.target)) {
|
|
162
|
+
let { id } = config.target
|
|
163
|
+
if (!id) {
|
|
164
|
+
id = getUID(NAME)
|
|
165
|
+
config.target.id = id
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
config.target = `#${id}`
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
typeCheckConfig(NAME, config, DefaultType)
|
|
172
|
+
|
|
173
|
+
return config
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
_getScrollTop() {
|
|
177
|
+
return this._scrollElement === window ?
|
|
178
|
+
this._scrollElement.pageYOffset :
|
|
179
|
+
this._scrollElement.scrollTop
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
_getScrollHeight() {
|
|
183
|
+
return this._scrollElement.scrollHeight || Math.max(
|
|
184
|
+
document.body.scrollHeight,
|
|
185
|
+
document.documentElement.scrollHeight
|
|
186
|
+
)
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
_getOffsetHeight() {
|
|
190
|
+
return this._scrollElement === window ?
|
|
191
|
+
window.innerHeight :
|
|
192
|
+
this._scrollElement.getBoundingClientRect().height
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
_process() {
|
|
196
|
+
const scrollTop = this._getScrollTop() + this._config.offset
|
|
197
|
+
const scrollHeight = this._getScrollHeight()
|
|
198
|
+
const maxScroll = this._config.offset + scrollHeight - this._getOffsetHeight()
|
|
199
|
+
|
|
200
|
+
if (this._scrollHeight !== scrollHeight) {
|
|
201
|
+
this.refresh()
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if (scrollTop >= maxScroll) {
|
|
205
|
+
const target = this._targets[this._targets.length - 1]
|
|
206
|
+
|
|
207
|
+
if (this._activeTarget !== target) {
|
|
208
|
+
this._activate(target)
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
if (this._activeTarget && scrollTop < this._offsets[0] && this._offsets[0] > 0) {
|
|
215
|
+
this._activeTarget = null
|
|
216
|
+
this._clear()
|
|
217
|
+
return
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
for (let i = this._offsets.length; i--;) {
|
|
221
|
+
const isActiveTarget = this._activeTarget !== this._targets[i] &&
|
|
222
|
+
scrollTop >= this._offsets[i] &&
|
|
223
|
+
(typeof this._offsets[i + 1] === 'undefined' || scrollTop < this._offsets[i + 1])
|
|
224
|
+
|
|
225
|
+
if (isActiveTarget) {
|
|
226
|
+
this._activate(this._targets[i])
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
_activate(target) {
|
|
232
|
+
this._activeTarget = target
|
|
233
|
+
|
|
234
|
+
this._clear()
|
|
235
|
+
|
|
236
|
+
const queries = this._selector.split(',')
|
|
237
|
+
.map(selector => `${selector}[data-bs-target="${target}"],${selector}[href="${target}"]`)
|
|
238
|
+
|
|
239
|
+
const link = SelectorEngine.findOne(queries.join(','))
|
|
240
|
+
|
|
241
|
+
if (link.classList.contains(CLASS_NAME_DROPDOWN_ITEM)) {
|
|
242
|
+
SelectorEngine.findOne(SELECTOR_DROPDOWN_TOGGLE, link.closest(SELECTOR_DROPDOWN))
|
|
243
|
+
.classList.add(CLASS_NAME_ACTIVE)
|
|
244
|
+
|
|
245
|
+
link.classList.add(CLASS_NAME_ACTIVE)
|
|
246
|
+
} else {
|
|
247
|
+
// Set triggered link as active
|
|
248
|
+
link.classList.add(CLASS_NAME_ACTIVE)
|
|
249
|
+
|
|
250
|
+
SelectorEngine.parents(link, SELECTOR_NAV_LIST_GROUP)
|
|
251
|
+
.forEach(listGroup => {
|
|
252
|
+
// Set triggered links parents as active
|
|
253
|
+
// With both <ul> and <nav> markup a parent is the previous sibling of any nav ancestor
|
|
254
|
+
SelectorEngine.prev(listGroup, `${SELECTOR_NAV_LINKS}, ${SELECTOR_LIST_ITEMS}`)
|
|
255
|
+
.forEach(item => item.classList.add(CLASS_NAME_ACTIVE))
|
|
256
|
+
|
|
257
|
+
// Handle special case when .nav-link is inside .nav-item
|
|
258
|
+
SelectorEngine.prev(listGroup, SELECTOR_NAV_ITEMS)
|
|
259
|
+
.forEach(navItem => {
|
|
260
|
+
SelectorEngine.children(navItem, SELECTOR_NAV_LINKS)
|
|
261
|
+
.forEach(item => item.classList.add(CLASS_NAME_ACTIVE))
|
|
262
|
+
})
|
|
263
|
+
})
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
EventHandler.trigger(this._scrollElement, EVENT_ACTIVATE, {
|
|
267
|
+
relatedTarget: target
|
|
268
|
+
})
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
_clear() {
|
|
272
|
+
SelectorEngine.find(this._selector)
|
|
273
|
+
.filter(node => node.classList.contains(CLASS_NAME_ACTIVE))
|
|
274
|
+
.forEach(node => node.classList.remove(CLASS_NAME_ACTIVE))
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// Static
|
|
278
|
+
|
|
279
|
+
static jQueryInterface(config) {
|
|
280
|
+
return this.each(function () {
|
|
281
|
+
let data = Data.get(this, DATA_KEY)
|
|
282
|
+
const _config = typeof config === 'object' && config
|
|
283
|
+
|
|
284
|
+
if (!data) {
|
|
285
|
+
data = new ScrollSpy(this, _config)
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
if (typeof config === 'string') {
|
|
289
|
+
if (typeof data[config] === 'undefined') {
|
|
290
|
+
throw new TypeError(`No method named "${config}"`)
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
data[config]()
|
|
294
|
+
}
|
|
295
|
+
})
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* ------------------------------------------------------------------------
|
|
301
|
+
* Data Api implementation
|
|
302
|
+
* ------------------------------------------------------------------------
|
|
303
|
+
*/
|
|
304
|
+
|
|
305
|
+
EventHandler.on(window, EVENT_LOAD_DATA_API, () => {
|
|
306
|
+
SelectorEngine.find(SELECTOR_DATA_SPY)
|
|
307
|
+
.forEach(spy => new ScrollSpy(spy, Manipulator.getDataAttributes(spy)))
|
|
308
|
+
})
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* ------------------------------------------------------------------------
|
|
312
|
+
* jQuery
|
|
313
|
+
* ------------------------------------------------------------------------
|
|
314
|
+
* add .ScrollSpy to jQuery only if jQuery is present
|
|
315
|
+
*/
|
|
316
|
+
|
|
317
|
+
defineJQueryPlugin(NAME, ScrollSpy)
|
|
318
|
+
|
|
319
|
+
export default ScrollSpy
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* --------------------------------------------------------------------------
|
|
3
|
+
* Bootstrap (v5.0.0-beta3): tab.js
|
|
4
|
+
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
|
5
|
+
* --------------------------------------------------------------------------
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
defineJQueryPlugin,
|
|
10
|
+
emulateTransitionEnd,
|
|
11
|
+
getElementFromSelector,
|
|
12
|
+
getTransitionDurationFromElement,
|
|
13
|
+
isDisabled,
|
|
14
|
+
reflow
|
|
15
|
+
} from './util/index'
|
|
16
|
+
import Data from './dom/data'
|
|
17
|
+
import EventHandler from './dom/event-handler'
|
|
18
|
+
import SelectorEngine from './dom/selector-engine'
|
|
19
|
+
import BaseComponent from './base-component'
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* ------------------------------------------------------------------------
|
|
23
|
+
* Constants
|
|
24
|
+
* ------------------------------------------------------------------------
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
const NAME = 'tab'
|
|
28
|
+
const DATA_KEY = 'bs.tab'
|
|
29
|
+
const EVENT_KEY = `.${DATA_KEY}`
|
|
30
|
+
const DATA_API_KEY = '.data-api'
|
|
31
|
+
|
|
32
|
+
const EVENT_HIDE = `hide${EVENT_KEY}`
|
|
33
|
+
const EVENT_HIDDEN = `hidden${EVENT_KEY}`
|
|
34
|
+
const EVENT_SHOW = `show${EVENT_KEY}`
|
|
35
|
+
const EVENT_SHOWN = `shown${EVENT_KEY}`
|
|
36
|
+
const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`
|
|
37
|
+
|
|
38
|
+
const CLASS_NAME_DROPDOWN_MENU = 'dropdown-menu'
|
|
39
|
+
const CLASS_NAME_ACTIVE = 'active'
|
|
40
|
+
const CLASS_NAME_FADE = 'fade'
|
|
41
|
+
const CLASS_NAME_SHOW = 'show'
|
|
42
|
+
|
|
43
|
+
const SELECTOR_DROPDOWN = '.dropdown'
|
|
44
|
+
const SELECTOR_NAV_LIST_GROUP = '.nav, .list-group'
|
|
45
|
+
const SELECTOR_ACTIVE = '.active'
|
|
46
|
+
const SELECTOR_ACTIVE_UL = ':scope > li > .active'
|
|
47
|
+
const SELECTOR_DATA_TOGGLE = '[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]'
|
|
48
|
+
const SELECTOR_DROPDOWN_TOGGLE = '.dropdown-toggle'
|
|
49
|
+
const SELECTOR_DROPDOWN_ACTIVE_CHILD = ':scope > .dropdown-menu .active'
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* ------------------------------------------------------------------------
|
|
53
|
+
* Class Definition
|
|
54
|
+
* ------------------------------------------------------------------------
|
|
55
|
+
*/
|
|
56
|
+
|
|
57
|
+
class Tab extends BaseComponent {
|
|
58
|
+
// Getters
|
|
59
|
+
|
|
60
|
+
static get DATA_KEY() {
|
|
61
|
+
return DATA_KEY
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Public
|
|
65
|
+
|
|
66
|
+
show() {
|
|
67
|
+
if ((this._element.parentNode &&
|
|
68
|
+
this._element.parentNode.nodeType === Node.ELEMENT_NODE &&
|
|
69
|
+
this._element.classList.contains(CLASS_NAME_ACTIVE)) ||
|
|
70
|
+
isDisabled(this._element)) {
|
|
71
|
+
return
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
let previous
|
|
75
|
+
const target = getElementFromSelector(this._element)
|
|
76
|
+
const listElement = this._element.closest(SELECTOR_NAV_LIST_GROUP)
|
|
77
|
+
|
|
78
|
+
if (listElement) {
|
|
79
|
+
const itemSelector = listElement.nodeName === 'UL' || listElement.nodeName === 'OL' ? SELECTOR_ACTIVE_UL : SELECTOR_ACTIVE
|
|
80
|
+
previous = SelectorEngine.find(itemSelector, listElement)
|
|
81
|
+
previous = previous[previous.length - 1]
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const hideEvent = previous ?
|
|
85
|
+
EventHandler.trigger(previous, EVENT_HIDE, {
|
|
86
|
+
relatedTarget: this._element
|
|
87
|
+
}) :
|
|
88
|
+
null
|
|
89
|
+
|
|
90
|
+
const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, {
|
|
91
|
+
relatedTarget: previous
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
if (showEvent.defaultPrevented || (hideEvent !== null && hideEvent.defaultPrevented)) {
|
|
95
|
+
return
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
this._activate(this._element, listElement)
|
|
99
|
+
|
|
100
|
+
const complete = () => {
|
|
101
|
+
EventHandler.trigger(previous, EVENT_HIDDEN, {
|
|
102
|
+
relatedTarget: this._element
|
|
103
|
+
})
|
|
104
|
+
EventHandler.trigger(this._element, EVENT_SHOWN, {
|
|
105
|
+
relatedTarget: previous
|
|
106
|
+
})
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (target) {
|
|
110
|
+
this._activate(target, target.parentNode, complete)
|
|
111
|
+
} else {
|
|
112
|
+
complete()
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Private
|
|
117
|
+
|
|
118
|
+
_activate(element, container, callback) {
|
|
119
|
+
const activeElements = container && (container.nodeName === 'UL' || container.nodeName === 'OL') ?
|
|
120
|
+
SelectorEngine.find(SELECTOR_ACTIVE_UL, container) :
|
|
121
|
+
SelectorEngine.children(container, SELECTOR_ACTIVE)
|
|
122
|
+
|
|
123
|
+
const active = activeElements[0]
|
|
124
|
+
const isTransitioning = callback && (active && active.classList.contains(CLASS_NAME_FADE))
|
|
125
|
+
|
|
126
|
+
const complete = () => this._transitionComplete(element, active, callback)
|
|
127
|
+
|
|
128
|
+
if (active && isTransitioning) {
|
|
129
|
+
const transitionDuration = getTransitionDurationFromElement(active)
|
|
130
|
+
active.classList.remove(CLASS_NAME_SHOW)
|
|
131
|
+
|
|
132
|
+
EventHandler.one(active, 'transitionend', complete)
|
|
133
|
+
emulateTransitionEnd(active, transitionDuration)
|
|
134
|
+
} else {
|
|
135
|
+
complete()
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
_transitionComplete(element, active, callback) {
|
|
140
|
+
if (active) {
|
|
141
|
+
active.classList.remove(CLASS_NAME_ACTIVE)
|
|
142
|
+
|
|
143
|
+
const dropdownChild = SelectorEngine.findOne(SELECTOR_DROPDOWN_ACTIVE_CHILD, active.parentNode)
|
|
144
|
+
|
|
145
|
+
if (dropdownChild) {
|
|
146
|
+
dropdownChild.classList.remove(CLASS_NAME_ACTIVE)
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (active.getAttribute('role') === 'tab') {
|
|
150
|
+
active.setAttribute('aria-selected', false)
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
element.classList.add(CLASS_NAME_ACTIVE)
|
|
155
|
+
if (element.getAttribute('role') === 'tab') {
|
|
156
|
+
element.setAttribute('aria-selected', true)
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
reflow(element)
|
|
160
|
+
|
|
161
|
+
if (element.classList.contains(CLASS_NAME_FADE)) {
|
|
162
|
+
element.classList.add(CLASS_NAME_SHOW)
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (element.parentNode && element.parentNode.classList.contains(CLASS_NAME_DROPDOWN_MENU)) {
|
|
166
|
+
const dropdownElement = element.closest(SELECTOR_DROPDOWN)
|
|
167
|
+
|
|
168
|
+
if (dropdownElement) {
|
|
169
|
+
SelectorEngine.find(SELECTOR_DROPDOWN_TOGGLE)
|
|
170
|
+
.forEach(dropdown => dropdown.classList.add(CLASS_NAME_ACTIVE))
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
element.setAttribute('aria-expanded', true)
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (callback) {
|
|
177
|
+
callback()
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Static
|
|
182
|
+
|
|
183
|
+
static jQueryInterface(config) {
|
|
184
|
+
return this.each(function () {
|
|
185
|
+
const data = Data.get(this, DATA_KEY) || new Tab(this)
|
|
186
|
+
|
|
187
|
+
if (typeof config === 'string') {
|
|
188
|
+
if (typeof data[config] === 'undefined') {
|
|
189
|
+
throw new TypeError(`No method named "${config}"`)
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
data[config]()
|
|
193
|
+
}
|
|
194
|
+
})
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* ------------------------------------------------------------------------
|
|
200
|
+
* Data Api implementation
|
|
201
|
+
* ------------------------------------------------------------------------
|
|
202
|
+
*/
|
|
203
|
+
|
|
204
|
+
EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
|
|
205
|
+
event.preventDefault()
|
|
206
|
+
|
|
207
|
+
const data = Data.get(this, DATA_KEY) || new Tab(this)
|
|
208
|
+
data.show()
|
|
209
|
+
})
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* ------------------------------------------------------------------------
|
|
213
|
+
* jQuery
|
|
214
|
+
* ------------------------------------------------------------------------
|
|
215
|
+
* add .Tab to jQuery only if jQuery is present
|
|
216
|
+
*/
|
|
217
|
+
|
|
218
|
+
defineJQueryPlugin(NAME, Tab)
|
|
219
|
+
|
|
220
|
+
export default Tab
|