Add color picker component (#8812)

This commit is contained in:
Bjarne Fyrstenborg
2020-09-30 19:57:39 +02:00
committed by GitHub
parent 4ecbb7abe6
commit 5911243908
8 changed files with 318 additions and 75 deletions

View File

@@ -0,0 +1,238 @@
/**
@ngdoc directive
@name umbraco.directives.directive:umbColorPicker
@restrict E
@scope
@description
<strong>Added in Umbraco v. 8.8:</strong> Use this directive to render a color picker.
<h3>Markup example</h3>
<pre>
<div ng-controller="My.ColorController as vm">
<umb-color-picker
options="vm.options"
on-show="vm.show(color)"
on-hide="vm.hide(color)"
on-change="vm.change(color)">
</umb-color-picker>
</div>
</pre>
<h3>Controller example</h3>
<pre>
(function () {
"use strict";
function Controller() {
var vm = this;
vm.options = {
type: "color",
color: defaultColor,
showAlpha: false,
showPalette: true,
showPaletteOnly: false,
preferredFormat: "hex",
};
vm.show = show;
vm.hide = hide;
vm.change = change;
function show(color) {
color.toHexString().trimStart("#");
}
function hide(color) {
color.toHexString().trimStart("#");
}
function change(color) {
color.toHexString().trimStart("#");
}
}
angular.module("umbraco").controller("My.ColorController", Controller);
})();
</pre>
@param {string} ngModel (<code>binding</code>): Value for the color picker.
@param {object} options (<code>binding</code>): Config object for the color picker.
@param {function} onBeforeShow (<code>expression</code>): Callback function before color picker is shown.
@param {function} onChange (<code>expression</code>): Callback function when the color is changed.
@param {function} onShow (<code>expression</code>): Callback function when color picker is shown.
@param {function} onHide (<code>expression</code>): Callback function when color picker is hidden.
@param {function} onMove (<code>expression</code>): Callback function when the color is moved in color picker.
**/
(function () {
'use strict';
function ColorPickerController($scope, $element, $timeout, assetsService, localizationService) {
const ctrl = this;
let colorPickerInstance = null;
let labels = {};
ctrl.$onInit = function() {
// load the separate css for the editor to avoid it blocking our js loading
assetsService.loadCss("lib/spectrum/spectrum.css", $scope);
// load the js file for the color picker
assetsService.load([
//"lib/spectrum/tinycolor.js",
"lib/spectrum/spectrum.js"
], $scope).then(function () {
// init color picker
grabElementAndRun();
});
}
function grabElementAndRun() {
var labelKeys = [
"general_cancel",
"general_choose",
"general_clear"
];
localizationService.localizeMany(labelKeys).then(values => {
labels.cancel = values[0];
labels.choose = values[1];
labels.clear = values[2];
});
$timeout(function () {
const element = $element.find('.umb-color-picker > input')[0];
setColorPicker(element, labels);
}, 0, true);
}
function setColorPicker(element, labels) {
// Spectrum options: https://seballot.github.io/spectrum/#options
const defaultOptions = {
type: "color",
color: null,
showAlpha: false,
showInitial: false,
showInput: true,
cancelText: labels.cancel,
clearText: labels.clear,
chooseText: labels.choose,
preferredFormat: "hex",
clickoutFiresChange: true
};
// If has ngModel set the color
if (ctrl.ngModel) {
defaultOptions.color = ctrl.ngModel;
}
//const options = ctrl.options ? ctrl.options : defaultOptions;
const options = Utilities.extend(defaultOptions, ctrl.options);
var elem = angular.element(element);
// Create new color pickr instance
const colorPicker = elem.spectrum(options);
colorPickerInstance = colorPicker;
if (colorPickerInstance) {
// destroy the color picker instance when the dom element is removed
elem.on('$destroy', function () {
colorPickerInstance.spectrum('destroy');
});
}
setUpCallbacks();
// Refresh the scope
$scope.$applyAsync();
}
// Spectrum events: https://seballot.github.io/spectrum/#events
function setUpCallbacks() {
if (colorPickerInstance) {
// bind hook for beforeShow
if (ctrl.onBeforeShow) {
colorPickerInstance.on('beforeShow.spectrum', (e, tinycolor) => {
$timeout(function () {
ctrl.onBeforeShow({ color: tinycolor });
});
});
}
// bind hook for show
if (ctrl.onShow) {
colorPickerInstance.on('show.spectrum', (e, tinycolor) => {
$timeout(function () {
ctrl.onShow({ color: tinycolor });
});
});
}
// bind hook for hide
if (ctrl.onHide) {
colorPickerInstance.on('hide.spectrum', (e, tinycolor) => {
$timeout(function () {
ctrl.onHide({ color: tinycolor });
});
});
}
// bind hook for change
if (ctrl.onChange) {
colorPickerInstance.on('change.spectrum', (e, tinycolor) => {
$timeout(function () {
ctrl.onChange({ color: tinycolor });
});
});
}
// bind hook for move
if (ctrl.onMove) {
colorPickerInstance.on('move.spectrum', (e, tinycolor) => {
$timeout(function () {
ctrl.onMove({ color: tinycolor });
});
});
}
}
}
}
angular
.module('umbraco.directives')
.component('umbColorPicker', {
template: '<div class="umb-color-picker"><input type="hidden" /></div>',
controller: ColorPickerController,
bindings: {
ngModel: '<',
options: '<',
onBeforeShow: '&',
onShow: '&',
onHide: '&',
onChange: '&',
onMove: '&'
}
});
})();

View File

@@ -46,7 +46,7 @@ For extra details about options and events take a look here: https://refreshless
</pre>
@param {object} ngModel (<code>binding</code>): Value for the slider.
@param {object} options (<code>binding</code>): Config object for the date picker.
@param {object} options (<code>binding</code>): Config object for the slider.
@param {callback} onSetup (<code>callback</code>): onSetup gets triggered when the slider is initialized
@param {callback} onUpdate (<code>callback</code>): onUpdate fires every time the slider values are changed.
@param {callback} onSlide (<code>callback</code>): onSlide gets triggered when the handle is being dragged.

View File

@@ -98,9 +98,9 @@
})();
</pre>
@param {string} icon (<code>binding</code>): The node icon.
@param {string} name (<code>binding</code>): The node name.
@param {string} published (<code>binding</code>): The node published state.
@param {array} items (<code>binding</code>): The items for the table.
@param {array} itemProperties (<code>binding</code>): The properties for the items to use in table.
@param {boolean} allowSelectAll (<code>binding</code>): Specify whether to allow select all.
@param {function} onSelect (<code>expression</code>): Callback function when the row is selected.
@param {function} onClick (<code>expression</code>): Callback function when the "Name" column link is clicked.
@param {function} onSelectAll (<code>expression</code>): Callback function when selecting all items.

View File

@@ -143,6 +143,7 @@
@import "components/umb-property-editor.less";
@import "components/umb-property-actions.less";
@import "components/umb-code-snippet.less";
@import "components/umb-color-picker.less";
@import "components/umb-color-swatches.less";
@import "components/check-circle.less";
@import "components/umb-file-icon.less";

View File

@@ -0,0 +1,21 @@
.umb-color-picker {
.sp-replacer {
display: inline-flex;
margin-right: 18px;
height: 32px;
&.sp-light {
background-color: @white;
}
.sp-preview {
margin: 5px;
height: auto;
}
.sp-dd {
line-height: 2rem;
}
}
}

View File

@@ -160,21 +160,6 @@
width: auto;
}
.sp-replacer {
display: inline-flex;
margin-right: 18px;
height: auto;
.sp-preview {
margin: 5px;
height: auto;
}
.sp-dd {
line-height: 2rem;
}
}
label {
border: 1px solid @white;
padding: 6px 10px;

View File

@@ -1,12 +1,20 @@
<div class="umb-property-editor umb-prevalues-multivalues" ng-controller="Umbraco.PrevalueEditors.MultiColorPickerController">
<div class="umb-property-editor umb-prevalues-multivalues" ng-controller="Umbraco.PrevalueEditors.MultiColorPickerController as vm">
<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" focus-when="{{focusOnNew}}" class="umb-property-editor color-label" placeholder="Label" ng-show="labelEnabled" />
<umb-color-picker
ng-model="newColor"
options="options"
on-hide="vm.hide(color)"
on-show="vm.show(color)"
on-change="vm.change(color)">
</umb-color-picker>
<label val-highlight="{{hasError}}">#{{newColor}}</label>
<input type="text" name="newLabel" ng-model="newLabel" focus-when="{{focusOnNew}}" class="umb-property-editor color-label" localize="placeholder" placeholder="@general_label" ng-show="vm.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>
<button type="button" class="btn btn-info add" ng-click="vm.add($event)"><localize key="general_add">Add</localize></button>
</div>
</div>
<div ui-sortable="sortableOptions" ng-model="model.value">
@@ -21,7 +29,7 @@
</div>
</div>
<div class="umb-prevalues-multivalues__right">
<button type="button" class="umb-node-preview__action umb-node-preview__action--red" ng-click="remove(item, $event)"><localize key="general_remove">Remove</localize></button>
<button type="button" class="umb-node-preview__action umb-node-preview__action--red" ng-click="vm.remove(item, $event)"><localize key="general_remove">Remove</localize></button>
</div>
</div>
</div>

View File

@@ -1,5 +1,17 @@
angular.module("umbraco").controller("Umbraco.PrevalueEditors.MultiColorPickerController",
function ($scope, $timeout, assetsService, angularHelper, $element, localizationService, eventsService) {
function ($scope, angularHelper, $element, eventsService) {
var vm = this;
vm.add = add;
vm.remove = remove;
vm.show = show;
vm.hide = hide;
vm.change = change;
vm.labelEnabled = false;
//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;
@@ -9,52 +21,33 @@
$scope.hasError = false;
$scope.focusOnNew = false;
$scope.labels = {};
$scope.options = {
type: "color",
color: defaultColor,
allowEmpty: false,
showAlpha: false
};
var labelKeys = [
"general_cancel",
"general_choose"
];
function hide(color) {
// show the add button
$element.find(".btn.add").show();
}
$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];
});
function show(color) {
// hide the add button
$element.find(".btn.add").hide();
}
assetsService.load([
//"lib/spectrum/tinycolor.js",
"lib/spectrum/spectrum.js"
], $scope).then(function () {
var elem = $element.find("input[name='newColor']");
elem.spectrum({
type: "color",
color: defaultColor,
showAlpha: false,
showInitial: false,
showInput: true,
chooseText: $scope.labels.choose,
cancelText: $scope.labels.cancel,
preferredFormat: "hex",
clickoutFiresChange: true,
hide: function (color) {
//show the add butotn
$element.find(".btn.add").show();
},
change: function (color) {
angularHelper.safeApply($scope, function () {
$scope.newColor = color.toHexString().trimStart("#"); // #ff0000
});
},
show: function() {
//hide the add butotn
$element.find(".btn.add").hide();
function change(color) {
angularHelper.safeApply($scope, function () {
if (color) {
$scope.newColor = color.toHexString().trimStart("#");
}
});
}
eventsService.on("toggleValue", function (e, args) {
vm.labelEnabled = args.value;
});
if (!Utilities.isArray($scope.model.value)) {
@@ -96,7 +89,7 @@
return label !== null && typeof label !== "undefined" && label !== "" && label.length && label.length > 0;
}
$scope.remove = function (item, evt) {
function remove(item, evt) {
evt.preventDefault();
@@ -105,9 +98,9 @@
});
angularHelper.getCurrentForm($scope).$setDirty();
};
}
$scope.add = function (evt) {
function add(evt) {
evt.preventDefault();
if ($scope.newColor) {
@@ -127,11 +120,10 @@
return;
}
//there was an error, do the highlight (will be set back by the directive)
// there was an error, do the highlight (will be set back by the directive)
$scope.hasError = true;
}
};
}
$scope.sortableOptions = {
axis: 'y',
@@ -145,6 +137,4 @@
}
};
//load the separate css for the editor to avoid it blocking our js loading
assetsService.loadCss("lib/spectrum/spectrum.css", $scope);
});