Add GSS support in UiBinder. Third patch concerning the support of GSS in GWT. This patch introduces a new attribute named useGss that you can use in order to enable GSS in the inline style of UiBinder Change-Id: I7e6f907c3ffa4a4c8f642786506de2f9c4107e85
diff --git a/user/src/com/google/gwt/resources/gss/ClassNamesCollector.java b/user/src/com/google/gwt/resources/gss/ClassNamesCollector.java new file mode 100644 index 0000000..610ef26 --- /dev/null +++ b/user/src/com/google/gwt/resources/gss/ClassNamesCollector.java
@@ -0,0 +1,73 @@ +/* + * Copyright 2014 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.google.gwt.resources.gss; + +import com.google.gwt.core.ext.typeinfo.JClassType; +import com.google.gwt.resources.rg.GssResourceGenerator; +import com.google.gwt.thirdparty.common.css.compiler.ast.CssClassSelectorNode; +import com.google.gwt.thirdparty.common.css.compiler.ast.CssTree; +import com.google.gwt.thirdparty.common.css.compiler.ast.DefaultTreeVisitor; +import com.google.gwt.thirdparty.guava.common.base.Preconditions; + +import java.util.HashSet; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; + +/** + * Collect all CSS class names in a stylesheet. + */ +public class ClassNamesCollector extends DefaultTreeVisitor { + private Set<String> classNames; + private SortedSet<String> excludedPrefixes; + + /** + * Extract all CSS class names in the provided stylesheet, modulo those + * imported from another context. + */ + public Set<String> getClassNames(CssTree tree, Set<JClassType> imports) { + Preconditions.checkNotNull(tree, "tree cannot be null"); + Preconditions.checkNotNull(imports, "imports set cannot be null"); + + classNames = new HashSet<String>(); + excludedPrefixes = new TreeSet<String>(); + + for (JClassType importedType : imports) { + excludedPrefixes.add(GssResourceGenerator.getImportPrefix(importedType)); + } + + tree.getVisitController().startVisit(this); + + return classNames; + } + + @Override + public boolean enterClassSelector(CssClassSelectorNode classSelector) { + String className = classSelector.getRefinerName(); + + if (!isImportedClass(className)) { + classNames.add(className); + } + + return false; + } + + private boolean isImportedClass(String className) { + SortedSet<String> lowerPrefixes = excludedPrefixes.headSet(className); + + return !lowerPrefixes.isEmpty() && className.startsWith(lowerPrefixes.last()); + } +}
diff --git a/user/src/com/google/gwt/resources/rg/CssResourceGenerator.java b/user/src/com/google/gwt/resources/rg/CssResourceGenerator.java index 8206f98..ecf6c3c 100644 --- a/user/src/com/google/gwt/resources/rg/CssResourceGenerator.java +++ b/user/src/com/google/gwt/resources/rg/CssResourceGenerator.java
@@ -539,6 +539,9 @@ throw new UnableToCompleteException(); } + // At this point, gss is not enabled so we shouldn't try to compile a gss file. + ensureNoGssFile(resources, logger); + // Create the AST and do a quick scan for requirements CssStylesheet sheet = GenerateCssAst.exec(logger, resources); checkSheet(logger, sheet); @@ -546,6 +549,19 @@ (new RequirementsCollector(logger, context.getRequirements())).accept(sheet); } + private void ensureNoGssFile(URL[] resources, TreeLogger logger) + throws UnableToCompleteException { + + for (URL stylesheet : resources) { + if (stylesheet.getFile().endsWith(".gss")) { + logger.log(Type.ERROR, "GSS is not enabled. Add the following line to your gwt.xml file " + + "to enable it: " + + "<set-configuration-property name=\"CssResource.enableGss\" value=\"true\" />"); + throw new UnableToCompleteException(); + } + } + } + protected void checkSheet(TreeLogger logger, CssStylesheet stylesheet) throws UnableToCompleteException { // Do nothing
diff --git a/user/src/com/google/gwt/resources/rg/GssResourceGenerator.java b/user/src/com/google/gwt/resources/rg/GssResourceGenerator.java index 8093068..5c9f088 100644 --- a/user/src/com/google/gwt/resources/rg/GssResourceGenerator.java +++ b/user/src/com/google/gwt/resources/rg/GssResourceGenerator.java
@@ -243,6 +243,19 @@ 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', '0', '1', '2', '3', '4', '5', '6'}; + /** + * Returns the import prefix for a type, including the trailing hyphen. + */ + public static String getImportPrefix(JClassType importType) { + String prefix = importType.getSimpleSourceName(); + ImportedWithPrefix exp = importType.getAnnotation(ImportedWithPrefix.class); + if (exp != null) { + prefix = exp.value(); + } + + return prefix + "-"; + } + private static String encode(long id) { assert id >= 0; @@ -1106,7 +1119,7 @@ // This substitution map will prefix each renamed class with the resource prefix and use a // MinimalSubstitutionMap for computing the obfuscated name. SubstitutionMap prefixingSubstitutionMap = new PrefixingSubstitutionMap( - new MinimalSubstitutionMap(), obfuscationPrefix + resourcePrefix + "_"); + new MinimalSubstitutionMap(), obfuscationPrefix + resourcePrefix + "-"); for (JMethod method : cssResource.getOverridableMethods()) { if (method == getNameMethod || method == getTextMethod || method == ensuredInjectedMethod) { @@ -1139,17 +1152,4 @@ replacementsForSharedMethods.put(method, obfuscatedClassName); } } - - /** - * Returns the import prefix for a type, including the trailing hyphen. - */ - private String getImportPrefix(JClassType importType) { - String prefix = importType.getSimpleSourceName(); - ImportedWithPrefix exp = importType.getAnnotation(ImportedWithPrefix.class); - if (exp != null) { - prefix = exp.value(); - } - - return prefix + "-"; - } }
diff --git a/user/src/com/google/gwt/uibinder/rebind/UiBinderParser.java b/user/src/com/google/gwt/uibinder/rebind/UiBinderParser.java index c1cd78b..b7e16ca 100644 --- a/user/src/com/google/gwt/uibinder/rebind/UiBinderParser.java +++ b/user/src/com/google/gwt/uibinder/rebind/UiBinderParser.java
@@ -92,6 +92,7 @@ private static final String REPEAT_STYLE_ATTRIBUTE = "repeatStyle"; private static final String SOURCE_ATTRIBUTE = "src"; private static final String TYPE_ATTRIBUTE = "type"; + private static final String GSS_ATTRIBUTE = "gss"; // TODO(rjrjr) Make all the ElementParsers receive their dependencies via // constructor like this one does, and make this an ElementParser. I want @@ -445,8 +446,10 @@ importTypes.add(findCssResourceType(elem, type)); } + Boolean gss = elem.consumeBooleanConstantAttribute(GSS_ATTRIBUTE); + ImplicitCssResource cssMethod = bundleClass.createCssResource(name, source, - publicType, body, importTypes, resourceOracle); + publicType, body, importTypes, gss, resourceOracle); FieldWriter field = fieldManager.registerFieldForGeneratedCssResource(cssMethod); field.setInitializer(String.format("%s.%s()",
diff --git a/user/src/com/google/gwt/uibinder/rebind/model/ImplicitClientBundle.java b/user/src/com/google/gwt/uibinder/rebind/model/ImplicitClientBundle.java index 3e98c33..e1afec8 100644 --- a/user/src/com/google/gwt/uibinder/rebind/model/ImplicitClientBundle.java +++ b/user/src/com/google/gwt/uibinder/rebind/model/ImplicitClientBundle.java
@@ -63,14 +63,15 @@ * @param body the inline css text * @param importTypes for the {@literal @}Import annotation, if any. LinkedHashSet * to enforce deterministic order across recompiles + * @param gss indicates that GSS is used or not * @param resourceOracle from which to load resources * @return the newly-created CssResource */ public ImplicitCssResource createCssResource(String name, String[] source, JClassType extendedInterface, String body, LinkedHashSet<JClassType> importTypes, - ResourceOracle resourceOracle) { + Boolean gss, ResourceOracle resourceOracle) { ImplicitCssResource css = new ImplicitCssResource(packageName, cssBaseName + name, name, source, - extendedInterface, body, logger, importTypes, resourceOracle); + extendedInterface, body, logger, importTypes, gss, resourceOracle); cssMethods.add(css); return css; }
diff --git a/user/src/com/google/gwt/uibinder/rebind/model/ImplicitCssResource.java b/user/src/com/google/gwt/uibinder/rebind/model/ImplicitCssResource.java index e3012ec..df4b742 100644 --- a/user/src/com/google/gwt/uibinder/rebind/model/ImplicitCssResource.java +++ b/user/src/com/google/gwt/uibinder/rebind/model/ImplicitCssResource.java
@@ -15,6 +15,7 @@ */ package com.google.gwt.uibinder.rebind.model; +import com.google.gwt.core.ext.TreeLogger; import com.google.gwt.core.ext.UnableToCompleteException; import com.google.gwt.core.ext.impl.ResourceLocatorImpl; import com.google.gwt.core.ext.typeinfo.JClassType; @@ -23,6 +24,11 @@ import com.google.gwt.resources.css.GenerateCssAst; import com.google.gwt.resources.css.ast.CssStylesheet; import com.google.gwt.resources.ext.ResourceGeneratorUtil; +import com.google.gwt.resources.gss.ClassNamesCollector; +import com.google.gwt.thirdparty.common.css.SourceCode; +import com.google.gwt.thirdparty.common.css.compiler.ast.CssTree; +import com.google.gwt.thirdparty.common.css.compiler.ast.GssParser; +import com.google.gwt.thirdparty.common.css.compiler.ast.GssParserException; import com.google.gwt.uibinder.attributeparsers.CssNameConverter; import com.google.gwt.uibinder.rebind.MortalLogger; @@ -55,6 +61,7 @@ private final MortalLogger logger; private final Set<JClassType> imports; private final ResourceOracle resourceOracle; + private final boolean gss; private File generatedFile; private Set<String> cssClassNames; @@ -65,7 +72,8 @@ */ public ImplicitCssResource(String packageName, String className, String name, String[] source, JClassType extendedInterface, String body, - MortalLogger logger, Set<JClassType> importTypes, ResourceOracle resourceOracle) { + MortalLogger logger, Set<JClassType> importTypes, Boolean gss, + ResourceOracle resourceOracle) { this.packageName = packageName; this.className = className; this.name = name; @@ -74,6 +82,7 @@ this.logger = logger; this.imports = Collections.unmodifiableSet(importTypes); this.resourceOracle = resourceOracle; + this.gss = Boolean.TRUE.equals(gss); sources = Arrays.asList(source); } @@ -85,9 +94,9 @@ } /** - * Returns the set of CSS classnames in the underlying .css files. + * Returns the set of CSS classnames in the underlying css or gss files. * - * @throws UnableToCompleteException if the user has called for a .css file we + * @throws UnableToCompleteException if the user has called for a css/gss file we * can't find. */ public Set<String> getCssClassNames() throws UnableToCompleteException { @@ -103,10 +112,23 @@ } assert urls.size() > 0; - CssStylesheet sheet = GenerateCssAst.exec(logger.getTreeLogger(), - urls.toArray(new URL[urls.size()])); - cssClassNames = ExtractClassNamesVisitor.exec(sheet, - imports.toArray(new JClassType[imports.size()])); + if (gss) { + SourceCode sourceCode = new SourceCode(bodyFile.getName(), body); + CssTree tree; + try { + tree = new GssParser(sourceCode).parse(); + } catch (GssParserException e) { + logger.getTreeLogger().log(TreeLogger.ERROR, "Unable to parse CSS", e); + throw new UnableToCompleteException(); + } + cssClassNames = new ClassNamesCollector().getClassNames(tree, imports); + + } else { + CssStylesheet sheet = GenerateCssAst.exec(logger.getTreeLogger(), + urls.toArray(new URL[urls.size()])); + cssClassNames = ExtractClassNamesVisitor.exec(sheet, + imports.toArray(new JClassType[imports.size()])); + } } return cssClassNames; } @@ -168,7 +190,7 @@ } /** - * Returns the name of the .css file(s), separate by white space. + * Returns the name of the css or gss file(s), separate by white space. */ public Collection<String> getSource() { if (body.length() == 0) { @@ -181,7 +203,8 @@ } private String getBodyFileName() { - String bodyFileName = String.format("uibinder.%s.%s.css", packageName, className); + String bodyFileName = String.format("uibinder.%s.%s.%s", packageName, className, + getCssFileExtension()); // To verify that the resulting file can be retrieved out of zip files using a URL reference. assert isValidUrl("file:/" + bodyFileName); return bodyFileName; @@ -225,8 +248,8 @@ if (generatedFile == null) { try { - File f = File.createTempFile(String.format("uiBinder_%s_%s", - packageName, className), ".css"); + File f = File.createTempFile(String.format("uiBinder_%s_%s", packageName, className), + "." + getCssFileExtension()); f.deleteOnExit(); BufferedWriter out = new BufferedWriter(new FileWriter(f)); @@ -251,4 +274,8 @@ } return true; } + + private String getCssFileExtension() { + return gss ? "gss" : "css"; + } }
diff --git a/user/test/com/google/gwt/resources/ResourcesJreSuite.java b/user/test/com/google/gwt/resources/ResourcesJreSuite.java index 3cd9dac..0fef2d5 100644 --- a/user/test/com/google/gwt/resources/ResourcesJreSuite.java +++ b/user/test/com/google/gwt/resources/ResourcesJreSuite.java
@@ -28,6 +28,7 @@ import com.google.gwt.resources.css.ExtractClassNamesVisitorTest; import com.google.gwt.resources.css.UnknownAtRuleTest; import com.google.gwt.resources.ext.ResourceGeneratorUtilTest; +import com.google.gwt.resources.gss.ClassNamesCollectorTest; import com.google.gwt.resources.gss.CssPrinterTest; import com.google.gwt.resources.gss.ExtendedEliminateConditionalNodesTest; import com.google.gwt.resources.gss.ExternalClassesCollectorTest; @@ -64,6 +65,8 @@ // GSS tests suite.addTestSuite(ExternalClassesCollectorTest.class); suite.addTestSuite(RenamingSubstitutionMapTest.class); + suite.addTestSuite(ImageSpriteCreatorTest.class); + suite.addTestSuite(ClassNamesCollectorTest.class); suite.addTestSuite(CssPrinterTest.class); suite.addTestSuite(PermutationsCollectorTest.class); suite.addTestSuite(RecordingBidiFlipperTest.class); @@ -74,7 +77,6 @@ suite.addTestSuite(RuntimeConditionalBlockCollectorTest.class); suite.addTestSuite(ValidateRuntimeConditionalNodeTest.class); suite.addTestSuite(ValueFunctionTest.class); - suite.addTestSuite(ImageSpriteCreatorTest.class); // CSS to GSS converter tests suite.addTestSuite(Css2GssTest.class);
diff --git a/user/test/com/google/gwt/resources/gss/ClassNamesCollectorTest.java b/user/test/com/google/gwt/resources/gss/ClassNamesCollectorTest.java new file mode 100644 index 0000000..ca24695 --- /dev/null +++ b/user/test/com/google/gwt/resources/gss/ClassNamesCollectorTest.java
@@ -0,0 +1,133 @@ +/* + * Copyright 2014 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.google.gwt.resources.gss; + +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import com.google.gwt.core.ext.typeinfo.JClassType; +import com.google.gwt.resources.client.CssResource.ImportedWithPrefix; +import com.google.gwt.thirdparty.common.css.compiler.ast.CssClassSelectorNode; +import com.google.gwt.thirdparty.common.css.compiler.ast.CssTree; +import com.google.gwt.thirdparty.common.css.compiler.ast.VisitController; + +import junit.framework.TestCase; + +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * Test for {@link ClassNamesCollector}. + */ +public class ClassNamesCollectorTest extends TestCase { + private CssClassSelectorNode cssClassSelectorNode; + private CssTree cssTree; + private VisitController visitController; + private ClassNamesCollector classNamesCollector; + + @Override + protected void setUp() { + classNamesCollector = new ClassNamesCollector(); + cssClassSelectorNode = mock(CssClassSelectorNode.class); + cssTree = mock(CssTree.class); + visitController = mock(VisitController.class); + + when(cssTree.getVisitController()).thenReturn(visitController); + } + + public void testGetClassNames_noImport_collectAllClasses() { + // Given + List<CssClassSelectorNode> classSelectorNodes = createClassSelectorNodes("class1", "class2", + "class3"); + whenVisitorControllerVisitTreeThenVisitAllNodes(classSelectorNodes); + + // When + Set<String> classNames = classNamesCollector.getClassNames(cssTree, new HashSet<JClassType>()); + + // Then + assertEquals(3, classNames.size()); + assertTrue(classNames.contains("class1")); + assertTrue(classNames.contains("class2")); + assertTrue(classNames.contains("class3")); + } + + public void testGetClassNames_withImport_dontCollectImportedClasses() { + // Given + List<CssClassSelectorNode> classSelectorNodes = createClassSelectorNodes("class1", "class2", + "class3", "Imported-class", "ImportedFakeClass", "otherImport-class"); + whenVisitorControllerVisitTreeThenVisitAllNodes(classSelectorNodes); + + Set<JClassType> importedType = new HashSet<JClassType>(); + + // mock a class without @ImportedWithPrefix annotation + JClassType importedClassType = mock(JClassType.class); + when(importedClassType.getSimpleSourceName()).thenReturn("Imported"); + importedType.add(importedClassType); + + // mock a class with a @ImportedWithPrefix annotation + JClassType importedWithPrefixClassType = mock(JClassType.class); + when(importedWithPrefixClassType.getSimpleSourceName()).thenReturn("ImportedWithPrefix"); + ImportedWithPrefix importedWithPrefixAnnotation = mock(ImportedWithPrefix.class); + when(importedWithPrefixAnnotation.value()).thenReturn("otherImport"); + when(importedWithPrefixClassType.getAnnotation(ImportedWithPrefix.class)) + .thenReturn(importedWithPrefixAnnotation); + importedType.add(importedWithPrefixClassType); + + // When + Set<String> classNames = classNamesCollector.getClassNames(cssTree, importedType); + + // Then + assertEquals(4, classNames.size()); + assertTrue(classNames.contains("class1")); + assertTrue(classNames.contains("class2")); + assertTrue(classNames.contains("class3")); + assertTrue(classNames.contains("ImportedFakeClass")); + assertFalse(classNames.contains("otherImport-class")); + assertFalse(classNames.contains("Imported-class")); + } + + private List<CssClassSelectorNode> createClassSelectorNodes(String... classNames) { + List<CssClassSelectorNode> classSelectorNodes = new ArrayList<CssClassSelectorNode>(classNames + .length); + + for (String className : classNames) { + CssClassSelectorNode node = mock(CssClassSelectorNode.class); + when(node.getRefinerName()).thenReturn(className); + classSelectorNodes.add(node); + } + + return classSelectorNodes; + } + + private void whenVisitorControllerVisitTreeThenVisitAllNodes(final List<CssClassSelectorNode> + nodes) { + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) throws Throwable { + for (CssClassSelectorNode node : nodes) { + classNamesCollector.enterClassSelector(node); + } + return null; + } + }).when(visitController).startVisit(classNamesCollector); + } +}
diff --git a/user/test/com/google/gwt/uibinder/UiBinderSuite.java b/user/test/com/google/gwt/uibinder/UiBinderSuite.java index 0657bc1..110ed3c 100644 --- a/user/test/com/google/gwt/uibinder/UiBinderSuite.java +++ b/user/test/com/google/gwt/uibinder/UiBinderSuite.java
@@ -23,6 +23,7 @@ import com.google.gwt.uibinder.test.client.UiBinderTest; import com.google.gwt.uibinder.test.client.UiChildTest; import com.google.gwt.uibinder.test.client.UiHandlerTest; +import com.google.gwt.uibinder.test.client.gss.UiBinderWithGssTest; import junit.framework.Test; @@ -41,6 +42,7 @@ suite.addTestSuite(UiBinderUtilTest.class); suite.addTestSuite(UiChildTest.class); suite.addTestSuite(UiHandlerTest.class); + suite.addTestSuite(UiBinderWithGssTest.class); return suite; }
diff --git a/user/test/com/google/gwt/uibinder/rebind/FieldWriterOfGeneratedCssResourceTest.java b/user/test/com/google/gwt/uibinder/rebind/FieldWriterOfGeneratedCssResourceTest.java index eae9c83..a76923f 100644 --- a/user/test/com/google/gwt/uibinder/rebind/FieldWriterOfGeneratedCssResourceTest.java +++ b/user/test/com/google/gwt/uibinder/rebind/FieldWriterOfGeneratedCssResourceTest.java
@@ -58,7 +58,8 @@ ImplicitCssResource css = new ImplicitCssResource("package", "ClassName", "fieldName", new String[] {}, cssResourceType, ".able-baker {}", - MortalLogger.NULL, Collections.<JClassType> emptySet(), new MockResourceOracle()); + MortalLogger.NULL, Collections.<JClassType> emptySet(), false, + new MockResourceOracle()); FieldWriterOfGeneratedCssResource f = new FieldWriterOfGeneratedCssResource( null, stringType, css, MortalLogger.NULL); @@ -74,7 +75,7 @@ ImplicitCssResource css = new ImplicitCssResource("package", "ClassName", "fieldName", new String[] {}, cssResourceType, ".ableBaker {}", - MortalLogger.NULL, Collections.<JClassType> emptySet(), new MockResourceOracle()); + MortalLogger.NULL, Collections.<JClassType> emptySet(), false, new MockResourceOracle()); FieldWriterOfGeneratedCssResource f = new FieldWriterOfGeneratedCssResource( null, stringType, css, MortalLogger.NULL);
diff --git a/user/test/com/google/gwt/uibinder/test/UiBinderWithGss.gwt.xml b/user/test/com/google/gwt/uibinder/test/UiBinderWithGss.gwt.xml new file mode 100644 index 0000000..f7ccadf --- /dev/null +++ b/user/test/com/google/gwt/uibinder/test/UiBinderWithGss.gwt.xml
@@ -0,0 +1,8 @@ +<module type="fileset"> + <inherits name="com.google.gwt.user.User" /> + <inherits name="com.google.gwt.debug.Debug"/> + <inherits name="com.google.gwt.junit.JUnit"/> + + <set-configuration-property name="CssResource.enableGss" value="true" /> + <set-configuration-property name="CssResource.legacy" value="true" /> +</module>
diff --git a/user/test/com/google/gwt/uibinder/test/client/gss/UiBinderWithGssTest.java b/user/test/com/google/gwt/uibinder/test/client/gss/UiBinderWithGssTest.java new file mode 100644 index 0000000..3b2f39f --- /dev/null +++ b/user/test/com/google/gwt/uibinder/test/client/gss/UiBinderWithGssTest.java
@@ -0,0 +1,52 @@ +/* + * Copyright 2014 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.google.gwt.uibinder.test.client.gss; + +import com.google.gwt.junit.client.GWTTestCase; +import com.google.gwt.uibinder.test.client.gss.WidgetUsingCss.CssStyle; +import com.google.gwt.uibinder.test.client.gss.WidgetUsingGss.GssStyle; +import com.google.gwt.user.client.ui.RootPanel; + +/** + * Test case for GSS integration in UiBinder. + */ +public class UiBinderWithGssTest extends GWTTestCase { + @Override + public String getModuleName() { + return "com.google.gwt.uibinder.test.UiBinderWithGss"; + } + + public void testGssIntegration() { + WidgetUsingGss widgetUsingGss = new WidgetUsingGss(); + GssStyle style = widgetUsingGss.style; + RootPanel.get().add(widgetUsingGss); + + assertEquals(style.main(), widgetUsingGss.getStyleName()); + String expectedCss = "." + style.main() + "{background-color:black;color:white;width:200px;" + + "height:300px}"; + assertEquals(expectedCss, widgetUsingGss.style.getText()); + } + + public void testCssConversion() { + WidgetUsingCss widgetUsingCss = new WidgetUsingCss(); + CssStyle style = widgetUsingCss.style; + RootPanel.get().add(widgetUsingCss); + + assertEquals(style.main(), widgetUsingCss.getStyleName()); + String expectedCss = "." + style.main() + "{background-color:black;color:white}"; + assertEquals(expectedCss, widgetUsingCss.style.getText()); + } +}
diff --git a/user/test/com/google/gwt/uibinder/test/client/gss/WidgetUsingCss.java b/user/test/com/google/gwt/uibinder/test/client/gss/WidgetUsingCss.java new file mode 100644 index 0000000..52d5691 --- /dev/null +++ b/user/test/com/google/gwt/uibinder/test/client/gss/WidgetUsingCss.java
@@ -0,0 +1,46 @@ +/* + * Copyright 2014 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.google.gwt.uibinder.test.client.gss; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.resources.client.CssResource; +import com.google.gwt.uibinder.client.UiBinder; +import com.google.gwt.uibinder.client.UiField; +import com.google.gwt.user.client.ui.Composite; +import com.google.gwt.user.client.ui.Widget; + +/** + * Widget not using GSS syntax in the inline style of its UiBinder template. + */ +public class WidgetUsingCss extends Composite { + interface WidgetUsingCssUiBinder extends UiBinder<Widget, WidgetUsingCss> { + } + + interface CssStyle extends CssResource { + String main(); + } + + static final String WHITE = "white"; + + private static WidgetUsingCssUiBinder uiBinder = GWT.create(WidgetUsingCssUiBinder.class); + + @UiField + CssStyle style; + + public WidgetUsingCss() { + initWidget(uiBinder.createAndBindUi(this)); + } +}
diff --git a/user/test/com/google/gwt/uibinder/test/client/gss/WidgetUsingCss.ui.xml b/user/test/com/google/gwt/uibinder/test/client/gss/WidgetUsingCss.ui.xml new file mode 100644 index 0000000..a3c973d --- /dev/null +++ b/user/test/com/google/gwt/uibinder/test/client/gss/WidgetUsingCss.ui.xml
@@ -0,0 +1,13 @@ +<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder' + xmlns:g='urn:import:com.google.gwt.user.client.ui'> + <ui:style type="com.google.gwt.uibinder.test.client.gss.WidgetUsingCss.CssStyle"> + @def my_black black; + @eval my_white com.google.gwt.uibinder.test.client.gss.WidgetUsingCss.WHITE; + + .main { + background-color: my_black; + color: my_white; + } + </ui:style> + <g:SimplePanel styleName="{style.main}"/> +</ui:UiBinder>
diff --git a/user/test/com/google/gwt/uibinder/test/client/gss/WidgetUsingGss.java b/user/test/com/google/gwt/uibinder/test/client/gss/WidgetUsingGss.java new file mode 100644 index 0000000..35e941f --- /dev/null +++ b/user/test/com/google/gwt/uibinder/test/client/gss/WidgetUsingGss.java
@@ -0,0 +1,44 @@ +/* + * Copyright 2014 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.google.gwt.uibinder.test.client.gss; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.resources.client.CssResource; +import com.google.gwt.uibinder.client.UiBinder; +import com.google.gwt.uibinder.client.UiField; +import com.google.gwt.user.client.ui.Composite; +import com.google.gwt.user.client.ui.Widget; + +/** + * Widget using GSS syntax in the inline style of its UiBinder template. + */ +public class WidgetUsingGss extends Composite { + interface WidgetUsingGssUiBinder extends UiBinder<Widget, WidgetUsingGss> { + } + + private static WidgetUsingGssUiBinder uiBinder = GWT.create(WidgetUsingGssUiBinder.class); + + interface GssStyle extends CssResource { + String main(); + } + + @UiField + GssStyle style; + + public WidgetUsingGss() { + initWidget(uiBinder.createAndBindUi(this)); + } +}
diff --git a/user/test/com/google/gwt/uibinder/test/client/gss/WidgetUsingGss.ui.xml b/user/test/com/google/gwt/uibinder/test/client/gss/WidgetUsingGss.ui.xml new file mode 100644 index 0000000..bfe056a --- /dev/null +++ b/user/test/com/google/gwt/uibinder/test/client/gss/WidgetUsingGss.ui.xml
@@ -0,0 +1,18 @@ +<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder' + xmlns:g='urn:import:com.google.gwt.user.client.ui'> + <ui:style gss="true" type="com.google.gwt.uibinder.test.client.gss.WidgetUsingGss.GssStyle"> + @def BLACK black; + + @defmixin size(WIDTH, HEIGHT) { + width: WIDTH; + height: HEIGHT; + } + + .main { + background-color: BLACK; + color: white; + @mixin size(200px, 300px); + } + </ui:style> + <g:SimplePanel styleName="{style.main}"/> +</ui:UiBinder>