From e999d55dc0b70b05eb94519d42d549f688a07e4a Mon Sep 17 00:00:00 2001
From: chris <kokosias@yahoo.gr>
Date: Thu, 16 Mar 2023 18:26:14 +0200
Subject: [PATCH] add new files

---
 .../ExternalAPIContentService/AnyStyleTool.js | 69 +++++++++++++++++++
 .../AnyStyleToolGroupService/AnyStyle.js      | 13 ++++
 .../AnyStyleToolGroupService.js               | 10 +++
 .../ExternalAPIContentService.js              | 24 +++++++
 .../ExternalAPIContentService/anyStyle.css    |  5 ++
 .../components/ExternalApiButton.js           | 58 ++++++++++++++++
 .../plugins/AnyStylePlaceHolderPlugin.js      | 37 ++++++++++
 .../ExternalAPIContentService/replaceText.js  | 62 +++++++++++++++++
 8 files changed, 278 insertions(+)
 create mode 100644 wax-prosemirror-services/src/ExternalAPIContentService/AnyStyleTool.js
 create mode 100644 wax-prosemirror-services/src/ExternalAPIContentService/AnyStyleToolGroupService/AnyStyle.js
 create mode 100644 wax-prosemirror-services/src/ExternalAPIContentService/AnyStyleToolGroupService/AnyStyleToolGroupService.js
 create mode 100644 wax-prosemirror-services/src/ExternalAPIContentService/ExternalAPIContentService.js
 create mode 100644 wax-prosemirror-services/src/ExternalAPIContentService/anyStyle.css
 create mode 100644 wax-prosemirror-services/src/ExternalAPIContentService/components/ExternalApiButton.js
 create mode 100644 wax-prosemirror-services/src/ExternalAPIContentService/plugins/AnyStylePlaceHolderPlugin.js
 create mode 100644 wax-prosemirror-services/src/ExternalAPIContentService/replaceText.js

diff --git a/wax-prosemirror-services/src/ExternalAPIContentService/AnyStyleTool.js b/wax-prosemirror-services/src/ExternalAPIContentService/AnyStyleTool.js
new file mode 100644
index 000000000..f3bdb1cd8
--- /dev/null
+++ b/wax-prosemirror-services/src/ExternalAPIContentService/AnyStyleTool.js
@@ -0,0 +1,69 @@
+import React, { useContext } from 'react';
+import { v4 as uuidv4 } from 'uuid';
+import { isEmpty } from 'lodash';
+import { injectable } from 'inversify';
+import { WaxContext, Commands, Tools } from 'wax-prosemirror-core';
+import ExternalApiButton from './components/ExternalApiButton';
+import replaceText from './replaceText';
+
+@injectable()
+class AnyStyleTool extends Tools {
+  title = 'ChatGPT';
+  name = 'ChatGPT';
+  label = 'ChatGPT';
+
+  get run() {
+    return true;
+  }
+
+  select = activeView => {
+    return true;
+  };
+
+  get enable() {
+    return state => {
+      return true;
+    };
+  }
+
+  renderTool(view) {
+    if (isEmpty(view)) return null;
+    const context = useContext(WaxContext);
+    const anyStyle = replaceText(
+      view,
+      this.config.get('config.ExternalAPIContentService')
+        .ExternalAPIContentTransformation,
+      this.pmplugins.get('anyStylePlaceHolder'),
+      context,
+    );
+    return this.isDisplayed() ? (
+      <ExternalApiButton
+        anyStyle={anyStyle}
+        item={this.toJSON()}
+        key={uuidv4()}
+        view={view}
+      />
+    ) : null;
+  }
+
+  //   renderTool(view) {
+  //     if (isEmpty(view)) return null;
+  //     const context = useContext(WaxContext);
+  //     const upload = fileUpload(
+  //       view,
+  //       this.config.get('fileUpload'),
+  //       this.pmplugins.get('imagePlaceHolder'),
+  //       context,
+  //     );
+  //     return this.isDisplayed() ? (
+  //       <ImageUpload
+  //         fileUpload={upload}
+  //         item={this.toJSON()}
+  //         key={uuidv4()}
+  //         view={view}
+  //       />
+  //     ) : null;
+  //   }
+}
+
+export default AnyStyleTool;
diff --git a/wax-prosemirror-services/src/ExternalAPIContentService/AnyStyleToolGroupService/AnyStyle.js b/wax-prosemirror-services/src/ExternalAPIContentService/AnyStyleToolGroupService/AnyStyle.js
new file mode 100644
index 000000000..57217fd67
--- /dev/null
+++ b/wax-prosemirror-services/src/ExternalAPIContentService/AnyStyleToolGroupService/AnyStyle.js
@@ -0,0 +1,13 @@
+import { injectable, inject } from 'inversify';
+import { ToolGroup } from 'wax-prosemirror-core';
+
+@injectable()
+class Anystyle extends ToolGroup {
+  tools = [];
+  constructor(@inject('AnyStyleTool') anyStyleTool) {
+    super();
+    this.tools = [anyStyleTool];
+  }
+}
+
+export default Anystyle;
diff --git a/wax-prosemirror-services/src/ExternalAPIContentService/AnyStyleToolGroupService/AnyStyleToolGroupService.js b/wax-prosemirror-services/src/ExternalAPIContentService/AnyStyleToolGroupService/AnyStyleToolGroupService.js
new file mode 100644
index 000000000..703a4688e
--- /dev/null
+++ b/wax-prosemirror-services/src/ExternalAPIContentService/AnyStyleToolGroupService/AnyStyleToolGroupService.js
@@ -0,0 +1,10 @@
+import { Service } from 'wax-prosemirror-core';
+import AnyStyle from './AnyStyle';
+
+class AnyStyleToolGroupService extends Service {
+  register() {
+    this.container.bind('AnyStyle').to(AnyStyle);
+  }
+}
+
+export default AnyStyleToolGroupService;
diff --git a/wax-prosemirror-services/src/ExternalAPIContentService/ExternalAPIContentService.js b/wax-prosemirror-services/src/ExternalAPIContentService/ExternalAPIContentService.js
new file mode 100644
index 000000000..5d6012349
--- /dev/null
+++ b/wax-prosemirror-services/src/ExternalAPIContentService/ExternalAPIContentService.js
@@ -0,0 +1,24 @@
+import { Service } from 'wax-prosemirror-core';
+import AnyStyleTool from './AnyStyleTool';
+import AnyStyleToolGroupService from './AnyStyleToolGroupService/AnyStyleToolGroupService';
+import AnyStylePlaceHolderPlugin from './plugins/AnyStylePlaceHolderPlugin';
+import './anyStyle.css';
+
+class ExternalAPIContentService extends Service {
+  name = 'ExternalAPIContentService';
+
+  boot() {
+    this.app.PmPlugins.add(
+      'anyStylePlaceHolder',
+      AnyStylePlaceHolderPlugin('anyStylePlaceHolder'),
+    );
+  }
+
+  register() {
+    this.container.bind('AnyStyleTool').to(AnyStyleTool);
+  }
+
+  dependencies = [new AnyStyleToolGroupService()];
+}
+
+export default ExternalAPIContentService;
diff --git a/wax-prosemirror-services/src/ExternalAPIContentService/anyStyle.css b/wax-prosemirror-services/src/ExternalAPIContentService/anyStyle.css
new file mode 100644
index 000000000..ef4885cbd
--- /dev/null
+++ b/wax-prosemirror-services/src/ExternalAPIContentService/anyStyle.css
@@ -0,0 +1,5 @@
+placeholder-any-style:before {
+    position: relative;
+    top: 3px;
+    content: url("data:image/svg+xml; utf8, <svg xmlns='http://www.w3.org/2000/svg' height='24' width='24'><path d='M8 20h8v-3q0-1.65-1.175-2.825Q13.65 13 12 13q-1.65 0-2.825 1.175Q8 15.35 8 17Zm-4 2v-2h2v-3q0-1.525.713-2.863Q7.425 12.8 8.7 12q-1.275-.8-1.987-2.138Q6 8.525 6 7V4H4V2h16v2h-2v3q0 1.525-.712 2.862Q16.575 11.2 15.3 12q1.275.8 1.988 2.137Q18 15.475 18 17v3h2v2Z' /></svg>");
+}
\ No newline at end of file
diff --git a/wax-prosemirror-services/src/ExternalAPIContentService/components/ExternalApiButton.js b/wax-prosemirror-services/src/ExternalAPIContentService/components/ExternalApiButton.js
new file mode 100644
index 000000000..2ac05fa10
--- /dev/null
+++ b/wax-prosemirror-services/src/ExternalAPIContentService/components/ExternalApiButton.js
@@ -0,0 +1,58 @@
+/* eslint react/prop-types: 0 */
+import React, { useContext, useMemo, useEffect } from 'react';
+import { WaxContext, DocumentHelpers, MenuButton } from 'wax-prosemirror-core';
+import { TextSelection } from 'prosemirror-state';
+
+const ExternalApiButton = ({ view = {}, item, anyStyle }) => {
+  const { active, icon, label, run, select, title } = item;
+
+  const {
+    app,
+    pmViews: { main },
+    activeViewId,
+    activeView,
+  } = useContext(WaxContext);
+
+  const { state } = view;
+
+  const handleMouseDown = (e, editorState) => {
+    e.preventDefault();
+    const {
+      selection: { $from, $to },
+    } = editorState;
+    /* this is the content that we have to get from the selection */
+    const textSelection = new TextSelection($from, $to);
+
+    const content = textSelection.content();
+
+    anyStyle(content.content.content[0].textContent);
+  };
+
+  useEffect(() => {}, []);
+
+  const isActive = !!active(state, activeViewId);
+  let isDisabled = !select(state, activeViewId, activeView);
+
+  const isEditable = main.props.editable(editable => {
+    return editable;
+  });
+  if (!isEditable) isDisabled = true;
+
+  const ExternalApiButtonComponent = useMemo(
+    () => (
+      <MenuButton
+        active={isActive || false}
+        disabled={isDisabled}
+        iconName={icon}
+        label={label}
+        onMouseDown={e => handleMouseDown(e, view.state, view.dispatch)}
+        title={title}
+      />
+    ),
+    [isActive, isDisabled],
+  );
+
+  return ExternalApiButtonComponent;
+};
+
+export default ExternalApiButton;
diff --git a/wax-prosemirror-services/src/ExternalAPIContentService/plugins/AnyStylePlaceHolderPlugin.js b/wax-prosemirror-services/src/ExternalAPIContentService/plugins/AnyStylePlaceHolderPlugin.js
new file mode 100644
index 000000000..990b75ee2
--- /dev/null
+++ b/wax-prosemirror-services/src/ExternalAPIContentService/plugins/AnyStylePlaceHolderPlugin.js
@@ -0,0 +1,37 @@
+/* eslint-disable no-param-reassign */
+import { Plugin, PluginKey } from 'prosemirror-state';
+import { Decoration, DecorationSet } from 'prosemirror-view';
+
+export default key =>
+  new Plugin({
+    key: new PluginKey(key),
+    state: {
+      init: function init() {
+        return DecorationSet.empty;
+      },
+      apply: function apply(tr, set) {
+        // Adjust decoration positions to changes made by the transaction
+        set = set.map(tr.mapping, tr.doc);
+        // See if the transaction adds or removes any placeholders
+        const action = tr.getMeta(this);
+        if (action && action.add) {
+          const widget = document.createElement('placeholder-any-style');
+          const deco = Decoration.widget(action.add.pos, widget, {
+            id: action.add.id,
+          });
+
+          set = set.add(tr.doc, [deco]);
+        } else if (action && action.remove) {
+          set = set.remove(
+            set.find(null, null, spec => spec.id === action.remove.id),
+          );
+        }
+        return set;
+      },
+    },
+    props: {
+      decorations: function decorations(state) {
+        return this.getState(state);
+      },
+    },
+  });
diff --git a/wax-prosemirror-services/src/ExternalAPIContentService/replaceText.js b/wax-prosemirror-services/src/ExternalAPIContentService/replaceText.js
new file mode 100644
index 000000000..e54ae8af2
--- /dev/null
+++ b/wax-prosemirror-services/src/ExternalAPIContentService/replaceText.js
@@ -0,0 +1,62 @@
+import { v4 as uuidv4 } from 'uuid';
+import { DOMParser } from 'prosemirror-model';
+
+const findPlaceholder = (state, id, placeholderPlugin) => {
+  const decos = placeholderPlugin.getState(state);
+  const found = decos.find(null, null, spec => spec.id === id);
+  return found.length ? found[0].from : null;
+};
+
+const elementFromString = string => {
+  const wrappedValue = `<body>${string}</body>`;
+
+  return new window.DOMParser().parseFromString(wrappedValue, 'text/html').body;
+};
+
+export default (
+  view,
+  ExternalAPIContentTransformation,
+  placeholderPlugin,
+  context,
+) => data => {
+  const { state } = view;
+  // A fresh object to act as the ID for this upload
+  const id = {};
+
+  // Replace the selection with a placeholder
+  const { tr } = state;
+  if (!tr.selection.empty) tr.deleteSelection();
+
+  tr.setMeta(placeholderPlugin, {
+    add: { id, pos: tr.selection.from },
+  });
+
+  view.dispatch(tr);
+
+  ExternalAPIContentTransformation(data).then(
+    text => {
+      const pos = findPlaceholder(view.state, id, placeholderPlugin);
+      // If the content around the placeholder has been deleted, drop
+      // the image
+      if (pos == null) {
+        return;
+      }
+      const parser = DOMParser.fromSchema(
+        context.pmViews.main.state.config.schema,
+      );
+      const parsedContent = parser.parse(elementFromString(text));
+      // Otherwise, insert it at the placeholder's position, and remove
+      // the placeholder
+      context.pmViews[context.activeViewId].dispatch(
+        context.pmViews[context.activeViewId].state.tr
+          .replaceWith(pos, pos, parsedContent)
+          .setMeta(placeholderPlugin, { remove: { id } }),
+      );
+    },
+
+    () => {
+      // On failure, just clean up the placeholder
+      view.dispatch(tr.setMeta(placeholderPlugin, { remove: { id } }));
+    },
+  );
+};
-- 
GitLab