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

Commit

Permalink
Merge pull request #239 from eea/develop
Browse files Browse the repository at this point in the history
Add poweruser menu (#234)
  • Loading branch information
avoinea authored May 17, 2022
2 parents 030b6f2 + 9abd1c5 commit 09f1c9c
Show file tree
Hide file tree
Showing 12 changed files with 289 additions and 23 deletions.
10 changes: 9 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,17 @@ All notable changes to this project will be documented in this file. Dates are d

Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).

#### [6.0.0](https://github.com/eea/volto-slate/compare/5.4.1...6.0.0)

- Use block data form [`#240`](https://github.com/eea/volto-slate/pull/240)
- Add poweruser menu [`#234`](https://github.com/eea/volto-slate/pull/234)
- Release 6.0.0 [`de78cb5`](https://github.com/eea/volto-slate/commit/de78cb5495e0a8ea262ff45b05b87f900dccf5eb)

#### [5.4.1](https://github.com/eea/volto-slate/compare/5.4.0...5.4.1)

- chore(cypress): Fix paste html [`0bebd22`](https://github.com/eea/volto-slate/commit/0bebd222609ad8186d12be93c230ac1bc1b3c16d)
> 19 March 2022
- chore(cypress): Fix paste html [`#237`](https://github.com/eea/volto-slate/pull/237)

#### [5.4.0](https://github.com/eea/volto-slate/compare/5.3.5...5.4.0)

Expand Down
4 changes: 2 additions & 2 deletions Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -184,10 +184,10 @@ pipeline {
unstash "xunit-reports"
unstash "cypress-coverage"
def scannerHome = tool 'SonarQubeScanner';
def nodeJS = tool 'NodeJS11';
def nodeJS = tool 'NodeJS';
withSonarQubeEnv('Sonarqube') {
sh '''sed -i "s#/opt/frontend/my-volto-project/src/addons/${GIT_NAME}/##g" xunit-reports/coverage/lcov.info'''
sh "export PATH=$PATH:${scannerHome}/bin:${nodeJS}/bin; sonar-scanner -Dsonar.javascript.lcov.reportPaths=./xunit-reports/coverage/lcov.info,./cypress-coverage/coverage/lcov.info -Dsonar.sources=./src -Dsonar.projectKey=$GIT_NAME-$BRANCH_NAME -Dsonar.projectVersion=$BRANCH_NAME-$BUILD_NUMBER"
sh "export PATH=${scannerHome}/bin:${nodeJS}/bin:$PATH; sonar-scanner -Dsonar.javascript.lcov.reportPaths=./xunit-reports/coverage/lcov.info,./cypress-coverage/coverage/lcov.info -Dsonar.sources=./src -Dsonar.projectKey=$GIT_NAME-$BRANCH_NAME -Dsonar.projectVersion=$BRANCH_NAME-$BUILD_NUMBER"
sh '''try=2; while [ \$try -gt 0 ]; do curl -s -XPOST -u "${SONAR_AUTH_TOKEN}:" "${SONAR_HOST_URL}api/project_tags/set?project=${GIT_NAME}-${BRANCH_NAME}&tags=${SONARQUBE_TAGS},${BRANCH_NAME}" > set_tags_result; if [ \$(grep -ic error set_tags_result ) -eq 0 ]; then try=0; else cat set_tags_result; echo "... Will retry"; sleep 60; try=\$(( \$try - 1 )); fi; done'''
}
}
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "volto-slate",
"version": "5.4.1",
"version": "6.0.0",
"description": "Slate.js integration with Volto",
"main": "src/index.js",
"author": "European Environment Agency: IDM2 A-Team",
Expand Down
18 changes: 16 additions & 2 deletions src/blocks/Text/DefaultTextBlockEditor.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { Dimmer, Loader, Message, Segment } from 'semantic-ui-react';
import { flattenToAppURL, getBaseUrl } from '@plone/volto/helpers';
import config from '@plone/volto/registry';
import {
InlineForm,
BlockDataForm,
SidebarPortal,
BlockChooserButton,
} from '@plone/volto/components';
Expand All @@ -23,6 +23,7 @@ import {
} from 'volto-slate/utils';
import { Transforms } from 'slate';

import PersistentSlashMenu from './SlashMenu';
import ShortcutListing from './ShortcutListing';
import MarkdownIntroduction from './MarkdownIntroduction';
import { handleKey } from './keyboard';
Expand Down Expand Up @@ -86,6 +87,17 @@ export const DefaultTextBlockEditor = (props) => {
[props],
);

const slateSettings = React.useMemo(
() => ({
...config.settings.slate,
persistentHelpers: [
...config.settings.slate.persistentHelpers,
PersistentSlashMenu,
],
}),
[],
);

const onDrop = React.useCallback(
(files) => {
// TODO: need to fix setUploading, treat uploading indicator
Expand Down Expand Up @@ -231,6 +243,7 @@ export const DefaultTextBlockEditor = (props) => {
onKeyDown={handleKey}
selected={selected}
placeholder={placeholder}
slateSettings={slateSettings}
/>
{DEBUG ? <div>{block}</div> : ''}
</>
Expand Down Expand Up @@ -264,7 +277,7 @@ export const DefaultTextBlockEditor = (props) => {
<>
<ShortcutListing />
<MarkdownIntroduction />
<InlineForm
<BlockDataForm
schema={schema}
title={schema.title}
onChangeField={(id, value) => {
Expand All @@ -274,6 +287,7 @@ export const DefaultTextBlockEditor = (props) => {
});
}}
formData={data}
block={block}
/>
</>
)}
Expand Down
3 changes: 3 additions & 0 deletions src/blocks/Text/ShortcutListing.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ const ShortcutListing = (props) => {

<Segment secondary attached>
<List>
<List.Item>
Type a slash (<em>/</em>) to change block type
</List.Item>
{Object.entries(hotkeys || {}).map(([shortcut, { format, type }]) => (
<List.Item key={shortcut}>{`${shortcut}: ${format}`}</List.Item>
))}
Expand Down
164 changes: 164 additions & 0 deletions src/blocks/Text/SlashMenu.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
import React from 'react';
import PropTypes from 'prop-types';
import { filter, isEmpty } from 'lodash';
import { Menu } from 'semantic-ui-react';
import { useIntl, FormattedMessage } from 'react-intl';
import { Icon } from '@plone/volto/components';

const emptySlateBlock = () => ({
value: [
{
children: [
{
text: '',
},
],
type: 'p',
},
],
plaintext: '',
});

const useIsMounted = () => {
const ref = React.useRef();
React.useEffect(() => {
ref.current = true;
return () => (ref.current = false);
}, []);
return ref.current;
};

const SlashMenu = ({
currentBlock,
onMutateBlock,
selected,
availableBlocks,
}) => {
const intl = useIntl();

return (
<div className="power-user-menu">
<Menu vertical fluid borderless>
{availableBlocks.map((block, index) => (
<Menu.Item
key={block.id}
className={block.id}
active={index === selected}
onClick={(e) => {
// onInsertBlock(currentBlock, { '@type': block.id });
onMutateBlock(currentBlock, { '@type': block.id });
e.stopPropagation();
}}
>
<Icon name={block.icon} size="24px" />
{intl.formatMessage({
id: block.title,
defaultMessage: block.title,
})}
</Menu.Item>
))}
{availableBlocks.length === 0 && (
<Menu.Item>
<FormattedMessage
id="No matching blocks"
defaultMessage="No matching blocks"
/>
</Menu.Item>
)}
</Menu>
</div>
);
};

SlashMenu.propTypes = {
currentBlock: PropTypes.string.isRequired,
onInsertBlock: PropTypes.func,
selected: PropTypes.number,
blocksConfig: PropTypes.arrayOf(PropTypes.any),
};

/**
* A SlashMenu wrapper implemented as a volto-slate PersistentHelper.
*/
const PersistentSlashMenu = ({ editor }) => {
const props = editor.getBlockProps();
const {
block,
blocksConfig,
data,
onMutateBlock,
properties,
selected,
allowedBlocks,
detached,
} = props;
const disableNewBlocks = data?.disableNewBlocks || detached;

const [slashMenuSelected, setSlashMenuSelected] = React.useState(0);

const useAllowedBlocks = !isEmpty(allowedBlocks);
const slashCommand = data.plaintext?.trim().match(/^\/([a-z]*)$/);

const availableBlocks = React.useMemo(
() =>
filter(blocksConfig, (item) =>
useAllowedBlocks
? allowedBlocks.includes(item.id)
: typeof item.restricted === 'function'
? !item.restricted({ properties, block: item })
: !item.restricted,
)
.filter(
// TODO: make it work with intl?
(block) => slashCommand && block.id.indexOf(slashCommand[1]) === 0,
)
.sort((a, b) => (a.title < b.title ? -1 : 1)),
[allowedBlocks, blocksConfig, properties, slashCommand, useAllowedBlocks],
);

const slashMenuSize = availableBlocks.length;
const show = selected && slashCommand && !disableNewBlocks;

const isMounted = useIsMounted();

React.useEffect(() => {
if (isMounted && show && slashMenuSelected > slashMenuSize - 1) {
setSlashMenuSelected(slashMenuSize - 1);
}
}, [show, slashMenuSelected, isMounted, slashMenuSize]);

editor.showSlashMenu = show;

editor.slashEnter = () =>
slashMenuSize > 0 &&
onMutateBlock(
block,
{
'@type': availableBlocks[slashMenuSelected].id,
},
emptySlateBlock(),
);

editor.slashArrowUp = () =>
setSlashMenuSelected(
slashMenuSelected === 0 ? slashMenuSize - 1 : slashMenuSelected - 1,
);

editor.slashArrowDown = () =>
setSlashMenuSelected(
slashMenuSelected >= slashMenuSize - 1 ? 0 : slashMenuSelected + 1,
);

return show ? (
<SlashMenu
currentBlock={block}
onMutateBlock={onMutateBlock}
availableBlocks={availableBlocks}
selected={slashMenuSelected}
/>
) : (
''
);
};

export default PersistentSlashMenu;
6 changes: 6 additions & 0 deletions src/blocks/Text/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import {
moveListItemUp,
traverseBlocks,
unwrapEmptyString,
slashMenu,
cancelEsc,
} from './keyboard';
import { withDeleteSelectionOnEnter } from 'volto-slate/editor/extensions';
import {
Expand Down Expand Up @@ -58,21 +60,25 @@ export default (config) => {
joinWithNextBlock, // Delete at end of block joins with next block
],
Enter: [
slashMenu,
unwrapEmptyString,
softBreak, // Handles shift+Enter as a newline (<br/>)
],
ArrowUp: [
slashMenu,
moveListItemUp, // Move up a list with with Ctrl+up
goUp, // Select previous block
],
ArrowDown: [
slashMenu,
moveListItemDown, // Move down a list item with Ctrl+down
goDown, // Select next block
],
Tab: [
indentListItems, // <tab> and <c-tab> behaviour for list items
traverseBlocks,
],
Escape: [cancelEsc],
},
textblockDetachedKeyboardHandlers: {
Enter: [
Expand Down
7 changes: 7 additions & 0 deletions src/blocks/Text/keyboard/cancelEsc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export const cancelEsc = ({ editor, event }) => {
// TODO: this doesn't work, escape canceling doesn't work.
event.stopPropagation();
event.nativeEvent.stopImmediatePropagation();
event.preventDefault();
return true;
};
2 changes: 2 additions & 0 deletions src/blocks/Text/keyboard/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ export * from './moveListItems';
export * from './softBreak';
export * from './traverseBlocks';
export * from './unwrapEmptyString';
export * from './slashMenu';
export * from './cancelEsc';

/**
* Takes all the handlers from `slate.textblockKeyboardHandlers` that are
Expand Down
16 changes: 16 additions & 0 deletions src/blocks/Text/keyboard/slashMenu.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
export const slashMenu = ({ editor, event }) => {
if (!editor.showSlashMenu) return;

const { slashArrowUp, slashArrowDown, slashEnter } = editor;

const handlers = {
ArrowUp: slashArrowUp,
ArrowDown: slashArrowDown,
Enter: slashEnter,
};

const handler = handlers[event.key];
if (handler) handler();

return true;
};
Loading

0 comments on commit 09f1c9c

Please sign in to comment.