/**
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*/
import Soy from 'metal-soy';
import {Config} from 'metal-state';
import {PortletBase, openToast} from 'frontend-js-web';
import templates from './FragmentEditor.soy';
import './FragmentPreview.es';
import './SourceEditor.es';
/**
* Creates a Fragment Editor component that lets you create a new fragment or
* edit an existing fragment. This component integrates three
* <code><SourceEditor /></code> components for each part of the fragment and
* a <code><FragmentPreview /></code> component for the preview.
*/
class FragmentEditor extends PortletBase {
/**
* @inheritDoc
*/
shouldUpdate(changes) {
return (
changes._html ||
changes._js ||
changes._configuration ||
changes._css ||
changes._saving
);
}
/**
* Returns content for the fragment.
*
* @public
* @return {{
* configuration: string,
* css: string,
* html: string,
* js: string
* }}
*/
getContent() {
return {
configuration: this._configuration,
css: this._css,
html: this._html,
js: this._js
};
}
/**
* Returns <code>true</code> when HTML content is valid.
*
* @public
* @return {boolean} <code>true</code> when HTML is valid; <code>false</code>
* otherwise.
*/
isHtmlValid() {
return this._htmlValid;
}
/**
* Callback that propagates the <code>contentChanged</code> event when
* content is modified.
*
* @private
*/
_handleContentChanged() {
this.emit('contentChanged', this.getContent());
}
/**
* Callback executed when the Configuration editor changes.
*
* @param {!Event} event
* @private
*/
_handleConfigurationChanged(event) {
this._configuration = event.content;
this._handleContentChanged();
}
/**
* Callback executed when the CSS editor changes.
*
* @param {!Event} event
* @private
*/
_handleCSSChanged(event) {
this._css = event.content;
this._handleContentChanged();
}
/**
* Callback executed when the HTML editor changes.
*
* @param {!Event} event
* @private
*/
_handleHTMLChanged(event) {
this._html = event.content;
this._htmlValid = event.valid;
this._handleContentChanged();
}
/**
* Callback executed when the JS editor changes.
*
* @param {!Event} event
* @private
*/
_handleJSChanged(event) {
this._js = event.content;
this._handleContentChanged();
}
/**
* Saves the fragment content when the Save button is clicked.
*
* @param {!Event} event
* @private
*/
_handleSaveButtonClick(event) {
const content = this.getContent();
const status = event.delegateTarget.value;
if (this.isHtmlValid()) {
this._saving = true;
this.fetch(this.urls.edit, {
configurationContent: content.configuration,
cssContent: content.css,
fragmentCollectionId: this.fragmentCollectionId,
fragmentEntryId: this.fragmentEntryId,
htmlContent: content.html,
jsContent: content.js,
name: this.name,
status
})
.then(response => response.json())
.then(response => {
if (response.error) {
throw response.error;
}
return response;
})
.then(response => {
const redirectURL = response.redirect || this.urls.redirect;
Liferay.Util.navigate(redirectURL);
})
.catch(error => {
this._saving = false;
const message =
typeof error === 'string'
? error
: Liferay.Language.get('error');
openToast({
message,
title: Liferay.Language.get('error'),
type: 'danger'
});
});
} else {
alert(Liferay.Language.get('fragment-html-is-invalid'));
}
}
}
/**
* State definition.
*
* @static
* @type {!Object}
*/
FragmentEditor.STATE = {
/**
* Updated Configuration content of the editor. This value is propagated to the
* preview pane.
*
* @default ''
* @instance
* @memberOf FragmentEditor
* @private
* @type {string}
*/
_configuration: Config.string()
.internal()
.value(''),
/**
* Updated CSS content of the editor. This value is propagated to the
* preview pane.
*
* @default ''
* @instance
* @memberOf FragmentEditor
* @private
* @type {string}
*/
_css: Config.string()
.internal()
.value(''),
/**
* Updated HTML content of the editor. This value is propagated to the
* preview pane.
*
* @default ''
* @instance
* @memberOf FragmentEditor
* @private
* @type {string}
*/
_html: Config.string()
.internal()
.value(''),
/**
* Flag to specify if the editor's updated HTML content is valid.
*
* @default true
* @instance
* @memberOf FragmentEditor
* @private
* @type {boolean}
*/
_htmlValid: Config.bool()
.internal()
.value(true),
/**
* Updated JS content of the editor. This value is propagated to the preview
* pane.
*
* @default ''
* @instance
* @memberOf FragmentEditor
* @private
* @type {string}
*/
_js: Config.string()
.internal()
.value(''),
/**
* If <code>true</code>, the fragment is saved.
*
* @default false
* @instance
* @memberOf FragmentEditor
* @private
* @type {bool}
*/
_saving: Config.bool()
.internal()
.value(false),
/**
* List of tags for custom autocompletion in the HTML editor.
*
* @default []
* @instance
* @memberOf FragmentEditor
* @type Array
*/
autocompleteTags: Config.arrayOf(
Config.shapeOf({
content: Config.string(),
name: Config.string()
})
),
/**
* Fragment collection ID.
*
* @default undefined
* @instance
* @memberOf FragmentEditor
* @type {!string}
*/
fragmentCollectionId: Config.string().required(),
/**
* Fragment entry ID.
*
* @default undefined
* @instance
* @memberOf FragmentEditor
* @type {!string}
*/
fragmentEntryId: Config.string().required(),
/**
* Fragment name.
*
* @default undefined
* @instance
* @memberOf FragmentEditor
* @type {!string}
*/
name: Config.string().required(),
/**
* URLs used for communicating with back-end logic.
*
* @instance
* @memberOf FragmentEditor
* @type {{
* edit: !string,
* redirect: !string
* }}
*/
urls: Config.shapeOf({
edit: Config.string().required(),
redirect: Config.string().required()
}).required()
};
Soy.register(FragmentEditor, templates);
export {FragmentEditor};
export default FragmentEditor;