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.html;
039:
040: import java.io.IOException;
041: import java.util.Map;
042:
043: import com.gargoylesoftware.htmlunit.Page;
044: import com.gargoylesoftware.htmlunit.ScriptResult;
045: import com.gargoylesoftware.htmlunit.javascript.host.Event;
046: import com.gargoylesoftware.htmlunit.javascript.host.MouseEvent;
047:
048: /**
049: * Intermediate base class for "clickable" HTML elements. As defined
050: * <a href='http://www.w3.org/TR/html401/'>HTML 4.01</a> documentation,
051: * this class is a base class for all HTML elements except these:
052: * applet, base, basefront, bdo, br, font, frame, frameset, head, html,
053: * iframe, isindex, meta, param, script, style, and title.
054: *
055: * @version $Revision: 2132 $
056: * @author David K. Taylor
057: * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
058: * @author <a href="mailto:chen_jun@users.sourceforge.net">Jun Chen</a>
059: * @author <a href="mailto:cse@dynabean.de">Christian Sell</a>
060: * @author David D. Kilzer
061: * @author Marc Guillemot
062: * @author Ahmed Ashour
063: */
064: public abstract class ClickableElement extends StyledElement {
065:
066: /**
067: * Create an instance
068: *
069: * @param namespaceURI the URI that identifies an XML namespace.
070: * @param qualifiedName The qualified name of the element type to instantiate
071: * @param page The page that contains this element
072: * @param attributes the initial attributes
073: */
074: protected ClickableElement(final String namespaceURI,
075: final String qualifiedName, final HtmlPage page,
076: final Map attributes) {
077: super (namespaceURI, qualifiedName, page, attributes);
078: }
079:
080: /**
081: * Simulate clicking this element.
082: *
083: * @return The page that occupies this window after this element is
084: * clicked. It may be the same window or it may be a freshly loaded one.
085: * @exception IOException If an IO error occurs
086: */
087: public Page click() throws IOException {
088: return click(false, false, false);
089: }
090:
091: /**
092: * Simulate clicking this element.
093: *
094: * @param shiftKey true if SHIFT is pressed
095: * @param ctrlKey true if CTRL is pressed
096: * @param altKey true if ALT is pressed
097: *
098: * @return The page that occupies this window after this element is
099: * clicked. It may be the same window or it may be a freshly loaded one.
100: * @exception IOException If an IO error occurs
101: */
102: public Page click(final boolean shiftKey, final boolean ctrlKey,
103: final boolean altKey) throws IOException {
104: if (this instanceof DisabledElement
105: && ((DisabledElement) this ).isDisabled()) {
106: return getPage();
107: }
108:
109: final Event event = new MouseEvent(this , MouseEvent.TYPE_CLICK,
110: shiftKey, ctrlKey, altKey, MouseEvent.BUTTON_LEFT);
111: return click(event);
112: }
113:
114: /**
115: * <span style="color:red">INTERNAL API - SUBJECT TO CHANGE AT ANY TIME - USE AT YOUR OWN RISK.</span><br/>
116: * Simulate clicking this element.
117: *
118: * @param event the click event used.
119: *
120: * @return The page that occupies this window after this element is
121: * clicked. It may be the same window or it may be a freshly loaded one.
122: * @exception IOException If an IO error occurs
123: */
124: public Page click(final Event event) throws IOException {
125: if (this instanceof DisabledElement
126: && ((DisabledElement) this ).isDisabled()) {
127: return getPage();
128: }
129:
130: final HtmlPage page = getPage();
131:
132: boolean stateUpdated = false;
133: if (isStateUpdateFirst()) {
134: doClickAction(page);
135: stateUpdated = true;
136: }
137: final ScriptResult scriptResult = fireEvent(event);
138: final Page currentPage;
139: if (scriptResult == null) {
140: currentPage = page;
141: } else {
142: currentPage = scriptResult.getNewPage();
143: }
144:
145: if (stateUpdated || ScriptResult.isFalse(scriptResult)
146: || event.isPreventDefault()) {
147: return currentPage;
148: } else {
149: return doClickAction(currentPage);
150: }
151: }
152:
153: /**
154: * Simulate double clicking this element, note that
155: * {@link #click()} is called first.
156: *
157: * @return The page that occupies this window after this element is double
158: * clicked. It may be the same window or it may be a freshly loaded one.
159: * @exception IOException If an IO error occurs
160: */
161: public Page dblClick() throws IOException {
162: return dblClick(false, false, false);
163: }
164:
165: /**
166: * Simulate double clicking this element, note that
167: * {@link #click(boolean, boolean, boolean)} is called first.
168: *
169: * @param shiftKey true if SHIFT is pressed
170: * @param ctrlKey true if CTRL is pressed
171: * @param altKey true if ALT is pressed
172: *
173: * @return The page that occupies this window after this element is double
174: * clicked. It may be the same window or it may be a freshly loaded one.
175: * @exception IOException If an IO error occurs
176: */
177: public Page dblClick(final boolean shiftKey, final boolean ctrlKey,
178: final boolean altKey) throws IOException {
179: if (this instanceof DisabledElement
180: && ((DisabledElement) this ).isDisabled()) {
181: return getPage();
182: }
183:
184: //call click event first
185: final Page clickPage = click(shiftKey, ctrlKey, altKey);
186: if (clickPage != getPage()) {
187: getLog()
188: .debug(
189: "dblClick() is ignored, as click() loaded a different page.");
190: return clickPage;
191: }
192:
193: final Event event = new MouseEvent(this ,
194: MouseEvent.TYPE_DBL_CLICK, shiftKey, ctrlKey, altKey,
195: MouseEvent.BUTTON_LEFT);
196: final ScriptResult scriptResult = fireEvent(event);
197: if (scriptResult == null) {
198: return clickPage;
199: } else {
200: return scriptResult.getNewPage();
201: }
202: }
203:
204: /**
205: * This method will be called if there either wasn't an onclick handler or
206: * there was but the result of that handler wasn't <code>false</code>.
207: * This is the default behavior of clicking the element.
208: * The default implementation returns
209: * the current page - subclasses requiring different behavior (like
210: * {@link HtmlSubmitInput}) will override this method.
211: *
212: * @param defaultPage The default page to return if the action does not
213: * load a new page.
214: * @return The page that is currently loaded after execution of this method
215: * @throws IOException If an IO error occurred
216: */
217: protected Page doClickAction(final Page defaultPage)
218: throws IOException {
219: return defaultPage;
220: }
221:
222: /**
223: * Return the value of the attribute "lang". Refer to the
224: * <a href='http://www.w3.org/TR/html401/'>HTML 4.01</a>
225: * documentation for details on the use of this attribute.
226: *
227: * @return The value of the attribute "lang"
228: * or an empty string if that attribute isn't defined.
229: */
230: public final String getLangAttribute() {
231: return getAttributeValue("lang");
232: }
233:
234: /**
235: * Return the value of the attribute "xml:lang". Refer to the
236: * <a href='http://www.w3.org/TR/html401/'>HTML 4.01</a>
237: * documentation for details on the use of this attribute.
238: *
239: * @return The value of the attribute "xml:lang"
240: * or an empty string if that attribute isn't defined.
241: */
242: public final String getXmlLangAttribute() {
243: return getAttributeValue("xml:lang");
244: }
245:
246: /**
247: * Return the value of the attribute "dir". Refer to the
248: * <a href='http://www.w3.org/TR/html401/'>HTML 4.01</a>
249: * documentation for details on the use of this attribute.
250: *
251: * @return The value of the attribute "dir"
252: * or an empty string if that attribute isn't defined.
253: */
254: public final String getTextDirectionAttribute() {
255: return getAttributeValue("dir");
256: }
257:
258: /**
259: * Return the value of the attribute "onclick". Refer to the
260: * <a href='http://www.w3.org/TR/html401/'>HTML 4.01</a>
261: * documentation for details on the use of this attribute.
262: *
263: * @return The value of the attribute "onclick"
264: * or an empty string if that attribute isn't defined.
265: */
266: public final String getOnClickAttribute() {
267: return getAttributeValue("onclick");
268: }
269:
270: /**
271: * Return the value of the attribute "ondblclick". Refer to the
272: * <a href='http://www.w3.org/TR/html401/'>HTML 4.01</a>
273: * documentation for details on the use of this attribute.
274: *
275: * @return The value of the attribute "ondblclick"
276: * or an empty string if that attribute isn't defined.
277: */
278: public final String getOnDblClickAttribute() {
279: return getAttributeValue("ondblclick");
280: }
281:
282: /**
283: * Return the value of the attribute "onmousedown". Refer to the
284: * <a href='http://www.w3.org/TR/html401/'>HTML 4.01</a>
285: * documentation for details on the use of this attribute.
286: *
287: * @return The value of the attribute "onmousedown"
288: * or an empty string if that attribute isn't defined.
289: */
290: public final String getOnMouseDownAttribute() {
291: return getAttributeValue("onmousedown");
292: }
293:
294: /**
295: * Return the value of the attribute "onmouseup". Refer to the
296: * <a href='http://www.w3.org/TR/html401/'>HTML 4.01</a>
297: * documentation for details on the use of this attribute.
298: *
299: * @return The value of the attribute "onmouseup"
300: * or an empty string if that attribute isn't defined.
301: */
302: public final String getOnMouseUpAttribute() {
303: return getAttributeValue("onmouseup");
304: }
305:
306: /**
307: * Return the value of the attribute "onmouseover". Refer to the
308: * <a href='http://www.w3.org/TR/html401/'>HTML 4.01</a>
309: * documentation for details on the use of this attribute.
310: *
311: * @return The value of the attribute "onmouseover"
312: * or an empty string if that attribute isn't defined.
313: */
314: public final String getOnMouseOverAttribute() {
315: return getAttributeValue("onmouseover");
316: }
317:
318: /**
319: * Return the value of the attribute "onmousemove". Refer to the
320: * <a href='http://www.w3.org/TR/html401/'>HTML 4.01</a>
321: * documentation for details on the use of this attribute.
322: *
323: * @return The value of the attribute "onmousemove"
324: * or an empty string if that attribute isn't defined.
325: */
326: public final String getOnMouseMoveAttribute() {
327: return getAttributeValue("onmousemove");
328: }
329:
330: /**
331: * Return the value of the attribute "onmouseout". Refer to the
332: * <a href='http://www.w3.org/TR/html401/'>HTML 4.01</a>
333: * documentation for details on the use of this attribute.
334: *
335: * @return The value of the attribute "onmouseout"
336: * or an empty string if that attribute isn't defined.
337: */
338: public final String getOnMouseOutAttribute() {
339: return getAttributeValue("onmouseout");
340: }
341:
342: /**
343: * Return the value of the attribute "onkeypress". Refer to the
344: * <a href='http://www.w3.org/TR/html401/'>HTML 4.01</a>
345: * documentation for details on the use of this attribute.
346: *
347: * @return The value of the attribute "onkeypress"
348: * or an empty string if that attribute isn't defined.
349: */
350: public final String getOnKeyPressAttribute() {
351: return getAttributeValue("onkeypress");
352: }
353:
354: /**
355: * Return the value of the attribute "onkeydown". Refer to the
356: * <a href='http://www.w3.org/TR/html401/'>HTML 4.01</a>
357: * documentation for details on the use of this attribute.
358: *
359: * @return The value of the attribute "onkeydown"
360: * or an empty string if that attribute isn't defined.
361: */
362: public final String getOnKeyDownAttribute() {
363: return getAttributeValue("onkeydown");
364: }
365:
366: /**
367: * Return the value of the attribute "onkeyup". Refer to the
368: * <a href='http://www.w3.org/TR/html401/'>HTML 4.01</a>
369: * documentation for details on the use of this attribute.
370: *
371: * @return The value of the attribute "onkeyup"
372: * or an empty string if that attribute isn't defined.
373: */
374: public final String getOnKeyUpAttribute() {
375: return getAttributeValue("onkeyup");
376: }
377:
378: /**
379: * Return true if the state update should be done before onclick event
380: * handling.
381: * This is expected to be overridden to return "true" by derived classes
382: * like HtmlCheckBoxInput.
383: * @return Return true if state update should be done first.
384: */
385: protected boolean isStateUpdateFirst() {
386: return false;
387: }
388:
389: }
|