aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorHsieh Chin Fan <pham@topo.tw>2024-10-23 16:50:01 +0800
committerHsieh Chin Fan <pham@topo.tw>2024-10-23 20:50:23 +0800
commit5c02dfcd703c20c304e62a87c0a6796009157d2f (patch)
tree0879c9cdcccea4ca29df3533e66d4dc5ee4f1f0b
parent1c6d532ac8775dc572df18ed90ba068076d914b7 (diff)
feat: patch 5cb442c, observer for layout
-rw-r--r--src/dumbymap.mjs144
-rw-r--r--src/editor.mjs8
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 */
38export const markdown2HTML = (container, mdContent) => { 38export 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 */
477const updateDumbyMap = (callback = null) => { 477const 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}