├── .gitignore
├── README.md
├── UNLICENSE
├── mockapp-backend
├── pom.xml
└── src
│ ├── main
│ └── java
│ │ └── org
│ │ └── vaadin
│ │ └── mockapp
│ │ └── samples
│ │ └── backend
│ │ ├── DataService.java
│ │ ├── data
│ │ ├── Availability.java
│ │ ├── Category.java
│ │ └── Product.java
│ │ └── mock
│ │ ├── MockDataGenerator.java
│ │ └── MockDataService.java
│ └── test
│ └── java
│ └── org
│ └── vaadin
│ └── mockapp
│ └── samples
│ └── backend
│ └── DataServiceTest.java
├── mockapp-production
├── pom.xml
└── src
│ └── main
│ └── webapp
│ └── WEB-INF
│ └── web.xml
├── mockapp-ui
├── pom.xml
└── src
│ └── main
│ ├── java
│ └── org
│ │ └── vaadin
│ │ └── mockapp
│ │ ├── MockAppUI.java
│ │ └── samples
│ │ ├── ErrorView.java
│ │ ├── MainScreen.java
│ │ ├── Menu.java
│ │ ├── about
│ │ └── AboutView.java
│ │ ├── authentication
│ │ ├── AccessControl.java
│ │ ├── BasicAccessControl.java
│ │ ├── CurrentUser.java
│ │ └── LoginScreen.java
│ │ └── crud
│ │ ├── CategoryField.java
│ │ ├── CollectionToStringConverter.java
│ │ ├── EuroConverter.java
│ │ ├── NumberField.java
│ │ ├── ProductForm.java
│ │ ├── ProductFormDesign.java
│ │ ├── ProductGrid.java
│ │ ├── SampleCrudLogic.java
│ │ └── SampleCrudView.java
│ ├── resources
│ └── org
│ │ └── vaadin
│ │ └── mockapp
│ │ └── samples
│ │ └── crud
│ │ └── ProductFormDesign.html
│ └── webapp
│ └── VAADIN
│ └── themes
│ └── mockapp
│ ├── addons.scss
│ ├── favicon.ico
│ ├── img
│ ├── archetype-login-bg.jpg
│ └── table-logo.png
│ ├── layouts
│ └── aboutview.html
│ ├── mockapp.scss
│ └── styles.scss
├── mockapp-widgetset
├── pom.xml
└── src
│ └── main
│ ├── java
│ └── org
│ │ └── vaadin
│ │ └── mockapp
│ │ ├── client
│ │ └── samples
│ │ │ └── ResetButtonForTextFieldConnector.java
│ │ └── samples
│ │ ├── AttributeExtension.java
│ │ ├── AttributeExtensionState.java
│ │ └── ResetButtonForTextField.java
│ └── resources
│ └── org
│ └── vaadin
│ └── mockapp
│ ├── MockAppWidgetset.gwt.xml
│ ├── public
│ └── resetbuttonfortextfield
│ │ ├── resetbutton-default.png
│ │ ├── resetbutton-default.svg
│ │ ├── resetbutton-hover.png
│ │ ├── resetbutton-hover.svg
│ │ └── styles.css
│ └── samples
│ └── attribute_extension_connector.js
└── pom.xml
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .idea/
3 | *.iml
4 | target/
5 | mockapp/overlays/
6 | mockapp-server/src/main/webapp/VAADIN/themes/mockapp/styles.css
7 | .settings/
8 | */.settings/
9 | .classpath
10 | */.classpath
11 | .project
12 | */.project
13 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | mockapp
2 | ==============
3 |
4 | Template for a full-blown Vaadin application that only requires a Servlet 3.0 container to run (no other JEE dependencies).
5 |
6 |
7 | Project Structure
8 | =================
9 |
10 | The project consists of the following three modules:
11 |
12 | - parent project: common metadata and configuration
13 | - mockapp-widgetset: widgetset, custom client side code and dependencies to widget add-ons
14 | - mockapp-ui: main application module, development time
15 | - mockapp-production: module that produces a production mode WAR for deployment
16 |
17 | The production mode module recompiles the widgetset (obfuscated, not draft), activates production mode for Vaadin with a context parameter in web.xml and contains a precompiled theme. The ui module WAR contains an unobfuscated widgetset, and is meant to be used at development time only.
18 |
19 | Workflow
20 | ========
21 |
22 | To compile the entire project, run "mvn install" in the parent project.
23 |
24 | Other basic workflow steps:
25 |
26 | - getting started
27 | - compiling the whole project
28 | - run "mvn install" in parent project
29 | - developing the application
30 | - edit code in the ui module
31 | - run "mvn jetty:run" in ui module
32 | - open http://localhost:8080/
33 | - developing the theme
34 | - run the application as above
35 | - edit the theme in the ui module
36 | - optional: see below for precompiling the theme
37 | - reload the application page
38 | - client side changes or add-ons
39 | - edit code/POM in widgetset module
40 | - run "mvn install" in widgetset module
41 | - if a new add-on has an embedded theme, run "mvn vaadin:update-theme" in the ui module
42 | - debugging client side code
43 | - run "mvn vaadin:run-codeserver" in widgetset module
44 | - activate Super Dev Mode in the debug window of the application
45 | - creating a production mode war
46 | - run "mvn -Pproduction package" in the production mode module or in the parent module
47 | - testing the production mode war
48 | - run "mvn -Pproduction jetty:run-war" in the production mode module
49 |
50 |
51 | Using a precompiled theme
52 | -------------------------
53 |
54 | When developing the UI module, Vaadin can compile the theme on the fly on every
55 | application reload, or the theme can be precompiled to speed up page loads.
56 |
57 | To precompile the theme run "mvn vaadin:compile-theme" in the ui module. Note, though,
58 | that once the theme has been precompiled, any theme changes will not be visible until
59 | the next theme compilation or running the "mvn clean" target.
60 |
61 | When developing the theme, running the application in the "run" mode (rather than
62 | in "debug") in the IDE can speed up consecutive on-the-fly theme compilations
63 | significantly.
64 |
65 | The production module always automatically precompiles the theme for the production WAR.
66 |
--------------------------------------------------------------------------------
/UNLICENSE:
--------------------------------------------------------------------------------
1 | This is free and unencumbered software released into the public domain.
2 |
3 | Anyone is free to copy, modify, publish, use, compile, sell, or
4 | distribute this software, either in source code form or as a compiled
5 | binary, for any purpose, commercial or non-commercial, and by any
6 | means.
7 |
8 | In jurisdictions that recognize copyright laws, the author or authors
9 | of this software dedicate any and all copyright interest in the
10 | software to the public domain. We make this dedication for the benefit
11 | of the public at large and to the detriment of our heirs and
12 | successors. We intend this dedication to be an overt act of
13 | relinquishment in perpetuity of all present and future rights to this
14 | software under copyright law.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 | OTHER DEALINGS IN THE SOFTWARE.
23 |
24 | For more information, please refer to
25 |
--------------------------------------------------------------------------------
/mockapp-backend/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | mockapp-parent
6 | org.vaadin.maven.mockapp
7 | 1.0-SNAPSHOT
8 |
9 | 4.0.0
10 |
11 | mockapp-backend
12 | mockapp-backend
13 | jar
14 |
15 |
16 |
17 | javax.validation
18 | validation-api
19 | 1.1.0.Final
20 |
21 |
22 |
23 |
24 | junit
25 | junit
26 | 4.11
27 | test
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/mockapp-backend/src/main/java/org/vaadin/mockapp/samples/backend/DataService.java:
--------------------------------------------------------------------------------
1 | package org.vaadin.mockapp.samples.backend;
2 |
3 | import java.util.Collection;
4 |
5 | import org.vaadin.mockapp.samples.backend.data.Category;
6 | import org.vaadin.mockapp.samples.backend.data.Product;
7 | import org.vaadin.mockapp.samples.backend.mock.MockDataService;
8 |
9 | /**
10 | * Back-end service interface for retrieving and updating product data.
11 | */
12 | public abstract class DataService {
13 |
14 | public abstract Collection getAllProducts();
15 |
16 | public abstract Collection getAllCategories();
17 |
18 | public abstract void updateProduct(Product p);
19 |
20 | public abstract void deleteProduct(int productId);
21 |
22 | public abstract Product getProductById(int productId);
23 |
24 | public static DataService get() {
25 | return MockDataService.getInstance();
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/mockapp-backend/src/main/java/org/vaadin/mockapp/samples/backend/data/Availability.java:
--------------------------------------------------------------------------------
1 | package org.vaadin.mockapp.samples.backend.data;
2 |
3 | public enum Availability {
4 | COMING("Coming"), AVAILABLE("Available"), DISCONTINUED("Discontinued");
5 |
6 | private final String name;
7 |
8 | private Availability(String name) {
9 | this.name = name;
10 | }
11 |
12 | @Override
13 | public String toString() {
14 | return name;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/mockapp-backend/src/main/java/org/vaadin/mockapp/samples/backend/data/Category.java:
--------------------------------------------------------------------------------
1 | package org.vaadin.mockapp.samples.backend.data;
2 |
3 | import java.io.Serializable;
4 |
5 | import javax.validation.constraints.NotNull;
6 |
7 | public class Category implements Serializable {
8 |
9 | @NotNull
10 | private int id;
11 | @NotNull
12 | private String name;
13 |
14 | public int getId() {
15 | return id;
16 | }
17 |
18 | public void setId(int id) {
19 | this.id = id;
20 | }
21 |
22 | public String getName() {
23 | return name;
24 | }
25 |
26 | public void setName(String name) {
27 | this.name = name;
28 | }
29 |
30 | @Override
31 | public String toString() {
32 | return getName();
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/mockapp-backend/src/main/java/org/vaadin/mockapp/samples/backend/data/Product.java:
--------------------------------------------------------------------------------
1 | package org.vaadin.mockapp.samples.backend.data;
2 |
3 | import java.io.Serializable;
4 | import java.math.BigDecimal;
5 | import java.util.Set;
6 |
7 | import javax.validation.constraints.Min;
8 | import javax.validation.constraints.NotNull;
9 | import javax.validation.constraints.Size;
10 |
11 | public class Product implements Serializable {
12 |
13 | @NotNull
14 | private int id = -1;
15 | @NotNull
16 | @Size(min = 2, message = "Product name must have at least two characters")
17 | private String productName = "";
18 | @Min(0)
19 | private BigDecimal price = BigDecimal.ZERO;
20 | private Set category;
21 | @Min(value = 0, message = "Can't have negative amount in stock")
22 | private int stockCount = 0;
23 | @NotNull
24 | private Availability availability = Availability.COMING;
25 |
26 | public int getId() {
27 | return id;
28 | }
29 |
30 | public void setId(int id) {
31 | this.id = id;
32 | }
33 |
34 | public String getProductName() {
35 | return productName;
36 | }
37 |
38 | public void setProductName(String productName) {
39 | this.productName = productName;
40 | }
41 |
42 | public BigDecimal getPrice() {
43 | return price;
44 | }
45 |
46 | public void setPrice(BigDecimal price) {
47 | this.price = price;
48 | }
49 |
50 | public Set getCategory() {
51 | return category;
52 | }
53 |
54 | public void setCategory(Set category) {
55 | this.category = category;
56 | }
57 |
58 | public int getStockCount() {
59 | return stockCount;
60 | }
61 |
62 | public void setStockCount(int stockCount) {
63 | this.stockCount = stockCount;
64 | }
65 |
66 | public Availability getAvailability() {
67 | return availability;
68 | }
69 |
70 | public void setAvailability(Availability availability) {
71 | this.availability = availability;
72 | }
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/mockapp-backend/src/main/java/org/vaadin/mockapp/samples/backend/mock/MockDataGenerator.java:
--------------------------------------------------------------------------------
1 | package org.vaadin.mockapp.samples.backend.mock;
2 |
3 | import java.math.BigDecimal;
4 | import java.util.ArrayList;
5 | import java.util.HashSet;
6 | import java.util.List;
7 | import java.util.Random;
8 | import java.util.Set;
9 |
10 | import org.vaadin.mockapp.samples.backend.data.Availability;
11 | import org.vaadin.mockapp.samples.backend.data.Category;
12 | import org.vaadin.mockapp.samples.backend.data.Product;
13 |
14 | public class MockDataGenerator {
15 | private static int nextCategoryId = 1;
16 | private static int nextProductId = 1;
17 | private static final Random random = new Random(1);
18 | private static final String categoryNames[] = new String[] {
19 | "Children's books", "Best sellers", "Romance", "Mystery",
20 | "Thriller", "Sci-fi", "Non-fiction", "Cookbooks" };
21 |
22 | private static String[] word1 = new String[] { "The art of", "Mastering",
23 | "The secrets of", "Avoiding", "For fun and profit: ",
24 | "How to fail at", "10 important facts about",
25 | "The ultimate guide to", "Book of", "Surviving", "Encyclopedia of",
26 | "Very much", "Learning the basics of", "The cheap way to",
27 | "Being awesome at", "The life changer:", "The Vaadin way:",
28 | "Becoming one with", "Beginners guide to",
29 | "The complete visual guide to", "The mother of all references:" };
30 |
31 | private static String[] word2 = new String[] { "gardening",
32 | "living a healthy life", "designing tree houses", "home security",
33 | "intergalaxy travel", "meditation", "ice hockey",
34 | "children's education", "computer programming", "Vaadin TreeTable",
35 | "winter bathing", "playing the cello", "dummies", "rubber bands",
36 | "feeling down", "debugging", "running barefoot",
37 | "speaking to a big audience", "creating software", "giant needles",
38 | "elephants", "keeping your wife happy" };
39 |
40 | static List createCategories() {
41 | List categories = new ArrayList();
42 | for (String name : categoryNames) {
43 | Category c = createCategory(name);
44 | categories.add(c);
45 | }
46 | return categories;
47 |
48 | }
49 |
50 | static List createProducts(List categories) {
51 | List products = new ArrayList();
52 | for (int i = 0; i < 100; i++) {
53 | Product p = createProduct(categories);
54 | products.add(p);
55 | }
56 |
57 | return products;
58 | }
59 |
60 | private static Category createCategory(String name) {
61 | Category c = new Category();
62 | c.setId(nextCategoryId++);
63 | c.setName(name);
64 | return c;
65 | }
66 |
67 | private static Product createProduct(List categories) {
68 | Product p = new Product();
69 | p.setId(nextProductId++);
70 | p.setProductName(generateName());
71 |
72 | p.setPrice(new BigDecimal((random.nextInt(250) + 50) / 10.0));
73 | p.setAvailability(Availability.values()[random.nextInt(Availability
74 | .values().length)]);
75 | if (p.getAvailability() == Availability.AVAILABLE) {
76 | p.setStockCount(random.nextInt(523));
77 | }
78 |
79 | p.setCategory(getCategory(categories, 1, 2));
80 | return p;
81 | }
82 |
83 | private static Set getCategory(List categories,
84 | int min, int max) {
85 | int nr = random.nextInt(max) + min;
86 | HashSet productCategories = new HashSet();
87 | for (int i = 0; i < nr; i++) {
88 | productCategories.add(categories.get(random.nextInt(categories
89 | .size())));
90 | }
91 |
92 | return productCategories;
93 | }
94 |
95 | private static String generateName() {
96 | return word1[random.nextInt(word1.length)] + " "
97 | + word2[random.nextInt(word2.length)];
98 | }
99 |
100 | }
101 |
--------------------------------------------------------------------------------
/mockapp-backend/src/main/java/org/vaadin/mockapp/samples/backend/mock/MockDataService.java:
--------------------------------------------------------------------------------
1 | package org.vaadin.mockapp.samples.backend.mock;
2 |
3 | import java.util.List;
4 |
5 | import org.vaadin.mockapp.samples.backend.DataService;
6 | import org.vaadin.mockapp.samples.backend.data.Category;
7 | import org.vaadin.mockapp.samples.backend.data.Product;
8 |
9 | /**
10 | * Mock data model. This implementation has very simplistic locking and does not
11 | * notify users of modifications.
12 | */
13 | public class MockDataService extends DataService {
14 |
15 | private static MockDataService INSTANCE;
16 |
17 | private List products;
18 | private List categories;
19 | private int nextProductId = 0;
20 |
21 | private MockDataService() {
22 | categories = MockDataGenerator.createCategories();
23 | products = MockDataGenerator.createProducts(categories);
24 | nextProductId = products.size() + 1;
25 | }
26 |
27 | public synchronized static DataService getInstance() {
28 | if (INSTANCE == null) {
29 | INSTANCE = new MockDataService();
30 | }
31 | return INSTANCE;
32 | }
33 |
34 | @Override
35 | public synchronized List getAllProducts() {
36 | return products;
37 | }
38 |
39 | @Override
40 | public synchronized List getAllCategories() {
41 | return categories;
42 | }
43 |
44 | @Override
45 | public synchronized void updateProduct(Product p) {
46 | if (p.getId() < 0) {
47 | // New product
48 | p.setId(nextProductId++);
49 | products.add(p);
50 | return;
51 | }
52 | for (int i = 0; i < products.size(); i++) {
53 | if (products.get(i).getId() == p.getId()) {
54 | products.set(i, p);
55 | return;
56 | }
57 | }
58 |
59 | throw new IllegalArgumentException("No product with id " + p.getId()
60 | + " found");
61 | }
62 |
63 | @Override
64 | public synchronized Product getProductById(int productId) {
65 | for (int i = 0; i < products.size(); i++) {
66 | if (products.get(i).getId() == productId) {
67 | return products.get(i);
68 | }
69 | }
70 | return null;
71 | }
72 |
73 | @Override
74 | public synchronized void deleteProduct(int productId) {
75 | Product p = getProductById(productId);
76 | if (p == null) {
77 | throw new IllegalArgumentException("Product with id " + productId
78 | + " not found");
79 | }
80 | products.remove(p);
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/mockapp-backend/src/test/java/org/vaadin/mockapp/samples/backend/DataServiceTest.java:
--------------------------------------------------------------------------------
1 | package org.vaadin.mockapp.samples.backend;
2 |
3 | import org.junit.Before;
4 | import org.junit.Test;
5 | import org.vaadin.mockapp.samples.backend.data.Product;
6 | import org.vaadin.mockapp.samples.backend.mock.MockDataService;
7 |
8 | import static org.junit.Assert.assertEquals;
9 | import static org.junit.Assert.assertFalse;
10 |
11 | /**
12 | * Simple unit test for the back-end data service.
13 | */
14 | public class DataServiceTest {
15 |
16 | private DataService service;
17 |
18 | @Before
19 | public void setUp() throws Exception {
20 | service = MockDataService.getInstance();
21 | }
22 |
23 | @Test
24 | public void testDataServiceCanFetchProducts() throws Exception {
25 | assertFalse(service.getAllProducts().isEmpty());
26 | }
27 |
28 | @Test
29 | public void testDataServiceCanFetchCategories() throws Exception {
30 | assertFalse(service.getAllCategories().isEmpty());
31 | }
32 |
33 | @Test
34 | public void testUpdateProduct_updatesTheProduct() throws Exception {
35 | Product p = service.getAllProducts().iterator().next();
36 | p.setProductName("My Test Name");
37 | service.updateProduct(p);
38 | Product p2 = service.getAllProducts().iterator().next();
39 | assertEquals("My Test Name", p2.getProductName());
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/mockapp-production/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | mockapp-parent
6 | org.vaadin.maven.mockapp
7 | 1.0-SNAPSHOT
8 |
9 | 4.0.0
10 |
11 | mockapp-production
12 | mockapp-production
13 | war
14 |
15 |
16 | ${project.build.directory}/${project.build.finalName}
17 |
18 |
19 |
20 |
21 |
22 | ${project.groupId}
23 | mockapp-ui
24 | ${project.version}
25 | war
26 | runtime
27 |
28 |
30 |
31 | ${project.groupId}
32 | mockapp-ui
33 | ${project.version}
34 | classes
35 | provided
36 |
37 |
38 | ${project.groupId}
39 | mockapp-widgetset
40 | ${project.version}
41 | sources
42 | provided
43 |
44 |
45 |
46 |
47 |
48 | production
49 |
50 |
51 |
53 |
54 | org.apache.maven.plugins
55 | maven-dependency-plugin
56 | 2.9
57 |
58 |
59 | unpack
60 | generate-resources
61 |
62 | unpack
63 |
64 |
65 |
66 |
67 | ${project.groupId}
68 | mockapp-ui
69 | ${project.version}
70 | war
71 | VAADIN/themes/**/*
72 |
74 | VAADIN/themes/**/styles.css
75 | ${vaadin.resource.directory}
76 |
77 |
78 | ${project.groupId}
79 | mockapp-widgetset
80 | ${project.version}
81 | jar
82 | org/vaadin/mockapp/**
83 |
85 | ${vaadin.resource.directory}/WEB-INF/classes
86 |
87 |
88 | true
89 |
90 |
91 |
92 |
93 |
94 | net.alchim31.maven
95 | yuicompressor-maven-plugin
96 | 1.5.1
97 |
98 | true
99 | ${vaadin.resource.directory}
100 |
101 |
102 |
103 |
104 | compress
105 |
106 |
107 |
108 |
109 |
110 | com.vaadin
111 | vaadin-maven-plugin
112 |
113 | org.vaadin.mockapp.MockAppWidgetset
114 | -Xmx512M -Xss1024k
115 | ${vaadin.resource.directory}
116 | ${vaadin.resource.directory}/VAADIN/widgetsets
117 | false
118 | false
119 |
120 | true
121 | mockapp
122 |
123 |
124 |
125 |
126 | compile
127 | compile-theme
128 |
129 |
130 |
131 |
132 |
133 | org.apache.maven.plugins
134 | maven-war-plugin
135 |
136 |
137 | default-war
138 | package
139 |
140 |
141 |
142 |
143 |
144 | ${project.groupId}
145 | mockapp-ui
146 |
147 |
149 |
151 | WEB-INF/lib/mockapp-widgetset-*.jar
152 |
154 |
156 | WEB-INF/lib/vaadin-sass-compiler-*.jar
157 | WEB-INF/lib/sac-*.jar
158 | WEB-INF/lib/flute-*.jar
159 |
160 |
161 |
162 |
164 | VAADIN/gwt-unitCache/**,VAADIN/widgetsets/WEB-INF/**
165 |
166 |
167 |
168 |
169 | org.apache.maven.plugins
170 | maven-install-plugin
171 | 2.4
172 |
173 |
174 | default-install
175 | install
176 |
177 |
178 |
179 |
181 |
182 | org.eclipse.jetty
183 | jetty-maven-plugin
184 | ${jetty.plugin.version}
185 |
186 | ${vaadin.resource.directory}
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
198 |
199 | org.apache.maven.plugins
200 | maven-war-plugin
201 |
202 |
203 | default-war
204 | none
205 |
206 |
207 |
208 |
209 | org.apache.maven.plugins
210 | maven-install-plugin
211 | 2.4
212 |
213 |
214 | default-install
215 | none
216 |
217 |
218 |
219 |
220 |
221 |
222 |
224 |
226 |
227 | org.eclipse.m2e
228 | lifecycle-mapping
229 | 1.0.0
230 |
231 |
232 |
233 |
234 |
235 | com.vaadin
236 |
237 | vaadin-maven-plugin
238 |
239 |
240 | [7.1.11,)
241 |
242 |
243 | compile-theme
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 | org.apache.maven.plugins
254 |
255 |
256 | maven-dependency-plugin
257 |
258 |
259 | [2.9,)
260 |
261 |
262 | unpack
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
--------------------------------------------------------------------------------
/mockapp-production/src/main/webapp/WEB-INF/web.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | productionMode
5 | true
6 |
7 |
--------------------------------------------------------------------------------
/mockapp-ui/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | mockapp-parent
6 | org.vaadin.maven.mockapp
7 | 1.0-SNAPSHOT
8 |
9 | 4.0.0
10 |
11 | mockapp-ui
12 | mockapp-ui
13 | war
14 |
15 |
16 |
17 |
18 | javax.servlet
19 | javax.servlet-api
20 | provided
21 |
22 |
23 | com.vaadin
24 | vaadin-server
25 |
26 |
27 | com.vaadin
28 | vaadin-push
29 |
30 |
31 | com.vaadin
32 | vaadin-themes
33 |
34 |
35 |
36 | ${project.groupId}
37 | mockapp-backend
38 | ${project.version}
39 |
40 |
41 |
42 |
43 | ${project.groupId}
44 | mockapp-widgetset
45 | ${project.version}
46 |
47 |
48 |
49 |
50 | org.hibernate
51 | hibernate-validator
52 | 5.1.0.CR1
53 |
54 |
55 |
56 |
57 | junit
58 | junit
59 | 4.11
60 | test
61 |
62 |
63 |
64 |
65 |
66 |
67 | org.apache.maven.plugins
68 | maven-war-plugin
69 |
70 |
73 | true
74 |
76 | WEB-INF/classes/VAADIN/gwt-unitCache/**,
77 | WEB-INF/classes/VAADIN/widgetsets/WEB-INF/**
78 |
79 |
80 |
81 |
83 |
84 | org.eclipse.jetty
85 | jetty-maven-plugin
86 | ${jetty.plugin.version}
87 |
88 | 2
89 |
90 |
91 |
92 |
93 | org.apache.maven.plugins
94 | maven-failsafe-plugin
95 | 2.16
96 |
97 |
98 | default
99 |
100 | true
101 |
102 |
103 |
104 | integration-test
105 |
106 | integration-test
107 |
108 |
109 |
110 | verify
111 |
112 | verify
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
--------------------------------------------------------------------------------
/mockapp-ui/src/main/java/org/vaadin/mockapp/MockAppUI.java:
--------------------------------------------------------------------------------
1 | package org.vaadin.mockapp;
2 |
3 | import javax.servlet.annotation.WebServlet;
4 |
5 | import org.vaadin.mockapp.samples.MainScreen;
6 | import org.vaadin.mockapp.samples.authentication.AccessControl;
7 | import org.vaadin.mockapp.samples.authentication.BasicAccessControl;
8 | import org.vaadin.mockapp.samples.authentication.LoginScreen;
9 | import org.vaadin.mockapp.samples.authentication.LoginScreen.LoginListener;
10 |
11 | import com.vaadin.annotations.Theme;
12 | import com.vaadin.annotations.VaadinServletConfiguration;
13 | import com.vaadin.annotations.Viewport;
14 | import com.vaadin.annotations.Widgetset;
15 | import com.vaadin.server.Responsive;
16 | import com.vaadin.server.VaadinRequest;
17 | import com.vaadin.server.VaadinServlet;
18 | import com.vaadin.ui.UI;
19 | import com.vaadin.ui.themes.ValoTheme;
20 |
21 | /**
22 | * Main UI class of the application that shows either the login screen or the
23 | * main view of the application depending on whether a user is signed in.
24 | *
25 | * The @Viewport annotation configures the viewport meta tags appropriately on
26 | * mobile devices. Instead of device based scaling (default), using responsive
27 | * layouts.
28 | */
29 | @Viewport("user-scalable=no,initial-scale=1.0")
30 | @Theme("mockapp")
31 | @Widgetset("org.vaadin.mockapp.MockAppWidgetset")
32 | public class MockAppUI extends UI {
33 |
34 | private AccessControl accessControl = new BasicAccessControl();
35 |
36 | @Override
37 | protected void init(VaadinRequest vaadinRequest) {
38 | Responsive.makeResponsive(this);
39 | setLocale(vaadinRequest.getLocale());
40 | getPage().setTitle("MockApp");
41 | if (!accessControl.isUserSignedIn()) {
42 | setContent(new LoginScreen(accessControl, new LoginListener() {
43 | @Override
44 | public void loginSuccessful() {
45 | showMainView();
46 | }
47 | }));
48 | } else {
49 | showMainView();
50 | }
51 | }
52 |
53 | protected void showMainView() {
54 | addStyleName(ValoTheme.UI_WITH_MENU);
55 | setContent(new MainScreen(MockAppUI.this));
56 | getNavigator().navigateTo(getNavigator().getState());
57 | }
58 |
59 | public static MockAppUI get() {
60 | return (MockAppUI) UI.getCurrent();
61 | }
62 |
63 | public AccessControl getAccessControl() {
64 | return accessControl;
65 | }
66 |
67 | @WebServlet(urlPatterns = "/*", name = "MockAppUIServlet", asyncSupported = true)
68 | @VaadinServletConfiguration(ui = MockAppUI.class, productionMode = false)
69 | public static class MockAppUIServlet extends VaadinServlet {
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/mockapp-ui/src/main/java/org/vaadin/mockapp/samples/ErrorView.java:
--------------------------------------------------------------------------------
1 | package org.vaadin.mockapp.samples;
2 |
3 | import com.vaadin.navigator.View;
4 | import com.vaadin.navigator.ViewChangeListener;
5 | import com.vaadin.ui.Label;
6 | import com.vaadin.ui.VerticalLayout;
7 | import com.vaadin.ui.themes.Reindeer;
8 |
9 | /**
10 | * View shown when trying to navigate to a view that does not exist using
11 | * {@link com.vaadin.navigator.Navigator}.
12 | *
13 | *
14 | */
15 | public class ErrorView extends VerticalLayout implements View {
16 |
17 | private Label explanation;
18 |
19 | public ErrorView() {
20 | setMargin(true);
21 | setSpacing(true);
22 |
23 | Label header = new Label("The view could not be found");
24 | header.addStyleName(Reindeer.LABEL_H1);
25 | addComponent(header);
26 | addComponent(explanation = new Label());
27 | }
28 |
29 | @Override
30 | public void enter(ViewChangeListener.ViewChangeEvent event) {
31 | explanation.setValue(String.format(
32 | "You tried to navigate to a view ('%s') that does not exist.",
33 | event.getViewName()));
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/mockapp-ui/src/main/java/org/vaadin/mockapp/samples/MainScreen.java:
--------------------------------------------------------------------------------
1 | package org.vaadin.mockapp.samples;
2 |
3 | import org.vaadin.mockapp.MockAppUI;
4 | import org.vaadin.mockapp.samples.about.AboutView;
5 | import org.vaadin.mockapp.samples.crud.SampleCrudView;
6 |
7 | import com.vaadin.navigator.Navigator;
8 | import com.vaadin.navigator.ViewChangeListener;
9 | import com.vaadin.server.FontAwesome;
10 | import com.vaadin.ui.CssLayout;
11 | import com.vaadin.ui.HorizontalLayout;
12 |
13 | /**
14 | * Content of the UI when the user is logged in.
15 | *
16 | *
17 | */
18 | public class MainScreen extends HorizontalLayout {
19 | private Menu menu;
20 |
21 | public MainScreen(MockAppUI ui) {
22 |
23 | setStyleName("main-screen");
24 |
25 | CssLayout viewContainer = new CssLayout();
26 | viewContainer.addStyleName("valo-content");
27 | viewContainer.setSizeFull();
28 |
29 | final Navigator navigator = new Navigator(ui, viewContainer);
30 | navigator.setErrorView(ErrorView.class);
31 | menu = new Menu(navigator);
32 | menu.addView(new SampleCrudView(), SampleCrudView.VIEW_NAME,
33 | SampleCrudView.VIEW_NAME, FontAwesome.EDIT);
34 | menu.addView(new AboutView(), AboutView.VIEW_NAME, AboutView.VIEW_NAME,
35 | FontAwesome.INFO_CIRCLE);
36 |
37 | navigator.addViewChangeListener(viewChangeListener);
38 |
39 | addComponent(menu);
40 | addComponent(viewContainer);
41 | setExpandRatio(viewContainer, 1);
42 | setSizeFull();
43 | }
44 |
45 | // notify the view menu about view changes so that it can display which view
46 | // is currently active
47 | ViewChangeListener viewChangeListener = new ViewChangeListener() {
48 |
49 | @Override
50 | public boolean beforeViewChange(ViewChangeEvent event) {
51 | return true;
52 | }
53 |
54 | @Override
55 | public void afterViewChange(ViewChangeEvent event) {
56 | menu.setActiveView(event.getViewName());
57 | }
58 |
59 | };
60 | }
61 |
--------------------------------------------------------------------------------
/mockapp-ui/src/main/java/org/vaadin/mockapp/samples/Menu.java:
--------------------------------------------------------------------------------
1 | package org.vaadin.mockapp.samples;
2 |
3 | import java.util.HashMap;
4 | import java.util.Map;
5 |
6 | import com.vaadin.navigator.Navigator;
7 | import com.vaadin.navigator.View;
8 | import com.vaadin.server.FontAwesome;
9 | import com.vaadin.server.Page;
10 | import com.vaadin.server.Resource;
11 | import com.vaadin.server.ThemeResource;
12 | import com.vaadin.server.VaadinSession;
13 | import com.vaadin.ui.Alignment;
14 | import com.vaadin.ui.Button;
15 | import com.vaadin.ui.Button.ClickEvent;
16 | import com.vaadin.ui.Button.ClickListener;
17 | import com.vaadin.ui.CssLayout;
18 | import com.vaadin.ui.HorizontalLayout;
19 | import com.vaadin.ui.Image;
20 | import com.vaadin.ui.Label;
21 | import com.vaadin.ui.MenuBar;
22 | import com.vaadin.ui.MenuBar.Command;
23 | import com.vaadin.ui.MenuBar.MenuItem;
24 | import com.vaadin.ui.themes.ValoTheme;
25 |
26 | /**
27 | * Responsive navigation menu presenting a list of available views to the user.
28 | */
29 | public class Menu extends CssLayout {
30 |
31 | private static final String VALO_MENUITEMS = "valo-menuitems";
32 | private static final String VALO_MENU_TOGGLE = "valo-menu-toggle";
33 | private static final String VALO_MENU_VISIBLE = "valo-menu-visible";
34 | private Navigator navigator;
35 | private Map viewButtons = new HashMap();
36 |
37 | private CssLayout menuItemsLayout;
38 | private CssLayout menuPart;
39 |
40 | public Menu(Navigator navigator) {
41 | this.navigator = navigator;
42 | setPrimaryStyleName(ValoTheme.MENU_ROOT);
43 | menuPart = new CssLayout();
44 | menuPart.addStyleName(ValoTheme.MENU_PART);
45 |
46 | // header of the menu
47 | final HorizontalLayout top = new HorizontalLayout();
48 | top.setDefaultComponentAlignment(Alignment.MIDDLE_LEFT);
49 | top.addStyleName(ValoTheme.MENU_TITLE);
50 | top.setSpacing(true);
51 | Label title = new Label("My CRUD");
52 | title.addStyleName(ValoTheme.LABEL_H3);
53 | title.setSizeUndefined();
54 | Image image = new Image(null, new ThemeResource("img/table-logo.png"));
55 | image.setStyleName("logo");
56 | top.addComponent(image);
57 | top.addComponent(title);
58 | menuPart.addComponent(top);
59 |
60 | // logout menu item
61 | MenuBar logoutMenu = new MenuBar();
62 | logoutMenu.addItem("Logout", FontAwesome.SIGN_OUT, new Command() {
63 |
64 | @Override
65 | public void menuSelected(MenuItem selectedItem) {
66 | VaadinSession.getCurrent().getSession().invalidate();
67 | Page.getCurrent().reload();
68 | }
69 | });
70 |
71 | logoutMenu.addStyleName("user-menu");
72 | menuPart.addComponent(logoutMenu);
73 |
74 | // button for toggling the visibility of the menu when on a small screen
75 | final Button showMenu = new Button("Menu", new ClickListener() {
76 | @Override
77 | public void buttonClick(final ClickEvent event) {
78 | if (menuPart.getStyleName().contains(VALO_MENU_VISIBLE)) {
79 | menuPart.removeStyleName(VALO_MENU_VISIBLE);
80 | } else {
81 | menuPart.addStyleName(VALO_MENU_VISIBLE);
82 | }
83 | }
84 | });
85 | showMenu.addStyleName(ValoTheme.BUTTON_PRIMARY);
86 | showMenu.addStyleName(ValoTheme.BUTTON_SMALL);
87 | showMenu.addStyleName(VALO_MENU_TOGGLE);
88 | showMenu.setIcon(FontAwesome.NAVICON);
89 | menuPart.addComponent(showMenu);
90 |
91 | // container for the navigation buttons, which are added by addView()
92 | menuItemsLayout = new CssLayout();
93 | menuItemsLayout.setPrimaryStyleName(VALO_MENUITEMS);
94 | menuPart.addComponent(menuItemsLayout);
95 |
96 | addComponent(menuPart);
97 | }
98 |
99 | /**
100 | * Register a pre-created view instance in the navigation menu and in the
101 | * {@link Navigator}.
102 | *
103 | * @see Navigator#addView(String, View)
104 | *
105 | * @param view
106 | * view instance to register
107 | * @param name
108 | * view name
109 | * @param caption
110 | * view caption in the menu
111 | * @param icon
112 | * view icon in the menu
113 | */
114 | public void addView(View view, final String name, String caption,
115 | Resource icon) {
116 | navigator.addView(name, view);
117 | createViewButton(name, caption, icon);
118 | }
119 |
120 | /**
121 | * Register a view in the navigation menu and in the {@link Navigator} based
122 | * on a view class.
123 | *
124 | * @see Navigator#addView(String, Class)
125 | *
126 | * @param viewClass
127 | * class of the views to create
128 | * @param name
129 | * view name
130 | * @param caption
131 | * view caption in the menu
132 | * @param icon
133 | * view icon in the menu
134 | */
135 | public void addView(Class extends View> viewClass, final String name,
136 | String caption, Resource icon) {
137 | navigator.addView(name, viewClass);
138 | createViewButton(name, caption, icon);
139 | }
140 |
141 | private void createViewButton(final String name, String caption,
142 | Resource icon) {
143 | Button button = new Button(caption, new ClickListener() {
144 |
145 | @Override
146 | public void buttonClick(ClickEvent event) {
147 | navigator.navigateTo(name);
148 |
149 | }
150 | });
151 | button.setPrimaryStyleName(ValoTheme.MENU_ITEM);
152 | button.setIcon(icon);
153 | menuItemsLayout.addComponent(button);
154 | viewButtons.put(name, button);
155 | }
156 |
157 | /**
158 | * Highlights a view navigation button as the currently active view in the
159 | * menu. This method does not perform the actual navigation.
160 | *
161 | * @param viewName
162 | * the name of the view to show as active
163 | */
164 | public void setActiveView(String viewName) {
165 | for (Button button : viewButtons.values()) {
166 | button.removeStyleName("selected");
167 | }
168 | Button selected = viewButtons.get(viewName);
169 | if (selected != null) {
170 | selected.addStyleName("selected");
171 | }
172 | menuPart.removeStyleName(VALO_MENU_VISIBLE);
173 | }
174 | }
175 |
--------------------------------------------------------------------------------
/mockapp-ui/src/main/java/org/vaadin/mockapp/samples/about/AboutView.java:
--------------------------------------------------------------------------------
1 | package org.vaadin.mockapp.samples.about;
2 |
3 | import com.vaadin.navigator.View;
4 | import com.vaadin.navigator.ViewChangeListener.ViewChangeEvent;
5 | import com.vaadin.server.FontAwesome;
6 | import com.vaadin.shared.Version;
7 | import com.vaadin.shared.ui.label.ContentMode;
8 | import com.vaadin.ui.Alignment;
9 | import com.vaadin.ui.CustomLayout;
10 | import com.vaadin.ui.Label;
11 | import com.vaadin.ui.VerticalLayout;
12 |
13 | public class AboutView extends VerticalLayout implements View {
14 |
15 | public static final String VIEW_NAME = "About";
16 |
17 | public AboutView() {
18 | CustomLayout aboutContent = new CustomLayout("aboutview");
19 | aboutContent.setStyleName("about-content");
20 |
21 | // you can add Vaadin components in predefined slots in the custom
22 | // layout
23 | aboutContent.addComponent(
24 | new Label(FontAwesome.INFO_CIRCLE.getHtml()
25 | + " This application is using Vaadin "
26 | + Version.getFullVersion(), ContentMode.HTML), "info");
27 |
28 | setSizeFull();
29 | setStyleName("about-view");
30 | addComponent(aboutContent);
31 | setComponentAlignment(aboutContent, Alignment.MIDDLE_CENTER);
32 | }
33 |
34 | @Override
35 | public void enter(ViewChangeEvent event) {
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/mockapp-ui/src/main/java/org/vaadin/mockapp/samples/authentication/AccessControl.java:
--------------------------------------------------------------------------------
1 | package org.vaadin.mockapp.samples.authentication;
2 |
3 | /**
4 | * Simple interface for authentication and authorization checks.
5 | */
6 | public interface AccessControl {
7 |
8 | public boolean signIn(String username, String password);
9 |
10 | public boolean isUserSignedIn();
11 |
12 | public boolean isUserInRole(String role);
13 |
14 | public String getPrincipalName();
15 | }
16 |
--------------------------------------------------------------------------------
/mockapp-ui/src/main/java/org/vaadin/mockapp/samples/authentication/BasicAccessControl.java:
--------------------------------------------------------------------------------
1 | package org.vaadin.mockapp.samples.authentication;
2 |
3 | /**
4 | * Default mock implementation of {@link AccessControl}. This implementation
5 | * accepts any string as a password, and considers the user "admin" as the only
6 | * administrator.
7 | */
8 | public class BasicAccessControl implements AccessControl {
9 |
10 | @Override
11 | public boolean signIn(String username, String password) {
12 | if (username == null || username.isEmpty())
13 | return false;
14 |
15 | CurrentUser.set(username);
16 | return true;
17 | }
18 |
19 | @Override
20 | public boolean isUserSignedIn() {
21 | return !CurrentUser.get().isEmpty();
22 | }
23 |
24 | @Override
25 | public boolean isUserInRole(String role) {
26 | if ("admin".equals(role)) {
27 | // Only the "admin" user is in the "admin" role
28 | return getPrincipalName().equals("admin");
29 | }
30 |
31 | // All users are in all non-admin roles
32 | return true;
33 | }
34 |
35 | @Override
36 | public String getPrincipalName() {
37 | return CurrentUser.get();
38 | }
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/mockapp-ui/src/main/java/org/vaadin/mockapp/samples/authentication/CurrentUser.java:
--------------------------------------------------------------------------------
1 | package org.vaadin.mockapp.samples.authentication;
2 |
3 | import com.vaadin.server.VaadinRequest;
4 | import com.vaadin.server.VaadinSession;
5 | import com.vaadin.server.WrappedSession;
6 |
7 | /**
8 | * Class for retrieving and setting the name of the current user of the current
9 | * session (without using JAAS). All methods of this class require that a
10 | * {@link VaadinRequest} is bound to the current thread.
11 | *
12 | *
13 | * @see com.vaadin.server.VaadinService#getCurrentRequest()
14 | */
15 | public final class CurrentUser {
16 |
17 | /**
18 | * The attribute key used to store the username in the session.
19 | */
20 | public static final String CURRENT_USER_SESSION_ATTRIBUTE_KEY = CurrentUser.class
21 | .getCanonicalName();
22 |
23 | private CurrentUser() {
24 | }
25 |
26 | /**
27 | * Returns the name of the current user stored in the current session, or an
28 | * empty string if no user name is stored.
29 | *
30 | * @throws IllegalStateException
31 | * if the current session cannot be accessed.
32 | */
33 | public static String get() {
34 | String currentUser = (String) getCurrentHttpSession().getAttribute(
35 | CURRENT_USER_SESSION_ATTRIBUTE_KEY);
36 | if (currentUser == null) {
37 | return "";
38 | } else {
39 | return currentUser;
40 | }
41 | }
42 |
43 | private static WrappedSession getCurrentHttpSession() {
44 | VaadinSession s = VaadinSession.getCurrent();
45 | if (s == null) {
46 | throw new IllegalStateException(
47 | "No session found for current thread");
48 | }
49 | return s.getSession();
50 | }
51 |
52 | /**
53 | * Sets the name of the current user and stores it in the current session.
54 | * Using a {@code null} username will remove the username from the session.
55 | *
56 | * @throws IllegalStateException
57 | * if the current session cannot be accessed.
58 | */
59 | public static void set(String currentUser) {
60 | if (currentUser == null) {
61 | getCurrentHttpSession().removeAttribute(
62 | CURRENT_USER_SESSION_ATTRIBUTE_KEY);
63 | } else {
64 | getCurrentHttpSession().setAttribute(
65 | CURRENT_USER_SESSION_ATTRIBUTE_KEY, currentUser);
66 | }
67 | }
68 |
69 | }
70 |
--------------------------------------------------------------------------------
/mockapp-ui/src/main/java/org/vaadin/mockapp/samples/authentication/LoginScreen.java:
--------------------------------------------------------------------------------
1 | package org.vaadin.mockapp.samples.authentication;
2 |
3 | import java.io.Serializable;
4 |
5 | import com.vaadin.event.ShortcutAction;
6 | import com.vaadin.server.Page;
7 | import com.vaadin.shared.ui.label.ContentMode;
8 | import com.vaadin.ui.Alignment;
9 | import com.vaadin.ui.Button;
10 | import com.vaadin.ui.Component;
11 | import com.vaadin.ui.CssLayout;
12 | import com.vaadin.ui.FormLayout;
13 | import com.vaadin.ui.Label;
14 | import com.vaadin.ui.Notification;
15 | import com.vaadin.ui.PasswordField;
16 | import com.vaadin.ui.TextField;
17 | import com.vaadin.ui.VerticalLayout;
18 | import com.vaadin.ui.themes.ValoTheme;
19 |
20 | /**
21 | * UI content when the user is not logged in yet.
22 | */
23 | public class LoginScreen extends CssLayout {
24 |
25 | private TextField username;
26 | private PasswordField password;
27 | private Button login;
28 | private Button forgotPassword;
29 | private LoginListener loginListener;
30 | private AccessControl accessControl;
31 |
32 | public LoginScreen(AccessControl accessControl, LoginListener loginListener) {
33 | this.loginListener = loginListener;
34 | this.accessControl = accessControl;
35 | buildUI();
36 | username.focus();
37 | }
38 |
39 | private void buildUI() {
40 | addStyleName("login-screen");
41 |
42 | // login form, centered in the available part of the screen
43 | Component loginForm = buildLoginForm();
44 |
45 | // layout to center login form when there is sufficient screen space
46 | // - see the theme for how this is made responsive for various screen
47 | // sizes
48 | VerticalLayout centeringLayout = new VerticalLayout();
49 | centeringLayout.setStyleName("centering-layout");
50 | centeringLayout.addComponent(loginForm);
51 | centeringLayout.setComponentAlignment(loginForm,
52 | Alignment.MIDDLE_CENTER);
53 |
54 | // information text about logging in
55 | CssLayout loginInformation = buildLoginInformation();
56 |
57 | addComponent(centeringLayout);
58 | addComponent(loginInformation);
59 | }
60 |
61 | private Component buildLoginForm() {
62 | FormLayout loginForm = new FormLayout();
63 |
64 | loginForm.addStyleName("login-form");
65 | loginForm.setSizeUndefined();
66 | loginForm.setMargin(false);
67 |
68 | loginForm.addComponent(username = new TextField("Username", "admin"));
69 | username.setWidth(15, Unit.EM);
70 | loginForm.addComponent(password = new PasswordField("Password"));
71 | password.setWidth(15, Unit.EM);
72 | password.setDescription("Write anything");
73 | CssLayout buttons = new CssLayout();
74 | buttons.setStyleName("buttons");
75 | loginForm.addComponent(buttons);
76 |
77 | buttons.addComponent(login = new Button("Login"));
78 | login.setDisableOnClick(true);
79 | login.addClickListener(new Button.ClickListener() {
80 | @Override
81 | public void buttonClick(Button.ClickEvent event) {
82 | try {
83 | login();
84 | } finally {
85 | login.setEnabled(true);
86 | }
87 | }
88 | });
89 | login.setClickShortcut(ShortcutAction.KeyCode.ENTER);
90 | login.addStyleName(ValoTheme.BUTTON_FRIENDLY);
91 |
92 | buttons.addComponent(forgotPassword = new Button("Forgot password?"));
93 | forgotPassword.addClickListener(new Button.ClickListener() {
94 | @Override
95 | public void buttonClick(Button.ClickEvent event) {
96 | showNotification(new Notification("Hint: Try anything"));
97 | }
98 | });
99 | forgotPassword.addStyleName(ValoTheme.BUTTON_LINK);
100 | return loginForm;
101 | }
102 |
103 | private CssLayout buildLoginInformation() {
104 | CssLayout loginInformation = new CssLayout();
105 | loginInformation.setStyleName("login-information");
106 | Label loginInfoText = new Label(
107 | "Login Information
"
108 | + "Log in as "admin" to have full access. Log in with any other username to have read-only access. For all users, any password is fine",
109 | ContentMode.HTML);
110 | loginInformation.addComponent(loginInfoText);
111 | return loginInformation;
112 | }
113 |
114 | private void login() {
115 | if (accessControl.signIn(username.getValue(), password.getValue())) {
116 | loginListener.loginSuccessful();
117 | } else {
118 | showNotification(new Notification("Login failed",
119 | "Please check your username and password and try again.",
120 | Notification.Type.HUMANIZED_MESSAGE));
121 | username.focus();
122 | }
123 | }
124 |
125 | private void showNotification(Notification notification) {
126 | // keep the notification visible a little while after moving the
127 | // mouse, or until clicked
128 | notification.setDelayMsec(2000);
129 | notification.show(Page.getCurrent());
130 | }
131 |
132 | public interface LoginListener extends Serializable {
133 | void loginSuccessful();
134 | }
135 | }
136 |
--------------------------------------------------------------------------------
/mockapp-ui/src/main/java/org/vaadin/mockapp/samples/crud/CategoryField.java:
--------------------------------------------------------------------------------
1 | package org.vaadin.mockapp.samples.crud;
2 |
3 | import java.util.Collection;
4 | import java.util.HashMap;
5 | import java.util.HashSet;
6 | import java.util.Map;
7 | import java.util.Set;
8 |
9 | import org.vaadin.mockapp.samples.backend.data.Category;
10 |
11 | import com.vaadin.data.util.converter.Converter.ConversionException;
12 | import com.vaadin.ui.CheckBox;
13 | import com.vaadin.ui.Component;
14 | import com.vaadin.ui.CustomField;
15 | import com.vaadin.ui.VerticalLayout;
16 |
17 | /**
18 | * A custom Field implementation that allows selecting a set of categories using
19 | * checkboxes rather than multi-selection in a list/table or a TwinColSelect.
20 | */
21 | public class CategoryField extends CustomField> {
22 |
23 | private VerticalLayout options;
24 | private Map checkboxes = new HashMap();
25 | private boolean updatingField = false;
26 |
27 | public CategoryField() {
28 | options = new VerticalLayout();
29 | }
30 |
31 | public CategoryField(String caption) {
32 | this();
33 | setCaption(caption);
34 | }
35 |
36 | @Override
37 | protected Component initContent() {
38 | return options;
39 | }
40 |
41 | /**
42 | * Set the collection of categories among which the used can select a
43 | * subset.
44 | *
45 | * @param categories
46 | * all available categories
47 | */
48 | public void setOptions(Collection categories) {
49 | options.removeAllComponents();
50 | checkboxes.clear();
51 | for (final Category category : categories) {
52 | final CheckBox box = new CheckBox(category.getName());
53 | checkboxes.put(category, box);
54 | box.addValueChangeListener(new ValueChangeListener() {
55 |
56 | @Override
57 | public void valueChange(
58 | com.vaadin.data.Property.ValueChangeEvent event) {
59 | if (!updatingField) {
60 | Set oldCategories = getValue();
61 | Set categories;
62 | if (oldCategories != null) {
63 | categories = new HashSet(oldCategories);
64 | } else {
65 | categories = new HashSet();
66 | }
67 | if (box.getValue()) {
68 | categories.add(category);
69 | } else {
70 | categories.remove(category);
71 | }
72 | setInternalValue(categories);
73 | }
74 | }
75 | });
76 | options.addComponent(box);
77 | }
78 | }
79 |
80 | @Override
81 | public Class getType() {
82 | return Set.class;
83 | }
84 |
85 | @Override
86 | protected void setInternalValue(Set newValue) {
87 | updatingField = true;
88 | super.setInternalValue(newValue);
89 | if (newValue != null) {
90 | for (Category category : checkboxes.keySet()) {
91 | checkboxes.get(category).setValue(newValue.contains(category));
92 | }
93 | } else {
94 | for (Category category : checkboxes.keySet()) {
95 | checkboxes.get(category).setValue(false);
96 | }
97 | }
98 | updatingField = false;
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/mockapp-ui/src/main/java/org/vaadin/mockapp/samples/crud/CollectionToStringConverter.java:
--------------------------------------------------------------------------------
1 | package org.vaadin.mockapp.samples.crud;
2 |
3 | import java.util.Collection;
4 | import java.util.Locale;
5 |
6 | import com.vaadin.data.util.converter.Converter;
7 |
8 | /**
9 | * A converter that allows displaying a collection as a comma separated list of
10 | * strings.
11 | */
12 | public class CollectionToStringConverter implements
13 | Converter {
14 |
15 | @Override
16 | public Collection convertToModel(String value,
17 | Class extends Collection> targetType, Locale locale)
18 | throws com.vaadin.data.util.converter.Converter.ConversionException {
19 | throw new UnsupportedOperationException(
20 | "Can only convert from collection to string");
21 | }
22 |
23 | @Override
24 | public String convertToPresentation(Collection value,
25 | Class extends String> targetType, Locale locale)
26 | throws com.vaadin.data.util.converter.Converter.ConversionException {
27 | if (value == null)
28 | return "";
29 | StringBuilder b = new StringBuilder();
30 | for (Object o : value) {
31 | b.append(o.toString());
32 | b.append(", ");
33 | }
34 | return b.substring(0, b.length() - 2);
35 |
36 | }
37 |
38 | @Override
39 | public Class getModelType() {
40 | return Collection.class;
41 | }
42 |
43 | @Override
44 | public Class getPresentationType() {
45 | return String.class;
46 | }
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/mockapp-ui/src/main/java/org/vaadin/mockapp/samples/crud/EuroConverter.java:
--------------------------------------------------------------------------------
1 | package org.vaadin.mockapp.samples.crud;
2 |
3 | import java.math.BigDecimal;
4 | import java.text.DecimalFormat;
5 | import java.text.NumberFormat;
6 | import java.util.Locale;
7 |
8 | import com.vaadin.data.util.converter.StringToBigDecimalConverter;
9 |
10 | /**
11 | * A converter that adds/removes the euro sign and formats currencies with two
12 | * decimal places.
13 | */
14 | public class EuroConverter extends StringToBigDecimalConverter {
15 |
16 | @Override
17 | public BigDecimal convertToModel(String value,
18 | Class extends BigDecimal> targetType, Locale locale)
19 | throws com.vaadin.data.util.converter.Converter.ConversionException {
20 | value = value.replaceAll("[€\\s]", "").trim();
21 | if ("".equals(value)) {
22 | value = "0";
23 | }
24 | return super.convertToModel(value, targetType, locale);
25 | }
26 |
27 | @Override
28 | protected NumberFormat getFormat(Locale locale) {
29 | // Always display currency with two decimals
30 | NumberFormat format = super.getFormat(locale);
31 | if (format instanceof DecimalFormat) {
32 | ((DecimalFormat) format).setMaximumFractionDigits(2);
33 | ((DecimalFormat) format).setMinimumFractionDigits(2);
34 | }
35 | return format;
36 | }
37 |
38 | @Override
39 | public String convertToPresentation(BigDecimal value,
40 | Class extends String> targetType, Locale locale)
41 | throws com.vaadin.data.util.converter.Converter.ConversionException {
42 | return super.convertToPresentation(value, targetType, locale) + " €";
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/mockapp-ui/src/main/java/org/vaadin/mockapp/samples/crud/NumberField.java:
--------------------------------------------------------------------------------
1 | package org.vaadin.mockapp.samples.crud;
2 |
3 | import java.text.DecimalFormat;
4 | import java.text.NumberFormat;
5 | import java.util.Locale;
6 |
7 | import org.vaadin.mockapp.samples.AttributeExtension;
8 |
9 | import com.vaadin.data.util.converter.StringToIntegerConverter;
10 | import com.vaadin.ui.TextField;
11 |
12 | /**
13 | * A field for entering numbers. On touch devices, a numeric keyboard is shown
14 | * instead of the normal one.
15 | */
16 | public class NumberField extends TextField {
17 | public NumberField() {
18 | // Mark the field as numeric.
19 | // This affects the virtual keyboard shown on mobile devices.
20 | AttributeExtension ae = new AttributeExtension();
21 | ae.extend(this);
22 | ae.setAttribute("type", "number");
23 |
24 | setConverter(new StringToIntegerConverter() {
25 | @Override
26 | protected NumberFormat getFormat(Locale locale) {
27 | // do not use a thousands separator, as HTML5 input type
28 | // number expects a fixed wire/DOM number format regardless
29 | // of how the browser presents it to the user (which could
30 | // depend on the browser locale)
31 | DecimalFormat format = new DecimalFormat();
32 | format.setMaximumFractionDigits(0);
33 | format.setDecimalSeparatorAlwaysShown(false);
34 | format.setParseIntegerOnly(true);
35 | format.setGroupingUsed(false);
36 | return format;
37 | }
38 | });
39 | }
40 |
41 | public NumberField(String caption) {
42 | this();
43 | setCaption(caption);
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/mockapp-ui/src/main/java/org/vaadin/mockapp/samples/crud/ProductForm.java:
--------------------------------------------------------------------------------
1 | package org.vaadin.mockapp.samples.crud;
2 |
3 | import java.util.Collection;
4 |
5 | import org.vaadin.mockapp.samples.backend.DataService;
6 | import org.vaadin.mockapp.samples.backend.data.Availability;
7 | import org.vaadin.mockapp.samples.backend.data.Category;
8 | import org.vaadin.mockapp.samples.backend.data.Product;
9 |
10 | import com.vaadin.data.Property.ValueChangeEvent;
11 | import com.vaadin.data.Property.ValueChangeListener;
12 | import com.vaadin.data.fieldgroup.BeanFieldGroup;
13 | import com.vaadin.data.fieldgroup.FieldGroup.CommitEvent;
14 | import com.vaadin.data.fieldgroup.FieldGroup.CommitException;
15 | import com.vaadin.data.fieldgroup.FieldGroup.CommitHandler;
16 | import com.vaadin.data.util.BeanItem;
17 | import com.vaadin.server.Page;
18 | import com.vaadin.ui.Button.ClickEvent;
19 | import com.vaadin.ui.Button.ClickListener;
20 | import com.vaadin.ui.Field;
21 | import com.vaadin.ui.Notification;
22 | import com.vaadin.ui.Notification.Type;
23 |
24 | /**
25 | * A form for editing a single product.
26 | *
27 | * Using responsive layouts, the form can be displayed either sliding out on the
28 | * side of the view or filling the whole screen - see the theme for the related
29 | * CSS rules.
30 | */
31 | public class ProductForm extends ProductFormDesign {
32 |
33 | private SampleCrudLogic viewLogic;
34 | private BeanFieldGroup fieldGroup;
35 |
36 | public ProductForm(SampleCrudLogic sampleCrudLogic) {
37 | super();
38 | addStyleName("product-form");
39 | viewLogic = sampleCrudLogic;
40 |
41 | price.setConverter(new EuroConverter());
42 |
43 | for (Availability s : Availability.values()) {
44 | availability.addItem(s);
45 | }
46 |
47 | fieldGroup = new BeanFieldGroup(Product.class);
48 | fieldGroup.bindMemberFields(this);
49 |
50 | // perform validation and enable/disable buttons while editing
51 | ValueChangeListener valueListener = new ValueChangeListener() {
52 | @Override
53 | public void valueChange(ValueChangeEvent event) {
54 | formHasChanged();
55 | }
56 | };
57 | for (Field f : fieldGroup.getFields()) {
58 | f.addValueChangeListener(valueListener);
59 | }
60 |
61 | fieldGroup.addCommitHandler(new CommitHandler() {
62 |
63 | @Override
64 | public void preCommit(CommitEvent commitEvent)
65 | throws CommitException {
66 | }
67 |
68 | @Override
69 | public void postCommit(CommitEvent commitEvent)
70 | throws CommitException {
71 | DataService.get().updateProduct(
72 | fieldGroup.getItemDataSource().getBean());
73 | }
74 | });
75 |
76 | save.addClickListener(new ClickListener() {
77 | @Override
78 | public void buttonClick(ClickEvent event) {
79 | try {
80 | fieldGroup.commit();
81 |
82 | // only if validation succeeds
83 | Product product = fieldGroup.getItemDataSource().getBean();
84 | viewLogic.saveProduct(product);
85 | } catch (CommitException e) {
86 | Notification n = new Notification(
87 | "Please re-check the fields", Type.ERROR_MESSAGE);
88 | n.setDelayMsec(500);
89 | n.show(getUI().getPage());
90 | }
91 | }
92 | });
93 |
94 | cancel.addClickListener(new ClickListener() {
95 | @Override
96 | public void buttonClick(ClickEvent event) {
97 | viewLogic.cancelProduct();
98 | }
99 | });
100 |
101 | delete.addClickListener(new ClickListener() {
102 | @Override
103 | public void buttonClick(ClickEvent event) {
104 | Product product = fieldGroup.getItemDataSource().getBean();
105 | viewLogic.deleteProduct(product);
106 | }
107 | });
108 | }
109 |
110 | public void setCategories(Collection categories) {
111 | category.setOptions(categories);
112 | }
113 |
114 | public void editProduct(Product product) {
115 | if (product == null) {
116 | product = new Product();
117 | }
118 | fieldGroup.setItemDataSource(new BeanItem(product));
119 |
120 | // before the user makes any changes, disable validation error indicator
121 | // of the product name field (which may be empty)
122 | productName.setValidationVisible(false);
123 |
124 | // Scroll to the top
125 | // As this is not a Panel, using JavaScript
126 | String scrollScript = "window.document.getElementById('" + getId()
127 | + "').scrollTop = 0;";
128 | Page.getCurrent().getJavaScript().execute(scrollScript);
129 | }
130 |
131 | private void formHasChanged() {
132 | // show validation errors after the user has changed something
133 | productName.setValidationVisible(true);
134 |
135 | // only products that have been saved should be removable
136 | boolean canRemoveProduct = false;
137 | BeanItem item = fieldGroup.getItemDataSource();
138 | if (item != null) {
139 | Product product = item.getBean();
140 | canRemoveProduct = product.getId() != -1;
141 | }
142 | delete.setEnabled(canRemoveProduct);
143 | }
144 | }
145 |
--------------------------------------------------------------------------------
/mockapp-ui/src/main/java/org/vaadin/mockapp/samples/crud/ProductFormDesign.java:
--------------------------------------------------------------------------------
1 | package org.vaadin.mockapp.samples.crud;
2 |
3 | import com.vaadin.annotations.AutoGenerated;
4 | import com.vaadin.annotations.DesignRoot;
5 | import com.vaadin.ui.Button;
6 | import com.vaadin.ui.ComboBox;
7 | import com.vaadin.ui.CssLayout;
8 | import com.vaadin.ui.TextField;
9 | import com.vaadin.ui.declarative.Design;
10 |
11 | /**
12 | * !! DO NOT EDIT THIS FILE !!
13 | *
14 | * This class is generated by Vaadin Designer and will be overwritten.
15 | *
16 | * Please make a subclass with logic and additional interfaces as needed, e.g
17 | * class LoginView extends LoginDesign implements View { … }
18 | */
19 | @DesignRoot
20 | @AutoGenerated
21 | @SuppressWarnings("serial")
22 | public class ProductFormDesign extends CssLayout {
23 | protected TextField productName;
24 | protected TextField price;
25 | protected NumberField stockCount;
26 | protected ComboBox availability;
27 | protected CategoryField category;
28 | protected Button save;
29 | protected Button cancel;
30 | protected Button delete;
31 |
32 | public ProductFormDesign() {
33 | Design.read(this);
34 | }
35 | }
--------------------------------------------------------------------------------
/mockapp-ui/src/main/java/org/vaadin/mockapp/samples/crud/ProductGrid.java:
--------------------------------------------------------------------------------
1 | package org.vaadin.mockapp.samples.crud;
2 |
3 | import java.util.Collection;
4 | import java.util.Locale;
5 |
6 | import org.vaadin.mockapp.samples.backend.data.Availability;
7 | import org.vaadin.mockapp.samples.backend.data.Product;
8 |
9 | import com.vaadin.data.util.BeanItem;
10 | import com.vaadin.data.util.BeanItemContainer;
11 | import com.vaadin.data.util.MethodProperty;
12 | import com.vaadin.data.util.converter.Converter;
13 | import com.vaadin.data.util.converter.StringToEnumConverter;
14 | import com.vaadin.data.util.converter.StringToIntegerConverter;
15 | import com.vaadin.data.util.filter.Or;
16 | import com.vaadin.data.util.filter.SimpleStringFilter;
17 | import com.vaadin.server.FontAwesome;
18 | import com.vaadin.ui.Grid;
19 | import com.vaadin.ui.renderers.HtmlRenderer;
20 |
21 | /**
22 | * Grid of products, handling the visual presentation and filtering of a set of
23 | * items. This version uses an in-memory data source that is suitable for small
24 | * data sets.
25 | */
26 | public class ProductGrid extends Grid {
27 |
28 | private StringToEnumConverter availabilityConverter = new StringToEnumConverter() {
29 | @Override
30 | public String convertToPresentation(Enum availability,
31 | java.lang.Class extends String> targetType, Locale locale)
32 | throws Converter.ConversionException {
33 | String text = super.convertToPresentation(availability, targetType,
34 | locale);
35 |
36 | String color = "";
37 | if (availability == Availability.AVAILABLE) {
38 | color = "#2dd085";
39 | } else if (availability == Availability.COMING) {
40 | color = "#ffc66e";
41 | } else if (availability == Availability.DISCONTINUED) {
42 | color = "#f54993";
43 | }
44 |
45 | String iconCode = ""
48 | + Integer.toHexString(FontAwesome.CIRCLE.getCodepoint())
49 | + ";";
50 |
51 | return iconCode + " " + text;
52 | };
53 | };
54 |
55 | public ProductGrid() {
56 | setSizeFull();
57 |
58 | setSelectionMode(SelectionMode.SINGLE);
59 |
60 | BeanItemContainer container = new BeanItemContainer(
61 | Product.class);
62 | setContainerDataSource(container);
63 | setColumnOrder("id", "productName", "price", "availability",
64 | "stockCount", "category");
65 |
66 | // Show empty stock as "-"
67 | getColumn("stockCount").setConverter(new StringToIntegerConverter() {
68 | @Override
69 | public String convertToPresentation(Integer value,
70 | java.lang.Class extends String> targetType, Locale locale)
71 | throws Converter.ConversionException {
72 | if (value == 0) {
73 | return "-";
74 | }
75 |
76 | return super.convertToPresentation(value, targetType, locale);
77 | };
78 | });
79 |
80 | // Add an traffic light icon in front of availability
81 | getColumn("availability").setConverter(availabilityConverter)
82 | .setRenderer(new HtmlRenderer());
83 |
84 | // Add " €" automatically after price
85 | getColumn("price").setConverter(new EuroConverter());
86 |
87 | // Show categories as a comma separated list
88 | getColumn("category").setConverter(new CollectionToStringConverter());
89 |
90 | // Align columns using a style generator and theme rule until #15438
91 | setCellStyleGenerator(new CellStyleGenerator() {
92 |
93 | @Override
94 | public String getStyle(CellReference cellReference) {
95 | if (cellReference.getPropertyId().equals("price")
96 | || cellReference.getPropertyId().equals("stockCount")) {
97 | return "align-right";
98 | }
99 | return null;
100 | }
101 | });
102 | }
103 |
104 | /**
105 | * Filter the grid based on a search string that is searched for in the
106 | * product name, availability and category columns.
107 | *
108 | * @param filterString
109 | * string to look for
110 | */
111 | public void setFilter(String filterString) {
112 | getContainer().removeAllContainerFilters();
113 | if (filterString.length() > 0) {
114 | SimpleStringFilter nameFilter = new SimpleStringFilter(
115 | "productName", filterString, true, false);
116 | SimpleStringFilter availabilityFilter = new SimpleStringFilter(
117 | "availability", filterString, true, false);
118 | SimpleStringFilter categoryFilter = new SimpleStringFilter(
119 | "category", filterString, true, false);
120 | getContainer().addContainerFilter(
121 | new Or(nameFilter, availabilityFilter, categoryFilter));
122 | }
123 |
124 | }
125 |
126 | private BeanItemContainer getContainer() {
127 | return (BeanItemContainer) super.getContainerDataSource();
128 | }
129 |
130 | @Override
131 | public Product getSelectedRow() throws IllegalStateException {
132 | return (Product) super.getSelectedRow();
133 | }
134 |
135 | public void setProducts(Collection products) {
136 | getContainer().removeAllItems();
137 | getContainer().addAll(products);
138 | }
139 |
140 | public void refresh(Product product) {
141 | // We avoid updating the whole table through the backend here so we can
142 | // get a partial update for the grid
143 | BeanItem item = getContainer().getItem(product);
144 | if (item != null) {
145 | // Updated product
146 | MethodProperty p = (MethodProperty) item.getItemProperty("id");
147 | p.fireValueChange();
148 | } else {
149 | // New product
150 | getContainer().addBean(product);
151 | }
152 | }
153 |
154 | public void remove(Product product) {
155 | getContainer().removeItem(product);
156 | }
157 | }
158 |
--------------------------------------------------------------------------------
/mockapp-ui/src/main/java/org/vaadin/mockapp/samples/crud/SampleCrudLogic.java:
--------------------------------------------------------------------------------
1 | package org.vaadin.mockapp.samples.crud;
2 |
3 | import org.vaadin.mockapp.MockAppUI;
4 | import org.vaadin.mockapp.samples.backend.DataService;
5 | import org.vaadin.mockapp.samples.backend.data.Product;
6 |
7 | import com.vaadin.server.Page;
8 |
9 | /**
10 | * This class provides an interface for the logical operations between the CRUD
11 | * view, its parts like the product editor form and the data source, including
12 | * fetching and saving products.
13 | *
14 | * Having this separate from the view makes it easier to test various parts of
15 | * the system separately, and to e.g. provide alternative views for the same
16 | * data.
17 | */
18 | public class SampleCrudLogic {
19 |
20 | private SampleCrudView view;
21 |
22 | public SampleCrudLogic(SampleCrudView simpleCrudView) {
23 | view = simpleCrudView;
24 | }
25 |
26 | public void init() {
27 | editProduct(null);
28 | // Hide and disable if not admin
29 | if (!MockAppUI.get().getAccessControl().isUserInRole("admin")) {
30 | view.setNewProductEnabled(false);
31 | }
32 |
33 | view.showProducts(DataService.get().getAllProducts());
34 | }
35 |
36 | public void cancelProduct() {
37 | setFragmentParameter("");
38 | view.clearSelection();
39 | view.editProduct(null);
40 | }
41 |
42 | /**
43 | * Update the fragment without causing navigator to change view
44 | */
45 | private void setFragmentParameter(String productId) {
46 | String fragmentParameter;
47 | if (productId == null || productId.isEmpty()) {
48 | fragmentParameter = "";
49 | } else {
50 | fragmentParameter = productId;
51 | }
52 |
53 | Page page = MockAppUI.get().getPage();
54 | page.setUriFragment("!" + SampleCrudView.VIEW_NAME + "/"
55 | + fragmentParameter, false);
56 | }
57 |
58 | public void enter(String productId) {
59 | if (productId != null && !productId.isEmpty()) {
60 | if (productId.equals("new")) {
61 | newProduct();
62 | } else {
63 | // Ensure this is selected even if coming directly here from
64 | // login
65 | try {
66 | int pid = Integer.parseInt(productId);
67 | Product product = findProduct(pid);
68 | view.selectRow(product);
69 | } catch (NumberFormatException e) {
70 | }
71 | }
72 | }
73 | }
74 |
75 | private Product findProduct(int productId) {
76 | return DataService.get().getProductById(productId);
77 | }
78 |
79 | public void saveProduct(Product product) {
80 | view.showSaveNotification(product.getProductName() + " ("
81 | + product.getId() + ") updated");
82 | view.clearSelection();
83 | view.editProduct(null);
84 | view.refreshProduct(product);
85 | setFragmentParameter("");
86 | }
87 |
88 | public void deleteProduct(Product product) {
89 | DataService.get().deleteProduct(product.getId());
90 | view.showSaveNotification(product.getProductName() + " ("
91 | + product.getId() + ") removed");
92 |
93 | view.clearSelection();
94 | view.editProduct(null);
95 | view.removeProduct(product);
96 | setFragmentParameter("");
97 | }
98 |
99 | public void editProduct(Product product) {
100 | if (product == null) {
101 | setFragmentParameter("");
102 | } else {
103 | setFragmentParameter(product.getId() + "");
104 | }
105 | view.editProduct(product);
106 | }
107 |
108 | public void newProduct() {
109 | view.clearSelection();
110 | setFragmentParameter("new");
111 | view.editProduct(new Product());
112 | }
113 |
114 | public void rowSelected(Product product) {
115 | if (MockAppUI.get().getAccessControl().isUserInRole("admin")) {
116 | view.editProduct(product);
117 | }
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/mockapp-ui/src/main/java/org/vaadin/mockapp/samples/crud/SampleCrudView.java:
--------------------------------------------------------------------------------
1 | package org.vaadin.mockapp.samples.crud;
2 |
3 | import java.util.Collection;
4 |
5 | import org.vaadin.mockapp.samples.ResetButtonForTextField;
6 | import org.vaadin.mockapp.samples.backend.DataService;
7 | import org.vaadin.mockapp.samples.backend.data.Product;
8 |
9 | import com.vaadin.event.FieldEvents;
10 | import com.vaadin.event.SelectionEvent;
11 | import com.vaadin.event.SelectionEvent.SelectionListener;
12 | import com.vaadin.navigator.View;
13 | import com.vaadin.navigator.ViewChangeListener.ViewChangeEvent;
14 | import com.vaadin.server.FontAwesome;
15 | import com.vaadin.ui.Alignment;
16 | import com.vaadin.ui.Button;
17 | import com.vaadin.ui.Button.ClickEvent;
18 | import com.vaadin.ui.Button.ClickListener;
19 | import com.vaadin.ui.CssLayout;
20 | import com.vaadin.ui.Grid.SelectionModel;
21 | import com.vaadin.ui.HorizontalLayout;
22 | import com.vaadin.ui.Notification;
23 | import com.vaadin.ui.Notification.Type;
24 | import com.vaadin.ui.TextField;
25 | import com.vaadin.ui.VerticalLayout;
26 | import com.vaadin.ui.themes.ValoTheme;
27 |
28 | /**
29 | * A view for performing create-read-update-delete operations on products.
30 | *
31 | * See also {@link SampleCrudLogic} for fetching the data, the actual CRUD
32 | * operations and controlling the view based on events from outside.
33 | */
34 | public class SampleCrudView extends CssLayout implements View {
35 |
36 | public static final String VIEW_NAME = "Inventory";
37 | private ProductGrid grid;
38 | private ProductForm form;
39 |
40 | private SampleCrudLogic viewLogic = new SampleCrudLogic(this);
41 | private Button newProduct;
42 |
43 | public SampleCrudView() {
44 | setSizeFull();
45 | addStyleName("crud-view");
46 | HorizontalLayout topLayout = createTopBar();
47 |
48 | grid = new ProductGrid();
49 | grid.addSelectionListener(new SelectionListener() {
50 |
51 | @Override
52 | public void select(SelectionEvent event) {
53 | viewLogic.rowSelected(grid.getSelectedRow());
54 | }
55 | });
56 |
57 | form = new ProductForm(viewLogic);
58 | form.setCategories(DataService.get().getAllCategories());
59 |
60 | VerticalLayout barAndGridLayout = new VerticalLayout();
61 | barAndGridLayout.addComponent(topLayout);
62 | barAndGridLayout.addComponent(grid);
63 | barAndGridLayout.setMargin(true);
64 | barAndGridLayout.setSpacing(true);
65 | barAndGridLayout.setSizeFull();
66 | barAndGridLayout.setExpandRatio(grid, 1);
67 | barAndGridLayout.setStyleName("crud-main-layout");
68 |
69 | addComponent(barAndGridLayout);
70 | addComponent(form);
71 |
72 | viewLogic.init();
73 | }
74 |
75 | public HorizontalLayout createTopBar() {
76 | TextField filter = new TextField();
77 | filter.setStyleName("filter-textfield");
78 | filter.setInputPrompt("Filter");
79 | ResetButtonForTextField.extend(filter);
80 | filter.setImmediate(true);
81 | filter.addTextChangeListener(new FieldEvents.TextChangeListener() {
82 | @Override
83 | public void textChange(FieldEvents.TextChangeEvent event) {
84 | grid.setFilter(event.getText());
85 | }
86 | });
87 |
88 | newProduct = new Button("New product");
89 | newProduct.addStyleName(ValoTheme.BUTTON_PRIMARY);
90 | newProduct.setIcon(FontAwesome.PLUS_CIRCLE);
91 | newProduct.addClickListener(new ClickListener() {
92 | @Override
93 | public void buttonClick(ClickEvent event) {
94 | viewLogic.newProduct();
95 | }
96 | });
97 |
98 | HorizontalLayout topLayout = new HorizontalLayout();
99 | topLayout.setSpacing(true);
100 | topLayout.setWidth("100%");
101 | topLayout.addComponent(filter);
102 | topLayout.addComponent(newProduct);
103 | topLayout.setComponentAlignment(filter, Alignment.MIDDLE_LEFT);
104 | topLayout.setExpandRatio(filter, 1);
105 | topLayout.setStyleName("top-bar");
106 | return topLayout;
107 | }
108 |
109 | @Override
110 | public void enter(ViewChangeEvent event) {
111 | viewLogic.enter(event.getParameters());
112 | }
113 |
114 | public void showError(String msg) {
115 | Notification.show(msg, Type.ERROR_MESSAGE);
116 | }
117 |
118 | public void showSaveNotification(String msg) {
119 | Notification.show(msg, Type.TRAY_NOTIFICATION);
120 | }
121 |
122 | public void setNewProductEnabled(boolean enabled) {
123 | newProduct.setEnabled(enabled);
124 | }
125 |
126 | public void clearSelection() {
127 | grid.getSelectionModel().reset();
128 | }
129 |
130 | public void selectRow(Product row) {
131 | ((SelectionModel.Single) grid.getSelectionModel()).select(row);
132 | }
133 |
134 | public Product getSelectedRow() {
135 | return grid.getSelectedRow();
136 | }
137 |
138 | public void editProduct(Product product) {
139 | if (product != null) {
140 | form.addStyleName("visible");
141 | form.setEnabled(true);
142 | } else {
143 | form.removeStyleName("visible");
144 | form.setEnabled(false);
145 | }
146 | form.editProduct(product);
147 | }
148 |
149 | public void showProducts(Collection products) {
150 | grid.setProducts(products);
151 | }
152 |
153 | public void refreshProduct(Product product) {
154 | grid.refresh(product);
155 | grid.scrollTo(product);
156 | }
157 |
158 | public void removeProduct(Product product) {
159 | grid.remove(product);
160 | }
161 |
162 | }
163 |
--------------------------------------------------------------------------------
/mockapp-ui/src/main/resources/org/vaadin/mockapp/samples/crud/ProductFormDesign.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | Save
18 | Cancel
19 | Delete
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/mockapp-ui/src/main/webapp/VAADIN/themes/mockapp/addons.scss:
--------------------------------------------------------------------------------
1 | /* This file is automatically managed and will be overwritten from time to time. */
2 | /* Do not manually edit this file. */
3 |
4 | /* Import and include this mixin into your project theme to include the addon themes */
5 | @mixin addons {
6 | }
7 |
8 |
--------------------------------------------------------------------------------
/mockapp-ui/src/main/webapp/VAADIN/themes/mockapp/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vaadin/archetype-application-example/2aa89b8c56eccb41ce266f8ae7490c9bf3b3faff/mockapp-ui/src/main/webapp/VAADIN/themes/mockapp/favicon.ico
--------------------------------------------------------------------------------
/mockapp-ui/src/main/webapp/VAADIN/themes/mockapp/img/archetype-login-bg.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vaadin/archetype-application-example/2aa89b8c56eccb41ce266f8ae7490c9bf3b3faff/mockapp-ui/src/main/webapp/VAADIN/themes/mockapp/img/archetype-login-bg.jpg
--------------------------------------------------------------------------------
/mockapp-ui/src/main/webapp/VAADIN/themes/mockapp/img/table-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vaadin/archetype-application-example/2aa89b8c56eccb41ce266f8ae7490c9bf3b3faff/mockapp-ui/src/main/webapp/VAADIN/themes/mockapp/img/table-logo.png
--------------------------------------------------------------------------------
/mockapp-ui/src/main/webapp/VAADIN/themes/mockapp/layouts/aboutview.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | About
9 |
10 |
11 |
12 | Vaadin web page
13 |
14 |
15 |
--------------------------------------------------------------------------------
/mockapp-ui/src/main/webapp/VAADIN/themes/mockapp/mockapp.scss:
--------------------------------------------------------------------------------
1 | // Global variable overrides. Must be declared before importing Valo.
2 |
3 | // Defines the plaintext font size, weight and family. Font size affects general component sizing.
4 | //$v-font-size: 16px;
5 | //$v-font-weight: 300;
6 | //$v-font-family: "Open Sans", sans-serif;
7 |
8 | // Defines the border used by all components.
9 | //$v-border: 1px solid (v-shade 0.7);
10 | //$v-border-radius: 4px;
11 |
12 | // Affects the color of some component elements, e.g Button, Panel title, etc
13 | //$v-background-color: hsl(210, 0%, 98%);
14 | // Affects the color of content areas, e.g Panel and Window content, TextField input etc
15 | //$v-app-background-color: $v-background-color;
16 |
17 | // Affects the visual appearance of all components
18 | //$v-gradient: v-linear 8%;
19 | //$v-bevel-depth: 30%;
20 | //$v-shadow-opacity: 5%;
21 |
22 | // Defines colors for indicating status (focus, success, failure)
23 | //$v-focus-color: valo-focus-color(); // Calculates a suitable color automatically
24 | //$v-friendly-color: #2c9720;
25 | //$v-error-indicator-color: #ed473b;
26 |
27 | // For more information, see: https://vaadin.com/book/-/page/themes.valo.html
28 | // Example variants can be copy/pasted from https://vaadin.com/wiki/-/wiki/Main/Valo+Examples
29 |
30 | $v-luminance-threshold: 180 !default;
31 |
32 | $editor-background-color: #3b3f42 !default;
33 | $valo-menu-background-color: $editor-background-color !default;
34 |
35 | $v-focus-color: rgb(96, 160, 234) !default;
36 | $v-error-indicator-color: #eb2977 !default;
37 | $v-friendly-color: rgb(54, 185, 85);
38 |
39 | $v-font-size: 15px !default;
40 | $v-font-weight: 400 !default;
41 | $v-unit-size: 32px !default;
42 |
43 | $login-info-width: 300px !default;
44 | $login-info-opacity: 0.7 !default;
45 | $login-background-color: $editor-background-color !default;
46 | // Get more background images from unsplash.com (remember to optimize the filesize)
47 | $login-background-image: "img/archetype-login-bg.jpg" !default;
48 |
49 | $editor-shadow: 0 0 10px 10px rgba(0,0,0,.1) !default;
50 | $editor-embed-background-color: darken($editor-background-color, 5%) !default;
51 | $editor-raised-background-color: lighten($editor-background-color, 10%) !default;
52 | $editor-caption-font-color: valo-font-color($editor-background-color, 0.5) !default;
53 |
54 | $v-layout-margin-top: round($v-unit-size / 1.5) !default;
55 | $v-layout-margin-right: $v-layout-margin-top !default;
56 | $v-layout-margin-bottom: $v-layout-margin-top !default;
57 | $v-layout-margin-left: $v-layout-margin-top !default;
58 | $v-layout-spacing-vertical: round($v-unit-size / 1.8) !default;
59 | $v-layout-spacing-horizontal: round($v-unit-size / 1.8) !default;
60 |
61 |
62 | @import "../valo/valo.scss";
63 |
64 |
65 | @mixin mockapp {
66 | @include valo;
67 |
68 |
69 | // login screen - for small screens, see below
70 | .login-screen {
71 | background: $editor-background-color;
72 |
73 | @if $login-background-image {
74 | background-image: url(#{$login-background-image});
75 | background-size: cover;
76 | background-position: 50% 50%;
77 | }
78 |
79 | width: 100%;
80 | height: 100%;
81 |
82 | .login-form {
83 | @include valo-panel-style;
84 | border: none;
85 | padding: $v-layout-margin;
86 | @include valo-animate-in-fade($duration: 1s);
87 | }
88 |
89 | .login-information {
90 | display: inline-block;
91 | position: absolute;
92 | top: 0;
93 | left: 0;
94 | width: $login-info-width;
95 | height: 100%;
96 | background: $v-selection-color; // For IE8
97 | background-color: rgba($v-selection-color, $login-info-opacity);
98 | padding: $v-layout-margin;
99 | color: valo-font-color($v-selection-color, 0.9);
100 | @include animation(valo-animate-in-fade 1s 1s backwards);
101 |
102 | h1 {
103 | color: inherit;
104 | }
105 | }
106 |
107 | .centering-layout {
108 | display: inline-block;
109 | width: 100%;
110 | height: 100%;
111 | padding-left: $login-info-width;
112 |
113 | .v-slot {
114 | height: 100%;
115 | }
116 | }
117 | }
118 |
119 | // makes the CRUD view keep the sidebar editor within the view as sidebar is absolutely positioned
120 | .crud-view {
121 | position: relative;
122 |
123 | .filter-textfield {
124 | width: round($v-unit-size * 9);
125 | }
126 | }
127 |
128 | // sidebar editor for CRUD, scrolls if there is not enough space vertically
129 | .product-form-wrapper {
130 | position: absolute;
131 | top: 0;
132 | bottom: 0;
133 | right: 0;
134 | z-index: 100;
135 | width: round($v-unit-size * 9);
136 | height: 100%;
137 | overflow: auto;
138 | padding: $v-layout-spacing-vertical $v-layout-spacing-horizontal;
139 | background-color: $editor-background-color;
140 | color: valo-font-color($editor-background-color, 0.8);
141 |
142 | // Set the context color for the style mixins
143 | $temp: $v-app-background-color;
144 | $v-app-background-color: $editor-background-color;
145 |
146 | .v-textfield {
147 | @include valo-textfield-style($background-color: $editor-embed-background-color);
148 | }
149 |
150 | .v-checkbox {
151 | @include valo-checkbox-style($background-color: $editor-raised-background-color);
152 | }
153 |
154 | .v-filterselect {
155 | @include valo-combobox-style($background-color: $editor-raised-background-color, $bevel: $v-bevel, $gradient: $v-gradient);
156 | }
157 |
158 | // Restore variable
159 | $v-app-background-color: $temp;
160 |
161 | .v-button {
162 | display: block;
163 | }
164 |
165 | .v-caption {
166 | color: $editor-caption-font-color;
167 | }
168 |
169 | // try to ensure there is space under the last button also on small displays (does not work on IE8)
170 | .form-layout > .v-expand > .v-slot:last-child {
171 | padding-bottom: $v-layout-spacing-vertical;
172 | }
173 |
174 | }
175 |
176 | .product-form {
177 | right: 0;
178 | @include transition(all 300ms);
179 | @include transform(translatex(100%));
180 | }
181 |
182 | // Enables animation for opening CRUD editor
183 | .visible {
184 | @include transform(none);
185 | @include box-shadow($editor-shadow);
186 | }
187 |
188 | // About view
189 |
190 | .about-view {
191 | overflow: auto;
192 |
193 | .about-content {
194 | @include valo-panel-style;
195 | max-width: 500px;
196 | // Override the default of CustomLayout
197 | padding: $v-unit-size !important;
198 | }
199 | }
200 |
201 | // Style rules for smaller display sizes
202 |
203 | // No top menu on the login view, login screen layout changes
204 | .v-ui[width-range~="0-800px"] {
205 |
206 | .main-screen {
207 | padding-top: $v-unit-size;
208 | }
209 | // TODO also move loading indicator if using the hack above
210 |
211 | // More compact login screen
212 | .login-screen {
213 | height: auto;
214 | min-height: 100%;
215 |
216 | .login-information {
217 | position: static;
218 | width: 100%;
219 | height: auto;
220 |
221 | .v-label {
222 | text-align: center;
223 |
224 | h1 {
225 | margin-top: .4em;
226 | }
227 | }
228 | }
229 |
230 | .centering-layout {
231 | display: block;
232 | width: 100%;
233 | height: auto;
234 | padding-left: 0;
235 | padding-top: 60px;
236 | padding-bottom: 60px;
237 | }
238 |
239 | .login-form {
240 | width: 400px;
241 | max-width: 100%;
242 |
243 | table {
244 | width: 100%;
245 | }
246 |
247 | .v-textfield {
248 | width: 100% !important;
249 | }
250 |
251 | .v-formlayout-captioncell,
252 | .v-formlayout-contentcell,
253 | .v-formlayout-errorcell {
254 | display: block;
255 | text-align: center;
256 | padding-top: 0;
257 | }
258 | .buttons {
259 | width: 100%;
260 | .v-button {
261 | display: block;
262 | text-align: center;
263 | }
264 | }
265 | }
266 | }
267 | }
268 |
269 | // hide the logo for a more compact header when the menu is narrow
270 | .v-ui[width-range~="801px-1100px"] .valo-menu-part {
271 | .v-slot-logo,
272 | .v-slot-logo + .v-spacing {
273 | display: none;
274 | }
275 | }
276 |
277 | // Move logout button to the bottom of the menu on large screens
278 | .v-ui[width-range~="801px-"] .valo-menu-part {
279 | .user-menu {
280 | position: fixed;
281 | bottom: 0;
282 | margin-bottom: 0;
283 | }
284 | }
285 |
286 | // Editor should take whole browser width when we are under 550px in width.
287 | .v-ui[width-range~="0-550px"] {
288 | .product-form-wrapper {
289 | width:100%;
290 | }
291 |
292 | // Remove margins around the grid and reduce top bar margins on small screens
293 | .crud-view .crud-main-layout {
294 | padding: 0 0 0 0;
295 |
296 | .top-bar {
297 | // Use spacing to the grid below as the margin - smaller than default margin
298 | padding: $v-layout-spacing-vertical $v-layout-spacing-horizontal 0 $v-layout-spacing-horizontal;
299 |
300 | .filter-textfield {
301 | width: 100%;
302 | }
303 | }
304 | }
305 |
306 | // About view fills the display on small screens
307 | .about-view {
308 | padding-bottom: 0;
309 | padding-top: 0;
310 | height: auto;
311 | padding: 0.1 * $v-unit-size;
312 |
313 | .v-slot-about-content {
314 | overflow: auto;
315 | }
316 |
317 | .about-content {
318 | width: 100%;
319 | max-width: 100%;
320 | height: auto;
321 | vertical-align: top;
322 | padding: 0;
323 | background: transparent;
324 | @include box-shadow(none);
325 | }
326 | }
327 | }
328 |
329 | // Override valo default narrow menu button on small screens to have the full logout text visible
330 | .v-ui[width-range~="0-500px"] {
331 | .valo-menu .v-menubar-user-menu .v-menubar-menuitem-caption {
332 | width: auto;
333 | }
334 | }
335 |
336 | // Hide spinner buttons from number input
337 | input[type=number]::-webkit-inner-spin-button,
338 | input[type=number]::-webkit-outer-spin-button {
339 | -webkit-appearance: none;
340 | margin: 0;
341 | }
342 |
343 | // For aligning in grid until #15438 is done
344 | .align-right {
345 | text-align: right;
346 | }
347 |
348 | }
349 |
--------------------------------------------------------------------------------
/mockapp-ui/src/main/webapp/VAADIN/themes/mockapp/styles.scss:
--------------------------------------------------------------------------------
1 | @import "mockapp.scss";
2 | @import "addons.scss";
3 |
4 | // This should be in the Valo theme as a shorthand
5 | $v-layout-margin: $v-layout-margin-top $v-layout-margin-right $v-layout-margin-bottom $v-layout-margin-left !default;
6 |
7 | // This file prefixes all rules with the theme name to avoid causing conflicts with other themes.
8 | // The actual styles should be defined in mockapp.scss
9 |
10 | .mockapp {
11 | @include addons;
12 | @include mockapp;
13 | }
14 |
--------------------------------------------------------------------------------
/mockapp-widgetset/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | mockapp-parent
6 | org.vaadin.maven.mockapp
7 | 1.0-SNAPSHOT
8 |
9 | 4.0.0
10 |
11 | mockapp-widgetset
12 | mockapp-widgetset
13 | jar
14 |
15 |
16 |
17 |
18 | com.vaadin
19 | vaadin-client
20 |
22 |
23 |
24 |
25 | com.vaadin
26 | vaadin-client-compiler
27 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 | com.vaadin
37 | vaadin-maven-plugin
38 |
39 | -Xmx512M -Xss1024k
40 | ${basedir}/target/classes/VAADIN/widgetsets
41 | true
42 | false
43 |
44 | true
45 |
46 |
47 |
48 |
49 | update-widgetset
50 | compile
51 |
52 |
53 |
54 |
55 |
56 | org.apache.maven.plugins
57 | maven-source-plugin
58 |
59 |
60 |
61 | jar
62 |
63 |
64 |
65 |
66 |
67 | org.apache.maven.plugins
68 | maven-jar-plugin
69 |
70 |
71 |
72 | 1
73 | org.vaadin.mockapp.MockAppWidgetset
74 |
75 |
76 |
78 |
79 | VAADIN/gwt-unitCache/**
80 | VAADIN/widgetsets/WEB-INF/**
81 |
82 |
83 |
84 |
85 |
86 |
87 |
89 |
91 |
92 | org.eclipse.m2e
93 | lifecycle-mapping
94 | 1.0.0
95 |
96 |
97 |
98 |
99 |
100 | com.vaadin
101 |
102 | vaadin-maven-plugin
103 |
104 |
105 | [7.1.11,)
106 |
107 |
108 | resources
109 |
110 | update-widgetset
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
--------------------------------------------------------------------------------
/mockapp-widgetset/src/main/java/org/vaadin/mockapp/client/samples/ResetButtonForTextFieldConnector.java:
--------------------------------------------------------------------------------
1 | package org.vaadin.mockapp.client.samples;
2 |
3 | import com.google.gwt.core.client.Scheduler;
4 | import com.google.gwt.dom.client.Element;
5 | import com.google.gwt.dom.client.Style;
6 | import com.google.gwt.event.dom.client.KeyUpEvent;
7 | import com.google.gwt.event.dom.client.KeyUpHandler;
8 | import com.google.gwt.event.logical.shared.AttachEvent;
9 | import com.google.gwt.user.client.DOM;
10 | import com.vaadin.client.ComponentConnector;
11 | import com.vaadin.client.ServerConnector;
12 | import com.vaadin.client.communication.StateChangeEvent;
13 | import com.vaadin.client.extensions.AbstractExtensionConnector;
14 | import com.vaadin.client.ui.VTextField;
15 | import com.vaadin.shared.ui.Connect;
16 | import org.vaadin.mockapp.samples.ResetButtonForTextField;
17 |
18 | /**
19 | * Client side implementation of {@link ResetButtonForTextField}.
20 | *
21 | * @see Extending components
22 | * in Vaadin 7
23 | */
24 | @Connect(ResetButtonForTextField.class)
25 | public class ResetButtonForTextFieldConnector extends
26 | AbstractExtensionConnector implements KeyUpHandler, AttachEvent.Handler {
27 |
28 | public static final String CLASSNAME = "resetbuttonfortextfield";
29 | private VTextField textField;
30 | private Element resetButtonElement;
31 |
32 | @Override
33 | protected void extend(ServerConnector serverConnector) {
34 | serverConnector
35 | .addStateChangeHandler(new StateChangeEvent.StateChangeHandler() {
36 | @Override
37 | public void onStateChanged(StateChangeEvent stateChangeEvent) {
38 | Scheduler.get().scheduleDeferred(
39 | new Scheduler.ScheduledCommand() {
40 | @Override
41 | public void execute() {
42 | updateResetButtonVisibility();
43 | }
44 | });
45 | }
46 | });
47 |
48 | textField = (VTextField) ((ComponentConnector) serverConnector)
49 | .getWidget();
50 | textField.addStyleName(CLASSNAME + "-textfield");
51 |
52 | resetButtonElement = DOM.createDiv();
53 | resetButtonElement.addClassName(CLASSNAME + "-resetbutton");
54 |
55 | textField.addAttachHandler(this);
56 | textField.addKeyUpHandler(this);
57 | }
58 |
59 | private void updateResetButtonVisibility() {
60 | if (textField.getValue().isEmpty()
61 | || textField.getStyleName().contains("v-textfield-prompt")) {
62 | resetButtonElement.getStyle().setDisplay(Style.Display.NONE);
63 | } else {
64 | resetButtonElement.getStyle().clearDisplay();
65 | }
66 | }
67 |
68 | public native void addResetButtonClickListener(Element el)
69 | /*-{
70 | var self = this;
71 | el.onclick = $entry(function () {
72 | self.@org.vaadin.mockapp.client.samples.ResetButtonForTextFieldConnector::clearTextField()();
73 | });
74 | }-*/;
75 |
76 | public native void removeResetButtonClickListener(Element el)
77 | /*-{
78 | el.onclick = null;
79 | }-*/;
80 |
81 | @Override
82 | public void onKeyUp(KeyUpEvent keyUpEvent) {
83 | updateResetButtonVisibility();
84 | }
85 |
86 | @Override
87 | public void onAttachOrDetach(AttachEvent attachEvent) {
88 | if (attachEvent.isAttached()) {
89 | textField.getElement().getParentElement()
90 | .insertAfter(resetButtonElement, textField.getElement());
91 | updateResetButtonVisibility();
92 | addResetButtonClickListener(resetButtonElement);
93 | } else {
94 | Element parentElement = resetButtonElement.getParentElement();
95 | if (parentElement != null) {
96 | parentElement.removeChild(resetButtonElement);
97 | }
98 | removeResetButtonClickListener(resetButtonElement);
99 | }
100 | }
101 |
102 | private void clearTextField() {
103 | textField.setValue("");
104 | textField.valueChange(true);
105 | updateResetButtonVisibility();
106 | textField.getElement().focus();
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/mockapp-widgetset/src/main/java/org/vaadin/mockapp/samples/AttributeExtension.java:
--------------------------------------------------------------------------------
1 | package org.vaadin.mockapp.samples;
2 |
3 | import com.vaadin.annotations.JavaScript;
4 | import com.vaadin.server.AbstractJavaScriptExtension;
5 | import com.vaadin.ui.TextField;
6 |
7 | /**
8 | * A JavaScript extension for adding arbitrary HTML attributes for components.
9 | */
10 | @JavaScript("attribute_extension_connector.js")
11 | public class AttributeExtension extends AbstractJavaScriptExtension {
12 |
13 | public void extend(TextField target) {
14 | super.extend(target);
15 | }
16 |
17 | @Override
18 | protected AttributeExtensionState getState() {
19 | return (AttributeExtensionState) super.getState();
20 | }
21 |
22 | public void setAttribute(String attribute, String value) {
23 | getState().attributes.put(attribute, value);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/mockapp-widgetset/src/main/java/org/vaadin/mockapp/samples/AttributeExtensionState.java:
--------------------------------------------------------------------------------
1 | package org.vaadin.mockapp.samples;
2 |
3 | import com.vaadin.shared.JavaScriptExtensionState;
4 |
5 | import java.util.HashMap;
6 |
7 | /**
8 | * Shared state class for {@link AttributeExtension} communication from server
9 | * to client.
10 | */
11 | public class AttributeExtensionState extends JavaScriptExtensionState {
12 | public HashMap attributes = new HashMap();
13 | }
14 |
--------------------------------------------------------------------------------
/mockapp-widgetset/src/main/java/org/vaadin/mockapp/samples/ResetButtonForTextField.java:
--------------------------------------------------------------------------------
1 | package org.vaadin.mockapp.samples;
2 |
3 | import com.vaadin.server.AbstractClientConnector;
4 | import com.vaadin.server.AbstractExtension;
5 | import com.vaadin.ui.TextField;
6 |
7 | /**
8 | * An extension adding a button in a text field for clearing the field. Only
9 | * shown when the text field is non-empty.
10 | *
11 | * @see Extending components
12 | * in Vaadin 7
13 | */
14 | public class ResetButtonForTextField extends AbstractExtension {
15 |
16 | public static void extend(TextField field) {
17 | new ResetButtonForTextField().extend((AbstractClientConnector) field);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/mockapp-widgetset/src/main/resources/org/vaadin/mockapp/MockAppWidgetset.gwt.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/mockapp-widgetset/src/main/resources/org/vaadin/mockapp/public/resetbuttonfortextfield/resetbutton-default.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vaadin/archetype-application-example/2aa89b8c56eccb41ce266f8ae7490c9bf3b3faff/mockapp-widgetset/src/main/resources/org/vaadin/mockapp/public/resetbuttonfortextfield/resetbutton-default.png
--------------------------------------------------------------------------------
/mockapp-widgetset/src/main/resources/org/vaadin/mockapp/public/resetbuttonfortextfield/resetbutton-default.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/mockapp-widgetset/src/main/resources/org/vaadin/mockapp/public/resetbuttonfortextfield/resetbutton-hover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vaadin/archetype-application-example/2aa89b8c56eccb41ce266f8ae7490c9bf3b3faff/mockapp-widgetset/src/main/resources/org/vaadin/mockapp/public/resetbuttonfortextfield/resetbutton-hover.png
--------------------------------------------------------------------------------
/mockapp-widgetset/src/main/resources/org/vaadin/mockapp/public/resetbuttonfortextfield/resetbutton-hover.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/mockapp-widgetset/src/main/resources/org/vaadin/mockapp/public/resetbuttonfortextfield/styles.css:
--------------------------------------------------------------------------------
1 | .resetbuttonfortextfield-textfield {
2 | padding-right: 16pt !important;
3 | }
4 |
5 | .resetbuttonfortextfield-resetbutton {
6 | position: relative;
7 | display: inline-block;
8 | vertical-align: middle;
9 | right: 18pt;
10 | margin-right: -18pt;
11 | cursor: pointer;
12 | width: 16px;
13 | height: 16px;
14 | background-image: url(resetbutton-default.svg);
15 | background-position: center center;
16 | background-repeat: no-repeat;
17 | }
18 |
19 | .resetbuttonfortextfield-resetbutton:hover {
20 | background-image: url(resetbutton-hover.svg);
21 | cursor: pointer;
22 | }
23 |
24 | .v-ie8 .resetbuttonfortextfield-resetbutton {
25 | background-image: url(resetbutton-default.png);
26 | }
27 |
28 | .v-ie8 .resetbuttonfortextfield-resetbutton:hover {
29 | background-image: url(resetbutton-hover.png);
30 | }
31 |
--------------------------------------------------------------------------------
/mockapp-widgetset/src/main/resources/org/vaadin/mockapp/samples/attribute_extension_connector.js:
--------------------------------------------------------------------------------
1 | window.org_vaadin_mockapp_samples_AttributeExtension = function() {
2 |
3 | this.onStateChange = function() {
4 | var element = this.getElement(this.getParentId());
5 | if (element) {
6 | var attributes = this.getState().attributes;
7 | for (var attr in attributes) {
8 | if (attributes.hasOwnProperty(attr)) {
9 | element.setAttribute(attr, attributes[attr]);
10 | }
11 | }
12 | }
13 | }
14 | }
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | org.vaadin.maven.mockapp
7 | mockapp-parent
8 | pom
9 | 1.0-SNAPSHOT
10 | mockapp-parent
11 |
12 |
13 |
14 | UNLICENSE
15 | http://unlicense.org/
16 | repo
17 |
18 |
19 |
20 |
21 | mockapp-widgetset
22 | mockapp-backend
23 | mockapp-ui
24 | mockapp-production
25 |
26 |
27 |
28 | 7.4.3
29 | ${vaadin.version}
30 | 9.2.3.v20140905
31 | 1.7
32 | 1.7
33 | UTF-8
34 |
35 |
36 |
37 |
38 |
39 | org.apache.maven.plugins
40 | maven-compiler-plugin
41 | 3.0
42 |
43 | ${project.encoding}
44 | ${project.source.version}
45 | ${project.target.version}
46 |
47 |
48 |
49 | org.apache.maven.plugins
50 | maven-resources-plugin
51 | 2.6
52 |
53 | ${project.encoding}
54 |
55 |
56 |
57 |
58 |
59 |
60 | org.apache.maven.plugins
61 | maven-war-plugin
62 | 2.3
63 |
64 | false
65 |
66 |
67 |
68 | com.vaadin
69 | vaadin-maven-plugin
70 | ${vaadin.plugin.version}
71 |
72 |
73 | org.apache.maven.plugins
74 | maven-jar-plugin
75 | 2.5
76 |
77 |
78 | org.apache.maven.plugins
79 | maven-source-plugin
80 | 2.4
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 | javax.servlet
90 | javax.servlet-api
91 | 3.0.1
92 | provided
93 |
94 |
95 | com.vaadin
96 | vaadin-bom
97 | ${vaadin.version}
98 | pom
99 | import
100 |
101 |
102 |
103 |
104 |
105 |
106 | vaadin-addons
107 | https://maven.vaadin.com/vaadin-addons
108 |
109 |
110 | vaadin-snapshots
111 | https://oss.sonatype.org/content/repositories/vaadin-snapshots/
112 |
113 | false
114 |
115 |
116 | true
117 |
118 |
119 |
120 |
121 |
122 |
--------------------------------------------------------------------------------