Как то форуме 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: