/*
LATER:
- Get/show current font size, line height & letter spacing
- Click toggle button shows gray highlight
- Image di luar domain gak bisa di-edit (kasih warning)
*/

import {Util, Dom} from './util.js';
import ColorPicker from './colorpicker.js';
import Hyperlink from './elementhyperlink.js';
import ElementStyleEditor from './elementpanel-css.js';

const dom = new Dom();

/**
 * RTE Class
 */
class Rte {

    /**
     * Constructor
     *
     * @param builder
     */
    constructor(builder) {

        this.builder = builder;

        const util = new Util(builder);
        this.util  = util;

        const builderStuff = util.builderStuff();
        this.builderStuff  = builderStuff;

        this.elementStyleEditor = new ElementStyleEditor(builder);
        this.hyperlink = new Hyperlink(builder);

        let rteTool = builderStuff.querySelector('#divRteTool');
        let elementRteTool;
        let rteAlignOptions;
        let rteFormattingOptions;
        let rteColorPicker;
        let rteListOptions;
        let rteFontFamilyOptions;
        let rteParagraphOptions;
        let rteMoreOptions;
        let elementRteMoreOptions;
        let rteTextSettingOptions;
        let rteIconOptions;
        let rteCustomTagOptions;

        // If no tool
        if (!rteTool) {
            let customtag_button = '';
            var customTagsHtml   = '';

            // If custom tags
            if (builder.opts.customTags.length > 0) {
                customtag_button = `
                    <button class="rte-tags">
                        <svg class="is-icon-flex" style="width:14px; height:14px">
                            <use xlink:href="#ion-code-working"></use>
                        </svg>
                    </button>
                `;

                for (let j = 0; j < builder.opts.customTags.length; j++) {
                    customTagsHtml += `
                        <button data-value="${builder.opts.customTags[j][1]}"> 
                            ${builder.opts.customTags[j][0]}
                        </button>
                    `;
                }
            }

            // If more buttons
            let html_rtemore = '';
            for (var j = 0; j < builder.opts.buttonsMore.length; j++) {

                let btnMore = builder.opts.buttonsMore[j].toLowerCase();

                if (btnMore === 'createlink') {
                    html_rtemore += `
                        <button title="${util.out('Hyperlink')}" class="rte-link">
                            <svg class="is-icon-flex" style="width:14px; height:14px;">
                                <use xlink:href="#ion-link"></use>
                            </svg>
                        </button>
                    `;

                } else if (btnMore === 'icon' && !this.builder.opts.emailMode) {
                    html_rtemore += `
                        <button title="${util.out('Icon')}" class="rte-icon">
                            <svg class="is-icon-flex" style="width:14px; height:14px; margin-top:2px;">
                                <use xlink:href="#ion-android-happy"></use>
                            </svg>
                        </button>
                    `;

                } else if (btnMore === 'removeformat') {
                    html_rtemore += `
                        <button title="${util.out('Clean')}" class="rte-clean">
                            <svg class="is-icon-flex" style="width:11px; height:11px;">
                                <use xlink:href="#icon-clean"></use>
                            </svg>
                        </button>
                    `;

                } else if (btnMore === 'bold') {
                    html_rtemore += `
                        <button title="${util.out('Bold')}" class="rte-format" data-command="bold">
                            <span style="font-family:serif; font-size:14px;">B</span>
                        </button>
                    `;

                } else if (btnMore === 'italic') {
                    html_rtemore += `
                        <button title="${util.out('Italic')}" class="rte-format" data-command="italic">
                            <span style="font-family:serif; font-size:14px; font-style:italic;">i</span>
                        </button>
                    `;

                } else if (btnMore === 'underline') {
                    html_rtemore += `
                        <button title="${util.out('Underline')}" class="rte-format" data-command="underline">
                            <span style="font-family:serif; font-size:14px; text-decoration:underline;">U</span>
                        </button>
                    `;

                } else if (btnMore === 'align') {
                    html_rtemore += `
                        <button title="${util.out('Align')}" class="rte-align">
                            <svg class="is-icon-flex" style="width:12px; height:12px; margin-top:-2px;">
                                <use xlink:href="#icon-align-full"></use>
                            </svg>
                        </button>
                    `;

                } else if (btnMore === 'list') {
                    html_rtemore += `
                        <button title="${util.out('List')}" class="rte-list">
                            <svg class="is-icon-flex" style="width:12px;height:12px;">
                                <use xlink:href="#icon-list-bullet"></use>
                            </svg>
                        </button>
                    `;

                } else if (btnMore === 'color') {
                    html_rtemore += `
                        <button title="${util.out('Color')}" class="rte-color">
                            <svg class="is-icon-flex" style="width:12px; height:12px;">
                                <use xlink:href="#ion-contrast"></use>
                            </svg>
                        </button>
                    `;

                } else if (btnMore === 'formatting') {
                    html_rtemore += `
                        <button title="${util.out('Formatting')}" class="rte-formatting">
                            <span style="font-family:serif; font-size:15px; display:inline-block;">A</span>
                        </button>
                    `;

                } else if (btnMore === 'tags') {
                    html_rtemore += customtag_button;

                } else if (btnMore === 'image') {
                    html_rtemore += `
                        <button title="${util.out('Image')}" class="rte-image">
                            <svg class="is-icon-flex" style="width:13px; height:13px;">
                                <use xlink:href="#ion-image"></use>
                            </svg>
                        </button>
                    `;

                } else if (btnMore === 'gridtool') {
                    html_rtemore += `
                        <button title="${util.out('Grid Tool')}" class="rte-grideditor">
                            <svg class="is-icon-flex" style="margin-right:-3px;">
                                <use xlink:href="#ion-grid"></use>
                            </svg>
                        </button>
                    `;

                } else if (btnMore === 'html') {
                    html_rtemore += `
                        <button title="${util.out('HTML')}" class="rte-html">
                            <svg class="is-icon-flex" style="margin-right:-3px; width:14px; height:14px;">
                                <use xlink:href="#ion-ios-arrow-left"></use>
                            </svg>
                            <svg class="is-icon-flex" style="margin-left:-2px; fill:rgba(0, 0, 0, 0.65); width:14px; height:14px;">
                                <use xlink:href="#ion-ios-arrow-right"></use>
                            </svg>
                        </button>
                    `;

                } else if (btnMore === 'preferences') {
                    html_rtemore += `
                        <button title="${util.out('Preferences')}" class="rte-preferences">
                            <svg class="is-icon-flex" style="width:13px; height:13px;">
                                <use xlink:href="#ion-wrench"></use>
                            </svg>
                        </button>
                    `;

                } else if (btnMore === 'addsnippet') {
                    html_rtemore += `
                        <button title="${util.out('Add Snippet')}" class="rte-addsnippet">
                            <svg class="is-icon-flex" style="width:18px; height:18px; margin-top:-1px;">
                                <use xlink:href="#ion-ios-plus-empty"></use>
                            </svg>
                        </button>
                    `;

                } else if (btnMore === 'formatpara') {
                    html_rtemore += `
                        <button title="${util.out('Paragraph')}" class="rte-paragraph">
                            <span style="font-family:serif; font-size:14px; display:inline-block; margin-top:2px;">H</span>
                        </button>
                    `;

                } else if (btnMore === 'font') {
                    html_rtemore += `
                        <button title="${util.out('Font')}" class="rte-fontfamily">
                            <span style="font-family:serif; font-size:18px; text-transform:none; display:inline-block; margin-top: -3px;">a</span>
                        </button>
                    `;

                } else if (btnMore === 'textsettings') {
                    html_rtemore += `
                        <button title="${util.out('Text Settings')}" class="rte-textsettings">
                            <svg class="is-icon-flex" style="width:16px; height:16px;">
                                <use xlink:href="#ion-ios-settings"></use>
                            </svg>
                        </button>
                    `;

                } else if (btnMore === 'undo') {
                    html_rtemore += `
                        <button title="${util.out('Undo')}" class="rte-undo">
                            <svg class="is-icon-flex" style="margin-top:2px; width:15px; height:15px;">
                                <use xlink:href="#ion-ios-undo"></use>
                            </svg>
                        </button>
                    `;

                } else if (btnMore === 'redo') {
                    html_rtemore += `
                        <button title="${util.out('Redo')}" class="rte-redo">
                            <svg class="is-icon-flex" style="margin-top:2px;width:15px;height:15px;">
                                <use xlink:href="#ion-ios-redo"></use>
                            </svg>
                        </button>
                    `;

                } else if (btnMore === '|') {
                    html_rtemore += '<div class="rte-separator"></div>';

                } else {
                    html_rtemore += `<button title="button not found" data-plugin="${btnMore}">-</button>`; //temporary (later will be replaced with plugin button)
                }
            }

            // Normal buttons
            let html_rte = '';
            for (j = 0; j < builder.opts.buttons.length; j++) {

                let btnNormal = builder.opts.buttons[j].toLowerCase();

                if (btnNormal === 'bold') {
                    html_rte += `
                        <button title="${util.out('Bold')}" class="rte-format" data-command="bold">
                            <span style="font-family:serif; font-size:14px;">B</span>
                        </button>
                    `;

                } else if (btnNormal === 'italic') {
                    html_rte += `
                        <button title="${util.out('Italic')}" class="rte-format" data-command="italic">
                            <span style="font-family:serif; font-size:14px; font-style:italic;">i</span>
                        </button>
                    `;

                } else if (btnNormal === 'underline') {
                    html_rte += `
                        <button title="${util.out('Underline')}" class="rte-format" data-command="underline">
                            <span style="font-family:serif; font-size:14px; text-decoration:underline;">U</span>
                        </button>
                    `;

                } else if (btnNormal === 'createlink') {
                    html_rte += `
                        <button title="${util.out('Hyperlink')}" class="rte-link">
                            <svg class="is-icon-flex" style="width:14px;height:14px;">
                                <use xlink:href="#ion-link"></use>
                            </svg>
                        </button>
                    `;

                } else if (btnNormal === 'align') {
                    html_rte += `
                        <button title="${util.out('Align')}" class="rte-align">
                            <svg class="is-icon-flex" style="width:12px; height:12px; margin-top:-2px;">
                                <use xlink:href="#icon-align-full"></use>
                            </svg>
                        </button>
                    `;

                } else if (btnNormal === 'formatpara') {
                    html_rte += `
                        <button title="${util.out('Tag Type')}" class="rte-paragraph">
                            <span style="font-family:serif; font-size:14px; display:inline-block; margin-top:2px;">H</span>
                        </button>
                    `;

                } else if (btnNormal === 'color') {
                    html_rte += `
                        <button title="${util.out('Color')}" class="rte-color">
                            <svg class="is-icon-flex" style="width:12px;height:12px;">
                                <use xlink:href="#ion-contrast"></use>
                            </svg>
                        </button>
                    `;

                } else if (btnNormal === 'formatting') {
                    html_rte += `
                        <button title="${util.out('Formatting')}" class="rte-formatting">
                            <span style="font-family:serif; font-size:15px; display:inline-block;">A</span>
                        </button>
                    `;

                } else if (btnNormal === 'list') {
                    html_rte += `
                        <button title="${util.out('List')}" class="rte-list">
                            <svg class="is-icon-flex" style="width:12px; height:12px;">
                                <use xlink:href="#icon-list-bullet"></use>
                            </svg>
                        </button>
                    `;

                } else if (btnNormal === 'textsettings') {
                    html_rte += `
                        <button title="${util.out('Text Style')}" class="rte-textsettings">
                            <svg class="is-icon-flex" style="width:16px;height:16px;">
                                <use xlink:href="#ion-ios-settings"></use>
                            </svg>
                        </button>
                    `;

                } else if (btnNormal === 'icon' && !this.builder.opts.emailMode) {
                    html_rte += `
                        <button title="${util.out('Icon')}" class="rte-icon">
                            <svg class="is-icon-flex" style="width:14px;height:14px;margin-top:2px">
                                <use xlink:href="#ion-android-happy"></use>
                            </svg>
                        </button>
                    `;

                } else if (btnNormal === 'tags') {
                    html_rte += customtag_button;

                } else if (btnNormal === 'removeformat') {
                    html_rte += `
                        <button title="${util.out('Clean')}" class="rte-format" data-command="clean">
                            <svg class="is-icon-flex" style="width:11px;height:11px;">
                                <use xlink:href="#icon-clean"></use>
                            </svg>
                        </button>
                    `;

                } else if (btnNormal === 'font') {
                    html_rte += `
                        <button title="${util.out('Font')}" class="rte-fontfamily">
                            <span style="font-family:serif;font-size:18px;text-transform:none;display:inline-block;margin-top: -3px;">a</span>
                        </button>
                    `;

                } else if (btnNormal === 'image') {
                    html_rte += `
                        <button title="${util.out('Image')}" class="rte-image">
                            <svg class="is-icon-flex" style="width:13px;height:13px;">
                                <use xlink:href="#ion-image"></use>
                            </svg>
                        </button>
                    `;

                } else if (btnNormal === 'gridtool') {
                    html_rte += `
                        <button title="${util.out('Grid Tool')}" class="rte-grideditor">
                            <svg class="is-icon-flex" style="margin-right:-3px;width:17px;height:17px;">
                                <use xlink:href="#ion-grid"></use>
                            </svg>
                        </button>
                    `;

                } else if (btnNormal === 'html') {
                    html_rte += `
                        <button title="${util.out('HTML')}" class="rte-html">
                            <svg class="is-icon-flex" style="margin-right:-3px; width:14px; height:14px;">
                                <use xlink:href="#ion-ios-arrow-left"></use>
                            </svg>
                            <svg class="is-icon-flex" style="margin-left:-2px; fill:rgba(0, 0, 0, 0.65); width:14px; height:14px;">
                                <use xlink:href="#ion-ios-arrow-right"></use>
                            </svg>
                        </button>
                    `;

                } else if (btnNormal === 'preferences') {
                    html_rte += `
                        <button title="${util.out('Preferences')}" class="rte-preferences">
                            <svg class="is-icon-flex" style="width:13px;height:13px;">
                                <use xlink:href="#ion-wrench"></use>
                            </svg>
                        </button>
                    `;

                } else if (btnNormal === 'addsnippet') {
                    html_rte += `
                        <button title="${util.out('Add Snippet')}" class="rte-addsnippet">
                            <svg class="is-icon-flex" style="width:18px;height:18px;margin-top:-1px;">
                                <use xlink:href="#ion-ios-plus-empty"></use>
                            </svg>
                        </button>
                    `;

                } else if (btnNormal === 'undo') {
                    html_rte += `
                        <button title="${util.out('Undo')}" class="rte-undo">
                            <svg class="is-icon-flex" style="margin-top:2px;width:15px;height:15px;">
                                <use xlink:href="#ion-ios-undo"></use>
                            </svg>
                        </button>
                    `;

                } else if (btnNormal === 'redo') {
                    html_rte += `
                        <button title="${util.out('Redo')}" class="rte-redo">
                            <svg class="is-icon-flex" style="margin-top:2px;width:15px;height:15px;">
                                <use xlink:href="#ion-ios-redo"></use>
                            </svg>
                        </button>
                    `;

                } else if (btnNormal === 'more' && html_rtemore !== '') {
                    html_rte += `
                        <button title="${util.out('More')}" class="rte-more">
                            <svg class="is-icon-flex" style="width:13px;height:13px;">
                                <use xlink:href="#ion-more"></use>
                            </svg>
                        </button>
                    `;

                } else if (btnNormal === '|') {
                    html_rte += '<div class="rte-separator"></div>';

                } else {
                    html_rte += `<button title="button not found" data-plugin="${btnNormal}">-</button>`; //temporary (later will be replaced with plugin button)
                }
            }

            // Snippet buttons
            if (this.builder.opts.toolbarAddSnippetButton &&
                html_rte.indexOf('rte-addsnippet') === -1 &&
                html_rtemore.indexOf('rte-addsnippet') === -1
            ) {
                html_rte = `
                    <button title="${util.out('Add Snippet')}" class="rte-addsnippet">
                        <svg class="is-icon-flex" style="width:18px; height:18px; margin-top:-1px;">
                            <use xlink:href="#ion-ios-plus-empty"></use>
                        </svg>
                    </button>
                ` + html_rte;
            }

            // More button
            if (html_rtemore !== '' && html_rte.indexOf('rte-more') === -1) {
                html_rte += `
                    <button title="${util.out('More')}" class="rte-more">
                        <svg class="is-icon-flex" style="width:13px;height:13px;">
                            <use xlink:href="#ion-more"></use>
                        </svg>
                    </button>
                `;
            }

            // Element Toolbar
            let html_elementrtemore = '';
            for (j = 0; j < builder.opts.elementButtonsMore.length; j++) {

                let btnToolbar = builder.opts.elementButtonsMore[j].toLowerCase();

                if (btnToolbar === 'gridtool') {
                    html_elementrtemore += `
                        <button title="${util.out('Grid Tool')}" class="rte-grideditor">
                            <svg class="is-icon-flex" style="margin-right:-3px;">
                                <use xlink:href="#ion-grid"></use>
                            </svg>
                        </button>
                    `;

                } else if (btnToolbar === 'html') {
                    html_elementrtemore += `
                        <button title="${util.out('HTML')}" class="rte-html">
                            <svg class="is-icon-flex" style="margin-right:-3px; width:14px; height:14px;">
                                <use xlink:href="#ion-ios-arrow-left"></use>
                            </svg>
                            <svg class="is-icon-flex" style="margin-left:-2px; fill:rgba(0, 0, 0, 0.65); width:14px; height:14px;">
                                <use xlink:href="#ion-ios-arrow-right"></use>
                            </svg>
                        </button>
                    `;

                } else if (btnToolbar === 'preferences') {
                    html_elementrtemore += `
                        <button title="${util.out('Preferences')}" class="rte-preferences">
                            <svg class="is-icon-flex" style="width:13px; height:13px;">
                                <use xlink:href="#ion-wrench"></use>
                            </svg>
                        </button>
                    `;

                } else if (btnToolbar === 'addsnippet') {
                    html_elementrtemore += `
                        <button title="${util.out('Add Snippet')}" class="rte-addsnippet">
                            <svg class="is-icon-flex" style="width:18px; height:18px; margin-top:-1px;">
                                <use xlink:href="#ion-ios-plus-empty"></use>
                            </svg>
                        </button>
                    `;

                } else if (btnToolbar === 'undo') {
                    html_elementrtemore += `
                        <button title="${util.out('Undo')}" class="rte-undo">
                            <svg class="is-icon-flex" style="margin-top:2px; width:15px; height:15px;">
                                <use xlink:href="#ion-ios-undo"></use>
                            </svg>
                        </button>
                    `;

                } else if (btnToolbar === 'redo') {
                    html_elementrtemore += `
                        <button title="${util.out('Redo')}" class="rte-redo">
                            <svg class="is-icon-flex" style="margin-top:2px;width:15px;height:15px;">
                                <use xlink:href="#ion-ios-redo"></use>
                            </svg>
                        </button>
                    `;

                } else if (btnToolbar === '|') {
                    html_elementrtemore += '<div class="rte-separator"></div>';

                } else {
                    html_elementrtemore += `<button title="button not found" data-plugin="${btnToolbar}">-</button>`; //temporary (later will be replaced with plugin button)
                }
            }

            // Html element
            let html_elementrte = '';
            for (j = 0; j < builder.opts.elementButtons.length; j++) {

                let btnHtml = builder.opts.elementButtons[j].toLowerCase();

                if (btnHtml === 'left') {
                    html_elementrte += `
                        <button title="${util.out('Align Left')}" data-align="left">
                            <svg class="is-icon-flex" style="width:14px;height:14px;">
                                <use xlink:href="#icon-align-left"></use>
                            </svg>
                        </button>
                    `;

                } else if (btnHtml === 'center') {
                    html_elementrte += `
                        <button title="${util.out('Align Center')}" data-align="center">
                            <svg class="is-icon-flex" style="width:14px;height:14px;">
                                <use xlink:href="#icon-align-center"></use>
                            </svg>
                        </button>
                    `;

                } else if (btnHtml === 'right') {
                    html_elementrte += `
                        <button title="${util.out('Align Right')}" data-align="right">
                            <svg class="is-icon-flex" style="width:14px;height:14px;">
                                <use xlink:href="#icon-align-right"></use>
                            </svg>
                        </button>
                    `;

                } else if (btnHtml === 'full') {
                    html_elementrte += `
                        <button title="${util.out('Align Full')}" data-align="justify">
                            <svg class="is-icon-flex" style="width:14px;height:14px;">
                                <use xlink:href="#icon-align-full"></use>
                            </svg>
                        </button>
                    `;

                } else if (btnHtml === 'gridtool') {
                    html_elementrte += `
                        <button title="${util.out('Grid Tool')}" class="rte-grideditor">
                            <svg class="is-icon-flex" style="margin-right:-3px;width:17px;height:17px;">
                                <use xlink:href="#ion-grid"></use>
                            </svg>
                        </button>
                    `;

                } else if (btnHtml === 'html') {
                    html_elementrte += `
                        <button title="${util.out('HTML')}" class="rte-html">
                            <svg class="is-icon-flex" style="margin-right:-3px;width:14px;height:14px;">
                                <use xlink:href="#ion-ios-arrow-left"></use></svg>
                            <svg class="is-icon-flex" style="margin-left:-2px;fill:rgba(0, 0, 0, 0.65);width:14px;height:14px;">
                                <use xlink:href="#ion-ios-arrow-right"></use>
                            </svg>
                        </button>
                    `;

                } else if (btnHtml === 'preferences') {
                    html_elementrte += `
                        <button title="${util.out('Preferences')}" class="rte-preferences">
                            <svg class="is-icon-flex" style="width:13px;height:13px;">
                                <use xlink:href="#ion-wrench"></use>
                            </svg>
                        </button>
                    `;

                } else if (btnHtml === 'addsnippet') {
                    html_elementrte += `
                        <button title="${util.out('Add Snippet')}" class="rte-addsnippet">
                            <svg class="is-icon-flex" style="width:18px;height:18px;margin-top:-1px;">
                                <use xlink:href="#ion-ios-plus-empty"></use>
                            </svg>
                        </button>
                    `;

                } else if (btnHtml === 'undo') {
                    html_elementrte += `
                        <button title="${util.out('Undo')}" class="rte-undo">
                            <svg class="is-icon-flex" style="margin-top:2px;width:15px;height:15px;">
                                <use xlink:href="#ion-ios-undo"></use>
                            </svg>
                        </button>
                    `;

                } else if (btnHtml === 'redo') {
                    html_elementrte += `
                        <button title="${util.out('Redo')}" class="rte-redo">
                            <svg class="is-icon-flex" style="margin-top:2px;width:15px;height:15px;">
                                <use xlink:href="#ion-ios-redo"></use>
                            </svg>
                        </button>
                    `;

                } else if (btnHtml === 'more' && html_elementrtemore !== '') {
                    html_elementrte += `
                        <button title="${util.out('More')}" class="rte-more">
                            <svg class="is-icon-flex" style="width:13px;height:13px;">
                                <use xlink:href="#ion-more"></use>
                            </svg>
                        </button>
                    `;

                } else if (btnHtml === '|') {
                    html_elementrte += '<div class="rte-separator"></div>';

                } else {
                    html_elementrte += `<button title="button not found" data-plugin="${btnHtml}">-</button>`; //temporary (later will be replaced with plugin button)
                }
            }

            // Snippet again
            if (this.builder.opts.toolbarAddSnippetButton &&
                html_elementrte.indexOf('rte-addsnippet') === -1 &&
                html_elementrtemore.indexOf('rte-addsnippet') === -1
            ) {
                html_elementrte = `
                    <button title="${util.out('Add Snippet')}" class="rte-addsnippet">
                        <svg class="is-icon-flex" style="width:18px;height:18px;margin-top:-1px;">
                            <use xlink:href="#ion-ios-plus-empty"></use>
                        </svg>
                    </button>
                ` + html_rte;
            }

            // More button again
            if (html_elementrtemore !== '' && html_elementrte.indexOf('rte-more') === -1) {
                html_elementrte += `
                    <button title="${util.out('More')}" class="rte-more">
                        <svg class="is-icon-flex" style="width:13px;height:13px;">
                            <use xlink:href="#ion-more"></use>
                        </svg>
                    </button>
                `;
            }

            // <div class="is-draggable" style="width: 5px;height: 45pxpx;background:#fff;cursor: move;"></div>
            // <div style="height:55px;background:#fff;border-top:#f5f5f5 1px solid;">
            // </div>

            // Html for the dropdowns
            let html = `
                <div class="is-rte-tool" style="position:fixed; flex-direction:column; display:none;">
                    <div style="display:flex">
                        ${html_rte}
                    </div>
                </div>

                <div class="is-elementrte-tool" style="position:fixed; flex-direction:column; display:none;">
                    <div style="display:flex">
                        ${html_elementrte}
                    </div>
                </div>

                <div class="rte-formatting-options is-rte-pop">
                    <div>
                        <button title="${util.out('Strikethrough')}" class="rte-format" data-command="strikethrough" style="float:left">
                            <svg class="is-icon-flex" style="width:17px;height:17px;">
                                <use xlink:href="#icon-strike"></use>
                            </svg>
                        </button>
                        <button title="${util.out('Superscript')}" class="rte-format" data-command="superscript" style="float:left">
                            <span style="font-family:serif;font-size:13px;">x</span><sup style="font-size:10px">2</sup>
                        </button>
                        <button title="${util.out('Subscript')}" class="rte-format" data-command="subscript" style="float:left">
                            <span style="font-family:serif;font-size:13px;">x</span><sub style="font-size:10px">2</sub>
                        </button>
                        <button title="${util.out('Uppercase')}" class="rte-format" data-command="uppercase" style="float:left">
                            <span style="font-family:serif;font-size:14px;display:inline-block;text-transform: none;">Aa</span>
                        </button>
                        <button title="${util.out('Clean')}" class="rte-format" data-command="clean">
                            <svg class="is-icon-flex" style="width:11px;height:11px;">
                                <use xlink:href="#icon-clean"></use>
                            </svg>
                        </button>
                    </div>
                </div>

                <div class="rte-align-options is-rte-pop">
                    <div>
                        <button title="${util.out('Align Left')}" data-align="left">
                            <svg class="is-icon-flex" style="width:14px;height:14px;">
                                <use xlink:href="#icon-align-left"></use>
                            </svg>
                        </button>
                        <button title="${util.out('Align Center')}" data-align="center">
                            <svg class="is-icon-flex" style="width:14px;height:14px;">
                                <use xlink:href="#icon-align-center"></use>
                            </svg>
                        </button>
                        <button title="${util.out('Align Right')}" data-align="right">
                            <svg class="is-icon-flex" style="width:14px;height:14px;">
                                <use xlink:href="#icon-align-right"></use>
                            </svg>
                        </button>
                        <button title="${util.out('Align Full')}" data-align="justify">
                            <svg class="is-icon-flex" style="width:14px;height:14px;">
                                <use xlink:href="#icon-align-full"></use>
                            </svg>
                        </button>
                    </div>
                </div>

                <div class="rte-list-options is-rte-pop">
                    <div>
                        <button title="${util.out('Bullets')}" data-action="insertUnorderedList">
                            <svg class="is-icon-flex" style="width:14px;height:14px;">
                                <use xlink:href="#icon-list-bullet"></use>
                            </svg>
                        </button>
                        <button title="${util.out('Numbering')}" data-action="insertOrderedList">
                            <svg class="is-icon-flex" style="width:14px;height:14px;">
                                <use xlink:href="#icon-list-number"></use>
                            </svg>
                        </button>
                        <button title="${util.out('Indent')}" data-action="indent">
                            <svg class="is-icon-flex" style="width:14px;height:14px;">
                                <use xlink:href="#icon-indent"></use>
                            </svg>
                        </button>
                        <button title="${util.out('Outdent')}" data-action="outdent">
                            <svg class="is-icon-flex" style="width:14px;height:14px;">
                                <use xlink:href="#icon-outdent"></use>
                            </svg>
                        </button>
                    </div>
                </div>

                <div class="rte-paragraph-options is-rte-pop">
                    <div>
                        <div title="${util.out('Heading 1')}" data-block="h1">
                            <h1>Heading 1</h1>
                        </div>
                        <div title="${util.out('Heading 2')}" data-block="h2">
                            <h2>Heading 2</h2>
                        </div>
                        <div title="${util.out('Heading 3')}" data-block="h3">
                            <h3>Heading 3</h3>
                        </div>
                        <div title="${util.out('Heading 4')}" data-block="h4">
                            <h4>Heading 4</h4>
                        </div>
                        <div title="${util.out('Paragraph')}" data-block="p">
                            <p>Paragraph</p>
                        </div>
                        <div title="${util.out('Preformatted')}" data-block="pre">
                            <p style="font-family:courier;">Preformatted</p>
                        </div>
                    </div>
                </div>

                <div class="rte-fontfamily-options is-rte-pop">
                    <iframe src="about:blank"></iframe>
                </div>

                <div class="rte-color-picker is-rte-pop" data-command="forecolor">
                    <div class="is-pop-tabs">
                        <div class="is-pop-tab-item active" data-value="forecolor">${util.out('Forecolor')}</div>
                        <div class="is-pop-tab-item" data-value="backcolor">${util.out('Backcolor')}</div>
                    </div>
                    <div class="rte-color-picker-area"></div>
                </div>
            
                <div class="rte-textsetting-options is-rte-pop">
                    <div>
                        <div data-value="display-1">
                            <span class=".display-1">Display 1</span>
                        </div>
                        <div data-value="display-2">
                            <span class=".display-2">Display 2</span>
                        </div>
                        <div data-value="display-3">
                            <span class=".display-3">Display 3</span>
                        </div>
                        <div data-value="display-4">
                            <span class=".display-4">Display 4</span>
                        </div>
                        <div data-value="h1">
                            <span class=".h1">H1</span>
                        </div>
                        <div data-value="h2">
                            <span class=".h2">H2</span>
                        </div>
                        <div data-value="h3">
                            <span class=".h3">H3</span>
                        </div>
                        <div data-value="h4">
                            <span class=".h4">H4</span>
                        </div>
                        <div data-value="h5">
                            <span class=".h5">H5</span>
                        </div>
                        <div data-value="h6">
                            <span class=".h6">H6</span>
                        </div>
                        <div data-value="lead">
                            <span class=".lead">Lead</span>
                        </div>
                        <div data-value="mark">
                            <span class=".mark">Mark</span>
                        </div>
                        <div data-value="small">
                            <span class=".small">Small</span>
                        </div>
                        <div data-value="">
                            <span>Remove Formatting</span>
                        </div>
                    </div>
                </div>

                <div class="is-modal insertimage">
                    <div style="max-width:560px;">
                        <div class="is-browse-area">
                            <div class="is-drop-area">
                                <input id="fileInsertImage" type="file" accept="image/*" />
                                <div class="drag-text">
                                    <p style="display:flex;justify-content:center;align-items:center;">
                                        <svg class="is-icon-flex" style="fill:rgba(0, 0, 0, 0.7);width:20px;height:20px;">
                                            <use xlink:href="#ion-camera"></use>
                                        </svg> 
                                        <span style="margin-left:5px;margin-top:3px;"> 
                                            ${util.out('Drag and drop an image or click to browse.')} 
                                        </span>
                                    </p>
                                </div>
                            </div>
                            <div class="is-preview-area">
                                <div>
                                    <img id="imgInsertImagePreview" alt="" />
                                    <i class="ion-ios-close-empty"></i>
                                </div>
                            </div>
                        </div>
                            
                        <p>${util.out('Or Specify Image Source')}:</p>
                        ${
                            ((this.builder.opts.onImageSelectClick + '').replace(/\s/g, '') !== 'function(){}' || this.builder.opts.imageselect !== '' ? `<div class="image-src clearfix" style="margin-bottom: 12px;"><input class="input-src" type="text" placeholder="${util.out('Source')}"><button title="${util.out('Select')}" class="input-select" style="flex:none;width:50px;height:50px;"><svg class="is-icon-flex"><use xlink:href="#ion-more"></use></svg></button></div>` : `<div class="image-src clearfix" style="margin-bottom: 12px;"><input class="input-src" type="text" placeholder="${util.out('Source')}"></div>`)
                        }
                        
                        <div style="text-align:right">
                            <button title="${util.out('Cancel')}" class="input-cancel classic-secondary">
                                ${util.out('Cancel')}
                            </button>
                            <button title="${util.out('Ok')}" class="input-ok classic-primary">
                                ${util.out('Ok')}
                            </button>
                        </div>
                    </div>
                </div>

                <div class="rte-icon-options is-rte-pop">
                    <iframe id="ifrIconInsert" src="about:blank"></iframe>
                </div>

                <div class="rte-customtag-options is-rte-pop">
                    <div>${customTagsHtml}</div>
                </div>

                <div class="rte-more-options is-rte-pop">
                    <div>
                        ${html_rtemore}
                    </div>
                </div>

                <div class="elementrte-more-options is-rte-pop">
                    <div>
                        ${html_elementrtemore}
                    </div>
                </div>
            `;

            dom.appendHtml(builderStuff, html);
            rteTool               = builderStuff.querySelector('.is-rte-tool');
            elementRteTool        = builderStuff.querySelector('.is-elementrte-tool');
            rteMoreOptions        = builderStuff.querySelector('.rte-more-options');
            elementRteMoreOptions = builderStuff.querySelector('.elementrte-more-options');

            rteAlignOptions       = builderStuff.querySelector('.rte-align-options');
            rteFormattingOptions  = builderStuff.querySelector('.rte-formatting-options');
            rteColorPicker        = builderStuff.querySelector('.rte-color-picker');
            rteListOptions        = builderStuff.querySelector('.rte-list-options');
            rteFontFamilyOptions  = builderStuff.querySelector('.rte-fontfamily-options');
            rteParagraphOptions   = builderStuff.querySelector('.rte-paragraph-options');
            rteTextSettingOptions = builderStuff.querySelector('.rte-textsetting-options');
            rteIconOptions        = builderStuff.querySelector('.rte-icon-options');
            rteCustomTagOptions   = builderStuff.querySelector('.rte-customtag-options');

            // Prepare for tooltip
            let elms = rteTool.querySelectorAll('[title]');
            Array.prototype.forEach.call(elms, (elm) => {
                elm.setAttribute('data-title', elm.getAttribute('title'));
            });

            elms = elementRteTool.querySelectorAll('[title]');
            Array.prototype.forEach.call(elms, (elm) => {
                elm.setAttribute('data-title', elm.getAttribute('title'));
            });

            elms = rteAlignOptions.querySelectorAll('[title]');
            Array.prototype.forEach.call(elms, (elm) => {
                elm.setAttribute('data-title', elm.getAttribute('title'));
            });

            elms = rteFormattingOptions.querySelectorAll('[title]');
            Array.prototype.forEach.call(elms, (elm) => {
                elm.setAttribute('data-title', elm.getAttribute('title'));
            });

            elms = rteListOptions.querySelectorAll('[title]');
            Array.prototype.forEach.call(elms, (elm) => {
                elm.setAttribute('data-title', elm.getAttribute('title'));
            });

            elms = rteMoreOptions.querySelectorAll('[title]');
            Array.prototype.forEach.call(elms, (elm) => {
                elm.setAttribute('data-title', elm.getAttribute('title'));
            });

            elms = elementRteMoreOptions.querySelectorAll('[title]');
            Array.prototype.forEach.call(elms, (elm) => {
                elm.setAttribute('data-title', elm.getAttribute('title'));
            });

            if (this.builder.isTouchSupport) {
                // On iPad, on double click text to select word, getSelected() won't return the word, instead it returns empty
                // So this is needed to call getSelected() after 'selectionchange' that is triggered after double click a text.
                document.addEventListener('selectionchange', function () {
                    if (dom.checkEditable()) {
                        var text = dom.getSelected();
                        if (text.trim() !== '') {
                            //save selection
                            util.saveSelection();
                        }
                    }
                }, false);
            }
        }

        this.rteTool               = rteTool;
        this.elementRteTool        = elementRteTool;
        this.rteAlignOptions       = rteAlignOptions;
        this.rteFormattingOptions  = rteFormattingOptions;
        this.rteColorPicker        = rteColorPicker;
        this.rteListOptions        = rteListOptions;
        this.rteFontFamilyOptions  = rteFontFamilyOptions;
        this.rteParagraphOptions   = rteParagraphOptions;
        this.rteMoreOptions        = rteMoreOptions;
        this.elementRteMoreOptions = elementRteMoreOptions;
        this.rteTextSettingOptions = rteTextSettingOptions;
        this.rteIconOptions        = rteIconOptions;
        this.rteCustomTagOptions   = rteCustomTagOptions;

        this.positionToolbar();

        // Formatting
        let btnRteFormatting = this.rteTool.querySelector('button.rte-formatting');
        btnRteFormatting     = btnRteFormatting ? btnRteFormatting : this.rteMoreOptions.querySelector('button.rte-formatting');
        if (btnRteFormatting) {
            dom.addEventListener(btnRteFormatting, 'click', () => {

                const pop         = this.rteFormattingOptions;
                const top         = btnRteFormatting.getBoundingClientRect().top; // + window.pageYOffset;
                const left        = btnRteFormatting.getBoundingClientRect().left; // + window.pageXOffset;
                pop.style.display = 'flex';
                const w           = pop.offsetWidth; //to get value, element must not hidden (display:none). So set display:flex before this.
                const h           = pop.offsetHeight;

                if (!dom.hasClass(pop, 'active')) {
                    if (this.builder.opts.toolbar === 'left') {
                        pop.style.top   = (top - (h / 2) + 20) + 'px';
                        pop.style.left  = (left + 54) + 'px';
                        pop.style.right = 'auto';

                    } else if (this.builder.opts.toolbar === 'right') {
                        pop.style.top       = (top - (h / 2) + 20) + 'px';
                        pop.style.left      = 'auto';
                        const viewportWidth = window.innerWidth;
                        pop.style.right     = (viewportWidth - left + 9) + 'px';

                    } else {
                        pop.style.top   = (top + 54 - 6) + 'px';
                        pop.style.left  = (left - (w / 2) + 23) + 'px';
                        pop.style.right = 'auto';
                    }

                    dom.removeClass(pop, 'deactive');
                    dom.addClass(pop, 'active');

                } else {
                    dom.removeClass(pop, 'active');
                    dom.addClass(pop, 'deactive');
                }

            });
        }

        // Align
        let btnRteAlign = this.rteTool.querySelector('button.rte-align');
        btnRteAlign     = btnRteAlign ? btnRteAlign : this.rteMoreOptions.querySelector('button.rte-align');
        if (btnRteAlign) {
            dom.addEventListener(btnRteAlign, 'click', () => {

                const pop         = this.rteAlignOptions;
                const top         = btnRteAlign.getBoundingClientRect().top; // + window.pageYOffset;
                const left        = btnRteAlign.getBoundingClientRect().left; // + window.pageXOffset;
                pop.style.display = 'flex';
                const w           = pop.offsetWidth; //to get value, element must not hidden (display:none). So set display:flex before this.
                const h           = pop.offsetHeight;

                if (!dom.hasClass(pop, 'active')) {
                    if (this.builder.opts.toolbar === 'left') {
                        pop.style.top   = (top - (h / 2) + 20) + 'px';
                        pop.style.left  = (left + 54) + 'px';
                        pop.style.right = 'auto';

                    } else if (this.builder.opts.toolbar === 'right') {
                        pop.style.top       = (top - (h / 2) + 20) + 'px';
                        pop.style.left      = 'auto';
                        const viewportWidth = window.innerWidth;
                        pop.style.right     = (viewportWidth - left + 9) + 'px';

                    } else {
                        pop.style.top   = (top + 54 - 6) + 'px';
                        pop.style.left  = (left - (w / 2) + 23) + 'px';
                        pop.style.right = 'auto';
                    }

                    dom.removeClass(pop, 'deactive');
                    dom.addClass(pop, 'active');

                } else {
                    dom.removeClass(pop, 'active');
                    dom.addClass(pop, 'deactive');
                }

            });
        }

        // List
        let btnRteList = this.rteTool.querySelector('button.rte-list');
        btnRteList     = btnRteList ? btnRteList : this.rteMoreOptions.querySelector('button.rte-list');
        if (btnRteList) {
            dom.addEventListener(btnRteList, 'click', () => {

                const pop         = this.rteListOptions;
                const top         = btnRteList.getBoundingClientRect().top; // + window.pageYOffset;
                const left        = btnRteList.getBoundingClientRect().left; // + window.pageXOffset;
                pop.style.display = 'flex';
                const w           = pop.offsetWidth; //to get value, element must not hidden (display:none). So set display:flex before this.
                const h           = pop.offsetHeight;

                if (!dom.hasClass(pop, 'active')) {
                    if (this.builder.opts.toolbar === 'left') {
                        pop.style.top   = (top - (h / 2) + 20) + 'px';
                        pop.style.left  = (left + 54) + 'px';
                        pop.style.right = 'auto';

                    } else if (this.builder.opts.toolbar === 'right') {
                        pop.style.top       = (top - (h / 2) + 20) + 'px';
                        pop.style.left      = 'auto';
                        const viewportWidth = window.innerWidth;
                        pop.style.right     = (viewportWidth - left + 9) + 'px';

                    } else {
                        pop.style.top   = (top + 54 - 6) + 'px';
                        pop.style.left  = (left - (w / 2) + 23) + 'px';
                        pop.style.right = 'auto';
                    }

                    dom.removeClass(pop, 'deactive');
                    dom.addClass(pop, 'active');

                } else {
                    dom.removeClass(pop, 'active');
                    dom.addClass(pop, 'deactive');
                }

            });
        }

        // Custom Tags
        let btnRteTags = this.rteTool.querySelector('button.rte-tags');
        btnRteTags     = btnRteTags ? btnRteTags : this.rteMoreOptions.querySelector('button.rte-tags');
        if (btnRteTags) {
            dom.addEventListener(btnRteTags, 'click', () => {

                const pop         = this.rteCustomTagOptions;
                const top         = btnRteTags.getBoundingClientRect().top; // + window.pageYOffset;
                const left        = btnRteTags.getBoundingClientRect().left; // + window.pageXOffset;
                pop.style.display = 'flex';
                const w           = pop.offsetWidth; //to get value, element must not hidden (display:none). So set display:flex before this.
                const h           = pop.offsetHeight;

                if (!dom.hasClass(pop, 'active')) {
                    if (this.builder.opts.toolbar === 'left') {
                        pop.style.top   = (top - (h / 2) + 20) + 'px';
                        pop.style.left  = (left + 54) + 'px';
                        pop.style.right = 'auto';

                    } else if (this.builder.opts.toolbar === 'right') {
                        pop.style.top       = (top - (h / 2) + 20) + 'px';
                        pop.style.left      = 'auto';
                        const viewportWidth = window.innerWidth;
                        pop.style.right     = (viewportWidth - left + 9) + 'px';

                    } else {
                        pop.style.top   = (top + 54 - 6) + 'px';
                        pop.style.left  = (left - (w / 2) + 23) + 'px';
                        pop.style.right = 'auto';
                    }

                    if (dom.parentsHasClass(btnRteTags, 'rte-more-options')) {

                        // Adjustment if button is placed on 2nd bar (div.rte-more-options)
                        if (this.builder.opts.toolbar === 'left') {
                            pop.style.top   = (parseInt(this.rteMoreOptions.style.top) + this.rteMoreOptions.offsetHeight - h) + 'px';
                            pop.style.left  = (left + 54) + 'px';
                            pop.style.right = 'auto';

                        } else if (this.builder.opts.toolbar === 'right') {
                            pop.style.top       = (parseInt(this.rteMoreOptions.style.top) + this.rteMoreOptions.offsetHeight - h) + 'px';
                            pop.style.left      = 'auto';
                            const viewportWidth = window.innerWidth;
                            pop.style.right     = (viewportWidth - left + 9) + 'px';

                        } else {
                            pop.style.top = (top + 54 - 6) + 'px';

                            if (btnRteTags.getBoundingClientRect().left + 45 - parseInt(this.rteMoreOptions.style.left) < pop.offsetWidth) {
                                pop.style.left = (parseInt(this.rteMoreOptions.style.left)) + 'px';

                            } else if ((parseInt(this.rteMoreOptions.style.left) + this.rteMoreOptions.offsetWidth - btnRteTags.getBoundingClientRect().left + 45) < pop.offsetWidth) {
                                pop.style.left = (parseInt(this.rteMoreOptions.style.left) + this.rteMoreOptions.offsetWidth - w) + 'px';
                            }

                            pop.style.right = 'auto';
                        }
                    }

                    dom.removeClass(pop, 'deactive');
                    dom.addClass(pop, 'active');

                } else {
                    dom.removeClass(pop, 'active');
                    dom.addClass(pop, 'deactive');
                }

            });
        }

        // Paragraph
        let btnRteParagraph = this.rteTool.querySelector('button.rte-paragraph');
        btnRteParagraph     = btnRteParagraph ? btnRteParagraph : this.rteMoreOptions.querySelector('button.rte-paragraph');
        if (btnRteParagraph) {
            dom.addEventListener(btnRteParagraph, 'click', () => {

                const pop         = this.rteParagraphOptions;
                const top         = btnRteParagraph.getBoundingClientRect().top; // + window.pageYOffset;
                const left        = btnRteParagraph.getBoundingClientRect().left; // + window.pageXOffset;
                pop.style.display = 'flex';
                const w           = pop.offsetWidth; //to get value, element must not hidden (display:none). So set display:flex before this.
                const h           = pop.offsetHeight;

                if (!dom.hasClass(pop, 'active')) {
                    if (this.builder.opts.toolbar === 'left') {
                        pop.style.top   = (top - (h / 2) + 20) + 'px';
                        pop.style.left  = (left + 54) + 'px';
                        pop.style.right = 'auto';

                    } else if (this.builder.opts.toolbar === 'right') {
                        pop.style.top       = (top - (h / 2) + 20) + 'px';
                        pop.style.left      = 'auto';
                        const viewportWidth = window.innerWidth;
                        pop.style.right     = (viewportWidth - left + 9) + 'px';

                    } else {
                        pop.style.top   = (top + 54 - 6) + 'px';
                        pop.style.left  = (left - (w / 2) + 23) + 'px';
                        pop.style.right = 'auto';
                    }

                    if (dom.parentsHasClass(btnRteParagraph, 'rte-more-options')) {
                        // Adjustment if button is placed on 2nd bar (div.rte-more-options)
                        if (this.builder.opts.toolbar === 'left') {
                            pop.style.top   = (parseInt(this.rteMoreOptions.style.top) + this.rteMoreOptions.offsetHeight - h) + 'px';
                            pop.style.left  = (left + 54) + 'px';
                            pop.style.right = 'auto';

                        } else if (this.builder.opts.toolbar === 'right') {
                            pop.style.top       = (parseInt(this.rteMoreOptions.style.top) + this.rteMoreOptions.offsetHeight - h) + 'px';
                            pop.style.left      = 'auto';
                            const viewportWidth = window.innerWidth;
                            pop.style.right     = (viewportWidth - left + 9) + 'px';

                        } else {
                            pop.style.top   = (top + 54 - 6) + 'px';
                            pop.style.left  = (parseInt(this.rteMoreOptions.style.left) + this.rteMoreOptions.offsetWidth - w) + 'px';
                            pop.style.right = 'auto';
                        }
                    }

                    dom.removeClass(pop, 'deactive');
                    dom.addClass(pop, 'active');

                } else {
                    dom.removeClass(pop, 'active');
                    dom.addClass(pop, 'deactive');
                }

                this.getState();

            });
        }

        // Font Family
        let iframe = rteFontFamilyOptions.querySelector('iframe');
        if (iframe.src === 'about:blank') {
            iframe.src = this.builder.opts.fontSelect;
        }
        let btnRteFontFamily = this.rteTool.querySelector('button.rte-fontfamily');
        btnRteFontFamily     = btnRteFontFamily ? btnRteFontFamily : this.rteMoreOptions.querySelector('button.rte-fontfamily');
        if (btnRteFontFamily) {
            dom.addEventListener(btnRteFontFamily, 'click', () => {

                const pop         = this.rteFontFamilyOptions;
                const top         = btnRteFontFamily.getBoundingClientRect().top; // + window.pageYOffset;
                const left        = btnRteFontFamily.getBoundingClientRect().left; // + window.pageXOffset;
                pop.style.display = 'flex';
                const w           = pop.offsetWidth; //to get value, element must not hidden (display:none). So set display:flex before this.
                const h           = pop.offsetHeight;

                if (!dom.hasClass(pop, 'active')) {

                    if (this.builder.opts.toolbar === 'left') {
                        pop.style.top   = (top - (h / 2) + 20) + 'px';
                        pop.style.left  = (left + 54) + 'px';
                        pop.style.right = 'auto';

                    } else if (this.builder.opts.toolbar === 'right') {
                        pop.style.top       = (top - (h / 2) + 20) + 'px';
                        pop.style.left      = 'auto';
                        const viewportWidth = window.innerWidth;
                        pop.style.right     = (viewportWidth - left + 9) + 'px';

                    } else {
                        pop.style.top   = (top + 54 - 6) + 'px';
                        pop.style.left  = (left - (w / 2) + 23) + 'px';
                        pop.style.right = 'auto';
                    }

                    if (dom.parentsHasClass(btnRteFontFamily, 'rte-more-options')) {
                        // Adjustment if button is placed on 2nd bar (div.rte-more-options)
                        if (this.builder.opts.toolbar === 'left') {
                            pop.style.top   = (parseInt(this.rteMoreOptions.style.top) + this.rteMoreOptions.offsetHeight - h) + 'px';
                            pop.style.left  = (left + 54) + 'px';
                            pop.style.right = 'auto';

                        } else if (this.builder.opts.toolbar === 'right') {
                            pop.style.top       = (parseInt(this.rteMoreOptions.style.top) + this.rteMoreOptions.offsetHeight - h) + 'px';
                            pop.style.left      = 'auto';
                            const viewportWidth = window.innerWidth;
                            pop.style.right     = (viewportWidth - left + 9) + 'px';

                        } else {
                            pop.style.top   = (top + 54 - 6) + 'px';
                            pop.style.left  = (parseInt(this.rteMoreOptions.style.left) + this.rteMoreOptions.offsetWidth - w) + 'px';
                            pop.style.right = 'auto';
                        }
                    }

                    dom.removeClass(pop, 'deactive');
                    dom.addClass(pop, 'active');

                } else {
                    dom.removeClass(pop, 'active');
                    dom.addClass(pop, 'deactive');
                }

                this.getState();

                let iframe = pop.querySelector('iframe');
                let area   = iframe.contentWindow.document.querySelector('#divFontList');
                var target = area.querySelector('.on');
                if (target) {
                    area.scrollTop = area.scrollTop + target.getBoundingClientRect().top;
                }

            });
        }

        // Icons
        iframe = rteIconOptions.querySelector('iframe');
        if (iframe.src === 'about:blank') {
            iframe.src = this.builder.opts.iconSelect;
        }

        let btnRteIcons = this.rteTool.querySelector('button.rte-icon');
        btnRteIcons     = btnRteIcons ? btnRteIcons : this.rteMoreOptions.querySelector('button.rte-icon');
        if (btnRteIcons) {
            dom.addEventListener(btnRteIcons, 'click', () => {

                const pop         = this.rteIconOptions;
                const top         = btnRteIcons.getBoundingClientRect().top; // + window.pageYOffset;
                const left        = btnRteIcons.getBoundingClientRect().left; // + window.pageXOffset;
                pop.style.display = 'flex';
                const w           = pop.offsetWidth; //to get value, element must not hidden (display:none). So set display:flex before this.
                const h           = pop.offsetHeight;

                if (!dom.hasClass(pop, 'active')) {

                    if (this.builder.opts.toolbar === 'left') {
                        pop.style.top   = (top - (h / 2) + 20) + 'px';
                        pop.style.left  = (left + 54) + 'px';
                        pop.style.right = 'auto';

                    } else if (this.builder.opts.toolbar === 'right') {
                        pop.style.top       = (top - (h / 2) + 20) + 'px';
                        pop.style.left      = 'auto';
                        const viewportWidth = window.innerWidth;
                        pop.style.right     = (viewportWidth - left + 9) + 'px';

                    } else {
                        pop.style.top   = (top + 54 - 6) + 'px';
                        pop.style.left  = (left - (w / 2) + 23) + 'px';
                        pop.style.right = 'auto';
                    }

                    if (dom.parentsHasClass(btnRteIcons, 'rte-more-options')) {
                        // Adjustment if button is placed on 2nd bar (div.rte-more-options)
                        if (this.builder.opts.toolbar === 'left') {
                            pop.style.top   = (parseInt(this.rteMoreOptions.style.top) + this.rteMoreOptions.offsetHeight - h) + 'px';
                            pop.style.left  = (left + 54) + 'px';
                            pop.style.right = 'auto';

                        } else if (this.builder.opts.toolbar === 'right') {
                            pop.style.top       = (parseInt(this.rteMoreOptions.style.top) + this.rteMoreOptions.offsetHeight - h) + 'px';
                            pop.style.left      = 'auto';
                            const viewportWidth = window.innerWidth;
                            pop.style.right     = (viewportWidth - left + 9) + 'px';

                        } else {
                            pop.style.top = (top + 54 - 6) + 'px';

                            if (btnRteIcons.getBoundingClientRect().left + 45 - parseInt(this.rteMoreOptions.style.left) < pop.offsetWidth) {
                                pop.style.left = (parseInt(this.rteMoreOptions.style.left)) + 'px';
                            } else if ((parseInt(this.rteMoreOptions.style.left) + this.rteMoreOptions.offsetWidth - btnRteIcons.getBoundingClientRect().left + 45) < pop.offsetWidth) {
                                pop.style.left = (parseInt(this.rteMoreOptions.style.left) + this.rteMoreOptions.offsetWidth - w) + 'px';
                            }

                            pop.style.right = 'auto';
                        }
                    }

                    dom.removeClass(pop, 'deactive');
                    dom.addClass(pop, 'active');

                } else {
                    dom.removeClass(pop, 'active');
                    dom.addClass(pop, 'deactive');
                }

            });
        }

        // Color
        let btnRteColor = this.rteTool.querySelector('button.rte-color');
        btnRteColor     = btnRteColor ? btnRteColor : this.rteMoreOptions.querySelector('button.rte-color');
        if (btnRteColor) {
            dom.addEventListener(btnRteColor, 'click', () => {

                const pop         = this.rteColorPicker;
                const top         = btnRteColor.getBoundingClientRect().top; // + window.pageYOffset;
                const left        = btnRteColor.getBoundingClientRect().left; // + window.pageXOffset;
                pop.style.display = 'flex';
                const w           = pop.offsetWidth; //to get value, element must not hidden (display:none). So set display:flex before this.
                // const h = pop.offsetHeight;

                if (!dom.hasClass(pop, 'active')) {

                    this.builder.uo.saveForUndo(true); // checkLater = true

                    if (this.builder.opts.toolbar === 'left') {
                        pop.style.top   = this.rteTool.style.top; //(top - (h/2) + 20) + 'px';
                        pop.style.left  = (left + 54) + 'px';
                        pop.style.right = 'auto';

                    } else if (this.builder.opts.toolbar === 'right') {
                        pop.style.top       = this.rteTool.style.top; //(top - (h/2) + 20) + 'px';
                        pop.style.left      = 'auto';
                        const viewportWidth = window.innerWidth;
                        pop.style.right     = (viewportWidth - left + 9) + 'px';

                    } else {
                        pop.style.top   = (top + 54 - 6) + 'px';
                        pop.style.left  = (left - (w / 2) + 23) + 'px';
                        pop.style.right = 'auto';
                    }

                    dom.removeClass(pop, 'deactive');
                    dom.addClass(pop, 'active');

                } else {
                    dom.removeClass(pop, 'active');
                    dom.addClass(pop, 'deactive');
                }

            });
        }

        // Preferences
        let btnRtePreferences = this.rteTool.querySelector('button.rte-preferences');
        btnRtePreferences     = btnRtePreferences ? btnRtePreferences : this.rteMoreOptions.querySelector('button.rte-preferences');
        if (btnRtePreferences) {
            dom.addEventListener(btnRtePreferences, 'click', () => {
                this.builder.viewPreferences();
            });
        }

        btnRtePreferences = this.elementRteTool.querySelector('button.rte-preferences');
        btnRtePreferences = btnRtePreferences ? btnRtePreferences : this.elementRteMoreOptions.querySelector('button.rte-preferences');
        if (btnRtePreferences) {
            dom.addEventListener(btnRtePreferences, 'click', () => {
                this.builder.viewPreferences();
            });
        }

        // View HTML
        let btnRteHtml = this.rteTool.querySelector('button.rte-html');
        btnRteHtml     = btnRteHtml ? btnRteHtml : this.rteMoreOptions.querySelector('button.rte-html');
        if (btnRteHtml) {
            dom.addEventListener(btnRteHtml, 'click', () => {
                this.builder.viewHtml();
            });
        }

        btnRteHtml = this.elementRteTool.querySelector('button.rte-html');
        btnRteHtml = btnRteHtml ? btnRteHtml : this.elementRteMoreOptions.querySelector('button.rte-html');
        if (btnRteHtml) {
            dom.addEventListener(btnRteHtml, 'click', () => {
                this.builder.viewHtml();
            });
        }

        // Grid Editor
        let btnRteGridEditor = this.rteTool.querySelector('button.rte-grideditor');
        btnRteGridEditor     = btnRteGridEditor ? btnRteGridEditor : this.rteMoreOptions.querySelector('button.rte-grideditor');
        if (btnRteGridEditor) {
            dom.addEventListener(btnRteGridEditor, 'click', () => {

                // direct
                const grideditor = this.builderStuff.querySelector('.grideditor');
                dom.addClass(grideditor, 'active');

                const builders = document.querySelectorAll(this.builder.opts.container);
                Array.prototype.forEach.call(builders, (builder) => {
                    builder.setAttribute('grideditor', '');
                });

            });
        }

        btnRteGridEditor = this.elementRteTool.querySelector('button.rte-grideditor');
        btnRteGridEditor = btnRteGridEditor ? btnRteGridEditor : this.elementRteMoreOptions.querySelector('button.rte-grideditor');
        if (btnRteGridEditor) {
            dom.addEventListener(btnRteGridEditor, 'click', () => {

                // direct
                const grideditor = this.builderStuff.querySelector('.grideditor');
                dom.addClass(grideditor, 'active');

                const builders = document.querySelectorAll(this.builder.opts.container);
                Array.prototype.forEach.call(builders, (builder) => {
                    builder.setAttribute('grideditor', '');
                });

            });
        }

        // Undo
        let btnRteUndo = this.rteTool.querySelector('button.rte-undo');
        btnRteUndo     = btnRteUndo ? btnRteUndo : this.rteMoreOptions.querySelector('button.rte-undo');
        if (btnRteUndo) {
            dom.addEventListener(btnRteUndo, 'click', () => {
                this.builder.uo.doUndo();
            });
        }

        btnRteUndo = this.elementRteTool.querySelector('button.rte-undo');
        btnRteUndo = btnRteUndo ? btnRteUndo : this.elementRteMoreOptions.querySelector('button.rte-undo');
        if (btnRteUndo) {
            dom.addEventListener(btnRteUndo, 'click', () => {
                this.builder.uo.doUndo();
            });
        }

        // Redo
        let btnRteRedo = this.rteTool.querySelector('button.rte-redo');
        btnRteRedo     = btnRteRedo ? btnRteRedo : this.rteMoreOptions.querySelector('button.rte-redo');
        if (btnRteRedo) {
            dom.addEventListener(btnRteRedo, 'click', () => {
                this.builder.uo.doRedo();
            });
        }

        btnRteRedo = this.elementRteTool.querySelector('button.rte-redo');
        btnRteRedo = btnRteRedo ? btnRteRedo : this.elementRteMoreOptions.querySelector('button.rte-redo');
        if (btnRteRedo) {
            dom.addEventListener(btnRteRedo, 'click', () => {
                this.builder.uo.doRedo();
            });
        }

        // Add Snippet
        let btnRteAddSnippet = this.rteTool.querySelector('button.rte-addsnippet');
        if (btnRteAddSnippet) {
            dom.addEventListener(btnRteAddSnippet, 'click', () => {

                this.viewSnippets();

            });
        }

        btnRteAddSnippet = this.elementRteTool.querySelector('button.rte-addsnippet');
        if (btnRteAddSnippet) {
            dom.addEventListener(btnRteAddSnippet, 'click', () => {

                this.viewSnippets();

            });
        }

        // Link
        let btnRteLink = this.rteTool.querySelector('button.rte-link');
        btnRteLink     = btnRteLink ? btnRteLink : this.rteMoreOptions.querySelector('button.rte-link');
        if (btnRteLink) {
            dom.addEventListener(btnRteLink, 'click', () => {
                const util = new Util(this.builder);
                util.clearActiveCell();
                this.hyperlink.createLink();
            });
        }

        // Image
        let btnRteImage = this.rteTool.querySelector('button.rte-image');
        btnRteImage     = btnRteImage ? btnRteImage : this.rteMoreOptions.querySelector('button.rte-image');
        if (btnRteImage) {
            dom.addEventListener(btnRteImage, 'click', () => {

                const modal = this.builderStuff.querySelector('.insertimage');
                util.showModal(modal, true, function () {
                    //if(!this.builder.isTouchSupport) util.restoreSelection();
                }, false);

                //Clear previous
                modal.querySelector('#fileInsertImage').value         = ''; // clear
                modal.querySelector('.is-preview-area').style.display = 'none';
                modal.querySelector('.is-drop-area').style.display    = 'block';
                dom.removeClass(modal.querySelector('.is-drop-area'), 'image-dropping');

                //Clear image source input
                modal.querySelector('.input-src').value = '';

            });
        }

        const modalInsertImage = this.builderStuff.querySelector('.insertimage');
        const fileInsertImage  = modalInsertImage.querySelector('#fileInsertImage');
        dom.addEventListener(fileInsertImage, 'change', (e) => {

            var input = e.target;

            if (input.files && input.files[0]) {

                var reader = new FileReader();

                reader.onload = function (e) {
                    modalInsertImage.querySelector('.is-drop-area').style.display = 'none';

                    modalInsertImage.querySelector('#imgInsertImagePreview').src     = e.target.result;
                    modalInsertImage.querySelector('.is-preview-area').style.display = 'block';
                    let fileToInsert                                                 = input.files[0].name;
                    modalInsertImage.querySelector('#imgInsertImagePreview').setAttribute('data-filename', fileToInsert);

                    //modalInsertImage.querySelector('.image-title').innerHTML = input.files[0].name;
                };

                reader.readAsDataURL(input.files[0]);

                modalInsertImage.querySelector('.input-src').value = ''; //Clear manually specified image soure

            }

        });

        const btnInsertImageOk = modalInsertImage.querySelector('.input-ok');
        dom.addEventListener(btnInsertImageOk, 'click', () => {

            if (!this.builder.activeCol) {
                util.hideModal(modalInsertImage);
                return;
            }

            this.builder.uo.saveForUndo();

            util.restoreSelection(); //a must

            let val = '';
            if (modalInsertImage.querySelector('.is-drop-area').style.display === 'none') {
                val = modalInsertImage.querySelector('#imgInsertImagePreview').src;
            } else {
                val = modalInsertImage.querySelector('.input-src').value;
            }

            if (val === '') {
                return;
            }
            let fileToInsert = modalInsertImage.querySelector('#imgInsertImagePreview').getAttribute('data-filename');
            util.pasteHtmlAtCaret('<img data-filename="' + fileToInsert + '" src="' + val + '" alt="" />', false);

            util.hideModal(modalInsertImage);

            this.builder.applyBehavior();

            //save selection
            util.saveSelection();

            //Trigger Change event
            this.builder.opts.onChange();

            //Trigger Render event
            this.builder.opts.onRender();

        });

        const btnInsertImageCancel = modalInsertImage.querySelector('.input-cancel');
        dom.addEventListener(btnInsertImageCancel, 'click', () => {

            util.hideModal(modalInsertImage);

        });

        const dropArea = modalInsertImage.querySelector('.is-drop-area');
        dom.addEventListener(dropArea, 'dragover', () => {
            dom.addClass(dropArea, 'image-dropping');
        });
        dom.addEventListener(dropArea, 'dragleave', () => {
            dom.removeClass(dropArea, 'image-dropping');
        });

        const delImageInsert = modalInsertImage.querySelector('.is-preview-area i');
        dom.addEventListener(delImageInsert, 'click', () => {

            //Clear drop image area
            modalInsertImage.querySelector('#fileInsertImage').value         = ''; // clear
            modalInsertImage.querySelector('.is-preview-area').style.display = 'none';
            dropArea.style.display                                           = 'block';
            dom.removeClass(dropArea, 'image-dropping');

        });

        const inputImageInsertSrc = modalInsertImage.querySelector('.input-src');
        dom.addEventListener(inputImageInsertSrc, 'keyup', () => {

            //Clear drop image area
            modalInsertImage.querySelector('#fileInsertImage').value         = ''; // clear
            modalInsertImage.querySelector('.is-preview-area').style.display = 'none';
            dropArea.style.display                                           = 'block';
            dom.removeClass(dropArea, 'image-dropping');

        });

        if (!this.builder.opts.onImageSelectClick && this.builder.opts.imageselect === '') {
            modalInsertImage.querySelector('.input-select').style.display = 'none';
        }

        if (this.builder.opts.onImageSelectClick || this.builder.opts.imageselect !== '') {

            dom.addClass(modalInsertImage.querySelector('.image-src'), 'image-select');

            //Open Custom Image Select
            const inputImageSelect = modalInsertImage.querySelector('.input-select');
            if (inputImageSelect) {
                dom.addEventListener(inputImageSelect, 'click', () => {

                    if (this.builder.opts.onImageSelectClick) {

                        this.builder.opts.onImageSelectClick({
                            targetInput : modalInsertImage.querySelector('.input-src'),
                            theTrigger  : inputImageSelect
                        });

                    } else {

                        let modalImageSelect = this.builderStuff.querySelector('.is-modal.imageselect');
                        let iframe           = modalImageSelect.querySelector('iframe');
                        if (iframe.src === 'about:blank') {
                            iframe.src = this.builder.opts.imageselect;
                        }
                        util.showModal(modalImageSelect);

                    }

                });
            }

        } else {
            dom.removeClass(inputImageInsertSrc, 'image-select');
        }


        // Text Settings
        let btnRteTextSettings = this.rteTool.querySelector('button.rte-textsettings');
        btnRteTextSettings     = btnRteTextSettings ? btnRteTextSettings : this.rteMoreOptions.querySelector('button.rte-textsettings');
        if (btnRteTextSettings) {
            dom.addEventListener(btnRteTextSettings, 'click', () => {

                const pop         = this.rteTextSettingOptions;
                const top         = btnRteTextSettings.getBoundingClientRect().top; // + window.pageYOffset;
                const left        = btnRteTextSettings.getBoundingClientRect().left; // + window.pageXOffset;
                pop.style.display = 'flex';
                const w           = pop.offsetWidth; //to get value, element must not hidden (display:none). So set display:flex before this.
                const h           = pop.offsetHeight;

                if (!dom.hasClass(pop, 'active')) {

                    if (this.builder.opts.toolbar === 'left') {
                        pop.style.top   = (top - (h / 2) + 20) + 'px';
                        pop.style.left  = (left + 54) + 'px';
                        pop.style.right = 'auto';
                    } else if (this.builder.opts.toolbar === 'right') {
                        pop.style.top       = (top - (h / 2) + 20) + 'px';
                        pop.style.left      = 'auto';
                        const viewportWidth = window.innerWidth;
                        pop.style.right     = (viewportWidth - left + 9) + 'px';
                    } else {
                        pop.style.top   = (top + 54 - 6) + 'px';
                        pop.style.left  = (left - (w / 2) + 23) + 'px';
                        pop.style.right = 'auto';
                    }

                    if (dom.parentsHasClass(btnRteTextSettings, 'rte-more-options')) {
                        // Adjustment if button is placed on 2nd bar (div.rte-more-options)
                        if (this.builder.opts.toolbar === 'left') {
                            pop.style.top   = (parseInt(this.rteMoreOptions.style.top) + this.rteMoreOptions.offsetHeight - h) + 'px';
                            pop.style.left  = (left + 54) + 'px';
                            pop.style.right = 'auto';
                        } else if (this.builder.opts.toolbar === 'right') {
                            pop.style.top       = (parseInt(this.rteMoreOptions.style.top) + this.rteMoreOptions.offsetHeight - h) + 'px';
                            pop.style.left      = 'auto';
                            const viewportWidth = window.innerWidth;
                            pop.style.right     = (viewportWidth - left + 9) + 'px';
                        } else {
                            pop.style.top   = (top + 54 - 6) + 'px';
                            pop.style.left  = (left - (w / 2) + 23) + 'px'; //(parseInt(this.rteMoreOptions.style.left) + this.rteMoreOptions.offsetWidth - w) + 'px';
                            pop.style.right = 'auto';
                        }
                    }

                    dom.removeClass(pop, 'deactive');
                    dom.addClass(pop, 'active');
                } else {
                    dom.removeClass(pop, 'active');
                    dom.addClass(pop, 'deactive');
                }

            });
        }

        // More
        let btnRteMore = this.rteTool.querySelector('button.rte-more');
        if (btnRteMore) {
            dom.addEventListener(btnRteMore, 'click', () => {

                this.showRteMore();

            });
        }

        let btnElementRteMore = this.elementRteTool.querySelector('button.rte-more');
        if (btnElementRteMore) {
            dom.addEventListener(btnElementRteMore, 'click', () => {

                this.showElementRteMore();

            });
        }

        // -----------------------------

        // Formatting
        var btns = Array.prototype
            .slice.call(this.rteTool.querySelectorAll('.rte-format'))
            .concat(Array.prototype.slice.call(this.rteFormattingOptions.querySelectorAll('.rte-format')))
            .concat(Array.prototype.slice.call(this.rteMoreOptions.querySelectorAll('.rte-format')));

        Array.prototype.forEach.call(btns, (btn) => {
            dom.addEventListener(btn, 'click', () => { // old 8368

                this.builder.uo.saveForUndo();

                let elm;
                try {
                    let curr;
                    if (window.getSelection) {
                        curr = window.getSelection().getRangeAt(0).commonAncestorContainer;
                        if (curr.nodeType === 3) {  //text node
                            elm = curr.parentNode;
                        } else {
                            elm = curr;
                        }
                    } else if (document.selection) {
                        curr = document.selection.createRange();
                        elm  = document.selection.createRange().parentElement();
                    }
                } catch (e) {
                    return;
                }

                const command = btn.getAttribute('data-command');

                var text = dom.getSelected();

                if (command === 'bold') {

                    if (text.trim() === '') {

                        var tagname = elm.tagName.toLowerCase();
                        if (tagname === 'b') {

                            dom.selectElementContents(elm);

                            document.execCommand('bold', false, null);

                        } else {
                            if (elm.style.fontWeight === 'bold' || elm.style.fontWeight > 400) {
                                elm.style.fontWeight = '';
                            } else {
                                elm.style.fontWeight = 'bold';
                            }
                        }
                    } else {
                        document.execCommand('bold', false, null);
                    }

                }

                if (command === 'italic') {

                    if (text.trim() === '') {

                        tagname = elm.tagName.toLowerCase();
                        if (tagname === 'i') {

                            dom.selectElementContents(elm);

                            document.execCommand('italic', false, null);

                        } else {
                            if (elm.style.fontStyle === 'italic') {
                                elm.style.fontStyle = '';
                            } else {
                                elm.style.fontStyle = 'italic';
                            }
                        }
                    } else {
                        document.execCommand('italic', false, null);
                    }

                }

                if (command === 'underline') {

                    if (text.trim() === '') {

                        tagname = elm.tagName.toLowerCase();
                        if (tagname === 'u') {

                            dom.selectElementContents(elm);

                            document.execCommand('underline', false, null);

                        } else {
                            if (elm.style.textDecoration.indexOf('underline') !== -1) {
                                elm.style.textDecoration = '';
                            } else {
                                elm.style.textDecoration = 'underline';
                            }
                        }
                    } else {
                        document.execCommand('underline', false, null);
                    }

                }
                if (command === 'strikethrough') {

                    if (text.trim() === '') {

                        tagname = elm.tagName.toLowerCase();
                        if (tagname === 'strike') {

                            dom.selectElementContents(elm);

                            document.execCommand('strikethrough', false, null);

                        } else {
                            if (elm.style.textDecoration.indexOf('line-through') !== -1) {
                                elm.style.textDecoration = '';
                            } else {
                                elm.style.textDecoration = 'line-through';
                            }
                        }
                    } else {
                        document.execCommand('strikethrough', false, null);
                    }

                }

                if (command === 'superscript') {
                    document.execCommand('superscript', false, null);
                }

                if (command === 'subscript') {
                    document.execCommand('subscript', false, null);
                }

                if (command === 'uppercase') {
                    if (elm.style.textTransform === 'uppercase') {
                        elm.style.textTransform = '';
                    } else {
                        elm.style.textTransform = 'uppercase';
                    }
                }

                if (command === 'clean') {
                    if (text.trim() === '') {

                        elm.style.cssText = '';
                        elm.className     = '';

                    } else {

                        if (elm.innerText.replace(/(\r\n|\n|\r)/gm, '') === text.trim().replace(/(\r\n|\n|\r)/gm, '')) {

                            elm.style.cssText = '';
                            elm.className     = '';
                            document.execCommand('removeFormat', false, null);
                            document.execCommand('removeFormat', false, null);

                        } else {

                            document.execCommand('removeFormat', false, null);
                            document.execCommand('removeFormat', false, null);

                        }
                    }
                }

                this.getState();

                //save selection (only for desktop)
                if (!this.builder.isTouchSupport) {
                    util.saveSelection(); //Needed because after format, a tag is added (ex. <b>,<i>), so, make selection again.
                }

                if (text.trim() === '') {
                    util.restoreSelection(); //place cursor back after formatting (bold, italic, ...)

                    if (this.builder.isTouchSupport) { //prevent keyboard open
                        const btnFocus = this.rteTool.querySelector('button');
                        btnFocus.focus();
                    }
                }

                // Or can be placed here:
                // if(this.builder.isTouchSupport) { //prevent keyboard open
                //     const btnFocus = this.rteTool.querySelector('button');
                //     btnFocus.focus();
                // }

                //Trigger Change event
                this.builder.opts.onChange();

            });
        });

        // Align
        btns = this.rteAlignOptions.querySelectorAll('button[data-align]');
        Array.prototype.forEach.call(btns, (btn) => {
            dom.addEventListener(btn, 'click', () => {

                this.builder.uo.saveForUndo();

                util.restoreSelection(); //a must

                if (this.builder.isTouchSupport) { //prevent keyboard open
                    const btnFocus = this.rteTool.querySelector('button');
                    btnFocus.focus();
                }

                const command = btn.getAttribute('data-align');

                let elm;
                try {
                    let curr;
                    if (window.getSelection) {
                        curr = window.getSelection().getRangeAt(0).commonAncestorContainer;
                        if (curr.nodeType === 3) {  //text node
                            elm = curr.parentNode;
                        } else {
                            elm = curr;
                        }
                    } else if (document.selection) {
                        curr = document.selection.createRange();
                        elm  = document.selection.createRange().parentElement();
                    }
                } catch (e) {
                    return;
                }

                let element = elm;
                while (element.tagName.toLowerCase() !== 'p' &&
                element.tagName.toLowerCase() !== 'h1' &&
                element.tagName.toLowerCase() !== 'h2' &&
                element.tagName.toLowerCase() !== 'h3' &&
                element.tagName.toLowerCase() !== 'h4' &&
                element.tagName.toLowerCase() !== 'h5' &&
                element.tagName.toLowerCase() !== 'h6' &&
                element.tagName.toLowerCase() !== 'pre' &&
                element.tagName.toLowerCase() !== 'blockquote' &&
                element.tagName.toLowerCase() !== 'div') {
                    element = element.parentNode;
                }
                element.style.textAlign = command;

                this.getState();

                //save selection
                util.saveSelection();

                //Trigger Change event
                this.builder.opts.onChange();

            });
        });
        btns = this.elementRteTool.querySelectorAll('button[data-align]');
        Array.prototype.forEach.call(btns, (btn) => {
            dom.addEventListener(btn, 'click', () => {

                this.builder.uo.saveForUndo();

                //util.restoreSelection(); //a must

                // if(this.builder.isTouchSupport) { //prevent keyboard open
                //     const btnFocus = this.rteTool.querySelector('button');
                //     btnFocus.focus();
                // }

                const command = btn.getAttribute('data-align');

                // let elm;
                // try{
                //     let curr;
                //     if (window.getSelection) {
                //         curr = window.getSelection().getRangeAt(0).commonAncestorContainer;
                //         if (curr.nodeType === 3) {  //text node
                //             elm = curr.parentNode;
                //         } else {
                //             elm = curr;
                //         }
                //     }
                //     else if (document.selection) {
                //         curr = document.selection.createRange();
                //         elm = document.selection.createRange().parentElement();
                //     }
                // } catch(e) {return;}


                let elm = this.builder.inspectedElement;

                let element = elm;
                while (element.tagName.toLowerCase() !== 'p' &&
                element.tagName.toLowerCase() !== 'h1' &&
                element.tagName.toLowerCase() !== 'h2' &&
                element.tagName.toLowerCase() !== 'h3' &&
                element.tagName.toLowerCase() !== 'h4' &&
                element.tagName.toLowerCase() !== 'h5' &&
                element.tagName.toLowerCase() !== 'h6' &&
                element.tagName.toLowerCase() !== 'pre' &&
                element.tagName.toLowerCase() !== 'blockquote' &&
                element.tagName.toLowerCase() !== 'div') {
                    element = element.parentNode;
                }
                element.style.textAlign = command;

                this.getState();

                //save selection
                // util.saveSelection();

                //Trigger Change event
                this.builder.opts.onChange();

            });
        });

        // List
        btns = this.rteListOptions.querySelectorAll('button[data-action]');
        Array.prototype.forEach.call(btns, (btn) => {
            dom.addEventListener(btn, 'click', () => {

                this.builder.uo.saveForUndo();

                util.restoreSelection(); //a must

                // cleanup span with style
                let activeCol = this.builder.activeCol;
                let spans     = activeCol.querySelectorAll('span');
                Array.prototype.forEach.call(spans, (span) => {
                    span.setAttribute('data-keep', '');
                });

                const command = btn.getAttribute('data-action'); //insertUnorderedList, insertOrderedList, indent, outdent
                document.execCommand(command, false, null);

                // cleanup span with style
                activeCol = this.builder.activeCol;
                spans     = activeCol.querySelectorAll('span');
                Array.prototype.forEach.call(spans, (span) => {
                    let attr = span.getAttribute('data-keep');
                    if (!attr) {
                        span.outerHTML = span.innerHTML;
                    }
                });
                Array.prototype.forEach.call(spans, (span) => {
                    let attr = span.getAttribute('data-keep');
                    if (attr) {
                        dom.removeAttribute(span, 'data-keep');
                    }
                });

                this.getState();

                //save selection
                util.saveSelection();

                //Trigger Change event
                this.builder.opts.onChange();

                if (this.builder.isTouchSupport) { //prevent keyboard open
                    const btnFocus = this.rteTool.querySelector('button');
                    btnFocus.focus();
                }

            });
        });

        // Custom Tags
        btns = this.rteCustomTagOptions.querySelectorAll('[data-value]');
        Array.prototype.forEach.call(btns, (btn) => {
            dom.addEventListener(btn, 'click', () => {

                this.builder.uo.saveForUndo();

                const tag = btn.getAttribute('data-value');
                util.pasteHtmlAtCaret(tag, true);

                this.rteCustomTagOptions.style.display = '';
            });
        });

        // Paragraph
        btns = this.rteParagraphOptions.querySelectorAll('[data-block]');
        Array.prototype.forEach.call(btns, (btn) => {
            dom.addEventListener(btn, 'click', () => {

                this.builder.uo.saveForUndo();

                util.restoreSelection(); //a must

                const command = btn.getAttribute('data-block'); //h1, h2, h3, h4, p, pre

                let block = document.queryCommandValue('FormatBlock');
                block     = block.toLowerCase();
                if (block === 'pre') {
                    // document.execCommand('formatBlock', false, '<div>'); // without this, pref-ormatted won't change.

                    let elm = dom.textSelection();
                    if (elm) {
                        let element = elm;
                        while (element.tagName.toLowerCase() !== 'pre') {
                            element = element.parentNode;
                        }
                        let newnode       = element.cloneNode(true);
                        let s             = newnode.outerHTML.replace('<pre', '<' + command);
                        s                 = s.replace('</pre>', '</' + command + '>');
                        element.outerHTML = s;

                        // Highlight
                        let btns = this.rteParagraphOptions.querySelectorAll('[data-block]');
                        Array.prototype.forEach.call(btns, (btn) => {
                            dom.removeClass(btn, 'on');
                        });
                        dom.addClass(this.rteParagraphOptions.querySelector('[data-block="' + command + '"]'), 'on');

                    }
                } else {
                    document.execCommand('formatBlock', false, '<' + command + '>'); //Needs contenteditable.
                }

                this.rteParagraphOptions.style.display = 'none';
                dom.removeClass(this.rteParagraphOptions, 'active');
                dom.addClass(this.rteParagraphOptions, 'deactive');

                this.getState();

                //save selection
                util.saveSelection();

                //Trigger Change event
                this.builder.opts.onChange();

                if (this.builder.isTouchSupport) { //prevent keyboard open
                    const btnFocus = this.rteTool.querySelector('button');
                    btnFocus.focus();
                }
            });
        });

        // Color
        let tabs = rteColorPicker.querySelectorAll('.is-pop-tab-item');
        Array.prototype.forEach.call(tabs, (tab) => {
            dom.addEventListener(tab, 'click', (e) => {

                this.builder.uo.saveForUndo(true); // checkLater = true

                let elms = rteColorPicker.querySelectorAll('.is-pop-tab-item');
                Array.prototype.forEach.call(elms, (elm) => {
                    dom.removeClass(elm, 'active');
                });
                dom.addClass(e.target, 'active');

                let val = rteColorPicker.querySelector('.active').getAttribute('data-value');
                if (val === 'forecolor') {
                    rteColorPicker.setAttribute('data-command', 'forecolor');
                } else {
                    rteColorPicker.setAttribute('data-command', 'backcolor');
                }
            });
        });

        new ColorPicker({
            colors   : this.builder.opts.colors,
            onPick   : (color) => {

                util.restoreSelection(); //a must

                let elm;
                try {
                    let curr;
                    if (window.getSelection) {
                        curr = window.getSelection().getRangeAt(0).commonAncestorContainer;
                        if (curr.nodeType === 3) {  //text node
                            elm = curr.parentNode;
                        } else {
                            elm = curr;
                        }
                    } else if (document.selection) {
                        curr = document.selection.createRange();
                        elm  = document.selection.createRange().parentElement();
                    }
                } catch (e) {
                    return;
                }

                const command = rteColorPicker.getAttribute('data-command');

                var text = dom.getSelected();

                if (text.trim() === '') {
                    if (command === 'forecolor') {
                        elm.style.color = color;
                    } else {
                        elm.style.backgroundColor = color;
                    }
                } else {

                    if (elm.innerText === text) {
                        if (command === 'forecolor') {
                            elm.style.color = color;
                        } else {
                            elm.style.backgroundColor = color;
                        }
                    } else {
                        if (command === 'forecolor') {
                            document.execCommand('ForeColor', false, color);
                        } else {
                            document.execCommand('BackColor', false, color);
                        }

                        //Cleanup FONTs
                        var fontElements = document.getElementsByTagName('font');
                        for (var i = 0, len = fontElements.length; i < len; ++i) {
                            var s = fontElements[i].color;
                            if (s !== '') {
                                if (command === 'forecolor') {
                                    fontElements[i].removeAttribute('color');
                                    fontElements[i].style.color = color; //s;
                                    // if(this.builder.isTouchSupport) dom.addClass(fontElements[i], 'textblock-active');
                                }
                            }
                        }
                    }
                }

                //save selection (only for desktop)
                if (!this.builder.isTouchSupport) {
                    util.saveSelection(); //Needed because after format, a tag is added (ex. <b>,<i>), so, make selection again.
                }

                if (text.trim() === '') {
                    util.restoreSelection(); //place cursor back after formatting (bold, italic, ...)
                }

                if (this.builder.isTouchSupport) { //prevent keyboard open
                    const btnFocus = this.rteTool.querySelector('button');
                    btnFocus.focus();
                }
                //Trigger Change event
                this.builder.opts.onChange();


            },
            renderOn : '.rte-color-picker-area',

            animateModal     : this.builder.opts.animateModal,
            elementToAnimate : this.builder.opts.container,
            lang             : this.builder.opts.lang
        });


        // Font Size
        btns = rteTextSettingOptions.querySelectorAll('[data-value]');
        Array.prototype.forEach.call(btns, (btn) => {
            dom.addEventListener(btn, 'click', () => { // old 9135

                // Get the value of the option that was clicked
                let num = btn.getAttribute('data-value');

                util.restoreSelection(); //a must

                // Work out what element is currently selected
                let elm;
                try {
                    let curr;
                    if (window.getSelection) {
                        curr = window.getSelection().getRangeAt(0).commonAncestorContainer;
                        if (curr.nodeType === 3) {  //text node
                            elm = curr.parentNode;
                        } else {
                            elm = curr;
                        }
                    } else if (document.selection) {
                        curr = document.selection.createRange();
                        elm  = document.selection.createRange().parentElement();
                    }
                } catch (e) {
                    return;
                }

                var text = dom.getSelected();

                // If the user has the clicked a dom element
                if (text.trim() === '' || (text.trim() !== '' && elm.innerText === text)) {
                    this.builder.uo.saveForUndo();
                    this.applyClassFontSize(elm, num);

                } else { // Else the user has highlighted a specific piece of text
                    this.builder.uo.saveForUndo();

                    // Get the computed font size from the window
                    let currentFontSize = Number(window.getComputedStyle(elm).getPropertyValue('font-size').match(/\d+/)[0]);

                    // Run the font size browser command on the curently selected text and set its size to 7px so we can identify it later
                    document.execCommand('fontSize', false, '7'); // bug: this makes keyboard opens on mobile

                    let newFontDomElement;

                    // Loop through all the font tags on the page
                    var fontElements = document.getElementsByTagName('font');
                    for (var i = 0, len = fontElements.length; i < len; ++i) {

                        // Try and see if we can find the font element we tagged via the 'fontSize' command above
                        if (fontElements[i].size === '7') {

                            // Remove the 7px size as this is not needed now
                            fontElements[i].removeAttribute('size');

                            // Set the font size to match the original computed size
                            fontElements[i].style.fontSize = currentFontSize + 'px';

                            // Select the content of the font tag
                            dom.selectElementContents(fontElements[i]);
                            // if(this.builder.isTouchSupport) dom.addClass(fontElements[i], 'textblock-active');

                            // Now that we have found the font tag use that as the dom element going forward
                            newFontDomElement = fontElements[i];
                        }
                    }

                    // If we managed to identify the font tag apply the class to it
                    if (newFontDomElement) {
                        this.applyClassFontSize(newFontDomElement, num);
                    }
                }

                // save selection
                util.saveSelection();

                this.getState();

                // Trigger Change event
                this.builder.opts.onChange();

                if (this.builder.isTouchSupport) { //prevent keyboard open
                    const btnFocus = this.rteTool.querySelector('button');
                    btnFocus.focus();
                }

            });
        });

        // -----------------------------

        // Click anywhere will hide Column tool
        document.addEventListener('click', (e) => {
            e          = e || window.event;
            var target = e.target || e.srcElement;

            let a, b, c, d, f;

            if (this.rteAlignOptions.style.display === 'flex') {
                a = dom.parentsHasClass(target, 'rte-align');
                b = dom.parentsHasClass(target, 'rte-align-options');
                if (!(a || b)) {
                    this.rteAlignOptions.style.display = '';
                    dom.removeClass(this.rteAlignOptions, 'active');
                    dom.addClass(this.rteAlignOptions, 'deactive');
                }
            }

            if (this.rteListOptions.style.display === 'flex') {
                a = dom.parentsHasClass(target, 'rte-list');
                b = dom.parentsHasClass(target, 'rte-list-options');
                if (!(a || b)) {
                    this.rteListOptions.style.display = '';
                    dom.removeClass(this.rteListOptions, 'active');
                    dom.addClass(this.rteListOptions, 'deactive');
                }
            }

            if (this.rteFormattingOptions.style.display === 'flex') {
                a = dom.parentsHasClass(target, 'rte-formatting');
                b = dom.parentsHasClass(target, 'rte-formatting-options');
                if (!(a || b)) {
                    this.rteFormattingOptions.style.display = '';
                    dom.removeClass(this.rteFormattingOptions, 'active');
                    dom.addClass(this.rteFormattingOptions, 'deactive');
                }
            }

            if (this.rteColorPicker.style.display === 'flex') {
                a = dom.parentsHasClass(target, 'rte-color');
                b = dom.parentsHasClass(target, 'rte-color-picker');
                c = dom.parentsHasClass(target, 'pickcolormore');
                if (!(a || b || c)) {
                    this.rteColorPicker.style.display = '';
                    dom.removeClass(this.rteColorPicker, 'active');
                    dom.addClass(this.rteColorPicker, 'deactive');
                }
            }

            if (this.rteFontFamilyOptions.style.display === 'flex') {
                a = dom.parentsHasClass(target, 'rte-fontfamily');
                b = dom.parentsHasClass(target, 'rte-fontfamily-options');
                if (!(a || b)) {
                    this.rteFontFamilyOptions.style.display = '';
                    dom.removeClass(this.rteFontFamilyOptions, 'active');
                    dom.addClass(this.rteFontFamilyOptions, 'deactive');
                }
            }

            if (this.rteIconOptions.style.display === 'flex') {
                a = dom.parentsHasClass(target, 'rte-icon');
                b = dom.parentsHasClass(target, 'rte-icon-options');
                c = false;
                if (target.tagName) {
                    c = target.tagName.toLowerCase() === 'i' && target.innerHTML === '';
                }
                if (!(a || b || c)) {
                    this.rteIconOptions.style.display = '';
                    dom.removeClass(this.rteIconOptions, 'active');
                    dom.addClass(this.rteIconOptions, 'deactive');
                }
            }

            if (this.rteCustomTagOptions.style.display === 'flex') {
                a = dom.parentsHasClass(target, 'rte-tags');
                b = dom.parentsHasClass(target, 'rte-customtag-options');
                if (!(a || b)) {
                    this.rteCustomTagOptions.style.display = '';
                    dom.removeClass(this.rteCustomTagOptions, 'active');
                    dom.addClass(this.rteCustomTagOptions, 'deactive');
                }
            }

            if (this.rteParagraphOptions.style.display === 'flex') {
                a = dom.parentsHasClass(target, 'rte-paragraph');
                b = dom.parentsHasClass(target, 'rte-paragraph-options');
                if (!(a || b)) {
                    this.rteParagraphOptions.style.display = '';
                    dom.removeClass(this.rteParagraphOptions, 'active');
                    dom.addClass(this.rteParagraphOptions, 'deactive');
                }
            }

            if (this.rteTextSettingOptions.style.display === 'flex') {
                a = dom.parentsHasClass(target, 'rte-textsettings');
                b = dom.parentsHasClass(target, 'rte-textsetting-options');
                if (!(a || b)) {
                    this.rteTextSettingOptions.style.display = '';
                    dom.removeClass(this.rteTextSettingOptions, 'active');
                    dom.addClass(this.rteTextSettingOptions, 'deactive');
                }
            }

            if (this.rteMoreOptions.style.display === 'flex') {
                a = dom.parentsHasClass(target, 'rte-more');
                b = dom.parentsHasClass(target, 'rte-more-options');
                c = dom.parentsHasClass(target, 'is-rte-pop');
                d = dom.parentsHasClass(target, 'is-modal');
                f = false;
                if (target.tagName) {
                    f = target.tagName.toLowerCase() === 'i' && target.innerHTML === '' && dom.parentsHasClass(btnRteIcons, 'rte-more-options');
                }
                if (!(a || b || c || d || f)) {
                    this.rteMoreOptions.style.display = '';
                    dom.removeClass(this.rteMoreOptions, 'active');
                    dom.addClass(this.rteMoreOptions, 'deactive');
                }
            }

            if (this.elementRteMoreOptions.style.display === 'flex') {
                a = dom.parentsHasClass(target, 'rte-more'); // more button
                b = dom.parentsHasClass(target, 'elementrte-more-options');
                c = dom.parentsHasClass(target, 'is-rte-pop');
                d = dom.parentsHasClass(target, 'is-modal');
                f = false;
                //if(target.tagName) f = target.tagName.toLowerCase() === 'i' && target.innerHTML === '' && dom.parentsHasClass(btnRteIcons, 'rte-more-options');
                if (!(a || b || c || d || f)) {
                    this.elementRteMoreOptions.style.display = '';
                    dom.removeClass(this.elementRteMoreOptions, 'active');
                    dom.addClass(this.elementRteMoreOptions, 'deactive');
                }
            }

        });
    }

    /**
     * View snippets
     */
    viewSnippets() {

        // direct
        const util = new Util(this.builder);
        let modal  = this.builderStuff.querySelector('.snippets');
        util.showModal(modal, false, null, false);

        let iframe = modal.querySelector('iframe');
        if (iframe.src === 'about:blank') {
            iframe.src = this.builder.opts.snippetData;
        }

    }

    /**
     * Show more option
     */
    showRteMore() {
        const btnRteMore  = this.rteTool.querySelector('button.rte-more');
        const pop         = this.rteMoreOptions;
        const top         = btnRteMore.getBoundingClientRect().top; // + window.pageYOffset;
        const left        = btnRteMore.getBoundingClientRect().left; // + window.pageXOffset;
        pop.style.display = 'flex';
        const w           = pop.offsetWidth; //to get value, element must not hidden (display:none). So set display:flex before this.
        const h           = pop.offsetHeight;

        if (!dom.hasClass(pop, 'active')) {
            if (this.builder.opts.toolbar === 'left') {
                pop.style.top   = (parseInt(this.rteTool.style.top) + this.rteTool.offsetHeight - h) + 'px'; //(top - (h/2) + 20) + 'px';
                pop.style.left  = (left + 54) + 'px';
                pop.style.right = 'auto';
            } else if (this.builder.opts.toolbar === 'right') {
                pop.style.top       = (parseInt(this.rteTool.style.top) + this.rteTool.offsetHeight - h) + 'px'; //(top - (h/2) + 20) + 'px';
                pop.style.left      = 'auto';
                const viewportWidth = window.innerWidth;
                pop.style.right     = (viewportWidth - left + 9) + 'px';
            } else {
                pop.style.top   = (top + 54 - 6) + 'px';
                pop.style.left  = (parseInt(this.rteTool.style.left) + this.rteTool.offsetWidth - w) + 'px'; //(left -(w/2)+23) + 'px';
                pop.style.right = 'auto';
            }

            dom.removeClass(pop, 'deactive');
            dom.addClass(pop, 'active');
        } else {
            dom.removeClass(pop, 'active');
            dom.addClass(pop, 'deactive');
        }
    }

    /**
     *
     */
    showElementRteMore() {
        const btnElementRteMore = this.elementRteTool.querySelector('button.rte-more');
        const pop               = this.elementRteMoreOptions;
        const top               = btnElementRteMore.getBoundingClientRect().top; // + window.pageYOffset;
        const left              = btnElementRteMore.getBoundingClientRect().left; // + window.pageXOffset;
        pop.style.display       = 'flex';
        const w                 = pop.offsetWidth; //to get value, element must not hidden (display:none). So set display:flex before this.
        const h                 = pop.offsetHeight;

        if (!dom.hasClass(pop, 'active')) {
            if (this.builder.opts.toolbar === 'left') {
                pop.style.top   = (parseInt(this.elementRteTool.style.top) + this.elementRteTool.offsetHeight - h) + 'px'; //(top - (h/2) + 20) + 'px';
                pop.style.left  = (left + 54) + 'px';
                pop.style.right = 'auto';
            } else if (this.builder.opts.toolbar === 'right') {
                pop.style.top       = (parseInt(this.elementRteTool.style.top) + this.elementRteTool.offsetHeight - h) + 'px'; //(top - (h/2) + 20) + 'px';
                pop.style.left      = 'auto';
                const viewportWidth = window.innerWidth;
                pop.style.right     = (viewportWidth - left + 9) + 'px';
            } else {
                pop.style.top   = (top + 54 - 6) + 'px';
                pop.style.left  = (parseInt(this.elementRteTool.style.left) + this.elementRteTool.offsetWidth - w) + 'px'; //(left -(w/2)+23) + 'px';
                pop.style.right = 'auto';
            }

            dom.removeClass(pop, 'deactive');
            dom.addClass(pop, 'active');
        } else {
            dom.removeClass(pop, 'active');
            dom.addClass(pop, 'deactive');
        }
    }

    /**
     * Apply inline font
     *
     * @param elm
     * @param num
     */
    applyInlineFontSize(elm, num) {

        let currentFontSize = Number(window.getComputedStyle(elm).getPropertyValue('font-size').match(/\d+/)[0]);

        let fontsize;
        if (num === '+') {
            fontsize = (currentFontSize + 1) + 'px';
        } else if (num === '-') {
            fontsize = (currentFontSize - 1) + 'px';
        } else if (num === '') {
            fontsize = '';
        } else {
            fontsize = num + 'px';
        }
        elm.style.fontSize = fontsize;
    }

    /**
     *
     * @param elm
     * @param num
     */
    applyClassFontSize(elm, num) {

        const arrSizes = [
            'display-1', 'display-2', 'display-3', 'display-4',
            'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
            'lead', 'mark', 'small',
            'size-12', 'size-14', 'size-16', 'size-18', 'size-21', 'size-24', 'size-28',
            'size-32', 'size-35', 'size-38',
            'size-42', 'size-46', 'size-48', 'size-50', 'size-54', 'size-60', 'size-64', 'size-68',
            'size-72', 'size-76', 'size-80', 'size-84', 'size-88',
            'size-92', 'size-96', 'size-100', 'size-104', 'size-108',
            'size-112', 'size-116', 'size-120', 'size-124', 'size-128',
            'size-132', 'size-136', 'size-140', 'size-144', 'size-148',
            'size-152', 'size-156', 'size-160', 'size-164', 'size-168',
            'size-172', 'size-176', 'size-180', 'size-184', 'size-188',
            'size-192', 'size-196', 'size-200', 'size-204', 'size-208',
            'size-212', 'size-216', 'size-220'
        ];

        // Remove all the class sizes
        for (var i = 0; i <= arrSizes.length - 1; i++) {
            if (dom.hasClass(elm, arrSizes[i])) {
                dom.removeClass(elm, arrSizes[i]);
            }
        }

        // Add the new size class
        dom.addClass(elm, num);
        elm.style.fontSize = '';
    }

    /**
     *
     * @param col
     */
    click(col) {

        let elm = this.builder.inspectedElement;


        this.rteTool.style.display        = 'none';
        this.elementRteTool.style.display = 'none';

        if (elm.tagName.toLowerCase() === 'img' ||
            dom.hasClass(elm, 'is-social') ||
            dom.hasClass(elm, 'is-rounded-button-medium') ||
            dom.hasClass(elm, 'cell-active')) {

            if (this.elementRteTool.style.display === 'none' || this.elementRteTool.style.display === '') {
                this.elementRteTool.style.display = 'flex';
                this.rteTool.style.display        = 'none';

                let btns = this.elementRteTool.querySelectorAll('button[data-align]');
                Array.prototype.forEach.call(btns, (btn) => {
                    btn.style.display = '';
                });

                this.positionToolbar();
            }

        } else if (dom.hasClass(elm, 'spacer') ||
            dom.hasClass(elm, 'ovl') ||
            col.getAttribute('data-html')) {

            if (this.elementRteTool.style.display === 'none' || this.elementRteTool.style.display === '') {
                this.elementRteTool.style.display = 'flex';
                this.rteTool.style.display        = 'none';

                let btns = this.elementRteTool.querySelectorAll('button[data-align]');
                Array.prototype.forEach.call(btns, (btn) => {
                    btn.style.display = 'none';
                });

                this.positionToolbar();
            }

        } else {

            if (this.rteTool.style.display === 'none' || this.rteTool.style.display === '') {
                this.rteTool.style.display        = 'flex';
                this.elementRteTool.style.display = 'none';
                this.positionToolbar();
            }

        }


        this.util.saveSelection();

        this.getState();

    }

    /**
     *
     */
    getState() { // old 14140

        if (document.queryCommandState('bold')) {
            dom.addClass(this.rteTool.querySelector('button[data-command=bold]'), 'on');
        } else {
            dom.removeClass(this.rteTool.querySelector('button[data-command=bold]'), 'on');
        }
        if (document.queryCommandState('italic')) {
            dom.addClass(this.rteTool.querySelector('button[data-command=italic]'), 'on');
        } else {
            dom.removeClass(this.rteTool.querySelector('button[data-command=italic]'), 'on');
        }
        if (document.queryCommandState('underline')) {
            dom.addClass(this.rteTool.querySelector('button[data-command=underline]'), 'on');
        } else {
            dom.removeClass(this.rteTool.querySelector('button[data-command=underline]'), 'on');
        }
        if (document.queryCommandState('strikethrough')) {
            dom.addClass(this.rteFormattingOptions.querySelector('[data-command=strikethrough]'), 'on');
        } else {
            dom.removeClass(this.rteFormattingOptions.querySelector('[data-command=strikethrough]'), 'on');
        }
        if (document.queryCommandState('superscript')) {
            dom.addClass(this.rteFormattingOptions.querySelector('[data-command=superscript]'), 'on');
        } else {
            dom.removeClass(this.rteFormattingOptions.querySelector('[data-command=superscript]'), 'on');
        }
        if (document.queryCommandState('subscript')) {
            dom.addClass(this.rteFormattingOptions.querySelector('[data-command=subscript]'), 'on');
        } else {
            dom.removeClass(this.rteFormattingOptions.querySelector('[data-command=subscript]'), 'on');
        }

        let elm = dom.textSelection();
        if (elm) {
            if (elm.style.textTransform === 'uppercase') {
                dom.addClass(this.rteFormattingOptions.querySelector('[data-command=uppercase]'), 'on');
            } else {
                dom.removeClass(this.rteFormattingOptions.querySelector('[data-command=uppercase]'), 'on');
            }
        } else {
            return; // Without this, the line below generates error on first image click (FF). In addition, getState is for text.
        }

        if (document.queryCommandState('JustifyFull')) {
            dom.addClass(this.rteAlignOptions.querySelector('[data-align=justify]'), 'on');
            // let elm = this.elementRteTool.querySelector('[data-align=justify]');
            // if(elm) dom.addClass(elm, 'on');
        } else {
            dom.removeClass(this.rteAlignOptions.querySelector('[data-align=justify]'), 'on');
        }
        if (document.queryCommandState('JustifyLeft')) {
            dom.addClass(this.rteAlignOptions.querySelector('[data-align=left]'), 'on');
        } else {
            dom.removeClass(this.rteAlignOptions.querySelector('[data-align=left]'), 'on');
        }
        if (document.queryCommandState('JustifyRight')) {
            dom.addClass(this.rteAlignOptions.querySelector('[data-align=right]'), 'on');
        } else {
            dom.removeClass(this.rteAlignOptions.querySelector('[data-align=right]'), 'on');
        }
        if (document.queryCommandState('JustifyCenter')) {
            dom.addClass(this.rteAlignOptions.querySelector('[data-align=center]'), 'on');
        } else {
            dom.removeClass(this.rteAlignOptions.querySelector('[data-align=center]'), 'on');
        }

        var s        = document.queryCommandValue('FontName');
        var fontname = s.split(',')[0];
        fontname     = fontname.replace(/"/g, '');
        fontname     = fontname.replace(/'/g, ''); // NEW 4.0.5
        fontname     = fontname.replace(/&quot;/g, ''); // NEW 4.0.5
        fontname     = fontname.trim().toLowerCase();

        let btnRteFontFamily = this.rteTool.querySelector('button.rte-fontfamily');
        btnRteFontFamily     = btnRteFontFamily ? btnRteFontFamily : this.rteMoreOptions.querySelector('button.rte-fontfamily');
        if (btnRteFontFamily) {
            const iframe       = this.rteFontFamilyOptions.querySelector('iframe');
            let iframeDocument = iframe.contentDocument || iframe.contentWindow.document;
            if (iframeDocument) {
                [].forEach.call(iframeDocument.querySelectorAll('#divFontList > div'), function (e) {

                    var f = e.getAttribute('data-font-family');
                    f     = f.split(',')[0];
                    f     = f.replace(/'/g, ''); // NEW 4.0.5
                    f     = f.trim().toLowerCase();

                    if (f === fontname && f !== '') {
                        dom.addClass(e, 'on');
                    } else {
                        dom.removeClass(e, 'on');
                    }

                });
            }
        }

        let btns = this.rteParagraphOptions.querySelectorAll('[data-block]');
        Array.prototype.forEach.call(btns, (btn) => {
            dom.removeClass(btn, 'on');
        });

        var block = document.queryCommandValue('FormatBlock');
        block     = block.toLowerCase();

        if (block === 'normal') {
            block = 'p';
        }
        if (block === 'heading 1') {
            block = 'h1';
        }
        if (block === 'heading 2') {
            block = 'h2';
        }
        if (block === 'heading 3') {
            block = 'h3';
        }
        if (block === 'heading 4') {
            block = 'h4';
        }
        if (block === 'formatted') {
            block = 'pre';
        }
        if (block === 'p' || block === 'h1' || block === 'h2' || block === 'h3' || block === 'h4' || block === 'pre') {
            dom.addClass(this.rteParagraphOptions.querySelector('[data-block="' + block + '"]'), 'on');
        }

    }

    /**
     *
     * @param classname
     */
    addIcon(classname) {

        this.util.restoreSelection();

        if (this.builder.activeIcon) {
            this.builder.uo.saveForUndo();
            const arrSizes = this.builder.opts.fontSizeClassValues;

            // Get current class size
            var currentClassSize = '';
            for (var i = 0; i <= arrSizes.length - 1; i++) {
                if (dom.hasClass(this.builder.activeIcon, 'size-' + arrSizes[i])) {
                    currentClassSize = 'size-' + arrSizes[i];
                }
            }

            this.builder.activeIcon.className = classname + (currentClassSize !== '' ? ' ' + currentClassSize : '');
            dom.addClass(this.builder.activeIcon, 'icon-active');
            dom.selectElementContents(this.builder.activeIcon);
            this.util.saveSelection();

        } else {
            if (!dom.textSelection()) {
                return;
            }
            this.builder.uo.saveForUndo();
            this.util.pasteHtmlAtCaret('<i class="' + classname + ' icon-active"></i>', true);
            this.builder.activeIcon = document.querySelector('.icon-active');
            dom.selectElementContents(this.builder.activeIcon);
            this.util.saveSelection();
        }

        //Trigger Change event
        this.builder.opts.onChange();

        //Trigger Render event
        this.builder.opts.onRender();
    }

    /**
     *
     */
    clearFont() {

        this.builder.uo.saveForUndo();

        this.applyFont('', '', '');
    }

    /**
     *
     * @param fontfamily
     * @param fontstyle
     * @param provider
     */
    applyFont(fontfamily, fontstyle, provider) {

        let elm;

        var panel = this.builderStuff.querySelector('.is-side.elementstyles');
        if (dom.hasClass(panel, 'active')) {

            this.builder.uo.saveForUndo();

            elm = this.builder.inspectedElement;

            elm.style.fontFamily = fontfamily;

            this.builderStuff.querySelector('#inpElmFontFamily').value = fontfamily; //direct (see elementpanel-text.js)

            this.elementStyleEditor.refresh();

        } else {

            try {
                let curr;
                if (window.getSelection) {
                    curr = window.getSelection().getRangeAt(0).commonAncestorContainer;
                    if (curr.nodeType === 3) {  //text node
                        elm = curr.parentNode;
                    } else {
                        elm = curr;
                    }
                    if (elm.tagName !== 'H1' && elm.tagName !== 'H2' && elm.tagName !== 'H3' &&
                        elm.tagName !== 'H4' && elm.tagName !== 'H5' && elm.tagName !== 'H6' &&
                        elm.tagName !== 'P') {
                        elm = elm.parentNode;
                    }
                } else if (document.selection) {
                    curr = document.selection.createRange();
                    elm  = document.selection.createRange().parentElement();

                    if (elm.tagName !== 'H1' && elm.tagName !== 'H2' && elm.tagName !== 'H3' &&
                        elm.tagName !== 'H4' && elm.tagName !== 'H5' && elm.tagName !== 'H6' &&
                        elm.tagName !== 'P') {
                        elm = elm.parentElement();
                    }
                }
            } catch (e) {
                return;
            }

            this.builder.uo.saveForUndo();

            var text = dom.getSelected();

            if (text.trim() !== '' && elm.innerText !== text) {
                document.execCommand('fontName', false, fontfamily);
                var fontElements = document.getElementsByTagName('font');
                for (var i = 0, len = fontElements.length; i < len; ++i) {
                    if (fontElements[i].face === fontfamily) {
                        fontElements[i].removeAttribute('face');
                        fontElements[i].style.fontFamily = fontfamily;
                        dom.selectElementContents(fontElements[i]);
                        // if(this.builder.isTouchSupport) dom.addClass(fontElements[i], 'textblock-active');
                    }
                }

            } else if (text.trim() !== '' && elm.innerText === text) { //selection fully mode on text AND element. Use element then.
                elm.style.fontFamily = fontfamily;
            } else {
                elm.style.fontFamily = fontfamily;
            }

        }


        var o = fontstyle;
        if (!o) {
            o = '';
        } else {
            o = ':' + o;
        }

        var fontname = fontfamily.split(',')[0];
        if (provider === 'google') {
            var bExist = false;
            var links  = document.getElementsByTagName('link');
            for (i = 0; i < links.length; i++) {
                var sSrc = links[i].href.toLowerCase();
                sSrc     = sSrc.replace(/\+/g, ' ').replace(/%20/g, ' ');
                if (sSrc.indexOf(fontname.toLowerCase()) !== -1) {
                    bExist = true;
                }
            }

            if (!bExist) {
                var element = elm;
                while (!dom.hasClass(element, 'is-builder')) {
                    element = element.parentNode;
                }
                dom.appendHtml(element, '<link href="//fonts.googleapis.com/css?family=' + fontname + o + '" rel="stylesheet" property="stylesheet" type="text/css">');

            }
        }

        if (!this.builder.inspectedElement) {
            //save selection
            this.util.saveSelection(); //Needed because after format, a tag is added (ex. <span>), so, make selection again.

            if (this.builder.isTouchSupport) { //prevent keyboard open
                const btnFocus = this.rteTool.querySelector('button');
                btnFocus.focus();
            }

            this.getState();
        }

        //Trigger Change event
        this.builder.opts.onChange();
        setTimeout(() => {
            this.builder.opts.onChange();
        }, 300);

        //LATER: make function
        //Cleanup Google font css link

        links = document.getElementsByTagName('link');
        for (i = 0; i < links.length; i++) {
            sSrc = links[i].href.toLowerCase();
            if (sSrc.indexOf('googleapis') !== -1) {
                //get fontname
                sSrc     = sSrc.replace(/\+/g, ' ').replace(/%20/g, ' ');
                fontname = sSrc.substr(sSrc.indexOf('family=') + 7);
                if (fontname.indexOf(':') !== -1) {
                    fontname = fontname.split(':')[0];
                }
                if (fontname.indexOf('|') !== -1) {
                    fontname = fontname.split('|')[0];
                }
                //check if fontname used in content
                var tmp = document.body.innerHTML.toLowerCase();

                var count = tmp.split(fontname).length;
                if (count < 3) {
                    //not used
                    var attr = links[i].getAttribute('data-protect');
                    if (!attr) {
                        links[i].setAttribute('data-rel', '_del');
                    }
                }
            }
        }

        [].forEach.call(document.querySelectorAll('link[data-rel="_del"]'), function (e) {
            e.parentNode.removeChild(e);
        });

    }

    /**
     *
     * @param fontfamily
     * @param fontstyle
     * @param fontdisplay
     * @param provider
     */
    setFont(fontfamily, fontstyle, fontdisplay, provider) { // NEW 4.0.5

        let elm;

        var panel = this.builderStuff.querySelector('.is-side.elementstyles');
        if (dom.hasClass(panel, 'active')) {

            this.builder.uo.saveForUndo();

            elm = this.builder.inspectedElement;

            elm.style.fontFamily = fontfamily;

            this.builderStuff.querySelector('#inpElmFontFamily').value = fontfamily; //direct (see elementpanel-text.js)

            this.elementStyleEditor.refresh();

        } else {
            if (this.builder.isIE) {
                this.util.restoreSelection();
            } //a must (IE)

            try {
                let curr;
                if (window.getSelection) {
                    curr = window.getSelection().getRangeAt(0).commonAncestorContainer;
                    if (curr.nodeType === 3) {  //text node
                        elm = curr.parentNode;
                    } else {
                        elm = curr;
                    }
                    if (elm.tagName !== 'H1' && elm.tagName !== 'H2' && elm.tagName !== 'H3' &&
                        elm.tagName !== 'H4' && elm.tagName !== 'H5' && elm.tagName !== 'H6' &&
                        elm.tagName !== 'P') {
                        elm = elm.parentNode;
                    }
                } else if (document.selection) {
                    curr = document.selection.createRange();
                    elm  = document.selection.createRange().parentElement();

                    if (elm.tagName !== 'H1' && elm.tagName !== 'H2' && elm.tagName !== 'H3' &&
                        elm.tagName !== 'H4' && elm.tagName !== 'H5' && elm.tagName !== 'H6' &&
                        elm.tagName !== 'P') {
                        elm = elm.parentElement();
                    }
                }
            } catch (e) {
                return;
            }

            this.builder.uo.saveForUndo();

            var text = dom.getSelected();

            if (text.trim() !== '' && elm.innerText !== text) {
                document.execCommand('fontName', false, fontfamily); // this removes all quotes, so needs to make valid later (below).
                var fontElements = document.getElementsByTagName('font');
                for (var i = 0, len = fontElements.length; i < len; ++i) {
                    // fontElements[i].face = Press Start 2p, cursive => no quotes here
                    // fontfamily = 'Press Start 2p', cursive
                    if (fontElements[i].face.replace(/'/g, '') === fontfamily.replace(/'/g, '')) {
                        fontElements[i].removeAttribute('face');
                        fontElements[i].style.fontFamily = fontfamily;
                        dom.selectElementContents(fontElements[i]);
                        // if(this.builder.isTouchSupport) dom.addClass(fontElements[i], 'textblock-active');
                    }
                }

                //cleaning added <span face="">.
                // example:
                // <p style="text-align: justify;"><span style="font-family: &quot;Press Start 2p&quot;, cursive;">Lorem </span>
                // <span style="font-family: &quot;M PLUS Rounded 1c&quot;, sans-serif;">Ipsum</span>
                // <span face="Press Start 2p, cursive;"> is simply dummy text of the printing and typesetting industry...</span></p>
                fontElements = document.querySelectorAll('[face]');
                for (i = 0, len = fontElements.length; i < len; ++i) {
                    // Make valid (adding quotes):
                    let tmp = fontElements[i].getAttribute('face');
                    if (tmp.indexOf(',') !== -1) {
                        var f1 = tmp.split(',')[0];
                        var f2 = tmp.split(',')[1];
                        if (f1.indexOf(' ') !== -1) {
                            tmp = `'${f1}',${f2}`;
                        }
                    }
                    fontElements[i].style.fontFamily = tmp;
                    fontElements[i].removeAttribute('face');
                }

            } else if (text.trim() !== '' && elm.innerText === text) { //selection fully mode on text AND element. Use element then.
                elm.style.fontFamily = fontfamily;

                let allfonts = elm.querySelectorAll('*');
                Array.prototype.forEach.call(allfonts, (item) => {
                    if (item.style.fontFamily !== '') {
                        item.style.fontFamily = '';
                    }
                });

            } else {
                elm.style.fontFamily = fontfamily;
            }

        }


        var o = fontstyle;
        if (!o) {
            o = '';
        } else {
            o = ':' + o;
        }

        var d = ''; // NEW 4.0.5
        if (fontdisplay) {
            d = '&display=swap';
        }

        var fontname = fontfamily.split(',')[0];

        fontname = fontname.replace(/'/g, ''); // NEW 4.0.5 (replace quotes in font family)

        if (provider === 'google') {
            var bExist = false;
            var links  = document.getElementsByTagName('link');
            for (i = 0; i < links.length; i++) {
                var sSrc = links[i].href.toLowerCase();
                sSrc     = sSrc.replace(/\+/g, ' ').replace(/%20/g, ' ');
                if (sSrc.indexOf(fontname.toLowerCase()) !== -1) {
                    bExist = true;
                }
            }

            if (!bExist) {
                var element = elm;
                while (!dom.hasClass(element, 'is-builder')) {
                    element = element.parentNode;
                }
                dom.appendHtml(element, '<link href="//fonts.googleapis.com/css?family=' + fontname + d + o + '" rel="stylesheet" property="stylesheet" type="text/css">');

            }
        }

        if (!this.builder.inspectedElement) {
            //save selection
            this.util.saveSelection(); //Needed because after format, a tag is added (ex. <span>), so, make selection again.

            if (this.builder.isTouchSupport) { //prevent keyboard open
                const btnFocus = this.rteTool.querySelector('button');
                btnFocus.focus();
            }

            this.getState();
        }

        //Trigger Change event
        this.builder.opts.onChange();

        //LATER: make function
        //Cleanup Google font css link

        links = document.getElementsByTagName('link');
        for (i = 0; i < links.length; i++) {
            sSrc = links[i].href.toLowerCase();
            if (sSrc.indexOf('googleapis') !== -1) {

                //get fontname
                sSrc     = sSrc.replace(/\+/g, ' ').replace(/%20/g, ' ');
                fontname = sSrc.substr(sSrc.indexOf('family=') + 7);
                if (fontname.indexOf(':') !== -1) {
                    fontname = fontname.split(':')[0];
                }
                if (fontname.indexOf('|') !== -1) {
                    fontname = fontname.split('|')[0];
                }

                fontname = fontname.replace('&display=swap', ''); // NEW 4.0.5

                //check if fontname used in content
                let tmp = document.body.innerHTML.toLowerCase();

                var count = tmp.split(fontname).length;
                if (count < 3) {
                    //not used
                    var attr = links[i].getAttribute('data-protect');
                    if (!attr) {
                        links[i].setAttribute('data-rel', '_del');
                    }
                }
            }
        }

        [].forEach.call(document.querySelectorAll('link[data-rel="_del"]'), function (e) {
            e.parentNode.removeChild(e);
        });

    }

    /**
     *
     */
    positionToolbar() {

        const viewportWidth  = window.innerWidth;
        const viewportHeight = window.innerHeight;

        if (this.builder.opts.toolbar === 'left' || this.builder.opts.toolbar === 'right') {

            let h = this.rteTool.offsetHeight;

            let top = (viewportHeight / 2) - (h / 2);

            this.rteTool.style.left = '';
            this.rteTool.style.top  = top + 'px';

            // Element Toolbar
            h = this.elementRteTool.offsetHeight;

            top = (viewportHeight / 2) - (h / 2);

            this.elementRteTool.style.left = '';
            this.elementRteTool.style.top  = top + 'px';


        } else {

            let w = this.rteTool.offsetWidth;

            let left = (viewportWidth / 2) - (w / 2);

            this.rteTool.style.top  = '';
            this.rteTool.style.left = left + 'px';

            // Element Toolbar
            w = this.elementRteTool.offsetWidth;

            left = (viewportWidth / 2) - (w / 2);

            this.elementRteTool.style.top  = '';
            this.elementRteTool.style.left = left + 'px';

        }
    }
}

export default Rte;