diff options
| -rw-r--r-- | eslint.config.js | 49 | ||||
| -rw-r--r-- | package.json | 3 | ||||
| -rw-r--r-- | rollup.config.js | 27 | ||||
| -rw-r--r-- | src/Layout.mjs | 8 | ||||
| -rw-r--r-- | src/MenuItem.mjs | 46 | ||||
| -rw-r--r-- | src/dumbyUtils.mjs | 36 | ||||
| -rw-r--r-- | src/dumbymap.mjs | 44 | ||||
| -rw-r--r-- | src/editor.mjs | 140 | ||||
| -rw-r--r-- | src/utils.mjs | 8 |
9 files changed, 154 insertions, 207 deletions
diff --git a/eslint.config.js b/eslint.config.js deleted file mode 100644 index 3bca729..0000000 --- a/eslint.config.js +++ /dev/null | |||
| @@ -1,49 +0,0 @@ | |||
| 1 | import globals from 'globals' | ||
| 2 | import js from '@eslint/js' | ||
| 3 | import importPlugin from 'eslint-plugin-import' | ||
| 4 | import promisePlugin from 'eslint-plugin-promise' | ||
| 5 | import nodePlugin from 'eslint-plugin-node' | ||
| 6 | import jsdoc from 'eslint-plugin-jsdoc' | ||
| 7 | |||
| 8 | export default [ | ||
| 9 | js.configs.recommended, | ||
| 10 | { | ||
| 11 | languageOptions: { | ||
| 12 | ecmaVersion: 2022, | ||
| 13 | sourceType: 'module', | ||
| 14 | globals: { | ||
| 15 | ...globals.browser, | ||
| 16 | ...globals.node | ||
| 17 | } | ||
| 18 | }, | ||
| 19 | plugins: { | ||
| 20 | import: importPlugin, | ||
| 21 | promise: promisePlugin, | ||
| 22 | node: nodePlugin | ||
| 23 | }, | ||
| 24 | rules: { | ||
| 25 | 'no-unused-vars': ['warn', { | ||
| 26 | varsIgnorePattern: '^_', | ||
| 27 | argsIgnorePattern: '^_', | ||
| 28 | caughtErrorsIgnorePattern: '^ignore|_' | ||
| 29 | }], | ||
| 30 | 'import/no-unresolved': 'error', | ||
| 31 | 'no-console': ['error', { allow: ['info', 'warn', 'error'] }], | ||
| 32 | eqeqeq: ['error', 'always'], | ||
| 33 | // 'curly': ['warn', 'multi'], | ||
| 34 | 'prefer-const': 'error', | ||
| 35 | 'no-var': 'error', | ||
| 36 | 'array-callback-return': 'error', | ||
| 37 | 'no-unexpected-multiline': 'warn' | ||
| 38 | } | ||
| 39 | }, | ||
| 40 | { | ||
| 41 | files: ['src/*js'], | ||
| 42 | plugins: { | ||
| 43 | jsdoc | ||
| 44 | }, | ||
| 45 | rules: { | ||
| 46 | 'jsdoc/require-description': 'warn' | ||
| 47 | } | ||
| 48 | } | ||
| 49 | ] | ||
diff --git a/package.json b/package.json index 2c39691..0017e6c 100644 --- a/package.json +++ b/package.json | |||
| @@ -25,7 +25,7 @@ | |||
| 25 | "build-resources": "cp node_modules/easymde/dist/easymde.min.js dist; cp node_modules/easymde/dist/easymde.min.css dist/css", | 25 | "build-resources": "cp node_modules/easymde/dist/easymde.min.js dist; cp node_modules/easymde/dist/easymde.min.css dist/css", |
| 26 | "server": "live-server --port=8080 --ignore='**/src/**js' --wait=2000 --no-browser --cors", | 26 | "server": "live-server --port=8080 --ignore='**/src/**js' --wait=2000 --no-browser --cors", |
| 27 | "dev": "npm run server", | 27 | "dev": "npm run server", |
| 28 | "lint": "npx standard", | 28 | "lint": "standard --fix", |
| 29 | "style": "scripts/stylelint.sh", | 29 | "style": "scripts/stylelint.sh", |
| 30 | "prepack": "npm run lint && npm run style && npm run build", | 30 | "prepack": "npm run lint && npm run style && npm run build", |
| 31 | "postpack": "rm -rf dist/css dist/renderers; ln -sf `pwd`/src/css dist; cp node_modules/easymde/dist/easymde.min.css src/css; ln -sf `pwd`/mapclay/dist/renderers dist" | 31 | "postpack": "rm -rf dist/css dist/renderers; ln -sf `pwd`/src/css dist; cp node_modules/easymde/dist/easymde.min.css src/css; ln -sf `pwd`/mapclay/dist/renderers dist" |
| @@ -38,7 +38,6 @@ | |||
| 38 | "globals": "^15.10.0", | 38 | "globals": "^15.10.0", |
| 39 | "rollup": "^4.24.0", | 39 | "rollup": "^4.24.0", |
| 40 | "rollup-plugin-bundle-stats": "^4.15.1", | 40 | "rollup-plugin-bundle-stats": "^4.15.1", |
| 41 | "standard": "^17.1.2", | ||
| 42 | "stylelint": "^16.9.0", | 41 | "stylelint": "^16.9.0", |
| 43 | "stylelint-config-standard": "^36.0.1", | 42 | "stylelint-config-standard": "^36.0.1", |
| 44 | "stylelint-order": "^6.0.4" | 43 | "stylelint-order": "^6.0.4" |
diff --git a/rollup.config.js b/rollup.config.js index 145224b..f5a22eb 100644 --- a/rollup.config.js +++ b/rollup.config.js | |||
| @@ -13,12 +13,12 @@ const general = { | |||
| 13 | dir: './dist', | 13 | dir: './dist', |
| 14 | format: 'esm', | 14 | format: 'esm', |
| 15 | entryFileNames: '[name].mjs', | 15 | entryFileNames: '[name].mjs', |
| 16 | sourcemap: 'true' | 16 | sourcemap: 'true', |
| 17 | } | 17 | }, |
| 18 | ], | 18 | ], |
| 19 | watch: { | 19 | watch: { |
| 20 | clearScreen: false, | 20 | clearScreen: false, |
| 21 | include: ['src/**', 'mapclay/dist/mapclay.mjs'] | 21 | include: ['src/**', 'mapclay/dist/mapclay.mjs'], |
| 22 | }, | 22 | }, |
| 23 | context: 'window', | 23 | context: 'window', |
| 24 | plugins: [ | 24 | plugins: [ |
| @@ -26,13 +26,12 @@ const general = { | |||
| 26 | name: 'watch-mapclay', | 26 | name: 'watch-mapclay', |
| 27 | buildStart () { | 27 | buildStart () { |
| 28 | const mapclayPath = join(process.cwd(), 'mapclay', 'dist', 'mapclay.mjs') | 28 | const mapclayPath = join(process.cwd(), 'mapclay', 'dist', 'mapclay.mjs') |
| 29 | console.log('Watching:', mapclayPath) | ||
| 30 | if (existsSync(mapclayPath)) { | 29 | if (existsSync(mapclayPath)) { |
| 31 | this.addWatchFile(mapclayPath) | 30 | this.addWatchFile(mapclayPath) |
| 32 | } else { | 31 | } else { |
| 33 | console.log('mapclay.mjs not found at:', mapclayPath) | 32 | console.warn('mapclay.mjs not found at:', mapclayPath) |
| 34 | } | 33 | } |
| 35 | } | 34 | }, |
| 36 | }, | 35 | }, |
| 37 | { | 36 | { |
| 38 | name: 'leader-line', | 37 | name: 'leader-line', |
| @@ -41,7 +40,7 @@ const general = { | |||
| 41 | return `${code}\nexport default LeaderLine;` | 40 | return `${code}\nexport default LeaderLine;` |
| 42 | } | 41 | } |
| 43 | return null | 42 | return null |
| 44 | } | 43 | }, |
| 45 | }, | 44 | }, |
| 46 | { | 45 | { |
| 47 | name: 'mapclay', | 46 | name: 'mapclay', |
| @@ -50,24 +49,24 @@ const general = { | |||
| 50 | return './mapclay/dist/mapclay.mjs' | 49 | return './mapclay/dist/mapclay.mjs' |
| 51 | } | 50 | } |
| 52 | return null | 51 | return null |
| 53 | } | 52 | }, |
| 54 | }, | 53 | }, |
| 55 | node(), | 54 | node(), |
| 56 | commonjs(), | 55 | commonjs(), |
| 57 | production && terser({ | 56 | production && terser({ |
| 58 | keep_fnames: true | 57 | keep_fnames: true, |
| 59 | }), | 58 | }), |
| 60 | production && bundleStats() | 59 | production && bundleStats(), |
| 61 | ] | 60 | ], |
| 62 | } | 61 | } |
| 63 | 62 | ||
| 64 | export default [ | 63 | export default [ |
| 65 | { | 64 | { |
| 66 | input: 'src/editor.mjs' | 65 | input: 'src/editor.mjs', |
| 67 | }, | 66 | }, |
| 68 | { | 67 | { |
| 69 | input: 'src/dumbymap.mjs' | 68 | input: 'src/dumbymap.mjs', |
| 70 | } | 69 | }, |
| 71 | ] | 70 | ] |
| 72 | .map(config => ({ ...general, ...config })) | 71 | .map(config => ({ ...general, ...config })) |
| 73 | .filter((config) => production || config.input.match(/editor/)) | 72 | .filter((config) => production || config.input.match(/editor/)) |
diff --git a/src/Layout.mjs b/src/Layout.mjs index 6bb6282..c5276b4 100644 --- a/src/Layout.mjs +++ b/src/Layout.mjs | |||
| @@ -55,7 +55,7 @@ export class SideBySide extends Layout { | |||
| 55 | 55 | ||
| 56 | const draggable = new PlainDraggable(bar, { | 56 | const draggable = new PlainDraggable(bar, { |
| 57 | handle, | 57 | handle, |
| 58 | containment: { left: '25%', top: 0, right: '75%', height: 0 } | 58 | containment: { left: '25%', top: 0, right: '75%', height: 0 }, |
| 59 | }) | 59 | }) |
| 60 | draggable.draggableCursor = 'grab' | 60 | draggable.draggableCursor = 'grab' |
| 61 | 61 | ||
| @@ -110,7 +110,7 @@ export class Overlay extends Layout { | |||
| 110 | addDraggable = element => { | 110 | addDraggable = element => { |
| 111 | // Make sure current element always on top | 111 | // Make sure current element always on top |
| 112 | const siblings = Array.from( | 112 | const siblings = Array.from( |
| 113 | element.parentElement?.querySelectorAll(':scope > *') ?? [] | 113 | element.parentElement?.querySelectorAll(':scope > *') ?? [], |
| 114 | ) | 114 | ) |
| 115 | let popTimer = null | 115 | let popTimer = null |
| 116 | element.onmouseover = () => { | 116 | element.onmouseover = () => { |
| @@ -135,7 +135,7 @@ export class Overlay extends Layout { | |||
| 135 | top, | 135 | top, |
| 136 | left, | 136 | left, |
| 137 | handle: draggablePart, | 137 | handle: draggablePart, |
| 138 | snap: { x: { step: 20 }, y: { step: 20 } } | 138 | snap: { x: { step: 20 }, y: { step: 20 } }, |
| 139 | }) | 139 | }) |
| 140 | 140 | ||
| 141 | // FIXME use pure CSS to hide utils | 141 | // FIXME use pure CSS to hide utils |
| @@ -215,7 +215,7 @@ export class Overlay extends Layout { | |||
| 215 | animateRectTransition( | 215 | animateRectTransition( |
| 216 | wrapper, | 216 | wrapper, |
| 217 | { left: originLeft, top: originTop }, | 217 | { left: originLeft, top: originTop }, |
| 218 | { resume: true, duration: 300 } | 218 | { resume: true, duration: 300 }, |
| 219 | ).finished.finally(() => this.addDraggable(wrapper)) | 219 | ).finished.finally(() => this.addDraggable(wrapper)) |
| 220 | 220 | ||
| 221 | // Trivial case: | 221 | // Trivial case: |
diff --git a/src/MenuItem.mjs b/src/MenuItem.mjs index d580cb3..0fea539 100644 --- a/src/MenuItem.mjs +++ b/src/MenuItem.mjs | |||
| @@ -81,9 +81,9 @@ export const pickMapItem = ({ utils }) => | |||
| 81 | onclick: () => { | 81 | onclick: () => { |
| 82 | map.classList.add('focus') | 82 | map.classList.add('focus') |
| 83 | map.scrollIntoView({ behavior: 'smooth' }) | 83 | map.scrollIntoView({ behavior: 'smooth' }) |
| 84 | } | 84 | }, |
| 85 | }) | 85 | }), |
| 86 | ) | 86 | ), |
| 87 | }) | 87 | }) |
| 88 | 88 | ||
| 89 | /** | 89 | /** |
| @@ -118,10 +118,10 @@ export const pickBlockItem = ({ blocks, utils }) => | |||
| 118 | // UX: remove menu after user select/deselect blocks | 118 | // UX: remove menu after user select/deselect blocks |
| 119 | const submenu = e.target.closest('.sub-menu') | 119 | const submenu = e.target.closest('.sub-menu') |
| 120 | submenu.onmouseleave = () => { submenu.closest('.menu').style.display = 'none' } | 120 | submenu.onmouseleave = () => { submenu.closest('.menu').style.display = 'none' } |
| 121 | } | 121 | }, |
| 122 | }) | 122 | }) |
| 123 | } | 123 | }, |
| 124 | ) | 124 | ), |
| 125 | }) | 125 | }) |
| 126 | 126 | ||
| 127 | /** | 127 | /** |
| @@ -138,14 +138,14 @@ export const pickLayoutItem = ({ container, layouts }) => | |||
| 138 | layout => | 138 | layout => |
| 139 | new Item({ | 139 | new Item({ |
| 140 | text: layout.name, | 140 | text: layout.name, |
| 141 | onclick: () => container.setAttribute('data-layout', layout.name) | 141 | onclick: () => container.setAttribute('data-layout', layout.name), |
| 142 | }) | 142 | }), |
| 143 | ), | 143 | ), |
| 144 | new Item({ | 144 | new Item({ |
| 145 | innerHTML: '<a href="https://github.com/outdoorsafetylab/dumbymap#layouts" class="external" style="display: block; padding: 0.5rem;">More...</a>', | 145 | innerHTML: '<a href="https://github.com/outdoorsafetylab/dumbymap#layouts" class="external" style="display: block; padding: 0.5rem;">More...</a>', |
| 146 | style: 'padding: 0;' | 146 | style: 'padding: 0;', |
| 147 | }) | 147 | }), |
| 148 | ] | 148 | ], |
| 149 | }) | 149 | }) |
| 150 | 150 | ||
| 151 | /** | 151 | /** |
| @@ -174,7 +174,7 @@ export const addGeoLink = ({ utils }, range) => | |||
| 174 | range.deleteContents() | 174 | range.deleteContents() |
| 175 | range.insertNode(anchor) | 175 | range.insertNode(anchor) |
| 176 | } | 176 | } |
| 177 | } | 177 | }, |
| 178 | }) | 178 | }) |
| 179 | 179 | ||
| 180 | /** | 180 | /** |
| @@ -195,7 +195,7 @@ export class Suggestion extends Item { | |||
| 195 | 195 | ||
| 196 | this.onmouseover = () => { | 196 | this.onmouseover = () => { |
| 197 | Array.from(this.parentElement?.children)?.forEach(s => | 197 | Array.from(this.parentElement?.children)?.forEach(s => |
| 198 | s.classList.remove('focus') | 198 | s.classList.remove('focus'), |
| 199 | ) | 199 | ) |
| 200 | this.classList.add('focus') | 200 | this.classList.add('focus') |
| 201 | } | 201 | } |
| @@ -244,12 +244,12 @@ export const renderResults = ({ modal, modalContent }, map) => | |||
| 244 | success: 'green', | 244 | success: 'green', |
| 245 | fail: 'red', | 245 | fail: 'red', |
| 246 | skip: 'black', | 246 | skip: 'black', |
| 247 | stop: 'chocolate' | 247 | stop: 'chocolate', |
| 248 | }[result.state] ?? 'black' | 248 | }[result.state] ?? 'black' |
| 249 | printObject( | 249 | printObject( |
| 250 | result, | 250 | result, |
| 251 | modalContent, | 251 | modalContent, |
| 252 | `${result.func.name} <span style='float: right;'><span style='display: inline-block; width: 100px; color: ${color};'>${result.state}</span></span>` | 252 | `${result.func.name} <span style='float: right;'><span style='display: inline-block; width: 100px; color: ${color};'>${result.state}</span></span>`, |
| 253 | ) | 253 | ) |
| 254 | } | 254 | } |
| 255 | 255 | ||
| @@ -258,7 +258,7 @@ export const renderResults = ({ modal, modalContent }, map) => | |||
| 258 | prepareHeading.textContent = 'Prepare Steps' | 258 | prepareHeading.textContent = 'Prepare Steps' |
| 259 | modalContent.appendChild(prepareHeading) | 259 | modalContent.appendChild(prepareHeading) |
| 260 | const prepareSteps = map.renderer.results.filter( | 260 | const prepareSteps = map.renderer.results.filter( |
| 261 | r => r.type === 'prepare' | 261 | r => r.type === 'prepare', |
| 262 | ) | 262 | ) |
| 263 | prepareSteps.forEach(printDetails) | 263 | prepareSteps.forEach(printDetails) |
| 264 | 264 | ||
| @@ -268,7 +268,7 @@ export const renderResults = ({ modal, modalContent }, map) => | |||
| 268 | modalContent.appendChild(renderHeading) | 268 | modalContent.appendChild(renderHeading) |
| 269 | const renderSteps = map.renderer.results.filter(r => r.type === 'render') | 269 | const renderSteps = map.renderer.results.filter(r => r.type === 'render') |
| 270 | renderSteps.forEach(printDetails) | 270 | renderSteps.forEach(printDetails) |
| 271 | } | 271 | }, |
| 272 | }) | 272 | }) |
| 273 | 273 | ||
| 274 | /** | 274 | /** |
| @@ -326,7 +326,7 @@ function printObject (obj, parentElement, name = null) { | |||
| 326 | export const toggleBlockFocus = block => | 326 | export const toggleBlockFocus = block => |
| 327 | new Item({ | 327 | new Item({ |
| 328 | text: 'Toggle Focus', | 328 | text: 'Toggle Focus', |
| 329 | onclick: () => block.classList.toggle('focus') | 329 | onclick: () => block.classList.toggle('focus'), |
| 330 | }) | 330 | }) |
| 331 | 331 | ||
| 332 | /** | 332 | /** |
| @@ -337,7 +337,7 @@ export const toggleBlockFocus = block => | |||
| 337 | export const toggleMapFocus = map => | 337 | export const toggleMapFocus = map => |
| 338 | new Item({ | 338 | new Item({ |
| 339 | text: 'Toggle Focus', | 339 | text: 'Toggle Focus', |
| 340 | onclick: () => map.classList.toggle('focus') | 340 | onclick: () => map.classList.toggle('focus'), |
| 341 | }) | 341 | }) |
| 342 | 342 | ||
| 343 | /** | 343 | /** |
| @@ -354,7 +354,7 @@ export const getCoordinatesByPixels = (map, xy) => | |||
| 354 | const xyString = `[${x.toFixed(7)}, ${y.toFixed(7)}]` | 354 | const xyString = `[${x.toFixed(7)}, ${y.toFixed(7)}]` |
| 355 | navigator.clipboard.writeText(xyString) | 355 | navigator.clipboard.writeText(xyString) |
| 356 | window.alert(`${xyString} copied to clipboard`) | 356 | window.alert(`${xyString} copied to clipboard`) |
| 357 | } | 357 | }, |
| 358 | }) | 358 | }) |
| 359 | 359 | ||
| 360 | /** | 360 | /** |
| @@ -365,7 +365,7 @@ export const getCoordinatesByPixels = (map, xy) => | |||
| 365 | export const restoreCamera = map => | 365 | export const restoreCamera = map => |
| 366 | new Item({ | 366 | new Item({ |
| 367 | text: 'Restore Camera', | 367 | text: 'Restore Camera', |
| 368 | onclick: () => map.renderer.restoreCamera() | 368 | onclick: () => map.renderer.restoreCamera(), |
| 369 | }) | 369 | }) |
| 370 | 370 | ||
| 371 | /** | 371 | /** |
| @@ -387,6 +387,6 @@ export const addRefLink = (cm, refLinks) => | |||
| 387 | } else { | 387 | } else { |
| 388 | cm.replaceSelection(`[${selection}][${refLink.ref}]`) | 388 | cm.replaceSelection(`[${selection}][${refLink.ref}]`) |
| 389 | } | 389 | } |
| 390 | } | 390 | }, |
| 391 | })) | 391 | })), |
| 392 | }) | 392 | }) |
diff --git a/src/dumbyUtils.mjs b/src/dumbyUtils.mjs index 852e4c7..2efc3b1 100644 --- a/src/dumbyUtils.mjs +++ b/src/dumbyUtils.mjs | |||
| @@ -6,7 +6,7 @@ import { insideWindow, insideParent } from './utils' | |||
| 6 | * | 6 | * |
| 7 | * @param {Boolean} reverse -- focus previous map | 7 | * @param {Boolean} reverse -- focus previous map |
| 8 | */ | 8 | */ |
| 9 | export function focusNextMap(reverse = false) { | 9 | export function focusNextMap (reverse = false) { |
| 10 | const renderedList = this.utils.renderedMaps() | 10 | const renderedList = this.utils.renderedMaps() |
| 11 | const index = renderedList.findIndex(e => e.classList.contains('focus')) | 11 | const index = renderedList.findIndex(e => e.classList.contains('focus')) |
| 12 | const nextIndex = (index + (reverse ? -1 : 1)) % renderedList.length | 12 | const nextIndex = (index + (reverse ? -1 : 1)) % renderedList.length |
| @@ -21,13 +21,13 @@ export function focusNextMap(reverse = false) { | |||
| 21 | * | 21 | * |
| 22 | * @param {Boolean} reverse -- focus previous block | 22 | * @param {Boolean} reverse -- focus previous block |
| 23 | */ | 23 | */ |
| 24 | export function focusNextBlock(reverse = false) { | 24 | export function focusNextBlock (reverse = false) { |
| 25 | const blocks = this.blocks.filter(b => | 25 | const blocks = this.blocks.filter(b => |
| 26 | b.checkVisibility({ | 26 | b.checkVisibility({ |
| 27 | contentVisibilityAuto: true, | 27 | contentVisibilityAuto: true, |
| 28 | opacityProperty: true, | 28 | opacityProperty: true, |
| 29 | visibilityProperty: true | 29 | visibilityProperty: true, |
| 30 | }) | 30 | }), |
| 31 | ) | 31 | ) |
| 32 | const index = blocks.findIndex(e => e.classList.contains('focus')) | 32 | const index = blocks.findIndex(e => e.classList.contains('focus')) |
| 33 | const nextIndex = (index + (reverse ? -1 : 1)) % blocks.length | 33 | const nextIndex = (index + (reverse ? -1 : 1)) % blocks.length |
| @@ -56,7 +56,7 @@ export const scrollToBlock = block => { | |||
| 56 | /** | 56 | /** |
| 57 | * focusDelay. Delay of throttle, value changes by cases | 57 | * focusDelay. Delay of throttle, value changes by cases |
| 58 | */ | 58 | */ |
| 59 | export function focusDelay() { | 59 | export function focusDelay () { |
| 60 | return window.window.getComputedStyle(this.showcase).display === 'none' ? 50 : 300 | 60 | return window.window.getComputedStyle(this.showcase).display === 'none' ? 50 : 300 |
| 61 | } | 61 | } |
| 62 | 62 | ||
| @@ -65,7 +65,7 @@ export function focusDelay() { | |||
| 65 | * | 65 | * |
| 66 | * @param {Boolean} reverse -- Switch to previous one | 66 | * @param {Boolean} reverse -- Switch to previous one |
| 67 | */ | 67 | */ |
| 68 | export function switchToNextLayout(reverse = false) { | 68 | export function switchToNextLayout (reverse = false) { |
| 69 | const layouts = this.layouts | 69 | const layouts = this.layouts |
| 70 | const currentLayoutName = this.container.getAttribute('data-layout') | 70 | const currentLayoutName = this.container.getAttribute('data-layout') |
| 71 | const currentIndex = layouts.map(l => l.name).indexOf(currentLayoutName) | 71 | const currentIndex = layouts.map(l => l.name).indexOf(currentLayoutName) |
| @@ -81,7 +81,7 @@ export function switchToNextLayout(reverse = false) { | |||
| 81 | /** | 81 | /** |
| 82 | * removeBlockFocus. | 82 | * removeBlockFocus. |
| 83 | */ | 83 | */ |
| 84 | export function removeBlockFocus() { | 84 | export function removeBlockFocus () { |
| 85 | this.blocks.forEach(b => b.classList.remove('focus')) | 85 | this.blocks.forEach(b => b.classList.remove('focus')) |
| 86 | } | 86 | } |
| 87 | 87 | ||
| @@ -94,7 +94,7 @@ export function removeBlockFocus() { | |||
| 94 | const getMarkersFromMaps = link => { | 94 | const getMarkersFromMaps = link => { |
| 95 | const maps = Array.from( | 95 | const maps = Array.from( |
| 96 | link.closest('.Dumby') | 96 | link.closest('.Dumby') |
| 97 | .querySelectorAll('.mapclay[data-render="fulfilled"]') | 97 | .querySelectorAll('.mapclay[data-render="fulfilled"]'), |
| 98 | ) | 98 | ) |
| 99 | return maps | 99 | return maps |
| 100 | .filter(map => link.targets ? link.targets.includes(map.id) : true) | 100 | .filter(map => link.targets ? link.targets.includes(map.id) : true) |
| @@ -105,7 +105,7 @@ const getMarkersFromMaps = link => { | |||
| 105 | return map.querySelector(`.marker[title="${markerTitle}"]`) ?? | 105 | return map.querySelector(`.marker[title="${markerTitle}"]`) ?? |
| 106 | renderer.addMarker({ | 106 | renderer.addMarker({ |
| 107 | xy: link.xy, | 107 | xy: link.xy, |
| 108 | title: markerTitle | 108 | title: markerTitle, |
| 109 | }) | 109 | }) |
| 110 | }) | 110 | }) |
| 111 | } | 111 | } |
| @@ -122,7 +122,7 @@ const addLeaderLine = (link, target) => { | |||
| 122 | end: target, | 122 | end: target, |
| 123 | hide: true, | 123 | hide: true, |
| 124 | middleLabel: link.url.searchParams.get('text'), | 124 | middleLabel: link.url.searchParams.get('text'), |
| 125 | path: 'magnet' | 125 | path: 'magnet', |
| 126 | }) | 126 | }) |
| 127 | line.show('draw', { duration: 300 }) | 127 | line.show('draw', { duration: 300 }) |
| 128 | 128 | ||
| @@ -196,10 +196,10 @@ export const createDocLink = link => { | |||
| 196 | end: target, | 196 | end: target, |
| 197 | middleLabel: LeaderLine.pathLabel({ | 197 | middleLabel: LeaderLine.pathLabel({ |
| 198 | text: label, | 198 | text: label, |
| 199 | fontWeight: 'bold' | 199 | fontWeight: 'bold', |
| 200 | }), | 200 | }), |
| 201 | hide: true, | 201 | hide: true, |
| 202 | path: 'magnet' | 202 | path: 'magnet', |
| 203 | }) | 203 | }) |
| 204 | link.lines.push(line) | 204 | link.lines.push(line) |
| 205 | line.show('draw', { duration: 300 }) | 205 | line.show('draw', { duration: 300 }) |
| @@ -229,7 +229,6 @@ const removeLeaderLines = link => { | |||
| 229 | * @return {Function} function | 229 | * @return {Function} function |
| 230 | */ | 230 | */ |
| 231 | const updateMapCameraByMarker = xy => marker => { | 231 | const updateMapCameraByMarker = xy => marker => { |
| 232 | console.log('update') | ||
| 233 | const renderer = marker.closest('.mapclay')?.renderer | 232 | const renderer = marker.closest('.mapclay')?.renderer |
| 234 | renderer.updateCamera({ center: xy }, true) | 233 | renderer.updateCamera({ center: xy }, true) |
| 235 | } | 234 | } |
| @@ -244,10 +243,17 @@ const isAnchorVisible = anchor => { | |||
| 244 | return insideWindow(anchor) && insideParent(anchor, mapContainer) | 243 | return insideWindow(anchor) && insideParent(anchor, mapContainer) |
| 245 | } | 244 | } |
| 246 | 245 | ||
| 246 | /** | ||
| 247 | * addAnchorByPoint. | ||
| 248 | * | ||
| 249 | * @param {point} options.point -- object has {x, y} for window coordinates | ||
| 250 | * @param {HTMLElement} options.map | ||
| 251 | * @param {Function} options.validateAnchorName -- validate anchor name is OK to use | ||
| 252 | */ | ||
| 247 | export const addAnchorByPoint = ({ | 253 | export const addAnchorByPoint = ({ |
| 248 | point, | 254 | point, |
| 249 | map, | 255 | map, |
| 250 | validateAnchorName = () => true | 256 | validateAnchorName = () => true, |
| 251 | }) => { | 257 | }) => { |
| 252 | const rect = map.getBoundingClientRect() | 258 | const rect = map.getBoundingClientRect() |
| 253 | const [x, y] = map.renderer | 259 | const [x, y] = map.renderer |
| @@ -268,7 +274,7 @@ export const addAnchorByPoint = ({ | |||
| 268 | map.renderer.addMarker({ | 274 | map.renderer.addMarker({ |
| 269 | xy: [x, y], | 275 | xy: [x, y], |
| 270 | title: `${map.id}@${x},${y}`, | 276 | title: `${map.id}@${x},${y}`, |
| 271 | type: 'circle' | 277 | type: 'circle', |
| 272 | }) | 278 | }) |
| 273 | 279 | ||
| 274 | return { ref: anchorName, link } | 280 | return { ref: anchorName, link } |
diff --git a/src/dumbymap.mjs b/src/dumbymap.mjs index 1da5bb6..b02e783 100644 --- a/src/dumbymap.mjs +++ b/src/dumbymap.mjs | |||
| @@ -17,7 +17,7 @@ const geoLinkSelector = 'a[href^="geo:"]' | |||
| 17 | const layouts = [ | 17 | const layouts = [ |
| 18 | new Layout({ name: 'normal' }), | 18 | new Layout({ name: 'normal' }), |
| 19 | new SideBySide({ name: 'side-by-side' }), | 19 | new SideBySide({ name: 'side-by-side' }), |
| 20 | new Overlay({ name: 'overlay' }) | 20 | new Overlay({ name: 'overlay' }), |
| 21 | ] | 21 | ] |
| 22 | const mapCache = {} | 22 | const mapCache = {} |
| 23 | 23 | ||
| @@ -37,12 +37,12 @@ export const markdown2HTML = (container, mdContent) => { | |||
| 37 | const md = MarkdownIt({ | 37 | const md = MarkdownIt({ |
| 38 | html: true, | 38 | html: true, |
| 39 | breaks: true, | 39 | breaks: true, |
| 40 | linkify: true | 40 | linkify: true, |
| 41 | }) | 41 | }) |
| 42 | .use(MarkdownItAnchor, { | 42 | .use(MarkdownItAnchor, { |
| 43 | permalink: MarkdownItAnchor.permalink.linkInsideHeader({ | 43 | permalink: MarkdownItAnchor.permalink.linkInsideHeader({ |
| 44 | placement: 'before' | 44 | placement: 'before', |
| 45 | }) | 45 | }), |
| 46 | }) | 46 | }) |
| 47 | .use(MarkdownItFootnote) | 47 | .use(MarkdownItFootnote) |
| 48 | .use(MarkdownItFrontMatter) | 48 | .use(MarkdownItFrontMatter) |
| @@ -58,11 +58,11 @@ export const markdown2HTML = (container, mdContent) => { | |||
| 58 | match.text = `${x}${sep} ${y}` | 58 | match.text = `${x}${sep} ${y}` |
| 59 | match.index += match.text.indexOf(x) + 1 | 59 | match.index += match.text.indexOf(x) + 1 |
| 60 | return match | 60 | return match |
| 61 | } | 61 | }, |
| 62 | } | 62 | } |
| 63 | const patterns = ['[', '(', '📍', '\uFF08', '@', 'geo:', 'twd'] | 63 | const patterns = ['[', '(', '📍', '\uFF08', '@', 'geo:', 'twd'] |
| 64 | patterns.forEach(prefix => | 64 | patterns.forEach(prefix => |
| 65 | md.linkify.add(prefix, coordinateValue) | 65 | md.linkify.add(prefix, coordinateValue), |
| 66 | ) | 66 | ) |
| 67 | 67 | ||
| 68 | // FIXME A better way to generate blocks | 68 | // FIXME A better way to generate blocks |
| @@ -133,7 +133,7 @@ export const generateMaps = (container, { delay, renderCallback } = {}) => { | |||
| 133 | ...utils, | 133 | ...utils, |
| 134 | renderedMaps: () => | 134 | renderedMaps: () => |
| 135 | Array.from( | 135 | Array.from( |
| 136 | container.querySelectorAll('.mapclay[data-render=fulfilled]') | 136 | container.querySelectorAll('.mapclay[data-render=fulfilled]'), |
| 137 | ).sort((a, b) => a.style.order > b.style.order), | 137 | ).sort((a, b) => a.style.order > b.style.order), |
| 138 | setContextMenu: (menuCallback) => { | 138 | setContextMenu: (menuCallback) => { |
| 139 | const originalCallback = container.oncontextmenu | 139 | const originalCallback = container.oncontextmenu |
| @@ -145,8 +145,8 @@ export const generateMaps = (container, { delay, renderCallback } = {}) => { | |||
| 145 | } | 145 | } |
| 146 | }, | 146 | }, |
| 147 | focusNextMap: throttle(utils.focusNextMap, utils.focusDelay), | 147 | focusNextMap: throttle(utils.focusNextMap, utils.focusDelay), |
| 148 | switchToNextLayout: throttle(utils.switchToNextLayout, 300) | 148 | switchToNextLayout: throttle(utils.switchToNextLayout, 300), |
| 149 | } | 149 | }, |
| 150 | } | 150 | } |
| 151 | Object.entries(dumbymap.utils).forEach(([util, func]) => { | 151 | Object.entries(dumbymap.utils).forEach(([util, func]) => { |
| 152 | dumbymap.utils[util] = func.bind(dumbymap) | 152 | dumbymap.utils[util] = func.bind(dumbymap) |
| @@ -155,7 +155,7 @@ export const generateMaps = (container, { delay, renderCallback } = {}) => { | |||
| 155 | // LeaderLine {{{ | 155 | // LeaderLine {{{ |
| 156 | 156 | ||
| 157 | Array.from(container.querySelectorAll(docLinkSelector)).filter( | 157 | Array.from(container.querySelectorAll(docLinkSelector)).filter( |
| 158 | utils.createDocLink | 158 | utils.createDocLink, |
| 159 | ) | 159 | ) |
| 160 | 160 | ||
| 161 | // Add GeoLinks | 161 | // Add GeoLinks |
| @@ -177,7 +177,7 @@ export const generateMaps = (container, { delay, renderCallback } = {}) => { | |||
| 177 | showcase.checkVisibility({ | 177 | showcase.checkVisibility({ |
| 178 | contentVisibilityAuto: true, | 178 | contentVisibilityAuto: true, |
| 179 | opacityProperty: true, | 179 | opacityProperty: true, |
| 180 | visibilityProperty: true | 180 | visibilityProperty: true, |
| 181 | }) | 181 | }) |
| 182 | 182 | ||
| 183 | if (focus) { | 183 | if (focus) { |
| @@ -217,12 +217,12 @@ export const generateMaps = (container, { delay, renderCallback } = {}) => { | |||
| 217 | // Resume rect from Semantic HTML to Showcase, with animation | 217 | // Resume rect from Semantic HTML to Showcase, with animation |
| 218 | animateRectTransition(target, placeholder.getBoundingClientRect(), { | 218 | animateRectTransition(target, placeholder.getBoundingClientRect(), { |
| 219 | duration: 300, | 219 | duration: 300, |
| 220 | resume: true | 220 | resume: true, |
| 221 | }) | 221 | }) |
| 222 | } else if (showcase.contains(target)) { | 222 | } else if (showcase.contains(target)) { |
| 223 | // Check placeholder is inside Semantic HTML | 223 | // Check placeholder is inside Semantic HTML |
| 224 | const placeholder = htmlHolder.querySelector( | 224 | const placeholder = htmlHolder.querySelector( |
| 225 | `[data-placeholder="${target.id}"]` | 225 | `[data-placeholder="${target.id}"]`, |
| 226 | ) | 226 | ) |
| 227 | if (!placeholder) { throw Error(`Cannot find placeholder for map "${target.id}"`) } | 227 | if (!placeholder) { throw Error(`Cannot find placeholder for map "${target.id}"`) } |
| 228 | 228 | ||
| @@ -234,7 +234,7 @@ export const generateMaps = (container, { delay, renderCallback } = {}) => { | |||
| 234 | 234 | ||
| 235 | // animation from Showcase to placeholder | 235 | // animation from Showcase to placeholder |
| 236 | animateRectTransition(target, placeholder.getBoundingClientRect(), { | 236 | animateRectTransition(target, placeholder.getBoundingClientRect(), { |
| 237 | duration: 300 | 237 | duration: 300, |
| 238 | }).finished.finally(afterAnimation) | 238 | }).finished.finally(afterAnimation) |
| 239 | } | 239 | } |
| 240 | }) | 240 | }) |
| @@ -277,7 +277,7 @@ export const generateMaps = (container, { delay, renderCallback } = {}) => { | |||
| 277 | attributes: true, | 277 | attributes: true, |
| 278 | attributeFilter: ['data-layout'], | 278 | attributeFilter: ['data-layout'], |
| 279 | attributeOldValue: true, | 279 | attributeOldValue: true, |
| 280 | characterDataOldValue: true | 280 | characterDataOldValue: true, |
| 281 | }) | 281 | }) |
| 282 | 282 | ||
| 283 | onRemove(htmlHolder, () => layoutObserver.disconnect()) | 283 | onRemove(htmlHolder, () => layoutObserver.disconnect()) |
| @@ -303,7 +303,7 @@ export const generateMaps = (container, { delay, renderCallback } = {}) => { | |||
| 303 | observer.observe(mapElement, { | 303 | observer.observe(mapElement, { |
| 304 | attributes: true, | 304 | attributes: true, |
| 305 | attributeFilter: ['class'], | 305 | attributeFilter: ['class'], |
| 306 | attributeOldValue: true | 306 | attributeOldValue: true, |
| 307 | }) | 307 | }) |
| 308 | onRemove(dumbymap.htmlHolder, () => { | 308 | onRemove(dumbymap.htmlHolder, () => { |
| 309 | observer.disconnect() | 309 | observer.disconnect() |
| @@ -329,7 +329,7 @@ export const generateMaps = (container, { delay, renderCallback } = {}) => { | |||
| 329 | 329 | ||
| 330 | // Render each code block with "language-map" class | 330 | // Render each code block with "language-map" class |
| 331 | const elementsWithMapConfig = Array.from( | 331 | const elementsWithMapConfig = Array.from( |
| 332 | container.querySelectorAll(mapBlockSelector) ?? [] | 332 | container.querySelectorAll(mapBlockSelector) ?? [], |
| 333 | ) | 333 | ) |
| 334 | /** | 334 | /** |
| 335 | * updateAttributeByStep. | 335 | * updateAttributeByStep. |
| @@ -338,7 +338,7 @@ export const generateMaps = (container, { delay, renderCallback } = {}) => { | |||
| 338 | */ | 338 | */ |
| 339 | const updateAttributeByStep = ({ results, target, steps }) => { | 339 | const updateAttributeByStep = ({ results, target, steps }) => { |
| 340 | let passNum = results.filter( | 340 | let passNum = results.filter( |
| 341 | r => r.type === 'render' && r.state.match(/success|skip/) | 341 | r => r.type === 'render' && r.state.match(/success|skip/), |
| 342 | ).length | 342 | ).length |
| 343 | const total = steps.length | 343 | const total = steps.length |
| 344 | passNum += `/${total}` | 344 | passNum += `/${total}` |
| @@ -367,9 +367,9 @@ export const generateMaps = (container, { delay, renderCallback } = {}) => { | |||
| 367 | ...config, | 367 | ...config, |
| 368 | aliases: { | 368 | aliases: { |
| 369 | ...defaultAliases, | 369 | ...defaultAliases, |
| 370 | ...(config.aliases ?? {}) | 370 | ...(config.aliases ?? {}), |
| 371 | }, | 371 | }, |
| 372 | stepCallback: updateAttributeByStep | 372 | stepCallback: updateAttributeByStep, |
| 373 | }) | 373 | }) |
| 374 | const render = renderWith(configConverter) | 374 | const render = renderWith(configConverter) |
| 375 | let order = 0 | 375 | let order = 0 |
| @@ -422,7 +422,7 @@ export const generateMaps = (container, { delay, renderCallback } = {}) => { | |||
| 422 | } | 422 | } |
| 423 | }) | 423 | }) |
| 424 | }, | 424 | }, |
| 425 | delay ?? 1000 | 425 | delay ?? 1000, |
| 426 | ) | 426 | ) |
| 427 | onRemove(htmlHolder, () => { | 427 | onRemove(htmlHolder, () => { |
| 428 | clearTimeout(timer) | 428 | clearTimeout(timer) |
| @@ -497,7 +497,7 @@ export const generateMaps = (container, { delay, renderCallback } = {}) => { | |||
| 497 | } | 497 | } |
| 498 | document.addEventListener('click', actionOutsideMenu) | 498 | document.addEventListener('click', actionOutsideMenu) |
| 499 | onRemove(htmlHolder, () => | 499 | onRemove(htmlHolder, () => |
| 500 | document.removeEventListener('click', actionOutsideMenu) | 500 | document.removeEventListener('click', actionOutsideMenu), |
| 501 | ) | 501 | ) |
| 502 | // }}} | 502 | // }}} |
| 503 | return Object.seal(dumbymap) | 503 | return Object.seal(dumbymap) |
diff --git a/src/editor.mjs b/src/editor.mjs index 3714327..55c6267 100644 --- a/src/editor.mjs +++ b/src/editor.mjs | |||
| @@ -3,12 +3,12 @@ | |||
| 3 | import { markdown2HTML, generateMaps } from './dumbymap' | 3 | import { markdown2HTML, generateMaps } from './dumbymap' |
| 4 | import { defaultAliases, parseConfigsFromYaml } from 'mapclay' | 4 | import { defaultAliases, parseConfigsFromYaml } from 'mapclay' |
| 5 | import * as menuItem from './MenuItem' | 5 | import * as menuItem from './MenuItem' |
| 6 | import { shiftByWindow } from './utils.mjs' | ||
| 7 | import { addAnchorByPoint } from './dumbyUtils.mjs' | 6 | import { addAnchorByPoint } from './dumbyUtils.mjs' |
| 7 | import { shiftByWindow } from './utils.mjs' | ||
| 8 | import LeaderLine from 'leader-line' | 8 | import LeaderLine from 'leader-line' |
| 9 | 9 | ||
| 10 | // Set up Containers {{{ | 10 | // Set up Containers {{{ |
| 11 | 11 | /** Variables about dumbymap and editor **/ | |
| 12 | const url = new URL(window.location) | 12 | const url = new URL(window.location) |
| 13 | const context = document.querySelector('[data-mode]') | 13 | const context = document.querySelector('[data-mode]') |
| 14 | const dumbyContainer = document.querySelector('.DumbyMap') | 14 | const dumbyContainer = document.querySelector('.DumbyMap') |
| @@ -27,7 +27,6 @@ const appendRefLink = ({ cm, ref, link }) => { | |||
| 27 | 27 | ||
| 28 | refLinks.push({ ref, link }) | 28 | refLinks.push({ ref, link }) |
| 29 | } | 29 | } |
| 30 | |||
| 31 | /** | 30 | /** |
| 32 | * Watch for changes of editing mode | 31 | * Watch for changes of editing mode |
| 33 | * | 32 | * |
| @@ -43,11 +42,10 @@ new window.MutationObserver(() => { | |||
| 43 | }).observe(context, { | 42 | }).observe(context, { |
| 44 | attributes: true, | 43 | attributes: true, |
| 45 | attributeFilter: ['data-mode'], | 44 | attributeFilter: ['data-mode'], |
| 46 | attributeOldValue: true | 45 | attributeOldValue: true, |
| 47 | }) | 46 | }) |
| 48 | |||
| 49 | /** | 47 | /** |
| 50 | * toggle editing mode | 48 | * toggleEditing: toggle editing mode |
| 51 | */ | 49 | */ |
| 52 | const toggleEditing = () => { | 50 | const toggleEditing = () => { |
| 53 | const mode = context.getAttribute('data-mode') | 51 | const mode = context.getAttribute('data-mode') |
| @@ -55,9 +53,7 @@ const toggleEditing = () => { | |||
| 55 | } | 53 | } |
| 56 | // }}} | 54 | // }}} |
| 57 | // Set up EasyMDE {{{ | 55 | // Set up EasyMDE {{{ |
| 58 | 56 | /** Contents for tutorial **/ | |
| 59 | // Content values for editor | ||
| 60 | |||
| 61 | const defaultContent = | 57 | const defaultContent = |
| 62 | `<br> | 58 | `<br> |
| 63 | 59 | ||
| @@ -105,12 +101,13 @@ If you want know more, take a look at subjects below: | |||
| 105 | [Editor]: #This%20is%20editor! "=>.editor" | 101 | [Editor]: #This%20is%20editor! "=>.editor" |
| 106 | [subject]: placeholder` | 102 | [subject]: placeholder` |
| 107 | 103 | ||
| 104 | /** Editor from EasyMDE **/ | ||
| 108 | const editor = new EasyMDE({ | 105 | const editor = new EasyMDE({ |
| 109 | element: textArea, | 106 | element: textArea, |
| 110 | initialValue: defaultContent, | 107 | initialValue: defaultContent, |
| 111 | autosave: { | 108 | autosave: { |
| 112 | enabled: true, | 109 | enabled: true, |
| 113 | uniqueId: 'dumbymap' | 110 | uniqueId: 'dumbymap', |
| 114 | }, | 111 | }, |
| 115 | indentWithTabs: false, | 112 | indentWithTabs: false, |
| 116 | lineNumbers: true, | 113 | lineNumbers: true, |
| @@ -123,21 +120,21 @@ const editor = new EasyMDE({ | |||
| 123 | map: 'Ctrl-Alt-M', | 120 | map: 'Ctrl-Alt-M', |
| 124 | debug: 'Ctrl-Alt-D', | 121 | debug: 'Ctrl-Alt-D', |
| 125 | toggleUnorderedList: null, | 122 | toggleUnorderedList: null, |
| 126 | toggleOrderedList: null | 123 | toggleOrderedList: null, |
| 127 | }, | 124 | }, |
| 128 | toolbar: [ | 125 | toolbar: [ |
| 129 | { | 126 | { |
| 130 | name: 'roll', | 127 | name: 'roll', |
| 131 | title: 'Roll a Dice', | 128 | title: 'Roll a Dice', |
| 132 | text: '\u{2684}', | 129 | text: '\u{2684}', |
| 133 | action: () => addMapRandomlyByPreset() | 130 | action: () => addMapRandomlyByPreset(), |
| 134 | }, | 131 | }, |
| 135 | { | 132 | { |
| 136 | name: 'export', | 133 | name: 'export', |
| 137 | title: 'Export current page', | 134 | title: 'Export current page', |
| 138 | text: '\u{1F4BE}', | 135 | text: '\u{1F4BE}', |
| 139 | action: () => { | 136 | action: () => { |
| 140 | } | 137 | }, |
| 141 | }, | 138 | }, |
| 142 | { | 139 | { |
| 143 | name: 'hash', | 140 | name: 'hash', |
| @@ -150,59 +147,59 @@ const editor = new EasyMDE({ | |||
| 150 | window.location.search = '' | 147 | window.location.search = '' |
| 151 | navigator.clipboard.writeText(window.location.href) | 148 | navigator.clipboard.writeText(window.location.href) |
| 152 | window.alert('URL updated in address bar, you can save current page as bookmark') | 149 | window.alert('URL updated in address bar, you can save current page as bookmark') |
| 153 | } | 150 | }, |
| 154 | }, | 151 | }, |
| 155 | '|', | 152 | '|', |
| 156 | { | 153 | { |
| 157 | name: 'undo', | 154 | name: 'undo', |
| 158 | title: 'Undo last editing', | 155 | title: 'Undo last editing', |
| 159 | text: '\u27F2', | 156 | text: '\u27F2', |
| 160 | action: EasyMDE.undo | 157 | action: EasyMDE.undo, |
| 161 | }, | 158 | }, |
| 162 | { | 159 | { |
| 163 | name: 'redo', | 160 | name: 'redo', |
| 164 | text: '\u27F3', | 161 | text: '\u27F3', |
| 165 | title: 'Redo editing', | 162 | title: 'Redo editing', |
| 166 | action: EasyMDE.redo | 163 | action: EasyMDE.redo, |
| 167 | }, | 164 | }, |
| 168 | '|', | 165 | '|', |
| 169 | { | 166 | { |
| 170 | name: 'heading-1', | 167 | name: 'heading-1', |
| 171 | text: 'H1', | 168 | text: 'H1', |
| 172 | title: 'Big Heading', | 169 | title: 'Big Heading', |
| 173 | action: EasyMDE['heading-1'] | 170 | action: EasyMDE['heading-1'], |
| 174 | }, | 171 | }, |
| 175 | { | 172 | { |
| 176 | name: 'heading-2', | 173 | name: 'heading-2', |
| 177 | text: 'H2', | 174 | text: 'H2', |
| 178 | title: 'Medium Heading', | 175 | title: 'Medium Heading', |
| 179 | action: EasyMDE['heading-2'] | 176 | action: EasyMDE['heading-2'], |
| 180 | }, | 177 | }, |
| 181 | '|', | 178 | '|', |
| 182 | { | 179 | { |
| 183 | name: 'link', | 180 | name: 'link', |
| 184 | text: '\u{1F517}', | 181 | text: '\u{1F517}', |
| 185 | title: 'Create Link', | 182 | title: 'Create Link', |
| 186 | action: EasyMDE.drawLink | 183 | action: EasyMDE.drawLink, |
| 187 | }, | 184 | }, |
| 188 | { | 185 | { |
| 189 | name: 'image', | 186 | name: 'image', |
| 190 | text: '\u{1F5BC}', | 187 | text: '\u{1F5BC}', |
| 191 | title: 'Create Image', | 188 | title: 'Create Image', |
| 192 | action: EasyMDE.drawImage | 189 | action: EasyMDE.drawImage, |
| 193 | }, | 190 | }, |
| 194 | '|', | 191 | '|', |
| 195 | { | 192 | { |
| 196 | name: 'Bold', | 193 | name: 'Bold', |
| 197 | text: '\u{1D401}', | 194 | text: '\u{1D401}', |
| 198 | title: 'Bold', | 195 | title: 'Bold', |
| 199 | action: EasyMDE.toggleBold | 196 | action: EasyMDE.toggleBold, |
| 200 | }, | 197 | }, |
| 201 | { | 198 | { |
| 202 | name: 'Italic', | 199 | name: 'Italic', |
| 203 | text: '\u{1D43C}', | 200 | text: '\u{1D43C}', |
| 204 | title: 'Italic', | 201 | title: 'Italic', |
| 205 | action: EasyMDE.toggleItalic | 202 | action: EasyMDE.toggleItalic, |
| 206 | }, | 203 | }, |
| 207 | '|', | 204 | '|', |
| 208 | { | 205 | { |
| @@ -213,13 +210,14 @@ const editor = new EasyMDE({ | |||
| 213 | editor.value(defaultContent) | 210 | editor.value(defaultContent) |
| 214 | refLinks = getRefLinks() | 211 | refLinks = getRefLinks() |
| 215 | updateDumbyMap() | 212 | updateDumbyMap() |
| 216 | } | 213 | }, |
| 217 | } | 214 | }, |
| 218 | ] | 215 | ], |
| 219 | }) | 216 | }) |
| 220 | 217 | /** CodeMirror Instance **/ | |
| 221 | const cm = editor.codemirror | 218 | const cm = editor.codemirror |
| 222 | 219 | ||
| 220 | /** Ref Links **/ | ||
| 223 | const getRefLinks = () => editor.value() | 221 | const getRefLinks = () => editor.value() |
| 224 | .split('\n') | 222 | .split('\n') |
| 225 | .map(line => { | 223 | .map(line => { |
| @@ -244,7 +242,6 @@ const getStateFromHash = hash => { | |||
| 244 | return {} | 242 | return {} |
| 245 | } | 243 | } |
| 246 | } | 244 | } |
| 247 | |||
| 248 | /** | 245 | /** |
| 249 | * get editor content from hash string | 246 | * get editor content from hash string |
| 250 | * | 247 | * |
| @@ -254,7 +251,9 @@ const getContentFromHash = hash => { | |||
| 254 | const state = getStateFromHash(hash) | 251 | const state = getStateFromHash(hash) |
| 255 | return state.content | 252 | return state.content |
| 256 | } | 253 | } |
| 254 | /** Hash and Query Parameters in URL **/ | ||
| 257 | const contentFromHash = getContentFromHash(window.location.hash) | 255 | const contentFromHash = getContentFromHash(window.location.hash) |
| 256 | window.location.hash = '' | ||
| 258 | 257 | ||
| 259 | if (url.searchParams.get('content') === 'tutorial') { | 258 | if (url.searchParams.get('content') === 'tutorial') { |
| 260 | editor.value(defaultContent) | 259 | editor.value(defaultContent) |
| @@ -263,12 +262,10 @@ if (url.searchParams.get('content') === 'tutorial') { | |||
| 263 | editor.cleanup() | 262 | editor.cleanup() |
| 264 | editor.value(contentFromHash) | 263 | editor.value(contentFromHash) |
| 265 | } | 264 | } |
| 266 | |||
| 267 | window.location.hash = '' | ||
| 268 | |||
| 269 | // }}} | 265 | // }}} |
| 270 | // Set up logic about editor content {{{ | 266 | // Set up logic about editor content {{{ |
| 271 | 267 | ||
| 268 | /** Sync scroll from HTML to CodeMirror **/ | ||
| 272 | const htmlOnScroll = (ele) => () => { | 269 | const htmlOnScroll = (ele) => () => { |
| 273 | if (textArea.dataset.scrollLine) return | 270 | if (textArea.dataset.scrollLine) return |
| 274 | 271 | ||
| @@ -288,12 +285,11 @@ const htmlOnScroll = (ele) => () => { | |||
| 288 | } | 285 | } |
| 289 | } | 286 | } |
| 290 | 287 | ||
| 291 | // Sync CodeMirror LineNumber with HTML Contents | ||
| 292 | new window.MutationObserver(() => { | 288 | new window.MutationObserver(() => { |
| 293 | clearTimeout(dumbyContainer.timer) | 289 | clearTimeout(dumbyContainer.timer) |
| 294 | dumbyContainer.timer = setTimeout( | 290 | dumbyContainer.timer = setTimeout( |
| 295 | () => delete dumbyContainer.dataset.scrollLine, | 291 | () => delete dumbyContainer.dataset.scrollLine, |
| 296 | 50 | 292 | 50, |
| 297 | ) | 293 | ) |
| 298 | 294 | ||
| 299 | const line = dumbyContainer.dataset.scrollLine | 295 | const line = dumbyContainer.dataset.scrollLine |
| @@ -306,7 +302,7 @@ new window.MutationObserver(() => { | |||
| 306 | } | 302 | } |
| 307 | }).observe(dumbyContainer, { | 303 | }).observe(dumbyContainer, { |
| 308 | attributes: true, | 304 | attributes: true, |
| 309 | attributeFilter: ['data-scroll-line'] | 305 | attributeFilter: ['data-scroll-line'], |
| 310 | }) | 306 | }) |
| 311 | 307 | ||
| 312 | const setScrollLine = () => { | 308 | const setScrollLine = () => { |
| @@ -318,12 +314,12 @@ const setScrollLine = () => { | |||
| 318 | } | 314 | } |
| 319 | cm.on('scroll', setScrollLine) | 315 | cm.on('scroll', setScrollLine) |
| 320 | 316 | ||
| 321 | // Sync HTML Contents with CodeMirror LineNumber | 317 | /** Sync scroll from CodeMirror to HTML **/ |
| 322 | new window.MutationObserver(() => { | 318 | new window.MutationObserver(() => { |
| 323 | clearTimeout(textArea.timer) | 319 | clearTimeout(textArea.timer) |
| 324 | textArea.timer = setTimeout( | 320 | textArea.timer = setTimeout( |
| 325 | () => delete textArea.dataset.scrollLine, | 321 | () => delete textArea.dataset.scrollLine, |
| 326 | 1000 | 322 | 1000, |
| 327 | ) | 323 | ) |
| 328 | 324 | ||
| 329 | const line = textArea.dataset.scrollLine | 325 | const line = textArea.dataset.scrollLine |
| @@ -345,11 +341,9 @@ new window.MutationObserver(() => { | |||
| 345 | dumbymap.htmlHolder.scrollBy(0, top - coords.top + 30) | 341 | dumbymap.htmlHolder.scrollBy(0, top - coords.top + 30) |
| 346 | }).observe(textArea, { | 342 | }).observe(textArea, { |
| 347 | attributes: true, | 343 | attributes: true, |
| 348 | attributeFilter: ['data-scroll-line'] | 344 | attributeFilter: ['data-scroll-line'], |
| 349 | }) | 345 | }) |
| 350 | 346 | ||
| 351 | markdown2HTML(dumbyContainer, editor.value()) | ||
| 352 | |||
| 353 | /** | 347 | /** |
| 354 | * addClassToCodeLines. Quick hack to style lines inside code block | 348 | * addClassToCodeLines. Quick hack to style lines inside code block |
| 355 | */ | 349 | */ |
| @@ -444,7 +438,7 @@ const menuForEditor = (event, menu) => { | |||
| 444 | if (context.dataset.mode !== 'editing') { | 438 | if (context.dataset.mode !== 'editing') { |
| 445 | const switchToEditingMode = new menuItem.Item({ | 439 | const switchToEditingMode = new menuItem.Item({ |
| 446 | innerHTML: '<strong>EDIT</strong>', | 440 | innerHTML: '<strong>EDIT</strong>', |
| 447 | onclick: () => (context.dataset.mode = 'editing') | 441 | onclick: () => (context.dataset.mode = 'editing'), |
| 448 | }) | 442 | }) |
| 449 | menu.appendChild(switchToEditingMode) | 443 | menu.appendChild(switchToEditingMode) |
| 450 | } | 444 | } |
| @@ -456,7 +450,7 @@ const menuForEditor = (event, menu) => { | |||
| 456 | onclick: (event) => { | 450 | onclick: (event) => { |
| 457 | const { ref, link } = addAnchorByPoint({ point: event, map, validateAnchorName }) | 451 | const { ref, link } = addAnchorByPoint({ point: event, map, validateAnchorName }) |
| 458 | appendRefLink({ cm, ref, link }) | 452 | appendRefLink({ cm, ref, link }) |
| 459 | } | 453 | }, |
| 460 | }) | 454 | }) |
| 461 | menu.insertBefore(item, menu.firstChild) | 455 | menu.insertBefore(item, menu.firstChild) |
| 462 | } | 456 | } |
| @@ -468,7 +462,7 @@ const menuForEditor = (event, menu) => { | |||
| 468 | const updateDumbyMap = () => { | 462 | const updateDumbyMap = () => { |
| 469 | markdown2HTML(dumbyContainer, editor.value()) | 463 | markdown2HTML(dumbyContainer, editor.value()) |
| 470 | // debounceForMap(dumbyContainer, afterMapRendered) | 464 | // debounceForMap(dumbyContainer, afterMapRendered) |
| 471 | dumbymap = generateMaps(dumbyContainer, { renderCallback }) | 465 | dumbymap = generateMaps(dumbyContainer, {}) |
| 472 | // Set onscroll callback | 466 | // Set onscroll callback |
| 473 | const htmlHolder = dumbymap.htmlHolder | 467 | const htmlHolder = dumbymap.htmlHolder |
| 474 | htmlHolder.onscroll = htmlOnScroll(htmlHolder) | 468 | htmlHolder.onscroll = htmlOnScroll(htmlHolder) |
| @@ -521,7 +515,7 @@ new window.MutationObserver(() => { | |||
| 521 | } | 515 | } |
| 522 | }).observe(menu, { | 516 | }).observe(menu, { |
| 523 | attributes: true, | 517 | attributes: true, |
| 524 | attributeFilter: ['style'] | 518 | attributeFilter: ['style'], |
| 525 | }) | 519 | }) |
| 526 | document.body.append(menu) | 520 | document.body.append(menu) |
| 527 | 521 | ||
| @@ -613,7 +607,7 @@ const getSuggestionsForOptions = (optionTyped, validOptions) => { | |||
| 613 | let suggestOptions = [] | 607 | let suggestOptions = [] |
| 614 | 608 | ||
| 615 | const matchedOptions = validOptions.filter(o => | 609 | const matchedOptions = validOptions.filter(o => |
| 616 | o.valueOf().toLowerCase().includes(optionTyped.toLowerCase()) | 610 | o.valueOf().toLowerCase().includes(optionTyped.toLowerCase()), |
| 617 | ) | 611 | ) |
| 618 | 612 | ||
| 619 | if (matchedOptions.length > 0) { | 613 | if (matchedOptions.length > 0) { |
| @@ -627,8 +621,8 @@ const getSuggestionsForOptions = (optionTyped, validOptions) => { | |||
| 627 | new menuItem.Suggestion({ | 621 | new menuItem.Suggestion({ |
| 628 | text: `<span>${o.valueOf()}</span><span class='info' title="${o.desc ?? ''}">ⓘ</span>`, | 622 | text: `<span>${o.valueOf()}</span><span class='info' title="${o.desc ?? ''}">ⓘ</span>`, |
| 629 | replace: `${o.valueOf()}: `, | 623 | replace: `${o.valueOf()}: `, |
| 630 | cm | 624 | cm, |
| 631 | }) | 625 | }), |
| 632 | ) | 626 | ) |
| 633 | } | 627 | } |
| 634 | // }}} | 628 | // }}} |
| @@ -647,7 +641,7 @@ const getSuggestionFromMapOption = option => { | |||
| 647 | return new menuItem.Suggestion({ | 641 | return new menuItem.Suggestion({ |
| 648 | text, | 642 | text, |
| 649 | replace: `${option.valueOf()}: ${option.example ?? ''}`, | 643 | replace: `${option.valueOf()}: ${option.example ?? ''}`, |
| 650 | cm | 644 | cm, |
| 651 | }) | 645 | }) |
| 652 | } | 646 | } |
| 653 | // }}} | 647 | // }}} |
| @@ -663,7 +657,7 @@ const getSuggestionsFromAliases = option => | |||
| 663 | return new menuItem.Suggestion({ | 657 | return new menuItem.Suggestion({ |
| 664 | text: `<span>${alias}</span><span class="truncate" style="color: gray">${valueString}</span>`, | 658 | text: `<span>${alias}</span><span class="truncate" style="color: gray">${valueString}</span>`, |
| 665 | replace: `${option.valueOf()}: ${valueString}`, | 659 | replace: `${option.valueOf()}: ${valueString}`, |
| 666 | cm | 660 | cm, |
| 667 | }) | 661 | }) |
| 668 | }) ?? [] | 662 | }) ?? [] |
| 669 | // }}} | 663 | // }}} |
| @@ -694,7 +688,7 @@ const getSuggestions = anchor => { | |||
| 694 | 688 | ||
| 695 | // Clear marks on text | 689 | // Clear marks on text |
| 696 | cm.findMarks({ ...anchor, ch: 0 }, { ...anchor, ch: text.length }).forEach( | 690 | cm.findMarks({ ...anchor, ch: 0 }, { ...anchor, ch: text.length }).forEach( |
| 697 | m => m.clear() | 691 | m => m.clear(), |
| 698 | ) | 692 | ) |
| 699 | 693 | ||
| 700 | // Mark user input invalid by case | 694 | // Mark user input invalid by case |
| @@ -704,7 +698,7 @@ const getSuggestions = anchor => { | |||
| 704 | .markText( | 698 | .markText( |
| 705 | { ...anchor, ch: 0 }, | 699 | { ...anchor, ch: 0 }, |
| 706 | { ...anchor, ch: text.length }, | 700 | { ...anchor, ch: text.length }, |
| 707 | { className: 'invalid-input' } | 701 | { className: 'invalid-input' }, |
| 708 | ) | 702 | ) |
| 709 | 703 | ||
| 710 | // Check if "use: <renderer>" is set | 704 | // Check if "use: <renderer>" is set |
| @@ -732,7 +726,7 @@ const getSuggestions = anchor => { | |||
| 732 | .catch(_ => { | 726 | .catch(_ => { |
| 733 | markInputIsInvalid(lineWithRenderer) | 727 | markInputIsInvalid(lineWithRenderer) |
| 734 | console.warn( | 728 | console.warn( |
| 735 | `Fail to get valid options from Renderer typed: ${renderer}` | 729 | `Fail to get valid options from Renderer typed: ${renderer}`, |
| 736 | ) | 730 | ) |
| 737 | }) | 731 | }) |
| 738 | return [] | 732 | return [] |
| @@ -765,7 +759,7 @@ const getSuggestions = anchor => { | |||
| 765 | if (!valueTyped) { | 759 | if (!valueTyped) { |
| 766 | return [ | 760 | return [ |
| 767 | getSuggestionFromMapOption(matchedOption), | 761 | getSuggestionFromMapOption(matchedOption), |
| 768 | ...getSuggestionsFromAliases(matchedOption) | 762 | ...getSuggestionsFromAliases(matchedOption), |
| 769 | ].filter(s => s instanceof menuItem.Suggestion) | 763 | ].filter(s => s instanceof menuItem.Suggestion) |
| 770 | } | 764 | } |
| 771 | if (valueTyped && !isValidValue) { | 765 | if (valueTyped && !isValidValue) { |
| @@ -787,19 +781,19 @@ const getSuggestions = anchor => { | |||
| 787 | new menuItem.Suggestion({ | 781 | new menuItem.Suggestion({ |
| 788 | text: `<span>use: ${renderer}</span><span class='info' title="${info.desc}">ⓘ</span>`, | 782 | text: `<span>use: ${renderer}</span><span class='info' title="${info.desc}">ⓘ</span>`, |
| 789 | replace: `use: ${renderer}`, | 783 | replace: `use: ${renderer}`, |
| 790 | cm | 784 | cm, |
| 791 | }) | 785 | }), |
| 792 | ) | 786 | ) |
| 793 | return rendererSuggestions.length === 0 | 787 | return rendererSuggestions.length === 0 |
| 794 | ? [] | 788 | ? [] |
| 795 | : [ | 789 | : [ |
| 796 | ...rendererSuggestions, | 790 | ...rendererSuggestions, |
| 797 | new menuItem.Item({ | 791 | new menuItem.Item({ |
| 798 | innerHTML: '<a href="https://github.com/outdoorsafetylab/mapclay#renderer" class="external" style="display: block;">More...</a>', | 792 | innerHTML: '<a href="https://github.com/outdoorsafetylab/mapclay#renderer" class="external" style="display: block;">More...</a>', |
| 799 | className: ['suggestion'], | 793 | className: ['suggestion'], |
| 800 | onclick: () => window.open('https://github.com/outdoorsafetylab/mapclay#renderer', '_blank') | 794 | onclick: () => window.open('https://github.com/outdoorsafetylab/mapclay#renderer', '_blank'), |
| 801 | }) | 795 | }), |
| 802 | ] | 796 | ] |
| 803 | } | 797 | } |
| 804 | return [] | 798 | return [] |
| 805 | } | 799 | } |
| @@ -943,7 +937,7 @@ new window.MutationObserver(mutaions => { | |||
| 943 | }).observe(dumbyContainer, { | 937 | }).observe(dumbyContainer, { |
| 944 | attributes: true, | 938 | attributes: true, |
| 945 | attributeFilter: ['data-layout'], | 939 | attributeFilter: ['data-layout'], |
| 946 | attributeOldValue: true | 940 | attributeOldValue: true, |
| 947 | }) | 941 | }) |
| 948 | // }}} | 942 | // }}} |
| 949 | 943 | ||
| @@ -954,7 +948,7 @@ const addMapRandomlyByPreset = () => { | |||
| 954 | const yamlText = [ | 948 | const yamlText = [ |
| 955 | 'apply: dist/default.yml', | 949 | 'apply: dist/default.yml', |
| 956 | 'width: 85%', | 950 | 'width: 85%', |
| 957 | 'height: 200px' | 951 | 'height: 200px', |
| 958 | ] | 952 | ] |
| 959 | const order = [ | 953 | const order = [ |
| 960 | 'id', | 954 | 'id', |
| @@ -964,12 +958,12 @@ const addMapRandomlyByPreset = () => { | |||
| 964 | 'height', | 958 | 'height', |
| 965 | 'center', | 959 | 'center', |
| 966 | 'XYZ', | 960 | 'XYZ', |
| 967 | 'zoom' | 961 | 'zoom', |
| 968 | ] | 962 | ] |
| 969 | const aliasesEntries = Object.entries(aliasesForMapOptions) | 963 | const aliasesEntries = Object.entries(aliasesForMapOptions) |
| 970 | .filter(([key, _]) => | 964 | .filter(([key, _]) => |
| 971 | order.includes(key) && | 965 | order.includes(key) && |
| 972 | !yamlText.find(text => text.startsWith(key)) | 966 | !yamlText.find(text => text.startsWith(key)), |
| 973 | ) | 967 | ) |
| 974 | if (aliasesEntries.length === 0) return | 968 | if (aliasesEntries.length === 0) return |
| 975 | 969 | ||
| @@ -997,12 +991,12 @@ const addMapRandomlyByPreset = () => { | |||
| 997 | }) | 991 | }) |
| 998 | 992 | ||
| 999 | yamlText.sort((a, b) => | 993 | yamlText.sort((a, b) => |
| 1000 | order.indexOf(a.split(':')[0]) > order.indexOf(b.split(':')[0]) | 994 | order.indexOf(a.split(':')[0]) > order.indexOf(b.split(':')[0]), |
| 1001 | ) | 995 | ) |
| 1002 | const anchor = cm.getCursor() | 996 | const anchor = cm.getCursor() |
| 1003 | cm.replaceRange( | 997 | cm.replaceRange( |
| 1004 | '\n```map\n' + yamlText.join('\n') + '\n```\n', | 998 | '\n```map\n' + yamlText.join('\n') + '\n```\n', |
| 1005 | anchor | 999 | anchor, |
| 1006 | ) | 1000 | ) |
| 1007 | } | 1001 | } |
| 1008 | 1002 | ||
| @@ -1068,6 +1062,7 @@ document.addEventListener('selectionchange', () => { | |||
| 1068 | } | 1062 | } |
| 1069 | }) | 1063 | }) |
| 1070 | 1064 | ||
| 1065 | /** Drag/Drop on map for new reference style link */ | ||
| 1071 | dumbyContainer.onmousedown = (e) => { | 1066 | dumbyContainer.onmousedown = (e) => { |
| 1072 | // Check should start drag event for GeoLink | 1067 | // Check should start drag event for GeoLink |
| 1073 | const selection = document.getSelection() | 1068 | const selection = document.getSelection() |
| @@ -1087,14 +1082,13 @@ dumbyContainer.onmousedown = (e) => { | |||
| 1087 | lineEnd.style.cssText = `position: absolute; left: ${e.clientX}px; top: ${e.clientY}px;` | 1082 | lineEnd.style.cssText = `position: absolute; left: ${e.clientX}px; top: ${e.clientY}px;` |
| 1088 | document.body.appendChild(lineEnd) | 1083 | document.body.appendChild(lineEnd) |
| 1089 | 1084 | ||
| 1090 | menu.style.display = 'block' | ||
| 1091 | const line = new LeaderLine({ | 1085 | const line = new LeaderLine({ |
| 1092 | start: geoLink, | 1086 | start: geoLink, |
| 1093 | end: lineEnd, | 1087 | end: lineEnd, |
| 1094 | path: 'magnet' | 1088 | path: 'magnet', |
| 1095 | }) | 1089 | }) |
| 1096 | 1090 | ||
| 1097 | function onMouseMove(event) { | 1091 | function onMouseMove (event) { |
| 1098 | lineEnd.style.left = event.clientX + 'px' | 1092 | lineEnd.style.left = event.clientX + 'px' |
| 1099 | lineEnd.style.top = event.clientY + 'px' | 1093 | lineEnd.style.top = event.clientY + 'px' |
| 1100 | line.position() | 1094 | line.position() |
| @@ -1102,7 +1096,7 @@ dumbyContainer.onmousedown = (e) => { | |||
| 1102 | } | 1096 | } |
| 1103 | 1097 | ||
| 1104 | dumbyContainer.onmousemove = onMouseMove | 1098 | dumbyContainer.onmousemove = onMouseMove |
| 1105 | dumbyContainer.onmouseup = function(e) { | 1099 | dumbyContainer.onmouseup = function (e) { |
| 1106 | dumbyContainer.onmousemove = null | 1100 | dumbyContainer.onmousemove = null |
| 1107 | dumbyContainer.onmouseup = null | 1101 | dumbyContainer.onmouseup = null |
| 1108 | line?.remove() | 1102 | line?.remove() |
| @@ -1122,16 +1116,14 @@ dumbyContainer.onmousedown = (e) => { | |||
| 1122 | return | 1116 | return |
| 1123 | } | 1117 | } |
| 1124 | 1118 | ||
| 1125 | const {ref, link} = refLink | 1119 | const { ref, link } = refLink |
| 1126 | appendRefLink({ cm, ref, link }) | 1120 | appendRefLink({ cm, ref, link }) |
| 1127 | if (selection === ref) { | 1121 | if (selection === ref) { |
| 1128 | cm.replaceSelection(`[${selection}]`) | 1122 | cm.replaceSelection(`[${selection}]`) |
| 1129 | } else { | 1123 | } else { |
| 1130 | cm.replaceSelection(`[${selection}][${ref}]`) | 1124 | cm.replaceSelection(`[${selection}][${ref}]`) |
| 1131 | } | 1125 | } |
| 1132 | }; | 1126 | } |
| 1133 | } | 1127 | } |
| 1134 | 1128 | ||
| 1135 | dumbyContainer.ondragstart = () => false | 1129 | dumbyContainer.ondragstart = () => false |
| 1136 | |||
| 1137 | // vim: sw=2 ts=2 foldmethod=marker foldmarker={{{,}}} | ||
diff --git a/src/utils.mjs b/src/utils.mjs index dba023a..d408b3d 100644 --- a/src/utils.mjs +++ b/src/utils.mjs | |||
| @@ -39,7 +39,7 @@ export const animateRectTransition = (element, rect, options = {}) => { | |||
| 39 | width: w2, | 39 | width: w2, |
| 40 | height: h2, | 40 | height: h2, |
| 41 | left: x2, | 41 | left: x2, |
| 42 | top: y2 | 42 | top: y2, |
| 43 | } = element.getBoundingClientRect() | 43 | } = element.getBoundingClientRect() |
| 44 | 44 | ||
| 45 | const rw = (w1 ?? w2) / w2 | 45 | const rw = (w1 ?? w2) / w2 |
| @@ -55,13 +55,13 @@ export const animateRectTransition = (element, rect, options = {}) => { | |||
| 55 | const transform2 = `translate(${dx}px, ${dy}px) scale(${rw}, ${rh})` | 55 | const transform2 = `translate(${dx}px, ${dy}px) scale(${rw}, ${rh})` |
| 56 | const keyframes = [ | 56 | const keyframes = [ |
| 57 | { transform: transform1, opacity: 1 }, | 57 | { transform: transform1, opacity: 1 }, |
| 58 | { transform: transform2, opacity: 0.3 } | 58 | { transform: transform2, opacity: 0.3 }, |
| 59 | ] | 59 | ] |
| 60 | if (options.resume === true) keyframes.reverse() | 60 | if (options.resume === true) keyframes.reverse() |
| 61 | 61 | ||
| 62 | return element.animate(keyframes, { | 62 | return element.animate(keyframes, { |
| 63 | duration: options.duration ?? 500, | 63 | duration: options.duration ?? 500, |
| 64 | easing: 'ease-in-out' | 64 | easing: 'ease-in-out', |
| 65 | }) | 65 | }) |
| 66 | } | 66 | } |
| 67 | 67 | ||
| @@ -81,7 +81,7 @@ export function throttle (func, delay) { | |||
| 81 | 81 | ||
| 82 | timerFlag = setTimeout( | 82 | timerFlag = setTimeout( |
| 83 | () => (timerFlag = null), | 83 | () => (timerFlag = null), |
| 84 | typeof delay === 'function' ? delay.call(context) : delay | 84 | typeof delay === 'function' ? delay.call(context) : delay, |
| 85 | ) | 85 | ) |
| 86 | 86 | ||
| 87 | return func.call(context, ...args) | 87 | return func.call(context, ...args) |