";
compiled = new $.EJS({text: text}).render() ;
- equals(compiled, "
Simple
");
+ $('#qunit-test-area').append($(compiled));
+ equals($('#hookup').html(), "Simple");
});
})
From 6553d53ef1eff059b124aa3b004bd5e4b6c36443 Mon Sep 17 00:00:00 2001
From: Ralph Holzmann
Date: Tue, 3 Jan 2012 10:25:28 -0600
Subject: [PATCH 04/42] A small bug fix for empty strings, pointed out by
@selecton.
---
dom/form_params/form_params.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/dom/form_params/form_params.js b/dom/form_params/form_params.js
index cbfc7f6c..69f56ac2 100644
--- a/dom/form_params/form_params.js
+++ b/dom/form_params/form_params.js
@@ -77,7 +77,7 @@ steal("jquery/dom").then(function( $ ) {
$this;
// Don't do all this work if there's no value
- if ( value ) {
+ if ( value !== undefined ) {
$this = $(this);
// Nested these if statements for performance
@@ -96,7 +96,7 @@ steal("jquery/dom").then(function( $ ) {
$this.val( value );
}
}
- });
+ });
},
getParams: function( convert ) {
var data = {},
From a187975b9b59162151263a1950b4b4187ae2d8f1 Mon Sep 17 00:00:00 2001
From: Justin Meyer
Date: Tue, 3 Jan 2012 14:56:50 -0600
Subject: [PATCH 05/42] maintaining future compatibility with steal.URI and
steal.File
---
controller/view/view.js | 6 ++++--
dom/fixture/fixture.js | 2 +-
dom/fixture/fixture_test.js | 6 +++---
model/test/qunit/model_test.js | 2 +-
view/helpers/helpers.js | 2 +-
view/view.js | 2 +-
6 files changed, 11 insertions(+), 9 deletions(-)
diff --git a/controller/view/view.js b/controller/view/view.js
index 5c05345f..773fbcbc 100644
--- a/controller/view/view.js
+++ b/controller/view/view.js
@@ -1,4 +1,6 @@
steal('jquery/controller', 'jquery/view').then(function( $ ) {
+ var URI = steal.URI || steal.File;
+
jQuery.Controller.getFolder = function() {
return jQuery.String.underscore(this.fullName.replace(/\./g, "/")).replace("/Controllers", "");
};
@@ -19,10 +21,10 @@ steal('jquery/controller', 'jquery/view').then(function( $ ) {
if ( typeof view == "string" ) {
if ( view.substr(0, 2) == "//" ) { //leave where it is
} else {
- view = "//" + new steal.File('views/' + (view.indexOf('/') !== -1 ? view : (hasControllers ? controller_name + '/' : "") + view)).joinFrom(path) + suffix;
+ view = "//" + URI(path).join( 'views/' + (view.indexOf('/') !== -1 ? view : (hasControllers ? controller_name + '/' : "") + view)) + suffix;
}
} else if (!view ) {
- view = "//" + new steal.File('views/' + (hasControllers ? controller_name + '/' : "") + action_name.replace(/\.|#/g, '').replace(/ /g, '_')).joinFrom(path) + suffix;
+ view = "//" + URI(path).join('views/' + (hasControllers ? controller_name + '/' : "") + action_name.replace(/\.|#/g, '').replace(/ /g, '_'))+ suffix;
}
return view;
};
diff --git a/dom/fixture/fixture.js b/dom/fixture/fixture.js
index f2a020dc..fd4de3ce 100644
--- a/dom/fixture/fixture.js
+++ b/dom/fixture/fixture.js
@@ -35,7 +35,7 @@ steal('jquery/dom',
var url = settings.fixture;
if (/^\/\//.test(url) ) {
- url = steal.root.mapJoin(settings.fixture.substr(2));
+ url = steal.root.mapJoin(settings.fixture.substr(2))+'';
}
//@steal-remove-start
steal.dev.log("looking for fixture in " + url);
diff --git a/dom/fixture/fixture_test.js b/dom/fixture/fixture_test.js
index 55320696..7559d1ba 100644
--- a/dom/fixture/fixture_test.js
+++ b/dom/fixture/fixture_test.js
@@ -41,7 +41,7 @@ test("dynamic fixtures",function(){
test("fixture function", 3, function(){
stop();
- var url = steal.root.join("jquery/dom/fixture/fixtures/foo.json");
+ var url = steal.root.join("jquery/dom/fixture/fixtures/foo.json")+'';
$.fixture(url,"//jquery/dom/fixture/fixtures/foobar.json" );
$.get(url,function(data){
@@ -77,7 +77,7 @@ test("fixtures with converters", function(){
stop();
$.ajax( {
- url : steal.root.join("jquery/dom/fixture/fixtures/foobar.json"),
+ url : steal.root.join("jquery/dom/fixture/fixtures/foobar.json")+'',
dataType: "json fooBar",
converters: {
"json fooBar": function( data ) {
@@ -250,7 +250,7 @@ test("fixture function gets id", function(){
});
test("replacing and removing a fixture", function(){
- var url = steal.root.join("jquery/dom/fixture/fixtures/remove.json")
+ var url = steal.root.join("jquery/dom/fixture/fixtures/remove.json")+''
$.fixture("GET "+url, function(){
return {weird: "ness!"}
})
diff --git a/model/test/qunit/model_test.js b/model/test/qunit/model_test.js
index b9ffac43..d2ad9091 100644
--- a/model/test/qunit/model_test.js
+++ b/model/test/qunit/model_test.js
@@ -318,7 +318,7 @@ test("isNew", function(){
test("findAll string", function(){
$.fixture.on = false;
$.Model("Test.Thing",{
- findAll : steal.root.join("jquery/model/test/qunit/findAll.json")
+ findAll : steal.root.join("jquery/model/test/qunit/findAll.json")+''
},{});
stop();
Test.Thing.findAll({},function(things){
diff --git a/view/helpers/helpers.js b/view/helpers/helpers.js
index 75b3f91b..478046eb 100644
--- a/view/helpers/helpers.js
+++ b/view/helpers/helpers.js
@@ -315,7 +315,7 @@ $.extend($.EJS.Helpers.prototype, {
*/
img_tag: function( image_location, options ) {
options = options || {};
- options.src = steal.root.join("resources/images/"+image_location);
+ options.src = steal.root.join("resources/images/"+image_location)+'';
return this.single_tag_for('img', options);
}
diff --git a/view/view.js b/view/view.js
index 93e23a69..e8c63cbd 100644
--- a/view/view.js
+++ b/view/view.js
@@ -407,7 +407,7 @@ steal("jquery").then(function( $ ) {
var sub = url.substr(2);
url = typeof steal === "undefined" ?
url = "/" + sub :
- steal.root.mapJoin(sub);
+ steal.root.mapJoin(sub) +'';
}
//set the template engine type
From abb94d097a5d9684f6d2bab721d3016a17986c1d Mon Sep 17 00:00:00 2001
From: Justin Meyer
Date: Fri, 6 Jan 2012 00:10:06 -0600
Subject: [PATCH 06/42] updated routes to handle routes that start the same
like foo and football
---
dom/route/route.js | 6 +++---
dom/route/route_test.js | 14 +++++++++++---
2 files changed, 14 insertions(+), 6 deletions(-)
diff --git a/dom/route/route.js b/dom/route/route.js
index 44084c78..2edbbcf5 100644
--- a/dom/route/route.js
+++ b/dom/route/route.js
@@ -220,7 +220,7 @@ function( $ ) {
// A regular expression that will match the route when variable values
// are present; i.e. for :page/:type the regEx is /([\w\.]*)/([\w\.]*)/ which
// will match for any value of :page and :type (word chars or period).
- test: new RegExp("^" + test),
+ test: new RegExp("^" + test+"($|&)"),
// The original URL, same as the index for this entry in routes.
route: url,
// An array of all the variable names in this route
@@ -316,7 +316,7 @@ function( $ ) {
// start will contain the full matched string; parts contain the variable values.
start = parts.shift(),
// The remainder will be the &key=value list at the end of the URL.
- remainder = url.substr(start.length),
+ remainder = url.substr(start.length - (parts[parts.length-1] === "&" ? 1 : 0) ),
// If there is a remainder and it contains a &key=value list deparam it.
obj = (remainder && paramsMatcher.test(remainder)) ? $.String.deparam( remainder.slice(1) ) : {};
@@ -324,7 +324,7 @@ function( $ ) {
obj = extend(true, {}, route.defaults, obj);
// Overwrite each of the default values in obj with those in parts if that part is not empty.
each(parts,function(i, part){
- if ( part ) {
+ if ( part && part !== '&') {
obj[route.names[i]] = decode( part );
}
});
diff --git a/dom/route/route_test.js b/dom/route/route_test.js
index ed7e7f09..f487da94 100644
--- a/dom/route/route_test.js
+++ b/dom/route/route_test.js
@@ -169,8 +169,8 @@ test("param-deparam", function(){
var res = $.route.param(data);
var obj = $.route.deparam(res);
delete obj.route
- same(data, obj)
-
+ same(obj,data )
+ return;
data = {page: "jQuery.Controller", type: "foo", bar: "baz", where: "there"};
res = $.route.param(data);
obj = $.route.deparam(res);
@@ -254,6 +254,14 @@ test("param with route defined", function(){
equal(res, "foo&foo=abc")
})
-
+test("route endings", function(){
+ $.route.routes = {};
+ $.route("foo",{foo: true});
+ $.route("food",{food: true})
+
+ var res = $.route.deparam("food")
+ ok(res.food, "we get food back")
+
+})
})
From 45b56aad0b0950f2fd3ee2920f198056d6ee5e15 Mon Sep 17 00:00:00 2001
From: Justin Meyer
Date: Fri, 6 Jan 2012 00:15:37 -0600
Subject: [PATCH 07/42] adding a todo
---
dom/route/route.js | 1 +
1 file changed, 1 insertion(+)
diff --git a/dom/route/route.js b/dom/route/route.js
index 2edbbcf5..4159adec 100644
--- a/dom/route/route.js
+++ b/dom/route/route.js
@@ -212,6 +212,7 @@ function( $ ) {
var names = [],
test = url.replace(matcher, function( whole, name ) {
names.push(name)
+ // TODO: I think this should have a +
return "([^\\/\\&]*)" // The '\\' is for string-escaping giving single '\' for regEx escaping
});
From 5b3291449618d9e3d756d8439de7c78b25ddc72e Mon Sep 17 00:00:00 2001
From: Justin Meyer
Date: Mon, 9 Jan 2012 00:54:46 -0600
Subject: [PATCH 08/42] preparing view to work with URI
---
view/view.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/view/view.js b/view/view.js
index e8c63cbd..069e8899 100644
--- a/view/view.js
+++ b/view/view.js
@@ -539,7 +539,7 @@ steal("jquery").then(function( $ ) {
if ( window.steal ) {
steal.type(info.suffix + " view js", function( options, success, error ) {
var type = $view.types["." + options.type],
- id = toId(options.rootSrc);
+ id = toId(options.rootSrc+'');
options.text = type.script(id, options.text)
success();
@@ -580,7 +580,7 @@ steal("jquery").then(function( $ ) {
if ( window.steal ) {
steal.type("view js", function( options, success, error ) {
var type = $view.types["." + options.type],
- id = toId(options.rootSrc);
+ id = toId(options.rootSrc+'');
options.text = "steal('" + (type.plugin || "jquery/view/" + options.type) + "').then(function($){" + "$.View.preload('" + id + "'," + options.text + ");\n})";
success();
From ddef98a8ef2870f7fb75fdeb0591df34c0eb05b0 Mon Sep 17 00:00:00 2001
From: Justin Meyer
Date: Mon, 9 Jan 2012 11:52:20 -0600
Subject: [PATCH 09/42] fixes drop so it handles elements removed from the dom
while triggering drop events
---
event/drop/drop.js | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/event/drop/drop.js b/event/drop/drop.js
index df624632..267abf4f 100644
--- a/event/drop/drop.js
+++ b/event/drop/drop.js
@@ -368,7 +368,9 @@ steal('jquery/event/drag','jquery/dom/within','jquery/dom/compare').then(functio
}
},
end: function( event, moveable ) {
- var responder, la, endName = this.lowerName+'end';
+ var responder, la,
+ endName = this.lowerName+'end',
+ dropData;
// call dropon
//go through the actives ... if you are over one, call dropped on it
@@ -378,9 +380,11 @@ steal('jquery/event/drag','jquery/dom/within','jquery/dom/compare').then(functio
la.callHandlers(this.endName, null, event, moveable);
}
}
+ var drop
// call dropend
for(var r =0; r
Date: Mon, 9 Jan 2012 12:13:19 -0600
Subject: [PATCH 10/42] a little more cleaning of drop
---
event/drop/drop.js | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)
diff --git a/event/drop/drop.js b/event/drop/drop.js
index 267abf4f..792c860a 100644
--- a/event/drop/drop.js
+++ b/event/drop/drop.js
@@ -1,8 +1,5 @@
-steal('jquery/event/drag','jquery/dom/within','jquery/dom/compare').then(function($){
- var event = $.event,
- callHanders = function(){
-
- };
+steal('jquery/event/drag','jquery/dom/within','jquery/dom/compare',function($){
+ var event = $.event;
//somehow need to keep track of elements with selectors on them. When element is removed, somehow we need to know that
//
/**
@@ -380,7 +377,6 @@ steal('jquery/event/drag','jquery/dom/within','jquery/dom/compare').then(functio
la.callHandlers(this.endName, null, event, moveable);
}
}
- var drop
// call dropend
for(var r =0; r
Date: Tue, 10 Jan 2012 14:43:18 -0500
Subject: [PATCH 11/42] Exposing fixture overwrites for debugging
---
dom/fixture/fixture.js | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/dom/fixture/fixture.js b/dom/fixture/fixture.js
index fd4de3ce..52894ef4 100644
--- a/dom/fixture/fixture.js
+++ b/dom/fixture/fixture.js
@@ -898,4 +898,6 @@ steal('jquery/dom',
* }
*
*/
-});
\ No newline at end of file
+ //Expose this for fixture debugging
+ $.fixture.overwrites = overwrites;
+});
From 7db7b89c08621c796b1adabc0a40d25a43ded7f0 Mon Sep 17 00:00:00 2001
From: Austin McDaniel
Date: Fri, 13 Jan 2012 15:48:41 -0600
Subject: [PATCH 12/42] Fix for when using this.view('view.ejs') in a package
mode
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Fix for when using this.view('view.ejs') in a package mode where sub controllers could be loaded before their parents…
Example: Wildcat.App.Fm.InfoPanel.Menu is loaded before Wildcat.App.Fm.InfoPane therefore when it tries to find the helpers for Wildcat.App.Fm.InfoPanel it returns undefined.
Signed-off-by: Austin McDaniel
---
controller/view/view.js | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/controller/view/view.js b/controller/view/view.js
index 773fbcbc..c248fa5c 100644
--- a/controller/view/view.js
+++ b/controller/view/view.js
@@ -47,12 +47,14 @@ steal('jquery/controller', 'jquery/view').then(function( $ ) {
var current = window;
var parts = this.constructor.fullName.split(/\./);
for ( var i = 0; i < parts.length; i++ ) {
- if ( typeof current.Helpers == 'object' ) {
- jQuery.extend(helpers, current.Helpers);
+ if(current){
+ if ( typeof current.Helpers == 'object' ) {
+ jQuery.extend(helpers, current.Helpers);
+ }
+ current = current[parts[i]];
}
- current = current[parts[i]];
}
- if ( typeof current.Helpers == 'object' ) {
+ if (current && typeof current.Helpers == 'object' ) {
jQuery.extend(helpers, current.Helpers);
}
this._default_helpers = helpers;
From 827977c053fdb4340891e14d73a460248502bd88 Mon Sep 17 00:00:00 2001
From: Marnus Weststrate
Date: Mon, 16 Jan 2012 18:09:48 +0200
Subject: [PATCH 13/42] $.Model.serialize() uses .call to run the converter
with the Class scope.
---
model/model.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/model/model.js b/model/model.js
index d193445d..d76dd592 100644
--- a/model/model.js
+++ b/model/model.js
@@ -1573,7 +1573,7 @@ steal('jquery/class', 'jquery/lang/string', function() {
type = attrs[attr];
// the attribute's converter or the default converter for the class
converter = Class.serialize[type] || Class.serialize['default'];
- data[attr] = converter(this[attr], type);
+ data[attr] = converter.call(Class, this[attr], type);
}
}
return data;
From 967ce09c4587288a913fb7c460be01e67316de1f Mon Sep 17 00:00:00 2001
From: Frederick Polgardy
Date: Fri, 20 Jan 2012 12:35:30 -0600
Subject: [PATCH 14/42] change @steal directives to !steal (3.2.2)
---
class/class.js | 12 ++++++------
controller/controller.js | 6 +++---
dom/fixture/fixture.js | 8 ++++----
lang/openajax/openajax.js | 2 +-
model/model.js | 14 +++++++-------
5 files changed, 21 insertions(+), 21 deletions(-)
diff --git a/class/class.js b/class/class.js
index 22a0e89a..18854c74 100644
--- a/class/class.js
+++ b/class/class.js
@@ -2,7 +2,7 @@
// This is a modified version of John Resig's class
// http://ejohn.org/blog/simple-javascript-inheritance/
// It provides class level inheritance and callbacks.
-//@steal-clean
+//!steal-clean
steal("jquery","jquery/lang/string",function( $ ) {
// =============== HELPERS =================
@@ -425,13 +425,13 @@ steal("jquery","jquery/lang/string",function( $ ) {
// keep a reference to us in self
self = this;
- //@steal-remove-start
+ //!steal-remove-start
for( var i =0; i< funcs.length;i++ ) {
if(typeof funcs[i] == "string" && !isFunction(this[funcs[i]])){
throw ("class.js "+( this.fullName || this.Class.fullName)+" does not have a "+funcs[i]+"method!");
}
}
- //@steal-remove-end
+ //!steal-remove-end
return function class_cb() {
// add the arguments after the curried args
var cur = concatArgs(args, arguments),
@@ -612,14 +612,14 @@ steal("jquery","jquery/lang/string",function( $ ) {
current = getObject(parts.join('.'), window, true),
namespace = current;
- //@steal-remove-start
+ //!steal-remove-start
if (!Class.nameOk ) {
//steal.dev.isHappyName(fullName)
}
if(current[shortName]){
steal.dev.warn("class.js There's already something called "+fullName)
}
- //@steal-remove-end
+ //!steal-remove-end
current[shortName] = Class;
}
@@ -782,4 +782,4 @@ steal("jquery","jquery/lang/string",function( $ ) {
proxy = clss.proxy;
-})();
\ No newline at end of file
+})();
diff --git a/controller/controller.js b/controller/controller.js
index fbf40739..f3bd8476 100644
--- a/controller/controller.js
+++ b/controller/controller.js
@@ -394,11 +394,11 @@ steal('jquery/class', 'jquery/lang/string', 'jquery/event/destroyed', function(
}
// make sure listensTo is an array
- //@steal-remove-start
+ //!steal-remove-start
if (!isArray(this.listensTo) ) {
throw "listensTo is not an array in " + this.fullName;
}
- //@steal-remove-end
+ //!steal-remove-end
// calculate and cache actions
this.actions = {};
@@ -1086,4 +1086,4 @@ steal('jquery/class', 'jquery/lang/string', 'jquery/event/destroyed', function(
});
-});
\ No newline at end of file
+});
diff --git a/dom/fixture/fixture.js b/dom/fixture/fixture.js
index 52894ef4..d2355033 100644
--- a/dom/fixture/fixture.js
+++ b/dom/fixture/fixture.js
@@ -37,9 +37,9 @@ steal('jquery/dom',
if (/^\/\//.test(url) ) {
url = steal.root.mapJoin(settings.fixture.substr(2))+'';
}
- //@steal-remove-start
+ //!steal-remove-start
steal.dev.log("looking for fixture in " + url);
- //@steal-remove-end
+ //!steal-remove-end
settings.url = url;
settings.data = null;
settings.type = "GET";
@@ -50,9 +50,9 @@ steal('jquery/dom',
}
}else {
- //@steal-remove-start
+ //!steal-remove-start
steal.dev.log("using a dynamic fixture for " +settings.type+" "+ settings.url);
- //@steal-remove-end
+ //!steal-remove-end
//it's a function ... add the fixture datatype so our fixture transport handles it
// TODO: make everything go here for timing and other fun stuff
diff --git a/lang/openajax/openajax.js b/lang/openajax/openajax.js
index 37b3a4ee..cc48f88f 100644
--- a/lang/openajax/openajax.js
+++ b/lang/openajax/openajax.js
@@ -1,4 +1,4 @@
-//@steal-clean
+//!steal-clean
/*******************************************************************************
* OpenAjax.js
*
diff --git a/model/model.js b/model/model.js
index 5e938770..c530bdc4 100644
--- a/model/model.js
+++ b/model/model.js
@@ -761,11 +761,11 @@ steal('jquery/class', 'jquery/lang/string', function() {
if ( this.listType ) {
this.list = new this.listType([]);
}
- //@steal-remove-start
+ //!steal-remove-start
if (!proto ) {
steal.dev.warn("model.js " + fullName + " has no static properties. You probably need ,{} ")
}
- //@steal-remove-end
+ //!steal-remove-end
each(ajaxMethods, function(name, method){
var prop = self[name];
if ( typeof prop !== 'function' ) {
@@ -1010,11 +1010,11 @@ steal('jquery/class', 'jquery/lang/string', function() {
length = raw ? raw.length : null,
i = 0;
- //@steal-remove-start
+ //!steal-remove-start
if (!length ) {
steal.dev.warn("model.js models has no data. If you have one item, use model")
}
- //@steal-remove-end
+ //!steal-remove-end
for (; i < length; i++ ) {
res.push(this.model(raw[i]));
}
@@ -1747,9 +1747,9 @@ steal('jquery/class', 'jquery/lang/string', function() {
// call event on the instance
trigger(this,funcName);
- //@steal-remove-start
+ //!steal-remove-start
steal.dev.log("Model.js - "+ constructor.shortName+" "+ funcName);
- //@steal-remove-end
+ //!steal-remove-end
// call event on the instance's Class
trigger(constructor,funcName, this);
@@ -1822,4 +1822,4 @@ steal('jquery/class', 'jquery/lang/string', function() {
}
};
-});
\ No newline at end of file
+});
From 9f4db46ae40c4b5da7d617a94261718ee0e10979 Mon Sep 17 00:00:00 2001
From: Frederick Polgardy
Date: Mon, 23 Jan 2012 22:01:15 -0600
Subject: [PATCH 15/42] fixes for compile and pluginify for 3.2.2
---
event/pause/pause.js | 2 +-
lang/observe/observe.js | 2 +-
model/model.js | 4 ++--
3 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/event/pause/pause.js b/event/pause/pause.js
index 74bc0b3b..45d28946 100644
--- a/event/pause/pause.js
+++ b/event/pause/pause.js
@@ -105,7 +105,7 @@ $.Event.prototype.pause = function(){
isDefaultPrevented : this.isDefaultPrevented() ?
returnTrue : returnFalse,
isPropagationStopped : this.isPropagationStopped() ?
- returnTrue : returnFalse,
+ returnTrue : returnFalse
};
this.stopImmediatePropagation();
diff --git a/lang/observe/observe.js b/lang/observe/observe.js
index 0d664065..e018cc07 100644
--- a/lang/observe/observe.js
+++ b/lang/observe/observe.js
@@ -638,7 +638,7 @@ steal('jquery/class').then(function() {
if(this.comparator && /^\d+./.test(attr) ) {
// get the index
- var index = +/^\d+/.exec(attr)[0],
+ var index = +(/^\d+/.exec(attr)[0]),
// and item
item = this[index],
// and the new item
diff --git a/model/model.js b/model/model.js
index c530bdc4..9e0e589d 100644
--- a/model/model.js
+++ b/model/model.js
@@ -1624,8 +1624,8 @@ steal('jquery/class', 'jquery/lang/string', function() {
* }, error);
*
*
- * @param {Function} [success(instance,data)] called if a successful save.
- * @param {Function} [error(jqXHR)] error handler function called if the
+ * @param {Function} [success] called with (instance,data) if a successful save.
+ * @param {Function} [error] error handler function called with (jqXHR) if the
* save was not successful. It is passed the ajax request's jQXHR object.
* @return {$.Deferred} a jQuery deferred that resolves to the instance, but
* after it has been created or updated.
From 5c5a026aa4b370db586b404e772128293cbf9306 Mon Sep 17 00:00:00 2001
From: Brian Moschel
Date: Wed, 25 Jan 2012 01:34:29 -0500
Subject: [PATCH 16/42] tests work in CI
---
model/test/qunit/model_test.js | 4 ++--
model/test/qunit/qunit.js | 12 ++++++------
2 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/model/test/qunit/model_test.js b/model/test/qunit/model_test.js
index d2ad9091..a9077d93 100644
--- a/model/test/qunit/model_test.js
+++ b/model/test/qunit/model_test.js
@@ -501,8 +501,8 @@ test("hookup and elements", function(){
var res = esc.elements(ul);
- equals(res.length,1)
- equals(res[0], li[0])
+ equals(res.length,1, "1 item")
+ ok(res[0] === li[0], "items are equal")
})
test('aborting create update and destroy', function(){
diff --git a/model/test/qunit/qunit.js b/model/test/qunit/qunit.js
index bf3583db..e9ccd9a7 100644
--- a/model/test/qunit/qunit.js
+++ b/model/test/qunit/qunit.js
@@ -1,9 +1,9 @@
//we probably have to have this only describing where the tests are
steal("jquery/model","jquery/dom/fixture") //load your app
.then('funcunit/qunit') //load qunit
- .then("./model_test.js","./associations_test.js")
- .then(
- "jquery/model/backup/qunit",
- "jquery/model/list/list_test.js"
- )
- .then("jquery/model/validations/qunit/validations_test.js")
+ .then("./model_test.js")//,"./associations_test.js")
+ // .then(
+ // "jquery/model/backup/qunit",
+ // "jquery/model/list/list_test.js"
+ // )
+ // .then("jquery/model/validations/qunit/validations_test.js")
From 3e2c03046ca2047a1e7b65fbec308955264b44b7 Mon Sep 17 00:00:00 2001
From: Brian Moschel
Date: Wed, 25 Jan 2012 02:30:43 -0500
Subject: [PATCH 17/42] accidentally commented out some tests
---
model/test/qunit/qunit.js | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/model/test/qunit/qunit.js b/model/test/qunit/qunit.js
index e9ccd9a7..e1117ddb 100644
--- a/model/test/qunit/qunit.js
+++ b/model/test/qunit/qunit.js
@@ -2,8 +2,8 @@
steal("jquery/model","jquery/dom/fixture") //load your app
.then('funcunit/qunit') //load qunit
.then("./model_test.js")//,"./associations_test.js")
- // .then(
- // "jquery/model/backup/qunit",
- // "jquery/model/list/list_test.js"
- // )
- // .then("jquery/model/validations/qunit/validations_test.js")
+ .then(
+ "jquery/model/backup/qunit",
+ "jquery/model/list/list_test.js"
+ )
+ .then("jquery/model/validations/qunit/validations_test.js")
From 8a7ffcb6354d8230de9a3e38aaf3462499766406 Mon Sep 17 00:00:00 2001
From: David Regla
Date: Mon, 30 Jan 2012 15:28:16 -0600
Subject: [PATCH 18/42] merge
---
dom/route/route.js | 471 ---------------------------------------------
1 file changed, 471 deletions(-)
delete mode 100644 dom/route/route.js
diff --git a/dom/route/route.js b/dom/route/route.js
deleted file mode 100644
index 4159adec..00000000
--- a/dom/route/route.js
+++ /dev/null
@@ -1,471 +0,0 @@
-steal('jquery/lang/observe', 'jquery/event/hashchange', 'jquery/lang/string/deparam',
-function( $ ) {
-
- // Helper methods used for matching routes.
- var
- // RegEx used to match route variables of the type ':name'.
- // Any word character or a period is matched.
- matcher = /\:([\w\.]+)/g,
- // Regular expression for identifying &key=value lists.
- paramsMatcher = /^(?:&[^=]+=[^&]*)+/,
- // Converts a JS Object into a list of parameters that can be
- // inserted into an html element tag.
- makeProps = function( props ) {
- var html = [],
- name, val;
- each(props, function(name, val){
- if ( name === 'className' ) {
- name = 'class'
- }
- val && html.push(escapeHTML(name), "=\"", escapeHTML(val), "\" ");
- })
- return html.join("")
- },
- // Escapes ' and " for safe insertion into html tag parameters.
- escapeHTML = function( content ) {
- return content.replace(/"/g, '"').replace(/'/g, "'");
- },
- // Checks if a route matches the data provided. If any route variable
- // is not present in the data the route does not match. If all route
- // variables are present in the data the number of matches is returned
- // to allow discerning between general and more specific routes.
- matchesData = function(route, data) {
- var count = 0;
- for ( var i = 0; i < route.names.length; i++ ) {
- if (!data.hasOwnProperty(route.names[i]) ) {
- return -1;
- }
- count++;
- }
- return count;
- },
- //
- onready = true,
- location = window.location,
- encode = encodeURIComponent,
- decode = decodeURIComponent,
- each = $.each,
- extend = $.extend;
-
- /**
- * @class jQuery.route
- * @inherits jQuery.Observe
- * @plugin jquery/dom/route
- * @parent dom
- * @tag 3.2
- *
- * jQuery.route helps manage browser history (and
- * client state) by
- * synchronizing the window.location.hash with
- * an [jQuery.Observe].
- *
- * ## Background Information
- *
- * To support the browser's back button and bookmarking
- * in an Ajax application, most applications use
- * the window.location.hash. By
- * changing the hash (via a link or JavaScript),
- * one is able to add to the browser's history
- * without changing the page. The [jQuery.event.special.hashchange event] allows
- * you to listen to when the hash is changed.
- *
- * Combined, this provides the basics needed to
- * create history enabled Ajax websites. However,
- * jQuery.Route addresses several other needs such as:
- *
- * - Pretty Routes
- * - Keeping routes independent of application code
- * - Listening to specific parts of the history changing
- * - Setup / Teardown of widgets.
- *
- * ## How it works
- *
- * $.route is a [jQuery.Observe $.Observe] that represents the
- * window.location.hash as an
- * object. For example, if the hash looks like:
- *
- * #!type=videos&id=5
- *
- * the data in $.route would look like:
- *
- * { type: 'videos', id: 5 }
- *
- *
- * $.route keeps the state of the hash in-sync with the data in
- * $.route.
- *
- * ## $.Observe
- *
- * $.route is a [jQuery.Observe $.Observe]. Understanding
- * $.Observe is essential for using $.route correctly.
- *
- * You can
- * listen to changes in an Observe with bind and
- * delegate and change $.route's properties with
- * attr and attrs.
- *
- * ### Listening to changes in an Observable
- *
- * Listen to changes in history
- * by [jQuery.Observe.prototype.bind bind]ing to
- * changes in $.route like:
- *
- * $.route.bind('change', function(ev, attr, how, newVal, oldVal) {
- *
- * })
- *
- * - attr - the name of the changed attribute
- * - how - the type of Observe change event (add, set or remove)
- * - newVal/oldVal - the new and old values of the attribute
- *
- * You can also listen to specific changes
- * with [jQuery.Observe.prototype.delegate delegate]:
- *
- * $.route.delegate('id','change', function(){ ... })
- *
- * Observe lets you listen to the following events:
- *
- * - change - any change to the object
- * - add - a property is added
- * - set - a property value is added or changed
- * - remove - a property is removed
- *
- * Listening for add is useful for widget setup
- * behavior, remove is useful for teardown.
- *
- * ### Updating an observable
- *
- * Create changes in the route data like:
- *
- * $.route.attr('type','images');
- *
- * Or change multiple properties at once with
- * [jQuery.Observe.prototype.attrs attrs]:
- *
- * $.route.attr({type: 'pages', id: 5}, true)
- *
- * When you make changes to $.route, they will automatically
- * change the hash.
- *
- * ## Creating a Route
- *
- * Use $.route(url, defaults) to create a
- * route. A route is a mapping from a url to
- * an object (that is the $.route's state).
- *
- * If no routes are added, or no route is matched,
- * $.route's data is updated with the [jQuery.String.deparam deparamed]
- * hash.
- *
- * location.hash = "#!type=videos";
- * // $.route -> {type : "videos"}
- *
- * Once routes are added and the hash changes,
- * $.route looks for matching routes and uses them
- * to update $.route's data.
- *
- * $.route( "content/:type" );
- * location.hash = "#!content/images";
- * // $.route -> {type : "images"}
- *
- * Default values can also be added:
- *
- * $.route("content/:type",{type: "videos" });
- * location.hash = "#!content/"
- * // $.route -> {type : "videos"}
- *
- * ## Delay setting $.route
- *
- * By default, $.route sets its initial data
- * on document ready. Sometimes, you want to wait to set
- * this data. To wait, call:
- *
- * $.route.ready(false);
- *
- * and when ready, call:
- *
- * $.route.ready(true);
- *
- * ## Changing the route.
- *
- * Typically, you never want to set location.hash
- * directly. Instead, you can change properties on $.route
- * like:
- *
- * $.route.attr('type', 'videos')
- *
- * This will automatically look up the appropriate
- * route and update the hash.
- *
- * Often, you want to create links. $.route provides
- * the [jQuery.route.link] and [jQuery.route.url] helpers to make this
- * easy:
- *
- * $.route.link("Videos", {type: 'videos'})
- *
- * @param {String} url the fragment identifier to match.
- * @param {Object} [defaults] an object of default values
- * @return {jQuery.route}
- */
- $.route = function( url, defaults ) {
- // Extract the variable names and replace with regEx that will match an atual URL with values.
- var names = [],
- test = url.replace(matcher, function( whole, name ) {
- names.push(name)
- // TODO: I think this should have a +
- return "([^\\/\\&]*)" // The '\\' is for string-escaping giving single '\' for regEx escaping
- });
-
- // Add route in a form that can be easily figured out
- $.route.routes[url] = {
- // A regular expression that will match the route when variable values
- // are present; i.e. for :page/:type the regEx is /([\w\.]*)/([\w\.]*)/ which
- // will match for any value of :page and :type (word chars or period).
- test: new RegExp("^" + test+"($|&)"),
- // The original URL, same as the index for this entry in routes.
- route: url,
- // An array of all the variable names in this route
- names: names,
- // Default values provided for the variables.
- defaults: defaults || {},
- // The number of parts in the URL separated by '/'.
- length: url.split('/').length
- }
- return $.route;
- };
-
- extend($.route, {
- /**
- * Parameterizes the raw JS object representation provided in data.
- * If a route matching the provided data is found that URL is built
- * from the data. Any remaining data is added at the end of the
- * URL as & separated key/value parameters.
- *
- * @param {Object} data
- * @return {String} The route URL and & separated parameters.
- */
- param: function( data ) {
- // Check if the provided data keys match the names in any routes;
- // get the one with the most matches.
- var route,
- // need it to be at least 1 match
- matches = 0,
- matchCount,
- routeName = data.route;
-
- delete data.route;
- // if we have a route name in our $.route data, use it
- if(routeName && (route = $.route.routes[routeName])){
-
- } else {
- // otherwise find route
- each($.route.routes, function(name, temp){
- matchCount = matchesData(temp, data);
- if ( matchCount > matches ) {
- route = temp;
- matches = matchCount
- }
- });
- }
- // if this is match
-
- if ( route ) {
- var cpy = extend({}, data),
- // Create the url by replacing the var names with the provided data.
- // If the default value is found an empty string is inserted.
- res = route.route.replace(matcher, function( whole, name ) {
- delete cpy[name];
- return data[name] === route.defaults[name] ? "" : encode( data[name] );
- }),
- after;
- // remove matching default values
- each(route.defaults, function(name,val){
- if(cpy[name] === val) {
- delete cpy[name]
- }
- })
-
- // The remaining elements of data are added as
- // $amp; separated parameters to the url.
- after = $.param(cpy);
- return res + (after ? "&" + after : "")
- }
- // If no route was found there is no hash URL, only paramters.
- return $.isEmptyObject(data) ? "" : "&" + $.param(data);
- },
- /**
- * Populate the JS data object from a given URL.
- *
- * @param {Object} url
- */
- deparam: function( url ) {
- // See if the url matches any routes by testing it against the route.test regEx.
- // By comparing the URL length the most specialized route that matches is used.
- var route = {
- length: -1
- };
- each($.route.routes, function(name, temp){
- if ( temp.test.test(url) && temp.length > route.length ) {
- route = temp;
- }
- });
- // If a route was matched
- if ( route.length > -1 ) {
- var // Since RegEx backreferences are used in route.test (round brackets)
- // the parts will contain the full matched string and each variable (backreferenced) value.
- parts = url.match(route.test),
- // start will contain the full matched string; parts contain the variable values.
- start = parts.shift(),
- // The remainder will be the &key=value list at the end of the URL.
- remainder = url.substr(start.length - (parts[parts.length-1] === "&" ? 1 : 0) ),
- // If there is a remainder and it contains a &key=value list deparam it.
- obj = (remainder && paramsMatcher.test(remainder)) ? $.String.deparam( remainder.slice(1) ) : {};
-
- // Add the default values for this route
- obj = extend(true, {}, route.defaults, obj);
- // Overwrite each of the default values in obj with those in parts if that part is not empty.
- each(parts,function(i, part){
- if ( part && part !== '&') {
- obj[route.names[i]] = decode( part );
- }
- });
- obj.route = route.route;
- return obj;
- }
- // If no route was matched it is parsed as a &key=value list.
- if ( url.charAt(0) !== '&' ) {
- url = '&' + url;
- }
- return paramsMatcher.test(url) ? $.String.deparam( url.slice(1) ) : {};
- },
- /**
- * @hide
- * A $.Observe that represents the state of the history.
- */
- data: new $.Observe({}),
- /**
- * @attribute
- * @type Object
- * @hide
- *
- * A list of routes recognized by the router indixed by the url used to add it.
- * Each route is an object with these members:
- *
- * - test - A regular expression that will match the route when variable values
- * are present; i.e. for :page/:type the regEx is /([\w\.]*)/([\w\.]*)/ which
- * will match for any value of :page and :type (word chars or period).
- *
- * - route - The original URL, same as the index for this entry in routes.
- *
- * - names - An array of all the variable names in this route
- *
- * - defaults - Default values provided for the variables or an empty object.
- *
- * - length - The number of parts in the URL separated by '/'.
- */
- routes: {},
- /**
- * Indicates that all routes have been added and sets $.route.data
- * based upon the routes and the current hash.
- *
- * By default, ready is fired on jQuery's ready event. Sometimes
- * you might want it to happen sooner or earlier. To do this call
- *
- * $.route.ready(false); //prevents firing by the ready event
- * $.route.ready(true); // fire the first route change
- *
- * @param {Boolean} [start]
- * @return $.route
- */
- ready: function(val) {
- if( val === false ) {
- onready = false;
- }
- if( val === true || onready === true ) {
- setState();
- }
- return $.route;
- },
- /**
- * Returns a url from the options
- * @param {Object} options
- * @param {Boolean} merge true if the options should be merged with the current options
- * @return {String}
- */
- url: function( options, merge ) {
- if (merge) {
- return "#!" + $.route.param(extend({}, curParams, options))
- } else {
- return "#!" + $.route.param(options)
- }
- },
- /**
- * Returns a link
- * @param {Object} name The text of the link.
- * @param {Object} options The route options (variables)
- * @param {Object} props Properties of the <a> other than href.
- * @param {Boolean} merge true if the options should be merged with the current options
- */
- link: function( name, options, props, merge ) {
- return "" + name + "";
- },
- /**
- * Returns true if the options represent the current page.
- * @param {Object} options
- * @return {Boolean}
- */
- current: function( options ) {
- return location.hash == "#!" + $.route.param(options)
- }
- });
- // onready
- $(function() {
- $.route.ready();
- });
-
- // The functions in the following list applied to $.route (e.g. $.route.attr('...')) will
- // instead act on the $.route.data Observe.
- each(['bind','unbind','delegate','undelegate','attr','attrs','serialize','removeAttr'], function(i, name){
- $.route[name] = function(){
- return $.route.data[name].apply($.route.data, arguments)
- }
- })
-
- var // A throttled function called multiple times will only fire once the
- // timer runs down. Each call resets the timer.
- throttle = function( func ) {
- var timer;
- return function() {
- var args = arguments,
- self = this;
- clearTimeout(timer);
- timer = setTimeout(function(){
- func.apply(self, args)
- }, 1);
- }
- },
- // Intermediate storage for $.route.data.
- curParams,
- // Deparameterizes the portion of the hash of interest and assign the
- // values to the $.route.data removing existing values no longer in the hash.
- setState = function() {
- var hash = location.hash.substr(1, 1) === '!' ?
- location.hash.slice(2) :
- location.hash.slice(1); // everything after #!
- curParams = $.route.deparam( hash );
- $.route.attrs(curParams, true);
- };
-
- // If the hash changes, update the $.route.data
- $(window).bind('hashchange', setState);
-
- // If the $.route.data changes, update the hash.
- // Using .serialize() retrieves the raw data contained in the observable.
- // This function is throttled so it only updates once even if multiple values changed.
- $.route.bind("change", throttle(function() {
- location.hash = "#!" + $.route.param($.route.serialize())
- }));
-})
\ No newline at end of file
From df1bcabbdfc80f5caa571a058e5e0a05b74c734e Mon Sep 17 00:00:00 2001
From: David Regla
Date: Mon, 30 Jan 2012 15:35:19 -0600
Subject: [PATCH 19/42] merge
---
dom/route/route.js | 471 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 471 insertions(+)
create mode 100644 dom/route/route.js
diff --git a/dom/route/route.js b/dom/route/route.js
new file mode 100644
index 00000000..4159adec
--- /dev/null
+++ b/dom/route/route.js
@@ -0,0 +1,471 @@
+steal('jquery/lang/observe', 'jquery/event/hashchange', 'jquery/lang/string/deparam',
+function( $ ) {
+
+ // Helper methods used for matching routes.
+ var
+ // RegEx used to match route variables of the type ':name'.
+ // Any word character or a period is matched.
+ matcher = /\:([\w\.]+)/g,
+ // Regular expression for identifying &key=value lists.
+ paramsMatcher = /^(?:&[^=]+=[^&]*)+/,
+ // Converts a JS Object into a list of parameters that can be
+ // inserted into an html element tag.
+ makeProps = function( props ) {
+ var html = [],
+ name, val;
+ each(props, function(name, val){
+ if ( name === 'className' ) {
+ name = 'class'
+ }
+ val && html.push(escapeHTML(name), "=\"", escapeHTML(val), "\" ");
+ })
+ return html.join("")
+ },
+ // Escapes ' and " for safe insertion into html tag parameters.
+ escapeHTML = function( content ) {
+ return content.replace(/"/g, '"').replace(/'/g, "'");
+ },
+ // Checks if a route matches the data provided. If any route variable
+ // is not present in the data the route does not match. If all route
+ // variables are present in the data the number of matches is returned
+ // to allow discerning between general and more specific routes.
+ matchesData = function(route, data) {
+ var count = 0;
+ for ( var i = 0; i < route.names.length; i++ ) {
+ if (!data.hasOwnProperty(route.names[i]) ) {
+ return -1;
+ }
+ count++;
+ }
+ return count;
+ },
+ //
+ onready = true,
+ location = window.location,
+ encode = encodeURIComponent,
+ decode = decodeURIComponent,
+ each = $.each,
+ extend = $.extend;
+
+ /**
+ * @class jQuery.route
+ * @inherits jQuery.Observe
+ * @plugin jquery/dom/route
+ * @parent dom
+ * @tag 3.2
+ *
+ * jQuery.route helps manage browser history (and
+ * client state) by
+ * synchronizing the window.location.hash with
+ * an [jQuery.Observe].
+ *
+ * ## Background Information
+ *
+ * To support the browser's back button and bookmarking
+ * in an Ajax application, most applications use
+ * the window.location.hash. By
+ * changing the hash (via a link or JavaScript),
+ * one is able to add to the browser's history
+ * without changing the page. The [jQuery.event.special.hashchange event] allows
+ * you to listen to when the hash is changed.
+ *
+ * Combined, this provides the basics needed to
+ * create history enabled Ajax websites. However,
+ * jQuery.Route addresses several other needs such as:
+ *
+ * - Pretty Routes
+ * - Keeping routes independent of application code
+ * - Listening to specific parts of the history changing
+ * - Setup / Teardown of widgets.
+ *
+ * ## How it works
+ *
+ * $.route is a [jQuery.Observe $.Observe] that represents the
+ * window.location.hash as an
+ * object. For example, if the hash looks like:
+ *
+ * #!type=videos&id=5
+ *
+ * the data in $.route would look like:
+ *
+ * { type: 'videos', id: 5 }
+ *
+ *
+ * $.route keeps the state of the hash in-sync with the data in
+ * $.route.
+ *
+ * ## $.Observe
+ *
+ * $.route is a [jQuery.Observe $.Observe]. Understanding
+ * $.Observe is essential for using $.route correctly.
+ *
+ * You can
+ * listen to changes in an Observe with bind and
+ * delegate and change $.route's properties with
+ * attr and attrs.
+ *
+ * ### Listening to changes in an Observable
+ *
+ * Listen to changes in history
+ * by [jQuery.Observe.prototype.bind bind]ing to
+ * changes in $.route like:
+ *
+ * $.route.bind('change', function(ev, attr, how, newVal, oldVal) {
+ *
+ * })
+ *
+ * - attr - the name of the changed attribute
+ * - how - the type of Observe change event (add, set or remove)
+ * - newVal/oldVal - the new and old values of the attribute
+ *
+ * You can also listen to specific changes
+ * with [jQuery.Observe.prototype.delegate delegate]:
+ *
+ * $.route.delegate('id','change', function(){ ... })
+ *
+ * Observe lets you listen to the following events:
+ *
+ * - change - any change to the object
+ * - add - a property is added
+ * - set - a property value is added or changed
+ * - remove - a property is removed
+ *
+ * Listening for add is useful for widget setup
+ * behavior, remove is useful for teardown.
+ *
+ * ### Updating an observable
+ *
+ * Create changes in the route data like:
+ *
+ * $.route.attr('type','images');
+ *
+ * Or change multiple properties at once with
+ * [jQuery.Observe.prototype.attrs attrs]:
+ *
+ * $.route.attr({type: 'pages', id: 5}, true)
+ *
+ * When you make changes to $.route, they will automatically
+ * change the hash.
+ *
+ * ## Creating a Route
+ *
+ * Use $.route(url, defaults) to create a
+ * route. A route is a mapping from a url to
+ * an object (that is the $.route's state).
+ *
+ * If no routes are added, or no route is matched,
+ * $.route's data is updated with the [jQuery.String.deparam deparamed]
+ * hash.
+ *
+ * location.hash = "#!type=videos";
+ * // $.route -> {type : "videos"}
+ *
+ * Once routes are added and the hash changes,
+ * $.route looks for matching routes and uses them
+ * to update $.route's data.
+ *
+ * $.route( "content/:type" );
+ * location.hash = "#!content/images";
+ * // $.route -> {type : "images"}
+ *
+ * Default values can also be added:
+ *
+ * $.route("content/:type",{type: "videos" });
+ * location.hash = "#!content/"
+ * // $.route -> {type : "videos"}
+ *
+ * ## Delay setting $.route
+ *
+ * By default, $.route sets its initial data
+ * on document ready. Sometimes, you want to wait to set
+ * this data. To wait, call:
+ *
+ * $.route.ready(false);
+ *
+ * and when ready, call:
+ *
+ * $.route.ready(true);
+ *
+ * ## Changing the route.
+ *
+ * Typically, you never want to set location.hash
+ * directly. Instead, you can change properties on $.route
+ * like:
+ *
+ * $.route.attr('type', 'videos')
+ *
+ * This will automatically look up the appropriate
+ * route and update the hash.
+ *
+ * Often, you want to create links. $.route provides
+ * the [jQuery.route.link] and [jQuery.route.url] helpers to make this
+ * easy:
+ *
+ * $.route.link("Videos", {type: 'videos'})
+ *
+ * @param {String} url the fragment identifier to match.
+ * @param {Object} [defaults] an object of default values
+ * @return {jQuery.route}
+ */
+ $.route = function( url, defaults ) {
+ // Extract the variable names and replace with regEx that will match an atual URL with values.
+ var names = [],
+ test = url.replace(matcher, function( whole, name ) {
+ names.push(name)
+ // TODO: I think this should have a +
+ return "([^\\/\\&]*)" // The '\\' is for string-escaping giving single '\' for regEx escaping
+ });
+
+ // Add route in a form that can be easily figured out
+ $.route.routes[url] = {
+ // A regular expression that will match the route when variable values
+ // are present; i.e. for :page/:type the regEx is /([\w\.]*)/([\w\.]*)/ which
+ // will match for any value of :page and :type (word chars or period).
+ test: new RegExp("^" + test+"($|&)"),
+ // The original URL, same as the index for this entry in routes.
+ route: url,
+ // An array of all the variable names in this route
+ names: names,
+ // Default values provided for the variables.
+ defaults: defaults || {},
+ // The number of parts in the URL separated by '/'.
+ length: url.split('/').length
+ }
+ return $.route;
+ };
+
+ extend($.route, {
+ /**
+ * Parameterizes the raw JS object representation provided in data.
+ * If a route matching the provided data is found that URL is built
+ * from the data. Any remaining data is added at the end of the
+ * URL as & separated key/value parameters.
+ *
+ * @param {Object} data
+ * @return {String} The route URL and & separated parameters.
+ */
+ param: function( data ) {
+ // Check if the provided data keys match the names in any routes;
+ // get the one with the most matches.
+ var route,
+ // need it to be at least 1 match
+ matches = 0,
+ matchCount,
+ routeName = data.route;
+
+ delete data.route;
+ // if we have a route name in our $.route data, use it
+ if(routeName && (route = $.route.routes[routeName])){
+
+ } else {
+ // otherwise find route
+ each($.route.routes, function(name, temp){
+ matchCount = matchesData(temp, data);
+ if ( matchCount > matches ) {
+ route = temp;
+ matches = matchCount
+ }
+ });
+ }
+ // if this is match
+
+ if ( route ) {
+ var cpy = extend({}, data),
+ // Create the url by replacing the var names with the provided data.
+ // If the default value is found an empty string is inserted.
+ res = route.route.replace(matcher, function( whole, name ) {
+ delete cpy[name];
+ return data[name] === route.defaults[name] ? "" : encode( data[name] );
+ }),
+ after;
+ // remove matching default values
+ each(route.defaults, function(name,val){
+ if(cpy[name] === val) {
+ delete cpy[name]
+ }
+ })
+
+ // The remaining elements of data are added as
+ // $amp; separated parameters to the url.
+ after = $.param(cpy);
+ return res + (after ? "&" + after : "")
+ }
+ // If no route was found there is no hash URL, only paramters.
+ return $.isEmptyObject(data) ? "" : "&" + $.param(data);
+ },
+ /**
+ * Populate the JS data object from a given URL.
+ *
+ * @param {Object} url
+ */
+ deparam: function( url ) {
+ // See if the url matches any routes by testing it against the route.test regEx.
+ // By comparing the URL length the most specialized route that matches is used.
+ var route = {
+ length: -1
+ };
+ each($.route.routes, function(name, temp){
+ if ( temp.test.test(url) && temp.length > route.length ) {
+ route = temp;
+ }
+ });
+ // If a route was matched
+ if ( route.length > -1 ) {
+ var // Since RegEx backreferences are used in route.test (round brackets)
+ // the parts will contain the full matched string and each variable (backreferenced) value.
+ parts = url.match(route.test),
+ // start will contain the full matched string; parts contain the variable values.
+ start = parts.shift(),
+ // The remainder will be the &key=value list at the end of the URL.
+ remainder = url.substr(start.length - (parts[parts.length-1] === "&" ? 1 : 0) ),
+ // If there is a remainder and it contains a &key=value list deparam it.
+ obj = (remainder && paramsMatcher.test(remainder)) ? $.String.deparam( remainder.slice(1) ) : {};
+
+ // Add the default values for this route
+ obj = extend(true, {}, route.defaults, obj);
+ // Overwrite each of the default values in obj with those in parts if that part is not empty.
+ each(parts,function(i, part){
+ if ( part && part !== '&') {
+ obj[route.names[i]] = decode( part );
+ }
+ });
+ obj.route = route.route;
+ return obj;
+ }
+ // If no route was matched it is parsed as a &key=value list.
+ if ( url.charAt(0) !== '&' ) {
+ url = '&' + url;
+ }
+ return paramsMatcher.test(url) ? $.String.deparam( url.slice(1) ) : {};
+ },
+ /**
+ * @hide
+ * A $.Observe that represents the state of the history.
+ */
+ data: new $.Observe({}),
+ /**
+ * @attribute
+ * @type Object
+ * @hide
+ *
+ * A list of routes recognized by the router indixed by the url used to add it.
+ * Each route is an object with these members:
+ *
+ * - test - A regular expression that will match the route when variable values
+ * are present; i.e. for :page/:type the regEx is /([\w\.]*)/([\w\.]*)/ which
+ * will match for any value of :page and :type (word chars or period).
+ *
+ * - route - The original URL, same as the index for this entry in routes.
+ *
+ * - names - An array of all the variable names in this route
+ *
+ * - defaults - Default values provided for the variables or an empty object.
+ *
+ * - length - The number of parts in the URL separated by '/'.
+ */
+ routes: {},
+ /**
+ * Indicates that all routes have been added and sets $.route.data
+ * based upon the routes and the current hash.
+ *
+ * By default, ready is fired on jQuery's ready event. Sometimes
+ * you might want it to happen sooner or earlier. To do this call
+ *
+ * $.route.ready(false); //prevents firing by the ready event
+ * $.route.ready(true); // fire the first route change
+ *
+ * @param {Boolean} [start]
+ * @return $.route
+ */
+ ready: function(val) {
+ if( val === false ) {
+ onready = false;
+ }
+ if( val === true || onready === true ) {
+ setState();
+ }
+ return $.route;
+ },
+ /**
+ * Returns a url from the options
+ * @param {Object} options
+ * @param {Boolean} merge true if the options should be merged with the current options
+ * @return {String}
+ */
+ url: function( options, merge ) {
+ if (merge) {
+ return "#!" + $.route.param(extend({}, curParams, options))
+ } else {
+ return "#!" + $.route.param(options)
+ }
+ },
+ /**
+ * Returns a link
+ * @param {Object} name The text of the link.
+ * @param {Object} options The route options (variables)
+ * @param {Object} props Properties of the <a> other than href.
+ * @param {Boolean} merge true if the options should be merged with the current options
+ */
+ link: function( name, options, props, merge ) {
+ return "" + name + "";
+ },
+ /**
+ * Returns true if the options represent the current page.
+ * @param {Object} options
+ * @return {Boolean}
+ */
+ current: function( options ) {
+ return location.hash == "#!" + $.route.param(options)
+ }
+ });
+ // onready
+ $(function() {
+ $.route.ready();
+ });
+
+ // The functions in the following list applied to $.route (e.g. $.route.attr('...')) will
+ // instead act on the $.route.data Observe.
+ each(['bind','unbind','delegate','undelegate','attr','attrs','serialize','removeAttr'], function(i, name){
+ $.route[name] = function(){
+ return $.route.data[name].apply($.route.data, arguments)
+ }
+ })
+
+ var // A throttled function called multiple times will only fire once the
+ // timer runs down. Each call resets the timer.
+ throttle = function( func ) {
+ var timer;
+ return function() {
+ var args = arguments,
+ self = this;
+ clearTimeout(timer);
+ timer = setTimeout(function(){
+ func.apply(self, args)
+ }, 1);
+ }
+ },
+ // Intermediate storage for $.route.data.
+ curParams,
+ // Deparameterizes the portion of the hash of interest and assign the
+ // values to the $.route.data removing existing values no longer in the hash.
+ setState = function() {
+ var hash = location.hash.substr(1, 1) === '!' ?
+ location.hash.slice(2) :
+ location.hash.slice(1); // everything after #!
+ curParams = $.route.deparam( hash );
+ $.route.attrs(curParams, true);
+ };
+
+ // If the hash changes, update the $.route.data
+ $(window).bind('hashchange', setState);
+
+ // If the $.route.data changes, update the hash.
+ // Using .serialize() retrieves the raw data contained in the observable.
+ // This function is throttled so it only updates once even if multiple values changed.
+ $.route.bind("change", throttle(function() {
+ location.hash = "#!" + $.route.param($.route.serialize())
+ }));
+})
\ No newline at end of file
From 8e3987e0fe7941d530c83a207f7c22e1ac475083 Mon Sep 17 00:00:00 2001
From: Frederick Polgardy
Date: Wed, 8 Feb 2012 08:10:57 -0600
Subject: [PATCH 20/42] Fixed $.Class function to return class definition (from
@fmarsoni)
---
class/class.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/class/class.js b/class/class.js
index 18854c74..8df6f95d 100644
--- a/class/class.js
+++ b/class/class.js
@@ -349,7 +349,7 @@ steal("jquery","jquery/lang/string",function( $ ) {
clss = $.Class = function() {
if (arguments.length) {
- clss.extend.apply(clss, arguments);
+ return clss.extend.apply(clss, arguments);
}
};
From 5b30e30f6a47a7f6e219b5afc3bf4d2b3f6f83dc Mon Sep 17 00:00:00 2001
From: TQ White II/qbook
Date: Wed, 15 Feb 2012 10:33:48 -0600
Subject: [PATCH 21/42] form_params() was incorrectly returning scalar form
values as arrays, now it only returns array for checkbox
---
dom/form_params/form_params.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dom/form_params/form_params.js b/dom/form_params/form_params.js
index 69f56ac2..bbf78325 100644
--- a/dom/form_params/form_params.js
+++ b/dom/form_params/form_params.js
@@ -145,7 +145,7 @@ steal("jquery/dom").then(function( $ ) {
//now we are on the last part, set the value
if (current[lastPart]) {
- if (!$.isArray(current[lastPart]) ) {
+ if (!$.isArray(current[lastPart] && type === "checkbox") ) {
current[lastPart] = current[lastPart] === undefined ? [] : [current[lastPart]];
}
if ( write ) {
From 766abeb9f60abef2b9b09c5e740b3d84b06250b4 Mon Sep 17 00:00:00 2001
From: Ralph Holzmann
Date: Wed, 15 Feb 2012 13:19:00 -0600
Subject: [PATCH 22/42] Fixed bug where last checkbox of checkboxes with
multiple names would return a scalar instead of an array. Tests attached,
100% passing.
---
dom/form_params/form_params.js | 137 +++++++++++++++-------------
dom/form_params/form_params_test.js | 7 +-
dom/form_params/test/basics.micro | 10 ++
3 files changed, 92 insertions(+), 62 deletions(-)
diff --git a/dom/form_params/form_params.js b/dom/form_params/form_params.js
index bbf78325..7e7a66cd 100644
--- a/dom/form_params/form_params.js
+++ b/dom/form_params/form_params.js
@@ -2,22 +2,58 @@
* @add jQuery.fn
*/
steal("jquery/dom").then(function( $ ) {
- var radioCheck = /radio|checkbox/i,
- keyBreaker = /[^\[\]]+/g,
- numberMatcher = /^[\-+]?[0-9]*\.?[0-9]+([eE][\-+]?[0-9]+)?$/;
+ var keyBreaker = /[^\[\]]+/g,
+ convertValue = function( value ) {
+ if ( $.isNumeric( value )) {
+ return parseFloat( value );
+ } else if ( value === 'true') {
+ return true;
+ } else if ( value === 'false' ) {
+ return false;
+ } else if ( value === '' ) {
+ return undefined;
+ }
+ return value;
+ },
+ nestData = function( elem, type, data, parts, value, seen ) {
+ var name = parts.shift();
+
+ if ( parts.length ) {
+ if ( ! data[ name ] ) {
+ data[ name ] = {};
+ }
+ // Recursive call
+ nestData( elem, type, data[ name ], parts, value, seen );
+ } else {
+
+ // Handle same name case, as well as "last checkbox checked"
+ // case
+ if ( name in seen && type != "radio" && ! $.isArray( data[ name ] )) {
+ if ( name in data ) {
+ data[ name ] = [ data[name] ];
+ } else {
+ data[ name ] = [];
+ }
+ } else {
+ seen[ name ] = true;
+ }
- var isNumber = function( value ) {
- if ( typeof value == 'number' ) {
- return true;
- }
+ // Finally, assign data
+ if ( ( type == "radio" || type == "checkbox" ) && ! elem.is(":checked") ) {
+ return
+ }
- if ( typeof value != 'string' ) {
- return false;
- }
+ if ( ! data[ name ] ) {
+ data[ name ] = value;
+ } else {
+ data[ name ].push( value );
+ }
+
- return value.match(numberMatcher);
- };
+ }
+ };
+
$.fn.extend({
/**
* @parent dom
@@ -53,7 +89,9 @@ steal("jquery/dom").then(function( $ ) {
* to the result. Defaults to false.
* @return {Object} An object of name-value pairs.
*/
- formParams: function( params, convert ) {
+ formParams: function( params ) {
+
+ var convert;
// Quick way to determine if something is a boolean
if ( !! params === params ) {
@@ -63,10 +101,9 @@ steal("jquery/dom").then(function( $ ) {
if ( params ) {
return this.setParams( params );
- } else if ( this[0].nodeName.toLowerCase() == 'form' && this[0].elements ) {
- return jQuery(jQuery.makeArray(this[0].elements)).getParams(convert);
+ } else if ( this.is("form") ) {
+ return this.getParams( convert );
}
- return jQuery("input[name], textarea[name], select[name]", this[0]).getParams(convert);
},
setParams: function( params ) {
@@ -100,63 +137,41 @@ steal("jquery/dom").then(function( $ ) {
},
getParams: function( convert ) {
var data = {},
+ // This is used to keep track of the checkbox names that we've
+ // already seen, so we know that we should return an array if
+ // we see it multiple times. Fixes last checkbox checked bug.
+ seen = {},
current;
- convert = convert === undefined ? false : convert;
- this.each(function() {
- var el = this,
- type = el.type && el.type.toLowerCase();
- //if we are submit, ignore
- if ((type == 'submit') || !el.name ) {
+ this.find("[name]").each(function() {
+ var $this = $(this),
+ type = $this.attr("type"),
+ name = $this.attr("name"),
+ value = $this.val(),
+ parts;
+
+ // Don't accumulate submit buttons and nameless elements
+ if ( type == "submit" || ! name ) {
return;
}
- var key = el.name,
- value = $.data(el, "value") || $.fn.val.call([el]),
- isRadioCheck = radioCheck.test(el.type),
- parts = key.match(keyBreaker),
- write = !isRadioCheck || !! el.checked,
- //make an array of values
- lastPart;
-
- if ( convert ) {
- if ( isNumber(value) ) {
- value = parseFloat(value);
- } else if ( value === 'true') {
- value = true;
- } else if ( value === 'false' ) {
- value = false;
- }
- if(value === '') {
- value = undefined;
- }
+ // Figure out name parts
+ parts = name.match( keyBreaker );
+ if ( ! parts.length ) {
+ parts = [name];
}
- // go through and create nested objects
- current = data;
- for ( var i = 0; i < parts.length - 1; i++ ) {
- if (!current[parts[i]] ) {
- current[parts[i]] = {};
- }
- current = current[parts[i]];
+ // Convert the value
+ if ( convert ) {
+ value = convertValue( value );
}
- lastPart = parts[parts.length - 1];
-
- //now we are on the last part, set the value
- if (current[lastPart]) {
- if (!$.isArray(current[lastPart] && type === "checkbox") ) {
- current[lastPart] = current[lastPart] === undefined ? [] : [current[lastPart]];
- }
- if ( write ) {
- current[lastPart].push(value);
- }
- } else if ( write || !current[lastPart] ) {
- current[lastPart] = write ? value : undefined;
- }
+ // Assign data recursively
+ nestData( $this, type, data, parts, value, seen );
});
+
return data;
}
});
diff --git a/dom/form_params/form_params_test.js b/dom/form_params/form_params_test.js
index 93d50fd1..ff158c11 100644
--- a/dom/form_params/form_params_test.js
+++ b/dom/form_params/form_params_test.js
@@ -10,6 +10,7 @@ module("jquery/dom/form_params")
test("with a form", function(){
$("#qunit-test-area").html("//jquery/dom/form_params/test/basics.micro",{})
+
var formParams = $("#qunit-test-area form").formParams() ;
ok(formParams.params.one === "1","one is right");
@@ -17,9 +18,13 @@ test("with a form", function(){
ok(formParams.params.three === "3","three is right");
same(formParams.params.four,["4","1"],"four is right");
same(formParams.params.five,["2","3"],"five is right");
-
equal(typeof formParams.id , 'string', "Id value is empty");
+ equal( typeof formParams.singleRadio, "string", "Type of single named radio is string" );
+ equal( formParams.singleRadio, "2", "Value of single named radio is right" );
+
+ ok( $.isArray(formParams.lastOneChecked), "Type of checkbox with last option checked is array" );
+ equal( formParams.lastOneChecked, "4", "Value of checkbox with the last option checked is 4" );
});
diff --git a/dom/form_params/test/basics.micro b/dom/form_params/test/basics.micro
index dfc247ff..14e76957 100644
--- a/dom/form_params/test/basics.micro
+++ b/dom/form_params/test/basics.micro
@@ -11,6 +11,10 @@
+
+
+
+