Implement post editing

This commit is contained in:
Toby Zerner 2015-02-08 15:55:33 +10:30
parent e23192a4e0
commit b12fcf1b2d
8 changed files with 92 additions and 29 deletions

View File

@ -0,0 +1,48 @@
import Ember from 'ember';
import TaggedArray from '../../utils/tagged-array';
var precompileTemplate = Ember.Handlebars.compile;
export default Ember.Component.extend(Ember.Evented, {
layoutName: 'components/discussions/composer-body',
submitLabel: 'Save Changes',
placeholder: '',
content: Ember.computed.oneWay('post.content'),
originalContent: Ember.computed.oneWay('post.content'),
submit: null,
loading: false,
didInsertElement: function() {
var controls = TaggedArray.create();
this.trigger('populateControls', controls);
this.set('controls', controls);
},
populateControls: function(controls) {
var title = Ember.Component.create({
tagName: 'h3',
layout: precompileTemplate('Editing Post #{{component.post.number}} in <em>{{discussion.title}}</em>'),
discussion: this.get('post.discussion'),
component: this
});
controls.pushObjectWithTag(title, 'title');
},
actions: {
submit: function(content) {
this.get('submit')({
content: content
});
},
willExit: function(abort) {
// If the user has typed something, prompt them before exiting
// this composer state.
if (this.get('content') !== this.get('originalContent') && ! confirm('You have not saved your post. Do you wish to discard your changes?')) {
abort();
}
}
}
});

View File

@ -35,6 +35,7 @@ var Discussion = DS.Model.extend({
var posts = this.get('posts') || '';
return posts.split(',');
}.property('posts'),
loadedPosts: DS.hasMany('post'),
readTime: DS.attr('date'),
readNumber: DS.attr('number'),

View File

@ -42,17 +42,6 @@ export default Ember.ArrayProxy.extend(Ember.Evented, {
// stream to a big gap that covers the amount of posts we now have.
this.set('ids', ids);
this.clear();
// Look in the store and see if we already have the data for any of
// these posts. If we do, we can add them to the stream.
var posts = [];
var store = this.get('store');
ids.forEach(function(id) {
if (store.hasRecordForId('post', id)) {
posts.pushObject(store.getById('post', id));
}
});
this.addPosts(posts);
},
// Clear the contents of the post stream, resetting it to one big gap.

View File

@ -3,22 +3,22 @@ import DS from 'ember-data';
export default DS.Model.extend({
discussion: DS.belongsTo('discussion', {inverse: null}),
discussion: DS.belongsTo('discussion', {inverse: 'loadedPosts'}),
number: DS.attr('number'),
time: DS.attr('string'),
time: DS.attr('date'),
user: DS.belongsTo('user'),
type: DS.attr('string'),
content: DS.attr('string'),
contentHtml: DS.attr('string'),
editTime: DS.attr('string'),
editTime: DS.attr('date'),
editUser: DS.belongsTo('user'),
edited: Ember.computed.notEmpty('editTime'),
isEdited: Ember.computed.notEmpty('editTime'),
deleteTime: DS.attr('string'),
deleteTime: DS.attr('date'),
deleteUser: DS.belongsTo('user'),
deleted: Ember.computed.notEmpty('deleteTime'),
isDeleted: Ember.computed.notEmpty('deleteTime'),
canEdit: DS.attr('boolean'),
canDelete: DS.attr('boolean')

View File

@ -44,18 +44,41 @@ export default Ember.Route.extend({
start: controller.get('start')
});
// Each time we view a discussion we want to reload its posts from
// scratch so that we have the most up-to-date data. Also, if we were
// to leave them in the store, the stream would try and render them
// which has the potential to be slow.
this.store.unloadAll('post');
// When we know we have the post IDs, we can set up the post stream with
// them. Then we will tell the view that we have finished loading so that
// it can scroll down to the appropriate post.
promise.then(function(discussion) {
stream.setup(discussion.get('postIds'));
var postIds = discussion.get('postIds');
stream.setup(postIds);
// A page of posts will have been returned as linked data by this
// request, and automatically loaded into the store. In turn, we
// want to load them into the stream. However, since there is no
// way to access them directly, we need to retrieve them based on
// the requested start number. This code finds the post for that
// number, gets its index, slices an array of surrounding post
// IDs, and finally adds these posts to the stream.
var posts = discussion.get('loadedPosts');
var startPost = posts.findBy('number', parseInt(controller.get('start')));
if (startPost) {
var startIndex = postIds.indexOf(startPost.get('id'));
var count = stream.get('postLoadCount');
startIndex = Math.max(0, startIndex - count / 2);
var loadIds = postIds.slice(startIndex, startIndex + count);
stream.addPosts(posts.filter(function(item) {
return loadIds.indexOf(item.get('id')) !== -1;
}));
}
// Clear the list of post IDs for this discussion (without
// dirtying the record), so that next time we load the discussion,
// the discussion details and post IDs will be refreshed.
controller.store.push('discussion', {id: discussion.get('id'), posts: ''});
// It's possible for this promise to have resolved but the user
// has clicked away to a different discussion. So only if we're
// still on the original one, we will tell the view that we're
// done loading.
if (controller.get('model') === discussion) {
controller.set('loaded', true);
Ember.run.scheduleOnce('afterRender', function() {

View File

@ -227,7 +227,6 @@ export default Ember.View.extend(Ember.Evented, {
var deltaPixels = event.data.mouseStart - event.clientY;
var height = event.data.heightStart + deltaPixels;
view.set('height', height);
view.setContentHeight(height);
view.updateBodyPadding();
localStorage.setItem('composerHeight', height);

View File

@ -32,6 +32,7 @@ class PostSerializer extends PostBasicSerializer
protected function attributes(Post $post)
{
$attributes = parent::attributes($post);
$user = User::current();
unset($attributes['content']);
if ($post->type != 'comment') {
@ -39,17 +40,19 @@ class PostSerializer extends PostBasicSerializer
} else {
// @todo move to a formatter class
$attributes['contentHtml'] = $post->content_html ?: '<p>'.nl2br(htmlspecialchars(trim($post->content))).'</p>';
if ($post->can($user, 'edit')) {
$attributes['content'] = $post->content;
}
}
if ($post->edit_time) {
$attributes['editTime'] = (string) $post->edit_time;
$attributes['editTime'] = $post->edit_time->toRFC3339String();
}
if ($post->delete_time) {
$attributes['deleteTime'] = (string) $post->delete_time;
$attributes['deleteTime'] = $post->delete_time->toRFC3339String();
}
$user = User::current();
$attributes += [
'canEdit' => $post->can($user, 'edit'),

View File

@ -14,7 +14,7 @@ class CommentPost extends Post
{
parent::boot();
static::saving(function ($post) {
static::creating(function ($post) {
$post->number = ++$post->discussion->number_index;
$post->discussion->save();
});