Added sorting to picker inputs

- Data Type picker
- Document Type picker
- Entity picker
- Language picker
- Media Type picker
- Stylesheet Rule picker
- User picker

+ code tidy-up, consistency between picker code/markup
This commit is contained in:
leekelleher
2024-04-23 11:01:52 +01:00
parent 85c1a91570
commit ede4033d5e
7 changed files with 369 additions and 200 deletions

View File

@@ -1,14 +1,30 @@
import { css, html, customElement, property, state, repeat, when } from '@umbraco-cms/backoffice/external/lit';
import { css, html, customElement, property, repeat, state, when } from '@umbraco-cms/backoffice/external/lit';
import { splitStringToArray } from '@umbraco-cms/backoffice/utils';
import { UUIFormControlMixin } from '@umbraco-cms/backoffice/external/uui';
import { UmbChangeEvent } from '@umbraco-cms/backoffice/event';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { UmbSorterController } from '@umbraco-cms/backoffice/sorter';
import { UUIFormControlMixin } from '@umbraco-cms/backoffice/external/uui';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import type { UmbPickerInputContext } from '@umbraco-cms/backoffice/picker-input';
import type { UmbUniqueItemModel } from '@umbraco-cms/backoffice/models';
@customElement('umb-input-entity')
export class UmbInputEntityElement extends UUIFormControlMixin(UmbLitElement, '') {
// TODO: [LK] Add sort ordering.
#sorter = new UmbSorterController<string>(this, {
getUniqueOfElement: (element) => {
return element.id;
},
getUniqueOfModel: (modelEntry) => {
return modelEntry;
},
identifier: 'Umb.SorterIdentifier.InputEntity',
itemSelector: 'uui-ref-node',
containerSelector: 'uui-ref-list',
onChange: ({ model }) => {
this.selection = model;
this.dispatchEvent(new UmbChangeEvent());
},
});
protected getFormElement() {
return undefined;
@@ -41,14 +57,23 @@ export class UmbInputEntityElement extends UUIFormControlMixin(UmbLitElement, ''
#max: number = Infinity;
@property({ attribute: false })
getIcon?: (item: any) => string;
getIcon?: (item: UmbUniqueItemModel) => string;
@property({ type: String, attribute: 'min-message' })
maxMessage = 'This field exceeds the allowed amount of items';
@property({ type: Array })
public set selection(uniques: Array<string>) {
this.#pickerContext?.setSelection(uniques);
this.#sorter.setModel(uniques);
}
public get selection(): Array<string> | undefined {
return this.#pickerContext?.getSelection();
}
@property()
public set value(value: string) {
this.selection = splitStringToArray(value);
public set value(uniques: string) {
this.selection = splitStringToArray(uniques);
}
public get value(): string {
return this.selection?.join(',') ?? '';
@@ -60,18 +85,12 @@ export class UmbInputEntityElement extends UUIFormControlMixin(UmbLitElement, ''
this.#pickerContext = new ctor(this);
this.#observePickerContext();
}
#pickerContext?: UmbPickerInputContext<any>;
public set selection(value: Array<string>) {
this.#pickerContext?.setSelection(value);
}
public get selection(): Array<string> | undefined {
return this.#pickerContext?.getSelection();
}
@state()
private _items?: Array<UmbUniqueItemModel>;
#pickerContext?: UmbPickerInputContext<any>;
constructor() {
super();
}
@@ -100,19 +119,8 @@ export class UmbInputEntityElement extends UUIFormControlMixin(UmbLitElement, ''
this.#pickerContext.min = this.min;
this.#pickerContext.max = this.max;
this.observe(
this.#pickerContext.selection,
(selection) => (this.value = selection?.join(',') ?? ''),
'observeSelection',
);
this.observe(
this.#pickerContext.selectedItems,
(selectedItems) => {
this._items = selectedItems;
},
'observeSelectedItems',
);
this.observe(this.#pickerContext.selection, (selection) => (this.value = selection.join(',')), '_observeSelection');
this.observe(this.#pickerContext.selectedItems, (selectedItems) => (this._items = selectedItems), '_observerItems');
}
#openPicker() {
@@ -121,6 +129,10 @@ export class UmbInputEntityElement extends UUIFormControlMixin(UmbLitElement, ''
});
}
#removeItem(item: UmbUniqueItemModel) {
this.#pickerContext?.requestRemoveItem(item.unique);
}
render() {
return html`${this.#renderItems()} ${this.#renderAddButton()}`;
}
@@ -153,12 +165,10 @@ export class UmbInputEntityElement extends UUIFormControlMixin(UmbLitElement, ''
if (!item.unique) return;
const icon = this.getIcon?.(item) ?? item.icon ?? '';
return html`
<uui-ref-node name=${item.name}>
<uui-ref-node name=${item.name} id=${item.unique}>
${when(icon, () => html`<umb-icon slot="icon" name=${icon}></umb-icon>`)}
<uui-action-bar slot="actions">
<uui-button
@click=${() => this.#pickerContext?.requestRemoveItem(item.unique)}
label=${this.localize.term('general_remove')}></uui-button>
<uui-button @click=${() => this.#removeItem(item)} label=${this.localize.term('general_remove')}></uui-button>
</uui-action-bar>
</uui-ref-node>
`;

View File

@@ -1,12 +1,31 @@
import type { UmbDataTypeItemModel } from '../../repository/item/types.js';
import { UmbDataTypePickerContext } from './data-type-input.context.js';
import { css, html, customElement, property, state } from '@umbraco-cms/backoffice/external/lit';
import { UUIFormControlMixin } from '@umbraco-cms/backoffice/external/uui';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { css, html, customElement, nothing, property, repeat, state } from '@umbraco-cms/backoffice/external/lit';
import { splitStringToArray } from '@umbraco-cms/backoffice/utils';
import { UmbChangeEvent } from '@umbraco-cms/backoffice/event';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { UmbSorterController } from '@umbraco-cms/backoffice/sorter';
import { UUIFormControlMixin } from '@umbraco-cms/backoffice/external/uui';
// TODO: Rename to 'umb-input-data-type'. [LK]
@customElement('umb-data-type-input')
export class UmbDataTypeInputElement extends UUIFormControlMixin(UmbLitElement, '') {
#sorter = new UmbSorterController<string>(this, {
getUniqueOfElement: (element) => {
return element.id;
},
getUniqueOfModel: (modelEntry) => {
return modelEntry;
},
identifier: 'Umb.SorterIdentifier.InputDataType',
itemSelector: 'uui-ref-node-data-type',
containerSelector: 'uui-ref-list',
onChange: ({ model }) => {
this.selection = model;
this.dispatchEvent(new UmbChangeEvent());
},
});
/**
* This is a minimum amount of selected items in this input.
* @type {number}
@@ -54,20 +73,20 @@ export class UmbDataTypeInputElement extends UUIFormControlMixin(UmbLitElement,
maxMessage = 'This field exceeds the allowed amount of items';
@property({ type: Array })
public set selection(ids: Array<string> | undefined) {
this.#pickerContext.setSelection(ids ?? []);
public set selection(uniques: Array<string>) {
this.#pickerContext.setSelection(uniques ?? []);
this.#sorter.setModel(uniques);
}
public get selection(): Array<string> | undefined {
public get selection(): Array<string> {
return this.#pickerContext.getSelection();
}
@property()
public set value(idsString: string) {
// Its with full purpose we don't call super.value, as thats being handled by the observation of the context selection.
this.selection = splitStringToArray(idsString);
public set value(uniques: string) {
this.selection = splitStringToArray(uniques);
}
public get value(): string {
return this.selection?.join(',') ?? '';
return this.selection.join(',');
}
@state()
@@ -90,33 +109,58 @@ export class UmbDataTypeInputElement extends UUIFormControlMixin(UmbLitElement,
() => !!this.max && this.#pickerContext.getSelection().length > this.max,
);
this.observe(this.#pickerContext.selection, (selection) => (this.value = selection.join(',')));
this.observe(this.#pickerContext.selectedItems, (selectedItems) => (this._items = selectedItems));
this.observe(this.#pickerContext.selection, (selection) => (this.value = selection.join(',')), '_observeSelection');
this.observe(this.#pickerContext.selectedItems, (selectedItems) => (this._items = selectedItems), '_observerItems');
}
protected getFormElement() {
return undefined;
}
#openPicker() {
this.#pickerContext.openPicker({
hideTreeRoot: true,
});
}
#removeItem(item: UmbDataTypeItemModel) {
this.#pickerContext.requestRemoveItem(item.unique);
}
render() {
return html`${this.#renderItems()} ${this.#renderAddButton()}`;
}
#renderAddButton() {
if (this.max > 0 && this.selection.length >= this.max) return nothing;
return html`
<uui-ref-list>${this._items?.map((item) => this._renderItem(item))}</uui-ref-list>
<uui-button
id="add-button"
id="btn-add"
look="placeholder"
@click=${() => this.#pickerContext.openPicker({ hideTreeRoot: true })}
label=${this.localize.term('general_choose')}></uui-button>
@click=${this.#openPicker}
label="${this.localize.term('general_choose')}"></uui-button>
`;
}
private _renderItem(item: UmbDataTypeItemModel) {
#renderItems() {
if (!this._items) return nothing;
return html`
<uui-ref-list>
${repeat(
this._items,
(item) => item.unique,
(item) => this.#renderItem(item),
)}
</uui-ref-list>
`;
}
#renderItem(item: UmbDataTypeItemModel) {
if (!item.unique) return;
return html`
<uui-ref-node-data-type name=${item.name}>
<uui-ref-node-data-type name=${item.name} id=${item.unique}>
<uui-action-bar slot="actions">
<uui-button
@click=${() => this.#pickerContext.requestRemoveItem(item.unique)}
label=${this.localize.term('general_remove')}></uui-button>
<uui-button @click=${() => this.#removeItem(item)} label=${this.localize.term('general_remove')}></uui-button>
</uui-action-bar>
</uui-ref-node-data-type>
`;
@@ -124,7 +168,7 @@ export class UmbDataTypeInputElement extends UUIFormControlMixin(UmbLitElement,
static styles = [
css`
#add-button {
#btn-add {
width: 100%;
}
`,

View File

@@ -1,22 +1,31 @@
import type { UmbDocumentTypeItemModel } from '../../repository/index.js';
import { UmbDocumentTypePickerContext } from './input-document-type.context.js';
import {
css,
html,
customElement,
property,
state,
ifDefined,
repeat,
nothing,
} from '@umbraco-cms/backoffice/external/lit';
import { UUIFormControlMixin } from '@umbraco-cms/backoffice/external/uui';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { css, html, customElement, property, state, repeat, nothing } from '@umbraco-cms/backoffice/external/lit';
import { splitStringToArray } from '@umbraco-cms/backoffice/utils';
import { UMB_WORKSPACE_MODAL, UmbModalRouteRegistrationController } from '@umbraco-cms/backoffice/modal';
import { UmbChangeEvent } from '@umbraco-cms/backoffice/event';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { UmbModalRouteRegistrationController, UMB_WORKSPACE_MODAL } from '@umbraco-cms/backoffice/modal';
import { UmbSorterController } from '@umbraco-cms/backoffice/sorter';
import { UUIFormControlMixin } from '@umbraco-cms/backoffice/external/uui';
@customElement('umb-input-document-type')
export class UmbInputDocumentTypeElement extends UUIFormControlMixin(UmbLitElement, '') {
#sorter = new UmbSorterController<string>(this, {
getUniqueOfElement: (element) => {
return element.id;
},
getUniqueOfModel: (modelEntry) => {
return modelEntry;
},
identifier: 'Umb.SorterIdentifier.InputDocumentType',
itemSelector: 'uui-ref-node-document-type',
containerSelector: 'uui-ref-list',
onChange: ({ model }) => {
this.selection = model;
this.dispatchEvent(new UmbChangeEvent());
},
});
/**
* Limits to only select Element Types
* @type {boolean}
@@ -73,17 +82,17 @@ export class UmbInputDocumentTypeElement extends UUIFormControlMixin(UmbLitEleme
maxMessage = 'This field exceeds the allowed amount of items';
@property({ type: Array })
public set selection(ids: Array<string> | undefined) {
this.#pickerContext.setSelection(ids ?? []);
public set selection(uniques: Array<string>) {
this.#pickerContext.setSelection(uniques);
this.#sorter.setModel(uniques);
}
public get selection(): Array<string> {
return this.#pickerContext.getSelection();
}
@property()
public set value(idsString: string) {
// Its with full purpose we don't call super.value, as thats being handled by the observation of the context selection.
this.selection = splitStringToArray(idsString);
public set value(uniques: string) {
this.selection = splitStringToArray(uniques);
}
public get value(): string {
return this.selection.join(',');
@@ -93,7 +102,7 @@ export class UmbInputDocumentTypeElement extends UUIFormControlMixin(UmbLitEleme
private _items?: Array<UmbDocumentTypeItemModel>;
@state()
private _editDocumentTypePath = '';
private _editPath = '';
#pickerContext = new UmbDocumentTypePickerContext(this);
@@ -106,7 +115,7 @@ export class UmbInputDocumentTypeElement extends UUIFormControlMixin(UmbLitEleme
return { data: { entityType: 'document-type', preset: {} } };
})
.observeRouteBuilder((routeBuilder) => {
this._editDocumentTypePath = routeBuilder({});
this._editPath = routeBuilder({});
});
this.addValidator(
@@ -121,8 +130,8 @@ export class UmbInputDocumentTypeElement extends UUIFormControlMixin(UmbLitEleme
() => !!this.max && this.#pickerContext.getSelection().length > this.max,
);
this.observe(this.#pickerContext.selection, (selection) => (this.value = selection.join(',')));
this.observe(this.#pickerContext.selectedItems, (selectedItems) => (this._items = selectedItems));
this.observe(this.#pickerContext.selection, (selection) => (this.value = selection.join(',')), '_observeSelection');
this.observe(this.#pickerContext.selectedItems, (selectedItems) => (this._items = selectedItems), '_observerItems');
}
protected getFormElement() {
@@ -130,64 +139,53 @@ export class UmbInputDocumentTypeElement extends UUIFormControlMixin(UmbLitEleme
}
#openPicker() {
if (this.elementTypesOnly) {
this.#pickerContext.openPicker({
hideTreeRoot: true,
pickableFilter: (x) => x.isElement,
});
} else {
this.#pickerContext.openPicker({
hideTreeRoot: true,
});
}
this.#pickerContext.openPicker({
hideTreeRoot: true,
pickableFilter: this.elementTypesOnly ? (x) => x.isElement : undefined,
});
}
#removeItem(item: UmbDocumentTypeItemModel) {
this.#pickerContext.requestRemoveItem(item.unique);
}
render() {
return html` ${this.#renderItems()} ${this.#renderAddButton()} `;
}
#renderItems() {
if (!this._items) return nothing;
return html`
<uui-ref-list
>${repeat(
this._items,
(item) => item.unique,
(item) => this.#renderItem(item),
)}</uui-ref-list
>
`;
return html`${this.#renderItems()} ${this.#renderAddButton()}`;
}
#renderAddButton() {
if (this.max > 0 && this.selection.length >= this.max) return nothing;
return html`
<uui-button
id="add-button"
id="btn-add"
look="placeholder"
@click=${this.#openPicker}
label="${this.localize.term('general_choose')}"></uui-button>
`;
}
#renderItems() {
if (!this._items) return nothing;
return html`
<uui-ref-list>
${repeat(
this._items,
(item) => item.unique,
(item) => this.#renderItem(item),
)}
</uui-ref-list>
`;
}
#renderItem(item: UmbDocumentTypeItemModel) {
if (!item.unique) return;
const href = `${this._editPath}edit/${item.unique}`;
return html`
<uui-ref-node-document-type name=${ifDefined(item.name)}>
<uui-ref-node-document-type name=${item.name} id=${item.unique}>
${this.#renderIcon(item)}
<uui-action-bar slot="actions">
<uui-button
compact
href=${this._editDocumentTypePath + 'edit/' + item.unique}
label=${this.localize.term('general_edit') + ` ${item.name}`}>
<uui-icon name="icon-edit"></uui-icon>
</uui-button>
<uui-button
compact
@click=${() => this.#pickerContext.requestRemoveItem(item.unique)}
label="Edit Document Type ${item.name}">
<uui-icon name="icon-trash"></uui-icon>
</uui-button>
<uui-button href=${href} label=${this.localize.term('general_open')}></uui-button>
<uui-button @click=${() => this.#removeItem(item)} label=${this.localize.term('general_remove')}></uui-button>
</uui-action-bar>
</uui-ref-node-document-type>
`;
@@ -200,7 +198,7 @@ export class UmbInputDocumentTypeElement extends UUIFormControlMixin(UmbLitEleme
static styles = [
css`
#add-button {
#btn-add {
width: 100%;
}
`,

View File

@@ -1,12 +1,30 @@
import type { UmbLanguageItemModel } from '../../repository/index.js';
import { UmbLanguagePickerContext } from './input-language.context.js';
import { css, html, ifDefined, customElement, property, state } from '@umbraco-cms/backoffice/external/lit';
import { UUIFormControlMixin } from '@umbraco-cms/backoffice/external/uui';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { css, html, customElement, property, state, repeat, nothing } from '@umbraco-cms/backoffice/external/lit';
import { splitStringToArray } from '@umbraco-cms/backoffice/utils';
import { UmbChangeEvent } from '@umbraco-cms/backoffice/event';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { UmbSorterController } from '@umbraco-cms/backoffice/sorter';
import { UUIFormControlMixin } from '@umbraco-cms/backoffice/external/uui';
@customElement('umb-input-language')
export class UmbInputLanguageElement extends UUIFormControlMixin(UmbLitElement, '') {
#sorter = new UmbSorterController<string>(this, {
getUniqueOfElement: (element) => {
return element.id;
},
getUniqueOfModel: (modelEntry) => {
return modelEntry;
},
identifier: 'Umb.SorterIdentifier.InputLanguage',
itemSelector: 'uui-ref-node',
containerSelector: 'uui-ref-list',
onChange: ({ model }) => {
this.selection = model;
this.dispatchEvent(new UmbChangeEvent());
},
});
/**
* This is a minimum amount of selected items in this input.
* @type {number}
@@ -56,8 +74,10 @@ export class UmbInputLanguageElement extends UUIFormControlMixin(UmbLitElement,
@property({ type: Object, attribute: false })
public filter: (language: UmbLanguageItemModel) => boolean = () => true;
@property({ type: Array })
public set selection(uniques: Array<string>) {
this.#pickerContext.setSelection(uniques);
this.#sorter.setModel(uniques);
}
public get selection(): Array<string> {
return this.#pickerContext.getSelection();
@@ -65,7 +85,6 @@ export class UmbInputLanguageElement extends UUIFormControlMixin(UmbLitElement,
@property()
public set value(uniques: string) {
// Its with full purpose we don't call super.value, as thats being handled by the observation of the context selection.
this.selection = splitStringToArray(uniques);
}
public get value(): string {
@@ -92,8 +111,8 @@ export class UmbInputLanguageElement extends UUIFormControlMixin(UmbLitElement,
() => !!this.max && this.#pickerContext.getSelection().length > this.max,
);
this.observe(this.#pickerContext.selection, (selection) => (this.value = selection.join(',')));
this.observe(this.#pickerContext.selectedItems, (selectedItems) => (this._items = selectedItems));
this.observe(this.#pickerContext.selection, (selection) => (this.value = selection.join(',')), '_observeSelection');
this.observe(this.#pickerContext.selectedItems, (selectedItems) => (this._items = selectedItems), '_observerItems');
}
protected getFormElement() {
@@ -106,14 +125,35 @@ export class UmbInputLanguageElement extends UUIFormControlMixin(UmbLitElement,
});
}
#removeItem(item: UmbLanguageItemModel) {
this.#pickerContext.requestRemoveItem(item.unique);
}
render() {
return html`${this.#renderItems()} ${this.#renderAddButton()}`;
}
#renderAddButton() {
if (this.max > 0 && this.selection.length >= this.max) return nothing;
return html`
<uui-ref-list> ${this._items.map((item) => this.#renderItem(item))} </uui-ref-list>
<uui-button
id="add-button"
id="btn-add"
look="placeholder"
@click=${this.#openPicker}
label=${this.localize.term('general_choose')}></uui-button>
label="${this.localize.term('general_choose')}"></uui-button>
`;
}
#renderItems() {
if (!this._items) return nothing;
return html`
<uui-ref-list>
${repeat(
this._items,
(item) => item.unique,
(item) => this.#renderItem(item),
)}
</uui-ref-list>
`;
}
@@ -121,11 +161,9 @@ export class UmbInputLanguageElement extends UUIFormControlMixin(UmbLitElement,
if (!item.unique) return;
return html`
<!-- TODO: add language ref element -->
<uui-ref-node name=${ifDefined(item.name === null ? undefined : item.name)} detail=${ifDefined(item.unique)}>
<uui-ref-node name=${item.name} id=${item.unique} detail=${item.unique}>
<uui-action-bar slot="actions">
<uui-button
@click=${() => this.#pickerContext.requestRemoveItem(item.unique)}
label=${this.localize.term('general_remove')}></uui-button>
<uui-button @click=${() => this.#removeItem(item)} label=${this.localize.term('general_remove')}></uui-button>
</uui-action-bar>
</uui-ref-node>
`;
@@ -133,7 +171,7 @@ export class UmbInputLanguageElement extends UUIFormControlMixin(UmbLitElement,
static styles = [
css`
#add-button {
#btn-add {
width: 100%;
}
`,

View File

@@ -1,12 +1,31 @@
import type { UmbMediaTypeItemModel } from '../../repository/index.js';
import { UmbMediaTypePickerContext } from './input-media-type.context.js';
import { css, html, customElement, property, state, ifDefined, repeat } from '@umbraco-cms/backoffice/external/lit';
import { UUIFormControlMixin } from '@umbraco-cms/backoffice/external/uui';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { css, html, customElement, property, state, repeat, nothing } from '@umbraco-cms/backoffice/external/lit';
import { splitStringToArray } from '@umbraco-cms/backoffice/utils';
import { UmbChangeEvent } from '@umbraco-cms/backoffice/event';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { UmbModalRouteRegistrationController, UMB_WORKSPACE_MODAL } from '@umbraco-cms/backoffice/modal';
import { UmbSorterController } from '@umbraco-cms/backoffice/sorter';
import { UUIFormControlMixin } from '@umbraco-cms/backoffice/external/uui';
@customElement('umb-input-media-type')
export class UmbInputMediaTypeElement extends UUIFormControlMixin(UmbLitElement, '') {
#sorter = new UmbSorterController<string>(this, {
getUniqueOfElement: (element) => {
return element.id;
},
getUniqueOfModel: (modelEntry) => {
return modelEntry;
},
identifier: 'Umb.SorterIdentifier.InputMediaType',
itemSelector: 'uui-ref-node-document-type',
containerSelector: 'uui-ref-list',
onChange: ({ model }) => {
this.selection = model;
this.dispatchEvent(new UmbChangeEvent());
},
});
/**
* This is a minimum amount of selected items in this input.
* @type {number}
@@ -53,30 +72,43 @@ export class UmbInputMediaTypeElement extends UUIFormControlMixin(UmbLitElement,
@property({ type: String, attribute: 'min-message' })
maxMessage = 'This field exceeds the allowed amount of items';
public set selection(ids: Array<string>) {
this.#pickerContext.setSelection(ids);
@property({ type: Array })
public set selection(uniques: Array<string>) {
this.#pickerContext.setSelection(uniques);
this.#sorter.setModel(uniques);
}
public get selection(): Array<string> {
return this.#pickerContext.getSelection();
}
@property()
public set value(idsString: string) {
// Its with full purpose we don't call super.value, as thats being handled by the observation of the context selection.
this.selection = splitStringToArray(idsString);
public set value(uniques: string) {
this.selection = splitStringToArray(uniques);
}
public get value() {
public get value(): string {
return this.selection.join(',');
}
@state()
private _items?: Array<UmbMediaTypeItemModel>;
@state()
private _editPath = '';
#pickerContext = new UmbMediaTypePickerContext(this);
constructor() {
super();
new UmbModalRouteRegistrationController(this, UMB_WORKSPACE_MODAL)
.addAdditionalPath('media-type')
.onSetup(() => {
return { data: { entityType: 'media-type', preset: {} } };
})
.observeRouteBuilder((routeBuilder) => {
this._editPath = routeBuilder({});
});
this.addValidator(
'rangeUnderflow',
() => this.minMessage,
@@ -89,8 +121,8 @@ export class UmbInputMediaTypeElement extends UUIFormControlMixin(UmbLitElement,
() => !!this.max && this.#pickerContext.getSelection().length > this.max,
);
this.observe(this.#pickerContext.selection, (selection) => (this.value = selection.join(',')));
this.observe(this.#pickerContext.selectedItems, (selectedItems) => (this._items = selectedItems));
this.observe(this.#pickerContext.selection, (selection) => (this.value = selection.join(',')), '_observeSelection');
this.observe(this.#pickerContext.selectedItems, (selectedItems) => (this._items = selectedItems), '_observerItems');
}
protected getFormElement() {
@@ -103,12 +135,27 @@ export class UmbInputMediaTypeElement extends UUIFormControlMixin(UmbLitElement,
});
}
#removeItem(item: UmbMediaTypeItemModel) {
this.#pickerContext.requestRemoveItem(item.unique);
}
render() {
return html` ${this.#renderItems()} ${this.#renderAddButton()} `;
return html`${this.#renderItems()} ${this.#renderAddButton()}`;
}
#renderAddButton() {
if (this.max > 0 && this.selection.length >= this.max) return nothing;
return html`
<uui-button
id="btn-add"
look="placeholder"
@click=${this.#openPicker}
label="${this.localize.term('general_choose')}"></uui-button>
`;
}
#renderItems() {
if (!this._items) return;
if (!this._items) return nothing;
return html`
<uui-ref-list>
${repeat(
@@ -120,26 +167,15 @@ export class UmbInputMediaTypeElement extends UUIFormControlMixin(UmbLitElement,
`;
}
#renderAddButton() {
if (this.max === 1 && this.selection.length >= this.max) return;
return html`
<uui-button
id="btn-add"
look="placeholder"
@click=${this.#openPicker}
label="${this.localize.term('general_choose')}"></uui-button>
`;
}
#renderItem(item: UmbMediaTypeItemModel) {
if (!item.unique) return;
const href = `${this._editPath}edit/${item.unique}`;
return html`
<uui-ref-node-document-type name=${ifDefined(item.name)}>
<uui-ref-node-document-type name=${item.name} id=${item.unique}>
${this.#renderIcon(item)}
<uui-action-bar slot="actions">
<uui-button
@click=${() => this.#pickerContext.requestRemoveItem(item.unique)}
label="${this.localize.term('general_remove')} ${item.name}"></uui-button>
<uui-button href=${href} label=${this.localize.term('general_open')}></uui-button>
<uui-button @click=${() => this.#removeItem(item)} label=${this.localize.term('general_remove')}></uui-button>
</uui-action-bar>
</uui-ref-node-document-type>
`;

View File

@@ -1,15 +1,26 @@
import type { UmbStylesheetRule } from '../../types.js';
import { UMB_STYLESHEET_RULE_SETTINGS_MODAL } from './stylesheet-rule-settings-modal.token.js';
import { UmbChangeEvent } from '@umbraco-cms/backoffice/event';
import { css, html, customElement, repeat, property } from '@umbraco-cms/backoffice/external/lit';
import { UUIFormControlMixin } from '@umbraco-cms/backoffice/external/uui';
import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal';
import { UmbChangeEvent } from '@umbraco-cms/backoffice/event';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
// TODO: add sorting when we have a generic sorting component/functionality for ref lists
import { UmbSorterController } from '@umbraco-cms/backoffice/sorter';
import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal';
import { UUIFormControlMixin } from '@umbraco-cms/backoffice/external/uui';
@customElement('umb-stylesheet-rule-input')
export class UmbStylesheetRuleInputElement extends UUIFormControlMixin(UmbLitElement, '') {
#sorter = new UmbSorterController<UmbStylesheetRule>(this, {
getUniqueOfElement: (element) => element.id,
getUniqueOfModel: (modelEntry) => modelEntry.name,
identifier: 'Umb.SorterIdentifier.InputStylesheetRule',
itemSelector: 'umb-stylesheet-rule-ref',
containerSelector: 'uui-ref-list',
onChange: ({ model }) => {
this.rules = model;
this.dispatchEvent(new UmbChangeEvent());
},
});
@property({ type: Array, attribute: false })
rules: UmbStylesheetRule[] = [];
@@ -57,6 +68,10 @@ export class UmbStylesheetRuleInputElement extends UUIFormControlMixin(UmbLitEle
this.dispatchEvent(new UmbChangeEvent());
};
firstUpdated() {
this.#sorter.setModel(this.rules);
}
render() {
return html`
<uui-ref-list>
@@ -64,16 +79,20 @@ export class UmbStylesheetRuleInputElement extends UUIFormControlMixin(UmbLitEle
this.rules,
(rule, index) => rule.name + index,
(rule, index) => html`
<umb-stylesheet-rule-ref name=${rule.name} detail=${rule.selector}>
<umb-stylesheet-rule-ref name=${rule.name} id=${rule.name} detail=${rule.selector}>
<uui-action-bar slot="actions">
<uui-button @click=${() => this.#editRule(rule, index)} label="Edit ${rule.name}">Edit</uui-button>
<uui-button @click=${() => this.#removeRule(rule)} label="Remove ${rule.name}">Remove</uui-button>
<uui-button
label=${this.localize.term('general_edit')}
@click=${() => this.#editRule(rule, index)}></uui-button>
<uui-button
label=${this.localize.term('general_remove')}
@click=${() => this.#removeRule(rule)}></uui-button>
</uui-action-bar>
</umb-stylesheet-rule-ref>
`,
)}
</uui-ref-list>
<uui-button label="Add rule" look="placeholder" @click=${this.#appendRule}>Add</uui-button>
<uui-button label=${this.localize.term('general_add')} look="placeholder" @click=${this.#appendRule}></uui-button>
`;
}

View File

@@ -1,13 +1,30 @@
import type { UmbUserItemModel } from '../../repository/index.js';
import { UmbUserPickerContext } from './user-input.context.js';
import { css, html, customElement, property, state, nothing } from '@umbraco-cms/backoffice/external/lit';
import { UUIFormControlMixin } from '@umbraco-cms/backoffice/external/uui';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { css, customElement, html, nothing, property, repeat, state } from '@umbraco-cms/backoffice/external/lit';
import { splitStringToArray } from '@umbraco-cms/backoffice/utils';
import { UmbChangeEvent } from '@umbraco-cms/backoffice/event';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { UmbSorterController } from '@umbraco-cms/backoffice/sorter';
import { UUIFormControlMixin } from '@umbraco-cms/backoffice/external/uui';
// TODO: Shall we rename to 'umb-input-user'? [LK]
@customElement('umb-user-input')
export class UmbUserInputElement extends UUIFormControlMixin(UmbLitElement, '') {
// TODO: [LK] Add sorting!
#sorter = new UmbSorterController<string>(this, {
getUniqueOfElement: (element) => {
return element.id;
},
getUniqueOfModel: (modelEntry) => {
return modelEntry;
},
identifier: 'Umb.SorterIdentifier.InputUser',
itemSelector: 'uui-ref-node-user',
containerSelector: 'uui-ref-list',
onChange: ({ model }) => {
this.selection = model;
this.dispatchEvent(new UmbChangeEvent());
},
});
/**
* This is a minimum amount of selected items in this input.
@@ -55,17 +72,18 @@ export class UmbUserInputElement extends UUIFormControlMixin(UmbLitElement, '')
@property({ type: String, attribute: 'min-message' })
maxMessage = 'This field exceeds the allowed amount of items';
@property({ type: Array })
public set selection(uniques: Array<string>) {
this.#pickerContext.setSelection(uniques);
this.#sorter.setModel(uniques);
}
public get selection(): Array<string> {
return this.#pickerContext.getSelection();
}
public set selection(ids: Array<string>) {
this.#pickerContext.setSelection(ids);
}
@property()
public set value(idsString: string) {
// Its with full purpose we don't call super.value, as thats being handled by the observation of the context selection.
this.selection = splitStringToArray(idsString);
public set value(uniques: string) {
this.selection = splitStringToArray(uniques);
}
public get value(): string {
return this.selection.join(',');
@@ -91,16 +109,8 @@ export class UmbUserInputElement extends UUIFormControlMixin(UmbLitElement, '')
() => !!this.max && this.#pickerContext.getSelection().length > this.max,
);
this.observe(
this.#pickerContext.selection,
(selection) => (this.value = selection.join(',')),
'umbUserInputSelectionObserver',
);
this.observe(
this.#pickerContext.selectedItems,
(selectedItems) => (this._items = selectedItems),
'umbUserInputItemsObserver',
);
this.observe(this.#pickerContext.selection, (selection) => (this.value = selection.join(',')), '_observeSelection');
this.observe(this.#pickerContext.selectedItems, (selectedItems) => (this._items = selectedItems), '_observerItems');
}
protected getFormElement() {
@@ -111,35 +121,49 @@ export class UmbUserInputElement extends UUIFormControlMixin(UmbLitElement, '')
this.#pickerContext.openPicker({});
}
#removeItem(item: UmbUserItemModel) {
this.#pickerContext.requestRemoveItem(item.unique);
}
render() {
return html`${this.#renderItems()} ${this.#renderAddButton()}`;
}
#renderAddButton() {
if (this.max > 0 && this.selection.length >= this.max) return nothing;
return html`
<uui-ref-list> ${this._items?.map((item) => this.#renderItem(item))} </uui-ref-list>
${this.#renderAddButton()}
<uui-button
id="btn-add"
look="placeholder"
@click=${this.#openPicker}
label="${this.localize.term('general_choose')}"></uui-button>
`;
}
#renderItems() {
if (!this._items) return nothing;
return html`
<uui-ref-list>
${repeat(
this._items,
(item) => item.unique,
(item) => this.#renderItem(item),
)}
</uui-ref-list>
`;
}
#renderItem(item: UmbUserItemModel) {
if (!item.unique) return;
return html`
<uui-ref-node-user name=${item.name}>
<uui-ref-node-user name=${item.name} id=${item.unique}>
<uui-action-bar slot="actions">
<uui-button
@click=${() => this.#pickerContext.requestRemoveItem(item.unique)}
label=${this.localize.term('general_remove')}></uui-button>
<uui-button label=${this.localize.term('general_remove')} @click=${() => this.#removeItem(item)}></uui-button>
</uui-action-bar>
</uui-ref-node-user>
`;
}
#renderAddButton() {
if (this.max === 1 && this.selection.length >= this.max) return nothing;
return html`<uui-button
id="btn-add"
look="placeholder"
@click=${this.#openPicker}
label=${this.localize.term('general_add')}></uui-button>`;
}
static styles = [
css`
#btn-add {