Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
MauiXamlRenderer.cs
1using SkiaSharp;
2using System.Globalization;
3using System.Text;
4using System.Xml;
11using Waher.Events;
12using Waher.Script;
15
17{
25 {
29 public readonly XmlWriter XmlOutput;
30
35
39 public bool Bold = false;
40
44 public bool Italic = false;
45
49 public bool StrikeThrough = false;
50
54 public bool Underline = false;
55
59 public bool Superscript = false;
60
64 public bool Subscript = false;
65
69 public bool Code = false;
70
74 public bool InLabel = false;
75
79 public string? Hyperlink = null;
80
85 public MauiXamlRenderer(XmlWriterSettings XmlSettings)
86 : base()
87 {
88 this.XmlOutput = XmlWriter.Create(this.Output, XmlSettings);
89 }
90
96 public MauiXamlRenderer(StringBuilder Output, XmlWriterSettings XmlSettings)
97 : base(Output)
98 {
99 this.XmlOutput = XmlWriter.Create(this.Output, XmlSettings);
100 }
101
103 public override void Dispose()
104 {
105 this.Dispose(true);
106 GC.SuppressFinalize(this);
107 }
108
109 private bool isDisposed;
110
114 protected virtual void Dispose(bool disposing)
115 {
116 if (this.isDisposed)
117 return;
118
119 if (disposing)
120 {
121 base.Dispose();
122 this.XmlOutput.Dispose();
123 }
124
125 this.isDisposed = true;
126 }
127
133 public override Task RenderDocument(MarkdownDocument Document, bool Inclusion)
134 {
135 this.Alignment = Waher.Content.Markdown.Model.TextAlignment.Left;
136 this.Bold = false;
137 this.Italic = false;
138 this.StrikeThrough = false;
139 this.Underline = false;
140 this.Superscript = false;
141 this.Subscript = false;
142 this.Code = false;
143 this.InLabel = false;
144 this.Hyperlink = null;
145
146 return base.RenderDocument(Document, Inclusion);
147 }
148
152 public override Task RenderDocumentHeader()
153 {
154 this.XmlOutput.WriteStartElement("VerticalStackLayout", "http://schemas.microsoft.com/dotnet/2021/maui");
155 this.XmlOutput.WriteAttributeString("xmlns", "x", null, "http://schemas.microsoft.com/winfx/2009/xaml");
156 this.XmlOutput.WriteAttributeString("xmlns", "ui", null, "clr-namespace:NeuroAccessMaui.UI");
157 this.XmlOutput.WriteAttributeString("Spacing", "0");
158
159 return Task.CompletedTask;
160 }
161
165 public override async Task RenderFootnotes()
166 {
168 int Nr;
169 int Row = 0;
170
171 this.XmlOutput.WriteStartElement("BoxView");
172 this.XmlOutput.WriteAttributeString("HeightRequest", "1");
173 this.XmlOutput.WriteAttributeString("BackgroundColor", "{AppThemeBinding Light={StaticResource NormalEditPlaceholderLight}, Dark={StaticResource NormalEditPlaceholderDark}}");
174 this.XmlOutput.WriteAttributeString("HorizontalOptions", "FillAndExpand");
175 this.XmlOutput.WriteAttributeString("Margin", SmallMargins(false, false, true, true));
176 this.XmlOutput.WriteEndElement();
177
178 this.XmlOutput.WriteStartElement("Grid");
179 this.XmlOutput.WriteAttributeString("RowSpacing", "0");
180 this.XmlOutput.WriteAttributeString("ColumnSpacing", "0");
181
182 this.XmlOutput.WriteStartElement("Grid.ColumnDefinitions");
183
184 this.XmlOutput.WriteStartElement("ColumnDefinition");
185 this.XmlOutput.WriteAttributeString("Width", "Auto");
186 this.XmlOutput.WriteEndElement();
187
188 this.XmlOutput.WriteStartElement("ColumnDefinition");
189 this.XmlOutput.WriteAttributeString("Width", "*");
190 this.XmlOutput.WriteEndElement();
191
192 this.XmlOutput.WriteEndElement();
193 this.XmlOutput.WriteStartElement("Grid.RowDefinitions");
194
195 foreach (string Key in this.Document.FootnoteOrder)
196 {
197 if ((this.Document?.TryGetFootnoteNumber(Key, out Nr) ?? false) &&
198 (this.Document?.TryGetFootnote(Key, out Footnote) ?? false) &&
200 {
201 this.XmlOutput.WriteStartElement("RowDefinition");
202 this.XmlOutput.WriteAttributeString("Height", "Auto");
203 this.XmlOutput.WriteEndElement();
204 }
205 }
206
207 this.XmlOutput.WriteEndElement();
208
209 if (this.Document is not null)
210 {
211 foreach (string Key in this.Document.FootnoteOrder)
212 {
213 if ((this.Document?.TryGetFootnoteNumber(Key, out Nr) ?? false) &&
214 (this.Document?.TryGetFootnote(Key, out Footnote) ?? false) &&
216 {
217 this.XmlOutput.WriteStartElement("ContentView");
218 this.XmlOutput.WriteAttributeString("Margin", "{StaticResource SmallMargins}");
219 this.XmlOutput.WriteAttributeString("Grid.Column", "0");
220 this.XmlOutput.WriteAttributeString("Grid.Row", Row.ToString(CultureInfo.InvariantCulture));
221 this.XmlOutput.WriteAttributeString("Scale", "0.75");
222 this.XmlOutput.WriteAttributeString("TranslationY", "-5");
223
224 this.XmlOutput.WriteStartElement("Label");
225 this.XmlOutput.WriteAttributeString("Text", Nr.ToString(CultureInfo.InvariantCulture));
226 this.XmlOutput.WriteEndElement();
227 this.XmlOutput.WriteEndElement();
228
229 this.XmlOutput.WriteStartElement("ContentView");
230 this.XmlOutput.WriteAttributeString("Grid.Column", "1");
231 this.XmlOutput.WriteAttributeString("Grid.Row", Row.ToString(CultureInfo.InvariantCulture));
232 await Footnote.Render(this);
233 this.XmlOutput.WriteEndElement();
234
235 Row++;
236 }
237 }
238 }
239
240 this.XmlOutput.WriteEndElement();
241 }
242
246 public override Task RenderDocumentFooter()
247 {
248 this.XmlOutput.WriteEndElement();
249 this.XmlOutput.Flush();
250
251 return Task.CompletedTask;
252 }
253
254 #region Span Elements
255
260 public override Task Render(Abbreviation Element)
261 {
262 return this.RenderChildren(Element);
263 }
264
269 public override Task Render(AutomaticLinkMail Element)
270 {
271 string? Bak = this.Hyperlink;
272 this.Hyperlink = "mailto:" + Element.EMail;
273 this.RenderSpan(this.Hyperlink);
274 this.Hyperlink = Bak;
275
276 return Task.CompletedTask;
277 }
278
283 public override Task Render(AutomaticLinkUrl Element)
284 {
285 string? Bak = this.Hyperlink;
286 this.Hyperlink = Element.URL;
287 this.RenderSpan(Element.URL);
288 this.Hyperlink = Bak;
289
290 return Task.CompletedTask;
291 }
292
297 public override async Task Render(Delete Element)
298 {
299 bool Bak = this.StrikeThrough;
300 this.StrikeThrough = true;
301
302 await this.RenderChildren(Element);
303
304 this.StrikeThrough = Bak;
305 }
306
311 public override Task Render(DetailsReference Element)
312 {
313 if (this.Document.Detail is not null)
314 return this.RenderDocument(this.Document.Detail, false);
315 else
316 return this.Render((MetaReference)Element);
317 }
318
323 public override async Task Render(EmojiReference Element)
324 {
325 if (this.InLabel)
326 this.RenderSpan(Element.Emoji.Unicode);
327 else
328 {
329 IEmojiSource EmojiSource = this.Document.EmojiSource;
330
331 if (EmojiSource is null)
332 this.RenderSpan(Element.Delimiter + Element.Emoji.ShortName + Element.Delimiter);
333 else if (!EmojiSource.EmojiSupported(Element.Emoji))
334 this.RenderSpan(Element.Emoji.Unicode);
335 else
336 {
338 await Multimedia.ImageContent.OutputMauiXaml(this.XmlOutput, Source);
339 }
340 }
341 }
342
347 public override async Task Render(Emphasize Element)
348 {
349 bool Bak = this.Italic;
350 this.Italic = true;
351
352 await this.RenderChildren(Element);
353
354 this.Italic = Bak;
355 }
356
361 public override async Task Render(FootnoteReference Element)
362 {
363 if (!(this.Document?.TryGetFootnote(Element.Key, out Footnote? Footnote) ?? false))
364 Footnote = null;
365
366 if (Element.AutoExpand && Footnote is not null)
367 await this.Render(Footnote);
368 else if (this.Document?.TryGetFootnoteNumber(Element.Key, out int Nr) ?? false)
369 {
370 bool Bak = this.Superscript;
371 this.Superscript = true;
372
373 this.RenderSpan(Nr.ToString(CultureInfo.InvariantCulture));
374
375 this.Superscript = Bak;
376
377 if (Footnote is not null)
378 Footnote.Referenced = true;
379 }
380 }
381
386 public override Task Render(HashTag Element)
387 {
388 this.RenderSpan(Element.Tag);
389 return Task.CompletedTask;
390 }
391
396 public override Task Render(HtmlEntity Element)
397 {
399 if (!string.IsNullOrEmpty(s))
400 this.RenderSpan(s);
401
402 return Task.CompletedTask;
403 }
404
409 public override Task Render(HtmlEntityUnicode Element)
410 {
411 this.RenderSpan(new string((char)Element.Code, 1));
412 return Task.CompletedTask;
413 }
414
419 public override Task Render(InlineCode Element)
420 {
421 bool Bak = this.Code;
422 this.Code = true;
423
424 this.RenderSpan(Element.Code);
425
426 this.Code = Bak;
427
428 return Task.CompletedTask;
429 }
430
435 public override Task Render(InlineHTML Element)
436 {
437 this.XmlOutput.WriteComment(Element.HTML);
438 return Task.CompletedTask;
439 }
440
445 public override async Task Render(InlineScript Element)
446 {
447 object Result = await Element.EvaluateExpression();
448 await this.RenderObject(Result, Element.AloneInParagraph, Element.Variables);
449 }
450
457 public async Task RenderObject(object? Result, bool AloneInParagraph, Variables Variables)
458 {
459 if (Result is null)
460 return;
461
462 string? s;
463
464 if (Result is XmlDocument Xml)
465 Result = await MarkdownDocument.TransformXml(Xml, Variables);
466 else if (Result is IToMatrix ToMatrix)
467 Result = ToMatrix.ToMatrix();
468
469 if (this.InLabel)
470 {
471 s = Result?.ToString();
472 if (!string.IsNullOrEmpty(s))
473 this.RenderSpan(Result?.ToString() ?? string.Empty);
474
475 return;
476 }
477
478 if (Result is Graph G)
479 {
480 PixelInformation Pixels = G.CreatePixels(Variables);
481 byte[] Bin = Pixels.EncodeAsPng();
482
483 s = "data:image/png;base64," + Convert.ToBase64String(Bin, 0, Bin.Length);
484
485 await Multimedia.ImageContent.OutputMauiXaml(this.XmlOutput, new Waher.Content.Emoji.ImageSource()
486 {
487 Url = s,
488 Width = Pixels.Width,
489 Height = Pixels.Height
490 });
491 }
492 else if (Result is SKImage Img)
493 {
494 using SKData Data = Img.Encode(SKEncodedImageFormat.Png, 100);
495 byte[] Bin = Data.ToArray();
496
497 s = "data:image/png;base64," + Convert.ToBase64String(Bin, 0, Bin.Length);
498
499 await Multimedia.ImageContent.OutputMauiXaml(this.XmlOutput, new Waher.Content.Emoji.ImageSource()
500 {
501 Url = s,
502 Width = Img.Width,
503 Height = Img.Height
504 });
505 }
506 else if (Result is MarkdownDocument Doc)
507 {
508 await this.RenderDocument(Doc, true); // Does not call ProcessAsyncTasks()
509 Doc.ProcessAsyncTasks();
510 }
511 else if (Result is MarkdownContent Markdown)
512 {
513 Doc = await MarkdownDocument.CreateAsync(Markdown.Markdown);
514 await this.RenderDocument(Doc, true); // Does not call ProcessAsyncTasks()
515 Doc.ProcessAsyncTasks();
516 }
517 else if (Result is Exception ex)
518 {
519 ex = Log.UnnestException(ex);
520
521 if (ex is AggregateException ex2)
522 {
523 foreach (Exception ex3 in ex2.InnerExceptions)
524 {
525 this.RenderContentView();
526 this.XmlOutput.WriteStartElement("Label");
527 this.XmlOutput.WriteAttributeString("LineBreakMode", "WordWrap");
528 this.XmlOutput.WriteAttributeString("TextColor", "Red");
529 this.XmlOutput.WriteValue(ex3.Message);
530 this.XmlOutput.WriteEndElement();
531 this.XmlOutput.WriteEndElement();
532 }
533 }
534 else
535 {
536 if (AloneInParagraph)
537 this.RenderContentView();
538
539 this.XmlOutput.WriteStartElement("Label");
540 this.XmlOutput.WriteAttributeString("LineBreakMode", "WordWrap");
541 this.XmlOutput.WriteAttributeString("TextColor", "Red");
542 this.XmlOutput.WriteValue(ex.Message);
543 this.XmlOutput.WriteEndElement();
544
545 if (AloneInParagraph)
546 this.XmlOutput.WriteEndElement();
547 }
548 }
549 else
550 {
551 if (AloneInParagraph)
552 this.RenderContentView();
553
554 this.XmlOutput.WriteStartElement("Label");
555 this.XmlOutput.WriteAttributeString("LineBreakMode", "WordWrap");
556
558 this.XmlOutput.WriteValue(Result.ToString());
559 this.XmlOutput.WriteEndElement();
560
561 if (AloneInParagraph)
562 this.XmlOutput.WriteEndElement();
563 }
564 }
565
570 public override Task Render(InlineText Element)
571 {
572 this.RenderSpan(Element.Value);
573 return Task.CompletedTask;
574 }
575
580 public override async Task Render(Insert Element)
581 {
582 bool Bak = this.Underline;
583 this.Underline = true;
584
585 await this.RenderChildren(Element);
586
587 this.Underline = Bak;
588 }
589
594 public override Task Render(LineBreak Element)
595 {
596 this.RenderSpan(Environment.NewLine);
597 return Task.CompletedTask;
598 }
599
604 public override async Task Render(Link Element)
605 {
606 string? Bak = this.Hyperlink;
607 this.Hyperlink = Element.Url;
608
609 await this.RenderChildren(Element);
610
611 this.Hyperlink = Bak;
612 }
613
618 public override async Task Render(LinkReference Element)
619 {
621
622 string? Bak = this.Hyperlink;
623
624 if (Multimedia is not null)
625 this.Hyperlink = Multimedia.Items[0].Url;
626
627 await this.RenderChildren(Element);
628
629 this.Hyperlink = Bak;
630 }
631
636 public override Task Render(MetaReference Element)
637 {
638 StringBuilder sb = new();
639 bool FirstOnRow = true;
640
641 if (Element.TryGetMetaData(out KeyValuePair<string, bool>[] Values))
642 {
643 foreach (KeyValuePair<string, bool> P in Values)
644 {
645 if (FirstOnRow)
646 FirstOnRow = false;
647 else
648 sb.Append(' ');
649
650 sb.Append(P.Key);
651 if (P.Value)
652 {
653 sb.Append(Environment.NewLine);
654 FirstOnRow = true;
655 }
656 }
657 }
658
659 this.RenderSpan(sb.ToString());
660
661 return Task.CompletedTask;
662 }
663
669 {
671 if (Renderer is null)
672 return this.RenderChildren(Element);
673 else
674 return Renderer.RenderMauiXaml(this, Element.Items, Element.Children, Element.AloneInParagraph, Element.Document);
675 }
676
681 public override Task Render(MultimediaReference Element)
682 {
684
685 if (Multimedia is not null)
686 {
688 if (Renderer is not null)
689 return Renderer.RenderMauiXaml(this, Multimedia.Items, Element.Children, Element.AloneInParagraph, Element.Document);
690 }
691
692 return this.RenderChildren(Element);
693 }
694
699 public override async Task Render(StrikeThrough Element)
700 {
701 bool Bak = this.StrikeThrough;
702 this.StrikeThrough = true;
703
704 await this.RenderChildren(Element);
705
706 this.StrikeThrough = Bak;
707 }
708
713 public override async Task Render(Strong Element)
714 {
715 bool Bak = this.Bold;
716 this.Bold = true;
717
718 await this.RenderChildren(Element);
719
720 this.Bold = Bak;
721 }
722
727 public override async Task Render(SubScript Element)
728 {
729 bool Bak = this.Subscript;
730 this.Subscript = true;
731
732 await this.RenderChildren(Element);
733
734 this.Subscript = Bak;
735 }
736
741 public override async Task Render(SuperScript Element)
742 {
743 bool Bak = this.Superscript;
744 this.Superscript = true;
745
746 await this.RenderChildren(Element);
747
748 this.Superscript = Bak;
749 }
750
755 public override async Task Render(Underline Element)
756 {
757 bool Bak = this.Underline;
758 this.Underline = true;
759
760 await this.RenderChildren(Element);
761
762 this.Underline = Bak;
763 }
764
765 #endregion
766
767 #region Block elements
768
773 public override async Task Render(BlockQuote Element)
774 {
775 this.XmlOutput.WriteStartElement("ContentView");
776 this.XmlOutput.WriteAttributeString("Padding", SmallMargins(true, false, true, true));
777
778 this.XmlOutput.WriteStartElement("Frame");
779 this.XmlOutput.WriteAttributeString("Padding", SmallMargins(true, true, false, false));
780 this.XmlOutput.WriteAttributeString("BorderColor", "{AppThemeBinding Light={StaticResource PrimaryForegroundLight}, Dark={StaticResource PrimaryForegroundDark}}");
781 // TODO: Border thickness
782
783 this.XmlOutput.WriteStartElement("VerticalStackLayout");
784
785 await this.RenderChildren(Element);
786
787 this.XmlOutput.WriteEndElement();
788 this.XmlOutput.WriteEndElement();
789 this.XmlOutput.WriteEndElement();
790 }
791
796 public override async Task Render(BulletList Element)
797 {
798 int Row = 0;
799 bool ParagraphBullet;
800
801 this.XmlOutput.WriteStartElement("ContentView");
802 this.XmlOutput.WriteAttributeString("Padding", SmallMargins(false, false, true, true));
803
804 this.XmlOutput.WriteStartElement("Grid");
805 this.XmlOutput.WriteAttributeString("RowSpacing", "0");
806 this.XmlOutput.WriteAttributeString("ColumnSpacing", "0");
807
808 this.XmlOutput.WriteStartElement("Grid.ColumnDefinitions");
809
810 this.XmlOutput.WriteStartElement("ColumnDefinition");
811 this.XmlOutput.WriteAttributeString("Width", "Auto");
812 this.XmlOutput.WriteEndElement();
813
814 this.XmlOutput.WriteStartElement("ColumnDefinition");
815 this.XmlOutput.WriteAttributeString("Width", "*");
816 this.XmlOutput.WriteEndElement();
817
818 this.XmlOutput.WriteEndElement();
819 this.XmlOutput.WriteStartElement("Grid.RowDefinitions");
820
821 foreach (MarkdownElement _ in Element.Children)
822 {
823 this.XmlOutput.WriteStartElement("RowDefinition");
824 this.XmlOutput.WriteAttributeString("Height", "Auto");
825 this.XmlOutput.WriteEndElement();
826 }
827
828 this.XmlOutput.WriteEndElement();
829
830 foreach (MarkdownElement E in Element.Children)
831 {
832 if (E is UnnumberedItem Item)
833 {
834 ParagraphBullet = !E.InlineSpanElement || E.OutsideParagraph;
835 GetMargins(E, out bool TopMargin, out bool BottomMargin);
836
837 this.RenderContentView(SmallMargins(false, true, TopMargin, BottomMargin));
838
839 this.XmlOutput.WriteAttributeString("Grid.Column", "0");
840 this.XmlOutput.WriteAttributeString("Grid.Row", Row.ToString(CultureInfo.InvariantCulture));
841
842 this.XmlOutput.WriteElementString("Label", "•");
843 this.XmlOutput.WriteEndElement();
844
845 this.XmlOutput.WriteStartElement("VerticalStackLayout");
846 this.XmlOutput.WriteAttributeString("Grid.Column", "1");
847 this.XmlOutput.WriteAttributeString("Grid.Row", Row.ToString(CultureInfo.InvariantCulture));
848
849 if (ParagraphBullet)
850 await E.Render(this);
851 else
852 await this.RenderLabel(Item, false);
853
854 this.XmlOutput.WriteEndElement();
855 }
856
857 Row++;
858 }
859
860 this.XmlOutput.WriteEndElement();
861 this.XmlOutput.WriteEndElement();
862 }
863
864 private static string SmallMargins(bool Left, bool Right, bool Top, bool Bottom)
865 {
866 StringBuilder sb = new();
867
868 sb.Append("{StaticResource ");
869
870 if (!(Left || Right || Top || Bottom))
871 sb.Append("No");
872 else
873 {
874 sb.Append("Small");
875
876 if (!(Left && Right && Top && Bottom))
877 {
878 if (Left)
879 sb.Append("Left");
880
881 if (Right)
882 sb.Append("Right");
883
884 if (Top)
885 sb.Append("Top");
886
887 if (Bottom)
888 sb.Append("Bottom");
889 }
890 }
891
892 sb.Append("Margins}");
893
894 return sb.ToString();
895 }
896
903 private static void GetMargins(MarkdownElement Element, out bool TopMargin, out bool BottomMargin)
904 {
905 if (Element.InlineSpanElement && !Element.OutsideParagraph)
906 {
907 TopMargin = false;
908 BottomMargin = false;
909 }
910 else if (Element is NestedBlock NestedBlock)
911 {
912 bool First = true;
913
914 TopMargin = BottomMargin = false;
915
917 {
918 if (First)
919 {
920 First = false;
921 GetMargins(E, out TopMargin, out BottomMargin);
922 }
923 else
924 GetMargins(E, out bool _, out BottomMargin);
925 }
926 }
927 else if (Element is MarkdownElementSingleChild SingleChild)
928 GetMargins(SingleChild.Child, out TopMargin, out BottomMargin);
929 else
930 {
931 TopMargin = true;
932 BottomMargin = true;
933 }
934 }
935
940 public override async Task Render(CenterAligned Element)
941 {
942 this.XmlOutput.WriteStartElement("VerticalStackLayout");
943
945 this.Alignment = Waher.Content.Markdown.Model.TextAlignment.Center;
946
947 await this.RenderChildren(Element);
948
949 this.Alignment = Bak;
950 this.XmlOutput.WriteEndElement();
951 }
952
957 public override async Task Render(CodeBlock Element)
958 {
960
961 if (Renderer is not null)
962 {
963 try
964 {
965 if (await Renderer.RenderMauiXaml(this, Element.Rows, Element.Language, Element.Indent, Element.Document))
966 return;
967 }
968 catch (Exception ex)
969 {
970 ex = Log.UnnestException(ex);
971
972 if (ex is AggregateException ex2)
973 {
974 foreach (Exception ex3 in ex2.InnerExceptions)
975 {
976 this.RenderContentView();
977 this.XmlOutput.WriteStartElement("Label");
978 this.XmlOutput.WriteAttributeString("LineBreakMode", "WordWrap");
979 this.XmlOutput.WriteAttributeString("TextColor", "Red");
980 this.XmlOutput.WriteValue(ex3.Message);
981 this.XmlOutput.WriteEndElement();
982 this.XmlOutput.WriteEndElement();
983 }
984 }
985 else
986 {
987 this.RenderContentView();
988 this.XmlOutput.WriteStartElement("Label");
989 this.XmlOutput.WriteAttributeString("LineBreakMode", "WordWrap");
990 this.XmlOutput.WriteAttributeString("TextColor", "Red");
991 this.XmlOutput.WriteValue(ex.Message);
992 this.XmlOutput.WriteEndElement();
993 this.XmlOutput.WriteEndElement();
994 }
995 }
996 }
997
998 this.RenderContentView();
999 this.XmlOutput.WriteStartElement("VerticalStackLayout");
1000
1001 int i;
1002
1003 for (i = Element.Start; i <= Element.End; i++)
1004 {
1005 this.XmlOutput.WriteStartElement("Label");
1006 this.XmlOutput.WriteAttributeString("LineBreakMode", "NoWrap");
1007 this.RenderLabelAlignment();
1008 this.XmlOutput.WriteAttributeString("FontFamily", "Courier New");
1009 this.XmlOutput.WriteAttributeString("Text", Element.Rows[i]);
1010 this.XmlOutput.WriteEndElement();
1011 }
1012
1013 this.XmlOutput.WriteEndElement();
1014 this.XmlOutput.WriteEndElement();
1015 }
1016
1021 public override Task Render(CommentBlock Element)
1022 {
1023 return Task.CompletedTask;
1024 }
1025
1030 public override async Task Render(DefinitionDescriptions Element)
1031 {
1032 MarkdownElement? Last = null;
1033
1034 foreach (MarkdownElement Description in Element.Children)
1035 Last = Description;
1036
1037 foreach (MarkdownElement Description in Element.Children)
1038 {
1039 if (Description.InlineSpanElement && !Description.OutsideParagraph)
1040 {
1041 this.RenderContentView();
1042
1043 this.XmlOutput.WriteStartElement("Label");
1044 this.XmlOutput.WriteAttributeString("LineBreakMode", "WordWrap");
1045 this.RenderLabelAlignment();
1046 this.XmlOutput.WriteAttributeString("TextType", "Html");
1047
1048 using (HtmlRenderer Renderer = new(new HtmlSettings()
1049 {
1050 XmlEntitiesOnly = true
1051 }, this.Document))
1052 {
1053 await Description.Render(Renderer);
1054 this.XmlOutput.WriteCData(Renderer.ToString());
1055 }
1056
1057 this.XmlOutput.WriteEndElement();
1058 this.XmlOutput.WriteEndElement();
1059 }
1060 else
1061 {
1062 this.XmlOutput.WriteStartElement("ContentView");
1063 this.XmlOutput.WriteAttributeString("Padding", SmallMargins(true, false, false, Description == Last));
1064
1065 this.XmlOutput.WriteStartElement("VerticalStackLayout");
1066 await Description.Render(this);
1067 this.XmlOutput.WriteEndElement();
1068
1069 this.XmlOutput.WriteEndElement();
1070 }
1071 }
1072 }
1073
1078 public override Task Render(DefinitionList Element)
1079 {
1080 return this.RenderChildren(Element);
1081 }
1082
1087 public override async Task Render(DefinitionTerms Element)
1088 {
1089 bool Top = true;
1090
1091 foreach (MarkdownElement Term in Element.Children)
1092 {
1093 this.RenderContentView(SmallMargins(true, true, Top, false));
1094
1095 bool BoldBak = this.Bold;
1096 this.Bold = true;
1097
1098 await this.RenderLabel(Term, true);
1099
1100 this.Bold = BoldBak;
1101 this.XmlOutput.WriteEndElement();
1102
1103 Top = false;
1104 }
1105 }
1106
1111 public override async Task Render(DeleteBlocks Element)
1112 {
1113 this.XmlOutput.WriteStartElement("ContentView");
1114 this.XmlOutput.WriteAttributeString("Padding", SmallMargins(true, false, true, true));
1115
1116 this.XmlOutput.WriteStartElement("Frame");
1117 this.XmlOutput.WriteAttributeString("Padding", SmallMargins(true, true, false, false));
1118 this.XmlOutput.WriteAttributeString("BorderColor", "{AppThemeBinding Light={StaticResource DeletedBorderLight}, Dark={StaticResource DeletedBorderDark}}");
1119 // TODO: Border thickness
1120
1121 this.XmlOutput.WriteStartElement("VerticalStackLayout");
1122
1123 foreach (MarkdownElement E in Element.Children)
1124 await E.Render(this);
1125
1126 this.XmlOutput.WriteEndElement();
1127 this.XmlOutput.WriteEndElement();
1128 this.XmlOutput.WriteEndElement();
1129 }
1130
1135 public override Task Render(Footnote Element)
1136 {
1137 return this.RenderChildren(Element);
1138 }
1139
1144 public override async Task Render(Header Element)
1145 {
1146 this.RenderContentView();
1147
1148 int Level = Math.Max(0, Math.Min(9, Element.Level));
1149
1150 this.XmlOutput.WriteStartElement("Label");
1151 this.XmlOutput.WriteAttributeString("LineBreakMode", "WordWrap");
1152 this.XmlOutput.WriteAttributeString("Style", "{StaticResource Header" + Level.ToString(CultureInfo.InvariantCulture) + "}");
1153 this.RenderLabelAlignment();
1154
1155 this.XmlOutput.WriteAttributeString("TextType", "Html");
1156
1157 using (HtmlRenderer Renderer = new(new HtmlSettings()
1158 {
1159 XmlEntitiesOnly = true
1160 }, this.Document))
1161 {
1162 await Renderer.RenderChildren(Element);
1163
1164 this.XmlOutput.WriteCData(Renderer.ToString());
1165 }
1166
1167 this.XmlOutput.WriteEndElement();
1168 this.XmlOutput.WriteEndElement();
1169 }
1170
1175 {
1176 switch (this.Alignment)
1177 {
1178 case Waher.Content.Markdown.Model.TextAlignment.Left:
1179 this.XmlOutput.WriteAttributeString("HorizontalTextAlignment", "Start");
1180 break;
1181
1182 case Waher.Content.Markdown.Model.TextAlignment.Right:
1183 this.XmlOutput.WriteAttributeString("HorizontalTextAlignment", "End");
1184 break;
1185
1186 case Waher.Content.Markdown.Model.TextAlignment.Center:
1187 this.XmlOutput.WriteAttributeString("HorizontalTextAlignment", "Center");
1188 break;
1189 }
1190 }
1191
1196 public override Task Render(HorizontalRule Element)
1197 {
1198 this.XmlOutput.WriteStartElement("BoxView");
1199 this.XmlOutput.WriteAttributeString("HeightRequest", "1");
1200 this.XmlOutput.WriteAttributeString("BackgroundColor", "{AppThemeBinding Light={StaticResource NormalEditPlaceholderLight}, Dark={StaticResource NormalEditPlaceholderDark}}");
1201 this.XmlOutput.WriteAttributeString("HorizontalOptions", "FillAndExpand");
1202 this.XmlOutput.WriteAttributeString("Margin", SmallMargins(false, false, true, true));
1203 this.XmlOutput.WriteEndElement();
1204
1205 return Task.CompletedTask;
1206 }
1207
1212 public override async Task Render(HtmlBlock Element)
1213 {
1214 this.RenderContentView();
1215
1216 this.XmlOutput.WriteStartElement("Label");
1217 this.XmlOutput.WriteAttributeString("LineBreakMode", "WordWrap");
1218 this.RenderLabelAlignment();
1219 this.XmlOutput.WriteAttributeString("TextType", "Html");
1220
1221 using HtmlRenderer Renderer = new(new HtmlSettings()
1222 {
1223 XmlEntitiesOnly = true
1224 }, this.Document);
1225
1226 await Renderer.RenderChildren(Element);
1227
1228 this.XmlOutput.WriteCData(Renderer.ToString());
1229
1230 this.XmlOutput.WriteEndElement();
1231 this.XmlOutput.WriteEndElement();
1232 }
1233
1238 public override async Task Render(InsertBlocks Element)
1239 {
1240 this.XmlOutput.WriteStartElement("ContentView");
1241 this.XmlOutput.WriteAttributeString("Padding", SmallMargins(true, false, true, true));
1242
1243 this.XmlOutput.WriteStartElement("Frame");
1244 this.XmlOutput.WriteAttributeString("Padding", SmallMargins(true, true, false, false));
1245 this.XmlOutput.WriteAttributeString("BorderColor", "{AppThemeBinding Light={StaticResource InsertedBorderLight}, Dark={StaticResource InsertedBorderDark}}");
1246 // TODO: Border thickness
1247
1248 this.XmlOutput.WriteStartElement("VerticalStackLayout");
1249
1250 await this.RenderChildren(Element);
1251
1252 this.XmlOutput.WriteEndElement();
1253 this.XmlOutput.WriteEndElement();
1254 this.XmlOutput.WriteEndElement();
1255 }
1256
1261 public override Task Render(InvisibleBreak Element)
1262 {
1263 return Task.CompletedTask;
1264 }
1265
1270 public override async Task Render(LeftAligned Element)
1271 {
1272 this.XmlOutput.WriteStartElement("VerticalStackLayout");
1273
1275 this.Alignment = Waher.Content.Markdown.Model.TextAlignment.Left;
1276
1277 await this.RenderChildren(Element);
1278
1279 this.Alignment = Bak;
1280 this.XmlOutput.WriteEndElement();
1281 }
1282
1287 public override async Task Render(MarginAligned Element)
1288 {
1289 this.XmlOutput.WriteStartElement("VerticalStackLayout");
1290
1292 this.Alignment = Waher.Content.Markdown.Model.TextAlignment.Left;
1293
1294 await this.RenderChildren(Element);
1295
1296 this.Alignment = Bak;
1297 this.XmlOutput.WriteEndElement();
1298 }
1299
1304 public override async Task Render(NestedBlock Element)
1305 {
1306 if (Element.HasOneChild)
1307 await Element.FirstChild.Render(this);
1308 else
1309 {
1310 HtmlSettings Settings = new()
1311 {
1312 XmlEntitiesOnly = true
1313 };
1314 HtmlRenderer? Html = null;
1315
1316 try
1317 {
1318 foreach (MarkdownElement E in Element.Children)
1319 {
1320 if (E.InlineSpanElement)
1321 {
1322 Html ??= new HtmlRenderer(Settings, this.Document);
1323 await E.Render(Html);
1324 }
1325 else
1326 {
1327 if (Html is not null)
1328 {
1329 this.XmlOutput.WriteStartElement("Label");
1330 this.XmlOutput.WriteAttributeString("LineBreakMode", "WordWrap");
1331 this.RenderLabelAlignment();
1332 this.XmlOutput.WriteAttributeString("TextType", "Html");
1333 this.XmlOutput.WriteCData(Html.ToString());
1334 this.XmlOutput.WriteEndElement();
1335
1336 Html.Dispose();
1337 Html = null;
1338 }
1339
1340 await E.Render(this);
1341 }
1342 }
1343
1344 if (Html is not null)
1345 {
1346 this.XmlOutput.WriteStartElement("Label");
1347 this.XmlOutput.WriteAttributeString("LineBreakMode", "WordWrap");
1348 this.RenderLabelAlignment();
1349 this.XmlOutput.WriteAttributeString("TextType", "Html");
1350 this.XmlOutput.WriteCData(Html.ToString());
1351 this.XmlOutput.WriteEndElement();
1352 }
1353 }
1354 finally
1355 {
1356 Html?.Dispose();
1357 }
1358 }
1359 }
1360
1365 public override Task Render(NumberedItem Element)
1366 {
1367 return this.RenderChild(Element);
1368 }
1369
1374 public override async Task Render(NumberedList Element)
1375 {
1376 int Expected = 0;
1377 int Row = 0;
1378 bool ParagraphBullet;
1379
1380 this.XmlOutput.WriteStartElement("ContentView");
1381 this.XmlOutput.WriteAttributeString("Padding", SmallMargins(false, false, true, true));
1382
1383 this.XmlOutput.WriteStartElement("Grid");
1384 this.XmlOutput.WriteAttributeString("RowSpacing", "0");
1385 this.XmlOutput.WriteAttributeString("ColumnSpacing", "0");
1386
1387 this.XmlOutput.WriteStartElement("Grid.ColumnDefinitions");
1388
1389 this.XmlOutput.WriteStartElement("ColumnDefinition");
1390 this.XmlOutput.WriteAttributeString("Width", "Auto");
1391 this.XmlOutput.WriteEndElement();
1392
1393 this.XmlOutput.WriteStartElement("ColumnDefinition");
1394 this.XmlOutput.WriteAttributeString("Width", "*");
1395 this.XmlOutput.WriteEndElement();
1396
1397 this.XmlOutput.WriteEndElement();
1398 this.XmlOutput.WriteStartElement("Grid.RowDefinitions");
1399
1400 foreach (MarkdownElement _ in Element.Children)
1401 {
1402 this.XmlOutput.WriteStartElement("RowDefinition");
1403 this.XmlOutput.WriteAttributeString("Height", "Auto");
1404 this.XmlOutput.WriteEndElement();
1405 }
1406
1407 this.XmlOutput.WriteEndElement();
1408
1409 foreach (MarkdownElement E in Element.Children)
1410 {
1411 if (E is BlockElementSingleChild Item)
1412 {
1413 Expected++;
1414
1415 ParagraphBullet = !E.InlineSpanElement || E.OutsideParagraph;
1416 GetMargins(E, out bool TopMargin, out bool BottomMargin);
1417
1418 this.RenderContentView(SmallMargins(false, true, TopMargin, BottomMargin));
1419 this.XmlOutput.WriteAttributeString("Grid.Column", "0");
1420 this.XmlOutput.WriteAttributeString("Grid.Row", Row.ToString(CultureInfo.InvariantCulture));
1421
1422 this.XmlOutput.WriteStartElement("Label");
1423
1424 if (Item is NumberedItem NumberedItem)
1425 this.XmlOutput.WriteValue((Expected = NumberedItem.Number).ToString(CultureInfo.InvariantCulture));
1426 else
1427 this.XmlOutput.WriteValue(Expected.ToString(CultureInfo.InvariantCulture));
1428
1429 this.XmlOutput.WriteValue(".");
1430 this.XmlOutput.WriteEndElement();
1431 this.XmlOutput.WriteEndElement();
1432
1433 this.XmlOutput.WriteStartElement("VerticalStackLayout");
1434 this.XmlOutput.WriteAttributeString("Grid.Column", "1");
1435 this.XmlOutput.WriteAttributeString("Grid.Row", Row.ToString(CultureInfo.InvariantCulture));
1436
1437 if (ParagraphBullet)
1438 await E.Render(this);
1439 else
1440 await this.RenderLabel(Item, false);
1441
1442 this.XmlOutput.WriteEndElement();
1443 }
1444
1445 Row++;
1446 }
1447
1448 this.XmlOutput.WriteEndElement();
1449 this.XmlOutput.WriteEndElement();
1450 }
1451
1456 public override async Task Render(Paragraph Element)
1457 {
1458 this.RenderContentView();
1459 await this.RenderLabel(Element, false);
1460 this.XmlOutput.WriteEndElement();
1461 }
1462
1463 internal async Task RenderLabel(MarkdownElement Element, bool IncludeElement)
1464 {
1465 bool HasLink = !Element.ForEach((E, _) =>
1466 {
1467 return !(
1468 E is AutomaticLinkMail ||
1469 E is AutomaticLinkUrl ||
1470 E is Link ||
1471 E is LinkReference);
1472 }, null);
1473
1474 this.XmlOutput.WriteStartElement("Label");
1475 this.XmlOutput.WriteAttributeString("LineBreakMode", "WordWrap");
1476 this.RenderLabelAlignment();
1477
1478 if (HasLink)
1479 {
1480 if (this.InLabel)
1481 {
1482 if (IncludeElement)
1483 await Element.Render(this);
1484 else
1485 await this.RenderChildren(Element);
1486 }
1487 else
1488 {
1489 this.InLabel = true;
1490
1491 this.XmlOutput.WriteStartElement("Label.FormattedText");
1492 this.XmlOutput.WriteStartElement("FormattedString");
1493
1494 if (IncludeElement)
1495 await Element.Render(this);
1496 else
1497 await this.RenderChildren(Element);
1498
1499 this.XmlOutput.WriteEndElement();
1500 this.XmlOutput.WriteEndElement();
1501
1502 this.InLabel = false;
1503 }
1504 }
1505 else
1506 {
1507 this.XmlOutput.WriteAttributeString("TextType", "Html");
1508
1509 if (this.Bold)
1510 this.XmlOutput.WriteAttributeString("FontAttributes", "Bold");
1511
1512 using HtmlRenderer Renderer = new(new HtmlSettings()
1513 {
1514 XmlEntitiesOnly = true
1515 }, this.Document);
1516
1517 if (IncludeElement)
1518 await Element.Render(Renderer);
1519 else
1520 await Renderer.RenderChildren(Element);
1521
1522 this.XmlOutput.WriteCData(Renderer.ToString());
1523 }
1524
1525 this.XmlOutput.WriteEndElement();
1526 }
1527
1528 internal void RenderSpan(string Text)
1529 {
1530 if (!this.InLabel)
1531 {
1532 this.XmlOutput.WriteStartElement("Label");
1533 this.XmlOutput.WriteAttributeString("LineBreakMode", "WordWrap");
1534 this.RenderLabelAlignment();
1535 this.XmlOutput.WriteStartElement("Label.FormattedText");
1536 this.XmlOutput.WriteStartElement("FormattedString");
1537 }
1538
1539 this.XmlOutput.WriteStartElement("Span");
1540
1541 if (this.Superscript)
1542 Text = TextRenderer.ToSuperscript(Text);
1543 else if (this.Subscript)
1544 Text = TextRenderer.ToSubscript(Text);
1545
1546 this.XmlOutput.WriteAttributeString("Text", Text);
1547
1548 if (this.Bold && this.Italic)
1549 this.XmlOutput.WriteAttributeString("FontAttributes", "Italic, Bold");
1550 else if (this.Bold)
1551 this.XmlOutput.WriteAttributeString("FontAttributes", "Bold");
1552 else if (this.Italic)
1553 this.XmlOutput.WriteAttributeString("FontAttributes", "Italic");
1554
1555 if (this.StrikeThrough && this.Underline)
1556 this.XmlOutput.WriteAttributeString("TextDecorations", "Strikethrough, Underline");
1557 else if (this.StrikeThrough)
1558 this.XmlOutput.WriteAttributeString("TextDecorations", "Strikethrough");
1559 else if (this.Underline)
1560 this.XmlOutput.WriteAttributeString("TextDecorations", "Underline");
1561
1562 if (this.Code)
1563 this.XmlOutput.WriteAttributeString("FontFamily", "Courier New");
1564
1565 if (this.Hyperlink is not null)
1566 {
1567 this.XmlOutput.WriteAttributeString("TextColor", "{AppThemeBinding Light={StaticResource AccentForegroundLight}, Dark={StaticResource AccentForegroundDark}}");
1568
1569 this.XmlOutput.WriteStartElement("Span.GestureRecognizers");
1570 this.XmlOutput.WriteStartElement("TapGestureRecognizer");
1571 this.XmlOutput.WriteAttributeString("Command", "{Binding HyperlinkClicked}");
1572 this.XmlOutput.WriteAttributeString("CommandParameter", this.Hyperlink);
1573 this.XmlOutput.WriteEndElement();
1574 this.XmlOutput.WriteEndElement();
1575 }
1576
1577 if (!this.InLabel)
1578 {
1579 this.XmlOutput.WriteEndElement();
1580 this.XmlOutput.WriteEndElement();
1581 this.XmlOutput.WriteEndElement();
1582 }
1583
1584 this.XmlOutput.WriteEndElement();
1585 }
1586
1587 internal void RenderContentView()
1588 {
1589 this.RenderContentView(this.Alignment, SmallMargins(false, false, true, true), null);
1590 }
1591
1592 internal void RenderContentView(string Margins)
1593 {
1594 this.RenderContentView(this.Alignment, Margins, null);
1595 }
1596
1597 internal void RenderContentView(Waher.Content.Markdown.Model.TextAlignment Alignment, string? Margins)
1598 {
1599 this.RenderContentView(Alignment, Margins, null);
1600 }
1601
1602 internal void RenderContentView(Waher.Content.Markdown.Model.TextAlignment Alignment, string? Margins, string? Style)
1603 {
1604 this.XmlOutput.WriteStartElement("ContentView");
1605
1606 if (!string.IsNullOrEmpty(Margins))
1607 this.XmlOutput.WriteAttributeString("Padding", Margins);
1608
1609 if (!string.IsNullOrEmpty(Style))
1610 this.XmlOutput.WriteAttributeString("Style", "{StaticResource " + Style + "}");
1611
1612 switch (Alignment)
1613 {
1614 case Waher.Content.Markdown.Model.TextAlignment.Center:
1615 this.XmlOutput.WriteAttributeString("HorizontalOptions", "Center");
1616 break;
1617
1618 case Waher.Content.Markdown.Model.TextAlignment.Left:
1619 this.XmlOutput.WriteAttributeString("HorizontalOptions", "Start");
1620 break;
1621
1622 case Waher.Content.Markdown.Model.TextAlignment.Right:
1623 this.XmlOutput.WriteAttributeString("HorizontalOptions", "End");
1624 break;
1625 }
1626 }
1627
1632 public override async Task Render(RightAligned Element)
1633 {
1634 this.XmlOutput.WriteStartElement("VerticalStackLayout");
1635
1637 this.Alignment = Waher.Content.Markdown.Model.TextAlignment.Right;
1638
1639 await this.RenderChildren(Element);
1640
1641 this.Alignment = Bak;
1642 this.XmlOutput.WriteEndElement();
1643 }
1644
1649 public override Task Render(Sections Element)
1650 {
1651 return this.RenderChildren(Element);
1652 }
1653
1658 public override Task Render(SectionSeparator Element)
1659 {
1660 this.XmlOutput.WriteStartElement("BoxView");
1661 this.XmlOutput.WriteAttributeString("HeightRequest", "1");
1662 this.XmlOutput.WriteAttributeString("BackgroundColor", "{AppThemeBinding Light={StaticResource NormalEditPlaceholderLight}, Dark={StaticResource NormalEditPlaceholderDark}}");
1663 this.XmlOutput.WriteAttributeString("HorizontalOptions", "FillAndExpand");
1664 this.XmlOutput.WriteAttributeString("Margin", SmallMargins(false, false, true, true));
1665 this.XmlOutput.WriteEndElement();
1666
1667 return Task.CompletedTask;
1668 }
1669
1674 public override async Task Render(Table Element)
1675 {
1676 int Column;
1677 int Row, NrRows;
1678 int RowNr = 0;
1679
1680 this.XmlOutput.WriteStartElement("ScrollView");
1681 this.XmlOutput.WriteAttributeString("Orientation", "Horizontal");
1682 this.XmlOutput.WriteStartElement("ContentView");
1683 this.XmlOutput.WriteAttributeString("Padding", SmallMargins(false, false, true, true));
1684
1685 this.XmlOutput.WriteStartElement("Grid");
1686 this.XmlOutput.WriteAttributeString("RowSpacing", "-2");
1687 this.XmlOutput.WriteAttributeString("ColumnSpacing", "-2");
1688
1689 // TODO: Tooltip/caption
1690
1691 this.XmlOutput.WriteStartElement("Grid.ColumnDefinitions");
1692
1693 for (Column = 0; Column < Element.Columns; Column++)
1694 {
1695 this.XmlOutput.WriteStartElement("ColumnDefinition");
1696 this.XmlOutput.WriteAttributeString("Width", "Auto");
1697 this.XmlOutput.WriteEndElement();
1698 }
1699
1700 this.XmlOutput.WriteEndElement();
1701 this.XmlOutput.WriteStartElement("Grid.RowDefinitions");
1702
1703 for (Row = 0, NrRows = Element.Rows.Length + Element.Headers.Length; Row < NrRows; Row++)
1704 {
1705 this.XmlOutput.WriteStartElement("RowDefinition");
1706 this.XmlOutput.WriteAttributeString("Height", "Auto");
1707 this.XmlOutput.WriteEndElement();
1708 }
1709
1710 this.XmlOutput.WriteEndElement();
1711
1712 for (Row = 0, NrRows = Element.Headers.Length; Row < NrRows; Row++, RowNr++)
1713 await this.Render(Element.Headers[Row], Element.HeaderCellAlignments[Row], RowNr, true, Element);
1714
1715 for (Row = 0, NrRows = Element.Rows.Length; Row < NrRows; Row++, RowNr++)
1716 await this.Render(Element.Rows[Row], Element.RowCellAlignments[Row], RowNr, false, Element);
1717
1718 this.XmlOutput.WriteEndElement();
1719 this.XmlOutput.WriteEndElement();
1720 this.XmlOutput.WriteEndElement();
1721
1722 }
1723
1724 private void ClearState()
1725 {
1726 this.Alignment = Waher.Content.Markdown.Model.TextAlignment.Left;
1727 this.Bold = false;
1728 this.Italic = false;
1729 this.StrikeThrough = false;
1730 this.Underline = false;
1731 this.Superscript = false;
1732 this.Subscript = false;
1733 this.Code = false;
1734 this.InLabel = false;
1735 this.Hyperlink = null;
1736 }
1737
1738 private StateBackup Backup()
1739 {
1740 return new StateBackup()
1741 {
1742 Alignment = this.Alignment,
1743 Bold = this.Bold,
1744 Italic = this.Italic,
1745 StrikeThrough = this.StrikeThrough,
1746 Underline = this.Underline,
1747 Superscript = this.Superscript,
1748 Subscript = this.Subscript,
1749 Code = this.Code,
1750 InLabel = this.InLabel,
1751 Hyperlink = this.Hyperlink
1752 };
1753 }
1754
1755 private void Restore(StateBackup Backup)
1756 {
1757 this.Alignment = Backup.Alignment;
1758 this.Bold = Backup.Bold;
1759 this.Italic = Backup.Italic;
1760 this.StrikeThrough = Backup.StrikeThrough;
1761 this.Underline = Backup.Underline;
1762 this.Superscript = Backup.Superscript;
1763 this.Subscript = Backup.Subscript;
1764 this.Code = Backup.Code;
1765 this.InLabel = Backup.InLabel;
1766 this.Hyperlink = Backup.Hyperlink;
1767 }
1768
1769 private class StateBackup
1770 {
1772 public bool Bold;
1773 public bool Italic;
1774 public bool StrikeThrough;
1775 public bool Underline;
1776 public bool Superscript;
1777 public bool Subscript;
1778 public bool Code;
1779 public bool InLabel;
1780 public string? Hyperlink;
1781 }
1782
1783 private async Task Render(MarkdownElement[] CurrentRow, Waher.Content.Markdown.Model.TextAlignment?[] CellAlignments,
1784 int RowNr, bool Bold, Table Element)
1785 {
1788 int Column;
1789 int NrColumns = Element.Columns;
1790 int ColSpan;
1791 StateBackup Bak = this.Backup();
1792
1793 this.ClearState();
1794
1795 for (Column = 0; Column < NrColumns; Column++)
1796 {
1797 E = CurrentRow[Column];
1798 if (E is null)
1799 continue;
1800
1801 TextAlignment = CellAlignments[Column] ?? Element.ColumnAlignments[Column];
1802 ColSpan = Column + 1;
1803 while (ColSpan < NrColumns && CurrentRow[ColSpan] is null)
1804 ColSpan++;
1805
1806 ColSpan -= Column;
1807
1808 this.XmlOutput.WriteStartElement("Frame");
1809
1810 if ((RowNr & 1) == 0)
1811 this.XmlOutput.WriteAttributeString("Style", "{StaticResource TableCellEven}");
1812 else
1813 this.XmlOutput.WriteAttributeString("Style", "{StaticResource TableCellOdd}");
1814
1815 this.XmlOutput.WriteAttributeString("Grid.Column", Column.ToString(CultureInfo.InvariantCulture));
1816 this.XmlOutput.WriteAttributeString("Grid.Row", RowNr.ToString(CultureInfo.InvariantCulture));
1817
1818 if (ColSpan > 1)
1819 this.XmlOutput.WriteAttributeString("Grid.ColumnSpan", ColSpan.ToString(CultureInfo.InvariantCulture));
1820
1821 if (E.InlineSpanElement)
1822 {
1823 this.RenderContentView(TextAlignment, null, "TableCell");
1824
1825 this.Bold = Bold;
1826 await this.RenderLabel(E, true);
1827 this.Bold = false;
1828
1829 this.XmlOutput.WriteEndElement(); // Paragraph
1830 }
1831 else
1832 {
1833 this.XmlOutput.WriteStartElement("ContentView");
1834 this.XmlOutput.WriteAttributeString("Style", null, "{StaticResource TableCell}");
1835
1836 this.XmlOutput.WriteStartElement("VerticalStackLayout");
1837 await E.Render(this);
1838 this.XmlOutput.WriteEndElement(); // StackLayout
1839
1840 this.XmlOutput.WriteEndElement(); // ContentView
1841 }
1842
1843 this.XmlOutput.WriteEndElement(); // Frame
1844 }
1845
1846 this.Restore(Bak);
1847 }
1848
1853 public override Task Render(TaskItem Element)
1854 {
1855 return this.RenderChild(Element);
1856 }
1857
1862 public override async Task Render(TaskList Element)
1863 {
1864 int Row = 0;
1865 bool ParagraphBullet;
1866
1867 this.XmlOutput.WriteStartElement("ContentView");
1868 this.XmlOutput.WriteAttributeString("Padding", SmallMargins(false, false, true, true));
1869
1870 this.XmlOutput.WriteStartElement("Grid");
1871 this.XmlOutput.WriteAttributeString("RowSpacing", "0");
1872 this.XmlOutput.WriteAttributeString("ColumnSpacing", "0");
1873
1874 this.XmlOutput.WriteStartElement("Grid.ColumnDefinitions");
1875
1876 this.XmlOutput.WriteStartElement("ColumnDefinition");
1877 this.XmlOutput.WriteAttributeString("Width", "Auto");
1878 this.XmlOutput.WriteEndElement();
1879
1880 this.XmlOutput.WriteStartElement("ColumnDefinition");
1881 this.XmlOutput.WriteAttributeString("Width", "*");
1882 this.XmlOutput.WriteEndElement();
1883
1884 this.XmlOutput.WriteEndElement();
1885 this.XmlOutput.WriteStartElement("Grid.RowDefinitions");
1886
1887 foreach (MarkdownElement _ in Element.Children)
1888 {
1889 this.XmlOutput.WriteStartElement("RowDefinition");
1890 this.XmlOutput.WriteAttributeString("Height", "Auto");
1891 this.XmlOutput.WriteEndElement();
1892 }
1893
1894 this.XmlOutput.WriteEndElement();
1895
1896 foreach (MarkdownElement E in Element.Children)
1897 {
1898 if (E is TaskItem TaskItem)
1899 {
1900 ParagraphBullet = !E.InlineSpanElement || E.OutsideParagraph;
1901 GetMargins(E, out bool TopMargin, out bool BottomMargin);
1902
1903 if (TaskItem.IsChecked)
1904 {
1905 this.RenderContentView(SmallMargins(false, true, TopMargin, BottomMargin));
1906 this.XmlOutput.WriteAttributeString("Grid.Column", "0");
1907 this.XmlOutput.WriteAttributeString("Grid.Row", Row.ToString(CultureInfo.InvariantCulture));
1908
1909 this.XmlOutput.WriteElementString("Label", "✓");
1910 this.XmlOutput.WriteEndElement();
1911 }
1912
1913 this.XmlOutput.WriteStartElement("VerticalStackLayout");
1914 this.XmlOutput.WriteAttributeString("Grid.Column", "1");
1915 this.XmlOutput.WriteAttributeString("Grid.Row", Row.ToString(CultureInfo.InvariantCulture));
1916
1917 if (ParagraphBullet)
1918 await E.Render(this);
1919 else
1920 await this.RenderLabel(TaskItem, false);
1921
1922 this.XmlOutput.WriteEndElement();
1923 }
1924
1925 Row++;
1926 }
1927
1928 this.XmlOutput.WriteEndElement();
1929 this.XmlOutput.WriteEndElement();
1930 }
1931
1936 public override Task Render(UnnumberedItem Element)
1937 {
1938 return this.RenderChild(Element);
1939 }
1940
1941 #endregion
1942
1943 }
1944}
Renders XAML (Maui flavour) from a Markdown document.
override Task RenderDocumentHeader()
Renders the document header.
override async Task Render(Emphasize Element)
Renders Element .
override async Task Render(Underline Element)
Renders Element .
override async Task Render(NestedBlock Element)
Renders Element .
override Task Render(TaskItem Element)
Renders Element .
override async Task Render(TaskList Element)
Renders Element .
void RenderLabelAlignment()
Writes a text-alignment attribute to a Maui label element.
override Task Render(InlineText Element)
Renders Element .
override async Task Render(DeleteBlocks Element)
Renders Element .
override Task Render(HtmlEntity Element)
Renders Element .
override async Task Render(Table Element)
Renders Element .
override Task Render(AutomaticLinkMail Element)
Renders Element .
override async Task Render(Delete Element)
Renders Element .
override async Task Render(DefinitionTerms Element)
Renders Element .
override Task Render(HashTag Element)
Renders Element .
virtual void Dispose(bool disposing)
IDisposable.Dispose
override Task Render(Footnote Element)
Renders Element .
override Task Render(HorizontalRule Element)
Renders Element .
Waher.Content.Markdown.Model.TextAlignment Alignment
Current text-alignment.
override async Task Render(FootnoteReference Element)
Renders Element .
override Task Render(CommentBlock Element)
Renders Element .
override Task Render(MultimediaReference Element)
Renders Element .
override async Task Render(InlineScript Element)
Renders Element .
override async Task Render(BlockQuote Element)
Renders Element .
override async Task Render(NumberedList Element)
Renders Element .
override async Task Render(RightAligned Element)
Renders Element .
override async Task Render(DefinitionDescriptions Element)
Renders Element .
override async Task Render(EmojiReference Element)
Renders Element .
override async Task Render(HtmlBlock Element)
Renders Element .
override async Task Render(Paragraph Element)
Renders Element .
override async Task Render(SubScript Element)
Renders Element .
override Task Render(Abbreviation Element)
Renders Element .
bool InLabel
If rendering is inside a label.
override async Task Render(LinkReference Element)
Renders Element .
override Task Render(UnnumberedItem Element)
Renders Element .
override Task Render(DetailsReference Element)
Renders Element .
MauiXamlRenderer(StringBuilder Output, XmlWriterSettings XmlSettings)
Renders XAML (Maui flavour) from a Markdown document.
override Task Render(LineBreak Element)
Renders Element .
override Task Render(InlineHTML Element)
Renders Element .
async Task RenderObject(object? Result, bool AloneInParagraph, Variables Variables)
Generates Maui XAML from Script output.
override Task Render(Sections Element)
Renders Element .
override Task Render(Waher.Content.Markdown.Model.SpanElements.Multimedia Element)
Renders Element .
override async Task Render(Insert Element)
Renders Element .
override async Task Render(InsertBlocks Element)
Renders Element .
override Task Render(MetaReference Element)
Renders Element .
override async Task RenderFootnotes()
Renders footnotes.
override Task RenderDocumentFooter()
Renders the document header.
override async Task Render(CenterAligned Element)
Renders Element .
override Task Render(DefinitionList Element)
Renders Element .
override Task Render(AutomaticLinkUrl Element)
Renders Element .
override async Task Render(StrikeThrough Element)
Renders Element .
override Task Render(SectionSeparator Element)
Renders Element .
string? Hyperlink
Link, if rendering a hyperlink, null otherwise.
override Task Render(NumberedItem Element)
Renders Element .
override async Task Render(BulletList Element)
Renders Element .
override Task Render(InlineCode Element)
Renders Element .
override async Task Render(SuperScript Element)
Renders Element .
override Task Render(HtmlEntityUnicode Element)
Renders Element .
override async Task Render(Header Element)
Renders Element .
MauiXamlRenderer(XmlWriterSettings XmlSettings)
Renders XAML (Maui flavour) from a Markdown document.
override async Task Render(Link Element)
Renders Element .
override async Task Render(LeftAligned Element)
Renders Element .
override Task Render(InvisibleBreak Element)
Renders Element .
override async Task Render(CodeBlock Element)
Renders Element .
bool StrikeThrough
If text is stricken through
override async Task Render(Strong Element)
Renders Element .
override async Task Render(MarginAligned Element)
Renders Element .
override Task RenderDocument(MarkdownDocument Document, bool Inclusion)
Renders a document.
override void Dispose()
Disposes of the renderer.
string ShortName
Emoji short name.
string Unicode
Unicode representation of emoji.
Contains information about an emoji image.
Definition: ImageSource.cs:9
static string EntityToCharacter(string Entity)
Converts an HTML entity into a character.
Definition: HtmlEntity.cs:71
Class that can be used to encapsulate Markdown to be returned from a Web Service, bypassing any encod...
Contains a markdown document. This markdown document class supports original markdown,...
static async Task< object > TransformXml(XmlDocument Xml, Variables Variables)
Transforms XML to an object that is easier to visualize.
IEnumerable< string > FootnoteOrder
Order of footnotes.
IEmojiSource EmojiSource
Source for emojis in the document.
MarkdownDocument Detail
Detail document of a master document.
Multimedia GetReference(string Label)
Gets the multimedia information referenced by a label.
static Task< MarkdownDocument > CreateAsync(string MarkdownText, params Type[] TransparentExceptionTypes)
Contains a markdown document. This markdown document class supports original markdown,...
Abstract base class for block elements with one child.
Represents a block quote in a markdown document.
Definition: BlockQuote.cs:11
Represents a bullet list in a markdown document.
Definition: BulletList.cs:11
Represents a center-aligned set of blocks in a markdown document.
Represents a code block in a markdown document.
Definition: CodeBlock.cs:16
Represents a comment block in a markdown document.
Definition: CommentBlock.cs:10
Represents a definition list in a markdown document.
Represents inserted blocks in a markdown document.
Definition: DeleteBlocks.cs:11
override Task Render(IRenderer Output)
Renders the element.
bool Referenced
If the Footnote has been referenced during rendering, and therefore needs to be shown at the end of t...
Definition: Footnote.cs:51
Represents a header in a markdown document.
Definition: Header.cs:15
Represents a block of HTML in a markdown document.
Definition: HtmlBlock.cs:11
Represents inserted blocks in a markdown document.
Definition: InsertBlocks.cs:11
Represents a left-aligned set of blocks in a markdown document.
Definition: LeftAligned.cs:11
Represents a margin-aligned set of blocks in a markdown document.
Represents a nested block with no special formatting rules in a markdown document.
Definition: NestedBlock.cs:11
Represents a numbered item in an ordered list.
Definition: NumberedItem.cs:10
Represents a numbered list in a markdown document.
Definition: NumberedList.cs:11
Represents a paragraph in a markdown document.
Definition: Paragraph.cs:11
Represents a right-aligned set of blocks in a markdown document.
Definition: RightAligned.cs:11
Represents a sequence of sections.
Definition: Sections.cs:11
Represents a table in a markdown document.
Definition: Table.cs:11
TextAlignment[] ColumnAlignments
Table column alignments.
Definition: Table.cs:64
override IEnumerable< MarkdownElement > Children
Any children of the element.
Definition: Table.cs:100
MarkdownElement[][] Headers
Headers in table.
Definition: Table.cs:54
TextAlignment?[][] RowCellAlignments
Row cell alignments in table.
Definition: Table.cs:79
TextAlignment?[][] HeaderCellAlignments
Header cell alignments in table.
Definition: Table.cs:74
MarkdownElement[][] Rows
Rows in table.
Definition: Table.cs:59
Represents a task item in a task list.
Definition: TaskItem.cs:10
bool IsChecked
If the item is checked or not.
Definition: TaskItem.cs:31
Represents a task list in a markdown document.
Definition: TaskList.cs:11
Represents an unnumbered item in an ordered list.
override IEnumerable< MarkdownElement > Children
Any children of the element.
bool HasOneChild
If the element has only one child.
MarkdownElement FirstChild
First child, or null if none.
Abstract base class for all markdown elements.
virtual bool ForEach(MarkdownElementHandler Callback, object State)
Loops through all child-elements for the element.
abstract Task Render(IRenderer Output)
Renders the element.
virtual IEnumerable< MarkdownElement > Children
Any children of the element.
abstract bool InlineSpanElement
If the element is an inline span element.
virtual bool OutsideParagraph
If element, parsed as a span element, can stand outside of a paragraph if alone in it.
MarkdownDocument Document
Markdown document.
Abstract base class for all markdown elements with one child element.
string Delimiter
Delimiter string used to identify emoji.
int Level
Level (number of colons used to define the emoji)
bool AutoExpand
If the footnote should automatically be expanded when rendered, if format supports auto-expansion.
Represents an HTML entity in Unicode format.
bool AloneInParagraph
If the element is alone in a paragraph.
Definition: InlineScript.cs:55
async Task< object > EvaluateExpression()
Evaluates the script expression.
Definition: InlineScript.cs:71
bool TryGetMetaData(out KeyValuePair< string, bool >[] Values)
Tries to get meta-data from the document.
MultimediaItem[] Items
Multimedia items.
Definition: Multimedia.cs:40
bool AloneInParagraph
If the element is alone in a paragraph.
Renders HTML from a Markdown document.
Definition: HtmlRenderer.cs:24
Contains settings that the HTML export uses to customize HTML output.
Definition: HtmlSettings.cs:7
Abstract base class for Markdown renderers.
Definition: Renderer.cs:14
readonly StringBuilder Output
Renderer output.
Definition: Renderer.cs:18
Task RenderChild(MarkdownElementSingleChild Element)
Renders the child of Element .
Definition: Renderer.cs:175
async Task RenderChildren(MarkdownElementChildren Element)
Renders the children of Element .
Definition: Renderer.cs:147
override string ToString()
Returns the renderer output.
Definition: Renderer.cs:130
virtual void Dispose()
Disposes of the renderer.
Definition: Renderer.cs:65
MarkdownDocument Document
Reference to Markdown document being processed.
Definition: Renderer.cs:23
Renders plain text from a Markdown document.
Definition: TextRenderer.cs:16
static string ToSubscript(string s)
Converts a string to subscript (as far as it goes).
static string ToSuperscript(string s)
Converts a string to superscript (as far as it goes).
Static class managing the application event log. Applications and services log events on this static ...
Definition: Log.cs:13
static Exception UnnestException(Exception Exception)
Unnests an exception, to extract the relevant inner exception.
Definition: Log.cs:818
Base class for graphs.
Definition: Graph.cs:79
Contains pixel information
virtual byte[] EncodeAsPng()
Encodes the pixels into a binary PNG image.
ToMatrix(ScriptNode Operand, bool NullCheck, int Start, int Length, Expression Expression)
To-Matrix operator.
Definition: ToMatrix.cs:22
Collection of variables.
Definition: Variables.cs:25
Interface for multimedia content Maui XAML renderers.
Interface for Emoji sources. Emoji sources provide emojis to content providers.
Definition: IEmojiSource.cs:12
Task< IImageSource > GetImageSource(EmojiInfo Emoji)
Gets the image source of an emoji.
bool EmojiSupported(EmojiInfo Emoji)
If the emoji is supported by the emoji source.
Contains information about an emoji image.
Definition: IImageSource.cs:9
Interface for objects that can be converted into matrices.
Definition: IToMatrix.cs:9
TextAlignment
Text alignment of contents.
Definition: App.xaml.cs:4