From 30516bfa12b6cf608d5a3fab6fde6e25473c2fa3 Mon Sep 17 00:00:00 2001 From: Elitsa Marinovska Date: Tue, 17 Mar 2020 15:36:38 +0100 Subject: [PATCH] Creating JavaScriptHelper class and taking some of the logic from the JsInitialization class --- src/Umbraco.Core/Assets/JavascriptFile.cs | 4 +- .../JsInitializationTests.cs | 3 +- src/Umbraco.Web/Editors/PreviewController.cs | 6 +- .../HtmlHelperBackOfficeExtensions.cs | 2 +- .../JavaScript/JavaScriptHelper.cs | 147 ++++++++++++++++++ 5 files changed, 154 insertions(+), 8 deletions(-) create mode 100644 src/Umbraco.Web/JavaScript/JavaScriptHelper.cs diff --git a/src/Umbraco.Core/Assets/JavascriptFile.cs b/src/Umbraco.Core/Assets/JavascriptFile.cs index 477c8eabab..51d4a26d82 100644 --- a/src/Umbraco.Core/Assets/JavascriptFile.cs +++ b/src/Umbraco.Core/Assets/JavascriptFile.cs @@ -7,9 +7,9 @@ namespace Umbraco.Core.Assets /// /// Represents a JS asset file /// - public class JavascriptFile : AssetFile + public class JavaScriptFile : AssetFile { - public JavascriptFile(string filePath) + public JavaScriptFile(string filePath) : base(AssetType.Javascript) { FilePath = filePath; diff --git a/src/Umbraco.Tests/Web/AngularIntegration/JsInitializationTests.cs b/src/Umbraco.Tests/Web/AngularIntegration/JsInitializationTests.cs index c4b5e3247b..71e7963d61 100644 --- a/src/Umbraco.Tests/Web/AngularIntegration/JsInitializationTests.cs +++ b/src/Umbraco.Tests/Web/AngularIntegration/JsInitializationTests.cs @@ -2,6 +2,7 @@ using NUnit.Framework; using Umbraco.Core; using Umbraco.Web.JavaScript; +using Umbraco.Web.JavaScript.CDF; namespace Umbraco.Tests.Web.AngularIntegration { @@ -19,7 +20,7 @@ namespace Umbraco.Tests.Web.AngularIntegration [Test] public void Parse_Main() { - var result = JsInitialization.WriteScript("[World]", "Hello", "Blah"); + var result = JavaScriptHelper.WriteScript("[World]", "Hello", "Blah"); Assert.AreEqual(@"LazyLoad.js([World], function () { //we need to set the legacy UmbClientMgr path diff --git a/src/Umbraco.Web/Editors/PreviewController.cs b/src/Umbraco.Web/Editors/PreviewController.cs index b1f9d15feb..93c7da9962 100644 --- a/src/Umbraco.Web/Editors/PreviewController.cs +++ b/src/Umbraco.Web/Editors/PreviewController.cs @@ -1,5 +1,4 @@ using System; -using System.Linq; using System.Web; using System.Web.Mvc; using System.Web.UI; @@ -14,7 +13,6 @@ using Umbraco.Core.Services; using Umbraco.Web.Composing; using Umbraco.Web.Features; using Umbraco.Web.JavaScript; -using Umbraco.Web.Models.ContentEditing; using Umbraco.Web.Mvc; using Umbraco.Web.PublishedCache; using Umbraco.Web.Trees; @@ -103,8 +101,8 @@ namespace Umbraco.Web.Editors [OutputCache(Order = 1, VaryByParam = "none", Location = OutputCacheLocation.Server, Duration = 5000)] public JavaScriptResult Application() { - var files = JsInitialization.OptimizeScriptFiles(HttpContext, JsInitialization.GetPreviewInitialization(), _runtimeMinifier); - var result = JsInitialization.GetJavascriptInitialization(HttpContext, files, "umbraco.preview", _globalSettings, _ioHelper); + var files = JavaScriptHelper.OptimizeScriptFiles(HttpContext, JavaScriptHelper.GetPreviewInitialization(), _runtimeMinifier); + var result = JavaScriptHelper.GetJavascriptInitialization(HttpContext, files, "umbraco.preview", _globalSettings, _ioHelper); return JavaScript(result); } diff --git a/src/Umbraco.Web/HtmlHelperBackOfficeExtensions.cs b/src/Umbraco.Web/HtmlHelperBackOfficeExtensions.cs index 3fa6b604d5..2093984e54 100644 --- a/src/Umbraco.Web/HtmlHelperBackOfficeExtensions.cs +++ b/src/Umbraco.Web/HtmlHelperBackOfficeExtensions.cs @@ -130,7 +130,7 @@ namespace Umbraco.Web public static IHtmlString AngularValueTinyMceAssets(this HtmlHelper html, IRuntimeMinifier runtimeMinifier) { var ctx = new HttpContextWrapper(HttpContext.Current); - var files = JsInitialization.OptimizeTinyMceScriptFiles(ctx, runtimeMinifier); + var files = JavaScriptHelper.OptimizeTinyMceScriptFiles(ctx, runtimeMinifier); var sb = new StringBuilder(); diff --git a/src/Umbraco.Web/JavaScript/JavaScriptHelper.cs b/src/Umbraco.Web/JavaScript/JavaScriptHelper.cs new file mode 100644 index 0000000000..d42526be05 --- /dev/null +++ b/src/Umbraco.Web/JavaScript/JavaScriptHelper.cs @@ -0,0 +1,147 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Web; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Umbraco.Core; +using Umbraco.Core.Assets; +using Umbraco.Core.Configuration; +using Umbraco.Core.IO; +using Umbraco.Core.Runtime; +using CssFile = Umbraco.Core.Assets.CssFile; + +namespace Umbraco.Web.JavaScript +{ + public class JavaScriptHelper + { + // deal with javascript functions inside of json (not a supported json syntax) + private const string PrefixJavaScriptObject = "@@@@"; + private static readonly Regex JsFunctionParser = new Regex($"(\"{PrefixJavaScriptObject}(.*?)\")+", + RegexOptions.Multiline | RegexOptions.CultureInvariant | RegexOptions.Compiled); + + // replace tokens in the js main + private static readonly Regex Token = new Regex("(\"##\\w+?##\")", RegexOptions.Compiled); + + + /// + /// Gets the JS initialization script to boot the back office application + /// + /// + /// + /// + /// The angular module name to boot + /// + /// + public static string GetJavascriptInitialization(HttpContextBase httpContext, IEnumerable scripts, string angularModule, IGlobalSettings globalSettings, IIOHelper ioHelper) + { + var jarray = new StringBuilder(); + jarray.AppendLine("["); + var first = true; + foreach (var file in scripts) + { + if (first) first = false; + else jarray.AppendLine(","); + jarray.Append("\""); + jarray.Append(file); + jarray.Append("\""); + + } + jarray.Append("]"); + + return WriteScript(jarray.ToString(), ioHelper.ResolveUrl(globalSettings.UmbracoPath), angularModule); + } + + /// + /// Parses the JsResources.Main and replaces the replacement tokens accordingly + /// + /// + /// + /// + /// + internal static string WriteScript(string scripts, string umbracoPath, string angularModule) + { + var count = 0; + var replacements = new[] { scripts, umbracoPath, angularModule }; + // replace, catering for the special syntax when we have + // js function() objects contained in the json + + return Token.Replace(Resources.Main, match => + { + var replacement = replacements[count++]; + return JsFunctionParser.Replace(replacement, "$2"); + }); + } + + internal static IEnumerable GetTinyMceInitialization() + { + var resources = JsonConvert.DeserializeObject(Resources.TinyMceInitialize); + return resources.Where(x => x.Type == JTokenType.String).Select(x => x.ToString()); + } + + internal static IEnumerable OptimizeTinyMceScriptFiles(HttpContextBase httpContext, IRuntimeMinifier runtimeMinifier) + { + return OptimizeScriptFiles(httpContext, GetTinyMceInitialization(), runtimeMinifier); + } + + + /// + /// Returns the default config as a JArray + /// + /// + internal static IEnumerable GetPreviewInitialization() + { + var resources = JsonConvert.DeserializeObject(Resources.PreviewInitialize); + return resources.Where(x => x.Type == JTokenType.String).Select(x => x.ToString()); + } + + + /// + /// Returns a list of optimized script paths + /// + /// + /// + /// + /// + /// + /// Used to cache bust and optimize script paths + /// + public static IEnumerable OptimizeScriptFiles(HttpContextBase httpContext, IEnumerable scriptFiles, IRuntimeMinifier runtimeMinifier) + { + var scripts = new HashSet(); + foreach (var script in scriptFiles) + scripts.Add(script); + + scripts = new HashSet(OptimizeAssetCollection(scripts, AssetType.Javascript, httpContext, runtimeMinifier)); + + return scripts.ToArray(); + } + + internal static IEnumerable OptimizeAssetCollection(IEnumerable assets, AssetType assetType, HttpContextBase httpContext, IRuntimeMinifier runtimeMinifier) + { + if (httpContext == null) throw new ArgumentNullException(nameof(httpContext)); + + var requestUrl = httpContext.Request.Url; + if (requestUrl == null) throw new ArgumentException("HttpContext.Request.Url is null.", nameof(httpContext)); + + var dependencies = assets.Where(x => x.IsNullOrWhiteSpace() == false).Select(x => + { + // most declarations with be made relative to the /umbraco folder, so things + // like lib/blah/blah.js so we need to turn them into absolutes here + if (x.StartsWith("/") == false && Uri.IsWellFormedUriString(x, UriKind.Relative)) + { + return new AssetFile(assetType) { FilePath = new Uri(requestUrl, x).AbsolutePath }; + } + + return assetType == AssetType.Javascript + ? new JavaScriptFile(x) + : new CssFile(x) as IAssetFile; + }).ToList(); + + + return runtimeMinifier.GetAssetPaths(assetType, dependencies);; + } + } +}