jodit / jodit/jodit-angular

Backspace not working in Safari

Open
#132 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
48
Forks
35
PR merge metrics
No merged PRs in 30d

Description

We are using jodit with encapsulation: ViewEncapsulation.ShadowDom. In Safari shadowRoot.getSelection() does not work, which results in various problems. One of them is backspace key not working in the editor.

Component throws the following error: HierarchyRequestError: The operation would yield an incorrect node tree.

We were able to override the backspace key logic with the following code:

  handleKeyDown(event) {
    // getSelection does not pierce shadowDom in Safari
    // backspace clicks must be handled by the code below in Safari
    if (!('getSelection' in this.shadowRoot) && event.args[0].keyCode === 8) {
      const selection = window.getSelection() as any;
      if (selection) {
        const range = selection.getComposedRanges(this.elementRef.nativeElement.shadowRoot)[0];
        this.isPreviewModeActive = true;
        if (range.collapsed) {
          this.handleNoTextSelected(range);
        } else {
          this.handleTextSelected(range);
        }
      }
    }
    this.updateCaretWithDebounce$.next();
  }

  private handleNoTextSelected(range: StaticRange): void {
    const { startOffset } = range;
    const value = range.startContainer.nodeValue;
    range.startContainer.nodeValue = value.slice(0, startOffset - 1) + value.slice(startOffset);
  }

  private handleTextSelected(range: StaticRange): void {
    const { startOffset, endOffset } = range;
    const sValue = range.startContainer.nodeValue;
    const eValue = range.endContainer.nodeValue;

    // text from one node is selected
    if (range.startContainer === range.endContainer) {
      range.startContainer.nodeValue = sValue.slice(0, startOffset) + sValue.slice(endOffset);
    }
    // text from multiple nodes is selected
    else {
      this.removeNodesBetweenStartAndEnd(range);
      range.startContainer.nodeValue = sValue.slice(0, startOffset);
      range.endContainer.nodeValue = eValue.slice(endOffset);
    }
  }

  private removeNodesBetweenStartAndEnd(range: StaticRange): void {
    while (this.nextNodeIsNotEndNode(range)) {
      range.startContainer.nextSibling
        ? range.startContainer.nextSibling.remove()
        : range.startContainer.parentElement.nextSibling.remove();
    }
  }

  private nextNodeIsNotEndNode(range: StaticRange): boolean {
    return (
      range.startContainer.nextSibling !== range.endContainer &&
      range.startContainer.nextSibling !== range.endContainer.parentElement &&
      range.startContainer.parentElement.nextSibling !== range.endContainer &&
      range.startContainer.parentElement.nextSibling !== range.endContainer.parentElement
    );
  }

But even though backspace deletes content, the editor loses focus right after backspace is clicked.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reproducing issue #132 in the jodit-angular wrapper with Angular ViewEncapsulation.ShadowDom in Safari. Inspect the editor's backspace and selection handling around shadowRoot.getSelection(), using the reported HierarchyRequestError and focus loss as symptoms. Done means backspace works and the editor retains focus without breaking selection behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
angular, typescript
Domain
frontend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.