# components/Logbook/EditorWrapper.js

## Maintainability

65.74

## Lines of code

177

## Difficulty

31.10

## Estimated Errors

1.58

## Function weight

### By Complexity

### By SLOC

import React, { Component } from 'react' import PropTypes from 'prop-types' import { EditionModeConfig } from '../../config/tinymce/tinymce.js' import tinymce from 'tinymce/tinymce'; import { getContent } from '../../helpers/EventHelpers.js'; import { HTML_CONTENT_FORMAT, EDIT_EVENT_CONTEXT, NEW_EVENT_CONTEXT, PLAINTEXT_CONTENT_FORMAT, LOCALSTORAGE_KEY_NEW_EVENT_CONTENT_IN_PLAINTEXT_FORMAT, LOCALSTORAGE_KEY_NEW_EVENT_CONTENT_IN_HTML_FORMAT, LOCALSTORAGE_KEY_EDITED_EVENT_CONTENT_IN_PLAINTEXT_FORMAT, LOCALSTORAGE_KEY_EDITED_EVENT_CONTENT_IN_HTML_FORMAT } from '../../constants/EventTypes.js'; import { Editor } from '@tinymce/tinymce-react' import UI from '../../config/ui/config'; import axios from 'axios'; import { uploadFile } from '../../api/icat/icatPlus.js' import { getFileByEventId } from "../../api/icat/icatPlus" const EDITOR_ID_FOR_CREATION = 'myEditorForCreation'; const EDITOR_ID_FOR_EDITION = 'myEditorForEdition'; export default class EditorWrapper extends Component { constructor(props) { super(props); this.state = { text: props.event ? getContent(props.event.content, HTML_CONTENT_FORMAT) : undefined // HTML text } this.onEditorStateChanged = this.onEditorStateChanged.bind(this); this.setImageHeightByCSSRule = this.setImageHeightByCSSRule.bind(this); } render() { const config = new EditionModeConfig(); return <Editor id={this.props.event ? EDITOR_ID_FOR_EDITION : EDITOR_ID_FOR_CREATION} init={{ plugins: config.plugins, skin_url: config.skin_url, branding: config.branding, readonly: config.readonly, toolbar: config.toolbar, menubar: config.menubar, statusbar: config.statusbar, images_upload_handler: this.imagesUploadHandler, paste_data_images: config.paste_data_images, formats: config.formats, //content_css: config.content_css, }} value={this.state.text} onEditorChange={this.onEditorStateChanged} /> } /** * Function triggered when the editor state changes (mouse click, key press for example ) * @param {String} text current editor content in HTML format */ onEditorStateChanged(text) { let context = this.props.event ? EDIT_EVENT_CONTEXT : NEW_EVENT_CONTEXT; if (text) { // Editor content has been modified by the user. Save the update to localStorage this.storeToLocalStorage(context, tinymce.activeEditor.getContent({ format: 'text' }), PLAINTEXT_CONTENT_FORMAT) this.storeToLocalStorage(context, tinymce.activeEditor.getContent(), HTML_CONTENT_FORMAT) } this.setImageHeightByCSSRule(); this.props.onContentChanged(); this.setState({ text: text }); } componentDidMount() { // Make sure localstorage is populated in case the editor is not clicked on at all let context = this.props.event ? EDIT_EVENT_CONTEXT : NEW_EVENT_CONTEXT; this.storeToLocalStorage(context, this.state.text, HTML_CONTENT_FORMAT); } componentWillUnmount() { let context = this.props.event ? EDIT_EVENT_CONTEXT : NEW_EVENT_CONTEXT; if (context === NEW_EVENT_CONTEXT) { localStorage.removeItem(LOCALSTORAGE_KEY_NEW_EVENT_CONTENT_IN_PLAINTEXT_FORMAT); localStorage.removeItem(LOCALSTORAGE_KEY_NEW_EVENT_CONTENT_IN_HTML_FORMAT); } if (context === EDIT_EVENT_CONTEXT) { localStorage.removeItem(LOCALSTORAGE_KEY_EDITED_EVENT_CONTENT_IN_PLAINTEXT_FORMAT + this.props.event._id); localStorage.removeItem(LOCALSTORAGE_KEY_EDITED_EVENT_CONTENT_IN_HTML_FORMAT + this.props.event._id); } } /** * Store data to the localstorage * @param {string} context * @param {string} content content data to store * @param {string} contentFormat data format */ storeToLocalStorage(context, content, contentFormat) { if (context && contentFormat) { if (context === NEW_EVENT_CONTEXT) { if (contentFormat === PLAINTEXT_CONTENT_FORMAT) { localStorage.setItem(LOCALSTORAGE_KEY_NEW_EVENT_CONTENT_IN_PLAINTEXT_FORMAT, content); } else if (contentFormat === HTML_CONTENT_FORMAT) { localStorage.setItem(LOCALSTORAGE_KEY_NEW_EVENT_CONTENT_IN_HTML_FORMAT, content); } } if (context === EDIT_EVENT_CONTEXT) { if (contentFormat === PLAINTEXT_CONTENT_FORMAT) { localStorage.setItem(LOCALSTORAGE_KEY_EDITED_EVENT_CONTENT_IN_PLAINTEXT_FORMAT + this.props.event._id, content); } else if (contentFormat === HTML_CONTENT_FORMAT) { localStorage.setItem(LOCALSTORAGE_KEY_EDITED_EVENT_CONTENT_IN_HTML_FORMAT + this.props.event._id, content); } } } } /** * Sets a default image height using a CSS rule. This is a trick to make sure the image height * is applied in the editor (for scrollabar propose) especially because the image is not necessary * yet downloaded at this step. The height is changed to auto after the image is fully downloaded * such that image ratio is kept. */ setImageHeightByCSSRule() { if (tinymce && tinymce.activeEditor) { let selectedNode = tinymce.activeEditor.selection.getNode(); if (selectedNode.nodeName === 'IMG' && selectedNode.style.height !== 'auto') { let nxElement = selectedNode; nxElement.style.height = UI.logbook.NEW_EVENT_MAX_HEIGHT; nxElement.style.width = 'auto'; // a css trick for some browsers IE8 and old iceweasel nxElement.onload = this.onImageLoaded; tinymce.activeEditor.dom.replace(nxElement, selectedNode); } } } /** * Defines what to do when the user drag an image onto the dropzone of the editor image plugin. This function must return a promise. * The value of a fullfilled promise must be an array of the form { data: { link: url } } where url value is the link to the image which * has just been uoloaded to the ICAT+ server. * @param {*} file : the image which has just been dropped on the drop zone. */ imagesUploadHandler(blobInfo, success, failure) { let { investigationId } = this.props; let sessionId = this.props.user.sessionId; let data = new FormData(); data.append('file', blobInfo.blob(), blobInfo.filename()); data.append('investigationId', investigationId); data.append('creationDate', Date()); data.append('type', 'attachment'); data.append('category', 'file'); data.append('username', this.props.user.username); axios({ method: "post", url: uploadFile(sessionId, investigationId), data: data, }) .then(function (value) { let eventId = value.data._id; success(getFileByEventId(sessionId, investigationId, eventId)); }, function (error) { console.log("[ERROR] Retrieval of the image you have just upladed into the editor failed ! "); failure(error); }); } } EditorWrapper.propTypes = { /** Event being edited. When event is undefined, editor is used to create content of a new event */ event: PropTypes.object, /** the investigationId of the event being edited. */ investigationId: PropTypes.string, /** Function triggered when editor content changed */ onContentChanged: PropTypes.func, /** the user who is currently logged in */ user: PropTypes.object.isRequired, }