diff --git a/src/ng/compile.js b/src/ng/compile.js index 561bb13fef16..4ec3ea5d6d94 100644 --- a/src/ng/compile.js +++ b/src/ng/compile.js @@ -3647,7 +3647,9 @@ var SPECIAL_CHARS_REGEXP = /[:\-_]+(.)/g; function directiveNormalize(name) { return name .replace(PREFIX_REGEXP, '') - .replace(SPECIAL_CHARS_REGEXP, fnCamelCaseReplace); + .replace(SPECIAL_CHARS_REGEXP, function(_, letter, offset) { + return offset ? letter.toUpperCase() : letter; + }); } /** diff --git a/src/ng/directive/input.js b/src/ng/directive/input.js index f87e755b8c8d..ebae9b3bed18 100644 --- a/src/ng/directive/input.js +++ b/src/ng/directive/input.js @@ -1604,8 +1604,8 @@ function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) { var maxVal; if (isDefined(attr.min) || attr.ngMin) { - ctrl.$validators.min = function(value) { - return ctrl.$isEmpty(value) || isUndefined(minVal) || value >= minVal; + ctrl.$validators.min = function(modelValue, viewValue) { + return ctrl.$isEmpty(viewValue) || isUndefined(minVal) || viewValue >= minVal; }; attr.$observe('min', function(val) { @@ -1616,8 +1616,8 @@ function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) { } if (isDefined(attr.max) || attr.ngMax) { - ctrl.$validators.max = function(value) { - return ctrl.$isEmpty(value) || isUndefined(maxVal) || value <= maxVal; + ctrl.$validators.max = function(modelValue, viewValue) { + return ctrl.$isEmpty(viewValue) || isUndefined(maxVal) || viewValue <= maxVal; }; attr.$observe('max', function(val) { diff --git a/src/ngSanitize/filter/linky.js b/src/ngSanitize/filter/linky.js index 34881c847729..564799d59e4b 100644 --- a/src/ngSanitize/filter/linky.js +++ b/src/ngSanitize/filter/linky.js @@ -12,7 +12,7 @@ * Requires the {@link ngSanitize `ngSanitize`} module to be installed. * * @param {string} text Input text. - * @param {string} target Window (`_blank|_self|_parent|_top`) or named frame to open links in. + * @param {string} [target] Window (`_blank|_self|_parent|_top`) or named frame to open links in. * @param {object|function(url)} [attributes] Add custom attributes to the link element. * * Can be one of: diff --git a/test/ng/compileSpec.js b/test/ng/compileSpec.js index 2890a76ac0c0..ca2d43380e8f 100644 --- a/test/ng/compileSpec.js +++ b/test/ng/compileSpec.js @@ -294,6 +294,27 @@ describe('$compile', function() { inject(function($compile) {}); }); + it('should ignore special chars before processing attribute directive name', function() { + // a regression https://github.com/angular/angular.js/issues/16278 + module(function() { + directive('t', function(log) { + return { + restrict: 'A', + link: { + pre: log.fn('pre'), + post: log.fn('post') + } + }; + }); + }); + inject(function($compile, $rootScope, log) { + $compile('
')($rootScope); + $compile('')($rootScope); + $compile('')($rootScope); + expect(log).toEqual('pre; post; pre; post; pre; post'); + }); + }); + it('should throw an exception if the directive factory is not defined', function() { module(function() { expect(function() { diff --git a/test/ng/directive/inputSpec.js b/test/ng/directive/inputSpec.js index 260e11d1d4b7..d1a552194c4e 100644 --- a/test/ng/directive/inputSpec.js +++ b/test/ng/directive/inputSpec.js @@ -2284,6 +2284,15 @@ describe('input', function() { describe('number', function() { + // Helpers for min / max tests + var subtract = function(value) { + return value - 5; + }; + + var add = function(value) { + return value + 5; + }; + it('should reset the model if view is invalid', function() { var inputElm = helper.compileInput(''); @@ -2465,6 +2474,29 @@ describe('input', function() { expect($rootScope.form.alias.$error.min).toBeFalsy(); }); + + it('should validate against the viewValue', function() { + var inputElm = helper.compileInput( + ''); + + var ngModelCtrl = inputElm.controller('ngModel'); + ngModelCtrl.$parsers.push(subtract); + + helper.changeInputValueTo('10'); + expect(inputElm).toBeValid(); + expect($rootScope.value).toBe(5); + expect($rootScope.form.alias.$error.min).toBeFalsy(); + + ngModelCtrl.$parsers.pop(); + ngModelCtrl.$parsers.push(add); + + helper.changeInputValueTo('5'); + expect(inputElm).toBeInvalid(); + expect($rootScope.form.alias.$error.min).toBeTruthy(); + expect($rootScope.value).toBe(10); + }); + + it('should validate even if min value changes on-the-fly', function() { $rootScope.min = undefined; var inputElm = helper.compileInput(''); @@ -2511,6 +2543,28 @@ describe('input', function() { expect($rootScope.form.alias.$error.min).toBeFalsy(); }); + + it('should validate against the viewValue', function() { + var inputElm = helper.compileInput( + ''); + var ngModelCtrl = inputElm.controller('ngModel'); + ngModelCtrl.$parsers.push(subtract); + + helper.changeInputValueTo('10'); + expect(inputElm).toBeValid(); + expect($rootScope.value).toBe(5); + expect($rootScope.form.alias.$error.min).toBeFalsy(); + + ngModelCtrl.$parsers.pop(); + ngModelCtrl.$parsers.push(add); + + helper.changeInputValueTo('5'); + expect(inputElm).toBeInvalid(); + expect($rootScope.form.alias.$error.min).toBeTruthy(); + expect($rootScope.value).toBe(10); + }); + + it('should validate even if the ngMin value changes on-the-fly', function() { $rootScope.min = undefined; var inputElm = helper.compileInput(''); @@ -2558,6 +2612,28 @@ describe('input', function() { expect($rootScope.form.alias.$error.max).toBeFalsy(); }); + + it('should validate against the viewValue', function() { + var inputElm = helper.compileInput(''); + var ngModelCtrl = inputElm.controller('ngModel'); + ngModelCtrl.$parsers.push(add); + + helper.changeInputValueTo('10'); + expect(inputElm).toBeValid(); + expect($rootScope.value).toBe(15); + expect($rootScope.form.alias.$error.max).toBeFalsy(); + + ngModelCtrl.$parsers.pop(); + ngModelCtrl.$parsers.push(subtract); + + helper.changeInputValueTo('15'); + expect(inputElm).toBeInvalid(); + expect($rootScope.form.alias.$error.max).toBeTruthy(); + expect($rootScope.value).toBe(10); + }); + + it('should validate even if max value changes on-the-fly', function() { $rootScope.max = undefined; var inputElm = helper.compileInput(''); @@ -2604,6 +2680,28 @@ describe('input', function() { expect($rootScope.form.alias.$error.max).toBeFalsy(); }); + + it('should validate against the viewValue', function() { + var inputElm = helper.compileInput(''); + var ngModelCtrl = inputElm.controller('ngModel'); + ngModelCtrl.$parsers.push(add); + + helper.changeInputValueTo('10'); + expect(inputElm).toBeValid(); + expect($rootScope.value).toBe(15); + expect($rootScope.form.alias.$error.max).toBeFalsy(); + + ngModelCtrl.$parsers.pop(); + ngModelCtrl.$parsers.push(subtract); + + helper.changeInputValueTo('15'); + expect(inputElm).toBeInvalid(); + expect($rootScope.form.alias.$error.max).toBeTruthy(); + expect($rootScope.value).toBe(10); + }); + + it('should validate even if the ngMax value changes on-the-fly', function() { $rootScope.max = undefined; var inputElm = helper.compileInput('');