From fcd53e7cb8e2abc40076bdb81842d99e85392be1 Mon Sep 17 00:00:00 2001 From: Tiberiu Ichim Date: Fri, 14 May 2021 08:44:47 +0300 Subject: [PATCH] Add SimpleLink WIP --- src/components/ElementEditor/index.js | 92 +------------------ .../ElementEditor/makeInlineElementPlugin.js | 91 ++++++++++++++++++ src/editor/SlateEditor.jsx | 1 + src/editor/index.js | 3 +- src/editor/plugins/SimpleLink/extensions.js | 30 ++++++ src/editor/plugins/SimpleLink/index.js | 51 ++++++++++ src/editor/plugins/SimpleLink/render.jsx | 10 ++ src/editor/ui/SlateToolbar.jsx | 21 +++-- src/editor/ui/Toolbar.jsx | 4 +- 9 files changed, 200 insertions(+), 103 deletions(-) create mode 100644 src/components/ElementEditor/makeInlineElementPlugin.js create mode 100644 src/editor/plugins/SimpleLink/extensions.js create mode 100644 src/editor/plugins/SimpleLink/index.js create mode 100644 src/editor/plugins/SimpleLink/render.jsx diff --git a/src/components/ElementEditor/index.js b/src/components/ElementEditor/index.js index 26721597..e7d57d83 100644 --- a/src/components/ElementEditor/index.js +++ b/src/components/ElementEditor/index.js @@ -1,94 +1,4 @@ -import React from 'react'; -import SidebarEditor from './SidebarEditor'; -import makeContextButtons from './ContextButtons'; -import PluginEditor from './PluginEditor'; -import { - _insertElement, - _unwrapElement, - _isActiveElement, - _getActiveElement, -} from './utils'; -import messages from './messages'; -import ToolbarButton from './ToolbarButton'; -import tagSVG from '@plone/volto/icons/tag.svg'; -import SchemaProvider from './SchemaProvider'; -import { omit } from 'lodash'; - -export const makeInlineElementPlugin = (options) => { - const { elementType, isInlineElement, pluginId, title = 'Element' } = options; - const omittedProps = [ - 'pluginEditor', - 'getActiveElement', - 'unwrapElement', - 'schemaProvider', - 'hasValue', - 'elementType', - 'isInlineElement', - 'editSchema', - 'element', - ]; - const pluginOptions = { - pluginEditor: PluginEditor, - insertElement: _insertElement(elementType), - getActiveElement: _getActiveElement(elementType), - isActiveElement: _isActiveElement(elementType), - unwrapElement: _unwrapElement(elementType), - messages, - toolbarButtonIcon: tagSVG, - title, - extensions: [], - - // a component that should provide a schema as a render prop - schemaProvider: SchemaProvider, - // schema that can be used to create the edit form for this component - // editSchema, - - // A generic "validation" method, just finds that a "positive" value - // exists. Plugin authors should overwrite it in options - // If it returns true, the value is saved in the editor, othwerwise the - // element type is removed from the editor - hasValue: (data) => Object.values(data).findIndex((v) => !!v) > -1, - - ...options, - }; - - const ElementContextButtons = makeContextButtons(pluginOptions); - - const PersistentHelper = (props) => ( - - ); - - const install = (config) => { - const { slate } = config.settings; - if (isInlineElement) { - slate.inlineElements[elementType] = true; - } - - slate.buttons[pluginId] = (props) => ( - - ); - slate.contextToolbarButtons.push(ElementContextButtons); - slate.persistentHelpers.push(PersistentHelper); - slate.extensions = [ - ...(slate.extensions || []), - ...pluginOptions.extensions, - ]; - slate.elements[elementType] = options.element; - slate.nodeTypesToHighlight.push(elementType); - - // The plugin authors should manually add the button to the relevant toolbars - // slate.toolbarButtons = [...(slate.toolbarButtons || []), pluginId]; - // slate.expandedToolbarButtons = [...(slate.expandedToolbarButtons || []), pluginId]; - - return config; - }; - - return [install, ElementContextButtons, PersistentHelper]; -}; +export { makeInlineElementPlugin } from './makeInlineElementPlugin'; export const makeBlockElementPlugin = (options) => { return [(config) => config]; diff --git a/src/components/ElementEditor/makeInlineElementPlugin.js b/src/components/ElementEditor/makeInlineElementPlugin.js new file mode 100644 index 00000000..b5b69d66 --- /dev/null +++ b/src/components/ElementEditor/makeInlineElementPlugin.js @@ -0,0 +1,91 @@ +import React from 'react'; +import SidebarEditor from './SidebarEditor'; +import makeContextButtons from './ContextButtons'; +import PluginEditor from './PluginEditor'; +import { + _insertElement, + _unwrapElement, + _isActiveElement, + _getActiveElement, +} from './utils'; +import messages from './messages'; +import ToolbarButton from './ToolbarButton'; +import tagSVG from '@plone/volto/icons/tag.svg'; +import SchemaProvider from './SchemaProvider'; +import { omit } from 'lodash'; + +export const makeInlineElementPlugin = (options) => { + const { elementType, isInlineElement, pluginId, title = 'Element' } = options; + const omittedProps = [ + 'pluginEditor', + 'getActiveElement', + 'unwrapElement', + 'schemaProvider', + 'hasValue', + 'elementType', + 'isInlineElement', + 'editSchema', + 'element', + ]; + const pluginOptions = { + pluginEditor: PluginEditor, + insertElement: _insertElement(elementType), + getActiveElement: _getActiveElement(elementType), + isActiveElement: _isActiveElement(elementType), + unwrapElement: _unwrapElement(elementType), + messages, + toolbarButtonIcon: tagSVG, + title, + extensions: [], + + // a component that should provide a schema as a render prop + schemaProvider: SchemaProvider, + // schema that can be used to create the edit form for this component + // editSchema, + + // A generic "validation" method, just finds that a "positive" value + // exists. Plugin authors should overwrite it in options + // If it returns true, the value is saved in the editor, othwerwise the + // element type is removed from the editor + hasValue: (data) => Object.values(data).findIndex((v) => !!v) > -1, + + ...options, + }; + + const ElementContextButtons = makeContextButtons(pluginOptions); + + const PersistentHelper = (props) => ( + + ); + + const install = (config) => { + const { slate } = config.settings; + if (isInlineElement) { + slate.inlineElements[elementType] = true; + } + + slate.buttons[pluginId] = (props) => ( + + ); + slate.contextToolbarButtons.push(ElementContextButtons); + slate.persistentHelpers.push(PersistentHelper); + slate.extensions = [ + ...(slate.extensions || []), + ...pluginOptions.extensions, + ]; + slate.elements[elementType] = options.element; + slate.nodeTypesToHighlight.push(elementType); + + // The plugin authors should manually add the button to the relevant toolbars + // slate.toolbarButtons = [...(slate.toolbarButtons || []), pluginId]; + // slate.expandedToolbarButtons = [...(slate.expandedToolbarButtons || []), pluginId]; + + return config; + }; + + return [install, ElementContextButtons, PersistentHelper]; +}; diff --git a/src/editor/SlateEditor.jsx b/src/editor/SlateEditor.jsx index 9b03f91a..46dbbc69 100644 --- a/src/editor/SlateEditor.jsx +++ b/src/editor/SlateEditor.jsx @@ -35,6 +35,7 @@ const Toolbar = (props) => { return isRangeSelection || hasDomSelection ? ( { config.settings.slate = { ...slateConfig, - showExpandedToolbar: false, + // showExpandedToolbar: false, + enableExpandedToolbar: false, }; config = installDefaultPlugins(config); return config; diff --git a/src/editor/plugins/SimpleLink/extensions.js b/src/editor/plugins/SimpleLink/extensions.js new file mode 100644 index 00000000..fff08b0b --- /dev/null +++ b/src/editor/plugins/SimpleLink/extensions.js @@ -0,0 +1,30 @@ +import { SIMPLELINK } from 'volto-slate/constants'; + +export const withSimpleLink = (editor) => { + // const { insertData, insertText, isInline } = editor; + + const { isInline } = editor; + + editor.isInline = (element) => { + return element.type === SIMPLELINK ? true : isInline(element); + }; + + // editor.insertText = (text) => { + // if (text && isUrl(text)) { + // wrapLink(editor, text); + // } else { + // insertText(text); + // } + // }; + // + // editor.insertData = (data) => { + // const text = data.getData('text/plain'); + // + // if (text && isUrl(text)) { + // wrapLink(editor, text); + // } else { + // insertData(data); + // } + // }; + return editor; +}; diff --git a/src/editor/plugins/SimpleLink/index.js b/src/editor/plugins/SimpleLink/index.js new file mode 100644 index 00000000..3987443d --- /dev/null +++ b/src/editor/plugins/SimpleLink/index.js @@ -0,0 +1,51 @@ +import { makeInlineElementPlugin } from 'volto-slate/components/ElementEditor'; +import { SIMPLELINK, LINK } from 'volto-slate/constants'; +import { LinkElement } from './render'; +import { defineMessages } from 'react-intl'; // , defineMessages +import { withSimpleLink } from './extensions'; +import linkSVG from '@plone/volto/icons/link.svg'; + +const linkDeserializer = () => {}; + +const messages = defineMessages({ + edit: { + id: 'Edit link', + defaultMessage: 'Edit link', + }, + delete: { + id: 'Remove link', + defaultMessage: 'Remove link', + }, +}); + +export default (config) => { + const { slate } = config.settings; + + const PLUGINID = SIMPLELINK; + + slate.toolbarButtons = slate.toolbarButtons.filter((b) => b !== LINK); + slate.toolbarButtons = slate.toolbarButtons.slice(0, 2).concat([PLUGINID]); + slate.expandedToolbarButtons = slate.expandedToolbarButtons.filter( + (b) => b !== LINK, + ); + + slate.htmlTagsToSlate.A = linkDeserializer; + + const opts = { + title: 'SimpleLink', + pluginId: PLUGINID, + elementType: PLUGINID, + element: LinkElement, + isInlineElement: true, + // editSchema: LinkEditSchema, + extensions: [withSimpleLink], + hasValue: (formData) => !!formData.link, + toolbarButtonIcon: linkSVG, + messages, + }; + + const [installLinkEditor] = makeInlineElementPlugin(opts); + config = installLinkEditor(config); + + return config; +}; diff --git a/src/editor/plugins/SimpleLink/render.jsx b/src/editor/plugins/SimpleLink/render.jsx new file mode 100644 index 00000000..23693c2b --- /dev/null +++ b/src/editor/plugins/SimpleLink/render.jsx @@ -0,0 +1,10 @@ +import React from 'react'; + +export const LinkElement = (props) => { + const { attributes, children } = props; + return ( + + {children} + + ); +}; diff --git a/src/editor/ui/SlateToolbar.jsx b/src/editor/ui/SlateToolbar.jsx index f2cd1838..2fceaa69 100644 --- a/src/editor/ui/SlateToolbar.jsx +++ b/src/editor/ui/SlateToolbar.jsx @@ -23,6 +23,7 @@ const SlateToolbar = (props) => { showExpandedToolbar, setShowExpandedToolbar, className, + enableExpando = false, } = props; const { slate } = config.settings; const { toolbarButtons, expandedToolbarButtons, buttons } = slate; @@ -38,15 +39,17 @@ const SlateToolbar = (props) => { {!showExpandedToolbar && ( { - setShowExpandedToolbar(!showExpandedToolbar); - event.preventDefault(); - }} - icon={toggleIcon} - active={showExpandedToolbar} - /> + enableExpando && ( + { + setShowExpandedToolbar(!showExpandedToolbar); + event.preventDefault(); + }} + icon={toggleIcon} + active={showExpandedToolbar} + /> + ) } className={className} > diff --git a/src/editor/ui/Toolbar.jsx b/src/editor/ui/Toolbar.jsx index 267ac09c..2172488d 100644 --- a/src/editor/ui/Toolbar.jsx +++ b/src/editor/ui/Toolbar.jsx @@ -5,7 +5,7 @@ import { useSlate } from 'slate-react'; import Separator from './Separator'; import BasicToolbar from './BasicToolbar'; -const Toolbar = ({ toggleButton, className, children }) => { +const Toolbar = ({ enableExpando, toggleButton, className, children }) => { const ref = useRef(); const editor = useSlate(); @@ -52,7 +52,7 @@ const Toolbar = ({ toggleButton, className, children }) => { {children} - {toggleButton && ( + {enableExpando && toggleButton && ( <> {toggleButton}