├── blog1 ├── .editorconfig ├── .gitignore ├── .jshintignore ├── .jshintrc ├── .yo-rc.json ├── README.md ├── client │ └── README.md ├── common │ └── models │ │ ├── category.js │ │ ├── category.json │ │ ├── entry.js │ │ ├── entry.json │ │ ├── test-content.js │ │ └── test-content.json ├── package.json └── server │ ├── boot │ ├── 01seed.js │ ├── authentication.js │ └── routes.js │ ├── component-config.json │ ├── config.json │ ├── datasources.json │ ├── middleware.json │ ├── middleware.production.json │ ├── model-config.json │ ├── server.js │ └── views │ ├── entry.handlebars │ ├── index.handlebars │ └── layouts │ └── main.handlebars ├── blog2 ├── .editorconfig ├── .gitignore ├── .jshintignore ├── .jshintrc ├── .yo-rc.json ├── README.md ├── client │ ├── README.md │ └── electron-quick-start │ │ ├── .gitignore │ │ ├── LICENSE.md │ │ ├── README.md │ │ ├── main.js │ │ ├── package.json │ │ └── www │ │ ├── css │ │ └── style.css │ │ ├── img │ │ └── ionic.png │ │ ├── index.html │ │ ├── js │ │ ├── app.js │ │ ├── controllers.js │ │ └── services.js │ │ ├── lib │ │ └── ionic │ │ │ ├── css │ │ │ ├── ionic.css │ │ │ └── ionic.min.css │ │ │ ├── fonts │ │ │ ├── ionicons.eot │ │ │ ├── ionicons.svg │ │ │ ├── ionicons.ttf │ │ │ └── ionicons.woff │ │ │ ├── js │ │ │ ├── angular-ui │ │ │ │ ├── angular-ui-router.js │ │ │ │ └── angular-ui-router.min.js │ │ │ ├── angular │ │ │ │ ├── angular-animate.js │ │ │ │ ├── angular-animate.min.js │ │ │ │ ├── angular-resource.js │ │ │ │ ├── angular-resource.min.js │ │ │ │ ├── angular-sanitize.js │ │ │ │ ├── angular-sanitize.min.js │ │ │ │ ├── angular.js │ │ │ │ └── angular.min.js │ │ │ ├── ionic-angular.js │ │ │ ├── ionic-angular.min.js │ │ │ ├── ionic.bundle.js │ │ │ ├── ionic.bundle.min.js │ │ │ ├── ionic.js │ │ │ └── ionic.min.js │ │ │ ├── scss │ │ │ ├── _action-sheet.scss │ │ │ ├── _animations.scss │ │ │ ├── _backdrop.scss │ │ │ ├── _badge.scss │ │ │ ├── _bar.scss │ │ │ ├── _button-bar.scss │ │ │ ├── _button.scss │ │ │ ├── _checkbox.scss │ │ │ ├── _form.scss │ │ │ ├── _grid.scss │ │ │ ├── _items.scss │ │ │ ├── _list.scss │ │ │ ├── _loading.scss │ │ │ ├── _menu.scss │ │ │ ├── _mixins.scss │ │ │ ├── _modal.scss │ │ │ ├── _platform.scss │ │ │ ├── _popover.scss │ │ │ ├── _popup.scss │ │ │ ├── _progress.scss │ │ │ ├── _radio.scss │ │ │ ├── _range.scss │ │ │ ├── _refresher.scss │ │ │ ├── _reset.scss │ │ │ ├── _scaffolding.scss │ │ │ ├── _select.scss │ │ │ ├── _slide-box.scss │ │ │ ├── _slides.scss │ │ │ ├── _spinner.scss │ │ │ ├── _tabs.scss │ │ │ ├── _toggle.scss │ │ │ ├── _transitions.scss │ │ │ ├── _type.scss │ │ │ ├── _util.scss │ │ │ ├── _variables.scss │ │ │ ├── ionic.scss │ │ │ └── ionicons │ │ │ │ ├── _ionicons-font.scss │ │ │ │ ├── _ionicons-icons.scss │ │ │ │ ├── _ionicons-variables.scss │ │ │ │ └── ionicons.scss │ │ │ └── version.json │ │ └── partials │ │ ├── entry.html │ │ ├── home.html │ │ └── login.html ├── common │ └── models │ │ ├── appuser.js │ │ ├── appuser.json │ │ ├── category.js │ │ ├── category.json │ │ ├── entry.js │ │ └── entry.json ├── package.json └── server │ ├── boot │ ├── authentication.js │ └── routes.js │ ├── component-config.json │ ├── config.json │ ├── datasources.json │ ├── middleware.json │ ├── middleware.production.json │ ├── model-config.json │ ├── server.js │ └── views │ ├── entry.handlebars │ ├── index.handlebars │ └── layouts │ └── main.handlebars ├── filetest ├── .editorconfig ├── .eslintignore ├── .eslintrc ├── .gitignore ├── .yo-rc.json ├── client │ ├── README.md │ ├── app.js │ └── index.html ├── common │ └── models │ │ ├── attachment.js │ │ ├── attachment.json │ │ ├── cat.js │ │ ├── cat.json │ │ ├── note.js │ │ └── note.json ├── data.db ├── files │ └── resume │ │ ├── avatar.jpg │ │ ├── foo.txt │ │ ├── goo.txt │ │ └── windowsfield.jpg ├── notes.txt ├── package.json └── server │ ├── boot │ ├── authentication.js │ └── root.js │ ├── component-config.json │ ├── config.json │ ├── datasources.json │ ├── middleware.development.json │ ├── middleware.json │ ├── model-config.json │ └── server.js ├── geotest ├── .editorconfig ├── .gitignore ├── .jshintignore ├── .jshintrc ├── .yo-rc.json ├── README.md ├── client │ ├── README.md │ ├── img │ │ └── sadcat.png │ ├── js │ │ ├── map.js │ │ └── near.js │ ├── map.html │ └── near.html ├── common │ └── models │ │ ├── cat.js │ │ ├── cat.json │ │ └── localmongo.js ├── fakedata.txt ├── memory.db ├── package.json └── server │ ├── boot │ ├── authentication.js │ └── root.js │ ├── component-config.json │ ├── config.json │ ├── datasources.json │ ├── middleware.json │ ├── middleware.production.json │ ├── model-config.json │ └── server.js ├── ormdemo ├── .editorconfig ├── .gitignore ├── .jshintignore ├── .jshintrc ├── .yo-rc.json ├── README.md ├── client │ └── README.md ├── common │ └── models │ │ ├── part.js │ │ ├── part.json │ │ ├── product.js │ │ ├── product.json │ │ ├── test.js │ │ └── test.json ├── data.db ├── package.json └── server │ ├── boot │ ├── authentication.js │ ├── root.js │ └── routes.js │ ├── component-config.json │ ├── config.json │ ├── datasources.json │ ├── middleware.json │ ├── middleware.production.json │ ├── model-config.json │ ├── public │ └── css │ │ └── styles.css │ ├── server.js │ └── views │ ├── edit.handlebars │ ├── editpart.handlebars │ ├── index.handlebars │ └── layouts │ └── main.handlebars ├── simpleauthdemo ├── .editorconfig ├── .eslintignore ├── .eslintrc ├── .gitignore ├── .yo-rc.json ├── README.md ├── client │ ├── README.md │ ├── index.html │ └── js │ │ └── app.js ├── common │ └── models │ │ ├── appuser.js │ │ ├── appuser.json │ │ ├── post.js │ │ └── post.json ├── data.db ├── notes.txt ├── package.json └── server │ ├── boot │ ├── authentication.js │ └── root.js │ ├── component-config.json │ ├── config.json │ ├── datasources.json │ ├── middleware.development.json │ ├── middleware.json │ ├── model-config.json │ └── server.js └── superlongscroll ├── .editorconfig ├── .gitignore ├── .jshintignore ├── .jshintrc ├── .yo-rc.json ├── client ├── README.md ├── app1 │ ├── .gitignore │ ├── .vscode │ │ └── typings │ │ │ └── cordova │ │ │ └── cordova.d.ts │ ├── app │ │ ├── app.ts │ │ ├── pages │ │ │ └── home │ │ │ │ ├── home.html │ │ │ │ ├── home.scss │ │ │ │ └── home.ts │ │ ├── providers │ │ │ └── people-service │ │ │ │ └── people-service.ts │ │ └── theme │ │ │ ├── app.core.scss │ │ │ ├── app.ios.scss │ │ │ ├── app.md.scss │ │ │ ├── app.variables.scss │ │ │ └── app.wp.scss │ ├── gulpfile.js │ ├── hooks │ │ ├── README.md │ │ └── after_prepare │ │ │ └── 010_add_platform_class.js │ ├── ionic.config.js │ ├── ionic.config.json │ ├── package.json │ ├── resources │ │ ├── android │ │ │ ├── icon │ │ │ │ ├── drawable-hdpi-icon.png │ │ │ │ ├── drawable-ldpi-icon.png │ │ │ │ ├── drawable-mdpi-icon.png │ │ │ │ ├── drawable-xhdpi-icon.png │ │ │ │ ├── drawable-xxhdpi-icon.png │ │ │ │ └── drawable-xxxhdpi-icon.png │ │ │ └── splash │ │ │ │ ├── drawable-land-hdpi-screen.png │ │ │ │ ├── drawable-land-ldpi-screen.png │ │ │ │ ├── drawable-land-mdpi-screen.png │ │ │ │ ├── drawable-land-xhdpi-screen.png │ │ │ │ ├── drawable-land-xxhdpi-screen.png │ │ │ │ ├── drawable-land-xxxhdpi-screen.png │ │ │ │ ├── drawable-port-hdpi-screen.png │ │ │ │ ├── drawable-port-ldpi-screen.png │ │ │ │ ├── drawable-port-mdpi-screen.png │ │ │ │ ├── drawable-port-xhdpi-screen.png │ │ │ │ ├── drawable-port-xxhdpi-screen.png │ │ │ │ └── drawable-port-xxxhdpi-screen.png │ │ ├── icon.png │ │ ├── ios │ │ │ ├── icon │ │ │ │ ├── icon-40.png │ │ │ │ ├── icon-40@2x.png │ │ │ │ ├── icon-50.png │ │ │ │ ├── icon-50@2x.png │ │ │ │ ├── icon-60.png │ │ │ │ ├── icon-60@2x.png │ │ │ │ ├── icon-60@3x.png │ │ │ │ ├── icon-72.png │ │ │ │ ├── icon-72@2x.png │ │ │ │ ├── icon-76.png │ │ │ │ ├── icon-76@2x.png │ │ │ │ ├── icon-small.png │ │ │ │ ├── icon-small@2x.png │ │ │ │ ├── icon-small@3x.png │ │ │ │ ├── icon.png │ │ │ │ └── icon@2x.png │ │ │ └── splash │ │ │ │ ├── Default-568h@2x~iphone.png │ │ │ │ ├── Default-667h.png │ │ │ │ ├── Default-736h.png │ │ │ │ ├── Default-Landscape-736h.png │ │ │ │ ├── Default-Landscape@2x~ipad.png │ │ │ │ ├── Default-Landscape~ipad.png │ │ │ │ ├── Default-Portrait@2x~ipad.png │ │ │ │ ├── Default-Portrait~ipad.png │ │ │ │ ├── Default@2x~iphone.png │ │ │ │ └── Default~iphone.png │ │ └── splash.png │ ├── tsconfig.json │ ├── typings.json │ ├── typings │ │ ├── browser.d.ts │ │ ├── browser │ │ │ └── ambient │ │ │ │ └── es6-shim │ │ │ │ └── index.d.ts │ │ ├── main.d.ts │ │ └── main │ │ │ └── ambient │ │ │ └── es6-shim │ │ │ └── index.d.ts │ └── www │ │ └── index.html └── simple │ ├── app.js │ └── index.html ├── common └── models │ ├── note.js │ ├── note.json │ ├── person.js │ └── person.json ├── data.db ├── package.json └── server ├── boot └── root.js ├── component-config.json ├── config.json ├── datasources.json ├── middleware.json ├── middleware.production.json ├── model-config.json ├── server.js └── users.json /blog1/.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # http://editorconfig.org 4 | 5 | root = true 6 | 7 | [*] 8 | indent_style = space 9 | indent_size = 2 10 | end_of_line = lf 11 | charset = utf-8 12 | trim_trailing_whitespace = true 13 | insert_final_newline = true 14 | -------------------------------------------------------------------------------- /blog1/.gitignore: -------------------------------------------------------------------------------- 1 | *.csv 2 | *.dat 3 | *.iml 4 | *.log 5 | *.out 6 | *.pid 7 | *.seed 8 | *.sublime-* 9 | *.swo 10 | *.swp 11 | *.tgz 12 | *.xml 13 | .DS_Store 14 | .idea 15 | .project 16 | .strong-pm 17 | coverage 18 | node_modules 19 | npm-debug.log 20 | -------------------------------------------------------------------------------- /blog1/.jshintignore: -------------------------------------------------------------------------------- 1 | /client/ 2 | /node_modules/ 3 | -------------------------------------------------------------------------------- /blog1/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "esnext": true, 4 | "bitwise": true, 5 | "camelcase": true, 6 | "eqeqeq": true, 7 | "eqnull": true, 8 | "immed": true, 9 | "indent": 2, 10 | "latedef": "nofunc", 11 | "newcap": true, 12 | "nonew": true, 13 | "noarg": true, 14 | "quotmark": "single", 15 | "regexp": true, 16 | "undef": true, 17 | "unused": false, 18 | "trailing": true, 19 | "sub": true, 20 | "maxlen": 80 21 | } 22 | -------------------------------------------------------------------------------- /blog1/.yo-rc.json: -------------------------------------------------------------------------------- 1 | { 2 | "generator-loopback": {} 3 | } -------------------------------------------------------------------------------- /blog1/README.md: -------------------------------------------------------------------------------- 1 | # My Application 2 | 3 | The project is generated by [LoopBack](http://loopback.io). -------------------------------------------------------------------------------- /blog1/client/README.md: -------------------------------------------------------------------------------- 1 | ## Client 2 | 3 | This is the place for your application front-end files. 4 | -------------------------------------------------------------------------------- /blog1/common/models/category.js: -------------------------------------------------------------------------------- 1 | module.exports = function(Category) { 2 | 3 | }; 4 | -------------------------------------------------------------------------------- /blog1/common/models/category.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "category", 3 | "base": "PersistedModel", 4 | "strict": false, 5 | "idInjection": false, 6 | "options": { 7 | "validateUpsert": true 8 | }, 9 | "properties": { 10 | "name": { 11 | "type": "string", 12 | "required": true 13 | } 14 | }, 15 | "validations": [], 16 | "relations": {}, 17 | "acls": [], 18 | "methods": {} 19 | } 20 | -------------------------------------------------------------------------------- /blog1/common/models/entry.js: -------------------------------------------------------------------------------- 1 | module.exports = function(Entry) { 2 | 3 | Entry.observe('loaded', function(ctx, next) { 4 | if(ctx && ctx.instance && ctx.instance.released) { 5 | var date = ctx.instance.published; 6 | ctx.instance.url = "/"+date.getFullYear()+"/"+(date.getMonth()+1)+"/"+date.getDate()+"/"+ctx.instance.slug; 7 | } 8 | next(); 9 | }); 10 | 11 | }; 12 | -------------------------------------------------------------------------------- /blog1/common/models/entry.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "entry", 3 | "base": "PersistedModel", 4 | "strict": false, 5 | "idInjection": false, 6 | "options": { 7 | "validateUpsert": true 8 | }, 9 | "properties": { 10 | "title": { 11 | "type": "string", 12 | "required": true 13 | }, 14 | "released": { 15 | "type": "boolean", 16 | "required": true 17 | }, 18 | "published": { 19 | "type": "date", 20 | "required": true 21 | }, 22 | "slug": { 23 | "type": "string", 24 | "required": true 25 | }, 26 | "body": { 27 | "type": "string", 28 | "required": true 29 | } 30 | }, 31 | "validations": [], 32 | "relations": { 33 | "categories": { 34 | "type": "hasMany", 35 | "model": "category", 36 | "foreignKey": "" 37 | } 38 | }, 39 | "acls": [], 40 | "methods": {} 41 | } 42 | -------------------------------------------------------------------------------- /blog1/common/models/test-content.js: -------------------------------------------------------------------------------- 1 | module.exports = function(TestContent) { 2 | 3 | }; 4 | -------------------------------------------------------------------------------- /blog1/common/models/test-content.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "testContent", 3 | "base": "PersistedModel", 4 | "strict": false, 5 | "idInjection": false, 6 | "options": { 7 | "validateUpsert": true 8 | }, 9 | "properties": { 10 | "title": { 11 | "type": "string" 12 | }, 13 | "body": { 14 | "type": "string" 15 | }, 16 | "posted": { 17 | "type": "date" 18 | } 19 | }, 20 | "validations": [], 21 | "relations": {}, 22 | "acls": [], 23 | "methods": {} 24 | } 25 | -------------------------------------------------------------------------------- /blog1/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "blog1", 3 | "version": "1.0.0", 4 | "main": "server/server.js", 5 | "scripts": { 6 | "pretest": "jshint ." 7 | }, 8 | "dependencies": { 9 | "chalk": "^1.1.1", 10 | "compression": "^1.0.3", 11 | "cors": "^2.5.2", 12 | "express-handlebars": "^2.0.1", 13 | "handlebars-helper-moment": "^0.2.0", 14 | "loopback": "^2.22.0", 15 | "loopback-boot": "^2.6.5", 16 | "loopback-component-explorer": "^2.1.0", 17 | "loopback-connector-mongodb": "^1.13.2", 18 | "loopback-datasource-juggler": "^2.39.0", 19 | "moment": "^2.11.0", 20 | "serve-favicon": "^2.0.1" 21 | }, 22 | "devDependencies": { 23 | "jshint": "^2.5.6" 24 | }, 25 | "repository": { 26 | "type": "", 27 | "url": "" 28 | }, 29 | "description": "blog1" 30 | } 31 | -------------------------------------------------------------------------------- /blog1/server/boot/01seed.js: -------------------------------------------------------------------------------- 1 | 2 | var chalk = require('chalk'); 3 | 4 | console.log(chalk.magenta('Lets seed this app!')); 5 | 6 | /* 7 | This script is based on: 8 | https://github.com/strongloop-training/coffee-time/blob/master/server/boot/create-sample-model-data.js 9 | */ 10 | 11 | module.exports = function(app) { 12 | 13 | //sample data 14 | var data = [ 15 | { 16 | title:'Content One', 17 | body:'Body One', 18 | posted:new Date() 19 | }, 20 | { 21 | title:'Content Two', 22 | body:"Body Two", 23 | posted:new Date() 24 | }, 25 | { 26 | title:'Content Three', 27 | body:'Body Three', 28 | posted:new Date() 29 | } 30 | ]; 31 | 32 | app.models.TestContent.create(data, function(err, records) { 33 | if (err) { return console.log(chalk.red(err.message)); } 34 | console.log(chalk.magenta('Done seeding data, '+records.length+' records created.')); 35 | }); 36 | 37 | 38 | } -------------------------------------------------------------------------------- /blog1/server/boot/authentication.js: -------------------------------------------------------------------------------- 1 | module.exports = function enableAuthentication(server) { 2 | // enable authentication 3 | server.enableAuth(); 4 | }; 5 | -------------------------------------------------------------------------------- /blog1/server/boot/routes.js: -------------------------------------------------------------------------------- 1 | module.exports = function(app) { 2 | // Install a `/` route that returns server status 3 | //var router = server.loopback.Router(); 4 | //router.get('/', server.loopback.status()); 5 | //server.use(router); 6 | 7 | app.get('/', function(req, res) { 8 | console.log('getting blog entries'); 9 | app.models.entry.find({where:{released:true},order:'published desc'}).then(function(entries) { 10 | res.render('index',{entries:entries}); 11 | }); 12 | }); 13 | 14 | app.get('/:year/:month/:day/:slug', function(req, res) { 15 | console.log('do blog entry'); 16 | console.dir(req.params); 17 | //create an upper and lower date range 18 | var lowerDate = new Date(req.params.year, req.params.month-1, req.params.day); 19 | var upperDate = new Date(lowerDate); 20 | upperDate.setDate(upperDate.getDate()+1); 21 | app.models.entry.findOne({where:{ 22 | released:true, 23 | slug:req.params.slug, 24 | published:{between:[lowerDate,upperDate]} 25 | },limit:1}).then(function(entry) { 26 | //first - did we get any? 27 | if(!entry) { 28 | res.redirect('/'); 29 | } 30 | res.render('entry', {entry:entry}); 31 | }); 32 | }); 33 | }; 34 | -------------------------------------------------------------------------------- /blog1/server/component-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "loopback-component-explorer": { 3 | "mountPath": "/explorer" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /blog1/server/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "restApiRoot": "/api", 3 | "host": "0.0.0.0", 4 | "port": 3000, 5 | "remoting": { 6 | "context": { 7 | "enableHttpContext": false 8 | }, 9 | "rest": { 10 | "normalizeHttpPath": false, 11 | "xml": false 12 | }, 13 | "json": { 14 | "strict": false, 15 | "limit": "100kb" 16 | }, 17 | "urlencoded": { 18 | "extended": true, 19 | "limit": "100kb" 20 | }, 21 | "cors": false, 22 | "errorHandler": { 23 | "disableStackTrace": false 24 | } 25 | }, 26 | "legacyExplorer": false 27 | } 28 | -------------------------------------------------------------------------------- /blog1/server/datasources.json: -------------------------------------------------------------------------------- 1 | { 2 | "db": { 3 | "name": "db", 4 | "connector": "memory" 5 | }, 6 | "blogdata": { 7 | "host": "localhost", 8 | "port": 27017, 9 | "database": "blogdata", 10 | "name": "blogdata", 11 | "connector": "mongodb" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /blog1/server/middleware.json: -------------------------------------------------------------------------------- 1 | { 2 | "initial:before": { 3 | "loopback#favicon": {} 4 | }, 5 | "initial": { 6 | "compression": {}, 7 | "cors": { 8 | "params": { 9 | "origin": true, 10 | "credentials": true, 11 | "maxAge": 86400 12 | } 13 | } 14 | }, 15 | "session": {}, 16 | "auth": {}, 17 | "parse": {}, 18 | "routes": { 19 | "loopback#rest": { 20 | "paths": [ 21 | "${restApiRoot}" 22 | ] 23 | } 24 | }, 25 | "files": {}, 26 | "final": { 27 | "loopback#urlNotFound": {} 28 | }, 29 | "final:after": { 30 | "loopback#errorHandler": {} 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /blog1/server/middleware.production.json: -------------------------------------------------------------------------------- 1 | { 2 | "final:after": { 3 | "loopback#errorHandler": { 4 | "params": { 5 | "includeStack": false 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /blog1/server/model-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "sources": [ 4 | "loopback/common/models", 5 | "loopback/server/models", 6 | "../common/models", 7 | "./models" 8 | ], 9 | "mixins": [ 10 | "loopback/common/mixins", 11 | "loopback/server/mixins", 12 | "../common/mixins", 13 | "./mixins" 14 | ] 15 | }, 16 | "User": { 17 | "dataSource": "db" 18 | }, 19 | "AccessToken": { 20 | "dataSource": "db", 21 | "public": false 22 | }, 23 | "ACL": { 24 | "dataSource": "db", 25 | "public": false 26 | }, 27 | "RoleMapping": { 28 | "dataSource": "db", 29 | "public": false 30 | }, 31 | "Role": { 32 | "dataSource": "db", 33 | "public": false 34 | }, 35 | "entry": { 36 | "dataSource": "blogdata", 37 | "public": true, 38 | "$promise": {}, 39 | "$resolved": true 40 | }, 41 | "category": { 42 | "dataSource": "blogdata", 43 | "public": true, 44 | "$promise": {}, 45 | "$resolved": true 46 | }, 47 | "testContent": { 48 | "dataSource": "db", 49 | "public": true, 50 | "$promise": {}, 51 | "$resolved": true 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /blog1/server/server.js: -------------------------------------------------------------------------------- 1 | var loopback = require('loopback'); 2 | var boot = require('loopback-boot'); 3 | 4 | var app = module.exports = loopback(); 5 | var exphbs = require('express-handlebars'); 6 | 7 | var hbs = exphbs.create({ 8 | defaultLayout:'main', 9 | helpers:require('handlebars-helper-moment')() 10 | }); 11 | 12 | app.engine('handlebars', hbs.engine); 13 | app.set('view engine', 'handlebars'); 14 | 15 | app.start = function() { 16 | // start the web server 17 | return app.listen(function() { 18 | app.emit('started'); 19 | var baseUrl = app.get('url').replace(/\/$/, ''); 20 | console.log('Web server listening at: %s', baseUrl); 21 | if (app.get('loopback-component-explorer')) { 22 | var explorerPath = app.get('loopback-component-explorer').mountPath; 23 | console.log('Browse your REST API at %s%s', baseUrl, explorerPath); 24 | } 25 | }); 26 | }; 27 | 28 | // Bootstrap the application, configure models, datasources and middleware. 29 | // Sub-apps like REST API are mounted via boot scripts. 30 | boot(app, __dirname, function(err) { 31 | if (err) throw err; 32 | 33 | // start the server if `$ node server.js` 34 | if (require.main === module) 35 | app.start(); 36 | }); 37 | 38 | -------------------------------------------------------------------------------- /blog1/server/views/entry.handlebars: -------------------------------------------------------------------------------- 1 | 2 |

{{entry.title}}

3 |

4 | Published: {{moment published format="MMMM D, YYYY h:mm A"}} 5 |

6 | 7 | {{{entry.body}}} -------------------------------------------------------------------------------- /blog1/server/views/index.handlebars: -------------------------------------------------------------------------------- 1 | 2 | 3 |

Entries

4 | 5 | {{#each entries}} 6 |

7 | {{title}}
8 | Published: {{moment published format="MMMM D, YYYY h:mm A"}} 9 |

10 | 11 | {{/each}} -------------------------------------------------------------------------------- /blog1/server/views/layouts/main.handlebars: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 18 | 19 |
20 |
21 | 22 |
23 | 24 | My Blog 25 |
26 |
28 | 32 |
33 | 35 |
36 |
37 |
38 | 39 |
40 |
41 | 42 | 48 |
49 |
50 |
51 | Menu 52 | 58 |
59 |
60 |
61 | 62 |
63 |
64 |
{{{body}}}
65 |
66 |
67 | 68 |
69 |
70 |
71 | 72 | 73 | -------------------------------------------------------------------------------- /blog2/.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # http://editorconfig.org 4 | 5 | root = true 6 | 7 | [*] 8 | indent_style = space 9 | indent_size = 2 10 | end_of_line = lf 11 | charset = utf-8 12 | trim_trailing_whitespace = true 13 | insert_final_newline = true 14 | -------------------------------------------------------------------------------- /blog2/.gitignore: -------------------------------------------------------------------------------- 1 | *.csv 2 | *.dat 3 | *.iml 4 | *.log 5 | *.out 6 | *.pid 7 | *.seed 8 | *.sublime-* 9 | *.swo 10 | *.swp 11 | *.tgz 12 | *.xml 13 | .DS_Store 14 | .idea 15 | .project 16 | .strong-pm 17 | coverage 18 | node_modules 19 | npm-debug.log 20 | -------------------------------------------------------------------------------- /blog2/.jshintignore: -------------------------------------------------------------------------------- 1 | /client/ 2 | /node_modules/ 3 | -------------------------------------------------------------------------------- /blog2/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "esnext": true, 4 | "bitwise": true, 5 | "camelcase": true, 6 | "eqeqeq": true, 7 | "eqnull": true, 8 | "immed": true, 9 | "indent": 2, 10 | "latedef": "nofunc", 11 | "newcap": true, 12 | "nonew": true, 13 | "noarg": true, 14 | "quotmark": "single", 15 | "regexp": true, 16 | "undef": true, 17 | "unused": false, 18 | "trailing": true, 19 | "sub": true, 20 | "maxlen": 80 21 | } 22 | -------------------------------------------------------------------------------- /blog2/.yo-rc.json: -------------------------------------------------------------------------------- 1 | { 2 | "generator-loopback": {} 3 | } -------------------------------------------------------------------------------- /blog2/README.md: -------------------------------------------------------------------------------- 1 | # My Application 2 | 3 | The project is generated by [LoopBack](http://loopback.io). -------------------------------------------------------------------------------- /blog2/client/README.md: -------------------------------------------------------------------------------- 1 | ## Client 2 | 3 | This is the place for your application front-end files. 4 | -------------------------------------------------------------------------------- /blog2/client/electron-quick-start/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /blog2/client/electron-quick-start/README.md: -------------------------------------------------------------------------------- 1 | # electron-quick-start 2 | 3 | **Clone and run for a quick way to see an Electron in action.** 4 | 5 | This is a minimal Electron application based on the [Quick Start Guide](http://electron.atom.io/docs/latest/tutorial/quick-start) within the Electron documentation. 6 | 7 | A basic Electron application needs just these files: 8 | 9 | - `index.html` - A web page to render. 10 | - `main.js` - Starts the app and creates a browser window to render HTML. 11 | - `package.json` - Points to the app's main file and lists its details and dependencies. 12 | 13 | You can learn more about each of these components within the [Quick Start Guide](http://electron.atom.io/docs/latest/tutorial/quick-start). 14 | 15 | ## To Use 16 | 17 | To clone and run this repository you'll need [Git](https://git-scm.com) and [Node.js](https://nodejs.org/en/download/) (which comes with [npm](http://npmjs.com)) installed on your computer. From your command line: 18 | 19 | ```bash 20 | # Clone this repository 21 | git clone https://github.com/atom/electron-quick-start 22 | # Go into the repository 23 | cd electron-quick-start 24 | # Install dependencies and run the app 25 | npm install && npm start 26 | ``` 27 | 28 | Learn more about Electron and its API in the [documentation](http://electron.atom.io/docs/latest). 29 | 30 | #### License [CC0 (Public Domain)](LICENSE.md) 31 | -------------------------------------------------------------------------------- /blog2/client/electron-quick-start/main.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const electron = require('electron'); 4 | // Module to control application life. 5 | const app = electron.app; 6 | // Module to create native browser window. 7 | const BrowserWindow = electron.BrowserWindow; 8 | 9 | // Keep a global reference of the window object, if you don't, the window will 10 | // be closed automatically when the JavaScript object is garbage collected. 11 | let mainWindow; 12 | 13 | function createWindow () { 14 | // Create the browser window. 15 | mainWindow = new BrowserWindow({width: 800, height: 600}); 16 | 17 | // and load the index.html of the app. 18 | mainWindow.loadURL('file://' + __dirname + '/www/index.html'); 19 | 20 | // Emitted when the window is closed. 21 | mainWindow.on('closed', function() { 22 | // Dereference the window object, usually you would store windows 23 | // in an array if your app supports multi windows, this is the time 24 | // when you should delete the corresponding element. 25 | mainWindow = null; 26 | }); 27 | } 28 | 29 | // This method will be called when Electron has finished 30 | // initialization and is ready to create browser windows. 31 | app.on('ready', createWindow); 32 | 33 | // Quit when all windows are closed. 34 | app.on('window-all-closed', function () { 35 | // On OS X it is common for applications and their menu bar 36 | // to stay active until the user quits explicitly with Cmd + Q 37 | if (process.platform !== 'darwin') { 38 | app.quit(); 39 | } 40 | }); 41 | 42 | app.on('activate', function () { 43 | // On OS X it's common to re-create a window in the app when the 44 | // dock icon is clicked and there are no other windows open. 45 | if (mainWindow === null) { 46 | createWindow(); 47 | } 48 | }); 49 | -------------------------------------------------------------------------------- /blog2/client/electron-quick-start/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "electron-quick-start", 3 | "version": "1.0.0", 4 | "description": "A minimal Electron application", 5 | "main": "main.js", 6 | "scripts": { 7 | "start": "electron main.js" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/atom/electron-quick-start.git" 12 | }, 13 | "keywords": [ 14 | "Electron", 15 | "quick", 16 | "start", 17 | "tutorial" 18 | ], 19 | "author": "GitHub", 20 | "license": "CC0-1.0", 21 | "bugs": { 22 | "url": "https://github.com/atom/electron-quick-start/issues" 23 | }, 24 | "homepage": "https://github.com/atom/electron-quick-start#readme", 25 | "devDependencies": { 26 | "electron-prebuilt": "^0.36.0" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /blog2/client/electron-quick-start/www/css/style.css: -------------------------------------------------------------------------------- 1 | /* Empty. Add your own CSS if you like */ 2 | -------------------------------------------------------------------------------- /blog2/client/electron-quick-start/www/img/ionic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cfjedimaster/StrongLoopDemos/615610a8c80c011176bd80a9883b4521fbee7caa/blog2/client/electron-quick-start/www/img/ionic.png -------------------------------------------------------------------------------- /blog2/client/electron-quick-start/www/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Blog Editor 7 | 8 | 9 | 10 | 11 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /blog2/client/electron-quick-start/www/js/app.js: -------------------------------------------------------------------------------- 1 | // Ionic Starter App 2 | 3 | // angular.module is a global place for creating, registering and retrieving Angular modules 4 | // 'starter' is the name of this angular module example (also set in a attribute in index.html) 5 | // the 2nd parameter is an array of 'requires' 6 | angular.module('starter', ['ionic','starter.controllers','starter.services','ngResource']) 7 | 8 | .config(function($stateProvider,$urlRouterProvider) { 9 | 10 | $stateProvider 11 | .state('root', { 12 | url:'/root', 13 | abstract:true, 14 | controller:'rootCtrl', 15 | template:'' 16 | }) 17 | .state('root.Login', { 18 | url:'/login', 19 | controller:'loginCtrl', 20 | templateUrl:'partials/login.html' 21 | }) 22 | .state('root.Home', { 23 | url:'/home', 24 | controller:'homeCtrl', 25 | templateUrl:'partials/home.html' 26 | }) 27 | .state('root.EditEntry', { 28 | url:'/editentry', 29 | controller:'entryCtrl', 30 | templateUrl:'partials/entry.html' 31 | }); 32 | 33 | $urlRouterProvider.otherwise('/root/login'); 34 | 35 | }) 36 | .run(function($ionicPlatform) { 37 | 38 | 39 | }) 40 | -------------------------------------------------------------------------------- /blog2/client/electron-quick-start/www/js/controllers.js: -------------------------------------------------------------------------------- 1 | angular.module('starter.controllers', []) 2 | 3 | .controller('rootCtrl', function($scope) { 4 | 5 | $scope.$on('$ionicView.afterEnter', function(ev, data) { 6 | ev.stopPropagation(); 7 | }); 8 | 9 | }) 10 | 11 | .controller('loginCtrl', ['$scope', '$rootScope', 'userService', '$state', '$http', 12 | function($scope, $rootScope, userService, $state, $http) { 13 | 14 | $scope.user = {username:'raymondcamden@gmail.com',password:'password'}; 15 | 16 | $scope.doLogin = function() { 17 | if($scope.user.username === '' || $scope.user.password === '') { 18 | return; 19 | } 20 | userService.login({email:$scope.user.username,password:$scope.user.password},function(res) { 21 | $rootScope.authToken = res.id; // don't really need to keep it 22 | $http.defaults.headers.common['Authorization'] = $rootScope.authToken; 23 | $state.go('root.Home'); 24 | },function(e) { 25 | //for right now - generic error 26 | alert('Login Failed'); 27 | }); 28 | }; 29 | 30 | }]) 31 | 32 | .controller('homeCtrl', ['$scope', '$rootScope', 'entryService', '$state', 33 | function($scope, $rootScope, entryService, state) { 34 | 35 | $scope.$on('$ionicView.enter', function() { 36 | entryService.query({"filter[order]":"published desc"},function(res) { 37 | $scope.entries = res; 38 | }, function(e) { 39 | console.log('bad '+JSON.stringify(e)); 40 | }); 41 | }); 42 | 43 | }]) 44 | .controller('entryCtrl', ['$scope', '$rootScope', 'entryService', '$state', 45 | function($scope, $rootScope, entryService, $state) { 46 | 47 | $scope.entry = {title:"",body:""}; 48 | 49 | $scope.doSave = function() { 50 | var postedDate = new Date(); 51 | 52 | var newEntry = new entryService(); 53 | newEntry.title = $scope.entry.title; 54 | newEntry.body = $scope.entry.body; 55 | newEntry.released = true; 56 | newEntry.published = new Date(); 57 | //not perfect... 58 | newEntry.slug = newEntry.title.replace(/ /g,'-'); 59 | newEntry.$save(); 60 | $state.go('root.Home'); 61 | 62 | } 63 | 64 | }]); 65 | -------------------------------------------------------------------------------- /blog2/client/electron-quick-start/www/js/services.js: -------------------------------------------------------------------------------- 1 | angular.module('starter.services', []) 2 | .factory('userService', function($q,$resource) { 3 | 4 | return $resource('http://localhost:3000/api/appusers/:id',{}, 5 | { 6 | 'login':{ 7 | 'method':'POST', 8 | 'url':'http://localhost:3000/api/appusers/login' 9 | } 10 | }); 11 | 12 | }) 13 | .factory('entryService', function($q,$resource) { 14 | 15 | return $resource('http://localhost:3000/api/entries/:id'); 16 | 17 | }); -------------------------------------------------------------------------------- /blog2/client/electron-quick-start/www/lib/ionic/fonts/ionicons.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cfjedimaster/StrongLoopDemos/615610a8c80c011176bd80a9883b4521fbee7caa/blog2/client/electron-quick-start/www/lib/ionic/fonts/ionicons.eot -------------------------------------------------------------------------------- /blog2/client/electron-quick-start/www/lib/ionic/fonts/ionicons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cfjedimaster/StrongLoopDemos/615610a8c80c011176bd80a9883b4521fbee7caa/blog2/client/electron-quick-start/www/lib/ionic/fonts/ionicons.ttf -------------------------------------------------------------------------------- /blog2/client/electron-quick-start/www/lib/ionic/fonts/ionicons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cfjedimaster/StrongLoopDemos/615610a8c80c011176bd80a9883b4521fbee7caa/blog2/client/electron-quick-start/www/lib/ionic/fonts/ionicons.woff -------------------------------------------------------------------------------- /blog2/client/electron-quick-start/www/lib/ionic/js/angular/angular-resource.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | AngularJS v1.4.3 3 | (c) 2010-2015 Google, Inc. http://angularjs.org 4 | License: MIT 5 | */ 6 | (function(I,d,B){'use strict';function D(f,q){q=q||{};d.forEach(q,function(d,h){delete q[h]});for(var h in f)!f.hasOwnProperty(h)||"$"===h.charAt(0)&&"$"===h.charAt(1)||(q[h]=f[h]);return q}var x=d.$$minErr("$resource"),C=/^(\.[a-zA-Z_$@][0-9a-zA-Z_$@]*)+$/;d.module("ngResource",["ng"]).provider("$resource",function(){var f=this;this.defaults={stripTrailingSlashes:!0,actions:{get:{method:"GET"},save:{method:"POST"},query:{method:"GET",isArray:!0},remove:{method:"DELETE"},"delete":{method:"DELETE"}}}; 7 | this.$get=["$http","$q",function(q,h){function u(d,g){this.template=d;this.defaults=s({},f.defaults,g);this.urlParams={}}function w(y,g,l,m){function c(b,k){var c={};k=s({},g,k);r(k,function(a,k){v(a)&&(a=a());var d;if(a&&a.charAt&&"@"==a.charAt(0)){d=b;var e=a.substr(1);if(null==e||""===e||"hasOwnProperty"===e||!C.test("."+e))throw x("badmember",e);for(var e=e.split("."),n=0,g=e.length;n .ng-enter { 10 | @include transition(all cubic-bezier(.1, .7, .1, 1) 400ms); 11 | } 12 | .slide-in-up.ng-enter-active, 13 | .slide-in-up > .ng-enter-active { 14 | @include translate3d(0, 0, 0); 15 | } 16 | 17 | .slide-in-up.ng-leave, 18 | .slide-in-up > .ng-leave { 19 | @include transition(all ease-in-out 250ms); 20 | } 21 | 22 | 23 | // Scale Out 24 | // Scale from hero (1 in this case) to zero 25 | // ------------------------------- 26 | 27 | @-webkit-keyframes scaleOut { 28 | from { -webkit-transform: scale(1); opacity: 1; } 29 | to { -webkit-transform: scale(0.8); opacity: 0; } 30 | } 31 | @keyframes scaleOut { 32 | from { transform: scale(1); opacity: 1; } 33 | to { transform: scale(0.8); opacity: 0; } 34 | } 35 | 36 | 37 | // Super Scale In 38 | // Scale from super (1.x) to duper (1 in this case) 39 | // ------------------------------- 40 | 41 | @-webkit-keyframes superScaleIn { 42 | from { -webkit-transform: scale(1.2); opacity: 0; } 43 | to { -webkit-transform: scale(1); opacity: 1 } 44 | } 45 | @keyframes superScaleIn { 46 | from { transform: scale(1.2); opacity: 0; } 47 | to { transform: scale(1); opacity: 1; } 48 | } 49 | -------------------------------------------------------------------------------- /blog2/client/electron-quick-start/www/lib/ionic/scss/_backdrop.scss: -------------------------------------------------------------------------------- 1 | 2 | .backdrop { 3 | position: fixed; 4 | top: 0; 5 | left: 0; 6 | z-index: $z-index-backdrop; 7 | 8 | width: 100%; 9 | height: 100%; 10 | 11 | background-color: $loading-backdrop-bg-color; 12 | 13 | visibility: hidden; 14 | opacity: 0; 15 | 16 | &.visible { 17 | visibility: visible; 18 | } 19 | &.active { 20 | opacity: 1; 21 | } 22 | 23 | @include transition($loading-backdrop-fadein-duration opacity linear); 24 | } 25 | -------------------------------------------------------------------------------- /blog2/client/electron-quick-start/www/lib/ionic/scss/_badge.scss: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Badges 4 | * -------------------------------------------------- 5 | */ 6 | 7 | .badge { 8 | @include badge-style($badge-default-bg, $badge-default-text); 9 | z-index: $z-index-badge; 10 | display: inline-block; 11 | padding: 3px 8px; 12 | min-width: 10px; 13 | border-radius: $badge-border-radius; 14 | vertical-align: baseline; 15 | text-align: center; 16 | white-space: nowrap; 17 | font-weight: $badge-font-weight; 18 | font-size: $badge-font-size; 19 | line-height: $badge-line-height; 20 | 21 | &:empty { 22 | display: none; 23 | } 24 | } 25 | 26 | //Be sure to override specificity of rule that 'badge color matches tab color by default' 27 | .tabs .tab-item .badge, 28 | .badge { 29 | &.badge-light { 30 | @include badge-style($badge-light-bg, $badge-light-text); 31 | } 32 | &.badge-stable { 33 | @include badge-style($badge-stable-bg, $badge-stable-text); 34 | } 35 | &.badge-positive { 36 | @include badge-style($badge-positive-bg, $badge-positive-text); 37 | } 38 | &.badge-calm { 39 | @include badge-style($badge-calm-bg, $badge-calm-text); 40 | } 41 | &.badge-assertive { 42 | @include badge-style($badge-assertive-bg, $badge-assertive-text); 43 | } 44 | &.badge-balanced { 45 | @include badge-style($badge-balanced-bg, $badge-balanced-text); 46 | } 47 | &.badge-energized { 48 | @include badge-style($badge-energized-bg, $badge-energized-text); 49 | } 50 | &.badge-royal { 51 | @include badge-style($badge-royal-bg, $badge-royal-text); 52 | } 53 | &.badge-dark { 54 | @include badge-style($badge-dark-bg, $badge-dark-text); 55 | } 56 | } 57 | 58 | // Quick fix for labels/badges in buttons 59 | .button .badge { 60 | position: relative; 61 | top: -1px; 62 | } 63 | -------------------------------------------------------------------------------- /blog2/client/electron-quick-start/www/lib/ionic/scss/_button-bar.scss: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Button Bar 4 | * -------------------------------------------------- 5 | */ 6 | 7 | .button-bar { 8 | @include display-flex(); 9 | @include flex(1); 10 | width: 100%; 11 | 12 | &.button-bar-inline { 13 | display: block; 14 | width: auto; 15 | 16 | @include clearfix(); 17 | 18 | > .button { 19 | width: auto; 20 | display: inline-block; 21 | float: left; 22 | } 23 | } 24 | } 25 | 26 | .button-bar > .button { 27 | @include flex(1); 28 | display: block; 29 | 30 | overflow: hidden; 31 | 32 | padding: 0 16px; 33 | 34 | width: 0; 35 | 36 | border-width: 1px 0px 1px 1px; 37 | border-radius: 0; 38 | text-align: center; 39 | text-overflow: ellipsis; 40 | white-space: nowrap; 41 | 42 | &:before, 43 | .icon:before { 44 | line-height: 44px; 45 | } 46 | 47 | &:first-child { 48 | border-radius: $button-border-radius 0px 0px $button-border-radius; 49 | } 50 | &:last-child { 51 | border-right-width: 1px; 52 | border-radius: 0px $button-border-radius $button-border-radius 0px; 53 | } 54 | &:only-child { 55 | border-radius: $button-border-radius; 56 | } 57 | } 58 | 59 | .button-bar > .button-small { 60 | &:before, 61 | .icon:before { 62 | line-height: 28px; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /blog2/client/electron-quick-start/www/lib/ionic/scss/_grid.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Grid 3 | * -------------------------------------------------- 4 | * Using flexbox for the grid, inspired by Philip Walton: 5 | * http://philipwalton.github.io/solved-by-flexbox/demos/grids/ 6 | * By default each .col within a .row will evenly take up 7 | * available width, and the height of each .col with take 8 | * up the height of the tallest .col in the same .row. 9 | */ 10 | 11 | .row { 12 | @include display-flex(); 13 | padding: ($grid-padding-width / 2); 14 | width: 100%; 15 | } 16 | 17 | .row-wrap { 18 | @include flex-wrap(wrap); 19 | } 20 | 21 | .row-no-padding { 22 | padding: 0; 23 | 24 | > .col { 25 | padding: 0; 26 | } 27 | } 28 | 29 | .row + .row { 30 | margin-top: ($grid-padding-width / 2) * -1; 31 | padding-top: 0; 32 | } 33 | 34 | .col { 35 | @include flex(1); 36 | display: block; 37 | padding: ($grid-padding-width / 2); 38 | width: 100%; 39 | } 40 | 41 | 42 | /* Vertically Align Columns */ 43 | /* .row-* vertically aligns every .col in the .row */ 44 | .row-top { 45 | @include align-items(flex-start); 46 | } 47 | .row-bottom { 48 | @include align-items(flex-end); 49 | } 50 | .row-center { 51 | @include align-items(center); 52 | } 53 | .row-stretch { 54 | @include align-items(stretch); 55 | } 56 | .row-baseline { 57 | @include align-items(baseline); 58 | } 59 | 60 | /* .col-* vertically aligns an individual .col */ 61 | .col-top { 62 | @include align-self(flex-start); 63 | } 64 | .col-bottom { 65 | @include align-self(flex-end); 66 | } 67 | .col-center { 68 | @include align-self(center); 69 | } 70 | 71 | /* Column Offsets */ 72 | .col-offset-10 { 73 | margin-left: 10%; 74 | } 75 | .col-offset-20 { 76 | margin-left: 20%; 77 | } 78 | .col-offset-25 { 79 | margin-left: 25%; 80 | } 81 | .col-offset-33, .col-offset-34 { 82 | margin-left: 33.3333%; 83 | } 84 | .col-offset-50 { 85 | margin-left: 50%; 86 | } 87 | .col-offset-66, .col-offset-67 { 88 | margin-left: 66.6666%; 89 | } 90 | .col-offset-75 { 91 | margin-left: 75%; 92 | } 93 | .col-offset-80 { 94 | margin-left: 80%; 95 | } 96 | .col-offset-90 { 97 | margin-left: 90%; 98 | } 99 | 100 | 101 | /* Explicit Column Percent Sizes */ 102 | /* By default each grid column will evenly distribute */ 103 | /* across the grid. However, you can specify individual */ 104 | /* columns to take up a certain size of the available area */ 105 | .col-10 { 106 | @include flex(0, 0, 10%); 107 | max-width: 10%; 108 | } 109 | .col-20 { 110 | @include flex(0, 0, 20%); 111 | max-width: 20%; 112 | } 113 | .col-25 { 114 | @include flex(0, 0, 25%); 115 | max-width: 25%; 116 | } 117 | .col-33, .col-34 { 118 | @include flex(0, 0, 33.3333%); 119 | max-width: 33.3333%; 120 | } 121 | .col-40 { 122 | @include flex(0, 0, 40%); 123 | max-width: 40%; 124 | } 125 | .col-50 { 126 | @include flex(0, 0, 50%); 127 | max-width: 50%; 128 | } 129 | .col-60 { 130 | @include flex(0, 0, 60%); 131 | max-width: 60%; 132 | } 133 | .col-66, .col-67 { 134 | @include flex(0, 0, 66.6666%); 135 | max-width: 66.6666%; 136 | } 137 | .col-75 { 138 | @include flex(0, 0, 75%); 139 | max-width: 75%; 140 | } 141 | .col-80 { 142 | @include flex(0, 0, 80%); 143 | max-width: 80%; 144 | } 145 | .col-90 { 146 | @include flex(0, 0, 90%); 147 | max-width: 90%; 148 | } 149 | 150 | 151 | /* Responsive Grid Classes */ 152 | /* Adding a class of responsive-X to a row */ 153 | /* will trigger the flex-direction to */ 154 | /* change to column and add some margin */ 155 | /* to any columns in the row for clearity */ 156 | 157 | @include responsive-grid-break('.responsive-sm', $grid-responsive-sm-break); 158 | @include responsive-grid-break('.responsive-md', $grid-responsive-md-break); 159 | @include responsive-grid-break('.responsive-lg', $grid-responsive-lg-break); 160 | -------------------------------------------------------------------------------- /blog2/client/electron-quick-start/www/lib/ionic/scss/_list.scss: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Lists 4 | * -------------------------------------------------- 5 | */ 6 | 7 | .list { 8 | position: relative; 9 | padding-top: $item-border-width; 10 | padding-bottom: $item-border-width; 11 | padding-left: 0; // reset padding because ul and ol 12 | margin-bottom: 20px; 13 | } 14 | .list:last-child { 15 | margin-bottom: 0px; 16 | &.card{ 17 | margin-bottom:40px; 18 | } 19 | } 20 | 21 | 22 | /** 23 | * List Header 24 | * -------------------------------------------------- 25 | */ 26 | 27 | .list-header { 28 | margin-top: $list-header-margin-top; 29 | padding: $list-header-padding; 30 | background-color: $list-header-bg; 31 | color: $list-header-color; 32 | font-weight: bold; 33 | } 34 | 35 | // when its a card make sure it doesn't duplicate top and bottom borders 36 | .card.list .list-item { 37 | padding-right: 1px; 38 | padding-left: 1px; 39 | } 40 | 41 | 42 | /** 43 | * Cards and Inset Lists 44 | * -------------------------------------------------- 45 | * A card and list-inset are close to the same thing, except a card as a box shadow. 46 | */ 47 | 48 | .card, 49 | .list-inset { 50 | overflow: hidden; 51 | margin: ($content-padding * 2) $content-padding; 52 | border-radius: $card-border-radius; 53 | background-color: $card-body-bg; 54 | } 55 | 56 | .card { 57 | padding-top: $item-border-width; 58 | padding-bottom: $item-border-width; 59 | box-shadow: $card-box-shadow; 60 | 61 | .item { 62 | border-left: 0; 63 | border-right: 0; 64 | } 65 | .item:first-child { 66 | border-top: 0; 67 | } 68 | .item:last-child { 69 | border-bottom: 0; 70 | } 71 | } 72 | 73 | .padding { 74 | .card, .list-inset { 75 | margin-left: 0; 76 | margin-right: 0; 77 | } 78 | } 79 | 80 | .card .item, 81 | .list-inset .item, 82 | .padding > .list .item 83 | { 84 | &:first-child { 85 | border-top-left-radius: $card-border-radius; 86 | border-top-right-radius: $card-border-radius; 87 | 88 | .item-content { 89 | border-top-left-radius: $card-border-radius; 90 | border-top-right-radius: $card-border-radius; 91 | } 92 | } 93 | &:last-child { 94 | border-bottom-right-radius: $card-border-radius; 95 | border-bottom-left-radius: $card-border-radius; 96 | 97 | .item-content { 98 | border-bottom-right-radius: $card-border-radius; 99 | border-bottom-left-radius: $card-border-radius; 100 | } 101 | } 102 | } 103 | 104 | .card .item:last-child, 105 | .list-inset .item:last-child { 106 | margin-bottom: $item-border-width * -1; 107 | } 108 | 109 | .card .item, 110 | .list-inset .item, 111 | .padding > .list .item, 112 | .padding-horizontal > .list .item { 113 | margin-right: 0; 114 | margin-left: 0; 115 | 116 | &.item-input input { 117 | padding-right: 44px; 118 | } 119 | } 120 | .padding-left > .list .item { 121 | margin-left: 0; 122 | } 123 | .padding-right > .list .item { 124 | margin-right: 0; 125 | } 126 | -------------------------------------------------------------------------------- /blog2/client/electron-quick-start/www/lib/ionic/scss/_loading.scss: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Loading 4 | * -------------------------------------------------- 5 | */ 6 | 7 | .loading-container { 8 | position: absolute; 9 | left: 0; 10 | top: 0; 11 | right: 0; 12 | bottom: 0; 13 | 14 | z-index: $z-index-loading; 15 | 16 | @include display-flex(); 17 | @include justify-content(center); 18 | @include align-items(center); 19 | 20 | @include transition(0.2s opacity linear); 21 | visibility: hidden; 22 | opacity: 0; 23 | 24 | &:not(.visible) .icon, 25 | &:not(.visible) .spinner{ 26 | display: none; 27 | } 28 | &.visible { 29 | visibility: visible; 30 | } 31 | &.active { 32 | opacity: 1; 33 | } 34 | 35 | .loading { 36 | padding: $loading-padding; 37 | 38 | border-radius: $loading-border-radius; 39 | background-color: $loading-bg-color; 40 | 41 | color: $loading-text-color; 42 | 43 | text-align: center; 44 | text-overflow: ellipsis; 45 | font-size: $loading-font-size; 46 | 47 | h1, h2, h3, h4, h5, h6 { 48 | color: $loading-text-color; 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /blog2/client/electron-quick-start/www/lib/ionic/scss/_menu.scss: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Menus 4 | * -------------------------------------------------- 5 | * Side panel structure 6 | */ 7 | 8 | .menu { 9 | position: absolute; 10 | top: 0; 11 | bottom: 0; 12 | z-index: $z-index-menu; 13 | overflow: hidden; 14 | 15 | min-height: 100%; 16 | max-height: 100%; 17 | width: $menu-width; 18 | 19 | background-color: $menu-bg; 20 | 21 | .scroll-content { 22 | z-index: $z-index-menu-scroll-content; 23 | } 24 | 25 | .bar-header { 26 | z-index: $z-index-menu-bar-header; 27 | } 28 | } 29 | 30 | .menu-content { 31 | @include transform(none); 32 | box-shadow: $menu-side-shadow; 33 | } 34 | 35 | .menu-open .menu-content .pane, 36 | .menu-open .menu-content .scroll-content { 37 | pointer-events: none; 38 | } 39 | .menu-open .menu-content .scroll-content .scroll { 40 | pointer-events: none; 41 | } 42 | .menu-open .menu-content .scroll-content:not(.overflow-scroll) { 43 | overflow: hidden; 44 | } 45 | 46 | .grade-b .menu-content, 47 | .grade-c .menu-content { 48 | @include box-sizing(content-box); 49 | right: -1px; 50 | left: -1px; 51 | border-right: 1px solid #ccc; 52 | border-left: 1px solid #ccc; 53 | box-shadow: none; 54 | } 55 | 56 | .menu-left { 57 | left: 0; 58 | } 59 | 60 | .menu-right { 61 | right: 0; 62 | } 63 | 64 | .aside-open.aside-resizing .menu-right { 65 | display: none; 66 | } 67 | 68 | .menu-animated { 69 | @include transition-transform($menu-animation-speed ease); 70 | } 71 | -------------------------------------------------------------------------------- /blog2/client/electron-quick-start/www/lib/ionic/scss/_modal.scss: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Modals 4 | * -------------------------------------------------- 5 | * Modals are independent windows that slide in from off-screen. 6 | */ 7 | 8 | .modal-backdrop, 9 | .modal-backdrop-bg { 10 | position: fixed; 11 | top: 0; 12 | left: 0; 13 | z-index: $z-index-modal; 14 | width: 100%; 15 | height: 100%; 16 | } 17 | 18 | .modal-backdrop-bg { 19 | pointer-events: none; 20 | } 21 | 22 | .modal { 23 | display: block; 24 | position: absolute; 25 | top: 0; 26 | z-index: $z-index-modal; 27 | overflow: hidden; 28 | min-height: 100%; 29 | width: 100%; 30 | background-color: $modal-bg-color; 31 | } 32 | 33 | @media (min-width: $modal-inset-mode-break-point) { 34 | // inset mode is when the modal doesn't fill the entire 35 | // display but instead is centered within a large display 36 | .modal { 37 | top: $modal-inset-mode-top; 38 | right: $modal-inset-mode-right; 39 | bottom: $modal-inset-mode-bottom; 40 | left: $modal-inset-mode-left; 41 | min-height: $modal-inset-mode-min-height; 42 | width: (100% - $modal-inset-mode-left - $modal-inset-mode-right); 43 | } 44 | 45 | .modal.ng-leave-active { 46 | bottom: 0; 47 | } 48 | 49 | // remove ios header padding from inset header 50 | .platform-ios.platform-cordova .modal-wrapper .modal { 51 | .bar-header:not(.bar-subheader) { 52 | height: $bar-height; 53 | > * { 54 | margin-top: 0; 55 | } 56 | } 57 | .tabs-top > .tabs, 58 | .tabs.tabs-top { 59 | top: $bar-height; 60 | } 61 | .has-header, 62 | .bar-subheader { 63 | top: $bar-height; 64 | } 65 | .has-subheader { 66 | top: $bar-height + $bar-subheader-height; 67 | } 68 | .has-header.has-tabs-top { 69 | top: $bar-height + $tabs-height; 70 | } 71 | .has-header.has-subheader.has-tabs-top { 72 | top: $bar-height + $bar-subheader-height + $tabs-height; 73 | } 74 | } 75 | 76 | .modal-backdrop-bg { 77 | @include transition(opacity 300ms ease-in-out); 78 | background-color: $modal-backdrop-bg-active; 79 | opacity: 0; 80 | } 81 | 82 | .active .modal-backdrop-bg { 83 | opacity: 0.5; 84 | } 85 | } 86 | 87 | // disable clicks on all but the modal 88 | .modal-open { 89 | pointer-events: none; 90 | 91 | .modal, 92 | .modal-backdrop { 93 | pointer-events: auto; 94 | } 95 | // prevent clicks on modal when loading overlay is active though 96 | &.loading-active { 97 | .modal, 98 | .modal-backdrop { 99 | pointer-events: none; 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /blog2/client/electron-quick-start/www/lib/ionic/scss/_platform.scss: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Platform 4 | * -------------------------------------------------- 5 | * Platform specific tweaks 6 | */ 7 | 8 | .platform-ios.platform-cordova { 9 | // iOS has a status bar which sits on top of the header. 10 | // Bump down everything to make room for it. However, if 11 | // if its in Cordova, and set to fullscreen, then disregard the bump. 12 | &:not(.fullscreen) { 13 | .bar-header:not(.bar-subheader) { 14 | height: $bar-height + $ios-statusbar-height; 15 | 16 | &.item-input-inset .item-input-wrapper { 17 | margin-top: 19px !important; 18 | } 19 | 20 | > * { 21 | margin-top: $ios-statusbar-height; 22 | } 23 | } 24 | .tabs-top > .tabs, 25 | .tabs.tabs-top { 26 | top: $bar-height + $ios-statusbar-height; 27 | } 28 | 29 | .has-header, 30 | .bar-subheader { 31 | top: $bar-height + $ios-statusbar-height; 32 | } 33 | .has-subheader { 34 | top: $bar-height + $bar-subheader-height + $ios-statusbar-height; 35 | } 36 | .has-header.has-tabs-top { 37 | top: $bar-height + $tabs-height + $ios-statusbar-height; 38 | } 39 | .has-header.has-subheader.has-tabs-top { 40 | top: $bar-height + $bar-subheader-height + $tabs-height + $ios-statusbar-height; 41 | } 42 | } 43 | .popover{ 44 | .bar-header:not(.bar-subheader) { 45 | height: $bar-height; 46 | &.item-input-inset .item-input-wrapper { 47 | margin-top: -1px; 48 | } 49 | > * { 50 | margin-top: 0; 51 | } 52 | } 53 | .has-header, 54 | .bar-subheader { 55 | top: $bar-height; 56 | } 57 | .has-subheader { 58 | top: $bar-height + $bar-subheader-height; 59 | } 60 | } 61 | &.status-bar-hide { 62 | // Cordova doesn't adjust the body height correctly, this makes up for it 63 | margin-bottom: 20px; 64 | } 65 | } 66 | 67 | @media (orientation:landscape) { 68 | .platform-ios.platform-browser.platform-ipad { 69 | position: fixed; // required for iPad 7 Safari 70 | } 71 | } 72 | 73 | .platform-c:not(.enable-transitions) * { 74 | // disable transitions on grade-c devices (Android 2) 75 | -webkit-transition: none !important; 76 | transition: none !important; 77 | } 78 | -------------------------------------------------------------------------------- /blog2/client/electron-quick-start/www/lib/ionic/scss/_popover.scss: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Popovers 4 | * -------------------------------------------------- 5 | * Popovers are independent views which float over content 6 | */ 7 | 8 | .popover-backdrop { 9 | position: fixed; 10 | top: 0; 11 | left: 0; 12 | z-index: $z-index-popover; 13 | width: 100%; 14 | height: 100%; 15 | background-color: $popover-backdrop-bg-inactive; 16 | 17 | &.active { 18 | background-color: $popover-backdrop-bg-active; 19 | } 20 | } 21 | 22 | .popover { 23 | position: absolute; 24 | top: 25%; 25 | left: 50%; 26 | z-index: $z-index-popover; 27 | display: block; 28 | margin-top: 12px; 29 | margin-left: -$popover-width / 2; 30 | height: $popover-height; 31 | width: $popover-width; 32 | background-color: $popover-bg-color; 33 | box-shadow: $popover-box-shadow; 34 | opacity: 0; 35 | 36 | .item:first-child { 37 | border-top: 0; 38 | } 39 | 40 | .item:last-child { 41 | border-bottom: 0; 42 | } 43 | 44 | &.popover-bottom { 45 | margin-top: -12px; 46 | } 47 | } 48 | 49 | 50 | // Set popover border-radius 51 | .popover, 52 | .popover .bar-header { 53 | border-radius: $popover-border-radius; 54 | } 55 | .popover .scroll-content { 56 | z-index: 1; 57 | margin: 2px 0; 58 | } 59 | .popover .bar-header { 60 | border-bottom-right-radius: 0; 61 | border-bottom-left-radius: 0; 62 | } 63 | .popover .has-header { 64 | border-top-right-radius: 0; 65 | border-top-left-radius: 0; 66 | } 67 | .popover-arrow { 68 | display: none; 69 | } 70 | 71 | 72 | // iOS Popover 73 | .platform-ios { 74 | 75 | .popover { 76 | box-shadow: $popover-box-shadow-ios; 77 | border-radius: $popover-border-radius-ios; 78 | } 79 | .popover .bar-header { 80 | @include border-top-radius($popover-border-radius-ios); 81 | } 82 | .popover .scroll-content { 83 | margin: 8px 0; 84 | border-radius: $popover-border-radius-ios; 85 | } 86 | .popover .scroll-content.has-header { 87 | margin-top: 0; 88 | } 89 | .popover-arrow { 90 | position: absolute; 91 | display: block; 92 | top: -17px; 93 | width: 30px; 94 | height: 19px; 95 | overflow: hidden; 96 | 97 | &:after { 98 | position: absolute; 99 | top: 12px; 100 | left: 5px; 101 | width: 20px; 102 | height: 20px; 103 | background-color: $popover-bg-color; 104 | border-radius: 3px; 105 | content: ''; 106 | @include rotate(-45deg); 107 | } 108 | } 109 | .popover-bottom .popover-arrow { 110 | top: auto; 111 | bottom: -10px; 112 | &:after { 113 | top: -6px; 114 | } 115 | } 116 | } 117 | 118 | 119 | // Android Popover 120 | .platform-android { 121 | 122 | .popover { 123 | margin-top: -32px; 124 | background-color: $popover-bg-color-android; 125 | box-shadow: $popover-box-shadow-android; 126 | 127 | .item { 128 | border-color: $popover-bg-color-android; 129 | background-color: $popover-bg-color-android; 130 | color: #4d4d4d; 131 | } 132 | &.popover-bottom { 133 | margin-top: 32px; 134 | } 135 | } 136 | 137 | .popover-backdrop, 138 | .popover-backdrop.active { 139 | background-color: transparent; 140 | } 141 | } 142 | 143 | 144 | // disable clicks on all but the popover 145 | .popover-open { 146 | pointer-events: none; 147 | 148 | .popover, 149 | .popover-backdrop { 150 | pointer-events: auto; 151 | } 152 | // prevent clicks on popover when loading overlay is active though 153 | &.loading-active { 154 | .popover, 155 | .popover-backdrop { 156 | pointer-events: none; 157 | } 158 | } 159 | } 160 | 161 | 162 | // wider popover on larger viewports 163 | @media (min-width: $popover-large-break-point) { 164 | .popover { 165 | width: $popover-large-width; 166 | margin-left: -$popover-large-width / 2; 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /blog2/client/electron-quick-start/www/lib/ionic/scss/_popup.scss: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Popups 4 | * -------------------------------------------------- 5 | */ 6 | 7 | .popup-container { 8 | position: absolute; 9 | top: 0; 10 | left: 0; 11 | bottom: 0; 12 | right: 0; 13 | background: rgba(0,0,0,0); 14 | 15 | @include display-flex(); 16 | @include justify-content(center); 17 | @include align-items(center); 18 | 19 | z-index: $z-index-popup; 20 | 21 | // Start hidden 22 | visibility: hidden; 23 | &.popup-showing { 24 | visibility: visible; 25 | } 26 | 27 | &.popup-hidden .popup { 28 | @include animation-name(scaleOut); 29 | @include animation-duration($popup-leave-animation-duration); 30 | @include animation-timing-function(ease-in-out); 31 | @include animation-fill-mode(both); 32 | } 33 | 34 | &.active .popup { 35 | @include animation-name(superScaleIn); 36 | @include animation-duration($popup-enter-animation-duration); 37 | @include animation-timing-function(ease-in-out); 38 | @include animation-fill-mode(both); 39 | } 40 | 41 | .popup { 42 | width: $popup-width; 43 | max-width: 100%; 44 | max-height: 90%; 45 | 46 | border-radius: $popup-border-radius; 47 | background-color: $popup-background-color; 48 | 49 | @include display-flex(); 50 | @include flex-direction(column); 51 | } 52 | 53 | input, 54 | textarea { 55 | width: 100%; 56 | } 57 | } 58 | 59 | .popup-head { 60 | padding: 15px 10px; 61 | border-bottom: 1px solid #eee; 62 | text-align: center; 63 | } 64 | .popup-title { 65 | margin: 0; 66 | padding: 0; 67 | font-size: 15px; 68 | } 69 | .popup-sub-title { 70 | margin: 5px 0 0 0; 71 | padding: 0; 72 | font-weight: normal; 73 | font-size: 11px; 74 | } 75 | .popup-body { 76 | padding: 10px; 77 | overflow: auto; 78 | } 79 | 80 | .popup-buttons { 81 | @include display-flex(); 82 | @include flex-direction(row); 83 | padding: 10px; 84 | min-height: $popup-button-min-height + 20; 85 | 86 | .button { 87 | @include flex(1); 88 | display: block; 89 | min-height: $popup-button-min-height; 90 | border-radius: $popup-button-border-radius; 91 | line-height: $popup-button-line-height; 92 | 93 | margin-right: 5px; 94 | &:last-child { 95 | margin-right: 0px; 96 | } 97 | } 98 | } 99 | 100 | .popup-open { 101 | pointer-events: none; 102 | 103 | &.modal-open .modal { 104 | pointer-events: none; 105 | } 106 | 107 | .popup-backdrop, .popup { 108 | pointer-events: auto; 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /blog2/client/electron-quick-start/www/lib/ionic/scss/_progress.scss: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Progress 4 | * -------------------------------------------------- 5 | */ 6 | 7 | progress { 8 | display: block; 9 | margin: $progress-margin; 10 | width: $progress-width; 11 | } 12 | -------------------------------------------------------------------------------- /blog2/client/electron-quick-start/www/lib/ionic/scss/_radio.scss: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Radio Button Inputs 4 | * -------------------------------------------------- 5 | */ 6 | 7 | .item-radio { 8 | padding: 0; 9 | 10 | &:hover { 11 | cursor: pointer; 12 | } 13 | } 14 | 15 | .item-radio .item-content { 16 | /* give some room to the right for the checkmark icon */ 17 | padding-right: $item-padding * 4; 18 | } 19 | 20 | .item-radio .radio-icon { 21 | /* checkmark icon will be hidden by default */ 22 | position: absolute; 23 | top: 0; 24 | right: 0; 25 | z-index: $z-index-item-radio; 26 | visibility: hidden; 27 | padding: $item-padding - 2; 28 | height: 100%; 29 | font-size: 24px; 30 | } 31 | 32 | .item-radio input { 33 | /* hide any radio button inputs elements (the ugly circles) */ 34 | position: absolute; 35 | left: -9999px; 36 | 37 | &:checked + .radio-content .item-content { 38 | /* style the item content when its checked */ 39 | background: #f7f7f7; 40 | } 41 | 42 | &:checked + .radio-content .radio-icon { 43 | /* show the checkmark icon when its checked */ 44 | visibility: visible; 45 | } 46 | } 47 | 48 | -------------------------------------------------------------------------------- /blog2/client/electron-quick-start/www/lib/ionic/scss/_refresher.scss: -------------------------------------------------------------------------------- 1 | 2 | // Scroll refresher (for pull to refresh) 3 | .scroll-refresher { 4 | position: absolute; 5 | top: -60px; 6 | right: 0; 7 | left: 0; 8 | overflow: hidden; 9 | margin: auto; 10 | height: 60px; 11 | .ionic-refresher-content { 12 | position: absolute; 13 | bottom: 15px; 14 | left: 0; 15 | width: 100%; 16 | color: $scroll-refresh-icon-color; 17 | text-align: center; 18 | 19 | font-size: 30px; 20 | 21 | .text-refreshing, 22 | .text-pulling { 23 | font-size: 16px; 24 | line-height: 16px; 25 | } 26 | &.ionic-refresher-with-text { 27 | bottom: 10px; 28 | } 29 | } 30 | 31 | .icon-refreshing, 32 | .icon-pulling { 33 | width: 100%; 34 | -webkit-backface-visibility: hidden; 35 | backface-visibility: hidden; 36 | -webkit-transform-style: preserve-3d; 37 | transform-style: preserve-3d; 38 | } 39 | .icon-pulling { 40 | @include animation-name(refresh-spin-back); 41 | @include animation-duration(200ms); 42 | @include animation-timing-function(linear); 43 | @include animation-fill-mode(none); 44 | -webkit-transform: translate3d(0,0,0) rotate(0deg); 45 | transform: translate3d(0,0,0) rotate(0deg); 46 | } 47 | .icon-refreshing, 48 | .text-refreshing { 49 | display: none; 50 | } 51 | .icon-refreshing { 52 | @include animation-duration(1.5s); 53 | } 54 | 55 | &.active { 56 | .icon-pulling:not(.pulling-rotation-disabled) { 57 | @include animation-name(refresh-spin); 58 | -webkit-transform: translate3d(0,0,0) rotate(-180deg); 59 | transform: translate3d(0,0,0) rotate(-180deg); 60 | } 61 | &.refreshing { 62 | @include transition(-webkit-transform .2s); 63 | @include transition(transform .2s); 64 | -webkit-transform: scale(1,1); 65 | transform: scale(1,1); 66 | 67 | .icon-pulling, 68 | .text-pulling { 69 | display: none; 70 | } 71 | .icon-refreshing, 72 | .text-refreshing { 73 | display: block; 74 | } 75 | &.refreshing-tail { 76 | -webkit-transform: scale(0,0); 77 | transform: scale(0,0); 78 | } 79 | } 80 | } 81 | } 82 | .overflow-scroll > .scroll{ 83 | &.overscroll{ 84 | position:fixed; 85 | right: 0; 86 | left: 0; 87 | } 88 | -webkit-overflow-scrolling:touch; 89 | width:100%; 90 | } 91 | 92 | .overflow-scroll.padding > .scroll.overscroll{ 93 | padding: 10px; 94 | } 95 | @-webkit-keyframes refresh-spin { 96 | 0% { -webkit-transform: translate3d(0,0,0) rotate(0); } 97 | 100% { -webkit-transform: translate3d(0,0,0) rotate(180deg); } 98 | } 99 | 100 | @keyframes refresh-spin { 101 | 0% { transform: translate3d(0,0,0) rotate(0); } 102 | 100% { transform: translate3d(0,0,0) rotate(180deg); } 103 | } 104 | 105 | @-webkit-keyframes refresh-spin-back { 106 | 0% { -webkit-transform: translate3d(0,0,0) rotate(180deg); } 107 | 100% { -webkit-transform: translate3d(0,0,0) rotate(0); } 108 | } 109 | 110 | @keyframes refresh-spin-back { 111 | 0% { transform: translate3d(0,0,0) rotate(180deg); } 112 | 100% { transform: translate3d(0,0,0) rotate(0); } 113 | } 114 | -------------------------------------------------------------------------------- /blog2/client/electron-quick-start/www/lib/ionic/scss/_select.scss: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Select 4 | * -------------------------------------------------- 5 | */ 6 | 7 | .item-select { 8 | position: relative; 9 | 10 | select { 11 | @include appearance(none); 12 | position: absolute; 13 | top: 0; 14 | bottom: 0; 15 | right: 0; 16 | padding: 0 ($item-padding * 3) 0 $item-padding; 17 | max-width: 65%; 18 | 19 | border: none; 20 | background: $item-default-bg; 21 | color: #333; 22 | 23 | // hack to hide default dropdown arrow in FF 24 | text-indent: .01px; 25 | text-overflow: ''; 26 | 27 | white-space: nowrap; 28 | font-size: $font-size-base; 29 | 30 | cursor: pointer; 31 | direction: rtl; // right align the select text 32 | } 33 | 34 | select::-ms-expand { 35 | // hide default dropdown arrow in IE 36 | display: none; 37 | } 38 | 39 | option { 40 | direction: ltr; 41 | } 42 | 43 | &:after { 44 | position: absolute; 45 | top: 50%; 46 | right: $item-padding; 47 | margin-top: -3px; 48 | width: 0; 49 | height: 0; 50 | border-top: 5px solid; 51 | border-right: 5px solid rgba(0, 0, 0, 0); 52 | border-left: 5px solid rgba(0, 0, 0, 0); 53 | color: #999; 54 | content: ""; 55 | pointer-events: none; 56 | } 57 | &.item-light { 58 | select{ 59 | background:$item-light-bg; 60 | color:$item-light-text; 61 | } 62 | } 63 | &.item-stable { 64 | select{ 65 | background:$item-stable-bg; 66 | color:$item-stable-text; 67 | } 68 | &:after, .input-label{ 69 | color:darken($item-stable-border,30%); 70 | } 71 | } 72 | &.item-positive { 73 | select{ 74 | background:$item-positive-bg; 75 | color:$item-positive-text; 76 | } 77 | &:after, .input-label{ 78 | color:$item-positive-text; 79 | } 80 | } 81 | &.item-calm { 82 | select{ 83 | background:$item-calm-bg; 84 | color:$item-calm-text; 85 | } 86 | &:after, .input-label{ 87 | color:$item-calm-text; 88 | } 89 | } 90 | &.item-assertive { 91 | select{ 92 | background:$item-assertive-bg; 93 | color:$item-assertive-text; 94 | } 95 | &:after, .input-label{ 96 | color:$item-assertive-text; 97 | } 98 | } 99 | &.item-balanced { 100 | select{ 101 | background:$item-balanced-bg; 102 | color:$item-balanced-text; 103 | } 104 | &:after, .input-label{ 105 | color:$item-balanced-text; 106 | } 107 | } 108 | &.item-energized { 109 | select{ 110 | background:$item-energized-bg; 111 | color:$item-energized-text; 112 | } 113 | &:after, .input-label{ 114 | color:$item-energized-text; 115 | } 116 | } 117 | &.item-royal { 118 | select{ 119 | background:$item-royal-bg; 120 | color:$item-royal-text; 121 | } 122 | &:after, .input-label{ 123 | color:$item-royal-text; 124 | } 125 | } 126 | &.item-dark { 127 | select{ 128 | background:$item-dark-bg; 129 | color:$item-dark-text; 130 | } 131 | &:after, .input-label{ 132 | color:$item-dark-text; 133 | } 134 | } 135 | } 136 | 137 | select { 138 | &[multiple], 139 | &[size] { 140 | height: auto; 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /blog2/client/electron-quick-start/www/lib/ionic/scss/_slide-box.scss: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Slide Box 4 | * -------------------------------------------------- 5 | */ 6 | 7 | .slider { 8 | position: relative; 9 | visibility: hidden; 10 | // Make sure items don't scroll over ever 11 | overflow: hidden; 12 | } 13 | 14 | .slider-slides { 15 | position: relative; 16 | height: 100%; 17 | } 18 | 19 | .slider-slide { 20 | position: relative; 21 | display: block; 22 | float: left; 23 | width: 100%; 24 | height: 100%; 25 | vertical-align: top; 26 | } 27 | 28 | .slider-slide-image { 29 | > img { 30 | width: 100%; 31 | } 32 | } 33 | 34 | .slider-pager { 35 | position: absolute; 36 | bottom: 20px; 37 | z-index: $z-index-slider-pager; 38 | width: 100%; 39 | height: 15px; 40 | text-align: center; 41 | 42 | .slider-pager-page { 43 | display: inline-block; 44 | margin: 0px 3px; 45 | width: 15px; 46 | color: #000; 47 | text-decoration: none; 48 | 49 | opacity: 0.3; 50 | 51 | &.active { 52 | @include transition(opacity 0.4s ease-in); 53 | opacity: 1; 54 | } 55 | } 56 | } 57 | 58 | //Disable animate service animations 59 | .slider-slide, 60 | .slider-pager-page { 61 | &.ng-enter, 62 | &.ng-leave, 63 | &.ng-animate { 64 | -webkit-transition: none !important; 65 | transition: none !important; 66 | } 67 | &.ng-animate { 68 | -webkit-animation: none 0s; 69 | animation: none 0s; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /blog2/client/electron-quick-start/www/lib/ionic/scss/_spinner.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Spinners 3 | * -------------------------------------------------- 4 | */ 5 | 6 | .spinner { 7 | svg { 8 | width: $spinner-width; 9 | height: $spinner-height; 10 | } 11 | 12 | stroke: $spinner-default-stroke; 13 | fill: $spinner-default-fill; 14 | 15 | &.spinner-light { 16 | stroke: $spinner-light-stroke; 17 | fill: $spinner-light-fill; 18 | } 19 | &.spinner-stable { 20 | stroke: $spinner-stable-stroke; 21 | fill: $spinner-stable-fill; 22 | } 23 | &.spinner-positive { 24 | stroke: $spinner-positive-stroke; 25 | fill: $spinner-positive-fill; 26 | } 27 | &.spinner-calm { 28 | stroke: $spinner-calm-stroke; 29 | fill: $spinner-calm-fill; 30 | } 31 | &.spinner-balanced { 32 | stroke: $spinner-balanced-stroke; 33 | fill: $spinner-balanced-fill; 34 | } 35 | &.spinner-assertive { 36 | stroke: $spinner-assertive-stroke; 37 | fill: $spinner-assertive-fill; 38 | } 39 | &.spinner-energized { 40 | stroke: $spinner-energized-stroke; 41 | fill: $spinner-energized-fill; 42 | } 43 | &.spinner-royal { 44 | stroke: $spinner-royal-stroke; 45 | fill: $spinner-royal-fill; 46 | } 47 | &.spinner-dark { 48 | stroke: $spinner-dark-stroke; 49 | fill: $spinner-dark-fill; 50 | } 51 | } 52 | 53 | .spinner-android { 54 | stroke: #4b8bf4; 55 | } 56 | 57 | .spinner-ios, 58 | .spinner-ios-small { 59 | stroke: #69717d; 60 | } 61 | 62 | .spinner-spiral { 63 | .stop1 { 64 | stop-color: $spinner-light-fill; 65 | stop-opacity: 0; 66 | } 67 | 68 | &.spinner-light { 69 | .stop1 { 70 | stop-color: $spinner-default-fill; 71 | } 72 | .stop2 { 73 | stop-color: $spinner-light-fill; 74 | } 75 | } 76 | &.spinner-stable .stop2 { 77 | stop-color: $spinner-stable-fill; 78 | } 79 | &.spinner-positive .stop2 { 80 | stop-color: $spinner-positive-fill; 81 | } 82 | &.spinner-calm .stop2 { 83 | stop-color: $spinner-calm-fill; 84 | } 85 | &.spinner-balanced .stop2 { 86 | stop-color: $spinner-balanced-fill; 87 | } 88 | &.spinner-assertive .stop2 { 89 | stop-color: $spinner-assertive-fill; 90 | } 91 | &.spinner-energized .stop2 { 92 | stop-color: $spinner-energized-fill; 93 | } 94 | &.spinner-royal .stop2 { 95 | stop-color: $spinner-royal-fill; 96 | } 97 | &.spinner-dark .stop2 { 98 | stop-color: $spinner-dark-fill; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /blog2/client/electron-quick-start/www/lib/ionic/scss/_type.scss: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Typography 4 | * -------------------------------------------------- 5 | */ 6 | 7 | 8 | // Body text 9 | // ------------------------- 10 | 11 | p { 12 | margin: 0 0 ($line-height-computed / 2); 13 | } 14 | 15 | 16 | // Emphasis & misc 17 | // ------------------------- 18 | 19 | small { font-size: 85%; } 20 | cite { font-style: normal; } 21 | 22 | 23 | // Alignment 24 | // ------------------------- 25 | 26 | .text-left { text-align: left; } 27 | .text-right { text-align: right; } 28 | .text-center { text-align: center; } 29 | 30 | 31 | // Headings 32 | // ------------------------- 33 | 34 | h1, h2, h3, h4, h5, h6, 35 | .h1, .h2, .h3, .h4, .h5, .h6 { 36 | color: $base-color; 37 | font-weight: $headings-font-weight; 38 | font-family: $headings-font-family; 39 | line-height: $headings-line-height; 40 | 41 | small { 42 | font-weight: normal; 43 | line-height: 1; 44 | } 45 | } 46 | 47 | h1, .h1, 48 | h2, .h2, 49 | h3, .h3 { 50 | margin-top: $line-height-computed; 51 | margin-bottom: ($line-height-computed / 2); 52 | 53 | &:first-child { 54 | margin-top: 0; 55 | } 56 | 57 | + h1, + .h1, 58 | + h2, + .h2, 59 | + h3, + .h3 { 60 | margin-top: ($line-height-computed / 2); 61 | } 62 | } 63 | 64 | h4, .h4, 65 | h5, .h5, 66 | h6, .h6 { 67 | margin-top: ($line-height-computed / 2); 68 | margin-bottom: ($line-height-computed / 2); 69 | } 70 | 71 | h1, .h1 { font-size: floor($font-size-base * 2.60); } // ~36px 72 | h2, .h2 { font-size: floor($font-size-base * 2.15); } // ~30px 73 | h3, .h3 { font-size: ceil($font-size-base * 1.70); } // ~24px 74 | h4, .h4 { font-size: ceil($font-size-base * 1.25); } // ~18px 75 | h5, .h5 { font-size: $font-size-base; } 76 | h6, .h6 { font-size: ceil($font-size-base * 0.85); } // ~12px 77 | 78 | h1 small, .h1 small { font-size: ceil($font-size-base * 1.70); } // ~24px 79 | h2 small, .h2 small { font-size: ceil($font-size-base * 1.25); } // ~18px 80 | h3 small, .h3 small, 81 | h4 small, .h4 small { font-size: $font-size-base; } 82 | 83 | 84 | // Description Lists 85 | // ------------------------- 86 | 87 | dl { 88 | margin-bottom: $line-height-computed; 89 | } 90 | dt, 91 | dd { 92 | line-height: $line-height-base; 93 | } 94 | dt { 95 | font-weight: bold; 96 | } 97 | 98 | 99 | // Blockquotes 100 | // ------------------------- 101 | 102 | blockquote { 103 | margin: 0 0 $line-height-computed; 104 | padding: ($line-height-computed / 2) $line-height-computed; 105 | border-left: 5px solid gray; 106 | 107 | p { 108 | font-weight: 300; 109 | font-size: ($font-size-base * 1.25); 110 | line-height: 1.25; 111 | } 112 | 113 | p:last-child { 114 | margin-bottom: 0; 115 | } 116 | 117 | small { 118 | display: block; 119 | line-height: $line-height-base; 120 | &:before { 121 | content: '\2014 \00A0';// EM DASH, NBSP; 122 | } 123 | } 124 | } 125 | 126 | 127 | // Quotes 128 | // ------------------------- 129 | 130 | q:before, 131 | q:after, 132 | blockquote:before, 133 | blockquote:after { 134 | content: ""; 135 | } 136 | 137 | 138 | // Addresses 139 | // ------------------------- 140 | 141 | address { 142 | display: block; 143 | margin-bottom: $line-height-computed; 144 | font-style: normal; 145 | line-height: $line-height-base; 146 | } 147 | 148 | 149 | // Links 150 | // ------------------------- 151 | a { 152 | color: $link-color; 153 | } 154 | 155 | a.subdued { 156 | padding-right: 10px; 157 | color: #888; 158 | text-decoration: none; 159 | 160 | &:hover { 161 | text-decoration: none; 162 | } 163 | &:last-child { 164 | padding-right: 0; 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /blog2/client/electron-quick-start/www/lib/ionic/scss/ionic.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | @import 4 | // Ionicons 5 | "ionicons/ionicons.scss", 6 | 7 | // Variables 8 | "mixins", 9 | "variables", 10 | 11 | // Base 12 | "reset", 13 | "scaffolding", 14 | "type", 15 | 16 | // Components 17 | "action-sheet", 18 | "backdrop", 19 | "bar", 20 | "tabs", 21 | "menu", 22 | "modal", 23 | "popover", 24 | "popup", 25 | "loading", 26 | "items", 27 | "list", 28 | "badge", 29 | "slide-box", 30 | "slides", 31 | "refresher", 32 | "spinner", 33 | 34 | // Forms 35 | "form", 36 | "checkbox", 37 | "toggle", 38 | "radio", 39 | "range", 40 | "select", 41 | "progress", 42 | 43 | // Buttons 44 | "button", 45 | "button-bar", 46 | 47 | // Util 48 | "grid", 49 | "util", 50 | "platform", 51 | 52 | // Animations 53 | "animations", 54 | "transitions"; 55 | -------------------------------------------------------------------------------- /blog2/client/electron-quick-start/www/lib/ionic/scss/ionicons/_ionicons-font.scss: -------------------------------------------------------------------------------- 1 | // Ionicons Font Path 2 | // -------------------------- 3 | 4 | @font-face { 5 | font-family: $ionicons-font-family; 6 | src:url("#{$ionicons-font-path}/ionicons.eot?v=#{$ionicons-version}"); 7 | src:url("#{$ionicons-font-path}/ionicons.eot?v=#{$ionicons-version}#iefix") format("embedded-opentype"), 8 | url("#{$ionicons-font-path}/ionicons.ttf?v=#{$ionicons-version}") format("truetype"), 9 | url("#{$ionicons-font-path}/ionicons.woff?v=#{$ionicons-version}") format("woff"), 10 | url("#{$ionicons-font-path}/ionicons.woff") format("woff"), /* for WP8 */ 11 | url("#{$ionicons-font-path}/ionicons.svg?v=#{$ionicons-version}#Ionicons") format("svg"); 12 | font-weight: normal; 13 | font-style: normal; 14 | } 15 | 16 | .ion { 17 | display: inline-block; 18 | font-family: $ionicons-font-family; 19 | speak: none; 20 | font-style: normal; 21 | font-weight: normal; 22 | font-variant: normal; 23 | text-transform: none; 24 | text-rendering: auto; 25 | line-height: 1; 26 | -webkit-font-smoothing: antialiased; 27 | -moz-osx-font-smoothing: grayscale; 28 | } 29 | -------------------------------------------------------------------------------- /blog2/client/electron-quick-start/www/lib/ionic/scss/ionicons/ionicons.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | @import "ionicons-variables"; 3 | /*! 4 | Ionicons, v2.0.1 5 | Created by Ben Sperry for the Ionic Framework, http://ionicons.com/ 6 | https://twitter.com/benjsperry https://twitter.com/ionicframework 7 | MIT License: https://github.com/driftyco/ionicons 8 | 9 | Android-style icons originally built by Google’s 10 | Material Design Icons: https://github.com/google/material-design-icons 11 | used under CC BY http://creativecommons.org/licenses/by/4.0/ 12 | Modified icons to fit ionicon’s grid from original. 13 | */ 14 | 15 | @import "ionicons-font"; 16 | @import "ionicons-icons"; 17 | -------------------------------------------------------------------------------- /blog2/client/electron-quick-start/www/lib/ionic/version.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.2.4", 3 | "codename": "", 4 | "date": "2016-01-03", 5 | "time": "19:55:51" 6 | } 7 | -------------------------------------------------------------------------------- /blog2/client/electron-quick-start/www/partials/entry.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
7 | 10 | 13 |
14 | 15 | 17 | 18 |
19 | 20 |
-------------------------------------------------------------------------------- /blog2/client/electron-quick-start/www/partials/home.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | [{{entry.published | date:'short'}}] {{entry.title}} 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /blog2/client/electron-quick-start/www/partials/login.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
6 | 9 | 12 |
13 | 14 | 16 | 17 |
18 | 19 |
-------------------------------------------------------------------------------- /blog2/common/models/appuser.js: -------------------------------------------------------------------------------- 1 | module.exports = function(Appuser) { 2 | 3 | }; 4 | -------------------------------------------------------------------------------- /blog2/common/models/appuser.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "appuser", 3 | "base": "User", 4 | "strict": false, 5 | "idInjection": false, 6 | "options": { 7 | "validateUpsert": true 8 | }, 9 | "properties": {}, 10 | "validations": [], 11 | "relations": {}, 12 | "acls": [], 13 | "methods": {} 14 | } 15 | -------------------------------------------------------------------------------- /blog2/common/models/category.js: -------------------------------------------------------------------------------- 1 | module.exports = function(Category) { 2 | 3 | }; 4 | -------------------------------------------------------------------------------- /blog2/common/models/category.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "category", 3 | "base": "PersistedModel", 4 | "strict": false, 5 | "idInjection": false, 6 | "options": { 7 | "validateUpsert": true 8 | }, 9 | "properties": { 10 | "name": { 11 | "type": "string", 12 | "required": true 13 | } 14 | }, 15 | "validations": [], 16 | "relations": {}, 17 | "acls": [ 18 | { 19 | "accessType": "*", 20 | "principalType": "ROLE", 21 | "principalId": "$everyone", 22 | "permission": "DENY" 23 | }, 24 | { 25 | "accessType": "READ", 26 | "principalType": "ROLE", 27 | "principalId": "$everyone", 28 | "permission": "ALLOW" 29 | }, 30 | { 31 | "accessType": "WRITE", 32 | "principalType": "ROLE", 33 | "principalId": "$authenticated", 34 | "permission": "ALLOW" 35 | } 36 | ], 37 | "methods": {} 38 | } 39 | -------------------------------------------------------------------------------- /blog2/common/models/entry.js: -------------------------------------------------------------------------------- 1 | module.exports = function(Entry) { 2 | 3 | Entry.observe('loaded', function(ctx, next) { 4 | if(ctx && ctx.instance && ctx.instance.released) { 5 | var date = ctx.instance.published; 6 | ctx.instance.url = "/"+date.getFullYear()+"/"+(date.getMonth()+1)+"/"+date.getDate()+"/"+ctx.instance.slug; 7 | } 8 | next(); 9 | }); 10 | 11 | }; 12 | -------------------------------------------------------------------------------- /blog2/common/models/entry.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "entry", 3 | "base": "PersistedModel", 4 | "strict": false, 5 | "idInjection": false, 6 | "options": { 7 | "validateUpsert": true 8 | }, 9 | "properties": { 10 | "title": { 11 | "type": "string", 12 | "required": true 13 | }, 14 | "released": { 15 | "type": "boolean", 16 | "required": true 17 | }, 18 | "published": { 19 | "type": "date", 20 | "required": true 21 | }, 22 | "slug": { 23 | "type": "string", 24 | "required": true 25 | }, 26 | "body": { 27 | "type": "string", 28 | "required": true 29 | } 30 | }, 31 | "validations": [], 32 | "relations": { 33 | "categories": { 34 | "type": "hasMany", 35 | "model": "category", 36 | "foreignKey": "" 37 | } 38 | }, 39 | "acls": [ 40 | { 41 | "accessType": "*", 42 | "principalType": "ROLE", 43 | "principalId": "$everyone", 44 | "permission": "DENY" 45 | }, 46 | { 47 | "accessType": "READ", 48 | "principalType": "ROLE", 49 | "principalId": "$everyone", 50 | "permission": "ALLOW" 51 | }, 52 | { 53 | "accessType": "WRITE", 54 | "principalType": "ROLE", 55 | "principalId": "$authenticated", 56 | "permission": "ALLOW" 57 | } 58 | ], 59 | "methods": {} 60 | } 61 | -------------------------------------------------------------------------------- /blog2/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "blog1", 3 | "version": "1.0.0", 4 | "main": "server/server.js", 5 | "scripts": { 6 | "pretest": "jshint ." 7 | }, 8 | "dependencies": { 9 | "chalk": "^1.1.1", 10 | "compression": "^1.0.3", 11 | "cors": "^2.5.2", 12 | "express-handlebars": "^2.0.1", 13 | "handlebars-helper-moment": "^0.2.0", 14 | "loopback": "^2.22.0", 15 | "loopback-boot": "^2.6.5", 16 | "loopback-component-explorer": "^2.1.0", 17 | "loopback-connector-mongodb": "^1.13.2", 18 | "loopback-datasource-juggler": "^2.39.0", 19 | "moment": "^2.11.0", 20 | "serve-favicon": "^2.0.1" 21 | }, 22 | "devDependencies": { 23 | "jshint": "^2.5.6" 24 | }, 25 | "repository": { 26 | "type": "", 27 | "url": "" 28 | }, 29 | "description": "blog1" 30 | } 31 | -------------------------------------------------------------------------------- /blog2/server/boot/authentication.js: -------------------------------------------------------------------------------- 1 | module.exports = function enableAuthentication(server) { 2 | // enable authentication 3 | server.enableAuth(); 4 | }; 5 | -------------------------------------------------------------------------------- /blog2/server/boot/routes.js: -------------------------------------------------------------------------------- 1 | module.exports = function(app) { 2 | // Install a `/` route that returns server status 3 | //var router = server.loopback.Router(); 4 | //router.get('/', server.loopback.status()); 5 | //server.use(router); 6 | 7 | app.get('/', function(req, res) { 8 | console.log('getting blog entries'); 9 | app.models.entry.find({where:{released:true},order:'published desc'}).then(function(entries) { 10 | res.render('index',{entries:entries}); 11 | }); 12 | }); 13 | 14 | app.get('/:year/:month/:day/:slug', function(req, res) { 15 | console.log('do blog entry'); 16 | console.dir(req.params); 17 | //create an upper and lower date range 18 | var lowerDate = new Date(req.params.year, req.params.month-1, req.params.day); 19 | var upperDate = new Date(lowerDate); 20 | upperDate.setDate(upperDate.getDate()+1); 21 | app.models.entry.findOne({where:{ 22 | released:true, 23 | slug:req.params.slug, 24 | published:{between:[lowerDate,upperDate]} 25 | },limit:1}).then(function(entry) { 26 | //first - did we get any? 27 | if(!entry) { 28 | res.redirect('/'); 29 | } 30 | res.render('entry', {entry:entry}); 31 | }); 32 | }); 33 | }; 34 | -------------------------------------------------------------------------------- /blog2/server/component-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "loopback-component-explorer": { 3 | "mountPath": "/explorer" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /blog2/server/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "restApiRoot": "/api", 3 | "host": "0.0.0.0", 4 | "port": 3000, 5 | "remoting": { 6 | "context": { 7 | "enableHttpContext": false 8 | }, 9 | "rest": { 10 | "normalizeHttpPath": false, 11 | "xml": false 12 | }, 13 | "json": { 14 | "strict": false, 15 | "limit": "100kb" 16 | }, 17 | "urlencoded": { 18 | "extended": true, 19 | "limit": "100kb" 20 | }, 21 | "cors": false, 22 | "errorHandler": { 23 | "disableStackTrace": false 24 | } 25 | }, 26 | "legacyExplorer": false 27 | } 28 | -------------------------------------------------------------------------------- /blog2/server/datasources.json: -------------------------------------------------------------------------------- 1 | { 2 | "db": { 3 | "name": "db", 4 | "connector": "memory" 5 | }, 6 | "blogdata": { 7 | "host": "localhost", 8 | "port": 27017, 9 | "database": "blogdata", 10 | "name": "blogdata", 11 | "connector": "mongodb" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /blog2/server/middleware.json: -------------------------------------------------------------------------------- 1 | { 2 | "initial:before": { 3 | "loopback#favicon": {} 4 | }, 5 | "initial": { 6 | "compression": {}, 7 | "cors": { 8 | "params": { 9 | "origin": true, 10 | "credentials": true, 11 | "maxAge": 86400 12 | } 13 | } 14 | }, 15 | "session": {}, 16 | "auth": {}, 17 | "parse": {}, 18 | "routes": { 19 | "loopback#rest": { 20 | "paths": [ 21 | "${restApiRoot}" 22 | ] 23 | } 24 | }, 25 | "files": {}, 26 | "final": { 27 | "loopback#urlNotFound": {} 28 | }, 29 | "final:after": { 30 | "loopback#errorHandler": {} 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /blog2/server/middleware.production.json: -------------------------------------------------------------------------------- 1 | { 2 | "final:after": { 3 | "loopback#errorHandler": { 4 | "params": { 5 | "includeStack": false 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /blog2/server/model-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "sources": [ 4 | "loopback/common/models", 5 | "loopback/server/models", 6 | "../common/models", 7 | "./models" 8 | ], 9 | "mixins": [ 10 | "loopback/common/mixins", 11 | "loopback/server/mixins", 12 | "../common/mixins", 13 | "./mixins" 14 | ] 15 | }, 16 | "User": { 17 | "dataSource": "db" 18 | }, 19 | "AccessToken": { 20 | "dataSource": "db", 21 | "public": false 22 | }, 23 | "ACL": { 24 | "dataSource": "db", 25 | "public": false 26 | }, 27 | "RoleMapping": { 28 | "dataSource": "db", 29 | "public": false 30 | }, 31 | "Role": { 32 | "dataSource": "db", 33 | "public": false 34 | }, 35 | "entry": { 36 | "dataSource": "blogdata", 37 | "public": true, 38 | "$promise": {}, 39 | "$resolved": true 40 | }, 41 | "category": { 42 | "dataSource": "blogdata", 43 | "public": true, 44 | "$promise": {}, 45 | "$resolved": true 46 | }, 47 | "appuser": { 48 | "dataSource": "blogdata", 49 | "public": true, 50 | "$promise": {}, 51 | "$resolved": true 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /blog2/server/server.js: -------------------------------------------------------------------------------- 1 | var loopback = require('loopback'); 2 | var boot = require('loopback-boot'); 3 | 4 | var app = module.exports = loopback(); 5 | var exphbs = require('express-handlebars'); 6 | 7 | var hbs = exphbs.create({ 8 | defaultLayout:'main', 9 | helpers:require('handlebars-helper-moment')() 10 | }); 11 | 12 | app.engine('handlebars', hbs.engine); 13 | app.set('view engine', 'handlebars'); 14 | 15 | app.start = function() { 16 | // start the web server 17 | return app.listen(function() { 18 | app.emit('started'); 19 | var baseUrl = app.get('url').replace(/\/$/, ''); 20 | console.log('Web server listening at: %s', baseUrl); 21 | if (app.get('loopback-component-explorer')) { 22 | var explorerPath = app.get('loopback-component-explorer').mountPath; 23 | console.log('Browse your REST API at %s%s', baseUrl, explorerPath); 24 | } 25 | }); 26 | }; 27 | 28 | // Bootstrap the application, configure models, datasources and middleware. 29 | // Sub-apps like REST API are mounted via boot scripts. 30 | boot(app, __dirname, function(err) { 31 | if (err) throw err; 32 | 33 | // start the server if `$ node server.js` 34 | if (require.main === module) 35 | app.start(); 36 | }); 37 | 38 | -------------------------------------------------------------------------------- /blog2/server/views/entry.handlebars: -------------------------------------------------------------------------------- 1 | 2 |

{{entry.title}}

3 |

4 | Published: {{moment published format="MMMM D, YYYY h:mm A"}} 5 |

6 | 7 | {{{entry.body}}} -------------------------------------------------------------------------------- /blog2/server/views/index.handlebars: -------------------------------------------------------------------------------- 1 | 2 | 3 |

Entries

4 | 5 | {{#each entries}} 6 |

7 | {{title}}
8 | Published: {{moment published format="MMMM D, YYYY h:mm A"}} 9 |

10 | 11 | {{/each}} -------------------------------------------------------------------------------- /blog2/server/views/layouts/main.handlebars: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 18 | 19 |
20 |
21 | 22 |
23 | 24 | My Blog 25 |
26 |
28 | 32 |
33 | 35 |
36 |
37 |
38 | 39 |
40 |
41 | 42 | 48 |
49 |
50 |
51 | Menu 52 | 58 |
59 |
60 |
61 | 62 |
63 |
64 |
{{{body}}}
65 |
66 |
67 | 68 |
69 |
70 |
71 | 72 | 73 | -------------------------------------------------------------------------------- /filetest/.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # http://editorconfig.org 4 | 5 | root = true 6 | 7 | [*] 8 | indent_style = space 9 | indent_size = 2 10 | end_of_line = lf 11 | charset = utf-8 12 | trim_trailing_whitespace = true 13 | insert_final_newline = true 14 | -------------------------------------------------------------------------------- /filetest/.eslintignore: -------------------------------------------------------------------------------- 1 | /client/ -------------------------------------------------------------------------------- /filetest/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "loopback" 3 | } -------------------------------------------------------------------------------- /filetest/.gitignore: -------------------------------------------------------------------------------- 1 | *.csv 2 | *.dat 3 | *.iml 4 | *.log 5 | *.out 6 | *.pid 7 | *.seed 8 | *.sublime-* 9 | *.swo 10 | *.swp 11 | *.tgz 12 | *.xml 13 | .DS_Store 14 | .idea 15 | .project 16 | .strong-pm 17 | coverage 18 | node_modules 19 | npm-debug.log 20 | -------------------------------------------------------------------------------- /filetest/.yo-rc.json: -------------------------------------------------------------------------------- 1 | { 2 | "generator-loopback": {} 3 | } -------------------------------------------------------------------------------- /filetest/client/README.md: -------------------------------------------------------------------------------- 1 | ## Client 2 | 3 | This is the place for your application front-end files. 4 | 5 | yep -------------------------------------------------------------------------------- /filetest/client/app.js: -------------------------------------------------------------------------------- 1 | var $name, $age, $breed, $picture, $resume, $catList; 2 | 3 | var apiUrl = 'http://localhost:3000/api/'; 4 | 5 | $(document).ready(function() { 6 | 7 | $('#addCatForm').on('submit', handleForm); 8 | 9 | $name = $('#name'); 10 | $age = $('#age'); 11 | $breed = $('#breed'); 12 | $picture = $('#picture'); 13 | $resume = $('#resume'); 14 | $catList = $('#catList'); 15 | 16 | getCats(); 17 | 18 | }); 19 | 20 | function getCats() { 21 | 22 | var list = ''; 23 | 24 | $.get(apiUrl + 'cats').then(function(res) { 25 | res.forEach(function(cat) { 26 | list += `

${cat.name}

`; 27 | if(cat.picture) { 28 | list += ``; 29 | } 30 | list += ` 31 |

32 | ${cat.name} is a ${cat.breed} and is ${cat.age} year(s) old. 33 |

`; 34 | }); 35 | $catList.html(list); 36 | }); 37 | } 38 | 39 | function handleForm(e) { 40 | e.preventDefault(); 41 | 42 | var cat = { 43 | name:$name.val(), 44 | age:$age.val(), 45 | breed:$breed.val() 46 | } 47 | 48 | console.log(cat); 49 | 50 | // step 1 - make the cat, this gives us something to associate with 51 | $.post(apiUrl + 'cats', cat).then(function(res) { 52 | 53 | //copy res since it has the id 54 | cat = res; 55 | 56 | var promises = []; 57 | 58 | // step 2: do we have binary crap? 59 | if($resume.val() != '') { 60 | console.log('i need to process the resume upload'); 61 | promises.push(sendFile($resume.get(0).files[0], apiUrl + 'attachments/resume/upload')); 62 | } 63 | 64 | if($picture.val() != '') { 65 | console.log('i need to process thepicture upload'); 66 | promises.push(sendFile($picture.get(0).files[0], apiUrl + 'attachments/picture/upload')); 67 | } 68 | 69 | // no need to see if I have promises, it still resolves if empty 70 | Promise.all(promises).then(function(results) { 71 | console.log('back from all promises', results); 72 | //update cat if we need to 73 | if(promises.length >= 1) { 74 | /* 75 | so we have one or two results, we could add some logic to see what 76 | we selected so we know what is what, but we can simplify since the result 77 | contains a 'container' field that matches the property 78 | */ 79 | results.forEach(function(resultOb) { 80 | if(resultOb.result.files && resultOb.result.files.file[0].container) { 81 | cat[resultOb.result.files.file[0].container] = resultOb.result.files.file[0].name; 82 | } 83 | }); 84 | console.dir(cat); 85 | //now update cat, we can't include the id though 86 | var id = cat.id; 87 | delete cat.id; 88 | $.post(apiUrl + 'cats/'+id+'/replace', cat).then(function() { 89 | getCats(); 90 | }); 91 | } else { 92 | getCats(); 93 | } 94 | }); 95 | 96 | }); 97 | 98 | } 99 | 100 | //Stolen from: https://developer.mozilla.org/en-US/docs/Using_files_from_web_applications 101 | function sendFile(file, url) { 102 | return new Promise(function(resolve, reject) { 103 | 104 | var xhr = new XMLHttpRequest(); 105 | var fd = new FormData(); 106 | 107 | xhr.open("POST", url, true); 108 | xhr.onreadystatechange = function() { 109 | if(xhr.readyState == 4 && xhr.status == 200) { 110 | resolve(JSON.parse(xhr.responseText)); 111 | } 112 | }; 113 | fd.append('file', file); 114 | xhr.send(fd); 115 | 116 | }); 117 | } -------------------------------------------------------------------------------- /filetest/client/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 16 | 17 | 18 | 19 |

Cats

20 | 21 |
22 | 23 |
24 | 25 |

Add Cat

26 | 27 |
28 | 29 |

30 | 31 | 32 |

33 | 34 |

35 | 36 | 37 |

38 | 39 |

40 | 41 | 42 |

43 | 44 |

45 | 46 | 47 |

48 | 49 |

50 | 51 | 52 |

53 | 54 | 55 | 56 |
57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /filetest/common/models/attachment.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function(Attachment) { 4 | 5 | }; 6 | -------------------------------------------------------------------------------- /filetest/common/models/attachment.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "attachment", 3 | "base": "Model", 4 | "idInjection": true, 5 | "options": { 6 | "validateUpsert": true 7 | }, 8 | "properties": {}, 9 | "validations": [], 10 | "relations": {}, 11 | "acls": [], 12 | "methods": {} 13 | } 14 | -------------------------------------------------------------------------------- /filetest/common/models/cat.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function(Cat) { 4 | 5 | }; 6 | -------------------------------------------------------------------------------- /filetest/common/models/cat.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cat", 3 | "base": "PersistedModel", 4 | "idInjection": true, 5 | "options": { 6 | "validateUpsert": true 7 | }, 8 | "properties": { 9 | "name": { 10 | "type": "string", 11 | "required": true 12 | }, 13 | "age": { 14 | "type": "number", 15 | "required": true 16 | }, 17 | "breed": { 18 | "type": "string", 19 | "required": true 20 | } 21 | }, 22 | "validations": [], 23 | "relations": {}, 24 | "acls": [], 25 | "methods": {} 26 | } 27 | -------------------------------------------------------------------------------- /filetest/common/models/note.js: -------------------------------------------------------------------------------- 1 | module.exports = function(Note) { 2 | }; 3 | -------------------------------------------------------------------------------- /filetest/common/models/note.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Note", 3 | "properties": { 4 | "title": { 5 | "type": "string", 6 | "required": true 7 | }, 8 | "content": { 9 | "type": "string" 10 | } 11 | }, 12 | "validations": [], 13 | "relations": {}, 14 | "acls": [], 15 | "methods": {} 16 | } 17 | -------------------------------------------------------------------------------- /filetest/data.db: -------------------------------------------------------------------------------- 1 | { 2 | "ids": { 3 | "User": 1, 4 | "AccessToken": 1, 5 | "ACL": 1, 6 | "RoleMapping": 1, 7 | "Role": 1, 8 | "Note": 1, 9 | "cat": 3 10 | }, 11 | "models": { 12 | "User": {}, 13 | "AccessToken": {}, 14 | "ACL": {}, 15 | "RoleMapping": {}, 16 | "Role": {}, 17 | "Note": {}, 18 | "cat": { 19 | "1": "{\"name\":\"Mr Fluffy\",\"age\":2,\"breed\":\"mutt\",\"id\":1}", 20 | "2": "{\"name\":\"moo\",\"age\":7,\"breed\":\"mutt\",\"id\":2}" 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /filetest/files/resume/avatar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cfjedimaster/StrongLoopDemos/615610a8c80c011176bd80a9883b4521fbee7caa/filetest/files/resume/avatar.jpg -------------------------------------------------------------------------------- /filetest/files/resume/goo.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cfjedimaster/StrongLoopDemos/615610a8c80c011176bd80a9883b4521fbee7caa/filetest/files/resume/goo.txt -------------------------------------------------------------------------------- /filetest/files/resume/windowsfield.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cfjedimaster/StrongLoopDemos/615610a8c80c011176bd80a9883b4521fbee7caa/filetest/files/resume/windowsfield.jpg -------------------------------------------------------------------------------- /filetest/notes.txt: -------------------------------------------------------------------------------- 1 | Storage component - http://loopback.io/doc/en/lb2/Storage-component.html 2 | 3 | issues: 4 | 5 | containers/files 6 | 7 | its a datasource 8 | 9 | the name should be what? what im calling the property or something generic? 10 | make your folder 11 | make a subfolder? 12 | make a model 13 | 14 | { 15 | "result": { 16 | "files": { 17 | "file": [ 18 | { 19 | "container": "resume", 20 | "name": "avatar.jpg", 21 | "type": "image/jpeg", 22 | "size": 5055 23 | } 24 | ] 25 | }, 26 | "fields": {} 27 | } 28 | } -------------------------------------------------------------------------------- /filetest/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "filetest", 3 | "version": "1.0.0", 4 | "main": "server/server.js", 5 | "scripts": { 6 | "lint": "eslint .", 7 | "start": "node .", 8 | "posttest": "npm run lint && nsp check" 9 | }, 10 | "dependencies": { 11 | "compression": "^1.0.3", 12 | "cors": "^2.5.2", 13 | "helmet": "^1.3.0", 14 | "loopback": "^2.22.0", 15 | "loopback-boot": "^2.6.5", 16 | "loopback-component-explorer": "^2.4.0", 17 | "loopback-datasource-juggler": "^2.39.0", 18 | "serve-favicon": "^2.0.1", 19 | "storage": "^0.2.0", 20 | "strong-error-handler": "^1.0.1" 21 | }, 22 | "devDependencies": { 23 | "eslint": "^2.13.1", 24 | "eslint-config-loopback": "^4.0.0", 25 | "nsp": "^2.1.0" 26 | }, 27 | "repository": { 28 | "type": "", 29 | "url": "" 30 | }, 31 | "license": "UNLICENSED", 32 | "description": "filetest" 33 | } 34 | -------------------------------------------------------------------------------- /filetest/server/boot/authentication.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function enableAuthentication(server) { 4 | // enable authentication 5 | server.enableAuth(); 6 | }; 7 | -------------------------------------------------------------------------------- /filetest/server/boot/root.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function(server) { 4 | // Install a `/` route that returns server status 5 | var router = server.loopback.Router(); 6 | // router.get('/', server.loopback.status()); 7 | server.use(router); 8 | }; 9 | -------------------------------------------------------------------------------- /filetest/server/component-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "loopback-component-explorer": { 3 | "mountPath": "/explorer" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /filetest/server/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "restApiRoot": "/api", 3 | "host": "0.0.0.0", 4 | "port": 3000, 5 | "remoting": { 6 | "context": false, 7 | "rest": { 8 | "normalizeHttpPath": false, 9 | "xml": false 10 | }, 11 | "json": { 12 | "strict": false, 13 | "limit": "100kb" 14 | }, 15 | "urlencoded": { 16 | "extended": true, 17 | "limit": "100kb" 18 | }, 19 | "cors": false, 20 | "handleErrors": false 21 | }, 22 | "legacyExplorer": false 23 | } 24 | -------------------------------------------------------------------------------- /filetest/server/datasources.json: -------------------------------------------------------------------------------- 1 | { 2 | "db": { 3 | "name": "db", 4 | "connector": "memory", 5 | "file": "data.db" 6 | }, 7 | "storage": { 8 | "name": "storage", 9 | "connector": "loopback-component-storage", 10 | "provider": "filesystem", 11 | "root": "./files" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /filetest/server/middleware.development.json: -------------------------------------------------------------------------------- 1 | { 2 | "final:after": { 3 | "strong-error-handler": { 4 | "params": { 5 | "debug": true, 6 | "log": true 7 | } 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /filetest/server/middleware.json: -------------------------------------------------------------------------------- 1 | { 2 | "initial:before": { 3 | "loopback#favicon": {} 4 | }, 5 | "initial": { 6 | "compression": {}, 7 | "cors": { 8 | "params": { 9 | "origin": true, 10 | "credentials": true, 11 | "maxAge": 86400 12 | } 13 | }, 14 | "helmet#xssFilter": {}, 15 | "helmet#frameguard": { 16 | "params": [ 17 | "deny" 18 | ] 19 | }, 20 | "helmet#hsts": { 21 | "params": { 22 | "maxAge": 0, 23 | "includeSubdomains": true 24 | } 25 | }, 26 | "helmet#hidePoweredBy": {}, 27 | "helmet#ieNoOpen": {}, 28 | "helmet#noSniff": {}, 29 | "helmet#noCache": { 30 | "enabled": false 31 | } 32 | }, 33 | "session": {}, 34 | "auth": {}, 35 | "parse": {}, 36 | "routes": { 37 | "loopback#rest": { 38 | "paths": [ 39 | "${restApiRoot}" 40 | ] 41 | } 42 | }, 43 | "files": { 44 | "loopback#static":{ 45 | "params":"$!../client" 46 | } 47 | }, 48 | "final": { 49 | "loopback#urlNotFound": {} 50 | }, 51 | "final:after": { 52 | "strong-error-handler": {} 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /filetest/server/model-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "sources": [ 4 | "loopback/common/models", 5 | "loopback/server/models", 6 | "../common/models", 7 | "./models" 8 | ], 9 | "mixins": [ 10 | "loopback/common/mixins", 11 | "loopback/server/mixins", 12 | "../common/mixins", 13 | "./mixins" 14 | ] 15 | }, 16 | "User": { 17 | "dataSource": "db" 18 | }, 19 | "AccessToken": { 20 | "dataSource": "db", 21 | "public": false 22 | }, 23 | "ACL": { 24 | "dataSource": "db", 25 | "public": false 26 | }, 27 | "RoleMapping": { 28 | "dataSource": "db", 29 | "public": false 30 | }, 31 | "Role": { 32 | "dataSource": "db", 33 | "public": false 34 | }, 35 | "Note": { 36 | "dataSource": "db" 37 | }, 38 | "cat": { 39 | "dataSource": "db", 40 | "public": true 41 | }, 42 | "attachment": { 43 | "dataSource": "storage", 44 | "public": true 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /filetest/server/server.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var loopback = require('loopback'); 4 | var boot = require('loopback-boot'); 5 | 6 | var app = module.exports = loopback(); 7 | 8 | app.start = function() { 9 | // start the web server 10 | return app.listen(function() { 11 | app.emit('started'); 12 | var baseUrl = app.get('url').replace(/\/$/, ''); 13 | console.log('Web server listening at: %s', baseUrl); 14 | if (app.get('loopback-component-explorer')) { 15 | var explorerPath = app.get('loopback-component-explorer').mountPath; 16 | console.log('Browse your REST API at %s%s', baseUrl, explorerPath); 17 | } 18 | }); 19 | }; 20 | 21 | // Bootstrap the application, configure models, datasources and middleware. 22 | // Sub-apps like REST API are mounted via boot scripts. 23 | boot(app, __dirname, function(err) { 24 | if (err) throw err; 25 | 26 | // start the server if `$ node server.js` 27 | if (require.main === module) 28 | app.start(); 29 | }); 30 | -------------------------------------------------------------------------------- /geotest/.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # http://editorconfig.org 4 | 5 | root = true 6 | 7 | [*] 8 | indent_style = space 9 | indent_size = 2 10 | end_of_line = lf 11 | charset = utf-8 12 | trim_trailing_whitespace = true 13 | insert_final_newline = true 14 | -------------------------------------------------------------------------------- /geotest/.gitignore: -------------------------------------------------------------------------------- 1 | *.csv 2 | *.dat 3 | *.iml 4 | *.log 5 | *.out 6 | *.pid 7 | *.seed 8 | *.sublime-* 9 | *.swo 10 | *.swp 11 | *.tgz 12 | *.xml 13 | .DS_Store 14 | .idea 15 | .project 16 | .strong-pm 17 | coverage 18 | node_modules 19 | npm-debug.log 20 | -------------------------------------------------------------------------------- /geotest/.jshintignore: -------------------------------------------------------------------------------- 1 | /client/ 2 | /node_modules/ 3 | -------------------------------------------------------------------------------- /geotest/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "esnext": true, 4 | "bitwise": true, 5 | "camelcase": true, 6 | "eqeqeq": true, 7 | "eqnull": true, 8 | "immed": true, 9 | "indent": 2, 10 | "latedef": "nofunc", 11 | "newcap": true, 12 | "nonew": true, 13 | "noarg": true, 14 | "quotmark": "single", 15 | "regexp": true, 16 | "undef": true, 17 | "unused": false, 18 | "trailing": true, 19 | "sub": true, 20 | "maxlen": 80 21 | } 22 | -------------------------------------------------------------------------------- /geotest/.yo-rc.json: -------------------------------------------------------------------------------- 1 | { 2 | "generator-loopback": {} 3 | } -------------------------------------------------------------------------------- /geotest/README.md: -------------------------------------------------------------------------------- 1 | # My Application 2 | 3 | The project is generated by [LoopBack](http://loopback.io). -------------------------------------------------------------------------------- /geotest/client/README.md: -------------------------------------------------------------------------------- 1 | ## Client 2 | 3 | This is the place for your application front-end files. 4 | -------------------------------------------------------------------------------- /geotest/client/img/sadcat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cfjedimaster/StrongLoopDemos/615610a8c80c011176bd80a9883b4521fbee7caa/geotest/client/img/sadcat.png -------------------------------------------------------------------------------- /geotest/client/js/map.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function() { 2 | $.get("/api/Cats", function(res) { 3 | console.log(res); 4 | //generate the map with the results 5 | var mapurl = 'https://maps.googleapis.com/maps/api/staticmap?'; 6 | mapurl += '&size=700x700&markers=color:red' 7 | res.forEach(function(cat) { 8 | console.dir(cat.location); 9 | mapurl += '%7C'+cat.location.lat+','+cat.location.lng; 10 | }); 11 | 12 | $('#map').attr('src',mapurl); 13 | console.log(mapurl); 14 | }); 15 | }); -------------------------------------------------------------------------------- /geotest/client/js/near.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function() { 2 | 3 | $status = $('#status'); 4 | 5 | console.log('Begin trying to get position'); 6 | navigator.geolocation.getCurrentPosition(function(pos) { 7 | 8 | $.get('/api/Cats/?filter[where][location][near]='+pos.coords.latitude+','+pos.coords.longitude+'&filter[where][location][maxDistance]=20', function(res) { 9 | 10 | if(res.length === 0) { 11 | $status.html('Sorry, but no cats are by you. I has a sad. Here, have this cat.
'); 12 | return; 13 | } 14 | var result = 'I found these cats:'; 19 | $status.html(result); 20 | 21 | }); 22 | 23 | }, function(err) { 24 | $status.html('I\'m sorry, but I was unable to get your location. Blame Apple.'); 25 | }); 26 | }); -------------------------------------------------------------------------------- /geotest/client/map.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |

Map Demo

12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /geotest/client/near.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |

Cats near you?

12 | 13 |
14 | Attempting to find your location... 15 |
16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /geotest/common/models/cat.js: -------------------------------------------------------------------------------- 1 | module.exports = function(Cat) { 2 | 3 | }; 4 | -------------------------------------------------------------------------------- /geotest/common/models/cat.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Cat", 3 | "base": "PersistedModel", 4 | "idInjection": true, 5 | "options": { 6 | "validateUpsert": true 7 | }, 8 | "properties": { 9 | "name": { 10 | "type": "string", 11 | "required": true 12 | }, 13 | "location": { 14 | "type": "geopoint", 15 | "required": true 16 | } 17 | }, 18 | "validations": [], 19 | "relations": {}, 20 | "acls": [], 21 | "methods": {} 22 | } 23 | -------------------------------------------------------------------------------- /geotest/common/models/localmongo.js: -------------------------------------------------------------------------------- 1 | module.exports = function(Localmongo) { 2 | 3 | }; 4 | -------------------------------------------------------------------------------- /geotest/fakedata.txt: -------------------------------------------------------------------------------- 1 | { 2 | "name": "san fran cat", 3 | "location": { 4 | "lat": 37.77493, 5 | "lng": -122.41942 6 | } 7 | } 8 | 9 | { 10 | "name": "paris cat", 11 | "location": { 12 | "lat": 48.87146, 13 | "lng": 2.355 14 | } 15 | } 16 | { 17 | "name": "home cat", 18 | "location": { 19 | "lat": 30.22996, 20 | "lng": -92.05052 21 | } 22 | } 23 | { 24 | "name": "dallas cat", 25 | "location": { 26 | "lat": 32.68500, 27 | "lng": -96.73069 28 | } 29 | } 30 | 31 | Sorted by closeness to home 32 | 33 | http://localhost:3000/api/Cats/?filter[where][location][near]=30.22996,-92.05052 34 | 35 | home 30.22996 -92.05052 36 | 37 | Not working: 38 | 39 | http://localhost:3000/api/Cats/?filter[where][and][0][location][near]=30.22996,-92.05052&filter[where][and][1][maxdistance][lt]=2000 -------------------------------------------------------------------------------- /geotest/memory.db: -------------------------------------------------------------------------------- 1 | { 2 | "ids": { 3 | "User": 1, 4 | "AccessToken": 1, 5 | "ACL": 1, 6 | "RoleMapping": 1, 7 | "Role": 1, 8 | "Cat": 5 9 | }, 10 | "models": { 11 | "User": {}, 12 | "AccessToken": {}, 13 | "ACL": {}, 14 | "RoleMapping": {}, 15 | "Role": {}, 16 | "Cat": { 17 | "1": "{\"name\":\"paris cat\",\"location\":{\"lat\":48.87146,\"lng\":2.355},\"id\":1}", 18 | "2": "{\"name\":\"san fran cat\",\"location\":{\"lat\":37.77493,\"lng\":-122.41942},\"id\":2}", 19 | "3": "{\"name\":\"home cat\",\"location\":{\"lat\":30.22996,\"lng\":-92.05052},\"id\":3}", 20 | "4": "{\"name\":\"dallas cat\",\"location\":{\"lat\":32.685,\"lng\":-96.73069},\"id\":4}" 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /geotest/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "geotest", 3 | "version": "1.0.0", 4 | "main": "server/server.js", 5 | "scripts": { 6 | "start": "node .", 7 | "pretest": "jshint .", 8 | "posttest": "nsp check" 9 | }, 10 | "dependencies": { 11 | "compression": "^1.0.3", 12 | "cors": "^2.5.2", 13 | "helmet": "^0.14.0", 14 | "loopback": "^2.22.0", 15 | "loopback-boot": "^2.6.5", 16 | "loopback-component-explorer": "^2.4.0", 17 | "loopback-connector-mongodb": "^1.13.3", 18 | "loopback-datasource-juggler": "^2.39.0", 19 | "serve-favicon": "^2.0.1" 20 | }, 21 | "devDependencies": { 22 | "jshint": "^2.5.6", 23 | "nsp": "^2.1.0" 24 | }, 25 | "repository": { 26 | "type": "", 27 | "url": "" 28 | }, 29 | "description": "geotest" 30 | } 31 | -------------------------------------------------------------------------------- /geotest/server/boot/authentication.js: -------------------------------------------------------------------------------- 1 | module.exports = function enableAuthentication(server) { 2 | // enable authentication 3 | server.enableAuth(); 4 | }; 5 | -------------------------------------------------------------------------------- /geotest/server/boot/root.js: -------------------------------------------------------------------------------- 1 | var loopback = require('loopback'); 2 | 3 | module.exports = function(server) { 4 | // Install a `/` route that returns server status 5 | var router = server.loopback.Router(); 6 | router.get('/', server.loopback.status()); 7 | 8 | router.get('/test', function(req, res) { 9 | 10 | server.models.Cat.find({where: {location: {maxDistance:2, near: {lat: 30.22996, lng: -92.05052}}}}, console.log); 11 | 12 | res.send('done'); 13 | }); 14 | 15 | 16 | server.use(router); 17 | }; 18 | -------------------------------------------------------------------------------- /geotest/server/component-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "loopback-component-explorer": { 3 | "mountPath": "/explorer" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /geotest/server/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "restApiRoot": "/api", 3 | "host": "0.0.0.0", 4 | "port": 3000, 5 | "remoting": { 6 | "context": { 7 | "enableHttpContext": false 8 | }, 9 | "rest": { 10 | "normalizeHttpPath": false, 11 | "xml": false 12 | }, 13 | "json": { 14 | "strict": false, 15 | "limit": "100kb" 16 | }, 17 | "urlencoded": { 18 | "extended": true, 19 | "limit": "100kb" 20 | }, 21 | "cors": false, 22 | "errorHandler": { 23 | "disableStackTrace": false 24 | } 25 | }, 26 | "legacyExplorer": false 27 | } 28 | -------------------------------------------------------------------------------- /geotest/server/datasources.json: -------------------------------------------------------------------------------- 1 | { 2 | "db": { 3 | "name": "db", 4 | "connector": "memory", 5 | "file": "memory.db" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /geotest/server/middleware.json: -------------------------------------------------------------------------------- 1 | { 2 | "initial:before": { 3 | "loopback#favicon": {} 4 | }, 5 | "initial": { 6 | "compression": {}, 7 | "cors": { 8 | "params": { 9 | "origin": true, 10 | "credentials": true, 11 | "maxAge": 86400 12 | } 13 | }, 14 | "helmet#xssFilter": {}, 15 | "helmet#frameguard": { 16 | "params": [ 17 | "deny" 18 | ] 19 | }, 20 | "helmet#hsts": { 21 | "params": { 22 | "maxAge": 0, 23 | "includeSubdomains": true 24 | } 25 | }, 26 | "helmet#hidePoweredBy": {}, 27 | "helmet#ieNoOpen": {}, 28 | "helmet#noSniff": {}, 29 | "helmet#noCache": { 30 | "enabled": false 31 | } 32 | }, 33 | "session": {}, 34 | "auth": {}, 35 | "parse": {}, 36 | "routes": { 37 | "loopback#rest": { 38 | "paths": [ 39 | "${restApiRoot}" 40 | ] 41 | } 42 | }, 43 | "files": { 44 | "loopback#static":{ 45 | "params":"$!../client" 46 | } 47 | }, 48 | "final": { 49 | "loopback#urlNotFound": {} 50 | }, 51 | "final:after": { 52 | "loopback#errorHandler": {} 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /geotest/server/middleware.production.json: -------------------------------------------------------------------------------- 1 | { 2 | "final:after": { 3 | "loopback#errorHandler": { 4 | "params": { 5 | "includeStack": false 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /geotest/server/model-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "sources": [ 4 | "loopback/common/models", 5 | "loopback/server/models", 6 | "../common/models", 7 | "./models" 8 | ], 9 | "mixins": [ 10 | "loopback/common/mixins", 11 | "loopback/server/mixins", 12 | "../common/mixins", 13 | "./mixins" 14 | ] 15 | }, 16 | "User": { 17 | "dataSource": "db" 18 | }, 19 | "AccessToken": { 20 | "dataSource": "db", 21 | "public": false 22 | }, 23 | "ACL": { 24 | "dataSource": "db", 25 | "public": false 26 | }, 27 | "RoleMapping": { 28 | "dataSource": "db", 29 | "public": false 30 | }, 31 | "Role": { 32 | "dataSource": "db", 33 | "public": false 34 | }, 35 | "Cat": { 36 | "dataSource": "db", 37 | "public": true, 38 | "$promise": {}, 39 | "$resolved": true 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /geotest/server/server.js: -------------------------------------------------------------------------------- 1 | var loopback = require('loopback'); 2 | var boot = require('loopback-boot'); 3 | 4 | var app = module.exports = loopback(); 5 | 6 | app.start = function() { 7 | // start the web server 8 | return app.listen(function() { 9 | app.emit('started'); 10 | var baseUrl = app.get('url').replace(/\/$/, ''); 11 | console.log('Web server listening at: %s', baseUrl); 12 | if (app.get('loopback-component-explorer')) { 13 | var explorerPath = app.get('loopback-component-explorer').mountPath; 14 | console.log('Browse your REST API at %s%s', baseUrl, explorerPath); 15 | } 16 | }); 17 | }; 18 | 19 | // Bootstrap the application, configure models, datasources and middleware. 20 | // Sub-apps like REST API are mounted via boot scripts. 21 | boot(app, __dirname, function(err) { 22 | if (err) throw err; 23 | 24 | // start the server if `$ node server.js` 25 | if (require.main === module) 26 | app.start(); 27 | }); 28 | -------------------------------------------------------------------------------- /ormdemo/.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # http://editorconfig.org 4 | 5 | root = true 6 | 7 | [*] 8 | indent_style = space 9 | indent_size = 2 10 | end_of_line = lf 11 | charset = utf-8 12 | trim_trailing_whitespace = true 13 | insert_final_newline = true 14 | -------------------------------------------------------------------------------- /ormdemo/.gitignore: -------------------------------------------------------------------------------- 1 | *.csv 2 | *.dat 3 | *.iml 4 | *.log 5 | *.out 6 | *.pid 7 | *.seed 8 | *.sublime-* 9 | *.swo 10 | *.swp 11 | *.tgz 12 | *.xml 13 | .DS_Store 14 | .idea 15 | .project 16 | .strong-pm 17 | coverage 18 | node_modules 19 | npm-debug.log 20 | -------------------------------------------------------------------------------- /ormdemo/.jshintignore: -------------------------------------------------------------------------------- 1 | /client/ 2 | /node_modules/ 3 | -------------------------------------------------------------------------------- /ormdemo/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "esnext": true, 4 | "bitwise": true, 5 | "camelcase": true, 6 | "eqeqeq": true, 7 | "eqnull": true, 8 | "immed": true, 9 | "indent": 2, 10 | "latedef": "nofunc", 11 | "newcap": true, 12 | "nonew": true, 13 | "noarg": true, 14 | "quotmark": "single", 15 | "regexp": true, 16 | "undef": true, 17 | "unused": false, 18 | "trailing": true, 19 | "sub": true, 20 | "maxlen": 80 21 | } 22 | -------------------------------------------------------------------------------- /ormdemo/.yo-rc.json: -------------------------------------------------------------------------------- 1 | { 2 | "generator-loopback": {} 3 | } -------------------------------------------------------------------------------- /ormdemo/README.md: -------------------------------------------------------------------------------- 1 | # My Application 2 | 3 | The project is generated by [LoopBack](http://loopback.io). -------------------------------------------------------------------------------- /ormdemo/client/README.md: -------------------------------------------------------------------------------- 1 | ## Client 2 | 3 | This is the place for your application front-end files. 4 | -------------------------------------------------------------------------------- /ormdemo/common/models/part.js: -------------------------------------------------------------------------------- 1 | module.exports = function(Part) { 2 | 3 | }; 4 | -------------------------------------------------------------------------------- /ormdemo/common/models/part.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Part", 3 | "plural": "Parts", 4 | "base": "PersistedModel", 5 | "idInjection": true, 6 | "options": { 7 | "validateUpsert": true 8 | }, 9 | "properties": { 10 | "name": { 11 | "type": "string" 12 | } 13 | }, 14 | "validations": [], 15 | "relations": { 16 | "products": { 17 | "type": "hasAndBelongsToMany", 18 | "model": "Product", 19 | "foreignKey": "" 20 | } 21 | }, 22 | "acls": [], 23 | "methods": {} 24 | } 25 | -------------------------------------------------------------------------------- /ormdemo/common/models/product.js: -------------------------------------------------------------------------------- 1 | module.exports = function(Product) { 2 | 3 | }; 4 | -------------------------------------------------------------------------------- /ormdemo/common/models/product.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Product", 3 | "plural": "Products", 4 | "base": "PersistedModel", 5 | "idInjection": true, 6 | "options": { 7 | "validateUpsert": true 8 | }, 9 | "properties": { 10 | "name": { 11 | "type": "string" 12 | }, 13 | "price": { 14 | "type": "number" 15 | } 16 | }, 17 | "validations": [], 18 | "relations": { 19 | "parts": { 20 | "type": "hasAndBelongsToMany", 21 | "model": "Part", 22 | "foreignKey": "" 23 | } 24 | }, 25 | "acls": [], 26 | "methods": {} 27 | } 28 | -------------------------------------------------------------------------------- /ormdemo/common/models/test.js: -------------------------------------------------------------------------------- 1 | module.exports = function(Test) { 2 | 3 | }; 4 | -------------------------------------------------------------------------------- /ormdemo/common/models/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test", 3 | "base": "PersistedModel", 4 | "strict": false, 5 | "idInjection": false, 6 | "options": { 7 | "validateUpsert": true 8 | }, 9 | "properties": { 10 | "name": { 11 | "type": "string" 12 | } 13 | }, 14 | "validations": [], 15 | "relations": {}, 16 | "acls": [], 17 | "methods": {} 18 | } 19 | -------------------------------------------------------------------------------- /ormdemo/data.db: -------------------------------------------------------------------------------- 1 | { 2 | "ids": { 3 | "User": 1, 4 | "AccessToken": 1, 5 | "ACL": 1, 6 | "RoleMapping": 1, 7 | "Role": 1, 8 | "Product": 5, 9 | "Part": 4 10 | }, 11 | "models": { 12 | "User": {}, 13 | "AccessToken": {}, 14 | "ACL": {}, 15 | "RoleMapping": {}, 16 | "Role": {}, 17 | "Product": { 18 | "1": "{\"name\":\"productAlpha!\",\"price\":90,\"id\":1}", 19 | "4": "{\"name\":\"moon\",\"price\":9,\"id\":4}" 20 | }, 21 | "Part": { 22 | "1": "{\"name\":\"partA!\",\"id\":1}", 23 | "3": "{\"name\":\"partb\",\"id\":3}" 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /ormdemo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ormdemo", 3 | "version": "1.0.0", 4 | "main": "server/server.js", 5 | "scripts": { 6 | "start": "node .", 7 | "pretest": "jshint .", 8 | "posttest": "nsp check" 9 | }, 10 | "dependencies": { 11 | "body-parser": "^1.15.0", 12 | "compression": "^1.0.3", 13 | "cors": "^2.5.2", 14 | "express-handlebars": "^2.0.1", 15 | "helmet": "^0.14.0", 16 | "loopback": "^2.22.0", 17 | "loopback-boot": "^2.6.5", 18 | "loopback-component-explorer": "^2.1.0", 19 | "loopback-connector-mongodb": "^1.13.3", 20 | "loopback-datasource-juggler": "^2.39.0", 21 | "serve-favicon": "^2.0.1" 22 | }, 23 | "devDependencies": { 24 | "jshint": "^2.5.6", 25 | "nsp": "^2.1.0" 26 | }, 27 | "repository": { 28 | "type": "", 29 | "url": "" 30 | }, 31 | "description": "ormdemo" 32 | } 33 | -------------------------------------------------------------------------------- /ormdemo/server/boot/authentication.js: -------------------------------------------------------------------------------- 1 | module.exports = function enableAuthentication(server) { 2 | // enable authentication 3 | server.enableAuth(); 4 | }; 5 | -------------------------------------------------------------------------------- /ormdemo/server/boot/root.js: -------------------------------------------------------------------------------- 1 | module.exports = function(server) { 2 | // Install a `/` route that returns server status 3 | /* 4 | var router = server.loopback.Router(); 5 | router.get('/', server.loopback.status()); 6 | server.use(router); 7 | */ 8 | }; 9 | -------------------------------------------------------------------------------- /ormdemo/server/component-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "loopback-component-explorer": { 3 | "mountPath": "/explorer" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /ormdemo/server/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "restApiRoot": "/api", 3 | "host": "0.0.0.0", 4 | "port": 3000, 5 | "remoting": { 6 | "context": { 7 | "enableHttpContext": false 8 | }, 9 | "rest": { 10 | "normalizeHttpPath": false, 11 | "xml": false 12 | }, 13 | "json": { 14 | "strict": false, 15 | "limit": "100kb" 16 | }, 17 | "urlencoded": { 18 | "extended": true, 19 | "limit": "100kb" 20 | }, 21 | "cors": false, 22 | "errorHandler": { 23 | "disableStackTrace": false 24 | } 25 | }, 26 | "legacyExplorer": false 27 | } 28 | -------------------------------------------------------------------------------- /ormdemo/server/datasources.json: -------------------------------------------------------------------------------- 1 | { 2 | "db": { 3 | "name": "db", 4 | "connector": "memory", 5 | "file": "data.db" 6 | }, 7 | "mongodatasource": { 8 | "database": "ormdemo", 9 | "name": "mongodatasource", 10 | "connector": "mongodb" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /ormdemo/server/middleware.json: -------------------------------------------------------------------------------- 1 | { 2 | "initial:before": { 3 | "loopback#favicon": {} 4 | }, 5 | "initial": { 6 | "compression": {}, 7 | "cors": { 8 | "params": { 9 | "origin": true, 10 | "credentials": true, 11 | "maxAge": 86400 12 | } 13 | }, 14 | "helmet#xssFilter": {}, 15 | "helmet#frameguard": { 16 | "params": [ 17 | "deny" 18 | ] 19 | }, 20 | "helmet#hsts": { 21 | "params": { 22 | "maxAge": 0, 23 | "includeSubdomains": true 24 | } 25 | }, 26 | "helmet#hidePoweredBy": {}, 27 | "helmet#ieNoOpen": {}, 28 | "helmet#noSniff": {}, 29 | "helmet#noCache": { 30 | "enabled": false 31 | } 32 | }, 33 | "session": {}, 34 | "auth": {}, 35 | "parse": {}, 36 | "routes": { 37 | "loopback#rest": { 38 | "paths": [ 39 | "${restApiRoot}" 40 | ] 41 | } 42 | }, 43 | "files": { 44 | "loopback#static": { 45 | "params": "$!./public" 46 | } 47 | }, 48 | "final": { 49 | "loopback#urlNotFound": {} 50 | }, 51 | "final:after": { 52 | "loopback#errorHandler": {} 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /ormdemo/server/middleware.production.json: -------------------------------------------------------------------------------- 1 | { 2 | "final:after": { 3 | "loopback#errorHandler": { 4 | "params": { 5 | "includeStack": false 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /ormdemo/server/model-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "sources": [ 4 | "loopback/common/models", 5 | "loopback/server/models", 6 | "../common/models", 7 | "./models" 8 | ], 9 | "mixins": [ 10 | "loopback/common/mixins", 11 | "loopback/server/mixins", 12 | "../common/mixins", 13 | "./mixins" 14 | ] 15 | }, 16 | "User": { 17 | "dataSource": "db" 18 | }, 19 | "AccessToken": { 20 | "dataSource": "db", 21 | "public": false 22 | }, 23 | "ACL": { 24 | "dataSource": "db", 25 | "public": false 26 | }, 27 | "RoleMapping": { 28 | "dataSource": "db", 29 | "public": false 30 | }, 31 | "Role": { 32 | "dataSource": "db", 33 | "public": false 34 | }, 35 | "Product": { 36 | "dataSource": "mongodatasource", 37 | "public": true, 38 | "$promise": {}, 39 | "$resolved": true 40 | }, 41 | "Part": { 42 | "dataSource": "mongodatasource", 43 | "public": true, 44 | "$promise": {}, 45 | "$resolved": true 46 | }, 47 | "test": { 48 | "dataSource": "mongodatasource", 49 | "public": true, 50 | "$promise": {}, 51 | "$resolved": true 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /ormdemo/server/public/css/styles.css: -------------------------------------------------------------------------------- 1 | table { 2 | width: 400px; 3 | } 4 | 5 | label { 6 | width: 75px; 7 | display: inline-block; 8 | } -------------------------------------------------------------------------------- /ormdemo/server/server.js: -------------------------------------------------------------------------------- 1 | var loopback = require('loopback'); 2 | var boot = require('loopback-boot'); 3 | 4 | var app = module.exports = loopback(); 5 | var bodyParser = require('body-parser'); 6 | app.use(bodyParser.urlencoded({ extended: true })); 7 | 8 | var exphbs = require('express-handlebars'); 9 | 10 | // We customize layoutsDir and views (few lines below) due to confusion of paths by default 11 | var hbs = exphbs.create({ 12 | defaultLayout:'main', 13 | layoutsDir:__dirname+'/views/layouts', 14 | helpers:{ 15 | ifSelected:function(product,partid) { 16 | if(!product) return ''; 17 | var parts = product.parts(); 18 | for(var i=0;iEdit 2 | 3 |
4 | 5 |

6 |
7 |

8 |

9 |
10 |

11 |

12 | 13 | 18 |

19 | 20 |
21 | -------------------------------------------------------------------------------- /ormdemo/server/views/editpart.handlebars: -------------------------------------------------------------------------------- 1 |

Edit

2 | 3 |
4 | 5 |

6 |
7 |

8 | 9 |
10 | -------------------------------------------------------------------------------- /ormdemo/server/views/index.handlebars: -------------------------------------------------------------------------------- 1 |

Products

2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | {{#each products}} 13 | 14 | 15 | 16 | 17 | 18 | {{/each}} 19 | 20 |
NamePrice
{{name}}{{price}}Delete
21 | 22 |

23 | Add New Product 24 |

25 | 26 |

Parts

27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | {{#each parts}} 37 | 38 | 39 | 40 | 41 | {{/each}} 42 | 43 |
Name
{{name}}Delete
44 | 45 |

46 | Add New Part 47 |

-------------------------------------------------------------------------------- /ormdemo/server/views/layouts/main.handlebars: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | {{{body}}} 9 | 10 | 11 | -------------------------------------------------------------------------------- /simpleauthdemo/.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # http://editorconfig.org 4 | 5 | root = true 6 | 7 | [*] 8 | indent_style = space 9 | indent_size = 2 10 | end_of_line = lf 11 | charset = utf-8 12 | trim_trailing_whitespace = true 13 | insert_final_newline = true 14 | -------------------------------------------------------------------------------- /simpleauthdemo/.eslintignore: -------------------------------------------------------------------------------- 1 | /client/ -------------------------------------------------------------------------------- /simpleauthdemo/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "loopback" 3 | } -------------------------------------------------------------------------------- /simpleauthdemo/.gitignore: -------------------------------------------------------------------------------- 1 | *.csv 2 | *.dat 3 | *.iml 4 | *.log 5 | *.out 6 | *.pid 7 | *.seed 8 | *.sublime-* 9 | *.swo 10 | *.swp 11 | *.tgz 12 | *.xml 13 | .DS_Store 14 | .idea 15 | .project 16 | .strong-pm 17 | coverage 18 | node_modules 19 | npm-debug.log 20 | -------------------------------------------------------------------------------- /simpleauthdemo/.yo-rc.json: -------------------------------------------------------------------------------- 1 | { 2 | "generator-loopback": {} 3 | } -------------------------------------------------------------------------------- /simpleauthdemo/README.md: -------------------------------------------------------------------------------- 1 | # Simple Authentication Demo 2 | 3 | Blog post coming soon! -------------------------------------------------------------------------------- /simpleauthdemo/client/README.md: -------------------------------------------------------------------------------- 1 | ## Client 2 | 3 | This is the place for your application front-end files. 4 | -------------------------------------------------------------------------------- /simpleauthdemo/common/models/appuser.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function(Appuser) { 4 | 5 | }; 6 | -------------------------------------------------------------------------------- /simpleauthdemo/common/models/appuser.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "appuser", 3 | "base": "User", 4 | "idInjection": true, 5 | "options": { 6 | "validateUpsert": true 7 | }, 8 | "properties": {}, 9 | "validations": [], 10 | "relations": {}, 11 | "acls": [], 12 | "methods": {} 13 | } 14 | -------------------------------------------------------------------------------- /simpleauthdemo/common/models/post.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function(Post) { 4 | 5 | Post.beforeRemote('create', function(ctx, instance, next) { 6 | console.log('before create'); 7 | //override created 8 | ctx.args.data.created = new Date(); 9 | //set creator to current user 10 | ctx.args.data.ownerId = ctx.req.accessToken.userId; 11 | 12 | next(); 13 | }); 14 | }; 15 | 16 | -------------------------------------------------------------------------------- /simpleauthdemo/common/models/post.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "post", 3 | "base": "PersistedModel", 4 | "idInjection": true, 5 | "options": { 6 | "validateUpsert": true 7 | }, 8 | "properties": { 9 | "created": { 10 | "type": "date", 11 | "required": false 12 | }, 13 | "text": { 14 | "type": "string", 15 | "required": true 16 | } 17 | }, 18 | "validations": [], 19 | "relations": { 20 | "creator": { 21 | "type": "belongsTo", 22 | "model": "appuser", 23 | "foreignKey": "ownerId" 24 | } 25 | }, 26 | "acls": [ 27 | { 28 | "accessType": "*", 29 | "principalType": "ROLE", 30 | "principalId": "$everyone", 31 | "permission": "DENY" 32 | }, 33 | { 34 | "accessType": "EXECUTE", 35 | "principalType": "ROLE", 36 | "principalId": "$authenticated", 37 | "permission": "ALLOW", 38 | "property": "create" 39 | }, 40 | { 41 | "accessType": "EXECUTE", 42 | "principalType": "ROLE", 43 | "principalId": "$owner", 44 | "permission": "ALLOW", 45 | "property": ["updateAttributes","deleteById"] 46 | }, 47 | { 48 | "accessType": "READ", 49 | "principalType": "ROLE", 50 | "principalId": "$everyone", 51 | "permission": "ALLOW" 52 | } 53 | ], 54 | "methods": {} 55 | } 56 | -------------------------------------------------------------------------------- /simpleauthdemo/data.db: -------------------------------------------------------------------------------- 1 | { 2 | "ids": { 3 | "User": 1, 4 | "AccessToken": 10, 5 | "ACL": 1, 6 | "RoleMapping": 1, 7 | "Role": 1, 8 | "post": 23, 9 | "appuser": 5 10 | }, 11 | "models": { 12 | "User": {}, 13 | "AccessToken": { 14 | "AqL45B6g9iiMcTv8LFGuGFSsUuYPVawCBo2ugDpQT43ZmdSWTjJ9bNYc7mloBaD5": "{\"id\":\"AqL45B6g9iiMcTv8LFGuGFSsUuYPVawCBo2ugDpQT43ZmdSWTjJ9bNYc7mloBaD5\",\"ttl\":1209600,\"created\":\"2016-11-07T17:14:41.616Z\",\"userId\":1}", 15 | "0DVkQecyU4mCDMxpJyvJ9GQbgZhjlmoWJOOuEGLVFH4K4xvbkYlCcLEdRDGZceC1": "{\"id\":\"0DVkQecyU4mCDMxpJyvJ9GQbgZhjlmoWJOOuEGLVFH4K4xvbkYlCcLEdRDGZceC1\",\"ttl\":1209600,\"created\":\"2016-11-07T18:30:59.622Z\",\"userId\":1}", 16 | "BQJGfxNQVif2Owyb9LqjnQslTADYlXLayjYDNpWLY3imKUWNlcGxCvTaBx2ItM0L": "{\"id\":\"BQJGfxNQVif2Owyb9LqjnQslTADYlXLayjYDNpWLY3imKUWNlcGxCvTaBx2ItM0L\",\"ttl\":1209600,\"created\":\"2016-11-07T18:54:50.180Z\",\"userId\":1}", 17 | "RuJRBDtCxMrnmiFQnng7EFByTMop6pc1lLNX7BDxFMBXBHEes6FUngWIu9Wh7rDD": "{\"id\":\"RuJRBDtCxMrnmiFQnng7EFByTMop6pc1lLNX7BDxFMBXBHEes6FUngWIu9Wh7rDD\",\"ttl\":1209600,\"created\":\"2016-11-08T20:09:55.649Z\",\"userId\":3}", 18 | "ASfG7j6rJu2CQn1ywq5KcVxstqEZCazBOdWv0QCqFoECP05Ggom4yDPyQtFgab2g": "{\"id\":\"ASfG7j6rJu2CQn1ywq5KcVxstqEZCazBOdWv0QCqFoECP05Ggom4yDPyQtFgab2g\",\"ttl\":1209600,\"created\":\"2016-11-08T20:15:14.322Z\",\"userId\":4}", 19 | "yW4ZOzNS3JGWzAztnfydCQUx6yG9AEqZPdcYzOva78VviIGnUSovEO4lACwrRin9": "{\"id\":\"yW4ZOzNS3JGWzAztnfydCQUx6yG9AEqZPdcYzOva78VviIGnUSovEO4lACwrRin9\",\"ttl\":1209600,\"created\":\"2016-11-08T23:07:33.274Z\",\"userId\":3}", 20 | "7JDVRr7Nxk4kZTu0XjDRNalVzJrFg83dsqvmy2WzWQKKJMCKUipid98n9cMtjNhh": "{\"id\":\"7JDVRr7Nxk4kZTu0XjDRNalVzJrFg83dsqvmy2WzWQKKJMCKUipid98n9cMtjNhh\",\"ttl\":1209600,\"created\":\"2016-11-08T23:08:04.553Z\",\"userId\":3}", 21 | "K62zp82lb0B5BvcmgrOL1Wo4Yo2nGShD2sPqTUEziDgryfF78HeT3GGW269PqmYB": "{\"id\":\"K62zp82lb0B5BvcmgrOL1Wo4Yo2nGShD2sPqTUEziDgryfF78HeT3GGW269PqmYB\",\"ttl\":1209600,\"created\":\"2016-11-08T23:14:50.980Z\",\"userId\":3}", 22 | "4HWCh6TEYNRzCVicpSN64ndggyJWeDu0I7kEDTxTsqwjEyZkM16MlwiCIfu8cs35": "{\"id\":\"4HWCh6TEYNRzCVicpSN64ndggyJWeDu0I7kEDTxTsqwjEyZkM16MlwiCIfu8cs35\",\"ttl\":1209600,\"created\":\"2016-11-08T23:20:06.158Z\",\"userId\":3}" 23 | }, 24 | "ACL": {}, 25 | "RoleMapping": {}, 26 | "Role": {}, 27 | "post": { 28 | "16": "{\"created\":\"2016-11-07T20:07:21.433Z\",\"text\":\"strsddksjdksjsdkjing\",\"ownerId\":1,\"id\":16}", 29 | "17": "{\"created\":\"2016-11-08T16:22:13.781Z\",\"text\":\"test on the 8th\",\"ownerId\":1,\"id\":17}", 30 | "18": "{\"created\":\"2016-11-08T16:27:18.115Z\",\"text\":\"test on the 8th part deux\",\"ownerId\":1,\"id\":18}", 31 | "19": "{\"created\":\"2016-11-08T16:36:07.004Z\",\"text\":\"test on the 8th part three\",\"ownerId\":1,\"id\":19}", 32 | "20": "{\"created\":\"2016-11-08T16:37:39.035Z\",\"text\":\"test on the 8th part 4\",\"ownerId\":1,\"id\":20}", 33 | "21": "{\"created\":\"2016-11-08T16:57:48.601Z\",\"text\":\"sMOOOOOOOtring\",\"ownerId\":1,\"id\":21}", 34 | "22": "{\"created\":\"2016-11-08T23:20:10.447Z\",\"text\":\"foo\",\"ownerId\":3,\"id\":22}" 35 | }, 36 | "appuser": { 37 | "1": "{\"password\":\"$2a$10$64cmhn7nw4TZnAoGJQJZket3AulLKemhDdOObhvaxHjPuxXWapEcW\",\"email\":\"user1@gmail.com\",\"id\":1}", 38 | "2": "{\"password\":\"$2a$10$SIoKTp5QrPJubJ9IQS799.p9PVI1.hEvQwBe8ip3oUoBafWKgZS3u\",\"email\":\"user2@gmail.com\",\"id\":2}", 39 | "3": "{\"password\":\"$2a$10$xLnnRgb9e6fF90bSw55lD.Myp.zmDSdAMaQrxsngXr69DhG6xlqqS\",\"email\":\"user3@gmail.com\",\"id\":3}", 40 | "4": "{\"password\":\"$2a$10$xxjL3x7/WXNhykLj0o69nu/Ly/obXQ8dFXtDJJr6z54i7oth2J6oy\",\"email\":\"user4@gmail.com\",\"id\":4}" 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /simpleauthdemo/notes.txt: -------------------------------------------------------------------------------- 1 | Need to extend User (done) 2 | Need to hide User (public: false) 3 | 4 | No way to automatically say, "when making ob, set owner to me" 5 | Link A to B(where B extends user) * thats the magic 6 | 7 | 8 | the object X belongs to me if: 9 | 10 | [12:26] 11 | a) it has a relation to a model that extends user (and obviously it points to me) 12 | 13 | [12:26] 14 | b) it has a simple property called userId where the val matches my user ID 15 | 16 | [12:26] 17 | c) ditto for "owner" 18 | 19 | 20 | When locking down a method - how do you know the names? 21 | this list - http://apidocs.strongloop.com/loopback/#persistedmodel 22 | 23 | beforeSave, set to currentuser 24 | 25 | auth req error even though logged in 26 | -------------------------------------------------------------------------------- /simpleauthdemo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "simpleauthdemo", 3 | "version": "1.0.0", 4 | "main": "server/server.js", 5 | "scripts": { 6 | "lint": "eslint .", 7 | "start": "node .", 8 | "posttest": "npm run lint && nsp check" 9 | }, 10 | "dependencies": { 11 | "compression": "^1.0.3", 12 | "cors": "^2.5.2", 13 | "helmet": "^1.3.0", 14 | "loopback-boot": "^2.6.5", 15 | "loopback-component-explorer": "^2.4.0", 16 | "serve-favicon": "^2.0.1", 17 | "strong-error-handler": "^1.0.1", 18 | "loopback-datasource-juggler": "^2.39.0", 19 | "loopback": "^2.22.0" 20 | }, 21 | "devDependencies": { 22 | "eslint": "^2.13.1", 23 | "eslint-config-loopback": "^4.0.0", 24 | "nsp": "^2.1.0" 25 | }, 26 | "repository": { 27 | "type": "", 28 | "url": "" 29 | }, 30 | "license": "UNLICENSED", 31 | "description": "simpleauthdemo" 32 | } 33 | -------------------------------------------------------------------------------- /simpleauthdemo/server/boot/authentication.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function enableAuthentication(server) { 4 | // enable authentication 5 | server.enableAuth(); 6 | }; 7 | -------------------------------------------------------------------------------- /simpleauthdemo/server/boot/root.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function(server) { 4 | // Install a `/` route that returns server status 5 | var router = server.loopback.Router(); 6 | //router.get('/', server.loopback.status()); 7 | server.use(router); 8 | }; 9 | -------------------------------------------------------------------------------- /simpleauthdemo/server/component-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "loopback-component-explorer": { 3 | "mountPath": "/explorer" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /simpleauthdemo/server/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "restApiRoot": "/api", 3 | "host": "0.0.0.0", 4 | "port": 3000, 5 | "remoting": { 6 | "context": false, 7 | "rest": { 8 | "normalizeHttpPath": false, 9 | "xml": false 10 | }, 11 | "json": { 12 | "strict": false, 13 | "limit": "100kb" 14 | }, 15 | "urlencoded": { 16 | "extended": true, 17 | "limit": "100kb" 18 | }, 19 | "cors": false, 20 | "handleErrors": false 21 | }, 22 | "legacyExplorer": false 23 | } 24 | -------------------------------------------------------------------------------- /simpleauthdemo/server/datasources.json: -------------------------------------------------------------------------------- 1 | { 2 | "db": { 3 | "name": "db", 4 | "connector": "memory", 5 | "file": "data.db" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /simpleauthdemo/server/middleware.development.json: -------------------------------------------------------------------------------- 1 | { 2 | "final:after": { 3 | "strong-error-handler": { 4 | "params": { 5 | "debug": true, 6 | "log": true 7 | } 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /simpleauthdemo/server/middleware.json: -------------------------------------------------------------------------------- 1 | { 2 | "initial:before": { 3 | "loopback#favicon": {} 4 | }, 5 | "initial": { 6 | "compression": {}, 7 | "cors": { 8 | "params": { 9 | "origin": true, 10 | "credentials": true, 11 | "maxAge": 86400 12 | } 13 | }, 14 | "helmet#xssFilter": {}, 15 | "helmet#frameguard": { 16 | "params": [ 17 | "deny" 18 | ] 19 | }, 20 | "helmet#hsts": { 21 | "params": { 22 | "maxAge": 0, 23 | "includeSubdomains": true 24 | } 25 | }, 26 | "helmet#hidePoweredBy": {}, 27 | "helmet#ieNoOpen": {}, 28 | "helmet#noSniff": {}, 29 | "helmet#noCache": { 30 | "enabled": false 31 | } 32 | }, 33 | "session": {}, 34 | "auth": {}, 35 | "parse": {}, 36 | "routes": { 37 | "loopback#rest": { 38 | "paths": [ 39 | "${restApiRoot}" 40 | ] 41 | } 42 | }, 43 | "files": { 44 | "loopback#static": { 45 | "params": "$!../client" 46 | } 47 | }, 48 | "final": { 49 | "loopback#urlNotFound": {} 50 | }, 51 | "final:after": { 52 | "strong-error-handler": {} 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /simpleauthdemo/server/model-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "sources": [ 4 | "loopback/common/models", 5 | "loopback/server/models", 6 | "../common/models", 7 | "./models" 8 | ], 9 | "mixins": [ 10 | "loopback/common/mixins", 11 | "loopback/server/mixins", 12 | "../common/mixins", 13 | "./mixins" 14 | ] 15 | }, 16 | "User": { 17 | "dataSource": "db", 18 | "public": false 19 | }, 20 | "AccessToken": { 21 | "dataSource": "db", 22 | "public": false 23 | }, 24 | "ACL": { 25 | "dataSource": "db", 26 | "public": false 27 | }, 28 | "RoleMapping": { 29 | "dataSource": "db", 30 | "public": false 31 | }, 32 | "Role": { 33 | "dataSource": "db", 34 | "public": false 35 | }, 36 | "post": { 37 | "dataSource": "db", 38 | "public": true 39 | }, 40 | "appuser": { 41 | "dataSource": "db", 42 | "public": true 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /simpleauthdemo/server/server.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var loopback = require('loopback'); 4 | var boot = require('loopback-boot'); 5 | 6 | var app = module.exports = loopback(); 7 | 8 | app.start = function() { 9 | // start the web server 10 | return app.listen(function() { 11 | app.emit('started'); 12 | var baseUrl = app.get('url').replace(/\/$/, ''); 13 | console.log('Web server listening at: %s', baseUrl); 14 | if (app.get('loopback-component-explorer')) { 15 | var explorerPath = app.get('loopback-component-explorer').mountPath; 16 | console.log('Browse your REST API at %s%s', baseUrl, explorerPath); 17 | } 18 | }); 19 | }; 20 | 21 | // Bootstrap the application, configure models, datasources and middleware. 22 | // Sub-apps like REST API are mounted via boot scripts. 23 | boot(app, __dirname, function(err) { 24 | if (err) throw err; 25 | 26 | // start the server if `$ node server.js` 27 | if (require.main === module) 28 | app.start(); 29 | }); 30 | -------------------------------------------------------------------------------- /superlongscroll/.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # http://editorconfig.org 4 | 5 | root = true 6 | 7 | [*] 8 | indent_style = space 9 | indent_size = 2 10 | end_of_line = lf 11 | charset = utf-8 12 | trim_trailing_whitespace = true 13 | insert_final_newline = true 14 | -------------------------------------------------------------------------------- /superlongscroll/.gitignore: -------------------------------------------------------------------------------- 1 | *.csv 2 | *.dat 3 | *.iml 4 | *.log 5 | *.out 6 | *.pid 7 | *.seed 8 | *.sublime-* 9 | *.swo 10 | *.swp 11 | *.tgz 12 | *.xml 13 | .DS_Store 14 | .idea 15 | .project 16 | .strong-pm 17 | coverage 18 | node_modules 19 | npm-debug.log 20 | -------------------------------------------------------------------------------- /superlongscroll/.jshintignore: -------------------------------------------------------------------------------- 1 | /client/ 2 | /node_modules/ 3 | -------------------------------------------------------------------------------- /superlongscroll/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "esnext": true, 4 | "bitwise": true, 5 | "camelcase": true, 6 | "eqeqeq": true, 7 | "eqnull": true, 8 | "immed": true, 9 | "indent": 2, 10 | "latedef": "nofunc", 11 | "newcap": true, 12 | "nonew": true, 13 | "noarg": true, 14 | "quotmark": "single", 15 | "regexp": true, 16 | "undef": true, 17 | "unused": false, 18 | "trailing": true, 19 | "sub": true, 20 | "maxlen": 80 21 | } 22 | -------------------------------------------------------------------------------- /superlongscroll/.yo-rc.json: -------------------------------------------------------------------------------- 1 | { 2 | "generator-loopback": {} 3 | } -------------------------------------------------------------------------------- /superlongscroll/client/README.md: -------------------------------------------------------------------------------- 1 | ## Client 2 | 3 | This is the place for your application front-end files. 4 | -------------------------------------------------------------------------------- /superlongscroll/client/app1/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | www/build/ 3 | platforms/ 4 | plugins/ 5 | .DS_Store 6 | -------------------------------------------------------------------------------- /superlongscroll/client/app1/.vscode/typings/cordova/cordova.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for Apache Cordova 2 | // Project: http://cordova.apache.org 3 | // Definitions by: Microsoft Open Technologies Inc. 4 | // Definitions: https://github.com/borisyankov/DefinitelyTyped 5 | // 6 | // Copyright (c) Microsoft Open Technologies, Inc. 7 | // Licensed under the MIT license. 8 | 9 | interface Cordova { 10 | /** Invokes native functionality by specifying corresponding service name, action and optional parameters. 11 | * @param success A success callback function. 12 | * @param fail An error callback function. 13 | * @param service The service name to call on the native side (corresponds to a native class). 14 | * @param action The action name to call on the native side (generally corresponds to the native class method). 15 | * @param args An array of arguments to pass into the native environment. 16 | */ 17 | exec(success: () => any, fail: () => any, service: string, action: string, args?: string[]): void; 18 | /** Gets the operating system name. */ 19 | platformId: string; 20 | /** Gets Cordova framework version */ 21 | version: string; 22 | /** Defines custom logic as a Cordova module. Other modules can later access it using module name provided. */ 23 | define(moduleName: string, factory: (require: any, exports: any, module: any) => any): void; 24 | /** Access a Cordova module by name. */ 25 | require(moduleName: string): any; 26 | /** Namespace for Cordova plugin functionality */ 27 | plugins:CordovaPlugins; 28 | } 29 | 30 | interface CordovaPlugins {} 31 | 32 | interface Document { 33 | addEventListener(type: "deviceready", listener: (ev: Event) => any, useCapture?: boolean): void; 34 | addEventListener(type: "pause", listener: (ev: Event) => any, useCapture?: boolean): void; 35 | addEventListener(type: "resume", listener: (ev: Event) => any, useCapture?: boolean): void; 36 | addEventListener(type: "backbutton", listener: (ev: Event) => any, useCapture?: boolean): void; 37 | addEventListener(type: "menubutton", listener: (ev: Event) => any, useCapture?: boolean): void; 38 | addEventListener(type: "searchbutton", listener: (ev: Event) => any, useCapture?: boolean): void; 39 | addEventListener(type: "startcallbutton", listener: (ev: Event) => any, useCapture?: boolean): void; 40 | addEventListener(type: "endcallbutton", listener: (ev: Event) => any, useCapture?: boolean): void; 41 | addEventListener(type: "volumedownbutton", listener: (ev: Event) => any, useCapture?: boolean): void; 42 | addEventListener(type: "volumeupbutton", listener: (ev: Event) => any, useCapture?: boolean): void; 43 | 44 | removeEventListener(type: "deviceready", listener: (ev: Event) => any, useCapture?: boolean): void; 45 | removeEventListener(type: "pause", listener: (ev: Event) => any, useCapture?: boolean): void; 46 | removeEventListener(type: "resume", listener: (ev: Event) => any, useCapture?: boolean): void; 47 | removeEventListener(type: "backbutton", listener: (ev: Event) => any, useCapture?: boolean): void; 48 | removeEventListener(type: "menubutton", listener: (ev: Event) => any, useCapture?: boolean): void; 49 | removeEventListener(type: "searchbutton", listener: (ev: Event) => any, useCapture?: boolean): void; 50 | removeEventListener(type: "startcallbutton", listener: (ev: Event) => any, useCapture?: boolean): void; 51 | removeEventListener(type: "endcallbutton", listener: (ev: Event) => any, useCapture?: boolean): void; 52 | removeEventListener(type: "volumedownbutton", listener: (ev: Event) => any, useCapture?: boolean): void; 53 | removeEventListener(type: "volumeupbutton", listener: (ev: Event) => any, useCapture?: boolean): void; 54 | 55 | addEventListener(type: string, listener: (ev: Event) => any, useCapture?: boolean): void; 56 | removeEventListener(type: string, listener: (ev: Event) => any, useCapture?: boolean): void; 57 | } 58 | 59 | interface Window { 60 | cordova:Cordova; 61 | } 62 | 63 | // cordova/argscheck module 64 | interface ArgsCheck { 65 | checkArgs(argsSpec: string, functionName: string, args: any[], callee?: any): void; 66 | getValue(value?: any, defaultValue?: any): any; 67 | enableChecks: boolean; 68 | } 69 | 70 | // cordova/urlutil module 71 | interface UrlUtil { 72 | makeAbsolute(url: string): string 73 | } 74 | 75 | /** Apache Cordova instance */ 76 | declare var cordova: Cordova; 77 | 78 | declare module 'cordova' { 79 | export = cordova; 80 | } 81 | -------------------------------------------------------------------------------- /superlongscroll/client/app1/app/app.ts: -------------------------------------------------------------------------------- 1 | import {App, Platform} from 'ionic-angular'; 2 | import {StatusBar} from 'ionic-native'; 3 | import {HomePage} from './pages/home/home'; 4 | 5 | 6 | @App({ 7 | template: '', 8 | config: {} // http://ionicframework.com/docs/v2/api/config/Config/ 9 | }) 10 | export class MyApp { 11 | rootPage: any = HomePage; 12 | 13 | constructor(platform: Platform) { 14 | platform.ready().then(() => { 15 | // Okay, so the platform is ready and our plugins are available. 16 | // Here you can do any higher level native things you might need. 17 | StatusBar.styleDefault(); 18 | }); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /superlongscroll/client/app1/app/pages/home/home.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Home 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |

{{person.name}}

15 |
16 |
17 | 18 | 19 | 20 | 21 | 22 |
23 | -------------------------------------------------------------------------------- /superlongscroll/client/app1/app/pages/home/home.scss: -------------------------------------------------------------------------------- 1 | .home { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /superlongscroll/client/app1/app/pages/home/home.ts: -------------------------------------------------------------------------------- 1 | import {Page} from 'ionic-angular'; 2 | import {PeopleService} from '../../providers/people-service/people-service'; 3 | 4 | @Page({ 5 | templateUrl: 'build/pages/home/home.html', 6 | providers:[PeopleService] 7 | 8 | }) 9 | export class HomePage { 10 | public people:any = []; 11 | private start:number=0; 12 | 13 | constructor(public peopleService:PeopleService) { 14 | 15 | this.loadPeople(); 16 | } 17 | 18 | loadPeople() { 19 | 20 | return new Promise(resolve => { 21 | 22 | this.peopleService.load(this.start) 23 | .then(data => { 24 | 25 | for(let person of data) { 26 | this.people.push(person); 27 | } 28 | 29 | resolve(true); 30 | 31 | }); 32 | 33 | }); 34 | 35 | } 36 | 37 | doInfinite(infiniteScroll:any) { 38 | console.log('doInfinite, start is currently '+this.start); 39 | this.start+=50; 40 | 41 | this.loadPeople().then(()=>{ 42 | infiniteScroll.complete(); 43 | }); 44 | 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /superlongscroll/client/app1/app/providers/people-service/people-service.ts: -------------------------------------------------------------------------------- 1 | import {Injectable} from 'angular2/core'; 2 | import {Http} from 'angular2/http'; 3 | import 'rxjs/add/operator/map'; 4 | 5 | /* 6 | Generated class for the PeopleService provider. 7 | 8 | See https://angular.io/docs/ts/latest/guide/dependency-injection.html 9 | for more info on providers and Angular 2 DI. 10 | */ 11 | @Injectable() 12 | export class PeopleService { 13 | 14 | perpage:number = 50; 15 | 16 | constructor(public http: Http) {} 17 | 18 | load(start:number=0) { 19 | 20 | return new Promise(resolve => { 21 | 22 | this.http.get('http://192.168.4.13:3000/api/people?filter[limit]='+this.perpage+'&filter[skip]='+start) 23 | .map(res => res.json()) 24 | .subscribe(data => { 25 | 26 | resolve(data); 27 | 28 | }); 29 | }); 30 | } 31 | } 32 | 33 | -------------------------------------------------------------------------------- /superlongscroll/client/app1/app/theme/app.core.scss: -------------------------------------------------------------------------------- 1 | // http://ionicframework.com/docs/v2/theming/ 2 | 3 | 4 | // App Shared Imports 5 | // -------------------------------------------------- 6 | // These are the imports which make up the design of this app. 7 | // By default each design mode includes these shared imports. 8 | // App Shared Sass variables belong in app.variables.scss. 9 | 10 | @import '../pages/home/home'; 11 | -------------------------------------------------------------------------------- /superlongscroll/client/app1/app/theme/app.ios.scss: -------------------------------------------------------------------------------- 1 | // http://ionicframework.com/docs/v2/theming/ 2 | 3 | 4 | // App Shared Variables 5 | // -------------------------------------------------- 6 | // Shared Sass variables go in the app.variables.scss file 7 | @import 'app.variables'; 8 | 9 | 10 | // App iOS Variables 11 | // -------------------------------------------------- 12 | // iOS only Sass variables can go here 13 | 14 | 15 | // Ionic iOS Sass 16 | // -------------------------------------------------- 17 | // Custom App variables must be declared before importing Ionic. 18 | // Ionic will use its default values when a custom variable isn't provided. 19 | @import 'ionic.ios'; 20 | 21 | 22 | // App Shared Sass 23 | // -------------------------------------------------- 24 | // All Sass files that make up this app goes into the app.core.scss file. 25 | // For simpler CSS overrides, custom app CSS must come after Ionic's CSS. 26 | @import 'app.core'; 27 | 28 | 29 | // App iOS Only Sass 30 | // -------------------------------------------------- 31 | // CSS that should only apply to the iOS app 32 | -------------------------------------------------------------------------------- /superlongscroll/client/app1/app/theme/app.md.scss: -------------------------------------------------------------------------------- 1 | // http://ionicframework.com/docs/v2/theming/ 2 | 3 | 4 | // App Shared Variables 5 | // -------------------------------------------------- 6 | // Shared Sass variables go in the app.variables.scss file 7 | @import 'app.variables'; 8 | 9 | 10 | // App Material Design Variables 11 | // -------------------------------------------------- 12 | // Material Design only Sass variables can go here 13 | 14 | 15 | // Ionic Material Design Sass 16 | // -------------------------------------------------- 17 | // Custom App variables must be declared before importing Ionic. 18 | // Ionic will use its default values when a custom variable isn't provided. 19 | @import 'ionic.md'; 20 | 21 | 22 | // App Shared Sass 23 | // -------------------------------------------------- 24 | // All Sass files that make up this app goes into the app.core.scss file. 25 | // For simpler CSS overrides, custom app CSS must come after Ionic's CSS. 26 | @import 'app.core'; 27 | 28 | 29 | // App Material Design Only Sass 30 | // -------------------------------------------------- 31 | // CSS that should only apply to the Material Design app 32 | -------------------------------------------------------------------------------- /superlongscroll/client/app1/app/theme/app.variables.scss: -------------------------------------------------------------------------------- 1 | // http://ionicframework.com/docs/v2/theming/ 2 | 3 | // Ionic Shared Functions 4 | // -------------------------------------------------- 5 | // Makes Ionic Sass functions available to your App 6 | 7 | @import 'globals.core'; 8 | 9 | // App Shared Variables 10 | // -------------------------------------------------- 11 | // To customize the look and feel of this app, you can override 12 | // the Sass variables found in Ionic's source scss files. Setting 13 | // variables before Ionic's Sass will use these variables rather than 14 | // Ionic's default Sass variable values. App Shared Sass imports belong 15 | // in the app.core.scss file and not this file. Sass variables specific 16 | // to the mode belong in either the app.ios.scss or app.md.scss files. 17 | 18 | 19 | // App Shared Color Variables 20 | // -------------------------------------------------- 21 | // It's highly recommended to change the default colors 22 | // to match your app's branding. Ionic uses a Sass map of 23 | // colors so you can add, rename and remove colors as needed. 24 | // The "primary" color is the only required color in the map. 25 | // Both iOS and MD colors can be further customized if colors 26 | // are different per mode. 27 | 28 | $colors: ( 29 | primary: #387ef5, 30 | secondary: #32db64, 31 | danger: #f53d3d, 32 | light: #f4f4f4, 33 | dark: #222, 34 | favorite: #69BB7B 35 | ); 36 | -------------------------------------------------------------------------------- /superlongscroll/client/app1/app/theme/app.wp.scss: -------------------------------------------------------------------------------- 1 | // http://ionicframework.com/docs/v2/theming/ 2 | 3 | 4 | // App Shared Variables 5 | // -------------------------------------------------- 6 | // Shared Sass variables go in the app.variables.scss file 7 | @import 'app.variables'; 8 | 9 | 10 | // App Windows Variables 11 | // -------------------------------------------------- 12 | // Windows only Sass variables can go here 13 | 14 | 15 | // Ionic Windows Sass 16 | // -------------------------------------------------- 17 | // Custom App variables must be declared before importing Ionic. 18 | // Ionic will use its default values when a custom variable isn't provided. 19 | @import "ionic.wp"; 20 | 21 | 22 | // App Shared Sass 23 | // -------------------------------------------------- 24 | // All Sass files that make up this app goes into the app.core.scss file. 25 | // For simpler CSS overrides, custom app CSS must come after Ionic's CSS. 26 | @import 'app.core'; 27 | 28 | 29 | // App Windows Only Sass 30 | // -------------------------------------------------- 31 | // CSS that should only apply to the Windows app 32 | -------------------------------------------------------------------------------- /superlongscroll/client/app1/gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'), 2 | gulpWatch = require('gulp-watch'), 3 | del = require('del'), 4 | runSequence = require('run-sequence'), 5 | argv = process.argv; 6 | 7 | 8 | /** 9 | * Ionic hooks 10 | * Add ':before' or ':after' to any Ionic project command name to run the specified 11 | * tasks before or after the command. 12 | */ 13 | gulp.task('serve:before', ['watch']); 14 | gulp.task('emulate:before', ['build']); 15 | gulp.task('deploy:before', ['build']); 16 | gulp.task('build:before', ['build']); 17 | 18 | // we want to 'watch' when livereloading 19 | var shouldWatch = argv.indexOf('-l') > -1 || argv.indexOf('--livereload') > -1; 20 | gulp.task('run:before', [shouldWatch ? 'watch' : 'build']); 21 | 22 | /** 23 | * Ionic Gulp tasks, for more information on each see 24 | * https://github.com/driftyco/ionic-gulp-tasks 25 | * 26 | * Using these will allow you to stay up to date if the default Ionic 2 build 27 | * changes, but you are of course welcome (and encouraged) to customize your 28 | * build however you see fit. 29 | */ 30 | var buildBrowserify = require('ionic-gulp-browserify-typescript'); 31 | var buildSass = require('ionic-gulp-sass-build'); 32 | var copyHTML = require('ionic-gulp-html-copy'); 33 | var copyFonts = require('ionic-gulp-fonts-copy'); 34 | var copyScripts = require('ionic-gulp-scripts-copy'); 35 | 36 | var isRelease = argv.indexOf('--release') > -1; 37 | 38 | gulp.task('watch', ['clean'], function(done){ 39 | runSequence( 40 | ['sass', 'html', 'fonts', 'scripts'], 41 | function(){ 42 | gulpWatch('app/**/*.scss', function(){ gulp.start('sass'); }); 43 | gulpWatch('app/**/*.html', function(){ gulp.start('html'); }); 44 | buildBrowserify({ watch: true }).on('end', done); 45 | } 46 | ); 47 | }); 48 | 49 | gulp.task('build', ['clean'], function(done){ 50 | runSequence( 51 | ['sass', 'html', 'fonts', 'scripts'], 52 | function(){ 53 | buildBrowserify({ 54 | browserifyOptions: { 55 | debug: !isRelease 56 | } 57 | }).on('end', done); 58 | } 59 | ); 60 | }); 61 | 62 | gulp.task('sass', buildSass); 63 | gulp.task('html', copyHTML); 64 | gulp.task('fonts', copyFonts); 65 | gulp.task('scripts', copyScripts); 66 | gulp.task('clean', function(){ 67 | return del('www/build'); 68 | }); 69 | -------------------------------------------------------------------------------- /superlongscroll/client/app1/hooks/after_prepare/010_add_platform_class.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | // Add Platform Class 4 | // v1.0 5 | // Automatically adds the platform class to the body tag 6 | // after the `prepare` command. By placing the platform CSS classes 7 | // directly in the HTML built for the platform, it speeds up 8 | // rendering the correct layout/style for the specific platform 9 | // instead of waiting for the JS to figure out the correct classes. 10 | 11 | var fs = require('fs'); 12 | var path = require('path'); 13 | 14 | var rootdir = process.argv[2]; 15 | 16 | function addPlatformBodyTag(indexPath, platform) { 17 | // add the platform class to the body tag 18 | try { 19 | var platformClass = 'platform-' + platform; 20 | var cordovaClass = 'platform-cordova platform-webview'; 21 | 22 | var html = fs.readFileSync(indexPath, 'utf8'); 23 | 24 | var bodyTag = findBodyTag(html); 25 | if(!bodyTag) return; // no opening body tag, something's wrong 26 | 27 | if(bodyTag.indexOf(platformClass) > -1) return; // already added 28 | 29 | var newBodyTag = bodyTag; 30 | 31 | var classAttr = findClassAttr(bodyTag); 32 | if(classAttr) { 33 | // body tag has existing class attribute, add the classname 34 | var endingQuote = classAttr.substring(classAttr.length-1); 35 | var newClassAttr = classAttr.substring(0, classAttr.length-1); 36 | newClassAttr += ' ' + platformClass + ' ' + cordovaClass + endingQuote; 37 | newBodyTag = bodyTag.replace(classAttr, newClassAttr); 38 | 39 | } else { 40 | // add class attribute to the body tag 41 | newBodyTag = bodyTag.replace('>', ' class="' + platformClass + ' ' + cordovaClass + '">'); 42 | } 43 | 44 | html = html.replace(bodyTag, newBodyTag); 45 | 46 | fs.writeFileSync(indexPath, html, 'utf8'); 47 | 48 | process.stdout.write('add to body class: ' + platformClass + '\n'); 49 | } catch(e) { 50 | process.stdout.write(e); 51 | } 52 | } 53 | 54 | function findBodyTag(html) { 55 | // get the body tag 56 | try{ 57 | return html.match(/])(.*?)>/gi)[0]; 58 | }catch(e){} 59 | } 60 | 61 | function findClassAttr(bodyTag) { 62 | // get the body tag's class attribute 63 | try{ 64 | return bodyTag.match(/ class=["|'](.*?)["|']/gi)[0]; 65 | }catch(e){} 66 | } 67 | 68 | if (rootdir) { 69 | 70 | // go through each of the platform directories that have been prepared 71 | var platforms = (process.env.CORDOVA_PLATFORMS ? process.env.CORDOVA_PLATFORMS.split(',') : []); 72 | 73 | for(var x=0; x 2 | -------------------------------------------------------------------------------- /superlongscroll/client/app1/typings/main.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /superlongscroll/client/app1/www/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Ionic 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /superlongscroll/client/simple/app.js: -------------------------------------------------------------------------------- 1 | var $backBtn, $fwdBtn; 2 | var $results; 3 | 4 | var currentPos = 0; 5 | var total; 6 | 7 | var perPage = 10; 8 | 9 | $(document).ready(function() { 10 | $backBtn = $("#goBackBtn"); 11 | $fwdBtn = $("#goForwardBtn"); 12 | $results = $("#results"); 13 | 14 | //step one - how much crap do we have? 15 | $.get('http://localhost:3000/api/people/count', function(res) { 16 | total = res.count; 17 | console.log('count is '+total); 18 | },'json'); 19 | 20 | fetchData(); 21 | 22 | $backBtn.on('click', moveBack); 23 | $fwdBtn.on('click', moveForward); 24 | 25 | }); 26 | 27 | function fetchData() { 28 | 29 | //first, disable both 30 | $backBtn.attr('disabled','disabled'); 31 | $fwdBtn.attr('disabled','disabled'); 32 | 33 | //hide results currently there 34 | $results.html(''); 35 | 36 | //now fetch 37 | $.get('http://localhost:3000/api/people?filter[limit]='+perPage+'&filter[skip]='+currentPos, function(res) { 38 | renderData(res); 39 | 40 | if(currentPos > 0) $backBtn.removeAttr('disabled'); 41 | if(currentPos + perPage < total) $fwdBtn.removeAttr('disabled'); 42 | },'json'); 43 | 44 | } 45 | 46 | //could(should) use a nice template lang 47 | function renderData(p) { 48 | s = ''; 49 | p.forEach(function(person) { 50 | s += '
'+person.name+'
'; 51 | }); 52 | $results.html(s); 53 | } 54 | 55 | function moveBack() { 56 | currentPos -= perPage; 57 | fetchData(); 58 | } 59 | 60 | function moveForward() { 61 | currentPos += perPage; 62 | fetchData(); 63 | } 64 | 65 | -------------------------------------------------------------------------------- /superlongscroll/client/simple/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | - 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /superlongscroll/common/models/note.js: -------------------------------------------------------------------------------- 1 | module.exports = function(Note) { 2 | Note.greet = function(msg, cb) { 3 | process.nextTick(function() { 4 | msg = msg || 'world'; 5 | cb(null, 'Hello ' + msg); 6 | }); 7 | }; 8 | }; 9 | -------------------------------------------------------------------------------- /superlongscroll/common/models/note.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "note", 3 | "properties": { 4 | "title": { 5 | "type": "string", 6 | "required": true 7 | }, 8 | "content": { 9 | "type": "string" 10 | } 11 | }, 12 | "validations": [], 13 | "relations": {}, 14 | "acls": [], 15 | "methods": { 16 | "greet": { 17 | "isStatic": true, 18 | "accepts": [ 19 | { 20 | "arg": "msg", 21 | "type": "string", 22 | "http": { 23 | "source": "query" 24 | } 25 | } 26 | ], 27 | "returns": { 28 | "arg": "greeting", 29 | "type": "string" 30 | }, 31 | "http": { 32 | "verb": "get" 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /superlongscroll/common/models/person.js: -------------------------------------------------------------------------------- 1 | module.exports = function(Person) { 2 | 3 | Person.beforeRemote('find', function(ctx, instance, next) { 4 | if(!ctx.args.filter || !ctx.args.filter.limit) { 5 | console.log('forcing limit!'); 6 | if(!ctx.args.filter) ctx.args.filter = {}; 7 | ctx.args.filter.limit = 10; 8 | } 9 | next(); 10 | }); 11 | }; 12 | -------------------------------------------------------------------------------- /superlongscroll/common/models/person.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "person", 3 | "plural": "people", 4 | "base": "PersistedModel", 5 | "idInjection": true, 6 | "options": { 7 | "validateUpsert": true 8 | }, 9 | "properties": { 10 | "name": { 11 | "type": "string", 12 | "required": true 13 | }, 14 | "picture": { 15 | "type": "string", 16 | "required": true 17 | } 18 | }, 19 | "validations": [], 20 | "relations": {}, 21 | "acls": [], 22 | "methods": {} 23 | } 24 | -------------------------------------------------------------------------------- /superlongscroll/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "superlongscroll", 3 | "version": "1.0.0", 4 | "main": "server/server.js", 5 | "scripts": { 6 | "start": "node .", 7 | "pretest": "jshint .", 8 | "posttest": "nsp check" 9 | }, 10 | "dependencies": { 11 | "compression": "^1.0.3", 12 | "cors": "^2.5.2", 13 | "helmet": "^0.14.0", 14 | "loopback": "^2.22.0", 15 | "loopback-boot": "^2.6.5", 16 | "loopback-component-explorer": "^2.4.0", 17 | "loopback-datasource-juggler": "^2.39.0", 18 | "serve-favicon": "^2.0.1" 19 | }, 20 | "devDependencies": { 21 | "jshint": "^2.5.6", 22 | "nsp": "^2.1.0" 23 | }, 24 | "repository": { 25 | "type": "", 26 | "url": "" 27 | }, 28 | "description": "superlongscroll" 29 | } 30 | -------------------------------------------------------------------------------- /superlongscroll/server/boot/root.js: -------------------------------------------------------------------------------- 1 | module.exports = function(server) { 2 | // Install a `/` route that returns server status 3 | var router = server.loopback.Router(); 4 | router.get('/', server.loopback.status()); 5 | 6 | //crappy temp way to copy in a bunch of data 7 | var ucaseFirst = function(s) { 8 | return s.substring(0,1).toUpperCase() + s.substring(1); 9 | }; 10 | 11 | /* 12 | router.get('/temp', function(req, res) { 13 | 14 | console.dir(server.models.person); 15 | 16 | var usersRaw = require('../users.json').results; 17 | var users = []; 18 | console.log('going to insert '+usersRaw.length+' users'); 19 | 20 | for(var i=0;i