001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: * $Header:$
018: */
019: package org.apache.beehive.netui.tags.html;
020:
021: import org.apache.beehive.netui.tags.IHtmlAccessable;
022: import org.apache.beehive.netui.tags.internal.PageFlowTagUtils;
023: import org.apache.beehive.netui.tags.javascript.CoreScriptFeature;
024: import org.apache.beehive.netui.tags.javascript.ScriptRequestState;
025: import org.apache.beehive.netui.tags.rendering.AbstractHtmlState;
026: import org.apache.beehive.netui.tags.rendering.InputImageTag;
027: import org.apache.beehive.netui.tags.rendering.TagRenderingBase;
028: import org.apache.beehive.netui.tags.rendering.WriteRenderAppender;
029: import org.apache.beehive.netui.util.Bundle;
030: import org.apache.struts.Globals;
031: import org.apache.struts.config.ModuleConfig;
032:
033: import javax.servlet.ServletRequest;
034: import javax.servlet.http.HttpServletRequest;
035: import javax.servlet.http.HttpServletResponse;
036: import javax.servlet.jsp.JspException;
037: import java.net.URISyntaxException;
038:
039: /**
040: * Generates an <code><input type="image"></code> tag with the specified attributes. ImageButton
041: * ignores its body content.
042: * @jsptagref.tagdescription Renders an <code><input type="image"></code> tag with the specified attributes.
043: *
044: * <p><b>JavaScript</b></p>
045: * <p>If the <netui:imageButton> specifies
046: * a <code>rolloverImage</code> attribute, the following JavaScript will be written to the page:</p>
047: * <pre> function swapImage(control, image)
048: * {
049: * control.src = image;
050: * }</pre>
051: * @example In this sample, an <netui:imageButton> tag displays the image "house.jpg".
052: * On mouseover, the image "house_highlight.jpg" is displayed.
053: * When clicked, the <netui:imageButton> will invoke the action specified by its parent
054: * <netui:form> tag.
055: * <pre> <netui:form action="formSubmit">
056: * <netui:imageButton rolloverImage="house_highlight.jpg" src="house.jpg" />
057: * </netui:form></pre>
058: * @netui:tag name="imageButton" description="Combines the functionality of the netui:image and netui:button tags."
059: */
060: public class ImageButton extends HtmlFocusBaseTag implements
061: IHtmlAccessable {
062: private InputImageTag.State _state = new InputImageTag.State();
063:
064: private String _page; // The module-relative URI of the image.
065: private String _rolloverImage; // The roll-over image of the ImageButton.
066:
067: /**
068: * Return the name of the Tag.
069: */
070: public String getTagName() {
071: return "ImageButton";
072: }
073:
074: /**
075: * This method will return the state associated with the tag. This is used by this
076: * base class to access the individual state objects created by the tags.
077: * @return a subclass of the <code>AbstractHtmlState</code> class.
078: */
079: protected AbstractHtmlState getState() {
080: return _state;
081: }
082:
083: /**
084: * Base support for the attribute tag. This is overridden to prevent setting the <code>src</code>
085: * and <code>value</code> attributes
086: * @param name The name of the attribute. This value may not be null or the empty string.
087: * @param value The value of the attribute. This may contain an expression.
088: * @param facet The name of a facet to which the attribute will be applied. This is optional.
089: * @throws JspException A JspException may be thrown if there is an error setting the attribute.
090: */
091: public void setAttribute(String name, String value, String facet)
092: throws JspException {
093: if (name != null) {
094: if (name.equals(SRC) || name.equals(VALUE)) {
095: String s = Bundle.getString(
096: "Tags_AttributeMayNotBeSet",
097: new Object[] { name });
098: registerTagError(s, null);
099: } else {
100: if (name.equals(DISABLED)) {
101: setDisabled(Boolean.parseBoolean(value));
102: return;
103: }
104: }
105: }
106: super .setAttribute(name, value, facet);
107: }
108:
109: /**
110: * Sets the property to specify where to align the image.
111: * @param align the image alignment.
112: * @jsptagref.attributedescription The alignment of the image.
113: * @jsptagref.databindable false
114: * @jsptagref.attributesyntaxvalue <i>string_align</i>
115: * @netui:attribute required="false" rtexprvalue="true"
116: * description="Sets the property to specify where to align the image."
117: */
118: public void setAlign(String align) {
119: _state.registerAttribute(AbstractHtmlState.ATTR_GENERAL, ALIGN,
120: align);
121: }
122:
123: /**
124: * Sets the accessKey attribute value. This should key value of the
125: * keyboard navigation key. It is recommended not to use the following
126: * values because there are often used by browsers <code>A, C, E, F, G,
127: * H, V, left arrow, and right arrow</code>.
128: * @param accessKey the accessKey value.
129: * @jsptagref.attributedescription The keyboard navigation key for the element.
130: * The following values are not recommended because they
131: * are often used by browsers: <code>A, C, E, F, G,
132: * H, V, left arrow, and right arrow</code>
133: * @jsptagref.databindable false
134: * @jsptagref.attributesyntaxvalue <i>string_accessKey</i>
135: * @netui:attribute required="false" rtexprvalue="true" type="char"
136: * description="The keyboard navigation key for the element.
137: * The following values are not recommended because they
138: * are often used by browsers: A, C, E, F, G,
139: * H, V, left arrow, and right arrow"
140: */
141: public void setAccessKey(char accessKey) {
142: _state.registerAttribute(AbstractHtmlState.ATTR_GENERAL,
143: ACCESSKEY, Character.toString(accessKey));
144: }
145:
146: /**
147: * Sets the tabIndex of the rendered html tag.
148: * @param tabindex the tab index.
149: * @jsptagref.attributedescription The tabIndex of the rendered HTML tag. This attribute determines the position of the
150: * rendered HTML tag in the sequence of tags that the user may advance through by pressing the TAB key.
151: * @jsptagref.databindable false
152: * @jsptagref.attributesyntaxvalue <i>string_tabIndex</i>
153: * @netui:attribute required="false" rtexprvalue="true" type="int"
154: * description="The tabIndex of the rendered HTML tag. This attribute determines the position of the
155: * rendered HTML tag in the sequence of tags that the user may advance through by pressing the TAB key."
156: */
157: public void setTabindex(int tabindex) {
158: _state.registerAttribute(AbstractHtmlState.ATTR_GENERAL,
159: TABINDEX, Integer.toString(tabindex));
160: }
161:
162: /**
163: * Sets the usemap of for the map.
164: * @param usemap the tab index.
165: * @jsptagref.attributedescription Sets the usemap of for the map.
166: * @jsptagref.databindable false
167: * @jsptagref.attributesyntaxvalue <i>string_usemap</i>
168: * @netui:attribute required="false" rtexprvalue="true"
169: * description="Sets the usemap of for the map."
170: */
171: public void setUsemap(String usemap) {
172: _state.registerAttribute(AbstractHtmlState.ATTR_GENERAL,
173: USEMAP, usemap);
174: }
175:
176: /**
177: * Sets the ismap of for the map.
178: * @param ismap the tab index.
179: * @jsptagref.attributedescription Sets the ismap of for the map.
180: * @jsptagref.databindable false
181: * @jsptagref.attributesyntaxvalue <i>string_ismap</i>
182: * @netui:attribute required="false" rtexprvalue="true"
183: * description="Sets the ismap of for the map."
184: */
185: public void setIsmap(String ismap) {
186: _state.registerAttribute(AbstractHtmlState.ATTR_GENERAL, ISMAP,
187: ismap);
188: }
189:
190: /**
191: * Sets the property to specify the alt text of the image.
192: * @param alt the image alt text.
193: * @jsptagref.attributedescription The alternative text of the image
194: * @jsptagref.databindable Read Only
195: * @jsptagref.attributesyntaxvalue <i>string_alt</i>
196: * @netui:attribute required="false" rtexprvalue="true"
197: * description="The alternative text of the image"
198: */
199: public void setAlt(String alt) {
200: _state.registerAttribute(AbstractHtmlState.ATTR_GENERAL, ALT,
201: alt);
202: }
203:
204: /**
205: * Sets the roll-over image of the ImageAnchor.
206: * @param rolloverImage the rollover image.
207: * @jsptagref.attributedescription The URI of the rollover image.
208: * @jsptagref.databindable false
209: * @jsptagref.attributesyntaxvalue <i>string_rolloverImage</i>
210: * @netui:attribute required="false" rtexprvalue="true"
211: * description="The URI of the rollover image."
212: */
213: public void setRolloverImage(String rolloverImage) {
214: _rolloverImage = rolloverImage;
215: }
216:
217: /**
218: * Sets the image source URI.
219: * @param src the source URI.
220: * @jsptagref.attributedescription The image source URI
221: * @jsptagref.databindable Read Only
222: * @jsptagref.attributesyntaxvalue <i>string_src</i>
223: * @netui:attribute required="false" rtexprvalue="true"
224: * description="The image source URI"
225: * reftype="img-url"
226: */
227: public void setSrc(String src) throws JspException {
228: _state.src = src;
229: }
230:
231: /**
232: * Set the value of the ImageButton.
233: * @param value the value of the ImageButton.
234: * @jsptagref.attributedescription The value of the image button.
235: * @jsptagref.databindable false
236: * @jsptagref.attributesyntaxvalue <i>string_value</i>
237: * @netui:attribute required="false" rtexprvalue="true"
238: * description="The value of the image button."
239: */
240: public void setValue(String value) {
241: _state.value = value;
242: }
243:
244: /**
245: * Process the start of this tag.
246: * @throws JspException if a JSP exception has occurred
247: */
248: public int doStartTag() throws JspException {
249:
250: if (_rolloverImage != null
251: && getJavaScriptAttribute(ONMOUSEOVER) == null) {
252: // cause the roll over script to be inserted
253: ScriptRequestState srs = ScriptRequestState
254: .getScriptRequestState((HttpServletRequest) pageContext
255: .getRequest());
256: WriteRenderAppender writer = new WriteRenderAppender(
257: pageContext);
258: srs.writeFeature(getScriptReporter(), writer,
259: CoreScriptFeature.ROLLOVER, true, false, null);
260: }
261:
262: return EVAL_BODY_BUFFERED;
263: }
264:
265: /**
266: * Save the body content of the ImageButton.
267: * @throws JspException if a JSP exception has occurred
268: */
269: public int doAfterBody() throws JspException {
270:
271: if (bodyContent != null) {
272: bodyContent.clearBody();
273: }
274: return SKIP_BODY;
275: }
276:
277: /**
278: * Process the end of this tag.
279: * @throws JspException if a JSP exception has occurred
280: */
281: public int doEndTag() throws JspException {
282: ServletRequest req = pageContext.getRequest();
283: String idScript = null;
284: String tmp = null;
285:
286: // we assume that tagId will over have override id if both
287: // are defined.
288: if (getTagId() != null) {
289: idScript = renderNameAndId((HttpServletRequest) req,
290: _state, null);
291: }
292:
293: HttpServletResponse response = (HttpServletResponse) pageContext
294: .getResponse();
295: tmp = src();
296: if (tmp != null) {
297: try {
298: String uri = PageFlowTagUtils.rewriteResourceURL(
299: pageContext, tmp, null, null);
300: _state.src = response.encodeURL(uri);
301: } catch (URISyntaxException e) {
302: // report the error...
303: String s = Bundle.getString("Tags_Image_URLException",
304: new Object[] { _state.src, e.getMessage() });
305: registerTagError(s, e);
306: }
307: }
308:
309: _state.disabled = isDisabled();
310:
311: if (_rolloverImage != null) {
312:
313: if (hasErrors()) {
314: reportErrors();
315: localRelease();
316: return EVAL_PAGE;
317: }
318:
319: try {
320: String uri = PageFlowTagUtils.rewriteResourceURL(
321: pageContext, _rolloverImage, null, null);
322: _rolloverImage = response.encodeURL(uri);
323: } catch (URISyntaxException e) {
324: // report the error...
325: String s = Bundle
326: .getString("Tags_Rollover_Image_URLException",
327: new Object[] { _rolloverImage,
328: e.getMessage() });
329: registerTagError(s, e);
330: }
331: }
332:
333: if ((getJavaScriptAttribute(ONMOUSEOUT) == null)
334: && (_rolloverImage != null)) {
335: setOnMouseOut("swapImage(this,'" + _state.src + "')");
336: }
337: if ((getJavaScriptAttribute(ONMOUSEOVER) == null)
338: && (_rolloverImage != null)) {
339: setOnMouseOver("swapImage(this,'" + _rolloverImage + "')");
340: }
341:
342: WriteRenderAppender writer = new WriteRenderAppender(
343: pageContext);
344: TagRenderingBase br = TagRenderingBase.Factory.getRendering(
345: TagRenderingBase.INPUT_IMAGE_TAG, req);
346: br.doStartTag(writer, _state);
347: br.doEndTag(writer);
348:
349: if (idScript != null)
350: write(idScript);
351:
352: // Evaluate the remainder of this page
353: localRelease();
354: return EVAL_PAGE;
355: }
356:
357: /**
358: * Release any acquired resources.
359: */
360: protected void localRelease() {
361: super .localRelease();
362:
363: _state.clear();
364:
365: _page = null;
366: _rolloverImage = null;
367: }
368:
369: /**
370: * Return the base source URL that will be rendered in the <code>src</code>
371: * property for this generated element, or <code>null</code> if there is
372: * no such URL.
373: */
374: private String src() {
375:
376: // Deal with a direct context-relative page that has been specified
377: if (_page != null) {
378: HttpServletRequest request = (HttpServletRequest) pageContext
379: .getRequest();
380: ModuleConfig config = (ModuleConfig) request
381: .getAttribute(Globals.MODULE_KEY);
382: if (config == null)
383: return (request.getContextPath() + _page);
384: return (request.getContextPath() + config.getPrefix() + _page);
385: }
386:
387: // Deal with an absolute source that has been specified
388: if (_state.src != null)
389: return _state.src;
390: return null;
391: }
392: }
|