From 06400f8db5c57af9ab9e634fd52a65a983f55099 Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 25 Sep 2013 14:29:59 +1000 Subject: [PATCH] Gets the modal content loading in the rte on editor load all in async, fixes an issue with valtogglemsg when used in a modal to ensure we unsubscribe from the events when the modal element is destroyed. --- src/Umbraco.Core/Macros/MacroTagParser.cs | 5 +- src/Umbraco.Tests/Macros/MacroParserTests.cs | 10 ++-- .../validation/valtogglemsg.directive.js | 14 ++++- .../src/common/services/macro.service.js | 6 +- .../src/common/services/tinymce.service.js | 59 ++++++++++++++----- .../common/dialogs/insertmacro.controller.js | 12 ++-- .../common/services/macro-service.spec.js | 22 ++++--- 7 files changed, 82 insertions(+), 46 deletions(-) diff --git a/src/Umbraco.Core/Macros/MacroTagParser.cs b/src/Umbraco.Core/Macros/MacroTagParser.cs index 9ba529f7cd..93a72466ed 100644 --- a/src/Umbraco.Core/Macros/MacroTagParser.cs +++ b/src/Umbraco.Core/Macros/MacroTagParser.cs @@ -25,7 +25,7 @@ namespace Umbraco.Core.Macros /// /// {div class='umb-macro-holder'} /// - /// This could be some macro content + /// {ins}Macro alias: {strong}My Macro{/strong}{/ins} /// {/div} /// /// @@ -53,10 +53,11 @@ namespace Umbraco.Core.Macros sb.Append(match.Groups[1].Value.Trim()); sb.Append(" />"); sb.AppendLine(" -->"); + sb.Append(""); sb.Append("Macro alias: "); sb.Append(""); sb.Append(alias); - sb.Append(""); + sb.Append(""); return sb.ToString(); } //replace with nothing if we couldn't find the syntax for whatever reason diff --git a/src/Umbraco.Tests/Macros/MacroParserTests.cs b/src/Umbraco.Tests/Macros/MacroParserTests.cs index ce5ca3d3a8..1154b741b9 100644 --- a/src/Umbraco.Tests/Macros/MacroParserTests.cs +++ b/src/Umbraco.Tests/Macros/MacroParserTests.cs @@ -20,7 +20,7 @@ namespace Umbraco.Tests.Macros

asdfsadf

-Macro alias: Map
+Macro alias: Map

asdfasdf

", result); } @@ -37,7 +37,7 @@ Macro alias: Map

asdfsadf

-Macro alias: Map
+Macro alias: Map

asdfasdf

", result); } @@ -54,7 +54,7 @@ Macro alias: Map

asdfsadf

-Macro alias: Map
+Macro alias: Map

asdfasdf

", result); } @@ -71,7 +71,7 @@ Macro alias: Map

asdfsadf

-Macro alias: Map
+Macro alias: Map

asdfasdf

", result); } @@ -88,7 +88,7 @@ Macro alias: Map

asdfsadf

-Macro alias: Map
+Macro alias: Map

asdfasdf

", result); } diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/validation/valtogglemsg.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/validation/valtogglemsg.directive.js index e2db686605..4ebbb79200 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/validation/valtogglemsg.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/validation/valtogglemsg.directive.js @@ -43,7 +43,8 @@ function valToggleMsg(serverValidationManager) { } }); - scope.$on("saving", function(ev, args) { + //listen for the saving event (the result is a callback method which is called to unsubscribe) + var unsubscribeSaving = scope.$on("saving", function (ev, args) { showValidation = true; if (formCtrl[attr.valMsgFor].$error[attr.valToggleMsg]) { element.show(); @@ -57,11 +58,20 @@ function valToggleMsg(serverValidationManager) { } }); - scope.$on("saved", function (ev, args) { + //listen for the saved event (the result is a callback method which is called to unsubscribe) + var unsubscribeSaved = scope.$on("saved", function (ev, args) { showValidation = false; element.hide(); }); + //when the element is disposed we need to unsubscribe! + // NOTE: this is very important otherwise if this directive is part of a modal, the listener still exists because the dom + // element might still be there even after the modal has been hidden. + element.bind('$destroy', function () { + unsubscribeSaving(); + unsubscribeSaved(); + }); + } }; } diff --git a/src/Umbraco.Web.UI.Client/src/common/services/macro.service.js b/src/Umbraco.Web.UI.Client/src/common/services/macro.service.js index f6bf63596e..9151b4c159 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/macro.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/macro.service.js @@ -26,11 +26,11 @@ function macroService() { var paramExpression = new RegExp("(\\w+?)=['\"](.*?)['\"]", "g"); var paramMatch; var returnVal = { - alias: alias, - params: [] + macroAlias: alias, + marcoParamsDictionary: {} }; while (paramMatch = paramExpression.exec(paramsChunk)) { - returnVal.params.push({ alias: paramMatch[1], value: paramMatch[2] }); + returnVal.marcoParamsDictionary[paramMatch[1]] = paramMatch[2]; } return returnVal; }, diff --git a/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js b/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js index 6a87ea8a06..d3d0060ff5 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js @@ -162,6 +162,39 @@ function tinyMceService(dialogService, $log, imageHelper, assetsService, $timeou return null; } + /** loads in the macro content async from the server */ + function loadMacroContent($macroDiv, macroData) { + + //if we don't have the macroData, then we'll need to parse it from the macro div + if (!macroData) { + var contents = $macroDiv.contents(); + var comment = _.find(contents, function (item) { + return item.nodeType === 8; + }); + if (!comment) { + throw "Cannot parse the current macro, the syntax in the editor is invalid"; + } + var syntax = comment.textContent.trim(); + var parsed = macroService.parseMacroSyntax(syntax); + macroData = parsed; + } + + var $ins = $macroDiv.find("ins"); + + //show the throbber + $macroDiv.addClass("loading"); + + macroResource.getMacroResultAsHtmlForEditor(macroData.macroAlias, 1234, macroData.marcoParamsDictionary) + .then(function (htmlResult) { + + $macroDiv.removeClass("loading"); + htmlResult = htmlResult.trim(); + if (htmlResult !== "") { + $ins.html(htmlResult); + } + }); + } + /** Adds the button instance */ editor.addButton('umbmacro', { icon: 'custom icon-settings-alt', @@ -217,9 +250,14 @@ function tinyMceService(dialogService, $log, imageHelper, assetsService, $timeou } /** when the contents load we need to find any macros declared and load in their content */ - editor.on("LoadContent", function(o) { - var asdf = editor.getContent(); - alert(asdf); + editor.on("LoadContent", function (o) { + + //get all macro divs and load their content + $(editor.dom.select(".umb-macro-holder.mceNonEditable")).each(function() { + loadMacroContent($(this)); + }); + + }); /** This prevents any other commands from executing when the current element is the macro so the content cannot be edited */ @@ -361,20 +399,9 @@ function tinyMceService(dialogService, $log, imageHelper, assetsService, $timeou editor.selection.setNode(macroDiv); var $macroDiv = $(editor.dom.select("div.umb-macro-holder." + uniqueId)); - var $ins = $macroDiv.find("ins"); - //show the throbber - $macroDiv.addClass("loading"); - - macroResource.getMacroResultAsHtmlForEditor(data.macroAlias, 1234, data.marcoParamsDictionary) - .then(function (htmlResult) { - - $macroDiv.removeClass("loading"); - htmlResult = htmlResult.trim(); - if (htmlResult !== "") { - $ins.html(htmlResult); - } - }); + //async load the macro content + loadMacroContent($macroDiv, data); } }); diff --git a/src/Umbraco.Web.UI.Client/src/views/common/dialogs/insertmacro.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/dialogs/insertmacro.controller.js index c2d77eb5c3..1c8d6b4f0b 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/dialogs/insertmacro.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/common/dialogs/insertmacro.controller.js @@ -25,13 +25,13 @@ function InsertMacroController($scope, entityResource, macroResource, umbPropEdi $scope.macroParams = data; //fill in the data if we are editing this macro - if ($scope.dialogData && $scope.dialogData.macroData && $scope.dialogData.macroData.params) { - _.each($scope.dialogData.macroData.params, function(p) { + if ($scope.dialogData && $scope.dialogData.macroData && $scope.dialogData.macroData.marcoParamsDictionary) { + _.each($scope.dialogData.macroData.marcoParamsDictionary, function (val, key) { var prop = _.find($scope.macroParams, function (item) { - return item.alias == p.alias; + return item.alias == key; }); if (prop) { - prop.value = p.value; + prop.value = val; } }); @@ -111,9 +111,9 @@ function InsertMacroController($scope, entityResource, macroResource, umbPropEdi $scope.macros = data; //check if there's a pre-selected macro and if it exists - if ($scope.dialogData && $scope.dialogData.macroData && $scope.dialogData.macroData.alias) { + if ($scope.dialogData && $scope.dialogData.macroData && $scope.dialogData.macroData.macroAlias) { var found = _.find(data, function (item) { - return item.alias === $scope.dialogData.macroData.alias; + return item.alias === $scope.dialogData.macroData.macroAlias; }); if (found) { //select the macro and go to next screen diff --git a/src/Umbraco.Web.UI.Client/test/unit/common/services/macro-service.spec.js b/src/Umbraco.Web.UI.Client/test/unit/common/services/macro-service.spec.js index 78768cb4e2..f9eb19e57b 100644 --- a/src/Umbraco.Web.UI.Client/test/unit/common/services/macro-service.spec.js +++ b/src/Umbraco.Web.UI.Client/test/unit/common/services/macro-service.spec.js @@ -14,12 +14,11 @@ describe('macro service tests', function () { var result = macroService.parseMacroSyntax(""); expect(result).not.toBeNull(); - expect(result.alias).toBe("Map"); - expect(result.params.length).toBe(2); - expect(result.params[0].alias).toBe("test1"); - expect(result.params[0].value).toBe("asdf"); - expect(result.params[1].alias).toBe("test2"); - expect(result.params[1].value).toBe("hello"); + expect(result.macroAlias).toBe("Map"); + expect(result.marcoParamsDictionary.test1).not.toBeUndefined(); + expect(result.marcoParamsDictionary.test1).toBe("asdf"); + expect(result.marcoParamsDictionary.test2).not.toBeUndefined(); + expect(result.marcoParamsDictionary.test2).toBe("hello"); }); @@ -29,12 +28,11 @@ describe('macro service tests', function () { var result = macroService.parseMacroSyntax(""); expect(result).not.toBeNull(); - expect(result.alias).toBe("Map"); - expect(result.params.length).toBe(2); - expect(result.params[0].alias).toBe("test1"); - expect(result.params[0].value).toBe("asdf"); - expect(result.params[1].alias).toBe("test2"); - expect(result.params[1].value).toBe("hello"); + expect(result.macroAlias).toBe("Map"); + expect(result.marcoParamsDictionary.test1).not.toBeUndefined(); + expect(result.marcoParamsDictionary.test1).toBe("asdf"); + expect(result.marcoParamsDictionary.test2).not.toBeUndefined(); + expect(result.marcoParamsDictionary.test2).toBe("hello"); });