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

View File

@ -4,8 +4,8 @@ export default class Notification extends Component {
view() { view() {
var notification = this.props.notification; var notification = this.props.notification;
return m('div.notification', { return m('div.notification.notification-'+notification.contentType(), {
classNames: !notification.isRead ? 'unread' : '', classNames: !notification.isRead() ? 'unread' : '',
onclick: this.read.bind(this) onclick: this.read.bind(this)
}, this.content()); }, 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 classList from 'flarum/utils/class-list';
import ComposerEdit from 'flarum/components/composer-edit';
import PostHeaderUser from 'flarum/components/post-header-user'; import PostHeaderUser from 'flarum/components/post-header-user';
import PostHeaderMeta from 'flarum/components/post-header-meta'; import PostHeaderMeta from 'flarum/components/post-header-meta';
import PostHeaderEdited from 'flarum/components/post-header-edited'; import PostHeaderEdited from 'flarum/components/post-header-edited';
import PostHeaderToggle from 'flarum/components/post-header-toggle'; import PostHeaderToggle from 'flarum/components/post-header-toggle';
import ItemList from 'flarum/utils/item-list'; 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'; 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 (controls, header, and footer) surrounding the post's HTML content. Allows
the post to be edited with the composer, hidden, or restored. 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) { constructor(props) {
super(props); super(props);
this.postHeaderUser = new PostHeaderUser({post: this.props.post}); this.postHeaderUser = new PostHeaderUser({post: this.props.post});
this.subtree.add(this.postHeaderUser.showCard);
this.subtree = new SubtreeRetainer(
() => this.props.post.freshness,
() => this.props.post.user() && this.props.post.user().freshness,
this.postHeaderUser.showCard
);
} }
view() { view() {
var post = this.props.post; var post = this.props.post;
var classes = { return super.view([
'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'
}) : '',
m('header.post-header', m('ul', listItems(this.headerItems().toArray()))), m('header.post-header', m('ul', listItems(this.headerItems().toArray()))),
m('div.post-body', m.trust(post.contentHtml())), m('div.post-body', m.trust(post.contentHtml())),
m('aside.post-footer', m('ul', listItems(this.footerItems().toArray()))), m('aside.post-footer', m('ul', listItems(this.footerItems().toArray()))),
m('aside.post-actions', m('ul', listItems(this.actionItems().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() { toggleContent() {
@ -78,25 +61,6 @@ export default class PostComment extends Component {
return items; 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() { footerItems() {
return new ItemList(); return new ItemList();
} }
@ -104,30 +68,4 @@ export default class PostComment extends Component {
actionItems() { actionItems() {
return new ItemList(); 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 PostActivity from 'flarum/components/post-activity';
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();
export default class PostDiscussionRenamed extends PostActivity {
view() {
var post = this.props.post; var post = this.props.post;
var oldTitle = post.content()[0]; var oldTitle = post.content()[0];
var newTitle = post.content()[1]; var newTitle = post.content()[1];
return m('article.post.post-activity.post-discussion-renamed', this.subtree.retain() || m('div', [ return super.view(['changed the title from ', m('strong.old-title', oldTitle), ' to ', m('strong.new-title', newTitle), '.'], {
controls.length ? DropdownButton.component({ className: 'post-discussion-renamed',
items: controls, icon: 'pencil'
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);
} }
} }

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;
}
};