/*
* This file is part of ORY Editor.
*
* ORY Editor is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ORY Editor is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with ORY Editor. If not, see .
*
* @license LGPL-3.0
* @copyright 2016-2018 Aeneas Rekkas
* @author Aeneas Rekkas
*
*/
import { v4 } from 'uuid';
import Editable from './components/Editable';
import createStore from './store';
import { actions, ActionsTypes, Actions } from './actions';
import { selectors, Selectors } from './selector';
import PluginService from './service/plugin';
import { ContentPlugin, LayoutPlugin } from './service/plugin/classes';
import pluginDefault from './service/plugin/default';
import { EditableType, NativeFactory } from './types/editable';
import forEach from 'ramda/src/forEach';
import HTML5Backend, { NativeTypes } from 'react-dnd-html5-backend';
import { DragDropContext as dragDropContext } from 'react-dnd';
import { reducer } from './reducer';
import { Store, Middleware } from 'redux';
import { RootState } from './types/state';
import lazyLoad from './helper/lazyLoad';
import {
Plugins,
ContentPluginConfig,
LayoutPluginConfig
} from './service/plugin/classes';
import { isProduction } from './const';
import { shouldPureComponentUpdate } from './helper/shouldComponentUpdate';
export { shouldPureComponentUpdate };
import i18n from './service/i18n';
import DragDropContext from './components/DragDropContext';
export {
Plugins,
NativeFactory,
Actions,
Selectors,
RootState,
i18n,
DragDropContext
};
let instance: Editor;
const initialState = () => ({
reactPage: {
editables: {
past: [],
present: [],
future: [],
},
},
});
const nativeTypes = (editor: Editor) =>
editor.plugins.hasNativePlugin()
? [NativeTypes.URL, NativeTypes.FILE, NativeTypes.TEXT]
: [];
const update = (editor: Editor) => (editable: EditableType) => {
const state = editor.plugins.unserialize(editable);
actions(editor.store.dispatch).editable.update({
...state,
config: {
plugins: editor.plugins,
whitelist: [
...editor.plugins.getRegisteredNames(),
...nativeTypes(editor),
],
},
// tslint:disable-next-line:no-any
} as any);
};
const dndBackend = HTML5Backend;
export interface EditorProps {
// tslint:disable-next-line:no-any
plugins?: Plugins;
middleware?: [];
editables?: EditableType[];
defaultPlugin?: ContentPluginConfig;
// tslint:disable-next-line:no-any
dragDropBackend?: any;
store?: Store;
}
/**
* Editor is the core interface for dealing with the editor.
*/
class Editor {
store: Store;
plugins: PluginService;
middleware: Middleware[];
// tslint:disable-next-line:no-any
dragDropContext: any;
defaultPlugin: ContentPluginConfig;
trigger: ActionsTypes;
query = {};
constructor({
plugins,
middleware = [],
editables = [],
defaultPlugin = pluginDefault,
dragDropBackend,
store,
}: EditorProps = {}) {
if (instance) {
console.warn(
'You defined multiple instances of the Editor class, this can cause problems.'
);
}
instance = this;
this.store = store || createStore(initialState(), middleware);
this.plugins = new PluginService(plugins);
this.middleware = middleware;
this.trigger = actions(this.store.dispatch);
this.query = selectors(this.store);
this.defaultPlugin = defaultPlugin;
this.dragDropContext = dragDropContext(dragDropBackend || dndBackend);
// tslint:disable-next-line:no-any
this.trigger.editable.add = update(this) as any;
// tslint:disable-next-line:no-any
this.trigger.editable.update = update(this) as any;
editables.forEach(this.trigger.editable.add);
}
public refreshEditables = () => {
forEach((editable: EditableType) => {
if (!isProduction) {
// tslint:disable-next-line:no-console
console.log(this.plugins.serialize(editable));
}
// tslint:disable-next-line:no-any
this.trigger.editable.update(this.plugins.serialize(editable) as any);
}, this.store.getState().reactPage.editables.present);
}
// tslint:disable-next-line:no-any
public setLayoutPlugins = (plugins: LayoutPluginConfig[] = []) => {
this.plugins.setLayoutPlugins(plugins);
this.refreshEditables();
}
public addLayoutPlugin = (config: LayoutPluginConfig) => {
this.plugins.addLayoutPlugin(config);
this.refreshEditables();
}
public removeLayoutPlugin = (name: string) => {
this.plugins.removeLayoutPlugin(name);
this.refreshEditables();
}
public setContentPlugins = (plugins: ContentPluginConfig[] = []) => {
this.plugins.setContentPlugins(plugins);
this.refreshEditables();
}
public addContentPlugin = (config: ContentPluginConfig) => {
this.plugins.addContentPlugin(config);
this.refreshEditables();
}
public removeContentPlugin = (name: string) => {
this.plugins.removeContentPlugin(name);
this.refreshEditables();
}
}
export {
PluginService,
ContentPlugin,
LayoutPlugin,
Editable,
Editor,
reducer,
lazyLoad
};
export const createEmptyState: () => EditableType = () =>
({ id: v4(), cells: [] } as EditableType);
export default Editor;