MdXaml
MdXaml copied to clipboard
New Plugin: CheckBox
I created this new plugin to display checkboxes defined by [ ] and [x] in markdown
You may include this in the repo and release a nuget for it ;)
You may also update it to reflect your code style or add new features.
Sadly the plugin api doesn't provide the original index of the text span a parser is parsing. So I had to add a wild hack to be able to ensure the checkbox can update the markdown at the correct place
public class CheckboxPluginSetup : IPluginSetup
{
public void Setup(MdXamlPlugins plugins) => plugins.Inline.Add(new CheckboxInlineParser());
}
public class CheckboxInlineParser : IInlineParser
{
public CheckboxInlineParser()
{
this.FirstMatchPattern = new Regex(@"\[(?<value>[ |x])\]\s*(?<caption>[^\n|[]*)");
}
public Regex FirstMatchPattern { get; }
public IEnumerable<Inline> Parse(string text, Match firstMatch, IMarkdown engine, out int parseTextBegin, out int parseTextEnd)
{
parseTextBegin = firstMatch.Index;
parseTextEnd = firstMatch.Index + firstMatch.Length;
CheckBox chk = new()
{
IsChecked = "x".Equals(firstMatch.Groups["value"].Value, StringComparison.InvariantCultureIgnoreCase),
};
chk.Checked += (sender, e) => this.ReflectChkChangeInMarkdown(sender as CheckBox, true, firstMatch.Value);
chk.Unchecked += (sender, e) => this.ReflectChkChangeInMarkdown(sender as CheckBox, false, firstMatch.Value);
chk.Loaded += (sender, e) => this.UpdateChkEnabled(sender as CheckBox, firstMatch.Value);
if (firstMatch.Groups["caption"].Value is string caption && !string.IsNullOrEmpty(caption))
{
chk.Content = new FlowDocumentScrollViewer()
{
Document = engine.Transform(caption),
HorizontalScrollBarVisibility = ScrollBarVisibility.Hidden,
VerticalScrollBarVisibility = ScrollBarVisibility.Hidden,
Focusable = false
};
}
StackPanel sp = new();
sp.Children.Add(chk);
return new Inline[] { new InlineUIContainer(sp) };
}
private void UpdateChkEnabled(CheckBox chk, string text)
{
if (this.FindParentMarkdownViewer(chk) is not MarkdownScrollViewer viewer)
{
chk.IsEnabled = false;
}
else
{
chk.IsEnabled = this.UniqueIndex(viewer.Markdown, text) >=0;
}
}
private void ReflectChkChangeInMarkdown(DependencyObject chk, bool isChecked, string text)
{
if (this.FindParentMarkdownViewer(chk) is not MarkdownScrollViewer viewer)
{
return;
}
string markdown = viewer.Markdown;
int startIndex = this.UniqueIndex(markdown, text);
if (startIndex == -1)
{
// Not unique
return;
}
StringBuilder sb = new(viewer.Markdown);
sb[startIndex + 1] = isChecked ? 'x' : ' ';
viewer.Markdown = sb.ToString();
}
private MarkdownScrollViewer FindParentMarkdownViewer(DependencyObject child)
{
var parent = VisualTreeHelper.GetParent(child);
while (parent is not MarkdownScrollViewer and not null)
{
parent = VisualTreeHelper.GetParent(parent);
}
if (parent is not MarkdownScrollViewer viewer)
{
return null;
}
return viewer;
}
private int UniqueIndex(string markdown, string text)
{
int firstIndex = markdown.IndexOf(text);
if (firstIndex == -1)
{
// Not found
return -1;
}
int secondIndex = markdown.IndexOf(text, firstIndex + 1);
if (secondIndex != -1)
{
// Second hit
return -1;
}
return firstIndex;
}
}
Thanks a lot, this is an excellent example on how to write a custom plugin ;)
Hi, thank you for the plugin. I just connected it to my project and tested it. It has some problems, like when I check the checkbox in a so-called "Markdown view", and then I come back to the text, it doesn't affect the text itself, the [ ] is still without an x, moreover, when I put more checkboxes in my list, they do not appear in the "Markdown view". I am writing something like an obsidian replica just for fun. Gonna try to solve this problem in a very simple way. Thank you so much again!!!!!!!!!
Hi, thank you for the plugin. I just connected it to my project and tested it. It has some problems, like when I check the checkbox in a so-called "Markdown view", and then I come back to the text, it doesn't affect the text itself, the [ ] is still without an x, moreover, when I put more checkboxes in my list, they do not appear in the "Markdown view". I am writing something like an obsidian replica just for fun. Gonna try to solve this problem in a very simple way. Thank you so much again!!!!!!!!!
I just disabled the possibility of checking the checkbox in a "Markdown view". Works fine for me