mirror of
https://github.com/flarum/core.git
synced 2025-07-27 19:50:20 +02:00
198 lines
6.0 KiB
JavaScript
198 lines
6.0 KiB
JavaScript
import Component from 'flarum/component';
|
|
import avatar from 'flarum/helpers/avatar';
|
|
import listItems from 'flarum/helpers/list-items';
|
|
import humanTime from 'flarum/utils/human-time';
|
|
import ItemList from 'flarum/utils/item-list';
|
|
import abbreviateNumber from 'flarum/utils/abbreviate-number';
|
|
import ActionButton from 'flarum/components/action-button';
|
|
import DropdownButton from 'flarum/components/dropdown-button';
|
|
import LoadingIndicator from 'flarum/components/loading-indicator';
|
|
import TerminalPost from 'flarum/components/terminal-post';
|
|
|
|
export default class DiscussionList extends Component {
|
|
constructor(props) {
|
|
super(props);
|
|
|
|
this.loading = m.prop(true);
|
|
this.moreResults = m.prop(false);
|
|
this.discussions = m.prop([]);
|
|
this.sort = m.prop(this.props.sort || 'recent');
|
|
this.sortOptions = m.prop([
|
|
{key: 'recent', value: 'Recent', sort: 'recent'},
|
|
{key: 'replies', value: 'Replies', sort: '-replies'},
|
|
{key: 'newest', value: 'Newest', sort: '-created'},
|
|
{key: 'oldest', value: 'Oldest', sort: 'created'}
|
|
]);
|
|
|
|
this.refresh();
|
|
|
|
app.session.on('loggedIn', this.loggedInHandler = this.refresh.bind(this))
|
|
}
|
|
|
|
refresh() {
|
|
m.startComputation();
|
|
this.loading(true);
|
|
this.discussions([]);
|
|
m.endComputation();
|
|
this.loadResults().then(this.parseResults.bind(this));
|
|
}
|
|
|
|
onunload() {
|
|
app.session.off('loggedIn', this.loggedInHandler);
|
|
}
|
|
|
|
terminalPostType() {
|
|
return ['newest', 'oldest'].indexOf(this.sort()) !== -1 ? 'start' : 'last'
|
|
}
|
|
|
|
countType() {
|
|
return this.sort() === 'replies' ? 'replies' : 'unread';
|
|
}
|
|
|
|
loadResults(start) {
|
|
var self = this;
|
|
|
|
var sort = this.sortOptions()[0].sort;
|
|
this.sortOptions().some(function(option) {
|
|
if (option.key === self.sort()) {
|
|
sort = option.sort;
|
|
return true;
|
|
}
|
|
});
|
|
|
|
var params = {sort, start};
|
|
|
|
return app.store.find('discussions', params);
|
|
}
|
|
|
|
loadMore() {
|
|
var self = this;
|
|
this.loading(true);
|
|
this.loadResults(this.discussions().length).then((results) => this.parseResults(results, true));
|
|
}
|
|
|
|
parseResults(results, append) {
|
|
m.startComputation();
|
|
this.loading(false);
|
|
[].push.apply(this.discussions(), results);
|
|
this.moreResults(!!results.meta.moreUrl);
|
|
m.endComputation();
|
|
return results;
|
|
}
|
|
|
|
markAsRead(discussion) {
|
|
if (discussion.isUnread()) {
|
|
discussion.save({ readNumber: discussion.lastPostNumber() });
|
|
m.redraw();
|
|
}
|
|
}
|
|
|
|
delete(discussion) {
|
|
if (confirm('Are you sure you want to delete this discussion?')) {
|
|
discussion.delete();
|
|
this.removeDiscussion(discussion);
|
|
if (app.current.discussion && app.current.discussion().id() === discussion.id()) {
|
|
app.history.back();
|
|
}
|
|
}
|
|
}
|
|
|
|
removeDiscussion(discussion) {
|
|
var index = this.discussions().indexOf(discussion);
|
|
if (index !== -1) {
|
|
this.discussions().splice(index, 1);
|
|
}
|
|
}
|
|
|
|
view() {
|
|
return m('div', [
|
|
m('ul.discussions-list', [
|
|
this.discussions().map(function(discussion) {
|
|
var startUser = discussion.startUser()
|
|
var isUnread = discussion.isUnread()
|
|
var displayUnread = this.props.countType !== 'replies' && isUnread
|
|
var jumpTo = Math.min(discussion.lastPostNumber(), (discussion.readNumber() || 0) + 1)
|
|
|
|
var controls = this.controlItems(discussion).toArray();
|
|
|
|
var discussionRoute = app.route('discussion', discussion);
|
|
var active = m.route().substr(0, discussionRoute.length) === discussionRoute;
|
|
|
|
return m('li.discussion-summary'+(isUnread ? '.unread' : '')+(active ? '.active' : ''), {key: discussion.id()}, [
|
|
controls.length ? DropdownButton.component({
|
|
items: controls,
|
|
className: 'contextual-controls',
|
|
buttonClass: 'btn btn-default btn-icon btn-sm btn-naked',
|
|
menuClass: 'pull-right'
|
|
}) : '',
|
|
m('a.author', {
|
|
href: app.route('user', startUser),
|
|
config: function(element, isInitialized, context) {
|
|
$(element).tooltip({ placement: 'right' })
|
|
m.route.call(this, element)
|
|
},
|
|
title: 'Started by '+startUser.username()+' '+humanTime(discussion.startTime())
|
|
}, [
|
|
avatar(startUser, {title: ''})
|
|
]),
|
|
m('ul.badges', listItems(discussion.badges().toArray())),
|
|
m('a.main', {href: app.route('discussion.near', {id: discussion.id(), slug: discussion.slug(), near: jumpTo}), config: m.route}, [
|
|
m('h3.title', discussion.title()),
|
|
m('ul.info', listItems(this.infoItems(discussion).toArray()))
|
|
]),
|
|
m('span.count', {onclick: this.markAsRead.bind(this, discussion)}, [
|
|
abbreviateNumber(discussion[displayUnread ? 'unreadCount' : 'repliesCount']()),
|
|
m('span.label', displayUnread ? 'unread' : 'replies')
|
|
])
|
|
])
|
|
}.bind(this))
|
|
]),
|
|
this.loading()
|
|
? LoadingIndicator.component()
|
|
: (this.moreResults() ? m('div.load-more', ActionButton.component({
|
|
label: 'Load More',
|
|
className: 'control-loadMore btn btn-default',
|
|
onclick: this.loadMore.bind(this)
|
|
})) : '')
|
|
]);
|
|
}
|
|
|
|
/**
|
|
Build an item list of info for a discussion listing. By default this is
|
|
just the first/last post indicator.
|
|
|
|
@return {ItemList}
|
|
*/
|
|
infoItems(discussion) {
|
|
var items = new ItemList();
|
|
|
|
items.add('terminalPost',
|
|
TerminalPost.component({
|
|
discussion,
|
|
lastPost: this.props.terminalPostType !== 'start'
|
|
})
|
|
);
|
|
|
|
return items;
|
|
}
|
|
|
|
/**
|
|
Build an item list of controls for a discussion listing.
|
|
|
|
@return {ItemList}
|
|
*/
|
|
controlItems(discussion) {
|
|
var items = new ItemList();
|
|
|
|
if (discussion.canDelete()) {
|
|
items.add('delete', ActionButton.component({
|
|
icon: 'times',
|
|
label: 'Delete',
|
|
onclick: this.delete.bind(this, discussion)
|
|
}));
|
|
}
|
|
|
|
return items;
|
|
}
|
|
}
|