From a0a24ebf72f8af53aa6bc6473c1d62cd5ac33c5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A1ssio=20Zen?= Date: Wed, 17 Aug 2016 09:52:17 -0300 Subject: [PATCH] plugin architecture --- package.json | 4 ++-- src/actions/editor.js | 8 ++++++++ src/index.js | 3 +++ src/plugins/index.js | 40 ++++++++++++++++++++++++++++++++++++++++ src/reducers/editor.js | 11 ++++++----- 5 files changed, 59 insertions(+), 7 deletions(-) create mode 100644 src/plugins/index.js diff --git a/package.json b/package.json index c91c9083..5afdd2bf 100644 --- a/package.json +++ b/package.json @@ -74,11 +74,11 @@ "json-loader": "^0.5.4", "localforage": "^1.4.2", "lodash": "^4.13.1", - "markup-it": "git+https://github.com/cassiozen/markup-it.git", + "markup-it": "git+https://github.com/GitbookIO/markup-it.git", "pluralize": "^3.0.0", "prismjs": "^1.5.1", "react-portal": "^2.2.1", "selection-position": "^1.0.0", - "slate": "^0.12.2" + "slate": "^0.13.5" } } diff --git a/src/actions/editor.js b/src/actions/editor.js index c9e35448..fe26c1af 100644 --- a/src/actions/editor.js +++ b/src/actions/editor.js @@ -1,4 +1,5 @@ export const SWITCH_VISUAL_MODE = 'SWITCH_VISUAL_MODE'; +export const REGISTER_COMPONENT = 'REGISTER_COMPONENT'; export function switchVisualMode(useVisualMode) { return { @@ -6,3 +7,10 @@ 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 508b38f0..55c88e99 100644 --- a/src/index.js +++ b/src/index.js @@ -5,6 +5,7 @@ import { Router } from 'react-router'; import configureStore from './store/configureStore'; import routes from './routing/routes'; import history, { syncHistory } from './routing/history'; +import { initPluginAPI } from './plugins'; import 'file?name=index.html!../example/index.html'; import './index.css'; @@ -13,6 +14,8 @@ const store = configureStore(); // Create an enhanced history that syncs navigation events with the store syncHistory(store); +initPluginAPI(store); + const el = document.createElement('div'); el.id = 'root'; document.body.appendChild(el); diff --git a/src/plugins/index.js b/src/plugins/index.js new file mode 100644 index 00000000..fffb9412 --- /dev/null +++ b/src/plugins/index.js @@ -0,0 +1,40 @@ +import { registerComponent } from '../actions/editor'; + +let storeRef; +const requiredEditorComponentProperties = ['label', 'fields', 'detect', 'fromBlock', 'toBlock']; + +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); +}; + +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.`); + } + }; +} + +export const initPluginAPI = (store) => { + storeRef = store; + window.CMS = new CMS(); +}; diff --git a/src/reducers/editor.js b/src/reducers/editor.js index 2273e708..9a6c2936 100644 --- a/src/reducers/editor.js +++ b/src/reducers/editor.js @@ -1,11 +1,12 @@ -import { Map } from 'immutable'; -import { SWITCH_VISUAL_MODE } from '../actions/editor'; +import { Map, List } from 'immutable'; +import { SWITCH_VISUAL_MODE, REGISTER_COMPONENT } from '../actions/editor'; -const editor = (state = Map({ useVisualMode: true }), action) => { +const editor = (state = Map({ useVisualMode: true, registeredComponents: List() }), action) => { switch (action.type) { case SWITCH_VISUAL_MODE: - return Map({ useVisualMode: action.payload }); - + return state.setIn(['useVisualMode'], action.payload); + case REGISTER_COMPONENT: + return state.updateIn(['registeredComponents'], list => list.push(action.payload)); default: return state; }