├── 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 | New Project »
9 |
10 |
11 |
17 |
18 |
19 |
20 |
Project Details
21 |
22 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/express-angular/public/account/projects.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
Projects
5 |
6 |
7 |
8 | New Project »
9 |
10 |
11 |
17 |
18 |
19 |
20 |
Project Details
21 |
22 |
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 |
71 |
72 |
73 |
74 |
Account
75 |
76 |
Your Details
77 |
93 |
94 |
Change Your Password
95 |
111 |
112 |
113 |
Your Organisation
114 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
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 |
71 |
72 |
73 |
74 |
Account
75 |
76 |
Your Details
77 |
93 |
94 |
Change Your Password
95 |
111 |
112 |
113 |
Your Organisation
114 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
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 |
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 |
104 |
105 |
{{msg}}
106 |
107 |
108 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
Password Reset
122 |
136 |
137 | {{msg}}
138 |
139 |
140 |
141 |
142 |
143 |
144 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
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 |
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 |
105 |
106 |
{{msg}}
107 |
108 |
109 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
Password Reset
123 |
137 |
138 | {{msg}}
139 |
140 |
141 |
142 |
143 |
144 |
145 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
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