From 6cff2b19fdb558d84da62182025a813cc5531c68 Mon Sep 17 00:00:00 2001 From: SachaG Date: Sat, 6 May 2017 16:08:01 +0900 Subject: [PATCH] integrate Embedly thumbnail inside EmbedlyURL component (not using ThumbnailURL anymore) --- .../lib/components/EmbedlyURL.jsx | 98 ++++++++++++++++--- .../lib/components/ThumbnailURL.jsx | 18 ++-- packages/vulcan-embedly/lib/custom_fields.js | 2 +- .../lib/server/get_embedly_data.js | 4 +- .../lib/stylesheets/embedly.scss | 44 ++++++++- packages/vulcan-forms/lib/Form.jsx | 32 ++++-- packages/vulcan-i18n-en-us/lib/en_US.js | 1 + packages/vulcan-lib/lib/modules/icons.js | 2 + 8 files changed, 162 insertions(+), 39 deletions(-) diff --git a/packages/vulcan-embedly/lib/components/EmbedlyURL.jsx b/packages/vulcan-embedly/lib/components/EmbedlyURL.jsx index e4619af29..78ec57685 100644 --- a/packages/vulcan-embedly/lib/components/EmbedlyURL.jsx +++ b/packages/vulcan-embedly/lib/components/EmbedlyURL.jsx @@ -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 ( +
+ +
+ + +
+
+ ) + } + + renderNoThumbnail() { + return ( +
+
+ + +
+
+ ) + } + render() { const wrapperStyle = { @@ -94,15 +148,29 @@ class EmbedlyURL extends Component { const {document, control, getEmbedlyData, ...rest} = this.props; // eslint-disable-line return ( -
- this.input = ref} - /> -
- +
+ +
+
+ this.input = ref} + layout="elementOnly" + /> +
+ +
+
+ + {this.state.thumbnailUrl ? this.renderThumbnail() : this.renderNoThumbnail()} + +
); @@ -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({ diff --git a/packages/vulcan-embedly/lib/components/ThumbnailURL.jsx b/packages/vulcan-embedly/lib/components/ThumbnailURL.jsx index fa64da099..c9f621779 100644 --- a/packages/vulcan-embedly/lib/components/ThumbnailURL.jsx +++ b/packages/vulcan-embedly/lib/components/ThumbnailURL.jsx @@ -29,15 +29,15 @@ class ThumbnailURL extends Component { renderThumbnail() { return (
- - + +
) } diff --git a/packages/vulcan-embedly/lib/custom_fields.js b/packages/vulcan-embedly/lib/custom_fields.js index 97f7b917e..06cc90453 100644 --- a/packages/vulcan-embedly/lib/custom_fields.js +++ b/packages/vulcan-embedly/lib/custom_fields.js @@ -17,7 +17,7 @@ Posts.addField([ insertableBy: ['members'], editableBy: ['members'], viewableBy: ['guests'], - control: ThumbnailURL + hidden: true } }, { diff --git a/packages/vulcan-embedly/lib/server/get_embedly_data.js b/packages/vulcan-embedly/lib/server/get_embedly_data.js index c8376096b..ebb03c871 100644 --- a/packages/vulcan-embedly/lib/server/get_embedly_data.js +++ b/packages/vulcan-embedly/lib/server/get_embedly_data.js @@ -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 diff --git a/packages/vulcan-embedly/lib/stylesheets/embedly.scss b/packages/vulcan-embedly/lib/stylesheets/embedly.scss index 30a343f7e..3cabd900a 100644 --- a/packages/vulcan-embedly/lib/stylesheets/embedly.scss +++ b/packages/vulcan-embedly/lib/stylesheets/embedly.scss @@ -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; + } } \ No newline at end of file diff --git a/packages/vulcan-forms/lib/Form.jsx b/packages/vulcan-forms/lib/Form.jsx index 484e931cd..5cf14fac5 100644 --- a/packages/vulcan-forms/lib/Form.jsx +++ b/packages/vulcan-forms/lib/Form.jsx @@ -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, diff --git a/packages/vulcan-i18n-en-us/lib/en_US.js b/packages/vulcan-i18n-en-us/lib/en_US.js index 859222d43..2f92445b1 100644 --- a/packages/vulcan-i18n-en-us/lib/en_US.js +++ b/packages/vulcan-i18n-en-us/lib/en_US.js @@ -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.", diff --git a/packages/vulcan-lib/lib/modules/icons.js b/packages/vulcan-lib/lib/modules/icons.js index 4c6562d3e..2b23c8b26 100644 --- a/packages/vulcan-lib/lib/modules/icons.js +++ b/packages/vulcan-lib/lib/modules/icons.js @@ -55,4 +55,6 @@ Utils.icons = { spinner: "spinner", new: "plus", user: "user", + like: "heart", + image: "picture-o", };