aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorHsieh Chin Fan <pham@topo.tw>2024-09-11 18:21:32 +0800
committerHsieh Chin Fan <pham@topo.tw>2024-09-11 18:21:33 +0800
commit0e6110ad9be2e444880b13e9f670f636ccd09381 (patch)
treefa4c4a102eb3950d801ed20ee35138c07e435b9f /src
parent7e62f6353fa485bd184e9910f933791a414d3398 (diff)
feat: Use CSS selector on DocLinks
* Now module export method createDocLinks() * DocLink now decides target by CSS selector in title with prefix "=>", or just by doc fragment
Diffstat (limited to 'src')
-rw-r--r--src/dumbymap.mjs72
-rw-r--r--src/editor.mjs5
2 files changed, 49 insertions, 28 deletions
diff --git a/src/dumbymap.mjs b/src/dumbymap.mjs
index cd3b8ff..a896d0d 100644
--- a/src/dumbymap.mjs
+++ b/src/dumbymap.mjs
@@ -7,7 +7,8 @@ import LeaderLine from 'leader-line'
7import PlainDraggable from 'plain-draggable' 7import PlainDraggable from 'plain-draggable'
8import { render, parseConfigsFromYaml } from 'mapclay' 8import { render, parseConfigsFromYaml } from 'mapclay'
9 9
10function onRemove(element, callback) { 10// Utils {{{
11const onRemove = (element, callback) => {
11 const parent = element.parentNode; 12 const parent = element.parentNode;
12 if (!parent) throw new Error("The node must already be attached"); 13 if (!parent) throw new Error("The node must already be attached");
13 14
@@ -23,12 +24,47 @@ function onRemove(element, callback) {
23 }); 24 });
24 obs.observe(parent, { childList: true, }); 25 obs.observe(parent, { childList: true, });
25} 26}
27// }}}
28// FUNCTION: Get DocLinks from normal special anchor element {{{
26 29
27// Render: Markdown -> HTML {{{ 30const docLinkSelector = 'a[href^="#"][title^="=>"]'
28export const markdown2HTML = (container, mdContent) => { 31export const createDocLinks = (container) => Array.from(container.querySelectorAll(docLinkSelector))
32 .map(link => {
33 link.classList.add('with-leader-line', 'doclink')
34 link.lines = []
35
36 link.onmouseover = () => {
37 const label = decodeURIComponent(link.href.split('#')[1])
38 const selector = link.title.split('=>')[1] ?? '#' + label
39 const target = document.querySelector(selector)
40 if (!target?.checkVisibility()) return
41
42 const line = new LeaderLine({
43 start: link,
44 end: target,
45 middleLabel: LeaderLine.pathLabel({
46 text: label,
47 fontWeight: 'bold',
48 }),
49 hide: true,
50 path: "magnet"
51 })
52 link.lines.push(line)
53 line.show('draw', { duration: 300, })
54 }
55 link.onmouseout = () => {
56 link.lines.forEach(line => line.remove())
57 link.lines.length = 0
58 }
29 59
60 return link
61 })
62// }}}
63export const markdown2HTML = (container, mdContent) => {
64 // Render: Markdown -> HTML {{{
30 Array.from(container.children).map(e => e.remove()) 65 Array.from(container.children).map(e => e.remove())
31 66
67
32 container.innerHTML = '<div class="SemanticHtml"></div>' 68 container.innerHTML = '<div class="SemanticHtml"></div>'
33 const htmlHolder = container.querySelector('.SemanticHtml') 69 const htmlHolder = container.querySelector('.SemanticHtml')
34 70
@@ -50,7 +86,11 @@ export const markdown2HTML = (container, mdContent) => {
50 86
51 // Add close tag for block with more than 2 empty lines 87 // Add close tag for block with more than 2 empty lines
52 md.block.ruler.before('table', 'draggable_block', (state, startLine) => { 88 md.block.ruler.before('table', 'draggable_block', (state, startLine) => {
53 if (state.src[state.bMarks[startLine - 1]] === '\n' && state.src[state.bMarks[startLine - 2]] === '\n') { 89 if (
90 state.src[state.bMarks[startLine - 1]] === '\n' &&
91 state.src[state.bMarks[startLine - 2]] === '\n' &&
92 state.tokens.at(-1).type !== 'list_item_open' // Quick hack for not adding tag after "::marker" for <li>
93 ) {
54 state.push('draggable_block_close', '', -1); 94 state.push('draggable_block_close', '', -1);
55 state.push('draggable_block_open', '', 1); 95 state.push('draggable_block_open', '', 1);
56 } 96 }
@@ -68,34 +108,10 @@ export const markdown2HTML = (container, mdContent) => {
68 108
69 109
70 // TODO Improve it! 110 // TODO Improve it!
71 const docLinks = Array.from(container.querySelectorAll('a[href^="#"][title^="doc"]'))
72 docLinks.forEach(link => {
73 link.classList.add('with-leader-line', 'doclink')
74 link.lines = []
75
76 link.onmouseover = () => {
77 const target = document.querySelector(link.getAttribute('href'))
78 if (!target?.checkVisibility()) return
79
80 const line = new LeaderLine({
81 start: link,
82 end: target,
83 hide: true,
84 path: "magnet"
85 })
86 link.lines.push(line)
87 line.show('draw', { duration: 300, })
88 }
89 link.onmouseout = () => {
90 link.lines.forEach(line => line.remove())
91 link.lines.length = 0
92 }
93 })
94 111
95 return container 112 return container
96 //}}} 113 //}}}
97} 114}
98
99// FIXME Don't use hard-coded CSS selector 115// FIXME Don't use hard-coded CSS selector
100export const generateMaps = async (container) => { 116export const generateMaps = async (container) => {
101 // LeaderLine {{{ 117 // LeaderLine {{{
diff --git a/src/editor.mjs b/src/editor.mjs
index 1544589..107743b 100644
--- a/src/editor.mjs
+++ b/src/editor.mjs
@@ -1,5 +1,6 @@
1import { markdown2HTML, generateMaps } from './dumbymap' 1import { markdown2HTML, generateMaps } from './dumbymap'
2import { defaultAliasesForRenderer, parseConfigsFromYaml } from 'mapclay' 2import { defaultAliasesForRenderer, parseConfigsFromYaml } from 'mapclay'
3import { createDocLinks } from './dumbymap.mjs'
3 4
4// Set up Editor {{{ 5// Set up Editor {{{
5 6
@@ -12,6 +13,7 @@ const toggleMaps = (container) => {
12 document.activeElement.blur(); 13 document.activeElement.blur();
13 } else { 14 } else {
14 markdown2HTML(HtmlContainer, editor.value()) 15 markdown2HTML(HtmlContainer, editor.value())
16 createDocLinks(container)
15 container.setAttribute('data-layout', 'none') 17 container.setAttribute('data-layout', 'none')
16 } 18 }
17} 19}
@@ -70,9 +72,12 @@ const editor = new EasyMDE({
70 72
71const cm = editor.codemirror 73const cm = editor.codemirror
72markdown2HTML(HtmlContainer, editor.value()) 74markdown2HTML(HtmlContainer, editor.value())
75createDocLinks(HtmlContainer)
73 76
77// Re-render HTML by editor content
74cm.on("change", () => { 78cm.on("change", () => {
75 markdown2HTML(HtmlContainer, editor.value()) 79 markdown2HTML(HtmlContainer, editor.value())
80 createDocLinks(HtmlContainer)
76}) 81})
77// }}} 82// }}}
78 83