├── .gitattributes
├── .gitignore
├── .jshintrc
├── README.md
├── config.js
├── css
└── main.css
├── gulpfile.js
├── index.html
├── karma.conf.js
├── package.json
├── src
├── app.js
├── components
│ └── main
│ │ ├── flickr-gallery-directive-spec.js
│ │ ├── flickr-gallery-directive.js
│ │ ├── flickr-gallery.html
│ │ ├── flickr-service-spec.js
│ │ ├── flickr-service.js
│ │ ├── main-controller.js
│ │ ├── main.js
│ │ ├── shaker-directive.js
│ │ └── title-header-styler-filter.js
└── config
│ ├── config.js
│ ├── constants.js
│ └── decorators.js
└── tasks
├── bundle.js
├── cover.js
└── watch.js
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
4 | # Custom for Visual Studio
5 | *.cs diff=csharp
6 | *.sln merge=union
7 | *.csproj merge=union
8 | *.vbproj merge=union
9 | *.fsproj merge=union
10 | *.dbproj merge=union
11 |
12 | # Standard to msysgit
13 | *.doc diff=astextplain
14 | *.DOC diff=astextplain
15 | *.docx diff=astextplain
16 | *.DOCX diff=astextplain
17 | *.dot diff=astextplain
18 | *.DOT diff=astextplain
19 | *.pdf diff=astextplain
20 | *.PDF diff=astextplain
21 | *.rtf diff=astextplain
22 | *.RTF diff=astextplain
23 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | jspm_packages/
3 | bundle
4 | dist
5 |
6 |
7 | *.sublime-project +bundle
8 | *.sublime-workspace
--------------------------------------------------------------------------------
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "node": true,
3 | "esnext": true,
4 | "bitwise": false,
5 | "curly": false,
6 | "eqeqeq": true,
7 | "eqnull": true,
8 | "immed": true,
9 | "latedef": true,
10 | "newcap": true,
11 | "noarg": true,
12 | "undef": true,
13 | "strict": false,
14 | "globalstrict": true,
15 | "trailing": true,
16 | "smarttabs": true,
17 | "globals": {
18 | "window": false,
19 | "document": false,
20 | "angular": false,
21 | "System": false,
22 | "jasmine": false,
23 | "inject": false,
24 | "describe": false,
25 | "beforeEach": false,
26 | "expect": false,
27 | "it": false
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Angular ES6
2 |
3 | This example shows how to use ES6 with [AngularJS](https://angularjs.org/).
4 |
5 | The tools used are:
6 | * [NodeJS](http://nodejs.org/) as a general dependency
7 | * [Gulp](http://gulpjs.com/) for automation of the ES6 to ES5 transpilation as well as BrowserSync
8 | * [BrowserSync](http://gulpjs.com/) automatically refreshes your browser on js/html/css changes
9 | * [jspm](http://jspm.io/) modern Package Manager supporting ES6 Module Syntax
10 | * [BabelJS](https://babeljs.io/) for ES6 to ES5 transpilation
11 | * [isparta](https://github.com/douglasduteil/isparta) for ES6 code coverage
12 |
13 | ## Development
14 | All AngularJS Application files are located in the folder src/
15 | Make sure to start gulp watch (see below for howto) before doing changes in order to get
16 | the source files automatically transpiled to the dist/ folder
17 |
18 | ## How to start
19 |
20 | In order to start the application do the following:
21 |
22 | 1. Make sure that [NodeJS](http://nodejs.org/) is installed.
23 | 2. Make sure that [Gulp](http://gulpjs.com/) is installed: `npm install -g gulp`
24 | 3. Make sure that [jspm](http://jspm.io/) is installed: `npm install -g jspm`
25 | 4. Go to the project folder
26 | 5. Execute the following command to install all node-dependencies: `npm install`
27 | 6. Now install all client-side dependencies with [jspm](http://jspm.io/): `jspm install`
28 | 7. Start the application with the gulp watch task: `gulp watch`
29 | 8. Open up your favorite Browser and navigate to [http://localhost:9000](http://localhost:9000) to see the app.
30 |
31 | ## Using decorators
32 |
33 | There is a base decorator called `@register` which performs generic component registrations. In order to save work
34 | you may use one of the following concrete implementations, which allow you to omit the type information
35 |
36 | ### Constants
37 |
38 | ```
39 | import {constant} from './path/to/config/decorators';
40 |
41 | @constant
42 | export default class MyConstant {
43 | constructor () {
44 | return 'my-constant';
45 | }
46 | }
47 | ```
48 |
49 | ### Values
50 |
51 | ```
52 | import {value} from './path/to/config/decorators';
53 |
54 | @value
55 | export default class MyValue {
56 | constructor () {
57 | return 'my-value';
58 | }
59 | }
60 | ```
61 |
62 | ### Factories
63 |
64 | ```
65 | import {factory} from './path/to/config/decorators';
66 |
67 | @factory
68 | export default class MyFactory {
69 | constructor (/* dependancies */) { }
70 | }
71 | ```
72 |
73 | ### Services
74 |
75 | ```
76 | import {service} from './path/to/config/decorators';
77 |
78 | @service
79 | export default class MyService {
80 | constructor (/* dependancies */) { }
81 | }
82 | ```
83 |
84 | ### Providers
85 |
86 | ```
87 | import {provider} from './path/to/config/decorators';
88 |
89 | @constant
90 | export default class MyProvider {
91 | constructor (/* dependancies */) { }
92 | }
93 | ```
94 |
95 | ### Controllers
96 |
97 | ```
98 | import {controller} from './path/to/config/decorators';
99 |
100 | @controller
101 | export default class MyController {
102 | constructor (/* dependancies */) { }
103 | }
104 | ```
105 |
106 | ### Directives
107 |
108 | ```
109 | import {directive} from './path/to/config/decorators';
110 | import {baseURL} from './path/to/config/constants';
111 |
112 | @directive({
113 | restrict: 'E',
114 | templateUrl: `${baseURL}/path/to/the/template.html`
115 | })
116 | export default class MyController {
117 | constructor (/* dependancies */) {
118 | this.foo = 'bar';
119 | }
120 | }
121 |
122 | // In template.html :
123 |
124 |
{{ ctrl.foo }} will display "bar"
125 | ```
126 |
127 | ### Filters
128 |
129 | ```
130 | import {filter} from './path/to/config/decorators';
131 |
132 | @filter
133 | export default class MyFilter {
134 | constructor (/* dependancies */) { }
135 | filter (input) {
136 | return input.toUpperCase();
137 | }
138 | }
139 | ```
140 |
141 | ### Injections
142 |
143 | In order to inject existing components/services into your new component you can leverage the following decorator as
144 | depicted in the example below.
145 |
146 | ```
147 | import {inject} from './path/to/config/decorators';
148 |
149 | @controller
150 | @inject('$http', 'MyService')
151 | export default class MyController {
152 | constructor ($http, MyService) { }
153 | }
154 | ```
155 |
156 | ### Injection as a property
157 |
158 | Let's say you want to inject a component/service but use it with a different property name. In order to do so use the
159 | `injectAs` decorator
160 |
161 | ```
162 | import {inject, injectAs} from './path/to/config/decorators';
163 |
164 | @controller
165 | export default class MyController {
166 | @inject $http = null;
167 | @inject MyService = null;
168 | @injectAs('$q') Promise = null;
169 | doSomething () {
170 | return this.Promise((resolve, reject) {
171 | $http.get(this.MyService.path)
172 | .success(data => resolve(data)
173 | .error(err => reject(err));
174 | });
175 | }
176 | }
177 | ```
178 |
179 |
180 | ## Running Unit Tests
181 |
182 | In order to run the unit tests do all mentioned steps from above and the additional ones:
183 |
184 | 1. Make sure that [Karma](http://karma-runner.github.io/) CLI is installed:
185 | ```shell
186 | npm install -g karma-cli
187 | ```
188 | 2. Start the Karma Runner with:
189 | ```shell
190 | karma start
191 | ```
192 |
193 | ## Running code coverage
194 |
195 | To create a full code-coverage report execute the following command:
196 | ```shell
197 | gulp cover
198 | ```
199 |
200 | This will result in a new folder called `coverage` in your project. It contains an index.html, which you can open with
201 | your browser to get a nice code-coverage-report
202 |
203 |
204 | ## Credits
205 | Special thanks goes to [Hadrien Lanneau](https://github.com/hadrienl) for his great contribution to this project
--------------------------------------------------------------------------------
/config.js:
--------------------------------------------------------------------------------
1 | System.config({
2 | "transpiler": "babel",
3 | "babelOptions": {
4 | "optional": [
5 | "es7.decorators",
6 | "es7.classProperties",
7 | "runtime"
8 | ]
9 | },
10 | "paths": {
11 | "*": "*.js",
12 | "github:*": "jspm_packages/github/*.js",
13 | "npm:*": "jspm_packages/npm/*.js",
14 | "angular-es6/*": "lib/*.js"
15 | },
16 | "baseUrl": "dist"
17 | });
18 |
19 | System.config({
20 | "map": {
21 | "angular": "github:angular/bower-angular@1.4.0",
22 | "angular-mocks": "github:angular/bower-angular-mocks@1.4.0",
23 | "babel": "npm:babel-core@5.5.7",
24 | "babel-runtime": "npm:babel-runtime@5.5.7",
25 | "bootstrap": "github:twbs/bootstrap@3.3.4",
26 | "core-js": "npm:core-js@0.9.16",
27 | "jquery": "github:components/jquery@2.1.3",
28 | "traceur": "github:jmcriffey/bower-traceur@0.0.88",
29 | "traceur-runtime": "github:jmcriffey/bower-traceur-runtime@0.0.88",
30 | "github:angular/bower-angular-mocks@1.4.0": {
31 | "angular": "github:angular/bower-angular@1.4.0"
32 | },
33 | "github:jspm/nodelibs-process@0.1.1": {
34 | "process": "npm:process@0.10.1"
35 | },
36 | "github:twbs/bootstrap@3.3.4": {
37 | "jquery": "github:components/jquery@2.1.3"
38 | },
39 | "npm:babel-runtime@5.5.7": {
40 | "process": "github:jspm/nodelibs-process@0.1.1"
41 | },
42 | "npm:core-js@0.9.16": {
43 | "fs": "github:jspm/nodelibs-fs@0.1.2",
44 | "process": "github:jspm/nodelibs-process@0.1.1",
45 | "systemjs-json": "github:systemjs/plugin-json@0.1.0"
46 | }
47 | }
48 | });
49 |
50 |
--------------------------------------------------------------------------------
/css/main.css:
--------------------------------------------------------------------------------
1 | h4 {
2 | font-size: 14px;
3 | height: 40px;
4 | }
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp'),
2 | path = {
3 | source: 'src',
4 | scripts: 'src/**/*.js',
5 | html: ['index.html', 'src/**/*.html'],
6 | output:'dist/',
7 | css: 'css/*.css',
8 | bundle: 'bundle/',
9 | appmodule: 'src/app'
10 | },
11 | bundleTask = require('./tasks/bundle')(path),
12 | watchTask = require('./tasks/watch')(path),
13 | coverTask = require('./tasks/cover')(path);
14 |
15 | gulp.task('default', ['watch']);
16 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
Flickr Photo Album
12 |
13 |
14 |
15 |
16 | Number of hits: {{ctrl.service.numberOfHits()}}
17 |
18 |
19 |
20 |
21 |
22 |
23 |
33 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/karma.conf.js:
--------------------------------------------------------------------------------
1 | // Karma configuration
2 | // Generated on Fri Dec 05 2014 16:49:29 GMT-0500 (EST)
3 |
4 | module.exports = function(config) {
5 | config.set({
6 |
7 | // base path that will be used to resolve all patterns (eg. files, exclude)
8 | basePath: '',
9 |
10 |
11 | // frameworks to use
12 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
13 | frameworks: ['jspm', 'jasmine', 'es6-shim'],
14 |
15 | jspm: {
16 | // Edit this to your needs
17 | loadFiles: [
18 | 'jspm_packages/github/angular/bower-angular@1.4.1/angular.js',
19 | 'src/**/*.js',
20 | 'src/**/*.html'
21 | ]
22 | },
23 |
24 |
25 | // list of files / patterns to load in the browser
26 | files: [
27 | ],
28 |
29 |
30 | // list of files to exclude
31 | exclude: [],
32 |
33 |
34 | // preprocess matching files before serving them to the browser
35 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
36 | preprocessors: {
37 | 'test/**/*.js': ['babel'],
38 | 'src/**/*.js': ['babel'],
39 | '**/*.html': ['ng-html2js']
40 | },
41 | 'babelPreprocessor': {
42 | options: {
43 | sourceMap: 'inline',
44 | modules: 'system',
45 | moduleIds: false,
46 | optional: [
47 | "es7.decorators",
48 | "es7.classProperties"
49 | ]
50 | }
51 | },
52 |
53 | ngHtml2JsPreprocessor: {
54 | stripPrefix: 'src',
55 | prependPrefix: 'dist',
56 | moduleName: 'mocked-templates'
57 | },
58 |
59 | // test results reporter to use
60 | // possible values: 'dots', 'progress'
61 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter
62 | reporters: ['progress'],
63 |
64 |
65 | // web server port
66 | port: 9876,
67 |
68 |
69 | // enable / disable colors in the output (reporters and logs)
70 | colors: true,
71 |
72 |
73 | // level of logging
74 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
75 | logLevel: config.LOG_INFO,
76 |
77 |
78 | // enable / disable watching file and executing tests whenever any file changes
79 | autoWatch: true,
80 |
81 |
82 | // start these browsers
83 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
84 | browsers: ['PhantomJS'],
85 |
86 |
87 | // Continuous Integration mode
88 | // if true, Karma captures browsers, runs the tests and exits
89 | singleRun: false
90 | });
91 | };
92 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "angular-es6",
3 | "version": "0.2.3",
4 | "description": "AngularJS with JSPM and Babel for ES6",
5 | "keywords": [
6 | "angularjs",
7 | "jspm",
8 | "6to5"
9 | ],
10 | "license": "MIT",
11 | "author": "Vildan Softic ",
12 | "main": "index.js",
13 | "devDependencies": {
14 | "browser-sync": "^1.8.1",
15 | "del": "^1.2.0",
16 | "es5-shim": "^4.1.6",
17 | "es6-shim": "^0.28.1",
18 | "gulp": "^3.8.10",
19 | "gulp-babel": "^5.1.0",
20 | "gulp-changed": "^1.1.0",
21 | "gulp-exec": "^2.1.1",
22 | "gulp-istanbul": "^0.10.0",
23 | "gulp-jshint": "^1.9.0",
24 | "gulp-plumber": "^0.6.6",
25 | "gulp-preprocess": "^1.2.0",
26 | "gulp-sourcemaps": "^1.5.2",
27 | "gulp-useref": "^1.2.0",
28 | "isparta": "^3.0.3",
29 | "jasmine-core": "^2.1.3",
30 | "jshint-stylish": "^1.0.0",
31 | "karma": "^0.12.28",
32 | "karma-babel-preprocessor": "^5.0.0",
33 | "karma-chrome-launcher": "^0.1.7",
34 | "karma-es6-shim": "^0.1.3",
35 | "karma-jasmine": "^0.3.2",
36 | "karma-jspm": "^1.0.1",
37 | "karma-ng-html2js-preprocessor": "^0.1.2",
38 | "karma-phantomjs-launcher": "^0.2.0",
39 | "object.assign": "^1.0.3",
40 | "run-sequence": "^1.0.2",
41 | "unzip": "*"
42 | },
43 | "jspm": {
44 | "dependencies": {
45 | "angular": "github:angular/bower-angular@^1.4.1",
46 | "angular-mocks": "github:angular/angular-mocks@^1.4.1",
47 | "bootstrap": "github:twbs/bootstrap@^3.3.1"
48 | },
49 | "devDependencies": {
50 | "babel": "npm:babel-core@^5.5.6",
51 | "babel-runtime": "npm:babel-runtime@^5.5.6",
52 | "core-js": "npm:core-js@^0.9.4"
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/app.js:
--------------------------------------------------------------------------------
1 | import angular from 'angular';
2 |
3 | import configModule from './config/config';
4 | import {appName} from './config/constants';
5 |
6 | import MainComponent from './components/main/main';
7 |
8 | var app = angular.module(appName, [
9 | configModule.name,
10 | MainComponent.name
11 | ]);
12 |
13 | // INFO: Manual Application Bootstrapping
14 | angular.element(document).ready(function() {
15 | angular.bootstrap(document, [appName]);
16 | });
17 |
18 | // INFO: Export app as so others may require it
19 | export {app};
20 |
--------------------------------------------------------------------------------
/src/components/main/flickr-gallery-directive-spec.js:
--------------------------------------------------------------------------------
1 | import angular from 'angular';
2 | /* globals mocks: false */
3 | /* jshint ignore:start */
4 | import * as mocks from 'angular-mocks';
5 | /* jshint ignore:end */
6 | import {appName, baseURL} from '../../config/constants';
7 |
8 | describe('', () => {
9 |
10 | let element, $scope, ctrl;
11 | beforeEach(() => {
12 | angular.mock.module('mocked-templates');
13 | angular.mock.module(`${appName}.main`);
14 | angular.mock.module('decorators');
15 | });
16 |
17 | beforeEach(inject(($compile, $rootScope) => {
18 | $scope = $rootScope.$new();
19 | $scope.images = [{
20 | title: 'foo'
21 | }, {
22 | title: 'bar'
23 | }];
24 | element = angular.element('');
25 | element = $compile(element)($scope);
26 | $scope.$digest();
27 | ctrl = element.controller('flickrGallery');
28 | }));
29 |
30 | it ('should have a $scope', () => {
31 | expect(ctrl.$scope).toBe(element.isolateScope());
32 | });
33 |
34 | it('should get data', () => {
35 | expect(ctrl.getData()).toBe($scope.images);
36 | });
37 |
38 | });
39 |
--------------------------------------------------------------------------------
/src/components/main/flickr-gallery-directive.js:
--------------------------------------------------------------------------------
1 | import {directive, inject} from '../../config/decorators';
2 | import {baseURL} from '../../config/constants';
3 |
4 | /* jshint ignore:start */
5 | @directive({
6 | restrict: 'E',
7 | scope: {
8 | data: '='
9 | },
10 | templateUrl: `${baseURL}components/main/flickr-gallery.html`
11 | })
12 | @inject('$scope')
13 | /* jshint ignore:end */
14 | export default class FlickrGallery {
15 | constructor ($scope) {
16 | this.$scope = $scope;
17 | }
18 | getData () {
19 | return this.data;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/components/main/flickr-gallery.html:
--------------------------------------------------------------------------------
1 |
3 |
11 |
{{ image.title | titleHeaderStyler }}
12 |
14 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/components/main/flickr-service-spec.js:
--------------------------------------------------------------------------------
1 | import angular from 'angular';
2 | import * as mocks from 'angular-mocks';
3 | import {appName} from '../../config/constants';
4 |
5 | describe('FlickrService', () => {
6 |
7 | var service, $httpBackend;
8 | beforeEach(() => { angular.mock.module(appName); });
9 |
10 | beforeEach(mocks.default.inject((_$httpBackend_, _FlickrService_) => {
11 | service = _FlickrService_;
12 | $httpBackend = _$httpBackend_;
13 |
14 | $httpBackend.whenJSONP(/http:\/\/api.flickr.com/)
15 | .respond({
16 | "title": "Fake response",
17 | "link": "http://fakelink.com",
18 | "description": "",
19 | "modified": "1970-01-01T01:01:01Z",
20 | "generator": "FakeGenerator",
21 | "items": [
22 | {
23 | "title": "TEST",
24 | "link": "http://FakeImageLing",
25 | "media": {"m":"http://fakeImage.jpg"},
26 | "date_taken": "1970-01-01T12:05:34-08:00",
27 | "description": "FakeDescription",
28 | "published": "1970-01-01T22:59:45Z",
29 | "author": "fake@unittest.com",
30 | "author_id": "F@K3",
31 | "tags": "fake tags for testing"
32 | }]
33 | });
34 | }));
35 |
36 |
37 | it("should perform a request against Flickr", () => {
38 | $httpBackend.expectJSONP(/http:\/\/api.flickr.com/);
39 | service.loadImages('AngularJS');
40 | $httpBackend.flush();
41 | });
42 |
43 | it("should contain result with items", function() {
44 | $httpBackend.expectJSONP(/http:\/\/api.flickr.com/);
45 | service.loadImages('AngularJS').then(() => {
46 | expect(service.numberOfHits()).toBe(1);
47 | });
48 | $httpBackend.flush();
49 | });
50 |
51 | });
52 |
--------------------------------------------------------------------------------
/src/components/main/flickr-service.js:
--------------------------------------------------------------------------------
1 | import {service, inject} from '../../config/decorators';
2 |
3 | /* jshint ignore:start */
4 | @service
5 | /* jshint ignore:end */
6 | export default class FlickrService {
7 | /* jshint ignore:start */
8 | @inject $http = null;
9 | images = [];
10 | /* jshint ignore:end */
11 |
12 | numberOfHits() {
13 | return this.images.length;
14 | }
15 |
16 | loadImages(searchTag) {
17 | let URL = `http://api.flickr.com/services/feeds/photos_public.gne?tags=${searchTag}&tagmode=any&format=json&jsoncallback=JSON_CALLBACK`;
18 |
19 | return this.$http
20 | .jsonp(URL)
21 | .then(response => {
22 | this.images = response.data.items;
23 | });
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/components/main/main-controller.js:
--------------------------------------------------------------------------------
1 | import {controller, inject, injectAs} from '../../config/decorators';
2 |
3 | /* jshint ignore:start */
4 | @controller
5 | @inject('$scope')
6 | /* jshint ignore:end */
7 | export class MainCtrl {
8 | /* jshint ignore:start */
9 | @injectAs('FlickrService') service = null;
10 | /* jshint ignore:end */
11 | constructor($scope) {
12 | this.searchTag = 'AngularJS';
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/components/main/main.js:
--------------------------------------------------------------------------------
1 | import angular from 'angular';
2 | import {appName} from '../../config/constants';
3 | import MainController from './main-controller';
4 | import FlickrGallery from './flickr-gallery-directive';
5 | import FlickrService from './flickr-service';
6 | import Shaker from './shaker-directive';
7 | import TitleHeaderStyler from './title-header-styler-filter';
8 |
9 | let MainComponent = angular.module(`${appName}.main`, []);
10 |
11 | export default MainComponent;
12 |
--------------------------------------------------------------------------------
/src/components/main/shaker-directive.js:
--------------------------------------------------------------------------------
1 | import $ from 'jquery';
2 | import {directive, inject} from '../../config/decorators';
3 |
4 | // Add jQuery shake animation
5 | /* jshint ignore:start */
6 | (function($) {
7 | $.fn.shake = function(o) {
8 | if (typeof o === 'function')
9 | o = {callback: o};
10 | // Set options
11 | var o = $.extend({
12 | direction: "left",
13 | distance: 20,
14 | times: 3,
15 | speed: 140,
16 | easing: "swing"
17 | }, o);
18 |
19 | return this.each(function() {
20 |
21 | // Create element
22 | var el = $(this), props = {
23 | position: el.css("position"),
24 | top: el.css("top"),
25 | bottom: el.css("bottom"),
26 | left: el.css("left"),
27 | right: el.css("right")
28 | };
29 |
30 | el.css("position", "relative");
31 |
32 | // Adjust
33 | var ref = (o.direction == "up" || o.direction == "down") ? "top" : "left";
34 | var motion = (o.direction == "up" || o.direction == "left") ? "pos" : "neg";
35 |
36 | // Animation
37 | var animation = {}, animation1 = {}, animation2 = {};
38 | animation[ref] = (motion == "pos" ? "-=" : "+=") + o.distance;
39 | animation1[ref] = (motion == "pos" ? "+=" : "-=") + o.distance * 2;
40 | animation2[ref] = (motion == "pos" ? "-=" : "+=") + o.distance * 2;
41 |
42 | // Animate
43 | el.animate(animation, o.speed, o.easing);
44 | for (var i = 1; i < o.times; i++) { // Shakes
45 | el.animate(animation1, o.speed, o.easing).animate(animation2, o.speed, o.easing);
46 | };
47 | el.animate(animation1, o.speed, o.easing).
48 | animate(animation, o.speed / 2, o.easing, function(){ // Last shake
49 | el.css(props); // Restore
50 | if(o.callback) o.callback.apply(this, arguments); // Callback
51 | });
52 | });
53 | };
54 | })(jQuery);
55 | /* jshint ignore:end */
56 |
57 | /* jshint ignore:start */
58 | @directive({
59 | scope: {
60 | count: '=',
61 | duration: '=',
62 | distance: '='
63 | },
64 | restrict: 'A'
65 | })
66 | @inject('$element')
67 | /* jshint ignore:end */
68 | export class Shaker {
69 | constructor ($element) {
70 | $element.on('click', () => {
71 | this.shake($element, this.count, this.distance, this.duration, this.direction);
72 | });
73 | }
74 |
75 | shake(element, shakes, distance, duration, direction) {
76 | $(element).shake({
77 | direction: direction,
78 | distance: distance,
79 | times: shakes,
80 | speed: duration
81 | });
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/src/components/main/title-header-styler-filter.js:
--------------------------------------------------------------------------------
1 | import {filter, inject} from '../../config/decorators';
2 |
3 | /* jshint ignore:start */
4 | @filter
5 | @inject('$http')
6 | /* jshint ignore:end */
7 | export class TitleHeaderStyler {
8 | constructor ($http) {
9 | this.$http = $http;
10 | }
11 |
12 | filter(input) {
13 | return input.toUpperCase();
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/config/config.js:
--------------------------------------------------------------------------------
1 | import angular from 'angular';
2 | import {appName} from './constants';
3 |
4 | import DecoratorsComponent from './decorators';
5 |
6 | let configComponent = angular.module(`${appName}.core`, [
7 | DecoratorsComponent.name
8 | ]);
9 |
10 | export default configComponent;
11 |
--------------------------------------------------------------------------------
/src/config/constants.js:
--------------------------------------------------------------------------------
1 | export const appName = 'app';
2 | export const baseURL = 'dist/';
3 |
--------------------------------------------------------------------------------
/src/config/decorators.js:
--------------------------------------------------------------------------------
1 | import angular from 'angular';
2 |
3 | let decoratorsModule = angular.module('decorators', []);
4 | export default decoratorsModule;
5 |
6 | let $injector;
7 |
8 | decoratorsModule.run(_$injector_ => {
9 | $injector = _$injector_;
10 | });
11 |
12 | /**
13 | * @example
14 | * import {inject} from './decorators';
15 | *
16 | * @inject('$scope', '$http')
17 | * class MyController {
18 | * constructor($scope, $http) {
19 | * this.$scope = $scope;
20 | * this.$http = $http;
21 | * }
22 | * }
23 | *
24 | * class MyOtherController {
25 | * @inject $http = null;
26 | * @inject MyService = null;
27 | * doSomething () {
28 | * this.MyService.doServiceTask();
29 | * }
30 | * }
31 | */
32 | export function inject (...components) {
33 | if (typeof components[0] === 'object') {
34 | let key = components[1];
35 |
36 | return {
37 | get: () => {
38 | try {
39 | return $injector.get(key);
40 | } catch (err) {
41 | throw new Error(`${key} cannot be injected as a property. Inject it in the controller.`);
42 | }
43 | }
44 | };
45 | } else {
46 | return function decorate (target, key, property) {
47 | target.$inject = components;
48 | };
49 | }
50 | }
51 |
52 | /**
53 | * @example
54 | * import {injectAs} from './decorators';
55 | *
56 | * class MyController {
57 | * @injectAs('MyService') service = null;
58 | * constructor() {
59 | * this.service.doSomething();
60 | * }
61 | * }
62 | */
63 | export function injectAs (dep) {
64 | return function decorate (target, key, descriptor) {
65 | return {
66 | get: () => {
67 | try {
68 | return $injector.get(dep);
69 | } catch (err) {
70 | throw new Error(`${name} cannot be injected as a property. Inject it in the controller.`);
71 | }
72 | }
73 | };
74 | };
75 | }
76 |
77 | /**
78 | * @example
79 | * import {directive, inject} from './decorators';
80 | * import {baseUrl} from './constants';
81 | *
82 | * @directive({
83 | * priority: 42,
84 | * templateUrl: `${baseUrl}/components/myComponent/myView.html`,
85 | * restrict: 'E',
86 | * require: '^parentDirective',
87 | * // etc
88 | * })
89 | * @inject('$scope', '$element', '$attrs')
90 | * class MyView {
91 | * constructor($scope, $element, '$attrs') {
92 | * $element.on('click', e => console.log('click'));
93 | * }
94 | *
95 | * // If you want to use link function :
96 | * static link (scope, element, attrs) {
97 | * element.on('click', e => console.log('click'));
98 | * }
99 | * }
100 | */
101 | export function directive (opts) {
102 | return function decorate (Target) {
103 | let name = opts.name || getTargetName(Target);
104 | name = name.substring(0,1).toLowerCase() + name.substring(1);
105 | function factory(...deps) {
106 | let inject = Target.$inject || [];
107 | let directiveDefinitionObject = {
108 | priority: opts.priority,
109 | template: opts.template,
110 | templateUrl: opts.templateUrl,
111 | transclude: opts.transclude,
112 | restrict: opts.restrict,
113 | templateNamespace: opts.templateNamespace,
114 | scope: opts.scope,
115 | controller: [...inject, function (...deps) {
116 | return new Target(...deps);
117 | }],
118 | controllerAs: opts.controllerAs || 'ctrl',
119 | bindToController: opts.bindToController || true,
120 | require: opts.require
121 | };
122 | if (Target.compile) {
123 | directiveDefinitionObject.compile = function compile(...args) {
124 | return Target.compile(...args);
125 | };
126 | }
127 | if (Target.link) {
128 | directiveDefinitionObject.link = function link(...args) {
129 | return Target.link(...args);
130 | };
131 | }
132 | return directiveDefinitionObject;
133 | }
134 | decoratorsModule.directive(name, factory);
135 | };
136 | }
137 |
138 |
139 | /**
140 | * @example
141 | * import {register} from './decorators';
142 | *
143 | * @register({
144 | * type: 'controller'
145 | * })
146 | * export default class MyController {}
147 | */
148 | export function register (opts) {
149 | return function decorate(target) {
150 | if(opts.inject) {
151 | target.$inject = opts.inject;
152 | }
153 |
154 | let name = opts.name || getTargetName(target);
155 | decoratorsModule[opts.type](name, target);
156 | };
157 | }
158 |
159 | /**
160 | * @example
161 | * import {controller} from './decorators';
162 | *
163 | * @controller
164 | * export default class MyController {}
165 | */
166 | export function controller (target) {
167 | return register({ type: 'controller' })(target);
168 | }
169 | /**
170 | * @example
171 | * import {filter, inject} from './decorators';
172 | *
173 | * @filter
174 | * @inject('$http')
175 | * export default class MyFilter {
176 | * constructor($http) {
177 | * return this.
178 | * }
179 | * filter (input) {
180 | * return input.toUpperCase();
181 | * }
182 | * }
183 | */
184 | export function filter (Target) {
185 | let name = getTargetName(Target);
186 | name = name.substring(0,1).toLowerCase() + name.substring(1);
187 | let deps = Target.$inject || [];
188 | decoratorsModule.filter(name, [...deps, function (...deps) {
189 | let instance = new Target();
190 | return function (...args) { return instance.filter(...args); };
191 | }]);
192 | }
193 | /**
194 | * @example
195 | * import {constant} from './decorators';
196 | *
197 | * @controller
198 | * export default class MyConstant {
199 | * constructor(...deps) {
200 | * return () => {};
201 | * }
202 | * }
203 | */
204 | export function constant (Target) {
205 | let name = getTargetName(Target);
206 | name = name.substring(0,1).toLowerCase() + name.substring(1);
207 | return register({ type: 'constant', name: name })(new Target());
208 | }
209 | /**
210 | * @example
211 | * import {value} from './decorators';
212 | *
213 | * @controller
214 | * export default class MyValue {
215 | * constructor(...deps) {
216 | * return () => {};
217 | * }
218 | * }
219 | */
220 | export function value (Target) {
221 | return register({ type: 'value', name: getTargetName(Target) })(new Target());
222 | }
223 | /**
224 | * @example
225 | * import {factory} from './decorators';
226 | *
227 | * @controller
228 | * export default class MyFactory {}
229 | */
230 | export function factory (target) {
231 | return register({ type: 'factory' })(target);
232 | }
233 | /**
234 | * @example
235 | * import {service} from './decorators';
236 | *
237 | * @controller
238 | * export default class MyService {}
239 | */
240 | export function service (target) {
241 | return register({ type: 'service' })(target);
242 | }
243 | /**
244 | * @example
245 | * import {provider} from './decorators';
246 | *
247 | * @controller
248 | * export default class Myprovider {}
249 | */
250 | export function provider (target) {
251 | return register({ type: 'provider' })(target);
252 | }
253 |
254 |
255 | /**
256 | * Polyfill for IE to return Target.name
257 | */
258 | function getTargetName (o) {
259 | if (o.name) {
260 | return o.name;
261 | }
262 | // if IE
263 | return o.toString().match(/function\s?(.*)\s?\(/)[1];
264 | }
265 |
--------------------------------------------------------------------------------
/tasks/bundle.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp'),
2 | runSequence = require('run-sequence'),
3 | del = require('del'),
4 | exec = require('gulp-exec'),
5 | useref = require('gulp-useref'),
6 | preprocess = require('gulp-preprocess'),
7 | NODE_ENV = process.env.NODE_ENV || 'development',
8 | path;
9 |
10 | module.exports = function (_path_) {
11 | path = _path_;
12 | };
13 |
14 | gulp.task('clean-bundle', function (done) {
15 | del('bundle', done);
16 | });
17 |
18 | gulp.task('bundle-app', function () {
19 | console.log('jspm bundle-sfx ' + path.appmodule + ' ' + path.bundle + 'app.js');
20 | return gulp.src('src/app.js')
21 | .pipe(exec('jspm bundle-sfx ' + path.appmodule + ' ' + path.bundle + 'app.js'))
22 | .pipe(exec.reporter());
23 | });
24 |
25 | gulp.task('bundle-systemjs', function () {
26 | return gulp.src(['config.js', 'jspm_packages/system.js*', 'jspm_packages/es6-module-loader.js*'])
27 | .pipe(gulp.dest(path.bundle));
28 | });
29 |
30 | gulp.task('bundle-css', function () {
31 | return gulp.src(path.css)
32 | .pipe(gulp.dest(path.bundle + 'css'));
33 | });
34 |
35 | gulp.task('bundle-templates', function () {
36 | return gulp.src(path.source + '/**/*.html')
37 | .pipe(gulp.dest(path.bundle + 'dist'));
38 | });
39 |
40 | gulp.task('bundle-index', function () {
41 | var assets = useref.assets();
42 |
43 | return gulp.src(['index.html'])
44 | .pipe(preprocess({
45 | context: {
46 | NODE_ENV: 'production'
47 | }
48 | }))
49 | .pipe(assets)
50 | .pipe(assets.restore())
51 | .pipe(useref())
52 | .pipe(gulp.dest(path.bundle));
53 | });
54 |
55 | gulp.task('bundle-statics', function () {
56 | runSequence(['css', 'build-html'], ['bundle-templates', 'bundle-systemjs', 'bundle-index']);
57 | });
58 |
59 | gulp.task('bundle', function () {
60 | runSequence('clean-bundle', 'bundle-app', 'bundle-statics');
61 | });
62 |
--------------------------------------------------------------------------------
/tasks/cover.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp')
2 | , istanbul = require('gulp-istanbul')
3 | , isparta = require('isparta');
4 |
5 |
6 | var path;
7 |
8 | module.exports = function (_path_) {
9 | path = _path_;
10 | };
11 |
12 | gulp.task('cover', function(cb) {
13 | gulp.src([path.scripts, '!src/**/*-spec.js'])
14 | .pipe(istanbul({
15 | instrumenter: isparta.Instrumenter,
16 | includeUntested: true,
17 | babel: { stage: 0 }
18 | }))
19 | .pipe(istanbul.hookRequire())
20 | .pipe(istanbul.writeReports({
21 | dir: './coverage',
22 | reportOpts: {dir: './coverage'},
23 | reporters: ['html']
24 | }))
25 | .on('finish', cb)
26 | });
--------------------------------------------------------------------------------
/tasks/watch.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp'),
2 | runSequence = require('run-sequence'),
3 | to5 = require('gulp-babel'),
4 | jshint = require('gulp-jshint'),
5 | stylish = require('jshint-stylish'),
6 | assign = Object.assign || require('object.assign'),
7 | fs = require('fs'),
8 | browserSync = require('browser-sync'),
9 | changed = require('gulp-changed'),
10 | plumber = require('gulp-plumber'),
11 | reload = browserSync.reload,
12 | sourcemaps = require('gulp-sourcemaps'),
13 | del = require('del'),
14 | preprocess = require('gulp-preprocess'),
15 | NODE_ENV = process.env.NODE_ENV || 'development';
16 |
17 | var path;
18 |
19 | module.exports = function (_path_) {
20 | path = _path_;
21 | };
22 |
23 | var compilerOptions = {
24 | modules: 'system',
25 | moduleIds: false,
26 | stage: 2,
27 | optional: [
28 | 'es7.decorators',
29 | 'es7.classProperties'
30 | ]
31 | };
32 |
33 | var jshintConfig = {esnext:true};
34 |
35 | gulp.task('build-system', function () {
36 | return gulp.src(path.scripts)
37 | .pipe(plumber())
38 | .pipe(changed(path.output, {extension: '.js'}))
39 | .pipe(sourcemaps.init())
40 | .pipe(to5(assign({}, compilerOptions, {modules:'system'})))
41 | .pipe(sourcemaps.write("."))
42 | .pipe(gulp.dest(path.output))
43 | .pipe(browserSync.reload({ stream: true }));
44 | });
45 |
46 | gulp.task('build-html', function () {
47 | return gulp.src(path.html)
48 | .pipe(changed(path.output, {extension: '.html'}))
49 | .pipe(preprocess({
50 | context: {
51 | NODE_ENV: NODE_ENV
52 | }
53 | }))
54 | .pipe(gulp.dest(path.output))
55 | .pipe(browserSync.reload({ stream: true }));
56 | });
57 |
58 | gulp.task('lint', function() {
59 | return gulp.src(path.scripts)
60 | .pipe(jshint(jshintConfig))
61 | .pipe(jshint.reporter(stylish));
62 | });
63 |
64 | gulp.task('clean-dist', function (done) {
65 | del('dist', done);
66 | });
67 |
68 | gulp.task('build', function(callback) {
69 | return runSequence(
70 | ['build-system', 'build-html', 'css'],
71 | callback
72 | );
73 | });
74 |
75 | gulp.task('serve', ['build'], function(done) {
76 | browserSync({
77 | open: false,
78 | port: 9000,
79 | files: {
80 | src: path.css
81 | },
82 | server: {
83 | baseDir: ['.'],
84 | middleware: function (req, res, next) {
85 | if (req.url.match(/^(.(?!\..+))*$/) ||
86 | req.url === 'index.html') {
87 | req.url = '/dist/index.html';
88 | }
89 | res.setHeader('Access-Control-Allow-Origin', '*');
90 | next();
91 | }
92 | }
93 | }, done);
94 | });
95 |
96 | gulp.task('css', function () {
97 | return gulp.src(path.css)
98 | .pipe(reload({stream:true}));
99 | });
100 |
101 | gulp.task('watch', ['serve'], function() {
102 | var watcher = gulp.watch([path.scripts, path.html], ['build']);
103 | watcher.on('change', function(event) {
104 | console.log('File ' + event.path + ' was ' + event.type + ', running tasks...');
105 | });
106 | gulp.watch(path.css, ['css']);
107 | });
108 |
--------------------------------------------------------------------------------