├── .gitignore
├── README.md
├── app
├── Backend
│ ├── RestApis
│ │ ├── SampleAPI.js
│ │ └── _all.js
│ └── server.js
├── Frontend
│ ├── app.js
│ ├── favicon.ico
│ ├── images
│ │ └── logo
│ │ │ ├── logo_iot_bzh.svg
│ │ │ ├── logo_iot_bzhx350.png
│ │ │ ├── tampon-iot-bzhx450.png
│ │ │ ├── triskel_iot_bzh.png
│ │ │ ├── triskel_iot_bzh.svg
│ │ │ └── triskel_iot_bzhx250.png
│ ├── index.html
│ ├── pages
│ │ ├── ajax
│ │ │ ├── ajax.html
│ │ │ ├── ajax.js
│ │ │ └── ajax.scss
│ │ ├── home
│ │ │ ├── home.html
│ │ │ └── homeModule.js
│ │ └── sample
│ │ │ ├── sample.html
│ │ │ └── sampleModule.js
│ ├── styles
│ │ ├── _settings.scss
│ │ ├── app.scss
│ │ └── globalapp.scss
│ ├── tmp
│ │ └── routes.js
│ └── widgets
│ │ ├── widgetA
│ │ ├── widgetA.html
│ │ ├── widgetA.js
│ │ └── widgetA.scss
│ │ └── widgetB
│ │ ├── widgetB.html
│ │ └── widgetB.js
└── etc
│ ├── AppDefaults.js
│ ├── _Config.js
│ └── _Debug.js
├── bower.json
├── gulpfile.js
├── nbproject
├── project.properties
└── project.xml
└── package.json
/.gitignore:
--------------------------------------------------------------------------------
1 | /.idea
2 | /bower_components
3 | /node_modules
4 | /dist.*
5 | *.DS_Store
6 | /nbproject/private/
7 | npm-debug.log
8 | .sass-cache/
9 | .noderc*
10 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Angular/Foundation6 best practices template: fork from http://paislee.io/a-healthy-gulp-setup-for-angularjs-projects
2 |
3 | ### Modifications from original version
4 | + support for Fondation-6 for App http://foundation.zurb.com/apps/docs/#!/
5 | + support for NodeJS V4+V5
6 | + sample based on a components somehow similar to what Angular-2 should use
7 | + support development and production mode [javascript html partial templates are loaded in the right order where ever they are within dev tree]
8 | + support node debugger in development mode [tested with Netbeans 8.1, but should work with any]
9 |
10 | ### Installation
11 |
12 | 0. Install Node.js
13 | 1. Download/Install healthy-gulp-angular-foundation6 from https://github.com/iotbzh/healthy-gulp-angular-foundation6
14 | 2. npm install
15 | 3. npm run start
16 | Optional: Chrome/LiveReload (https://chrome.google.com/webstore/detail/livereload/jnihajbhpnppcggbcgedagnkighmdlei)
17 |
18 | ### Using Gulp
19 | A. ./node_modules/.bin/gulp help
20 | B. ./node_modules/.bin/gulp watch-dev
21 | Note: if gulp is installed globally you may use directly "gulp help"
22 |
23 |
24 | ### customisation
25 | # Create a ".noderc.js" at project root to overload .app/etc/AppDefault.js
26 |
27 | var config= {
28 | APPNAME: "MyFirstApp" // replace @@APPNAME@@ in Index.html & app.js for dev/prod
29 | HOST : "localhost", // listen on a specific interface/IP [default==localhost]
30 | PORT : 8081, // httpd port [default 8080]
31 | DEBUG : 9081, // nodejs debug port in dev mode [comment to remove debug in devmod]
32 | URLBASE: '/' // URL base for rewriting should match with your http server application base [default/]
33 | };
34 | module.exports = config;
35 |
36 | ### Bugs
37 | + Check Angular & Angular-Animate get the exact same version otherwise you may get an error looking like " [$injector:unpr] Unknown provider: $$asyncCallbackProvider"
38 | + Gulp watch modification only on existing files. Adding a new file will not be detected. User should restart Gulp watch command
39 | + In some case automatic update notification to browser fail and page has to be reloaded manually
40 | + When using IDEs it's easy to have multiple GULP process watching the same thing!!! In case of doubt when having strange result 'pkill -9 gulp; pkill -9 node"
41 |
42 | ## Project Structure
43 | The project ships with a directory structure like:
44 |
45 | /MyProject
46 | |
47 | |-- gulpfile.js // Check 'gulp help' for options
48 | |-- package.json
49 | |-- bower.json
50 | |-- .noderc.js [Warning: contains private keys DO-NOT upload in Github]
51 | |
52 | |--- /app
53 | | |
54 | | |---etc
55 | | | |
56 | | | | AppDefault.js // Default config for Application
57 | | |
58 | | |---Backend [HTTPd server production/mock]
59 | | | |--- server.js // server bootstrap and options
60 | | | |--- /RestApi
61 | | | | | _all.js // API module registration
62 | | | | | SampleApi.js // As many API modules as needed
63 | | |
64 | | |---Frontend [Angular/Foundation HTML5 app]
65 | | | |--- index.html // index template should not need any changes
66 | | | |--- app.js // main entry point should register here every pages module
67 | | | |
68 | | | |--- /styles // your global SASS files and Foundation6 config
69 | | | | |--- _settings.scss
70 | | | | |---- app.scss
71 | | | |
72 | | | |--- /Widgets // Add as many widgets Directories/Files as needed
73 | | | | |--- Widget-1
74 | | | | |... Widget-xxx
75 | | | |
76 | | | |----/Pages // Partial Directory/Files as needed
77 | | | | |--- Home Partial
78 | | | | |--- Any Other Partials
79 | | | |
80 | | | |----/xxxx // Partial/Widget/Style may sit in as many directories as needed
81 | | |
82 | |
83 | |--- (/dist.dev) // received copy of JS/HTML during debug session
84 | |--- (/dist.prod // received compressed JS/HTML for production mode
85 |
86 | NOTE: By convention Directory/Files name starting by an Uppercase can be customised.
87 | Changing those ones starting by lowercase might break GULP config.
--------------------------------------------------------------------------------
/app/Backend/RestApis/SampleAPI.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Dummy API that return basic JSON objects
3 | */
4 |
5 | var config = require('../../etc/_Config');
6 |
7 | function RestAPI (app) {
8 | 'use strict';
9 |
10 | app.get('/api/get-date', function (req, res) {
11 | var now = new Date();
12 | if (req.session && !req.session.logged) res.send({type: 'error', app: config.APPNAME, data: 'No Session Cookie'});
13 | else {
14 | var date= now.getDate() + '/' + now.getMonth() +'/'+ now.getFullYear() ;
15 | res.send({type: 'date', data: date});
16 | }
17 | });
18 |
19 | app.get('/api/get-time', function (req, res) {
20 | if (req.session && !req.session.logged) res.send({type: 'error', app: config.APPNAME, data: 'No Session Cookie'});
21 | else {
22 | var time= new Date().toTimeString().replace(/.*(\d{2}:\d{2}:\d{2}).*/, "$1");
23 | res.send({type: 'time', data: time});
24 | }
25 | });
26 |
27 | }
28 |
29 | module.exports = RestAPI;
--------------------------------------------------------------------------------
/app/Backend/RestApis/_all.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 "IoT.bzh"
3 | * Author "Fulup Ar Foll"
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see
15 |
Note: To Check error handling "Stop" your httpd server and click on any button
20 | 21 | 25 | -------------------------------------------------------------------------------- /app/Frontend/pages/ajax/ajax.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This sample module implement two directives with a share templates. 3 | * 4 | * Note: 5 | * - while both directives are within the same module each owns a private scope. 6 | * - depending on where you place static date they are share or not 7 | */ 8 | 9 | (function() { 10 | 'use strict'; 11 | 12 | // simple template can be store directly inside a static variable 13 | var tmpl = ' {{info}}: [{{data}}] Elapse:{{elapsed}}s'; 14 | 15 | // list all rependencies within the page + controler if needed 16 | angular.module('MyAjaxModule', []) 17 | 18 | .directive('serverTime', function($http, $timeout) { 19 | 20 | 21 | function private_methods(scope, elem, attrs) { 22 | 23 | // initial scope at instanciation 24 | scope.data = "Click For Time"; 25 | scope.status = "FX"; 26 | scope.info = attrs.info; 27 | scope.counter = 0; 28 | scope.elapsed = 0; 29 | scope.rate = 250; // increase timer every 250ms 30 | 31 | // method call when user click on element 32 | scope.clicked = function () { 33 | 34 | // send AJAX request to server 35 | var handler = $http.get('/api/get-time'); 36 | 37 | handler.success(function(response, errcode, headers, config) { 38 | 39 | // check if response is valid 40 | if (response.type !== "time") { 41 | alert ("Hoops [server restarted] :" + response.data); 42 | return; 43 | } 44 | 45 | scope.data = response.data; 46 | scope.status = "OK"; 47 | scope.counter= 0; 48 | }); 49 | 50 | handler.error(function(status, errcode, headers) { 51 | console.log ("Hoops /api/get-time failed err=" + errcode); 52 | scope.data = "Server not Responding"; 53 | scope.status = "FX"; 54 | }); 55 | }; 56 | 57 | scope.count = function() { 58 | scope.counter ++; 59 | scope.elapsed = (scope.counter * scope.rate / 1000).toFixed(2); 60 | $timeout (scope.count, scope.rate); 61 | 62 | // when date too old change color 63 | if (scope.counter > 25) scope.status = "FX"; 64 | }; 65 | 66 | // init counter timeout 67 | $timeout (scope.count, scope.rate); 68 | 69 | } // end link 70 | 71 | return { 72 | restrict: 'E', 73 | template: tmpl, 74 | link: private_methods, 75 | scope: {} // 100% Private Scope 76 | }; 77 | }) 78 | 79 | .directive('serverDate', function($http, $timeout) { 80 | 81 | 82 | function private_methods(scope, elem, attrs) { 83 | 84 | // initial scope at instanciation 85 | scope.data = "Click For Time"; 86 | scope.status = "FX"; 87 | scope.info = attrs.info; 88 | scope.counter = 0; 89 | scope.elapsed = 0; 90 | scope.rate = 1000; // count every second 91 | 92 | // method call when user click on element 93 | scope.clicked = function () { 94 | 95 | // send AJAX request to server 96 | var handler = $http.get('/api/get-date'); 97 | 98 | handler.success(function(response, errcode, headers, config) { 99 | 100 | // check if response is valid 101 | if (response.type !== "date") { 102 | alert ("Hoops [server restarted] : " + response.data); 103 | return; 104 | } 105 | 106 | scope.data = response.data; 107 | scope.status = "OK"; 108 | scope.counter= 0; 109 | }); 110 | 111 | handler.error(function(status, errcode, headers) { 112 | console.log ("Hoops /api/get-date failed err=" + errcode); 113 | scope.data = "Server not Responding"; 114 | scope.status = "FX"; 115 | }); 116 | }; 117 | 118 | scope.count = function() { 119 | scope.counter ++; 120 | scope.elapsed = (scope.counter * scope.rate / 1000).toFixed(2); 121 | $timeout (scope.count, scope.rate); 122 | 123 | // when date too old change color 124 | if (scope.counter > 15) scope.status = "FX"; 125 | }; 126 | 127 | // init counter timeout 128 | $timeout (scope.count, scope.rate); 129 | 130 | } // end link 131 | 132 | return { 133 | restrict: 'E', 134 | template: tmpl, 135 | link: private_methods, 136 | scope: {} // 100% Private Scope 137 | }; 138 | }); 139 | 140 | console.log ("RestSampleModule Loaded"); 141 | })(); -------------------------------------------------------------------------------- /app/Frontend/pages/ajax/ajax.scss: -------------------------------------------------------------------------------- 1 | /* 2 | Sample of style overload for a specific widget 3 | 4 | Note: this SCSS is injected with main HTML page, it scope should be reduce 5 | to a specific widget or it value will be propagated at a global level. 6 | */ 7 | 8 | @mixin server-button { 9 | display: block; 10 | margin: 1rem; 11 | box-shadow: 5px 5px 2px #656565; 12 | } 13 | 14 | server-date, server-time { 15 | 16 | .OK { 17 | @include server-button; 18 | color: #191970; 19 | border: 2px solid blue !important; 20 | padding:15px 50px 15px 50px;margin:0 0 5px 5px; 21 | 22 | background-color: rgba(150, 200, 50,0.7); 23 | } 24 | .OK:hover{background-color:greenyellow;} 25 | 26 | .FX { 27 | @include server-button; 28 | color: #191970; 29 | border: 2px solid red !important; 30 | padding:15px 50px 15px 50px;margin:0 0 5px 5px; 31 | background-color: rgba(255, 165, 0,0.7); 32 | } 33 | .FX:hover{background-color:red;} 34 | } 35 | -------------------------------------------------------------------------------- /app/Frontend/pages/home/home.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | --- 4 | name: myhome 5 | url: /home 6 | animationIn: slideInLeft 7 | animationOut: slideOutRight 8 | controller: MyHomeController 9 | --- 10 | 11 |
15 |
20 |
Sample Page
21 |
Ajax Sample
22 |
15 |
20 |
Home Page
21 |
Ajax Sample
22 |
tags
187 | // $code-color: grayscale($primary-color);
188 | // $code-font-family: Consolas, 'Liberation Mono', Courier, monospace;
189 | // $code-font-weight: $font-weight-normal;
190 | // $code-background-color: scale-color($secondary-color, $lightness: 70%);
191 | // $code-border-size: 1px;
192 | // $code-border-style: solid;
193 | // $code-border-color: scale-color($code-background-color, $lightness: -10%);
194 | // $code-padding: rem-calc(2) rem-calc(5) rem-calc(1);
195 |
196 | // We use these to style anchors
197 | // $anchor-text-decoration: none;
198 | // $anchor-text-decoration-hover: none;
199 | // $anchor-font-color: $primary-color;
200 | // $anchor-font-color-hover: scale-color($anchor-font-color, $lightness: -14%);
201 |
202 | // We use these to style the
element
203 | // $hr-border-width: 1px;
204 | // $hr-border-style: solid;
205 | // $hr-border-color: #ddd;
206 | // $hr-margin: rem-calc(20);
207 |
208 | // We use these to style lists
209 | // $list-font-family: $paragraph-font-family;
210 | // $list-font-size: $paragraph-font-size;
211 | // $list-line-height: $paragraph-line-height;
212 | // $list-margin-bottom: $paragraph-margin-bottom;
213 | // $list-style-position: outside;
214 | // $list-side-margin: 1.1rem;
215 | // $list-ordered-side-margin: 1.4rem;
216 | // $list-side-margin-no-bullet: 0;
217 | // $list-nested-margin: rem-calc(20);
218 | // $definition-list-header-weight: $font-weight-bold;
219 | // $definition-list-header-margin-bottom: .3rem;
220 | // $definition-list-margin-bottom: rem-calc(12);
221 |
222 | // We use these to style blockquotes
223 | // $blockquote-font-color: scale-color($header-font-color, $lightness: 35%);
224 | // $blockquote-padding: rem-calc(9 20 0 19);
225 | // $blockquote-border: 1px solid #ddd;
226 | // $blockquote-cite-font-size: rem-calc(13);
227 | // $blockquote-cite-font-color: scale-color($header-font-color, $lightness: 23%);
228 | // $blockquote-cite-link-color: $blockquote-cite-font-color;
229 |
230 | // Acronym styles
231 | // $acronym-underline: 1px dotted #ddd;
232 |
233 | // 5. Grid
234 | // - - - - - - - - - - - - - - -
235 |
236 | // $container-width: rem-calc(900);
237 | // $block-padding: $global-padding;
238 | // $total-columns: 12;
239 | // $block-grid-max-size: 6;
240 |
241 | // 6. Button
242 | // - - - - - - - - - - - - - - -
243 |
244 | // $button-padding: 0.85em 1em;
245 | // $button-margin: 0 $global-padding $global-padding 0;
246 | // $button-style: solid;
247 | // $button-background: $primary-color;
248 | // $button-color: auto;
249 | // $button-radius: 0;
250 | // $button-sizes: (
251 | // tiny: 0.7,
252 | // small: 0.8,
253 | // medium: 1,
254 | // large: 1.3,
255 | // );
256 | // $button-font-size: 0.9rem;
257 | // $button-opacity-disabled: 0.5;
258 | // $button-tag-selector: false;
259 |
260 | // 7. Accordion
261 | // - - - - - - - - - - - - - - -
262 |
263 | // $accordion-border: 1px solid $gray-dark;
264 |
265 | // $accordion-title-background: $gray-light;
266 | // $accordion-title-background-hover: smartscale($accordion-title-background, 5%);
267 | // $accordion-title-background-active: smartscale($accordion-title-background, 3%);
268 | // $accordion-title-color: isitlight($accordion-title-background);
269 | // $accordion-title-color-active: isitlight($accordion-title-background);
270 |
271 | // $accordion-title-padding: $global-padding;
272 | // $accordion-content-padding: $global-padding;
273 |
274 | // 8. Action Sheet
275 | // - - - - - - - - - - - - - - -
276 |
277 | // $actionsheet-background: white;
278 | // $actionsheet-border-color: #ccc;
279 | // $actionsheet-animate: transform opacity;
280 | // $actionsheet-animation-speed: 0.25s;
281 | // $actionsheet-width: 300px;
282 | // $actionsheet-radius: 4px;
283 | // $actionsheet-shadow: 0 -3px 10px rgba(black, 0.25);
284 | // $actionsheet-padding: $global-padding;
285 | // $actionsheet-tail-size: 10px;
286 |
287 | // $actionsheet-popup-shadow: 0 0 10px rgba(black, 0.25);
288 |
289 | // $actionsheet-link-color: #000;
290 | // $actionsheet-link-background-hover: smartscale($actionsheet-background);
291 |
292 | // 9. Block List
293 | // - - - - - - - - - - - - - - -
294 |
295 | // $blocklist-background: #fff;
296 | // $blocklist-fullbleed: true;
297 | // $blocklist-fontsize: 1rem;
298 |
299 | // $blocklist-item-padding: 0.8rem 1rem;
300 | // $blocklist-item-color: isitlight($blocklist-background, #000, #fff);
301 | // $blocklist-item-background-hover: smartscale($blocklist-background, 4.5%);
302 | // $blocklist-item-color-disabled: #999;
303 | // $blocklist-item-border: 1px solid smartscale($blocklist-background, 18.5%);
304 |
305 | // $blocklist-item-label-color: scale-color($blocklist-item-color, $lightness: 60%);
306 | // $blocklist-item-icon-size: 0.8;
307 |
308 | // $blocklist-header-fontsize: 0.8em;
309 | // $blocklist-header-color: smartscale($blocklist-item-color, 40%);
310 | // $blocklist-header-uppercase: true;
311 |
312 | // $blocklist-check-icons: true;
313 |
314 | // 10. Button Group
315 | // - - - - - - - - - - - - - - -
316 |
317 | // $btngroup-background: $primary-color;
318 | // $btngroup-color: #fff;
319 | // $btngroup-radius: $button-radius;
320 |
321 | // 11. Card
322 | // - - - - - - - - - - - - - - -
323 |
324 | // $card-background: #fff;
325 | // $card-color: isitlight($card-background);
326 | // $card-border: 1px solid smartscale($card-background, 7%);
327 | // $card-radius: $global-radius;
328 | // $card-shadow: 0 1px 2px rgba(#000, 0.2);
329 | // $card-padding: $global-padding;
330 | // $card-margin: 0.5rem;
331 |
332 | // $card-divider-background: smartscale($card-background, 7%);
333 |
334 | // 12. Extras
335 | // - - - - - - - - - - - - - - -
336 |
337 | // $closebutton-position: (top right);
338 | // $closebutton-size: 2em;
339 | // $closebutton-lineheight: 0.5;
340 | // $closebutton-color: #999;
341 | // $closebutton-color-hover: #333;
342 |
343 | // $thumbnail-padding: 0.5rem;
344 | // $thumbnail-shadow: 0 3px 15px rgba(black, 0.25);
345 |
346 | // 13. Forms
347 | // - - - - - - - - - - - - - - -
348 |
349 | // Basic form variables
350 | // $form-fontsize: 1rem;
351 | // $form-padding: 0.5rem;
352 |
353 | // Text fields
354 | // $input-color: #000;
355 | // $input-color-hover: $input-color;
356 | // $input-color-focus: $input-color;
357 | // $input-background: #fff;
358 | // $input-background-hover: $input-background;
359 | // $input-background-focus: $input-background;
360 | // $input-border: 1px solid #ccc;
361 | // $input-border-hover: 1px solid #bbb;
362 | // $input-border-focus: 1px solid #999;
363 |
364 | // Select menus
365 | // $select-color: #000;
366 | // $select-background: #fafafa;
367 | // $select-background-hover: smartscale($select-background, 4%);
368 | // $select-arrow: true;
369 | // $select-arrow-color: $select-color;
370 |
371 | // Labels
372 | // $form-label-fontsize: 0.9rem;
373 | // $form-label-margin: 0.5rem;
374 | // $form-label-color: #333;
375 |
376 | // Inline labels
377 | // $inlinelabel-color: #333;
378 | // $inlinelabel-background: #eee;
379 | // $inlinelabel-border: $input-border;
380 |
381 | // Range slider
382 | // $slider-background: #ddd;
383 | // $slider-height: 1rem;
384 | // $slider-radius: 0px;
385 | // $slider-thumb-height: 1.5rem;
386 | // $slider-thumb-color: $primary-color;
387 | // $slider-thumb-radius: 0px;
388 |
389 | // Progress and meter
390 | // $meter-height: 1.5rem;
391 | // $meter-background: #ccc;
392 | // $meter-fill: $primary-color;
393 | // $meter-fill-high: $success-color;
394 | // $meter-fill-medium: #e7cf00;
395 | // $meter-fill-low: $alert-color;
396 | // $meter-radius: 0;
397 |
398 | // 14. Iconic
399 | // - - - - - - - - - - - - - - -
400 |
401 | // $iconic-primary-fill: $primary-color;
402 | // $iconic-primary-stroke: $primary-color;
403 | // $iconic-accent-fill: $iconic-primary-fill;
404 | // $iconic-accent-stroke: $iconic-accent-fill;
405 |
406 | // 15. Label
407 | // - - - - - - - - - - - - - - -
408 |
409 | // $label-fontsize: 0.8rem;
410 | // $label-padding: ($global-padding / 3) ($global-padding / 2);
411 | // $label-radius: 0;
412 | // $label-background: $primary-color;
413 | // $label-color: isitlight($primary-color);
414 |
415 | // $badge-fontsize: 0.8em;
416 | // $badge-diameter: 1.5rem;
417 | // $badge-background: $primary-color;
418 | // $badge-color: #fff;
419 |
420 | // DEPRECATED: these variables will be removed in v1.1.
421 | // $badge-padding: .1em .61em;
422 | // $badge-radius: $global-rounded;
423 | // $badge-font-color: #fff;
424 |
425 | // 16. Menu Bar
426 | // - - - - - - - - - - - - - - -
427 |
428 | // $menubar-fontsize: 1rem;
429 | // $menubar-background: #fff;
430 | // $menubar-background-hover: smartscale($menubar-background, 7%);
431 | // $menubar-background-active: $menubar-background-hover;
432 | // $menubar-color: isitlight($menubar-background);
433 | // $menubar-color-hover: $menubar-color;
434 | // $menubar-color-active: $menubar-color-hover;
435 |
436 | // $menubar-item-padding: $global-padding;
437 | // $menubar-icon-size: 25px;
438 | // $menubar-icon-spacing: $menubar-item-padding;
439 |
440 | // 17. Modal
441 | // - - - - - - - - - - - - - - -
442 |
443 | // $modal-background: #fff;
444 | // $modal-border: 0;
445 | // $modal-radius: 0px;
446 | // $modal-shadow: none;
447 | // $modal-zindex: 1000;
448 | // $modal-sizes: (
449 | // tiny: 300px,
450 | // small: 500px,
451 | // medium: 600px,
452 | // large: 800px,
453 | // );
454 |
455 | // $modal-overlay-class: 'modal-overlay';
456 | // $modal-overlay-background: rgba(#333, 0.7);
457 |
458 | // 18. Motion UI
459 | // - - - - - - - - - - - - - - -
460 |
461 | // Classes to use when triggering in/out animations
462 | // $motion-class: (
463 | // in: "ng-enter",
464 | // out: "ng-leave",
465 | // );
466 | // $motion-class-active: (
467 | // in: "ng-enter-active",
468 | // out: "ng-leave-active",
469 | // );
470 | // $motion-class-stagger: (
471 | // in: "ng-enter-stagger",
472 | // out: "ng-leave-stagger",
473 | // );
474 |
475 | // Set if movement-based transitions should also fade the element in and out
476 | // $motion-slide-and-fade: false;
477 | // $motion-hinge-and-fade: true;
478 | // $motion-scale-and-fade: true;
479 | // $motion-spin-and-fade: true;
480 |
481 | // Default speed for transitions and animations
482 | // $motion-duration-default: 500ms;
483 | // Slow and fast modifiders
484 | // $motion-duration-slow: 750ms;
485 | // $motion-duration-fast: 250ms;
486 | // $motion-stagger-duration-default: 150ms;
487 | // $motion-stagger-duration-short: 50ms;
488 | // $motion-stagger-duration-long: 300ms;
489 |
490 | // Default timing function for transitions and animations
491 | // $motion-timing-default: ease;
492 | // Built-in and custom easing functions
493 | // Every item in this map becomes a CSS class
494 | // $motion-timings: (
495 | // linear: linear,
496 | // ease: ease,
497 | // easeIn: ease-in,
498 | // easeOut: ease-out,
499 | // easeInOut: ease-in-out,
500 | // bounceIn: cubic-bezier(0.485, 0.155, 0.240, 1.245),
501 | // bounceOut: cubic-bezier(0.485, 0.155, 0.515, 0.845),
502 | // bounceInOut: cubic-bezier(0.760, -0.245, 0.240, 1.245),
503 | // );
504 |
505 | // Default delay for all transitions and animations
506 | // $motion-delay-default: 0;
507 | // Short and long delay modifiers
508 | // $motion-delay-short: 300ms;
509 | // $motion-delay-long: 700ms;
510 |
511 | // 19. Notification
512 | // - - - - - - - - - - - - - - -
513 |
514 | // $notification-default-position: right top;
515 | // $notification-width: rem-calc(400);
516 | // $notification-offset: $global-padding;
517 |
518 | // $notification-background: $primary-color;
519 | // $notification-color: white;
520 | // $notification-padding: $global-padding;
521 | // $notification-radius: 4px;
522 |
523 | // $notification-icon-size: 60px;
524 | // $notification-icon-margin: $global-padding;
525 | // $notification-icon-align: top;
526 |
527 |
528 | // 20. Off-canvas
529 | // - - - - - - - - - - - - - - -
530 |
531 | // $offcanvas-size-horizontal: 250px;
532 | // $offcanvas-size-vertical: 250px;
533 |
534 | // $offcanvas-background: #fff;
535 | // $offcanvas-color: isitlight($offcanvas-background);
536 | // $offcanvas-padding: 0;
537 | // $offcanvas-shadow: 3px 0 10px rgba(black, 0.25);
538 | // $offcanvas-animation-speed: 0.25s;
539 |
540 | // $offcanvas-frame-selector: '.grid-frame';
541 |
542 | // 21. Panel
543 | // - - - - - - - - - - - - - - -
544 |
545 | // $panel-size-horizontal: 300px;
546 | // $panel-size-vertical: 300px;
547 | // $panel-padding: 0;
548 |
549 | // $panel-background: #fff;
550 | // $panel-shadow: 3px 0 10px rgba(black, 0.25);
551 | // $panel-animation-speed: 0.25s;
552 |
553 | // 22. Popup
554 | // - - - - - - - - - - - - - - -
555 |
556 | // $popup-width: rem-calc(300);
557 | // $popup-background: #fff;
558 | // $popup-border: 0;
559 | // $popup-radius: 0;
560 | // $popup-shadow: 0 0 10px rgba(#000, 0.25);
561 |
562 | // 23. Switch
563 | // - - - - - - - - - - - - - - -
564 |
565 | // $switch-width: rem-calc(50);
566 | // $switch-height: rem-calc(32);
567 | // $switch-background: #ccc;
568 | // $switch-background-active: $primary-color;
569 | // $switch-border: 0;
570 | // $switch-radius: 9999px;
571 | // $switch-animation-speed: 0.15s;
572 |
573 | // $switch-paddle-color: white;
574 | // $switch-paddle-offset: 4px;
575 |
576 | // 24. Tabs
577 | // - - - - - - - - - - - - - - -
578 |
579 | // $tabstrip-background: transparent;
580 |
581 | // $tab-title-background: $gray-light;
582 | // $tab-title-background-hover: smartscale($tab-title-background, 5%);
583 | // $tab-title-background-active: smartscale($tab-title-background, 3%);
584 | // $tab-title-color: isitlight($tab-title-background);
585 | // $tab-title-color-active: $tab-title-color;
586 |
587 | // $tab-title-padding: $global-padding;
588 | // $tab-content-padding: $global-padding;
589 |
590 | // 25. Title Bar
591 | // - - - - - - - - - - - - - - -
592 |
593 | // $titlebar-center-width: 50%;
594 | // $titlebar-side-width: (100% - $titlebar-center-width) / 2;
595 | // $titlebar-background: #eee;
596 | // $titlebar-color: #000;
597 | // $titlebar-border: 1px solid #ccc;
598 | // $titlebar-padding: $global-padding;
599 | // $titlebar-item-classes: (
600 | // center: 'center',
601 | // left: 'left',
602 | // right: 'right',
603 | // title: 'title',
604 | // );
605 |
--------------------------------------------------------------------------------
/app/Frontend/styles/app.scss:
--------------------------------------------------------------------------------
1 | @import "settings";
2 | @import "foundation";
3 |
--------------------------------------------------------------------------------
/app/Frontend/styles/globalapp.scss:
--------------------------------------------------------------------------------
1 | /*
2 | Every SCSS files will be injected into main HTML page
3 | */
4 |
5 | .status-ok {
6 | color: #191970;
7 | border: 2px solid greenyellow !important;
8 | padding:15px 50px 15px 50px;margin:0 0 5px 5px;
9 | box-shadow: 5px 5px 2px #656565;
10 | background-color: rgba(20, 205, 50,0.7);
11 | }
12 | .status-ok:hover{background-color:greenyellow;}
13 |
14 | .status-fx {
15 | color: #191970;
16 | border: 2px solid violet !important;
17 | padding:15px 50px 15px 50px;margin:0 0 5px 5px;
18 | box-shadow: 5px 5px 2px #656565;
19 | background-color: rgba(180, 50, 50,0.7);
20 | }
21 | .status-fx:hover{background-color:#696969;}
22 |
23 |
--------------------------------------------------------------------------------
/app/Frontend/tmp/routes.js:
--------------------------------------------------------------------------------
1 | var foundationRoutes = [{"name":"mysample","url":"/sample","animationIn":"slideInRight","path":"pages/sample/sample.html"},{"name":"myhome","url":"/home","animationIn":"slideInLeft","animationOut":"slideOutRight","controller":"MyHomeController","path":"pages/home/home.html"},{"name":"ajaxsample","url":"/ajax","animationIn":"slideInUp","path":"pages/ajax/ajax.html"}];
2 |
--------------------------------------------------------------------------------
/app/Frontend/widgets/widgetA/widgetA.html:
--------------------------------------------------------------------------------
1 | Widget-AA [{{value}}]
--------------------------------------------------------------------------------
/app/Frontend/widgets/widgetA/widgetA.js:
--------------------------------------------------------------------------------
1 |
2 | /*
3 | * This model force class change simply by updating a variable within the
4 | * private scope of the directive. Might not be the prefered model to change
5 | * a class, but it a simple way to demonstrate how a template can interact with
6 | * javascript.
7 | *
8 | * Note: widgetA uses a private widgetA.scss style.
9 | */
10 |
11 | (function() {
12 | 'use strict';
13 |
14 | angular.module('WidgetA',[])
15 |
16 | .directive('widgetA', function() {
17 | function mymethods(scope, elem, attrs) {
18 |
19 | scope.value="OFF";
20 |
21 | scope.clicked = function () {
22 | if (scope.value === "ON") {
23 | scope.value = "OFF";
24 | } else {
25 | scope.value = "ON";
26 | }
27 | console.log ("Clicked WidgetA value=" + scope.value);
28 | };
29 |
30 | }
31 |
32 | return {
33 | restrict: 'E',
34 | templateUrl: 'widgets/widgetA/widgetA.html',
35 | link: mymethods,
36 | scope: {}
37 | };
38 | });
39 |
40 | console.log ("widgetA Loaded");
41 | })();
42 |
--------------------------------------------------------------------------------
/app/Frontend/widgets/widgetA/widgetA.scss:
--------------------------------------------------------------------------------
1 | /*
2 | Sample of style overload for a specific widget
3 |
4 | Note: this SCSS is injected with main HTML page, it scope should be reduce
5 | to a specific widget or it value will be propagated at a global level.
6 | */
7 |
8 | widget-a {
9 | .status-ON {
10 | color: #191970;
11 | border: 2px solid blue !important;
12 | padding:15px 50px 15px 50px;margin:0 0 5px 5px;
13 | box-shadow: 5px 5px 2px #656565;
14 | background-color: rgba(150, 200, 50,0.7);
15 | }
16 | .status-ON:hover{background-color:greenyellow;}
17 |
18 | .status-OFF {
19 | color: #191970;
20 | border: 2px solid red !important;
21 | padding:15px 50px 15px 50px;margin:0 0 5px 5px;
22 | box-shadow: 5px 5px 2px #656565;
23 | background-color: rgba(200, 10, 10,0.7);
24 | }
25 | .status-OFF:hover{background-color:red;}
26 | }
27 |
--------------------------------------------------------------------------------
/app/Frontend/widgets/widgetB/widgetB.html:
--------------------------------------------------------------------------------
1 | Widget-B [ON]
--------------------------------------------------------------------------------
/app/Frontend/widgets/widgetB/widgetB.js:
--------------------------------------------------------------------------------
1 |
2 | /*
3 | * Change class through Angular Add/Remove class methods.
4 | * Note that Element point onto HTML tag element and that searching
5 | * in the widget for the right element is necessary. This search can
6 | * use tag,id,class,...
7 | *
8 | * We may search for the element only once at initialisation time and keep
9 | * the reference within the private scope of the directive.
10 | *
11 | * Note: widgetB uses globalapp.scss style.
12 | */
13 |
14 | (function() {
15 | 'use strict';
16 |
17 | angular.module('WidgetB',[])
18 |
19 | .directive('widgetB', function() {
20 | function mymethods(scope, elem, attrs) {
21 |
22 | scope.button = elem.children('span');
23 | console.log (scope.button);
24 |
25 | scope.clicked = function () {
26 | if (scope.button.hasClass ("status-ok")) {
27 | console.log ("Clicked WidgetB value=FX" );
28 | scope.button.removeClass("status-ok");
29 | scope.button.addClass("status-fx");
30 | scope.button.text("Widget-B [OFF]");
31 | } else {
32 | console.log ("Clicked WidgetB value=OK" );
33 | scope.button.removeClass("status-fx");
34 | scope.button.addClass("status-ok");
35 | scope.button.text("Widget-B [ON]");
36 | }
37 | };
38 | }
39 |
40 | return {
41 | restrict: 'E',
42 | templateUrl: 'widgets/widgetB/widgetB.html',
43 | link: mymethods,
44 | scope: {
45 | initvalues : '='
46 | }
47 | };
48 | });
49 |
50 | console.log ("widgetB Loaded");
51 | })();
--------------------------------------------------------------------------------
/app/etc/AppDefaults.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 "IoT.bzh"
3 | * Author "Fulup Ar Foll"
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | // Default config will be superseaded by ProjectRoot/.config-l4a.js $HOME/.config-l4a.js /etc/default/config-l4a.js
20 | config = {
21 | APPNAME : 'MySampleApp', // AppName is use as main Angular Module name
22 | HOST : 'localhost', // HTTP will only listen on related Internet interface
23 | PORT : 8080, // HTTP port
24 | URLBASE : '/', // HTML basedir when running in production
25 | LOGDIR : __dirname + '/log', // httpd log file
26 | FRONTEND: "Frontend", // HTML5 frontend [WARNING: no leading './']
27 | BACKEND : "Backend", // NodeJS Rest API [WARNING: no leading './']
28 | SECRET : Math.random().toString(36).slice(2) // [default cookie session]
29 | };
30 |
31 | module.exports = config;
32 |
33 |
--------------------------------------------------------------------------------
/app/etc/_Config.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Fulup Ar Foll
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | var fs = require('fs');
18 |
19 | function Config () {
20 | 'use strict';
21 | var values=[];
22 | var extention='-myapp.js';
23 | var conf;
24 |
25 | // Configs file path last one supersead first one.
26 | var files= [__dirname + "/AppDefaults.js", "/etc/default/noderc"+ extention, process.env.NODERC, process.env.HOME + "/.noderc"+ extention , __dirname +"/../../.noderc.js" ];
27 |
28 | // Parse any existing files within config list & merge them
29 | for (var idx in files) {
30 | if (files[idx]) {
31 | if (fs.existsSync (files[idx])) conf=require (files[idx]);
32 | for (var i in conf) values[i] = conf[i];
33 | }
34 | }
35 | // console.log ("values=", values);
36 | return values;
37 | }
38 |
39 | module.exports = Config();
40 |
--------------------------------------------------------------------------------
/app/etc/_Debug.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Fulup Ar Foll
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | var traceback = require('traceback'); // https://www.npmjs.org/package/traceback
18 | var util = require("util");
19 |
20 | // ------- Public Methods --------------
21 | var Debug = function(level, format) { //+ arguments
22 |
23 | if (this.debug >= level ) {
24 |
25 | var args = [].slice.call(arguments, 1); // copy argument in a real array leaving out level
26 | var message = util.format.apply(null, args);
27 |
28 | try {
29 | var trace = traceback()[1]; // get trace up to previous calling function
30 | if (this.debug > 5) console.log("-%d- %s/%s:%d [%s]", level, trace.file, trace.name, trace.line, message);
31 | else console.log("-- %s [%s] -- %j", level, trace.name, message);
32 | } catch (e) {
33 | console.log("-- %s [%s] -- %j", level, 'no trace', message);
34 | }
35 | }
36 | };
37 |
38 | module.exports = Debug;
39 |
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "healthy-gulp-angular",
3 | "version": "0.0.0",
4 | "authors": "",
5 | "private": true,
6 | "dependencies": {
7 | "foundation-apps": "~1.1.0"
8 | },
9 |
10 | "overrides": {
11 | "foundation": {
12 | "main": [
13 |
14 | ]
15 | }
16 | }
17 | }
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 |
2 |
3 | var gulp = require('gulp');
4 | var plugins = require('gulp-load-plugins')();
5 | var del = require('del');
6 | var es = require('event-stream');
7 | var bowerFiles = require('main-bower-files');
8 | var print = require('gulp-print');
9 | var Q = require('q');
10 | var imagemin = require('gulp-imagemin'), pngquant = require('imagemin-pngquant');
11 | var taskListing = require('gulp-task-listing');
12 |
13 | // addon for Foundation6
14 | var router = require('front-router');
15 |
16 | // == PATH STRINGS ========
17 | var appdir = "./app/"; // Warning to not forget trailling '/'
18 | config=require (appdir + "etc/_Config"); // upload user local preferences if any
19 |
20 | // Run node in debug mode in developpement mode ?
21 | var nodeopts = config.DEBUG !== undefined ? '--debug='+config.DEBUG : '';
22 | var frontend= appdir + config.FRONTEND;
23 | var backend = appdir + config.BACKEND;
24 |
25 | var paths = {
26 | application: frontend,
27 | scripts : frontend+'/**/*.js',
28 | styles : [frontend+'/**/*.css', frontend+'/**/*.scss'],
29 | images : [frontend+'/**/*.ico',frontend+'/**/*.png',frontend+'/**/*.jpg',frontend+'/**/*.jpeg',frontend+'/**/*.svg',frontend+'/**/*.ttf'],
30 | index : frontend+'/index.html',
31 | partials : [frontend + '/**/*.html', '!' + frontend +'/index.html'],
32 | distDev : './dist.dev',
33 | distProd : './dist.prod',
34 | distScriptsProd: './dist.prod/scripts',
35 | scriptsDevServer: backend + '/**/*.js',
36 | sass: ['bower_components/foundation-apps/scss']
37 | };
38 |
39 | // Run node in debug mode in developpement mode ?
40 | var nodeopts = config.DEBUG !== undefined ? '--debug='+config.DEBUG : '';
41 |
42 | // == PIPE SEGMENTS ========
43 | var pipes = {};
44 |
45 | pipes.orderedVendorScripts = function() {
46 | return plugins.order(['jquery.js', 'angular.js']);
47 | };
48 |
49 | pipes.orderedAppScripts = function() {
50 | return plugins.angularFilesort();
51 | };
52 |
53 | pipes.minifiedFileName = function() {
54 | return plugins.rename(function (path) {
55 | path.extname = '.min' + path.extname;
56 | });
57 | };
58 |
59 | pipes.validatedAppScripts = function() {
60 | return gulp.src(paths.scripts)
61 | .pipe(plugins.replace('@@APPNAME@@', config.APPNAME))
62 | .pipe(plugins.jshint())
63 | .pipe(plugins.jshint.reporter('jshint-stylish'));
64 | };
65 |
66 | pipes.builtAppScriptsDev = function() {
67 | return pipes.validatedAppScripts()
68 | .pipe(gulp.dest(paths.distDev));
69 | };
70 |
71 | pipes.builtAppScriptsProd = function() {
72 | var scriptedPartials = pipes.scriptedPartials();
73 | var validatedAppScripts = pipes.validatedAppScripts();
74 |
75 | return es.merge(scriptedPartials, validatedAppScripts)
76 | .pipe(plugins.ngAnnotate())
77 | .pipe(pipes.orderedAppScripts())
78 | .pipe(plugins.sourcemaps.init())
79 | .pipe(plugins.concat('app.min.js'))
80 | .pipe(plugins.uglify({compress: {drop_console: true}}))
81 | .pipe(plugins.sourcemaps.write())
82 | .pipe(gulp.dest(paths.distScriptsProd));
83 | };
84 |
85 | pipes.builtVendorScriptsDev = function() {
86 | return gulp.src(bowerFiles())
87 | .pipe(gulp.dest('dist.dev/bower_components'));
88 | };
89 |
90 | pipes.builtVendorScriptsProd = function() {
91 | return gulp.src(bowerFiles('**/*.js'))
92 | .pipe(pipes.orderedVendorScripts())
93 | .pipe(plugins.concat('vendor.min.js'))
94 | .pipe(plugins.uglify())
95 | .pipe(gulp.dest(paths.distScriptsProd));
96 | };
97 |
98 | pipes.validatedDevServerScripts = function() {
99 | return gulp.src(paths.scriptsDevServer)
100 | .pipe(plugins.jshint())
101 | .pipe(plugins.jshint.reporter('jshint-stylish'));
102 | };
103 |
104 | pipes.validatedPartials = function() {
105 | return gulp.src(paths.partials)
106 | .pipe(plugins.htmlhint({'doctype-first': false}))
107 | .pipe(router({path: paths.application+'/tmp/routes.js', root: paths.application}))
108 | .pipe(plugins.htmlhint.reporter());
109 | };
110 |
111 | pipes.builtPartialsDev = function() {
112 | return pipes.validatedPartials()
113 | .pipe(gulp.dest(paths.distDev));
114 | };
115 |
116 | pipes.scriptedPartials = function() {
117 | return pipes.validatedPartials()
118 | .pipe(plugins.htmlhint.failReporter())
119 | .pipe(plugins.htmlmin({collapseWhitespace: true, removeComments: true}))
120 | .pipe(plugins.ngHtml2js({
121 | moduleName: config.APPNAME,
122 | template: "(function() {"
123 | + "angular.module('<%= moduleName %>').run(['$templateCache', function($templateCache) {"
124 | + "$templateCache.put('<%= template.url %>',\n '<%= template.escapedContent %>');"
125 | + "}]);\n"
126 | + "})();\n"
127 | }));
128 | };
129 |
130 | pipes.builtStylesDev = function() {
131 | return gulp.src(paths.styles)
132 | .pipe(plugins.sass({includePaths: paths.sass}))
133 | .pipe(gulp.dest(paths.distDev));
134 | };
135 |
136 | pipes.builtStylesProd = function() {
137 | return gulp.src(paths.styles)
138 | .pipe(plugins.sourcemaps.init())
139 | .pipe(plugins.sass({includePaths: paths.sass}))
140 | .pipe(plugins.minifyCss())
141 | .pipe(plugins.sourcemaps.write())
142 | .pipe(pipes.minifiedFileName())
143 | .pipe(gulp.dest(paths.distProd));
144 | };
145 |
146 | pipes.processedImagesDev = function() {
147 | return gulp.src(paths.images)
148 | .pipe(gulp.dest(paths.distDev));
149 | };
150 |
151 | pipes.processedImagesProd = function() {
152 | return gulp.src(paths.images)
153 | .pipe(imagemin({
154 | progressive: true,
155 | svgoPlugins: [{removeViewBox: false}],
156 | use: [pngquant()]
157 | }))
158 | .pipe(gulp.dest(paths.distProd));
159 | };
160 |
161 | pipes.validatedIndex = function() {
162 | return gulp.src(paths.index)
163 | .pipe(plugins.replace('@@APPNAME@@', config.APPNAME))
164 | .pipe(plugins.replace('@@URLBASE@@', config.URLBASE))
165 | .pipe(plugins.htmlhint())
166 | .pipe(plugins.htmlhint.reporter());
167 | };
168 |
169 | pipes.builtIndexDev = function() {
170 |
171 | var orderedVendorScripts = pipes.builtVendorScriptsDev()
172 | .pipe(pipes.orderedVendorScripts());
173 |
174 | var orderedAppScripts = pipes.builtAppScriptsDev()
175 | .pipe(pipes.orderedAppScripts());
176 |
177 | var appStyles = pipes.builtStylesDev();
178 |
179 | return pipes.validatedIndex()
180 | .pipe(gulp.dest(paths.distDev)) // write first to get relative path for inject
181 | .pipe(plugins.inject(orderedVendorScripts, {relative: true, name: 'bower'}))
182 | .pipe(plugins.inject(orderedAppScripts, {relative: true}))
183 | .pipe(plugins.inject(appStyles, {relative: true}))
184 | .pipe(gulp.dest(paths.distDev));
185 | };
186 |
187 | pipes.builtIndexProd = function() {
188 |
189 | var vendorScripts = pipes.builtVendorScriptsProd();
190 | var appScripts = pipes.builtAppScriptsProd();
191 | var appStyles = pipes.builtStylesProd();
192 |
193 | return pipes.validatedIndex()
194 | .pipe(gulp.dest(paths.distProd)) // write first to get relative path for inject
195 | .pipe(plugins.inject(vendorScripts, {relative: true, name: 'bower'}))
196 | .pipe(plugins.inject(appScripts, {relative: true}))
197 | .pipe(plugins.inject(appStyles, {relative: true}))
198 | .pipe(plugins.htmlmin({collapseWhitespace: true, removeComments: true}))
199 | .pipe(gulp.dest(paths.distProd));
200 | };
201 |
202 | pipes.builtAppDev = function() {
203 | return es.merge(pipes.builtIndexDev(), pipes.builtPartialsDev(), pipes.processedImagesDev());
204 | };
205 |
206 | pipes.builtAppProd = function() {
207 | return es.merge(pipes.builtIndexProd(), pipes.processedImagesProd());
208 | };
209 |
210 |
211 | // == TASKS ========
212 |
213 | // Add a task to render the output
214 | gulp.task('help', taskListing.withFilters(/-/));
215 |
216 | // clean, build of production environement
217 | gulp.task('build', ['clean-build-app-prod', 'validate-devserver-scripts']);
218 |
219 | gulp.task('run', function() {
220 | // start nodemon to auto-reload the dev server
221 | plugins.nodemon({ script: 'server.js', ext: 'js', watch: ['devServer/']})
222 | .on('change', ['validate-devserver-scripts'])
223 | .on('restart', function () {
224 | console.log('[nodemon] restarted dev server');
225 | });
226 | });
227 |
228 | // removes all compiled dev files
229 | gulp.task('clean-dev', function() {
230 | var deferred = Q.defer();
231 | del(paths.distDev, function() {
232 | deferred.resolve();
233 | });
234 | return deferred.promise;
235 | });
236 |
237 | // removes all compiled production files
238 | gulp.task('clean-prod', function() {
239 | var deferred = Q.defer();
240 | del(paths.distProd, function() {
241 | deferred.resolve();
242 | });
243 | return deferred.promise;
244 | });
245 |
246 | // checks html source files for syntax errors
247 | gulp.task('validate-partials', pipes.validatedPartials);
248 |
249 | // checks index.html for syntax errors
250 | gulp.task('validate-index', pipes.validatedIndex);
251 |
252 | // moves html source files into the dev environment
253 | gulp.task('build-partials-dev', pipes.builtPartialsDev);
254 |
255 | // converts partials to javascript using html2js
256 | gulp.task('convert-partials-to-js', pipes.scriptedPartials);
257 |
258 | // runs jshint on the dev server scripts
259 | gulp.task('validate-devserver-scripts', pipes.validatedDevServerScripts);
260 |
261 | // runs jshint on the app scripts
262 | gulp.task('validate-app-scripts', pipes.validatedAppScripts);
263 |
264 | // moves app scripts into the dev environment
265 | gulp.task('build-app-scripts-dev', pipes.builtAppScriptsDev);
266 |
267 | // concatenates, uglifies, and moves app scripts and partials into the prod environment
268 | gulp.task('build-app-scripts-prod', pipes.builtAppScriptsProd);
269 |
270 | // compiles app sass and moves to the dev environment
271 | gulp.task('build-styles-dev', pipes.builtStylesDev);
272 |
273 | // compiles and minifies app sass to css and moves to the prod environment
274 | gulp.task('build-styles-prod', pipes.builtStylesProd);
275 |
276 | // moves vendor scripts into the dev environment
277 | gulp.task('build-vendor-scripts-dev', pipes.builtVendorScriptsDev);
278 |
279 | // concatenates, uglifies, and moves vendor scripts into the prod environment
280 | gulp.task('build-vendor-scripts-prod', pipes.builtVendorScriptsProd);
281 |
282 | // validates and injects sources into index.html and moves it to the dev environment
283 | gulp.task('build-index-dev', pipes.builtIndexDev);
284 |
285 | // validates and injects sources into index.html, minifies and moves it to the dev environment
286 | gulp.task('build-index-prod', pipes.builtIndexProd);
287 |
288 | // builds a complete dev environment
289 | gulp.task('build-app-dev', pipes.builtAppDev);
290 |
291 | // builds a complete prod environment
292 | gulp.task('build-app-prod', pipes.builtAppProd);
293 |
294 | // cleans and builds a complete dev environment
295 | gulp.task('clean-build-app-dev', ['clean-dev'], pipes.builtAppDev);
296 |
297 | // cleans and builds a complete prod environment
298 | gulp.task('clean-build-app-prod', ['clean-prod'], pipes.builtAppProd);
299 |
300 | // clean, build, and watch live changes to the dev environment
301 | gulp.task('watch-dev', ['clean-build-app-dev', 'validate-devserver-scripts'], function() {
302 |
303 | // start nodemon to auto-reload the dev server
304 | plugins.nodemon({ exec: 'node ' + nodeopts, script: backend+'/server.js', ext: 'js', watch: [backend], env: {NODE_ENV : 'dev'} })
305 | .on('change', ['validate-devserver-scripts'])
306 | .on('restart', function () {
307 | console.log('[nodemon] restarted dev server');
308 | });
309 |
310 | // start live-reload server
311 | plugins.livereload.listen({ start: true });
312 |
313 | // watch index
314 | gulp.watch(paths.index, function() {
315 | return pipes.builtIndexDev()
316 | .pipe(plugins.livereload());
317 | });
318 |
319 | // watch app scripts
320 | gulp.watch(paths.scripts, function() {
321 | return pipes.builtAppScriptsDev()
322 | .pipe(plugins.livereload());
323 | });
324 |
325 | // watch html partials
326 | gulp.watch(paths.partials, function() {
327 | return pipes.builtPartialsDev()
328 | .pipe(plugins.livereload());
329 | });
330 |
331 | // watch Images
332 | gulp.watch(paths.images, function() {
333 | return pipes.processedImagesDev()
334 | .pipe(plugins.livereload());
335 | });
336 |
337 | // watch styles
338 | gulp.watch(paths.styles, function() {
339 | return pipes.builtStylesDev()
340 | .pipe(plugins.livereload());
341 | });
342 |
343 | });
344 |
345 | // clean, build, and watch live changes to the prod environment
346 | gulp.task('watch-prod', ['clean-build-app-prod', 'validate-devserver-scripts'], function() {
347 |
348 | // start nodemon to auto-reload the dev server
349 | plugins.nodemon({ script: backend +'/server.js', ext: 'js', watch: [backend], env: {MODE : 'prod'} })
350 | .on('change', ['validate-devserver-scripts'])
351 | .on('restart', function () {
352 | console.log('[nodemon] restarted dev server');
353 | });
354 |
355 | // start live-reload server
356 | plugins.livereload.listen({start: true});
357 |
358 | // watch index
359 | gulp.watch(paths.index, function() {
360 | return pipes.builtIndexProd()
361 | .pipe(plugins.livereload());
362 | });
363 |
364 | // watch app scripts
365 | gulp.watch(paths.scripts, function() {
366 | return pipes.builtAppScriptsProd()
367 | .pipe(plugins.livereload());
368 | });
369 |
370 | // watch hhtml partials
371 | gulp.watch(paths.partials, function() {
372 | return pipes.builtAppScriptsProd()
373 | .pipe(plugins.livereload());
374 | });
375 |
376 | // watch Images
377 | gulp.watch(paths.images, function() {
378 | return pipes.processedImagesProd()
379 | .pipe(plugins.livereload());
380 | });
381 |
382 | // watch styles
383 | gulp.watch(paths.styles, function() {
384 | return pipes.builtStylesProd()
385 | .pipe(plugins.livereload());
386 | });
387 |
388 | });
389 |
390 | // default task builds for prod
391 | gulp.task('default', ['clean-build-app-prod']);
392 |
--------------------------------------------------------------------------------
/nbproject/project.properties:
--------------------------------------------------------------------------------
1 | auxiliary.org-netbeans-modules-css-prep.sass_2e_configured=true
2 | file.reference.healthy-gulp-angular-foundation6-app=app
3 | file.reference.healthy-gulp-angular-foundation6-Frontend=Frontend
4 | files.encoding=UTF-8
5 | site.root.folder=${file.reference.healthy-gulp-angular-foundation6-Frontend}
6 | source.folder=
7 |
--------------------------------------------------------------------------------
/nbproject/project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | org.netbeans.modules.web.clientproject
4 |
5 |
6 | healthy-gulp-angular-foundation6
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "healthy-gulp-angular",
3 | "private": true,
4 | "version": "0.0.0",
5 | "repository": {
6 | "type": "git",
7 | "url": "https://github.com/iotbzh/healthy-gulp-angular-foundation6"
8 | },
9 | "scripts": {
10 | "postinstall": "bower install",
11 | "build": "./node_modules/.bin/gulp clean-build-app-dev",
12 | "start": "./node_modules/.bin/gulp watch-dev"
13 | },
14 | "devDependencies": {
15 | "body-parser": "^1.5.2",
16 | "bower": "^1.3.1",
17 | "cookie-parser": "^1.4.0",
18 | "del": "^1.1.1",
19 | "event-stream": "^3.2.2",
20 | "express": "^4.7.2",
21 | "express-session": "^1.12.1",
22 | "front-router": "^1.0.0",
23 | "gulp": "^3.9.0",
24 | "gulp-angular-filesort": "^1.0.4",
25 | "gulp-concat": "^2.4.3",
26 | "gulp-htmlhint": "0.0.9",
27 | "gulp-htmlmin": "^1.0.0",
28 | "gulp-imagemin": "*",
29 | "gulp-inject": "^1.1.1",
30 | "gulp-jshint": "^1.9.2",
31 | "gulp-livereload": "^3.7.0",
32 | "gulp-load-plugins": "^0.8.0",
33 | "gulp-minify-css": "^0.4.5",
34 | "gulp-ng-annotate": "^1.1.0",
35 | "gulp-ng-html2js": "^0.2.0",
36 | "gulp-nodemon": "^2.0.0",
37 | "gulp-order": "^1.1.1",
38 | "gulp-print": "^1.1.0",
39 | "gulp-rename": "^1.2.0",
40 | "gulp-replace": "^0.5.4",
41 | "gulp-sass": "^2.0.3",
42 | "gulp-sourcemaps": "^1.3.0",
43 | "gulp-task-listing": "^1.0.1",
44 | "gulp-uglify": "^1.2.0",
45 | "imagemin-pngquant": "*",
46 | "jshint-stylish": "^1.0.0",
47 | "karma": "^0.10",
48 | "karma-junit-reporter": "^0.2.2",
49 | "main-bower-files": "^2.5.0",
50 | "method-override": "^2.1.2",
51 | "protractor": "^1.1.1",
52 | "q": "^1.1.2",
53 | "shelljs": "^0.2.6"
54 | }
55 | }
56 |
--------------------------------------------------------------------------------