initCustomEvent pass data for method doesn't work anymore - javascript

I wrote a firefox extension and for interation data between privilege and non-privilege pages I use this snipped code
//Listen for the event
window.addEventListener("MyEvent", function(evt) {
console.log(evt.detail);
}, false);
//Dispatch an event
var evt = document.createEvent("CustomEvent");
evt.initCustomEvent("MyEvent", true, true, {
name : 'activate',
method : function() {
//...
}
});
window.dispatchEvent(evt);
and everything go well after I update my FireFox to version 32.0.1, at this time my FireFox doesn't work and I try to find the error and discover that the method I passed to MyEvent always null. Why?
Is it possible that in the new version of FireFox I couldn't pass function any more or I should do something newer for solve my problem?

You probably have to use __exposedProps__.
Like
var detail = {
name: "activate",
method: function(){},
__exposedProps__: {method: "r"}
};
Needless to say that, unless you are absolutely sure that you know what you 're doing, this is a security risk.

Are you sure things used to work before?
You need to set the 4th argument of addEventListener to true. Argument is called wantsUntrusted.
MDN :: addEventListener
Also see this topic here: How to listen to custom events on all windows, bubbling issue?
So try this:
//Listen for the event
window.addEventListener("MyEvent", function(evt) {
console.log(evt.detail);
}, false, true);
//Dispatch an event
var evt = document.createEvent("CustomEvent");
evt.initCustomEvent("MyEvent", true, true, {
name : 'activate',
method : function() {
//...
}
});
window.dispatchEvent(evt);

Related

Call change event of an input programatically [duplicate]

How do I programmatically force an onchange event on an input?
I've tried something like this:
var code = ele.getAttribute('onchange');
eval(code);
But my end goal is to fire any listener functions, and that doesn't seem to work. Neither does just updating the 'value' attribute.
Create an Event object and pass it to the dispatchEvent method of the element:
var element = document.getElementById('just_an_example');
var event = new Event('change');
element.dispatchEvent(event);
This will trigger event listeners regardless of whether they were registered by calling the addEventListener method or by setting the onchange property of the element.
By default, events created and dispatched like this don't propagate (bubble) up the DOM tree like events normally do.
If you want the event to bubble, you need to pass a second argument to the Event constructor:
var event = new Event('change', { bubbles: true });
Information about browser compability:
dispatchEvent()
Event()
In jQuery I mostly use:
$("#element").trigger("change");
ugh don't use eval for anything. Well, there are certain things, but they're extremely rare.
Rather, you would do this:
document.getElementById("test").onchange()
Look here for more options:
http://jehiah.cz/archive/firing-javascript-events-properly
For some reason ele.onchange() is throwing a "method not found" expception for me in IE on my page, so I ended up using this function from the link Kolten provided and calling fireEvent(ele, 'change'), which worked:
function fireEvent(element,event){
if (document.createEventObject){
// dispatch for IE
var evt = document.createEventObject();
return element.fireEvent('on'+event,evt)
}
else{
// dispatch for firefox + others
var evt = document.createEvent("HTMLEvents");
evt.initEvent(event, true, true ); // event type,bubbling,cancelable
return !element.dispatchEvent(evt);
}
}
I did however, create a test page that confirmed calling should onchange() work:
<input id="test1" name="test1" value="Hello" onchange="alert(this.value);"/>
<input type="button" onclick="document.getElementById('test1').onchange();" value="Say Hello"/>
Edit: The reason ele.onchange() didn't work was because I hadn't actually declared anything for the onchange event. But the fireEvent still works.
Taken from the bottom of QUnit
function triggerEvent( elem, type, event ) {
if ( $.browser.mozilla || $.browser.opera ) {
event = document.createEvent("MouseEvents");
event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
0, 0, 0, 0, 0, false, false, false, false, 0, null);
elem.dispatchEvent( event );
} else if ( $.browser.msie ) {
elem.fireEvent("on"+type);
}
}
You can, of course, replace the $.browser stuff to your own browser detection methods to make it jQuery independent.
To use this function:
var event;
triggerEvent(ele, "change", event);
This will basically fire the real DOM event as if something had actually changed.
This is the most correct answer for IE and Chrome::
var element = document.getElementById('xxxx');
var evt = document.createEvent('HTMLEvents');
evt.initEvent('change', false, true);
element.dispatchEvent(evt);
If you add all your events with this snippet of code:
//put this somewhere in your JavaScript:
HTMLElement.prototype.addEvent = function(event, callback){
if(!this.events)this.events = {};
if(!this.events[event]){
this.events[event] = [];
var element = this;
this['on'+event] = function(e){
var events = element.events[event];
for(var i=0;i<events.length;i++){
events[i](e||event);
}
}
}
this.events[event].push(callback);
}
//use like this:
element.addEvent('change', function(e){...});
then you can just use element.on<EVENTNAME>() where <EVENTNAME> is the name of your event, and that will call all events with <EVENTNAME>
The change event in an input element is triggered directly only by the user. To trigger the change event programmatically we need to dispatch the change event.
The question is Where and How?
"Where" we want the change event to be triggered exactly at the moment after a bunch of codes is executed, and "How" is in the form of the following syntax:
const myInput = document.getElementById("myInputId");
function myFunc() {
//some codes
myInput.dispatchEvent(new Event("change"));
}
In this way, we created the change event programmatically by using the Event constructor and dispatched it by the dispatchEvent() method. So whenever myFunc() method is invoked, after the //some codes are executed, our synthetic change event is immediately triggered on the desired input element.‍
Important result: Here, the change event is triggered by executing the //some codes in myFunc() instead of changing the input value by the user (default mode).
if you're using jQuery you would have:
$('#elementId').change(function() { alert('Do Stuff'); });
or MS AJAX:
$addHandler($get('elementId'), 'change', function(){ alert('Do Stuff'); });
Or in the raw HTML of the element:
<input type="text" onchange="alert('Do Stuff');" id="myElement" />
After re-reading the question I think I miss-read what was to be done. I've never found a way to update a DOM element in a manner which will force a change event, what you're best doing is having a separate event handler method, like this:
$addHandler($get('elementId'), 'change', elementChanged);
function elementChanged(){
alert('Do Stuff!');
}
function editElement(){
var el = $get('elementId');
el.value = 'something new';
elementChanged();
}
Since you're already writing a JavaScript method which will do the changing it's only 1 additional line to call.
Or, if you are using the Microsoft AJAX framework you can access all the event handlers via:
$get('elementId')._events
It'd allow you to do some reflection-style workings to find the right event handler(s) to fire.
Using JQuery you can do the following:
// for the element which uses ID
$("#id").trigger("change");
// for the element which uses class name
$(".class_name").trigger("change");
For triggering any event in Javascript.
document.getElementById("yourid").addEventListener("change", function({
//your code here
})

How to simulate keypress with Javascript in Chrome

I have found a lot of information on this topic, but none of them seem to work (anymore).
What I want to do is to simulate key(down/press/up) events in Chrome 59(I really don't care about other browser). Simulating the Event itself is not the problem, but the problem is that I have not found a solution that is backwards compatible and contains the charCode/keyCode values. If it were up to me, I would update the code of the other application to check for key/code, but unfortunately it is not up to me.
What I have tried so far:
var evt = new KeyboardEvent(type, {code: options.charCode, key: options.keyCode, keyCode: options.keyCode, charCode: options.keyCode, which: options.which});
element.dispatchEvent(evt);
According to https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/KeyboardEvent this should work and create an event with the keyCode/charCode/which set, but it does not work:
My code (I have tried with and without quotes and with characters instead of numbers):
new KeyboardEvent("keypress", {code: 123, key: 123, keyCode: 123, charCode: 123, which: 123});
Output:
KeyboardEvent {isTrusted: false, key: "123", code: "123", location: 0, ctrlKey: false…}
altKey:false
bubbles:false
cancelBubble:false
cancelable:false
charCode:0
code:"123"
composed:false
ctrlKey:false
currentTarget:null
defaultPrevented:false
detail:0
eventPhase:0
isComposing:false
isTrusted:false
key:"123"
keyCode:0
location:0
metaKey:false
path:Array(0)
repeat:false
returnValue:true
shiftKey:false
sourceCapabilities:null
srcElement:null
target:null
timeStamp:2469092.6000000006
type:"keypress"
view:null
which:0
__proto__:KeyboardEvent
I then had a look at the specification and noticed that the keyCode/charCode/which property are not there any more, which leads me to believe that it has been removed from the standard and it should not work like this any more: https://w3c.github.io/uievents/#keyboardevent
As this is clearly not working, I started to look into the deprecated function initKeyboardEvent and tried this:
var evt = document.createEvent("KeyboardEvent");
//Chrome hack
Object.defineProperty(evt, 'keyCode', {
get : function(){
return this.keyCodeVal;
}
});
Object.defineProperty(evt, 'which', {
get : function(){
return this.keyCodeVal
}
});
Object.defineProperty(evt, 'charCode', {
get : function(){
return this.charCodeVal
}
});
//initKeyBoardEvent seems to have different parameters in chrome according to MDN KeyboardEvent(sorry, can't post more than 2 links), but that did not work either
evt.initKeyboardEvent("keypress",
true,//bubbles
true,//cancelable
window,
false,//ctrlKey,
false,//altKey,
false,//shiftKey,
false,//metaKey,
123,//keyCode,
123//charCode
);
evt.charCodeVal = 123;
evt.keyCodeVal = 123;
So this already seemed promising, but when i dispatched the event, this is the event that I can see in the handler:
KeyboardEvent
altKey:false
bubbles:true
cancelBubble:false
cancelable:true
charCode:0
code:""
composed:false
ctrlKey:false
currentTarget:input#iceform:username.iceInpTxt.bookLoginTextbox
defaultPrevented:false
detail:0
eventPhase:2
isTrusted:false
key:""
keyCode:0
location:0
metaKey:true
path:Array[16]
repeat:false
returnValue:true
shiftKey:true
sourceCapabilities:null
srcElement:input#iceform:username.iceInpTxt.bookLoginTextbox
target:input#iceform:username.iceInpTxt.bookLoginTextbox
timeStamp:9932.905000000002
type:"keypress"
view:Window
which:0
__proto__:KeyboardEvent
This is when I finally gave up and decided to ask for help. Is there any way I can properly simulate those events in a way that it is also backwards compatible?
PLEASE DO NOT SUGGEST JQUERY OR SIMILIAR THINGS
OK i finally figured out the problem. The code itself is actually OK(the one with the deprecated initKeyboardEvent).
The problem is, that i was executing this in a contentscript of a chrome extension. In this case all the properties of the event get reset to their default values and THEN the event is raised. I am now adding a script to the page that contains exactly the same code and it works just fine.

Pass an Event to an iframe from the parent window? ( Javascript )

Before starting this question, i have to say I really searched everywhere to find the answer but nothing found. Also tried manythings like dispatchevent, postmessage, ... but nothing worked.
Here is the case.
I have a main windows, where I have 4 simple buttons, like downarrow, uparrow, left and right arrow. I want to create a simulation of events pass to the iframe which is in this main window.
In that iframe is a page loaded where is an Eventhandler and react on the arrows.
I tried following but did not worked
var event = document.createEvent('KeyboardEvent'); // create a key event define the event
event.initKeyboardEvent("keypress", // typeArg,
true, // canBubbleArg,
true, // cancelableArg,
null, // viewArg, Specifies UIEvent.view. This value may be null.
false, // ctrlKeyArg,
false, // altKeyArg,
false, // shiftKeyArg,
false, // metaKeyArg,
39, // keyCodeArg (39 is the right arrow key ),
0); // charCodeArg);
document.getElementById('vid').dispatchEvent(event);
Is there anybody who has an idea how I can solve this issue?
Use postMessage. It works perfectly.
document.getElementById('vid').contentWindow.postMessage(event);
Finally I have sorted out the issue. I have used parent.document on my iframe to catch the events from the parnet side and create them again on iframe and it works great!
you want something like this:
var iframe = document.getElementById('something');
var iframeEvent = new Event('iframe-keypress');
document.addEventListener('keypress', function (e) {
iframe.dispatchEvent(iframeEvent);
});
iframe.addEventListener('iframe-keypress', function (e) {
console.log(e);
});
listen for the event on the document then pass down a custom event to the iframe.
jsfiddle - http://jsfiddle.net/rfkqe64j/
This works, but with jQuery.
window.addEventListener("keydown", (evt) => {
const {type, key} = evt;
parent.$("body").trigger(parent.$.Event(type, {key}));
})
Interestingly, parent.$.Event(evt) directly doesn't work.
I think this jquery forum thread should help
https://forum.jquery.com/topic/how-to-pass-mouse-events-to-an-iframe

Javascript - Dispatch built-in events [duplicate]

Does anybody know of a method to trigger an event in Prototype, as you can with jQuery's trigger function?
I have bound an event listener using the observe method, but I would also like to be able to fire the event programatically.
event.simulate.js fits your needs.
I've used this several times and it works like a charm. It allows you to manually trigger native events, such as click or hover like so:
$('foo').simulate('click');
The great thing about this is that all attached event handlers will still be executed, just as if you would have clicked the element yourself.
For custom events you can use the standard prototype method Event.fire().
I don't think there is one built in to Prototype, but you can use this (not tested but should at least get you in the right direction):
Element.prototype.triggerEvent = function(eventName)
{
if (document.createEvent)
{
var evt = document.createEvent('HTMLEvents');
evt.initEvent(eventName, true, true);
return this.dispatchEvent(evt);
}
if (this.fireEvent)
return this.fireEvent('on' + eventName);
}
$('foo').triggerEvent('mouseover');
I found this post helpful... http://jehiah.cz/archive/firing-javascript-events-properly
It covers a way to fire events in both Firefox and IE.
function fireEvent(element,event){
if (document.createEventObject){
// dispatch for IE
var evt = document.createEventObject();
return element.fireEvent('on'+event,evt)
}
else{
// dispatch for firefox + others
var evt = document.createEvent("HTMLEvents");
evt.initEvent(event, true, true ); // event type,bubbling,cancelable
return !element.dispatchEvent(evt);
}
}
The answers here are true for "Normal" events, that is events which are defined by the User Agent, but for custom events you should use prototype's "fire" method. e.g.
$('something').observe('my:custom', function() { alert('Custom'); });
.
.
$('something').fire('my:custom'); // This will cause the alert to display

How do I programmatically force an onchange event on an input?

How do I programmatically force an onchange event on an input?
I've tried something like this:
var code = ele.getAttribute('onchange');
eval(code);
But my end goal is to fire any listener functions, and that doesn't seem to work. Neither does just updating the 'value' attribute.
Create an Event object and pass it to the dispatchEvent method of the element:
var element = document.getElementById('just_an_example');
var event = new Event('change');
element.dispatchEvent(event);
This will trigger event listeners regardless of whether they were registered by calling the addEventListener method or by setting the onchange property of the element.
By default, events created and dispatched like this don't propagate (bubble) up the DOM tree like events normally do.
If you want the event to bubble, you need to pass a second argument to the Event constructor:
var event = new Event('change', { bubbles: true });
Information about browser compability:
dispatchEvent()
Event()
In jQuery I mostly use:
$("#element").trigger("change");
ugh don't use eval for anything. Well, there are certain things, but they're extremely rare.
Rather, you would do this:
document.getElementById("test").onchange()
Look here for more options:
http://jehiah.cz/archive/firing-javascript-events-properly
For some reason ele.onchange() is throwing a "method not found" expception for me in IE on my page, so I ended up using this function from the link Kolten provided and calling fireEvent(ele, 'change'), which worked:
function fireEvent(element,event){
if (document.createEventObject){
// dispatch for IE
var evt = document.createEventObject();
return element.fireEvent('on'+event,evt)
}
else{
// dispatch for firefox + others
var evt = document.createEvent("HTMLEvents");
evt.initEvent(event, true, true ); // event type,bubbling,cancelable
return !element.dispatchEvent(evt);
}
}
I did however, create a test page that confirmed calling should onchange() work:
<input id="test1" name="test1" value="Hello" onchange="alert(this.value);"/>
<input type="button" onclick="document.getElementById('test1').onchange();" value="Say Hello"/>
Edit: The reason ele.onchange() didn't work was because I hadn't actually declared anything for the onchange event. But the fireEvent still works.
Taken from the bottom of QUnit
function triggerEvent( elem, type, event ) {
if ( $.browser.mozilla || $.browser.opera ) {
event = document.createEvent("MouseEvents");
event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
0, 0, 0, 0, 0, false, false, false, false, 0, null);
elem.dispatchEvent( event );
} else if ( $.browser.msie ) {
elem.fireEvent("on"+type);
}
}
You can, of course, replace the $.browser stuff to your own browser detection methods to make it jQuery independent.
To use this function:
var event;
triggerEvent(ele, "change", event);
This will basically fire the real DOM event as if something had actually changed.
This is the most correct answer for IE and Chrome::
var element = document.getElementById('xxxx');
var evt = document.createEvent('HTMLEvents');
evt.initEvent('change', false, true);
element.dispatchEvent(evt);
If you add all your events with this snippet of code:
//put this somewhere in your JavaScript:
HTMLElement.prototype.addEvent = function(event, callback){
if(!this.events)this.events = {};
if(!this.events[event]){
this.events[event] = [];
var element = this;
this['on'+event] = function(e){
var events = element.events[event];
for(var i=0;i<events.length;i++){
events[i](e||event);
}
}
}
this.events[event].push(callback);
}
//use like this:
element.addEvent('change', function(e){...});
then you can just use element.on<EVENTNAME>() where <EVENTNAME> is the name of your event, and that will call all events with <EVENTNAME>
The change event in an input element is triggered directly only by the user. To trigger the change event programmatically we need to dispatch the change event.
The question is Where and How?
"Where" we want the change event to be triggered exactly at the moment after a bunch of codes is executed, and "How" is in the form of the following syntax:
const myInput = document.getElementById("myInputId");
function myFunc() {
//some codes
myInput.dispatchEvent(new Event("change"));
}
In this way, we created the change event programmatically by using the Event constructor and dispatched it by the dispatchEvent() method. So whenever myFunc() method is invoked, after the //some codes are executed, our synthetic change event is immediately triggered on the desired input element.‍
Important result: Here, the change event is triggered by executing the //some codes in myFunc() instead of changing the input value by the user (default mode).
if you're using jQuery you would have:
$('#elementId').change(function() { alert('Do Stuff'); });
or MS AJAX:
$addHandler($get('elementId'), 'change', function(){ alert('Do Stuff'); });
Or in the raw HTML of the element:
<input type="text" onchange="alert('Do Stuff');" id="myElement" />
After re-reading the question I think I miss-read what was to be done. I've never found a way to update a DOM element in a manner which will force a change event, what you're best doing is having a separate event handler method, like this:
$addHandler($get('elementId'), 'change', elementChanged);
function elementChanged(){
alert('Do Stuff!');
}
function editElement(){
var el = $get('elementId');
el.value = 'something new';
elementChanged();
}
Since you're already writing a JavaScript method which will do the changing it's only 1 additional line to call.
Or, if you are using the Microsoft AJAX framework you can access all the event handlers via:
$get('elementId')._events
It'd allow you to do some reflection-style workings to find the right event handler(s) to fire.
Using JQuery you can do the following:
// for the element which uses ID
$("#id").trigger("change");
// for the element which uses class name
$(".class_name").trigger("change");
For triggering any event in Javascript.
document.getElementById("yourid").addEventListener("change", function({
//your code here
})

Categories