dotCMS / core

Headless/Hybrid Content Management System for Enterprises
http://dotcms.com
Other
802 stars 460 forks source link

UVE: Enable Inline editing in text fields for Angular SDK #28973

Open fmontes opened 1 week ago

fmontes commented 1 week ago

Related to

https://github.com/dotCMS/core/issues/28944

Task Description

As an author, I want to enable inline editing in text fields for pages in the Universal Visual Editor, so that users can easily edit text content directly on the page.

#### Acceptance Criteria
- [ ] Create a component `<editable-text>` to add to components
- [ ] Users should be able to click on "texts" in the Universal Visual Editor and edit the content directly on the page with TinyMCE.
- [ ] Changes made in the inline editing mode should be saved and reflected on the page.
- [ ] The inline editing feature should work seamlessly across different browsers and devices.
- [ ] Only loads in `EDIT_MODE`

Proposed Objective

Core Features

Proposed Priority

Priority 3 - Average

External Links... Slack Conversations, Support Tickets, Figma Designs, etc.:

In the traditional approach, developers need to "mark" sections of the contentlet being rendered that can be inline edited.

Example Markup

<h1 
    *ngIf="EDIT_MODE" 
    [attr.data-language]="CONTENT_LANGUAGE"
    [attr.data-mode]="'minimal'"
    [attr.data-inode]="ContentInode"
    [attr.data-field-name]="'title'"
>
    {{ title }}
</h1>

This markup shows a blue border around the text to indicate to the user that this is editable, and when the user clicks, it will start TinyMCE floating on top of the element.

[!WARNING]
If the contentlet lives in more than one page, it will pop up the corresponding dialog.

Developers need to pass four data attributes to their HTML in the container:

With this information, we can trigger a workflow action (REST) to save/update the corresponding contentlet field:

fetch("http://localhost:8080/api/v1/workflow/actions/default/fire/EDIT?inode=a196bf08-a1bd-4c1c-8709-786b6385545d", {
  body: JSON.stringify({
    contentlet: {
      inode: "a196bf08-a1bd-4c1c-8709-786b6385545d",
      title: "Explore the World 123"
    }
  }),
  method: "PUT"
});

This will edit the contentlet and save the new text.

Headless

Since we should not inject anything into our customer's headless implementations, we need to write a component in our SDK that allows developers to "mark" the text they want to be editable.

We need to provide a component. It should work the same way, but we have a new mode: plain, which uses the contenteditable attribute instead of TinyMCE. plain should be the default mode, meaning if no mode is passed, it defaults to plain. So now we have three modes:

Example Usage in Angular Application

import { Component, Input } from '@angular/core';
import { EditableText } from '@dotcms/angular';

@Component({
  selector: 'app-banner',
  templateUrl: './banner.component.html',
  styleUrls: ['./banner.component.css']
})
export class BannerComponent {
  @Input() contentlet: unknown;
}

And the HTML:

<div class="banner">
  <img [src]="contentlet.image" [alt]="contentlet.title">
  <div class="content">
    <h2>
      <editable-text mode="minimal" [inode]="contentlet.inode" field="title" [lang]="contentlet.language">{{ contentlet.title }}</editable-text>
    </h2>
    <p>{{ contentlet.caption }}</p>
    <a [href]="link">{{ contentlet.buttonText }}</a>
  </div>
</div>

EditableText Component

  1. It will show a blue border to indicate that it is editable.
  2. OnClick, it will initialize TinyMCE if the mode is full or minimal, or use the contenteditable attribute for plain.
  3. OnBlur, it will save the content by posting a message with the required information to the UVE.
  4. If the user deletes all text and blurs out, we don't emit anything and just return the old text.
  5. If the user clicks, changes nothing, and blurs out, we do nothing.
  6. Undo/Redo: should work, TinyCME might handle this.
  7. Error handling: if the request to save fails, we need to show a toast with the error and return to the previours text.
  8. ESC key: should cancel the editing and no save changes.

Loading TinyMCE

  1. TinyMCE has an official Angular component we can use.
  2. We only load TinyMCE in EDIT_MODE.
  3. In LIVE_MODE, no trace of TinyMCE should be in the bundle.
  4. You might want to dynamically load this if possible.

Assumptions & Initiation Needs

Quality Assurance Notes & Workarounds

N/A