Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Clipboard #17820

Merged
merged 246 commits into from
Jan 16, 2025
Merged

Feature: Clipboard #17820

merged 246 commits into from
Jan 16, 2025

Conversation

madsrasmussen
Copy link
Contributor

@madsrasmussen madsrasmussen commented Dec 16, 2024

Clipboard

Fixes: #16383
Fixes: #16898

The clipboard is a way to temporarily store property values that can later be pasted into other properties.
The first version of the Clipboard enables copying and pasting values between different block editors.

General Implementation

The clipboard is implemented like any other entity in the system with its own "clipboardEntry" entity type. The implementation includes repositories for data consumption (item, detail, collection) and a picker that makes it possible to interact with the clipboard in the same way as any other entity in the system. The main difference for the clipboard data is that it is stored in local storage instead of a server database. Doing it this way makes it possible for us to do a proper clipboard management UI following the same conventions as the rest of the codebase later.

The feature has a few "moving parts," including new extension points to aim for a flexible solution.

Copy/Pasting

The backbone of the feature is the Property Value copy and paste translators. These allow any property value to be translated into a more generic clipboard entry model when inserted into the clipboard and again translated from a generic clipboard entry model to any property value retrieved from the clipboard.

This PR introduces the first two clipboard entry value types:

  • block: The simplest clipboard representation of a block model
  • gridBlock: Representation of a block including grid information like nested blocks, column span, etc.

When adding RTE support, we will also see a rteBlock/htmlBlock that includes the markup.

A Clipboard Entry will have a data model that looks like this. The example shows a value copied from a Block Grid:

{
  unique: '1234',
  entityType: 'clipboardEntry',
  createDate: 'someDate',
  updateDate: 'someDate',
  ... // left out properties
  values: [
    {
      type: 'block',
      value: // Value here
    },
    {
      type: 'gridBlock',
      value: // Value here
    }
    // Any other value that is registed as a copy translator for the Block Grid
 ]
}

Any Property Editor with a paste translator that can translate either a block or gridBlock value will be able to paste this entry.

Enabling the feature for a Property Editor

Depending on what kind of support you are looking for in a Property Editor there are different needs for manifests.

Clipboard Property Context

To enable an API with helpers to copy/paste property values including value translation register a Clipboard Property Action extension:

Property Context Manifest

{
  type: 'propertyContext',
  kind: 'clipboard',
  alias: 'My.PropertyContext.MyPropertyEditor.Clipboard',
  name: 'My Property Editor Clipboard Property Context',
  forPropertyEditorUis: ['My.PropertyEditorUi']
 }

The context will be available on any property with the given Property Editor UIs.

Property Actions:

The quickest way to implement the clipboard copy/paste actions is through property actions. The actions will copy the entire Property Value to the clipboard and replace the value when pasting. Sometimes this is not the UX you are looking for, and you might need to implement a custom button in your Property Editor UI. The Property Actions are using the above Clipboard Property Context, so any custom button implementation will be able to do the same without the need for a lot of clipboard logic.

Copy Property Action Manifest:

 {
  type: 'propertyAction',
   kind: 'copyToClipboard',
  alias: 'My.PropertyAction.MyPropertyEditor.Clipboard.Copy',
  name: 'My Property Editor Copy To Clipboard Property Action',
  forPropertyEditorUis: ['My.PropertyEditorUi'],
  conditions: [
    {
      alias: UMB_WRITABLE_PROPERTY_CONDITION_ALIAS,
    },
    {
      alias: UMB_PROPERTY_HAS_VALUE_CONDITION_ALIAS,
    },
  ],
}

Paste Property Action Manifest:

 {
  type: 'propertyAction',
  kind: 'pasteFromClipboard',
  alias: 'My.PropertyAction.MyPropertyEditor.Clipboard.Paste',
  name: 'My Property Editor Paste From Clipboard Property Action',
  forPropertyEditorUis: ['My.PropertyEditorUi'],
  conditions: [
    {
      alias: UMB_WRITABLE_PROPERTY_CONDITION_ALIAS,
    },
  ],
}

With these enabled for a Property Editor UI the copy and paste Property Actions are available in the UI.

Copy/Paste Translators

Copy

To insert a value into the clipboard, you need a Property Value Copy translator. This ensures that your Property Value gets translated into a Clipboard Entry Value type. You can either copy as one of the already supported types, which will enable existing paste functionality to support pasting from your property editor, or create your own type:

Here is an example of a property editor copying to the block entry value type:

Manifest

{
  type: 'clipboardCopyPropertyValueTranslator',
  alias: 'My.ClipboardCopyPropertyValueTranslator.MyEditorToBlock',
  name: 'My Editor To Block Clipboard Copy Property Value Translator',
  api: () => import('./my-editor-to-block-copy-translator.js'),
  fromPropertyEditorUi: 'My.PropertyEditorUi',
  toClipboardEntryValueType: UMB_BLOCK_CLIPBOARD_ENTRY_VALUE_TYPE,
},

Implementation

import type { UmbBlockClipboardEntryValueModel } from '@umbraco-cms/backoffice/block';
import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
import type { UmbClipboardCopyPropertyValueTranslator } from '@umbraco-cms/backoffice/clipboard';

export class UmbMyEditorToBlockClipboardCopyPropertyValueTranslator 
  extends UmbControllerBase 
  implements UmbClipboardCopyPropertyValueTranslator<MyPropertyValueModel, UmbBlockClipboardEntryValueModel>
{
  async translate(propertyValue: MyPropertyValueModel) {
    // implementation here
  }
}

export { UmbMyEditorToBlockClipboardCopyPropertyValueTranslator as api };

Paste

To paste a value from the clipboard, you need a Property Value Paste translator. This ensures that the clipboard entry value gets translated into your property value format.

Manifest

{
  type: 'clipboardPastePropertyValueTranslator',
  alias: 'My.ClipboardPastePropertyValueTranslator.BlockToMyEditor,
  name: 'Block To My Editor Clipboard Paste Property Value Translator',
  api: () => import('./block-to-my-editor-paste-translator.js'),
  fromClipboardEntryValueType: UMB_BLOCK_CLIPBOARD_ENTRY_VALUE_TYPE,
  toPropertyEditorUi: 'My.PropertyEditorUi'
},

implementation

import type { UmbBlockClipboardEntryValueModel } from '@umbraco-cms/backoffice/block';
import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
import type { UmbClipboardPastePropertyValueTranslator } from '@umbraco-cms/backoffice/clipboard';

export class UmbBlockToMyEditorClipboardPastePropertyValueTranslator
	extends UmbControllerBase
	implements UmbClipboardPastePropertyValueTranslator<UmbBlockClipboardEntryValueModel, MyPropertyValueModel>
{
    async translate(value: UmbBlockClipboardEntryValueModel) {
      // implementation here
    }
}

export { UmbBlockToMyEditorClipboardPastePropertyValueTranslator as api };

Complex Property Values:

For complex nested property values, we have also introduced a property value resolver concept to traverse the property value and a property value cloner concept to clone and update any parts of the value along the way - like uniques. If any of these are registered they will be included when pasting a value.

More in-depth descriptions will be added to the documentation.

@madsrasmussen madsrasmussen marked this pull request as ready for review January 14, 2025 08:51
# Conflicts:
#	src/Umbraco.Web.UI.Client/src/packages/block/block/context/block-entries.context.ts
@nielslyngsoe nielslyngsoe merged commit e00290f into v15/dev Jan 16, 2025
28 of 29 checks passed
@nielslyngsoe nielslyngsoe deleted the v15/feature/clipboard branch January 16, 2025 14:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants