2
votes

I'm trying to implement the basic Rich Text Editing functionalities of ContentEditable in Meteor and I'm having an issue with execCommand. The undo and redo commands work fine but every other command such as bold and italic do not work and give out no errors. The code also worked fine as a regular page (I've done the obvious adaptations for Meteor such as templates and the events).

My html:

<body>
    {{> buttons}}
  <div id="editor" class="textZone" contenteditable="true"></div>
</body>

<template name="buttons">

    <div id="rtfOptions">
        <div class="separate">
            <div class="rtfOption" id="undo">undo</div>
            <div class="rtfOption" id="redo">redo</div>
        </div>

        <div class="separate">
            <div class="rtfOption" id="bold">bold</div>
            <div class="rtfOption" id="italic">italic</div>
        </div>
    </div>
</template>

My events (only 2 non-working + the undo as it works. As for the rest its pretty much the same):

if (Meteor.isClient) {
        Template.buttons.events({
                "click #bold": function() { // Toggles bold on/off for the selection or at the insertion point
                    document.execCommand("bold", false, "null");
                },
                "click #italic": function() { // Toggles italics on/off for the selection or at the insertion point
                    document.execCommand("italic", false, "null");
                },
                "click #undo": function() { // Undoes the last executed command.
                    document.execCommand('undo', false, "null");
                }
    )};
}

Someone know the issue? Does it have something to do with document or the scope?

1
"null" is wrong. It should be just null without the quotation marks. However, I'm not sure that would make any difference. Is your editor using an iframe for the editor content? - Tim Down
No, that doesn't make any difference. I had it just as null before and I simply was testing if that was it because of my linter. I am not using an iframe and I specifically don't want to. - mesosteros
OK. There's no obvious reason why it wouldn't work then. - Tim Down
There is no more code other than the other ExecCommands that are the same as the three above but for other options. The only thing i left out (I think) is that this is running in a if(Meteor.isClient) block. - mesosteros

1 Answers

2
votes

If you change the div tags to button instead (for the clickable elements), or make the div text unselectable (e.g disabling user-select with css) it should work as you expect.

The reason is that when you click on the div with text inside, the execCommand targets the div's text (which is not contenteditable) so the command fails silently. Try adding contenteditable="true" to the div and you'll see that it will bold the div's text if you click on it. Alternatively, try adding the css rule -webkit-user-select: none; (on Chrome, vendor prefixes differ on other browsers) to disable text selection on the div, and you'll see that the execCommand works just fine.

See a working demo here.

Code examples, for clarity:

Option 1

<template name="buttons">
  <div id="rtfOptions">
    <div class="separate">
      <div class="rtfOption" id="bold" style="user-select: none; -webkit-user-select: none; -webkit-touch-callout: none;">bold</div>
    </div>
  </div>
</template>

Option 2

<template name="buttons">
  <div id="rtfOptions">
    <div class="separate">
      <button class="rtfOption" id="bold">bold</button>
    </div>
  </div>
</template>