JavaScript event for contenteditable elements - javascript

Is there a way to capture JavaScript events for when a contenteditable element begins and ends editing?

I'm not sure exactly here, but aren't you after focus and blur? I'm not sure what else "begins and ends editing" could be translated to that has a different timing than those, unless you mean an event for every keystroke, etc.

As Nick said, focus and blur will work, and in all major browsers. IE also has a number of related events (although none of these are implemented in other browsers as far as I know): activate, deactivate, beforeactivate, beforedeactivate and beforeeditfocus

Related

JavaScript event handler race

If I have a text field with a registered onblur event handler and a button with a registered onmouseup event handler, which one of those two functions will run sooner and why?
To make my question clearer, let's suppose the focus is currently on the text field and I want to click on the button.
Will there be any difference between various Internet browsers?
Edit
Especially tricky seems the onmousedown event when it's registered with the button, whilst the text field has an onblur event registered with it.
The spec says blur must be fired when focus leaves the element (after taking focus away), but I don't see any explicit statement about when that must occur relative to the event causing the focus to be moved away.
Certainly the mouseup will happen much later (in computer terms), as first you have to mousedown.
I would have expected blur to fire prior to even the mousedown, but I would have been wrong: According to experimentation, mouseup is after, but mousedown is before. I tested that using Chrome 26, Opera 12.15, Firefox 20, IE8, and IE9 — and if you can get those five to agree on a behavior, it's likely to be consistent in others... :-) My suspicion is that this is because if you prevent the default action of the mousedown, focus never moves away from the text field: Example. (This behavior is consistent across four of those five browsers, with IE8 not preventing the focus change — meaning IE7 and 6 probably don't, either.) So while it seems odd, it does kind of make sense.
As always, test with the browsers you intend to support.
Just save the timestamp when starting
var start = new Date().getTime();
and then
var elapsed = new Date().getTime() - start;
into the handler.

Synchronizing identical html forms

I'd like to have two (or even more) identical html forms on my website.
For example, one - at the top, and another - at the bottom of the page.
What i want is for them to have exactly the same content at any given time. If user changes a value in one of them, all the rest are updated.
Is there a better way to synchronize then javascript onchange/onkeyup events?
onchange fires only after element loses focus.
onkeyup is not perfect too. It wastes a lot of cpu on long text copying and won't fire if element lost focus between onkeydown and onkeyup events.
Update: I just learned that HTML5 has a more appropriate event for this, oninput, but of course it doesn't work in older browsers. oninput will detect any kind of text change, including Paste, Cut, and Delete from the right-click menu. So the best option may be to check if the browser supports oninput (e.g. by using the function recommended here), falling back to the below method if not. On older versions of IE, onpropertychange can be used to simulate oninput.
I decided to change my answer, based on how KnockoutJS accomplishes this. From this page in the Knockout docs:
"afterkeydown" - updates your view model as soon as the user begins typing a
character. This works by catching the browser’s keydown event and handling the event
asynchronously.
Of these options, "afterkeydown" is the best choice if you want to keep your view model
updated in real-time.
It accomplishes the asynchronous behavior by using setTimeout with a time value of zero. Other than that, it appears to be just like a regular keydown event handler.
Here's a simple example, using jQuery, which I believe behaves equivalently to Knockout's "afterkeydown" event:
$('#email').keydown(function() {
setTimeout( $.proxy(handler, this), 0);
});
function handler() {
console.log( this.value );
}
Note:
This will not catch right-click paste events and drag-and-drop events. If you want to update the text on those events too, simply listen for them in the same manner as keydown, e.g.:
$('#email').on('keydown paste drop', function() {
setTimeout( $.proxy(handler, this), 0);
});
Like keydown, paste and drop also need the setTimeout in order to update with the latest value of the text.
Original answer:
onkeyup is probably the way to go, but you raise a good point about it not firing if the element loses focus between keydown and keyup. Based on this answer, I'm pretty sure the solution would be to listen for the keyup event on a container element (or on the body, although in this case it would probably make the most sense to bind it to the <form> element).
As to CPU usage on paste, you could try canceling the event unless a certain amount of time has passed (say 50 ms)...hopefully that will be sufficient. If not, you could look at how some of the popular 2-way data-binding frameworks handle this...most of the ones I've seen use onkeyup.

DOM Changed Event Firefox Extension

So I have created a Firefox extension and it works great, however when I submitted it (although it was accepted) it came up with one security warning. It said setTimeout() was removed in an else clause.
So, is there a way to listen for any DOM change? (or even a specific element changing, I have an ID for both). However, divs do not have an onChange event so any ideas?
I don't mind if it's ANY change, doesn't have to be div-specific.
DOMSubtreeModified event sound like something you want to use. Keep in mind, that it is deprecated and after some time its support will probably be removed from browsers.
http://help.dottoro.com/ljrmcldi.php
It turns out adding an "onChange" event to a div works fine, although it might not be W3C valid it doesn't really matter as it's only a Firefox extension (plus it works!).

Javascript context menu click event/detection - filter paste content

Scenario: I'm trying to intercept paste events inside a textarea/input text, and filter the content being pasted.
Webkit/IE are handled rather well, as I can attach code to the onpaste event, and then read from the clipboard what is being pasted. Plenty of examples around.
Gecko is trickier, because as far as I know it isn't possible to read the clipboard content on Firefox (unless somebody knows a workaround for that?)
I just use the input swap trick for that.
Opera is being annoying tho. I can trap CTRL+V and SHIFT+INS, but there's no onpaste event.
Not to mention any sort of clipboard interaction, apparently.
So, my question is:
Can I detect if the user clicked on paste in the context menu on Opera? Is there any other way to detect the event?
EDIT:
Thanks everybody for the answers - they all add a good input, even if there's no definitive solution.
Having to choose, I'll pick the only one that tried to address the original question, and that would probably work if it wasn't too much of an hack to even try.
Notes for those that have my same problem (input filtering):
it is possible to capture content being dragged: mouseup + setTimeout does the trick everywhere almost perfectly.
without flash, there is probably no solution bar polling. Even with flash, it's not a completely solid solution either. Too much effort to support 100% of the cases.
I ran into this last year. In short, no.
I ended up using an onchange handler and filtering the content after it's already been pasted into the text box.
You can intercept the paste with jQuery using the bind('paste', function() {});, compare string before and after pasting and apply your formatting.
The following was tested in IE7/FF3.6/Chrome/Safari 5
$("#textarea").bind('paste', function(e){
// Do whatever you needed to do with the code here.
});
Live Example http://jsfiddle.net/VSrTg/2/
Edit An approach would be something like this:
$("#textarea").bind('paste', function(e){
var oldText = this.value;
setTimeout(function() {
// Compare oldText to $("#textarea").val() and format accordingly.
}, 1000);
});
​Edit 2 Given your revisions to your original post, if you're worried about the giant market share that is Opera, you're going to have to monitor the value of your textbox with a setInterval() and compare it against itself for changes.
Ultimately there will always be a way around your script, even the above example is susceptible to simply dragging text from another text box (or the address bar) into it without triggering the paste event defined above.
I would like to point out DOJO menu widget that is creating context menus perfectly in different browsers. http://www.dojotoolkit.org/reference-guide/dijit/Menu.html#dijit-menu
What you can do is that detect paste event in browsers that are supporting it and override context menu in browsers that are not supporting this event like opera.
Once you create your own context menu then you can add copy paste menu item or create context menu similar to the default using css.
Edited
Some browsers might not allow us to fetch clipboard content, in this case we can always revert back to flash for borrowing some of its features that are cross browser. See couple of links I posted in comments.
Its complete implementation might have more issues than anticipated but it is possible and we can always give it a try (I will for sure).
The answer to the question is a simple no. The main browsers that have no paste event are recent versions of Opera and Firefox 2. Given that there is no paste event, you need to find an alternative event or set of events to detect a paste from the context menu as it actually happens. You can add handlers for every event there is (I've done this) and you simply get nothing in the relevant browsers when a paste is triggered from the context menu by the user.
This only leaves polling the text input's value regularly, which is not the same thing. You could keep track of keypresses and observe in your polling code that the text input's value has changed by some means other than keyboard input and do a diff, but that's hacky and unreliable.
I use the setTimeout for paste events. But for context menu select nothing seems to work(as stated above). I bind a mousemove to the input's form which fires the update function. Then unbind/bind so they don't stack up.
This handles the context menu select and dragging value to input field.
If your form is small, say with only one input field and the mouse will not land on it after selecting from context menu, bind to the form's parent or document. Sure, it has to wait until the mouse moves but that is the general user action after selecting from context menu.
Works fine.

Cross-browser JavaScript input live change/paste detection

Is there a cross-browser way to detect live changes to an input field?
By live, I mean not when the field loses focus, and not on the next keypress, and so on. Immediately or something like it.
Using combinations of jQuery and .change(), .keyup(), .bind('paste') and so on I can get working live change detection in some browsers, but not all. Using different combinations will make it work somewhat in other browsers.
The trickiest thing to get working is mouse manipulation of the input field - selecting text and moving it (which is essentially cut and paste), right-clicking and pasting or cutting, etc. For some reason even .mousedown() and .mouseup() don't seem to cut it.
The only cross-browser solution I can think of right now is to check the input field value every 100-or-so milliseconds and compare the value against a stored value. But this seems like overkill when the event-based solution comes so close.
Is there a jQuery plug-in that does this already? Or is there some other way to achieve this?
To complete your change and key handlers, you can add handlers for cut/copy/paste. They work in Firefox >=3, IE, Safari and Chrome (but not in Opera/Konqueror).
Would that cover everything for your use case?
Depending on the Browsers you need to support you might use HTML5's oninput.
It fires immediately when the monitored input changes. In jQuery you would just do:
$('#my-input').bind('input', function(e) {
console.log("#my-input's value changed");
});

Categories