Merge pull request #2775 from bjarnef/dev-v7-U4-9025-2

U4-9025 - Add sortable to color picker prevalues
This commit is contained in:
Sebastiaan Janssen
2018-07-26 13:47:53 +02:00
committed by GitHub
9 changed files with 397 additions and 265 deletions

View File

@@ -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();
}
};

View File

@@ -148,50 +148,67 @@ ul.color-picker li a {
cursor:pointer;
}
.control-group.color-picker-preval .thumbnail {
width:30px;
border:none;
}
/* pre-value editor */
/*.control-group.color-picker-preval:before {
content: "";
display: inline-block;
vertical-align: middle;
height: 100%;
}*/
.control-group.color-picker-preval {
.thumbnail {
width: 36px;
border: none;
cursor: move;
border-radius: 3px;
}
/*.control-group.color-picker-preval div.thumbnail {
display: inline-block;
vertical-align: middle;
}*/
.control-group.color-picker-preval div.color-picker-prediv {
display: inline-block;
width: 60%;
}
.handle {
float: left;
display: inline-flex;
margin: 5px 3px 5px 0;
}
.control-group.color-picker-preval pre {
display: inline;
margin-right: 20px;
margin-left: 10px;
width: 50%;
white-space: nowrap;
overflow: hidden;
margin-bottom: 0;
vertical-align: middle;
}
div.color-picker-prediv {
display: inline-flex;
align-items: center;
.control-group.color-picker-preval input[type="text"] {
min-width: 40%;
width: 40%;
display: inline-block;
margin-right: 20px;
margin-top: 1px;
}
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;
}
.control-group.color-picker-preval label {
border: solid @white 1px;
padding: 6px;
span {
margin-left: 5px;
}
}
input[type="text"] {
min-width: 40%;
width: 320px;
display: inline-block;
margin-top: 1px;
}
.sp-replacer {
margin-right: 18px;
}
label {
border: 1px solid #fff;
padding: 7px 10px;
font-family: monospace;
border: 1px solid #dfdfe1;
background: #f7f7f7;
margin: 0 15px 0 0;
border-radius: 3px;
}
}
@@ -238,15 +255,6 @@ ul.color-picker li a {
text-decoration: none;
}
.umb-mediapicker .label.trashed {
position: absolute;
top: 5px;
right: 5px;
color: #fff;
background-color: #fe6561;
background-image: linear-gradient(180deg,#fe6561,#fe6561);
}
.umb-mediapicker .add-link-square {
height: 120px;
}
@@ -518,7 +526,6 @@ ul.color-picker li a {
.gravity-container .viewport {
max-width: 600px;
min-width: 250px;
}
.gravity-container .viewport:hover {
@@ -810,38 +817,28 @@ ul.color-picker li a {
padding-top: 27px;
}
.umb-fileupload .file-icon-wrap {
.umb-fileupload .file-icon {
text-align: center;
display: block;
position: relative;
padding: 5px 0;
/* fit text within container */
& + span {
word-wrap: break-word;
> .icon {
font-size: 70px;
line-height: 110%;
color: @gray-4;
text-align: center;
}
.file-icon {
position: relative;
display: inline-block;
> .icon {
font-size: 70px;
line-height: 110%;
color: @gray-4;
text-align: center;
}
> span {
> span {
color: @white;
background: @gray-4;
padding: 1px 3px;
font-size: 12px;
line-height: 130%;
position: absolute;
top: 40px;
left: 35px;
}
padding: 1px 3px;
font-size: 12px;
line-height: 130%;
position: absolute;
top: 45px;
left: 110px;
}
}
@@ -901,19 +898,6 @@ ul.color-picker li a {
border-bottom: 1px solid @tableBorder;
}
.umb-multiple-textbox .textbox-wrapper { align-items: center; margin-bottom: 15px; }
.umb-multiple-textbox .textbox-wrapper .umb-editor { margin-bottom: 0; }
.umb-multiple-textbox .textbox-wrapper i { margin-right: 5px; }
.umb-multiple-textbox .textbox-wrapper i.handle { margin-left: 5px; }
.umb-multiple-textbox .textbox-wrapper a.remove { margin-left: 5px; text-decoration: none; }
.umb-multiple-textbox .add-link {
&:extend(.umb-node-preview-add);
}
.umb-editor-wrapper .umb-multiple-textbox .add-link {
&:extend(.umb-editor-wrapper .umb-node-preview);
}
.umb-modal .umb-multiple-textbox .textbox-wrapper .umb-editor { flex: 1 1 auto; width: auto; }
//
// Tags
@@ -943,21 +927,7 @@ ul.color-picker li a {
//
// Nested boolean (e.g. list view bulk action permissions)
// -------------------------------------------------------
// ---------------------=====-----------------------------
.umb-nested-boolean label {margin-bottom: 8px; float: left; width: 320px;}
.umb-nested-boolean label span {float: left; width: 80%;}
.umb-nested-boolean label input[type='checkbox'] {margin-right: 10px; float: left;}
//
// Custom styles of property editors in property preview in document type editor
// -----------------------------------------------------------------------------
.umb-group-builder__property-preview {
.umb-property-editor {
.slider {
.tooltip {
display: none;
}
}
}
}

View File

@@ -1,4 +1,4 @@
<a href="" ng-click="click()" class="umb-toggle" ng-class="{'umb-toggle--checked': checked}">
<a href="" ng-click="click()" class="umb-toggle dib" ng-class="{'umb-toggle--checked': checked}">
<span ng-if="!labelPosition && showLabels === 'true' || labelPosition === 'left' && showLabels === 'true'">
<span ng-if="!checked" class="umb-toggle__label umb-toggle__label--left">{{ displayLabelOff }}</span>
@@ -16,4 +16,4 @@
<span ng-if="checked" class="umb-toggle__label umb-toggle__label--right">{{ displayLabelOn }}</span>
</span>
</a>
</a>

View File

@@ -4,7 +4,7 @@
<input overlay-submit-on-enter="false" name="newItem" focus-when="{{focusOnNew}}" ng-keydown="createNew($event)" type="text" ng-model="newItem" val-highlight="{{hasError}}" />
</div>
<div class="umb-prevalues-multivalues__right">
<button class="btn btn-info" ng-click="add($event)">Add</button>
<button class="btn btn-info" ng-click="add($event)"><localize key="general_add">Add</localize></button>
</div>
</div>
<div ui-sortable="sortableOptions">
@@ -14,7 +14,7 @@
<input type="text" ng-model="item.value" val-server="item_{{$index}}" required />
</div>
<div class="umb-prevalues-multivalues__right">
<a class="umb-node-preview__action" ng-click="remove(item, $event)">Remove</a>
<a class="umb-node-preview__action umb-node-preview__action--red" ng-click="remove(item, $event)"><localize key="general_remove">Remove</localize></a>
</div>
</div>
</div>

View File

@@ -1,46 +1,111 @@
function ColorPickerController($scope) {
$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;
$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,
@@ -48,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";
}
}

View File

@@ -1,13 +1,24 @@
<div ng-controller="Umbraco.PrevalueEditors.MultiColorPickerController">
<div class="control-group color-picker-preval">
<input name="newColor" type="hidden" />
<label for="newColor" val-highlight="hasError">#{{newColor}}</label>
<input name="newLabel" type="text" ng-model="newLabel" class="umb-editor color-label" placeholder="Label" />
<button class="btn add" ng-click="add($event)"><localize key="general_add">Add</localize></button>
<div class="umb-editor umb-prevalues-multivalues" ng-controller="Umbraco.PrevalueEditors.MultiColorPickerController">
<div class="control-group umb-prevalues-multivalues__add color-picker-preval">
<div class="umb-prevalues-multivalues__left">
<input name="newColor" type="hidden" />
<label for="newColor" val-highlight="{{hasError}}">#{{newColor}}</label>
<input name="newLabel" type="text" ng-model="newLabel" class="umb-editor color-label" placeholder="Label" ng-show="labelEnabled" />
</div>
<div class="umb-prevalues-multivalues__right">
<button class="btn btn-info add" ng-click="add($event)"><localize key="general_add">Add</localize></button>
</div>
</div>
<div class="control-group color-picker-preval" ng-repeat="item in model.value">
<div class="thumbnail span1" hex-bg-color="{{item.value}}" bg-orig="transparent"></div>
<div class="color-picker-prediv"><pre>#{{item.value}} - {{item.label}}</pre></div>
<button class="btn btn-danger" ng-click="remove(item, $event)"><localize key="general_remove">Remove</localize></button>
<div ui-sortable="sortableOptions" ng-model="model.value">
<div class="control-group umb-prevalues-multivalues__listitem color-picker-preval" ng-repeat="item in model.value">
<i class="icon icon-navigation handle"></i>
<div class="umb-prevalues-multivalues__left">
<div class="thumbnail span1" hex-bg-color="{{item.value}}" bg-orig="transparent"></div>
<div class="color-picker-prediv"><pre>#{{item.value}}</pre><span>{{item.label}}</span></div>
</div>
<div class="umb-prevalues-multivalues__right">
<a class="umb-node-preview__action umb-node-preview__action--red" ng-click="remove(item, $event)"><localize key="general_remove">Remove</localize></a>
</div>
</div>
</div>
</div>

View File

@@ -1,5 +1,5 @@
angular.module("umbraco").controller("Umbraco.PrevalueEditors.MultiColorPickerController",
function ($scope, $timeout, assetsService, angularHelper, $element) {
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;
@@ -8,6 +8,23 @@
$scope.newLavel = defaultLabel;
$scope.hasError = false;
$scope.labels = {};
var labelKeys = [
"general_cancel",
"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];
});
assetsService.load([
//"lib/spectrum/tinycolor.js",
"lib/spectrum/spectrum.js"
@@ -16,8 +33,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,
@@ -46,16 +63,22 @@
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.value = items;
}
@@ -104,6 +127,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);
});

View File

@@ -22,17 +22,17 @@ 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());
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."
});
}
@@ -40,28 +40,44 @@ namespace Umbraco.Web.PropertyEditors
public override IDictionary<string, object> ConvertDbToEditor(IDictionary<string, object> 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);
var items2 = new Dictionary<int, object>();
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<ColorPickerColor>(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<string, object> { { "items", items2 } };
@@ -80,9 +96,8 @@ 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";
result["useLabel"] = new PreValue(useLabel ? "1" : "0");
@@ -90,21 +105,26 @@ namespace Umbraco.Web.PropertyEditors
// get all non-empty values
var index = 0;
// items get submitted in the sorted order, so just count them up
var sortOrder = -1;
foreach (var preValue in val.OfType<JObject>()
.Where(x => x["value"] != null)
.Select(x =>
{
var idString = x["id"] == null ? "0" : x["id"].ToString();
int id;
if (int.TryParse(idString, out id) == false) id = 0;
int.TryParse(idString, out var id);
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);
sortOrder++;
var value = useLabel
? JsonConvert.SerializeObject(new { value = color, label = label, sortOrder = sortOrder })
: color;
return new PreValue(id, value, sortOrder);
})
.WhereNotNull())
{
@@ -150,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; }
}
}

View File

@@ -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"
}
};