Re: CssResource inheritance and avoiding rule repetition on injection, possibility of an @Require?
Hi Jens, Yea, this is definitely a good point. Then any widget can inherit this minimal CssResource and define on its own how it will look like in enabled / disabled state (= you would not add enableddisabled.css to the various widgets @Source annotation although you extend HasEnabledDisabledStateCss). I think this really is the best practice use of @Shared and inheritance, and as Thomas pointed out it shouldn't be used as a CssResource directly but only as an actual style interface. -- You received this message because you are subscribed to the Google Groups Google Web Toolkit group. To unsubscribe from this group and stop receiving emails from it, send an email to google-web-toolkit+unsubscr...@googlegroups.com. To post to this group, send email to google-web-toolkit@googlegroups.com. Visit this group at http://groups.google.com/group/google-web-toolkit. For more options, visit https://groups.google.com/groups/opt_out.
Re: CssResource inheritance and avoiding rule repetition on injection, possibility of an @Require?
Hi Jens, Here's the full example of what I was trying to illustrate as it's probably unfair of me to have others expect that I'm setting everything up right from just the pseudo code alone: public class GwtTest3 implements EntryPoint { public interface MyClientBundle extends ClientBundle{ public final static MyClientBundle INSTANCE = GWT.create(MyClientBundle.class); @Shared @ImportedWithPrefix(global) public interface GlobalCss extends CssResource{ public String genButton(); public String genButtonOther(); } /* * Global.css contains: * .genButton{ background: green; } .genButtonOther{ background: yellow; } */ @Source(Global.css) GlobalCss globalCss(); public interface InitButtonCss extends CssResource{ public String initButton(); public String initButton2(); } /* * InitButton.css contains: * .initButton{ background: #66F; } .global-genButton.initButton2{ background: orange; } */ @Import(GlobalCss.class) @Source({InitButton.css}) InitButtonCss initButtonCss(); public interface MyCss extends GlobalCss{ public String myButton(); } /* * My.css contains: * .myButton{ background: red; } */ /* * Regardless of whether you use @Import on a CssResource that is extending another CssResource * you still need to specify the source of the extended CssResource or else * gwt will error because it cannot find the selectors OR you would have to redefine all of the * selectors from the extended css in the child css. * This occurs even if you use @NotStrict. */ @Import(GlobalCss.class) /* * if specifying the source for this resource because it does not have the default name as well as * the extended css then order matters as it is the order in which gwt will generate the source * into the final css */ @Source({Global.css,My.css}) //will cause duplicate insert of rules from Global.css MyCss myCss(); } /** * This is the entry point method. */ @Override public void onModuleLoad() { MyClientBundle.INSTANCE.globalCss().ensureInjected(); Button genButton = new Button(1.) add first buttons); genButton.getElement().setAttribute(style, position:absolute;top:50%;left:40%;); genButton.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { MyClientBundle.INSTANCE.initButtonCss().ensureInjected(); Button initButton = new Button(init button (overqualified)); initButton.getElement().setAttribute(style, position:absolute;top:60%;left:40%;); initButton.addStyleName(MyClientBundle.INSTANCE.globalCss().genButton() + + MyClientBundle.INSTANCE.initButtonCss().initButton2()); RootPanel.get().add(initButton); Button initButton2 = new Button(init button 2 (blue)); initButton2.getElement().setAttribute(style, position:absolute;top:70%;left:40%;); initButton2.addStyleName(MyClientBundle.INSTANCE.globalCss().genButton() + + MyClientBundle.INSTANCE.initButtonCss().initButton()); RootPanel.get().add(initButton2); } }); RootPanel.get().add(genButton); Button genButton2 = new Button(2.) add second button); genButton2.getElement().setAttribute(style, position:absolute;top:50%;left:60%;); genButton2.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { MyClientBundle.INSTANCE.myCss().ensureInjected(); Button myButton = new Button(My button); myButton.getElement().setAttribute(style, position:absolute;top:60%;left:60%;); myButton.addStyleName(MyClientBundle.INSTANCE.globalCss().genButton() + + MyClientBundle.INSTANCE.myCss().myButton()); RootPanel.get().add(myButton); } }); RootPanel.get().add(genButton2); } } If you run it and click the 1st button then the 2nd button you'll see the background color of init button 2 (blue) change from blue to green. -- You received this message because you are subscribed to the Google Groups Google Web Toolkit group. To unsubscribe from this group and stop receiving emails from it, send an email to google-web-toolkit+unsubscr...@googlegroups.com. To post to this group, send email to google-web-toolkit@googlegroups.com. Visit this group at http://groups.google.com/group/google-web-toolkit. For more options, visit https://groups.google.com/groups/opt_out.
Re: CssResource inheritance and avoiding rule repetition on injection, possibility of an @Require?
Hi Thomas, I think this part right here is the clarification I needed: - mapping class names to/from methods is based on the method name or a @ClassName annotation (the class name in the CSS file will thus be replaced with the unique name computed for the method) So, if you want to reuse a class name in a selector, then use @Import or @Shared+inheritance. The difference is that with @Shared you're forced to declare rules for the inherited/shared class names (to satisfy the 4th rule above), and the class name is accessible from outside the CSS file, from the CssResource interface (because of inheritance). I'd like to think I wasn't misunderstanding anything as I can't find anywhere in the doc where it says if you use @Shared with inheritance then you have to declare all the super cssresource selectors in the extending cssresource's css. It was for this reason that I was adding the extended CssResource's css to the source declaration of the extending cssresource. I thought that redeclaring the super's selectors (as empty rules of course) in the extending css again to avoid the GWT errors felt like a hack especially if you consider that any time you add a new class to the super css you would have to redeclare the same class in all extending css. This didn't feel as going in the direction of maintainability which is why I was redeclaring the css in the @source (even though the leads to duplicate rules being inserted). But as I see that this is the state of things currently I'd gladly redeclare the selectors as empty ones in all the extending css as seeing the error to fix is much better than inserting a whole bunch of duplicate css. For reference, with this in mind, the example I gave Jens above would need the following changes to work correctly without duplication or the precedence override issue: My.css would contain: .genButton,.genButtonOther{} /*redeclare super selectors as empty to avoid GWT error*/ .myButton{ background: red; } And the MyCss declaration in MyClientBundle would be changed simply to: @Source(My.css) MyCss myCss(); This is what you're referring to right? And thanks again for the detailed explanation, this will be extremely useful as a reference and complement to the doc. -- You received this message because you are subscribed to the Google Groups Google Web Toolkit group. To unsubscribe from this group and stop receiving emails from it, send an email to google-web-toolkit+unsubscr...@googlegroups.com. To post to this group, send email to google-web-toolkit@googlegroups.com. Visit this group at http://groups.google.com/group/google-web-toolkit. For more options, visit https://groups.google.com/groups/opt_out.
Re: CssResource inheritance and avoiding rule repetition on injection, possibility of an @Require?
The best fix would be to use @Import instead of @Shared+inheritance (you don't even use the fact that MyCss extends GlobalCss). In other words, your InitButton is OK, not MyCss. On Sunday, February 23, 2014 10:13:00 PM UTC+1, GWTter wrote: Hi Thomas, I think this part right here is the clarification I needed: - mapping class names to/from methods is based on the method name or a @ClassName annotation (the class name in the CSS file will thus be replaced with the unique name computed for the method) So, if you want to reuse a class name in a selector, then use @Import or @Shared+inheritance. The difference is that with @Shared you're forced to declare rules for the inherited/shared class names (to satisfy the 4th rule above), and the class name is accessible from outside the CSS file, from the CssResource interface (because of inheritance). I'd like to think I wasn't misunderstanding anything as I can't find anywhere in the doc where it says if you use @Shared with inheritance then you have to declare all the super cssresource selectors in the extending cssresource's css. It was for this reason that I was adding the extended CssResource's css to the source declaration of the extending cssresource. I thought that redeclaring the super's selectors (as empty rules of course) in the extending css again to avoid the GWT errors felt like a hack especially if you consider that any time you add a new class to the super css you would have to redeclare the same class in all extending css. This didn't feel as going in the direction of maintainability which is why I was redeclaring the css in the @source (even though the leads to duplicate rules being inserted). But as I see that this is the state of things currently I'd gladly redeclare the selectors as empty ones in all the extending css as seeing the error to fix is much better than inserting a whole bunch of duplicate css. For reference, with this in mind, the example I gave Jens above would need the following changes to work correctly without duplication or the precedence override issue: My.css would contain: .genButton,.genButtonOther{} /*redeclare super selectors as empty to avoid GWT error*/ .myButton{ background: red; } And the MyCss declaration in MyClientBundle would be changed simply to: @Source(My.css) MyCss myCss(); This is what you're referring to right? And thanks again for the detailed explanation, this will be extremely useful as a reference and complement to the doc. -- You received this message because you are subscribed to the Google Groups Google Web Toolkit group. To unsubscribe from this group and stop receiving emails from it, send an email to google-web-toolkit+unsubscr...@googlegroups.com. To post to this group, send email to google-web-toolkit@googlegroups.com. Visit this group at http://groups.google.com/group/google-web-toolkit. For more options, visit https://groups.google.com/groups/opt_out.
Re: CssResource inheritance and avoiding rule repetition on injection, possibility of an @Require?
On Sunday, February 23, 2014 10:13:00 PM UTC+1, GWTter wrote: Hi Thomas, I think this part right here is the clarification I needed: - mapping class names to/from methods is based on the method name or a @ClassName annotation (the class name in the CSS file will thus be replaced with the unique name computed for the method) So, if you want to reuse a class name in a selector, then use @Import or @Shared+inheritance. The difference is that with @Shared you're forced to declare rules for the inherited/shared class names (to satisfy the 4th rule above), and the class name is accessible from outside the CSS file, from the CssResource interface (because of inheritance). I'd like to think I wasn't misunderstanding anything as I can't find anywhere in the doc where it says if you use @Shared with inheritance then you have to declare all the super cssresource selectors in the extending cssresource's css. The basic rule is that each method's class name is used at least once in the stylesheet, whether this method is declared on the interface or inherited from a superinterface doesn't matter. @Shared is only about the unique name (obfuscated name) of the class name, it doesn't change the other rules. -- You received this message because you are subscribed to the Google Groups Google Web Toolkit group. To unsubscribe from this group and stop receiving emails from it, send an email to google-web-toolkit+unsubscr...@googlegroups.com. To post to this group, send email to google-web-toolkit@googlegroups.com. Visit this group at http://groups.google.com/group/google-web-toolkit. For more options, visit https://groups.google.com/groups/opt_out.
Re: CssResource inheritance and avoiding rule repetition on injection, possibility of an @Require?
Yes, in the example I gave there's no clear need for the inheritance with MyCss, it's just there to show how inheritance would be setup to try to illustrate the issue I was referring to. It seems more and more like it's probably best to avoid inheritance and just go in the @Import direction. Even if you have to make sure the imported css are themselves injected or that you have to add those classes via their actual interfaces instead of as inherited, this seems to be more maintainable than the @Shared+inheritance and having to redeclare the super's selectors in the extended css. Thanks again for the help Thomas, it's much appreciated. On Sunday, February 23, 2014 11:09:59 PM UTC+1, Thomas Broyer wrote: On Sunday, February 23, 2014 10:13:00 PM UTC+1, GWTter wrote: Hi Thomas, I think this part right here is the clarification I needed: - mapping class names to/from methods is based on the method name or a @ClassName annotation (the class name in the CSS file will thus be replaced with the unique name computed for the method) So, if you want to reuse a class name in a selector, then use @Import or @Shared+inheritance. The difference is that with @Shared you're forced to declare rules for the inherited/shared class names (to satisfy the 4th rule above), and the class name is accessible from outside the CSS file, from the CssResource interface (because of inheritance). I'd like to think I wasn't misunderstanding anything as I can't find anywhere in the doc where it says if you use @Shared with inheritance then you have to declare all the super cssresource selectors in the extending cssresource's css. The basic rule is that each method's class name is used at least once in the stylesheet, whether this method is declared on the interface or inherited from a superinterface doesn't matter. @Shared is only about the unique name (obfuscated name) of the class name, it doesn't change the other rules. -- You received this message because you are subscribed to the Google Groups Google Web Toolkit group. To unsubscribe from this group and stop receiving emails from it, send an email to google-web-toolkit+unsubscr...@googlegroups.com. To post to this group, send email to google-web-toolkit@googlegroups.com. Visit this group at http://groups.google.com/group/google-web-toolkit. For more options, visit https://groups.google.com/groups/opt_out.
Re: CssResource inheritance and avoiding rule repetition on injection, possibility of an @Require?
Just to get things right. Even in your complete example the usage of @Import in the case of InitButtonCSS is useless. Its useless because the css class initButton2 will be a unique name anyways and thus it doesn't really make sense to define the css rule as .global-genButton.initButton2. @Import is usually used the other way around. That means you have some sort of a parent container widget and you want to change the default style of its child widgets. In that case you would @Import the css of the child widget into the parent widget css and then define css rules like .parent .childwidget-header { ... } to change the header of the child widget if this child widget will be put into that specific parent container. @Shared works best when you generalize some common state like focus / selected / disabled / enabled. For example you could have some sort of a SecurityManager that enables/disables widgets based on permissions. Such a SecurityManager would use a minimal CssResource like @Shared interface HasEnabledDisabledStateCss extends CssResource { String enabled(); String disabled(); } Then any widget can inherit this minimal CssResource and define on its own how it will look like in enabled / disabled state (= you would not add enableddisabled.css to the various widgets @Source annotation although you extend HasEnabledDisabledStateCss). So either @Shared nor @Import do not really fit into your example above. If you delete all these annotations then you example will work without issues and it will look like the short snippet I posted earlier. -- J. -- You received this message because you are subscribed to the Google Groups Google Web Toolkit group. To unsubscribe from this group and stop receiving emails from it, send an email to google-web-toolkit+unsubscr...@googlegroups.com. To post to this group, send email to google-web-toolkit@googlegroups.com. Visit this group at http://groups.google.com/group/google-web-toolkit. For more options, visit https://groups.google.com/groups/opt_out.
Re: CssResource inheritance and avoiding rule repetition on injection, possibility of an @Require?
On Monday, February 24, 2014 12:27:18 AM UTC+1, Jens wrote: Just to get things right. Even in your complete example the usage of @Import in the case of InitButtonCSS is useless. Its useless because the css class initButton2 will be a unique name anyways and thus it doesn't really make sense to define the css rule as .global-genButton.initButton2. Unless one of these is dynamically added/removed. @Import is usually used the other way around. That means you have some sort of a parent container widget and you want to change the default style of its child widgets. In that case you would @Import the css of the child widget into the parent widget css and then define css rules like .parent .childwidget-header { ... } to change the header of the child widget if this child widget will be put into that specific parent container. It's also useful the other way around. I've used @Import to show/hide elements in cells when a CellTable row is hovered: .gwt-CellTable-cellTableCell .hiddenAction { visibility: hidden; } .gwt-CellTable-cellTableHoveredRowCell .hiddenAction { visibility: visible; } or showing some kind of label as red when put in an error panel: .label { width: 200px; } .global-hasError .label { color: red; } @Shared works best when you generalize some common state like focus / selected / disabled / enabled. For example you could have some sort of a SecurityManager that enables/disables widgets based on permissions. Such a SecurityManager would use a minimal CssResource like @Shared interface HasEnabledDisabledStateCss extends CssResource { String enabled(); String disabled(); } Then any widget can inherit this minimal CssResource and define on its own how it will look like in enabled / disabled state (= you would not add enableddisabled.css to the various widgets @Source annotation although you extend HasEnabledDisabledStateCss). +1, a @Shared interface would generally not have a CSS file and would only be used in extends (never as return type of a ClientBundle resource) So either @Shared nor @Import do not really fit into your example above. If you delete all these annotations then you example will work without issues and it will look like the short snippet I posted earlier. -- J. -- You received this message because you are subscribed to the Google Groups Google Web Toolkit group. To unsubscribe from this group and stop receiving emails from it, send an email to google-web-toolkit+unsubscr...@googlegroups.com. To post to this group, send email to google-web-toolkit@googlegroups.com. Visit this group at http://groups.google.com/group/google-web-toolkit. For more options, visit https://groups.google.com/groups/opt_out.
Re: CssResource inheritance and avoiding rule repetition on injection, possibility of an @Require?
On Friday, February 21, 2014 5:09:36 PM UTC+1, Thomas Broyer wrote: On Thursday, February 20, 2014 10:51:29 PM UTC+1, GWTter wrote: Before anything, sorry Thomas, I think I may have just replied to you instead of just the topic (buttons bugged on me a bit), no-spam intended You're right I guess I did misunderstand if the imported with prefix doesn't in fact use a different obfuscation for the original selectors in the final css. So using the imported with prefix method isn't a viable workaround for avoid the precedence override on injection after all. And definitely, anything that will help clear it up. I can try to clarify my original example: You have the following, === Pseudocode === CssResouces: SuperCssResource, is injected onModuleLoad (global css) and has the following css as its source: .genButton{ color: black; } and LeafCssResource extends SuperCssResource css definitions here Why are you using an extends here? what do you expect from it? and more importantly what does your ClientBundle(s) looks like? I'm just setting up viable example when working with Resources. In this case specifically you would expect to be able to reference the styles from SuperCssResource via LeafCssResource and be able to use the selectors from SuperCssResource's css to qualify other selectors in LeafCssResource's css. The client bundle would simply look like: interface LeafClientBundle extends ClientBundle{ @Source({Leaf.css,Super.css}) LeafCssResource leafCss(); } Finally, we have the following 2 widgets: WidgetDisplayedFirst, has the following css via uibinder: MyCssResource: .myButton{ color: red; } And this button element: button class=genButton myButton / Using this, it means you have to ensure SuperCssResource is always injected *before* you createAndBindUi for the widget. Using .genButton.myButton (higher specificity) in the CSS would fix it. Yes, and in this example I would make sure to inject LeafCssResource which would thereby inject SuperCssResource. And adding .genButton to further the specificity of .myButton would indeed fix, however the point I'm trying to make is that I think it's unreasonable to either overqualify every selector for fear of having your styles be overridden because of precedence or that developers need to be aware of all the other styles they would be affecting when creating their own widget trying to qualify their selectors with a global cssresource. and WidgetDisplayedSecond which uses LeafCssResource -- Now if while my app is running I just display WidgetDisplayedFirst then it will display its button with the correct color: red because the .myButton was declared last and thus overrides the .genButton which has the same specificity. The issue comes into play if I then display WidgetDisplayedSecond. Since WidgetDisplayedSecond uses LeafCssResource this will cause SuperCssResource and its css to be injected when LeafCssResource is injected. No. Unless you have a @Shared annotation on SuperCssResource, the names from LeafCssResource will be different from those of SuperCssResource (so even if you referenced the same CSS file in @Source of your 2 ClientBundle methods, you'd have duplicated rules with different selectors, in no way would SuperCssResource be reinjected). See http://www.gwtproject.org/doc/latest/DevGuideClientBundle.html#Scope Yes, and I should have actually put the @Shared in the example. I didn't remember to add it because I was talking about reusing selectors in the leaf css to qualify in which case you would need to have the same names or else the qualifying would not work at all since the names would be different. So in this case I am talking about using the @Shared on the SuperCssResource and that you do see the selectors from SuperCssResource's css reinjected when you inject LeafCssResource. At this point because SuperCssResource has now been reinjected and thus is now the last one declared between it and MyCssResource, its .genButton rule now wins and causes WidgetDisplayedFirst's button to now have a color of black. With the code above, it shouldn't (now there could be bugs). So you're saying that SuperCssResource's css should not be included in with the css generated for LeafCssResource to be injected? If that's the case then I think there is a bug. Now, granted, this is how Css is intended to work in terms of the cascade. However, what I'm trying to say is that this is an example of a case where that is not the desired outcome if you want the button to keep the color of red as defined in its MyCssResource. You really only have 3 options in order to prevent this currently as far as I can see: 1) You over-qualify all of your selectors to ensure that they always have the most specifity and nothing
Re: CssResource inheritance and avoiding rule repetition on injection, possibility of an @Require?
At this point because SuperCssResource has now been reinjected and thus is now the last one declared between it and MyCssResource, its .genButton rule now wins and causes WidgetDisplayedFirst's button to now have a color of black. With the code above, it shouldn't (now there could be bugs). So you're saying that SuperCssResource's css should not be included in with the css generated for LeafCssResource to be injected? If that's the case then I think there is a bug. In all your samples above you are not defining that SuperCssResource has a @Shared annotation and without that @Shared annotation your issue can not happen because all duplicated css classes will get unique names. Thus With the code above, it shouldn't. -- J. -- You received this message because you are subscribed to the Google Groups Google Web Toolkit group. To unsubscribe from this group and stop receiving emails from it, send an email to google-web-toolkit+unsubscr...@googlegroups.com. To post to this group, send email to google-web-toolkit@googlegroups.com. Visit this group at http://groups.google.com/group/google-web-toolkit. For more options, visit https://groups.google.com/groups/opt_out.
Re: CssResource inheritance and avoiding rule repetition on injection, possibility of an @Require?
You have a fundamental misunderstanding of @Import, despite the doc being rather clear, and that's your only problem (afaict). http://www.gwtproject.org/doc/latest/DevGuideClientBundle.html#Imported_scopes You also have a slight misunderstanding of @Shared. Let's go back to the basics: http://www.gwtproject.org/doc/latest/DevGuideClientBundle.html#Selector_obfuscation_details - each method in a CssResource interface maps to a unique name (let's call it obfuscated class name) based on the type of the interface and the name of the method - the basis for the unique name is the interface used as return type of the ClientBundle method, even for methods inherited from other interfaces, except if such an interface is annotated with @Shared, in which case the name will be unique for the @Shared interface (and the same name used for every sub-interface) - each class name used in the CSS must map to a method in the interface, unless you use @NotStrict, or the class name has been declared @external, or the class name has been @Import-ed from another interface. In that case, the .*prefix-className* in the CSS (where *prefix* is the prefix declared in @ImportedWithPrefix on the imported interface, and *className* is the original class name from the imported interface) will be replaced with the unique name computed for the method of the imported interface - mapping class names to/from methods is based on the method name or a @ClassName annotation (the class name in the CSS file will thus be replaced with the unique name computed for the method) So, if you want to reuse a class name in a selector, then use @Import or @Shared+inheritance. The difference is that with @Shared you're forced to declare rules for the inherited/shared class names (to satisfy the 4th rule above), and the class name is accessible from outside the CSS file, from the CssResource interface (because of inheritance). @Import is for cases where you want to say the style rules have to be slightly different when used within/in coordination with/in the context of some other widget (e.g. a cell that's slightly different when in a CellTree, compared to a CellTable or CellList, or a widget that's slightly different when put in some specific container widget, or possibly when defining the style of a container or composite widget saying a child widget needs to have a slightly different style). @Shared is generally for cases where you want to say the style rules have to be slightly different depending on some state/situation, where the state/situation is toggled/triggered externally by adding/removing a class name, and you possibly want a shared/common way to toggle/trigger that state/situation independently of the current specific style (e.g. all checkables have checked and unchecked states, whether they're checkboxes, push buttons, togglable menu items, etc.) In both cases, the goal is to write compound selectors using a local class name and an imported/shared class name, composed directly (both classes applied to the same element) or with an operator. In your case, you'll use either @Import or @Shared, depending on your use case. But if you use @Shared, then you MUST NOT use the parent CSS file in the @Source for the child interface! Inline notes below: On Saturday, February 22, 2014 10:09:48 PM UTC+1, GWTter wrote: On Friday, February 21, 2014 5:09:36 PM UTC+1, Thomas Broyer wrote: On Thursday, February 20, 2014 10:51:29 PM UTC+1, GWTter wrote: Before anything, sorry Thomas, I think I may have just replied to you instead of just the topic (buttons bugged on me a bit), no-spam intended You're right I guess I did misunderstand if the imported with prefix doesn't in fact use a different obfuscation for the original selectors in the final css. So using the imported with prefix method isn't a viable workaround for avoid the precedence override on injection after all. And definitely, anything that will help clear it up. I can try to clarify my original example: You have the following, === Pseudocode === CssResouces: SuperCssResource, is injected onModuleLoad (global css) and has the following css as its source: .genButton{ color: black; } and LeafCssResource extends SuperCssResource css definitions here Why are you using an extends here? what do you expect from it? and more importantly what does your ClientBundle(s) looks like? I'm just setting up viable example when working with Resources. In this case specifically you would expect to be able to reference the styles from SuperCssResource via LeafCssResource and be able to use the selectors from SuperCssResource's css to qualify other selectors in LeafCssResource's css. The client bundle would simply look like: interface LeafClientBundle extends ClientBundle{ @Source({Leaf.css,Super.css}) LeafCssResource leafCss(); }
Re: CssResource inheritance and avoiding rule repetition on injection, possibility of an @Require?
Hi Jens, Yes, this duplication when extending CssResources is exactly the issue I'm trying to highlight above and mitigate with the @required idea. Your suggestion is what I was trying to cover with the third option I gave above on how to avoid the duplication and unintended precedence override (although you do go a bit more in-depth into what it would actually look like). And I apologize if I'm giving the impression that this is an active issue which I don't know how to workaround or remedy, that's not my intention. I'm trying to say that I've come across this issue several times before, and while I'm aware of the cause and the current workarounds/remedies (as I try to briefly summarize in the 3 options above), I feel that they are not satisfactory enough when considering the scaling and maintenance of large webapps. This is why I'm trying to discuss the feasibility and/or ramifications of something like the @required because I think it's somewhere GWT would be able to shine and facilitate the scalability and maintainability of these webapps. Thanks for you response. On Friday, February 21, 2014 12:36:08 AM UTC+1, Jens wrote: If you write a widget and that widget uses a button and that button has a default style defined in a BaseCssResource then you should use that BaseCssResource directly in your widget. You should not make your WidgetCssResource extend the BaseCssResource. Why? Because as soon as you do so, all the CSS rules of BaseCssResource will be duplicated (even if the BaseCssResource is annotated with @Shared, which will cause the issue you describe) and that is not what you want. Imagine you have 50 widgets and each of their CssResources extends the BaseCssResource. You would end up with 50 times the same base CSS code injected in your html page (either with the same CSS class names if you use @Shared on your BaseCssResource or with different CSS class names if not). What you should do in all your widgets is: ui:with field=bundle type= / ui:style .redbutton { background-color:red; } /ui:style button class={bundle.baseCss.button} {style.redbutton} And in your custom widget constructor you would do public MyWidget() { bundle.baseCss().ensureInjected(); } That way your base CSS is only injected once into your HTML page and all your widgets use these rules directly instead of duplicating them over and over again. It is also clear, just by looking at the xml/code, that the base CSS is shared by multiple widgets and that the ui:style CSS is only local to that single widget. -- J. -- You received this message because you are subscribed to the Google Groups Google Web Toolkit group. To unsubscribe from this group and stop receiving emails from it, send an email to google-web-toolkit+unsubscr...@googlegroups.com. To post to this group, send email to google-web-toolkit@googlegroups.com. Visit this group at http://groups.google.com/group/google-web-toolkit. For more options, visit https://groups.google.com/groups/opt_out.
Re: CssResource inheritance and avoiding rule repetition on injection, possibility of an @Require?
On Thursday, February 20, 2014 10:51:29 PM UTC+1, GWTter wrote: Before anything, sorry Thomas, I think I may have just replied to you instead of just the topic (buttons bugged on me a bit), no-spam intended You're right I guess I did misunderstand if the imported with prefix doesn't in fact use a different obfuscation for the original selectors in the final css. So using the imported with prefix method isn't a viable workaround for avoid the precedence override on injection after all. And definitely, anything that will help clear it up. I can try to clarify my original example: You have the following, === Pseudocode === CssResouces: SuperCssResource, is injected onModuleLoad (global css) and has the following css as its source: .genButton{ color: black; } and LeafCssResource extends SuperCssResource css definitions here Why are you using an extends here? what do you expect from it? and more importantly what does your ClientBundle(s) looks like? Finally, we have the following 2 widgets: WidgetDisplayedFirst, has the following css via uibinder: MyCssResource: .myButton{ color: red; } And this button element: button class=genButton myButton / Using this, it means you have to ensure SuperCssResource is always injected *before* you createAndBindUi for the widget. Using .genButton.myButton (higher specificity) in the CSS would fix it. and WidgetDisplayedSecond which uses LeafCssResource -- Now if while my app is running I just display WidgetDisplayedFirst then it will display its button with the correct color: red because the .myButton was declared last and thus overrides the .genButton which has the same specificity. The issue comes into play if I then display WidgetDisplayedSecond. Since WidgetDisplayedSecond uses LeafCssResource this will cause SuperCssResource and its css to be injected when LeafCssResource is injected. No. Unless you have a @Shared annotation on SuperCssResource, the names from LeafCssResource will be different from those of SuperCssResource (so even if you referenced the same CSS file in @Source of your 2 ClientBundle methods, you'd have duplicated rules with different selectors, in no way would SuperCssResource be reinjected). See http://www.gwtproject.org/doc/latest/DevGuideClientBundle.html#Scope At this point because SuperCssResource has now been reinjected and thus is now the last one declared between it and MyCssResource, its .genButton rule now wins and causes WidgetDisplayedFirst's button to now have a color of black. With the code above, it shouldn't (now there could be bugs). Now, granted, this is how Css is intended to work in terms of the cascade. However, what I'm trying to say is that this is an example of a case where that is not the desired outcome if you want the button to keep the color of red as defined in its MyCssResource. You really only have 3 options in order to prevent this currently as far as I can see: 1) You over-qualify all of your selectors to ensure that they always have the most specifity and nothing will override them =CON: over-qualifying is not great for performance and is not as maintainable/cascadeable 2) You architect the app taking into account every single inheriting resource that is injected dynamically/on-demand to make sure that the injection of the extended resource does not cause an override in widgets who are using its classes. =CON: extremely unrealistic for non-trivial apps much less a real web-app Except that inheritance of CssResource interfaces does not work that way (and if it does in practice –I doubt it, there are unit tests–, then that's a bug). 3)Do not extend CssResources, this way you can ensure that all resources and their associated styles are ONLY injected once in the lifetime of the app so there are no worries of unintended precedence overrides. =CON: greatly restricts selector qualifying especially when trying to localize css and reuse widgets I don't get your CON here. If you need to use the class name from another CssResource in your CSS in a compound selector, then just @Import the other CssResource. As long as you're not changing the styles from the imported class names (same as if you had several CSS files without using ClientBundle), there's no need to worry. -- You received this message because you are subscribed to the Google Groups Google Web Toolkit group. To unsubscribe from this group and stop receiving emails from it, send an email to google-web-toolkit+unsubscr...@googlegroups.com. To post to this group, send email to google-web-toolkit@googlegroups.com. Visit this group at http://groups.google.com/group/google-web-toolkit. For more options, visit https://groups.google.com/groups/opt_out.
Re: CssResource inheritance and avoiding rule repetition on injection, possibility of an @Require?
On Thursday, February 20, 2014 12:08:28 AM UTC+1, GWTter wrote: On Wednesday, February 19, 2014 10:59:51 AM UTC+1, Thomas Broyer wrote: On Tuesday, February 18, 2014 6:38:36 PM UTC+1, GWTter wrote: Hi all, Let me just go with an example right off the bat. Let's say I have the following: === Pseudocode === SuperCssResource: This is injected onModuleLoad before anything else .genButton{ color: black; } Widget1 consists of: --- css --- MyCssResource: .myButton{ color: red; } --- html --- button class=genButton myButton / Widget2 consists of: --- css --- XCssResource extends SuperCssResource: ... rules that use classes from SuperCssResource --- html --- ...elements My problem is that if I display Widget1 first and then display Widget2 then the button in Widget1 will have a color of black instead of red. I know that this is expected behavior (GWT will merge the stylesheets together) since inheritance is basically the cssresource equivalent of CSS @import http://www.w3.org/TR/css3-cascade/#at-import Er, no. Inheritance of CssResource interfaces only deals with that: inheriting methods. The actual CSS backing the resource is given by the @Source annotation on your ClientBundle method, and if you use the same CSS file for 2 different CssResource interfaces, the CSS will be duplicated, because obfuscation of the class names is based on the interface fully-qualified name: http://www.gwtproject.org/doc/latest/DevGuideClientBundle.html#Scope (the order of the files in @Source will impact merging, just as they'd impact precedence in CSS). Hi Thomas, I guess I should have specified that it is inheritance along with specifying the source css that for all intents and purposes acts like CSS @import. I know that GWT will error if you extend the super resource and don't include it's source to match the classes, unless you're reimplementing them in the extending css resource which is not what I'm after and not the best idea IMHO. but I thought since this was GWT maybe there was a way to use inheritance in the sense that the inherited stylesheet would only be injected if not injected already. Is this currently possible? or could it be done with like a @Require annotation on the extending interface which would indicate that merging of the super stylesheet should not be done but rather a check would be made to see if it already exists and if not to inject it. This would easily resolve the specificity overriding issue in the example when it's not the desired behavior. I know I could also get around this by importing with a prefix, however I still don't like the idea of essentially reinjecting the same styles. If you don't want duplication, then you need a shared scope or imported scope. In any case, that means you should only use the shared/imported class names in more complex selectors, you shouldn't change the styles attached to the selector by itself. None of this applies if you use @external though, then it just works like standard CSS. I know, like you mentioned, that I could avoid the precedence override by importing with prefix for example. And my use case is only to increase specificity on the extending css resource, definitely not to change the super's rule def by redefining the super selector in the extending resource. But I'm not thrilled with essentially reinjecting all the same rules with just different prefixes and @external does really fit my need as I don't want to forgo the obfuscation. I don't understand that reinjecting all the same rules with just different prefixes bit; sounds like a misunderstanding of how @Import and @ImportedWithPrefix work. Obfuscation is based on the FQCN of the interface, so @Import()ing such an interface is only about importing the *names*, not the source (which is not defined in the interface anyway), and @ImportedWithPrefix is only there to prevent conflicts (it also helps visually distinguishing those names that have been imported and those that are defined in the stylesheet). The gwt-CellTree-cellTreeItem you'd get by @Import(CellTree.Style.class) will be replaced with the same obfuscated name as the cellTreeItem from the CellTree stylesheet, so you can match something in a CellTree, but nothing is injected with just different prefixes, the prefixes are gone after compilation. Either that, or I'm not understanding your use-case, and a simple example would really help! (in any case, if you could share a simple example, I think everyone could benefit from a discussion around it, or maybe just using it as a basis for their own work, maybe even a best practice) -- You received this message because you are subscribed to the Google Groups Google Web Toolkit group. To unsubscribe from this group and stop receiving emails from it, send an email to google-web-toolkit+unsubscr...@googlegroups.com. To post to this group, send email
Re: CssResource inheritance and avoiding rule repetition on injection, possibility of an @Require?
Before anything, sorry Thomas, I think I may have just replied to you instead of just the topic (buttons bugged on me a bit), no-spam intended You're right I guess I did misunderstand if the imported with prefix doesn't in fact use a different obfuscation for the original selectors in the final css. So using the imported with prefix method isn't a viable workaround for avoid the precedence override on injection after all. And definitely, anything that will help clear it up. I can try to clarify my original example: You have the following, === Pseudocode === CssResouces: SuperCssResource, is injected onModuleLoad (global css) and has the following css as its source: .genButton{ color: black; } and LeafCssResource extends SuperCssResource css definitions here Finally, we have the following 2 widgets: WidgetDisplayedFirst, has the following css via uibinder: MyCssResource: .myButton{ color: red; } And this button element: button class=genButton myButton / and WidgetDisplayedSecond which uses LeafCssResource -- Now if while my app is running I just display WidgetDisplayedFirst then it will display its button with the correct color: red because the .myButton was declared last and thus overrides the .genButton which has the same specificity. The issue comes into play if I then display WidgetDisplayedSecond. Since WidgetDisplayedSecond uses LeafCssResource this will cause SuperCssResource and its css to be injected when LeafCssResource is injected. At this point because SuperCssResource has now been reinjected and thus is now the last one declared between it and MyCssResource, its .genButton rule now wins and causes WidgetDisplayedFirst's button to now have a color of black. Now, granted, this is how Css is intended to work in terms of the cascade. However, what I'm trying to say is that this is an example of a case where that is not the desired outcome if you want the button to keep the color of red as defined in its MyCssResource. You really only have 3 options in order to prevent this currently as far as I can see: 1) You over-qualify all of your selectors to ensure that they always have the most specifity and nothing will override them =CON: over-qualifying is not great for performance and is not as maintainable/cascadeable 2) You architect the app taking into account every single inheriting resource that is injected dynamically/on-demand to make sure that the injection of the extended resource does not cause an override in widgets who are using its classes. =CON: extremely unrealistic for non-trivial apps much less a real web-app 3)Do not extend CssResources, this way you can ensure that all resources and their associated styles are ONLY injected once in the lifetime of the app so there are no worries of unintended precedence overrides. =CON: greatly restricts selector qualifying especially when trying to localize css and reuse widgets I think you can see why these 3 options are unappealing. I'd argue that this isn't an issue for static web pages and the non-webapp era since you could relegate css to a page and count on the browser refresh to always provide a clean slate. However, in the web-app era this seems to be a big issue maintainability-wise if nothing else. This is why I was suggesting the @required functionality so the developer can have some assurance that styles won't be injected more than once and thus be assured that if someone displays their widget anywhere then it won't break something else. Hope that somewhat clears up what I'm trying to say. Thanks again for the discussion. On Thursday, February 20, 2014 1:15:48 PM UTC+1, Thomas Broyer wrote: On Thursday, February 20, 2014 12:08:28 AM UTC+1, GWTter wrote: On Wednesday, February 19, 2014 10:59:51 AM UTC+1, Thomas Broyer wrote: On Tuesday, February 18, 2014 6:38:36 PM UTC+1, GWTter wrote: Hi all, Let me just go with an example right off the bat. Let's say I have the following: === Pseudocode === SuperCssResource: This is injected onModuleLoad before anything else .genButton{ color: black; } Widget1 consists of: --- css --- MyCssResource: .myButton{ color: red; } --- html --- button class=genButton myButton / Widget2 consists of: --- css --- XCssResource extends SuperCssResource: ... rules that use classes from SuperCssResource --- html --- ...elements My problem is that if I display Widget1 first and then display Widget2 then the button in Widget1 will have a color of black instead of red. I know that this is expected behavior (GWT will merge the stylesheets together) since inheritance is basically the cssresource equivalent of CSS @import http://www.w3.org/TR/css3-cascade/#at-import Er, no. Inheritance of CssResource interfaces only deals with that: inheriting methods. The actual CSS backing the resource is given by the @Source
Re: CssResource inheritance and avoiding rule repetition on injection, possibility of an @Require?
If you write a widget and that widget uses a button and that button has a default style defined in a BaseCssResource then you should use that BaseCssResource directly in your widget. You should not make your WidgetCssResource extend the BaseCssResource. Why? Because as soon as you do so, all the CSS rules of BaseCssResource will be duplicated (even if the BaseCssResource is annotated with @Shared, which will cause the issue you describe) and that is not what you want. Imagine you have 50 widgets and each of their CssResources extends the BaseCssResource. You would end up with 50 times the same base CSS code injected in your html page (either with the same CSS class names if you use @Shared on your BaseCssResource or with different CSS class names if not). What you should do in all your widgets is: ui:with field=bundle type= / ui:style .redbutton { background-color:red; } /ui:style button class={bundle.baseCss.button} {style.redbutton} And in your custom widget constructor you would do public MyWidget() { bundle.baseCss().ensureInjected(); } That way your base CSS is only injected once into your HTML page and all your widgets use these rules directly instead of duplicating them over and over again. It is also clear, just by looking at the xml/code, that the base CSS is shared by multiple widgets and that the ui:style CSS is only local to that single widget. -- J. -- You received this message because you are subscribed to the Google Groups Google Web Toolkit group. To unsubscribe from this group and stop receiving emails from it, send an email to google-web-toolkit+unsubscr...@googlegroups.com. To post to this group, send email to google-web-toolkit@googlegroups.com. Visit this group at http://groups.google.com/group/google-web-toolkit. For more options, visit https://groups.google.com/groups/opt_out.
Re: CssResource inheritance and avoiding rule repetition on injection, possibility of an @Require?
On Tuesday, February 18, 2014 6:38:36 PM UTC+1, GWTter wrote: Hi all, Let me just go with an example right off the bat. Let's say I have the following: === Pseudocode === SuperCssResource: This is injected onModuleLoad before anything else .genButton{ color: black; } Widget1 consists of: --- css --- MyCssResource: .myButton{ color: red; } --- html --- button class=genButton myButton / Widget2 consists of: --- css --- XCssResource extends SuperCssResource: ... rules that use classes from SuperCssResource --- html --- ...elements My problem is that if I display Widget1 first and then display Widget2 then the button in Widget1 will have a color of black instead of red. I know that this is expected behavior (GWT will merge the stylesheets together) since inheritance is basically the cssresource equivalent of CSS @import http://www.w3.org/TR/css3-cascade/#at-import Er, no. Inheritance of CssResource interfaces only deals with that: inheriting methods. The actual CSS backing the resource is given by the @Source annotation on your ClientBundle method, and if you use the same CSS file for 2 different CssResource interfaces, the CSS will be duplicated, because obfuscation of the class names is based on the interface fully-qualified name: http://www.gwtproject.org/doc/latest/DevGuideClientBundle.html#Scope (the order of the files in @Source will impact merging, just as they'd impact precedence in CSS). but I thought since this was GWT maybe there was a way to use inheritance in the sense that the inherited stylesheet would only be injected if not injected already. Is this currently possible? or could it be done with like a @Require annotation on the extending interface which would indicate that merging of the super stylesheet should not be done but rather a check would be made to see if it already exists and if not to inject it. This would easily resolve the specificity overriding issue in the example when it's not the desired behavior. I know I could also get around this by importing with a prefix, however I still don't like the idea of essentially reinjecting the same styles. If you don't want duplication, then you need a shared scope or imported scope. In any case, that means you should only use the shared/imported class names in more complex selectors, you shouldn't change the styles attached to the selector by itself. None of this applies if you use @external though, then it just works like standard CSS. …and no, there's no way to say please make sure that other stylesheet is injected when injecting that one, because, to begin with, it'd be hard to define what that other stylesheet is (the interface is not enough, given that the @Source is set on the ClientBundle method, so you'd have to say this method from this ClientBundle interface, but it wouldn't even be enough: what if you composed that interface with another one and GWT.create()d the composed interface? should that @Require mean that GWT would do a GWT.create() of the lone interface, therefore duplicating efforts? –in all honesty, I haven't looked closely at the impact in terms of generated code and how it could be optimized, but it could limit future evolutions of ClientBundle in which code it generates, just to make sure that feature would still be correctly optimized–) No really, given that ensureInjected() is a no-op if already injected, just make sure you call ensureInjected() on your required CssResource before calling ensureInjected() on the one that requires it, and document it thoroughly in the javadoc of the requiring ClientBundle method. -- You received this message because you are subscribed to the Google Groups Google Web Toolkit group. To unsubscribe from this group and stop receiving emails from it, send an email to google-web-toolkit+unsubscr...@googlegroups.com. To post to this group, send email to google-web-toolkit@googlegroups.com. Visit this group at http://groups.google.com/group/google-web-toolkit. For more options, visit https://groups.google.com/groups/opt_out.
Re: CssResource inheritance and avoiding rule repetition on injection, possibility of an @Require?
On Wednesday, February 19, 2014 10:59:51 AM UTC+1, Thomas Broyer wrote: On Tuesday, February 18, 2014 6:38:36 PM UTC+1, GWTter wrote: Hi all, Let me just go with an example right off the bat. Let's say I have the following: === Pseudocode === SuperCssResource: This is injected onModuleLoad before anything else .genButton{ color: black; } Widget1 consists of: --- css --- MyCssResource: .myButton{ color: red; } --- html --- button class=genButton myButton / Widget2 consists of: --- css --- XCssResource extends SuperCssResource: ... rules that use classes from SuperCssResource --- html --- ...elements My problem is that if I display Widget1 first and then display Widget2 then the button in Widget1 will have a color of black instead of red. I know that this is expected behavior (GWT will merge the stylesheets together) since inheritance is basically the cssresource equivalent of CSS @import http://www.w3.org/TR/css3-cascade/#at-import Er, no. Inheritance of CssResource interfaces only deals with that: inheriting methods. The actual CSS backing the resource is given by the @Source annotation on your ClientBundle method, and if you use the same CSS file for 2 different CssResource interfaces, the CSS will be duplicated, because obfuscation of the class names is based on the interface fully-qualified name: http://www.gwtproject.org/doc/latest/DevGuideClientBundle.html#Scope (the order of the files in @Source will impact merging, just as they'd impact precedence in CSS). Hi Thomas, I guess I should have specified that it is inheritance along with specifying the source css that for all intents and purposes acts like CSS @import. I know that GWT will error if you extend the super resource and don't include it's source to match the classes, unless you're reimplementing them in the extending css resource which is not what I'm after and not the best idea IMHO. but I thought since this was GWT maybe there was a way to use inheritance in the sense that the inherited stylesheet would only be injected if not injected already. Is this currently possible? or could it be done with like a @Require annotation on the extending interface which would indicate that merging of the super stylesheet should not be done but rather a check would be made to see if it already exists and if not to inject it. This would easily resolve the specificity overriding issue in the example when it's not the desired behavior. I know I could also get around this by importing with a prefix, however I still don't like the idea of essentially reinjecting the same styles. If you don't want duplication, then you need a shared scope or imported scope. In any case, that means you should only use the shared/imported class names in more complex selectors, you shouldn't change the styles attached to the selector by itself. None of this applies if you use @external though, then it just works like standard CSS. I know, like you mentioned, that I could avoid the precedence override by importing with prefix for example. And my use case is only to increase specificity on the extending css resource, definitely not to change the super's rule def by redefining the super selector in the extending resource. But I'm not thrilled with essentially reinjecting all the same rules with just different prefixes and @external does really fit my need as I don't want to forgo the obfuscation. …and no, there's no way to say please make sure that other stylesheet is injected when injecting that one, because, to begin with, it'd be hard to define what that other stylesheet is (the interface is not enough, given that the @Source is set on the ClientBundle method, so you'd have to say this method from this ClientBundle interface, but it wouldn't even be enough: what if you composed that interface with another one and GWT.create()d the composed interface? should that @Require mean that GWT would do a GWT.create() of the lone interface, therefore duplicating efforts? –in all honesty, I haven't looked closely at the impact in terms of generated code and how it could be optimized, but it could limit future evolutions of ClientBundle in which code it generates, just to make sure that feature would still be correctly optimized–) Originally I did think that the interface would be enough but as you pointed out you can technically use another source css to attach to the interface when defining it in the Clientbundle, wouldn't necessarily always be the same one. I only thought of what I think you alluded to which would have been to specify the clientbundle such as in the @Required(MyClientbundle). In that composed case you mention isn't that what's currently happening? From what I can see in the generated css, the extended resources are basically inlined before the extending resource css and the whole thing becomes the final css which GWT
CssResource inheritance and avoiding rule repetition on injection, possibility of an @Require?
Hi all, Let me just go with an example right off the bat. Let's say I have the following: === Pseudocode === SuperCssResource: This is injected onModuleLoad before anything else .genButton{ color: black; } Widget1 consists of: --- css --- MyCssResource: .myButton{ color: red; } --- html --- button class=genButton myButton / Widget2 consists of: --- css --- XCssResource extends SuperCssResource: ... rules that use classes from SuperCssResource --- html --- ...elements My problem is that if I display Widget1 first and then display Widget2 then the button in Widget1 will have a color of black instead of red. I know that this is expected behavior (GWT will merge the stylesheets together) since inheritance is basically the cssresource equivalent of CSS @import http://www.w3.org/TR/css3-cascade/#at-import but I thought since this was GWT maybe there was a way to use inheritance in the sense that the inherited stylesheet would only be injected if not injected already. Is this currently possible? or could it be done with like a @Require annotation on the extending interface which would indicate that merging of the super stylesheet should not be done but rather a check would be made to see if it already exists and if not to inject it. This would easily resolve the specificity overriding issue in the example when it's not the desired behavior. I know I could also get around this by importing with a prefix, however I still don't like the idea of essentially reinjecting the same styles. Any thoughts? Much thanks in advance. -- You received this message because you are subscribed to the Google Groups Google Web Toolkit group. To unsubscribe from this group and stop receiving emails from it, send an email to google-web-toolkit+unsubscr...@googlegroups.com. To post to this group, send email to google-web-toolkit@googlegroups.com. Visit this group at http://groups.google.com/group/google-web-toolkit. For more options, visit https://groups.google.com/groups/opt_out.