editor.js icon indicating copy to clipboard operation
editor.js copied to clipboard

No trigger onChange for <select> input

Open thucne opened this issue 3 years ago • 1 comments

Hmm, I'm facing this issue rn, I had tried with text-area, and it worked, but not for select tag...
I need the onChange function triggered every time the selected value changes.

Thanks in advance!

new Editor({
    ...otherProps,
    onChange: handleOnChange 
})

My code:

export default class CodeEditor {
    // This plugin allows to write code and select language
    static get toolbox() {
        return {
            title: 'New Raw Code',
            icon: '<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6"><path stroke-linecap="round" stroke-linejoin="round" d="M17.25 6.75L22.5 12l-5.25 5.25m-10.5 0L1.5 12l5.25-5.25m7.5-3l-4.5 16.5" /></svg>'
        };
    }

    static get isReadOnlySupported() {
        return true;
    }

    constructor({ data, config, api, readOnly }) {
        this.api = api;
        this.readOnly = readOnly;
        this.data = {
            language: data.language || 'javascript',
            code: data.code || ''
        };
    }

    render() {
        // include a language selector and a code editor
        this._element = document.createElement('div');
        this._element.classList.add('code-editor');

        // flex-col 
        this._element.style.display = 'flex';
        this._element.style.flexDirection = 'column';

        // language selector
        this.languageSelector = document.createElement('select');
        this.languageSelector.classList.add('language-selector');
        this.languageSelector.style.marginBottom = '10px';
        this.languageSelector.style.padding = '5px';
        this.languageSelector.style.borderRadius = '5px';
        this.languageSelector.style.border = '1px solid #ccc';
        this.languageSelector.style.outline = 'none';
        this.languageSelector.style.fontSize = '14px';
        this.languageSelector.style.fontFamily = 'monospace';
        this.languageSelector.style.width = '100px';

        let option;
        let textOption;
        // add languages
        supportedLanguages.map(language => {
            option = document.createElement('option');
            option.setAttribute('value', language);
            textOption = document.createTextNode(language);
            option.appendChild(textOption);
            this.languageSelector.appendChild(option);
        })

        // if data is present, set the language
        if (this.data.language) {
            this.languageSelector.value = this.data.language;
        }

        // code editor
        this._editor = document.createElement('textarea');
        this._editor.classList.add('code-editor__textarea');
        this._editor.style.flex = '1';
        this._editor.style.borderRadius = '5px';
        this._editor.style.border = '1px solid #ccc';
        this._editor.style.outline = 'none';
        this._editor.style.fontSize = '14px';
        this._editor.style.fontFamily = 'monospace';
        this._editor.style.padding = '10px';
        this._editor.style.resize = 'none';

        // if data is present, set the code
        if (this.data.code) {
            this._editor.value = this.data.code;
        }

        // append to element
        this._element.appendChild(this.languageSelector);
        this._element.appendChild(this._editor);

        return this._element;
    }

    save(blockContent) {
        return {
            language: this.languageSelector.value,
            code: this._editor.value
        };
    }

    validate(savedData) {
        if (!savedData.code.trim()) {
            return false;
        }

        return true;
    }

    renderSettings() {
        const wrapper = document.createElement('div');

        // language selector
        this.languageSelector = document.createElement('select');
        this.languageSelector.classList.add('language-selector');
        this.languageSelector.style.marginBottom = '10px';
        this.languageSelector.style.padding = '5px';
        this.languageSelector.style.borderRadius = '5px';
        this.languageSelector.style.border = '1px solid #ccc';
        this.languageSelector.style.outline = 'none';
        this.languageSelector.style.fontSize = '14px';
        this.languageSelector.style.fontFamily = 'monospace';
        this.languageSelector.style.width = '100px';

        let option;
        let textOption;
        // add languages
        supportedLanguages.map(language => {
            option = document.createElement('option');
            option.setAttribute('value', language);
            textOption = document.createTextNode(language);
            option.appendChild(textOption);
            this.languageSelector.appendChild(option);
        })

        wrapper.appendChild(this.languageSelector);

        return wrapper;
    }
}

const supportedLanguages = [
    "plain",
    "plaintext",
    "text",
]

thucne avatar Sep 14 '22 06:09 thucne

I've just added an event listener that calls update by block id every time the selected value changes.

        this.languageSelector.addEventListener('change', () => {
            let blockId = this.api.blocks.getBlockByIndex(this.api.blocks.getCurrentBlockIndex()).id;
            this.api.blocks.update(blockId, {
                language: this.languageSelector.value,
                code: this._editor.value
            });
        })

If you guys have better solutions please let me know, thanks!

thucne avatar Sep 14 '22 07:09 thucne