diff options
author | Hsieh Chin Fan <pham@topo.tw> | 2024-10-23 16:50:01 +0800 |
---|---|---|
committer | Hsieh Chin Fan <pham@topo.tw> | 2024-10-23 20:50:23 +0800 |
commit | 5c02dfcd703c20c304e62a87c0a6796009157d2f (patch) | |
tree | 0879c9cdcccea4ca29df3533e66d4dc5ee4f1f0b | |
parent | 1c6d532ac8775dc572df18ed90ba068076d914b7 (diff) |
feat: patch 5cb442c, observer for layout
-rw-r--r-- | src/dumbymap.mjs | 144 | ||||
-rw-r--r-- | src/editor.mjs | 8 |
2 files changed, 93 insertions, 59 deletions
diff --git a/src/dumbymap.mjs b/src/dumbymap.mjs index d05e7c4..d512136 100644 --- a/src/dumbymap.mjs +++ b/src/dumbymap.mjs | |||
@@ -37,9 +37,7 @@ const mapCache = {} | |||
37 | */ | 37 | */ |
38 | export const markdown2HTML = (container, mdContent) => { | 38 | export const markdown2HTML = (container, mdContent) => { |
39 | /** Prepare Elements for Container */ | 39 | /** Prepare Elements for Container */ |
40 | container.replaceChildren() | 40 | container.querySelector('.SemanticHtml')?.remove() |
41 | container.innerHTML = '<div class="SemanticHtml"></div>' | ||
42 | const htmlHolder = container.querySelector('.SemanticHtml') | ||
43 | 41 | ||
44 | /** Prepare MarkdownIt Instance */ | 42 | /** Prepare MarkdownIt Instance */ |
45 | const md = MarkdownIt({ | 43 | const md = MarkdownIt({ |
@@ -80,7 +78,10 @@ export const markdown2HTML = (container, mdContent) => { | |||
80 | }) | 78 | }) |
81 | 79 | ||
82 | /** Render HTML */ | 80 | /** Render HTML */ |
81 | const htmlHolder = document.createElement('div') | ||
82 | htmlHolder.className = 'SemanticHtml' | ||
83 | htmlHolder.innerHTML = md.render(mdContent) | 83 | htmlHolder.innerHTML = md.render(mdContent) |
84 | container.appendChild(htmlHolder) | ||
84 | 85 | ||
85 | return container | 86 | return container |
86 | } | 87 | } |
@@ -160,6 +161,47 @@ export const generateMaps = (container, { | |||
160 | container.appendChild(showcase) | 161 | container.appendChild(showcase) |
161 | showcase.classList.add('Showcase') | 162 | showcase.classList.add('Showcase') |
162 | 163 | ||
164 | /** Prepare Other Variables */ | ||
165 | const modalContent = document.createElement('div') | ||
166 | container.appendChild(modalContent) | ||
167 | const modal = new PlainModal(modalContent) | ||
168 | |||
169 | /** Define dumbymap Object */ | ||
170 | const dumbymap = { | ||
171 | layouts: [...defaultLayouts, ...layouts.map(l => typeof l === 'object' ? l : { name: l })], | ||
172 | container, | ||
173 | get htmlHolder () { return container.querySelector('.SemanticHtml') }, | ||
174 | get showcase () { return container.querySelector('.Showcase') }, | ||
175 | get blocks () { return Array.from(container.querySelectorAll('.dumby-block')) }, | ||
176 | modal, | ||
177 | modalContent, | ||
178 | utils: { | ||
179 | ...utils, | ||
180 | renderedMaps: () => | ||
181 | Array.from( | ||
182 | container.querySelectorAll('.mapclay[data-render=fulfilled]'), | ||
183 | ).sort((a, b) => a.style.order > b.style.order), | ||
184 | setContextMenu: (menuCallback) => { | ||
185 | const originalCallback = container.oncontextmenu | ||
186 | container.oncontextmenu = (e) => { | ||
187 | const menu = originalCallback(e) | ||
188 | if (!menu) return | ||
189 | |||
190 | menuCallback(e, menu) | ||
191 | menu.style.transform = '' | ||
192 | shiftByWindow(menu) | ||
193 | } | ||
194 | }, | ||
195 | focusNextMap: throttle(utils.focusNextMap, utils.focusDelay), | ||
196 | switchToNextLayout: throttle(utils.switchToNextLayout, 300), | ||
197 | }, | ||
198 | } | ||
199 | Object.entries(dumbymap.utils).forEach(([util, value]) => { | ||
200 | if (typeof value === 'function') { | ||
201 | dumbymap.utils[util] = value.bind(dumbymap) | ||
202 | } | ||
203 | }) | ||
204 | |||
163 | /** WATCH: text content of Semantic HTML */ | 205 | /** WATCH: text content of Semantic HTML */ |
164 | new window.MutationObserver((mutations) => { | 206 | new window.MutationObserver((mutations) => { |
165 | for (const mutation of mutations) { | 207 | for (const mutation of mutations) { |
@@ -180,7 +222,6 @@ export const generateMaps = (container, { | |||
180 | subtree: true, | 222 | subtree: true, |
181 | }) | 223 | }) |
182 | 224 | ||
183 | const counter = 0 | ||
184 | /** WATCH: children of Semantic HTML */ | 225 | /** WATCH: children of Semantic HTML */ |
185 | new window.MutationObserver((mutations) => { | 226 | new window.MutationObserver((mutations) => { |
186 | for (const mutation of mutations) { | 227 | for (const mutation of mutations) { |
@@ -223,52 +264,46 @@ export const generateMaps = (container, { | |||
223 | } | 264 | } |
224 | }).observe(container, { | 265 | }).observe(container, { |
225 | attributes: true, | 266 | attributes: true, |
226 | attributesFilter: ['data-init-dumby'], | 267 | attributeFilter: ['data-init-dumby'], |
227 | childList: true, | 268 | childList: true, |
228 | subtree: true, | 269 | subtree: true, |
229 | }) | 270 | }) |
230 | 271 | ||
231 | container.dataset.initDumby = 'true' | 272 | container.dataset.initDumby = 'true' |
232 | 273 | ||
233 | /** Prepare Other Variables */ | 274 | /** WATCH: Layout changes */ |
234 | const modalContent = document.createElement('div') | 275 | new window.MutationObserver(mutations => { |
235 | container.appendChild(modalContent) | 276 | const mutation = mutations.at(-1) |
236 | const modal = new PlainModal(modalContent) | 277 | const oldLayout = mutation.oldValue |
278 | const newLayout = container.dataset.layout | ||
279 | |||
280 | // Apply handler for leaving/entering layouts | ||
281 | if (oldLayout) { | ||
282 | dumbymap.layouts | ||
283 | .find(l => l.name === oldLayout) | ||
284 | ?.leaveHandler?.call(this, dumbymap) | ||
285 | } | ||
237 | 286 | ||
238 | /** Define dumbymap Object */ | 287 | Object.values(dumbymap) |
239 | const dumbymap = { | 288 | .filter(ele => ele instanceof window.HTMLElement) |
240 | layouts: [...defaultLayouts, ...layouts.map(l => typeof l === 'object' ? l : { name: l })], | 289 | .forEach(ele => { ele.style.cssText = '' }) |
241 | container, | ||
242 | htmlHolder, | ||
243 | showcase, | ||
244 | get blocks () { return Array.from(container.querySelectorAll('.dumby-block')) }, | ||
245 | modal, | ||
246 | modalContent, | ||
247 | utils: { | ||
248 | ...utils, | ||
249 | renderedMaps: () => | ||
250 | Array.from( | ||
251 | container.querySelectorAll('.mapclay[data-render=fulfilled]'), | ||
252 | ).sort((a, b) => a.style.order > b.style.order), | ||
253 | setContextMenu: (menuCallback) => { | ||
254 | const originalCallback = container.oncontextmenu | ||
255 | container.oncontextmenu = (e) => { | ||
256 | const menu = originalCallback(e) | ||
257 | if (!menu) return | ||
258 | 290 | ||
259 | menuCallback(e, menu) | 291 | if (newLayout) { |
260 | menu.style.transform = '' | 292 | dumbymap.layouts |
261 | shiftByWindow(menu) | 293 | .find(l => l.name === newLayout) |
262 | } | 294 | ?.enterHandler?.call(this, dumbymap) |
263 | }, | ||
264 | focusNextMap: throttle(utils.focusNextMap, utils.focusDelay), | ||
265 | switchToNextLayout: throttle(utils.switchToNextLayout, 300), | ||
266 | }, | ||
267 | } | ||
268 | Object.entries(dumbymap.utils).forEach(([util, value]) => { | ||
269 | if (typeof value === 'function') { | ||
270 | dumbymap.utils[util] = value.bind(dumbymap) | ||
271 | } | 295 | } |
296 | |||
297 | // Since layout change may show/hide showcase, the current focused map may need to go into/outside showcase | ||
298 | // Reset attribute triggers MutationObserver which is observing it | ||
299 | const focusMap = | ||
300 | container.querySelector('.mapclay.focus') ?? | ||
301 | container.querySelector('.mapclay') | ||
302 | focusMap?.classList?.add('focus') | ||
303 | }).observe(container, { | ||
304 | attributes: true, | ||
305 | attributeFilter: ['data-layout'], | ||
306 | attributeOldValue: true, | ||
272 | }) | 307 | }) |
273 | 308 | ||
274 | /** | 309 | /** |
@@ -473,17 +508,19 @@ export const generateMaps = (container, { | |||
473 | } | 508 | } |
474 | 509 | ||
475 | if (!target.renderMap) { | 510 | if (!target.renderMap) { |
476 | target.renderMap = debounce(() => { | 511 | target.renderMap = debounce( |
477 | // Render maps | 512 | () => { |
478 | render(target, configList).forEach(renderPromise => { | 513 | // Render maps |
479 | renderPromise.then(afterMapRendered) | 514 | render(target, configList).forEach(renderPromise => { |
480 | }) | 515 | renderPromise.then(afterMapRendered) |
481 | Array.from(target.children).forEach(e => { | 516 | }) |
482 | if (e.dataset.render === 'fulfilled') { | 517 | Array.from(target.children).forEach(e => { |
483 | afterMapRendered(e.renderer) | 518 | if (e.dataset.render === 'fulfilled') { |
484 | } | 519 | afterMapRendered(e.renderer) |
485 | }), mapDelay | 520 | } |
486 | }) | 521 | }) |
522 | }, mapDelay, | ||
523 | ) | ||
487 | } | 524 | } |
488 | target.renderMap() | 525 | target.renderMap() |
489 | } | 526 | } |
@@ -498,7 +535,8 @@ export const generateMaps = (container, { | |||
498 | 535 | ||
499 | menu.style.display = 'none' | 536 | menu.style.display = 'none' |
500 | } | 537 | } |
501 | document.body.appendChild(menu) | 538 | container.appendChild(menu) |
539 | window.menu = menu | ||
502 | 540 | ||
503 | /** MENU: Menu Items for Context Menu */ | 541 | /** MENU: Menu Items for Context Menu */ |
504 | container.oncontextmenu = e => { | 542 | container.oncontextmenu = e => { |
diff --git a/src/editor.mjs b/src/editor.mjs index 430353a..3f8f27d 100644 --- a/src/editor.mjs +++ b/src/editor.mjs | |||
@@ -476,13 +476,9 @@ function menuForEditor (event, menu) { | |||
476 | */ | 476 | */ |
477 | const updateDumbyMap = (callback = null) => { | 477 | const updateDumbyMap = (callback = null) => { |
478 | markdown2HTML(dumbyContainer, editor.value()) | 478 | markdown2HTML(dumbyContainer, editor.value()) |
479 | // debounceForMap(dumbyContainer, afterMapRendered) | ||
480 | // dumbymap = generateMaps(dumbyContainer, { | ||
481 | // crs, | ||
482 | // }) | ||
483 | // Set onscroll callback | 479 | // Set onscroll callback |
484 | // const htmlHolder = dumbymap.htmlHolder | 480 | const htmlHolder = dumbymap.htmlHolder |
485 | // htmlHolder.onscroll = updateScrollLine(htmlHolder) | 481 | dumbymap.htmlHolder.onscroll = updateScrollLine(htmlHolder) |
486 | 482 | ||
487 | callback?.(dumbymap) | 483 | callback?.(dumbymap) |
488 | } | 484 | } |