Browse files

can now apply a serialized object or array back to a form

  • Loading branch information...
1 parent 3115812 commit ddbf89e48e73861ddbd784b4f3e3cd6f9ee9be1f @fojas committed May 8, 2012
Showing with 419 additions and 0 deletions.
  1. +37 −0 jquery-serializeObject.js
  2. +1 −0 tests/index.html
  3. +325 −0 tests/lib/jasmine-jquery.js
  4. +56 −0 tests/specs/jquery-serializeObject_spec.js
View
37 jquery-serializeObject.js
@@ -61,9 +61,46 @@ $.deserializeObject = function deserializeObject(json,arr,prefix){
return arr;
}
+var check = function(){
+ // older versions of jQuery do not have prop
+ var propExists = !!$.fn.prop;
+ return function(obj,checked){
+ if(propExists) obj.prop('checked',checked);
+ else obj.attr('checked', (checked ? 'checked' : null ));
+ };
+}();
+
+$.applySerializedArray = function(form,obj){
+ var $form = $(form).find('input,select,textarea'), el;
+ check($form.filter(':checked'),false)
+ for(var i = obj.length;i--;){
+ el = $form.filter("[name='"+obj[i].name+"']");
+ if(el.filter(':checkbox').length){
+ if(el.val() == obj[i].value) check(el.filter(':checkbox'),true);
+ }else if(el.filter(':radio').length){
+ check(el.filter("[value='"+obj[i].value+"']"),true)
+ } else {
+ el.val(obj[i].value);
+ }
+ }
+};
+
+$.applySerializedObject = function(form, obj){
+ $.applySerializedArray(form,$.deserializeObject(obj));
+};
+
$.fn.serializeObject = $.fn.serializeObject || function(){
return $.serializeObject(this.serializeArray());
};
+$.fn.applySerializedObject = function(obj){
+ $.applySerializedObject(this,obj);
+ return this;
+};
+
+$.fn.applySerializedArray = function(obj){
+ $.applySerializedArray(this,obj);
+ return this;
+};
}(jQuery);
View
1 tests/index.html
@@ -10,6 +10,7 @@
<!-- include dependecies here -->
<script type="text/javascript" src="lib/jquery-1.7.2.min.js"></script>
+ <script type="text/javascript" src="lib/jasmine-jquery.js"></script>
<!-- include source files here... -->
<script type="text/javascript" src="../jquery-serializeObject.js"></script>
View
325 tests/lib/jasmine-jquery.js
@@ -0,0 +1,325 @@
+var readFixtures = function() {
+ return jasmine.getFixtures().proxyCallTo_('read', arguments);
+};
+
+var preloadFixtures = function() {
+ jasmine.getFixtures().proxyCallTo_('preload', arguments);
+};
+
+var loadFixtures = function() {
+ jasmine.getFixtures().proxyCallTo_('load', arguments);
+};
+
+var addFixtures = function() {
+ jasmine.getFixtures().proxyCallTo_('add', arguments);
+};
+
+var setFixtures = function(html) {
+ jasmine.getFixtures().set(html);
+};
+
+var sandbox = function(attributes) {
+ return jasmine.getFixtures().sandbox(attributes);
+};
+
+var spyOnEvent = function(selector, eventName) {
+ jasmine.JQuery.events.spyOn(selector, eventName);
+};
+
+jasmine.getFixtures = function() {
+ return jasmine.currentFixtures_ = jasmine.currentFixtures_ || new jasmine.Fixtures();
+};
+
+jasmine.Fixtures = function() {
+ this.containerId = 'jasmine-fixtures';
+ this.fixturesCache_ = {};
+ this.fixturesPath = 'spec/javascripts/fixtures';
+};
+
+jasmine.Fixtures.prototype.set = function(html) {
+ this.cleanUp();
+ this.createContainer_(html);
+};
+
+jasmine.Fixtures.prototype.preload = function() {
+ this.read.apply(this, arguments);
+};
+
+jasmine.Fixtures.prototype.load = function() {
+ this.cleanUp();
+ this.createContainer_(this.read.apply(this, arguments));
+};
+
+jasmine.Fixtures.prototype.add = function() {
+ this.addToContainer_(this.read.apply(this, arguments));
+};
+
+jasmine.Fixtures.prototype.read = function() {
+ var htmlChunks = [];
+
+ var fixtureUrls = arguments;
+ for(var urlCount = fixtureUrls.length, urlIndex = 0; urlIndex < urlCount; urlIndex++) {
+ htmlChunks.push(this.getFixtureHtml_(fixtureUrls[urlIndex]));
+ }
+
+ return htmlChunks.join('');
+};
+
+jasmine.Fixtures.prototype.clearCache = function() {
+ this.fixturesCache_ = {};
+};
+
+jasmine.Fixtures.prototype.cleanUp = function() {
+ jQuery('#' + this.containerId).remove();
+};
+
+jasmine.Fixtures.prototype.sandbox = function(attributes) {
+ var attributesToSet = attributes || {};
+ return jQuery('<div id="sandbox" />').attr(attributesToSet);
+};
+
+jasmine.Fixtures.prototype.createContainer_ = function(html) {
+ var container;
+ if(html instanceof jQuery) {
+ container = jQuery('<div id="' + this.containerId + '" />');
+ container.html(html);
+ } else {
+ container = '<div id="' + this.containerId + '">' + html + '</div>'
+ }
+ jQuery('body').append(container);
+};
+
+jasmine.Fixtures.prototype.addToContainer_ = function(html){
+ var container = jQuery('body').find('#'+this.containerId).append(html);
+ if(!container.length){
+ this.createContainer_(html);
+ }
+}
+
+jasmine.Fixtures.prototype.getFixtureHtml_ = function(url) {
+ if (typeof this.fixturesCache_[url] == 'undefined') {
+ this.loadFixtureIntoCache_(url);
+ }
+ return this.fixturesCache_[url];
+};
+
+jasmine.Fixtures.prototype.loadFixtureIntoCache_ = function(relativeUrl) {
+ var url = this.makeFixtureUrl_(relativeUrl);
+ var request = new XMLHttpRequest();
+ request.open("GET", url + "?" + new Date().getTime(), false);
+ request.send(null);
+ this.fixturesCache_[relativeUrl] = request.responseText;
+};
+
+jasmine.Fixtures.prototype.makeFixtureUrl_ = function(relativeUrl){
+ return this.fixturesPath.match('/$') ? this.fixturesPath + relativeUrl : this.fixturesPath + '/' + relativeUrl;
+};
+
+jasmine.Fixtures.prototype.proxyCallTo_ = function(methodName, passedArguments) {
+ return this[methodName].apply(this, passedArguments);
+};
+
+
+jasmine.JQuery = function() {};
+
+jasmine.JQuery.browserTagCaseIndependentHtml = function(html) {
+ return jQuery('<div/>').append(html).html();
+};
+
+jasmine.JQuery.elementToString = function(element) {
+ return jQuery('<div />').append($(element).clone()).html();
+};
+
+jasmine.JQuery.matchersClass = {};
+
+(function(namespace) {
+ var data = {
+ spiedEvents: {},
+ handlers: []
+ };
+
+ namespace.events = {
+ spyOn: function(selector, eventName) {
+ var handler = function(e) {
+ data.spiedEvents[[selector, eventName]] = e;
+ };
+ jQuery(selector).bind(eventName, handler);
+ data.handlers.push(handler);
+ },
+
+ wasTriggered: function(selector, eventName) {
+ return !!(data.spiedEvents[[selector, eventName]]);
+ },
+
+ wasPrevented: function(selector, eventName) {
+ return data.spiedEvents[[selector, eventName]].isDefaultPrevented();
+ },
+
+ cleanUp: function() {
+ data.spiedEvents = {};
+ data.handlers = [];
+ }
+ }
+})(jasmine.JQuery);
+
+(function(){
+ var jQueryMatchers = {
+ toHaveClass: function(className) {
+ return this.actual.hasClass(className);
+ },
+
+ toBeVisible: function() {
+ return this.actual.is(':visible');
+ },
+
+ toBeHidden: function() {
+ return this.actual.is(':hidden');
+ },
+
+ toBeSelected: function() {
+ return this.actual.is(':selected');
+ },
+
+ toBeChecked: function() {
+ return this.actual.is(':checked');
+ },
+
+ toBeEmpty: function() {
+ return this.actual.is(':empty');
+ },
+
+ toExist: function() {
+ return this.actual.length;
+ },
+
+ toHaveAttr: function(attributeName, expectedAttributeValue) {
+ return hasProperty(this.actual.attr(attributeName), expectedAttributeValue);
+ },
+
+ toHaveProp: function(propertyName, expectedPropertyValue) {
+ return hasProperty(this.actual.prop(propertyName), expectedPropertyValue);
+ },
+
+ toHaveId: function(id) {
+ return this.actual.attr('id') == id;
+ },
+
+ toHaveHtml: function(html) {
+ return this.actual.html() == jasmine.JQuery.browserTagCaseIndependentHtml(html);
+ },
+
+ toHaveText: function(text) {
+ var trimmedText = $.trim(this.actual.text());
+ if (text && jQuery.isFunction(text.test)) {
+ return text.test(trimmedText);
+ } else {
+ return trimmedText == text;
+ }
+ },
+
+ toHaveValue: function(value) {
+ return this.actual.val() == value;
+ },
+
+ toHaveData: function(key, expectedValue) {
+ return hasProperty(this.actual.data(key), expectedValue);
+ },
+
+ toBe: function(selector) {
+ return this.actual.is(selector);
+ },
+
+ toContain: function(selector) {
+ return this.actual.find(selector).length;
+ },
+
+ toBeDisabled: function(selector){
+ return this.actual.is(':disabled');
+ },
+
+ toBeFocused: function(selector) {
+ return this.actual.is(':focus');
+ },
+
+ // tests the existence of a specific event binding
+ toHandle: function(eventName) {
+ var events = this.actual.data("events");
+ return events && events[eventName].length > 0;
+ },
+
+ // tests the existence of a specific event binding + handler
+ toHandleWith: function(eventName, eventHandler) {
+ var stack = this.actual.data("events")[eventName];
+ var i;
+ for (i = 0; i < stack.length; i++) {
+ if (stack[i].handler == eventHandler) {
+ return true;
+ }
+ }
+ return false;
+ }
+ };
+
+ var hasProperty = function(actualValue, expectedValue) {
+ if (expectedValue === undefined) {
+ return actualValue !== undefined;
+ }
+ return actualValue == expectedValue;
+ };
+
+ var bindMatcher = function(methodName) {
+ var builtInMatcher = jasmine.Matchers.prototype[methodName];
+
+ jasmine.JQuery.matchersClass[methodName] = function() {
+ if (this.actual
+ && (this.actual instanceof jQuery
+ || jasmine.isDomNode(this.actual))) {
+ this.actual = $(this.actual);
+ var result = jQueryMatchers[methodName].apply(this, arguments);
+ this.actual = jasmine.JQuery.elementToString(this.actual);
+ return result;
+ }
+
+ if (builtInMatcher) {
+ return builtInMatcher.apply(this, arguments);
+ }
+
+ return false;
+ };
+ };
+
+ for(var methodName in jQueryMatchers) {
+ bindMatcher(methodName);
+ }
+})();
+
+beforeEach(function() {
+ this.addMatchers(jasmine.JQuery.matchersClass);
+ this.addMatchers({
+ toHaveBeenTriggeredOn: function(selector) {
+ this.message = function() {
+ return [
+ "Expected event " + this.actual + " to have been triggered on " + selector,
+ "Expected event " + this.actual + " not to have been triggered on " + selector
+ ];
+ };
+ return jasmine.JQuery.events.wasTriggered($(selector), this.actual);
+ }
+ });
+ this.addMatchers({
+ toHaveBeenPreventedOn: function(selector) {
+ this.message = function() {
+ return [
+ "Expected event " + this.actual + " to have been prevented on " + selector,
+ "Expected event " + this.actual + " not to have been prevented on " + selector
+ ];
+ };
+ return jasmine.JQuery.events.wasPrevented(selector, this.actual);
+ }
+ });
+});
+
+afterEach(function() {
+ jasmine.getFixtures().cleanUp();
+ jasmine.JQuery.events.cleanUp();
+});
View
56 tests/specs/jquery-serializeObject_spec.js
@@ -145,3 +145,59 @@ describe("jQuery.deserializeObject",function(){
});
});
+describe("jQuery.applySerializedObject", function(){
+ var $ = jQuery;
+ describe("with a simple form", function(){
+ beforeEach(function(){
+ setFixtures('<form id="form-fixture""><input name="banana_stand" /><textarea name="bluth_co"></textarea></form>')
+ });
+ it("should put values in form",function(){
+ $.applySerializedObject($('#form-fixture'),{banana_stand:"money",bluth_co:"chicken dance"})
+ expect($('#form-fixture').find('[name=banana_stand]').val()).toBe("money");
+ expect($('#form-fixture').find('[name=bluth_co]').val()).toBe("chicken dance");
+ });
+ });
+
+ describe("a form with nested attributes", function(){
+ beforeEach(function(){
+ setFixtures('<form id="form-fixture""><input name="banana_stand[]" /><textarea name="bluth_co[p]"></textarea></form>')
+ });
+ it("should put values in form",function(){
+ $.applySerializedObject($('#form-fixture'),{banana_stand:["money"],bluth_co:{p:"chicken dance"}})
+ expect($('#form-fixture').find("[name='banana_stand[]']").val()).toBe("money");
+ expect($('#form-fixture').find("[name='bluth_co[p]']").val()).toBe("chicken dance");
+ });
+ });
+
+ describe("with a form with a checkbox",function(){
+ beforeEach(function(){
+ setFixtures('<form id="form-fixture""><input type="checkbox" checked="checked" name="banana_stand" /><input type="checkbox" name="bluth_co" value="chicken dance" /></form>')
+ });
+
+ it("should check a checkbox",function(){
+ $.applySerializedObject($('#form-fixture'),{bluth_co:"chicken dance"})
+ expect($('#form-fixture').find('[name=bluth_co]')).toBeChecked()
+ });
+
+ it("should uncheck a checkbox", function(){
+ $.applySerializedObject($('#form-fixture'),{bluth_co:"chicken dance"})
+ expect($('#form-fixture').find('[name=banana_stand]')).not.toBeChecked();
+ });
+ });
+
+ describe("with a form with a radio",function(){
+ beforeEach(function(){
+ setFixtures('<form id="form-fixture""><input type="radio" checked="checked" name="bluth_co" value="corn baller" /><input type="radio" name="bluth_co" value="chicken dance" /></form>')
+ });
+
+ it("should check a radio",function(){
+ $.applySerializedObject($('#form-fixture'),{bluth_co:"chicken dance"})
+ expect($('#form-fixture').find('[value="chicken dance"]')).toBeChecked()
+ });
+
+ it("should uncheck a radio", function(){
+ $.applySerializedObject($('#form-fixture'),{bluth_co:"chicken dance"})
+ expect($('#form-fixture').find('[value="corn baller"]')).not.toBeChecked();
+ });
+ });
+});

0 comments on commit ddbf89e

Please sign in to comment.