Skip to content

Commit 6d650a1

Browse files
committed
Merge branch 'release/8.0.0'
2 parents a010a53 + e33c19e commit 6d650a1

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+1986
-603
lines changed

.travis.yml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
language: node_js
22
node_js:
3-
- "6.9.1"
3+
- "8.9.4"
44
install:
55
- yarn install
66
script:
77
- npm test
8-
- npm start -- build
9-
- npm start -- mobile.setup
8+
- npm start build
9+
- npm start mobile.setup
10+
- npm start mobile.cordova.addbowser
11+
- npm start mobile.build
1012
notifications:
1113
email: false
1214
hipchat: 861e4f14f03ed33d069f1083a6c9f5@2679708

README.md

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
[![Build Status](https://api.travis-ci.org/w3tecch/aurelia-typescript-boilerplate.svg?branch=master)](https://travis-ci.org/w3tecch/aurelia-typescript-boilerplate)
2+
[![Build status](https://ci.appveyor.com/api/projects/status/7oyx5vxl6ue6oqsf/branch/master?svg=true)](https://ci.appveyor.com/project/dweber019/aurelia-typescript-boilerplate/branch/master)
23
[![Dependency Status](https://david-dm.org/w3tecch/aurelia-typescript-boilerplate.svg)](https://david-dm.org/w3tecch/aurelia-typescript-boilerplate)
34
[![devDependency Status](https://david-dm.org/w3tecch/aurelia-typescript-boilerplate/dev-status.svg)](https://david-dm.org/w3tecch/aurelia-typescript-boilerplate#info=devDependencies)
45

@@ -211,3 +212,111 @@ If you like to update the source do this
211212
```shell
212213
docker cp ./dist/. mycontainer:/usr/share/nginx/html
213214
```
215+
216+
## Additional features
217+
This repo houses some additional features which provd to be very useful in projects.
218+
219+
## String polyfill
220+
The file `utils/polyfills.utils.ts` contains a string polyfills.
221+
With this polyfill you can do this:
222+
```
223+
'Teststring'.isEmpty() => false
224+
''.isEmpty() => true
225+
undefined.isEmpty() => true
226+
```
227+
228+
## Validation
229+
The file `utils/validation.utils.ts` contains some validatoin helper functions and regex patterns.
230+
231+
The function `validateFilledFieldsWithValidationRules` us really useful as you can check a object which is already prefiled if it's valid and if not show errors.
232+
233+
The function `controllerValidByRules` will check if a validation controller is valid.
234+
235+
This could be an example implementation
236+
```
237+
class FormExample {
238+
239+
@bindable({ defaultBindingMode: bindingMode.twoWay }) public user: User;
240+
241+
private controller: ValidationController;
242+
private rules: Rule<CustomerContactRestModel, any>[][];
243+
244+
public constructor(
245+
private validationControllerFactory: ValidationControllerFactory
246+
) {
247+
this.controller = this.validationControllerFactory.createForCurrentScope();
248+
this.controller.validateTrigger = validateTrigger.changeOrBlur;
249+
}
250+
251+
public bind(): void {
252+
this.setupValidationRules();
253+
validateFilledFieldsWithValidationRules(this.rules, this.user, this.controller);
254+
}
255+
256+
@computedFrom('user')
257+
public get isValid(): boolean {
258+
return controllerValidByRules(this.rules, this.user, this.controller);
259+
}
260+
261+
private setupValidationRules(): void {
262+
this.rules = ValidationRules
263+
.ensure((user: User) => user.lastName)
264+
.displayName('USER.LAST_NAME')
265+
.required()
266+
.ensure((user: User) => user.email)
267+
.displayName('USER.EMAIL')
268+
.email()
269+
.on(this.customerContact).rules;
270+
}
271+
}
272+
```
273+
274+
### i18n integration
275+
You can pass a tranlation string into the `displayName('USER.LAST_NAME')` and it will be translated for you.
276+
277+
Additionally you can translate methods like `.required()` in `src/local/*` as demostrated in the files.
278+
279+
If you use the the method `withMessageKey('YOUR.TRANSLATION')` you can pass a translation string and it will be translated for you.
280+
281+
## Route generator service
282+
If you have router tree like this
283+
```
284+
root
285+
/ \
286+
left right
287+
```
288+
You can't navigate from `left` to `right` with `this.router.navigateToRoute(...)` as `right` is in a branch which `left` is unaware of. This is due to the injection of the router service.
289+
290+
One solution is to use `this.router.navigate(...)` but this is unsave as if the route configuration is changed the navigation is broken as it's hardcoded.
291+
292+
The `route-generator.service.ts` will provide a type safe solution for save navigation.
293+
294+
Check the following files to get an idea how to use it:
295+
- `route-generator.service.ts`
296+
- `app.vm.ts` and `app.routes.ts`
297+
- `child-router.vm.ts` and `child-router.routes.ts`
298+
299+
As an example you could navigate like this from `left` to `right`
300+
```
301+
this.routeGeneratorService.navigateByRouteNames(
302+
{ routeName: 'root' },
303+
{ routeName: 'right' }
304+
);
305+
```
306+
307+
You can also pass route parameters like this but remember that query parameter have to attached to the last element
308+
```
309+
this.routeGeneratorService.navigateByRouteNames(
310+
{ routeName: 'root', params: { id: '1' }},
311+
{ routeName: 'right' }
312+
);
313+
```
314+
315+
## Class transfomer (model handling)
316+
We have included the [class transformer](https://github.com/typestack/class-transformer) which helps creating models (`src/app/models/*`). This transformation can be done
317+
in both direction (rest to model, model to rest).
318+
319+
## Dialog service
320+
There is a custom dialog implementation for simpler useage of elements in dialogs.
321+
322+
The Service is named `generic-dialog.service.ts` and an example can be found in `welcome.vm.ts`.

appveyor.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
environment:
2+
nodejs_version: "8"
3+
4+
install:
5+
- ps: Install-Product node $env:nodejs_version
6+
- yarn install
7+
8+
test_script:
9+
- npm test
10+
- npm start build
11+
- npm start mobile.setup
12+
- npm start mobile.cordova.addbowser
13+
- npm start mobile.build

package-scripts.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,11 @@ module.exports = {
112112
clean: series(
113113
rimraf('./cordova/platforms'),
114114
rimraf('./cordova/plugins')
115-
)
115+
),
116+
addbowser: ifWindows(
117+
'cd .\\cordova && .\\..\\node_modules\\.bin\\cordova platform add browser',
118+
'cd ./cordova && ./../node_modules/.bin/cordova platform add browser'
119+
),
116120
}
117121
}
118122
},

package.json

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "aurelia-typescript-boilerplate",
3-
"version": "7.0.0",
3+
"version": "8.0.0",
44
"title": "Aurelia Typescript Boilerplate",
55
"description": "A starter kit for building a standard navigation-style app with Aurelia and Webpack.",
66
"main": "dist/app.bundle.js",
@@ -56,7 +56,7 @@
5656
],
5757
"testEnvironment": "node",
5858
"moduleNameMapper": {
59-
"aurelia-(.*)": "<rootDir>/node_modules/aurelia-$1"
59+
"^.*\\.scss$": "<rootDir>/test/unit/stubs/sass-stub.js"
6060
},
6161
"collectCoverage": true,
6262
"collectCoverageFrom": [
@@ -77,7 +77,7 @@
7777
"devDependencies": {
7878
"@types/cordova": "^0.0.34",
7979
"@types/i18next-browser-languagedetector": "^2.0.0",
80-
"@types/jest": "^20.0.8",
80+
"@types/jest": "^22.1.2",
8181
"@types/jquery": "^3.2.12",
8282
"@types/lodash": "^4.14.74",
8383
"@types/node": "^8.0.26",
@@ -88,7 +88,7 @@
8888
"aurelia-template-lint-webpack-loader": "^1.0.3",
8989
"aurelia-testing": "^1.0.0-beta.3.0.1",
9090
"aurelia-webpack-plugin": "^2.0.0-rc.5",
91-
"autoprefixer": "^7.1.3",
91+
"autoprefixer": "^8.0.0",
9292
"awesome-typescript-loader": "^3.2.3",
9393
"case-sensitive-paths-webpack-plugin": "^2.1.1",
9494
"chalk": "^2.1.0",
@@ -104,13 +104,9 @@
104104
"http-server": "^0.11.1",
105105
"img-loader": "^2.0.0",
106106
"istanbul-instrumenter-loader": "^3.0.0",
107-
"jest": "^20.0.4",
108-
"jest-cli": "^20.0.4",
107+
"jest": "^22.3.0",
108+
"jest-cli": "^22.3.0",
109109
"json-loader": "^0.5.7",
110-
"karma-chrome-launcher": "^2.2.0",
111-
"karma-jasmine": "^1.1.0",
112-
"karma-mocha-reporter": "^2.2.4",
113-
"karma-webpack": "^2.0.4",
114110
"loader-utils": "^1.1.0",
115111
"ncp": "^2.0.0",
116112
"node-sass": "^4.5.3",
@@ -120,7 +116,7 @@
120116
"protractor": "^5.1.2",
121117
"sass-loader": "^6.0.6",
122118
"style-loader": "^0.20.1",
123-
"ts-jest": "^20.0.14",
119+
"ts-jest": "^22.0.4",
124120
"ts-node": "^4.1.0",
125121
"tslib": "^1.7.1",
126122
"tslint": "^5.7.0",
@@ -155,11 +151,13 @@
155151
"aurelia-validation": "^1.1.1",
156152
"bluebird": "^3.5.0",
157153
"bootstrap": "^4.0.0",
154+
"class-transformer": "^0.1.9",
158155
"i18next-browser-languagedetector": "^2.0.0",
159156
"isomorphic-fetch": "^2.2.1",
160157
"jquery": "^3.2.1",
161158
"moment": "^2.18.1",
162-
"normalize.css": "^7.0.0",
163-
"popper.js": "^1.12.9"
159+
"normalize.css": "^8.0.0",
160+
"popper.js": "^1.12.9",
161+
"reflect-metadata": "^0.1.12"
164162
}
165163
}

src/app/app.routes.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { PLATFORM } from 'aurelia-framework';
2+
3+
export type RouteNames = 'welcome' | 'users' | 'child-router';
4+
5+
export const welcome = {
6+
route: ['', 'welcome'],
7+
name: 'welcome',
8+
moduleId: PLATFORM.moduleName('modules/welcome/welcome.vm', 'welcome'),
9+
nav: true,
10+
title: 'Welcome'
11+
};
12+
13+
export const users = {
14+
route: 'users',
15+
name: 'users',
16+
moduleId: PLATFORM.moduleName('modules/users/users.vm', 'users'),
17+
nav: true,
18+
title: 'Github Users'
19+
};
20+
21+
export const childRouter = {
22+
route: 'child-router',
23+
name: 'child-router',
24+
moduleId: PLATFORM.moduleName('modules/child-router/child-router.vm', 'child-router'),
25+
nav: true,
26+
title: 'Child Router'
27+
};

src/app/app.vm.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<template>
22

3-
<nav-bar router.bind="router"></nav-bar>
3+
<nav-bar router.bind="router" containerless></nav-bar>
44

55
<div class="page-host">
66
<router-view swap-order="after"></router-view>

src/app/app.vm.ts

Lines changed: 7 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Lazy, inject, PLATFORM } from 'aurelia-framework';
1+
import { Lazy, inject } from 'aurelia-framework';
22
import { Router, RouterConfiguration } from 'aurelia-router';
33
import { I18N } from 'aurelia-i18n';
44
import { HttpClient } from 'aurelia-fetch-client';
@@ -10,21 +10,23 @@ import { CordovaService } from './services/cordova.service';
1010
import { EventBusService, EventBusEvents } from './services/event-bus.service';
1111
import { LanguageService } from './services/language.service';
1212
import { ExampleStep } from './piplines/example.step';
13+
import { RouteGeneratorService } from './services/route-generator.service';
1314

14-
@inject(I18N, AppConfigService, Lazy.of(CordovaService), EventBusService, LanguageService, HttpClient)
15+
@inject(I18N, AppConfigService, Lazy.of(CordovaService), EventBusService, LanguageService, HttpClient, RouteGeneratorService)
1516
export class AppViewModel {
1617

1718
private logger: Logger;
1819

19-
public router: Router;
20+
public router!: Router;
2021

2122
constructor(
2223
private i18n: I18N,
2324
private appConfigService: AppConfigService,
2425
private cordovaServiceFn: () => CordovaService,
2526
private eventBusService: EventBusService,
2627
private languageService: LanguageService,
27-
private httpClient: HttpClient
28+
private httpClient: HttpClient,
29+
private routeGeneratorService: RouteGeneratorService,
2830
) {
2931
this.logger = LogManager.getLogger('AppViewModel');
3032
this.configureHttpClient();
@@ -42,29 +44,7 @@ export class AppViewModel {
4244
if (this.appConfigService.platformIsMobile()) {
4345
this.cordovaServiceFn();
4446
}
45-
config.map([
46-
{
47-
route: ['', 'welcome'],
48-
name: 'welcome',
49-
moduleId: PLATFORM.moduleName('./modules/welcome/welcome.vm', 'welcome'),
50-
nav: true,
51-
title: 'Welcome'
52-
},
53-
{
54-
route: 'users',
55-
name: 'users',
56-
moduleId: PLATFORM.moduleName('./modules/users/users.vm', 'users'),
57-
nav: true,
58-
title: 'Github Users'
59-
},
60-
{
61-
route: 'child-router',
62-
name: 'child-router',
63-
moduleId: PLATFORM.moduleName('./modules/child-router/child-router.vm', 'child-router'),
64-
nav: true,
65-
title: 'Child Router'
66-
}
67-
]);
47+
config.map(this.routeGeneratorService.getRootRoutesConfig());
6848
config.mapUnknownRoutes({ route: '', redirect: '' });
6949

7050
config.addAuthorizeStep(ExampleStep);

src/app/main.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ const appConfigService = new AppConfigService();
1515
*/
1616
import { Aurelia, LogManager, PLATFORM } from 'aurelia-framework';
1717
import { ConsoleAppender } from 'aurelia-logging-console';
18+
import { ValidationMessageProvider } from 'aurelia-validation';
19+
import { Expression } from 'aurelia-binding';
20+
import { I18N } from 'aurelia-i18n';
1821

1922
/**
2023
* Locals i18n imports
@@ -28,6 +31,12 @@ import de_CHTranslation from './../locales/de_CH.json';
2831
import 'isomorphic-fetch';
2932
import LanguageDetector from 'i18next-browser-languagedetector';
3033

34+
/**
35+
* Polyfills
36+
*/
37+
import 'reflect-metadata';
38+
import 'utils/polyfills.utils';
39+
3140
// Fontawesome setup
3241
import fontawesome from '@fortawesome/fontawesome';
3342
import fontawesomeSolid from '@fortawesome/fontawesome-free-solid';
@@ -128,4 +137,19 @@ export async function configure(aurelia: Aurelia): Promise<void> {
128137
const offline = await System.import('offline-plugin/runtime');
129138
offline.install();
130139
*/
140+
141+
// Configure validation translations
142+
ValidationMessageProvider.prototype.getMessage = function (key): Expression {
143+
const i18n = aurelia.container.get(I18N);
144+
const translationId = `VALIDATIONS.${key}`;
145+
let translation = i18n.tr(translationId);
146+
if (translation === translationId) {
147+
translation = i18n.tr(key);
148+
}
149+
return (this as any).parser.parse(translation);
150+
};
151+
ValidationMessageProvider.prototype.getDisplayName = function (...args): string {
152+
const i18n = aurelia.container.get(I18N);
153+
return i18n.tr(args[1]);
154+
};
131155
}

0 commit comments

Comments
 (0)