aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/dumbymap.mjs70
1 files changed, 40 insertions, 30 deletions
diff --git a/src/dumbymap.mjs b/src/dumbymap.mjs
index d18fab8..d7a29e9 100644
--- a/src/dumbymap.mjs
+++ b/src/dumbymap.mjs
@@ -266,9 +266,6 @@ export const generateMaps = async (container, callback) => {
266 container.appendChild(showcase) 266 container.appendChild(showcase)
267 showcase.classList.add('Showcase') 267 showcase.classList.add('Showcase')
268 268
269 const toShowcaseWithThrottle = throttle(animateRectTransition, 300)
270 const fromShowCaseWithThrottle = throttle(animateRectTransition, 300)
271
272 const mapFocusObserver = () => new MutationObserver((mutations) => { 269 const mapFocusObserver = () => new MutationObserver((mutations) => {
273 const mutation = mutations.at(-1) 270 const mutation = mutations.at(-1)
274 const target = mutation.target 271 const target = mutation.target
@@ -289,16 +286,14 @@ export const generateMaps = async (container, callback) => {
289 showcase.appendChild(target) 286 showcase.appendChild(target)
290 287
291 // Resume rect from Semantic HTML to Showcase, with animation 288 // Resume rect from Semantic HTML to Showcase, with animation
292 toShowcaseWithThrottle(target, placeholder.getBoundingClientRect(), { 289 animateRectTransition(target, placeholder.getBoundingClientRect(), {
293 duration: 300, 290 duration: 300,
294 resume: true 291 resume: true
295 }) 292 })
296 } else if (showcase.contains(target)) { 293 } else if (showcase.contains(target)) {
297 const placeholder = htmlHolder.querySelector(`[data-placeholder="${target.id}"]`) 294 const placeholder = htmlHolder.querySelector(`[data-placeholder="${target.id}"]`)
298 if (!placeholder) throw Error(`Cannot fine placeholder for map "${target.id}"`) 295 if (!placeholder) throw Error(`Cannot fine placeholder for map "${target.id}"`)
299 const animation = fromShowCaseWithThrottle(target, placeholder.getBoundingClientRect(), { 296 const animation = animateRectTransition(target, placeholder.getBoundingClientRect(), { duration: 300 })
300 duration: 300
301 })
302 297
303 const afterAnimation = () => { 298 const afterAnimation = () => {
304 placeholder.parentElement.replaceChild(target, placeholder) 299 placeholder.parentElement.replaceChild(target, placeholder)
@@ -322,7 +317,40 @@ export const generateMaps = async (container, callback) => {
322 const layouts = ['none', 'side', 'overlay'] 317 const layouts = ['none', 'side', 'overlay']
323 container.setAttribute("data-layout", layouts[0]) 318 container.setAttribute("data-layout", layouts[0])
324 319
325 // FIXME Use UI to switch layouts 320 const switchToNextLayout = throttle(() => {
321 let currentLayout = container.getAttribute('data-layout')
322 currentLayout = currentLayout ? currentLayout : 'none'
323 const nextIndex = (layouts.indexOf(currentLayout) + 1) % layouts.length
324 const nextLayout = layouts[nextIndex]
325
326 container.setAttribute("data-layout", nextLayout)
327 }, 300)
328
329 // TODO Use UI to switch layouts
330 // Focus to next map with throttle
331 const focusNextMap = throttle((reverse = false) => {
332 // Decide how many candidates could be focused
333 const selector = '.map-container, [data-placeholder]'
334 const candidates = Array.from(htmlHolder.querySelectorAll(selector))
335 if (candidates.length <= 1) return
336
337 // Get current focused element
338 const currentFocus = htmlHolder.querySelector('.map-container[data-focus=true]')
339 ?? htmlHolder.querySelector('[data-placeholder]')
340
341 // Remove class name of focus for ALL candidates
342 // This may trigger animation
343 Array.from(container.querySelectorAll('.map-container'))
344 .forEach(ele => ele.removeAttribute('data-focus'));
345
346 // Focus next focus element
347 const nextIndex = currentFocus
348 ? (candidates.indexOf(currentFocus) + (reverse ? -1 : 1)) % candidates.length
349 : 0
350 const nextFocus = candidates.at(nextIndex)
351 nextFocus.setAttribute('data-focus', "true")
352 }, 300)
353
326 const originalKeyDown = document.onkeydown 354 const originalKeyDown = document.onkeydown
327 document.onkeydown = (e) => { 355 document.onkeydown = (e) => {
328 const event = originalKeyDown(e) 356 const event = originalKeyDown(e)
@@ -330,32 +358,13 @@ export const generateMaps = async (container, callback) => {
330 358
331 if (event.key === 'x' && container.querySelector('.map-container')) { 359 if (event.key === 'x' && container.querySelector('.map-container')) {
332 e.preventDefault() 360 e.preventDefault()
333 let currentLayout = container.getAttribute('data-layout') 361 switchToNextLayout()
334 currentLayout = currentLayout ? currentLayout : 'none'
335 const nextIndex = (layouts.indexOf(currentLayout) + 1) % layouts.length
336 const nextLayout = layouts[nextIndex]
337
338 container.setAttribute("data-layout", nextLayout)
339 } 362 }
340 363
341 // Use Tab to change focus map 364 // Use Tab to change focus map
342 if (event.key === 'Tab') { 365 if (event.key === 'Tab') {
343 e.preventDefault() 366 e.preventDefault()
344 367 focusNextMap(event.shiftkey)
345 const selector = '.map-container, [data-placeholder]'
346 const candidates = Array.from(htmlHolder.querySelectorAll(selector))
347 if (candidates.length <= 1) return
348
349 const currentFocus = htmlHolder.querySelector('.map-container[data-focus=true]')
350 ?? htmlHolder.querySelector('[data-placeholder]')
351 Array.from(container.querySelectorAll('.map-container')).forEach(e =>
352 e.removeAttribute('data-focus')
353 );
354 const index = currentFocus
355 ? (candidates.indexOf(currentFocus) + (event.shiftKey ? -1 : 1)) % candidates.length
356 : 0
357 const nextFocus = candidates.at(index)
358 nextFocus.setAttribute('data-focus', "true")
359 } 368 }
360 } 369 }
361 370
@@ -402,7 +411,8 @@ export const generateMaps = async (container, callback) => {
402 layoutObserver.observe(container, { 411 layoutObserver.observe(container, {
403 attributes: true, 412 attributes: true,
404 attributeFilter: ["data-layout"], 413 attributeFilter: ["data-layout"],
405 attributeOldValue: true 414 attributeOldValue: true,
415 characterDataOldValue: true
406 }); 416 });
407 417
408 onRemove(htmlHolder, () => layoutObserver.disconnect()) 418 onRemove(htmlHolder, () => layoutObserver.disconnect())