mirror of
https://github.com/flarum/framework.git
synced 2025-04-27 07:04:03 +08:00
Implement post editing
This commit is contained in:
parent
2d181933ea
commit
59964e3b22
48
ember/app/components/discussions/composer-edit.js
Normal file
48
ember/app/components/discussions/composer-edit.js
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
@ -35,6 +35,7 @@ var Discussion = DS.Model.extend({
|
|||||||
var posts = this.get('posts') || '';
|
var posts = this.get('posts') || '';
|
||||||
return posts.split(',');
|
return posts.split(',');
|
||||||
}.property('posts'),
|
}.property('posts'),
|
||||||
|
loadedPosts: DS.hasMany('post'),
|
||||||
|
|
||||||
readTime: DS.attr('date'),
|
readTime: DS.attr('date'),
|
||||||
readNumber: DS.attr('number'),
|
readNumber: DS.attr('number'),
|
||||||
|
@ -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.
|
// stream to a big gap that covers the amount of posts we now have.
|
||||||
this.set('ids', ids);
|
this.set('ids', ids);
|
||||||
this.clear();
|
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.
|
// Clear the contents of the post stream, resetting it to one big gap.
|
||||||
|
@ -3,22 +3,22 @@ import DS from 'ember-data';
|
|||||||
|
|
||||||
export default DS.Model.extend({
|
export default DS.Model.extend({
|
||||||
|
|
||||||
discussion: DS.belongsTo('discussion', {inverse: null}),
|
discussion: DS.belongsTo('discussion', {inverse: 'loadedPosts'}),
|
||||||
number: DS.attr('number'),
|
number: DS.attr('number'),
|
||||||
|
|
||||||
time: DS.attr('string'),
|
time: DS.attr('date'),
|
||||||
user: DS.belongsTo('user'),
|
user: DS.belongsTo('user'),
|
||||||
type: DS.attr('string'),
|
type: DS.attr('string'),
|
||||||
content: DS.attr('string'),
|
content: DS.attr('string'),
|
||||||
contentHtml: DS.attr('string'),
|
contentHtml: DS.attr('string'),
|
||||||
|
|
||||||
editTime: DS.attr('string'),
|
editTime: DS.attr('date'),
|
||||||
editUser: DS.belongsTo('user'),
|
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'),
|
deleteUser: DS.belongsTo('user'),
|
||||||
deleted: Ember.computed.notEmpty('deleteTime'),
|
isDeleted: Ember.computed.notEmpty('deleteTime'),
|
||||||
|
|
||||||
canEdit: DS.attr('boolean'),
|
canEdit: DS.attr('boolean'),
|
||||||
canDelete: DS.attr('boolean')
|
canDelete: DS.attr('boolean')
|
||||||
|
@ -44,18 +44,41 @@ export default Ember.Route.extend({
|
|||||||
start: controller.get('start')
|
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
|
// 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
|
// them. Then we will tell the view that we have finished loading so that
|
||||||
// it can scroll down to the appropriate post.
|
// it can scroll down to the appropriate post.
|
||||||
promise.then(function(discussion) {
|
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: ''});
|
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) {
|
if (controller.get('model') === discussion) {
|
||||||
controller.set('loaded', true);
|
controller.set('loaded', true);
|
||||||
Ember.run.scheduleOnce('afterRender', function() {
|
Ember.run.scheduleOnce('afterRender', function() {
|
||||||
|
@ -227,7 +227,6 @@ export default Ember.View.extend(Ember.Evented, {
|
|||||||
var deltaPixels = event.data.mouseStart - event.clientY;
|
var deltaPixels = event.data.mouseStart - event.clientY;
|
||||||
var height = event.data.heightStart + deltaPixels;
|
var height = event.data.heightStart + deltaPixels;
|
||||||
view.set('height', height);
|
view.set('height', height);
|
||||||
view.setContentHeight(height);
|
|
||||||
view.updateBodyPadding();
|
view.updateBodyPadding();
|
||||||
|
|
||||||
localStorage.setItem('composerHeight', height);
|
localStorage.setItem('composerHeight', height);
|
||||||
|
@ -32,6 +32,7 @@ class PostSerializer extends PostBasicSerializer
|
|||||||
protected function attributes(Post $post)
|
protected function attributes(Post $post)
|
||||||
{
|
{
|
||||||
$attributes = parent::attributes($post);
|
$attributes = parent::attributes($post);
|
||||||
|
$user = User::current();
|
||||||
|
|
||||||
unset($attributes['content']);
|
unset($attributes['content']);
|
||||||
if ($post->type != 'comment') {
|
if ($post->type != 'comment') {
|
||||||
@ -39,17 +40,19 @@ class PostSerializer extends PostBasicSerializer
|
|||||||
} else {
|
} else {
|
||||||
// @todo move to a formatter class
|
// @todo move to a formatter class
|
||||||
$attributes['contentHtml'] = $post->content_html ?: '<p>'.nl2br(htmlspecialchars(trim($post->content))).'</p>';
|
$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) {
|
if ($post->edit_time) {
|
||||||
$attributes['editTime'] = (string) $post->edit_time;
|
$attributes['editTime'] = $post->edit_time->toRFC3339String();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($post->delete_time) {
|
if ($post->delete_time) {
|
||||||
$attributes['deleteTime'] = (string) $post->delete_time;
|
$attributes['deleteTime'] = $post->delete_time->toRFC3339String();
|
||||||
}
|
}
|
||||||
|
|
||||||
$user = User::current();
|
|
||||||
|
|
||||||
$attributes += [
|
$attributes += [
|
||||||
'canEdit' => $post->can($user, 'edit'),
|
'canEdit' => $post->can($user, 'edit'),
|
||||||
|
@ -14,7 +14,7 @@ class CommentPost extends Post
|
|||||||
{
|
{
|
||||||
parent::boot();
|
parent::boot();
|
||||||
|
|
||||||
static::saving(function ($post) {
|
static::creating(function ($post) {
|
||||||
$post->number = ++$post->discussion->number_index;
|
$post->number = ++$post->discussion->number_index;
|
||||||
$post->discussion->save();
|
$post->discussion->save();
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user