From 129621440096674a014fec36c0768726380340dc Mon Sep 17 00:00:00 2001 From: Bjarne Fyrstenborg Date: Sun, 15 Jul 2018 20:20:57 +0200 Subject: [PATCH 01/15] Localization of text in color picker --- .../colorpicker/multicolorpicker.controller.js | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/multicolorpicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/multicolorpicker.controller.js index 98e649729c..e0e744062b 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/multicolorpicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/multicolorpicker.controller.js @@ -1,5 +1,5 @@ angular.module("umbraco").controller("Umbraco.PrevalueEditors.MultiColorPickerController", - function ($scope, $timeout, assetsService, angularHelper, $element) { + function ($scope, $timeout, assetsService, angularHelper, $element, localizationService) { //NOTE: We need to make each color an object, not just a string because you cannot 2-way bind to a primitive. var defaultColor = "000000"; var defaultLabel = null; @@ -8,6 +8,18 @@ $scope.newLavel = defaultLabel; $scope.hasError = false; + $scope.labels = {}; + + var labelKeys = [ + "general_cancel", + "general_choose" + ]; + + localizationService.localizeMany(labelKeys).then(function (values) { + $scope.labels.cancel = values[0]; + $scope.labels.choose = values[1]; + }); + assetsService.load([ //"lib/spectrum/tinycolor.js", "lib/spectrum/spectrum.js" @@ -16,8 +28,8 @@ elem.spectrum({ color: null, showInitial: false, - chooseText: "choose", // TODO: These can be localised - cancelText: "cancel", // TODO: These can be localised + chooseText: $scope.labels.choose, + cancelText: $scope.labels.cancel, preferredFormat: "hex", showInput: true, clickoutFiresChange: true, From d697e46f249c2a85794d5d43c98af838ff8de9a0 Mon Sep 17 00:00:00 2001 From: Bjarne Fyrstenborg Date: Sun, 15 Jul 2018 20:22:12 +0200 Subject: [PATCH 02/15] Configurate sortable on color picker property editor --- .../src/less/property-editors.less | 27 +++++-------- .../colorpicker/colorpicker.controller.js | 38 +++++++++++++++++++ .../colorpicker/colorpicker.prevalues.html | 13 ++++--- .../multicolorpicker.controller.js | 37 ++++++++++++++++++ 4 files changed, 92 insertions(+), 23 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/property-editors.less b/src/Umbraco.Web.UI.Client/src/less/property-editors.less index dd0e4d3e77..5dc4b8658f 100644 --- a/src/Umbraco.Web.UI.Client/src/less/property-editors.less +++ b/src/Umbraco.Web.UI.Client/src/less/property-editors.less @@ -154,47 +154,38 @@ ul.color-picker li a { } /* pre-value editor */ -/*.control-group.color-picker-preval:before { - content: ""; +.control-group.color-picker-preval .handle { + float: left; display: inline-block; - vertical-align: middle; - height: 100%; -}*/ - -/*.control-group.color-picker-preval div.thumbnail { - display: inline-block; - vertical-align: middle; -}*/ + margin: 5px 3px 5px 0; +} .control-group.color-picker-preval div.color-picker-prediv { display: inline-block; - width: 60%; + width: 50%; } .control-group.color-picker-preval pre { display: inline; - margin-right: 20px; + margin-right: 10px; margin-left: 10px; width: 50%; white-space: nowrap; overflow: hidden; margin-bottom: 0; vertical-align: middle; -} - -.control-group.color-picker-preval btn { - //vertical-align: middle; + padding-top: 7px; + padding-bottom: 7px; } .control-group.color-picker-preval input[type="text"] { min-width: 40%; width: 40%; display: inline-block; - margin-right: 20px; margin-top: 1px; } .control-group.color-picker-preval label { - border: solid @white 1px; + border: 1px solid @white; padding: 6px; } diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/colorpicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/colorpicker.controller.js index 5230f9ef2c..03defbc930 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/colorpicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/colorpicker.controller.js @@ -1,5 +1,41 @@ function ColorPickerController($scope) { + //setup the default config + var config = { + items: [], + multiple: false + }; + + //map the user config + angular.extend(config, $scope.model.config); + + //map back to the model + $scope.model.config = config; + + function convertArrayToDictionaryArray(model) { + //now we need to format the items in the dictionary because we always want to have an array + var newItems = []; + for (var i = 0; i < model.length; i++) { + newItems.push({ id: model[i], sortOrder: 0, value: model[i] }); + } + + return newItems; + } + + + function convertObjectToDictionaryArray(model) { + //now we need to format the items in the dictionary because we always want to have an array + var newItems = []; + var vals = _.values($scope.model.config.items); + var keys = _.keys($scope.model.config.items); + + for (var i = 0; i < vals.length; i++) { + var label = vals[i].value ? vals[i].value : vals[i]; + newItems.push({ id: keys[i], sortOrder: vals[i].sortOrder, value: label }); + } + + return newItems; + } $scope.isConfigured = $scope.model.config && $scope.model.config.items && _.keys($scope.model.config.items).length > 0; if ($scope.isConfigured) { @@ -13,6 +49,8 @@ function ColorPickerController($scope) { initActiveColor(); } + //sort the values + $scope.model.config.items.sort(function (a, b) { return (a.sortOrder > b.sortOrder) ? 1 : ((b.sortOrder > a.sortOrder) ? -1 : 0); }); $scope.toggleItem = function (color) { var currentColor = ($scope.model.value && $scope.model.value.hasOwnProperty("value")) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/colorpicker.prevalues.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/colorpicker.prevalues.html index 2b917e69f8..2d342c92fc 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/colorpicker.prevalues.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/colorpicker.prevalues.html @@ -1,13 +1,16 @@
- +
-
-
-
#{{item.value}} - {{item.label}}
- +
+
+ +
+
#{{item.value}}
{{item.label}}
+ +
diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/multicolorpicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/multicolorpicker.controller.js index e0e744062b..3751117485 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/multicolorpicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/multicolorpicker.controller.js @@ -68,6 +68,10 @@ }); } } + + //ensure the items are sorted by the provided sort order + items.sort(function (a, b) { return (a.sortOrder > b.sortOrder) ? 1 : ((b.sortOrder > a.sortOrder) ? -1 : 0); }); + //now make the editor model the array $scope.model.value = items; } @@ -116,6 +120,39 @@ }; + $scope.sortableOptions = { + axis: 'y', + containment: 'parent', + cursor: 'move', + handle: ".handle, .thumbnail", + items: '> div.control-group', + tolerance: 'pointer', + update: function (e, ui) { + // Get the new and old index for the moved element (using the text as the identifier, so + // we'd have a problem if two prevalues were the same, but that would be unlikely) + var newIndex = ui.item.index(); + var movedPrevalueText = $('pre', ui.item).text(); + var originalIndex = getElementIndexByPrevalueText(movedPrevalueText); + + //// Move the element in the model + if (originalIndex > -1) { + var movedElement = $scope.model.value[originalIndex]; + $scope.model.value.splice(originalIndex, 1); + $scope.model.value.splice(newIndex, 0, movedElement); + } + } + }; + + function getElementIndexByPrevalueText(value) { + for (var i = 0; i < $scope.model.value.length; i++) { + if ($scope.model.value[i].value === value) { + return i; + } + } + + return -1; + } + //load the separate css for the editor to avoid it blocking our js loading assetsService.loadCss("lib/spectrum/spectrum.css", $scope); }); From 130dabfdce79ff1eee99423fce2984ad680e2c72 Mon Sep 17 00:00:00 2001 From: Bjarne Fyrstenborg Date: Sun, 15 Jul 2018 20:23:54 +0200 Subject: [PATCH 03/15] Add monospace font on pre elements to ensure same width of elements --- src/Umbraco.Web.UI.Client/src/less/property-editors.less | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Umbraco.Web.UI.Client/src/less/property-editors.less b/src/Umbraco.Web.UI.Client/src/less/property-editors.less index 5dc4b8658f..cff7141daa 100644 --- a/src/Umbraco.Web.UI.Client/src/less/property-editors.less +++ b/src/Umbraco.Web.UI.Client/src/less/property-editors.less @@ -166,6 +166,7 @@ ul.color-picker li a { .control-group.color-picker-preval pre { display: inline; + font-family: monospace; margin-right: 10px; margin-left: 10px; width: 50%; From 912b101d0a10db4f6a286cf53b3f07c2031eb3ab Mon Sep 17 00:00:00 2001 From: Bjarne Fyrstenborg Date: Sun, 15 Jul 2018 21:44:03 +0200 Subject: [PATCH 04/15] Order items by sort order --- .../PropertyEditors/ColorListPreValueEditor.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Web/PropertyEditors/ColorListPreValueEditor.cs b/src/Umbraco.Web/PropertyEditors/ColorListPreValueEditor.cs index a504ed0431..8c2a36fe10 100644 --- a/src/Umbraco.Web/PropertyEditors/ColorListPreValueEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/ColorListPreValueEditor.cs @@ -40,9 +40,9 @@ namespace Umbraco.Web.PropertyEditors public override IDictionary ConvertDbToEditor(IDictionary defaultPreVals, PreValueCollection persistedPreVals) { var dictionary = persistedPreVals.FormatAsDictionary(); - var items = dictionary - .Where(x => x.Key != "useLabel") - .ToDictionary(x => x.Value.Id, x => x.Value.Value); + var items = dictionary.Where(x => x.Key != "useLabel") + .OrderBy(x => x.Value.SortOrder) + .ToDictionary(x => x.Value.Id, x => x.Value.Value); var items2 = new Dictionary(); foreach (var item in items) @@ -150,4 +150,4 @@ namespace Umbraco.Web.PropertyEditors } } } -} \ No newline at end of file +} From ec78e99ca0583a09b3c7c59636b460038b1f57fc Mon Sep 17 00:00:00 2001 From: Bjarne Fyrstenborg Date: Sun, 15 Jul 2018 22:07:06 +0200 Subject: [PATCH 05/15] Add sortorder to prevalue --- .../PropertyEditors/ColorListPreValueEditor.cs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/Umbraco.Web/PropertyEditors/ColorListPreValueEditor.cs b/src/Umbraco.Web/PropertyEditors/ColorListPreValueEditor.cs index 8c2a36fe10..dc949c2dd7 100644 --- a/src/Umbraco.Web/PropertyEditors/ColorListPreValueEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/ColorListPreValueEditor.cs @@ -95,16 +95,20 @@ namespace Umbraco.Web.PropertyEditors .Select(x => { var idString = x["id"] == null ? "0" : x["id"].ToString(); - int id; - if (int.TryParse(idString, out id) == false) id = 0; + int id = int.TryParse(idString, out id) ? id : 0; var color = x["value"].ToString(); if (string.IsNullOrWhiteSpace(color)) return null; var label = x["label"].ToString(); - return new PreValue(id, useLabel - ? JsonConvert.SerializeObject(new { value = color, label = label }) - : color); + + int.TryParse(x["sortOrder"]?.ToString(), out var sortOrder); + + var value = useLabel + ? JsonConvert.SerializeObject(new { value = color, label = label, sortOrder = sortOrder }) + : color; + + return new PreValue(id, value, sortOrder); }) .WhereNotNull()) { From 6ac654a36b2f8fcc84962560e7e18316926d2cda Mon Sep 17 00:00:00 2001 From: Bjarne Fyrstenborg Date: Sun, 15 Jul 2018 22:21:55 +0200 Subject: [PATCH 06/15] Add different cursor styling on sortable thumbnail handle --- src/Umbraco.Web.UI.Client/src/less/property-editors.less | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/property-editors.less b/src/Umbraco.Web.UI.Client/src/less/property-editors.less index cff7141daa..c70688d935 100644 --- a/src/Umbraco.Web.UI.Client/src/less/property-editors.less +++ b/src/Umbraco.Web.UI.Client/src/less/property-editors.less @@ -149,8 +149,9 @@ ul.color-picker li a { } .control-group.color-picker-preval .thumbnail { - width:30px; - border:none; + width: 30px; + border: none; + cursor: move; } /* pre-value editor */ From 565c9ef95d833bf8eb72c9f5a6b0fc273f733352 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Mon, 16 Jul 2018 11:41:10 +0200 Subject: [PATCH 07/15] Cleans up some code and fixes sorting / storing the correct order. --- .../PropertyEditors/ColorListPreValueEditor.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Umbraco.Web/PropertyEditors/ColorListPreValueEditor.cs b/src/Umbraco.Web/PropertyEditors/ColorListPreValueEditor.cs index dc949c2dd7..da286e8260 100644 --- a/src/Umbraco.Web/PropertyEditors/ColorListPreValueEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/ColorListPreValueEditor.cs @@ -80,30 +80,30 @@ namespace Umbraco.Web.PropertyEditors try { - object useLabelObj; var useLabel = false; - if (editorValue.TryGetValue("useLabel", out useLabelObj)) + if (editorValue.TryGetValue("useLabel", out var useLabelObj)) { - useLabel = useLabelObj is string && (string) useLabelObj == "1"; + useLabel = useLabelObj is string && (string)useLabelObj == "1"; result["useLabel"] = new PreValue(useLabel ? "1" : "0"); } // get all non-empty values var index = 0; + // we don't get the actual sortOrder but items get submitted in the sorted order, so let's just count them up + var sortOrder = -1; foreach (var preValue in val.OfType() .Where(x => x["value"] != null) .Select(x => { var idString = x["id"] == null ? "0" : x["id"].ToString(); - int id = int.TryParse(idString, out id) ? id : 0; + int.TryParse(idString, out var id); var color = x["value"].ToString(); if (string.IsNullOrWhiteSpace(color)) return null; var label = x["label"].ToString(); - int.TryParse(x["sortOrder"]?.ToString(), out var sortOrder); - + sortOrder++; var value = useLabel ? JsonConvert.SerializeObject(new { value = color, label = label, sortOrder = sortOrder }) : color; From 157b66dc4c1055702ef8ef1b16836f33f796f010 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Mon, 16 Jul 2018 18:08:20 +0200 Subject: [PATCH 08/15] Fixes the persistence and correct display of the sort order --- .../colorpicker/colorpicker.controller.js | 331 ++++++++++-------- .../multicolorpicker.controller.js | 2 + .../ColorListPreValueEditor.cs | 70 ++-- 3 files changed, 229 insertions(+), 174 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/colorpicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/colorpicker.controller.js index 03defbc930..abb26ef4a2 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/colorpicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/colorpicker.controller.js @@ -1,84 +1,111 @@ -function ColorPickerController($scope) { - - //setup the default config - var config = { - items: [], - multiple: false - }; - - //map the user config - angular.extend(config, $scope.model.config); - - //map back to the model - $scope.model.config = config; - - function convertArrayToDictionaryArray(model) { - //now we need to format the items in the dictionary because we always want to have an array - var newItems = []; - for (var i = 0; i < model.length; i++) { - newItems.push({ id: model[i], sortOrder: 0, value: model[i] }); - } - - return newItems; - } - - - function convertObjectToDictionaryArray(model) { - //now we need to format the items in the dictionary because we always want to have an array - var newItems = []; - var vals = _.values($scope.model.config.items); - var keys = _.keys($scope.model.config.items); - - for (var i = 0; i < vals.length; i++) { - var label = vals[i].value ? vals[i].value : vals[i]; - newItems.push({ id: keys[i], sortOrder: vals[i].sortOrder, value: label }); - } - - return newItems; - } - $scope.isConfigured = $scope.model.config && $scope.model.config.items && _.keys($scope.model.config.items).length > 0; - - if ($scope.isConfigured) { - - for (var key in $scope.model.config.items) { - if (!$scope.model.config.items[key].hasOwnProperty("value")) - $scope.model.config.items[key] = { value: $scope.model.config.items[key], label: $scope.model.config.items[key] }; - } - - $scope.model.useLabel = isTrue($scope.model.config.useLabel); - initActiveColor(); - } +function ColorPickerController($scope) { + + //setup the default config + var config = { + items: [], + multiple: false + }; + + //map the user config + angular.extend(config, $scope.model.config); + + //map back to the model + $scope.model.config = config; + + function convertArrayToDictionaryArray(model) { + //now we need to format the items in the dictionary because we always want to have an array + var newItems = []; + for (var i = 0; i < model.length; i++) { + newItems.push({ id: model[i], sortOrder: 0, value: model[i] }); + } + + return newItems; + } + + + function convertObjectToDictionaryArray(model) { + //now we need to format the items in the dictionary because we always want to have an array + var newItems = []; + var vals = _.values($scope.model.config.items); + var keys = _.keys($scope.model.config.items); + + for (var i = 0; i < vals.length; i++) { + var label = vals[i].value ? vals[i].value : vals[i]; + newItems.push({ id: keys[i], sortOrder: vals[i].sortOrder, value: label }); + } + + return newItems; + } + $scope.isConfigured = $scope.model.config && $scope.model.config.items && _.keys($scope.model.config.items).length > 0; + + if ($scope.isConfigured) { + + for (var key in $scope.model.config.items) { + if (!$scope.model.config.items[key].hasOwnProperty("value")) + $scope.model.config.items[key] = { value: $scope.model.config.items[key], label: $scope.model.config.items[key] }; + } + + $scope.model.useLabel = isTrue($scope.model.config.useLabel); + initActiveColor(); + } + + if (!angular.isArray($scope.model.config.items)) { + //make an array from the dictionary + var items = []; + for (var i in $scope.model.config.items) { + var oldValue = $scope.model.config.items[i]; + if (oldValue.hasOwnProperty("value")) { + items.push({ + value: oldValue.value, + label: oldValue.label, + sortOrder: oldValue.sortOrder, + id: i + }); + } else { + items.push({ + value: oldValue, + label: oldValue, + sortOrder: sortOrder, + id: i + }); + } + } + + //ensure the items are sorted by the provided sort order + items.sort(function (a, b) { return (a.sortOrder > b.sortOrder) ? 1 : ((b.sortOrder > a.sortOrder) ? -1 : 0); }); + + //now make the editor model the array + $scope.model.config.items = items; + } + + $scope.toggleItem = function (color) { + + var currentColor = ($scope.model.value && $scope.model.value.hasOwnProperty("value")) + ? $scope.model.value.value + : $scope.model.value; - //sort the values - $scope.model.config.items.sort(function (a, b) { return (a.sortOrder > b.sortOrder) ? 1 : ((b.sortOrder > a.sortOrder) ? -1 : 0); }); - $scope.toggleItem = function (color) { - - var currentColor = ($scope.model.value && $scope.model.value.hasOwnProperty("value")) - ? $scope.model.value.value - : $scope.model.value; - var newColor; - if (currentColor === color.value) { - // deselect - $scope.model.value = $scope.model.useLabel ? { value: "", label: "" } : ""; - newColor = ""; - } - else { + if (currentColor === color.value) { + // deselect + $scope.model.value = $scope.model.useLabel ? { value: "", label: "" } : ""; + newColor = ""; + } + else { // select - $scope.model.value = $scope.model.useLabel ? { value: color.value, label: color.label } : color.value; + $scope.model.value = $scope.model.useLabel ? { value: color.value, label: color.label } : color.value; newColor = color.value; - } - - // this is required to re-validate - $scope.propertyForm.modelValue.$setViewValue(newColor); - }; + } + + // this is required to re-validate + $scope.propertyForm.modelValue.$setViewValue(newColor); + }; // Method required by the valPropertyValidator directive (returns true if the property editor has at least one color selected) - $scope.validateMandatory = function () { - var isValid = !$scope.model.validation.mandatory || ( - $scope.model.value != null - && $scope.model.value != "" - && (!$scope.model.value.hasOwnProperty("value") || $scope.model.value.value !== "") + $scope.validateMandatory = function () { + var isValid = !$scope.model.validation.mandatory || ( + $scope.model.value != null + && $scope.model.value != "" + && (!$scope.model.value.hasOwnProperty("value") || $scope.model.value.value !== "") ); return { isValid: isValid, @@ -86,83 +113,83 @@ function ColorPickerController($scope) { errorKey: "required" }; } - $scope.isConfigured = $scope.model.config && $scope.model.config.items && _.keys($scope.model.config.items).length > 0; - - // A color is active if it matches the value and label of the model. - // If the model doesn't store the label, ignore the label during the comparison. - $scope.isActiveColor = function (color) { - - // no value - if (!$scope.model.value) - return false; - - // Complex color (value and label)? - if (!$scope.model.value.hasOwnProperty("value")) - return $scope.model.value === color.value; - - return $scope.model.value.value === color.value && $scope.model.value.label === color.label; - }; - - // Finds the color best matching the model's color, - // and sets the model color to that one. This is useful when - // either the value or label was changed on the data type. - function initActiveColor() { - - // no value - if (!$scope.model.value) - return; - - // Complex color (value and label)? - if (!$scope.model.value.hasOwnProperty("value")) - return; - - var modelColor = $scope.model.value.value; - var modelLabel = $scope.model.value.label; - - // Check for a full match or partial match. - var foundItem = null; - - // Look for a fully matching color. - for (var key in $scope.model.config.items) { - var item = $scope.model.config.items[key]; - if (item.value == modelColor && item.label == modelLabel) { - foundItem = item; - break; - } - } - - // Look for a color with a matching value. - if (!foundItem) { - for (var key in $scope.model.config.items) { - var item = $scope.model.config.items[key]; - if (item.value == modelColor) { - foundItem = item; - break; - } - } - } - - // Look for a color with a matching label. - if (!foundItem) { - for (var key in $scope.model.config.items) { - var item = $scope.model.config.items[key]; - if (item.label == modelLabel) { - foundItem = item; - break; - } - } - } - - // If a match was found, set it as the active color. - if (foundItem) { - $scope.model.value.value = foundItem.value; - $scope.model.value.label = foundItem.label; - } - } - - // figures out if a value is trueish enough - function isTrue(bool) { - return !!bool && bool !== "0" && angular.lowercase(bool) !== "false"; + $scope.isConfigured = $scope.model.config && $scope.model.config.items && _.keys($scope.model.config.items).length > 0; + + // A color is active if it matches the value and label of the model. + // If the model doesn't store the label, ignore the label during the comparison. + $scope.isActiveColor = function (color) { + + // no value + if (!$scope.model.value) + return false; + + // Complex color (value and label)? + if (!$scope.model.value.hasOwnProperty("value")) + return $scope.model.value === color.value; + + return $scope.model.value.value === color.value && $scope.model.value.label === color.label; + }; + + // Finds the color best matching the model's color, + // and sets the model color to that one. This is useful when + // either the value or label was changed on the data type. + function initActiveColor() { + + // no value + if (!$scope.model.value) + return; + + // Complex color (value and label)? + if (!$scope.model.value.hasOwnProperty("value")) + return; + + var modelColor = $scope.model.value.value; + var modelLabel = $scope.model.value.label; + + // Check for a full match or partial match. + var foundItem = null; + + // Look for a fully matching color. + for (var key in $scope.model.config.items) { + var item = $scope.model.config.items[key]; + if (item.value == modelColor && item.label == modelLabel) { + foundItem = item; + break; + } + } + + // Look for a color with a matching value. + if (!foundItem) { + for (var key in $scope.model.config.items) { + var item = $scope.model.config.items[key]; + if (item.value == modelColor) { + foundItem = item; + break; + } + } + } + + // Look for a color with a matching label. + if (!foundItem) { + for (var key in $scope.model.config.items) { + var item = $scope.model.config.items[key]; + if (item.label == modelLabel) { + foundItem = item; + break; + } + } + } + + // If a match was found, set it as the active color. + if (foundItem) { + $scope.model.value.value = foundItem.value; + $scope.model.value.label = foundItem.label; + } + } + + // figures out if a value is trueish enough + function isTrue(bool) { + return !!bool && bool !== "0" && angular.lowercase(bool) !== "false"; } } diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/multicolorpicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/multicolorpicker.controller.js index 3751117485..f19fb260f4 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/multicolorpicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/multicolorpicker.controller.js @@ -58,12 +58,14 @@ items.push({ value: oldValue.value, label: oldValue.label, + sortOrder: oldValue.sortOrder, id: i }); } else { items.push({ value: oldValue, label: oldValue, + sortOrder: sortOrder, id: i }); } diff --git a/src/Umbraco.Web/PropertyEditors/ColorListPreValueEditor.cs b/src/Umbraco.Web/PropertyEditors/ColorListPreValueEditor.cs index da286e8260..20dd3f9ec8 100644 --- a/src/Umbraco.Web/PropertyEditors/ColorListPreValueEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/ColorListPreValueEditor.cs @@ -26,13 +26,13 @@ namespace Umbraco.Web.PropertyEditors //change the label field.Name = "Add color"; //need to have some custom validation happening here - field.Validators.Add(new ColorListValidator()); - + field.Validators.Add(new ColorListValidator()); + Fields.Insert(0, new PreValueField { - Name = "Include labels?", - View = "boolean", - Key = "useLabel", + Name = "Include labels?", + View = "boolean", + Key = "useLabel", Description = "Stores colors as a Json object containing both the color hex string and label, rather than just the hex string." }); } @@ -41,27 +41,43 @@ namespace Umbraco.Web.PropertyEditors { var dictionary = persistedPreVals.FormatAsDictionary(); var items = dictionary.Where(x => x.Key != "useLabel") - .OrderBy(x => x.Value.SortOrder) - .ToDictionary(x => x.Value.Id, x => x.Value.Value); + .OrderBy(x => x.Value.SortOrder); var items2 = new Dictionary(); foreach (var item in items) { - if (item.Value.DetectIsJson() == false) + var valueItem = new ColorPickerColor { - items2[item.Key] = item.Value; - continue; - } + Color = item.Value.Value, + Label = item.Value.Value, + SortOrder = item.Value.SortOrder + }; - try + if (item.Value.Value.DetectIsJson()) { - items2[item.Key] = JsonConvert.DeserializeObject(item.Value); + try + { + var valueObject = JsonConvert.DeserializeObject(item.Value.Value); + valueItem = new ColorPickerColor + { + Color = valueObject.Color, + Label = valueObject.Label, + SortOrder = valueObject.SortOrder + }; + } + catch + { + // let's say parsing Json failed, we'll not do anything, + // we'll just use the valueItem we built in the first place + } } - catch + + items2[item.Value.Id] = new JObject { - // let's say parsing Json failed, so what we have is the string - build json - items2[item.Key] = new JObject { { "color", item.Value }, { "label", item.Value } }; - } + { "value", valueItem.Color }, + { "label", valueItem.Label }, + { "sortOrder", valueItem.SortOrder } + }; } var result = new Dictionary { { "items", items2 } }; @@ -83,13 +99,13 @@ namespace Umbraco.Web.PropertyEditors var useLabel = false; if (editorValue.TryGetValue("useLabel", out var useLabelObj)) { - useLabel = useLabelObj is string && (string)useLabelObj == "1"; + useLabel = useLabelObj is string && (string) useLabelObj == "1"; result["useLabel"] = new PreValue(useLabel ? "1" : "0"); } // get all non-empty values var index = 0; - // we don't get the actual sortOrder but items get submitted in the sorted order, so let's just count them up + // items get submitted in the sorted order, so just count them up var sortOrder = -1; foreach (var preValue in val.OfType() .Where(x => x["value"] != null) @@ -105,10 +121,10 @@ namespace Umbraco.Web.PropertyEditors sortOrder++; var value = useLabel - ? JsonConvert.SerializeObject(new { value = color, label = label, sortOrder = sortOrder }) - : color; + ? JsonConvert.SerializeObject(new { value = color, label = label, sortOrder = sortOrder }) + : color; - return new PreValue(id, value, sortOrder); + return new PreValue(id, value, sortOrder); }) .WhereNotNull()) { @@ -154,4 +170,14 @@ namespace Umbraco.Web.PropertyEditors } } } + + internal class ColorPickerColor + { + [JsonProperty("value")] + public string Color { get; set; } + [JsonProperty("label")] + public string Label { get; set; } + [JsonProperty("sortOrder")] + public int SortOrder { get; set; } + } } From e0b15070569d58d4c6532c90e0c26d6fb0b5fe1a Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Mon, 23 Jul 2018 23:22:52 +0200 Subject: [PATCH 09/15] Show/hide label field when label is toggled Adds dib class to parent div to make the click target smaller --- .../directives/components/buttons/umbtoggle.directive.js | 6 ++++-- .../src/views/components/buttons/umb-toggle.html | 4 ++-- .../propertyeditors/colorpicker/colorpicker.prevalues.html | 2 +- .../colorpicker/multicolorpicker.controller.js | 7 ++++++- 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/buttons/umbtoggle.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/buttons/umbtoggle.directive.js index a7bdd4b741..e3c4cbf40c 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/buttons/umbtoggle.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/buttons/umbtoggle.directive.js @@ -64,7 +64,7 @@ (function () { 'use strict'; - function ToggleDirective(localizationService) { + function ToggleDirective(localizationService, eventsService) { function link(scope, el, attr, ctrl) { @@ -73,6 +73,7 @@ function onInit() { setLabelText(); + eventsService.emit("toggleValue", { value: scope.checked }); } function setLabelText() { @@ -98,7 +99,8 @@ } scope.click = function() { - if(scope.onClick) { + if (scope.onClick) { + eventsService.emit("toggleValue", { value: !scope.checked }); scope.onClick(); } }; diff --git a/src/Umbraco.Web.UI.Client/src/views/components/buttons/umb-toggle.html b/src/Umbraco.Web.UI.Client/src/views/components/buttons/umb-toggle.html index c7c34b2eaa..e850bf22b8 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/buttons/umb-toggle.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/buttons/umb-toggle.html @@ -1,4 +1,4 @@ - + {{ displayLabelOff }} @@ -16,4 +16,4 @@ {{ displayLabelOn }} - \ No newline at end of file + diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/colorpicker.prevalues.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/colorpicker.prevalues.html index 2d342c92fc..1df2e87685 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/colorpicker.prevalues.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/colorpicker.prevalues.html @@ -2,7 +2,7 @@
- +
diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/multicolorpicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/multicolorpicker.controller.js index f19fb260f4..3819b054a3 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/multicolorpicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/multicolorpicker.controller.js @@ -1,5 +1,5 @@ angular.module("umbraco").controller("Umbraco.PrevalueEditors.MultiColorPickerController", - function ($scope, $timeout, assetsService, angularHelper, $element, localizationService) { + function ($scope, $timeout, assetsService, angularHelper, $element, localizationService, eventsService) { //NOTE: We need to make each color an object, not just a string because you cannot 2-way bind to a primitive. var defaultColor = "000000"; var defaultLabel = null; @@ -15,6 +15,11 @@ "general_choose" ]; + $scope.labelEnabled = false; + eventsService.on("toggleValue", function (e, args) { + $scope.labelEnabled = args.value; + }); + localizationService.localizeMany(labelKeys).then(function (values) { $scope.labels.cancel = values[0]; $scope.labels.choose = values[1]; From 0f3a8bff5d9ed6422113e1c4be8de9522c6fa281 Mon Sep 17 00:00:00 2001 From: Bjarne Fyrstenborg Date: Thu, 26 Jul 2018 11:17:53 +0200 Subject: [PATCH 10/15] Add consistency and a few localizations --- .../src/less/property-editors.less | 77 ++++++++++--------- .../views/prevalueeditors/multivalues.html | 4 +- .../colorpicker/colorpicker.prevalues.html | 28 ++++--- .../multicolorpicker.controller.js | 2 +- 4 files changed, 62 insertions(+), 49 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/property-editors.less b/src/Umbraco.Web.UI.Client/src/less/property-editors.less index c70688d935..6a576c0e5e 100644 --- a/src/Umbraco.Web.UI.Client/src/less/property-editors.less +++ b/src/Umbraco.Web.UI.Client/src/less/property-editors.less @@ -148,47 +148,52 @@ ul.color-picker li a { cursor:pointer; } -.control-group.color-picker-preval .thumbnail { - width: 30px; - border: none; - cursor: move; -} + /* pre-value editor */ -.control-group.color-picker-preval .handle { - float: left; - display: inline-block; - margin: 5px 3px 5px 0; -} -.control-group.color-picker-preval div.color-picker-prediv { - display: inline-block; - width: 50%; -} +.control-group.color-picker-preval { + .thumbnail { + width: 30px; + border: none; + cursor: move; + } -.control-group.color-picker-preval pre { - display: inline; - font-family: monospace; - margin-right: 10px; - margin-left: 10px; - width: 50%; - white-space: nowrap; - overflow: hidden; - margin-bottom: 0; - vertical-align: middle; - padding-top: 7px; - padding-bottom: 7px; -} + .handle { + float: left; + display: inline-flex; + margin: 5px 3px 5px 0; + } -.control-group.color-picker-preval input[type="text"] { - min-width: 40%; - width: 40%; - display: inline-block; - margin-top: 1px; -} + div.color-picker-prediv { + display: inline-flex; + align-items: center; + } -.control-group.color-picker-preval label { - border: 1px solid @white; - padding: 6px; + pre { + display: inline; + font-family: monospace; + margin-right: 10px; + margin-left: 10px; + width: 50%; + white-space: nowrap; + overflow: hidden; + margin-bottom: 0; + vertical-align: middle; + padding-top: 7px; + padding-bottom: 7px; + } + + input[type="text"] { + min-width: 40%; + width: 40%; + display: inline-block; + margin-top: 1px; + } + + label { + border: 1px solid @white; + padding: 6px; + } } diff --git a/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/multivalues.html b/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/multivalues.html index 5c7d3b52c2..f9fbf0b9f0 100644 --- a/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/multivalues.html +++ b/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/multivalues.html @@ -4,7 +4,7 @@
- +
@@ -14,7 +14,7 @@
diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/colorpicker.prevalues.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/colorpicker.prevalues.html index 1df2e87685..3d9e2efdf8 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/colorpicker.prevalues.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/colorpicker.prevalues.html @@ -1,16 +1,24 @@ -
-
- - - - +
+
+
+ + + +
+
+ +
-
+
-
-
#{{item.value}}
{{item.label}}
- +
+
+
#{{item.value}}
{{item.label}}
+
+
+ Remove +
diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/multicolorpicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/multicolorpicker.controller.js index 3819b054a3..7ae728a85a 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/multicolorpicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/multicolorpicker.controller.js @@ -131,7 +131,7 @@ axis: 'y', containment: 'parent', cursor: 'move', - handle: ".handle, .thumbnail", + //handle: ".handle, .thumbnail", items: '> div.control-group', tolerance: 'pointer', update: function (e, ui) { From 99181d5bf45add5400dbc33ea57caf293fb38ec6 Mon Sep 17 00:00:00 2001 From: Bjarne Fyrstenborg Date: Thu, 26 Jul 2018 11:23:24 +0200 Subject: [PATCH 11/15] Adjust thumbnail styling --- src/Umbraco.Web.UI.Client/src/less/property-editors.less | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/property-editors.less b/src/Umbraco.Web.UI.Client/src/less/property-editors.less index 6a576c0e5e..afc14f0520 100644 --- a/src/Umbraco.Web.UI.Client/src/less/property-editors.less +++ b/src/Umbraco.Web.UI.Client/src/less/property-editors.less @@ -153,9 +153,10 @@ ul.color-picker li a { /* pre-value editor */ .control-group.color-picker-preval { .thumbnail { - width: 30px; + width: 36px; border: none; cursor: move; + border-radius: 3px; } .handle { From d2e8b084f523b4d93f373fa31d4a26fd11fc1aa2 Mon Sep 17 00:00:00 2001 From: Bjarne Fyrstenborg Date: Thu, 26 Jul 2018 11:25:38 +0200 Subject: [PATCH 12/15] Remove width on label --- src/Umbraco.Web.UI.Client/src/less/property-editors.less | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/property-editors.less b/src/Umbraco.Web.UI.Client/src/less/property-editors.less index afc14f0520..d247e9eb3b 100644 --- a/src/Umbraco.Web.UI.Client/src/less/property-editors.less +++ b/src/Umbraco.Web.UI.Client/src/less/property-editors.less @@ -186,7 +186,6 @@ ul.color-picker li a { input[type="text"] { min-width: 40%; - width: 40%; display: inline-block; margin-top: 1px; } From 89c84c7a309163f717bb7972927514ab94ea1e9a Mon Sep 17 00:00:00 2001 From: Bjarne Fyrstenborg Date: Thu, 26 Jul 2018 11:28:24 +0200 Subject: [PATCH 13/15] Set same width as for multivalues --- src/Umbraco.Web.UI.Client/src/less/property-editors.less | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Umbraco.Web.UI.Client/src/less/property-editors.less b/src/Umbraco.Web.UI.Client/src/less/property-editors.less index d247e9eb3b..798d8d0059 100644 --- a/src/Umbraco.Web.UI.Client/src/less/property-editors.less +++ b/src/Umbraco.Web.UI.Client/src/less/property-editors.less @@ -186,6 +186,7 @@ ul.color-picker li a { input[type="text"] { min-width: 40%; + width: 320px; display: inline-block; margin-top: 1px; } From c571284f403d50e8466d3bf8c950892ed58064b0 Mon Sep 17 00:00:00 2001 From: Bjarne Fyrstenborg Date: Thu, 26 Jul 2018 11:50:31 +0200 Subject: [PATCH 14/15] Adjust a bit more styling --- .../src/less/property-editors.less | 44 ++++++++++++------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/property-editors.less b/src/Umbraco.Web.UI.Client/src/less/property-editors.less index 798d8d0059..7075cd15f9 100644 --- a/src/Umbraco.Web.UI.Client/src/less/property-editors.less +++ b/src/Umbraco.Web.UI.Client/src/less/property-editors.less @@ -168,20 +168,25 @@ ul.color-picker li a { div.color-picker-prediv { display: inline-flex; align-items: center; - } - pre { - display: inline; - font-family: monospace; - margin-right: 10px; - margin-left: 10px; - width: 50%; - white-space: nowrap; - overflow: hidden; - margin-bottom: 0; - vertical-align: middle; - padding-top: 7px; - padding-bottom: 7px; + pre { + display: inline; + font-family: monospace; + margin-right: 10px; + margin-left: 10px; + width: 50%; + white-space: nowrap; + overflow: hidden; + margin-bottom: 0; + vertical-align: middle; + padding-top: 7px; + padding-bottom: 7px; + background: #f7f7f7; + } + + span { + margin-left: 5px; + } } input[type="text"] { @@ -191,9 +196,18 @@ ul.color-picker li a { margin-top: 1px; } + .sp-replacer { + margin-right: 18px; + } + label { - border: 1px solid @white; - padding: 6px; + border: 1px solid #fff; + padding: 7px 10px; + font-family: monospace; + border: 1px solid #dfdfe1; + background: #f7f7f7; + margin: 0 15px 0 0; + border-radius: 3px; } } From 567863079ecf4e14e3891bd1240223b071471137 Mon Sep 17 00:00:00 2001 From: Bjarne Fyrstenborg Date: Thu, 26 Jul 2018 12:03:31 +0200 Subject: [PATCH 15/15] Update a few names and descriptions for prevalues --- .../PropertyEditors/ColorListPreValueEditor.cs | 4 ++-- .../PropertyEditors/ValueListPreValueEditor.cs | 8 +++----- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/Umbraco.Web/PropertyEditors/ColorListPreValueEditor.cs b/src/Umbraco.Web/PropertyEditors/ColorListPreValueEditor.cs index 20dd3f9ec8..4eb9d04217 100644 --- a/src/Umbraco.Web/PropertyEditors/ColorListPreValueEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/ColorListPreValueEditor.cs @@ -22,9 +22,9 @@ namespace Umbraco.Web.PropertyEditors //use a custom editor too field.View = "views/propertyeditors/colorpicker/colorpicker.prevalues.html"; //change the description - field.Description = "Add and remove colors"; + field.Description = "Add, remove or sort colors."; //change the label - field.Name = "Add color"; + field.Name = "Colors"; //need to have some custom validation happening here field.Validators.Add(new ColorListValidator()); diff --git a/src/Umbraco.Web/PropertyEditors/ValueListPreValueEditor.cs b/src/Umbraco.Web/PropertyEditors/ValueListPreValueEditor.cs index 42484282e9..99400b4b48 100644 --- a/src/Umbraco.Web/PropertyEditors/ValueListPreValueEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/ValueListPreValueEditor.cs @@ -2,14 +2,12 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; -using System.Text.RegularExpressions; -using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Umbraco.Core; using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; -using umbraco; +using Umbraco.Core.Services; namespace Umbraco.Web.PropertyEditors { @@ -37,7 +35,7 @@ namespace Umbraco.Web.PropertyEditors { new PreValueField(new EnsureUniqueValuesValidator()) { - Description = "Add and remove values for the list", + Description = "Add, remove or sort values for the list.", //we're going to call this 'items' 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) @@ -45,7 +43,7 @@ namespace Umbraco.Web.PropertyEditors //It's also important to note that by default the dropdown angular controller is expecting the // config options to come in with a property called 'items' Key = "items", - Name = ui.Text("editdatatype", "addPrevalue"), + Name = ApplicationContext.Current.Services.TextService.Localize("editdatatype/addPrevalue"), View = "multivalues" } };