1using CommunityToolkit.Maui.Markup;
2using Microsoft.Maui.Controls;
4using System.Globalization;
5using System.Runtime.CompilerServices;
22using Microsoft.Maui.Graphics.Text;
27using Microsoft.Maui.Controls.Shapes;
29using System.Runtime.Intrinsics.Arm;
43 #region Fields & properties
53 private VerticalStackLayout mainStackLayout;
58 private View currentElement;
120 this.mainStackLayout =
new VerticalStackLayout();
121 this.mainStackLayout.Spacing = 10;
122 this.currentElement =
new ContentView();
131 if (this.mainStackLayout.Children.Count == 0)
return null;
132 return this.mainStackLayout;
136 #region Render Document
148 this.StrikeThrough =
false;
149 this.Underline =
false;
150 this.Superscript =
false;
151 this.Subscript =
false;
153 this.InLabel =
false;
154 this.Hyperlink =
null;
170 if (!Inclusion && this.Document.
TryGetMetaData(
"BODYONLY", out KeyValuePair<string, bool>[] Values))
181 this.currentElement =
new ContentView();
183 await
E.Render(
this);
185 this.mainStackLayout.Add(this.currentElement);
188 if (this.NeedsToDisplayFootnotes())
191 this.mainStackLayout.Add(this.currentElement);
194 this.Document = DocBak;
202 return Task.CompletedTask;
214 ContentView SeparatorContentView =
new ContentView
216 Content =
new Rectangle
220 Aspect = Stretch.Fill
224 this.mainStackLayout.Add(SeparatorContentView);
226 Grid FootnoteGrid =
new Grid
232 new ColumnDefinition(GridLength.Auto),
233 new ColumnDefinition(GridLength.Star)
239 if ((this.Document?.TryGetFootnoteNumber(Key, out FootnoteNumber) ??
false) &&
240 (this.Document?.TryGetFootnote(Key, out CurrentFootnote) ??
false) &&
241 CurrentFootnote.Referenced)
243 FootnoteGrid.AddRowDefinition(
new RowDefinition { Height = GridLength.Auto });
247 if (this.Document is not
null)
251 if ((this.Document?.TryGetFootnoteNumber(Key, out FootnoteNumber) ??
false) &&
252 (this.Document?.TryGetFootnote(Key, out CurrentFootnote) ??
false) &&
253 CurrentFootnote.Referenced)
255 ContentView FootnoteNumberView =
new ContentView
262 Text = FootnoteNumber.ToString(CultureInfo.InvariantCulture)
266 FootnoteGrid.Add(FootnoteNumberView, 0, RowIndex);
268 ContentView FootnoteContentView =
new ContentView();
269 this.currentElement = FootnoteContentView;
270 await this.
Render(CurrentFootnote);
272 FootnoteGrid.Add(FootnoteContentView, 1, RowIndex);
279 this.currentElement = FootnoteGrid;
283 #region Children Render Helpers
291 if (this.InLabel && !(Element.
Children is
null))
295 await
E.Render(
this);
300 ContentView Bakup = (ContentView)this.currentElement;
302 VerticalStackLayout ChildrenContainer =
new();
303 ChildrenContainer.Spacing = 8;
304 Bakup.Content = ChildrenContainer;
310 ContentView ChildContentView =
new ContentView();
311 this.currentElement = ChildContentView;
312 await
E.Render(
this);
313 ChildrenContainer.Add(ChildContentView);
316 this.currentElement = Bakup;
326 IEnumerable<MarkdownElement> Children = Element.
Children;
328 if (this.InLabel && !(Children is
null))
332 await
E.Render(
this);
337 ContentView Bakup = (ContentView)this.currentElement;
339 VerticalStackLayout ChildrenContainer =
new();
340 Bakup.Content = ChildrenContainer;
342 if (!(Children is
null))
346 ContentView ChildContentView =
new ContentView();
347 this.currentElement = ChildContentView;
348 await
E.Render(
this);
349 ChildrenContainer.Add(ChildContentView);
353 this.currentElement = Bakup;
363 if (Element.
Child is
null)
364 return Task.CompletedTask;
368 return Task.CompletedTask;
373 #region Base Element Renderers
400 this.StrikeThrough =
true;
404 this.StrikeThrough = Bak;
429 return Task.CompletedTask;
439 this.Underline =
true;
443 this.Underline = Bak;
452 ContentView Bakup = (ContentView)this.currentElement;
455 bool ParagraphBullet;
457 Grid TaskListGrid =
new Grid
463 new ColumnDefinition { Width = GridLength.Auto },
464 new ColumnDefinition { Width = GridLength.Star },
470 TaskListGrid.AddRowDefinition(
new RowDefinition { Height = GridLength.Auto });
477 ParagraphBullet = !E.InlineSpanElement ||
E.OutsideParagraph;
483 ContentView CheckmarkContentView = (ContentView)this.currentElement;
485 CheckmarkContentView.Column(0);
486 CheckmarkContentView.Row(RowIndex);
488 CheckmarkContentView.Content = (
new Label { Text =
"✓" });
490 TaskListGrid.Add(CheckmarkContentView);
493 ContentView TaskContentView =
new ContentView();
494 TaskContentView.Column(1);
495 TaskContentView.Row(RowIndex);
497 this.currentElement = TaskContentView;
500 await
E.Render(
this);
502 await this.RenderLabel(
TaskItem,
false);
504 TaskListGrid.Add(TaskContentView);
510 Bakup.Content = TaskListGrid;
511 this.currentElement = Bakup;
522 return Task.CompletedTask;
531 ContentView Bakup = (ContentView)this.currentElement;
534 int RowIndex, NrRows;
537 Grid TableGrid =
new Grid
545 for (Column = 0; Column < Element.
Columns; Column++)
547 TableGrid.AddColumnDefinition(
new ColumnDefinition { Width = GridLength.Auto });
550 for (RowIndex = 0, NrRows = Element.
Rows.Length + Element.
Headers.Length; RowIndex < NrRows; RowIndex++)
552 TableGrid.AddRowDefinition(
new RowDefinition { Height = GridLength.Auto });
555 ScrollView TableScrollView =
new ScrollView
557 Orientation = ScrollOrientation.Horizontal,
561 for (RowIndex = 0, NrRows = Element.
Headers.Length; RowIndex < NrRows; RowIndex++, RowNr++)
563 this.currentElement = TableGrid;
567 for (RowIndex = 0, NrRows = Element.
Rows.Length; RowIndex < NrRows; RowIndex++, RowNr++)
569 this.currentElement = TableGrid;
573 Bakup.Content = TableScrollView;
574 this.currentElement = Bakup;
592 int NrColumns = Element.
Columns;
594 StateBackup Bak = this.Backup();
596 Grid Bakup = (Grid)this.currentElement;
600 for (Column = 0; Column < NrColumns; Column++)
602 E = CurrentRow[Column];
607 ColSpan = Column + 1;
608 while (ColSpan < NrColumns && CurrentRow[ColSpan] is
null)
613 Border Frame =
new Border();
615 if ((RowNr & 1) == 0)
621 Frame.Column(Column);
625 Frame.ColumnSpan(ColSpan);
627 if (
E.InlineSpanElement)
631 ContentView Cv = (ContentView)this.currentElement;
632 this.currentElement = Cv;
635 await this.RenderLabel(
E,
true);
642 ContentView Cv =
new ContentView
644 Style = AppStyles.TableCell
646 this.currentElement = Cv;
648 await
E.Render(
this);
656 this.currentElement = Bakup;
666 this.Superscript =
true;
670 this.Superscript = Bak;
680 this.Subscript =
true;
684 this.Subscript = Bak;
693 bool Bak = this.
Bold;
708 this.StrikeThrough =
true;
712 this.StrikeThrough = Bak;
721 ContentView Bakup = (ContentView)this.currentElement;
723 Rectangle Separator =
new Rectangle
727 Aspect = Stretch.Fill
731 Bakup.Content = Separator;
733 return Task.CompletedTask;
756 this.Alignment = Bak;
765 await this.RenderLabel(Element,
false);
774 ContentView Bakup = (ContentView)this.currentElement;
778 bool ParagraphBullet;
780 Grid ListGrid =
new Grid
786 new ColumnDefinition { Width = GridLength.Auto },
787 new ColumnDefinition { Width = GridLength.Star }
793 ListGrid.AddRowDefinition(
new RowDefinition { Height = GridLength.Auto });
802 ParagraphBullet = !E.InlineSpanElement ||
E.OutsideParagraph;
805 ContentView InnerContentView = (ContentView)this.currentElement;
806 InnerContentView.Column(0);
807 InnerContentView.Row(RowIndex);
809 Label Label =
new Label();
814 Label.Text = Expected.ToString(CultureInfo.InvariantCulture) +
".";
816 InnerContentView.Content = Label;
817 ListGrid.Add(InnerContentView);
819 ContentView ItemContentView =
new ContentView();
820 ItemContentView.Column(1);
821 ItemContentView.Row(RowIndex);
822 this.currentElement = ItemContentView;
826 await
E.Render(
this);
830 await this.RenderLabel(Item,
false);
833 ListGrid.Add(ItemContentView);
839 Bakup.Content = ListGrid;
840 this.currentElement = Bakup;
851 return Task.CompletedTask;
860 ContentView Bakup = (ContentView)this.currentElement;
870 XmlEntitiesOnly =
true
874 VerticalStackLayout OuterVerticalStackLayout =
new VerticalStackLayout();
880 if (
E.InlineSpanElement)
883 await
E.Render(Html);
887 if (Html is not
null)
889 Label HTMLLabel =
new Label
891 LineBreakMode = LineBreakMode.WordWrap,
893 TextType = TextType.Html,
900 OuterVerticalStackLayout.Add(HTMLLabel);
903 ContentView InnerContentView =
new ContentView();
904 this.currentElement = InnerContentView;
905 await
E.Render(
this);
906 OuterVerticalStackLayout.Add(InnerContentView);
910 if (Html is not
null)
912 Label HTMLLabel =
new Label
914 LineBreakMode = LineBreakMode.WordWrap,
916 TextType = TextType.Html,
919 OuterVerticalStackLayout.Add(HTMLLabel);
927 Bakup.Content = OuterVerticalStackLayout;
928 this.currentElement = Bakup;
963 await this.RenderMaui(Element);
972 StringBuilder StringBuilder =
new();
973 bool FirstOnRow =
true;
975 if (Element.
TryGetMetaData(out KeyValuePair<string, bool>[] Values))
977 foreach (KeyValuePair<string, bool> P
in Values)
982 StringBuilder.Append(
' ');
984 StringBuilder.Append(P.Key);
987 StringBuilder.Append(Environment.NewLine);
993 this.RenderSpan(StringBuilder.ToString());
995 return Task.CompletedTask;
1009 this.Alignment = Bak;
1022 if (Multimedia is not
null)
1027 this.Hyperlink = Bak;
1037 this.Hyperlink = Element.
Url;
1041 this.Hyperlink = Bak;
1050 this.RenderSpan(Environment.NewLine);
1052 return Task.CompletedTask;
1066 this.Alignment = Bak;
1076 return Task.CompletedTask;
1085 ContentView Bakup = (ContentView)this.currentElement;
1087 Border BlockBorder =
new Border
1090 Stroke =
new SolidColorBrush
1094 StrokeThickness = 1,
1095 StrokeShape =
new RoundRectangle
1101 Bakup.Content = BlockBorder;
1103 ContentView InnerContentView =
new ContentView();
1104 this.currentElement = InnerContentView;
1108 BlockBorder.Content = InnerContentView;
1109 this.currentElement = Bakup;
1119 this.Underline =
true;
1123 this.Underline = Bak;
1132 this.RenderSpan(Element.
Value);
1134 return Task.CompletedTask;
1153 if (this.currentElement is Label ExistingLabel)
1155 ExistingLabel.TextType = TextType.Html;
1156 ExistingLabel.Text = $
"<--- {Element.HTML} --->";
1160 ContentView Bakup = (ContentView)this.currentElement;
1162 Label NewLabel =
new Label
1164 TextType = TextType.Html,
1165 Text = $
"<--- {Element.HTML} --->",
1168 Bakup.Content = NewLabel;
1171 return Task.CompletedTask;
1180 bool Bak = this.
Code;
1183 this.RenderSpan(Element.
Code);
1187 return Task.CompletedTask;
1196 this.RenderSpan(
new string((
char)Element.
Code, 1));
1198 return Task.CompletedTask;
1208 if (!
string.IsNullOrEmpty(S))
1213 return Task.CompletedTask;
1222 ContentView Bakup = (ContentView)this.currentElement;
1225 Bakup.Margin = Margins;
1227 Label HTMLTextLabel =
new Label
1229 LineBreakMode = LineBreakMode.WordWrap,
1231 TextType = TextType.Html,
1236 XmlEntitiesOnly =
true
1241 HTMLTextLabel.Text = HTMLRenderer.ToString();
1243 Bakup.Content = HTMLTextLabel;
1244 this.currentElement = Bakup;
1253 ContentView CurrentContentView = (ContentView)this.currentElement;
1255 CurrentContentView.Content =
new Rectangle
1259 Aspect = Stretch.Fill,
1262 return Task.CompletedTask;
1271 int Level = Math.Max(0, Math.Min(9, Element.
Level));
1273 Label HeaderLabel =
new Label
1275 LineBreakMode = LineBreakMode.WordWrap,
1277 TextType = TextType.Html
1282 XmlEntitiesOnly =
true
1292 ContentView Bakup = (ContentView)this.currentElement;
1293 Bakup.Content = HeaderLabel;
1294 this.currentElement = Bakup;
1304 ContentView Bakup = (ContentView)this.currentElement;
1306 ContentView InnerContentView =
new();
1307 this.currentElement = InnerContentView;
1309 Border ContentBorder =
new Border
1311 Background = Color.FromArgb(
"FFFAFAD2"),
1312 Content = InnerContentView
1315 this.RenderSpan(Element.
Tag);
1317 Bakup.Content = ContentBorder;
1318 return Task.CompletedTask;
1331 await this.
Render(Footnote);
1332 else if (this.Document?.TryGetFootnoteNumber(Element.
Key, out
int Nr) ??
false)
1335 this.Superscript =
true;
1337 await this.RenderSpan(Nr.ToString(CultureInfo.InvariantCulture));
1339 this.Superscript = Bak;
1342 Footnote.Referenced =
true;
1358 if (EmojiSource is
null)
1365 await this.OutputImage(Source);
1376 if (this.Document.
Detail is not
null)
1381 return Task.CompletedTask;
1390 ContentView Bakup = (ContentView)this.currentElement;
1392 Border Border =
new Border
1395 Stroke =
new SolidColorBrush
1399 StrokeThickness = 1,
1400 StrokeShape =
new RoundRectangle
1406 Bakup.Content = Border;
1408 ContentView InnerContentView =
new ContentView();
1409 this.currentElement = InnerContentView;
1413 Border.Content = InnerContentView;
1414 this.currentElement = Bakup;
1425 ContentView Bakup = (ContentView)this.currentElement;
1433 this.RenderContentView(Margins);
1434 ContentView InnerContentView = (ContentView)this.currentElement;
1435 this.currentElement = InnerContentView;
1437 bool BoldBak = this.
Bold;
1440 await this.RenderLabel(Term,
true);
1441 Bakup.Content = InnerContentView;
1442 this.Bold = BoldBak;
1447 this.currentElement = Bakup;
1465 ContentView Bakup = (ContentView)this.currentElement;
1478 Label HTMLLabel =
new Label
1480 LineBreakMode = LineBreakMode.WordWrap,
1482 TextType = TextType.Html
1487 XmlEntitiesOnly =
true
1494 Bakup.Content = HTMLLabel;
1500 if (Description == Last)
1503 ContentView InnerCV =
new();
1504 this.currentElement = InnerCV;
1505 await Description.
Render(
this);
1508 VerticalStackLayout Vsl =
new VerticalStackLayout();
1510 Bakup.Content = Vsl;
1521 ContentView Bakup = (ContentView)this.currentElement;
1522 VerticalStackLayout BlockStackLayout =
new();
1524 StringBuilder
Output =
new();
1532 if (Element.
Language.Equals(
"image/png", StringComparison.OrdinalIgnoreCase))
1534 string Bin = Element.
Rows[0];
1535 byte[] Data = Convert.FromBase64String(Bin);
1536 string Uri =
"data:image/png;base64," + Convert.ToBase64String(Data, 0, Data.Length);
1550 catch (Exception Ex)
1554 if (Ex is AggregateException Ex2)
1556 foreach (Exception Ex3
in Ex2.InnerExceptions)
1558 Label ExceptionLabel =
new Label
1560 LineBreakMode = LineBreakMode.WordWrap,
1565 BlockStackLayout.Add(ExceptionLabel);
1570 Label ExceptionLabel =
new Label
1572 LineBreakMode = LineBreakMode.WordWrap,
1577 BlockStackLayout.Add(ExceptionLabel);
1582 for (
int i = Element.
Start; i <= Element.
End; i++)
1584 Label ContentLabel =
new Label
1586 LineBreakMode = LineBreakMode.NoWrap,
1588 FontFamily =
"SpaceGroteskRegular",
1589 Text = Element.
Rows[i]
1592 BlockStackLayout.Add(ContentLabel);
1595 Bakup.Content = BlockStackLayout;
1596 this.currentElement = Bakup;
1606 return Task.CompletedTask;
1615 ContentView Bakup = (ContentView)this.currentElement;
1618 bool ParagraphBullet;
1620 Grid ListGrid =
new Grid
1626 new ColumnDefinition { Width = GridLength.Auto },
1627 new ColumnDefinition { Width = GridLength.Star }
1633 ListGrid.AddRowDefinition(
new RowDefinition { Height = GridLength.Auto });
1640 ParagraphBullet = !E.InlineSpanElement ||
E.OutsideParagraph;
1644 ContentView StarContentView = (ContentView)this.currentElement;
1645 StarContentView.Column(0);
1646 StarContentView.Row(Row);
1648 Label Lbl =
new Label { Text =
"•" };
1649 StarContentView.Content = Lbl;
1650 ListGrid.Add(StarContentView);
1652 ContentView VslContainer =
new ContentView();
1653 VslContainer.Column(1);
1654 VslContainer.Row(Row);
1655 this.currentElement = VslContainer;
1657 if (ParagraphBullet)
1658 await
E.Render(
this);
1660 await this.RenderLabel(Item,
false);
1662 ListGrid.Add(VslContainer);
1668 Bakup.Content = ListGrid;
1669 this.currentElement = Bakup;
1683 this.Alignment = Bak;
1692 ContentView Bakup = (ContentView)this.currentElement;
1694 Border BlockQuoteBorder =
new Border
1697 Stroke =
new SolidColorBrush
1701 StrokeThickness = 1,
1702 StrokeShape =
new RoundRectangle
1708 Bakup.Content = BlockQuoteBorder;
1710 ContentView BlockQuoteContentView =
new ContentView();
1711 this.currentElement = BlockQuoteContentView;
1715 BlockQuoteBorder.Content = BlockQuoteContentView;
1716 this.currentElement = Bakup;
1726 this.Hyperlink = Element.
URL;
1727 this.RenderSpan(Element.
URL);
1728 this.Hyperlink = Bak;
1730 return Task.CompletedTask;
1740 this.Hyperlink =
"mailto:" + Element.
EMail;
1741 this.RenderSpan(this.Hyperlink);
1742 this.Hyperlink = Bak;
1744 return Task.CompletedTask;
1749 #region Label & Span
1757 internal async Task RenderLabel(
MarkdownElement Element,
bool IncludeElement)
1759 ContentView Bakup = (ContentView)this.currentElement;
1761 Label ParentLabel =
new Label
1763 LineBreakMode = LineBreakMode.WordWrap,
1767 this.currentElement = ParentLabel;
1769 bool WasInLabel = this.
InLabel;
1770 this.InLabel =
true;
1775 await Element.
Render(
this);
1781 this.InLabel = WasInLabel;
1782 this.currentElement = Bakup;
1785 Bakup.Content = ParentLabel;
1793 internal Task RenderSpan(
string Text)
1796 FormattedString FormattedString;
1800 MainLabel =
new Label
1802 LineBreakMode = LineBreakMode.WordWrap,
1805 ContentView Cv = (ContentView)this.currentElement;
1806 Cv.Content = MainLabel;
1807 this.currentElement = Cv;
1811 MainLabel = (Label)this.currentElement;
1812 this.currentElement = MainLabel;
1815 if (MainLabel.FormattedText is
null)
1817 FormattedString =
new();
1821 FormattedString = MainLabel.FormattedText;
1824 Span MainSpan =
new Span();
1825 FormattedString.Spans.Add(MainSpan);
1826 MainLabel.FormattedText = FormattedString;
1828 if (this.Superscript)
1830 else if (this.Subscript)
1833 MainSpan.Text = Text;
1835 if (this.Bold && this.Italic)
1836 MainSpan.FontAttributes = FontAttributes.Bold | FontAttributes.Italic;
1838 MainSpan.FontAttributes = FontAttributes.Bold;
1839 else if (this.Italic)
1840 MainSpan.FontAttributes = FontAttributes.Italic;
1842 if (this.StrikeThrough && this.Underline)
1843 MainSpan.TextDecorations = TextDecorations.Underline | TextDecorations.Strikethrough;
1844 else if (this.StrikeThrough)
1845 MainSpan.TextDecorations = TextDecorations.Strikethrough;
1846 else if (this.Underline)
1847 MainSpan.TextDecorations = TextDecorations.Underline;
1851 MainSpan.FontAttributes |= FontAttributes.Italic;
1852 MainSpan.FontFamily =
"SpaceGroteskBold";
1855 if (this.Hyperlink is not
null)
1857 MainSpan.TextColor = AppColors.BlueLink;
1859 MainSpan.GestureRecognizers.Add(
new TapGestureRecognizer { CommandParameter = this.
Hyperlink,
Command =
new Command(async Parameter => await App.OpenUrlAsync(Parameter as
string ??
string.Empty)) });
1862 return Task.CompletedTask;
1872 GC.SuppressFinalize(
this);
1875 private bool isDisposed;
1882 if (this.isDisposed)
1889 this.isDisposed =
true;
1894 #region Logic Helpers
1898 private bool NeedsToDisplayFootnotes()
1900 IEnumerable<Footnote> DocumentFootnotes = this.GetFootnotes(this.Document.
Footnotes);
1902 if (DocumentFootnotes is
null)
1921 private IEnumerable<Footnote> GetFootnotes(
string[] keys)
1923 foreach(
string Key
in keys)
1940 Image Image =
new Image
1942 Source = Source.Url,
1945 if (Source.Width.HasValue)
1946 Image.WidthRequest = Source.Width.Value;
1948 if (Source.Height.HasValue)
1949 Image.HeightRequest = Source.Height.Value;
1951 ScrollView ScrollView =
new ScrollView
1953 Orientation = ScrollOrientation.Horizontal,
1957 ContentView Cv = (ContentView)this.currentElement;
1958 Cv.Content = ScrollView;
1969 switch (this.Alignment)
1972 return Microsoft.Maui.TextAlignment.Start;
1975 return Microsoft.Maui.TextAlignment.End;
1978 return Microsoft.Maui.TextAlignment.Center;
1981 return Microsoft.Maui.TextAlignment.Center;
1993 ContentView ContentView =
new ContentView();
1995 if (!Margins.Equals(Thickness.Zero))
1996 ContentView.Padding = Margins;
1998 if (BoxStyle is not
null)
1999 ContentView.Style = BoxStyle;
2004 ContentView.HorizontalOptions = LayoutOptions.Center;
2008 ContentView.HorizontalOptions = LayoutOptions.Start;
2012 ContentView.HorizontalOptions = LayoutOptions.End;
2016 this.currentElement = ContentView;
2023 internal void RenderContentView(Thickness Margins)
2025 this.RenderContentView(this.Alignment, Margins,
null);
2037 ContentView Bakup = (ContentView)this.currentElement;
2044 if (Result is XmlDocument Xml)
2051 S = Result?.ToString();
2052 if (!
string.IsNullOrEmpty(S))
2053 await this.RenderSpan(Result?.
ToString() ??
string.Empty);
2058 if (Result is
Graph G)
2063 S =
"data:image/png;base64," + Convert.ToBase64String(Bin, 0, Bin.Length);
2071 Width = Pixels.Width,
2072 Height = Pixels.Height
2075 else if (Result is SKImage Img)
2077 using SKData Data = Img.Encode(SKEncodedImageFormat.Png, 100);
2078 byte[] Bin = Data.ToArray();
2080 S =
"data:image/png;base64," + Convert.ToBase64String(Bin, 0, Bin.Length);
2093 Doc.ProcessAsyncTasks();
2099 Doc.ProcessAsyncTasks();
2101 else if (Result is Exception Ex)
2105 if (Ex is AggregateException Ex2)
2107 VerticalStackLayout Vsl =
new();
2109 foreach (Exception Ex3
in Ex2.InnerExceptions)
2111 Label Label =
new Label
2113 LineBreakMode = LineBreakMode.WordWrap,
2120 Bakup.Content = Vsl;
2124 Label Label =
new Label
2126 LineBreakMode = LineBreakMode.WordWrap,
2131 Bakup.Content = Label;
2136 Label Label =
new Label
2138 LineBreakMode = LineBreakMode.WordWrap,
2140 Text = Result.ToString()
2143 Bakup.Content = Label;
2153 private static void GetMargins(
MarkdownElement Element, out
bool TopMargin, out
bool BottomMargin)
2158 BottomMargin =
false;
2164 TopMargin = BottomMargin =
false;
2171 GetMargins(
E, out TopMargin, out BottomMargin);
2174 GetMargins(
E, out
bool _, out BottomMargin);
2178 GetMargins(SingleChild.Child, out TopMargin, out BottomMargin);
2182 BottomMargin =
true;
2193 await this.OutputMaui(Source,
null);
2204 Image Image =
new Image
2206 Source = Source.Url,
2209 ScrollView Sv =
new ScrollView
2211 Orientation = ScrollOrientation.Horizontal,
2215 VerticalStackLayout Vsl =
new VerticalStackLayout
2217 Spacing = AppStyles.SmallSpacing
2222 if (Title is not
null)
2224 Label Label =
new Label
2226 LineBreakMode = LineBreakMode.WordWrap,
2227 HorizontalTextAlignment =
Microsoft.Maui.TextAlignment.Center,
2233 if (Source.Height.HasValue)
2234 Sv.HeightRequest = Source.Height.Value;
2236 ContentView Cv = (ContentView)this.currentElement;
2248 ContentView Bakup = (ContentView)this.currentElement;
2249 VerticalStackLayout MauiStackLayout =
new VerticalStackLayout();
2253 ContentView ElementContentView =
new();
2254 this.currentElement = ElementContentView;
2256 string? Caption =
null;
2257 if (!Item.
Title.Equals(String.Empty, StringComparison.Ordinal))
2259 Caption = Item.
Title;
2264 Url = Element.Document.CheckURL(Item.Url, null),
2266 Height = Item.Height,
2268 MauiStackLayout.Add(ElementContentView);
2270 Bakup.Content = MauiStackLayout;
2271 this.currentElement = Bakup;
2280 string Url = Source.Url;
2283 if (Url.StartsWith(
"data:", StringComparison.CurrentCultureIgnoreCase) && (i = Url.IndexOf(
"base64,")) > 0)
2285 int? Width = Source.Width;
2286 int? Height = Source.Height;
2287 byte[] Data = Convert.FromBase64String(Url.Substring(i + 7));
2289 using (SKBitmap Bitmap = SKBitmap.Decode(Data))
2291 Width = Bitmap.Width;
2292 Height = Bitmap.Height;
2309 #region State Management
2311 private void ClearState()
2315 this.Italic =
false;
2316 this.StrikeThrough =
false;
2317 this.Underline =
false;
2318 this.Superscript =
false;
2319 this.Subscript =
false;
2321 this.InLabel =
false;
2322 this.Hyperlink =
null;
2325 private StateBackup Backup()
2327 return new StateBackup()
2338 Hyperlink = this.Hyperlink
2342 private void Restore(StateBackup Backup)
2344 this.Alignment = Backup.Alignment;
2345 this.Bold = Backup.Bold;
2346 this.Italic = Backup.Italic;
2347 this.StrikeThrough = Backup.StrikeThrough;
2348 this.Underline = Backup.Underline;
2349 this.Superscript = Backup.Superscript;
2350 this.Subscript = Backup.Subscript;
2351 this.Code = Backup.Code;
2352 this.InLabel = Backup.InLabel;
2353 this.Hyperlink = Backup.Hyperlink;
2356 private class StateBackup
2363 public bool Superscript;
2364 public bool Subscript;
2366 public bool InLabel;
2367 public string? Hyperlink;
Static class that gives access to app-specific themed colors. All colors are fetched directly from th...
static Color DeletedBorder
Deleted Border color.
static Color InsertedBorder
Inserted Border color.
static Color PrimaryForeground
Primary foreground color.
static Color Alert
Alert color.
Static class that gives access to app-specific styles
static Thickness SmallMargins
Small margins
static Thickness SmallRightMargins
Right-only small margins
static Style TableCellOdd
Style for odd table cells
static Style TableCell
Style for table cells
static Thickness SmallBottomMargins
Bottom-only small margins
static Style TableCellEven
Style for even table cells
static Thickness SmallLeftMargins
Left-only small margins
static Thickness SmallTopMargins
Top-only small margins
static Style GetHeaderStyle(int x)
Get style for header of certain size
Renders MAUI objects in a verticalStackLayout from a Markdown document.
Task Render(NumberedItem Element)
Renders Element .
async Task Render(DefinitionList Element)
Renders Element .
Task RenderChild(MarkdownElementSingleChild Element)
Renders the child of Element .
async Task Render(CenterAligned Element)
Renders Element .
Task Render(InvisibleBreak Element)
Renders Element .
async Task Render(Link Element)
Renders Element .
async Task Render(DeleteBlocks Element)
Renders Element .
async Task Render(HtmlBlock Element)
Renders Element .
bool Italic
If text is italic
async Task Render(NumberedList Element)
Renders Element .
async Task Render(DefinitionTerms Element)
Renders Element .
Task Render(UnnumberedItem Element)
Renders Element .
async Task Render(Footnote Element)
Renders Element .
VerticalStackLayout? Output()
Retrieves the final VerticalStackLayout containing all rendered views.
Task Render(DetailsReference Element)
Renders Element .
Task RenderDocument(MarkdownDocument Document, bool Inclusion)
Sets up default state and calls main render function.
Task Render(SectionSeparator Element)
Renders Element .
Task Render(InlineCode Element)
Renders Element .
bool Superscript
If text is superscript
async Task Render(Abbreviation Element)
Renders Element .
bool Underline
If text is underlined
Task Render(MetaReference Element)
Renders Element .
Task Render(HashTag Element)
Renders Element .
async Task Render(StrikeThrough Element)
Renders Element .
async Task Render(SuperScript Element)
Renders Element .
async Task Render(TaskList Element)
Renders Element .
async Task Render(DefinitionDescriptions Element)
Renders Element .
Microsoft.Maui.TextAlignment LabelAlignment()
Helper function to determine label text alignment
Task Render(LineBreak Element)
Renders Element .
async Task Render(Sections Element)
Renders Element .
static async Task< Waher.Content.Emoji.IImageSource > CheckDataUri(Waher.Content.Emoji.IImageSource Source)
Checks a Data URI image, that it contains a decodable image.
Task Render(HtmlEntity Element)
Renders Element .
async Task Render(InsertBlocks Element)
Renders Element .
async Task Render(InlineScript Element)
Renders Element .
Task Render(AutomaticLinkMail Element)
Renders Element .
Task Render(InlineHTML Element)
Renders Element .
Task Render(TaskItem Element)
Renders Element .
async Task Render(NestedBlock Element)
Renders Element .
async Task Render(Delete Element)
Renders Element .
async Task Render(MultimediaReference Element)
Renders Element .
bool Subscript
If text is subscript
bool StrikeThrough
If text is stricken through
async Task Render(Waher.Content.Markdown.Model.SpanElements.Multimedia Element)
Renders Element .
Task Render(HorizontalRule Element)
Renders Element .
virtual void Dispose(bool disposing)
IDisposable.Dispose
async Task Render(Emphasize Element)
Renders Element .
async Task Render(LeftAligned Element)
Renders Element .
async Task Render(Underline Element)
Renders Element .
async Task Render(EmojiReference Element)
Renders Element .
Task Render(AutomaticLinkUrl Element)
Renders Element .
async Task RenderChildren(MarkdownElement Element)
Renders the children of Element .
async Task Render(Table Element)
Renders Element .
string? Hyperlink
Link, if rendering a hyperlink, null otherwise.
async Task Render(RightAligned Element)
Renders Element .
Task Render(InlineText Element)
Renders Element .
Task Render(CommentBlock Element)
Renders Element .
async Task Render(FootnoteReference Element)
Renders Element .
async Task RenderChildren(MarkdownElementChildren Element)
Renders the children of Element .
async Task Render(Insert Element)
Renders Element .
async Task RenderObject(object? Result, bool AloneInParagraph, Variables Variables)
Renders an object such as images, graphs, exceptions, or other documents.
async Task Render(LinkReference Element)
Renders Element .
MarkdownDocument Document
Reference to Markdown document being processed.
async Task Render(MarginAligned Element)
Renders Element .
async Task Render(CodeBlock Element)
Renders Element .
Task Render(HtmlEntityUnicode Element)
Renders Element .
async Task Render(Header Element)
Renders Element .
async Task Render(SubScript Element)
Renders Element .
bool InLabel
If rendering is inside a label.
async Task Render(BlockQuote Element)
Renders Element .
Task RenderDocumentHeader()
Renders the document header.
async Task Render(Paragraph Element)
Renders Element .
Waher.Content.Markdown.Model.TextAlignment Alignment
Current text-alignment.
virtual async Task RenderDocumentEntry(MarkdownDocument Document, bool Inclusion)
Renders a document.
MauiRenderer(MarkdownDocument Document)
Initializes a new instance of the MauiRenderer class.
async Task Render(BulletList Element)
Renders Element .
bool Code
If text is inline code.
async Task RenderFootnotes()
Renders footnotes.
async Task Render(Strong Element)
Renders Element .
Renders XAML (Maui flavour) from a Markdown document.
Helps with parsing of commong data types.
static bool TryParse(string s, out double Value)
Tries to decode a string encoded double.
string ShortName
Emoji short name.
string Unicode
Unicode representation of emoji.
Contains information about an emoji image.
static string EntityToCharacter(string Entity)
Converts an HTML entity into a character.
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.
bool TryGetFootnote(string Key, out Footnote Footnote)
Tries to get a footnote, given its key.
bool TryGetMetaData(string Key, out KeyValuePair< string, bool >[] Value)
Tries to get a meta-data value given its key.
IEnumerable< string > FootnoteOrder
Order of footnotes.
IEmojiSource EmojiSource
Source for emojis in the document.
string[] Footnotes
Gets the keys of the footnotes in the order that they are referenced 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,...
ChunkedList< MarkdownElement > Elements
Markdown elements making up the document.
Abstract base class for block elements with one child.
Represents a block quote in a markdown document.
Represents a bullet list in a markdown document.
Represents a center-aligned set of blocks in a markdown document.
Represents a code block in a markdown document.
string[] Rows
Rows in code block
Represents a definition list in a markdown document.
Represents inserted blocks in a markdown document.
Represents a block of HTML in a markdown document.
Represents inserted blocks in a markdown document.
Represents a left-aligned set of blocks in a markdown document.
Represents a margin-aligned set of blocks in a markdown document.
Represents a nested block with no special formatting rules in a markdown document.
Represents a numbered item in an ordered list.
int Number
Number associated with item.
Represents a numbered list in a markdown document.
Represents a paragraph in a markdown document.
Represents a right-aligned set of blocks in a markdown document.
Represents a sequence of sections.
Represents a table in a markdown document.
TextAlignment[] ColumnAlignments
Table column alignments.
MarkdownElement[][] Headers
Headers in table.
int Columns
Number of columns.
TextAlignment?[][] RowCellAlignments
Row cell alignments in table.
override ChunkedList< MarkdownElement > Children
Any children of the element.
TextAlignment?[][] HeaderCellAlignments
Header cell alignments in table.
MarkdownElement[][] Rows
Rows in table.
Represents a task item in a task list.
bool IsChecked
If the item is checked or not.
Represents a task list in a markdown document.
Represents an unnumbered item in an ordered list.
Abstract base class for all markdown elements with a variable number of child elements.
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.
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.
MarkdownElement Child
Child element.
static Task< string > GetTemporaryFile(byte[] BinaryImage)
Stores an image in binary form as a temporary file. Files will be deleted when application closes.
string Title
Optional title.
string Delimiter
Delimiter string used to identify emoji.
int Level
Level (number of colons used to define the emoji)
EmojiInfo Emoji
Emoji information.
Represents an HTML entity.
Represents an HTML entity in Unicode format.
int Code
Unicode character
bool AloneInParagraph
If the element is alone in a paragraph.
Variables Variables
Variables.
async Task< object > EvaluateExpression()
Evaluates the script expression.
string Value
Unformatted text.
bool TryGetMetaData(out KeyValuePair< string, bool >[] Values)
Tries to get meta-data from the document.
MultimediaItem[] Items
Multimedia items.
Renders HTML from a Markdown document.
Contains settings that the HTML export uses to customize HTML output.
Abstract base class for Markdown renderers.
Task RenderChildren(MarkdownElementChildren Element)
Renders the children of Element .
override string ToString()
Returns the renderer output.
virtual void Dispose()
Disposes of the renderer.
Renders plain text from a Markdown document.
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).
Helps with common XML-related tasks.
static XmlWriterSettings WriterSettings(bool Indent, bool OmitXmlDeclaration)
Gets an XML writer settings object.
Static class managing the application event log. Applications and services log events on this static ...
static Exception UnnestException(Exception Exception)
Unnests an exception, to extract the relevant inner exception.
Handles two-dimensional graphs.
string Title
Title for graph.
ToMatrix(ScriptNode Operand, bool NullCheck, int Start, int Length, Expression Expression)
To-Matrix operator.
Interface for code content Maui XAML renderers.
Interface for Emoji sources. Emoji sources provide emojis to content providers.
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.
Interface for Markdown renderers.
Interface for objects that can be converted into matrices.
TextAlignment
Text alignment of contents.
delegate string ToString(IElement Element)
Delegate for callback methods that convert an element value to a string.