Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
JavaScriptRenderer.cs
1using SkiaSharp;
2using System;
3using System.Collections.Generic;
4using System.IO;
5using System.Text;
6using System.Threading.Tasks;
7using System.Xml;
14using Waher.Events;
15using Waher.Script;
19
21{
26 {
30 public readonly HtmlSettings htmlSettings;
31
37 : base()
38 {
39 this.htmlSettings = HtmlSettings;
40 }
41
48 : base(Output)
49 {
50 this.htmlSettings = HtmlSettings;
51 }
52
59 : base(Document)
60 {
61 this.htmlSettings = HtmlSettings;
62 }
63
71 : base(Output, Document)
72 {
73 this.htmlSettings = HtmlSettings;
74 }
75
79 public override Task RenderDocumentHeader()
80 {
81 string FileName = Path.GetFileName(this.Document.FileName);
82 bool LetterOrUnderscore = false;
83 StringBuilder sb = new StringBuilder();
84
85 foreach (char ch in Path.ChangeExtension(FileName, null))
86 {
87 if (char.IsLetter(ch) || ch == '_')
88 {
89 sb.Append(ch);
90 LetterOrUnderscore = true;
91 }
92 else if (char.IsDigit(ch))
93 {
94 if (!LetterOrUnderscore)
95 {
96 sb.Append('_');
97 LetterOrUnderscore = true;
98 }
99
100 sb.Append(ch);
101 }
102 else
103 {
104 sb.Append('_');
105 LetterOrUnderscore = true;
106 }
107 }
108
109 string Name = sb.ToString();
110
111 this.Output.Append("function CreateInnerHTML");
112 this.Output.Append(Name);
113 this.Output.AppendLine("(ElementId, Args)");
114 this.Output.AppendLine("{");
115 this.Output.AppendLine("\tvar Element = document.getElementById(ElementId);");
116 this.Output.AppendLine("\tif (Element)");
117 this.Output.Append("\t\tElement.innerHTML = CreateHTML");
118 this.Output.Append(Name);
119 this.Output.AppendLine("(Args);");
120 this.Output.AppendLine("}");
121 this.Output.AppendLine();
122 this.Output.Append("function CreateHTML");
123 this.Output.Append(Name);
124 this.Output.AppendLine("(Args)");
125 this.Output.AppendLine("{");
126 this.Output.Append("\tvar Segments = [");
127
128 this.firstSegment = true;
129
130 return Task.CompletedTask;
131 }
132
133 private bool firstSegment;
134
135 private void AppendHtml(string Html)
136 {
137 this.AppendHtml(Html, false, false);
138 }
139
140 private void AppendHtml(string Html, bool Script, bool AppendNewLine)
141 {
142 if (this.firstSegment)
143 this.firstSegment = false;
144 else
145 this.Output.Append(',');
146
147 this.Output.AppendLine();
148 this.Output.Append("\t\t");
149
150 if (Script)
151 this.Output.Append(Html);
152 else
153 {
154 this.Output.Append('"');
155 this.Output.Append(JSON.Encode(Html));
156
157 if (AppendNewLine)
158 this.Output.Append(jsonEncodedNewLine);
159
160 this.Output.Append('"');
161 }
162 }
163
164 private void AppendHtmlLine()
165 {
166 this.AppendHtml(string.Empty, false, true);
167 }
168
169 private void AppendHtmlLine(string Html)
170 {
171 this.AppendHtml(Html, false, true);
172 }
173
174 private static readonly string jsonEncodedNewLine = JSON.Encode(Environment.NewLine);
175
179 public override async Task RenderFootnotes()
180 {
181 this.AppendHtmlLine("<div class=\"footnotes\">");
182 this.AppendHtmlLine("<hr />");
183 this.AppendHtmlLine("<ol>");
184
185 foreach (string Key in this.Document.FootnoteOrder)
186 {
187 if ((this.Document?.TryGetFootnoteNumber(Key, out int Nr) ?? false) &&
188 (this.Document?.TryGetFootnote(Key, out Footnote Footnote) ?? false) &&
190 {
191 this.AppendHtml("<li id=\"fn-" + Nr.ToString() + "\">");
192
194 {
195 InlineHTML Backlink = new InlineHTML(this.Document, "<a href=\"#fnref-" + Nr.ToString() + "\" class=\"footnote-backref\">&#8617;</a>");
196
198 P.AddChildren(Backlink);
199 else
200 Footnote.AddChildren(Backlink);
201
202 Footnote.BacklinkAdded = true;
203 }
204
205 await Footnote.Render(this);
206
207 this.AppendHtmlLine("</li>");
208 }
209 }
210
211 this.AppendHtmlLine("</ol>");
212 this.AppendHtmlLine("</div>");
213 }
214
218 public override Task RenderDocumentFooter()
219 {
220 this.Output.AppendLine("];");
221 this.Output.AppendLine("\treturn Segments.join(\"\");");
222 this.Output.AppendLine("}");
223
224 return Task.CompletedTask;
225 }
226
227 #region Span Elements
228
233 public override async Task Render(Abbreviation Element)
234 {
235 this.AppendHtml("<abbr data-title=\"" +
236 XML.HtmlAttributeEncode(Element.Description).Replace(" ", "&nbsp;") + "\">");
237
238 await this.RenderChildren(Element);
239
240 this.AppendHtml("</abbr>");
241 }
242
247 public override Task Render(AutomaticLinkMail Element)
248 {
249 string s = Element.EMail;
250 byte[] Data = Encoding.ASCII.GetBytes(s);
251 StringBuilder sb = new StringBuilder();
252
253 foreach (byte b in Data)
254 {
255 sb.Append("&#x");
256 sb.Append(b.ToString("X2"));
257 sb.Append(';');
258 }
259
260 s = sb.ToString();
261
262 sb.Clear();
263 Data = Encoding.ASCII.GetBytes("mailto:");
264 foreach (byte b in Data)
265 {
266 sb.Append("&#x");
267 sb.Append(b.ToString("X2"));
268 sb.Append(';');
269 }
270
271 this.AppendHtml("<a href=\"" + sb.ToString() + s + "\">" + s + "</a>");
272
273 return Task.CompletedTask;
274 }
275
280 public override Task Render(AutomaticLinkUrl Element)
281 {
282 bool IsRelative = Element.URL.IndexOf(':') < 0;
283
284 this.AppendHtml("<a href=\"" +
285 XML.HtmlAttributeEncode(this.Document.CheckURL(Element.URL, null)));
286
287 if (!IsRelative)
288 this.AppendHtml("\" target=\"_blank");
289
290 this.AppendHtml("\">" + XML.HtmlValueEncode(Element.URL) + "</a>");
291
292 return Task.CompletedTask;
293 }
294
299 public override async Task Render(Delete Element)
300 {
301 this.AppendHtml("<del>");
302 await this.RenderChildren(Element);
303 this.AppendHtml("</del>");
304 }
305
310 public override Task Render(DetailsReference Element)
311 {
312 if (!(this.Document.Detail is null))
313 return this.RenderDocument(this.Document.Detail, true);
314 else
315 return this.Render((MetaReference)Element);
316 }
317
322 public override Task Render(EmojiReference Element)
323 {
324 IEmojiSource EmojiSource = this.Document.EmojiSource;
325
326 if (EmojiSource is null)
327 this.AppendHtml(Element.Delimiter + Element.Emoji.ShortName + Element.Delimiter);
328 else if (!EmojiSource.EmojiSupported(Element.Emoji))
329 this.AppendHtml(Element.Emoji.Unicode);
330 else
331 {
332 StringBuilder sb = new StringBuilder();
333 EmojiSource.GenerateHTML(sb, Element.Emoji, Element.Level, this.Document.Settings.EmbedEmojis);
334 this.AppendHtml(sb.ToString());
335 }
336
337 return Task.CompletedTask;
338 }
339
344 public override async Task Render(Emphasize Element)
345 {
346 this.AppendHtml("<em>");
347 await this.RenderChildren(Element);
348 this.AppendHtml("</em>");
349 }
350
355 public override async Task Render(FootnoteReference Element)
356 {
357 string s;
358
359 if (!(this.Document?.TryGetFootnote(Element.Key, out Footnote Footnote) ?? false))
360 Footnote = null;
361
362 if (Element.AutoExpand && !(Footnote is null))
363 await this.Render(Footnote);
364 else if (this.Document?.TryGetFootnoteNumber(Element.Key, out int Nr) ?? false)
365 {
366 s = Nr.ToString();
367
368 this.AppendHtml("<sup id=\"fnref-" + s + "\"><a href=\"#fn-" + s +
369 "\" class=\"footnote-ref\">" + s + "</a></sup>");
370
371 if (!(Footnote is null))
372 Footnote.Referenced = true;
373 }
374 }
375
380 public override Task Render(HashTag Element)
381 {
382 this.AppendHtml("<mark");
383
384 string s = this.htmlSettings?.HashtagClass;
385
386 if (!string.IsNullOrEmpty(s))
387 this.AppendHtml(" class=\"" + XML.HtmlAttributeEncode(s) + "\"");
388
389 s = this.htmlSettings?.HashtagClickScript;
390
391 if (!string.IsNullOrEmpty(s))
392 this.AppendHtml(" onclick=\"" + XML.HtmlAttributeEncode(s) + "\"");
393
394 this.AppendHtml(">" + Element.Tag + "</mark>");
395
396 return Task.CompletedTask;
397 }
398
403 public override Task Render(HtmlEntity Element)
404 {
405 if (this.htmlSettings?.XmlEntitiesOnly ?? true)
406 {
407 switch (Element.Entity)
408 {
409 case "quot":
410 case "amp":
411 case "apos":
412 case "lt":
413 case "gt":
414 case "nbsp": // Has syntactic significance when parsing HTML or Markdown
415 this.AppendHtml("&" + Element.Entity + ";");
416 break;
417
418 case "QUOT":
419 case "AMP":
420 case "LT":
421 case "GT":
422 this.AppendHtml("&" + Element.Entity.ToLower() + ";");
423 break;
424
425 default:
426 string s = Html.HtmlEntity.EntityToCharacter(Element.Entity);
427 if (!string.IsNullOrEmpty(s))
428 this.AppendHtml(s);
429 break;
430 }
431 }
432 else
433 this.AppendHtml("&" + Element.Entity + ";");
434
435 return Task.CompletedTask;
436 }
437
442 public override Task Render(HtmlEntityUnicode Element)
443 {
444 this.AppendHtml("&#" + Element.Code.ToString() + ";");
445
446 return Task.CompletedTask;
447 }
448
453 public override Task Render(InlineCode Element)
454 {
455 this.AppendHtml("<code>" + XML.HtmlValueEncode(Element.Code) + "</code>");
456
457 return Task.CompletedTask;
458 }
459
464 public override Task Render(InlineHTML Element)
465 {
466 this.AppendHtml(Element.HTML);
467
468 return Task.CompletedTask;
469 }
470
475 public override Task Render(InlineScript Element)
476 {
477 this.AppendHtml(Element.Expression.Script, true, false);
478 return Task.CompletedTask;
479 }
480
487 public async Task RenderObject(object Result, bool AloneInParagraph, Variables Variables)
488 {
489 if (Result is null)
490 return;
491
492 if (Result is XmlDocument Xml)
493 Result = await MarkdownDocument.TransformXml(Xml, Variables);
494 else if (Result is IToMatrix ToMatrix)
495 Result = ToMatrix.ToMatrix();
496
497 if (Result is Graph G)
498 {
499 PixelInformation Pixels = G.CreatePixels(out GraphSettings GraphSettings);
500 byte[] Bin = Pixels.EncodeAsPng();
501
502 if (AloneInParagraph)
503 this.AppendHtml("<figure>");
504
505 this.AppendHtml("<img border=\"2\" width=\"" + GraphSettings.Width.ToString() +
506 "\" height=\"" + GraphSettings.Height.ToString() +
507 "\" src=\"data:image/png;base64," + Convert.ToBase64String(Bin, 0, Bin.Length) +
508 "\" alt=\"");
509
510 if (G is Graph2D Graph2D && !string.IsNullOrEmpty(Graph2D.Title))
511 this.AppendHtml(XML.Encode(Graph2D.Title));
512 else
513 this.AppendHtml("Graph");
514
515 this.AppendHtml("\" />");
516
517 if (AloneInParagraph)
518 this.AppendHtml("</figure>");
519 }
520 else if (Result is PixelInformation Pixels)
521 {
522 byte[] Bin = Pixels.EncodeAsPng();
523
524 if (AloneInParagraph)
525 this.AppendHtml("<figure>");
526
527 this.AppendHtml("<img border=\"2\" width=\"" + Pixels.Width.ToString() +
528 "\" height=\"" + Pixels.Height.ToString() + "\" src=\"data:image/png;base64," +
529 Convert.ToBase64String(Bin, 0, Bin.Length) + "\" alt=\"Image\" />");
530
531 if (AloneInParagraph)
532 this.AppendHtml("</figure>");
533 }
534 else if (Result is SKImage Img)
535 {
536 using (SKData Data = Img.Encode(SKEncodedImageFormat.Png, 100))
537 {
538 byte[] Bin = Data.ToArray();
539
540 if (AloneInParagraph)
541 this.AppendHtml("<figure>");
542
543 this.AppendHtml("<img border=\"2\" width=\"" + Img.Width.ToString() +
544 "\" height=\"" + Img.Height.ToString() + "\" src=\"data:image/png;base64," +
545 Convert.ToBase64String(Bin, 0, Bin.Length) + "\" alt=\"Image\" />");
546
547 if (AloneInParagraph)
548 this.AppendHtml("</figure>");
549 }
550 }
551 else if (Result is MarkdownDocument Doc)
552 {
553 await this.RenderDocument(Doc, true); // Does not call ProcessAsyncTasks()
554 Doc.ProcessAsyncTasks();
555 }
556 else if (Result is MarkdownContent Markdown)
557 {
558 Doc = await MarkdownDocument.CreateAsync(Markdown.Markdown, Markdown.Settings ?? new MarkdownSettings());
559 await this.RenderDocument(Doc, true); // Does not call ProcessAsyncTasks()
560 Doc.ProcessAsyncTasks();
561 }
562 else if (Result is Exception ex)
563 {
564 ex = Log.UnnestException(ex);
565
566 this.AppendHtmlLine("<font class=\"error\">");
567
568 if (ex is AggregateException ex2)
569 {
570 foreach (Exception ex3 in ex2.InnerExceptions)
571 this.AppendHtmlLine("<p>" + XML.HtmlValueEncode(ex3.Message) + "</p>");
572 }
573 else
574 {
575 if (AloneInParagraph)
576 this.AppendHtml("<p>");
577
578 this.AppendHtml(XML.HtmlValueEncode(ex.Message));
579
580 if (AloneInParagraph)
581 this.AppendHtml("</p>");
582 }
583
584 this.AppendHtmlLine("</font>");
585 }
586 else if (Result is ObjectMatrix M && !(M.ColumnNames is null))
587 {
588 this.AppendHtml("<table><thead><tr>");
589
590 foreach (string s2 in M.ColumnNames)
591 this.AppendHtml("<th>" + FormatText(XML.HtmlValueEncode(s2)) + "</th>");
592
593 this.AppendHtml("</tr></thead><tbody>");
594
595 int x, y;
596
597 for (y = 0; y < M.Rows; y++)
598 {
599 this.AppendHtml("<tr>");
600
601 for (x = 0; x < M.Columns; x++)
602 {
603 this.AppendHtml("<td>");
604
605 object Item = M.GetElement(x, y).AssociatedObjectValue;
606 if (!(Item is null))
607 {
608 if (Item is string s2)
609 this.AppendHtml(FormatText(XML.HtmlValueEncode(s2)));
610 else if (Item is MarkdownElement Element)
611 await Element.Render(this);
612 else
613 this.AppendHtml(FormatText(XML.HtmlValueEncode(Expression.ToString(Item))));
614 }
615
616 this.AppendHtml("</td>");
617 }
618
619 this.AppendHtml("</tr>");
620 }
621
622 this.AppendHtml("</tbody></table>");
623 }
624 else if (Result is Array A)
625 {
626 foreach (object Item in A)
627 await this.RenderObject(Item, false, Variables);
628 }
629 else
630 {
631 if (AloneInParagraph)
632 this.AppendHtml("<p>");
633
634 this.AppendHtml(XML.HtmlValueEncode(Result?.ToString() ?? string.Empty));
635
636 if (AloneInParagraph)
637 this.AppendHtml("</p>");
638 }
639
640 if (AloneInParagraph)
641 this.AppendHtmlLine();
642 }
643
644 private static string FormatText(string s)
645 {
646 return s.Replace("\r\n", "\n").Replace("\n", "<br/>").Replace("\r", "<br/>").
647 Replace("\t", "&nbsp;&nbsp;&nbsp;").Replace(" ", "&nbsp;");
648 }
649
654 public override Task Render(InlineText Element)
655 {
656 this.AppendHtml(XML.HtmlValueEncode(Element.Value));
657
658 return Task.CompletedTask;
659 }
660
665 public override async Task Render(Insert Element)
666 {
667 this.AppendHtml("<ins>");
668 await this.RenderChildren(Element);
669 this.AppendHtml("</ins>");
670 }
671
676 public override Task Render(LineBreak Element)
677 {
678 this.AppendHtmlLine("<br/>");
679
680 return Task.CompletedTask;
681 }
682
687 public override Task Render(Link Element)
688 {
689 return this.Render(Element.Url, Element.Title, Element.Children, Element.Document);
690 }
691
699 public async Task Render(string Url, string Title, IEnumerable<MarkdownElement> ChildNodes, MarkdownDocument Document)
700 {
701 bool IsRelative = Url.IndexOf(':') < 0;
702
703 if (!IsRelative && Url.StartsWith("javascript:", StringComparison.OrdinalIgnoreCase))
704 {
705 this.AppendHtml("<a href=\"#\" onclick=\"" +
706 XML.HtmlAttributeEncode(System.Net.WebUtility.UrlDecode(Url.Substring(11))));
707
708 IsRelative = true;
709 }
710 else
711 this.AppendHtml("<a href=\"" + XML.HtmlAttributeEncode(Document.CheckURL(Url, null)));
712
713 if (!string.IsNullOrEmpty(Title))
714 this.AppendHtml("\" title=\"" + XML.HtmlAttributeEncode(Title));
715
716 if (!IsRelative)
717 this.AppendHtml("\" target=\"_blank");
718
719 this.AppendHtml("\">");
720
721 foreach (MarkdownElement E in ChildNodes)
722 await E.Render(this);
723
724 this.AppendHtml("</a>");
725 }
726
731 public override Task Render(LinkReference Element)
732 {
734
735 if (!(Multimedia is null))
736 return this.Render(Multimedia.Items[0].Url, Multimedia.Items[0].Title, Element.Children, Element.Document);
737 else
738 return this.RenderChildren(Element);
739 }
740
745 public override Task Render(MetaReference Element)
746 {
747 bool FirstOnRow = true;
748
749 if (Element.TryGetMetaData(out KeyValuePair<string, bool>[] Values))
750 {
751 foreach (KeyValuePair<string, bool> P in Values)
752 {
753 if (FirstOnRow)
754 FirstOnRow = false;
755 else
756 this.AppendHtml(" ");
757
758 this.AppendHtml(XML.HtmlValueEncode(P.Key));
759 if (P.Value)
760 {
761 this.AppendHtmlLine("<br/>");
762 FirstOnRow = true;
763 }
764 }
765 }
766
767 return Task.CompletedTask;
768 }
769
774 public override async Task Render(Multimedia Element)
775 {
776 IMultimediaHtmlRenderer Renderer = Element.MultimediaHandler<IMultimediaHtmlRenderer>();
777 if (Renderer is null)
778 await this.RenderChildren(Element);
779 else
780 {
781 using (HtmlRenderer Renderer2 = new HtmlRenderer(this.htmlSettings))
782 {
783 await Renderer.RenderHtml(Renderer2, Element.Items, Element.Children, Element.AloneInParagraph, Element.Document);
784 this.AppendHtml(Renderer2.ToString());
785 }
786 }
787 }
788
793 public override async Task Render(MultimediaReference Element)
794 {
796
797 if (!(Multimedia is null))
798 {
800 if (!(Renderer is null))
801 {
802 using (HtmlRenderer Renderer2 = new HtmlRenderer(this.htmlSettings))
803 {
804 await Renderer.RenderHtml(Renderer2, Multimedia.Items, Element.Children, Element.AloneInParagraph, Element.Document);
805 this.AppendHtml(Renderer2.ToString());
806 }
807 }
808 }
809
810 await this.RenderChildren(Element);
811 }
812
817 public override async Task Render(StrikeThrough Element)
818 {
819 this.AppendHtml("<s>");
820 await this.RenderChildren(Element);
821 this.AppendHtml("</s>");
822 }
823
828 public override async Task Render(Strong Element)
829 {
830 this.AppendHtml("<strong>");
831 await this.RenderChildren(Element);
832 this.AppendHtml("</strong>");
833 }
834
839 public override async Task Render(SubScript Element)
840 {
841 this.AppendHtml("<sub>");
842 await this.RenderChildren(Element);
843 this.AppendHtml("</sub>");
844 }
845
850 public override async Task Render(SuperScript Element)
851 {
852 this.AppendHtml("<sup>");
853 await this.RenderChildren(Element);
854 this.AppendHtml("</sup>");
855 }
856
861 public override async Task Render(Underline Element)
862 {
863 this.AppendHtml("<u>");
864 await this.RenderChildren(Element);
865 this.AppendHtml("</u>");
866 }
867
868 #endregion
869
870 #region Block elements
871
876 public override async Task Render(BlockQuote Element)
877 {
878 this.AppendHtmlLine("<blockquote>");
879 await this.RenderChildren(Element);
880 this.AppendHtmlLine("</blockquote>");
881 }
882
887 public override async Task Render(BulletList Element)
888 {
889 this.AppendHtmlLine("<ul>");
890 await this.RenderChildren(Element);
891 this.AppendHtmlLine("</ul>");
892 }
893
898 public override async Task Render(CenterAligned Element)
899 {
900 this.AppendHtmlLine("<div class='horizontalAlignCenter'>");
901 await this.RenderChildren(Element);
902 this.AppendHtmlLine("</div>");
903 }
904
909 public override async Task Render(CodeBlock Element)
910 {
911 ICodeContentHtmlRenderer Renderer = Element.CodeContentHandler<ICodeContentHtmlRenderer>();
912
913 if (!(Renderer is null))
914 {
915 try
916 {
917 using (HtmlRenderer Renderer2 = new HtmlRenderer(this.htmlSettings))
918 {
919 if (await Renderer.RenderHtml(Renderer2, Element.Rows, Element.Language, Element.Indent, Element.Document))
920 return;
921
922 this.AppendHtml(Renderer2.ToString());
923 }
924 }
925 catch (Exception ex)
926 {
927 ex = Log.UnnestException(ex);
928
929 this.AppendHtmlLine("<font class=\"error\">");
930
931 if (ex is AggregateException ex2)
932 {
933 foreach (Exception ex3 in ex2.InnerExceptions)
934 this.AppendHtmlLine("<p>" + XML.HtmlValueEncode(ex3.Message) + "</p>");
935 }
936 else
937 this.AppendHtml("<p>" + XML.HtmlValueEncode(ex.Message) + "</p>");
938
939 this.AppendHtml("</font>");
940 }
941 }
942
943 int i;
944
945 this.AppendHtml("<pre><code class=\"");
946
947 if (string.IsNullOrEmpty(Element.Language))
948 this.AppendHtml("nohighlight");
949 else
950 this.AppendHtml(XML.Encode(Element.Language));
951
952 this.AppendHtml("\">");
953
954 for (i = Element.Start; i <= Element.End; i++)
955 this.AppendHtmlLine(Element.IndentString + XML.HtmlValueEncode(Element.Rows[i]));
956
957 this.AppendHtmlLine("</code></pre>");
958 }
959
964 public override Task Render(CommentBlock Element)
965 {
966 return Task.CompletedTask;
967 }
968
973 public override async Task Render(DefinitionDescriptions Element)
974 {
975 foreach (MarkdownElement E in Element.Children)
976 {
977 this.AppendHtml("<dd>");
978 await E.Render(this);
979 this.AppendHtmlLine("</dd>");
980 }
981 }
982
987 public override async Task Render(DefinitionList Element)
988 {
989 this.AppendHtmlLine("<dl>");
990 await this.RenderChildren(Element);
991 this.AppendHtmlLine("</dl>");
992 }
993
998 public override async Task Render(DefinitionTerms Element)
999 {
1000 foreach (MarkdownElement E in Element.Children)
1001 {
1002 this.AppendHtml("<dt>");
1003 await E.Render(this);
1004 this.AppendHtmlLine("</dt>");
1005 }
1006 }
1007
1012 public override async Task Render(DeleteBlocks Element)
1013 {
1014 this.AppendHtmlLine("<blockquote class=\"deleted\">");
1015
1016 foreach (MarkdownElement E in Element.Children)
1017 await E.Render(this);
1018
1019 this.AppendHtmlLine("</blockquote>");
1020 }
1021
1026 public override Task Render(Footnote Element)
1027 {
1028 return this.RenderChildren(Element);
1029 }
1030
1035 public override async Task Render(Header Element)
1036 {
1037 this.AppendHtml("<h" + Element.Level.ToString());
1038
1039 string Id = await Element.Id;
1040
1041 if (!string.IsNullOrEmpty(Id))
1042 this.AppendHtml(" id=\"" + XML.HtmlAttributeEncode(Id) + "\"");
1043
1045 this.AppendHtml(" class=\"tocReference\"");
1046
1047 this.AppendHtml(">");
1048
1049 await this.RenderChildren(Element);
1050
1051 this.AppendHtmlLine("</h" + Element.Level.ToString() + ">");
1052 }
1053
1058 public override Task Render(HorizontalRule Element)
1059 {
1060 this.AppendHtmlLine("<hr/>");
1061
1062 return Task.CompletedTask;
1063 }
1064
1069 public override async Task Render(HtmlBlock Element)
1070 {
1071 await this.RenderChildren(Element);
1072 this.AppendHtmlLine();
1073 }
1074
1079 public override async Task Render(InsertBlocks Element)
1080 {
1081 this.AppendHtmlLine("<blockquote class=\"inserted\">");
1082 await this.RenderChildren(Element);
1083 this.AppendHtmlLine("</blockquote>");
1084 }
1085
1090 public override Task Render(InvisibleBreak Element)
1091 {
1092 return Task.CompletedTask; // TODO
1093 }
1094
1099 public override async Task Render(LeftAligned Element)
1100 {
1101 this.AppendHtmlLine("<div class='horizontalAlignLeft'>");
1102 await this.RenderChildren(Element);
1103 this.AppendHtmlLine("</div>");
1104 }
1105
1110 public override async Task Render(MarginAligned Element)
1111 {
1112 this.AppendHtmlLine("<div class='horizontalAlignMargins'>");
1113 await this.RenderChildren(Element);
1114 this.AppendHtmlLine("</div>");
1115 }
1116
1121 public override Task Render(NestedBlock Element)
1122 {
1123 return this.RenderChildren(Element);
1124 }
1125
1130 public override async Task Render(NumberedItem Element)
1131 {
1132 if (Element.NumberExplicit)
1133 this.AppendHtml("<li value=\"" + Element.Number.ToString() + "\">");
1134 else
1135 this.AppendHtml("<li>");
1136
1137 await this.RenderChild(Element);
1138
1139 this.AppendHtmlLine("</li>");
1140 }
1141
1146 public override async Task Render(NumberedList Element)
1147 {
1148 NumberedItem Item;
1149 int Expected = 0;
1150
1151 this.AppendHtmlLine("<ol>");
1152
1153 foreach (MarkdownElement E in Element.Children)
1154 {
1155 Expected++;
1156 Item = E as NumberedItem;
1157
1158 if (Item is null)
1159 await E.Render(this);
1160 else if (Item.Number == Expected)
1161 {
1162 this.AppendHtml("<li>");
1163 await Item.Child.Render(this);
1164 this.AppendHtmlLine("</li>");
1165 }
1166 else
1167 {
1168 await Item.Render(this);
1169 Expected = Item.Number;
1170 }
1171 }
1172
1173 this.AppendHtmlLine("</ol>");
1174 }
1175
1180 public override async Task Render(Paragraph Element)
1181 {
1182 if (!Element.Implicit)
1183 this.AppendHtml("<p>");
1184
1185 await this.RenderChildren(Element);
1186
1187 if (!Element.Implicit)
1188 this.AppendHtmlLine("</p>");
1189 }
1190
1195 public override async Task Render(RightAligned Element)
1196 {
1197 this.AppendHtmlLine("<div class='horizontalAlignRight'>");
1198 await this.RenderChildren(Element);
1199 this.AppendHtmlLine("</div>");
1200 }
1201
1206 public override async Task Render(Sections Element)
1207 {
1208 this.GenerateSectionHTML(Element.InitialNrColumns);
1209 await this.RenderChildren(Element);
1210 this.AppendHtmlLine("</section>");
1211 }
1212
1213 private void GenerateSectionHTML(int NrColumns)
1214 {
1215 this.AppendHtml("<section");
1216
1217 if (NrColumns > 1)
1218 {
1219 string s = NrColumns.ToString();
1220
1221 this.AppendHtml(" style=\"-webkit-column-count:" + s + ";-moz-column-count:" +
1222 s + ";column-count:" + s + "\"");
1223 }
1224
1225 this.AppendHtmlLine(">");
1226 }
1227
1232 public override Task Render(SectionSeparator Element)
1233 {
1234 this.AppendHtmlLine("</section>");
1235 this.GenerateSectionHTML(Element.NrColumns);
1236
1237 return Task.CompletedTask;
1238 }
1239
1244 public override async Task Render(Table Element)
1245 {
1247 MarkdownElement[] Row;
1248 TextAlignment?[] CellAlignments;
1249 int NrRows, RowIndex;
1250 int NrColumns = Element.Columns;
1251 int i, j, k;
1252 bool OnlyRows = false;
1253
1254 if (Element.Headers.Length == 0 && !(this.Document?.Elements is null))
1255 {
1256 OnlyRows = true;
1257 foreach (MarkdownElement Child in this.Document.Elements)
1258 {
1259 if (Child != Element)
1260 {
1261 OnlyRows = false;
1262 break;
1263 }
1264 }
1265 }
1266
1267 if (!OnlyRows)
1268 {
1269 this.AppendHtmlLine("<table>");
1270
1271 if (!string.IsNullOrEmpty(Element.Id))
1272 {
1273 this.AppendHtml("<caption id=\"" + XML.HtmlAttributeEncode(Element.Id) + "\">");
1274
1275 if (string.IsNullOrEmpty(Element.Caption))
1276 this.AppendHtml(XML.HtmlValueEncode(Element.Id));
1277 else
1278 this.AppendHtml(XML.HtmlValueEncode(Element.Caption));
1279
1280 this.AppendHtmlLine("</caption>");
1281 }
1282
1283 this.AppendHtmlLine("<colgroup>");
1284
1285 foreach (TextAlignment Alignment in Element.ColumnAlignments)
1286 this.AppendHtmlLine("<col style=\"text-align:" + Alignment.ToString().ToLower() + "\"/>");
1287
1288 this.AppendHtmlLine("</colgroup>");
1289
1290 this.AppendHtmlLine("<thead>");
1291
1292 NrRows = Element.Headers.Length;
1293 for (RowIndex = 0; RowIndex < NrRows; RowIndex++)
1294 {
1295 Row = Element.Headers[RowIndex];
1296 CellAlignments = Element.HeaderCellAlignments[RowIndex];
1297
1298 this.AppendHtmlLine("<tr>");
1299
1300 for (i = 0; i < NrColumns; i++)
1301 {
1302 E = Row[i];
1303 if (E is null)
1304 continue;
1305
1306 k = 1;
1307 j = i + 1;
1308 while (j < NrColumns && Row[j++] is null)
1309 k++;
1310
1311 this.AppendHtml("<th style=\"text-align:" +
1312 (CellAlignments[i] ?? Element.ColumnAlignments[i]).ToString().ToLower());
1313
1314 if (k > 1)
1315 this.AppendHtml("\" colspan=\"" + k.ToString());
1316
1317 this.AppendHtml("\">");
1318 await E.Render(this);
1319 this.AppendHtmlLine("</th>");
1320 }
1321
1322 this.AppendHtmlLine("</tr>");
1323 }
1324 this.AppendHtmlLine("</thead>");
1325
1326 this.AppendHtmlLine("<tbody>");
1327 }
1328
1329 NrRows = Element.Rows.Length;
1330 for (RowIndex = 0; RowIndex < NrRows; RowIndex++)
1331 {
1332 Row = Element.Rows[RowIndex];
1333 CellAlignments = Element.RowCellAlignments[RowIndex];
1334
1335 this.AppendHtmlLine("<tr>");
1336
1337 for (i = 0; i < NrColumns; i++)
1338 {
1339 E = Row[i];
1340 if (E is null)
1341 continue;
1342
1343 k = 1;
1344 j = i + 1;
1345 while (j < NrColumns && Row[j++] is null)
1346 k++;
1347
1348 this.AppendHtml("<td style=\"text-align:" +
1349 (CellAlignments[i] ?? Element.ColumnAlignments[i]).ToString().ToLower());
1350
1351 if (k > 1)
1352 this.AppendHtml("\" colspan=\"" + k.ToString());
1353
1354 this.AppendHtml("\">");
1355 await E.Render(this);
1356 this.AppendHtmlLine("</td>");
1357 }
1358
1359 this.AppendHtmlLine("</tr>");
1360 }
1361
1362 if (!OnlyRows)
1363 {
1364 this.AppendHtmlLine("</tbody>");
1365 this.AppendHtmlLine("</table>");
1366 }
1367 }
1368
1373 public override async Task Render(TaskItem Element)
1374 {
1375 this.AppendHtml("<li class=\"taskListItem\"><input disabled=\"disabled");
1376
1377 if (Element.CheckPosition > 0)
1378 {
1379 this.AppendHtml("\" id=\"item" + Element.CheckPosition.ToString() +
1380 "\" data-position=\"" + Element.CheckPosition.ToString());
1381 }
1382
1383 this.AppendHtml("\" type=\"checkbox\"");
1384
1385 if (Element.IsChecked)
1386 this.AppendHtml(" checked=\"checked\"");
1387
1388 this.AppendHtml("/><span></span><label class=\"taskListItemLabel\"");
1389
1390 if (Element.CheckPosition > 0)
1391 this.AppendHtml(" for=\"item" + Element.CheckPosition.ToString() + "\"");
1392
1393 this.AppendHtml(">");
1394
1395 if (Element.Child is NestedBlock NestedBlock)
1396 {
1397 bool EndLabel = true;
1398 bool First = true;
1399
1400 foreach (MarkdownElement E in NestedBlock.Children)
1401 {
1402 if (First)
1403 {
1404 First = false;
1405
1406 if (E.InlineSpanElement)
1407 await E.Render(this);
1408 else
1409 {
1410 await NestedBlock.Render(this);
1411 break;
1412 }
1413 }
1414 else
1415 {
1416 if (!E.InlineSpanElement)
1417 {
1418 this.AppendHtml("</label>");
1419 EndLabel = false;
1420 }
1421
1422 await E.Render(this);
1423 }
1424 }
1425
1426 if (EndLabel)
1427 this.AppendHtml("</label>");
1428
1429 this.AppendHtmlLine("</li>");
1430 }
1431 else
1432 {
1433 await Element.Child.Render(this);
1434 this.AppendHtmlLine("</label></li>");
1435 }
1436 }
1437
1442 public override async Task Render(TaskList Element)
1443 {
1444 this.AppendHtmlLine("<ul class=\"taskList\">");
1445 await this.RenderChildren(Element);
1446 this.AppendHtmlLine("</ul>");
1447 }
1448
1453 public override async Task Render(UnnumberedItem Element)
1454 {
1455 this.AppendHtml("<li");
1456
1457 MarkdownDocument Detail = Element.Document.Detail;
1458
1459 if (!(Detail is null))
1460 {
1461 if (Element.Child is Link Link)
1462 {
1463 if (string.Compare(Detail.ResourceName, Link.Url, true) == 0)
1464 this.AppendHtml(" class=\"active\"");
1465 }
1466 else if (Element.Child is LinkReference LinkReference)
1467 {
1468 string Label = LinkReference.Label;
1469 Multimedia Multimedia = Element.Document.GetReference(Label);
1470
1471 if (!(Multimedia is null) && Multimedia.Items.Length == 1 &&
1472 string.Compare(Multimedia.Items[0].Url, Detail.ResourceName, true) == 0)
1473 {
1474 this.AppendHtml(" class=\"active\"");
1475 }
1476 }
1477 }
1478
1479 this.AppendHtml(">");
1480 await Element.Child.Render(this);
1481 this.AppendHtmlLine("</li>");
1482 }
1483
1484 #endregion
1485
1486 }
1487}
string ShortName
Emoji short name.
string Unicode
Unicode representation of emoji.
Helps with common JSON-related tasks.
Definition: JSON.cs:14
static string Encode(string s)
Encodes a string for inclusion in JSON.
Definition: JSON.cs:507
Renders JavaScript from a Markdown document.
async Task RenderObject(object Result, bool AloneInParagraph, Variables Variables)
Generates HTML from Script output.
override async Task Render(Delete Element)
Renders Element .
override async Task Render(TaskItem Element)
Renders Element .
override async Task Render(NumberedItem Element)
Renders Element .
override Task RenderDocumentHeader()
Renders the document header.
override async Task Render(BlockQuote Element)
Renders Element .
override Task Render(Link Element)
Renders Element .
override async Task Render(NumberedList Element)
Renders Element .
override async Task Render(Paragraph Element)
Renders Element .
override async Task Render(BulletList Element)
Renders Element .
override Task Render(DetailsReference Element)
Renders Element .
override async Task Render(MarginAligned Element)
Renders Element .
override Task RenderDocumentFooter()
Renders the document header.
override async Task Render(DeleteBlocks Element)
Renders Element .
override async Task Render(StrikeThrough Element)
Renders Element .
override async Task Render(HtmlBlock Element)
Renders Element .
override Task Render(InlineText Element)
Renders Element .
override async Task Render(SuperScript Element)
Renders Element .
override async Task Render(Table Element)
Renders Element .
override Task Render(HashTag Element)
Renders Element .
override async Task Render(Header Element)
Renders Element .
override async Task Render(TaskList Element)
Renders Element .
override async Task Render(DefinitionDescriptions Element)
Renders Element .
JavaScriptRenderer(HtmlSettings HtmlSettings, MarkdownDocument Document)
Renders JavaScript from a Markdown document.
override async Task Render(LeftAligned Element)
Renders Element .
override async Task Render(Abbreviation Element)
Renders Element .
override async Task RenderFootnotes()
Renders footnotes.
override async Task Render(Multimedia Element)
Renders Element .
override async Task Render(InsertBlocks Element)
Renders Element .
override async Task Render(Insert Element)
Renders Element .
override async Task Render(SubScript Element)
Renders Element .
override Task Render(InlineScript Element)
Renders Element .
override async Task Render(DefinitionTerms Element)
Renders Element .
override Task Render(CommentBlock Element)
Renders Element .
JavaScriptRenderer(StringBuilder Output, HtmlSettings HtmlSettings, MarkdownDocument Document)
Renders JavaScript from a Markdown document.
override Task Render(MetaReference Element)
Renders Element .
override async Task Render(Underline Element)
Renders Element .
override Task Render(LinkReference Element)
Renders Element .
override Task Render(SectionSeparator Element)
Renders Element .
override async Task Render(Strong Element)
Renders Element .
JavaScriptRenderer(HtmlSettings HtmlSettings)
Renders JavaScript from a Markdown document.
override async Task Render(UnnumberedItem Element)
Renders Element .
override Task Render(Footnote Element)
Renders Element .
override Task Render(InlineCode Element)
Renders Element .
override Task Render(NestedBlock Element)
Renders Element .
override async Task Render(Emphasize Element)
Renders Element .
override Task Render(HtmlEntity Element)
Renders Element .
override Task Render(LineBreak Element)
Renders Element .
JavaScriptRenderer(StringBuilder Output, HtmlSettings HtmlSettings)
Renders JavaScript from a Markdown document.
async Task Render(string Url, string Title, IEnumerable< MarkdownElement > ChildNodes, MarkdownDocument Document)
Generates HTML for a link.
override Task Render(HtmlEntityUnicode Element)
Renders Element .
readonly HtmlSettings htmlSettings
HTML settings.
override Task Render(InvisibleBreak Element)
Renders Element .
override Task Render(HorizontalRule Element)
Renders Element .
override Task Render(EmojiReference Element)
Renders Element .
override async Task Render(CodeBlock Element)
Renders Element .
override Task Render(InlineHTML Element)
Renders Element .
override async Task Render(Sections Element)
Renders Element .
override async Task Render(MultimediaReference Element)
Renders Element .
override async Task Render(CenterAligned Element)
Renders Element .
override Task Render(AutomaticLinkUrl Element)
Renders Element .
override async Task Render(RightAligned Element)
Renders Element .
override async Task Render(FootnoteReference Element)
Renders Element .
override Task Render(AutomaticLinkMail Element)
Renders Element .
override async Task Render(DefinitionList Element)
Renders Element .
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 IncludesTableOfContents
If the document contains a Table of Contents.
string CheckURL(string Url, string URL)
Checks the URL if it needs redirection to a proxy.
IEnumerable< MarkdownElement > Elements
Markdown elements making up the document.
IEnumerable< string > FootnoteOrder
Order of footnotes.
IEmojiSource EmojiSource
Source for emojis in the document.
string ResourceName
Local resource name of Markdown document, if referenced through a web server. Master documents use th...
string FileName
Filename of Markdown document. Markdown inclusion will be made relative to this filename.
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,...
Contains settings that the Markdown parser uses to customize its behavior.
Represents a block quote in a markdown document.
Definition: BlockQuote.cs:11
Represents a bullet list in a markdown document.
Definition: BulletList.cs:11
Represents a center-aligned set of blocks in a markdown document.
Represents a code block in a markdown document.
Definition: CodeBlock.cs:16
string IndentString
String used for indentation.
Definition: CodeBlock.cs:273
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
bool BacklinkAdded
If a backlink has been added to the footnote.
Definition: Footnote.cs:69
Represents a header in a markdown document.
Definition: Header.cs:15
Represents a block of HTML in a markdown document.
Definition: HtmlBlock.cs:11
Represents inserted blocks in a markdown document.
Definition: InsertBlocks.cs:11
Represents a left-aligned set of blocks in a markdown document.
Definition: LeftAligned.cs:11
Represents a margin-aligned set of blocks in a markdown document.
Represents a nested block with no special formatting rules in a markdown document.
Definition: NestedBlock.cs:11
override Task Render(IRenderer Output)
Renders the element.
Represents a numbered item in an ordered list.
Definition: NumberedItem.cs:10
bool NumberExplicit
If number is explicitly provided (true) or inferred (false).
Definition: NumberedItem.cs:40
Represents a numbered list in a markdown document.
Definition: NumberedList.cs:11
Represents a paragraph in a markdown document.
Definition: Paragraph.cs:11
bool Implicit
If paragraph is implicit or not.
Definition: Paragraph.cs:41
Represents a right-aligned set of blocks in a markdown document.
Definition: RightAligned.cs:11
int NrColumns
Number of columns in following section.
Represents a sequence of sections.
Definition: Sections.cs:11
int InitialNrColumns
Number of columns for initial section.
Definition: Sections.cs:32
Represents a table in a markdown document.
Definition: Table.cs:11
TextAlignment[] ColumnAlignments
Table column alignments.
Definition: Table.cs:64
MarkdownElement[][] Headers
Headers in table.
Definition: Table.cs:54
TextAlignment?[][] RowCellAlignments
Row cell alignments in table.
Definition: Table.cs:79
TextAlignment?[][] HeaderCellAlignments
Header cell alignments in table.
Definition: Table.cs:74
MarkdownElement[][] Rows
Rows in table.
Definition: Table.cs:59
Represents a task item in a task list.
Definition: TaskItem.cs:10
int CheckPosition
Position of the checkmark in the original markdown text document.
Definition: TaskItem.cs:36
bool IsChecked
If the item is checked or not.
Definition: TaskItem.cs:31
Represents a task list in a markdown document.
Definition: TaskList.cs:11
Represents an unnumbered item in an ordered list.
override IEnumerable< MarkdownElement > Children
Any children of the element.
MarkdownElement LastChild
Last child, or null if none.
void AddChildren(params MarkdownElement[] NewChildren)
Adds children to the element.
Abstract base class for all markdown elements.
abstract Task Render(IRenderer Output)
Renders the element.
virtual IEnumerable< MarkdownElement > Children
Any children of the element.
abstract bool InlineSpanElement
If the element is an inline span element.
MarkdownDocument Document
Markdown document.
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 TryGetMetaData(out KeyValuePair< string, bool >[] Values)
Tries to get meta-data from the document.
MultimediaItem[] Items
Multimedia items.
Definition: Multimedia.cs:40
bool AloneInParagraph
If the element is alone in a paragraph.
Definition: Multimedia.cs:45
bool AloneInParagraph
If the element is alone in a paragraph.
Renders HTML from a Markdown document.
Definition: HtmlRenderer.cs:24
Contains settings that the HTML export uses to customize HTML output.
Definition: HtmlSettings.cs:7
Abstract base class for Markdown renderers.
Definition: Renderer.cs:14
readonly StringBuilder Output
Renderer output.
Definition: Renderer.cs:18
Task RenderChild(MarkdownElementSingleChild Element)
Renders the child of Element .
Definition: Renderer.cs:175
async Task RenderChildren(MarkdownElementChildren Element)
Renders the children of Element .
Definition: Renderer.cs:147
virtual async Task RenderDocument(MarkdownDocument Document, bool Inclusion)
Renders a document.
Definition: Renderer.cs:75
override string ToString()
Returns the renderer output.
Definition: Renderer.cs:130
MarkdownDocument Document
Reference to Markdown document being processed.
Definition: Renderer.cs:23
Helps with common XML-related tasks.
Definition: XML.cs:19
static string HtmlValueEncode(string s)
Differs from Encode(String), in that it does not encode the aposotrophe or the quote.
Definition: XML.cs:209
static string Encode(string s)
Encodes a string for use in XML.
Definition: XML.cs:27
static string HtmlAttributeEncode(string s)
Differs from Encode(String), in that it does not encode the aposotrophe.
Definition: XML.cs:119
Static class managing the application event log. Applications and services log events on this static ...
Definition: Log.cs:13
static Exception UnnestException(Exception Exception)
Unnests an exception, to extract the relevant inner exception.
Definition: Log.cs:818
Class managing a script expression.
Definition: Expression.cs:39
string Script
Original script string.
Definition: Expression.cs:181
static string ToString(double Value)
Converts a value to a string, that can be parsed as part of an expression.
Definition: Expression.cs:4496
Handles two-dimensional graphs.
Definition: Graph2D.cs:26
string Title
Title for graph.
Definition: Graph2D.cs:251
Base class for graphs.
Definition: Graph.cs:79
int Width
Width of graph, in pixels. (Default=640 pixels.)
int Height
Height of graph, in pixels. (Default=480 pixels.)
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 Emoji sources. Emoji sources provide emojis to content providers.
Definition: IEmojiSource.cs:12
Task GenerateHTML(StringBuilder Output, EmojiInfo Emoji, bool EmbedImage)
Generates HTML for a given Emoji.
bool EmojiSupported(EmojiInfo Emoji)
If the emoji is supported by the emoji source.
Interface for multimedia content HTML renderers.
Interface for objects that can be converted into matrices.
Definition: IToMatrix.cs:9
TextAlignment
Text alignment of contents.