diff --git a/src/actions/editor.js b/src/actions/editor.js index fe26c1af..c9e35448 100644 --- a/src/actions/editor.js +++ b/src/actions/editor.js @@ -1,5 +1,4 @@ export const SWITCH_VISUAL_MODE = 'SWITCH_VISUAL_MODE'; -export const REGISTER_COMPONENT = 'REGISTER_COMPONENT'; export function switchVisualMode(useVisualMode) { return { @@ -7,10 +6,3 @@ export function switchVisualMode(useVisualMode) { payload: useVisualMode }; } - -export function registerComponent(options) { - return { - type: REGISTER_COMPONENT, - payload: options - }; -} diff --git a/src/index.js b/src/index.js index 55c88e99..13dc95ca 100644 --- a/src/index.js +++ b/src/index.js @@ -14,7 +14,7 @@ const store = configureStore(); // Create an enhanced history that syncs navigation events with the store syncHistory(store); -initPluginAPI(store); +const Plugin = initPluginAPI(); const el = document.createElement('div'); el.id = 'root'; @@ -22,8 +22,10 @@ document.body.appendChild(el); render(( - - {routes} - + + + {routes} + + ), el); diff --git a/src/plugins/index.js b/src/plugins/index.js index fffb9412..485a0c4c 100644 --- a/src/plugins/index.js +++ b/src/plugins/index.js @@ -1,40 +1,58 @@ -import { registerComponent } from '../actions/editor'; +import { Component, PropTypes, Children } from 'react'; +import { List, Record } from 'immutable'; +import _ from 'lodash'; -let storeRef; -const requiredEditorComponentProperties = ['label', 'fields', 'detect', 'fromBlock', 'toBlock']; +const plugins = { editor: List() }; -const checkConfigKeys = (config, requiredProps) => { - for (var i = requiredProps.length; i--;) { - if (!config.hasOwnProperty(requiredProps[i])) return false; - } - return true; -}; - -const wrap = (func) => function() { - func.apply(null, arguments); -}; +const catchesNothing = /.^/; +const EditorComponent = Record({ + id: null, + label: 'unnamed component', + icon: 'exclamation-triangle', + fields: [], + pattern: catchesNothing, + fromBlock: function(match) { return {}; }, + toBlock: function(attributes) { return 'Plugin'; }, + toPreview: function(attributes) { return 'Plugin'; } +}); function CMS() { this.registerEditorComponent = (config) => { - if (checkConfigKeys(config, requiredEditorComponentProperties)) { - const configObj = { - label: config.label || 'unnamed', - icon: config.icon || 'exclamation-triangle', - fields: config.fields, - detect: wrap(config.detect), - fromBlock: wrap(config.fromBlock), - toBlock: wrap(config.toBlock), - toPreview: config.toPreview ? wrap(config.toPreview) : wrap(config.toBlock) - }; - storeRef.dispatch(registerComponent(configObj)); - } else { - const label = config.label || 'unnamed'; - window.console && console.error(`The provided component configuration for ${label} is incorrect.`); - } + const configObj = new EditorComponent({ + id: config.id || config.label.replace(/[^A-Z0-9]+/ig, '_'), + label: config.label, + icon: config.icon, + fields: config.fields, + pattern: config.pattern, + fromBlock: _.isFunction(config.fromBlock) ? config.fromBlock.bind(null) : null, + toBlock: _.isFunction(config.toBlock) ? config.toBlock.bind(null) : null, + toPreview: _.isFunction(config.toPreview) ? config.toPreview.bind(null) : config.toBlock.bind(null) + }); + + plugins.editor = plugins.editor.push(configObj); }; } -export const initPluginAPI = (store) => { - storeRef = store; - window.CMS = new CMS(); + +class Plugin extends Component { + getChildContext() { + return { plugins: plugins }; + } + + render() { + return Children.only(this.props.children); + } +} + +Plugin.propTypes = { + children: PropTypes.element.isRequired +}; +Plugin.childContextTypes = { + plugins: PropTypes.object +}; + + +export const initPluginAPI = () => { + window.CMS = new CMS(); + return Plugin; }; diff --git a/src/reducers/editor.js b/src/reducers/editor.js index 9a6c2936..4917befb 100644 --- a/src/reducers/editor.js +++ b/src/reducers/editor.js @@ -1,12 +1,10 @@ -import { Map, List } from 'immutable'; -import { SWITCH_VISUAL_MODE, REGISTER_COMPONENT } from '../actions/editor'; +import { Map } from 'immutable'; +import { SWITCH_VISUAL_MODE } from '../actions/editor'; -const editor = (state = Map({ useVisualMode: true, registeredComponents: List() }), action) => { +const editor = (state = Map({ useVisualMode: true }), action) => { switch (action.type) { case SWITCH_VISUAL_MODE: return state.setIn(['useVisualMode'], action.payload); - case REGISTER_COMPONENT: - return state.updateIn(['registeredComponents'], list => list.push(action.payload)); default: return state; }