When running my javascript program on IE, it loops forever.
It works on Firefox, Safari and Chrome.
There is a similar question in Stackoverflow, but here the suggestion was to remove the functionname of the embedded function. I don't have a name on it.
Here an excerpt of the function to set up an asynchronous httprequest. 'rq' is the request object, with open() already called, but not send().
I am trying to set a response function. I am using the 'self' var so that the function will have the same this pointer (also member of same object as calling function).
var self = this;
rq.onreadystatechange = function()
{
self._reqStateChange(rq); // *
} // *
this._req[sl]=rq;
rq.send(null);
return true;
IE endless loops the two lines marked with // *, also the first return in the embedded function:
this._reqStateChange = function(rq)
{
if( (!rq) || rq.readyState!=4 )
return; // exits here every time.
IE 9.0, using built-in debugger.
no jQuery or any other libs inplace.
I have no idea. thanks for helping. I would like to understand the logic here...
Note:
I just built a little script to see if the self-construct is wrong. That works. Seems to be related to the onreadystatechange function. Everytime it exits, it is immediately called again.
This code does NOT lock up in IE:
someObject = function()
{
this.callback = function(){}
this.funcCallsCallback = function()
{
// call the callback
this.callback();
};
}
muell = new function()
{
this.value = 42;
this.test = function()
{
var rq = new someObject();
var self = this;
rq.callback = function()
{
self.endFunc();
}
// now:
rq.funcCallsCallback();
};
this.endFunc = function()
{
alert("called! value="+this.value.toString());
};
}
muell.test();
Related
I'm writing a test where two browsers need to interact. The problem with simply forking the browser is that my page objects still reference the old browser. I didn't want to rewrite all of my PO's to take the browser as a parameter so I tried the first solution found in the link below where they overwrite the global variables with the new browser's version :
Multiple browsers and the Page Object pattern
However, changing the global variables doesn't seem to work as all the subsequent page object functions that I call are performed against the original browser instance. I have tried logging the window handler before and after the switch and they are indeed different which only baffles me further. Here's some of the code.
spec:
var MultiBrowserFunctions = require('../common/multiBrowserFunctions.js');
var HomePage = require('../home/home.po.js');
describe('blah', function(){
it('blah', function(){
MultiBrowserFunctions.openNewBrowser(true);
HomePage.initializePage();
});
});
MultiBrowserFunctions:
(function() {
var browserRegistry = [];
module.exports = {
openNewBrowser: function(isSameUrl){
if(typeof browserRegistry[0] == 'undefined'){
browserRegistry[0] = {
browser: browser,
element: element,
$: $,
$$: $$,
}
}
var tmp = browser.forkNewDriverInstance(isSameUrl);
var id = browserRegistry.length;
browserRegistry[id] = {
browser: tmp,
element: tmp.element,
$: tmp.$,
$$: tmp.$$,
}
switchToBrowserContext(id);
return id;
},
resetBrowserInstance : function(){
browserRegistry.splice(1,browserRegistry.length);
switchToBrowserContext(0);
}
}
function switchToBrowserContext(id){
console.log('---------------------------switching to browser: ' + id);
browser=browserRegistry[id].browser;
element=browserRegistry[id].element;
$=browserRegistry[id].$;
$$=browserRegistry[id].$$;
}
}());
My questions are:
(1) why doesn't this work?
(2) Is there some other solution that doesn't involve rewriting all of my po's?
What you can do is, save the browsers in different variables and then switch between them by overriding the globals via a utility or something.
describe('Switching browsers back and forth', function () {
var browserA, browserB;
it('Browser Switch', function () {
var browsers = {
a : browser,
b : browser.forkNewDriverInstance(true)
};
browserA = browsers.a;
browserB = browsers.b;
var browserAndElement = switchBrowser(browserB);
browser = browserAndElement.browser;
element = browserAndElement.element;
//do your stuff
var browserAndElement = switchBrowser(browserA);
browser = browserAndElement.browser;
element = browserAndElement.element;
//do your stuff
});
});
The switchBrowser() can look like following:
this.switchBrowser = function (currentBrowser) {
browser = currentBrowser;
element = currentBrowser.element;
return {
browser : browser,
element : element
}
}
In this way you don't have to rewrite your POs to take in the new globals.
Hope it helps!
Cheers
Is there any difference between
foo.bind(this)(arg1, arg2);
and
foo.bind(this, arg1, arg2)();
Both codes works fine on many sites, but in one site second example gives error due to the fact that arg2 is undefined.
UPDATE for more complex example
// Create an immediately invoked functional expression to wrap our code
(function () {
// Define our constructor
this.Widget = function (options) {
this.widgetWrap = null;
this.widgetHeaderTitle = null;
//Code removed for clarity
// Establish our default settings
this.options = extend({
formHeaders: ['Заголовок 1', 'Заголовок 2'],
}, options);
this.init();
};
// Public Methods
Widget.prototype.init = function () {
//Code removed for clarity
contentAnimation.bind(this)(this.widgetHeaderTitle, this.options.formHeaders);
//Not working on http://healthyclinic.ru/ but working on any other site
//this.options.formHeaders - Array with several elements. NOT NULL and NOT UNDEFINED
//contentAnimation.bind(this, this.widgetHeaderTitle, this.options.formHeaders)();
//Code removed for clarity
};
// Private Methods
function contentAnimation(el, arr) {
//In this place with second example 'arr' already UNDEFINED
var self = this;
var current = 1;
self.titleAnimationInterval = setInterval(function () {
el.style.opacity = 0;
setTimeout(function () {
el.textContent = arr[current];
el.style.opacity = 1;
current = ++current % arr.length;
}, self.options.transitionDuration);
}, 4000);
}
//Code removed for clarity
}());
In the code above, you can see the code in my library. The code works fine on many sites and on the local machine, with the exception of only one site where the second argument becomes undefined.
No, there is no difference in functionality between the two (that foo would be able to detect), given that foo is a function and .bind() is the built-in function method.
Here is my JS simple script:
var Chat = function() {
console.log("init");
this.debug = function (txt) {
console.log(txt);
}
document.getElementById('shoutBoxInput').addEventListener("keypress", keyPressedFunction, false);
this.keyPressedFunction = function(e){
console.log("keyPressed");
}
this.sendText = function() {
var texte = document.getElementById('shoutBoxInput').value;
if (texte=="") return;
document.getElementById('shoutBoxInput').value =""
this.debug("sendTexte:"+texte);
}
this.receiveText = function(username, texte) {
}
}
var chat = new Chat();
My problem comes from:
document.getElementById('shoutBoxInput').addEventListener("keypress", keyPressedFunction, false);
this.keyPressedFunction = function(e){
Error Uncaught ReferenceError: keyPressedFunction is not defined
If I use:
document.getElementById('shoutBoxInput').addEventListener("keydown", this.keyPressedFunction, true);
then keyPressedFunction is never called.
Fiddle: http://jsfiddle.net/ghLfhb6z/
Let's start with the problem, and then move to what's dangerous about your code.
The problem is that when you call addEventListener, this.keyPressedEvent doesn't yet exist:
// this.keyPressedFunction doesn't exist...so you are registering a 'keypress'
// event to undefined.
document.getElementById('shoutBoxInput').addEventListener("keypress",
keyPressedFunction, false);
// now you define this.keyPressedFunction
this.keyPressedFunction = function(e){
console.log("keyPressed");
}
// so this is where you should be attaching it to the event
You may be thinking about JavaScript's hosting mechanism, and thinking "ah, the this.keyPressedFunction definition is being hoisted to the top of this function, so it's available for assigment." But hoisting only applies to variable and function definitions; what you're doing is assigning an anonymous function to a member property, so hoisting does not apply.
Now on to the dangerous:
When you use a method (a function property of an object) for a callback, the meaning of this is lost when that callback is invoked. (I know you aren't currently using this in your callback, but you probably will eventually!) In other words, when a key is pressed, and keyPressedFunction is called, the value of this won't be what you expect. The upshot of this is you have to be very careful assigning methods to callbacks or events. If you want to do it, you'll have to use Function.prototype.bind. Here's your code re-written in the correct order, and using bind:
this.keyPressedFunction = function(e){
console.log("keyPressed");
}
document.getElementById('shoutBoxInput').addEventListener("keypress",
this.keyPressedFunction.bind(this), false);
place your function before you use its referenc...then use this.keyPressedFunction...then is 'keypress' a valid native js event ?
http://jsfiddle.net/ghLfhb6z/4/
yes there was the errors I told, in fact most important is to place your event handlers at the end, check the right event, and use this if the function is on this :
var Chat = function() {
console.log("init");
this.debug = function (txt) {
console.log(txt);
}
this.keyPressedFunction = function(e){
console.log("keyPressed");
}
this.sendText = function() {
var texte = document.getElementById('shoutBoxInput').value;
if (texte=="") return;
document.getElementById('shoutBoxInput').value =""
this.debug("sendTexte:"+texte);
}
this.receiveText = function(username, texte) {
}
// place this at the end
document.getElementById('shoutBoxInput').addEventListener("keydown", this.keyPressedFunction, false);
}
var chat = new Chat();
#dmidz has provided a correct answer that will solve your problem, but if your keyPressedFunction only needs to be referred to code inside your Chat() module, then you don't need to make them properties of this (Chat):
var Chat = function() {
console.log("init");
function debug(txt) {
console.log(txt);
}
function keyPressedFunction(e){
console.log("keyPressed");
}
this.sendText = function() {
var texte = document.getElementById('shoutBoxInput').value;
if (texte=="") return;
document.getElementById('shoutBoxInput').value ="";
debug("sendTexte:"+texte);
}
this.receiveText = function(username, texte) {
}
document.getElementById('shoutBoxInput')
.addEventListener("keypress", keyPressedFunction, false);
}
If you do this, then you don't necessarily have to declare your functions before you use them, but it would be good style to do so nonetheless.
Here is a simplified snippet from some code I wrote for managing tablet gestures on canvas elements
first a function that accepts an element and a dictionary of callbacks and register the events plus adding other features like 'hold' gestures:
function registerStageGestures(stage, callbacks, recieverArg) {
stage.inhold = false;
stage.timer = null;
var touchduration = 1000;
var reciever = recieverArg || window;
stage.onLongTouch = function(e) {
if (stage.timer) clearTimeout(stage.timer);
stage.inhold = true;
if (callbacks.touchholdstart) callbacks.touchholdstart.call(reciever, e);
};
stage.getContent().addEventListener('touchstart', function(e) {
e.preventDefault();
calcTouchEventData(e);
stage.timer = setTimeout(function() {
stage.onLongTouch(e);
}, touchduration);
if (callbacks.touchstart) callbacks.touchholdstart.call(reciever, e);
});
stage.getContent().addEventListener('touchmove', function(e) {
e.preventDefault();
if (stage.timer) clearTimeout(stage.timer);
if (stage.inhold) {
if (callbacks.touchholdmove) callbacks.touchholdmove.call(reciever, e);
} else {
if (callbacks.touchmove) callbacks.touchmove.call(reciever, e);
}
});
stage.getContent().addEventListener('touchend', function(e) {
e.preventDefault();
if (stage.timer) clearTimeout(stage.timer);
if (stage.inhold) {
if (callbacks.touchholdend) callbacks.touchholdend.call(reciever, e);
} else {
if (callbacks.touchend) callbacks.touchend.call(reciever, e);
}
stage.inhold = false;
});
}
later I call registerStageGestures on a few elements (represented by 'View' objects) in the same page. Something like:
function View() {
var self=this;
..
function InitView() {
...
registerStageGestures(kineticStage, {
touchstart: function(e) {
// do something
},
touchmove: function(e) {
// do something
},
touchendunction(e) {
// do something
},
touchholdstart: function(e) {
// do something
},
touchholdmove: function(e) {
// do something
},
touchholdend: function(e) {
// do something
},
}, self);
Everything works fine, however I'm left wondering about two things in the implementation of registerStageGestures:
First, is it necessary to make inhold, timer and onLongTouch members of the stage ? or will closures make everything works well if they are local vars in registerStageGestures ?
Second, is it necessary to call the callbacks with '.call(receiver,' syntax ? I'm doing this to make sure the callback code will run in the context of the View but I'm not sure if it's needed ?
any input is much appreciated
Thanks!
First, is it necessary to make inhold, timer and onLongTouch members
of the stage ? or will closures make everything works well if they are
local vars in registerStageGestures ?
As far as registerStageGestures() is concerned, var inhold, var timer and function onLongTouch(e) {...}. would suffice. The mechanism by which an inner function has automatic access to its outer function's members is known as "closure". You would only need to set stage.inhold, stage.timer and stage.onLongTouch if some other piece of code needs access to these settings as properties of stage.
Second, is it necessary to call the callbacks with '.call(receiver,'
syntax ? I'm doing this to make sure the callback code will run in the
context of the View but I'm not sure if it's needed ?
Possibly, depending on how those callbacks are written. .call() and .apply() are sometimes used when calling functions that use this internally. In both cases, the first parameter passed defines the object to be interpreted as this. Thus, javascript gives you the means of defining general purpose methods with no a priori assumption about the object to which those methods will apply when called. Similarly, you can call a method of an object in such a way that it acts on another object.
EDIT:
For completeness, please note that even in the absence of this in a function, .apply() can be very useful as it allows multiple parameters to be specified as elements of a single array, eg the ubiquitous jQuery.when.apply(null, arrayOfPromises)...
There are some simple answers, here.
First, closure:
Closure basically says that whatever is defined inside of a function, has access to the rest of that function's contents.
And all of those contents are guaranteed to stay alive (out of the trash), until there are no more objects left, which ere created inside.
A simple test:
var testClosure = function () {
var name = "Bob",
recallName = function () { return name; };
return { getName : recallName };
};
var test = testClosure();
console.log(test.getName()); // Bob
So anything that was created inside can be accessed by any function which was also created inside (or created inside of a function created in a function[, ...], inside).
var closure_2x = function () {
var name = "Bob",
innerScope = function () {
console.log(name);
return function () {
console.log("Still " + name);
}
};
return innerScope;
};
var inner_func = closure_2x();
var even_deeper = inner_func(); // "Bob"
even_deeper(); // "Still Bob"
This applies not only to variables/objects/functions created inside, but also to function arguments passed inside.
The arguments have no access to the inner-workings(unless passed to methods/callbacks), but the inner-workings will remember the arguments.
So as long as your functions are being created in the same scope as your values (or a child-scope), there's access.
.call is trickier.
You know what it does (replaces this inside of the function with the object you pass it)...
...but why and when, in this case are harder.
var Person = function (name, age) {
this.age = age;
this.getAge = function () {
return this.age;
};
};
var bob = new Person("Bob", 32);
This looks pretty normal.
Honestly, this could look a lot like Java or C# with a couple of tweaks.
bob.getAge(); // 32
Works like Java or C#, too.
doSomething.then(bob.getAge);
? Buh ?
We've now passed Bob's method into a function, as a function, all by itself.
var doug = { age : 28 };
doug.getAge = bob.getAge;
Now we've given doug a reference to directly use bobs methid -- not a copy, but a pointer to the actual method.
doug.getAge(); // 28
Well, that's odd.
What about what came out of passing it in as a callback?
var test = bob.getAge;
test(); // undefined
The reason for this, is, as you said, about context...
But the specific reason is because this inside of a function in JS isn't pre-compiled, or stored...
this is worked out on the fly, every time the function is called.
If you call
obj.method();
this === obj;
If you call
a.b.c.d();
this === a.b.c;
If you call
var test = bob.getAge;
test();
...?
this is equal to window.
In "strict mode" this doesn't happen (you get errors really quickly).
test.call(bob); //32
Balance restored!
Mostly...
There are still a few catches.
var outerScope = function () {
console.log(this.age);
var inner = function () {
console.log("Still " + this.age);
};
inner();
};
outerScope.call(bob);
// "32"
// "Still undefined"
This makes sense, when you think about it...
We know that if a function figures out this at the moment it's called -- scope has nothing to do with it...
...and we didn't add inner to an object...
this.inner = inner;
this.inner();
would have worked just fine (but now you just messed with an external object)...
So inner saw this as window.
The solution would either be to use .call, or .apply, or to use function-scoping and/or closure
var person = this,
inner = function () { console.log(person.age); };
The rabbit hole goes deeper, but my phone is dying...
I'm a bit stuck on a problem which I can't solve, I performed investigation on internet and on this site, but I can't find the answer to my question.
So basically I have a javascript file, which I cannot modify, so I have another javascript file which should catch the method when it is called and override it.
Normally I know how it works and I already done the function overriding, but I don't know how to solve this issue.
I have a very big script, but I will show just a small piece of it:
Microsoft.Office.Server.Ajax.NavResizer.prototype = {
$6: null,
$7: null,
......
$20:function ($p0) {
if (this.$1E) {
$p0.preventDefault();
}
},
$21: function ($p0) {
var $0 = $p0.target;
this.$1F = ($0 === this.$A);
if (this.$1F || $0 === this.$B) {
this.$1E = $0;
this.$18 = $p0.clientX;
this.$19 = $p0.clientY;
Sys.UI.DomEvent.removeHandler(this.$1E, 'mousedown', this.$12);
var $1 = document.body; Sys.UI.DomEvent.addHandler($1, 'mouseup', this.$13);
Sys.UI.DomEvent.addHandler($1, 'mousemove', this.$14);
$1.style.cursor = (this.$1F) ? 'e-resize' : 'n-resize';
this.$1A = this.get_$42();
this.$1B = this.get_$43();
$1.focus();
Sys.UI.DomEvent.addHandler($1, 'selectstart', this.$15);
$p0.preventDefault();
}
},
$22: function ($p0) {
this.$34($p0);
var $0 = document.body;
Sys.UI.DomEvent.removeHandler($0, 'mouseup', this.$13);
Sys.UI.DomEvent.removeHandler($0, 'mousemove', this.$14);
Sys.UI.DomEvent.addHandler($0, 'selectstart', this.$15);
$0.style.cursor = 'default';
Sys.UI.DomEvent.addHandler(this.$1E, 'mousedown', this.$12);
this.$1E = null;
},
$23: function ($p0) {
this.$34($p0);
},
$24: function ($p0) {
this.$26();
},
....
Basically this is the part of the script: so lets say I want to override function: $22: function ($p0) in the script in another javascript file, how do i do that?
I would appreciate any help.
A small update, some good examples were provided but they are not working.
The environment where i run this sript is SharePoint, normally when I did override I used this method:
var oldFixRibbonAndWorkspaceDimensions = window.FixRibbonAndWorkspaceDimensions;
window.FixRibbonAndWorkspaceDimensions = function () {
this.MyFixRibbonAndWorkspaceDimensions();
};
function MyFixRibbonAndWorkspaceDimensions(){...}
And it didn't matter when i load the script as this function was only called when the default function was called not before not after. Just in the same time. But with the example which were provided here, the function is trying to execute on the document.ready()
You want to permanently override it? Just do this:
Microsoft.Office.Server.Ajax.NavResizer.prototype.$22 = function($p0) {
// your code.
};
As long as your script is executed after the original is defined, you're good.
Old post.. but this works for me:
ExecuteOrDelayUntilScriptLoaded(overrideNavResizer, "NavResizer.js");
function overrideNavResizer(){
Microsoft.Office.Server.Ajax.NavResizer.prototype.$22 = function($p0) {
// your code.
};
}
In your new script:
Microsoft.Office.Server.Ajax.NavResizer.prototype.$22 = function () {//your function code}
Assuming you have access to the prototype object (it's in global scope) and your scripts runs after it, that is easy:
var proto = Microsoft.Office.Server.Ajax.NavResizer.prototype,
oldMethod = proto.$22;
proto.$22 = function newMethod(args, …){
…
};