superdesk/superdesk-client-core

View on GitHub
scripts/core/editor3/service.ts

Summary

Maintainability
A
0 mins
Test Coverage
import * as action from './actions';
import {forEachMatch} from './helpers/find-replace';
import {clearHighlights} from './helpers/find-replace';
import {prepareHtmlForPatching} from './helpers/patch-editor-3-html';
import {editor3StateToHtml} from './html/to-html/editor3StateToHtml';
import {IArticle} from 'superdesk-api';

/**
 * @type {Object} Redux stores
 * @description Holds the store of the find and replace target
 * of the open article.
 * @private
 */
let store = null;

/**
 * @type {array} Redux stores
 * @description Holds the stores of the editors on the open article
 * if they are spellchecker targets
 * @private
 */
let spellcheckerStores = [];

/**
 * @ngdoc service
 * @module superdesk.core.editor3
 * @name editor3
 * @description editor3 is the service that allows interacting with the editor from
 * the outside.
 */
export class EditorService {
    /**
     * @ngdoc method
     * @name editor3#setStore
     * @param {Object} redux store
     * @description Registers the passed redux store with the service.
     */
    setStore(s) {
        if (store !== null) {
            console.warn('You\'ve overwritten the find & replace target.');
        }

        store = s;
    }

    /**
     * @ngdoc method
     * @name editor3#addSpellcheckerStore
     * @param {Object} redux store
     * @description Registers the passed redux store with the spellchecker service
     * @returns {Integer}
     */
    addSpellcheckerStore(s, field) {
        spellcheckerStores.push(s);
        s.field = field;
        return spellcheckerStores.length - 1;
    }

    /**
     * @ngdoc method
     * @name editor3#version
     * @description Returns the editor version (this is for when using editorResolver).
     * @returns {string}
     */
    version() {
        return '3';
    }

    /**
     * @ngdoc method
     * @name editor3#unsetStore
     * @description Clears the find and replace store.
     */
    unsetStore() {
        store = null;
    }

    removeAllSpellcheckerStores() {
        spellcheckerStores = [];
    }

    /**
     * @ngdoc method
     * @name editor3#selectNext
     * @description Triggers the action to select the next occurence of the search
     * criteria in the editor.
     */
    selectNext() {
        if (ok()) {
            store.dispatch(action.findNext());
        }
    }

    /**
     * @ngdoc method
     * @name editor3#selectPrev
     * @description Triggers the action to select the previous occurence of the search
     * criteria in the editor.
     */
    selectPrev() {
        if (ok()) {
            store.dispatch(action.findPrev());
        }
    }

    /**
     * @ngdoc method
     * @name editor3#replace
     * @param {string} txt
     * @description Replaces the currently highlighted search criteria with the given text.
     */
    replace(txt) {
        if (ok()) {
            store.dispatch(action.replace(txt));
        }
    }

    /**
     * @ngdoc method
     * @name editor3#replace
     * @param {string} txt
     * @description Replaces all the search criteria with the given text.
     */
    replaceAll(txt) {
        if (ok()) {
            store.dispatch(action.replaceAll(txt));
        }
    }

    /**
     * @ngdoc method
     * @name editor3#setSettings
     * @param {Object} The setting can be findreplace or spellcheck; findreplace is an object containing the keys
     * caseSensitive (boolean) and diff (object having one or multiple keys that is the diff).
     * @description Updates the settings for editor3.
     */
    setSettings({findreplace, spellcheck, language}) {
        if (!ok()) {
            return;
        }

        if (typeof findreplace !== 'undefined') {
            store.dispatch(action.setHighlightCriteria(findreplace || {}));
        }

        if (typeof spellcheck !== 'undefined') {
            spellcheckerStores.forEach((_store) => {
                _store.dispatch(action.setSpellcheckerLanguage(language));
                _store.dispatch(action.setSpellcheckerStatus(spellcheck));
            });
        }
    }

    /**
     * @ngdoc method
     * @name editor3#render
     * @description Highlights the current search criteria in the editor.
     */
    render() {
        if (ok()) {
            store.dispatch(action.renderHighlights());
        }
    }

    /**
     * @ngdoc method
     * @name editor3#getActiveText
     * @description Gets the text under the current selection.
     */
    getActiveText() {
        if (!ok()) {
            return;
        }

        const state = store.getState();
        const {editorState, searchTerm} = state;
        const {index, pattern, caseSensitive} = searchTerm;
        const content = editorState.getCurrentContent();

        let txt = pattern;

        // find the active match
        forEachMatch(content, pattern, caseSensitive, (i, selection, block, newContent) => {
            if (i === index) {
                const start = selection.getStartOffset();
                const end = selection.getEndOffset();

                txt = block.getText().slice(start, end);
            }

            return newContent;
        });

        return txt;
    }

    /**
     * @ngdoc method
     * @name editor3#getHTML
     * @description Gets the content of the editor as HTML.
     * @returns {string} HTML
     */
    getHTML() {
        if (!ok()) {
            return '';
        }

        const state = store.getState();
        const content = state.editorState.getCurrentContent();
        const cleanedContent = clearHighlights(content).content;

        return editor3StateToHtml(cleanedContent);
    }

    /**
     * @ngdoc method
     * @name editor3#getHtmlForTansa
     * @description Gets the content of the editor as custom(simplified) html for Tansa.
     * @returns {string} HTML
     */
    getHtmlForTansa() {
        if (!ok()) {
            return '';
        }

        const state = store.getState();
        const {editorState} = state;

        return prepareHtmlForPatching(editorState);
    }

    /**
     * @ngdoc method
     * @name editor3#setHtmlFromTansa
     * @param {string} html
     * @param {string} simpleReplace
     * @description For every block from editor content merge the changes received from tansa.
     * If the simpleReplace is true try to preserve the existing inline styles and entities
     */
    setHtmlFromTansa(html, simpleReplace = false) {
        if (ok()) {
            store.dispatch(action.setHtmlFromTansa(html, simpleReplace));
        }
    }

    setEditorStateFromItem(item: IArticle, field: string) {
        if (ok()) {
            // store.dispatch(action.setEditorStateFromItem(item, field));
            spellcheckerStores.forEach((_store) => {
                if (_store.field === field) {
                    _store.dispatch(action.setEditorStateFromItem(item, field));
                }
            });
        }
    }
}

function ok() {
    if (store === null) {
        console.error('No editor set as target in service.');
    }

    return store !== null;
}