View Javadoc
1   /*
2    * Copyright (c) 2002-2025 Gargoyle Software Inc.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * https://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  package org.htmlunit.html;
16  
17  import org.htmlunit.WebDriverTestCase;
18  import org.htmlunit.junit.BrowserRunner;
19  import org.htmlunit.junit.annotation.Alerts;
20  import org.htmlunit.junit.annotation.HtmlUnitNYI;
21  import org.junit.After;
22  import org.junit.Test;
23  import org.junit.runner.RunWith;
24  import org.openqa.selenium.By;
25  import org.openqa.selenium.WebDriver;
26  
27  /**
28   * Tests for elements with onblur and onfocus attributes.
29   *
30   * @author David D. Kilzer
31   * @author Marc Guillemot
32   * @author Ahmed Ashour
33   * @author Ronald Brill
34   * @author Frank Danek
35   */
36  @RunWith(BrowserRunner.class)
37  public class FocusableElement2Test extends WebDriverTestCase {
38  
39      /**
40       * We like to start with a new browser for each test.
41       * @throws Exception If an error occurs
42       */
43      @After
44      public void shutDownRealBrowsers() throws Exception {
45          super.shutDownAll();
46      }
47  
48      /**
49       * @throws Exception if the test fails
50       */
51      @Test
52      @Alerts(DEFAULT = {"body", "active: body", "onload", "active: body",
53                         "onfocus:[object Window]", "active: body"},
54              CHROME = {"body", "active: body", "onload", "active: body"},
55              EDGE = {"body", "active: body", "onload", "active: body"})
56      @HtmlUnitNYI(FF = {"body", "active: body", "onload", "active: body"},
57              FF_ESR = {"body", "active: body", "onload", "active: body"})
58      // TODO FF & FF68 fail due to wrong body vs. window event handling
59      public void bodyLoad() throws Exception {
60          final String html = DOCTYPE_HTML
61              + "<html>\n"
62              + "  <head>\n"
63              + "    <script>\n"
64              + logger()
65              + "      function test() {\n"
66              + "        log('onload');\n"
67              + "      }\n"
68              + "    </script>\n"
69              + "  </head>\n"
70              + "  <body id='body' onload='test()' " + logEvents("") + ">\n"
71              + "    <script>\n"
72              + "      log('body');"
73              + "    </script>\n"
74              + "  </body>\n"
75              + "</html>\n";
76  
77          final WebDriver driver = loadPage2(html);
78          assertTitle(driver, String.join(";", getExpectedAlerts()) + (getExpectedAlerts().length > 0 ? ";" : ""));
79      }
80  
81      /**
82       * @throws Exception if the test fails
83       */
84      @Test
85      @Alerts(DEFAULT = {"onfocus:[object Window]", "active: focusId",
86                         "before", "active: focusId", "after", "active: focusId"},
87              CHROME = {"before", "active: focusId", "after", "active: focusId"},
88              EDGE = {"before", "active: focusId", "after", "active: focusId"})
89      @HtmlUnitNYI(FF = {"before", "active: focusId", "after", "active: focusId"},
90              FF_ESR = {"before", "active: focusId", "after", "active: focusId"})
91      // TODO FF & FF68 fail due to wrong body vs. window event handling
92      public void body() throws Exception {
93          final String html = DOCTYPE_HTML
94              + "<html>\n"
95              + "  <head>\n"
96              + "    <script>\n"
97              + logger()
98              + "      function test() {\n"
99              + "        log('before');\n"
100             + "        document.getElementById('focusId').focus();\n"
101             + "        document.getElementById('focusId').focus();\n"
102             + "        document.getElementById('focusId').blur();\n"
103             + "        document.getElementById('focusId').blur();\n"
104             + "        log('after');\n"
105             + "      }\n"
106             + "    </script>\n"
107             + "  </head>\n"
108             + "  <body id='focusId' onload='setTimeout(test, 10)' " + logEvents("") + ">\n"
109             + "  </body>\n"
110             + "</html>\n";
111 
112         final WebDriver driver = loadPage2(html);
113         assertTitle(driver, String.join(";", getExpectedAlerts()) + (getExpectedAlerts().length > 0 ? ";" : ""));
114     }
115 
116     /**
117      * @throws Exception if the test fails
118      */
119     @Test
120     @Alerts(DEFAULT = {"onfocus:[object Window]", "active: body",
121                        "before", "active: body", "after", "active: body"},
122             CHROME = {"before", "active: body", "after", "active: body"},
123             EDGE = {"before", "active: body", "after", "active: body"})
124     @HtmlUnitNYI(FF = {"before", "active: body", "after", "active: body"},
125             FF_ESR = {"before", "active: body", "after", "active: body"})
126     // TODO FF & FF68 fail due to wrong body vs. window event handling
127     public void bodySwitchFromBodyToNotFocusable() throws Exception {
128         final String html = DOCTYPE_HTML
129             + "<html>\n"
130             + "  <head>\n"
131             + "    <script>\n"
132             + logger()
133             + "      function test() {\n"
134             + "        log('before');\n"
135             + "        document.getElementById('focusId').focus();\n"
136             + "        document.getElementById('focusId').blur();\n"
137             + "        log('after');\n"
138             + "      }\n"
139             + "    </script>\n"
140             + "  </head>\n"
141             + "  <body id='body' onload='setTimeout(test, 10)' " + logEvents("") + ">\n"
142             + "    <div id='focusId' " + logEvents("F") + ">div</div>\n"
143             + "  </body>\n"
144             + "</html>\n";
145 
146         final WebDriver driver = loadPage2(html);
147         assertTitle(driver, String.join(";", getExpectedAlerts()) + (getExpectedAlerts().length > 0 ? ";" : ""));
148     }
149 
150     /**
151      * @throws Exception if the test fails
152      */
153     @Test
154     @Alerts(DEFAULT = {"onfocus:[object Window]", "active: body",
155                        "before", "active: body",
156                        "onfocusF:focusId", "active: focusId", "onfocusinF:focusId",
157                        "active: focusId", "onfocusin:focusId", "active: focusId",
158                        "onblurF:focusId", "active: body", "onfocusoutF:focusId",
159                        "active: body", "onfocusout:focusId", "active: body",
160                        "after", "active: body"},
161             CHROME = {"before", "active: body",
162                       "onfocusF:focusId", "active: focusId", "onfocusinF:focusId",
163                       "active: focusId", "onfocusin:focusId", "active: focusId",
164                       "onblurF:focusId", "active: body", "onfocusoutF:focusId",
165                       "active: body", "onfocusout:focusId", "active: body",
166                       "after", "active: body"},
167             EDGE = {"before", "active: body",
168                     "onfocusF:focusId", "active: focusId", "onfocusinF:focusId",
169                     "active: focusId", "onfocusin:focusId", "active: focusId",
170                     "onblurF:focusId", "active: body", "onfocusoutF:focusId",
171                     "active: body", "onfocusout:focusId", "active: body",
172                     "after", "active: body"})
173     @HtmlUnitNYI(FF = {"before", "active: body",
174                        "onfocusF:focusId", "active: focusId", "onfocusinF:focusId",
175                        "active: focusId", "onfocusin:focusId", "active: focusId",
176                        "onblurF:focusId", "active: body", "onfocusoutF:focusId",
177                        "active: body", "onfocusout:focusId", "active: body",
178                        "after", "active: body"},
179             FF_ESR = {"before", "active: body",
180                       "onfocusF:focusId", "active: focusId", "onfocusinF:focusId",
181                       "active: focusId", "onfocusin:focusId", "active: focusId",
182                       "onblurF:focusId", "active: body", "onfocusoutF:focusId",
183                       "active: body", "onfocusout:focusId", "active: body",
184                       "after", "active: body"})
185     // TODO FF & FF68 fail due to wrong body vs. window event handling
186     public void bodySwitchFromBodyToFocusable() throws Exception {
187         final String html = DOCTYPE_HTML
188             + "<html>\n"
189             + "  <head>\n"
190             + "    <script>\n"
191             + logger()
192             + "      function test() {\n"
193             + "        log('before');\n"
194             + "        document.getElementById('focusId').focus();\n"
195             + "        document.getElementById('focusId').blur();\n"
196             + "        log('after');\n"
197             + "      }\n"
198             + "    </script>\n"
199             + "  </head>\n"
200             + "  <body id='body' onload='setTimeout(test, 10)' " + logEvents("") + ">\n"
201             + "    <input type='text' id='focusId' " + logEvents("F") + ">\n"
202             + "  </body>\n"
203             + "</html>\n";
204 
205         final WebDriver driver = loadPage2(html);
206         assertTitle(driver, String.join(";", getExpectedAlerts()) + (getExpectedAlerts().length > 0 ? ";" : ""));
207     }
208 
209     /**
210      * @throws Exception if the test fails
211      */
212     @Test
213     @Alerts(DEFAULT = {"onfocus:[object Window]", "active: body",
214                        "before", "active: body", "onfocusin:focusId1", "active: focusId1", "after", "active: focusId1"},
215             CHROME = {"before", "active: body", "onfocusin:focusId1", "active: focusId1", "after", "active: focusId1"},
216             EDGE = {"before", "active: body", "onfocusin:focusId1", "active: focusId1", "after", "active: focusId1"})
217     @HtmlUnitNYI(FF = {"before", "active: body", "onfocusin:focusId1", "active: focusId1", "after", "active: focusId1"},
218             FF_ESR = {"before", "active: body", "onfocusin:focusId1", "active: focusId1", "after", "active: focusId1"})
219     // TODO FF & FF68 fail due to wrong body vs. window event handling
220     public void bodySwitchFromFocusableToNotFocusable() throws Exception {
221         testBodySwitchWithCallFocusAndBlur("<input type='text' id='focusId1'>\n"
222             + "<div id='focusId2'>div</div>");
223     }
224 
225     /**
226      * @throws Exception if the test fails
227      */
228     @Test
229     @Alerts(DEFAULT = {"onfocus:[object Window]", "active: body", "before", "active: body",
230                        "onfocusin:focusId1", "active: focusId1",
231                        "onfocusout:focusId1", "active: body", "onfocusin:focusId2", "active: focusId2",
232                        "after", "active: focusId2"},
233             CHROME = {"before", "active: body",
234                       "onfocusin:focusId1", "active: focusId1",
235                       "onfocusout:focusId1", "active: body", "onfocusin:focusId2", "active: focusId2",
236                       "after", "active: focusId2"},
237             EDGE = {"before", "active: body",
238                     "onfocusin:focusId1", "active: focusId1",
239                     "onfocusout:focusId1", "active: body", "onfocusin:focusId2", "active: focusId2",
240                     "after", "active: focusId2"})
241     @HtmlUnitNYI(FF = {"before", "active: body",
242                        "onfocusin:focusId1", "active: focusId1",
243                        "onfocusout:focusId1", "active: body", "onfocusin:focusId2", "active: focusId2",
244                        "after", "active: focusId2"},
245             FF_ESR = {"before", "active: body",
246                       "onfocusin:focusId1", "active: focusId1",
247                       "onfocusout:focusId1", "active: body", "onfocusin:focusId2", "active: focusId2",
248                       "after", "active: focusId2"})
249     // TODO FF & FF68 fail due to wrong body vs. window event handling
250     public void bodySwitchFromFocusableToFocusable() throws Exception {
251         testBodySwitchWithCallFocusAndBlur("<input type='text' id='focusId1'>\n"
252             + "<input type='text' id='focusId2'>");
253     }
254 
255     private void testBodySwitchWithCallFocusAndBlur(final String snippet) throws Exception {
256         final String html = DOCTYPE_HTML
257             + "<html>\n"
258             + "  <head>\n"
259             + "    <script>\n"
260             + logger()
261             + "      function test() {\n"
262             + "        log('before');\n"
263             + "        document.getElementById('focusId1').focus();\n"
264             + "        document.getElementById('focusId2').focus();\n"
265             + "        log('after');\n"
266             + "      }\n"
267             + "    </script>\n"
268             + "  </head>\n"
269             + "  <body id='body' onload='setTimeout(test, 10)' " + logEvents("") + ">\n"
270             + snippet
271             + "  </body>\n"
272             + "</html>\n";
273 
274         final WebDriver driver = loadPage2(html);
275         assertTitle(driver, String.join(";", getExpectedAlerts()) + (getExpectedAlerts().length > 0 ? ";" : ""));
276     }
277 
278     /**
279      * @throws Exception if the test fails
280      */
281     @Test
282     @Alerts({"before", "active: body", "between", "active: body", "after", "active: body"})
283     public void notFocusable() throws Exception {
284         testWithCallFocusAndBlur("<div id='focusId'>div</div>");
285     }
286 
287     /**
288      * @throws Exception if the test fails
289      */
290     @Test
291     @Alerts({"before", "active: body", "between", "active: body", "after", "active: body"})
292     public void notFocusableWithTabIndexEmpty() throws Exception {
293         testWithCallFocusAndBlur("<div tabindex='' id='focusId'>div</div>");
294     }
295 
296     /**
297      * @throws Exception if the test fails
298      */
299     @Test
300     @Alerts({"before", "active: body",
301              "onfocus:focusId", "active: focusId", "onfocusin:focusId", "active: focusId",
302              "between", "active: focusId",
303              "onblur:focusId", "active: body", "onfocusout:focusId", "active: body",
304              "after", "active: body"})
305     public void notFocusableWithTabIndexNegative() throws Exception {
306         testWithCallFocusAndBlur("<div tabindex='-1' id='focusId'>div</div>");
307     }
308 
309     /**
310      * @throws Exception if the test fails
311      */
312     @Test
313     @Alerts({"before", "active: body",
314              "onfocus:focusId", "active: focusId", "onfocusin:focusId", "active: focusId",
315              "between", "active: focusId",
316              "onblur:focusId", "active: body", "onfocusout:focusId", "active: body",
317              "after", "active: body"})
318     public void notFocusableWithTabIndexZero() throws Exception {
319         testWithCallFocusAndBlur("<div tabindex='0' id='focusId'>div</div>");
320     }
321 
322     /**
323      * @throws Exception if the test fails
324      */
325     @Test
326     @Alerts({"before", "active: body",
327              "onfocus:focusId", "active: focusId", "onfocusin:focusId", "active: focusId",
328              "between", "active: focusId",
329              "onblur:focusId", "active: body", "onfocusout:focusId", "active: body",
330              "after", "active: body"})
331     public void notFocusableWithTabIndexPositive() throws Exception {
332         testWithCallFocusAndBlur("<div tabindex='1' id='focusId'>div</div>");
333     }
334 
335     /**
336      * @throws Exception if the test fails
337      */
338     @Test
339     @Alerts({"before", "active: body", "between", "active: body", "after", "active: body"})
340     public void notFocusableWithTabIndexNotDisplayed() throws Exception {
341         testWithCallFocusAndBlur("<div tabindex='0' style='display: none;' id='focusId'>div</div>");
342     }
343 
344     /**
345      * @throws Exception if the test fails
346      */
347     @Test
348     @Alerts({"before", "active: body", "between", "active: body", "after", "active: body"})
349     public void notFocusableWithTabIndexNotVisible() throws Exception {
350         testWithCallFocusAndBlur("<div tabindex='0' style='visibility: hidden;' id='focusId'>div</div>");
351     }
352 
353     /**
354      * @throws Exception if the test fails
355      */
356     @Test
357     @Alerts({"before", "active: body", "between", "active: body", "after", "active: body"})
358     public void notFocusableWithTabIndexHidden() throws Exception {
359         testWithCallFocusAndBlur("<div tabindex='0' hidden id='focusId'>div</div>");
360     }
361 
362     /**
363      * @throws Exception if the test fails
364      */
365     @Test
366     @Alerts({"before", "active: body",
367              "onfocus:focusId", "active: focusId", "onfocusin:focusId", "active: focusId",
368              "between", "active: focusId",
369              "onblur:focusId", "active: body", "onfocusout:focusId", "active: body",
370              "after", "active: body"})
371     public void anchor() throws Exception {
372         testWithCallFocusAndBlur("<a href='#' id='focusId'>link</a>");
373     }
374 
375     /**
376      * @throws Exception if the test fails
377      */
378     @Test
379     @Alerts({"before", "active: body",
380              "onfocus:focusId", "active: focusId", "onfocusin:focusId", "active: focusId",
381              "between", "active: focusId",
382              "onblur:focusId", "active: body", "onfocusout:focusId", "active: body",
383              "after", "active: body"})
384     public void anchorWithEmptyHref() throws Exception {
385         testWithCallFocusAndBlur("<a href='' id='focusId'>link</a>");
386     }
387 
388     /**
389      * @throws Exception if the test fails
390      */
391     @Test
392     @Alerts({"before", "active: body", "between", "active: body", "after", "active: body"})
393     public void anchorWithoutHref() throws Exception {
394         testWithCallFocusAndBlur("<a id='focusId'>link</a>");
395     }
396 
397     /**
398      * @throws Exception if the test fails
399      */
400     @Test
401     @Alerts({"before", "active: body",
402              "onfocus:focusId", "active: focusId", "onfocusin:focusId", "active: focusId",
403              "between", "active: focusId",
404              "onblur:focusId", "active: body", "onfocusout:focusId", "active: body",
405              "after", "active: body"})
406     public void area() throws Exception {
407         testWithCallFocusAndBlur("<map name='dot'><area shape='rect' coords='0,0,5,5' href='#' id='focusId' /></map>"
408             + "<img usemap='#dot'"
409             + " src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAA"
410             + "HElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=='>");
411     }
412 
413     /**
414      * @throws Exception if the test fails
415      */
416     @Test
417     @Alerts({"before", "active: body",
418              "onfocus:focusId", "active: focusId", "onfocusin:focusId", "active: focusId",
419              "between", "active: focusId",
420              "onblur:focusId", "active: body", "onfocusout:focusId", "active: body",
421              "after", "active: body"})
422     public void areaWithEmptyHref() throws Exception {
423         testWithCallFocusAndBlur("<img usemap='#dot'"
424             + " src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAA"
425             + "HElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=='>\n"
426             + "<map name='dot'><area shape='rect' coords='0,0,1,1' href='' id='focusId' /></map>");
427     }
428 
429     /**
430      * @throws Exception if the test fails
431      */
432     @Test
433     @Alerts(DEFAULT = {"before", "active: body", "between", "active: body", "after", "active: body"},
434             FF = {"before", "active: body",
435                   "onfocus:focusId", "active: focusId", "onfocusin:focusId", "active: focusId",
436                   "between", "active: focusId",
437                   "onblur:focusId", "active: body", "onfocusout:focusId",
438                   "active: body", "after", "active: body"},
439             FF_ESR = {"before", "active: body",
440                       "onfocus:focusId", "active: focusId", "onfocusin:focusId", "active: focusId",
441                       "between", "active: focusId",
442                       "onblur:focusId", "active: body", "onfocusout:focusId",
443                       "active: body", "after", "active: body"})
444     public void areaWithoutHref() throws Exception {
445         testWithCallFocusAndBlur("<img usemap='#dot'"
446             + " src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAA"
447             + "HElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=='>\n"
448             + "<map name='dot'><area shape='rect' coords='0,0,1,1' id='focusId' /></map>");
449     }
450 
451     /**
452      * @throws Exception if the test fails
453      */
454     @Test
455     @Alerts({"before", "active: body",
456              "onfocus:focusId", "active: focusId", "onfocusin:focusId", "active: focusId",
457              "between", "active: focusId",
458              "onblur:focusId", "active: body", "onfocusout:focusId", "active: body",
459              "after", "active: body"})
460     public void button() throws Exception {
461         testWithCallFocusAndBlur("<button id='focusId'>button</button>");
462     }
463 
464     /**
465      * @throws Exception if the test fails
466      */
467     @Test
468     @Alerts({"before", "active: body",
469              "onfocus:focusId", "active: focusId", "onfocusin:focusId", "active: focusId",
470              "between", "active: focusId",
471              "onblur:focusId", "active: body", "onfocusout:focusId", "active: body",
472              "after", "active: body"})
473     public void input() throws Exception {
474         testWithCallFocusAndBlur("<input type='text' id='focusId'>");
475     }
476 
477     /**
478      * @throws Exception if the test fails
479      */
480     @Test
481     @Alerts({"before", "active: body", "between", "active: body", "after", "active: body"})
482     public void inputHidden() throws Exception {
483         testWithCallFocusAndBlur("<input type='hidden' id='focusId'>");
484     }
485 
486     /**
487      * @throws Exception if the test fails
488      */
489     @Test
490     @Alerts({"before", "active: body",
491              "onfocusT:textId", "active: textId", "onfocusinT:textId", "active: textId",
492              "between", "active: textId", "after", "active: textId"})
493     public void labelFor() throws Exception {
494         testWithCallFocusAndBlur("<label for='textId' id='focusId'>label</label><input type='text' id='textId' "
495                 + logEvents("T") + ">");
496     }
497 
498     /**
499      * @throws Exception if the test fails
500      */
501     @Test
502     @Alerts({"before", "active: body", "between", "active: body", "after", "active: body"})
503     public void labelForDisabled() throws Exception {
504         testWithCallFocusAndBlur("<label for='textId' id='focusId'>label</label>"
505                 + "<input type='text' disabled id='textId' " + logEvents("T") + ">");
506     }
507 
508     /**
509      * @throws Exception if the test fails
510      */
511     @Test
512     @Alerts({"before", "active: body",
513              "onfocusT:textId", "active: textId", "onfocusinT:textId", "active: textId",
514              "between", "active: textId", "after", "active: textId"})
515     public void labelForReadonly() throws Exception {
516         testWithCallFocusAndBlur("<label for='textId' id='focusId'>label</label>"
517                 + "<input type='text' readonly id='textId' " + logEvents("T") + ">");
518     }
519 
520     /**
521      * @throws Exception if the test fails
522      */
523     @Test
524     @Alerts({"before", "active: body", "between", "active: body", "after", "active: body"})
525     public void labelForNotDisplayed() throws Exception {
526         testWithCallFocusAndBlur("<label for='textId' id='focusId'>label"
527                 + "</label><input type='text' style='display: none;' id='textId' " + logEvents("T") + ">");
528     }
529 
530     /**
531      * @throws Exception if the test fails
532      */
533     @Test
534     @Alerts({"before", "active: body", "between", "active: body", "after", "active: body"})
535     public void labelForNotVisible() throws Exception {
536         testWithCallFocusAndBlur("<label for='textId' id='focusId'>label</label>"
537                 + "<input type='text' style='visibility: hidden;' id='textId' " + logEvents("T") + ">");
538     }
539 
540     /**
541      * @throws Exception if the test fails
542      */
543     @Test
544     @Alerts({"before", "active: body", "between", "active: body", "after", "active: body"})
545     public void labelForHidden() throws Exception {
546         testWithCallFocusAndBlur("<label for='textId' id='focusId'>label</label>"
547                 + "<input type='text' hidden id='textId' " + logEvents("T") + ">");
548     }
549 
550     /**
551      * @throws Exception if the test fails
552      */
553     @Test
554     @Alerts({"before", "active: body",
555              "onfocusT:textId", "active: textId", "onfocusinT:textId", "active: textId",
556              "between", "active: textId", "after", "active: textId"})
557     public void labelNotDisplayedFor() throws Exception {
558         testWithCallFocusAndBlur("<label for='textId' style='display: none;' id='focusId'>label</label>"
559                 + "<input type='text' id='textId' " + logEvents("T") + ">");
560     }
561 
562     /**
563      * @throws Exception if the test fails
564      */
565     @Test
566     @Alerts({"before", "active: body",
567              "onfocusT:textId", "active: textId", "onfocusinT:textId", "active: textId",
568              "between", "active: textId", "after", "active: textId"})
569     public void labelNotVisibleFor() throws Exception {
570         testWithCallFocusAndBlur("<label for='textId' style='visibility: hidden;' id='focusId'>label</label>"
571                 + "<input type='text' id='textId' " + logEvents("T") + ">");
572     }
573 
574     /**
575      * @throws Exception if the test fails
576      */
577     @Test
578     @Alerts({"before", "active: body",
579              "onfocusT:textId", "active: textId", "onfocusinT:textId", "active: textId",
580              "between", "active: textId", "after", "active: textId"})
581     public void labelHiddenFor() throws Exception {
582         testWithCallFocusAndBlur("<label for='textId' hidden id='focusId'>label</label>"
583                 + "<input type='text' id='textId' " + logEvents("T") + ">");
584     }
585 
586     /**
587      * @throws Exception if the test fails
588      */
589     @Test
590     @Alerts({"before", "active: body",
591              "onfocusT:textId", "active: textId", "onfocusinT:textId",
592              "active: textId", "onfocusin:textId", "active: textId",
593              "between", "active: textId", "after", "active: textId"})
594     public void labelNested() throws Exception {
595         testWithCallFocusAndBlur("<label for='textId' id='focusId'>label <input type='text' id='textId' "
596                 + logEvents("T") + "></label>");
597     }
598 
599     /**
600      * @throws Exception if the test fails
601      */
602     @Test
603     @Alerts({"before", "active: body", "between", "active: body", "after", "active: body"})
604     public void labelNestedDisabled() throws Exception {
605         testWithCallFocusAndBlur("<label for='textId' id='focusId'>label "
606                 + "<input type='text' disabled id='textId' " + logEvents("T") + "></label>");
607     }
608 
609     /**
610      * @throws Exception if the test fails
611      */
612     @Test
613     @Alerts({"before", "active: body",
614              "onfocusT:textId", "active: textId", "onfocusinT:textId",
615              "active: textId", "onfocusin:textId", "active: textId",
616              "between", "active: textId", "after", "active: textId"})
617     public void labelNestedReadonly() throws Exception {
618         testWithCallFocusAndBlur("<label for='textId' id='focusId'>label <input type='text' readonly id='textId' "
619                 + logEvents("T") + "></label>");
620     }
621 
622     /**
623      * @throws Exception if the test fails
624      */
625     @Test
626     @Alerts({"before", "active: body", "between", "active: body", "after", "active: body"})
627     public void labelNestedNotDisplayed() throws Exception {
628         testWithCallFocusAndBlur("<label for='textId' id='focusId'>label "
629                 + "<input type='text' style='display: none;' id='textId' " + logEvents("T") + "></label>");
630     }
631 
632     /**
633      * @throws Exception if the test fails
634      */
635     @Test
636     @Alerts({"before", "active: body", "between", "active: body", "after", "active: body"})
637     public void labelNestedNotVisible() throws Exception {
638         testWithCallFocusAndBlur("<label for='textId' id='focusId'>label "
639                 + "<input type='text' style='display: none;' id='textId' "
640                 + logEvents("T") + "></label>");
641     }
642 
643     /**
644      * @throws Exception if the test fails
645      */
646     @Test
647     @Alerts({"before", "active: body", "between", "active: body", "after", "active: body"})
648     public void labelNestedHidden() throws Exception {
649         testWithCallFocusAndBlur("<label for='textId' id='focusId'>label <input type='text' hidden id='textId' "
650                 + logEvents("T") + "></label>");
651     }
652 
653     /**
654      * @throws Exception if the test fails
655      */
656     @Test
657     @Alerts({"before", "active: body", "between", "active: body", "after", "active: body"})
658     public void labelNotDisplayedNested() throws Exception {
659         testWithCallFocusAndBlur("<label for='textId' style='display: none;' id='focusId'>label "
660                 + "<input type='text' id='textId' " + logEvents("T") + "></label>");
661     }
662 
663     /**
664      * @throws Exception if the test fails
665      */
666     @Test
667     @Alerts({"before", "active: body", "between", "active: body", "after", "active: body"})
668     public void labelNotVisibleNested() throws Exception {
669         testWithCallFocusAndBlur("<label for='textId' style='visibility: hidden;' id='focusId'>label "
670                 + "<input type='text' id='textId' " + logEvents("T") + "></label>");
671     }
672 
673     /**
674      * @throws Exception if the test fails
675      */
676     @Test
677     @Alerts({"before", "active: body", "between", "active: body", "after", "active: body"})
678     public void labelHiddenNested() throws Exception {
679         testWithCallFocusAndBlur("<label for='textId' hidden id='focusId'>label "
680                 + "<input type='text' id='textId' " + logEvents("T") + "></label>");
681     }
682 
683     /**
684      * @throws Exception if the test fails
685      */
686     @Test
687     @Alerts({"before", "active: body", "between", "active: body", "after", "active: body"})
688     public void optionGroup() throws Exception {
689         testWithCallFocusAndBlur("<select><optgroup label='group' id='focusId'><option>1</option></optgroup></select>");
690     }
691 
692     /**
693      * @throws Exception if the test fails
694      */
695     @Test
696     @Alerts({"before", "active: body", "between", "active: body", "after", "active: body"})
697     public void option() throws Exception {
698         testWithCallFocusAndBlur("<select><option id='focusId'>1</option></select>");
699     }
700 
701     /**
702      * @throws Exception if the test fails
703      */
704     @Test
705     @Alerts({"before", "active: body",
706              "onfocus:focusId", "active: focusId", "onfocusin:focusId", "active: focusId",
707              "between", "active: focusId",
708              "onblur:focusId", "active: body", "onfocusout:focusId", "active: body",
709              "after", "active: body"})
710     public void select() throws Exception {
711         testWithCallFocusAndBlur("<select id='focusId'><option>1</option></select>");
712     }
713 
714     /**
715      * @throws Exception if the test fails
716      */
717     @Test
718     @Alerts({"before", "active: body",
719              "onfocus:focusId", "active: focusId", "onfocusin:focusId", "active: focusId",
720              "between", "active: focusId",
721              "onblur:focusId", "active: body", "onfocusout:focusId", "active: body",
722              "after", "active: body"})
723     public void textArea() throws Exception {
724         testWithCallFocusAndBlur("<textarea id='focusId'></textarea>");
725     }
726 
727     /**
728      * @throws Exception if the test fails
729      */
730     @Test
731     @Alerts({"before", "active: body", "between", "active: body", "after", "active: body"})
732     public void focusableDisabled() throws Exception {
733         testWithCallFocusAndBlur("<input type='text' disabled id='focusId'>");
734     }
735 
736     /**
737      * @throws Exception if the test fails
738      */
739     @Test
740     @Alerts({"before", "active: body",
741              "onfocus:focusId", "active: focusId", "onfocusin:focusId", "active: focusId",
742              "between", "active: focusId",
743              "onblur:focusId", "active: body", "onfocusout:focusId", "active: body",
744              "after", "active: body"})
745     public void focusableReadonly() throws Exception {
746         testWithCallFocusAndBlur("<input type='text' readonly id='focusId'>");
747     }
748 
749     /**
750      * @throws Exception if the test fails
751      */
752     @Test
753     @Alerts({"before", "active: body", "between", "active: body", "after", "active: body"})
754     public void focusableNotDisplayed() throws Exception {
755         testWithCallFocusAndBlur("<input type='text' style='display: none;' id='focusId'>");
756     }
757 
758     /**
759      * @throws Exception if the test fails
760      */
761     @Test
762     @Alerts({"before", "active: body", "between", "active: body", "after", "active: body"})
763     public void focusableNotVisible() throws Exception {
764         testWithCallFocusAndBlur("<input type='text' style='visibility: hidden;' id='focusId'>");
765     }
766 
767     /**
768      * @throws Exception if the test fails
769      */
770     @Test
771     @Alerts({"before", "active: body", "between", "active: body", "after", "active: body"})
772     public void focusableHidden() throws Exception {
773         testWithCallFocusAndBlur("<input type='text' hidden id='focusId'>");
774     }
775 
776     private void testWithCallFocusAndBlur(String snippet) throws Exception {
777         snippet = snippet.replaceFirst("id='focusId'( /)?>", "id='focusId' " + logEvents("") + "$1>");
778 
779         final String html = DOCTYPE_HTML
780             + "<html>\n"
781             + "  <head>\n"
782             + "    <script>\n"
783             + logger()
784             + "      function test() {\n"
785             + "        log('before');\n"
786             + "        document.getElementById('focusId').focus();\n"
787             + "        document.getElementById('focusId').focus();\n"
788             + "        log('between');\n"
789             + "        document.getElementById('focusId').blur();\n"
790             + "        document.getElementById('focusId').blur();\n"
791             + "        log('after');\n"
792             + "      }\n"
793             + "    </script>\n"
794             + "  </head>\n"
795             + "  <body id='body' onload='setTimeout(test, 10)'>\n"
796             + snippet
797             + "  </body>\n"
798             + "</html>\n";
799 
800         final WebDriver driver = loadPage2(html);
801         assertTitle(driver, String.join(";", getExpectedAlerts()) + (getExpectedAlerts().length > 0 ? ";" : ""));
802     }
803 
804     /**
805      * @throws Exception if the test fails
806      */
807     @Test
808     @Alerts({"before", "active: body",
809              "onfocus1:focusId1", "active: focusId1", "onfocusin1:focusId1", "active: focusId1",
810              "after", "active: focusId1"})
811     public void switchFromFocusableToNotFocusable() throws Exception {
812         testSwitchWithCallFocusAndBlur("<input type='text' id='focusId1'>\n"
813             + "<div id='focusId2'>div</div>");
814     }
815 
816     /**
817      * @throws Exception if the test fails
818      */
819     @Test
820     @Alerts({"before", "active: body",
821              "onfocus1:focusId1", "active: focusId1", "onfocusin1:focusId1", "active: focusId1",
822              "onblur1:focusId1", "active: body", "onfocusout1:focusId1", "active: body",
823              "onfocus2:focusId2", "active: focusId2", "onfocusin2:focusId2", "active: focusId2",
824              "after", "active: focusId2"})
825     public void switchFromFocusableToFocusable() throws Exception {
826         testSwitchWithCallFocusAndBlur("<input type='text' id='focusId1'>\n"
827             + "<input type='text' id='focusId2'>");
828     }
829 
830     /**
831      * @throws Exception if the test fails
832      */
833     @Test
834     @Alerts({"before", "active: body",
835              "onfocus1:focusId1", "active: focusId1", "onfocusin1:focusId1", "active: focusId1",
836              "after", "active: focusId1"})
837     public void switchFromFocusableToFocusableDisabled() throws Exception {
838         testSwitchWithCallFocusAndBlur("<input type='text' id='focusId1'>\n"
839             + "<input type='text' disabled id='focusId2'>");
840     }
841 
842     /**
843      * @throws Exception if the test fails
844      */
845     @Test
846     @Alerts({"before", "active: body",
847              "onfocus1:focusId1", "active: focusId1", "onfocusin1:focusId1", "active: focusId1",
848              "onblur1:focusId1", "active: body", "onfocusout1:focusId1", "active: body",
849              "onfocus2:focusId2", "active: focusId2", "onfocusin2:focusId2", "active: focusId2",
850              "after", "active: focusId2"})
851     public void switchFromFocusableToFocusableReadonly() throws Exception {
852         testSwitchWithCallFocusAndBlur("<input type='text' id='focusId1'>\n"
853             + "<input type='text' readonly id='focusId2'>");
854     }
855 
856     /**
857      * @throws Exception if the test fails
858      */
859     @Test
860     @Alerts({"before", "active: body",
861              "onfocus1:focusId1", "active: focusId1", "onfocusin1:focusId1", "active: focusId1",
862              "after", "active: focusId1"})
863     public void switchFromFocusableToFocusableNotDisplayed() throws Exception {
864         testSwitchWithCallFocusAndBlur("<input type='text' id='focusId1'>\n"
865             + "<input type='text' style='display: none;' id='focusId2'>");
866     }
867 
868     /**
869      * @throws Exception if the test fails
870      */
871     @Test
872     @Alerts({"before", "active: body",
873              "onfocus1:focusId1", "active: focusId1", "onfocusin1:focusId1", "active: focusId1",
874              "after", "active: focusId1"})
875     public void switchFromFocusableToFocusableNotVisible() throws Exception {
876         testSwitchWithCallFocusAndBlur("<input type='text' id='focusId1'>\n"
877             + "<input type='text' style='visibility: hidden;' id='focusId2'>");
878     }
879 
880     /**
881      * @throws Exception if the test fails
882      */
883     @Test
884     @Alerts({"before", "active: body",
885              "onfocus1:focusId1", "active: focusId1", "onfocusin1:focusId1", "active: focusId1",
886              "after", "active: focusId1"})
887     public void switchFromFocusableToFocusableHidden() throws Exception {
888         testSwitchWithCallFocusAndBlur("<input type='text' id='focusId1'>\n"
889             + "<input type='text' hidden id='focusId2'>");
890     }
891 
892     private void testSwitchWithCallFocusAndBlur(String snippet) throws Exception {
893         snippet = snippet.replaceFirst("id='focusId1'( /)?>", "id='focusId1' " + logEvents("1") + "$1>");
894         snippet = snippet.replaceFirst("id='focusId2'( /)?>", "id='focusId2' " + logEvents("2") + "$1>");
895 
896         final String html = DOCTYPE_HTML
897             + "<html>\n"
898             + "  <head>\n"
899             + "    <script>\n"
900             + logger()
901             + "      function test() {\n"
902             + "        log('before');\n"
903             + "        document.getElementById('focusId1').focus();\n"
904             + "        document.getElementById('focusId2').focus();\n"
905             + "        log('after');\n"
906             + "      }\n"
907             + "    </script>\n"
908             + "  </head>\n"
909             + "  <body id='body' onload='setTimeout(test, 10)'>\n"
910             + snippet
911             + "  </body>\n"
912             + "</html>\n";
913 
914         final WebDriver driver = loadPage2(html);
915         assertTitle(driver, String.join(";", getExpectedAlerts()) + (getExpectedAlerts().length > 0 ? ";" : ""));
916     }
917 
918     /**
919      * @throws Exception if the test fails
920      */
921     @Test
922     @Alerts({"before", "active: body", "after", "active: body"})
923     public void jsClickOnNotFocusable() throws Exception {
924         testWithCallClick("<div id='focusId'>div</div>");
925     }
926 
927     /**
928      * @throws Exception if the test fails
929      */
930     @Test
931     @Alerts({"before", "active: body", "after", "active: body"})
932     @HtmlUnitNYI(CHROME = {"before", "active: body",
933                            "onfocus:focusId", "active: focusId", "onfocusin:focusId", "active: focusId",
934                            "onblur:focusId", "active: body", "onfocusout:focusId", "active: body",
935                            "after", "active: body"},
936             EDGE = {"before", "active: body",
937                     "onfocus:focusId", "active: focusId", "onfocusin:focusId", "active: focusId",
938                     "onblur:focusId", "active: body", "onfocusout:focusId", "active: body",
939                     "after", "active: body"},
940             FF = {"before", "active: body",
941                   "onfocus:focusId", "active: focusId", "onfocusin:focusId", "active: focusId",
942                   "onblur:focusId", "active: body", "onfocusout:focusId", "active: body",
943                   "after", "active: body"},
944             FF_ESR = {"before", "active: body",
945                       "onfocus:focusId", "active: focusId", "onfocusin:focusId", "active: focusId",
946                       "onblur:focusId", "active: body", "onfocusout:focusId", "active: body",
947                       "after", "active: body"})
948     // FIXME click for either divs or inputs seems broken... :(
949     public void jsClickOnNotFocusableWithTabIndex() throws Exception {
950         testWithCallClick("<div tabindex='0' id='focusId'>div</div>");
951     }
952 
953     /**
954      * @throws Exception if the test fails
955      */
956     @Test
957     @Alerts({"before", "active: body", "after", "active: body"})
958     public void jsClickOnFocusable() throws Exception {
959         testWithCallClick("<input type='text' id='focusId'>");
960     }
961 
962     private void testWithCallClick(String snippet) throws Exception {
963         snippet = snippet.replaceFirst("id='focusId'( /)?>", "id='focusId' " + logEvents("") + "$1>");
964 
965         final String html = DOCTYPE_HTML
966             + "<html>\n"
967             + "  <head>\n"
968             + "    <script>\n"
969             + logger()
970             + "      function test() {\n"
971             + "        log('before');\n"
972             + "        document.getElementById('focusId').click();\n"
973             + "        document.getElementById('focusId').click();\n"
974             + "        document.getElementById('otherId').click();\n"
975             + "        log('after');\n"
976             + "      }\n"
977             + "    </script>\n"
978             + "  </head>\n"
979             + "  <body id='body' onload='setTimeout(test, 10)'>\n"
980             + snippet
981             + "    <div id='otherId'>div</div>\n"
982             + "  </body>\n"
983             + "</html>\n";
984 
985         final WebDriver driver = loadPage2(html);
986         assertTitle(driver, String.join(";", getExpectedAlerts()) + (getExpectedAlerts().length > 0 ? ";" : ""));
987     }
988 
989     /**
990      * @throws Exception if the test fails
991      */
992     @Test
993     public void clickOnNotFocusable() throws Exception {
994         testWithClick("<div id='focusId'>div</div>");
995     }
996 
997     /**
998      * @throws Exception if the test fails
999      */
1000     @Test
1001     @Alerts({"onfocus:focusId", "active: focusId", "onfocusin:focusId", "active: focusId",
1002              "onblur:focusId", "active: body", "onfocusout:focusId", "active: body"})
1003     public void clickOnNotFocusableWithTabIndex() throws Exception {
1004         testWithClick("<div tabindex='0' id='focusId'>div</div>");
1005     }
1006 
1007     /**
1008      * @throws Exception if the test fails
1009      */
1010     @Test
1011     @Alerts({"onfocus:focusId", "active: focusId", "onfocusin:focusId", "active: focusId",
1012              "onblur:focusId", "active: body", "onfocusout:focusId", "active: body"})
1013     public void clickOnFocusable() throws Exception {
1014         testWithClick("<input type='text' id='focusId'>");
1015     }
1016 
1017     /**
1018      * @throws Exception if the test fails
1019      */
1020     @Test
1021     public void clickOnFocusableDisabled() throws Exception {
1022         testWithClick("<input type='text' disabled id='focusId'>");
1023     }
1024 
1025     /**
1026      * @throws Exception if the test fails
1027      */
1028     @Test
1029     @Alerts({"onfocus:focusId", "active: focusId", "onfocusin:focusId", "active: focusId",
1030              "onblur:focusId", "active: body", "onfocusout:focusId", "active: body"})
1031     public void clickOnFocusableReadonly() throws Exception {
1032         testWithClick("<input type='text' readonly id='focusId'>");
1033     }
1034 
1035     /**
1036      * @throws Exception if the test fails
1037      */
1038     @Test
1039     @Alerts({"onfocusT:textId", "active: textId", "onfocusinT:textId", "active: textId",
1040              "onblurT:textId", "active: body", "onfocusoutT:textId", "active: body"})
1041     public void clickOnLabelFor() throws Exception {
1042         testWithClick("<label for='textId' id='focusId'>label</label><input type='text' id='textId' "
1043                 + logEvents("T") + ">");
1044     }
1045 
1046     /**
1047      * @throws Exception if the test fails
1048      */
1049     @Test
1050     @Alerts({"onfocusT:textId", "active: textId", "onfocusinT:textId",
1051              "active: textId", "onfocusin:textId", "active: textId",
1052              "onblurT:textId", "active: body", "onfocusoutT:textId",
1053              "active: body", "onfocusout:textId", "active: body"})
1054     public void clickOnLabelNested() throws Exception {
1055         testWithClick("<label for='textId' id='focusId'>label <input type='text' id='textId' "
1056                 + logEvents("T") + "></label>");
1057     }
1058 
1059     private void testWithClick(String snippet) throws Exception {
1060         snippet = snippet.replaceFirst("id='focusId'( /)?>", "id='focusId' " + logEvents("") + "$1>");
1061 
1062         final String html = DOCTYPE_HTML
1063             + "<html>\n"
1064             + "  <head>\n"
1065             + "    <script>\n"
1066             + logger()
1067             + "    </script>\n"
1068             + "  </head>\n"
1069             + "  <body id='body'>\n"
1070             + snippet
1071             + "    <div id='otherId'>div</div>\n"
1072             + "  </body>\n"
1073             + "</html>\n";
1074 
1075         final WebDriver driver = loadPage2(html);
1076 
1077         driver.findElement(By.id("focusId")).click();
1078         driver.findElement(By.id("otherId")).click();
1079 
1080         assertTitle(driver, String.join(";", getExpectedAlerts()) + (getExpectedAlerts().length > 0 ? ";" : ""));
1081     }
1082 
1083     /**
1084      * @throws Exception if the test fails
1085      */
1086     @Test
1087     @Alerts({"onfocus1:focusId1", "active: focusId1", "onfocusin1:focusId1", "active: focusId1",
1088              "onblur1:focusId1", "active: body", "onfocusout1:focusId1", "active: body",
1089              "onfocus2:focusId2", "active: focusId2", "onfocusin2:focusId2", "active: focusId2"})
1090     public void clickFromFocusableToFocusable() throws Exception {
1091         testSwitchWithClick("<input type='text' id='focusId1'>\n"
1092             + "<input type='text' id='focusId2'>");
1093     }
1094 
1095     /**
1096      * @throws Exception if the test fails
1097      */
1098     @Test
1099     @Alerts({"onfocus1:focusId1", "active: focusId1", "onfocusin1:focusId1", "active: focusId1",
1100              "onblur1:focusId1", "active: body", "onfocusout1:focusId1", "active: body"})
1101     @HtmlUnitNYI(CHROME = {"onfocus1:focusId1", "active: focusId1", "onfocusin1:focusId1", "active: focusId1"},
1102             EDGE = {"onfocus1:focusId1", "active: focusId1", "onfocusin1:focusId1", "active: focusId1"},
1103             FF = {"onfocus1:focusId1", "active: focusId1", "onfocusin1:focusId1", "active: focusId1"},
1104             FF_ESR = {"onfocus1:focusId1", "active: focusId1", "onfocusin1:focusId1", "active: focusId1"})
1105     public void clickFromFocusableToFocusableDisabled() throws Exception {
1106         testSwitchWithClick("<input type='text' id='focusId1'>\n"
1107             + "<input type='text' disabled id='focusId2'>");
1108     }
1109 
1110     /**
1111      * @throws Exception if the test fails
1112      */
1113     @Test
1114     @Alerts({"onfocus1:focusId1", "active: focusId1", "onfocusin1:focusId1", "active: focusId1",
1115              "onblur1:focusId1", "active: body", "onfocusout1:focusId1", "active: body",
1116              "onfocus2:focusId2", "active: focusId2", "onfocusin2:focusId2", "active: focusId2"})
1117     public void clickFromFocusableToFocusableReadonly() throws Exception {
1118         testSwitchWithClick("<input type='text' id='focusId1'>\n"
1119             + "<input type='text' readonly id='focusId2'>");
1120     }
1121 
1122     private void testSwitchWithClick(String snippet) throws Exception {
1123         snippet = snippet.replaceFirst("id='focusId1'( /)?>", "id='focusId1' " + logEvents("1") + "$1>");
1124         snippet = snippet.replaceFirst("id='focusId2'( /)?>", "id='focusId2' " + logEvents("2") + "$1>");
1125 
1126         final String html = DOCTYPE_HTML
1127             + "<html>\n"
1128             + "  <head>\n"
1129             + "    <script>\n"
1130             + logger()
1131             + "    </script>\n"
1132             + "  </head>\n"
1133             + "  <body id='body'>\n"
1134             + snippet
1135             + "  </body>\n"
1136             + "</html>\n";
1137 
1138         final WebDriver driver = loadPage2(html);
1139 
1140         driver.findElement(By.id("focusId1")).click();
1141         driver.findElement(By.id("focusId2")).click();
1142 
1143         assertTitle(driver, String.join(";", getExpectedAlerts()) + (getExpectedAlerts().length > 0 ? ";" : ""));
1144     }
1145 
1146     private static String logger() {
1147         return  "      function log(x, e) {\n"
1148             + "        document.title += x + (e ? ':' + (e.target.id ? e.target.id : e.target) : '') + ';';\n"
1149             + "        document.title += 'active: ' "
1150                         + "+ (document.activeElement ? document.activeElement.id : 'null') + ';';\n"
1151             + "      }\n";
1152     }
1153 
1154     private static String logEvents(final String aSuffix) {
1155         return "onblur=\"log('onblur" + aSuffix + "', event)\" "
1156             + "onfocusin=\"log('onfocusin" + aSuffix + "', event)\" "
1157             + "onfocusout=\"log('onfocusout" + aSuffix + "', event)\" "
1158             + "onfocus=\"log('onfocus" + aSuffix + "', event)\"";
1159     }
1160 }