outline.cs 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. using FastReport.Utils;
  2. using FastReport.Web.Services;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Net;
  6. using System.Text;
  7. using System.Web;
  8. namespace FastReport.Web
  9. {
  10. partial class WebReport
  11. {
  12. string template_outline()
  13. {
  14. if (!Outline)
  15. return "";
  16. if ((Report.PreparedPages?.OutlineXml?.Count ?? 0) == 0)
  17. return "";
  18. var outline = new StringBuilder();
  19. BuildOutline(outline, Report.PreparedPages.OutlineXml, true);
  20. return $@"
  21. <div class=""{template_FR}-outline"">
  22. <div class=""{template_FR}-outline-inner"">
  23. {outline}
  24. </div>
  25. </div>
  26. <script>
  27. (function(){{{ResourceLoader.GetContent("split.min.js")}}}).call({template_FR});
  28. {template_FR}.outline();
  29. </script>
  30. ";
  31. }
  32. void BuildOutline(StringBuilder sb, XmlItem xml, bool top)
  33. {
  34. for (int i = 0; i < xml.Count; i++)
  35. {
  36. var opened = top && xml.Count == 1;
  37. var styleShow = opened ? @"style=""display:none""" : @"style=""display:block""";
  38. var styleHide = opened ? @"style=""display:block""" : @"style=""display:none""";
  39. var node = xml[i];
  40. var hasChildren = node.Count > 0;
  41. var (text, page, offset) = ReadOutlineNode(node);
  42. var nodeId = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{ID}{page}{offset}{sb.Length}{GetCurrentTabName()}"));
  43. sb.Append($@"<div class=""{template_FR}-outline-node"">");
  44. string caret;
  45. if (hasChildren)
  46. {
  47. caret = $@"<img class=""{template_FR}-outline-caret {template_FR}-js-outline-open-node"" src=""data:image/svg+xml;base64,{GerResourceBase64("caret-right.svg")}"" data-fr-outline-node-id=""{nodeId}"" onclick=""{template_FR}.outlineOpenNode(this);"" {styleShow}>";
  48. caret += $@"<img class=""{template_FR}-outline-caret {template_FR}-js-outline-close-node"" src=""data:image/svg+xml;base64,{GerResourceBase64("caret-down.svg")}"" data-fr-outline-node-id=""{nodeId}"" onclick=""{template_FR}.outlineCloseNode(this);"" {styleHide}>";
  49. }
  50. else
  51. {
  52. caret = $@"<div class=""{template_FR}-outline-caret-blank""></div>";
  53. }
  54. sb.Append($@"<div class=""{template_FR}-outline-text"">");
  55. sb.Append(caret);
  56. sb.Append($@"<img class=""{template_FR}-outline-file"" src=""data:image/svg+xml;base64,{GerResourceBase64("file.svg")}"">");
  57. sb.Append($@"<a onclick=""{template_FR}.outlineGoto({page + 1}, {offset.ToString().Replace(',', '.')});"">{HttpUtility.HtmlEncode(text)}</a>");
  58. sb.Append($@"</div>");
  59. if (hasChildren)
  60. {
  61. sb.Append($@"<div style=""width:100%""></div>"); // line break
  62. sb.Append($@"<div class=""{template_FR}-outline-children"" {styleHide}>");
  63. BuildOutline(sb, node, false);
  64. sb.Append("</div>");
  65. }
  66. sb.Append("</div>");
  67. }
  68. }
  69. (string text, int page, float offset) ReadOutlineNode(XmlItem node)
  70. {
  71. string text = node.GetProp("Text");
  72. int page = 0;
  73. float offset = 0f;
  74. string s = node.GetProp("Page");
  75. if (!s.IsNullOrWhiteSpace())
  76. {
  77. page = int.Parse(s);
  78. s = node.GetProp("Offset");
  79. if (!s.IsNullOrWhiteSpace())
  80. offset = (float)Converter.FromString(typeof(float), s) /* * PDF_DIVIDER*/;
  81. }
  82. return (text, page, offset);
  83. }
  84. }
  85. }