View Javadoc
1   /*
2    * Copyright (c) 2002-2026 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.javascript.host.event;
16  
17  import static org.htmlunit.javascript.configuration.SupportedBrowser.FF;
18  import static org.htmlunit.javascript.configuration.SupportedBrowser.FF_ESR;
19  
20  import java.util.ArrayList;
21  
22  import org.htmlunit.ScriptResult;
23  import org.htmlunit.corejs.javascript.Context;
24  import org.htmlunit.corejs.javascript.Scriptable;
25  import org.htmlunit.corejs.javascript.ScriptableObject;
26  import org.htmlunit.html.DomNode;
27  import org.htmlunit.javascript.HtmlUnitScriptable;
28  import org.htmlunit.javascript.JavaScriptEngine;
29  import org.htmlunit.javascript.configuration.JsxClass;
30  import org.htmlunit.javascript.configuration.JsxConstant;
31  import org.htmlunit.javascript.configuration.JsxConstructor;
32  import org.htmlunit.javascript.configuration.JsxFunction;
33  import org.htmlunit.javascript.configuration.JsxGetter;
34  import org.htmlunit.javascript.configuration.JsxSetter;
35  
36  /**
37   * JavaScript host object for {@code Event}.
38   *
39   * @author Chris Eldredge
40   * @author Mike Bowler
41   * @author Chris Erskine
42   * @author Marc Guillemot
43   * @author Daniel Gredler
44   * @author Brad Murray
45   * @author Ahmed Ashour
46   * @author Rob Di Marco
47   * @author Ronald Brill
48   * @author Frank Danek
49   * @author Atsushi Nakagawa
50   * @author Thorsten Wendelmuth
51   *
52   * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/Event">MDN Documentation</a>
53   */
54  @JsxClass
55  public class Event extends HtmlUnitScriptable {
56  
57      /**
58       * Key to place the event's target in the Context's scope during event processing
59       * to compute node coordinates compatible with those of the event.
60       */
61      protected static final String KEY_CURRENT_EVENT = "Event#current";
62  
63      /** The submit event type, triggered by {@code onsubmit} event handlers. */
64      public static final String TYPE_SUBMIT = "submit";
65  
66      /** The change event type, triggered by {@code onchange} event handlers. */
67      public static final String TYPE_CHANGE = "change";
68  
69      /** The load event type, triggered by {@code onload} event handlers. */
70      public static final String TYPE_LOAD = "load";
71  
72      /** The unload event type, triggered by {@code onunload} event handlers. */
73      public static final String TYPE_UNLOAD = "unload";
74  
75      /** The popstate event type, triggered by {@code onpopstate} event handlers. */
76      public static final String TYPE_POPSTATE = "popstate";
77  
78      /** The focus event type, triggered by {@code onfocus} event handlers. */
79      public static final String TYPE_FOCUS = "focus";
80  
81      /** The focus in event type, triggered by {@code onfocusin} event handlers. */
82      public static final String TYPE_FOCUS_IN = "focusin";
83  
84      /** The focus out event type, triggered by {@code onfocusout} event handlers. */
85      public static final String TYPE_FOCUS_OUT = "focusout";
86  
87      /** The blur event type, triggered by {@code onblur} event handlers. */
88      public static final String TYPE_BLUR = "blur";
89  
90      /** The key down event type, triggered by {@code onkeydown} event handlers. */
91      public static final String TYPE_KEY_DOWN = "keydown";
92  
93      /** The key press event type, triggered by {@code onkeypress} event handlers. */
94      public static final String TYPE_KEY_PRESS = "keypress";
95  
96      /** The input event type, triggered by {@code oninput} event handlers. */
97      public static final String TYPE_INPUT = "input";
98  
99      /** The key up event type, triggered by {@code onkeyup} event handlers. */
100     public static final String TYPE_KEY_UP = "keyup";
101 
102     /** The reset event type, triggered by {@code onreset} event handlers. */
103     public static final String TYPE_RESET = "reset";
104 
105     /** The beforeunload event type, triggered by {@code onbeforeunload} event handlers. */
106     public static final String TYPE_BEFORE_UNLOAD = "beforeunload";
107 
108     /** Triggered after the DOM has loaded but before images etc. */
109     public static final String TYPE_DOM_DOCUMENT_LOADED = "DOMContentLoaded";
110 
111     /** The event type triggered by {@code onpropertychange} event handlers. */
112     public static final String TYPE_PROPERTY_CHANGE = "propertychange";
113 
114     /** The event type triggered by {@code onhashchange} event handlers. */
115     public static final String TYPE_HASH_CHANGE = "hashchange";
116 
117     /** The event type triggered by {@code onreadystatechange} event handlers. */
118     public static final String TYPE_READY_STATE_CHANGE = "readystatechange";
119 
120     /** The event type triggered by {@code onerror} event handlers. */
121     public static final String TYPE_ERROR = "error";
122 
123     /** The message event type, triggered by postMessage. */
124     public static final String TYPE_MESSAGE = "message";
125 
126     /** The close event type, triggered by {@code onclose} event handlers. */
127     public static final String TYPE_CLOSE = "close";
128 
129     /** The open event type, triggered by {@code onopen} event handlers. */
130     public static final String TYPE_OPEN = "open";
131 
132     /** The load start event type, triggered by {@code onloadstart} event handlers. */
133     public static final String TYPE_LOAD_START = "loadstart";
134 
135     /** The load end event type, triggered by {@code onloadend} event handlers. */
136     public static final String TYPE_LOAD_END = "loadend";
137 
138     /** The progress event type, triggered by {@code onprogress} event handlers. */
139     public static final String TYPE_PROGRESS = "progress";
140 
141     /** The abort event type, triggered by {@code onabort} event handlers. */
142     public static final String TYPE_ABORT = "abort";
143 
144     /** The timeout event type, triggered by {@code ontimeout} event handlers. */
145     public static final String TYPE_TIMEOUT = "timeout";
146 
147     /** The scroll event type, triggered by {@code onscroll} event handlers. */
148     public static final String TYPE_SCROLL = "scroll";
149 
150     /** The scrollend event type, triggered by {@code onscrollend} event handlers. */
151     public static final String TYPE_SCROLLEND = "scrollend";
152 
153     /** The search event type, triggered by {@code onsearch} event handlers. */
154     public static final String TYPE_SEARCH = "search";
155 
156     /** The dragend event type, triggered by {@code dragend} event handlers. */
157     public static final String TYPE_DRAGEND = "dragend";
158 
159     /** The invalid event type, triggered by {@code invalid} event handlers. */
160     public static final String TYPE_INVALID = "invalid";
161 
162     /** The pointerout event type, triggered by {@code pointerout} event handlers. */
163     public static final String TYPE_POINTEROUT = "pointerout";
164 
165     /** The ratechange event type, triggered by {@code ratechange} event handlers. */
166     public static final String TYPE_RATECHANGE = "ratechange";
167 
168     /** The animationiteration event type, triggered by {@code animationiteration} event handlers. */
169     public static final String TYPE_ANIMATIONITERATION = "animationiteration";
170 
171     /** The canplaythrough event type, triggered by {@code canplaythrough} event handlers. */
172     public static final String TYPE_CANPLAYTHROUGH = "canplaythrough";
173 
174     /** The cancel event type, triggered by {@code cancel} event handlers. */
175     public static final String TYPE_CANCEL = "cancel";
176 
177     /** The pointerenter event type, triggered by {@code pointerenter} event handlers. */
178     public static final String TYPE_POINTERENTER = "pointerenter";
179 
180     /** The select event type, triggered by {@code select} event handlers. */
181     public static final String TYPE_SELECT = "select";
182 
183     /** The auxclick event type, triggered by {@code auxclick} event handlers. */
184     public static final String TYPE_AUXCLICK = "auxclick";
185 
186     /** The webkitanimationstart event type, triggered by {@code webkitanimationstart} event handlers. */
187     public static final String TYPE_WEBANIMATIONSTART = "webkitanimationstart";
188 
189     /** The drag event type, triggered by {@code drag} event handlers. */
190     public static final String TYPE_DRAG = "drag";
191 
192     /** The seeked event type, triggered by {@code seeked} event handlers. */
193     public static final String TYPE_SEEKED = "seeked";
194 
195     /** The offline event type, triggered by {@code offline} event handlers. */
196     public static final String TYPE_OFFLINE = "offline";
197 
198     /** The deviceorientation event type, triggered by {@code deviceorientation} event handlers. */
199     public static final String TYPE_DEVICEORIENTATION = "deviceorientation";
200 
201     /** The toggle event type, triggered by {@code toggle} event handlers. */
202     public static final String TYPE_TOGGLE = "toggle";
203 
204     /** The play event type, triggered by {@code play} event handlers. */
205     public static final String TYPE_PLAY = "play";
206 
207     /** The loadedmetadata event type, triggered by {@code loadedmetadata} event handlers. */
208     public static final String TYPE_LOADEDMETADATA = "loadedmetadata";
209 
210     /** The pointermove event type, triggered by {@code pointermove} event handlers. */
211     public static final String TYPE_POINTERMOVE = "pointermove";
212 
213     /** The lostpointercapture event type, triggered by {@code lostpointercapture} event handlers. */
214     public static final String TYPE_LOSTPOINTERCAPTURE = "lostpointercapture";
215 
216     /** The pointerover event type, triggered by {@code pointerover} event handlers. */
217     public static final String TYPE_POINTEROVER = "pointerover";
218 
219     /** The animationcancel event type, triggered by {@code animationcancel} event handlers. */
220     public static final String TYPE_ANIMATIONCANCEL = "animationcancel";
221 
222     /** The animationend event type, triggered by {@code animationend} event handlers. */
223     public static final String TYPE_ANIMATIONEND = "animationend";
224 
225     /** The dragenter event type, triggered by {@code dragenter} event handlers. */
226     public static final String TYPE_DRAGENTER = "dragenter";
227 
228     /** The afterprint event type, triggered by {@code afterprint} event handlers. */
229     public static final String TYPE_AFTERPRINT = "afterprint";
230 
231     /** The mozfullscreenerror event type, triggered by {@code mozfullscreenerror} event handlers. */
232     public static final String TYPE_MOZFULLSCREENERROR = "mozfullscreenerror";
233 
234     /** The mouseleave event type, triggered by {@code mouseleave} event handlers. */
235     public static final String TYPE_MOUSELEAVE = "mouseleave";
236 
237     /** The mousewheel event type, triggered by {@code mousewheel} event handlers. */
238     public static final String TYPE_MOUSEWHEEL = "mousewheel";
239 
240     /** The seeking event type, triggered by {@code seeking} event handlers. */
241     public static final String TYPE_SEEKING = "seeking";
242 
243     /** The cuechange event type, triggered by {@code cuechange} event handlers. */
244     public static final String TYPE_CUECHANGE = "cuechange";
245 
246     /** The pageshow event type, triggered by {@code pageshow} event handlers. */
247     public static final String TYPE_PAGESHOW = "pageshow";
248 
249     /** The mozfullscreenchange event type, triggered by {@code mozfullscreenchange} event handlers. */
250     public static final String TYPE_MOZFULLSCREENCHANGE = "mozfullscreenchange";
251 
252     /** The durationchange event type, triggered by {@code durationchange} event handlers. */
253     public static final String TYPE_DURATIONCHANGE = "durationchange";
254 
255     /** The playing event type, triggered by {@code playing} event handlers. */
256     public static final String TYPE_PLAYING = "playing";
257 
258     /** The ended event type, triggered by {@code ended} event handlers. */
259     public static final String TYPE_ENDED = "ended";
260 
261     /** The loadeddata event type, triggered by {@code loadeddata} event handlers. */
262     public static final String TYPE_LOADEDDATA = "loadeddata";
263 
264     /** The unhandledrejection event type, triggered by {@code unhandledrejection} event handlers. */
265     public static final String TYPE_UNHANDLEDREJECTION = "unhandledrejection";
266 
267     /** The suspend event type, triggered by {@code suspend} event handlers. */
268     public static final String TYPE_SUSPEND = "suspend";
269 
270     /** The waiting event type, triggered by {@code waiting} event handlers. */
271     public static final String TYPE_WAITING = "waiting";
272 
273     /** The canplay event type, triggered by {@code canplay} event handlers. */
274     public static final String TYPE_CANPLAY = "canplay";
275 
276     /** The languagechange event type, triggered by {@code languagechange} event handlers. */
277     public static final String TYPE_LANGUAGECHANGE = "languagechange";
278 
279     /** The emptied event type, triggered by {@code emptied} event handlers. */
280     public static final String TYPE_EMPTIED = "emptied";
281 
282     /** The rejectionhandled event type, triggered by {@code rejectionhandled} event handlers. */
283     public static final String TYPE_REJECTIONHANDLED = "rejectionhandled";
284 
285     /** The pointercancel event type, triggered by {@code pointercancel} event handlers. */
286     public static final String TYPE_POINTERCANCEL = "pointercancel";
287 
288     /** The resize event type, triggered by {@code resize} event handlers. */
289     public static final String TYPE_RESIZE = "resize";
290 
291     /** The pause event type, triggered by {@code pause} event handlers. */
292     public static final String TYPE_PAUSE = "pause";
293 
294     /** The pointerup event type, triggered by {@code pointerup} event handlers. */
295     public static final String TYPE_POINTERUP = "pointerup";
296 
297     /** The wheel event type, triggered by {@code wheel} event handlers. */
298     public static final String TYPE_WHEEL = "wheel";
299 
300     /** The pointerleave event type, triggered by {@code pointerleave} event handlers. */
301     public static final String TYPE_POINTERLEAVE = "pointerleave";
302 
303     /** The beforeprint event type, triggered by {@code beforeprint} event handlers. */
304     public static final String TYPE_BEFOREPRINT = "beforeprint";
305 
306     /** The storage event type, triggered by {@code storage} event handlers. */
307     public static final String TYPE_STORAGE = "storage";
308 
309     /** The animationstart event type, triggered by {@code animationstart} event handlers. */
310     public static final String TYPE_ANIMATIONSTART = "animationstart";
311 
312     /** The timeupdate event type, triggered by {@code timeupdate} event handlers. */
313     public static final String TYPE_TIMEUPDATE = "timeupdate";
314 
315     /** The pagehide event type, triggered by {@code pagehide} event handlers. */
316     public static final String TYPE_PAGEHIDE = "pagehide";
317 
318     /** The webkitanimationiteration event type, triggered by {@code webkitanimationiteration} event handlers. */
319     public static final String TYPE_WEBKITANIMATIONITERATION = "webkitanimationiteration";
320 
321     /** The dragover event type, triggered by {@code dragover} event handlers. */
322     public static final String TYPE_DRAGOVER = "dragover";
323 
324     /** The online event type, triggered by {@code online} event handlers. */
325     public static final String TYPE_ONLINE = "online";
326 
327     /** The volumechange event type, triggered by {@code volumechange} event handlers. */
328     public static final String TYPE_VOLUMECHANGE = "volumechange";
329 
330     /** The gotpointercapture event type, triggered by {@code gotpointercapture} event handlers. */
331     public static final String TYPE_GOTPOINTERCAPTURE = "gotpointercapture";
332 
333     /** The webkittransitionend event type, triggered by {@code webkittransitionend} event handlers. */
334     public static final String TYPE_WEBKITTRANSITIONEND = "webkittransitionend";
335 
336     /** The webkitanimationend event type, triggered by {@code webkitanimationend} event handlers. */
337     public static final String TYPE_WEBKITANIMATIONEND = "webkitanimationend";
338 
339     /** The devicemotion event type, triggered by {@code devicemotion} event handlers. */
340     public static final String TYPE_DEVICEMOTION = "devicemotion";
341 
342     /** The stalled event type, triggered by {@code stalled} event handlers. */
343     public static final String TYPE_STALLED = "stalled";
344 
345     /** The mouseenter event type, triggered by {@code mouseenter} event handlers. */
346     public static final String TYPE_MOUDEENTER = "mouseenter";
347 
348     /** The dragleave event type, triggered by {@code dragleave} event handlers. */
349     public static final String TYPE_DRAGLEAVE = "dragleave";
350 
351     /** The pointerdown event type, triggered by {@code pointerdown} event handlers. */
352     public static final String TYPE_POINTERDOWN = "pointerdown";
353 
354     /** The drop event type, triggered by {@code drop} event handlers. */
355     public static final String TYPE_DROP = "drop";
356 
357     /** The dragstart event type, triggered by {@code dragstart} event handlers. */
358     public static final String TYPE_DRAGSTART = "dragstart";
359 
360     /** The transitionend event type, triggered by {@code transitionend} event handlers. */
361     public static final String TYPE_TRANSITIONEND = "transitionend";
362 
363     /** The deviceorientationabsolute event type, triggered by {@code deviceorientationabsolute} event handlers. */
364     public static final String TYPE_DEVICEORIENTATIONABSOLUTE = "deviceorientationabsolute";
365 
366     /** The beforecopy event type, triggered by {@code beforecopy} event handlers. */
367     public static final String TYPE_BEFORECOPY = "beforecopy";
368 
369     /** The beforecut event type, triggered by {@code beforecut} event handlers. */
370     public static final String TYPE_BEFORECUT = "beforecut";
371 
372     /** The beforepaste event type, triggered by {@code beforepaste} event handlers. */
373     public static final String TYPE_BEFOREPASTE = "beforepaste";
374 
375     /** The selectstart event type, triggered by {@code selectstart} event handlers. */
376     public static final String TYPE_SELECTSTART = "selectstart";
377 
378     /** The webkitfullscreenchange event type, triggered by {@code webkitfullscreenchange} event handlers. */
379     public static final String TYPE_WEBKITFULLSCREENCHANGE = "webkitfullscreenchange";
380 
381     /** The webkitfullscreenerror event type, triggered by {@code webkitfullscreenerror} event handlers. */
382     public static final String TYPE_WEBKITFULLSCREENERROR = "webkitfullscreenerror";
383 
384     /** The copy event type, triggered by {@code copy} event handlers. */
385     public static final String TYPE_COPY = "copy";
386 
387     /** The cut event type, triggered by {@code cut} event handlers. */
388     public static final String TYPE_CUT = "cut";
389 
390     /** The paste event type, triggered by {@code paste} event handlers. */
391     public static final String TYPE_PASTE = "paste";
392 
393     /** The messageerror event type, triggered by {@code onmessageerror} event handlers. */
394     public static final String TYPE_ONMESSAGEERROR = "onmessageerror";
395 
396     /** The pointerlockchange event type, triggered by {@code pointerlockchange} event handlers. */
397     public static final String TYPE_POINTERLOCKCHANGE = "pointerlockchange";
398 
399     /** The pointerlockerror event type, triggered by {@code pointerlockerror} event handlers. */
400     public static final String TYPE_POINTERLOCKERROR = "pointerlockerror";
401 
402     /** The selectionchange event type, triggered by {@code selectionchange} event handlers. */
403     public static final String TYPE_SELECTIONCHANGE = "selectionchange";
404 
405     /** The afterscriptexecute event type, triggered by {@code afterscriptexecute} event handlers. */
406     public static final String TYPE_AFTERSCRIPTEXECUTE = "afterscriptexecute";
407 
408     /** The beforescriptexecute event type, triggered by {@code beforescriptexecute} event handlers. */
409     public static final String TYPE_BEFORESCRIPTEXECUTE = "beforescriptexecute";
410 
411     /** The transitioncancel event type, triggered by {@code ontransitioncancel} event handlers. */
412     public static final String TYPE_ONTRANSITIONCANCEL = "ontransitioncancel";
413 
414     /** The transitionend event type, triggered by {@code ontransitionend} event handlers. */
415     public static final String TYPE_ONTRANSITIONEND = "ontransitionend";
416 
417     /** The transitionrun event type, triggered by {@code ontransitionrun} event handlers. */
418     public static final String TYPE_ONTRANSITIONRUN = "ontransitionrun";
419 
420     /** The transitionstart event type, triggered by {@code ontransitionstart} event handlers. */
421     public static final String TYPE_ONTRANSITIONSTART = "ontransitionstart";
422 
423     /** The gamepadconnected event type, triggered by {@code ongamepadconnected} event handlers. */
424     public static final String TYPE_GAMEPAD_CONNECTED = "ongamepadconnected";
425 
426     /** The gamepaddisconnected event type, triggered by {@code ongamepaddisconnected} event handlers. */
427     public static final String TYPE_GAMEPAD_DISCONNECTED = "ongamepaddisconnected";
428 
429     /** No event phase. */
430     @JsxConstant
431     public static final int NONE = 0;
432 
433     /** The first event phase: the capturing phase. */
434     @JsxConstant
435     public static final int CAPTURING_PHASE = 1;
436 
437     /** The second event phase: at the event target. */
438     @JsxConstant
439     public static final int AT_TARGET = 2;
440 
441     /** The third (and final) event phase: the bubbling phase. */
442     @JsxConstant
443     public static final int BUBBLING_PHASE = 3;
444 
445     /** Constant. */
446     @JsxConstant({FF, FF_ESR})
447     public static final int ALT_MASK = 0x1;
448 
449     /** Constant. */
450     @JsxConstant({FF, FF_ESR})
451     public static final int CONTROL_MASK = 0x2;
452 
453     /** Constant. */
454     @JsxConstant({FF, FF_ESR})
455     public static final int SHIFT_MASK = 0x4;
456 
457     /** Constant. */
458     @JsxConstant({FF, FF_ESR})
459     public static final int META_MASK = 0x8;
460 
461     private Object srcElement_;        // writable equivalent of target.
462     private EventTarget target_;       // W3C standard read-only equivalent of srcElement.
463     private Scriptable currentTarget_; // Changes during event capturing and bubbling.
464     private String type_ = "";         // The event type.
465     private int keyCode_;              // Key code for a keypress
466     private boolean shiftKey_;
467     private boolean ctrlKey_;
468     private boolean altKey_;
469     private String propertyName_;
470     private boolean stopPropagation_;
471     private boolean stopImmediatePropagation_;
472     private boolean preventDefault_;
473 
474     /**
475      * The current event phase. This is a W3C standard attribute. One of {@link #NONE},
476      * {@link #CAPTURING_PHASE}, {@link #AT_TARGET} or {@link #BUBBLING_PHASE}.
477      */
478     private int eventPhase_;
479 
480     /**
481      * Whether or not the event bubbles. The value of this attribute depends on the event type. Most
482      * event types do bubble, so this is {@code true} by default; event types which do not bubble should
483      * overwrite this value in their constructors.
484      */
485     private boolean bubbles_ = true;
486 
487     /**
488      * Whether or not the event can be canceled. The value of this attribute depends on the event type.
489      * The more common event types are cancelable, so this is {@code true} by default; event types which
490      * cannot be canceled should overwrite this value in their constructors.
491      */
492     private boolean cancelable_ = true;
493 
494     /**
495      * The time at which the event was created.
496      */
497     private final long timeStamp_ = System.currentTimeMillis();
498 
499     /**
500      * Creates a new event instance.
501      *
502      * @param domNode the DOM node that triggered the event
503      * @param type the event type
504      */
505     public Event(final DomNode domNode, final String type) {
506         this(domNode.getScriptableObject(), type);
507         setDomNode(domNode, false);
508     }
509 
510     /**
511      * Creates a new event instance.
512      *
513      * @param target the event target
514      * @param type the event type
515      */
516     public Event(final EventTarget target, final String type) {
517         this(type);
518 
519         srcElement_ = target;
520         target_ = target;
521         currentTarget_ = target;
522 
523         setParentScope(target.getParentScope());
524         setPrototype(getPrototype(getClass()));
525 
526         if (TYPE_CHANGE.equals(type)) {
527             cancelable_ = false;
528         }
529         else if (TYPE_LOAD.equals(type)
530                     || TYPE_CLOSE.equals(type)) {
531             bubbles_ = false;
532             cancelable_ = false;
533         }
534         else if (TYPE_ERROR.equals(type)) {
535             // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-error
536             bubbles_ = false;
537         }
538         else if (
539                 TYPE_FOCUS.equals(type)
540                 || TYPE_BLUR.equals(type)
541                 || TYPE_BEFOREPRINT.equals(type)
542                 || TYPE_AFTERPRINT.equals(type)) {
543             bubbles_ = false;
544             cancelable_ = false;
545         }
546     }
547 
548     /**
549      * Creates a new event instance.
550      *
551      * @param type the event type
552      */
553     public Event(final String type) {
554         super();
555         type_ = type;
556     }
557 
558     /**
559      * Creates a new {@link #TYPE_PROPERTY_CHANGE} event for the given DOM node.
560      *
561      * @param domNode the DOM node that triggered the event
562      * @param propertyName the property name that was changed
563      * @return the new Event object
564      */
565     public static Event createPropertyChangeEvent(final DomNode domNode, final String propertyName) {
566         final Event event = new Event(domNode, TYPE_PROPERTY_CHANGE);
567         event.propertyName_ = propertyName;
568         return event;
569     }
570 
571     /**
572      * Default constructor used to build the prototype.
573      */
574     public Event() {
575         super();
576     }
577 
578     /**
579      * Called whenever an event is created using {@code Document.createEvent(..)}.
580      * This method is called after the parent scope was set so you are able to access the browser version.
581      */
582     public void eventCreated() {
583         setBubbles(false);
584         setCancelable(false);
585     }
586 
587     /**
588      * Creates an instance of this event.
589      *
590      * @param type the event type
591      * @param details the event details (optional)
592      */
593     @JsxConstructor
594     public void jsConstructor(final String type, final ScriptableObject details) {
595         boolean bubbles = false;
596         boolean cancelable = false;
597 
598         if (details != null && !JavaScriptEngine.isUndefined(details)) {
599             bubbles = JavaScriptEngine.toBoolean(details.get("bubbles"));
600             cancelable  = JavaScriptEngine.toBoolean(details.get("cancelable"));
601         }
602         initEvent(type, bubbles, cancelable);
603     }
604 
605     /**
606      * Called when the event starts being fired.
607      */
608     @SuppressWarnings("unchecked")
609     public void startFire() {
610         final Context context = Context.getCurrentContext();
611         ArrayList<Event> events = (ArrayList<Event>) context.getThreadLocal(KEY_CURRENT_EVENT);
612         if (events == null) {
613             events = new ArrayList<>();
614             context.putThreadLocal(KEY_CURRENT_EVENT, events);
615         }
616         events.add(this);
617     }
618 
619     /**
620      * Called when the event being fired ends.
621      */
622     @SuppressWarnings("unchecked")
623     public void endFire() {
624         final Context context = Context.getCurrentContext();
625         final ArrayList<Event> events = (ArrayList<Event>) context.getThreadLocal(KEY_CURRENT_EVENT);
626         if (events != null && !events.isEmpty()) {
627             events.remove(events.size() - 1);
628         }
629     }
630 
631     /**
632      * Returns the object that fired the event.
633      *
634      * @return the object that fired the event
635      */
636     @JsxGetter
637     public Object getSrcElement() {
638         return srcElement_;
639     }
640 
641     /**
642      * Sets the object that fired the event.
643      *
644      * @param srcElement the object that fired the event
645      */
646     public void setSrcElement(final Object srcElement) {
647         srcElement_ = srcElement;
648     }
649 
650     /**
651      * Returns the event target to which the event was originally dispatched.
652      *
653      * @return the event target to which the event was originally dispatched
654      */
655     @JsxGetter
656     public Object getTarget() {
657         return target_;
658     }
659 
660     /**
661      * Sets the event target.
662      *
663      * @param target the event target
664      */
665     public void setTarget(final EventTarget target) {
666         target_ = target;
667     }
668 
669     /**
670      * Returns the event target whose event listeners are currently being processed.
671      * This is useful during event capturing and event bubbling.
672      *
673      * @return the current event target
674      */
675     @JsxGetter
676     public Scriptable getCurrentTarget() {
677         return currentTarget_;
678     }
679 
680     /**
681      * Sets the current target.
682      *
683      * @param target the new current target
684      */
685     public void setCurrentTarget(final Scriptable target) {
686         currentTarget_ = target;
687     }
688 
689     /**
690      * Returns the event type.
691      *
692      * @return the event type
693      */
694     @JsxGetter
695     public String getType() {
696         return type_;
697     }
698 
699     /**
700      * Sets the event type.
701      *
702      * @param type the event type
703      */
704     public void setType(final String type) {
705         type_ = type;
706     }
707 
708     /**
709      * Sets the event type.
710      *
711      * @param eventType the event type
712      */
713     public void setEventType(final String eventType) {
714         type_ = eventType;
715     }
716 
717     /**
718      * Returns the time at which this event was created.
719      *
720      * @return the time at which this event was created
721      */
722     @JsxGetter
723     public long getTimeStamp() {
724         return timeStamp_;
725     }
726 
727     /**
728      * Sets the key code.
729      *
730      * @param keyCode the virtual key code value of the key which was depressed, otherwise zero
731      */
732     protected void setKeyCode(final int keyCode) {
733         keyCode_ = keyCode;
734     }
735 
736     /**
737      * Returns the key code associated with the event.
738      *
739      * @return the key code associated with the event
740      */
741     public int getKeyCode() {
742         return keyCode_;
743     }
744 
745     /**
746      * Returns whether the {@code SHIFT} key was pressed during this event.
747      *
748      * @return {@code true} if {@code SHIFT} was pressed
749      */
750     public boolean isShiftKey() {
751         return shiftKey_;
752     }
753 
754     /**
755      * Sets whether the {@code SHIFT} key is pressed.
756      *
757      * @param shiftKey {@code true} if {@code SHIFT} is pressed
758      */
759     protected void setShiftKey(final boolean shiftKey) {
760         shiftKey_ = shiftKey;
761     }
762 
763     /**
764      * Returns whether the {@code CTRL} key was pressed during this event.
765      *
766      * @return {@code true} if {@code CTRL} was pressed
767      */
768     public boolean isCtrlKey() {
769         return ctrlKey_;
770     }
771 
772     /**
773      * Sets whether the {@code CTRL} key is pressed.
774      *
775      * @param ctrlKey {@code true} if {@code CTRL} is pressed
776      */
777     protected void setCtrlKey(final boolean ctrlKey) {
778         ctrlKey_ = ctrlKey;
779     }
780 
781     /**
782      * Returns whether the {@code ALT} key was pressed during this event.
783      *
784      * @return {@code true} if {@code ALT} was pressed
785      */
786     public boolean isAltKey() {
787         return altKey_;
788     }
789 
790     /**
791      * Sets whether the {@code ALT} key is pressed.
792      *
793      * @param altKey {@code true} if {@code ALT} is pressed
794      */
795     protected void setAltKey(final boolean altKey) {
796         altKey_ = altKey;
797     }
798 
799     /**
800      * Returns the current event phase for the event.
801      *
802      * @return the current event phase
803      */
804     @JsxGetter
805     public int getEventPhase() {
806         return eventPhase_;
807     }
808 
809     /**
810      * Sets the current event phase. Must be one of {@link #CAPTURING_PHASE}, {@link #AT_TARGET} or
811      * {@link #BUBBLING_PHASE}.
812      *
813      * @param phase the phase the event is in
814      */
815     public void setEventPhase(final int phase) {
816         if (phase != CAPTURING_PHASE && phase != AT_TARGET && phase != BUBBLING_PHASE) {
817             throw new IllegalArgumentException("Illegal phase specified: " + phase);
818         }
819         eventPhase_ = phase;
820     }
821 
822     /**
823      * Returns whether this event bubbles.
824      *
825      * @return {@code true} if this event bubbles
826      */
827     @JsxGetter
828     public boolean isBubbles() {
829         return bubbles_;
830     }
831 
832     /**
833      * Sets whether this event bubbles.
834      *
835      * @param bubbles {@code true} if this event should bubble
836      */
837     public void setBubbles(final boolean bubbles) {
838         bubbles_ = bubbles;
839     }
840 
841     /**
842      * Returns whether this event can be canceled.
843      *
844      * @return {@code true} if this event can be canceled
845      */
846     @JsxGetter
847     public boolean isCancelable() {
848         return cancelable_;
849     }
850 
851     /**
852      * Sets whether this event can be canceled.
853      *
854      * @param cancelable {@code true} if this event can be canceled
855      */
856     public void setCancelable(final boolean cancelable) {
857         cancelable_ = cancelable;
858     }
859 
860     /**
861      * Returns {@code true} if both {@code cancelable} is {@code true} and {@code preventDefault()} has been
862      * called for this event, otherwise returns {@code false}.
863      *
864      * @return {@code true} if this event has been cancelled
865      */
866     @JsxGetter
867     public boolean isDefaultPrevented() {
868         return cancelable_ && preventDefault_;
869     }
870 
871     /**
872      * Returns whether event propagation is stopped.
873      *
874      * @return {@code true} if event propagation is stopped
875      */
876     @JsxGetter
877     public boolean isCancelBubble() {
878         return stopPropagation_;
879     }
880 
881     /**
882      * Sets whether event propagation is stopped.
883      *
884      * @param newValue {@code true} to stop event propagation
885      */
886     @JsxSetter
887     public void setCancelBubble(final boolean newValue) {
888         stopPropagation_ = newValue;
889     }
890 
891     /**
892      * Stops the event from propagating.
893      */
894     @JsxFunction
895     public void stopPropagation() {
896         stopPropagation_ = true;
897     }
898 
899     /**
900      * Returns whether event propagation is stopped.
901      *
902      * @return {@code true} if propagation is stopped
903      */
904     public boolean isPropagationStopped() {
905         return stopPropagation_;
906     }
907 
908     /**
909      * Prevents other listeners of the same event from being called.
910      */
911     @JsxFunction
912     public void stopImmediatePropagation() {
913         stopImmediatePropagation_ = true;
914         stopPropagation();
915     }
916 
917     /**
918      * Returns whether immediate event propagation is stopped.
919      *
920      * @return {@code true} if immediate propagation is stopped
921      */
922     public boolean isImmediatePropagationStopped() {
923         return stopImmediatePropagation_;
924     }
925 
926     /**
927      * Handles the return values of property handlers.
928      *
929      * @param returnValue the return value returned by the property handler
930      */
931     void handlePropertyHandlerReturnValue(final Object returnValue) {
932         if (Boolean.FALSE.equals(returnValue)) {
933             preventDefault();
934         }
935     }
936 
937     /**
938      * Returns the property name associated with the event.
939      *
940      * @return the property name associated with the event
941      */
942     public String getPropertyName() {
943         return propertyName_;
944     }
945 
946     /**
947      * Initializes this event.
948      *
949      * @param type the event type
950      * @param bubbles whether or not the event should bubble
951      * @param cancelable whether or not the event should be cancelable
952      */
953     @JsxFunction
954     public void initEvent(final String type, final boolean bubbles, final boolean cancelable) {
955         type_ = type;
956         bubbles_ = bubbles;
957         cancelable_ = cancelable;
958     }
959 
960     /**
961      * Cancels the event if it is cancelable, preventing the default action associated with it.
962      * Calling this method for a non-cancelable event has no effect.
963      */
964     @JsxFunction
965     public void preventDefault() {
966         if (isCancelable()) {
967             preventDefault_ = true;
968         }
969     }
970 
971     /**
972      * Returns {@code true} if this event has been aborted via {@code preventDefault()} in
973      * standards-compliant browsers.
974      *
975      * @param result the event handler result (if {@code false}, the event is considered aborted)
976      * @return {@code true} if this event has been aborted
977      */
978     public boolean isAborted(final ScriptResult result) {
979         return ScriptResult.isFalse(result) || preventDefault_;
980     }
981 
982     /**
983      * {@inheritDoc}
984      */
985     @Override
986     public String toString() {
987         final StringBuilder builder = new StringBuilder(40);
988         builder.append("Event ")
989             .append(getType())
990             .append(" (Current Target: ")
991             .append(currentTarget_)
992             .append(");");
993         return builder.toString();
994     }
995 
996     /**
997      * <span style="color:red">INTERNAL API - SUBJECT TO CHANGE AT ANY TIME - USE AT YOUR OWN RISK.</span><br>
998      *
999      * If we click on a label, we have to simulate a click on the element referenced by the {@code for} attribute.
1000      * To support this for special events, this method can be overridden.
1001      *
1002      * @return {@code false} in this default implementation
1003      */
1004     public boolean processLabelAfterBubbling() {
1005         return false;
1006     }
1007 
1008     /**
1009      * Returns the return value property.
1010      *
1011      * @return the return value
1012      */
1013     @JsxGetter
1014     public Object getReturnValue() {
1015         return !preventDefault_;
1016     }
1017 
1018     /**
1019      * Sets the return value property.
1020      *
1021      * @param newValue the new return value
1022      */
1023     @JsxSetter
1024     public void setReturnValue(final Object newValue) {
1025         if (isCancelable()) {
1026             final boolean bool = !JavaScriptEngine.toBoolean(newValue);
1027             if (bool) {
1028                 preventDefault_ = bool;
1029             }
1030         }
1031     }
1032 
1033     /**
1034      * Returns the {@code composed} property.
1035      *
1036      * @return {@code false} as the default implementation
1037      */
1038     @JsxGetter
1039     public boolean isComposed() {
1040         return false;
1041     }
1042 
1043     /**
1044      * Returns whether the given value indicates a missing or undefined property.
1045      *
1046      * @param value the value to check
1047      * @return {@code true} if the value is missing or undefined
1048      */
1049     protected static boolean isMissingOrUndefined(final Object value) {
1050         return value == Scriptable.NOT_FOUND || JavaScriptEngine.isUndefined(value);
1051     }
1052 
1053     /**
1054      * Returns whether the given value is {@code null}, missing, or undefined.
1055      *
1056      * @param value the value to check
1057      * @return {@code true} if the value is {@code null}, missing, or undefined
1058      */
1059     protected static boolean isNullMissingOrUndefined(final Object value) {
1060         return value == null || value == Scriptable.NOT_FOUND || JavaScriptEngine.isUndefined(value);
1061     }
1062 }