04d7f787 by Adam Heath

First pass.

1 parent 155b7073
.*.sw?
/.grunt/
/node_modules/
/src/lib/bower/
/dist/
/* global module */
module.exports = function (grunt) {
/* global require */
'use strict';
var config = {};
config.base = 'src';
config.jshint = {
options: {
},
browserOptions: {
},
};
config.bower = {
directory: 'lib/bower',
};
config.jscs = {
options: {
validateIndentation: 4,
reporter: 'console',
maxErrors: -1,
},
};
config.jasmine = {
withCoverage: true,
};
var montyPython = require('grunt-monty-python')(grunt);
montyPython.createConfig(config);
};
{
"name": "rivets-bfeach-binder",
"version": "0.0.0",
"authors": [
"Adam Heath <doogie@brainfood.com>"
],
"main": [
"src/scripts/rivets-bfeach-binder.js"
],
"private": true,
"ignore": [
"**/.*",
"node_modules",
"src/lib"
],
"dependencies": {
"backbone": "",
"backbone-validation": "",
"rivets-backbone-adapter-brainfood": "git@gitlab.brainfood.com:brainfood/rivets-backbone-adapter-brainfood.git",
"backbone-model-overlay": "git@gitlab.brainfood.com:brainfood/backbone-model-overlay.git",
"jquery": "",
"requirejs": "",
"rivets": "",
"underscore": ""
}
}
{
"name": "rivets-bfeach-binder",
"version": "0.0.0",
"main": [
"src/scripts/rivets-bfeach-binder.js"
],
"dependencies": {
"rivets": "",
"requirejs": ""
},
"devDependencies": {
"bower-requirejs": "~0.9.2",
"grunt": "~0",
"grunt-monty-python": "git+ssh://git@gitlab.brainfood.com:brainfood/grunt-monty-python.git"
},
"engines": {
"node": ">=0.8.0"
}
}
/* global require:true */
var require;
require = (function() {
'use strict';
var require = {
baseUrl: 'scripts',
config: {},
shim: {
rivets: {
deps: ['jquery'],
},
},
_map: {
'*': {
'sightglass': 'sightglass-overlay',
},
'sightglass-overlay': {
'sightglass': 'sightglass',
},
},
paths: {
backbone: '../lib/bower/backbone/backbone',
underscore: '../lib/bower/underscore/underscore',
sightglass: '../lib/bower/sightglass/index',
rivets: '../lib/bower/rivets/dist/rivets',
jquery: '../lib/bower/jquery/dist/jquery',
'rivets-backbone-adapter-brainfood': '../lib/bower/rivets-backbone-adapter-brainfood/src/scripts/rivets-backbone-adapter-brainfood',
'backbone-model-overlay': '../lib/bower/backbone-model-overlay/src/scripts/backbone-model-overlay',
},
};
return require;
})();
/* global require */
define(function() {
'use strict';
});
define(function(require) {
'use strict';
var Backbone = require('backbone');
var rivets = require('rivets');
var BackboneModelOverlay = require('backbone-model-overlay');
var bfEachUtil = {
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: function(el) {
var insertionPoint = this.insertionPoint;
if (this.insertionPoint === undefined) {
var type = this.type, parentNode = el.parentNode;
this.insertionPoint = insertionPoint = document.createComment(' rivets: ' + type + ' ');
el.removeAttribute([this.view.prefix, type].join('-').replace('--', '-'));
this.subItems = [];
parentNode.insertBefore(insertionPoint, el);
parentNode.removeChild(el);
} else {
var i;
var subItems = this.subItems;
for (i = 0; i < subItems.length; i++) {
subItems[i].view.bind();
}
}
},
unbind: function(el) {
var i;
var subItems = this.subItems;
for (i = 0; i < subItems.length; i++) {
subItems[i].view.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 subItems = this.subItems;
var insertionPoint = this.insertionPoint;
var newItemCount = 0;
iterate(value, function(value, index) {
var subItem = subItems[index];
var subData = {};
subData[modelName] = value;
subData['index'] = index;
subData[iterationAlias] = index;
if (subItem === undefined) {
var clonedEl = el.cloneNode(true);
subItem = {model: new BackboneModelOverlay(subData, {parent: parentView.models}), el: clonedEl};
var options = parentView.options();
options.preloadData = true;
//options.adapters = bfEachUtil.makeOverrideAdapters(options.adapters, subData);
subItem.view = rivets.bind(clonedEl, subItem.model, options);
subItems.push(subItem);
insertionPoint.parentNode.insertBefore(clonedEl, insertionPoint.nextSibling);
} else {
subItem.model.set(subData, {overlay: true});
}
insertionPoint = subItem.el;
newItemCount++;
});
while (subItems.length > newItemCount) {
var extraItem = subItems.pop();
extraItem.view.unbind();
extraItem.el.parentNode.removeChild(extraItem.el);
}
},
// update function not needed
};
})(rivets.binders);
return bfEachUtil;
});
define(function(require) {
'use strict';
var $ = require('jquery');
window.jQuery = $;
var RivetsBFEachUtil = require('rivets-bfeach-binder');
require('rivets-backbone-adapter-brainfood');
var _ = require('underscore');
var Backbone = require('backbone');
var rivets = require('rivets');
//rivets.config.rootInterface = ':';
/* global console:false */
describe('RivetsBFEachUtil', function() {
var rootScope, rootNode;
beforeEach(function() {
rootScope = new Backbone.Model({
sub: new Backbone.Model({
subKey: 'sub-key',
list: new Backbone.Collection([
{key: 'A'},
{key: 'B'},
{key: 'C'},
], {parse: true}),
}),
list: new Backbone.Collection([
{key: 'A'},
{key: 'B'},
{key: 'C'},
], {parse: true}),
constant: 'this-is-a-constant',
});
rootNode = $($.parseHTML('<div>{:constant}<div rv-bfeach-item=":list">key:{:item:key} constant:{:constant}<ul><li rv-bfeach-subitem=":sub:list">sub-key:{:subitem:key} constant:{:constant}<input rv-value=":inputValue" /></li></ul></div></div>'));
});
it('returns defined', function() {
expect(RivetsBFEachUtil).toBeDefined();
});
describe('binder', function() {
var rivetsView;
beforeEach(function() {
rivetsView = rivets.bind(rootNode, rootScope);
});
it('first-pass', function() {
var subListHtml = '<ul><!-- rivets: bfeach-subitem --><li>sub-key:A constant:this-is-a-constant<input rv-value=":inputValue"></li><li>sub-key:B constant:this-is-a-constant<input rv-value=":inputValue"></li><li>sub-key:C constant:this-is-a-constant<input rv-value=":inputValue"></li></ul>';
expect(rootNode.html()).toEqual(
'this-is-a-constant' +
'<!-- rivets: bfeach-item -->' +
'<div>key:A constant:this-is-a-constant' + subListHtml + '</div>' +
'<div>key:B constant:this-is-a-constant' + subListHtml + '</div>' +
'<div>key:C constant:this-is-a-constant' + subListHtml + '</div>'
);
});
describe('add-insert', function() {
beforeEach(function() {
rootScope.get('list').add({key: 'D'}, {at: -1, parse: true});
rootScope.get('list').add({key: 'preA'}, {at: 0, parse: true});
});
it('test', function() {
var subListHtml = '<ul><!-- rivets: bfeach-subitem --><li>sub-key:A constant:this-is-a-constant<input rv-value=":inputValue"></li><li>sub-key:B constant:this-is-a-constant<input rv-value=":inputValue"></li><li>sub-key:C constant:this-is-a-constant<input rv-value=":inputValue"></li></ul>';
expect(rootNode.html()).toEqual(
'this-is-a-constant' +
'<!-- rivets: bfeach-item -->' +
'<div>key:preA constant:this-is-a-constant' + subListHtml + '</div>' +
'<div>key:A constant:this-is-a-constant' + subListHtml + '</div>' +
'<div>key:B constant:this-is-a-constant' + subListHtml + '</div>' +
'<div>key:C constant:this-is-a-constant' + subListHtml + '</div>' +
'<div>key:D constant:this-is-a-constant' + subListHtml + '</div>'
);
});
describe('update-constant', function() {
var subListHtml = '<ul><!-- rivets: bfeach-subitem --><li>sub-key:A constant:updated-constant<input rv-value=":inputValue"></li><li>sub-key:B constant:updated-constant<input rv-value=":inputValue"></li><li>sub-key:C constant:updated-constant<input rv-value=":inputValue"></li></ul>';
var wantedHtml =
'updated-constant' +
'<!-- rivets: bfeach-item -->' +
'<div>key:preA constant:updated-constant' + subListHtml + '</div>' +
'<div>key:A constant:updated-constant' + subListHtml + '</div>' +
'<div>key:B constant:updated-constant' + subListHtml + '</div>' +
'<div>key:C constant:updated-constant' + subListHtml + '</div>' +
'<div>key:D constant:updated-constant' + subListHtml + '</div>';
beforeEach(function() {
rootScope.set('constant', 'updated-constant');
});
it('test', function() {
expect(rootNode.html()).toEqual(wantedHtml);
});
describe('unbind+change', function() {
beforeEach(function() {
rivetsView.unbind();
rootScope.set('constant', 'changed-constant');
});
it('test', function() {
expect(rootNode.html()).toEqual(wantedHtml);
});
describe('bind', function() {
beforeEach(function() {
rivetsView.bind();
});
it('test', function() {
expect(rootNode.html()).toEqual(wantedHtml.replace(/updated-constant/g, 'changed-constant'));
});
describe('shift', function() {
beforeEach(function() {
rootScope.get('sub').get('list').shift();
});
it('test', function() {
expect(rootNode.html()).toEqual(wantedHtml.replace(/updated-constant/g, 'changed-constant').replace(/<li>sub-key:A constant:changed-constant<input rv-value=":inputValue"><\/li>/g, ''));
expect(rootScope.get('inputValue')).toBeUndefined();
});
describe('input-set-value', function() {
beforeEach(function() {
var lastInput = rootNode.find('input:last');
lastInput.trigger('focus');
lastInput[0].value = 'typed';
lastInput.trigger('input');
lastInput.trigger('change').trigger('blur');
});
it('test', function() {
expect(rootScope.get('inputValue')).toEqual('typed');
var inputElementValues = [];
rootNode.find('input').each(function(i) {
inputElementValues.push(this.value);
});
expect(inputElementValues).toEqual([
'typed', 'typed', // preA
'typed', 'typed', // A
'typed', 'typed', // B
'typed', 'typed', // C
'typed', 'typed', // D
]);
});
});
});
});
});
});
});
});
});
});
define(function(require) {
'use strict';
var Sightglass = require('sightglass');
function callIt(container, methodName, args) {
return container[methodName].apply(container, args);
}
var tokenStack;
function sightglass() {
tokenStack = [];
try {
return Sightglass.apply(this, arguments);
} finally {
tokenStack = [];
}
};
sightglass.makeOverrideAdapters = function makeOverrideAdapters(parentAdapters, roData) {
function getStackPath() {
var currentStackPath = '';
_.each(tokenStack, function(token) {
currentStackPath += token.i + token.path;
});
return currentStackPath;
}
var subAdapters = {};
_.each(parentAdapters, function(adapterFunctions, interfaceKey) {
var subAdapter = {};
_.each(['observe', 'unobserve', 'get', 'set'], function wrapApiMethod(methodName) {
subAdapter[methodName] = function(obj, key, cbOrValue) {
var stackPath = getStackPath();
var fullKeyPath = stackPath + interfaceKey + key;
if (fullKeyPath in roData) {
return callIt(parentAdapters['.'], methodName, [roData, fullKeyPath, cbOrValue]);
} else if (stackPath in roData) {
obj = roData[stackPath];
}
try {
return callIt(adapterFunctions, methodName, [obj, key, cbOrValue]);
} finally {
tokenStack.push({i: interfaceKey, path: key});
}
};
});
if (adapterFunctions.iterate) {
subAdapter.iterate = adapterFunctions.iterate;
}
subAdapters[interfaceKey] = subAdapter;
});
return subAdapters;
};
return sightglass;
});
define(function(require) {
'use strict';
var $ = require('jquery');
window.jQuery = $;
var SightglassOverlay = require('sightglass-overlay');
require('rivets-backbone-adapter-brainfood');
var _ = require('underscore');
var Backbone = require('backbone');
var rivets = require('rivets');
//rivets.config.rootInterface = ':';
/* global console:false */
describe('SightglassOverlay', function() {
var rootScope, rootNode;
beforeEach(function() {
rootScope = new Backbone.Model({
sub: new Backbone.Model({
subKey: 'sub-key',
list: new Backbone.Collection([
{key: 'A'},
{key: 'B'},
{key: 'C'},
], {parse: true}),
}),
list: new Backbone.Collection([
{key: 'A'},
{key: 'B'},
{key: 'C'},
], {parse: true}),
constant: 'this-is-a-constant',
});
rootNode = $($.parseHTML('<div>{:constant}<div rv-bfeach-item=":list">key:{:item:key} constant:{:constant}<ul><li rv-bfeach-subitem=":sub:list">sub-key:{:subitem:key} constant:{:constant}<input rv-value=":inputValue" /></li></ul></div></div>'));
});
it('returns defined', function() {
expect(SightglassOverlay).toBeDefined();
});
describe('makeOverrideAdapters', function() {
var newAdapters, roData, rivetsView;
beforeEach(function() {
roData = {};
roData[':sub:list'] = new Backbone.Collection([
{key: 'sub1'},
{key: 'sub2'},
{key: 'sub3'},
], {parse: true});
roData[':list'] = new Backbone.Collection([
{key: '1'},
{key: '2'},
{key: '3'},
], {parse: true});
newAdapters = SightglassOverlay.makeOverrideAdapters(rivets.adapters, roData);
rivetsView = rivets.bind(rootNode, rootScope, {adapters: newAdapters});
});
xit('test', function() {
var subListHtml = '<ul><!-- rivets: bfeach-subitem --><li>sub-key:sub1 constant:this-is-a-constant<input rv-value=":inputValue"></li><li>sub-key:sub2 constant:this-is-a-constant<input rv-value=":inputValue"></li><li>sub-key:sub3 constant:this-is-a-constant<input rv-value=":inputValue"></li></ul>';
expect(rootNode.html()).toEqual(
'this-is-a-constant' +
'<!-- rivets: bfeach-item -->' +
'<div>key:1 constant:this-is-a-constant' + subListHtml + '</div>' +
'<div>key:2 constant:this-is-a-constant' + subListHtml + '</div>' +
'<div>key:3 constant:this-is-a-constant' + subListHtml + '</div>'
);
});
});
});
});