001: /*
002: * Copyright (c) 2002-2008 Gargoyle Software Inc. All rights reserved.
003: *
004: * Redistribution and use in source and binary forms, with or without
005: * modification, are permitted provided that the following conditions are met:
006: *
007: * 1. Redistributions of source code must retain the above copyright notice,
008: * this list of conditions and the following disclaimer.
009: * 2. Redistributions in binary form must reproduce the above copyright notice,
010: * this list of conditions and the following disclaimer in the documentation
011: * and/or other materials provided with the distribution.
012: * 3. The end-user documentation included with the redistribution, if any, must
013: * include the following acknowledgment:
014: *
015: * "This product includes software developed by Gargoyle Software Inc.
016: * (http://www.GargoyleSoftware.com/)."
017: *
018: * Alternately, this acknowledgment may appear in the software itself, if
019: * and wherever such third-party acknowledgments normally appear.
020: * 4. The name "Gargoyle Software" must not be used to endorse or promote
021: * products derived from this software without prior written permission.
022: * For written permission, please contact info@GargoyleSoftware.com.
023: * 5. Products derived from this software may not be called "HtmlUnit", nor may
024: * "HtmlUnit" appear in their name, without prior written permission of
025: * Gargoyle Software Inc.
026: *
027: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
028: * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
029: * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GARGOYLE
030: * SOFTWARE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
031: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
032: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
033: * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
034: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
035: * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
036: * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
037: */
038: package com.gargoylesoftware.htmlunit.javascript.host;
039:
040: import org.mozilla.javascript.Context;
041: import org.mozilla.javascript.Scriptable;
042:
043: import com.gargoylesoftware.htmlunit.html.DomNode;
044: import com.gargoylesoftware.htmlunit.javascript.SimpleScriptable;
045:
046: /**
047: * JavaScript object representing an event that is passed into event handlers when they are
048: * invoked. For general information on which properties and functions should be supported,
049: * see <a href="http://developer.mozilla.org/en/docs/DOM:event">the mozilla docs</a>,
050: * <a href="http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-Event">the W3C DOM
051: * Level 2 Event Documentation</a> or <a href="http://msdn2.microsoft.com/en-us/library/aa703876.aspx">IE's
052: * IHTMLEventObj interface</a>.
053: *
054: * @version $Revision: 2132 $
055: * @author <a href="mailto:chriseldredge@comcast.net">Chris Eldredge</a>
056: * @author Mike Bowler
057: * @author Chris Erskine
058: * @author Marc Guillemot
059: * @author Daniel Gredler
060: * @author Brad Murray
061: * @author Ahmed Ashour
062: * @author Rob Di Marco
063: */
064: public class Event extends SimpleScriptable {
065:
066: /**
067: * Key to place the event's target in the Context's scope during event processing
068: * to compute node coordinates compatible with those of the event.
069: */
070: static final String KEY_CURRENT_EVENT = "Event#current";
071:
072: /** The submit event type, triggered by "onsubmit" event handlers. */
073: public static final String TYPE_SUBMIT = "submit";
074:
075: /** The change event type, triggered by "onchange" event handlers. */
076: public static final String TYPE_CHANGE = "change";
077:
078: /** The load event type, triggered by "onload" event handlers. */
079: public static final String TYPE_LOAD = "load";
080:
081: /** The unload event type, triggered by "onunload" event handlers. */
082: public static final String TYPE_UNLOAD = "unload";
083:
084: /** The focus event type, triggered by "onfocus" event handlers. */
085: public static final String TYPE_FOCUS = "focus";
086:
087: /** The blur event type, triggered by "onblur" event handlers. */
088: public static final String TYPE_BLUR = "blur";
089:
090: /** The key down event type, triggered by "onkeydown" event handlers. */
091: public static final String TYPE_KEY_DOWN = "keydown";
092:
093: /** The key down event type, triggered by "onkeypress" event handlers. */
094: public static final String TYPE_KEY_PRESS = "keypress";
095:
096: /** The key down event type, triggered by "onkeyup" event handlers. */
097: public static final String TYPE_KEY_UP = "keyup";
098:
099: /** The submit event type, triggered by "onreset" event handlers. */
100: public static final String TYPE_RESET = "reset";
101:
102: /** The beforeunload event type, triggered by "onbeforeunload" event handlers. */
103: public static final String TYPE_BEFORE_UNLOAD = "beforeunload";
104:
105: /** Triggered after the DOM has loaded but before images etc. */
106: public static final String TYPE_DOM_DOCUMENT_LOADED = "DOMContentLoaded";
107:
108: /** The first event phase: the capturing phase. */
109: public static final short CAPTURING_PHASE = 1;
110:
111: /** The second event phase: at the event target. */
112: public static final short AT_TARGET = 2;
113:
114: /** The third (and final) event phase: the bubbling phase. */
115: public static final short BUBBLING_PHASE = 3;
116:
117: private static final long serialVersionUID = 4050485607908455730L;
118:
119: private Object srcElement_; // IE-only writeable equivalent of target.
120: private Object target_; // W3C standard read-only equivalent of srcElement.
121: private Object currentTarget_; // Changes during event capturing and bubbling.
122: private String type_; // The event type.
123: private Object keyCode_; // Key code for a keypress
124: private boolean shiftKey_; // Exposed here in IE, only in mouse events in FF.
125: private boolean ctrlKey_; // Exposed here in IE, only in mouse events in FF.
126: private boolean altKey_; // Exposed here in IE, only in mouse events in FF.
127: private boolean stopPropagation_;
128: private Object returnValue_;
129: private boolean preventDefault_;
130:
131: /**
132: * The current event phase. This is a W3C standard attribute not implemented by IE. One of
133: * {@link #CAPTURING_PHASE}, {@link #AT_TARGET} or {@link #BUBBLING_PHASE}.
134: */
135: private short eventPhase_;
136:
137: /**
138: * Whether or not the event bubbles. The value of this attribute depends on the event type. To
139: * determine if a certain event type bubbles, see http://www.w3.org/TR/DOM-Level-2-Events/events.html
140: * Most event types do bubble, so this is true by default; event types which do not bubble should
141: * overwrite this value in their constructors.
142: */
143: private boolean bubbles_ = true;
144:
145: /**
146: * Whether or not the event can be canceled. The value of this attribute depends on the event type. To
147: * determine if a certain event type can be canceled, see http://www.w3.org/TR/DOM-Level-2-Events/events.html
148: * The more common event types are cancelable, so this is true by default; event types which cannot be
149: * canceled should overwrite this value in their constructors.
150: */
151: private boolean cancelable_ = true;
152:
153: /**
154: * The time at which the event was created.
155: */
156: private long timeStamp_ = System.currentTimeMillis();
157:
158: /**
159: * Creates a new event instance.
160: * @param domNode The DOM node that triggered the event.
161: * @param type The event type.
162: */
163: public Event(final DomNode domNode, final String type) {
164: this (domNode, type, false, false, false);
165: }
166:
167: /**
168: * Creates a new event instance.
169: * @param domNode The DOM node that triggered the event.
170: * @param type The event type.
171: * @param shiftKey true if SHIFT is pressed
172: * @param ctrlKey true if CTRL is pressed
173: * @param altKey true if ALT is pressed
174: */
175: public Event(final DomNode domNode, final String type,
176: final boolean shiftKey, final boolean ctrlKey,
177: final boolean altKey) {
178: final Object target = domNode.getScriptObject();
179: srcElement_ = target;
180: target_ = target;
181: currentTarget_ = target;
182: type_ = type;
183: shiftKey_ = shiftKey;
184: ctrlKey_ = ctrlKey;
185: altKey_ = altKey;
186: keyCode_ = Context.getUndefinedValue();
187: setParentScope((SimpleScriptable) target);
188: setPrototype(getPrototype(getClass()));
189: setDomNode(domNode, false);
190: }
191:
192: /**
193: * Creates a new event instance for a keypress event.
194: * @param domNode the DOM node that triggered the event.
195: * @param type The event type.
196: * @param keyCode The key code associated with the event.
197: * @param shiftKey true if SHIFT is pressed
198: * @param ctrlKey true if CTRL is pressed
199: * @param altKey true if ALT is pressed
200: */
201: public Event(final DomNode domNode, final String type,
202: final int keyCode, final boolean shiftKey,
203: final boolean ctrlKey, final boolean altKey) {
204: this (domNode, type, shiftKey, ctrlKey, altKey);
205: keyCode_ = new Integer(keyCode);
206: }
207:
208: /**
209: * Used to build the prototype.
210: */
211: public Event() {
212: // Empty.
213: }
214:
215: /**
216: * Called when the event starts being fired
217: */
218: void startFire() {
219: Context.getCurrentContext().putThreadLocal(KEY_CURRENT_EVENT,
220: this );
221: }
222:
223: /**
224: * Called when the event starts being fired
225: */
226: void endFire() {
227: Context.getCurrentContext()
228: .removeThreadLocal(KEY_CURRENT_EVENT);
229: }
230:
231: /**
232: * Returns the object that fired the event. This is an IE-only property.
233: * @return The object that fired the event.
234: */
235: public Object jsxGet_srcElement() {
236: return srcElement_;
237: }
238:
239: /**
240: * Sets the object that fired the event. This is an IE-only property.
241: * @param srcElement The object that fired the event.
242: */
243: public void jsxSet_srcElement(final Object srcElement) {
244: srcElement_ = srcElement;
245: }
246:
247: /**
248: * Returns the event target to which the event was originally dispatched.
249: * @return The event target to which the event was originally dispatched.
250: */
251: public Object jsxGet_target() {
252: return target_;
253: }
254:
255: /**
256: * Returns the event target whose event listeners are currently being processed. This
257: * is useful during event capturing and event bubbling.
258: * @return The current event target.
259: */
260: public Object jsxGet_currentTarget() {
261: return currentTarget_;
262: }
263:
264: /**
265: * Sets the current target
266: * @param target the new value
267: */
268: public void setCurrentTarget(final Scriptable target) {
269: currentTarget_ = target;
270: }
271:
272: /**
273: * Returns the event type.
274: * @return The event type.
275: */
276: public String jsxGet_type() {
277: return type_;
278: }
279:
280: /**
281: * Sets the event type.
282: * @param eventType The event type.
283: */
284: public void setEventType(final String eventType) {
285: type_ = eventType;
286: }
287:
288: /**
289: * Returns the time at which this event was created.
290: * @return the time at which this event was created
291: */
292: public long jsxGet_timeStamp() {
293: return timeStamp_;
294: }
295:
296: /**
297: * Returns the key code associated with the event.
298: * @return The key code associated with the event.
299: */
300: public Object jsxGet_keyCode() {
301: return keyCode_;
302: }
303:
304: /**
305: * @return whether SHIFT has been pressed during this event or not.
306: */
307: public boolean jsxGet_shiftKey() {
308: return shiftKey_;
309: }
310:
311: /**
312: * @param shiftKey whether SHIFT has been pressed during this event or not.
313: */
314: protected void setShiftKey(final boolean shiftKey) {
315: shiftKey_ = shiftKey;
316: }
317:
318: /**
319: * @return whether CTRL has been pressed during this event or not.
320: */
321: public boolean jsxGet_ctrlKey() {
322: return ctrlKey_;
323: }
324:
325: /**
326: * @param ctrlKey whether CTRL has been pressed during this event or not.
327: */
328: protected void setCtrlKey(final boolean ctrlKey) {
329: ctrlKey_ = ctrlKey;
330: }
331:
332: /**
333: * @return whether ALT has been pressed during this event or not.
334: */
335: public boolean jsxGet_altKey() {
336: return altKey_;
337: }
338:
339: /**
340: * @param altKey whether ALT has been pressed during this event or not.
341: */
342: protected void setAltKey(final boolean altKey) {
343: altKey_ = altKey;
344: }
345:
346: /**
347: * @return the current event phase for the event.
348: */
349: public int jsxGet_eventPhase() {
350: return eventPhase_;
351: }
352:
353: /**
354: * Sets the current event phase. Must be one of {@link #CAPTURING_PHASE}, {@link #AT_TARGET} or
355: * {@link #BUBBLING_PHASE}.
356: *
357: * @param phase the phase the event is in
358: */
359: public void setEventPhase(final short phase) {
360: if (phase != CAPTURING_PHASE && phase != AT_TARGET
361: && phase != BUBBLING_PHASE) {
362: throw new IllegalArgumentException(
363: "Illegal phase specified: " + phase);
364: }
365: eventPhase_ = phase;
366: }
367:
368: /**
369: * @return whether or not this event bubbles.
370: */
371: public boolean jsxGet_bubbles() {
372: return bubbles_;
373: }
374:
375: /**
376: * @return whether or not this event can be canceled.
377: */
378: public boolean jsxGet_cancelable() {
379: return cancelable_;
380: }
381:
382: /**
383: * @return indicates if event propagation is stopped.
384: */
385: public boolean jsxGet_cancelBubble() {
386: return stopPropagation_;
387: }
388:
389: /**
390: * @param newValue indicates if event propagation is stopped.
391: */
392: public void jsxSet_cancelBubble(final boolean newValue) {
393: stopPropagation_ = newValue;
394: }
395:
396: /**
397: * Stops the event from propagating.
398: */
399: public void jsxFunction_stopPropagation() {
400: stopPropagation_ = true;
401: }
402:
403: /**
404: * Indicates if event propagation is stopped.
405: * @return the status
406: */
407: public boolean isPropagationStopped() {
408: return stopPropagation_;
409: }
410:
411: /**
412: * Returns the return value associated with the event.
413: * @return The return value associated with the event.
414: */
415: public Object jsxGet_returnValue() {
416: return returnValue_;
417: }
418:
419: /**
420: * Sets the return value associated with the event.
421: * @param returnValue The return value associated with the event.
422: */
423: public void jsxSet_returnValue(final Object returnValue) {
424: returnValue_ = returnValue;
425: }
426:
427: /**
428: * Initializes this event.
429: * @param type the event type
430: * @param bubbles whether or not the event should bubble
431: * @param cancelable whether or not the event the event should be cancelable
432: */
433: public void jsxFunction_initEvent(final String type,
434: final boolean bubbles, final boolean cancelable) {
435: type_ = type;
436: bubbles_ = bubbles;
437: cancelable_ = cancelable;
438: }
439:
440: /**
441: * If, during any stage of event flow, this method is called the event is canceled.
442: * Any default action associated with the event will not occur.
443: * Calling this method for a non-cancelable event has no effect.
444: */
445: public void jsxFunction_preventDefault() {
446: preventDefault_ = true;
447: }
448:
449: /**
450: * Returns if the preventDefault() method has been called for this event.
451: * @return if the preventDefault() method has been called for this event.
452: */
453: public boolean isPreventDefault() {
454: return preventDefault_;
455: }
456:
457: /**
458: * Copies properties from another event to this event. This method should
459: * be overridden in subclasses in order to account for extra properties.
460: * @param event the event to copy the properties from
461: */
462: public void copyPropertiesFrom(final Event event) {
463: srcElement_ = event.srcElement_;
464: target_ = event.target_;
465: currentTarget_ = event.currentTarget_;
466: type_ = event.type_;
467: keyCode_ = event.keyCode_;
468: shiftKey_ = event.shiftKey_;
469: ctrlKey_ = event.ctrlKey_;
470: altKey_ = event.altKey_;
471: stopPropagation_ = event.stopPropagation_;
472: returnValue_ = event.returnValue_;
473: eventPhase_ = event.eventPhase_;
474: bubbles_ = event.bubbles_;
475: cancelable_ = event.cancelable_;
476: }
477:
478: /**
479: * {@inheritDoc}
480: */
481: public String toString() {
482: final StringBuffer buffer = new StringBuffer("Event ");
483: buffer.append(jsxGet_type());
484: buffer.append(" (");
485: buffer.append("Current Target: ");
486: buffer.append(currentTarget_);
487: buffer.append(");");
488: return buffer.toString();
489: }
490:
491: }
|