diff options
| author | Ben Ripkens | 2013-05-20 19:10:04 +0200 |
|---|---|---|
| committer | Igor Minar | 2013-07-13 22:22:28 -0700 |
| commit | 724819e3cfd8aeda1f724fb527db2b57494be9b7 (patch) | |
| tree | 50a64772698458b7c7ecc29f48b85d6f164980f7 | |
| parent | 32f8a04c8f3eb480b3f405ac6b1324c96025b2fc (diff) | |
| download | angular.js-724819e3cfd8aeda1f724fb527db2b57494be9b7.tar.bz2 | |
fix(angular.equals): add support for regular expressions
Regular expression objects didn't used to be considered to be equal when using
'angular.equals'. Dirty checking therefore failed to recognize a
property modification.
Closes #2685
| -rw-r--r-- | src/Angular.js | 25 | ||||
| -rw-r--r-- | test/AngularSpec.js | 28 |
2 files changed, 49 insertions, 4 deletions
diff --git a/src/Angular.js b/src/Angular.js index 746f1134..02dadf8d 100644 --- a/src/Angular.js +++ b/src/Angular.js @@ -414,6 +414,18 @@ function isFunction(value){return typeof value == 'function';} /** + * Determines if a value is a regular expression object. + * + * @private + * @param {*} value Reference to check. + * @returns {boolean} True if `value` is a `RegExp`. + */ +function isRegExp(value) { + return toString.apply(value) == '[object RegExp]'; +} + + +/** * Checks if `obj` is a window object. * * @private @@ -646,7 +658,7 @@ function shallowCopy(src, dst) { * @function * * @description - * Determines if two objects or two values are equivalent. Supports value types, arrays and + * Determines if two objects or two values are equivalent. Supports value types, regular expressions, arrays and * objects. * * Two objects or values are considered equivalent if at least one of the following is true: @@ -654,6 +666,9 @@ function shallowCopy(src, dst) { * * Both objects or values pass `===` comparison. * * Both objects or values are of the same type and all of their properties pass `===` comparison. * * Both values are NaN. (In JavasScript, NaN == NaN => false. But we consider two NaN as equal) + * * Both values represent the same regular expression (In JavasScript, + * /abc/ == /abc/ => false. But we consider two regular expressions as equal when their textual + * representation matches). * * During a property comparison, properties of `function` type and properties with names * that begin with `$` are ignored. @@ -680,6 +695,8 @@ function equals(o1, o2) { } } else if (isDate(o1)) { return isDate(o2) && o1.getTime() == o2.getTime(); + } else if (isRegExp(o1) && isRegExp(o2)) { + return o1.toString() == o2.toString(); } else { if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2)) return false; keySet = {}; @@ -949,9 +966,9 @@ function encodeUriQuery(val, pctEncodeSpaces) { * one ngApp directive can be used per HTML document. The directive * designates the root of the application and is typically placed * at the root of the page. - * - * The first ngApp found in the document will be auto-bootstrapped. To use multiple applications in an - * HTML document you must manually bootstrap them using {@link angular.bootstrap}. + * + * The first ngApp found in the document will be auto-bootstrapped. To use multiple applications in an + * HTML document you must manually bootstrap them using {@link angular.bootstrap}. * Applications cannot be nested. * * In the example below if the `ngApp` directive would not be placed diff --git a/test/AngularSpec.js b/test/AngularSpec.js index da70aef7..151aac0a 100644 --- a/test/AngularSpec.js +++ b/test/AngularSpec.js @@ -278,6 +278,17 @@ describe('angular', function() { expect(equals({}, {hasOwnProperty: 1})).toBe(false); expect(equals({}, {toString: null})).toBe(false); }); + + it('should compare regular expressions', function() { + expect(equals(/abc/, /abc/)).toBe(true); + expect(equals(/abc/i, new RegExp('abc', 'i'))).toBe(true); + expect(equals(new RegExp('abc', 'i'), new RegExp('abc', 'i'))).toBe(true); + expect(equals(new RegExp('abc', 'i'), new RegExp('abc'))).toBe(false); + expect(equals(/abc/i, /abc/)).toBe(false); + expect(equals(/abc/, /def/)).toBe(false); + expect(equals(/^abc/, /abc/)).toBe(false); + expect(equals(/^abc/, '/^abc/')).toBe(false); + }); }); describe('size', function() { @@ -654,6 +665,23 @@ describe('angular', function() { }); }); + + describe('isRegExp', function() { + it('should return true for RegExp object', function() { + expect(isRegExp(/^foobar$/)).toBe(true); + expect(isRegExp(new RegExp('^foobar$/'))).toBe(true); + }); + + it('should return false for non RegExp objects', function() { + expect(isRegExp([])).toBe(false); + expect(isRegExp('')).toBe(false); + expect(isRegExp(23)).toBe(false); + expect(isRegExp({})).toBe(false); + expect(isRegExp(new Date())).toBe(false); + }); + }); + + describe('compile', function() { it('should link to existing node and create scope', inject(function($rootScope, $compile) { var template = angular.element('<div>{{greeting = "hello world"}}</div>'); |
