Support for object widget

This commit is contained in:
Mathias Biilmann Christensen 2016-10-28 04:51:37 +02:00
parent 442a02f009
commit 6b73c39ba8
9 changed files with 125 additions and 5 deletions

View File

@ -37,6 +37,13 @@ collections: # A list of collections the CMS should be able to edit
description: "General Site Settings"
fields:
- {label: "Global title", name: "site_title", widget: "string"}
- label: "Post Settings"
name: posts
widget: "object"
fields:
- {label: "Number of posts on frontpage", name: front_limit, widget: number}
- {label: "Default Author", name: author, widget: string}
- {label: "Default Thumbnail", name: thumb, widget: image, class: "thumb"}
- name: "authors"
label: "Authors"

View File

@ -154,16 +154,18 @@ class Backend {
throw (new Error('Not allowed to create new entries in this collection'));
}
const slug = slugFormatter(collection.get('slug'), entryDraft.getIn(['entry', 'data']));
const path = collectionModel.entryPath(slug);
entryObj = {
path: collectionModel.entryPath(slug),
path,
slug,
raw: this.entryToRaw(collection, entryData),
raw: this.entryToRaw(collection, Object.assign({ path }, entryData)),
};
} else {
const path = entryDraft.getIn(['entry', 'path']);
entryObj = {
path: entryDraft.getIn(['entry', 'path']),
path,
slug: entryDraft.getIn(['entry', 'slug']),
raw: this.entryToRaw(collection, entryData),
raw: this.entryToRaw(collection, Object.assign({ path }, entryData)),
};
}

View File

@ -3,6 +3,8 @@ import UnknownControl from './Widgets/UnknownControl';
import UnknownPreview from './Widgets/UnknownPreview';
import StringControl from './Widgets/StringControl';
import StringPreview from './Widgets/StringPreview';
import NumberControl from './Widgets/NumberControl';
import NumberPreview from './Widgets/NumberPreview';
import ListControl from './Widgets/ListControl';
import ListPreview from './Widgets/ListPreview';
import TextControl from './Widgets/TextControl';
@ -13,13 +15,17 @@ import ImageControl from './Widgets/ImageControl';
import ImagePreview from './Widgets/ImagePreview';
import DateTimeControl from './Widgets/DateTimeControl';
import DateTimePreview from './Widgets/DateTimePreview';
import ObjectControl from './Widgets/ObjectControl';
import ObjectPreview from './Widgets/ObjectPreview';
registry.registerWidget('string', StringControl, StringPreview);
registry.registerWidget('text', TextControl, TextPreview);
registry.registerWidget('number', NumberControl, NumberPreview);
registry.registerWidget('list', ListControl, ListPreview);
registry.registerWidget('markdown', MarkdownControl, MarkdownPreview);
registry.registerWidget('image', ImageControl, ImagePreview);
registry.registerWidget('datetime', DateTimeControl, DateTimePreview);
registry.registerWidget('object', ObjectControl, ObjectPreview);
registry.registerWidget('unknown', UnknownControl, UnknownPreview);
export function resolveWidget(name) {

View File

@ -0,0 +1,16 @@
import React, { PropTypes } from 'react';
export default class StringControl extends React.Component {
handleChange = e => {
this.props.onChange(e.target.value);
};
render() {
return <input type="number" value={this.props.value || ''} onChange={this.handleChange}/>;
}
}
StringControl.propTypes = {
onChange: PropTypes.func.isRequired,
value: PropTypes.node,
};

View File

@ -0,0 +1,9 @@
import React, { PropTypes } from 'react';
export default function StringPreview({ value }) {
return <span>{value}</span>;
}
StringPreview.propTypes = {
value: PropTypes.node,
};

View File

@ -0,0 +1,51 @@
import React, { Component, PropTypes } from 'react';
import { Map } from 'immutable';
import { resolveWidget } from '../Widgets';
import styles from '../ControlPanel/ControlPane.css';
export default class ObjectControl extends Component {
static propTypes = {
onChange: PropTypes.func.isRequired,
onAddMedia: PropTypes.func.isRequired,
getMedia: PropTypes.func.isRequired,
value: PropTypes.node,
field: PropTypes.node,
};
controlFor(field) {
const { onAddMedia, onRemoveMedia, getMedia, value, onChange } = this.props;
const widget = resolveWidget(field.get('widget') || 'string');
const fieldValue = value && value.get(field.get('name'));
return (
<div className={styles.control} key={field.get('name')}>
<label className={styles.label}>{field.get('label')}</label>
{
React.createElement(widget.control, {
field,
value: fieldValue,
onChange: (val) => {
onChange((value || Map()).set(field.get('name'), val));
},
onAddMedia,
onRemoveMedia,
getMedia,
})
}
</div>
);
}
render() {
const { field } = this.props;
const fields = field.get('fields');
if (!fields) {
return <h3>No fields defined for this widget</h3>;
}
return (<div>
{field.get('fields').map(field => this.controlFor(field))}
</div>);
}
}

View File

@ -0,0 +1,28 @@
import React, { PropTypes, Component } from 'react';
import { resolveWidget } from '../Widgets';
export default class ObjectPreview extends Component {
widgetFor = (field) => {
const { value, getMedia } = this.props;
const widget = resolveWidget(field.get('widget'));
return (<div key={field.get('name')}>{React.createElement(widget.preview, {
key: field.get('name'),
value: value && value.get(field.get('name')),
field,
getMedia,
})}</div>);
};
render() {
const { field } = this.props;
const fields = field && field.get('fields');
return <div>{fields && fields.map(f => this.widgetFor(f))}</div>;
}
}
ObjectPreview.propTypes = {
value: PropTypes.node,
field: PropTypes.node,
getMedia: PropTypes.func.isRequired,
};

View File

@ -33,6 +33,7 @@ export function resolveFormat(collectionOrEntity, entry) {
if (typeof collectionOrEntity === 'string') {
return formatByType(collectionOrEntity);
}
console.log('entry: %o', entry);
const path = entry && entry.path;
if (path) {
return formatByExtension(path.split('.').pop());

View File

@ -4,6 +4,6 @@ export default class JSONFormatter {
}
toFile(data) {
return JSON.generate(data);
return JSON.stringify(data);
}
}