// Ensures that embed bound properties are writable private void checkEmbedAgainst( PageCompilingContext pc, EvaluatorCompiler compiler, Map<String, String> properties, Class<?> embedClass, Node node) { // TODO also type check them against expressions for (String property : properties.keySet()) { try { if (!compiler.isWritable(property)) { pc.errors.add( CompileError.in(node.outerHtml()) // TODO we need better line number detection if there is whitespace between the // annotation and tag. .near(node.siblingIndex() - 1) // TODO - line number of the annotation .causedBy( CompileErrors.PROPERTY_NOT_WRITEABLE, String.format( "Property %s#%s was not writable. Did you forget to create " + "a setter or @Visible annotation?", embedClass.getSimpleName(), property))); } } catch (ExpressionCompileException ece) { pc.errors.add( CompileError.in(node.outerHtml()) .near(node.siblingIndex()) // TODO - line number .causedBy(CompileErrors.ERROR_COMPILING_PROPERTY)); } } }
private Map<String, Type> parseRepeatScope(PageCompilingContext pc, String[] extract, Node node) { RepeatToken repeat = registry.parseRepeat(extract[1]); Map<String, Type> context = Maps.newHashMap(); // Verify that @Repeat was parsed correctly. if (null == repeat.var()) { pc.errors.add( CompileError.in(node.outerHtml()) .near(node.siblingIndex()) // TODO - line number .causedBy(CompileErrors.MISSING_REPEAT_VAR)); } if (null == repeat.items()) { pc.errors.add( CompileError.in(node.outerHtml()) .near(node.siblingIndex()) // TODO - line number .causedBy(CompileErrors.MISSING_REPEAT_ITEMS)); } try { Type egressType = pc.lexicalScopes.peek().resolveEgressType(repeat.items()); // convert to collection if we need to Type elementType; Class<?> egressClass = Generics.erase(egressType); if (egressClass.isArray()) { elementType = Generics.getArrayComponentType(egressType); } else if (Collection.class.isAssignableFrom(egressClass)) { elementType = Generics.getTypeParameter(egressType, Collection.class.getTypeParameters()[0]); } else { pc.errors.add( CompileError.in(node.outerHtml()) .near(node.siblingIndex()) // TODO - line number .causedBy(CompileErrors.REPEAT_OVER_ATOM)); return Collections.emptyMap(); } context.put(repeat.var(), elementType); context.put(repeat.pageVar(), pc.page); context.put("__page", pc.page); context.put("index", int.class); context.put("isLast", boolean.class); } catch (ExpressionCompileException e) { pc.errors.add( CompileError.in(node.outerHtml()) .near(node.siblingIndex()) // TODO - line number .causedBy(e)); } return context; }
private void checkFormFields(PageCompilingContext pc, Node element) { if (null == pc.form) return; String action = pc.form.attr("action"); // Only look at contextual uris (i.e. hosted by us). // TODO - relative, not starting with '/' if (null == action || (!action.startsWith("/"))) return; final PageBook.Page page = pageBook.get(action); // Only look at pages we actually have registered. if (null == page) { pc.warnings.add( CompileError.in(element.outerHtml()) .near(line(element)) .causedBy(CompileErrors.UNRESOLVABLE_FORM_ACTION)); return; } // If we're inside a form do a throw-away compile against the target page. if ("input".equals(element.nodeName()) || "textarea".equals(element.nodeName())) { String name = element.attr("name"); // Skip submits and buttons. if (skippable(element.attr("type"))) return; // TODO Skip empty? if (null == name) { pc.warnings.add( CompileError.in(element.outerHtml()) .near(line(element)) .causedBy(CompileErrors.FORM_MISSING_NAME)); return; } // Compile expression path. try { new MvelEvaluatorCompiler(page.pageClass()).compile(name); } catch (ExpressionCompileException e) { // TODO Very hacky, needed to strip out xmlns attribution. pc.warnings.add( CompileError.in(element.outerHtml()) .near(element.siblingIndex()) // TODO - line number .causedBy(CompileErrors.UNRESOLVABLE_FORM_BINDING, e)); } } }
private static String cleanHtml(final Node node) { if (node instanceof Element) { Element element = ((Element) node); StringBuilder accum = new StringBuilder(); accum.append("<").append(element.tagName()); for (Attribute attribute : element.attributes()) { if (!(attribute.getKey().startsWith("_"))) { accum.append(" "); accum.append(attribute.getKey()); accum.append("=\""); accum.append(attribute.getValue()); accum.append('"'); } } if (element.childNodes().isEmpty() && element.tag().isEmpty()) { accum.append(" />"); } else { accum.append(">"); for (Node child : element.childNodes()) accum.append(cleanHtml(child)); accum.append("</").append(element.tagName()).append(">"); } return accum.toString(); } else if (node instanceof TextNode) { return ((TextNode) node).getWholeText(); } else if (node instanceof XmlDeclaration) { // HACK if (node.childNodes().isEmpty()) { return ""; } return node.outerHtml(); } else if (node instanceof Comment) { // HACK: elide comments for now. return ""; } else if (node instanceof DataNode && node.childNodes().isEmpty()) { // No child nodes are defined but we have to handle content if such exists, example // <script language="JavaScript">var a = { name: "${user.name}"}</script> String content = node.attr("data"); if (Strings.empty(content)) { return ""; } return content; } else { return node.outerHtml(); } }
public static String outerHtml(Node node) { if (htmlCache.containsKey(node)) { return htmlCache.get(node); } String html = node.outerHtml(); if (htmlCache.size() == MAX_HTML_CACHE) { htmlCache.clear(); } htmlCache.put(node, html); return html; }
// hit when the node is first seen public void head(Node node, int depth) { String name = node.nodeName(); if (name.equals("li")) append('\n'); else if (node.toString().startsWith("<select")) { append1("[SELECT]"); append(tab); } else if (node.outerHtml().startsWith("<option")) { // append1(node.attr("value")+":");append1(" "); TextNodeVisitor textVisitor = new TextNodeVisitor(); node.traverse(textVisitor); append1("{" + textVisitor.toString() + "}"); } else if (node.outerHtml().startsWith("<input")) { if (node.attr("type").equals("input")) append1("[INPUT]" + node.attr("maxLength")); } else if (node.outerHtml().startsWith("<span")) { TextNodeVisitor textVisitor = new TextNodeVisitor(); node.traverse(textVisitor); append1(":" + textVisitor.toString() + " "); } }
public Map<String, String> attempt(Element element) { Map<String, String> attributes = new HashMap<String, String>(); for (Entry<String, Matcher> entry : matchers.entrySet()) { if (entry.getValue().test(element)) { attributes.put(entry.getKey(), decode(element.text())); } } for (Entry<String, Matcher> entry : textMatchers.entrySet()) { if (entry.getValue().test(element)) { Node textNode = element.nextSibling(); if (null != textNode) { attributes.put(entry.getKey(), decode(textNode.outerHtml())); } } } for (Entry<String, Matcher> entry : subtextMatchers.entrySet()) { if (entry.getValue().test(element)) { TextNode textNode = element.textNodes().get(0); if (null != textNode) { attributes.put(entry.getKey(), decode(textNode.outerHtml())); } } } for (Entry<String, Matcher> entry : htmlMatchers.entrySet()) { if (entry.getValue().test(element)) { attributes.put(entry.getKey(), element.html()); } } for (Entry<String, Matcher> entry : ptextMatchers.entrySet()) { if (entry.getValue().test(element)) { attributes.put(entry.getKey(), plainTextFormatter.getPlainText(element)); } } for (Entry<String, Object[]> entry : attrMatchers.entrySet()) { Object[] objects = entry.getValue(); Matcher matcher = (Matcher) objects[0]; String attr = (String) objects[1]; if (matcher.test(element)) { attributes.put(entry.getKey(), element.attr(attr)); } } return attributes; }
private void checkUriConsistency(PageCompilingContext pc, Node element) { String uriAttrib = element.attr("action"); if (null == uriAttrib) uriAttrib = element.attr("src"); if (null == uriAttrib) uriAttrib = element.attr("href"); if (null != uriAttrib) { // Verify that such a uri exists in the page book, // only if it is contextual--ignore abs & relative URIs. if (uriAttrib.startsWith("/")) if (null == pageBook.nonCompilingGet(uriAttrib)) pc.warnings.add( CompileError.in(element.outerHtml()) .near(element.siblingIndex()) // TODO - line number .causedBy(CompileErrors.UNRESOLVABLE_FORM_ACTION, uriAttrib)); } }
/** * Get the outer HTML of this node. * * @return HTML */ public String outerHtml() { StringBuilder accum = new StringBuilder(32 * 1024); outerHtml(accum); return accum.toString(); }
private void html(StringBuilder accum) { for (Node node : childNodes) node.outerHtml(accum); }