From 9ff4d9817432b022a8ab8744c1f9f57f8d158cf4 Mon Sep 17 00:00:00 2001 From: Giannis Kopanas <jkopanas@gmail.com> Date: Sat, 7 Dec 2019 20:12:26 +0200 Subject: [PATCH] feat(menuService): add Tool and ToolGroup libraries --- editors/editoria/src/EditorConfig.js | 22 ++++---- editors/editoria/src/config/menu.js | 10 ++-- wax-prosemirror-components/index.js | 2 + wax-prosemirror-core/src/Application.js | 4 +- wax-prosemirror-core/src/Config/Config.js | 23 +++++---- .../src/Config/defaultConfig.js | 3 +- wax-prosemirror-core/src/Wax.js | 1 + .../src/config/Config/config.js | 6 --- wax-prosemirror-core/src/ioc-react.js | 7 ++- .../src/services/Config/config.js | 6 --- .../src/services/LayoutService/Layout.js | 15 ++++-- .../components/componentPlugin.js | 13 +++-- .../src/services/MenuService/Menu.js | 27 ---------- .../src/services/MenuService/MenuService.js | 10 ---- wax-prosemirror-core/src/services/Service.js | 4 +- wax-prosemirror-plugins/index.js | 4 +- wax-prosemirror-plugins/package.json | 4 +- .../src/MenuService/Menu.js | 39 +++++++++++++++ .../src/MenuService/MenuCollection.js | 13 +++++ .../src/MenuService/MenuService.js | 50 +++++++++++++++++++ .../src/MenuService/MenuWrapper.js | 20 ++++++++ .../src/RedoUndoService/Redo.js | 18 +++++++ .../src/RedoUndoService/RedoUndo.js | 19 +++++++ .../src/RedoUndoService/RedoUndoService.js | 15 ++++++ .../src/RedoUndoService/Undo.js | 18 +++++++ wax-prosemirror-plugins/src/lib/GroupTool.js | 29 +++++++++++ wax-prosemirror-plugins/src/lib/Tools.js | 48 ++++++++++++++++++ 27 files changed, 334 insertions(+), 96 deletions(-) delete mode 100644 wax-prosemirror-core/src/config/Config/config.js delete mode 100644 wax-prosemirror-core/src/services/Config/config.js delete mode 100644 wax-prosemirror-core/src/services/MenuService/Menu.js delete mode 100644 wax-prosemirror-core/src/services/MenuService/MenuService.js create mode 100644 wax-prosemirror-plugins/src/MenuService/Menu.js create mode 100644 wax-prosemirror-plugins/src/MenuService/MenuCollection.js create mode 100644 wax-prosemirror-plugins/src/MenuService/MenuService.js create mode 100644 wax-prosemirror-plugins/src/MenuService/MenuWrapper.js create mode 100644 wax-prosemirror-plugins/src/RedoUndoService/Redo.js create mode 100644 wax-prosemirror-plugins/src/RedoUndoService/RedoUndo.js create mode 100644 wax-prosemirror-plugins/src/RedoUndoService/RedoUndoService.js create mode 100644 wax-prosemirror-plugins/src/RedoUndoService/Undo.js create mode 100644 wax-prosemirror-plugins/src/lib/GroupTool.js create mode 100644 wax-prosemirror-plugins/src/lib/Tools.js diff --git a/editors/editoria/src/EditorConfig.js b/editors/editoria/src/EditorConfig.js index c3cffe3b8..c0a25e94b 100644 --- a/editors/editoria/src/EditorConfig.js +++ b/editors/editoria/src/EditorConfig.js @@ -86,18 +86,18 @@ const plugins = [ columnResizing(), tableEditing(), TrackChangePlugin({ options: {} }), - invisibles([hardBreak()]), + invisibles([hardBreak()]) // FindAndReplacePlugin, - MenuBarPlugin({ - Component: MainMenuBar, - renderArea: "topBar", - menuItems: ["undo", "redo"] - }), - MenuBarPlugin({ - Component: SideMenuBar, - renderArea: "leftSideBar" - //menuItems: ["plain"] - }) + // MenuBarPlugin({ + // Component: MainMenuBar, + // renderArea: "topBar", + // menuItems: ["undo", "redo"] + // }), + // MenuBarPlugin({ + // Component: SideMenuBar, + // renderArea: "leftSideBar" + // //menuItems: ["plain"] + // }) ]; const services = [new LinkService()]; diff --git a/editors/editoria/src/config/menu.js b/editors/editoria/src/config/menu.js index 69523798b..c29b97c34 100644 --- a/editors/editoria/src/config/menu.js +++ b/editors/editoria/src/config/menu.js @@ -1,13 +1,9 @@ export default { - menus: [ + MenuService: [ { + name: "top", templateArea: "topBar", - tools: ["redo", "undo"], - groups: [ - "redo-undo", - "annotations", - { group: "Annotation", exclude: [], include: [] } - ] + groupTools: [{ name: "RedoUndo", exclude: [] }] } ] }; diff --git a/wax-prosemirror-components/index.js b/wax-prosemirror-components/index.js index 0fb830248..0e8075554 100644 --- a/wax-prosemirror-components/index.js +++ b/wax-prosemirror-components/index.js @@ -2,3 +2,5 @@ export { default as MainMenuBar } from "./src/mainMenuBar/MainMenuBar"; export { default as SideMenuBar } from "./src/sideMenuBar/SideMenuBar"; export { default as InfoArea } from "./src/components/infoArea/InfoArea"; export { default as Overlay } from "./src/components/Overlay"; +export { default as Button } from "./src/components/Button"; +export { default as icons } from "./src/icons/icons"; diff --git a/wax-prosemirror-core/src/Application.js b/wax-prosemirror-core/src/Application.js index fc602e1b3..8c77d71bd 100644 --- a/wax-prosemirror-core/src/Application.js +++ b/wax-prosemirror-core/src/Application.js @@ -26,9 +26,8 @@ export default class Application { setConfig(config) { this.config = this.container.get("Config"); - Object.keys(config).forEach(conf => { - this.config.pushToArray(conf, config[conf]); + this.config = this.config.pushToArray(conf, config[conf]); }); } @@ -63,6 +62,7 @@ export default class Application { const app = container.get("Wax"); app.setConfig(config); app.registerServices(); + return app; } } diff --git a/wax-prosemirror-core/src/Config/Config.js b/wax-prosemirror-core/src/Config/Config.js index a5b349e10..34f027839 100644 --- a/wax-prosemirror-core/src/Config/Config.js +++ b/wax-prosemirror-core/src/Config/Config.js @@ -3,27 +3,28 @@ import { injectable, inject } from "inversify"; @injectable() export default class Config { - config = {}; + _config = {}; constructor(@inject("config") config) { - this.config = config; + this._config = config; } set(key, value) { - set(this.config, key, value); - return this.config; + set(this._config, key, value); + return this._config; } get(key) { - return get(this.config, key); + return get(this._config, key); } pushToArray(key, value) { - const oldValue = this.get(key); - let newValue = value; - if (oldValue && isArrayLikeObject(oldValue)) { - newValue = oldValue.push(value); + let oldValue = this.get(key); + if (oldValue) { + oldValue.push(value); + } else { + oldValue = value; } - - return this.set(key, newValue); + this.set(key, oldValue); + return this; } } diff --git a/wax-prosemirror-core/src/Config/defaultConfig.js b/wax-prosemirror-core/src/Config/defaultConfig.js index d1138e2f1..3ecd95773 100644 --- a/wax-prosemirror-core/src/Config/defaultConfig.js +++ b/wax-prosemirror-core/src/Config/defaultConfig.js @@ -1,5 +1,6 @@ import LayoutService from "../services/LayoutService/LayoutService"; +import { MenuService, RedoUndoService } from "wax-prosemirror-plugins"; export default { - services: [new LayoutService()] + services: [new LayoutService(), new MenuService(), new RedoUndoService()] }; diff --git a/wax-prosemirror-core/src/Wax.js b/wax-prosemirror-core/src/Wax.js index cdca230c3..e6cf49d29 100644 --- a/wax-prosemirror-core/src/Wax.js +++ b/wax-prosemirror-core/src/Wax.js @@ -45,6 +45,7 @@ class Wax extends Component { constructor(props) { super(props); const { config } = props; + console.log("Appp Started", config); this.application = Application.create(config); } diff --git a/wax-prosemirror-core/src/config/Config/config.js b/wax-prosemirror-core/src/config/Config/config.js deleted file mode 100644 index 3f6296f92..000000000 --- a/wax-prosemirror-core/src/config/Config/config.js +++ /dev/null @@ -1,6 +0,0 @@ -import LayoutService from "../services/LayoutService/LayoutService"; -import ConfigService from "./ConfigService"; - -export default { - services: [new LayoutService(), new ConfigService()] -}; diff --git a/wax-prosemirror-core/src/ioc-react.js b/wax-prosemirror-core/src/ioc-react.js index 538a79c51..53e818b2e 100644 --- a/wax-prosemirror-core/src/ioc-react.js +++ b/wax-prosemirror-core/src/ioc-react.js @@ -10,12 +10,15 @@ export default props => ( export function useInjection(identifier) { const { - app: { container } + app: { container }, + view } = useContext(WaxContext); if (!container) { throw new Error(); } - return container.isBound(identifier) ? container.get(identifier) : null; + return container.isBound(identifier) + ? { view, instance: container.get(identifier) } + : null; } diff --git a/wax-prosemirror-core/src/services/Config/config.js b/wax-prosemirror-core/src/services/Config/config.js deleted file mode 100644 index 7ffbb9afe..000000000 --- a/wax-prosemirror-core/src/services/Config/config.js +++ /dev/null @@ -1,6 +0,0 @@ -import LayoutService from "../../services/LayoutService/LayoutService"; -import ConfigService from "./ConfigService"; - -export default { - services: [new LayoutService(), new ConfigService()] -}; diff --git a/wax-prosemirror-core/src/services/LayoutService/Layout.js b/wax-prosemirror-core/src/services/LayoutService/Layout.js index 9fbbe4f05..734a53f7b 100644 --- a/wax-prosemirror-core/src/services/LayoutService/Layout.js +++ b/wax-prosemirror-core/src/services/LayoutService/Layout.js @@ -4,23 +4,32 @@ import LayoutFactory from "./components/LayoutFactory"; @injectable() export default class Layout { - components = {}; + components = []; layoutComponent = LayoutFactory(DefaultLayout); addComponent(renderArea, component) { - const size = this.components[renderArea].size(); + if (!this.components[renderArea]) { + this.createArea(renderArea); + } + const size = this.components[renderArea].size; this.components[renderArea].set(size + 1, component); return this; } render(renderArea) { if (!this.components[renderArea]) return null; - return this.components[renderArea].values(); + return this.getArray(this.components[renderArea]); } createArea(area) { this.components[area] = new Map(); } + getArray(iterator) { + const components = []; + iterator.forEach(component => components.push(component)); + return components; + } + setLayout(component) { this.layoutComponent = LayoutFactory(component); } diff --git a/wax-prosemirror-core/src/services/LayoutService/components/componentPlugin.js b/wax-prosemirror-core/src/services/LayoutService/components/componentPlugin.js index 283c47c08..dd8eec1f3 100644 --- a/wax-prosemirror-core/src/services/LayoutService/components/componentPlugin.js +++ b/wax-prosemirror-core/src/services/LayoutService/components/componentPlugin.js @@ -2,11 +2,14 @@ import React from "react"; import { useInjection } from "../../../ioc-react"; const ComponentPlugin = renderArea => props => { - const Layout = useInjection("Layout"); - const Components = Layout.render(renderArea); + const { view, instance } = useInjection("Layout"); - return (Components || []).map(Component => ( - <Component renderArea={renderArea} /> - )); + const components = instance.render(renderArea); + + return components + ? components.map(Component => { + return <Component view={view} />; + }) + : null; }; export default ComponentPlugin; diff --git a/wax-prosemirror-core/src/services/MenuService/Menu.js b/wax-prosemirror-core/src/services/MenuService/Menu.js deleted file mode 100644 index b4b09ca10..000000000 --- a/wax-prosemirror-core/src/services/MenuService/Menu.js +++ /dev/null @@ -1,27 +0,0 @@ -export default class Menu { - groups = new Map(); - constructor(config = []) { - - this.addGroup() - } - - addGroup(name, value) { - this.groups.set(name, value); - } - -} - - -{ - groupNanme : "Annotation", - tools: [ - {},{} - ] -} -, -{ - groupNanme : "Annotation", - tools: [ - {},{} - ] -} \ No newline at end of file diff --git a/wax-prosemirror-core/src/services/MenuService/MenuService.js b/wax-prosemirror-core/src/services/MenuService/MenuService.js deleted file mode 100644 index ed98e9525..000000000 --- a/wax-prosemirror-core/src/services/MenuService/MenuService.js +++ /dev/null @@ -1,10 +0,0 @@ -import Menu from "./Menu"; -export default class MenuService extends Services { - boot() {} - register() { - this.container - .bind("Menu") - .to(Menu) - .inSingletonScope(); - } -} diff --git a/wax-prosemirror-core/src/services/Service.js b/wax-prosemirror-core/src/services/Service.js index a7acc31eb..03bf881d7 100644 --- a/wax-prosemirror-core/src/services/Service.js +++ b/wax-prosemirror-core/src/services/Service.js @@ -9,8 +9,6 @@ export default class Service { } get config() { - return this.app.config; + return this.app.config.get(this.name); } - - boot() {} } diff --git a/wax-prosemirror-plugins/index.js b/wax-prosemirror-plugins/index.js index 1456c63fc..a8d92ad8b 100644 --- a/wax-prosemirror-plugins/index.js +++ b/wax-prosemirror-plugins/index.js @@ -1,5 +1,7 @@ export { default as TrackChangePlugin } from "./src/trackChanges/TrackChangePlugin"; export { default as FindAndReplacePlugin } from "./src/FindAndReplacePlugin"; -export { default as MenuBarPlugin } from "./src/menuBar/MenuBarPlugin"; export { default as OverlayPlugin } from "./src/overlay/OverlayPlugin"; export { default as LinkService } from "./src/LinkService/LinkService"; +export { default as MenuService } from "./src/MenuService/MenuService"; +export { default as RedoUndoService } from "./src/RedoUndoService/RedoUndoService"; +export { default as Tool } from "./src/lib/Tools"; diff --git a/wax-prosemirror-plugins/package.json b/wax-prosemirror-plugins/package.json index 7a97096f3..5cef4e552 100644 --- a/wax-prosemirror-plugins/package.json +++ b/wax-prosemirror-plugins/package.json @@ -14,6 +14,8 @@ "inversify": "^5.0.1", "inversify-inject-decorators": "^3.1.0", "reflect-metadata": "^0.1.13", - "wax-prosemirror-layouts": "^0.0.3" + "wax-prosemirror-layouts": "^0.0.3", + "wax-prosemirror-core": "^0.0.3", + "wax-prosemirror-components": "^0.0.3" } } diff --git a/wax-prosemirror-plugins/src/MenuService/Menu.js b/wax-prosemirror-plugins/src/MenuService/Menu.js new file mode 100644 index 000000000..2848c41d2 --- /dev/null +++ b/wax-prosemirror-plugins/src/MenuService/Menu.js @@ -0,0 +1,39 @@ +import React from "react"; +import { injectable } from "inversify"; +import GroupTool from "../lib/GroupTool"; + +import MenuWrapper from "./MenuWrapper"; +@injectable() +export default class Menu { + groupTools = []; + config = {}; + name = ""; + constructor(config, createTools) { + this.name = config.name; + this.config = config; + console.log(this.config, "menu config"); + this.groupTools = createTools(this.config.groupTools); + + this.excludeIncludeTools(); + } + + excludeIncludeTools() { + this.groupTools.forEach(groupTool => { + if (groupTool instanceof GroupTool) { + groupTool.excludeIncludeTools(); + } + }); + } + + render() { + return view => <MenuWrapper items={this.groupTools} view={view} />; + } +} + +// { +// templateArea: "topBar", +// tools: [ +// "redo-undo", +// { name: "Annotations", exclude: [], include: [] } +// ] +// } diff --git a/wax-prosemirror-plugins/src/MenuService/MenuCollection.js b/wax-prosemirror-plugins/src/MenuService/MenuCollection.js new file mode 100644 index 000000000..ab72fc3b5 --- /dev/null +++ b/wax-prosemirror-plugins/src/MenuService/MenuCollection.js @@ -0,0 +1,13 @@ +import { injectable, multiInject } from "inversify"; + +@injectable() +export default class MenuCollection { + menus = []; + constructor(@multiInject("Menu") menus) { + this.menus = menus; + } + + getMenu(name) { + return this.menus.find(menu => menu.name === name); + } +} diff --git a/wax-prosemirror-plugins/src/MenuService/MenuService.js b/wax-prosemirror-plugins/src/MenuService/MenuService.js new file mode 100644 index 000000000..7afc254cd --- /dev/null +++ b/wax-prosemirror-plugins/src/MenuService/MenuService.js @@ -0,0 +1,50 @@ +import { isPlainObject, isFunction } from "lodash"; +import Menu from "./Menu"; +import MenuCollection from "./MenuCollection"; +import Service from "wax-prosemirror-core/src/services/Service"; + +export default class MenuService extends Service { + name = "MenuService"; + boot() { + const { menus } = this.container.get("MenuCollection"); + const layout = this.container.get("Layout"); + menus.forEach(menu => { + layout.addComponent(menu.config.templateArea, menu.render()); + }); + } + + register() { + /* create Menu Factory */ + this.config.map(conf => { + this.container.bind("Menu").toFactory(context => { + return new Menu(conf, context.container.get("createTools")); + }); + }); + + /*create MenuCollection of Menus */ + this.container + .bind("MenuCollection") + .to(MenuCollection) + .inSingletonScope(); + + /* create factory of tools */ + this.container.bind("createTools").toFactory(context => { + return configTools => { + const tools = []; + configTools.forEach(tool => { + let tl = {}; + if (isPlainObject(tool)) { + tl = context.container.get(tool.name); + tl.setGroupConfig(tool); + } else if (isFunction(tool)) { + tl = context.container.get(tool()); + } else { + tl = context.container.get(tool); + } + tools.push(tl); + }); + return tools; + }; + }); + } +} diff --git a/wax-prosemirror-plugins/src/MenuService/MenuWrapper.js b/wax-prosemirror-plugins/src/MenuService/MenuWrapper.js new file mode 100644 index 000000000..6c2bf21b9 --- /dev/null +++ b/wax-prosemirror-plugins/src/MenuService/MenuWrapper.js @@ -0,0 +1,20 @@ +import React from "react"; +import styled from "styled-components"; +import { useContext } from "react"; + +import { map } from "lodash"; + +const MainMenu = styled.div` + background: #fff; + padding: 2px 2px 2px 0; + position: relative; + background: transparent; +`; + +const MainMenuBar = ({ items = [], view }) => ( + <MainMenu key="MainMenu"> + {map(items, item => item.renderTools(view))} + </MainMenu> +); + +export default MainMenuBar; diff --git a/wax-prosemirror-plugins/src/RedoUndoService/Redo.js b/wax-prosemirror-plugins/src/RedoUndoService/Redo.js new file mode 100644 index 000000000..386932ba2 --- /dev/null +++ b/wax-prosemirror-plugins/src/RedoUndoService/Redo.js @@ -0,0 +1,18 @@ +import { redo } from "prosemirror-history"; +import Tools from "../lib/Tools"; +import { injectable } from "inversify"; +import { icons } from "wax-prosemirror-components"; + +@injectable() +export default class Redo extends Tools { + title = "Redo last undone change"; + content = icons.redo; + + get run() { + return redo; + } + + get enable() { + return redo; + } +} diff --git a/wax-prosemirror-plugins/src/RedoUndoService/RedoUndo.js b/wax-prosemirror-plugins/src/RedoUndoService/RedoUndo.js new file mode 100644 index 000000000..7c9242bc7 --- /dev/null +++ b/wax-prosemirror-plugins/src/RedoUndoService/RedoUndo.js @@ -0,0 +1,19 @@ +import { injectable, inject } from "inversify"; +import GroupTool from "../lib/GroupTool"; + +@injectable() +export default class RedoUndo extends GroupTool { + tools = []; + constructor(@inject("Redo") redo, @inject("Undo") undo) { + super(); + this.tools = [redo, undo]; + } + + renderTools(view) { + const tools = []; + this.tools.forEach(tool => { + tools.push(tool.renderTool(view)); + }); + return tools; + } +} diff --git a/wax-prosemirror-plugins/src/RedoUndoService/RedoUndoService.js b/wax-prosemirror-plugins/src/RedoUndoService/RedoUndoService.js new file mode 100644 index 000000000..477b33392 --- /dev/null +++ b/wax-prosemirror-plugins/src/RedoUndoService/RedoUndoService.js @@ -0,0 +1,15 @@ +import RedoUndo from "./RedoUndo"; +import Service from "wax-prosemirror-core/src/services/Service"; +import Redo from "./Redo"; +import Undo from "./Undo"; + +export default class RedoService extends Service { + name = "RedoService"; + + register() { + this.container.bind("RedoUndo").to(RedoUndo); + + this.container.bind("Redo").to(Redo); + this.container.bind("Undo").to(Undo); + } +} diff --git a/wax-prosemirror-plugins/src/RedoUndoService/Undo.js b/wax-prosemirror-plugins/src/RedoUndoService/Undo.js new file mode 100644 index 000000000..9d07b6c25 --- /dev/null +++ b/wax-prosemirror-plugins/src/RedoUndoService/Undo.js @@ -0,0 +1,18 @@ +import { undo } from "prosemirror-history"; +import Tools from "../lib/Tools"; +import { injectable } from "inversify"; +import { icons } from "wax-prosemirror-components"; + +@injectable() +export default class Undo extends Tools { + title = "Undo last change"; + content = icons.undo; + + get run() { + return undo; + } + + get enable() { + return undo; + } +} diff --git a/wax-prosemirror-plugins/src/lib/GroupTool.js b/wax-prosemirror-plugins/src/lib/GroupTool.js new file mode 100644 index 000000000..19885aaa4 --- /dev/null +++ b/wax-prosemirror-plugins/src/lib/GroupTool.js @@ -0,0 +1,29 @@ +import { injectable } from "inversify"; + +@injectable() +export default class GroupTool { + _config = {}; + constructor() {} + setGroupConfig(config) { + this._config = config; + } + excludeIncludeTools() { + const { exclude = [], include = [] } = this._config; + + if (include.length > 0) { + this.tools.map(tool => { + if (include.includes(tool.constructor.name)) { + tool.enable(); + } else { + tool.disable(); + } + }); + } else { + this.tools.map(tool => { + if (exclude.includes(tool.constructor.name)) { + tool.disable(); + } + }); + } + } +} diff --git a/wax-prosemirror-plugins/src/lib/Tools.js b/wax-prosemirror-plugins/src/lib/Tools.js new file mode 100644 index 000000000..79eaadb92 --- /dev/null +++ b/wax-prosemirror-plugins/src/lib/Tools.js @@ -0,0 +1,48 @@ +import React from "react"; +import { v4 as uuid } from "uuid"; +import { injectable } from "inversify"; +import { Button } from "wax-prosemirror-components"; + +@injectable() +export default class Tools { + title = "title"; + content = "content"; + + _isEnabled = true; + + get run() { + return true; + } + + get enable() { + return true; + } + + select() { + return () => true; + } + + toJSON() { + return { + title: this.title, + content: this.content, + run: this.run, + enable: () => this.enable, + select: this.select + }; + } + + renderTool(view) { + return this._isEnabled ? ( + <Button key={uuid()} item={this.toJSON()} {...view} /> + ) : null; + } + + disable() { + this._isEnabled = false; + } + + enable() { + this._isEnabled = true; + } +} -- GitLab