From 91b6c5f7ffaa19f967547ae3916641fed9e0f04c Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Sun, 7 Nov 2010 13:04:48 -0800 Subject: Added documentation for validators. BACKWARD INCOMPATIBLE: removed ssn validators, since it is unlikely that most people will need it and if they do, they can added it thorough RegExp --- src/filters.js | 4 +- src/scenario/dsl.js | 29 +------ src/validators.js | 217 ++++++++++++++++++++++++++++++++++++++++++++++++++-- src/widgets.js | 129 +++++++++++++++++++++++++++++++ 4 files changed, 344 insertions(+), 35 deletions(-) (limited to 'src') diff --git a/src/filters.js b/src/filters.js index 206da240..14d0dff8 100644 --- a/src/filters.js +++ b/src/filters.js @@ -343,7 +343,7 @@ snippet</p> }); it('should update', function(){ - textarea('snippet').enter('new text'); + input('snippet').enter('new text'); expect(using('#html-filter').binding('snippet | html')).toBe('new text'); expect(using('#escaped-html').binding('snippet')).toBe("new <b>text</b>"); expect(using('#html-unsafe-filter').binding("snippet | html:'unsafe'")).toBe('new text'); @@ -415,7 +415,7 @@ and one more: ftp://127.0.0.1/. }); it('should update', function(){ - textarea('snippet').enter('new http://link.'); + input('snippet').enter('new http://link.'); expect(using('#linky-filter').binding('snippet | linky')). toBe('new http://link.'); expect(using('#escaped-html').binding('snippet')).toBe('new http://link.'); diff --git a/src/scenario/dsl.js b/src/scenario/dsl.js index f37ab71d..99bc63a9 100644 --- a/src/scenario/dsl.js +++ b/src/scenario/dsl.js @@ -191,7 +191,7 @@ angular.scenario.dsl('input', function() { chain.enter = function(value) { return this.addFutureAction("input '" + this.name + "' enter '" + value + "'", function($window, $document, done) { - var input = $document.elements('input[name="$1"]', this.name); + var input = $document.elements(':input[name="$1"]', this.name); input.val(value); input.trigger('change'); done(); @@ -200,7 +200,7 @@ angular.scenario.dsl('input', function() { chain.check = function() { return this.addFutureAction("checkbox '" + this.name + "' toggle", function($window, $document, done) { - var input = $document.elements('input:checkbox[name="$1"]', this.name); + var input = $document.elements(':checkbox[name="$1"]', this.name); input.trigger('click'); done(); }); @@ -209,7 +209,7 @@ angular.scenario.dsl('input', function() { chain.select = function(value) { return this.addFutureAction("radio button '" + this.name + "' toggle '" + value + "'", function($window, $document, done) { var input = $document. - elements('input:radio[name$="@$1"][value="$2"]', this.name, value); + elements(':radio[name$="@$1"][value="$2"]', this.name, value); input.trigger('click'); done(); }); @@ -222,29 +222,6 @@ angular.scenario.dsl('input', function() { }); -/** - * Usage: - * textarea(name).enter(value) enters value in the text area with specified name - */ -angular.scenario.dsl('textarea', function() { - var chain = {}; - - chain.enter = function(value) { - return this.addFutureAction("textarea '" + this.name + "' enter '" + value + "'", function($window, $document, done) { - var textarea = $document.elements('textarea[name="$1"]', this.name); - textarea.val(value); - textarea.trigger('change'); - done(); - }); - }; - - return function(name) { - this.name = name; - return chain; - }; -}); - - /** * Usage: * repeater('#products table', 'Product List').count() number of rows diff --git a/src/validators.js b/src/validators.js index 2d8b5354..9715be59 100644 --- a/src/validators.js +++ b/src/validators.js @@ -1,6 +1,31 @@ extend(angularValidator, { 'noop': function() { return _null; }, + /** + * @ngdoc validator + * @name angular.validator.regexp + * @description + * Use regexp validator to restrict the input to any Regular Expression. + * + * @param {string} value value to validate + * @param {regexp} expression regular expression. + * @css ng-validation-error + * + * @example + * Enter valid SSN: + * + * + * @scenario + * it('should invalidate non ssn', function(){ + * var textBox = element('.example :input'); + * expect(textBox.attr('className')).not().toMatch(/ng-validation-error/); + * expect(textBox.val()).toEqual('123-45-6789'); + * + * input('ssn').enter('123-45-67890'); + * expect(textBox.attr('className')).toMatch(/ng-validation-error/); + * }); + * + */ 'regexp': function(value, regexp, msg) { if (!value.match(regexp)) { return msg || @@ -10,6 +35,43 @@ extend(angularValidator, { } }, + /** + * @ngdoc validator + * @name angular.validator.number + * @description + * Use number validator to restrict the input to numbers with an + * optional range. (See integer for whole numbers validator). + * + * @param {string} value value to validate + * @param {int=} [min=MIN_INT] minimum value. + * @param {int=} [max=MAX_INT] maximum value. + * @css ng-validation-error + * + * @example + * Enter number:
+ * Enter number greater than 10:
+ * Enter number between 100 and 200:
+ * + * @scenario + * it('should invalidate number', function(){ + * var n1 = element('.example :input[name=n1]'); + * expect(n1.attr('className')).not().toMatch(/ng-validation-error/); + * input('n1').enter('1.x'); + * expect(n1.attr('className')).toMatch(/ng-validation-error/); + * + * var n2 = element('.example :input[name=n2]'); + * expect(n2.attr('className')).not().toMatch(/ng-validation-error/); + * input('n2').enter('9'); + * expect(n2.attr('className')).toMatch(/ng-validation-error/); + * + * var n3 = element('.example :input[name=n3]'); + * expect(n3.attr('className')).not().toMatch(/ng-validation-error/); + * input('n3').enter('201'); + * expect(n3.attr('className')).toMatch(/ng-validation-error/); + * + * }); + * + */ 'number': function(value, min, max) { var num = 1 * value; if (num == value) { @@ -25,6 +87,42 @@ extend(angularValidator, { } }, + /** + * @ngdoc validator + * @name angular.validator.integer + * @description + * Use number validator to restrict the input to integers with an + * optional range. (See integer for whole numbers validator). + * + * @param {string} value value to validate + * @param {int=} [min=MIN_INT] minimum value. + * @param {int=} [max=MAX_INT] maximum value. + * @css ng-validation-error + * + * @example + * Enter integer:
+ * Enter integer equal or greater than 10:
+ * Enter integer between 100 and 200 (inclusive):
+ * + * @scenario + * it('should invalidate integer', function(){ + * var n1 = element('.example :input[name=n1]'); + * expect(n1.attr('className')).not().toMatch(/ng-validation-error/); + * input('n1').enter('1.1'); + * expect(n1.attr('className')).toMatch(/ng-validation-error/); + * + * var n2 = element('.example :input[name=n2]'); + * expect(n2.attr('className')).not().toMatch(/ng-validation-error/); + * input('n2').enter('10.1'); + * expect(n2.attr('className')).toMatch(/ng-validation-error/); + * + * var n3 = element('.example :input[name=n3]'); + * expect(n3.attr('className')).not().toMatch(/ng-validation-error/); + * input('n3').enter('100.1'); + * expect(n3.attr('className')).toMatch(/ng-validation-error/); + * + * }); + */ 'integer': function(value, min, max) { var numberError = angularValidator['number'](value, min, max); if (numberError) return numberError; @@ -34,6 +132,29 @@ extend(angularValidator, { return _null; }, + /** + * @ngdoc validator + * @name angular.validator.date + * @description + * Use date validator to restrict the user input to a valid date + * in format in format MM/DD/YYYY. + * + * @param {string} value value to validate + * @css ng-validation-error + * + * @example + * Enter valid date: + * + * + * @scenario + * it('should invalidate date', function(){ + * var n1 = element('.example :input'); + * expect(n1.attr('className')).not().toMatch(/ng-validation-error/); + * input('text').enter('123/123/123'); + * expect(n1.attr('className')).toMatch(/ng-validation-error/); + * }); + * + */ 'date': function(value) { var fields = /^(\d\d?)\/(\d\d?)\/(\d\d\d\d)$/.exec(value); var date = fields ? new Date(fields[3], fields[1]-1, fields[2]) : 0; @@ -44,13 +165,28 @@ extend(angularValidator, { _null : "Value is not a date. (Expecting format: 12/31/2009)."; }, - 'ssn': function(value) { - if (value.match(/^\d\d\d-\d\d-\d\d\d\d$/)) { - return _null; - } - return "SSN needs to be in 999-99-9999 format."; - }, - + /** + * @ngdoc validator + * @name angular.validator.email + * @description + * Use email validator if you wist to restrict the user input to a valid email. + * + * @param {string} value value to validate + * @css ng-validation-error + * + * @example + * Enter valid email: + * + * + * @scenario + * it('should invalidate email', function(){ + * var n1 = element('.example :input'); + * expect(n1.attr('className')).not().toMatch(/ng-validation-error/); + * input('text').enter('a@b.c'); + * expect(n1.attr('className')).toMatch(/ng-validation-error/); + * }); + * + */ 'email': function(value) { if (value.match(/^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}$/)) { return _null; @@ -58,6 +194,28 @@ extend(angularValidator, { return "Email needs to be in username@host.com format."; }, + /** + * @ngdoc validator + * @name angular.validator.phone + * @description + * Use phone validator to restrict the input phone numbers. + * + * @param {string} value value to validate + * @css ng-validation-error + * + * @example + * Enter valid phone number: + * + * + * @scenario + * it('should invalidate phone', function(){ + * var n1 = element('.example :input'); + * expect(n1.attr('className')).not().toMatch(/ng-validation-error/); + * input('text').enter('+12345678'); + * expect(n1.attr('className')).toMatch(/ng-validation-error/); + * }); + * + */ 'phone': function(value) { if (value.match(/^1\(\d\d\d\)\d\d\d-\d\d\d\d$/)) { return _null; @@ -68,6 +226,28 @@ extend(angularValidator, { return "Phone number needs to be in 1(987)654-3210 format in North America or +999 (123) 45678 906 internationaly."; }, + /** + * @ngdoc validator + * @name angular.validator.url + * @description + * Use phone validator to restrict the input URLs. + * + * @param {string} value value to validate + * @css ng-validation-error + * + * @example + * Enter valid phone number: + * + * + * @scenario + * it('should invalidate url', function(){ + * var n1 = element('.example :input'); + * expect(n1.attr('className')).not().toMatch(/ng-validation-error/); + * input('text').enter('abc://server/path'); + * expect(n1.attr('className')).toMatch(/ng-validation-error/); + * }); + * + */ 'url': function(value) { if (value.match(/^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/)) { return _null; @@ -75,6 +255,29 @@ extend(angularValidator, { return "URL needs to be in http://server[:port]/path format."; }, + /** + * @ngdoc validator + * @name angular.validator.json + * @description + * Use json validator if you wish to restrict the user input to a valid JSON. + * + * @param {string} value value to validate + * @css ng-validation-error + * + * @example + * + * + * @scenario + * it('should invalidate json', function(){ + * var n1 = element('.example :input'); + * expect(n1.attr('className')).not().toMatch(/ng-validation-error/); + * input('json').enter('{name}'); + * expect(n1.attr('className')).toMatch(/ng-validation-error/); + * }); + * + */ 'json': function(value) { try { fromJson(value); diff --git a/src/widgets.js b/src/widgets.js index 4845e694..43a16c8c 100644 --- a/src/widgets.js +++ b/src/widgets.js @@ -1,5 +1,134 @@ /** + * @ngdoc widget + * @name angular.widget.HTML * + * @description + * The most common widgets you will use will be in the from of the + * standard HTML set. These widgets are bound using the name attribute + * to an expression. In addition they can have `ng:validate`, `ng:required`, + * `ng:format`, `ng:change` attribute to further control their behavior. + * + * @usageContent + * see example below for usage + * + * + * + {{input2|json}} + + + radio + String + + <input type="radio" name="input3" value="A">
+ <input type="radio" name="input3" value="B"> +
+ + + + + {{input3|json}} + + + checkbox + Boolean + <input type="checkbox" name="input4" value="checked"> + + {{input4|json}} + + + pulldown + String + + <select name="input5">
+   <option value="c">C</option>
+   <option value="d">D</option>
+ </select>
+
+ + + + {{input5|json}} + + + multiselect + Array + + <select name="input6" multiple size="4">
+   <option value="e">E</option>
+   <option value="f">F</option>
+ </select>
+
+ + + + {{input6|json}} + + + + * @scenario + * it('should exercise text', function(){ + * input('input1').enter('Carlos'); + * expect(binding('input1')).toEqual('"Carlos"'); + * }); + * it('should exercise textarea', function(){ + * input('input2').enter('Carlos'); + * expect(binding('input2')).toEqual('"Carlos"'); + * }); + * it('should exercise radio', function(){ + * expect(binding('input3')).toEqual('null'); + * input('input3').select('A'); + * expect(binding('input3')).toEqual('"A"'); + * input('input3').select('B'); + * expect(binding('input3')).toEqual('"B"'); + * }); + * it('should exercise checkbox', function(){ + * expect(binding('input4')).toEqual('false'); + * input('input4').check(); + * expect(binding('input4')).toEqual('true'); + * }); + * it('should exercise pulldown', function(){ + * expect(binding('input5')).toEqual('"c"'); + * select('input5').option('d'); + * expect(binding('input5')).toEqual('"d"'); + * }); + * it('should exercise multiselect', function(){ + * expect(binding('input6')).toEqual('[]'); + * select('input6').options('e'); + * expect(binding('input6')).toEqual('["e"]'); + * select('input6').options('e', 'f'); + * expect(binding('input6')).toEqual('["e","f"]'); + * }); */ function modelAccessor(scope, element) { -- cgit v1.2.3