I'm coding the MELT monitor (free software, alpha stage, related to the GCC MELT domain specific language to customize GCC). It is using libonion to behave as a specialized web server, and I want it to become a syntax directed editor of some DSL I am designing. I'm speaking of commit 97d60053 if that matters. You could run it as ./monimelt -Dweb,run -W localhost.localdomain:8086
then open http://localhost.localdomain:8086/microedit.html in your browser.
I am emitting (thru file webroot/microedit.html
)
<h1>Micro Editing Monimelt</h1>
<div id='microedit_id' contenteditable='true'>*</div>
<hr/>
then some AJAX trickery is filling that #micredit_id
element with something containing stuff similar to:
<dd class='statval_cl' data-forattr='notice'> ▵
<span class='momnode_cl'>*<span class='momconn_cl'>
<span class='momitemref_cl'>comment</span></span>
(“<span class='momstring_cl'>some simple notice</span>”
<span class='momnode_cl'>*<span class='momconn_cl'>
<span class='momitemref_cl'>web_state</span></span>
(<span class='momnumber_cl'>2</span>)</span>
<span class='momitemval_cl'>hashset</span>
<span class='momset_cl'>{<span class='momitemref_cl'>microedit</span>
<span class='momitemref_cl'>the_agenda</span>}</span>
<span class='momtuple_cl'>[<span class='momitemref_cl'>web_session</span>
<span class='momitemref_cl empty_cl'>~</span>
<span class='momitemref_cl'>the_system</span>]</span>)</span> ;</dd>
Now, I want every <span>
of class momitemref_cl
to be sensitive to some keyboard (and perhaps mouse) events. However, the contenteditable
elements can be edited by many user actions (I don't even understand what is the entire list of such user actions....) and I only want these span elements to be responsive to a defined and restricted set of key presses (alphanumerical & space) and not be able to be user-changed otherwise (e.g. no punctuation characters, no "cut", no "paste", no backspace, no tab, etc...).
Is there a complete list of events (or user actions) that a contenteditable='true'
element can get and is reacting to?
How to disable most of these events or user actions (on keyboard & mouse) and react only to some (well defined) keyboard events?
Apparently, a <span>
element in a non-contenteditable
element cannot get any keyboard user action (because it cannot get the focus)...
I am targeting only recent HTML5 browsers, such as Firefox 38 or 42, or Chrome 47 etc... on Debian/Linux/x86-64 if that matters (so I really don't care about IE9)
PS. this is a related question, but not the same one.
PS2: Found the why contenteditable
is terrible blog page. Makes me almost cry... Also read about faking an editable control in browser Javascript (for CodeMirror). See also W3C draft internal document on Editing Explainer and edit events draft. Both W3C things are work in progress. W3C TR on UI events is still (nov.2015) a working draft. See also http://jsfiddle.net/8j6jea6p/ (which behaves differently in Chrome 46 and in Firefox 42 or 43 beta)
PS3: perhaps a contenteditable
is after all a bad idea. I am (sadly) considering using a canvas
(à la carota) and doing all the editing & drawing by hand-written javascript...
addenda:
(November 26th 2015)
By discussing privately with some Mozilla persons, I understood that:
contenteditable
is messy (so I rather avoid it), and is not anymore worked much in Firefox (for instance, even recent beta Firefox don't know aboutcontenteditable='events'
, seensGenericHTMLElement.h
file)event bubbling and capturing matters a big lot
a normal
<div>
(or<span>
) can be made focusable by giving it atabindex
propertytext selection API could be useful (but has some recent bugs)
So I probably don't need contenteditable
You can do as such:
Edit:
(Handles only the spans with the said class. Also handles the case, where you could go back from another span into a previous one and could delete it. Incorporates the idea of @AWolff for switching the contenteditable attribute on focus)
The overall idea remains the same as that of the previous version.
Fiddle: http://jsfiddle.net/abhitalks/gb0mbwLu/
Snippet:
Apart from the usual handling of events on the spans and preventing / allowing the keys and/or commands from the white-lists and balck-lists; what this code does is to also check if the cursor or editing is currently being done on other spans which are not constrained. When selecting or moving using arrow keys from there into the target spans, we dis-allow special keys to prevent deletion etc.
I could not get much time, and thus one problem still remains. And, that is to disallow commands as well like cut and paste while moving into the target spans from outside.
Older version for reference only:
You could maintain a white-list (or blacklist if number of commands allowed are higher) of all keystrokes that you want to allow. Similarly, also maintain a dictionary of all events that you want to block.
Then wire up the commands on your
div
and useevent.preventDefault()
to reject that action. Next up, wire up thekeydown
event and use the whitelist to allow all keystrokes that are in the permissible ranges as defined above:In the example below only numbers and alphabets will be allowed as per the first range and arrow keys (along with pageup/down and space) will be allowed as per the second range. Rest all actions are blocked / rejected.
You can then extend it further to your use-case. Try it out in the demo below.
Fiddle: http://jsfiddle.net/abhitalks/re7ucgra/
Snippet:
Edited, to fix the problem of not capturing special keys especially when shift was pressed and the same
keyCode
is generated forkeypress
. Added,keydown
for handling special keys.Note: This is assuming that to happen on the entire
div
. As I see in the question, there are onlyspan
s and that too nested ones. There are no other elements. If there are other elements involved and you want to exempt those, then you will need to bind the event to those elements only. This is because, the events on children are captured by the parent when parent iscontenteditable
and not fired on the children.A straightforward solution to your problem would be to listen on the
keydown
event fired by the inner-most element and act accordingly. An exemplary code snippet can be found below:HTML:
JS:
This works for both
<input>
elements as well as elements with thecontenteditable
attribute set totrue
.JS Fiddle: https://jsfiddle.net/rsjw3c87/22/
EDIT: Also added additional checks to prevent right-click & copy/cut/paste. Disabling right-click directly via the
contextmenu
event will not work as certain browsers & OSes disallow you from disabling that specific event.This snippet could be what you are looking for, making
span.momitemref_cl
elements focusable but not tabbable and setting hascontenteditable
. But as i'm testing it on chrome,contenteditable
inside any container with attributecontenteditable
set totrue
, don't fire any keyboard event. So the trick could be on focus to set any container to not editable (and switch back on blur).See e.g: (keypress and keydown events are both binded to handle some specific cases where keypress or keydown wouldn't be fired on specifc keys)
NOTE: has you seem to populate DIV with content dynamically, you could delegate it or bind event (& set tabindex attribute if changing it in HTML markup not a solution) once ajax request has completed.
First,
HTMLElements
becomecontentEditableElements
when you set theircontentEditable
attribute totrue
.Now, the best way to do your parsing IMO is to listen to the
inputEvent
and check your element'stextContent
:Unfortunately, the input event isn't widely supported so you may need to add
onkeydown
andonpaste
and maybeonclick
event handlers to catch non-supporting browsers (a.k.a IE).