Block editors: resolves clipboard UFM label (#20102)
* Block item copy rendered UFM label to clipboard * Fixes clipboard entry's icon * Clipboard entry: sets title and fallback on the unique (instead of empty string) * Clipboard entry: CSS for flat menu structure * Clipboard entry: replace condition with `when` + imports tidy-up * Imports tidy-up * Fixed UFM Virtual Render's nested text retrieval Previously, it'd placed nested text after the parent's text, now it remains nested. * Update src/Umbraco.Web.UI.Client/src/packages/ufm/controllers/ufm-virtual-render.controller.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -6,10 +6,8 @@ import {
|
||||
} from '../../constants.js';
|
||||
import { UMB_BLOCK_GRID_MANAGER_CONTEXT } from '../../block-grid-manager/block-grid-manager.context-token.js';
|
||||
import { UMB_BLOCK_GRID_ENTRIES_CONTEXT } from '../block-grid-entries/block-grid-entries.context-token.js';
|
||||
import {
|
||||
type UmbBlockGridScalableContext,
|
||||
UmbBlockGridScaleManager,
|
||||
} from '../../context/block-grid-scale-manager/block-grid-scale-manager.controller.js';
|
||||
import { UmbBlockGridScaleManager } from '../../context/block-grid-scale-manager/block-grid-scale-manager.controller.js';
|
||||
import type { UmbBlockGridScalableContext } from '../../context/block-grid-scale-manager/block-grid-scale-manager.controller.js';
|
||||
import {
|
||||
UmbArrayState,
|
||||
UmbBooleanState,
|
||||
@@ -18,10 +16,10 @@ import {
|
||||
mergeObservables,
|
||||
observeMultiple,
|
||||
} from '@umbraco-cms/backoffice/observable-api';
|
||||
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
|
||||
import { UmbBlockEntryContext } from '@umbraco-cms/backoffice/block';
|
||||
import { UMB_PROPERTY_CONTEXT, UMB_PROPERTY_DATASET_CONTEXT } from '@umbraco-cms/backoffice/property';
|
||||
import { UMB_CLIPBOARD_PROPERTY_CONTEXT } from '@umbraco-cms/backoffice/clipboard';
|
||||
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
|
||||
|
||||
export class UmbBlockGridEntryContext
|
||||
extends UmbBlockEntryContext<
|
||||
@@ -301,7 +299,7 @@ export class UmbBlockGridEntryContext
|
||||
|
||||
const workspaceName = propertyDatasetContext?.getName();
|
||||
const propertyLabel = propertyContext?.getLabel();
|
||||
const blockLabel = this.getLabel();
|
||||
const blockLabel = this.getName();
|
||||
|
||||
const entryName = workspaceName
|
||||
? `${workspaceName} - ${propertyLabel} - ${blockLabel}`
|
||||
|
||||
@@ -5,24 +5,25 @@ import {
|
||||
UMB_BLOCK_LIST_PROPERTY_EDITOR_SCHEMA_ALIAS,
|
||||
UMB_BLOCK_LIST_PROPERTY_EDITOR_UI_ALIAS,
|
||||
} from '../../constants.js';
|
||||
import { css, customElement, html, nothing, property, state } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbLitElement, umbDestroyOnDisconnect } from '@umbraco-cms/backoffice/lit-element';
|
||||
import { html, css, customElement, property, state, nothing } from '@umbraco-cms/backoffice/external/lit';
|
||||
import type { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/property-editor';
|
||||
import { stringOrStringArrayContains } from '@umbraco-cms/backoffice/utils';
|
||||
import { UmbObserveValidationStateController } from '@umbraco-cms/backoffice/validation';
|
||||
import { UmbDataPathBlockElementDataQuery } from '@umbraco-cms/backoffice/block';
|
||||
import { UmbObserveValidationStateController } from '@umbraco-cms/backoffice/validation';
|
||||
import { UUIBlinkAnimationValue, UUIBlinkKeyframes } from '@umbraco-cms/backoffice/external/uui';
|
||||
import { UMB_PROPERTY_CONTEXT, UMB_PROPERTY_DATASET_CONTEXT } from '@umbraco-cms/backoffice/property';
|
||||
import { UMB_CLIPBOARD_PROPERTY_CONTEXT } from '@umbraco-cms/backoffice/clipboard';
|
||||
import type {
|
||||
ManifestBlockEditorCustomView,
|
||||
UmbBlockEditorCustomViewProperties,
|
||||
} from '@umbraco-cms/backoffice/block-custom-view';
|
||||
import type { UmbExtensionElementInitializer } from '@umbraco-cms/backoffice/extension-api';
|
||||
import { UUIBlinkAnimationValue, UUIBlinkKeyframes } from '@umbraco-cms/backoffice/external/uui';
|
||||
import { UMB_PROPERTY_CONTEXT, UMB_PROPERTY_DATASET_CONTEXT } from '@umbraco-cms/backoffice/property';
|
||||
import { UMB_CLIPBOARD_PROPERTY_CONTEXT } from '@umbraco-cms/backoffice/clipboard';
|
||||
import type { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/property-editor';
|
||||
|
||||
import '../ref-list-block/index.js';
|
||||
import '../inline-list-block/index.js';
|
||||
import '../unsupported-list-block/index.js';
|
||||
|
||||
/**
|
||||
* @element umb-block-list-entry
|
||||
*/
|
||||
@@ -309,7 +310,7 @@ export class UmbBlockListEntryElement extends UmbLitElement implements UmbProper
|
||||
|
||||
const workspaceName = propertyDatasetContext?.getName();
|
||||
const propertyLabel = propertyContext?.getLabel();
|
||||
const blockLabel = this._label;
|
||||
const blockLabel = this.#context.getName();
|
||||
|
||||
const entryName = workspaceName
|
||||
? `${workspaceName} - ${propertyLabel} - ${blockLabel}`
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
import { UmbClipboardCollectionRepository } from '../../collection/index.js';
|
||||
import type { UmbClipboardEntryDetailModel } from '../types.js';
|
||||
import { html, customElement, state, repeat, property } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbSelectionManager } from '@umbraco-cms/backoffice/utils';
|
||||
import { UmbEntityContext, type UmbEntityUnique } from '@umbraco-cms/backoffice/entity';
|
||||
import { UMB_ACTION_EVENT_CONTEXT } from '@umbraco-cms/backoffice/action';
|
||||
import { css, customElement, html, property, repeat, state, when } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbEntityContext } from '@umbraco-cms/backoffice/entity';
|
||||
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
|
||||
import {
|
||||
UmbRequestReloadChildrenOfEntityEvent,
|
||||
UmbRequestReloadStructureForEntityEvent,
|
||||
} from '@umbraco-cms/backoffice/entity-action';
|
||||
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
|
||||
import { UmbSelectionManager } from '@umbraco-cms/backoffice/utils';
|
||||
import { UMB_ACTION_EVENT_CONTEXT } from '@umbraco-cms/backoffice/action';
|
||||
import type { UmbEntityUnique } from '@umbraco-cms/backoffice/entity';
|
||||
|
||||
// TODO: make this into an extension point (Picker) with two kinds of pickers: tree-item-picker and collection-item-picker;
|
||||
@customElement('umb-clipboard-entry-picker')
|
||||
@@ -117,19 +118,24 @@ export class UmbClipboardEntryPickerElement extends UmbLitElement {
|
||||
};
|
||||
|
||||
override render() {
|
||||
return html`${this._items.length > 0
|
||||
? repeat(
|
||||
return when(
|
||||
this._items.length > 0,
|
||||
() =>
|
||||
repeat(
|
||||
this._items,
|
||||
(item) => item.unique,
|
||||
(item) => this.#renderItem(item),
|
||||
)
|
||||
: html`There are no items in the clipboard`}`;
|
||||
),
|
||||
() => html`<p>There are no items in the clipboard.</p>`,
|
||||
);
|
||||
}
|
||||
|
||||
#renderItem(item: UmbClipboardEntryDetailModel) {
|
||||
const label = item.name ?? item.unique;
|
||||
return html`
|
||||
<uui-menu-item
|
||||
label=${item.name ?? ''}
|
||||
label=${label}
|
||||
title=${label}
|
||||
selectable
|
||||
@selected=${() => this.#selectionManager.select(item.unique)}
|
||||
@deselected=${() => this.#selectionManager.deselect(item.unique)}
|
||||
@@ -141,7 +147,7 @@ export class UmbClipboardEntryPickerElement extends UmbLitElement {
|
||||
|
||||
#renderItemIcon(item: UmbClipboardEntryDetailModel) {
|
||||
const iconName = item.icon ?? 'icon-clipboard-entry';
|
||||
return html`<uui-icon slot="icon" name=${iconName}></uui-icon>`;
|
||||
return html`<umb-icon slot="icon" name=${iconName}></umb-icon>`;
|
||||
}
|
||||
|
||||
#renderItemActions(item: UmbClipboardEntryDetailModel) {
|
||||
@@ -168,6 +174,14 @@ export class UmbClipboardEntryPickerElement extends UmbLitElement {
|
||||
|
||||
super.destroy();
|
||||
}
|
||||
|
||||
static override styles = [
|
||||
css`
|
||||
:host {
|
||||
--uui-menu-item-flat-structure: 1;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
||||
declare global {
|
||||
|
||||
@@ -12,21 +12,26 @@ export class UmbUfmVirtualRenderController extends UmbControllerBase {
|
||||
|
||||
const items: Array<string> = [];
|
||||
|
||||
items.push(element.shadowRoot?.textContent ?? element.textContent ?? '');
|
||||
|
||||
if (element.shadowRoot !== null) {
|
||||
Array.from(element.shadowRoot.children).forEach((element) => {
|
||||
items.push(this.#getTextFromDescendants(element));
|
||||
});
|
||||
// Try get the text content from the shadow root first, otherwise get it from the light DOM. [LK]
|
||||
if (element.shadowRoot) {
|
||||
for (const node of element.shadowRoot.childNodes) {
|
||||
if (node.nodeType === Node.ELEMENT_NODE) {
|
||||
items.push(this.#getTextFromDescendants(node as Element));
|
||||
} else if (node.nodeType === Node.TEXT_NODE) {
|
||||
items.push(node.textContent ?? '');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (const node of element.childNodes) {
|
||||
if (node.nodeType === Node.ELEMENT_NODE) {
|
||||
items.push(this.#getTextFromDescendants(node as Element));
|
||||
} else if (node.nodeType === Node.TEXT_NODE) {
|
||||
items.push(node.textContent ?? '');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (element.children !== null) {
|
||||
Array.from(element.children).forEach((element) => {
|
||||
items.push(this.#getTextFromDescendants(element));
|
||||
});
|
||||
}
|
||||
|
||||
return items.filter((x) => x).join(' ');
|
||||
return items.filter((x) => x).join('');
|
||||
}
|
||||
|
||||
set markdown(markdown: string | undefined) {
|
||||
|
||||
Reference in New Issue
Block a user