├── express-angular ├── email-templates │ ├── auth-create-reset │ │ ├── text.ejs │ │ └── html.ejs │ └── auth-register │ │ ├── text.ejs │ │ └── html.ejs ├── .gitignore ├── README.md ├── public │ ├── bower.json │ ├── account │ │ ├── projects.html │ │ ├── index.html │ │ └── mvp-account.js │ ├── css │ │ ├── mvp.css │ │ └── animate.css │ ├── js │ │ ├── angular-route.1.2.0.rc2.min.js │ │ ├── cookies.js │ │ └── mvp-public.js │ └── index.html ├── LICENSE ├── package.json ├── options.example.js └── mvp-app.js ├── hapi-angular ├── email-templates │ ├── auth-create-reset │ │ ├── text.ejs │ │ └── html.ejs │ └── auth-register │ │ ├── text.ejs │ │ └── html.ejs ├── .gitignore ├── README.md ├── public │ ├── bower.json │ ├── account │ │ ├── projects.html │ │ ├── index.html │ │ └── mvp-account.js │ ├── css │ │ └── mvp.css │ ├── js │ │ ├── angular-route.1.2.0.rc2.min.js │ │ ├── cookies.js │ │ └── mvp-public.js │ └── index.html ├── LICENSE ├── package.json ├── options.example.js └── mvp-app.js ├── README.md └── docs └── screenshots.js /express-angular/email-templates/auth-create-reset/text.ejs: -------------------------------------------------------------------------------- 1 | Hello <%=name%>! 2 | 3 | To reset your password, please visit 4 | <%=resetlink%> 5 | 6 | regards, 7 | Seneca 8 | -------------------------------------------------------------------------------- /hapi-angular/email-templates/auth-create-reset/text.ejs: -------------------------------------------------------------------------------- 1 | Hello <%=name%>! 2 | 3 | To reset your password, please visit 4 | <%=resetlink%> 5 | 6 | regards, 7 | Seneca 8 | -------------------------------------------------------------------------------- /express-angular/.gitignore: -------------------------------------------------------------------------------- 1 | lib-cov 2 | *.seed 3 | *.log 4 | *.csv 5 | *.dat 6 | *.out 7 | *.pid 8 | *.gz 9 | 10 | pids 11 | logs 12 | results 13 | 14 | npm-debug.log 15 | 16 | *~ 17 | node_modules 18 | bower_components 19 | 20 | options.mine.js 21 | -------------------------------------------------------------------------------- /hapi-angular/.gitignore: -------------------------------------------------------------------------------- 1 | lib-cov 2 | *.seed 3 | *.log 4 | *.csv 5 | *.dat 6 | *.out 7 | *.pid 8 | *.gz 9 | 10 | pids 11 | logs 12 | results 13 | 14 | npm-debug.log 15 | 16 | *~ 17 | node_modules 18 | bower_components 19 | 20 | options.mine.js 21 | -------------------------------------------------------------------------------- /express-angular/email-templates/auth-register/text.ejs: -------------------------------------------------------------------------------- 1 | Hello <%=name%>! 2 | 3 | Thanks for registering! 4 | 5 | <% if( confirmcode ) { %> 6 | Please confirm your registration by visiting 7 | <%=confirmlink%> 8 | <% } %> 9 | 10 | regards, 11 | Seneca 12 | -------------------------------------------------------------------------------- /hapi-angular/email-templates/auth-register/text.ejs: -------------------------------------------------------------------------------- 1 | Hello <%=name%>! 2 | 3 | Thanks for registering! 4 | 5 | <% if( confirmcode ) { %> 6 | Please confirm your registration by visiting 7 | <%=confirmlink%> 8 | <% } %> 9 | 10 | regards, 11 | Seneca 12 | -------------------------------------------------------------------------------- /express-angular/email-templates/auth-create-reset/html.ejs: -------------------------------------------------------------------------------- 1 | 2 |

3 | Hello <%=name%>! 4 |

5 | 6 |

7 | To reset your password, please visit 8 | <%=resetlink%> 9 |

10 | 11 |

12 | regards,
13 | Seneca 14 |

15 | -------------------------------------------------------------------------------- /hapi-angular/email-templates/auth-create-reset/html.ejs: -------------------------------------------------------------------------------- 1 | 2 |

3 | Hello <%=name%>! 4 |

5 | 6 |

7 | To reset your password, please visit 8 | <%=resetlink%> 9 |

10 | 11 |

12 | regards,
13 | Seneca 14 |

15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | seneca-mvp 2 | ========== 3 | 4 | How to build a Minimim Viable Product with Seneca 5 | 6 | ## Setup 7 | 8 | There are two project examples, each in its sub-folder: 9 | - Hapi server, Chairo & seneca-auth & Angular 10 | - Express server, seneca-web & seneca-auth & Angular 11 | 12 | Please check corresponding Readme file for details. 13 | -------------------------------------------------------------------------------- /hapi-angular/email-templates/auth-register/html.ejs: -------------------------------------------------------------------------------- 1 | 2 |

3 | Hello <%=name%>! 4 |

5 | 6 |

7 | Thanks for registering! 8 |

9 | 10 | <% if( confirmcode ) { %> 11 |

12 | Please confirm your registration by visiting 13 | <%=confirmlink%> 14 |

15 | <% } %> 16 | 17 |

18 | regards,
19 | Seneca 20 |

21 | -------------------------------------------------------------------------------- /express-angular/email-templates/auth-register/html.ejs: -------------------------------------------------------------------------------- 1 | 2 |

3 | Hello <%=name%>! 4 |

5 | 6 |

7 | Thanks for registering! 8 |

9 | 10 | <% if( confirmcode ) { %> 11 |

12 | Please confirm your registration by visiting 13 | <%=confirmlink%> 14 |

15 | <% } %> 16 | 17 |

18 | regards,
19 | Seneca 20 |

21 | -------------------------------------------------------------------------------- /hapi-angular/README.md: -------------------------------------------------------------------------------- 1 | seneca-mvp 2 | ========== 3 | 4 | How to build a Minimim Viable Product with Seneca & Hapi 5 | 6 | ## Setup 7 | 8 | ```bash 9 | npm install 10 | ``` 11 | 12 | Copy options.example.js to options.mine.js and modify as needed. 13 | 14 | 15 | ## Run 16 | 17 | ```bash 18 | npm start 19 | ``` 20 | 21 | And open [localhost:3333](http://localhost:3333) 22 | 23 | 24 | -------------------------------------------------------------------------------- /express-angular/README.md: -------------------------------------------------------------------------------- 1 | seneca-mvp 2 | ========== 3 | 4 | How to build a Minimim Viable Product with Seneca & Express 5 | 6 | ## Setup 7 | 8 | ```bash 9 | npm install 10 | ``` 11 | 12 | Copy options.example.js to options.mine.js and modify as needed. 13 | 14 | 15 | ## Run 16 | 17 | ```bash 18 | npm start 19 | ``` 20 | 21 | And open [localhost:3333](http://localhost:3333) 22 | 23 | 24 | -------------------------------------------------------------------------------- /express-angular/public/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nodescale", 3 | "version": "0.0.0", 4 | "homepage": "https://github.com/rjrodger/seneca-mvp", 5 | "authors": [ 6 | "Richard Rodger " 7 | ], 8 | "license": "MIT", 9 | "private": true, 10 | "ignore": [ 11 | "**/.*", 12 | "node_modules", 13 | "bower_components", 14 | "test", 15 | "tests" 16 | ], 17 | "dependencies": { 18 | "bootstrap": "~3.2.0", 19 | "lodash": "^2.4.1", 20 | "jquery": "~2.1.1", 21 | "angular": "*" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /hapi-angular/public/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nodescale", 3 | "version": "0.0.0", 4 | "homepage": "https://github.com/rjrodger/seneca-mvp", 5 | "authors": [ 6 | "Richard Rodger " 7 | ], 8 | "license": "MIT", 9 | "private": true, 10 | "ignore": [ 11 | "**/.*", 12 | "node_modules", 13 | "bower_components", 14 | "test", 15 | "tests" 16 | ], 17 | "dependencies": { 18 | "bootstrap": "~3.2.0", 19 | "lodash": "^2.4.1", 20 | "jquery": "~2.1.1", 21 | "angular": "*" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /hapi-angular/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Richard Rodger 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /express-angular/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Richard Rodger 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /hapi-angular/public/account/projects.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 |

Projects

5 | 6 |
7 |
8 | 9 |
10 | 11 |
12 |
13 | 16 |
17 | 18 | 19 | 20 |

Project Details

21 | 22 |
23 |
24 | 25 |
26 | 27 | 28 |
29 |
30 | 31 | 32 |
33 | 34 | 35 | 36 | 37 | 40 |
41 | 42 | 43 |
44 | 45 | -------------------------------------------------------------------------------- /express-angular/public/account/projects.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 |

Projects

5 | 6 |
7 |
8 | 9 |
10 | 11 |
12 |
13 | 16 |
17 | 18 | 19 | 20 |

Project Details

21 | 22 |
23 |
24 | 25 |
26 | 27 | 28 |
29 |
30 | 31 | 32 |
33 | 34 | 35 | 36 | 37 | 40 |
41 | 42 | 43 |
44 | 45 | -------------------------------------------------------------------------------- /hapi-angular/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "seneca-mvp", 3 | "version": "0.2.0", 4 | "description": "How to build a Minimim Viable Product with Seneca", 5 | "main": "mvp-app.js", 6 | "scripts": { 7 | "preinstall": "cp -n options.example.js options.mine.js; true", 8 | "prestart": "cd public; bower install", 9 | "start": "node mvp-app.js", 10 | "test": "echo \"Error: no test specified\" && exit 1" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git://github.com/rjrodger/seneca-mvp.git" 15 | }, 16 | "author": { 17 | "name": "Richard Rodger", 18 | "email": "richard@ricebridge.com", 19 | "url": "http://richardrodger.com/" 20 | }, 21 | "contributors": [ 22 | { 23 | "name": "Mircea Alexandru", 24 | "email": "mircea.alexandru@gmail.com", 25 | "url": "https://github.com/mirceaalexandru" 26 | } 27 | ], 28 | "license": "MIT", 29 | "readmeFilename": "README.md", 30 | "dependencies": { 31 | "bell": "~6.1.0", 32 | "chairo": "~2.2.1", 33 | "hapi": "~13.0.0", 34 | "hapi-auth-cookie": "~5.0.0", 35 | "inert": "~3.0.0", 36 | "seneca": "~2.1.0", 37 | "seneca-account": "~0.1.8", 38 | "seneca-auth": "~1.1.0", 39 | "seneca-data-editor": "~0.2.0", 40 | "seneca-entity": "~1.2.0", 41 | "seneca-facebook-auth": "~0.1.0", 42 | "seneca-github-auth": "~0.1.1", 43 | "seneca-google-auth": "~1.0.0", 44 | "seneca-jsonrest-api": "~0.3.1", 45 | "seneca-local-auth": "~0.1.2", 46 | "seneca-mail": "~0.2.2", 47 | "seneca-perm": "~0.5.6", 48 | "seneca-project": "~0.1.6", 49 | "seneca-twitter-auth": "~0.1.1", 50 | "seneca-user": "~1.1.0" 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /express-angular/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "seneca-mvp", 3 | "version": "0.2.0", 4 | "description": "How to build a Minimim Viable Product with Seneca", 5 | "main": "mvp-app.js", 6 | "scripts": { 7 | "preinstall": "cp -n options.example.js options.mine.js; true", 8 | "prestart": "cd public; bower install", 9 | "start": "node mvp-app.js", 10 | "test": "echo \"Error: no test specified\" && exit 1" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git://github.com/rjrodger/seneca-mvp.git" 15 | }, 16 | "author": { 17 | "name": "Richard Rodger", 18 | "email": "richard@ricebridge.com", 19 | "url": "http://richardrodger.com/" 20 | }, 21 | "contributors": [ 22 | { 23 | "name": "Mircea Alexandru", 24 | "email": "mircea.alexandru@gmail.com", 25 | "url": "https://github.com/mirceaalexandru" 26 | } 27 | ], 28 | "license": "MIT", 29 | "readmeFilename": "README.md", 30 | "dependencies": { 31 | "body-parser": "~1.11.0", 32 | "cookie-parser": "~1.3.0", 33 | "express": "~4.11.0", 34 | "express-session": "~1.10.0", 35 | "seneca": "~2.1.0", 36 | "seneca-account": "~0.1.8", 37 | "seneca-admin": "~0.2.0", 38 | "seneca-auth": "~1.1.0", 39 | "seneca-data-editor": "~0.2.0", 40 | "seneca-entity": "~1.2.0", 41 | "seneca-facebook-auth": "~0.1.0", 42 | "seneca-github-auth": "~0.1.1", 43 | "seneca-google-auth": "~1.0.0", 44 | "seneca-jsonrest-api": "~0.3.1", 45 | "seneca-local-auth": "~0.1.2", 46 | "seneca-mail": "~0.2.2", 47 | "seneca-perm": "~0.5.6", 48 | "seneca-project": "~0.1.6", 49 | "seneca-settings": "~0.1.4", 50 | "seneca-twitter-auth": "~0.1.1", 51 | "seneca-user": "~1.1.0", 52 | "seneca-web": "~0.8.0" 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /docs/screenshots.js: -------------------------------------------------------------------------------- 1 | var casper = require('casper').create({ 2 | viewportSize : {width : 1200, height : 800}, 3 | verbose: true, 4 | logLevel: "debug" 5 | }); 6 | 7 | // TODO make helper function for taking screenshots which lists urls and file names in a JSON data file 8 | 9 | casper.start("http://localhost:3333/", function () { 10 | this.capture("not-logged-in.png"); 11 | }); 12 | 13 | casper.then(function() { 14 | this.fillSelectors('form', { 15 | 'input#email': 'u1@example.com', 16 | 'input#password': 'u1' 17 | }, false); 18 | this.capture("ready-to-log-in.png"); 19 | this.click("a[ng-click^=signin]"); 20 | this.waitForSelector("body.account"); 21 | }); 22 | 23 | casper.then(function() { 24 | this.capture("logged-in.png"); 25 | this.clickLabel("Settings", "a"); 26 | this.waitForSelector("table#seneca-settings"); 27 | }); 28 | 29 | // Wait longer so FontAwesome loads 30 | casper.wait(1000); 31 | 32 | casper.then(function() { 33 | this.capture("settings.png"); 34 | 35 | this.fillSelectors('form#seneca-settings-form', { 36 | 'input#setting-a' : 'foobar' 37 | }, false); 38 | 39 | this.click("#setting-l-star-6"); 40 | this.click("#setting-ll-star-2"); 41 | 42 | this.capture("filled-in.png"); 43 | this.clickLabel("Update Settings", "a"); 44 | }); 45 | 46 | casper.wait(1000); 47 | 48 | casper.then(function() { 49 | this.capture("updated.png"); 50 | }); 51 | 52 | function assert(truthy, falsemsg) { 53 | if (truthy) { 54 | console.log("assertion ok"); 55 | } else { 56 | console.log("fail: " + failmsg); 57 | throw (falsemsg || "FAIL"); 58 | } 59 | } 60 | 61 | casper.thenOpen("http://localhost:3333/settings/load?kind=user", function() { 62 | console.log(this.getPageContent()); 63 | var settingsInfo = JSON.parse(this.getPageContent()); 64 | assert(settingsInfo['settings']['a'] === 'foobar'); 65 | assert(settingsInfo['settings']['l'] === 6); 66 | assert(settingsInfo['settings']['ll'] === 2); 67 | }); 68 | 69 | /// "run" 70 | casper.run(); 71 | -------------------------------------------------------------------------------- /express-angular/options.example.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | module.exports = { 4 | 5 | main: { 6 | port:3333, 7 | public:'/public' 8 | }, 9 | 10 | auth: { 11 | redirect: { 12 | "login": { 13 | win: '/account', 14 | fail: '/', 15 | always: true 16 | } 17 | } 18 | }, 19 | "facebook" : { 20 | "appId" : "APP_ID", 21 | "appSecret" : "APP_SECRET", 22 | "urlhost" : "http://localhost:3333", 23 | "serviceParams": { 24 | "scope" : [ 25 | "email" 26 | ] 27 | } 28 | }, 29 | "google" : { 30 | "clientID" : "CLIENT_ID", 31 | "clientSecret" : "CLIENT_SECRET", 32 | "urlhost" : "http://localhost:3333" 33 | }, 34 | "github" : { 35 | "clientID" : "CLIENT_ID", 36 | "clientSecret" : "CLIENT_SECRET", 37 | "urlhost" : "http://localhost:3333" 38 | }, 39 | "twitter" : { 40 | "apiKey" : "APP_KEY", 41 | "apiSecret" : "API_SECRET", 42 | "urlhost" : "http://localhost:3333" 43 | }, 44 | mail: { 45 | mail: {from:'youremail@example.com'}, 46 | config:{ 47 | service: "Gmail", 48 | auth: { 49 | user: "youremail@example.com", 50 | pass: "yourpass" 51 | } 52 | } 53 | }, 54 | 55 | settings: { 56 | spec: { 57 | a:{"type":"text", "nice":"A", "help":"Example of text."}, 58 | b:{"type":"email", "nice":"B", "help":"Example of email."}, 59 | c:{"type":"tel", "nice":"C", "help":"Example of tel."}, 60 | d:{"type":"number", "nice":"D", "help":"Example of number."}, 61 | e:{"type":"time", "nice":"E", "help":"Example of time."}, 62 | f:{"type":"date", "nice":"F", "help":"Example of date."}, 63 | g:{"type":"datetime", "nice":"G", "help":"Example of datetime."}, 64 | h:{"type":"color", "nice":"H", "help":"Example of color."}, 65 | i:{"type":"url", "nice":"I", "help":"Example of url."}, 66 | j:{"type":"checkbox", "nice":"J", "help":"Example of checkbox."}, 67 | k:{"type":"range", "nice":"K", "help":"Example of range.", "default" : 50}, 68 | l:{"type":"rating", "nice":"L", "help":"Example of rating.", "stars" : 6 }, 69 | ll:{"type":"rating", "nice":"LL", "help":"Example of rating."}, 70 | m:{"type":"yesno", "nice":"M", "help":"Example of yesno."}, 71 | n:{"type":"onoff", "nice":"N", "help":"Example of onoff slider.", "default" : 0}, 72 | o:{"type":"buttons", "nice":"O", "help":"Example of buttons.", "options" : ["foo", "bar", "baz"]}, 73 | p:{"type":"dropdown", "nice":"P", "help":"Example of dropdown.", "options" : ["foo", "bar", "baz"]}, 74 | q:{"type":"dropdownplus", "nice":"Q", "help":"Example of dropdownplus.", "options" : ["foo", "bar", "baz"]}, 75 | r:{"type":"longtext", "nice":"R", "help":"Example of longtext."}, 76 | s:{"type":"radio", "nice":"S", "help":"Example of radio.", "options" : ["foo", "bar", "baz"]}, 77 | } 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /hapi-angular/options.example.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | module.exports = { 4 | 5 | main: { 6 | port:3333, 7 | public:'/public' 8 | }, 9 | 10 | auth: { 11 | restrict: ['/project', '/account'], 12 | redirect: { 13 | "login": { 14 | win: '/account', 15 | fail: '/', 16 | always: true 17 | } 18 | } 19 | }, 20 | "facebook-auth" : { 21 | "appId" : "APP_ID", 22 | "appSecret" : "APP_SECRET", 23 | "urlhost" : "http://localhost:3333", 24 | "isSecure": false, 25 | "serviceParams": { 26 | "scope" : [ 27 | "email" 28 | ] 29 | } 30 | }, 31 | "google-auth" : { 32 | "clientID" : "CLIENT_ID", 33 | "clientSecret" : "CLIENT_SECRET", 34 | "urlhost" : "http://localhost:3333", 35 | "isSecure": false 36 | }, 37 | "github-auth" : { 38 | "clientID" : "CLIENT_ID", 39 | "clientSecret" : "CLIENT_SECRET", 40 | "urlhost" : "http://localhost:3333", 41 | "isSecure": false 42 | }, 43 | "twitter-auth" : { 44 | "apiKey" : "APP_KEY", 45 | "apiSecret" : "API_SECRET", 46 | "urlhost" : "http://localhost:3333", 47 | "isSecure": false 48 | }, 49 | mail: { 50 | mail: {from:'youremail@example.com'}, 51 | config:{ 52 | service: "Gmail", 53 | auth: { 54 | user: "youremail@example.com", 55 | pass: "yourpass" 56 | } 57 | } 58 | }, 59 | 60 | settings: { 61 | spec: { 62 | a:{"type":"text", "nice":"A", "help":"Example of text."}, 63 | b:{"type":"email", "nice":"B", "help":"Example of email."}, 64 | c:{"type":"tel", "nice":"C", "help":"Example of tel."}, 65 | d:{"type":"number", "nice":"D", "help":"Example of number."}, 66 | e:{"type":"time", "nice":"E", "help":"Example of time."}, 67 | f:{"type":"date", "nice":"F", "help":"Example of date."}, 68 | g:{"type":"datetime", "nice":"G", "help":"Example of datetime."}, 69 | h:{"type":"color", "nice":"H", "help":"Example of color."}, 70 | i:{"type":"url", "nice":"I", "help":"Example of url."}, 71 | j:{"type":"checkbox", "nice":"J", "help":"Example of checkbox."}, 72 | k:{"type":"range", "nice":"K", "help":"Example of range.", "default" : 50}, 73 | l:{"type":"rating", "nice":"L", "help":"Example of rating.", "stars" : 6 }, 74 | ll:{"type":"rating", "nice":"LL", "help":"Example of rating."}, 75 | m:{"type":"yesno", "nice":"M", "help":"Example of yesno."}, 76 | n:{"type":"onoff", "nice":"N", "help":"Example of onoff slider.", "default" : 0}, 77 | o:{"type":"buttons", "nice":"O", "help":"Example of buttons.", "options" : ["foo", "bar", "baz"]}, 78 | p:{"type":"dropdown", "nice":"P", "help":"Example of dropdown.", "options" : ["foo", "bar", "baz"]}, 79 | q:{"type":"dropdownplus", "nice":"Q", "help":"Example of dropdownplus.", "options" : ["foo", "bar", "baz"]}, 80 | r:{"type":"longtext", "nice":"R", "help":"Example of longtext."}, 81 | s:{"type":"radio", "nice":"S", "help":"Example of radio.", "options" : ["foo", "bar", "baz"]}, 82 | } 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /hapi-angular/mvp-app.js: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2015 Richard Rodger, MIT License */ 2 | "use strict"; 3 | 4 | var Hapi = require('hapi') 5 | var Bell = require('bell') 6 | var Chairo = require('chairo') 7 | var Cookie = require('hapi-auth-cookie') 8 | var Inert = require('inert') 9 | 10 | 11 | process.on('uncaughtException', function (err) { 12 | console.error('uncaughtException:', err.message) 13 | console.error(err.stack) 14 | process.exit(1) 15 | }) 16 | 17 | function endIfErr (err) { 18 | if (err) { 19 | console.error(err) 20 | process.exit(1) 21 | } 22 | } 23 | 24 | var options = require('./options.mine.js') 25 | 26 | // Create our server. 27 | var server = new Hapi.Server({ debug: { request: ['error'] } }) 28 | server.connection({port: options.main.port}) 29 | 30 | var plugins = [ 31 | {register: Bell}, 32 | {register: Cookie}, 33 | {register: Chairo, options: {log: 'print'}}, 34 | {register: Inert} 35 | ] 36 | 37 | // Register our plugins. 38 | server.register(plugins, function (err) { 39 | endIfErr(err) 40 | 41 | server.route({ 42 | method: 'GET', 43 | path: '/{param*}', 44 | handler: { 45 | directory: { 46 | path: './public', 47 | redirectToSlash: true, 48 | index: true 49 | } 50 | } 51 | }) 52 | 53 | server.seneca.use('options', options) 54 | 55 | initSeneca(server.seneca, function() { 56 | // Kick off the server. 57 | server.start(function (err) { 58 | endIfErr(err) 59 | 60 | 61 | console.log('Listening at: ' + server.info.port) 62 | }) 63 | }) 64 | }) 65 | 66 | 67 | function initSeneca(seneca, done) { 68 | seneca.use('mem-store', {web: {dump: true}}) 69 | seneca.use('entity') 70 | seneca.use('user', {confirm: true}) 71 | //seneca.use('mail') 72 | seneca.use('auth') 73 | 74 | // should be sure that seneca-auth is fully loaded 75 | seneca.ready(function (err) { 76 | if (err) return process.exit(!console.error(err)); 77 | 78 | var options = seneca.export('options') 79 | //console.log(options.main) 80 | 81 | seneca.use('account') 82 | seneca.use('project') 83 | //seneca.use('data-editor') 84 | 85 | seneca.use('facebook-auth', options.facebook || {}) 86 | seneca.use('google-auth') 87 | seneca.use('github-auth') 88 | seneca.use('twitter-auth') 89 | 90 | //seneca.use('admin', {server: server, local: true}); 91 | 92 | seneca.act('role: user, cmd: register', {nick: 'u1', name: 'nu1', email: 'u1@example.com', password: 'u1', active: true}, function (err, out) { 93 | seneca.act('role: project, cmd: save', {data: {name: 'p1'}, account: out.user.accounts[0]}) 94 | }) 95 | 96 | seneca.act('role: user, cmd: register', {nick: 'u2', name: 'nu2', email: 'u2@example.com', password: 'u2', active: true}) 97 | seneca.act('role: user, cmd: register', {nick: 'a1', name: 'na1', email: 'a1@example.com', password: 'a1', active: true, admin: true}) 98 | 99 | done() 100 | }) 101 | } 102 | 103 | -------------------------------------------------------------------------------- /hapi-angular/public/css/mvp.css: -------------------------------------------------------------------------------- 1 | 2 | 3 | html, 4 | body { 5 | height: 100%; 6 | /* The html and body elements cannot have any padding or margin. */ 7 | } 8 | 9 | /* Wrapper for page content to push down footer */ 10 | #wrap { 11 | min-height: 100%; 12 | height: auto !important; 13 | height: 100%; 14 | /* Negative indent footer by its height */ 15 | margin: 0 auto -60px; 16 | /* Pad bottom by footer height */ 17 | padding: 0 0 60px; 18 | } 19 | 20 | /* Set the fixed height of the footer here */ 21 | footer { 22 | height: 60px; 23 | background-color: #f5f5f5; 24 | } 25 | 26 | .footer { 27 | margin-top: 200px; 28 | } 29 | 30 | 31 | #welcome { 32 | margin: 200px auto; 33 | height: 400px; 34 | } 35 | 36 | #reset { 37 | margin: 200px auto; 38 | } 39 | 40 | 41 | #loginbtns { 42 | width:100%; 43 | } 44 | 45 | #loginbtns td.left { 46 | text-align:left; 47 | } 48 | #loginbtns td.center { 49 | text-align:center; 50 | } 51 | #loginbtns td.right { 52 | text-align:right; 53 | } 54 | 55 | 56 | .half-width { 57 | width: 50%; 58 | } 59 | 60 | 61 | .mvp_hide { 62 | visibility: hidden; 63 | } 64 | 65 | div.mvp_seek_input label { 66 | font-style:italic; 67 | color: red; 68 | } 69 | 70 | div.mvp_seek_input input { 71 | border-color: red; 72 | } 73 | 74 | a.mvp_seek_input:hover { 75 | background-color:red; 76 | color:black; 77 | } 78 | div.mvp_seek_input input::-webkit-input-placeholder { /* WebKit browsers */ 79 | color: red; 80 | } 81 | div.mvp_seek_input input:-moz-placeholder { /* Mozilla Firefox 4 to 18 */ 82 | color: red; 83 | } 84 | div.mvp_seek_input input::-moz-placeholder { /* Mozilla Firefox 19+ */ 85 | color: red; 86 | } 87 | div.mvp_seek_input input:-ms-input-placeholder { /* Internet Explorer 10+ */ 88 | color: red; 89 | } 90 | 91 | div.mvp_show_input { 92 | display:block; 93 | } 94 | 95 | div.mvp_hide_input { 96 | display:none; 97 | } 98 | 99 | 100 | 101 | 102 | body.account { 103 | padding-top: 50px; 104 | padding-bottom: 20px; 105 | } 106 | 107 | 108 | p.account_msg { 109 | margin-top: 10px; 110 | height: 60px; 111 | } 112 | 113 | 114 | ul.selection-list li { 115 | border-bottom: 1px solid #ccc; 116 | } 117 | 118 | .rating { 119 | unicode-bidi:bidi-override; 120 | direction:rtl; 121 | font-size:30px; 122 | } 123 | 124 | .rating span.star { 125 | font-family:FontAwesome; 126 | font-weight:normal; 127 | font-style:normal; 128 | display:inline-block; 129 | } 130 | 131 | .rating span.star:hover{ 132 | cursor:pointer; 133 | } 134 | 135 | .rating span.star:before{ 136 | content:"\f006"; 137 | padding-right:5px; 138 | color:#999999; 139 | } 140 | 141 | .rating span.star-active:before { 142 | content: "\f005"; 143 | color: #e3cf7a; 144 | } 145 | 146 | .rating span.star:hover:before, .rating span.star:hover ~ span.star:before { 147 | content: "\f005"; 148 | color: #e3cf7a; 149 | } 150 | 151 | .rating span.star:hover:before { 152 | color: #cfb02c; 153 | } 154 | -------------------------------------------------------------------------------- /express-angular/mvp-app.js: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2015 Richard Rodger, MIT License */ 2 | "use strict"; 3 | 4 | var http = require('http') 5 | 6 | var express = require('express') 7 | 8 | var cookieparser = require('cookie-parser') 9 | var bodyparser = require('body-parser') 10 | var session = require('express-session') 11 | 12 | var seneca = require('seneca')({log: 'print'}) 13 | 14 | process.on('uncaughtException', function (err) { 15 | console.error('uncaughtException:', err.message) 16 | console.error(err.stack) 17 | process.exit(1) 18 | }) 19 | 20 | seneca.use('options', 'options.mine.js') 21 | 22 | seneca.use('mem-store', {web: {dump: true}}) 23 | seneca.use('entity') 24 | seneca.use('user',{confirm:true}) 25 | //seneca.use('mail') 26 | seneca.use('auth') 27 | 28 | // should be sure that seneca-auth is fully loaded 29 | seneca.ready(function (err) { 30 | if (err) return process.exit(!console.error(err)); 31 | 32 | var options = seneca.export('options') 33 | //console.log(options.main) 34 | 35 | seneca.use('account') 36 | seneca.use('project') 37 | seneca.use('settings') 38 | seneca.use('data-editor') 39 | 40 | seneca.use('facebook-auth', options.facebook || {}) 41 | seneca.use('google-auth', options.google || {}) 42 | seneca.use('github-auth', options.github || {}) 43 | seneca.use('twitter-auth', options.twitter || {}) 44 | 45 | var web = seneca.export('web') 46 | 47 | var app = express() 48 | 49 | app.use(cookieparser()) 50 | app.use(bodyparser.json()) 51 | 52 | app.use(session({secret: 'seneca', resave: true, saveUninitialized: true})) 53 | 54 | app.use(web) 55 | 56 | app.use( function( req, res, next ){ 57 | if( 0 == req.url.indexOf('/reset') || 58 | 0 == req.url.indexOf('/confirm') ) 59 | { 60 | req.url = '/' 61 | } 62 | 63 | next() 64 | }) 65 | 66 | app.use(express.static(__dirname + options.main.public)) 67 | 68 | var server = http.createServer(app) 69 | 70 | seneca.use('admin', {server: server, local: true}); 71 | 72 | // should be sure that all plugins are fully loaded before starting server 73 | seneca.ready(function(){ 74 | loadDefaultData() 75 | seneca.act('role:settings, cmd:define_spec, kind:user', {spec: options.settings.spec}) 76 | 77 | console.log('Listen on ' + options.main.port) 78 | server.listen(options.main.port) 79 | 80 | seneca.log.info('listen', options.main.port) 81 | seneca.listen() 82 | }) 83 | 84 | function loadDefaultData(){ 85 | var u = seneca.pin({role: 'user', cmd: '*'}) 86 | var projectpin = seneca.pin({role: 'project', cmd: '*'}) 87 | 88 | u.register({nick: 'u1', name: 'nu1', email: 'u1@example.com', password: 'u1', active: true}, function (err, out) { 89 | projectpin.save({data: {name: 'p1'}, account: out.user.accounts[0]}) 90 | seneca.act('role:settings, cmd:save, kind:user, settings:{a:"aaa"}, ref:"' + out.user.id + '"') 91 | }) 92 | u.register({nick: 'u2', name: 'nu2', email: 'u2@example.com', password: 'u2', active: true}) 93 | u.register({nick: 'a1', name: 'na1', email: 'a1@example.com', password: 'a1', active: true, admin: true}) 94 | } 95 | }) 96 | 97 | 98 | -------------------------------------------------------------------------------- /express-angular/public/css/mvp.css: -------------------------------------------------------------------------------- 1 | 2 | 3 | html, 4 | body { 5 | height: 100%; 6 | /* The html and body elements cannot have any padding or margin. */ 7 | } 8 | 9 | /* Wrapper for page content to push down footer */ 10 | #wrap { 11 | min-height: 100%; 12 | height: auto !important; 13 | height: 100%; 14 | /* Negative indent footer by its height */ 15 | margin: 0 auto -60px; 16 | /* Pad bottom by footer height */ 17 | padding: 0 0 60px; 18 | } 19 | 20 | /* Set the fixed height of the footer here */ 21 | footer { 22 | height: 60px; 23 | background-color: #f5f5f5; 24 | } 25 | 26 | .footer { 27 | margin-top: 200px; 28 | } 29 | 30 | 31 | #welcome { 32 | margin: 200px auto; 33 | height: 400px; 34 | } 35 | 36 | #reset { 37 | margin: 200px auto; 38 | } 39 | 40 | 41 | #loginbtns { 42 | width:100%; 43 | } 44 | 45 | #loginbtns td.left { 46 | text-align:left; 47 | } 48 | #loginbtns td.center { 49 | text-align:center; 50 | } 51 | #loginbtns td.right { 52 | text-align:right; 53 | } 54 | 55 | 56 | .half-width { 57 | width: 50%; 58 | } 59 | 60 | 61 | .mvp_hide { 62 | visibility: hidden; 63 | } 64 | 65 | div.mvp_seek_input label { 66 | font-style:italic; 67 | color: red; 68 | } 69 | 70 | div.mvp_seek_input input { 71 | border-color: red; 72 | } 73 | 74 | a.mvp_seek_input:hover { 75 | background-color:red; 76 | color:black; 77 | } 78 | div.mvp_seek_input input::-webkit-input-placeholder { /* WebKit browsers */ 79 | color: red; 80 | } 81 | div.mvp_seek_input input:-moz-placeholder { /* Mozilla Firefox 4 to 18 */ 82 | color: red; 83 | } 84 | div.mvp_seek_input input::-moz-placeholder { /* Mozilla Firefox 19+ */ 85 | color: red; 86 | } 87 | div.mvp_seek_input input:-ms-input-placeholder { /* Internet Explorer 10+ */ 88 | color: red; 89 | } 90 | 91 | div.mvp_show_input { 92 | display:block; 93 | } 94 | 95 | div.mvp_hide_input { 96 | display:none; 97 | } 98 | 99 | 100 | 101 | 102 | body.account { 103 | padding-top: 50px; 104 | padding-bottom: 20px; 105 | } 106 | 107 | 108 | p.account_msg { 109 | margin-top: 10px; 110 | height: 60px; 111 | } 112 | 113 | 114 | ul.selection-list li { 115 | border-bottom: 1px solid #ccc; 116 | } 117 | 118 | /* Settings */ 119 | table#seneca-settings { 120 | margin: 20px; 121 | } 122 | 123 | table#seneca-settings td { 124 | } 125 | 126 | table#seneca-settings td:first-child { 127 | text-align: center; 128 | padding-left: 10px; 129 | padding-right: 10px; 130 | } 131 | 132 | table#seneca-settings td:nth-child(2) { 133 | padding: 10px; 134 | max-width: 40%; 135 | } 136 | 137 | 138 | .rating { 139 | unicode-bidi:bidi-override; 140 | direction:rtl; 141 | font-size:30px; 142 | } 143 | 144 | .rating span.star { 145 | font-family:FontAwesome; 146 | font-weight:normal; 147 | font-style:normal; 148 | display:inline-block; 149 | } 150 | 151 | .rating span.star:hover{ 152 | cursor:pointer; 153 | } 154 | 155 | .rating span.star:before{ 156 | content:"\f006"; 157 | padding-right:5px; 158 | color:#999999; 159 | } 160 | 161 | .rating span.star-active:before { 162 | content: "\f005"; 163 | color: #e3cf7a; 164 | } 165 | 166 | .rating span.star:hover:before, .rating span.star:hover ~ span.star:before { 167 | content: "\f005"; 168 | color: #e3cf7a; 169 | } 170 | 171 | .rating span.star:hover:before { 172 | color: #cfb02c; 173 | } 174 | -------------------------------------------------------------------------------- /hapi-angular/public/js/angular-route.1.2.0.rc2.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | AngularJS v1.2.0-rc.2 3 | (c) 2010-2012 Google, Inc. http://angularjs.org 4 | License: MIT 5 | */ 6 | (function(q,c,I){'use strict';function x(c,f){return m(new (m(function(){},{prototype:c})),f)}function t(c,f,a,p,n){return{restrict:"ECA",terminal:!0,priority:1E3,transclude:"element",compile:function(g,m,D){return function(u,m,e){function g(){k&&(k.$destroy(),k=null);l&&(n.leave(l),l=null)}function s(){var h=c.current&&c.current.locals,y=h&&h.$template;if(y){var z=u.$new();D(z,function(d){g();d.html(y);n.enter(d,null,m);var G=a(d.contents()),r=c.current;k=r.scope=z;l=d;if(r.controller){h.$scope= 7 | k;var e=p(r.controller,h);r.controllerAs&&(k[r.controllerAs]=e);d.data("$ngControllerController",e);d.contents().data("$ngControllerController",e)}G(k);k.$emit("$viewContentLoaded");k.$eval(b);f()})}else g()}var k,l,b=e.onload||"";u.$on("$routeChangeSuccess",s);s()}}}}var A=c.copy,H=c.equals,m=c.extend,w=c.forEach,v=c.isDefined,B=c.isFunction,C=c.isString;q=c.module("ngRoute",["ng"]).provider("$route",function(){function c(a,p){var f=p.caseInsensitiveMatch,g={originalPath:a,regexp:a},m=g.keys=[]; 8 | a=a.replace(/([().])/g,"\\$1").replace(/(\/)?:(\w+)([\?|\*])?/g,function(a,c,p,e){a="?"===e?e:null;e="*"===e?e:null;m.push({name:p,optional:!!a});c=c||"";return""+(a?"":c)+"(?:"+(a?c:"")+(e&&"(.+)?"||"([^/]+)?")+")"+(a||"")}).replace(/([\/$\*])/g,"\\$1");g.regexp=RegExp("^"+a+"$",f?"i":"");return g}var f={};this.when=function(a,p){f[a]=m({reloadOnSearch:!0},p,a&&c(a,p));if(a){var n="/"==a[a.length-1]?a.substr(0,a.length-1):a+"/";f[n]=m({redirectTo:a},c(n,p))}return this};this.otherwise=function(a){this.when(null, 9 | a);return this};this.$get=["$rootScope","$location","$routeParams","$q","$injector","$http","$templateCache","$sce",function(a,c,n,g,s,q,u,t){function e(){var b=E(),h=l.current;if(b&&h&&b.$$route===h.$$route&&H(b.pathParams,h.pathParams)&&!b.reloadOnSearch&&!k)h.params=b.params,A(h.params,n),a.$broadcast("$routeUpdate",h);else if(b||h)k=!1,a.$broadcast("$routeChangeStart",b,h),(l.current=b)&&b.redirectTo&&(C(b.redirectTo)?c.path(F(b.redirectTo,b.params)).search(b.params).replace():c.url(b.redirectTo(b.pathParams, 10 | c.path(),c.search())).replace()),g.when(b).then(function(){if(b){var a=m({},b.resolve),c,d;w(a,function(b,c){a[c]=C(b)?s.get(b):s.invoke(b)});v(c=b.template)?B(c)&&(c=c(b.params)):v(d=b.templateUrl)&&(B(d)&&(d=d(b.params)),d=t.getTrustedResourceUrl(d),v(d)&&(b.loadedTemplateUrl=d,c=q.get(d,{cache:u}).then(function(b){return b.data})));v(c)&&(a.$template=c);return g.all(a)}}).then(function(c){b==l.current&&(b&&(b.locals=c,A(b.params,n)),a.$broadcast("$routeChangeSuccess",b,h))},function(c){b==l.current&& 11 | a.$broadcast("$routeChangeError",b,h,c)})}function E(){var b,a;w(f,function(e,k){var d;if(d=!a){var f=c.path();d=e.keys;var r={};if(e.regexp)if(f=e.regexp.exec(f)){for(var g=1,l=f.length;g 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Account 11 | 12 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 28 | 29 | 30 | 31 | 32 |
33 | 34 | 52 | 53 | 54 |
55 | 56 | 59 | 60 |
61 |
62 |

Dashboard

63 |

Your content.

64 |
65 |
66 | 67 |
68 |
69 |
70 |
71 | 72 |
73 |
74 |

Account

75 | 76 |

Your Details

77 |
78 |
79 | 80 | 81 |
82 |
83 | 84 | 85 |
86 | 87 | 88 | 89 | 92 |
93 | 94 |

Change Your Password

95 |
96 |
97 | 98 | 99 |
100 |
101 | 102 | 103 |
104 | 105 | 106 | 107 | 110 |
111 | 112 | 113 |

Your Organisation

114 |
115 |
116 | 117 | 118 |
119 |
120 | 121 | 122 |
123 | 124 | 125 | 126 | 129 |
130 | 131 | 132 |
133 |
134 | 135 |
136 | 137 |
138 | 139 |
140 |
141 |

© Footer

142 |
143 |
144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | -------------------------------------------------------------------------------- /express-angular/public/account/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Account 11 | 12 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 28 | 29 | 30 | 31 | 32 |
33 | 34 | 52 | 53 | 54 |
55 | 56 | 59 | 60 |
61 |
62 |

Dashboard

63 |

Your content.

64 |
65 |
66 | 67 |
68 |
69 |
70 |
71 | 72 |
73 |
74 |

Account

75 | 76 |

Your Details

77 |
78 |
79 | 80 | 81 |
82 |
83 | 84 | 85 |
86 | 87 | 88 | 89 | 92 |
93 | 94 |

Change Your Password

95 |
96 |
97 | 98 | 99 |
100 |
101 | 102 | 103 |
104 | 105 | 106 | 107 | 110 |
111 | 112 | 113 |

Your Organisation

114 |
115 |
116 | 117 | 118 |
119 |
120 | 121 | 122 |
123 | 124 | 125 | 126 | 129 |
130 | 131 | 132 |
133 |
134 | 135 |
136 | 137 |
138 | 139 |
140 |
141 |

© Footer

142 |
143 |
144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | -------------------------------------------------------------------------------- /hapi-angular/public/js/cookies.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * A complete cookies reader/writer Angular Module with full unicode support 5 | * 6 | * ### Original Source - A little framework: a complete cookies reader/writer with full unicode support 7 | * 8 | * https://developer.mozilla.org/en-US/docs/DOM/document.cookie 9 | * 10 | * ### Syntax 11 | * 12 | * Cookies.setItem(name, value[, end[, path[, domain[, secure]]]]) 13 | * Cookies.getItem(name) 14 | * Cookies.removeItem(name[, path]) 15 | * Cookies.hasItem(name) 16 | * Cookies.keys() 17 | * 18 | * @date 2013-08-02 19 | * @version 0.0.1 20 | * 21 | * ### Notes 22 | * 23 | * - This framework is released under the GNU Public License, version 3 or later. http://www.gnu.org/licenses/gpl-3.0-standalone.html 24 | * 25 | */ 26 | 27 | /** 28 | * Setup the cookiesModule. 29 | */ 30 | var cookiesModule = angular.module('cookiesModule', []); 31 | 32 | /** 33 | * Set date value for infinity parameter 34 | */ 35 | cookiesModule.constant('infinity_date', 'Fri, 31 Dec 9999 23:59:59 GMT'); 36 | 37 | cookiesModule.factory('Cookies', ['infinity_date' ,function (infinity_date) { 38 | 39 | return { 40 | 41 | /** 42 | * Read a cookie. If the cookie doesn't exist a null value will be returned. 43 | * 44 | * ### Syntax 45 | * 46 | * Cookies.getItem(name) 47 | * 48 | * ### Example usage 49 | * 50 | * Cookies.getItem('test1'); 51 | * Cookies.getItem('test5'); 52 | * Cookies.getItem('test1'); 53 | * Cookies.getItem('test5'); 54 | * Cookies.getItem('unexistingCookie'); 55 | * Cookies.getItem(); 56 | * 57 | * ### Parameters 58 | * 59 | * @param sKey - name - the name of the cookie to read (string). 60 | * @returns {string|null} 61 | */ 62 | 63 | getItem: function (sKey) { 64 | return decodeURI(document.cookie.replace(new RegExp('(?:(?:^|.*;)\\s*' + encodeURI(sKey).replace(/[\-\.\+\*]/g, '\\$&') + '\\s*\\=\\s*([^;]*).*$)|^.*$'), '$1')) || null; 65 | }, 66 | 67 | /** 68 | * Create/overwrite a cookie. 69 | * 70 | * ### Syntax 71 | * 72 | * Cookies.setItem(name, value[, end[, path[, domain[, secure]]]]) 73 | * 74 | * ### Example usage 75 | * 76 | * Cookies.setItem('test0', 'Hello world!'); 77 | * Cookies.setItem('test1', 'Unicode test: \u00E0\u00E8\u00EC\u00F2\u00F9', Infinity); 78 | * Cookies.setItem('test2', 'Hello world!', new Date(2020, 5, 12)); 79 | * Cookies.setItem('test3', 'Hello world!', new Date(2027, 2, 3), '/blog'); 80 | * Cookies.setItem('test4', 'Hello world!', 'Sun, 06 Nov 2022 21:43:15 GMT'); 81 | * Cookies.setItem('test5', 'Hello world!', 'Tue, 06 Dec 2022 13:11:07 GMT', '/home'); 82 | * Cookies.setItem('test6', 'Hello world!', 150); 83 | * Cookies.setItem('test7', 'Hello world!', 245, '/content'); 84 | * Cookies.setItem('test8', 'Hello world!', null, null, 'example.com'); 85 | * Cookies.setItem('test9', 'Hello world!', null, null, null, true); 86 | * 87 | * ### Notes 88 | * 89 | * For never-expire-cookies we used the arbitrarily distant date Fri, 31 Dec 9999 23:59:59 GMT. If for any reason you are afraid of such a date, use the conventional date of end of the world Tue, 19 Jan 2038 03:14:07 GMT – which is the maximum number of seconds elapsed since since 1 January 1970 00:00:00 UTC expressible by a signed 32-bit integer (i.e.: 01111111111111111111111111111111, which is new Date(0x7fffffff * 1e3)). 90 | * 91 | * ### Parameters 92 | * 93 | * @param sKey - name (required) - The name of the cookie to create/overwrite (string). 94 | * @param sValue - value (required) - The value of the cookie (string). 95 | * @param vEnd - end (optional) - The max-age in seconds (e.g. 31536e3 for a year, Infinity for a never-expires cookie) or the expires date in GMTString format or as Date object; if not specified it will expire at the end of session (number – finite or Infinity – string, Date object or null). 96 | * @param sPath - path (optional) - E.g., "/", "/mydir"; if not specified, defaults to the current path of the current document location (string or null). 97 | * @param sDomain - domain (optional) - E.g., "example.com", ".example.com" (includes all subdomains) or "subdomain.example.com"; if not specified, defaults to the host portion of the current document location (string or null). 98 | * @param bSecure - secure (optional) - The cookie will be transmitted only over secure protocol as https (boolean or null). 99 | * @returns {boolean} 100 | */ 101 | 102 | setItem: function (sKey, sValue, vEnd, sPath, sDomain, bSecure) { 103 | if (!sKey || /^(?:expires|max\-age|path|domain|secure)$/i.test(sKey)) { return false; } 104 | var sExpires = ''; 105 | if (vEnd) { 106 | switch (vEnd.constructor) { 107 | case Number: 108 | sExpires = vEnd === Infinity ? '; expires=' + infinity_date : '; max-age=' + vEnd; 109 | break; 110 | case String: 111 | sExpires = '; expires=' + vEnd; 112 | break; 113 | case Date: 114 | sExpires = '; expires=' + vEnd.toGMTString(); 115 | break; 116 | } 117 | } 118 | document.cookie = encodeURI(sKey) + '=' + encodeURI(sValue) + sExpires + (sDomain ? '; domain=' + sDomain : '') + (sPath ? '; path=' + sPath : '') + (bSecure ? '; secure' : ''); 119 | return true; 120 | }, 121 | 122 | /** 123 | * Delete a cookie 124 | * 125 | * ### Syntax 126 | * 127 | * Cookies.removeItem(name[, path]) 128 | * 129 | * ### Example usage 130 | * 131 | * Cookies.removeItem('test1'); 132 | * Cookies.removeItem('test5', '/home'); 133 | * 134 | * ### Parameters 135 | * 136 | * @param sKey - name - the name of the cookie to remove (string). 137 | * @param sPath - path (optional) - e.g., "/", "/mydir"; if not specified, defaults to the current path of the current document location (string or null). 138 | * @returns {boolean} 139 | */ 140 | 141 | removeItem: function (sKey, sPath) { 142 | if (!sKey || !this.hasItem(sKey)) { return false; } 143 | document.cookie = encodeURI(sKey) + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT' + (sPath ? '; path=' + sPath : ''); 144 | return true; 145 | }, 146 | 147 | /** 148 | * Check if a cookie exists. 149 | * 150 | * ### Syntax 151 | * 152 | * Cookies.hasItem(name) 153 | * 154 | * ### Parameters 155 | * 156 | * @param sKey - name - the name of the cookie to test (string). 157 | * @returns {*} 158 | */ 159 | 160 | hasItem: function (sKey) { 161 | return (new RegExp('(?:^|;\\s*)' + encodeURI(sKey).replace(/[\-\.\+\*]/g, '\\$&') + '\\s*\\=')).test(document.cookie); 162 | }, 163 | 164 | /** 165 | * Returns an array of all readable cookies from this location. 166 | * 167 | * ### Example usage 168 | * 169 | * Cookies.keys().join('\n'); 170 | * 171 | * @returns {*} 172 | */ 173 | 174 | keys: /* optional method: you can safely remove it! */ function () { 175 | var aKeys = document.cookie.replace(/((?:^|\s*;)[^\=]+)(?=;|$)|^\s*|\s*(?:\=[^;]*)?(?:\1|$)/g, '').split(/\s*(?:\=[^;]*)?;\s*/); 176 | for (var nIdx = 0; nIdx < aKeys.length; nIdx++) { aKeys[nIdx] = decodeURI(aKeys[nIdx]); } 177 | return aKeys; 178 | } 179 | 180 | }; 181 | 182 | }]); 183 | -------------------------------------------------------------------------------- /express-angular/public/js/cookies.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * A complete cookies reader/writer Angular Module with full unicode support 5 | * 6 | * ### Original Source - A little framework: a complete cookies reader/writer with full unicode support 7 | * 8 | * https://developer.mozilla.org/en-US/docs/DOM/document.cookie 9 | * 10 | * ### Syntax 11 | * 12 | * Cookies.setItem(name, value[, end[, path[, domain[, secure]]]]) 13 | * Cookies.getItem(name) 14 | * Cookies.removeItem(name[, path]) 15 | * Cookies.hasItem(name) 16 | * Cookies.keys() 17 | * 18 | * @date 2013-08-02 19 | * @version 0.0.1 20 | * 21 | * ### Notes 22 | * 23 | * - This framework is released under the GNU Public License, version 3 or later. http://www.gnu.org/licenses/gpl-3.0-standalone.html 24 | * 25 | */ 26 | 27 | /** 28 | * Setup the cookiesModule. 29 | */ 30 | var cookiesModule = angular.module('cookiesModule', []); 31 | 32 | /** 33 | * Set date value for infinity parameter 34 | */ 35 | cookiesModule.constant('infinity_date', 'Fri, 31 Dec 9999 23:59:59 GMT'); 36 | 37 | cookiesModule.factory('Cookies', ['infinity_date' ,function (infinity_date) { 38 | 39 | return { 40 | 41 | /** 42 | * Read a cookie. If the cookie doesn't exist a null value will be returned. 43 | * 44 | * ### Syntax 45 | * 46 | * Cookies.getItem(name) 47 | * 48 | * ### Example usage 49 | * 50 | * Cookies.getItem('test1'); 51 | * Cookies.getItem('test5'); 52 | * Cookies.getItem('test1'); 53 | * Cookies.getItem('test5'); 54 | * Cookies.getItem('unexistingCookie'); 55 | * Cookies.getItem(); 56 | * 57 | * ### Parameters 58 | * 59 | * @param sKey - name - the name of the cookie to read (string). 60 | * @returns {string|null} 61 | */ 62 | 63 | getItem: function (sKey) { 64 | return decodeURI(document.cookie.replace(new RegExp('(?:(?:^|.*;)\\s*' + encodeURI(sKey).replace(/[\-\.\+\*]/g, '\\$&') + '\\s*\\=\\s*([^;]*).*$)|^.*$'), '$1')) || null; 65 | }, 66 | 67 | /** 68 | * Create/overwrite a cookie. 69 | * 70 | * ### Syntax 71 | * 72 | * Cookies.setItem(name, value[, end[, path[, domain[, secure]]]]) 73 | * 74 | * ### Example usage 75 | * 76 | * Cookies.setItem('test0', 'Hello world!'); 77 | * Cookies.setItem('test1', 'Unicode test: \u00E0\u00E8\u00EC\u00F2\u00F9', Infinity); 78 | * Cookies.setItem('test2', 'Hello world!', new Date(2020, 5, 12)); 79 | * Cookies.setItem('test3', 'Hello world!', new Date(2027, 2, 3), '/blog'); 80 | * Cookies.setItem('test4', 'Hello world!', 'Sun, 06 Nov 2022 21:43:15 GMT'); 81 | * Cookies.setItem('test5', 'Hello world!', 'Tue, 06 Dec 2022 13:11:07 GMT', '/home'); 82 | * Cookies.setItem('test6', 'Hello world!', 150); 83 | * Cookies.setItem('test7', 'Hello world!', 245, '/content'); 84 | * Cookies.setItem('test8', 'Hello world!', null, null, 'example.com'); 85 | * Cookies.setItem('test9', 'Hello world!', null, null, null, true); 86 | * 87 | * ### Notes 88 | * 89 | * For never-expire-cookies we used the arbitrarily distant date Fri, 31 Dec 9999 23:59:59 GMT. If for any reason you are afraid of such a date, use the conventional date of end of the world Tue, 19 Jan 2038 03:14:07 GMT – which is the maximum number of seconds elapsed since since 1 January 1970 00:00:00 UTC expressible by a signed 32-bit integer (i.e.: 01111111111111111111111111111111, which is new Date(0x7fffffff * 1e3)). 90 | * 91 | * ### Parameters 92 | * 93 | * @param sKey - name (required) - The name of the cookie to create/overwrite (string). 94 | * @param sValue - value (required) - The value of the cookie (string). 95 | * @param vEnd - end (optional) - The max-age in seconds (e.g. 31536e3 for a year, Infinity for a never-expires cookie) or the expires date in GMTString format or as Date object; if not specified it will expire at the end of session (number – finite or Infinity – string, Date object or null). 96 | * @param sPath - path (optional) - E.g., "/", "/mydir"; if not specified, defaults to the current path of the current document location (string or null). 97 | * @param sDomain - domain (optional) - E.g., "example.com", ".example.com" (includes all subdomains) or "subdomain.example.com"; if not specified, defaults to the host portion of the current document location (string or null). 98 | * @param bSecure - secure (optional) - The cookie will be transmitted only over secure protocol as https (boolean or null). 99 | * @returns {boolean} 100 | */ 101 | 102 | setItem: function (sKey, sValue, vEnd, sPath, sDomain, bSecure) { 103 | if (!sKey || /^(?:expires|max\-age|path|domain|secure)$/i.test(sKey)) { return false; } 104 | var sExpires = ''; 105 | if (vEnd) { 106 | switch (vEnd.constructor) { 107 | case Number: 108 | sExpires = vEnd === Infinity ? '; expires=' + infinity_date : '; max-age=' + vEnd; 109 | break; 110 | case String: 111 | sExpires = '; expires=' + vEnd; 112 | break; 113 | case Date: 114 | sExpires = '; expires=' + vEnd.toGMTString(); 115 | break; 116 | } 117 | } 118 | document.cookie = encodeURI(sKey) + '=' + encodeURI(sValue) + sExpires + (sDomain ? '; domain=' + sDomain : '') + (sPath ? '; path=' + sPath : '') + (bSecure ? '; secure' : ''); 119 | return true; 120 | }, 121 | 122 | /** 123 | * Delete a cookie 124 | * 125 | * ### Syntax 126 | * 127 | * Cookies.removeItem(name[, path]) 128 | * 129 | * ### Example usage 130 | * 131 | * Cookies.removeItem('test1'); 132 | * Cookies.removeItem('test5', '/home'); 133 | * 134 | * ### Parameters 135 | * 136 | * @param sKey - name - the name of the cookie to remove (string). 137 | * @param sPath - path (optional) - e.g., "/", "/mydir"; if not specified, defaults to the current path of the current document location (string or null). 138 | * @returns {boolean} 139 | */ 140 | 141 | removeItem: function (sKey, sPath) { 142 | if (!sKey || !this.hasItem(sKey)) { return false; } 143 | document.cookie = encodeURI(sKey) + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT' + (sPath ? '; path=' + sPath : ''); 144 | return true; 145 | }, 146 | 147 | /** 148 | * Check if a cookie exists. 149 | * 150 | * ### Syntax 151 | * 152 | * Cookies.hasItem(name) 153 | * 154 | * ### Parameters 155 | * 156 | * @param sKey - name - the name of the cookie to test (string). 157 | * @returns {*} 158 | */ 159 | 160 | hasItem: function (sKey) { 161 | return (new RegExp('(?:^|;\\s*)' + encodeURI(sKey).replace(/[\-\.\+\*]/g, '\\$&') + '\\s*\\=')).test(document.cookie); 162 | }, 163 | 164 | /** 165 | * Returns an array of all readable cookies from this location. 166 | * 167 | * ### Example usage 168 | * 169 | * Cookies.keys().join('\n'); 170 | * 171 | * @returns {*} 172 | */ 173 | 174 | keys: /* optional method: you can safely remove it! */ function () { 175 | var aKeys = document.cookie.replace(/((?:^|\s*;)[^\=]+)(?=;|$)|^\s*|\s*(?:\=[^;]*)?(?:\1|$)/g, '').split(/\s*(?:\=[^;]*)?;\s*/); 176 | for (var nIdx = 0; nIdx < aKeys.length; nIdx++) { aKeys[nIdx] = decodeURI(aKeys[nIdx]); } 177 | return aKeys; 178 | } 179 | 180 | }; 181 | 182 | }]); 183 | -------------------------------------------------------------------------------- /hapi-angular/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Service 10 | 11 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 28 | 29 | 30 | 31 | 32 |
33 | 34 |
35 |
36 | 39 |

Seneca MVP

40 |
41 | 42 | 43 |
44 |
45 |
46 |

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras quis enim sed nunc congue fermentum. Phasellus vitae tincidunt arcu.

47 |
48 | 49 |
50 |
51 |
52 |
53 | 54 | 55 |
56 |
57 | 58 | 59 |
60 |
61 | 62 | 63 |
64 |
65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 |
Sign Up »CancelSign In »Send Reset »
or
Facebook Sign In »
or
Google Sign In »
or
Github Sign In »
or
Twitter Sign In »
100 |

101 | forgot password? 102 |

103 |
104 | 105 |

{{msg}}

106 |
107 | 108 |
109 |

Welcome {{user.name}}!

110 | Your Account » 111 |
112 | 113 |
114 |
115 |
116 | 117 | 118 |
119 |
 
120 |
121 |

Password Reset

122 |
123 |
124 | 125 | 126 |
127 |
128 | 129 | 130 |
131 | 132 | Reset Password » 133 | Sign In » 134 | 135 |
136 |

137 | {{msg}} 138 |

139 |
140 |
 
141 |
142 | 143 | 144 |
145 |
 
146 |
147 |

Confirm Account

148 | 149 |

150 | {{msg}} 151 |

152 | 153 | Your Account » 154 | Sign In » 155 | 156 |
157 |
 
158 |
159 | 160 |
161 | 162 | 163 | 164 | 165 | 166 |
167 |
168 |

Footer

169 |
170 |
171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | -------------------------------------------------------------------------------- /express-angular/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Service 11 | 12 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 29 | 30 | 31 | 32 | 33 |
34 | 35 |
36 |
37 | 40 |

Seneca MVP

41 |
42 | 43 | 44 |
45 |
46 |
47 |

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras quis enim sed nunc congue fermentum. Phasellus vitae tincidunt arcu.

48 |
49 | 50 |
51 |
52 |
53 |
54 | 55 | 56 |
57 |
58 | 59 | 60 |
61 |
62 | 63 | 64 |
65 |
66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 |
Sign Up »CancelSign In »Send Reset »
or
Facebook Sign In »
or
Google Sign In »
or
Github Sign In »
or
Twitter Sign In »
101 |

102 | forgot password? 103 |

104 |
105 | 106 |

{{msg}}

107 |
108 | 109 |
110 |

Welcome {{user.name}}!

111 | Your Account » 112 |
113 | 114 |
115 |
116 |
117 | 118 | 119 |
120 |
 
121 |
122 |

Password Reset

123 |
124 |
125 | 126 | 127 |
128 |
129 | 130 | 131 |
132 | 133 | Reset Password » 134 | Sign In » 135 | 136 |
137 |

138 | {{msg}} 139 |

140 |
141 |
 
142 |
143 | 144 | 145 |
146 |
 
147 |
148 |

Confirm Account

149 | 150 |

151 | {{msg}} 152 |

153 | 154 | Your Account » 155 | Sign In » 156 | 157 |
158 |
 
159 |
160 | 161 |
162 | 163 | 164 | 165 | 166 | 167 |
168 |
169 |

Footer

170 |
171 |
172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | -------------------------------------------------------------------------------- /hapi-angular/public/account/mvp-account.js: -------------------------------------------------------------------------------- 1 | ;(function(){ 2 | function noop(){for(var i=0;i