I am a beginner in Javascript & HTML5
Suppose I have a contenteditable <div> [block-level] element in my HTML5 window.
What is the exhaustive list of JavaScript events which the user could trigger by modifying this element (or some sub-elements) through user interaction?
How should I code in JavaScript to reject some user action? or change the DOM... (i.e. replace some TextNode with e.g. some <span>)
It seems that the input event cannot "undo" or "reject" some user action...
FWIW, at this point I only care about recent Firefox browsers (mine is 21 beta 7 on Linux).
This is an answer to a related question.
In other words, I don't have a clear picture of how to design rich text editors in HTML5 & JavaScript.
PS I want plain JavaScript, not interested in any library above it yet.
Addenda
Maybe mutation observers could be relevant?
Follow-up question here...
The exhaustive list of events on contenteditable elements is the same as for input type=text. See this list of all events (look especially at Form Events): http://www.w3schools.com/tags/ref_eventattributes.asp
"How should I code in Javascript to reject some user action?"... just put "event.preventDefault()" at the beginning of an event listener for the event of that action. Example to reject keypresses:
contenteditableElement.addEventListener('keypress', function (e) {
e.preventDefault();
// do something else, maybe...
});
To undo a user's action:
document.execCommand('undo', false, '');
As to designing rich text editors, there are many good demos available. I recommend:
https://developer.mozilla.org/en-US/docs/Rich-Text_Editing_in_Mozilla
http://www.quirksmode.org/dom/execCommand/
Make sure to view source of the last link; especially the buttons.js file. Also check out the amazing commands list on the MDN article. Good luck -- but try not to re-invent the wheel. There are many well-tested editors out there; check out this list: http://www.webdesignerdepot.com/2008/12/20-excellent-free-rich-text-editors/
Related
I am trying to add more accessibility to my app so i've added eslint-plugin-jsx-a11y to my eslint process. This has been great, however I have a question in regards to the click-events-have-key-events rule (https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/click-events-have-key-events.md ).
I want to add an onKeyDown or an onKeyPress anywhere I'm using the onClick in my react code. However I am not sure which keycode I should be listening to.
If, for example, I just do
<div
onClick={this.myFunction}
onKeyDown={this.myFunction}
/>
That onKeyDown function fires when i just tab away from that div. So I am thinking I need to filter keyCodes, however when trying to meed accessibility standards, I'm not sure which keyCodes I need to listen for. Is the enter keyCodes enough - do all screen readers respect this for example?
Looking for some insight into this to help make my app more accessible and screen reader friendly.
You didn't ask specifically about this but the best solution is to use a native html element if possible. See the first rule of ARIA use. Native elements have the behavior built in to the element and work great with screen readers.
However, sometimes you need to create a custom element and that's where ARIA comes in. But you need both attributes and a role to make a custom element, and additionally you need keyboard/mouse handlers if the element will be interactive.
The types of keyboard events you listen for depends on the role. For example, if you were creating your own link element, instead of using an <a>, you'd listen for the ENTER key. If you were creating your own button, you'd listen for both the ENTER and SPACE keys.
The types of keys you listen for are explained in the design patterns in "WAI-ARIA Authoring Practices 1.1". For example, see the "Keyboard Interaction" section for buttons.
I have a webapp which will be viewed using certain popular browsers and I am required to support the handling of certain keypress events. Our users will be using Windows and the keypress events always use the Alt key as a modifier.
There is no specific requirement for keyUp/keyDown event handling, the user just has to feel like something happens when he/she presses, for example, Alt-F.
How do we accomplish this in the Firefox browser, which we are required to support?
The problem:
All of our implementation attempts are interfered-with by the fact that when the FireFox menu bar is visible (File, Edit...), pressing an Alt key combination which is already claimed by the menu bar (example: Alt-f) will cause the appropriate menu to expand. We don't want this to happen. I have been shown examples of web apps (using tens of thousands of lines of javascript....) that do NOT experience this issue, so I know it is possible, but I don't know how this was done in the example I've seen with my own eyes.
I can find dozens of examples on the web of how to write an alt-key handler in JS, but I haven't found a single article on this issue or a single code example that works under the circumstances I've described. We are using Spring-MVC and a recent version of jQuery, if that matters.
I'm happy to update the question with any other information that proves relevant.
Side note about work-around suggestions:
The requestor has specifically demanded that I use the Alt key as the modifier, on the grounds that they use other webapps in FireFox where both the menu-bar is visible AND alt key combinations work. (Example: Alt-s). So, feel free to post well-intentioned work-arounds in the comment section if you wish - I promise that my own personal curiosity will drive me to read them all - but also keep in mind this is not the subject of my question.
Be aware that some browsers will not allow you to capture certain shortcuts! A working example in native Javascript for the Alt+s shortcut in Mozilla Firefox (version: 51.0.1, Linux):
window.onkeydown = function(e){
if(e.altKey && e.keyCode == 83){
e.preventDefault();
alert("Shotcut Pressed")
}
}
Hotkeys have been done well by various projects, such as jquery.hotkeys. You can see a working example on their demo page for most hotkeys. It's very small, only about 200 lines.
Here is a small example with the Alt+S hotkey that works for me (without triggering the history menu) in Firefox 40.0.2 (when the page is in focus of course, not the codepen editor).
$(document).bind('keydown', 'Alt+s', function() {
$('body').append('Alt+s was pressed; ');
// alert('alert will cause the menu to activate, do not use');
return false;
});
Most of user interaction elements associated to a custom JavaScript behavior in Web applications can be HTML links (a elements) having a meaningful href attribute value, enabling them to be used in non JavaScript-enabled environments:
<a id="profile" href="profile">Profile</a>
<script>
document.getElementById("profile").onclick = function() {
return !open(this.href, "_blank", "scrollbars=no,status=no"); // whatever
};
</script>
But some interaction elements are deeply linked to JavaScript, either because the Web application they are contained in requires JavaScript to run or because they were generated by JavaScript and don't make any sense when it is not available.
For those, as I want users to be able to interact with them whatever device they are on (i.e. I don't want to define mouse, keyboard, touch, … interaction by myself on a span element), I see two relevant HTML elements: a and button.
My problem with the a element here is that it defines at least one behavior I don't want: the ability for the user to open its target anywhere he wants to (e.g. in a new tab), whereas the interaction I want to take place is specific to the current tab.
My problem with the button element here is that, as far as I can tell from the online resources, it is difficult to style reliably on all modern browsers (but I am not sure if it is still the case now).
Some of the facets of this question have already been answered elsewhere, but I can't find a comprehensive and up-to-date summary: what HTML element would you recommend to use?
If you want an element to semantically be a button without the style issues of a <button> element, or behavior of an <a href> element, then you should use an element with [role="button"]. <span> is commonly used, but pretty much any element could be used.
<span role="button"></span>
Now, [role="button"] is really just a flag for assistive technology, so some interactions need to be set up to react as a button, but they're actually quite easy.
Buttons (such as links and form elements) are typically tabbable. This isn't always necessary, such as if a keyboard shortcut has been set for it already. If you want the <span> in the tabbing order, just add the [tabindex] attribute:
<span role="button" tabindex="0"></span>
Now you can tab to the button, but you'd probably still want to trigger the click event when Enter and/or Space is pressed.
Simply adding an event listener to the button is enough.
For brevity this example uses jQuery:
$(document).on('keydown', 'span[role="button"]', function (e) {
if (e.which === 13 || e.which === 32) {
$(this).click();
e.preventDefault();
}
});
This uses an event delegation format to provide click support for all spans with [role="button"], you may want to choose a different selector depending on your situation.
Now all that's left is to listen for when the button is clicked:
Again, jQuery:
$('.myButtonClass').click(function () {
...do stuff...
});
Now, for other devices, you're going to want to trigger a click on, say, a touch event. If you're using jQuery, there are assorted libraries to support turning touch into click and/or tap. If you're not using jQuery, it's not a lot of work to listen for touch events.
I'm not going to provide a code example to handle touch, but that's because it depends on what the button is supposed to do. In some cases you want to trigger a handler simply by starting a touch on the button (equivalent to mousedown), in other cases you want to trigger the handler if you've started and stopped the touch event on the same element (similar to how click works normally).
I need to send bunch of commands to the server on timer - like:
put(0,"hello")
del(4,1)
put(4," is around the corner")
so I need to monitor and record all of the user input and compile/flush it on the timeout (idle), something like macros.
I can record all things happening onKeyUp/onKeyDown/onMouseDown/onMouseUp using textarea cursor position and keys information (and make it cross-browser some time later) but I can't handle things like pasting using mouse right button and selecting 'Paste' or pasting from the menu (I can handle onChange, but I will have no information is it pasted or already recorded as pressed keys and it fires only after focus change). Even pasting from context menu fires some useful info, but the menu from the browser is the only thing, giving nothing for Javascript.
Is there any plugin for jQuery or something like that and do I really have no other ways to implement it without comparing current-document and document-a-second-before?
Upd.: There are events for handling cut/copy/paste: http://www.quirksmode.org/dom/events/cutcopypaste.html , but what about
the undo one?
P.S. I will show a macro-recording code when I'll finish, if someone really needs it. And to finish it properly, I just need the undo handling possibility. Current version is here: http://code.google.com/p/sametimed/source/browse/WebContent/module-editor.js, look for compileCommands method.
There are events for cut/copy/paste you may listen to, depending on browser. So if they are triggered you may use them, otherwise fall back to more tedious work-around.
See: http://www.quirksmode.org/dom/events/cutcopypaste.html
I've noticed that some sites (usually banks) suppress the ability to paste text into text fields. How is this done? I know that JavaScript can be used to swallow the keyboard shortcut for paste, but what about the right-click menu item?
Probably using the onpaste event, and either return false from it or use e.preventDefault() on the Event object.
Note that onpaste is non standard, don't rely on it for production sites, because it will not be there forever.
$(document).on("paste",function(e){
console.log("paste")
e.preventDefault()
return false;
})
Even if it is somewhat possible to intercept the paste event in many browsers (but not all as shown at the link on the previous answer), that is quite unreliable and posible not complete (depending on the browser / OS it may be possible to do the paste operation in different ways that may not be trappable by javascript code).
Here is a collection of notes regarding paste (and copy) in the context of rich text editors that may be applied also elsewhere.