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.ByRef;
022: import org.apache.beehive.netui.tags.rendering.AbstractHtmlState;
023: import org.apache.beehive.netui.tags.rendering.TagRenderingBase;
024: import org.apache.beehive.netui.tags.rendering.WriteRenderAppender;
025:
026: import javax.servlet.http.HttpServletRequest;
027: import javax.servlet.jsp.JspException;
028:
029: /**
030: * <p>
031: * Generates a URL-encoded hyperlink to a specified URI.
032: * Also adds support for URL re-writing and JavaScript-based form submission.
033: * An anchor must have one of the following attributes to correctly create the hyperlink:
034: * <ul>
035: * <li>action - an action invoked by clicking the hyperlink.</li>
036: * <li>href - a URL to go to</li>
037: * <li>linkName - an internal place in the page to move to</li>
038: * <li>clientAction - the action to run on the client</li>
039: * <li>tagId - the ID of the tag</li>
040: * <li>formSubmit - indicates whether or not the enclosing Form should be submitted</li>
041: * </ul>
042: * </p>
043: * @jsptagref.tagdescription <p>
044: * Generates an anchor that can link to another document or invoke an action method in the Controller file.
045: * The <netui:anchor> tag also supports JavaScript-based form submission and URL re-writing.
046: * <p>
047: * An anchor must have one of the following attributes to correctly create the hyperlink:
048: * <blockquote>
049: * <ul>
050: * <li><code>action</code> - the action method invoked by clicking the hyperlink</li>
051: * <li><code>href</code> - the URL to go to</li>
052: * <li><code>linkName</code> - an internal place in the page to move to</li>
053: * <li><code>clientAction</code> - the action to run on the client</li>
054: * <li><code>tagId</code> - the ID of the tag</li>
055: * <li><code>formSubmit</code> - indicates whether or not the enclosing Form should be submitted</li>
056: * </ul>
057: * </blockquote>
058: * </p>
059: * <p>
060: * The Anchor tag can accept NetUI parameter tags that implement the
061: * {@link IUrlParams} interface. When parameter tags are contained inside of
062: * the Anchor tag, they add URL parameters onto the rendered href. For
063: * example:
064: * <pre>
065: * <netui:anchor href="foo.jsp" value="Go To Foo">
066: * <netui:parameter name="paramKey" value="paramValue"/>
067: * </netui:anchor>
068: * </pre>
069: * will render:
070: * <pre>
071: * <a href="foo.jsp?paramKey=paramValue">Go To Foo</a>
072: * </pre>
073: * </p>
074: * @example <b>Submitting Form Data</b>
075: * <p>In this sample, clicking on this anchor submits the form data and invokes the method
076: * <code>submitForm</code>.
077: * <pre>
078: * <netui:form action="formSubmit">
079: * Firstname:
080: * <netui:textBox dataSource="actionForm.firstname"/>
081: * Lastname:
082: * <netui:textBox dataSource="actionForm.lastname"/>
083: * <netui:anchor formSubmit="true">Submit</netui:anchor>
084: * </netui:form></pre>
085: * <p>If the <code>formSubmit</code> attribute is set to <code>true</code> and no
086: * <code>onClick</code> attribute is set, the following JavaScript function will be written to the HTML page.
087: * This JavaScript function will be referenced by the <code>onclick</code> attribute of the generated anchor tag.</p>
088: * <pre>
089: * function anchor_submit_form(netuiName, newAction)
090: * {
091: * for (var i=0; i<document.forms.length; i++) {
092: * if (document.forms[i].id == netuiName) {
093: * document.forms[i].method = "POST";
094: * document.forms[i].action = newAction;
095: * document.forms[i].submit();
096: * }
097: * }
098: * }</pre>
099: * <p> The JavaScript function will be invoked by the generated HTML anchor tag as follows:
100: * <pre>
101: * <a href="/WebApp/tagSamples/anchor/formSubmit.do"
102: * onClick='anchor_submit_form("Netui_Form_0","/WebApp/tagSamples/anchor/formSubmit.do");return false;'>Submit</a></pre>
103: * <p>
104: * <b>Custom JavaScript Functions</b>
105: * </p>
106: * <p>It is possible to write a custom <code>onClick</code> JavaScript event handler that would
107: * do additional work, for example form validation, and still POST the form correctly. To
108: * accomplish this, add the custom JavaScript method to the page:
109: * <pre>
110: * function SubmitFromAnchor()
111: * {
112: * // implement custom logic here
113: *
114: * for(var i=0; i<document.forms.length; i++)
115: * {
116: * // submit to the action /aWebapp/formPost.do
117: * if (document.forms[i].action == "/aWebapp/formPost.do")
118: * {
119: * document.forms[i].method="POST";
120: * document.forms[i].action="/aWebapp/formPost.do";
121: * document.forms[i].submit();
122: * }
123: * }
124: * }</pre>
125: * Then reference the JavaScript method from the <netui:anchor> tag:
126: * <pre>
127: * <netui:anchor formSubmit="true" onClick="SubmitFromAnchor(); return false;">Submit</netui:anchor></pre>
128: * @netui:tag name="anchor" description="Generates a URL-encoded hyperlink to a specified URI."
129: * @see Attribute
130: * @see java.lang.String
131: */
132: public class Anchor extends AnchorBase {
133: private String _text; // The body content of this tag (if any).
134: private String _value;
135:
136: /**
137: * Returns the name of the Tag.
138: */
139: public String getTagName() {
140: return "Anchor";
141: }
142:
143: /**
144: * This method will return the state associated with the tag. This is used by this
145: * base class to access the individual state objects created by the tags.
146: * @return a subclass of the <code>AbstractHtmlState</code> class.
147: */
148: public AbstractHtmlState getState() {
149: return _state;
150: }
151:
152: /**
153: * Sets the onClick javascript event.
154: * @param onclick the onClick event.
155: * @jsptagref.attributedescription The onClick JavaScript event.
156: * @jsptagref.databindable false
157: * @jsptagref.attributesyntaxvalue <i>string_onClick</i>
158: * @netui:attribute required="false" rtexprvalue="true"
159: * description="The onClick JavaScript event."
160: */
161: public void setOnClick(String onclick) {
162: _state.registerAttribute(AbstractHtmlState.ATTR_JAVASCRIPT,
163: ONCLICK, setNonEmptyValueAttribute(onclick));
164: // Jira 299
165: //_state.onClick = setNonEmptyValueAttribute(onclick);
166: }
167:
168: /**
169: * Set a client action to run on the client. When set on an anchor, a NetUI JavaScript action
170: * will be run. This attribute may not be set if <code>href</code> or <code>action</code> is set.
171: * @param action an action to run on the client.
172: * @jsptagref.attributedescription The action (NetUI JavaScript) to run on the client.
173: * @jsptagref.databindable false
174: * @jsptagref.attributesyntaxvalue <i>string_clientAction</i>
175: * @netui:attribute required="false" rtexprvalue="true" description="The client action."
176: * description="The action (NetUI JavaScript) to run on the client."
177: */
178: public void setClientAction(String action) throws JspException {
179: _clientAction = setRequiredValueAttribute(action,
180: "clientAction");
181: }
182:
183: /**
184: * Sets the link name of the Anchor. The link name is treated as a fragment
185: * identifier and may or may not contain the "#" character. If it does, the
186: * link name will not be qualified into a ScriptContainer. If the link name
187: * does not contain the "#" the normal tagId qualification will take place
188: * to produce the actual fragment identifier.
189: * @param linkName the link name for the Anchor.
190: * @jsptagref.attributedescription An internal place on the page to go to.
191: * @jsptagref.databindable false
192: * @jsptagref.attributesyntaxvalue <i>string_linkName</i>
193: * @netui:attribute required="false" rtexprvalue="true"
194: * description="An internal place on the page to go to."
195: */
196: public void setLinkName(String linkName) throws JspException {
197: _linkName = setRequiredValueAttribute(linkName, "linkName");
198: }
199:
200: /**
201: * Sets <code>charset</code> attribute for the anchor.
202: * @param charSet the window target.
203: * @jsptagref.attributedescription The character set.
204: * @jsptagref.databindable false
205: * @jsptagref.attributesyntaxvalue <i>string_charset</i>
206: * @netui:attribute required="false" rtexprvalue="true"
207: * description="The character set."
208: */
209: public void setCharSet(String charSet) {
210: _state.registerAttribute(AbstractHtmlState.ATTR_GENERAL,
211: CHARSET, charSet);
212: }
213:
214: /**
215: * Sets <code>type</code> attribute for the anchor.
216: * @param type the window target.
217: * @jsptagref.attributedescription The type.
218: * @jsptagref.databindable false
219: * @jsptagref.attributesyntaxvalue <i>string_type</i>
220: * @netui:attribute required="false" rtexprvalue="true"
221: * description="The type."
222: */
223: public void setType(String type) {
224: _state.registerAttribute(AbstractHtmlState.ATTR_GENERAL, TYPE,
225: type);
226: }
227:
228: /**
229: * Sets <code>hreflang</code> attribute for the anchor.
230: * @param hreflang the window target.
231: * @jsptagref.attributedescription The HREF lang.
232: * @jsptagref.databindable false
233: * @jsptagref.attributesyntaxvalue <i>string_hreflang</i>
234: * @netui:attribute required="false" rtexprvalue="true"
235: * description="The HREF lang."
236: */
237: public void setHrefLang(String hreflang) {
238: _state.registerAttribute(AbstractHtmlState.ATTR_GENERAL,
239: HREFLANG, hreflang);
240: }
241:
242: /**
243: * Sets <code>rel</code> attribute for the anchor.
244: * @param rel the window target.
245: * @jsptagref.attributedescription The relationship between the current document and the target Url.
246: * @jsptagref.databindable false
247: * @jsptagref.attributesyntaxvalue <i>string_rel</i>
248: * @netui:attribute required="false" rtexprvalue="true"
249: * description="The rel."
250: */
251: public void setRel(String rel) {
252: _state.registerAttribute(AbstractHtmlState.ATTR_GENERAL, REL,
253: rel);
254: }
255:
256: /**
257: * Sets <code>rev</code> attribute for the anchor.
258: * @param rev the window target.
259: * @jsptagref.attributedescription Describes a reverse link from the anchor specified to the current document.
260: * @jsptagref.databindable false
261: * @jsptagref.attributesyntaxvalue <i>string_rev</i>
262: * @netui:attribute required="false" rtexprvalue="true"
263: * description="The rev."
264: */
265: public void setRev(String rev) {
266: _state.registerAttribute(AbstractHtmlState.ATTR_GENERAL, REV,
267: rev);
268: }
269:
270: /**
271: * Sets the window target.
272: * @param target the window target.
273: * @jsptagref.attributedescription The window target.
274: * @jsptagref.databindable false
275: * @jsptagref.attributesyntaxvalue <i>string_action</i>
276: * @netui:attribute required="false" rtexprvalue="true"
277: * description="The window target."
278: */
279: public void setTarget(String target) {
280: _state.registerAttribute(AbstractHtmlState.ATTR_GENERAL,
281: TARGET, target);
282: }
283:
284: /**
285: * This will set the text of the anchor. If there is body content, this
286: * will override that value.
287: * @param value the text of the anchor.
288: * @jsptagref.attributedescription Set the text of the anchor, overriding the body content.
289: * @jsptagref.databindable false
290: * @jsptagref.attributesyntaxvalue <i>string_value</i>
291: * @netui:attribute required="false" rtexprvalue="true"
292: * description="Set the text of the anchor overriding the body content"
293: */
294: public void setValue(String value) {
295: _value = setNonEmptyValueAttribute(value);
296: }
297:
298: /**
299: * Prepare the hyperlink for rendering
300: * @throws JspException if a JSP exception has occurred
301: */
302: public int doStartTag() throws JspException {
303: if (hasErrors())
304: return SKIP_BODY;
305: return EVAL_BODY_BUFFERED;
306: }
307:
308: /**
309: * Save the body content of the Anchor.
310: * @throws JspException if a JSP exception has occurred
311: */
312: public int doAfterBody() throws JspException {
313: if (bodyContent != null && _value == null) {
314: String value = bodyContent.getString().trim();
315: bodyContent.clearBody();
316: if (value.length() > 0)
317: _text = value;
318: }
319: return SKIP_BODY;
320: }
321:
322: /**
323: * Render the hyperlink.
324: * @throws JspException if a JSP exception has occurred
325: */
326: public int doEndTag() throws JspException {
327: // report errors that may have occurred when the required attributes are being set
328: if (hasErrors())
329: return reportAndExit(EVAL_PAGE);
330:
331: if (_value != null) {
332: _text = _value;
333: }
334:
335: // build the anchor into the results
336: ByRef script = new ByRef();
337:
338: WriteRenderAppender writer = new WriteRenderAppender(
339: pageContext);
340: HttpServletRequest request = (HttpServletRequest) pageContext
341: .getRequest();
342: TagRenderingBase trb = TagRenderingBase.Factory.getRendering(
343: TagRenderingBase.ANCHOR_TAG, request);
344:
345: if (!createAnchorBeginTag(request, script, trb, writer,
346: REQUIRED_ATTR)) {
347: if (!script.isNull())
348: write(script.getRef().toString());
349: return reportAndExit(EVAL_PAGE);
350: }
351:
352: if (_text != null)
353: write(_text);
354:
355: assert (trb != null) : "trb is null";
356: trb.doEndTag(writer);
357:
358: if (!script.isNull())
359: write(script.getRef().toString());
360:
361: // Render the remainder to the output stream
362: localRelease();
363: return EVAL_PAGE;
364: }
365:
366: }
|