/** * Returns HTML tags to include all JavaScript files and codes that are required when loading a * ZUML page (never null). * * <p>FUTURE CONSIDERATION: we might generate the inclusion on demand instead of all at once. * * @param exec the execution (never null) * @param wapp the Web application. If null, exec.getDesktop().getWebApp() is used. So you have to * specify it if the execution is not associated with desktop (a fake execution, such as * JSP/DSP). * @param deviceType the device type, such as ajax. If null, exec.getDesktop().getDeviceType() is * used. So you have to specify it if the execution is not associated with desktop (a fake * execution). */ public static final String outLangJavaScripts(Execution exec, WebApp wapp, String deviceType) { if (exec.isAsyncUpdate(null) || exec.getAttribute(ATTR_LANG_JS_GENED) != null) return ""; // nothing to generate exec.setAttribute(ATTR_LANG_JS_GENED, Boolean.TRUE); final Desktop desktop = exec.getDesktop(); if (wapp == null) wapp = desktop.getWebApp(); if (deviceType == null) deviceType = desktop != null ? desktop.getDeviceType() : "ajax"; final StringBuffer sb = new StringBuffer(1536); final Set<JavaScript> jses = new LinkedHashSet<JavaScript>(32); for (LanguageDefinition langdef : LanguageDefinition.getByDeviceType(deviceType)) jses.addAll(langdef.getJavaScripts()); for (JavaScript js : jses) append(sb, js); sb.append("\n<!-- ZK ").append(wapp.getVersion()); if (WebApps.getFeature("ee")) sb.append(" EE"); else if (WebApps.getFeature("pe")) sb.append(" PE"); sb.append(' ').append(wapp.getBuild()); Object o = wapp.getAttribute("org.zkoss.zk.ui.notice"); if (o != null) sb.append(o); sb.append(" -->\n"); int tmout = 0; final Boolean autoTimeout = getAutomaticTimeout(desktop); if (autoTimeout != null ? autoTimeout.booleanValue() : wapp.getConfiguration().isAutomaticTimeout(deviceType)) { if (desktop != null) { tmout = desktop.getSession().getMaxInactiveInterval(); } else { Object req = exec.getNativeRequest(); if (req instanceof HttpServletRequest) { final HttpSession hsess = ((HttpServletRequest) req).getSession(false); if (hsess != null) { final Session sess = SessionsCtrl.getSession(wapp, hsess); if (sess != null) { tmout = sess.getMaxInactiveInterval(); } else { // try configuration first since HttpSession's timeout is set // when ZK Session is created (so it is not set yet) // Note: no need to setMaxInactiveInternval here since it will // be set later or not useful at the end tmout = wapp.getConfiguration().getSessionMaxInactiveInterval(); if (tmout <= 0) // system default tmout = hsess.getMaxInactiveInterval(); } } else tmout = wapp.getConfiguration().getSessionMaxInactiveInterval(); } } if (tmout > 0) { // unit: seconds int extra = tmout / 8; tmout += extra > 60 ? 60 : extra < 5 ? 5 : extra; // Add extra seconds to ensure it is really timeout } } final boolean keepDesktop = exec.getAttribute(Attributes.NO_CACHE) == null && !"page".equals(ExecutionsCtrl.getPageRedrawControl(exec)), groupingAllowed = isGroupingAllowed(desktop); final String progressboxPos = org.zkoss.lang.Library.getProperty("org.zkoss.zul.progressbox.position", ""); if (tmout > 0 || keepDesktop || progressboxPos.length() > 0 || !groupingAllowed) { sb.append("<script class=\"z-runonce\" type=\"text/javascript\">\nzkopt({"); if (keepDesktop) sb.append("kd:1,"); if (!groupingAllowed) sb.append("gd:1,"); if (tmout > 0) sb.append("to:").append(tmout).append(','); if (progressboxPos.length() > 0) sb.append("ppos:'").append(progressboxPos).append('\''); if (sb.charAt(sb.length() - 1) == ',') sb.setLength(sb.length() - 1); sb.append("});\n</script>"); } final Device device = Devices.getDevice(deviceType); String s = device.getEmbedded(); if (s != null) sb.append(s).append('\n'); return sb.toString(); }
private static void parseLang(Document doc, Locator locator, URL url, boolean addon) throws Exception { final Element root = doc.getRootElement(); final String lang = IDOMs.getRequiredElementValue(root, "language-name"); final LanguageDefinition langdef; final Device device; if (addon) { if (log.isDebugEnabled()) log.debug( "Addon language to " + lang + " from " + root.getElementValue("addon-name", true)); langdef = LanguageDefinition.lookup(lang); device = Devices.getDevice(langdef.getDeviceType()); if (root.getElement("case-insensitive") != null) throw new UiException(message("case-insensitive not allowed in addon", root)); } else { final String ns = IDOMs.getRequiredElementValue(root, "namespace"); final String deviceType = IDOMs.getRequiredElementValue(root, "device-type"); String treeBuilderClass = root.getElementValue("treebuilder-class", true); if (treeBuilderClass == null) // XulTreeBuilder as default treeBuilderClass = XmlTreeBuilder.class.getName(); // if (log.isDebugEnabled()) log.debug("Load language: "+lang+", "+ns); PageRenderer pageRenderer = (PageRenderer) locateClass(IDOMs.getRequiredElementValue(root, "renderer-class"), PageRenderer.class) .newInstance(); final List<String> exts = parseExtensions(root); if (exts.isEmpty()) throw new UiException(message("The extension must be specified for " + lang, root)); String ignoreCase = root.getElementValue("case-insensitive", true); String bNative = root.getElementValue("native-namespace", true); langdef = new LanguageDefinition( deviceType, lang, ns, exts, pageRenderer, "true".equals(ignoreCase), "true".equals(bNative), locator, treeBuilderClass); device = Devices.getDevice(deviceType); } parsePI(langdef, doc); parseLabelTemplate(langdef, root); parseDynamicTag(langdef, root); parseMacroTemplate(langdef, root); parseNativeTemplate(langdef, root); parseShadowTemplate(langdef, root); for (Element el : root.getElements("message-loader-class")) { final String clsname = el.getText().trim(); if (Strings.isEmpty(clsname)) throw new UiException("Empty class name of message loader for " + lang); MessageLoader msgLoader = (MessageLoader) locateClass(clsname).newInstance(); langdef.addMessageLoader(msgLoader); } for (Element el : root.getElements("library-property")) { ConfigParser.parseLibProperty(el); } for (Iterator it = root.getElements("system-property").iterator(); it.hasNext(); ) { final Element el = (Element) it.next(); final String nm = IDOMs.getRequiredElementValue(el, "name"); final String val = IDOMs.getRequiredElementValue(el, "value"); System.setProperty(nm, val); } for (Iterator it = root.getElements("javascript").iterator(); it.hasNext(); ) { final Element el = (Element) it.next(); String src = el.getAttributeValue("src"), pkg = el.getAttributeValue("package"); String mergeTo = el.getAttributeValue("merge"); final boolean merge = mergeTo != null && !"false".equals(mergeTo); if (merge && "true".equals(mergeTo)) mergeTo = "zk"; final boolean ondemand = "true".equals(el.getAttributeValue("ondemand")); // ondemand means to cancel the previous definition (merge or not) if (pkg != null) { if (src != null) log.warn("The src attribute ignored because package is specified, " + el.getLocator()); if (!ondemand && !merge) { src = "~." + device.packageToPath(pkg); pkg = null; } } final String ctn = el.getText(true); final JavaScript js; if (pkg != null && pkg.length() > 0) { if (ondemand) { // ondemand has the higher priority than merge langdef.removeJavaScript("~." + device.packageToPath(pkg)); langdef.unmergeJavaScriptPackage(pkg, mergeTo); } else { // merge must be true langdef.mergeJavaScriptPackage(pkg, mergeTo); } continue; // TODO } else if (src != null && src.length() > 0) { if (ctn != null && ctn.length() > 0) throw new UiException( message("You cannot specify the content if the src attribute is specified", el)); final String charset = el.getAttributeValue("charset"); js = new JavaScript(src, charset); } else if (ctn != null && ctn.length() > 0) { js = new JavaScript(ctn); } else { log.warn( "Ignored: none of the src or package attribute, or the content specified, " + el.getLocator()); continue; } langdef.addJavaScript(js); } for (Iterator it = root.getElements("javascript-module").iterator(); it.hasNext(); ) { final Element el = (Element) it.next(); langdef.addJavaScriptModule( IDOMs.getRequiredAttributeValue(el, "name"), IDOMs.getRequiredAttributeValue(el, "version")); } for (Iterator it = root.getElements("stylesheet").iterator(); it.hasNext(); ) { final Element el = (Element) it.next(); final String href = el.getAttributeValue("href"); final String ctn = el.getText(true); final StyleSheet ss; if (href != null && href.length() > 0) { if (ctn != null && ctn.length() > 0) throw new UiException( message("You cannot specify the content if the href attribute is specified", el)); ss = new StyleSheet( href, el.getAttributeValue("type"), el.getAttributeValue("media"), false); } else if (ctn != null && ctn.length() > 0) { ss = new StyleSheet(ctn, el.getAttributeValue("type"), el.getAttributeValue("media"), true); } else { throw new UiException( message("You must specify either the href attribute or the content", el)); } langdef.addStyleSheet(ss); } for (Iterator it = root.getElements("zscript").iterator(); it.hasNext(); ) { final Element el = (Element) it.next(); final String zslang; final Attribute attr = el.getAttributeItem("language"); if (attr == null) { zslang = "Java"; } else { zslang = attr.getValue(); if (zslang == null || zslang.length() == 0) throw new UiException(message("The language attribute cannot be empty", attr)); } final String s = el.getText(true); final String eachTime = el.getAttributeValue("each-time"); if ("true".equals(eachTime)) langdef.addEachTimeScript(zslang, s); else langdef.addInitScript(zslang, s); } for (Iterator it = root.getElements("component").iterator(); it.hasNext(); ) { final Element el = (Element) it.next(); final String name = IDOMs.getRequiredElementValue(el, "component-name"); String clsnm = el.getElementValue("component-class", true); Class<? extends Component> cls = null; if (clsnm != null) { if (clsnm.length() > 0) { noEL("component-class", clsnm, el); try { cls = locateClass(clsnm, Component.class); } catch (Throwable ex) { // Feature 1873426 log.warn( "Component " + name + " ignored. Reason: unable to load " + clsnm + " due to " + ex.getClass().getName() + ": " + ex.getMessage() + (ex instanceof NoClassDefFoundError ? "" : "\n" + el.getLocator())); log.debug("", ex); // keep processing (Feature 2060367) } } else { clsnm = null; } } final String macroURI = el.getElementValue("macro-uri", true); final String templateURI = el.getElementValue("template-uri", true); final ComponentDefinitionImpl compdef; boolean extend = false; if (macroURI != null && macroURI.length() != 0) { if (log.isTraceEnabled()) log.trace("macro component definition: " + name); final String inline = el.getElementValue("inline", true); compdef = (ComponentDefinitionImpl) langdef.getMacroDefinition(name, macroURI, "true".equals(inline), null); if (cls != null) compdef.setImplementationClass(cls); else if (clsnm != null) compdef.setImplementationClass(clsnm); compdef.setDeclarationURL(url); langdef.addComponentDefinition(compdef); } else if (templateURI != null && templateURI.length() != 0) { // apply template uri extend = true; String extendedCls = "apply"; final ComponentDefinition ref = (ComponentDefinitionImpl) langdef.getShadowDefinitionIfAny(extendedCls); if (extendedCls.equals(name)) { compdef = (ComponentDefinitionImpl) ref; } else { compdef = (ComponentDefinitionImpl) ref.clone(ref.getLanguageDefinition(), name); compdef.setDeclarationURL(url); } if (cls != null) compdef.setImplementationClass(cls); else if (clsnm != null) compdef.setImplementationClass(clsnm); langdef.addShadowDefinition(compdef); compdef.addProperty("templateURI", templateURI); } else if (el.getElement("extends") != null) { // extends extend = true; final String extnm = el.getElementValue("extends", true); if (log.isTraceEnabled()) log.trace("Extends component definition, " + name + ", from " + extnm); ComponentDefinition tmpRef = langdef.getComponentDefinitionIfAny(extnm); if (tmpRef == null) // search Shadow tmpRef = langdef.getShadowDefinitionIfAny(extnm); final ComponentDefinition ref = tmpRef; if (ref == null) { log.warn( "Component " + name + " ignored. Reason: extends a non-existent component " + extnm + ".\n" + el.getLocator()); // not throw exception since the derived component might be // ignored due to class-not-found continue; } if (ref.isMacro()) throw new UiException(message("Unable to extend from a macro component", el)); if (extnm.equals(name)) { compdef = (ComponentDefinitionImpl) ref; } else { compdef = (ComponentDefinitionImpl) ref.clone(ref.getLanguageDefinition(), name); compdef.setDeclarationURL(url); } if (cls != null) compdef.setImplementationClass(cls); else if (clsnm != null) compdef.setImplementationClass(clsnm); if (compdef.isShadowElement()) { langdef.addShadowDefinition(compdef); } else { langdef.addComponentDefinition(compdef); } // Note: setImplementationClass before addComponentDefinition } else { if (log.isTraceEnabled()) log.trace("Add component definition: name=" + name); if (cls == null && clsnm == null) throw new UiException(message("component-class is required", el)); String s = el.getElementValue("shadow-element", true); if (s != null && !"false".equals(s)) { compdef = cls != null ? new ShadowDefinitionImpl(langdef, null, name, cls) : new ShadowDefinitionImpl(langdef, null, name, clsnm); compdef.setDeclarationURL(url); langdef.addShadowDefinition(compdef); } else { compdef = cls != null ? new ComponentDefinitionImpl(langdef, null, name, cls) : new ComponentDefinitionImpl(langdef, null, name, clsnm); compdef.setDeclarationURL(url); langdef.addComponentDefinition(compdef); } } parseTextAs(compdef, el.getElement("text-as")); String s = el.getElementValue("preserve-blank", true); compdef.setBlankPreserved((s != null && !"false".equals(s))); String wgtnm = el.getElementValue("widget-class", true); WidgetDefinition wgtdef = null; if (wgtnm == null && extend) wgtnm = compdef.getDefaultWidgetClass(null); if (wgtnm != null) { if (!withEL(wgtnm)) wgtdef = getWidgetDefinition(langdef, compdef, wgtnm); compdef.setDefaultWidgetClass(wgtnm); } s = el.getElementValue("component-apply", true); if (s == null) s = el.getElementValue("apply", true); // backward-compatible compdef.setApply(s); for (Iterator i = el.getElements("mold").iterator(); i.hasNext(); ) { final Element e = (Element) i.next(); final String nm = IDOMs.getRequiredElementValue(e, "mold-name"); final String moldURI = e.getElementValue("mold-uri", true); String cssURI = e.getElementValue("css-uri", true); final String wn = e.getElementValue("widget-class", true); noEL("mold-uri", moldURI, e); // 5.0 limitation noEL("css-uri", cssURI, e); compdef.addMold(nm, wn != null ? wn : wgtnm); WidgetDefinition wd = wn == null ? wgtdef : withEL(wn) ? null : getWidgetDefinition(langdef, compdef, wn); if (moldURI != null) { if (wd != null) wd.addMold(nm, moldURI); else log.error( "Mold " + nm + " for " + name + " ignored because " + ((wn != null && withEL(wn)) || (wgtnm != null && withEL(wgtnm)) ? "widget-class contains EL expressions" : "widget-class is required") + ", " + e.getLocator()); } if (cssURI != null && cssURI.length() > 0) { final char cc = cssURI.charAt(0); if (cc != '/' && cc != '~') { String n = wn != null ? wn : wgtnm; if (!withEL(n)) { int k = n.lastIndexOf('.'); cssURI = "~." + device.toAbsolutePath(n.substring(0, k).replace('.', '/') + '/' + cssURI); } else { log.error( "Absolute path required for cssURI, since the widget class contains EL expressions, " + e.getLocator()); } } langdef.addCSSURI(cssURI); } } for (Iterator e = parseCustAttrs(el).entrySet().iterator(); e.hasNext(); ) { final Map.Entry me = (Map.Entry) e.next(); compdef.addCustomAttribute((String) me.getKey(), (String) me.getValue()); } for (Iterator e = parseProps(el).entrySet().iterator(); e.hasNext(); ) { final Map.Entry me = (Map.Entry) e.next(); compdef.addProperty((String) me.getKey(), (String) me.getValue()); } parseAnnots(compdef, el); } }