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

update: forum/components/DiscussionListItem

This commit is contained in:
Alexander Skvortsov
2020-08-08 12:05:14 -04:00
committed by Franz Liedke
parent 9793c10610
commit 60c3f23667

View File

@@ -8,7 +8,6 @@ import ItemList from '../../common/utils/ItemList';
import abbreviateNumber from '../../common/utils/abbreviateNumber'; import abbreviateNumber from '../../common/utils/abbreviateNumber';
import Dropdown from '../../common/components/Dropdown'; import Dropdown from '../../common/components/Dropdown';
import TerminalPost from './TerminalPost'; import TerminalPost from './TerminalPost';
import PostPreview from './PostPreview';
import SubtreeRetainer from '../../common/utils/SubtreeRetainer'; import SubtreeRetainer from '../../common/utils/SubtreeRetainer';
import DiscussionControls from '../utils/DiscussionControls'; import DiscussionControls from '../utils/DiscussionControls';
import slidable from '../utils/slidable'; import slidable from '../utils/slidable';
@@ -26,7 +25,9 @@ import { escapeRegExp } from 'lodash-es';
* - `params` * - `params`
*/ */
export default class DiscussionListItem extends Component { export default class DiscussionListItem extends Component {
init() { oninit(vnode) {
super.oninit(vnode);
/** /**
* Set up a subtree retainer so that the discussion will not be redrawn * Set up a subtree retainer so that the discussion will not be redrawn
* unless new data comes in. * unless new data comes in.
@@ -34,7 +35,7 @@ export default class DiscussionListItem extends Component {
* @type {SubtreeRetainer} * @type {SubtreeRetainer}
*/ */
this.subtree = new SubtreeRetainer( this.subtree = new SubtreeRetainer(
() => this.props.discussion.freshness, () => this.attrs.discussion.freshness,
() => { () => {
const time = app.session.user && app.session.user.markedAllAsReadAt(); const time = app.session.user && app.session.user.markedAllAsReadAt();
return time && time.getTime(); return time && time.getTime();
@@ -43,37 +44,33 @@ export default class DiscussionListItem extends Component {
); );
} }
attrs() { elementAttrs() {
return { return {
className: classList([ className: classList([
'DiscussionListItem', 'DiscussionListItem',
this.active() ? 'active' : '', this.active() ? 'active' : '',
this.props.discussion.isHidden() ? 'DiscussionListItem--hidden' : '', this.attrs.discussion.isHidden() ? 'DiscussionListItem--hidden' : '',
]), ]),
}; };
} }
view() { view(vnode) {
const retain = this.subtree.retain(); const discussion = this.attrs.discussion;
if (retain) return retain;
const discussion = this.props.discussion;
const user = discussion.user(); const user = discussion.user();
const isUnread = discussion.isUnread(); const isUnread = discussion.isUnread();
const isRead = discussion.isRead(); const isRead = discussion.isRead();
const showUnread = !this.showRepliesCount() && isUnread; const showUnread = !this.showRepliesCount() && isUnread;
let jumpTo = 0; let jumpTo = 0;
const controls = DiscussionControls.controls(discussion, this).toArray(); const controls = DiscussionControls.controls(discussion, this).toArray();
const attrs = this.attrs(); const attrs = this.elementAttrs();
if (this.props.params.q) { if (this.attrs.params.q) {
const post = discussion.mostRelevantPost(); const post = discussion.mostRelevantPost();
if (post) { if (post) {
jumpTo = post.number(); jumpTo = post.number();
} }
const phrase = escapeRegExp(this.props.params.q); const phrase = escapeRegExp(this.attrs.params.q);
this.highlightRegExp = new RegExp(phrase + '|' + phrase.trim().replace(/\s+/g, '|'), 'gi'); this.highlightRegExp = new RegExp(phrase + '|' + phrase.trim().replace(/\s+/g, '|'), 'gi');
} else { } else {
jumpTo = Math.min(discussion.lastPostNumber(), (discussion.lastReadPostNumber() || 0) + 1); jumpTo = Math.min(discussion.lastPostNumber(), (discussion.lastReadPostNumber() || 0) + 1);
@@ -82,12 +79,14 @@ export default class DiscussionListItem extends Component {
return ( return (
<div {...attrs}> <div {...attrs}>
{controls.length {controls.length
? Dropdown.component({ ? Dropdown.component(
icon: 'fas fa-ellipsis-v', {
children: controls, icon: 'fas fa-ellipsis-v',
className: 'DiscussionListItem-controls', className: 'DiscussionListItem-controls',
buttonClassName: 'Button Button--icon Button--flat Slidable-underneath Slidable-underneath--right', buttonClassName: 'Button Button--icon Button--flat Slidable-underneath Slidable-underneath--right',
}) },
controls
)
: ''} : ''}
<a <a
@@ -131,8 +130,8 @@ export default class DiscussionListItem extends Component {
); );
} }
config(isInitialized) { oncreate(vnode) {
if (isInitialized) return; super.oncreate(vnode);
// If we're on a touch device, set up the discussion row to be slidable. // If we're on a touch device, set up the discussion row to be slidable.
// This allows the user to drag the row to either side of the screen to // This allows the user to drag the row to either side of the screen to
@@ -144,6 +143,12 @@ export default class DiscussionListItem extends Component {
} }
} }
onbeforeupdate(vnode, old) {
super.onbeforeupdate(vnode, old);
return this.subtree.needsRebuild();
}
/** /**
* Determine whether or not the discussion is currently being viewed. * Determine whether or not the discussion is currently being viewed.
* *
@@ -152,7 +157,7 @@ export default class DiscussionListItem extends Component {
active() { active() {
const idParam = m.route.param('id'); const idParam = m.route.param('id');
return idParam && idParam.split('-')[0] === this.props.discussion.id(); return idParam && idParam.split('-')[0] === this.attrs.discussion.id();
} }
/** /**
@@ -163,7 +168,7 @@ export default class DiscussionListItem extends Component {
* @return {Boolean} * @return {Boolean}
*/ */
showFirstPost() { showFirstPost() {
return ['newest', 'oldest'].indexOf(this.props.params.sort) !== -1; return ['newest', 'oldest'].indexOf(this.attrs.params.sort) !== -1;
} }
/** /**
@@ -173,14 +178,14 @@ export default class DiscussionListItem extends Component {
* @return {Boolean} * @return {Boolean}
*/ */
showRepliesCount() { showRepliesCount() {
return this.props.params.sort === 'replies'; return this.attrs.params.sort === 'replies';
} }
/** /**
* Mark the discussion as read. * Mark the discussion as read.
*/ */
markAsRead() { markAsRead() {
const discussion = this.props.discussion; const discussion = this.attrs.discussion;
if (discussion.isUnread()) { if (discussion.isUnread()) {
discussion.save({ lastReadPostNumber: discussion.lastPostNumber() }); discussion.save({ lastReadPostNumber: discussion.lastPostNumber() });
@@ -197,8 +202,8 @@ export default class DiscussionListItem extends Component {
infoItems() { infoItems() {
const items = new ItemList(); const items = new ItemList();
if (this.props.params.q) { if (this.attrs.params.q) {
const post = this.props.discussion.mostRelevantPost() || this.props.discussion.firstPost(); const post = this.attrs.discussion.mostRelevantPost() || this.attrs.discussion.firstPost();
if (post && post.contentType() === 'comment') { if (post && post.contentType() === 'comment') {
const excerpt = highlight(post.contentPlain(), this.highlightRegExp, 175); const excerpt = highlight(post.contentPlain(), this.highlightRegExp, 175);
@@ -208,7 +213,7 @@ export default class DiscussionListItem extends Component {
items.add( items.add(
'terminalPost', 'terminalPost',
TerminalPost.component({ TerminalPost.component({
discussion: this.props.discussion, discussion: this.attrs.discussion,
lastPost: !this.showFirstPost(), lastPost: !this.showFirstPost(),
}) })
); );