Commit 33ee6d0a9d1dfc968dcc7d318daa210c0cf8ead8
0 parents
Exists in
master
and in
38 other branches
Initial commit
Showing
57 changed files
with
1599 additions
and
0 deletions
Show diff stats
1 | +++ a/.editorconfig | ||
@@ -0,0 +1,13 @@ | @@ -0,0 +1,13 @@ | ||
1 | +# http://editorconfig.org | ||
2 | +root = true | ||
3 | + | ||
4 | +[*] | ||
5 | +indent_style = space | ||
6 | +indent_size = 2 | ||
7 | +end_of_line = lf | ||
8 | +charset = utf-8 | ||
9 | +trim_trailing_whitespace = true | ||
10 | +insert_final_newline = true | ||
11 | + | ||
12 | +[*.md] | ||
13 | +trim_trailing_whitespace = false |
1 | +++ a/.yo-rc.json | ||
@@ -0,0 +1,78 @@ | @@ -0,0 +1,78 @@ | ||
1 | +{ | ||
2 | + "generator-gulp-angular": { | ||
3 | + "version": "1.0.2", | ||
4 | + "props": { | ||
5 | + "angularVersion": "~1.4.2", | ||
6 | + "angularModules": [ | ||
7 | + { | ||
8 | + "key": "animate", | ||
9 | + "module": "ngAnimate" | ||
10 | + }, | ||
11 | + { | ||
12 | + "key": "cookies", | ||
13 | + "module": "ngCookies" | ||
14 | + }, | ||
15 | + { | ||
16 | + "key": "touch", | ||
17 | + "module": "ngTouch" | ||
18 | + }, | ||
19 | + { | ||
20 | + "key": "sanitize", | ||
21 | + "module": "ngSanitize" | ||
22 | + }, | ||
23 | + { | ||
24 | + "key": "messages", | ||
25 | + "module": "ngMessages" | ||
26 | + }, | ||
27 | + { | ||
28 | + "key": "aria", | ||
29 | + "module": "ngAria" | ||
30 | + } | ||
31 | + ], | ||
32 | + "jQuery": { | ||
33 | + "key": "jqLite" | ||
34 | + }, | ||
35 | + "resource": { | ||
36 | + "key": "angular-resource", | ||
37 | + "module": "ngResource" | ||
38 | + }, | ||
39 | + "router": { | ||
40 | + "key": "angular-route", | ||
41 | + "module": "ngRoute" | ||
42 | + }, | ||
43 | + "ui": { | ||
44 | + "key": "bootstrap", | ||
45 | + "module": null | ||
46 | + }, | ||
47 | + "bootstrapComponents": { | ||
48 | + "key": "ui-bootstrap", | ||
49 | + "module": "ui.bootstrap" | ||
50 | + }, | ||
51 | + "cssPreprocessor": { | ||
52 | + "key": "node-sass", | ||
53 | + "extension": "scss" | ||
54 | + }, | ||
55 | + "jsPreprocessor": { | ||
56 | + "key": "noJsPrepro", | ||
57 | + "extension": "js", | ||
58 | + "srcExtension": "js" | ||
59 | + }, | ||
60 | + "htmlPreprocessor": { | ||
61 | + "key": "noHtmlPrepro", | ||
62 | + "extension": "html" | ||
63 | + }, | ||
64 | + "foundationComponents": { | ||
65 | + "name": null, | ||
66 | + "version": null, | ||
67 | + "key": null, | ||
68 | + "module": null | ||
69 | + }, | ||
70 | + "paths": { | ||
71 | + "src": "src", | ||
72 | + "dist": "dist", | ||
73 | + "e2e": "e2e", | ||
74 | + "tmp": ".tmp" | ||
75 | + } | ||
76 | + } | ||
77 | + } | ||
78 | +} | ||
0 | \ No newline at end of file | 79 | \ No newline at end of file |
1 | +++ a/bower.json | ||
@@ -0,0 +1,39 @@ | @@ -0,0 +1,39 @@ | ||
1 | +{ | ||
2 | + "name": "angular", | ||
3 | + "version": "0.0.0", | ||
4 | + "dependencies": { | ||
5 | + "angular-animate": "~1.4.2", | ||
6 | + "angular-cookies": "~1.4.2", | ||
7 | + "angular-touch": "~1.4.2", | ||
8 | + "angular-sanitize": "~1.4.2", | ||
9 | + "angular-messages": "~1.4.2", | ||
10 | + "angular-aria": "~1.4.2", | ||
11 | + "angular-resource": "~1.4.2", | ||
12 | + "angular-route": "~1.4.2", | ||
13 | + "bootstrap-sass": "~3.3.5", | ||
14 | + "angular-bootstrap": "~0.13.4", | ||
15 | + "malarkey": "yuanqing/malarkey#~1.3.1", | ||
16 | + "angular-toastr": "~1.5.0", | ||
17 | + "moment": "~2.10.6", | ||
18 | + "animate.css": "~3.4.0", | ||
19 | + "angular": "~1.4.2" | ||
20 | + }, | ||
21 | + "devDependencies": { | ||
22 | + "angular-mocks": "~1.4.2" | ||
23 | + }, | ||
24 | + "overrides": { | ||
25 | + "bootstrap-sass": { | ||
26 | + "main": [ | ||
27 | + "assets/stylesheets/_bootstrap.scss", | ||
28 | + "assets/fonts/bootstrap/glyphicons-halflings-regular.eot", | ||
29 | + "assets/fonts/bootstrap/glyphicons-halflings-regular.svg", | ||
30 | + "assets/fonts/bootstrap/glyphicons-halflings-regular.ttf", | ||
31 | + "assets/fonts/bootstrap/glyphicons-halflings-regular.woff", | ||
32 | + "assets/fonts/bootstrap/glyphicons-halflings-regular.woff2" | ||
33 | + ] | ||
34 | + } | ||
35 | + }, | ||
36 | + "resolutions": { | ||
37 | + "angular": "~1.4.2" | ||
38 | + } | ||
39 | +} |
1 | +++ a/e2e/main.po.js | ||
@@ -0,0 +1,15 @@ | @@ -0,0 +1,15 @@ | ||
1 | +/** | ||
2 | + * This file uses the Page Object pattern to define the main page for tests | ||
3 | + * https://docs.google.com/presentation/d/1B6manhG0zEXkC-H-tPo2vwU06JhL8w9-XCF9oehXzAQ | ||
4 | + */ | ||
5 | + | ||
6 | +'use strict'; | ||
7 | + | ||
8 | +var MainPage = function() { | ||
9 | + this.jumbEl = element(by.css('.jumbotron')); | ||
10 | + this.h1El = this.jumbEl.element(by.css('h1')); | ||
11 | + this.imgEl = this.jumbEl.element(by.css('img')); | ||
12 | + this.thumbnailEls = element(by.css('body')).all(by.repeater('awesomeThing in main.awesomeThings')); | ||
13 | +}; | ||
14 | + | ||
15 | +module.exports = new MainPage(); |
1 | +++ a/e2e/main.spec.js | ||
@@ -0,0 +1,21 @@ | @@ -0,0 +1,21 @@ | ||
1 | +'use strict'; | ||
2 | + | ||
3 | +describe('The main view', function () { | ||
4 | + var page; | ||
5 | + | ||
6 | + beforeEach(function () { | ||
7 | + browser.get('/index.html'); | ||
8 | + page = require('./main.po'); | ||
9 | + }); | ||
10 | + | ||
11 | + it('should include jumbotron with correct data', function() { | ||
12 | + expect(page.h1El.getText()).toBe('\'Allo, \'Allo!'); | ||
13 | + expect(page.imgEl.getAttribute('src')).toMatch(/assets\/images\/yeoman.png$/); | ||
14 | + expect(page.imgEl.getAttribute('alt')).toBe('I\'m Yeoman'); | ||
15 | + }); | ||
16 | + | ||
17 | + it('should list more than 5 awesome things', function () { | ||
18 | + expect(page.thumbnailEls.count()).toBeGreaterThan(5); | ||
19 | + }); | ||
20 | + | ||
21 | +}); |
1 | +++ a/gulp/build.js | ||
@@ -0,0 +1,98 @@ | @@ -0,0 +1,98 @@ | ||
1 | +'use strict'; | ||
2 | + | ||
3 | +var path = require('path'); | ||
4 | +var gulp = require('gulp'); | ||
5 | +var conf = require('./conf'); | ||
6 | + | ||
7 | +var $ = require('gulp-load-plugins')({ | ||
8 | + pattern: ['gulp-*', 'main-bower-files', 'uglify-save-license', 'del'] | ||
9 | +}); | ||
10 | + | ||
11 | +gulp.task('partials', function () { | ||
12 | + return gulp.src([ | ||
13 | + path.join(conf.paths.src, '/app/**/*.html'), | ||
14 | + path.join(conf.paths.tmp, '/serve/app/**/*.html') | ||
15 | + ]) | ||
16 | + .pipe($.minifyHtml({ | ||
17 | + empty: true, | ||
18 | + spare: true, | ||
19 | + quotes: true | ||
20 | + })) | ||
21 | + .pipe($.angularTemplatecache('templateCacheHtml.js', { | ||
22 | + module: 'angular', | ||
23 | + root: 'app' | ||
24 | + })) | ||
25 | + .pipe(gulp.dest(conf.paths.tmp + '/partials/')); | ||
26 | +}); | ||
27 | + | ||
28 | +gulp.task('html', ['inject', 'partials'], function () { | ||
29 | + var partialsInjectFile = gulp.src(path.join(conf.paths.tmp, '/partials/templateCacheHtml.js'), { read: false }); | ||
30 | + var partialsInjectOptions = { | ||
31 | + starttag: '<!-- inject:partials -->', | ||
32 | + ignorePath: path.join(conf.paths.tmp, '/partials'), | ||
33 | + addRootSlash: false | ||
34 | + }; | ||
35 | + | ||
36 | + var htmlFilter = $.filter('*.html', { restore: true }); | ||
37 | + var jsFilter = $.filter('**/*.js', { restore: true }); | ||
38 | + var cssFilter = $.filter('**/*.css', { restore: true }); | ||
39 | + var assets; | ||
40 | + | ||
41 | + return gulp.src(path.join(conf.paths.tmp, '/serve/*.html')) | ||
42 | + .pipe($.inject(partialsInjectFile, partialsInjectOptions)) | ||
43 | + .pipe(assets = $.useref.assets()) | ||
44 | + .pipe($.rev()) | ||
45 | + .pipe(jsFilter) | ||
46 | + .pipe($.sourcemaps.init()) | ||
47 | + .pipe($.ngAnnotate()) | ||
48 | + .pipe($.uglify({ preserveComments: $.uglifySaveLicense })).on('error', conf.errorHandler('Uglify')) | ||
49 | + .pipe($.sourcemaps.write('maps')) | ||
50 | + .pipe(jsFilter.restore) | ||
51 | + .pipe(cssFilter) | ||
52 | + .pipe($.sourcemaps.init()) | ||
53 | + .pipe($.replace('../../bower_components/bootstrap-sass/assets/fonts/bootstrap/', '../fonts/')) | ||
54 | + .pipe($.minifyCss({ processImport: false })) | ||
55 | + .pipe($.sourcemaps.write('maps')) | ||
56 | + .pipe(cssFilter.restore) | ||
57 | + .pipe(assets.restore()) | ||
58 | + .pipe($.useref()) | ||
59 | + .pipe($.revReplace()) | ||
60 | + .pipe(htmlFilter) | ||
61 | + .pipe($.minifyHtml({ | ||
62 | + empty: true, | ||
63 | + spare: true, | ||
64 | + quotes: true, | ||
65 | + conditionals: true | ||
66 | + })) | ||
67 | + .pipe(htmlFilter.restore) | ||
68 | + .pipe(gulp.dest(path.join(conf.paths.dist, '/'))) | ||
69 | + .pipe($.size({ title: path.join(conf.paths.dist, '/'), showFiles: true })); | ||
70 | + }); | ||
71 | + | ||
72 | +// Only applies for fonts from bower dependencies | ||
73 | +// Custom fonts are handled by the "other" task | ||
74 | +gulp.task('fonts', function () { | ||
75 | + return gulp.src($.mainBowerFiles()) | ||
76 | + .pipe($.filter('**/*.{eot,svg,ttf,woff,woff2}')) | ||
77 | + .pipe($.flatten()) | ||
78 | + .pipe(gulp.dest(path.join(conf.paths.dist, '/fonts/'))); | ||
79 | +}); | ||
80 | + | ||
81 | +gulp.task('other', function () { | ||
82 | + var fileFilter = $.filter(function (file) { | ||
83 | + return file.stat.isFile(); | ||
84 | + }); | ||
85 | + | ||
86 | + return gulp.src([ | ||
87 | + path.join(conf.paths.src, '/**/*'), | ||
88 | + path.join('!' + conf.paths.src, '/**/*.{html,css,js,scss}') | ||
89 | + ]) | ||
90 | + .pipe(fileFilter) | ||
91 | + .pipe(gulp.dest(path.join(conf.paths.dist, '/'))); | ||
92 | +}); | ||
93 | + | ||
94 | +gulp.task('clean', function () { | ||
95 | + return $.del([path.join(conf.paths.dist, '/'), path.join(conf.paths.tmp, '/')]); | ||
96 | +}); | ||
97 | + | ||
98 | +gulp.task('build', ['html', 'fonts', 'other']); |
1 | +++ a/gulp/conf.js | ||
@@ -0,0 +1,41 @@ | @@ -0,0 +1,41 @@ | ||
1 | +/** | ||
2 | + * This file contains the variables used in other gulp files | ||
3 | + * which defines tasks | ||
4 | + * By design, we only put there very generic config values | ||
5 | + * which are used in several places to keep good readability | ||
6 | + * of the tasks | ||
7 | + */ | ||
8 | + | ||
9 | +var gutil = require('gulp-util'); | ||
10 | + | ||
11 | +/** | ||
12 | + * The main paths of your project handle these with care | ||
13 | + */ | ||
14 | +exports.paths = { | ||
15 | + src: 'src', | ||
16 | + dist: 'dist', | ||
17 | + tmp: '.tmp', | ||
18 | + e2e: 'e2e' | ||
19 | +}; | ||
20 | + | ||
21 | +/** | ||
22 | + * Wiredep is the lib which inject bower dependencies in your project | ||
23 | + * Mainly used to inject script tags in the index.html but also used | ||
24 | + * to inject css preprocessor deps and js files in karma | ||
25 | + */ | ||
26 | +exports.wiredep = { | ||
27 | + exclude: [/jquery/, /\/bootstrap\.js$/, /\/bootstrap-sass\/.*\.js/, /\/bootstrap\.css/], | ||
28 | + directory: 'bower_components' | ||
29 | +}; | ||
30 | + | ||
31 | +/** | ||
32 | + * Common implementation for an error handler of a Gulp plugin | ||
33 | + */ | ||
34 | +exports.errorHandler = function(title) { | ||
35 | + 'use strict'; | ||
36 | + | ||
37 | + return function(err) { | ||
38 | + gutil.log(gutil.colors.red('[' + title + ']'), err.toString()); | ||
39 | + this.emit('end'); | ||
40 | + }; | ||
41 | +}; |
1 | +++ a/gulp/e2e-tests.js | ||
@@ -0,0 +1,38 @@ | @@ -0,0 +1,38 @@ | ||
1 | +'use strict'; | ||
2 | + | ||
3 | +var path = require('path'); | ||
4 | +var gulp = require('gulp'); | ||
5 | +var conf = require('./conf'); | ||
6 | + | ||
7 | +var browserSync = require('browser-sync'); | ||
8 | + | ||
9 | +var $ = require('gulp-load-plugins')(); | ||
10 | + | ||
11 | +// Downloads the selenium webdriver | ||
12 | +gulp.task('webdriver-update', $.protractor.webdriver_update); | ||
13 | + | ||
14 | +gulp.task('webdriver-standalone', $.protractor.webdriver_standalone); | ||
15 | + | ||
16 | +function runProtractor (done) { | ||
17 | + var params = process.argv; | ||
18 | + var args = params.length > 3 ? [params[3], params[4]] : []; | ||
19 | + | ||
20 | + gulp.src(path.join(conf.paths.e2e, '/**/*.js')) | ||
21 | + .pipe($.protractor.protractor({ | ||
22 | + configFile: 'protractor.conf.js', | ||
23 | + args: args | ||
24 | + })) | ||
25 | + .on('error', function (err) { | ||
26 | + // Make sure failed tests cause gulp to exit non-zero | ||
27 | + throw err; | ||
28 | + }) | ||
29 | + .on('end', function () { | ||
30 | + // Close browser sync server | ||
31 | + browserSync.exit(); | ||
32 | + done(); | ||
33 | + }); | ||
34 | +} | ||
35 | + | ||
36 | +gulp.task('protractor', ['protractor:src']); | ||
37 | +gulp.task('protractor:src', ['serve:e2e', 'webdriver-update'], runProtractor); | ||
38 | +gulp.task('protractor:dist', ['serve:e2e-dist', 'webdriver-update'], runProtractor); |
1 | +++ a/gulp/inject.js | ||
@@ -0,0 +1,42 @@ | @@ -0,0 +1,42 @@ | ||
1 | +'use strict'; | ||
2 | + | ||
3 | +var path = require('path'); | ||
4 | +var gulp = require('gulp'); | ||
5 | +var conf = require('./conf'); | ||
6 | + | ||
7 | +var $ = require('gulp-load-plugins')(); | ||
8 | + | ||
9 | +var wiredep = require('wiredep').stream; | ||
10 | +var _ = require('lodash'); | ||
11 | + | ||
12 | +var browserSync = require('browser-sync'); | ||
13 | + | ||
14 | +gulp.task('inject-reload', ['inject'], function() { | ||
15 | + browserSync.reload(); | ||
16 | +}); | ||
17 | + | ||
18 | +gulp.task('inject', ['scripts', 'styles'], function () { | ||
19 | + var injectStyles = gulp.src([ | ||
20 | + path.join(conf.paths.tmp, '/serve/app/**/*.css'), | ||
21 | + path.join('!' + conf.paths.tmp, '/serve/app/vendor.css') | ||
22 | + ], { read: false }); | ||
23 | + | ||
24 | + var injectScripts = gulp.src([ | ||
25 | + path.join(conf.paths.src, '/app/**/*.module.js'), | ||
26 | + path.join(conf.paths.src, '/app/**/*.js'), | ||
27 | + path.join('!' + conf.paths.src, '/app/**/*.spec.js'), | ||
28 | + path.join('!' + conf.paths.src, '/app/**/*.mock.js'), | ||
29 | + ]) | ||
30 | + .pipe($.angularFilesort()).on('error', conf.errorHandler('AngularFilesort')); | ||
31 | + | ||
32 | + var injectOptions = { | ||
33 | + ignorePath: [conf.paths.src, path.join(conf.paths.tmp, '/serve')], | ||
34 | + addRootSlash: false | ||
35 | + }; | ||
36 | + | ||
37 | + return gulp.src(path.join(conf.paths.src, '/*.html')) | ||
38 | + .pipe($.inject(injectStyles, injectOptions)) | ||
39 | + .pipe($.inject(injectScripts, injectOptions)) | ||
40 | + .pipe(wiredep(_.extend({}, conf.wiredep))) | ||
41 | + .pipe(gulp.dest(path.join(conf.paths.tmp, '/serve'))); | ||
42 | +}); |
1 | +++ a/gulp/scripts.js | ||
@@ -0,0 +1,26 @@ | @@ -0,0 +1,26 @@ | ||
1 | +'use strict'; | ||
2 | + | ||
3 | +var path = require('path'); | ||
4 | +var gulp = require('gulp'); | ||
5 | +var conf = require('./conf'); | ||
6 | + | ||
7 | +var browserSync = require('browser-sync'); | ||
8 | + | ||
9 | +var $ = require('gulp-load-plugins')(); | ||
10 | + | ||
11 | + | ||
12 | +gulp.task('scripts-reload', function() { | ||
13 | + return buildScripts() | ||
14 | + .pipe(browserSync.stream()); | ||
15 | +}); | ||
16 | + | ||
17 | +gulp.task('scripts', function() { | ||
18 | + return buildScripts(); | ||
19 | +}); | ||
20 | + | ||
21 | +function buildScripts() { | ||
22 | + return gulp.src(path.join(conf.paths.src, '/app/**/*.js')) | ||
23 | + .pipe($.eslint()) | ||
24 | + .pipe($.eslint.format()) | ||
25 | + .pipe($.size()) | ||
26 | +}; |
1 | +++ a/gulp/server.js | ||
@@ -0,0 +1,63 @@ | @@ -0,0 +1,63 @@ | ||
1 | +'use strict'; | ||
2 | + | ||
3 | +var path = require('path'); | ||
4 | +var gulp = require('gulp'); | ||
5 | +var conf = require('./conf'); | ||
6 | + | ||
7 | +var browserSync = require('browser-sync'); | ||
8 | +var browserSyncSpa = require('browser-sync-spa'); | ||
9 | + | ||
10 | +var util = require('util'); | ||
11 | + | ||
12 | +var proxyMiddleware = require('http-proxy-middleware'); | ||
13 | + | ||
14 | +function browserSyncInit(baseDir, browser) { | ||
15 | + browser = browser === undefined ? 'default' : browser; | ||
16 | + | ||
17 | + var routes = null; | ||
18 | + if(baseDir === conf.paths.src || (util.isArray(baseDir) && baseDir.indexOf(conf.paths.src) !== -1)) { | ||
19 | + routes = { | ||
20 | + '/bower_components': 'bower_components' | ||
21 | + }; | ||
22 | + } | ||
23 | + | ||
24 | + var server = { | ||
25 | + baseDir: baseDir, | ||
26 | + routes: routes | ||
27 | + }; | ||
28 | + | ||
29 | + /* | ||
30 | + * You can add a proxy to your backend by uncommenting the line below. | ||
31 | + * You just have to configure a context which will we redirected and the target url. | ||
32 | + * Example: $http.get('/users') requests will be automatically proxified. | ||
33 | + * | ||
34 | + * For more details and option, https://github.com/chimurai/http-proxy-middleware/blob/v0.9.0/README.md | ||
35 | + */ | ||
36 | + // server.middleware = proxyMiddleware('/users', {target: 'http://jsonplaceholder.typicode.com', changeOrigin: true}); | ||
37 | + | ||
38 | + browserSync.instance = browserSync.init({ | ||
39 | + startPath: '/', | ||
40 | + server: server, | ||
41 | + browser: browser | ||
42 | + }); | ||
43 | +} | ||
44 | + | ||
45 | +browserSync.use(browserSyncSpa({ | ||
46 | + selector: '[ng-app]'// Only needed for angular apps | ||
47 | +})); | ||
48 | + | ||
49 | +gulp.task('serve', ['watch'], function () { | ||
50 | + browserSyncInit([path.join(conf.paths.tmp, '/serve'), conf.paths.src]); | ||
51 | +}); | ||
52 | + | ||
53 | +gulp.task('serve:dist', ['build'], function () { | ||
54 | + browserSyncInit(conf.paths.dist); | ||
55 | +}); | ||
56 | + | ||
57 | +gulp.task('serve:e2e', ['inject'], function () { | ||
58 | + browserSyncInit([conf.paths.tmp + '/serve', conf.paths.src], []); | ||
59 | +}); | ||
60 | + | ||
61 | +gulp.task('serve:e2e-dist', ['build'], function () { | ||
62 | + browserSyncInit(conf.paths.dist, []); | ||
63 | +}); |
1 | +++ a/gulp/styles.js | ||
@@ -0,0 +1,54 @@ | @@ -0,0 +1,54 @@ | ||
1 | +'use strict'; | ||
2 | + | ||
3 | +var path = require('path'); | ||
4 | +var gulp = require('gulp'); | ||
5 | +var conf = require('./conf'); | ||
6 | + | ||
7 | +var browserSync = require('browser-sync'); | ||
8 | + | ||
9 | +var $ = require('gulp-load-plugins')(); | ||
10 | + | ||
11 | +var wiredep = require('wiredep').stream; | ||
12 | +var _ = require('lodash'); | ||
13 | + | ||
14 | +gulp.task('styles-reload', ['styles'], function() { | ||
15 | + return buildStyles() | ||
16 | + .pipe(browserSync.stream()); | ||
17 | +}); | ||
18 | + | ||
19 | +gulp.task('styles', function() { | ||
20 | + return buildStyles(); | ||
21 | +}); | ||
22 | + | ||
23 | +var buildStyles = function() { | ||
24 | + var sassOptions = { | ||
25 | + style: 'expanded' | ||
26 | + }; | ||
27 | + | ||
28 | + var injectFiles = gulp.src([ | ||
29 | + path.join(conf.paths.src, '/app/**/*.scss'), | ||
30 | + path.join('!' + conf.paths.src, '/app/index.scss') | ||
31 | + ], { read: false }); | ||
32 | + | ||
33 | + var injectOptions = { | ||
34 | + transform: function(filePath) { | ||
35 | + filePath = filePath.replace(conf.paths.src + '/app/', ''); | ||
36 | + return '@import "' + filePath + '";'; | ||
37 | + }, | ||
38 | + starttag: '// injector', | ||
39 | + endtag: '// endinjector', | ||
40 | + addRootSlash: false | ||
41 | + }; | ||
42 | + | ||
43 | + | ||
44 | + return gulp.src([ | ||
45 | + path.join(conf.paths.src, '/app/index.scss') | ||
46 | + ]) | ||
47 | + .pipe($.inject(injectFiles, injectOptions)) | ||
48 | + .pipe(wiredep(_.extend({}, conf.wiredep))) | ||
49 | + .pipe($.sourcemaps.init()) | ||
50 | + .pipe($.sass(sassOptions)).on('error', conf.errorHandler('Sass')) | ||
51 | + .pipe($.autoprefixer()).on('error', conf.errorHandler('Autoprefixer')) | ||
52 | + .pipe($.sourcemaps.write()) | ||
53 | + .pipe(gulp.dest(path.join(conf.paths.tmp, '/serve/app/'))); | ||
54 | +}; |
1 | +++ a/gulp/unit-tests.js | ||
@@ -0,0 +1,52 @@ | @@ -0,0 +1,52 @@ | ||
1 | +'use strict'; | ||
2 | + | ||
3 | +var path = require('path'); | ||
4 | +var gulp = require('gulp'); | ||
5 | +var conf = require('./conf'); | ||
6 | + | ||
7 | +var karma = require('karma'); | ||
8 | + | ||
9 | +var pathSrcHtml = [ | ||
10 | + path.join(conf.paths.src, '/**/*.html') | ||
11 | +]; | ||
12 | + | ||
13 | +var pathSrcJs = [ | ||
14 | + path.join(conf.paths.src, '/**/!(*.spec).js') | ||
15 | +]; | ||
16 | + | ||
17 | +function runTests (singleRun, done) { | ||
18 | + var reporters = ['progress']; | ||
19 | + var preprocessors = {}; | ||
20 | + | ||
21 | + pathSrcHtml.forEach(function(path) { | ||
22 | + preprocessors[path] = ['ng-html2js']; | ||
23 | + }); | ||
24 | + | ||
25 | + if (singleRun) { | ||
26 | + pathSrcJs.forEach(function(path) { | ||
27 | + preprocessors[path] = ['coverage']; | ||
28 | + }); | ||
29 | + reporters.push('coverage') | ||
30 | + } | ||
31 | + | ||
32 | + var localConfig = { | ||
33 | + configFile: path.join(__dirname, '/../karma.conf.js'), | ||
34 | + singleRun: singleRun, | ||
35 | + autoWatch: !singleRun, | ||
36 | + reporters: reporters, | ||
37 | + preprocessors: preprocessors | ||
38 | + }; | ||
39 | + | ||
40 | + var server = new karma.Server(localConfig, function(failCount) { | ||
41 | + done(failCount ? new Error("Failed " + failCount + " tests.") : null); | ||
42 | + }) | ||
43 | + server.start(); | ||
44 | +} | ||
45 | + | ||
46 | +gulp.task('test', ['scripts'], function(done) { | ||
47 | + runTests(true, done); | ||
48 | +}); | ||
49 | + | ||
50 | +gulp.task('test:auto', ['watch'], function(done) { | ||
51 | + runTests(false, done); | ||
52 | +}); |
1 | +++ a/gulp/watch.js | ||
@@ -0,0 +1,39 @@ | @@ -0,0 +1,39 @@ | ||
1 | +'use strict'; | ||
2 | + | ||
3 | +var path = require('path'); | ||
4 | +var gulp = require('gulp'); | ||
5 | +var conf = require('./conf'); | ||
6 | + | ||
7 | +var browserSync = require('browser-sync'); | ||
8 | + | ||
9 | +function isOnlyChange(event) { | ||
10 | + return event.type === 'changed'; | ||
11 | +} | ||
12 | + | ||
13 | +gulp.task('watch', ['inject'], function () { | ||
14 | + | ||
15 | + gulp.watch([path.join(conf.paths.src, '/*.html'), 'bower.json'], ['inject-reload']); | ||
16 | + | ||
17 | + gulp.watch([ | ||
18 | + path.join(conf.paths.src, '/app/**/*.css'), | ||
19 | + path.join(conf.paths.src, '/app/**/*.scss') | ||
20 | + ], function(event) { | ||
21 | + if(isOnlyChange(event)) { | ||
22 | + gulp.start('styles-reload'); | ||
23 | + } else { | ||
24 | + gulp.start('inject-reload'); | ||
25 | + } | ||
26 | + }); | ||
27 | + | ||
28 | + gulp.watch(path.join(conf.paths.src, '/app/**/*.js'), function(event) { | ||
29 | + if(isOnlyChange(event)) { | ||
30 | + gulp.start('scripts-reload'); | ||
31 | + } else { | ||
32 | + gulp.start('inject-reload'); | ||
33 | + } | ||
34 | + }); | ||
35 | + | ||
36 | + gulp.watch(path.join(conf.paths.src, '/app/**/*.html'), function(event) { | ||
37 | + browserSync.reload(event.path); | ||
38 | + }); | ||
39 | +}); |
1 | +++ a/gulpfile.js | ||
@@ -0,0 +1,29 @@ | @@ -0,0 +1,29 @@ | ||
1 | +/** | ||
2 | + * Welcome to your gulpfile! | ||
3 | + * The gulp tasks are splitted in several files in the gulp directory | ||
4 | + * because putting all here was really too long | ||
5 | + */ | ||
6 | + | ||
7 | +'use strict'; | ||
8 | + | ||
9 | +var gulp = require('gulp'); | ||
10 | +var wrench = require('wrench'); | ||
11 | + | ||
12 | +/** | ||
13 | + * This will load all js or coffee files in the gulp directory | ||
14 | + * in order to load all gulp tasks | ||
15 | + */ | ||
16 | +wrench.readdirSyncRecursive('./gulp').filter(function(file) { | ||
17 | + return (/\.(js|coffee)$/i).test(file); | ||
18 | +}).map(function(file) { | ||
19 | + require('./gulp/' + file); | ||
20 | +}); | ||
21 | + | ||
22 | + | ||
23 | +/** | ||
24 | + * Default task clean temporaries directories and launch the | ||
25 | + * main optimization build task | ||
26 | + */ | ||
27 | +gulp.task('default', ['clean'], function () { | ||
28 | + gulp.start('build'); | ||
29 | +}); |
1 | +++ a/karma.conf.js | ||
@@ -0,0 +1,110 @@ | @@ -0,0 +1,110 @@ | ||
1 | +'use strict'; | ||
2 | + | ||
3 | +var path = require('path'); | ||
4 | +var conf = require('./gulp/conf'); | ||
5 | + | ||
6 | +var _ = require('lodash'); | ||
7 | +var wiredep = require('wiredep'); | ||
8 | + | ||
9 | +var pathSrcHtml = [ | ||
10 | + path.join(conf.paths.src, '/**/*.html') | ||
11 | +]; | ||
12 | + | ||
13 | +function listFiles() { | ||
14 | + var wiredepOptions = _.extend({}, conf.wiredep, { | ||
15 | + dependencies: true, | ||
16 | + devDependencies: true | ||
17 | + }); | ||
18 | + | ||
19 | + var patterns = wiredep(wiredepOptions).js | ||
20 | + .concat([ | ||
21 | + path.join(conf.paths.src, '/app/**/*.module.js'), | ||
22 | + path.join(conf.paths.src, '/app/**/*.js'), | ||
23 | + path.join(conf.paths.src, '/**/*.spec.js'), | ||
24 | + path.join(conf.paths.src, '/**/*.mock.js'), | ||
25 | + ]) | ||
26 | + .concat(pathSrcHtml); | ||
27 | + | ||
28 | + var files = patterns.map(function(pattern) { | ||
29 | + return { | ||
30 | + pattern: pattern | ||
31 | + }; | ||
32 | + }); | ||
33 | + files.push({ | ||
34 | + pattern: path.join(conf.paths.src, '/assets/**/*'), | ||
35 | + included: false, | ||
36 | + served: true, | ||
37 | + watched: false | ||
38 | + }); | ||
39 | + return files; | ||
40 | +} | ||
41 | + | ||
42 | +module.exports = function(config) { | ||
43 | + | ||
44 | + var configuration = { | ||
45 | + files: listFiles(), | ||
46 | + | ||
47 | + singleRun: true, | ||
48 | + | ||
49 | + autoWatch: false, | ||
50 | + | ||
51 | + ngHtml2JsPreprocessor: { | ||
52 | + stripPrefix: conf.paths.src + '/', | ||
53 | + moduleName: 'angular' | ||
54 | + }, | ||
55 | + | ||
56 | + logLevel: 'WARN', | ||
57 | + | ||
58 | + frameworks: ['jasmine', 'angular-filesort'], | ||
59 | + | ||
60 | + angularFilesort: { | ||
61 | + whitelist: [path.join(conf.paths.src, '/**/!(*.html|*.spec|*.mock).js')] | ||
62 | + }, | ||
63 | + | ||
64 | + browsers : ['PhantomJS'], | ||
65 | + | ||
66 | + plugins : [ | ||
67 | + 'karma-phantomjs-launcher', | ||
68 | + 'karma-angular-filesort', | ||
69 | + 'karma-coverage', | ||
70 | + 'karma-jasmine', | ||
71 | + 'karma-ng-html2js-preprocessor' | ||
72 | + ], | ||
73 | + | ||
74 | + coverageReporter: { | ||
75 | + type : 'html', | ||
76 | + dir : 'coverage/' | ||
77 | + }, | ||
78 | + | ||
79 | + reporters: ['progress'], | ||
80 | + | ||
81 | + proxies: { | ||
82 | + '/assets/': path.join('/base/', conf.paths.src, '/assets/') | ||
83 | + } | ||
84 | + }; | ||
85 | + | ||
86 | + // This is the default preprocessors configuration for a usage with Karma cli | ||
87 | + // The coverage preprocessor is added in gulp/unit-test.js only for single tests | ||
88 | + // It was not possible to do it there because karma doesn't let us now if we are | ||
89 | + // running a single test or not | ||
90 | + configuration.preprocessors = {}; | ||
91 | + pathSrcHtml.forEach(function(path) { | ||
92 | + configuration.preprocessors[path] = ['ng-html2js']; | ||
93 | + }); | ||
94 | + | ||
95 | + // This block is needed to execute Chrome on Travis | ||
96 | + // If you ever plan to use Chrome and Travis, you can keep it | ||
97 | + // If not, you can safely remove it | ||
98 | + // https://github.com/karma-runner/karma/issues/1144#issuecomment-53633076 | ||
99 | + if(configuration.browsers[0] === 'Chrome' && process.env.TRAVIS) { | ||
100 | + configuration.customLaunchers = { | ||
101 | + 'chrome-travis-ci': { | ||
102 | + base: 'Chrome', | ||
103 | + flags: ['--no-sandbox'] | ||
104 | + } | ||
105 | + }; | ||
106 | + configuration.browsers = ['chrome-travis-ci']; | ||
107 | + } | ||
108 | + | ||
109 | + config.set(configuration); | ||
110 | +}; |
1 | +++ a/package.json | ||
@@ -0,0 +1,55 @@ | @@ -0,0 +1,55 @@ | ||
1 | +{ | ||
2 | + "name": "angular", | ||
3 | + "version": "0.0.0", | ||
4 | + "dependencies": {}, | ||
5 | + "scripts": { | ||
6 | + "test": "gulp test" | ||
7 | + }, | ||
8 | + "devDependencies": { | ||
9 | + "estraverse": "~4.1.0", | ||
10 | + "gulp": "~3.9.0", | ||
11 | + "gulp-autoprefixer": "~3.0.2", | ||
12 | + "gulp-angular-templatecache": "~1.8.0", | ||
13 | + "del": "~2.0.2", | ||
14 | + "lodash": "~3.10.1", | ||
15 | + "gulp-minify-css": "~1.2.1", | ||
16 | + "gulp-filter": "~3.0.1", | ||
17 | + "gulp-flatten": "~0.2.0", | ||
18 | + "gulp-eslint": "~1.0.0", | ||
19 | + "eslint-plugin-angular": "~0.12.0", | ||
20 | + "gulp-load-plugins": "~0.10.0", | ||
21 | + "gulp-size": "~2.0.0", | ||
22 | + "gulp-uglify": "~1.4.1", | ||
23 | + "gulp-useref": "~1.3.0", | ||
24 | + "gulp-util": "~3.0.6", | ||
25 | + "gulp-ng-annotate": "~1.1.0", | ||
26 | + "gulp-replace": "~0.5.4", | ||
27 | + "gulp-rename": "~1.2.2", | ||
28 | + "gulp-rev": "~6.0.1", | ||
29 | + "gulp-rev-replace": "~0.4.2", | ||
30 | + "gulp-minify-html": "~1.0.4", | ||
31 | + "gulp-inject": "~3.0.0", | ||
32 | + "gulp-protractor": "~1.0.0", | ||
33 | + "gulp-sourcemaps": "~1.6.0", | ||
34 | + "gulp-sass": "~2.0.4", | ||
35 | + "gulp-angular-filesort": "~1.1.1", | ||
36 | + "main-bower-files": "~2.9.0", | ||
37 | + "wiredep": "~2.2.2", | ||
38 | + "karma": "~0.13.10", | ||
39 | + "karma-jasmine": "~0.3.6", | ||
40 | + "karma-phantomjs-launcher": "~0.2.1", | ||
41 | + "phantomjs": "~1.9.18", | ||
42 | + "karma-angular-filesort": "~1.0.0", | ||
43 | + "karma-coverage": "~0.5.2", | ||
44 | + "karma-ng-html2js-preprocessor": "~0.2.0", | ||
45 | + "browser-sync": "~2.9.11", | ||
46 | + "browser-sync-spa": "~1.0.3", | ||
47 | + "http-proxy-middleware": "~0.9.0", | ||
48 | + "chalk": "~1.1.1", | ||
49 | + "uglify-save-license": "~0.4.1", | ||
50 | + "wrench": "~1.5.8" | ||
51 | + }, | ||
52 | + "engines": { | ||
53 | + "node": ">=0.10.0" | ||
54 | + } | ||
55 | +} |
1 | +++ a/protractor.conf.js | ||
@@ -0,0 +1,27 @@ | @@ -0,0 +1,27 @@ | ||
1 | +'use strict'; | ||
2 | + | ||
3 | +var paths = require('./.yo-rc.json')['generator-gulp-angular'].props.paths; | ||
4 | + | ||
5 | +// An example configuration file. | ||
6 | +exports.config = { | ||
7 | + // The address of a running selenium server. | ||
8 | + //seleniumAddress: 'http://localhost:4444/wd/hub', | ||
9 | + //seleniumServerJar: deprecated, this should be set on node_modules/protractor/config.json | ||
10 | + | ||
11 | + // Capabilities to be passed to the webdriver instance. | ||
12 | + capabilities: { | ||
13 | + 'browserName': 'chrome' | ||
14 | + }, | ||
15 | + | ||
16 | + baseUrl: 'http://localhost:3000', | ||
17 | + | ||
18 | + // Spec patterns are relative to the current working directory when | ||
19 | + // protractor is called. | ||
20 | + specs: [paths.e2e + '/**/*.js'], | ||
21 | + | ||
22 | + // Options to be passed to Jasmine-node. | ||
23 | + jasmineNodeOpts: { | ||
24 | + showColors: true, | ||
25 | + defaultTimeoutInterval: 30000 | ||
26 | + } | ||
27 | +}; |
src/app/components/githubContributor/githubContributor.service.js
0 → 100644
1 | +++ a/src/app/components/githubContributor/githubContributor.service.js | ||
@@ -0,0 +1,37 @@ | @@ -0,0 +1,37 @@ | ||
1 | +(function() { | ||
2 | + 'use strict'; | ||
3 | + | ||
4 | + angular | ||
5 | + .module('angular') | ||
6 | + .factory('githubContributor', githubContributor); | ||
7 | + | ||
8 | + /** @ngInject */ | ||
9 | + function githubContributor($log, $http) { | ||
10 | + var apiHost = 'https://api.github.com/repos/Swiip/generator-gulp-angular'; | ||
11 | + | ||
12 | + var service = { | ||
13 | + apiHost: apiHost, | ||
14 | + getContributors: getContributors | ||
15 | + }; | ||
16 | + | ||
17 | + return service; | ||
18 | + | ||
19 | + function getContributors(limit) { | ||
20 | + if (!limit) { | ||
21 | + limit = 30; | ||
22 | + } | ||
23 | + | ||
24 | + return $http.get(apiHost + '/contributors?per_page=' + limit) | ||
25 | + .then(getContributorsComplete) | ||
26 | + .catch(getContributorsFailed); | ||
27 | + | ||
28 | + function getContributorsComplete(response) { | ||
29 | + return response.data; | ||
30 | + } | ||
31 | + | ||
32 | + function getContributorsFailed(error) { | ||
33 | + $log.error('XHR Failed for getContributors.\n' + angular.toJson(error.data, true)); | ||
34 | + } | ||
35 | + } | ||
36 | + } | ||
37 | +})(); |
src/app/components/githubContributor/githubContributor.service.spec.js
0 → 100644
1 | +++ a/src/app/components/githubContributor/githubContributor.service.spec.js | ||
@@ -0,0 +1,62 @@ | @@ -0,0 +1,62 @@ | ||
1 | +(function() { | ||
2 | + 'use strict'; | ||
3 | + | ||
4 | + describe('service githubContributor', function() { | ||
5 | + var githubContributor; | ||
6 | + var $httpBackend; | ||
7 | + var $log; | ||
8 | + | ||
9 | + beforeEach(module('angular')); | ||
10 | + beforeEach(inject(function(_githubContributor_, _$httpBackend_, _$log_) { | ||
11 | + githubContributor = _githubContributor_; | ||
12 | + $httpBackend = _$httpBackend_; | ||
13 | + $log = _$log_; | ||
14 | + })); | ||
15 | + | ||
16 | + it('should be registered', function() { | ||
17 | + expect(githubContributor).not.toEqual(null); | ||
18 | + }); | ||
19 | + | ||
20 | + describe('apiHost variable', function() { | ||
21 | + it('should exist', function() { | ||
22 | + expect(githubContributor.apiHost).not.toEqual(null); | ||
23 | + }); | ||
24 | + }); | ||
25 | + | ||
26 | + describe('getContributors function', function() { | ||
27 | + it('should exist', function() { | ||
28 | + expect(githubContributor.getContributors).not.toEqual(null); | ||
29 | + }); | ||
30 | + | ||
31 | + it('should return data', function() { | ||
32 | + $httpBackend.when('GET', githubContributor.apiHost + '/contributors?per_page=1').respond(200, [{pprt: 'value'}]); | ||
33 | + var data; | ||
34 | + githubContributor.getContributors(1).then(function(fetchedData) { | ||
35 | + data = fetchedData; | ||
36 | + }); | ||
37 | + $httpBackend.flush(); | ||
38 | + expect(data).toEqual(jasmine.any(Array)); | ||
39 | + expect(data.length === 1).toBeTruthy(); | ||
40 | + expect(data[0]).toEqual(jasmine.any(Object)); | ||
41 | + }); | ||
42 | + | ||
43 | + it('should define a limit per page as default value', function() { | ||
44 | + $httpBackend.when('GET', githubContributor.apiHost + '/contributors?per_page=30').respond(200, new Array(30)); | ||
45 | + var data; | ||
46 | + githubContributor.getContributors().then(function(fetchedData) { | ||
47 | + data = fetchedData; | ||
48 | + }); | ||
49 | + $httpBackend.flush(); | ||
50 | + expect(data).toEqual(jasmine.any(Array)); | ||
51 | + expect(data.length === 30).toBeTruthy(); | ||
52 | + }); | ||
53 | + | ||
54 | + it('should log a error', function() { | ||
55 | + $httpBackend.when('GET', githubContributor.apiHost + '/contributors?per_page=1').respond(500); | ||
56 | + githubContributor.getContributors(1); | ||
57 | + $httpBackend.flush(); | ||
58 | + expect($log.error.logs).toEqual(jasmine.stringMatching('XHR Failed for')); | ||
59 | + }); | ||
60 | + }); | ||
61 | + }); | ||
62 | +})(); |
1 | +++ a/src/app/components/malarkey/malarkey.directive.js | ||
@@ -0,0 +1,75 @@ | @@ -0,0 +1,75 @@ | ||
1 | +(function() { | ||
2 | + 'use strict'; | ||
3 | + | ||
4 | + angular | ||
5 | + .module('angular') | ||
6 | + .directive('acmeMalarkey', acmeMalarkey); | ||
7 | + | ||
8 | + /** @ngInject */ | ||
9 | + function acmeMalarkey(malarkey) { | ||
10 | + var directive = { | ||
11 | + restrict: 'E', | ||
12 | + scope: { | ||
13 | + extraValues: '=' | ||
14 | + }, | ||
15 | + template: ' ', | ||
16 | + link: linkFunc, | ||
17 | + controller: MalarkeyController, | ||
18 | + controllerAs: 'vm' | ||
19 | + }; | ||
20 | + | ||
21 | + return directive; | ||
22 | + | ||
23 | + function linkFunc(scope, el, attr, vm) { | ||
24 | + var watcher; | ||
25 | + var typist = malarkey(el[0], { | ||
26 | + typeSpeed: 40, | ||
27 | + deleteSpeed: 40, | ||
28 | + pauseDelay: 800, | ||
29 | + loop: true, | ||
30 | + postfix: ' ' | ||
31 | + }); | ||
32 | + | ||
33 | + el.addClass('acme-malarkey'); | ||
34 | + | ||
35 | + angular.forEach(scope.extraValues, function(value) { | ||
36 | + typist.type(value).pause().delete(); | ||
37 | + }); | ||
38 | + | ||
39 | + watcher = scope.$watch('vm.contributors', function() { | ||
40 | + angular.forEach(vm.contributors, function(contributor) { | ||
41 | + typist.type(contributor.login).pause().delete(); | ||
42 | + }); | ||
43 | + }); | ||
44 | + | ||
45 | + scope.$on('$destroy', function () { | ||
46 | + watcher(); | ||
47 | + }); | ||
48 | + } | ||
49 | + | ||
50 | + /** @ngInject */ | ||
51 | + function MalarkeyController($log, githubContributor) { | ||
52 | + var vm = this; | ||
53 | + | ||
54 | + vm.contributors = []; | ||
55 | + | ||
56 | + activate(); | ||
57 | + | ||
58 | + function activate() { | ||
59 | + return getContributors().then(function() { | ||
60 | + $log.info('Activated Contributors View'); | ||
61 | + }); | ||
62 | + } | ||
63 | + | ||
64 | + function getContributors() { | ||
65 | + return githubContributor.getContributors(10).then(function(data) { | ||
66 | + vm.contributors = data; | ||
67 | + | ||
68 | + return vm.contributors; | ||
69 | + }); | ||
70 | + } | ||
71 | + } | ||
72 | + | ||
73 | + } | ||
74 | + | ||
75 | +})(); |
1 | +++ a/src/app/components/malarkey/malarkey.directive.spec.js | ||
@@ -0,0 +1,45 @@ | @@ -0,0 +1,45 @@ | ||
1 | +(function() { | ||
2 | + 'use strict'; | ||
3 | + | ||
4 | + /** | ||
5 | + * @todo Complete the test | ||
6 | + * This example is not perfect. | ||
7 | + * The `link` function is not tested. | ||
8 | + * (malarkey usage, addClass, $watch, $destroy) | ||
9 | + */ | ||
10 | + describe('directive malarkey', function() { | ||
11 | + var $log; | ||
12 | + var vm; | ||
13 | + var el; | ||
14 | + | ||
15 | + beforeEach(module('angular')); | ||
16 | + beforeEach(inject(function($compile, $rootScope, githubContributor, $q, _$log_) { | ||
17 | + $log = _$log_; | ||
18 | + | ||
19 | + spyOn(githubContributor, 'getContributors').and.callFake(function() { | ||
20 | + return $q.when([{}, {}, {}, {}, {}, {}]); | ||
21 | + }); | ||
22 | + | ||
23 | + el = angular.element('<acme-malarkey extra-values="[\'Poney\', \'Monkey\']"></acme-malarkey>'); | ||
24 | + | ||
25 | + $compile(el)($rootScope.$new()); | ||
26 | + $rootScope.$digest(); | ||
27 | + vm = el.isolateScope().vm; | ||
28 | + })); | ||
29 | + | ||
30 | + it('should be compiled', function() { | ||
31 | + expect(el.html()).not.toEqual(null); | ||
32 | + }); | ||
33 | + | ||
34 | + it('should have isolate scope object with instanciate members', function() { | ||
35 | + expect(vm).toEqual(jasmine.any(Object)); | ||
36 | + | ||
37 | + expect(vm.contributors).toEqual(jasmine.any(Array)); | ||
38 | + expect(vm.contributors.length).toEqual(6); | ||
39 | + }); | ||
40 | + | ||
41 | + it('should log a info', function() { | ||
42 | + expect($log.info.logs).toEqual(jasmine.stringMatching('Activated Contributors View')); | ||
43 | + }); | ||
44 | + }); | ||
45 | +})(); |
1 | +++ a/src/app/components/malarkey/malarkey.scss | ||
@@ -0,0 +1,25 @@ | @@ -0,0 +1,25 @@ | ||
1 | +.acme-malarkey { | ||
2 | + text-transform: capitalize; | ||
3 | + color: #cb3837; | ||
4 | + | ||
5 | + &:after { | ||
6 | + animation: cursor-blink 0.4s linear infinite; | ||
7 | + content: "|"; | ||
8 | + color: #cb3837; | ||
9 | + } | ||
10 | +} | ||
11 | + | ||
12 | +@keyframes cursor-blink { | ||
13 | + 1% { | ||
14 | + opacity: 0; | ||
15 | + } | ||
16 | + 40% { | ||
17 | + opacity: 0; | ||
18 | + } | ||
19 | + 60% { | ||
20 | + opacity: 1; | ||
21 | + } | ||
22 | + 100% { | ||
23 | + opacity: 1; | ||
24 | + } | ||
25 | +} |
1 | +++ a/src/app/components/navbar/navbar.directive.js | ||
@@ -0,0 +1,32 @@ | @@ -0,0 +1,32 @@ | ||
1 | +(function() { | ||
2 | + 'use strict'; | ||
3 | + | ||
4 | + angular | ||
5 | + .module('angular') | ||
6 | + .directive('acmeNavbar', acmeNavbar); | ||
7 | + | ||
8 | + /** @ngInject */ | ||
9 | + function acmeNavbar() { | ||
10 | + var directive = { | ||
11 | + restrict: 'E', | ||
12 | + templateUrl: 'app/components/navbar/navbar.html', | ||
13 | + scope: { | ||
14 | + creationDate: '=' | ||
15 | + }, | ||
16 | + controller: NavbarController, | ||
17 | + controllerAs: 'vm', | ||
18 | + bindToController: true | ||
19 | + }; | ||
20 | + | ||
21 | + return directive; | ||
22 | + | ||
23 | + /** @ngInject */ | ||
24 | + function NavbarController(moment) { | ||
25 | + var vm = this; | ||
26 | + | ||
27 | + // "vm.creation" is avaible by directive option "bindToController: true" | ||
28 | + vm.relativeDate = moment(vm.creationDate).fromNow(); | ||
29 | + } | ||
30 | + } | ||
31 | + | ||
32 | +})(); |
1 | +++ a/src/app/components/navbar/navbar.directive.spec.js | ||
@@ -0,0 +1,50 @@ | @@ -0,0 +1,50 @@ | ||
1 | +(function() { | ||
2 | + 'use strict'; | ||
3 | + | ||
4 | + /** | ||
5 | + * @todo Complete the test | ||
6 | + * This example is not perfect. | ||
7 | + * Test should check if MomentJS have been called | ||
8 | + */ | ||
9 | + describe('directive navbar', function() { | ||
10 | + // var $window; | ||
11 | + var vm; | ||
12 | + var el; | ||
13 | + var timeInMs; | ||
14 | + | ||
15 | + beforeEach(module('angular')); | ||
16 | + beforeEach(inject(function($compile, $rootScope) { | ||
17 | + // spyOn(_$window_, 'moment').and.callThrough(); | ||
18 | + // $window = _$window_; | ||
19 | + | ||
20 | + timeInMs = new Date(); | ||
21 | + timeInMs = timeInMs.setHours(timeInMs.getHours() - 24); | ||
22 | + | ||
23 | + el = angular.element('<acme-navbar creation-date="' + timeInMs + '"></acme-navbar>'); | ||
24 | + | ||
25 | + $compile(el)($rootScope.$new()); | ||
26 | + $rootScope.$digest(); | ||
27 | + vm = el.isolateScope().vm; | ||
28 | + // ctrl = el.controller('acmeNavbar'); | ||
29 | + })); | ||
30 | + | ||
31 | + it('should be compiled', function() { | ||
32 | + expect(el.html()).not.toEqual(null); | ||
33 | + }); | ||
34 | + | ||
35 | + it('should have isolate scope object with instanciate members', function() { | ||
36 | + expect(vm).toEqual(jasmine.any(Object)); | ||
37 | + | ||
38 | + expect(vm.creationDate).toEqual(jasmine.any(Number)); | ||
39 | + expect(vm.creationDate).toEqual(timeInMs); | ||
40 | + | ||
41 | + expect(vm.relativeDate).toEqual(jasmine.any(String)); | ||
42 | + expect(vm.relativeDate).toEqual('a day ago'); | ||
43 | + }); | ||
44 | + | ||
45 | + // it('should call Moment', function() { | ||
46 | + // console.log($window.moment) | ||
47 | + // expect($window.moment).toHaveBeenCalled(); | ||
48 | + // }); | ||
49 | + }); | ||
50 | +})(); |
1 | +++ a/src/app/components/navbar/navbar.html | ||
@@ -0,0 +1,21 @@ | @@ -0,0 +1,21 @@ | ||
1 | +<nav class="navbar navbar-static-top navbar-inverse"> | ||
2 | + <div class="container-fluid"> | ||
3 | + <div class="navbar-header"> | ||
4 | + <a class="navbar-brand" href="https://github.com/Swiip/generator-gulp-angular"> | ||
5 | + <span class="glyphicon glyphicon-home"></span> Gulp Angular | ||
6 | + </a> | ||
7 | + </div> | ||
8 | + | ||
9 | + <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-6"> | ||
10 | + <ul class="nav navbar-nav"> | ||
11 | + <li class="active"><a ng-href="#">Home</a></li> | ||
12 | + <li><a ng-href="#">About</a></li> | ||
13 | + <li><a ng-href="#">Contact</a></li> | ||
14 | + </ul> | ||
15 | + | ||
16 | + <ul class="nav navbar-nav navbar-right acme-navbar-text"> | ||
17 | + <li>Application was created {{ vm.relativeDate }}.</li> | ||
18 | + </ul> | ||
19 | + </div> | ||
20 | + </div> | ||
21 | +</nav> |
1 | +++ a/src/app/components/webDevTec/webDevTec.service.js | ||
@@ -0,0 +1,74 @@ | @@ -0,0 +1,74 @@ | ||
1 | +(function() { | ||
2 | + 'use strict'; | ||
3 | + | ||
4 | + angular | ||
5 | + .module('angular') | ||
6 | + .service('webDevTec', webDevTec); | ||
7 | + | ||
8 | + /** @ngInject */ | ||
9 | + function webDevTec() { | ||
10 | + var data = [ | ||
11 | + { | ||
12 | + 'title': 'AngularJS', | ||
13 | + 'url': 'https://angularjs.org/', | ||
14 | + 'description': 'HTML enhanced for web apps!', | ||
15 | + 'logo': 'angular.png' | ||
16 | + }, | ||
17 | + { | ||
18 | + 'title': 'BrowserSync', | ||
19 | + 'url': 'http://browsersync.io/', | ||
20 | + 'description': 'Time-saving synchronised browser testing.', | ||
21 | + 'logo': 'browsersync.png' | ||
22 | + }, | ||
23 | + { | ||
24 | + 'title': 'GulpJS', | ||
25 | + 'url': 'http://gulpjs.com/', | ||
26 | + 'description': 'The streaming build system.', | ||
27 | + 'logo': 'gulp.png' | ||
28 | + }, | ||
29 | + { | ||
30 | + 'title': 'Jasmine', | ||
31 | + 'url': 'http://jasmine.github.io/', | ||
32 | + 'description': 'Behavior-Driven JavaScript.', | ||
33 | + 'logo': 'jasmine.png' | ||
34 | + }, | ||
35 | + { | ||
36 | + 'title': 'Karma', | ||
37 | + 'url': 'http://karma-runner.github.io/', | ||
38 | + 'description': 'Spectacular Test Runner for JavaScript.', | ||
39 | + 'logo': 'karma.png' | ||
40 | + }, | ||
41 | + { | ||
42 | + 'title': 'Protractor', | ||
43 | + 'url': 'https://github.com/angular/protractor', | ||
44 | + 'description': 'End to end test framework for AngularJS applications built on top of WebDriverJS.', | ||
45 | + 'logo': 'protractor.png' | ||
46 | + }, | ||
47 | + { | ||
48 | + 'title': 'Bootstrap', | ||
49 | + 'url': 'http://getbootstrap.com/', | ||
50 | + 'description': 'Bootstrap is the most popular HTML, CSS, and JS framework for developing responsive, mobile first projects on the web.', | ||
51 | + 'logo': 'bootstrap.png' | ||
52 | + }, | ||
53 | + { | ||
54 | + 'title': 'Angular UI Bootstrap', | ||
55 | + 'url': 'http://angular-ui.github.io/bootstrap/', | ||
56 | + 'description': 'Bootstrap components written in pure AngularJS by the AngularUI Team.', | ||
57 | + 'logo': 'ui-bootstrap.png' | ||
58 | + }, | ||
59 | + { | ||
60 | + 'title': 'Sass (Node)', | ||
61 | + 'url': 'https://github.com/sass/node-sass', | ||
62 | + 'description': 'Node.js binding to libsass, the C version of the popular stylesheet preprocessor, Sass.', | ||
63 | + 'logo': 'node-sass.png' | ||
64 | + } | ||
65 | + ]; | ||
66 | + | ||
67 | + this.getTec = getTec; | ||
68 | + | ||
69 | + function getTec() { | ||
70 | + return data; | ||
71 | + } | ||
72 | + } | ||
73 | + | ||
74 | +})(); |
1 | +++ a/src/app/components/webDevTec/webDevTec.service.spec.js | ||
@@ -0,0 +1,29 @@ | @@ -0,0 +1,29 @@ | ||
1 | +(function() { | ||
2 | + 'use strict'; | ||
3 | + | ||
4 | + describe('service webDevTec', function() { | ||
5 | + var webDevTec; | ||
6 | + | ||
7 | + beforeEach(module('angular')); | ||
8 | + beforeEach(inject(function(_webDevTec_) { | ||
9 | + webDevTec = _webDevTec_; | ||
10 | + })); | ||
11 | + | ||
12 | + it('should be registered', function() { | ||
13 | + expect(webDevTec).not.toEqual(null); | ||
14 | + }); | ||
15 | + | ||
16 | + describe('getTec function', function() { | ||
17 | + it('should exist', function() { | ||
18 | + expect(webDevTec.getTec).not.toEqual(null); | ||
19 | + }); | ||
20 | + | ||
21 | + it('should return array of object', function() { | ||
22 | + var data = webDevTec.getTec(); | ||
23 | + expect(data).toEqual(jasmine.any(Array)); | ||
24 | + expect(data[0]).toEqual(jasmine.any(Object)); | ||
25 | + expect(data.length > 5).toBeTruthy(); | ||
26 | + }); | ||
27 | + }); | ||
28 | + }); | ||
29 | +})(); |
1 | +++ a/src/app/index.config.js | ||
@@ -0,0 +1,21 @@ | @@ -0,0 +1,21 @@ | ||
1 | +(function() { | ||
2 | + 'use strict'; | ||
3 | + | ||
4 | + angular | ||
5 | + .module('angular') | ||
6 | + .config(config); | ||
7 | + | ||
8 | + /** @ngInject */ | ||
9 | + function config($logProvider, toastrConfig) { | ||
10 | + // Enable log | ||
11 | + $logProvider.debugEnabled(true); | ||
12 | + | ||
13 | + // Set options third-party lib | ||
14 | + toastrConfig.allowHtml = true; | ||
15 | + toastrConfig.timeOut = 3000; | ||
16 | + toastrConfig.positionClass = 'toast-top-right'; | ||
17 | + toastrConfig.preventDuplicates = true; | ||
18 | + toastrConfig.progressBar = true; | ||
19 | + } | ||
20 | + | ||
21 | +})(); |
1 | +++ a/src/app/index.route.js | ||
@@ -0,0 +1,20 @@ | @@ -0,0 +1,20 @@ | ||
1 | +(function() { | ||
2 | + 'use strict'; | ||
3 | + | ||
4 | + angular | ||
5 | + .module('angular') | ||
6 | + .config(routeConfig); | ||
7 | + | ||
8 | + function routeConfig($routeProvider) { | ||
9 | + $routeProvider | ||
10 | + .when('/', { | ||
11 | + templateUrl: 'app/main/main.html', | ||
12 | + controller: 'MainController', | ||
13 | + controllerAs: 'main' | ||
14 | + }) | ||
15 | + .otherwise({ | ||
16 | + redirectTo: '/' | ||
17 | + }); | ||
18 | + } | ||
19 | + | ||
20 | +})(); |
1 | +++ a/src/app/index.scss | ||
@@ -0,0 +1,35 @@ | @@ -0,0 +1,35 @@ | ||
1 | +/** | ||
2 | + * If you want to override some bootstrap variables, you have to change values here. | ||
3 | + * The list of variables are listed here bower_components/bootstrap-sass/assets/stylesheets/bootstrap/_variables.scss | ||
4 | + */ | ||
5 | +$navbar-inverse-link-color: #5AADBB; | ||
6 | +$icon-font-path: "../../bower_components/bootstrap-sass/assets/fonts/bootstrap/"; | ||
7 | + | ||
8 | +/** | ||
9 | + * Do not remove the comments below. It's the markers used by wiredep to inject | ||
10 | + * sass dependencies when defined in the bower.json of your dependencies | ||
11 | + */ | ||
12 | +// bower:scss | ||
13 | +// endbower | ||
14 | + | ||
15 | +.browsehappy { | ||
16 | + margin: 0.2em 0; | ||
17 | + background: #ccc; | ||
18 | + color: #000; | ||
19 | + padding: 0.2em 0; | ||
20 | +} | ||
21 | + | ||
22 | +.thumbnail { | ||
23 | + height: 200px; | ||
24 | + | ||
25 | + img.pull-right { | ||
26 | + width: 50px; | ||
27 | + } | ||
28 | +} | ||
29 | + | ||
30 | +/** | ||
31 | + * Do not remove the comments below. It's the markers used by gulp-inject to inject | ||
32 | + * all your sass files automatically | ||
33 | + */ | ||
34 | +// injector | ||
35 | +// endinjector |
1 | +++ a/src/app/main/main.controller.js | ||
@@ -0,0 +1,39 @@ | @@ -0,0 +1,39 @@ | ||
1 | +(function() { | ||
2 | + 'use strict'; | ||
3 | + | ||
4 | + angular | ||
5 | + .module('angular') | ||
6 | + .controller('MainController', MainController); | ||
7 | + | ||
8 | + /** @ngInject */ | ||
9 | + function MainController($timeout, webDevTec, toastr) { | ||
10 | + var vm = this; | ||
11 | + | ||
12 | + vm.awesomeThings = []; | ||
13 | + vm.classAnimation = ''; | ||
14 | + vm.creationDate = 1452020281605; | ||
15 | + vm.showToastr = showToastr; | ||
16 | + | ||
17 | + activate(); | ||
18 | + | ||
19 | + function activate() { | ||
20 | + getWebDevTec(); | ||
21 | + $timeout(function() { | ||
22 | + vm.classAnimation = 'rubberBand'; | ||
23 | + }, 4000); | ||
24 | + } | ||
25 | + | ||
26 | + function showToastr() { | ||
27 | + toastr.info('Fork <a href="https://github.com/Swiip/generator-gulp-angular" target="_blank"><b>generator-gulp-angular</b></a>'); | ||
28 | + vm.classAnimation = ''; | ||
29 | + } | ||
30 | + | ||
31 | + function getWebDevTec() { | ||
32 | + vm.awesomeThings = webDevTec.getTec(); | ||
33 | + | ||
34 | + angular.forEach(vm.awesomeThings, function(awesomeThing) { | ||
35 | + awesomeThing.rank = Math.random(); | ||
36 | + }); | ||
37 | + } | ||
38 | + } | ||
39 | +})(); |
1 | +++ a/src/app/main/main.controller.spec.js | ||
@@ -0,0 +1,39 @@ | @@ -0,0 +1,39 @@ | ||
1 | +(function() { | ||
2 | + 'use strict'; | ||
3 | + | ||
4 | + describe('controllers', function(){ | ||
5 | + var vm; | ||
6 | + var $timeout; | ||
7 | + var toastr; | ||
8 | + | ||
9 | + beforeEach(module('angular')); | ||
10 | + beforeEach(inject(function(_$controller_, _$timeout_, _webDevTec_, _toastr_) { | ||
11 | + spyOn(_webDevTec_, 'getTec').and.returnValue([{}, {}, {}, {}, {}]); | ||
12 | + spyOn(_toastr_, 'info').and.callThrough(); | ||
13 | + | ||
14 | + vm = _$controller_('MainController'); | ||
15 | + $timeout = _$timeout_; | ||
16 | + toastr = _toastr_; | ||
17 | + })); | ||
18 | + | ||
19 | + it('should have a timestamp creation date', function() { | ||
20 | + expect(vm.creationDate).toEqual(jasmine.any(Number)); | ||
21 | + }); | ||
22 | + | ||
23 | + it('should define animate class after delaying timeout ', function() { | ||
24 | + $timeout.flush(); | ||
25 | + expect(vm.classAnimation).toEqual('rubberBand'); | ||
26 | + }); | ||
27 | + | ||
28 | + it('should show a Toastr info and stop animation when invoke showToastr()', function() { | ||
29 | + vm.showToastr(); | ||
30 | + expect(toastr.info).toHaveBeenCalled(); | ||
31 | + expect(vm.classAnimation).toEqual(''); | ||
32 | + }); | ||
33 | + | ||
34 | + it('should define more than 5 awesome things', function() { | ||
35 | + expect(angular.isArray(vm.awesomeThings)).toBeTruthy(); | ||
36 | + expect(vm.awesomeThings.length === 5).toBeTruthy(); | ||
37 | + }); | ||
38 | + }); | ||
39 | +})(); |
1 | +++ a/src/app/main/main.html | ||
@@ -0,0 +1,34 @@ | @@ -0,0 +1,34 @@ | ||
1 | +<div class="container"> | ||
2 | + | ||
3 | + <div> | ||
4 | + <acme-navbar creation-date="main.creationDate"></acme-navbar> | ||
5 | + </div> | ||
6 | + | ||
7 | + <div class="jumbotron text-center"> | ||
8 | + <h1>'Allo, 'Allo!</h1> | ||
9 | + <p class="lead"> | ||
10 | + <img src="assets/images/yeoman.png" alt="I'm Yeoman"><br> | ||
11 | + Always a pleasure scaffolding your apps. | ||
12 | + </p> | ||
13 | + <p class="animated infinite" ng-class="main.classAnimation"> | ||
14 | + <button type="button" class="btn btn-lg btn-success" ng-click="main.showToastr()">Splendid Toastr</button> | ||
15 | + </p> | ||
16 | + <p> | ||
17 | + With ♥ thanks to the contributions of<acme-malarkey extra-values="['Yeoman', 'Gulp', 'Angular']"></acme-malarkey> | ||
18 | + </p> | ||
19 | + </div> | ||
20 | + | ||
21 | + <div class="row"> | ||
22 | + <div class="col-sm-6 col-md-4" ng-repeat="awesomeThing in main.awesomeThings | orderBy:'rank'"> | ||
23 | + <div class="thumbnail"> | ||
24 | + <img class="pull-right" ng-src="assets/images/{{ awesomeThing.logo }}" alt="{{ awesomeThing.title }}"> | ||
25 | + <div class="caption"> | ||
26 | + <h3>{{ awesomeThing.title }}</h3> | ||
27 | + <p>{{ awesomeThing.description }}</p> | ||
28 | + <p><a ng-href="{{awesomeThing.url}}">{{ awesomeThing.url }}</a></p> | ||
29 | + </div> | ||
30 | + </div> | ||
31 | + </div> | ||
32 | + </div> | ||
33 | + | ||
34 | +</div> |
13.2 KB
12.6 KB
11.3 KB
10.4 KB
15.5 KB
9.89 KB
4.85 KB
9.95 KB
13.2 KB
13.2 KB
No preview for this file type
1 | +++ a/src/index.html | ||
@@ -0,0 +1,46 @@ | @@ -0,0 +1,46 @@ | ||
1 | +<!doctype html> | ||
2 | +<html ng-app="angular"> | ||
3 | + <head> | ||
4 | + <meta charset="utf-8"> | ||
5 | + <title>angular</title> | ||
6 | + <meta name="description" content=""> | ||
7 | + <meta name="viewport" content="width=device-width"> | ||
8 | + <!-- Place favicon.ico and apple-touch-icon.png in the root directory --> | ||
9 | + | ||
10 | + <!-- build:css({.tmp/serve,src}) styles/vendor.css --> | ||
11 | + <!-- bower:css --> | ||
12 | + <!-- run `gulp inject` to automatically populate bower styles dependencies --> | ||
13 | + <!-- endbower --> | ||
14 | + <!-- endbuild --> | ||
15 | + | ||
16 | + <!-- build:css({.tmp/serve,src}) styles/app.css --> | ||
17 | + <!-- inject:css --> | ||
18 | + <!-- css files will be automatically insert here --> | ||
19 | + <!-- endinject --> | ||
20 | + <!-- endbuild --> | ||
21 | + </head> | ||
22 | + <body> | ||
23 | + <!--[if lt IE 10]> | ||
24 | + <p class="browsehappy">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p> | ||
25 | + <![endif]--> | ||
26 | + | ||
27 | + <div ng-view></div> | ||
28 | + | ||
29 | + <!-- build:js(src) scripts/vendor.js --> | ||
30 | + <!-- bower:js --> | ||
31 | + <!-- run `gulp inject` to automatically populate bower script dependencies --> | ||
32 | + <!-- endbower --> | ||
33 | + <!-- endbuild --> | ||
34 | + | ||
35 | + <!-- build:js({.tmp/serve,.tmp/partials,src}) scripts/app.js --> | ||
36 | + <!-- inject:js --> | ||
37 | + <!-- js files will be automatically insert here --> | ||
38 | + <!-- endinject --> | ||
39 | + | ||
40 | + <!-- inject:partials --> | ||
41 | + <!-- angular templates will be automatically converted in js and inserted here --> | ||
42 | + <!-- endinject --> | ||
43 | + <!-- endbuild --> | ||
44 | + | ||
45 | + </body> | ||
46 | +</html> |