diff options
| author | Hsieh Chin Fan <pham@topo.tw> | 2024-10-16 16:57:47 +0800 |
|---|---|---|
| committer | Hsieh Chin Fan <pham@topo.tw> | 2024-10-16 18:57:18 +0800 |
| commit | 1caf56dc0a2bbf4bb484fe4f312b5229a63aace3 (patch) | |
| tree | 913a3e5803e9d4128d0ad6d8bd6ed64326d5e5d4 /src | |
| parent | 9c90bd1cbdc5de5b50def0eb4cb3e65e80194af3 (diff) | |
feat: add simple script to test mapclay
* add more options for generateMaps for general purposes
* add rollup config for adding script into addon
Diffstat (limited to 'src')
| -rw-r--r-- | src/dumbymap.mjs | 128 |
1 files changed, 78 insertions, 50 deletions
diff --git a/src/dumbymap.mjs b/src/dumbymap.mjs index 8e26ee6..ee61838 100644 --- a/src/dumbymap.mjs +++ b/src/dumbymap.mjs | |||
| @@ -3,7 +3,7 @@ import MarkdownItAnchor from 'markdown-it-anchor' | |||
| 3 | import MarkdownItFootnote from 'markdown-it-footnote' | 3 | import MarkdownItFootnote from 'markdown-it-footnote' |
| 4 | import MarkdownItFrontMatter from 'markdown-it-front-matter' | 4 | import MarkdownItFrontMatter from 'markdown-it-front-matter' |
| 5 | import MarkdownItInjectLinenumbers from 'markdown-it-inject-linenumbers' | 5 | import MarkdownItInjectLinenumbers from 'markdown-it-inject-linenumbers' |
| 6 | import { renderWith, defaultAliases, parseConfigsFromYaml } from 'mapclay' | 6 | import * as mapclay from 'mapclay' |
| 7 | import { replaceTextNodes, onRemove, animateRectTransition, throttle, shiftByWindow } from './utils' | 7 | import { replaceTextNodes, onRemove, animateRectTransition, throttle, shiftByWindow } from './utils' |
| 8 | import { Layout, SideBySide, Overlay } from './Layout' | 8 | import { Layout, SideBySide, Overlay } from './Layout' |
| 9 | import * as utils from './dumbyUtils' | 9 | import * as utils from './dumbyUtils' |
| @@ -86,6 +86,68 @@ export const markdown2HTML = (container, mdContent) => { | |||
| 86 | } | 86 | } |
| 87 | 87 | ||
| 88 | /** | 88 | /** |
| 89 | * defaultBlocks. | ||
| 90 | * @description Default way to get blocks from Semantic HTML | ||
| 91 | * @param {HTMLElement} root | ||
| 92 | */ | ||
| 93 | const defaultBlocks = root => { | ||
| 94 | const articles = root.querySelectorAll('article') | ||
| 95 | if (articles.length > 2) return articles | ||
| 96 | |||
| 97 | const others = Array.from( | ||
| 98 | root.querySelectorAll(':has(>p, >blockquote, >pre, >ul, >ol, >table, >details)'), | ||
| 99 | ) | ||
| 100 | .map(e => { | ||
| 101 | e.classList.add('dumby-block') | ||
| 102 | return e | ||
| 103 | }) | ||
| 104 | .filter(e => { | ||
| 105 | const isContained = e.parentElement.closest('.dumby-block') | ||
| 106 | if (isContained) e.classList.remove('dumby-block') | ||
| 107 | return !isContained | ||
| 108 | }) | ||
| 109 | |||
| 110 | return others | ||
| 111 | } | ||
| 112 | |||
| 113 | /** | ||
| 114 | * updateAttributeByStep. | ||
| 115 | * @description Update data attribute by steps of map render | ||
| 116 | * @param {Object} - renderer which is running steps | ||
| 117 | */ | ||
| 118 | const updateAttributeByStep = ({ results, target, steps }) => { | ||
| 119 | let passNum = results.filter( | ||
| 120 | r => r.type === 'render' && r.state.match(/success|skip/), | ||
| 121 | ).length | ||
| 122 | const total = steps.length | ||
| 123 | passNum += `/${total}` | ||
| 124 | |||
| 125 | const final = results.filter(r => r.type === 'render').length === total | ||
| 126 | |||
| 127 | // FIXME HACK use MutationObserver for animation | ||
| 128 | if (!target.animations) target.animations = Promise.resolve() | ||
| 129 | target.animations = target.animations.then(async () => { | ||
| 130 | await new Promise(resolve => setTimeout(resolve, 100)) | ||
| 131 | if (final) passNum += '\x20' | ||
| 132 | target.dataset.report = passNum | ||
| 133 | |||
| 134 | if (final) setTimeout(() => delete target.dataset.report, 100) | ||
| 135 | }) | ||
| 136 | } | ||
| 137 | |||
| 138 | /** Get default render method by converter */ | ||
| 139 | const defaultRender = mapclay.renderWith(config => ({ | ||
| 140 | use: config.use ?? 'Leaflet', | ||
| 141 | width: '100%', | ||
| 142 | ...config, | ||
| 143 | aliases: { | ||
| 144 | ...mapclay.defaultAliases, | ||
| 145 | ...(config.aliases ?? {}), | ||
| 146 | }, | ||
| 147 | stepCallback: updateAttributeByStep, | ||
| 148 | })) | ||
| 149 | |||
| 150 | /** | ||
| 89 | * Generates maps based on the provided configuration | 151 | * Generates maps based on the provided configuration |
| 90 | * | 152 | * |
| 91 | * @param {HTMLElement} container - The container element for the maps | 153 | * @param {HTMLElement} container - The container element for the maps |
| @@ -96,16 +158,19 @@ export const markdown2HTML = (container, mdContent) => { | |||
| 96 | */ | 158 | */ |
| 97 | export const generateMaps = (container, { | 159 | export const generateMaps = (container, { |
| 98 | crs = 'EPSG:4326', | 160 | crs = 'EPSG:4326', |
| 161 | initialLayout, | ||
| 99 | layouts = [], | 162 | layouts = [], |
| 100 | delay, | 163 | delay, |
| 101 | renderCallback, | 164 | renderCallback, |
| 102 | addBlocks = htmlHolder => Array.from(htmlHolder.querySelectorAll('article')), | 165 | addBlocks = defaultBlocks, |
| 166 | render = defaultRender, | ||
| 103 | } = {}) => { | 167 | } = {}) => { |
| 104 | /** Prepare Contaner/HTML-Holder/Showcase */ | 168 | /** Prepare Contaner */ |
| 105 | container.classList.add('Dumby') | 169 | container.classList.add('Dumby') |
| 106 | delete container.dataset.layout | 170 | delete container.dataset.layout |
| 107 | container.dataset.layout = defaultLayouts[0].name | 171 | container.dataset.layout = initialLayout ?? defaultLayouts[0].name |
| 108 | 172 | ||
| 173 | /** Prepare Semantic HTML part and blocks of contents inside */ | ||
| 109 | const htmlHolder = container.querySelector('.SemanticHtml, :has(article, section)') ?? container.firstElementChild | 174 | const htmlHolder = container.querySelector('.SemanticHtml, :has(article, section)') ?? container.firstElementChild |
| 110 | htmlHolder.classList.add('.SemanticHtml') | 175 | htmlHolder.classList.add('.SemanticHtml') |
| 111 | const blocks = addBlocks(htmlHolder) | 176 | const blocks = addBlocks(htmlHolder) |
| @@ -114,12 +179,13 @@ export const generateMaps = (container, { | |||
| 114 | b.dataset.total = blocks.length | 179 | b.dataset.total = blocks.length |
| 115 | }) | 180 | }) |
| 116 | 181 | ||
| 182 | /** Prepare Showcase */ | ||
| 117 | const showcase = document.createElement('div') | 183 | const showcase = document.createElement('div') |
| 118 | container.appendChild(showcase) | 184 | container.appendChild(showcase) |
| 119 | showcase.classList.add('Showcase') | 185 | showcase.classList.add('Showcase') |
| 120 | const renderPromises = [] | ||
| 121 | 186 | ||
| 122 | /** Prepare Modal */ | 187 | /** Prepare Other Variables */ |
| 188 | const renderPromises = [] | ||
| 123 | const modalContent = document.createElement('div') | 189 | const modalContent = document.createElement('div') |
| 124 | container.appendChild(modalContent) | 190 | container.appendChild(modalContent) |
| 125 | const modal = new PlainModal(modalContent) | 191 | const modal = new PlainModal(modalContent) |
| @@ -392,63 +458,25 @@ export const generateMaps = (container, { | |||
| 392 | const elementsWithMapConfig = Array.from( | 458 | const elementsWithMapConfig = Array.from( |
| 393 | container.querySelectorAll(mapBlockSelector) ?? [], | 459 | container.querySelectorAll(mapBlockSelector) ?? [], |
| 394 | ) | 460 | ) |
| 395 | /** | 461 | if (elementsWithMapConfig.length === 0) { |
| 396 | * updateAttributeByStep. | 462 | const map = document.createElement('pre') |
| 397 | * | 463 | map.textContent = '#Created by DumbyMap' |
| 398 | * @param {Object} - renderer which is running steps | 464 | htmlHolder.insertBefore(map, htmlHolder.firstElementChild) |
| 399 | */ | 465 | elementsWithMapConfig.push(map) |
| 400 | const updateAttributeByStep = ({ results, target, steps }) => { | ||
| 401 | let passNum = results.filter( | ||
| 402 | r => r.type === 'render' && r.state.match(/success|skip/), | ||
| 403 | ).length | ||
| 404 | const total = steps.length | ||
| 405 | passNum += `/${total}` | ||
| 406 | |||
| 407 | const final = results.filter(r => r.type === 'render').length === total | ||
| 408 | |||
| 409 | // FIXME HACK use MutationObserver for animation | ||
| 410 | if (!target.animations) target.animations = Promise.resolve() | ||
| 411 | target.animations = target.animations.then(async () => { | ||
| 412 | await new Promise(resolve => setTimeout(resolve, 100)) | ||
| 413 | if (final) passNum += '\x20' | ||
| 414 | target.dataset.report = passNum | ||
| 415 | |||
| 416 | if (final) setTimeout(() => delete target.dataset.report, 100) | ||
| 417 | }) | ||
| 418 | } | 466 | } |
| 419 | /** | ||
| 420 | * config converter for mapclay.renderWith() | ||
| 421 | * | ||
| 422 | * @param {Object} config | ||
| 423 | * @return {Object} - converted config | ||
| 424 | */ | ||
| 425 | const configConverter = config => ({ | ||
| 426 | use: config.use ?? 'Leaflet', | ||
| 427 | width: '100%', | ||
| 428 | ...config, | ||
| 429 | aliases: { | ||
| 430 | ...defaultAliases, | ||
| 431 | ...(config.aliases ?? {}), | ||
| 432 | }, | ||
| 433 | stepCallback: updateAttributeByStep, | ||
| 434 | }) | ||
| 435 | |||
| 436 | /** Get render method by converter */ | ||
| 437 | const render = renderWith(configConverter) | ||
| 438 | 467 | ||
| 439 | /** Render each taget element for maps */ | 468 | /** Render each taget element for maps */ |
| 440 | let order = 0 | 469 | let order = 0 |
| 441 | elementsWithMapConfig.forEach(target => { | 470 | elementsWithMapConfig.forEach(target => { |
| 442 | // Get text in code block starts with markdown text '```map' | 471 | // Get text in code block starts with markdown text '```map' |
| 443 | const configText = target | 472 | const configText = target |
| 444 | .querySelector('.language-map') | ||
| 445 | .textContent // BE CAREFUL!!! 0xa0 char is "non-breaking spaces" in HTML text content | 473 | .textContent // BE CAREFUL!!! 0xa0 char is "non-breaking spaces" in HTML text content |
| 446 | // replace it by normal space | 474 | // replace it by normal space |
| 447 | .replace(/\u00A0/g, '\u0020') | 475 | .replace(/\u00A0/g, '\u0020') |
| 448 | 476 | ||
| 449 | let configList = [] | 477 | let configList = [] |
| 450 | try { | 478 | try { |
| 451 | configList = parseConfigsFromYaml(configText).map(assignMapId) | 479 | configList = mapclay.parseConfigsFromYaml(configText).map(assignMapId) |
| 452 | } catch (_) { | 480 | } catch (_) { |
| 453 | console.warn('Fail to parse yaml config for element', target) | 481 | console.warn('Fail to parse yaml config for element', target) |
| 454 | return | 482 | return |