mirror of
https://github.com/flarum/framework.git
synced 2025-03-15 00:05:12 +08:00
forum: make Discussion Page properly redraw PostStream - don't store vnode
Issue is that the code now looks like an ugly mess. :/
This commit is contained in:
parent
b9583943c5
commit
dcb3cc1701
4
js/dist/forum.js
vendored
4
js/dist/forum.js
vendored
File diff suppressed because one or more lines are too long
2
js/dist/forum.js.map
vendored
2
js/dist/forum.js.map
vendored
File diff suppressed because one or more lines are too long
@ -127,7 +127,7 @@ export default class CommentPost extends Post {
|
||||
const post = this.props.post;
|
||||
const props = { post };
|
||||
|
||||
items.add('user', this.postUser, 100);
|
||||
items.add('user', <PostUser post={this.props.post} />, 100);
|
||||
// items.add('meta', PostMeta.component(props));
|
||||
|
||||
if (post.isEdited() && !post.isHidden()) {
|
||||
|
@ -10,8 +10,6 @@ import DiscussionControls from '../utils/DiscussionControls';
|
||||
import Discussion from '../../common/models/Discussion';
|
||||
import Post from '../../common/models/Post';
|
||||
|
||||
import { Vnode } from 'mithril';
|
||||
|
||||
/**
|
||||
* The `DiscussionPage` component displays a whole discussion page, including
|
||||
* the discussion list pane, the hero, the posts, and the sidebar.
|
||||
@ -27,7 +25,10 @@ export default class DiscussionPage extends Page {
|
||||
*/
|
||||
near?: number;
|
||||
|
||||
stream?: Vnode<{}, PostStream>;
|
||||
stream!: PostStream;
|
||||
scrubber!: PostStreamScrubber;
|
||||
|
||||
includedPosts: Post[] = [];
|
||||
|
||||
oninit(vnode) {
|
||||
super.oninit(vnode);
|
||||
@ -63,7 +64,7 @@ export default class DiscussionPage extends Page {
|
||||
const near = m.route.param('near') || '1';
|
||||
|
||||
if (near !== String(this.near)) {
|
||||
this.stream?.state.goToNumber(near);
|
||||
this.stream.goToNumber(near);
|
||||
}
|
||||
|
||||
this.near = null;
|
||||
@ -89,6 +90,23 @@ export default class DiscussionPage extends Page {
|
||||
view() {
|
||||
const discussion = this.discussion;
|
||||
|
||||
// Set up the post stream for this discussion, along with the first page of
|
||||
// posts we want to display. Tell the stream to scroll down and highlight
|
||||
// the specific post that was routed to.
|
||||
const postStream = (
|
||||
<PostStream
|
||||
discussion={discussion}
|
||||
includedPosts={this.includedPosts}
|
||||
oninit={vnode => {
|
||||
this.stream = vnode.state;
|
||||
this.scrubber.stream = vnode.state;
|
||||
|
||||
this.stream.on('positionChanged', this.positionChanged.bind(this));
|
||||
this.stream.goToNumber(m.route.param('near') || (this.includedPosts[0] && this.includedPosts[0].number()), true);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="DiscussionPage">
|
||||
{app.cache.discussionList ? (
|
||||
@ -107,7 +125,7 @@ export default class DiscussionPage extends Page {
|
||||
<nav className="DiscussionPage-nav">
|
||||
<ul>{listItems(this.sidebarItems().toArray())}</ul>
|
||||
</nav>
|
||||
<div className="DiscussionPage-stream">{this.stream}</div>
|
||||
<div className="DiscussionPage-stream">{postStream}</div>
|
||||
</div>,
|
||||
]
|
||||
: LoadingIndicator.component({ className: 'LoadingIndicator--block' })}
|
||||
@ -173,11 +191,10 @@ export default class DiscussionPage extends Page {
|
||||
// extensions. We need to distinguish the two so we don't end up displaying
|
||||
// the wrong posts. We do so by filtering out the posts that don't have
|
||||
// the 'discussion' relationship linked, then sorting and splicing.
|
||||
let includedPosts: Post[] = [];
|
||||
if (discussion.payload && discussion.payload.included) {
|
||||
const discussionId = discussion.id();
|
||||
|
||||
includedPosts = discussion.payload.included
|
||||
this.includedPosts = discussion.payload.included
|
||||
.filter(
|
||||
record =>
|
||||
record.type === 'posts' &&
|
||||
@ -191,22 +208,6 @@ export default class DiscussionPage extends Page {
|
||||
}
|
||||
|
||||
m.redraw();
|
||||
|
||||
const positionChanged = this.positionChanged.bind(this);
|
||||
|
||||
// Set up the post stream for this discussion, along with the first page of
|
||||
// posts we want to display. Tell the stream to scroll down and highlight
|
||||
// the specific post that was routed to.
|
||||
this.stream = (
|
||||
<PostStream
|
||||
discussion={discussion}
|
||||
includedPosts={includedPosts}
|
||||
oncreate={function(this: PostStream) {
|
||||
this.on('positionChanged', positionChanged);
|
||||
this.goToNumber(m.route.param('near') || (includedPosts[0] && includedPosts[0].number()), true);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -259,7 +260,7 @@ export default class DiscussionPage extends Page {
|
||||
})
|
||||
);
|
||||
|
||||
items.add('scrubber', <PostStreamScrubber stream={this.stream} className="App-titleControl" />, -100);
|
||||
items.add('scrubber', <PostStreamScrubber oninit={vnode => (this.scrubber = vnode.state)} className="App-titleControl" />, -100);
|
||||
|
||||
return items;
|
||||
}
|
||||
|
@ -1,21 +1,15 @@
|
||||
import Component, { ComponentProps } from '../../common/Component';
|
||||
import Component from '../../common/Component';
|
||||
import icon from '../../common/helpers/icon';
|
||||
import ScrollListener from '../../common/utils/ScrollListener';
|
||||
import SubtreeRetainer from '../../common/utils/SubtreeRetainer';
|
||||
import formatNumber from '../../common/utils/formatNumber';
|
||||
import PostStream from './PostStream';
|
||||
import { EventHandler } from '../../common/utils/Evented';
|
||||
import { Vnode } from 'mithril';
|
||||
|
||||
export interface PostStreamScrubberProps extends ComponentProps {
|
||||
stream: Vnode<{}, PostStream>;
|
||||
}
|
||||
|
||||
/**
|
||||
* The `PostStreamScrubber` component displays a scrubber which can be used to
|
||||
* navigate/scrub through a post stream.
|
||||
*/
|
||||
export default class PostStreamScrubber<T extends PostStreamScrubberProps = PostStreamScrubberProps> extends Component<T> {
|
||||
export default class PostStreamScrubber extends Component {
|
||||
handlers: { [key: string]: EventHandler } = {};
|
||||
|
||||
/**
|
||||
@ -51,13 +45,12 @@ export default class PostStreamScrubber<T extends PostStreamScrubberProps = Post
|
||||
mouseStart = 0;
|
||||
indexStart = 0;
|
||||
|
||||
oninit(vnode) {
|
||||
super.oninit(vnode);
|
||||
}
|
||||
// Added when Component is initialized through `oninit` prop
|
||||
stream!: PostStream;
|
||||
|
||||
view() {
|
||||
const count = this.count();
|
||||
const unreadCount = this.props.stream.state?.discussion.unreadCount() || 0;
|
||||
const unreadCount = this.stream?.discussion.unreadCount() || 0;
|
||||
const unreadPercent = count ? Math.min(count - this.index, unreadCount) / count : 0;
|
||||
|
||||
const viewing = app.translator.transChoice('core.forum.post_scrubber.viewing_text', count, {
|
||||
@ -129,7 +122,7 @@ export default class PostStreamScrubber<T extends PostStreamScrubberProps = Post
|
||||
* Go to the first post in the discussion.
|
||||
*/
|
||||
goToFirst() {
|
||||
this.props.stream.state?.goToFirst();
|
||||
this.stream.goToFirst();
|
||||
this.index = 0;
|
||||
this.renderScrollbar(true);
|
||||
}
|
||||
@ -138,7 +131,7 @@ export default class PostStreamScrubber<T extends PostStreamScrubberProps = Post
|
||||
* Go to the last post in the discussion.
|
||||
*/
|
||||
goToLast() {
|
||||
this.props.stream.state?.goToLast();
|
||||
this.stream.goToLast();
|
||||
this.index = this.count();
|
||||
this.renderScrollbar(true);
|
||||
}
|
||||
@ -147,7 +140,7 @@ export default class PostStreamScrubber<T extends PostStreamScrubberProps = Post
|
||||
* Get the number of posts in the discussion.
|
||||
*/
|
||||
count(): number {
|
||||
return this.props.stream.state?.count() || 0;
|
||||
return this.stream?.count() || 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -171,7 +164,7 @@ export default class PostStreamScrubber<T extends PostStreamScrubberProps = Post
|
||||
* posts.
|
||||
*/
|
||||
onscroll(top: number) {
|
||||
const stream = this.props.stream.state;
|
||||
const stream = this.stream;
|
||||
|
||||
if (!stream || stream.paused || !stream.$()) return;
|
||||
|
||||
@ -184,7 +177,7 @@ export default class PostStreamScrubber<T extends PostStreamScrubberProps = Post
|
||||
* current scroll position.
|
||||
*/
|
||||
update(scrollTop?: number) {
|
||||
const stream = this.props.stream.state;
|
||||
const stream = this.stream;
|
||||
|
||||
const marginTop = stream.getMarginTop();
|
||||
const viewportTop = scrollTop + marginTop;
|
||||
@ -253,8 +246,8 @@ export default class PostStreamScrubber<T extends PostStreamScrubberProps = Post
|
||||
|
||||
// When the post stream begins loading posts at a certain index, we want our
|
||||
// scrubber scrollbar to jump to that position.
|
||||
this.props.stream.state.on('unpaused', (this.handlers.streamWasUnpaused = this.streamWasUnpaused.bind(this)));
|
||||
this.props.stream.state.on('update', () => this.update());
|
||||
this.stream.on('unpaused', (this.handlers.streamWasUnpaused = this.streamWasUnpaused.bind(this)));
|
||||
this.stream.on('update', () => this.update());
|
||||
|
||||
this.scrollListener.start();
|
||||
|
||||
@ -293,7 +286,7 @@ export default class PostStreamScrubber<T extends PostStreamScrubberProps = Post
|
||||
ondestroy() {
|
||||
this.scrollListener.stop();
|
||||
|
||||
this.props.stream.state.off('unpaused', this.handlers.streamWasUnpaused);
|
||||
this.stream.off('unpaused', this.handlers.streamWasUnpaused);
|
||||
|
||||
$(window).off('resize', this.handlers.onresize);
|
||||
|
||||
@ -384,7 +377,7 @@ export default class PostStreamScrubber<T extends PostStreamScrubberProps = Post
|
||||
this.mouseStart = e.clientY || e.originalEvent.touches[0].clientY;
|
||||
this.indexStart = this.index;
|
||||
this.dragging = true;
|
||||
this.props.stream.state.paused = true;
|
||||
this.stream.paused = true;
|
||||
$('body').css('cursor', 'move');
|
||||
}
|
||||
|
||||
@ -417,7 +410,7 @@ export default class PostStreamScrubber<T extends PostStreamScrubberProps = Post
|
||||
// If the index we've landed on is in a gap, then tell the stream-
|
||||
// content that we want to load those posts.
|
||||
const intIndex = Math.floor(this.index);
|
||||
this.props.stream.state?.goToIndex(intIndex);
|
||||
this.stream.goToIndex(intIndex);
|
||||
this.renderScrollbar(true);
|
||||
}
|
||||
|
||||
@ -439,7 +432,7 @@ export default class PostStreamScrubber<T extends PostStreamScrubberProps = Post
|
||||
// content component to jump to that index.
|
||||
let offsetIndex = offsetPercent / this.percentPerPost().index;
|
||||
offsetIndex = Math.max(0, Math.min(this.count() - 1, offsetIndex));
|
||||
this.props.stream.state?.goToIndex(Math.floor(offsetIndex));
|
||||
this.stream.goToIndex(Math.floor(offsetIndex));
|
||||
this.index = offsetIndex;
|
||||
this.renderScrollbar(true);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user