aboutsummaryrefslogtreecommitdiff
path: root/app/javascript/mastodon/features/compose/components/upload.js
diff options
context:
space:
mode:
authorEugen Rochko <eugen@zeonfederated.com>2017-09-28 15:31:31 +0200
committerGitHub <noreply@github.com>2017-09-28 15:31:31 +0200
commit4ec1771165ab8dd40e52804fd087eacfab25290b (patch)
treee356a5477ee1790367a9b8981fdf5f6419540f88 /app/javascript/mastodon/features/compose/components/upload.js
parent3d9b8847d21d886886baae483304288139669795 (diff)
downloadmastodon-4ec1771165ab8dd40e52804fd087eacfab25290b.tar
mastodon-4ec1771165ab8dd40e52804fd087eacfab25290b.tar.gz
mastodon-4ec1771165ab8dd40e52804fd087eacfab25290b.tar.bz2
mastodon-4ec1771165ab8dd40e52804fd087eacfab25290b.zip
Add ability to specify alternative text for media attachments (#5123)
* Fix #117 - Add ability to specify alternative text for media attachments - POST /api/v1/media accepts `description` straight away - PUT /api/v1/media/:id to update `description` (only for unattached ones) - Serialized as `name` of Document object in ActivityPub - Uploads form adjusted for better performance and description input * Add tests * Change undo button blend mode to difference
Diffstat (limited to 'app/javascript/mastodon/features/compose/components/upload.js')
-rw-r--r--app/javascript/mastodon/features/compose/components/upload.js96
1 files changed, 96 insertions, 0 deletions
diff --git a/app/javascript/mastodon/features/compose/components/upload.js b/app/javascript/mastodon/features/compose/components/upload.js
new file mode 100644
index 000000000..c2bf3b72e
--- /dev/null
+++ b/app/javascript/mastodon/features/compose/components/upload.js
@@ -0,0 +1,96 @@
+import React from 'react';
+import ImmutablePropTypes from 'react-immutable-proptypes';
+import PropTypes from 'prop-types';
+import IconButton from '../../../components/icon_button';
+import Motion from 'react-motion/lib/Motion';
+import spring from 'react-motion/lib/spring';
+import ImmutablePureComponent from 'react-immutable-pure-component';
+import { defineMessages, injectIntl } from 'react-intl';
+import classNames from 'classnames';
+
+const messages = defineMessages({
+ undo: { id: 'upload_form.undo', defaultMessage: 'Undo' },
+ description: { id: 'upload_form.description', defaultMessage: 'Describe for the visually impaired' },
+});
+
+@injectIntl
+export default class Upload extends ImmutablePureComponent {
+
+ static propTypes = {
+ media: ImmutablePropTypes.map.isRequired,
+ intl: PropTypes.object.isRequired,
+ onUndo: PropTypes.func.isRequired,
+ onDescriptionChange: PropTypes.func.isRequired,
+ };
+
+ state = {
+ hovered: false,
+ focused: false,
+ dirtyDescription: null,
+ };
+
+ handleUndoClick = () => {
+ this.props.onUndo(this.props.media.get('id'));
+ }
+
+ handleInputChange = e => {
+ this.setState({ dirtyDescription: e.target.value });
+ }
+
+ handleMouseEnter = () => {
+ this.setState({ hovered: true });
+ }
+
+ handleMouseLeave = () => {
+ this.setState({ hovered: false });
+ }
+
+ handleInputFocus = () => {
+ this.setState({ focused: true });
+ }
+
+ handleInputBlur = () => {
+ const { dirtyDescription } = this.state;
+
+ this.setState({ focused: false, dirtyDescription: null });
+
+ if (dirtyDescription !== null) {
+ this.props.onDescriptionChange(this.props.media.get('id'), dirtyDescription);
+ }
+ }
+
+ render () {
+ const { intl, media } = this.props;
+ const active = this.state.hovered || this.state.focused;
+ const description = this.state.dirtyDescription || media.get('description') || '';
+
+ return (
+ <div className='compose-form__upload' onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave}>
+ <Motion defaultStyle={{ scale: 0.8 }} style={{ scale: spring(1, { stiffness: 180, damping: 12 }) }}>
+ {({ scale }) => (
+ <div className='compose-form__upload-thumbnail' style={{ transform: `translateZ(0) scale(${scale})`, backgroundImage: `url(${media.get('preview_url')})` }}>
+ <IconButton icon='times' title={intl.formatMessage(messages.undo)} size={36} onClick={this.handleUndoClick} />
+
+ <div className={classNames('compose-form__upload-description', { active })}>
+ <label>
+ <span style={{ display: 'none' }}>{intl.formatMessage(messages.description)}</span>
+
+ <input
+ placeholder={intl.formatMessage(messages.description)}
+ type='text'
+ value={description}
+ maxLength={140}
+ onFocus={this.handleInputFocus}
+ onChange={this.handleInputChange}
+ onBlur={this.handleInputBlur}
+ />
+ </label>
+ </div>
+ </div>
+ )}
+ </Motion>
+ </div>
+ );
+ }
+
+}