├── .bowerrc
├── .editorconfig
├── .gitattributes
├── .gitignore
├── .jshintrc
├── .yo-rc.json
├── Gruntfile.js
├── README.md
├── app
├── .buildignore
├── .htaccess
├── 404.html
├── favicon.ico
├── images
│ └── yeoman.png
├── index.html
├── robots.txt
├── scripts
│ ├── app.js
│ ├── controllers
│ │ ├── cart.js
│ │ ├── category.js
│ │ ├── checkout.js
│ │ ├── complete.js
│ │ ├── main.js
│ │ ├── payment.js
│ │ ├── product.js
│ │ └── store.js
│ ├── services
│ │ └── moltin.js
│ └── vendor
│ │ └── moltin.min.js
├── styles
│ ├── main.scss
│ └── storefront.scss
└── views
│ ├── cart.html
│ ├── category.html
│ ├── checkout.html
│ ├── complete.html
│ ├── main.html
│ ├── payment.html
│ ├── product.html
│ └── store.html
├── bower.json
├── package.json
└── test
├── .jshintrc
└── spec
└── controllers
├── cart.js
├── category.js
├── checkout.js
├── complete.js
├── main.js
├── payment.js
├── product.js
└── store.js
/.bowerrc:
--------------------------------------------------------------------------------
1 | {
2 | "directory": "bower_components"
3 | }
4 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig helps developers define and maintain consistent
2 | # coding styles between different editors and IDEs
3 | # editorconfig.org
4 |
5 | root = true
6 |
7 |
8 | [*]
9 |
10 | # Change these settings to your own preference
11 | indent_style = space
12 | indent_size = 2
13 |
14 | # We recommend you to keep these unchanged
15 | end_of_line = lf
16 | charset = utf-8
17 | trim_trailing_whitespace = true
18 | insert_final_newline = true
19 |
20 | [*.md]
21 | trim_trailing_whitespace = false
22 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | dist
3 | .tmp
4 | .sass-cache
5 | bower_components
6 |
--------------------------------------------------------------------------------
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "node": true,
3 | "browser": true,
4 | "esnext": true,
5 | "bitwise": true,
6 | "camelcase": true,
7 | "curly": true,
8 | "eqeqeq": true,
9 | "immed": true,
10 | "indent": 2,
11 | "latedef": true,
12 | "newcap": true,
13 | "noarg": true,
14 | "quotmark": "single",
15 | "undef": true,
16 | "unused": true,
17 | "strict": true,
18 | "trailing": true,
19 | "smarttabs": true,
20 | "globals": {
21 | "angular": false
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/.yo-rc.json:
--------------------------------------------------------------------------------
1 | {}
2 |
--------------------------------------------------------------------------------
/Gruntfile.js:
--------------------------------------------------------------------------------
1 | // Generated on 2015-03-10 using generator-angular 0.11.1
2 | 'use strict';
3 |
4 | // # Globbing
5 | // for performance reasons we're only matching one level down:
6 | // 'test/spec/{,*/}*.js'
7 | // use this if you want to recursively match all subfolders:
8 | // 'test/spec/**/*.js'
9 |
10 | module.exports = function (grunt) {
11 |
12 | // Load grunt tasks automatically
13 | require('load-grunt-tasks')(grunt);
14 |
15 | // Time how long tasks take. Can help when optimizing build times
16 | require('time-grunt')(grunt);
17 |
18 | // Configurable paths for the application
19 | var appConfig = {
20 | app: require('./bower.json').appPath || 'app',
21 | dist: 'dist'
22 | };
23 |
24 | // Define the configuration for all the tasks
25 | grunt.initConfig({
26 |
27 | // Project settings
28 | yeoman: appConfig,
29 |
30 | // Watches files for changes and runs tasks based on the changed files
31 | watch: {
32 | bower: {
33 | files: ['bower.json'],
34 | tasks: ['wiredep']
35 | },
36 | js: {
37 | files: ['<%= yeoman.app %>/scripts/{,*/}*.js'],
38 | tasks: ['newer:jshint:all'],
39 | options: {
40 | livereload: '<%= connect.options.livereload %>'
41 | }
42 | },
43 | jsTest: {
44 | files: ['test/spec/{,*/}*.js'],
45 | tasks: ['newer:jshint:test', 'karma']
46 | },
47 | compass: {
48 | files: ['<%= yeoman.app %>/styles/{,*/}*.{scss,sass}'],
49 | tasks: ['compass:server', 'autoprefixer']
50 | },
51 | gruntfile: {
52 | files: ['Gruntfile.js']
53 | },
54 | livereload: {
55 | options: {
56 | livereload: '<%= connect.options.livereload %>'
57 | },
58 | files: [
59 | '<%= yeoman.app %>/{,*/}*.html',
60 | '.tmp/styles/{,*/}*.css',
61 | '<%= yeoman.app %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}'
62 | ]
63 | }
64 | },
65 |
66 | // The actual grunt server settings
67 | connect: {
68 | options: {
69 | port: 9000,
70 | // Change this to '0.0.0.0' to access the server from outside.
71 | hostname: 'localhost',
72 | livereload: 35729
73 | },
74 | livereload: {
75 | options: {
76 | open: true,
77 | middleware: function (connect) {
78 | return [
79 | connect.static('.tmp'),
80 | connect().use(
81 | '/bower_components',
82 | connect.static('./bower_components')
83 | ),
84 | connect().use(
85 | '/app/styles',
86 | connect.static('./app/styles')
87 | ),
88 | connect.static(appConfig.app)
89 | ];
90 | }
91 | }
92 | },
93 | test: {
94 | options: {
95 | port: 9001,
96 | middleware: function (connect) {
97 | return [
98 | connect.static('.tmp'),
99 | connect.static('test'),
100 | connect().use(
101 | '/bower_components',
102 | connect.static('./bower_components')
103 | ),
104 | connect.static(appConfig.app)
105 | ];
106 | }
107 | }
108 | },
109 | dist: {
110 | options: {
111 | open: true,
112 | base: '<%= yeoman.dist %>'
113 | }
114 | }
115 | },
116 |
117 | // Make sure code styles are up to par and there are no obvious mistakes
118 | jshint: {
119 | options: {
120 | jshintrc: '.jshintrc',
121 | reporter: require('jshint-stylish')
122 | },
123 | all: {
124 | src: [
125 | 'Gruntfile.js',
126 | '<%= yeoman.app %>/scripts/{,*/}*.js'
127 | ]
128 | },
129 | test: {
130 | options: {
131 | jshintrc: 'test/.jshintrc'
132 | },
133 | src: ['test/spec/{,*/}*.js']
134 | }
135 | },
136 |
137 | // Empties folders to start fresh
138 | clean: {
139 | dist: {
140 | files: [{
141 | dot: true,
142 | src: [
143 | '.tmp',
144 | '<%= yeoman.dist %>/{,*/}*',
145 | '!<%= yeoman.dist %>/.git{,*/}*'
146 | ]
147 | }]
148 | },
149 | server: '.tmp'
150 | },
151 |
152 | // Add vendor prefixed styles
153 | autoprefixer: {
154 | options: {
155 | browsers: ['last 1 version']
156 | },
157 | server: {
158 | options: {
159 | map: true,
160 | },
161 | files: [{
162 | expand: true,
163 | cwd: '.tmp/styles/',
164 | src: '{,*/}*.css',
165 | dest: '.tmp/styles/'
166 | }]
167 | },
168 | dist: {
169 | files: [{
170 | expand: true,
171 | cwd: '.tmp/styles/',
172 | src: '{,*/}*.css',
173 | dest: '.tmp/styles/'
174 | }]
175 | }
176 | },
177 |
178 | // Automatically inject Bower components into the app
179 | wiredep: {
180 | app: {
181 | src: ['<%= yeoman.app %>/index.html'],
182 | ignorePath: /\.\.\//
183 | },
184 | test: {
185 | devDependencies: true,
186 | src: '<%= karma.unit.configFile %>',
187 | ignorePath: /\.\.\//,
188 | fileTypes:{
189 | js: {
190 | block: /(([\s\t]*)\/{2}\s*?bower:\s*?(\S*))(\n|\r|.)*?(\/{2}\s*endbower)/gi,
191 | detect: {
192 | js: /'(.*\.js)'/gi
193 | },
194 | replace: {
195 | js: '\'{{filePath}}\','
196 | }
197 | }
198 | }
199 | },
200 | sass: {
201 | src: ['<%= yeoman.app %>/styles/{,*/}*.{scss,sass}'],
202 | ignorePath: /(\.\.\/){1,2}bower_components\//
203 | }
204 | },
205 |
206 | // Compiles Sass to CSS and generates necessary files if requested
207 | compass: {
208 | options: {
209 | sassDir: '<%= yeoman.app %>/styles',
210 | cssDir: '.tmp/styles',
211 | generatedImagesDir: '.tmp/images/generated',
212 | imagesDir: '<%= yeoman.app %>/images',
213 | javascriptsDir: '<%= yeoman.app %>/scripts',
214 | fontsDir: '<%= yeoman.app %>/styles/fonts',
215 | importPath: './bower_components',
216 | httpImagesPath: '/images',
217 | httpGeneratedImagesPath: '/images/generated',
218 | httpFontsPath: '/styles/fonts',
219 | relativeAssets: false,
220 | assetCacheBuster: false,
221 | raw: 'Sass::Script::Number.precision = 10\n'
222 | },
223 | dist: {
224 | options: {
225 | generatedImagesDir: '<%= yeoman.dist %>/images/generated'
226 | }
227 | },
228 | server: {
229 | options: {
230 | sourcemap: true
231 | }
232 | }
233 | },
234 |
235 | // Renames files for browser caching purposes
236 | filerev: {
237 | dist: {
238 | src: [
239 | '<%= yeoman.dist %>/scripts/{,*/}*.js',
240 | '<%= yeoman.dist %>/styles/{,*/}*.css',
241 | '<%= yeoman.dist %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}',
242 | '<%= yeoman.dist %>/styles/fonts/*'
243 | ]
244 | }
245 | },
246 |
247 | // Reads HTML for usemin blocks to enable smart builds that automatically
248 | // concat, minify and revision files. Creates configurations in memory so
249 | // additional tasks can operate on them
250 | useminPrepare: {
251 | html: '<%= yeoman.app %>/index.html',
252 | options: {
253 | dest: '<%= yeoman.dist %>',
254 | flow: {
255 | html: {
256 | steps: {
257 | js: ['concat', 'uglifyjs'],
258 | css: ['cssmin']
259 | },
260 | post: {}
261 | }
262 | }
263 | }
264 | },
265 |
266 | // Performs rewrites based on filerev and the useminPrepare configuration
267 | usemin: {
268 | html: ['<%= yeoman.dist %>/{,*/}*.html'],
269 | css: ['<%= yeoman.dist %>/styles/{,*/}*.css'],
270 | options: {
271 | assetsDirs: [
272 | '<%= yeoman.dist %>',
273 | '<%= yeoman.dist %>/images',
274 | '<%= yeoman.dist %>/styles'
275 | ]
276 | }
277 | },
278 |
279 | // The following *-min tasks will produce minified files in the dist folder
280 | // By default, your `index.html`'s will take care of
281 | // minification. These next options are pre-configured if you do not wish
282 | // to use the Usemin blocks.
283 | // cssmin: {
284 | // dist: {
285 | // files: {
286 | // '<%= yeoman.dist %>/styles/main.css': [
287 | // '.tmp/styles/{,*/}*.css'
288 | // ]
289 | // }
290 | // }
291 | // },
292 | // uglify: {
293 | // dist: {
294 | // files: {
295 | // '<%= yeoman.dist %>/scripts/scripts.js': [
296 | // '<%= yeoman.dist %>/scripts/scripts.js'
297 | // ]
298 | // }
299 | // }
300 | // },
301 | // concat: {
302 | // dist: {}
303 | // },
304 |
305 | imagemin: {
306 | dist: {
307 | files: [{
308 | expand: true,
309 | cwd: '<%= yeoman.app %>/images',
310 | src: '{,*/}*.{png,jpg,jpeg,gif}',
311 | dest: '<%= yeoman.dist %>/images'
312 | }]
313 | }
314 | },
315 |
316 | svgmin: {
317 | dist: {
318 | files: [{
319 | expand: true,
320 | cwd: '<%= yeoman.app %>/images',
321 | src: '{,*/}*.svg',
322 | dest: '<%= yeoman.dist %>/images'
323 | }]
324 | }
325 | },
326 |
327 | htmlmin: {
328 | dist: {
329 | options: {
330 | collapseWhitespace: true,
331 | conservativeCollapse: true,
332 | collapseBooleanAttributes: true,
333 | removeCommentsFromCDATA: true,
334 | removeOptionalTags: true
335 | },
336 | files: [{
337 | expand: true,
338 | cwd: '<%= yeoman.dist %>',
339 | src: ['*.html', 'views/{,*/}*.html'],
340 | dest: '<%= yeoman.dist %>'
341 | }]
342 | }
343 | },
344 |
345 | // ng-annotate tries to make the code safe for minification automatically
346 | // by using the Angular long form for dependency injection.
347 | ngAnnotate: {
348 | dist: {
349 | files: [{
350 | expand: true,
351 | cwd: '.tmp/concat/scripts',
352 | src: '*.js',
353 | dest: '.tmp/concat/scripts'
354 | }]
355 | }
356 | },
357 |
358 | // Replace Google CDN references
359 | cdnify: {
360 | dist: {
361 | html: ['<%= yeoman.dist %>/*.html']
362 | }
363 | },
364 |
365 | // Copies remaining files to places other tasks can use
366 | copy: {
367 | dist: {
368 | files: [{
369 | expand: true,
370 | dot: true,
371 | cwd: '<%= yeoman.app %>',
372 | dest: '<%= yeoman.dist %>',
373 | src: [
374 | '*.{ico,png,txt}',
375 | '.htaccess',
376 | '*.html',
377 | 'views/{,*/}*.html',
378 | 'images/{,*/}*.{webp}',
379 | 'styles/fonts/{,*/}*.*'
380 | ]
381 | }, {
382 | expand: true,
383 | cwd: '.tmp/images',
384 | dest: '<%= yeoman.dist %>/images',
385 | src: ['generated/*']
386 | }, {
387 | expand: true,
388 | cwd: '.',
389 | src: 'bower_components/bootstrap-sass-official/assets/fonts/bootstrap/*',
390 | dest: '<%= yeoman.dist %>'
391 | }]
392 | },
393 | styles: {
394 | expand: true,
395 | cwd: '<%= yeoman.app %>/styles',
396 | dest: '.tmp/styles/',
397 | src: '{,*/}*.css'
398 | }
399 | },
400 |
401 | // Run some tasks in parallel to speed up the build process
402 | concurrent: {
403 | server: [
404 | 'compass:server'
405 | ],
406 | test: [
407 | 'compass'
408 | ],
409 | dist: [
410 | 'compass:dist',
411 | 'imagemin',
412 | 'svgmin'
413 | ]
414 | },
415 |
416 | // Test settings
417 | karma: {
418 | unit: {
419 | configFile: 'test/karma.conf.js',
420 | singleRun: true
421 | }
422 | }
423 | });
424 |
425 |
426 | grunt.registerTask('serve', 'Compile then start a connect web server', function (target) {
427 | if (target === 'dist') {
428 | return grunt.task.run(['build', 'connect:dist:keepalive']);
429 | }
430 |
431 | grunt.task.run([
432 | 'clean:server',
433 | 'wiredep',
434 | 'concurrent:server',
435 | 'autoprefixer:server',
436 | 'connect:livereload',
437 | 'watch'
438 | ]);
439 | });
440 |
441 | grunt.registerTask('server', 'DEPRECATED TASK. Use the "serve" task instead', function (target) {
442 | grunt.log.warn('The `server` task has been deprecated. Use `grunt serve` to start a server.');
443 | grunt.task.run(['serve:' + target]);
444 | });
445 |
446 | grunt.registerTask('test', [
447 | 'clean:server',
448 | 'wiredep',
449 | 'concurrent:test',
450 | 'autoprefixer',
451 | 'connect:test',
452 | 'karma'
453 | ]);
454 |
455 | grunt.registerTask('build', [
456 | 'clean:dist',
457 | 'wiredep',
458 | 'useminPrepare',
459 | 'concurrent:dist',
460 | 'autoprefixer',
461 | 'concat',
462 | 'ngAnnotate',
463 | 'copy:dist',
464 | 'cdnify',
465 | 'cssmin',
466 | 'uglify',
467 | 'filerev',
468 | 'usemin',
469 | 'htmlmin'
470 | ]);
471 |
472 | grunt.registerTask('default', [
473 | 'newer:jshint',
474 | 'test',
475 | 'build'
476 | ]);
477 | };
478 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # storefront
2 |
3 | This project is generated with [yo angular generator](https://github.com/yeoman/generator-angular)
4 | version 0.11.1.
5 |
6 | ## Build & development
7 |
8 | Run `grunt` for building and `grunt serve` for preview.
9 |
10 | ## Testing
11 |
12 | Running `grunt test` will run the unit tests with karma.
13 |
--------------------------------------------------------------------------------
/app/.buildignore:
--------------------------------------------------------------------------------
1 | *.coffee
--------------------------------------------------------------------------------
/app/.htaccess:
--------------------------------------------------------------------------------
1 | # Apache Configuration File
2 |
3 | # (!) Using `.htaccess` files slows down Apache, therefore, if you have access
4 | # to the main server config file (usually called `httpd.conf`), you should add
5 | # this logic there: http://httpd.apache.org/docs/current/howto/htaccess.html.
6 |
7 | # ##############################################################################
8 | # # CROSS-ORIGIN RESOURCE SHARING (CORS) #
9 | # ##############################################################################
10 |
11 | # ------------------------------------------------------------------------------
12 | # | Cross-domain AJAX requests |
13 | # ------------------------------------------------------------------------------
14 |
15 | # Enable cross-origin AJAX requests.
16 | # http://code.google.com/p/html5security/wiki/CrossOriginRequestSecurity
17 | # http://enable-cors.org/
18 |
19 | #
20 | # Header set Access-Control-Allow-Origin "*"
21 | #
22 |
23 | # ------------------------------------------------------------------------------
24 | # | CORS-enabled images |
25 | # ------------------------------------------------------------------------------
26 |
27 | # Send the CORS header for images when browsers request it.
28 | # https://developer.mozilla.org/en/CORS_Enabled_Image
29 | # http://blog.chromium.org/2011/07/using-cross-domain-images-in-webgl-and.html
30 | # http://hacks.mozilla.org/2011/11/using-cors-to-load-webgl-textures-from-cross-domain-images/
31 |
32 |
33 |
34 |
35 | SetEnvIf Origin ":" IS_CORS
36 | Header set Access-Control-Allow-Origin "*" env=IS_CORS
37 |
38 |
39 |
40 |
41 | # ------------------------------------------------------------------------------
42 | # | Web fonts access |
43 | # ------------------------------------------------------------------------------
44 |
45 | # Allow access from all domains for web fonts
46 |
47 |
48 |
49 | Header set Access-Control-Allow-Origin "*"
50 |
51 |
52 |
53 |
54 | # ##############################################################################
55 | # # ERRORS #
56 | # ##############################################################################
57 |
58 | # ------------------------------------------------------------------------------
59 | # | 404 error prevention for non-existing redirected folders |
60 | # ------------------------------------------------------------------------------
61 |
62 | # Prevent Apache from returning a 404 error for a rewrite if a directory
63 | # with the same name does not exist.
64 | # http://httpd.apache.org/docs/current/content-negotiation.html#multiviews
65 | # http://www.webmasterworld.com/apache/3808792.htm
66 |
67 | Options -MultiViews
68 |
69 | # ------------------------------------------------------------------------------
70 | # | Custom error messages / pages |
71 | # ------------------------------------------------------------------------------
72 |
73 | # You can customize what Apache returns to the client in case of an error (see
74 | # http://httpd.apache.org/docs/current/mod/core.html#errordocument), e.g.:
75 |
76 | ErrorDocument 404 /404.html
77 |
78 |
79 | # ##############################################################################
80 | # # INTERNET EXPLORER #
81 | # ##############################################################################
82 |
83 | # ------------------------------------------------------------------------------
84 | # | Better website experience |
85 | # ------------------------------------------------------------------------------
86 |
87 | # Force IE to render pages in the highest available mode in the various
88 | # cases when it may not: http://hsivonen.iki.fi/doctype/ie-mode.pdf.
89 |
90 |
91 | Header set X-UA-Compatible "IE=edge"
92 | # `mod_headers` can't match based on the content-type, however, we only
93 | # want to send this header for HTML pages and not for the other resources
94 |
95 | Header unset X-UA-Compatible
96 |
97 |
98 |
99 | # ------------------------------------------------------------------------------
100 | # | Cookie setting from iframes |
101 | # ------------------------------------------------------------------------------
102 |
103 | # Allow cookies to be set from iframes in IE.
104 |
105 | #
106 | # Header set P3P "policyref=\"/w3c/p3p.xml\", CP=\"IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT\""
107 | #
108 |
109 | # ------------------------------------------------------------------------------
110 | # | Screen flicker |
111 | # ------------------------------------------------------------------------------
112 |
113 | # Stop screen flicker in IE on CSS rollovers (this only works in
114 | # combination with the `ExpiresByType` directives for images from below).
115 |
116 | # BrowserMatch "MSIE" brokenvary=1
117 | # BrowserMatch "Mozilla/4.[0-9]{2}" brokenvary=1
118 | # BrowserMatch "Opera" !brokenvary
119 | # SetEnvIf brokenvary 1 force-no-vary
120 |
121 |
122 | # ##############################################################################
123 | # # MIME TYPES AND ENCODING #
124 | # ##############################################################################
125 |
126 | # ------------------------------------------------------------------------------
127 | # | Proper MIME types for all files |
128 | # ------------------------------------------------------------------------------
129 |
130 |
131 |
132 | # Audio
133 | AddType audio/mp4 m4a f4a f4b
134 | AddType audio/ogg oga ogg
135 |
136 | # JavaScript
137 | # Normalize to standard type (it's sniffed in IE anyways):
138 | # http://tools.ietf.org/html/rfc4329#section-7.2
139 | AddType application/javascript js jsonp
140 | AddType application/json json
141 |
142 | # Video
143 | AddType video/mp4 mp4 m4v f4v f4p
144 | AddType video/ogg ogv
145 | AddType video/webm webm
146 | AddType video/x-flv flv
147 |
148 | # Web fonts
149 | AddType application/font-woff woff
150 | AddType application/vnd.ms-fontobject eot
151 |
152 | # Browsers usually ignore the font MIME types and sniff the content,
153 | # however, Chrome shows a warning if other MIME types are used for the
154 | # following fonts.
155 | AddType application/x-font-ttf ttc ttf
156 | AddType font/opentype otf
157 |
158 | # Make SVGZ fonts work on iPad:
159 | # https://twitter.com/FontSquirrel/status/14855840545
160 | AddType image/svg+xml svg svgz
161 | AddEncoding gzip svgz
162 |
163 | # Other
164 | AddType application/octet-stream safariextz
165 | AddType application/x-chrome-extension crx
166 | AddType application/x-opera-extension oex
167 | AddType application/x-shockwave-flash swf
168 | AddType application/x-web-app-manifest+json webapp
169 | AddType application/x-xpinstall xpi
170 | AddType application/xml atom rdf rss xml
171 | AddType image/webp webp
172 | AddType image/x-icon ico
173 | AddType text/cache-manifest appcache manifest
174 | AddType text/vtt vtt
175 | AddType text/x-component htc
176 | AddType text/x-vcard vcf
177 |
178 |
179 |
180 | # ------------------------------------------------------------------------------
181 | # | UTF-8 encoding |
182 | # ------------------------------------------------------------------------------
183 |
184 | # Use UTF-8 encoding for anything served as `text/html` or `text/plain`.
185 | AddDefaultCharset utf-8
186 |
187 | # Force UTF-8 for certain file formats.
188 |
189 | AddCharset utf-8 .atom .css .js .json .rss .vtt .webapp .xml
190 |
191 |
192 |
193 | # ##############################################################################
194 | # # URL REWRITES #
195 | # ##############################################################################
196 |
197 | # ------------------------------------------------------------------------------
198 | # | Rewrite engine |
199 | # ------------------------------------------------------------------------------
200 |
201 | # Turning on the rewrite engine and enabling the `FollowSymLinks` option is
202 | # necessary for the following directives to work.
203 |
204 | # If your web host doesn't allow the `FollowSymlinks` option, you may need to
205 | # comment it out and use `Options +SymLinksIfOwnerMatch` but, be aware of the
206 | # performance impact: http://httpd.apache.org/docs/current/misc/perf-tuning.html#symlinks
207 |
208 | # Also, some cloud hosting services require `RewriteBase` to be set:
209 | # http://www.rackspace.com/knowledge_center/frequently-asked-question/why-is-mod-rewrite-not-working-on-my-site
210 |
211 |
212 | Options +FollowSymlinks
213 | # Options +SymLinksIfOwnerMatch
214 | RewriteEngine On
215 | # RewriteBase /
216 |
217 |
218 | # ------------------------------------------------------------------------------
219 | # | Suppressing / Forcing the "www." at the beginning of URLs |
220 | # ------------------------------------------------------------------------------
221 |
222 | # The same content should never be available under two different URLs especially
223 | # not with and without "www." at the beginning. This can cause SEO problems
224 | # (duplicate content), therefore, you should choose one of the alternatives and
225 | # redirect the other one.
226 |
227 | # By default option 1 (no "www.") is activated:
228 | # http://no-www.org/faq.php?q=class_b
229 |
230 | # If you'd prefer to use option 2, just comment out all the lines from option 1
231 | # and uncomment the ones from option 2.
232 |
233 | # IMPORTANT: NEVER USE BOTH RULES AT THE SAME TIME!
234 |
235 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
236 |
237 | # Option 1: rewrite www.example.com → example.com
238 |
239 |
240 | RewriteCond %{HTTPS} !=on
241 | RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
242 | RewriteRule ^ http://%1%{REQUEST_URI} [R=301,L]
243 |
244 |
245 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
246 |
247 | # Option 2: rewrite example.com → www.example.com
248 |
249 | # Be aware that the following might not be a good idea if you use "real"
250 | # subdomains for certain parts of your website.
251 |
252 | #
253 | # RewriteCond %{HTTPS} !=on
254 | # RewriteCond %{HTTP_HOST} !^www\..+$ [NC]
255 | # RewriteRule ^ http://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
256 | #
257 |
258 |
259 | # ##############################################################################
260 | # # SECURITY #
261 | # ##############################################################################
262 |
263 | # ------------------------------------------------------------------------------
264 | # | Content Security Policy (CSP) |
265 | # ------------------------------------------------------------------------------
266 |
267 | # You can mitigate the risk of cross-site scripting and other content-injection
268 | # attacks by setting a Content Security Policy which whitelists trusted sources
269 | # of content for your site.
270 |
271 | # The example header below allows ONLY scripts that are loaded from the current
272 | # site's origin (no inline scripts, no CDN, etc). This almost certainly won't
273 | # work as-is for your site!
274 |
275 | # To get all the details you'll need to craft a reasonable policy for your site,
276 | # read: http://html5rocks.com/en/tutorials/security/content-security-policy (or
277 | # see the specification: http://w3.org/TR/CSP).
278 |
279 | #
280 | # Header set Content-Security-Policy "script-src 'self'; object-src 'self'"
281 | #
282 | # Header unset Content-Security-Policy
283 | #
284 | #
285 |
286 | # ------------------------------------------------------------------------------
287 | # | File access |
288 | # ------------------------------------------------------------------------------
289 |
290 | # Block access to directories without a default document.
291 | # Usually you should leave this uncommented because you shouldn't allow anyone
292 | # to surf through every directory on your server (which may includes rather
293 | # private places like the CMS's directories).
294 |
295 |
296 | Options -Indexes
297 |
298 |
299 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
300 |
301 | # Block access to hidden files and directories.
302 | # This includes directories used by version control systems such as Git and SVN.
303 |
304 |
305 | RewriteCond %{SCRIPT_FILENAME} -d [OR]
306 | RewriteCond %{SCRIPT_FILENAME} -f
307 | RewriteRule "(^|/)\." - [F]
308 |
309 |
310 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
311 |
312 | # Block access to backup and source files.
313 | # These files may be left by some text editors and can pose a great security
314 | # danger when anyone has access to them.
315 |
316 |
317 | Order allow,deny
318 | Deny from all
319 | Satisfy All
320 |
321 |
322 | # ------------------------------------------------------------------------------
323 | # | Secure Sockets Layer (SSL) |
324 | # ------------------------------------------------------------------------------
325 |
326 | # Rewrite secure requests properly to prevent SSL certificate warnings, e.g.:
327 | # prevent `https://www.example.com` when your certificate only allows
328 | # `https://secure.example.com`.
329 |
330 | #
331 | # RewriteCond %{SERVER_PORT} !^443
332 | # RewriteRule ^ https://example-domain-please-change-me.com%{REQUEST_URI} [R=301,L]
333 | #
334 |
335 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
336 |
337 | # Force client-side SSL redirection.
338 |
339 | # If a user types "example.com" in his browser, the above rule will redirect him
340 | # to the secure version of the site. That still leaves a window of opportunity
341 | # (the initial HTTP connection) for an attacker to downgrade or redirect the
342 | # request. The following header ensures that browser will ONLY connect to your
343 | # server via HTTPS, regardless of what the users type in the address bar.
344 | # http://www.html5rocks.com/en/tutorials/security/transport-layer-security/
345 |
346 | #
347 | # Header set Strict-Transport-Security max-age=16070400;
348 | #
349 |
350 | # ------------------------------------------------------------------------------
351 | # | Server software information |
352 | # ------------------------------------------------------------------------------
353 |
354 | # Avoid displaying the exact Apache version number, the description of the
355 | # generic OS-type and the information about Apache's compiled-in modules.
356 |
357 | # ADD THIS DIRECTIVE IN THE `httpd.conf` AS IT WILL NOT WORK IN THE `.htaccess`!
358 |
359 | # ServerTokens Prod
360 |
361 |
362 | # ##############################################################################
363 | # # WEB PERFORMANCE #
364 | # ##############################################################################
365 |
366 | # ------------------------------------------------------------------------------
367 | # | Compression |
368 | # ------------------------------------------------------------------------------
369 |
370 |
371 |
372 | # Force compression for mangled headers.
373 | # http://developer.yahoo.com/blogs/ydn/posts/2010/12/pushing-beyond-gzipping
374 |
375 |
376 | SetEnvIfNoCase ^(Accept-EncodXng|X-cept-Encoding|X{15}|~{15}|-{15})$ ^((gzip|deflate)\s*,?\s*)+|[X~-]{4,13}$ HAVE_Accept-Encoding
377 | RequestHeader append Accept-Encoding "gzip,deflate" env=HAVE_Accept-Encoding
378 |
379 |
380 |
381 | # Compress all output labeled with one of the following MIME-types
382 | # (for Apache versions below 2.3.7, you don't need to enable `mod_filter`
383 | # and can remove the `` and `` lines
384 | # as `AddOutputFilterByType` is still in the core directives).
385 |
386 | AddOutputFilterByType DEFLATE application/atom+xml \
387 | application/javascript \
388 | application/json \
389 | application/rss+xml \
390 | application/vnd.ms-fontobject \
391 | application/x-font-ttf \
392 | application/x-web-app-manifest+json \
393 | application/xhtml+xml \
394 | application/xml \
395 | font/opentype \
396 | image/svg+xml \
397 | image/x-icon \
398 | text/css \
399 | text/html \
400 | text/plain \
401 | text/x-component \
402 | text/xml
403 |
404 |
405 |
406 |
407 | # ------------------------------------------------------------------------------
408 | # | Content transformations |
409 | # ------------------------------------------------------------------------------
410 |
411 | # Prevent some of the mobile network providers from modifying the content of
412 | # your site: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.5.
413 |
414 | #
415 | # Header set Cache-Control "no-transform"
416 | #
417 |
418 | # ------------------------------------------------------------------------------
419 | # | ETag removal |
420 | # ------------------------------------------------------------------------------
421 |
422 | # Since we're sending far-future expires headers (see below), ETags can
423 | # be removed: http://developer.yahoo.com/performance/rules.html#etags.
424 |
425 | # `FileETag None` is not enough for every server.
426 |
427 | Header unset ETag
428 |
429 |
430 | FileETag None
431 |
432 | # ------------------------------------------------------------------------------
433 | # | Expires headers (for better cache control) |
434 | # ------------------------------------------------------------------------------
435 |
436 | # The following expires headers are set pretty far in the future. If you don't
437 | # control versioning with filename-based cache busting, consider lowering the
438 | # cache time for resources like CSS and JS to something like 1 week.
439 |
440 |
441 |
442 | ExpiresActive on
443 | ExpiresDefault "access plus 1 month"
444 |
445 | # CSS
446 | ExpiresByType text/css "access plus 1 year"
447 |
448 | # Data interchange
449 | ExpiresByType application/json "access plus 0 seconds"
450 | ExpiresByType application/xml "access plus 0 seconds"
451 | ExpiresByType text/xml "access plus 0 seconds"
452 |
453 | # Favicon (cannot be renamed!)
454 | ExpiresByType image/x-icon "access plus 1 week"
455 |
456 | # HTML components (HTCs)
457 | ExpiresByType text/x-component "access plus 1 month"
458 |
459 | # HTML
460 | ExpiresByType text/html "access plus 0 seconds"
461 |
462 | # JavaScript
463 | ExpiresByType application/javascript "access plus 1 year"
464 |
465 | # Manifest files
466 | ExpiresByType application/x-web-app-manifest+json "access plus 0 seconds"
467 | ExpiresByType text/cache-manifest "access plus 0 seconds"
468 |
469 | # Media
470 | ExpiresByType audio/ogg "access plus 1 month"
471 | ExpiresByType image/gif "access plus 1 month"
472 | ExpiresByType image/jpeg "access plus 1 month"
473 | ExpiresByType image/png "access plus 1 month"
474 | ExpiresByType video/mp4 "access plus 1 month"
475 | ExpiresByType video/ogg "access plus 1 month"
476 | ExpiresByType video/webm "access plus 1 month"
477 |
478 | # Web feeds
479 | ExpiresByType application/atom+xml "access plus 1 hour"
480 | ExpiresByType application/rss+xml "access plus 1 hour"
481 |
482 | # Web fonts
483 | ExpiresByType application/font-woff "access plus 1 month"
484 | ExpiresByType application/vnd.ms-fontobject "access plus 1 month"
485 | ExpiresByType application/x-font-ttf "access plus 1 month"
486 | ExpiresByType font/opentype "access plus 1 month"
487 | ExpiresByType image/svg+xml "access plus 1 month"
488 |
489 |
490 |
491 | # ------------------------------------------------------------------------------
492 | # | Filename-based cache busting |
493 | # ------------------------------------------------------------------------------
494 |
495 | # If you're not using a build process to manage your filename version revving,
496 | # you might want to consider enabling the following directives to route all
497 | # requests such as `/css/style.12345.css` to `/css/style.css`.
498 |
499 | # To understand why this is important and a better idea than `*.css?v231`, read:
500 | # http://stevesouders.com/blog/2008/08/23/revving-filenames-dont-use-querystring
501 |
502 | #
503 | # RewriteCond %{REQUEST_FILENAME} !-f
504 | # RewriteCond %{REQUEST_FILENAME} !-d
505 | # RewriteRule ^(.+)\.(\d+)\.(js|css|png|jpg|gif)$ $1.$3 [L]
506 | #
507 |
508 | # ------------------------------------------------------------------------------
509 | # | File concatenation |
510 | # ------------------------------------------------------------------------------
511 |
512 | # Allow concatenation from within specific CSS and JS files, e.g.:
513 | # Inside of `script.combined.js` you could have
514 | #
515 | #
516 | # and they would be included into this single file.
517 |
518 | #
519 | #
520 | # Options +Includes
521 | # AddOutputFilterByType INCLUDES application/javascript application/json
522 | # SetOutputFilter INCLUDES
523 | #
524 | #
525 | # Options +Includes
526 | # AddOutputFilterByType INCLUDES text/css
527 | # SetOutputFilter INCLUDES
528 | #
529 | #
530 |
531 | # ------------------------------------------------------------------------------
532 | # | Persistent connections |
533 | # ------------------------------------------------------------------------------
534 |
535 | # Allow multiple requests to be sent over the same TCP connection:
536 | # http://httpd.apache.org/docs/current/en/mod/core.html#keepalive.
537 |
538 | # Enable if you serve a lot of static content but, be aware of the
539 | # possible disadvantages!
540 |
541 | #
542 | # Header set Connection Keep-Alive
543 | #
544 |
--------------------------------------------------------------------------------
/app/404.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Page Not Found :(
6 |
141 |
142 |
143 |
144 |
Not found :(
145 |
Sorry, but the page you were trying to view does not exist.
146 |
It looks like this was the result of either:
147 |
148 | - a mistyped address
149 | - an out-of-date link
150 |
151 |
154 |
155 |
156 |
157 |
158 |
--------------------------------------------------------------------------------
/app/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/learncodeacademy/moltin-angular/541cac65e35e09f4874811cd52fe4c6bb516baf7/app/favicon.ico
--------------------------------------------------------------------------------
/app/images/yeoman.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/learncodeacademy/moltin-angular/541cac65e35e09f4874811cd52fe4c6bb516baf7/app/images/yeoman.png
--------------------------------------------------------------------------------
/app/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
22 |
23 |
24 |
56 |
57 |
60 |
61 |
66 |
67 |
68 |
69 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
--------------------------------------------------------------------------------
/app/robots.txt:
--------------------------------------------------------------------------------
1 | # robotstxt.org
2 |
3 | User-agent: *
4 |
--------------------------------------------------------------------------------
/app/scripts/app.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * @ngdoc overview
5 | * @name storefrontApp
6 | * @description
7 | * # storefrontApp
8 | *
9 | * Main module of the application.
10 | */
11 | angular
12 | .module('storefrontApp', [
13 | 'storefrontApp.moltin',
14 | 'ngAnimate',
15 | 'ngCookies',
16 | 'ngResource',
17 | 'ngRoute',
18 | 'ngSanitize',
19 | 'ngTouch'
20 | ])
21 | .config(function ($routeProvider) {
22 | $routeProvider
23 | .when('/', {
24 | templateUrl: 'views/main.html',
25 | controller: 'MainCtrl'
26 | })
27 | .when('/about', {
28 | templateUrl: 'views/about.html',
29 | controller: 'AboutCtrl'
30 | })
31 | .when('/store', {
32 | templateUrl: 'views/store.html',
33 | controller: 'StoreCtrl',
34 | resolve: {
35 | categories: function($q, MoltinAuth) {
36 | var deferred = $q.defer();
37 | MoltinAuth.then(function(moltin) {
38 | moltin.Category.List(null, function(categories) {
39 | deferred.resolve(categories);
40 | });
41 | })
42 | return deferred.promise;
43 | },
44 | features: function($q, MoltinAuth) {
45 | var deferred = $q.defer();
46 | MoltinAuth.then(function(moltin) {
47 | //"Homepage Features" collection
48 | moltin.Product.List({collection:'947420948187841171'}, function(collection) {
49 | deferred.resolve(collection);
50 | });
51 | });
52 | return deferred.promise;
53 | }
54 | }
55 | })
56 | .when('/category/:id', {
57 | templateUrl: 'views/category.html',
58 | controller: 'CategoryCtrl',
59 | resolve: {
60 | category: function($q, $route, MoltinAuth) {
61 | var deferred = $q.defer();
62 | MoltinAuth.then(function(moltin) {
63 | moltin.Category.Get($route.current.params.id, function(category) {
64 | deferred.resolve(category);
65 | });
66 | })
67 | return deferred.promise;
68 | },
69 | products: function($q, $route, MoltinAuth) {
70 | var deferred = $q.defer();
71 | MoltinAuth.then(function(moltin) {
72 | moltin.Product.List({category: $route.current.params.id}, function(products) {
73 | deferred.resolve(products);
74 | });
75 | })
76 | return deferred.promise;
77 | }
78 | }
79 | })
80 | .when('/product/:id', {
81 | templateUrl: 'views/product.html',
82 | controller: 'ProductCtrl',
83 | resolve: {
84 | product: function($q, $route, MoltinAuth) {
85 | var deferred = $q.defer();
86 | MoltinAuth.then(function(moltin) {
87 | moltin.Product.Get($route.current.params.id, function(product) {
88 | deferred.resolve(product);
89 | });
90 | })
91 | return deferred.promise;
92 | },
93 | moltin: function(MoltinAuth) {
94 | return MoltinAuth;
95 | }
96 | }
97 | })
98 | .when('/cart', {
99 | templateUrl: 'views/cart.html',
100 | controller: 'CartCtrl',
101 | resolve: {
102 | cart: function($q, MoltinAuth) {
103 | var deferred = $q.defer();
104 | MoltinAuth.then(function(moltin) {
105 | moltin.Cart.Contents(function(cart) {
106 | deferred.resolve(cart);
107 | });
108 | })
109 | return deferred.promise;
110 | },
111 | }
112 | })
113 | .when('/checkout', {
114 | templateUrl: 'views/checkout.html',
115 | controller: 'CheckoutCtrl',
116 | resolve: {
117 | cart: function($q, MoltinAuth) {
118 | var deferred = $q.defer();
119 | MoltinAuth.then(function(moltin) {
120 | moltin.Cart.Contents(function(cart) {
121 | deferred.resolve(cart);
122 | });
123 | })
124 | return deferred.promise;
125 | },
126 | options: function($q, MoltinAuth) {
127 | var deferred = $q.defer();
128 | MoltinAuth.then(function(moltin) {
129 | moltin.Cart.Checkout(function(options) {
130 | deferred.resolve(options);
131 | });
132 | })
133 | return deferred.promise;
134 | },
135 | fields: function($q, MoltinAuth) {
136 | var deferred = $q.defer();
137 | MoltinAuth.then(function(moltin) {
138 | moltin.Address.Fields(null, null, function(fields) {
139 | deferred.resolve(fields);
140 | });
141 | })
142 | return deferred.promise;
143 | },
144 | moltin: function(MoltinAuth) {
145 | return MoltinAuth;
146 | }
147 | }
148 | })
149 | .when('/payment', {
150 | templateUrl: 'views/payment.html',
151 | controller: 'PaymentCtrl',
152 | resolve: {
153 | moltin: function($q, MoltinAuth) {
154 | return MoltinAuth;
155 | }
156 | }
157 | })
158 | .when('/complete', {
159 | templateUrl: 'views/complete.html',
160 | controller: 'CompleteCtrl'
161 | })
162 | .otherwise({
163 | redirectTo: '/'
164 | });
165 | }).run(function(MoltinAuth, $rootScope) {
166 | MoltinAuth.then(function(moltin) {
167 | moltin.Cart.Contents(function(items) {
168 | $rootScope.cart = items;
169 | $rootScope.$apply();
170 | });
171 | });
172 | });
173 |
--------------------------------------------------------------------------------
/app/scripts/controllers/cart.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * @ngdoc function
5 | * @name storefrontApp.controller:CartCtrl
6 | * @description
7 | * # CartCtrl
8 | * Controller of the storefrontApp
9 | */
10 | angular.module('storefrontApp')
11 | .controller('CartCtrl', function ($scope, cart) {
12 | $scope.cart = cart;
13 | console.log(cart);
14 | });
15 |
--------------------------------------------------------------------------------
/app/scripts/controllers/category.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * @ngdoc function
5 | * @name storefrontApp.controller:CategoryCtrl
6 | * @description
7 | * # CategoryCtrl
8 | * Controller of the storefrontApp
9 | */
10 | angular.module('storefrontApp')
11 | .controller('CategoryCtrl', function ($scope, category, products) {
12 | $scope.category = category;
13 | $scope.products = products;
14 | console.log(category, products);
15 | });
16 |
--------------------------------------------------------------------------------
/app/scripts/controllers/checkout.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * @ngdoc function
5 | * @name storefrontApp.controller:CheckoutCtrl
6 | * @description
7 | * # CheckoutCtrl
8 | * Controller of the storefrontApp
9 | */
10 | angular.module('storefrontApp')
11 | .controller('CheckoutCtrl', function ($scope, $rootScope, $location, moltin, cart, options, fields) {
12 | $scope.data = {bill: {}, ship: {}, ship_bill: 0, notes: '', shipping: '', gateway: ''}
13 | $scope.cart = cart;
14 | $scope.options = options;
15 | $scope.fields = fields;
16 |
17 | $scope.createOrder = function() {
18 | moltin.Cart.Order({
19 | customer: '947445503480562327', //guest customer for now
20 | shipping: $scope.data.shipping,
21 | gateway: $scope.data.gateway,
22 | bill_to: $scope.data.bill,
23 | ship_to: $scope.data.ship_bill ? 'bill_to' : $scope.data.ship
24 | }, function(response) {
25 | $rootScope.order = response;
26 | $rootScope.$apply(function() {
27 | $location.path('/payment');
28 | });
29 | })
30 | }
31 |
32 | });
33 |
--------------------------------------------------------------------------------
/app/scripts/controllers/complete.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * @ngdoc function
5 | * @name storefrontApp.controller:CompleteCtrl
6 | * @description
7 | * # CompleteCtrl
8 | * Controller of the storefrontApp
9 | */
10 | angular.module('storefrontApp')
11 | .controller('CompleteCtrl', function ($scope) {
12 | $scope.awesomeThings = [
13 | 'HTML5 Boilerplate',
14 | 'AngularJS',
15 | 'Karma'
16 | ];
17 | });
18 |
--------------------------------------------------------------------------------
/app/scripts/controllers/main.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * @ngdoc function
5 | * @name storefrontApp.controller:MainCtrl
6 | * @description
7 | * # MainCtrl
8 | * Controller of the storefrontApp
9 | */
10 | angular.module('storefrontApp')
11 | .controller('MainCtrl', function ($scope) {
12 | $scope.awesomeThings = [
13 | 'HTML5 Boilerplate',
14 | 'AngularJS',
15 | 'Karma'
16 | ];
17 | });
18 |
--------------------------------------------------------------------------------
/app/scripts/controllers/payment.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * @ngdoc function
5 | * @name storefrontApp.controller:PaymentCtrl
6 | * @description
7 | * # PaymentCtrl
8 | * Controller of the storefrontApp
9 | */
10 | angular.module('storefrontApp')
11 | .controller('PaymentCtrl', function ($scope, $location, $rootScope, moltin) {
12 | $scope.payment = function(data) {
13 | moltin.Checkout.Payment('purchase', $scope.order.id, {data: $scope.data}, function(response) {
14 | $rootScope.order = $rootScope.cart = null;
15 | $rootScope.payment = response;
16 | $rootScope.$apply(function() {
17 | $location.path('/complete');
18 | });
19 | });
20 | }
21 | });
22 |
--------------------------------------------------------------------------------
/app/scripts/controllers/product.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * @ngdoc function
5 | * @name storefrontApp.controller:ProductCtrl
6 | * @description
7 | * # ProductCtrl
8 | * Controller of the storefrontApp
9 | */
10 | angular.module('storefrontApp')
11 | .controller('ProductCtrl', function ($scope, $rootScope, product, moltin, $timeout) {
12 | $scope.product = product;
13 | $scope.addStatus = null;
14 |
15 | $scope.addCart = function() {
16 | $scope.addStatus = 'Adding to cart...';
17 | // Insert(id, qty, modifiers/size, callback)
18 | moltin.Cart.Insert(product.id, 1, null, function(cart) {
19 | $scope.addStatus = 'Success!';
20 | moltin.Cart.Contents(function(items) {
21 | $rootScope.cart = items;
22 | $rootScope.$apply();
23 | });
24 | $scope.$apply();
25 | $timeout(function() {
26 | $scope.addStatus = null;
27 | }, 1000);
28 | });
29 | }
30 | console.log(product);
31 | });
32 |
--------------------------------------------------------------------------------
/app/scripts/controllers/store.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * @ngdoc function
5 | * @name storefrontApp.controller:StoreCtrl
6 | * @description
7 | * # StoreCtrl
8 | * Controller of the storefrontApp
9 | */
10 | angular.module('storefrontApp')
11 | .controller('StoreCtrl', function ($scope, categories, features) {
12 | $scope.categories = categories;
13 | $scope.features = features;
14 | console.log(features);
15 | });
16 |
--------------------------------------------------------------------------------
/app/scripts/services/moltin.js:
--------------------------------------------------------------------------------
1 | angular.module('storefrontApp.moltin', [])
2 | .factory('MoltinAuth', function($q) {
3 | var deferred = $q.defer();
4 | var moltin = new Moltin({publicId: 'hHr6QhXDTz9XigXiyPzKaaeLEHLHJJXhychmd186'});
5 | moltin.Authenticate(function() {
6 | deferred.resolve(moltin);
7 | });
8 |
9 | return deferred.promise;
10 | });
11 |
--------------------------------------------------------------------------------
/app/scripts/vendor/moltin.min.js:
--------------------------------------------------------------------------------
1 | /*! moltin-sdk minified - v0.6.0 - 2015-02-15 */
2 |
3 | var Moltin,__indexOf=[].indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(b in this&&this[b]===a)return b;return-1};Moltin=function(){"use strict";function a(a){this.options=this.Merge(this.options,a),this.Storage=new o,this.Address=new b(this),this.Brand=new c(this),this.Cart=new d(this),this.Category=new e(this),this.Checkout=new f(this),this.Collection=new g(this),this.Currency=new h(this),this.Entry=new j(this),this.Gateway=new k(this),this.Order=new l(this),this.Product=new m(this),this.Shipping=new n(this),this.Tax=new p(this),this.Storage.get("_mc")&&(this.options.currency=this.Storage.get("_mc")),this.Storage.get("_ms")||this.Storage.set("_ms",this.Cart.CreateIdentifier())}var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p;return a.prototype.options={publicId:"",auth:{},url:"https://api.molt.in/",version:"beta",debug:!1,currency:!1,notice:function(a,b){return alert(a+": "+b)},methods:["GET","POST","PUT","DELETE"]},a.prototype.Merge=function(a,b){var c,d,e;d={};for(c in a)e=a[c],d[c]=e;for(c in b)e=b[c],d[c]=e;return d},a.prototype.InArray=function(a,b){return __indexOf.call(b,a)<0?!1:!0},a.prototype.Serialize=function(a,b){var c,d,e;null==b&&(b=null),d=[];for(c in a)e=a[c],c=null!==b?b+"["+c+"]":c,d.push("object"==typeof e?this.Serialize(e,c):encodeURIComponent(c)+"="+encodeURIComponent(e));return d.join("&")},a.prototype.Error=function(a){var b,c,d,e;if(c="","undefind"!=typeof a.errors){e=a.errors;for(b in e)d=e[b],c+=d+"
"}else c=a.error;return this.options.notice("Error",c)},a.prototype.Ajax=function(a){var b,c,d,e,f,g,h;b={type:"GET",async:!1,data:null,timeout:5e3,headers:{},url:this.options.url+this.options.version,success:function(){},error:function(){}},b=this.Merge(b,a),b.type=b.type.toUpperCase();try{e=new XMLHttpRequest}catch(i){c=i;try{e=new ActiveXObject("Msxml2.XMLHTTP")}catch(i){return c=i,!1}}"GET"===b.type?(b.url+="?"+this.Serialize(b.data),b.data=null):b.data=this.Serialize(b.data),e.open(b.type,b.url,b.async),f=setTimeout(function(a){return function(){return e.abort(),b.error(a.options.notice("error","Your request timed out"))}}(this),b.timeout),h=b.headers;for(d in h)g=h[d],e.setRequestHeader(d,g);return e.onreadystatechange=function(){var a;return 4!==e.readyState?null:(clearTimeout(f),a=JSON.parse(e.responseText),"2"!==e.status.toString().charAt(0)?b.error(e,e.status,a):b.success(a,e.status,e))},e.send(b.data)},a.prototype.Authenticate=function(a){var b;return this.options.publicId.length<=0?this.options.notice("error","Public ID must be set"):null!==this.Storage.get("_mt")&&parseInt(this.Storage.get("_me"))>Date.now()?(this.options.auth={token:this.Storage.get("_mt"),expires:this.Storage.get("_me")},"function"==typeof a&&a(this.options.auth),b=new CustomEvent("MoltinReady",{detail:this}),window.dispatchEvent(b),this):(this.Ajax({type:"POST",url:this.options.url+"oauth/access_token",data:{grant_type:"implicit",client_id:this.options.publicId},async:"function"==typeof a?!0:!1,headers:{"Content-Type":"application/x-www-form-urlencoded"},success:function(c){return function(d){return c.options.auth={token:d.access_token,expires:1e3*parseInt(d.expires)},c.Storage.set("_mt",d.access_token),c.Storage.set("_me",c.options.auth.expires),"function"==typeof a&&a(d),b=new CustomEvent("MoltinReady",{detail:c}),window.dispatchEvent(b)}}(this),error:function(a){return function(){return a.options.notice("error","Authorization failed")}}(this)}),this)},a.prototype.Request=function(a,b,c,d){var e,f;return null==b&&(b="GET"),null==c&&(c=null),e={},f={"Content-Type":"application/x-www-form-urlencoded",Authorization:"Bearer "+this.options.auth.token,"X-Session":this.Storage.get("_ms"),"X-Location":window.location.href},null===this.options.auth.token?this.options.notice("error","You must authenticate first"):(Date.now()>parseInt(this.Storage.get("_me"))&&this.Authenticate(),this.InArray(b,this.options.methods)?(this.options.currency&&(f["X-Currency"]=this.options.currency),this.Ajax({type:b,url:this.options.url+this.options.version+"/"+a,data:c,async:"function"==typeof d?!0:!1,headers:f,success:function(){return function(a){return"function"==typeof d?d(a.result,"undefined"!=typeof a.pagination?a.pagination:null):e=a}}(this),error:function(a){return function(b,c){var d;return d=JSON.parse(b.responseText),d.status===!1&&a.options.notice("error","undefined"!=typeof d.errors?d.errors:d.error,c),e=d}}(this)}),"undefined"==typeof d?e.result:void 0):this.options.notice("error","Invalid request method ("+b+")"))},o=function(){function a(){}return a.prototype.set=function(a,b,c){var d,e;return e="",c&&(d=new Date,d.setTime(d.getTime()+24*c*60*60*1e3),e="; expires="+d.toGMTString()),document.cookie=a+"="+b+e+"; path=/"},a.prototype.get=function(a){var b,c,d,e;for(a+="=",e=document.cookie.split(";"),c=0,d=e.length;d>c;c++){for(b=e[c];" "===b.charAt(0);)b=b.substring(1,b.length);if(0===b.indexOf(a))return b.substring(a.length,b.length)}return null},a.prototype.remove=function(a){return this.set(a,"",-1)},a}(),b=function(){function a(a){this.m=a}return a.prototype.Get=function(a,b,c){return this.m.Request("customer/"+a+"/address/"+b,"GET",null,c)},a.prototype.Find=function(a,b,c){return this.m.Request("customer/"+a+"/address","GET",b,c)},a.prototype.List=function(a,b,c){return this.m.Request("customer/"+a+"/addresses","GET",b,c)},a.prototype.Create=function(a,b,c){return this.m.Request("customer/"+a+"/address","POST",b,c)},a.prototype.Fields=function(a,b,c){var d;return null==a&&(a=0),null==b&&(b=0),d=a>0&&0>=b?"customer/"+a+"/address/fields":a>0&&b>0?"customer/"+a+"/address/"+b+"/fields":"address/fields",this.m.Request(d,"GET",null,c)},a}(),c=function(){function a(a){this.m=a}return a.prototype.Get=function(a,b){return this.m.Request("brand/"+a,"GET",null,b)},a.prototype.Find=function(a,b){return this.m.Request("brand","GET",a,b)},a.prototype.List=function(a,b){return this.m.Request("brands","GET",a,b)},a.prototype.Fields=function(a,b){var c;return null==a&&(a=0),c="brand/"+(0!==a?a+"/fields":"fields"),this.m.Request(c,"GET",null,b)},a}(),d=function(){function a(a){this.m=a,this.identifier=this.GetIdentifier()}return a.prototype.CreateIdentifier=function(){return"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx".replace(/[x]/g,function(){return(16*Math.random()|0).toString(16)})},a.prototype.GetIdentifier=function(){var a;return null!==this.m.Storage.get("_mb")?this.m.Storage.get("_mb"):(a=this.CreateIdentifier(),this.m.Storage.set("_mb",a),a)},a.prototype.Contents=function(a){return this.m.Request("cart/"+this.identifier,"GET",null,a)},a.prototype.Insert=function(a,b,c,d){return null==b&&(b=1),null==c&&(c=null),this.m.Request("cart/"+this.identifier,"POST",{id:a,quantity:b,modifier:c},d)},a.prototype.Update=function(a,b,c){return this.m.Request("cart/"+this.identifier+"/item/"+a,"PUT",b,c)},a.prototype.Delete=function(a){return this.m.Request("cart/"+this.identifier,"DELETE",null,a)},a.prototype.Remove=function(a,b){return this.m.Request("cart/"+this.identifier+"/item/"+a,"DELETE",null,b)},a.prototype.Item=function(a,b){return this.m.Request("cart/"+this.identifier+"/item/"+a,"GET",null,b)},a.prototype.InCart=function(a,b){return this.m.Request("cart/"+this.identifier+"/has/"+a,"GET",null,b)},a.prototype.Checkout=function(a){return this.m.Request("cart/"+this.identifier+"/checkout","GET",null,a)},a.prototype.Order=function(a,b){return this.m.Request("cart/"+this.identifier+"/checkout","POST",a,b)},a}(),e=function(){function a(a){this.m=a}return a.prototype.Get=function(a,b){return this.m.Request("category/"+a,"GET",null,b)},a.prototype.Find=function(a,b){return this.m.Request("category","GET",a,b)},a.prototype.List=function(a,b){return this.m.Request("categories","GET",a,b)},a.prototype.Tree=function(a,b){return this.m.Request("categories/tree","GET",a,b)},a.prototype.Fields=function(a,b){var c;return null==a&&(a=0),c="category/"+(0!==a?a+"/fields":"fields"),this.m.Request(c,"GET",null,b)},a}(),f=function(){function a(a){this.m=a}return a.prototype.Payment=function(a,b,c,d){return this.m.Request("checkout/payment/"+a+"/"+b,"POST",c,d)},a}(),g=function(){function a(a){this.m=a}return a.prototype.Get=function(a,b){return this.m.Request("collection/"+a,"GET",null,b)},a.prototype.Find=function(a,b){return this.m.Request("collection","GET",a,b)},a.prototype.List=function(a,b){return this.m.Request("collections","GET",a,b)},a.prototype.Fields=function(a,b){var c;return null==a&&(a=0),c="collection/"+(0!==a?a+"/fields":"fields"),this.m.Request(c,"GET",null,b)},a}(),h=function(){function a(a){this.m=a}return a.prototype.Get=function(a,b){return this.m.Request("currency/"+a,"GET",null,b)},a.prototype.Set=function(a,b){return this.m.Storage.set("_mc",a),this.m.options.currency=a,"function"==typeof b?b(a):void 0},a.prototype.Find=function(a,b){return this.m.Request("currency","GET",a,b)},a.prototype.List=function(a,b){return this.m.Request("currencies","GET",a,b)},a.prototype.Fields=function(a,b){var c;return null==a&&(a=0),c="currency/"+(0!==a?a+"/fields":"fields"),this.m.Request(c,"GET",null,b)},a}(),i=function(){function a(a){this.m=a}return a.prototype.Get=function(a,b){return this.m.Request("customer/"+a,"GET",null,b)},a.prototype.Find=function(a,b){return this.m.Request("customer","GET",a,b)},a.prototype.List=function(a,b){return this.m.Request("customers","GET",a,b)},a.prototype.Fields=function(a,b){var c;return null==a&&(a=0),c="customer/"+(0!==a?a+"/fields":"fields"),this.m.Request(c,"GET",null,b)},a}(),j=function(){function a(a){this.m=a}return a.prototype.Get=function(a,b,c){return this.m.Request("flow/"+a+"/entry/"+b,"GET",null,c)},a.prototype.Find=function(a,b,c){return this.m.Request("flow/"+a+"/entry","GET",b,c)},a.prototype.List=function(a,b,c){return this.m.Request("flow/"+a+"/entries","GET",b,c)},a}(),k=function(){function a(a){this.m=a}return a.prototype.Get=function(a,b){return this.m.Request("gateway/"+a,"GET",null,b)},a.prototype.List=function(a,b){return this.m.Request("gateways","GET",a,b)},a}(),l=function(){function a(a){this.m=a}return a.prototype.Get=function(a,b){return this.m.Request("order/"+a,"GET",null,b)},a.prototype.Find=function(a,b){return this.m.Request("order","GET",a,b)},a.prototype.List=function(a,b){return this.m.Request("orders","GET",a,b)},a.prototype.Create=function(a,b){return this.m.Request("order","POST",a,b)},a}(),m=function(){function a(a){this.m=a}return a.prototype.Get=function(a,b){return this.m.Request("product/"+a,"GET",null,b)},a.prototype.Find=function(a,b){return this.m.Request("product","GET",a,b)},a.prototype.List=function(a,b){return this.m.Request("products","GET",a,b)},a.prototype.Search=function(a,b){return this.m.Request("products/search","GET",a,b)},a.prototype.Fields=function(a,b){var c;return null==a&&(a=0),c="product/"+(0!==a?a+"/fields":"fields"),this.m.Request(c,"GET",null,b)},a.prototype.Modifiers=function(a,b){return this.m.Request("product/"+a+"/modifiers","GET",null,b)},a.prototype.Variations=function(a){return this.m.Request("product/"+a+"/variations","GET",null,callback)},a}(),n=function(){function a(a){this.m=a}return a.prototype.Get=function(a,b){return this.m.Request("shipping/"+a,"GET",null,b)},a.prototype.List=function(a,b){return this.m.Request("shipping","GET",a,b)},a}(),p=function(){function a(a){this.m=a}return a.prototype.Get=function(a,b){return this.m.Request("tax/"+a,"GET",null,b)},a.prototype.Find=function(a,b){return this.m.Request("tax","GET",a,b)},a.prototype.List=function(a,b){return this.m.Request("taxes","GET",a,b)},a.prototype.Fields=function(a,b){var c;return null==a&&(a=0),c="tax/"+(0!==a?a+"/fields":"fields"),this.m.Request(c,"GET",null,b)},a}(),a}();
4 |
--------------------------------------------------------------------------------
/app/styles/main.scss:
--------------------------------------------------------------------------------
1 | $icon-font-path: "../bower_components/bootstrap-sass-official/assets/fonts/bootstrap/";
2 | // bower:scss
3 | @import "bootstrap-sass-official/assets/stylesheets/_bootstrap.scss";
4 | // endbower
5 |
6 | .browsehappy {
7 | margin: 0.2em 0;
8 | background: #ccc;
9 | color: #000;
10 | padding: 0.2em 0;
11 | }
12 |
13 | body {
14 | padding: 0;
15 | }
16 |
17 | /* Everything but the jumbotron gets side spacing for mobile first views */
18 | .header,
19 | .marketing,
20 | .footer {
21 | padding-left: 15px;
22 | padding-right: 15px;
23 | }
24 |
25 | /* Custom page header */
26 | .header {
27 | border-bottom: 1px solid #e5e5e5;
28 | margin-bottom: 10px;
29 |
30 | /* Make the masthead heading the same height as the navigation */
31 | h3 {
32 | margin-top: 0;
33 | margin-bottom: 0;
34 | line-height: 40px;
35 | padding-bottom: 19px;
36 | }
37 | }
38 |
39 | /* Custom page footer */
40 | .footer {
41 | padding-top: 19px;
42 | color: #777;
43 | border-top: 1px solid #e5e5e5;
44 | }
45 |
46 | .container-narrow > hr {
47 | margin: 30px 0;
48 | }
49 |
50 | /* Main marketing message and sign up button */
51 | .jumbotron {
52 | text-align: center;
53 | border-bottom: 1px solid #e5e5e5;
54 |
55 | .btn {
56 | font-size: 21px;
57 | padding: 14px 24px;
58 | }
59 | }
60 |
61 | /* Supporting marketing content */
62 | .marketing {
63 | margin: 40px 0;
64 |
65 | p + h4 {
66 | margin-top: 28px;
67 | }
68 | }
69 |
70 | /* Responsive: Portrait tablets and up */
71 | @media screen and (min-width: 768px) {
72 | .container {
73 | max-width: 730px;
74 | }
75 |
76 | /* Remove the padding we set earlier */
77 | .header,
78 | .marketing,
79 | .footer {
80 | padding-left: 0;
81 | padding-right: 0;
82 | }
83 | /* Space out the masthead */
84 | .header {
85 | margin-bottom: 30px;
86 | }
87 | /* Remove the bottom border on the jumbotron for visual effect */
88 | .jumbotron {
89 | border-bottom: 0;
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/app/styles/storefront.scss:
--------------------------------------------------------------------------------
1 | #cart {
2 | margin-top: 10px;
3 | }
4 |
--------------------------------------------------------------------------------
/app/views/cart.html:
--------------------------------------------------------------------------------
1 | Your Cart:
2 |
3 |
4 |
5 |
6 | Item |
7 | Qty |
8 | Price |
9 |
10 |
11 |
12 |
13 | {{product.name}} |
14 | {{product.quantity}} |
15 | {{product.pricing.formatted.without_tax}} |
16 |
17 |
18 |
19 |
20 | Total Price: {{cart.totals.formatted.with_tax}}
21 |
22 | Checkout!
23 |
--------------------------------------------------------------------------------
/app/views/category.html:
--------------------------------------------------------------------------------
1 | {{ category.title }}
2 |
3 |
11 |
--------------------------------------------------------------------------------
/app/views/checkout.html:
--------------------------------------------------------------------------------
1 | Checkout
2 |
3 |
103 |
--------------------------------------------------------------------------------
/app/views/complete.html:
--------------------------------------------------------------------------------
1 | Thanks for your order!!!
2 |
--------------------------------------------------------------------------------
/app/views/main.html:
--------------------------------------------------------------------------------
1 |
2 |
Storefront
3 |
4 | Put something awesome here...or this could be the /store view.
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/views/payment.html:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
10 |
Billing Address
11 |
12 | - {{ order.bill_to.data.first_name }} {{ order.bill_to.data.last_name }}
13 | - {{ order.bill_to.data.company }}
14 | - {{ order.bill_to.data.address_1 }}
15 | - {{ order.bill_to.data.address_2 }}
16 | - {{ order.bill_to.data.county }}
17 | - {{ order.bill_to.data.postcode }}
18 | - {{ order.bill_to.data.country.value }}
19 |
20 |
21 |
22 |
23 |
24 |
Shipping Address
25 |
26 | - {{ order.ship_to.data.first_name }} {{ order.ship_to.data.last_name }}
27 | - {{ order.ship_to.data.company }}
28 | - {{ order.ship_to.data.address_1 }}
29 | - {{ order.ship_to.data.address_2 }}
30 | - {{ order.ship_to.data.county }}
31 | - {{ order.ship_to.data.postcode }}
32 | - {{ order.ship_to.data.country.value }}
33 |
34 |
35 |
36 |
67 |
68 |
--------------------------------------------------------------------------------
/app/views/product.html:
--------------------------------------------------------------------------------
1 | {{ product.title }}
2 |
3 |
4 |
9 |
10 |
{{ product.pricing.formatted.without_tax }}
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/app/views/store.html:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
Featured Items
11 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "storefront",
3 | "version": "0.0.0",
4 | "dependencies": {
5 | "angular": "^1.3.0",
6 | "bootstrap-sass-official": "^3.2.0",
7 | "angular-animate": "^1.3.0",
8 | "angular-cookies": "^1.3.0",
9 | "angular-resource": "^1.3.0",
10 | "angular-route": "^1.3.0",
11 | "angular-sanitize": "^1.3.0",
12 | "angular-touch": "^1.3.0"
13 | },
14 | "devDependencies": {
15 | "angular-mocks": "^1.3.0"
16 | },
17 | "appPath": "app",
18 | "moduleName": "storefrontApp"
19 | }
20 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "storefront",
3 | "version": "0.0.0",
4 | "dependencies": {},
5 | "repository": {},
6 | "devDependencies": {
7 | "grunt": "^0.4.5",
8 | "grunt-autoprefixer": "^2.0.0",
9 | "grunt-concurrent": "^1.0.0",
10 | "grunt-contrib-clean": "^0.6.0",
11 | "grunt-contrib-compass": "^1.0.0",
12 | "grunt-contrib-concat": "^0.5.0",
13 | "grunt-contrib-connect": "^0.9.0",
14 | "grunt-contrib-copy": "^0.7.0",
15 | "grunt-contrib-cssmin": "^0.12.0",
16 | "grunt-contrib-htmlmin": "^0.4.0",
17 | "grunt-contrib-imagemin": "^0.9.2",
18 | "grunt-contrib-jshint": "^0.11.0",
19 | "grunt-contrib-uglify": "^0.7.0",
20 | "grunt-contrib-watch": "^0.6.1",
21 | "grunt-filerev": "^2.1.2",
22 | "grunt-google-cdn": "^0.4.3",
23 | "grunt-newer": "^1.1.0",
24 | "grunt-ng-annotate": "^0.9.2",
25 | "grunt-svgmin": "^2.0.0",
26 | "grunt-usemin": "^3.0.0",
27 | "grunt-wiredep": "^2.0.0",
28 | "jshint-stylish": "^1.0.0",
29 | "load-grunt-tasks": "^3.1.0",
30 | "time-grunt": "^1.0.0"
31 | },
32 | "engines": {
33 | "node": ">=0.10.0"
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/test/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "node": true,
3 | "browser": true,
4 | "esnext": true,
5 | "bitwise": true,
6 | "camelcase": true,
7 | "curly": true,
8 | "eqeqeq": true,
9 | "immed": true,
10 | "indent": 2,
11 | "latedef": true,
12 | "newcap": true,
13 | "noarg": true,
14 | "quotmark": "single",
15 | "regexp": true,
16 | "undef": true,
17 | "unused": true,
18 | "strict": true,
19 | "trailing": true,
20 | "smarttabs": true,
21 | "jasmine": true,
22 | "globals": {
23 | "angular": false,
24 | "browser": false,
25 | "inject": false
26 | }
27 | }
28 |
29 |
--------------------------------------------------------------------------------
/test/spec/controllers/cart.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | describe('Controller: CartCtrl', function () {
4 |
5 | // load the controller's module
6 | beforeEach(module('storefrontApp'));
7 |
8 | var CartCtrl,
9 | scope;
10 |
11 | // Initialize the controller and a mock scope
12 | beforeEach(inject(function ($controller, $rootScope) {
13 | scope = $rootScope.$new();
14 | CartCtrl = $controller('CartCtrl', {
15 | $scope: scope
16 | });
17 | }));
18 |
19 | it('should attach a list of awesomeThings to the scope', function () {
20 | expect(scope.awesomeThings.length).toBe(3);
21 | });
22 | });
23 |
--------------------------------------------------------------------------------
/test/spec/controllers/category.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | describe('Controller: CategoryCtrl', function () {
4 |
5 | // load the controller's module
6 | beforeEach(module('storefrontApp'));
7 |
8 | var CategoryCtrl,
9 | scope;
10 |
11 | // Initialize the controller and a mock scope
12 | beforeEach(inject(function ($controller, $rootScope) {
13 | scope = $rootScope.$new();
14 | CategoryCtrl = $controller('CategoryCtrl', {
15 | $scope: scope
16 | });
17 | }));
18 |
19 | it('should attach a list of awesomeThings to the scope', function () {
20 | expect(scope.awesomeThings.length).toBe(3);
21 | });
22 | });
23 |
--------------------------------------------------------------------------------
/test/spec/controllers/checkout.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | describe('Controller: CheckoutCtrl', function () {
4 |
5 | // load the controller's module
6 | beforeEach(module('storefrontApp'));
7 |
8 | var CheckoutCtrl,
9 | scope;
10 |
11 | // Initialize the controller and a mock scope
12 | beforeEach(inject(function ($controller, $rootScope) {
13 | scope = $rootScope.$new();
14 | CheckoutCtrl = $controller('CheckoutCtrl', {
15 | $scope: scope
16 | });
17 | }));
18 |
19 | it('should attach a list of awesomeThings to the scope', function () {
20 | expect(scope.awesomeThings.length).toBe(3);
21 | });
22 | });
23 |
--------------------------------------------------------------------------------
/test/spec/controllers/complete.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | describe('Controller: CompleteCtrl', function () {
4 |
5 | // load the controller's module
6 | beforeEach(module('storefrontApp'));
7 |
8 | var CompleteCtrl,
9 | scope;
10 |
11 | // Initialize the controller and a mock scope
12 | beforeEach(inject(function ($controller, $rootScope) {
13 | scope = $rootScope.$new();
14 | CompleteCtrl = $controller('CompleteCtrl', {
15 | $scope: scope
16 | });
17 | }));
18 |
19 | it('should attach a list of awesomeThings to the scope', function () {
20 | expect(scope.awesomeThings.length).toBe(3);
21 | });
22 | });
23 |
--------------------------------------------------------------------------------
/test/spec/controllers/main.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | describe('Controller: MainCtrl', function () {
4 |
5 | // load the controller's module
6 | beforeEach(module('storefrontApp'));
7 |
8 | var MainCtrl,
9 | scope;
10 |
11 | // Initialize the controller and a mock scope
12 | beforeEach(inject(function ($controller, $rootScope) {
13 | scope = $rootScope.$new();
14 | MainCtrl = $controller('MainCtrl', {
15 | $scope: scope
16 | });
17 | }));
18 |
19 | it('should attach a list of awesomeThings to the scope', function () {
20 | expect(scope.awesomeThings.length).toBe(3);
21 | });
22 | });
23 |
--------------------------------------------------------------------------------
/test/spec/controllers/payment.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | describe('Controller: PaymentCtrl', function () {
4 |
5 | // load the controller's module
6 | beforeEach(module('storefrontApp'));
7 |
8 | var PaymentCtrl,
9 | scope;
10 |
11 | // Initialize the controller and a mock scope
12 | beforeEach(inject(function ($controller, $rootScope) {
13 | scope = $rootScope.$new();
14 | PaymentCtrl = $controller('PaymentCtrl', {
15 | $scope: scope
16 | });
17 | }));
18 |
19 | it('should attach a list of awesomeThings to the scope', function () {
20 | expect(scope.awesomeThings.length).toBe(3);
21 | });
22 | });
23 |
--------------------------------------------------------------------------------
/test/spec/controllers/product.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | describe('Controller: ProductCtrl', function () {
4 |
5 | // load the controller's module
6 | beforeEach(module('storefrontApp'));
7 |
8 | var ProductCtrl,
9 | scope;
10 |
11 | // Initialize the controller and a mock scope
12 | beforeEach(inject(function ($controller, $rootScope) {
13 | scope = $rootScope.$new();
14 | ProductCtrl = $controller('ProductCtrl', {
15 | $scope: scope
16 | });
17 | }));
18 |
19 | it('should attach a list of awesomeThings to the scope', function () {
20 | expect(scope.awesomeThings.length).toBe(3);
21 | });
22 | });
23 |
--------------------------------------------------------------------------------
/test/spec/controllers/store.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | describe('Controller: StoreCtrl', function () {
4 |
5 | // load the controller's module
6 | beforeEach(module('storefrontApp'));
7 |
8 | var StoreCtrl,
9 | scope;
10 |
11 | // Initialize the controller and a mock scope
12 | beforeEach(inject(function ($controller, $rootScope) {
13 | scope = $rootScope.$new();
14 | StoreCtrl = $controller('StoreCtrl', {
15 | $scope: scope
16 | });
17 | }));
18 |
19 | it('should attach a list of awesomeThings to the scope', function () {
20 | expect(scope.awesomeThings.length).toBe(3);
21 | });
22 | });
23 |
--------------------------------------------------------------------------------