aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorHsieh Chin Fan <pham@topo.tw>2024-09-23 17:38:04 +0800
committerHsieh Chin Fan <pham@topo.tw>2024-09-23 17:38:04 +0800
commit6500301ce49107886315dd47d1f710ef1a3dc41d (patch)
tree88d5243058634230f7d8e2871d8928d2b067a8c5 /src
parentd085eff1ac4a58408f5518d5cbabf076ffab055f (diff)
refactor: store maps as [HTMLElement, Promise]
Diffstat (limited to 'src')
-rw-r--r--src/dumbymap.mjs64
1 files changed, 31 insertions, 33 deletions
diff --git a/src/dumbymap.mjs b/src/dumbymap.mjs
index d642504..808ca06 100644
--- a/src/dumbymap.mjs
+++ b/src/dumbymap.mjs
@@ -139,21 +139,24 @@ export const markdown2HTML = (container, mdContent) => {
139// FIXME Don't use hard-coded CSS selector 139// FIXME Don't use hard-coded CSS selector
140// TODO Use UI to switch layouts 140// TODO Use UI to switch layouts
141function focusNextMap(reverse = false) { 141function focusNextMap(reverse = false) {
142 const mapNum = this.renderedMaps.length 142 const renderedList = this.renderMaps
143 .map(render => render.target)
144 .filter(ele => ele.getAttribute('data-state') === 'rendered')
145 const mapNum = renderedList.length
143 if (mapNum === 0) return 146 if (mapNum === 0) return
147
144 // Get current focused map element 148 // Get current focused map element
145 const currentFocus = this.container.querySelector('.map-container[data-focus]') 149 const currentFocus = this.container.querySelector('.map-container[data-focus]')
146 150
147 // Remove class name of focus for ALL candidates 151 // Remove class name of focus for ALL candidates
148 // This may trigger animation 152 // This may trigger animation
149 Array.from(this.container.querySelectorAll('.map-container')) 153 renderedList.forEach(ele => ele.removeAttribute('data-focus'))
150 .forEach(ele => ele.removeAttribute('data-focus'))
151 154
152 // Get next existing map element 155 // Get next existing map element
153 const padding = reverse ? -1 : 1 156 const padding = reverse ? -1 : 1
154 let nextIndex = currentFocus ? this.renderedMaps.indexOf(currentFocus) + padding : 0 157 let nextIndex = currentFocus ? renderedList.indexOf(currentFocus) + padding : 0
155 nextIndex = (nextIndex + mapNum) % mapNum 158 nextIndex = (nextIndex + mapNum) % mapNum
156 const nextFocus = this.renderedMaps[nextIndex] 159 const nextFocus = renderedList[nextIndex]
157 nextFocus.setAttribute('data-focus', "true") 160 nextFocus.setAttribute('data-focus', "true")
158 161
159 return nextFocus 162 return nextFocus
@@ -162,10 +165,11 @@ function focusDelay() {
162 return window.getComputedStyle(this.showcase).display === 'none' ? 50 : 300 165 return window.getComputedStyle(this.showcase).display === 'none' ? 50 : 300
163} 166}
164 167
165function switchToNextLayout() { 168function switchToNextLayout(reverse = false) {
166 const currentLayoutName = this.container.getAttribute('data-layout') 169 const currentLayoutName = this.container.getAttribute('data-layout')
167 const currentIndex = layouts.map(l => l.name).indexOf(currentLayoutName) 170 const currentIndex = layouts.map(l => l.name).indexOf(currentLayoutName)
168 const nextIndex = currentIndex === -1 ? 0 : (currentIndex + 1) % layouts.length 171 const padding = reverse ? -1 : 1
172 const nextIndex = currentIndex === -1 ? 0 : (currentIndex + padding + layouts.length) % layouts.length
169 const nextLayout = layouts[nextIndex] 173 const nextLayout = layouts[nextIndex]
170 this.container.setAttribute("data-layout", nextLayout.name) 174 this.container.setAttribute("data-layout", nextLayout.name)
171} 175}
@@ -177,14 +181,14 @@ export const generateMaps = (container, callback) => {
177 const showcase = document.createElement('div') 181 const showcase = document.createElement('div')
178 container.appendChild(showcase) 182 container.appendChild(showcase)
179 showcase.classList.add('Showcase') 183 showcase.classList.add('Showcase')
180 const renderedMaps = [] 184 const renderMaps = []
181 185
182 const dumbymap = { 186 const dumbymap = {
183 container, 187 container,
184 htmlHolder, 188 htmlHolder,
185 showcase, 189 showcase,
186 blocks, 190 blocks,
187 renderedMaps, 191 renderMaps: renderMaps,
188 } 192 }
189 dumbymap.utils = { 193 dumbymap.utils = {
190 focusNextMap: throttle(focusNextMap.bind(dumbymap), focusDelay.bind(dumbymap)), 194 focusNextMap: throttle(focusNextMap.bind(dumbymap), focusDelay.bind(dumbymap)),
@@ -346,10 +350,9 @@ export const generateMaps = (container, callback) => {
346 } 350 }
347 351
348 Object.values(dumbymap) 352 Object.values(dumbymap)
349 .filter(e => e instanceof HTMLElement) 353 .flat()
350 .forEach(e => e.removeAttribute('style')) 354 .filter(ele => ele instanceof HTMLElement)
351 dumbymap.blocks 355 .forEach(ele => ele.removeAttribute('style'))
352 .forEach(e => e.removeAttribute('style'))
353 356
354 if (newLayout) { 357 if (newLayout) {
355 layouts.find(l => l.name === newLayout) 358 layouts.find(l => l.name === newLayout)
@@ -376,9 +379,8 @@ export const generateMaps = (container, callback) => {
376 // Render Maps {{{ 379 // Render Maps {{{
377 380
378 const afterEachMapLoaded = (mapContainer) => { 381 const afterEachMapLoaded = (mapContainer) => {
379 renderedMaps.push(mapContainer)
380 renderedMaps.sort((a, b) => mapIdList.indexOf(a.id) - mapIdList.indexOf(b.id))
381 mapContainer.setAttribute('tabindex', "-1") 382 mapContainer.setAttribute('tabindex', "-1")
383 mapContainer.setAttribute('data-state', "rendered")
382 384
383 const observer = mapFocusObserver() 385 const observer = mapFocusObserver()
384 mapFocusObserver().observe(mapContainer, { 386 mapFocusObserver().observe(mapContainer, {
@@ -416,7 +418,7 @@ export const generateMaps = (container, callback) => {
416 ...config.aliases ?? {} 418 ...config.aliases ?? {}
417 }, 419 },
418 })) 420 }))
419 const renderTargets = elementsWithMapConfig 421 elementsWithMapConfig
420 .map(async (target) => { 422 .map(async (target) => {
421 // Get text in code block starts with '```map' 423 // Get text in code block starts with '```map'
422 const configText = target.querySelector('.language-map') 424 const configText = target.querySelector('.language-map')
@@ -433,25 +435,23 @@ export const generateMaps = (container, callback) => {
433 } 435 }
434 436
435 // Render maps 437 // Render maps
436 return render(target, configList) 438 return render(target, configList).map(renderMap => {
437 .then(results => { 439 renderMaps.push(renderMap)
438 results.forEach((mapByConfig) => { 440 renderMap.promise
439 if (mapByConfig.status === 'fulfilled') { 441 .then(_ => afterEachMapLoaded(renderMap.target))
440 afterEachMapLoaded(mapByConfig.value) 442 .catch(err => console.error('Fail to render target element with ID:', renderMap.target.id, err))
441 return mapByConfig.value 443
442 } else { 444 return renderMap.promise
443 console.error('Fail to render target element', mapByConfig.reason) 445 })
444 }
445 })
446 })
447 }) 446 })
448 447
449 Promise.all(renderTargets) 448 Promise.allSettled(renderMaps.map(r => r.promise))
450 .then(() => { 449 .then(() => {
451 console.info('Finish Rendering') 450 console.info('Finish Rendering')
452 451
453 const maps = htmlHolder.querySelectorAll('.map-container') ?? [] 452 renderMaps
454 Array.from(maps) 453 .map(r => r.target)
454 .filter(target => target.getAttribute('data-state') === 'rendered')
455 .forEach(ele => { 455 .forEach(ele => {
456 callback(ele) 456 callback(ele)
457 const markers = geoLinks 457 const markers = geoLinks
@@ -465,10 +465,8 @@ export const generateMaps = (container, callback) => {
465 465
466 htmlHolder.querySelectorAll('.marker') 466 htmlHolder.querySelectorAll('.marker')
467 .forEach(marker => htmlHolder.anchors.push(marker)) 467 .forEach(marker => htmlHolder.anchors.push(marker))
468
469 return maps
470 }) 468 })
471 469
472 //}}} 470 //}}}
473 return dumbymap 471 return Object.seal(dumbymap)
474} 472}