All Downloads are FREE. Search and download functionalities are using the official Maven repository.

META-INF.resources.js.fragment-editor.FragmentEditor.js Maven / Gradle / Ivy

There is a newer version: 4.0.119
Show newest version
/**
 * SPDX-FileCopyrightText: (c) 2000 Liferay, Inc. https://liferay.com
 * SPDX-License-Identifier: LGPL-2.1-or-later OR LicenseRef-Liferay-DXP-EULA-2.0.0-2023-06
 */

import ClayForm from '@clayui/form';
import ClayIcon from '@clayui/icon';
import ClayTabs from '@clayui/tabs';
import {useIsMounted, usePrevious} from '@liferay/frontend-js-react-web';
import {
	cancelDebounce,
	debounce,
	fetch,
	navigate,
	openToast,
	sub,
} from 'frontend-js-web';
import React, {useCallback, useEffect, useState} from 'react';

import CodeMirrorEditor from './CodeMirrorEditor';
import {FieldTypeSelector} from './FieldTypeSelector';
import FragmentPreview from './FragmentPreview';
import createFile from './createFile';

const CHANGES_STATUS = {
	saved: Liferay.Language.get('changes-saved'),
	saving: Liferay.Language.get('saving-changes'),
	unsaved: Liferay.Language.get('unsaved-changes'),
};

const FragmentEditor = ({
	context: {namespace},
	props: {
		allowedStatus = {
			approved: false,
			draft: false,
		},
		autocompleteTags,
		dataAttributes,
		fieldTypes: availableFieldTypes,
		fragmentCollectionId,
		fragmentConfigurationURL,
		fragmentEntryId,
		htmlEditorCustomEntities,
		initialCSS,
		initialConfiguration,
		initialFieldTypes,
		initialHTML,
		initialJS,
		name,
		propagationEnabled,
		readOnly,
		showFieldTypes,
		status,
		urls,
	},
}) => {
	const [activeTabKeyValue, setActiveTabKeyValue] = useState(0);
	const [changesStatus, setChangesStatus] = useState(null);
	const [configuration, setConfiguration] = useState(initialConfiguration);
	const [css, setCss] = useState(initialCSS);
	const [html, setHtml] = useState(initialHTML);
	const [js, setJs] = useState(initialJS);
	const [fieldTypes, setFieldTypes] = useState(initialFieldTypes);
	const previousConfiguration =
		usePrevious(configuration) || initialConfiguration;
	const previousCss = usePrevious(css) || initialCSS;
	const previousFieldTypes = usePrevious(fieldTypes) || initialFieldTypes;
	const previousHtml = usePrevious(html) || initialHTML;
	const previousJs = usePrevious(js) || initialJS;

	const [previewData, setPreviewData] = useState({
		configuration: initialConfiguration,
		css: initialCSS,
		html: initialHTML,
		js: initialJS,
	});

	const isMounted = useIsMounted();

	const contentHasChanged = useCallback(() => {
		return (
			previousConfiguration !== configuration ||
			previousCss !== css ||
			previousFieldTypes.length !== fieldTypes.length ||
			previousHtml !== html ||
			previousJs !== js
		);
	}, [
		configuration,
		css,
		fieldTypes,
		html,
		previousCss,
		previousConfiguration,
		previousFieldTypes,
		previousHtml,
		previousJs,
		js,
	]);

	const publish = () => {
		const formData = new FormData();

		formData.append(`${namespace}fragmentEntryId`, fragmentEntryId);

		fetch(urls.publish, {
			body: formData,
			method: 'POST',
		})
			.then((response) => response.json())
			.then((response) => {
				if (response.error) {
					throw response.error;
				}

				return response;
			})
			.then((response) => {
				const redirectURL = response.redirect || urls.redirect;

				navigate(redirectURL);
			})
			.catch((error) => {
				if (isMounted()) {
					setChangesStatus(CHANGES_STATUS.unsaved);
				}

				const message =
					typeof error === 'string'
						? error
						: Liferay.Language.get('error');

				openToast({
					message,
					type: 'danger',
				});
			});
	};

	/* eslint-disable-next-line react-hooks/exhaustive-deps */
	const saveDraft = useCallback(
		debounce(() => {
			setChangesStatus(CHANGES_STATUS.saving);

			const formData = new FormData();

			formData.append(`${namespace}configurationContent`, configuration);
			formData.append(
				`${namespace}cssContent`,
				createFile('cssContent', css)
			);
			formData.append(`${namespace}fieldTypes`, fieldTypes);
			formData.append(
				`${namespace}fragmentCollectionId`,
				fragmentCollectionId
			);
			formData.append(`${namespace}fragmentEntryId`, fragmentEntryId);
			formData.append(
				`${namespace}htmlContent`,
				createFile('htmlContent', html)
			);
			formData.append(
				`${namespace}jsContent`,
				createFile('jsContent', js)
			);
			formData.append(`${namespace}name`, name);
			formData.append(`${namespace}status`, allowedStatus.draft);

			fetch(urls.edit, {
				body: formData,
				method: 'POST',
			})
				.then((response) => response.json())
				.then((response) => {
					if (response.error) {
						throw response.error;
					}

					return response;
				})
				.then(() => {
					setPreviewData({configuration, css, html, js});

					setChangesStatus(CHANGES_STATUS.saved);
				})
				.catch((error) => {
					if (isMounted()) {
						setChangesStatus(CHANGES_STATUS.unsaved);
					}

					const message =
						typeof error === 'string'
							? error
							: Liferay.Language.get('error');

					openToast({
						message,
						type: 'danger',
					});
				});
		}, 500),
		[configuration, css, fieldTypes, html, js]
	);

	const previousSaveDraft = usePrevious(saveDraft);

	useEffect(() => {
		if (previousSaveDraft && previousSaveDraft !== saveDraft) {
			cancelDebounce(previousSaveDraft);
		}
	}, [previousSaveDraft, saveDraft]);

	useEffect(() => {
		if (contentHasChanged()) {
			setChangesStatus(CHANGES_STATUS.unsaved);
			saveDraft();
		}
	}, [contentHasChanged, saveDraft]);

	return (
		
setActiveTabKeyValue(0)} > {Liferay.Language.get('code')} setActiveTabKeyValue(1)} > {Liferay.Language.get('configuration')}
{readOnly ? ( {Liferay.Language.get('read-only-view')} ) : ( <> {propagationEnabled && ( {Liferay.Language.get( 'automatic-propagation-enabled' )} )}
{changesStatus}
)}
', 'const fragmentElement = ...;', 'const configuration = ...;', ]} content={initialJS} mode="javascript" onChange={setJs} readOnly={readOnly} />
{showFieldTypes && ( <> )}

json

{!readOnly && (

{Liferay.Language.get( 'add-the-json-configuration' )}

)}
); }; export default FragmentEditor;




© 2015 - 2024 Weber Informatics LLC | Privacy Policy