diff options
Diffstat (limited to 'src/dumbymap.mjs')
-rw-r--r-- | src/dumbymap.mjs | 64 |
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 |
141 | function focusNextMap(reverse = false) { | 141 | function 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 | ||
165 | function switchToNextLayout() { | 168 | function 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 | } |