diff --git a/README b/README index 19b1dfba..f5535b09 100644 --- a/README +++ b/README @@ -22,3 +22,4 @@ A. How to get (and contribute) JMVC 5. Make changes in steal or jquerymx, and push them back to your fork. 6. Make a pull request to your fork. + diff --git a/class/class.js b/class/class.js index 22a0e89a..b48d1d00 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 ================= @@ -61,7 +61,7 @@ steal("jquery","jquery/lang/string",function( $ ) { * @test jquery/class/qunit.html * @description Easy inheritance in JavaScript. * - * Class provides simulated inheritance in JavaScript. Use clss to bridge the gap between + * Class provides simulated inheritance in JavaScript. Use Class to bridge the gap between * jQuery's functional programming style and Object Oriented Programming. It * is based off John Resig's [http://ejohn.org/blog/simple-javascript-inheritance/|Simple Class] * Inheritance library. Besides prototypal inheritance, it includes a few important features: @@ -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); } }; @@ -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/controller/view/view.js b/controller/view/view.js index 5c05345f..c248fa5c 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; }; @@ -45,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; diff --git a/dom/fixture/fixture.js b/dom/fixture/fixture.js index f2a020dc..672b5a7b 100644 --- a/dom/fixture/fixture.js +++ b/dom/fixture/fixture.js @@ -35,11 +35,14 @@ steal('jquery/dom', var url = settings.fixture; if (/^\/\//.test(url) ) { - url = steal.root.mapJoin(settings.fixture.substr(2)); + var sub = settings.fixture.substr(2) + ''; + url = typeof steal === "undefined" ? + url = "/" + sub : + steal.root.mapJoin(sub) +''; } - //@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 +53,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 @@ -898,4 +901,6 @@ steal('jquery/dom', * } * */ -}); \ No newline at end of file + //Expose this for fixture debugging + $.fixture.overwrites = overwrites; +}); 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/dom/form_params/form_params.js b/dom/form_params/form_params.js index cbfc7f6c..0234c4d4 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 { + return this.getParams( convert ); } - return jQuery("input[name], textarea[name], select[name]", this[0]).getParams(convert); }, setParams: function( params ) { @@ -77,7 +114,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,67 +133,45 @@ steal("jquery/dom").then(function( $ ) { $this.val( value ); } } - }); + }); }, 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]) ) { - 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..2a9e2f3c 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,12 +18,26 @@ 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" ); }); +test("With a non-form element", function() { + + $("#qunit-test-area").html("//jquery/dom/form_params/test/non-form.micro",{}) + + var formParams = $("#divform").formParams() ; + + equal( formParams.id , "foo-bar-baz", "ID input read correctly" ); + +}); + test("with true false", function(){ $("#qunit-test-area").html("//jquery/dom/form_params/test/truthy.micro",{}); 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 @@ + + + +