Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions app/adapters/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,11 @@ import ENV from 'code-corps-ember/config/environment';
export default DS.JSONAPIAdapter.extend(DataAdapterMixin, {
authorizer: 'authorizer:oauth2',
host: ENV.API_BASE_URL,

// eliminates a deprecation warning
// default behavior will return true in ember data 2.x
// so we should consider accounting for that
shouldBackgroundReloadRecord: function() {
return false;
}
});
46 changes: 45 additions & 1 deletion app/components/comment-item.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,49 @@
import Ember from 'ember';

export default Ember.Component.extend({
classNames: ['comment-item']
classNames: ['comment-item'],
classNameBindings: ['isEditing:editing'],

session: Ember.inject.service(),

currentUserId: Ember.computed.alias('session.session.authenticated.user_id'),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We may want to refactor this later with the currentUser object I'm introducing in #76.

commentAuthorId: Ember.computed.alias('comment.user.id'),
currentUserIsCommentAuthor: Ember.computed('currentUserId', 'commentAuthorId', function() {
let userId = parseInt(this.get('currentUserId'), 10);
let authorId = parseInt(this.get('commentAuthorId'), 10);
return userId === authorId;
}),

canEdit: Ember.computed.and('session.isAuthenticated', 'currentUserIsCommentAuthor'),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Common to keep the aliases all together near the top after static attributes, then computed properties, then methods, then actions. Keeps the files clean and clear.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I'm having trouble seeing how you want this reordered. Can you order it in something like:

  • classNames
  • classNameBindings
  • canEdit
  • whateverElse

so I can understand better?


didInitAttrs() {
this.set('isEditing', false);
return this._super(...arguments);
},

actions: {
edit() {
this.set('isEditing', true);
},

cancel() {
this.set('isEditing', false);
},

save() {
let component = this;
let comment = this.get('comment');
comment.set('preview', false);
comment.save().then(() => {
component.set('isEditing', false);
});
},

generatePreview(markdown) {
let comment = this.get('comment');
comment.set('markdownPreview', markdown);
comment.set('preview', true);
comment.save();
}
}
});
11 changes: 10 additions & 1 deletion app/components/create-comment-form.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,17 @@ export default Ember.Component.extend({
tagName: 'form',

actions: {
saveComment(comment) {
saveComment() {
let comment = this.get('comment');
comment.set('preview', false);
this.sendAction('saveComment', comment);
},

generatePreview(markdown) {
let comment = this.get('comment');
comment.set('markdownPreview', markdown);
comment.set('preview', true);
comment.save();
}
}
});
29 changes: 29 additions & 0 deletions app/components/editor-with-preview.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import Ember from 'ember';

export default Ember.Component.extend({
classNames: ['editor-with-preview'],
classNameBindings: ['mode'],

mode: null,

editing: Ember.computed.equal('mode', 'editing'),
previewing: Ember.computed.equal('mode', 'previewing'),

didInitAttrs() {
this._super(...arguments);
this.mode = 'editing';
},

actions: {
preview() {
this.set('mode', 'previewing');
this.set('preview', 'Loading preview...');
let content = this.get('input');
this.sendAction('generatePreview', content);
},

edit() {
this.set('mode', 'editing');
}
}
});
46 changes: 45 additions & 1 deletion app/components/post-details.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,49 @@
import Ember from 'ember';

export default Ember.Component.extend({
classNames: ['post-details']
session: Ember.inject.service(),

classNames: ['post-details'],
classNameBindings: ['post.postType'],

didInitAttrs() {
this.set('isEditingBody', false);
this.set('isEditingTitle', false);
return this._super(...arguments);
},

actions: {
editPostBody() {
this.set('isEditingBody', true);
},

cancelEditingPostBody() {
this.set('isEditingBody', false);
},

generatePreview(markdown) {
let post = this.get('post');
post.set('markdownPreview', markdown);
post.set('preview', true);
post.save();
},

savePostBody() {
let component = this;
let post = this.get('post');
post.set('preview', false);
post.save().then(() => {
component.set('isEditingBody', false);
});
},

savePostTitle(title) {
let component = this;
let post = this.get('post');
post.set('title', title);
post.save().then(() => {
component.set('isEditingTitle', false);
});
}
}
});
8 changes: 8 additions & 0 deletions app/components/post-new-form.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,15 @@ export default Ember.Component.extend({
actions: {
submit() {
let post = this.get('post');
post.set('preview', false);
this.sendAction('savePost', post);
},

generatePreview(markdown) {
let post = this.get('post');
post.set('markdownPreview', markdown);
post.set('preview', true);
post.save();
}
}
});
31 changes: 31 additions & 0 deletions app/components/post-title.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import Ember from 'ember';

export default Ember.Component.extend({
session: Ember.inject.service(),

classNames: ['post-title'],
classNameBindings: ['isEditing:editing'],

didInitAttrs() {
this.setProperties({
isEditing: false,
});
},

actions: {
edit() {
this.set('newTitle', this.get('title'));
this.set('isEditing', true);
},

save() {
let newTitle = this.get('newTitle');
this.sendAction('saveTitle', newTitle);
this.set('isEditing', false);
},

cancel() {
this.set('isEditing', false);
}
}
});
8 changes: 6 additions & 2 deletions app/models/comment.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@ import DS from 'ember-data';

export default DS.Model.extend({
markdown: DS.attr('string'),
markdownPreview: DS.attr('string'),
body: DS.attr('string'),
bodyPreview: DS.attr('string'),

post: DS.belongsTo('post'),
user: DS.belongsTo('user')
preview: DS.attr('boolean'),

post: DS.belongsTo('post', { async: true }),
user: DS.belongsTo('user', { async: true })
});
17 changes: 12 additions & 5 deletions app/models/post.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,21 @@ import DS from 'ember-data';

export default DS.Model.extend({
title: DS.attr('string'),

body: DS.attr('string'),
bodyPreview: DS.attr('string'),

markdown: DS.attr('string'),
state: DS.attr('string'),
markdownPreview: DS.attr('string'),

preview: DS.attr('boolean'),

postType: DS.attr('string'),
likesCount: DS.attr('number'),
project: DS.belongsTo('project'),
user: DS.belongsTo('user', { async: true }),
comments: DS.hasMany('comment'),
number: DS.attr('number'),
createdAt: DS.attr('date')
createdAt: DS.attr('date'),

project: DS.belongsTo('project', { async: true }),
user: DS.belongsTo('user', { async: true }),
comments: DS.hasMany('comment', { async: true }),
});
2 changes: 1 addition & 1 deletion app/models/slugged-route.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import DS from 'ember-data';

export default DS.Model.extend({
model: DS.belongsTo('model', { polymorphic: true }),
model: DS.belongsTo('model', { async: true, polymorphic: true }),
modelType: DS.attr('string'),
slug: DS.attr('string'),
});
1 change: 0 additions & 1 deletion app/routes/project/posts/new.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ export default Ember.Route.extend(AuthenticatedRouteMixin, {

actions: {
savePost(post) {
post.set('state', 'published');
post.save().then((post) => {
this.transitionTo('project.posts.post', post.get('number'));
}).catch((error) => {
Expand Down
28 changes: 28 additions & 0 deletions app/serializers/comment.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import ApplicationSerializer from './application';

export default ApplicationSerializer.extend({
_attributeIsPreviewOnly(attribute) {
return ['preview', 'markdownPreview'].indexOf(attribute.name) > -1;
},

serializeAttribute: function(snapshot, json, key, attribute) {
// for creating records, just regularly serialize the payload
if (snapshot.record.get('isNew')) {
if (snapshot.attr('preview')) {
if (this._attributeIsPreviewOnly(attribute)) {
this._super(snapshot, json, key, attribute);
}
} else {
this._super(snapshot, json, key, attribute);
}
} else {
// for updating existing records, we have 2 cases
// we're editing or requesting a preview of the post body. In that
// case, we only need to push markdownPreview and the preview flag itself

if (this._attributeIsPreviewOnly(attribute)) {
this._super(snapshot, json, key, attribute);
}
}
}
});
39 changes: 39 additions & 0 deletions app/serializers/post.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import ApplicationSerializer from './application';

export default ApplicationSerializer.extend({
_attributeIsPreviewOnly(attribute) {
return ['preview', 'markdownPreview'].indexOf(attribute.name) > -1;
},

serializeAttribute: function(snapshot, json, key, attribute) {
// for creating records, just regularly serialize the payload
if (snapshot.record.get('isNew')) {
if (snapshot.attr('preview')) {
if (this._attributeIsPreviewOnly(attribute)) {
this._super(snapshot, json, key, attribute);
}
} else {
this._super(snapshot, json, key, attribute);
}
} else {
// for updating existing records, we have 3 cases
// 1. we're editing or requesting a preview of the post body. In that
// case, we only need to push markdownPreview and the preview flag itself
// 2. we're editing the title. In that case, we only push the title
// 3. We're outright editing the post body - we only send markdownPreview
if (snapshot.attr('preview') === true) {
if (this._attributeIsPreviewOnly(attribute)) {
this._super(snapshot, json, key, attribute);
}
} else if (snapshot.changedAttributes().title) {
if (attribute.name === 'title') {
this._super(snapshot, json, key, attribute);
}
} else {
if (attribute.name === 'markdownPreview') {
this._super(snapshot, json, key, attribute);
}
}
}
}
});
5 changes: 4 additions & 1 deletion app/styles/app.scss
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,7 @@
@import "components/project-details";
@import "components/project-menu";
@import "components/project-post-list";
@import "components/signup-form";
@import "components/signup-form";
@import "components/editor-with-preview";
@import "components/post-title";
@import "components/post-details";
40 changes: 40 additions & 0 deletions app/styles/components/editor-with-preview.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
.editor-with-preview {
margin: 10px;

ul {
@include clearfix;
margin: 0 0 10px 0;
padding: 0;
list-style-type: none;
width: 100%;
border-bottom: 1px solid $border-default;

li {
float: left;
}

a {
display: block;
padding: 10px 14px;
text-decoration: none;
color: $light-text;
font-weight: 700;
border-bottom: 5px solid transparent;

&.active {
color: $link-color;
border-bottom-color: $dark-blue;
}

&:hover {
color: $link-color;
border-bottom-color: $dark-blue;
transition: border-bottom-color ease 0.3s;
}
}
}

textarea {
width: 100%;
}
}
Loading