1 import navItems from '../../content/nav.yml'
2
3 /*
4 *
5 * Internal functions
6 *
7 */
8 const getPath = path => {
9 while (path && path.endsWith('/')) {
10 path = path.substring(0, path.length - 1)
11 }
12
13 return path
14 }
15
16 const getCurrentVariant = (root, path) => {
17 for (const v of root.variants) {
18 if (isActiveItem(path, v)) {
19 return v
20 }
21 }
22
23 return null
24 }
25
26 const getDefaultVariant = root => {
27 for (const v of root.variants) {
28 if (v.default) {
29 return v
30 }
31 }
32
33 return root.variants[0]
34 }
35
36 const getVariantAndPage = (root, path) => {
37 if (!root || !path.startsWith(`${root}/`)) {
38 return null
39 }
40
41 path = path.substring(root.length + 1)
42
43 const match = /^([^/]+)(?:\/(.*))?/.exec(path)
44
45 if (!match) {
46 return null
47 }
48
49 return {variant: match[1], page: match[2]}
50 }
51
52 const hideVariantsForItems = (items, path) => {
53 if (!items) {
54 return null
55 }
56
57 const updated = []
58
59 for (const item of items) {
60 if (item.variants) {
61 updated.push({
62 ...item,
63 url: getCurrentOrDefaultVariant(item, path).url,
64 })
65 } else {
66 updated.push(item)
67 }
68 }
69
70 return updated
71 }
72
73 const getItemHierarchy = (path, items = navItems) => {
74 if (!path) {
75 return null
76 }
77
78 for (let i = 0; i < items.length; i++) {
79 const item = items[i]
80
81 if (getPath(item.url) === getPath(path)) {
82 return [item]
83 }
84
85 const children = item.variants ? item.variants : item.children
86
87 if (children) {
88 const hierarchy = getItemHierarchy(path, children)
89
90 if (hierarchy) {
91 return [item, ...hierarchy]
92 }
93 }
94 }
95
96 return null
97 }
98
99 const isChildItem = (path, items = navItems) => {
100 if (!path) {
101 return false
102 }
103
104 return findItem(item => (isPathForItem(path, item) ? item : null), items) != null
105 }
106
107 const findItem = (fn, items = navItems) => {
108 for (let i = 0; i < items.length; i++) {
109 const item = items[i]
110 let result = fn(item)
111
112 if (!result && item.children) {
113 result = findItem(fn, item.children)
114 }
115
116 if (result) {
117 return result
118 }
119 }
120
121 return null
122 }
123
124 const isActiveItem = (currentPath, linkItem) => {
125 return (
126 isPathForItem(currentPath, linkItem) ||
127 (linkItem.children && isChildItem(currentPath, linkItem.children)) ||
128 (linkItem.variants && isChildItem(currentPath, linkItem.variants))
129 )
130 }
131
132 const getVariantsForPage = (root, page) => {
133 const pages = []
134 const rootItem = findItem(item => (getPath(item.url) === getPath(root) ? item : null))
135
136 if (rootItem && rootItem.variants) {
137 for (const variant of rootItem.variants) {
138 if (!variant.children) {
139 continue
140 }
141
142 const vp = getVariantPage(root, variant.url)
143 const variantPage =
144 vp === page
145 ? variant
146 : findItem(item => {
147 const itemVp = getVariantPage(root, item.url)
148 return itemVp === page ? item : null
149 }, variant.children)
150
151 if (!variantPage) {
152 continue
153 }
154
155 pages.push({variant, page: variantPage})
156 }
157 }
158
159 return pages
160 }
161
162 /*
163 *
164 * Export functions
165 *
166 */
167 export const getItemBreadcrumbs = (path, {hideVariants} = {}) => {
168 let hierarchy = getItemHierarchy(path)
169
170 if (!hierarchy) {
171 return []
172 }
173
174 if (hideVariants) {
175 const root = getVariantRoot(path)
176 const variant = getVariant(root, path)
177 hierarchy = hierarchy.filter(item => (variant ? item.shortName !== variant : true))
178 }
179
180 return hierarchy
181 }
182
183 export const getVariantRoot = (path, {stripTrailing = true} = {}) => {
184 if (stripTrailing) {
185 path = getPath(path)
186 }
187
188 return findItem(item => {
189 if (item.variants && path.startsWith(`${item.url}/`)) {
190 return item.url
191 }
192
193 return null
194 })
195 }
196
197 export const getItem = (path, items = navItems) => {
198 path = getPath(path)
199
200 if (!path) {
201 return {url: '/', children: items}
202 }
203
204 for (let i = 0; i < items.length; i++) {
205 const item = items[i]
206
207 if (getPath(item.url) === getPath(path)) {
208 return item
209 }
210
211 const children = item.variants ? item.variants : item.children
212
213 if (children) {
214 const child = getItem(path, children)
215
216 if (child) {
217 return child
218 }
219 }
220 }
221
222 return null
223 }
224
225 export const isPathForItem = (path, item) => {
226 return getPath(item.url) === getPath(path)
227 }
228
229 export const getHierarchy = (root, path, {hideVariants} = {}) => {
230 let children
231
232 if (!root) {
233 children = navItems
234 } else if (root.variants && hideVariants === true) {
235 children = getCurrentOrDefaultVariant(root, path).children
236 } else if (root.variants) {
237 children = root.variants
238 } else {
239 children = root.children
240 }
241
242 return children && hideVariants === true ? hideVariantsForItems(children, path) : children
243 }
244
245 export const getCurrentOrDefaultVariant = (root, path) => {
246 let variant = path ? getCurrentVariant(root, path) : null
247
248 if (!variant) {
249 variant = getDefaultVariant(root)
250 }
251
252 return variant
253 }
254
255 export const getVariant = (root, path) => getVariantAndPage(root, path)?.variant ?? null
256
257 export const getVariantPage = (root, path) => getVariantAndPage(root, path)?.page ?? null
258
259 export const didVariantChange = (oldPath, newPath) => {
260 if (!oldPath || !newPath || oldPath === newPath) {
261 return false
262 }
263
264 const oldVariant = getVariant(getVariantRoot(oldPath), getPath(oldPath))
265 if (!oldVariant) {
266 return false
267 }
268
269 return oldVariant !== getVariant(getVariantRoot(newPath), getPath(newPath))
270 }
271
272 export const getVariantsForPath = path => {
273 const root = getVariantRoot(path)
274 const vPage = getVariantPage(root, path)
275 return vPage ? getVariantsForPage(root, vPage) : []
276 }
277
278 export const isActiveUrl = (currentPath, linkPath) => {
279 const linkItem = getItem(linkPath)
280 return linkItem ? isActiveItem(currentPath, linkItem) : false
281 }