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 @@ |
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 @@ |
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 | 79 | \ No newline at end of file | ... | ... |
1 | +++ a/bower.json | |
... | ... | @@ -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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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> | ... | ... |