diff --git a/docs/extending.md b/docs/extending.md index 2fb44d23..82d4d57d 100644 --- a/docs/extending.md +++ b/docs/extending.md @@ -37,9 +37,10 @@ Registers a template for a collection. **React Component Props:** * collection: The name of the collection which this preview component will be used for. -* react_component: A React component that renders the collection data. Three props will be passed to your component during render: +* react_component: A React component that renders the collection data. Four props will be passed to your component during render: * entry: Immutable collection containing the entry data. * widgetFor: Returns the appropriate widget preview component for a given field. + * [widgetsFor](#lists-and-objects): Returns an array of objects with widgets and associated field data. For use with list and object type entries. * getAsset: Returns the correct filePath or in-memory preview for uploaded images. **Example:** @@ -63,6 +64,95 @@ CMS.registerPreviewTemplate("posts", PostPreview); ``` +### Lists and Objects +The API for accessing the individual fields of list and object type entries is similar to the API +for accessing fields in standard entries, but there are a few key differences. Access to these +nested fields is facilitated through the `widgetsFor` function, which is passed to the preview +template component during render. + +**Note**: as is often the case with the Netlify CMS API, arrays and objects are created with +Immutable.js. If some of the methods that we use are unfamiliar, such as `getIn`, check out +[their docs](https://facebook.github.io/immutable-js/docs/#/) to get a better understanding. + +**List Example:** + +```html + +``` + +**Object Example:** + +```html + +``` + ### Accessing Metadata Preview Components also receive an additional prop: `fieldsMetaData`. It contains aditional information (besides the plain plain textual value of each field) that can be useful for preview purposes. diff --git a/example/index.html b/example/index.html index 73c98009..6ab62374 100644 --- a/example/index.html +++ b/example/index.html @@ -98,10 +98,10 @@ h('h1', {}, title), h('dl', {}, h('dt', {}, 'Posts on Frontpage'), - h('dd', {}, posts && posts.get('front_limit') || '0'), + h('dd', {}, this.props.widgetsFor('posts').getIn(['widgets', 'front_limit']) || 0), h('dt', {}, 'Default Author'), - h('dd', {}, posts && posts.get('author') || 'None'), + h('dd', {}, this.props.widgetsFor('posts').getIn(['data', 'author']) || 'None'), h('dt', {}, 'Default Thumbnail'), h('dd', {}, thumb && h('img', {src: this.props.getAsset(thumb).toString()})) @@ -110,8 +110,24 @@ } }); + var AuthorsPreview = createClass({ + render: function() { + return h('div', {}, + h('h1', {}, 'Authors'), + this.props.widgetsFor('authors').map(function(author, index) { + return h('div', {key: index}, + h('hr', {}), + h('strong', {}, author.getIn(['data', 'name'])), + author.getIn(['widgets', 'description']) + ); + }) + ); + } + }); + CMS.registerPreviewTemplate("posts", PostPreview); CMS.registerPreviewTemplate("general", GeneralPreview); + CMS.registerPreviewTemplate("authors", AuthorsPreview); CMS.registerPreviewStyle("/example.css"); CMS.registerEditorComponent({ id: "youtube", diff --git a/src/components/PreviewPane/PreviewPane.js b/src/components/PreviewPane/PreviewPane.js index 07903ab1..07c1fd72 100644 --- a/src/components/PreviewPane/PreviewPane.js +++ b/src/components/PreviewPane/PreviewPane.js @@ -1,5 +1,6 @@ import React, { PropTypes } from 'react'; import ReactDOM from 'react-dom'; +import { List, Map } from 'immutable'; import ImmutablePropTypes from 'react-immutable-proptypes'; import { ScrollSyncPane } from '../ScrollSync'; import registry from '../../lib/registry'; @@ -15,6 +16,18 @@ export default class PreviewPane extends React.Component { this.renderPreview(); } + getWidget = (field, value, props) => { + const { fieldsMetaData, getAsset } = props; + const widget = resolveWidget(field.get('widget')); + return React.createElement(widget.preview, { + field, + key: field.get('name'), + value: value && Map.isMap(value) ? value.get(field.get('name')) : value, + metadata: fieldsMetaData && fieldsMetaData.get(field.get('name')), + getAsset, + }); + }; + inferedFields = {}; inferFields() { @@ -29,24 +42,35 @@ export default class PreviewPane extends React.Component { } widgetFor = (name) => { - const { fields, entry, fieldsMetaData, getAsset } = this.props; + const { fields, entry } = this.props; const field = fields.find(f => f.get('name') === name); let value = entry.getIn(['data', field.get('name')]); - const metadata = fieldsMetaData.get(field.get('name')); const labelledWidgets = ['string', 'text', 'number']; if (Object.keys(this.inferedFields).indexOf(name) !== -1) { value = this.inferedFields[name].defaultPreview(value); } else if (value && labelledWidgets.indexOf(field.get('widget')) !== -1 && value.toString().length < 50) { value =