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
157 // TODO: test change. OLD: this.XmlOutput.WriteAttributeString("xmlns", "ui", null, "clr-namespace:NeuroAccessMaui.UI");
158 string UiAssembly = typeof(NeuroAccessMaui.UI.Geometries).Assembly.GetName().Name ?? "NeuroAccessMaui";
159 this.XmlOutput.WriteAttributeString("xmlns", "ui", null, $"clr-namespace:NeuroAccessMaui.UI;assembly={UiAssembly}");
160
161 this.XmlOutput.WriteAttributeString("Spacing", "0");
162
163 return Task.CompletedTask;
164 }
165
169 public override async Task RenderFootnotes()
170 {
172 int Nr;
173 int Row = 0;
174
175 this.XmlOutput.WriteStartElement("BoxView");
176 this.XmlOutput.WriteAttributeString("HeightRequest", "1");
177 this.XmlOutput.WriteAttributeString("BackgroundColor", "{DynamicResource InputFieldsContentSecondary}");
178 this.XmlOutput.WriteAttributeString("HorizontalOptions", "Fill");
179 this.XmlOutput.WriteAttributeString("Margin", SmallMargins(false, false, true, true));
180 this.XmlOutput.WriteEndElement();
181
182 this.XmlOutput.WriteStartElement("Grid");
183 this.XmlOutput.WriteAttributeString("RowSpacing", "0");
184 this.XmlOutput.WriteAttributeString("ColumnSpacing", "0");
185
186 this.XmlOutput.WriteStartElement("Grid.ColumnDefinitions");
187
188 this.XmlOutput.WriteStartElement("ColumnDefinition");
189 this.XmlOutput.WriteAttributeString("Width", "Auto");
190 this.XmlOutput.WriteEndElement();
191
192 this.XmlOutput.WriteStartElement("ColumnDefinition");
193 this.XmlOutput.WriteAttributeString("Width", "*");
194 this.XmlOutput.WriteEndElement();
195
196 this.XmlOutput.WriteEndElement();
197 this.XmlOutput.WriteStartElement("Grid.RowDefinitions");
198
199 foreach (string Key in this.Document.FootnoteOrder)
200 {
201 if ((this.Document?.TryGetFootnoteNumber(Key, out Nr) ?? false) &&
202 (this.Document?.TryGetFootnote(Key, out Footnote) ?? false) &&
204 {
205 this.XmlOutput.WriteStartElement("RowDefinition");
206 this.XmlOutput.WriteAttributeString("Height", "Auto");
207 this.XmlOutput.WriteEndElement();
208 }
209 }
210
211 this.XmlOutput.WriteEndElement();
212
213 if (this.Document is not null)
214 {
215 foreach (string Key in this.Document.FootnoteOrder)
216 {
217 if ((this.Document?.TryGetFootnoteNumber(Key, out Nr) ?? false) &&
218 (this.Document?.TryGetFootnote(Key, out Footnote) ?? false) &&
220 {
221 this.XmlOutput.WriteStartElement("ContentView");
222 this.XmlOutput.WriteAttributeString("Margin", "{DynamicResource SmallMargins}");
223 this.XmlOutput.WriteAttributeString("Grid.Column", "0");
224 this.XmlOutput.WriteAttributeString("Grid.Row", Row.ToString(CultureInfo.InvariantCulture));
225 this.XmlOutput.WriteAttributeString("Scale", "0.75");
226 this.XmlOutput.WriteAttributeString("TranslationY", "-5");
227
228 this.XmlOutput.WriteStartElement("Label");
229 this.XmlOutput.WriteAttributeString("Text", Nr.ToString(CultureInfo.InvariantCulture));
230 this.XmlOutput.WriteEndElement();
231 this.XmlOutput.WriteEndElement();
232
233 this.XmlOutput.WriteStartElement("ContentView");
234 this.XmlOutput.WriteAttributeString("Grid.Column", "1");
235 this.XmlOutput.WriteAttributeString("Grid.Row", Row.ToString(CultureInfo.InvariantCulture));
236 await Footnote.Render(this);
237 this.XmlOutput.WriteEndElement();
238
239 Row++;
240 }
241 }
242 }
243
244 this.XmlOutput.WriteEndElement();
245 }
246
250 public override Task RenderDocumentFooter()
251 {
252 this.XmlOutput.WriteEndElement();
253 this.XmlOutput.Flush();
254
255 return Task.CompletedTask;
256 }
257
258 #region Span Elements
259
264 public override Task Render(Abbreviation Element)
265 {
266 return this.RenderChildren(Element);
267 }
268
273 public override Task Render(AutomaticLinkMail Element)
274 {
275 string? Bak = this.Hyperlink;
276 this.Hyperlink = "mailto:" + Element.EMail;
277 this.RenderSpan(this.Hyperlink);
278 this.Hyperlink = Bak;
279
280 return Task.CompletedTask;
281 }
282
287 public override Task Render(AutomaticLinkUrl Element)
288 {
289 string? Bak = this.Hyperlink;
290 this.Hyperlink = Element.URL;
291 this.RenderSpan(Element.URL);
292 this.Hyperlink = Bak;
293
294 return Task.CompletedTask;
295 }
296
301 public override async Task Render(Delete Element)
302 {
303 bool Bak = this.StrikeThrough;
304 this.StrikeThrough = true;
305
306 await this.RenderChildren(Element);
307
308 this.StrikeThrough = Bak;
309 }
310
315 public override Task Render(DetailsReference Element)
316 {
317 if (this.Document.Detail is not null)
318 return this.RenderDocument(this.Document.Detail, false);
319 else
320 return this.Render((MetaReference)Element);
321 }
322
327 public override async Task Render(EmojiReference Element)
328 {
329 if (this.InLabel)
330 this.RenderSpan(Element.Emoji.Unicode);
331 else
332 {
333 IEmojiSource EmojiSource = this.Document.EmojiSource;
334
335 if (EmojiSource is null)
336 this.RenderSpan(Element.Delimiter + Element.Emoji.ShortName + Element.Delimiter);
337 else if (!EmojiSource.EmojiSupported(Element.Emoji))
338 this.RenderSpan(Element.Emoji.Unicode);
339 else
340 {
342 await Multimedia.ImageContent.OutputMauiXaml(this.XmlOutput, Source);
343 }
344 }
345 }
346
351 public override async Task Render(Emphasize Element)
352 {
353 bool Bak = this.Italic;
354 this.Italic = true;
355
356 await this.RenderChildren(Element);
357
358 this.Italic = Bak;
359 }
360
365 public override async Task Render(FootnoteReference Element)
366 {
367 if (!(this.Document?.TryGetFootnote(Element.Key, out Footnote? Footnote) ?? false))
368 Footnote = null;
369
370 if (Element.AutoExpand && Footnote is not null)
371 await this.Render(Footnote);
372 else if (this.Document?.TryGetFootnoteNumber(Element.Key, out int Nr) ?? false)
373 {
374 bool Bak = this.Superscript;
375 this.Superscript = true;
376
377 this.RenderSpan(Nr.ToString(CultureInfo.InvariantCulture));
378
379 this.Superscript = Bak;
380
381 if (Footnote is not null)
382 Footnote.Referenced = true;
383 }
384 }
385
390 public override Task Render(HashTag Element)
391 {
392 this.RenderSpan(Element.Tag);
393 return Task.CompletedTask;
394 }
395
400 public override Task Render(HtmlEntity Element)
401 {
403 if (!string.IsNullOrEmpty(s))
404 this.RenderSpan(s);
405
406 return Task.CompletedTask;
407 }
408
413 public override Task Render(HtmlEntityUnicode Element)
414 {
415 this.RenderSpan(new string((char)Element.Code, 1));
416 return Task.CompletedTask;
417 }
418
423 public override Task Render(InlineCode Element)
424 {
425 bool Bak = this.Code;
426 this.Code = true;
427
428 this.RenderSpan(Element.Code);
429
430 this.Code = Bak;
431
432 return Task.CompletedTask;
433 }
434
439 public override Task Render(InlineHTML Element)
440 {
441 this.XmlOutput.WriteComment(Element.HTML);
442 return Task.CompletedTask;
443 }
444
449 public override async Task Render(InlineScript Element)
450 {
451 object Result = await Element.EvaluateExpression();
452 await this.RenderObject(Result, Element.AloneInParagraph, Element.Variables);
453 }
454
461 public async Task RenderObject(object? Result, bool AloneInParagraph, Variables Variables)
462 {
463 if (Result is null)
464 return;
465
466 string? s;
467
468 if (Result is XmlDocument Xml)
469 Result = await MarkdownDocument.TransformXml(Xml, Variables);
470 else if (Result is IToMatrix ToMatrix)
471 Result = ToMatrix.ToMatrix();
472
473 if (this.InLabel)
474 {
475 s = Result?.ToString();
476 if (!string.IsNullOrEmpty(s))
477 this.RenderSpan(Result?.ToString() ?? string.Empty);
478
479 return;
480 }
481
482 if (Result is Graph G)
483 {
484 PixelInformation Pixels = G.CreatePixels(Variables);
485 byte[] Bin = Pixels.EncodeAsPng();
486
487 s = "data:image/png;base64," + Convert.ToBase64String(Bin, 0, Bin.Length);
488
489 await Multimedia.ImageContent.OutputMauiXaml(this.XmlOutput, new Waher.Content.Emoji.ImageSource()
490 {
491 Url = s,
492 Width = Pixels.Width,
493 Height = Pixels.Height
494 });
495 }
496 else if (Result is SKImage Img)
497 {
498 using SKData Data = Img.Encode(SKEncodedImageFormat.Png, 100);
499 byte[] Bin = Data.ToArray();
500
501 s = "data:image/png;base64," + Convert.ToBase64String(Bin, 0, Bin.Length);
502
503 await Multimedia.ImageContent.OutputMauiXaml(this.XmlOutput, new Waher.Content.Emoji.ImageSource()
504 {
505 Url = s,
506 Width = Img.Width,
507 Height = Img.Height
508 });
509 }
510 else if (Result is MarkdownDocument Doc)
511 {
512 await this.RenderDocument(Doc, true); // Does not call ProcessAsyncTasks()
513 Doc.ProcessAsyncTasks();
514 }
515 else if (Result is MarkdownContent Markdown)
516 {
517 Doc = await MarkdownDocument.CreateAsync(Markdown.Markdown);
518 await this.RenderDocument(Doc, true); // Does not call ProcessAsyncTasks()
519 Doc.ProcessAsyncTasks();
520 }
521 else if (Result is Exception ex)
522 {
523 ex = Log.UnnestException(ex);
524
525 if (ex is AggregateException ex2)
526 {
527 foreach (Exception ex3 in ex2.InnerExceptions)
528 {
529 this.RenderContentView();
530 this.XmlOutput.WriteStartElement("Label");
531 this.XmlOutput.WriteAttributeString("LineBreakMode", "WordWrap");
532 this.XmlOutput.WriteAttributeString("TextColor", "Red");
533 this.XmlOutput.WriteValue(ex3.Message);
534 this.XmlOutput.WriteEndElement();
535 this.XmlOutput.WriteEndElement();
536 }
537 }
538 else
539 {
540 if (AloneInParagraph)
541 this.RenderContentView();
542
543 this.XmlOutput.WriteStartElement("Label");
544 this.XmlOutput.WriteAttributeString("LineBreakMode", "WordWrap");
545 this.XmlOutput.WriteAttributeString("TextColor", "Red");
546 this.XmlOutput.WriteValue(ex.Message);
547 this.XmlOutput.WriteEndElement();
548
549 if (AloneInParagraph)
550 this.XmlOutput.WriteEndElement();
551 }
552 }
553 else
554 {
555 if (AloneInParagraph)
556 this.RenderContentView();
557
558 this.XmlOutput.WriteStartElement("Label");
559 this.XmlOutput.WriteAttributeString("LineBreakMode", "WordWrap");
560
562 this.XmlOutput.WriteValue(Result.ToString());
563 this.XmlOutput.WriteEndElement();
564
565 if (AloneInParagraph)
566 this.XmlOutput.WriteEndElement();
567 }
568 }
569
574 public override Task Render(InlineText Element)
575 {
576 this.RenderSpan(Element.Value);
577 return Task.CompletedTask;
578 }
579
584 public override async Task Render(Insert Element)
585 {
586 bool Bak = this.Underline;
587 this.Underline = true;
588
589 await this.RenderChildren(Element);
590
591 this.Underline = Bak;
592 }
593
598 public override Task Render(LineBreak Element)
599 {
600 this.RenderSpan(Environment.NewLine);
601 return Task.CompletedTask;
602 }
603
608 public override async Task Render(Link Element)
609 {
610 string? Bak = this.Hyperlink;
611 this.Hyperlink = Element.Url;
612
613 await this.RenderChildren(Element);
614
615 this.Hyperlink = Bak;
616 }
617
622 public override async Task Render(LinkReference Element)
623 {
625
626 string? Bak = this.Hyperlink;
627
628 if (Multimedia is not null)
629 this.Hyperlink = Multimedia.Items[0].Url;
630
631 await this.RenderChildren(Element);
632
633 this.Hyperlink = Bak;
634 }
635
640 public override Task Render(MetaReference Element)
641 {
642 StringBuilder sb = new();
643 bool FirstOnRow = true;
644
645 if (Element.TryGetMetaData(out KeyValuePair<string, bool>[] Values))
646 {
647 foreach (KeyValuePair<string, bool> P in Values)
648 {
649 if (FirstOnRow)
650 FirstOnRow = false;
651 else
652 sb.Append(' ');
653
654 sb.Append(P.Key);
655 if (P.Value)
656 {
657 sb.Append(Environment.NewLine);
658 FirstOnRow = true;
659 }
660 }
661 }
662
663 this.RenderSpan(sb.ToString());
664
665 return Task.CompletedTask;
666 }
667
673 {
675 if (Renderer is null)
676 return this.RenderChildren(Element);
677 else
678 return Renderer.RenderMauiXaml(this, Element.Items, Element.Children, Element.AloneInParagraph, Element.Document);
679 }
680
685 public override Task Render(MultimediaReference Element)
686 {
688
689 if (Multimedia is not null)
690 {
692 if (Renderer is not null)
693 return Renderer.RenderMauiXaml(this, Multimedia.Items, Element.Children, Element.AloneInParagraph, Element.Document);
694 }
695
696 return this.RenderChildren(Element);
697 }
698
703 public override async Task Render(StrikeThrough Element)
704 {
705 bool Bak = this.StrikeThrough;
706 this.StrikeThrough = true;
707
708 await this.RenderChildren(Element);
709
710 this.StrikeThrough = Bak;
711 }
712
717 public override async Task Render(Strong Element)
718 {
719 bool Bak = this.Bold;
720 this.Bold = true;
721
722 await this.RenderChildren(Element);
723
724 this.Bold = Bak;
725 }
726
731 public override async Task Render(SubScript Element)
732 {
733 bool Bak = this.Subscript;
734 this.Subscript = true;
735
736 await this.RenderChildren(Element);
737
738 this.Subscript = Bak;
739 }
740
745 public override async Task Render(SuperScript Element)
746 {
747 bool Bak = this.Superscript;
748 this.Superscript = true;
749
750 await this.RenderChildren(Element);
751
752 this.Superscript = Bak;
753 }
754
759 public override async Task Render(Underline Element)
760 {
761 bool Bak = this.Underline;
762 this.Underline = true;
763
764 await this.RenderChildren(Element);
765
766 this.Underline = Bak;
767 }
768
769 #endregion
770
771 #region Block elements
772
777 public override async Task Render(BlockQuote Element)
778 {
779 this.XmlOutput.WriteStartElement("ContentView");
780 this.XmlOutput.WriteAttributeString("Padding", SmallMargins(true, false, true, true));
781
782 this.XmlOutput.WriteStartElement("Border");
783 this.XmlOutput.WriteAttributeString("Padding", SmallMargins(true, true, false, false));
784 this.XmlOutput.WriteAttributeString("Stroke", "{DynamicResource ContentPrimaryWL}");
785 // TODO: Border thickness
786
787 this.XmlOutput.WriteStartElement("VerticalStackLayout");
788
789 await this.RenderChildren(Element);
790
791 this.XmlOutput.WriteEndElement();
792 this.XmlOutput.WriteEndElement();
793 this.XmlOutput.WriteEndElement();
794 }
795
800 public override async Task Render(BulletList Element)
801 {
802 int Row = 0;
803 bool ParagraphBullet;
804
805 this.XmlOutput.WriteStartElement("ContentView");
806 this.XmlOutput.WriteAttributeString("Padding", SmallMargins(false, false, true, true));
807
808 this.XmlOutput.WriteStartElement("Grid");
809 this.XmlOutput.WriteAttributeString("RowSpacing", "0");
810 this.XmlOutput.WriteAttributeString("ColumnSpacing", "0");
811
812 this.XmlOutput.WriteStartElement("Grid.ColumnDefinitions");
813
814 this.XmlOutput.WriteStartElement("ColumnDefinition");
815 this.XmlOutput.WriteAttributeString("Width", "Auto");
816 this.XmlOutput.WriteEndElement();
817
818 this.XmlOutput.WriteStartElement("ColumnDefinition");
819 this.XmlOutput.WriteAttributeString("Width", "*");
820 this.XmlOutput.WriteEndElement();
821
822 this.XmlOutput.WriteEndElement();
823 this.XmlOutput.WriteStartElement("Grid.RowDefinitions");
824
825 foreach (MarkdownElement _ in Element.Children)
826 {
827 this.XmlOutput.WriteStartElement("RowDefinition");
828 this.XmlOutput.WriteAttributeString("Height", "Auto");
829 this.XmlOutput.WriteEndElement();
830 }
831
832 this.XmlOutput.WriteEndElement();
833
834 foreach (MarkdownElement E in Element.Children)
835 {
836 if (E is UnnumberedItem Item)
837 {
838 ParagraphBullet = !E.InlineSpanElement || E.OutsideParagraph;
839 GetMargins(E, out bool TopMargin, out bool BottomMargin);
840
841 this.RenderContentView(SmallMargins(false, true, TopMargin, BottomMargin));
842
843 this.XmlOutput.WriteAttributeString("Grid.Column", "0");
844 this.XmlOutput.WriteAttributeString("Grid.Row", Row.ToString(CultureInfo.InvariantCulture));
845
846 this.XmlOutput.WriteElementString("Label", "•");
847 this.XmlOutput.WriteEndElement();
848
849 this.XmlOutput.WriteStartElement("VerticalStackLayout");
850 this.XmlOutput.WriteAttributeString("Grid.Column", "1");
851 this.XmlOutput.WriteAttributeString("Grid.Row", Row.ToString(CultureInfo.InvariantCulture));
852
853 if (ParagraphBullet)
854 await E.Render(this);
855 else
856 await this.RenderLabel(Item, false);
857
858 this.XmlOutput.WriteEndElement();
859 }
860
861 Row++;
862 }
863
864 this.XmlOutput.WriteEndElement();
865 this.XmlOutput.WriteEndElement();
866 }
867
868 private static string SmallMargins(bool Left, bool Right, bool Top, bool Bottom)
869 {
870 StringBuilder sb = new();
871
872 sb.Append("{DynamicResource ");
873
874 if (!(Left || Right || Top || Bottom))
875 sb.Append("No");
876 else
877 {
878 sb.Append("Small");
879
880 if (!(Left && Right && Top && Bottom))
881 {
882 if (Left)
883 sb.Append("Left");
884
885 if (Right)
886 sb.Append("Right");
887
888 if (Top)
889 sb.Append("Top");
890
891 if (Bottom)
892 sb.Append("Bottom");
893 }
894 }
895
896 sb.Append("Margins}");
897
898 return sb.ToString();
899 }
900
907 private static void GetMargins(MarkdownElement Element, out bool TopMargin, out bool BottomMargin)
908 {
909 if (Element.InlineSpanElement && !Element.OutsideParagraph)
910 {
911 TopMargin = false;
912 BottomMargin = false;
913 }
914 else if (Element is NestedBlock NestedBlock)
915 {
916 bool First = true;
917
918 TopMargin = BottomMargin = false;
919
921 {
922 if (First)
923 {
924 First = false;
925 GetMargins(E, out TopMargin, out BottomMargin);
926 }
927 else
928 GetMargins(E, out bool _, out BottomMargin);
929 }
930 }
931 else if (Element is MarkdownElementSingleChild SingleChild)
932 GetMargins(SingleChild.Child, out TopMargin, out BottomMargin);
933 else
934 {
935 TopMargin = true;
936 BottomMargin = true;
937 }
938 }
939
944 public override async Task Render(CenterAligned Element)
945 {
946 this.XmlOutput.WriteStartElement("VerticalStackLayout");
947
949 this.Alignment = Waher.Content.Markdown.Model.TextAlignment.Center;
950
951 await this.RenderChildren(Element);
952
953 this.Alignment = Bak;
954 this.XmlOutput.WriteEndElement();
955 }
956
961 public override async Task Render(CodeBlock Element)
962 {
964
965 if (Renderer is not null)
966 {
967 try
968 {
969 if (await Renderer.RenderMauiXaml(this, Element.Rows, Element.Language, Element.Indent, Element.Document))
970 return;
971 }
972 catch (Exception ex)
973 {
974 ex = Log.UnnestException(ex);
975
976 if (ex is AggregateException ex2)
977 {
978 foreach (Exception ex3 in ex2.InnerExceptions)
979 {
980 this.RenderContentView();
981 this.XmlOutput.WriteStartElement("Label");
982 this.XmlOutput.WriteAttributeString("LineBreakMode", "WordWrap");
983 this.XmlOutput.WriteAttributeString("TextColor", "Red");
984 this.XmlOutput.WriteValue(ex3.Message);
985 this.XmlOutput.WriteEndElement();
986 this.XmlOutput.WriteEndElement();
987 }
988 }
989 else
990 {
991 this.RenderContentView();
992 this.XmlOutput.WriteStartElement("Label");
993 this.XmlOutput.WriteAttributeString("LineBreakMode", "WordWrap");
994 this.XmlOutput.WriteAttributeString("TextColor", "Red");
995 this.XmlOutput.WriteValue(ex.Message);
996 this.XmlOutput.WriteEndElement();
997 this.XmlOutput.WriteEndElement();
998 }
999 }
1000 }
1001
1002 this.RenderContentView();
1003 this.XmlOutput.WriteStartElement("VerticalStackLayout");
1004
1005 int i;
1006
1007 for (i = Element.Start; i <= Element.End; i++)
1008 {
1009 this.XmlOutput.WriteStartElement("Label");
1010 this.XmlOutput.WriteAttributeString("LineBreakMode", "NoWrap");
1011 this.RenderLabelAlignment();
1012 this.XmlOutput.WriteAttributeString("FontFamily", "SpaceGroteskRegular");
1013 this.XmlOutput.WriteAttributeString("Text", Element.Rows[i]);
1014 this.XmlOutput.WriteEndElement();
1015 }
1016
1017 this.XmlOutput.WriteEndElement();
1018 this.XmlOutput.WriteEndElement();
1019 }
1020
1025 public override Task Render(CommentBlock Element)
1026 {
1027 return Task.CompletedTask;
1028 }
1029
1034 public override async Task Render(DefinitionDescriptions Element)
1035 {
1036 MarkdownElement? Last = null;
1037
1038 foreach (MarkdownElement Description in Element.Children)
1039 Last = Description;
1040
1041 foreach (MarkdownElement Description in Element.Children)
1042 {
1043 if (Description.InlineSpanElement && !Description.OutsideParagraph)
1044 {
1045 this.RenderContentView();
1046
1047 this.XmlOutput.WriteStartElement("Label");
1048 this.XmlOutput.WriteAttributeString("LineBreakMode", "WordWrap");
1049 this.RenderLabelAlignment();
1050 this.XmlOutput.WriteAttributeString("TextType", "Html");
1051
1052 using (HtmlRenderer Renderer = new(new HtmlSettings()
1053 {
1054 XmlEntitiesOnly = true
1055 }, this.Document))
1056 {
1057 await Description.Render(Renderer);
1058 this.XmlOutput.WriteCData(Renderer.ToString());
1059 }
1060
1061 this.XmlOutput.WriteEndElement();
1062 this.XmlOutput.WriteEndElement();
1063 }
1064 else
1065 {
1066 this.XmlOutput.WriteStartElement("ContentView");
1067 this.XmlOutput.WriteAttributeString("Padding", SmallMargins(true, false, false, Description == Last));
1068
1069 this.XmlOutput.WriteStartElement("VerticalStackLayout");
1070 await Description.Render(this);
1071 this.XmlOutput.WriteEndElement();
1072
1073 this.XmlOutput.WriteEndElement();
1074 }
1075 }
1076 }
1077
1082 public override Task Render(DefinitionList Element)
1083 {
1084 return this.RenderChildren(Element);
1085 }
1086
1091 public override async Task Render(DefinitionTerms Element)
1092 {
1093 bool Top = true;
1094
1095 foreach (MarkdownElement Term in Element.Children)
1096 {
1097 this.RenderContentView(SmallMargins(true, true, Top, false));
1098
1099 bool BoldBak = this.Bold;
1100 this.Bold = true;
1101
1102 await this.RenderLabel(Term, true);
1103
1104 this.Bold = BoldBak;
1105 this.XmlOutput.WriteEndElement();
1106
1107 Top = false;
1108 }
1109 }
1110
1115 public override async Task Render(DeleteBlocks Element)
1116 {
1117 this.XmlOutput.WriteStartElement("ContentView");
1118 this.XmlOutput.WriteAttributeString("Padding", SmallMargins(true, false, true, true));
1119
1120 this.XmlOutput.WriteStartElement("Border");
1121 this.XmlOutput.WriteAttributeString("Padding", SmallMargins(true, true, false, false));
1122 this.XmlOutput.WriteAttributeString("Stroke", "{DynamicResource TnPDangerbgWL}");
1123 // TODO: Border thickness
1124
1125 this.XmlOutput.WriteStartElement("VerticalStackLayout");
1126
1127 foreach (MarkdownElement E in Element.Children)
1128 await E.Render(this);
1129
1130 this.XmlOutput.WriteEndElement();
1131 this.XmlOutput.WriteEndElement();
1132 this.XmlOutput.WriteEndElement();
1133 }
1134
1139 public override Task Render(Footnote Element)
1140 {
1141 return this.RenderChildren(Element);
1142 }
1143
1148 public override async Task Render(Header Element)
1149 {
1150 this.RenderContentView();
1151
1152 int Level = Math.Max(0, Math.Min(9, Element.Level));
1153
1154 this.XmlOutput.WriteStartElement("Label");
1155 this.XmlOutput.WriteAttributeString("LineBreakMode", "WordWrap");
1156 this.XmlOutput.WriteAttributeString("Style", "{DynamicResource Header" + Level.ToString(CultureInfo.InvariantCulture) + "}");
1157 this.RenderLabelAlignment();
1158
1159 this.XmlOutput.WriteAttributeString("TextType", "Html");
1160
1161 using (HtmlRenderer Renderer = new(new HtmlSettings()
1162 {
1163 XmlEntitiesOnly = true
1164 }, this.Document))
1165 {
1166 await Renderer.RenderChildren(Element);
1167
1168 this.XmlOutput.WriteCData(Renderer.ToString());
1169 }
1170
1171 this.XmlOutput.WriteEndElement();
1172 this.XmlOutput.WriteEndElement();
1173 }
1174
1179 {
1180 switch (this.Alignment)
1181 {
1182 case Waher.Content.Markdown.Model.TextAlignment.Left:
1183 this.XmlOutput.WriteAttributeString("HorizontalTextAlignment", "Start");
1184 break;
1185
1186 case Waher.Content.Markdown.Model.TextAlignment.Right:
1187 this.XmlOutput.WriteAttributeString("HorizontalTextAlignment", "End");
1188 break;
1189
1190 case Waher.Content.Markdown.Model.TextAlignment.Center:
1191 this.XmlOutput.WriteAttributeString("HorizontalTextAlignment", "Center");
1192 break;
1193 }
1194 }
1195
1200 public override Task Render(HorizontalRule Element)
1201 {
1202 this.XmlOutput.WriteStartElement("BoxView");
1203 this.XmlOutput.WriteAttributeString("HeightRequest", "1");
1204 this.XmlOutput.WriteAttributeString("BackgroundColor", "{DynamicResource InputFieldsContentSecondary}");
1205 this.XmlOutput.WriteAttributeString("HorizontalOptions", "Fill");
1206 this.XmlOutput.WriteAttributeString("Margin", SmallMargins(false, false, true, true));
1207 this.XmlOutput.WriteEndElement();
1208
1209 return Task.CompletedTask;
1210 }
1211
1216 public override async Task Render(HtmlBlock Element)
1217 {
1218 this.RenderContentView();
1219
1220 this.XmlOutput.WriteStartElement("Label");
1221 this.XmlOutput.WriteAttributeString("LineBreakMode", "WordWrap");
1222 this.RenderLabelAlignment();
1223 this.XmlOutput.WriteAttributeString("TextType", "Html");
1224
1225 using HtmlRenderer Renderer = new(new HtmlSettings()
1226 {
1227 XmlEntitiesOnly = true
1228 }, this.Document);
1229
1230 await Renderer.RenderChildren(Element);
1231
1232 this.XmlOutput.WriteCData(Renderer.ToString());
1233
1234 this.XmlOutput.WriteEndElement();
1235 this.XmlOutput.WriteEndElement();
1236 }
1237
1242 public override async Task Render(InsertBlocks Element)
1243 {
1244 this.XmlOutput.WriteStartElement("ContentView");
1245 this.XmlOutput.WriteAttributeString("Padding", SmallMargins(true, false, true, true));
1246
1247 this.XmlOutput.WriteStartElement("Border");
1248 this.XmlOutput.WriteAttributeString("Padding", SmallMargins(true, true, false, false));
1249 this.XmlOutput.WriteAttributeString("Stroke", "{DynamicResource TnPSuccessbgWL}");
1250 // TODO: Border thickness
1251
1252 this.XmlOutput.WriteStartElement("VerticalStackLayout");
1253
1254 await this.RenderChildren(Element);
1255
1256 this.XmlOutput.WriteEndElement();
1257 this.XmlOutput.WriteEndElement();
1258 this.XmlOutput.WriteEndElement();
1259 }
1260
1265 public override Task Render(InvisibleBreak Element)
1266 {
1267 return Task.CompletedTask;
1268 }
1269
1274 public override async Task Render(LeftAligned Element)
1275 {
1276 this.XmlOutput.WriteStartElement("VerticalStackLayout");
1277
1279 this.Alignment = Waher.Content.Markdown.Model.TextAlignment.Left;
1280
1281 await this.RenderChildren(Element);
1282
1283 this.Alignment = Bak;
1284 this.XmlOutput.WriteEndElement();
1285 }
1286
1291 public override async Task Render(MarginAligned Element)
1292 {
1293 this.XmlOutput.WriteStartElement("VerticalStackLayout");
1294
1296 this.Alignment = Waher.Content.Markdown.Model.TextAlignment.Left;
1297
1298 await this.RenderChildren(Element);
1299
1300 this.Alignment = Bak;
1301 this.XmlOutput.WriteEndElement();
1302 }
1303
1308 public override async Task Render(NestedBlock Element)
1309 {
1310 if (Element.HasOneChild)
1311 await Element.FirstChild.Render(this);
1312 else
1313 {
1314 HtmlSettings Settings = new()
1315 {
1316 XmlEntitiesOnly = true
1317 };
1318 HtmlRenderer? Html = null;
1319
1320 try
1321 {
1322 foreach (MarkdownElement E in Element.Children)
1323 {
1324 if (E.InlineSpanElement)
1325 {
1326 Html ??= new HtmlRenderer(Settings, this.Document);
1327 await E.Render(Html);
1328 }
1329 else
1330 {
1331 if (Html is not null)
1332 {
1333 this.XmlOutput.WriteStartElement("Label");
1334 this.XmlOutput.WriteAttributeString("LineBreakMode", "WordWrap");
1335 this.RenderLabelAlignment();
1336 this.XmlOutput.WriteAttributeString("TextType", "Html");
1337 this.XmlOutput.WriteCData(Html.ToString());
1338 this.XmlOutput.WriteEndElement();
1339
1340 Html.Dispose();
1341 Html = null;
1342 }
1343
1344 await E.Render(this);
1345 }
1346 }
1347
1348 if (Html is not null)
1349 {
1350 this.XmlOutput.WriteStartElement("Label");
1351 this.XmlOutput.WriteAttributeString("LineBreakMode", "WordWrap");
1352 this.RenderLabelAlignment();
1353 this.XmlOutput.WriteAttributeString("TextType", "Html");
1354 this.XmlOutput.WriteCData(Html.ToString());
1355 this.XmlOutput.WriteEndElement();
1356 }
1357 }
1358 finally
1359 {
1360 Html?.Dispose();
1361 }
1362 }
1363 }
1364
1369 public override Task Render(NumberedItem Element)
1370 {
1371 return this.RenderChild(Element);
1372 }
1373
1378 public override async Task Render(NumberedList Element)
1379 {
1380 int Expected = 0;
1381 int Row = 0;
1382 bool ParagraphBullet;
1383
1384 this.XmlOutput.WriteStartElement("ContentView");
1385 this.XmlOutput.WriteAttributeString("Padding", SmallMargins(false, false, true, true));
1386
1387 this.XmlOutput.WriteStartElement("Grid");
1388 this.XmlOutput.WriteAttributeString("RowSpacing", "0");
1389 this.XmlOutput.WriteAttributeString("ColumnSpacing", "0");
1390
1391 this.XmlOutput.WriteStartElement("Grid.ColumnDefinitions");
1392
1393 this.XmlOutput.WriteStartElement("ColumnDefinition");
1394 this.XmlOutput.WriteAttributeString("Width", "Auto");
1395 this.XmlOutput.WriteEndElement();
1396
1397 this.XmlOutput.WriteStartElement("ColumnDefinition");
1398 this.XmlOutput.WriteAttributeString("Width", "*");
1399 this.XmlOutput.WriteEndElement();
1400
1401 this.XmlOutput.WriteEndElement();
1402 this.XmlOutput.WriteStartElement("Grid.RowDefinitions");
1403
1404 foreach (MarkdownElement _ in Element.Children)
1405 {
1406 this.XmlOutput.WriteStartElement("RowDefinition");
1407 this.XmlOutput.WriteAttributeString("Height", "Auto");
1408 this.XmlOutput.WriteEndElement();
1409 }
1410
1411 this.XmlOutput.WriteEndElement();
1412
1413 foreach (MarkdownElement E in Element.Children)
1414 {
1415 if (E is BlockElementSingleChild Item)
1416 {
1417 Expected++;
1418
1419 ParagraphBullet = !E.InlineSpanElement || E.OutsideParagraph;
1420 GetMargins(E, out bool TopMargin, out bool BottomMargin);
1421
1422 this.RenderContentView(SmallMargins(false, true, TopMargin, BottomMargin));
1423 this.XmlOutput.WriteAttributeString("Grid.Column", "0");
1424 this.XmlOutput.WriteAttributeString("Grid.Row", Row.ToString(CultureInfo.InvariantCulture));
1425
1426 this.XmlOutput.WriteStartElement("Label");
1427
1428 if (Item is NumberedItem NumberedItem)
1429 this.XmlOutput.WriteValue((Expected = NumberedItem.Number).ToString(CultureInfo.InvariantCulture));
1430 else
1431 this.XmlOutput.WriteValue(Expected.ToString(CultureInfo.InvariantCulture));
1432
1433 this.XmlOutput.WriteValue(".");
1434 this.XmlOutput.WriteEndElement();
1435 this.XmlOutput.WriteEndElement();
1436
1437 this.XmlOutput.WriteStartElement("VerticalStackLayout");
1438 this.XmlOutput.WriteAttributeString("Grid.Column", "1");
1439 this.XmlOutput.WriteAttributeString("Grid.Row", Row.ToString(CultureInfo.InvariantCulture));
1440
1441 if (ParagraphBullet)
1442 await E.Render(this);
1443 else
1444 await this.RenderLabel(Item, false);
1445
1446 this.XmlOutput.WriteEndElement();
1447 }
1448
1449 Row++;
1450 }
1451
1452 this.XmlOutput.WriteEndElement();
1453 this.XmlOutput.WriteEndElement();
1454 }
1455
1460 public override async Task Render(Paragraph Element)
1461 {
1462 this.RenderContentView();
1463 await this.RenderLabel(Element, false);
1464 this.XmlOutput.WriteEndElement();
1465 }
1466
1467 internal async Task RenderLabel(MarkdownElement Element, bool IncludeElement)
1468 {
1469 bool HasLink = !Element.ForEach((E, _) =>
1470 {
1471 return !(
1472 E is AutomaticLinkMail ||
1473 E is AutomaticLinkUrl ||
1474 E is Link ||
1475 E is LinkReference);
1476 }, null);
1477
1478 this.XmlOutput.WriteStartElement("Label");
1479 this.XmlOutput.WriteAttributeString("LineBreakMode", "WordWrap");
1480 this.RenderLabelAlignment();
1481
1482 if (HasLink)
1483 {
1484 if (this.InLabel)
1485 {
1486 if (IncludeElement)
1487 await Element.Render(this);
1488 else
1489 await this.RenderChildren(Element);
1490 }
1491 else
1492 {
1493 this.InLabel = true;
1494
1495 this.XmlOutput.WriteStartElement("Label.FormattedText");
1496 this.XmlOutput.WriteStartElement("FormattedString");
1497
1498 if (IncludeElement)
1499 await Element.Render(this);
1500 else
1501 await this.RenderChildren(Element);
1502
1503 this.XmlOutput.WriteEndElement();
1504 this.XmlOutput.WriteEndElement();
1505
1506 this.InLabel = false;
1507 }
1508 }
1509 else
1510 {
1511 this.XmlOutput.WriteAttributeString("TextType", "Html");
1512
1513 if (this.Bold)
1514 this.XmlOutput.WriteAttributeString("FontAttributes", "Bold");
1515
1516 using HtmlRenderer Renderer = new(new HtmlSettings()
1517 {
1518 XmlEntitiesOnly = true
1519 }, this.Document);
1520
1521 if (IncludeElement)
1522 await Element.Render(Renderer);
1523 else
1524 await Renderer.RenderChildren(Element);
1525
1526 this.XmlOutput.WriteCData(Renderer.ToString());
1527 }
1528
1529 this.XmlOutput.WriteEndElement();
1530 }
1531
1532 internal void RenderSpan(string Text)
1533 {
1534 if (!this.InLabel)
1535 {
1536 this.XmlOutput.WriteStartElement("Label");
1537 this.XmlOutput.WriteAttributeString("LineBreakMode", "WordWrap");
1538 this.RenderLabelAlignment();
1539 this.XmlOutput.WriteStartElement("Label.FormattedText");
1540 this.XmlOutput.WriteStartElement("FormattedString");
1541 }
1542
1543 this.XmlOutput.WriteStartElement("Span");
1544
1545 if (this.Superscript)
1546 Text = TextRenderer.ToSuperscript(Text);
1547 else if (this.Subscript)
1548 Text = TextRenderer.ToSubscript(Text);
1549
1550 this.XmlOutput.WriteAttributeString("Text", Text);
1551
1552 if (this.Bold && this.Italic)
1553 this.XmlOutput.WriteAttributeString("FontAttributes", "Italic, Bold");
1554 else if (this.Bold)
1555 this.XmlOutput.WriteAttributeString("FontAttributes", "Bold");
1556 else if (this.Italic)
1557 this.XmlOutput.WriteAttributeString("FontAttributes", "Italic");
1558
1559 if (this.StrikeThrough && this.Underline)
1560 this.XmlOutput.WriteAttributeString("TextDecorations", "Strikethrough, Underline");
1561 else if (this.StrikeThrough)
1562 this.XmlOutput.WriteAttributeString("TextDecorations", "Strikethrough");
1563 else if (this.Underline)
1564 this.XmlOutput.WriteAttributeString("TextDecorations", "Underline");
1565
1566 if (this.Code)
1567 this.XmlOutput.WriteAttributeString("FontFamily", "SpaceGroteskRegular");
1568
1569 if (this.Hyperlink is not null)
1570 {
1571 this.XmlOutput.WriteAttributeString("TextColor", "{DynamicResource TnPInfoContentWL}");
1572
1573 this.XmlOutput.WriteStartElement("Span.GestureRecognizers");
1574 this.XmlOutput.WriteStartElement("TapGestureRecognizer");
1575 this.XmlOutput.WriteAttributeString("Command", "{Binding HyperlinkClicked}");
1576 this.XmlOutput.WriteAttributeString("CommandParameter", this.Hyperlink);
1577 this.XmlOutput.WriteEndElement();
1578 this.XmlOutput.WriteEndElement();
1579 }
1580
1581 if (!this.InLabel)
1582 {
1583 this.XmlOutput.WriteEndElement();
1584 this.XmlOutput.WriteEndElement();
1585 this.XmlOutput.WriteEndElement();
1586 }
1587
1588 this.XmlOutput.WriteEndElement();
1589 }
1590
1591 internal void RenderContentView()
1592 {
1593 this.RenderContentView(this.Alignment, SmallMargins(false, false, true, true), null);
1594 }
1595
1596 internal void RenderContentView(string Margins)
1597 {
1598 this.RenderContentView(this.Alignment, Margins, null);
1599 }
1600
1601 internal void RenderContentView(Waher.Content.Markdown.Model.TextAlignment Alignment, string? Margins)
1602 {
1603 this.RenderContentView(Alignment, Margins, null);
1604 }
1605
1606 internal void RenderContentView(Waher.Content.Markdown.Model.TextAlignment Alignment, string? Margins, string? Style)
1607 {
1608 this.XmlOutput.WriteStartElement("ContentView");
1609
1610 if (!string.IsNullOrEmpty(Margins))
1611 this.XmlOutput.WriteAttributeString("Padding", Margins);
1612
1613 if (!string.IsNullOrEmpty(Style))
1614 this.XmlOutput.WriteAttributeString("Style", "{DynamicResource " + Style + "}");
1615
1616 switch (Alignment)
1617 {
1618 case Waher.Content.Markdown.Model.TextAlignment.Center:
1619 this.XmlOutput.WriteAttributeString("HorizontalOptions", "Center");
1620 break;
1621
1622 case Waher.Content.Markdown.Model.TextAlignment.Left:
1623 this.XmlOutput.WriteAttributeString("HorizontalOptions", "Start");
1624 break;
1625
1626 case Waher.Content.Markdown.Model.TextAlignment.Right:
1627 this.XmlOutput.WriteAttributeString("HorizontalOptions", "End");
1628 break;
1629 }
1630 }
1631
1636 public override async Task Render(RightAligned Element)
1637 {
1638 this.XmlOutput.WriteStartElement("VerticalStackLayout");
1639
1641 this.Alignment = Waher.Content.Markdown.Model.TextAlignment.Right;
1642
1643 await this.RenderChildren(Element);
1644
1645 this.Alignment = Bak;
1646 this.XmlOutput.WriteEndElement();
1647 }
1648
1653 public override Task Render(Sections Element)
1654 {
1655 return this.RenderChildren(Element);
1656 }
1657
1662 public override Task Render(SectionSeparator Element)
1663 {
1664 this.XmlOutput.WriteStartElement("BoxView");
1665 this.XmlOutput.WriteAttributeString("HeightRequest", "1");
1666 this.XmlOutput.WriteAttributeString("BackgroundColor", "{DynamicResource InputFieldsContentSecondary}");
1667 this.XmlOutput.WriteAttributeString("HorizontalOptions", "Fill");
1668 this.XmlOutput.WriteAttributeString("Margin", SmallMargins(false, false, true, true));
1669 this.XmlOutput.WriteEndElement();
1670
1671 return Task.CompletedTask;
1672 }
1673
1678 public override async Task Render(Table Element)
1679 {
1680 int Column;
1681 int Row, NrRows;
1682 int RowNr = 0;
1683
1684 this.XmlOutput.WriteStartElement("ScrollView");
1685 this.XmlOutput.WriteAttributeString("Orientation", "Horizontal");
1686 this.XmlOutput.WriteStartElement("ContentView");
1687 this.XmlOutput.WriteAttributeString("Padding", SmallMargins(false, false, true, true));
1688
1689 this.XmlOutput.WriteStartElement("Grid");
1690 this.XmlOutput.WriteAttributeString("RowSpacing", "-2");
1691 this.XmlOutput.WriteAttributeString("ColumnSpacing", "-2");
1692
1693 // TODO: Tooltip/caption
1694
1695 this.XmlOutput.WriteStartElement("Grid.ColumnDefinitions");
1696
1697 for (Column = 0; Column < Element.Columns; Column++)
1698 {
1699 this.XmlOutput.WriteStartElement("ColumnDefinition");
1700 this.XmlOutput.WriteAttributeString("Width", "Auto");
1701 this.XmlOutput.WriteEndElement();
1702 }
1703
1704 this.XmlOutput.WriteEndElement();
1705 this.XmlOutput.WriteStartElement("Grid.RowDefinitions");
1706
1707 for (Row = 0, NrRows = Element.Rows.Length + Element.Headers.Length; Row < NrRows; Row++)
1708 {
1709 this.XmlOutput.WriteStartElement("RowDefinition");
1710 this.XmlOutput.WriteAttributeString("Height", "Auto");
1711 this.XmlOutput.WriteEndElement();
1712 }
1713
1714 this.XmlOutput.WriteEndElement();
1715
1716 for (Row = 0, NrRows = Element.Headers.Length; Row < NrRows; Row++, RowNr++)
1717 await this.Render(Element.Headers[Row], Element.HeaderCellAlignments[Row], RowNr, true, Element);
1718
1719 for (Row = 0, NrRows = Element.Rows.Length; Row < NrRows; Row++, RowNr++)
1720 await this.Render(Element.Rows[Row], Element.RowCellAlignments[Row], RowNr, false, Element);
1721
1722 this.XmlOutput.WriteEndElement();
1723 this.XmlOutput.WriteEndElement();
1724 this.XmlOutput.WriteEndElement();
1725
1726 }
1727
1728 private void ClearState()
1729 {
1730 this.Alignment = Waher.Content.Markdown.Model.TextAlignment.Left;
1731 this.Bold = false;
1732 this.Italic = false;
1733 this.StrikeThrough = false;
1734 this.Underline = false;
1735 this.Superscript = false;
1736 this.Subscript = false;
1737 this.Code = false;
1738 this.InLabel = false;
1739 this.Hyperlink = null;
1740 }
1741
1742 private StateBackup Backup()
1743 {
1744 return new StateBackup()
1745 {
1746 Alignment = this.Alignment,
1747 Bold = this.Bold,
1748 Italic = this.Italic,
1749 StrikeThrough = this.StrikeThrough,
1750 Underline = this.Underline,
1751 Superscript = this.Superscript,
1752 Subscript = this.Subscript,
1753 Code = this.Code,
1754 InLabel = this.InLabel,
1755 Hyperlink = this.Hyperlink
1756 };
1757 }
1758
1759 private void Restore(StateBackup Backup)
1760 {
1761 this.Alignment = Backup.Alignment;
1762 this.Bold = Backup.Bold;
1763 this.Italic = Backup.Italic;
1764 this.StrikeThrough = Backup.StrikeThrough;
1765 this.Underline = Backup.Underline;
1766 this.Superscript = Backup.Superscript;
1767 this.Subscript = Backup.Subscript;
1768 this.Code = Backup.Code;
1769 this.InLabel = Backup.InLabel;
1770 this.Hyperlink = Backup.Hyperlink;
1771 }
1772
1773 private class StateBackup
1774 {
1776 public bool Bold;
1777 public bool Italic;
1778 public bool StrikeThrough;
1779 public bool Underline;
1780 public bool Superscript;
1781 public bool Subscript;
1782 public bool Code;
1783 public bool InLabel;
1784 public string? Hyperlink;
1785 }
1786
1787 private async Task Render(MarkdownElement[] CurrentRow, Waher.Content.Markdown.Model.TextAlignment?[] CellAlignments,
1788 int RowNr, bool Bold, Table Element)
1789 {
1792 int Column;
1793 int NrColumns = Element.Columns;
1794 int ColSpan;
1795 StateBackup Bak = this.Backup();
1796
1797 this.ClearState();
1798
1799 for (Column = 0; Column < NrColumns; Column++)
1800 {
1801 E = CurrentRow[Column];
1802 if (E is null)
1803 continue;
1804
1805 TextAlignment = CellAlignments[Column] ?? Element.ColumnAlignments[Column];
1806 ColSpan = Column + 1;
1807 while (ColSpan < NrColumns && CurrentRow[ColSpan] is null)
1808 ColSpan++;
1809
1810 ColSpan -= Column;
1811
1812 this.XmlOutput.WriteStartElement("Border");
1813
1814 if ((RowNr & 1) == 0)
1815 this.XmlOutput.WriteAttributeString("Style", "{DynamicResource TableCellEven}");
1816 else
1817 this.XmlOutput.WriteAttributeString("Style", "{DynamicResource TableCellOdd}");
1818
1819 this.XmlOutput.WriteAttributeString("Grid.Column", Column.ToString(CultureInfo.InvariantCulture));
1820 this.XmlOutput.WriteAttributeString("Grid.Row", RowNr.ToString(CultureInfo.InvariantCulture));
1821
1822 if (ColSpan > 1)
1823 this.XmlOutput.WriteAttributeString("Grid.ColumnSpan", ColSpan.ToString(CultureInfo.InvariantCulture));
1824
1825 if (E.InlineSpanElement)
1826 {
1827 this.RenderContentView(TextAlignment, null, "TableCell");
1828
1829 this.Bold = Bold;
1830 await this.RenderLabel(E, true);
1831 this.Bold = false;
1832
1833 this.XmlOutput.WriteEndElement(); // Paragraph
1834 }
1835 else
1836 {
1837 this.XmlOutput.WriteStartElement("ContentView");
1838 this.XmlOutput.WriteAttributeString("Style", null, "{DynamicResource TableCell}");
1839
1840 this.XmlOutput.WriteStartElement("VerticalStackLayout");
1841 await E.Render(this);
1842 this.XmlOutput.WriteEndElement(); // StackLayout
1843
1844 this.XmlOutput.WriteEndElement(); // ContentView
1845 }
1846
1847 this.XmlOutput.WriteEndElement(); // Border
1848 }
1849
1850 this.Restore(Bak);
1851 }
1852
1857 public override Task Render(TaskItem Element)
1858 {
1859 return this.RenderChild(Element);
1860 }
1861
1866 public override async Task Render(TaskList Element)
1867 {
1868 int Row = 0;
1869 bool ParagraphBullet;
1870
1871 this.XmlOutput.WriteStartElement("ContentView");
1872 this.XmlOutput.WriteAttributeString("Padding", SmallMargins(false, false, true, true));
1873
1874 this.XmlOutput.WriteStartElement("Grid");
1875 this.XmlOutput.WriteAttributeString("RowSpacing", "0");
1876 this.XmlOutput.WriteAttributeString("ColumnSpacing", "0");
1877
1878 this.XmlOutput.WriteStartElement("Grid.ColumnDefinitions");
1879
1880 this.XmlOutput.WriteStartElement("ColumnDefinition");
1881 this.XmlOutput.WriteAttributeString("Width", "Auto");
1882 this.XmlOutput.WriteEndElement();
1883
1884 this.XmlOutput.WriteStartElement("ColumnDefinition");
1885 this.XmlOutput.WriteAttributeString("Width", "*");
1886 this.XmlOutput.WriteEndElement();
1887
1888 this.XmlOutput.WriteEndElement();
1889 this.XmlOutput.WriteStartElement("Grid.RowDefinitions");
1890
1891 foreach (MarkdownElement _ in Element.Children)
1892 {
1893 this.XmlOutput.WriteStartElement("RowDefinition");
1894 this.XmlOutput.WriteAttributeString("Height", "Auto");
1895 this.XmlOutput.WriteEndElement();
1896 }
1897
1898 this.XmlOutput.WriteEndElement();
1899
1900 foreach (MarkdownElement E in Element.Children)
1901 {
1902 if (E is TaskItem TaskItem)
1903 {
1904 ParagraphBullet = !E.InlineSpanElement || E.OutsideParagraph;
1905 GetMargins(E, out bool TopMargin, out bool BottomMargin);
1906
1907 if (TaskItem.IsChecked)
1908 {
1909 this.RenderContentView(SmallMargins(false, true, TopMargin, BottomMargin));
1910 this.XmlOutput.WriteAttributeString("Grid.Column", "0");
1911 this.XmlOutput.WriteAttributeString("Grid.Row", Row.ToString(CultureInfo.InvariantCulture));
1912
1913 this.XmlOutput.WriteElementString("Label", "✓");
1914 this.XmlOutput.WriteEndElement();
1915 }
1916
1917 this.XmlOutput.WriteStartElement("VerticalStackLayout");
1918 this.XmlOutput.WriteAttributeString("Grid.Column", "1");
1919 this.XmlOutput.WriteAttributeString("Grid.Row", Row.ToString(CultureInfo.InvariantCulture));
1920
1921 if (ParagraphBullet)
1922 await E.Render(this);
1923 else
1924 await this.RenderLabel(TaskItem, false);
1925
1926 this.XmlOutput.WriteEndElement();
1927 }
1928
1929 Row++;
1930 }
1931
1932 this.XmlOutput.WriteEndElement();
1933 this.XmlOutput.WriteEndElement();
1934 }
1935
1940 public override Task Render(UnnumberedItem Element)
1941 {
1942 return this.RenderChild(Element);
1943 }
1944
1945 #endregion
1946
1947 }
1948}
Static class containing SVG Paths for symbols used in the app.
Definition: Geometries.cs:11
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:7
static string EntityToCharacter(string Entity)
Converts an HTML entity into a character.
Definition: HtmlEntity.cs:73
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:17
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:12
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:65
MarkdownElement[][] Headers
Headers in table.
Definition: Table.cs:55
TextAlignment?[][] RowCellAlignments
Row cell alignments in table.
Definition: Table.cs:80
override ChunkedList< MarkdownElement > Children
Any children of the element.
Definition: Table.cs:101
TextAlignment?[][] HeaderCellAlignments
Header cell alignments in table.
Definition: Table.cs:75
MarkdownElement[][] Rows
Rows in table.
Definition: Table.cs:60
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 ChunkedList< 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.
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.
virtual ChunkedList< MarkdownElement > Children
Any children of the element.
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:41
bool AloneInParagraph
If the element is alone in a paragraph.
Renders HTML from a Markdown document.
Definition: HtmlRenderer.cs:25
Contains settings that the HTML export uses to customize HTML output.
Definition: HtmlSettings.cs:7
Abstract base class for Markdown renderers.
Definition: Renderer.cs:15
readonly StringBuilder Output
Renderer output.
Definition: Renderer.cs:19
Task RenderChild(MarkdownElementSingleChild Element)
Renders the child of Element .
Definition: Renderer.cs:178
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:66
MarkdownDocument Document
Reference to Markdown document being processed.
Definition: Renderer.cs:24
Renders plain text from a Markdown document.
Definition: TextRenderer.cs:18
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:14
static Exception UnnestException(Exception Exception)
Unnests an exception, to extract the relevant inner exception.
Definition: Log.cs:828
Base class for graphs.
Definition: Graph.cs:88
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:10
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:7
Interface for objects that can be converted into matrices.
Definition: IToMatrix.cs:9
Definition: ImplTypes.g.cs:58
TextAlignment
Text alignment of contents.
Definition: App.xaml.cs:4