diff --git a/app/javascript/mastodon/features/follow_requests/components/account_authorize.js b/app/javascript/mastodon/features/follow_requests/components/account_authorize.js
index 66fa5c235c6..4fc5638d957 100644
--- a/app/javascript/mastodon/features/follow_requests/components/account_authorize.js
+++ b/app/javascript/mastodon/features/follow_requests/components/account_authorize.js
@@ -4,7 +4,6 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import Permalink from '../../../components/permalink';
import Avatar from '../../../components/avatar';
import DisplayName from '../../../components/display_name';
-import emojify from '../../../emoji';
import IconButton from '../../../components/icon_button';
import { defineMessages, injectIntl } from 'react-intl';
import ImmutablePureComponent from 'react-immutable-pure-component';
@@ -26,7 +25,7 @@ export default class AccountAuthorize extends ImmutablePureComponent {
render () {
const { intl, account, onAuthorize, onReject } = this.props;
- const content = { __html: emojify(account.get('note')) };
+ const content = { __html: account.get('note_emojified') };
return (
diff --git a/app/javascript/mastodon/features/notifications/components/notification.js b/app/javascript/mastodon/features/notifications/components/notification.js
index 9d631644a02..2992185fd1e 100644
--- a/app/javascript/mastodon/features/notifications/components/notification.js
+++ b/app/javascript/mastodon/features/notifications/components/notification.js
@@ -4,8 +4,6 @@ import StatusContainer from '../../../containers/status_container';
import AccountContainer from '../../../containers/account_container';
import { FormattedMessage } from 'react-intl';
import Permalink from '../../../components/permalink';
-import emojify from '../../../emoji';
-import escapeTextContentForBrowser from 'escape-html';
import ImmutablePureComponent from 'react-immutable-pure-component';
export default class Notification extends ImmutablePureComponent {
@@ -67,9 +65,8 @@ export default class Notification extends ImmutablePureComponent {
render () {
const { notification } = this.props;
const account = notification.get('account');
- const displayName = account.get('display_name').length > 0 ? account.get('display_name') : account.get('username');
- const displayNameHTML = { __html: emojify(escapeTextContentForBrowser(displayName)) };
- const link =
;
+ const displayNameHtml = { __html: account.get('display_name_html') };
+ const link =
;
switch(notification.get('type')) {
case 'follow':
diff --git a/app/javascript/mastodon/features/report/components/status_check_box.js b/app/javascript/mastodon/features/report/components/status_check_box.js
index 6a1a84c28c0..cc92322011a 100644
--- a/app/javascript/mastodon/features/report/components/status_check_box.js
+++ b/app/javascript/mastodon/features/report/components/status_check_box.js
@@ -1,7 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
-import emojify from '../../../emoji';
import Toggle from 'react-toggle';
export default class StatusCheckBox extends React.PureComponent {
@@ -15,7 +14,7 @@ export default class StatusCheckBox extends React.PureComponent {
render () {
const { status, checked, onToggle, disabled } = this.props;
- const content = { __html: emojify(status.get('content')) };
+ const content = { __html: status.get('contentHtml') };
if (status.get('reblog')) {
return null;
diff --git a/app/javascript/mastodon/features/ui/index.js b/app/javascript/mastodon/features/ui/index.js
index b6307dd4cf1..a791f894739 100644
--- a/app/javascript/mastodon/features/ui/index.js
+++ b/app/javascript/mastodon/features/ui/index.js
@@ -12,6 +12,7 @@ import { debounce } from 'lodash';
import { uploadCompose } from '../../actions/compose';
import { refreshHomeTimeline } from '../../actions/timelines';
import { refreshNotifications } from '../../actions/notifications';
+import { clearStatusesHeight } from '../../actions/statuses';
import { WrappedSwitch, WrappedRoute } from './util/react_router_helpers';
import UploadArea from './components/upload_area';
import ColumnsAreaContainer from './containers/columns_area_container';
@@ -66,6 +67,9 @@ export default class UI extends React.PureComponent {
};
handleResize = debounce(() => {
+ // The cached heights are no longer accurate, invalidate
+ this.props.dispatch(clearStatusesHeight());
+
this.setState({ width: window.innerWidth });
}, 500, {
trailing: true,
diff --git a/app/javascript/mastodon/reducers/accounts.js b/app/javascript/mastodon/reducers/accounts.js
index 4d7c3adc972..6442d13bef9 100644
--- a/app/javascript/mastodon/reducers/accounts.js
+++ b/app/javascript/mastodon/reducers/accounts.js
@@ -44,7 +44,9 @@ import {
FAVOURITED_STATUSES_EXPAND_SUCCESS,
} from '../actions/favourites';
import { STORE_HYDRATE } from '../actions/store';
+import emojify from '../emoji';
import { Map as ImmutableMap, fromJS } from 'immutable';
+import escapeTextContentForBrowser from 'escape-html';
const normalizeAccount = (state, account) => {
account = { ...account };
@@ -53,6 +55,10 @@ const normalizeAccount = (state, account) => {
delete account.following_count;
delete account.statuses_count;
+ const displayName = account.display_name.length === 0 ? account.username : account.display_name;
+ account.display_name_html = emojify(escapeTextContentForBrowser(displayName));
+ account.note_emojified = emojify(account.note);
+
return state.set(account.id, fromJS(account));
};
diff --git a/app/javascript/mastodon/reducers/statuses.js b/app/javascript/mastodon/reducers/statuses.js
index b1b1d0988e2..3e40b0b424f 100644
--- a/app/javascript/mastodon/reducers/statuses.js
+++ b/app/javascript/mastodon/reducers/statuses.js
@@ -13,6 +13,8 @@ import {
CONTEXT_FETCH_SUCCESS,
STATUS_MUTE_SUCCESS,
STATUS_UNMUTE_SUCCESS,
+ STATUS_SET_HEIGHT,
+ STATUSES_CLEAR_HEIGHT,
} from '../actions/statuses';
import {
TIMELINE_REFRESH_SUCCESS,
@@ -33,7 +35,11 @@ import {
FAVOURITED_STATUSES_EXPAND_SUCCESS,
} from '../actions/favourites';
import { SEARCH_FETCH_SUCCESS } from '../actions/search';
+import emojify from '../emoji';
import { Map as ImmutableMap, fromJS } from 'immutable';
+import escapeTextContentForBrowser from 'escape-html';
+
+const domParser = new DOMParser();
const normalizeStatus = (state, status) => {
if (!status) {
@@ -49,7 +55,9 @@ const normalizeStatus = (state, status) => {
}
const searchContent = [status.spoiler_text, status.content].join(' ').replace(/
/g, '\n').replace(/<\/p>
/g, '\n\n');
- normalStatus.search_index = new DOMParser().parseFromString(searchContent, 'text/html').documentElement.textContent;
+ normalStatus.search_index = domParser.parseFromString(searchContent, 'text/html').documentElement.textContent;
+ normalStatus.contentHtml = emojify(normalStatus.content);
+ normalStatus.spoilerHtml = emojify(escapeTextContentForBrowser(normalStatus.spoiler_text || ''));
return state.update(status.id, ImmutableMap(), map => map.mergeDeep(fromJS(normalStatus)));
};
@@ -82,6 +90,18 @@ const filterStatuses = (state, relationship) => {
return state;
};
+const setHeight = (state, id, height) => {
+ return state.update(id, ImmutableMap(), map => map.set('height', height));
+};
+
+const clearHeights = (state) => {
+ state.forEach(status => {
+ state = state.deleteIn([status.get('id'), 'height']);
+ });
+
+ return state;
+};
+
const initialState = ImmutableMap();
export default function statuses(state = initialState, action) {
@@ -120,6 +140,10 @@ export default function statuses(state = initialState, action) {
return deleteStatus(state, action.id, action.references);
case ACCOUNT_BLOCK_SUCCESS:
return filterStatuses(state, action.relationship);
+ case STATUS_SET_HEIGHT:
+ return setHeight(state, action.id, action.height);
+ case STATUSES_CLEAR_HEIGHT:
+ return clearHeights(state);
default:
return state;
}
diff --git a/app/javascript/styles/components.scss b/app/javascript/styles/components.scss
index 9174f51124b..77b06b2d0da 100644
--- a/app/javascript/styles/components.scss
+++ b/app/javascript/styles/components.scss
@@ -1572,7 +1572,6 @@
overflow-y: scroll;
overflow-x: hidden;
flex: 1 1 auto;
- backface-visibility: hidden;
-webkit-overflow-scrolling: touch;
@supports(display: grid) { // hack to fix Chrome <57
contain: strict;
diff --git a/spec/javascript/components/display_name.test.js b/spec/javascript/components/display_name.test.js
index ad9288d4dfc..ab484cf3e29 100644
--- a/spec/javascript/components/display_name.test.js
+++ b/spec/javascript/components/display_name.test.js
@@ -9,19 +9,9 @@ describe('', () => {
const account = fromJS({
username: 'bar',
acct: 'bar@baz',
- display_name: 'Foo',
+ display_name_html: '
Foo
',
});
const wrapper = render(
);
expect(wrapper).to.have.text('Foo @bar@baz');
});
-
- it('renders the username + account name if display name is empty', () => {
- const account = fromJS({
- username: 'bar',
- acct: 'bar@baz',
- display_name: '',
- });
- const wrapper = render(
);
- expect(wrapper).to.have.text('bar @bar@baz');
- });
});