Browse Source

Improved clone() - only clone data, no objects.

Martin Edenhofer 10 years ago
parent
commit
644cd811e7

+ 5 - 0
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]

+ 18 - 3
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) ->
 

+ 43 - 4
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;
 }
 

+ 17 - 0
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

+ 2 - 2
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')

+ 59 - 0
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' );
+
+
 });
 
 }