All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.zkoss.zk.ui.HtmlNativeComponent Maven / Gradle / Ivy

There is a newer version: 10.0.0-jakarta
Show newest version
/* HtmlNativeComponent.java

	Purpose:
		
	Description:
		
	History:
		Thu Jul 19 18:05:01     2007, Created by tomyeh

Copyright (C) 2007 Potix Corporation. All Rights Reserved.

{{IS_RIGHT
	This program is distributed under LGPL Version 2.1 in the hope that
	it will be useful, but WITHOUT ANY WARRANTY.
}}IS_RIGHT
*/
package org.zkoss.zk.ui;

import java.io.StringWriter;
import java.io.Writer;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.zkoss.html.HTMLs;
import org.zkoss.idom.Namespace;
import org.zkoss.lang.Strings;
import org.zkoss.zk.ui.ext.DynamicTag;
import org.zkoss.zk.ui.ext.Native;
import org.zkoss.zk.ui.ext.render.DirectContent;
import org.zkoss.zk.ui.ext.render.PrologAllowed;
import org.zkoss.zk.ui.impl.NativeHelpers;
import org.zkoss.zk.ui.sys.ComponentCtrl;
import org.zkoss.zk.ui.sys.ComponentsCtrl;
import org.zkoss.zk.ui.sys.ExecutionsCtrl;
import org.zkoss.zk.ui.sys.HtmlPageRenders;
import org.zkoss.zk.ui.sys.PropertyAccess;
import org.zkoss.zk.ui.sys.StringPropertyAccess;

/**
 * A component used to represent XML elements that are associated
 * with the native namespace (http://www.zkoss.org/2005/zk/native).
 *
 * 

It contains the content that shall be sent directly to client. * It has three parts: prolog, children and epilog. * The prolog ({@link #getPrologContent}) and epilog ({@link #getEpilogContent}) * are both {@link String}. * *

When this component is rendered ({@link #redraw}), it generates * the prolog first, the children and then the epilog. * * @author tomyeh * @since 3.0.0 */ public class HtmlNativeComponent extends AbstractComponent implements DynamicTag, Native { //cannot be RawId since two native might have the same ID private static final Helper _helper = new HtmlHelper(); private static final String ATTR_RENDER_CONTEXT = "org.zkoss.zk.native.renderContext"; //--------- //structure: _prefix <_tag> _prolog children _epilog _postifx //--------- private String _tag; private String _prolog = "", _epilog = ""; /** The text before the tag name. */ private String _prefix, _postfix; private Map _props; /** Declared namespaces ({@link Namespace}). */ private List _dns; /** Constructs a {@link HtmlNativeComponent} component. * */ public HtmlNativeComponent() { } /** Constructs a {@link HtmlNativeComponent} component with the specified tag name. * * @param tag the tag name. If null or empty, plain text is assumed. */ public HtmlNativeComponent(String tag) { setTag(tag); } /** Constructs a {@link HtmlNativeComponent} component with the specified * prolog and epilog. * @param tag the tag name. If null or empty, plain text is assumed. * @param prolog the content right before the children, if any. * @param epilog the content right after the children, if any. */ public HtmlNativeComponent(String tag, String prolog, String epilog) { this(tag); _prolog = prolog != null ? prolog : ""; _epilog = epilog != null ? epilog : ""; } /** Returns the widget class, "zk.Native". * @since 5.0.0 */ public String getWidgetClass() { return "zk.Native"; } /** Returns the tag name, or null if plain text. */ public String getTag() { return _tag; } //Native// public List getDeclaredNamespaces() { if (_dns != null) return _dns; return Collections.emptyList(); } public void addDeclaredNamespace(Namespace ns) { if (ns == null) throw new IllegalArgumentException(); if (_dns == null) _dns = new LinkedList(); _dns.add(ns); } public String getPrologContent() { return _prolog; } public void setPrologContent(String prolog) { _prolog = prolog != null ? prolog : ""; } public String getEpilogContent() { return _epilog; } public void setEpilogContent(String epilog) { _epilog = epilog != null ? epilog : ""; } public Helper getHelper() { return _helper; } //-- Component --// public boolean setVisible(boolean visible) { throw new UnsupportedOperationException("Use client-dependent attribute, such as display:none"); } public void redraw(Writer out) throws java.io.IOException { //Note: _tag == null can NOT be handled specially final Execution exec = Executions.getCurrent(); final boolean root = getParent() == null && (getPage().isComplete() || (exec != null && "complete".equals(ExecutionsCtrl.getPageRedrawControl(exec)))); if (exec == null || exec.isAsyncUpdate(null) || (!root && !HtmlPageRenders.isDirectContent(exec))) { super.redraw(out); //renderProperties (assume in zscript) return; } Writer oldout = null; if (exec != null && !HtmlPageRenders.isZkTagsGenerated(exec) && exec.getAttribute(ATTR_TOP_NATIVE) == null) { //need to check topmost native only String tn; if (root || "html".equals(tn = _tag != null ? _tag.toLowerCase(java.util.Locale.ENGLISH) : "") || "body".equals(tn) || "head".equals(tn)) { exec.setAttribute(ATTR_TOP_NATIVE, Boolean.TRUE); oldout = out; out = new StringWriter(); } } out.write(getPrologHalf()); //children Component child = getFirstChild(); if (child == null) { //need to invoke outStandalone to generate response if any (Bug 3009925) //however, it is not required if not root (since others will invoke) if (root) HtmlPageRenders.outStandalone(exec, null, out); } else { if (root) HtmlPageRenders.setDirectContent(exec, true); do { Component next = child.getNextSibling(); if (child instanceof Native || ((ComponentCtrl) child).getExtraCtrl() instanceof DirectContent) { ((ComponentCtrl) child).redraw(out); } else { HtmlPageRenders.setDirectContent(exec, false); HtmlPageRenders.outStandalone(exec, child, out); HtmlPageRenders.setDirectContent(exec, true); } child = next; } while (child != null); } out.write(getEpilogHalf()); if (oldout != null) { exec.removeAttribute(ATTR_TOP_NATIVE); //order: //1. replace if found //2. insert before if found //3. insert after if found //4. insert after if found //5. insert at the end if none of above found final StringBuffer sb = ((StringWriter) out).getBuffer(); if (!HtmlPageRenders.isZkTagsGenerated(exec)) { int jhead = -1, //anchor of header junav = -1, //anchor of unavailable head = -1, //index of heade = -1, //index of html = -1; //index of for (int j = 0, len = sb.length(); (j = sb.indexOf("<", j)) >= 0;) { ++j; if (jhead < 0 && startsWith(sb, "zkhead", j)) { int l = Strings.indexOf(sb, '>', j) + 1; sb.delete(jhead = --j, l); //jhead found len = sb.length(); } else if (head < 0 && startsWith(sb, "head", j)) { head = Strings.indexOf(sb, '>', j) + 1; } else if (html < 0 && startsWith(sb, "html", j)) { html = Strings.indexOf(sb, '>', j) + 1; } else if (junav < 0 && startsWith(sb, "body", j)) { junav = Strings.indexOf(sb, '>', j) + 1; //junav found break; //done } else if (sb.charAt(j) == '/' && startsWith(sb, "head", ++j)) { heade = j - 2; } } boolean disableUnavailable = false; if (jhead < 0 && ((jhead = head) < 0) //use if no && ((jhead = heade) < 0) //use if no (though unlikely) && ((jhead = junav) < 0) //use if no && ((jhead = html) < 0)) { //use if no if (_tag != null) { final String tn = _tag.toLowerCase(java.util.Locale.ENGLISH); if ("div".equals(tn) || "span".equals(tn)) { l_loop: for (int j = 0, len = sb.length(); j < len; ++j) switch (sb.charAt(j)) { case '>': disableUnavailable = true; //make output cleaner jhead = j + 1; //found case '=': //it might have something depends on JS case '"': break l_loop; } } } if (jhead < 0) jhead = 0; //insert at head if not found } final String msg = HtmlPageRenders.outUnavailable(exec); //called if disableUnavailable (so it won't be generated later) if (msg != null && !disableUnavailable) { if (junav < 0) { if (html >= 0) junav = sb.lastIndexOf("= 0) sb.insert(junav < jhead ? jhead : junav, msg); else sb.append(msg); } final String zktags = HtmlPageRenders.outHeaderZkTags(exec, getPage()); if (zktags != null) sb.insert(jhead, zktags); } oldout.write(sb.toString()); } } /** Used to indicate the redrawing of the top native is found. */ private static final String ATTR_TOP_NATIVE = "zkHtmlTopNative"; private static boolean startsWith(StringBuffer sb, String tag, int start) { int end = start + tag.length(); char cc; return sb.length() > end && tag.equalsIgnoreCase(sb.substring(start, end)) && ((cc = sb.charAt(end)) < 'a' || cc > 'z') && (cc < 'A' || cc > 'Z'); } protected void renderProperties(org.zkoss.zk.ui.sys.ContentRenderer renderer) throws java.io.IOException { super.renderProperties(renderer); render(renderer, "prolog", getPrologHalf()); render(renderer, "epilog", getEpilogHalf()); } private String getPrologHalf() { final StringBuffer sb = new StringBuffer(128); final Helper helper = getHelper(); //don't use _helper directly, since the derive might override it if (_prefix != null) sb.append(_prefix); //first half helper.getFirstHalf(sb, _tag, _props, _dns); //prolog sb.append(_prolog); //no encoding return sb.toString(); } private String getEpilogHalf() { final StringBuffer sb = new StringBuffer(128); final Helper helper = getHelper(); //epilog sb.append(_epilog); //second half helper.getSecondHalf(sb, _tag); if (_postfix != null) sb.append(_postfix); return sb.toString(); } //DynamicTag// /** Sets the tag name. * * @param tag the tag name. If null or empty, plain text is assumed. */ public void setTag(String tag) throws WrongValueException { _tag = tag != null && tag.length() > 0 ? tag : null; } public boolean hasTag(String tag) { return true; //accept anything } public boolean hasDynamicProperty(String name) { return ComponentsCtrl.isReservedAttribute(name); } public Object getDynamicProperty(String name) { return _props != null ? _props.get(name) : null; } public Map getDynamicProperties() { return _props; } public void setDynamicProperty(String name, Object value) throws WrongValueException { if (name == null) throw new WrongValueException("name required"); if (value == null) { if (_props != null) _props.remove(name); } else { if (_props == null) _props = new LinkedHashMap(); if ("sclass".equals(name)) _props.put("class", value); else _props.put(name, value); } } /** The HTML helper. */ public static class HtmlHelper implements Helper { public Component newNative(String text) { final HtmlNativeComponent nc = new HtmlNativeComponent(); if (text != null) nc.setPrologContent(text); return nc; } public void getFirstHalf(StringBuffer sb, String tag, Map props, Collection namespaces) { if (tag != null) sb.append('<').append(tag); NativeHelpers.getAttributes(sb, props, namespaces); if (tag != null) { final String tn = tag.toLowerCase(java.util.Locale.ENGLISH); if ("zkhead".equals(tn) || HTMLs.isOrphanTag(tn)) sb.append('/'); sb.append('>'); } } public void getSecondHalf(StringBuffer sb, String tag) { if (tag != null) { final String tn = tag.toLowerCase(java.util.Locale.ENGLISH); if ("zkhead".equals(tn) || HTMLs.isOrphanTag(tn)) return; sb.append("'); } } public void appendText(StringBuffer sb, String text) { sb.append(text); //don't encode (bug 2689443) } } //--ComponentCtrl--// private static HashMap _properties = new HashMap(5); static { _properties.put("id", new StringPropertyAccess() { public void setValue(Component cmp, String value) { ((HtmlNativeComponent) cmp).setId(value); } public String getValue(Component cmp) { return ((HtmlNativeComponent) cmp).getId(); } }); _properties.put("tag", new StringPropertyAccess() { public void setValue(Component cmp, String value) { ((HtmlNativeComponent) cmp).setTag(value); } public String getValue(Component cmp) { return ((HtmlNativeComponent) cmp).getTag(); } }); _properties.put("epilogContent", new StringPropertyAccess() { public void setValue(Component cmp, String value) { ((HtmlNativeComponent) cmp).setEpilogContent(value); } public String getValue(Component cmp) { return ((HtmlNativeComponent) cmp).getEpilogContent(); } }); _properties.put("prologContent", new StringPropertyAccess() { public void setValue(Component cmp, String value) { ((HtmlNativeComponent) cmp).setPrologContent(value); } public String getValue(Component cmp) { return ((HtmlNativeComponent) cmp).getPrologContent(); } }); } public PropertyAccess getPropertyAccess(String prop) { PropertyAccess pa = _properties.get(prop); if (pa != null) return pa; return super.getPropertyAccess(prop); } public Object getExtraCtrl() { return new ExtraCtrl(); } protected class ExtraCtrl implements DirectContent, PrologAllowed { //-- PrologAware --// public void setPrologContent(String prolog) { _prefix = prolog; //Notice: it is used as prefix (shown before the tag and children) //while _prolog is the text shown after the tag and before the children } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy