added [go to latest message] button
This commit is contained in:
+13
-3
@@ -478,19 +478,29 @@ div.trusted-badge {
|
|||||||
min-height: unset;
|
min-height: unset;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
line-height: 3.25rem;
|
|
||||||
outline: none; /* otherwise a square outline is shown */
|
outline: none; /* otherwise a square outline is shown */
|
||||||
box-shadow: 0 2px 0.5rem 0 rgba(0, 0, 0, 0.25);
|
box-shadow: 0 2px 0.5rem 0 rgba(0, 0, 0, 0.25);
|
||||||
transition: all 250ms;
|
transition: all 150ms;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.action-button:focus, .action-button:hover {
|
.action-button:focus, .action-button:hover {
|
||||||
color: #888;
|
color: #888;
|
||||||
|
background-color: #f0f0f0;
|
||||||
}
|
}
|
||||||
.action-button:active {
|
.action-button:active {
|
||||||
color: #777;
|
color: #777;
|
||||||
background-color: #e0e0e0;
|
background-color: #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-button.hidden {
|
||||||
|
width: 1px;
|
||||||
|
height: 1px;
|
||||||
|
font-size: 1px;
|
||||||
|
line-height: 1px;
|
||||||
|
right: 2.625rem;
|
||||||
|
bottom: 2.625rem;
|
||||||
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Element which can take focus but shows no outline */
|
/* Element which can take focus but shows no outline */
|
||||||
|
|||||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
+38
-17
@@ -16,17 +16,17 @@ import LoadSpinner from '../widgets/load-spinner.jsx';
|
|||||||
import LogoView from './logo-view.jsx';
|
import LogoView from './logo-view.jsx';
|
||||||
import SendMessage from '../widgets/send-message.jsx';
|
import SendMessage from '../widgets/send-message.jsx';
|
||||||
|
|
||||||
import { DEFAULT_P2P_ACCESS_MODE, IMAGE_PREVIEW_DIM, IMAGE_THUMBNAIL_DIM, KEYPRESS_DELAY,
|
import { DEFAULT_P2P_ACCESS_MODE, IMAGE_PREVIEW_DIM, KEYPRESS_DELAY,
|
||||||
MESSAGES_PAGE, MAX_EXTERN_ATTACHMENT_SIZE, MAX_IMAGE_DIM, MAX_INBAND_ATTACHMENT_SIZE,
|
MESSAGES_PAGE, MAX_EXTERN_ATTACHMENT_SIZE, MAX_IMAGE_DIM, MAX_INBAND_ATTACHMENT_SIZE,
|
||||||
READ_DELAY, QUOTED_REPLY_LENGTH } from '../config.js';
|
READ_DELAY, QUOTED_REPLY_LENGTH } from '../config.js';
|
||||||
import { SUPPORTED_IMAGE_FORMATS, blobToBase64, base64ToBlob, filePasted, fileToBase64,
|
import { blobToBase64, fileToBase64, imageScaled, makeImageUrl } from '../lib/blob-helpers.js';
|
||||||
imageScaled, makeImageUrl } from '../lib/blob-helpers.js';
|
|
||||||
import HashNavigation from '../lib/navigation.js';
|
import HashNavigation from '../lib/navigation.js';
|
||||||
import { bytesToHumanSize, shortDateFormat, letterTileColorId } from '../lib/strformat.js';
|
import { bytesToHumanSize, shortDateFormat } from '../lib/strformat.js';
|
||||||
import { sanitizeImageUrl } from '../lib/utils.js';
|
|
||||||
|
|
||||||
// Run timer with this frequency (ms) for checking notification queue.
|
// Run timer with this frequency (ms) for checking notification queue.
|
||||||
const NOTIFICATION_EXEC_INTERVAL = 300;
|
const NOTIFICATION_EXEC_INTERVAL = 300;
|
||||||
|
// Scroll distance before [go to latest message] button is shown.
|
||||||
|
const SHOW_GO_TO_LAST_DIST = 100;
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
online_now: {
|
online_now: {
|
||||||
@@ -110,6 +110,7 @@ class MessagesView extends React.Component {
|
|||||||
this.handleCancelUpload = this.handleCancelUpload.bind(this);
|
this.handleCancelUpload = this.handleCancelUpload.bind(this);
|
||||||
this.postReadNotification = this.postReadNotification.bind(this);
|
this.postReadNotification = this.postReadNotification.bind(this);
|
||||||
this.clearNotificationQueue = this.clearNotificationQueue.bind(this);
|
this.clearNotificationQueue = this.clearNotificationQueue.bind(this);
|
||||||
|
this.goToLatestMessage = this.goToLatestMessage.bind(this);
|
||||||
|
|
||||||
this.handlePickReply = this.handlePickReply.bind(this);
|
this.handlePickReply = this.handlePickReply.bind(this);
|
||||||
this.handleCancelReply = this.handleCancelReply.bind(this);
|
this.handleCancelReply = this.handleCancelReply.bind(this);
|
||||||
@@ -149,13 +150,13 @@ class MessagesView extends React.Component {
|
|||||||
// Scroll last message into view on component update e.g. on message received
|
// Scroll last message into view on component update e.g. on message received
|
||||||
// or vertical shrinking.
|
// or vertical shrinking.
|
||||||
componentDidUpdate(prevProps, prevState) {
|
componentDidUpdate(prevProps, prevState) {
|
||||||
if (this.messagesScroller) {
|
if (this.messagesScroller &&
|
||||||
if (prevState.topic != this.state.topic || prevState.messageCount != this.state.messageCount) {
|
(prevState.topic != this.state.topic || prevState.messageCount != this.state.messageCount)) {
|
||||||
// New message
|
// New message.
|
||||||
this.messagesScroller.scrollTop = this.messagesScroller.scrollHeight - this.state.scrollPosition;
|
if (this.state.scrollPosition < SHOW_GO_TO_LAST_DIST) {
|
||||||
} else if (prevProps.viewportHeight > this.props.viewportHeight) {
|
this.messagesScroller.scrollTop = this.messagesScroller.scrollHeight -
|
||||||
// Componet changed height.
|
this.state.scrollPosition -
|
||||||
this.messagesScroller.scrollTop += prevProps.viewportHeight - this.props.viewportHeight;
|
this.messagesScroller.offsetHeight;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -210,7 +211,8 @@ class MessagesView extends React.Component {
|
|||||||
fetchingMessages: false,
|
fetchingMessages: false,
|
||||||
peerMessagingDisabled: false,
|
peerMessagingDisabled: false,
|
||||||
channel: false,
|
channel: false,
|
||||||
reply: null
|
reply: null,
|
||||||
|
showGoToLastButton: false
|
||||||
};
|
};
|
||||||
} else if (nextProps.topic != prevState.topic) {
|
} else if (nextProps.topic != prevState.topic) {
|
||||||
const topic = nextProps.tinode.getTopic(nextProps.topic);
|
const topic = nextProps.tinode.getTopic(nextProps.topic);
|
||||||
@@ -234,7 +236,8 @@ class MessagesView extends React.Component {
|
|||||||
typingIndicator: false,
|
typingIndicator: false,
|
||||||
scrollPosition: 0,
|
scrollPosition: 0,
|
||||||
fetchingMessages: false,
|
fetchingMessages: false,
|
||||||
reply: reply
|
reply: reply,
|
||||||
|
showGoToLastButton: false
|
||||||
};
|
};
|
||||||
|
|
||||||
if (topic) {
|
if (topic) {
|
||||||
@@ -405,6 +408,7 @@ class MessagesView extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Don't use React.createRef as the ref.current is not available in componentDidMount in this component.
|
||||||
handleScrollReference(node) {
|
handleScrollReference(node) {
|
||||||
if (node) {
|
if (node) {
|
||||||
node.addEventListener('scroll', this.handleScrollEvent);
|
node.addEventListener('scroll', this.handleScrollEvent);
|
||||||
@@ -413,9 +417,14 @@ class MessagesView extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get older messages
|
// Get older messages and show/hide [go to latest message] button.
|
||||||
handleScrollEvent(event) {
|
handleScrollEvent(event) {
|
||||||
this.setState({scrollPosition: event.target.scrollHeight - event.target.scrollTop});
|
const pos = event.target.scrollHeight - event.target.scrollTop - event.target.offsetHeight;
|
||||||
|
this.setState({
|
||||||
|
scrollPosition: pos,
|
||||||
|
showGoToLastButton: pos > SHOW_GO_TO_LAST_DIST,
|
||||||
|
});
|
||||||
|
|
||||||
if (this.state.fetchingMessages) {
|
if (this.state.fetchingMessages) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -432,6 +441,13 @@ class MessagesView extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
goToLatestMessage() {
|
||||||
|
this.setState({scrollPosition: 0});
|
||||||
|
if (this.messagesScroller) {
|
||||||
|
this.messagesScroller.scrollTop = this.messagesScroller.scrollHeight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
handleDescChange(desc) {
|
handleDescChange(desc) {
|
||||||
if (desc.public) {
|
if (desc.public) {
|
||||||
this.setState({
|
this.setState({
|
||||||
@@ -557,8 +573,12 @@ class MessagesView extends React.Component {
|
|||||||
// Scroll to the bottom if the message is added to the end of the message list.
|
// Scroll to the bottom if the message is added to the end of the message list.
|
||||||
// TODO: This should be replaced by showing a "scroll to bottom" button.
|
// TODO: This should be replaced by showing a "scroll to bottom" button.
|
||||||
if (topic.isNewMessage(msg.seq)) {
|
if (topic.isNewMessage(msg.seq)) {
|
||||||
|
if (this.state.scrollPosition > SHOW_GO_TO_LAST_DIST) {
|
||||||
|
this.setState({showGoToLastButton: true});
|
||||||
|
} else {
|
||||||
this.setState({scrollPosition: 0});
|
this.setState({scrollPosition: 0});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Aknowledge messages except own messages. They are
|
// Aknowledge messages except own messages. They are
|
||||||
// automatically assumed to be read and recived.
|
// automatically assumed to be read and recived.
|
||||||
@@ -1082,7 +1102,8 @@ class MessagesView extends React.Component {
|
|||||||
: null}
|
: null}
|
||||||
<LoadSpinner show={this.state.fetchingMessages} />
|
<LoadSpinner show={this.state.fetchingMessages} />
|
||||||
<div id="messages-container">
|
<div id="messages-container">
|
||||||
<button className="action-button">
|
<button className={'action-button' + (this.state.showGoToLastButton ? '' : ' hidden')}
|
||||||
|
onClick={this.goToLatestMessage}>
|
||||||
<i className="material-icons">arrow_downward</i>
|
<i className="material-icons">arrow_downward</i>
|
||||||
</button>
|
</button>
|
||||||
<div id="messages-panel" ref={this.handleScrollReference}>
|
<div id="messages-panel" ref={this.handleScrollReference}>
|
||||||
|
|||||||
+32
-11
@@ -3266,7 +3266,6 @@ __webpack_require__.r(__webpack_exports__);
|
|||||||
/* harmony import */ var _lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ../lib/blob-helpers.js */ "./src/lib/blob-helpers.js");
|
/* harmony import */ var _lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ../lib/blob-helpers.js */ "./src/lib/blob-helpers.js");
|
||||||
/* harmony import */ var _lib_navigation_js__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ../lib/navigation.js */ "./src/lib/navigation.js");
|
/* harmony import */ var _lib_navigation_js__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ../lib/navigation.js */ "./src/lib/navigation.js");
|
||||||
/* harmony import */ var _lib_strformat_js__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! ../lib/strformat.js */ "./src/lib/strformat.js");
|
/* harmony import */ var _lib_strformat_js__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! ../lib/strformat.js */ "./src/lib/strformat.js");
|
||||||
/* harmony import */ var _lib_utils_js__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! ../lib/utils.js */ "./src/lib/utils.js");
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -3286,8 +3285,8 @@ const Drafty = (tinode_sdk__WEBPACK_IMPORTED_MODULE_2___default().Drafty);
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const NOTIFICATION_EXEC_INTERVAL = 300;
|
const NOTIFICATION_EXEC_INTERVAL = 300;
|
||||||
|
const SHOW_GO_TO_LAST_DIST = 100;
|
||||||
const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({
|
const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({
|
||||||
online_now: {
|
online_now: {
|
||||||
id: "online_now",
|
id: "online_now",
|
||||||
@@ -3393,6 +3392,7 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
|||||||
this.handleCancelUpload = this.handleCancelUpload.bind(this);
|
this.handleCancelUpload = this.handleCancelUpload.bind(this);
|
||||||
this.postReadNotification = this.postReadNotification.bind(this);
|
this.postReadNotification = this.postReadNotification.bind(this);
|
||||||
this.clearNotificationQueue = this.clearNotificationQueue.bind(this);
|
this.clearNotificationQueue = this.clearNotificationQueue.bind(this);
|
||||||
|
this.goToLatestMessage = this.goToLatestMessage.bind(this);
|
||||||
this.handlePickReply = this.handlePickReply.bind(this);
|
this.handlePickReply = this.handlePickReply.bind(this);
|
||||||
this.handleCancelReply = this.handleCancelReply.bind(this);
|
this.handleCancelReply = this.handleCancelReply.bind(this);
|
||||||
this.handleQuoteClick = this.handleQuoteClick.bind(this);
|
this.handleQuoteClick = this.handleQuoteClick.bind(this);
|
||||||
@@ -3427,11 +3427,9 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate(prevProps, prevState) {
|
componentDidUpdate(prevProps, prevState) {
|
||||||
if (this.messagesScroller) {
|
if (this.messagesScroller && (prevState.topic != this.state.topic || prevState.messageCount != this.state.messageCount)) {
|
||||||
if (prevState.topic != this.state.topic || prevState.messageCount != this.state.messageCount) {
|
if (this.state.scrollPosition < SHOW_GO_TO_LAST_DIST) {
|
||||||
this.messagesScroller.scrollTop = this.messagesScroller.scrollHeight - this.state.scrollPosition;
|
this.messagesScroller.scrollTop = this.messagesScroller.scrollHeight - this.state.scrollPosition - this.messagesScroller.offsetHeight;
|
||||||
} else if (prevProps.viewportHeight > this.props.viewportHeight) {
|
|
||||||
this.messagesScroller.scrollTop += prevProps.viewportHeight - this.props.viewportHeight;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3485,7 +3483,8 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
|||||||
fetchingMessages: false,
|
fetchingMessages: false,
|
||||||
peerMessagingDisabled: false,
|
peerMessagingDisabled: false,
|
||||||
channel: false,
|
channel: false,
|
||||||
reply: null
|
reply: null,
|
||||||
|
showGoToLastButton: false
|
||||||
};
|
};
|
||||||
} else if (nextProps.topic != prevState.topic) {
|
} else if (nextProps.topic != prevState.topic) {
|
||||||
const topic = nextProps.tinode.getTopic(nextProps.topic);
|
const topic = nextProps.tinode.getTopic(nextProps.topic);
|
||||||
@@ -3508,7 +3507,8 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
|||||||
typingIndicator: false,
|
typingIndicator: false,
|
||||||
scrollPosition: 0,
|
scrollPosition: 0,
|
||||||
fetchingMessages: false,
|
fetchingMessages: false,
|
||||||
reply: reply
|
reply: reply,
|
||||||
|
showGoToLastButton: false
|
||||||
};
|
};
|
||||||
|
|
||||||
if (topic) {
|
if (topic) {
|
||||||
@@ -3692,8 +3692,10 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleScrollEvent(event) {
|
handleScrollEvent(event) {
|
||||||
|
const pos = event.target.scrollHeight - event.target.scrollTop - event.target.offsetHeight;
|
||||||
this.setState({
|
this.setState({
|
||||||
scrollPosition: event.target.scrollHeight - event.target.scrollTop
|
scrollPosition: pos,
|
||||||
|
showGoToLastButton: pos > SHOW_GO_TO_LAST_DIST
|
||||||
});
|
});
|
||||||
|
|
||||||
if (this.state.fetchingMessages) {
|
if (this.state.fetchingMessages) {
|
||||||
@@ -3715,6 +3717,16 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
goToLatestMessage() {
|
||||||
|
this.setState({
|
||||||
|
scrollPosition: 0
|
||||||
|
});
|
||||||
|
|
||||||
|
if (this.messagesScroller) {
|
||||||
|
this.messagesScroller.scrollTop = this.messagesScroller.scrollHeight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
handleDescChange(desc) {
|
handleDescChange(desc) {
|
||||||
if (desc.public) {
|
if (desc.public) {
|
||||||
this.setState({
|
this.setState({
|
||||||
@@ -3843,10 +3855,18 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (topic.isNewMessage(msg.seq)) {
|
if (topic.isNewMessage(msg.seq)) {
|
||||||
|
console.log("new message", this.state.scrollPosition, SHOW_GO_TO_LAST_DIST);
|
||||||
|
|
||||||
|
if (this.state.scrollPosition > SHOW_GO_TO_LAST_DIST) {
|
||||||
|
this.setState({
|
||||||
|
showGoToLastButton: true
|
||||||
|
});
|
||||||
|
} else {
|
||||||
this.setState({
|
this.setState({
|
||||||
scrollPosition: 0
|
scrollPosition: 0
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const status = topic.msgStatus(msg, true);
|
const status = topic.msgStatus(msg, true);
|
||||||
|
|
||||||
@@ -4412,7 +4432,8 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
|||||||
}), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
|
}), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
|
||||||
id: "messages-container"
|
id: "messages-container"
|
||||||
}, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", {
|
}, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", {
|
||||||
className: "action-button"
|
className: 'action-button' + (this.state.showGoToLastButton ? '' : ' hidden'),
|
||||||
|
onClick: this.goToLatestMessage
|
||||||
}, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", {
|
}, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", {
|
||||||
className: "material-icons"
|
className: "material-icons"
|
||||||
}, "arrow_downward")), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
|
}, "arrow_downward")), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user