Bernardstanislas
10/1/2015 - 3:12 PM

Autocomplete

Autocomplete

// Dependencies
'use strict';

var React = __webpack_require__(124);
var builder = __webpack_require__(406).component.builder;
var types = __webpack_require__(406).component.types;
var find = __webpack_require__(755);

// Components

var Autocomplete = __webpack_require__(844).component;

/**
 * Autocomplete for component
 * @type {Object}
 */
var AutocompleteFor = {
    /**
     * Default props
     * @return {Object} default props
     */
    getDefaultProps: function getDefaultProps() {
        return {
            AutocompleteComp: Autocomplete,
            pickList: [],
            value: ''
        };
    },
    /**
     * Props validation
     * @type {Object}
     */
    propTypes: {
        AutocompleteComp: types('func'),
        allowUnmatchedValue: types('bool'),
        codeResolver: types('func'),
        isEdit: types('bool'),
        onInputBlur: types('func'),
        pickList: types('array'),
        searcher: types('func'),
        selectionHandler: types('func'),
        value: types('string')
    },
    /**
     * Get initial state
     * @return {Object} initial state
     */
    getInitialState: function getInitialState() {
        var pickList = this.props.pickList;

        return { pickList: pickList };
    },
    /**
     * Component will mount, load the list
     */
    componentWillMount: function componentWillMount() {
        var _this = this;

        var _props = this.props;
        var isEdit = _props.isEdit;
        var value = _props.value;
        var codeResolver = _props.codeResolver;

        if (!isEdit && value && codeResolver) {
            // Resolve the code if in consult
            codeResolver(value).then(function (resolvedCode) {
                return _this.setState({ value: resolvedCode });
            });
        } else {
            this._doLoad();
        }
    },
    componentWillReceiveProps: function componentWillReceiveProps(_ref) {
        var _this2 = this;

        var codeResolver = _ref.codeResolver;
        var value = _ref.value;

        if (value !== this.props.value) {
            codeResolver(value).then(function (resolvedCode) {
                return _this2.setState({ value: resolvedCode });
            });
        }
    },
    /**
     * List loader
     * @param  {string} text='' input text to search from
     */
    _doLoad: function _doLoad() {
        var _this3 = this;

        var text = arguments.length <= 0 || arguments[0] === undefined ? '' : arguments[0];
        var searcher = this.props.searcher;

        if (searcher) {
            searcher(text).then(function (pickList) {
                return _this3.setState({ pickList: pickList });
            });
        }
    },
    /**
     * Get value of the field
     * @return {string} the code of the curren value
     */
    getValue: function getValue() {
        var autocomplete = this.refs.autocomplete;

        return autocomplete ? autocomplete.getValue() : this.state.value;
    },
    /**
     * Render the edit mode
     * @return {HTML} rendered element
     */
    _renderEdit: function _renderEdit() {
        var _props2 = this.props;
        var AutocompleteComp = _props2.AutocompleteComp;
        var allowUnmatchedValue = _props2.allowUnmatchedValue;
        var onInputBlur = _props2.onInputBlur;
        var selectionHandler = _props2.selectionHandler;
        var code = _props2.value;
        var pickList = this.state.pickList;

        return React.createElement(AutocompleteComp, {
            allowUnmatchedValue: allowUnmatchedValue,
            code: code,
            inputChangeHandler: this._doLoad,
            onInputBlur: onInputBlur,
            pickList: pickList,
            ref: 'autocomplete',
            selectionHandler: selectionHandler
        });
    },
    /**
     * Render the consult mode
     * @return {HTML} rendered element
     */
    _renderConsult: function _renderConsult() {
        var value = this.state.value;
        var code = this.props.value;

        return React.createElement(
            'span',
            null,
            value ? value : code
        );
    },
    /**
     * Render the component
     * @return {HTML} the rendered component
     */
    render: function render() {
        var isEdit = this.props.isEdit;

        return false === isEdit ? this._renderConsult() : this._renderEdit();
    }
};

module.exports = builder(AutocompleteFor);
var Autocomplete = {
    /**
     * Component will mount.
     * Check if the Awesomplete library is in the Window object.
     */
    componentWillMount: function componentWillMount() {
        // Check if Awesomplete is set in Window
        if (!window.Awesomplete) {
            throw new Error('Please include Awesomplete to your application. See http://leaverou.github.io/awesomplete/ for more information');
        }
    },
    /**
     * Component did mount.
     * Initiates the Awesomplete object.
     */
    componentDidMount: function componentDidMount() {
        var _this = this;

        var input = this.refs.input.refs.inputText;
        var _props = this.props;
        var code = _props.code;
        var codeResolver = _props.codeResolver;
        var pickList = _props.pickList;

        this._awesomeplete = new Awesomplete(React.findDOMNode(input), {
            list: this._extractListFromData(pickList)
        });
        this._awesomeplete.input.addEventListener('awesomplete-select', function (event) {
            return _this._selectionHandler(event.text);
        });
        this._resolveValueFromPicklistOrCodeResolver(code, pickList);
    },
    /**
     * Default props.
     * @return {Object} default props
     */
    getDefaultProps: function getDefaultProps() {
        return {
            code: '',
            pickList: [],
            timeoutDuration: 200,
            allowUnmatchedValue: true
        };
    },
    /**
     * Prop validation
     * @type {Object}
     */
    propTypes: {
        allowUnmatchedValue: types('bool'), // restrict user input to values of the list, or allow freestyle
        code: types('string'), // the field code value
        inputChangeHandler: types('func'), // callback when input changed
        onInputBlur: types('func'),
        pickList: types('array'), // list of values, looking like [{code: '', value: ''}, {code: '', value: ''}, ...]
        selectionHandler: types('func'), // selection callback
        timeoutDuration: types('number') // the throttle duration of the input rate
    },
    /**
     * Initial state.
     * Retrieve the value from the provided code and pick list.
     * @return {Object} initial state
     */
    getInitialState: function getInitialState() {
        var _props2 = this.props;
        var code = _props2.code;
        var pickList = _props2.pickList;

        return {
            value: 0 < pickList.length ? this._getValueFromCode(code) : code
        };
    },
    /**
     * Component will receive props.
     * Update the pick list, and try to resolve the new value.
     * @param  {Object} nextProps new props
     */
    componentWillReceiveProps: function componentWillReceiveProps(_ref) {
        var pickList = _ref.pickList;
        var code = _ref.code;

        if (code !== this.props.code) {
            this._resolveValueFromPicklistOrCodeResolver(code, pickList);
        }
        this._awesomeplete._list = this._extractListFromData(pickList);
    },
    _resolveValueFromPicklistOrCodeResolver: function _resolveValueFromPicklistOrCodeResolver(code, pickList) {
        var _this2 = this;

        var codeResolver = this.props.codeResolver;

        var value = this._getValueFromCode(code, pickList);
        if ('' !== value) {
            this.setState({ value: value }); // eslint-disable-line
        } else if (codeResolver) {
                codeResolver(code).then(function (resolvedValue) {
                    if ('' !== resolvedValue) {
                        _this2.setState({ value: resolvedValue }, function () {
                            _this2.props.inputChangeHandler(resolvedValue);
                        }); // eslint-disable-line
                    }
                });
            }
    },
    /**
     * Selection handler.
     * If a selection handler is set in the props, send it the selected pick.
     * Also, set a flag to tell the blur listener not to empty the value, because the selection, as it is a click outside the input, raises a blur event.
     * @param  {String} value selected value from the dropdown list
     */
    _selectionHandler: function _selectionHandler(value) {
        var selectionHandler = this.props.selectionHandler;

        if (selectionHandler) {
            var pickList = this.props.pickList;

            var selectedPick = find(pickList, { value: value });
            selectionHandler(selectedPick);
        }
        this._isSelecting = true; // Private flag to tell the blur listener not to replace the value
        this.setState({ value: value });
    },
    /**
     * Extract list of suggestions from pick list
     * @param  {Object} data the pick list
     * @return {Array}      the suggestion array
     */
    _extractListFromData: function _extractListFromData(data) {
        return data.map(function (datum) {
            return datum.value;
        });
    },
    /**
     * Get code from value in the pick list
     * @param  {String} value the value
     * @return {String} the code
     */
    _getCodeFromValue: function _getCodeFromValue(value) {
        var pickList = this.props.pickList;

        var pick = find(pickList, { value: value });
        return pick ? pick.code : pick;
    },
    /**
     * Get value from code in the pick list
     * @param  {String} code the code
     * @param  {Object} pickList=this.props.pickList  optional pick list to resolve the value from
     * @return {String} value
     */
    _getValueFromCode: function _getValueFromCode(code) {
        var pickList = arguments.length <= 1 || arguments[1] === undefined ? this.props.pickList : arguments[1];

        var pick = find(pickList, { code: code });
        return pick ? pick.value : '';
    },
    /**
     * Get the current code
     * @return {String} the code
     */
    getValue: function getValue() {
        var value = this.state.value;
        var allowUnmatchedValue = this.props.allowUnmatchedValue;

        var computedValue = this._getCodeFromValue(value);
        return computedValue ? computedValue : allowUnmatchedValue ? value : undefined;
    },
    /**
     * On input blur.
     * If allowUnmatchedValue is set in the props, validate the current value and erase it if not valid.
     */
    _onInputBlur: function _onInputBlur() {
        var value = this.state.value;
        var _props3 = this.props;
        var allowUnmatchedValue = _props3.allowUnmatchedValue;
        var onInputBlur = _props3.onInputBlur;
        var pickList = _props3.pickList;
        var selectionHandler = _props3.selectionHandler;

        var selectedPick = find(pickList, { value: value });
        var code = this._getCodeFromValue(value);
        if (selectedPick && !this._isSelecting && selectionHandler) {
            selectionHandler(selectedPick);
        }
        if (!code && !allowUnmatchedValue && !this._isSelecting) {
            this.setState({ value: '' });
        }
        if (onInputBlur) {
            onInputBlur();
        }
        this._isSelecting = false;
    },
    /**
     * On input change
     * @param  {Object} event change event
     */
    _onInputChange: function _onInputChange(event) {
        var _this3 = this;

        var value = event.target.value;
        var timeoutDuration = this.props.timeoutDuration;

        this.setState({ value: value });
        if (this._changeTimeout) {
            clearTimeout(this._changeTimeout);
        }
        this._changeTimeout = setTimeout(function () {
            var inputChangeHandler = _this3.props.inputChangeHandler;

            if (inputChangeHandler) {
                inputChangeHandler(value);
            }
        }, timeoutDuration);
    },
    /**
     * Render
     * @return {HTML} rendered element
     */
    render: function render() {
        var value = this.state.value;
        var _onInputBlur = this._onInputBlur;
        var _onInputChange = this._onInputChange;

        return React.createElement(
            'div',
            { 'data-focus': 'autocomplete' },
            React.createElement(InputText, { onBlur: _onInputBlur, onChange: _onInputChange, ref: 'input', value: value })
        );
    }
};