Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 0 additions & 25 deletions .eslintrc.js

This file was deleted.

5 changes: 4 additions & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,14 @@ jobs:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '16'
node-version: '22'
cache: 'yarn'

- name: Install dependencies
run: yarn

- name: Install dependencies
run: yarn lint

- name: Build the plugin
run: yarn build
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
16
22
807 changes: 0 additions & 807 deletions .yarn/releases/yarn-3.3.0.cjs

This file was deleted.

942 changes: 942 additions & 0 deletions .yarn/releases/yarn-4.9.2.cjs

Large diffs are not rendered by default.

7 changes: 6 additions & 1 deletion .yarnrc.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
compressionLevel: mixed

enableGlobalCache: true

nodeLinker: node-modules

pnpMode: loose
yarnPath: .yarn/releases/yarn-3.3.0.cjs

yarnPath: .yarn/releases/yarn-4.9.2.cjs
23 changes: 23 additions & 0 deletions Resources/Private/Scripts/HyphensEditor/esbuild.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
const esbuild = require('esbuild');
const extensibilityMap = require('@neos-project/neos-ui-extensibility/extensibilityMap.json');
const isWatch = process.argv.includes('--watch');

/** @type {import("esbuild").BuildOptions} */
const options = {
logLevel: 'info',
bundle: true,
minify: !isWatch,
target: 'es2020',
entryPoints: { Plugin: 'src/index.js' },
loader: {
'.js': 'tsx',
},
alias: extensibilityMap,
outdir: '../../../Public/HyphensEditor',
};

if (isWatch) {
esbuild.context(options).then((ctx) => ctx.watch());
} else {
esbuild.build(options);
}
13 changes: 5 additions & 8 deletions Resources/Private/Scripts/HyphensEditor/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,12 @@
"name": "hyphens-editor",
"version": "1.0.0",
"scripts": {
"build": "NODE_ENV=production neos-react-scripts build",
"watch": "neos-react-scripts watch"
"build": "node esbuild.js",
"watch": "node esbuild.js --watch"
},
"devDependencies": {
"@neos-project/neos-ui-extensibility": "^8.3.0",
"@neos-project/neos-ui-extensibility-webpack-adapter": "^8.3.0",
"@neos-project/react-ui-components": "^8.3.0"
},
"neos": {
"buildTargetDirectory": "../../../Public/HyphensEditor"
"@neos-project/neos-ui-extensibility": "^8.3.14",
"@neos-project/react-ui-components": "^8.3.14",
"esbuild": "~0.25.8"
}
}
4 changes: 2 additions & 2 deletions Resources/Private/Scripts/HyphensEditor/src/commands/nbsp.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
export default function NbspCommand(editor) {
return {
execute: () => {
editor.model.change(writer => {
editor.model.change((writer) => {
const insertPosition = editor.model.document.selection.getFirstPosition();
writer.insertText('\u00A0', insertPosition);
});
}
},
};
}
4 changes: 2 additions & 2 deletions Resources/Private/Scripts/HyphensEditor/src/commands/shy.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
export default function ShyCommand(editor) {
return {
execute: () => {
editor.model.change(writer => {
editor.model.change((writer) => {
const insertPosition = editor.model.document.selection.getFirstPosition();
writer.insertText('\u00AD', insertPosition);
});
}
},
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.btnWithoutPadding {
padding: 0;
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import HyphensFactory from "./plugins/hyphens";
import HyphensFactory from './plugins/hyphens';

const addPlugin = (Plugin) => (ckEditorConfiguration, options) => {
if (options.editorOptions && (options.editorOptions.nbsp || options.editorOptions.hyphens)) {
Expand All @@ -9,10 +9,10 @@ const addPlugin = (Plugin) => (ckEditorConfiguration, options) => {
};

export default (ckEditorRegistry, editorConfig) => {
const config = ckEditorRegistry.get("config");
const config = ckEditorRegistry.get('config');

const HyphensPlugin = HyphensFactory(editorConfig);
config.set("hyphens", addPlugin(HyphensPlugin));
config.set('hyphens', addPlugin(HyphensPlugin));

return config;
};
2 changes: 1 addition & 1 deletion Resources/Private/Scripts/HyphensEditor/src/manifest.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import manifest from '@neos-project/neos-ui-extensibility';
import initializeRichtextToolbarRegistry from './manifest.richtextToolbar';
import initializeConfigRegistry from './manifest.config';

manifest('Shel.Neos:HyphenEditor', {}, (globalRegistry, {frontendConfiguration}) => {
manifest('Shel.Neos:HyphenEditor', {}, (globalRegistry, { frontendConfiguration }) => {
const ckEditorRegistry = globalRegistry.get('ckEditor5');
const editorConfig = frontendConfiguration['Shel.Neos:HyphensEditor'];

Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
import React, {PureComponent} from 'react';
import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import {Button} from '@neos-project/react-ui-components';
import {neos} from '@neos-project/neos-ui-decorators';
import {themr} from '@friendsofreactjs/react-css-themr';
import { Button } from '@neos-project/react-ui-components';
import { neos } from '@neos-project/neos-ui-decorators';

import buttonTheme from './hyphensButtonTheme.css';
import style from './editorButton.module.css';

const BUTTON_PROPS = ['formattingRule', 'inlineEditorOptions', 'i18nRegistry', 'tooltip', 'isActive', 'label'];

@neos(globalRegistry => ({
i18nRegistry: globalRegistry.get('i18n')
}))
@themr('HyphensButton', buttonTheme)
const mapGlobalRegistryToProps = neos((globalRegistry) => ({
i18nRegistry: globalRegistry.get('i18n'),
}));

class HyphenButtonComponent extends PureComponent {
static propTypes = {
i18nRegistry: PropTypes.object,
tooltip: PropTypes.string
tooltip: PropTypes.string,
};

render() {
Expand All @@ -24,28 +23,30 @@ class HyphenButtonComponent extends PureComponent {
return carry;
}, {});
return (
<Button {...finalProps} isActive={Boolean(this.props.isActive)} className={buttonTheme['btn--no-padding']}
title={this.props.i18nRegistry.translate(this.props.tooltip)}>
<Button
{...finalProps}
isActive={Boolean(this.props.isActive)}
className={style.btnWithoutPadding}
title={this.props.i18nRegistry.translate(this.props.tooltip)}
>
<svg xmlns="http://www.w3.org/2000/svg" width="18.109" height="9.697" viewBox="0, 0, 18.109, 9.697">
<g stroke="currentColor" strokeMiterlimit="3.864" fill="none">
<path d="M2.596 1a5.44 5.44 0 0 0 0 7.697m12.918 0a5.44 5.44 0 0 0 0-7.697" strokeWidth=".907"/>
<path d="M4.52 4.848h9.07" strokeWidth="1.814"/>
<path
d="M2.596 1a5.44 5.44 0 0 0 0 7.697m12.918 0a5.44 5.44 0 0 0 0-7.697"
strokeWidth=".907"
/>
<path d="M4.52 4.848h9.07" strokeWidth="1.814" />
</g>
</svg>
</Button>
);
}
}


@neos(globalRegistry => ({
i18nRegistry: globalRegistry.get('i18n')
}))
@themr('NbspButton', buttonTheme)
class NbspButtonComponent extends PureComponent {
static propTypes = {
i18nRegistry: PropTypes.object,
tooltip: PropTypes.string
tooltip: PropTypes.string,
};

render() {
Expand All @@ -54,11 +55,20 @@ class NbspButtonComponent extends PureComponent {
return carry;
}, {});
return (
<Button {...finalProps} isActive={Boolean(this.props.isActive)} className={buttonTheme['btn--no-padding']}
title={this.props.i18nRegistry.translate(this.props.tooltip)}>
<Button
{...finalProps}
isActive={Boolean(this.props.isActive)}
className={style.btnWithoutPadding}
title={this.props.i18nRegistry.translate(this.props.tooltip)}
>
<svg width="18px" height="9px" viewBox="0 0 18 9" version="1.1" xmlns="http://www.w3.org/2000/svg">
<g stroke="none" strokeWidth="1" fill="none" fillRule="evenodd" strokeLinecap="square">
<path d="M16.3846154,2.61538462 L16.3846154,7.53846154 M16.3846154,7.53846154 L1.61538462,7.53846154 M1.61538462,2.61538462 L1.61538462,7.53846154" id="Combined-Shape" stroke="#FFFFFF" strokeWidth="1.8"></path>
<path
d="M16.3846154,2.61538462 L16.3846154,7.53846154 M16.3846154,7.53846154 L1.61538462,7.53846154 M1.61538462,2.61538462 L1.61538462,7.53846154"
id="Combined-Shape"
stroke="#FFFFFF"
strokeWidth="1.8"
></path>
</g>
</svg>
</Button>
Expand All @@ -69,25 +79,25 @@ class NbspButtonComponent extends PureComponent {
//
// Modify richtext editing toolbar registry
//
export default ckEditorRegistry => {
export default (ckEditorRegistry) => {
const richtextToolbar = ckEditorRegistry.get('richtextToolbar');

richtextToolbar.set('shy', {
label: 'Shy',
commandName: 'insertShyEntity',
component: HyphenButtonComponent,
component: mapGlobalRegistryToProps(HyphenButtonComponent),
callbackPropName: 'onClick',
style: 'transparent',
hoverStyle: 'brand',
tooltip: 'Shel.Neos.Hyphens:Main:ckeditor__toolbar__shy',
isVisible: (config, bar, foo) => config && config.hyphens,
isVisible: (config) => config && config.hyphens,
isActive: (config) => config && config.hyphens,
});

richtextToolbar.set('nbsp', {
label: 'Nbsp',
commandName: 'insertNbspEntity',
component: NbspButtonComponent,
component: mapGlobalRegistryToProps(NbspButtonComponent),
callbackPropName: 'onClick',
style: 'transparent',
hoverStyle: 'brand',
Expand Down
71 changes: 37 additions & 34 deletions Resources/Private/Scripts/HyphensEditor/src/plugins/hyphens.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {ViewRange} from 'ckeditor5-exports';
import { ViewRange } from 'ckeditor5-exports';
import ShyCommand from '../commands/shy';
import NbspCommand from '../commands/nbsp';
import './hyphens.vanilla-css';
import './hyphens.css';

const softHyphenCharacter = '\u00AD';
const nbspCharacter = '\u00A0';
Expand All @@ -15,47 +15,50 @@ function HyphensFactory(config) {
editor.keystrokes.set(config.shortcut, 'insertShyEntity');
}

editor.conversion.for('editingDowncast').add(dispatcher => {
dispatcher.on('insert:$text', (evt, data, conversionApi) => {
// Here should be an `if` that would check whether the feature's command is enabled.
if (!conversionApi.consumable.consume(data.item, 'insert')) {
return;
}
editor.conversion.for('editingDowncast').add((dispatcher) => {
dispatcher.on(
'insert:$text',
(evt, data, conversionApi) => {
// Here should be an `if` that would check whether the feature's command is enabled.
if (!conversionApi.consumable.consume(data.item, 'insert')) {
return;
}

const viewWriter = conversionApi.writer;
const viewWriter = conversionApi.writer;

let modelPosition = data.range.start;
let viewPosition = conversionApi.mapper.toViewPosition(modelPosition);
let modelPosition = data.range.start;
let viewPosition = conversionApi.mapper.toViewPosition(modelPosition);

const dataChunks = data.item.data.split(/([\u00AD,\u00A0])/);
const dataChunks = data.item.data.split(/([\u00AD,\u00A0])/);

for (let i = 0; i < dataChunks.length; i++) {
const chunk = dataChunks[i];
for (let i = 0; i < dataChunks.length; i++) {
const chunk = dataChunks[i];

if (chunk === '') {
continue;
}
if (chunk === '') {
continue;
}

viewWriter.insert(viewPosition, viewWriter.createText(chunk));
viewWriter.insert(viewPosition, viewWriter.createText(chunk));

// Wrap special characters with spans and matching classes for styling
if (chunk === nbspCharacter || chunk === softHyphenCharacter) {
const characterClass = chunk === nbspCharacter ? 'nbsp' : 'shy';
const viewSpaceSpan = viewWriter.createAttributeElement('span', {
class: characterClass
});
const modelWrapRange = new ViewRange(modelPosition, modelPosition.getShiftedBy(1));
const viewWrapRange = conversionApi.mapper.toViewRange(modelWrapRange);
// Wrap special characters with spans and matching classes for styling
if (chunk === nbspCharacter || chunk === softHyphenCharacter) {
const characterClass = chunk === nbspCharacter ? 'nbsp' : 'shy';
const viewSpaceSpan = viewWriter.createAttributeElement('span', {
class: characterClass,
});
const modelWrapRange = new ViewRange(modelPosition, modelPosition.getShiftedBy(1));
const viewWrapRange = conversionApi.mapper.toViewRange(modelWrapRange);

viewWriter.wrap(viewWrapRange, viewSpaceSpan);
}
viewWriter.wrap(viewWrapRange, viewSpaceSpan);
}

// Need to recalculate `viewPosition` after every inserted item.
modelPosition = modelPosition.getShiftedBy(chunk.length);
viewPosition = conversionApi.mapper.toViewPosition(modelPosition);
}
evt.stop();
}, {priority: 'high'});
// Need to recalculate `viewPosition` after every inserted item.
modelPosition = modelPosition.getShiftedBy(chunk.length);
viewPosition = conversionApi.mapper.toViewPosition(modelPosition);
}
},
{ priority: 'high' },
);
});
};
}
Expand Down
Loading