Got the macro dialog working with previously selected macros in the rte and pre-fills the data that was previously there.
This commit is contained in:
@@ -11,7 +11,7 @@ namespace Umbraco.Core.Macros
|
||||
internal class MacroTagParser
|
||||
{
|
||||
private static readonly Regex MacroRteContent = new Regex(@"(<div class=[""']umb-macro-holder.+?[""'].*?>.*?<!--\s*?)(<\?UMBRACO_MACRO.*?/>)(.*?</div>)", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);
|
||||
private static readonly Regex MacroPersistedFormat = new Regex(@"<\?UMBRACO_MACRO macroAlias=[""'](\w+?)[""'].+?/>", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);
|
||||
private static readonly Regex MacroPersistedFormat = new Regex(@"(<\?UMBRACO_MACRO macroAlias=[""'](\w+?)[""'].+?)(?:/>|>.*?</\?UMBRACO_MACRO>)", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);
|
||||
|
||||
/// <summary>
|
||||
/// This formats the persisted string to something useful for the rte so that the macro renders properly since we
|
||||
@@ -33,10 +33,10 @@ namespace Umbraco.Core.Macros
|
||||
{
|
||||
return MacroPersistedFormat.Replace(persistedContent, match =>
|
||||
{
|
||||
if (match.Groups.Count >= 2)
|
||||
if (match.Groups.Count >= 3)
|
||||
{
|
||||
//<div class="umb-macro-holder myMacro mceNonEditable">
|
||||
var alias = match.Groups[1].Value;
|
||||
var alias = match.Groups[2].Value;
|
||||
var sb = new StringBuilder("<div class=\"umb-macro-holder ");
|
||||
sb.Append(alias);
|
||||
sb.Append(" mceNonEditable\"");
|
||||
@@ -50,7 +50,8 @@ namespace Umbraco.Core.Macros
|
||||
}
|
||||
sb.AppendLine(">");
|
||||
sb.Append("<!-- ");
|
||||
sb.Append(match.Groups[0].Value);
|
||||
sb.Append(match.Groups[1].Value.Trim());
|
||||
sb.Append(" />");
|
||||
sb.AppendLine(" -->");
|
||||
sb.Append("Macro alias: ");
|
||||
sb.Append("<strong>");
|
||||
|
||||
@@ -24,6 +24,74 @@ Macro alias: <strong>Map</strong></div>
|
||||
<p>asdfasdf</p>", result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Format_RTE_Data_For_Editor_Closing_Tag()
|
||||
{
|
||||
var content = @"<p>asdfasdf</p>
|
||||
<p>asdfsadf</p>
|
||||
<?UMBRACO_MACRO macroAlias=""Map"" ></?UMBRACO_MACRO>
|
||||
<p>asdfasdf</p>";
|
||||
var result = MacroTagParser.FormatRichTextPersistedDataForEditor(content, new Dictionary<string, string>() { { "test1", "value1" }, { "test2", "value2" } });
|
||||
|
||||
Assert.AreEqual(@"<p>asdfasdf</p>
|
||||
<p>asdfsadf</p>
|
||||
<div class=""umb-macro-holder Map mceNonEditable"" test1=""value1"" test2=""value2"">
|
||||
<!-- <?UMBRACO_MACRO macroAlias=""Map"" /> -->
|
||||
Macro alias: <strong>Map</strong></div>
|
||||
<p>asdfasdf</p>", result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Format_RTE_Data_For_Editor_With_Params()
|
||||
{
|
||||
var content = @"<p>asdfasdf</p>
|
||||
<p>asdfsadf</p>
|
||||
<?UMBRACO_MACRO macroAlias=""Map"" test1=""value1"" test2=""value2"" />
|
||||
<p>asdfasdf</p>";
|
||||
var result = MacroTagParser.FormatRichTextPersistedDataForEditor(content, new Dictionary<string, string>() { { "test1", "value1" }, { "test2", "value2" } });
|
||||
|
||||
Assert.AreEqual(@"<p>asdfasdf</p>
|
||||
<p>asdfsadf</p>
|
||||
<div class=""umb-macro-holder Map mceNonEditable"" test1=""value1"" test2=""value2"">
|
||||
<!-- <?UMBRACO_MACRO macroAlias=""Map"" test1=""value1"" test2=""value2"" /> -->
|
||||
Macro alias: <strong>Map</strong></div>
|
||||
<p>asdfasdf</p>", result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Format_RTE_Data_For_Editor_With_Params_Closing_Tag()
|
||||
{
|
||||
var content = @"<p>asdfasdf</p>
|
||||
<p>asdfsadf</p>
|
||||
<?UMBRACO_MACRO macroAlias=""Map"" test1=""value1"" test2=""value2"" ></?UMBRACO_MACRO>
|
||||
<p>asdfasdf</p>";
|
||||
var result = MacroTagParser.FormatRichTextPersistedDataForEditor(content, new Dictionary<string, string>() { { "test1", "value1" }, { "test2", "value2" } });
|
||||
|
||||
Assert.AreEqual(@"<p>asdfasdf</p>
|
||||
<p>asdfsadf</p>
|
||||
<div class=""umb-macro-holder Map mceNonEditable"" test1=""value1"" test2=""value2"">
|
||||
<!-- <?UMBRACO_MACRO macroAlias=""Map"" test1=""value1"" test2=""value2"" /> -->
|
||||
Macro alias: <strong>Map</strong></div>
|
||||
<p>asdfasdf</p>", result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Format_RTE_Data_For_Editor_With_Params_Closing_Tag_And_Content()
|
||||
{
|
||||
var content = @"<p>asdfasdf</p>
|
||||
<p>asdfsadf</p>
|
||||
<?UMBRACO_MACRO macroAlias=""Map"" test1=""value1"" test2=""value2"" ><img src='blah.jpg'/></?UMBRACO_MACRO>
|
||||
<p>asdfasdf</p>";
|
||||
var result = MacroTagParser.FormatRichTextPersistedDataForEditor(content, new Dictionary<string, string>() { { "test1", "value1" }, { "test2", "value2" } });
|
||||
|
||||
Assert.AreEqual(@"<p>asdfasdf</p>
|
||||
<p>asdfsadf</p>
|
||||
<div class=""umb-macro-holder Map mceNonEditable"" test1=""value1"" test2=""value2"">
|
||||
<!-- <?UMBRACO_MACRO macroAlias=""Map"" test1=""value1"" test2=""value2"" /> -->
|
||||
Macro alias: <strong>Map</strong></div>
|
||||
<p>asdfasdf</p>", result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Format_RTE_Data_For_Persistence()
|
||||
{
|
||||
|
||||
@@ -10,6 +10,31 @@ function macroService() {
|
||||
|
||||
return {
|
||||
|
||||
/** parses the special macro syntax like <?UMBRACO_MACRO macroAlias="Map" /> and returns an object with the macro alias and it's parameters */
|
||||
parseMacroSyntax: function (syntax) {
|
||||
|
||||
var expression = /(<\?UMBRACO_MACRO macroAlias=["'](\w+?)["'].+?)(\/>|>.*?<\/\?UMBRACO_MACRO>)/im;
|
||||
var match = expression.exec(syntax);
|
||||
if (!match || match.length < 3) {
|
||||
return null;
|
||||
}
|
||||
var alias = match[2];
|
||||
|
||||
//this will leave us with just the parameters
|
||||
var paramsChunk = match[1].trim().replace(new RegExp("UMBRACO_MACRO macroAlias=[\"']" + alias + "[\"']"), "").trim();
|
||||
|
||||
var paramExpression = new RegExp("(\\w+?)=['\"](.*?)['\"]", "g");
|
||||
var paramMatch;
|
||||
var returnVal = {
|
||||
alias: alias,
|
||||
params: []
|
||||
};
|
||||
while (paramMatch = paramExpression.exec(paramsChunk)) {
|
||||
returnVal.params.push({ alias: paramMatch[1], value: paramMatch[2] });
|
||||
}
|
||||
return returnVal;
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc function
|
||||
* @name generateWebFormsSyntax
|
||||
@@ -25,7 +50,7 @@ function macroService() {
|
||||
|
||||
// <?UMBRACO_MACRO macroAlias="BlogListPosts" />
|
||||
|
||||
var macroString = '<?UMBRACO_MACRO ';
|
||||
var macroString = '<?UMBRACO_MACRO macroAlias=\"' + args.macroAlias + "\" ";
|
||||
|
||||
if (args.macroParams) {
|
||||
for (var i = 0; i < args.macroParams.length; i++) {
|
||||
@@ -35,7 +60,7 @@ function macroService() {
|
||||
}
|
||||
}
|
||||
|
||||
macroString += "macroAlias=\"" + args.macroAlias + "\" />";
|
||||
macroString += "/>";
|
||||
|
||||
return macroString;
|
||||
},
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* @description
|
||||
* A service containing all logic for all of the Umbraco TinyMCE plugins
|
||||
*/
|
||||
function tinyMceService(dialogService, $log, imageHelper, assetsService, $timeout, macroResource) {
|
||||
function tinyMceService(dialogService, $log, imageHelper, assetsService, $timeout, macroResource, macroService) {
|
||||
return {
|
||||
|
||||
/**
|
||||
@@ -143,6 +143,25 @@ function tinyMceService(dialogService, $log, imageHelper, assetsService, $timeou
|
||||
|
||||
});
|
||||
|
||||
/**
|
||||
* Because the macro gets wrapped in a P tag because of the way 'enter' works, this
|
||||
* method will return the macro element if not wrapped in a p, or the p if the macro
|
||||
* element is the only one inside of it even if we are deep inside an element inside the macro
|
||||
*/
|
||||
function getRealMacroElem(element) {
|
||||
var e = $(element).closest(".umb-macro-holder");
|
||||
if (e.length > 0) {
|
||||
if (e.get(0).parentNode.nodeName === "P") {
|
||||
//now check if we're the only element
|
||||
if (element.parentNode.childNodes.length === 1) {
|
||||
return e.get(0).parentNode;
|
||||
}
|
||||
}
|
||||
return e.get(0);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Adds the button instance */
|
||||
editor.addButton('umbmacro', {
|
||||
icon: 'custom icon-settings-alt',
|
||||
@@ -152,25 +171,6 @@ function tinyMceService(dialogService, $log, imageHelper, assetsService, $timeou
|
||||
var ctrl = this;
|
||||
var isOnMacroElement = false;
|
||||
|
||||
/**
|
||||
* Because the macro gets wrapped in a P tag because of the way 'enter' works, this
|
||||
* method will return the macro element if not wrapped in a p, or the p if the macro
|
||||
* element is the only one inside of it even if we are deep inside an element inside the macro
|
||||
*/
|
||||
function getRealMacroElem(element) {
|
||||
var e = $(element).closest(".umb-macro-holder");
|
||||
if (e.length > 0) {
|
||||
if (e.get(0).parentNode.nodeName === "P") {
|
||||
//now check if we're the only element
|
||||
if (element.parentNode.childNodes.length === 1) {
|
||||
return e.get(0).parentNode;
|
||||
}
|
||||
}
|
||||
return e.get(0);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a node change handler, test if we're editing a macro and select the whole thing, then set our isOnMacroElement flag.
|
||||
* If we change the selection inside this method, then we end up in an infinite loop, so we have to remove ourselves
|
||||
@@ -310,8 +310,32 @@ function tinyMceService(dialogService, $log, imageHelper, assetsService, $timeou
|
||||
/** The insert macro button click event handler */
|
||||
onclick: function () {
|
||||
|
||||
var dialogData;
|
||||
|
||||
//when we click we could have a macro already selected and in that case we'll want to edit the current parameters
|
||||
//so we'll need to extract them and submit them to the dialog.
|
||||
var macroElement = editor.selection.getNode();
|
||||
macroElement = getRealMacroElem(macroElement);
|
||||
if (macroElement) {
|
||||
//we have a macro selected so we'll need to parse it's alias and parameters
|
||||
var contents = $(macroElement).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);
|
||||
dialogData = {
|
||||
macroData: parsed
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
dialogService.macroPicker({
|
||||
scope: $scope,
|
||||
dialogData : dialogData,
|
||||
callback: function(data) {
|
||||
|
||||
//put the macro syntax in comments, we will parse this out on the server side to be used
|
||||
|
||||
@@ -23,6 +23,19 @@ function InsertMacroController($scope, entityResource, macroResource, umbPropEdi
|
||||
} else {
|
||||
$scope.wizardStep = "paramSelect";
|
||||
$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) {
|
||||
var prop = _.find($scope.macroParams, function (item) {
|
||||
return item.alias == p.alias;
|
||||
});
|
||||
if (prop) {
|
||||
prop.value = p.value;
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -82,26 +95,35 @@ function InsertMacroController($scope, entityResource, macroResource, umbPropEdi
|
||||
|
||||
};
|
||||
|
||||
//here we check to see if we've been passed a selected macro and if so we'll set the
|
||||
//editor to start with parameter editing
|
||||
if ($scope.dialogData && $scope.dialogData.macroData) {
|
||||
$scope.wizardStep = "paramSelect";
|
||||
}
|
||||
|
||||
//get the macro list
|
||||
entityResource.getAll("Macro")
|
||||
.then(function (data) {
|
||||
.then(function (data) {
|
||||
|
||||
$scope.macros = data;
|
||||
|
||||
|
||||
//check if there's a pre-selected macro and if it exists
|
||||
if ($scope.dialogData.selectedAlias) {
|
||||
var found = _.find(data, function(item) {
|
||||
return item.alias === $scope.dialogData.selectedAlias;
|
||||
if ($scope.dialogData && $scope.dialogData.macroData && $scope.dialogData.macroData.alias) {
|
||||
var found = _.find(data, function (item) {
|
||||
return item.alias === $scope.dialogData.macroData.alias;
|
||||
});
|
||||
if (found) {
|
||||
//select the macro and go to next screen
|
||||
$scope.selectedMacro = found.id;
|
||||
editParams();
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
//we don't have a pre-selected macro so ensure the correct step is set
|
||||
$scope.wizardStep = "macroSelect";
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
angular.module("umbraco").controller("Umbraco.Dialogs.InsertMacroController", InsertMacroController);
|
||||
|
||||
@@ -7,6 +7,40 @@ describe('macro service tests', function () {
|
||||
macroService = $injector.get('macroService');
|
||||
}));
|
||||
|
||||
describe('generates macro syntax', function() {
|
||||
|
||||
it('can parse syntax for macros', function () {
|
||||
|
||||
var result = macroService.parseMacroSyntax("<?UMBRACO_MACRO macroAlias='Map' test1=\"asdf\" test2='hello' />");
|
||||
|
||||
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");
|
||||
|
||||
|
||||
});
|
||||
|
||||
it('can parse syntax for macros with body', function () {
|
||||
|
||||
var result = macroService.parseMacroSyntax("<?UMBRACO_MACRO macroAlias='Map' test1=\"asdf\" test2='hello' ><img src='blah.jpg'/></?UMBRACO_MACRO>");
|
||||
|
||||
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");
|
||||
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('generates macro syntax', function () {
|
||||
|
||||
it('can generate syntax for macros', function () {
|
||||
@@ -21,7 +55,7 @@ describe('macro service tests', function () {
|
||||
});
|
||||
|
||||
expect(syntax).
|
||||
toBe("<?UMBRACO_MACRO param1=\"value1\" param2=\"value2\" param3=\"value3\" macroAlias=\"myMacro\" />");
|
||||
toBe("<?UMBRACO_MACRO macroAlias=\"myMacro\" param1=\"value1\" param2=\"value2\" param3=\"value3\" />");
|
||||
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user