From 5a06b7dcd4c7f707d186a95c9e74f5e261dcd844 Mon Sep 17 00:00:00 2001 From: Aleksander Nowodzinski Date: Thu, 23 Dec 2021 15:39:11 +0100 Subject: [PATCH 1/5] Implemented a modal to set editor data. --- package.json | 1 + src/assets/img/load-data.svg | 1 + src/assets/img/source.svg | 2 +- src/editorquickactions.js | 2 + src/seteditordatabutton.css | 114 +++++++++++++++++++++++++++++++++++ src/seteditordatabutton.js | 109 +++++++++++++++++++++++++++++++++ src/ui.css | 7 ++- yarn.lock | 27 +++++++++ 8 files changed, 260 insertions(+), 3 deletions(-) create mode 100644 src/assets/img/load-data.svg create mode 100644 src/seteditordatabutton.css create mode 100644 src/seteditordatabutton.js diff --git a/package.json b/package.json index 4bbfb90..1377d42 100644 --- a/package.json +++ b/package.json @@ -74,6 +74,7 @@ "prop-types": "^15.7.2", "react": "^16.14.0", "react-dom": "^16.14.0", + "react-modal": "^3.14.4", "react-redux": "^7.2.6", "react-rnd": "~10.2.4", "react-svg-loader": "^3.0.3", diff --git a/src/assets/img/load-data.svg b/src/assets/img/load-data.svg new file mode 100644 index 0000000..7d244a8 --- /dev/null +++ b/src/assets/img/load-data.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/img/source.svg b/src/assets/img/source.svg index 1c3ebfe..e1b66da 100644 --- a/src/assets/img/source.svg +++ b/src/assets/img/source.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/src/editorquickactions.js b/src/editorquickactions.js index 713b702..9407a3c 100644 --- a/src/editorquickactions.js +++ b/src/editorquickactions.js @@ -9,6 +9,7 @@ import React, { Component } from 'react'; import { connect } from 'react-redux'; import copy from 'copy-to-clipboard'; +import SetEditorDataButton from './seteditordatabutton'; import Button from './components/button'; import SourceIcon from './assets/img/source.svg'; @@ -43,6 +44,7 @@ class EditorQuickActions extends Component { onClick={() => console.log( this.props.editor )} /> { this._getLogButton() } + + + + + + ]; + } + + _setEditorData() { + this.props.editor.setData( this.state.setDataModalValue ); + + this._closeModal(); + } + + _closeModal() { + this.setState( { + isSetDataModalOpen: false + } ); + } + + _handleSetDataModalValueChange( evt ) { + this.setState( { + setDataModalValue: evt.target.value + } ); + } +} diff --git a/src/ui.css b/src/ui.css index 92e021f..d54fc26 100644 --- a/src/ui.css +++ b/src/ui.css @@ -3,7 +3,8 @@ * For licensing, see LICENSE.md. */ -.ck-inspector { +.ck-inspector, +.ck-inspector-portal { --ck-inspector-color-white: #fff; --ck-inspector-color-black: #000; --ck-inspector-color-background: #F3F3F3; @@ -15,7 +16,9 @@ /* Reset first */ .ck-inspector, -.ck-inspector *:not(select) { +.ck-inspector *:not(select), +.ck-inspector-portal, +.ck-inspector-portal *:not(select) { box-sizing: border-box; width: auto; height: auto; diff --git a/yarn.lock b/yarn.lock index bc3ceec..4c4f028 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3649,6 +3649,11 @@ execa@^4.1.0: signal-exit "^3.0.2" strip-final-newline "^2.0.0" +exenv@^1.2.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/exenv/-/exenv-1.2.2.tgz#2ae78e85d9894158670b03d47bec1f03bd91bb9d" + integrity sha1-KueOhdmJQVhnCwPUe+wfA72Ru50= + expand-brackets@^2.1.4: version "2.1.4" resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" @@ -7433,6 +7438,21 @@ react-is@^17.0.2: resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== +react-lifecycles-compat@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" + integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA== + +react-modal@^3.14.4: + version "3.14.4" + resolved "https://registry.yarnpkg.com/react-modal/-/react-modal-3.14.4.tgz#2ca7e8e9a180955e5c9508c228b73167c1e6f6a3" + integrity sha512-8surmulejafYCH9wfUmFyj4UfbSJwjcgbS9gf3oOItu4Hwd6ivJyVBETI0yHRhpJKCLZMUtnhzk76wXTsNL6Qg== + dependencies: + exenv "^1.2.0" + prop-types "^15.7.2" + react-lifecycles-compat "^3.0.0" + warning "^4.0.3" + react-redux@^7.2.6: version "7.2.6" resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.6.tgz#49633a24fe552b5f9caf58feb8a138936ddfe9aa" @@ -9217,6 +9237,13 @@ void-elements@^2.0.0: resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-2.0.1.tgz#c066afb582bb1cb4128d60ea92392e94d5e9dbec" integrity sha1-wGavtYK7HLQSjWDqkjkulNXp2+w= +warning@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3" + integrity sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w== + dependencies: + loose-envify "^1.0.0" + watchpack-chokidar2@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/watchpack-chokidar2/-/watchpack-chokidar2-2.0.1.tgz#38500072ee6ece66f3769936950ea1771be1c957" From 791a47b9e48e4d4d979e1daf1a3df07c4c139f70 Mon Sep 17 00:00:00 2001 From: Aleksander Nowodzinski Date: Fri, 4 Feb 2022 18:14:19 +0100 Subject: [PATCH 2/5] WIP --- src/seteditordatabutton.js | 28 +++-- tests/inspector/editorquickactions.js | 40 +++++++ tests/inspector/seteditordatabutton.js | 145 +++++++++++++++++++++++++ 3 files changed, 206 insertions(+), 7 deletions(-) create mode 100644 tests/inspector/seteditordatabutton.js diff --git a/src/seteditordatabutton.js b/src/seteditordatabutton.js index d4fd665..4c75299 100644 --- a/src/seteditordatabutton.js +++ b/src/seteditordatabutton.js @@ -13,6 +13,7 @@ import LoadDataIcon from './assets/img/load-data.svg'; import './seteditordatabutton.css'; +// TODO: Let's move this button to components maybe? export default class SetEditorDataButton extends Component { constructor( props ) { super( props ); @@ -31,17 +32,19 @@ export default class SetEditorDataButton extends Component { text="Set editor data" icon={} isEnabled={!!this.props.editor} - onClick={() => this.setState( { isSetDataModalOpen: true } )} + onClick={() => this.setState( { + isSetDataModalOpen: true + } )} key="button" />, this.setState( { setDataModalValue: '' } )} + onAfterOpen={this._handleModalAfterOpen.bind( this )} overlayClassName='ck-inspector-modal ck-inspector-quick-actions__set-data-modal' className='ck-inspector-quick-actions__set-data-modal__content' onRequestClose={this._closeModal.bind( this )} - portalClassName="ck-inspector-portal" + portalClassName='ck-inspector-portal' shouldCloseOnEsc={true} shouldCloseOnOverlayClick={true} key="modal" @@ -69,19 +72,22 @@ export default class SetEditorDataButton extends Component { } ); this.textarea.current.focus(); - }}> - Load current editor data + }} + > + Load data @@ -106,4 +112,12 @@ export default class SetEditorDataButton extends Component { setDataModalValue: evt.target.value } ); } + + _handleModalAfterOpen() { + this.setState( { + setDataModalValue: this.props.editor.getData() + } ); + + this.textarea.current.select(); + } } diff --git a/tests/inspector/editorquickactions.js b/tests/inspector/editorquickactions.js index 5b4843c..8834df0 100644 --- a/tests/inspector/editorquickactions.js +++ b/tests/inspector/editorquickactions.js @@ -15,6 +15,7 @@ import EditorQuickActions from '../../src/editorquickactions'; import SourceIcon from '../../src/assets/img/source.svg'; import CopyToClipboardIcon from '../../src/assets/img/copy-to-clipboard.svg'; import CheckmarkIcon from '../../src/assets/img/checkmark.svg'; +import LoadDataIcon from '../../src/assets/img/load-data.svg'; describe( '', () => { let editor, store, wrapper, element; @@ -261,6 +262,45 @@ describe( '', () => { } ); } ); + describe( 'set editor data button', () => { + let inspectorWrapper; + + beforeEach( () => { + // needs this. It will warn otherwise. + inspectorWrapper = document.createElement( 'div' ); + inspectorWrapper.classList.add( 'ck-inspector-wrapper' ); + document.body.appendChild( inspectorWrapper ); + } ); + + afterEach( () => { + inspectorWrapper.remove(); + } ); + + it( 'should be rendered', () => { + const setDataButton = wrapper.find( 'SetEditorDataButton' ); + + expect( setDataButton.childAt( 0 ).props().text ).to.equal( 'Set editor data' ); + expect( setDataButton.childAt( 0 ).props().icon.type ).to.equal( LoadDataIcon ); + } ); + + it( 'should open a model when clicked', () => { + const setDataButton = wrapper.find( 'SetEditorDataButton' ); + + expect( setDataButton.state() ).to.deep.equal( { + isSetDataModalOpen: false, + setDataModalValue: '' + }, 'before click' ); + + setDataButton.simulate( 'click' ); + wrapper.update(); + + expect( setDataButton.state() ).to.deep.equal( { + isSetDataModalOpen: true, + setDataModalValue: '' + }, 'after click' ); + } ); + } ); + describe( 'toggle read only button', () => { it( 'should be rendered and toggle the editor read only state', () => { const toggleReadOnlyButton = wrapper.find( 'Button' ).at( 2 ); diff --git a/tests/inspector/seteditordatabutton.js b/tests/inspector/seteditordatabutton.js new file mode 100644 index 0000000..bd8380d --- /dev/null +++ b/tests/inspector/seteditordatabutton.js @@ -0,0 +1,145 @@ +/** + * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved. + * For licensing, see LICENSE.md. + */ + +/* global document, window */ + +import React from 'react'; +import TestEditor from '../utils/testeditor'; + +import SetEditorDataButton from '../../src/seteditordatabutton'; + +import LoadDataIcon from '../../src/assets/img/load-data.svg'; + +// TODO: Let's move this button to components maybe? +describe( '', () => { + let editor, wrapper, element, inspectorWrapperDomElement; + + beforeEach( () => { + window.localStorage.clear(); + + element = document.createElement( 'div' ); + document.body.appendChild( element ); + + // needs this. It will warn otherwise. + inspectorWrapperDomElement = document.createElement( 'div' ); + inspectorWrapperDomElement.classList.add( 'ck-inspector-wrapper' ); + document.body.appendChild( inspectorWrapperDomElement ); + + return TestEditor.create( element ).then( newEditor => { + editor = newEditor; + + wrapper = mount( ); + } ); + } ); + + afterEach( () => { + wrapper.unmount(); + + element.remove(); + + inspectorWrapperDomElement.remove(); + + return editor.destroy(); + } ); + + describe( 'constructor()', () => { + it( 'should have initial state', () => { + expect( wrapper.state() ).to.deep.equal( { + isSetDataModalOpen: false, + setDataModalValue: '' + } ); + } ); + } ); + + describe( 'render()', () => { + describe( '