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.
@@ -1,671 +1,672 @@
1
1
  /* eslint no-var: off */
2
2
  var defaultOptions = {
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
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 (options) {
35
- var reduce = [].reduce
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
- function getLastItem (array) {
43
- return array[array.length - 1]
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
- function getHeadingLevel (heading) {
52
- return +heading.nodeName.toUpperCase().replace('H', '')
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
- 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
- }
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
- const headingLabel = heading.getAttribute('data-heading-label') ||
70
+ const headingLabel = heading.getAttribute('data-heading-label') ||
71
71
  (options.headingLabelCallback ? String(options.headingLabelCallback(heading.textContent)) : heading.textContent.trim())
72
- var obj = {
73
- id: heading.id,
74
- children: [],
75
- nodeName: heading.nodeName,
76
- headingLevel: getHeadingLevel(heading),
77
- textContent: headingLabel
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
- if (options.includeHtml) {
81
- obj.childNodes = heading.childNodes
82
- }
80
+ if (options.includeHtml) {
81
+ obj.childNodes = heading.childNodes
82
+ }
83
83
 
84
- if (options.headingObjectCallback) {
85
- return options.headingObjectCallback(obj, heading)
86
- }
84
+ if (options.headingObjectCallback) {
85
+ return options.headingObjectCallback(obj, heading)
86
+ }
87
87
 
88
- return obj
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
- 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
- }
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
- if (level >= options.collapseDepth) {
119
- obj.isCollapsed = true
120
- }
118
+ if (level >= options.collapseDepth) {
119
+ obj.isCollapsed = true
120
+ }
121
121
 
122
- array.push(obj)
123
- return array
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
- 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) {
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
- return null
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
- 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
- }
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
- 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 = ' '
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
- 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)
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
- function render (parent, data) {
204
- var collapsed = false
205
- var container = createList(collapsed)
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
- // Remove existing child if it exists.
218
- if (tocElement.firstChild) {
219
- tocElement.removeChild(tocElement.firstChild)
220
- }
207
+ data.forEach(function (d) {
208
+ createEl(d, container)
209
+ })
221
210
 
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
- }
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
- // Append the Elements that have been created
228
- return tocElement.appendChild(container)
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
- 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
- }
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
- if (options.onClick) {
244
- a.onclick = options.onClick
245
- }
243
+ if (options.onClick) {
244
+ a.onclick = options.onClick
245
+ }
246
246
 
247
- if (options.includeTitleTags) {
248
- a.setAttribute('title', data.textContent)
249
- }
247
+ if (options.includeTitleTags) {
248
+ a.setAttribute('title', data.textContent)
249
+ }
250
250
 
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 +
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
- item.appendChild(a)
264
- return item
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
- function createList (isCollapsed) {
273
- var listElement = (options.orderedList) ? 'ol' : 'ul'
274
- var list = document.createElement(listElement)
275
- var classes = options.listClass +
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
- if (isCollapsed) {
278
- classes += SPACE_CHAR + options.collapsibleClass
279
- classes += SPACE_CHAR + options.isCollapsedClass
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
- 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)
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
- if (options.fixedSidebarOffset === 'auto') {
299
- options.fixedSidebarOffset = tocElement.offsetTop
300
- }
298
+ if (options.fixedSidebarOffset === 'auto') {
299
+ options.fixedSidebarOffset = tocElement.offsetTop
300
+ }
301
301
 
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('')
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
- function getHeadingTopPos (obj) {
317
- var position = 0
318
- if (obj !== null) {
319
- position = obj.offsetTop
320
- if (options.hasInnerContainers) { position += getHeadingTopPos(obj.offsetParent) }
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
- var tocLinks = tocElement
329
- .querySelectorAll('.' + options.linkClass)
330
- forEach.call(tocLinks, function (tocLink) {
331
- tocLink.className = tocLink.className.split(SPACE_CHAR + options.activeLinkClass).join('')
332
- })
333
- var tocLis = tocElement
334
- .querySelectorAll('.' + options.listItemClass)
335
- forEach.call(tocLis, function (tocLi) {
336
- tocLi.className = tocLi.className.split(SPACE_CHAR + options.activeListItemClass).join('')
337
- })
338
-
339
- // Add the active class to the active tocLink.
340
- var activeTocLink = tocElement
341
- .querySelector('.' + options.linkClass +
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
- if (activeTocLink && activeTocLink.className.indexOf(options.activeLinkClass) === -1) {
345
- activeTocLink.className += SPACE_CHAR + options.activeLinkClass
346
- }
347
- var li = activeTocLink && activeTocLink.parentNode
348
- if (li && li.className.indexOf(options.activeListItemClass) === -1) {
349
- li.className += SPACE_CHAR + options.activeListItemClass
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
- var tocLists = tocElement
353
- .querySelectorAll('.' + options.listClass + '.' + options.collapsibleClass)
353
+ var tocLists = tocElement
354
+ .querySelectorAll('.' + options.listClass + '.' + options.collapsibleClass)
354
355
 
355
- // Collapse the other collapsible lists.
356
- forEach.call(tocLists, function (list) {
357
- if (list.className.indexOf(options.isCollapsedClass) === -1) {
358
- list.className += SPACE_CHAR + options.isCollapsedClass
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
- // Expand the active link's collapsible list and its sibling if applicable.
363
- if (activeTocLink && activeTocLink.nextSibling && activeTocLink.nextSibling.className.indexOf(options.isCollapsedClass) !== -1) {
364
- activeTocLink.nextSibling.className = activeTocLink.nextSibling.className.split(SPACE_CHAR + options.isCollapsedClass).join('')
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
- function updateToc (headingsArray) {
373
- // If a fixed content container was set
374
- if (options.scrollContainer && document.querySelector(options.scrollContainer)) {
375
- var top
376
- top = document.querySelector(options.scrollContainer).scrollTop
377
- } else {
378
- top = document.documentElement.scrollTop || body.scrollTop
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
- // Add fixed class at offset
382
- if (options.positionFixedSelector) {
383
- updateFixedSidebarClass()
384
- }
382
+ // Add fixed class at offset
383
+ if (options.positionFixedSelector) {
384
+ updateFixedSidebarClass()
385
+ }
385
386
 
386
- // Get the top most heading currently visible on the page so we know what to highlight.
387
- var headings = headingsArray
388
- var topHeader
389
- // Using some instead of each so that we can escape early.
390
- if (currentlyHighlighting &&
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
- some.call(headings, function (heading, i) {
394
- var modifiedTopOffset = top + 10
395
- if (mainContainer) {
396
- modifiedTopOffset += mainContainer.clientHeight * (mainContainer.scrollTop) / (mainContainer.scrollHeight - mainContainer.clientHeight)
397
- }
398
- if (getHeadingTopPos(heading) > modifiedTopOffset) {
399
- // Don't allow negative index value.
400
- var index = (i === 0) ? i : i - 1
401
- topHeader = headings[index]
402
- return true
403
- } else if (i === headings.length - 1) {
404
- // This allows scrolling for the last heading on the page.
405
- topHeader = headings[headings.length - 1]
406
- return true
407
- }
408
- })
409
-
410
- // Remove the active class from the other tocLinks.
411
- updateListActiveElement(topHeader)
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
- function removeCollapsedFromParents (element) {
421
- if (element && element.className.indexOf(options.collapsibleClass) !== -1 && element.className.indexOf(options.isCollapsedClass) !== -1) {
422
- element.className = element.className.split(SPACE_CHAR + options.isCollapsedClass).join('')
423
- return removeCollapsedFromParents(element.parentNode.parentNode)
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
- function disableTocAnimation (event) {
433
- var target = event.target || event.srcElement
434
- if (typeof target.className !== 'string' || target.className.indexOf(options.linkClass) === -1) {
435
- return
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
- function enableTocAnimation () {
446
- currentlyHighlighting = true
447
- }
448
-
449
- return {
450
- enableTocAnimation,
451
- disableTocAnimation,
452
- render,
453
- updateToc,
454
- updateListActiveElement
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 (options) {
459
- var toc = options.tocElement || document.querySelector(options.tocSelector)
460
- if (toc && toc.scrollHeight > toc.clientHeight) {
461
- var activeItem = toc.querySelector('.' + options.activeListItemClass)
462
- if (activeItem) {
463
- var topOffset = toc.getBoundingClientRect().top
464
- toc.scrollTop = activeItem.offsetTop - topOffset
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
- if (typeof define === 'function' && define.amd) {
471
- define([], factory(root))
472
- } else if (typeof exports === 'object') {
473
- module.exports = factory(root)
474
- } else {
475
- root.tocbot = factory(root)
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
- return target
505
- }
506
-
507
- // From: https://remysharp.com/2010/07/21/throttling-function-calls
508
- function throttle (fn, threshhold, scope) {
509
- threshhold || (threshhold = 250)
510
- var last
511
- var deferTimer
512
- return function () {
513
- var context = scope || this
514
- var now = +new Date()
515
- var args = arguments
516
- if (last && now < last + threshhold) {
517
- // hold on to it
518
- clearTimeout(deferTimer)
519
- deferTimer = setTimeout(function () {
520
- last = now
521
- fn.apply(context, args)
522
- }, threshhold)
523
- } else {
524
- last = now
525
- fn.apply(context, args)
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
- function getContentElement (options) {
531
- try {
532
- return options.contentElement || document.querySelector(options.contentSelector)
533
- } catch (e) {
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
- return null
536
+ return null
537
+ }
536
538
  }
537
- }
538
539
 
539
- function getTocElement (options) {
540
- try {
541
- return options.tocElement || document.querySelector(options.tocSelector)
542
- } catch (e) {
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
- return null
545
+ return null
546
+ }
545
547
  }
546
- }
547
548
 
548
- /**
549
+ /**
549
550
  * Destroy tocbot.
550
551
  */
551
- tocbot.destroy = function () {
552
- var tocElement = getTocElement(options)
553
- if (tocElement === null) {
554
- return
555
- }
552
+ tocbot.destroy = function () {
553
+ var tocElement = getTocElement(options)
554
+ if (tocElement === null) {
555
+ return
556
+ }
556
557
 
557
- if (!options.skipRendering) {
558
- // Clear HTML.
559
- if (tocElement) {
560
- tocElement.innerHTML = ''
561
- }
562
- }
558
+ if (!options.skipRendering) {
559
+ // Clear HTML.
560
+ if (tocElement) {
561
+ tocElement.innerHTML = ''
562
+ }
563
+ }
563
564
 
564
- // Remove event listeners.
565
- if (options.scrollContainer && document.querySelector(options.scrollContainer)) {
566
- document.querySelector(options.scrollContainer).removeEventListener('scroll', this._scrollListener, false)
567
- document.querySelector(options.scrollContainer).removeEventListener('resize', this._scrollListener, false)
568
- } else {
569
- document.removeEventListener('scroll', this._scrollListener, false)
570
- document.removeEventListener('resize', this._scrollListener, false)
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
- tocbot.init = function (customOptions) {
579
- // feature test
580
- if (!supports) {
581
- return
582
- }
579
+ tocbot.init = function (customOptions) {
580
+ // feature test
581
+ if (!supports) {
582
+ return
583
+ }
583
584
 
584
- // Merge defaults with user options.
585
- // Set to options variable at the top.
586
- options = extend(defaultOptions, customOptions || {})
587
- this.options = options
588
- this.state = {}
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
- // Init smooth scroll if enabled (default).
591
- if (options.scrollSmooth) {
592
- options.duration = options.scrollSmoothDuration
593
- options.offset = options.scrollSmoothOffset
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
- // Pass options to these modules.
597
- buildHtml = BuildHtml(options)
598
- parseContent = ParseContent(options)
597
+ // Pass options to these modules.
598
+ buildHtml = BuildHtml(options)
599
+ parseContent = ParseContent(options)
599
600
 
600
- // For testing purposes.
601
- this._buildHtml = buildHtml
602
- this._parseContent = parseContent
603
- this._headingsArray = headingsArray
604
- this.updateTocListActiveElement = buildHtml.updateListActiveElement
601
+ // For testing purposes.
602
+ this._buildHtml = buildHtml
603
+ this._parseContent = parseContent
604
+ this._headingsArray = headingsArray
605
+ this.updateTocListActiveElement = buildHtml.updateListActiveElement
605
606
 
606
- // Destroy it if it exists first.
607
- tocbot.destroy()
607
+ // Destroy it if it exists first.
608
+ tocbot.destroy()
608
609
 
609
- var contentElement = getContentElement(options)
610
- if (contentElement === null) {
611
- return
612
- }
610
+ var contentElement = getContentElement(options)
611
+ if (contentElement === null) {
612
+ return
613
+ }
613
614
 
614
- var tocElement = getTocElement(options)
615
- if (tocElement === null) {
616
- return
617
- }
615
+ var tocElement = getTocElement(options)
616
+ if (tocElement === null) {
617
+ return
618
+ }
618
619
 
619
- // Get headings array.
620
- headingsArray = parseContent.selectHeadings(contentElement, options.headingSelector)
621
- // Return if no headings are found.
622
- if (headingsArray === null) {
623
- return
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
- // Build nested headings array.
627
- var nestedHeadingsObj = parseContent.nestHeadingsArray(headingsArray)
628
- var nestedHeadings = nestedHeadingsObj.nest
627
+ // Build nested headings array.
628
+ var nestedHeadingsObj = parseContent.nestHeadingsArray(headingsArray)
629
+ var nestedHeadings = nestedHeadingsObj.nest
629
630
 
630
- // Render.
631
- if (!options.skipRendering) {
632
- buildHtml.render(tocElement, nestedHeadings)
633
- }
631
+ // Render.
632
+ if (!options.skipRendering) {
633
+ buildHtml.render(tocElement, nestedHeadings)
634
+ }
634
635
 
635
- // Update Sidebar and bind listeners.
636
- this._scrollListener = throttle(function (e) {
637
- buildHtml.updateToc(headingsArray)
638
- !options.disableTocScrollSync && updateTocScroll(options)
639
- var isTop = e && e.target && e.target.scrollingElement && e.target.scrollingElement.scrollTop === 0
640
- if ((e && (e.eventPhase === 0 || e.currentTarget === null)) || isTop) {
641
- buildHtml.updateToc(headingsArray)
642
- if (options.scrollEndCallback) {
643
- options.scrollEndCallback(e)
644
- }
645
- }
646
- }, options.throttleTimeout)
647
- this._scrollListener()
648
- if (options.scrollContainer && document.querySelector(options.scrollContainer)) {
649
- document.querySelector(options.scrollContainer).addEventListener('scroll', this._scrollListener, false)
650
- document.querySelector(options.scrollContainer).addEventListener('resize', this._scrollListener, false)
651
- } else {
652
- document.addEventListener('scroll', this._scrollListener, false)
653
- document.addEventListener('resize', this._scrollListener, false)
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
- return this
657
- }
657
+ return this
658
+ }
658
659
 
659
- /**
660
+ /**
660
661
  * Refresh tocbot.
661
662
  */
662
- tocbot.refresh = function (customOptions) {
663
- tocbot.destroy()
664
- tocbot.init(customOptions || this.options)
665
- }
663
+ tocbot.refresh = function (customOptions) {
664
+ tocbot.destroy()
665
+ tocbot.init(customOptions || this.options)
666
+ }
666
667
 
667
- // Make tocbot available globally.
668
- root.tocbot = tocbot
668
+ // Make tocbot available globally.
669
+ root.tocbot = tocbot
669
670
 
670
- return tocbot
671
- })
671
+ return tocbot
672
+ })