Sacha
Sacha

Reputation: 861

Insert 4 spaces instead of tab

I have a contenteditable div with divs inside them like this:

<div id="wrapper" contenteditable=true onkeydown="preventTab(event);">
  <div id="line1" class="line"></div>
  <div id="line2" class="line"></div>
  <div id="line3" class="line"></div>
  <div id="line4" class="line"></div>
</div>

With CSS, using ::before for line numbers , this looks like this:

example

Now, I want, whenever someone presses tab, it automatically inserts four spaces instead of a tab. I got this function, but it doesn't do anything after it has fired the events.

function preventTab(event) {

    event = event || window.event;

    if (event.keyCode === 9) {

        // for loop, so the user can set the amount of spaces they want.
        for (let i = 0; i < tabSize; i++) {
            let e = new KeyboardEvent("keydown", {
                bubbles: true,
                code: "Space",
                key: " ",
                keyCode: 32
            });

            event.target.dispatchEvent(e);
        }

        event.preventDefault();
    }
}

As I said, nothing really happens (maybe because isTrusted: false?), also no errors are thrown.
By the way, I have noticed this question with the same title, but that heavily depends on the jQuery library and I'm looking for a pure JavaScript approach.

Upvotes: 2

Views: 1225

Answers (2)

Besworks
Besworks

Reputation: 4483

Simulating clicks and keystrokes is considered a security risk. According to the W3C UI Events Working Draft:

"Most untrusted events will not trigger their default actions..."

Instead you can manipulate the contents of the contenteditable=true element using selections and ranges like I have demonstrated in this snippet.

let tabSize = 2;
let spaces = '';
for (i = 0; i < tabSize; i++) {
  spaces += ' ';
}

document.getElementById('editor').addEventListener('keydown', preventTab);

function preventTab(event) {
  if (event.keyCode === 9) {
    event.preventDefault();
    let selection = window.getSelection();
    selection.collapseToStart();
    let range = selection.getRangeAt(0);
    range.insertNode(document.createTextNode(spaces));
    selection.collapseToEnd();
  }
}
html,
body {
  height: 100%;
  width: 100%;
  margin: 0;
}

#editor {
  width: 100%;
  height: 100%;
  font-family: monospace;
  white-space: pre;
}
<div id="editor" contenteditable=true></div>

Upvotes: 1

andriusain
andriusain

Reputation: 1207

Have you tried inserting one &nbsp; per space instead of multiple empty characters? In HTML multiple empty spaces together will not render unless you use &nbsp;.

Upvotes: 0

Related Questions