mirror of
https://github.com/vale981/Vulcan
synced 2025-03-06 10:01:40 -05:00
integrate Embedly thumbnail inside EmbedlyURL component (not using ThumbnailURL anymore)
This commit is contained in:
parent
f9148219cc
commit
6cff2b19fd
8 changed files with 162 additions and 39 deletions
|
@ -1,6 +1,7 @@
|
|||
import { Components, registerComponent, Utils } from 'meteor/vulcan:core';
|
||||
import { Components, registerComponent, Utils, getSetting } from 'meteor/vulcan:core';
|
||||
import { withMutation } from 'meteor/vulcan:core';
|
||||
import React, { PropTypes, Component } from 'react';
|
||||
import { FormattedMessage, intlShape } from 'react-intl';
|
||||
import FRC from 'formsy-react-components';
|
||||
|
||||
const Input = FRC.Input;
|
||||
|
@ -10,10 +11,13 @@ class EmbedlyURL extends Component {
|
|||
constructor(props) {
|
||||
super(props);
|
||||
this.handleBlur = this.handleBlur.bind(this);
|
||||
|
||||
this.editThumbnail = this.editThumbnail.bind(this);
|
||||
this.clearThumbnail = this.clearThumbnail.bind(this);
|
||||
|
||||
this.state = {
|
||||
loading: false,
|
||||
value: props.value || '',
|
||||
thumbnailUrl: props.document.thumbnailUrl || ''
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -28,6 +32,22 @@ class EmbedlyURL extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
editThumbnail() {
|
||||
const newThumbnailUrl = prompt(this.context.intl.formatMessage({id: 'posts.enter_thumbnail_url'}), this.state.thumbnailUrl);
|
||||
if (newThumbnailUrl) {
|
||||
this.setState({thumbnailUrl: newThumbnailUrl});
|
||||
// this.context.updateCurrentValues({thumbnailUrl: newThumbnailUrl});
|
||||
}
|
||||
}
|
||||
|
||||
clearThumbnail() {
|
||||
if (confirm(this.context.intl.formatMessage({id: 'posts.clear_thumbnail?'}))) {
|
||||
this.setState({thumbnailUrl: ''});
|
||||
this.context.addToDeletedValues('thumbnailUrl');
|
||||
// this.context.updateCurrentValues({thumbnailUrl: ''});
|
||||
}
|
||||
}
|
||||
|
||||
// called whenever the URL input field loses focus
|
||||
async handleBlur() {
|
||||
try {
|
||||
|
@ -48,16 +68,16 @@ class EmbedlyURL extends Component {
|
|||
|
||||
// extract the relevant data, for easier consumption
|
||||
const { data: { getEmbedlyData: { title, description, thumbnailUrl } } } = result;
|
||||
|
||||
|
||||
// update the form
|
||||
await this.context.updateCurrentValues({
|
||||
title: title || "",
|
||||
body: description || "",
|
||||
thumbnailUrl: thumbnailUrl || "",
|
||||
// thumbnailUrl: thumbnailUrl || "",
|
||||
});
|
||||
|
||||
// embedly component is done
|
||||
await this.setState({loading: false});
|
||||
await this.setState({loading: false, thumbnailUrl});
|
||||
|
||||
// remove errors & keep the current values
|
||||
await this.context.clearForm({clearErrors: true});
|
||||
|
@ -75,6 +95,40 @@ class EmbedlyURL extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
getDimensions() {
|
||||
const width = getSetting('thumbnailWidth', 80);
|
||||
const height = getSetting('thumbnailHeight', 60);
|
||||
const ratio = width/height;
|
||||
return {
|
||||
width,
|
||||
height,
|
||||
ratio
|
||||
}
|
||||
}
|
||||
|
||||
renderThumbnail() {
|
||||
return (
|
||||
<div className="embedly-thumbnail">
|
||||
<img className="embedly-thumbnail-image" src={this.state.thumbnailUrl} />
|
||||
<div className="embedly-thumbnail-actions">
|
||||
<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>
|
||||
)
|
||||
}
|
||||
|
||||
renderNoThumbnail() {
|
||||
return (
|
||||
<div className="embedly-thumbnail">
|
||||
<div style={{width: `${Math.round(60 * this.getDimensions().ratio)}px`, height: `60px`}} onClick={this.editThumbnail} className="embedly-thumbnail-placeholder">
|
||||
<Components.Icon name="image" />
|
||||
<FormattedMessage id="posts.enter_thumbnail_url"/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
const wrapperStyle = {
|
||||
|
@ -94,15 +148,29 @@ class EmbedlyURL extends Component {
|
|||
const {document, control, getEmbedlyData, ...rest} = this.props; // eslint-disable-line
|
||||
|
||||
return (
|
||||
<div className="embedly-url-field" style={wrapperStyle}>
|
||||
<Input
|
||||
{...rest}
|
||||
onBlur={this.handleBlur}
|
||||
type="text"
|
||||
ref={ref => this.input = ref}
|
||||
/>
|
||||
<div className="embedly-url-field-loading" style={loadingStyle}>
|
||||
<Components.Loading />
|
||||
<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
|
||||
{...rest}
|
||||
onBlur={this.handleBlur}
|
||||
type="text"
|
||||
ref={ref => this.input = ref}
|
||||
layout="elementOnly"
|
||||
/>
|
||||
<div className="embedly-url-field-loading" style={loadingStyle}>
|
||||
<Components.Loading />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{this.state.thumbnailUrl ? this.renderThumbnail() : this.renderNoThumbnail()}
|
||||
|
||||
<Input
|
||||
type="hidden"
|
||||
name="thumbnailUrl"
|
||||
value={this.state.thumbnailUrl}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -117,8 +185,10 @@ EmbedlyURL.propTypes = {
|
|||
|
||||
EmbedlyURL.contextTypes = {
|
||||
updateCurrentValues: PropTypes.func,
|
||||
addToDeletedValues: PropTypes.func,
|
||||
throwError: PropTypes.func,
|
||||
clearForm: PropTypes.func,
|
||||
intl: intlShape
|
||||
}
|
||||
|
||||
export default withMutation({
|
||||
|
|
|
@ -29,15 +29,15 @@ class ThumbnailURL extends Component {
|
|||
renderThumbnail() {
|
||||
return (
|
||||
<div>
|
||||
<img
|
||||
className="embedly-thumbnail"
|
||||
src={this.props.value}
|
||||
style={{
|
||||
"width": 150,
|
||||
"height": getSetting('thumbnailHeight', 150) * 150 / getSetting('thumbnailWidth', 150)
|
||||
}}
|
||||
/>
|
||||
<a className="thumbnail-url-clear" onClick={this.clearThumbnail}><FormattedMessage id="posts.clear_thumbnail"/></a>
|
||||
<img
|
||||
className="embedly-thumbnail"
|
||||
src={this.props.value}
|
||||
style={{
|
||||
"width": 150,
|
||||
"height": getSetting('thumbnailHeight', 150) * 150 / getSetting('thumbnailWidth', 150)
|
||||
}}
|
||||
/>
|
||||
<a className="thumbnail-url-clear" onClick={this.clearThumbnail}><FormattedMessage id="posts.clear_thumbnail"/></a>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ Posts.addField([
|
|||
insertableBy: ['members'],
|
||||
editableBy: ['members'],
|
||||
viewableBy: ['guests'],
|
||||
control: ThumbnailURL
|
||||
hidden: true
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
|
@ -5,8 +5,8 @@ function getEmbedlyData(url) {
|
|||
var extractBase = 'http://api.embed.ly/1/extract';
|
||||
var embedlyKey = getSetting('embedlyKey');
|
||||
// 200 x 200 is the minimum size accepted by facebook
|
||||
var thumbnailWidth = getSetting('thumbnailWidth', 200);
|
||||
var thumbnailHeight = getSetting('thumbnailHeight', 200);
|
||||
var thumbnailWidth = getSetting('thumbnailWidth', 400);
|
||||
var thumbnailHeight = getSetting('thumbnailHeight', 300);
|
||||
|
||||
if(!embedlyKey) {
|
||||
// fail silently to still let the post be submitted as usual
|
||||
|
|
|
@ -1,9 +1,43 @@
|
|||
.embedly-thumbnail{
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
border: 3px solid #ddd;
|
||||
.embedly-form-control{
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.thumbnail-url-clear{
|
||||
.embedly-url-field{
|
||||
position: relative;
|
||||
flex: 1;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.embedly-thumbnail-placeholder{
|
||||
background: #eee;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
|
||||
.icon{
|
||||
display: block;
|
||||
color: rgba(0,0,0,0.5);
|
||||
}
|
||||
span{
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.embedly-thumbnail-image{
|
||||
height: 60px;
|
||||
width: auto;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.embedly-thumbnail-actions{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
.thumbnail-edit{
|
||||
margin-right: 5px;
|
||||
}
|
||||
span{
|
||||
display: none;
|
||||
}
|
||||
}
|
|
@ -58,6 +58,7 @@ class Form extends Component {
|
|||
this.mutationSuccessCallback = this.mutationSuccessCallback.bind(this);
|
||||
this.mutationErrorCallback = this.mutationErrorCallback.bind(this);
|
||||
this.addToAutofilledValues = this.addToAutofilledValues.bind(this);
|
||||
this.addToDeletedValues = this.addToDeletedValues.bind(this);
|
||||
this.throwError = this.throwError.bind(this);
|
||||
this.clearForm = this.clearForm.bind(this);
|
||||
this.updateCurrentValues = this.updateCurrentValues.bind(this);
|
||||
|
@ -71,6 +72,7 @@ class Form extends Component {
|
|||
disabled: false,
|
||||
errors: [],
|
||||
autofilledValues: props.prefilledProps || {},
|
||||
deletedValues: [],
|
||||
currentValues: {}
|
||||
};
|
||||
}
|
||||
|
@ -338,7 +340,7 @@ class Form extends Component {
|
|||
}));
|
||||
}
|
||||
|
||||
// add something to prefilled values
|
||||
// add something to autofilled values
|
||||
addToAutofilledValues(property) {
|
||||
this.setState(prevState => ({
|
||||
autofilledValues: {
|
||||
|
@ -348,6 +350,13 @@ class Form extends Component {
|
|||
}));
|
||||
}
|
||||
|
||||
// add something to deleted values
|
||||
addToDeletedValues(name) {
|
||||
this.setState(prevState => ({
|
||||
deletedValues: [...prevState.deletedValues, name]
|
||||
}));
|
||||
}
|
||||
|
||||
setFormState(fn) {
|
||||
this.setState(fn);
|
||||
}
|
||||
|
@ -359,6 +368,7 @@ class Form extends Component {
|
|||
clearForm: this.clearForm,
|
||||
autofilledValues: this.state.autofilledValues,
|
||||
addToAutofilledValues: this.addToAutofilledValues,
|
||||
addToDeletedValues: this.addToDeletedValues,
|
||||
updateCurrentValues: this.updateCurrentValues,
|
||||
getDocument: this.getDocument,
|
||||
setFormState: this.setFormState,
|
||||
|
@ -453,15 +463,20 @@ class Form extends Component {
|
|||
const set = _.compactObject(flatten(data));
|
||||
|
||||
// put all keys without data on $unset
|
||||
const unsetKeys = _.difference(fields, _.keys(set));
|
||||
const unset = _.object(unsetKeys, unsetKeys.map(()=>true));
|
||||
const setKeys = _.keys(set);
|
||||
let unsetKeys = _.difference(fields, setKeys);
|
||||
|
||||
// build modifier
|
||||
const modifier = {$set: set};
|
||||
if (!_.isEmpty(unset)) modifier.$unset = unset;
|
||||
// add all keys to delete (minus those that have data associated)
|
||||
unsetKeys = _.unique(unsetKeys.concat(_.difference(this.state.deletedValues, setKeys)));
|
||||
|
||||
// build mutation arguments object
|
||||
const args = {documentId: document._id, set: set};
|
||||
if (unsetKeys.length > 0) {
|
||||
const unset = _.object(unsetKeys, unsetKeys.map(() => true));
|
||||
args.unset = unset;
|
||||
}
|
||||
// call method with _id of document being edited and modifier
|
||||
// Meteor.call(this.props.methodName, document._id, modifier, this.methodCallback);
|
||||
this.props.editMutation({documentId: document._id, set: set, unset: unset}).then(this.editMutationSuccessCallback).catch(this.mutationErrorCallback);
|
||||
this.props.editMutation(args).then(this.editMutationSuccessCallback).catch(this.mutationErrorCallback);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -565,6 +580,7 @@ Form.contextTypes = {
|
|||
Form.childContextTypes = {
|
||||
autofilledValues: PropTypes.object,
|
||||
addToAutofilledValues: PropTypes.func,
|
||||
addToDeletedValues: PropTypes.func,
|
||||
updateCurrentValues: PropTypes.func,
|
||||
setFormState: PropTypes.func,
|
||||
throwError: PropTypes.func,
|
||||
|
|
|
@ -68,6 +68,7 @@ addStrings('en', {
|
|||
"posts.scheduled": "Scheduled",
|
||||
"posts.daily": "Daily",
|
||||
"posts.clear_thumbnail": "Clear Thumbnail",
|
||||
"posts.clear_thumbnail?": "Clear thumbnail?",
|
||||
"posts.enter_thumbnail_url": "Enter URL",
|
||||
"posts.created_message": "Post created.",
|
||||
"posts.rate_limit_error": "Please wait {value} seconds before posting again.",
|
||||
|
|
|
@ -55,4 +55,6 @@ Utils.icons = {
|
|||
spinner: "spinner",
|
||||
new: "plus",
|
||||
user: "user",
|
||||
like: "heart",
|
||||
image: "picture-o",
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue