Home > Mobile >  Which event should be cancelled to stop a contenteditable keyboard shortcut?
Which event should be cancelled to stop a contenteditable keyboard shortcut?

Time:03-20

I am trying to build around contenteditable by first disabling it's text styling behavior from keyboard shortcuts, such as ctrl b or ctrl i.

I am using event.preventDefault() when these shortcuts are detected on keyup and keydown events -- however sometimes rarely, I am noticing that contenteditable still ignores event.preventDefault() and the keyboard shortcut is respected.

Is there any way I can fully disable these keyboard shortcuts other than cancelling keyup and keydown?


My shortcut detector was faulty and it was letting the event go through at certain cases. It seems cancelling the event on keydown does actually cancel the shortcut as well.

I have created a jsfiddle for anyone who wants to try it: https://jsfiddle.net/mohj19bs/28/

I will be closing this thread tomorrow, just in case someone else might share something interesting since contenteditable never ceased to surprise me.

CodePudding user response:

Not sure what problem you're dealing with, but this works well...

document.getElementById("test").addEventListener("keydown", e => {
  if(!e.ctrlKey) return;
  if(e.keyCode === 66 || e.keyCode === 73) {
    e.preventDefault();
  }
});
<div id="test" contenteditable>This div is editable</div>

And a one-liner for your enjoyment:

document.getElementById("test").onkeydown = e => !(e.ctrlKey && (e.keyCode === 66 || e.keyCode === 73));
<div id="test" contenteditable>This div is editable</div>

CodePudding user response:

Here is another strategy that may work for you. Instead of trying to prevent b and i elements from being inserted, just remove them right away on keyup or on paste.

Handled cases are:

  • [CTRL] [b] and [CTRL] [i]
  • pasted HTML which contains inline style attribute

And it works recursively to take care of nested elements.

let forbiddenTags = ["B", "I", "STRONG"]
let clean = function(e){

  // Loop through all child nodes
  e.target.childNodes.forEach(function(item){
  
    // recursion if there are childnodes
    if(item.childNodes){
      clean({target:item})
    }
    
    // Remove forbidden tags
    if(item.tagName && forbiddenTags.indexOf(item.tagName) > -1){
      item.insertAdjacentHTML("afterEnd", item.innerHTML)
      item.remove()
      return
    }
    
    // Reset inline style
    if(item.style){
      item.style.fontWeight = "normal"
      item.style.fontStyle = "normal"
    }
  })
}

document.querySelector("#test").addEventListener("keyup", clean)
document.querySelector("#test").addEventListener("paste", clean)
div{
  border: 1px solid grey;
  padding: 0.5em;
}
table{
  border-collapse: collapse;
}
td{
  border: 1px solid grey;
}
<div id="test" contentEditable=true>Enter text here</div>
<br>
Paste me in!:
<div id="pasteit">
  <b>bold</b> <i>italic</i> <strong>strong</strong> <span style="font-weight:bold;">inline</span>
  <table>
    <tr>
      <td style="font-style:italic;">Italic</td>
      <td style="font-weight:bold;">Bold</td>
    </tr>
  </table>
</div>

  • Related