{ancestors}
diff --git a/app/javascript/mastodon/features/ui/components/audio_modal.js b/app/javascript/mastodon/features/ui/components/audio_modal.js
index 0676bd9cf..c46fefce8 100644
--- a/app/javascript/mastodon/features/ui/components/audio_modal.js
+++ b/app/javascript/mastodon/features/ui/components/audio_modal.js
@@ -4,7 +4,6 @@ import PropTypes from 'prop-types';
import Audio from 'mastodon/features/audio';
import { connect } from 'react-redux';
import ImmutablePureComponent from 'react-immutable-pure-component';
-import { previewState } from './video_modal';
import Footer from 'mastodon/features/picture_in_picture/components/footer';
const mapStateToProps = (state, { statusId }) => ({
@@ -25,32 +24,6 @@ class AudioModal extends ImmutablePureComponent {
onChangeBackgroundColor: PropTypes.func.isRequired,
};
- static contextTypes = {
- router: PropTypes.object,
- };
-
- componentDidMount () {
- if (this.context.router) {
- const history = this.context.router.history;
-
- history.push(history.location.pathname, previewState);
-
- this.unlistenHistory = history.listen(() => {
- this.props.onClose();
- });
- }
- }
-
- componentWillUnmount () {
- if (this.context.router) {
- this.unlistenHistory();
-
- if (this.context.router.history.location.state === previewState) {
- this.context.router.history.goBack();
- }
- }
- }
-
render () {
const { media, accountStaticAvatar, statusId, onClose } = this.props;
const options = this.props.options || {};
diff --git a/app/javascript/mastodon/features/ui/components/boost_modal.js b/app/javascript/mastodon/features/ui/components/boost_modal.js
index 83229833b..f8a344690 100644
--- a/app/javascript/mastodon/features/ui/components/boost_modal.js
+++ b/app/javascript/mastodon/features/ui/components/boost_modal.js
@@ -68,7 +68,7 @@ class BoostModal extends ImmutablePureComponent {
if (e.button === 0 && !(e.ctrlKey || e.metaKey)) {
e.preventDefault();
this.props.onClose();
- this.context.router.history.push(`/accounts/${this.props.status.getIn(['account', 'id'])}`);
+ this.context.router.history.push(`/@${this.props.status.getIn(['account', 'acct'])}`);
}
}
diff --git a/app/javascript/mastodon/features/ui/components/columns_area.js b/app/javascript/mastodon/features/ui/components/columns_area.js
index 039abe432..193637113 100644
--- a/app/javascript/mastodon/features/ui/components/columns_area.js
+++ b/app/javascript/mastodon/features/ui/components/columns_area.js
@@ -53,7 +53,7 @@ const messages = defineMessages({
publish: { id: 'compose_form.publish', defaultMessage: 'Toot' },
});
-const shouldHideFAB = path => path.match(/^\/statuses\/|^\/search|^\/getting-started|^\/start/);
+const shouldHideFAB = path => path.match(/^\/statuses\/|^\/@[^/]+\/\d+|^\/publish|^\/search|^\/getting-started|^\/start/);
export default @(component => injectIntl(component, { withRef: true }))
class ColumnsArea extends ImmutablePureComponent {
@@ -216,7 +216,7 @@ class ColumnsArea extends ImmutablePureComponent {
const columnIndex = getIndex(this.context.router.history.location.pathname);
if (singleColumn) {
- const floatingActionButton = shouldHideFAB(this.context.router.history.location.pathname) ? null : ;
+ const floatingActionButton = shouldHideFAB(this.context.router.history.location.pathname) ? null : ;
const content = columnIndex !== -1 ? (
diff --git a/app/javascript/mastodon/features/ui/components/confirmation_modal.js b/app/javascript/mastodon/features/ui/components/confirmation_modal.js
index 1227fa453..65d97ca16 100644
--- a/app/javascript/mastodon/features/ui/components/confirmation_modal.js
+++ b/app/javascript/mastodon/features/ui/components/confirmation_modal.js
@@ -13,15 +13,22 @@ class ConfirmationModal extends React.PureComponent {
onConfirm: PropTypes.func.isRequired,
secondary: PropTypes.string,
onSecondary: PropTypes.func,
+ closeWhenConfirm: PropTypes.bool,
intl: PropTypes.object.isRequired,
};
+ static defaultProps = {
+ closeWhenConfirm: true,
+ };
+
componentDidMount() {
this.button.focus();
}
handleClick = () => {
- this.props.onClose();
+ if (this.props.closeWhenConfirm) {
+ this.props.onClose();
+ }
this.props.onConfirm();
}
diff --git a/app/javascript/mastodon/features/ui/components/focal_point_modal.js b/app/javascript/mastodon/features/ui/components/focal_point_modal.js
index 3457b7633..a2e6b3d16 100644
--- a/app/javascript/mastodon/features/ui/components/focal_point_modal.js
+++ b/app/javascript/mastodon/features/ui/components/focal_point_modal.js
@@ -4,7 +4,7 @@ import PropTypes from 'prop-types';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { connect } from 'react-redux';
import classNames from 'classnames';
-import { changeUploadCompose, uploadThumbnail } from '../../../actions/compose';
+import { changeUploadCompose, uploadThumbnail, onChangeMediaDescription, onChangeMediaFocus } from '../../../actions/compose';
import { getPointerPosition } from '../../video';
import { FormattedMessage, defineMessages, injectIntl } from 'react-intl';
import IconButton from 'mastodon/components/icon_button';
@@ -27,14 +27,22 @@ import { assetHost } from 'mastodon/utils/config';
const messages = defineMessages({
close: { id: 'lightbox.close', defaultMessage: 'Close' },
apply: { id: 'upload_modal.apply', defaultMessage: 'Apply' },
+ applying: { id: 'upload_modal.applying', defaultMessage: 'Applying…' },
placeholder: { id: 'upload_modal.description_placeholder', defaultMessage: 'A quick brown fox jumps over the lazy dog' },
chooseImage: { id: 'upload_modal.choose_image', defaultMessage: 'Choose image' },
+ discardMessage: { id: 'confirmations.discard_edit_media.message', defaultMessage: 'You have unsaved changes to the media description or preview, discard them anyway?' },
+ discardConfirm: { id: 'confirmations.discard_edit_media.confirm', defaultMessage: 'Discard' },
});
const mapStateToProps = (state, { id }) => ({
media: state.getIn(['compose', 'media_attachments']).find(item => item.get('id') === id),
account: state.getIn(['accounts', me]),
isUploadingThumbnail: state.getIn(['compose', 'isUploadingThumbnail']),
+ description: state.getIn(['compose', 'media_modal', 'description']),
+ focusX: state.getIn(['compose', 'media_modal', 'focusX']),
+ focusY: state.getIn(['compose', 'media_modal', 'focusY']),
+ dirty: state.getIn(['compose', 'media_modal', 'dirty']),
+ is_changing_upload: state.getIn(['compose', 'is_changing_upload']),
});
const mapDispatchToProps = (dispatch, { id }) => ({
@@ -43,6 +51,14 @@ const mapDispatchToProps = (dispatch, { id }) => ({
dispatch(changeUploadCompose(id, { description, focus: `${x.toFixed(2)},${y.toFixed(2)}` }));
},
+ onChangeDescription: (description) => {
+ dispatch(onChangeMediaDescription(description));
+ },
+
+ onChangeFocus: (focusX, focusY) => {
+ dispatch(onChangeMediaFocus(focusX, focusY));
+ },
+
onSelectThumbnail: files => {
dispatch(uploadThumbnail(id, files[0]));
},
@@ -83,8 +99,8 @@ class ImageLoader extends React.PureComponent {
}
-export default @connect(mapStateToProps, mapDispatchToProps)
-@injectIntl
+export default @connect(mapStateToProps, mapDispatchToProps, null, { forwardRef: true })
+@(component => injectIntl(component, { withRef: true }))
class FocalPointModal extends ImmutablePureComponent {
static propTypes = {
@@ -92,34 +108,21 @@ class FocalPointModal extends ImmutablePureComponent {
account: ImmutablePropTypes.map.isRequired,
isUploadingThumbnail: PropTypes.bool,
onSave: PropTypes.func.isRequired,
+ onChangeDescription: PropTypes.func.isRequired,
+ onChangeFocus: PropTypes.func.isRequired,
onSelectThumbnail: PropTypes.func.isRequired,
onClose: PropTypes.func.isRequired,
intl: PropTypes.object.isRequired,
};
state = {
- x: 0,
- y: 0,
- focusX: 0,
- focusY: 0,
dragging: false,
- description: '',
dirty: false,
progress: 0,
loading: true,
ocrStatus: '',
};
- componentWillMount () {
- this.updatePositionFromMedia(this.props.media);
- }
-
- componentWillReceiveProps (nextProps) {
- if (this.props.media.get('id') !== nextProps.media.get('id')) {
- this.updatePositionFromMedia(nextProps.media);
- }
- }
-
componentWillUnmount () {
document.removeEventListener('mousemove', this.handleMouseMove);
document.removeEventListener('mouseup', this.handleMouseUp);
@@ -164,54 +167,37 @@ class FocalPointModal extends ImmutablePureComponent {
const focusX = (x - .5) * 2;
const focusY = (y - .5) * -2;
- this.setState({ x, y, focusX, focusY, dirty: true });
- }
-
- updatePositionFromMedia = media => {
- const focusX = media.getIn(['meta', 'focus', 'x']);
- const focusY = media.getIn(['meta', 'focus', 'y']);
- const description = media.get('description') || '';
-
- if (focusX && focusY) {
- const x = (focusX / 2) + .5;
- const y = (focusY / -2) + .5;
-
- this.setState({
- x,
- y,
- focusX,
- focusY,
- description,
- dirty: false,
- });
- } else {
- this.setState({
- x: 0.5,
- y: 0.5,
- focusX: 0,
- focusY: 0,
- description,
- dirty: false,
- });
- }
+ this.props.onChangeFocus(focusX, focusY);
}
handleChange = e => {
- this.setState({ description: e.target.value, dirty: true });
+ this.props.onChangeDescription(e.target.value);
}
handleKeyDown = (e) => {
if (e.keyCode === 13 && (e.ctrlKey || e.metaKey)) {
e.preventDefault();
e.stopPropagation();
- this.setState({ description: e.target.value, dirty: true });
+ this.props.onChangeDescription(e.target.value);
this.handleSubmit();
}
}
handleSubmit = () => {
- this.props.onSave(this.state.description, this.state.focusX, this.state.focusY);
- this.props.onClose();
+ this.props.onSave(this.props.description, this.props.focusX, this.props.focusY);
+ }
+
+ getCloseConfirmationMessage = () => {
+ const { intl, dirty } = this.props;
+
+ if (dirty) {
+ return {
+ message: intl.formatMessage(messages.discardMessage),
+ confirm: intl.formatMessage(messages.discardConfirm),
+ };
+ } else {
+ return null;
+ }
}
setRef = c => {
@@ -219,6 +205,10 @@ class FocalPointModal extends ImmutablePureComponent {
}
handleTextDetection = () => {
+ this._detectText();
+ }
+
+ _detectText = (refreshCache = false) => {
const { media } = this.props;
this.setState({ detecting: true });
@@ -235,6 +225,7 @@ class FocalPointModal extends ImmutablePureComponent {
this.setState({ ocrStatus: 'preparing', progress });
}
},
+ cacheMethod: refreshCache ? 'refresh' : 'write',
});
let media_url = media.get('url');
@@ -247,14 +238,21 @@ class FocalPointModal extends ImmutablePureComponent {
}
}
- (async () => {
+ return (async () => {
await worker.load();
await worker.loadLanguage('eng');
await worker.initialize('eng');
const { data: { text } } = await worker.recognize(media_url);
- this.setState({ description: removeExtraLineBreaks(text), dirty: true, detecting: false });
+ this.setState({ detecting: false });
+ this.props.onChangeDescription(removeExtraLineBreaks(text));
await worker.terminate();
- })();
+ })().catch((e) => {
+ if (refreshCache) {
+ throw e;
+ } else {
+ this._detectText(true);
+ }
+ });
}).catch((e) => {
console.error(e);
this.setState({ detecting: false });
@@ -263,7 +261,6 @@ class FocalPointModal extends ImmutablePureComponent {
handleThumbnailChange = e => {
if (e.target.files.length > 0) {
- this.setState({ dirty: true });
this.props.onSelectThumbnail(e.target.files);
}
}
@@ -277,8 +274,10 @@ class FocalPointModal extends ImmutablePureComponent {
}
render () {
- const { media, intl, account, onClose, isUploadingThumbnail } = this.props;
- const { x, y, dragging, description, dirty, detecting, progress, ocrStatus } = this.state;
+ const { media, intl, account, onClose, isUploadingThumbnail, description, focusX, focusY, dirty, is_changing_upload } = this.props;
+ const { dragging, detecting, progress, ocrStatus } = this.state;
+ const x = (focusX / 2) + .5;
+ const y = (focusY / -2) + .5;
const width = media.getIn(['meta', 'original', 'width']) || null;
const height = media.getIn(['meta', 'original', 'height']) || null;
@@ -333,7 +332,7 @@ class FocalPointModal extends ImmutablePureComponent {
accept='image/png,image/jpeg'
onChange={this.handleThumbnailChange}
style={{ display: 'none' }}
- disabled={isUploadingThumbnail}
+ disabled={isUploadingThumbnail || is_changing_upload}
/>
@@ -352,7 +351,7 @@ class FocalPointModal extends ImmutablePureComponent {
value={detecting ? '…' : description}
onChange={this.handleChange}
onKeyDown={this.handleKeyDown}
- disabled={detecting}
+ disabled={detecting || is_changing_upload}
autoFocus
/>
@@ -362,11 +361,11 @@ class FocalPointModal extends ImmutablePureComponent {
-
+
-