Skip to content

Commit

Permalink
Merge pull request #1055 from ckeditor/t/1053
Browse files Browse the repository at this point in the history
Introduce CKEDITOR.tools.object.merge  - #1053
  • Loading branch information
f1ames authored Oct 17, 2017
2 parents 6102c2b + 27ab4a9 commit 19e23a4
Show file tree
Hide file tree
Showing 5 changed files with 150 additions and 28 deletions.
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ New Features:
* [#607](https://github.com/ckeditor/ckeditor-dev/issues/607): Manually inserted hex color is prefixed with hash tag if needed. It ensures a valid hex color is used when setting table cell border or background color via [Color Dialog](http://ckeditor.com/addon/colordialog) window.
* [#584](https://github.com/ckeditor/ckeditor-dev/issues/584): [Font size and Family](http://ckeditor.com/addon/font) and [Format](http://ckeditor.com/addon/format) drop-downs are not toggleable anymore. Default option to reset styles added.
* [#856](https://github.com/ckeditor/ckeditor-dev/issues/856): Introduced [`CKEDITOR.tools.keystrokeToArray`](https://docs.ckeditor.com/ckeditor-docs/build/#!/api/CKEDITOR.tools-method-keystrokeToArray). It converts given keystroke into its string representation, returning every key name as separate array element.
* [#1053](https://github.com/ckeditor/ckeditor-dev/issues/1053): Introduced [`CKEDITOR.tools.object.merge`](https://docs.ckeditor.com/ckeditor4/docs/#!/api/CKEDITOR.tools.object-method-merge). It allows to merge two objects, returning the new object with all properties from both objects deeply cloned.

Fixed Issues:

Expand Down
53 changes: 53 additions & 0 deletions core/tools.js
Original file line number Diff line number Diff line change
Expand Up @@ -1991,6 +1991,59 @@
}

return null;
},

/**
* Merges two objects and returns new one.
*
* var obj1 = {
* a: 1,
* conflicted: 10,
* obj: {
* c: 1
* }
* },
* obj2 = {
* b: 2,
* conflicted: 20,
* obj: {
* d: 2
* }
* };
*
* CKEDITOR.tools.object.merge( obj1, obj2 );
*
* This code produces the following object;
*
* {
* a: 1,
* b: 2,
* conflicted: 20,
* obj: {
* c: 1,
* d: 2
* }
* }
*
* @param {Object} obj1 Source object, which will be used to create a new base object.
* @param {Object} obj2 An object, which properties will be merged to the base one.
* @returns {Object} Merged object.
* @member CKEDITOR.tools.object
*/
merge: function( obj1, obj2 ) {
var tools = CKEDITOR.tools,
copy1 = tools.clone( obj1 ),
copy2 = tools.clone( obj2 );

tools.array.forEach( tools.objectKeys( copy2 ), function( key ) {
if ( typeof copy2[ key ] === 'object' && typeof copy1[ key ] === 'object' ) {
copy1[ key ] = tools.object.merge( copy1[ key ], copy2[ key ] );
} else {
copy1[ key ] = copy2[ key ];
}
} );

return copy1;
}
}
};
Expand Down
34 changes: 34 additions & 0 deletions tests/_benderjs/ckeditor/static/extensions.js
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,40 @@
assert.areSame( expected, bender.tools.compatHtml( actual, false, true, false, true, true ), message );
};

/**
* Asserts that two objects are deep equal.
*
* @param {Object} expected
* @param {Object} actual
* @param {String} [message]
*/
bender.objectAssert.areDeepEqual = function( expected, actual, message ) {
// Based on http://yuilibrary.com/yui/docs/api/files/test_js_ObjectAssert.js.html#l12.
var expectedKeys = YUITest.Object.keys( expected ),
actualKeys = YUITest.Object.keys( actual );

YUITest.Assert._increment();

// First check keys array length.
if ( expectedKeys.length != actualKeys.length ) {
YUITest.Assert.fail( YUITest.Assert._formatMessage( message,
'Object should have ' + expectedKeys.length + ' keys but has ' + actualKeys.length ) );
}

// Then check values.
for ( var name in expected ) {
if ( expected.hasOwnProperty( name ) ) {
if ( expected[ name ] && typeof expected[ name ] === 'object' ) {
bender.objectAssert.areDeepEqual( expected[ name ], actual[ name ] );
}
else if ( expected[ name ] !== actual[ name ] ) {
throw new YUITest.ComparisonFailure( YUITest.Assert._formatMessage( message,
'Values should be equal for property ' + name ), expected[ name ], actual[ name ] );
}
}
}
};

// Add support test ignore.
YUITest.Ignore = function() {};

Expand Down
62 changes: 62 additions & 0 deletions tests/core/tools/object.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,68 @@

returned = this.object.findKey( inputObject, innerObject );
assert.areSame( returned, 'c' );
},

// (#1053)
'test object.merge': function() {
var obj1 = {
one: 1,
conflicted: 10,
falsy: false,
nully: null,
obj: {
nested1: 1,
nestedObj: {
a: 3
}
},
array: [ 1, 2 ]
},
obj2 = {
two: 2,
conflicted: 20,
truthy: true,
undef: undefined,
obj: {
nested2: 2,
nestedObj: {
b: 4
}
},
array: [ 3, 4 ]
},
expected = {
one: 1,
two: 2,
conflicted: 20,
falsy: false,
truthy: true,
nully: null,
undef: undefined,
obj: {
nested1: 1,
nested2: 2,
nestedObj: {
a: 3,
b: 4
}
},
array: [ 3, 4 ]
},
actual = this.object.merge( obj1, obj2 );

assert.areNotSame( obj1, actual, 'Merging does not modify obj1' );
assert.areNotSame( obj2, actual, 'Merging does not modify obj2' );
objectAssert.areDeepEqual( expected, actual, 'Merging produces correct object' );

// Reversed merge should produce same object, but with different conflicted and array properties.
expected.conflicted = 10;
expected.array = [ 1, 2 ];
actual = this.object.merge( obj2, obj1 );

assert.areNotSame( obj1, actual, 'Merging does not modify obj1' );
assert.areNotSame( obj2, actual, 'Merging does not modify obj2' );
objectAssert.areDeepEqual( expected, actual, 'Merging produces correct object' );
}
} );
} )();
28 changes: 0 additions & 28 deletions tests/plugins/copyformatting/_helpers/tools.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,6 @@

'use strict';

// Based on http://yuilibrary.com/yui/docs/api/files/test_js_ObjectAssert.js.html#l12.
YUITest.ObjectAssert.areDeepEqual = function( expected, actual, message ) {
var expectedKeys = YUITest.Object.keys( expected ),
actualKeys = YUITest.Object.keys( actual ),
areEqual = YUITest.ObjectAssert.areEqual;

YUITest.Assert._increment();

// First check keys array length.
if ( expectedKeys.length != actualKeys.length ) {
YUITest.Assert.fail( YUITest.Assert._formatMessage( message,
'Object should have ' + expectedKeys.length + ' keys but has ' + actualKeys.length ) );
}

// Then check values.
for ( var name in expected ) {
if ( expected.hasOwnProperty( name ) ) {
if ( typeof expected[ name ] === 'object' ) {
areEqual( expected[ name ], actual[ name ] );
}
else if ( expected[ name ] !== actual[ name ] ) {
throw new YUITest.ComparisonFailure( YUITest.Assert._formatMessage( message,
'Values should be equal for property ' + name ), expected[ name ], actual[ name ] );
}
}
}
};

// Safari and IE8 use text selection and all other browsers use element selection. Therefore we must normalize it.
function fixHtml( html ) {
if ( ( CKEDITOR.env.webkit && !CKEDITOR.env.chrome ) || ( CKEDITOR.env.ie && CKEDITOR.env.version === 8 ) ) {
Expand Down

0 comments on commit 19e23a4

Please sign in to comment.