Reputation: 1
I am converting tutorials for students (2nd language speakers, 9 to 12 yrs old) to access in an offline / intranet context. Hence the websites I would like them to use are unavailable.
I am trying to mimic the 'alter the code' style of tutorials for helping with JavaScript / HTML5 Canvas.
This works :
<canvas id="myCanvas" height="400px" width="400px"></canvas>
<script>
function update(){
eval(document.getElementById('demoScript').value);
}
var ctx = document.getElementById("myCanvas").getContext("2d");
</script>
<textarea id="demoScript">
ctx.fillRect(100,100,50,50);
</textarea>
<input type="button" value="update" onClick="update()">
... but everything I have read says eval() is a bad idea.
I can get the textarea content to pop-up in a div if I want, but I can't get it to pop-up in a script anywhere ... leaving me with just eval().
Options and recommendations for alternatives please ... or this is as good as it gets ?
Upvotes: 0
Views: 425
Reputation: 318332
You can get the value string from the textarea, split, validate and run it manually.
For a demonstration like this, where ctx
is given, something like this should work
var ctx = document.getElementById("myCanvas").getContext("2d");
function update(){
var val = document.getElementById('demoScript').value,
fn = val.match(/\.(.*?)\(/),
arg = val.match(/\((.*?)\)/);
if (fn && fn.length > 0) {
if (arg && arg.length > 0) {
var args = arg[1].indexOf(',') != -1 ? arg[1].split(',') : [arg[1]];
ctx[fn[1]].apply(ctx, args);
}else{
ctx[fn[1]]();
}
}
}
Upvotes: 0
Reputation: 10982
Options and recommendations for alternatives please ... or this is as good as it gets ?
I'd suggest using the Function
constructor instead of eval
. While in your simple example it may not make much difference, in other cases it may.
This will make the code evaluate in the global scope, so none of your local variables can be touched. It also allows JS engines to more easily optimize the local code. Using eval()
can disable optimizations.
So to use the Function
constructor, just pass the code to eval as the last argument. Since you have no parameters to define for the new function, it'll be the only argument.
var f = new Function("return " + document.getElementById("demoScript").value);
Then invoke the function.
f();
Notice that I concatenated a return
statement into the provided code. This isn't required if you don't care about getting the returned value from the code your invoking, and should be removed if it might interfere with the provided code.
And of course, you can do this all in one line if you're only going to invoke it once.
new Function(document.getElementById("demoScript").value)();
Upvotes: 1
Reputation: 9966
First of all, it's not a "bad idea" to use eval. Second: anything that replaces eval will have the same "disadvantages" since it executes code. You'll have to execute code to do this. If you don't want to make your own interpreter (which is at least ten times worse and more vulnerable) you'll have to stick with eval or something similar.
Now what is the danger of it? Nothing else but the fact that it executes code. It's like telling someone that a hammer is dangerous because it hits hard - YES, and it's necessary when it gets to nailing something. Of course, a hammer can kill.
So,
You can limit a lot of things for the user, like only one instruction per line, only double quotes, etc, to make it more controllable. Anything that's off the limit will be deleted. If no dangerous thing can be pushed thru the input, eval is harmless.
Upvotes: 1
Reputation: 324790
This is an acceptable use for eval
, because at worst a student will lock up their own browser with an infinite loop.
Upvotes: 1
Reputation: 77806
You could do
var fn = document.getElementById("demoScript").value;
window[fn]();
Upvotes: -1