diff --git a/src/Umbraco.Core/Manifest/ManifestParser.cs b/src/Umbraco.Core/Manifest/ManifestParser.cs
index e772cd3df7..be3fcb238e 100644
--- a/src/Umbraco.Core/Manifest/ManifestParser.cs
+++ b/src/Umbraco.Core/Manifest/ManifestParser.cs
@@ -33,7 +33,10 @@ namespace Umbraco.Core.Manifest
///
internal static IEnumerable GetPropertyEditors(JArray jsonEditors)
{
- return JsonConvert.DeserializeObject>(jsonEditors.ToString(), new PropertyEditorConverter());
+ return JsonConvert.DeserializeObject>(
+ jsonEditors.ToString(),
+ new PropertyEditorConverter(),
+ new PreValueFieldConverter());
}
///
diff --git a/src/Umbraco.Core/Manifest/PropertyEditorConverter.cs b/src/Umbraco.Core/Manifest/PropertyEditorConverter.cs
index 9b502315e7..a5199af379 100644
--- a/src/Umbraco.Core/Manifest/PropertyEditorConverter.cs
+++ b/src/Umbraco.Core/Manifest/PropertyEditorConverter.cs
@@ -27,6 +27,28 @@ namespace Umbraco.Core.Manifest
target.StaticallyDefinedValueEditor.Validators = new List();
}
+ if (jObject["preValueEditor"] != null)
+ {
+ target.StaticallyDefinedPreValueEditor.Fields = new List();
+ }
+
+ base.Deserialize(jObject, target, serializer);
+ }
+ }
+
+ internal class PreValueFieldConverter : JsonCreationConverter
+ {
+ protected override PreValueField Create(Type objectType, JObject jObject)
+ {
+ return new PreValueField()
+ {
+ //assign manifest validators so the serialization process can continue
+ Validators = new List()
+ };
+ }
+
+ protected override void Deserialize(JObject jObject, PreValueField target, JsonSerializer serializer)
+ {
base.Deserialize(jObject, target, serializer);
}
}
diff --git a/src/Umbraco.Core/PropertyEditors/PreValueEditor.cs b/src/Umbraco.Core/PropertyEditors/PreValueEditor.cs
index 3bc978177a..c3917e2227 100644
--- a/src/Umbraco.Core/PropertyEditors/PreValueEditor.cs
+++ b/src/Umbraco.Core/PropertyEditors/PreValueEditor.cs
@@ -1,4 +1,5 @@
using System.Collections.Generic;
+using System.Linq;
using Newtonsoft.Json;
namespace Umbraco.Core.PropertyEditors
@@ -7,20 +8,26 @@ namespace Umbraco.Core.PropertyEditors
/// Defines a pre-value editor
///
///
- /// The Json serialization attributes are required for manifest property editors to work
+ /// A pre-value editor is made up of multiple pre-value fields, each field defines a key that the value is stored against.
+ /// Each field can have any editor and the value from each field can store any data such as a simple string or a json structure.
+ ///
+ /// The Json serialization attributes are required for manifest property editors to work.
///
public class PreValueEditor
{
- ///
- /// The full virtual path or the relative path to the current Umbraco folder for the angular view
- ///
- [JsonProperty("view")]
- public string View { get; set; }
+ public PreValueEditor()
+ {
+ Fields = Enumerable.Empty();
+ }
///
- /// A collection of validators for the pre value editor
+ /// A collection of pre-value fields to be edited
///
- [JsonProperty("validation")]
- public IEnumerable Validators { get; set; }
+ ///
+ /// If fields are specified then the master View and Validators will be ignored
+ ///
+ [JsonProperty("fields")]
+ public IEnumerable Fields { get; set; }
+
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/PropertyEditors/PreValueField.cs b/src/Umbraco.Core/PropertyEditors/PreValueField.cs
new file mode 100644
index 0000000000..ec8283c1b9
--- /dev/null
+++ b/src/Umbraco.Core/PropertyEditors/PreValueField.cs
@@ -0,0 +1,47 @@
+using System.Collections.Generic;
+using Newtonsoft.Json;
+
+namespace Umbraco.Core.PropertyEditors
+{
+ ///
+ /// Defines a pre value editable field
+ ///
+ public class PreValueField
+ {
+ ///
+ /// The name to display for this pre-value field
+ ///
+ [JsonProperty("label", Required = Required.Always)]
+ public string Name { get; set; }
+
+ ///
+ /// The description to display for this pre-value field
+ ///
+ [JsonProperty("description")]
+ public string Description { get; set; }
+
+ ///
+ /// Specifies whether to hide the label for the pre-value
+ ///
+ [JsonProperty("hideLabel")]
+ public bool HideLabel { get; set; }
+
+ ///
+ /// The key to store the pre-value against
+ ///
+ [JsonProperty("key", Required = Required.Always)]
+ public string Key { get; set; }
+
+ ///
+ /// The view to render for the field
+ ///
+ [JsonProperty("view", Required = Required.Always)]
+ public string View { get; set; }
+
+ ///
+ /// A collection of validators for the pre value field
+ ///
+ [JsonProperty("validation")]
+ public IEnumerable Validators { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Core/PropertyEditors/PropertyEditor.cs b/src/Umbraco.Core/PropertyEditors/PropertyEditor.cs
index bb69b0a445..e86915bb49 100644
--- a/src/Umbraco.Core/PropertyEditors/PropertyEditor.cs
+++ b/src/Umbraco.Core/PropertyEditors/PropertyEditor.cs
@@ -32,7 +32,6 @@ namespace Umbraco.Core.PropertyEditors
StaticallyDefinedValueEditor.ValueType = att.ValueType;
StaticallyDefinedValueEditor.View = att.EditorView;
- StaticallyDefinedPreValueEditor.View = att.PreValueEditorView;
}
}
@@ -60,7 +59,7 @@ namespace Umbraco.Core.PropertyEditors
[JsonProperty("name", Required = Required.Always)]
public string Name { get; internal set; }
- [JsonProperty("editor")]
+ [JsonProperty("editor", Required = Required.Always)]
public ValueEditor ValueEditor
{
get { return CreateValueEditor(); }
@@ -105,7 +104,18 @@ namespace Umbraco.Core.PropertyEditors
///
///
protected virtual PreValueEditor CreatePreValueEditor()
- {
+ {
+ if (StaticallyDefinedPreValueEditor != null)
+ {
+ foreach (var f in StaticallyDefinedPreValueEditor.Fields)
+ {
+ //detect if the view is a virtual path (in most cases, yes) then convert it
+ if (f.View.StartsWith("~/"))
+ {
+ f.View = IOHelper.ResolveUrl(f.View);
+ }
+ }
+ }
return StaticallyDefinedPreValueEditor;
}
diff --git a/src/Umbraco.Core/PropertyEditors/ValidatorBase.cs b/src/Umbraco.Core/PropertyEditors/ValidatorBase.cs
index 1ce79bf130..c75d1eb2d6 100644
--- a/src/Umbraco.Core/PropertyEditors/ValidatorBase.cs
+++ b/src/Umbraco.Core/PropertyEditors/ValidatorBase.cs
@@ -11,7 +11,11 @@ namespace Umbraco.Core.PropertyEditors
///
/// Validates the object with the resolved ValueValidator found for this type
///
- ///
+ ///
+ /// Depending on what is being validated, this value can be a json structure representing an editor's model, it could be a single
+ /// string representing an editor's model, this class structure is also used to validate pre-values and in that case this value
+ /// could be a json structure representing the entire pre-value model or it could ba a single value representing a pre-value field.
+ ///
/// The current pre-values stored for the data type
/// The property editor instance that we are validating for
///
diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj
index 72d2d64f53..cabf7e59e4 100644
--- a/src/Umbraco.Core/Umbraco.Core.csproj
+++ b/src/Umbraco.Core/Umbraco.Core.csproj
@@ -571,6 +571,7 @@
+
diff --git a/src/Umbraco.Tests/Manifest/ManifestParserTests.cs b/src/Umbraco.Tests/Manifest/ManifestParserTests.cs
index f5da535b70..1e631bb09a 100644
--- a/src/Umbraco.Tests/Manifest/ManifestParserTests.cs
+++ b/src/Umbraco.Tests/Manifest/ManifestParserTests.cs
@@ -14,6 +14,63 @@ namespace Umbraco.Belle.Tests
public class ManifestParserTests
{
+ [Test]
+ public void Parse_Property_Editors_With_Pre_Vals()
+ {
+
+ var a = JsonConvert.DeserializeObject(@"[
+ {
+ id: '0EEBB7CE-51BA-4F6B-9D9C-78BB3314366C',
+ name: 'Test 1',
+ editor: {
+ view: '~/App_Plugins/MyPackage/PropertyEditors/MyEditor.html',
+ valueType: 'int',
+ validation: [
+ {
+ type: 'Required'
+ },
+ {
+ type: 'Regex',
+ value: '\\d*'
+ },
+ ]
+ },
+ preValueEditor: {
+ fields: [
+ {
+ label: 'Some config 1',
+ key: 'key1',
+ view: '~/App_Plugins/MyPackage/PropertyEditors/Views/pre-val1.html',
+ validation: [
+ {
+ type: 'Required'
+ }
+ ]
+ },
+ {
+ label: 'Some config 2',
+ key: 'key2',
+ view: '~/App_Plugins/MyPackage/PropertyEditors/Views/pre-val2.html'
+ }
+ ]
+ }
+ }
+]");
+ var parser = ManifestParser.GetPropertyEditors(a);
+
+ Assert.AreEqual(1, parser.Count());
+ Assert.AreEqual(2, parser.ElementAt(0).PreValueEditor.Fields.Count());
+ Assert.AreEqual("key1", parser.ElementAt(0).PreValueEditor.Fields.ElementAt(0).Key);
+ Assert.AreEqual("Some config 1", parser.ElementAt(0).PreValueEditor.Fields.ElementAt(0).Name);
+ Assert.AreEqual("/App_Plugins/MyPackage/PropertyEditors/Views/pre-val1.html", parser.ElementAt(0).PreValueEditor.Fields.ElementAt(0).View);
+ Assert.AreEqual(1, parser.ElementAt(0).PreValueEditor.Fields.ElementAt(0).Validators.Count());
+
+ Assert.AreEqual("key2", parser.ElementAt(0).PreValueEditor.Fields.ElementAt(1).Key);
+ Assert.AreEqual("Some config 2", parser.ElementAt(0).PreValueEditor.Fields.ElementAt(1).Name);
+ Assert.AreEqual("/App_Plugins/MyPackage/PropertyEditors/Views/pre-val2.html", parser.ElementAt(0).PreValueEditor.Fields.ElementAt(1).View);
+ Assert.AreEqual(0, parser.ElementAt(0).PreValueEditor.Fields.ElementAt(1).Validators.Count());
+ }
+
[Test]
public void Parse_Property_Editors()
{
@@ -39,22 +96,25 @@ namespace Umbraco.Belle.Tests
{
id: '1FCF5C39-5FC7-4BCE-AFBE-6500D9EBA261',
name: 'Test 2',
+ defaultConfig: { key1: 'some default pre val' },
editor: {
view: '~/App_Plugins/MyPackage/PropertyEditors/CsvEditor.html'
}
- },
+ }
]");
var parser = ManifestParser.GetPropertyEditors(a);
Assert.AreEqual(2, parser.Count());
Assert.AreEqual(new Guid("0EEBB7CE-51BA-4F6B-9D9C-78BB3314366C"), parser.ElementAt(0).Id);
Assert.AreEqual("Test 1", parser.ElementAt(0).Name);
- Assert.AreEqual("~/App_Plugins/MyPackage/PropertyEditors/MyEditor.html", parser.ElementAt(0).ValueEditor.View);
+ Assert.AreEqual("/App_Plugins/MyPackage/PropertyEditors/MyEditor.html", parser.ElementAt(0).ValueEditor.View);
Assert.AreEqual("int", parser.ElementAt(0).ValueEditor.ValueType);
Assert.AreEqual(2, parser.ElementAt(0).ValueEditor.Validators.Count());
Assert.AreEqual(new Guid("1FCF5C39-5FC7-4BCE-AFBE-6500D9EBA261"), parser.ElementAt(1).Id);
Assert.AreEqual("Test 2", parser.ElementAt(1).Name);
+ Assert.IsTrue(parser.ElementAt(1).DefaultPreValues.ContainsKey("key1"));
+ Assert.AreEqual("some default pre val", parser.ElementAt(1).DefaultPreValues["key1"]);
}
[Test]
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/umbeditor.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/umbeditor.directive.js
index dfb802e4b3..7446ef8f16 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/umbeditor.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/umbeditor.directive.js
@@ -9,7 +9,8 @@ angular.module("umbraco.directives")
.directive('umbEditor', function (umbPropEditorHelper) {
return {
scope: {
- model: "="
+ model: "=",
+ isPreValue: "@"
},
require: "^form",
restrict: 'E',
@@ -26,7 +27,7 @@ angular.module("umbraco.directives")
scope.model.alias = Math.random().toString(36).slice(2);
}
- scope.propertyEditorView = umbPropEditorHelper.getViewPath(scope.model.view);
+ scope.propertyEditorView = umbPropEditorHelper.getViewPath(scope.model.view, scope.isPreValue);
}
};
});
\ No newline at end of file
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/valpropertymsg.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/valpropertymsg.directive.js
index 8ad52c4df4..119f6202db 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/valpropertymsg.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/valpropertymsg.directive.js
@@ -36,11 +36,7 @@ function valPropertyMsg(serverValidationManager) {
//listen for error changes
scope.$watch("formCtrl.$error", function () {
- if (formCtrl.$valid === undefined) {
- return;
- }
-
- if (!formCtrl.$valid) {
+ if (formCtrl.$invalid) {
//first we need to check if the valPropertyMsg validity is invalid
if (formCtrl.$error.valPropertyMsg && formCtrl.$error.valPropertyMsg.length > 0) {
@@ -53,7 +49,11 @@ function valPropertyMsg(serverValidationManager) {
hasError = true;
//update the validation message if we don't already have one assigned.
if (showValidation && scope.errorMsg === "") {
- var err = serverValidationManager.getPropertyError(scope.property.alias, "");
+ var err;
+ //this can be null if no property was assigned
+ if (scope.property) {
+ err = serverValidationManager.getPropertyError(scope.property.alias, "");
+ }
scope.errorMsg = err ? err.errorMsg : "Property has errors";
}
}
@@ -72,7 +72,11 @@ function valPropertyMsg(serverValidationManager) {
scope.$on("saving", function (ev, args) {
showValidation = true;
if (hasError && scope.errorMsg === "") {
- var err = serverValidationManager.getPropertyError(scope.property.alias, "");
+ var err;
+ //this can be null if no property was assigned
+ if (scope.property) {
+ err = serverValidationManager.getPropertyError(scope.property.alias, "");
+ }
scope.errorMsg = err ? err.errorMsg : "Property has errors";
}
else if (!hasError) {
@@ -109,27 +113,30 @@ function valPropertyMsg(serverValidationManager) {
// It's important to note that we need to subscribe to server validation changes here because we always must
// indicate that a content property is invalid at the property level since developers may not actually implement
// the correct field validation in their property editors.
- serverValidationManager.subscribe(scope.property.alias, "", function (isValid, propertyErrors, allErrors) {
- hasError = !isValid;
- if (hasError) {
- //set the error message to the server message
- scope.errorMsg = propertyErrors[0].errorMsg;
- //flag that the current validator is invalid
- formCtrl.$setValidity('valPropertyMsg', false);
- }
- else {
- scope.errorMsg = "";
- //flag that the current validator is valid
- formCtrl.$setValidity('valPropertyMsg', true);
- }
- });
- //when the element is disposed we need to unsubscribe!
- // NOTE: this is very important otherwise when this controller re-binds the previous subscriptsion will remain
- // but they are a different callback instance than the above.
- element.bind('$destroy', function () {
- serverValidationManager.unsubscribe(scope.property.alias, "");
- });
+ if (scope.property) { //this can be null if no property was assigned
+ serverValidationManager.subscribe(scope.property.alias, "", function(isValid, propertyErrors, allErrors) {
+ hasError = !isValid;
+ if (hasError) {
+ //set the error message to the server message
+ scope.errorMsg = propertyErrors[0].errorMsg;
+ //flag that the current validator is invalid
+ formCtrl.$setValidity('valPropertyMsg', false);
+ }
+ else {
+ scope.errorMsg = "";
+ //flag that the current validator is valid
+ formCtrl.$setValidity('valPropertyMsg', true);
+ }
+ });
+
+ //when the element is disposed we need to unsubscribe!
+ // NOTE: this is very important otherwise when this controller re-binds the previous subscriptsion will remain
+ // but they are a different callback instance than the above.
+ element.bind('$destroy', function() {
+ serverValidationManager.unsubscribe(scope.property.alias, "");
+ });
+ }
}
};
}
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/valregex.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/valregex.directive.js
index c3b832f17e..3edb230d0d 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/valregex.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/valregex.directive.js
@@ -12,13 +12,12 @@ function valRegex() {
link: function (scope, elm, attrs, ctrl) {
var regex;
- if (scope[attrs.valRegex]) {
+ try {
regex = new RegExp(scope.$eval(attrs.valRegex));
}
- else {
+ catch(e) {
regex = new RegExp(attrs.valRegex);
}
-
var patternValidator = function (viewValue) {
//NOTE: we don't validate on empty values, use required validator for that
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/valtab.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/valtab.directive.js
index 5d6d3ec5d9..1df0c3459d 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/valtab.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/valtab.directive.js
@@ -18,14 +18,10 @@ function valTab() {
scope.tabHasError = false;
//watch the current form's validation for the current field name
- scope.$watch("formCtrl.$valid", function (isValid, lastValue) {
- if (isValid === undefined) {
- return;
- }
-
+ scope.$watch("formCtrl.$valid", function () {
var tabContent = element.closest(".umb-panel").find("#" + tabId);
- if (!isValid) {
+ if (formCtrl.$invalid) {
//check if the validation messages are contained inside of this tabs
if (tabContent.find(".ng-invalid").length > 0) {
scope.tabHasError = true;
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/valtogglemsg.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/valtogglemsg.directive.js
index e324e6ae4e..273e153b37 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/valtogglemsg.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/valtogglemsg.directive.js
@@ -14,18 +14,19 @@ function valToggleMsg(serverValidationManager) {
if (!attr.valMsgFor){
throw "valToggleMsg requires that the attribute valMsgFor exists on the element";
}
+ if (!formCtrl[attr.valMsgFor]) {
+ throw "valToggleMsg cannot find field " + attr.valMsgFor + " on form " + formCtrl.$name;
+ }
//assign the form control to our isolated scope so we can watch it's values
scope.formCtrl = formCtrl;
//if there's any remaining errors in the server validation service then we should show them.
var showValidation = serverValidationManager.items.length > 0;
- var hasError = false;
//add a watch to the validator for the value (i.e. myForm.value.$error.required )
- scope.$watch(formCtrl.$name + "." + attr.valMsgFor + ".$error." + attr.valToggleMsg, function (isInvalid, oldValue) {
- hasError = isInvalid;
- if (hasError && showValidation) {
+ scope.$watch("formCtrl." + attr.valMsgFor + ".$error." + attr.valToggleMsg, function () {
+ if (formCtrl[attr.valMsgFor].$error[attr.valToggleMsg] && showValidation) {
element.show();
}
else {
@@ -35,7 +36,7 @@ function valToggleMsg(serverValidationManager) {
scope.$on("saving", function(ev, args) {
showValidation = true;
- if (hasError) {
+ if (formCtrl[attr.valMsgFor].$error[attr.valToggleMsg]) {
element.show();
}
else {
diff --git a/src/Umbraco.Web.UI.Client/src/common/mocks/resources/datatype.mocks.js b/src/Umbraco.Web.UI.Client/src/common/mocks/resources/datatype.mocks.js
index 6f0c21fa67..7cb3fe5daf 100644
--- a/src/Umbraco.Web.UI.Client/src/common/mocks/resources/datatype.mocks.js
+++ b/src/Umbraco.Web.UI.Client/src/common/mocks/resources/datatype.mocks.js
@@ -2,30 +2,84 @@ angular.module('umbraco.mocks').
factory('dataTypeMocks', ['$httpBackend', 'mocksUtils', function ($httpBackend, mocksUtils) {
'use strict';
- function returnNodebyId(status, data, headers) {
+ function returnById(status, data, headers) {
if (!mocksUtils.checkAuth()) {
return [401, null, null];
}
var id = mocksUtils.getParameterByName(data, "id") || 1234;
-
+
+ var selectedId = String.CreateGuid();
+
var dataType = {
id: id,
- name: "Data type " + id,
- selectedEditor: String.CreateGuid()
+ name: "Simple editor " + id,
+ selectedEditor: selectedId,
+ availableEditors: [
+ { name: "Simple editor 1", editorId: String.CreateGuid() },
+ { name: "Simple editor 2", editorId: String.CreateGuid() },
+ { name: "Simple editor 3", editorId: selectedId },
+ { name: "Simple editor 4", editorId: String.CreateGuid() },
+ { name: "Simple editor 5", editorId: String.CreateGuid() },
+ { name: "Simple editor 6", editorId: String.CreateGuid() }
+ ],
+ preValues: [
+ {
+ label: "Custom pre value 1",
+ description: "Enter a value for this pre-value",
+ key: "myPreVal",
+ view: "requiredfield",
+ validation: [
+ {
+ type: "Required"
+ }
+ ]
+ },
+ {
+ label: "Custom pre value 2",
+ description: "Enter a value for this pre-value",
+ key: "myPreVal",
+ view: "requiredfield",
+ validation: [
+ {
+ type: "Required"
+ }
+ ]
+ }
+ ]
};
return [200, dataType, null];
}
+ function returnEmpty(status, data, headers) {
+ if (!mocksUtils.checkAuth()) {
+ return [401, null, null];
+ }
+
+ var response = returnById(200, "", null);
+ var node = response[1];
+
+ node.name = "";
+ node.selectedEditor = "";
+ node.id = 0;
+ node.preValues = [];
+
+ return response;
+ }
return {
register: function() {
- $httpBackend
- .whenGET(mocksUtils.urlRegex('/umbraco/UmbracoApi/DataType/GetById'))
- .respond(returnNodebyId);
+
+ $httpBackend
+ .whenGET(mocksUtils.urlRegex('/umbraco/UmbracoApi/DataType/GetById'))
+ .respond(returnById);
+
+ $httpBackend
+ .whenGET(mocksUtils.urlRegex('/umbraco/UmbracoApi/DataType/GetEmpty'))
+ .respond(returnEmpty);
},
expectGetById: function() {
$httpBackend
diff --git a/src/Umbraco.Web.UI.Client/src/common/mocks/resources/tree.mocks.js b/src/Umbraco.Web.UI.Client/src/common/mocks/resources/tree.mocks.js
index 6df4bf4071..3e92067787 100644
--- a/src/Umbraco.Web.UI.Client/src/common/mocks/resources/tree.mocks.js
+++ b/src/Umbraco.Web.UI.Client/src/common/mocks/resources/tree.mocks.js
@@ -63,6 +63,38 @@ angular.module('umbraco.mocks').
return [200, children, null];
}
+ function returnDataTypes(status, data, headers) {
+ if (!mocksUtils.checkAuth()) {
+ return [401, null, null];
+ }
+
+ var children = [
+ { name: "Textstring", childNodesUrl: null, id: 10, icon: "icon-file-alt", children: [], expanded: false, hasChildren: false, level: 1, defaultAction: null, menuUrl: null },
+ { name: "Multiple textstring", childNodesUrl: null, id: 11, icon: "icon-file-alt", children: [], expanded: false, hasChildren: false, level: 1, defaultAction: null, menuUrl: null },
+ { name: "Yes/No", childNodesUrl: null, id: 12, icon: "icon-file-alt", children: [], expanded: false, hasChildren: false, level: 1, defaultAction: null, menuUrl: null },
+ { name: "Rich Text Editor", childNodesUrl: null, id: 13, icon: "icon-file-alt", children: [], expanded: false, hasChildren: false, level: 1, defaultAction: null, menuUrl: null }
+ ];
+
+ return [200, children, null];
+ }
+
+ function returnDataTypeMenu(status, data, headers) {
+ if (!mocksUtils.checkAuth()) {
+ return [401, null, null];
+ }
+
+ var menu = [
+ {
+ name: "Create", cssclass: "plus", alias: "create", metaData: {
+ jsAction: "umbracoMenuActions.CreateChildEntity"
+ }
+ },
+ { seperator: true, name: "Reload", cssclass: "refresh", alias: "users", metaData: {} }
+ ];
+
+ return [200, menu, null];
+ }
+
function returnApplicationTrees(status, data, headers) {
if (!mocksUtils.checkAuth()) {
@@ -111,12 +143,16 @@ angular.module('umbraco.mocks').
};
break;
- case "developer":
+ case "developer":
+
+ var dataTypeChildrenUrl = "/umbraco/UmbracoTrees/DataTypeTree/GetNodes?id=-1&application=developer";
+ var dataTypeMenuUrl = "/umbraco/UmbracoTrees/DataTypeTree/GetMenu?id=-1&application=developer";
+
t = {
name: "developer",
id: -1,
children: [
- { name: "Data types", childNodesUrl: url, id: -1, icon: "icon-folder-close", children: [], expanded: false, hasChildren: true, level: 1, menuUrl: menuUrl, metaData: { treeAlias: "datatype" } },
+ { name: "Data types", childNodesUrl: dataTypeChildrenUrl, id: -1, icon: "icon-folder-close", children: [], expanded: false, hasChildren: true, level: 1, menuUrl: dataTypeMenuUrl, metaData: { treeAlias: "datatype" } },
{ name: "Macros", childNodesUrl: url, id: -1, icon: "icon-folder-close", children: [], expanded: false, hasChildren: true, level: 1, menuUrl: menuUrl, metaData: { treeAlias: "macros" } },
{ name: "Packages", childNodesUrl: url, id: -1, icon: "icon-folder-close", children: [], expanded: false, hasChildren: true, level: 1, menuUrl: menuUrl, metaData: { treeAlias: "packager" } },
{ name: "XSLT Files", childNodesUrl: url, id: -1, icon: "icon-folder-close", children: [], expanded: false, hasChildren: true, level: 1, menuUrl: menuUrl, metaData: { treeAlias: "xslt" } },
@@ -184,6 +220,15 @@ angular.module('umbraco.mocks').
.whenGET(mocksUtils.urlRegex('/umbraco/UmbracoTrees/ApplicationTreeApi/GetChildren'))
.respond(returnChildren);
+
+ $httpBackend
+ .whenGET(mocksUtils.urlRegex('/umbraco/UmbracoTrees/DataTypeTree/GetNodes'))
+ .respond(returnDataTypes);
+
+ $httpBackend
+ .whenGET(mocksUtils.urlRegex('/umbraco/UmbracoTrees/DataTypeTree/GetMenu'))
+ .respond(returnDataTypeMenu);
+
$httpBackend
.whenGET(mocksUtils.urlRegex('/umbraco/UmbracoTrees/ApplicationTreeApi/GetMenu'))
.respond(getMenuItems);
diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/datatype.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/datatype.resource.js
index 160603e98b..e459cd6128 100644
--- a/src/Umbraco.Web.UI.Client/src/common/resources/datatype.resource.js
+++ b/src/Umbraco.Web.UI.Client/src/common/resources/datatype.resource.js
@@ -34,12 +34,12 @@ function dataTypeResource($q, $http, umbDataFormatter, umbRequestHelper) {
/** saves or updates a data type object */
save: function (dataType, isNew) {
return umbRequestHelper.resourcePromise(
- $http.post(
- umbRequestHelper.getApiUrl(
- "dataTypeApiBaseUrl",
- "PostSave",
- [{ id: id }])),
- 'Failed to save data for data type id ' + id);
+ $http.post(umbRequestHelper.getApiUrl("dataTypeApiBaseUrl", "PostSave"),
+ {
+ //TODO: SD: I need to finish this on Monday!
+ action: "save" + (isNew ? "New" : "")
+ }),
+ 'Failed to save data for data type id ' + id);
}
};
}
diff --git a/src/Umbraco.Web.UI.Client/src/common/services/menuactions.service.js b/src/Umbraco.Web.UI.Client/src/common/services/menuactions.service.js
index 6b18077070..302834194c 100644
--- a/src/Umbraco.Web.UI.Client/src/common/services/menuactions.service.js
+++ b/src/Umbraco.Web.UI.Client/src/common/services/menuactions.service.js
@@ -8,7 +8,7 @@
* @description
* Defines the methods that are called when menu items declare only an action to execute
*/
-function umbracoMenuActions($q, treeService) {
+function umbracoMenuActions($q, treeService, $location) {
return {
@@ -26,6 +26,24 @@ function umbracoMenuActions($q, treeService) {
*/
"RefreshNodeMenuItem": function (args) {
treeService.loadNodeChildren({ node: args.treeNode, section: args.section });
+ },
+
+ /**
+ * @ngdoc method
+ * @name umbraco.services.umbracoMenuActions#CreateChildEntity
+ * @methodOf umbraco.services.umbracoMenuActions
+ * @function
+ *
+ * @description
+ * This will re-route to a route for creating a new entity as a child of the current node
+ * @param {object} args An arguments object
+ * @param {object} args.treeNode The tree node
+ * @param {object} args.section The current section
+ */
+ "CreateChildEntity": function (args) {
+ var route = "/" + args.section + "/" + treeService.getTreeAlias(args.treeNode) + "/edit/" + args.treeNode.id;
+ //change to new path
+ $location.path(route).search({ create: true });
}
};
}
diff --git a/src/Umbraco.Web.UI.Client/src/common/services/util.service.js b/src/Umbraco.Web.UI.Client/src/common/services/util.service.js
index 452a442a11..96c1f22497 100644
--- a/src/Umbraco.Web.UI.Client/src/common/services/util.service.js
+++ b/src/Umbraco.Web.UI.Client/src/common/services/util.service.js
@@ -196,15 +196,21 @@ function umbPropEditorHelper() {
*
* @param {string} input the view path currently stored for the property editor
*/
- getViewPath: function (input) {
+ getViewPath: function (input, isPreValue) {
var path = String(input);
if (path.startsWith('/')) {
return path;
}
else {
var pathName = path.replace('.', '/');
- //i.e. views/propertyeditors/fileupload/fileupload.html
- return "views/propertyeditors/" + pathName + "/" + pathName + ".html";
+ if (!isPreValue) {
+ //i.e. views/propertyeditors/fileupload/fileupload.html
+ return "views/propertyeditors/" + pathName + "/" + pathName + ".html";
+ }
+ else {
+ //i.e. views/prevalueeditors/requiredfield.html
+ return "views/prevalueeditors/" + pathName + ".html";
+ }
}
}
};
diff --git a/src/Umbraco.Web.UI.Client/src/packages/property editors/relatedlinks/relatedlinks.html b/src/Umbraco.Web.UI.Client/src/packages/property editors/relatedlinks/relatedlinks.html
deleted file mode 100644
index 87180e4324..0000000000
--- a/src/Umbraco.Web.UI.Client/src/packages/property editors/relatedlinks/relatedlinks.html
+++ /dev/null
@@ -1 +0,0 @@
-{{model | json}}
\ No newline at end of file
diff --git a/src/Umbraco.Web.UI.Client/src/packages/property editors/relatedlinks/relatedlinks.js b/src/Umbraco.Web.UI.Client/src/packages/property editors/relatedlinks/relatedlinks.js
deleted file mode 100644
index c8a6f62e5e..0000000000
--- a/src/Umbraco.Web.UI.Client/src/packages/property editors/relatedlinks/relatedlinks.js
+++ /dev/null
@@ -1 +0,0 @@
-alert("bong");
\ No newline at end of file
diff --git a/src/Umbraco.Web.UI.Client/src/packages/propertyeditors/relatedlinks/relatedlinks.html b/src/Umbraco.Web.UI.Client/src/packages/propertyeditors/relatedlinks/relatedlinks.html
index e69de29bb2..87180e4324 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/propertyeditors/relatedlinks/relatedlinks.html
+++ b/src/Umbraco.Web.UI.Client/src/packages/propertyeditors/relatedlinks/relatedlinks.html
@@ -0,0 +1 @@
+{{model | json}}
\ No newline at end of file
diff --git a/src/Umbraco.Web.UI.Client/src/packages/propertyeditors/relatedlinks/relatedlinks.js b/src/Umbraco.Web.UI.Client/src/packages/propertyeditors/relatedlinks/relatedlinks.js
index e69de29bb2..c8a6f62e5e 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/propertyeditors/relatedlinks/relatedlinks.js
+++ b/src/Umbraco.Web.UI.Client/src/packages/propertyeditors/relatedlinks/relatedlinks.js
@@ -0,0 +1 @@
+alert("bong");
\ No newline at end of file
diff --git a/src/Umbraco.Web.UI.Client/src/views/content/edit.html b/src/Umbraco.Web.UI.Client/src/views/content/edit.html
index fbdeb707de..fc32829941 100644
--- a/src/Umbraco.Web.UI.Client/src/views/content/edit.html
+++ b/src/Umbraco.Web.UI.Client/src/views/content/edit.html
@@ -1,50 +1,51 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
diff --git a/src/Umbraco.Web.UI.Client/src/views/datatype/datatype.edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/datatype/datatype.edit.controller.js
index 6649921165..4bd72c084e 100644
--- a/src/Umbraco.Web.UI.Client/src/views/datatype/datatype.edit.controller.js
+++ b/src/Umbraco.Web.UI.Client/src/views/datatype/datatype.edit.controller.js
@@ -7,13 +7,43 @@
* The controller for the content editor
*/
function DataTypeEditController($scope, $routeParams, $location, dataTypeResource, notificationsService, angularHelper, serverValidationManager, contentEditingHelper) {
-
+
+ //set up the standard data type props
+ function createDisplayProps() {
+ $scope.properties = {
+ selectedEditor: {
+ alias: "selectedEditor",
+ description: "Select a property editor",
+ label: "Property editor"
+ },
+ selectedEditorId: {
+ alias: "selectedEditorId",
+ label: "Property editor GUID"
+ }
+ };
+ }
+
+ //setup the pre-values as props
+ function createPreValueProps(preVals) {
+ $scope.preValues = [];
+ for (var i = 0; i < preVals.length; i++) {
+ $scope.preValues.push({
+ hideLabel: preVals[i].hideLabel,
+ alias: preVals[i].key,
+ description: preVals[i].description,
+ label: preVals[i].label,
+ view: preVals[i].view,
+ });
+ }
+ }
+
if ($routeParams.create) {
//we are creating so get an empty content item
dataTypeResource.getScaffold($routeParams.id, $routeParams.doctype)
.then(function(data) {
$scope.loaded = true;
$scope.content = data;
+ createDisplayProps();
});
}
else {
@@ -22,6 +52,8 @@ function DataTypeEditController($scope, $routeParams, $location, dataTypeResourc
.then(function(data) {
$scope.loaded = true;
$scope.content = data;
+ createDisplayProps();
+ createPreValueProps($scope.content.preValues);
//in one particular special case, after we've created a new item we redirect back to the edit
// route but there might be server validation errors in the collection which we need to display
@@ -34,6 +66,8 @@ function DataTypeEditController($scope, $routeParams, $location, dataTypeResourc
//ensure there is a form object assigned.
var currentForm = angularHelper.getRequiredCurrentForm($scope);
+ //TODO: We need to handle the dynamic loading of the pre-value editor view whenever the drop down changes!
+
$scope.save = function (cnt) {
$scope.$broadcast("saving", { scope: $scope });
@@ -42,12 +76,12 @@ function DataTypeEditController($scope, $routeParams, $location, dataTypeResourc
serverValidationManager.reset();
- dataTypeResource.save(cnt, $routeParams.create, $scope.files)
+ dataTypeResource.save(cnt, $routeParams.create)
.then(function (data) {
- contentEditingHelper.handleSuccessfulSave({
- scope: $scope,
- newContent: data
- });
+
+ //TODO: SD: I need to finish this on monday!
+ alert("Woot!");
+
}, function (err) {
contentEditingHelper.handleSaveError(err, $scope);
});
@@ -55,4 +89,4 @@ function DataTypeEditController($scope, $routeParams, $location, dataTypeResourc
}
-angular.module("umbraco").controller("Umbraco.Editors.DataType.EditController", DataTypeEditController);
+angular.module("umbraco").controller("Umbraco.Editors.DataType.EditController", DataTypeEditController);
\ No newline at end of file
diff --git a/src/Umbraco.Web.UI.Client/src/views/datatype/edit.html b/src/Umbraco.Web.UI.Client/src/views/datatype/edit.html
index c4ae0d5a31..87987bc464 100644
--- a/src/Umbraco.Web.UI.Client/src/views/datatype/edit.html
+++ b/src/Umbraco.Web.UI.Client/src/views/datatype/edit.html
@@ -1,4 +1,4 @@
-
-
-
-
-
+
+
+
-
-
-
-
-
+
+
+
+
+ Required
+
-
-
+
+
+
+ {{content.selectedEditor}}
+
+
+
+
+
+
+
+
+
+
+
+
-
+
diff --git a/src/Umbraco.Web.UI.Client/src/views/media/edit.html b/src/Umbraco.Web.UI.Client/src/views/media/edit.html
index d8a9d668de..8f031bb0b0 100644
--- a/src/Umbraco.Web.UI.Client/src/views/media/edit.html
+++ b/src/Umbraco.Web.UI.Client/src/views/media/edit.html
@@ -1,4 +1,4 @@
-
+
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/requiredfield.html b/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/requiredfield.html
new file mode 100644
index 0000000000..621a0cb9d7
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/requiredfield.html
@@ -0,0 +1,7 @@
+
+
+
+ Required
+
diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/validationtest/validationtest.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/validationtest/validationtest.html
index 0258e9f518..b114564780 100644
--- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/validationtest/validationtest.html
+++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/validationtest/validationtest.html
@@ -1,12 +1,12 @@
Enter a numeric value
-
-
Required!
-
The value entered is not a number
-
A server error occurred
+
Required!
+
The value entered is not a number
+
A server error occurred
diff --git a/src/Umbraco.Web.UI/App_Plugins/MyPackage/Package.manifest b/src/Umbraco.Web.UI/App_Plugins/MyPackage/Package.manifest
index 5893b50449..a542d5b3ff 100644
--- a/src/Umbraco.Web.UI/App_Plugins/MyPackage/Package.manifest
+++ b/src/Umbraco.Web.UI/App_Plugins/MyPackage/Package.manifest
@@ -3,6 +3,9 @@
{
id: "0BA0F832-D759-4526-9B3E-94BBFC98F92E",
name: "Regex",
+ defaultConfig: {
+ regexStatement: "^\\d*$"
+ },
editor: {
view: "~/App_Plugins/MyPackage/PropertyEditors/Views/RegexEditor.html",
validation: [
@@ -15,8 +18,20 @@
}
]
},
- preValues: {
- view: "myPreValues1"
+ preValueEditor: {
+ fields: [
+ {
+ label: "Regular expression",
+ description: "Enter a regular expression to use to validate this editor",
+ key: "regex",
+ view: "~/App_Plugins/MyPackage/PropertyEditors/Views/regexStatement.html",
+ validation: [
+ {
+ type: "Required"
+ }
+ ]
+ }
+ ]
}
},
{
diff --git a/src/Umbraco.Web.UI/App_Plugins/MyPackage/PropertyEditors/Views/PostcodeEditor.html b/src/Umbraco.Web.UI/App_Plugins/MyPackage/PropertyEditors/Views/PostcodeEditor.html
index 1e2a9e525d..c1d1e5ea7a 100644
--- a/src/Umbraco.Web.UI/App_Plugins/MyPackage/PropertyEditors/Views/PostcodeEditor.html
+++ b/src/Umbraco.Web.UI/App_Plugins/MyPackage/PropertyEditors/Views/PostcodeEditor.html
@@ -4,7 +4,7 @@
+ val-postcode="model.config.country"/>
{{propertyForm.myPackage_postcode.errorMsg}}
{{propertyForm.myPackage_postcode.errorMsg}}
diff --git a/src/Umbraco.Web.UI/App_Plugins/MyPackage/PropertyEditors/Views/RegexEditor.html b/src/Umbraco.Web.UI/App_Plugins/MyPackage/PropertyEditors/Views/RegexEditor.html
index 75e6633415..ad86065019 100644
--- a/src/Umbraco.Web.UI/App_Plugins/MyPackage/PropertyEditors/Views/RegexEditor.html
+++ b/src/Umbraco.Web.UI/App_Plugins/MyPackage/PropertyEditors/Views/RegexEditor.html
@@ -8,7 +8,7 @@
Required!
diff --git a/src/Umbraco.Web/HttpUrlHelperExtensions.cs b/src/Umbraco.Web/HttpUrlHelperExtensions.cs
index 829bc419c7..a8988ac264 100644
--- a/src/Umbraco.Web/HttpUrlHelperExtensions.cs
+++ b/src/Umbraco.Web/HttpUrlHelperExtensions.cs
@@ -96,11 +96,11 @@ namespace Umbraco.Web
routeName = string.Format("umbraco-{0}-{1}-{2}", "api", area, controllerName);
if (id == null)
{
- return url.Link(routeName, new {controller = controllerName, action = actionName, area = area});
+ return url.Link(routeName, new {controller = controllerName, action = actionName});
}
else
{
- return url.Link(routeName, new { controller = controllerName, action = actionName, area = area, id = id });
+ return url.Link(routeName, new { controller = controllerName, action = actionName, id = id });
}
}
}
diff --git a/src/Umbraco.Web/Trees/ContentTreeController.cs b/src/Umbraco.Web/Trees/ContentTreeController.cs
index ee85b0ccdb..27e787575e 100644
--- a/src/Umbraco.Web/Trees/ContentTreeController.cs
+++ b/src/Umbraco.Web/Trees/ContentTreeController.cs
@@ -9,15 +9,18 @@ using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Services;
+using Umbraco.Web.Mvc;
using Umbraco.Web.Trees.Menu;
using umbraco;
using umbraco.BusinessLogic.Actions;
using umbraco.businesslogic;
using umbraco.interfaces;
+using Constants = Umbraco.Core.Constants;
namespace Umbraco.Web.Trees
{
[Tree(Constants.Applications.Content, Constants.Trees.Content, "Content")]
+ [PluginController("UmbracoTrees")]
public class ContentTreeController : ContentTreeControllerBase
{
protected override TreeNode CreateRootNode(FormDataCollection queryStrings)
diff --git a/src/Umbraco.Web/Trees/DataTypeTreeController.cs b/src/Umbraco.Web/Trees/DataTypeTreeController.cs
index c9159b336b..73477e0f71 100644
--- a/src/Umbraco.Web/Trees/DataTypeTreeController.cs
+++ b/src/Umbraco.Web/Trees/DataTypeTreeController.cs
@@ -5,12 +5,15 @@ using System.Net;
using System.Net.Http.Formatting;
using System.Web.Http;
using Umbraco.Core;
+using Umbraco.Web.Mvc;
using Umbraco.Web.Trees.Menu;
using umbraco.BusinessLogic.Actions;
+using Constants = Umbraco.Core.Constants;
namespace Umbraco.Web.Trees
{
[Tree(Constants.Applications.Developer, Constants.Trees.DataTypes, "Data Types")]
+ [PluginController("UmbracoTrees")]
public class DataTypeTreeController : TreeApiController
{
protected override TreeNodeCollection GetTreeNodes(string id, FormDataCollection queryStrings)
diff --git a/src/Umbraco.Web/Trees/MediaTreeController.cs b/src/Umbraco.Web/Trees/MediaTreeController.cs
index 0ea1954456..7078e7d2ac 100644
--- a/src/Umbraco.Web/Trees/MediaTreeController.cs
+++ b/src/Umbraco.Web/Trees/MediaTreeController.cs
@@ -3,12 +3,15 @@ using System.Net.Http.Formatting;
using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Core.Services;
+using Umbraco.Web.Mvc;
using Umbraco.Web.Trees.Menu;
using umbraco.BusinessLogic.Actions;
+using Constants = Umbraco.Core.Constants;
namespace Umbraco.Web.Trees
{
[Tree(Constants.Applications.Media, Constants.Trees.Media, "Media")]
+ [PluginController("UmbracoTrees")]
public class MediaTreeController : ContentTreeControllerBase
{
protected override int RecycleBinId