# Source: ui/base/abstract-text-field.js

    /*global require, exports, document, Error*/
    var AbstractControl = require("./abstract-control").AbstractControl,
        KeyComposer = require("../../composer/key-composer").KeyComposer,
        deprecate = require('../../core/deprecate');

    /**
     * @class AbstractTextField
     * @extends AbstractControl
     */
    var AbstractTextField = exports.AbstractTextField = AbstractControl.specialize(/** @lends AbstractTextField# */ {

        /**
         * Dispatched when the textfield is activated when the user presses enter.
         * @event action
         * @memberof AbstractTextField
         * @param {Event} event
         */
        constructor: {
            value: function AbstractTextField() {
                if(this.constructor === AbstractTextField) {
                    throw new Error("AbstractTextField cannot be instantiated.");
                }

                this.defineBindings({
                    // classList management
                    "classList.has('montage--disabled')": {
                        "<-": "!enabled"
                    }
                });
            }
        },

        hasTemplate: {
            value: false
        },

        acceptsActiveTarget: {
            get: function () {
                return (this.callDelegateMethod("shouldBeginEditing", this) !== false);
            }
        },

        delegate: {
            value: null
        },

        enabled: {
            value: true
        },

        _placeholder: {
            value: null
        },

        placeholderValue: {
            set: function (value) {
                deprecate.deprecationWarning("placeholderValue", "placeholder");
                this.placeholder = value;
            },
            get: function () {
                return this.placeholder;
            }
        },

        placeholder: {
            set: function (value) {
                this._placeholder = value;
                this.needsDraw = true;
            },
            get: function () {
                return this._placeholder;
            }
        },

        _value: {
            value: null
        },

        value: {
            set: function (value) {
                if (value !== this._value) {
                    if (!this.hasFocus || this.callDelegateMethod("shouldAcceptValue", this, value)) {
                        this._value = value;
                        this.needsDraw = true;
                    }
                }
            },
            get: function () {
                return this._value;
            }
        },

        errorMessage: {
            value: null
        },

        /**
         * An optional converter for transforming the `value` into the
         * corresponding rendered text.
         * Converters are called at time of draw.
         * @type {?Converter}
         * @default null
         */
        converter: {
            value: null
        },

        _hasFocus: {
            value: false
        },

        hasFocus: {
            set: function (value) {
                this._hasFocus = value;
            },
            get: function () {
                return this._hasFocus;
            }
        },

        __keyComposer: {
            value: null
        },

        _keyComposer: {
            get: function () {
                if (!this.__keyComposer) {
                    this.__keyComposer = new KeyComposer();
                    this.__keyComposer.component = this;
                    this.__keyComposer.keys = "enter";
                    this.addComposer(this.__keyComposer);
                }

                return this.__keyComposer;
            }
        },

        handleKeyPress: {
            value: function (evt) {
                if (!this.enabled || evt.keyComposer !== this._keyComposer) {
                    return;
                }

                this.dispatchActionEvent();
            }
        },

        prepareForActivationEvents: {
            value: function () {
                this._keyComposer.addEventListener("keyPress", this, false);
            }
        },

        enterDocument: {
            value: function (firstTime) {
                if (firstTime) {
                    this.element.addEventListener("input", this, false);
                    this.element.addEventListener("change", this, false);
                }
            }
        },

        draw: {
            value: function () {
                var displayValue = this.value,
                    typeOfDisplayValue,

                    // FIXME: the cursor position should be also check in the new textField control
                    start = this.element.selectionStart,
                    end = this.element.selectionEnd;

                if (this.converter) {
                    displayValue = this.converter.convert(displayValue);
                }

                // need to be check after the converter convert the value.
                typeOfDisplayValue = typeof displayValue;

                if (displayValue === null || typeOfDisplayValue === "undefined") {
                    this.element.value = "";
                } else if (typeOfDisplayValue === "boolean" || typeOfDisplayValue === "object" || typeOfDisplayValue === "number") {
                    this.element.value = displayValue.toString();
                } else {
                    this.element.value = displayValue;
                }

                if (this.eventManager.activeTarget === this && typeof this.element.setSelectionRange === "function") {
                    // restore the previous cursor position.
                    // TODO: contenteditable?
                    this.element.setSelectionRange(start, end);
                }

                if (this._placeholder) {
                    this.element.setAttribute("placeholder", this._placeholder);
                }

                this.element.disabled = !this.enabled;
            }
        },

        handleChange: {
            value: function () {
                this._updateValueFromDom();
            }
        },

        handleInput: {
            value: function (event) {
                this._updateValueFromDom();
            }
        },

        willBecomeActiveTarget: {
            value: function (event) {
                this.hasFocus = true;
                this.callDelegateMethod("didBeginEditing", this);
            }
        },

        surrendersActiveTarget: {
            value: function (event) {
                if (this.callDelegateMethod("shouldEndEditing", this) === false) {
                    return false;
                }

                this._hasFocus = false;
                this.callDelegateMethod("didEndEditing", this);

                return true;
            }
        },

        _updateValueFromDom: {
            value: function () {

                var displayedValue, value;

                value = displayedValue = this.element.value;

                if (this.converter) {
                    try {
                        value = this.converter.revert(displayedValue);
                        this.errorMessage = null;

                    } catch (error) {
                        this.errorMessage = error.message || error;
                    }
                }

                if (this._value !== value) {
                    this._value = value;

                    this.dispatchOwnPropertyChange("value", this._value);
                    this.callDelegateMethod("didChange", this);
                }

                if (this.converter) {
                    //safer -> be sure this._value is set before request a draw.
                    this.needsDraw = true;
                }
            }
        }

    });