From 0dc7add99b1f52a8ec88828b6cd381dcc084d2c4 Mon Sep 17 00:00:00 2001
From: karin-lu <95747594+karin-lu@users.noreply.github.com>
Date: Mon, 5 Dec 2022 14:45:32 +0100
Subject: [PATCH 1/5] npm install
---
node-backend/package-lock.json | 11 +++++++++++
node-backend/package.json | 5 +++--
2 files changed, 14 insertions(+), 2 deletions(-)
diff --git a/node-backend/package-lock.json b/node-backend/package-lock.json
index 9ebce232..279df48b 100644
--- a/node-backend/package-lock.json
+++ b/node-backend/package-lock.json
@@ -8,6 +8,7 @@
"name": "basic-auth-app",
"version": "0.0.0",
"dependencies": {
+ "all": "^0.0.0",
"cookie-parser": "~1.4.4",
"debug": "~2.6.9",
"express": "~4.16.1",
@@ -85,6 +86,11 @@
"node": ">=0.10.0"
}
},
+ "node_modules/all": {
+ "version": "0.0.0",
+ "resolved": "https://registry.npmjs.org/all/-/all-0.0.0.tgz",
+ "integrity": "sha512-0oKlfNVv2d+d7c1gwjGspzgbwot47PGQ4b3v1ccx4mR8l9P/Y6E6Dr/yE8lNT63EcAKEbHo6UG3odDpC/NQcKw=="
+ },
"node_modules/amdefine": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz",
@@ -1342,6 +1348,11 @@
"repeat-string": "^1.5.2"
}
},
+ "all": {
+ "version": "0.0.0",
+ "resolved": "https://registry.npmjs.org/all/-/all-0.0.0.tgz",
+ "integrity": "sha512-0oKlfNVv2d+d7c1gwjGspzgbwot47PGQ4b3v1ccx4mR8l9P/Y6E6Dr/yE8lNT63EcAKEbHo6UG3odDpC/NQcKw=="
+ },
"amdefine": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz",
diff --git a/node-backend/package.json b/node-backend/package.json
index 05aafda2..3705f809 100644
--- a/node-backend/package.json
+++ b/node-backend/package.json
@@ -7,13 +7,14 @@
"start": "SET DBPORT=65535 && node ./bin/www"
},
"dependencies": {
+ "all": "^0.0.0",
"cookie-parser": "~1.4.4",
"debug": "~2.6.9",
"express": "~4.16.1",
"http-errors": "~1.6.3",
"jade": "~1.11.0",
+ "monk": "7.3.3",
"morgan": "~1.9.1",
- "njwt": "^1.0.0",
- "monk": "7.3.3"
+ "njwt": "^1.0.0"
}
}
From 227e78d97f4b5fdba6f7a0b1af1a9781d7f20175 Mon Sep 17 00:00:00 2001
From: Totta-Git Simple wysiwyg editor
+
+ Simple wysiwyg editor
-
- ', '
', '
', '
', '
', '
']
+ };
+ },
+ componentWillReceiveProps: function componentWillReceiveProps(newProps) {
+ if (this.state.ref !== newProps.reference || this.state.id !== newProps.id) {
+ this.setState({
+ ref: newProps.reference,
+ id: newProps.id
+ });
+ }
+ },
+ insertStyle: function insertStyle(type) {
+ document.execCommand(type, false, null);
+ this.contentUpdate();
+ },
+ insertHeading: function insertHeading(h) {
+ document.execCommand('formatBlock', false, h);
+ this.contentUpdate();
+ },
+ insertLink: function insertLink(uri) {
+ document.execCommand('createLink', false, uri);
+ this.setState({ link_url: '' }, function () {
+ this.contentUpdate();
+ });
+ },
+ insertField: function insertField(field, e) {
+ document.execCommand('insertText', false, field);
+ this.contentUpdate();
+ },
+ insertImage: function insertImage(uri) {
+ document.execCommand('insertImage', false, uri);
+ this.contentUpdate();
+ },
+ uploadImage: function uploadImage(e) {
+ var file = e.target.files[0];
+ var reader = new FileReader();
+ if (file) {
+ reader.onload = this.imageIsLoaded;
+ reader.readAsDataURL(file);
+ }
+ },
+ imageIsLoaded: function imageIsLoaded(e) {
+ this.insertImage(e.target.result);
+ },
+ setCursor: function setCursor() {
+ React.findDOMNode(this.refs[this.state.ref]).focus();
+ var sel = window.getSelection();
+ var range = document.createRange();
+ range.setStart(React.findDOMNode(this.refs[this.state.ref]), 0);
+ range.collapse(true);
+ sel.removeAllRanges();
+ sel.addRange(range);
+ },
+ onMouseDown: function onMouseDown() {
+ this.setCursor();
+ },
+ onKeyUp: function onKeyUp(e) {
+ this.contentUpdate();
+ },
+ contentUpdate: function contentUpdate() {
+ var target = React.findDOMNode(this.refs[this.state.ref]);
+ target.focus();
+ this.props.update(target.innerHTML, this.state.ref);
+ },
+ onUrlChange: function onUrlChange(e) {
+ this.setState({ link_url: e.target.value });
+ },
+ toolBar: function toolBar() {
+ if (!this.state.show_toolbar) {
+ return null;
+ }
+
+ return this.state.toolbar_buttons.map(function (type) {
+ return this.getButton(type);
+ }, this);
+ },
+ getButton: function getButton(type) {
+ switch (type) {
+ case 'link':
+ return React.createElement(
+ 'div',
+ { className: 'input-group', key: '_wysiwyg_' + type },
+ React.createElement(
+ 'span',
+ { className: 'input-group-btn' },
+ React.createElement(
+ 'button',
+ { key: type, type: 'button', className: 'btn btn-primary', onClick: this.insertLink.bind(null, this.state.link_url) },
+ React.createElement('i', { className: 'glyphicon glyphicon-link' })
+ )
+ ),
+ React.createElement('input', { type: 'text', className: 'form-control', placeholder: 'URL', value: this.state.link_url, onChange: this.onUrlChange })
+ );
+ case 'list':
+ return React.createElement(
+ 'button',
+ { key: type, type: 'button', className: 'btn btn-primary', onClick: this.insertStyle.bind(null, 'insertUnorderedList') },
+ React.createElement('i', { className: 'glyphicon glyphicon-list' })
+ );
+ case 'underline':
+ return React.createElement(
+ 'button',
+ { key: type, type: 'button', className: 'btn btn-primary', onClick: this.insertStyle.bind(null, type) },
+ 'U'
+ );
+ case 'justify':
+ var pos = type.split('justify')[1].toLowerCase();
+ if (pos === 'full') {
+ pos = 'justify';
+ }
+ return React.createElement(
+ 'button',
+ { key: type, type: 'button', className: 'btn btn-primary', onClick: this.insertStyle.bind(null, type) },
+ React.createElement('i', { className: "glyphicon glyphicon-align-" + pos })
+ );
+ case 'image':
+ return React.createElement('input', { style: { display: 'inline' }, key: type, type: 'file', className: 'btn btn-primary', onChange: this.uploadImage.bind(this) });
+ case 'header':
+ return this.state.headerTags.map(function (tag, i) {
+ return React.createElement(
+ 'button',
+ { key: type + '_' + tag, type: 'button', className: 'btn btn-primary', onClick: this.insertHeading.bind(null, tag) },
+ React.createElement('i', { className: "glyphicon glyphicon-header" }),
+ i + 1
+ );
+ }, this);
+ default:
+ return React.createElement(
+ 'button',
+ { key: type, type: 'button', className: 'btn btn-primary', onClick: this.insertStyle.bind(null, type) },
+ React.createElement('i', { className: "glyphicon glyphicon-" + type })
+ );
+ }
+ },
+ txtEditor: function txtEditor() {
+ return React.createElement('div', {
+ id: this.state.id,
+ ref: this.state.ref,
+ name: 'text_body',
+ className: this.state.className,
+ tabIndex: 0,
+ key: '0',
+ contentEditable: true,
+ onMouseDown: this.onMouseDown,
+ onTouchStart: this.onMouseDown,
+ onKeyUp: this.onKeyUp,
+ onClick: this.props.onClick,
+ style: this.state.style,
+ dangerouslySetInnerHTML: {
+ __html: this.props.html
+ }
+ });
+ },
+
+ render: function render() {
+ return React.createElement(
+ 'div',
+ null,
+ React.createElement(
+ 'div',
+ { className: 'form-inline' },
+ this.toolBar()
+ ),
+ this.txtEditor()
+ );
+ }
+});
+
+module.exports = TextEditor;
\ No newline at end of file
diff --git a/react-frontend/src/wysiwyg-editor-react.jsx b/react-frontend/src/wysiwyg-editor-react.jsx
new file mode 100644
index 00000000..c4440efe
--- /dev/null
+++ b/react-frontend/src/wysiwyg-editor-react.jsx
@@ -0,0 +1,145 @@
+var React = require( 'react' );
+
+var TextEditor = React.createClass({
+
+ getInitialState: function () {
+ return {
+ ref: this.props.reference || 'wysiwyg_editor',
+ id: this.props.id || 'wysiwyg_editor',
+ className: this.props.className || 'well',
+ style: this.props.style || { maxHeight: '300px', overflow: 'scroll' },
+ toolbar_buttons: this.props.toolbar_buttons || [ 'bold', 'italic', 'underline', 'list', 'link', 'justifyLeft', 'justifyCenter','justifyRight', 'justifyFull', 'image', 'header' ],
+ show_toolbar: this.props.show_toolbar === undefined ? true : this.props.show_toolbar,
+ headerTags: [ '
', '
', '
', '
', '
', '
' ]
+ }
+ },
+ componentWillReceiveProps: function ( newProps ) {
+ if ( this.state.ref !== newProps.reference || this.state.id !== newProps.id ) {
+ this.setState( {
+ ref: newProps.reference,
+ id: newProps.id
+ } );
+ }
+ },
+ insertStyle: function ( type ) {
+ document.execCommand( type, false, null );
+ this.contentUpdate();
+ },
+ insertHeading: function ( h ) {
+ document.execCommand( 'formatBlock', false, h );
+ this.contentUpdate();
+ },
+ insertLink: function ( uri ) {
+ document.execCommand( 'createLink', false, uri );
+ this.setState( { link_url: '' }, function () {
+ this.contentUpdate();
+ } );
+ },
+ insertField: function ( field, e ) {
+ document.execCommand( 'insertText', false, field );
+ this.contentUpdate();
+ },
+ insertImage: function ( uri ) {
+ document.execCommand( 'insertImage', false, uri );
+ this.contentUpdate();
+ },
+ uploadImage: function ( e ) {
+ var file = e.target.files[ 0 ];
+ var reader = new FileReader();
+ if ( file ) {
+ reader.onload = this.imageIsLoaded;
+ reader.readAsDataURL( file );
+ }
+ },
+ imageIsLoaded: function ( e ) {
+ this.insertImage( e.target.result );
+ },
+ setCursor: function () {
+ React.findDOMNode( this.refs[ this.state.ref ] ).focus();
+ var sel = window.getSelection();
+ var range = document.createRange();
+ range.setStart( React.findDOMNode( this.refs[ this.state.ref ] ), 0 );
+ range.collapse( true );
+ sel.removeAllRanges();
+ sel.addRange( range );
+ },
+ onMouseDown: function () {
+ this.setCursor();
+ },
+ onKeyUp: function ( e ) {
+ this.contentUpdate();
+ },
+ contentUpdate: function () {
+ var target = React.findDOMNode( this.refs[ this.state.ref ] );
+ target.focus();
+ this.props.update( target.innerHTML, this.state.ref );
+ },
+ onUrlChange: function ( e ) {
+ this.setState( { link_url: e.target.value } );
+ },
+ toolBar: function () {
+ if ( !this.state.show_toolbar ) { return null; }
+
+ return this.state.toolbar_buttons.map( function ( type ) {
+ return this.getButton( type );
+ }, this );
+ },
+ getButton: function ( type ) {
+ switch ( type ) {
+ case 'link':
+ return (
+