image crop modal links

This commit is contained in:
Lone Iversen
2024-05-24 14:52:22 +02:00
parent 67b26ae449
commit 2477c87174
3 changed files with 90 additions and 17 deletions

View File

@@ -1,9 +1,9 @@
import { UmbImagingRepository } from '@umbraco-cms/backoffice/imaging';
import { UMB_IMAGE_CROPPER_EDITOR_MODAL, UMB_MEDIA_PICKER_MODAL } from '../../modals/index.js';
import type { UmbCropModel, UmbMediaPickerPropertyValue } from '../../property-editors/index.js';
import { customElement, html, ifDefined, nothing, property, repeat, state } from '@umbraco-cms/backoffice/external/lit';
import { UmbChangeEvent } from '@umbraco-cms/backoffice/event';
import { UmbId } from '@umbraco-cms/backoffice/id';
import { UmbImagingRepository } from '@umbraco-cms/backoffice/imaging';
import { UmbInputMediaElement, UmbMediaItemRepository } from '@umbraco-cms/backoffice/media';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import {
@@ -190,6 +190,7 @@ export class UmbInputRichMediaElement extends UUIFormControlMixin(UmbLitElement,
focalPointEnabled: this.focalPointEnabled,
key,
unique: item.mediaKey,
pickableFilter: this.#pickableFilter,
},
value: {
crops: item.crops ?? [],
@@ -202,8 +203,16 @@ export class UmbInputRichMediaElement extends UUIFormControlMixin(UmbLitElement,
})
.onSubmit((value) => {
this.items = this.items.map((item) => {
if (item.key !== value.key) return item;
const focalPoint = this.focalPointEnabled ? value.focalPoint : null;
return item.key === value.key ? { ...item, ...value, focalPoint } : item;
const crops = value.crops;
const mediaKey = value.unique;
// if the key changes, the card will update
const key = mediaKey === item.mediaKey ? item.key : UmbId.new();
return { ...item, crops, mediaKey, focalPoint, key };
});
this.dispatchEvent(new UmbChangeEvent());
@@ -303,12 +312,8 @@ export class UmbInputRichMediaElement extends UUIFormControlMixin(UmbLitElement,
confirmLabel: this.localize.term('actions_remove'),
});
const index = this.items.findIndex((x) => x.key === item.unique);
if (index == -1) return;
const tmpItems = [...this.items];
tmpItems.splice(index, 1);
this.#items = tmpItems;
this.#items = this.#items.filter((x) => x.key !== item.unique);
this._cards = this._cards.filter((x) => x.unique !== item.unique);
this.dispatchEvent(new UmbChangeEvent());
}

View File

@@ -2,18 +2,25 @@ import { UmbMediaUrlRepository } from '../../repository/index.js';
import type { UmbCropModel } from '../../property-editors/index.js';
import type { UmbInputImageCropperFieldElement } from '../../components/input-image-cropper/image-cropper-field.element.js';
import type { UmbImageCropperPropertyEditorValue } from '../../components/index.js';
import { UMB_MEDIA_PICKER_MODAL } from '../media-picker/media-picker-modal.token.js';
import type {
UmbImageCropperEditorModalData,
UmbImageCropperEditorModalValue,
} from './image-cropper-editor-modal.token.js';
import { css, customElement, html, state } from '@umbraco-cms/backoffice/external/lit';
import { UmbModalBaseElement } from '@umbraco-cms/backoffice/modal';
import {
UMB_MODAL_MANAGER_CONTEXT,
UMB_WORKSPACE_MODAL,
UmbModalBaseElement,
type UmbModalManagerContext,
UmbModalRouteRegistrationController,
} from '@umbraco-cms/backoffice/modal';
/** TODO Make some of the components from property editor image cropper reuseable for this modal... */
@customElement('umb-image-cropper-editor-modal')
export class UmbImageCropperEditorModalElement extends UmbModalBaseElement<
UmbImageCropperEditorModalData,
UmbImageCropperEditorModalData<any>,
UmbImageCropperEditorModalValue
> {
#urlRepository = new UmbMediaUrlRepository(this);
@@ -34,6 +41,30 @@ export class UmbImageCropperEditorModalElement extends UmbModalBaseElement<
@state()
private _crops: Array<UmbCropModel> = [];
@state()
private _editMediaPath = '';
@state()
private _pickableFilter?: (item: any) => boolean;
#modalManager?: UmbModalManagerContext;
constructor() {
super();
this.consumeContext(UMB_MODAL_MANAGER_CONTEXT, (context) => {
this.#modalManager = context;
});
new UmbModalRouteRegistrationController(this, UMB_WORKSPACE_MODAL)
.addAdditionalPath('media')
.onSetup(() => {
return { data: { entityType: 'media', preset: {} } };
})
.observeRouteBuilder((routeBuilder) => {
this._editMediaPath = routeBuilder({});
});
}
connectedCallback(): void {
super.connectedCallback();
@@ -42,6 +73,7 @@ export class UmbImageCropperEditorModalElement extends UmbModalBaseElement<
this._focalPointEnabled = this.data?.focalPointEnabled ?? false;
this._crops = this.data?.cropOptions ?? [];
this._pickableFilter = this.data?.pickableFilter;
this.#getSrc();
}
@@ -60,6 +92,19 @@ export class UmbImageCropperEditorModalElement extends UmbModalBaseElement<
this._imageCropperValue = value;
}
async #openMediaPicker() {
const modal = this.#modalManager?.open(this, UMB_MEDIA_PICKER_MODAL, {
data: { multiple: false, pickableFilter: this._pickableFilter },
value: { selection: [this._unique] },
});
const data = await modal?.onSubmit().catch(() => null);
if (!data) return;
this._unique = data.selection[0];
this.value = { ...this.value, unique: this._unique };
this.#getSrc();
}
#onChange(e: CustomEvent) {
const value = (e.target as UmbInputImageCropperFieldElement).value;
if (!value) return;
@@ -70,7 +115,7 @@ export class UmbImageCropperEditorModalElement extends UmbModalBaseElement<
render() {
return html`
<umb-body-layout headline=${this.localize.term('defaultdialogs_selectMedia')}>
<umb-image-cropper-field @change=${this.#onChange} .value=${this._imageCropperValue}></umb-image-cropper-field>
${this.#renderBody()}
<div slot="actions">
<uui-button label=${this.localize.term('general_close')} @click=${this._rejectModal}></uui-button>
<uui-button
@@ -83,12 +128,34 @@ export class UmbImageCropperEditorModalElement extends UmbModalBaseElement<
`;
}
#renderBody() {
return html`<div id="layout">
<umb-image-cropper-field @change=${this.#onChange} .value=${this._imageCropperValue}></umb-image-cropper-field>
<div id="options">
<uui-menu-item @click=${this.#openMediaPicker} label=${this.localize.term('mediaPicker_changeMedia')}>
<umb-icon slot="icon" name="icon-search"></umb-icon>
</uui-menu-item>
<uui-menu-item
href=${this._editMediaPath + 'edit/' + this._unique}
label=${this.localize.term('mediaPicker_openMedia')}>
<umb-icon slot="icon" name="icon-out"></umb-icon>
</uui-menu-item>
</div>
</div>`;
}
static styles = [
css`
uui-tab {
flex: 1;
min-height: 100px;
min-width: 100px;
#layout {
height: 100%;
display: flex;
flex-direction: column;
justify-content: space-between;
}
#options {
display: flex;
justify-content: center;
}
img {

View File

@@ -2,11 +2,12 @@ import type { UmbImageCropperCrop } from '../../components/index.js';
import type { UmbCropModel } from '../../property-editors/index.js';
import { UmbModalToken } from '@umbraco-cms/backoffice/modal';
export interface UmbImageCropperEditorModalData {
export interface UmbImageCropperEditorModalData<ItemType> {
key: string;
unique: string;
focalPointEnabled: boolean;
cropOptions: Array<UmbCropModel>;
pickableFilter?: (item: ItemType) => boolean;
}
export interface UmbImageCropperEditorModalValue {
@@ -17,7 +18,7 @@ export interface UmbImageCropperEditorModalValue {
}
export const UMB_IMAGE_CROPPER_EDITOR_MODAL = new UmbModalToken<
UmbImageCropperEditorModalData,
UmbImageCropperEditorModalData<any>,
UmbImageCropperEditorModalValue
>('Umb.Modal.ImageCropperEditor', {
modal: {