Remove fake img preview before loaded (#5854)

Remove fake img preview and collapse toggle before it is loaded,
only show img and toggle after it is fully loaded.
Fix markdown img size and add scroll down behaviour.
Этот коммит содержится в:
VeraLyu
2017-06-17 01:12:22 +08:00
коммит произвёл Harrison Healey
родитель 617c6e0b23
Коммит 5158d3a446
6 изменённых файлов: 91 добавлений и 33 удалений

Просмотреть файл

@@ -23,19 +23,20 @@ export default class PostBodyAdditionalContent extends React.Component {
this.toggleEmbedVisibility = this.toggleEmbedVisibility.bind(this); this.toggleEmbedVisibility = this.toggleEmbedVisibility.bind(this);
this.isLinkToggleable = this.isLinkToggleable.bind(this); this.isLinkToggleable = this.isLinkToggleable.bind(this);
this.handleLinkLoadError = this.handleLinkLoadError.bind(this); this.handleLinkLoadError = this.handleLinkLoadError.bind(this);
this.handleLinkLoaded = this.handleLinkLoaded.bind(this);
this.state = { this.state = {
embedVisible: props.previewCollapsed.startsWith('false'), embedVisible: props.previewCollapsed.startsWith('false'),
link: Utils.extractFirstLink(props.post.message), link: Utils.extractFirstLink(props.post.message),
linkLoadError: false linkLoadError: false,
linkLoaded: false
}; };
} }
componentWillReceiveProps(nextProps) { componentWillReceiveProps(nextProps) {
this.setState({ this.setState({
embedVisible: nextProps.previewCollapsed.startsWith('false'), embedVisible: nextProps.previewCollapsed.startsWith('false'),
link: Utils.extractFirstLink(nextProps.post.message), link: Utils.extractFirstLink(nextProps.post.message)
linkLoadError: false
}); });
} }
@@ -52,6 +53,9 @@ export default class PostBodyAdditionalContent extends React.Component {
if (nextState.linkLoadError !== this.state.linkLoadError) { if (nextState.linkLoadError !== this.state.linkLoadError) {
return true; return true;
} }
if (nextState.linkLoaded !== this.state.linkLoaded) {
return true;
}
return false; return false;
} }
@@ -105,6 +109,12 @@ export default class PostBodyAdditionalContent extends React.Component {
}); });
} }
handleLinkLoaded() {
this.setState({
linkLoaded: true
});
}
generateToggleableEmbed() { generateToggleableEmbed() {
const link = this.state.link; const link = this.state.link;
if (!link) { if (!link) {
@@ -127,6 +137,8 @@ export default class PostBodyAdditionalContent extends React.Component {
channelId={this.props.post.channel_id} channelId={this.props.post.channel_id}
link={link} link={link}
onLinkLoadError={this.handleLinkLoadError} onLinkLoadError={this.handleLinkLoadError}
onLinkLoaded={this.handleLinkLoaded}
childComponentDidUpdateFunction={this.props.childComponentDidUpdateFunction}
/> />
); );
} }
@@ -174,11 +186,13 @@ export default class PostBodyAdditionalContent extends React.Component {
</div> </div>
); );
let contents; const contents = [message];
if (prependToggle) { if (this.state.linkLoaded) {
contents = [toggle, message]; if (prependToggle) {
} else { contents.unshift(toggle);
contents = [message, toggle]; } else {
contents.push(toggle);
}
} }
if (this.state.embedVisible) { if (this.state.embedVisible) {

Просмотреть файл

@@ -32,6 +32,9 @@ export default class PostImageEmbed extends React.Component {
} }
componentDidUpdate(prevProps) { componentDidUpdate(prevProps) {
if (this.state.loaded && this.props.childComponentDidUpdateFunction) {
this.props.childComponentDidUpdateFunction();
}
if (!this.state.loaded && prevProps.link !== this.props.link) { if (!this.state.loaded && prevProps.link !== this.props.link) {
this.loadImg(this.props.link); this.loadImg(this.props.link);
} }
@@ -46,8 +49,12 @@ export default class PostImageEmbed extends React.Component {
handleLoadComplete() { handleLoadComplete() {
this.setState({ this.setState({
loaded: true loaded: true,
errored: false
}); });
if (this.props.onLinkLoaded) {
this.props.onLinkLoaded();
}
} }
handleLoadError() { handleLoadError() {
@@ -61,29 +68,26 @@ export default class PostImageEmbed extends React.Component {
} }
render() { render() {
if (this.state.errored) { if (this.state.errored || !this.state.loaded) {
return null; return null;
} }
if (!this.state.loaded) {
return (
<img
className='img-div placeholder'
height='500px'
/>
);
}
return ( return (
<img <div
className='img-div' className='post__embed-container'
src={this.props.link} >
/> <img
className='img-div'
src={this.props.link}
/>
</div>
); );
} }
} }
PostImageEmbed.propTypes = { PostImageEmbed.propTypes = {
link: PropTypes.string.isRequired, link: PropTypes.string.isRequired,
onLinkLoadError: PropTypes.func onLinkLoadError: PropTypes.func,
onLinkLoaded: PropTypes.func,
childComponentDidUpdateFunction: PropTypes.func
}; };

Просмотреть файл

@@ -23,7 +23,7 @@ const ScrollTypes = Constants.ScrollTypes;
import PostStore from 'stores/post_store.jsx'; import PostStore from 'stores/post_store.jsx';
import PreferenceStore from 'stores/preference_store.jsx'; import PreferenceStore from 'stores/preference_store.jsx';
import ScrollStore from 'stores/scroll_store.jsx';
import {FormattedDate, FormattedMessage} from 'react-intl'; import {FormattedDate, FormattedMessage} from 'react-intl';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
@@ -49,6 +49,7 @@ export default class PostList extends React.Component {
this.scrollToBottomAnimated = this.scrollToBottomAnimated.bind(this); this.scrollToBottomAnimated = this.scrollToBottomAnimated.bind(this);
this.handleKeyDown = this.handleKeyDown.bind(this); this.handleKeyDown = this.handleKeyDown.bind(this);
this.childComponentDidUpdate = this.childComponentDidUpdate.bind(this); this.childComponentDidUpdate = this.childComponentDidUpdate.bind(this);
this.checkAndUpdateScrolling = this.checkAndUpdateScrolling.bind(this);
this.jumpToPostNode = null; this.jumpToPostNode = null;
this.wasAtBottom = true; this.wasAtBottom = true;
@@ -536,6 +537,7 @@ export default class PostList extends React.Component {
window.addEventListener('keydown', this.handleKeyDown); window.addEventListener('keydown', this.handleKeyDown);
PostStore.addPostDraftChangeListener(this.props.channelId, this.handlePostDraftChange); PostStore.addPostDraftChangeListener(this.props.channelId, this.handlePostDraftChange);
ScrollStore.addPostScrollListener(this.checkAndUpdateScrolling);
} }
handlePostDraftChange = (draft) => { handlePostDraftChange = (draft) => {
@@ -550,6 +552,7 @@ export default class PostList extends React.Component {
window.cancelAnimationFrame(this.animationFrameId); window.cancelAnimationFrame(this.animationFrameId);
window.removeEventListener('resize', this.handleResize); window.removeEventListener('resize', this.handleResize);
window.removeEventListener('keydown', this.handleKeyDown); window.removeEventListener('keydown', this.handleKeyDown);
ScrollStore.removePostScrollListener(this.checkAndUpdateScrolling);
this.scrollStopAction.cancel(); this.scrollStopAction.cancel();
PostStore.removePostDraftChangeListener(this.props.channelId, this.handlePostDraftChange); PostStore.removePostDraftChangeListener(this.props.channelId, this.handlePostDraftChange);

Просмотреть файл

@@ -156,7 +156,13 @@ export default class YoutubeVideo extends React.Component {
render() { render() {
if (!this.state.loaded) { if (!this.state.loaded) {
return <div className='video-loading'/>; return (
<div
className='post__embed-container'
>
<div className='video-loading'/>
</div>
);
} }
let header; let header;
@@ -217,13 +223,17 @@ export default class YoutubeVideo extends React.Component {
} }
return ( return (
<div> <div
{header} className='post__embed-container'
<div >
className='video-div embed-responsive-item' <div>
onClick={this.play} {header}
> <div
{content} className='video-div embed-responsive-item'
onClick={this.play}
>
{content}
</div>
</div> </div>
</div> </div>
); );

24
webapp/stores/scroll_store.jsx Обычный файл
Просмотреть файл

@@ -0,0 +1,24 @@
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
import EventEmitter from 'events';
const UPDATE_POST_SCROLL_EVENT = 'update_post_scroll';
class ScrollStoreClass extends EventEmitter {
emitPostScroll() {
this.emit(UPDATE_POST_SCROLL_EVENT);
}
addPostScrollListener(callback) {
this.on(UPDATE_POST_SCROLL_EVENT, callback);
}
removePostScrollLisener(callback) {
this.removeListener(UPDATE_POST_SCROLL_EVENT, callback);
}
}
var ScrollStore = new ScrollStoreClass();
export default ScrollStore;

Просмотреть файл

@@ -7,6 +7,8 @@ import * as SyntaxHighlighting from './syntax_highlighting.jsx';
import marked from 'marked'; import marked from 'marked';
import katex from 'katex'; import katex from 'katex';
import ScrollStore from 'stores/scroll_store.jsx';
function markdownImageLoaded(image) { function markdownImageLoaded(image) {
if (image.hasAttribute('height') && image.attributes.height.value !== 'auto') { if (image.hasAttribute('height') && image.attributes.height.value !== 'auto') {
const maxHeight = parseInt(global.getComputedStyle(image).maxHeight, 10); const maxHeight = parseInt(global.getComputedStyle(image).maxHeight, 10);
@@ -20,6 +22,7 @@ function markdownImageLoaded(image) {
} else { } else {
image.style.height = 'auto'; image.style.height = 'auto';
} }
ScrollStore.emitPostScroll();
} }
global.markdownImageLoaded = markdownImageLoaded; global.markdownImageLoaded = markdownImageLoaded;