You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

DynamicallyInjectingCSS.asciidoc 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. ---
  2. title: Dynamically Injecting CSS
  3. order: 54
  4. layout: page
  5. ---
  6. [[dynamically-injecting-css]]
  7. = Dynamically injecting CSS
  8. In most cases you will style your components using SASS or CSS and
  9. create a theme for the application which you include with the `@Theme`
  10. annotation. This is always the preferred way of theming your
  11. application. But in some cases this is not enough. Sometimes you will
  12. want your user to be able to change some property on-the-fly without
  13. providing pre-made class names. To do this you can use CSS style
  14. injection. In this example I am going to show you how you can use CSS
  15. injection to create an editor which you can use to modify text visually
  16. with, a WYSIWYG of sorts. Here is an image of the final component I am
  17. going to create:
  18. image:img/theme-editor.png[Theme editor]
  19. First lets start by defining the UI of the editor component, it looks
  20. like this:
  21. [source,java]
  22. ....
  23. private Component createEditor(String text) {
  24. Panel editor = new Panel("Text Editor");
  25. editor.setWidth("580px");
  26. VerticalLayout panelContent = new VerticalLayout();
  27. panelContent.setSpacing(true);
  28. panelContent.setMargin(new MarginInfo(true, false, false, false));
  29. editor.setContent(panelContent);
  30. // Create the toolbar
  31. HorizontalLayout toolbar = new HorizontalLayout();
  32. toolbar.setSpacing(true);
  33. toolbar.setMargin(new MarginInfo(false, false, false, true));
  34. // Create the font family selector
  35. toolbar.addComponent(createFontSelect());
  36. // Create the font size selector
  37. toolbar.addComponent(createFontSizeSelect());
  38. // Create the text color selector
  39. toolbar.addComponent(createTextColorSelect());
  40. // Create the background color selector
  41. toolbar.addComponent(createBackgroundColorSelect());
  42. panelContent.addComponent(toolbar);
  43. panelContent.setComponentAlignment(toolbar, Alignment.MIDDLE_LEFT);
  44. // Spacer between toolbar and text
  45. panelContent.addComponent(new Label("<hr />", ContentMode.HTML));
  46. // The text to edit
  47. TextArea textLabel = new TextArea(null, text);
  48. textLabel.setWidth("100%");
  49. textLabel.setHeight("200px");
  50. // IMPORTANT: We are here setting the style name of the label, we are going to use this in our injected styles to target the label
  51. textLabel.setStyleName("text-label");
  52. panelContent.addComponent(textLabel);
  53. return editor;
  54. }
  55. ....
  56. Basically the editor component is a Panel with a text area and some
  57. buttons which you can use to modify the text area text with. The
  58. important thing here is that we give the text area a style name
  59. "text-label". With this style name we will be able to inject CSS styles
  60. targeted at that text area and modify colors and fonts of it. Lets next
  61. take a look at how the controls in the toolbar is implemented. They are
  62. all pretty similar but lets first take a look at how the Font selector
  63. was made:
  64. [source,java]
  65. ....
  66. private Component createFontSelect() {
  67. final ComboBox select = new ComboBox(null,
  68. Arrays.asList("Arial", "Helvetica", "Verdana", "Courier", "Times", "sans-serif"));
  69. select.setValue("Arial");
  70. select.setWidth("200px");
  71. select.setInputPrompt("Font");
  72. select.setDescription("Font");
  73. select.setImmediate(true);
  74. select.setNullSelectionAllowed(false);
  75. select.setNewItemsAllowed(false);
  76. select.addValueChangeListener(new ValueChangeListener() {
  77. @Override
  78. public void valueChange( ValueChangeEvent event ) {
  79. // Get the new font family
  80. String fontFamily = select.getValue().toString();
  81. // Get the stylesheet of the page
  82. Styles styles = Page.getCurrent().getStyles();
  83. // inject the new font size as a style. We need .v-app to override Vaadin's default styles here
  84. styles.add(".v-app .v-textarea.text-label { font-family:" + fontFamily + "; }");
  85. }
  86. });
  87. return select;
  88. }
  89. ....
  90. The important part here is what is inside the `ValueChangeListener`. Once
  91. we get the value from the ComboBox we are ready to inject it to the page
  92. so the user can visually see what have changed. To do this we fetch the
  93. StyleSheet for the current Page by calling `Page.getCurrent()`. Once we
  94. have the current Page we can get its StyleSheet by calling
  95. `Page.getstyleSheet()`. Once we got the StyleSheet we are free to inject
  96. any CSS string into the page by using `StyleSheet.inject(String css)`. As
  97. you see here we use the style name we gave to the TextArea as the
  98. selector and apply the font-family attribute to change the font family
  99. to the one the user has selected. For the sake of clarity, lets look at
  100. how another one, the text color selector, was implemented:
  101. [source,java]
  102. ....
  103. private Component createTextColorSelect( ) {
  104. // Colorpicker for changing text color
  105. ColorPicker textColor = new ColorPicker("Color", Color.BLACK);
  106. textColor.setWidth("110px");
  107. textColor.setCaption("Color");
  108. textColor.addColorChangeListener(new ColorChangeListener() {
  109. @Override
  110. public void colorChanged( ColorChangeEvent event ) {
  111. // Get the new text color
  112. Color color = event.getColor();
  113. // Get the stylesheet of the page
  114. Styles styles = Page.getCurrent().getStyles();
  115. // inject the new color as a style
  116. styles.add(".v-app .v-textarea.text-label { color:" + color.getCSS() + "; }");
  117. }
  118. });
  119. return textColor;
  120. }
  121. ....
  122. Again, the important part in this method is in the `ColorChangeListener`.
  123. Basically here we do the exactly same thing as we did with the font
  124. family except here we are dealing with a color. To change the color of
  125. the text we just simply apply the 'color' attribute for text area. The
  126. `ColorPicker.Color` even provides us with a convenient method of directly
  127. converting the received Color object into a CSS color. And finally, for
  128. completeness, here is the full example code which will produce the demo
  129. application in the picture above for you to try out:
  130. [source,java]
  131. ....
  132. /**
  133. * Imports and package definition omitted
  134. */
  135. public class CSSInjectWithColorpicker extends UI {
  136. @Override
  137. protected void init( VaadinRequest request ) { // Create a text editor
  138. Component editor =
  139. createEditor("Lorem ipsum dolor sit amet, lacus pharetra sed, sit a "
  140. + "tortor. Id aliquam lorem pede, orci ut enim metus, diam nulla mi "
  141. + "suspendisse tempor tortor. Eleifend lorem proin, morbi vel diam ut. "
  142. + "Tempor est tellus vitae, pretium condimentum facilisis sit. Sagittis "
  143. + "quam, ac urna eros est cras id cras, eleifend eu mattis nec."
  144. + "Lorem ipsum dolor sit amet, lacus pharetra sed, sit a "
  145. + "tortor. Id aliquam lorem pede, orci ut enim metus, diam nulla mi "
  146. + "suspendisse tempor tortor. Eleifend lorem proin, morbi vel diam ut. "
  147. + "Tempor est tellus vitae, pretium condimentum facilisis sit. Sagittis "
  148. + "quam, ac urna eros est cras id cras, eleifend eu mattis nec."
  149. + "Lorem ipsum dolor sit amet, lacus pharetra sed, sit a "
  150. + "tortor. Id aliquam lorem pede, orci ut enim metus, diam nulla mi "
  151. + "suspendisse tempor tortor. Eleifend lorem proin, morbi vel diam ut. "
  152. + "Tempor est tellus vitae, pretium condimentum facilisis sit. Sagittis "
  153. + "quam, ac urna eros est cras id cras, eleifend eu mattis nec."
  154. + "Lorem ipsum dolor sit amet, lacus pharetra sed, sit a "
  155. + "tortor. Id aliquam lorem pede, orci ut enim metus, diam nulla mi "
  156. + "suspendisse tempor tortor. Eleifend lorem proin, morbi vel diam ut. "
  157. + "Tempor est tellus vitae, pretium condimentum facilisis sit. Sagittis "
  158. + "quam, ac urna eros est cras id cras, eleifend eu mattis nec.");
  159. VerticalLayout content = new VerticalLayout(editor);
  160. content.setMargin(true);
  161. setContent(content);
  162. }
  163. /**
  164. * Creates a text editor for visually editing text
  165. *
  166. * @param text The text editor
  167. * @return
  168. */
  169. private Component createEditor( String text ) {
  170. Panel editor = new Panel("Text Editor");
  171. editor.setWidth("580px");
  172. VerticalLayout panelContent = new VerticalLayout();
  173. panelContent.setSpacing(true);
  174. panelContent.setMargin(new MarginInfo(true, false, false, false));
  175. editor.setContent(panelContent);
  176. // Create the toolbar
  177. HorizontalLayout toolbar = new HorizontalLayout();
  178. toolbar.setSpacing(true);
  179. toolbar.setMargin(new MarginInfo(false, false, false, true));
  180. // Create the font family selector
  181. toolbar.addComponent(createFontSelect());
  182. // Create the font size selector
  183. toolbar.addComponent(createFontSizeSelect());
  184. // Create the text color selector
  185. toolbar.addComponent(createTextColorSelect());
  186. // Create the background color selector
  187. toolbar.addComponent(createBackgroundColorSelect());
  188. panelContent.addComponent(toolbar);
  189. panelContent.setComponentAlignment(toolbar, Alignment.MIDDLE_LEFT);
  190. // Spacer between toolbar and text
  191. panelContent.addComponent(new Label("<hr />", ContentMode.HTML));
  192. // The text to edit
  193. TextArea textLabel = new TextArea(null, text);
  194. textLabel.setWidth("100%");
  195. textLabel.setHeight("200px");
  196. // IMPORTANT: We are here setting the style name of the label, we are going to use this in our injected styles to
  197. // target the label
  198. textLabel.setStyleName("text-label");
  199. panelContent.addComponent(textLabel);
  200. return editor;
  201. }
  202. /**
  203. * Creates a background color select dialog
  204. */
  205. private Component createBackgroundColorSelect( ) {
  206. ColorPicker bgColor = new ColorPicker("Background", Color.WHITE);
  207. bgColor.setWidth("110px");
  208. bgColor.setCaption("Background");
  209. bgColor.addColorChangeListener(new ColorChangeListener() {
  210. @Override
  211. public void colorChanged( ColorChangeEvent event ) {
  212. // Get the new background color
  213. Color color = event.getColor();
  214. // Get the stylesheet of the page
  215. Styles styles = Page.getCurrent().getStyles();
  216. // inject the new background color
  217. styles.add(".v-app .v-textarea.text-label { background-color:" + color.getCSS() + "; }");
  218. }
  219. });
  220. return bgColor;
  221. }
  222. /**
  223. * Create a text color selection dialog
  224. */
  225. private Component createTextColorSelect( ) {
  226. // Colorpicker for changing text color
  227. ColorPicker textColor = new ColorPicker("Color", Color.BLACK);
  228. textColor.setWidth("110px");
  229. textColor.setCaption("Color");
  230. textColor.addColorChangeListener(new ColorChangeListener() {
  231. @Override
  232. public void colorChanged( ColorChangeEvent event ) {
  233. // Get the new text color
  234. Color color = event.getColor();
  235. // Get the stylesheet of the page
  236. Styles styles = Page.getCurrent().getStyles();
  237. // inject the new color as a style
  238. styles.add(".v-app .v-textarea.text-label { color:" + color.getCSS() + "; }");
  239. }
  240. });
  241. return textColor;
  242. }
  243. /**
  244. * Creates a font family selection dialog
  245. */
  246. private Component createFontSelect( ) {
  247. final ComboBox select =
  248. new ComboBox(null, Arrays.asList("Arial", "Helvetica", "Verdana", "Courier", "Times", "sans-serif"));
  249. select.setValue("Arial");
  250. select.setWidth("200px");
  251. select.setInputPrompt("Font");
  252. select.setDescription("Font");
  253. select.setImmediate(true);
  254. select.setNullSelectionAllowed(false);
  255. select.setNewItemsAllowed(false);
  256. select.addValueChangeListener(new ValueChangeListener() {
  257. @Override
  258. public void valueChange( ValueChangeEvent event ) {
  259. // Get the new font family
  260. String fontFamily = select.getValue().toString();
  261. // Get the stylesheet of the page
  262. Styles styles = Page.getCurrent().getStyles();
  263. // inject the new font size as a style. We need .v-app to override Vaadin's default styles here
  264. styles.add(".v-app .v-textarea.text-label { font-family:" + fontFamily + "; }");
  265. }
  266. });
  267. return select;
  268. }
  269. /**
  270. * Creates a font size selection control
  271. */
  272. private Component createFontSizeSelect( ) {
  273. final ComboBox select = new ComboBox(null, Arrays.asList(8, 9, 10, 12, 14, 16, 20, 25, 30, 40, 50));
  274. select.setWidth("100px");
  275. select.setValue(12);
  276. select.setInputPrompt("Font size");
  277. select.setDescription("Font size");
  278. select.setImmediate(true);
  279. select.setNullSelectionAllowed(false);
  280. select.setNewItemsAllowed(false);
  281. select.addValueChangeListener(new ValueChangeListener() {
  282. @Override
  283. public void valueChange( ValueChangeEvent event ) {
  284. // Get the new font size
  285. Integer fontSize = (Integer) select.getValue();
  286. // Get the stylesheet of the page
  287. Styles styles = Page.getCurrent().getStyles();
  288. // inject the new font size as a style. We need .v-app to override Vaadin's default styles here
  289. styles.add(".v-app .v-textarea.text-label { font-size:" + String.valueOf(fontSize) + "px; }");
  290. }
  291. });
  292. return select;
  293. }
  294. }
  295. ....