├── vendor └── .gitkeep ├── app ├── components │ └── .gitkeep ├── helpers │ └── .gitkeep ├── models │ ├── .gitkeep │ ├── comment.js │ ├── site.js │ ├── user.js │ ├── author.js │ └── post.js ├── routes │ ├── .gitkeep │ ├── application.js │ ├── sites │ │ └── new.js │ ├── users │ │ └── new.js │ ├── authors │ │ └── new.js │ ├── comments │ │ ├── edit.js │ │ └── new.js │ ├── login.js │ ├── posts │ │ ├── edit.js │ │ └── new.js │ ├── users.js │ ├── sites.js │ ├── authors.js │ ├── comments.js │ └── posts.js ├── controllers │ └── .gitkeep ├── templates │ ├── components │ │ └── .gitkeep │ ├── login.hbs │ ├── posts │ │ ├── list.hbs │ │ └── edit.hbs │ ├── sites │ │ ├── list.hbs │ │ └── edit.hbs │ ├── users │ │ ├── list.hbs │ │ └── edit.hbs │ ├── comments │ │ ├── list.hbs │ │ └── edit.hbs │ ├── authors │ │ ├── list.hbs │ │ └── edit.hbs │ ├── index.hbs │ └── application.hbs ├── adapters │ └── application.js ├── serializers │ └── application.js ├── initializers │ └── authentication.js ├── styles │ └── app.css ├── app.js ├── index.html ├── router.js └── authenticators │ └── basic-to-jwt-authenticator.js ├── tests ├── unit │ ├── .gitkeep │ ├── routes │ │ ├── posts-test.js │ │ ├── sites-test.js │ │ ├── users-test.js │ │ ├── authors-test.js │ │ ├── comments-test.js │ │ └── application-test.js │ ├── models │ │ ├── user-test.js │ │ ├── site-test.js │ │ ├── author-test.js │ │ ├── comment-test.js │ │ └── post-test.js │ ├── adapters │ │ └── application-test.js │ └── initializers │ │ └── authentication-test.js ├── test-helper.js ├── helpers │ ├── resolver.js │ └── start-app.js ├── .jshintrc └── index.html ├── .watchmanconfig ├── public ├── robots.txt └── crossdomain.xml ├── .bowerrc ├── img └── screenshot.png ├── testem.json ├── .ember-cli ├── .gitignore ├── .travis.yml ├── bower.json ├── .jshintrc ├── .editorconfig ├── ember-cli-build.js ├── package.json ├── README.md └── config └── environment.js /vendor/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/components/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/helpers/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/models/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/routes/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/unit/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/controllers/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/templates/components/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.watchmanconfig: -------------------------------------------------------------------------------- 1 | { 2 | "ignore_dirs": ["tmp"] 3 | } 4 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # http://www.robotstxt.org 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "bower_components", 3 | "analytics": false 4 | } 5 | -------------------------------------------------------------------------------- /img/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InactiveProjects/limoncello-ember/HEAD/img/screenshot.png -------------------------------------------------------------------------------- /app/models/comment.js: -------------------------------------------------------------------------------- 1 | import DS from 'ember-data'; 2 | 3 | export default DS.Model.extend({ 4 | 5 | body: DS.attr('string'), 6 | post: DS.belongsTo('post', {async: true}) 7 | 8 | }); 9 | -------------------------------------------------------------------------------- /app/models/site.js: -------------------------------------------------------------------------------- 1 | import DS from 'ember-data'; 2 | 3 | export default DS.Model.extend({ 4 | 5 | name: DS.attr('string'), 6 | posts: DS.hasMany('post', {async: true}) 7 | 8 | }); 9 | -------------------------------------------------------------------------------- /app/models/user.js: -------------------------------------------------------------------------------- 1 | import DS from 'ember-data'; 2 | 3 | export default DS.Model.extend({ 4 | 5 | name: DS.attr('string'), 6 | email: DS.attr('string'), 7 | password: DS.attr('string') 8 | 9 | }); 10 | -------------------------------------------------------------------------------- /app/routes/application.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import ApplicationRouteMixin from 'simple-auth/mixins/application-route-mixin'; 3 | 4 | export default Ember.Route.extend(ApplicationRouteMixin, { 5 | }); 6 | -------------------------------------------------------------------------------- /app/routes/sites/new.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | 3 | export default Ember.Route.extend({ 4 | 5 | templateName: 'sites.edit', 6 | 7 | model() { 8 | return this.store.createRecord('site'); 9 | } 10 | 11 | }); 12 | -------------------------------------------------------------------------------- /app/routes/users/new.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | 3 | export default Ember.Route.extend({ 4 | 5 | templateName: 'users.edit', 6 | 7 | model() { 8 | return this.store.createRecord('user'); 9 | } 10 | 11 | }); 12 | -------------------------------------------------------------------------------- /app/routes/authors/new.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | 3 | export default Ember.Route.extend({ 4 | 5 | templateName: 'authors.edit', 6 | 7 | model() { 8 | return this.store.createRecord('author'); 9 | } 10 | 11 | }); 12 | -------------------------------------------------------------------------------- /tests/test-helper.js: -------------------------------------------------------------------------------- 1 | import resolver from './helpers/resolver'; 2 | import registerSelectHelper from './helpers/register-select-helper'; 3 | registerSelectHelper(); 4 | import { 5 | setResolver 6 | } from 'ember-qunit'; 7 | 8 | setResolver(resolver); 9 | -------------------------------------------------------------------------------- /app/models/author.js: -------------------------------------------------------------------------------- 1 | import DS from 'ember-data'; 2 | 3 | export default DS.Model.extend({ 4 | 5 | first: DS.attr('string'), 6 | last: DS.attr('string'), 7 | twitter: DS.attr('string'), 8 | posts: DS.hasMany('post', {async: true}) 9 | 10 | }); 11 | -------------------------------------------------------------------------------- /testem.json: -------------------------------------------------------------------------------- 1 | { 2 | "framework": "qunit", 3 | "test_page": "tests/index.html?hidepassed", 4 | "disable_watching": true, 5 | "launch_in_ci": [ 6 | "PhantomJS" 7 | ], 8 | "launch_in_dev": [ 9 | "PhantomJS", 10 | "Chrome" 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /app/adapters/application.js: -------------------------------------------------------------------------------- 1 | import DS from 'ember-data'; 2 | import environment from 'limoncello-ember/config/environment'; 3 | 4 | export default DS.JSONAPIAdapter.extend({ 5 | 6 | host: environment.API.host, 7 | namespace: environment.API.namespace, 8 | shouldReloadAll: () => true 9 | 10 | }); 11 | -------------------------------------------------------------------------------- /.ember-cli: -------------------------------------------------------------------------------- 1 | { 2 | /** 3 | Ember CLI sends analytics information by default. The data is completely 4 | anonymous, but there are times when you might want to disable this behavior. 5 | 6 | Setting `disableAnalytics` to true will prevent any data from being sent. 7 | */ 8 | "disableAnalytics": false 9 | } 10 | -------------------------------------------------------------------------------- /tests/helpers/resolver.js: -------------------------------------------------------------------------------- 1 | import Resolver from 'ember/resolver'; 2 | import config from '../../config/environment'; 3 | 4 | var resolver = Resolver.create(); 5 | 6 | resolver.namespace = { 7 | modulePrefix: config.modulePrefix, 8 | podModulePrefix: config.podModulePrefix 9 | }; 10 | 11 | export default resolver; 12 | -------------------------------------------------------------------------------- /app/models/post.js: -------------------------------------------------------------------------------- 1 | import DS from 'ember-data'; 2 | 3 | export default DS.Model.extend({ 4 | 5 | title: DS.attr('string'), 6 | body: DS.attr('string'), 7 | author: DS.belongsTo('author', {async: true}), 8 | site: DS.belongsTo('site', {async: true}), 9 | comment: DS.hasMany('comment', {async: true}) 10 | 11 | }); 12 | -------------------------------------------------------------------------------- /app/serializers/application.js: -------------------------------------------------------------------------------- 1 | import DS from 'ember-data'; 2 | 3 | export default DS.JSONAPISerializer.extend({ 4 | serializeAttribute(snapshot, json, key/*, attributes*/) { 5 | if (snapshot.changedAttributes()[key] || snapshot.record.get('isNew')) { 6 | return this._super(...arguments); 7 | } 8 | } 9 | }); 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | 7 | # dependencies 8 | /node_modules 9 | /bower_components 10 | 11 | # misc 12 | /.sass-cache 13 | /connect.lock 14 | /coverage/* 15 | /libpeerconnection.log 16 | npm-debug.log 17 | testem.log 18 | .idea/ 19 | -------------------------------------------------------------------------------- /tests/unit/routes/posts-test.js: -------------------------------------------------------------------------------- 1 | import { moduleFor, test } from 'ember-qunit'; 2 | 3 | moduleFor('route:posts', 'Unit | Route | posts', { 4 | // Specify the other units that are required for this test. 5 | // needs: ['controller:foo'] 6 | }); 7 | 8 | test('it exists', function(assert) { 9 | var route = this.subject(); 10 | assert.ok(route); 11 | }); 12 | -------------------------------------------------------------------------------- /tests/unit/routes/sites-test.js: -------------------------------------------------------------------------------- 1 | import { moduleFor, test } from 'ember-qunit'; 2 | 3 | moduleFor('route:sites', 'Unit | Route | sites', { 4 | // Specify the other units that are required for this test. 5 | // needs: ['controller:foo'] 6 | }); 7 | 8 | test('it exists', function(assert) { 9 | var route = this.subject(); 10 | assert.ok(route); 11 | }); 12 | -------------------------------------------------------------------------------- /tests/unit/routes/users-test.js: -------------------------------------------------------------------------------- 1 | import { moduleFor, test } from 'ember-qunit'; 2 | 3 | moduleFor('route:users', 'Unit | Route | users', { 4 | // Specify the other units that are required for this test. 5 | // needs: ['controller:foo'] 6 | }); 7 | 8 | test('it exists', function(assert) { 9 | var route = this.subject(); 10 | assert.ok(route); 11 | }); 12 | -------------------------------------------------------------------------------- /tests/unit/routes/authors-test.js: -------------------------------------------------------------------------------- 1 | import { moduleFor, test } from 'ember-qunit'; 2 | 3 | moduleFor('route:authors', 'Unit | Route | authors', { 4 | // Specify the other units that are required for this test. 5 | // needs: ['controller:foo'] 6 | }); 7 | 8 | test('it exists', function(assert) { 9 | var route = this.subject(); 10 | assert.ok(route); 11 | }); 12 | -------------------------------------------------------------------------------- /app/templates/login.hbs: -------------------------------------------------------------------------------- 1 |
2 | 3 | {{input id='login' placeholder='Login' value=login}} 4 | 5 | {{input id='password' placeholder='Password' type='password' value=password}} 6 | 7 |
8 | -------------------------------------------------------------------------------- /tests/unit/routes/comments-test.js: -------------------------------------------------------------------------------- 1 | import { moduleFor, test } from 'ember-qunit'; 2 | 3 | moduleFor('route:comments', 'Unit | Route | comments', { 4 | // Specify the other units that are required for this test. 5 | // needs: ['controller:foo'] 6 | }); 7 | 8 | test('it exists', function(assert) { 9 | var route = this.subject(); 10 | assert.ok(route); 11 | }); 12 | -------------------------------------------------------------------------------- /tests/unit/routes/application-test.js: -------------------------------------------------------------------------------- 1 | import { moduleFor, test } from 'ember-qunit'; 2 | 3 | moduleFor('route:application', 'Unit | Route | application', { 4 | // Specify the other units that are required for this test. 5 | // needs: ['controller:foo'] 6 | }); 7 | 8 | test('it exists', function(assert) { 9 | var route = this.subject(); 10 | assert.ok(route); 11 | }); 12 | -------------------------------------------------------------------------------- /tests/unit/models/user-test.js: -------------------------------------------------------------------------------- 1 | import { moduleForModel, test } from 'ember-qunit'; 2 | 3 | moduleForModel('user', 'Unit | Model | user', { 4 | // Specify the other units that are required for this test. 5 | needs: [] 6 | }); 7 | 8 | test('it exists', function(assert) { 9 | var model = this.subject(); 10 | // var store = this.store(); 11 | assert.ok(!!model); 12 | }); 13 | -------------------------------------------------------------------------------- /tests/unit/models/site-test.js: -------------------------------------------------------------------------------- 1 | import { moduleForModel, test } from 'ember-qunit'; 2 | 3 | moduleForModel('site', 'Unit | Model | site', { 4 | // Specify the other units that are required for this test. 5 | needs: ['model:post'] 6 | }); 7 | 8 | test('it exists', function(assert) { 9 | var model = this.subject(); 10 | // var store = this.store(); 11 | assert.ok(!!model); 12 | }); 13 | -------------------------------------------------------------------------------- /app/initializers/authentication.js: -------------------------------------------------------------------------------- 1 | import BasicToJwtAuthenticator from '../authenticators/basic-to-jwt-authenticator'; 2 | 3 | export function initialize(container, application) { 4 | application.register('authenticator:basicToJwt', BasicToJwtAuthenticator); 5 | } 6 | 7 | export default { 8 | name: 'authentication', 9 | before: 'simple-auth-oauth2', 10 | initialize: initialize 11 | }; 12 | -------------------------------------------------------------------------------- /tests/unit/models/author-test.js: -------------------------------------------------------------------------------- 1 | import { moduleForModel, test } from 'ember-qunit'; 2 | 3 | moduleForModel('author', 'Unit | Model | author', { 4 | // Specify the other units that are required for this test. 5 | needs: ['model:post'] 6 | }); 7 | 8 | test('it exists', function(assert) { 9 | var model = this.subject(); 10 | // var store = this.store(); 11 | assert.ok(!!model); 12 | }); 13 | -------------------------------------------------------------------------------- /app/templates/posts/list.hbs: -------------------------------------------------------------------------------- 1 | {{#if model}} 2 |

Posts

3 | 10 | {{else}} 11 | No posts 12 | {{/if}} 13 | {{link-to "New" "posts.new" tagName="button"}} 14 | -------------------------------------------------------------------------------- /app/templates/sites/list.hbs: -------------------------------------------------------------------------------- 1 | {{#if model}} 2 |

Sites

3 | 10 | {{else}} 11 | No sites 12 | {{/if}} 13 | {{link-to "New" "sites.new" tagName="button"}} 14 | -------------------------------------------------------------------------------- /tests/unit/models/comment-test.js: -------------------------------------------------------------------------------- 1 | import { moduleForModel, test } from 'ember-qunit'; 2 | 3 | moduleForModel('comment', 'Unit | Model | comment', { 4 | // Specify the other units that are required for this test. 5 | needs: ['model:post'] 6 | }); 7 | 8 | test('it exists', function(assert) { 9 | var model = this.subject(); 10 | // var store = this.store(); 11 | assert.ok(!!model); 12 | }); 13 | -------------------------------------------------------------------------------- /app/styles/app.css: -------------------------------------------------------------------------------- 1 | body { 2 | display: block; 3 | width: 100%; 4 | padding: 80px; 5 | } 6 | 7 | footer { 8 | padding-top: 100px; 9 | font-size: 1.1em; 10 | } 11 | 12 | .warning-message { 13 | margin: 30px; 14 | padding: 30px; 15 | border: dotted hsl(36, 100%, 31%); 16 | border-radius: 10px; 17 | font-size: 1.5em; 18 | color: hsl(36, 100%, 31%); 19 | background: hsl(47, 97%, 84%); 20 | } 21 | -------------------------------------------------------------------------------- /app/templates/users/list.hbs: -------------------------------------------------------------------------------- 1 | {{#if model}} 2 |

Users

3 | 10 | {{else}} 11 | No users 12 | {{/if}} 13 | {{link-to "New" "users.new" tagName="button"}} 14 | -------------------------------------------------------------------------------- /tests/unit/models/post-test.js: -------------------------------------------------------------------------------- 1 | import { moduleForModel, test } from 'ember-qunit'; 2 | 3 | moduleForModel('post', 'Unit | Model | post', { 4 | // Specify the other units that are required for this test. 5 | needs: ['model:author', 'model:comment', 'model:site'] 6 | }); 7 | 8 | test('it exists', function(assert) { 9 | var model = this.subject(); 10 | // var store = this.store(); 11 | assert.ok(!!model); 12 | }); 13 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | --- 2 | language: node_js 3 | node_js: 4 | - "0.12" 5 | 6 | sudo: false 7 | 8 | cache: 9 | directories: 10 | - node_modules 11 | 12 | before_install: 13 | - export PATH=/usr/local/phantomjs-2.0.0/bin:$PATH 14 | - "npm config set spin false" 15 | - "npm install -g npm@^2" 16 | 17 | install: 18 | - npm install -g bower 19 | - npm install 20 | - bower install 21 | 22 | script: 23 | - npm test 24 | -------------------------------------------------------------------------------- /app/templates/comments/list.hbs: -------------------------------------------------------------------------------- 1 | {{#if model}} 2 |

Comments

3 | 10 | {{else}} 11 | No comments 12 | {{/if}} 13 | {{link-to "New" "comments.new" tagName="button"}} 14 | -------------------------------------------------------------------------------- /tests/unit/adapters/application-test.js: -------------------------------------------------------------------------------- 1 | import { moduleFor, test } from 'ember-qunit'; 2 | 3 | moduleFor('adapter:application', 'Unit | Adapter | application', { 4 | // Specify the other units that are required for this test. 5 | // needs: ['serializer:foo'] 6 | }); 7 | 8 | // Replace this with your real tests. 9 | test('it exists', function(assert) { 10 | var adapter = this.subject(); 11 | assert.ok(adapter); 12 | }); 13 | -------------------------------------------------------------------------------- /app/templates/authors/list.hbs: -------------------------------------------------------------------------------- 1 | {{#if model}} 2 |

Authors

3 | 10 | {{else}} 11 | No authors 12 | {{/if}} 13 | {{link-to "New" "authors.new" tagName="button"}} 14 | -------------------------------------------------------------------------------- /app/templates/sites/edit.hbs: -------------------------------------------------------------------------------- 1 |
2 | Name {{input value=model.name}} 3 | {{#unless model.isNew}} 4 | 5 | {{/unless}} 6 | 7 | {{#if model.hasDirtyAttributes}} 8 | {{#unless model.isSaving}} 9 | 10 | {{/unless}} 11 | {{/if}} 12 |
13 | -------------------------------------------------------------------------------- /app/app.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import Resolver from 'ember/resolver'; 3 | import loadInitializers from 'ember/load-initializers'; 4 | import config from './config/environment'; 5 | 6 | var App; 7 | 8 | Ember.MODEL_FACTORY_INJECTIONS = true; 9 | 10 | App = Ember.Application.extend({ 11 | modulePrefix: config.modulePrefix, 12 | podModulePrefix: config.podModulePrefix, 13 | Resolver: Resolver 14 | }); 15 | 16 | loadInitializers(App, config.modulePrefix); 17 | 18 | export default App; 19 | -------------------------------------------------------------------------------- /app/templates/authors/edit.hbs: -------------------------------------------------------------------------------- 1 |
2 | First Name {{input value=model.first}} 3 | Last Name {{input value=model.last}} 4 | Twitter {{input value=model.twitter}} 5 | {{#unless model.isNew}} 6 | 7 | {{/unless}} 8 | 9 | {{#if model.hasDirtyAttributes}} 10 | {{#unless model.isSaving}} 11 | 12 | {{/unless}} 13 | {{/if}} 14 |
15 | -------------------------------------------------------------------------------- /tests/helpers/start-app.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import Application from '../../app'; 3 | import config from '../../config/environment'; 4 | 5 | export default function startApp(attrs) { 6 | var application; 7 | 8 | var attributes = Ember.merge({}, config.APP); 9 | attributes = Ember.merge(attributes, attrs); // use defaults, but you can override; 10 | 11 | Ember.run(function() { 12 | application = Application.create(attributes); 13 | application.setupForTesting(); 14 | application.injectTestHelpers(); 15 | }); 16 | 17 | return application; 18 | } 19 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "limoncello-ember", 3 | "dependencies": { 4 | "ember": "^1.13.7", 5 | "ember-cli-shims": "ember-cli/ember-cli-shims#0.0.3", 6 | "ember-cli-test-loader": "ember-cli-test-loader#0.1.3", 7 | "ember-data": "^1.13.8", 8 | "ember-load-initializers": "ember-cli/ember-load-initializers#0.1.5", 9 | "ember-qunit": "^0.4.9", 10 | "ember-qunit-notifications": "^0.0.7", 11 | "ember-resolver": "~0.1.18", 12 | "jquery": "^1.11.3", 13 | "loader.js": "ember-cli/loader.js#3.2.1", 14 | "qunit": "~1.18.0", 15 | "ember-simple-auth": "^0.8.0", 16 | "picnic": "~4.1.1" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "predef": [ 3 | "document", 4 | "window", 5 | "-Promise" 6 | ], 7 | "browser": true, 8 | "boss": true, 9 | "curly": true, 10 | "debug": false, 11 | "devel": true, 12 | "eqeqeq": true, 13 | "evil": true, 14 | "forin": false, 15 | "immed": false, 16 | "laxbreak": false, 17 | "newcap": true, 18 | "noarg": true, 19 | "noempty": false, 20 | "nonew": false, 21 | "nomen": false, 22 | "onevar": false, 23 | "plusplus": false, 24 | "undef": true, 25 | "sub": true, 26 | "strict": false, 27 | "white": false, 28 | "eqnull": true, 29 | "esnext": true, 30 | "unused": true 31 | } 32 | -------------------------------------------------------------------------------- /public/crossdomain.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 15 | 16 | -------------------------------------------------------------------------------- /app/routes/comments/edit.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | 3 | export default Ember.Route.extend({ 4 | 5 | templateName: 'comments.edit', 6 | 7 | model(params) { 8 | return Ember.RSVP.hash({ 9 | comment: this.store.peekRecord('comment', params.comment_id), 10 | posts: this.store.findAll('post') 11 | }).then(function (hash) { 12 | hash.selectedPost = hash.comment.get('post'); 13 | 14 | return Ember.RSVP.hash(hash); 15 | }); 16 | }, 17 | 18 | actions: { 19 | selectPost(post) { 20 | this.controller.set('model.selectedPost', post); 21 | this.controller.set('model.relationshipsDirty', true); 22 | } 23 | } 24 | 25 | }); 26 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | 8 | [*] 9 | end_of_line = lf 10 | charset = utf-8 11 | trim_trailing_whitespace = true 12 | insert_final_newline = true 13 | indent_style = space 14 | indent_size = 2 15 | 16 | [*.js] 17 | indent_style = space 18 | indent_size = 2 19 | 20 | [*.hbs] 21 | insert_final_newline = false 22 | indent_style = space 23 | indent_size = 2 24 | 25 | [*.css] 26 | indent_style = space 27 | indent_size = 2 28 | 29 | [*.html] 30 | indent_style = space 31 | indent_size = 2 32 | 33 | [*.{diff,md}] 34 | trim_trailing_whitespace = false 35 | -------------------------------------------------------------------------------- /app/templates/comments/edit.hbs: -------------------------------------------------------------------------------- 1 |
2 | Body {{input value=model.comment.body}} 3 | Post {{#x-select value=model.selectedPost action="selectPost"}} 4 | {{#each model.posts as |post|}} 5 | {{#x-option value=post}}{{post.title}}{{/x-option}} 6 | {{/each}} 7 | {{/x-select}} 8 | 9 | {{#unless model.comment.isNew}} 10 | 11 | {{/unless}} 12 | 13 | {{#if (or model.comment.hasDirtyAttributes model.relationshipsDirty)}} 14 | {{#unless model.comment.isSaving}} 15 | 16 | {{/unless}} 17 | {{/if}} 18 |
19 | -------------------------------------------------------------------------------- /app/templates/users/edit.hbs: -------------------------------------------------------------------------------- 1 |
2 | Name {{input value=model.name}} 3 | Email {{input value=model.email}} 4 | Password {{input value=model.password type="password"}} 5 | {{#unless model.isNew}} 6 | 7 | {{/unless}} 8 | 9 | {{#if model.hasDirtyAttributes}} 10 | {{#unless model.isSaving}} 11 | 12 | {{/unless}} 13 | {{/if}} 14 | {{#if (eq model.id '1')}} 15 |
Deletion and changing of default user is prohibited. The server will return an error.
16 | {{/if}} 17 |
18 | -------------------------------------------------------------------------------- /tests/unit/initializers/authentication-test.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import { initialize } from '../../../initializers/authentication'; 3 | import { module, test } from 'qunit'; 4 | 5 | var registry, application; 6 | 7 | module('Unit | Initializer | authentication', { 8 | beforeEach: function() { 9 | Ember.run(function() { 10 | application = Ember.Application.create(); 11 | registry = application.registry; 12 | application.deferReadiness(); 13 | }); 14 | } 15 | }); 16 | 17 | // Replace this with your real tests. 18 | test('it works', function(assert) { 19 | initialize(registry, application); 20 | 21 | // you would normally confirm the results of the initializer here 22 | assert.ok(true); 23 | }); 24 | -------------------------------------------------------------------------------- /app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | LimoncelloEmber 7 | 8 | 9 | 10 | {{content-for 'head'}} 11 | 12 | 13 | 14 | 15 | {{content-for 'head-footer'}} 16 | 17 | 18 | {{content-for 'body'}} 19 | 20 | 21 | 22 | 23 | {{content-for 'body-footer'}} 24 | 25 | 26 | -------------------------------------------------------------------------------- /app/routes/comments/new.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | 3 | export default Ember.Route.extend({ 4 | 5 | templateName: 'comments.edit', 6 | 7 | model() { 8 | return Ember.RSVP.hash({ 9 | comment: this.store.createRecord('comment'), 10 | posts: this.store.findAll('post') 11 | }).then(function (hash) { 12 | const firstPost = hash.posts.objectAt(0); 13 | if (firstPost !== undefined) { 14 | hash.comment.set('post', firstPost); 15 | } 16 | 17 | hash.selectedPost = firstPost; 18 | 19 | return Ember.RSVP.hash(hash); 20 | }); 21 | }, 22 | 23 | actions: { 24 | selectPost(post) { 25 | this.controller.set('model.selectedPost', post); 26 | this.controller.set('model.relationshipsDirty', true); 27 | } 28 | } 29 | 30 | }); 31 | -------------------------------------------------------------------------------- /app/routes/login.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | 3 | const successHandler = (jwt) => { 4 | Ember.Logger.debug('Logged in successfully. Jwt:', jwt); 5 | }; 6 | 7 | const errorHandler = (reason) => { 8 | Ember.Logger.error('Error:', reason.errors); 9 | }; 10 | 11 | export default Ember.Route.extend({ 12 | 13 | actions: { 14 | 15 | login() { 16 | const controller = this.controller; 17 | let login = controller.get('login'); 18 | let password = controller.get('password'); 19 | 20 | login = login ? login : ''; 21 | password = password ? password : ''; 22 | 23 | this 24 | .get('session') 25 | .authenticate('authenticator:basicToJwt', {login, password}) 26 | .then(successHandler, errorHandler); 27 | } 28 | 29 | } 30 | 31 | }); 32 | -------------------------------------------------------------------------------- /app/templates/index.hbs: -------------------------------------------------------------------------------- 1 |
2 | {{#unless session.isAuthenticated}} 3 |

4 | This is a client application for JSON-API quick start server applications Limoncello Collins and Limoncello Shot. 5 |

6 |

7 | By default it connects to server API at localhost:8888 8 |

9 |

10 |

Default login: user@example.com
11 |
Default password: password
12 |

13 | {{else}} 14 |

15 | You are logged in and can add/edit/remove Sites, Authors, Posts, Comments and Users. 16 |

17 | {{/unless}} 18 |
19 | -------------------------------------------------------------------------------- /app/templates/application.hbs: -------------------------------------------------------------------------------- 1 | 16 |
17 | {{outlet}} 18 |
19 | {{#if session.isAuthenticated}} 20 | 23 | {{/if}} 24 | -------------------------------------------------------------------------------- /app/routes/posts/edit.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | 3 | export default Ember.Route.extend({ 4 | 5 | templateName: 'posts.edit', 6 | 7 | model(params) { 8 | return Ember.RSVP.hash({ 9 | post: this.store.peekRecord('post', params.post_id), 10 | sites: this.store.findAll('site'), 11 | authors: this.store.findAll('author') 12 | }).then(function (hash) { 13 | hash.selectedSite = hash.post.get('site'); 14 | hash.selectedAuthor = hash.post.get('author'); 15 | 16 | return Ember.RSVP.hash(hash); 17 | }); 18 | }, 19 | 20 | actions: { 21 | selectSite(site) { 22 | this.controller.set('model.selectedSite', site); 23 | this.controller.set('model.relationshipsDirty', true); 24 | }, 25 | selectAuthor(author) { 26 | this.controller.set('model.selectedAuthor', author); 27 | this.controller.set('model.relationshipsDirty', true); 28 | } 29 | } 30 | 31 | }); 32 | -------------------------------------------------------------------------------- /app/routes/users.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import AuthenticatedRouteMixin from 'simple-auth/mixins/authenticated-route-mixin'; 3 | 4 | const ROUTE_USERS_LIST = 'users.list'; 5 | 6 | const errorHandler = (reason) => { 7 | Ember.Logger.error('Error:', reason.errors); 8 | }; 9 | 10 | export default Ember.Route.extend(AuthenticatedRouteMixin, { 11 | 12 | model() { 13 | return this.store.findAll('user'); 14 | }, 15 | 16 | actions: { 17 | 18 | save(model) { 19 | model.save().then(() => { 20 | this.transitionTo(ROUTE_USERS_LIST); 21 | }, errorHandler); 22 | }, 23 | 24 | cancel(model) { 25 | model.rollbackAttributes(); 26 | this.transitionTo(ROUTE_USERS_LIST); 27 | }, 28 | 29 | delete(model) { 30 | model.deleteRecord(); 31 | model.save().then(() => { 32 | this.transitionTo(ROUTE_USERS_LIST); 33 | }, errorHandler); 34 | } 35 | 36 | } 37 | 38 | }); 39 | -------------------------------------------------------------------------------- /app/routes/sites.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import AuthenticatedRouteMixin from 'simple-auth/mixins/authenticated-route-mixin'; 3 | 4 | const ROUTE_SITES_LIST = 'sites.list'; 5 | 6 | const errorHandler = (reason) => { 7 | Ember.Logger.error('Error:', reason.errors); 8 | }; 9 | 10 | export default Ember.Route.extend(AuthenticatedRouteMixin, { 11 | 12 | model() { 13 | return this.store.findAll('site'); 14 | }, 15 | 16 | actions: { 17 | 18 | save(model) { 19 | model.save().then(() => { 20 | this.transitionTo(ROUTE_SITES_LIST); 21 | }, errorHandler); 22 | }, 23 | 24 | cancel(model) { 25 | model.rollbackAttributes(); 26 | this.transitionTo(ROUTE_SITES_LIST); 27 | }, 28 | 29 | delete(model) { 30 | model.deleteRecord(); 31 | model.save() 32 | .then(() => { 33 | this.transitionTo(ROUTE_SITES_LIST); 34 | }, errorHandler); 35 | } 36 | 37 | } 38 | 39 | }); 40 | -------------------------------------------------------------------------------- /app/routes/authors.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import AuthenticatedRouteMixin from 'simple-auth/mixins/authenticated-route-mixin'; 3 | 4 | const ROUTE_AUTHORS_LIST = 'authors.list'; 5 | 6 | export default Ember.Route.extend(AuthenticatedRouteMixin, { 7 | 8 | model() { 9 | return this.store.findAll('author'); 10 | }, 11 | 12 | actions: { 13 | 14 | save(model) { 15 | model.save().then(() => { 16 | this.transitionTo(ROUTE_AUTHORS_LIST); 17 | }, 18 | (reason) => { 19 | console.error(reason); 20 | }); 21 | }, 22 | 23 | cancel(model) { 24 | model.rollbackAttributes(); 25 | this.transitionTo(ROUTE_AUTHORS_LIST); 26 | }, 27 | 28 | delete(model) { 29 | model.deleteRecord(); 30 | model.save().then(() => { 31 | this.transitionTo(ROUTE_AUTHORS_LIST); 32 | }, 33 | (reason) => { 34 | console.log(reason); 35 | }); 36 | } 37 | 38 | } 39 | 40 | }); 41 | -------------------------------------------------------------------------------- /app/templates/posts/edit.hbs: -------------------------------------------------------------------------------- 1 |
2 | Title {{input value=model.post.title}} 3 | Body {{input value=model.post.body}} 4 | Site {{#x-select value=model.selectedSite action="selectSite"}} 5 | {{#each model.sites as |site|}} 6 | {{#x-option value=site}}{{site.name}}{{/x-option}} 7 | {{/each}} 8 | {{/x-select}} 9 | Author {{#x-select value=model.selectedAuthor action="selectAuthor"}} 10 | {{#each model.authors as |author|}} 11 | {{#x-option value=author}}{{author.first}} {{author.last}}{{/x-option}} 12 | {{/each}} 13 | {{/x-select}} 14 | 15 | {{#unless model.isNew}} 16 | 17 | {{/unless}} 18 | 19 | {{#if (or model.post.hasDirtyAttributes model.relationshipsDirty)}} 20 | {{#unless model.post.isSaving}} 21 | 22 | {{/unless}} 23 | {{/if}} 24 |
25 | -------------------------------------------------------------------------------- /ember-cli-build.js: -------------------------------------------------------------------------------- 1 | /* global require, module */ 2 | var EmberApp = require('ember-cli/lib/broccoli/ember-app'); 3 | 4 | module.exports = function(defaults) { 5 | var app = new EmberApp(defaults, { 6 | // Add options here 7 | }); 8 | 9 | // Use `app.import` to add additional libraries to the generated 10 | // output files. 11 | // 12 | // If you need to use different assets in different 13 | // environments, specify an object as the first parameter. That 14 | // object's keys should be the environment name and the values 15 | // should be the asset to use in that environment. 16 | // 17 | // If the library that you are including contains AMD or ES6 18 | // modules that you would like to import into your application 19 | // please specify an object with the list of modules as keys 20 | // along with the exports of each module as its value. 21 | 22 | app.import('bower_components/picnic/releases/plugins.min.css'); 23 | app.import('bower_components/picnic/releases/picnic.min.css'); 24 | 25 | return app.toTree(); 26 | }; 27 | -------------------------------------------------------------------------------- /tests/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "predef": [ 3 | "document", 4 | "window", 5 | "location", 6 | "setTimeout", 7 | "$", 8 | "-Promise", 9 | "define", 10 | "console", 11 | "visit", 12 | "exists", 13 | "fillIn", 14 | "click", 15 | "select", 16 | "keyEvent", 17 | "triggerEvent", 18 | "find", 19 | "findWithAssert", 20 | "wait", 21 | "DS", 22 | "andThen", 23 | "currentURL", 24 | "currentPath", 25 | "currentRouteName" 26 | ], 27 | "node": false, 28 | "browser": false, 29 | "boss": true, 30 | "curly": true, 31 | "debug": false, 32 | "devel": false, 33 | "eqeqeq": true, 34 | "evil": true, 35 | "forin": false, 36 | "immed": false, 37 | "laxbreak": false, 38 | "newcap": true, 39 | "noarg": true, 40 | "noempty": false, 41 | "nonew": false, 42 | "nomen": false, 43 | "onevar": false, 44 | "plusplus": false, 45 | "undef": true, 46 | "sub": true, 47 | "strict": false, 48 | "white": false, 49 | "eqnull": true, 50 | "esnext": true, 51 | "unused": true 52 | } 53 | -------------------------------------------------------------------------------- /app/routes/comments.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import AuthenticatedRouteMixin from 'simple-auth/mixins/authenticated-route-mixin'; 3 | 4 | const ROUTE_COMMENTS_LIST = 'comments.list'; 5 | 6 | const errorHandler = (reason) => { 7 | Ember.Logger.error('Error:', reason.errors); 8 | }; 9 | 10 | export default Ember.Route.extend(AuthenticatedRouteMixin, { 11 | 12 | model() { 13 | return this.store.findAll('comment'); 14 | }, 15 | 16 | actions: { 17 | save(model) { 18 | model 19 | .comment 20 | .set('post', model.selectedPost) 21 | .save() 22 | .then(() => { 23 | this.transitionTo(ROUTE_COMMENTS_LIST); 24 | }, errorHandler); 25 | }, 26 | 27 | cancel(model) { 28 | model.comment.rollbackAttributes(); 29 | this.transitionTo(ROUTE_COMMENTS_LIST); 30 | }, 31 | 32 | delete(model) { 33 | model.comment.deleteRecord(); 34 | model.comment.save().then(() => { 35 | this.transitionTo(ROUTE_COMMENTS_LIST); 36 | }, errorHandler); 37 | } 38 | 39 | } 40 | 41 | }); 42 | -------------------------------------------------------------------------------- /app/routes/posts.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import AuthenticatedRouteMixin from 'simple-auth/mixins/authenticated-route-mixin'; 3 | 4 | const ROUTE_POSTS_LIST = 'posts.list'; 5 | 6 | const errorHandler = (reason) => { 7 | Ember.Logger.error('Error:', reason.errors); 8 | }; 9 | 10 | export default Ember.Route.extend(AuthenticatedRouteMixin, { 11 | 12 | model() { 13 | return this.store.findAll('post'); 14 | }, 15 | 16 | actions: { 17 | 18 | save(model) { 19 | model 20 | .post 21 | .set('site', model.selectedSite) 22 | .set('author', model.selectedAuthor) 23 | .save() 24 | .then(() => { 25 | this.transitionTo(ROUTE_POSTS_LIST); 26 | }, errorHandler); 27 | }, 28 | 29 | cancel(model) { 30 | model.post.rollbackAttributes(); 31 | this.transitionTo(ROUTE_POSTS_LIST); 32 | }, 33 | 34 | delete(model) { 35 | model.post.deleteRecord(); 36 | model.post.save().then(() => { 37 | this.transitionTo(ROUTE_POSTS_LIST); 38 | }, errorHandler); 39 | } 40 | 41 | } 42 | 43 | }); 44 | -------------------------------------------------------------------------------- /tests/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | LimoncelloEmber Tests 7 | 8 | 9 | 10 | {{content-for 'head'}} 11 | {{content-for 'test-head'}} 12 | 13 | 14 | 15 | 16 | 17 | {{content-for 'head-footer'}} 18 | {{content-for 'test-head-footer'}} 19 | 20 | 21 | 22 | {{content-for 'body'}} 23 | {{content-for 'test-body'}} 24 | 25 | 26 | 27 | 28 | 29 | 30 | {{content-for 'body-footer'}} 31 | {{content-for 'test-body-footer'}} 32 | 33 | 34 | -------------------------------------------------------------------------------- /app/router.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import config from './config/environment'; 3 | 4 | var Router = Ember.Router.extend({ 5 | location: config.locationType 6 | }); 7 | 8 | Router.map(function() { 9 | 10 | this.route('sites', function() { 11 | this.route('list', { path: '/' }); 12 | this.route('new'); 13 | this.route('edit', { path: '/:site_id/edit' }); 14 | }); 15 | 16 | this.route('authors', function() { 17 | this.route('list', { path: '/' }); 18 | this.route('new'); 19 | this.route('edit', { path: '/:author_id/edit' }); 20 | }); 21 | 22 | this.route('comments', function() { 23 | this.route('list', { path: '/' }); 24 | this.route('new'); 25 | this.route('edit', { path: '/:comment_id/edit' }); 26 | }); 27 | 28 | this.route('posts', function() { 29 | this.route('list', { path: '/' }); 30 | this.route('new'); 31 | this.route('edit', { path: '/:post_id/edit' }); 32 | }); 33 | 34 | this.route('users', function() { 35 | this.route('list', { path: '/' }); 36 | this.route('new'); 37 | this.route('edit', { path: '/:user_id/edit' }); 38 | }); 39 | 40 | this.route('login'); 41 | 42 | }); 43 | 44 | export default Router; 45 | -------------------------------------------------------------------------------- /app/routes/posts/new.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | 3 | export default Ember.Route.extend({ 4 | 5 | templateName: 'posts.edit', 6 | 7 | model() { 8 | return Ember.RSVP.hash({ 9 | post: this.store.createRecord('post'), 10 | sites: this.store.findAll('site'), 11 | authors: this.store.findAll('author') 12 | }).then(function (hash) { 13 | const firstSite = hash.sites.objectAt(0); 14 | if (firstSite !== undefined) { 15 | hash.post.set('site', firstSite); 16 | } 17 | 18 | const firstAuthor = hash.authors.objectAt(0); 19 | if (firstAuthor !== undefined) { 20 | hash.post.set('author', firstAuthor); 21 | } 22 | 23 | hash.selectedSite = firstSite; 24 | hash.selectedAuthor = firstAuthor; 25 | 26 | return Ember.RSVP.hash(hash); 27 | }); 28 | }, 29 | 30 | actions: { 31 | selectSite(site) { 32 | this.controller.set('model.selectedSite', site); 33 | this.controller.set('model.relationshipsDirty', true); 34 | }, 35 | selectAuthor(author) { 36 | this.controller.set('model.selectedAuthor', author); 37 | this.controller.set('model.relationshipsDirty', true); 38 | } 39 | } 40 | 41 | }); 42 | -------------------------------------------------------------------------------- /app/authenticators/basic-to-jwt-authenticator.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import Base from 'simple-auth/authenticators/base'; 3 | import environment from 'limoncello-ember/config/environment'; 4 | 5 | const { API } = environment; 6 | const LOGIN_BASIC_URL = API.host + "/" + API.loginBasic; 7 | 8 | export default Base.extend({ 9 | restore(data) { 10 | return new Ember.RSVP.Promise(function(resolve, reject) { 11 | if (!Ember.isEmpty(data.access_token)) { 12 | resolve(data); 13 | } else { 14 | reject(); 15 | } 16 | }); 17 | }, 18 | 19 | authenticate(credentials) { 20 | const login = credentials.login ? credentials.login : ""; 21 | const password = credentials.password ? credentials.password : ""; 22 | const basicHeaderValue = "Basic " + btoa(login + ":" + password); 23 | 24 | return new Ember.RSVP.Promise(function(resolve, reject) { 25 | Ember.$.ajax({ 26 | url: LOGIN_BASIC_URL, 27 | headers: {Authorization: basicHeaderValue} 28 | }).then((jwt) => { 29 | Ember.run(() => { 30 | resolve({ access_token: jwt }); 31 | }); 32 | }, (xhr/*, status, error*/) => { 33 | let response = JSON.parse(xhr.responseText); 34 | Ember.run(() => { 35 | reject(response.error); 36 | }); 37 | }); 38 | }); 39 | }, 40 | 41 | invalidate(/*data*/) { 42 | return Ember.RSVP.resolve(); 43 | } 44 | }); 45 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "limoncello-ember", 3 | "version": "0.0.1", 4 | "description": "Client application for JSON-API quick start server applications Limoncello Collins and Limoncello Shot", 5 | "private": true, 6 | "directories": { 7 | "doc": "doc", 8 | "test": "tests" 9 | }, 10 | "scripts": { 11 | "build": "ember build", 12 | "start": "ember server", 13 | "test": "ember test" 14 | }, 15 | "repository": "https://github.com/neomerx/limoncello-ember", 16 | "engines": { 17 | "node": ">= 0.12.0" 18 | }, 19 | "author": "info@neomerx.com", 20 | "license": "MIT", 21 | "devDependencies": { 22 | "broccoli-asset-rev": "^2.1.2", 23 | "ember-cli": "^1.13.8", 24 | "ember-cli-app-version": "^0.5.0", 25 | "ember-cli-babel": "^5.1.3", 26 | "ember-cli-content-security-policy": "^0.4.0", 27 | "ember-cli-dependency-checker": "^1.0.1", 28 | "ember-cli-htmlbars": "^0.7.9", 29 | "ember-cli-htmlbars-inline-precompile": "^0.2.0", 30 | "ember-cli-ic-ajax": "^0.2.1", 31 | "ember-cli-inject-live-reload": "^1.3.1", 32 | "ember-cli-qunit": "^1.0.0", 33 | "ember-cli-release": "^0.2.3", 34 | "ember-cli-simple-auth": "^0.8.0", 35 | "ember-cli-simple-auth-oauth2": "^0.8.0", 36 | "ember-cli-sri": "^1.0.3", 37 | "ember-cli-uglify": "^1.2.0", 38 | "ember-data": "^1.13.8", 39 | "ember-disable-proxy-controllers": "^1.0.0", 40 | "ember-export-application-global": "^1.0.3", 41 | "ember-truth-helpers": "^1.1.0", 42 | "emberx-select": "^2.0.0" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Limoncello Ember 2 | 3 | This is a client application for [JSON API](http://jsonapi.org/) quick start server applications [Limoncello Collins](https://github.com/neomerx/limoncello-collins) and [Limoncello Shot](https://github.com/neomerx/limoncello-shot) (5.1 branches). 4 | 5 | It supports 6 | - CRUD operations for Authors, Comments, Posts, Sites and Users. 7 | - Cross-origin requests (CORS) to API server. 8 | - Server login (Basic Auth) and API authentication (JWT Bearer). 9 | 10 | ![App screen-shot](img/screenshot.png) 11 | 12 | ### Prerequisites 13 | 14 | You will need the following things properly installed on your computer. 15 | 16 | * [Git](http://git-scm.com/) 17 | * [Node.js](http://nodejs.org/) (with NPM) 18 | * [Bower](http://bower.io/) 19 | * [Ember CLI](http://www.ember-cli.com/) 20 | * [PhantomJS](http://phantomjs.org/) (for tests only) 21 | 22 | ### Installation 23 | 24 | * Install and run [Limoncello Collins](https://github.com/neomerx/limoncello-collins) or [Limoncello Shot](https://github.com/neomerx/limoncello-shot). 25 | * `git clone ` this repository 26 | * change into the new directory 27 | * `npm install` 28 | * `bower install` 29 | 30 | ### Running / Development 31 | 32 | * `ember s` 33 | * Visit your app at [http://localhost:4200](http://localhost:4200). 34 | 35 | #### Running Tests 36 | 37 | * `ember test` 38 | * `ember test --server` 39 | 40 | #### Building 41 | 42 | * `ember build` (development) 43 | * `ember build --environment production` (production) 44 | 45 | ### Credits 46 | 47 | I would like to especially thank [Christopher](https://github.com/lindyhopchris) for his invaluable help and advice. 48 | 49 | ### Licence 50 | 51 | MIT 52 | -------------------------------------------------------------------------------- /config/environment.js: -------------------------------------------------------------------------------- 1 | /* jshint node: true */ 2 | 3 | const API_HOST = 'http://localhost:8888'; 4 | const API_NAMESPACE = 'api/v1'; 5 | const API_LOGIN_BASIC = 'login/basic'; 6 | 7 | module.exports = function(environment) { 8 | var ENV = { 9 | modulePrefix: 'limoncello-ember', 10 | environment: environment, 11 | baseURL: '/', 12 | locationType: 'auto', 13 | EmberENV: { 14 | FEATURES: { 15 | // Here you can enable experimental features on an ember canary build 16 | // e.g. 'with-controller': true 17 | } 18 | }, 19 | 20 | APP: { 21 | // Here you can pass flags/options to your application instance 22 | // when it is created 23 | }, 24 | 25 | API: { 26 | host: API_HOST, 27 | namespace: API_NAMESPACE, 28 | loginBasic: API_LOGIN_BASIC 29 | } 30 | }; 31 | 32 | if (environment === 'development') { 33 | // ENV.APP.LOG_RESOLVER = true; 34 | // ENV.APP.LOG_ACTIVE_GENERATION = true; 35 | // ENV.APP.LOG_TRANSITIONS = true; 36 | // ENV.APP.LOG_TRANSITIONS_INTERNAL = true; 37 | // ENV.APP.LOG_VIEW_LOOKUPS = true; 38 | } 39 | 40 | if (environment === 'test') { 41 | // Testem prefers this... 42 | ENV.baseURL = '/'; 43 | ENV.locationType = 'none'; 44 | 45 | // keep test console output quieter 46 | ENV.APP.LOG_ACTIVE_GENERATION = false; 47 | ENV.APP.LOG_VIEW_LOOKUPS = false; 48 | 49 | ENV.APP.rootElement = '#ember-testing'; 50 | } 51 | 52 | if (environment === 'production') { 53 | 54 | } 55 | 56 | ENV.contentSecurityPolicy = { 57 | 'default-src': "'none'", 58 | 'script-src' : "'self'", 59 | 'font-src' : "'self'", 60 | 'connect-src': "'self' " + API_HOST, 61 | 'img-src' : "'self' data:", 62 | 'style-src' : "'self'", 63 | 'media-src' : "'self'" 64 | }; 65 | 66 | ENV['simple-auth'] = { 67 | authorizer: 'simple-auth-authorizer:oauth2-bearer', 68 | store: 'simple-auth-session-store:local-storage', 69 | //store: 'simple-auth-session-store:ephemeral', 70 | crossOriginWhitelist: [API_HOST] 71 | }; 72 | 73 | return ENV; 74 | }; 75 | --------------------------------------------------------------------------------