From b9b4721295125ca16a481e2a2bfd83ff906887d6 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Mon, 19 Aug 2019 14:36:56 +0100 Subject: [PATCH 1/6] * Adds TinyMCE JS assets into init page load via script in default.cshtml view for Umbraco backoffice ng-app * Add TinyMCE JS assets array via NG app.value & uses assetsService to load (if not loaded in time by main init script above) --- .../propertyeditors/rte/rte.controller.js | 8 ++--- .../Umbraco/Views/Default.cshtml | 3 ++ .../Editors/BackOfficeController.cs | 23 ++++++++++++++ .../HtmlHelperBackOfficeExtensions.cs | 16 ++++++++++ .../JavaScript/JsInitialization.cs | 31 +++++++++++++++++++ .../JavaScript/Resources.Designer.cs | 12 +++++++ src/Umbraco.Web/JavaScript/Resources.resx | 5 ++- .../JavaScript/TinyMceInitialize.js | 19 ++++++++++++ src/Umbraco.Web/Umbraco.Web.csproj | 1 + 9 files changed, 113 insertions(+), 5 deletions(-) create mode 100644 src/Umbraco.Web/JavaScript/TinyMceInitialize.js diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.controller.js index 52b105201e..48170fb4b7 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.controller.js @@ -1,6 +1,6 @@ angular.module("umbraco") .controller("Umbraco.PropertyEditors.RTEController", - function ($scope, $q, assetsService, $timeout, tinyMceService, angularHelper) { + function ($scope, $q, assetsService, $timeout, tinyMceService, angularHelper, tinyMceAssets) { // TODO: A lot of the code below should be shared between the grid rte and the normal rte @@ -30,9 +30,9 @@ angular.module("umbraco") var promises = []; //queue file loading - if (typeof tinymce === "undefined") { // Don't reload tinymce if already loaded - promises.push(assetsService.loadJs("lib/tinymce/tinymce.min.js", $scope)); - } + tinyMceAssets.forEach(function (tinyJsAsset) { + promises.push(assetsService.loadJs(tinyJsAsset, $scope)); + }); //stores a reference to the editor var tinyMceEditor = null; diff --git a/src/Umbraco.Web.UI/Umbraco/Views/Default.cshtml b/src/Umbraco.Web.UI/Umbraco/Views/Default.cshtml index 3574d5d175..00ab8e0166 100644 --- a/src/Umbraco.Web.UI/Umbraco/Views/Default.cshtml +++ b/src/Umbraco.Web.UI/Umbraco/Views/Default.cshtml @@ -119,6 +119,8 @@ document.angularReady = function(app) { @Html.AngularValueExternalLoginInfoScript(ViewData.GetExternalSignInError()) @Html.AngularValueResetPasswordCodeInfoScript(ViewData["PasswordResetCode"]) + @Html.AngularValueTinyMceAssets() + //required for the noscript trick document.getElementById("mainwrapper").style.display = "inherit"; } @@ -126,6 +128,7 @@ + @if (isDebug) { diff --git a/src/Umbraco.Web/Editors/BackOfficeController.cs b/src/Umbraco.Web/Editors/BackOfficeController.cs index 34022f8f9f..72a9d6f6b1 100644 --- a/src/Umbraco.Web/Editors/BackOfficeController.cs +++ b/src/Umbraco.Web/Editors/BackOfficeController.cs @@ -28,6 +28,7 @@ using Umbraco.Web.JavaScript; using Umbraco.Web.Security; using Constants = Umbraco.Core.Constants; using JArray = Newtonsoft.Json.Linq.JArray; +using System.Text; namespace Umbraco.Web.Editors { @@ -210,6 +211,28 @@ namespace Umbraco.Web.Editors return JavaScript(result); } + [MinifyJavaScriptResult(Order = 0)] + [OutputCache(Order = 1, VaryByParam = "none", Location = OutputCacheLocation.Server, Duration = 5000)] + public JavaScriptResult TinyMceEditor() + { + var files = JsInitialization.OptimizeTinyMceScriptFiles(HttpContext); + + var rawJS = new StringBuilder(); + rawJS.AppendLine("LazyLoad.js(["); + var first = true; + foreach (var file in files) + { + if (first) first = false; + else rawJS.AppendLine(","); + rawJS.Append("\""); + rawJS.Append(file); + rawJS.Append("\""); + + } + rawJS.Append("]);"); + return JavaScript(rawJS.ToString()); + } + /// /// Returns a js array of all of the manifest assets /// diff --git a/src/Umbraco.Web/HtmlHelperBackOfficeExtensions.cs b/src/Umbraco.Web/HtmlHelperBackOfficeExtensions.cs index 26a1d97f67..1d518fa1d3 100644 --- a/src/Umbraco.Web/HtmlHelperBackOfficeExtensions.cs +++ b/src/Umbraco.Web/HtmlHelperBackOfficeExtensions.cs @@ -13,6 +13,7 @@ using Umbraco.Web.Models; namespace Umbraco.Web { using Core.Configuration; + using Umbraco.Web.JavaScript; /// /// HtmlHelper extensions for the back office @@ -118,6 +119,21 @@ namespace Umbraco.Web sb.AppendLine(JsonConvert.SerializeObject(resetCodeModel)); sb.AppendLine(@"});"); + return html.Raw(sb.ToString()); + } + + public static IHtmlString AngularValueTinyMceAssets(this HtmlHelper html) + { + var ctx = new HttpContextWrapper(HttpContext.Current); + var files = JsInitialization.OptimizeTinyMceScriptFiles(ctx); + + var sb = new StringBuilder(); + + sb.AppendLine(@"app.value(""tinyMceAssets"","); + sb.AppendLine(JsonConvert.SerializeObject(files)); + sb.AppendLine(@");"); + + return html.Raw(sb.ToString()); } } diff --git a/src/Umbraco.Web/JavaScript/JsInitialization.cs b/src/Umbraco.Web/JavaScript/JsInitialization.cs index 638b1bf5b4..b8726e73c3 100644 --- a/src/Umbraco.Web/JavaScript/JsInitialization.cs +++ b/src/Umbraco.Web/JavaScript/JsInitialization.cs @@ -60,6 +60,26 @@ namespace Umbraco.Web.JavaScript return WriteScript(jarray.ToString(), IOHelper.ResolveUrl(SystemDirectories.Umbraco), angularModule); } + public static string GetTinyJavascriptInitialization(HttpContextBase httpContext, IEnumerable scripts) + { + var rawJs = new StringBuilder(); + rawJs.AppendLine("LazyLoad.js(["); + + var first = true; + foreach (var file in scripts) + { + if (first) first = false; + else rawJs.AppendLine(","); + rawJs.Append("\""); + rawJs.Append(file); + rawJs.Append("\""); + + } + rawJs.Append("]);"); + + return rawJs.ToString(); + } + /// /// Returns a list of optimized script paths for the back office /// @@ -131,6 +151,17 @@ namespace Umbraco.Web.JavaScript return resources.Where(x => x.Type == JTokenType.String).Select(x => x.ToString()); } + 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) + { + return OptimizeScriptFiles(httpContext, GetTinyMceInitialization()); + } + /// /// Parses the JsResources.Main and replaces the replacement tokens accordingly. /// diff --git a/src/Umbraco.Web/JavaScript/Resources.Designer.cs b/src/Umbraco.Web/JavaScript/Resources.Designer.cs index ca571b1186..f11839f6ca 100644 --- a/src/Umbraco.Web/JavaScript/Resources.Designer.cs +++ b/src/Umbraco.Web/JavaScript/Resources.Designer.cs @@ -146,5 +146,17 @@ namespace Umbraco.Web.JavaScript { return ResourceManager.GetString("ServerVariables", resourceCulture); } } + + /// + /// Looks up a localized string similar to [ + /// '../lib/tinymce/tinymce.min.js', + ///] + ///. + /// + internal static string TinyMceInitialize { + get { + return ResourceManager.GetString("TinyMceInitialize", resourceCulture); + } + } } } diff --git a/src/Umbraco.Web/JavaScript/Resources.resx b/src/Umbraco.Web/JavaScript/Resources.resx index 95526f51e7..1adcaeeb4a 100644 --- a/src/Umbraco.Web/JavaScript/Resources.resx +++ b/src/Umbraco.Web/JavaScript/Resources.resx @@ -130,4 +130,7 @@ servervariables.js;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 - + + TinyMceInitialize.js;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + \ No newline at end of file diff --git a/src/Umbraco.Web/JavaScript/TinyMceInitialize.js b/src/Umbraco.Web/JavaScript/TinyMceInitialize.js new file mode 100644 index 0000000000..1ffcce4a59 --- /dev/null +++ b/src/Umbraco.Web/JavaScript/TinyMceInitialize.js @@ -0,0 +1,19 @@ +[ + 'lib/tinymce/tinymce.min.js', + + 'lib/tinymce/langs/en_us.js', + + 'lib/tinymce/plugins/paste/plugin.min.js', + 'lib/tinymce/plugins/anchor/plugin.min.js', + 'lib/tinymce/plugins/charmap/plugin.min.js', + 'lib/tinymce/plugins/table/plugin.min.js', + 'lib/tinymce/plugins/lists/plugin.min.js', + 'lib/tinymce/plugins/advlist/plugin.min.js', + 'lib/tinymce/plugins/hr/plugin.min.js', + 'lib/tinymce/plugins/autolink/plugin.min.js', + 'lib/tinymce/plugins/directionality/plugin.min.js', + 'lib/tinymce/plugins/tabfocus/plugin.min.js', + 'lib/tinymce/plugins/searchreplace/plugin.min.js', + 'lib/tinymce/plugins/fullscreen/plugin.min.js', + 'lib/tinymce/plugins/noneditable/plugin.min.js' +] diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index dc06222209..36712a198c 100755 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -1205,6 +1205,7 @@ + From 0daa80efa4a18314f30613bd5945d7c1379be016 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Tue, 20 Aug 2019 11:01:45 +0100 Subject: [PATCH 2/6] Undo some of the changes as we will load it via assetService in the angular main controller & fixes the double load issue --- .../Umbraco/Views/Default.cshtml | 1 - .../Editors/BackOfficeController.cs | 22 ------------------- .../JavaScript/JsInitialization.cs | 20 ----------------- 3 files changed, 43 deletions(-) diff --git a/src/Umbraco.Web.UI/Umbraco/Views/Default.cshtml b/src/Umbraco.Web.UI/Umbraco/Views/Default.cshtml index 00ab8e0166..056d2b6f51 100644 --- a/src/Umbraco.Web.UI/Umbraco/Views/Default.cshtml +++ b/src/Umbraco.Web.UI/Umbraco/Views/Default.cshtml @@ -128,7 +128,6 @@ - @if (isDebug) { diff --git a/src/Umbraco.Web/Editors/BackOfficeController.cs b/src/Umbraco.Web/Editors/BackOfficeController.cs index 72a9d6f6b1..ca17f534c4 100644 --- a/src/Umbraco.Web/Editors/BackOfficeController.cs +++ b/src/Umbraco.Web/Editors/BackOfficeController.cs @@ -211,28 +211,6 @@ namespace Umbraco.Web.Editors return JavaScript(result); } - [MinifyJavaScriptResult(Order = 0)] - [OutputCache(Order = 1, VaryByParam = "none", Location = OutputCacheLocation.Server, Duration = 5000)] - public JavaScriptResult TinyMceEditor() - { - var files = JsInitialization.OptimizeTinyMceScriptFiles(HttpContext); - - var rawJS = new StringBuilder(); - rawJS.AppendLine("LazyLoad.js(["); - var first = true; - foreach (var file in files) - { - if (first) first = false; - else rawJS.AppendLine(","); - rawJS.Append("\""); - rawJS.Append(file); - rawJS.Append("\""); - - } - rawJS.Append("]);"); - return JavaScript(rawJS.ToString()); - } - /// /// Returns a js array of all of the manifest assets /// diff --git a/src/Umbraco.Web/JavaScript/JsInitialization.cs b/src/Umbraco.Web/JavaScript/JsInitialization.cs index b8726e73c3..17e4f7b094 100644 --- a/src/Umbraco.Web/JavaScript/JsInitialization.cs +++ b/src/Umbraco.Web/JavaScript/JsInitialization.cs @@ -60,26 +60,6 @@ namespace Umbraco.Web.JavaScript return WriteScript(jarray.ToString(), IOHelper.ResolveUrl(SystemDirectories.Umbraco), angularModule); } - public static string GetTinyJavascriptInitialization(HttpContextBase httpContext, IEnumerable scripts) - { - var rawJs = new StringBuilder(); - rawJs.AppendLine("LazyLoad.js(["); - - var first = true; - foreach (var file in scripts) - { - if (first) first = false; - else rawJs.AppendLine(","); - rawJs.Append("\""); - rawJs.Append(file); - rawJs.Append("\""); - - } - rawJs.Append("]);"); - - return rawJs.ToString(); - } - /// /// Returns a list of optimized script paths for the back office /// From 6873c12f0491b3274306e2047e1d8272ac5527ad Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Tue, 20 Aug 2019 11:11:29 +0100 Subject: [PATCH 3/6] Update to main controller to load in the TinyMCE assets - assetsService deals with de-duping already loaded assets --- src/Umbraco.Web.UI.Client/src/main.controller.js | 9 ++++++++- src/Umbraco.Web.UI/Umbraco/js/main.controller.js | 9 ++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/main.controller.js b/src/Umbraco.Web.UI.Client/src/main.controller.js index 654bbb1d03..f4bac95767 100644 --- a/src/Umbraco.Web.UI.Client/src/main.controller.js +++ b/src/Umbraco.Web.UI.Client/src/main.controller.js @@ -10,7 +10,7 @@ */ function MainController($scope, $location, appState, treeService, notificationsService, userService, historyService, updateChecker, navigationService, eventsService, - tmhDynamicLocale, localStorageService, editorService, overlayService) { + tmhDynamicLocale, localStorageService, editorService, overlayService, assetsService, tinyMceAssets) { //the null is important because we do an explicit bool check on this in the view $scope.authenticated = null; @@ -21,6 +21,13 @@ function MainController($scope, $location, appState, treeService, notificationsS $scope.search = {}; $scope.login = {}; $scope.tabbingActive = false; + + // Load TinyMCE Assets ahead of time in the background for the user + // To help woth first load of the RTE + tinyMceAssets.forEach(function (tinyJsAsset) { + assetsService.loadJs(tinyJsAsset, $scope); + }); + // There are a number of ways to detect when a focus state should be shown when using the tab key and this seems to be the simplest solution. // For more information about this approach, see https://hackernoon.com/removing-that-ugly-focus-ring-and-keeping-it-too-6c8727fefcd2 diff --git a/src/Umbraco.Web.UI/Umbraco/js/main.controller.js b/src/Umbraco.Web.UI/Umbraco/js/main.controller.js index 654bbb1d03..f4bac95767 100644 --- a/src/Umbraco.Web.UI/Umbraco/js/main.controller.js +++ b/src/Umbraco.Web.UI/Umbraco/js/main.controller.js @@ -10,7 +10,7 @@ */ function MainController($scope, $location, appState, treeService, notificationsService, userService, historyService, updateChecker, navigationService, eventsService, - tmhDynamicLocale, localStorageService, editorService, overlayService) { + tmhDynamicLocale, localStorageService, editorService, overlayService, assetsService, tinyMceAssets) { //the null is important because we do an explicit bool check on this in the view $scope.authenticated = null; @@ -21,6 +21,13 @@ function MainController($scope, $location, appState, treeService, notificationsS $scope.search = {}; $scope.login = {}; $scope.tabbingActive = false; + + // Load TinyMCE Assets ahead of time in the background for the user + // To help woth first load of the RTE + tinyMceAssets.forEach(function (tinyJsAsset) { + assetsService.loadJs(tinyJsAsset, $scope); + }); + // There are a number of ways to detect when a focus state should be shown when using the tab key and this seems to be the simplest solution. // For more information about this approach, see https://hackernoon.com/removing-that-ugly-focus-ring-and-keeping-it-too-6c8727fefcd2 From a95360036ddb14202dbe21fb14678fd6a578bb32 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Tue, 20 Aug 2019 11:12:20 +0100 Subject: [PATCH 4/6] Pre-loading this lang JS file does not seem to help Tiny as it does not check its already loaded & it reloads itself anyway (But the plugins work all fine & are checked by Tiny to see if they have been loaded) --- src/Umbraco.Web/JavaScript/TinyMceInitialize.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Umbraco.Web/JavaScript/TinyMceInitialize.js b/src/Umbraco.Web/JavaScript/TinyMceInitialize.js index 1ffcce4a59..6cb9cf6277 100644 --- a/src/Umbraco.Web/JavaScript/TinyMceInitialize.js +++ b/src/Umbraco.Web/JavaScript/TinyMceInitialize.js @@ -1,8 +1,6 @@ [ 'lib/tinymce/tinymce.min.js', - 'lib/tinymce/langs/en_us.js', - 'lib/tinymce/plugins/paste/plugin.min.js', 'lib/tinymce/plugins/anchor/plugin.min.js', 'lib/tinymce/plugins/charmap/plugin.min.js', From 4fc265275bba0e9a6f792a40ba207a91a782cbc2 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Tue, 20 Aug 2019 11:28:02 +0100 Subject: [PATCH 5/6] Fix up unit test for RTE, it was failing as I added the Angular app.value for tinyMceAssets - this ensures we add an empty array of tinymce assets --- .../test/unit/app/propertyeditors/rte-controller.spec.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/test/unit/app/propertyeditors/rte-controller.spec.js b/src/Umbraco.Web.UI.Client/test/unit/app/propertyeditors/rte-controller.spec.js index 9668a03580..274d256a64 100644 --- a/src/Umbraco.Web.UI.Client/test/unit/app/propertyeditors/rte-controller.spec.js +++ b/src/Umbraco.Web.UI.Client/test/unit/app/propertyeditors/rte-controller.spec.js @@ -1,7 +1,9 @@ describe('RTE controller tests', function () { var scope, controllerFactory; - beforeEach(module('umbraco')); + beforeEach(module('umbraco', function ($provide) { + $provide.value('tinyMceAssets', []); + })); beforeEach(inject(function ($rootScope, $controller) { controllerFactory = $controller; @@ -20,4 +22,5 @@ describe('RTE controller tests', function () { }); }); -}); \ No newline at end of file +}); + From bec54a04674215cc26afbd6b5813fb252437c5d8 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Tue, 20 Aug 2019 11:28:29 +0100 Subject: [PATCH 6/6] Remove unecessary change --- src/Umbraco.Web/Editors/BackOfficeController.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Umbraco.Web/Editors/BackOfficeController.cs b/src/Umbraco.Web/Editors/BackOfficeController.cs index ca17f534c4..34022f8f9f 100644 --- a/src/Umbraco.Web/Editors/BackOfficeController.cs +++ b/src/Umbraco.Web/Editors/BackOfficeController.cs @@ -28,7 +28,6 @@ using Umbraco.Web.JavaScript; using Umbraco.Web.Security; using Constants = Umbraco.Core.Constants; using JArray = Newtonsoft.Json.Linq.JArray; -using System.Text; namespace Umbraco.Web.Editors {