Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge branch 'master' into loading-fixes

  • Loading branch information...
commit c4478011dd9d9af64d83ee2c03f63a1f8af6ddf3 2 parents 7df986c + 333b2ab
@kpdecker kpdecker authored
View
9 Jakefile
@@ -0,0 +1,9 @@
+var build = require('phoenix-build');
+
+build.lumbarFile = 'build.json';
+build.projectDir = __dirname;
+build.mochaTests = true;
+build.testPlatforms = [
+ {platform: 'jquery'},
+ {platform: 'zepto'}
+];
View
16 bin/test-server.js
@@ -1,16 +0,0 @@
-// Shamelessly pulled from Modernizr
-// https://github.com/Modernizr/Modernizr/blob/master/test/js/server.js
-var express = require('express'),
- path = require('path'),
- fs = require('fs'),
- args = process.argv.slice(2),
- root = path.join(__dirname, '..'),
- folder = path.join(root, 'build'),
- port = args[1] || '80';
-
-var server = express.createServer();
-server.use(express.static(folder));
-
-server.listen(port);
-
-console.log("Server started on port %s in %s", port, folder);
View
23 build.json
@@ -40,33 +40,24 @@
},
"test": {
+ "mixins": [
+ "test",
+ "loaded-test-runner"
+ ],
"scripts": [
- {"src": "test/lib/mocha.js", "global": true},
- {"src": "test/lib/chai.js", "global": true},
- {"src": "test/lib/sinon-chai.js", "global": true},
- {"src": "test/lib/sinon.js", "global": true},
- {"src": "test/lib/sinon-backbone.js", "global": true},
- "test/lib/runner.js",
-
"test/src/"
],
- "styles": [
- "test/lib/mocha.css"
- ],
"static": [
- {"src": "test/jquery.html", "dest": "jquery.html"},
- {"src": "test/zepto.html", "dest": "zepto.html"}
+ {"src": "test/jquery.html", "dest": "jquery/test.html"},
+ {"src": "test/zepto.html", "dest": "zepto/test.html"}
]
}
},
"mixins": [
+ "node_modules/phoenix-build/mixin",
"."
],
"scope": {
"template": "src/fragments/scope.handlebars"
- },
-
- "test": {
- "auto-include": "test/src/test."
}
}
View
2  lumbar.json
@@ -1,4 +1,6 @@
{
+ "name": "thorax",
+
"mixins": {
"thorax-dep-jquery": {
"scripts": [
View
5 mock-server.json
@@ -0,0 +1,5 @@
+{
+ "build-targets": [
+ {"name": "Test", "path": "build/dev"}
+ ]
+}
View
15 package.json
@@ -15,21 +15,14 @@
"node": ">=0.4.7"
},
"dependencies": {
- "fs-watch-tree": "0.2.0",
- "handlebars": "1.0.x"
+ "fs-watch-tree": "0.2.0"
},
"devDependencies": {
- "express": "2.5.11",
- "lumbar": "~2",
- "mocha-phantomjs": "~1.1"
+ "jake": "~0.5",
+ "phoenix-build": "~1"
},
"scripts": {
- "watch": "./node_modules/.bin/lumbar watch ./build.json ./build",
-
- "start": "node bin/test-server.js . 8083",
-
- "pretest": "./node_modules/.bin/lumbar build ./build.json ./build",
- "test": "./node_modules/.bin/mocha-phantomjs 'http://localhost:8083/zepto.html' && ./node_modules/.bin/mocha-phantomjs 'http://localhost:8083/jquery.html'"
+ "test": "./node_modules/.bin/jake test"
},
"bin": {
"thorax": "bin/thorax"
View
3,655 test/lib/chai.js
0 additions, 3,655 deletions not shown
View
7 test/lib/mocha-override.css
@@ -1,7 +0,0 @@
-#mocha-stats {
- position: static;
-}
-
-#mocha .test a.replay {
- right: 0;
-}
View
227 test/lib/mocha.css
@@ -1,227 +0,0 @@
-@charset "UTF-8";
-body {
- font: 20px/1.5 "Helvetica Neue", Helvetica, Arial, sans-serif;
- padding: 60px 50px;
-}
-
-#mocha ul, #mocha li {
- margin: 0;
- padding: 0;
-}
-
-#mocha ul {
- list-style: none;
-}
-
-#mocha h1, #mocha h2 {
- margin: 0;
-}
-
-#mocha h1 {
- margin-top: 15px;
- font-size: 1em;
- font-weight: 200;
-}
-
-#mocha h1 a {
- text-decoration: none;
- color: inherit;
-}
-
-#mocha h1 a:hover {
- text-decoration: underline;
-}
-
-#mocha .suite .suite h1 {
- margin-top: 0;
- font-size: .8em;
-}
-
-.hidden {
- display: none;
-}
-
-#mocha h2 {
- font-size: 12px;
- font-weight: normal;
- cursor: pointer;
-}
-
-#mocha .suite {
- margin-left: 15px;
-}
-
-#mocha .test {
- margin-left: 15px;
-}
-
-#mocha .test.pending:hover h2::after {
- content: '(pending)';
- font-family: arial;
-}
-
-#mocha .test.pass.medium .duration {
- background: #C09853;
-}
-
-#mocha .test.pass.slow .duration {
- background: #B94A48;
-}
-
-#mocha .test.pass::before {
- content: '';
- font-size: 12px;
- display: block;
- float: left;
- margin-right: 5px;
- color: #00d6b2;
-}
-
-#mocha .test.pass .duration {
- font-size: 9px;
- margin-left: 5px;
- padding: 2px 5px;
- color: white;
- -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.2);
- -moz-box-shadow: inset 0 1px 1px rgba(0,0,0,.2);
- box-shadow: inset 0 1px 1px rgba(0,0,0,.2);
- -webkit-border-radius: 5px;
- -moz-border-radius: 5px;
- -ms-border-radius: 5px;
- -o-border-radius: 5px;
- border-radius: 5px;
-}
-
-#mocha .test.pass.fast .duration {
- display: none;
-}
-
-#mocha .test.pending {
- color: #0b97c4;
-}
-
-#mocha .test.pending::before {
- content: '';
- color: #0b97c4;
-}
-
-#mocha .test.fail {
- color: #c00;
-}
-
-#mocha .test.fail pre {
- color: black;
-}
-
-#mocha .test.fail::before {
- content: '';
- font-size: 12px;
- display: block;
- float: left;
- margin-right: 5px;
- color: #c00;
-}
-
-#mocha .test pre.error {
- color: #c00;
- max-height: 300px;
- overflow: auto;
-}
-
-#mocha .test pre {
- display: inline-block;
- font: 12px/1.5 monaco, monospace;
- margin: 5px;
- padding: 15px;
- border: 1px solid #eee;
- border-bottom-color: #ddd;
- -webkit-border-radius: 3px;
- -webkit-box-shadow: 0 1px 3px #eee;
- -moz-border-radius: 3px;
- -moz-box-shadow: 0 1px 3px #eee;
-}
-
-#mocha .test h2 {
- position: relative;
-}
-
-#mocha .test a.replay {
- position: absolute;
- top: 3px;
- right: -20px;
- text-decoration: none;
- vertical-align: middle;
- display: block;
- width: 15px;
- height: 15px;
- line-height: 15px;
- text-align: center;
- background: #eee;
- font-size: 15px;
- -moz-border-radius: 15px;
- border-radius: 15px;
- -webkit-transition: opacity 200ms;
- -moz-transition: opacity 200ms;
- transition: opacity 200ms;
- opacity: 0.2;
- color: #888;
-}
-
-#mocha .test:hover a.replay {
- opacity: 1;
-}
-
-#mocha-report.pass .test.fail {
- display: none;
-}
-
-#mocha-report.fail .test.pass {
- display: none;
-}
-
-#mocha-error {
- color: #c00;
- font-size: 1.5 em;
- font-weight: 100;
- letter-spacing: 1px;
-}
-
-#mocha-stats {
- position: fixed;
- top: 15px;
- right: 10px;
- font-size: 12px;
- margin: 0;
- color: #888;
-}
-
-#mocha-stats .progress {
- float: right;
- padding-top: 0;
-}
-
-#mocha-stats em {
- color: black;
-}
-
-#mocha-stats a {
- text-decoration: none;
- color: inherit;
-}
-
-#mocha-stats a:hover {
- border-bottom: 1px solid #eee;
-}
-
-#mocha-stats li {
- display: inline-block;
- margin: 0 5px;
- list-style: none;
- padding-top: 11px;
-}
-
-code .comment { color: #ddd }
-code .init { color: #2F6FAD }
-code .string { color: #5890AD }
-code .keyword { color: #8A6343 }
-code .number { color: #2F6FAD }
View
4,994 test/lib/mocha.js
0 additions, 4,994 deletions not shown
View
35 test/lib/runner.js
@@ -1,35 +0,0 @@
-/*global chai, mocha, mochaPhantomJS */
-mocha.setup({
- ui: 'bdd',
- globals: ['addEventListener', 'removeEventListener']
-});
-
-window.expect = chai.expect;
-
-chai.Assertion.includeStack = true;
-
-sinon.config = {
- injectIntoThis: true,
- injectInto: null,
- properties: ['spy', 'stub', 'mock', 'clock', 'sandbox', 'server', 'requests', 'on'],
- useFakeTimers: [10],
- useFakeServer: true
-};
-
-beforeEach(function() {
- var config = sinon.getConfig(sinon.config);
- config.injectInto = this;
- this.sandbox = sinon.sandbox.create(config);
-});
-afterEach(function() {
- this.clock.tick(1000);
- this.sandbox.verifyAndRestore();
-});
-
-$(document).ready(function() {
- if (window.mochaPhantomJS) {
- mochaPhantomJS.run();
- } else {
- mocha.run();
- }
-});
View
18 test/lib/sinon-backbone.js
@@ -1,18 +0,0 @@
-(function() {
- // Allow for simple backbone event cleanup
- var inject = sinon.sandbox.inject;
- sinon.sandbox.inject = function(obj) {
- obj = inject.call(this, obj);
-
- obj.on = function(obj, event, callback) {
- var spy = this.spy(callback);
- spy.restore = function() {
- obj.off(event, spy);
- };
- obj.on(event, spy);
- return spy;
- };
-
- return obj;
- };
-})();
View
121 test/lib/sinon-chai.js
@@ -1,121 +0,0 @@
-/*
- DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
- Version 2, December 2004
-
- Copyright (C) 2012 Domenic Denicola <domenic@domenicdenicola.com>
-
- Everyone is permitted to copy and distribute verbatim or modified
- copies of this license document, and changing it is allowed as long
- as the name is changed.
-
- DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
- 0. You just DO WHAT THE FUCK YOU WANT TO.
-*/
-(function (sinonChai) {
- "use strict";
-
- // Module systems magic dance.
-
- if (typeof require === "function" && typeof exports === "object" && typeof module === "object") {
- // NodeJS
- module.exports = sinonChai;
- } else if (typeof define === "function" && define.amd) {
- // AMD
- define(function () {
- return sinonChai;
- });
- } else {
- // Other environment (usually <script> tag): plug in to global chai instance directly.
- chai.use(sinonChai);
- }
-}(function sinonChai(chai, utils) {
- "use strict";
-
- var slice = Array.prototype.slice;
-
- function isSpy(putativeSpy) {
- return typeof putativeSpy === "function" &&
- typeof putativeSpy.getCall === "function" &&
- typeof putativeSpy.calledWithExactly === "function";
- }
-
- function isCall(putativeCall) {
- return putativeCall && isSpy(putativeCall.proxy);
- }
-
- function assertCanWorkWith(assertion) {
- if (!isSpy(assertion._obj) && !isCall(assertion._obj)) {
- throw new TypeError(utils.inspect(assertion._obj) + " is not a spy or a call to a spy!");
- }
- }
-
- function getMessages(spy, action, nonNegatedSuffix, always, args) {
- var verbPhrase = always ? "always have " : "have ";
- nonNegatedSuffix = nonNegatedSuffix || "";
- spy = spy.proxy || spy;
-
- function printfArray(array) {
- return spy.printf.apply(spy, array);
- }
-
- return {
- affirmative: printfArray(["expected %n to " + verbPhrase + action + nonNegatedSuffix].concat(args)),
- negative: printfArray(["expected %n to not " + verbPhrase + action].concat(args))
- };
- }
-
- function sinonProperty(name, action, nonNegatedSuffix) {
- utils.addProperty(chai.Assertion.prototype, name, function () {
- assertCanWorkWith(this);
-
- var messages = getMessages(this._obj, action, nonNegatedSuffix, false);
- this.assert(this._obj[name], messages.affirmative, messages.negative);
- });
- }
-
- function createSinonMethodHandler(sinonName, action, nonNegatedSuffix) {
- return function () {
- assertCanWorkWith(this);
-
- var alwaysSinonMethod = "always" + sinonName[0].toUpperCase() + sinonName.substring(1);
- var shouldBeAlways = utils.flag(this, "always") && typeof this._obj[alwaysSinonMethod] === "function";
- var sinonMethod = shouldBeAlways ? alwaysSinonMethod : sinonName;
-
- var messages = getMessages(this._obj, action, nonNegatedSuffix, shouldBeAlways, slice.call(arguments));
- this.assert(this._obj[sinonMethod].apply(this._obj, arguments), messages.affirmative, messages.negative);
- };
- }
-
- function sinonMethodAsProperty(name, action, nonNegatedSuffix) {
- var handler = createSinonMethodHandler(name, action, nonNegatedSuffix);
- utils.addProperty(chai.Assertion.prototype, name, handler);
- }
-
- function exceptionalSinonMethod(chaiName, sinonName, action, nonNegatedSuffix) {
- var handler = createSinonMethodHandler(sinonName, action, nonNegatedSuffix);
- utils.addMethod(chai.Assertion.prototype, chaiName, handler);
- }
-
- function sinonMethod(name, action, nonNegatedSuffix) {
- exceptionalSinonMethod(name, name, action, nonNegatedSuffix);
- }
-
- utils.addProperty(chai.Assertion.prototype, "always", function () {
- utils.flag(this, "always", true);
- });
-
- sinonProperty("called", "been called", " at least once, but it was never called");
- sinonProperty("calledOnce", "been called exactly once", ", but it was called %c%C");
- sinonProperty("calledTwice", "been called exactly twice", ", but it was called %c%C");
- sinonProperty("calledThrice", "been called exactly thrice", ", but it was called %c%C");
- sinonMethodAsProperty("calledWithNew", "been called with new");
- sinonMethod("calledBefore", "been called before %1");
- sinonMethod("calledAfter", "been called after %1");
- sinonMethod("calledOn", "been called with %1 as this", ", but it was called with %t instead");
- sinonMethod("calledWith", "been called with arguments %*", "%C");
- sinonMethod("calledWithExactly", "been called with exact arguments %*", "%C");
- sinonMethod("returned", "returned %1");
- exceptionalSinonMethod("thrown", "threw", "thrown %1");
-}));
View
41 test/lib/sinon-qunit.js
@@ -1,41 +0,0 @@
-/*global sinon, QUnit, test*/
-sinon.assert.fail = function (msg) {
- QUnit.ok(false, msg);
-};
-
-sinon.assert.pass = function (assertion) {
- QUnit.ok(true, assertion);
-};
-
-sinon.config = {
- injectIntoThis: true,
- injectInto: null,
- properties: ['spy', 'stub', 'mock', 'clock', 'sandbox', 'server', 'requests'],
- useFakeTimers: [10],
- useFakeServer: true
-};
-
-(function (global) {
- var module = QUnit.module;
-
- QUnit.module = function(moduleName, env) {
- var sandbox;
-
- module.call(this, moduleName, {
- setup: function() {
- var config = sinon.getConfig(sinon.config);
- config.injectInto = this;
- sandbox = sinon.sandbox.create(config);
-
- env && env.setup && env.setup.call(this);
- },
- teardown: function() {
- env && env.teardown && env.teardown.call(this);
- sandbox.verifyAndRestore();
- }
- });
- };
-
- // Make sure that we are seeded
- QUnit.module('', {});
-}(this));
View
4,157 test/lib/sinon.js
0 additions, 4,157 deletions not shown
View
0  test/src/test.collection.js → test/src/collection.js
File renamed without changes
View
0  test/src/test.event.js → test/src/event.js
File renamed without changes
View
4 test/src/test.form.js → test/src/form.js
@@ -2,7 +2,9 @@ describe('form', function() {
it("serialize() / populate()", function() {
var FormView = Thorax.View.extend({
name: 'form',
- template: Handlebars.compile('<form><input name="one"/><select name="two"><option value="a">a</option><option value="b">b</option></select><input name="three[four]"/><input name="five" value="A" type="checkbox" /><input name="five" value="B" type="checkbox" checked /><input name="five" value="C" type="checkbox" checked /><input name="six" value="LOL" type="checkbox" checked /></form>', {data: true})
+ template: function() {
+ return '<form><input name="one"/><select name="two"><option value="a">a</option><option value="b">b</option></select><input name="three[four]"/><input name="five" value="A" type="checkbox" /><input name="five" value="B" type="checkbox" checked /><input name="five" value="C" type="checkbox" checked /><input name="six" value="LOL" type="checkbox" checked /></form>';
+ }
});
var model = new Thorax.Model({
View
40 test/src/test.helpers.js → test/src/helpers/button-link.js
@@ -1,34 +1,9 @@
-describe('helpers', function() {
- it("url helper", function() {
- var view = new Thorax.View({
- template: '<a href="{{url "/a/{{b}}" expand-tokens=true}}"></a>'
- });
- view.render();
- expect(view.$('a').attr('href')).to.equal('#/a/');
- view.b = 'b';
- view.render();
- expect(view.$('a').attr('href')).to.equal('#/a/b');
- view.b = false;
- view.setModel(new Backbone.Model({
- b: 'c'
- }));
- expect(view.$('a').attr('href')).to.equal('#/a/c');
-
- var view = new Thorax.View({
- template: '<a href="{{url "a" b}}"></a>',
- b: 'c'
- });
- view.render();
- expect(view.$('a').attr('href')).to.equal('#a/c');
- });
-
+describe('button-link helpers', function() {
it("option hash required arguments for button and link", function() {
- var view = new Thorax.View({
- template: '{{#link href="a"}}{{/link}}{{#button method="b"}}{{/button}}'
- });
- view.render();
- expect(view.$('a').attr('href')).to.equal('#a');
- expect(view.$('button').attr('data-call-method')).to.equal('b');
+ var link = $(Handlebars.helpers.link({hash: {href: 'a'}}).toString()),
+ button = $(Handlebars.helpers.button({hash: {method: 'b'}}).toString());
+ expect(link.attr('href')).to.equal('#a');
+ expect(button.attr('data-call-method')).to.equal('b');
});
it("multiple arguments to link", function() {
@@ -74,9 +49,4 @@ describe('helpers', function() {
expect(view.$('a').html()).to.equal('content');
expect(view.$('a').attr('href')).to.equal('#href');
});
-
- it('should have access to handlebars noop', function() {
- // Explicit verification that Handlebars is exposing this field.
- expect(Handlebars.VM.noop).to.exist;
- });
});
View
6 test/src/helpers/collection.js
@@ -0,0 +1,6 @@
+describe('collection helper', function() {
+ it('should have access to handlebars noop', function() {
+ // Explicit verification that Handlebars is exposing this field.
+ expect(Handlebars.VM.noop).to.exist;
+ });
+});
View
33 test/src/helpers/element.js
@@ -0,0 +1,33 @@
+describe('element helper', function() {
+ it("element helper", function() {
+ var a = document.createElement('li');
+ a.innerHTML = 'one';
+ var view = new Thorax.View({
+ template: '<ul>{{element a tag="li"}}{{element b tag="li"}}{{element c}}{{element d}}</ul>',
+ a: a,
+ b: function() {
+ var li = document.createElement('li');
+ li.innerHTML = 'two';
+ return li;
+ },
+ c: function() {
+ return $('<li>three</li><li>four</li>');
+ },
+ d: $('<li>five</li>')
+ });
+ view.render();
+ expect(view.$('li')[0].innerHTML).to.equal('one');
+ expect(view.$('li')[1].innerHTML).to.equal('two');
+ expect(view.$('li')[2].innerHTML).to.equal('three');
+ expect(view.$('li')[3].innerHTML).to.equal('four');
+ expect(view.$('li')[4].innerHTML).to.equal('five');
+ view.html('');
+ expect(view.$('li').length).to.equal(0);
+ view.render();
+ expect(view.$('li')[0].innerHTML).to.equal('one');
+ expect(view.$('li')[1].innerHTML).to.equal('two');
+ expect(view.$('li')[2].innerHTML).to.equal('three');
+ expect(view.$('li')[3].innerHTML).to.equal('four');
+ expect(view.$('li')[4].innerHTML).to.equal('five');
+ });
+});
View
37 test/src/helpers/super.js
@@ -0,0 +1,37 @@
+describe('super helper', function() {
+
+ it("super helper", function() {
+ var parent, child;
+ Thorax.templates['super-named-test'] = '<div class="parent"></div>';
+ parent = Thorax.View.extend({
+ name: 'super-named-test'
+ });
+ child = new (parent.extend({
+ template: '<div class="child"></div>{{super}}'
+ }))();
+ child.render();
+ expect(child.$('.parent').length).to.equal(1);
+ expect(child.$('.child').length).to.equal(1);
+
+ parent = Thorax.View.extend({
+ name: 'super-test',
+ template: '<div class="parent"></div>'
+ });
+ child = new (parent.extend({
+ template: '<div class="child"></div>{{super}}'
+ }))();
+ child.render();
+ expect(child.$('.parent').length).to.equal(1);
+ expect(child.$('.child').length).to.equal(1);
+
+ parent = Thorax.View.extend({
+ template: '{{#collection letters tag="ul"}}<li>{{letter}}</li>{{/collection}}'
+ });
+ var instance = new (parent.extend({
+ template: '{{super}}'
+ }))({letters: new Thorax.Collection([{letter: 'a'}])});
+ instance.render();
+ expect(instance.$('li').length).to.equal(1);
+ expect(instance.$('li').eq(0).html()).to.equal('a');
+ });
+});
View
13 test/src/helpers/url.js
@@ -0,0 +1,13 @@
+describe('url helper', function() {
+ it("url helper", function() {
+ var href = Handlebars.helpers.url.call({}, '/a/{{b}}', {'expand-tokens': true});
+ expect(href).to.equal('#/a/');
+ href = Handlebars.helpers.url.call({b: 'b'}, '/a/{{b}}', {'expand-tokens': true});
+ expect(href).to.equal('#/a/b');
+ href = Handlebars.helpers.url.call({b: 'c'}, '/a/{{b}}', {'expand-tokens': true});
+ expect(href).to.equal('#/a/c');
+
+ href = Handlebars.helpers.url('a', 'c', {});
+ expect(href).to.equal('#a/c');
+ });
+});
View
154 test/src/helpers/view.js
@@ -0,0 +1,154 @@
+describe('view helper', function() {
+ it("throws an error when template compiled without data", function() {
+ expect(function() {
+ Handlebars.helpers.view({}, {});
+ }).to['throw']();
+ });
+
+ it('should use the registry to lookup view clases', function() {
+ //test nested
+ Thorax.Views.Outer = {
+ Inner: Thorax.View.extend({
+ template: function() { return 'inner'; }
+ }),
+ More: {
+ Nested: Thorax.View.extend({
+ template: function() { return 'nested'; }
+ })
+ }
+ };
+
+ var view = new Thorax.View({
+ template: '<p>{{view "Outer.Inner" tag="span"}}</p><div>{{view "Outer.More.Nested" tag="span"}}</div>'
+ });
+ view.render();
+ expect(view.$('p > span').html()).to.equal('inner', 'test nested registryGet');
+ expect(view.$('div > span').html()).to.equal('nested', 'test nested registryGet');
+
+ view = new Thorax.View({
+ name: 'extension-test'
+ });
+ view.render();
+ expect(view.html()).to.equal('123');
+ });
+
+ it("fail silently when no view initialized", function() {
+ var parent = new Thorax.View({
+ template: "{{view child}}"
+ });
+ parent.render();
+ expect(parent.$el.html()).to.equal('');
+ });
+
+ it("child views", function() {
+ var childRenderedCount = 0,
+ parentRenderedCount = 0;
+ Thorax.View.extend({
+ name: 'child',
+ initialize: function() {
+ this.on('rendered', function() {
+ ++childRenderedCount;
+ });
+ }
+ });
+ var Parent = Thorax.View.extend({
+ name: 'parent',
+ initialize: function() {
+ this.on('rendered', function() {
+ ++parentRenderedCount;
+ });
+ this.childModel = new Backbone.Model({
+ value: 'a'
+ });
+ this.child = new Thorax.Views.child({
+ model: this.childModel
+ });
+ }
+ });
+ var parent = new Parent();
+ parent.render();
+ expect(parent.$('[data-view-name="child"] > div').html()).to.equal('a', 'view embedded');
+ expect(parentRenderedCount).to.equal(1);
+ expect(childRenderedCount).to.equal(1);
+
+ parent.render();
+ expect(parent.$('[data-view-name="child"] > div').html()).to.equal('a', 'view embedded');
+ expect(parentRenderedCount).to.equal(2, 're-render of parent does not render child');
+ expect(childRenderedCount).to.equal(1, 're-render of parent does not render child');
+
+ parent.childModel.set({value: 'b'});
+ expect(parent.$('[data-view-name="child"] > div').html()).to.equal('b', 'view embedded');
+ expect(parentRenderedCount).to.equal(2, 're-render of child does not parent child');
+ expect(childRenderedCount).to.equal(2, 're-render of child does not render parent');
+
+ //ensure recursion does not happen when child view has the same model
+ //as parent
+ parent.setModel(parent.childModel);
+ parent.model.set({value: 'c'});
+ expect(parentRenderedCount).to.equal(4);
+ expect(childRenderedCount).to.equal(3);
+ });
+
+ it("child views within #each", function() {
+ var parent = new Thorax.View({
+ template: '{{#each views}}{{view this}}{{/each}}',
+ views: [
+ new Thorax.View({
+ template: "a"
+ }),
+ new Thorax.View({
+ template: "b"
+ })
+ ]
+ });
+ parent.render();
+ expect(parent.$('div').get(0).innerHTML).to.equal('a');
+ expect(parent.$('div').get(1).innerHTML).to.equal('b');
+ });
+
+ // TODO: The bug and test to ensure it is fixed is limited to jQuery
+ // The test fails on PhantomJS running the zepto tests for unknown
+ // reasons. The test passes on Zepto when run directly in a browser.
+ // It is disabled for now as it does not affect Zepto.
+ if (typeof jQuery !== 'undefined' && $ === jQuery) {
+ it("child view re-render will keep dom events intact", function() {
+ var callCount = 0;
+ var parent = new Thorax.View({
+ name: 'parent-event-dom-test',
+ child: new Thorax.View({
+ name: 'child-event-dom-test',
+ events: {
+ 'click .test': function() {
+ ++callCount;
+ }
+ },
+ template: function() { return '<div class="test"></div>'; }
+ }),
+ template: "{{view child}}"
+ });
+ parent.render();
+ document.body.appendChild(parent.el);
+ parent.child.$('.test').trigger('click');
+ expect(callCount).to.equal(1);
+ parent.render();
+ parent.child.$('.test').trigger('click');
+ expect(callCount).to.equal(2);
+ $(parent.el).remove();
+ });
+ }
+
+ it("$.fn.view", function() {
+ var child = new Thorax.View({
+ template: '<div class="child"></div>'
+ });
+ child.render();
+ expect(child.$('div.child').view()).to.equal(child);
+ var parent = new Thorax.View({
+ template: '<div class="parent">{{view child}}</div>',
+ child: child
+ });
+ parent.render();
+ expect(parent.$('div.parent').view()).to.equal(parent);
+ expect(parent.$('div.child').view()).to.equal(child);
+ });
+});
View
0  test/src/test.layout.js → test/src/layout.js
File renamed without changes
View
10 test/src/test.loading.js → test/src/loading.js
@@ -29,7 +29,7 @@ describe('loading', function() {
var view = new Thorax.View({
name: 'food',
myCollection: collection,
- template: ''
+ template: function() {}
});
view.bindCollection(view.myCollection);
view.on('load:start', spy);
@@ -77,8 +77,8 @@ describe('loading', function() {
var view = new Thorax.View({
name: 'food',
collection: collection,
- template: '',
- itemTemplate: function() {return '';}
+ template: function() {},
+ itemTemplate: function() {return ''; }
});
var spy = this.spy(view, 'onLoadEnd');
view.bindCollection(view.collection);
@@ -94,7 +94,7 @@ describe('loading', function() {
it('views should see load end after destroy', function() {
var spy = this.spy(),
model = new Thorax.Model({url: 'foo'}),
- view = new Thorax.View({name: 'food', template: '', model: model}),
+ view = new Thorax.View({name: 'food', template: function() {}, model: model}),
endSpy = this.spy(view, 'onLoadEnd');
view.on('load:start', spy);
@@ -123,7 +123,7 @@ describe('loading', function() {
exports.on('load:start', Thorax.loadHandler(this.startSpy, this.endSpy));
this.model = new Thorax.Model({url: 'foo'});
- this.view = new Thorax.View({name: 'food', model: this.model, template: ''});
+ this.view = new Thorax.View({name: 'food', model: this.model, template: function() {}});
});
afterEach(function() {
exports._loadStart = undefined;
View
0  test/src/test.model.js → test/src/model.js
File renamed without changes
View
224 test/src/test.js → test/src/thorax.js
@@ -25,31 +25,6 @@ describe('core', function() {
key: 'value'
});
expect(Thorax.Views['a-name'].prototype.key).to.equal('value', 'registry will extend an existing class prototype');
-
- //test nested
- Thorax.Views.Outer = {
- Inner: Thorax.View.extend({
- template: 'inner'
- }),
- More: {
- Nested: Thorax.View.extend({
- template: 'nested'
- })
- }
- };
-
- var view = new Thorax.View({
- template: '<p>{{view "Outer.Inner" tag="span"}}</p><div>{{view "Outer.More.Nested" tag="span"}}</div>'
- });
- view.render();
- expect(view.$('p > span').html()).to.equal('inner', 'test nested registryGet');
- expect(view.$('div > span').html()).to.equal('nested', 'test nested registryGet');
-
- view = new Thorax.View({
- name: 'extension-test'
- });
- view.render();
- expect(view.html()).to.equal('123');
});
it("context may be an object", function() {
@@ -67,125 +42,10 @@ describe('core', function() {
expect(view.html()).to.equal('abc');
});
- it("child views", function() {
- var childRenderedCount = 0,
- parentRenderedCount = 0;
- Thorax.View.extend({
- name: 'child',
- initialize: function() {
- this.on('rendered', function() {
- ++childRenderedCount;
- });
- }
- });
- var Parent = Thorax.View.extend({
- name: 'parent',
- initialize: function() {
- this.on('rendered', function() {
- ++parentRenderedCount;
- });
- this.childModel = new Backbone.Model({
- value: 'a'
- });
- this.child = new Thorax.Views.child({
- model: this.childModel
- });
- }
- });
- var parent = new Parent();
- parent.render();
- expect(parent.$('[data-view-name="child"] > div').html()).to.equal('a', 'view embedded');
- expect(parentRenderedCount).to.equal(1);
- expect(childRenderedCount).to.equal(1);
-
- parent.render();
- expect(parent.$('[data-view-name="child"] > div').html()).to.equal('a', 'view embedded');
- expect(parentRenderedCount).to.equal(2, 're-render of parent does not render child');
- expect(childRenderedCount).to.equal(1, 're-render of parent does not render child');
-
- parent.childModel.set({value: 'b'});
- expect(parent.$('[data-view-name="child"] > div').html()).to.equal('b', 'view embedded');
- expect(parentRenderedCount).to.equal(2, 're-render of child does not parent child');
- expect(childRenderedCount).to.equal(2, 're-render of child does not render parent');
-
- //ensure recursion does not happen when child view has the same model
- //as parent
- parent.setModel(parent.childModel);
- parent.model.set({value: 'c'});
- expect(parentRenderedCount).to.equal(4);
- expect(childRenderedCount).to.equal(3);
- });
-
- it("child views within #each", function() {
- var parent = new Thorax.View({
- template: '{{#each views}}{{view this}}{{/each}}',
- views: [
- new Thorax.View({
- template: "a"
- }),
- new Thorax.View({
- template: "b"
- })
- ]
- });
- parent.render();
- expect(parent.$('div').get(0).innerHTML).to.equal('a');
- expect(parent.$('div').get(1).innerHTML).to.equal('b');
- });
-
- it("throws an error when template compiled without data", function() {
- var view = new Thorax.View({
- child: new Thorax.View({template: ''}),
- template: Handlebars.compile('{{view child}}', {data: false})
- });
- expect(function() {
- view.render();
- }).to['throw']();
- });
-
- it("fail silently when no view initialized", function() {
- var parent = new Thorax.View({
- template: "{{view child}}"
- });
- parent.render();
- expect(parent.$el.html()).to.equal('');
- });
-
- // TODO: The bug and test to ensure it is fixed is limited to jQuery
- // The test fails on PhantomJS running the zepto tests for unknown
- // reasons. The test passes on Zepto when run directly in a browser.
- // It is disabled for now as it does not affect Zepto.
- if (typeof jQuery !== 'undefined' && $ === jQuery) {
- it("child view re-render will keep dom events intact", function() {
- var callCount = 0;
- var parent = new Thorax.View({
- name: 'parent-event-dom-test',
- child: new Thorax.View({
- name: 'child-event-dom-test',
- events: {
- 'click .test': function() {
- ++callCount;
- }
- },
- template: "<div class=\"test\"></div>"
- }),
- template: "{{view child}}"
- });
- parent.render();
- document.body.appendChild(parent.el);
- parent.child.$('.test').trigger('click');
- expect(callCount).to.equal(1);
- parent.render();
- parent.child.$('.test').trigger('click');
- expect(callCount).to.equal(2);
- $(parent.el).remove();
- });
- }
-
it("can set view el", function() {
$('body').append('<div id="test-target-container"><div id="test-target"></div></div>');
var view = new Thorax.View({
- template: 'testing123',
+ template: function() { return 'testing123'; },
el: $('#test-target')[0]
});
view.render();
@@ -219,41 +79,6 @@ describe('core', function() {
expect(childReturning$.$('p').html()).to.equal('template');
});
- it("super helper", function() {
- var parent, child;
- Thorax.templates['super-named-test'] = '<div class="parent"></div>';
- parent = Thorax.View.extend({
- name: 'super-named-test'
- });
- child = new (parent.extend({
- template: '<div class="child"></div>{{super}}'
- }))();
- child.render();
- expect(child.$('.parent').length).to.equal(1);
- expect(child.$('.child').length).to.equal(1);
-
- parent = Thorax.View.extend({
- name: 'super-test',
- template: '<div class="parent"></div>'
- });
- child = new (parent.extend({
- template: '<div class="child"></div>{{super}}'
- }))();
- child.render();
- expect(child.$('.parent').length).to.equal(1);
- expect(child.$('.child').length).to.equal(1);
-
- parent = Thorax.View.extend({
- template: '{{#collection letters tag="ul"}}<li>{{letter}}</li>{{/collection}}'
- });
- var instance = new (parent.extend({
- template: '{{super}}'
- }))({letters: new Thorax.Collection([{letter: 'a'}])});
- instance.render();
- expect(instance.$('li').length).to.equal(1);
- expect(instance.$('li').eq(0).html()).to.equal('a');
- });
-
it("template yield", function() {
Thorax.templates['yield-child'] = '<span>{{yield}}</span>';
Thorax.templates['yield-parent'] = '<p>{{#template "yield-child"}}content{{/template}}</p>';
@@ -264,38 +89,6 @@ describe('core', function() {
expect(view.$('p > span').html()).to.equal('content');
});
- it("element helper", function() {
- var a = document.createElement('li');
- a.innerHTML = 'one';
- var view = new Thorax.View({
- template: '<ul>{{element a tag="li"}}{{element b tag="li"}}{{element c}}{{element d}}</ul>',
- a: a,
- b: function() {
- var li = document.createElement('li');
- li.innerHTML = 'two';
- return li;
- },
- c: function() {
- return $('<li>three</li><li>four</li>');
- },
- d: $('<li>five</li>')
- });
- view.render();
- expect(view.$('li')[0].innerHTML).to.equal('one');
- expect(view.$('li')[1].innerHTML).to.equal('two');
- expect(view.$('li')[2].innerHTML).to.equal('three');
- expect(view.$('li')[3].innerHTML).to.equal('four');
- expect(view.$('li')[4].innerHTML).to.equal('five');
- view.html('');
- expect(view.$('li').length).to.equal(0);
- view.render();
- expect(view.$('li')[0].innerHTML).to.equal('one');
- expect(view.$('li')[1].innerHTML).to.equal('two');
- expect(view.$('li')[2].innerHTML).to.equal('three');
- expect(view.$('li')[3].innerHTML).to.equal('four');
- expect(view.$('li')[4].innerHTML).to.equal('five');
- });
-
it("local view functions are called in template scope", function() {
var child = new Thorax.View({
template: '{{key}}',
@@ -422,21 +215,6 @@ describe('core', function() {
delete Handlebars.helpers.test;
});
- it("$.fn.view", function() {
- var child = new Thorax.View({
- template: '<div class="child"></div>'
- });
- child.render();
- expect(child.$('div.child').view()).to.equal(child);
- var parent = new Thorax.View({
- template: '<div class="parent">{{view child}}</div>',
- child: child
- });
- parent.render();
- expect(parent.$('div.parent').view()).to.equal(parent);
- expect(parent.$('div.child').view()).to.equal(child);
- });
-
it("onException", function() {
var oldOnException = Thorax.onException;
var view = new Thorax.View({
Please sign in to comment.
Something went wrong with that request. Please try again.