diff options
| author | Hsieh Chin Fan <pham@topo.tw> | 2024-10-09 16:28:43 +0800 |
|---|---|---|
| committer | Hsieh Chin Fan <pham@topo.tw> | 2024-10-09 16:28:43 +0800 |
| commit | 479ddf1ac9a3a4ac2f31c42fc01297d24889ca34 (patch) | |
| tree | 399dda0511e96da876cd5bdce71cf3522aa50773 /src | |
| parent | 2d5f7ad47019b54fa1c2ef08cafb9b25f82a4ecc (diff) | |
style: add jsdoc for expressions
Diffstat (limited to 'src')
| -rw-r--r-- | src/dumbymap.mjs | 68 |
1 files changed, 38 insertions, 30 deletions
diff --git a/src/dumbymap.mjs b/src/dumbymap.mjs index b02e783..180517b 100644 --- a/src/dumbymap.mjs +++ b/src/dumbymap.mjs | |||
| @@ -10,15 +10,19 @@ import * as utils from './dumbyUtils' | |||
| 10 | import * as menuItem from './MenuItem' | 10 | import * as menuItem from './MenuItem' |
| 11 | import PlainModal from 'plain-modal' | 11 | import PlainModal from 'plain-modal' |
| 12 | 12 | ||
| 13 | /** Selector of special HTML Elements */ | ||
| 13 | const mapBlockSelector = 'pre:has(.language-map)' | 14 | const mapBlockSelector = 'pre:has(.language-map)' |
| 14 | const docLinkSelector = 'a[href^="#"][title^="=>"]' | 15 | const docLinkSelector = 'a[href^="#"][title^="=>"]' |
| 15 | const geoLinkSelector = 'a[href^="geo:"]' | 16 | const geoLinkSelector = 'a[href^="geo:"]' |
| 16 | 17 | ||
| 18 | /** Default Layouts */ | ||
| 17 | const layouts = [ | 19 | const layouts = [ |
| 18 | new Layout({ name: 'normal' }), | 20 | new Layout({ name: 'normal' }), |
| 19 | new SideBySide({ name: 'side-by-side' }), | 21 | new SideBySide({ name: 'side-by-side' }), |
| 20 | new Overlay({ name: 'overlay' }), | 22 | new Overlay({ name: 'overlay' }), |
| 21 | ] | 23 | ] |
| 24 | |||
| 25 | /** Cache across every dumbymap generation */ | ||
| 22 | const mapCache = {} | 26 | const mapCache = {} |
| 23 | 27 | ||
| 24 | /** | 28 | /** |
| @@ -28,12 +32,12 @@ const mapCache = {} | |||
| 28 | * @param {String} mdContent -- Texts in Markdown | 32 | * @param {String} mdContent -- Texts in Markdown |
| 29 | */ | 33 | */ |
| 30 | export const markdown2HTML = (container, mdContent) => { | 34 | export const markdown2HTML = (container, mdContent) => { |
| 31 | // Render: Markdown -> HTML {{{ | 35 | /** Prepare Elements for Container */ |
| 32 | container.replaceChildren() | 36 | container.replaceChildren() |
| 33 | |||
| 34 | container.innerHTML = '<div class="SemanticHtml"></div>' | 37 | container.innerHTML = '<div class="SemanticHtml"></div>' |
| 35 | const htmlHolder = container.querySelector('.SemanticHtml') | 38 | const htmlHolder = container.querySelector('.SemanticHtml') |
| 36 | 39 | ||
| 40 | /** Prepare MarkdownIt Instance */ | ||
| 37 | const md = MarkdownIt({ | 41 | const md = MarkdownIt({ |
| 38 | html: true, | 42 | html: true, |
| 39 | breaks: true, | 43 | breaks: true, |
| @@ -48,11 +52,11 @@ export const markdown2HTML = (container, mdContent) => { | |||
| 48 | .use(MarkdownItFrontMatter) | 52 | .use(MarkdownItFrontMatter) |
| 49 | .use(MarkdownItInjectLinenumbers) | 53 | .use(MarkdownItInjectLinenumbers) |
| 50 | 54 | ||
| 51 | // Create links with geo scheme | 55 | /** Set up linkify for GeoLinks */ |
| 52 | const coordinateRegex = /^(\D*)(-?\d+\.?\d*)\s*([,\x2F\uFF0C])\s*(-?\d+\.?\d*)/ | 56 | const coordinateRegex = /^(\D*)(-?\d+\.?\d*)\s*([,\x2F\uFF0C])\s*(-?\d+\.?\d*)/ |
| 53 | const coordinateValue = { | 57 | const coordinateValue = { |
| 54 | validate: coordinateRegex, | 58 | validate: coordinateRegex, |
| 55 | normalize: function (match) { | 59 | normalize: function(match) { |
| 56 | const [, , x, sep, y] = match.text.match(coordinateRegex) | 60 | const [, , x, sep, y] = match.text.match(coordinateRegex) |
| 57 | match.url = `geo:${y},${x}?xy=${x},${y}` | 61 | match.url = `geo:${y},${x}?xy=${x},${y}` |
| 58 | match.text = `${x}${sep} ${y}` | 62 | match.text = `${x}${sep} ${y}` |
| @@ -65,6 +69,7 @@ export const markdown2HTML = (container, mdContent) => { | |||
| 65 | md.linkify.add(prefix, coordinateValue), | 69 | md.linkify.add(prefix, coordinateValue), |
| 66 | ) | 70 | ) |
| 67 | 71 | ||
| 72 | /** Custom rule for Blocks in DumbyMap */ | ||
| 68 | // FIXME A better way to generate blocks | 73 | // FIXME A better way to generate blocks |
| 69 | md.renderer.rules.dumby_block_open = () => '<div>' | 74 | md.renderer.rules.dumby_block_open = () => '<div>' |
| 70 | md.renderer.rules.dumby_block_close = () => '</div>' | 75 | md.renderer.rules.dumby_block_close = () => '</div>' |
| @@ -87,8 +92,9 @@ export const markdown2HTML = (container, mdContent) => { | |||
| 87 | state.tokens.push(new state.Token('dumby_block_close', '', -1)) | 92 | state.tokens.push(new state.Token('dumby_block_close', '', -1)) |
| 88 | }) | 93 | }) |
| 89 | 94 | ||
| 95 | /** Render HTML */ | ||
| 90 | htmlHolder.innerHTML = md.render(mdContent) | 96 | htmlHolder.innerHTML = md.render(mdContent) |
| 91 | 97 | /** Post HTML rendered */ | |
| 92 | // TODO Do this in markdown-it | 98 | // TODO Do this in markdown-it |
| 93 | const blocks = htmlHolder.querySelectorAll(':scope > div:not(:has(nav))') | 99 | const blocks = htmlHolder.querySelectorAll(':scope > div:not(:has(nav))') |
| 94 | blocks.forEach(b => { | 100 | blocks.forEach(b => { |
| @@ -97,7 +103,6 @@ export const markdown2HTML = (container, mdContent) => { | |||
| 97 | }) | 103 | }) |
| 98 | 104 | ||
| 99 | return container | 105 | return container |
| 100 | // }}} | ||
| 101 | } | 106 | } |
| 102 | 107 | ||
| 103 | /** | 108 | /** |
| @@ -108,6 +113,8 @@ export const markdown2HTML = (container, mdContent) => { | |||
| 108 | * @return {Object} dumbymap -- Include and Elements and Methods about managing contents | 113 | * @return {Object} dumbymap -- Include and Elements and Methods about managing contents |
| 109 | */ | 114 | */ |
| 110 | export const generateMaps = (container, { delay, renderCallback } = {}) => { | 115 | export const generateMaps = (container, { delay, renderCallback } = {}) => { |
| 116 | |||
| 117 | /** Prepare Contaner/HTML Holder/Showcase */ | ||
| 111 | container.classList.add('Dumby') | 118 | container.classList.add('Dumby') |
| 112 | container.removeAttribute('data-layout') | 119 | container.removeAttribute('data-layout') |
| 113 | container.setAttribute('data-layout', layouts[0].name) | 120 | container.setAttribute('data-layout', layouts[0].name) |
| @@ -117,10 +124,13 @@ export const generateMaps = (container, { delay, renderCallback } = {}) => { | |||
| 117 | container.appendChild(showcase) | 124 | container.appendChild(showcase) |
| 118 | showcase.classList.add('Showcase') | 125 | showcase.classList.add('Showcase') |
| 119 | const renderPromises = [] | 126 | const renderPromises = [] |
| 127 | |||
| 128 | /** Prepare Modal */ | ||
| 120 | const modalContent = document.createElement('div') | 129 | const modalContent = document.createElement('div') |
| 121 | container.appendChild(modalContent) | 130 | container.appendChild(modalContent) |
| 122 | const modal = new PlainModal(modalContent) | 131 | const modal = new PlainModal(modalContent) |
| 123 | 132 | ||
| 133 | /** Define dumbymap Object */ | ||
| 124 | const dumbymap = { | 134 | const dumbymap = { |
| 125 | layouts, | 135 | layouts, |
| 126 | container, | 136 | container, |
| @@ -152,21 +162,16 @@ export const generateMaps = (container, { delay, renderCallback } = {}) => { | |||
| 152 | dumbymap.utils[util] = func.bind(dumbymap) | 162 | dumbymap.utils[util] = func.bind(dumbymap) |
| 153 | }) | 163 | }) |
| 154 | 164 | ||
| 155 | // LeaderLine {{{ | 165 | /** Create GeoLinks and DocLinks */ |
| 156 | 166 | container.querySelectorAll(docLinkSelector) | |
| 157 | Array.from(container.querySelectorAll(docLinkSelector)).filter( | 167 | .forEach(utils.createDocLink) |
| 158 | utils.createDocLink, | ||
| 159 | ) | ||
| 160 | |||
| 161 | // Add GeoLinks | ||
| 162 | container.querySelectorAll(geoLinkSelector) | 168 | container.querySelectorAll(geoLinkSelector) |
| 163 | .forEach(utils.createGeoLink) | 169 | .forEach(utils.createGeoLink) |
| 164 | 170 | ||
| 165 | // }}} | 171 | /** |
| 166 | // CSS observer {{{ | 172 | * mapFocusObserver. observe for map focus |
| 167 | // Focus Map {{{ | 173 | * @return {MutationObserver} observer |
| 168 | // Set focusArea | 174 | */ |
| 169 | |||
| 170 | const mapFocusObserver = () => | 175 | const mapFocusObserver = () => |
| 171 | new window.MutationObserver(mutations => { | 176 | new window.MutationObserver(mutations => { |
| 172 | const mutation = mutations.at(-1) | 177 | const mutation = mutations.at(-1) |
| @@ -238,11 +243,8 @@ export const generateMaps = (container, { delay, renderCallback } = {}) => { | |||
| 238 | }).finished.finally(afterAnimation) | 243 | }).finished.finally(afterAnimation) |
| 239 | } | 244 | } |
| 240 | }) | 245 | }) |
| 241 | // }}} | ||
| 242 | // Layout {{{ | ||
| 243 | // press key to switch layout | ||
| 244 | 246 | ||
| 245 | // observe layout change | 247 | /** Observer for layout changes */ |
| 246 | const layoutObserver = new window.MutationObserver(mutations => { | 248 | const layoutObserver = new window.MutationObserver(mutations => { |
| 247 | const mutation = mutations.at(-1) | 249 | const mutation = mutations.at(-1) |
| 248 | const oldLayout = mutation.oldValue | 250 | const oldLayout = mutation.oldValue |
| @@ -281,10 +283,12 @@ export const generateMaps = (container, { delay, renderCallback } = {}) => { | |||
| 281 | }) | 283 | }) |
| 282 | 284 | ||
| 283 | onRemove(htmlHolder, () => layoutObserver.disconnect()) | 285 | onRemove(htmlHolder, () => layoutObserver.disconnect()) |
| 284 | // }}} | ||
| 285 | // }}} | ||
| 286 | // Render Maps {{{ | ||
| 287 | 286 | ||
| 287 | /** | ||
| 288 | * afterMapRendered. callback of each map rendered | ||
| 289 | * | ||
| 290 | * @param {Object} renderer | ||
| 291 | */ | ||
| 288 | const afterMapRendered = renderer => { | 292 | const afterMapRendered = renderer => { |
| 289 | const mapElement = renderer.target | 293 | const mapElement = renderer.target |
| 290 | // FIXME | 294 | // FIXME |
| @@ -371,7 +375,11 @@ export const generateMaps = (container, { delay, renderCallback } = {}) => { | |||
| 371 | }, | 375 | }, |
| 372 | stepCallback: updateAttributeByStep, | 376 | stepCallback: updateAttributeByStep, |
| 373 | }) | 377 | }) |
| 378 | |||
| 379 | /** Get render method by converter */ | ||
| 374 | const render = renderWith(configConverter) | 380 | const render = renderWith(configConverter) |
| 381 | |||
| 382 | /** Render each taget element for maps */ | ||
| 375 | let order = 0 | 383 | let order = 0 |
| 376 | elementsWithMapConfig.forEach(target => { | 384 | elementsWithMapConfig.forEach(target => { |
| 377 | // Get text in code block starts with markdown text '```map' | 385 | // Get text in code block starts with markdown text '```map' |
| @@ -428,8 +436,8 @@ export const generateMaps = (container, { delay, renderCallback } = {}) => { | |||
| 428 | clearTimeout(timer) | 436 | clearTimeout(timer) |
| 429 | }) | 437 | }) |
| 430 | }) | 438 | }) |
| 431 | // }}} | 439 | |
| 432 | // Menu {{{ | 440 | /** Prepare Context Menu */ |
| 433 | const menu = document.createElement('div') | 441 | const menu = document.createElement('div') |
| 434 | menu.className = 'menu' | 442 | menu.className = 'menu' |
| 435 | menu.style.display = 'none' | 443 | menu.style.display = 'none' |
| @@ -441,7 +449,7 @@ export const generateMaps = (container, { delay, renderCallback } = {}) => { | |||
| 441 | } | 449 | } |
| 442 | container.appendChild(menu) | 450 | container.appendChild(menu) |
| 443 | 451 | ||
| 444 | // Menu Items | 452 | /** Menu Items for Context Menu */ |
| 445 | container.oncontextmenu = e => { | 453 | container.oncontextmenu = e => { |
| 446 | menu.replaceChildren() | 454 | menu.replaceChildren() |
| 447 | menu.style.display = 'block' | 455 | menu.style.display = 'block' |
| @@ -479,7 +487,7 @@ export const generateMaps = (container, { delay, renderCallback } = {}) => { | |||
| 479 | return menu | 487 | return menu |
| 480 | } | 488 | } |
| 481 | 489 | ||
| 482 | // Remove menu when click outside | 490 | /** Event Handler when clicking outside of Context Manu */ |
| 483 | const actionOutsideMenu = e => { | 491 | const actionOutsideMenu = e => { |
| 484 | if (menu.style.display === 'none') return | 492 | if (menu.style.display === 'none') return |
| 485 | const keepMenu = e.target.closest('.keep-menu') || e.target.classList.contains('.keep-menu') | 493 | const keepMenu = e.target.closest('.keep-menu') || e.target.classList.contains('.keep-menu') |
| @@ -499,6 +507,6 @@ export const generateMaps = (container, { delay, renderCallback } = {}) => { | |||
| 499 | onRemove(htmlHolder, () => | 507 | onRemove(htmlHolder, () => |
| 500 | document.removeEventListener('click', actionOutsideMenu), | 508 | document.removeEventListener('click', actionOutsideMenu), |
| 501 | ) | 509 | ) |
| 502 | // }}} | 510 | |
| 503 | return Object.seal(dumbymap) | 511 | return Object.seal(dumbymap) |
| 504 | } | 512 | } |