-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy path01-nav.js
More file actions
154 lines (136 loc) · 5.38 KB
/
Copy path01-nav.js
File metadata and controls
154 lines (136 loc) · 5.38 KB
1
2
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
;(function () {
'use strict'
var SECT_CLASS_RX = /^sect(\d)$/
var navContainer = document.querySelector('.nav-container')
var navToggle = document.querySelector('.nav-toggle')
navToggle.addEventListener('click', showNav)
navContainer.addEventListener('click', trapEvent)
var menuPanel = navContainer.querySelector('[data-panel=menu]')
if (!menuPanel) return
var nav = navContainer.querySelector('.nav')
var currentPageItem = menuPanel.querySelector('.is-current-page')
var originalPageItem = currentPageItem
if (currentPageItem) {
activateCurrentPath(currentPageItem)
scrollItemToMidpoint(menuPanel, currentPageItem.querySelector('.nav-link'))
} else {
menuPanel.scrollTop = 0
}
find(menuPanel, '.nav-item-toggle').forEach(function (btn) {
var li = btn.parentElement
btn.addEventListener('click', toggleActive.bind(li))
var navItemSpan = findNextElement(btn, '.nav-text')
if (navItemSpan) {
navItemSpan.style.cursor = 'pointer'
navItemSpan.addEventListener('click', toggleActive.bind(li))
}
})
// nav.querySelector('[data-panel=explore] .context').addEventListener('click', function () {
// // NOTE logic assumes there are only two panels
// find(nav, '[data-panel]').forEach(function (panel) {
// panel.classList.toggle('is-active')
// })
// })
// NOTE prevent text from being selected by double click
menuPanel.addEventListener('mousedown', function (e) {
if (e.detail > 1) e.preventDefault()
})
function onHashChange () {
var navLink
var hash = window.location.hash
if (hash) {
if (hash.indexOf('%')) hash = decodeURIComponent(hash)
navLink = menuPanel.querySelector('.nav-link[href="' + hash + '"]')
if (!navLink) {
var targetNode = document.getElementById(hash.slice(1))
if (targetNode) {
var current = targetNode
var ceiling = document.querySelector('article.doc')
while ((current = current.parentNode) && current !== ceiling) {
var id = current.id
// NOTE: look for section heading
if (!id && (id = SECT_CLASS_RX.test(current.className))) id = (current.firstElementChild || {}).id
if (id && (navLink = menuPanel.querySelector('.nav-link[href="#' + id + '"]'))) break
}
}
}
}
var navItem
if (navLink) {
navItem = navLink.parentNode
} else if (originalPageItem) {
navLink = (navItem = originalPageItem).querySelector('.nav-link')
} else {
return
}
if (navItem === currentPageItem) return
find(menuPanel, '.nav-item.is-active').forEach(function (el) {
el.classList.remove('is-active', 'is-current-path', 'is-current-page')
})
navItem.classList.add('is-current-page')
currentPageItem = navItem
activateCurrentPath(navItem)
scrollItemToMidpoint(menuPanel, navLink)
}
if (menuPanel.querySelector('.nav-link[href^="#"]')) {
if (window.location.hash) onHashChange()
window.addEventListener('hashchange', onHashChange)
}
function activateCurrentPath (navItem) {
var ancestorClasses
var ancestor = navItem.parentNode
while (!(ancestorClasses = ancestor.classList).contains('nav-menu')) {
if (ancestor.tagName === 'LI' && ancestorClasses.contains('nav-item')) {
ancestorClasses.add('is-active', 'is-current-path')
}
ancestor = ancestor.parentNode
}
navItem.classList.add('is-active')
}
function toggleActive () {
if (this.classList.toggle('is-active')) {
var padding = parseFloat(window.getComputedStyle(this).marginTop)
var rect = this.getBoundingClientRect()
var menuPanelRect = menuPanel.getBoundingClientRect()
var overflowY = (rect.bottom - menuPanelRect.top - menuPanelRect.height + padding).toFixed()
if (overflowY > 0) menuPanel.scrollTop += Math.min((rect.top - menuPanelRect.top - padding).toFixed(), overflowY)
}
}
function showNav (e) {
if (navToggle.classList.contains('is-active')) return hideNav(e)
trapEvent(e)
var html = document.documentElement
html.classList.add('is-clipped--nav')
navToggle.classList.add('is-active')
navContainer.classList.add('is-active')
var bounds = nav.getBoundingClientRect()
var expectedHeight = window.innerHeight - Math.round(bounds.top)
if (Math.round(bounds.height) !== expectedHeight) nav.style.height = expectedHeight + 'px'
html.addEventListener('click', hideNav)
}
function hideNav (e) {
trapEvent(e)
var html = document.documentElement
html.classList.remove('is-clipped--nav')
navToggle.classList.remove('is-active')
navContainer.classList.remove('is-active')
html.removeEventListener('click', hideNav)
}
function trapEvent (e) {
e.stopPropagation()
}
function scrollItemToMidpoint (panel, el) {
var rect = panel.getBoundingClientRect()
var effectiveHeight = rect.height
var navStyle = window.getComputedStyle(nav)
if (navStyle.position === 'sticky') effectiveHeight -= rect.top - parseFloat(navStyle.top)
panel.scrollTop = Math.max(0, (el.getBoundingClientRect().height - effectiveHeight) * 0.5 + el.offsetTop)
}
function find (from, selector) {
return [].slice.call(from.querySelectorAll(selector))
}
function findNextElement (from, selector) {
var el = from.nextElementSibling
return el && selector ? el[el.matches ? 'matches' : 'msMatchesSelector'](selector) && el : el
}
})()