DaQuirm/nexus

View on GitHub
src/core/cell.js

Summary

Maintainability
A
25 mins
Test Coverage
var nx = {
    Binding: require('./binding'),
    Event:   require('./event'),
    Mapping: require('./mapping')
};

var flatMethods = [
    '<-*', '<<-*', '->*', '->>*',
    '*->', '*->>', '*<-', '*<<-'
];

nx.Cell = function (options) {
    options = options || {};

    this._history = [];
    if (typeof options.value !== 'undefined') {
        this._value = options.value;
        this._history = [options.value];
    }

    this._bindingIndex = 0;
    this.bindings = {};

    this.onvalue = new nx.Event();
    if (typeof options.action !== 'undefined') {
        this.onvalue.add(options.action);
    }

    ['->', '<-', '<<-', '->>', '<->']
        .concat(flatMethods)
        .forEach(function (method) {
            if (typeof options[method] !== 'undefined') {
                this[method].apply(this, options[method]);
            }
        }, this);
};

Object.defineProperty(nx.Cell.prototype, 'value', {
    enumerable : true,
    get: function () { return this._value; },
    set: function (value) {
        this._history = [value, this._value];
        this._value = value;
        this.onvalue.trigger.apply(this.onvalue, this._history);
        for (var index in this.bindings) {
            var binding = this.bindings[index];
            var hasTwin = typeof binding.twin !== 'undefined';
            if (hasTwin) {
                binding.twin.lock();
            }
            binding.sync.apply(binding, this._history);
            if (hasTwin) {
                binding.twin.unlock();
            }
        }
    }
});

nx.Cell.prototype._createBinding = function (cell, conversion) {
    var binding = new nx.Binding(this, cell, conversion);
    binding.index = this._bindingIndex;
    this.bindings[this._bindingIndex++] = binding;
    return binding;
};

nx.Cell.prototype['->'] = function (cell, conversion, sync) {
    var binding = this._createBinding(cell, conversion);
    if (sync) {
        binding.sync.apply(binding, this._history);
    }
    return binding;
};

nx.Cell.prototype['<-'] = function (arg, conversion, sync) {
    var values;
    var _this = this;
    if (Array.isArray(arg)) {
        values = new Array(arg.length);
        return arg.map(function (cell, index) {
            values[index] = cell.value;
            return cell['->'](_this, function (value) {
                values[index] = value;
                return conversion.apply(null, values);
            }, sync);
        });
    }
    return arg['->'](this, conversion, sync);
};

nx.Cell.prototype['->>'] = function (cell, conversion) {
    return this['->'](cell, conversion, true);
};

nx.Cell.prototype['<<-'] = function (cell, conversion) {
    return this['<-'](cell, conversion, true);
};

nx.Cell.prototype['<->'] = function (cell, conversion, backConversion, sync) {
    if (conversion instanceof nx.Mapping) {
        backConversion = backConversion || conversion.inverse();
    }
    var binding = this._createBinding(cell, conversion);
    var backBinding = cell._createBinding(this, backConversion);
    binding.pair(backBinding);
    if (sync === '->') {
        binding.sync.apply(binding, this._history);
    } else if (sync === '<-') {
        backBinding.sync.apply(backBinding, cell._history);
    }
    return [binding, backBinding];
};

nx.Cell.prototype['<->>'] = function (cell, conversion, backConversion) {
    this['<->'](cell, conversion, backConversion, '->');
};

nx.Cell.prototype['<<->'] = function (cell, conversion, backConversion) {
    this['<->'](cell, conversion, backConversion, '<-');
};

nx.Cell.prototype.bind = function (cell, mode, conversion, backConversion) {
    this[mode](cell, conversion, backConversion);
};

nx.Cell.prototype._flatBind = function (cell, selector, conversion, method) {
    var _this = this;
    var binding;

    var getTarget = function (value) {
        var type = typeof selector;
        if (type === 'string') {
            return value[selector];
        } else if (type === 'function') {
            return selector(value);
        }
    };

    var bind = function (value) {
        if (typeof binding !== 'undefined') {
            binding.unbind();
        }
        var target = getTarget(value);
        binding = _this[method](target, conversion);
    };

    if (typeof cell.value !== 'undefined') {
        bind(cell.value);
    }
    cell.onvalue.add(bind);
};

flatMethods.forEach(function (method) {
    nx.Cell.prototype[method] = function (cell, selector, conversion) {
        this._flatBind(cell, selector, conversion, method.replace('*', ''));
    };
});

module.exports = nx.Cell;