diff options
Diffstat (limited to 'src/dumbymap.mjs')
-rw-r--r-- | src/dumbymap.mjs | 80 |
1 files changed, 45 insertions, 35 deletions
diff --git a/src/dumbymap.mjs b/src/dumbymap.mjs index 6e4c00e..bdb7ee8 100644 --- a/src/dumbymap.mjs +++ b/src/dumbymap.mjs | |||
@@ -86,28 +86,28 @@ export const markdown2HTML = (container, mdContent) => { | |||
86 | .use(MarkdownItFrontMatter) | 86 | .use(MarkdownItFrontMatter) |
87 | .use(MarkdownItTocDoneRight) | 87 | .use(MarkdownItTocDoneRight) |
88 | 88 | ||
89 | // FIXME A better way to generate draggable code block | 89 | // FIXME A better way to generate blocks |
90 | md.renderer.rules.draggable_block_open = () => '<div>' | 90 | md.renderer.rules.dumby_block_open = () => '<div>' |
91 | md.renderer.rules.draggable_block_close = () => '</div>' | 91 | md.renderer.rules.dumby_block_close = () => '</div>' |
92 | 92 | ||
93 | md.core.ruler.before('block', 'draggable_block', (state) => { | 93 | md.core.ruler.before('block', 'dumby_block', (state) => { |
94 | state.tokens.push(new state.Token('draggable_block_open', '', 1)) | 94 | state.tokens.push(new state.Token('dumby_block_open', '', 1)) |
95 | }) | 95 | }) |
96 | 96 | ||
97 | // Add close tag for block with more than 2 empty lines | 97 | // Add close tag for block with more than 2 empty lines |
98 | md.block.ruler.before('table', 'draggable_block', (state, startLine) => { | 98 | md.block.ruler.before('table', 'dumby_block', (state, startLine) => { |
99 | if ( | 99 | if ( |
100 | state.src[state.bMarks[startLine - 1]] === '\n' && | 100 | state.src[state.bMarks[startLine - 1]] === '\n' && |
101 | state.src[state.bMarks[startLine - 2]] === '\n' && | 101 | state.src[state.bMarks[startLine - 2]] === '\n' && |
102 | state.tokens.at(-1).type !== 'list_item_open' // Quick hack for not adding tag after "::marker" for <li> | 102 | state.tokens.at(-1).type !== 'list_item_open' // Quick hack for not adding tag after "::marker" for <li> |
103 | ) { | 103 | ) { |
104 | state.push('draggable_block_close', '', -1); | 104 | state.push('dumby_block_close', '', -1); |
105 | state.push('draggable_block_open', '', 1); | 105 | state.push('dumby_block_open', '', 1); |
106 | } | 106 | } |
107 | }) | 107 | }) |
108 | 108 | ||
109 | md.core.ruler.after('block', 'draggable_block', (state) => { | 109 | md.core.ruler.after('block', 'dumby_block', (state) => { |
110 | state.tokens.push(new state.Token('draggable_block_close', '', -1)) | 110 | state.tokens.push(new state.Token('dumby_block_close', '', -1)) |
111 | }) | 111 | }) |
112 | 112 | ||
113 | const contentWithToc = '${toc}\n\n\n' + mdContent | 113 | const contentWithToc = '${toc}\n\n\n' + mdContent |
@@ -115,7 +115,7 @@ export const markdown2HTML = (container, mdContent) => { | |||
115 | 115 | ||
116 | // TODO Do this in markdown-it | 116 | // TODO Do this in markdown-it |
117 | htmlHolder.querySelectorAll('* > div:not(:has(nav))') | 117 | htmlHolder.querySelectorAll('* > div:not(:has(nav))') |
118 | .forEach(b => b.classList.add('draggable-block')) | 118 | .forEach(b => b.classList.add('dumby-block')) |
119 | 119 | ||
120 | return container | 120 | return container |
121 | //}}} | 121 | //}}} |
@@ -200,33 +200,48 @@ export const generateMaps = async (container, callback) => { | |||
200 | childRect.bottom < parentRect.bottom - offset | 200 | childRect.bottom < parentRect.bottom - offset |
201 | } | 201 | } |
202 | //}}} | 202 | //}}} |
203 | // Draggable Blocks{{{ | 203 | // Draggable Blocks {{{ |
204 | // Add draggable part for blocks | 204 | // Add draggable part for blocks |
205 | htmlHolder.blocks = Array.from(htmlHolder.querySelectorAll('.draggable-block')) | 205 | |
206 | htmlHolder.blocks.forEach(block => { | 206 | const dumbyBlocks = Array.from(htmlHolder.querySelectorAll('.dumby-block')) |
207 | const intoDraggableContainer = (block) => { | ||
208 | // Create draggable block | ||
209 | const draggableContainer = document.createElement('div') | ||
210 | draggableContainer.classList.add('draggable-block') | ||
211 | |||
207 | // Add draggable part | 212 | // Add draggable part |
208 | const draggablePart = document.createElement('div'); | 213 | const draggablePart = document.createElement('div'); |
209 | draggablePart.classList.add('draggable') | 214 | draggablePart.classList.add('draggable') |
210 | draggablePart.textContent = '☰' | 215 | draggablePart.textContent = '☰' |
211 | draggablePart.title = 'Use middle-click to remove block' | 216 | draggablePart.title = 'Use middle-click to remove block' |
212 | block.insertBefore(draggablePart, block.firstChild) | 217 | // Hide block with middle click |
213 | block.draggablePart = draggablePart | ||
214 | |||
215 | draggablePart.onmouseup = (e) => { | 218 | draggablePart.onmouseup = (e) => { |
216 | if (e.button === 1) { | 219 | if (e.button === 1) { |
217 | block.style.display = "none"; | 220 | draggableContainer.style.display = "none"; |
218 | } | 221 | } |
219 | } | 222 | } |
220 | }) | 223 | draggableContainer.appendChild(draggablePart) |
221 | 224 | ||
225 | draggableContainer.appendChild(block) | ||
226 | htmlHolder.appendChild(draggableContainer) | ||
227 | return draggableContainer | ||
228 | } | ||
229 | |||
230 | const resumeFromDraggableContainer = (block) => { | ||
231 | const draggableContainer = block.closest('.draggable-block') | ||
232 | if (!draggableContainer) return | ||
233 | htmlHolder.appendChild(block) | ||
234 | draggableContainer.draggableInstance.remove() | ||
235 | draggableContainer.remove() | ||
236 | } | ||
222 | // }}} | 237 | // }}} |
223 | // CSS observer {{{ | 238 | // CSS observer {{{ |
239 | // Focus Map {{{ | ||
224 | // Set focusArea | 240 | // Set focusArea |
225 | const showcase = document.createElement('div') | 241 | const showcase = document.createElement('div') |
226 | container.appendChild(showcase) | 242 | container.appendChild(showcase) |
227 | showcase.classList.add('Showcase') | 243 | showcase.classList.add('Showcase') |
228 | 244 | ||
229 | // Focus Map {{{ | ||
230 | const toShowcaseWithThrottle = throttle(animateRectTransition, 300) | 245 | const toShowcaseWithThrottle = throttle(animateRectTransition, 300) |
231 | const fromShowCaseWithThrottle = throttle(animateRectTransition, 300) | 246 | const fromShowCaseWithThrottle = throttle(animateRectTransition, 300) |
232 | 247 | ||
@@ -331,7 +346,7 @@ export const generateMaps = async (container, callback) => { | |||
331 | focusMap?.setAttribute('data-focus', 'true') | 346 | focusMap?.setAttribute('data-focus', 'true') |
332 | 347 | ||
333 | // Check empty block with map-container in showcase | 348 | // Check empty block with map-container in showcase |
334 | htmlHolder.blocks.forEach(b => { | 349 | dumbyBlocks.forEach(b => { |
335 | const contentChildren = Array.from(b.querySelectorAll(':scope > :not(.draggable)')) ?? [] | 350 | const contentChildren = Array.from(b.querySelectorAll(':scope > :not(.draggable)')) ?? [] |
336 | if (contentChildren.length === 1 | 351 | if (contentChildren.length === 1 |
337 | && elementsWithMapConfig.includes(contentChildren[0]) | 352 | && elementsWithMapConfig.includes(contentChildren[0]) |
@@ -344,32 +359,27 @@ export const generateMaps = async (container, callback) => { | |||
344 | }) | 359 | }) |
345 | 360 | ||
346 | if (layout === 'overlay') { | 361 | if (layout === 'overlay') { |
362 | const draggableContainers = dumbyBlocks.map(intoDraggableContainer) | ||
363 | |||
364 | // Set initial position side by side | ||
347 | let [x, y] = [0, 0]; | 365 | let [x, y] = [0, 0]; |
348 | htmlHolder.blocks.forEach(block => { | 366 | draggableContainers.forEach((c) => { |
367 | |||
349 | // Add draggable instance | 368 | // Add draggable instance |
350 | block.draggableInstance = new PlainDraggable(block, { | 369 | c.draggableInstance = new PlainDraggable(c, { |
351 | handle: block.draggablePart, | 370 | handle: c.querySelector('.draggable') ?? c, |
352 | snap: { x: { step: 20 }, y: { step: 20 } }, | 371 | snap: { x: { step: 20 }, y: { step: 20 } }, |
353 | left: x, | 372 | left: x, |
354 | top: y, | 373 | top: y, |
355 | }) | 374 | }) |
356 | 375 | x += parseInt(window.getComputedStyle(c).width) + 30 | |
357 | // Set initial position side by side | ||
358 | x += parseInt(window.getComputedStyle(block).width) + 50 | ||
359 | if (x > window.innerWidth) { | 376 | if (x > window.innerWidth) { |
360 | y += 200 | 377 | y += 200 |
361 | x = x % window.innerWidth | 378 | x = x % window.innerWidth |
362 | } | 379 | } |
363 | }) | 380 | }) |
364 | } else { | 381 | } else { |
365 | htmlHolder.blocks.forEach(block => { | 382 | dumbyBlocks.forEach(resumeFromDraggableContainer) |
366 | block.removeAttribute('style') | ||
367 | try { | ||
368 | block.draggableInstance.remove() | ||
369 | } catch (_) { | ||
370 | null | ||
371 | } | ||
372 | }) | ||
373 | } | 383 | } |
374 | }); | 384 | }); |
375 | layoutObserver.observe(container, { | 385 | layoutObserver.observe(container, { |