From 6cdddb9add9243bd5ece61a96792fd30cc335dbb Mon Sep 17 00:00:00 2001
From: Giannis Kopanas <jkopanas@gmail.com>
Date: Fri, 22 Nov 2019 22:58:45 +0200
Subject: [PATCH] feat(services): add services

---
 editors/editoria/config-overrides.js          |   6 +-
 editors/editoria/jsconfig.json                |   5 +
 editors/editoria/package.json                 |   3 +-
 editors/editoria/src/EditorConfig.js          |   8 +-
 editors/editoria/src/Editoria.js              |   5 +-
 package.json                                  |   7 +-
 wax-prosemirror-components/index.js           |   2 +-
 .../src/components/componentPlugin.js         |  28 -----
 wax-prosemirror-core/index.js                 |   1 +
 wax-prosemirror-core/package.json             |   5 +-
 wax-prosemirror-core/src/Wax.js               |  22 +++-
 wax-prosemirror-core/src/componentPlugin.js   |  16 +++
 wax-prosemirror-core/src/ioc-react.js         |  24 ++++
 wax-prosemirror-core/src/ioc.js               |   6 +
 wax-prosemirror-plugins/index.js              |   2 +
 wax-prosemirror-plugins/package.json          |   5 +-
 .../src/LayoutService/Layout.js               |  17 +++
 .../src/LayoutService/LayoutService.js        |  11 ++
 .../src/LinkService/LinkPlugin.js             |  40 +++++++
 .../src/LinkService/LinkService.js            |  21 ++++
 .../src/LinkService/pmPlugins/find.js         |  14 +++
 .../src/LinkService/pmPlugins/placeholder.js  |  14 +++
 wax-prosemirror-plugins/src/Service.js        |   9 ++
 .../src/overlay/OverlayPlugin.js              | 111 ++++++++----------
 24 files changed, 277 insertions(+), 105 deletions(-)
 create mode 100644 editors/editoria/jsconfig.json
 delete mode 100644 wax-prosemirror-components/src/components/componentPlugin.js
 create mode 100644 wax-prosemirror-core/src/componentPlugin.js
 create mode 100644 wax-prosemirror-core/src/ioc-react.js
 create mode 100644 wax-prosemirror-core/src/ioc.js
 create mode 100644 wax-prosemirror-plugins/src/LayoutService/Layout.js
 create mode 100644 wax-prosemirror-plugins/src/LayoutService/LayoutService.js
 create mode 100644 wax-prosemirror-plugins/src/LinkService/LinkPlugin.js
 create mode 100644 wax-prosemirror-plugins/src/LinkService/LinkService.js
 create mode 100644 wax-prosemirror-plugins/src/LinkService/pmPlugins/find.js
 create mode 100644 wax-prosemirror-plugins/src/LinkService/pmPlugins/placeholder.js
 create mode 100644 wax-prosemirror-plugins/src/Service.js

diff --git a/editors/editoria/config-overrides.js b/editors/editoria/config-overrides.js
index 82c74c17d..e2cf94482 100644
--- a/editors/editoria/config-overrides.js
+++ b/editors/editoria/config-overrides.js
@@ -12,7 +12,11 @@ module.exports = function override(config, env) {
                 [require("@babel/preset-env"), { modules: false }],
                 require("@babel/preset-react")
               ],
-              plugins: [require("@babel/plugin-proposal-class-properties")]
+              plugins: [
+                ["@babel/plugin-proposal-decorators", { legacy: true }],
+                "babel-plugin-parameter-decorator",
+                ["@babel/plugin-proposal-class-properties", { loose: true }]
+              ]
             }
           },
           {
diff --git a/editors/editoria/jsconfig.json b/editors/editoria/jsconfig.json
new file mode 100644
index 000000000..504cd646e
--- /dev/null
+++ b/editors/editoria/jsconfig.json
@@ -0,0 +1,5 @@
+{
+  "compilerOptions": {
+    "experimentalDecorators": true
+  }
+}
diff --git a/editors/editoria/package.json b/editors/editoria/package.json
index 84d3efed8..820265276 100644
--- a/editors/editoria/package.json
+++ b/editors/editoria/package.json
@@ -13,7 +13,8 @@
     "wax-prosemirror-core": "^0.0.3",
     "wax-prosemirror-layouts": "^0.0.3",
     "wax-prosemirror-schema": "^0.0.3",
-    "wax-prosemirror-themes": "^0.0.3"
+    "wax-prosemirror-themes": "^0.0.3",
+    "babel-plugin-parameter-decorator": "1.0.12"
   },
   "scripts": {
     "start": "react-app-rewired start",
diff --git a/editors/editoria/src/EditorConfig.js b/editors/editoria/src/EditorConfig.js
index e0d225b71..4dbf29f8b 100644
--- a/editors/editoria/src/EditorConfig.js
+++ b/editors/editoria/src/EditorConfig.js
@@ -31,7 +31,9 @@ import {
   LinkToolTipPlugin,
   FindAndReplacePlugin,
   TrackChangePlugin,
-  MenuBarPlugin
+  MenuBarPlugin,
+  LinkService,
+  LayoutService
 } from "wax-prosemirror-plugins";
 
 import { MainMenuBar, SideMenuBar } from "wax-prosemirror-components";
@@ -98,7 +100,9 @@ const plugins = [
   })
 ];
 
+const services = [new LayoutService(), new LinkService()];
+
 // Add Rules
 const rules = [emDash, ellipsis];
 
-export { schema, keys, plugins, rules };
+export { schema, keys, plugins, rules, services };
diff --git a/editors/editoria/src/Editoria.js b/editors/editoria/src/Editoria.js
index 594b9b630..dd3b7e463 100644
--- a/editors/editoria/src/Editoria.js
+++ b/editors/editoria/src/Editoria.js
@@ -3,7 +3,7 @@ import styled, { createGlobalStyle } from "styled-components";
 
 import { setLayout } from "wax-prosemirror-core";
 
-import { schema, keys, plugins, rules } from "./EditorConfig";
+import { schema, keys, plugins, rules, services } from "./EditorConfig";
 
 import text from "./text";
 
@@ -11,7 +11,8 @@ const options = {
   schema,
   plugins,
   keys,
-  rules
+  rules,
+  services
 };
 
 const GlobalStyle = createGlobalStyle`
diff --git a/package.json b/package.json
index f58069cda..090c5c4d7 100644
--- a/package.json
+++ b/package.json
@@ -3,8 +3,7 @@
   "version": "0.0.1",
   "main": "index.js",
   "author": "Collaborative Knowledge Foundation",
-  "description":
-    "Monorepo for wax-prosemirror, its components and its integrations",
+  "description": "Monorepo for wax-prosemirror, its components and its integrations",
   "repository": {
     "type": "git",
     "url": "git@gitlab.coko.foundation:wax/wax-prosemirror.git"
@@ -13,8 +12,7 @@
   "private": true,
   "scripts": {
     "bootstrap": "lerna bootstrap --no-ci --hoist",
-    "clean":
-      "yarn run clean:artifacts && yarn run clean:packages && yarn run clean:root",
+    "clean": "yarn run clean:artifacts && yarn run clean:packages && yarn run clean:root",
     "clean:artifacts": "lerna run clean --parallel",
     "clean:packages": "lerna clean --yes",
     "clean:root": "rm -rf node_modules",
@@ -26,6 +24,7 @@
   "dependencies": {},
   "devDependencies": {
     "@babel/plugin-proposal-class-properties": "^7.0.0",
+    "@babel/plugin-proposal-decorators": "^7.0.0",
     "@babel/preset-env": "^7.0.0",
     "@babel/preset-react": "^7.0.0",
     "css-loader": "^0.28.11",
diff --git a/wax-prosemirror-components/index.js b/wax-prosemirror-components/index.js
index 57975b195..64873c033 100644
--- a/wax-prosemirror-components/index.js
+++ b/wax-prosemirror-components/index.js
@@ -1,5 +1,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 componentPlugin } from "./src/components/componentPlugin";
+export { default as componentPlugin } from "wax-prosemirror-core/src/componentPlugin";
 export { default as Overlay } from "./src/components/Overlay";
diff --git a/wax-prosemirror-components/src/components/componentPlugin.js b/wax-prosemirror-components/src/components/componentPlugin.js
deleted file mode 100644
index c9d2ba14b..000000000
--- a/wax-prosemirror-components/src/components/componentPlugin.js
+++ /dev/null
@@ -1,28 +0,0 @@
-import React from "react";
-import WaxContext from "wax-prosemirror-core/src/helpers/WaxContext";
-
-const ComponentPlugin = renderArea => props => (
-  <WaxContext.Consumer>
-    {context => {
-      const { state = { plugins: [] } } = context.view;
-      const pluginComponent = state.plugins.map(plugin => {
-        if (
-          state[plugin.key] &&
-          state[plugin.key].renderArea === renderArea &&
-          state[plugin.key].component
-        ) {
-          const Component = state[plugin.key].component;
-          return (
-            <Component key={plugin.key} view={context.view} state={state} />
-          );
-        }
-
-        return null;
-      });
-
-      return pluginComponent;
-    }}
-  </WaxContext.Consumer>
-);
-
-export default ComponentPlugin;
diff --git a/wax-prosemirror-core/index.js b/wax-prosemirror-core/index.js
index a9e4bb31a..47330de98 100644
--- a/wax-prosemirror-core/index.js
+++ b/wax-prosemirror-core/index.js
@@ -3,3 +3,4 @@ export { default as CreateSchema } from "./src/config/classes/CreateSchema";
 export { default as setLayout } from "./src/helpers/setLayout";
 export { default as CreateShortCuts } from "./src/config/classes/CreateShortCuts";
 export { default as WaxContext } from "./src/helpers/WaxContext";
+export { default as Container } from "./src/ioc";
diff --git a/wax-prosemirror-core/package.json b/wax-prosemirror-core/package.json
index ceb04f8d0..45b97b43b 100644
--- a/wax-prosemirror-core/package.json
+++ b/wax-prosemirror-core/package.json
@@ -23,7 +23,10 @@
     "prosemirror-view": "^1.13.4",
     "react": "^16.8.6",
     "react-dom": "^16.8.6",
-    "styled-components": "^4.2.0"
+    "styled-components": "^4.2.0",
+    "inversify": "^5.0.1",
+    "inversify-inject-decorators": "^3.1.0",
+    "reflect-metadata": "^0.1.13"
   },
   "devDependencies": {
     "mocha": "^3.4.2",
diff --git a/wax-prosemirror-core/src/Wax.js b/wax-prosemirror-core/src/Wax.js
index e1657c505..9da883db8 100644
--- a/wax-prosemirror-core/src/Wax.js
+++ b/wax-prosemirror-core/src/Wax.js
@@ -1,11 +1,13 @@
 import React, { Component } from "react";
+import WaxProvider from "./ioc-react";
+import container from "./ioc";
+
 import debounce from "lodash/debounce";
 import styled from "styled-components";
 
 import { DOMParser, DOMSerializer } from "prosemirror-model";
 import { DefaultLayout } from "wax-prosemirror-layouts";
 
-import WaxContext from "./helpers/WaxContext";
 import WaxView from "./WaxView";
 import defaultPlugins from "./config/defaultPlugins";
 import placeholder from "./config/plugins/placeholder";
@@ -42,7 +44,7 @@ const LayoutWrapper = styled.div`
 class Wax extends Component {
   componentWillMount() {
     const { value, onChange, options } = this.props;
-    const { schema, plugins, keys, rules } = options;
+    const { schema, plugins, keys, rules, services } = options;
     const WaxOnchange = onChange ? onChange : value => true;
 
     const WaxShortCuts = keys
@@ -61,6 +63,12 @@ class Wax extends Component {
       WaxRules
     ]);
 
+    services.map(plugin => {
+      if (plugin.register) {
+        plugin.register();
+      }
+    });
+
     this.WaxOptions = {
       schema,
       plugins: finalPlugins
@@ -70,6 +78,12 @@ class Wax extends Component {
     const serialize = serializer(schema);
     this.WaxOptions.doc = parse(editorContent);
 
+    services.map(plugin => {
+      if (plugin.register) {
+        plugin.boot();
+      }
+    });
+
     this.onChange = debounce(
       value => {
         WaxOnchange(serialize(value));
@@ -115,9 +129,9 @@ class Wax extends Component {
           user={user}
         >
           {({ view, editor }) => (
-            <WaxContext.Provider value={{ view }}>
+            <WaxProvider view={view} container={container}>
               <WaxRender editor={editor} />
-            </WaxContext.Provider>
+            </WaxProvider>
           )}
         </WaxView>
       </LayoutWrapper>
diff --git a/wax-prosemirror-core/src/componentPlugin.js b/wax-prosemirror-core/src/componentPlugin.js
new file mode 100644
index 000000000..8a44c7a93
--- /dev/null
+++ b/wax-prosemirror-core/src/componentPlugin.js
@@ -0,0 +1,16 @@
+import React from "react";
+import { useInjection } from "./ioc-react";
+
+const ComponentPlugin = renderArea => props => {
+  const Layout = useInjection("Layout");
+  console.log(Layout);
+  const { Component } = Layout.render(renderArea);
+
+  return Component ? <Component renderArea={renderArea} /> : null;
+  return Component.map(Component =>
+    Component.renderArea === renderArea ? (
+      <Component.component renderArea={renderArea} />
+    ) : null
+  );
+};
+export default ComponentPlugin;
diff --git a/wax-prosemirror-core/src/ioc-react.js b/wax-prosemirror-core/src/ioc-react.js
new file mode 100644
index 000000000..8f82eec3d
--- /dev/null
+++ b/wax-prosemirror-core/src/ioc-react.js
@@ -0,0 +1,24 @@
+import React, { useContext } from "react";
+
+const WaxContext = React.createContext({ view: null, container: null });
+
+export default props => {
+  console.log(props);
+  return (
+    <WaxContext.Provider
+      value={{ container: props.container, view: props.view }}
+    >
+      {props.children}
+    </WaxContext.Provider>
+  );
+};
+
+export function useInjection(identifier) {
+  const { container } = useContext(WaxContext);
+
+  if (!container) {
+    throw new Error();
+  }
+
+  return container.isBound(identifier) ? container.get(identifier) : null;
+}
diff --git a/wax-prosemirror-core/src/ioc.js b/wax-prosemirror-core/src/ioc.js
new file mode 100644
index 000000000..5e07d5aee
--- /dev/null
+++ b/wax-prosemirror-core/src/ioc.js
@@ -0,0 +1,6 @@
+import { Container } from "inversify";
+import "reflect-metadata";
+
+const container = new Container();
+
+export default container;
diff --git a/wax-prosemirror-plugins/index.js b/wax-prosemirror-plugins/index.js
index 47d507af1..07e822af8 100644
--- a/wax-prosemirror-plugins/index.js
+++ b/wax-prosemirror-plugins/index.js
@@ -2,3 +2,5 @@ export { default as TrackChangePlugin } from "./src/trackChanges/TrackChangePlug
 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 LayoutService } from "./src/LayoutService/LayoutService";
+export { default as LinkService } from "./src/LinkService/LinkService";
diff --git a/wax-prosemirror-plugins/package.json b/wax-prosemirror-plugins/package.json
index eedc5ee50..76421fc64 100644
--- a/wax-prosemirror-plugins/package.json
+++ b/wax-prosemirror-plugins/package.json
@@ -10,6 +10,9 @@
   },
   "dependencies": {
     "prosemirror-state": "^1.2.2",
-    "prosemirror-view": "^1.13.1"
+    "prosemirror-view": "^1.13.1",
+    "inversify": "^5.0.1",
+    "inversify-inject-decorators": "^3.1.0",
+    "reflect-metadata": "^0.1.13"
   }
 }
diff --git a/wax-prosemirror-plugins/src/LayoutService/Layout.js b/wax-prosemirror-plugins/src/LayoutService/Layout.js
new file mode 100644
index 000000000..f88b2244e
--- /dev/null
+++ b/wax-prosemirror-plugins/src/LayoutService/Layout.js
@@ -0,0 +1,17 @@
+import { injectable, multiInject } from "inversify";
+
+@injectable()
+export default class Layout {
+  constructor() {
+    this.components = new Map();
+  }
+
+  addComponent(renderArea, component) {
+    this.components.set(renderArea, component);
+    return this;
+  }
+
+  render(renderArea) {
+    return { Component: this.components.get(renderArea) };
+  }
+}
diff --git a/wax-prosemirror-plugins/src/LayoutService/LayoutService.js b/wax-prosemirror-plugins/src/LayoutService/LayoutService.js
new file mode 100644
index 000000000..b98b5fb9e
--- /dev/null
+++ b/wax-prosemirror-plugins/src/LayoutService/LayoutService.js
@@ -0,0 +1,11 @@
+import Service from "../Service";
+import Layout from "./Layout";
+export default class LayoutService extends Service {
+  name = "LayoutService";
+  register() {
+    this.container
+      .bind("Layout")
+      .to(Layout)
+      .inSingletonScope();
+  }
+}
diff --git a/wax-prosemirror-plugins/src/LinkService/LinkPlugin.js b/wax-prosemirror-plugins/src/LinkService/LinkPlugin.js
new file mode 100644
index 000000000..206e598df
--- /dev/null
+++ b/wax-prosemirror-plugins/src/LinkService/LinkPlugin.js
@@ -0,0 +1,40 @@
+import React from "react";
+import { injectable, multiInject, inject, named } from "inversify";
+
+const Component1 = props => <div>{props.renderArea}</div>;
+const Component2 = props => <div>{props.renderArea}</div>;
+
+@injectable()
+export default class LinkPlugin {
+  items = [
+    {
+      link: "1",
+      link2: "3"
+    },
+    {
+      link: "2",
+      link2: "4"
+    }
+  ];
+  plugins = [];
+
+  constructor(
+    @inject("Layout") layout,
+    @inject("findPlugin") find,
+    @inject("placeholderPlugin") placeholder
+  ) {
+    this.find = find;
+    this.placeholder = placeholder;
+
+    //console.log(this.find, this.placeholder);
+    layout
+      .addComponent("topBar", Component2)
+      .addComponent("leftSideBar", Component1);
+
+    this.initPlugins();
+  }
+
+  initPlugins() {
+    this.plugins = [this.placeholder(this.items[1]), this.find("s")];
+  }
+}
diff --git a/wax-prosemirror-plugins/src/LinkService/LinkService.js b/wax-prosemirror-plugins/src/LinkService/LinkService.js
new file mode 100644
index 000000000..6d2900ab0
--- /dev/null
+++ b/wax-prosemirror-plugins/src/LinkService/LinkService.js
@@ -0,0 +1,21 @@
+import LinkPlugin from "./LinkPlugin";
+import Service from "../Service";
+import find from "./pmPlugins/find";
+import placeholder from "./pmPlugins/placeholder";
+
+export default class myLinkPluginService extends Service {
+  name = "LinkPlugin";
+
+  boot() {
+    const test = this.container.get("LinkPlugin");
+    console.log(test);
+  }
+
+  register() {
+    this.container.bind(this.name).to(LinkPlugin);
+
+    this.container.bind("findPlugin").toFactory(find);
+
+    this.container.bind("placeholderPlugin").toFactory(placeholder);
+  }
+}
diff --git a/wax-prosemirror-plugins/src/LinkService/pmPlugins/find.js b/wax-prosemirror-plugins/src/LinkService/pmPlugins/find.js
new file mode 100644
index 000000000..4a6d8bbb5
--- /dev/null
+++ b/wax-prosemirror-plugins/src/LinkService/pmPlugins/find.js
@@ -0,0 +1,14 @@
+import { Plugin, PluginKey } from "prosemirror-state";
+export const findLink = new PluginKey("findLink");
+
+export default items => {
+  return () =>
+    new Plugin({
+      key: findLink,
+      state: {
+        init() {
+          return items;
+        }
+      }
+    });
+};
diff --git a/wax-prosemirror-plugins/src/LinkService/pmPlugins/placeholder.js b/wax-prosemirror-plugins/src/LinkService/pmPlugins/placeholder.js
new file mode 100644
index 000000000..6ca4468e4
--- /dev/null
+++ b/wax-prosemirror-plugins/src/LinkService/pmPlugins/placeholder.js
@@ -0,0 +1,14 @@
+import { Plugin, PluginKey } from "prosemirror-state";
+export const placeholderLink = new PluginKey("placeholderLink");
+
+export default items => {
+  return () =>
+    new Plugin({
+      key: placeholderLink,
+      state: {
+        init() {
+          return items;
+        }
+      }
+    });
+};
diff --git a/wax-prosemirror-plugins/src/Service.js b/wax-prosemirror-plugins/src/Service.js
new file mode 100644
index 000000000..d3c2e4603
--- /dev/null
+++ b/wax-prosemirror-plugins/src/Service.js
@@ -0,0 +1,9 @@
+import { Container } from "wax-prosemirror-core";
+
+export default class Service {
+  constructor() {
+    this.container = Container;
+  }
+
+  boot() {}
+}
diff --git a/wax-prosemirror-plugins/src/overlay/OverlayPlugin.js b/wax-prosemirror-plugins/src/overlay/OverlayPlugin.js
index deda62777..f923f2906 100644
--- a/wax-prosemirror-plugins/src/overlay/OverlayPlugin.js
+++ b/wax-prosemirror-plugins/src/overlay/OverlayPlugin.js
@@ -27,63 +27,54 @@ const OverlayPlugin = args => {
 
 export default OverlayPlugin;
 
-
-reactComponent 
-
-overlayPlugin position 
-
-linkPlugin showhide
-
-
-linkPlugin = createplugin (reactComponent, overlay)
-
-
-
-const createPlugin = (reactComponent, overlayPlugin) => {
-
-  return new Plugin ({
-     key,
-     state,
-     view,
-  })
-}
-
-createPlugin = () => class {
-  name: "test",
-  renderArea,
-  component: () => {},
-  itemsMenus: [],
-  plugins: [plugin, plugin]
-}
-
-
-
-class createPlugin {
-  constructor() {
-    this.name
-    this.plugins.push(overlayPlugin(Component, showCommand))
-  }
-  plugins () { return []}
-}
-
-
-class waxPlugin {
-  constructor() {
-    this.name 
-    
-  }
-
-  createPlugin () {
-    
-  }
-}
-
-class linkPlugin extends waxPlugin {
-  component:
-  renderArea:
-  showCommand:
-  itemsMenus:
-  
-}
-
-new(OverlayPlugin)
\ No newline at end of file
+// reactComponent
+
+// overlayPlugin position
+
+// linkPlugin showhide
+
+// linkPlugin = createplugin(reactComponent, overlay);
+
+// const createPlugin = (reactComponent, overlayPlugin) => {
+//   return new Plugin({
+//     key,
+//     state,
+//     view
+//   });
+// };
+
+// createPlugin = () => class {
+//   name: "test",
+//   renderArea,
+//   component: () => {},
+//   itemsMenus: [],
+//   plugins: [plugin, plugin]
+// }
+
+// class createPlugin {
+//   constructor() {
+//     this.name;
+//     this.plugins.push(overlayPlugin(Component, showCommand));
+//   }
+//   plugins() {
+//     return [];
+//   }
+// }
+
+// class waxPlugin {
+//   constructor() {
+//     this.name;
+//   }
+
+//   createPlugin() {}
+// }
+
+// class linkPlugin extends waxPlugin {
+//   component:
+//   renderArea:
+//   showCommand:
+//   itemsMenus:
+
+// }
+
+// new(OverlayPlugin)
-- 
GitLab