diff options
| author | Hsieh Chin Fan <pham@topo.tw> | 2024-10-04 13:38:08 +0800 |
|---|---|---|
| committer | Hsieh Chin Fan <pham@topo.tw> | 2024-10-04 15:11:28 +0800 |
| commit | dbd3b03ec842c446488135853ed380f5a75adb27 (patch) | |
| tree | 00fa406566361a308808add3cdc445ed892e81ec /src | |
| parent | ec23491d3a39f9f9201449f14a536b7540a8c281 (diff) | |
docs: add jsdoc
Diffstat (limited to 'src')
| -rw-r--r-- | src/Layout.mjs | 57 | ||||
| -rw-r--r-- | src/MenuItem.mjs | 77 | ||||
| -rw-r--r-- | src/dumbyUtils.mjs | 28 | ||||
| -rw-r--r-- | src/dumbymap.mjs | 19 | ||||
| -rw-r--r-- | src/editor.mjs | 83 | ||||
| -rw-r--r-- | src/utils.mjs | 5 |
6 files changed, 255 insertions, 14 deletions
diff --git a/src/Layout.mjs b/src/Layout.mjs index 3c4ea3d..6bb6282 100644 --- a/src/Layout.mjs +++ b/src/Layout.mjs | |||
| @@ -1,7 +1,15 @@ | |||
| 1 | import PlainDraggable from 'plain-draggable' | 1 | import PlainDraggable from 'plain-draggable' |
| 2 | import { onRemove, animateRectTransition } from './utils' | 2 | import { onRemove, animateRectTransition } from './utils' |
| 3 | 3 | ||
| 4 | /** | ||
| 5 | * Layout. Basic class for layout | ||
| 6 | */ | ||
| 4 | export class Layout { | 7 | export class Layout { |
| 8 | /** | ||
| 9 | * constructor. | ||
| 10 | * | ||
| 11 | * @param {} options | ||
| 12 | */ | ||
| 5 | constructor (options = {}) { | 13 | constructor (options = {}) { |
| 6 | if (!options.name) throw Error('Layout name is not given') | 14 | if (!options.name) throw Error('Layout name is not given') |
| 7 | this.name = options.name | 15 | this.name = options.name |
| @@ -9,12 +17,28 @@ export class Layout { | |||
| 9 | this.leaveHandler = options.leaveHandler | 17 | this.leaveHandler = options.leaveHandler |
| 10 | } | 18 | } |
| 11 | 19 | ||
| 20 | /** | ||
| 21 | * valueOf. | ||
| 22 | */ | ||
| 12 | valueOf = () => this.name | 23 | valueOf = () => this.name |
| 13 | } | 24 | } |
| 14 | 25 | ||
| 26 | /** | ||
| 27 | * Side-By-Side Layout, HTML content and Showcase show on left/right side | ||
| 28 | * | ||
| 29 | * @extends {Layout} | ||
| 30 | */ | ||
| 15 | export class SideBySide extends Layout { | 31 | export class SideBySide extends Layout { |
| 32 | /** | ||
| 33 | * @type {} | ||
| 34 | */ | ||
| 16 | name = 'side-by-side' | 35 | name = 'side-by-side' |
| 17 | 36 | ||
| 37 | /** | ||
| 38 | * enterHandler. | ||
| 39 | * | ||
| 40 | * @param {} | ||
| 41 | */ | ||
| 18 | enterHandler = ({ container, htmlHolder, showcase }) => { | 42 | enterHandler = ({ container, htmlHolder, showcase }) => { |
| 19 | const bar = document.createElement('div') | 43 | const bar = document.createElement('div') |
| 20 | bar.className = 'bar' | 44 | bar.className = 'bar' |
| @@ -46,20 +70,43 @@ export class SideBySide extends Layout { | |||
| 46 | onRemove(bar, () => draggable.remove()) | 70 | onRemove(bar, () => draggable.remove()) |
| 47 | } | 71 | } |
| 48 | 72 | ||
| 73 | /** | ||
| 74 | * leaveHandler. | ||
| 75 | * | ||
| 76 | * @param {} | ||
| 77 | */ | ||
| 49 | leaveHandler = ({ container }) => { | 78 | leaveHandler = ({ container }) => { |
| 50 | container.querySelector('.bar')?.remove() | 79 | container.querySelector('.bar')?.remove() |
| 51 | } | 80 | } |
| 52 | } | 81 | } |
| 53 | 82 | ||
| 83 | /** | ||
| 84 | * Overlay Layout, Showcase occupies viewport, and HTML content becomes draggable blocks | ||
| 85 | * | ||
| 86 | * @extends {Layout} | ||
| 87 | */ | ||
| 54 | export class Overlay extends Layout { | 88 | export class Overlay extends Layout { |
| 89 | /** | ||
| 90 | * @type {} | ||
| 91 | */ | ||
| 55 | name = 'overlay' | 92 | name = 'overlay' |
| 56 | 93 | ||
| 94 | /** | ||
| 95 | * saveLeftTopAsData. | ||
| 96 | * | ||
| 97 | * @param {} element | ||
| 98 | */ | ||
| 57 | saveLeftTopAsData = element => { | 99 | saveLeftTopAsData = element => { |
| 58 | const { left, top } = element.getBoundingClientRect() | 100 | const { left, top } = element.getBoundingClientRect() |
| 59 | element.setAttribute('data-left', left) | 101 | element.setAttribute('data-left', left) |
| 60 | element.setAttribute('data-top', top) | 102 | element.setAttribute('data-top', top) |
| 61 | } | 103 | } |
| 62 | 104 | ||
| 105 | /** | ||
| 106 | * addDraggable. | ||
| 107 | * | ||
| 108 | * @param {} element | ||
| 109 | */ | ||
| 63 | addDraggable = element => { | 110 | addDraggable = element => { |
| 64 | // Make sure current element always on top | 111 | // Make sure current element always on top |
| 65 | const siblings = Array.from( | 112 | const siblings = Array.from( |
| @@ -119,6 +166,11 @@ export class Overlay extends Layout { | |||
| 119 | }) | 166 | }) |
| 120 | } | 167 | } |
| 121 | 168 | ||
| 169 | /** | ||
| 170 | * enterHandler. | ||
| 171 | * | ||
| 172 | * @param {} | ||
| 173 | */ | ||
| 122 | enterHandler = ({ htmlHolder, blocks }) => { | 174 | enterHandler = ({ htmlHolder, blocks }) => { |
| 123 | // FIXME It is weird rect from this method and this scope are different... | 175 | // FIXME It is weird rect from this method and this scope are different... |
| 124 | blocks.forEach(this.saveLeftTopAsData) | 176 | blocks.forEach(this.saveLeftTopAsData) |
| @@ -197,6 +249,11 @@ export class Overlay extends Layout { | |||
| 197 | }) | 249 | }) |
| 198 | } | 250 | } |
| 199 | 251 | ||
| 252 | /** | ||
| 253 | * leaveHandler. | ||
| 254 | * | ||
| 255 | * @param {} | ||
| 256 | */ | ||
| 200 | leaveHandler = ({ htmlHolder, blocks }) => { | 257 | leaveHandler = ({ htmlHolder, blocks }) => { |
| 201 | const resumeFromDraggable = block => { | 258 | const resumeFromDraggable = block => { |
| 202 | const draggableContainer = block.closest('.draggable-block') | 259 | const draggableContainer = block.closest('.draggable-block') |
diff --git a/src/MenuItem.mjs b/src/MenuItem.mjs index fe0bd99..864bc05 100644 --- a/src/MenuItem.mjs +++ b/src/MenuItem.mjs | |||
| @@ -1,6 +1,16 @@ | |||
| 1 | import { shiftByWindow } from './utils.mjs' | 1 | import { shiftByWindow } from './utils.mjs' |
| 2 | 2 | ||
| 3 | /** | ||
| 4 | * Item. Basic Element for menu item | ||
| 5 | * | ||
| 6 | * @extends {window.HTMLDivElement} | ||
| 7 | */ | ||
| 3 | export class Item extends window.HTMLDivElement { | 8 | export class Item extends window.HTMLDivElement { |
| 9 | /** | ||
| 10 | * constructor. | ||
| 11 | * | ||
| 12 | * @param {} | ||
| 13 | */ | ||
| 4 | constructor ({ text, innerHTML, onclick, style, className, onmouseover }) { | 14 | constructor ({ text, innerHTML, onclick, style, className, onmouseover }) { |
| 5 | super() | 15 | super() |
| 6 | this.innerHTML = innerHTML ?? text | 16 | this.innerHTML = innerHTML ?? text |
| @@ -18,7 +28,17 @@ export class Item extends window.HTMLDivElement { | |||
| 18 | } | 28 | } |
| 19 | window.customElements.define('menu-item', Item, { extends: 'div' }) | 29 | window.customElements.define('menu-item', Item, { extends: 'div' }) |
| 20 | 30 | ||
| 31 | /** | ||
| 32 | * Folder. Basic Element for menu item, it generate submenu on hover | ||
| 33 | * | ||
| 34 | * @extends {window.HTMLDivElement} | ||
| 35 | */ | ||
| 21 | export class Folder extends window.HTMLDivElement { | 36 | export class Folder extends window.HTMLDivElement { |
| 37 | /** | ||
| 38 | * constructor. | ||
| 39 | * | ||
| 40 | * @param {} | ||
| 41 | */ | ||
| 22 | constructor ({ text, innerHTML, items }) { | 42 | constructor ({ text, innerHTML, items }) { |
| 23 | super() | 43 | super() |
| 24 | this.innerHTML = innerHTML ?? text | 44 | this.innerHTML = innerHTML ?? text |
| @@ -44,6 +64,11 @@ export class Folder extends window.HTMLDivElement { | |||
| 44 | } | 64 | } |
| 45 | window.customElements.define('menu-folder', Folder, { extends: 'div' }) | 65 | window.customElements.define('menu-folder', Folder, { extends: 'div' }) |
| 46 | 66 | ||
| 67 | /** | ||
| 68 | * pickMapItem. | ||
| 69 | * | ||
| 70 | * @param {Function[]} options.utils | ||
| 71 | */ | ||
| 47 | export const pickMapItem = ({ utils }) => | 72 | export const pickMapItem = ({ utils }) => |
| 48 | new Folder({ | 73 | new Folder({ |
| 49 | innerHTML: '<span>Maps<span><span class="info">(Tab)</span>', | 74 | innerHTML: '<span>Maps<span><span class="info">(Tab)</span>', |
| @@ -59,6 +84,12 @@ export const pickMapItem = ({ utils }) => | |||
| 59 | ) | 84 | ) |
| 60 | }) | 85 | }) |
| 61 | 86 | ||
| 87 | /** | ||
| 88 | * pickBlockItem. | ||
| 89 | * | ||
| 90 | * @param {HTMLElement[]} options.blocks | ||
| 91 | * @param {Function[]} options.utils | ||
| 92 | */ | ||
| 62 | export const pickBlockItem = ({ blocks, utils }) => | 93 | export const pickBlockItem = ({ blocks, utils }) => |
| 63 | new Folder({ | 94 | new Folder({ |
| 64 | innerHTML: '<span>Blocks<span><span class="info">(n/p)</span>', | 95 | innerHTML: '<span>Blocks<span><span class="info">(n/p)</span>', |
| @@ -92,6 +123,12 @@ export const pickBlockItem = ({ blocks, utils }) => | |||
| 92 | ) | 123 | ) |
| 93 | }) | 124 | }) |
| 94 | 125 | ||
| 126 | /** | ||
| 127 | * pickLayoutItem. | ||
| 128 | * | ||
| 129 | * @param {HTEMElement} options.container | ||
| 130 | * @param {String[]} options.layouts | ||
| 131 | */ | ||
| 95 | export const pickLayoutItem = ({ container, layouts }) => | 132 | export const pickLayoutItem = ({ container, layouts }) => |
| 96 | new Folder({ | 133 | new Folder({ |
| 97 | innerHTML: '<span>Layouts<span><span class="info">(x)</span>', | 134 | innerHTML: '<span>Layouts<span><span class="info">(x)</span>', |
| @@ -115,6 +152,12 @@ export const pickLayoutItem = ({ container, layouts }) => | |||
| 115 | ] | 152 | ] |
| 116 | }) | 153 | }) |
| 117 | 154 | ||
| 155 | /** | ||
| 156 | * addGeoLink. | ||
| 157 | * | ||
| 158 | * @param {Function[]} options.utils | ||
| 159 | * @param {Range} range | ||
| 160 | */ | ||
| 118 | export const addGeoLink = ({ utils }, range) => | 161 | export const addGeoLink = ({ utils }, range) => |
| 119 | new Item({ | 162 | new Item({ |
| 120 | text: 'Add GeoLink', | 163 | text: 'Add GeoLink', |
| @@ -138,7 +181,17 @@ export const addGeoLink = ({ utils }, range) => | |||
| 138 | } | 181 | } |
| 139 | }) | 182 | }) |
| 140 | 183 | ||
| 184 | /** | ||
| 185 | * Suggestion. Menu Item for editor suggestion | ||
| 186 | * | ||
| 187 | * @extends {Item} | ||
| 188 | */ | ||
| 141 | export class Suggestion extends Item { | 189 | export class Suggestion extends Item { |
| 190 | /** | ||
| 191 | * constructor. | ||
| 192 | * | ||
| 193 | * @param {} | ||
| 194 | */ | ||
| 142 | constructor ({ text, replace, cm }) { | 195 | constructor ({ text, replace, cm }) { |
| 143 | super({ text }) | 196 | super({ text }) |
| 144 | this.replace = replace | 197 | this.replace = replace |
| @@ -165,6 +218,13 @@ export class Suggestion extends Item { | |||
| 165 | } | 218 | } |
| 166 | window.customElements.define('menu-item-suggestion', Suggestion, { extends: 'div' }) | 219 | window.customElements.define('menu-item-suggestion', Suggestion, { extends: 'div' }) |
| 167 | 220 | ||
| 221 | /** | ||
| 222 | * renderResults. return a menu item for reporting render results | ||
| 223 | * | ||
| 224 | * @param {Object} options.modal -- Ojbect of plain-modal | ||
| 225 | * @param {HTMLElement} options.modalContent | ||
| 226 | * @param {HTMLElement} map -- Rendered map element | ||
| 227 | */ | ||
| 168 | export const renderResults = ({ modal, modalContent }, map) => | 228 | export const renderResults = ({ modal, modalContent }, map) => |
| 169 | new Item({ | 229 | new Item({ |
| 170 | text: 'Render Results', | 230 | text: 'Render Results', |
| @@ -215,6 +275,13 @@ export const renderResults = ({ modal, modalContent }, map) => | |||
| 215 | } | 275 | } |
| 216 | }) | 276 | }) |
| 217 | 277 | ||
| 278 | /** | ||
| 279 | * printObject. Generate <details> in parent element based on Ojbect properties | ||
| 280 | * | ||
| 281 | * @param {Object} obj | ||
| 282 | * @param {HTMLElement} parentElement | ||
| 283 | * @param {String} name | ||
| 284 | */ | ||
| 218 | function printObject (obj, parentElement, name = null) { | 285 | function printObject (obj, parentElement, name = null) { |
| 219 | // Create <details> and <summary> inside | 286 | // Create <details> and <summary> inside |
| 220 | const detailsEle = document.createElement('details') | 287 | const detailsEle = document.createElement('details') |
| @@ -255,12 +322,22 @@ function printObject (obj, parentElement, name = null) { | |||
| 255 | } | 322 | } |
| 256 | } | 323 | } |
| 257 | 324 | ||
| 325 | /** | ||
| 326 | * toggleBlockFocus. Menu Item for toggling focus on a block | ||
| 327 | * | ||
| 328 | * @param {HTMLElement} block | ||
| 329 | */ | ||
| 258 | export const toggleBlockFocus = block => | 330 | export const toggleBlockFocus = block => |
| 259 | new Item({ | 331 | new Item({ |
| 260 | text: 'Toggle Focus', | 332 | text: 'Toggle Focus', |
| 261 | onclick: () => block.classList.toggle('focus') | 333 | onclick: () => block.classList.toggle('focus') |
| 262 | }) | 334 | }) |
| 263 | 335 | ||
| 336 | /** | ||
| 337 | * toggleMapFocus. Menu Item for toggling focus on a map | ||
| 338 | * | ||
| 339 | * @param {HTMLElement} map | ||
| 340 | */ | ||
| 264 | export const toggleMapFocus = map => | 341 | export const toggleMapFocus = map => |
| 265 | new Item({ | 342 | new Item({ |
| 266 | text: 'Toggle Focus', | 343 | text: 'Toggle Focus', |
diff --git a/src/dumbyUtils.mjs b/src/dumbyUtils.mjs index b0845bd..5182a8f 100644 --- a/src/dumbyUtils.mjs +++ b/src/dumbyUtils.mjs | |||
| @@ -1,5 +1,10 @@ | |||
| 1 | import LeaderLine from 'leader-line' | 1 | import LeaderLine from 'leader-line' |
| 2 | 2 | ||
| 3 | /** | ||
| 4 | * focusNextMap. | ||
| 5 | * | ||
| 6 | * @param {Boolean} reverse -- focus previous map | ||
| 7 | */ | ||
| 3 | export function focusNextMap (reverse = false) { | 8 | export function focusNextMap (reverse = false) { |
| 4 | const renderedList = this.utils.renderedMaps() | 9 | const renderedList = this.utils.renderedMaps() |
| 5 | const index = renderedList.findIndex(e => e.classList.contains('focus')) | 10 | const index = renderedList.findIndex(e => e.classList.contains('focus')) |
| @@ -10,6 +15,11 @@ export function focusNextMap (reverse = false) { | |||
| 10 | nextMap.scrollIntoView({ behavior: 'smooth' }) | 15 | nextMap.scrollIntoView({ behavior: 'smooth' }) |
| 11 | } | 16 | } |
| 12 | 17 | ||
| 18 | /** | ||
| 19 | * focusNextBlock. | ||
| 20 | * | ||
| 21 | * @param {Boolean} reverse -- focus previous block | ||
| 22 | */ | ||
| 13 | export function focusNextBlock (reverse = false) { | 23 | export function focusNextBlock (reverse = false) { |
| 14 | const blocks = this.blocks.filter(b => | 24 | const blocks = this.blocks.filter(b => |
| 15 | b.checkVisibility({ | 25 | b.checkVisibility({ |
| @@ -27,7 +37,12 @@ export function focusNextBlock (reverse = false) { | |||
| 27 | scrollToBlock(nextBlock) | 37 | scrollToBlock(nextBlock) |
| 28 | } | 38 | } |
| 29 | 39 | ||
| 30 | // Consider block is bigger then viewport height | 40 | /** |
| 41 | * scrollToBlock. Smoothly scroll to target block. | ||
| 42 | * If block is bigger than viewport, then pick strategy wisely. | ||
| 43 | * | ||
| 44 | * @param {HTMLElement} block -- Scroll to this element | ||
| 45 | */ | ||
| 31 | export const scrollToBlock = block => { | 46 | export const scrollToBlock = block => { |
| 32 | const parentRect = block.parentElement.getBoundingClientRect() | 47 | const parentRect = block.parentElement.getBoundingClientRect() |
| 33 | const scrollBlock = | 48 | const scrollBlock = |
| @@ -37,10 +52,18 @@ export const scrollToBlock = block => { | |||
| 37 | block.scrollIntoView({ behavior: 'smooth', block: scrollBlock }) | 52 | block.scrollIntoView({ behavior: 'smooth', block: scrollBlock }) |
| 38 | } | 53 | } |
| 39 | 54 | ||
| 55 | /** | ||
| 56 | * focusDelay. Delay of throttle, value changes by cases | ||
| 57 | */ | ||
| 40 | export function focusDelay () { | 58 | export function focusDelay () { |
| 41 | return window.window.getComputedStyle(this.showcase).display === 'none' ? 50 : 300 | 59 | return window.window.getComputedStyle(this.showcase).display === 'none' ? 50 : 300 |
| 42 | } | 60 | } |
| 43 | 61 | ||
| 62 | /** | ||
| 63 | * switchToNextLayout. | ||
| 64 | * | ||
| 65 | * @param {Boolean} reverse -- Switch to previous one | ||
| 66 | */ | ||
| 44 | export function switchToNextLayout (reverse = false) { | 67 | export function switchToNextLayout (reverse = false) { |
| 45 | const layouts = this.layouts | 68 | const layouts = this.layouts |
| 46 | const currentLayoutName = this.container.getAttribute('data-layout') | 69 | const currentLayoutName = this.container.getAttribute('data-layout') |
| @@ -54,6 +77,9 @@ export function switchToNextLayout (reverse = false) { | |||
| 54 | this.container.setAttribute('data-layout', nextLayout.name) | 77 | this.container.setAttribute('data-layout', nextLayout.name) |
| 55 | } | 78 | } |
| 56 | 79 | ||
| 80 | /** | ||
| 81 | * removeBlockFocus. | ||
| 82 | */ | ||
| 57 | export function removeBlockFocus () { | 83 | export function removeBlockFocus () { |
| 58 | this.blocks.forEach(b => b.classList.remove('focus')) | 84 | this.blocks.forEach(b => b.classList.remove('focus')) |
| 59 | } | 85 | } |
diff --git a/src/dumbymap.mjs b/src/dumbymap.mjs index 0c6f0be..744d216 100644 --- a/src/dumbymap.mjs +++ b/src/dumbymap.mjs | |||
| @@ -21,6 +21,12 @@ const layouts = [ | |||
| 21 | ] | 21 | ] |
| 22 | const mapCache = {} | 22 | const mapCache = {} |
| 23 | 23 | ||
| 24 | /** | ||
| 25 | * markdown2HTML. | ||
| 26 | * | ||
| 27 | * @param {HTMLElement} container -- Target Element to include generated HTML contents | ||
| 28 | * @param {String} mdContent -- Texts in Markdown | ||
| 29 | */ | ||
| 24 | export const markdown2HTML = (container, mdContent) => { | 30 | export const markdown2HTML = (container, mdContent) => { |
| 25 | // Render: Markdown -> HTML {{{ | 31 | // Render: Markdown -> HTML {{{ |
| 26 | container.replaceChildren() | 32 | container.replaceChildren() |
| @@ -83,7 +89,7 @@ export const markdown2HTML = (container, mdContent) => { | |||
| 83 | state.tokens.push(new state.Token('dumby_block_close', '', -1)) | 89 | state.tokens.push(new state.Token('dumby_block_close', '', -1)) |
| 84 | }) | 90 | }) |
| 85 | 91 | ||
| 86 | const contentWithToc = '${toc}\n\n\n' + mdContent // eslint-disable-line | 92 | const contentWithToc = '${toc}\n\n\n' + mdContent |
| 87 | htmlHolder.innerHTML = md.render(contentWithToc) | 93 | htmlHolder.innerHTML = md.render(contentWithToc) |
| 88 | 94 | ||
| 89 | // TODO Do this in markdown-it | 95 | // TODO Do this in markdown-it |
| @@ -96,6 +102,13 @@ export const markdown2HTML = (container, mdContent) => { | |||
| 96 | return container | 102 | return container |
| 97 | // }}} | 103 | // }}} |
| 98 | } | 104 | } |
| 105 | |||
| 106 | /** | ||
| 107 | * generateMaps. | ||
| 108 | * | ||
| 109 | * @param {HTMLElement} container -- Target Element contains HTML contents | ||
| 110 | * @param {Object} dumbymap -- Include and Elements and Methods about managing contents | ||
| 111 | */ | ||
| 99 | export const generateMaps = (container, { delay, mapCallback }) => { | 112 | export const generateMaps = (container, { delay, mapCallback }) => { |
| 100 | container.classList.add('Dumby') | 113 | container.classList.add('Dumby') |
| 101 | container.removeAttribute('data-layout') | 114 | container.removeAttribute('data-layout') |
| @@ -159,7 +172,7 @@ export const generateMaps = (container, { delay, mapCallback }) => { | |||
| 159 | const isAnchorPointedBy = link => anchor => { | 172 | const isAnchorPointedBy = link => anchor => { |
| 160 | const mapContainer = anchor.closest('.mapclay') | 173 | const mapContainer = anchor.closest('.mapclay') |
| 161 | const isTarget = !link.targets || link.targets.includes(mapContainer.id) | 174 | const isTarget = !link.targets || link.targets.includes(mapContainer.id) |
| 162 | return anchor.title === link.url.pathname && isTarget | 175 | return anchor.title === link.url.searchParams.get('text') && isTarget |
| 163 | } | 176 | } |
| 164 | 177 | ||
| 165 | const isAnchorVisible = anchor => { | 178 | const isAnchorVisible = anchor => { |
| @@ -366,7 +379,7 @@ export const generateMaps = (container, { delay, mapCallback }) => { | |||
| 366 | mapCallback?.call(this, mapElement) | 379 | mapCallback?.call(this, mapElement) |
| 367 | const markers = geoLinks | 380 | const markers = geoLinks |
| 368 | .filter(link => !link.targets || link.targets.includes(mapElement.id)) | 381 | .filter(link => !link.targets || link.targets.includes(mapElement.id)) |
| 369 | .map(link => ({ xy: link.xy, title: link.url.pathname })) | 382 | .map(link => ({ xy: link.xy, title: link.url.searchParams.get('text') })) |
| 370 | 383 | ||
| 371 | // FIXME Here may cause error | 384 | // FIXME Here may cause error |
| 372 | // Add markers with Geolinks | 385 | // Add markers with Geolinks |
diff --git a/src/editor.mjs b/src/editor.mjs index 36f0fdc..e9ee84a 100644 --- a/src/editor.mjs +++ b/src/editor.mjs | |||
| @@ -23,6 +23,9 @@ new window.MutationObserver(() => { | |||
| 23 | attributeFilter: ['data-mode'], | 23 | attributeFilter: ['data-mode'], |
| 24 | attributeOldValue: true | 24 | attributeOldValue: true |
| 25 | }) | 25 | }) |
| 26 | /** | ||
| 27 | * toggle editing mode | ||
| 28 | */ | ||
| 26 | const toggleEditing = () => { | 29 | const toggleEditing = () => { |
| 27 | const mode = context.getAttribute('data-mode') | 30 | const mode = context.getAttribute('data-mode') |
| 28 | context.setAttribute('data-mode', mode === 'editing' ? '' : 'editing') | 31 | context.setAttribute('data-mode', mode === 'editing' ? '' : 'editing') |
| @@ -128,6 +131,11 @@ const editor = new EasyMDE({ | |||
| 128 | 131 | ||
| 129 | const cm = editor.codemirror | 132 | const cm = editor.codemirror |
| 130 | 133 | ||
| 134 | /** | ||
| 135 | * get state of website from hash string | ||
| 136 | * | ||
| 137 | * @param {String} hash | ||
| 138 | */ | ||
| 131 | const getStateFromHash = hash => { | 139 | const getStateFromHash = hash => { |
| 132 | const hashValue = hash.substring(1) | 140 | const hashValue = hash.substring(1) |
| 133 | const stateString = decodeURIComponent(hashValue) | 141 | const stateString = decodeURIComponent(hashValue) |
| @@ -138,6 +146,11 @@ const getStateFromHash = hash => { | |||
| 138 | } | 146 | } |
| 139 | } | 147 | } |
| 140 | 148 | ||
| 149 | /** | ||
| 150 | * get editor content from hash string | ||
| 151 | * | ||
| 152 | * @param {} hash | ||
| 153 | */ | ||
| 141 | const getContentFromHash = hash => { | 154 | const getContentFromHash = hash => { |
| 142 | const state = getStateFromHash(hash) | 155 | const state = getStateFromHash(hash) |
| 143 | return state.content | 156 | return state.content |
| @@ -154,7 +167,13 @@ if (contentFromHash) { | |||
| 154 | } | 167 | } |
| 155 | // }}} | 168 | // }}} |
| 156 | // Set up logic about editor content {{{ | 169 | // Set up logic about editor content {{{ |
| 157 | const afterMapRendered = _ => { | 170 | /** |
| 171 | * afterMapRendered. Callback of map rendered | ||
| 172 | * | ||
| 173 | * @param {HTEMLElement} map | ||
| 174 | */ | ||
| 175 | const afterMapRendered = map => { | ||
| 176 | console.info(map) | ||
| 158 | // mapHolder.oncontextmenu = (event) => { | 177 | // mapHolder.oncontextmenu = (event) => { |
| 159 | // event.preventDefault() | 178 | // event.preventDefault() |
| 160 | // const lonLat = mapHolder.renderer.unproject([event.x, event.y]) | 179 | // const lonLat = mapHolder.renderer.unproject([event.x, event.y]) |
| @@ -164,7 +183,9 @@ const afterMapRendered = _ => { | |||
| 164 | markdown2HTML(HtmlContainer, editor.value()) | 183 | markdown2HTML(HtmlContainer, editor.value()) |
| 165 | dumbymap = generateMaps(HtmlContainer, afterMapRendered) | 184 | dumbymap = generateMaps(HtmlContainer, afterMapRendered) |
| 166 | 185 | ||
| 167 | // Quick hack to style lines inside code block | 186 | /** |
| 187 | * addClassToCodeLines. Quick hack to style lines inside code block | ||
| 188 | */ | ||
| 168 | const addClassToCodeLines = () => { | 189 | const addClassToCodeLines = () => { |
| 169 | const lines = cm.getLineHandle(0).parent.lines | 190 | const lines = cm.getLineHandle(0).parent.lines |
| 170 | let insideCodeBlock = false | 191 | let insideCodeBlock = false |
| @@ -180,6 +201,11 @@ const addClassToCodeLines = () => { | |||
| 180 | } | 201 | } |
| 181 | addClassToCodeLines() | 202 | addClassToCodeLines() |
| 182 | 203 | ||
| 204 | /** | ||
| 205 | * completeForCodeBlock. | ||
| 206 | * | ||
| 207 | * @param {Object} change -- codemirror change object | ||
| 208 | */ | ||
| 183 | const completeForCodeBlock = change => { | 209 | const completeForCodeBlock = change => { |
| 184 | const line = change.to.line | 210 | const line = change.to.line |
| 185 | if (change.origin === '+input') { | 211 | if (change.origin === '+input') { |
| @@ -234,6 +260,9 @@ const completeForCodeBlock = change => { | |||
| 234 | // } | 260 | // } |
| 235 | // })() | 261 | // })() |
| 236 | 262 | ||
| 263 | /** | ||
| 264 | * update content of HTML about Dumbymap | ||
| 265 | */ | ||
| 237 | const updateDumbyMap = () => { | 266 | const updateDumbyMap = () => { |
| 238 | markdown2HTML(HtmlContainer, editor.value()) | 267 | markdown2HTML(HtmlContainer, editor.value()) |
| 239 | // TODO Test if generate maps intantly is OK with map cache | 268 | // TODO Test if generate maps intantly is OK with map cache |
| @@ -309,7 +338,11 @@ fetch(defaultApply) | |||
| 309 | }) | 338 | }) |
| 310 | .catch(err => console.warn(`Fail to get aliases from ${defaultApply}`, err)) | 339 | .catch(err => console.warn(`Fail to get aliases from ${defaultApply}`, err)) |
| 311 | // }}} | 340 | // }}} |
| 312 | // FUNCTION: Check if current token is inside code block {{{ | 341 | /** |
| 342 | * insideCodeblockForMap. Check if current token is inside code block {{{ | ||
| 343 | * | ||
| 344 | * @param {} anchor | ||
| 345 | */ | ||
| 313 | const insideCodeblockForMap = anchor => { | 346 | const insideCodeblockForMap = anchor => { |
| 314 | const token = cm.getTokenAt(anchor) | 347 | const token = cm.getTokenAt(anchor) |
| 315 | const insideCodeBlock = | 348 | const insideCodeBlock = |
| @@ -330,7 +363,11 @@ const insideCodeblockForMap = anchor => { | |||
| 330 | return false | 363 | return false |
| 331 | } | 364 | } |
| 332 | // }}} | 365 | // }}} |
| 333 | // FUNCTION: Get Renderer by cursor position in code block {{{ | 366 | /** |
| 367 | * getLineWithRenderer. Get Renderer by cursor position in code block {{{ | ||
| 368 | * | ||
| 369 | * @param {Object} anchor -- Codemirror Anchor Object | ||
| 370 | */ | ||
| 334 | const getLineWithRenderer = anchor => { | 371 | const getLineWithRenderer = anchor => { |
| 335 | const currentLine = anchor.line | 372 | const currentLine = anchor.line |
| 336 | if (!cm.getLine) return null | 373 | if (!cm.getLine) return null |
| @@ -365,7 +402,12 @@ const getLineWithRenderer = anchor => { | |||
| 365 | return null | 402 | return null |
| 366 | } | 403 | } |
| 367 | // }}} | 404 | // }}} |
| 368 | // FUNCTION: Return suggestions for valid options {{{ | 405 | /** |
| 406 | * getSuggestionsForOptions. Return suggestions for valid options {{{ | ||
| 407 | * | ||
| 408 | * @param {Boolean} optionTyped | ||
| 409 | * @param {Object[]} validOptions | ||
| 410 | */ | ||
| 369 | const getSuggestionsForOptions = (optionTyped, validOptions) => { | 411 | const getSuggestionsForOptions = (optionTyped, validOptions) => { |
| 370 | let suggestOptions = [] | 412 | let suggestOptions = [] |
| 371 | 413 | ||
| @@ -389,7 +431,11 @@ const getSuggestionsForOptions = (optionTyped, validOptions) => { | |||
| 389 | ) | 431 | ) |
| 390 | } | 432 | } |
| 391 | // }}} | 433 | // }}} |
| 392 | // FUNCTION: Return suggestion for example of option value {{{ | 434 | /** |
| 435 | * getSuggestionFromMapOption. Return suggestion for example of option value {{{ | ||
| 436 | * | ||
| 437 | * @param {Object} option | ||
| 438 | */ | ||
| 393 | const getSuggestionFromMapOption = option => { | 439 | const getSuggestionFromMapOption = option => { |
| 394 | if (!option.example) return null | 440 | if (!option.example) return null |
| 395 | 441 | ||
| @@ -404,7 +450,11 @@ const getSuggestionFromMapOption = option => { | |||
| 404 | }) | 450 | }) |
| 405 | } | 451 | } |
| 406 | // }}} | 452 | // }}} |
| 407 | // FUNCTION: Return suggestions from aliases {{{ | 453 | /** |
| 454 | * getSuggestionsFromAliases. Return suggestions from aliases {{{ | ||
| 455 | * | ||
| 456 | * @param {Object} option | ||
| 457 | */ | ||
| 408 | const getSuggestionsFromAliases = option => | 458 | const getSuggestionsFromAliases = option => |
| 409 | Object.entries(aliasesForMapOptions[option.valueOf()] ?? {})?.map(record => { | 459 | Object.entries(aliasesForMapOptions[option.valueOf()] ?? {})?.map(record => { |
| 410 | const [alias, value] = record | 460 | const [alias, value] = record |
| @@ -416,7 +466,11 @@ const getSuggestionsFromAliases = option => | |||
| 416 | }) | 466 | }) |
| 417 | }) ?? [] | 467 | }) ?? [] |
| 418 | // }}} | 468 | // }}} |
| 419 | // FUCNTION: Handler for map codeblock {{{ | 469 | /** |
| 470 | * handleTypingInCodeBlock. Handler for map codeblock {{{ | ||
| 471 | * | ||
| 472 | * @param {Object} anchor -- Codemirror Anchor Object | ||
| 473 | */ | ||
| 420 | const handleTypingInCodeBlock = anchor => { | 474 | const handleTypingInCodeBlock = anchor => { |
| 421 | const text = cm.getLine(anchor.line) | 475 | const text = cm.getLine(anchor.line) |
| 422 | if (text.match(/^\s\+$/) && text.length % 2 !== 0) { | 476 | if (text.match(/^\s\+$/) && text.length % 2 !== 0) { |
| @@ -429,7 +483,11 @@ const handleTypingInCodeBlock = anchor => { | |||
| 429 | } | 483 | } |
| 430 | } | 484 | } |
| 431 | // }}} | 485 | // }}} |
| 432 | // FUNCTION: get suggestions by current input {{{ | 486 | /** |
| 487 | * getSuggestions. Get suggestions by current input {{{ | ||
| 488 | * | ||
| 489 | * @param {Object} anchor -- Codemirror Anchor Object | ||
| 490 | */ | ||
| 433 | const getSuggestions = anchor => { | 491 | const getSuggestions = anchor => { |
| 434 | const text = cm.getLine(anchor.line) | 492 | const text = cm.getLine(anchor.line) |
| 435 | 493 | ||
| @@ -543,7 +601,12 @@ const getSuggestions = anchor => { | |||
| 543 | return [] | 601 | return [] |
| 544 | } | 602 | } |
| 545 | // }}} | 603 | // }}} |
| 546 | // {{{ FUNCTION: Show element about suggestions | 604 | /** |
| 605 | * addSuggestions. Show element about suggestions {{{ | ||
| 606 | * | ||
| 607 | * @param {Object} anchor -- Codemirror Anchor Object | ||
| 608 | * @param {Suggestion[]} suggestions | ||
| 609 | */ | ||
| 547 | const addSuggestions = (anchor, suggestions) => { | 610 | const addSuggestions = (anchor, suggestions) => { |
| 548 | if (suggestions.length === 0) { | 611 | if (suggestions.length === 0) { |
| 549 | menu.style.display = 'none' | 612 | menu.style.display = 'none' |
diff --git a/src/utils.mjs b/src/utils.mjs index c9a2457..ffd8978 100644 --- a/src/utils.mjs +++ b/src/utils.mjs | |||
| @@ -88,6 +88,11 @@ export function throttle (func, delay) { | |||
| 88 | } | 88 | } |
| 89 | } | 89 | } |
| 90 | 90 | ||
| 91 | /** | ||
| 92 | * shiftByWindow. make sure HTMLElement inside viewport | ||
| 93 | * | ||
| 94 | * @param {HTMLElement} element | ||
| 95 | */ | ||
| 91 | export const shiftByWindow = element => { | 96 | export const shiftByWindow = element => { |
| 92 | const rect = element.getBoundingClientRect() | 97 | const rect = element.getBoundingClientRect() |
| 93 | const offsetX = window.innerWidth - rect.left - rect.width | 98 | const offsetX = window.innerWidth - rect.left - rect.width |