diff --git a/Configuration/Settings.yaml b/Configuration/Settings.yaml new file mode 100644 index 0000000..becfef9 --- /dev/null +++ b/Configuration/Settings.yaml @@ -0,0 +1,7 @@ +Neos: + Neos: + Ui: + resources: + javascript: + 'Psmb.Footnote:Footnote': + resource: resource://Psmb.Footnote/Public/JavaScript/Footnote/Plugin.js diff --git a/README.md b/README.md new file mode 100644 index 0000000..df76374 --- /dev/null +++ b/README.md @@ -0,0 +1,18 @@ +This package provides a footnote plugin for CKeditor5 integraion in Neos CMS. + +## Installation + +1. Switch to using CKeditor 5 +2. `composer require '@psmb/footnote'` +3. Enable footnote button on node properties that should support it, e.g.: + +``` +'Neos.NodeTypes:TextMixin': + properties: + text: + ui: + inline: + editorOptions: + formatting: + footnote: true +``` diff --git a/Resources/Private/Footnotes/.editorconfig b/Resources/Private/Footnotes/.editorconfig new file mode 100644 index 0000000..189444b --- /dev/null +++ b/Resources/Private/Footnotes/.editorconfig @@ -0,0 +1,14 @@ +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true +indent_style = space +indent_size = 4 + +[*.{yml,yaml}] +indent_size = 2 + +[*.{md}] +indent_size = 2 +trim_trailing_whitespace = false diff --git a/Resources/Private/Footnotes/.gitignore b/Resources/Private/Footnotes/.gitignore new file mode 100644 index 0000000..3c3629e --- /dev/null +++ b/Resources/Private/Footnotes/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/Resources/Private/Footnotes/package.json b/Resources/Private/Footnotes/package.json new file mode 100644 index 0000000..590aaec --- /dev/null +++ b/Resources/Private/Footnotes/package.json @@ -0,0 +1,19 @@ +{ + "description": "Footnote", + "license": "MIT", + "private": true, + "scripts": { + "build": "neos-react-scripts build", + "watch": "neos-react-scripts watch" + }, + "devDependencies": { + "@neos-project/neos-ui-extensibility": "^1.3" + }, + "neos": { + "buildTargetDirectory": "../../Public/JavaScript/Footnote" + }, + "dependencies": { + "@ckeditor/ckeditor5-utils": "^10.2.1", + "lodash.upperfirst": "^4.3.1" + } +} diff --git a/Resources/Private/Footnotes/src/FootnoteButton.js b/Resources/Private/Footnotes/src/FootnoteButton.js new file mode 100644 index 0000000..10af994 --- /dev/null +++ b/Resources/Private/Footnotes/src/FootnoteButton.js @@ -0,0 +1,102 @@ +import React, {PureComponent, Fragment} from 'react'; +import PropTypes from 'prop-types'; +import {connect} from 'react-redux'; +import {$get, $transform} from 'plow-js'; + +import {IconButton, TextArea} from '@neos-project/react-ui-components'; +import {neos} from '@neos-project/neos-ui-decorators'; +import {executeCommand} from '@neos-project/neos-ui-ckeditor5-bindings'; + +import {selectors} from '@neos-project/neos-ui-redux-store'; + +import style from './style.css'; + +@connect($transform({ + formattingUnderCursor: selectors.UI.ContentCanvas.formattingUnderCursor +})) +@neos(globalRegistry => ({ + i18nRegistry: globalRegistry.get('i18n') +})) +export default class FootnoteButton extends PureComponent { + static propTypes = { + formattingUnderCursor: PropTypes.objectOf(PropTypes.oneOfType([ + PropTypes.number, + PropTypes.bool, + PropTypes.string, + PropTypes.object + ])), + inlineEditorOptions: PropTypes.object, + i18nRegistry: PropTypes.object.isRequired + }; + + state = { + isOpen: false + }; + + componentWillReceiveProps(nextProps) { + // if new selection doesn't have a footnote, close the footnote dialog + if (!$get('footnote', nextProps.formattingUnderCursor)) { + this.setState({isOpen: false}); + } + } + + handleFootnoteButtonClick = () => { + if (this.isOpen()) { + if ($get('footnote', this.props.formattingUnderCursor) !== undefined) { + executeCommand('footnote'); + } + this.setState({isOpen: false}); + } else { + this.setState({isOpen: true}); + } + } + + render() { + const {i18nRegistry, formattingUnderCursor, inlineEditorOptions } = this.props; + + return ( +
+ + {this.isOpen() ? : null} +
+ ); + } + + isOpen() { + return Boolean(this.state.isOpen || this.getFootnote()); + } + + getFootnote() { + return $get('footnote', this.props.formattingUnderCursor) || ''; + } +} + +@neos(globalRegistry => ({ + i18nRegistry: globalRegistry.get('i18n') +})) +class FootnoteTextField extends PureComponent { + static propTypes = { + i18nRegistry: PropTypes.object, + footnoteValue: PropTypes.string, + inlineEditorOptions: PropTypes.object + }; + + render() { + return ( +
+