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.template;
020:
021: import org.apache.beehive.netui.util.internal.InternalStringBuilder;
022:
023: import org.apache.beehive.netui.tags.AbstractClassicTag;
024: import org.apache.beehive.netui.tags.javascript.IScriptReporter;
025: import org.apache.beehive.netui.tags.javascript.ScriptRequestState;
026: import org.apache.beehive.netui.tags.divpanel.DivPanel;
027: import org.apache.beehive.netui.tags.databinding.repeater.Repeater;
028: import org.apache.beehive.netui.util.Bundle;
029:
030: import javax.servlet.ServletRequest;
031: import javax.servlet.http.HttpServletRequest;
032: import javax.servlet.jsp.JspException;
033: import javax.servlet.jsp.tagext.BodyContent;
034: import javax.servlet.jsp.tagext.Tag;
035: import java.util.HashMap;
036:
037: import org.apache.struts.util.ResponseUtils;
038:
039: /**
040: * Used within a content page to provide content for a placeholder
041: * section defined within a template. The body content of the tag
042: * is passed to the <code>IncludeSection</code> tag in the template
043: * providing the content for that section.
044: * If the <code>name</code> attribute matches a
045: * <code>name</code> attribute on a
046: * <code>IncludeSection</code> tag in the template, the body
047: * content of this tag will be rendered.
048:
049: * @jsptagref.tagdescription
050: * Sets HTML content inside placeholders defined by a
051: * {@link IncludeSection} tag.
052: *
053: * <p>The <netui-template:section> tag must have a parent
054: * {@link Template} tag.
055: *
056: * <p>The <netui-template:section> tag appears in content pages, which adopt a template page,
057: * set properties on the template's placeholders
058: * (using this <netui-template:section> tag),
059: * and render the completed HTML in the browser.
060: *
061: * <p>For content to be placed in the placeholder, the <netui-template:section> and
062: * <netui-template:includeSection> tags must have matching <code>name</code> attributes.
063: *
064: * <p>For example, assume a template page defines the following content placeholder.
065: *
066: * <p><b>In the template JSP page...</b>
067: *
068: * <pre> <table>
069: * <tr>
070: * <td colspan="3">
071: * <netui-template:includeSection name="tableHeader"/>
072: * </td>
073: * </tr></pre>
074: *
075: * <p>Then a content page can set HTML content in the placeholder using the <netui-template:section> tag.
076: *
077: * <p><b>In a content JSP page...</b>
078: *
079: * <pre> <netui-template:section name="tableHeader">
080: * <h1>HEADER TEXT</h1>
081: * </netui-template:section></pre>
082: *
083: * <p>The HTML rendered in the browser will appear as follows.
084: *
085: * <pre> <table>
086: * <tr>
087: * <td colspan="3">
088: * <h1>HEADER TEXT</h1>
089: * </td>
090: * </tr></pre>
091: *
092: * @example
093: * Assume a <netui-template:includeSection> tag defines a content placeholder inside a
094: * table row
095: *
096: * <pre> <tr>
097: * <netui-template:includeSection name="rowPlaceholder"/>
098: * </tr></pre>
099: *
100: * <p>A content page can set content into the placeholder using the <netui-template:section>
101: * tag as follows.
102: *
103: * <pre> <netui-template:section name="rowPlaceHolder">
104: * <td><p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit,
105: * sed diam nonummy nibh euismod tincidunt ut laoreet dolore
106: * magna aliquam erat volutpat. Ut wisi enim ad minim veniam,
107: * quis nostrud exerci tation ullamcorper suscipit lobortis nisl
108: * ut aliquip ex ea commodo consequat.</p></td>
109: * </netui-template:section></pre>
110: *
111: * The HTML rendered in the browser will appear as follows.
112: *
113: * <pre> <tr>
114: * <td><p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit,
115: * sed diam nonummy nibh euismod tincidunt ut laoreet dolore
116: * magna aliquam erat volutpat. Ut wisi enim ad minim veniam,
117: * quis nostrud exerci tation ullamcorper suscipit lobortis nisl
118: * ut aliquip ex ea commodo consequat.</p></td>
119: * </tr></pre>
120: *
121: * @netui:tag name="section"
122: * description="Use this tag to mark out content to replace a netui-template:includeSection within a template file."
123: */
124: public class Section extends AbstractClassicTag implements
125: TemplateConstants {
126: /**
127: * The name of the section.
128: */
129: private String _name;
130:
131: /**
132: * Is the section visible
133: */
134: private boolean _visible = true;
135:
136: /**
137: * Returns the name of the Tag. This is used to
138: * identify the type of tag reporting errors.
139: * @return a constant string representing the name of the tag.
140: */
141: public String getTagName() {
142: return "Section";
143: }
144:
145: /**
146: * Sets the name of the placeholder section defined in
147: * the template that this tag is providing content for.
148: * This name is matched against the <code>IncludeSection</code>
149: * name. If the names match, the content of this tag will be
150: * rendered within the template's section.
151: * @param name The name of an <code>IncludeSection<code> the
152: * this tag is providing content for.
153: *
154: * @jsptagref.attributedescription
155: * The name of the content to fill the placeholder.
156: * This name is matched against the <netui-template:includeSection>
157: * name. If the names match, the content of this tag will be
158: * rendered within the template's placeholder.
159: *
160: * @jsptagref.databindable false
161: *
162: * @jsptagref.attributesyntaxvalue <i>string_name</i>
163: *
164: * @netui:attribute required="true" rtexprvalue="true"
165: * description="The name of the content to fill the placeholder."
166: */
167: public void setName(String name) {
168: _name = name;
169: }
170:
171: /**
172: * Sets the visible state of the tag.
173: * @param visible <code>Boolean</code> value representing the visible state.
174: *
175: * @jsptagref.attributedescription
176: * Boolean. Determines if the section is visible.
177: *
178: * @jsptagref.databindable false
179: *
180: * @jsptagref.attributesyntaxvalue <i>boolean_literal_visible</i>
181: *
182: * @netui:attribute required="false" rtexprvalue="true" type="boolean"
183: * description="Determines if the section is visible."
184: */
185: public void setVisible(boolean visible) {
186: _visible = visible;
187: }
188:
189: /**
190: * Causes the content of the section to be rendered into a buffer.
191: * @return SKIP_BODY if the visible state is <code>false</code>,
192: * otherwise EVAL_BODY_BUFFERED to cause the body content to be buffered.
193: * @throws JspException if there are errors.
194: */
195: public int doStartTag() throws JspException {
196:
197: if (!_visible)
198: return SKIP_BODY;
199:
200: // If the parent is a DivPanel then this section will be inlined.
201: Tag parentTag = getParent();
202: // If the parent tag is a repeater then we must insure that the parent of that is a DivPanel
203: if (parentTag instanceof Repeater) {
204: parentTag = parentTag.getParent();
205: if (!(parentTag instanceof DivPanel)) {
206: String s = Bundle.getString("Temp_SectionInRepeater");
207: registerTagError(s, null);
208: reportErrors();
209: localRelease();
210: return EVAL_PAGE;
211: }
212: }
213: if (parentTag instanceof DivPanel) {
214: InternalStringBuilder results = new InternalStringBuilder(
215: 128);
216: results.append("<div ");
217: renderTagId(results);
218: if (hasErrors()) {
219: reportErrors();
220: localRelease();
221: return EVAL_PAGE;
222: }
223: results.append(">");
224: ResponseUtils.write(pageContext, results.toString());
225: return EVAL_BODY_BUFFERED;
226: }
227:
228: return EVAL_BODY_BUFFERED;
229: }
230:
231: /**
232: * Stores the buffered body content into the <code>TEMPLATE_SECTIONS
233: * HashMap</code>. The buffered body is
234: * accessed by the template page to obtain
235: * the content for <code>IncludeSection</code> tags.
236: * @return EVAL_PAGE to continue evaluating the page.
237: * @throws JspException on error.
238: */
239: public int doEndTag() throws JspException {
240:
241: // If the parent is a DivPanel then this section will be inlined.
242: Tag parentTag = getParent();
243: if (parentTag instanceof Repeater) {
244: parentTag = parentTag.getParent();
245: }
246: if (parentTag instanceof DivPanel) {
247: return processDivPanel();
248: }
249: assert (parentTag instanceof Template);
250: return processTemplate();
251: }
252:
253: /**
254: * Resets all of the fields of the tag.
255: */
256: protected void localRelease() {
257: super .localRelease();
258: _name = null;
259: _visible = true;
260: }
261:
262: /**
263: * This method will process the section in the context of a DivPanel
264: * @return returns the integer code doEndTag() will return.
265: */
266: private int processDivPanel() throws JspException {
267:
268: if (!_visible)
269: return EVAL_PAGE;
270:
271: if (hasErrors()) {
272: reportErrors();
273: localRelease();
274: return EVAL_PAGE;
275: }
276:
277: BodyContent bc = getBodyContent();
278: String content = (bc != null) ? bc.getString() : "";
279: ResponseUtils.write(pageContext, content);
280: ResponseUtils.write(pageContext, "</div>");
281: localRelease();
282: return EVAL_PAGE;
283: }
284:
285: /**
286: * This method will process the section in the context of the Template
287: * @return returns the integer code doEndTag() will return.
288: */
289: private int processTemplate() {
290: ServletRequest req = pageContext.getRequest();
291: Template.TemplateContext tc = (Template.TemplateContext) req
292: .getAttribute(TEMPLATE_SECTIONS);
293:
294: if (tc.secs == null) {
295: tc.secs = new HashMap();
296: }
297:
298: assert (tc.secs != null);
299:
300: if (!_visible) {
301: // set the section so that it doesn't contain anything
302: tc.secs.put(_name, "");
303: localRelease();
304: return EVAL_PAGE;
305: }
306: if (hasErrors()) {
307: String s = getErrorsReport();
308: tc.secs.put(_name, s);
309: localRelease();
310: return EVAL_PAGE;
311: }
312:
313: BodyContent bc = getBodyContent();
314: String content = (bc != null) ? bc.getString() : "";
315: tc.secs.put(_name, content);
316: localRelease();
317: return EVAL_PAGE;
318: }
319:
320: // @TODO: this code is duplicated between section and divPanel
321: /**
322: * This method will handle creating the tagId attribute. The tagId attribute indentifies the
323: * tag in the generated HTML. There is a lookup table created in JavaScript mapping the <coe>tagId</code>
324: * to the actual name. The tagId is also run through the naming service so it can be scoped. Some tags will
325: * write that <code>tagid</code> out as the <code>id</code> attribute of the HTML tag being generated.
326: * @param buffer
327: * @return String
328: */
329: private final String renderTagId(InternalStringBuilder buffer)
330: throws JspException {
331: assert (_name != null);
332:
333: // @todo: this is busted. It should be writing out inline.
334: String realName = rewriteName(_name);
335: String idScript = mapLegacyTagId(_name, realName);
336:
337: // some tags will output the id attribute themselves so they don't write this out
338: renderAttribute(buffer, "id", realName);
339: return idScript;
340: }
341:
342: /**
343: * This method will write append an attribute value to a InternalStringBuilder.
344: * The method assumes that the attr is not <code>null</code>. If the
345: * value is <code>null</code> the attribute will not be appended to the
346: * <code>InternalStringBuilder</code>.
347: */
348: private void renderAttribute(InternalStringBuilder buf,
349: String name, String value) {
350: assert (name != null);
351: if (value == null)
352: return;
353:
354: buf.append(" ");
355: buf.append(name);
356: buf.append("=\"");
357: buf.append(value);
358: buf.append("\"");
359: }
360:
361: private String mapLegacyTagId(String tagId, String value) {
362: // @todo: this is sort of broken, it needs to be updated
363: IScriptReporter scriptReporter = getScriptReporter();
364: ScriptRequestState srs = ScriptRequestState
365: .getScriptRequestState((HttpServletRequest) pageContext
366: .getRequest());
367: String scriptId = srs.mapLegacyTagId(scriptReporter, tagId,
368: value);
369: return scriptId;
370: }
371: }
|