Skip to content
This repository has been archived by the owner on Oct 25, 2022. It is now read-only.

Commit

Permalink
Merge branch 'develop' into refactor_link_toolbar
Browse files Browse the repository at this point in the history
  • Loading branch information
kreafox committed Aug 17, 2020
2 parents e8fafd6 + 2a8ce8c commit 689fd24
Show file tree
Hide file tree
Showing 10 changed files with 147 additions and 70 deletions.
4 changes: 4 additions & 0 deletions src/blocks/Text/TextBlockEdit.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,10 @@ const TextBlockEdit = (props) => {
// TODO: also add html serialized value
});
}}
onClick={(ev) => {
// TODO: explain why this is needed
ev.stopPropagation();
}}
onKeyDown={handleKey}
selected={selected}
placeholder={data.placeholder || 'Enter some rich text…'}
Expand Down
48 changes: 31 additions & 17 deletions src/editor/SlateEditor.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ import { settings } from '~/config';
import withTestingFeatures from './extensions/withTestingFeatures';
import { fixSelection, hasRangeSelection } from 'volto-slate/utils';

// import isHotkey from 'is-hotkey';
// import { toggleMark } from './utils';
import isHotkey from 'is-hotkey';
import { toggleMark } from 'volto-slate/utils';

import './less/editor.less';

Expand Down Expand Up @@ -111,12 +111,26 @@ const SlateEditor = ({
testingEditorRef.current = editor;
}

const j_value = JSON.stringify(value);
const handleChange = React.useCallback(
(newValue) => {
if (JSON.stringify(newValue) !== j_value) {
onChange(newValue);
}
},
[j_value, onChange],
);

return (
<div
{...rest['debug-values']} // used for `data-` HTML attributes set in the withTestingFeatures HOC
className={cx('slate-editor', { 'show-toolbar': showToolbar, selected })}
>
<Slate editor={editor} value={value || initialValue} onChange={onChange}>
<Slate
editor={editor}
value={value || initialValue}
onChange={handleChange}
>
{selected ? (
hasRangeSelection(editor) ? (
<SlateToolbar
Expand All @@ -140,20 +154,20 @@ const SlateEditor = ({
renderLeaf={(props) => <Leaf {...props} />}
decorate={multiDecorate}
onKeyDown={(event) => {
// let wasHotkey = false;
//
// for (const hotkey in slate.hotkeys) {
// if (isHotkey(hotkey, event)) {
// event.preventDefault();
// const mark = slate.hotkeys[hotkey];
// toggleMark(editor, mark);
// wasHotkey = true;
// }
// }
//
// if (wasHotkey) {
// return;
// }
let wasHotkey = false;

for (const hotkey in slate.hotkeys) {
if (isHotkey(hotkey, event)) {
event.preventDefault();
const mark = slate.hotkeys[hotkey];
toggleMark(editor, mark);
wasHotkey = true;
}
}

if (wasHotkey) {
return;
}

onKeyDown && onKeyDown({ editor, event });
}}
Expand Down
4 changes: 2 additions & 2 deletions src/editor/config.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import superindexIcon from '@plone/volto/icons/superindex.svg';
import { createEmptyParagraph } from 'volto-slate/utils';

import { MarkButton, BlockButton, Separator, Expando } from './ui';
import { HighlightByType, HighlightSelection } from './decorate';
import { highlightByType, highlightSelection } from './decorate';
import {
withDeleteSelectionOnEnter,
withDeserializers,
Expand Down Expand Up @@ -197,4 +197,4 @@ export const nodeTypesToHighlight = [];
// applied in the editor. They are not persisted in the final value, so they
// are useful for example to highlight search results or a certain type of node
// Signature: ([node, path], ranges) => ranges
export const runtimeDecorators = [HighlightSelection, HighlightByType];
export const runtimeDecorators = [highlightSelection]; // , highlightByType
37 changes: 21 additions & 16 deletions src/editor/decorate.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,20 @@ import { ReactEditor } from 'slate-react';

import { settings } from '~/config';

export const HighlightByType = (editor, [node, path], ranges) => {
/**
* highlightByType.
*
* @param {} editor
* @param {} node, path
* @param {} ranges
*/
export const highlightByType = (editor, [node, path], ranges) => {
const { slate } = settings;
const { nodeTypesToHighlight } = slate;

if (nodeTypesToHighlight.includes(node.type)) {
const [found] = Node.texts(editor, { from: path, to: path });
const visualSelectionRanges = _highlightSelection(editor, found, ranges);
const visualSelectionRanges = highlightSelection(editor, found, ranges);
const text = Node.string(node) || '';
const range = {
anchor: { path, offset: 0 },
Expand All @@ -24,7 +31,18 @@ export const HighlightByType = (editor, [node, path], ranges) => {
return ranges;
};

function _highlightSelection(editor, [node, path], ranges) {
/**
* @function highlightSelection
*
* @summary A runtime decorator that decorates the saved selection, when the editor is
* is no longer active.
*
* @param {Editor} editor The editor on which to apply the decorator.
* @param {Node} node
* @param {Path} path
* @param {Array} ranges
*/
export function highlightSelection(editor, [node, path], ranges) {
let selected = ReactEditor.isFocused(editor);

// Compatibility with Volto blocks
Expand All @@ -46,16 +64,3 @@ function _highlightSelection(editor, [node, path], ranges) {
}
return ranges;
}

/**
* HighlightSelection.
*
* A runtime decorator that decorates the saved selection, when the editor is
* is no longer active
*
* @param {}
* @param {} ranges
*/
export function HighlightSelection(editor, [node, path], ranges) {
return _highlightSelection(editor, [node, path], ranges);
}
12 changes: 11 additions & 1 deletion src/editor/extensions/insertData.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,24 @@
import { Editor, Text, Transforms } from 'slate';
import { Editor, Text, Transforms, Block } from 'slate';
import { deserialize } from 'volto-slate/editor/deserialize';
import { settings } from '~/config';

/**
* @param {Text} textNode The (leaf) Text node to wrap.
*
* @returns {Block} A Slate block node, of the default block type configured in the Slate settings, containing the given Text node.
*/
function createBlock(textNode) {
return {
type: settings.slate.defaultBlockType,
children: [textNode],
};
}

/**
* @summary Inserts in the given editor the feature of being able to paste HTML content in it.
*
* @param {Editor} editor A Slate editor object.
*/
export const insertData = (editor) => {
const { insertData } = editor;

Expand Down
21 changes: 19 additions & 2 deletions src/editor/plugins/Footnote/less/editor.less
Original file line number Diff line number Diff line change
@@ -1,4 +1,21 @@
.highlight-footnote {
// .highlight-footnote {
// background-color: #f0f0f0;
//
// &:after {
// position: relative;
// display: inline-block;
// padding: 1px;
// margin: 2px;
// margin-top: -10px;
// background-color: lightblue;
// border-radius: 4px;
// // content: 'footnote';
// font-size: 8px;
// line-height: 8px;
// }
// }

.footnote-edit-node {
background-color: #f0f0f0;

&:after {
Expand All @@ -9,7 +26,7 @@
margin-top: -10px;
background-color: lightblue;
border-radius: 4px;
content: 'footnote';
// content: 'footnote';
font-size: 8px;
line-height: 8px;
}
Expand Down
15 changes: 12 additions & 3 deletions src/editor/plugins/Footnote/render.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import React from 'react';
import { Popup } from 'semantic-ui-react';

import './less/public.less';

export const FootnoteElement = ({ attributes, children, element, mode }) => {
Expand All @@ -16,9 +18,16 @@ export const FootnoteElement = ({ attributes, children, element, mode }) => {
{children}
</a>
) : (
<span {...attributes} className="footnote">
{children}
</span>
<Popup
content={data.footnote}
header="Footnote"
position="bottom left"
trigger={
<span {...attributes} className="footnote footnote-edit-node">
{children}
</span>
}
/>
)}
</>
);
Expand Down
6 changes: 6 additions & 0 deletions src/editor/plugins/Footnote/utils.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import { Editor, Transforms } from 'slate'; // Range,
import { FOOTNOTE } from 'volto-slate/constants';

/**
* @description Creates or updates an existing FOOTNOTE. It also takes care of the saved selection and uses PathRef.
*
* @param {Editor} editor The editor in which to insert a footnote.
* @param {object} data The object which will be set as the value of the `data` property on the new or existing FOOTNOTE Slate node.
*/
export function insertFootnote(editor, data) {
if (editor.savedSelection) {
const selection = editor.savedSelection;
Expand Down
55 changes: 33 additions & 22 deletions src/editor/render.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,15 @@ export const Element = ({ element, ...rest }) => {
return <El element={element} {...rest} />;
};

export const Leaf = ({ attributes, leaf, children, mode }) => {
export const Leaf = ({
attributes,
leaf,
children,
mode,
text,
// path,
// editor,
}) => {
let { leafs } = settings.slate;

children = Object.keys(leafs).reduce((acc, name) => {
Expand Down Expand Up @@ -58,38 +66,41 @@ export const Leaf = ({ attributes, leaf, children, mode }) => {
};

export const serializeNodes = (nodes) => {
let index = 0;
// let index = 0;
const editor = { children: nodes || [] };

const _serializeNodes = (nodes) =>
(nodes || []).map((node, i) => {
const id = index++;
const _serializeNodes = (nodes) => {
return (nodes || []).map(([node, path], i) => {
// const id = index++;

if (Text.isText(node)) {
return (
<Leaf
leaf={node}
text={node}
attributes={{ 'data-slate-leaf': true }}
mode="view"
key={id}
>
{node.text}
</Leaf>
);
}
return (
return Text.isText(node) ? (
<Leaf
editor={editor}
path={path}
leaf={node}
text={node}
attributes={{ 'data-slate-leaf': true }}
mode="view"
key={path}
>
{node.text}
</Leaf>
) : (
<Element
editor={editor}
path={path}
element={node}
attributes={{ 'data-slate-node': 'element', ref: null }}
mode="view"
key={id}
key={path}
>
{_serializeNodes(node.children)}
{_serializeNodes(Array.from(Node.children(editor, path)))}
</Element>
);
});
};

return _serializeNodes(nodes);
return _serializeNodes(Array.from(Node.children(editor, [])));
};

export const serializeNodesToText = (nodes) => {
Expand Down
15 changes: 8 additions & 7 deletions src/utils/marks.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,10 @@ function addMark(editor, key, value) {
}
}

function isSelectionInline(editor) {
const [node] = Editor.node(editor, editor.selection || editor.savedSelection);
return Text.isText(node) || editor.isInline(node) || editor.isVoid(node);
}
// function isSelectionInline(editor) {
// const [node] = Editor.node(editor, editor.selection || editor.savedSelection);
// return Text.isText(node) || editor.isInline(node) || editor.isVoid(node);
// }

export function toggleMark(editor, format) {
const isActive = isMarkActive(editor, format);
Expand All @@ -64,9 +64,10 @@ export function toggleMark(editor, format) {
} else {
// don't apply marks inside inlines (such as footnote) because
// that splits the footnote into multiple footnotes
if (isSelectionInline(editor)) {
addMark(editor, format, true);
}
addMark(editor, format, true);
// if (isSelectionInline(editor)) {
// addMark(editor, format, true);
// }
}
}

Expand Down

0 comments on commit 689fd24

Please sign in to comment.