From f175669dc0d315f99345fc01e3edb57455e0979b Mon Sep 17 00:00:00 2001 From: ivan Date: Thu, 2 Mar 2017 00:00:45 -0300 Subject: [PATCH] Ivan - Allow international characters improve text editor [skip ci] --- client/package.json | 8 +- client/src/app-components/ticket-viewer.js | 8 +- .../articles/admin-panel-view-article.js | 4 +- .../settings/admin-panel-email-templates.js | 6 +- .../panel/staff/admin-panel-departments.js | 2 - .../tickets/admin-panel-custom-responses.js | 6 +- .../create-ticket-form.js | 6 +- .../__mocks__/text-editor-mock.js | 17 + .../__tests__/form-field-test.js | 13 +- .../core-components/__tests__/form-test.js | 12 +- client/src/core-components/form-field.js | 3 +- client/src/core-components/form.js | 6 +- client/src/core-components/text-editor.js | 62 +- client/src/core-components/text-editor.scss | 5 + client/src/data/fixtures/staff-fixtures.js | 84 +- client/src/data/fixtures/ticket-fixtures.js | 2 +- .../lib-app/validations/length-validator.js | 6 +- .../validations/validations-factory.js | 5 +- client/src/lib-app/validations/validator.js | 6 +- client/src/main.scss | 1 + client/src/scss/_react-draft-wysiwyg.scss | 985 ++++++++++++++++++ server/controllers/article/add-topic.php | 2 - server/controllers/article/add.php | 2 - server/controllers/staff/add.php | 2 +- server/controllers/staff/search-tickets.php | 2 +- server/controllers/system/delete-api-key.php | 2 +- server/controllers/user/signup.php | 2 +- 27 files changed, 1152 insertions(+), 107 deletions(-) create mode 100644 client/src/core-components/__mocks__/text-editor-mock.js create mode 100644 client/src/scss/_react-draft-wysiwyg.scss diff --git a/client/package.json b/client/package.json index 22a71851..58180d8f 100644 --- a/client/package.json +++ b/client/package.json @@ -55,9 +55,9 @@ "dependencies": { "app-module-path": "^1.0.3", "chart.js": "^2.4.0", - "classnames": "^2.1.3", - "draft-js": "^0.8.1", - "draft-js-export-html": "^0.4.0", + "classnames": "^2.2.5", + "draft-js": "^0.10.0", + "draft-js-export-html": "^0.5.2", "jquery": "^2.1.4", "keycode": "^2.1.4", "localStorage": "^1.0.3", @@ -67,12 +67,12 @@ "react-chartjs-2": "^2.0.0", "react-document-title": "^1.0.2", "react-dom": "^15.0.1", + "react-draft-wysiwyg": "^1.7.6", "react-google-recaptcha": "^0.5.2", "react-motion": "^0.4.7", "react-redux": "^4.4.5", "react-router": "^2.4.0", "react-router-redux": "^4.0.5", - "react-rte-browserify": "^0.5.0", "redux": "^3.5.2", "redux-promise-middleware": "^3.3.2" } diff --git a/client/src/app-components/ticket-viewer.js b/client/src/app-components/ticket-viewer.js index adc85536..265a1a9e 100644 --- a/client/src/app-components/ticket-viewer.js +++ b/client/src/app-components/ticket-viewer.js @@ -1,6 +1,5 @@ import React from 'react'; import _ from 'lodash'; -import RichTextEditor from 'react-rte-browserify'; import {connect} from 'react-redux'; import i18n from 'lib-app/i18n'; @@ -17,6 +16,7 @@ import DropDown from 'core-components/drop-down'; import Button from 'core-components/button'; import Message from 'core-components/message'; import Icon from 'core-components/icon'; +import TextEditor from 'core-components/text-editor'; class TicketViewer extends React.Component { static propTypes = { @@ -38,7 +38,7 @@ class TicketViewer extends React.Component { state = { loading: false, - commentValue: RichTextEditor.createEmptyValue(), + commentValue: TextEditor.createEmpty(), commentEdited: false }; @@ -305,7 +305,7 @@ class TicketViewer extends React.Component { onCustomResponsesChanged({index}) { let replaceContentWithCustomResponse = () => { this.setState({ - commentValue: RichTextEditor.createValueFromString(this.props.customResponses[index-1].content || '', 'html'), + commentValue: TextEditor.getEditorStateFromHTML(this.props.customResponses[index-1].content || ''), commentEdited: false }); }; @@ -334,7 +334,7 @@ class TicketViewer extends React.Component { onCommentSuccess() { this.setState({ loading: false, - commentValue: RichTextEditor.createEmptyValue(), + commentValue: TextEditor.createEmpty(), commentError: false, commentEdited: false }); diff --git a/client/src/app/admin/panel/articles/admin-panel-view-article.js b/client/src/app/admin/panel/articles/admin-panel-view-article.js index 13ec35c2..a399142c 100644 --- a/client/src/app/admin/panel/articles/admin-panel-view-article.js +++ b/client/src/app/admin/panel/articles/admin-panel-view-article.js @@ -2,7 +2,6 @@ import React from 'react'; import _ from 'lodash'; import {connect} from 'react-redux'; import {browserHistory} from 'react-router'; -import RichTextEditor from 'react-rte-browserify'; import ArticlesActions from 'actions/articles-actions'; import SessionStore from 'lib-app/session-store'; @@ -17,6 +16,7 @@ import Button from 'core-components/button'; import Form from 'core-components/form'; import FormField from 'core-components/form-field'; import SubmitButton from 'core-components/submit-button'; +import TextEditor from 'core-components/text-editor'; class AdminPanelViewArticle extends React.Component { @@ -117,7 +117,7 @@ class AdminPanelViewArticle extends React.Component { editable: true, form: { title: article.title, - content: RichTextEditor.createValueFromString(article.content, 'html') + content: TextEditor.getEditorStateFromHTML(article.content) } }); } diff --git a/client/src/app/admin/panel/settings/admin-panel-email-templates.js b/client/src/app/admin/panel/settings/admin-panel-email-templates.js index 99bdee30..74badc5f 100644 --- a/client/src/app/admin/panel/settings/admin-panel-email-templates.js +++ b/client/src/app/admin/panel/settings/admin-panel-email-templates.js @@ -1,6 +1,5 @@ import React from 'react'; import _ from 'lodash'; -import RichTextEditor from 'react-rte-browserify'; import i18n from 'lib-app/i18n'; import API from 'lib-app/api-call'; @@ -15,6 +14,7 @@ import Loading from 'core-components/loading'; import Form from 'core-components/form'; import FormField from 'core-components/form-field'; import SubmitButton from 'core-components/submit-button'; +import TextEditor from 'core-components/text-editor'; class AdminPanelEmailTemplates extends React.Component { @@ -28,7 +28,7 @@ class AdminPanelEmailTemplates extends React.Component { language: 'en', form: { title: '', - content: RichTextEditor.createEmptyValue() + content: TextEditor.createEmpty() } }; @@ -182,7 +182,7 @@ class AdminPanelEmailTemplates extends React.Component { language = language || this.state.language; form.title = (items[index] && items[index][language].subject) || ''; - form.content = RichTextEditor.createValueFromString((items[index] && items[index][language].body) || '', 'html'); + form.content = TextEditor.getEditorStateFromHTML((items[index] && items[index][language].body) || ''); this.setState({ selectedIndex: index, diff --git a/client/src/app/admin/panel/staff/admin-panel-departments.js b/client/src/app/admin/panel/staff/admin-panel-departments.js index 64a508d8..4c93928c 100644 --- a/client/src/app/admin/panel/staff/admin-panel-departments.js +++ b/client/src/app/admin/panel/staff/admin-panel-departments.js @@ -1,7 +1,6 @@ import React from 'react'; import _ from 'lodash'; import {connect} from 'react-redux'; -import RichTextEditor from 'react-rte-browserify'; import i18n from 'lib-app/i18n'; import API from 'lib-app/api-call'; @@ -31,7 +30,6 @@ class AdminPanelDepartments extends React.Component { errors: {}, form: { title: '', - content: RichTextEditor.createEmptyValue(), language: 'en' } }; diff --git a/client/src/app/admin/panel/tickets/admin-panel-custom-responses.js b/client/src/app/admin/panel/tickets/admin-panel-custom-responses.js index 9531652a..25a640a4 100644 --- a/client/src/app/admin/panel/tickets/admin-panel-custom-responses.js +++ b/client/src/app/admin/panel/tickets/admin-panel-custom-responses.js @@ -1,7 +1,6 @@ import React from 'react'; import _ from 'lodash'; import {connect} from 'react-redux'; -import RichTextEditor from 'react-rte-browserify'; import i18n from 'lib-app/i18n'; import API from 'lib-app/api-call'; @@ -18,6 +17,7 @@ import Loading from 'core-components/loading'; import Form from 'core-components/form'; import FormField from 'core-components/form-field'; import SubmitButton from 'core-components/submit-button'; +import TextEditor from 'core-components/text-editor'; class AdminPanelCustomResponses extends React.Component { static defaultProps = { @@ -31,7 +31,7 @@ class AdminPanelCustomResponses extends React.Component { errors: {}, form: { title: '', - content: RichTextEditor.createEmptyValue(), + content: TextEditor.createEmpty(), language: 'en' } }; @@ -203,7 +203,7 @@ class AdminPanelCustomResponses extends React.Component { let form = _.clone(this.state.form); form.title = (this.props.items[index] && this.props.items[index].name) || ''; - form.content = RichTextEditor.createValueFromString((this.props.items[index] && this.props.items[index].content) || '', 'html'); + form.content = TextEditor.getEditorStateFromHTML((this.props.items[index] && this.props.items[index].content) || ''); form.language = (this.props.items[index] && this.props.items[index].language) || 'en'; this.setState({ diff --git a/client/src/app/main/dashboard/dashboard-create-ticket/create-ticket-form.js b/client/src/app/main/dashboard/dashboard-create-ticket/create-ticket-form.js index 0e927776..469f9af4 100644 --- a/client/src/app/main/dashboard/dashboard-create-ticket/create-ticket-form.js +++ b/client/src/app/main/dashboard/dashboard-create-ticket/create-ticket-form.js @@ -1,8 +1,8 @@ import React from 'react'; import _ from 'lodash'; -import ReCAPTCHA from 'react-google-recaptcha'; import { browserHistory } from 'react-router'; -import RichTextEditor from 'react-rte-browserify'; +import {EditorState, convertToRaw} from 'draft-js'; +import { mdToDraftjs, draftjsToMd } from 'draftjs-md-converter'; import i18n from 'lib-app/i18n'; import API from 'lib-app/api-call'; @@ -33,7 +33,7 @@ class CreateTicketForm extends React.Component { message: null, form: { title: '', - content: RichTextEditor.createEmptyValue(), + content: EditorState.createEmpty(), departmentIndex: 0, email: '', name: '', diff --git a/client/src/core-components/__mocks__/text-editor-mock.js b/client/src/core-components/__mocks__/text-editor-mock.js new file mode 100644 index 00000000..c00080ca --- /dev/null +++ b/client/src/core-components/__mocks__/text-editor-mock.js @@ -0,0 +1,17 @@ +import _ from 'lodash'; + +let Mock = ReactMock(); + +_.extend(Mock, { + createEmpty: stub().returns({editorState: true}), + + getEditorStateFromHTML: stub().returns({editorState: true}), + + getHTMLFromEditorState: stub().returns('HTML_CODE'), + + isEditorState: (item) => { + return item.editorState; + } +}); + +export default Mock; \ No newline at end of file diff --git a/client/src/core-components/__tests__/form-field-test.js b/client/src/core-components/__tests__/form-field-test.js index 0d84c0a2..170b6b76 100644 --- a/client/src/core-components/__tests__/form-field-test.js +++ b/client/src/core-components/__tests__/form-field-test.js @@ -1,15 +1,13 @@ const Input = ReactMock(); const Checkbox = ReactMock(); const DropDown = ReactMock(); -const TextEditor = ReactMock(); - -const RichTextEditor = require('react-rte-browserify'); +const TextEditorMock = require('core-components/__mocks__/text-editor-mock'); const FormField = requireUnit('core-components/form-field', { 'core-components/input': Input, 'core-components/checkbox': Checkbox, 'core-components/drop-down': DropDown, - 'core-components/text-editor': TextEditor + 'core-components/text-editor': TextEditorMock }); @@ -21,7 +19,7 @@ describe('FormField component', function () { 'input': Input, 'checkbox': Checkbox, 'select': DropDown, - 'textarea': TextEditor + 'textarea': TextEditorMock }; component = reRenderIntoDocument( @@ -32,10 +30,9 @@ describe('FormField component', function () { describe('when calling static getDefaultValue', function () { it('should return correct values', function () { - expect(FormField.getDefaultValue('input')).to.equal(''); expect(FormField.getDefaultValue('checkbox')).to.equal(false); expect(FormField.getDefaultValue('select')).to.equal(0); - expect(FormField.getDefaultValue('textarea') instanceof RichTextEditor.EditorValue).to.equal(true); + expect(FormField.getDefaultValue('textarea')).to.equal(TextEditorMock.createEmpty()); }); }); @@ -415,7 +412,7 @@ describe('FormField component', function () { errored: true, name: 'MOCK_NAME', onBlur: component.props.onBlur, - required: true, + required: true }); expect(innerField.props.value).to.deep.equal({value: 'VALUE_MOCk'}); }); diff --git a/client/src/core-components/__tests__/form-test.js b/client/src/core-components/__tests__/form-test.js index 27518d84..f8d31de3 100644 --- a/client/src/core-components/__tests__/form-test.js +++ b/client/src/core-components/__tests__/form-test.js @@ -1,12 +1,13 @@ // MOCKS const ValidationFactoryMock = require('lib-app/__mocks__/validations/validation-factory-mock'); +const TextEditorMock = require('core-components/__mocks__/text-editor-mock'); const FormField = ReactMock(); -const RichTextEditor = require('react-rte-browserify'); // COMPONENT const Form = requireUnit('core-components/form', { 'lib-app/validations/validations-factory': ValidationFactoryMock, - 'core-components/form-field': FormField + 'core-components/form-field': FormField, + 'core-components/text-editor': TextEditorMock }); describe('Form component', function () { @@ -186,12 +187,11 @@ describe('Form component', function () { expect(form.props.onSubmit).to.not.have.been.called; }); - it('should tranform RichTextEditor value to HTML', function () { - form.state.form.first = RichTextEditor.createEmptyValue(); - form.state.form.first.toString = stub().returns('HTML_CODE'); + it('should transform TextEdit value to HTML', function () { + form.state.form.first = TextEditorMock.createEmpty(); TestUtils.Simulate.submit(ReactDOM.findDOMNode(form)); - expect(form.state.form.first.toString).to.have.been.called; + expect(TextEditorMock.getHTMLFromEditorState).to.have.been.calledWith(form.state.form.first); expect(form.props.onSubmit).to.have.been.calledWith({ first: 'HTML_CODE', second: 'value2', diff --git a/client/src/core-components/form-field.js b/client/src/core-components/form-field.js index d12dbe47..376c11db 100644 --- a/client/src/core-components/form-field.js +++ b/client/src/core-components/form-field.js @@ -1,5 +1,4 @@ import React from 'react'; -import RichTextEditor from 'react-rte-browserify'; import classNames from 'classnames'; import _ from 'lodash'; @@ -44,7 +43,7 @@ class FormField extends React.Component { return []; } else if (field === 'textarea') { - return RichTextEditor.createEmptyValue(); + return TextEditor.createEmpty(); } else if (field === 'select') { return 0; diff --git a/client/src/core-components/form.js b/client/src/core-components/form.js index 2fc3f14d..e7387e03 100644 --- a/client/src/core-components/form.js +++ b/client/src/core-components/form.js @@ -1,12 +1,12 @@ import React from 'react'; import _ from 'lodash'; import classNames from 'classnames'; -import RichTextEditor from 'react-rte-browserify'; import {reactDFS, renderChildrenWithProps} from 'lib-core/react-dfs'; import ValidationFactory from 'lib-app/validations/validations-factory'; import FormField from 'core-components/form-field'; +import TextEditor from 'core-components/text-editor'; class Form extends React.Component { @@ -161,8 +161,8 @@ class Form extends React.Component { event.preventDefault(); const form = _.mapValues(this.getFormValue(), (field) => { - if (field instanceof RichTextEditor.EditorValue) { - return field.toString('html'); + if (TextEditor.isEditorState(field)) { + return TextEditor.getHTMLFromEditorState(field); } else { return field; } diff --git a/client/src/core-components/text-editor.js b/client/src/core-components/text-editor.js index 2364c741..486fbd90 100644 --- a/client/src/core-components/text-editor.js +++ b/client/src/core-components/text-editor.js @@ -1,6 +1,8 @@ import React from 'react'; import classNames from 'classnames'; -import RichTextEditor from 'react-rte-browserify'; +import {Editor} from 'react-draft-wysiwyg'; +import {EditorState, ContentState, convertFromHTML} from 'draft-js'; +import {stateToHTML} from 'draft-js-export-html'; class TextEditor extends React.Component { static propTypes = { @@ -8,16 +10,38 @@ class TextEditor extends React.Component { onChange: React.PropTypes.func, value: React.PropTypes.object }; + + static createEmpty() { + return EditorState.createEmpty() + } + + static getEditorStateFromHTML(htmlString) { + const blocksFromHTML = convertFromHTML(htmlString); + const state = ContentState.createFromBlockArray( + blocksFromHTML.contentBlocks, + blocksFromHTML.entityMap + ); + + return EditorState.createWithContent(state); + } + + static getHTMLFromEditorState(editorState) { + return stateToHTML(editorState.getCurrentContent()); + } + + static isEditorState(editorState) { + return editorState && editorState.getCurrentContent; + } state = { - value: RichTextEditor.createEmptyValue(), + value: EditorState.createEmpty(), focused: false }; render() { return (
- +
); } @@ -36,15 +60,39 @@ class TextEditor extends React.Component { getEditorProps() { return { - className: 'text-editor__editor', - value: this.props.value || this.state.value, + wrapperClassName: 'text-editor__editor', + editorState: this.props.value || this.state.value, ref: 'editor', - onChange: this.onEditorChange.bind(this), + toolbar: this.getToolbarOptions(), + onEditorStateChange: this.onEditorChange.bind(this), onFocus: this.onEditorFocus.bind(this), onBlur: this.onBlur.bind(this) }; } + getToolbarOptions() { + return { + options: ['inline', 'blockType', 'list', 'link', 'image'], + inline: { + inDropdown: false, + options: ['bold', 'italic', 'underline', 'strikethrough', 'monospace'] + }, + blockType: { + inDropdown: true, + options: [ 'Normal', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'Blockquote'] + }, + list: { + inDropdown: false, + options: ['unordered', 'ordered'] + }, + image: { + urlEnabled: true, + uploadEnabled: false, + alignmentEnabled: false + } + }; + } + onEditorChange(value) { this.setState({value}); @@ -71,7 +119,7 @@ class TextEditor extends React.Component { focus() { if (this.refs.editor) { - this.refs.editor._focus(); + this.refs.editor.focusEditor(); } } } diff --git a/client/src/core-components/text-editor.scss b/client/src/core-components/text-editor.scss index e1d65935..fec643a2 100644 --- a/client/src/core-components/text-editor.scss +++ b/client/src/core-components/text-editor.scss @@ -8,6 +8,11 @@ .DraftEditor-root { height: 200px; + padding-left: 10px; + } + + .public-DraftEditor-content { + height: 185px; } } diff --git a/client/src/data/fixtures/staff-fixtures.js b/client/src/data/fixtures/staff-fixtures.js index ac7a07ee..77e47603 100644 --- a/client/src/data/fixtures/staff-fixtures.js +++ b/client/src/data/fixtures/staff-fixtures.js @@ -10,7 +10,7 @@ module.exports = [ data: { name: 'Emilia Clarke', email: 'staff@opensupports.com', - profilePic: 'http://www.opensupports.com/profilepic.jpg', + profilePic: '', level: 3, staff: true, departments: [ @@ -50,7 +50,7 @@ module.exports = [ author: { name: 'Emilia Clarke', email: 'jobs@steve.com', - profilePic: 'http://www.opensupports.com/profilepic.jpg', + profilePic: '', staff: true } }, @@ -61,7 +61,7 @@ module.exports = [ author: { name: 'Emilia Clarke', email: 'jobs@steve.com', - profilePic: 'http://www.opensupports.com/profilepic.jpg', + profilePic: '', staff: true } }, @@ -71,7 +71,7 @@ module.exports = [ author: { name: 'Emilia Clarke', email: 'jobs@steve.com', - profilePic: 'http://www.opensupports.com/profilepic.jpg', + profilePic: '', staff: true } }, @@ -82,7 +82,7 @@ module.exports = [ author: { name: 'Emilia Clarke', email: 'jobs@steve.com', - profilePic: 'http://www.opensupports.com/profilepic.jpg', + profilePic: '', staff: true } }, @@ -103,7 +103,7 @@ module.exports = [ author: { name: 'Emilia Clarke', email: 'jobs@steve.com', - profilePic: 'http://www.opensupports.com/profilepic.jpg', + profilePic: '', staff: true } }, @@ -123,7 +123,7 @@ module.exports = [ author: { name: 'Emilia Clarke', email: 'jobs@steve.com', - profilePic: 'http://www.opensupports.com/profilepic.jpg', + profilePic: '', staff: true } }, @@ -167,7 +167,7 @@ module.exports = [ author: { name: 'Emilia Clarke', email: 'jobs@steve.com', - profilePic: 'http://www.opensupports.com/profilepic.jpg', + profilePic: '', staff: true } }, @@ -178,7 +178,7 @@ module.exports = [ author: { name: 'Emilia Clarke', email: 'jobs@steve.com', - profilePic: 'http://www.opensupports.com/profilepic.jpg', + profilePic: '', staff: true } }, @@ -188,7 +188,7 @@ module.exports = [ author: { name: 'Emilia Clarke', email: 'jobs@steve.com', - profilePic: 'http://www.opensupports.com/profilepic.jpg', + profilePic: '', staff: true } }, @@ -199,7 +199,7 @@ module.exports = [ author: { name: 'Emilia Clarke', email: 'jobs@steve.com', - profilePic: 'http://www.opensupports.com/profilepic.jpg', + profilePic: '', staff: true } }, @@ -220,7 +220,7 @@ module.exports = [ author: { name: 'Emilia Clarke', email: 'jobs@steve.com', - profilePic: 'http://www.opensupports.com/profilepic.jpg', + profilePic: '', staff: true } }, @@ -240,7 +240,7 @@ module.exports = [ author: { name: 'Emilia Clarke', email: 'jobs@steve.com', - profilePic: 'http://www.opensupports.com/profilepic.jpg', + profilePic: '', staff: true } }, @@ -284,7 +284,7 @@ module.exports = [ author: { name: 'Emilia Clarke', email: 'jobs@steve.com', - profilePic: 'http://www.opensupports.com/profilepic.jpg', + profilePic: '', staff: true } }, @@ -295,7 +295,7 @@ module.exports = [ author: { name: 'Emilia Clarke', email: 'jobs@steve.com', - profilePic: 'http://www.opensupports.com/profilepic.jpg', + profilePic: '', staff: true } }, @@ -305,7 +305,7 @@ module.exports = [ author: { name: 'Emilia Clarke', email: 'jobs@steve.com', - profilePic: 'http://www.opensupports.com/profilepic.jpg', + profilePic: '', staff: true } }, @@ -316,7 +316,7 @@ module.exports = [ author: { name: 'Emilia Clarke', email: 'jobs@steve.com', - profilePic: 'http://www.opensupports.com/profilepic.jpg', + profilePic: '', staff: true } }, @@ -337,7 +337,7 @@ module.exports = [ author: { name: 'Emilia Clarke', email: 'jobs@steve.com', - profilePic: 'http://www.opensupports.com/profilepic.jpg', + profilePic: '', staff: true } }, @@ -357,7 +357,7 @@ module.exports = [ author: { name: 'Emilia Clarke', email: 'jobs@steve.com', - profilePic: 'http://www.opensupports.com/profilepic.jpg', + profilePic: '', staff: true } }, @@ -443,7 +443,7 @@ module.exports = [ author: { name: 'Emilia Clarke', email: 'jobs@steve.com', - profilePic: 'http://www.opensupports.com/profilepic.jpg', + profilePic: '', staff: true } }, @@ -454,7 +454,7 @@ module.exports = [ author: { name: 'Emilia Clarke', email: 'jobs@steve.com', - profilePic: 'http://www.opensupports.com/profilepic.jpg', + profilePic: '', staff: true } }, @@ -464,7 +464,7 @@ module.exports = [ author: { name: 'Emilia Clarke', email: 'jobs@steve.com', - profilePic: 'http://www.opensupports.com/profilepic.jpg', + profilePic: '', staff: true } }, @@ -475,7 +475,7 @@ module.exports = [ author: { name: 'Emilia Clarke', email: 'jobs@steve.com', - profilePic: 'http://www.opensupports.com/profilepic.jpg', + profilePic: '', staff: true } }, @@ -496,7 +496,7 @@ module.exports = [ author: { name: 'Emilia Clarke', email: 'jobs@steve.com', - profilePic: 'http://www.opensupports.com/profilepic.jpg', + profilePic: '', staff: true } }, @@ -516,7 +516,7 @@ module.exports = [ author: { name: 'Emilia Clarke', email: 'jobs@steve.com', - profilePic: 'http://www.opensupports.com/profilepic.jpg', + profilePic: '', staff: true } }, @@ -560,7 +560,7 @@ module.exports = [ author: { name: 'Emilia Clarke', email: 'jobs@steve.com', - profilePic: 'http://www.opensupports.com/profilepic.jpg', + profilePic: '', staff: true } }, @@ -571,7 +571,7 @@ module.exports = [ author: { name: 'Emilia Clarke', email: 'jobs@steve.com', - profilePic: 'http://www.opensupports.com/profilepic.jpg', + profilePic: '', staff: true } }, @@ -581,7 +581,7 @@ module.exports = [ author: { name: 'Emilia Clarke', email: 'jobs@steve.com', - profilePic: 'http://www.opensupports.com/profilepic.jpg', + profilePic: '', staff: true } }, @@ -592,7 +592,7 @@ module.exports = [ author: { name: 'Emilia Clarke', email: 'jobs@steve.com', - profilePic: 'http://www.opensupports.com/profilepic.jpg', + profilePic: '', staff: true } }, @@ -613,7 +613,7 @@ module.exports = [ author: { name: 'Emilia Clarke', email: 'jobs@steve.com', - profilePic: 'http://www.opensupports.com/profilepic.jpg', + profilePic: '', staff: true } }, @@ -633,7 +633,7 @@ module.exports = [ author: { name: 'Emilia Clarke', email: 'jobs@steve.com', - profilePic: 'http://www.opensupports.com/profilepic.jpg', + profilePic: '', staff: true } }, @@ -677,7 +677,7 @@ module.exports = [ author: { name: 'Emilia Clarke', email: 'jobs@steve.com', - profilePic: 'http://www.opensupports.com/profilepic.jpg', + profilePic: '', staff: true } }, @@ -688,7 +688,7 @@ module.exports = [ author: { name: 'Emilia Clarke', email: 'jobs@steve.com', - profilePic: 'http://www.opensupports.com/profilepic.jpg', + profilePic: '', staff: true } }, @@ -698,7 +698,7 @@ module.exports = [ author: { name: 'Emilia Clarke', email: 'jobs@steve.com', - profilePic: 'http://www.opensupports.com/profilepic.jpg', + profilePic: '', staff: true } }, @@ -709,7 +709,7 @@ module.exports = [ author: { name: 'Emilia Clarke', email: 'jobs@steve.com', - profilePic: 'http://www.opensupports.com/profilepic.jpg', + profilePic: '', staff: true } }, @@ -730,7 +730,7 @@ module.exports = [ author: { name: 'Emilia Clarke', email: 'jobs@steve.com', - profilePic: 'http://www.opensupports.com/profilepic.jpg', + profilePic: '', staff: true } }, @@ -750,7 +750,7 @@ module.exports = [ author: { name: 'Emilia Clarke', email: 'jobs@steve.com', - profilePic: 'http://www.opensupports.com/profilepic.jpg', + profilePic: '', staff: true } }, @@ -979,7 +979,7 @@ module.exports = [ data: [ { id: 22, - profilePic: 'http://www.opensupports.com/profilepic.jpg', + profilePic: '', name: 'Emilia Clarke', departments: [{id: 2, name: 'Technical issues'}], assignedTickets: 4, @@ -988,7 +988,7 @@ module.exports = [ }, { id: 22, - profilePic: 'http://www.opensupports.com/profilepic.jpg', + profilePic: '', name: 'Yulian A GUI Yermo', departments: [{id: 2, name: 'Technical issues'}, {id: 1, name: 'Sales Support'}], assignedTickets: 9, @@ -997,7 +997,7 @@ module.exports = [ }, { id: 22, - profilePic: 'http://www.opensupports.com/profilepic.jpg', + profilePic: '', name: 'Miltona Costa', departments: [{id: 1, name: 'Sales Support'}], assignedTickets: -1, @@ -1006,7 +1006,7 @@ module.exports = [ }, { id: 22, - profilePic: 'http://www.opensupports.com/profilepic.jpg', + profilePic: '', name: 'Emiliasnikova Rusachestkvuy', departments: [{id: 1, name: 'Sales Support'}, {id: 3, name: 'System and Administration'}], assignedTickets: 100, @@ -1015,7 +1015,7 @@ module.exports = [ }, { id: 22, - profilePic: 'http://www.opensupports.com/profilepic.jpg', + profilePic: '', name: 'Laurita Morrechaga Rusachestkvuy', departments: [{id: 3, name: 'System and Administration'}], assignedTickets: 1, diff --git a/client/src/data/fixtures/ticket-fixtures.js b/client/src/data/fixtures/ticket-fixtures.js index dea4ee7f..75af3df7 100644 --- a/client/src/data/fixtures/ticket-fixtures.js +++ b/client/src/data/fixtures/ticket-fixtures.js @@ -40,7 +40,7 @@ module.exports = [ status: 'success', data: [ {id: 1, name: 'Common issue #1', language: 'en', content: 'some content 1'}, - {id: 2, name: 'Common issue #2', language: 'en', content: 'some content 2'}, + {id: 2, name: 'Common issue #2', language: 'en', content: 'some content 2'}, {id: 3, name: 'Common issue #3', language: 'en', content: 'some content 3'}, {id: 4, name: 'H�ufiges Problem #1', language: 'de', content: 'einige Inhalte 1'}, {id: 5, name: 'H�ufiges Problem #2', language: 'de', content: 'einige Inhalte 2'} diff --git a/client/src/lib-app/validations/length-validator.js b/client/src/lib-app/validations/length-validator.js index 9aa33f7d..dcc03bec 100644 --- a/client/src/lib-app/validations/length-validator.js +++ b/client/src/lib-app/validations/length-validator.js @@ -1,4 +1,4 @@ -import RichTextEditor from 'react-rte-browserify'; +import TextEditor from 'core-components/text-editor'; import Validator from 'lib-app/validations/validator'; @@ -11,8 +11,8 @@ class LengthValidator extends Validator { } validate(value = '', form = {}) { - if (value instanceof RichTextEditor.EditorValue) { - value = value.getEditorState().getCurrentContent().getPlainText(); + if (TextEditor.isEditorState(value)) { + value = value.getCurrentContent().getPlainText(); } if (value.length < this.minlength) return this.getError(this.errorKey); diff --git a/client/src/lib-app/validations/validations-factory.js b/client/src/lib-app/validations/validations-factory.js index 28aab598..9f8b74d2 100644 --- a/client/src/lib-app/validations/validations-factory.js +++ b/client/src/lib-app/validations/validations-factory.js @@ -1,5 +1,4 @@ import Validator from 'lib-app/validations/validator'; -import AlphaNumericValidator from 'lib-app/validations/alphanumeric-validator'; import EmailValidator from 'lib-app/validations/email-validator'; import RepeatPasswordValidator from 'lib-app/validations/repeat-password-validator'; import LengthValidator from 'lib-app/validations/length-validator'; @@ -7,8 +6,8 @@ import ListValidator from 'lib-app/validations/list-validator'; let validators = { 'DEFAULT': new Validator(), - 'NAME': new AlphaNumericValidator('ERROR_NAME', new LengthValidator(2, 'ERROR_NAME')), - 'TITLE': new AlphaNumericValidator('ERROR_TITLE', new LengthValidator(2, 'ERROR_TITLE')), + 'NAME': new LengthValidator(2, 'ERROR_NAME'), + 'TITLE': new LengthValidator(2, 'ERROR_TITLE'), 'EMAIL': new EmailValidator(), 'TEXT_AREA': new LengthValidator(10, 'ERROR_CONTENT_SHORT'), 'PASSWORD': new LengthValidator(6, 'ERROR_PASSWORD'), diff --git a/client/src/lib-app/validations/validator.js b/client/src/lib-app/validations/validator.js index b253bc18..6b98ced3 100644 --- a/client/src/lib-app/validations/validator.js +++ b/client/src/lib-app/validations/validator.js @@ -1,4 +1,4 @@ -import RichTextEditor from 'react-rte-browserify'; +import TextEditor from 'core-components/text-editor'; import i18n from 'lib-app/i18n'; @@ -20,8 +20,8 @@ class Validator { } validate(value, form) { - if (value instanceof RichTextEditor.EditorValue) { - value = value.getEditorState().getPlainText() + if (TextEditor.isEditorState(value)) { + value = value.getPlainText(); } if (value.length === 0) return this.getError('ERROR_EMPTY'); diff --git a/client/src/main.scss b/client/src/main.scss index 9bc26c11..e53982b3 100644 --- a/client/src/main.scss +++ b/client/src/main.scss @@ -3,6 +3,7 @@ @import 'scss/typography'; @import 'scss/base'; @import 'scss/font_awesome/font-awesome'; +@import 'scss/react-draft-wysiwyg'; @import 'core-components/*'; @import 'app-components/*'; diff --git a/client/src/scss/_react-draft-wysiwyg.scss b/client/src/scss/_react-draft-wysiwyg.scss new file mode 100644 index 00000000..87c4199e --- /dev/null +++ b/client/src/scss/_react-draft-wysiwyg.scss @@ -0,0 +1,985 @@ +.rdw-option-wrapper { + border: 1px solid #F1F1F1; + padding: 5px; + min-width: 25px; + height: 20px; + border-radius: 2px; + margin: 0 4px; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + cursor: pointer; + background: white; + text-transform: capitalize; +} +.rdw-option-wrapper:hover { + box-shadow: 1px 1px 0px #BFBDBD; +} +.rdw-option-wrapper:active { + box-shadow: 1px 1px 0px #BFBDBD inset; +} +.rdw-option-active { + box-shadow: 1px 1px 0px #BFBDBD inset; +} +.rdw-option-disabled { + opacity: 0.3; + cursor: default; +} +.rdw-dropdown-wrapper { + height: 30px; + background: white; + cursor: pointer; + border: 1px solid #F1F1F1; + border-radius: 2px; + margin: 0 3px; + text-transform: capitalize; + background: white; +} +.rdw-dropdown-wrapper:focus { + outline: none; +} +.rdw-dropdown-wrapper:hover { + box-shadow: 1px 1px 0px #BFBDBD; + background-color: #FFFFFF; +} +.rdw-dropdown-wrapper:active { + box-shadow: 1px 1px 0px #BFBDBD inset; +} +.rdw-dropdown-carettoopen { + height: 0px; + width: 0px; + position: absolute; + top: 35%; + right: 10%; + border-top: 6px solid black; + border-left: 5px solid transparent; + border-right: 5px solid transparent; +} +.rdw-dropdown-carettoclose { + height: 0px; + width: 0px; + position: absolute; + top: 35%; + right: 10%; + border-bottom: 6px solid black; + border-left: 5px solid transparent; + border-right: 5px solid transparent; +} +.rdw-dropdown-selectedtext { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + position: relative; + height: 100%; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + padding: 0 5px; +} +.rdw-dropdown-optionwrapper { + z-index: 100; + position: relative; + border: 1px solid #F1F1F1; + width: 98%; + background: white; + border-radius: 2px; + margin: 0; + padding: 0; +} +.rdw-dropdown-optionwrapper:hover { + box-shadow: 1px 1px 0px #BFBDBD; + background-color: #FFFFFF; +} +.rdw-dropdownoption-default { + min-height: 25px; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + padding: 0 5px; +} +.rdw-dropdownoption-highlighted { + background: #F1F1F1; +} +.rdw-dropdownoption-active { + background: #f5f5f5; +} +.rdw-dropdownoption-disabled { + opacity: 0.3; + cursor: default; +} +.rdw-inline-wrapper { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + margin-bottom: 6px; +} +.rdw-inline-dropdown { + width: 50px; +} +.rdw-inline-dropdownoption { + height: 40px; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; +} +.rdw-block-wrapper { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + margin-bottom: 6px; +} +.rdw-block-dropdown { + width: 110px; +} +.rdw-fontsize-wrapper { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + margin-bottom: 6px; +} +.rdw-fontsize-dropdown { + min-width: 40px; +} +.rdw-fontsize-option { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; +} +.rdw-fontfamily-wrapper { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + margin-bottom: 6px; +} +.rdw-fontfamily-dropdown { + width: 115px; +} +.rdw-fontfamily-placeholder { + white-space: nowrap; + max-width: 90px; + overflow: hidden; + text-overflow: ellipsis; +} +.rdw-fontfamily-optionwrapper { + width: 140px; +} +.rdw-list-wrapper { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + margin-bottom: 6px; +} +.rdw-list-dropdown { + width: 50px; + z-index: 90; +} +.rdw-list-dropdownOption { + height: 40px; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; +} +.rdw-text-align-wrapper { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + margin-bottom: 6px; +} +.rdw-text-align-dropdown { + width: 50px; + z-index: 90; +} +.rdw-text-align-dropdownOption { + height: 40px; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; +} +.rdw-right-aligned-block { + text-align: right; +} +.rdw-left-aligned-block { + text-align: left; +} +.rdw-center-aligned-block { + text-align: center; +} +.rdw-justify-aligned-block { + text-align: justify; +} +.rdw-right-aligned-block > div { + display: inline; +} +.rdw-left-aligned-block > div { + display: inline; +} +.rdw-center-aligned-block > div { + display: inline; +} +.rdw-justify-aligned-block > div { + display: inline; +} +.rdw-colorpicker-wrapper { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + margin-bottom: 6px; + position: relative; +} +.rdw-colorpicker-modal { + position: absolute; + top: 35px; + left: 5px; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + width: 175px; + height: 175px; + border: 1px solid #F1F1F1; + padding: 15px; + border-radius: 2px; + z-index: 100; + background: white; + box-shadow: 3px 3px 5px #BFBDBD; +} +.rdw-colorpicker-modal-header { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + padding-bottom: 5px; +} +.rdw-colorpicker-modal-style-label { + font-size: 15px; + width: 50%; + text-align: center; + cursor: pointer; + padding: 0 10px 5px; +} +.rdw-colorpicker-modal-style-label-active { + border-bottom: 2px solid #0a66b7; +} +.rdw-colorpicker-modal-options { + margin: 5px auto; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + width: 170px; + -ms-flex-wrap: wrap; + flex-wrap: wrap; +} +.rdw-colorpicker-cube { + width: 22px; + height: 22px; + border: 1px solid #F1F1F1; +} +.rdw-colorpicker-option { + margin: 3px; + padding: 0; + min-height: 20px; + border: none; + width: 22px; + height: 22px; + min-width: 22px; + box-shadow: 1px 2px 1px #BFBDBD inset; +} +.rdw-colorpicker-option:hover { + box-shadow: 1px 2px 1px #BFBDBD; +} +.rdw-colorpicker-option:active { + box-shadow: -1px -2px 1px #BFBDBD; +} +.rdw-colorpicker-option-active { + box-shadow: 0px 0px 2px 2px #BFBDBD; +} +.rdw-link-wrapper { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + margin-bottom: 6px; + position: relative; +} +.rdw-link-dropdown { + width: 50px; +} +.rdw-link-dropdownOption { + height: 40px; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; +} +.rdw-link-dropdownPlaceholder { + margin-left: 8px; +} +.rdw-link-modal { + position: absolute; + top: 35px; + left: 5px; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + width: 235px; + height: 180px; + border: 1px solid #F1F1F1; + padding: 15px; + border-radius: 2px; + z-index: 100; + background: white; + box-shadow: 3px 3px 5px #BFBDBD; +} +.rdw-link-modal-label { + font-size: 15px; +} +.rdw-link-modal-input { + margin-top: 5px; + border-radius: 2px; + border: 1px solid #F1F1F1; + height: 25px; + margin-bottom: 15px; + padding: 0 5px; +} +.rdw-link-modal-input:focus { + outline: none; +} +.rdw-link-modal-buttonsection { + margin: 0 auto; +} +.rdw-link-modal-btn { + margin-left: 10px; + width: 75px; + height: 30px; + border: 1px solid #F1F1F1; + border-radius: 2px; + cursor: pointer; + background: white; + text-transform: capitalize; +} +.rdw-link-modal-btn:hover { + box-shadow: 1px 1px 0px #BFBDBD; +} +.rdw-link-modal-btn:active { + box-shadow: 1px 1px 0px #BFBDBD inset; +} +.rdw-link-modal-btn:focus { + outline: none !important; +} +.rdw-link-modal-btn:disabled { + background: #ece9e9; +} +.rdw-link-dropdownoption { + height: 40px; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; +} +.rdw-history-dropdown { + width: 50px; +} +.rdw-embedded-wrapper { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + margin-bottom: 6px; + position: relative; +} +.rdw-embedded-modal { + position: absolute; + top: 35px; + left: 5px; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + width: 235px; + height: 180px; + border: 1px solid #F1F1F1; + padding: 15px; + border-radius: 2px; + z-index: 100; + background: white; + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; + box-shadow: 3px 3px 5px #BFBDBD; +} +.rdw-embedded-modal-header { + font-size: 15px; + display: -webkit-box; + display: -ms-flexbox; + display: flex; +} +.rdw-embedded-modal-header-option { + width: 50%; + cursor: pointer; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; +} +.rdw-embedded-modal-header-label { + width: 95px; + border: 1px solid #f1f1f1; + margin-top: 5px; + background: #6EB8D4; + border-bottom: 2px solid #0a66b7; +} +.rdw-embedded-modal-link-section { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; +} +.rdw-embedded-modal-link-input { + width: 95%; + height: 35px; + margin: 10px 0; + border: 1px solid #F1F1F1; + border-radius: 2px; + font-size: 15px; + padding: 0 5px; +} +.rdw-embedded-modal-link-input:focus { + outline: none; +} +.rdw-embedded-modal-btn-section { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; +} +.rdw-embedded-modal-btn { + margin: 0 3px; + width: 75px; + height: 30px; + border: 1px solid #F1F1F1; + border-radius: 2px; + cursor: pointer; + background: white; + text-transform: capitalize; +} +.rdw-embedded-modal-btn:hover { + box-shadow: 1px 1px 0px #BFBDBD; +} +.rdw-embedded-modal-btn:active { + box-shadow: 1px 1px 0px #BFBDBD inset; +} +.rdw-embedded-modal-btn:focus { + outline: none !important; +} +.rdw-embedded-modal-btn:disabled { + background: #ece9e9; +} +.rdw-embedded-modal-size { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + margin: 5px 0 10px; + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; +} +.rdw-embedded-modal-size-input { + width: 45%; + height: 20px; + border: 1px solid #F1F1F1; + border-radius: 2px; + font-size: 12px; +} +.rdw-embedded-modal-size-input:focus { + outline: none; +} +.rdw-emoji-wrapper { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + margin-bottom: 6px; + position: relative; +} +.rdw-emoji-modal { + overflow: auto; + position: absolute; + top: 35px; + left: 5px; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + width: 235px; + height: 180px; + border: 1px solid #F1F1F1; + padding: 15px; + border-radius: 2px; + z-index: 100; + background: white; + box-shadow: 3px 3px 5px #BFBDBD; +} +.rdw-emoji-icon { + margin: 2.5px; + height: 24px; + width: 24px; + cursor: pointer; + font-size: 22px; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; +} +.rdw-spinner { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + height: 100%; + width: 100%; +} +.rdw-spinner > div { + width: 12px; + height: 12px; + background-color: #333; + + border-radius: 100%; + display: inline-block; + -webkit-animation: sk-bouncedelay 1.4s infinite ease-in-out both; + animation: sk-bouncedelay 1.4s infinite ease-in-out both; +} +.rdw-spinner .rdw-bounce1 { + -webkit-animation-delay: -0.32s; + animation-delay: -0.32s; +} +.rdw-spinner .rdw-bounce2 { + -webkit-animation-delay: -0.16s; + animation-delay: -0.16s; +} +@-webkit-keyframes sk-bouncedelay { + 0%, 80%, 100% { -webkit-transform: scale(0) } + 40% { -webkit-transform: scale(1.0) } +} +@keyframes sk-bouncedelay { + 0%, 80%, 100% { + -webkit-transform: scale(0); + transform: scale(0); + } 40% { + -webkit-transform: scale(1.0); + transform: scale(1.0); + } +} +.rdw-image-wrapper { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + margin-bottom: 6px; + position: relative; +} +.rdw-image-modal { + position: absolute; + top: 35px; + left: 5px; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + width: 235px; + height: 200px; + border: 1px solid #F1F1F1; + padding: 15px; + border-radius: 2px; + z-index: 100; + background: white; + box-shadow: 3px 3px 5px #BFBDBD; +} +.rdw-image-modal-header { + font-size: 15px; + margin: 10px 0; + display: -webkit-box; + display: -ms-flexbox; + display: flex; +} +.rdw-image-modal-header-option { + width: 50%; + cursor: pointer; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; +} +.rdw-image-modal-header-label { + width: 80px; + background: #f1f1f1; + border: 1px solid #f1f1f1; + margin-top: 5px; +} +.rdw-image-modal-header-label-highlighted { + background: #6EB8D4; + border-bottom: 2px solid #0a66b7; +} +.rdw-image-modal-upload-option { + height: 65px; + width: 100%; + color: gray; + cursor: pointer; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + border: none; + font-size: 15px; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + background-color: #f1f1f1; + outline: 2px dashed gray; + outline-offset: -10px; + margin: 10px 0; +} +.rdw-image-modal-upload-option-highlighted { + outline: 2px dashed #0a66b7; +} +.rdw-image-modal-upload-option-label { + cursor: pointer; + height: 100%; + width: 100%; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; +} +.rdw-image-modal-upload-option-input { + width: 0.1px; + height: 0.1px; + opacity: 0; + overflow: hidden; + position: absolute; + z-index: -1; +} +.rdw-image-modal-url-section { + display: -webkit-box; + display: -ms-flexbox; + display: flex; +} +.rdw-image-modal-url-input { + width: 95%; + height: 35px; + margin: 25px 0 5px; + border: 1px solid #F1F1F1; + border-radius: 2px; + font-size: 15px; + padding: 0 5px; +} +.rdw-image-modal-btn-section { + margin: 10px auto 0; +} +.rdw-image-modal-url-input:focus { + outline: none; +} +.rdw-image-modal-btn { + margin: 0 5px; + width: 75px; + height: 30px; + border: 1px solid #F1F1F1; + border-radius: 2px; + cursor: pointer; + background: white; + text-transform: capitalize; +} +.rdw-image-modal-btn:hover { + box-shadow: 1px 1px 0px #BFBDBD; +} +.rdw-image-modal-btn:active { + box-shadow: 1px 1px 0px #BFBDBD inset; +} +.rdw-image-modal-btn:focus { + outline: none !important; +} +.rdw-image-modal-btn:disabled { + background: #ece9e9; +} +.rdw-image-modal-spinner { + position: absolute; + top: -3px; + left: 0; + width: 100%; + height: 100%; + opacity: 0.5; +} +.rdw-remove-wrapper { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + margin-bottom: 6px; + position: relative; +} +.rdw-history-wrapper { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + margin-bottom: 6px; +} +.rdw-history-dropdownoption { + height: 40px; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; +} +.rdw-history-dropdown { + width: 50px; +} +.rdw-link-decorator-wrapper { + position: relative; +} +.rdw-link-decorator-icon { + position: absolute; + left: 40%; + top: 0; + cursor: pointer; + background-color: white; +} +.rdw-mention-link { + text-decoration: none; + color: #1236ff; + background-color: #f0fbff; + padding: 1px 2px; + border-radius: 2px; +} +.rdw-suggestion-wrapper { + position: relative; +} +.rdw-suggestion-dropdown { + position: absolute; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + border: 1px solid #F1F1F1; + min-width: 100px; + max-height: 150px; + overflow: auto; + background: white; + z-index: 100; +} +.rdw-suggestion-option { + padding: 7px 5px; + border-bottom: 1px solid #f1f1f1; +} +.rdw-suggestion-option-active { + background-color: #F1F1F1; +} +.rdw-hashtag-link { + text-decoration: none; + color: #1236ff; + background-color: #f0fbff; + padding: 1px 2px; + border-radius: 2px; +} +.rdw-image-alignment-options-popup { + position: absolute;; + background: white; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + padding: 5px 2px; + border-radius: 2px; + border: 1px solid #F1F1F1; + width: 105px; + cursor: pointer; + z-index: 100; +} +.rdw-alignment-option-left { + -webkit-box-pack: start; + -ms-flex-pack: start; + justify-content: flex-start; +} +.rdw-image-alignment-option { + height: 15px; + width: 15px; + min-width: 15px; +} +.rdw-image-alignment { + position: relative; +} +.rdw-image-imagewrapper { + position: relative; +} +.rdw-image-center { + float: none; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; +} +.rdw-image-left { + float: left; +} +.rdw-image-right { + float: right; +} +.rdw-editor-main { + height: 100%; + width: 100%; + overflow: auto; + box-sizing: content-box; +} +.rdw-editor-toolbar { + padding: 6px 5px 0; + border-radius: 2px; + border: 1px solid #F1F1F1; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: start; + -ms-flex-pack: start; + justify-content: flex-start; + width: 100%; + background: white; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + font-size: 15px; + margin-bottom: 5px; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} +.public-DraftStyleDefault-block { + margin: 1em 0; +} +.rdw-editor-wrapper:focus { + outline: none; +} +/** + * Draft v0.9.1 + * + * Copyright (c) 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ +.DraftEditor-editorContainer, .DraftEditor-root, .public-DraftEditor-content{height:inherit;text-align:initial}.public-DraftEditor-content[contenteditable=true]{-webkit-user-modify:read-write-plaintext-only}.DraftEditor-root{position:relative}.DraftEditor-editorContainer{background-color:rgba(255,255,255,0);border-left:.1px solid transparent;position:relative;z-index:1}.public-DraftEditor-block{position:relative}.DraftEditor-alignLeft .public-DraftStyleDefault-block{text-align:left}.DraftEditor-alignLeft .public-DraftEditorPlaceholder-root{left:0;text-align:left}.DraftEditor-alignCenter .public-DraftStyleDefault-block{text-align:center}.DraftEditor-alignCenter .public-DraftEditorPlaceholder-root{margin:0 auto;text-align:center;width:100%}.DraftEditor-alignRight .public-DraftStyleDefault-block{text-align:right}.DraftEditor-alignRight .public-DraftEditorPlaceholder-root{right:0;text-align:right}.public-DraftEditorPlaceholder-root{color:#9197a3;position:absolute;z-index:0}.public-DraftEditorPlaceholder-hasFocus{color:#bdc1c9}.DraftEditorPlaceholder-hidden{display:none}.public-DraftStyleDefault-block{position:relative;white-space:pre-wrap}.public-DraftStyleDefault-ltr{direction:ltr;text-align:left}.public-DraftStyleDefault-rtl{direction:rtl;text-align:right}.public-DraftStyleDefault-listLTR{direction:ltr}.public-DraftStyleDefault-listRTL{direction:rtl}.public-DraftStyleDefault-ol, .public-DraftStyleDefault-ul{margin:16px 0;padding:0}.public-DraftStyleDefault-depth0.public-DraftStyleDefault-listLTR{margin-left:1.5em}.public-DraftStyleDefault-depth0.public-DraftStyleDefault-listRTL{margin-right:1.5em}.public-DraftStyleDefault-depth1.public-DraftStyleDefault-listLTR{margin-left:3em}.public-DraftStyleDefault-depth1.public-DraftStyleDefault-listRTL{margin-right:3em}.public-DraftStyleDefault-depth2.public-DraftStyleDefault-listLTR{margin-left:4.5em}.public-DraftStyleDefault-depth2.public-DraftStyleDefault-listRTL{margin-right:4.5em}.public-DraftStyleDefault-depth3.public-DraftStyleDefault-listLTR{margin-left:6em}.public-DraftStyleDefault-depth3.public-DraftStyleDefault-listRTL{margin-right:6em}.public-DraftStyleDefault-depth4.public-DraftStyleDefault-listLTR{margin-left:7.5em}.public-DraftStyleDefault-depth4.public-DraftStyleDefault-listRTL{margin-right:7.5em}.public-DraftStyleDefault-unorderedListItem{list-style-type:square;position:relative}.public-DraftStyleDefault-unorderedListItem.public-DraftStyleDefault-depth0{list-style-type:disc}.public-DraftStyleDefault-unorderedListItem.public-DraftStyleDefault-depth1{list-style-type:circle}.public-DraftStyleDefault-orderedListItem{list-style-type:none;position:relative}.public-DraftStyleDefault-orderedListItem.public-DraftStyleDefault-listLTR:before{left:-36px;position:absolute;text-align:right;width:30px}.public-DraftStyleDefault-orderedListItem.public-DraftStyleDefault-listRTL:before{position:absolute;right:-36px;text-align:left;width:30px}.public-DraftStyleDefault-orderedListItem:before{content:counter(ol0) ". ";counter-increment:ol0}.public-DraftStyleDefault-orderedListItem.public-DraftStyleDefault-depth1:before{content:counter(ol1) ". ";counter-increment:ol1}.public-DraftStyleDefault-orderedListItem.public-DraftStyleDefault-depth2:before{content:counter(ol2) ". ";counter-increment:ol2}.public-DraftStyleDefault-orderedListItem.public-DraftStyleDefault-depth3:before{content:counter(ol3) ". ";counter-increment:ol3}.public-DraftStyleDefault-orderedListItem.public-DraftStyleDefault-depth4:before{content:counter(ol4) ". ";counter-increment:ol4}.public-DraftStyleDefault-depth0.public-DraftStyleDefault-reset{counter-reset:ol0}.public-DraftStyleDefault-depth1.public-DraftStyleDefault-reset{counter-reset:ol1}.public-DraftStyleDefault-depth2.public-DraftStyleDefault-reset{counter-reset:ol2}.public-DraftStyleDefault-depth3.public-DraftStyleDefault-reset{counter-reset:ol3}.public-DraftStyleDefault-depth4.public-DraftStyleDefault-reset{counter-reset:ol4} + +/*# sourceMappingURL=react-draft-wysiwyg.css.map*/ \ No newline at end of file diff --git a/server/controllers/article/add-topic.php b/server/controllers/article/add-topic.php index 71e9424b..d58e6458 100644 --- a/server/controllers/article/add-topic.php +++ b/server/controllers/article/add-topic.php @@ -26,8 +26,6 @@ class AddTopicController extends Controller { 'iconColor' => Controller::request('iconColor') ]); - $staff = Controller::getLoggedUser(); - Log::createLog('ADD_TOPIC', $topic->name); Response::respondSuccess([ diff --git a/server/controllers/article/add.php b/server/controllers/article/add.php index c01d7ecf..28abcab7 100644 --- a/server/controllers/article/add.php +++ b/server/controllers/article/add.php @@ -39,8 +39,6 @@ class AddArticleController extends Controller { $topic->ownArticleList->add($article); $topic->store(); - $staff = Controller::getLoggedUser(); - Log::createLog('ADD_ARTICLE', $article->title); Response::respondSuccess([ diff --git a/server/controllers/staff/add.php b/server/controllers/staff/add.php index 86f6a7cf..649f9cec 100644 --- a/server/controllers/staff/add.php +++ b/server/controllers/staff/add.php @@ -19,7 +19,7 @@ class AddStaffController extends Controller { 'permission' => 'staff_3', 'requestData' => [ 'name' => [ - 'validation' => DataValidator::length(2, 55)->alpha(), + 'validation' => DataValidator::length(2, 55), 'error' => ERRORS::INVALID_NAME ], 'email' => [ diff --git a/server/controllers/staff/search-tickets.php b/server/controllers/staff/search-tickets.php index 21998d9a..5cd48074 100644 --- a/server/controllers/staff/search-tickets.php +++ b/server/controllers/staff/search-tickets.php @@ -10,7 +10,7 @@ class SearchTicketStaffController extends Controller { 'permission' => 'staff_1', 'requestData' => [ 'query' => [ - 'validation' => DataValidator::alpha(), + 'validation' => DataValidator::length(1), 'error' => ERRORS::INVALID_QUERY ], 'page' => [ diff --git a/server/controllers/system/delete-api-key.php b/server/controllers/system/delete-api-key.php index c38201be..ee939518 100644 --- a/server/controllers/system/delete-api-key.php +++ b/server/controllers/system/delete-api-key.php @@ -10,7 +10,7 @@ class DeleteAPIKeyController extends Controller { 'permission' => 'staff_3', 'requestData' => [ 'name' => [ - 'validation' => DataValidator::length(2, 55)->alpha(), + 'validation' => DataValidator::length(2, 55), 'error' => ERRORS::INVALID_NAME ] ] diff --git a/server/controllers/user/signup.php b/server/controllers/user/signup.php index b1e936fa..444ea24c 100644 --- a/server/controllers/user/signup.php +++ b/server/controllers/user/signup.php @@ -22,7 +22,7 @@ class SignUpController extends Controller { 'permission' => 'any', 'requestData' => [ 'name' => [ - 'validation' => DataValidator::length(2, 55)->alpha(), + 'validation' => DataValidator::length(2, 55), 'error' => ERRORS::INVALID_NAME ], 'email' => [