DEV Community

Mahmoud Ehab
Mahmoud Ehab

Posted on • Updated on

execCommand() Alternative

Abstract

Unfortunately, document.execCommand() function is no longer recommended, as it may be in the process of being dropped. If you are implementing a text editor in your web application, this is probably bad news for you. As this feature (JS feature) is used in making bold and italic texts, and may be in other few things too, like highlighting, redoing, ...etc.

This article gives you another way for implementing this kind of text manipulating — using built-in JS objects. Although, this article handles only bolding texts, the general approach can be used in implementing almost anything.

Introduction: Some Definitions

Straightforwardly, we shall use Selection and Range built-in JS objects instead of the function document.execCommand().

Range Object

This is considered as the primitive object that makes the whole magic. It's exactly what we need to bold a text.

A range is a contiguous part of a document. A range can contain entire nodes as well as portions of nodes (such as a portion of a text node).

Selection Object

As this object deals with the selected text in the screen via the user. Then it's our key to get a range object represents the text (portion of node) that we desire to manipulate.

A Selection object represents the range of text selected by the user or the current position of the caret. To obtain a Selection object for examination or manipulation, call window.getSelection().

boldCommand Function

"Writing a function that makes the selected text bold" is kinda synoptic description or fuzzy, I'd say. Let's reformulate it to: a function that wraps the selected text within a node ("strong" HTML tag, for instance). And that's what we exactly are going to do; we'll insert the <strong> HTML element in the node of the selected text, in a specific range, using the Range JS object.

The logic of our function is simply as follows:

  • Create <strong></strong> HTML element.
  • Initialize a variable to the selection of the user (Selection Object).
  • Initialize a variable to the Range object from the selection in the previous step.
  • insert the created element in the first step using the range object in the previous step.
function boldCommand() {
    const strongElement = document.createElement("strong");
    const userSelection = window.getSelection();
    const selectedTextRange = userSelection.getRangeAt(0);
    selectedTextRange.surroundContents(strongElement);
}
Enter fullscreen mode Exit fullscreen mode

Top comments (4)

Collapse
 
jiminy0410 profile image
jiminy0410

And now how to go back? :-)

Collapse
 
_moehab profile image
Mahmoud Ehab

You can remove/replace the parent (the surrounding)... just like that:

**Function** removeSurroundingFrom(textElement):
           sur <- the parent of the textElement
           newNode <- create textNode with sur inner text
           replace sur with newNode
Enter fullscreen mode Exit fullscreen mode
Collapse
 
jiminy0410 profile image
jiminy0410

But than what happens if you select both the bold text and some new text?

Thread Thread
 
_moehab profile image
Mahmoud Ehab

I'm proposing a technique that could be used in designing the possible solutions: Remove The Surroundings.

Of course, solving such a problem would require much more than that. And I consider a well defined test suite for the required function (solution) is rather the most important aspect for us to concern.

The generic solution, that I've proposed, would definitely cause undesired or unexpected result in response to the action of unsurrounding a text while "selecting both the surrounded and a non-surrounded adjacent text". This reflects the nature of the problem, and that it needs more specific function more than a generic abstract one; we shall add a new parameter to the function that specifies the type of the surrounding that's expected to be found and thereafter to be removed.

Function rmvSurFromElm(string surType, TextElement elm)
          sur <- the parent of the textElement
          if sur.type == subtype then
                  newNode <- create textNode with sur inner text
                  replace sur with newNode
          endif
Enter fullscreen mode Exit fullscreen mode