I have a contenteditable div, and I want to split a node around a selection. Using execCommand(), I can toggle "bold" on or off for a selection, so if I have:
<b>ABCDEFGHI</b>
and select DEF, toggling "bold" gives me
<b>ABC</b>DEF<b>GHI</b>
where the <b> node has been split into two <b> nodes with a text node in between.
I want to be able to do the same with other elements not supported by execCommand(), for example <bdi>. In other words, if I start with
<bdi>ABCDEFGHI</bdi>
and select DEF, I want to end up with
<bdi>ABC</bdi>DEF<bdi>GHI</bdi>
I can test if the selection is contained in a surrounding <bdi> tag using range.commonAncestorContainer() and if not wrap the range in a <bdi> tag. However, what I want is the opposite: if there is an enclosing <bdi> node, I want to split it into (a) a well-formed <bdi> node before the selection, (b) a well-formed selection with no enclosing <bdi>, and (c) another well-formed <bdi> node after the selection, and then reassemble them. How can I do this?
EDIT: it seems that everyone believes I am trying to wrap a selection, but I'm not. Sergey's response below shows how to wrap some plain text, but I want something else.
Trying for a minimal reproducible example, consider the following:
<html>
<head></head>
<body>
<b>This text is <i>marked as
bold
with</i> some italic text too.</b>
</body>
</html>
Now what I want is to UNMARK the text "bold" so that the final result is:
<html>
<head></head>
<body>
<b>This text is <i>marked as</i></b>
<i>bold</i>
<b><i>with</i> some italic text too.</b>
</body>
</html>
Note that the text includes <i>...</i>, which must also be split. This is trivially easy with execCommand(), but I can't figure out how to do it without execCommand() (and hence do it for tags like <bdi> as well). I'm looking for a vanilla JS solutsion, not jQuery or Rangy please.
DEF? Could you do it yourself, or do you need a more complicated code sample? This is not hard to do, but it takes more time. Don't you think my demo is all you need to complete it?Added.