diff --git a/src/lib/core/util/object-extend.spec.ts b/src/lib/core/util/object-extend.spec.ts new file mode 100644 index 000000000000..1cb0b329b08b --- /dev/null +++ b/src/lib/core/util/object-extend.spec.ts @@ -0,0 +1,50 @@ +import {extendObject} from './object-extend'; + + +describe('extendObject', () => { + it('should extend an object', () => { + let extended = extendObject({}, {x: 123}); + + expect(extended).toEqual({x: 123}); + }); + + it('should overwrite existing properties', () => { + let extended = extendObject({x: 456}, {x: 123}); + + expect(extended).toEqual({x: 123}); + }); + + it('should add additional properties', () => { + let extended = extendObject({x: 456}, {y: 123}); + + expect(extended).toEqual({x: 456, y: 123}); + }); + + it('should extend from multiple sources', () => { + let extended = extendObject({}, {x: 123}, {y: 456}); + + expect(extended).toEqual({x: 123, y: 456}); + }); + + it('should overwrite properties from the later source', () => { + let extended = extendObject({}, {x: 123}, {x: 456}); + + expect(extended).toEqual({x: 456}); + }); + + it('should treat null and undefined sources as empty objects', () => { + let extended = extendObject({}, null, {x: 123}, undefined, {y: 456}); + + expect(extended).toEqual({x: 123, y: 456}); + }); + + it('should throw an error when the dest object is null', () => { + expect(() => extendObject(null, {x: 123})) + .toThrowError('Cannot convert undefined or null to object'); + }); + + it('should throw an error when the dest object is undefined', () => { + expect(() => extendObject(undefined, {x: 123})) + .toThrowError('Cannot convert undefined or null to object'); + }); +}); diff --git a/src/lib/core/util/object-extend.ts b/src/lib/core/util/object-extend.ts new file mode 100644 index 000000000000..168b8d84abc7 --- /dev/null +++ b/src/lib/core/util/object-extend.ts @@ -0,0 +1,24 @@ +/** + * Extends an object with the *enumerable* and *own* properties of one or more source objects, + * similar to Object.assign. + * + * @param dest The object which will have properties copied to it. + * @param sources The source objects from which properties will be copied. + */ +export function extendObject(dest: any, ...sources: any[]): any { + if (dest == null) { + throw TypeError('Cannot convert undefined or null to object'); + } + + for (let source of sources) { + if (source != null) { + for (let key in source) { + if (source.hasOwnProperty(key)) { + dest[key] = source[key]; + } + } + } + } + + return dest; +} diff --git a/src/lib/dialog/dialog.ts b/src/lib/dialog/dialog.ts index 8a4194f20f20..a71b260e021d 100644 --- a/src/lib/dialog/dialog.ts +++ b/src/lib/dialog/dialog.ts @@ -14,6 +14,7 @@ import {MdDialogRef} from './dialog-ref'; import {DialogInjector} from './dialog-injector'; import {MdDialogContainer} from './dialog-container'; import {A11yModule, InteractivityChecker} from '../core'; +import {extendObject} from '../core/util/object-extend'; export {MdDialogConfig} from './dialog-config'; export {MdDialogRef} from './dialog-ref'; @@ -41,7 +42,7 @@ export class MdDialog { * @param config */ open(component: ComponentType, config?: MdDialogConfig): MdDialogRef { - config = this._applyConfigDefaults(config); + config = _applyConfigDefaults(config); let overlayRef = this._createOverlay(config); let dialogContainer = this._attachDialogContainer(overlayRef, config); @@ -127,15 +128,15 @@ export class MdDialog { return state; } +} - /** - * Applies default options to the dialog config. - * @param dialogConfig Config to be modified. - * @returns The new configuration object. - */ - private _applyConfigDefaults(dialogConfig: MdDialogConfig): MdDialogConfig { - return Object.assign(new MdDialogConfig(), dialogConfig); - } +/** + * Applies default options to the dialog config. + * @param dialogConfig Config to be modified. + * @returns The new configuration object. + */ +function _applyConfigDefaults(dialogConfig: MdDialogConfig): MdDialogConfig { + return extendObject(new MdDialogConfig(), dialogConfig); } diff --git a/src/lib/snack-bar/snack-bar.ts b/src/lib/snack-bar/snack-bar.ts index 03e26fd6b03b..8ba710d8665c 100644 --- a/src/lib/snack-bar/snack-bar.ts +++ b/src/lib/snack-bar/snack-bar.ts @@ -20,6 +20,7 @@ import {MdSnackBarConfig} from './snack-bar-config'; import {MdSnackBarRef} from './snack-bar-ref'; import {MdSnackBarContainer} from './snack-bar-container'; import {SimpleSnackBar} from './simple-snack-bar'; +import {extendObject} from '../core/util/object-extend'; // TODO(josephperrott): Automate dismiss after timeout. @@ -124,7 +125,7 @@ export class MdSnackBar { * @returns The new configuration object with defaults applied. */ function _applyConfigDefaults(config: MdSnackBarConfig): MdSnackBarConfig { - return Object.assign(new MdSnackBarConfig(), config); + return extendObject(new MdSnackBarConfig(), config); }