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 | |
parent | ec23491d3a39f9f9201449f14a536b7540a8c281 (diff) |
docs: add jsdoc
-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 |