I have a situation in which I have to use eval in Javascript. Yes, I know it is evil, but in this case it is required, because two requisites:
The Javascript code is big.
It has to be evaluated (and downloaded) only in a few situations, so I don't want the script to be downloaded always, but on demand.
With these requisites, I have written an XMLHttpRequest to request the code (600+K), and I want to eval that code to take place immediately. As I'll show later, the script contains just data to be inserted in two variables. The problem is that evaluating this javascript fails always with syntax error. If I put the code verbatim (without eval), the code executes fine. This is the minimal example. I have a search.js file like this:
// search.js for functional mind. Generated statically
// from the set of posts.
posts = { 'postlist' : ['YYY', 'other link...' ] };
posts_for_word = { 'word1' : [0,1], 'word2' : [Z,K] };
The last variable, posts_for_word includes indexes of posts containing that word. The problem comes when I evaluate that Javascript inside eval:
// global environment
var posts = {}; // Initial value, empty
var posts_for_word = {}; // same
function() {
var request = // create XMLHTTPREQUEST request
var response = // obtain response (the javascript)
eval( response ); // <- syntax error
// access posts or posts_for_word
posts.postlist[ posts_for_word['word1'][0] ]
....
}
The problems:
When I evaluate the javascript shown above with eval, firefox tells me that it is bad formed in the first line.
I then removed the comments. I supposed that eval would evaluate it as if it was a normal Javascript program, but it doesn't seem to accept comments (why?).
After removing the comments, the code works, but still the Javascript console of Firefox tells me that there is a syntax error in the first line (that defining the JSON first variable). Why?
You shouldn't use AJAX and eval() to make a script happen on your website, instead, create a <script> element with a link to the file and append it to the body:
(function() {
var jsCode = document.createElement('script');
jsCode.setAttribute('src', 'http://localhost/tests/doStuff.js');
document.body.appendChild(jsCode);
}());
(This code is actually taken directly from a bookmarklet of mine, and it does the trick nicely.)
As for the variable scope, if you declare them as var variable in your inner file, it would override the file scope and become global.
However, should you require a synchronous load of a script, you will have to (despite the fact it is considered bad practice) to use a synchronous AJAX call. How to do that was already written before me, Dynamically loading JavaScript synchronously
Related
background
I have a JScript script running under WSH.
The script is fairly simple. It iterates over a list of strings, each string, a JScript itself, and run each "internal" script.
Problem
It is possible that some "internal" script, may call Quit method. This causes the main script to stop, which is not desired.
Simple example
var strSomeScript = "WScript.Quit(1)";
var F = new Function(strSomeScript);
var exitCode = (F)();
WScript.Echo("Continue doing more things...");
the last line will not be executed since the "internal" script stops the execution.
Question
If I have no control over the content of the "internal" scripts, how can I prevent them from breaking my main flow.
Requirements
I need to run each "internal" script, wait for it to finish and store its exit code.
If you want only to prevent specifically WScript.Quit calls you can simply sanitize your input with a simple replace. (*) If you want to be able to prevent any way of stopping the script - for example, var x = WScript; x.Quit(); - you're basically trying to solve the halting problem, which I hear is kind of hard.
If you were using regular JS you could have tried something like:
WScript.Quit = function(e) {
// Assume there's something reasonable to put here
};
or:
var __WScript = WScript;
WScript = { ConnectObject: function(obj, pref) { __WScript.ConnectObject(obj, pref); },
CreateObject: function(progid, pref) { __WScript.CreateObject(obj, pref); },
... };
But the WScript object doesn't implement IDIspatchEx etc. so that won't work.
The only way do make sure an arbitrary string, when interpreted as JavaScript code, doesn't end your script is not to eval that string as part of your script, but rather run it in a brand new context. (And calling the Function contrcutor on that string and then calling the resulting object is pretty much the same as evaling it.)
You can write it to a file and execute wscript.exe with this file as argument, or use the Microsoft Script Control if you don't want to write a file to disk and/or want to give the script access to objects from the parent script.
(*) Not that this makes any sense either way. Lets even say that your only problem is WScript.Quit. What are you going to put instead? return? That's not going to cut it:
function bar(a) {
if (Pred(a)) {
WScript.Quit(123);
}
return 456;
}
function foo() {
var x = bar(789);
if (!x) {
DoSomethingBad();
}
}
foo();
A script that used to end silently now does something bad. If you "know" that changing the WScript.Quit to return doesn't do anything bad you should also know that there aren't any WScript.Quits in the code in the first place.
There's simply nothing sensible you can do instead quitting even if you could catch every call to WScript.Quit.
I am writing a hybrid application with HTML interface and Python code.
I can access Python functions via a shared object:
pythonPart.py:
class BO(QObject):
def __init__(self, parent=None):
super(BO, self).__init__(parent)
#Slot(str)
def doStuff(self, txt):
print(txt)
bridgeObj = BO()
# init stuff and frame...
frame.addToJavaScriptWindowObject( 'pyBridge', bridgeObj )
frame.evaluateJavaScript('alert("Alert from Python")')
frame.evaluateJavaScript('testMe()')
frame.evaluateJavaScript('alert("Starting test");testMe();alert("Test over")')
jsPart.js:
function testMe() { alert('js function testMe called'); }
pyBridge.doStuff("bla");
testMe();
Calling Python functions from JS works, as does calling testMe from JS. Calling "standard" JS functions like alert from Python works, too.
The last two Python lines won't:
evaluateJavaScript("testMe()") doesn't do anything at all.
The last line executes the first alert and won't continue after that.
EDIT: I already tried having some time.sleep() between loading and calling the evaluateJavaScript and I'm loading the webpage from the local machine.
The most likely problem is that the JavaScript just isn't loaded yet. Adding time.sleep() calls doesn't help for that, those will also block the Qt event loop from continuing, not just your Python code.
Try waiting for the page to have fully loaded instead, for example (using the loadFinished signal:
def onLoad():
frame.evaluateJavaScript('testMe()')
frame.loadFinished.connect(onLoad)
Aditionally, for getting more debug information in situations like this, you might want to implement QtWebKit.QWebPage.javaScriptConsoleMessage.
There are at least two errors in the example code.
Firstly, when you add the object to the javascript window, you call it "pyBridge", but you then try to reference it in the javascript as "bridgeObj". Obviously, this will throw a ReferenceError which will prevent any further execution of the script.
Secondly, the doStuff method is missing a self argument, which will cause a TypeError to be raised by PySide.
Dealing with those two issues should be enough to fix your example code, so long as you make sure that the bridge object is added to the javacsript window before the html is loaded. This step is required if you want to reference the bridge object in top-level javascript code. However, if the bridge object is only ever referenced in function-level code, it can be safely added to the javascript window after the html has loaded.
I want to give clients an HTML block they can include in their site, and this HTML will contain some table and image, plus a javascript that will make manipulations over the HTML block.
so I give them the HTML :
<a data-theme="1" data-srv="http://localhost:50987/" class="block1" href="http://myserver/payment/Details">outer information</a><script type="text/javascript" src="http://myserver/Scripts/checkout.js"></script>
in checkout.js I have included JQuery if no Jquery exists in document and do manipulation over the element $('a.block1') ... the problem is when someone puts this block of HTML more then once over the same page, I want that the client will not call "checkout.js" more then once,
I've tried declaring global var inside "checkout.js" and check if it's exists, it works good to stop doing the same manipulation more then once but I want to stop the call to JS al together .
Javascript runs after it loads, you can't stop the JS running, if it is referenced multiple times. It won't be loaded multiple times, so the overhead of it running again is basically nil.
To stop the behavior of the javascript happening again, just put the check at the top level of the file, put the rest of the file in the conditional, and write to a global variable to make sure you don't run again.
if (window._your_unique_id === undefined) {
window._your_unique_id = true;
// the rest of your javascript
}
that will mean nothing in the script runs. You can still define whatever you like in that if statement, though if you define functions and variables in there, you may have to explicitly put them on the window object, because they'll otherwise be local (but then, it is bad practice to have anything implicitly defined global anyway, so it shouldn't make any difference if your code is well structured).
Just deploy your code as a module.
Ie.
(function(window){
if(window.CheckoutModule) return;
// now you're certain there's no global module loaded
var CheckoutModule = window.CheckoutModule = {};
// you can, ie, add a jQuery check here.
if('undefined' != typeof jQuery) {
// do your jQuery thing here.
}
return ;
})(window, jQuery);
So I'm trying to load a javascript remotely using jquery's $.getScript, but I'm puzzled on how I can pass data to the external script.
I've tried setting variables before the call but they aren't available in the script that gets loaded, and when I try to send/retrieve them using the query string, the remote script tries to read the querystring of the base file that it gets called from, not itself. Is there any other way to do this? Or is it possible to have a javascript file read its own querystring rather than the file it's called from (that's loaded in the browser)?
// editor ini
var editor_ini = { page: current_page, action: 'edit' };
var foo = 'bar';
// load the editor
$.getScript('assets/desktop/desklets/'+launcher.config.editor+'/execute.js', function(){});
In the execute.js file, the editor_ini and foo are both unavailable, I get the same result with:
// load the editor
$.getScript('assets/desktop/desklets/'+launcher.config.editor+'/execute.js', { page: current_page, action: 'edit', foo: 'bar' }, function(){});
because the remote script seems to be getting the query string from the original document rather than the one used when calling the file.
If it matters, I was trying to use the query object plugin for jquery for reading the query string.
global variable declared in inline javascript is accessible in external javascript page loaded using $.getScript().
I bet that your var foo='bar' is inside a function, so not visible in global scope. Try:
window.foo = 'bar'
Truly global variables will be accessible to your script. So, if they aren't, then it's probably because your variables that you think are global actually aren't. You can either move them to the top level scope or set them on the window object like Alexei suggested.
There are other ways to share data.
1) You can put an id on the <script> tag that loads the code and then have the code get the .src value from that tag and get the query string off the script's actual URL. I like this option, but I don't know if you can do it using jQuery.getScript() since I don't think it exposes that as an option.
2) You can have the loading script call a function that you provide and return an object with the desired data from that function.
3) Once the new script is loaded, you can call a setXXX() function in that script to set the state that it needs.
4) You can set information into a cookie that the other script can read.
5) You can encode data into a URL hash value that the other script can read.
Could someone explain the javascript that makes up Google's Website Optimiser Control script? Specifically: the first two lines, which seem to be empty functions, and why is the third function wrapped parentheses () ?
As far as I can tell this script is basically writing out a new <script> which presumably loads something for A/B testing.
function utmx_section(){}
function utmx(){}
(function() {
var k='0634742331',d=document,l=d.location,c=d.cookie;
function f(n) {
if(c) {
var i=c.indexOf(n+'=');
if (i>-1) {
var j=c.indexOf(';',i);
return escape(c.substring(i+n.length+1,j<0?c.length:j))
}
}
}
var x=f('__utmx'),xx=f('__utmxx'),h=l.hash;
d.write('<sc'+'ript src="'+'http'+(l.protocol=='https:'?'s://ssl':'://www')+'.google-analytics.com'+'/siteopt.js?v=1&utmxkey='+k+'&utmx='+(x?x:'')+'&utmxx='+(xx?xx:'')+'&utmxtime='+new Date().valueOf()+(h?'&utmxhash='+escape(h.substr(1)):'')+'" type="text/javascript" charset="utf-8"></sc'+'ript>')
}
)();
I've attempted to step through with the firebug debugger but it doesn't seem to like it. Any insights much appreciated.
Many thanks
inside anonymous function it shortens names of document and cookies inside it at first, function f(n) gets value of cookie under name n. Then Google reads its cookies and with help of d.write it loads its scripts (as I see they are related to Google Analytic). This way it makes On-Demand JavaScript loading... Actually you load these scripts all the time, Google just needs some additional parameters in url, so this is done this way - save parameters in cookie, which next time are used to get script again.
And finally back to the first two magic lines :) After Google loads its script (after executing d.write), there are some functions which uses utmx and utmx_section, as well as definition of these functions, or better to say overriding. I think they are empty at first just because another function can execute it before its real definition, and having empty functions nothing will happen (and no JS error), otherwise script would not work. E.g. after first iteration there is some data, which is used to make real definition of these functions and everything starts to work :)
The first 2 functions are in fact empty, and are probably overridden later on.
The third function is an anonymous self-executing function. The brackets are a convention to make you aware of the fact that it is self executing.
the "f" function looks up the value given to it in the document's cookies and returns it. Then a new script tag is written to document (and requested from server) with these values as part of its URL.