From 644cd811e76316e629ffba91c241f111d0e58bc0 Mon Sep 17 00:00:00 2001 From: Martin Edenhofer Date: Thu, 29 Jan 2015 14:19:11 +0100 Subject: [PATCH] Improved clone() - only clone data, no objects. --- .../_application_controller_form.js.coffee | 5 ++ .../app/lib/app_post/utils.js.coffee | 21 ++++++- app/assets/javascripts/application.js | 47 +++++++++++++-- public/assets/tests/core.js | 17 ++++++ public/assets/tests/form-validation.js | 4 +- public/assets/tests/html-utils.js | 59 +++++++++++++++++++ 6 files changed, 144 insertions(+), 9 deletions(-) diff --git a/app/assets/javascripts/app/controllers/_application_controller_form.js.coffee b/app/assets/javascripts/app/controllers/_application_controller_form.js.coffee index 0d086fea8..46b6c1a4e 100644 --- a/app/assets/javascripts/app/controllers/_application_controller_form.js.coffee +++ b/app/assets/javascripts/app/controllers/_application_controller_form.js.coffee @@ -1998,6 +1998,11 @@ class App.ControllerForm extends App.Controller el.find('[data-name="' + key + '"]').closest('.form-group').removeClass('hide') el.find('[data-name="' + key + '"]').removeClass('is-hidden') + # hide old validation states + if el + el.find('.has-error').removeClass('has-error') + el.find('.help-inline').html('') + _hide: (name, el = @el) -> if !_.isArray(name) name = [name] diff --git a/app/assets/javascripts/app/lib/app_post/utils.js.coffee b/app/assets/javascripts/app/lib/app_post/utils.js.coffee index 4a5b37e07..e1820deea 100644 --- a/app/assets/javascripts/app/lib/app_post/utils.js.coffee +++ b/app/assets/javascripts/app/lib/app_post/utils.js.coffee @@ -220,21 +220,36 @@ class App.Utils changes @_formDiffNormalizer: (data) -> + return undefined if data is undefined + return if !@_formDiffNormalizerCheckConstructor( data ) + if _.isArray( data ) for i in [0...data.length] - data[i] = @_formDiffNormalizer( data[i] ) + if @_formDiffNormalizerCheckConstructor( data[i] ) + data[i] = @_formDiffNormalizer( data[i] ) + else + data[i] = undefined else if _.isObject( data ) for key, value of data - if _.isArray( data[key] ) @_formDiffNormalizer( data[key] ) else if _.isObject( data[key] ) @_formDiffNormalizer( data[key] ) - else + else if @_formDiffNormalizerCheckConstructor( data[key] ) data[key] = @_formDiffNormalizerItem( key, data[key] ) else @_formDiffNormalizerItem( '', data ) + @_formDiffNormalizerCheckConstructor: (data) -> + return true if !data + return true if !data.constructor + name = data.constructor.name + return true if !name + return true if name is 'Object' + return true if name is 'Array' + return true if name is 'String' + return true if name is 'Number' + false @_formDiffNormalizerItem: (key, value) -> diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index df73bc31a..55002f83d 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -73,11 +73,49 @@ function difference(object1, object2) { return changes; } -// taken from http://stackoverflow.com/questions/4459928/how-to-deep-clone-in-javascript +// clone, just data, no instances of objects function clone(item) { + if (!item) { return item; } + + // ignore certain objects + var acceptedInstances = [ 'Object', 'Number', 'String', 'Boolean', 'Array' ]; + if (item && item.constructor) { + if (!_.contains(acceptedInstances, item.constructor.name)) { + return; + } + } + + var result; + // copy array + if ( _.isArray(item) ) { + result = []; + item.forEach(function(child, index, array) { + result[index] = clone( child ); + }); + } + + // copy object + else if ( _.isObject(item) ) { + result = {}; + for(var key in item) { + if (item.hasOwnProperty(key)) { + result[key] = clone(item[key]) + } + } + } + + // copy others + else { + result = item; + } + return result; +} + +// taken from http://stackoverflow.com/questions/4459928/how-to-deep-clone-in-javascript +function clone2(item) { if (!item) { return item; } // null, undefined values check - var types = [ Number, String, Boolean ], + var types = [ Number, String, Boolean ], result; // normalizing primitives if someone did new String('aaa'), or new Number('444'); @@ -90,13 +128,13 @@ function clone(item) { if (typeof result == "undefined") { if (Object.prototype.toString.call( item ) === "[object Array]") { result = []; - item.forEach(function(child, index, array) { + item.forEach(function(child, index, array) { result[index] = clone( child ); }); } else if (typeof item == "object") { // testing that this is DOM if (item.nodeType && typeof item.cloneNode == "function") { - var result = item.cloneNode( true ); + var result = item.cloneNode( true ); } else if (!item.prototype) { // check that this is a literal if (item instanceof Date) { result = new Date(item); @@ -121,6 +159,7 @@ function clone(item) { result = item; } } + return result; } diff --git a/public/assets/tests/core.js b/public/assets/tests/core.js index 505899f9b..bca6ec2df 100644 --- a/public/assets/tests/core.js +++ b/public/assets/tests/core.js @@ -441,6 +441,7 @@ test( "clone", function() { key2: '1234' }, [1,2,4,5,6], + 'some string äöü', { key1: 123, key2: null, @@ -481,6 +482,22 @@ test( "clone", function() { deepEqual( item, test, 'clone' ); }); + // complex test + var source = [ + { name: 'some name' }, + { name: 'some name2' }, + ] + var reference = [ + { name: 'some name' }, + { name: 'some name2' }, + ] + var result = clone( source ) + + // modify source later, should not have any result + source[0].name = 'some new name' + + deepEqual( result, reference, 'clone' ); + }); // diff diff --git a/public/assets/tests/form-validation.js b/public/assets/tests/form-validation.js index ff2a95be9..cbcf3dbc3 100644 --- a/public/assets/tests/form-validation.js +++ b/public/assets/tests/form-validation.js @@ -201,8 +201,8 @@ test( "date validation check", function() { App.ControllerForm.validate( { errors: errors, form: el } ) equal( el.find('[data-name="date1"]').closest('.form-group').hasClass('has-error'), true, 'check date1 has-error') - equal( el.find('[data-name="date1"]').closest('.form-group').find('.help-inline').text(), '', 'check date1 error message') - //equal( el.find('[data-name="date1"]').closest('.form-group').find('.help-inline').text(), 'is required', 'check date1 error message') + //equal( el.find('[data-name="date1"]').closest('.form-group').find('.help-inline').text(), '', 'check date1 error message') + equal( el.find('[data-name="date1"]').closest('.form-group').find('.help-inline').text(), 'is required', 'check date1 error message') // set new values el.find('[name="{date}date1___day"]').val('1') diff --git a/public/assets/tests/html-utils.js b/public/assets/tests/html-utils.js index f6f0a225f..6879cdc64 100644 --- a/public/assets/tests/html-utils.js +++ b/public/assets/tests/html-utils.js @@ -877,6 +877,65 @@ test( "check form diff", function() { deepEqual( result, diff, 'check form diff' ); + dataNow = undefined + dataLast = undefined + + diff = {} + result = App.Utils.formDiff( dataNow, dataLast ) + deepEqual( result, diff, 'check form diff' ); + + + dataNow = {} + dataLast = {"number":"10012","title":"some subject 123äöü","group_id":1,"owner_id":1,"customer_id":2,"state_id":3,"priority_id":2,"article":{"from":"Test Master Agent","to":"","cc":"","body":"dasdad","content_type":"text/html","ticket_id":12,"type_id":9,"sender_id":1,"internal":false,"form_id":"523405147"},"updated_at":"2015-01-29T09:22:23.000Z","pending_time":"2015-01-28T22:22:00.000Z","id":12} + diff = {} + result = App.Utils.formDiff( dataNow, dataLast ) + deepEqual( result, diff, 'check form diff' ); + + // do not compare content of data instances/objects + no = function test_object() { + this.a = function() { return 123; } + this.b = function() { return '1234'; } + this.c = function() { return [123]; } + this.d = [1,2,3]; + this.e = 'abc'; + } + no1 = new no() + no2 = new no() + no3 = new no() + + dataNow = { + number:'10013', + Article: [no1], + } + dataLast = { + number: "10012", + title: "some subject 123äöü", + Article: [ no2, no3 ], + } + diff = { + number:'10013', + } + result = App.Utils.formDiff( dataNow, dataLast ) + deepEqual( result, diff, 'check form diff' ); + + + dataNow = { + number:'10013', + Article: [no1,2], + } + dataLast = { + number: "10012", + title: "some subject 123äöü", + Article: [ no2, no3 ], + } + diff = { + number:'10013', + Article: ['2'], + } + result = App.Utils.formDiff( dataNow, dataLast ) + deepEqual( result, diff, 'check form diff' ); + + }); } \ No newline at end of file