I'll start with some context: I wrote a little typing app that displays text on the screen and tracks your wpm as you type using the keypress event. Out of boredom I wanted to play around with it a little bit and have a way that it would auto type after typing a hidden command (shortend kontra code using just the arrow keys). So I have a array of characters that I am iterating through and attempting to simulate the keypress event in my each loop as shown below.
$.each(_arrToCopy, function (index, value) {
setTimeout(function () {
console.log(value);
jQuery.event.trigger({ type: 'keypress', which: value.charCodeAt(0) });
//typeIt(value);
}, time);
time += 500;
});
The issue I'm having is it appears that my event is only triggering one time and then not triggering again. The setTimeout function was an early attempt to slow the loop down in case I was just processing things too quickly. After that didn't work I implemented a nearly pure javascript function (the typeIt()) function to fake the keyboard event. It is below.
function typeIt(character) {
var keyboardEvent = document.createEvent("KeyboardEvent");
var initMethod = typeof keyboardEvent.initKeyboardEvent !== 'undefined' ? "initKeyboardEvent" : "initKeyEvent";
console.log(String.fromCharCode(character.charCodeAt(0)) + ' ' + (character.charCodeAt(0)));
keyboardEvent[initMethod](
"keypress", // event type : keydown, keyup, keypress
true, // bubbles
true, // cancelable
window, // viewArg: should be window
false, // ctrlKeyArg
false, // altKeyArg
false, // shiftKeyArg
false, // metaKeyArg
0, // keyCodeArg
character.charCodeAt(0) // charCodeArgs
);
document.dispatchEvent(keyboardEvent);
}
This also typed once, but it appears to be typing the wrong character. So I circled back to trying to make the jQuery trigger work and have gotten stuck on that. I can get it to type the first letter, but after that it appears to completely stop firing. I was wondering if there's potentially a way to reset the event trigger if it's only able to fire once in the loop without being reset, or if that's even the issue here.
If for the sake of more context you want to take a look at what this is going in, I have a mock up here (although what I'm actually working on is now a bit more refined c# app will a full backend): http://codepen.io/jiggawagga/pen/wBoaRY
Thanks in advance team stackoverflow
I had this issue in simple jQuery click event. I did below and it worked fine. See if it solves your issue
jQuery(document).off().on('click', '.my-div', function(){
// SOME EVENT GOES HERE
})
Refer http://api.jquery.com/off/
I copied your code into a jsfiddle to try it out. The only thing I had to change to get it to work was changing this:
jQuery.event.trigger({ type: 'keypress', which: value.charCodeAt(0) });
to this:
$('#out').trigger({ type: 'keypress', which: value.charCodeAt(0)});
Basically triggering the event on the element that is to receive it. I'm not very well versed in jQuery so this might not be the solution you're after. But it worked for me.
The full js for the fiddle:
var _arrToCopy = Array.prototype.slice.call("lorem ipsum");
var time = 0;
$('#out').keypress(function(e){
$(this).text($(this).text() + String.fromCharCode(e.which));
});
$.each(_arrToCopy, function (index, value) {
setTimeout(function () {
console.log(value);
$('#out').trigger({ type: 'keypress', which: value.charCodeAt(0)});
}, time);
time += 500;
});
And the HTML:
<p id="out">
Related
I have an accepted answer but am open to better ones
Be gentle, this is my first question here
I am building a web browser plugin to automate a series of processes for my organization. I pretty much have everything handled but this one problem that I have been stuck on for two days... and its like really simple I think.
In a lookup field in our ERP, you must press Shift + Right to cycle through certain options.
I am attempting to trigger this or send this any kind of way that I can.
Jquery version 2.0.3
The required event only fires on key up
The required event is not firing when I simulate input
I suspect it needs to be targeted at the input, or perhaps its related to not being trusted/being simulated
It occurs to me, that as I am using a browser extension, perhaps it is something I can simulate from this? I dont know if thats a good way to put it... I wonder what the extension could do here that plain JS or JQ on a page could not.
Update(Dec 11): So per above thought, I am looking into modifying the Jquery framework that is being used. I have saved a local copy as an local override and used these two resources to implement.
Override Javascript file in chrome
https://www.ghacks.net/2018/02/27/make-permanent-changes-to-web-pages-with-chromes-overrides-dev-tool/
I am in process of determining if local overrides are persistent (Edit: they appear to be after restart of computer, lets see if its a long term solution) but I was able to console.log my code and see it in the console.
Next steps will be modifying the handler to perform the actions I need. and/or feed the information I want fed to the system.
Update(Dec 12): probably dont need to override the whole file with this answer how to override a javascript function
Here is my function that triggers the event handler (with no result) which was modified from here
function simulateKey (currentTarget, isTrusted, key, code, keyCode, type, modifiers) {
var evtName = (typeof(type) === "string") ? "key" + type : "keydown";
var modifier = (typeof(modifiers) === "object") ? modifier : {};
console.log("In simulate key function");
var event = document.createEvent("HTMLEvents");
event.initEvent(evtName, true, false);
event.keyCode = keyCode;
event.key = key;
event.code = code;
event.isTrusted = isTrusted;
event.Target = currentTarget;
for (var i in modifiers) {
event[i] = modifiers[i];
}
document.dispatchEvent(event);
}
Here is how I use it (a little hardcoded at the moment, just for testing purposes)
function changeLookup(Lookup) {
console.log("Change Lookup");
var event_object = Lookup;
console.log("Key Event Firing");
$("input[data-name='Entity.Customer.Key']").focus();
simulateKey(Lookup, true, "ArrowRight", "ArrowRight", 39, "up", {shiftKey: true });
console.log("Key Event Fired");
}
I have looked at or tried the following solutions
Trigger a built in event in javascript?
Arrow key pressed while shift key is held down
Is it possible to simulate key press events programmatically?
How to trigger event in JavaScript?
Execute Key Press Event
Firing a Keyboard Event in Safari, using JavaScript
I have reviewed the following documentation
https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent
https://developer.mozilla.org/en-US/docs/Web/API/Event
https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/dispatchEvent
I am at my wits end here...
The answer was found here Keydown Simulation in Chrome fires normally but not the correct key
I modified it to keyup and juggled some of the parameters so the shift key was pressed... Seems like OP in the other thread did some strange stuff with the parameters in such a way as to press ctrl and shift... So I fixed that for the initKeyboardEvent but not for initKeyEvent
keyUpEventSim = {};
keyUpEventSim.keyup = function(target, k, ctrlKey, altKey, shiftKey, metaKey) {
var oEvent = document.createEvent('KeyboardEvent');
// Chromium Hack
Object.defineProperty(oEvent, 'keyCode', {
get : function() {
return this.keyCodeVal;
}
});
Object.defineProperty(oEvent, 'which', {
get : function() {
return this.keyCodeVal;
}
});
if (oEvent.initKeyboardEvent) {
oEvent.initKeyboardEvent("keyup", true, false, document.defaultView, false, false, ctrlKey, altKey, shiftKey, metaKey);
} else {
oEvent.initKeyEvent("keyup", true, false, document.defaultView, false, false, true, false, k, 0);
}
oEvent.keyCodeVal = k;
if (oEvent.keyCode !== k) {
alert("keyCode mismatch " + oEvent.keyCode + "(" + oEvent.which + ")");
}
target.dispatchEvent(oEvent);
}
called it as follows
function changeLookup(Lookup) {
Lookup.focus();
keyUpEventSim.keyup(Lookup,39, false, false, true, false);
}
I'm not sure how to word it, this is what I'm trying to accomplish:
$(document).on('click', '.my-element', function(e) {
var data = [{
'event': e,
'self': this
}];
// Trigger the override function first in case they need to stop prop
$(document).trigger('override:something',dataa);
// Would like to only trigger this default method if the event above is not set
$(document).trigger('something',data);
});
Then on another page I have something to catch this event, like so:
$(document).on('override:something', function(e,data) {
e.stopImmediatePropagation();
data.e.stopImmediatePropagation(); // neither work
});
If I could stop all subsequent events like this that would be optimal, but I could also make it work if there were a way to check if custom events are set.
I could check whether override:something exists and if it does, do not execute the default something event afterwards.
I've tried setting removing specific callbacks like this, but it did not perform as expected and could get hard to manage.
var mycb = function() {
alert('hi');
}
$(document).on('something', mycb);
// now to remove it
$(document).off('something', mycb); // does not remove the event
Any help is greatly appreciated.
Thanks for the help guys, but this solution seems to the only thing I've found to work for now. Still accepting alternate answers, though.
var override = jQuery._data($(document)[0], 'events')['override:something'];
$(document).trigger('override:something', data);
if ( typeof override == typeof undefined )
$(document).trigger('dashboard:friend', data);
I am trying to create a custom "event" and I place this inside quotes because it won't be like a regular event per se from the events constructors.
So what I'd like to do is this
animate.addEventListener('animationReadyState',function(e){
if(e.readyState == "complete")
{
console.log("Done");
}
});
var animation = animate(document.getElementById('element'),{
left:"+200px",
top:"+200px",
easing: {
effect: "easeInOutBounce",
elasticity:1.5
}
});
My problem is how to fire off the "event"? I have the readyState changing throughout my code my problem is firing off this "event".
As of right now with using the events contructors I only get one readyState change fired off which is the complete. But I have others
initialising
invoked
animating
complete
No others are firing off.
Example of my Events Constructors:
var animateStateChange = new CustomEvent('animateStateChange',{ 'state' : null });
function initAnimate(){
animateStateChange.state = "initialising";
document.dispatchEvent(animateStateChange);
}
The problem with this is I'd have to do document.addEventListener or the element.addEventListener though putting the event listener on the element that is animating seems logical I'm not sure how to make it only fire from the element and not say on document... Maybe a little crash course on Custom Events or maybe a "hack" event firing system, even examples I can see logically.
This may give a better example of what I am looking for if you to this fiddle
I am not sure if my solution will answer your query, but i tried to use custom events considering situation given above. Also, I see that there is some glitch in dispatchEvent returned value if any handler is provided. Separately i try to return false from handler, but that too din't worked. Below might help you to understand javascript custom event a bit :
Check this link for working code:
http://jsfiddle.net/3q0vubyp/1/
var animation = animate(document.getElementById('element'),{
left:"+200px",
top:"+200px",
easing: {
effect: "easeInOutBounce",
elasticity:1.5
}
});
function handler(e){
if(e.detail.state === "complete"){
alert('Complete State');
return false;
//e.preventDefault();
//e.stopPropagation();
}
}
function animate(element, anim){
var i=0;
var j=true;
var state=['initialize','invoked','animating','complete'];
element.addEventListener('animateStateChange',handler);
while(j){
var animateStateChange = new CustomEvent('animateStateChange',{ 'detail' : {"state": state[i++]} });
//if(!element.dispatchEvent(animateStateChange)){
// j=false;
//}
element.dispatchEvent(animateStateChange);
if(i==4)
j=false;
};
}
In docs of dispatchEvent,doclink It is clearly mentioned that the return value is false if at least one of the event handlers which handled this event called Event.preventDefault(). Otherwise it returns true. That din't worked for me.
Hope that helps!
I would like to write some tests for some input filtering code in a text box. For most tests, I can just call setValue and trigger the change event, which is easy to do. However, in this case, because I want to test that the input gets filtered out (or not), I can't just setValue() directly.
I tried dispatching keydown, keyup, keypress, textinput events. I can see that the handlers for them are being called, but the text doesn't actually show in the text box Note that this only "works" in Firefox, I understand the code would look different for other browsers.
function dispatch(target, eventType, charCode) {
var evt = document.createEvent("KeyboardEvent");
evt.initKeyEvent(
eventType,
true,
true,
window,
false,
false,
false,
false,
charCode,
0
);
target.dispatchEvent(evt);
}
var id = document.getElementById('id');
id.onkeydown = id.onkeyup = id.onkeypress = function() {console.log(arguments)}
dispatch(id, 'keydown', 65);
dispatch(id, 'keyup', 65);
dispatch(id, 'keypress', 65);
dispatch(id, 'textinput', 65);
// I can see the handlers were called but it doesn't display in the text box
I understand this has restrictions because we don't want web apps to just pretend like they are acting for the user. However, this is for testing my own application and I could launch Firefox with a specific profile and install plugins, or even write my own if I know it will help.
What I am after is to avoid using Selenium, I want to keep Java out of my JS tests because not only is it slow, but I have to re-implement a lot of the DOM querying in Java.
After all this, the question is, does anybody know how to get that code to actually modify the input? Tweaking settings, installing plugins?
List of questions that don't answer my question
Simulating user input for TDD JavaScript
Definitive way to trigger keypress events with jQuery
How to send a key to an input text field using Javascript?
Is it possible to simulate key press events programmatically?
I just found out that the following code does work in Chrome at least. No go in firefox or IE http://jsfiddle.net/D2s5T/14/
function dispatch(target, eventType, char) {
var evt = document.createEvent("TextEvent");
evt.initTextEvent (eventType, true, true, window, char, 0, "en-US");
target.focus();
target.dispatchEvent(evt);
}
dispatch(el, "textInput", "a");
I'm attempting to build a webpage that loads depending on the input provided. I'm having some trouble wrapping my head around event handling in javascript, basically. Coming from python, if I wanted to wait for a specific keyboard input before moving on to the next object to display, I would create a while loop and put a key listener inside it.
Python:
def getInput():
while 1:
for event in pygame.event.get(): #returns a list of events from the keyboard/mouse
if event.type == KEYDOWN:
if event.key == "enter": # for example
do function()
return
elif event.key == "up":
do function2()
continue
else: continue # for clarity
In trying to find a way to implement this in DOM/javascript, I seem to just crash the page (I assume due to the While Loop), but I presume this is because my event handling is poorly written. Also, registering event handlers with "element.onkeydown = function;" difficult for me to wrap my head around, and setInterval(foo(), interval] hasn't brought me much success.
Basically, I want a "listening" loop to do a certain behavior for key X, but to break when key Y is hit.
In JavaScript, you give up control of the main loop. The browser runs the main loop and calls back down into your code when an event or timeout/interval occurs. You have to handle the event and then return so that the browser can get on with doing other things, firing events, and so on.
So you cannot have a ‘listening’ loop. The browser does that for you, giving you the event and letting you deal with it, but once you've finished handling the event you must return. You can't fall back into a different loop. This means you can't write step-by-step procedural code; if you have state that persists between event calls you must store it, eg. in a variable.
This approach cannot work:
<input type="text" readonly="readonly" value="" id="status" />
var s= document.getElementById('status');
s.value= 'Press A now';
while (true) {
var e= eventLoop.nextKeyEvent(); // THERE IS NO SUCH THING AS THIS
if (e.which=='a')
break
}
s.value= 'Press Y or N';
while (true) {
var e= eventLoop.nextKeyEvent();
if (e.which=='y') ...
Step-by-step code has to be turned inside out so that the browser calls down to you, instead of you calling up to the browser:
var state= 0;
function keypressed(event) {
var key= String.fromCharCode(event? event.which : window.event.keyCode); // IE compatibility
switch (state) {
case 0:
if (key=='a') {
s.value= 'Press Y or N';
state++;
}
break;
case 1:
if (key=='y') ...
break;
}
}
s.value= 'Press A now';
document.onkeypress= keypressed;
You can also make code look a little more linear and clean up some of the state stuff by using nested anonymous functions:
s.value= 'Press A now';
document.onkeypress= function(event) {
var key= String.fromCharCode(event? event.which : window.event.keyCode);
if (key=='a') {
s.value= 'Press Y or N';
document.onkeypress= function(event) {
var key= String.fromCharCode(event? event.which : window.event.keyCode);
if (key=='y') ...
};
}
};
you should not use such loops in javascript. basically you do not want to block the browser from doing its job. Thus you work with events (onkeyup/down).
also instead of a loop you should use setTimeout if you want to wait a little and continue if something happened
you can do sth like that:
<html>
<script>
var dataToLoad = new Array('data1', 'data2', 'data3' );
var pos = 0;
function continueData(ev) {
// do whatever checks you need about key
var ele = document.getElementById("mydata");
if (pos < dataToLoad.length)
{
ele.appendChild(document.createTextNode(dataToLoad[pos]));
pos++;
}
}
</script>
<body onkeyup="continueData()"><div id="mydata"></div></body></html>
everytime a key is released the next data field is appended
For easier implementation of event handling I recommend you to use a library such as Prototype or Jquery (Note that both links take you to their respective Event handling documentation.
In order to use them you have to keep in mind 3 things:
What DOM element you want to observe
What Event you want to capture
What action will the event trigger
This three points are mutually inclusive, meaning you need to take care of the 3 when writing the code.
So having this in mind, using Prototype, you could do this:
Event.observe($('id_of_the_element_to_observe'), 'keypress', function(ev) {
// the argument ev is the event object that has some useful information such
// as which keycode was pressed.
code_to_run;
});
Here is the code of a more useful example, a CharacterCounter (such as the one found in Twitter, but surely a lot less reliable ;) ):
var CharacterCounter = Class.create({
initialize: function(input, counter, max_chars) {
this.input = input;
this.counter = counter;
this.max_chars = max_chars;
Event.observe(this.input, 'keypress', this.keyPressHandler.bind(this));
Event.observe(this.input, 'keyup', this.keyUpHandler.bind(this));
},
keyUpHandler: function() {
words_left = this.max_chars - $F(this.input).length;
this.counter.innerHTML = words_left;
},
keyPressHandler: function(e) {
words_left = this.max_chars - $F(this.input).length;
if (words_left <= 0 && this.allowedChars(e.keyCode)) {
e.stop();
}
},
allowedChars: function(keycode) {
// 8: backspace, 37-40: arrow keys, 46: delete
allowed_keycodes = [ 8, 37, 38, 39, 40, 46 ];
if (allowed_keycodes.include(keycode)) {
return false;
}
return true
}
});
Any good browser will crash when it encounters a script that runs too long. This is to prevent malicious websites from locking up the client application.
You cannot have a infinite loop in javascript. Instead, attach an event listener to the window and point do your processing in the handler (think of it as interrupts instead of polling).
Example:
function addEventSimple(obj,evt,fn) {
if (obj.addEventListener)
obj.addEventListener(evt,fn,false);
else if (obj.attachEvent)
obj.attachEvent('on'+evt,fn);
} // method pulled from quirksmode.org for cross-browser compatibility
addEventSimple(window, "keydown", function(e) {
// check keys
});
document.onkeydown = function(e) {
//do what you need to do
}
That's all it takes in javascript. You don't need to loop to wait for the event to happen, whenever the event occurs that function will be called, which in turn can call other functions, do whatever needs to be be done. Think of it as that instead of you having to wait for the event your looking for to happen, the event your looking for will let you know when it happens.
you could attach an event listener to the window object like this
window.captureEvents(Event.KEYPRESS);
window.onkeypress = output;
function output(event) {
alert("you pressed" + event.which);
}
Check out the YUI key listener
http://developer.yahoo.com/yui/docs/YAHOO.util.KeyListener.html
using the key listener, YUI takes care of capturing any events. IN javascript, there will almost never be an instance where you must wait in a while loop for something to happen.
If you need examples of how event handling works, check out these pages.
http://developer.yahoo.com/yui/examples/event/eventsimple.html