149 lines
4 KiB
JavaScript
149 lines
4 KiB
JavaScript
var indexOf = function (xs, item) {
|
|
if (xs.indexOf) return xs.indexOf(item);
|
|
else for (var i = 0; i < xs.length; i++) {
|
|
if (xs[i] === item) return i;
|
|
}
|
|
return -1;
|
|
};
|
|
var Object_keys = function (obj) {
|
|
if (Object.keys) return Object.keys(obj)
|
|
else {
|
|
var res = [];
|
|
for (var key in obj) res.push(key)
|
|
return res;
|
|
}
|
|
};
|
|
|
|
var forEach = function (xs, fn) {
|
|
if (xs.forEach) return xs.forEach(fn)
|
|
else for (var i = 0; i < xs.length; i++) {
|
|
fn(xs[i], i, xs);
|
|
}
|
|
};
|
|
|
|
var defineProp = (function() {
|
|
try {
|
|
Object.defineProperty({}, '_', {});
|
|
return function(obj, name, value) {
|
|
Object.defineProperty(obj, name, {
|
|
writable: true,
|
|
enumerable: false,
|
|
configurable: true,
|
|
value: value
|
|
})
|
|
};
|
|
} catch(e) {
|
|
return function(obj, name, value) {
|
|
obj[name] = value;
|
|
};
|
|
}
|
|
}());
|
|
|
|
var globals = ['Array', 'Boolean', 'Date', 'Error', 'EvalError', 'Function',
|
|
'Infinity', 'JSON', 'Math', 'NaN', 'Number', 'Object', 'RangeError',
|
|
'ReferenceError', 'RegExp', 'String', 'SyntaxError', 'TypeError', 'URIError',
|
|
'decodeURI', 'decodeURIComponent', 'encodeURI', 'encodeURIComponent', 'escape',
|
|
'eval', 'isFinite', 'isNaN', 'parseFloat', 'parseInt', 'undefined', 'unescape'];
|
|
|
|
function Context() {}
|
|
Context.prototype = {};
|
|
|
|
var Script = exports.Script = function NodeScript (code) {
|
|
if (!(this instanceof Script)) return new Script(code);
|
|
this.code = code;
|
|
};
|
|
|
|
Script.prototype.runInContext = function (context) {
|
|
if (!(context instanceof Context)) {
|
|
throw new TypeError("needs a 'context' argument.");
|
|
}
|
|
|
|
var iframe = document.createElement('iframe');
|
|
if (!iframe.style) iframe.style = {};
|
|
iframe.style.display = 'none';
|
|
|
|
document.body.appendChild(iframe);
|
|
|
|
var win = iframe.contentWindow;
|
|
var wEval = win.eval, wExecScript = win.execScript;
|
|
|
|
if (!wEval && wExecScript) {
|
|
// win.eval() magically appears when this is called in IE:
|
|
wExecScript.call(win, 'null');
|
|
wEval = win.eval;
|
|
}
|
|
|
|
forEach(Object_keys(context), function (key) {
|
|
win[key] = context[key];
|
|
});
|
|
forEach(globals, function (key) {
|
|
if (context[key]) {
|
|
win[key] = context[key];
|
|
}
|
|
});
|
|
|
|
var winKeys = Object_keys(win);
|
|
|
|
var res = wEval.call(win, this.code);
|
|
|
|
forEach(Object_keys(win), function (key) {
|
|
// Avoid copying circular objects like `top` and `window` by only
|
|
// updating existing context properties or new properties in the `win`
|
|
// that was only introduced after the eval.
|
|
if (key in context || indexOf(winKeys, key) === -1) {
|
|
context[key] = win[key];
|
|
}
|
|
});
|
|
|
|
forEach(globals, function (key) {
|
|
if (!(key in context)) {
|
|
defineProp(context, key, win[key]);
|
|
}
|
|
});
|
|
|
|
document.body.removeChild(iframe);
|
|
|
|
return res;
|
|
};
|
|
|
|
Script.prototype.runInThisContext = function () {
|
|
return eval(this.code); // maybe...
|
|
};
|
|
|
|
Script.prototype.runInNewContext = function (context) {
|
|
var ctx = Script.createContext(context);
|
|
var res = this.runInContext(ctx);
|
|
|
|
if (context) {
|
|
forEach(Object_keys(ctx), function (key) {
|
|
context[key] = ctx[key];
|
|
});
|
|
}
|
|
|
|
return res;
|
|
};
|
|
|
|
forEach(Object_keys(Script.prototype), function (name) {
|
|
exports[name] = Script[name] = function (code) {
|
|
var s = Script(code);
|
|
return s[name].apply(s, [].slice.call(arguments, 1));
|
|
};
|
|
});
|
|
|
|
exports.isContext = function (context) {
|
|
return context instanceof Context;
|
|
};
|
|
|
|
exports.createScript = function (code) {
|
|
return exports.Script(code);
|
|
};
|
|
|
|
exports.createContext = Script.createContext = function (context) {
|
|
var copy = new Context();
|
|
if(typeof context === 'object') {
|
|
forEach(Object_keys(context), function (key) {
|
|
copy[key] = context[key];
|
|
});
|
|
}
|
|
return copy;
|
|
};
|