mirror of
https://github.com/vale981/Vulcan
synced 2025-03-06 01:51:40 -05:00
adding embedly integration
This commit is contained in:
parent
8a2c9dbeed
commit
a367ed426d
8 changed files with 220 additions and 86 deletions
85
packages/nova-embedly/lib/components/EmbedlyThumbnail.jsx
Normal file
85
packages/nova-embedly/lib/components/EmbedlyThumbnail.jsx
Normal file
|
@ -0,0 +1,85 @@
|
|||
import React, { PropTypes, Component } from 'react';
|
||||
import Formsy from 'formsy-react';
|
||||
import FRC from 'formsy-react-components';
|
||||
const Input = FRC.Input;
|
||||
|
||||
class EmbedlyThumbnail extends Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
thumbnailUrl: props.value,
|
||||
loading: false
|
||||
};
|
||||
}
|
||||
|
||||
// will trigger every time the context (i.e. form values) changes
|
||||
shouldComponentUpdate(nextProps, nextState, nextContext) {
|
||||
|
||||
const nextUrl = nextContext.currentValues.url;
|
||||
const currentUrl = this.context.currentValues.url;
|
||||
|
||||
if (nextUrl != currentUrl) {
|
||||
|
||||
this.setState({loading: true});
|
||||
|
||||
// the URL has changed, get a new thumbnail
|
||||
Meteor.call("getEmbedlyData", nextUrl, (error, result) => {
|
||||
|
||||
this.setState({loading: false});
|
||||
|
||||
if (error) {
|
||||
console.log(error)
|
||||
this.context.throwError({content: error.message, type: "error"});
|
||||
} else {
|
||||
this.setState({
|
||||
thumbnailUrl: result.thumbnailUrl
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
renderThumbnail() {
|
||||
|
||||
const currentUrl = this.context.currentValues && this.context.currentValues.url;
|
||||
|
||||
return currentUrl ? <img
|
||||
className="embedly-thumbnail"
|
||||
src={this.state.thumbnailUrl}
|
||||
height={Telescope.settings.get('thumbnailHeight', 125)}
|
||||
width={Telescope.settings.get('thumbnailWidth', 200)}
|
||||
/> : null;
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
const {name, value, label} = this.props;
|
||||
|
||||
Loading = Telescope.components.Loading;
|
||||
|
||||
return (
|
||||
<div className="form-group row">
|
||||
<label className="control-label col-sm-3">{label}</label>
|
||||
<div className="col-sm-9">
|
||||
{this.state.loading ? <Loading /> : this.renderThumbnail()}
|
||||
<Input name={name} type="hidden" readOnly value={this.state.thumbnailUrl} />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
EmbedlyThumbnail.propTypes = {
|
||||
name: React.PropTypes.string,
|
||||
value: React.PropTypes.any,
|
||||
label: React.PropTypes.string
|
||||
}
|
||||
|
||||
EmbedlyThumbnail.contextTypes = {
|
||||
currentValues: React.PropTypes.object,
|
||||
throwError: React.PropTypes.func
|
||||
}
|
||||
|
||||
export default EmbedlyThumbnail;
|
|
@ -1,4 +1,5 @@
|
|||
import PublicationUtils from 'meteor/utilities:smart-publications';
|
||||
import EmbedlyThumbnail from './components/EmbedlyThumbnail.jsx';
|
||||
|
||||
Posts.addField([
|
||||
{
|
||||
|
@ -9,10 +10,7 @@ Posts.addField([
|
|||
insertableIf: Users.is.memberOrAdmin,
|
||||
editableIf: Users.is.ownerOrAdmin,
|
||||
publish: true,
|
||||
autoform: {
|
||||
type: 'bootstrap-postthumbnail',
|
||||
order: 40
|
||||
}
|
||||
control: EmbedlyThumbnail
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -44,3 +42,40 @@ Posts.addField([
|
|||
|
||||
PublicationUtils.addToFields(Posts.publishedFields.list, ["thumbnailUrl", "media", "sourceName", "sourceUrl"]);
|
||||
PublicationUtils.addToFields(Posts.publishedFields.single, ["thumbnailUrl", "media", "sourceName", "sourceUrl"]);
|
||||
|
||||
if (typeof Telescope.settings.collection !== "undefined") {
|
||||
Telescope.settings.collection.addField([
|
||||
{
|
||||
fieldName: 'embedlyKey',
|
||||
fieldSchema: {
|
||||
type: String,
|
||||
optional: true,
|
||||
private: true,
|
||||
autoform: {
|
||||
group: 'embedly',
|
||||
class: 'private-field'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
fieldName: 'thumbnailWidth',
|
||||
fieldSchema: {
|
||||
type: Number,
|
||||
optional: true,
|
||||
autoform: {
|
||||
group: 'embedly'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
fieldName: 'thumbnailHeight',
|
||||
fieldSchema: {
|
||||
type: Number,
|
||||
optional: true,
|
||||
autoform: {
|
||||
group: 'embedly'
|
||||
}
|
||||
}
|
||||
}
|
||||
]);
|
||||
}
|
|
@ -16,39 +16,3 @@ function checkIfPreviouslyPosted (data) {
|
|||
return data;
|
||||
}
|
||||
Telescope.callbacks.add("afterEmbedlyPrefill", checkIfPreviouslyPosted);
|
||||
|
||||
|
||||
// Settings.addField([
|
||||
// {
|
||||
// fieldName: 'embedlyKey',
|
||||
// fieldSchema: {
|
||||
// type: String,
|
||||
// optional: true,
|
||||
// private: true,
|
||||
// autoform: {
|
||||
// group: 'embedly',
|
||||
// class: 'private-field'
|
||||
// }
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// fieldName: 'thumbnailWidth',
|
||||
// fieldSchema: {
|
||||
// type: Number,
|
||||
// optional: true,
|
||||
// autoform: {
|
||||
// group: 'embedly'
|
||||
// }
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// fieldName: 'thumbnailHeight',
|
||||
// fieldSchema: {
|
||||
// type: Number,
|
||||
// optional: true,
|
||||
// autoform: {
|
||||
// group: 'embedly'
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// ]);
|
|
@ -1,9 +1,9 @@
|
|||
getEmbedlyData = function (url) {
|
||||
var data = {};
|
||||
var extractBase = 'http://api.embed.ly/1/extract';
|
||||
var embedlyKey = Settings.get('embedlyKey');
|
||||
var thumbnailWidth = Settings.get('thumbnailWidth', 200);
|
||||
var thumbnailHeight = Settings.get('thumbnailHeight', 125);
|
||||
var embedlyKey = Telescope.settings.get('embedlyKey');
|
||||
var thumbnailWidth = Telescope.settings.get('thumbnailWidth', 200);
|
||||
var thumbnailHeight = Telescope.settings.get('thumbnailHeight', 125);
|
||||
|
||||
if(!embedlyKey) {
|
||||
// fail silently to still let the post be submitted as usual
|
||||
|
@ -115,7 +115,7 @@ Meteor.methods({
|
|||
return getEmbedlyData(url);
|
||||
},
|
||||
embedlyKeyExists: function () {
|
||||
return !!Settings.get('embedlyKey');
|
||||
return !!Telescope.settings.get('embedlyKey');
|
||||
},
|
||||
regenerateThumbnail: function (post) {
|
||||
check(post, Posts.simpleSchema());
|
||||
|
|
|
@ -17,12 +17,12 @@ Package.onUse( function(api) {
|
|||
|
||||
api.addFiles([
|
||||
// 'package-tap.i18n',
|
||||
// 'lib/embedly.js',
|
||||
'lib/embedly.js',
|
||||
'lib/custom_fields.js'
|
||||
], ['client', 'server']);
|
||||
|
||||
api.addFiles([
|
||||
// 'lib/server/get_embedly_data.js'
|
||||
'lib/server/get_embedly_data.js'
|
||||
], ['server']);
|
||||
|
||||
api.addFiles([
|
||||
|
|
|
@ -25,23 +25,30 @@ class FormComponent extends Component {
|
|||
const value = document && Utils.deepValue(document, fieldName) ? Utils.deepValue(document, fieldName) : "";
|
||||
const label = typeof labelFunction === "function" ? labelFunction(fieldName) : fieldName;
|
||||
|
||||
switch (field.control) {
|
||||
if (typeof field.control === "function") {
|
||||
|
||||
return <field.control key={fieldName} name={fieldName} value={value} label={label}/>
|
||||
|
||||
} else {
|
||||
|
||||
switch (field.control) {
|
||||
case "text":
|
||||
return <Input key={fieldName} name={fieldName} value={value} label={label} type="text" />;
|
||||
case "textarea":
|
||||
return <Textarea key={fieldName} name={fieldName} value={value} label={label} />;
|
||||
case "checkbox":
|
||||
return <Checkbox key={fieldName} name={fieldName} value={value} label={label}/>;
|
||||
// note: checkboxgroup cause React refs error
|
||||
case "checkboxgroup":
|
||||
return <CheckboxGroup key={fieldName} name={fieldName} value={value} label={label} options={options} />;
|
||||
case "radiogroup":
|
||||
return <RadioGroup key={fieldName} name={fieldName} value={value} label={label} options={options} />;
|
||||
case "select":
|
||||
return <Select key={fieldName} name={fieldName} value={value} label={label} options={options} />;
|
||||
default:
|
||||
return <Input key={fieldName} name={fieldName} value={value} label={label} type="text" />;
|
||||
}
|
||||
|
||||
case "text":
|
||||
return <Input key={fieldName} name={fieldName} value={value} label={label} type="text" />;
|
||||
case "textarea":
|
||||
return <Textarea key={fieldName} name={fieldName} value={value} label={label} />;
|
||||
case "checkbox":
|
||||
return <Checkbox key={fieldName} name={fieldName} value={value} label={label}/>;
|
||||
// note: checkboxgroup cause React refs error
|
||||
case "checkboxgroup":
|
||||
return <CheckboxGroup key={fieldName} name={fieldName} value={value} label={label} options={options} />;
|
||||
case "radiogroup":
|
||||
return <RadioGroup key={fieldName} name={fieldName} value={value} label={label} options={options} />;
|
||||
case "select":
|
||||
return <Select key={fieldName} name={fieldName} value={value} label={label} options={options} />;
|
||||
default:
|
||||
return <Input key={fieldName} name={fieldName} value={value} label={label} type="text" />;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,26 +7,74 @@ import Utils from './utils.js';
|
|||
|
||||
class NovaForm extends Component{
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.submitForm = this.submitForm.bind(this);
|
||||
this.methodCallback = this.methodCallback.bind(this);
|
||||
this.updateState = this.updateState.bind(this);
|
||||
this.throwError = this.throwError.bind(this);
|
||||
this.clearErrors = this.clearErrors.bind(this);
|
||||
this.state = {
|
||||
disabled: false,
|
||||
errors: []
|
||||
errors: [],
|
||||
currentValues: this.props.document
|
||||
};
|
||||
}
|
||||
|
||||
getFormType() { // if a document is being passed, this is an edit form
|
||||
// if a document is being passed, this is an edit form
|
||||
getFormType() {
|
||||
return this.props.document ? "edit" : "new";
|
||||
}
|
||||
|
||||
getFields() { // get relevant fields
|
||||
// get relevant fields
|
||||
getFields() {
|
||||
const collection = this.props.collection;
|
||||
const fields = this.getFormType() === "edit" ? collection.getEditableFields(this.props.currentUser) : collection.getInsertableFields(this.props.currentUser);
|
||||
return fields;
|
||||
}
|
||||
|
||||
// add error to state
|
||||
throwError(error) {
|
||||
this.setState({
|
||||
errors: [error]
|
||||
});
|
||||
}
|
||||
|
||||
// clear all errors
|
||||
clearErrors() {
|
||||
this.setState({
|
||||
errors: []
|
||||
});
|
||||
}
|
||||
|
||||
// render errors
|
||||
renderErrors() {
|
||||
Flash = Telescope.components.Flash;
|
||||
return <div className="form-errors">{this.state.errors.map(message => <Flash key={message} message={message}/>)}</div>
|
||||
}
|
||||
|
||||
// whenever the form values change, keep track of them in the state
|
||||
updateState(e) {
|
||||
// e can sometimes be event, sometims be currentValue
|
||||
// see https://github.com/christianalfoni/formsy-react/issues/203
|
||||
if (e.stopPropagation) {
|
||||
e.stopPropagation();
|
||||
} else {
|
||||
this.setState({
|
||||
currentValues: e
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// pass on form values as context to all child components for easy access
|
||||
getChildContext() {
|
||||
return {
|
||||
throwError: this.throwError,
|
||||
currentValues: this.state.currentValues
|
||||
};
|
||||
}
|
||||
|
||||
// common callback for both new and edit forms
|
||||
methodCallback(error, document) {
|
||||
|
||||
this.setState({disabled: false});
|
||||
|
@ -36,11 +84,9 @@ class NovaForm extends Component{
|
|||
console.log(error)
|
||||
|
||||
// add error to state
|
||||
this.setState({
|
||||
errors: [{
|
||||
content: error.message,
|
||||
type: "error"
|
||||
}]
|
||||
this.throwError({
|
||||
content: error.message,
|
||||
type: "error"
|
||||
});
|
||||
|
||||
// run error callback if it exists
|
||||
|
@ -48,9 +94,7 @@ class NovaForm extends Component{
|
|||
|
||||
} else { // success
|
||||
|
||||
this.setState({
|
||||
errors: []
|
||||
});
|
||||
this.clearErrors();
|
||||
|
||||
// reset form if this is a new document form
|
||||
if (this.getFormType() === "new") this.refs.form.reset();
|
||||
|
@ -64,8 +108,8 @@ class NovaForm extends Component{
|
|||
}
|
||||
}
|
||||
|
||||
// submit form handler
|
||||
submitForm(data) {
|
||||
|
||||
this.setState({disabled: true});
|
||||
|
||||
const fields = this.getFields();
|
||||
|
@ -101,7 +145,6 @@ class NovaForm extends Component{
|
|||
// build modifier
|
||||
const modifier = {$set: set};
|
||||
if (!_.isEmpty(unset)) modifier.$unset = unset;
|
||||
|
||||
// call method with _id of document being edited and modifier
|
||||
Meteor.call(this.props.methodName, document._id, modifier, this.methodCallback);
|
||||
|
||||
|
@ -109,11 +152,6 @@ class NovaForm extends Component{
|
|||
|
||||
}
|
||||
|
||||
renderErrors() {
|
||||
Flash = Telescope.components.Flash;
|
||||
return <div className="form-errors">{this.state.errors.map(message => <Flash key={message} message={message}/>)}</div>
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
const document = this.props.document;
|
||||
|
@ -127,7 +165,7 @@ class NovaForm extends Component{
|
|||
|
||||
return (
|
||||
<div className={"document-"+this.getFormType()} style={style}>
|
||||
<Formsy.Form onSubmit={this.submitForm} disabled={this.state.disabled} ref="form">
|
||||
<Formsy.Form onSubmit={this.submitForm} onChange={this.updateState} disabled={this.state.disabled} ref="form">
|
||||
{this.renderErrors()}
|
||||
{fields.map(fieldName => <FormComponent
|
||||
key={fieldName}
|
||||
|
@ -161,5 +199,10 @@ NovaForm.contextTypes = {
|
|||
closeCallback: React.PropTypes.func
|
||||
}
|
||||
|
||||
NovaForm.childContextTypes = {
|
||||
currentValues: React.PropTypes.object,
|
||||
throwError: React.PropTypes.func
|
||||
}
|
||||
|
||||
module.exports = NovaForm;
|
||||
export default NovaForm;
|
|
@ -25,8 +25,8 @@ SimpleSchema.extendOptions({
|
|||
profile: Match.Optional(Boolean), // profile: true means the field is shown on user profiles
|
||||
template: Match.Optional(String), // template used to display the field
|
||||
autoform: Match.Optional(Object), // autoform placeholder
|
||||
control: Match.Optional(String), // autoform placeholder
|
||||
// editableBy: Match.Optional(String)
|
||||
control: Match.Optional(Match.Any), // NovaForm control (String or React component)
|
||||
position: Match.Optional(Number) // position in the form
|
||||
});
|
||||
|
||||
// ------------------------------------- Components -------------------------------- //
|
||||
|
|
Loading…
Add table
Reference in a new issue