diff --git a/src/Umbraco.Core/PropertyEditors/PreValueField.cs b/src/Umbraco.Core/PropertyEditors/PreValueField.cs
index ec8283c1b9..94309e2ec7 100644
--- a/src/Umbraco.Core/PropertyEditors/PreValueField.cs
+++ b/src/Umbraco.Core/PropertyEditors/PreValueField.cs
@@ -33,7 +33,10 @@ namespace Umbraco.Core.PropertyEditors
public string Key { get; set; }
///
- /// The view to render for the field
+ /// Defines the view to use for the editor, this can be one of 3 things:
+ /// * the full virtual path or
+ /// * the relative path to the current Umbraco folder
+ /// * a simple view name which will map to the views/prevalueeditors/{view}.html
///
[JsonProperty("view", Required = Required.Always)]
public string View { get; set; }
diff --git a/src/Umbraco.Core/PropertyEditors/PropertyEditorAttribute.cs b/src/Umbraco.Core/PropertyEditors/PropertyEditorAttribute.cs
index f9c189e0ee..6f48ede182 100644
--- a/src/Umbraco.Core/PropertyEditors/PropertyEditorAttribute.cs
+++ b/src/Umbraco.Core/PropertyEditors/PropertyEditorAttribute.cs
@@ -34,25 +34,22 @@ namespace Umbraco.Core.PropertyEditors
ValueType = "string";
}
- public PropertyEditorAttribute(string id, string name, string valueType, string editorView, string preValueEditorView)
+ public PropertyEditorAttribute(string id, string name, string valueType, string editorView)
{
Mandate.ParameterNotNullOrEmpty(id, "id");
Mandate.ParameterNotNullOrEmpty(name, "name");
Mandate.ParameterNotNullOrEmpty(valueType, "valueType");
Mandate.ParameterNotNullOrEmpty(editorView, "editorView");
- Mandate.ParameterNotNullOrEmpty(preValueEditorView, "preValueEditorView");
Id = id;
Name = name;
ValueType = valueType;
EditorView = editorView;
- PreValueEditorView = preValueEditorView;
}
public string Id { get; private set; }
public string Name { get; private set; }
public string EditorView { get; private set; }
public string ValueType { get; set; }
- public string PreValueEditorView { get; set; }
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/PropertyEditors/ValueEditor.cs b/src/Umbraco.Core/PropertyEditors/ValueEditor.cs
index 5929b96512..1b5b0e7118 100644
--- a/src/Umbraco.Core/PropertyEditors/ValueEditor.cs
+++ b/src/Umbraco.Core/PropertyEditors/ValueEditor.cs
@@ -36,7 +36,10 @@ namespace Umbraco.Core.PropertyEditors
}
///
- /// The full virtual path or the relative path to the current Umbraco folder for the angular view
+ /// Defines the view to use for the editor, this can be one of 3 things:
+ /// * the full virtual path or
+ /// * the relative path to the current Umbraco folder
+ /// * a simple view name which will map to the views/propertyeditors/{view}/{view}.html
///
[JsonProperty("view", Required = Required.Always)]
public string View { get; set; }
diff --git a/src/Umbraco.Web.UI.Client/src/common/services/angularhelper.service.js b/src/Umbraco.Web.UI.Client/src/common/services/angularhelper.service.js
new file mode 100644
index 0000000000..dd439e14b7
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/common/services/angularhelper.service.js
@@ -0,0 +1,156 @@
+/**
+ * @ngdoc service
+ * @name umbraco.services.angularHelper
+ * @function
+ *
+ * @description
+ * Some angular helper/extension methods
+ */
+function angularHelper($log, $q) {
+ return {
+
+ /**
+ * @ngdoc function
+ * @name umbraco.services.angularHelper#rejectedPromise
+ * @methodOf umbraco.services.angularHelper
+ * @function
+ *
+ * @description
+ * In some situations we need to return a promise as a rejection, normally based on invalid data. This
+ * is a wrapper to do that so we can save one writing a bit of code.
+ *
+ * @param {object} objReject The object to send back with the promise rejection
+ */
+ rejectedPromise: function (objReject) {
+ var deferred = $q.defer();
+ //return an error object including the error message for UI
+ deferred.reject(objReject);
+ return deferred.promise;
+ },
+
+ /**
+ * @ngdoc function
+ * @name safeApply
+ * @methodOf umbraco.services.angularHelper
+ * @function
+ *
+ * @description
+ * This checks if a digest/apply is already occuring, if not it will force an apply call
+ */
+ safeApply: function (scope, fn) {
+ if (scope.$$phase || scope.$root.$$phase) {
+ if (angular.isFunction(fn)) {
+ fn();
+ }
+ }
+ else {
+ if (angular.isFunction(fn)) {
+ scope.$apply(fn);
+ }
+ else {
+ scope.$apply();
+ }
+ }
+ },
+
+ /**
+ * @ngdoc function
+ * @name getCurrentForm
+ * @methodOf umbraco.services.angularHelper
+ * @function
+ *
+ * @description
+ * Returns the current form object applied to the scope or null if one is not found
+ */
+ getCurrentForm: function (scope) {
+
+ //NOTE: There isn't a way in angular to get a reference to the current form object since the form object
+ // is just defined as a property of the scope when it is named but you'll always need to know the name which
+ // isn't very convenient. If we want to watch for validation changes we need to get a form reference.
+ // The way that we detect the form object is a bit hackerific in that we detect all of the required properties
+ // that exist on a form object.
+ //
+ //The other way to do it in a directive is to require "^form", but in a controller the only other way to do it
+ // is to inject the $element object and use: $element.inheritedData('$formController');
+
+ var form = null;
+ //var requiredFormProps = ["$error", "$name", "$dirty", "$pristine", "$valid", "$invalid", "$addControl", "$removeControl", "$setValidity", "$setDirty"];
+ var requiredFormProps = ["$addControl", "$removeControl", "$setValidity", "$setDirty", "$setPristine"];
+
+ // a method to check that the collection of object prop names contains the property name expected
+ function propertyExists(objectPropNames) {
+ //ensure that every required property name exists on the current scope property
+ return _.every(requiredFormProps, function (item) {
+
+ return _.contains(objectPropNames, item);
+ });
+ }
+
+ for (var p in scope) {
+
+ if (_.isObject(scope[p]) && p !== "this" && p.substr(0, 1) !== "$") {
+ //get the keys of the property names for the current property
+ var props = _.keys(scope[p]);
+ //if the length isn't correct, try the next prop
+ if (props.length < requiredFormProps.length) {
+ continue;
+ }
+
+ //ensure that every required property name exists on the current scope property
+ var containProperty = propertyExists(props);
+
+ if (containProperty) {
+ form = scope[p];
+ break;
+ }
+ }
+ }
+
+ return form;
+ },
+
+ /**
+ * @ngdoc function
+ * @name validateHasForm
+ * @methodOf umbraco.services.angularHelper
+ * @function
+ *
+ * @description
+ * This will validate that the current scope has an assigned form object, if it doesn't an exception is thrown, if
+ * it does we return the form object.
+ */
+ getRequiredCurrentForm: function (scope) {
+ var currentForm = this.getCurrentForm(scope);
+ if (!currentForm || !currentForm.$name) {
+ throw "The current scope requires a current form object (or ng-form) with a name assigned to it";
+ }
+ return currentForm;
+ },
+
+ /**
+ * @ngdoc function
+ * @name getNullForm
+ * @methodOf umbraco.services.angularHelper
+ * @function
+ *
+ * @description
+ * Returns a null angular FormController, mostly for use in unit tests
+ * NOTE: This is actually the same construct as angular uses internally for creating a null form but they don't expose
+ * any of this publicly to us, so we need to create our own.
+ *
+ * @param {string} formName The form name to assign
+ */
+ getNullForm: function (formName) {
+ return {
+ $addControl: angular.noop,
+ $removeControl: angular.noop,
+ $setValidity: angular.noop,
+ $setDirty: angular.noop,
+ $setPristine: angular.noop,
+ $name: formName
+ //NOTE: we don't include the 'properties', just the methods.
+ };
+ }
+ };
+}
+angular.module('umbraco.services').factory('angularHelper', angularHelper);
\ No newline at end of file
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 5556e3403f..421cba5fe4 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
@@ -20,164 +20,6 @@ function legacyJsLoader(assetsService, umbRequestHelper) {
}
angular.module('umbraco.services').factory('legacyJsLoader', legacyJsLoader);
-
-/**
- * @ngdoc service
- * @name umbraco.services.angularHelper
- * @function
- *
- * @description
- * Some angular helper/extension methods
- */
-function angularHelper($log, $q) {
- return {
-
- /**
- * @ngdoc function
- * @name umbraco.services.angularHelper#rejectedPromise
- * @methodOf umbraco.services.angularHelper
- * @function
- *
- * @description
- * In some situations we need to return a promise as a rejection, normally based on invalid data. This
- * is a wrapper to do that so we can save one writing a bit of code.
- *
- * @param {object} objReject The object to send back with the promise rejection
- */
- rejectedPromise: function (objReject) {
- var deferred = $q.defer();
- //return an error object including the error message for UI
- deferred.reject(objReject);
- return deferred.promise;
- },
-
- /**
- * @ngdoc function
- * @name safeApply
- * @methodOf umbraco.services.angularHelper
- * @function
- *
- * @description
- * This checks if a digest/apply is already occuring, if not it will force an apply call
- */
- safeApply: function (scope, fn) {
- if (scope.$$phase || scope.$root.$$phase) {
- if (angular.isFunction(fn)) {
- fn();
- }
- }
- else {
- if (angular.isFunction(fn)) {
- scope.$apply(fn);
- }
- else {
- scope.$apply();
- }
- }
- },
-
- /**
- * @ngdoc function
- * @name getCurrentForm
- * @methodOf umbraco.services.angularHelper
- * @function
- *
- * @description
- * Returns the current form object applied to the scope or null if one is not found
- */
- getCurrentForm: function (scope) {
-
- //NOTE: There isn't a way in angular to get a reference to the current form object since the form object
- // is just defined as a property of the scope when it is named but you'll always need to know the name which
- // isn't very convenient. If we want to watch for validation changes we need to get a form reference.
- // The way that we detect the form object is a bit hackerific in that we detect all of the required properties
- // that exist on a form object.
- //
- //The other way to do it in a directive is to require "^form", but in a controller the only other way to do it
- // is to inject the $element object and use: $element.inheritedData('$formController');
-
- var form = null;
- //var requiredFormProps = ["$error", "$name", "$dirty", "$pristine", "$valid", "$invalid", "$addControl", "$removeControl", "$setValidity", "$setDirty"];
- var requiredFormProps = ["$addControl", "$removeControl", "$setValidity", "$setDirty", "$setPristine"];
-
- // a method to check that the collection of object prop names contains the property name expected
- function propertyExists(objectPropNames) {
- //ensure that every required property name exists on the current scope property
- return _.every(requiredFormProps, function (item) {
-
- return _.contains(objectPropNames, item);
- });
- }
-
- for (var p in scope) {
-
- if (_.isObject(scope[p]) && p !== "this" && p.substr(0, 1) !== "$") {
- //get the keys of the property names for the current property
- var props = _.keys(scope[p]);
- //if the length isn't correct, try the next prop
- if (props.length < requiredFormProps.length) {
- continue;
- }
-
- //ensure that every required property name exists on the current scope property
- var containProperty = propertyExists(props);
-
- if (containProperty) {
- form = scope[p];
- break;
- }
- }
- }
-
- return form;
- },
-
- /**
- * @ngdoc function
- * @name validateHasForm
- * @methodOf umbraco.services.angularHelper
- * @function
- *
- * @description
- * This will validate that the current scope has an assigned form object, if it doesn't an exception is thrown, if
- * it does we return the form object.
- */
- getRequiredCurrentForm: function(scope) {
- var currentForm = this.getCurrentForm(scope);
- if (!currentForm || !currentForm.$name) {
- throw "The current scope requires a current form object (or ng-form) with a name assigned to it";
- }
- return currentForm;
- },
-
- /**
- * @ngdoc function
- * @name getNullForm
- * @methodOf umbraco.services.angularHelper
- * @function
- *
- * @description
- * Returns a null angular FormController, mostly for use in unit tests
- * NOTE: This is actually the same construct as angular uses internally for creating a null form but they don't expose
- * any of this publicly to us, so we need to create our own.
- *
- * @param {string} formName The form name to assign
- */
- getNullForm: function(formName) {
- return {
- $addControl: angular.noop,
- $removeControl: angular.noop,
- $setValidity: angular.noop,
- $setDirty: angular.noop,
- $setPristine: angular.noop,
- $name: formName
- //NOTE: we don't include the 'properties', just the methods.
- };
- }
- };
-}
-angular.module('umbraco.services').factory('angularHelper', angularHelper);
-
/**
* @ngdoc service
* @name umbraco.services.umbPropertyEditorHelper
@@ -198,19 +40,29 @@ function umbPropEditorHelper() {
*/
getViewPath: function (input, isPreValue) {
var path = String(input);
+
if (path.startsWith('/')) {
+
+ //This is an absolute path, so just leave it
return path;
}
else {
- var pathName = path.replace('.', '/');
- if (!isPreValue) {
- //i.e. views/propertyeditors/fileupload/fileupload.html
- return "views/propertyeditors/" + pathName + "/" + pathName + ".html";
+
+ if (path.indexOf("/") >= 0) {
+ //This is a relative path, so just leave it
+ return path;
}
else {
- //i.e. views/prevalueeditors/requiredfield.html
- return "views/prevalueeditors/" + pathName + ".html";
+ if (!isPreValue) {
+ //i.e. views/propertyeditors/fileupload/fileupload.html
+ return "views/propertyeditors/" + path + "/" + path + ".html";
+ }
+ else {
+ //i.e. views/prevalueeditors/requiredfield.html
+ return "views/prevalueeditors/" + path + ".html";
+ }
}
+
}
}
};
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 206f4c4a50..40f91b7b03 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
@@ -67,7 +67,7 @@ function DataTypeEditController($scope, $routeParams, $location, dataTypeResourc
$scope.$watch("content.selectedEditor", function (newVal, oldVal) {
//when the value changes, we need to dynamically load in the new editor
- if (newVal && oldVal && newVal != oldVal) {
+ if (newVal !== null && newVal !== undefined && newVal != oldVal) {
//we are editing so get the content item from the server
dataTypeResource.getPreValues(newVal)
.then(function (data) {
diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/dropdown/dropdown.prevalue.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/dropdown/dropdown.prevalue.html
new file mode 100644
index 0000000000..e67d96f0a1
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/dropdown/dropdown.prevalue.html
@@ -0,0 +1,4 @@
+
+ Hello world
+
+
\ No newline at end of file
diff --git a/src/Umbraco.Web/PropertyEditors/DatePropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/DatePropertyEditor.cs
index 135a76ee3a..20831fadfc 100644
--- a/src/Umbraco.Web/PropertyEditors/DatePropertyEditor.cs
+++ b/src/Umbraco.Web/PropertyEditors/DatePropertyEditor.cs
@@ -5,10 +5,37 @@ using Newtonsoft.Json.Linq;
using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Core.PropertyEditors;
+using umbraco;
namespace Umbraco.Web.PropertyEditors
{
- [PropertyEditor(Constants.PropertyEditors.Date, "Date", "datepicker", ValueType = "DATE")]
+ [PropertyEditor(Constants.PropertyEditors.DropDownList, "Dropdown list", "dropdown")]
+ public class DropDownPropertyEditor : PropertyEditor
+ {
+ protected override PreValueEditor CreatePreValueEditor()
+ {
+ var editor = base.CreatePreValueEditor();
+
+ editor.Fields = new List
+ {
+ new PreValueField
+ {
+ Description = "Add and remove values for the drop down list",
+ //we're going to call this 'temp' because we are going to override the
+ //serialization of the pre-values to ensure that each one gets saved with it's own key
+ //(new db row per pre-value, thus to maintain backwards compatibility)
+ Key = "temp",
+ Name = ui.Text("editdatatype", "addPrevalue"),
+ View = "Views/PropertyEditors/dropdown/dropdown.prevalue.html"
+ }
+ };
+
+ return editor;
+ }
+ }
+
+
+ [PropertyEditor(Constants.PropertyEditors.Date, "Date", "DATE", "datepicker")]
public class DatePropertyEditor : PropertyEditor
{
public DatePropertyEditor()