/**
 * A field version of [Froala Editor](https://www.froala.com). This allows you to use the Froala Editor
 * within a form and automatically have its name and value included in a form submit.
 */
Ext.define('Ext.froala.EditorField', {
    extend: 'Ext.form.field.Base',
    xtype: 'froalaeditorfield',
    mixins: {
        froalaeditor: 'Ext.froala.Mixin'
    },
 
    twoWayBindable: ['value'],
    defaultBindProperty: 'value',
 
    blankText: 'This field is required',
    allowBlank: true,
    baseCls: Ext.baseCSSPrefix + 'froala',
 
    /**
     * @event change
     * Fired when the html content changes
     * @param {Ext.froala.EditorField} this This component.
     * @param {String} the html content.
     */
 
    /**
     * @event ready
     * Fired after the FroalaEditor instance is initialized.
     * @param {Ext.froala.EditorField} this This component.
     * @param {Object} the FroalaEditor instance.
     */
 
    fieldSubTpl: [
        // note: {id} here is really {inputId}, but {cmpId} is available
        '<div id="{id}" data-ref="inputEl" {inputAttrTpl} class="{fieldCls}',
        '<tpl if="name"> name="{name}"</tpl>',
        '<tpl if="value"> value="{[Ext.util.Format.htmlEncode(values.value)]}"</tpl>',
        '<tpl if="placeholder"> placeholder="{placeholder}"</tpl>',
        '{%if (values.maxLength !== undefined){%} maxlength="{maxLength}"{%}%}',
        '<tpl if="readOnly"> readonly="readonly"</tpl>',
        '<tpl if="disabled"> disabled="disabled"</tpl>',
        '<tpl if="tabIdx != null"> tabindex="{tabIdx}"</tpl>',
        '<tpl if="fieldStyle"> style="{fieldStyle}"</tpl>',
        '<tpl if="ariaEl == \'inputEl\'">',
        '<tpl foreach="ariaElAttributes"> {$}="{.}"</tpl>',
        '</tpl>',
        '<tpl foreach="inputElAriaAttributes"> {$}="{.}"</tpl>',
        '></div>',
        {
            disableFormats: true
        }
    ],
 
    activeErrorsTpl: undefined,
 
    htmlActiveErrorsTpl: [
        '<tpl if="errors && errors.length">',
        '<ul class="{listCls}">',
        '<tpl for="errors"><li>{.}</li></tpl>',
        '</ul>',
        '</tpl>'
    ],
 
    getFroalaEditorDomElement: function() {
        return this.inputEl.dom;
    },
 
    initComponent: function() {
        var me = this;
 
        me.initiateFroala(arguments);
        me.callParent();
 
    },
 
    initiateFroala: function() {
        var me = this,
            config = me.config,
            editor;
 
        delete config.$initParent;
 
        // validate the field on undo and redo options
        if (!me.allowBlank) {
            config.events = {
                'commands.undo': function() {
                    me.validate();
                },
                'commands.redo': function() {
                    me.validate();
                    me.isValid();
                }
            };
        }
 
        me.froalaEl = new Ext.fly(document.createElement('div'));
 
        editor = me.mixins.froalaeditor.createFroalaEditor.call(me, config, me.froalaEl.dom);
        me.setEditor(editor);
    },
 
    afterRender: function() {
        var me = this,
            config = Ext.clone(me.config, false);
 
        delete config.$initParent;
        // to make form field borders align with froala
        me.addCls('curved-form-field-border');
 
        me.inputEl.appendChild(me.froalaEl.dom);
 
        // To validate field if value is binded
        if (!Ext.isEmpty(!me.allowBlank)) {
            me.validate();
        }
    },
 
    doDestroy: function() {
        this.setEditor(null);
        this.callParent();
    },
 
    setValue: function(value) {
        this.updateValue(value);
    },
 
    getValue: function() {
        var me = this,
            editor = me.editor,
            value;
 
        if (editor) {
            value = editor.el && editor.el.innerHTML;
 
            // There is &zerowidthspace; when ever we add and remove a character 
            // Hence removing any unwanted character while checking for the value.
            return value.replace(/[\u200B-\u200D\uFEFF]/g, '') === '<p><br></p>' ? '' : value;
        }
    },
 
    getRawValue: function() {
        var value = this.getValue();
 
        this.rawValue = value;
 
        return value;
    },
 
    getErrors: function(value) {
        var me = this,
            errors;
 
        value = this.getRawValue();
        errors = me.callParent([value]);
 
        if (value.length < 1) {
            if (!me.allowBlank) {
                errors.push(me.blankText);
            }
        }
 
        return errors;
    },
 
    updateValue: function(value) {
        this.mixins.froalaeditor.updateValue.call(this, value);
    },
 
    updateDisabled: function(disabled) {
        this.mixins.froalaeditor.updateDisabled.call(this, disabled);
    },
 
    privates: {
        // Overrides a private method in Ext.mixin.Observable
        doAddListener: function(ename) {
            var me = this,
                result;
 
            // It's safer to use arguments here, since there are so
            // many ways listener parameters are used.
            result = me.callParent(arguments);
 
            me.mixins.froalaeditor.handleAddListener.call(me, ename);
 
            return result;
        },
 
        // Overrides a private method in Ext.mixin.Observable
        doRemoveListener: function(ename) {
            var me = this,
                result;
 
            // It's safer to use arguments here, since there are so
            // many ways listener parameters are used.
            result = me.callParent(arguments);
 
            me.mixins.froalaeditor.handleRemoveListener.call(me, ename);
 
            return result;
        },
        // to show invalid text on editor input element
        getActionEl: function() {
            return (this.editor ? Ext.get(this.editor.el) : this.el);
        }
    }
});