How can i catch the firefox spellcheck correction event? - javascript

I have a textarea. After writing some misspelled text and using rightclick -> correction the word gets replaced with a correctly spelled word.
Now, my problem here is that i need to exectue some javascript code when the correction gets done.
How can i catch the firefox spellcheck correction event?
If there is a only a solution using a firefox Add-On i would be happy too to know that one.

Mozilla fires oninput in this case, didn't test in others, but should work everywhere.
Interestingly enough, FF seems to fire two input events when using spelling correction: it deletes the word first, and then inserts the new one:
> value=[holy coww]
(right click and choose "cow")
> value=[holy ]
> value=[holy cow]
http://jsfiddle.net/7ssYq/

I was originally going to suggest the oninput event, like thg435's answer, but I thought I'd fish for more details in the comments first. If you don't need to differentiate between spell checker corrections and other types of input (keyboard, paste, drag and drop, etc), then oninput would do the job just fine.
If you do want to differentiate between those types of input, then I'm afraid there's no event that fires specifically for spell checker corrections. However, there are events for most other types of input, so you could at least narrow down the likelihood of your input event being a correction if you check for other types of event first. Consider the following:
(function () {
var el = document.getElementById("MyInput"),
ignore = false;
el.oninput = function (e) {
// ignore the events that we don't need to capture
if (ignore) {
ignore = false;
return true;
}
// Your code here
}
// IIRC, you need the following line for the `ondrop` event to fire
el.ondragover = function () { return false; }
// Ignore paste, drop and keypress operations
el.onpaste = el.ondrop = el.onkeypress = setIgnore;
function setIgnore (e) {
ignore = true;
}
})();
This isn't a perfect solution, however. For instance, the event will still fire for Undo/Redo actions (and, perhaps some other actions) that aren't initiated by the keyboard.

Related

Debounce search only if search term changes [duplicate]

This question already has answers here:
Throttle event calls in jQuery
(7 answers)
Closed 5 years ago.
I'm working on a live ajax search field. So we have:
<input type="search" id="search">
And I want to trigger the search once the user has stopped typing for 500ms.
I got it working like this:
function throttle(f, delay){
var timer = null;
return function(){
var context = this, args = arguments;
clearTimeout(timer);
timer = window.setTimeout(function(){
f.apply(context, args);
},
delay || 500);
};
}
$('#search').keyup(throttle(function(){
// do ajax
}));
The problem is: if user holds shift key and releases it, the search will trigger regardless. So no new keys are added and the same search term was submitted.
How can I make it so that it triggers only if a new character has been added/removed?
Simply keep track of the state:
var currentSearch = "";
Then whenever a keyup happens, check if the input changed, if not stop updating:
if($("#search").val() === currentSearch) return;
//updated so:
currentSearch = $("#search").val();
Sidenote: as DOM lookup is time intensive you may cache $("#search") ...
You could also use the keyup event, and check if the keycode matches the keys on which you want to act on. Please refer this answer
Adapting that answer to your case:
$('#search').keyup(
function(event) {
var isWordCharacter = event.key.length === 1;
var isBackspaceOrDelete = (event.keyCode == 8 || event.keyCode == 46);
if (isWordCharacter || isBackspaceOrDelete) {
(throttle(function(){
// do ajax
})))();
}
})
You should use input event instead of keyup, which will be triggered only when the value will change.
$('#search').on('input', throttle(function(){
// do ajax
}));
The DOM input event is fired synchronously when the value of an <input>, <select>, or <textarea> element is changed. (For input elements with type=checkbox or type=radio, the input event does not fire when a user clicks the control, because the value attribute does not change.)
But be aware that this event has some problems in IE9/10/11 (and is not supported in previous IE versions at all):
[2] IE 9 does not fire an input event when the user deletes characters from an input (e.g. by pressing Backspace or Delete, or using the "Cut" operation).
[3] IE 10 and 11 has a bug, input event fires on placeholder attribute changes.
But the IE10/11 problem is kind of ok, so it depends on if you need to support IE9.
https://developer.mozilla.org/en-US/docs/Web/Events/input
EDIT: unfortunately change is not a suitable solution as it occurres only after blur (loosing focus of the input). Correct solution is to use input event.

Check if INSERT mode is ON when typing in an input

I'm trying to calculate the value of an input field on various events regardless of the event caught.
I'm taking into account the events keypress keyup keydown cut paste events (Do I forget anything?).
I'm trying to determine if the text-input INSERT mode is on (default - on), or off. I cannot determine the mode by capturing a key event of that key, though I don't know what was the initial state.
Does anyone know a way? Preferably - a cross browser solution that includes IE8+, Chrome and Firefox.
Any solution, or in the words of Barney Stinson, "scam, con, hustle, hoodwink, gambit, flim flam, stratagem, and bamboozle" that could help me would be appreciated.
For IE only:
document.queryCommandValue("OverWrite");
As far as I know, Firefox and Chrome don't have overwrite mode. The insert key doesn't work in those browsers, and they are always in insert mode.
Moreover, Mac keyboard doesn't have a insert key from the beginning. So Safari also is always in insert mode.
Although I don't think you can directly access the state of the user's Insert status, you can figure out how long the strings are when the user is editing the field.
Consider this, tied with a simple <input id="input" />:
var i = document.getElementById('input');
document.onkeydown = function(e) {
var c = String.fromCharCode(event.keyCode);
if(null !== c.match(/\w/)) {
l = i.value.length;
}
}
document.onkeyup = function(e) {
var c = String.fromCharCode(event.keyCode);
if(null !== c.match(/\w/)) {
if(l === i.value.length) {
console.log("Keyboard insert might be off - length hasn't changed");
}
}
}
Note that there is a rudimentary check to try and isolate only letters and numbers (with the match against the keyCode (borrowed from here), as you don't want to perform the check against a shift key being pressed, for instance.
Basic POC here: http://jsfiddle.net/Xp3Jh/
I'm certain there are more in-depth checks you can do, but hopefully this helps!

keyup on mobile web apps seems to still not override a content block

I have some input that i am obtaining from the keyup event on an input textbox.
$(selector).keyup(function(){
var str = $(this).val();
var X = 2;
var Y = 1;
$(this).val(str.substring(X,Y));
});
When looking it in a standard webapp, $(this).val() doesnt have the newly pressed key in there. WHich part of the lifecycle should i be looking at instead? It seems that when doing it in a webapp, it seems to execute as planned, but not when using this in an iOS webview/mobile app
Edit:
it seems that there may in fact be a difference in the lifecycle for these listeners. When doing keyup, it recognizes $(this).val() as the old content plus the new character, where as on the mobile device, it only recognzies the old content. The new character is easily obtained by:
String.fromCharCode(event.which)
but at that point in the life cycle i cannot say to not remove it. I was looking into the idea of maybe other events to tie into, as well as doing things like event.preventDefault(); or event.stopPropagation(); but i wasnt sure where to go.
Any idea how to work and handle this sort of event, or listener would be great. With my current logic, it is needed for when i have the new content set. Maybe a simple on("input") might suffice?
Guidance highly appreshiated. :)
Jquery Documentation on the page for keyup():
For catching actual text entry, .keypress() may be a better choice.
Resolving my coding issue:
1) Change the event from keyup to keypress.
2) Do the following:
var reg = new RegExp("\\D");
if(reg.test(String.fromCharCode(event.which))){
var str = $(this).val();
var strArr = str.split("");
// for handling when people maintain the press,
// i created a range array to delete the range.
strArr.splice(cRange[0], cRange[1]-cRange[0]+1);
str = strArr.join("");
$(this).val(str);
event.preventDefault();
}

how to remove keyup event listeners by javascript

I'm using the Google autocomplete api on a text field to suggest locations as you type.
The main problem I have with this is that Google does not let you limit results to a specific country, it just lets you bias results to area bounds which is kind of useless.
So seaching for term "ru" will give you Russia in suggestions even your region is set to somewhere in Europe.
I realized though that if you put for example "france ru" it gives you france locations only matching ru which is perfect.
So my problem is that the autocomple is completely built by google javascript.
autocomplete = new google.maps.places.Autocomplete(input, options);
So I cannot easily fiddle with search string to add in to it constantly "france"
I can see what is bound to the onkeyup event on that field and can take it and call it myself however I cannot unbind it from keyup. I tried several solutions how to do it but can't find a way. jQuery unbind won't work as this is not bound through it obviously. Native functions want a reference to a function bind to listener but this is annonymous function in it. Found some examples using loops over element.data['events'] but I get data undefined error.
Has anyone solution to unbind all what is register in onkeyup ?
You mentioned jQuery, so I'll use that:
$(input).data('events').keyup is the array that will contain all the keyup handlers. If there is only one keyup event used by Autocomplete, you can hijack the handler to first run whatever function you need, then run the original:
var originalKeyup = $(input).data('events').keyup[0].handler;
$(input).data('events').keyup[0].handler = function(){
// your code here, where you can add 'france' to input.value
// fire the old function
originalKeyup.apply(this,arguments);
};
You could also just remove the original event handler from the keyup array, and bind new ones that will do what you want.
UPDATE:
You could hijack Element.prototype.addEventListener (BEFORE ALL OTHER CODE) to add an events property to the Element which will contain any handlers added by any code:
var oldAddEventListener = Element.prototype.addEventListener || Element.prototype.attachEvent;
Element.prototype.addEventListener = Element.prototype.attachEvent = function(type, handler){
this.events = this.events || {};
this.events[type] = this.events[type] || [];
this.events[type].push({handler: handler})
oldAddEventListener.apply(this,arguments);
};
Now, every time addEventListener is called, by jQuery or otherwise, the Element's events property should be updated with the current events. You may also want to hijack removeEventListener to remove the corresponding event from the events object when removeEventListener is called:
var oldREL = Element.prototype.removeEventListener || Element.prototype.detachEvent;
Element.prototype.removeEventListener = Element.prototype.detachEvent = function(type, handler){
this.oldREL.apply(this,arguments);
if(this.events && this.events[type]){
for(var i=this.events[type].length-1; i>=0; i--){
if(this.events[type][i].handler == handler){
this.events[type].splice(i,1);
break; // remove only the first occurrence from the end
}
}
if(this.events[type].length==0){
delete this.events[type];
}
}
};
Now you should be able to inspect all events registered on any element. You can remove all 'keyup' events by iterating over the input.events.keyup object and using input.removeEventListener.
The attachEvent and detachEvent are used by IE<9. I don't have IE, so it hasn't been tested there. It works well in Safari 5. Let me know if you have issues in other browsers.
NOTE: These mods need to be in place BEFORE any other code is executed on the page.
Update:
Apparently, this will not work in FF or Opera. Changing Element to HTMLInputElement in the code will fix the problem.
Have you tried binding the autocomplete to the current map bounds, as shown in the documentation: autocomplete.bindTo('bounds', map) ?

How to change characters typed in Firefox

I need to change in a text input the character '.' to ',' while typing.
In IE I change the keyCode event property in the keypress event, like this
document.getElementById('mytext').onkeypress =
function (evt) {
var e = evt || window.event;
if (e.keyCode && e.keyCode==46)
e.keyCode = 44;
else if (e.which && e.which==46) {
e.which = 44;
}
};
but it seemes that in Firefox it's impossible to change characters typed in key events.
Any suggestions?
Try this. It works on all browsers:
window.onload = function () {
var input = document.getElementById("mytext");
input.onkeypress = function () {
var evt = arguments[0] || event;
var char = String.fromCharCode(evt.which || evt.keyCode);
// Is it a period?
if (char == ".") {
// Replace it with a comma
input.value += ",";
// Cancel the original event
evt.cancelBubble = true;
return false;
}
}
};
Update: Pier Luigi pointed out a problem with the above. It doesn't take care of the caret position not being at the end of the text. It will append the command to the end even if you're inserting some text to the value.
The solution would be, instead of appending a comma, to simulate a keypress event for the comma key. Unfortunately the way dispatching of synthetic events work in different browsers seems to show a lot of variety and isn't an easy feat. I'll see if I can find a nice and generic method for it.
Assume that all properties in an Event object are immutable. The DOM spec doesn't address what happens when you change those values manually.
Here's the logic you need: listen for all key events. If it's a period, suppress the event, and manually add the comma at the cursor position. (Here's a code snippet for inserting arbitrary text at the cursor position.)
You'd suppress the event in Firefox by calling event.preventDefault(); this tells the browser not to go ahead with the default action associated with this event (in this case, typing the character). You'd suppress the event in IE by setting event.returnValue to false.
If it's not a period, return early from your handler.
Technically you just want to replace all dots with commas.
document.getElementById('mytext').onkeyup = function(){
this.value = this.value.replace('.', ',');
}
If I look at the official Document Object Model Events document, mouse events fields are defined as read-only. Keyboard events are not defined there, I suppose Mozilla followed this policy for them.
So basically, unless there is some smart trick, you cannot alter an event the way you want. You probably have to intercept the key and insert the char (raw or translated) where the caret is, the way JS HTML editors do.
Does this really need to be done on the fly? If you are collecting the information to be posted to a form or submitted to a database, would it not be better to modify the data once it was submitted? That way the user never sees the confusing change.
This is possible now by intercepting and cancelling the default keydown event and using HTMLInputElement.setRangeText to insert your desired character. This would look something like this:
document.addEventListener('keydown', $event => {
if($event.code === 'Period'){
$event.preventDefault();
let inputEl = document.querySelector("#my-input");
inputEl.setRangeText(
',',
inputEl.selectionStart,
inputEl.selectionEnd,
"end"
);
}
})
setRangeText will insert text at the cursor position in a given input. The "end" string as the last argument sets the cursor to the end of the inserted content.
More info here: https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/setRangeText

Categories