Save button for template editors

This commit is contained in:
Tomas Bures 2018-11-22 20:53:44 +01:00
parent 3bb235a585
commit bd20072455
8 changed files with 73 additions and 17 deletions

View file

@ -63,15 +63,17 @@ export default class CustomContent extends Component {
entity: PropTypes.object
}
componentDidMount() {
this.getFormValuesFromEntity(this.props.entity, data => {
data.data_sourceCustom_type = data.data.sourceCustom.type;
data.data_sourceCustom_data = data.data.sourceCustom.data;
data.data_sourceCustom_html = data.data.sourceCustom.html;
data.data_sourceCustom_text = data.data.sourceCustom.text;
loadFromEntityMutator(data) {
data.data_sourceCustom_type = data.data.sourceCustom.type;
data.data_sourceCustom_data = data.data.sourceCustom.data;
data.data_sourceCustom_html = data.data.sourceCustom.html;
data.data_sourceCustom_text = data.data.sourceCustom.text;
this.templateTypes[data.data.sourceCustom.type].afterLoad(data);
});
this.templateTypes[data.data.sourceCustom.type].afterLoad(data);
}
componentDidMount() {
this.getFormValuesFromEntity(this.props.entity, data => this.loadFromEntityMutator(data));
}
localValidateFormValues(state) {
@ -84,7 +86,15 @@ export default class CustomContent extends Component {
}
}
async save() {
await this.doSave(true);
}
async submitHandler() {
await this.doSave(false);
}
async doSave(stayOnPage) {
const t = this.props.t;
const customTemplateTypeKey = this.getFormValue('data_sourceCustom_type');
@ -115,10 +125,14 @@ export default class CustomContent extends Component {
});
if (submitResponse) {
if (this.props.entity) {
this.navigateToWithFlashMessage('/campaigns', 'success', t('campaignSaved'));
if (stayOnPage) {
await this.getFormValuesFromURL(`rest/campaigns-content/${this.props.entity.id}`, data => this.loadFromEntityMutator(data));
this.enableForm();
this.clearFormStatusMessage();
this.setFlashMessage('success', t('campaignSaved'));
} else {
this.navigateToWithFlashMessage(`/campaigns/${submitResponse}/edit`, 'success', t('campaignSaved'));
this.navigateToWithFlashMessage('/campaigns', 'success', t('campaignSaved'));
}
} else {
this.enableForm();

View file

@ -31,6 +31,8 @@ export class CKEditorHost extends Component {
entity: PropTypes.object,
initialSource: PropTypes.string,
title: PropTypes.string,
onSave: PropTypes.func,
canSave: PropTypes.bool,
onTestSend: PropTypes.func,
onFullscreenAsync: PropTypes.func
}
@ -91,6 +93,7 @@ export class CKEditorHost extends Component {
<div className={styles.title}>{this.props.title}</div>
<a className={styles.btn} onClick={::this.toggleFullscreenAsync}><Icon icon="fullscreen"/></a>
<a className={styles.btn} onClick={this.props.onTestSend}><Icon icon="send"/></a>
{this.props.canSave ? <a className={styles.btn} onClick={this.props.onSave}><Icon icon="floppy-disk"/></a> : <span className={styles.btnDisabled}><Icon icon="floppy-disk"/></span>}
</div>
<UntrustedContentHost ref={node => this.contentNode = node} className={styles.host} singleToken={true} contentProps={editorData} contentSrc="ckeditor/editor" tokenMethod="ckeditor" tokenParams={editorData}/>
</div>

View file

@ -91,6 +91,9 @@ class CodeEditorSandbox extends Component {
this.refreshHandler = ::this.refresh;
this.refreshTimeoutId = null;
this.onMessageFromPreviewHandler = ::this.onMessageFromPreview;
this.previewScroll = {x: 0, y: 0};
}
static propTypes = {
@ -128,6 +131,8 @@ class CodeEditorSandbox extends Component {
parentRPC.setMethodHandler('exportState', ::this.exportState);
parentRPC.setMethodHandler('setPreview', ::this.setPreview);
parentRPC.setMethodHandler('setWrap', ::this.setWrap);
window.addEventListener('message', this.onMessageFromPreviewHandler, false);
}
componentWillUnmount() {
@ -156,6 +161,12 @@ class CodeEditorSandbox extends Component {
}
}
onMessageFromPreview(evt) {
if (evt.data.type === 'scroll') {
this.previewScroll = evt.data.data;
}
}
refresh() {
this.refreshTimeoutId = null;
@ -165,6 +176,16 @@ class CodeEditorSandbox extends Component {
}
render() {
const previewScript =
'(function() {\n' +
' function reportScroll() { window.parent.postMessage({type: \'scroll\', data: {x: window.scrollX, y: window.scrollY}}, \'*\'); }\n' +
' reportScroll();\n' +
' window.addEventListener(\'scroll\', reportScroll);\n' +
' window.addEventListener(\'load\', function(evt) { window.scrollTo(' + this.previewScroll.x + ',' + this.previewScroll.y +'); });\n' +
'})();\n';
const previewContents = this.state.previewContents.replace(/<\s*head\s*>/i, `<head><script>${previewScript}</script>`);
return (
<div className={styles.sandbox}>
<div className={this.state.preview ? styles.aceEditorWithPreview : styles.aceEditorWithoutPreview}>
@ -185,7 +206,7 @@ class CodeEditorSandbox extends Component {
{
this.state.preview &&
<div className={styles.preview}>
<iframe ref={node => this.previewNode = node} src={"data:text/html;charset=utf-8," + escape(this.state.previewContents)}></iframe>
<iframe ref={node => this.previewNode = node} src={"data:text/html;charset=utf-8," + escape(previewContents)}></iframe>
</div>
}
</div>

View file

@ -29,8 +29,9 @@ export class CodeEditorHost extends Component {
initialSource: PropTypes.string,
sourceType: PropTypes.string,
title: PropTypes.string,
onTestSend: PropTypes.func,
onSave: PropTypes.func,
canSave: PropTypes.bool,
onTestSend: PropTypes.func,
onFullscreenAsync: PropTypes.func
}

View file

@ -28,6 +28,8 @@ export class GrapesJSHost extends Component {
initialStyle: PropTypes.string,
sourceType: PropTypes.string,
title: PropTypes.string,
onSave: PropTypes.func,
canSave: PropTypes.bool,
onTestSend: PropTypes.func,
onFullscreenAsync: PropTypes.func
}
@ -67,6 +69,7 @@ export class GrapesJSHost extends Component {
<div className={styles.title}>{this.props.title}</div>
<a className={styles.btn} onClick={::this.toggleFullscreenAsync}><Icon icon="fullscreen"/></a>
<a className={styles.btn} onClick={this.props.onTestSend}><Icon icon="send"/></a>
{this.props.canSave ? <a className={styles.btn} onClick={this.props.onSave}><Icon icon="floppy-disk"/></a> : <span className={styles.btnDisabled}><Icon icon="floppy-disk"/></span>}
</div>
<UntrustedContentHost ref={node => this.contentNode = node} className={styles.host} singleToken={true} contentProps={editorData} contentSrc="grapesjs/editor" tokenMethod="grapesjs" tokenParams={tokenData}/>
</div>

View file

@ -26,6 +26,8 @@ export class MosaicoHost extends Component {
entityTypeId: PropTypes.string,
entity: PropTypes.object,
title: PropTypes.string,
onSave: PropTypes.func,
canSave: PropTypes.bool,
onTestSend: PropTypes.func,
onFullscreenAsync: PropTypes.func,
templateId: PropTypes.number,
@ -70,6 +72,7 @@ export class MosaicoHost extends Component {
<div className={styles.title}>{this.props.title}</div>
<a className={styles.btn} onClick={::this.toggleFullscreenAsync}><Icon icon="fullscreen"/></a>
<a className={styles.btn} onClick={this.props.onTestSend}><Icon icon="send"/></a>
{this.props.canSave ? <a className={styles.btn} onClick={this.props.onSave}><Icon icon="floppy-disk"/></a> : <span className={styles.btnDisabled}><Icon icon="floppy-disk"/></span>}
</div>
<UntrustedContentHost ref={node => this.contentNode = node} className={styles.host} singleToken={true} contentProps={editorData} contentSrc="mosaico/editor" tokenMethod="mosaico" tokenParams={tokenData}/>
</div>

View file

@ -52,7 +52,7 @@ export default class CUD extends Component {
this.state = {
showMergeTagReference: false,
elementInFullscreen: false,
showTestSendModal: false
showTestSendModal: false,
};
this.initForm({
@ -76,11 +76,13 @@ export default class CUD extends Component {
}
}
loadFromEntityMutator(data) {
this.templateTypes[data.type].afterLoad(data);
}
componentDidMount() {
if (this.props.entity) {
this.getFormValuesFromEntity(this.props.entity, data => {
this.templateTypes[data.type].afterLoad(data);
});
this.getFormValuesFromEntity(this.props.entity, data => this.loadFromEntityMutator(data));
} else {
this.populateFormValues({
name: '',
@ -146,6 +148,7 @@ export default class CUD extends Component {
if (submitResponse) {
if (stayOnPage) {
await this.getFormValuesFromURL(`rest/templates/${this.props.entity.id}`, data => this.loadFromEntityMutator(data));
this.enableForm();
this.clearFormStatusMessage();
this.setFlashMessage('success', t('templateSaved'));

View file

@ -121,6 +121,8 @@ export function getTemplateTypes(t, prefix = '', entityTypeId = ResourceType.TEM
templateId={owner.getFormValue(prefix + 'mosaicoTemplate')}
entityTypeId={entityTypeId}
title={t('mosaicoTemplateDesigner')}
onSave={::owner.save}
canSave={owner.isFormWithoutErrors()}
onTestSend={::owner.showTestSendModal}
onFullscreenAsync={::owner.setElementInFullscreen}
/>
@ -194,6 +196,8 @@ export function getTemplateTypes(t, prefix = '', entityTypeId = ResourceType.TEM
templatePath={getSandboxUrl(`static/mosaico/templates/${owner.getFormValue(prefix + 'mosaicoFsTemplate')}/index.html`)}
entityTypeId={entityTypeId}
title={t('mosaicoTemplateDesigner')}
onSave={::owner.save}
canSave={owner.isFormWithoutErrors()}
onTestSend={::owner.showTestSendModal}
onFullscreenAsync={::owner.setElementInFullscreen}
/>
@ -270,6 +274,8 @@ export function getTemplateTypes(t, prefix = '', entityTypeId = ResourceType.TEM
initialStyle={owner.getFormValue(prefix + 'grapesJSData').style}
sourceType={owner.getFormValue(prefix + 'grapesJSSourceType')}
title={t('grapesJsTemplateDesigner')}
onSave={::owner.save}
canSave={owner.isFormWithoutErrors()}
onTestSend={::owner.showTestSendModal}
onFullscreenAsync={::owner.setElementInFullscreen}
/>
@ -322,6 +328,8 @@ export function getTemplateTypes(t, prefix = '', entityTypeId = ResourceType.TEM
initialSource={owner.getFormValue(prefix + 'ckeditor4Data').source}
entityTypeId={entityTypeId}
title={t('ckEditor4TemplateDesigner')}
onSave={::owner.save}
canSave={owner.isFormWithoutErrors()}
onTestSend={::owner.showTestSendModal}
onFullscreenAsync={::owner.setElementInFullscreen}
/>