rivets-bfeach-binder.js 5.97 KB
define(function(require) {
    'use strict';
    var Backbone = require('backbone');
    var rivets = require('rivets');
    var Sightglass = require('sightglass');

    var setStack = (function(sightglassPrototype) {
        var origSet = sightglassPrototype.set;
        var setStack = [];
        sightglassPrototype.set = function set(active, key, obj, callback) {
            try {
                setStack.push(arguments);
                return origSet.apply(this, arguments);
            } finally {
                setSack.pop();
            }
        };
        return setStack;
    })(Sightglass.prototype);

    var bfEachUtil = {
        makeOverrideAdapters: function makeOverrideAdapters(parentAdapters, roData) {
            function getStackPath() {
                var currentStackPath = ''; 
                _.each(setStack, function(stackFrame, stackFrameIndex) {
                    var key = stackFrame[1];
                    currentStackPath += key.i + key.path;
                });
                return currentStackPath;
                currentStackPath += interfaceKey + leafKey;
                if (currentStackPath in roData) {
                    givenObj = roData[currentStackPath];
                }
                return givenObj;
            };
            var subAdapters = {};
            _.each(parentAdapters, function(adapterFunctions, interfaceKey) {
                var subAdapter = {};
                subAdapter.observe = function(obj, key, cb) {
                    var stackPath = getStackPath();
                    if (stackPath + interfaceKey + key in roData) {
                        return;
                    } else if (stackPath in roData) {
                        obj = roData[stackPath];
                    }
                    return adapterFunctions.observe(obj, key, cb);
                };
                subAdapter.unobserve = function(obj, key, cb) {
                    var stackPath = getStackPath();
                    if (stackPath in roData) {
                        obj = roData[stackPath];
                    }
                    if (stackPath + interfaceKey + key in roData) {
                        return;
                    } else if (stackPath in roData) {
                        obj = roData[stackPath];
                    }
                    return adapterFunctions.unobserve(obj, key, cb);
                };
                subAdapter.get = function(obj, key) {
                    var stackPath = getStackPath();
                    if (stackPath in roData) {
                        obj = roData[stackPath];
                    }
                    var fullKeyPath = stackPath + interfaceKey + key;
                    if (fullKeyPath in roData) {
                        return roData[fullKeyPath];
                    } else if (stackPath in roData) {
                        obj = roData[stackPath];
                    }
                    return adapterFunctions.get(obj, key);
                };
                subAdapter.set = function(obj, key, value) {
                    var stackPath = getStackPath();
                    if (stackPath in roData) {
                        obj = roData[stackPath];
                    }
                    var fullKeyPath = stackPath + interfaceKey + key;
                    if (fullKeyPath in roData) {
                        return roData[fullKeyPath];
                    } else if (stackPath in roData) {
                        obj = roData[stackPath];
                    }
                    return adapterFunctions.set(obj, key, value);
                };
                if (adapterFunctions.iterate) {
                    subAdapter.iterate = adapterFunctions.iterate;
                }
                subAdapters[interfaceKey] = subAdapter;
            });
            return subAdapters;
        },
        getIterator: function getIterator(adapter) {
            return adapter.iterate || function iterate(obj, cb) {
                obj = obj || [];
                var i;
                for (i = 0; i < obj.length; i++) {
                    cb(obj[i], i);
                }
            };
        },
    };

    (function(rivetsBinders) {
        rivetsBinders['bfeach-*'] = {
            block: true,
            bind: rivetsBinders['each-*'].bind,
            unbind: rivetsBinders['each-*'].unbind,

            routine: function(el, value) {
                var parentView = this.view;
                var observer = this.observer;
                var adapters = observer.options.adapters;
                var iterate = bfEachUtil.getIterator(adapters[observer.key.i]);

                var rootInterface = observer.tokens.length ? observer.tokens[0].i : observer.key.i;
                var modelName = this.args[0];
                var iterationAlias = rivets.iterationAlias(modelName);
                var iterated = this.iterated;
                var previous = this.marker;
                iterate(value, function(value, index) {
                    if (iterated[index] === undefined) {
                        var subData = {};
                        subData[rootInterface + 'index'] = index;
                        subData[rootInterface + modelName] = value;
                        subData[rootInterface + iterationAlias] = index;

                        var options = parentView.options();
                        options.preloadData = true;
                        options.adapters = bfEachUtil.makeOverrideAdapters(options.adapters, subData);
                        var template = el.cloneNode(true);
                        var childView = new rivets._.View(template, parentView.models, options);
                        childView.bind();
                        iterated.push(childView);
                        previous.parentNode.insertBefore(template, previous.nextSibling);
                        previous = template;
                    } else {
                        iterated[index].update(value);
                    }
                });
            },
        };
    })(rivets.binders);
    return bfEachUtil;
});