Error Showing Content - please login as admin for details.
Error Showing Content - please login as admin for details.
#7 Configurable Color Picker
2sxc Custom Color-Picker Input Field - Configurable
Input fields may expect some configuration - like default colors or WebApi endpoints. To enable such a configuration, we need a Content-Type which defines all the fields that can be configured. This can be in the app-data, or it can be stored in a subfolder of the field-extension, to make redestribution easier.
This example contains the json-exported content-type in the folder /system/field-string-app-color-pickr-pro/.data/contenttypes/
so you could just copy the extension folder to another app and use it from there.
So in this tutorial you'll learn how to:
- To see how the UI changes based on field configuration
- How to access such pre-configured settings with
connector.field.settings
- The Content-Type for configuration is included in the extension folder
Important: The feature "Public Use of Edit Form" is disabled
The feature is needed for anonymous users to use the Edit Form. Register your site here https://patrons.2sxc.org/ to get access to the feature.
New syntax: Configurable Color-Picker Input Field
This example shows two color-picker fields, with different initial configurations.
Hit this edit button to have a look:
@Kit.Toolbar.Empty().New("UiStringColorPickrPro").AsTag()
Old syntax: Configurable Color-Picker Input Field
This example shows two color-picker fields, with different initial configurations.
Hit this edit button to have a look:
@Edit.Toolbar(toolbar: new [] { "toolbar=empty", "+new?contentType=UiStringColorPickrPro" })
Important: We opened permissions that you can experience the edit dialog - so you can save, but it will just create draft data 😉.
/*
This examples shows a plain JS WebComponent which has has a Pickr color-picker
Uses the neat Pickr from https://simonwep.github.io/pickr/
This pro-picker allows the admin to define a set of recommended colors
*/
// always use an IFFE to ensure you don't put variables in the window scope
(() => {
const tagName = 'field-string-app-color-pickr-pro';
const pickrJsCdn = 'https://cdn.jsdelivr.net/npm/@simonwep/pickr/dist/pickr.min.js';
const html = `
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@simonwep/pickr/dist/themes/classic.min.css"/>
<div class="pickr-container"></div>`;
class StringColorPickerFlat extends HTMLElement {
/* Constructor for WebComponents - the first line must always be super() */
constructor() {
super();
}
/* connectedCallback() is the standard callback when the component has been attached */
connectedCallback() {
this.innerHTML = html;
// if the window.Pickr doesn't exist yet, load the JS from the CDN () and then do a callback
this.connector.loadScript('Pickr', pickrJsCdn, () => { this.initPick() });
}
/** disconnectedCallback() is a standard callback for clean-up */
disconnectedCallback() {
if (this.pickr) this.pickr.destroyAndRemove();
}
/** This is called when the JS is loaded from loadScript - so Pickr is ready */
initPick() {
this.pickr = new Pickr({
el: '.pickr-container',
theme: 'classic',
default: this.connector.data.value || null,
defaultRepresentation: 'HEXA',
swatches: this.getSwatches(),
components: {
// Main components
preview: true,
opacity: true,
hue: true,
// Input / output Options
interaction: {
hex: true,
rgba: true,
hsla: true,
hsva: true,
cmyk: true,
input: true,
cancel: true,
clear: true,
save: true,
},
},
});
// remember if we're working empty as of now
this.cleared = !this.connector.data.value;
// bind events for changes etc. to live-update the preview
this.pickr.on('change', (color, instance) => this.applyColor(instance));
this.pickr.on('changestop', (instance) => this.applyColor(instance));
this.pickr.on('swatchselect', (color, instance) => this.applyColor(instance));
this.pickr.on('save', (color,instance) => instance.hide());
this.pickr.on('hide', (instance) => this.update(instance));
this.pickr.on('clear', (instance) => {
this.cleared = true;
this.update();
});
}
/** Update the preview */
applyColor(instance) {
this.cleared = false;
instance.applyColor(true);
}
/** Update the value */
update(instance) {
// if it's still cleared, just save null
if (this.cleared) {
return this.updateIfChanged(null);
}
// otherwise get the current color
var color = instance.getColor();
if (color) color = color.toHEXA().toString();
this.updateIfChanged(color);
}
/** Only update the value if it really changed, so form isn't dirty if nothing was set */
updateIfChanged(value) {
var data = this.connector.data;
if (data.value === '' && value == null) return;
if (data.value === value) return;
data.update(value);
}
/** Load the settings and convert to swatch-list */
getSwatches() {
// the field "Swatches" is the field in the content-type containing the colors
// it's upper-case, because that's how the field is named
var swatches = this.connector.field.settings.Swatches;
if (!swatches) return [];
return swatches.split('\n').map((colorLine) => {
var withLabel = colorLine.trim().split(' ');
return withLabel[0]; // first part is the color
});
}
}
// Register this web component - if it hasn't been registered yet
if (!customElements.get(tagName)) customElements.define(tagName, StringColorPickerFlat);
})();
#7 Configurable Color Picker
{
"_": { "V": 1 },
"ContentType": {
"Id": "459d4ce3-b96b-4664-9947-75e46df9d33e",
"Name": "@string-app-color-pickr-pro",
"Scope": "System.Fields",
"Description": "",
"Attributes": [
{
"Name": "Swatches",
"Type": "String",
"InputType": "string-default",
"IsTitle": true,
"Metadata": [
{
"Id": 74876,
"Version": 2,
"Guid": "47026444-2298-4f78-8210-d088ec1ea14c",
"Type": { "Name": "@All", "Id": "@All" },
"Attributes": {
"String": {
"CustomJavaScript": { "*": "" },
"DefaultValue": { "*": "" },
"InputType": { "*": "string-default" },
"Name": { "*": "Swatches" },
"Notes": {
"*": "<p>Place recommended color codes - one on each line. Use HEXA format, like #770088aa</p>"
},
"ValidationRegExJavaScript": { "*": "" }
},
"Entity": { "Errors": { "*": [] }, "Warnings": { "*": [] } },
"Boolean": {
"Disabled": { "*": false },
"Required": { "*": false },
"VisibleInEditUI": { "*": true }
}
},
"Owner": "dnn:userid=1"
},
{
"Id": 74877,
"Version": 1,
"Guid": "75e73a53-b6cc-4f65-9cf8-22cdcb8fbc7f",
"Type": { "Name": "@String", "Id": "@String" },
"Attributes": {
"String": {
"DropdownValues": { "*": "" },
"InputType": { "*": "" }
}
},
"Owner": "dnn:userid=1"
},
{
"Id": 74878,
"Version": 1,
"Guid": "dea3bf2f-3a95-4a05-adcf-353de7ec07c0",
"Type": { "Name": "@string-default", "Id": "@string-default" },
"Attributes": { "Number": { "RowCount": { "*": 10.0 } } },
"Owner": "dnn:userid=1"
}
]
}
],
"Metadata": []
}
}