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,6 +159,120 @@ export default class CUD extends Component {
const typeKey = this.getFormValue('type'); const typeKey = this.getFormValue('type');
let editForm = null;
if (isEdit && typeKey) {
editForm = <div>
<AlignedRow>
<Button className="btn-default" onClickAsync={::this.toggleMergeTagReference} label={t('Merge tag reference')}/>
{this.state.showMergeTagReference &&
<div style={{marginTop: '15px'}}>
<Trans><p>Merge tags are tags that are replaced before sending out the message. The format of the merge tag is the following: <code>[TAG_NAME]</code> or <code>[TAG_NAME/fallback]</code> where <code>fallback</code> is an optional text value used when <code>TAG_NAME</code> is empty.</p></Trans>
<table className="table table-bordered table-condensed table-striped">
<thead>
<tr>
<th>
<Trans>Merge tag</Trans>
</th>
<th>
<Trans>Description</Trans>
</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">
[LINK_UNSUBSCRIBE]
</th>
<td>
<Trans>URL that points to the unsubscribe page</Trans>
</td>
</tr>
<tr>
<th scope="row">
[LINK_PREFERENCES]
</th>
<td>
<Trans>URL that points to the preferences page of the subscriber</Trans>
</td>
</tr>
<tr>
<th scope="row">
[LINK_BROWSER]
</th>
<td>
<Trans>URL to preview the message in a browser</Trans>
</td>
</tr>
<tr>
<th scope="row">
[EMAIL]
</th>
<td>
<Trans>Email address</Trans>
</td>
</tr>
<tr>
<th scope="row">
[FIRST_NAME]
</th>
<td>
<Trans>First name</Trans>
</td>
</tr>
<tr>
<th scope="row">
[LAST_NAME]
</th>
<td>
<Trans>Last name</Trans>
</td>
</tr>
<tr>
<th scope="row">
[FULL_NAME]
</th>
<td>
<Trans>Full name (first and last name combined)</Trans>
</td>
</tr>
<tr>
<th scope="row">
[SUBSCRIPTION_ID]
</th>
<td>
<Trans>Unique ID that identifies the recipient</Trans>
</td>
</tr>
<tr>
<th scope="row">
[LIST_ID]
</th>
<td>
<Trans>Unique ID that identifies the list used for this campaign</Trans>
</td>
</tr>
<tr>
<th scope="row">
[CAMPAIGN_ID]
</th>
<td>
<Trans>Unique ID that identifies current campaign</Trans>
</td>
</tr>
</tbody>
</table>
<Trans><p>In addition to that any custom field can have its own merge tag.</p></Trans>
</div>}
</AlignedRow>
{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 ( return (
<div> <div>
{canDelete && {canDelete &&
@ -190,113 +304,7 @@ export default class CUD extends Component {
<NamespaceSelect/> <NamespaceSelect/>
<AlignedRow> {editForm}
<Button className="btn-default" onClickAsync={::this.toggleMergeTagReference} label={t('Merge tag reference')}/>
{this.state.showMergeTagReference &&
<div style={{marginTop: '15px'}}>
<Trans><p>Merge tags are tags that are replaced before sending out the message. The format of the merge tag is the following: <code>[TAG_NAME]</code> or <code>[TAG_NAME/fallback]</code> where <code>fallback</code> is an optional text value used when <code>TAG_NAME</code> is empty.</p></Trans>
<table className="table table-bordered table-condensed table-striped">
<thead>
<tr>
<th>
<Trans>Merge tag</Trans>
</th>
<th>
<Trans>Description</Trans>
</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">
[LINK_UNSUBSCRIBE]
</th>
<td>
<Trans>URL that points to the unsubscribe page</Trans>
</td>
</tr>
<tr>
<th scope="row">
[LINK_PREFERENCES]
</th>
<td>
<Trans>URL that points to the preferences page of the subscriber</Trans>
</td>
</tr>
<tr>
<th scope="row">
[LINK_BROWSER]
</th>
<td>
<Trans>URL to preview the message in a browser</Trans>
</td>
</tr>
<tr>
<th scope="row">
[EMAIL]
</th>
<td>
<Trans>Email address</Trans>
</td>
</tr>
<tr>
<th scope="row">
[FIRST_NAME]
</th>
<td>
<Trans>First name</Trans>
</td>
</tr>
<tr>
<th scope="row">
[LAST_NAME]
</th>
<td>
<Trans>Last name</Trans>
</td>
</tr>
<tr>
<th scope="row">
[FULL_NAME]
</th>
<td>
<Trans>Full name (first and last name combined)</Trans>
</td>
</tr>
<tr>
<th scope="row">
[SUBSCRIPTION_ID]
</th>
<td>
<Trans>Unique ID that identifies the recipient</Trans>
</td>
</tr>
<tr>
<th scope="row">
[LIST_ID]
</th>
<td>
<Trans>Unique ID that identifies the list used for this campaign</Trans>
</td>
</tr>
<tr>
<th scope="row">
[CAMPAIGN_ID]
</th>
<td>
<Trans>Unique ID that identifies current campaign</Trans>
</td>
</tr>
</tbody>
</table>
<Trans><p>In addition to that any custom field can have its own merge tag.</p></Trans>
</div>}
</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>}/>
{isEdit && typeKey && this.templateTypes[typeKey].form}
<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'