Refactor post components and controls

This commit is contained in:
Toby Zerner 2015-05-05 17:07:12 +09:30
parent 1f53547ee5
commit 3baa817326
7 changed files with 126 additions and 128 deletions

View File

@ -1,6 +1,7 @@
import App from 'flarum/utils/app';
import store from 'flarum/initializers/store';
import discussionControls from 'flarum/initializers/discussion-controls';
import postControls from 'flarum/initializers/post-controls';
import preload from 'flarum/initializers/preload';
import session from 'flarum/initializers/session';
import routes from 'flarum/initializers/routes';
@ -12,6 +13,7 @@ var app = new App();
app.initializers.add('store', store);
app.initializers.add('discussion-controls', discussionControls);
app.initializers.add('post-controls', postControls);
app.initializers.add('session', session);
app.initializers.add('routes', routes);
app.initializers.add('components', components);

View File

@ -4,8 +4,8 @@ export default class Notification extends Component {
view() {
var notification = this.props.notification;
return m('div.notification', {
classNames: !notification.isRead ? 'unread' : '',
return m('div.notification.notification-'+notification.contentType(), {
classNames: !notification.isRead() ? 'unread' : '',
onclick: this.read.bind(this)
}, this.content());
}

View File

@ -0,0 +1,24 @@
import Post from 'flarum/components/post';
import username from 'flarum/helpers/username';
import icon from 'flarum/helpers/icon';
import humanTime from 'flarum/utils/human-time';
export default class PostActivity extends Post {
view(content, attrs) {
attrs.className = 'post-activity '+(attrs.className || '');
var iconName = attrs.icon;
delete attrs.icon;
var post = this.props.post;
return super.view([
icon(iconName+' post-icon'),
m('div.post-activity-info', [
m('a.post-user', {href: app.route('user', { username: post.user().username() }), config: m.route}, username(post.user())), ' ',
content
]),
m('div.post-activity-time', humanTime(post.time()))
], attrs);
}
}

View File

@ -1,14 +1,10 @@
import Component from 'flarum/component';
import Post from 'flarum/components/post';
import classList from 'flarum/utils/class-list';
import ComposerEdit from 'flarum/components/composer-edit';
import PostHeaderUser from 'flarum/components/post-header-user';
import PostHeaderMeta from 'flarum/components/post-header-meta';
import PostHeaderEdited from 'flarum/components/post-header-edited';
import PostHeaderToggle from 'flarum/components/post-header-toggle';
import ItemList from 'flarum/utils/item-list';
import ActionButton from 'flarum/components/action-button';
import DropdownButton from 'flarum/components/dropdown-button';
import SubtreeRetainer from 'flarum/utils/subtree-retainer';
import listItems from 'flarum/helpers/list-items';
/**
@ -16,43 +12,30 @@ import listItems from 'flarum/helpers/list-items';
(controls, header, and footer) surrounding the post's HTML content. Allows
the post to be edited with the composer, hidden, or restored.
*/
export default class PostComment extends Component {
export default class PostComment extends Post {
constructor(props) {
super(props);
this.postHeaderUser = new PostHeaderUser({post: this.props.post});
this.subtree = new SubtreeRetainer(
() => this.props.post.freshness,
() => this.props.post.user() && this.props.post.user().freshness,
this.postHeaderUser.showCard
);
this.subtree.add(this.postHeaderUser.showCard);
}
view() {
var post = this.props.post;
var classes = {
'is-hidden': post.isHidden(),
'is-edited': post.isEdited(),
'reveal-content': this.revealContent
};
var controls = this.controlItems().toArray();
// @todo Having to wrap children in a div isn't nice
return m('article.post.post-comment', {className: classList(classes)}, this.subtree.retain() || m('div', [
controls.length ? DropdownButton.component({
items: controls,
className: 'contextual-controls',
buttonClass: 'btn btn-default btn-icon btn-sm btn-naked',
menuClass: 'pull-right'
}) : '',
return super.view([
m('header.post-header', m('ul', listItems(this.headerItems().toArray()))),
m('div.post-body', m.trust(post.contentHtml())),
m('aside.post-footer', m('ul', listItems(this.footerItems().toArray()))),
m('aside.post-actions', m('ul', listItems(this.actionItems().toArray())))
]));
], {
className: classList({
'post-comment': true,
'is-hidden': post.isHidden(),
'is-edited': post.isEdited(),
'reveal-content': this.revealContent
})
});
}
toggleContent() {
@ -78,25 +61,6 @@ export default class PostComment extends Component {
return items;
}
controlItems() {
var items = new ItemList();
var post = this.props.post;
if (post.isHidden()) {
if (post.canEdit()) {
items.add('restore', ActionButton.component({ icon: 'reply', label: 'Restore', onclick: this.restore.bind(this) }));
}
if (post.canDelete()) {
items.add('delete', ActionButton.component({ icon: 'times', label: 'Delete Forever', onclick: this.delete.bind(this) }));
}
} else if (post.canEdit()) {
items.add('edit', ActionButton.component({ icon: 'pencil', label: 'Edit', onclick: this.edit.bind(this) }));
items.add('hide', ActionButton.component({ icon: 'times', label: 'Delete', onclick: this.hide.bind(this) }));
}
return items;
}
footerItems() {
return new ItemList();
}
@ -104,30 +68,4 @@ export default class PostComment extends Component {
actionItems() {
return new ItemList();
}
edit() {
if (!this.composer || app.composer.component !== this.composer) {
this.composer = new ComposerEdit({ post: this.props.post });
app.composer.load(this.composer);
}
app.composer.show();
}
hide() {
var post = this.props.post;
post.save({ isHidden: true });
post.pushData({ hideTime: new Date(), hideUser: app.session.user() });
}
restore() {
var post = this.props.post;
post.save({ isHidden: false });
post.pushData({ hideTime: null, hideUser: null });
}
delete() {
var post = this.props.post;
post.delete();
this.props.ondelete && this.props.ondelete(post);
}
}

View File

@ -1,59 +1,14 @@
import Component from 'flarum/component';
import icon from 'flarum/helpers/icon';
import username from 'flarum/helpers/username';
import humanTime from 'flarum/utils/human-time';
import SubtreeRetainer from 'flarum/utils/subtree-retainer';
import ItemList from 'flarum/utils/item-list';
import ActionButton from 'flarum/components/action-button';
import DropdownButton from 'flarum/components/dropdown-button';
export default class PostDiscussionRenamed extends Component {
constructor(props) {
super(props);
this.subtree = new SubtreeRetainer(
() => this.props.post.freshness,
() => this.props.post.user().freshness
);
}
view(ctrl) {
var controls = this.controlItems().toArray();
import PostActivity from 'flarum/components/post-activity';
export default class PostDiscussionRenamed extends PostActivity {
view() {
var post = this.props.post;
var oldTitle = post.content()[0];
var newTitle = post.content()[1];
return m('article.post.post-activity.post-discussion-renamed', this.subtree.retain() || m('div', [
controls.length ? DropdownButton.component({
items: controls,
className: 'contextual-controls',
buttonClass: 'btn btn-default btn-icon btn-sm btn-naked',
menuClass: 'pull-right'
}) : '',
icon('pencil post-icon'),
m('div.post-activity-info', [
m('a.post-user', {href: app.route('user', { username: post.user().username() }), config: m.route}, username(post.user())),
' changed the title from ', m('strong.old-title', oldTitle), ' to ', m('strong.new-title', newTitle), '.'
]),
m('div.post-activity-time', humanTime(post.time()))
]));
}
controlItems() {
var items = new ItemList();
var post = this.props.post;
if (post.canDelete()) {
items.add('delete', ActionButton.component({ icon: 'times', label: 'Delete', onclick: this.delete.bind(this) }));
}
return items;
}
delete() {
var post = this.props.post;
post.delete();
this.props.ondelete && this.props.ondelete(post);
return super.view(['changed the title from ', m('strong.old-title', oldTitle), ' to ', m('strong.new-title', newTitle), '.'], {
className: 'post-discussion-renamed',
icon: 'pencil'
});
}
}

View File

@ -0,0 +1,31 @@
import Component from 'flarum/component';
import SubtreeRetainer from 'flarum/utils/subtree-retainer';
import DropdownButton from 'flarum/components/dropdown-button';
export default class Post extends Component {
constructor(props) {
super(props);
this.subtree = new SubtreeRetainer(
() => this.props.post.freshness,
() => {
var user = this.props.post.user();
return user && user.freshness;
}
);
}
view(content, attrs) {
var controls = this.props.post.controls(this).toArray();
return m('article.post', attrs, this.subtree.retain() || m('div', [
controls.length ? DropdownButton.component({
items: controls,
className: 'contextual-controls',
buttonClass: 'btn btn-default btn-icon btn-sm btn-naked',
menuClass: 'pull-right'
}) : '',
content
]));
}
}

View File

@ -0,0 +1,48 @@
import Post from 'flarum/models/post';
import ComposerEdit from 'flarum/components/composer-edit';
import ActionButton from 'flarum/components/action-button';
import Separator from 'flarum/components/separator';
import ItemList from 'flarum/utils/item-list';
export default function(app) {
function editAction() {
app.composer.load(new ComposerEdit({ post: this }));
app.composer.show();
}
function hideAction() {
this.save({ isHidden: true });
this.pushData({ hideTime: new Date(), hideUser: app.session.user() });
}
function restoreAction() {
this.save({ isHidden: false });
this.pushData({ hideTime: null, hideUser: null });
}
function deleteAction() {
this.delete();
if (app.current instanceof DiscussionPage) {
app.current.stream().removePost(this.id());
}
}
Post.prototype.controls = function(context) {
var items = new ItemList();
if (this.contentType() === 'comment' && this.canEdit()) {
if (this.isHidden()) {
items.add('restore', ActionButton.component({ icon: 'reply', label: 'Restore', onclick: restoreAction.bind(this) }));
} else {
items.add('edit', ActionButton.component({ icon: 'pencil', label: 'Edit', onclick: editAction.bind(this) }));
items.add('hide', ActionButton.component({ icon: 'times', label: 'Delete', onclick: hideAction.bind(this) }));
}
}
if ((this.contentType() !== 'comment' || this.isHidden()) && this.canDelete()) {
items.add('delete', ActionButton.component({ icon: 'times', label: 'Delete', onclick: deleteAction.bind(this) }));
}
return items;
}
};