├── .gitignore ├── LICENSE ├── README.md ├── compile_readme_preview.bat ├── img ├── demo.png └── jasmine.png ├── pom.xml ├── vaangular-demo ├── VaangularApplication.launch ├── pom.xml └── src │ ├── main │ ├── java │ │ └── de │ │ │ └── akquinet │ │ │ └── engineering │ │ │ └── vaadin │ │ │ └── vaangular │ │ │ └── demo │ │ │ ├── VaangularApplication.java │ │ │ ├── VaangularServlet.java │ │ │ ├── VaangularUI.java │ │ │ └── weather │ │ │ └── Weather.java │ └── resources │ │ ├── application.properties │ │ └── de │ │ └── akquinet │ │ └── engineering │ │ └── vaadin │ │ └── vaangular │ │ └── demo │ │ └── weather │ │ ├── weather.html │ │ └── weather.js │ └── test │ └── resources │ └── de │ └── akquinet │ └── engineering │ └── vaadin │ └── vaangular │ └── demo │ └── weathertest │ ├── weatherSpec.js │ └── weatherTest.html └── vaangular ├── assembly ├── MANIFEST.MF └── assembly.xml ├── pom.xml └── src ├── main ├── java │ └── de │ │ └── akquinet │ │ └── engineering │ │ └── vaadin │ │ └── vaangular │ │ └── angular │ │ ├── MethodInvoker.java │ │ ├── NgTemplate.java │ │ ├── NgTemplatePlus.java │ │ ├── NgTemplateState.java │ │ └── ServiceMethod.java └── resources │ └── de │ └── akquinet │ └── engineering │ └── vaadin │ └── vaangular │ └── angular │ └── NgTemplate.js └── test ├── java └── de │ └── akquinet │ └── engineering │ └── vaadin │ └── vaangular │ └── angular │ ├── MethodInvokerTest.java │ ├── NgTemplatePlusTest.java │ └── NgTemplateTest.java └── resources └── de └── akquinet └── engineering └── vaadin └── vaangular └── angular └── angular.html /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | 3 | # Mobile Tools for Java (J2ME) 4 | .mtj.tmp/ 5 | 6 | # Package Files # 7 | *.jar 8 | *.war 9 | *.ear 10 | 11 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 12 | hs_err_pid* 13 | 14 | # Eclipse 15 | .project 16 | .classpath 17 | .settings 18 | target 19 | 20 | README.html 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | vaangular 2 | ========= 3 | 4 | Provide stellar integration of AngularJS with vaadin. 5 | 6 | ## What is vaangular? 7 | vaangular combines the power of [vaadin](https://vaadin.com) and Java with the power of [AngularJS](https://angularjs.org) to create awesome UIs. 8 | 9 | Some reasons why you might want to do that: 10 | - mix and match skill within your team 11 | - increase responsiveness (by doing client-side logic) 12 | - re-use existing AngularJS-based assets 13 | - have an alternative to custom GWT development 14 | 15 | you don't have to do any GWT development. Check out all necessary steps below. 16 | 17 | ## How does it work? (examples, please!) 18 | 19 | Effectively, you create three things: 20 | 1. an HTML fragment with AngularJS attributes and directives in it 21 | 2. an AngularJS controller (along with tests in e.g. Jasmine) 22 | 3. a vaadin component to hook up the previous two with the backend 23 | 24 | vaangular makes extensive use `com.vaadin.ui.AbstractJavaScriptComponent` and adds additional logic to bridge vaadin *states* with AngularJS *$scope(s)*. If you want, you can combine the [JavaScriptPlus for vaadin](https://github.com/akquinet/JavascriptPlusForvaadin) add-on with this add-on to use deferred variable changes in AngularJS. 25 | 26 | A comprehensive demo is included that shows the full roundtrip (see the `vaangular-demo` folder for all the code - you can fire off this example by running `de.akquinet.engineering.vaadin.vaangular.demo.VaangularApplication.main` which invokes Spring Boot, pulls up a server and offers you an endpoint at `localhost:8090`) 27 | 28 | We'll use this as an example throughout the page... (it's best viewed in Webkit = Chrome / Safari btw.) 29 | 30 | Here's what the example looks like: 31 | 32 | Screenshot of the weather application as explained in 'en detail' below 33 | 34 | En detail: the current weather (1) is displayed depending on the slider position (2) - this happens without server roundtrips (pure AngularJS). When clicking a 100%-vaadin-like AngularJS-button (3) or a standard-vaadin-button (4), you get a popup window (5) - this happens in vaadin (so there is a seamless integration between those two). 35 | 36 | ## Running the example from source 37 | 38 | You can run the example via 39 | 40 | ``` 41 | mvn exec:java -Dexec.mainClass="de.akquinet.engineering.vaadin.vaangular.demo.VaangularApplication" 42 | ``` 43 | from ```vaangular-demo``` 44 | 45 | ## Creating a component 46 | 47 | ### Project structure 48 | 49 | We recommend using [Maven](http://maven.apache.org) as build tool - which results into src/main/java, src/main/resources, etc. as base directory structure along with a pom.xml 50 | 51 | Furthermore, you can utilize Spring Boot, Eclipse, etc. (what our example does) 52 | 53 | ### Creating the package 54 | 55 | Create a package (with identical names) in both src/main/java and src/main/resources - in our example: `de.akquinet.engineering.vaadin.vaangular.demo.weather` 56 | 57 | ### Creating the HTML fragment 58 | 59 | Create an HTML file with the same name as the last part of the package (here: 'weather') ending with '.html'. The file can contain any markup as long as there is exactly one topmost tag. 60 | 61 | So, your 'weather.html' can initially look like this: 62 | ```html 63 |
64 |
65 | 66 |
67 |
68 |
{{zeit}}
:00 69 |
70 |
71 | 72 |
73 | 74 | {{userState.buttonCaption}} 75 | 76 |
77 |
78 | ``` 79 | 80 | What it does is: 81 | - declare a div to take up some dynamic values (rendered by *content()*) 82 | - create a range input field 83 | - create some labels below (yes, inline styling is bad, but verbose examples are, too) 84 | - provide a button in AngularJS that looks exactly like a button in vaadin 85 | 86 | ### Creating the AngularJS controller 87 | 88 | Obviously, our file also needs a controller which mainly needs to do two things: 89 | - render the content based on where the slider is (we use inline HTML via ngSanitize) 90 | - move the slider upon label click 91 | - make the slider pos available to vaadin (we use deferred variable changes via `setDeferredVariable` - more explanation can be found in the next section) 92 | - invoke some action on button click (i.e. call logic implemented in vaadin) 93 | 94 | ```javascript 95 | angular.module('weatherModule', ['ngSanitize']) 96 | .controller('WeatherController', function($scope, $connector, $sce) { 97 | $scope.sliderPos = 0; 98 | $scope.content = function() { 99 | var res = $scope.userState.entries[$scope.sliderPos]; 100 | return $sce.trustAsHtml(res); 101 | }; 102 | $scope.moveSlider = function(val) { 103 | $scope.sliderPos = val; 104 | $scope.sliderUpdated(); 105 | }; 106 | $scope.sliderUpdated = function() { 107 | $connector.setDeferredVariable("sliderPos", parseInt($scope.sliderPos)); 108 | }; 109 | $scope.clickButton = function() { 110 | $connector.button_click(); 111 | }; 112 | }); 113 | ``` 114 | 115 | There is also a Jasmine test in place for that - you can open */vaangular-demo/src/test/resources/de/akquinet/engineering/vaadin/vaangular/demo/weathertest/weatherTest.html* in a browser to view it (be sure to run `mvn package` once before so all resources are available). A successful run then looks like this: 116 | 117 | Four green test suites in Jasmine 118 | 119 | Nothing so far is mysterious - except that we use `$scope.userState` that seemingly comes out of nowhere. In fact, it is all the data vaadin ships to us - at our fingertips. How you fill the user state is actually explained right below: 120 | 121 | ### Providing a counterpart in vaadin (extending NgTemplate or NgTemplatePlus) 122 | 123 | So what we're still missing from above example is 124 | - filling `$scope.userState` 125 | - something to do with `sliderPos` 126 | - an implementation for `$connector.button_click()` 127 | 128 | In order to do that, there has to be a class `de.akquinet.engineering.vaadin.vaangular.demo.weather.Weather` extending `de.akquinet.engineering.vaadin.vaangular.angular.NgTemplate(Plus)` 129 | 130 | When extending `NgTemplatePlus` (that comes with the [JavaScriptPlus for vaadin](https://github.com/akquinet/JavascriptPlusForvaadin) add-on), you can use deferred variable changes: No call to the server is made until some button click or other (non-deferred) action happens. This dramatically increases responsiveness while reducing (unnecessary) network roundtrips and bandwidth usage. Many standard vaadin components provide this exact behavior via `immediate=false`. 131 | 132 | With this many advantages of deferred variable changes: our example uses those and therefore has to use either a custom widgetset or the pre-compiled widgeset coming with the [JavaScriptPlus for vaadin](https://github.com/akquinet/JavascriptPlusForvaadin) add-on (we do the latter). 133 | 134 | To fill up the user state with some times and weather infos, we provide the following method: 135 | ```java 136 | public void setDaten(int[] times, String[] entries) { 137 | validateParameters(times, entries); 138 | this.times = times; 139 | this.entries = entries; 140 | setUserState("times", times); 141 | setUserState("entries", entries); 142 | markAsDirty(); 143 | } 144 | ``` 145 | 146 | `setUserState` is provided by NgTemplate / NgTemplatePlus: adding `xyz` to it results in `$scope.userState.xyz` on the client - so `times` results in `$scope.userState.times`. Please observe that changes to this state on the client are not replicated back and overwritten without notice (the standard vaadin behavior). In order to get info from the client to the server, you can either use a method invocation or (provided you use NgTemplatePlus) a deferred variable change. So far, for providing infos to the client, `setUserState`is perfectly OK. 147 | 148 | To work with the slider position (`sliderPos`), we use 149 | 150 | ```javascript 151 | $connector.setDeferredVariable("sliderPos", parseInt($scope.sliderPos)); 152 | ``` 153 | 154 | on the JavaScript side. On the Java side, we can pull this as follows: 155 | 156 | ```java 157 | public int getSliderPos() { 158 | return Integer.parseInt(getVariables().get("sliderPos").toString()); 159 | } 160 | ``` 161 | 162 | As the variable change is deferred, no sync to the server happens before a button click. Our example provides a standard vaadin button (`de.akquinet.engineering.vaadin.vaangular.demo.VaangularUI.javaSend`) which (when clicked) shows the currently selected weather info. The following code on click does this: 163 | 164 | ```java 165 | javaSend.addClickListener(new ClickListener() { 166 | 167 | private static final long serialVersionUID = 1L; 168 | 169 | @Override 170 | public void buttonClick(ClickEvent event) { 171 | int index = weatherInfo.getSliderPos(); 172 | System.out.println("Button from w/in Java - value: " + index); 173 | showPopup(entries[index]); 174 | } 175 | }); 176 | ``` 177 | 178 | Upon clicking the button, vaadin does a server roundtrip (as it usually does for buttons). vaadin first processes the deferred variable changes (which is why `de.akquinet.engineering.vaadin.vaangular.angular.NgTemplatePlus.getVariables` yields a correct, up-to-date value) and the invokes the click listener. 179 | 180 | When you open the demo application (along with the Chrome inspector's Network tab), you don't see any server roundtrip when clicking or moving the slider. Only clicking the *E-Mail (from Java)* button produces one. 181 | 182 | Finally, we also want so show how to call the server *immediately* (and how to create a vaadin-like button in pure JavaScript): the *E-Mail (from angular)* is written in AngularJS and invokes vaadin via the following line: 183 | 184 | ```javascript 185 | $connector.button_click(); 186 | ``` 187 | 188 | On the Java side, we provide a counterpart for this as follows: 189 | 190 | ```java 191 | addService("button", new Object() { 192 | @ServiceMethod 193 | public void click() { 194 | int index = getSliderPos(); 195 | System.out.println("Button from w/in angular - value: " + index); 196 | for (WeatherClickListener listener : listeners) { 197 | listener.click(times[index], entries[index]); 198 | } 199 | } 200 | }); 201 | ``` 202 | 203 | We register such a listener to again display the pop-up. 204 | 205 | So: any class can provide methods to the AngularJS-side as long as their methods are *public* and annotated with `@ServiceMethod` (in fact: `de.akquinet.engineering.vaadin.vaangular.angular.ServiceMethod`). Clicking the button now results in the Java method being called (again with deferred variable changes processed before that). 206 | 207 | ### Getting data from vaadin to AngularJS 208 | 209 | Done by calling `de.akquinet.engineering.vaadin.vaangular.angular.NgTemplatePlus.setUserState(String, Object)` (2nd param must be something that can be turned into JSON). Angular then gets it via `$scope.userState` 210 | 211 | ### Calling vaadin from AngularJS 212 | 213 | Done by calling `de.akquinet.engineering.vaadin.vaangular.angular.NgTemplatePlus.addService(String, Object)` with the 2nd parameter being an implementing a service. Methods to be exposed need to have params that can be derived from JSON and have to be annotated with `@ServiceMethod`. Call from JavaScript via `$connector.service_method` 214 | 215 | ### Deferred variable changes 216 | 217 | Done by calling `$connector.setDeferredVariable` on the JavaScript side (the value will be JSON-serialized). Only available with NgTemplatePlus. 218 | 219 | ## Background 220 | 221 | vaangular solves two essential (and non-obvious) problems: 222 | 1. Delivering JavaScript in a pluggable fashion 223 | 2. Creating an AngularJS *$scope* along with a Controller in it that gets data from vaadin and can communicate back to vaadin 224 | 225 | ### Delivering JavaScript (using @JavaScript) 226 | 227 | vaadin provides a standard method for this via the `@JavaScript` annotation (`com.vaadin.annotations.JavaScript`). In order to include AngularJS, one can e.g. use [WebJars](http://www.webjars.org/) or simply check in the file along with the project. 228 | 229 | ### Creating the AngularJS *$scope* 230 | 231 | The main magic that happens within `NgTemplate.js` is creating a *$scope* for AngularJS. There is one essential challenge: the JavaScript invoked by vaadin is **outside** any AngularJS dependency injection or scope management. Meanwhile, all code you write for AngularJS is obviously **inside** dependency injection and scope management. 232 | 233 | Furthermore, AngularJS assumes (at least per se) that the page's HTML is parsed once and wired up to AngularJS. With vaadin, however, the page's HTML is just some proxy to fire up vaadin magic, and there is nothing to wire up. Even more so, the part with AngularJS in it might be added to a vaadin UI a considerable amount of time after the application was started. 234 | 235 | So, what is needed is an approach to create some new AngularJS-wired-up DOM and Controller on demand from outside AngularJS dependency management / scoping magic. 236 | 237 | vaangular achieves this (in bespoke `NgTemplate.js`) in two steps: 238 | 239 | First, a scope **within** AngularJS is created via 240 | ```javascript 241 | angular.injector([ 'ng', innerModuleName ]).invoke(function($compile, $rootScope) { 242 | ``` 243 | 244 | Second, the scope (called `scpe`) and DOM are brought together via 245 | ```javascript 246 | var cmp = $compile(templateElement); 247 | cmp(scpe); 248 | scpe.$digest(); 249 | ``` 250 | 251 | At the end of this process, we have a new part of the DOM wired up to a new controller - mission accomplished! 252 | -------------------------------------------------------------------------------- /compile_readme_preview.bat: -------------------------------------------------------------------------------- 1 | pandoc README.md -o README.html -f markdown_github -------------------------------------------------------------------------------- /img/demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akquinet/vaangular/deff1191ce81bbe0a1d342f8524b4c9d69588433/img/demo.png -------------------------------------------------------------------------------- /img/jasmine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akquinet/vaangular/deff1191ce81bbe0a1d342f8524b4c9d69588433/img/jasmine.png -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 20 | 4.0.0 21 | 22 | de.akquinet.engineering.vaadin.vaangular 23 | vaangular-parent 24 | 0.1.3-SNAPSHOT 25 | pom 26 | 27 | 33 | 34 | 35 | vaangular 36 | vaangular-demo 37 | 38 | 39 | 119 | 120 | 121 | -------------------------------------------------------------------------------- /vaangular-demo/VaangularApplication.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /vaangular-demo/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 20 | 26 | 27 | 4.0.0 28 | 29 | de.akquinet.engineering.vaadin.vaangular 30 | vaangular-demo 31 | 32 | 0.1.3-SNAPSHOT 33 | 34 | 35 | 1.2.1.RELEASE 36 | 37 | UTF-8 38 | 7.7.3 39 | 2.2.4 40 | 41 | 42 | 43 | 44 | de.akquinet.engineering.vaadin.vaangular 45 | vaangular 46 | ${project.version} 47 | 48 | 49 | de.akquinet.engineering 50 | javascriptplus-for-vaadin 51 | 52 | 54 | 0.1.2 55 | 56 | 57 | org.springframework.boot 58 | spring-boot-starter 59 | ${spring-boot.version} 60 | 61 | 62 | org.springframework.boot 63 | spring-boot-starter-web 64 | ${spring-boot.version} 65 | 66 | 67 | org.springframework.boot 68 | spring-boot-starter-jetty 69 | ${spring-boot.version} 70 | 71 | 72 | org.springframework.boot 73 | spring-boot-starter-actuator 74 | ${spring-boot.version} 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | org.apache.maven.plugins 84 | maven-compiler-plugin 85 | 2.3.2 86 | 87 | 1.8 88 | 1.8 89 | UTF-8 90 | 91 | 92 | 93 | 94 | org.apache.maven.plugins 95 | maven-resources-plugin 96 | 2.6 97 | 98 | UTF-8 99 | 100 | 101 | 102 | 103 | com.vaadin 104 | vaadin-maven-plugin 105 | ${vaadin.version} 106 | 107 | ${project.build.directory}/${project.build.finalName}stage/VAADIN/widgetsets 108 | -Xmx512M -Xss1024k 109 | true 110 | 111 | 112 | 113 | 114 | resources 115 | compile 116 | 117 | 118 | 119 | 120 | 121 | 122 | org.apache.maven.plugins 123 | maven-dependency-plugin 124 | 2.10 125 | 126 | 127 | unpack 128 | generate-resources 129 | 130 | unpack 131 | 132 | 133 | 134 | 135 | org.webjars 136 | angularjs 137 | 1.3.15 138 | jar 139 | META-INF/resources/webjars/angularjs/1.3.15/**/* 140 | ${project.build.directory}/jsunpack/de/akquinet/engineering/vaadin/vaangular/demo/weather 141 | 142 | 143 | 144 | 145 | 146 | unpackTest 147 | generate-test-resources 148 | 149 | unpack 150 | 151 | 152 | 153 | 154 | org.webjars 155 | jasmine 156 | 2.2.0 157 | jar 158 | META-INF/resources/webjars/jasmine/2.2.0/**/* 159 | ${project.build.directory}/jsunpackTest/de/akquinet/engineering/vaadin/vaangular/demo/weathertest 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | src/main/resources 170 | 171 | 172 | ${project.build.directory}/jsunpack 173 | false 174 | 175 | 176 | 177 | 178 | src/test/resources 179 | 180 | 181 | ${project.build.directory}/jsunpackTest 182 | false 183 | 184 | 185 | 186 | 187 | 188 | 189 | vaadin-addons 190 | http://maven.vaadin.com/vaadin-addons 191 | 192 | 193 | 194 | 195 | -------------------------------------------------------------------------------- /vaangular-demo/src/main/java/de/akquinet/engineering/vaadin/vaangular/demo/VaangularApplication.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 akquinet engineering GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | package de.akquinet.engineering.vaadin.vaangular.demo; 17 | 18 | import javax.servlet.Servlet; 19 | 20 | import org.springframework.boot.SpringApplication; 21 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 22 | import org.springframework.boot.builder.SpringApplicationBuilder; 23 | import org.springframework.boot.context.embedded.RegistrationBean; 24 | import org.springframework.boot.context.embedded.ServletRegistrationBean; 25 | import org.springframework.boot.context.web.SpringBootServletInitializer; 26 | import org.springframework.context.ApplicationContext; 27 | import org.springframework.context.annotation.Bean; 28 | import org.springframework.context.annotation.ComponentScan; 29 | import org.springframework.context.annotation.Configuration; 30 | 31 | @Configuration 32 | @ComponentScan 33 | @EnableAutoConfiguration 34 | public class VaangularApplication extends SpringBootServletInitializer 35 | { 36 | 37 | @Bean 38 | public RegistrationBean vaangularServlet(final ApplicationContext context) 39 | { 40 | final Servlet servlet = new VaangularServlet(); 41 | return new ServletRegistrationBean(servlet, "/*"); 42 | } 43 | 44 | @Override 45 | protected SpringApplicationBuilder configure(final SpringApplicationBuilder application) 46 | { 47 | return application.sources(VaangularApplication.class); 48 | } 49 | 50 | public static void main(final String... args) 51 | { 52 | SpringApplication.run(VaangularApplication.class, args); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /vaangular-demo/src/main/java/de/akquinet/engineering/vaadin/vaangular/demo/VaangularServlet.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 akquinet engineering GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | package de.akquinet.engineering.vaadin.vaangular.demo; 17 | 18 | import javax.servlet.annotation.WebServlet; 19 | 20 | import com.vaadin.annotations.VaadinServletConfiguration; 21 | import com.vaadin.server.VaadinServlet; 22 | 23 | @WebServlet() 24 | @VaadinServletConfiguration(ui = VaangularUI.class, productionMode = false, widgetset = "de.akquinet.engineering.vaadin.javascriptplus.JavaScriptPlusForVaadin") 25 | public class VaangularServlet extends VaadinServlet { 26 | 27 | private static final long serialVersionUID = 1L; 28 | 29 | } 30 | -------------------------------------------------------------------------------- /vaangular-demo/src/main/java/de/akquinet/engineering/vaadin/vaangular/demo/VaangularUI.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 akquinet engineering GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | package de.akquinet.engineering.vaadin.vaangular.demo; 17 | 18 | import com.vaadin.annotations.PreserveOnRefresh; 19 | import com.vaadin.annotations.Theme; 20 | import com.vaadin.server.VaadinRequest; 21 | import com.vaadin.shared.ui.label.ContentMode; 22 | import com.vaadin.ui.Accordion; 23 | import com.vaadin.ui.Button; 24 | import com.vaadin.ui.Button.ClickEvent; 25 | import com.vaadin.ui.Button.ClickListener; 26 | import com.vaadin.ui.Label; 27 | import com.vaadin.ui.UI; 28 | import com.vaadin.ui.VerticalLayout; 29 | import com.vaadin.ui.Window; 30 | 31 | import de.akquinet.engineering.vaadin.vaangular.demo.weather.Weather; 32 | import de.akquinet.engineering.vaadin.vaangular.demo.weather.Weather.WeatherClickListener; 33 | 34 | @Theme("valo") 35 | @PreserveOnRefresh 36 | public class VaangularUI extends UI { 37 | 38 | private static final long serialVersionUID = 1L; 39 | 40 | protected Weather weatherInfo; 41 | protected Button javaSend; 42 | 43 | /* 44 | * (non-Javadoc) 45 | * 46 | * @see com.vaadin.ui.UI#init(com.vaadin.server.VaadinRequest) 47 | */ 48 | @Override 49 | protected void init(VaadinRequest request) { 50 | 51 | try { 52 | 53 | VerticalLayout mainLayout = new VerticalLayout(); 54 | mainLayout.setMargin(true); 55 | mainLayout.setSpacing(true); 56 | Accordion accordion = new Accordion(); 57 | 58 | weatherInfo = new Weather(); 59 | final int[] times = new int[] { 10, 12, 14, 16 }; 60 | final String[] entries = new String[] { 61 | "10° sunny", "12° windy", 62 | "14° cold", "20° superb" }; 63 | weatherInfo.setDaten(times, entries); 64 | weatherInfo.addClickListener(new WeatherClickListener() { 65 | 66 | private static final long serialVersionUID = 1L; 67 | 68 | @Override 69 | public void click(int time, String entry) { 70 | showPopup(entry); 71 | } 72 | }); 73 | weatherInfo.setButtonCaption("E-Mail (from angular)"); 74 | accordion.addTab(weatherInfo, "Weather-Demo"); 75 | mainLayout.addComponent(accordion); 76 | 77 | javaSend = new Button(); 78 | javaSend.setCaption("E-Mail (from Java)"); 79 | javaSend.addClickListener(new ClickListener() { 80 | 81 | private static final long serialVersionUID = 1L; 82 | 83 | @Override 84 | public void buttonClick(ClickEvent event) { 85 | int index = weatherInfo.getSliderPos(); 86 | System.out.println("Button from w/in Java - value: " 87 | + index); 88 | showPopup(entries[index]); 89 | } 90 | }); 91 | mainLayout.addComponent(javaSend); 92 | 93 | setContent(mainLayout); 94 | } catch (Exception e) { 95 | throw new RuntimeException("some stupid error occured!", e); 96 | } 97 | } 98 | 99 | private void showPopup(String eintrag) { 100 | Window modalWin = new Window("E-Mail is being sent..."); 101 | modalWin.setContent(new Label("
" 102 | + "

Season's greetings

" + "

" + eintrag + "

" 103 | + "
", ContentMode.HTML)); 104 | modalWin.setModal(true); 105 | modalWin.setWidth("400px"); 106 | modalWin.setHeight("250px"); 107 | modalWin.center(); 108 | UI.getCurrent().addWindow(modalWin); 109 | } 110 | 111 | } 112 | -------------------------------------------------------------------------------- /vaangular-demo/src/main/java/de/akquinet/engineering/vaadin/vaangular/demo/weather/Weather.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 akquinet engineering GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | package de.akquinet.engineering.vaadin.vaangular.demo.weather; 17 | 18 | import java.io.IOException; 19 | import java.net.URISyntaxException; 20 | import java.util.ArrayList; 21 | import java.util.List; 22 | 23 | import com.vaadin.annotations.JavaScript; 24 | import com.vaadin.event.ConnectorEventListener; 25 | 26 | import de.akquinet.engineering.vaadin.vaangular.angular.NgTemplatePlus; 27 | import de.akquinet.engineering.vaadin.vaangular.angular.ServiceMethod; 28 | 29 | @JavaScript({ "META-INF/resources/webjars/angularjs/1.3.15/angular.js", 30 | "META-INF/resources/webjars/angularjs/1.3.15/angular-sanitize.js", 31 | "weather.js" }) 32 | public class Weather extends NgTemplatePlus { 33 | 34 | /** 35 | * 36 | */ 37 | private static final long serialVersionUID = -1857536974366619130L; 38 | 39 | private List listeners = new ArrayList(); 40 | 41 | private int[] times; 42 | private String[] entries; 43 | 44 | public Weather() throws IOException, URISyntaxException { 45 | super(Weather.class.getPackage(), "weatherModule"); 46 | addService("button", new Object() { 47 | @ServiceMethod 48 | public void click() { 49 | int index = getSliderPos(); 50 | System.out 51 | .println("Button from w/in angular - value: " + index); 52 | for (WeatherClickListener listener : listeners) { 53 | listener.click(times[index], entries[index]); 54 | } 55 | } 56 | }); 57 | setButtonCaption("senden"); 58 | } 59 | 60 | public void setButtonCaption(String caption) { 61 | setUserState("buttonCaption", caption); 62 | } 63 | 64 | public int getSliderPos() { 65 | return Integer.parseInt(getVariables().get("sliderPos").toString()); 66 | } 67 | 68 | public void setDaten(int[] times, String[] entries) { 69 | validateParameters(times, entries); 70 | this.times = times; 71 | this.entries = entries; 72 | setUserState("times", times); 73 | setUserState("entries", entries); 74 | markAsDirty(); 75 | } 76 | 77 | static void validateParameters(int[] times, String[] entries) { 78 | if (times.length != entries.length) { 79 | throw new IllegalArgumentException("#times does not match #entries"); 80 | } 81 | if (times.length < 2) { 82 | throw new IllegalArgumentException( 83 | "#times/#entries needs to be >=2"); 84 | } 85 | int step = calcStep(times); 86 | for (int i = 1; i < times.length; i++) { 87 | if (!(times[i - 1] < times[i])) { 88 | throw new IllegalArgumentException("Times must be in order"); 89 | } 90 | if ((times[i] - times[i - 1]) != step) { 91 | throw new IllegalArgumentException( 92 | "Times must have same delta between one another"); 93 | } 94 | } 95 | } 96 | 97 | private static int calcStep(int[] times) { 98 | int step = times[1] - times[0]; 99 | return step; 100 | } 101 | 102 | public void addClickListener(WeatherClickListener listener) { 103 | listeners.add(listener); 104 | } 105 | 106 | public void removeClickListener(WeatherClickListener listener) { 107 | listeners.remove(listener); 108 | } 109 | 110 | public interface WeatherClickListener extends ConnectorEventListener { 111 | 112 | public void click(int time, String entry); 113 | } 114 | 115 | } 116 | -------------------------------------------------------------------------------- /vaangular-demo/src/main/resources/application.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akquinet/vaangular/deff1191ce81bbe0a1d342f8524b4c9d69588433/vaangular-demo/src/main/resources/application.properties -------------------------------------------------------------------------------- /vaangular-demo/src/main/resources/de/akquinet/engineering/vaadin/vaangular/demo/weather/weather.html: -------------------------------------------------------------------------------- 1 | 16 |
17 |
18 | 19 |
20 |
21 |
{{zeit}}
:00 22 |
23 |
24 | 25 |
26 | 27 | {{userState.buttonCaption}} 28 | 29 |
30 |
-------------------------------------------------------------------------------- /vaangular-demo/src/main/resources/de/akquinet/engineering/vaadin/vaangular/demo/weather/weather.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 akquinet engineering GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | angular.module('weatherModule', ['ngSanitize']) 17 | .controller('WeatherController', function($scope, $connector, $sce) { 18 | $scope.sliderPos = 0; 19 | $scope.content = function() { 20 | var res = $scope.userState.entries[$scope.sliderPos]; 21 | return $sce.trustAsHtml(res); 22 | }; 23 | $scope.moveSlider = function(val) { 24 | $scope.sliderPos = val; 25 | $scope.sliderUpdated(); 26 | }; 27 | $scope.sliderUpdated = function() { 28 | $connector.setDeferredVariable("sliderPos", parseInt($scope.sliderPos)); 29 | }; 30 | $scope.clickButton = function() { 31 | $connector.button_click(); 32 | }; 33 | }); -------------------------------------------------------------------------------- /vaangular-demo/src/test/resources/de/akquinet/engineering/vaadin/vaangular/demo/weathertest/weatherSpec.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 akquinet engineering GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | describe("Weather base suite", function() { 17 | var $rootScope, $connector, $sce, createController; 18 | beforeEach(module("weatherModule")); 19 | beforeEach(inject(function($injector) { 20 | $rootScope = $injector.get('$rootScope'); 21 | $rootScope.userState={}; 22 | $connector = { 23 | setDeferredVariable : function() { 24 | }, 25 | button_click : function() { 26 | } 27 | }; 28 | $sce = { 29 | trustAsHtml : function(str){ 30 | return str; 31 | } 32 | }; 33 | var $controller = $injector.get('$controller'); 34 | createController = function() { 35 | return $controller('WeatherController', { 36 | '$scope' : $rootScope, 37 | '$connector' : $connector, 38 | '$sce' : $sce 39 | }); 40 | }; 41 | })); 42 | it("displays initial content", function() { 43 | var controller = createController(); 44 | $rootScope.sliderPos = 2; 45 | $rootScope.userState.entries = [ "zero", "one", "two", "three" ]; 46 | expect($rootScope.content()).toEqual("two"); 47 | }); 48 | it("displays content based on slider", function() { 49 | var controller = createController(); 50 | $rootScope.sliderPos = 2; 51 | $rootScope.userState.entries = [ "zero", "one", "two", "three" ]; 52 | spyOn($connector, 'setDeferredVariable'); 53 | $rootScope.moveSlider(1); 54 | expect($rootScope.content()).toEqual("one"); 55 | expect($connector.setDeferredVariable).toHaveBeenCalledWith("sliderPos", 1); 56 | }); 57 | it("reacts on slider change", function() { 58 | var controller = createController(); 59 | $rootScope.sliderPos = 2; 60 | $rootScope.userState.entries = [ "zero", "one", "two", "three" ]; 61 | spyOn($connector, 'setDeferredVariable'); 62 | $rootScope.sliderPos = 1; 63 | $rootScope.sliderUpdated(); 64 | expect($rootScope.content()).toEqual("one"); 65 | expect($connector.setDeferredVariable).toHaveBeenCalledWith("sliderPos", 1); 66 | }); 67 | it("button calls to vaadin", function() { 68 | var controller = createController(); 69 | spyOn($connector, 'button_click'); 70 | $rootScope.clickButton(); 71 | expect($connector.button_click).toHaveBeenCalled(); 72 | }); 73 | }); -------------------------------------------------------------------------------- /vaangular-demo/src/test/resources/de/akquinet/engineering/vaadin/vaangular/demo/weathertest/weatherTest.html: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | Jasmine Spec Runner v2.0.0 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /vaangular/assembly/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Vaadin-Package-Version: 1 3 | Vaadin-Addon: ${vaadin.addon} 4 | Vaadin-License-Title: ${vaadin.license.title} 5 | Implementation-Vendor: ${implementation.vendor} 6 | Implementation-Title: ${implementation.title} 7 | Implementation-Version: ${implementation.version} 8 | -------------------------------------------------------------------------------- /vaangular/assembly/assembly.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 21 | addon 22 | 23 | 24 | zip 25 | 26 | 27 | false 28 | 29 | 30 | 31 | .. 32 | 33 | LICENSE 34 | README.md 35 | 36 | 37 | 38 | target 39 | 40 | 41 | *.jar 42 | 43 | 44 | 45 | 46 | 47 | 48 | assembly/MANIFEST.MF 49 | META-INF 50 | true 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /vaangular/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 20 | 26 | 27 | 4.0.0 28 | 29 | de.akquinet.engineering.vaadin.vaangular 30 | vaangular 31 | 32 | 0.1.3-SNAPSHOT 33 | 34 | 35 | ${project.version} 36 | vaangular 37 | akquinet engineering GmbH 38 | Apache License Version 2.0 39 | ${project.artifactId}-${project.version}.jar 40 | 41 | UTF-8 42 | 7.7.3 43 | 2.2.4 44 | 45 | 46 | 47 | 48 | 49 | com.vaadin 50 | vaadin-server 51 | 52 | ${vaadin.version} 53 | 54 | 55 | com.vaadin 56 | vaadin-themes 57 | 58 | ${vaadin.version} 59 | 60 | 61 | 62 | com.google.code.gson 63 | gson 64 | 65 | ${gson.version} 66 | 67 | 68 | 69 | de.akquinet.engineering 70 | javascriptplus-for-vaadin 71 | true 72 | 73 | 0.1.3-SNAPSHOT 74 | 75 | 76 | 77 | junit 78 | junit 79 | test 80 | 81 | 4.10 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | org.apache.maven.plugins 92 | maven-compiler-plugin 93 | 2.3.2 94 | 95 | 1.8 96 | 1.8 97 | UTF-8 98 | 99 | 100 | 101 | 102 | org.apache.maven.plugins 103 | maven-resources-plugin 104 | 2.6 105 | 106 | UTF-8 107 | 108 | 109 | 110 | 111 | com.vaadin 112 | vaadin-maven-plugin 113 | ${vaadin.version} 114 | 115 | ${project.build.directory}/${project.build.finalName}stage/VAADIN/widgetsets 116 | -Xmx512M -Xss1024k 117 | true 118 | 119 | 120 | 121 | 122 | resources 123 | compile 124 | 125 | 126 | 127 | 128 | 129 | 130 | org.apache.maven.plugins 131 | maven-jar-plugin 132 | 2.5 133 | 134 | 135 | true 136 | 137 | true 138 | 139 | 140 | 141 | 1 142 | ${implementation.title} 143 | ${vaadin.license.title} 144 | 145 | 146 | 147 | 148 | 149 | 150 | org.apache.maven.plugins 151 | maven-assembly-plugin 152 | 2.5.3 153 | 154 | ${project.artifactId} 155 | false 156 | 157 | assembly/assembly.xml 158 | 159 | 160 | 161 | 162 | 163 | single 164 | 165 | package 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | -------------------------------------------------------------------------------- /vaangular/src/main/java/de/akquinet/engineering/vaadin/vaangular/angular/MethodInvoker.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 akquinet engineering GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | package de.akquinet.engineering.vaadin.vaangular.angular; 17 | 18 | import com.vaadin.ui.JavaScriptFunction; 19 | 20 | import elemental.json.JsonArray; 21 | 22 | import java.lang.reflect.InvocationTargetException; 23 | import java.lang.reflect.Method; 24 | import java.util.ArrayList; 25 | import java.util.List; 26 | 27 | /** 28 | * @author Axel Meier, akquinet engineering GmbH 29 | */ 30 | public class MethodInvoker implements JavaScriptFunction { 31 | private static final long serialVersionUID = 1L; 32 | 33 | private final Object object; 34 | private final Method method; 35 | 36 | public MethodInvoker(final Object object, final Method method) { 37 | this.object = object; 38 | this.method = method; 39 | } 40 | 41 | @Override 42 | public void call(final JsonArray arguments) { 43 | try { 44 | final Class[] paramTypes = method.getParameterTypes(); 45 | final List paramList = new ArrayList<>(paramTypes.length); 46 | for (int i = 0; i < paramTypes.length; ++i) { 47 | if (Boolean.class.isAssignableFrom(paramTypes[i])) { 48 | paramList.add(arguments.getBoolean(i)); 49 | } else if (Double.class.isAssignableFrom(paramTypes[i])) { 50 | paramList.add(arguments.getNumber(i)); 51 | } else if (String.class.isAssignableFrom(paramTypes[i])) { 52 | paramList.add(arguments.getString(i)); 53 | } else { 54 | paramList.add(arguments.get(i)); 55 | } 56 | } 57 | method.setAccessible(true); 58 | method.invoke(object, paramList.toArray()); 59 | } catch (IllegalAccessException e) { 60 | throw new RuntimeException(e); 61 | } catch (InvocationTargetException e) { 62 | throw new RuntimeException(e); 63 | } 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /vaangular/src/main/java/de/akquinet/engineering/vaadin/vaangular/angular/NgTemplate.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 akquinet engineering GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | package de.akquinet.engineering.vaadin.vaangular.angular; 17 | 18 | import java.io.File; 19 | import java.io.IOException; 20 | import java.io.UnsupportedEncodingException; 21 | import java.lang.reflect.Method; 22 | import java.net.URISyntaxException; 23 | import java.nio.file.Files; 24 | 25 | import com.google.gson.Gson; 26 | import com.vaadin.annotations.JavaScript; 27 | import com.vaadin.ui.AbstractJavaScriptComponent; 28 | 29 | import elemental.json.JsonObject; 30 | import elemental.json.JsonValue; 31 | import elemental.json.impl.JreJsonFactory; 32 | 33 | /** 34 | * Use AngularJS with Vaadin - lightweight take which does not need a Widgetset 35 | * - but does not offer additional functionality from 36 | * {@link de.akquinet.engineering.vaadinjavascriptplus.AbstractJavaScriptComponentPlus} 37 | */ 38 | @JavaScript("NgTemplate.js") 39 | public abstract class NgTemplate extends AbstractJavaScriptComponent { 40 | 41 | private static final long serialVersionUID = 1L; 42 | 43 | private JsonObject userState; 44 | 45 | public NgTemplate(String templateSource, String moduleName) { 46 | userState = new JreJsonFactory().createObject(); 47 | 48 | getState().templateSource = templateSource; 49 | getState().moduleName = moduleName; 50 | } 51 | 52 | public NgTemplate(Package templatePackage, String moduleName) 53 | throws URISyntaxException, UnsupportedEncodingException, 54 | IOException { 55 | userState = new JreJsonFactory().createObject(); 56 | 57 | File templateFolder = new File(NgTemplate.class.getClassLoader() 58 | .getResource(templatePackage.getName().replace('.', '/')) 59 | .getPath()); 60 | 61 | initFromFile(templateFolder, moduleName); 62 | } 63 | 64 | public NgTemplate(File templateFolder, String moduleName) 65 | throws IOException { 66 | userState = new JreJsonFactory().createObject(); 67 | 68 | initFromFile(templateFolder, moduleName); 69 | } 70 | 71 | private void initFromFile(File templateFolder, String moduleName) 72 | throws UnsupportedEncodingException, IOException { 73 | if (templateFolder == null) { 74 | throw new IllegalArgumentException( 75 | "param 'templateFolder' must be null!"); 76 | } 77 | if (templateFolder.exists() == false) { 78 | throw new IllegalArgumentException( 79 | "param 'templateFolder' must exist!"); 80 | } 81 | if (templateFolder.isDirectory() == false) { 82 | throw new IllegalArgumentException( 83 | "param 'templateFolder' must represent a directory!"); 84 | } 85 | String templateSource = new String(Files.readAllBytes(new File( 86 | templateFolder, templateFolder.getName() + ".html").toPath()), 87 | "UTF-8"); 88 | 89 | getState().templateSource = templateSource; 90 | getState().moduleName = moduleName; 91 | } 92 | 93 | @Override 94 | public NgTemplateState getState() { 95 | return (NgTemplateState) super.getState(); 96 | } 97 | 98 | public void addService(final String name, final Object callback) { 99 | Class type = callback.getClass(); 100 | for (final Method method : type.getMethods()) { 101 | if (method.isAnnotationPresent(ServiceMethod.class)) { 102 | final String methodName = method.getName(); 103 | addFunction(name + "_" + methodName, new MethodInvoker( 104 | callback, method)); 105 | } 106 | } 107 | } 108 | 109 | public void setUserState(String key, String value) { 110 | this.userState.put(key, value); 111 | pushUserStateChange(); 112 | } 113 | 114 | public void setUserState(String key, Object value) { 115 | 116 | String json = new Gson().toJson(value); 117 | this.userState.put(key, (JsonValue) new JreJsonFactory().parse(json)); 118 | pushUserStateChange(); 119 | } 120 | 121 | private void pushUserStateChange() { 122 | getState().changeType = "userState"; 123 | getState().userState = this.userState.toJson(); 124 | } 125 | 126 | } 127 | -------------------------------------------------------------------------------- /vaangular/src/main/java/de/akquinet/engineering/vaadin/vaangular/angular/NgTemplatePlus.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 akquinet engineering GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | package de.akquinet.engineering.vaadin.vaangular.angular; 17 | 18 | import java.io.File; 19 | import java.io.IOException; 20 | import java.io.UnsupportedEncodingException; 21 | import java.lang.reflect.Method; 22 | import java.net.URISyntaxException; 23 | import java.nio.file.Files; 24 | import java.util.HashMap; 25 | import java.util.Map; 26 | 27 | import com.google.gson.Gson; 28 | import com.vaadin.annotations.JavaScript; 29 | import com.vaadin.server.VariableOwner; 30 | 31 | import de.akquinet.engineering.vaadin.javascriptplus.AbstractJavaScriptPlusComponent; 32 | import elemental.json.JsonObject; 33 | import elemental.json.JsonValue; 34 | import elemental.json.impl.JreJsonFactory; 35 | 36 | /** 37 | * Use AngularJS with Vaadin - full-fledged take which DOES need a Widgetset - 38 | * offers additional functionality from 39 | * {@link de.akquinet.engineering.vaadinjavascriptplus.AbstractJavaScriptComponentPlus} 40 | */ 41 | @SuppressWarnings("deprecation") 42 | @JavaScript("NgTemplate.js") 43 | public abstract class NgTemplatePlus extends AbstractJavaScriptPlusComponent 44 | implements VariableOwner { 45 | 46 | private static final long serialVersionUID = 1L; 47 | 48 | private JsonObject userState; 49 | 50 | public NgTemplatePlus(String templateSource, String moduleName) { 51 | userState = new JreJsonFactory().createObject(); 52 | 53 | getState().templateSource = templateSource; 54 | getState().moduleName = moduleName; 55 | } 56 | 57 | public NgTemplatePlus(Package templatePackage, String moduleName) 58 | throws URISyntaxException, UnsupportedEncodingException, 59 | IOException { 60 | userState = new JreJsonFactory().createObject(); 61 | 62 | File templateFolder = new File(NgTemplatePlus.class.getClassLoader() 63 | .getResource(templatePackage.getName().replace('.', '/')) 64 | .getPath()); 65 | 66 | initFromFile(templateFolder, moduleName); 67 | } 68 | 69 | public NgTemplatePlus(File templateFolder, String moduleName) 70 | throws IOException { 71 | userState = new JreJsonFactory().createObject(); 72 | 73 | initFromFile(templateFolder, moduleName); 74 | } 75 | 76 | private void initFromFile(File templateFolder, String moduleName) 77 | throws UnsupportedEncodingException, IOException { 78 | if (templateFolder == null) { 79 | throw new IllegalArgumentException( 80 | "param 'templateFolder' must be null!"); 81 | } 82 | if (templateFolder.exists() == false) { 83 | throw new IllegalArgumentException( 84 | "param 'templateFolder' must exist!"); 85 | } 86 | if (templateFolder.isDirectory() == false) { 87 | throw new IllegalArgumentException( 88 | "param 'templateFolder' must represent a directory!"); 89 | } 90 | String templateSource = new String(Files.readAllBytes(new File( 91 | templateFolder, templateFolder.getName() + ".html").toPath()), 92 | "UTF-8"); 93 | 94 | getState().templateSource = templateSource; 95 | getState().moduleName = moduleName; 96 | } 97 | 98 | @Override 99 | public NgTemplateState getState() { 100 | return (NgTemplateState) super.getState(); 101 | } 102 | 103 | public void addService(final String name, final Object callback) { 104 | Class type = callback.getClass(); 105 | for (final Method method : type.getMethods()) { 106 | if (method.isAnnotationPresent(ServiceMethod.class)) { 107 | final String methodName = method.getName(); 108 | addFunction(name + "_" + methodName, new MethodInvoker( 109 | callback, method)); 110 | } 111 | } 112 | } 113 | 114 | public void setUserState(String key, String value) { 115 | this.userState.put(key, value); 116 | pushUserStateChange(); 117 | } 118 | 119 | public void setUserState(String key, Object value) { 120 | 121 | String json = new Gson().toJson(value); 122 | this.userState.put(key, (JsonValue) new JreJsonFactory().parse(json)); 123 | pushUserStateChange(); 124 | } 125 | 126 | private void pushUserStateChange() { 127 | getState().changeType = "userState"; 128 | getState().userState = this.userState.toJson(); 129 | } 130 | 131 | private Map variables = new HashMap(); 132 | 133 | public Map getVariables() { 134 | return variables; 135 | } 136 | 137 | @Override 138 | protected void onChangeVariables(Map variables) { 139 | this.variables.putAll(variables); 140 | } 141 | 142 | } 143 | -------------------------------------------------------------------------------- /vaangular/src/main/java/de/akquinet/engineering/vaadin/vaangular/angular/NgTemplateState.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 akquinet engineering GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | package de.akquinet.engineering.vaadin.vaangular.angular; 17 | 18 | import com.vaadin.shared.ui.JavaScriptComponentState; 19 | 20 | public class NgTemplateState extends JavaScriptComponentState { 21 | 22 | private static final long serialVersionUID = 1L; 23 | 24 | public String changeType; 25 | public String moduleName; 26 | public String templateSource; 27 | public String userState; 28 | 29 | } 30 | -------------------------------------------------------------------------------- /vaangular/src/main/java/de/akquinet/engineering/vaadin/vaangular/angular/ServiceMethod.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 akquinet engineering GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | package de.akquinet.engineering.vaadin.vaangular.angular; 17 | 18 | import java.lang.annotation.ElementType; 19 | import java.lang.annotation.Retention; 20 | import java.lang.annotation.RetentionPolicy; 21 | import java.lang.annotation.Target; 22 | 23 | /** 24 | * @author Axel Meier, akquinet engineering GmbH 25 | */ 26 | @Retention(RetentionPolicy.RUNTIME) 27 | @Target(ElementType.METHOD) 28 | public @interface ServiceMethod { 29 | } 30 | -------------------------------------------------------------------------------- /vaangular/src/main/resources/de/akquinet/engineering/vaadin/vaangular/angular/NgTemplate.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 akquinet engineering GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | var de_akquinet_engineering_vaadin_vaangular_angular_NgTemplate = function() { 17 | 18 | var connector = this; 19 | var initialized = false; 20 | var scpe; 21 | 22 | this.onStateChange = function() { 23 | 24 | if (!initialized) { 25 | 26 | initialized = true; 27 | 28 | var connectorElement = angular.element(connector.getElement()); 29 | 30 | var templateSource = connector.getState().templateSource; 31 | var templateElement = angular.element(templateSource); 32 | 33 | var innerModuleName = connector.getState().moduleName + "_inner" + connector.getConnectorId(); 34 | angular.module(innerModuleName, [connector.getState().moduleName]); 35 | angular.module(innerModuleName).factory("$connector", function() { 36 | return connector; 37 | }); 38 | 39 | angular.injector([ 'ng', innerModuleName ]).invoke(function($compile, $rootScope) { 40 | var cmp = $compile(templateElement); 41 | scpe = $rootScope.$new(false); 42 | if (connector.getState().userState) { 43 | scpe.userState = JSON.parse(connector.getState().userState); 44 | } 45 | cmp(scpe); 46 | connectorElement.append(templateElement); 47 | scpe.$digest(); 48 | }); 49 | } 50 | 51 | var changeType = connector.getState().changeType; 52 | 53 | if (changeType == "userState") { 54 | scpe.$apply(function() { 55 | scpe.userState = JSON.parse(connector.getState().userState); 56 | }); 57 | } 58 | } 59 | 60 | }; 61 | // also the 2nd connector 62 | var de_akquinet_engineering_vaadin_vaangular_angular_NgTemplatePlus = de_akquinet_engineering_vaadin_vaangular_angular_NgTemplate; 63 | -------------------------------------------------------------------------------- /vaangular/src/test/java/de/akquinet/engineering/vaadin/vaangular/angular/MethodInvokerTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 akquinet engineering GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | package de.akquinet.engineering.vaadin.vaangular.angular; 17 | 18 | import static org.junit.Assert.assertEquals; 19 | 20 | import java.lang.reflect.Method; 21 | import java.util.Arrays; 22 | 23 | import org.junit.Test; 24 | 25 | import elemental.json.JsonArray; 26 | import elemental.json.JsonString; 27 | import elemental.json.impl.JreJsonFactory; 28 | 29 | public class MethodInvokerTest { 30 | 31 | @Test 32 | public void testCall() { 33 | JreJsonFactory jsonFactory = new JreJsonFactory(); 34 | JsonArray params = jsonFactory.createArray(); 35 | params.set(0, true); 36 | params.set(1, "hey"); 37 | params.set(2, 88.0); 38 | JsonArray innerArray = jsonFactory.createArray(); 39 | innerArray.set(0, "inner"); 40 | params.set(3, innerArray); 41 | TestTarget target = new TestTarget(); 42 | Method testMethod = Arrays 43 | .stream(TestTarget.class.getDeclaredMethods()) 44 | .filter(m -> "testMethod".equals(m.getName())).findFirst() 45 | .get(); 46 | MethodInvoker invoker = new MethodInvoker(target, testMethod); 47 | invoker.call(params); 48 | assertEquals(Boolean.TRUE, target.getArg1()); 49 | assertEquals("hey", target.getArg2()); 50 | assertEquals(new Double(88.0), target.getArg3()); 51 | assertEquals(1, target.getArg4().length()); 52 | assertEquals("inner", 53 | ((JsonString) target.getArg4().get(0)).getString()); 54 | } 55 | 56 | @Test(expected = Exception.class) 57 | public void testCallInvalidArgs() { 58 | JreJsonFactory jsonFactory = new JreJsonFactory(); 59 | JsonArray params = jsonFactory.createArray(); 60 | params.set(0, true); 61 | params.set(1, "hey"); 62 | TestTarget target = new TestTarget(); 63 | Method testMethod = Arrays 64 | .stream(TestTarget.class.getDeclaredMethods()) 65 | .filter(m -> "testMethod".equals(m.getName())).findFirst() 66 | .get(); 67 | MethodInvoker invoker = new MethodInvoker(target, testMethod); 68 | invoker.call(params); 69 | } 70 | 71 | @Test(expected = RuntimeException.class) 72 | public void testCallException() { 73 | JreJsonFactory jsonFactory = new JreJsonFactory(); 74 | JsonArray params = jsonFactory.createArray(); 75 | TestTarget target = new TestTarget(); 76 | Method testMethod = Arrays 77 | .stream(TestTarget.class.getDeclaredMethods()) 78 | .filter(m -> "testMethodExc".equals(m.getName())).findFirst() 79 | .get(); 80 | MethodInvoker invoker = new MethodInvoker(target, testMethod); 81 | invoker.call(params); 82 | } 83 | 84 | private static final class TestTarget { 85 | 86 | private Boolean arg1 = null; 87 | private String arg2 = null; 88 | private Double arg3 = null; 89 | private JsonArray arg4 = null; 90 | 91 | @SuppressWarnings("unused") 92 | private void testMethod(Boolean arg1, String arg2, Double arg3, 93 | JsonArray arg4) { 94 | this.arg1 = arg1; 95 | this.arg2 = arg2; 96 | this.arg3 = arg3; 97 | this.arg4 = arg4; 98 | } 99 | 100 | @SuppressWarnings("unused") 101 | private void testMethodExc() throws Exception { 102 | throw new Exception("Test-Exception"); 103 | } 104 | 105 | public Boolean getArg1() { 106 | return arg1; 107 | } 108 | 109 | public String getArg2() { 110 | return arg2; 111 | } 112 | 113 | public Double getArg3() { 114 | return arg3; 115 | } 116 | 117 | public JsonArray getArg4() { 118 | return arg4; 119 | } 120 | } 121 | 122 | } 123 | -------------------------------------------------------------------------------- /vaangular/src/test/java/de/akquinet/engineering/vaadin/vaangular/angular/NgTemplatePlusTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 akquinet engineering GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | package de.akquinet.engineering.vaadin.vaangular.angular; 17 | 18 | import static org.junit.Assert.assertEquals; 19 | import static org.junit.Assert.assertFalse; 20 | import static org.junit.Assert.assertNotNull; 21 | import static org.junit.Assert.assertTrue; 22 | 23 | import java.io.IOException; 24 | import java.io.UnsupportedEncodingException; 25 | import java.net.URISyntaxException; 26 | import java.util.HashSet; 27 | import java.util.Set; 28 | 29 | import org.junit.Test; 30 | 31 | import com.vaadin.ui.JavaScriptFunction; 32 | 33 | public class NgTemplatePlusTest { 34 | 35 | @Test 36 | public void testConstructorStrings() { 37 | NgTemplatePlus template = new NgTemplatePlus("

moin

", 38 | "NgTemplateTest") { 39 | 40 | /** 41 | * 42 | */ 43 | private static final long serialVersionUID = 1L; 44 | }; 45 | assertEquals("

moin

", template.getState().templateSource); 46 | assertEquals("NgTemplateTest", template.getState().moduleName); 47 | } 48 | 49 | @Test 50 | public void testConstructorPackage() throws UnsupportedEncodingException, 51 | URISyntaxException, IOException { 52 | NgTemplatePlus template = new NgTemplatePlus( 53 | NgTemplatePlusTest.class.getPackage(), "NgTemplateTest") { 54 | 55 | /** 56 | * 57 | */ 58 | private static final long serialVersionUID = 1L; 59 | }; 60 | assertEquals("

heyho

", template.getState().templateSource); 61 | assertEquals("NgTemplateTest", template.getState().moduleName); 62 | } 63 | 64 | @Test 65 | public void testAddService() { 66 | final Set addedServices = new HashSet<>(); 67 | NgTemplatePlus template = new NgTemplatePlus("--", "NgTemplateTest") { 68 | 69 | /** 70 | * 71 | */ 72 | private static final long serialVersionUID = 1L; 73 | 74 | protected void addFunction(String functionName, 75 | JavaScriptFunction function) { 76 | addedServices.add(functionName); 77 | } 78 | }; 79 | template.addService("testService", new Object() { 80 | 81 | @ServiceMethod 82 | public void test1() { 83 | } 84 | 85 | @ServiceMethod 86 | public void test2() { 87 | } 88 | 89 | @SuppressWarnings("unused") 90 | public void test3() { 91 | } 92 | 93 | @SuppressWarnings("unused") 94 | private void test4() { 95 | } 96 | }); 97 | assertEquals(2, addedServices.size()); 98 | assertTrue(addedServices.contains("testService_test1")); 99 | assertTrue(addedServices.contains("testService_test2")); 100 | assertFalse(addedServices.contains("testService_test3")); 101 | assertFalse(addedServices.contains("testService_test4")); 102 | } 103 | 104 | @Test 105 | public void testSetUserState() { 106 | NgTemplatePlus template = new NgTemplatePlus("--", "NgTemplateTest") { 107 | 108 | /** 109 | * 110 | */ 111 | private static final long serialVersionUID = 1L; 112 | }; 113 | template.setUserState("test", "bla"); 114 | assertNotNull(template.getState().userState); 115 | assertEquals("{\"test\":\"bla\"}", 116 | template.getState().userState.replaceAll("[ \n\r\t]", "")); 117 | } 118 | 119 | } 120 | -------------------------------------------------------------------------------- /vaangular/src/test/java/de/akquinet/engineering/vaadin/vaangular/angular/NgTemplateTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 akquinet engineering GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | package de.akquinet.engineering.vaadin.vaangular.angular; 17 | 18 | import static org.junit.Assert.assertEquals; 19 | import static org.junit.Assert.assertFalse; 20 | import static org.junit.Assert.assertNotNull; 21 | import static org.junit.Assert.assertTrue; 22 | 23 | import java.io.IOException; 24 | import java.io.UnsupportedEncodingException; 25 | import java.net.URISyntaxException; 26 | import java.util.HashSet; 27 | import java.util.Set; 28 | 29 | import org.junit.Test; 30 | 31 | import com.vaadin.ui.JavaScriptFunction; 32 | 33 | public class NgTemplateTest { 34 | 35 | @Test 36 | public void testConstructorStrings() { 37 | NgTemplate template = new NgTemplate("

moin

", "NgTemplateTest") { 38 | 39 | /** 40 | * 41 | */ 42 | private static final long serialVersionUID = 1L; 43 | }; 44 | assertEquals("

moin

", template.getState().templateSource); 45 | assertEquals("NgTemplateTest", template.getState().moduleName); 46 | } 47 | 48 | @Test 49 | public void testConstructorPackage() throws UnsupportedEncodingException, 50 | URISyntaxException, IOException { 51 | NgTemplate template = new NgTemplate(NgTemplateTest.class.getPackage(), 52 | "NgTemplateTest") { 53 | 54 | /** 55 | * 56 | */ 57 | private static final long serialVersionUID = 1L; 58 | }; 59 | assertEquals("

heyho

", template.getState().templateSource); 60 | assertEquals("NgTemplateTest", template.getState().moduleName); 61 | } 62 | 63 | @Test 64 | public void testAddService() { 65 | final Set addedServices = new HashSet<>(); 66 | NgTemplate template = new NgTemplate("--", "NgTemplateTest") { 67 | 68 | /** 69 | * 70 | */ 71 | private static final long serialVersionUID = 1L; 72 | 73 | protected void addFunction(String functionName, 74 | JavaScriptFunction function) { 75 | addedServices.add(functionName); 76 | } 77 | }; 78 | template.addService("testService", new Object() { 79 | 80 | @ServiceMethod 81 | public void test1() { 82 | } 83 | 84 | @ServiceMethod 85 | public void test2() { 86 | } 87 | 88 | @SuppressWarnings("unused") 89 | public void test3() { 90 | } 91 | 92 | @SuppressWarnings("unused") 93 | private void test4() { 94 | } 95 | }); 96 | assertEquals(2, addedServices.size()); 97 | assertTrue(addedServices.contains("testService_test1")); 98 | assertTrue(addedServices.contains("testService_test2")); 99 | assertFalse(addedServices.contains("testService_test3")); 100 | assertFalse(addedServices.contains("testService_test4")); 101 | } 102 | 103 | @Test 104 | public void testSetUserState() { 105 | NgTemplate template = new NgTemplate("--", "NgTemplateTest") { 106 | 107 | /** 108 | * 109 | */ 110 | private static final long serialVersionUID = 1L; 111 | }; 112 | template.setUserState("test", "bla"); 113 | assertNotNull(template.getState().userState); 114 | assertEquals("{\"test\":\"bla\"}", 115 | template.getState().userState.replaceAll("[ \n\r\t]", "")); 116 | } 117 | 118 | } 119 | -------------------------------------------------------------------------------- /vaangular/src/test/resources/de/akquinet/engineering/vaadin/vaangular/angular/angular.html: -------------------------------------------------------------------------------- 1 |

heyho

--------------------------------------------------------------------------------