EMMA Coverage Report (generated Mon Nov 01 16:48:29 PDT 2010)
[all classes][com.google.caja.plugin.templates]

COVERAGE SUMMARY FOR SOURCE FILE [SafeCssMaker.java]

nameclass, %method, %block, %line, %
SafeCssMaker.java100% (1/1)100% (2/2)99%  (198/199)100% (39.9/40)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class SafeCssMaker100% (1/1)100% (2/2)99%  (198/199)100% (39.9/40)
SafeCssMaker (List, Document): void 100% (1/1)100% (9/9)100% (4/4)
make (): Pair 100% (1/1)99%  (189/190)100% (35.9/36)

1// Copyright (C) 2009 Google Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14 
15package com.google.caja.plugin.templates;
16 
17import com.google.caja.lexer.FilePosition;
18import com.google.caja.parser.css.CssTree;
19import com.google.caja.parser.html.Namespaces;
20import com.google.caja.parser.html.Nodes;
21import com.google.caja.parser.js.ArrayConstructor;
22import com.google.caja.parser.js.Expression;
23import com.google.caja.parser.js.ExpressionStmt;
24import com.google.caja.parser.js.Statement;
25import com.google.caja.parser.js.StringLiteral;
26import com.google.caja.parser.quasiliteral.QuasiBuilder;
27import com.google.caja.parser.quasiliteral.ReservedNames;
28import com.google.caja.plugin.CssRuleRewriter;
29import com.google.caja.util.Lists;
30import com.google.caja.util.Pair;
31 
32import java.util.List;
33 
34import org.w3c.dom.Document;
35import org.w3c.dom.Element;
36 
37/**
38 * Attaches CSS to either the static HTML or the uncajoled JS as appropriate.
39 * <p>
40 * Depends on <code>emitCss___</code> as defined in DOMita.
41 *
42 * @author mikesamuel@gmail.com
43 */
44final class SafeCssMaker {
45  private final List<CssTree.StyleSheet> validatedStylesheets;
46  private final Document doc;
47 
48  SafeCssMaker(List<CssTree.StyleSheet> validatedStylesheets, Document doc) {
49    this.validatedStylesheets = validatedStylesheets;
50    this.doc = doc;
51  }
52 
53  Pair<Statement, Element> make() {
54    if (validatedStylesheets.isEmpty()) { return Pair.pair(null, null); }
55 
56    // Accumulates dynamic CSS that will be added to the JS.
57    List<Expression> cssParts = Lists.newArrayList();
58    // Accumulate static CSS that can be embedded in the DOM.
59    StringBuilder css = new StringBuilder();
60    FilePosition staticPos = null, dynamicPos = null;
61    for (CssTree.StyleSheet ss : validatedStylesheets) {
62      ArrayConstructor ac = CssRuleRewriter.cssToJs(ss);
63      List<? extends Expression> children = ac.children();
64      if (children.isEmpty()) { continue; }
65      FilePosition acPos = ac.getFilePosition();
66      Expression child0 = children.get(0);
67      // The CssRuleRewriter gets to distinguish between static and dynamic.
68      // If the output is a single string, then joining it on the idClass would
69      // not add any information, so we can put it in the static HTML.
70      if (children.size() == 1 && child0 instanceof StringLiteral) {
71        css.append('\n').append(((StringLiteral) child0).getUnquotedValue());
72        staticPos = staticPos == null
73            ? acPos : FilePosition.span(staticPos, acPos);
74      } else {
75        // Don't just push all onto the list since that would create an
76        // extra, spurious separator after they're joined.
77        // To avoid the spurious separator, we concatenate the last item
78        // already on cssParts with child0.
79        int n = cssParts.size();
80        if (n == 0) {
81          cssParts.addAll(children);
82        } else {
83          JsConcatenator cat = new JsConcatenator();
84          cat.append(cssParts.get(n - 1));
85          cat.append(FilePosition.startOf(child0.getFilePosition()), "\n");
86          cat.append(child0);
87          cssParts.set(n - 1, cat.toExpression(false));
88          cssParts.addAll(children.subList(1, children.size()));
89        }
90        dynamicPos = dynamicPos == null
91            ? acPos : FilePosition.span(dynamicPos, acPos);
92      }
93    }
94 
95    ExpressionStmt dynamicCss = null;
96    Element staticCss = null;
97    // Emit any dynamic CSS.
98    if (!cssParts.isEmpty()) {
99      // The CSS rule
100      //     p { color: purple }
101      // is converted to the JavaScript
102      //     IMPORTS___.emitCss___(
103      //         ['.', ' p { color: purple }']
104      //         .join(IMPORTS___.getIdClass___()));
105      //
106      // If IMPORTS___.getIdClass() returns "g123___", then the resulting
107      //     .g123___ p { color: purple }
108      // will only make purple paragraphs that are under a node with class
109      // g123__.
110      dynamicCss = new ExpressionStmt(
111          dynamicPos,
112          (Expression) QuasiBuilder.substV(
113              ReservedNames.IMPORTS
114              + ".emitCss___(@cssParts./*@synthetic*/join("
115              + ReservedNames.IMPORTS + ".getIdClass___()))",
116              "cssParts", new ArrayConstructor(dynamicPos, cssParts)));
117    }
118 
119    // Emit any static CSS.
120    if (css.length() != 0) {
121      String nsUri = Namespaces.HTML_NAMESPACE_URI;
122      Element style = doc.createElementNS(nsUri, "style");
123      style.setAttributeNS(nsUri, "type", "text/css");
124      style.appendChild(doc.createTextNode(css.toString()));
125      Nodes.setFilePositionFor(style, dynamicPos);
126      staticCss = style;
127    }
128 
129    return Pair.pair((Statement) dynamicCss, staticCss);
130  }
131}

[all classes][com.google.caja.plugin.templates]
EMMA 2.0.5312 (C) Vladimir Roubtsov