Добавляем Ace Editor в приложение ExtJS

Как то форуме sencha возник вопрос: «Кто-нибудь знает, как добавить поле ввода в форму, которое бы являлась Ace Editor’ом?». Поэтому я решил реализовать такое поле.

В данной статье я попытался реализовать новое поле формы в базе класса Ext.form.field.Base и сделать похожим на другие поля формы extjs. Поле запускает событие «change», имеет проверки и информацию, ошибки и предупреждения. Надеюсь, код скажет сам за себя.

Ext.define('AceEditorTextArea', {
    extend: 'Ext.form.field.Base',
    alias: 'widget.aceeditortextarea',

    fieldSubTpl: [
        '<div foo="aaa" id="{aceWrapperDivId}" ',
            'style="min-height: {minHeight}px; height: {height}px"',
            '<tpl if="fieldStyle"> style="{fieldStyle}"</tpl>',
            '<tpl if="fieldCls"> class="{fieldCls}"</tpl>',
        '>',
            '<div id="{aceDivId}" ',
                'style="min-height: {minHeight}px; height: {height}px"',
            '></div>',
        '</div>',
    ],

    defaultAceEditorOptions: {
        highlightActiveLine: true,
        showPrintMargin: false
    },

    aceOptions: {},
    value: '',
    lastValue: '',

    minHeight: 58,
    allowBlank: true,
    blankText: "This field is required",

    extraFieldBodyCls: Ext.baseCSSPrefix + 'form-text-wrap-default',
    invalidCls: Ext.baseCSSPrefix + 'form-invalid-ace-field-default',

    initComponent: function () {
        this.on('afterrender', this.initAceEditor, this);
        this.callParent();
    },

    getAceEditor: function () {
        if (!this.aceEditor) {
            this.aceEditor = ace.edit(this.getAceDivId());
        }
        return this.aceEditor;
    },

    initAceEditor: function () {
        var me = this,
            aceOptions = Ext.Object.merge(
                this.defaultAceEditorOptions,
                this.aceOptions
            );

        this.getAceEditor().setOptions(aceOptions);
        this.getAceEditor().getSession().setValue(this.getValue());
        this.getAceEditor().getSession().setMode(this.defaultAceEditorOptions.mode);

        this.getAceEditor().getSession().on('change', function () {
            me.onChange.call(me);
        });
    },

    onChange: function () {
        this.lastValue = this.value;
        this.value = this.getAceEditor().getSession().getValue();
        this.isCodeValid();
        this.fireEvent('change', this, this.value, this.lastValue);
        this.callParent([this.value, this.lastValue]);
    },

    isCodeValid: function () {
        var annotations = this.getAceEditor().getSession().getAnnotations();
        if (annotations.length > 0) {
            this.fireEvent('annotation', annotations);
        }
        Ext.Array.each(annotations, function (annotation) {
            if (annotation.type == 'info') {
                this.fireEvent('infoannotation');
                return false;
            }
        }, this);

        Ext.Array.each(annotations, function (annotation) {
            if (annotation.type == 'error') {
                this.fireEvent('errorannotation');
                return false;
            }
        }, this);

        Ext.Array.each(annotations, function (annotation) {
            if (annotation.type == 'warning') {
                this.fireEvent('worningannotation');
                return false;
            }
        }, this);
        return this;
    },

    getValue: function () {
        var value = this.value;
        return value;
    },

    getSubmitValue: function () {
        var value = this.value;
        return value;
    },

    getSubTplData: function (fieldData) {

        fieldData.aceWrapperDivId = this.getAceWrapperDivId();
        fieldData.aceDivId = this.getAceDivId();
        fieldData.height = this.height || this.minHeight;
        fieldData.minHeight = this.minHeight;
        fieldData.fieldCls = this.fieldCls;

        return fieldData;
    },

    getAceWrapperDivId: function () {
        return this.getId() + '-aceDivWrapperId';
    },

    getAceWrapperEl: function() {
        return Ext.get(this.getAceWrapperDivId());
    },

    getAceDivId: function () {
        return this.getId() + '-aceDivId';
    },

    getErrors: function (value) {
        var errors = this.callParent([value]);

        if (!this.allowBlank && this.value.length == 0) {
            errors.push(this.blankText);
        }

        if(errors && errors.length > 0) {
            this.getAceWrapperEl().addCls(this.invalidCls);
        } else {
            this.getAceWrapperEl().removeCls(this.invalidCls);
        }
        return errors;
    }
});

Я также добавил тривиальные события, чтобы отключить / включить или проверить поле. Если вы будете использовать этот код и захотите добавить некоторые новые функции, эти события могут помочь вам в тестировании.

Fiddle:

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *