Integrated CKEditor for templates. We might need to move it to a sandbox later to make it secure.

This commit is contained in:
Tomas Bures 2018-02-24 21:59:00 +01:00
parent 508d6b3b2f
commit ba75623f86
5 changed files with 129 additions and 110 deletions

View file

@ -28,6 +28,7 @@
"querystringify": "^1.0.0", "querystringify": "^1.0.0",
"react": "^15.6.1", "react": "^15.6.1",
"react-ace": "^5.1.0", "react-ace": "^5.1.0",
"react-ckeditor-component": "^1.0.7",
"react-day-picker": "^6.1.0", "react-day-picker": "^6.1.0",
"react-dnd-html5-backend": "^2.4.1", "react-dnd-html5-backend": "^2.4.1",
"react-dnd-touch-backend": "^0.3.13", "react-dnd-touch-backend": "^0.3.13",

View file

@ -863,7 +863,9 @@ class CKEditor extends Component {
return wrapInput(id, htmlId, owner, props.format, '', props.label, props.help, return wrapInput(id, htmlId, owner, props.format, '', props.label, props.help,
<CKEditorRaw <CKEditorRaw
onChange={evt => owner.updateFormValue(id, evt.editor.getData())} events={{
"change": evt => owner.updateFormValue(id, evt.editor.getData())
}}
content={owner.getFormValue(id)} content={owner.getFormValue(id)}
config={{width: '100%', height: props.height}} config={{width: '100%', height: props.height}}
/> />

View file

@ -159,37 +159,9 @@ export default class CUD extends Component {
const typeKey = this.getFormValue('type'); const typeKey = this.getFormValue('type');
return ( let editForm = null;
<div> if (isEdit && typeKey) {
{canDelete && editForm = <div>
<DeleteModalDialog
stateOwner={this}
visible={this.props.action === 'delete'}
deleteUrl={`/rest/templates/${this.props.entity.id}`}
cudUrl={`/templates/${this.props.entity.id}/edit`}
listUrl="/templates"
deletingMsg={t('Deleting template ...')}
deletedMsg={t('Template deleted')}/>
}
<Title>{isEdit ? t('Edit Template') : t('Create Template')}</Title>
<Form stateOwner={this} onSubmitAsync={::this.submitHandler}>
<InputField id="name" label={t('Name')}/>
<TextArea id="description" label={t('Description')} help={t('HTML is allowed')}/>
{isEdit
?
<StaticField id="type" className={styles.formDisabled} label={t('Type')}>
{typeKey && this.templateTypes[typeKey].typeName}
</StaticField>
:
<Dropdown id="type" label={t('Type')} options={typeOptions}/>
}
<NamespaceSelect/>
<AlignedRow> <AlignedRow>
<Button className="btn-default" onClickAsync={::this.toggleMergeTagReference} label={t('Merge tag reference')}/> <Button className="btn-default" onClickAsync={::this.toggleMergeTagReference} label={t('Merge tag reference')}/>
{this.state.showMergeTagReference && {this.state.showMergeTagReference &&
@ -294,9 +266,45 @@ export default class CUD extends Component {
</div>} </div>}
</AlignedRow> </AlignedRow>
<ACEEditor id="text" height="400px" mode="text" label={t('Template content (plain text)')} help={<Trans>To extract the text from HTML click <ActionLink onClickAsync={::this.extractPlainText}>here</ActionLink>. Please note that your existing plaintext in the field above will be overwritten. This feature uses the <a href="http://premailer.dialect.ca/api">Premailer API</a>, a third party service. Their Terms of Service and Privacy Policy apply.</Trans>}/> {this.templateTypes[typeKey].form}
{isEdit && typeKey && this.templateTypes[typeKey].form} <ACEEditor id="text" height="400px" mode="text" label={t('Template content (plain text)')} help={<Trans>To extract the text from HTML click <ActionLink onClickAsync={::this.extractPlainText}>here</ActionLink>. Please note that your existing plaintext in the field above will be overwritten. This feature uses the <a href="http://premailer.dialect.ca/api">Premailer API</a>, a third party service. Their Terms of Service and Privacy Policy apply.</Trans>}/>
</div>
}
return (
<div>
{canDelete &&
<DeleteModalDialog
stateOwner={this}
visible={this.props.action === 'delete'}
deleteUrl={`/rest/templates/${this.props.entity.id}`}
cudUrl={`/templates/${this.props.entity.id}/edit`}
listUrl="/templates"
deletingMsg={t('Deleting template ...')}
deletedMsg={t('Template deleted')}/>
}
<Title>{isEdit ? t('Edit Template') : t('Create Template')}</Title>
<Form stateOwner={this} onSubmitAsync={::this.submitHandler}>
<InputField id="name" label={t('Name')}/>
<TextArea id="description" label={t('Description')} help={t('HTML is allowed')}/>
{isEdit
?
<StaticField id="type" className={styles.formDisabled} label={t('Type')}>
{typeKey && this.templateTypes[typeKey].typeName}
</StaticField>
:
<Dropdown id="type" label={t('Type')} options={typeOptions}/>
}
<NamespaceSelect/>
{editForm}
<ButtonRow> <ButtonRow>
<Button type="submit" className="btn-primary" icon="ok" label={isEdit ? t('Save') : t('Save and edit template')}/> <Button type="submit" className="btn-primary" icon="ok" label={isEdit ? t('Save') : t('Save and edit template')}/>

View file

@ -1,7 +1,10 @@
'use strict'; 'use strict';
import React from "react"; import React from "react";
import {ACEEditor, SummernoteEditor} from "../lib/form"; import {
ACEEditor,
CKEditor
} from "../lib/form";
import 'brace/mode/text'; import 'brace/mode/text';
import 'brace/mode/html' import 'brace/mode/html'
@ -19,7 +22,7 @@ export function getTemplateTypes(t) {
templateTypes.ckeditor = { templateTypes.ckeditor = {
typeName: t('CKEditor'), typeName: t('CKEditor'),
form: <SummernoteEditor id="html" height="600px" label={t('Template content (HTML)')}/> form: <CKEditor id="html" height="600px" label={t('Template content (HTML)')}/>
}; };
templateTypes.codeeditor = { templateTypes.codeeditor = {

View file

@ -52,9 +52,14 @@ module.exports = {
}, },
'sass-loader' ] 'sass-loader' ]
}, },
{
test: /\.(woff|ttf|eot)$/,
use: [ 'url-loader' ]
}
] ]
}, },
externals: { externals: {
$: "jQuery",
jquery: 'jQuery', jquery: 'jQuery',
csfrToken: 'csfrToken', csfrToken: 'csfrToken',
mailtrainConfig: 'mailtrainConfig' mailtrainConfig: 'mailtrainConfig'