1
0
mirror of https://github.com/flarum/core.git synced 2025-08-06 00:17:31 +02:00

Implement "renamed" posts

Record when the discussion was renamed, from what, and by whom.
Information is stored in the `content` field as a serialised JSON
object because proper polymorphism will be too difficult with Ember
Data and especially when extensions try to add new post types.
This commit is contained in:
Toby Zerner
2015-02-13 10:23:38 +10:30
parent dc21666215
commit 5ebd0a0e93
19 changed files with 225 additions and 90 deletions

View File

@@ -0,0 +1,48 @@
import Ember from 'ember';
import FadeIn from 'flarum/mixins/fade-in';
import HasItemLists from 'flarum/mixins/has-item-lists';
var precompileTemplate = Ember.Handlebars.compile;
/**
Component for a `renamed`-typed post.
*/
export default Ember.Component.extend(FadeIn, HasItemLists, {
layoutName: 'components/discussion/post-renamed',
tagName: 'article',
classNames: ['post', 'post-renamed', 'post-activity'],
itemLists: ['controls'],
// The stream-content component instansiates this component and sets the
// `content` property to the content of the item in the post-stream object.
// This happens to be our post model!
post: Ember.computed.alias('content'),
decodedContent: Ember.computed('post.content', function() {
return JSON.parse(this.get('post.content'));
}),
oldTitle: Ember.computed.alias('decodedContent.0'),
newTitle: Ember.computed.alias('decodedContent.1'),
populateControls: function(items) {
this.addActionItem(items, 'delete', 'Delete', 'times', 'post.canDelete');
},
actions: {
// In the template, we render the "controls" dropdown with the contents of
// the `renderControls` property. This way, when a post is initially
// rendered, it doesn't have to go to the trouble of rendering the
// controls right away, which speeds things up. When the dropdown button
// is clicked, this will fill in the actual controls.
renderControls: function() {
this.set('renderControls', this.get('controls'));
},
delete: function() {
var post = this.get('post');
post.destroyRecord();
this.sendAction('postRemoved', post);
}
}
});

View File

@@ -107,7 +107,16 @@ export default Ember.Controller.extend(Ember.Evented, UseComposerMixin, {
rename: function(title) {
var discussion = this.get('model');
discussion.set('title', title);
discussion.save();
// When we save the title, we should get back an 'added post' in the
// response which documents the title change. We'll add this to the post
// stream.
var controller = this;
discussion.save().then(function(discussion) {
discussion.get('addedPosts').forEach(function(post) {
controller.get('stream').addPostToEnd(post);
});
});
},
delete: function() {

View File

@@ -36,6 +36,7 @@ export default DS.Model.extend({
}),
loadedPosts: DS.hasMany('post'),
relevantPosts: DS.hasMany('post'),
addedPosts: DS.hasMany('post'),
readTime: DS.attr('date'),
readNumber: DS.attr('number'),

View File

@@ -7,10 +7,19 @@ export default Ember.Route.extend({
start: {replace: true}
},
model: function(params) {
return this.store.findQueryOne('discussion', params.id, {
discussion: function(id, start) {
return this.store.findQueryOne('discussion', id, {
include: 'posts',
near: params.start
near: start
});
},
// When we fetch the discussion from the model hook (i.e. on a fresh page
// load), we'll wrap it in an object proxy and set a `loaded` flag to true
// so that it won't be reloaded later on.
model: function(params) {
return this.discussion(params.id, params.start).then(function(discussion) {
return Ember.ObjectProxy.create({content: discussion, loaded: true});
});
},
@@ -36,18 +45,18 @@ export default Ember.Route.extend({
});
controller.set('stream', stream);
// Next, we need to make sure we have a list of the discussion's post
// IDs. If we don't already have this information, we'll need to
// reload the discussion model.
var promise = discussion.get('posts') ? Ember.RSVP.resolve(discussion) : this.model({
id: discussion.get('id'),
start: controller.get('start')
});
// We need to make sure we have an up-to-date list of the discussion's
// post IDs. If we didn't enter this route using the model hook (like if
// clicking on a discussion in the index), then we'll reload the model.
var promise = discussion.get('loaded') ?
Ember.RSVP.resolve(discussion.get('content')) :
this.discussion(discussion.get('id'), controller.get('start'));
// 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) {
controller.set('model', discussion);
var postIds = discussion.get('postIds');
stream.setup(postIds);
@@ -70,11 +79,6 @@ export default Ember.Route.extend({
}));
}
// 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

View File

@@ -152,10 +152,9 @@
}
.post-icon {
float: left;
margin-top: -2px;
margin-left: -90px;
width: 64px;
text-align: center;
text-align: right;
font-size: 22px;
}
.post.is-hidden {
@@ -194,6 +193,25 @@
}
}
.post-activity {
&, & a {
color: @fl-body-muted-color;
}
& a {
font-weight: bold;
}
}
.post-activity-info {
font-size: 15px;
margin-bottom: 5px;
}
.post-renamed {
& .old-title, & .new-title {
font-weight: normal;
font-style: italic;
}
}
// ------------------------------------
// Scrubber

View File

@@ -1,11 +1,4 @@
{{#if controls}}
{{ui/dropdown-button
items=renderControls
class="contextual-controls"
buttonClass="btn btn-default btn-icon btn-sm btn-naked"
buttonClick="renderControls"
menuClass="pull-right"}}
{{/if}}
{{partial "components/discussion/post-controls"}}
<header class="post-header">
{{ui/item-list items=header}}

View File

@@ -0,0 +1,8 @@
{{#if controls}}
{{ui/dropdown-button
items=renderControls
class="contextual-controls"
buttonClass="btn btn-default btn-icon btn-sm btn-naked"
buttonClick="renderControls"
menuClass="pull-right"}}
{{/if}}

View File

@@ -0,0 +1,7 @@
{{partial "components/discussion/post-controls"}}
{{fa-icon "pencil" class="post-icon"}}
<div class="post-activity-info">{{#link-to "user" post.user class="post-user"}}{{post.user.username}}{{/link-to}} changed the title from <strong class="old-title">{{oldTitle}}</strong> to <strong class="new-title">{{newTitle}}</strong>.</div>
<div class="post-activity-time">{{human-time post.time}}</div>

View File

@@ -1,4 +0,0 @@
<div class="activity">
{{fa-icon "pencil" class="post-icon"}}
{{#link-to "user" post.user}}{{post.user.username}}{{/link-to}} changed the title from <strong class="old-title">{{post.oldTitle}}</strong> to <strong class="new-title">{{post.newTitle}}</strong>.
</div>

View File

@@ -71,8 +71,9 @@ export default Ember.View.extend(HasItemLists, {
this.addActionItem(items, 'rename', 'Rename', 'pencil', 'discussion.canEdit', function() {
var discussion = view.get('controller.model');
var title = prompt('Enter a new title for this discussion:', discussion.get('title'));
if (title) {
var currentTitle = discussion.get('title');
var title = prompt('Enter a new title for this discussion:', currentTitle);
if (title && title !== currentTitle) {
view.get('controller').send('rename', title);
}
});