Monkey Patch jquery function contents - javascript

Thanks in advance for the help.
I am trying to monkeypatch an existing javascript function so that one of its lines point to a new location. It would be easy to just redefine the function, except that it is rendered from server side code that has dynamic contents in it.
function GoPrint() {
$.cookie('edit_child','on',{expires:28,path:'/'}); //Dynamically created (edit child could be off)
window.open('../../Common/Output/HTMLtoPDF.aspx','print'); //Always static, need to change this call.
}
In my example, the first line creating the cookie, is created dynamically server side, so the property could be set to off.
I need to the change the window.open to call a different page instead of the htmltopdf page.
Although nasty, I would like to just redefine the function with a replace on the HTMLtoPDF text to point to the new page.
I have started this below, but do not know how to get the existing contents of the function to change it.
function($){
var _oldPrint = $.fn.GoPrint;
$.fn.GoPrint = function(arg1,arg2){
return _oldPrint.call(this,'',);
};
})(jQuery);
Any suggestions?

One way to do it would be to call toString on the old function, sub the old URL out with the new one, and eval the result, but only after considering the security implications.
Purely security-wise, a safer way would be to monkey patch the window.open function inside the monkey patch of GoPrint.
function($) {
var _oldPrint = $.fn.GoPrint;
$.fn.GoPrint = function(arg1, arg2) {
var _oldopen = window.open;
window.open = function() {
_oldopen.call('YOUR_URL_HERE', 'print');
};
return _oldPrint.call(this);
window.open = _oldopen;
};
})(jQuery);

Related

Detect when a function is getting called in JavaScript

There are several elements on HTML page which triggers a js function HardCoded().
I cannot modify HardCoded() function.
I want to run some custom js code after the HardCoded() function is getting called. How can I do that? Is there any handlers for js functions?
I'm building a chrome extension that's why I cannot modify page source code.
I have access to JQuery.
One way is to find all elements who are calling HardCoded() and attach events to those elements but I would like to avoid this method.
You could do something like this:
var oldFn = HardCoded;
window.HardCoded = function(){
var res = oldFn.apply(this, arguments);
// New Code ....
return res;
}
What this does is to create a reference to the HardCoded function, redefine this function and then call the old implementation using the previously created reference.

creating a element in javascript with onclick function which passes $_session var

What I want in html code:
<a onclick="DeleteImage('javascript:this.id', <?=$_SESSION['UserID']?>)"></a>
which passes the var userid from $_session to the javascript function:
function DeleteImage(aid,userid){}
This worked when i didnt had to pass the $_session variable and only had this function
function DeleteImage(aid){}
Then i could create the a element in javascript like this:
cross = document.createElement('a');
cross.onclick = function() { DeleteImage(this.id) };
How can I create the a element so it generates the html code i want?
I want something like:
cross.onclick = function() { DeleteImage(this.id, "<?=$_SESSION['UserID']?>") };
which obviously does not work. Any help appreaciated :)
I think you should change the way you retrieve an information like $_SESSION['UserID']. An interesting option would be creating a data attribute, for example in the <html> tag itself:
<html data-user-id="<?=$_SESSION['UserID']?>">
Then all you have to do is to retrieve that value in the DeleteImage function itself:
function DeleteImage(aid) {
var userId = document.documentElement.getAttribute("data-user-id");
...
}
And you're done, you can call DeleteImage with the old way. (Note: you can also use document.documentElement.dataset.userId in Chrome, Firefox and Opera. There are partial polyfills for IE, but I guess they're not worth the effort in your case.)
You can even save some extra cycles retrieving the value at the beginning of the script and storing it in a scoped variable:
var userId = document.documentElement("data-user-id");
function DeleteImage(aid) {
...
}
Slightly off topic, may I suggest to using some more modern way to attach event listeners? And maybe considering some kind of event delegation?

Creating a JavaScript callback in an iframe

UPDATE: The back-end service was powered by an ASP.Net AJAX Web Service proxy.
1) The main page has two global objects, one for the back end connections (Svc) and another for handling the DOM (Main). It also dynamically loads documents into an iframe.
2) These iframes need to access services provided by Svc, and also supply a callback function.
3) The problem - passing a function created in the iframe to the parent frame, it's treated as an object not a function and cannot be invoked.
Can anyone provide a better solution than what I've got currently in the iframe:
var Main = parent.Main,
Svc = parent.Svc;
Svc.method(data, Main.createCallback(
function(response) {}
));
and in the parent frame:
Main.createCallback = function(func) {
return function() {
func.apply(func, arguments);
}
}
if you override the iFrame's function from the main, the main scope will then be used.
The inverse problem can be seen here, in your case, you just override the frame's function itself i.e:
document.getElementById('yourFrameID').contentWindow.targetFunctionInFrame = targetFunctionInMain;
Bonus: if you can modify the iFrame's code, I would suggest to:
In the frame:
make a placeholder function callbackParent() {}
add a call to this function into your iframe code, so that you just have to override the callbackParent from your main.
In the main:
make the function which should be invoked function doStuff() {}
override the function as described above document.getElementById('yourFrameID').contentWindow.callBackParent = doStuff;
I use iframes to modularize my app too.They are a kind of includes embedding all CSS, HTML and JS for a module.
My first attempts were by returning a function too, but then I found it quite hard for sharing scopes.
Now I make directly a reference to the main parent object in the iframe.
eg:
var Svc = parent.Svc, JSON = parent.JSON, $ = parent.$;
Svc.module1 = {
method1:function(arg){
...
},
...
}
The global var JSON and jQuery references are here to have them available inside the methods.
My guest is that Svc.method is making some checks to see if the callback has some criteria before calling it. This criteria might be that the callback function must created by the same framework (here it's ASP.Net). You have to find what that criteria is. if "Main.createCallback" works, it's because it's meeting that criteria.
Sorry but your all wrong... add this....
const event = new CustomEvent('MSGSent', { detail: "fff variable" });
Call it like this....use a global variable for detail... like an array []
window.dispatchEvent(event);
Now after the iframe loads add this code and you get an Object back in the main page....
iframe.onload = function() {
try {
iframe.contentWindow.addEventListener('MSGSent',function(e){
alert(e.detail);
});
} catch (error) {
}
};
The problem is ASP.Net AJAX Web Service proxies, which don't appear to support calling the web service from an iframe with an inline callback function.

"Decompile" Javascript function?

[1] Ok, I don't even know how to call this, to be honest. So let me get some semi-pseudo code, to show what I'm trying to do. I'm using jQuery to get an already existing script declared inside the page, inside a createDocument() element, from an AJAX call.
GM_xmlhttprequest({
...
load:function(r){
var doc = document_from_string(r.responseText);
script_content = $('body script:regex(html, local_xw_sig)', doc).html();
var scriptEl = document.createElement('script');
scriptEl.type = 'text/javascript';
scriptEl.innerHTML = script_content; // good till here
(function(sc){
eval(sc.innerHTML); // not exactly like this, but you get the idea, errors
alert('wont get here ' + local_xw_sig); // local_xw_sig is a global "var" inside the source
})(scriptEl);
}
});
So far so good, the script indeed contains the source from the entire script block. Now, inside this "script_content", there are auto executing functions, like $(document).ready(function(){...}) that, everything I "eval" the innerHTML, it executes this code, halting my encapsulated script. Like variables that doesn't exist, etc.
Removing certain parts of the script using regex isn't really an option... what I really wanted is to "walk" inside the function. like do a (completely fictional):
script = eval("function(){" + script_content + "};");
alert(script['local_xw_sig']); // a03ucc34095cw3495
Is there any way to 'disassemble' the function, and be able to reach the "var"s inside of it?
like this function:
function hello(){
var message = "hello";
}
alert(hello.message); // message = var inside the function
Is it possible at all? Or I will have to hack my way using regex? ;P
[2] also, is there any way I can access javascript inside a document created with "createDocument"?
Simply trying to access a local variable inside a function from outside of it is impossible due to scope. However, using closures you can absolutely accomplish this:
function hello(msg){
return function message(){
return msg;
}
}
alert(hello("yourMessage")()); // will alert "yourMessage"
Note exactly what's happening here. You are calling a function which returns a function, in which "yourMessage" is now defined inside its scope. Calling that inner closure the second time will yield that variable you set earlier.
If you are not familiar with closures in JS, I suggest you read this wonderful FAQ.
It's not possible that way. You can introspect object's properties (any function is an object), but not before you have created an instance with new operator.
Looking at your code sample, it seems that your approach is a bit messy – eval()'ing script blocks is something one should not do unless absolutely necessary (a situation I can't imagine).
In your example at
function hello(){
var message = "hello";
}
alert(hello.message); // message = var inside the function
you can in fact use hello.toString() to get the function source, like this:
alert(hello.toString().match(/var message = \"(.*)\";/));
You want to eval the script in global scope. Briefly it is,
// Evalulates a script in a global context
globalEval: function( data ) {
data = jQuery.trim( data );
if ( data ) {
if ( window.execScript )
window.execScript( data );
else if ( jQuery.browser.safari )
// safari doesn't provide a synchronous global eval
window.setTimeout( data, 0 );
else
eval.call( window, data );
}
}
Also check out Google's caja for secure external script evaluation.

Is it possible to destroy loaded JavaScript, including function & local variable?

I know. It is possible to dynamically load JavaScript and style sheet file into header of document. In the other hand, it is possible to remove script and style sheet tag from header of document. However, loaded JavaScript is still live in memory.
Is it possible to destroy loaded JavaScript from web browser memory? I think. It should be something like the following pseudo code.
// Scan all variables in loaded JavaScript file.
var loadedVariable = getLoadedVariable(JavaScriptFile);
for(var variable in loadedVariable)
{
variable = null;
}
// Do same thing with function.
Is it possible to create some JavaScript for doing like this?
Thanks,
PS. Now, you can use xLazyLoader and jQuery for dynamic loading content.
If the loaded script is assigned to a window property, for instance with the module pattern like so:
window.NiftyThing = (function() {
function doSomething() { ... }
return {
doSomething: doSomething
};
})();
or
window.NiftyThing = {
doSomething: function() { ... }
};
or
NiftyThing = {
doSomething: function() { ... }
};
Then you can delete the property that references it:
delete window.NiftyThing;
...which removes at least that one main reference to it; if there are other references to it, it may not get cleaned up.
If the var keyword has been used:
var NiftyThing = {
doSomething: function() { ... }
};
...then it's not a property and you can't use delete, so setting to undefined or null will break the reference:
NiftyThing = undefined;
You can hedge your bets:
NiftyThing = undefined;
try { delete NiftyThing; } catch (e) { }
In all cases, it's up to the JavaScript implementation to determine that there are no outstanding external references to the loaded script and clean up, but at least you're giving it the opportunity.
If, as Guffa says, the loaded script doesn't use the module pattern, then you need to apply these rules to all of its symbols. Which is yet another reason why the module pattern is a Good Thing(tm). ;-)
It might be possible to remove a Javascript file that has been loaded, but that doesn't undo what the code has done, i.e. the functions that was in the code are still defined.
You can remove a function definition by simply replacing it with something else:
myFunction = null;
This doesn't remove the identifier, but it's not a function any more.

Categories

Resources