/
event_handler.html
305 lines (279 loc) · 10.8 KB
/
event_handler.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
<title>Unsafe Names for HTML Form Controls - Unsafe Names</title>
<meta name="author" content="Garrett Smith">
<link rel="Start" href="./">
<link rel="stylesheet" href="../faq.css" type="text/css" media="all" charset="iso-8859-1">
<link rel="stylesheet" href="names.css" type="text/css" media="all" charset="iso-8859-1">
</head>
<body>
<h1>Unsafe Names for HTML Form Controls</h1>
<h2>Event Handler Scope</h2>
<h3>Event Handler Content Attributes and Augmented Scope Chain</h3>
<p>
Event Handler Content Attributes are event handler attributes that appear in the HTML source.
</p>
<p>
When an element has an event handler content attribute, the value
of that attribute becomes the <code>FunctionBody</code> of a function that the browser calls when it fires that event.
</p>
<p>
Modern browsers augment the <code>FunctionBody</code>'s scope chain with the element, the element's <code>FORM</code>
(if it is a form control), and <code>document</code>. There is no official standard for this augmented scope chain.
</p>
<p>
Older browsers, such as Safari 2, Mozilla 1.x, Opera 7, differ. Scope augmentation occurs for all
event handler content attributes with the notable exception of the <code>body</code> element, for
which event handler scope is not consistently augmented across event types and implementations.
</p>
<p>
The context (<code>thisArg</code>) is (with the exception of <code>body</code>), the element
itself. In the browsers that implement DOM Events [<a href="conclusion.html#controls-normref">DOMEvents</a>],
the event handler function has a single parameter named <code>event</code>.
</p>
<p>
Given the following markup:
</p>
<pre><p onclick="self.alert(event);"></p></pre>
<p>
The augmented scope chain, if written in ECMAScript, would look like:
</p>
<pre>
<span class='keyword'>function</span> onclick(<var>event</var>) {
<span class='keyword'>with</span>(document) {
<span class='keyword'>with</span>(<span class='keyword'>this</span>.form) {
<span class='keyword'>with</span>(<span class='keyword'>this</span>) {
self.alert(<var>event</var>);
}
}
}
}</pre>
<p>
Note that some browsers will not supply an <code><var>event</var></code> parameter.
</p>
<h4>Example 3: Augmented Scope Chain</h4>
<p>
This example shows how <code>window</code> and <code>document</code>
are shadowed:
</p>
<form action="">
<input type="hidden" name="document">
<button type="button" name="window"
onclick="self.alert([window.tagName, document.tagName])"
>self.alert([window.tagName, document.tagName])</button>
</form>
<strong>Source:</strong>
<pre>
<form action="">
<input type="hidden" name="document">
<button type="button" name="window"
onclick="self.alert([window.tagName, document.tagName])">self.alert([window.tagName, document.tagName])</button>
</form>
</pre>
<p>
The augmented scope chain, if written in ECMAScript, would look like:
</p>
<pre>
<span class='keyword'>function</span> onclick(<var>event</var>) {
<span class='keyword'>with</span>(document) {
<span class='keyword'>with</span>(<span class='keyword'>this</span>.form) {
<span class='keyword'>with</span>(<span class='keyword'>this</span>) {
self.alert([title, files, focus == window.focus]);
<span class='keyword'>var</span> e = <var>event</var>||window.event;
<span class='keyword'>if</span>(e && e.preventDefault) e.preventDefault();
e.returnValue = <span class='keyword'>false</span>;
}
}
}
}</pre>
<p>
For all intents and purposes, the browser's
<code>window</code> property of the <code>global</code> object is
an alias to the the <code>global</code> object itself.
</p>
<p>
Relying on an augmented scope chain to resolve properties may
have unexpected results in different environments (i.e. browsers). The following example
shows how in at least two browsers, <code>files</code> is resolved as a property
of an <code>input</code> element.
</p>
<script type="text/javascript">
var files = [1,2,3];
</script>
<form action="">
<input onclick="self.alert([title, files, focus == window.focus]);
var e = event||window.event;
if(e && e.preventDefault) e.preventDefault();e.returnValue = false;" type="file">
</form>
<pre>
<script type="text/javascript">
<span class='keyword'>var</span> files = [1,2,3];
</script>
<form action="">
<input onclick="self.alert([title, files, focus == window.focus]);
var e = event||window.event;
if(e && e.preventDefault) e.preventDefault();
e.returnValue = false;" type="file">
</form>
</pre>
<h3>Result</h3>
Firefox 3, Safari 3:
<pre>",[object FileList],false"</pre>
Opera 9.5, IE7, IE8:
<pre>",1,2,3,false"</pre>
<p>
The identifier <code>files</code> is resolved on the input element
in Firefox 3 and Safari 3. In IE8 or Opera 9.5, <code>files</code> is
resolved on the window object.
</p>
<p>
A <a href="scope_aug_example.html">modified example</a> from c.l.js thread <a
href="http://groups.google.com/group/comp.lang.javascript/browse_frm/thread/2d1bd03a4bc47add"
>"Works in ie and opera not mozilla"</a>, by Richard Cornford.
</p>
<h4>Browsers Tested:</h4>
<ul>
<li>Opera 9.27, 9.63, 10a;</li>
<li>Safari 3.2.1;</li>
<li>Chrome 1.0.154.46;</li>
<li>Firefox 2.0.0.18, 3.0.5;</li>
<li>IE 7, 8.0RC1;</li>
<li>IE 5.2 (Mac)</li>
<li>Konqueror 4.1;</li>
<li>Blackberry 4.7 (9500 model)</li>
<li>MSIEMobile 6.0 (WinCE)</li>
</ul>
<h4>Results:</h4>
<pre>
ex0 = global
ex1 = document #document
ex2 = document #document
ex3 = document #document
ex4 = 4 FORM
ex5 = 4 FORM
ex6 = 4 FORM
ex7 = 7 INPUT
ex8 = 7 INPUT
ex9 = 7 INPUT
// First link
ex0 = global
ex1 = document #document
ex2 = document #document
ex3 = document #document
ex4 = document #document
ex5 = document #document
ex6 = document #document
ex7 = document #document
ex8 = 8 A
ex9 = 8 A
// Second link
ex0 = global
ex1 = document #document
ex2 = document #document
ex3 = document #document
ex4 = document #document
ex5 = document #document
ex6 = document #document
ex7 = document #document
ex8 = document #document
ex9 = 9 A
</pre>
<p>Most of the above results were provided by Juriy Zaytsev on thread
<a
href="http://groups.google.com/group/comp.lang.javascript/browse_frm/thread/8e48b8520d359395/61b45f35fb76694f"
>Cross-Browser Mouse Event Handling</a>.
</p>
<h4>Older Browsers</h4>
<p>
Less recent browsers, including Safari 2.0.4, Mozilla 1.x,
and Opera 7, featured different scope chains.
</p>
<h4>Exception: The <code>BODY</code> Tag.</h4>
<p>
The <code>body</code> tag's event handler attributes are either mapped to
<code>window</code> (which has no tag) or to the <code>BODY</code> element.
Results vary based on the event and the browser. Do not use event handler
attributes for the <code>body</code> element.
</p>
<h3>Problem</h3>
<p>
An augmented scope chain, combined with event handler content attributes, means that
properties of the element itself, the element's form (if it is a form control),
and document, may shadow properties of the window object.
As explained in: <a href="http://groups.google.com/group/comp.lang.javascript/msg/3f5495216b3e9b67"
>select?</a>, and
<a href="http://lists.whatwg.org/htdig.cgi/whatwg-whatwg.org/2008-September/016184.html"
>hashchange only dispatched in history traversal</a>, comments by Garrett Smith. Shortened code excerpt:
</p>
<pre>
<img name='alert' alt="Alert!" src="alert.jpg">
<button onclick="self.alert(alert);">self.alert(alert);</button>
</pre>
<img name='alert' alt="Alert!" src="" style="z-index:-1;position:absolute">
<button onclick="self.alert(alert);">self.alert(alert);</button>
<h4>Result</h4>
<p>
Alerts <samp>[object HTMLImageElement]</samp> (or similar implementation-dependent string).
</p>
<p>
By using an unsafe name of <samp>"alert"</samp> for an <code>IMG</code>,
The <code>window</code>'s <code>alert</code> property
identifier is shadowed by <code>document</code>'s <code>alert</code>
property identifier because
<code>document</code> is in the event handler's augmented scope
before <code>window</code>.
</p>
<p>
By using event handler content attributes and unsafe names,
<code>document</code> and <code>window</code>, the respective identifiers
are resolved on the augmented scope chain.
</p>
<p>
The augmented scope chain
creates more ambiguity and increases the number of unsafe names.
</p>
<h3>Solution</h3>
<ul>
<li>
Don't rely on the augmented scope chain to find properties of the <code>FORM</code>,
<code>body</code>, or <code>document</code>. Instead, use fully qualified property lookups,
e.g. <code>document.body</code>, <code>this.form.elements</code>.
</li>
<li>
Avoid Event Handler Content Attributes.
Registering event callbacks in the script (not in HTML) avoids
the possibility of a property such as unqualified <code>alert</code>
being resolved on an object other than <code>window</code>.
</li>
<li>
Do not use Event Handler Content Attributes for <code>body</code>.
</li>
<li>
Use prefixed names for all <code>id</code> or <code>name</code> attribute values.
</li>
</ul>
<div id="toc">
<h4>Table of Contents</h4>
<ul class="pagination linkList">
<li><a href="./index.html">Introduction</a></li>
<li><a href="extra_props.html">Extra Properties: <code>FORM</code> Elements</a></li>
<li><a href="extra_props_document.html">Extra Properties: <code>document</code></a></li>
<li><a href="extra_props_global.html">Extra Properties: <code>global</code></a></li>
<li>Event Handler Scope</li>
<li><a href="api_design.html">API Design?</a></li>
<li><a href="unsafe_names.html">Unsafe Names</a></li>
<li><a href="conclusion.html">Conclusion</a></li>
</ul>
</div>
<ul id="nextLink" class="linkList">
<li>
<span class="prev">Previous:</span> <a href="extra_props_global.html">Extra Properties: global</a>
</li>
<li>
<span class="next">Next:</span> <a href="api_design.html">API Design?</a>
</li>
</ul>
</body>
</html>