From 9bf2dda6197f0782789630962052f73aa238163d Mon Sep 17 00:00:00 2001 From: FastReports-bot Date: Mon, 6 Apr 2026 11:10:16 +0300 Subject: [PATCH] * sync 04/06/2026 version: 2026.2.0 --- Demos/Reports/QR-Codes.frx | 80 +- .../JsonConnection/JsonTableDataSource.cs | 2 +- FastReport.Base/Export/Html/HTMLExport.cs | 20 +- .../Export/Html/HTMLExportLayers.cs | 18 +- .../Export/Html/HTMLExportUtils.cs | 7 + FastReport.Base/Functions/NumToWordsCn.cs | 274 ++++ FastReport.Base/Functions/StdFunctions.cs | 40 + .../WindowsForms/WindowsFormsReplacement.cs | 7 +- FastReport.Core.Web/Application/Constants.cs | 8 + .../Application/ExportMenuSettings.cs | 5 +- .../Application/Toolbar/ToolbarButton.cs | 4 +- .../Application/Toolbar/ToolbarInput.cs | 2 +- .../Application/Toolbar/ToolbarSelect.cs | 6 +- .../Application/ToolbarSettings.cs | 38 +- .../Application/WebReport.Backend.cs | 1 - FastReport.Core.Web/Application/WebReport.cs | 45 + .../Application/WebReportHtml.Backend.cs | 4 +- .../FastReport.OpenSource.Web.csproj | 68 +- .../FastReport.Web.Shared.props | 57 - .../FastReport.Web.Shared.targets | 26 + .../Services/Implementation/PrintService.cs | 3 + .../Implementation/TextEditService.cs | 8 +- .../ExportSettings/DocxExportSettings.cs | 100 +- .../ExportSettings/EmailExportSettings.cs | 61 +- .../ExportSettings/HtmlExportSettings.cs | 125 +- .../ExportSettings/ImageExportSettings.cs | 139 +- .../ExportSettings/OdsExportSettings.cs | 75 +- .../ExportSettings/OdtExportSettings.cs | 71 +- .../ExportSettings/PdfExportSettings.cs | 163 +-- .../ExportSettings/PptxExportSettings.cs | 58 +- .../ExportSettings/RtfExportSettings.cs | 86 +- .../ExportSettings/SvgExportSettings.cs | 74 +- .../ExportSettings/XlsxExportSettings.cs | 118 +- .../ExportSettings/XmlExportSettings.cs | 74 +- FastReport.Core.Web/Templates/body.cs | 19 +- FastReport.Core.Web/Templates/main.cs | 11 +- .../Templates/modalcontainer.cs | 131 +- FastReport.Core.Web/Templates/outline.cs | 27 +- FastReport.Core.Web/Templates/script.cs | 938 ++------------ FastReport.Core.Web/Templates/style.cs | 1093 +--------------- FastReport.Core.Web/Templates/tabs.cs | 12 +- FastReport.Core.Web/Templates/toolbar.cs | 94 +- FastReport.Web.Base/package.json | 21 + FastReport.Web.Base/postcss.config.js | 28 + FastReport.Web.Base/rollup.config.mjs | 78 ++ .../wwwroot/js/ExportScripts/docx-export.js | 41 + .../wwwroot/js/ExportScripts/email-export.js | 36 + .../export-settings-open-source.js | 2 + .../js/ExportScripts/export-settings.js | 12 + .../wwwroot/js/ExportScripts/export-utils.js | 146 +++ .../wwwroot/js/ExportScripts/html-export.js | 65 + .../wwwroot/js/ExportScripts/image-export.js | 90 ++ .../wwwroot/js/ExportScripts/ods-export.js | 27 + .../wwwroot/js/ExportScripts/odt-export.js | 27 + .../wwwroot/js/ExportScripts/pdf-export.js | 101 ++ .../wwwroot/js/ExportScripts/pptx-export.js | 15 + .../wwwroot/js/ExportScripts/rtf-export.js | 36 + .../wwwroot/js/ExportScripts/svg-export.js | 30 + .../wwwroot/js/ExportScripts/xlsx-export.js | 56 + .../wwwroot/js/ExportScripts/xml-export.js | 27 + FastReport.Web.Base/wwwroot/js/httpclient.js | 66 + .../wwwroot/js/main-scripts.js | 639 +++++++++ FastReport.Web.Base/wwwroot/js/printscript.js | 3 + FastReport.Web.Base/wwwroot/js/searcher.js | 272 ++++ .../wwwroot/js/split.js | 0 FastReport.Web.Base/wwwroot/styles.css | 1142 +++++++++++++++++ 66 files changed, 3985 insertions(+), 3167 deletions(-) create mode 100644 FastReport.Base/Functions/NumToWordsCn.cs delete mode 100644 FastReport.Core.Web/FastReport.Web.Shared.props create mode 100644 FastReport.Core.Web/FastReport.Web.Shared.targets create mode 100644 FastReport.Web.Base/package.json create mode 100644 FastReport.Web.Base/postcss.config.js create mode 100644 FastReport.Web.Base/rollup.config.mjs create mode 100644 FastReport.Web.Base/wwwroot/js/ExportScripts/docx-export.js create mode 100644 FastReport.Web.Base/wwwroot/js/ExportScripts/email-export.js create mode 100644 FastReport.Web.Base/wwwroot/js/ExportScripts/export-settings-open-source.js create mode 100644 FastReport.Web.Base/wwwroot/js/ExportScripts/export-settings.js create mode 100644 FastReport.Web.Base/wwwroot/js/ExportScripts/export-utils.js create mode 100644 FastReport.Web.Base/wwwroot/js/ExportScripts/html-export.js create mode 100644 FastReport.Web.Base/wwwroot/js/ExportScripts/image-export.js create mode 100644 FastReport.Web.Base/wwwroot/js/ExportScripts/ods-export.js create mode 100644 FastReport.Web.Base/wwwroot/js/ExportScripts/odt-export.js create mode 100644 FastReport.Web.Base/wwwroot/js/ExportScripts/pdf-export.js create mode 100644 FastReport.Web.Base/wwwroot/js/ExportScripts/pptx-export.js create mode 100644 FastReport.Web.Base/wwwroot/js/ExportScripts/rtf-export.js create mode 100644 FastReport.Web.Base/wwwroot/js/ExportScripts/svg-export.js create mode 100644 FastReport.Web.Base/wwwroot/js/ExportScripts/xlsx-export.js create mode 100644 FastReport.Web.Base/wwwroot/js/ExportScripts/xml-export.js create mode 100644 FastReport.Web.Base/wwwroot/js/httpclient.js create mode 100644 FastReport.Web.Base/wwwroot/js/main-scripts.js create mode 100644 FastReport.Web.Base/wwwroot/js/printscript.js create mode 100644 FastReport.Web.Base/wwwroot/js/searcher.js rename FastReport.Core.Web/Resources/split.min.js => FastReport.Web.Base/wwwroot/js/split.js (100%) create mode 100644 FastReport.Web.Base/wwwroot/styles.css diff --git a/Demos/Reports/QR-Codes.frx b/Demos/Reports/QR-Codes.frx index 7125b1a7..51904fea 100644 --- a/Demos/Reports/QR-Codes.frx +++ b/Demos/Reports/QR-Codes.frx @@ -1,7 +1,7 @@  - + - + @@ -16,24 +16,84 @@ - - + + - - - - + + + + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FastReport.Base/Data/JsonConnection/JsonTableDataSource.cs b/FastReport.Base/Data/JsonConnection/JsonTableDataSource.cs index 7db58cd5..1188d0fc 100644 --- a/FastReport.Base/Data/JsonConnection/JsonTableDataSource.cs +++ b/FastReport.Base/Data/JsonConnection/JsonTableDataSource.cs @@ -272,7 +272,7 @@ internal static void InitSchema(Column table, JsonSchema schema, bool simpleStru else if (kv.Value.Type == "array") { Column c = new JsonTableDataSource(); - c.Name = kv.Key; + c.Name = table.Report?.Dictionary?.CreateUniqueName(kv.Key) ?? kv.Key; c.Alias = kv.Key; c.PropName = kv.Key; c.DataType = kv.Value.DataType; diff --git a/FastReport.Base/Export/Html/HTMLExport.cs b/FastReport.Base/Export/Html/HTMLExport.cs index c70b74ba..0f944928 100644 --- a/FastReport.Base/Export/Html/HTMLExport.cs +++ b/FastReport.Base/Export/Html/HTMLExport.cs @@ -215,6 +215,18 @@ public bool Layers set { layers = value; } } + /// + /// For internal use only. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public string PrintScriptSrc { get; set; } + + /// + /// For internal use only. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public bool DisableInlineScript { get; set; } + /// /// For internal use only. /// @@ -618,7 +630,13 @@ private void DoPageStart(Stream stream, string documentTitle) private void DoPageEnd(Stream stream, bool print) { if (print) - ExportUtils.WriteLn(stream, PRINT_JS); + { + if (string.IsNullOrEmpty(PrintScriptSrc)) + ExportUtils.WriteLn(stream, PRINT_JS); + else + ExportUtils.WriteLn(stream, $@""); + } + ExportUtils.WriteLn(stream, BODY_END); ExportUtils.Write(stream, templates.PageTemplateFooter); } diff --git a/FastReport.Base/Export/Html/HTMLExportLayers.cs b/FastReport.Base/Export/Html/HTMLExportLayers.cs index 7b329c00..7983c4ca 100644 --- a/FastReport.Base/Export/Html/HTMLExportLayers.cs +++ b/FastReport.Base/Export/Html/HTMLExportLayers.cs @@ -93,9 +93,7 @@ private void Layer(FastString Page, ReportComponentBase obj, obj.AbsLeft.ToString("#0"), obj.AbsTop.ToString("#0")); - Page.Append(" onclick=\"") - .AppendFormat(OnClickTemplate, ReportID, onclick, eventParam) - .Append("\""); + Page.Append(" " + ClickEvent(onclick, eventParam)); } Page.Append(">"); @@ -148,8 +146,8 @@ private string GetHref(ReportComponentBase obj) EncodeURL(obj.Name), // object name for security reasons EncodeURL(obj.Hyperlink.ReportParameter), EncodeURL(obj.Hyperlink.Value)); - string onClick = String.Format(OnClickTemplate, ReportID, "detailed_report", url); - href = String.Format("", hrefStyle, onClick); + string onClick = ClickEvent("detailed_report", url); + href = String.Format("", hrefStyle, onClick); } else if (obj.Hyperlink.Kind == HyperlinkKind.DetailPage) { @@ -157,8 +155,8 @@ private string GetHref(ReportComponentBase obj) EncodeURL(obj.Name), EncodeURL(obj.Hyperlink.ReportParameter), EncodeURL(obj.Hyperlink.Value)); - string onClick = String.Format(OnClickTemplate, ReportID, "detailed_page", url); - href = String.Format("", hrefStyle, onClick); + string onClick = ClickEvent("detailed_page", url); + href = String.Format("", hrefStyle, onClick); } else if (SinglePage) { @@ -171,12 +169,12 @@ private string GetHref(ReportComponentBase obj) { string onClick = String.Empty; if (obj.Hyperlink.Kind == HyperlinkKind.Bookmark) - onClick = String.Format(OnClickTemplate, ReportID, "bookmark", url); + onClick = ClickEvent("bookmark", url); else if (obj.Hyperlink.Kind == HyperlinkKind.PageNumber) - onClick = String.Format(OnClickTemplate, ReportID, "goto", url); + onClick = ClickEvent("goto", url); if (onClick != String.Empty) - href = String.Format("", hrefStyle, onClick); + href = String.Format("", hrefStyle, onClick); } } return href; diff --git a/FastReport.Base/Export/Html/HTMLExportUtils.cs b/FastReport.Base/Export/Html/HTMLExportUtils.cs index 2df78610..dfd148ff 100644 --- a/FastReport.Base/Export/Html/HTMLExportUtils.cs +++ b/FastReport.Base/Export/Html/HTMLExportUtils.cs @@ -114,6 +114,13 @@ private void WriteMimePart(Stream stream, string mimetype, string charset, strin sb.Clear(); } + private string ClickEvent(string func, string parametrs) + { + if (DisableInlineScript) + return OnClickTemplate.Replace("{0}", func).Replace("{1}", parametrs); + return $"onclick=\"{String.Format(OnClickTemplate, ReportID, func, parametrs)}\""; + } + private void WriteMHTHeader(Stream Stream, string FileName) { FastString sb = new FastString(256); diff --git a/FastReport.Base/Functions/NumToWordsCn.cs b/FastReport.Base/Functions/NumToWordsCn.cs new file mode 100644 index 00000000..55ac8902 --- /dev/null +++ b/FastReport.Base/Functions/NumToWordsCn.cs @@ -0,0 +1,274 @@ +using System.Text; +using System.Collections.Generic; + +namespace FastReport.Functions +{ + /// + /// Converts numbers to Chinese financial notation (大写) for currencies CNY, USD, EUR. + /// + internal class NumToWordsCn : NumToWordsBase + { + private static Dictionary currencyList; + + private static readonly string Zero = "零"; + + private static readonly string[] FixedWords = + { + Zero, "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖" + }; + + private static readonly string Ten = "拾"; // 10 + private static readonly string Hundred = "佰"; // 100 + private static readonly string Thousand = "仟"; // 1 000 + private static readonly string TenThousand = "万"; // 10 000 + private static readonly string HundredMillion = "亿"; // 100 000 000 + + private static readonly string Yuan = "元"; // Chinese Yuan (CNY) + private static readonly string Jiao = "角"; // 0.1 Yuan (1/10 of Yuan) + private static readonly string Fen = "分"; // 0.01 Yuan (1/100 of Yuan) + private static readonly string USD = "美元"; // US Dollar + private static readonly string USCent = "美分"; // US Cents + private static readonly string EUR = "欧元"; // Euro + private static readonly string EuroCent = "欧分"; // Euro Cents + + private static readonly string WholeAmount = "整"; // "Exact amount" (used for whole numbers without fractional part) + private static readonly string Minus = "负"; + + private static readonly WordInfo unused = new WordInfo(""); + + private bool _hasNonZeroIntegerPart = false; + + protected override void Str(long value, WordInfo senior, StringBuilder result) + { + if (IsFractionalUnit(senior)) + { + HandleFractionalPart(value, senior, result); + } + else + { + HandleIntegerPart(value, senior, result); + } + } + + private void HandleFractionalPart(long value, WordInfo senior, StringBuilder result) + { + if (value == 0) + { + result.Append(WholeAmount); + return; + } + + if (senior.one == Fen) + { + HandleCnyFractional(value, result); + } + else + { + HandleForeignCurrencyFractional(value, senior, result); + } + } + + /// + /// Handles USD/EUR fractional part as cent amounts. + /// Adds "零" before single-digit cents when integer part exists. + /// + private void HandleForeignCurrencyFractional(long value, WordInfo senior, StringBuilder result) + { + string fractionalPart = ConvertInteger(value); + // Add "零" before single-digit cents if integer part is non-zero + if (_hasNonZeroIntegerPart && value < 10) + { + result.Append(Zero); + } + result.Append(fractionalPart); + + if (value != 0) + { + if (senior.one == USCent) result.Append(USCent); + else if (senior.one == EuroCent) result.Append(EuroCent); + + } + } + + /// + /// Handles CNY fractional part with 角(jiao)/分(fen) structure. + /// Adds "零" (zero) between integer part and 分 when 角 is missing. + /// + private void HandleCnyFractional(long value, StringBuilder result) + { + int jiao = (int)(value / 10); + int fen = (int)(value % 10); + + if (jiao > 0) + result.Append(FixedWords[jiao]).Append(Jiao); + + if (fen > 0) + { + // Add "零" only if there's no 角 but integer part exists + if (jiao == 0 && _hasNonZeroIntegerPart) + result.Append(Zero); + result.Append(FixedWords[fen]).Append(Fen); + } + } + + private void HandleIntegerPart(long value, WordInfo senior, StringBuilder result) + { + _hasNonZeroIntegerPart = (value != 0); + + string integerPart = ConvertInteger(value); + if (value == 0 && string.IsNullOrEmpty(integerPart)) + { + integerPart = Zero; + } + result.Append(integerPart); + + // Add currency symbol + if (senior.one == Yuan) result.Append(Yuan); + else if (senior.one == USD) result.Append(USD); + else if (senior.one == EUR) result.Append(EUR); + } + + private bool IsFractionalUnit(WordInfo unit) + { + return (unit != null) && + (unit.one == Fen || unit.one == USCent || unit.one == EuroCent); + } + + /// + /// Converts integer number to Chinese financial notation using 亿/万 blocks. + /// + private string ConvertInteger(long num) + { + if (num == 0) return ""; + + long units = num % 10000; + long tenThousand = (num / 10000) % 10000; + long hundredMillion = num / 100000000; + + StringBuilder sb = new StringBuilder(); + + // 亿 + if (hundredMillion > 0) + { + sb.Append(ConvertFourDigits((int)hundredMillion)); + sb.Append(HundredMillion); + } + + // 万 + if (tenThousand > 0) + { + // Missing digits between 亿 and 万 blocks + if (hundredMillion > 0 && units > 0 && tenThousand < 1000) + { + if (!sb.ToString().EndsWith(Zero)) + sb.Append(Zero); + } + sb.Append(ConvertFourDigits((int)tenThousand)); + sb.Append(TenThousand); + } + else if (hundredMillion > 0 && units > 0) + { + sb.Append(Zero); + } + + if (units > 0) + { + string unitStr = ConvertFourDigits((int)units); + // Missing thousands after 万 block + if (tenThousand > 0 && units < 1000 && !unitStr.StartsWith(Zero)) + { + unitStr = Zero + unitStr; + } + sb.Append(unitStr); + } + + return sb.ToString(); + } + + /// + /// Converts 4-digit number to Chinese financial notation. + /// + private string ConvertFourDigits(int num) + { + if (num == 0) return ""; + StringBuilder sb = new StringBuilder(); + + bool hasThousands = false; + bool hasHundreds = false; + + if (num >= 1000) + { + sb.Append(FixedWords[num / 1000]).Append(Thousand); + num %= 1000; + hasThousands = true; + } + + if (num >= 100) + { + sb.Append(FixedWords[num / 100]).Append(Hundred); + num %= 100; + hasHundreds = true; + } + else if ((hasThousands) && num > 0) + { + // Missing hundreds between thousands and lower digits + sb.Append(Zero); + } + + if (num >= 10) + { + sb.Append(FixedWords[num / 10]).Append(Ten); + num %= 10; + } + else if ((hasThousands || hasHundreds) && num > 0) + { + // Missing tens between higher digits and units + if (!sb.ToString().EndsWith(Zero)) + sb.Append(Zero); + } + + if (num > 0) + { + sb.Append(FixedWords[num]); + } + + return sb.ToString(); + } + + protected override int GetFixedWordsCount() => 10; + protected override string GetFixedWords(bool male, long value) => + (value >= 0 && value < FixedWords.Length) ? FixedWords[value] : string.Empty; + protected override string GetTen(bool male, long value) => string.Empty; + protected override string GetHund(bool male, long value) => string.Empty; + + protected override WordInfo GetThousands() => unused; + protected override WordInfo GetMillions() => unused; + protected override WordInfo GetMilliards() => unused; + protected override WordInfo GetTrillions() => unused; + + protected override CurrencyInfo GetCurrency(string currencyName) + { + currencyName = currencyName.ToUpper(); + if (currencyList.TryGetValue(currencyName, out var info)) + return info; + return currencyList["CNY"]; + } + + protected override string GetZero() => Zero; + protected override string GetMinus() => Minus; + protected override string GetDecimalSeparator() => string.Empty; + protected override string Get10_1Separator() => string.Empty; + protected override string Get100_10Separator() => string.Empty; + protected override string Case(long value, WordInfo info) => info.one; + + static NumToWordsCn() + { + currencyList = new Dictionary + { + ["CNY"] = new CurrencyInfo(new WordInfo(Yuan), new WordInfo(Fen)), + ["USD"] = new CurrencyInfo(new WordInfo(USD), new WordInfo(USCent)), + ["EUR"] = new CurrencyInfo(new WordInfo(EUR), new WordInfo(EuroCent)) + }; + } + } +} \ No newline at end of file diff --git a/FastReport.Base/Functions/StdFunctions.cs b/FastReport.Base/Functions/StdFunctions.cs index ddd36f5a..d3422523 100644 --- a/FastReport.Base/Functions/StdFunctions.cs +++ b/FastReport.Base/Functions/StdFunctions.cs @@ -917,6 +917,44 @@ public static string ToWordsEs(object value, string one, string many, bool decim return new NumToWordsEs().ConvertNumber(Convert.ToDecimal(value), true, one, many, many, decimalPartToWord); } + /// + /// Converts a currency value to a Chinese financial (大写) string representation. + /// + /// The currency value to convert. + /// The string representation of the specified value. + public static string ToWordsCn(object value) + { + return ToWordsCn(value, "CNY"); + } + + /// + /// Converts a currency value to a Chinese financial (大写) string representation, using the specified currency. + /// + /// The currency value to convert. + /// The 3-digit ISO name of the currency, for example "EUR". + /// The string representation of the specified value. + public static string ToWordsCn(object value, string currencyName) + { + var result = new NumToWordsCn().ConvertCurrency(Convert.ToDecimal(value), currencyName, true); + + // "整" means "without pennies/cents", "whole amount" and is added at the end of the amount when the fractional part = 0 + if (!result.EndsWith("整")) + { + // In financial practices of China when the amount is < 1, the currency is not specified with "零" (zero) + result = result.Replace("零元", "") // CNY + .Replace("零美元", "") // USD + .Replace("零欧元", ""); // EUR + } + + // The base class adds a space after the minus sign (负), but spaces are not used in the Chinese notation + if (result.StartsWith("负 ")) + { + result = $"负{result.Substring(2)}"; + } + + return result; + } + /// /// Converts a currency value to a russian string representation of that value. /// @@ -1813,6 +1851,8 @@ internal static void Register() RegisteredObjects.InternalAddFunction(myConv.GetMethod("ToWords", new Type[] { typeof(object), typeof(string), typeof(bool) }), "Conversion,ToWords"); RegisteredObjects.InternalAddFunction(myConv.GetMethod("ToWords", new Type[] { typeof(object), typeof(string), typeof(string) }), "Conversion,ToWords"); RegisteredObjects.InternalAddFunction(myConv.GetMethod("ToWords", new Type[] { typeof(object), typeof(string), typeof(string), typeof(bool) }), "Conversion,ToWords"); + RegisteredObjects.InternalAddFunction(myConv.GetMethod("ToWordsCn", new Type[] { typeof(object) }), "Conversion,ToWordsCn"); + RegisteredObjects.InternalAddFunction(myConv.GetMethod("ToWordsCn", new Type[] { typeof(object), typeof(string) }), "Conversion,ToWordsCn"); RegisteredObjects.InternalAddFunction(myConv.GetMethod("ToWordsIn", new Type[] { typeof(object) }), "Conversion,ToWordsIn"); RegisteredObjects.InternalAddFunction(myConv.GetMethod("ToWordsIn", new Type[] { typeof(object), typeof(bool) }), "Conversion,ToWordsIn"); RegisteredObjects.InternalAddFunction(myConv.GetMethod("ToWordsIn", new Type[] { typeof(object), typeof(string) }), "Conversion,ToWordsIn"); diff --git a/FastReport.Compat/shared/WindowsForms/WindowsFormsReplacement.cs b/FastReport.Compat/shared/WindowsForms/WindowsFormsReplacement.cs index 20e2b461..b1c920cd 100644 --- a/FastReport.Compat/shared/WindowsForms/WindowsFormsReplacement.cs +++ b/FastReport.Compat/shared/WindowsForms/WindowsFormsReplacement.cs @@ -1386,12 +1386,13 @@ public class MonthCalendar : Control public SelectionRange SelectionRange { get => new SelectionRange(SelectionStart, SelectionEnd); - set - { + set + { SelectionStart = value.Start; - SelectionEnd = value.End; + SelectionEnd = value.End; } } + public DateTime SelectionStart = DateTime.Now; // } diff --git a/FastReport.Core.Web/Application/Constants.cs b/FastReport.Core.Web/Application/Constants.cs index 32312bb4..f9e8b1ea 100644 --- a/FastReport.Core.Web/Application/Constants.cs +++ b/FastReport.Core.Web/Application/Constants.cs @@ -12,6 +12,14 @@ internal static class Constants } + internal static class JSEvents + { + internal const string CLICK = "click"; + internal const string INPUT = "input"; + internal const string CHANGE = "change"; + } + + #if DIALOGS public partial class Dialog { diff --git a/FastReport.Core.Web/Application/ExportMenuSettings.cs b/FastReport.Core.Web/Application/ExportMenuSettings.cs index b9ac04a7..d36db5d4 100644 --- a/FastReport.Core.Web/Application/ExportMenuSettings.cs +++ b/FastReport.Core.Web/Application/ExportMenuSettings.cs @@ -61,12 +61,13 @@ internal string UserFontSettingsStyle internal string FixedContainerPosition { - get => PinnedSettingsPosition ? "position: fixed; top: 0; left: 0;" : ""; + get => PinnedSettingsPosition ? "--container-position: fixed; --container-top: 0; --container-left: 0;" : ""; } internal string FixedContainerTags { - get => PinnedSettingsPosition ? "position : fixed; top: 50%; left: 50%; transform: translate(-50%, -50%);" : ""; + get => PinnedSettingsPosition ? + "--fixed-container-position: fixed; --fixed-container-top: 50%; --fixed-container-left: 50%; --fixed-container-transform: translate(-50%, -50%);" : ""; } internal string UserFontSettingsFamily diff --git a/FastReport.Core.Web/Application/Toolbar/ToolbarButton.cs b/FastReport.Core.Web/Application/Toolbar/ToolbarButton.cs index 24174dcd..44e8927f 100644 --- a/FastReport.Core.Web/Application/Toolbar/ToolbarButton.cs +++ b/FastReport.Core.Web/Application/Toolbar/ToolbarButton.cs @@ -25,8 +25,8 @@ internal override string Render(string template_FR) ? scriptButton.Script : $"{template_FR}.customMethodInvoke('{ID}', this.value)"; - return $@"
- + return $@"
+
"; } } diff --git a/FastReport.Core.Web/Application/Toolbar/ToolbarInput.cs b/FastReport.Core.Web/Application/Toolbar/ToolbarInput.cs index 2d024663..5121c0f6 100644 --- a/FastReport.Core.Web/Application/Toolbar/ToolbarInput.cs +++ b/FastReport.Core.Web/Application/Toolbar/ToolbarInput.cs @@ -39,7 +39,7 @@ internal override string Render(string template_FR) : $"{template_FR}.customMethodInvoke('{ID}', this.value)"; return - $@"
+ $@"
"; } diff --git a/FastReport.Core.Web/Application/Toolbar/ToolbarSelect.cs b/FastReport.Core.Web/Application/Toolbar/ToolbarSelect.cs index ef14d5fc..4c11c758 100644 --- a/FastReport.Core.Web/Application/Toolbar/ToolbarSelect.cs +++ b/FastReport.Core.Web/Application/Toolbar/ToolbarSelect.cs @@ -29,9 +29,9 @@ internal override string Render(string template_FR) var sb = new StringBuilder(); sb.Append( - $@"
- -
"); + $@"
+ +
"); foreach (var item in Items.Where(item => item.Enabled)) sb.Append(item.Render(template_FR)); diff --git a/FastReport.Core.Web/Application/ToolbarSettings.cs b/FastReport.Core.Web/Application/ToolbarSettings.cs index 77cdd19c..03f950ce 100644 --- a/FastReport.Core.Web/Application/ToolbarSettings.cs +++ b/FastReport.Core.Web/Application/ToolbarSettings.cs @@ -178,21 +178,21 @@ internal string StickyToolbarTags { if (Sticky) { - string tags = "position: sticky; position: -webkit-sticky; "; + string tags = "--sticky-toolbar-position: sticky; --sticky-toolbar-position-webkit: -webkit-sticky; "; if(TopOrBottom == -1) { if (Position == Positions.Left || Position == Positions.Right) { if (ContentPosition == ContentPositions.Right) - tags += "bottom: 10px; left: 10px; right: 10px;"; + tags += "--sticky-toolbar-bottom: 10px; --sticky-toolbar-left: 10px; --sticky-toolbar-right: 10px;"; else if (ContentPosition == ContentPositions.Center) - tags += "top: 10px; bottom: 10px; left: 10px; right: 10px;"; + tags += " --sticky-toolbar-top: 10px; --sticky-toolbar-bottom: 10px; --sticky-toolbar-left: 10px; --sticky-toolbar-right: 10px;"; } else - tags += "top: 10px; left: 10px; right: 10px;"; + tags += " --sticky-toolbar-top: 10px; --sticky-toolbar-left: 10px; --sticky-toolbar-right: 10px;"; } else - tags += "bottom: 10px; left: 10px; right: 10px;"; + tags += "--sticky-toolbar-bottom: 10px; --sticky-toolbar-left: 10px; --sticky-toolbar-right: 10px;"; return tags; } else @@ -208,21 +208,21 @@ internal string StickyToolbarTabsTags { int paddingVertical = Height + 10; float paddingHorizontal = Height * 1.55f + 10; - string tags = "position: sticky; position: -webkit-sticky; "; + string tags = "--sticky-toolbar-tabs-position: sticky; --sticky-toolbar-tabs-position-webkit: -webkit-sticky; "; if (TopOrBottom == -1) { if (Position == Positions.Left || Position == Positions.Right) { if (ContentPosition == ContentPositions.Right) - tags += $@"bottom: {paddingVertical}px; left: {paddingHorizontal}px; right: {paddingHorizontal}px;"; + tags += $@"--sticky-toolbar-tabs-bottom: {paddingVertical}px; --sticky-toolbar-tabs-left: {paddingHorizontal}px; --sticky-toolbar-tabs-right: {paddingHorizontal}px;"; else if (ContentPosition == ContentPositions.Center) - tags += $@"top: {paddingVertical}px; bottom: {paddingVertical}px; left: {paddingHorizontal}px; right: {paddingHorizontal}px;"; + tags += $@" --sticky-toolbar-tabs-top: {paddingVertical}px; --sticky-toolbar-tabs-bottom: {paddingVertical}px; --sticky-toolbar-tabs-left: {paddingHorizontal}px; --sticky-toolbar-tabs-right: {paddingHorizontal}px;"; } else - tags += $@"top: {paddingVertical}px; left: 10px; right: 10px;"; + tags += $@" --sticky-toolbar-tabs-top: {paddingVertical}px; --sticky-toolbar-tabs-left: 10px; --sticky-toolbar-tabs-right: 10px;"; } else - tags += $@"bottom: {paddingVertical}px; left: 10px; right: 10px;"; + tags += $@"--sticky-toolbar-tabs-bottom: {paddingVertical}px; --sticky-toolbar-tabs-left: 10px; --sticky-toolbar-tabs-right: 10px;"; return tags; } else @@ -230,7 +230,7 @@ internal string StickyToolbarTabsTags } } - internal string ModalContainerPosition => Sticky ? "position: fixed;" : ""; + internal string ModalContainerPosition => Sticky ? "fixed;" : "static"; internal string DropDownListPosition => Position == Positions.Bottom ? "bottom: 100%" : ""; @@ -376,13 +376,13 @@ internal string DropDownMenuPosition switch (Position) { case Positions.Left: - return "left:" + Height + "px;" + "text-align:left;" + "top:8px;"; + return "--toolbar-dropdownmenu-position-left:" + Height + "px;" + " --toolbar-dropdownmenu-text-align:left;" + "--toolbar-dropdownmenu-position-top:8px;"; case Positions.Right: - return "right:" + Height + "px;" + "text-align:right;" + "top:8px;"; + return "--toolbar-dropdownmenu-position-right:" + Height + "px;" + " --toolbar-dropdownmenu-text-align:right;" + "--toolbar-dropdownmenu-position-top:8px;"; case Positions.Bottom: - return "bottom:" + Height + "px;"; + return "--toolbar-dropdownmenu-position-bottom:" + Height + "px;"; default: - return "top:" + Height + "px;"; + return $@"--toolbar-dropdownmenu-position-top: {Height}px;"; } } } @@ -393,13 +393,13 @@ internal string TabsPositionSettings switch (Position) { case Positions.Left: - return "179px"; + return "--toolbar-tab-position: 179px;"; case Positions.Right: - return "179px"; + return "--toolbar-tab-position: 179px;"; case Positions.Bottom: - return "order:1;"; + return "--toolbar-tab-order:1;"; default: - return "auto"; + return "--toolbar-tab-position: auto;"; } } } diff --git a/FastReport.Core.Web/Application/WebReport.Backend.cs b/FastReport.Core.Web/Application/WebReport.Backend.cs index eb85663c..0d9ae422 100644 --- a/FastReport.Core.Web/Application/WebReport.Backend.cs +++ b/FastReport.Core.Web/Application/WebReport.Backend.cs @@ -39,7 +39,6 @@ public string LocalizationFile internal static IResourceLoader ResourceLoader { get; set; } - public HtmlString RenderSync() { return Task.Run(() => Render()).Result; diff --git a/FastReport.Core.Web/Application/WebReport.cs b/FastReport.Core.Web/Application/WebReport.cs index b0f46e31..1501a1a0 100644 --- a/FastReport.Core.Web/Application/WebReport.cs +++ b/FastReport.Core.Web/Application/WebReport.cs @@ -219,6 +219,51 @@ internal string InlineStyle } } + internal string GetStyleVars() + { + return $@" + --wbreport-width: {(Width.IsNullOrWhiteSpace() ? "auto" : Width)}; + --wbreport-height: {(Height.IsNullOrWhiteSpace() ? "auto" : Height)}; + --wbreport-inline-style: {InlineStyle}; + --toolbar-vertical-pos: {Toolbar.Vertical}; + --toolbar-content-pos: {Toolbar.Content}; + --multi-page-border: {(EnableMultiPagePreview && PageBorderVisible ? "0px 2px 4px rgba(0, 0, 0, 0.25)" : "none")}; + --multi-page-margin: {(EnableMultiPagePreview ? "10px" : "")}; + --page-border: {(!EnableMultiPagePreview || !SinglePage ? "0px 2px 4px rgba(0, 0, 0, 0.25)" : "none")}; + --user-font: {Toolbar.UserFontSettings}; + --toolbar-color: {ColorTranslator.ToHtml(Toolbar.Color)}; + --toolbar-direction: {Toolbar.RowOrColumn}; + --toolbar-position: {Toolbar.TopOrBottom} ; + --toolbar-content-align: {Toolbar.Content}; + --toolbar-roundness: {Toolbar.ToolbarRoundness}px; + --toolbar-height: {Toolbar.Height}px; + --toolbar-icon-color: {Toolbar.ColorIcon}; + --searchform-margin-left: {Toolbar.SearchFormLeft}; + --searchform-margin-top: {Toolbar.SearchFormTop}; + --search-highlight-color: {ColorTranslator.ToHtml(Toolbar.SearchHighlight)}; + --toolbar-dropdownmenu-color: {ColorTranslator.ToHtml(Toolbar.DropDownMenuColor)}; + --toolbar-dropdownmenu-text-color: {ColorTranslator.ToHtml(Toolbar.DropDownMenuTextColor)}; + --toolbar-dropdownlist-border: {Toolbar.DropDownListBorder}; + --modal-container-position: {Toolbar.ModalContainerPosition}; + --toolbar-user-font-style: {Toolbar.Exports.UserFontSettingsStyle}; + --toolbar-user-font-family: {Toolbar.Exports.UserFontSettingsFamily}; + --exports-button-color: {ColorTranslator.ToHtml(Toolbar.Exports.Color)}; + --select-arrow-icon: #ffffff url(../Resources/select-arrow.svg) no-repeat; + --exports-font-color: {ColorTranslator.ToHtml(Toolbar.Exports.FontColor)}; + --toolbar-narrow: {Toolbar.ToolbarNarrow}; + --button-active-icon: url(../Resources/button-active.svg) no-repeat; + --report-max-width: {ReportMaxWidth}px; + --transparency-icon: {Toolbar.TransparencyIcon}; + --toolbar-height: {Toolbar.VerticalToolbarHeight}; + {Toolbar.TabsPositionSettings} + {Toolbar.StickyToolbarTabsTags} + {Toolbar.Exports.FixedContainerPosition} + {Toolbar.Exports.FixedContainerTags} + {Toolbar.StickyToolbarTags} + {Toolbar.DropDownMenuPosition} + "; + } + #endregion public WebReport() diff --git a/FastReport.Core.Web/Application/WebReportHtml.Backend.cs b/FastReport.Core.Web/Application/WebReportHtml.Backend.cs index a8fc9f7d..cb224abf 100644 --- a/FastReport.Core.Web/Application/WebReportHtml.Backend.cs +++ b/FastReport.Core.Web/Application/WebReportHtml.Backend.cs @@ -47,7 +47,9 @@ internal StringBuilder ReportInHtml() html.Init_WebMode(); html.Pictures = Pictures; //html.Pictures = Prop.Pictures; html.EmbedPictures = EmbedPictures; //html.EmbedPictures = EmbedPictures; - html.OnClickTemplate = "fr{0}.click(this,'{1}','{2}')"; + html.DisableInlineScript = true; + html.OnClickTemplate = CreateOnClickEvent(ScriptName, "click", "this", "{0}", "{1}");// $"{ScriptName}.click(this,'{{0}}','{{1}}')"; + //html.OnClickTemplate = "fr{0}.click(this,'{1}','{2}')"; html.ReportID = ID; //html.ReportID = Prop.ControlID; html.EnableMargins = EnableMargins; //html.EnableMargins = Prop.EnableMargins; diff --git a/FastReport.Core.Web/FastReport.OpenSource.Web.csproj b/FastReport.Core.Web/FastReport.OpenSource.Web.csproj index 766d3826..31972df4 100644 --- a/FastReport.Core.Web/FastReport.OpenSource.Web.csproj +++ b/FastReport.Core.Web/FastReport.OpenSource.Web.csproj @@ -1,4 +1,4 @@ - + FastReport.OpenSource.Web @@ -17,13 +17,38 @@ true true + _content/FastReport.Web + FastReport.Web + true + + Fast Reports Inc. + Fast Reports Inc. + Fast Reports Inc. + + 9.0 + + ..\FastReport.Web.Base + + true + frlogo192.png + https://www.fast-report.com/en/product/fast-report-net + + reporting, reports, pdf, html, mvc, core + + true $(TargetFrameworks);net6.0-windows + + $(DefineConstants);DIALOGS + + + $(DefineConstants);DESIGNER + - + ../FastReport.OpenSource.snk @@ -62,4 +87,43 @@ + + + Application\%(Filename)%(Extension) + + + %(RecursiveDir)%(Filename)%(Extension) + Never + + + Always + + + %(RecursiveDir)%(Filename)%(Extension) + Never + + + + + + + + + $(AssemblyName).Resources.%(Filename)%(Extension) + + + + + + True + false + + + + + + + + + diff --git a/FastReport.Core.Web/FastReport.Web.Shared.props b/FastReport.Core.Web/FastReport.Web.Shared.props deleted file mode 100644 index 227f1d0e..00000000 --- a/FastReport.Core.Web/FastReport.Web.Shared.props +++ /dev/null @@ -1,57 +0,0 @@ - - - - FastReport.Web - true - - Fast Reports Inc. - Fast Reports Inc. - Fast Reports Inc. - - 9.0 - - true - frlogo192.png - https://www.fast-report.com/products/fast-report-net - - reporting, reports, pdf, html, mvc, core - - true - - - - $(DefineConstants);DIALOGS - - - $(DefineConstants);DESIGNER - - - - - Application\%(Filename)%(Extension) - - - - - $(AssemblyName).Resources.%(Filename)%(Extension) - - - $(AssemblyName).Resources.%(Filename)%(Extension) - - - - - - True - false - - - - - - - - - - - diff --git a/FastReport.Core.Web/FastReport.Web.Shared.targets b/FastReport.Core.Web/FastReport.Web.Shared.targets new file mode 100644 index 00000000..d51a0490 --- /dev/null +++ b/FastReport.Core.Web/FastReport.Web.Shared.targets @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + diff --git a/FastReport.Core.Web/Services/Implementation/PrintService.cs b/FastReport.Core.Web/Services/Implementation/PrintService.cs index 602b25ce..b687afa5 100644 --- a/FastReport.Core.Web/Services/Implementation/PrintService.cs +++ b/FastReport.Core.Web/Services/Implementation/PrintService.cs @@ -44,6 +44,9 @@ private byte[] PrintHtml(WebReport webReport) htmlExport.SubFolder = false; htmlExport.EmbedPictures = webReport.EmbedPictures; htmlExport.EnableMargins = webReport.EnableMargins; + htmlExport.DisableInlineScript = true; + htmlExport.OnClickTemplate = WebReport.CreateOnClickEvent(webReport.ScriptName, "click", "this", "{0}", "{1}");// $"{ScriptName}.click(this,'{{0}}','{{1}}')"; + htmlExport.PrintScriptSrc = "../_content/FastReport.Web/js/printscript.min.js"; //htmlExport.WebImagePrefix = WebUtils.ToUrl(FastReportGlobal.FastReportOptions.RouteBasePath, controller.RouteBasePath, ID, "picture") + "/"; htmlExport.WebImagePrefix = WebUtils.ToUrl(FastReportGlobal.FastReportOptions.RoutePathBaseRoot, FastReportGlobal.FastReportOptions.RouteBasePath, $"preview.getPicture?reportId={webReport.ID}&pictureId="); htmlExport.ExportMode = HTMLExport.ExportType.WebPrint; diff --git a/FastReport.Core.Web/Services/Implementation/TextEditService.cs b/FastReport.Core.Web/Services/Implementation/TextEditService.cs index f235b921..24a086cd 100644 --- a/FastReport.Core.Web/Services/Implementation/TextEditService.cs +++ b/FastReport.Core.Web/Services/Implementation/TextEditService.cs @@ -28,7 +28,7 @@ public string GetTemplateTextEditForm(string click, WebReport webReport) webReport.Res.Root("Buttons"); string okText = webReport.Res.Get("Ok"); string cancelText = webReport.Res.Get("Cancel"); - result = Template_textedit_form(textObject.Text, okText, cancelText); + result = Template_textedit_form(webReport, textObject.Text, okText, cancelText); }); return result; @@ -39,7 +39,7 @@ public string GetTemplateTextEditForm(string click, WebReport webReport) return null; } - private static string Template_textedit_form(string text, string okText, string cancelText) => $@" + private static string Template_textedit_form(WebReport webReport, string text, string okText, string cancelText) => $@" @@ -67,8 +67,8 @@ private static string Template_textedit_form(string text, string okText, string
- - + + "; diff --git a/FastReport.Core.Web/Templates/ExportSettings/DocxExportSettings.cs b/FastReport.Core.Web/Templates/ExportSettings/DocxExportSettings.cs index 17332bd1..23658bba 100644 --- a/FastReport.Core.Web/Templates/ExportSettings/DocxExportSettings.cs +++ b/FastReport.Core.Web/Templates/ExportSettings/DocxExportSettings.cs @@ -19,56 +19,56 @@ internal string template_DocxExportSettings() return $@"
-
-
+
+
{localizationDocx.Title}
- {(Report.PreparedPages.Count != 1 ? $@" -
-
-
- - +
" : "")}
-
+
-
-
-
-
-
-
-
-
-
+
+
{localizationDocx.RowHeightIs} {localizationDocx.Options}
-
- - @@ -76,60 +76,12 @@ internal string template_DocxExportSettings()
-
- - +{(false ? "" : "")} +
+ +
-
- -"; - +
"; } - } - } diff --git a/FastReport.Core.Web/Templates/ExportSettings/EmailExportSettings.cs b/FastReport.Core.Web/Templates/ExportSettings/EmailExportSettings.cs index 4026d752..0f5abb6d 100644 --- a/FastReport.Core.Web/Templates/ExportSettings/EmailExportSettings.cs +++ b/FastReport.Core.Web/Templates/ExportSettings/EmailExportSettings.cs @@ -15,14 +15,14 @@ internal string template_EmailExportSettings() return $@"
-
-
+
+
{localizationEmail.Title}
-
+
@@ -77,58 +77,13 @@ internal string template_EmailExportSettings()
- -
- - + {(false ? @"" : "")} +
+ +
-
- -"; - +
"; } - } - } #endif \ No newline at end of file diff --git a/FastReport.Core.Web/Templates/ExportSettings/HtmlExportSettings.cs b/FastReport.Core.Web/Templates/ExportSettings/HtmlExportSettings.cs index d0559138..e38d3d91 100644 --- a/FastReport.Core.Web/Templates/ExportSettings/HtmlExportSettings.cs +++ b/FastReport.Core.Web/Templates/ExportSettings/HtmlExportSettings.cs @@ -18,137 +18,66 @@ internal string template_HtmlExportSettings() return $@"
-
-
+
+
{localizationHtml.Title}
- {(Report.PreparedPages.Count != 1 ? $@" -
-
-
- - +
" : "")}
-
+
-
-
- - - - -
-
- - - -
-
- - + {(false ? @"" : "")} +
+ +
-
-"; - - } - +
"; + } } - } diff --git a/FastReport.Core.Web/Templates/ExportSettings/ImageExportSettings.cs b/FastReport.Core.Web/Templates/ExportSettings/ImageExportSettings.cs index 64c49818..dfb059b4 100644 --- a/FastReport.Core.Web/Templates/ExportSettings/ImageExportSettings.cs +++ b/FastReport.Core.Web/Templates/ExportSettings/ImageExportSettings.cs @@ -18,27 +18,27 @@ internal string template_ImageExportSettings() return $@"
-
-
+
+
{localizationImage.Title}
- {(Report.PreparedPages.Count != 1 ? $@" -
-
-
- - +
" : "")}
-
-
+
+
- @@ -47,11 +47,11 @@ internal string template_ImageExportSettings() -

X

-

Y

-
+

X

+

Y

+

{localizationImage.JpegQuality}

- @@ -65,115 +65,24 @@ internal string template_ImageExportSettings()
-
- - -
-
- - + {(false ? @"" : "")} +
+ +
-
-"; - +
"; } - } - } \ No newline at end of file diff --git a/FastReport.Core.Web/Templates/ExportSettings/OdsExportSettings.cs b/FastReport.Core.Web/Templates/ExportSettings/OdsExportSettings.cs index de192bb6..117607ba 100644 --- a/FastReport.Core.Web/Templates/ExportSettings/OdsExportSettings.cs +++ b/FastReport.Core.Web/Templates/ExportSettings/OdsExportSettings.cs @@ -18,84 +18,51 @@ internal string template_OdsExportSettings() return $@"
-
-
+
+
{localizationOdf.OdsTitle}
- {(Report.PreparedPages.Count != 1 ? $@" -
-
-
- - +
" : "")}
-
+
-
-
-
-
-
-
+
-
-
- - + {(false ? @"" : "")} +
+ +
-
-"; - +
"; } - } - } diff --git a/FastReport.Core.Web/Templates/ExportSettings/OdtExportSettings.cs b/FastReport.Core.Web/Templates/ExportSettings/OdtExportSettings.cs index 9242dd5a..b9fa3132 100644 --- a/FastReport.Core.Web/Templates/ExportSettings/OdtExportSettings.cs +++ b/FastReport.Core.Web/Templates/ExportSettings/OdtExportSettings.cs @@ -18,80 +18,47 @@ internal string template_OdtExportSettings() return $@"
-
-
+
+
{localizationOdf.OdtTitle}
- {(Report.PreparedPages.Count != 1 ? $@" -
-
-
- - +
" : "")}
-
+
-
- -
-
+
-
-
- - + {(false ? @"" : "")} +
+ +
-
-"; - +
"; } - } - } diff --git a/FastReport.Core.Web/Templates/ExportSettings/PdfExportSettings.cs b/FastReport.Core.Web/Templates/ExportSettings/PdfExportSettings.cs index 0b813e3a..f1fd530c 100644 --- a/FastReport.Core.Web/Templates/ExportSettings/PdfExportSettings.cs +++ b/FastReport.Core.Web/Templates/ExportSettings/PdfExportSettings.cs @@ -19,27 +19,27 @@ internal string template_PdfExportSettings() return $@"
-
-
+
+
{localizationPdf.Title}
- {(Report.PreparedPages.Count != 1 ? $@" -
-
-
- - +
" : "")}
-
+
-
- @@ -50,31 +50,31 @@ internal string template_PdfExportSettings()
-
-
- -
-
- -
-
+
-
-
+
+

{localizationPdf.JpegQuality}

- @@ -88,127 +88,26 @@ internal string template_PdfExportSettings()
-
- - -
-
- - + {(false ? @"" : "")} +
+ +
-
-"; - +
"; } } - } diff --git a/FastReport.Core.Web/Templates/ExportSettings/PptxExportSettings.cs b/FastReport.Core.Web/Templates/ExportSettings/PptxExportSettings.cs index 72c29484..9b1c7e5e 100644 --- a/FastReport.Core.Web/Templates/ExportSettings/PptxExportSettings.cs +++ b/FastReport.Core.Web/Templates/ExportSettings/PptxExportSettings.cs @@ -8,8 +8,8 @@ namespace FastReport.Web { - partial class WebReport - { + partial class WebReport + { internal string template_PptxExportSettings() { @@ -18,61 +18,41 @@ internal string template_PptxExportSettings() return $@"
-
-
+
+
{localizationPptx.Title}
- {(Report.PreparedPages.Count != 1 ? $@" -
-
-
- - +
" : "")}
-
-
+
+
-
-
-
- - + {(false ? @"" : "")} +
+ +
-"; - +
"; } - } - } diff --git a/FastReport.Core.Web/Templates/ExportSettings/RtfExportSettings.cs b/FastReport.Core.Web/Templates/ExportSettings/RtfExportSettings.cs index 44cf153e..a3a11123 100644 --- a/FastReport.Core.Web/Templates/ExportSettings/RtfExportSettings.cs +++ b/FastReport.Core.Web/Templates/ExportSettings/RtfExportSettings.cs @@ -18,99 +18,57 @@ internal string template_RtfExportSettings() return $@"
-
-
+
+
{localizationRtf.Title}
- {(Report.PreparedPages.Count != 1 ? $@" -
-
-
- - +
" : "")}
-
+
-
- -
-
-
+
+
{localizationRtf.Pictures} {localizationRtf.RTFObjectAs}
-
- -
-
- - + {(false ? @"" : "")} +
+ +
-
-"; - +
"; } - } - } diff --git a/FastReport.Core.Web/Templates/ExportSettings/SvgExportSettings.cs b/FastReport.Core.Web/Templates/ExportSettings/SvgExportSettings.cs index cfa26238..c52c4903 100644 --- a/FastReport.Core.Web/Templates/ExportSettings/SvgExportSettings.cs +++ b/FastReport.Core.Web/Templates/ExportSettings/SvgExportSettings.cs @@ -18,84 +18,48 @@ internal string template_SvgExportSettings() return $@"
-
-
+
+
{localizationSvg.Title}
- {(Report.PreparedPages.Count != 1 ? $@" -
-
-
- - +
" : "")}
-
+
-
- -
- -
-
- - + {(false ? @"" : "")} +
+ +
-
-"; - +
"; } - } - } diff --git a/FastReport.Core.Web/Templates/ExportSettings/XlsxExportSettings.cs b/FastReport.Core.Web/Templates/ExportSettings/XlsxExportSettings.cs index d1dec6c9..dd833276 100644 --- a/FastReport.Core.Web/Templates/ExportSettings/XlsxExportSettings.cs +++ b/FastReport.Core.Web/Templates/ExportSettings/XlsxExportSettings.cs @@ -18,62 +18,62 @@ internal string template_XlsxExportSettings() return $@"
-
-
+
+
{localizationXlsx.Title}
- {(Report.PreparedPages.Count != 1 ? $@" -
-
-
- - +
" : "")}
-
+
-
-
- - -
-
- - -
-
+
-
- -
+

{localizationXlsx.FontScale}

- @@ -89,74 +89,12 @@ internal string template_XlsxExportSettings()
-
- - + {(false ? @"" : "")} +
+ +
-
-"; - +
"; } - } - } diff --git a/FastReport.Core.Web/Templates/ExportSettings/XmlExportSettings.cs b/FastReport.Core.Web/Templates/ExportSettings/XmlExportSettings.cs index 216aa3af..6e6e9d42 100644 --- a/FastReport.Core.Web/Templates/ExportSettings/XmlExportSettings.cs +++ b/FastReport.Core.Web/Templates/ExportSettings/XmlExportSettings.cs @@ -18,81 +18,47 @@ internal string template_XmlExportSettings() return $@"
-
-
+
+
{localizationXml.Title}
- {(Report.PreparedPages.Count != 1 ? $@" -
-
-
- - +
" : "")}
-
+
-
-
- -
-
-
-
- - + {(false ? @"" : "")} +
+ +
-
-"; - +
"; } - } - } diff --git a/FastReport.Core.Web/Templates/body.cs b/FastReport.Core.Web/Templates/body.cs index 1cbf3168..6036c015 100644 --- a/FastReport.Core.Web/Templates/body.cs +++ b/FastReport.Core.Web/Templates/body.cs @@ -8,23 +8,18 @@ string template_body(bool renderBody) { if (!renderBody) return $@" -
- -
-"; - +
+ +
"; + return $@" -
- +
{template_outline()} -
+
{ReportBody()}
+ "; } } diff --git a/FastReport.Core.Web/Templates/main.cs b/FastReport.Core.Web/Templates/main.cs index 413a727c..214d0a4e 100644 --- a/FastReport.Core.Web/Templates/main.cs +++ b/FastReport.Core.Web/Templates/main.cs @@ -5,7 +5,6 @@ namespace FastReport.Web { partial class WebReport { - string template_FR => $"fr{ID}"; internal string template_ROUTE_BASE_PATH => WebUtils.ToUrl(FastReportGlobal.FastReportOptions.RoutePathBaseRoot, FastReportGlobal.FastReportOptions.RouteBasePath); internal string template_export_url(string exportFormat) => $"{template_ROUTE_BASE_PATH}/preview.exportReport?reportId={ID}&exportFormat={exportFormat}"; internal string templte_email_export_url => $"{template_ROUTE_BASE_PATH}/preview.sendEmail?reportId={ID}"; @@ -23,16 +22,14 @@ string template_render(bool renderBody) #endif return $@" -
- +{(!renderBody ? "" : "")} +
- -
+ +
{GetResource("spinner.svg")}
diff --git a/FastReport.Core.Web/Templates/modalcontainer.cs b/FastReport.Core.Web/Templates/modalcontainer.cs index 38926821..952e1ed8 100644 --- a/FastReport.Core.Web/Templates/modalcontainer.cs +++ b/FastReport.Core.Web/Templates/modalcontainer.cs @@ -8,137 +8,14 @@ namespace FastReport.Web { partial class WebReport { - private const string validation = @" - var pageSelector = document.getElementById('PageSelector'); - var pageRange = pageSelector ? pageSelector.value : ''; - var validationRegex = new RegExp(""^(\\s*\\d+\\s*\\-\\s*\\d+\\s*,?|\\s*\\d+\\s*,?)+$""); - - if(!validationRegex.test(pageRange) && pageRange !== """"){ - return; - }"; - - private const string template_pscustom = -@" const pageRange = input.value.trim(); - const validationRegex = /^(\s*\d+\s*-\s*\d+\s*,?|\s*\d+\s*,?)+$/; - let isError = false; - let numbers = []; - - if (pageRange) { - numbers = pageRange.match(/(-\d+|\d+)(,\d+)*(\.\d+)*/g) || []; - numbers = numbers.map(n => Number(n.replace(/,/g, ''))); - numbers.forEach(elem => { - if (elem > AllPages.value) { - isError = true; - } - }); - } - - if (validationRegex.test(pageRange) || pageRange === """") { - PageSelector = `&PageRange=PageNumbers&PageNumbers=${PageSelectorInput[0].value}`; - OnFirst[0].classList.remove('activeButton'); - OnAll[0].classList.remove('activeButton'); - input.classList.remove('input-error'); - okButton.classList.remove(""fr-webreport-popup-disabled-button""); - okButton.disabled = isError; - } else { - input.classList.add('input-error'); - okButton.classList.add(""fr-webreport-popup-disabled-button""); - okButton.disabled = true; - } -"; - - private const string template_modalcontainerscript = -@" var but = document.querySelectorAll('.fr-webreport-settings-btn'); - var modalOverlay = document.querySelector('.modalcontainer-overlay'); - var modalBtnsSubmit = document.querySelectorAll('.fr-webreport-popup-content-btn-submit'); - var activebtn = document.querySelectorAll('.fr-webreport-popup-content-export-parameters-button'); - var modals = document.querySelectorAll('.modalcontainer'); - var okButton = document.getElementById('okButton'); - var input = document.getElementById('PageSelector'); - - modalBtnsSubmit.forEach((el) => { - el.addEventListener('click', (e) => { - modalOverlay.classList.remove('modalcontainer-overlay--visible'); - modals.forEach((el) => { - el.classList.remove('modalcontainer--visible'); - }); - }); - }); - - but.forEach((el) => { - el.addEventListener('click', (e) => { - let path = e.currentTarget.getAttribute('data-path'); - - modals.forEach((el) => { - el.classList.remove('modalcontainer--visible'); - }); - }); - }); - - modalOverlay.addEventListener('click', (e) => { - - if (e.target == modalOverlay || e.target == modalBtnsSubmit) { - modalOverlay.classList.remove('modalcontainer-overlay--visible'); - modals.forEach((el) => { - el.innerHTML = ''; - el.classList.remove('modalcontainer--visible'); - }); - } - }); - - activebtn.forEach((el) => { - el.addEventListener('click', (e) => { - { - if(el.getAttribute('name') != 'OnRgbClick' && el.getAttribute('name') != 'OnCmykClick'){{ - el.classList.toggle('activeButton'); - }} - } - }); - }); - - var PageSelector = '&PageRange=All'; - var OnAll = document.getElementsByName('OnAllClick'); - var OnFirst = document.getElementsByName('OnFirstClick'); - var PageSelectorInput = document.getElementsByName('PageSelectorInput'); - - function OnFirstClick() { - for (var i = 0; i < PageSelectorInput.length; i++) { - PageSelectorInput[i].value = CurrentPage.value; - } - for (var i = 0; i < OnAll.length; i++) { - OnAll[i].classList.remove('activeButton'); - } - PageSelectorInput[0].value = CurrentPage.value; - OnAll[0].classList.remove('activeButton'); - PageSelector = '&PageRange=PageNumbers&PageNumbers=' + CurrentPage.value; - okButton.disabled = false; - okButton.classList.remove(""fr-webreport-popup-disabled-button""); - input.classList.remove('input-error'); - } - - function OnAllClick() { - PageSelectorInput[0].value = '1 - ' + AllPages.value; - OnFirst[0].classList.remove('activeButton'); - PageSelector = '&PageRange=All'; - okButton.disabled = false; - okButton.classList.remove(""fr-webreport-popup-disabled-button""); - input.classList.remove('input-error'); - } - var PSFirst = ''; - var PSLast = '' - var CustomPagesArray"; - string template_modalcontainer() { var templateModalContainer = $@" -
+
+ {(false ? @"" : "")}
- -
+ +
"; return templateModalContainer; diff --git a/FastReport.Core.Web/Templates/outline.cs b/FastReport.Core.Web/Templates/outline.cs index f0c194ed..31abee63 100644 --- a/FastReport.Core.Web/Templates/outline.cs +++ b/FastReport.Core.Web/Templates/outline.cs @@ -22,16 +22,13 @@ string template_outline() BuildOutline(outline, Report.PreparedPages.OutlineXml, true); return $@" -
-
+
+
{outline}
- + "; } @@ -49,29 +46,29 @@ void BuildOutline(StringBuilder sb, XmlItem xml, bool top) var (text, page, offset) = ReadOutlineNode(node); var nodeId = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{ID}{page}{offset}{sb.Length}{GetCurrentTabName()}")); - sb.Append($@"
"); - + sb.Append($@"
"); + string caret; if (hasChildren) { - caret = $@""; - caret += $@""; + caret = $@""; + caret += $@""; } else { - caret = $@"
"; + caret = $@"
"; } - sb.Append($@"
"); + sb.Append($@"
"); sb.Append(caret); - sb.Append($@""); - sb.Append($@"{HttpUtility.HtmlEncode(text)}"); + sb.Append($@""); + sb.Append($@"{HttpUtility.HtmlEncode(text)}"); sb.Append($@"
"); if (hasChildren) { sb.Append($@"
"); // line break - sb.Append($@"
"); + sb.Append($@"
"); BuildOutline(sb, node, false); sb.Append("
"); } diff --git a/FastReport.Core.Web/Templates/script.cs b/FastReport.Core.Web/Templates/script.cs index e4f46515..f7d0d6fc 100644 --- a/FastReport.Core.Web/Templates/script.cs +++ b/FastReport.Core.Web/Templates/script.cs @@ -1,878 +1,88 @@ -using static FastReport.Web.Constants; +using FastReport.Web.Infrastructure; +using System.Text.Json; namespace FastReport.Web { partial class WebReport { - - string template_script() + private class ScriptProps { - var localization = new ToolbarLocalization(Res); - return $@" -'use strict'; -class Searcher {{ - static ScrollOffsetTop = {Toolbar.SearchScrollOffsetTop}; -}} - -var {template_FR} = {{ - - toggleSearchForm: function() {{ - var form = document.getElementById('{template_FR}-toolbar-search-form'); - form.classList.toggle('open'); - if (!form.classList.contains('open')) {{ - var searchText = sessionStorage.getItem('fastreport-search-text'); - var matchCase = sessionStorage.getItem('fastreport-search-match-case') === 'true'; - var wholeWord = sessionStorage.getItem('fastreport-search-whole-word') === 'true'; - this.findNext( - sessionStorage.getItem('fastreport-search-index'), - searchText, - matchCase, - wholeWord, - true - ); - }} - }}, - - saveSearchFormState: function() {{ - sessionStorage.setItem('fastreport-search-text-state', document.getElementById('fr-search-text').value); - sessionStorage.setItem('fastreport-search-match-case-state', document.getElementById('fr-match-case').checked); - sessionStorage.setItem('fastreport-search-whole-word-state', document.getElementById('fr-whole-word').checked); - }}, - - restoreSearchFormState: function(resetIndex = false, openAfter = false) {{ - document.getElementById('fr-search-text').value = sessionStorage.getItem('fastreport-search-text-state'); - document.getElementById('fr-match-case').checked = sessionStorage.getItem('fastreport-search-match-case-state') === 'true'; - document.getElementById('fr-whole-word').checked = sessionStorage.getItem('fastreport-search-whole-word-state') === 'true'; - this.onEnterSearchText(); - if (resetIndex) - sessionStorage.setItem('fastreport-search-text', ''); - if (openAfter) - document.getElementById('{template_FR}-toolbar-search-form').classList.toggle('open'); - }}, - - onEnterSearchText: function () {{ - if(document.getElementById('fr-search-text').value == '') {{ - document.getElementById('fr-search-prev').setAttribute('disabled', 'disabled'); - document.getElementById('fr-search-next').setAttribute('disabled', 'disabled'); - document.getElementById('fr-match-case').setAttribute('disabled', 'disabled'); - document.getElementById('fr-whole-word').setAttribute('disabled', 'disabled'); - document.getElementById('clear-searchbox').setAttribute('hidden', 'hidden'); - }} - else{{ - document.getElementById('fr-search-prev').removeAttribute('disabled'); - document.getElementById('fr-search-next').removeAttribute('disabled'); - document.getElementById('fr-match-case').removeAttribute('disabled'); - document.getElementById('fr-whole-word').removeAttribute('disabled'); - document.getElementById('clear-searchbox').removeAttribute('hidden'); - }} - }}, - - clearSearchText: function () {{ - document.getElementById('fr-search-text').value = ''; - this.onEnterSearchText(); - }}, - - getSearchRanges: function (text, matchCase, wholeWord) {{ - var curScrollY = window.scrollY; - var curScrollX = window.scrollX; - var sel = window.getSelection(); - var ranges = [] - var container = document.getElementsByClassName('{template_FR}-body')[0]; - // find all occurrences in a page - while (window.find(text, matchCase, false, false, wholeWord, false, false)) {{ - // filter out search results outside of a specific element - if (container.contains(sel.anchorNode)) {{ - ranges.push(sel.getRangeAt(sel.rangeCount - 1)); - }} - }} - window.scrollTo(curScrollX, curScrollY); - return ranges - }}, - - findNext: function (index, text, matchCase, wholeWord, removeHighlight) {{ - var container = this._findContainer(); - // selection object - var sel = window.getSelection(); - - sel.collapse(container, 0) - var ranges = this.getSearchRanges(text, matchCase, wholeWord); - sel.collapse(container, 0); - - if (ranges.length == 0) {{ - return false; - }} - else if ((index < ranges.length && index >= 0) || removeHighlight) {{ - if (!removeHighlight) {{ - ranges.sort((a, b) => {{ - return a.startContainer.parentElement.getBoundingClientRect().top - b.startContainer.parentElement.getBoundingClientRect().top - }}); - ranges = [ranges[index]]; - }} - else {{ - ranges = ranges.filter((r) => r.startContainer.parentElement.classList.contains('search-highlight')); - }} - - for (var i = 0; i < ranges.length; i++) {{ - var range = ranges[i] - if (range.startContainer == range.endContainer) {{ - // Range includes just one node - if (removeHighlight) - this.clearHighlight(range) - else - this.highlight(range) - return true - }} else {{ - // More complex case: range includes multiple nodes - // Get all the text nodes in the range - var textNodes = this.getTextNodesInRange( - range.commonAncestorContainer, - range.startContainer, - range.endContainer) - - var startOffset = range.startOffset - var endOffset = range.endOffset - for (var j = 0; j < textNodes.length; j++) {{ - var node = textNodes[j] - range.setStart(node, j == 0 ? startOffset : 0) - range.setEnd(node, j == textNodes.length - 1 ? - endOffset : node.nodeValue.length) - if (removeHighlight) - this.clearHighlight(range); - else - this.highlight(range); - }} - }} - return true; - }} - - }} - return false; - }}, - - search: function (backward) {{ - var searchText = document.getElementById('fr-search-text').value; - var lastSearchText = sessionStorage.getItem('fastreport-search-text'); - var index = sessionStorage.getItem('fastreport-search-index'); - var matchCase = document.getElementById('fr-match-case').checked; - var wholeWord = document.getElementById('fr-whole-word').checked; - document.getElementById('fr-WebRepot-text-info').innerText = ''; - if (!index) - index = -1 - - if (lastSearchText) {{ - this.findNext(index, lastSearchText, sessionStorage.getItem('fastreport-search-match-case') === 'true', sessionStorage.getItem('fastreport-search-whole-word') === 'true', true) - }} - - if (backward) - index-- - else - index++ - - if (lastSearchText != searchText) - index = 0; - - if(!this.findNext(index, searchText, matchCase, wholeWord, false)) - {{ - var that = this; - var body = this._findBody(); - var container = this._findContainer(); - // search on next pages - this._fetch({{ - method: 'POST', - url: '{template_ROUTE_BASE_PATH}/preview.getReport?reportId={ID}&skipPrepare=yes&renderBody=yes&backward=' + backward + '&searchText=' + searchText+ '&matchCase=' + matchCase+ '&wholeWord=' + wholeWord, - onSend: function () {{ - that._activateSpinner(); - }}, - onSuccess: function (xhr) {{ - container.outerHTML = xhr.responseText; - that._execScripts(); - // get new container - container = that._findContainer(); - var sel = window.getSelection(); - sel.collapse(container, 0); - index = backward ? that.getSearchRanges(searchText, matchCase, wholeWord).length - 1 : 0; - sessionStorage.setItem('fastreport-search-index', index); - document.getElementById('{template_FR}-toolbar-search-form').classList.toggle('open'); - document.getElementById('fr-search-text').value = searchText; - that.onEnterSearchText(); - if (!that.findNext(index, searchText, matchCase, wholeWord, false)) - document.getElementById('fr-WebRepot-text-info').innerText = '{localization.searchNotFound}'; - }}, - onError: function (xhr) {{ - that._deactivateSpinner(); - index = backward ? 0 : index - 1; - sessionStorage.setItem('fastreport-search-index', index); - that.findNext(index, searchText, matchCase, wholeWord, false) - document.getElementById('fr-WebRepot-text-info').innerText = '{localization.searchNotFound}'; - }} - }}); - }} - sessionStorage.setItem('fastreport-search-index', index); - sessionStorage.setItem('fastreport-search-text', searchText); - sessionStorage.setItem('fastreport-search-match-case', matchCase); - sessionStorage.setItem('fastreport-search-whole-word', wholeWord); - }}, - - highlight: function (range) {{ - var newNode = document.createElement('span'); - newNode.className = 'search-highlight'; - range.surroundContents(newNode); - const rect = newNode.getBoundingClientRect(); - const vWidth = (window.innerWidth || document.documentElement.clientWidth) - rect.width; - const vHeight = (window.innerHeight || document.documentElement.clientHeight) - rect.height; - var topOfElement = window.scrollY; - var leftOfElement = window.screenX; - - if (rect.bottom < rect.height || rect.top > vHeight) - topOfElement = topOfElement + rect.top - Searcher.ScrollOffsetTop; - if (rect.right < rect.width || rect.left > vWidth) - leftOfElement = leftOfElement + rect.left; - window.scroll({{top: topOfElement, left: leftOfElement, behavior: 'smooth' }}); - }}, - - clearHighlight: function (range) {{ - var selection = document.getSelection() - selection.removeAllRanges() - selection.addRange(range) - const selParent = selection.anchorNode?.parentElement; - const selectedElem = selParent?.nodeType == 1 && selParent?.children.length < 2 && selParent; - if (selectedElem.tagName === 'SPAN' && selectedElem.classList.contains('search-highlight')) {{ - selectedElem.previousSibling.nodeValue += selectedElem.innerText; - selectedElem.previousSibling.nodeValue += selectedElem.nextSibling.nodeValue; - selectedElem.parentNode.removeChild(selectedElem.nextSibling); - selectedElem.parentNode.removeChild(selectedElem); - }} - }}, - - getTextNodesInRange: function (rootNode, firstNode, lastNode) {{ - var nodes = [] - var startNode = null, endNode = lastNode - var walker = document.createTreeWalker( - rootNode, - // search for text nodes - NodeFilter.SHOW_TEXT, - // Logic to determine whether to accept, reject or skip node. - // In this case, only accept nodes that are between - // firstNode and lastNode - {{ - acceptNode: function(node) - {{ - if (!startNode) {{ - if (firstNode == node){{ - startNode = node - return NodeFilter.FILTER_ACCEPT - }} - return NodeFilter.FILTER_REJECT - }} - - if (endNode) - {{ - if (lastNode == node){{ - endNode = null - }} - return NodeFilter.FILTER_ACCEPT - }} - - return NodeFilter.FILTER_REJECT - }} - }}, - false - ) - - while(walker.nextNode()){{ - nodes.push(walker.currentNode) - }} - return nodes - }}, - - outline: function () {{ - var sizes = sessionStorage.getItem('fastreport-outline-split-sizes'); - - if (sizes) {{ - sizes = JSON.parse(sizes); - }} else {{ - sizes = [25, 75]; - }} - - var split = this.Split(['.{template_FR}-outline', '.{template_FR}-report'], {{ - sizes: sizes, - minSize: [0, 50], - snapOffset: 20, - onDragEnd: function () {{ - sessionStorage.setItem('fastreport-outline-split-sizes', JSON.stringify(split.getSizes())); - }}, - elementStyle: function (dimension, size, gutterSize) {{ - return {{ - 'flex-basis': 'calc(' + size + '% - ' + gutterSize + 'px)' - }} - }}, - gutterStyle: function (dimension, gutterSize) {{ - return {{ - 'flex-basis': gutterSize + 'px' - }} - }}, - gutter: function (index, direction) {{ - var gutter = document.createElement('div'); - gutter.className = '{template_FR}-gutter {template_FR}-gutter-' + direction; - return gutter; - }} - }}); - - var tree = sessionStorage.getItem('fastreport-outline-tree'); - if (tree) {{ - tree = JSON.parse(tree); - var that = this; - var container = this._findContainer(); - Object.keys(tree).forEach(function (key) {{ - var caret = container.querySelector('[data-fr-outline-node-id=""' + key + '""]'); - if (caret) {{ - that.outlineOpenNode(caret, true); - }} - }}); - }} - }}, - - outlineOpenNode: function (caret, skipTreeStorage) {{ - caret.parentNode.parentNode.getElementsByClassName('{template_FR}-outline-children')[0].style.display = ''; - caret.parentNode.parentNode.getElementsByClassName('{template_FR}-js-outline-open-node')[0].style.display = 'none'; - caret.parentNode.parentNode.getElementsByClassName('{template_FR}-js-outline-close-node')[0].style.display = ''; - - if (skipTreeStorage === true) {{ - return; - }} - - var tree = sessionStorage.getItem('fastreport-outline-tree'); - if (tree) {{ - tree = JSON.parse(tree); - }} else {{ - tree = {{}}; - }} - - tree[caret.getAttribute('data-fr-outline-node-id')] = true; - sessionStorage.setItem('fastreport-outline-tree', JSON.stringify(tree)); - }}, - - outlineCloseNode: function (caret) {{ - caret.parentNode.parentNode.getElementsByClassName('{template_FR}-outline-children')[0].style.display = 'none'; - caret.parentNode.parentNode.getElementsByClassName('{template_FR}-js-outline-open-node')[0].style.display = ''; - caret.parentNode.parentNode.getElementsByClassName('{template_FR}-js-outline-close-node')[0].style.display = 'none'; - - var tree = sessionStorage.getItem('fastreport-outline-tree'); - if (tree) {{ - tree = JSON.parse(tree); - }} else {{ - tree = {{}}; - }} - - delete tree[caret.getAttribute('data-fr-outline-node-id')]; - sessionStorage.setItem('fastreport-outline-tree', JSON.stringify(tree)); - }}, - - outlineGoto: function (page, offset, singelPage = {SinglePage.ToString().ToLower()}) {{ - if (singelPage) {{ - const rect = document.getElementById(""PageN"" + page).getBoundingClientRect(); - var topOfElement = window.scrollY + rect.top + offset; - window.scroll({{top: topOfElement, behavior: 'smooth' }}); - }} - else{{ - var that = this; - this.goto(page, {{ - onSuccess: function (xhr) {{ - that.outlineGoto(1, offset, true); - }} - }}); - }} - }}, - - load: function () {{ - this._reload(); - }}, - - refresh: function () {{ - var that = this; - var searchForm = document.getElementById('{template_FR}-toolbar-search-form'); - var needRestoreSearch = false; - var searchText = sessionStorage.getItem('fastreport-search-text'); - var matchCase = sessionStorage.getItem('fastreport-search-match-case') === 'true'; - var wholeWord = sessionStorage.getItem('fastreport-search-whole-word') === 'true'; - - if (searchForm) {{ - needRestoreSearch = searchForm.classList.contains('open'); - this.saveSearchFormState(); - }} - this._reloadBase('&forceRefresh=yes', null,{{ - onSuccess: function (xhr) {{ - if(needRestoreSearch){{ - that.restoreSearchFormState(false, true); - that.findNext( - sessionStorage.getItem('fastreport-search-index'), - searchText, - matchCase, - wholeWord, - false - ); - }} - }} - }}); - }}, - - zoom: function (value) {{ - var that = this; - var searchForm = document.getElementById('{template_FR}-toolbar-search-form'); - var needRestoreSearch = false; - var searchText = sessionStorage.getItem('fastreport-search-text'); - var matchCase = sessionStorage.getItem('fastreport-search-match-case') === 'true'; - var wholeWord = sessionStorage.getItem('fastreport-search-whole-word') === 'true'; - - if (searchForm) {{ - needRestoreSearch = searchForm.classList.contains('open'); - this.saveSearchFormState(); - }} - this._closeDropdowns(); - this._reloadBase('&skipPrepare=yes&zoom=' + value, null,{{ - onSuccess: function (xhr) {{ - if(needRestoreSearch){{ - that.restoreSearchFormState(false, true); - that.findNext( - sessionStorage.getItem('fastreport-search-index'), - searchText, - matchCase, - wholeWord, - false - ); - }} - }} - }}); - }}, - - goto: function (page, options) {{ - this._reload('&skipPrepare=yes&goto=' + page, null, options); - }}, - - click: function (el, kind, value) {{ - var that = this; - - if (kind == 'text_edit') {{ - if (that._win) {{ - that._win.close(); - }} - that._win = this._popup('{template_ROUTE_BASE_PATH}/preview.textEditForm?reportId={ID}&click=' + value, 'Text edit', 400, 200); - that._win.onmessage = function (e) {{ - if (e.data == 'submit') {{ - var newText = that._win.document.querySelector('textarea').value; - var form = new FormData(); - form.append('text', newText); - that._reload('&skipPrepare=yes&' + kind + '=' + value, form); - that._win.close(); - }} - }}; - return; - }} - - this._reload('&skipPrepare=yes&' + kind + '=' + value); - }}, - - customMethodInvoke: function(elementId, inputValue){{ - var that = this; - var body = this._findBody(); - var container = this._findContainer(); - - this._fetch({{ - method: 'POST', - url: '{template_ROUTE_BASE_PATH}/preview.toolbarElementClick?reportId={ID}&elementId=' + elementId + '&inputValue=' + inputValue, - onSend: function () {{ - that._activateSpinner(); - }}, - onSuccess: function (xhr) {{ - container.outerHTML = xhr.responseText; - that._execScripts(); - }}, - onError: function (xhr) {{ - that._placeError(xhr, body); - that._deactivateSpinner(); - }} - }}); - }}, - - - settab: function (tab) {{ - this._reload('&skipPrepare=yes&settab=' + tab); - }}, - - closetab: function (tab) {{ - this._reload('&skipPrepare=yes&closetab=' + tab); - }}, - - _reload: function (params, form, options = {{}}) {{ - var that = this; - var onSuccess = options.onSuccess; - var searchForm = document.getElementById('{template_FR}-toolbar-search-form'); - var needRestoreSearch = false; - - if (searchForm) {{ - needRestoreSearch = searchForm.classList.contains('open'); - this.saveSearchFormState(); - }} - - this._reloadBase(params, form, {{ - onSuccess: function (xhr) {{ - if (typeof onSuccess === 'function') {{ - onSuccess(xhr); - }} - if(needRestoreSearch) - that.restoreSearchFormState(true, true); - }} - }}); - }}, - - _reloadBase: function (params, form, options) {{ - var that = this; - var body = this._findBody(); - var container = this._findContainer(); - var onSuccess = options.onSuccess; - var onError = options.onError; - var onSend = options.onSend; - var onFinally = options.onFinally; - - this._fetch({{ - method: 'POST', - url: '{template_ROUTE_BASE_PATH}/preview.getReport?reportId={ID}&renderBody=yes' + (params || ''), - form: form, - onSend: function () {{ - that._activateSpinner(); - //that._lockToolbar(); - if (typeof onSend === 'function') {{ - onSend(xhr); - }} - }}, - onSuccess: function (xhr) {{ - container.outerHTML = xhr.responseText; - that._execScripts(); - if (typeof onSuccess === 'function') {{ - onSuccess(xhr); - }} - }}, - onError: function (xhr) {{ - that._placeError(xhr, body); - that._deactivateSpinner(); - if (typeof onError === 'function') {{ - onError(xhr); - }} - }}, - onFinally: function () {{ - //that._unlockToolbar(); - if (typeof onFinally === 'function') {{ - onFinally(xhr); - }} - }} - }}); - }}, - - {SILENT_RELOAD}: function (params, form) {{ - var that = this; - var body = this._findBody(); - var container = this._findContainer(); - var searchForm = document.getElementById('{template_FR}-toolbar-search-form'); - var needRestoreSearch = false; - var searchText = sessionStorage.getItem('fastreport-search-text'); - var matchCase = sessionStorage.getItem('fastreport-search-match-case') === 'true'; - var wholeWord = sessionStorage.getItem('fastreport-search-whole-word') === 'true'; - - if (searchForm) {{ - needRestoreSearch = searchForm.classList.contains('open'); - this.saveSearchFormState(); - }} - - this._fetch({{ - method: 'POST', - url: '{template_ROUTE_BASE_PATH}/preview.getReport?reportId={ID}&renderBody=yes' + (params || ''), - form: form, - onSuccess: function (xhr) {{ - container.outerHTML = xhr.responseText; - that._execScripts(); - if(needRestoreSearch){{ - that.restoreSearchFormState(false, true); - that.findNext( - sessionStorage.getItem('fastreport-search-index'), - searchText, - matchCase, - wholeWord, - false - ); - }} - }}, - onError: function (xhr) {{ - that._placeError(xhr, body); - }}, - }}); - }}, - - - {DIALOG}: function (params, form) {{ - this._fetch({{ - method: 'POST', - url: '{template_ROUTE_BASE_PATH}/dialog?reportId={ID}' + (params || ''), - form: form - }}); - }}, - - showEmailExportModal: function() {{ - var modalcontainer = this._findModalContainer(); - const emailExportLink = document.getElementById('emailexport'); - const buttons = document.querySelectorAll('.fr-webreport-settings-btn'); - const Overlay = document.querySelector('.modalcontainer-overlay'); - var that = this; - - this._fetch({{ - method: 'POST', - url: '{template_ROUTE_BASE_PATH}/exportsettings.getSettings?reportId={ID}&format=email', - onSuccess: function (xhr) {{ - modalcontainer.innerHTML = xhr.responseText; - that._execModalScripts(); - document.querySelector(`[data-target=email]`).classList.add('modalcontainer--visible'); - Overlay.classList.add('modalcontainer-overlay--visible'); - }}, - }}) - }}, - -showPopup: function (message, isSuccess) {{ - var popup = document.createElement(""div""); - popup.className = ""fr-notification""; - if (isSuccess) {{ - popup.classList.add(""positive""); - }} else {{ - popup.classList.add(""negative""); - }} - - var content = document.createElement(""div""); - content.className = ""fr-notification-content""; - - var image = document.createElement(""img""); - image.src = ""/_fr/resources.getResource?resourceName=notification-bell.svg&contentType=image%2Fsvg%2Bxml""; - - var text = document.createElement(""div""); - text.innerText = message; - - content.appendChild(image); - content.appendChild(text); - popup.appendChild(content); - document.body.appendChild(popup); - - setTimeout(function () {{ - popup.style.opacity = ""0""; - setTimeout(function () {{ - popup.remove(); - }}, 500); - }}, 2000); -}}, - - getExportSettings: function () {{ - this._getExportSettings(); - }}, - - _getExportSettings: function (params, form) {{ - var modalcontainer = this._findModalContainer(); - const buttons = document.querySelectorAll('.fr-webreport-settings-btn'); - const Overlay = document.querySelector('.modalcontainer-overlay'); - var fileformat; - var that = this; - buttons.forEach((el) => {{ - el.addEventListener('click', (e) => {{ - fileformat = e.currentTarget.getAttribute('data-path'); - - this._fetch({{ - method: 'POST', - url: '{template_ROUTE_BASE_PATH}/exportsettings.getSettings?reportId={ID}&format='+ fileformat + (params || ''), - form: form, - onSuccess: function (xhr) {{ - modalcontainer.innerHTML = xhr.responseText; - that._execModalScripts(); - document.querySelector(`[data-target=${{fileformat}}]`).classList.add('modalcontainer--visible'); - Overlay.classList.add('modalcontainer-overlay--visible'); - }}, - }}); - }}) - }}); - }}, - - _execScripts: function () {{ - var container = this._findContainer(); - var scripts = container.getElementsByTagName('script'); - for (var i = 0; i < scripts.length; i++) {{ - eval(scripts[i].text); - }} - - }}, - _execModalScripts: function() {{ - var includeContainer = this._findModalContainer(); - var scripts = includeContainer.getElementsByTagName('script'); - for(var i = 0; i' + iframe.outerHTML + '
'; - body.innerHTML = '
Error
' + xhr.status + ' - ' + xhr.statusText + '
' + xhr.responseText + '
'; - }}, - - _activateSpinner: function () {{ - document.getElementsByClassName('{template_FR}-spinner')[0].style.display = ''; - }}, - - _deactivateSpinner: function () {{ - document.getElementsByClassName('{template_FR}-spinner')[0].style.display = 'none'; - }}, - - _findContainer: function () {{ - return document.getElementsByClassName('{template_FR}-container')[0]; - }}, - - _findModalContainer: function () {{ - return document.getElementsByClassName('content-modalcontainer')[0]; - }}, - -/* - _findToolbar: function () {{ - return document.getElementsByClassName('{template_FR}-toolbar')[0]; - }}, -*/ - - _findBody: function () {{ - return document.getElementsByClassName('{template_FR}-body')[0]; - }}, - - _closeDropdowns: function () {{ - var dropdowns = document.getElementsByClassName('{template_FR}-dropdown-content'); - - var func = function (dd) {{ - setTimeout(function () {{ - dd.style['display'] = ''; - }}, 100); - }} - - for (var i = 0; i < dropdowns.length; i++) {{ - var dd = dropdowns[i]; - dd.style['display'] = 'none'; - func(dd); - }} - }}, - -/* - _lockToolbar: function () {{ - var toolbar = this._findToolbar(); - if (toolbar) {{ - toolbar.style['pointer-events'] = 'none'; - }} - }}, - - _unlockToolbar: function () {{ - var toolbar = this._findToolbar(); - if (toolbar) {{ - toolbar.style['pointer-events'] = ''; - }} - }}, -*/ - - _fetchQueue: [], - - _fetch: function (options) {{ - var method = options.method; - var url = options.url; - var form = options.form; - var onSuccess = options.onSuccess; - var onError = options.onError; - var onSend = options.onSend; - var onFinally = options.onFinally; - - if(options.method == 'POST' && options.form == null){{ - form = {{ }}; - }} - - var that = this; - var xhr = new XMLHttpRequest(); - xhr.__form = form; - xhr.__onSend = onSend; - xhr.open(method, url, true); - xhr.onreadystatechange = function () {{ - if (xhr.readyState != 4) - return; - - if (xhr.status != 200) {{ - if (typeof onError === 'function') {{ - onError(xhr); - }} - }} else {{ - if (typeof onSuccess === 'function') {{ - onSuccess(xhr); - }} - }} - - if (typeof onFinally === 'function') {{ - onFinally(xhr); - }} - - that._nextFetch(); - }}; - - this._fetchQueue.push(xhr); - - if (this._fetchQueue.length == 1) {{ - var f = this._fetchQueue[0]; - if (typeof f.__onSend === 'function') {{ - f.__onSend(f); - }} - f.send(f.__form); - }} - }}, - - _nextFetch: function () {{ - this._fetchQueue.shift(); - - if (this._fetchQueue.length) {{ - var f = this._fetchQueue[0]; - if (typeof f.__onSend === 'function') {{ - f.__onSend(f); - }} - f.send(f.__form); - }} - }}, - - _popup: function (url, title, w, h) {{ - // Fixes dual-screen position Most browsers Firefox - var dualScreenLeft = window.screenLeft != undefined ? window.screenLeft : window.screenX; - var dualScreenTop = window.screenTop != undefined ? window.screenTop : window.screenY; - - var width = window.innerWidth ? window.innerWidth : document.documentElement.clientWidth ? document.documentElement.clientWidth : screen.width; - var height = window.innerHeight ? window.innerHeight : document.documentElement.clientHeight ? document.documentElement.clientHeight : screen.height; + public string ID { get; set; } + public string TemplateFR { get; set; } + public string SearchNotFoundText { get; set; } + public string RouteBasePath { get; set; } + public bool Outline { get; set; } + public int SearchScroolOffset { get; set; } + + public override string ToString() + { + return JsonSerializer.Serialize(this); + } + } - var left = ((width / 2) - (w / 2)) + dualScreenLeft; - var top = ((height / 2) - (h / 2)) + dualScreenTop; + private class ScriptEventData + { + public string TargetObj { get; set; } + public string Event { get; set; } + public string Func { get; set; } + public string[] Params { get; set; } + + public override string ToString() + { + return JsonSerializer.Serialize(this); + } + } - var params = 'menubar=0, toolbar=0, location=0, status=0, resizable=1, scrollbars=1'; - var newWindow = window.open(url, title, params + ', width=' + w + ', height=' + h + ', top=' + top + ', left=' + left); + /// + /// Prepare the data for creating the event in the js module. + /// + /// The event to which the handler will be added. + /// The object that will call the function. + /// The function that is called when the event is triggered + /// Parameters of function + /// + internal static string CreateEvent(string ev, string targetObj, string func, params string[] par) + { + var e = new ScriptEventData() + { + Event = ev, + Func = func, + Params = par, + TargetObj = targetObj, + }; + return $"data-event='{e}'"; + } - if (newWindow.focus) {{ - newWindow.focus(); - }} + /// + /// Prepare the data for creating the onclick event in the js module. + /// + /// The object that will call the function. + /// The function that is called when the event is triggered + /// Parameters of function + /// + internal static string CreateOnClickEvent(string targetObj, string func, params string[] par) + { + return CreateEvent(JSEvents.CLICK, targetObj, func, par); + } - return newWindow; - }} + /// + /// Entry point for calling js scripts. + /// + public string ScriptName { get => $"window.Webreports.get('{ID}')"; } -}}; -"; + private string GetScriptProps() + { + var scriptProps = new ScriptProps() + { + ID = this.ID, + SearchScroolOffset = Toolbar.SearchScrollOffsetTop, + TemplateFR = "fr", + SearchNotFoundText = new ToolbarLocalization(Res).searchNotFound, + RouteBasePath = WebUtils.ToUrl(FastReportGlobal.FastReportOptions.RoutePathBaseRoot, FastReportGlobal.FastReportOptions.RouteBasePath), + Outline = Outline, + }; + + return scriptProps.ToString(); } } } \ No newline at end of file diff --git a/FastReport.Core.Web/Templates/style.cs b/FastReport.Core.Web/Templates/style.cs index 2521c403..a695b65a 100644 --- a/FastReport.Core.Web/Templates/style.cs +++ b/FastReport.Core.Web/Templates/style.cs @@ -4,1097 +4,6 @@ namespace FastReport.Web { partial class WebReport { - string template_style() => $@" -/********** - MAIN -***********/ -.{template_FR}-container {{ - {(Width.IsNullOrWhiteSpace() ? "" : $"width: {Width};")} - {(Height.IsNullOrWhiteSpace() ? "" : $"height: {Height};")} - background-color: white; - display: {InlineStyle}; - flex-direction: {Toolbar.Vertical}; - position: relative; - align-items: {Toolbar.Content}; -}} - -.{template_FR}-container * {{ - box-sizing: content-box; - -moz-box-sizing: content-box; -}} - -.{template_FR}-body {{ - display: flex; - overflow: hidden; - width: 100%; - height: 100%; - margin-top: 20px; -}} - -.{template_FR}-report {{ - overflow: auto; - width: 100%; - display: flex; - flex-direction: column; - align-items: flex-start; - justify-content: center; -}} - -.{template_FR}-spinner[style*=""display:none""] ~ .{template_FR}-toolbar ~ .{template_FR}-body {{ - box-shadow: {(!EnableMultiPagePreview || !SinglePage ? "0px 2px 4px rgba(0, 0, 0, 0.25)" : "none")}; -}} - -.frpage-container [class^=""frpage""] {{ - box-shadow: {(EnableMultiPagePreview && PageBorderVisible ? "0px 2px 4px rgba(0, 0, 0, 0.25)" : "none")}; - margin: {(EnableMultiPagePreview ? "10px" : "")}; -}} - -.fr-form-header {{ - padding: 5px; - padding-left: 12px; - font: 14px Verdana,Arial sans-serif Regular; - min-height: 18px; - text-overflow: ellipsis; - overflow: hidden; - border-bottom: solid 1px lightgray; - vertical-align: middle; - text-align: -webkit-match-parent; - height: 30px; - align-items: center; - display: flex; - font-weight: bold; -}} - -.{template_FR}-body:has(.fr-dialog-form) {{ - width: fit-content; - border-radius: 12px; - background: #FFF; - box-shadow: 0px 4px 4px 0px rgba(0, 0, 0, 0.25); -}} - -/*********** - SPLIT -************/ - -.{template_FR}-gutter {{ - background-color: #f1f1f1; - background-repeat: no-repeat; - background-position: 50%; -}} - -.{template_FR}-gutter.{template_FR}-gutter-horizontal {{ - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAeCAYAAADkftS9AAAAIklEQVQoU2M4c+bMfxAGAgYYmwGrIIiDjrELjpo5aiZeMwF+yNnOs5KSvgAAAABJRU5ErkJggg=='); - cursor: ew-resize; -}} - -/************* - TOOLBAR -**************/ - -.{template_FR}-toolbar {{ - flex-shrink: 1; - font:{Toolbar.UserFontSettings}; - background-color: {ColorTranslator.ToHtml(Toolbar.Color)}; - /* {(Tabs.Count > 1 ? "" : "box-shadow: 0px 3px 4px -2px rgba(0, 0, 0, 0.2);")} */ - display: flex; - flex-direction: {Toolbar.RowOrColumn}; - /* flex-wrap: wrap; */ - width: fit-content; - height: {Toolbar.VerticalToolbarHeight}; - order:{Toolbar.TopOrBottom} ; - position: relative; - align-items: center; - justify-content:{Toolbar.Content}; - z-index: 2; - border-radius: {Toolbar.ToolbarRoundness}px; - /*min-width: intrinsic; - min-width: -moz-max-content; - min-width: -webkit-max-content; - min-width: max-content;*/ - -webkit-user-select: none; /* Safari */ - -ms-user-select: none; /* IE 10 and IE 11 */ - user-select: none; /* Standard syntax */ - {Toolbar.StickyToolbarTags} -}} - -.{template_FR}-toolbar-item {{ - height: {Toolbar.Height}px; - border: none; - border-radius:{Toolbar.ToolbarRoundness}px; - background-color: #00000000; - position: relative; - align-items: center; - display: flex; -}} - -.{template_FR}-toolbar-item:hover:not([hidden]) {{ - background-color: {ColorTranslator.ToHtml(Toolbar.Color)}; -}} - -.{template_FR}-toolbar-item[hidden] > svg {{ - filter: invert(99%) sepia(5%) saturate(91%) hue-rotate(66deg) brightness(114%) contrast(86%); -}} - -.{template_FR}-toolbar-item > svg {{ - height: calc({Toolbar.Height}px * 0.5); - padding-top: calc({Toolbar.Height}px * 0.15); - padding-bottom: calc({Toolbar.Height}px * 0.15); - padding-left: calc({Toolbar.Height}px * 0.25); - padding-right: calc({Toolbar.Height}px * 0.25); - opacity: {Toolbar.TransparencyIcon}; - display: block; - filter:invert({Toolbar.ColorIcon}); - margin-left: 10px; - margin-right: 10px; -}} - -.{template_FR}-toolbar-item:hover:not([hidden]) > svg {{ - opacity: 0.5; -}} - -.{template_FR}-toolbar-notbutton:hover {{ - background-color: transparent; -}} - -.{template_FR}-toolbar-notbutton:hover > svg {{ - opacity: 1; -}} - -.{template_FR}-toolbar-image{{ - width: calc({Toolbar.Height}px * 0.5); -}} - -/**************** - SEARCH FORM -*****************/ -.{template_FR}-toolbar-dropdown-content-searchbox {{ - float: none; - background-color: white; - text-decoration: none; - text-align: left; - height: auto; - user-select: none; - border: 1px solid #000; - border-radius: 6px; -}} - -.{template_FR}-toolbar-search-form > div > label > input {{ - margin-bottom: 12px; - border-radius: 3px; -}} - -.{template_FR}-toolbar-search-form > div > label:has(:disabled) {{ - color: #CACACA; -}} - -.{template_FR}-toolbar-search-form {{ - font-size: 14px; - display: none; - position: fixed; - width: 390px; - z-index: 4; - left: {Toolbar.SearchFormLeft}; - top: {Toolbar.SearchFormTop}; - padding: 0px 10px 0px 10px; - border-radius: 12px; - box-shadow: 0px 4px 4px 0px rgba(0, 0, 0, 0.2); - background-color: #EFEFEF; -}} - -.search-navigation-info-block {{ - display: flex; - align-items: center; - justify-content: center; - text-align: center; - margin: 12px 0px 6px 0px; -}} - -#fr-search-next > svg, #fr-search-prev > svg {{ - vertical-align: middle; - height: 12px; -}} - -#fr-search-next, #fr-search-prev {{ - background-color: white; - border: none; -}} - -#fr-search-next:disabled > svg, #fr-search-prev:disabled > svg {{ - filter: invert(99%) sepia(5%) saturate(91%) hue-rotate(66deg) brightness(114%) contrast(86%); -}} - -#fr-search-next:hover:enabled, #fr-search-prev:hover:enabled {{ - /* background-color: #d9d9d9; */ -}} - -#fr-search-next:active:enabled, #fr-search-prev:active:enabled {{ - background-color: #4A4A4A; -}} - -#fr-search-next:active:enabled > svg, #fr-search-prev:active:enabled > svg {{ - filter: invert(100%) sepia(100%) saturate(0%) hue-rotate(241deg) brightness(103%) contrast(103%); -}} - -#fr-search-prev{{ - margin-right: -5px; - border-radius: 3px 0px 0px 3px; -}} - -#fr-search-next {{ - border-radius: 0px 3px 3px 0px; -}} - -#fr-search-text {{ - min-height: 25px; - width: 90%; - border: none; - outline: none; - vertical-align: middle; - -webkit-appearance: none; - border-radius: 6px; -}} - -#clear-searchbox {{ - width: 20px; - height: 20px; - border: none; - vertical-align: middle; -}} - -#close-search-form-button {{ - font-size: 10px; - text-align: right; - padding: 6px 0px 0px 0px; -}} - -#fr-WebRepot-text-info {{ - width: 90%; -}} - -#close-search-form-button > img {{ - height: 20px; - width: 20px; - filter: invert(36%) sepia(0%) saturate(0%) hue-rotate(85deg) brightness(100%) contrast(91%); -}} - -#{template_FR}-toolbar-search-form.open {{ - display: block; -}} - -.search-highlight{{ - background-color: {ColorTranslator.ToHtml(Toolbar.SearchHighlight)}; -}} - -/********************** - TOOLBAR DROPDOWN -***********************/ - -.{template_FR}-toolbar-dropdown-content {{ - display: none; - box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2); - background-color: {ColorTranslator.ToHtml(Toolbar.DropDownMenuColor)}; - min-width: 50px; - z-index: 2; - position: absolute; - {Toolbar.DropDownMenuPosition} - white-space: nowrap; - border-radius: {Toolbar.DropDownListBorder}; -}} - -.{template_FR}-toolbar-item:hover:not([hidden]) > .{template_FR}-toolbar-dropdown-content {{ - display: block; -}} - -.{template_FR}-toolbar-dropdown-content > a {{ - float: none; - color: {ColorTranslator.ToHtml(Toolbar.DropDownMenuTextColor)}; - padding: 6px 12px 6px 8px; - text-decoration: none; - display: block; - text-align: left; - height: auto; - font-size: 14px; - user-select: none; -}} - -.{template_FR}-toolbar-dropdown-content > a:hover {{ - background-color: {ColorTranslator.ToHtml(Toolbar.DropDownMenuColor)}; - opacity: 0.5; - cursor: pointer; - border-radius: 0px 0px 10px 10px; -}} - -.{template_FR}-zoom-selected {{ - font-weight: bold; -}} -.modalcontainer-overlay {{ - position: absolute; - left: 0; - top: 0; - right: 0; - bottom: 0; - background-color: rgba(0, 0, 0, 0.7); - display: flex; - align-items: flex-start; - justify-content: flex-start; - opacity: 0; - z-index: 2; - visibility: hidden; - transition: all 0.3s ease-in-out; - align-content: flex-start; -}} - -.modalcontainer {{ - background-color: #fff; - width: 300px; - height: 300px; - display: flex; - align-items: center; - justify-content: center; - display: none; -}} - -.content-modalcontainer -{{ - width: 100%; -}} - -.modalcontainer-overlay--visible {{ - opacity: 1; - visibility: visible; - transition: all 0.3s ease-in-out; - {Toolbar.Exports.FixedContainerPosition} -}} - -.modalcontainer--visible {{ - display: flex; - width: fit-content; - height: fit-content; - min-width: 348px; - height: auto; - margin-top: 4rem; - margin-left: auto; - margin-right: auto; - padding: 0px 9px 50px 9px; - z-index: 4; - border-radius: 30px 30px 12px 12px; - background-color: #EFEFEF; - flex-wrap: nowrap; - align-content: center; - justify-content: center; - align-items: center; - flex-direction: column; - font-family: Arial,Verdana sans-serif; - {Toolbar.Exports.FixedContainerTags} - {Toolbar.ModalContainerPosition} -}} -//////////////////// - POPUP -/////////////////// -.fr-webreport-popup {{ - min-width: 100%; - position: absolute; - min-height: 100%; - z-index: 3; - padding-bottom: 1rem; - background-color: #0000005c; - display: flex; - align-content: flex-start; - flex-direction: row; - flex-wrap: nowrap; - justify-content: flex-start; - align-items: flex-start; -}} - -.fr-webreport-popup-content {{ - display: flex; - width: fit-content; - height: fit-content; - margin-top: 2.5rem; - margin-left: 2.6rem; - padding: 0px 10px 50px 10px; - z-index: 4; - border-radius: 10px; - background-color: white; - flex-wrap: nowrap; - align-content: center; - justify-content: center; - align-items: center; - flex-direction: column; - font-family: Arial,Verdana sans-serif; -}} - -.fr-webreport-popup-content-title {{ - display: flex; - width: 100%; - background-color: #35363A; - color: white; - font-weight: bold; - box-shadow: 0rem -0.1rem 0rem 0.6rem #35363A; - margin-top: 10px; - margin-bottom: 10px; - align-items: center; - flex-direction: column; - flex-wrap: nowrap; - justify-content: flex-start; - align-content: center; - font: {Toolbar.Exports.UserFontSettingsStyle} 16px {Toolbar.Exports.UserFontSettingsFamily}; - border-radius: 12px 12px 0px 0px; -}} - -.fr-webreport-popup-content-export-parameters-page-range-title{{ - margin-top: 25px; -}} - -.fr-webreport-popup-content-title input {{ - background-color: white; - border: 3px solid {ColorTranslator.ToHtml(Toolbar.Exports.Color)}; - color: black; - max-height: 9.8px; - border-radius: 3px; -}} - -button{{ - text-align: left; -}} - -.fr-webreport-popup-content-export-parameters {{ - display: flex; - width: 100%; - -ms-flex-wrap: wrap; - flex-direction: column; - border-radius: 3px; - padding-bottom: 1rem; - align-content: flex-start; - flex-wrap: wrap; - align-items: flex-start; - justify-content: flex-start; - font: {Toolbar.Exports.UserFontSettingsStyle} 14px {Toolbar.Exports.UserFontSettingsFamily}; - font-weight: bold; -}} - -.fr-webreport-popup-content-export-parameters-col {{ - display: flex; - align-content: center; - flex-wrap: nowrap; - flex-direction: column; - font: {Toolbar.Exports.UserFontSettingsStyle} 11px {Toolbar.Exports.UserFontSettingsFamily}; -}} -.custom-select{{ - width:auto; - outline: none; - max-width: 170px; - min-width: 20px; - border: none; - margin: 5px 5px 5px 5px; - border-radius: 3px; - height: 25px; - font: {Toolbar.Exports.UserFontSettingsStyle} 12px {Toolbar.Exports.UserFontSettingsFamily}; - font-size: 11px; - overflow: hidden; - background: #ffffff url('data:image/svg+xml;base64,{GerResourceBase64("select-arrow.svg")}') no-repeat; - background-position: calc(100% - 10px) center; - -moz-appearance:none; /* Firefox */ - -webkit-appearance:none; /* Safari and Chrome */ - appearance:none; - padding:0 30px 0 10px !important; - -webkit-padding-end: 30px !important; - -webkit-padding-start: 10px !important; -}} -.fr-webreport-popup-content-export-parameters-input {{ - margin-left: 0.3rem; - margin-bottom: 0.3rem; - padding: 6px; - max-width: 70px; - height: 8px; - outline: none; - border: none; - margin-left: 5px; - margin-right: 5px; - min-width: inherit; - border-radius: 4px; - font: {Toolbar.Exports.UserFontSettingsStyle} 10px {Toolbar.Exports.UserFontSettingsFamily}; -}} - -.input-error -{{ - animation: shake 0.2s ease-in-out 0s 2; - box-shadow: 0 0 0.5em red; -}} - -@keyframes shake {{ - 0% {{ margin-left: 0rem; }} - 25% {{ margin-left: 0.5rem; }} - 75% {{ margin-left: -0.5rem; }} - 100% {{ margin-left: 0rem; }} -}} - -.fr-webreport-popup-content-export-parameters-row {{ - display: flex; - padding-top: 5px; - flex-direction: row; - align-items: flex-start; - justify-content: flex-start; -}} -.fr-webreport-popup-content-export-parameters-slider {{ - display: flex; - margin: 0rem 0rem 0rem 0.35rem; - background-color: transparent; - border-radius: 10px; - justify-content: flex-start; - align-items: center; - align-content: center; - flex-direction: row; -}} - -.fr-webreport-popup-content-export-parameters-slider span {{ - color: black; - min-width: 128px; - font: {Toolbar.Exports.UserFontSettingsStyle} 11px {Toolbar.Exports.UserFontSettingsFamily}; - font-weight: normal; - white-space: nowrap; -}} -input[type=range] {{ - height: 1.7rem; - overflow: hidden; - -webkit-appearance: none; - margin-left: 0; - outline: none; - background-color: #424242; -}} - -input[type=range]::-webkit-slider-runnable-track {{ - width: 100%; - height: 100%; - cursor: pointer; - animate: 0.2s; - background: #424242; - border-radius: 0px; -}} -input[type=range]::-webkit-slider-thumb {{ - height: 100%; - width: 5%; - border-radius: 0px; - background: linear-gradient(gray,5%, {ColorTranslator.ToHtml(Toolbar.Exports.Color)}); - cursor: pointer; - -webkit-appearance: none; - box-shadow: -100vw 0vw 0vw 100vw {ColorTranslator.ToHtml(Toolbar.Exports.Color)}; - margin-top: 0px; -}} - -label{{ - margin: 5px 0px; -}} -.fr-webreport-popup-content-export-parameters-col input[type=text] {{ - background-color: white; - color: #000000; - border: 2px solid {ColorTranslator.ToHtml(Toolbar.Exports.Color)}; - max-height: 11px; -}} -.fr-webreport-popup-content-export-parameters-button {{ - padding: 5px; - outline: none; - border: none; - margin-left: 5px; - margin-right: 5px; - min-width: inherit; - font: {Toolbar.Exports.UserFontSettingsStyle} 11px {Toolbar.Exports.UserFontSettingsFamily}; - color: black; - background: url(/_fr/resources.getResource?resourceName=button.svg&contentType=image%2Fsvg%2Bxml) no-repeat; - background-position: 0px center; - padding-left: 20px; - vertical-align: middle; - cursor: pointer; -}} - -.fr-webreport-popup-content-buttons {{ - display: flex; - margin-bottom: -2.3rem; - width: 100%; - flex-wrap: nowrap; - align-content: center; - justify-content: space-between; - align-items: center; - flex-direction: row; -}} - -.fr-webreport-popup-content-btn-submit {{ - outline: none; - border: none; - background-color: #DD4433; - border-radius: 3px; - padding: 3px; - font: {Toolbar.Exports.UserFontSettingsStyle} 14px {Toolbar.Exports.UserFontSettingsFamily}; - color: {ColorTranslator.ToHtml(Toolbar.Exports.FontColor)}; - min-width: 70px; - width: fit-content; - height: 30px; - cursor: pointer; - text-align: center; -}} - -.fr-webreport-popup-content-btn-cancel{{ - padding: 3px; - background-color: #D9D9D9; - font: {Toolbar.Exports.UserFontSettingsStyle} 14px {Toolbar.Exports.UserFontSettingsFamily}; - min-width: 70px; - width: fit-content; - height: 30px; - border-radius: 3px; - border: none; - outline: none; - color: black; - text-align: center; -}} - -.fr-webreport-popup-content-btn-submit:hover {{ - transform: scale(1.015); -}} - -.{template_FR}-container .activeButton {{ - background: url('data:image/svg+xml;base64,{GerResourceBase64("button-active.svg")}') no-repeat; - background-position: 0px center; - vertical-align: middle; -}} - - -.fr-webreport-settings-btn {{ - background-color: transparent; - color: transparent; - padding-left: 1rem; - margin-left: 230px; - display: flex; - float: right; - margin-top: -1.6rem; - outline: none; - padding-right: 1rem; - border: none; - position: relative; - z-index: 4; - flex-direction: row; - align-content: space-around; - justify-content: space-between; - filter:alpha(opacity=50); - opacity: 1; -}} -.fr-webreport-settings-btn:hover{{ - background-color: transparent; - color: transparent; - padding-left: 1rem; - margin-left: 230px; - display: flex; - float: right; - margin-top: -1.6rem; - outline: none; - padding-right: 1rem; - border: none; - position: relative; - z-index: 4; - flex-direction: row; - align-content: space-around; - justify-content: space-between; - transform: scale(1.1); - filter:alpha(opacity=0); - opacity: 0.5; - cursor: pointer; -}} -.fr-webreport-settings-btn::-moz-focus-inner {{ - background-color: transparent; - color: transparent; - padding-left: 1rem; - margin-left: 230px; - display: flex; - float: right; - margin-top: -1.6rem; - outline: none; - padding-right: 1rem; - border: none; - position: relative; - z-index: 4; - flex-direction: row; - align-content: space-around; - justify-content: space-between; -}} - -.fr-webreport-popup-disabled-button{{ - background-color: #D9D9D9; - cursor: default; -}} - -/************************ - TOOLBAR NAVIGATION -*************************/ - -.{template_FR}-toolbar-narrow > svg {{ - transform: rotate({Toolbar.ToolbarNarrow}deg); - padding-left: 0px; - padding-right: 0px; - height: calc({Toolbar.Height}px * 0.35); - padding-top: 9px; -}} - -.{template_FR}-toolbar-slash{{ - }} - -.{template_FR}-toolbar-slash > svg {{ - margin-left: 0px; - margin-right: 0px; - height: calc({Toolbar.Height}px * 0.35); - padding-top: 9px; - margin: 5px 0px 0px; - padding-right: 5px; - padding-left: 5px; -}} - -.{template_FR}-toolbar-item > input {{ - font: {Toolbar.Exports.UserFontSettingsStyle} 12px {Toolbar.Exports.UserFontSettingsFamily}; - font-size: calc({Toolbar.Height}px * 0.35); - text-align: center; - border: 0; - background: #fbfbfb; - border-radius:{Toolbar.ToolbarRoundness}px; - height: calc({Toolbar.Height}px * 0.68); - width: 3.5em; - margin-top: calc({Toolbar.Height}px * 0.17); - margin-bottom: calc({Toolbar.Height}px * 0.15); - margin-left: calc({Toolbar.Height}px * 0.1); - margin-right: calc({Toolbar.Height}px * 0.1); - padding: 0; - display: block; - border-radius: 5px; -}} - -.{template_FR}-toolbar-item > input:hover:not([readonly]) {{ - background: #fff; -}} - -.{template_FR}-toolbar-item > input[readonly] {{ - cursor: default; -}} - -/************** - SPINNER -**************/ - -.{template_FR}-spinner {{ - height: 100%; - width: 100%; - position: absolute; - background-color: rgba(255, 255, 255, 0.7); - z-index: 10; -}} - -.{template_FR}-spinner svg {{ - width: 90px; - height: 90px; - left: calc(50%-50px); - top: calc(50%-50px); - position: absolute; - animation: {template_FR}-spin 1s infinite steps(8); - opacity: 0.5; -}} - -@keyframes {template_FR}-spin {{ - from {{ -webkit-transform: rotate(0deg); }} - to {{ -webkit-transform: rotate(360deg); }} -}} - -/************ - ERROR -************/ - -.{template_FR}-error-container {{ - width: 100%; - height: 100%; - display: flex; - flex-direction: column; - overflow: auto; -}} - -.{template_FR}-error-text {{ - color: red; - font-family: Consolas,monospace; - font-size: 16px; - margin: 20px; - text-align: center; -}} - -.{template_FR}-error-response {{ - height: 100%; - position: relative; -}} - -/*********** - TABS -***********/ - -.{template_FR}-tabs {{ - flex-shrink: 0; - font-family: Verdana,Arial,sans-serif; - background-color: #f1f1f1; - display: table; - width: {Toolbar.TabsPositionSettings}; - max-width: {ReportMaxWidth}px; - box-shadow: 0px 3px 4px -2px rgba(0, 0, 0, 0.2); - position: relative; - border-radius: 9px; - z-index: 1; - {Toolbar.StickyToolbarTabsTags} - {Toolbar.TabsPositionSettings} -}} - - -.{template_FR}-tabs .{template_FR}-tab {{ - float: left; - display: block; - color: #3b3b3b; - text-align: center; - text-decoration: none; - font-size: 12px; - background-color: #f1f1f1; - margin-top: 2px; - margin-right: 2px; - height: 24px; - border-radius: 9px; -}} - -.{template_FR}-tabs .{template_FR}-tab-title {{ - display: block; - float: left; - padding: 4.5px 10px; -}} - -.{template_FR}-tabs .{template_FR}-tab-close {{ - width: 13px; - height: 13px; - display: block; - float: left; - margin-top: 6px; - margin-right: 6px; -}} - -.{template_FR}-tabs .{template_FR}-tab-close svg{{ - border-radius: 10px; -}} - -.{template_FR}-tabs .{template_FR}-tab:hover {{ - background-color: lightgray; - color: black; - cursor: pointer; -}} - -.{template_FR}-tabs .{template_FR}-tab.active {{ - background-color: lightgray; - color: black; - cursor: default; -}} - -.{template_FR}-tabs .{template_FR}-tab a svg {{ - height: 13px; - opacity: 0; -}} - -.{template_FR}-tabs .{template_FR}-tab.active a svg {{ - opacity: 0.5; -}} - -.{template_FR}-tabs .{template_FR}-tab:hover a svg {{ - opacity: 0.5; -}} - -.{template_FR}-tabs .{template_FR}-tab a svg:hover {{ - opacity: 1; - background-color: #f1f1f1; - cursor: pointer; -}} - -/*********** - MISC -***********/ - -.{template_FR}-pointer:hover {{ - cursor: pointer; -}} - -.{template_FR}-disabled {{ - opacity: 0.5; -}} -.datetimepicker > input[type=""date""]{{ - background: url('data:image/svg+xml;base64,{GerResourceBase64("date-picker.svg")}') no-repeat; - background-size: 10px; - background-position: right 5px center; - background-origin: content-box, content-box; -}} -.datetimepicker > input[type=""date""]:disabled {{ - background: url("""") no-repeat; -}} -input[type=date]::-webkit-calendar-picker-indicator {{ - opacity: 0; -}} -/************** - OUTLINE -**************/ - -.{template_FR}-outline {{ - overflow: auto; - height: auto; - font-family: Verdana,Arial,sans-serif; - font-size: 11px; -}} - -.{template_FR}-outline img {{ - opacity: 0.5; -}} - -.{template_FR}-outline-inner {{ - padding: 5px; -}} - -.{template_FR}-outline-node {{ - display: flex; - flex-wrap: wrap; -}} - -.{template_FR}-outline-caret {{ - height: 14px; - width: 14px; - margin-top: 1.5px; - margin-right: 4px; -}} - -.{template_FR}-outline-caret:hover {{ - cursor: pointer; -}} - -.{template_FR}-outline-caret-blank {{ - width: 18px; -}} - -.{template_FR}-outline-file {{ - height: 14px; - margin-top: 1.5px; -}} - -.{template_FR}-outline-text {{ - white-space: nowrap; - display: flex; - align-items: center; -}} - -.{template_FR}-outline-text > a {{ - margin: 2px; - padding: 2px; -}} - -.{template_FR}-outline-text > a:hover {{ - text-decoration: underline; - cursor: pointer; -}} - -.{template_FR}-outline-children {{ - padding-left: 20px; -}} - -/******************* - - EMAIL EXPORT - -*******************/ -.fr-notification {{ - position: fixed; - bottom: 20px; - right: 20px; - display: flex; - align-items: center; - padding: 10px 20px; - border-radius: 4px; - font-size: 14px; - color: white; - opacity: 1; - transition: opacity 0.5s; - z-index: 9999; - font-family: Arial, sans-serif; -}} - -.fr-notification-content {{ - display: flex; - align-items: center; -}} - -.fr-notification-content img {{ - margin-right: 10px; -}} - -.fr-notification.positive {{ - background-color: #44cc44; -}} - -.fr-required-star {{ - color: red; -}} - - -.fr-notification.negative {{ - background-color: #cc4444; -}} - - -.fr-email-export-form {{ - display: flex; - flex-direction: column; - padding: 5px; - box-sizing: border-box; - width: 100%; -}} - -.fr-email-export-field {{ - display: flex; - margin-bottom: 5px; - justify-content: space-between; - width: 100%; - font-size: 12px; -}} - -.fr-email-export-input{{ - width: 244px; - padding: 8px; - border: none; - border-radius: 4px; - background: #FFF; - display: flex; - margin-left: 30px; - font-size: 12px; -}} - -.fr-email-export-textarea{{ - margin - left: 10px; - width: 244px; - height: 146px; - padding: 8px; - border: none; - border-radius: 5px; - resize: none; - font-size: 12px; -}} - -.fr-email-export-select{{ - overflow: hidden; - -moz-appearance:none; /* Firefox */ - -webkit-appearance:none; /* Safari and Chrome */ - background: #ffffff url('data:image/svg+xml;base64,{GerResourceBase64("select-arrow.svg")}') no-repeat; - background-position: calc(100% - 10px) center; - margin - left: 10px; - width: 244px; - padding: 8px; - border-radius: 5px; - border: none; - font-size: 12px; -}} - -.fr-email-export-label{{ - font-weight: normal; - font-size: 12px; -}} -"; + string template_style() => $" :root{{ {GetStyleVars()} }}"; } } \ No newline at end of file diff --git a/FastReport.Core.Web/Templates/tabs.cs b/FastReport.Core.Web/Templates/tabs.cs index 10a02bdd..d1b94f90 100644 --- a/FastReport.Core.Web/Templates/tabs.cs +++ b/FastReport.Core.Web/Templates/tabs.cs @@ -13,7 +13,7 @@ string template_tabs() { StringBuilder sb = new StringBuilder(64); - sb.Append($@"
"); + sb.Append($@"
"); for (int i = 0; i < Tabs.Count; i++) { @@ -30,14 +30,14 @@ string template_tabs() var tab = Tabs[i]; var active = i == CurrentTabIndex ? "active" : ""; - var settab = i == CurrentTabIndex ? "" : $@"onclick=""{template_FR}.settab('{i}');"""; - var closetab = $@"onclick=""{template_FR}.closetab('{i}');"""; + var settab = i == CurrentTabIndex ? "" : CreateOnClickEvent(ScriptName, "settab", i.ToString()); + var closetab = CreateOnClickEvent(ScriptName, "closetab", i.ToString()); - sb.Append($@"
"); - sb.Append($@"{GetTabName(i)}"); + sb.Append($@"
"); + sb.Append($@"{GetTabName(i)}"); if (tab.Closeable) - sb.Append($@" + sb.Append($@" {GetResource("close.svg")} "); diff --git a/FastReport.Core.Web/Templates/toolbar.cs b/FastReport.Core.Web/Templates/toolbar.cs index e872bbb2..7f4049a8 100644 --- a/FastReport.Core.Web/Templates/toolbar.cs +++ b/FastReport.Core.Web/Templates/toolbar.cs @@ -27,40 +27,40 @@ string template_toolbar(bool renderBody) var localization = new ToolbarLocalization(Res); var exports = Toolbar.Exports; var target = $"target=\"{(!exports.ExportInNewTab ? "_self" : "_blank")}\""; - var toolbarExportItem = $@"
+ var toolbarExportItem = $@"
{GetResource("save.svg")} -
" +
" + (exports.ShowPreparedReport ? $@"{localization.preparedTxt}" : "") #if !OPENSOURCE + (exports.ShowPdfExport ? $@"{localization.pdfTxt}":"") - + (exports.EnableSettings && exports.ShowPdfExport ? $@"" : "") + + (exports.EnableSettings && exports.ShowPdfExport ? $@"" : "") + (exports.ShowExcel2007Export ? $@"{localization.excel2007Txt}" : "") - + (exports.EnableSettings && exports.ShowExcel2007Export ? $@"" : "") + + (exports.EnableSettings && exports.ShowExcel2007Export ? $@"" : "") + (exports.ShowWord2007Export ? $@"{localization.word2007Txt}" : "") - + (exports.EnableSettings && exports.ShowWord2007Export ? $@"" : "") + + (exports.EnableSettings && exports.ShowWord2007Export ? $@"" : "") + (exports.ShowPowerPoint2007Export ? $@"{localization.powerPoint2007Txt}" : "") - + (exports.EnableSettings && exports.ShowPowerPoint2007Export ? $@"" : "") + + (exports.EnableSettings && exports.ShowPowerPoint2007Export ? $@"" : "") + (exports.ShowTextExport ? $@"{localization.textTxt}" : "") + (exports.ShowRtfExport ? $@"{localization.rtfTxt}" : "") - + (exports.EnableSettings && exports.ShowRtfExport ? $@"" : "") + + (exports.EnableSettings && exports.ShowRtfExport ? $@"" : "") + (exports.ShowXpsExport ? $@"{localization.xpsTxt}" : "") + (exports.ShowOdsExport ? $@"{localization.odsTxt}" : "") - + (exports.EnableSettings && exports.ShowOdsExport ? $@"" : "") + + (exports.EnableSettings && exports.ShowOdsExport ? $@"" : "") + (exports.ShowOdtExport ? $@"{localization.odtTxt}" : "") - + (exports.EnableSettings && exports.ShowOdtExport ? $@"" : "") + + (exports.EnableSettings && exports.ShowOdtExport ? $@"" : "") + (exports.ShowXmlExcelExport ? $@"{localization.xmlTxt}" : "") - + (exports.EnableSettings && exports.ShowXmlExcelExport ? $@"" : "") + + (exports.EnableSettings && exports.ShowXmlExcelExport ? $@"" : "") + (exports.ShowDbfExport ? $@"{localization.dbfTxt}" : "") + (exports.ShowCsvExport ? $@"{localization.csvTxt}" : "") + (exports.ShowSvgExport ? $@"{localization.svgTxt}" : "") - + (exports.EnableSettings && exports.ShowSvgExport? $@"" : "") + + (exports.EnableSettings && exports.ShowSvgExport? $@"" : "") + (exports.ShowMhtExport ? $@"{localization.mhtTxt}" : "") + (exports.ShowExcel97Export ? $@"{localization.excel97Txt}" : "") - + (exports.ShowEmailExport ? $@"{localization.emailTxt}" : "") + + (exports.ShowEmailExport ? $@"{localization.emailTxt}" : "") + (exports.ShowHpglExport ? $@"{localization.hpglTxt}" : "") + (exports.ShowHTMLExport ? $@"{localization.htmlTxt}" : "") - + (exports.EnableSettings && exports.ShowHTMLExport ? $@"" : "") - + (exports.ShowImageExport? $@"{localization.imageTxt}" : "") + (exports.EnableSettings && exports.ShowImageExport ? $@"" : "") + + (exports.EnableSettings && exports.ShowHTMLExport ? $@"" : "") + + (exports.ShowImageExport? $@"{localization.imageTxt}" : "") + (exports.EnableSettings && exports.ShowImageExport ? $@"" : "") + (exports.ShowJsonExport ? $@"{localization.jsonTxt}" : "") + (exports.ShowDxfExport ? $@"{localization.dxfTxt}" : "") + (exports.ShowLaTeXExport ? $@"{localization.latexTxt}" : "") @@ -71,9 +71,9 @@ string template_toolbar(bool renderBody) #endif + "
" ; - var toolbarPrintItem = $@"
+ var toolbarPrintItem = $@"
{GetResource("print.svg")} -
+
" + (Toolbar.PrintInHtml ? $@"{localization.printFromBrowserTxt} " : "") + @@ -84,17 +84,17 @@ string template_toolbar(bool renderBody) $@"
"; var currentZoom = Zoom * 100; - var selectedZoom1 = $@"
"; + var selectedZoom1 = $@"
"; var selectedZoom2 = $@"
"; var isFirstPage = CurrentPageIndex == 0; var isLastPage = CurrentPageIndex >= TotalPages - 1; var isSinglePage = SinglePage || TotalPages < 2; - var customButtons = string.Join("", Toolbar.Elements.Select(x => x.Render(template_FR))); + var customButtons = string.Join("", Toolbar.Elements.Select(x => x.Render(ScriptName))); string templateToolbar = $@" -
+
-{(showRefreshButton ? $@"
+{(showRefreshButton ? $@"
{GetResource("reload.svg")}
" : "")} @@ -102,24 +102,24 @@ string template_toolbar(bool renderBody) {(Toolbar.ShowPrint ? $"{toolbarPrintItem}" : "")} -{(Toolbar.ShowSearchButton ? $@"
+{(Toolbar.ShowSearchButton ? $@"
{GetResource("magnifier-search.svg")}
-
-
-
- - +
+
+
+ +
-

+

- -
@@ -137,44 +137,44 @@ string template_toolbar(bool renderBody)
" : "")} -{(Toolbar.ShowZoomButton ? $@" - {(currentZoom == 100 ? selectedZoom1 : selectedZoom2)}100%
- {(currentZoom == 90 ? selectedZoom1 : selectedZoom2)}90%
- {(currentZoom == 75 ? selectedZoom1 : selectedZoom2)}75%
- {(currentZoom == 50 ? selectedZoom1 : selectedZoom2)}50%
- {(currentZoom == 25 ? selectedZoom1 : selectedZoom2)}25%
+ + {(currentZoom == 200 ? selectedZoom1 : selectedZoom2)}200%
+ {(currentZoom == 150 ? selectedZoom1 : selectedZoom2)}150%
+ {(currentZoom == 100 ? selectedZoom1 : selectedZoom2)}100%
+ {(currentZoom == 90 ? selectedZoom1 : selectedZoom2)}90%
+ {(currentZoom == 75 ? selectedZoom1 : selectedZoom2)}75%
+ {(currentZoom == 50 ? selectedZoom1 : selectedZoom2)}50%
+ {(currentZoom == 25 ? selectedZoom1 : selectedZoom2)}25%
" : "")}" + $@" - {(Toolbar.ShowFirstButton ? $@"
+ {(Toolbar.ShowFirstButton ? $@"
{GetResource("angle-double-left.svg")}
" : "")} -{(Toolbar.ShowPrevButton ? $@"
+{(Toolbar.ShowPrevButton ? $@"
{GetResource("angle-left.svg")}
" : "")} -
- TotalPages ? TotalPages : (CurrentPageIndex + 1))}"" onchange=""{template_FR}.goto(document.getElementsByClassName('{template_FR}-current-page-input')[0].value);"" title=""{localization.currentPageTxt}""> +
+ TotalPages ? TotalPages : (CurrentPageIndex + 1))}"" {CreateEvent(JSEvents.CHANGE, ScriptName, "goto", "this.value")} title=""{localization.currentPageTxt}"">
-
+
{GetResource("slash.svg")}
-
+
-{(Toolbar.ShowNextButton ? $@"
+{(Toolbar.ShowNextButton ? $@"
{GetResource("angle-right.svg")}
" : "")} -{(Toolbar.ShowLastButton ? $@"
+{(Toolbar.ShowLastButton ? $@"
{GetResource("angle-double-right.svg")}
" : "")} {customButtons} diff --git a/FastReport.Web.Base/package.json b/FastReport.Web.Base/package.json new file mode 100644 index 00000000..d5d51997 --- /dev/null +++ b/FastReport.Web.Base/package.json @@ -0,0 +1,21 @@ +{ + "name": "fastreport-web", + "version": "1.0.0", + "scripts": { + "clean": "rimraf wwwroot/js/*.bundle.min.js" + }, + "devDependencies": { + "@rollup/plugin-commonjs": "^25.0.0", + "@rollup/plugin-node-resolve": "^15.0.0", + "@rollup/plugin-terser": "^0.4.0", + "rollup": "^3.0.0", + "rollup-plugin-delete": "^2.0.0", + "@rollup/plugin-replace": "^5.0.0", + "rimraf": "^5.0.0", + "autoprefixer": "^10.4.16", + "cssnano": "^6.0.1", + "npm-run-all": "^4.1.5", + "postcss": "^8.4.31", + "postcss-cli": "^10.1.0" + } +} \ No newline at end of file diff --git a/FastReport.Web.Base/postcss.config.js b/FastReport.Web.Base/postcss.config.js new file mode 100644 index 00000000..9f4757f3 --- /dev/null +++ b/FastReport.Web.Base/postcss.config.js @@ -0,0 +1,28 @@ +// CSS bundle builder +module.exports = (ctx) => { + const args = process.argv.slice(2); + const isProduction = args[args.indexOf('--environment') + 1] != 'development'; + + const plugins = [ + // Combining imports (@import) + // require('postcss-import')(), + + // Auto-prefixes + require('autoprefixer')({ + overrideBrowserslist: ['last 2 versions', '> 1%', 'IE 11'] + }) + ]; + + // Minification + if (isProduction) { + plugins.push( + require('cssnano')({ + preset: 'default' + }) + ); + } + + return { + plugins + }; +}; \ No newline at end of file diff --git a/FastReport.Web.Base/rollup.config.mjs b/FastReport.Web.Base/rollup.config.mjs new file mode 100644 index 00000000..ccd3791e --- /dev/null +++ b/FastReport.Web.Base/rollup.config.mjs @@ -0,0 +1,78 @@ +// JS bundle builder +import { nodeResolve } from '@rollup/plugin-node-resolve'; +import commonjs from '@rollup/plugin-commonjs'; +import terser from '@rollup/plugin-terser'; +import del from 'rollup-plugin-delete'; +import replace from '@rollup/plugin-replace'; +import { defineConfig } from 'rollup'; +import path from 'path'; + +const args = process.argv.slice(2); +const isProduction = args[args.indexOf('--environment') + 1] != 'development'; +const isOpenSource = args[args.indexOf('--environment') + 1] == 'opensource'; +const outPutPath = args[args.indexOf('--output-path') + 1].replace('"', ''); +const outputFile = path.join(outPutPath, 'wwwroot', 'js', 'webreport-script.bundle.min.js'); + +export default defineConfig([ + { + // main bundle + input: 'wwwroot/js/main-scripts.js', + output: { + file: outputFile, + format: 'iife', + name: 'WebReportScript', + sourcemap: !isProduction + }, + plugins: [ + + del({ targets: outputFile, force: true }), + del({ targets: `${outputFile}.min`, force: true }), + replace({ + preventAssignment: true, + values: { + '__EXPORT_SETTINGS__': !isOpenSource ? './ExportScripts/export-settings.js' : './ExportScripts/export-settings-open-source.js', + } + }), + nodeResolve({ browser: true }), + commonjs(), + + // Minification + isProduction && terser({ + compress: { + drop_console: true, + drop_debugger: true + } + }) + ].filter(Boolean), + onwarn(warning, warn) { + if (warning.code === 'THIS_IS_UNDEFINED') return; + warn(warning); + } + }, + { + input: 'wwwroot/js/printscript.js', + output: { + file: path.join(outPutPath, 'wwwroot', 'js', 'printscript.min.js'), + format: 'iife', + name: 'WebReportExportScript', + sourcemap: !isProduction + }, + plugins: [ + nodeResolve({ browser: true }), + commonjs(), + isProduction && terser() + ].filter(Boolean) + }, + { + input: 'wwwroot/js/split.js', + output: { + file: path.join(outPutPath, 'wwwroot', 'js', 'split.min.js'), + format: 'iife', + name: 'Split', + sourcemap: false + }, + plugins: [ + terser() + ].filter(Boolean) + } +]); \ No newline at end of file diff --git a/FastReport.Web.Base/wwwroot/js/ExportScripts/docx-export.js b/FastReport.Web.Base/wwwroot/js/ExportScripts/docx-export.js new file mode 100644 index 00000000..c72e1c32 --- /dev/null +++ b/FastReport.Web.Base/wwwroot/js/ExportScripts/docx-export.js @@ -0,0 +1,41 @@ +//DOCXEXPORT// +import { AddAction } from './export-utils.js'; +var DocxButtons; +var DocxRowHeights = '&RowHeight=Exactly'; +var DocxOnRenderMode = '&PrintFit=layers'; +var DocxWysiwyg = false; +var DocxPrintOptimized = false; +var DocxDoNotExpandShiftReturn = false; + +function DocxRowHeightsFunc(select) { + const DocxRowHeightsChange = select.querySelector(`option[value='${select.value}']`) + DocxRowHeights = '&RowHeight=' + DocxRowHeightsChange.value; +} + +function DocxOnRenderModeFunc(select) { + const DocxOnRenderModeChange = select.querySelector(`option[value='${select.value}']`); + const matrixBasedValue = DocxOnRenderModeChange.value === "table" ? "true" : "false"; + DocxOnRenderMode = '&PrintFit=' + DocxOnRenderModeChange.value + '&MatrixBased=' + matrixBasedValue; +} + +export function DOCXExport() { + if (document.getElementById('DocxPrintOptimized').classList.contains('activeButton')) { + DocxPrintOptimized = new Boolean(true); + } + else { DocxPrintOptimized = false; }; + if (document.getElementById('DocxDoNotExpandShiftReturn').classList.contains('activeButton')) { + DocxDoNotExpandShiftReturn = new Boolean(true); + } + else { DocxDoNotExpandShiftReturn = false; }; + if (document.getElementById('DocxWysiwyg').classList.contains('activeButton')) { + DocxWysiwyg = new Boolean(true); + } + else { DocxWysiwyg = false; }; + DocxButtons = ('&PrintOptimized=' + DocxPrintOptimized + '&DoNotExpandShiftReturn=' + DocxDoNotExpandShiftReturn + '&Wysiwyg=' + DocxWysiwyg + DocxRowHeights + DocxOnRenderMode ); + + window.location.href = DocxExport.href + DocxButtons + frActions.PageSelector; +} + +AddAction('DocxRowHeightsFunc', DocxRowHeightsFunc); +AddAction('DocxOnRenderModeFunc', DocxOnRenderModeFunc); +AddAction('DOCXExport', DOCXExport); diff --git a/FastReport.Web.Base/wwwroot/js/ExportScripts/email-export.js b/FastReport.Web.Base/wwwroot/js/ExportScripts/email-export.js new file mode 100644 index 00000000..7f8822e4 --- /dev/null +++ b/FastReport.Web.Base/wwwroot/js/ExportScripts/email-export.js @@ -0,0 +1,36 @@ +//EMAILEXPORT// +import { AddAction } from './export-utils.js'; +var EmailExportInputs; +var RecieverAddress; +var Subject; +var Message; +var SenderAddress; +var Host; + +function EMAILExport(webReport, SuccessMessage, FailureMessage) { + var url = `/_fr/preview.sendEmail?reportId=${webReport.ID}`; + + var formData = new FormData(); + formData.append("Address", document.getElementById("Email").value); + formData.append("Subject", document.getElementById("Subject").value); + formData.append("MessageBody", document.getElementById("Message").value); + formData.append("ExportFormat", document.getElementById("ExportFormat").value); + formData.append("NameAttachmentFile", document.getElementById("NameAttachmentFile").value); + + fetch(url, { + method: 'POST', + body: formData + }) + .then(response => { + if (response.ok) { + webReport.showPopup(`${SuccessMessage}`, true); + } else { + webReport.showPopup(`${FailureMessage}`, false); + } + }) + .catch(error => { + webReport.showPopup(`${FailureMessage}`, false); + }) +} + +AddAction('EMAILExport', EMAILExport); diff --git a/FastReport.Web.Base/wwwroot/js/ExportScripts/export-settings-open-source.js b/FastReport.Web.Base/wwwroot/js/ExportScripts/export-settings-open-source.js new file mode 100644 index 00000000..b1f6d227 --- /dev/null +++ b/FastReport.Web.Base/wwwroot/js/ExportScripts/export-settings-open-source.js @@ -0,0 +1,2 @@ +import './html-export'; +import './image-export'; \ No newline at end of file diff --git a/FastReport.Web.Base/wwwroot/js/ExportScripts/export-settings.js b/FastReport.Web.Base/wwwroot/js/ExportScripts/export-settings.js new file mode 100644 index 00000000..464e3caa --- /dev/null +++ b/FastReport.Web.Base/wwwroot/js/ExportScripts/export-settings.js @@ -0,0 +1,12 @@ +import './docx-export'; +import './email-export'; +import './html-export'; +import './image-export'; +import './ods-export'; +import './odt-export'; +import './pdf-export'; +import './pptx-export'; +import './rtf-export'; +import './svg-export'; +import './xlsx-export'; +import './xml-export'; \ No newline at end of file diff --git a/FastReport.Web.Base/wwwroot/js/ExportScripts/export-utils.js b/FastReport.Web.Base/wwwroot/js/ExportScripts/export-utils.js new file mode 100644 index 00000000..4cefcc34 --- /dev/null +++ b/FastReport.Web.Base/wwwroot/js/ExportScripts/export-utils.js @@ -0,0 +1,146 @@ +'use strict'; +export function IsValid() { + var pageSelector = document.getElementById('PageSelector'); + var pageRange = pageSelector ? pageSelector.value : ''; + var validationRegex = new RegExp("^(\\s*\\d+\\s*\\-\\s*\\d+\\s*,?|\\s*\\d+\\s*,?)+$"); + + if (!validationRegex.test(pageRange) && pageRange !== "") { + return false; + } + return true; +} + +export function onChange() { + var okButton = document.getElementById('okButton'); + var input = document.getElementById('PageSelector'); + + const pageRange = input.value.trim(); + const validationRegex = /^(\s*\d+\s*-\s*\d+\s*,?|\s*\d+\s*,?)+$/; + let isError = false; + let numbers = []; + + if (pageRange) { + numbers = pageRange.match(/(-\d+|\d+)(,\d+)*(\.\d+)*/g) || []; + numbers = numbers.map(n => Number(n.replace(/,/g, ''))); + numbers.forEach(elem => { + if (elem > AllPages.value) { + isError = true; + } + }); + } + + if (validationRegex.test(pageRange) || pageRange === "") { + window.frActions.PageSelector = `&PageRange=PageNumbers&PageNumbers=${pageRange}`; + input.classList.remove('input-error'); + okButton.classList.remove("fr-popup-disabled-button"); + okButton.disabled = isError; + } else { + input.classList.add('input-error'); + okButton.classList.add("fr-popup-disabled-button"); + okButton.disabled = true; + } +} +var modalOverlay; +var modalBtnsSubmit; +var modals; +export function createLisners() { + var but = document.querySelectorAll('.fr-settings-btn'); + var activebtn = document.querySelectorAll('.fr-popup-content-export-parameters-button'); + modals = document.querySelectorAll('.modalcontainer'); + modalOverlay = document.querySelector('.modalcontainer-overlay'); + modalBtnsSubmit = document.querySelectorAll('.fr-popup-content-btn-submit'); + window.frActions.PageSelector = '&PageRange=All'; + + modalBtnsSubmit.forEach((el) => { + el.addEventListener('click', (e) => { + modalOverlay.classList.remove('modalcontainer-overlay--visible'); + modals.forEach((el) => { + el.classList.remove('modalcontainer--visible'); + }); + }); + }); + + but.forEach((el) => { + el.removeEventListener('click', RadioButtonStateChange); + el.addEventListener('click', RadioButtonStateChange); + }); + + modalOverlay.addEventListener('click', ModalOverlayClick); + + activebtn.forEach((el) => { + el.addEventListener('click', (e) => { + { + if (el.getAttribute('name') != 'OnRgbClick' && el.getAttribute('name') != 'OnCmykClick' && + el.getAttribute('name') != 'OnFirstClick' && el.getAttribute('name') != 'OnAllClick') { + { + el.classList.toggle('activeButton'); + } + } + } + }); + }); + + AddAction('OnFirstClick', OnFirstClick); + AddAction('OnAllClick', OnAllClick); + AddAction('OnPageSelectorChange', onChange); +} + +function ModalOverlayClick(e) { + if (e.target == modalOverlay || e.target == modalBtnsSubmit) { + modalOverlay.classList.remove('modalcontainer-overlay--visible'); + modals.forEach((el) => { + el.innerHTML = ''; + el.classList.remove('modalcontainer--visible'); + }); + } +} +function RadioButtonStateChange(e) { + let path = e.currentTarget.getAttribute('data-path'); + + modals.forEach((el) => { + el.classList.remove('modalcontainer--visible'); + }); +} + +export function OnFirstClick() { + var OnFirst = document.getElementsByName('OnFirstClick'); + var OnAll = document.getElementsByName('OnAllClick'); + var PageSelectorInput = document.getElementsByName('PageSelectorInput'); + var okButton = document.getElementById('okButton'); + var input = document.getElementById('PageSelector'); + for (var i = 0; i < PageSelectorInput.length; i++) { + PageSelectorInput[i].value = CurrentPage.value; + } + for (var i = 0; i < OnAll.length; i++) { + OnAll[i].classList.remove('activeButton'); + } + OnFirst[0].classList.add('activeButton'); + PageSelectorInput[0].value = CurrentPage.value; + OnAll[0].classList.remove('activeButton'); + window.frActions.PageSelector = '&PageRange=PageNumbers&PageNumbers=' + CurrentPage.value; + okButton.disabled = false; + okButton.classList.remove("fr-popup-disabled-button"); + input.classList.remove('input-error'); +} + +export function OnAllClick() { + var OnAll = document.getElementsByName('OnAllClick'); + var OnFirst = document.getElementsByName('OnFirstClick'); + var PageSelectorInput = document.getElementsByName('PageSelectorInput'); + var okButton = document.getElementById('okButton'); + var input = document.getElementById('PageSelector'); + OnAll[0].classList.add('activeButton'); + PageSelectorInput[0].value = '1 - ' + AllPages.value; + OnFirst[0].classList.remove('activeButton'); + window.frActions.PageSelector = '&PageRange=All'; + okButton.disabled = false; + okButton.classList.remove("fr-popup-disabled-button"); + input.classList.remove('input-error'); +} + +export function AddAction(name, action) { + if (!window.frActions) + window.frActions = {}; + window.frActions[name] = action; +} + diff --git a/FastReport.Web.Base/wwwroot/js/ExportScripts/html-export.js b/FastReport.Web.Base/wwwroot/js/ExportScripts/html-export.js new file mode 100644 index 00000000..5e868844 --- /dev/null +++ b/FastReport.Web.Base/wwwroot/js/ExportScripts/html-export.js @@ -0,0 +1,65 @@ +//HTMLEXPORT// +import { AddAction } from './export-utils.js'; +var HTMLButtons; +var HTMLPictures = new Boolean(false); +var HTMLSubFolder = new Boolean(false); +var HTMLNavigator = new Boolean(false); +var HTMLSinglePage = new Boolean(false); +var HTMLLayers = new Boolean(false); +var HTMLShowPageBorder = new Boolean(false); +var HTMLCenterAndWrapPages = new Boolean(false) +var HTMLEmbeddingPictures = new Boolean(false); +var HTMLWysiwyg = new Boolean(false); + +function HTMLExport() { + if (document.getElementById('HTMLWysiwyg').classList.contains('activeButton')) { + HTMLWysiwyg = new Boolean(true); + } + else { HTMLWysiwyg = new Boolean(false); }; + + if (document.getElementById('HTMLPictures').classList.contains('activeButton')) { + HTMLPictures = new Boolean(true); + } + else { HTMLPictures = new Boolean(false); }; + + if (document.getElementById('HTMLSubFolder').classList.contains('activeButton')) { + HTMLSubFolder = new Boolean(true); + } + else { HTMLSubFolder = new Boolean(false); }; + + if (document.getElementById('HTMLShowPageBorder').classList.contains('activeButton')) { + HTMLShowPageBorder = new Boolean(true); + } + else { HTMLShowPageBorder = new Boolean(false); }; + + if (document.getElementById('HTMLCenterAndWrapPages').classList.contains('activeButton')) { + HTMLCenterAndWrapPages = new Boolean(true); + } + else { HTMLCenterAndWrapPages = new Boolean(false); }; + + if (document.getElementById('HTMLNavigator').classList.contains('activeButton')) { + HTMLNavigator = new Boolean(true); + } + else { HTMLNavigator = new Boolean(false); }; + + if (document.getElementById('HTMLSinglePage').classList.contains('activeButton')) { + HTMLSinglePage = new Boolean(true); + } + else { HTMLSinglePage = new Boolean(false); }; + + if (document.getElementById('HTMLLayers').classList.contains('activeButton')) { + HTMLLayers = new Boolean(true); + } + else { HTMLLayers = new Boolean(false); }; + + if (document.getElementById('HTMLEmbeddingPictures').classList.contains('activeButton')) { + HTMLEmbeddingPictures = new Boolean(true); + } + else { HTMLEmbeddingPictures = new Boolean(false); }; + HTMLButtons = ('&Navigator=' + HTMLNavigator + '&Wysiwyg=' + HTMLWysiwyg + '&Pictures=' + HTMLPictures + '&SinglePage=' + HTMLSinglePage + '&Layers=' + HTMLLayers + '&SubFolder=' + HTMLSubFolder + '&EmbedPictures=' + HTMLEmbeddingPictures + + '&ShowPageBorders=' + HTMLShowPageBorder + '&CenterAndWrapPages=' + HTMLCenterAndWrapPages); + + window.location.href = HtmlExport.href + HTMLButtons + window.frActions.PageSelector; +}; + +AddAction('HTMLExport', HTMLExport); diff --git a/FastReport.Web.Base/wwwroot/js/ExportScripts/image-export.js b/FastReport.Web.Base/wwwroot/js/ExportScripts/image-export.js new file mode 100644 index 00000000..d2ebd27e --- /dev/null +++ b/FastReport.Web.Base/wwwroot/js/ExportScripts/image-export.js @@ -0,0 +1,90 @@ +//SLIDER// +import { AddAction } from './export-utils.js'; +var SliderOutputImage = '90'; +function Slider() { + var SliderRange = document.getElementsByName('SliderRange'); + var SliderValue = document.getElementsByName('SliderValue'); + for (var i = 0; i < SliderRange.length; i++) { + SliderValue[i].innerHTML = SliderRange[i].value + + } + SliderOutputImage = SliderRange[0].value; +} + +function JpegQualityFunc(select){ + const JpegQuality = select.querySelector(`option[value='${select.value}']`) + SliderOutputImage = JpegQuality.value +} + +//IMAGE// +var ImageButtons; +var ImageResolutionX = '&ResolutionX=90'; +var ImageResolutionY = '&ResolutionY=90'; +var ImageQuality = '&JpegQuality=90'; +var ImageOptionSettings = document.getElementsByName('ImageEnableOrNot'); +var ImageOnImageFormat = '&ImageFormat=Jpeg'; +var ImageOnMultiFrameTiffClick = false; +var ImageOnMonochromeTiffClick = false; +var ImageOnSeparateFilesClick = false; + +//function OnInputClickIMAGE() { +// {template_pscustom} +//} +function ImageOnImageFormatFunc(select) { + const ImageOnImageFormatChange = select.querySelector(`option[value='${select.value}']`) + + if (ImageOnImageFormatChange.value == 'Gif' || ImageOnImageFormatChange.value == 'Png' || ImageOnImageFormatChange.value == 'Bmp' || ImageOnImageFormatChange.value == 'Metafile') { + + ImageOptionSettings[0].style.display = 'block'; + ImageOptionSettings[1].style.display = 'none'; + ImageOptionSettings[2].style.display = 'none'; + ImageOptionSettings[3].style.display = 'none'; + ImageOptionSettings[5].style.display = 'block'; + } + else if (ImageOnImageFormatChange.value == 'Jpeg') { + + ImageOptionSettings[0].style.display = 'block'; + ImageOptionSettings[1].style.display = 'none'; + ImageOptionSettings[2].style.display = 'flex'; + ImageOptionSettings[5].style.display = 'block'; + + + } + else if (ImageOnImageFormatChange.value == 'Tiff') { + ImageOptionSettings[0].style.display = 'block'; + ImageOptionSettings[1].style.display = 'block'; + ImageOptionSettings[2].style.display = 'none'; + ImageOptionSettings[3].style.display = 'block'; + ImageOptionSettings[4].style.display = 'block'; + ImageOptionSettings[5].style.display = 'block'; + } + ImageOnImageFormat = '&ImageFormat=' + ImageOnImageFormatChange.value; +} +function IMAGEExport() { + ImageResolutionX = '&ResolutionX=' + document.getElementById('ImageResolutionX').value; + ImageResolutionY = '&ResolutionY=' + document.getElementById('ImageResolutionY').value; + ImageQuality = '&JpegQuality=' + SliderOutputImage; + + if (document.getElementById('ImageOnMultiFrameTiffClick').classList.contains('activeButton')) { + ImageOnMultiFrameTiffClick = new Boolean(true); + } + else { ImageOnMultiFrameTiffClick = false; }; + + if (document.getElementById('ImageOnMonochromeTiffClick').classList.contains('activeButton')) { + ImageOnMonochromeTiffClick = new Boolean(true); + } + else { ImageOnMonochromeTiffClick = false; }; + + if (document.getElementById('ImageOnSeparateFilesClick').classList.contains('activeButton')) { + ImageOnSeparateFilesClick = new Boolean(true); + } + else { ImageOnSeparateFilesClick = false; }; + + ImageButtons = ('&MultiFrameTiff=' + ImageOnMultiFrameTiffClick + '&MonochromeTiff=' + ImageOnMonochromeTiffClick + '&SeparateFiles=' + ImageOnSeparateFilesClick); + window.location.href = ImageExport.href + ImageOnImageFormat + ImageButtons + frActions.PageSelector + ImageQuality + ImageResolutionX + ImageResolutionY; +} + +AddAction('IMAGEExport', IMAGEExport); +AddAction('ImageOnImageFormatFunc', ImageOnImageFormatFunc); +AddAction('Slider', Slider); +AddAction('JpegQualityFunc', JpegQualityFunc); diff --git a/FastReport.Web.Base/wwwroot/js/ExportScripts/ods-export.js b/FastReport.Web.Base/wwwroot/js/ExportScripts/ods-export.js new file mode 100644 index 00000000..e3a4409b --- /dev/null +++ b/FastReport.Web.Base/wwwroot/js/ExportScripts/ods-export.js @@ -0,0 +1,27 @@ +//ODSEXPORT// +import { AddAction } from './export-utils.js'; +var OdsButtons; +var OdsOnCompliance = '&OdfCompliance=None'; +var OdsWysiwyg = false; +var OdsPageBreaks = false; + +function OdsOnComplianceChangeFunc(select) { + const OdsOnComplianceChange = select.querySelector(`option[value='${select.value}']`) + OdsOnCompliance = '&OdfCompliance=' + OdsOnComplianceChange.value; +} +function ODSExport() { + if (document.getElementById('OdsWysiwyg').classList.contains('activeButton')) { + OdsWysiwyg = new Boolean(true); + } + else { OdsWysiwyg = false; }; + if (document.getElementById('OdsPageBreaks').classList.contains('activeButton')) { + OdsPageBreaks = new Boolean(true); + } + else { OdsPageBreaks = false; }; + OdsButtons = ('&Wysiwyg=' + OdsWysiwyg + '&PageBreaks=' + OdsPageBreaks); + + window.location.href = OdsExport.href + OdsButtons + OdsOnCompliance + frActions.PageSelector; +} + +AddAction('OdsOnComplianceChangeFunc', OdsOnComplianceChangeFunc); +AddAction('ODSExport', ODSExport); diff --git a/FastReport.Web.Base/wwwroot/js/ExportScripts/odt-export.js b/FastReport.Web.Base/wwwroot/js/ExportScripts/odt-export.js new file mode 100644 index 00000000..211d96ab --- /dev/null +++ b/FastReport.Web.Base/wwwroot/js/ExportScripts/odt-export.js @@ -0,0 +1,27 @@ +//ODTEXPORT// +import { AddAction } from './export-utils.js'; +var OdtButtons; +var OdtOnCompliance = '&OdfCompliance=None'; +var OdtWysiwyg = false; +var OdtPageBreaks = false; + +function OdtOnComplianceChangeFunc(select) { + const OdtOnComplianceChange = select.querySelector(`option[value='${select.value}']`) + OdtOnCompliance = '&OdfCompliance=' + OdtOnComplianceChange.value; +} +function ODTExport() { + if (document.getElementById('OdtWysiwyg').classList.contains('activeButton')) { + OdtWysiwyg = new Boolean(true); + } + else { OdtWysiwyg = false; }; + if (document.getElementById('OdtPageBreaks').classList.contains('activeButton')) { + OdtPageBreaks = new Boolean(true); + } + else { OdtPageBreaks = false; }; + OdtButtons = ('&Wysiwyg=' + OdtWysiwyg + '&PageBreaks=' + OdtPageBreaks); + + window.location.href = OdtExport.href + OdtButtons + OdtOnCompliance; +} + +AddAction('OdtOnComplianceChangeFunc', OdtOnComplianceChangeFunc); +AddAction('ODTExport', ODTExport); diff --git a/FastReport.Web.Base/wwwroot/js/ExportScripts/pdf-export.js b/FastReport.Web.Base/wwwroot/js/ExportScripts/pdf-export.js new file mode 100644 index 00000000..cbfcf4ec --- /dev/null +++ b/FastReport.Web.Base/wwwroot/js/ExportScripts/pdf-export.js @@ -0,0 +1,101 @@ +//PDFEXPORT// +import { AddAction } from './export-utils.js'; +var PDFCompilance = '&PdfCompliance=None'; +var PDFButtons = '&EmbeddingFonts=false&TextInCurves=false&InteractiveForms=false&Background=false'; +var PDFColorSpace = '&PDFColorSpace=RGB'; +var PDFJpegQuality = '&PDFJpegQuality=90'; +var PDFOnImageOption = '&PDFPrintOptimized=false&PDFImagesOriginalResolution=false'; +var PDFPrintOptimized = false; +var PDFImagesOriginalResolution = false; +var PDFOnEmbeddedFonts = false; +var PDFOnTextInCurves = false; +var PDFOnInteractive = false; +var PDFOnBackground = false; + +function OnRgbClick() { + let rgb = document.getElementById('RGB'); + let cmyk = document.getElementById('CMYK'); + + if (!document.getElementById('RGB').classList.contains('activeButton')) { + cmyk.classList.remove('activeButton'); + rgb.classList.add('activeButton'); + } + +} + +function OnCmykClick() { + let rgb = document.getElementById('RGB'); + let cmyk = document.getElementById('CMYK'); + + if (!document.getElementById('CMYK').classList.contains('activeButton')) { + rgb.classList.remove('activeButton'); + cmyk.classList.add('activeButton'); + } + +} + +function PDFCompilanceFunc(select) { + const PDFCompilanceOption = select.querySelector(`option[value='${select.value}']`) + PDFCompilance = '&PdfCompliance=' + PDFCompilanceOption.value; +} + +function PDFJpegQualityFunc(select) { + const JpegQuality = select.querySelector(`option[value='${select.value}']`) + PDFJpegQuality = '&PDFJpegQuality=' + JpegQuality.value; +} + +function PDFImageOptionFunc(select) { + const ImageOption = select.querySelector(`option[value='${select.value}']`) + if (ImageOption.value == 'None') { + PDFPrintOptimized = false; + PDFImagesOriginalResolution = false; + } + if (ImageOption.value == 'PrintOptimized') { + PDFPrintOptimized = new Boolean(true); + PDFImagesOriginalResolution = false; + } + if (ImageOption.value == 'ImagesOriginalResolution') { + PDFPrintOptimized = false; + PDFImagesOriginalResolution = new Boolean(true); + } + PDFOnImageOption = '&PDFPrintOptimized=' + PDFPrintOptimized + '&PDFImagesOriginalResolution=' + PDFImagesOriginalResolution; +} + +function PDFExport() { + if (document.getElementById('PDFOnEmbeddedFonts').classList.contains('activeButton')) { + PDFOnEmbeddedFonts = new Boolean(true); + } + else { PDFOnEmbeddedFonts = false; }; + + if (document.getElementById('RGB').classList.contains('activeButton')) { + PDFColorSpace = '&PDFColorSpace=' + 'RGB'; + } + else { PDFColorSpace = '&PDFColorSpace=' + 'CMYK'; } + + if (document.getElementById('PDFOnTextInCurves').classList.contains('activeButton')) { + PDFOnTextInCurves = new Boolean(true); + } + else { PDFOnTextInCurves = false; }; + + if (document.getElementById('PDFOnInteractive').classList.contains('activeButton')) { + PDFOnInteractive = new Boolean(true); + } + else { PDFOnInteractive = false; }; + + if (document.getElementById('PDFOnBackground').classList.contains('activeButton')) { + PDFOnBackground = new Boolean(true); + } + else { PDFOnBackground = false; }; + PDFButtons = ('&EmbeddingFonts=' + PDFOnEmbeddedFonts + '&TextInCurves=' + PDFOnTextInCurves + '&InteractiveForms=' + PDFOnInteractive + '&Background=' + PDFOnBackground); + + window.location.href = PdfExport.href + PDFCompilance + PDFColorSpace + PDFJpegQuality + frActions.PageSelector + PDFOnImageOption + PDFButtons; + +} + +AddAction('OnRgbClick', OnRgbClick); +AddAction('OnCmykClick', OnCmykClick); +AddAction('PDFCompilanceFunc', PDFCompilanceFunc); +AddAction('PDFJpegQualityFunc', PDFJpegQualityFunc); +AddAction('PDFImageOptionFunc', PDFImageOptionFunc); +AddAction('PDFExport', PDFExport); + diff --git a/FastReport.Web.Base/wwwroot/js/ExportScripts/pptx-export.js b/FastReport.Web.Base/wwwroot/js/ExportScripts/pptx-export.js new file mode 100644 index 00000000..a45c57e3 --- /dev/null +++ b/FastReport.Web.Base/wwwroot/js/ExportScripts/pptx-export.js @@ -0,0 +1,15 @@ +//PPTXEXPORT// +import { AddAction } from './export-utils.js'; +var PptxImageFormat = '&ImageFormat=Jpeg'; + +function PptxImageFormatFunc(select) { + const PptxImageFormatChage = select.querySelector(`option[value='${select.value}']`) + PptxImageFormat = '&ImageFormat=' + PptxImageFormatChage.value; +} + +function PPTXExport() { + window.location.href = PptxExport.href + PptxImageFormat //+PageSelector; +} + +AddAction('PptxImageFormatFunc', PptxImageFormatFunc); +AddAction('PPTXExport', PPTXExport); diff --git a/FastReport.Web.Base/wwwroot/js/ExportScripts/rtf-export.js b/FastReport.Web.Base/wwwroot/js/ExportScripts/rtf-export.js new file mode 100644 index 00000000..ffa686f0 --- /dev/null +++ b/FastReport.Web.Base/wwwroot/js/ExportScripts/rtf-export.js @@ -0,0 +1,36 @@ +//RTFEXPORT// +import { AddAction } from './export-utils.js'; +var RtfOnRichObject = '&Pictures=false&EmbeddedRTF=false'; +var RtfOnPictures = '&ImageFormat=Jpeg'; +var RtfEmbedded = false; +var RtfPicture = false; + +function RtfOnPicturesChangeFunc(select) { + const RtfOnPicturesChange = select.querySelector(`option[value='${select.value}']`) + if (RtfOnPicturesChange.value != 'None') { + RtfOnPictures = '&ImageFormat=' + RtfOnPicturesChange.value; + } + else{RtfOnPictures = ''} +} +function RtfOnRichObjectChangeFunc(select) { + + const RtfOnRichObjectChange = select.querySelector(`option[value='${select.value}']`) + + if (RtfOnRichObjectChange.value == 'EmbeddedRTF') { + RtfPicture = false; + RtfEmbedded = new Boolean(true); + } + if (RtfOnRichObjectChange.value == 'Picture') { + RtfPicture = new Boolean(true); + RtfEmbedded = false; + } + + RtfOnRichObject = '&Pictures=' + RtfPicture + '&EmbeddedRTF=' + RtfEmbedded; +} +function RTFExport() { + window.location.href = RtfExport.href + RtfOnPictures + RtfOnRichObject + frActions.PageSelector; +} +AddAction('RtfOnPicturesChangeFunc', RtfOnPicturesChangeFunc); +AddAction('RtfOnRichObjectChangeFunc', RtfOnRichObjectChangeFunc); +AddAction('RTFExport', RTFExport); + diff --git a/FastReport.Web.Base/wwwroot/js/ExportScripts/svg-export.js b/FastReport.Web.Base/wwwroot/js/ExportScripts/svg-export.js new file mode 100644 index 00000000..cc892c6c --- /dev/null +++ b/FastReport.Web.Base/wwwroot/js/ExportScripts/svg-export.js @@ -0,0 +1,30 @@ +//SVGEXPORT +import { AddAction } from './export-utils.js'; +var SVGImageFormat = '&ImageFormat=Jpeg'; +var SVGEmbedPictures = false; +var SVGHasMultiplyFiles = false; +var SVGButtons; + +function SVGImageFormatFunc(select) { + const ImageFormatOption = select.querySelector(`option[value='${select.value}']`) + if (ImageFormatOption.value == 'None') { ImageFormatOption.value = ''; } + else { SVGImageFormat = '&ImageFormat=' + ImageFormatOption.value; } +} +function SVGExport() { + if (document.getElementById('SVGEmbedPictures').classList.contains('activeButton')) { + SVGEmbedPictures = new Boolean(true); + } + else { SVGEmbedPictures = false; }; + + if (document.getElementById('SVGOnHasMultipleFilesClick').classList.contains('activeButton')) { + SVGHasMultiplyFiles = new Boolean(true); + } + else { SVGHasMultiplyFiles = false; }; + + SVGButtons = ('&EmbedPictures=' + SVGEmbedPictures + '&HasMultipleFiles=' + SVGHasMultiplyFiles); + + window.location.href = SvgExport.href + SVGImageFormat + SVGButtons + frActions.PageSelector; +} + +AddAction('SVGImageFormatFunc', SVGImageFormatFunc); +AddAction('SVGExport', SVGExport); diff --git a/FastReport.Web.Base/wwwroot/js/ExportScripts/xlsx-export.js b/FastReport.Web.Base/wwwroot/js/ExportScripts/xlsx-export.js new file mode 100644 index 00000000..d3e5b9a2 --- /dev/null +++ b/FastReport.Web.Base/wwwroot/js/ExportScripts/xlsx-export.js @@ -0,0 +1,56 @@ +//XLSXEXPORT// +import { AddAction } from './export-utils.js'; +var XlsxButtons; +var XlsxFontScaling = '&FontScale=1'; +var XlsxOnPrintFit = '&PrintFit=NoScaling'; +var XlsxPageBreaks = false; +var XlsxDataOnly = false; +var XlsxWysiwyg = false; +var XlsxSeamless = false; +var XlsxPrintOptimized = false; +var XlsxSplitPages = false; + +function XlsxFontScalingFunc(select){ + const XlsxFontScalingChange = select.querySelector(`option[value='${select.value}']`) + XlsxFontScaling = '&FontScale=' + XlsxFontScalingChange.value.replace('.', ','); +} + +function XlsxOnPrintFitChangeFunc(select) { + const XlsxOnPrintFitChange = select.querySelector(`option[value='${select.value}']`) + XlsxOnPrintFit = '&PrintFit=' + XlsxOnPrintFitChange.value; + } + +function XLSXExport() { + if (document.getElementById('XlsxWysiwyg').classList.contains('activeButton')) { + XlsxWysiwyg = new Boolean(true); + } + else { XlsxWysiwyg = false; }; + + if (document.getElementById('XlsxPageBreaks').classList.contains('activeButton')) { + XlsxPageBreaks = new Boolean(true); + } + else { XlsxPageBreaks = false; }; + if (document.getElementById('XlsxDataOnly').classList.contains('activeButton')) { + XlsxDataOnly = new Boolean(true); + } + else { XlsxSeamless = false; }; + if (document.getElementById('XlsxSeamless').classList.contains('activeButton')) { + XlsxSeamless = new Boolean(true); + } + else { XlsxPrintOptimized = false; }; + if (document.getElementById('XlsxPrintOptimized').classList.contains('activeButton')) { + XlsxPrintOptimized = new Boolean(true); + } + else { XlsxPrintOptimized = false; }; + if (document.getElementById('XlsxSplitPages').classList.contains('activeButton')) { + XlsxSplitPages = new Boolean(true); + } + else { XlsxSplitPages = false; }; + + XlsxButtons = (XlsxOnPrintFit + '&Wysiwyg=' + XlsxWysiwyg + '&PrintOptimized=' + XlsxPrintOptimized + '&DataOnly=' + XlsxDataOnly + '&Seamless=' + XlsxSeamless + '&SplitPages=' + XlsxSplitPages + '&PageBreaks=' + XlsxPageBreaks); + window.location.href = XlsxExport.href + XlsxButtons + frActions.PageSelector + XlsxFontScaling; +} + +AddAction('XlsxFontScalingFunc', XlsxFontScalingFunc); +AddAction('XlsxOnPrintFitChangeFunc', XlsxOnPrintFitChangeFunc); +AddAction('XLSXExport', XLSXExport); diff --git a/FastReport.Web.Base/wwwroot/js/ExportScripts/xml-export.js b/FastReport.Web.Base/wwwroot/js/ExportScripts/xml-export.js new file mode 100644 index 00000000..2756d31a --- /dev/null +++ b/FastReport.Web.Base/wwwroot/js/ExportScripts/xml-export.js @@ -0,0 +1,27 @@ +//XMLEXPORT// +import { AddAction } from './export-utils.js'; +var XmlButtons; +var XmlWysiwyg = false; +var XmlPageBreaks = false; +var XmlDataOnly = false; + +function XMLExport() { + if (document.getElementById('XmlWysiwyg').classList.contains('activeButton')) { + XmlWysiwyg = new Boolean(true); + } + else { XmlWysiwyg = false; }; + + if (document.getElementById('XmlPageBreaks').classList.contains('activeButton')) { + XmlPageBreaks = new Boolean(true); + } + else { XmlPageBreaks = false; }; + + if (document.getElementById('XmlDataOnly').classList.contains('activeButton')) { + XmlDataOnly = new Boolean(true); + } + else { XmlDataOnly = false; }; + XmlButtons = ('&Wysiwyg=' + XmlWysiwyg + '&PageBreaks=' + XmlPageBreaks + '&DataOnly=' + XmlDataOnly); + window.location.href = XmlExport.href + XmlButtons + frActions.PageSelector; +} + +AddAction('XMLExport', XMLExport); diff --git a/FastReport.Web.Base/wwwroot/js/httpclient.js b/FastReport.Web.Base/wwwroot/js/httpclient.js new file mode 100644 index 00000000..2fb3b22a --- /dev/null +++ b/FastReport.Web.Base/wwwroot/js/httpclient.js @@ -0,0 +1,66 @@ + +export class HttpClient { + _fetchQueue = [] + + fetch(options) { + var method = options.method; + var url = options.url; + var form = options.form; + var onSuccess = options.onSuccess; + var onError = options.onError; + var onSend = options.onSend; + var onFinally = options.onFinally; + + if (options.method == `POST` && options.form == null) { + form = {}; + } + + var that = this; + var xhr = new XMLHttpRequest(); + xhr.__form = form; + xhr.__onSend = onSend; + xhr.open(method, url, true); + xhr.onreadystatechange = function () { + if (xhr.readyState != 4) + return; + + if (xhr.status != 200) { + if (typeof onError === `function`) { + onError(xhr); + } + } else { + if (typeof onSuccess === `function`) { + onSuccess(xhr); + } + } + + if (typeof onFinally === `function`) { + onFinally(xhr); + } + + that._nextFetch(); + }; + + this._fetchQueue.push(xhr); + + if (this._fetchQueue.length == 1) { + var f = this._fetchQueue[0]; + if (typeof f.__onSend === `function`) { + f.__onSend(f); + } + f.send(f.__form); + } + }; + + _nextFetch() { + this._fetchQueue.shift(); + + if (this._fetchQueue.length) { + var f = this._fetchQueue[0]; + if (typeof f.__onSend === `function`) { + f.__onSend(f); + } + f.send(f.__form); + } + }; +} \ No newline at end of file diff --git a/FastReport.Web.Base/wwwroot/js/main-scripts.js b/FastReport.Web.Base/wwwroot/js/main-scripts.js new file mode 100644 index 00000000..58b974ac --- /dev/null +++ b/FastReport.Web.Base/wwwroot/js/main-scripts.js @@ -0,0 +1,639 @@ +import '__EXPORT_SETTINGS__'; +import { createLisners, IsValid } from './ExportScripts/export-utils.js'; +import { HttpClient } from './httpclient.js'; +import { Searcher as search } from './searcher.js'; + +class WebReport { + ID = ``; + route_base_path = ``; + Outline; + Searcher; + client; + observer; + + constructor(props) { + this.ID = props.ID; + this.route_base_path = props.RouteBasePath; + this.Outline = props.Outline; + this.Searcher = new search(this); + search.ScrollOffsetTop = props.SearchScroolOffset; + this.client = new HttpClient(); + }; + + static Init() { + var webReports = document.getElementsByClassName('webreport-script'); + for (var i = 0; i < webReports.length; i++) { + var props = JSON.parse(webReports[i].dataset.config); + var report = new WebReport(props); + if (!window.Webreports || !window.Webreports.has(props.ID)) { + window.Webreports = new Map(); + report.doc = document; + window.Webreports.set(props.ID, report); + report.load(); + } + } + } + + load() { + this._reload(); + } + + initialize() { + var calendars = document.getElementsByClassName('fr-monthcalendar'); + for (var i = 0; i < calendars.length; i++) { + var props = JSON.parse(calendars[i].dataset.props); + var elem = document.getElementById(props.ID); + $(elem).datepicker(); + $(elem).datepicker("option", "dateFormat", props.DataFormat); + $(elem).datepicker("setDate", props.SelectedDate, props.DataFormat); + } + + this.initEventLiseners(); + this.getExportSettings(); + if (window.Split && this.Outline) + this.outline(); + if ('MutationObserver' in window) { + + const callback = (mutationList) => { + var container = this._findModalContainer(); + for (const mutation of mutationList) { + if (mutation.type == "childList" && mutation.target == container) { + if (!IsValid()) + return; + createLisners(); + this.initEventLiseners(true); + } + } + }; + + this.observer = new MutationObserver(callback); + + const targetNode = document.querySelector(`#modalcontainers`); + if (targetNode) { + this.observer.observe(targetNode, { + childList: true, + subtree: true, + attributes: true, + characterData: true, + attributeOldValue: true, + characterDataOldValue: true + }); + } + } + } + + initEventLiseners(inModalContainer) { + // Create events from attached data to element + var body = inModalContainer ? this._findModalContainer() : this._findContainer(); + const elemWithEvent = body.querySelectorAll('[data-event]'); + const contextMap = new Map(); + contextMap.set(`window.Webreports.get('${this.ID}')`, this); + contextMap.set(`window.Webreports.get('${this.ID}').Searcher`, this.Searcher); + contextMap.set(`frActions`, window.frActions); + contextMap.set(`window`, window); + + for (var i = 0; i < elemWithEvent.length; i++) { + let elem = elemWithEvent[i]; + let event = JSON.parse(elem.dataset.event); + elem.addEventListener(event.Event, () => { + if (contextMap.has(event.TargetObj)) { + var params = event.Params.map(param => { + return this.convertToObject(param, elem, contextMap); + }); + var obj = contextMap.get(event.TargetObj); + obj[event.Func](...params); + } + else { + console.log(`Object ${event.TargetObj} not found`); + } + }) + } + }; + + convertToObject(param, elem, contextMap) { + param = param.trim(); + if (param === 'true') return true; + if (param === 'false') return false; + if (param === 'null') return null; + if (param.includes('this')) { + let concatedStr = param.split('+').map(par => { + par = par.trim(); + if (par === 'this.value.replace(/\\r?\\n/g, \'\\r\\n\')') return elem.value.replace(/\r?\n/g, '\r\n'); + if (par === 'this.value') return elem.value; + if (par === 'this.checked') return elem.checked; + if (par === 'this.selectedIndex') return elem.selectedIndex; + if (par === 'this') return elem; + return par.replace(new RegExp('^[\']+|[\']+$', 'g'), ''); + }); + if (concatedStr.length > 1) + return concatedStr.join(''); + return concatedStr[0]; + } + if (contextMap.has(param)) return contextMap.get(param); + if (!isNaN(param) && param !== '') return Number(param); + return param.replace(new RegExp('^[\']+|[\']+$', 'g'), ''); + } + + outline() { + var sizes = sessionStorage.getItem(`fastreport-outline-split-sizes`); + + if (sizes) { + sizes = JSON.parse(sizes); + } else { + sizes = [25, 75]; + } + + var that = this; + var split = window.Split([`.fr-outline`, `.fr-report`], { + sizes: sizes, + minSize: [0, 50], + snapOffset: 20, + onDragEnd() { + sessionStorage.setItem(`fastreport-outline-split-sizes`, JSON.stringify(split.getSizes())); + }, + elementStyle(dimension, size, gutterSize) { + return { + "flex-basis": `calc(` + size + `% - ` + gutterSize + `px)` + } + }, + gutterStyle(dimension, gutterSize) { + return { + "flex-basis": gutterSize + `px` + } + }, + gutter(index, direction) { + var gutter = document.createElement(`div`); + gutter.className = `fr-gutter fr-gutter-` + direction; + return gutter; + } + }); + + var tree = sessionStorage.getItem(`fastreport-outline-tree`); + if (tree) { + tree = JSON.parse(tree); + var that = this; + var container = this._findContainer(); + Object.keys(tree).forEach(function (key) { + var caret = container.querySelector(`[data-fr-outline-node-id="` + key + `"]`); + if (caret) { + that.outlineOpenNode(caret, true); + } + }); + } + }; + + outlineOpenNode(caret, skipTreeStorage) { + caret.parentNode.parentNode.getElementsByClassName(`fr-outline-children`)[0].style.display = ``; + caret.parentNode.parentNode.getElementsByClassName(`fr-js-outline-open-node`)[0].style.display = `none`; + caret.parentNode.parentNode.getElementsByClassName(`fr-js-outline-close-node`)[0].style.display = ``; + + if (skipTreeStorage === true) { + return; + } + + var tree = sessionStorage.getItem(`fastreport-outline-tree`); + if (tree) { + tree = JSON.parse(tree); + } else { + tree = {}; + } + + tree[caret.getAttribute(`data-fr-outline-node-id`)] = true; + sessionStorage.setItem(`fastreport-outline-tree`, JSON.stringify(tree)); + }; + + outlineCloseNode(caret) { + caret.parentNode.parentNode.getElementsByClassName(`fr-outline-children`)[0].style.display = `none`; + caret.parentNode.parentNode.getElementsByClassName(`fr-js-outline-open-node`)[0].style.display = ``; + caret.parentNode.parentNode.getElementsByClassName(`fr-js-outline-close-node`)[0].style.display = `none`; + + var tree = sessionStorage.getItem(`fastreport-outline-tree`); + if (tree) { + tree = JSON.parse(tree); + } else { + tree = {}; + } + + delete tree[caret.getAttribute(`data-fr-outline-node-id`)]; + sessionStorage.setItem(`fastreport-outline-tree`, JSON.stringify(tree)); + }; + + outlineGoto(page, offset, singelPage) { + if (singelPage) { + const rect = document.getElementById("PageN" + page).getBoundingClientRect(); + var topOfElement = window.scrollY + rect.top + offset; + window.scroll({ top: topOfElement, behavior: `smooth` }); + } + else { + var that = this; + this.goto(page, { + onSuccess(xhr) { + that.outlineGoto(1, offset, true); + } + }); + } + }; + + refresh() { + var that = this; + var searchForm = document.getElementById(`$fr-toolbar-search-form`); + var needRestoreSearch = false; + var searchText = sessionStorage.getItem(`fastreport-search-text`); + var matchCase = sessionStorage.getItem(`fastreport-search-match-case`) === `true`; + var wholeWord = sessionStorage.getItem(`fastreport-search-whole-word`) === `true`; + + if (searchForm) { + needRestoreSearch = searchForm.classList.contains(`open`); + this.Searcher.saveSearchFormState(); + } + this._reloadBase(`&forceRefresh=yes`, null, { + onSuccess(xhr) { + if (needRestoreSearch) { + that.Searcher.restoreSearchFormState(false, true); + that.Searcher.findNext( + sessionStorage.getItem(`fastreport-search-index`), + searchText, + matchCase, + wholeWord, + false + ); + } + } + }); + }; + + zoom(value) { + var that = this; + var searchForm = document.getElementById(`fr-toolbar-search-form`); + var needRestoreSearch = false; + var searchText = sessionStorage.getItem(`fastreport-search-text`); + var matchCase = sessionStorage.getItem(`fastreport-search-match-case`) === `true`; + var wholeWord = sessionStorage.getItem(`fastreport-search-whole-word`) === `true`; + + if (searchForm) { + needRestoreSearch = searchForm.classList.contains(`open`); + this.Searcher.saveSearchFormState(); + } + this._closeDropdowns(); + this._reloadBase(`&skipPrepare=yes&zoom=` + value, null, { + onSuccess(xhr) { + if (needRestoreSearch) { + that.Searcher.restoreSearchFormState(false, true); + that.Searcher.findNext( + sessionStorage.getItem(`fastreport-search-index`), + searchText, + matchCase, + wholeWord, + false + ); + } + } + }); + }; + + goto(page, options) { + this._reload(`&skipPrepare=yes&goto=` + page, null, options); + }; + + click(el, kind, value) { + var that = this; + + if (kind == `text_edit`) { + if (that._win) { + that._win.close(); + } + that._win = this._popup(`${this.route_base_path}/preview.textEditForm?reportId=${this.ID}&click=` + value, `Text edit`, 400, 200); + that._win.onmessage = function (e) { + if (e.data == `submit`) { + var newText = that._win.document.querySelector(`textarea`).value; + var form = new FormData(); + form.append(`text`, newText); + that._reload(`&skipPrepare=yes&` + kind + `=` + value, form); + that._win.close(); + } + }; + return; + } + + this._reload(`&skipPrepare=yes&` + kind + `=` + value); + }; + + customMethodInvoke(elementId, inputValue) { + var that = this; + var body = this._findBody(); + var container = this._findContainer(); + + this.client.fetch({ + method: `POST`, + url: `${that.route_base_path}/preview.toolbarElementClick?reportId=${that.ID}&elementId=` + elementId + `&inputValue=` + inputValue, + onSend() { + that._activateSpinner(); + }, + onSuccess(xhr) { + container.outerHTML = xhr.responseText; + that.initialize(); + }, + onError(xhr) { + that._placeError(xhr, body); + that._deactivateSpinner(); + } + }); + }; + + + settab(tab) { + this._reload(`&skipPrepare=yes&settab=` + tab); + }; + + closetab(tab) { + this._reload(`&skipPrepare=yes&closetab=` + tab); + }; + + _reload(params, form, options = {}) { + var that = this; + var onSuccess = options.onSuccess; + var searchForm = document.getElementById(`fr-toolbar-search-form`); + var needRestoreSearch = false; + + if (searchForm) { + needRestoreSearch = searchForm.classList.contains(`open`); + this.Searcher.saveSearchFormState(); + } + + this._reloadBase(params, form, { + onSuccess(xhr) { + if (typeof onSuccess === `function`) { + onSuccess(xhr); + } + if (needRestoreSearch) + that.Searcher.restoreSearchFormState(true, true); + } + }); + }; + + _reloadBase(params, form, options) { + var that = this; + var body = this._findBody(); + var container = this._findContainer(); + var onSuccess = options.onSuccess; + var onError = options.onError; + var onSend = options.onSend; + var onFinally = options.onFinally; + this.client.fetch({ + method: `POST`, + url: `${this.route_base_path}/preview.getReport?reportId=${this.ID}&renderBody=yes${(params || ``)}`, + form: form, + onSend() { + that._activateSpinner(); + if (typeof onSend === `function`) { + onSend(xhr); + } + }, + onSuccess(xhr) { + container.outerHTML = xhr.responseText; + that.initialize(); + if (typeof onSuccess === `function`) { + onSuccess(xhr); + } + }, + onError(xhr) { + that._placeError(xhr, body); + that._deactivateSpinner(); + if (typeof onError === `function`) { + onError(xhr); + } + }, + onFinally() { + if (typeof onFinally === `function`) { + onFinally(xhr); + } + } + }); + }; + + _silentReload(params, form) { + var that = this; + var body = this._findBody(); + var container = this._findContainer(); + var searchForm = document.getElementById(`fr-toolbar-search-form`); + var needRestoreSearch = false; + var searchText = sessionStorage.getItem(`fastreport-search-text`); + var matchCase = sessionStorage.getItem(`fastreport-search-match-case`) === `true`; + var wholeWord = sessionStorage.getItem(`fastreport-search-whole-word`) === `true`; + + if (searchForm) { + needRestoreSearch = searchForm.classList.contains(`open`); + this.Searcher.saveSearchFormState(); + } + + this.client.fetch({ + method: `POST`, + url: `${this.route_base_path}/preview.getReport?reportId=${this.ID}&renderBody=yes` + (params || ``), + form: form, + onSuccess(xhr) { + container.outerHTML = xhr.responseText; + that.initialize(); + if (needRestoreSearch) { + that.Searcher.restoreSearchFormState(false, true); + that.Searcher.findNext( + sessionStorage.getItem(`fastreport-search-index`), + searchText, + matchCase, + wholeWord, + false + ); + } + }, + onError(xhr) { + that._placeError(xhr, body); + }, + }); + }; + + + _dialog(params, form) { + this.client.fetch({ + method: `POST`, + url: `${this.route_base_path}/dialog?reportId=${this.ID}` + (params || ``), + form: form + }); + }; + + showEmailExportModal() { + var modalcontainer = this._findModalContainer(); + const emailExportLink = document.getElementById(`emailexport`); + const buttons = document.querySelectorAll(`.fr-settings-btn`); + const Overlay = document.querySelector(`.modalcontainer-overlay`); + var that = this; + + this.client.fetch({ + method: `POST`, + url: `${this.route_base_path}/exportsettings.getSettings?reportId=${this.ID}&format=email`, + onSuccess(xhr) { + modalcontainer.innerHTML = xhr.responseText; + that._execModalScripts(); + document.querySelector(`[data-target=email]`).classList.add(`modalcontainer--visible`); + Overlay.classList.add(`modalcontainer-overlay--visible`); + }, + }) + }; + + showPopup(message, isSuccess) { + var popup = document.createElement("div"); + popup.className = "fr-notification"; + if (isSuccess) { + popup.classList.add("positive"); + } else { + popup.classList.add("negative"); + } + + var content = document.createElement("div"); + content.className = "fr-notification-content"; + + var image = document.createElement("img"); + image.src = "/_fr/resources.getResource?resourceName=notification-bell.svg&contentType=image%2Fsvg%2Bxml"; + + var text = document.createElement("div"); + text.innerText = message; + + content.appendChild(image); + content.appendChild(text); + popup.appendChild(content); + document.body.appendChild(popup); + + setTimeout(function () { + popup.style.opacity = "0"; + setTimeout(function () { + popup.remove(); + }, 500); + }, 2000) + }; + + getExportSettings() { + this._getExportSettings(); + }; + + _getExportSettings(params, form) { + var modalcontainer = this._findModalContainer(); + const buttons = document.querySelectorAll(`.fr-settings-btn`); + const Overlay = document.querySelector(`.modalcontainer-overlay`); + var fileformat; + var that = this; + buttons.forEach((el) => { + el.addEventListener(`click`, (e) => { + fileformat = e.currentTarget.getAttribute(`data-path`); + + this.client.fetch({ + method: `POST`, + url: `${that.route_base_path}/exportsettings.getSettings?reportId=${that.ID}&format=` + fileformat + (params || ``), + form: form, + onSuccess(xhr) { + modalcontainer.innerHTML = xhr.responseText; + that._execModalScripts(); + document.querySelector(`[data-target=${fileformat}]`).classList.add(`modalcontainer--visible`); + Overlay.classList.add(`modalcontainer-overlay--visible`); + }, + }); + }) + }); + }; + + _execModalScripts() { + var includeContainer = this._findModalContainer(); + var scripts = includeContainer.getElementsByTagName(`script`); + for (var i = 0; i < scripts.length; i++) { + for (var j = 0; j < scripts[i].attributes.length; j++) { + if (scripts[i].attributes[j].name in HTMLScriptElement.prototype && scripts[i].attributes[j].name == "src") { + try { + if (import.meta.hot) { + import.meta.hot.invalidate(); + } + + const module = import(scripts[i].attributes[j].value.replace("_content/FastReport.Web/js/", "")); + } catch (error) { + console.error('Error on reloading:', error); + } + } + } + } + }; + + _placeError(xhr, body) { + body.innerHTML = `
Error
` + xhr.status + ` - ` + xhr.statusText + `
` + xhr.responseText + `
`; + }; + + _activateSpinner() { + document.getElementsByClassName(`fr-report-spinner`)[0].style.display = ``; + }; + + _deactivateSpinner() { + document.getElementsByClassName(`fr-report-spinner`)[0].style.display = `none`; + }; + + _findContainer() { + return document.getElementsByClassName(`fr-container`)[0]; + }; + + _findModalContainer() { + return document.getElementsByClassName(`content-modalcontainer`)[0]; + }; + + _findBody() { + return document.getElementsByClassName(`fr-report-body`)[0]; + }; + + _closeDropdowns() { + var dropdowns = document.getElementsByClassName(`fr-dropdown-content`); + + var func = function (dd) { + setTimeout(function () { + dd.style[`display`] = ``; + }, 100); + } + + for (var i = 0; i < dropdowns.length; i++) { + var dd = dropdowns[i]; + dd.style[`display`] = `none`; + func(dd); + } + }; + + _popup(url, title, w, h) { + // Fixes dual-screen position Most browsers Firefox + var dualScreenLeft = window.screenLeft != undefined ? window.screenLeft : window.screenX; + var dualScreenTop = window.screenTop != undefined ? window.screenTop : window.screenY; + + var width = window.innerWidth ? window.innerWidth : document.documentElement.clientWidth ? document.documentElement.clientWidth : screen.width; + var height = window.innerHeight ? window.innerHeight : document.documentElement.clientHeight ? document.documentElement.clientHeight : screen.height; + + var left = ((width / 2) - (w / 2)) + dualScreenLeft; + var top = ((height / 2) - (h / 2)) + dualScreenTop; + + var params = `menubar=0, toolbar=0, location=0, status=0, resizable=1, scrollbars=1`; + var newWindow = window.open(url, title, params + `, width=` + w + `, height=` + h + `, top=` + top + `, left=` + left); + + if (newWindow.focus) { + newWindow.focus(); + } + + return newWindow; + } +} + +if (window.top !== window.self) { + const observer = new MutationObserver((mutations) => { + if (document.readyState === 'complete') { + var webReports = document.getElementsByClassName('webreport-script'); + if (webReports.length == 0) + window.Webreports = new Map(); + WebReport.Init(); + } + }); + + observer.observe(document.body, { + childList: true, + subtree: true, + }); +} + +WebReport.Init(); diff --git a/FastReport.Web.Base/wwwroot/js/printscript.js b/FastReport.Web.Base/wwwroot/js/printscript.js new file mode 100644 index 00000000..9d959574 --- /dev/null +++ b/FastReport.Web.Base/wwwroot/js/printscript.js @@ -0,0 +1,3 @@ +parent.focus(); +parent.print(); +window.addEventListener('afterprint', function (event) { window.close(); }) \ No newline at end of file diff --git a/FastReport.Web.Base/wwwroot/js/searcher.js b/FastReport.Web.Base/wwwroot/js/searcher.js new file mode 100644 index 00000000..8dfc1f53 --- /dev/null +++ b/FastReport.Web.Base/wwwroot/js/searcher.js @@ -0,0 +1,272 @@ +export class Searcher { + static ScrollOffsetTop; + Webreport; + + constructor(webreport) { + this.Webreport = webreport; + } + + toggleSearchForm() { + var form = document.getElementById(`fr-toolbar-search-form`); + form.classList.toggle(`open`); + if (!form.classList.contains(`open`)) { + var searchText = sessionStorage.getItem(`fastreport-search-text`); + var matchCase = sessionStorage.getItem(`fastreport-search-match-case`) === `true`; + var wholeWord = sessionStorage.getItem(`fastreport-search-whole-word`) === `true`; + this.findNext( + sessionStorage.getItem(`fastreport-search-index`), + searchText, + matchCase, + wholeWord, + true + ); + } + }; + + saveSearchFormState() { + sessionStorage.setItem(`fastreport-search-text-state`, document.getElementById(`fr-search-text`).value); + sessionStorage.setItem(`fastreport-search-match-case-state`, document.getElementById(`fr-match-case`).checked); + sessionStorage.setItem(`fastreport-search-whole-word-state`, document.getElementById(`fr-whole-word`).checked); + }; + + restoreSearchFormState(resetIndex = false, openAfter = false) { + document.getElementById(`fr-search-text`).value = sessionStorage.getItem(`fastreport-search-text-state`); + document.getElementById(`fr-match-case`).checked = sessionStorage.getItem(`fastreport-search-match-case-state`) === `true`; + document.getElementById(`fr-whole-word`).checked = sessionStorage.getItem(`fastreport-search-whole-word-state`) === `true`; + this.onEnterSearchText(); + if (resetIndex) + sessionStorage.setItem(`fastreport-search-text`, ``); + if (openAfter) + document.getElementById(`fr-toolbar-search-form`).classList.toggle(`open`); + }; + + onEnterSearchText() { + if (document.getElementById(`fr-search-text`).value == ``) { + document.getElementById(`fr-search-prev`).setAttribute(`disabled`, `disabled`); + document.getElementById(`fr-search-next`).setAttribute(`disabled`, `disabled`); + document.getElementById(`fr-match-case`).setAttribute(`disabled`, `disabled`); + document.getElementById(`fr-whole-word`).setAttribute(`disabled`, `disabled`); + document.getElementById(`clear-searchbox`).setAttribute(`hidden`, `hidden`); + } + else { + document.getElementById(`fr-search-prev`).removeAttribute(`disabled`); + document.getElementById(`fr-search-next`).removeAttribute(`disabled`); + document.getElementById(`fr-match-case`).removeAttribute(`disabled`); + document.getElementById(`fr-whole-word`).removeAttribute(`disabled`); + document.getElementById(`clear-searchbox`).removeAttribute(`hidden`); + } + }; + + clearSearchText() { + document.getElementById(`fr-search-text`).value = ``; + this.onEnterSearchText(); + }; + + getSearchRanges(text, matchCase, wholeWord) { + var curScrollY = window.scrollY; + var curScrollX = window.scrollX; + var sel = window.getSelection(); + var ranges = [] + var container = document.getElementsByClassName(`fr-report-body`)[0]; + // find all occurrences in a page + while (window.find(text, matchCase, false, false, wholeWord, false, false)) { + // filter out search results outside of a specific element + if (container.contains(sel.anchorNode)) { + ranges.push(sel.getRangeAt(sel.rangeCount - 1)); + } + } + window.scrollTo(curScrollX, curScrollY); + return ranges + }; + + findNext(index, text, matchCase, wholeWord, removeHighlight) { + var container = this.Webreport._findContainer(); + // selection object + var sel = window.getSelection(); + + sel.collapse(container, 0) + var ranges = this.getSearchRanges(text, matchCase, wholeWord); + sel.collapse(container, 0); + + if (ranges.length == 0) { + return false; + } + else if ((index < ranges.length && index >= 0) || removeHighlight) { + if (!removeHighlight) { + ranges.sort((a, b) => { + return a.startContainer.parentElement.getBoundingClientRect().top - b.startContainer.parentElement.getBoundingClientRect().top + }); + ranges = [ranges[index]]; + } + else { + ranges = ranges.filter((r) => r.startContainer.parentElement.classList.contains(`search-highlight`)); + } + + for (var i = 0; i < ranges.length; i++) { + var range = ranges[i] + if (range.startContainer == range.endContainer) { + // Range includes just one node + if (removeHighlight) + this.clearHighlight(range) + else + this.highlight(range) + return true + } else { + // More complex case: range includes multiple nodes + // Get all the text nodes in the range + var textNodes = this.getTextNodesInRange( + range.commonAncestorContainer, + range.startContainer, + range.endContainer) + + var startOffset = range.startOffset + var endOffset = range.endOffset + for (var j = 0; j < textNodes.length; j++) { + var node = textNodes[j] + range.setStart(node, j == 0 ? startOffset : 0) + range.setEnd(node, j == textNodes.length - 1 ? + endOffset : node.nodeValue.length) + if (removeHighlight) + this.clearHighlight(range); + else + this.highlight(range); + } + } + return true; + } + + } + return false; + }; + + search(backward, searchNotFoundText) { + var searchText = document.getElementById(`fr-search-text`).value; + var lastSearchText = sessionStorage.getItem(`fastreport-search-text`); + var index = sessionStorage.getItem(`fastreport-search-index`); + var matchCase = document.getElementById(`fr-match-case`).checked; + var wholeWord = document.getElementById(`fr-whole-word`).checked; + document.getElementById(`fr-searchform-text-info`).innerText = ``; + if (!index) + index = -1 + + if (lastSearchText) { + this.findNext(index, lastSearchText, sessionStorage.getItem(`fastreport-search-match-case`) === `true`, sessionStorage.getItem(`fastreport-search-whole-word`) === `true`, true) + } + + if (backward) + index-- + else + index++ + + if (lastSearchText != searchText) + index = 0; + + if (!this.findNext(index, searchText, matchCase, wholeWord, false)) { + var that = this; + var container = this.Webreport._findContainer(); + // search on next pages + this.Webreport.client.fetch({ + method: `POST`, + url: `${this.Webreport.route_base_path}/preview.getReport?reportId=${this.Webreport.ID}&skipPrepare=yes&renderBody=yes&backward=` + backward + `&searchText=` + searchText + `&matchCase=` + matchCase + `&wholeWord=` + wholeWord, + onSend() { + that.Webreport._activateSpinner(); + }, + onSuccess(xhr) { + container.outerHTML = xhr.responseText; + that.Webreport.initialize(); + // get new container + container = that.Webreport._findContainer(); + var sel = window.getSelection(); + sel.collapse(container, 0); + index = backward ? that.getSearchRanges(searchText, matchCase, wholeWord).length - 1 : 0; + sessionStorage.setItem(`fastreport-search-index`, index); + document.getElementById(`fr-toolbar-search-form`).classList.toggle(`open`); + document.getElementById(`fr-search-text`).value = searchText; + that.onEnterSearchText(); + if (!that.findNext(index, searchText, matchCase, wholeWord, false)) + document.getElementById(`fr-searchform-text-info`).innerText = searchNotFoundText; + }, + onError(xhr) { + that.Webreport._deactivateSpinner(); + index = backward ? 0 : index - 1; + sessionStorage.setItem(`fastreport-search-index`, index); + that.findNext(index, searchText, matchCase, wholeWord, false) + document.getElementById(`fr-searchform-text-info`).innerText = searchNotFoundText; + } + }); + } + sessionStorage.setItem(`fastreport-search-index`, index); + sessionStorage.setItem(`fastreport-search-text`, searchText); + sessionStorage.setItem(`fastreport-search-match-case`, matchCase); + sessionStorage.setItem(`fastreport-search-whole-word`, wholeWord); + }; + + highlight(range) { + var newNode = document.createElement(`span`); + newNode.className = `search-highlight`; + range.surroundContents(newNode); + const rect = newNode.getBoundingClientRect(); + const vWidth = (window.innerWidth || document.documentElement.clientWidth) - rect.width; + const vHeight = (window.innerHeight || document.documentElement.clientHeight) - rect.height; + var topOfElement = window.scrollY; + var leftOfElement = window.screenX; + + if (rect.bottom < rect.height || rect.top > vHeight) + topOfElement = topOfElement + rect.top - Searcher.ScrollOffsetTop; + if (rect.right < rect.width || rect.left > vWidth) + leftOfElement = leftOfElement + rect.left; + window.scroll({ top: topOfElement, left: leftOfElement, behavior: 'smooth' }); + }; + + clearHighlight(range) { + var selection = document.getSelection() + selection.removeAllRanges() + selection.addRange(range) + const selParent = selection.anchorNode?.parentElement; + const selectedElem = selParent?.nodeType == 1 && selParent?.children.length < 2 && selParent; + if (selectedElem.tagName === `SPAN` && selectedElem.classList.contains(`search-highlight`)) { + selectedElem.previousSibling.nodeValue += selectedElem.innerText; + selectedElem.previousSibling.nodeValue += selectedElem.nextSibling.nodeValue; + selectedElem.parentNode.removeChild(selectedElem.nextSibling); + selectedElem.parentNode.removeChild(selectedElem); + } + }; + + getTextNodesInRange(rootNode, firstNode, lastNode) { + var nodes = [] + var startNode = null, endNode = lastNode + var walker = document.createTreeWalker( + rootNode, + // search for text nodes + NodeFilter.SHOW_TEXT, + // Logic to determine whether to accept, reject or skip node. + // In this.Webreport case, only accept nodes that are between + // firstNode and lastNode + { + acceptNode(node) { + if (!startNode) { + if (firstNode == node) { + startNode = node + return NodeFilter.FILTER_ACCEPT + } + return NodeFilter.FILTER_REJECT + } + + if (endNode) { + if (lastNode == node) { + endNode = null + } + return NodeFilter.FILTER_ACCEPT + } + + return NodeFilter.FILTER_REJECT + } + }, + false) + + while (walker.nextNode()) { + nodes.push(walker.currentNode) + } + return nodes + }; +} diff --git a/FastReport.Core.Web/Resources/split.min.js b/FastReport.Web.Base/wwwroot/js/split.js similarity index 100% rename from FastReport.Core.Web/Resources/split.min.js rename to FastReport.Web.Base/wwwroot/js/split.js diff --git a/FastReport.Web.Base/wwwroot/styles.css b/FastReport.Web.Base/wwwroot/styles.css new file mode 100644 index 00000000..6e7a22a3 --- /dev/null +++ b/FastReport.Web.Base/wwwroot/styles.css @@ -0,0 +1,1142 @@ +/********** + MAIN +***********/ +.fr-container { + width: var(--wbreport-width); + height: var(--wbreport-height); + background-color: white; + display: var(--wbreport-inline-style); + flex-direction: var(--toolbar-vertical-pos); + position: relative; + align-items: var( --toolbar-content-align); +} + +.fr-container * { + box-sizing: content-box; + -moz-box-sizing: content-box; +} + +.fr-report-body { + display: flex; + overflow: hidden; + width: 100%; + height: 100%; + margin-top: 20px; +} + +.fr-report { + overflow: auto; + width: 100%; + display: flex; + flex-direction: row; + align-items: flex-start; + justify-content: center; +} + +.fr-report-spinner[style*="display:none"] ~ .fr-toolbar ~ .fr-report-body, .fr-toolbar ~ .fr-report-body { + box-shadow: var(--page-border); +} + +.frpage-container [class^="frpage"] { + box-shadow: var( --multi-page-border); + margin: var(--multi-page-margin); +} + +.fr-form-header { + padding: 5px; + padding-left: 12px; + font: 14px Verdana,Arial sans-serif Regular; + min-height: 18px; + text-overflow: ellipsis; + overflow: hidden; + border-bottom: solid 1px lightgray; + vertical-align: middle; + text-align: -webkit-match-parent; + height: 30px; + align-items: center; + display: flex; + font-weight: bold; +} + +.fr-report-body:has(.fr-dialog-form) { + width: fit-content; + border-radius: 12px; + background: #FFF; + box-shadow: 0px 4px 4px 0px rgba(0, 0, 0, 0.25); +} + +/*********** + SPLIT +************/ + +.fr-gutter { + background-color: #f1f1f1; + background-repeat: no-repeat; + background-position: 50%; +} + +.fr-gutter.fr-gutter-horizontal, .fr-webreport -gutter.fr-webreport -gutter-horizontal { + background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAeCAYAAADkftS9AAAAIklEQVQoU2M4c+bMfxAGAgYYmwGrIIiDjrELjpo5aiZeMwF+yNnOs5KSvgAAAABJRU5ErkJggg=='); + cursor: ew-resize; +} + +/************* + TOOLBAR +**************/ + +.fr-toolbar { + flex-shrink: 1; + font: var(--user-font); + background-color: var(--toolbar-color); + display: flex; + flex-direction: var(--toolbar-direction); + width: fit-content; + height: var(--toolbar-height); + order: var(--toolbar-position); + position: relative; + align-items: center; + justify-content: var( --toolbar-content-align); + z-index: 2; + border-radius: var(--toolbar-roundness); + -webkit-user-select: none; /* Safari */ + -ms-user-select: none; /* IE 10 and IE 11 */ + user-select: none; /* Standard syntax */ + position: var(--sticky-toolbar-position); + position: var(--sticky-toolbar-position-webkit); + top: var(--sticky-toolbar-top); + left: var(--sticky-toolbar-left); + bottom: var(--sticky-toolbar-bottom); + right: var(--sticky-toolbar-right); +} + + +.fr-toolbar-item { + height: var(--toolbar-height); + border: none; + border-radius: var(--toolbar-roundness); + background-color: #00000000; + position: relative; + align-items: center; + display: flex; +} + +.fr-toolbar-item:hover:not([hidden]) { + background-color: var(--toolbar-color); +} + +.fr-toolbar-item[hidden] > svg, .fr-toolbar-item[hidden] > img { + filter: invert(99%) sepia(5%) saturate(91%) hue-rotate(66deg) brightness(114%) contrast(86%); +} + +.fr-toolbar-item > svg, .fr-toolbar-item > img { + height: calc(var(--toolbar-height) * 0.5); + padding-top: calc(var(--toolbar-height) * 0.15); + padding-bottom: calc(var(--toolbar-height) * 0.15); + padding-left: calc(var(--toolbar-height) * 0.25); + padding-right: calc(var(--toolbar-height) * 0.25); + opacity: var(--transparency-icon); + display: block; + filter: invert(var(--toolbar-icon-color)); + margin-left: 10px; + margin-right: 10px; +} + +.fr-toolbar-item:hover:not([hidden], .fr-disabled, .fr-toolbar-slash) > svg, +.fr-toolbar-item:hover:not([hidden], .fr-disabled, .fr-toolbar-slash) > img { + opacity: 0.5; +} + +.fr-toolbar-notbutton:hover { + background-color: transparent; +} + +.fr-toolbar-notbutton:hover > svg, .fr-toolbar-notbutton:hover > img { + opacity: 1; +} + +.fr-toolbar-image { + width: calc(var(--toolbar-height) * 0.5); +} + +/**************** + SEARCH FORM +*****************/ +.fr-toolbar-dropdown-content-searchbox { + float: none; + background-color: white; + text-decoration: none; + text-align: left; + height: auto; + user-select: none; + border: 1px solid #000; + border-radius: 6px; +} + +.fr-toolbar-search-form > div > label > input { + margin-bottom: 12px; + border-radius: 3px; +} + +.fr-toolbar-search-form > div > label:has(:disabled) { + color: #CACACA; +} + +.fr-toolbar-search-form { + font-size: 14px; + display: none; + position: fixed; + width: 390px; + z-index: 4; + left: var(--searchform-margin-left); + top: var(--searchform-margin-top); + padding: 0px 10px 0px 10px; + border-radius: 12px; + box-shadow: 0px 4px 4px 0px rgba(0, 0, 0, 0.2); + background-color: #EFEFEF; +} + +.search-navigation-info-block { + display: flex; + align-items: center; + justify-content: center; + text-align: center; + margin: 12px 0px 6px 0px; +} + +#fr-search-next > svg, #fr-search-prev > svg, #fr-search-next > img, #fr-search-prev > img { + vertical-align: middle; + height: 12px; +} + +#fr-search-next, #fr-search-prev { + background-color: white; + border: none; +} + +#fr-search-next:disabled > svg, #fr-search-prev:disabled > svg, #fr-search-next:disabled > img, #fr-search-prev:disabled > img { + filter: invert(99%) sepia(5%) saturate(91%) hue-rotate(66deg) brightness(114%) contrast(86%); +} + +#fr-search-next:hover:enabled, #fr-search-prev:hover:enabled { + /* background-color: #d9d9d9; */ +} + +#fr-search-next:active:enabled, #fr-search-prev:active:enabled { + background-color: #4A4A4A; +} + +#fr-search-next:active:enabled > svg, #fr-search-prev:active:enabled > svg, #fr-search-next:active:enabled > img, #fr-search-prev:active:enabled > img { + filter: invert(100%) sepia(100%) saturate(0%) hue-rotate(241deg) brightness(103%) contrast(103%); +} + +#fr-search-prev { + margin-right: -5px; + border-radius: 3px 0px 0px 3px; +} + +#fr-search-next { + border-radius: 0px 3px 3px 0px; +} + +#fr-search-text { + min-height: 25px; + width: 90%; + border: none; + outline: none; + vertical-align: middle; + -webkit-appearance: none; + border-radius: 6px; +} + +#clear-searchbox { + width: 20px; + height: 20px; + border: none; + vertical-align: middle; +} + +#close-search-form-button { + font-size: 10px; + text-align: right; + padding: 6px 0px 0px 0px; +} + +#fr-searchform-text-info { + width: 90%; +} + +#close-search-form-button > img { + height: 20px; + width: 20px; + filter: invert(36%) sepia(0%) saturate(0%) hue-rotate(85deg) brightness(100%) contrast(91%); +} + +#fr-toolbar-search-form.open { + display: block; +} + +.search-highlight { + background-color: var(--search-highlight-color); +} + +/********************** + TOOLBAR DROPDOWN +***********************/ + +.fr-toolbar-dropdown-content { + display: none; + box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2); + background-color: var(--toolbar-dropdownmenu-color); + min-width: 50px; + z-index: 2; + position: absolute; + top: var(--toolbar-dropdownmenu-position-top); + left: var(--toolbar-dropdownmenu-position-left); + bottom: var(--toolbar-dropdownmenu-position-bottom); + right: var(--toolbar-dropdownmenu-position-right); + text-align: var(--toolbar-dropdownmenu-text-align); + white-space: nowrap; + border-radius: var(--toolbar-dropdownlist-border); +} + +.fr-toolbar-item:hover:not([hidden]) > .fr-toolbar-dropdown-content { + display: block; +} + +.fr-toolbar-dropdown-content > a { + float: none; + color: var(--toolbar-dropdownmenu-text-color); + padding: 6px 12px 6px 8px; + text-decoration: none; + display: block; + text-align: left; + height: auto; + font-size: 14px; + user-select: none; +} + +.fr-toolbar-dropdown-content > a:hover { + background-color: var( --toolbar-dropdownmenu-color); + opacity: 0.5; + cursor: pointer; + border-radius: 0px 0px 10px 10px; +} + +.fr-zoom-selected { + font-weight: bold; +} + +.modalcontainer-overlay { + position: absolute; + left: 0; + top: 0; + right: 0; + bottom: 0; + background-color: rgba(0, 0, 0, 0.7); + display: flex; + align-items: flex-start; + justify-content: flex-start; + opacity: 0; + z-index: 2; + visibility: hidden; + transition: all 0.3s ease-in-out; + align-content: flex-start; +} + +.modalcontainer { + background-color: #fff; + width: 300px; + height: 300px; + display: flex; + align-items: center; + justify-content: center; + display: none; +} + +.content-modalcontainer { + width: 100%; +} + +.modalcontainer-overlay--visible { + opacity: 1; + visibility: visible; + transition: all 0.3s ease-in-out; + position: var(--container-position,absolute); + top: var(--container-top, 0); + left: var(--container-left, 0); +} + +.modalcontainer--visible { + display: flex; + width: fit-content; + height: fit-content; + min-width: 348px; + height: auto; + margin-top: 4rem; + margin-left: auto; + margin-right: auto; + padding: 0px 9px 50px 9px; + z-index: 4; + border-radius: 30px 30px 12px 12px; + background-color: #EFEFEF; + flex-wrap: nowrap; + align-content: center; + justify-content: center; + align-items: center; + flex-direction: column; + font-family: Arial,Verdana sans-serif; + position: var( --modal-container-position); + top: var(--fixed-container-top); + left: var(--fixed-container-left); + transform: var(--fixed-container-transform); +} +/****************** + POPUP +******************/ +.fr-popup { + min-width: 100%; + position: absolute; + min-height: 100%; + z-index: 3; + padding-bottom: 1rem; + background-color: #0000005c; + display: flex; + align-content: flex-start; + flex-direction: row; + flex-wrap: nowrap; + justify-content: flex-start; + align-items: flex-start; +} + +.fr-popup-content { + display: flex; + width: fit-content; + height: fit-content; + margin-top: 2.5rem; + margin-left: auto; + margin-right: auto; + padding: 0px 10px 50px 10px; + z-index: 4; + border-radius: 30px 30px 12px 12px; + background-color: #EFEFEF; + flex-wrap: nowrap; + align-content: center; + justify-content: center; + align-items: center; + flex-direction: column; + font-family: Arial,Verdana sans-serif; + position: var(--modal-container-position); +} + +.fr-popup-content-title { + display: flex; + width: 100%; + background-color: #35363A; + color: white; + font-weight: bold; + box-shadow: 0rem -0.1rem 0rem 0.6rem #35363A; + margin-top: 10px; + margin-bottom: 10px; + align-items: center; + flex-direction: column; + flex-wrap: nowrap; + justify-content: flex-start; + align-content: center; + font: var(--toolbar-user-font-style) 16px var(--toolbar-user-font-family); + border-radius: 12px 12px 0px 0px; +} + +.fr-popup-content-export-parameters-page-range-title { + margin-top: 25px; +} + +.fr-popup-content-title input { + background-color: white; + border: 3px solid var(--exports-button-color); + color: black; + max-height: 9.8px; + border-radius: 3px; +} + +button { + text-align: left; +} + +.fr-popup-content-export-parameters { + display: flex; + width: 100%; + -ms-flex-wrap: wrap; + flex-direction: column; + border-radius: 3px; + padding-bottom: 1rem; + align-content: flex-start; + flex-wrap: wrap; + align-items: flex-start; + justify-content: flex-start; + font: var(--toolbar-user-font-style) 14px var(--toolbar-user-font-family); + font-weight: bold; +} + +.fr-popup-content-export-parameters-col { + display: flex; + align-content: center; + flex-wrap: nowrap; + flex-direction: column; + font: var(--toolbar-user-font-style) 11px var(--toolbar-user-font-family); +} + +.custom-select { + width: auto; + outline: none; + max-width: 170px; + min-width: 20px; + border: none; + margin: 5px 5px 5px 5px; + border-radius: 3px; + height: 25px; + font: var(--toolbar-user-font-style) 12px var(--toolbar-user-font-family); + font-size: 11px; + overflow: hidden; + background: var(--select-arrow-icon); + background-position: calc(100% - 10px) center; + -moz-appearance: none; /* Firefox */ + -webkit-appearance: none; /* Safari and Chrome */ + appearance: none; + padding: 0 30px 0 10px !important; + -webkit-padding-end: 30px !important; + -webkit-padding-start: 10px !important; +} + +.fr-popup-content-export-parameters-input { + margin-left: 0.3rem; + margin-bottom: 0.3rem; + padding: 6px; + max-width: 70px; + height: 8px; + outline: none; + border: none; + margin-left: 5px; + margin-right: 5px; + min-width: inherit; + border-radius: 4px; + font: var(--toolbar-user-font-style) 10px var(--toolbar-user-font-family); +} + +.input-error { + animation: shake 0.2s ease-in-out 0s 2; + box-shadow: 0 0 0.5em red; +} + +@keyframes shake { + 0% { + margin-left: 0rem; + } + + 25% { + margin-left: 0.5rem; + } + + 75% { + margin-left: -0.5rem; + } + + 100% { + margin-left: 0rem; + } +} + +.fr-popup-content-export-parameters-row { + display: flex; + padding-top: 5px; + flex-direction: row; + align-items: flex-start; + justify-content: flex-start; +} + +.fr-popup-content-export-parameters-slider { + display: flex; + margin: 0rem 0rem 0rem 0.35rem; + background-color: transparent; + border-radius: 10px; + justify-content: flex-start; + align-items: center; + align-content: center; + flex-direction: row; +} + +.fr-popup-content-export-parameters-slider span { + color: black; + min-width: 128px; + font: var(--toolbar-user-font-style) 11px var(--toolbar-user-font-family); + font-weight: normal; + white-space: nowrap; +} + +input[type=range] { + height: 1.7rem; + overflow: hidden; + -webkit-appearance: none; + margin-left: 0; + outline: none; + background-color: #424242; +} + +input[type=range]::-webkit-slider-runnable-track { + width: 100%; + height: 100%; + cursor: pointer; + animate: 0.2s; + background: #424242; + border-radius: 0px; +} + +input[type=range]::-webkit-slider-thumb { + height: 100%; + width: 5%; + border-radius: 0px; + background: linear-gradient(gray,5%, var(--exports-button-color)); + cursor: pointer; + -webkit-appearance: none; + box-shadow: -100vw 0vw 0vw 100vw var(--exports-button-color); + margin-top: 0px; +} + +label { + margin: 5px 0px; +} + +.fr-popup-content-export-parameters-col input[type=text] { + background-color: white; + color: #000000; + border: 2px solid var(--exports-button-color); + max-height: 11px; +} + +.fr-popup-content-export-parameters-button { + padding: 5px; + outline: none; + border: none; + margin-left: 5px; + margin-right: 5px; + min-width: inherit; + font: var(--toolbar-user-font-style) 11px var(--toolbar-user-font-family); + color: black; + background: url(../Resources/button.svg) no-repeat; + background-position: 0px center; + padding-left: 20px; + vertical-align: middle; + cursor: pointer; +} + +.fr-popup-content-buttons { + display: flex; + margin-bottom: -2.3rem; + width: 100%; + flex-wrap: nowrap; + align-content: center; + justify-content: space-between; + align-items: center; + flex-direction: row; +} + +.fr-popup-content-btn-submit { + outline: none; + border: none; + background-color: #DD4433; + border-radius: 3px; + padding: 3px; + font: var(--toolbar-user-font-style) 14px var(--toolbar-user-font-family); + color: var(--exports-font-color); + min-width: 70px; + width: fit-content; + height: 30px; + cursor: pointer; + text-align: center; +} + +.fr-popup-content-btn-cancel { + padding: 3px; + background-color: #D9D9D9; + font: var(--toolbar-user-font-style) 14px var(--toolbar-user-font-family); + min-width: 70px; + width: fit-content; + height: 30px; + border-radius: 3px; + border: none; + outline: none; + color: black; + text-align: center; +} + +.fr-popup-content-btn-submit:hover { + transform: scale(1.015); +} + +.fr-container .activeButton, .fr-container .active-button { + background: var(--button-active-icon); + background-position: 0px center; + vertical-align: middle; +} + + +.fr-settings-btn { + background-color: transparent; + color: transparent; + padding-left: 1rem; + margin-left: 230px; + display: flex; + float: right; + margin-top: -1.6rem; + outline: none; + padding-right: 1rem; + border: none; + position: relative; + z-index: 4; + flex-direction: row; + align-content: space-around; + justify-content: space-between; + filter: alpha(opacity=50); + opacity: 1; +} + +.fr-settings-btn:hover { + background-color: transparent; + color: transparent; + padding-left: 1rem; + margin-left: 230px; + display: flex; + float: right; + margin-top: -1.6rem; + outline: none; + padding-right: 1rem; + border: none; + position: relative; + z-index: 4; + flex-direction: row; + align-content: space-around; + justify-content: space-between; + transform: scale(1.1); + filter: alpha(opacity=0); + opacity: 0.5; + cursor: pointer; +} + +.fr-settings-btn::-moz-focus-inner { + background-color: transparent; + color: transparent; + padding-left: 1rem; + margin-left: 230px; + display: flex; + float: right; + margin-top: -1.6rem; + outline: none; + padding-right: 1rem; + border: none; + position: relative; + z-index: 4; + flex-direction: row; + align-content: space-around; + justify-content: space-between; +} + +.fr-popup-disabled-button { + background-color: #D9D9D9; + cursor: default; +} + +/************************ + TOOLBAR NAVIGATION +*************************/ + +.fr-toolbar-narrow > svg, .fr-toolbar-narrow > img { + transform: rotate(var(--toolbar-narrow)deg); + padding-left: 0px; + padding-right: 0px; + height: calc(var(--toolbar-height) * 0.35); + padding-top: 9px; +} + +.fr-toolbar-slash { +} + +.fr-toolbar-slash > svg, .fr-toolbar-slash > img { + margin-left: 0px; + margin-right: 0px; + height: calc(var(--toolbar-height) * 0.35); + padding-top: 9px; + margin: 5px 0px 0px; + padding-right: 5px; + padding-left: 5px; +} + +.fr-toolbar-item > input { + font: var(--toolbar-user-font-style) 12px var(--toolbar-user-font-family); + font-size: calc(var(--toolbar-height) * 0.35); + text-align: center; + border: 0; + background: #fbfbfb; + border-radius: var(--toolbar-roundness); + height: calc(var(--toolbar-height) * 0.68); + width: 3.5em; + margin-top: calc(var(--toolbar-height) * 0.17); + margin-bottom: calc(var(--toolbar-height) * 0.15); + margin-left: calc(var(--toolbar-height) * 0.1); + margin-right: calc(var(--toolbar-height) * 0.1); + padding: 0; + display: block; + border-radius: 5px; +} + +.fr-toolbar-item > input:hover:not([readonly]) { + background: #fff; +} + +.fr-toolbar-item > input[readonly] { + cursor: default; +} + +/************** + SPINNER +**************/ + +.fr-report-spinner { + height: 100%; + width: 100%; + position: absolute; + background-color: rgba(255, 255, 255, 0.7); + z-index: 10; +} + +.fr-report-spinner svg, fr-report-spinner-img { + width: 90px; + height: 90px; + left: max(calc(50% - 50px), 25px); + top: max(calc(50% - 50px), 25px); + position: absolute; + animation: fr-spin 1s infinite steps(8); + opacity: 0.5; +} + +@keyframes fr-spin { + from { + -webkit-transform: rotate(0deg); + } + + to { + -webkit-transform: rotate(360deg); + } +} + +/************ + ERROR +************/ + +.fr-error-container { + width: 100%; + height: 100%; + display: flex; + flex-direction: column; + overflow: auto; +} + +.fr-error-text { + color: red; + font-family: Consolas,monospace; + font-size: 16px; + margin: 20px; + text-align: center; +} + +.fr-error-response { + height: 100%; + position: relative; +} + +/*********** + TABS +***********/ + +.fr-tabs { + flex-shrink: 0; + font-family: Verdana,Arial,sans-serif; + background-color: #f1f1f1; + display: table; + width: var(--toolbar-tab-position); + max-width: var(--report-max-width); + box-shadow: 0px 3px 4px -2px rgba(0, 0, 0, 0.2); + position: relative; + border-radius: 9px; + z-index: 1; + order: var(--toolbar-tab-order); + position: var(--sticky-toolbar-tabs-position); + top: var(--sticky-toolbar-tabs-top); + left: var(--sticky-toolbar-tabs-left); + bottom: var(--sticky-toolbar-tabs-bottom); + right: var(--sticky-toolbar-tabs-right); +} + + +.fr-tabs .fr-tab { + float: left; + display: block; + color: #3b3b3b; + text-align: center; + text-decoration: none; + font-size: 12px; + background-color: #f1f1f1; + margin-top: 2px; + margin-right: 2px; + height: 24px; + border-radius: 9px; +} + +.fr-tabs .fr-tab-title { + display: block; + float: left; + padding: 4.5px 10px; + color: black; +} + +.fr-tabs .fr-tab-close { + width: 13px; + height: 13px; + display: block; + float: left; + margin-top: 6px; + margin-right: 6px; +} + +.fr-tabs .fr-tab-close svg, .fr-tabs .fr-tab-close img { + border-radius: 10px; + width: 13px; + height: 13px; + display: block; +} + +.fr-tabs .fr-tab:hover { + background-color: lightgray; + color: black; + cursor: pointer; +} + +.fr-tabs .fr-tab.active { + background-color: lightgray; + color: black; + cursor: default; +} + +.fr-tabs .fr-tab a svg, fr-tabs .fr-tab a img { + height: 13px; + opacity: 0; +} + +.fr-tabs .fr-tab.active a svg, .fr-tabs .fr-tab.active a img, +.fr-tabs .fr-tab:hover a svg, .fr-tabs .fr-tab:hover a img { + opacity: 0.5; +} + +.fr-tabs .fr-tab a svg:hover, .fr-tabs .fr-tab a img:hover { + opacity: 1; + background-color: #f1f1f1; + cursor: pointer; +} + +/*********** + MISC +***********/ + +.fr-pointer:hover { + cursor: pointer; +} + +.fr-disabled { + opacity: 0.5; +} + +.datetimepicker > input[type="date"] { + background: url(../Resources/date-picker.svg) no-repeat; + background-size: 10px; + background-position: right 5px center; + background-origin: content-box, content-box; +} + +.datetimepicker > input[type="date"]:disabled { + background: url("") no-repeat; +} + +input[type=date]::-webkit-calendar-picker-indicator { + opacity: 0; +} +/************** + OUTLINE +**************/ + +.fr-outline { + overflow: auto; + height: auto; + font-family: Verdana,Arial,sans-serif; + font-size: 11px; +} + +.fr-outline img { + opacity: 0.5; +} + +.fr-outline-inner { + padding: 5px; +} + +.fr-outline-node { + display: flex; + flex-wrap: wrap; +} + +.fr-outline-caret { + height: 14px; + width: 14px; + margin-top: 1.5px; + margin-right: 4px; +} + +.fr-outline-caret:hover { + cursor: pointer; +} + +.fr-outline-caret-blank { + width: 18px; +} + +.fr-outline-file { + height: 14px; + margin-top: 1.5px; +} + +.fr-outline-text { + white-space: nowrap; + display: flex; + align-items: center; +} + +.fr-outline-text > a { + margin: 2px; + padding: 2px; +} + +.fr-outline-text > a:hover { + text-decoration: underline; + cursor: pointer; +} + +.fr-outline-children { + padding-left: 20px; +} + +/******************* + + EMAIL EXPORT + +*******************/ +.fr-notification { + position: fixed; + bottom: 20px; + right: 20px; + display: flex; + align-items: center; + padding: 10px 20px; + border-radius: 4px; + font-size: 14px; + color: white; + opacity: 1; + transition: opacity 0.5s; + z-index: 9999; + font-family: Arial, sans-serif; +} + +.fr-notification-content { + display: flex; + align-items: center; +} + +.fr-notification-content img { + margin-right: 10px; +} + +.fr-notification.positive { + background-color: #44cc44; +} + +.fr-required-star { + color: red; +} + + +.fr-notification.negative { + background-color: #cc4444; +} + + +.fr-email-export-form { + display: flex; + flex-direction: column; + padding: 5px; + box-sizing: border-box; + width: 100%; +} + +.fr-email-export-field { + display: flex; + margin-bottom: 5px; + justify-content: space-between; + width: 100%; + font-size: 12px; +} + +.fr-email-export-input { + width: 244px; + padding: 8px; + border: none; + border-radius: 4px; + background: #FFF; + display: flex; + margin-left: 30px; + font-size: 12px; +} + +.fr-email-export-textarea { + margin-left: 10px; + width: 244px; + height: 146px; + padding: 8px; + border: none; + border-radius: 5px; + resize: none; + font-size: 12px; +} + +.fr-email-export-select { + overflow: hidden; + -moz-appearance: none; /* Firefox */ + -webkit-appearance: none; /* Safari and Chrome */ + background: var(--select-arrow-icon); + background-position: calc(100% - 10px) center; + margin-left: 10px; + width: 244px; + padding: 8px; + border-radius: 5px; + border: none; + font-size: 12px; +} + +.fr-email-export-label { + font-weight: normal; + font-size: 12px; +} + +/****************** + Report styles +******************/ +.fr-input { + outline: none; + border: none; + resize: none; +}