@@ -5,6 +5,7 @@ var indexOf = function (xs, item) {
5
5
}
6
6
return - 1 ;
7
7
} ;
8
+
8
9
var Object_keys = function ( obj ) {
9
10
if ( Object . keys ) return Object . keys ( obj )
10
11
else {
@@ -39,6 +40,9 @@ var defineProp = (function() {
39
40
}
40
41
} ( ) ) ;
41
42
43
+ // cached iFrame instance, re-use for each runInContext Call.
44
+ var iFrame = null ;
45
+
42
46
var globals = [ 'Array' , 'Boolean' , 'Date' , 'Error' , 'EvalError' , 'Function' ,
43
47
'Infinity' , 'JSON' , 'Math' , 'NaN' , 'Number' , 'Object' , 'RangeError' ,
44
48
'ReferenceError' , 'RegExp' , 'String' , 'SyntaxError' , 'TypeError' , 'URIError' ,
@@ -50,59 +54,66 @@ Context.prototype = {};
50
54
51
55
var Script = exports . Script = function NodeScript ( code ) {
52
56
if ( ! ( this instanceof Script ) ) return new Script ( code ) ;
57
+ if ( ! iFrame ) {
58
+ iFrame = document . createElement ( 'iframe' ) ;
59
+ if ( ! iFrame . style ) iFrame . style = { } ;
60
+ iFrame . style . display = 'none' ;
61
+
62
+ document . body . appendChild ( iFrame ) ;
63
+ }
53
64
this . code = code ;
65
+ this . iFrame = iFrame ;
54
66
} ;
55
67
56
68
Script . prototype . runInContext = function ( context ) {
57
69
if ( ! ( context instanceof Context ) ) {
58
70
throw new TypeError ( "needs a 'context' argument." ) ;
59
71
}
60
-
61
- var iframe = document . createElement ( 'iframe' ) ;
62
- if ( ! iframe . style ) iframe . style = { } ;
63
- iframe . style . display = 'none' ;
64
-
65
- document . body . appendChild ( iframe ) ;
66
-
67
- var win = iframe . contentWindow ;
72
+
73
+ var win = this . iFrame . contentWindow ;
74
+ var winOriginal = Object_keys ( win ) ;
75
+ var originalToRestore = [ ] ;
68
76
var wEval = win . eval , wExecScript = win . execScript ;
69
77
70
78
if ( ! wEval && wExecScript ) {
71
79
// win.eval() magically appears when this is called in IE:
72
80
wExecScript . call ( win , 'null' ) ;
73
81
wEval = win . eval ;
74
82
}
75
-
83
+
76
84
forEach ( Object_keys ( context ) , function ( key ) {
77
- win [ key ] = context [ key ] ;
78
- } ) ;
79
- forEach ( globals , function ( key ) {
80
- if ( context [ key ] ) {
81
- win [ key ] = context [ key ] ;
82
- }
85
+ if ( win [ key ] !== undefined ) {
86
+ let restore = {
87
+ 'key' : key ,
88
+ 'value' : win [ key ]
89
+ } ;
90
+ originalToRestore . push ( restore ) ;
91
+ }
92
+ win [ key ] = context [ key ] ;
83
93
} ) ;
84
-
94
+
85
95
var winKeys = Object_keys ( win ) ;
86
96
87
97
var res = wEval . call ( win , this . code ) ;
88
-
98
+
89
99
forEach ( Object_keys ( win ) , function ( key ) {
90
100
// Avoid copying circular objects like `top` and `window` by only
91
101
// updating existing context properties or new properties in the `win`
92
102
// that was only introduced after the eval.
93
103
if ( key in context || indexOf ( winKeys , key ) === - 1 ) {
94
- context [ key ] = win [ key ] ;
104
+ if ( indexOf ( globals , key ) === - 1 ) context [ key ] = win [ key ] ;
105
+ else defineProp ( context , key , win [ key ] ) ;
95
106
}
107
+
108
+ // delete win context of extra fields
109
+ if ( indexOf ( winOriginal , key ) === - 1 ) delete win [ key ] ;
96
110
} ) ;
97
111
98
- forEach ( globals , function ( key ) {
99
- if ( ! ( key in context ) ) {
100
- defineProp ( context , key , win [ key ] ) ;
101
- }
112
+ // restore context to original field values
113
+ forEach ( originalToRestore , function ( orig ) {
114
+ win [ orig . key ] = orig . value ;
102
115
} ) ;
103
-
104
- document . body . removeChild ( iframe ) ;
105
-
116
+
106
117
return res ;
107
118
} ;
108
119
0 commit comments