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

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