Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ This extension provides visual editing features for content elements in TYPO3 CM
- 🔦 **Finding editable areas:** use Spotlight to highlight editable text, rich text, images, and content elements.
- 👻 **Showing empty fields:** use "show empty" when editable but currently empty fields are hard to see.
- ↔️ **Moving content:** drag content elements by their handle. Hold Ctrl while dropping to copy instead of moving.
- ✍️ **Editing special text characters:** type `­` for a soft hyphen and ` ` for a non-breaking space. Entity-like text that starts with `&`, such as ` `, is shown with `&` while editing so it stays literal text.

## Template Integration

Expand Down Expand Up @@ -77,6 +78,16 @@ If you do not have a Record object yet, you can create one with the `record-tran
lib.contentElement.dataProcessing.1768551979 = record-transformation
````

#### Editable text entities
For plain editable text fields, Visual Editor makes some otherwise hard-to-see characters explicit while the field is focused.
Soft hyphens are shown as `­`, and non-breaking spaces are shown as ` `.
Plain ampersands stay visible as `&`, but ampersands that start an entity-like sequence, such as ` `, ` `, or ` `, are shown as `&` while editing so the sequence stays literal text.
When the editor changes or leaves the field, these values are converted back before validation and storage.

````html
<h1>{record -> f:render.text(field: 'header')}</h1>
````

#### Fluid components
When you use Fluid components, render the editable text outside the component and pass the rendered value into the component.
This keeps the component decoupled from records and TCA fields, and lets callers pass either a plain string or the result of `f:render.text`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,28 @@ export class VeEditableText extends LitElement {
return this.shadowRoot?.querySelector('.slot');
}

/**
* @param {string} value
* @return {string}
*/
#storedTextToEditableText(value) {
return value
.replace(/&(?=#\d+;|#x[0-9a-fA-F]+;|[a-zA-Z][a-zA-Z0-9]+;)/g, '&amp;')
.replace(/\u00ad/g, '&shy;')
.replace(/\u00a0/g, '&nbsp;');
}

/**
* @param {string} value
* @return {string}
*/
#editableTextToStoredText(value) {
return value
.replace(/&shy;/gi, '\u00ad')
.replace(/&nbsp;/gi, '\u00a0')
.replace(/&amp;/gi, '&');
}

/**
* @param {HTMLElement} element
* @param {InputEvent} event
Expand Down Expand Up @@ -422,21 +444,22 @@ export class VeEditableText extends LitElement {
if (insertedText !== edit.insertedText) {
event.preventDefault();
insertTextAtSelection(element, insertedText);
this.#validateAndStore(this.#getSlotText());
this.#validateAndStore(this.#editableTextToStoredText(this.#getSlotText()));
}
}

#handleInput() {
this.#validateAndStore(this.#getSlotText());
this.#validateAndStore(this.#editableTextToStoredText(this.#getSlotText()));
}

#handleFocus() {
this.focused = true;
this.#setSlotText(this.#storedTextToEditableText(this.value));
}

#handleBlur() {
this.focused = false;
this.#setSlotText(this.#validateAndStore(this.#getSlotText()));
this.#setSlotText(this.#validateAndStore(this.#editableTextToStoredText(this.#getSlotText())));
}

/**
Expand Down