bajo-spatial 2.2.0 → 2.3.0
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.
- package/docs/BajoSpatial.html +1 -1
- package/docs/data/search.json +1 -1
- package/docs/global.html +1 -1
- package/docs/index.js.html +57 -17
- package/docs/scripts/core.js +477 -476
- package/docs/scripts/resize.js +36 -36
- package/docs/scripts/search.js +105 -105
- package/docs/scripts/third-party/fuse.js +1 -1
- package/docs/scripts/third-party/hljs-line-num-original.js +285 -282
- package/docs/scripts/third-party/hljs-line-num.js +1 -1
- package/docs/scripts/third-party/hljs-original.js +1202 -1195
- package/docs/scripts/third-party/hljs.js +1 -1
- package/docs/scripts/third-party/popper.js +1 -1
- package/docs/scripts/third-party/tippy.js +1 -1
- package/docs/scripts/third-party/tocbot.js +509 -508
- package/index.js +44 -4
- package/package.json +4 -2
- package/test/bajo-spatial.test.js +181 -0
- package/wiki/CHANGES.md +5 -0
|
@@ -1,671 +1,672 @@
|
|
|
1
1
|
/* eslint no-var: off */
|
|
2
2
|
var defaultOptions = {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
3
|
+
ignoreSelector: '.js-toc-ignore',
|
|
4
|
+
linkClass: 'toc-link',
|
|
5
|
+
extraLinkClasses: '',
|
|
6
|
+
activeLinkClass: 'is-active-link',
|
|
7
|
+
listClass: 'toc-list',
|
|
8
|
+
extraListClasses: '',
|
|
9
|
+
isCollapsedClass: 'is-collapsed',
|
|
10
|
+
collapsibleClass: 'is-collapsible',
|
|
11
|
+
listItemClass: 'toc-list-item',
|
|
12
|
+
activeListItemClass: 'is-active-li',
|
|
13
|
+
collapseDepth: 0,
|
|
14
|
+
scrollSmooth: true,
|
|
15
|
+
scrollSmoothDuration: 420,
|
|
16
|
+
scrollSmoothOffset: 0,
|
|
17
|
+
scrollEndCallback: function (e) { },
|
|
18
|
+
throttleTimeout: 50,
|
|
19
|
+
positionFixedSelector: null,
|
|
20
|
+
positionFixedClass: 'is-position-fixed',
|
|
21
|
+
fixedSidebarOffset: 'auto',
|
|
22
|
+
includeHtml: false,
|
|
23
|
+
includeTitleTags: false,
|
|
24
|
+
orderedList: true,
|
|
25
|
+
scrollContainer: null,
|
|
26
|
+
skipRendering: false,
|
|
27
|
+
headingLabelCallback: false,
|
|
28
|
+
ignoreHiddenElements: false,
|
|
29
|
+
headingObjectCallback: null,
|
|
30
|
+
basePath: '',
|
|
31
|
+
disableTocScrollSync: false
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
function ParseContent
|
|
35
|
-
|
|
34
|
+
function ParseContent(options) {
|
|
35
|
+
var reduce = [].reduce
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
/**
|
|
38
38
|
* Get the last item in an array and return a reference to it.
|
|
39
39
|
* @param {Array} array
|
|
40
40
|
* @return {Object}
|
|
41
41
|
*/
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
function getLastItem(array) {
|
|
43
|
+
return array[array.length - 1]
|
|
44
|
+
}
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
/**
|
|
47
47
|
* Get heading level for a heading dom node.
|
|
48
48
|
* @param {HTMLElement} heading
|
|
49
49
|
* @return {Number}
|
|
50
50
|
*/
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
51
|
+
function getHeadingLevel(heading) {
|
|
52
|
+
return +heading.nodeName.toUpperCase().replace('H', '')
|
|
53
|
+
}
|
|
54
54
|
|
|
55
|
-
|
|
55
|
+
/**
|
|
56
56
|
* Get important properties from a heading element and store in a plain object.
|
|
57
57
|
* @param {HTMLElement} heading
|
|
58
58
|
* @return {Object}
|
|
59
59
|
*/
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
60
|
+
function getHeadingObject(heading) {
|
|
61
|
+
// each node is processed twice by this method because nestHeadingsArray() and addNode() calls it
|
|
62
|
+
// first time heading is real DOM node element, second time it is obj
|
|
63
|
+
// that is causing problem so I am processing only original DOM node
|
|
64
|
+
if (!(heading instanceof window.HTMLElement)) return heading
|
|
65
|
+
|
|
66
|
+
if (options.ignoreHiddenElements && (!heading.offsetHeight || !heading.offsetParent)) {
|
|
67
|
+
return null
|
|
68
|
+
}
|
|
69
69
|
|
|
70
|
-
|
|
70
|
+
const headingLabel = heading.getAttribute('data-heading-label') ||
|
|
71
71
|
(options.headingLabelCallback ? String(options.headingLabelCallback(heading.textContent)) : heading.textContent.trim())
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
72
|
+
var obj = {
|
|
73
|
+
id: heading.id,
|
|
74
|
+
children: [],
|
|
75
|
+
nodeName: heading.nodeName,
|
|
76
|
+
headingLevel: getHeadingLevel(heading),
|
|
77
|
+
textContent: headingLabel
|
|
78
|
+
}
|
|
79
79
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
80
|
+
if (options.includeHtml) {
|
|
81
|
+
obj.childNodes = heading.childNodes
|
|
82
|
+
}
|
|
83
83
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
84
|
+
if (options.headingObjectCallback) {
|
|
85
|
+
return options.headingObjectCallback(obj, heading)
|
|
86
|
+
}
|
|
87
87
|
|
|
88
|
-
|
|
89
|
-
|
|
88
|
+
return obj
|
|
89
|
+
}
|
|
90
90
|
|
|
91
|
-
|
|
91
|
+
/**
|
|
92
92
|
* Add a node to the nested array.
|
|
93
93
|
* @param {Object} node
|
|
94
94
|
* @param {Array} nest
|
|
95
95
|
* @return {Array}
|
|
96
96
|
*/
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
97
|
+
function addNode(node, nest) {
|
|
98
|
+
var obj = getHeadingObject(node)
|
|
99
|
+
var level = obj.headingLevel
|
|
100
|
+
var array = nest
|
|
101
|
+
var lastItem = getLastItem(array)
|
|
102
|
+
var lastItemLevel = lastItem
|
|
103
|
+
? lastItem.headingLevel
|
|
104
|
+
: 0
|
|
105
|
+
var counter = level - lastItemLevel
|
|
106
|
+
|
|
107
|
+
while (counter > 0) {
|
|
108
|
+
lastItem = getLastItem(array)
|
|
109
|
+
// Handle case where there are multiple h5+ in a row.
|
|
110
|
+
if (lastItem && level === lastItem.headingLevel) {
|
|
111
|
+
break
|
|
112
|
+
} else if (lastItem && lastItem.children !== undefined) {
|
|
113
|
+
array = lastItem.children
|
|
114
|
+
}
|
|
115
|
+
counter--
|
|
116
|
+
}
|
|
117
117
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
118
|
+
if (level >= options.collapseDepth) {
|
|
119
|
+
obj.isCollapsed = true
|
|
120
|
+
}
|
|
121
121
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
122
|
+
array.push(obj)
|
|
123
|
+
return array
|
|
124
|
+
}
|
|
125
125
|
|
|
126
|
-
|
|
126
|
+
/**
|
|
127
127
|
* Select headings in content area, exclude any selector in options.ignoreSelector
|
|
128
128
|
* @param {HTMLElement} contentElement
|
|
129
129
|
* @param {Array} headingSelector
|
|
130
130
|
* @return {Array}
|
|
131
131
|
*/
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
132
|
+
function selectHeadings(contentElement, headingSelector) {
|
|
133
|
+
var selectors = headingSelector
|
|
134
|
+
if (options.ignoreSelector) {
|
|
135
|
+
selectors = headingSelector.split(',')
|
|
136
|
+
.map(function mapSelectors(selector) {
|
|
137
|
+
return selector.trim() + ':not(' + options.ignoreSelector + ')'
|
|
138
|
+
})
|
|
139
|
+
}
|
|
140
|
+
try {
|
|
141
|
+
return contentElement.querySelectorAll(selectors)
|
|
142
|
+
} catch (e) {
|
|
143
143
|
console.warn('Headers not found with selector: ' + selectors); // eslint-disable-line
|
|
144
|
-
|
|
144
|
+
return null
|
|
145
|
+
}
|
|
145
146
|
}
|
|
146
|
-
}
|
|
147
147
|
|
|
148
|
-
|
|
148
|
+
/**
|
|
149
149
|
* Nest headings array into nested arrays with 'children' property.
|
|
150
150
|
* @param {Array} headingsArray
|
|
151
151
|
* @return {Object}
|
|
152
152
|
*/
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
return {
|
|
166
|
-
nestHeadingsArray,
|
|
167
|
-
selectHeadings
|
|
168
|
-
}
|
|
169
|
-
}
|
|
153
|
+
function nestHeadingsArray(headingsArray) {
|
|
154
|
+
return reduce.call(headingsArray, function reducer(prev, curr) {
|
|
155
|
+
var currentHeading = getHeadingObject(curr)
|
|
156
|
+
if (currentHeading) {
|
|
157
|
+
addNode(currentHeading, prev.nest)
|
|
158
|
+
}
|
|
159
|
+
return prev
|
|
160
|
+
}, {
|
|
161
|
+
nest: []
|
|
162
|
+
})
|
|
163
|
+
}
|
|
170
164
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
var mainContainer = document.querySelector(options.contentSelector)
|
|
177
|
-
var currentlyHighlighting = true
|
|
178
|
-
var SPACE_CHAR = ' '
|
|
165
|
+
return {
|
|
166
|
+
nestHeadingsArray: nestHeadingsArray,
|
|
167
|
+
selectHeadings: selectHeadings
|
|
168
|
+
}
|
|
169
|
+
}
|
|
179
170
|
|
|
180
|
-
|
|
171
|
+
function BuildHtml(options) {
|
|
172
|
+
var forEach = [].forEach
|
|
173
|
+
var some = [].some
|
|
174
|
+
var body = document.body
|
|
175
|
+
var tocElement
|
|
176
|
+
var mainContainer = document.querySelector(options.contentSelector)
|
|
177
|
+
var currentlyHighlighting = true
|
|
178
|
+
var SPACE_CHAR = ' '
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
181
|
* Create link and list elements.
|
|
182
182
|
* @param {Object} d
|
|
183
183
|
* @param {HTMLElement} container
|
|
184
184
|
* @return {HTMLElement}
|
|
185
185
|
*/
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
186
|
+
function createEl(d, container) {
|
|
187
|
+
var link = container.appendChild(createLink(d))
|
|
188
|
+
if (d.children.length) {
|
|
189
|
+
var list = createList(d.isCollapsed)
|
|
190
|
+
d.children.forEach(function (child) {
|
|
191
|
+
createEl(child, list)
|
|
192
|
+
})
|
|
193
|
+
link.appendChild(list)
|
|
194
|
+
}
|
|
194
195
|
}
|
|
195
|
-
}
|
|
196
196
|
|
|
197
|
-
|
|
197
|
+
/**
|
|
198
198
|
* Render nested heading array data into a given element.
|
|
199
199
|
* @param {HTMLElement} parent Optional. If provided updates the {@see tocElement} to match.
|
|
200
200
|
* @param {Array} data
|
|
201
201
|
* @return {HTMLElement}
|
|
202
202
|
*/
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
data.forEach(function (d) {
|
|
208
|
-
createEl(d, container)
|
|
209
|
-
})
|
|
210
|
-
|
|
211
|
-
// Return if no TOC element is provided or known.
|
|
212
|
-
tocElement = parent || tocElement
|
|
213
|
-
if (tocElement === null) {
|
|
214
|
-
return
|
|
215
|
-
}
|
|
203
|
+
function render(parent, data) {
|
|
204
|
+
var collapsed = false
|
|
205
|
+
var container = createList(collapsed)
|
|
216
206
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
}
|
|
207
|
+
data.forEach(function (d) {
|
|
208
|
+
createEl(d, container)
|
|
209
|
+
})
|
|
221
210
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
211
|
+
// Return if no TOC element is provided or known.
|
|
212
|
+
tocElement = parent || tocElement
|
|
213
|
+
if (tocElement === null) {
|
|
214
|
+
return
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Remove existing child if it exists.
|
|
218
|
+
if (tocElement.firstChild) {
|
|
219
|
+
tocElement.removeChild(tocElement.firstChild)
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Just return the parent and don't append the list if no links are found.
|
|
223
|
+
if (data.length === 0) {
|
|
224
|
+
return tocElement
|
|
225
|
+
}
|
|
226
226
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
227
|
+
// Append the Elements that have been created
|
|
228
|
+
return tocElement.appendChild(container)
|
|
229
|
+
}
|
|
230
230
|
|
|
231
|
-
|
|
231
|
+
/**
|
|
232
232
|
* Create link element.
|
|
233
233
|
* @param {Object} data
|
|
234
234
|
* @return {HTMLElement}
|
|
235
235
|
*/
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
236
|
+
function createLink(data) {
|
|
237
|
+
var item = document.createElement('li')
|
|
238
|
+
var a = document.createElement('a')
|
|
239
|
+
if (options.listItemClass) {
|
|
240
|
+
item.setAttribute('class', options.listItemClass)
|
|
241
|
+
}
|
|
242
242
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
243
|
+
if (options.onClick) {
|
|
244
|
+
a.onclick = options.onClick
|
|
245
|
+
}
|
|
246
246
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
247
|
+
if (options.includeTitleTags) {
|
|
248
|
+
a.setAttribute('title', data.textContent)
|
|
249
|
+
}
|
|
250
250
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
251
|
+
if (options.includeHtml && data.childNodes.length) {
|
|
252
|
+
forEach.call(data.childNodes, function (node) {
|
|
253
|
+
a.appendChild(node.cloneNode(true))
|
|
254
|
+
})
|
|
255
|
+
} else {
|
|
256
|
+
// Default behavior.
|
|
257
|
+
a.textContent = data.textContent
|
|
258
|
+
}
|
|
259
|
+
a.setAttribute('href', options.basePath + '#' + data.id)
|
|
260
|
+
a.setAttribute('class', options.linkClass +
|
|
261
261
|
SPACE_CHAR + 'node-name--' + data.nodeName +
|
|
262
262
|
SPACE_CHAR + options.extraLinkClasses)
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
263
|
+
item.appendChild(a)
|
|
264
|
+
return item
|
|
265
|
+
}
|
|
266
266
|
|
|
267
|
-
|
|
267
|
+
/**
|
|
268
268
|
* Create list element.
|
|
269
269
|
* @param {Boolean} isCollapsed
|
|
270
270
|
* @return {HTMLElement}
|
|
271
271
|
*/
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
272
|
+
function createList(isCollapsed) {
|
|
273
|
+
var listElement = (options.orderedList) ? 'ol' : 'ul'
|
|
274
|
+
var list = document.createElement(listElement)
|
|
275
|
+
var classes = options.listClass +
|
|
276
276
|
SPACE_CHAR + options.extraListClasses
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
277
|
+
if (isCollapsed) {
|
|
278
|
+
classes += SPACE_CHAR + options.collapsibleClass
|
|
279
|
+
classes += SPACE_CHAR + options.isCollapsedClass
|
|
280
|
+
}
|
|
281
|
+
list.setAttribute('class', classes)
|
|
282
|
+
return list
|
|
280
283
|
}
|
|
281
|
-
list.setAttribute('class', classes)
|
|
282
|
-
return list
|
|
283
|
-
}
|
|
284
284
|
|
|
285
|
-
|
|
285
|
+
/**
|
|
286
286
|
* Update fixed sidebar class.
|
|
287
287
|
* @return {HTMLElement}
|
|
288
288
|
*/
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
289
|
+
function updateFixedSidebarClass() {
|
|
290
|
+
if (options.scrollContainer && document.querySelector(options.scrollContainer)) {
|
|
291
|
+
var top
|
|
292
|
+
top = document.querySelector(options.scrollContainer).scrollTop
|
|
293
|
+
} else {
|
|
294
|
+
top = document.documentElement.scrollTop || body.scrollTop
|
|
295
|
+
}
|
|
296
|
+
var posFixedEl = document.querySelector(options.positionFixedSelector)
|
|
297
297
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
298
|
+
if (options.fixedSidebarOffset === 'auto') {
|
|
299
|
+
options.fixedSidebarOffset = tocElement.offsetTop
|
|
300
|
+
}
|
|
301
301
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
302
|
+
if (top > options.fixedSidebarOffset) {
|
|
303
|
+
if (posFixedEl.className.indexOf(options.positionFixedClass) === -1) {
|
|
304
|
+
posFixedEl.className += SPACE_CHAR + options.positionFixedClass
|
|
305
|
+
}
|
|
306
|
+
} else {
|
|
307
|
+
posFixedEl.className = posFixedEl.className.split(SPACE_CHAR + options.positionFixedClass).join('')
|
|
308
|
+
}
|
|
308
309
|
}
|
|
309
|
-
}
|
|
310
310
|
|
|
311
|
-
|
|
311
|
+
/**
|
|
312
312
|
* Get top position of heading
|
|
313
313
|
* @param {HTMLElement} obj
|
|
314
314
|
* @return {int} position
|
|
315
315
|
*/
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
316
|
+
function getHeadingTopPos(obj) {
|
|
317
|
+
var position = 0
|
|
318
|
+
if (obj !== null) {
|
|
319
|
+
position = obj.offsetTop
|
|
320
|
+
if (options.hasInnerContainers) { position += getHeadingTopPos(obj.offsetParent) }
|
|
321
|
+
}
|
|
322
|
+
return position
|
|
321
323
|
}
|
|
322
|
-
return position
|
|
323
|
-
}
|
|
324
324
|
|
|
325
|
-
function updateListActiveElement (topHeader) {
|
|
326
|
-
var forEach = [].forEach
|
|
327
325
|
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
326
|
+
function updateListActiveElement(topHeader) {
|
|
327
|
+
var forEach = [].forEach
|
|
328
|
+
|
|
329
|
+
var tocLinks = tocElement
|
|
330
|
+
.querySelectorAll('.' + options.linkClass)
|
|
331
|
+
forEach.call(tocLinks, function (tocLink) {
|
|
332
|
+
tocLink.className = tocLink.className.split(SPACE_CHAR + options.activeLinkClass).join('')
|
|
333
|
+
})
|
|
334
|
+
var tocLis = tocElement
|
|
335
|
+
.querySelectorAll('.' + options.listItemClass)
|
|
336
|
+
forEach.call(tocLis, function (tocLi) {
|
|
337
|
+
tocLi.className = tocLi.className.split(SPACE_CHAR + options.activeListItemClass).join('')
|
|
338
|
+
})
|
|
339
|
+
|
|
340
|
+
// Add the active class to the active tocLink.
|
|
341
|
+
var activeTocLink = tocElement
|
|
342
|
+
.querySelector('.' + options.linkClass +
|
|
342
343
|
'.node-name--' + topHeader.nodeName +
|
|
343
344
|
'[href="' + options.basePath + '#' + topHeader.id.replace(/([ #;&,.+*~':"!^$[\]()=>|/@])/g, '\\$1') + '"]')
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
345
|
+
if (activeTocLink && activeTocLink.className.indexOf(options.activeLinkClass) === -1) {
|
|
346
|
+
activeTocLink.className += SPACE_CHAR + options.activeLinkClass
|
|
347
|
+
}
|
|
348
|
+
var li = activeTocLink && activeTocLink.parentNode
|
|
349
|
+
if (li && li.className.indexOf(options.activeListItemClass) === -1) {
|
|
350
|
+
li.className += SPACE_CHAR + options.activeListItemClass
|
|
351
|
+
}
|
|
351
352
|
|
|
352
|
-
|
|
353
|
-
|
|
353
|
+
var tocLists = tocElement
|
|
354
|
+
.querySelectorAll('.' + options.listClass + '.' + options.collapsibleClass)
|
|
354
355
|
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
356
|
+
// Collapse the other collapsible lists.
|
|
357
|
+
forEach.call(tocLists, function (list) {
|
|
358
|
+
if (list.className.indexOf(options.isCollapsedClass) === -1) {
|
|
359
|
+
list.className += SPACE_CHAR + options.isCollapsedClass
|
|
360
|
+
}
|
|
361
|
+
})
|
|
361
362
|
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
363
|
+
// Expand the active link's collapsible list and its sibling if applicable.
|
|
364
|
+
if (activeTocLink && activeTocLink.nextSibling && activeTocLink.nextSibling.className.indexOf(options.isCollapsedClass) !== -1) {
|
|
365
|
+
activeTocLink.nextSibling.className = activeTocLink.nextSibling.className.split(SPACE_CHAR + options.isCollapsedClass).join('')
|
|
366
|
+
}
|
|
367
|
+
removeCollapsedFromParents(activeTocLink && activeTocLink.parentNode.parentNode)
|
|
365
368
|
}
|
|
366
|
-
removeCollapsedFromParents(activeTocLink && activeTocLink.parentNode.parentNode)
|
|
367
|
-
}
|
|
368
369
|
|
|
369
|
-
|
|
370
|
+
/**
|
|
370
371
|
* Update TOC highlighting and collpased groupings.
|
|
371
372
|
*/
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
373
|
+
function updateToc(headingsArray) {
|
|
374
|
+
// If a fixed content container was set
|
|
375
|
+
if (options.scrollContainer && document.querySelector(options.scrollContainer)) {
|
|
376
|
+
var top
|
|
377
|
+
top = document.querySelector(options.scrollContainer).scrollTop
|
|
378
|
+
} else {
|
|
379
|
+
top = document.documentElement.scrollTop || body.scrollTop
|
|
380
|
+
}
|
|
380
381
|
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
382
|
+
// Add fixed class at offset
|
|
383
|
+
if (options.positionFixedSelector) {
|
|
384
|
+
updateFixedSidebarClass()
|
|
385
|
+
}
|
|
385
386
|
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
387
|
+
// Get the top most heading currently visible on the page so we know what to highlight.
|
|
388
|
+
var headings = headingsArray
|
|
389
|
+
var topHeader
|
|
390
|
+
// Using some instead of each so that we can escape early.
|
|
391
|
+
if (currentlyHighlighting &&
|
|
391
392
|
tocElement !== null &&
|
|
392
393
|
headings.length > 0) {
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
394
|
+
some.call(headings, function (heading, i) {
|
|
395
|
+
var modifiedTopOffset = top + 10
|
|
396
|
+
if (mainContainer) {
|
|
397
|
+
modifiedTopOffset += mainContainer.clientHeight * (mainContainer.scrollTop) / (mainContainer.scrollHeight - mainContainer.clientHeight)
|
|
398
|
+
}
|
|
399
|
+
if (getHeadingTopPos(heading) > modifiedTopOffset) {
|
|
400
|
+
// Don't allow negative index value.
|
|
401
|
+
var index = (i === 0) ? i : i - 1
|
|
402
|
+
topHeader = headings[index]
|
|
403
|
+
return true
|
|
404
|
+
} else if (i === headings.length - 1) {
|
|
405
|
+
// This allows scrolling for the last heading on the page.
|
|
406
|
+
topHeader = headings[headings.length - 1]
|
|
407
|
+
return true
|
|
408
|
+
}
|
|
409
|
+
})
|
|
410
|
+
|
|
411
|
+
// Remove the active class from the other tocLinks.
|
|
412
|
+
updateListActiveElement(topHeader)
|
|
413
|
+
}
|
|
412
414
|
}
|
|
413
|
-
}
|
|
414
415
|
|
|
415
|
-
|
|
416
|
+
/**
|
|
416
417
|
* Remove collpased class from parent elements.
|
|
417
418
|
* @param {HTMLElement} element
|
|
418
419
|
* @return {HTMLElement}
|
|
419
420
|
*/
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
421
|
+
function removeCollapsedFromParents(element) {
|
|
422
|
+
if (element && element.className.indexOf(options.collapsibleClass) !== -1 && element.className.indexOf(options.isCollapsedClass) !== -1) {
|
|
423
|
+
element.className = element.className.split(SPACE_CHAR + options.isCollapsedClass).join('')
|
|
424
|
+
return removeCollapsedFromParents(element.parentNode.parentNode)
|
|
425
|
+
}
|
|
426
|
+
return element
|
|
424
427
|
}
|
|
425
|
-
return element
|
|
426
|
-
}
|
|
427
428
|
|
|
428
|
-
|
|
429
|
+
/**
|
|
429
430
|
* Disable TOC Animation when a link is clicked.
|
|
430
431
|
* @param {Event} event
|
|
431
432
|
*/
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
433
|
+
function disableTocAnimation(event) {
|
|
434
|
+
var target = event.target || event.srcElement
|
|
435
|
+
if (typeof target.className !== 'string' || target.className.indexOf(options.linkClass) === -1) {
|
|
436
|
+
return
|
|
437
|
+
}
|
|
438
|
+
// Bind to tocLink clicks to temporarily disable highlighting
|
|
439
|
+
// while smoothScroll is animating.
|
|
440
|
+
currentlyHighlighting = false
|
|
436
441
|
}
|
|
437
|
-
// Bind to tocLink clicks to temporarily disable highlighting
|
|
438
|
-
// while smoothScroll is animating.
|
|
439
|
-
currentlyHighlighting = false
|
|
440
|
-
}
|
|
441
442
|
|
|
442
|
-
|
|
443
|
+
/**
|
|
443
444
|
* Enable TOC Animation.
|
|
444
445
|
*/
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
446
|
+
function enableTocAnimation() {
|
|
447
|
+
currentlyHighlighting = true
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
return {
|
|
451
|
+
enableTocAnimation: enableTocAnimation,
|
|
452
|
+
disableTocAnimation: disableTocAnimation,
|
|
453
|
+
render: render,
|
|
454
|
+
updateToc: updateToc,
|
|
455
|
+
updateListActiveElement: updateListActiveElement
|
|
456
|
+
}
|
|
456
457
|
}
|
|
457
458
|
|
|
458
|
-
function updateTocScroll
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
459
|
+
function updateTocScroll(options) {
|
|
460
|
+
var toc = options.tocElement || document.querySelector(options.tocSelector)
|
|
461
|
+
if (toc && toc.scrollHeight > toc.clientHeight) {
|
|
462
|
+
var activeItem = toc.querySelector('.' + options.activeListItemClass)
|
|
463
|
+
if (activeItem) {
|
|
464
|
+
var topOffset = toc.getBoundingClientRect().top
|
|
465
|
+
toc.scrollTop = activeItem.offsetTop - topOffset
|
|
466
|
+
}
|
|
465
467
|
}
|
|
466
|
-
}
|
|
467
468
|
}
|
|
468
469
|
|
|
469
470
|
(function (root, factory) {
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
}
|
|
477
|
-
})(typeof global !== 'undefined' ? global : this.window || this.global, function (root) {
|
|
478
|
-
'use strict'
|
|
479
|
-
|
|
480
|
-
var options = {}
|
|
481
|
-
var tocbot = {}
|
|
482
|
-
var buildHtml
|
|
483
|
-
var parseContent
|
|
484
|
-
|
|
485
|
-
// Just return if its not a browser.
|
|
486
|
-
var supports = !!root && !!root.document && !!root.document.querySelector && !!root.addEventListener // Feature test
|
|
487
|
-
if (typeof window === 'undefined' && !supports) {
|
|
488
|
-
return
|
|
489
|
-
}
|
|
490
|
-
var headingsArray
|
|
491
|
-
|
|
492
|
-
// From: https://github.com/Raynos/xtend
|
|
493
|
-
var hasOwnProperty = Object.prototype.hasOwnProperty
|
|
494
|
-
function extend () {
|
|
495
|
-
var target = {}
|
|
496
|
-
for (var i = 0; i < arguments.length; i++) {
|
|
497
|
-
var source = arguments[i]
|
|
498
|
-
for (var key in source) {
|
|
499
|
-
if (hasOwnProperty.call(source, key)) {
|
|
500
|
-
target[key] = source[key]
|
|
501
|
-
}
|
|
502
|
-
}
|
|
471
|
+
if (typeof define === 'function' && define.amd) {
|
|
472
|
+
define([], factory(root))
|
|
473
|
+
} else if (typeof exports === 'object') {
|
|
474
|
+
module.exports = factory(root)
|
|
475
|
+
} else {
|
|
476
|
+
root.tocbot = factory(root)
|
|
503
477
|
}
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
var
|
|
511
|
-
|
|
512
|
-
return
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
478
|
+
})(typeof global !== 'undefined' ? global : this.window || this.global, function (root) {
|
|
479
|
+
'use strict'
|
|
480
|
+
|
|
481
|
+
var options = {}
|
|
482
|
+
var tocbot = {}
|
|
483
|
+
var buildHtml
|
|
484
|
+
var parseContent
|
|
485
|
+
|
|
486
|
+
// Just return if its not a browser.
|
|
487
|
+
var supports = !!root && !!root.document && !!root.document.querySelector && !!root.addEventListener // Feature test
|
|
488
|
+
if (typeof window === 'undefined' && !supports) {
|
|
489
|
+
return
|
|
490
|
+
}
|
|
491
|
+
var headingsArray
|
|
492
|
+
|
|
493
|
+
// From: https://github.com/Raynos/xtend
|
|
494
|
+
var hasOwnProperty = Object.prototype.hasOwnProperty
|
|
495
|
+
function extend() {
|
|
496
|
+
var target = {}
|
|
497
|
+
for (var i = 0; i < arguments.length; i++) {
|
|
498
|
+
var source = arguments[i]
|
|
499
|
+
for (var key in source) {
|
|
500
|
+
if (hasOwnProperty.call(source, key)) {
|
|
501
|
+
target[key] = source[key]
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
return target
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
// From: https://remysharp.com/2010/07/21/throttling-function-calls
|
|
509
|
+
function throttle(fn, threshhold, scope) {
|
|
510
|
+
threshhold || (threshhold = 250)
|
|
511
|
+
var last
|
|
512
|
+
var deferTimer
|
|
513
|
+
return function () {
|
|
514
|
+
var context = scope || this
|
|
515
|
+
var now = +new Date()
|
|
516
|
+
var args = arguments
|
|
517
|
+
if (last && now < last + threshhold) {
|
|
518
|
+
// hold on to it
|
|
519
|
+
clearTimeout(deferTimer)
|
|
520
|
+
deferTimer = setTimeout(function () {
|
|
521
|
+
last = now
|
|
522
|
+
fn.apply(context, args)
|
|
523
|
+
}, threshhold)
|
|
524
|
+
} else {
|
|
525
|
+
last = now
|
|
526
|
+
fn.apply(context, args)
|
|
527
|
+
}
|
|
528
|
+
}
|
|
527
529
|
}
|
|
528
|
-
}
|
|
529
530
|
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
531
|
+
function getContentElement(options) {
|
|
532
|
+
try {
|
|
533
|
+
return options.contentElement || document.querySelector(options.contentSelector)
|
|
534
|
+
} catch (e) {
|
|
534
535
|
console.warn('Contents element not found: ' + options.contentSelector) // eslint-disable-line
|
|
535
|
-
|
|
536
|
+
return null
|
|
537
|
+
}
|
|
536
538
|
}
|
|
537
|
-
}
|
|
538
539
|
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
540
|
+
function getTocElement(options) {
|
|
541
|
+
try {
|
|
542
|
+
return options.tocElement || document.querySelector(options.tocSelector)
|
|
543
|
+
} catch (e) {
|
|
543
544
|
console.warn('TOC element not found: ' + options.tocSelector) // eslint-disable-line
|
|
544
|
-
|
|
545
|
+
return null
|
|
546
|
+
}
|
|
545
547
|
}
|
|
546
|
-
}
|
|
547
548
|
|
|
548
|
-
|
|
549
|
+
/**
|
|
549
550
|
* Destroy tocbot.
|
|
550
551
|
*/
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
552
|
+
tocbot.destroy = function () {
|
|
553
|
+
var tocElement = getTocElement(options)
|
|
554
|
+
if (tocElement === null) {
|
|
555
|
+
return
|
|
556
|
+
}
|
|
556
557
|
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
558
|
+
if (!options.skipRendering) {
|
|
559
|
+
// Clear HTML.
|
|
560
|
+
if (tocElement) {
|
|
561
|
+
tocElement.innerHTML = ''
|
|
562
|
+
}
|
|
563
|
+
}
|
|
563
564
|
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
565
|
+
// Remove event listeners.
|
|
566
|
+
if (options.scrollContainer && document.querySelector(options.scrollContainer)) {
|
|
567
|
+
document.querySelector(options.scrollContainer).removeEventListener('scroll', this._scrollListener, false)
|
|
568
|
+
document.querySelector(options.scrollContainer).removeEventListener('resize', this._scrollListener, false)
|
|
569
|
+
} else {
|
|
570
|
+
document.removeEventListener('scroll', this._scrollListener, false)
|
|
571
|
+
document.removeEventListener('resize', this._scrollListener, false)
|
|
572
|
+
}
|
|
571
573
|
}
|
|
572
|
-
}
|
|
573
574
|
|
|
574
|
-
|
|
575
|
+
/**
|
|
575
576
|
* Initialize tocbot.
|
|
576
577
|
* @param {object} customOptions
|
|
577
578
|
*/
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
579
|
+
tocbot.init = function (customOptions) {
|
|
580
|
+
// feature test
|
|
581
|
+
if (!supports) {
|
|
582
|
+
return
|
|
583
|
+
}
|
|
583
584
|
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
585
|
+
// Merge defaults with user options.
|
|
586
|
+
// Set to options variable at the top.
|
|
587
|
+
options = extend(defaultOptions, customOptions || {})
|
|
588
|
+
this.options = options
|
|
589
|
+
this.state = {}
|
|
589
590
|
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
591
|
+
// Init smooth scroll if enabled (default).
|
|
592
|
+
if (options.scrollSmooth) {
|
|
593
|
+
options.duration = options.scrollSmoothDuration
|
|
594
|
+
options.offset = options.scrollSmoothOffset
|
|
595
|
+
}
|
|
595
596
|
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
597
|
+
// Pass options to these modules.
|
|
598
|
+
buildHtml = BuildHtml(options)
|
|
599
|
+
parseContent = ParseContent(options)
|
|
599
600
|
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
601
|
+
// For testing purposes.
|
|
602
|
+
this._buildHtml = buildHtml
|
|
603
|
+
this._parseContent = parseContent
|
|
604
|
+
this._headingsArray = headingsArray
|
|
605
|
+
this.updateTocListActiveElement = buildHtml.updateListActiveElement
|
|
605
606
|
|
|
606
|
-
|
|
607
|
-
|
|
607
|
+
// Destroy it if it exists first.
|
|
608
|
+
tocbot.destroy()
|
|
608
609
|
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
610
|
+
var contentElement = getContentElement(options)
|
|
611
|
+
if (contentElement === null) {
|
|
612
|
+
return
|
|
613
|
+
}
|
|
613
614
|
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
615
|
+
var tocElement = getTocElement(options)
|
|
616
|
+
if (tocElement === null) {
|
|
617
|
+
return
|
|
618
|
+
}
|
|
618
619
|
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
620
|
+
// Get headings array.
|
|
621
|
+
headingsArray = parseContent.selectHeadings(contentElement, options.headingSelector)
|
|
622
|
+
// Return if no headings are found.
|
|
623
|
+
if (headingsArray === null) {
|
|
624
|
+
return
|
|
625
|
+
}
|
|
625
626
|
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
627
|
+
// Build nested headings array.
|
|
628
|
+
var nestedHeadingsObj = parseContent.nestHeadingsArray(headingsArray)
|
|
629
|
+
var nestedHeadings = nestedHeadingsObj.nest
|
|
629
630
|
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
631
|
+
// Render.
|
|
632
|
+
if (!options.skipRendering) {
|
|
633
|
+
buildHtml.render(tocElement, nestedHeadings)
|
|
634
|
+
}
|
|
634
635
|
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
636
|
+
// Update Sidebar and bind listeners.
|
|
637
|
+
this._scrollListener = throttle(function (e) {
|
|
638
|
+
buildHtml.updateToc(headingsArray)
|
|
639
|
+
!options.disableTocScrollSync && updateTocScroll(options)
|
|
640
|
+
var isTop = e && e.target && e.target.scrollingElement && e.target.scrollingElement.scrollTop === 0
|
|
641
|
+
if ((e && (e.eventPhase === 0 || e.currentTarget === null)) || isTop) {
|
|
642
|
+
buildHtml.updateToc(headingsArray)
|
|
643
|
+
if (options.scrollEndCallback) {
|
|
644
|
+
options.scrollEndCallback(e)
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
}, options.throttleTimeout)
|
|
648
|
+
this._scrollListener()
|
|
649
|
+
if (options.scrollContainer && document.querySelector(options.scrollContainer)) {
|
|
650
|
+
document.querySelector(options.scrollContainer).addEventListener('scroll', this._scrollListener, false)
|
|
651
|
+
document.querySelector(options.scrollContainer).addEventListener('resize', this._scrollListener, false)
|
|
652
|
+
} else {
|
|
653
|
+
document.addEventListener('scroll', this._scrollListener, false)
|
|
654
|
+
document.addEventListener('resize', this._scrollListener, false)
|
|
655
|
+
}
|
|
655
656
|
|
|
656
|
-
|
|
657
|
-
|
|
657
|
+
return this
|
|
658
|
+
}
|
|
658
659
|
|
|
659
|
-
|
|
660
|
+
/**
|
|
660
661
|
* Refresh tocbot.
|
|
661
662
|
*/
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
663
|
+
tocbot.refresh = function (customOptions) {
|
|
664
|
+
tocbot.destroy()
|
|
665
|
+
tocbot.init(customOptions || this.options)
|
|
666
|
+
}
|
|
666
667
|
|
|
667
|
-
|
|
668
|
-
|
|
668
|
+
// Make tocbot available globally.
|
|
669
|
+
root.tocbot = tocbot
|
|
669
670
|
|
|
670
|
-
|
|
671
|
-
})
|
|
671
|
+
return tocbot
|
|
672
|
+
})
|