From 12e842451f41c1c17aa2c8f8025e4d8480d0c639 Mon Sep 17 00:00:00 2001 From: Jonathan Tran Date: Fri, 9 Jun 2023 14:06:45 -0400 Subject: [PATCH 1/4] Fix task list checkbox toggle to work with YAML front matter --- modules/markup/markdown/ast.go | 4 ++- modules/markup/markdown/goldmark.go | 12 ++++---- modules/markup/markdown/markdown.go | 9 ++++++ modules/markup/markdown/markdown_test.go | 37 ++++++++++++++++++++++++ modules/markup/markdown/renderconfig.go | 3 ++ 5 files changed, 58 insertions(+), 7 deletions(-) diff --git a/modules/markup/markdown/ast.go b/modules/markup/markdown/ast.go index e844f801c4f7a..3e6e291ab25a4 100644 --- a/modules/markup/markdown/ast.go +++ b/modules/markup/markdown/ast.go @@ -76,7 +76,8 @@ func IsSummary(node ast.Node) bool { // TaskCheckBoxListItem is a block that represents a list item of a markdown block with a checkbox type TaskCheckBoxListItem struct { *ast.ListItem - IsChecked bool + IsChecked bool + SourcePosition int } // KindTaskCheckBoxListItem is the NodeKind for TaskCheckBoxListItem @@ -86,6 +87,7 @@ var KindTaskCheckBoxListItem = ast.NewNodeKind("TaskCheckBoxListItem") func (n *TaskCheckBoxListItem) Dump(source []byte, level int) { m := map[string]string{} m["IsChecked"] = strconv.FormatBool(n.IsChecked) + m["SourcePosition"] = strconv.FormatInt(int64(n.SourcePosition), 10) ast.DumpHelper(n, source, level, m, nil) } diff --git a/modules/markup/markdown/goldmark.go b/modules/markup/markdown/goldmark.go index f03a780900356..5a086305d94be 100644 --- a/modules/markup/markdown/goldmark.go +++ b/modules/markup/markdown/goldmark.go @@ -177,6 +177,11 @@ func (g *ASTTransformer) Transform(node *ast.Document, reader text.Reader, pc pa newChild := NewTaskCheckBoxListItem(listItem) newChild.IsChecked = taskCheckBox.IsChecked newChild.SetAttributeString("class", []byte("task-list-item")) + segments := newChild.FirstChild().Lines() + if segments.Len() > 0 { + segment := segments.At(0) + newChild.SourcePosition = rc.MetaLength + segment.Start + } v.AppendChild(v, newChild) } } @@ -457,12 +462,7 @@ func (r *HTMLRenderer) renderTaskCheckBoxListItem(w util.BufWriter, source []byt } else { _, _ = w.WriteString("
  • ") } - _, _ = w.WriteString(` 0 { - segment := segments.At(0) - _, _ = w.WriteString(fmt.Sprintf(` data-source-position="%d"`, segment.Start)) - } + _, _ = w.WriteString(fmt.Sprintf(` + + + + + + + + + + +
    foo
    bar
    + +`, + }, + } + + for _, test := range testcases { + res, err := RenderString(&markup.RenderContext{Ctx: git.DefaultContext}, test.testcase) + assert.NoError(t, err, "Unexpected error in testcase: %q", test.testcase) + assert.Equal(t, test.expected, res, "Unexpected result in testcase %q", test.testcase) + } +} diff --git a/modules/markup/markdown/renderconfig.go b/modules/markup/markdown/renderconfig.go index 691df7431209a..417f2b2c3b772 100644 --- a/modules/markup/markdown/renderconfig.go +++ b/modules/markup/markdown/renderconfig.go @@ -20,6 +20,9 @@ type RenderConfig struct { TOC string // "false": hide, "side"/empty: in sidebar, "main"/"true": in main view Lang string yamlNode *yaml.Node + + // Used internally. Cannot be controlled by frontmatter. + MetaLength int } func renderMetaModeFromString(s string) markup.RenderMetaMode { From 164a8159cd38ebe5967474a96ceefc9284e3649e Mon Sep 17 00:00:00 2001 From: Jonathan Tran Date: Mon, 12 Jun 2023 12:55:04 -0400 Subject: [PATCH 2/4] Fix to write directly instead of creating intermediate string --- modules/markup/markdown/goldmark.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/markup/markdown/goldmark.go b/modules/markup/markdown/goldmark.go index 5a086305d94be..a3e76dd1f2ddc 100644 --- a/modules/markup/markdown/goldmark.go +++ b/modules/markup/markdown/goldmark.go @@ -462,7 +462,7 @@ func (r *HTMLRenderer) renderTaskCheckBoxListItem(w util.BufWriter, source []byt } else { _, _ = w.WriteString("
  • ") } - _, _ = w.WriteString(fmt.Sprintf(` Date: Mon, 12 Jun 2023 13:16:08 -0400 Subject: [PATCH 3/4] Fix metaLength to be private --- modules/markup/markdown/goldmark.go | 2 +- modules/markup/markdown/markdown.go | 2 +- modules/markup/markdown/renderconfig.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/markup/markdown/goldmark.go b/modules/markup/markdown/goldmark.go index a3e76dd1f2ddc..ff4e6b1bd0eb3 100644 --- a/modules/markup/markdown/goldmark.go +++ b/modules/markup/markdown/goldmark.go @@ -180,7 +180,7 @@ func (g *ASTTransformer) Transform(node *ast.Document, reader text.Reader, pc pa segments := newChild.FirstChild().Lines() if segments.Len() > 0 { segment := segments.At(0) - newChild.SourcePosition = rc.MetaLength + segment.Start + newChild.SourcePosition = rc.metaLength + segment.Start } v.AppendChild(v, newChild) } diff --git a/modules/markup/markdown/markdown.go b/modules/markup/markdown/markdown.go index f7fc33e975054..43885889d125d 100644 --- a/modules/markup/markdown/markdown.go +++ b/modules/markup/markdown/markdown.go @@ -192,7 +192,7 @@ func actualRender(ctx *markup.RenderContext, input io.Reader, output io.Writer) if metaLength < 0 { metaLength = 0 } - rc.MetaLength = metaLength + rc.metaLength = metaLength pc.Set(renderConfigKey, rc) diff --git a/modules/markup/markdown/renderconfig.go b/modules/markup/markdown/renderconfig.go index 417f2b2c3b772..f4c48d1b3d8f9 100644 --- a/modules/markup/markdown/renderconfig.go +++ b/modules/markup/markdown/renderconfig.go @@ -22,7 +22,7 @@ type RenderConfig struct { yamlNode *yaml.Node // Used internally. Cannot be controlled by frontmatter. - MetaLength int + metaLength int } func renderMetaModeFromString(s string) markup.RenderMetaMode { From 36f4caa3fcec472701f7711f9a535fc2020c92ca Mon Sep 17 00:00:00 2001 From: Jonathan Tran Date: Mon, 12 Jun 2023 17:00:17 -0400 Subject: [PATCH 4/4] Add runtime check of surrounding characters to prevent corruption --- web_src/js/markup/tasklist.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/web_src/js/markup/tasklist.js b/web_src/js/markup/tasklist.js index 0f03837baac0e..ad1c6964a757f 100644 --- a/web_src/js/markup/tasklist.js +++ b/web_src/js/markup/tasklist.js @@ -29,6 +29,14 @@ export function initMarkupTasklist() { const encoder = new TextEncoder(); const buffer = encoder.encode(oldContent); + // Indexes may fall off the ends and return undefined. + if (buffer[position - 1] !== '['.codePointAt(0) || + buffer[position] !== ' '.codePointAt(0) && buffer[position] !== 'x'.codePointAt(0) || + buffer[position + 1] !== ']'.codePointAt(0)) { + // Position is probably wrong. Revert and don't allow change. + checkbox.checked = !checkbox.checked; + throw new Error(`Expected position to be space or x and surrounded by brackets, but it's not: position=${position}`); + } buffer.set(encoder.encode(checkboxCharacter), position); const newContent = new TextDecoder().decode(buffer);