Skip to content

Commit db3d70d

Browse files
committed
FEATURE: Add compatibility to React UI
1 parent 66066ab commit db3d70d

File tree

12 files changed

+18786
-0
lines changed

12 files changed

+18786
-0
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Resources/Private/Scripts/YamlEditor/node_modules
2+
yarn-error.log

Configuration/Settings.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,8 @@ Neos:
44
requireJsPathMapping:
55
'Flownative.Neos.Editors/Inspector': 'resource://Flownative.Neos.Editors/Public/Scripts/Inspector'
66

7+
Ui:
8+
resources:
9+
javascript:
10+
'Flownative.Neos.Editors:Yaml':
11+
resource: resource://Flownative.Neos.Editors/Public/Scripts/ReactUI/Plugin.js
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"description": "flownative-neos-editor-yamleditor",
3+
"license": "MIT",
4+
"private": true,
5+
"scripts": {
6+
"build": "neos-react-scripts build",
7+
"watch": "neos-react-scripts watch"
8+
},
9+
"devDependencies": {
10+
"@neos-project/neos-ui-extensibility": "^1.3"
11+
},
12+
"neos": {
13+
"buildTargetDirectory": "../../../Public/Scripts/ReactUI"
14+
},
15+
"dependencies": {
16+
"codemirror": "^5.24.0",
17+
"react-codemirror2": "^5.0.1",
18+
"lodash.upperfirst": "^4.3.1"
19+
}
20+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import React, {PureComponent} from 'react';
2+
import PropTypes from 'prop-types';
3+
import {UnControlled as CodeMirror} from 'react-codemirror2';
4+
5+
export default class YamlCodeMirrorWrap extends PureComponent {
6+
static propTypes = {
7+
onChange: PropTypes.func.isRequired,
8+
value: PropTypes.string
9+
};
10+
11+
editorRefCallback = ref => {
12+
if (!ref) {
13+
return;
14+
}
15+
const codeMirrorRef = ref;
16+
const codeMirrorWrapperDomElement = codeMirrorRef.editor.display.wrapper;
17+
const offsetTop = codeMirrorWrapperDomElement.getBoundingClientRect().top;
18+
const clientHeight = window.innerHeight || document.clientHeight || document.getElementByTagName('body').clientHeight;
19+
const height = clientHeight - offsetTop;
20+
codeMirrorRef.editor.setSize(null, height);
21+
};
22+
23+
onChangeCallback = (editor, data, value) => {
24+
const cursorCoordinates = editor.getCursor();
25+
let newValue;
26+
27+
// we replace inserted tabs with two spaces, because we need to work around CM behaviour
28+
if (editor._isCleaningUpTabs !== true) {
29+
editor._isCleaningUpTabs = true;
30+
newValue = value.replace(/^( *)\t/m, '$1 ');
31+
if (value !== newValue) {
32+
editor.setValue(newValue);
33+
// set character one ahead, since we replaced one tab by two spaces
34+
editor.setCursor({'line': cursorCoordinates.line, 'ch': cursorCoordinates.ch + 1});
35+
}
36+
editor._isCleaningUpTabs = false;
37+
}
38+
this.props.onChange(value);
39+
};
40+
41+
render() {
42+
const options = {
43+
mode: 'text/x-yaml',
44+
theme: 'twilight',
45+
indentWithTabs: false,
46+
tabSize: 2,
47+
indentUnit: 2,
48+
styleActiveLine: true,
49+
lineNumbers: true,
50+
lineWrapping: true,
51+
autoClearEmptyLines: true,
52+
_isCleaningUpTabs: false
53+
};
54+
55+
return (
56+
<CodeMirror value={this.props.value} options={options} ref={this.editorRefCallback}
57+
onChange={this.onChangeCallback} />
58+
);
59+
}
60+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import React, {PureComponent} from 'react';
2+
import PropTypes from 'prop-types';
3+
import {$get} from 'plow-js';
4+
5+
import {Button,Icon,Label} from '@neos-project/react-ui-components';
6+
import {I18n} from '@neos-project/neos-ui-i18n';
7+
import {neos} from '@neos-project/neos-ui-decorators';
8+
9+
import style from './style.css';
10+
11+
import YamlMode from 'codemirror/mode/yaml/yaml';
12+
13+
@neos(globalRegistry => ({
14+
secondaryEditorsRegistry: globalRegistry.get('inspector').get('secondaryEditors')
15+
}))
16+
export default class CodeMirror extends PureComponent {
17+
static propTypes = {
18+
className: PropTypes.string,
19+
identifier: PropTypes.string.isRequired,
20+
renderSecondaryInspector: PropTypes.func.isRequired,
21+
commit: PropTypes.func.isRequired,
22+
label: PropTypes.string.isRequired,
23+
value: PropTypes.string,
24+
secondaryEditorsRegistry: PropTypes.object.isRequired,
25+
options: PropTypes.object
26+
};
27+
28+
render() {
29+
const {label, identifier, className} = this.props;
30+
const disabled = $get('options.disabled', this.props);
31+
const handleClick = () => disabled ? null : this.handleOpenCodeEditor;
32+
33+
return (
34+
<div>
35+
<Label className={style.codemirror__label} htmlFor={identifier}>
36+
<Button className={className} style="lighter" disabled={disabled} onClick={handleClick()}>
37+
<Icon icon="pencil" padded="right" title="Edit"/>
38+
{label}
39+
</Button>
40+
</Label>
41+
</div>
42+
);
43+
}
44+
45+
handleChange = newValue => {
46+
this.props.commit(newValue);
47+
};
48+
49+
handleOpenCodeEditor = () => {
50+
const {secondaryEditorsRegistry} = this.props;
51+
const {component: YamlCodeMirrorWrap} = secondaryEditorsRegistry.get('Flownative.Neos.Editors/Editors/Secondary/YamlCodeMirrorWrap');
52+
53+
this.props.renderSecondaryInspector('CODEMIRROR_EDIT', () =>
54+
<YamlCodeMirrorWrap onChange={this.handleChange} value={this.props.value} highlightingMode='text/x-yaml'/>
55+
);
56+
}
57+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.codemirror__label {
2+
padding: 2px;
3+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import React from 'react';
2+
import I18n from '@neos-project/neos-ui-i18n';
3+
import yaml from '../../../../../Public/Scripts/Inspector/Validators/js-yaml.min'
4+
5+
/**
6+
* Checks if the given value is valid YAML
7+
*/
8+
const YamlValidator = value => {
9+
if (typeof(value) !== 'string') {
10+
this.addError(I18n.translate('content.inspector.validators.stringValidator.stringIsExpected'));
11+
}
12+
13+
try {
14+
yaml.safeLoad(value, 'utf8');
15+
return null;
16+
} catch (e) {
17+
console.log(e);
18+
return 'Invalid YAML, ' + e.message;
19+
}
20+
};
21+
22+
export default YamlValidator;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
require('./manifest');
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import manifest from '@neos-project/neos-ui-extensibility';
2+
3+
import YamlEditor from './YamlEditor/index';
4+
import YamlCodeMirrorWrap from "./Secondary/YamlCodeMirrorWrap";
5+
import YamlValidator from './YamlValidator/index';
6+
7+
manifest('Flownative.Neos.Editors:YamlEditor', {}, globalRegistry => {
8+
const editorsRegistry = globalRegistry.get('inspector').get('editors');
9+
const secondaryEditorsRegistry = globalRegistry.get('inspector').get('secondaryEditors');
10+
const validatorRegistry = globalRegistry.get('validators');
11+
12+
editorsRegistry.set('Flownative.Neos.Editors/Inspector/Editors/Yaml', {
13+
component: YamlEditor
14+
});
15+
secondaryEditorsRegistry.set('Flownative.Neos.Editors/Editors/Secondary/YamlCodeMirrorWrap', {
16+
component: YamlCodeMirrorWrap
17+
});
18+
validatorRegistry.set('Flownative.Neos.Editors/Inspector/Validators/Yaml', YamlValidator);
19+
});

0 commit comments

Comments
 (0)