Vulcan/packages/vulcan-embed/lib/components/EmbedURL.jsx

206 lines
6.2 KiB
React
Raw Normal View History

import { Components, registerComponent, Utils, getSetting } from 'meteor/vulcan:core';
2017-03-23 16:27:59 +09:00
import { withMutation } from 'meteor/vulcan:core';
2018-01-06 07:12:27 +01:00
import React, { Component } from 'react';
import PropTypes from 'prop-types';
2017-06-01 11:42:30 +09:00
import { FormattedMessage, intlShape } from 'meteor/vulcan:i18n';
2016-04-07 12:43:41 +09:00
import FRC from 'formsy-react-components';
2016-04-07 12:43:41 +09:00
const Input = FRC.Input;
2017-09-15 10:05:18 +02:00
class EmbedURL extends Component {
constructor(props) {
super(props);
2016-04-07 12:43:41 +09:00
this.state = {
loading: false,
value: props.value || '',
};
}
2018-03-29 11:58:05 +09:00
// clean the media property of the document if it exists: this field is handled server-side in an async callback
2018-03-29 11:58:05 +09:00
componentDidMount() {
try {
if (this.props.document && !_.isEmpty(this.props.document.media)) {
2018-03-29 11:58:05 +09:00
this.context.updateCurrentValues({ media: {} });
}
2018-03-29 11:58:05 +09:00
} catch (error) {
console.error('Error cleaning "media" property', error); // eslint-disable-line
2016-04-07 12:43:41 +09:00
}
}
2018-03-29 11:58:05 +09:00
editThumbnail = () => {
const newThumbnailUrl = prompt(
this.context.intl.formatMessage({ id: 'posts.enter_thumbnail_url' }),
this.context.getDocument().thumbnailUrl
);
if (newThumbnailUrl) {
2018-03-29 11:58:05 +09:00
this.context.updateCurrentValues({ thumbnailUrl: newThumbnailUrl });
}
2018-03-29 11:58:05 +09:00
};
2018-03-29 11:58:05 +09:00
clearThumbnail = () => {
if (confirm(this.context.intl.formatMessage({ id: 'posts.clear_thumbnail?' }))) {
this.context.updateCurrentValues({ thumbnailUrl: null });
}
2018-03-29 11:58:05 +09:00
};
2016-04-07 12:43:41 +09:00
// called whenever the URL input field loses focus
2018-03-29 11:58:05 +09:00
handleBlur = async () => {
try {
// value from formsy input ref
const url = this.input.getValue();
2018-03-29 11:58:05 +09:00
// start the mutation only if the input has a value
if (url.length) {
// notify the user that something happens
2018-03-29 11:58:05 +09:00
this.setState({ loading: true });
// the URL has changed, get new title, body, thumbnail & media for this url
2018-03-29 11:58:05 +09:00
const result = await this.props.getEmbedData({ url });
// uncomment for debug
2018-06-02 18:49:53 +09:00
// console.log('Embedly Data', result);
2018-03-29 11:58:05 +09:00
// extract the relevant data, for easier consumption
const { data: { getEmbedData: { title, description, thumbnailUrl } } } = result;
const body = description;
2018-03-29 11:58:05 +09:00
// update the form
if (title && !this.context.getDocument().title) {
2018-03-29 11:58:05 +09:00
this.context.updateCurrentValues({ title });
}
if (body && !this.context.getDocument().body) {
2018-03-29 11:58:05 +09:00
this.context.updateCurrentValues({ body });
}
if (thumbnailUrl && !this.context.getDocument().thumbnailUrl) {
2018-03-29 11:58:05 +09:00
this.context.updateCurrentValues({ thumbnailUrl });
}
2017-06-22 16:42:29 +09:00
// embedly component is done
2018-03-29 11:58:05 +09:00
this.setState({ loading: false });
// remove errors & keep the current values
// TODO: why??
// this.context.clearForm({clearErrors: true});
}
2018-03-29 11:58:05 +09:00
} catch (error) {
console.error(error); // eslint-disable-line
2018-03-29 11:58:05 +09:00
const errorMessage = error.message.includes('401')
? Utils.encodeIntlError({ id: 'app.embedly_not_authorized' })
: error.message;
// embedly component is done
2018-03-29 11:58:05 +09:00
this.setState({ loading: false });
// something bad happened
2018-03-29 11:58:05 +09:00
this.context.throwError({ id: 'embedurl.error_fetching_data', data: { name: this.props.path, message: errorMessage } });
2016-07-04 12:57:41 +09:00
}
2018-03-29 11:58:05 +09:00
};
2016-04-07 12:43:41 +09:00
2018-03-29 11:58:05 +09:00
getDimensions = () => {
const width = getSetting('thumbnailWidth', 80);
const height = getSetting('thumbnailHeight', 60);
2018-03-29 11:58:05 +09:00
const ratio = width / height;
return {
width,
height,
2018-03-29 11:58:05 +09:00
ratio,
};
};
renderThumbnail() {
return (
<div className="embedly-thumbnail">
2018-03-29 11:58:05 +09:00
<img className="embedly-thumbnail-image" src={this.context.getDocument().thumbnailUrl} />
<div className="embedly-thumbnail-actions">
2018-03-29 11:58:05 +09:00
<a className="thumbnail-edit" onClick={this.editThumbnail}>
<Components.Icon name="edit" /> <FormattedMessage id="posts.enter_thumbnail_url" />
</a>
<a className="thumbnail-clear" onClick={this.clearThumbnail}>
<Components.Icon name="delete" /> <FormattedMessage id="posts.clear_thumbnail" />
</a>
</div>
</div>
2018-03-29 11:58:05 +09:00
);
}
renderNoThumbnail() {
return (
<div className="embedly-thumbnail">
2018-03-29 11:58:05 +09:00
<div
2018-09-16 11:48:38 +09:00
style={{ width: `${Math.round(60 * this.getDimensions().ratio)}px`, height: '60px' }}
2018-03-29 11:58:05 +09:00
onClick={this.editThumbnail}
className="embedly-thumbnail-placeholder"
>
<Components.Icon name="image" />
2018-03-29 11:58:05 +09:00
<FormattedMessage id="posts.enter_thumbnail_url" />
</div>
</div>
2018-03-29 11:58:05 +09:00
);
}
2016-04-07 12:43:41 +09:00
render() {
const wrapperStyle = {
2018-03-29 11:58:05 +09:00
position: 'relative',
2016-04-07 12:43:41 +09:00
};
const loadingStyle = {
2018-03-29 11:58:05 +09:00
position: 'absolute',
pointerEvents: 'none',
top: '15px',
right: '15px',
2016-04-07 12:43:41 +09:00
};
2018-03-29 11:58:05 +09:00
loadingStyle.display = this.state.loading ? 'block' : 'none';
// see https://facebook.github.io/react/warnings/unknown-prop.html
2018-03-29 11:58:05 +09:00
const { document, control, getEmbedData, refFunction, inputProperties } = this.props; // eslint-disable-line
2016-04-07 12:43:41 +09:00
return (
<div className="form-group row embedly-form-group" style={wrapperStyle}>
<label className="control-label col-sm-3">{this.props.label}</label>
<div className="col-sm-9 embedly-form-control">
<div className="embedly-url-field">
<Input
2018-03-29 11:58:05 +09:00
{...inputProperties}
onBlur={this.handleBlur}
2017-06-22 16:42:29 +09:00
type="url"
2018-03-29 11:58:05 +09:00
ref={ref => (this.input = ref)}
layout="elementOnly"
/>
<div className="embedly-url-field-loading" style={loadingStyle}>
<Components.Loading />
</div>
</div>
2018-03-29 11:58:05 +09:00
{this.context.getDocument().thumbnailUrl ? this.renderThumbnail() : this.renderNoThumbnail()}
</div>
2016-04-07 12:43:41 +09:00
</div>
);
}
}
2017-09-15 10:05:18 +02:00
EmbedURL.propTypes = {
name: PropTypes.string,
value: PropTypes.any,
2018-03-29 11:58:05 +09:00
label: PropTypes.string,
};
2016-04-07 12:43:41 +09:00
2017-09-15 10:05:18 +02:00
EmbedURL.contextTypes = {
updateCurrentValues: PropTypes.func,
addToDeletedValues: PropTypes.func,
throwError: PropTypes.func,
clearForm: PropTypes.func,
getDocument: PropTypes.func,
2018-03-29 11:58:05 +09:00
intl: intlShape,
};
2016-04-07 12:43:41 +09:00
const options = {
name: 'getEmbedData',
2018-03-29 11:58:05 +09:00
args: { url: 'String' },
};
2017-09-15 10:05:18 +02:00
export default withMutation(options)(EmbedURL);
2018-03-29 11:58:05 +09:00
registerComponent('EmbedURL', EmbedURL, [withMutation, options]);