diff options
| author | Misko Hevery | 2011-01-31 16:21:29 -0800 |
|---|---|---|
| committer | Misko Hevery | 2011-02-01 10:00:09 -0800 |
| commit | ba6b68b6ae2bb2400a75ca2834fee47bfd60f1c6 (patch) | |
| tree | 94f08ee16f270dd5f6238fb77064c91c624df931 /src | |
| parent | ed768ebc53ef6746ca83d81892c22d2e9c3afeef (diff) | |
| download | angular.js-ba6b68b6ae2bb2400a75ca2834fee47bfd60f1c6.tar.bz2 | |
changed the documentation @example to use <doc:example>
Diffstat (limited to 'src')
| -rw-r--r-- | src/Angular.js | 92 | ||||
| -rw-r--r-- | src/Compiler.js | 68 | ||||
| -rw-r--r-- | src/Scope.js | 46 | ||||
| -rw-r--r-- | src/angular-mocks.js | 26 | ||||
| -rw-r--r-- | src/apis.js | 530 | ||||
| -rw-r--r-- | src/directives.js | 676 | ||||
| -rw-r--r-- | src/filters.js | 351 | ||||
| -rw-r--r-- | src/formatters.js | 197 | ||||
| -rw-r--r-- | src/services.js | 233 | ||||
| -rw-r--r-- | src/validators.js | 309 | ||||
| -rw-r--r-- | src/widgets.js | 554 |
11 files changed, 1666 insertions, 1416 deletions
diff --git a/src/Angular.js b/src/Angular.js index 2812c926..de2de30d 100644 --- a/src/Angular.js +++ b/src/Angular.js @@ -484,14 +484,18 @@ function map(obj, iterator, context) { * @returns {number} The size of `obj` or `0` if `obj` is neither an object or an array. * * @example - * Number of items in array: {{ [1,2].$size() }}<br/> - * Number of items in object: {{ {a:1, b:2, c:3}.$size() }}<br/> - * - * @scenario - it('should print correct sizes for an array and an object', function() { - expect(binding('[1,2].$size()')).toBe('2'); - expect(binding('{a:1, b:2, c:3}.$size()')).toBe('3'); - }); + * <doc:example> + * <doc:source> + * Number of items in array: {{ [1,2].$size() }}<br/> + * Number of items in object: {{ {a:1, b:2, c:3}.$size() }}<br/> + * </doc:source> + * <doc:scenario> + * it('should print correct sizes for an array and an object', function() { + * expect(binding('[1,2].$size()')).toBe('2'); + * expect(binding('{a:1, b:2, c:3}.$size()')).toBe('3'); + * }); + * </doc:scenario> + * </doc:example> */ function size(obj) { var size = 0, key; @@ -556,17 +560,19 @@ function isLeafNode (node) { * @returns {*} The copy or updated `destination` if `destination` was specified. * * @example - Salutation: <input type="text" name="master.salutation" value="Hello" /><br/> - Name: <input type="text" name="master.name" value="world"/><br/> - <button ng:click="form = master.$copy()">copy</button> - <hr/> - - The master object is <span ng:hide="master.$equals(form)">NOT</span> equal to the form object. - - <pre>master={{master}}</pre> - <pre>form={{form}}</pre> - - * @scenario + * <doc:example> + * <doc:source> + Salutation: <input type="text" name="master.salutation" value="Hello" /><br/> + Name: <input type="text" name="master.name" value="world"/><br/> + <button ng:click="form = master.$copy()">copy</button> + <hr/> + + The master object is <span ng:hide="master.$equals(form)">NOT</span> equal to the form object. + + <pre>master={{master}}</pre> + <pre>form={{form}}</pre> + * </doc:source> + * <doc:scenario> it('should print that initialy the form object is NOT equal to master', function() { expect(element('.doc-example input[name=master.salutation]').val()).toBe('Hello'); expect(element('.doc-example input[name=master.name]').val()).toBe('world'); @@ -577,6 +583,8 @@ function isLeafNode (node) { element('.doc-example button').click(); expect(element('.doc-example span').css('display')).toBe('none'); }); + * </doc:scenario> + * </doc:example> */ function copy(source, destination){ if (!destination) { @@ -633,27 +641,31 @@ function copy(source, destination){ * @returns {boolean} True if arguments are equal. * * @example - Salutation: <input type="text" name="greeting.salutation" value="Hello" /><br/> - Name: <input type="text" name="greeting.name" value="world"/><br/> - <hr/> - - The <code>greeting</code> object is - <span ng:hide="greeting.$equals({salutation:'Hello', name:'world'})">NOT</span> equal to - <code>{salutation:'Hello', name:'world'}</code>. - - <pre>greeting={{greeting}}</pre> - - @scenario - it('should print that initialy greeting is equal to the hardcoded value object', function() { - expect(element('.doc-example input[name=greeting.salutation]').val()).toBe('Hello'); - expect(element('.doc-example input[name=greeting.name]').val()).toBe('world'); - expect(element('.doc-example span').css('display')).toBe('none'); - }); - - it('should say that the objects are not equal when the form is modified', function() { - input('greeting.name').enter('kitty'); - expect(element('.doc-example span').css('display')).toBe('inline'); - }); + * <doc:example> + * <doc:source> + Salutation: <input type="text" name="greeting.salutation" value="Hello" /><br/> + Name: <input type="text" name="greeting.name" value="world"/><br/> + <hr/> + + The <code>greeting</code> object is + <span ng:hide="greeting.$equals({salutation:'Hello', name:'world'})">NOT</span> equal to + <code>{salutation:'Hello', name:'world'}</code>. + + <pre>greeting={{greeting}}</pre> + * </doc:source> + * <doc:scenario> + it('should print that initialy greeting is equal to the hardcoded value object', function() { + expect(element('.doc-example input[name=greeting.salutation]').val()).toBe('Hello'); + expect(element('.doc-example input[name=greeting.name]').val()).toBe('world'); + expect(element('.doc-example span').css('display')).toBe('none'); + }); + + it('should say that the objects are not equal when the form is modified', function() { + input('greeting.name').enter('kitty'); + expect(element('.doc-example span').css('display')).toBe('inline'); + }); + * </doc:scenario> + * </doc:example> */ function equals(o1, o2) { if (o1 == o2) return true; diff --git a/src/Compiler.js b/src/Compiler.js index c2c56650..472ec625 100644 --- a/src/Compiler.js +++ b/src/Compiler.js @@ -139,40 +139,44 @@ Compiler.prototype = { * @element ANY * @param {integer|string=} [priority=0] priority integer, or FIRST, LAST constant * - * @exampleDescription + * @example * try changing the invoice and see that the Total will lag in evaluation * @example - <div>TOTAL: without ng:eval-order {{ items.$sum('total') | currency }}</div> - <div ng:eval-order='LAST'>TOTAL: with ng:eval-order {{ items.$sum('total') | currency }}</div> - <table ng:init="items=[{qty:1, cost:9.99, desc:'gadget'}]"> - <tr> - <td>QTY</td> - <td>Description</td> - <td>Cost</td> - <td>Total</td> - <td></td> - </tr> - <tr ng:repeat="item in items"> - <td><input name="item.qty"/></td> - <td><input name="item.desc"/></td> - <td><input name="item.cost"/></td> - <td>{{item.total = item.qty * item.cost | currency}}</td> - <td><a href="" ng:click="items.$remove(item)">X</a></td> - </tr> - <tr> - <td colspan="3"><a href="" ng:click="items.$add()">add</a></td> - <td>{{ items.$sum('total') | currency }}</td> - </tr> - </table> - * - * @scenario - it('should check ng:format', function(){ - expect(using('.doc-example-live div:first').binding("items.$sum('total')")).toBe('$9.99'); - expect(using('.doc-example-live div:last').binding("items.$sum('total')")).toBe('$9.99'); - input('item.qty').enter('2'); - expect(using('.doc-example-live div:first').binding("items.$sum('total')")).toBe('$9.99'); - expect(using('.doc-example-live div:last').binding("items.$sum('total')")).toBe('$19.98'); - }); + <doc:example> + <doc:source> + <div>TOTAL: without ng:eval-order {{ items.$sum('total') | currency }}</div> + <div ng:eval-order='LAST'>TOTAL: with ng:eval-order {{ items.$sum('total') | currency }}</div> + <table ng:init="items=[{qty:1, cost:9.99, desc:'gadget'}]"> + <tr> + <td>QTY</td> + <td>Description</td> + <td>Cost</td> + <td>Total</td> + <td></td> + </tr> + <tr ng:repeat="item in items"> + <td><input name="item.qty"/></td> + <td><input name="item.desc"/></td> + <td><input name="item.cost"/></td> + <td>{{item.total = item.qty * item.cost | currency}}</td> + <td><a href="" ng:click="items.$remove(item)">X</a></td> + </tr> + <tr> + <td colspan="3"><a href="" ng:click="items.$add()">add</a></td> + <td>{{ items.$sum('total') | currency }}</td> + </tr> + </table> + </doc:source> + <doc:scenario> + it('should check ng:format', function(){ + expect(using('.doc-example-live div:first').binding("items.$sum('total')")).toBe('$9.99'); + expect(using('.doc-example-live div:last').binding("items.$sum('total')")).toBe('$9.99'); + input('item.qty').enter('2'); + expect(using('.doc-example-live div:first').binding("items.$sum('total')")).toBe('$9.99'); + expect(using('.doc-example-live div:last').binding("items.$sum('total')")).toBe('$19.98'); + }); + </doc:scenario> + </doc:example> */ templatize: function(element, elementIndex, priority){ diff --git a/src/Scope.js b/src/Scope.js index aef2706e..a73375ab 100644 --- a/src/Scope.js +++ b/src/Scope.js @@ -202,7 +202,7 @@ function errorHandlerFor(element, error) { * @returns {Object} Newly created scope. * * - * @exampleDescription + * @example * This example demonstrates scope inheritance and property overriding. * * In this example, the root scope encompasses the whole HTML DOM tree. This scope has `salutation`, @@ -216,27 +216,29 @@ function errorHandlerFor(element, error) { * - The child scope inherits the salutation property from the root scope. * - The $index property does not leak from the child scope to the root scope. * - * @example - <ul ng:init="salutation='Hello'; name='Misko'; names=['World', 'Earth']"> - <li ng:repeat="name in names"> - {{$index}}: {{salutation}} {{name}}! - </li> - </ul> - <pre> - $index={{$index}} - salutation={{salutation}} - name={{name}}</pre> - - @scenario - it('should inherit the salutation property and override the name property', function() { - expect(using('.doc-example-live').repeater('li').row(0)). - toEqual(['0', 'Hello', 'World']); - expect(using('.doc-example-live').repeater('li').row(1)). - toEqual(['1', 'Hello', 'Earth']); - expect(using('.doc-example-live').element('pre').text()). - toBe('$index=\nsalutation=Hello\nname=Misko'); - }); - + <doc:example> + <doc:source> + <ul ng:init="salutation='Hello'; name='Misko'; names=['World', 'Earth']"> + <li ng:repeat="name in names"> + {{$index}}: {{salutation}} {{name}}! + </li> + </ul> + <pre> + $index={{$index}} + salutation={{salutation}} + name={{name}}</pre> + </doc:source> + <doc:scenario> + it('should inherit the salutation property and override the name property', function() { + expect(using('.doc-example-live').repeater('li').row(0)). + toEqual(['0', 'Hello', 'World']); + expect(using('.doc-example-live').repeater('li').row(1)). + toEqual(['1', 'Hello', 'Earth']); + expect(using('.doc-example-live').element('pre').text()). + toBe('$index=\nsalutation=Hello\nname=Misko'); + }); + </doc:scenario> + </doc:example> */ function createScope(parent, providers, instanceCache) { function Parent(){} diff --git a/src/angular-mocks.js b/src/angular-mocks.js index fe0fb011..71a18d06 100644 --- a/src/angular-mocks.js +++ b/src/angular-mocks.js @@ -239,10 +239,10 @@ angular.service('$exceptionHandler', function(e) { */ angular.service('$log', function() { var $log = { - log: function(){ $log.logs.push(arguments) }, - warn: function(){ $log.logs.push(arguments) }, - info: function(){ $log.logs.push(arguments) }, - error: function(){ $log.logs.push(arguments) } + log: function(){ $log.logs.push(arguments); }, + warn: function(){ $log.logs.push(arguments); }, + info: function(){ $log.logs.push(arguments); }, + error: function(){ $log.logs.push(arguments); } }; $log.log.logs = []; @@ -265,6 +265,15 @@ angular.service('$log', function() { * @param {(number|string)} timestamp Timestamp representing the desired time in *UTC* * * @example + * !!!! WARNING !!!!! + * This is not a complete Date object so only methods that were implemented can be called safely. + * To make matters worse, TzDate instances inherit stuff from Date via a prototype. + * + * We do our best to intercept calls to "unimplemented" methods, but since the list of methods is + * incomplete we might be missing some non-standard methods. This can result in errors like: + * "Date.prototype.foo called on incompatible Object". + * + * <pre> * var newYearInBratislava = new TzDate(-1, '2009-12-31T23:00:00Z'); * newYearInBratislava.getTimezoneOffset() => -60; * newYearInBratislava.getFullYear() => 2010; @@ -272,15 +281,8 @@ angular.service('$log', function() { * newYearInBratislava.getDate() => 1; * newYearInBratislava.getHours() => 0; * newYearInBratislava.getMinutes() => 0; + * </pre> * - * - * !!!! WARNING !!!!! - * This is not a complete Date object so only methods that were implemented can be called safely. - * To make matters worse, TzDate instances inherit stuff from Date via a prototype. - * - * We do our best to intercept calls to "unimplemented" methods, but since the list of methods is - * incomplete we might be missing some non-standard methods. This can result in errors like: - * "Date.prototype.foo called on incompatible Object". */ function TzDate(offset, timestamp) { if (angular.isString(timestamp)) { diff --git a/src/apis.js b/src/apis.js index 35e3a92f..437cd6e0 100644 --- a/src/apis.js +++ b/src/apis.js @@ -79,22 +79,26 @@ var angularArray = { * @returns {number} The position of the element in `array`. The position is 0-based. `-1` is returned if the value can't be found. * * @example - <div ng:init="books = ['Moby Dick', 'Great Gatsby', 'Romeo and Juliet']"></div> - <input name='bookName' value='Romeo and Juliet'> <br> - Index of '{{bookName}}' in the list {{books}} is <em>{{books.$indexOf(bookName)}}</em>. - - @scenario - it('should correctly calculate the initial index', function() { - expect(binding('books.$indexOf(bookName)')).toBe('2'); - }); - - it('should recalculate', function() { - input('bookName').enter('foo'); - expect(binding('books.$indexOf(bookName)')).toBe('-1'); - - input('bookName').enter('Moby Dick'); - expect(binding('books.$indexOf(bookName)')).toBe('0'); - }); + <doc:example> + <doc:source> + <div ng:init="books = ['Moby Dick', 'Great Gatsby', 'Romeo and Juliet']"></div> + <input name='bookName' value='Romeo and Juliet'> <br> + Index of '{{bookName}}' in the list {{books}} is <em>{{books.$indexOf(bookName)}}</em>. + </doc:source> + <doc:scenario> + it('should correctly calculate the initial index', function() { + expect(binding('books.$indexOf(bookName)')).toBe('2'); + }); + + it('should recalculate', function() { + input('bookName').enter('foo'); + expect(binding('books.$indexOf(bookName)')).toBe('-1'); + + input('bookName').enter('Moby Dick'); + expect(binding('books.$indexOf(bookName)')).toBe('0'); + }); + </doc:scenario> + </doc:example> */ 'indexOf': indexOf, @@ -117,42 +121,46 @@ var angularArray = { * @returns {number} Sum of items in the array. * * @example - <table ng:init="invoice= {items:[{qty:10, description:'gadget', cost:9.95}]}"> - <tr><th>Qty</th><th>Description</th><th>Cost</th><th>Total</th><th></th></tr> - <tr ng:repeat="item in invoice.items"> - <td><input name="item.qty" value="1" size="4" ng:required ng:validate="integer"></td> - <td><input name="item.description"></td> - <td><input name="item.cost" value="0.00" ng:required ng:validate="number" size="6"></td> - <td>{{item.qty * item.cost | currency}}</td> - <td>[<a href ng:click="invoice.items.$remove(item)">X</a>]</td> - </tr> - <tr> - <td><a href ng:click="invoice.items.$add()">add item</a></td> - <td></td> - <td>Total:</td> - <td>{{invoice.items.$sum('qty*cost') | currency}}</td> - </tr> - </table> - - @scenario - //TODO: these specs are lame because I had to work around issues #164 and #167 - it('should initialize and calculate the totals', function() { - expect(repeater('.doc-example-live table tr', 'item in invoice.items').count()).toBe(3); - expect(repeater('.doc-example-live table tr', 'item in invoice.items').row(1)). - toEqual(['$99.50']); - expect(binding("invoice.items.$sum('qty*cost')")).toBe('$99.50'); - expect(binding("invoice.items.$sum('qty*cost')")).toBe('$99.50'); - }); - - it('should add an entry and recalculate', function() { - element('.doc-example a:contains("add item")').click(); - using('.doc-example-live tr:nth-child(3)').input('item.qty').enter('20'); - using('.doc-example-live tr:nth-child(3)').input('item.cost').enter('100'); - - expect(repeater('.doc-example-live table tr', 'item in invoice.items').row(2)). - toEqual(['$2,000.00']); - expect(binding("invoice.items.$sum('qty*cost')")).toBe('$2,099.50'); - }); + <doc:example> + <doc:source> + <table ng:init="invoice= {items:[{qty:10, description:'gadget', cost:9.95}]}"> + <tr><th>Qty</th><th>Description</th><th>Cost</th><th>Total</th><th></th></tr> + <tr ng:repeat="item in invoice.items"> + <td><input name="item.qty" value="1" size="4" ng:required ng:validate="integer"></td> + <td><input name="item.description"></td> + <td><input name="item.cost" value="0.00" ng:required ng:validate="number" size="6"></td> + <td>{{item.qty * item.cost | currency}}</td> + <td>[<a href ng:click="invoice.items.$remove(item)">X</a>]</td> + </tr> + <tr> + <td><a href ng:click="invoice.items.$add()">add item</a></td> + <td></td> + <td>Total:</td> + <td>{{invoice.items.$sum('qty*cost') | currency}}</td> + </tr> + </table> + </doc:source> + <doc:scenario> + //TODO: these specs are lame because I had to work around issues #164 and #167 + it('should initialize and calculate the totals', function() { + expect(repeater('.doc-example-live table tr', 'item in invoice.items').count()).toBe(3); + expect(repeater('.doc-example-live table tr', 'item in invoice.items').row(1)). + toEqual(['$99.50']); + expect(binding("invoice.items.$sum('qty*cost')")).toBe('$99.50'); + expect(binding("invoice.items.$sum('qty*cost')")).toBe('$99.50'); + }); + + it('should add an entry and recalculate', function() { + element('.doc-example a:contains("add item")').click(); + using('.doc-example-live tr:nth-child(3)').input('item.qty').enter('20'); + using('.doc-example-live tr:nth-child(3)').input('item.cost').enter('100'); + + expect(repeater('.doc-example-live table tr', 'item in invoice.items').row(2)). + toEqual(['$2,000.00']); + expect(binding("invoice.items.$sum('qty*cost')")).toBe('$2,099.50'); + }); + </doc:scenario> + </doc:example> */ 'sum':function(array, expression) { var fn = angular['Function']['compile'](expression); @@ -185,33 +193,37 @@ var angularArray = { * @returns {*} The removed element. * * @example - <ul ng:init="tasks=['Learn Angular', 'Read Documentation', - 'Check out demos', 'Build cool applications']"> - <li ng:repeat="task in tasks"> - {{task}} [<a href="" ng:click="tasks.$remove(task)">X</a>] - </li> - </ul> - <hr/> - tasks = {{tasks}} - - @scenario - it('should initialize the task list with for tasks', function() { - expect(repeater('.doc-example ul li', 'task in tasks').count()).toBe(4); - expect(repeater('.doc-example ul li', 'task in tasks').column('task')). - toEqual(['Learn Angular', 'Read Documentation', 'Check out demos', - 'Build cool applications']); - }); - - it('should initialize the task list with for tasks', function() { - element('.doc-example ul li a:contains("X"):first').click(); - expect(repeater('.doc-example ul li', 'task in tasks').count()).toBe(3); - - element('.doc-example ul li a:contains("X"):last').click(); - expect(repeater('.doc-example ul li', 'task in tasks').count()).toBe(2); - - expect(repeater('.doc-example ul li', 'task in tasks').column('task')). - toEqual(['Read Documentation', 'Check out demos']); - }); + <doc:example> + <doc:source> + <ul ng:init="tasks=['Learn Angular', 'Read Documentation', + 'Check out demos', 'Build cool applications']"> + <li ng:repeat="task in tasks"> + {{task}} [<a href="" ng:click="tasks.$remove(task)">X</a>] + </li> + </ul> + <hr/> + tasks = {{tasks}} + </doc:source> + <doc:scenario> + it('should initialize the task list with for tasks', function() { + expect(repeater('.doc-example ul li', 'task in tasks').count()).toBe(4); + expect(repeater('.doc-example ul li', 'task in tasks').column('task')). + toEqual(['Learn Angular', 'Read Documentation', 'Check out demos', + 'Build cool applications']); + }); + + it('should initialize the task list with for tasks', function() { + element('.doc-example ul li a:contains("X"):first').click(); + expect(repeater('.doc-example ul li', 'task in tasks').count()).toBe(3); + + element('.doc-example ul li a:contains("X"):last').click(); + expect(repeater('.doc-example ul li', 'task in tasks').count()).toBe(2); + + expect(repeater('.doc-example ul li', 'task in tasks').column('task')). + toEqual(['Read Documentation', 'Check out demos']); + }); + </doc:scenario> + </doc:example> */ 'remove':function(array, value) { var index = indexOf(array, value); @@ -254,48 +266,52 @@ var angularArray = { * the predicate returned true for. * * @example - <div ng:init="friends = [{name:'John', phone:'555-1276'}, - {name:'Mary', phone:'800-BIG-MARY'}, - {name:'Mike', phone:'555-4321'}, - {name:'Adam', phone:'555-5678'}, - {name:'Julie', phone:'555-8765'}]"></div> - - Search: <input name="searchText"/> - <table id="searchTextResults"> - <tr><th>Name</th><th>Phone</th><tr> - <tr ng:repeat="friend in friends.$filter(searchText)"> - <td>{{friend.name}}</td> - <td>{{friend.phone}}</td> - <tr> - </table> - <hr> - Any: <input name="search.$"/> <br> - Name only <input name="search.name"/><br> - Phone only <input name="search.phone"/><br> - <table id="searchObjResults"> - <tr><th>Name</th><th>Phone</th><tr> - <tr ng:repeat="friend in friends.$filter(search)"> - <td>{{friend.name}}</td> - <td>{{friend.phone}}</td> - <tr> - </table> - - @scenario - it('should search across all fields when filtering with a string', function() { - input('searchText').enter('m'); - expect(repeater('#searchTextResults tr', 'friend in friends').column('name')). - toEqual(['Mary', 'Mike', 'Adam']); - - input('searchText').enter('76'); - expect(repeater('#searchTextResults tr', 'friend in friends').column('name')). - toEqual(['John', 'Julie']); - }); - - it('should search in specific fields when filtering with a predicate object', function() { - input('search.$').enter('i'); - expect(repeater('#searchObjResults tr', 'friend in friends').column('name')). - toEqual(['Mary', 'Mike', 'Julie']); - }); + <doc:example> + <doc:source> + <div ng:init="friends = [{name:'John', phone:'555-1276'}, + {name:'Mary', phone:'800-BIG-MARY'}, + {name:'Mike', phone:'555-4321'}, + {name:'Adam', phone:'555-5678'}, + {name:'Julie', phone:'555-8765'}]"></div> + + Search: <input name="searchText"/> + <table id="searchTextResults"> + <tr><th>Name</th><th>Phone</th><tr> + <tr ng:repeat="friend in friends.$filter(searchText)"> + <td>{{friend.name}}</td> + <td>{{friend.phone}}</td> + <tr> + </table> + <hr> + Any: <input name="search.$"/> <br> + Name only <input name="search.name"/><br> + Phone only <input name="search.phone"/><br> + <table id="searchObjResults"> + <tr><th>Name</th><th>Phone</th><tr> + <tr ng:repeat="friend in friends.$filter(search)"> + <td>{{friend.name}}</td> + <td>{{friend.phone}}</td> + <tr> + </table> + </doc:source> + <doc:scenario> + it('should search across all fields when filtering with a string', function() { + input('searchText').enter('m'); + expect(repeater('#searchTextResults tr', 'friend in friends').column('name')). + toEqual(['Mary', 'Mike', 'Adam']); + + input('searchText').enter('76'); + expect(repeater('#searchTextResults tr', 'friend in friends').column('name')). + toEqual(['John', 'Julie']); + }); + + it('should search in specific fields when filtering with a predicate object', function() { + input('search.$').enter('i'); + expect(repeater('#searchObjResults tr', 'friend in friends').column('name')). + toEqual(['Mary', 'Mike', 'Julie']); + }); + </doc:scenario> + </doc:example> */ 'filter':function(array, expression) { var predicates = []; @@ -398,53 +414,55 @@ var angularArray = { * * @TODO simplify the example. * - * @exampleDescription + * @example * This example shows how an initially empty array can be filled with objects created from user * input via the `$add` method. - * - * @example - [<a href="" ng:click="people.$add()">add empty</a>] - [<a href="" ng:click="people.$add({name:'John', sex:'male'})">add 'John'</a>] - [<a href="" ng:click="people.$add({name:'Mary', sex:'female'})">add 'Mary'</a>] - - <ul ng:init="people=[]"> - <li ng:repeat="person in people"> - <input name="person.name"> - <select name="person.sex"> - <option value="">--chose one--</option> - <option>male</option> - <option>female</option> - </select> - [<a href="" ng:click="people.$remove(person)">X</a>] - </li> - </ul> - <pre>people = {{people}}</pre> - - @scenario - beforeEach(function() { - expect(binding('people')).toBe('people = []'); - }); - - it('should create an empty record when "add empty" is clicked', function() { - element('.doc-example a:contains("add empty")').click(); - expect(binding('people')).toBe('people = [{\n "name":"",\n "sex":null}]'); - }); - - it('should create a "John" record when "add \'John\'" is clicked', function() { - element('.doc-example a:contains("add \'John\'")').click(); - expect(binding('people')).toBe('people = [{\n "name":"John",\n "sex":"male"}]'); - }); - - it('should create a "Mary" record when "add \'Mary\'" is clicked', function() { - element('.doc-example a:contains("add \'Mary\'")').click(); - expect(binding('people')).toBe('people = [{\n "name":"Mary",\n "sex":"female"}]'); - }); - - it('should delete a record when "X" is clicked', function() { - element('.doc-example a:contains("add empty")').click(); - element('.doc-example li a:contains("X"):first').click(); - expect(binding('people')).toBe('people = []'); - }); + <doc:example> + <doc:source> + [<a href="" ng:click="people.$add()">add empty</a>] + [<a href="" ng:click="people.$add({name:'John', sex:'male'})">add 'John'</a>] + [<a href="" ng:click="people.$add({name:'Mary', sex:'female'})">add 'Mary'</a>] + + <ul ng:init="people=[]"> + <li ng:repeat="person in people"> + <input name="person.name"> + <select name="person.sex"> + <option value="">--chose one--</option> + <option>male</option> + <option>female</option> + </select> + [<a href="" ng:click="people.$remove(person)">X</a>] + </li> + </ul> + <pre>people = {{people}}</pre> + </doc:source> + <doc:scenario> + beforeEach(function() { + expect(binding('people')).toBe('people = []'); + }); + + it('should create an empty record when "add empty" is clicked', function() { + element('.doc-example a:contains("add empty")').click(); + expect(binding('people')).toBe('people = [{\n "name":"",\n "sex":null}]'); + }); + + it('should create a "John" record when "add \'John\'" is clicked', function() { + element('.doc-example a:contains("add \'John\'")').click(); + expect(binding('people')).toBe('people = [{\n "name":"John",\n "sex":"male"}]'); + }); + + it('should create a "Mary" record when "add \'Mary\'" is clicked', function() { + element('.doc-example a:contains("add \'Mary\'")').click(); + expect(binding('people')).toBe('people = [{\n "name":"Mary",\n "sex":"female"}]'); + }); + + it('should delete a record when "X" is clicked', function() { + element('.doc-example a:contains("add empty")').click(); + element('.doc-example li a:contains("X"):first').click(); + expect(binding('people')).toBe('people = []'); + }); + </doc:scenario> + </doc:example> */ 'add':function(array, value) { array.push(isUndefined(value)? {} : value); @@ -471,29 +489,33 @@ var angularArray = { * @returns {number} Number of elements in the array (for which the condition evaluates to true). * * @example - <pre ng:init="items = [{name:'knife', points:1}, - {name:'fork', points:3}, - {name:'spoon', points:1}]"></pre> - <ul> - <li ng:repeat="item in items"> - {{item.name}}: points= - <input type="text" name="item.points"/> <!-- id="item{{$index}} --> - </li> - </ul> - <p>Number of items which have one point: <em>{{ items.$count('points==1') }}</em></p> - <p>Number of items which have more than one point: <em>{{items.$count('points>1')}}</em></p> - - @scenario - it('should calculate counts', function() { - expect(binding('items.$count(\'points==1\')')).toEqual(2); - expect(binding('items.$count(\'points>1\')')).toEqual(1); - }); - - it('should recalculate when updated', function() { - using('.doc-example li:first-child').input('item.points').enter('23'); - expect(binding('items.$count(\'points==1\')')).toEqual(1); - expect(binding('items.$count(\'points>1\')')).toEqual(2); - }); + <doc:example> + <doc:source> + <pre ng:init="items = [{name:'knife', points:1}, + {name:'fork', points:3}, + {name:'spoon', points:1}]"></pre> + <ul> + <li ng:repeat="item in items"> + {{item.name}}: points= + <input type="text" name="item.points"/> <!-- id="item{{$index}} --> + </li> + </ul> + <p>Number of items which have one point: <em>{{ items.$count('points==1') }}</em></p> + <p>Number of items which have more than one point: <em>{{items.$count('points>1')}}</em></p> + </doc:source> + <doc:scenario> + it('should calculate counts', function() { + expect(binding('items.$count(\'points==1\')')).toEqual(2); + expect(binding('items.$count(\'points>1\')')).toEqual(1); + }); + + it('should recalculate when updated', function() { + using('.doc-example li:first-child').input('item.points').enter('23'); + expect(binding('items.$count(\'points==1\')')).toEqual(1); + expect(binding('items.$count(\'points>1\')')).toEqual(2); + }); + </doc:scenario> + </doc:example> */ 'count':function(array, condition) { if (!condition) return array.length; @@ -535,52 +557,56 @@ var angularArray = { * @returns {Array} Sorted copy of the source array. * * @example - <div ng:init="friends = [{name:'John', phone:'555-1212', age:10}, - {name:'Mary', phone:'555-9876', age:19}, - {name:'Mike', phone:'555-4321', age:21}, - {name:'Adam', phone:'555-5678', age:35}, - {name:'Julie', phone:'555-8765', age:29}]"></div> - - <pre>Sorting predicate = {{predicate}}</pre> - <hr/> - <table ng:init="predicate='-age'"> - <tr> - <th><a href="" ng:click="predicate = 'name'">Name</a> - (<a href ng:click="predicate = '-name'">^</a>)</th> - <th><a href="" ng:click="predicate = 'phone'">Phone</a> - (<a href ng:click="predicate = '-phone'">^</a>)</th> - <th><a href="" ng:click="predicate = 'age'">Age</a> - (<a href ng:click="predicate = '-age'">^</a>)</th> - <tr> - <tr ng:repeat="friend in friends.$orderBy(predicate)"> - <td>{{friend.name}}</td> - <td>{{friend.phone}}</td> - <td>{{friend.age}}</td> - <tr> - </table> - - @scenario - it('should be reverse ordered by aged', function() { - expect(binding('predicate')).toBe('Sorting predicate = -age'); - expect(repeater('.doc-example table', 'friend in friends').column('friend.age')). - toEqual(['35', '29', '21', '19', '10']); - expect(repeater('.doc-example table', 'friend in friends').column('friend.name')). - toEqual(['Adam', 'Julie', 'Mike', 'Mary', 'John']); - }); - - it('should reorder the table when user selects different predicate', function() { - element('.doc-example a:contains("Name")').click(); - expect(repeater('.doc-example table', 'friend in friends').column('friend.name')). - toEqual(['Adam', 'John', 'Julie', 'Mary', 'Mike']); - expect(repeater('.doc-example table', 'friend in friends').column('friend.age')). - toEqual(['35', '10', '29', '19', '21']); - - element('.doc-example a:contains("Phone")+a:contains("^")').click(); - expect(repeater('.doc-example table', 'friend in friends').column('friend.phone')). - toEqual(['555-9876', '555-8765', '555-5678', '555-4321', '555-1212']); - expect(repeater('.doc-example table', 'friend in friends').column('friend.name')). - toEqual(['Mary', 'Julie', 'Adam', 'Mike', 'John']); - }); + <doc:example> + <doc:source> + <div ng:init="friends = [{name:'John', phone:'555-1212', age:10}, + {name:'Mary', phone:'555-9876', age:19}, + {name:'Mike', phone:'555-4321', age:21}, + {name:'Adam', phone:'555-5678', age:35}, + {name:'Julie', phone:'555-8765', age:29}]"></div> + + <pre>Sorting predicate = {{predicate}}</pre> + <hr/> + <table ng:init="predicate='-age'"> + <tr> + <th><a href="" ng:click="predicate = 'name'">Name</a> + (<a href ng:click="predicate = '-name'">^</a>)</th> + <th><a href="" ng:click="predicate = 'phone'">Phone</a> + (<a href ng:click="predicate = '-phone'">^</a>)</th> + <th><a href="" ng:click="predicate = 'age'">Age</a> + (<a href ng:click="predicate = '-age'">^</a>)</th> + <tr> + <tr ng:repeat="friend in friends.$orderBy(predicate)"> + <td>{{friend.name}}</td> + <td>{{friend.phone}}</td> + <td>{{friend.age}}</td> + <tr> + </table> + </doc:source> + <doc:scenario> + it('should be reverse ordered by aged', function() { + expect(binding('predicate')).toBe('Sorting predicate = -age'); + expect(repeater('.doc-example table', 'friend in friends').column('friend.age')). + toEqual(['35', '29', '21', '19', '10']); + expect(repeater('.doc-example table', 'friend in friends').column('friend.name')). + toEqual(['Adam', 'Julie', 'Mike', 'Mary', 'John']); + }); + + it('should reorder the table when user selects different predicate', function() { + element('.doc-example a:contains("Name")').click(); + expect(repeater('.doc-example table', 'friend in friends').column('friend.name')). + toEqual(['Adam', 'John', 'Julie', 'Mary', 'Mike']); + expect(repeater('.doc-example table', 'friend in friends').column('friend.age')). + toEqual(['35', '10', '29', '19', '21']); + + element('.doc-example a:contains("Phone")+a:contains("^")').click(); + expect(repeater('.doc-example table', 'friend in friends').column('friend.phone')). + toEqual(['555-9876', '555-8765', '555-5678', '555-4321', '555-1212']); + expect(repeater('.doc-example table', 'friend in friends').column('friend.name')). + toEqual(['Mary', 'Julie', 'Adam', 'Mike', 'John']); + }); + </doc:scenario> + </doc:example> */ //TODO: WTH is descend param for and how/when it should be used, how is it affected by +/- in // predicate? the code below is impossible to read and specs are not very good. @@ -648,21 +674,25 @@ var angularArray = { * @returns {Array} A new sub-array of length `limit`. * * @example - <div ng:init="numbers = [1,2,3,4,5,6,7,8,9]"> - Limit [1,2,3,4,5,6,7,8,9] to: <input name="limit" value="3"/> - <p>Output: {{ numbers.$limitTo(limit) | json }}</p> - </div> - - * @scenario - it('should limit the numer array to first three items', function() { - expect(element('.doc-example input[name=limit]').val()).toBe('3'); - expect(binding('numbers.$limitTo(limit) | json')).toEqual('[1,2,3]'); - }); - - it('should update the output when -3 is entered', function() { - input('limit').enter(-3); - expect(binding('numbers.$limitTo(limit) | json')).toEqual('[7,8,9]'); - }); + <doc:example> + <doc:source> + <div ng:init="numbers = [1,2,3,4,5,6,7,8,9]"> + Limit [1,2,3,4,5,6,7,8,9] to: <input name="limit" value="3"/> + <p>Output: {{ numbers.$limitTo(limit) | json }}</p> + </div> + </doc:source> + <doc:scenario> + it('should limit the numer array to first three items', function() { + expect(element('.doc-example input[name=limit]').val()).toBe('3'); + expect(binding('numbers.$limitTo(limit) | json')).toEqual('[1,2,3]'); + }); + + it('should update the output when -3 is entered', function() { + input('limit').enter(-3); + expect(binding('numbers.$limitTo(limit) | json')).toEqual('[7,8,9]'); + }); + </doc:scenario> + </doc:example> */ limitTo: function(array, limit) { limit = parseInt(limit, 10); diff --git a/src/directives.js b/src/directives.js index 104ff9c8..5ca7c2ec 100644 --- a/src/directives.js +++ b/src/directives.js @@ -4,22 +4,26 @@ * @name angular.directive.ng:init * * @description - * `ng:init` attribute allows the for initialization tasks to be executed + * `ng:init` attribute allows the for initialization tasks to be executed * before the template enters execution mode during bootstrap. * * @element ANY * @param {expression} expression to eval. * * @example + <doc:example> + <doc:source> <div ng:init="greeting='Hello'; person='World'"> {{greeting}} {{person}}! </div> - * - * @scenario - it('should check greeting', function(){ - expect(binding('greeting')).toBe('Hello'); - expect(binding('person')).toBe('World'); - }); + </doc:source> + <doc:scenario> + it('should check greeting', function(){ + expect(binding('greeting')).toBe('Hello'); + expect(binding('person')).toBe('World'); + }); + </doc:scenario> + </doc:example> */ angularDirective("ng:init", function(expression){ return function(element){ @@ -33,66 +37,70 @@ angularDirective("ng:init", function(expression){ * @name angular.directive.ng:controller * * @description - * To support the Model-View-Controller design pattern, it is possible - * to assign behavior to a scope through `ng:controller`. The scope is - * the MVC model. The HTML (with data bindings) is the MVC view. + * To support the Model-View-Controller design pattern, it is possible + * to assign behavior to a scope through `ng:controller`. The scope is + * the MVC model. The HTML (with data bindings) is the MVC view. * The `ng:controller` directive specifies the MVC controller class * * @element ANY * @param {expression} expression to eval. * * @example - <script type="text/javascript"> - function SettingsController() { - this.name = "John Smith"; - this.contacts = [ - {type:'phone', value:'408 555 1212'}, - {type:'email', value:'john.smith@example.org'} ]; - } - SettingsController.prototype = { - greet: function(){ - alert(this.name); - }, - addContact: function(){ - this.contacts.push({type:'email', value:'yourname@example.org'}); - }, - removeContact: function(contactToRemove) { - angular.Array.remove(this.contacts, contactToRemove); - }, - clearContact: function(contact) { - contact.type = 'phone'; - contact.value = ''; - } - }; - </script> - <div ng:controller="SettingsController"> - Name: <input type="text" name="name"/> - [ <a href="" ng:click="greet()">greet</a> ]<br/> - Contact: - <ul> - <li ng:repeat="contact in contacts"> - <select name="contact.type"> - <option>phone</option> - <option>email</option> - </select> - <input type="text" name="contact.value"/> - [ <a href="" ng:click="clearContact(contact)">clear</a> - | <a href="" ng:click="removeContact(contact)">X</a> ] - </li> - <li>[ <a href="" ng:click="addContact()">add</a> ]</li> - </ul> - </div> - * - * @scenario - it('should check controller', function(){ - expect(element('.doc-example-live div>:input').val()).toBe('John Smith'); - expect(element('.doc-example-live li[ng\\:repeat-index="0"] input').val()).toBe('408 555 1212'); - expect(element('.doc-example-live li[ng\\:repeat-index="1"] input').val()).toBe('john.smith@example.org'); - element('.doc-example-live li:first a:contains("clear")').click(); - expect(element('.doc-example-live li:first input').val()).toBe(''); - element('.doc-example-live li:last a:contains("add")').click(); - expect(element('.doc-example-live li[ng\\:repeat-index="2"] input').val()).toBe('yourname@example.org'); - }); + <doc:example> + <doc:source> + <script type="text/javascript"> + function SettingsController() { + this.name = "John Smith"; + this.contacts = [ + {type:'phone', value:'408 555 1212'}, + {type:'email', value:'john.smith@example.org'} ]; + } + SettingsController.prototype = { + greet: function(){ + alert(this.name); + }, + addContact: function(){ + this.contacts.push({type:'email', value:'yourname@example.org'}); + }, + removeContact: function(contactToRemove) { + angular.Array.remove(this.contacts, contactToRemove); + }, + clearContact: function(contact) { + contact.type = 'phone'; + contact.value = ''; + } + }; + </script> + <div ng:controller="SettingsController"> + Name: <input type="text" name="name"/> + [ <a href="" ng:click="greet()">greet</a> ]<br/> + Contact: + <ul> + <li ng:repeat="contact in contacts"> + <select name="contact.type"> + <option>phone</option> + <option>email</option> + </select> + <input type="text" name="contact.value"/> + [ <a href="" ng:click="clearContact(contact)">clear</a> + | <a href="" ng:click="removeContact(contact)">X</a> ] + </li> + <li>[ <a href="" ng:click="addContact()">add</a> ]</li> + </ul> + </div> + </doc:source> + <doc:scenario> + it('should check controller', function(){ + expect(element('.doc-example-live div>:input').val()).toBe('John Smith'); + expect(element('.doc-example-live li[ng\\:repeat-index="0"] input').val()).toBe('408 555 1212'); + expect(element('.doc-example-live li[ng\\:repeat-index="1"] input').val()).toBe('john.smith@example.org'); + element('.doc-example-live li:first a:contains("clear")').click(); + expect(element('.doc-example-live li:first input').val()).toBe(''); + element('.doc-example-live li:last a:contains("add")').click(); + expect(element('.doc-example-live li[ng\\:repeat-index="2"] input').val()).toBe('yourname@example.org'); + }); + </doc:scenario> + </doc:example> */ angularDirective("ng:controller", function(expression){ this.scope(true); @@ -112,36 +120,38 @@ angularDirective("ng:controller", function(expression){ * @name angular.directive.ng:eval * * @description - * The `ng:eval` allows you to execute a binding which has side effects + * The `ng:eval` allows you to execute a binding which has side effects * without displaying the result to the user. * * @element ANY * @param {expression} expression to eval. * - * @exampleDescription - * Notice that `{{` `obj.multiplied = obj.a * obj.b` `}}` has a side effect of assigning - * a value to `obj.multiplied` and displaying the result to the user. Sometimes, - * however, it is desirable to execute a side effect without showing the value to - * the user. In such a case `ng:eval` allows you to execute code without updating - * the display. - * * @example - * <input name="obj.a" value="6" > - * * <input name="obj.b" value="2"> - * = {{obj.multiplied = obj.a * obj.b}} <br> - * <span ng:eval="obj.divide = obj.a / obj.b"></span> - * <span ng:eval="obj.updateCount = 1 + (obj.updateCount||0)"></span> - * <tt>obj.divide = {{obj.divide}}</tt><br/> - * <tt>obj.updateCount = {{obj.updateCount}}</tt> - * - * @scenario - it('should check eval', function(){ - expect(binding('obj.divide')).toBe('3'); - expect(binding('obj.updateCount')).toBe('2'); - input('obj.a').enter('12'); - expect(binding('obj.divide')).toBe('6'); - expect(binding('obj.updateCount')).toBe('3'); - }); + * Notice that `{{` `obj.multiplied = obj.a * obj.b` `}}` has a side effect of assigning + * a value to `obj.multiplied` and displaying the result to the user. Sometimes, + * however, it is desirable to execute a side effect without showing the value to + * the user. In such a case `ng:eval` allows you to execute code without updating + * the display. + <doc:example> + <doc:source> + <input name="obj.a" value="6" > + * <input name="obj.b" value="2"> + = {{obj.multiplied = obj.a * obj.b}} <br> + <span ng:eval="obj.divide = obj.a / obj.b"></span> + <span ng:eval="obj.updateCount = 1 + (obj.updateCount||0)"></span> + <tt>obj.divide = {{obj.divide}}</tt><br/> + <tt>obj.updateCount = {{obj.updateCount}}</tt> + </doc:source> + <doc:scenario> + it('should check eval', function(){ + expect(binding('obj.divide')).toBe('3'); + expect(binding('obj.updateCount')).toBe('2'); + input('obj.a').enter('12'); + expect(binding('obj.divide')).toBe('6'); + expect(binding('obj.updateCount')).toBe('3'); + }); + </doc:scenario> + </doc:example> */ angularDirective("ng:eval", function(expression){ return function(element){ @@ -155,27 +165,30 @@ angularDirective("ng:eval", function(expression){ * @name angular.directive.ng:bind * * @description - * The `ng:bind` attribute asks <angular/> to replace the text content of this - * HTML element with the value of the given expression and kept it up to - * date when the expression's value changes. Usually you just write - * {{expression}} and let <angular/> compile it into + * The `ng:bind` attribute asks <angular/> to replace the text content of this + * HTML element with the value of the given expression and kept it up to + * date when the expression's value changes. Usually you just write + * {{expression}} and let <angular/> compile it into * `<span ng:bind="expression"></span>` at bootstrap time. - * + * * @element ANY * @param {expression} expression to eval. * - * @exampleDescription - * Try it here: enter text in text box and watch the greeting change. * @example - * Enter name: <input type="text" name="name" value="Whirled">. <br> - * Hello <span ng:bind="name" />! - * - * @scenario - it('should check ng:bind', function(){ - expect(using('.doc-example-live').binding('name')).toBe('Whirled'); - using('.doc-example-live').input('name').enter('world'); - expect(using('.doc-example-live').binding('name')).toBe('world'); - }); + * Try it here: enter text in text box and watch the greeting change. + <doc:example> + <doc:source> + Enter name: <input type="text" name="name" value="Whirled">. <br> + Hello <span ng:bind="name" />! + </doc:source> + <doc:scenario> + it('should check ng:bind', function(){ + expect(using('.doc-example-live').binding('name')).toBe('Whirled'); + using('.doc-example-live').input('name').enter('world'); + expect(using('.doc-example-live').binding('name')).toBe('world'); + }); + </doc:scenario> + </doc:example> */ angularDirective("ng:bind", function(expression, element){ element.addClass('ng-binding'); @@ -259,32 +272,35 @@ function compileBindTemplate(template){ * @name angular.directive.ng:bind-template * * @description - * The `ng:bind-template` attribute specifies that the element - * text should be replaced with the template in ng:bind-template. - * Unlike ng:bind the ng:bind-template can contain multiple `{{` `}}` - * expressions. (This is required since some HTML elements + * The `ng:bind-template` attribute specifies that the element + * text should be replaced with the template in ng:bind-template. + * Unlike ng:bind the ng:bind-template can contain multiple `{{` `}}` + * expressions. (This is required since some HTML elements * can not have SPAN elements such as TITLE, or OPTION to name a few. - * + * * @element ANY * @param {string} template of form * <tt>{{</tt> <tt>expression</tt> <tt>}}</tt> to eval. * - * @exampleDescription - * Try it here: enter text in text box and watch the greeting change. * @example - Salutation: <input type="text" name="salutation" value="Hello"><br/> - Name: <input type="text" name="name" value="World"><br/> - <pre ng:bind-template="{{salutation}} {{name}}!"></pre> - * - * @scenario - it('should check ng:bind', function(){ - expect(using('.doc-example-live').binding('{{salutation}} {{name}}')). - toBe('Hello World!'); - using('.doc-example-live').input('salutation').enter('Greetings'); - using('.doc-example-live').input('name').enter('user'); - expect(using('.doc-example-live').binding('{{salutation}} {{name}}')). - toBe('Greetings user!'); - }); + * Try it here: enter text in text box and watch the greeting change. + <doc:example> + <doc:source> + Salutation: <input type="text" name="salutation" value="Hello"><br/> + Name: <input type="text" name="name" value="World"><br/> + <pre ng:bind-template="{{salutation}} {{name}}!"></pre> + </doc:source> + <doc:scenario> + it('should check ng:bind', function(){ + expect(using('.doc-example-live').binding('{{salutation}} {{name}}')). + toBe('Hello World!'); + using('.doc-example-live').input('salutation').enter('Greetings'); + using('.doc-example-live').input('name').enter('user'); + expect(using('.doc-example-live').binding('{{salutation}} {{name}}')). + toBe('Greetings user!'); + }); + </doc:scenario> + </doc:example> */ angularDirective("ng:bind-template", function(expression, element){ element.addClass('ng-binding'); @@ -313,49 +329,52 @@ var REMOVE_ATTRIBUTES = { * @name angular.directive.ng:bind-attr * * @description - * The `ng:bind-attr` attribute specifies that the element attributes - * which should be replaced by the expression in it. Unlike `ng:bind` - * the `ng:bind-attr` contains a JSON key value pairs representing - * which attributes need to be changed. You don’t usually write the - * `ng:bind-attr` in the HTML since embedding - * <tt ng:non-bindable>{{expression}}</tt> into the + * The `ng:bind-attr` attribute specifies that the element attributes + * which should be replaced by the expression in it. Unlike `ng:bind` + * the `ng:bind-attr` contains a JSON key value pairs representing + * which attributes need to be changed. You don’t usually write the + * `ng:bind-attr` in the HTML since embedding + * <tt ng:non-bindable>{{expression}}</tt> into the * attribute directly is the preferred way. The attributes get * translated into `<span ng:bind-attr="{attr:expression}"/>` at * bootstrap time. - * + * * This HTML snippet is preferred way of working with `ng:bind-attr` * <pre> * <a href="http://www.google.com/search?q={{query}}">Google</a> * </pre> - * + * * The above gets translated to bellow during bootstrap time. * <pre> * <a ng:bind-attr='{"href":"http://www.google.com/search?q={{query}}"}'>Google</a> * </pre> - * + * * @element ANY - * @param {string} attribute_json a JSON key-value pairs representing - * the attributes to replace. Each key matches the attribute - * which needs to be replaced. Each value is a text template of - * the attribute with embedded - * <tt ng:non-bindable>{{expression}}</tt>s. Any number of + * @param {string} attribute_json a JSON key-value pairs representing + * the attributes to replace. Each key matches the attribute + * which needs to be replaced. Each value is a text template of + * the attribute with embedded + * <tt ng:non-bindable>{{expression}}</tt>s. Any number of * key-value pairs can be specified. * - * @exampleDescription - * Try it here: enter text in text box and click Google. * @example - Google for: - <input type="text" name="query" value="AngularJS"/> - <a href="http://www.google.com/search?q={{query}}">Google</a> - * - * @scenario - it('should check ng:bind-attr', function(){ - expect(using('.doc-example-live').element('a').attr('href')). - toBe('http://www.google.com/search?q=AngularJS'); - using('.doc-example-live').input('query').enter('google'); - expect(using('.doc-example-live').element('a').attr('href')). - toBe('http://www.google.com/search?q=google'); - }); + * Try it here: enter text in text box and click Google. + <doc:example> + <doc:source> + Google for: + <input type="text" name="query" value="AngularJS"/> + <a href="http://www.google.com/search?q={{query}}">Google</a> + </doc:source> + <doc:scenario> + it('should check ng:bind-attr', function(){ + expect(using('.doc-example-live').element('a').attr('href')). + toBe('http://www.google.com/search?q=AngularJS'); + using('.doc-example-live').input('query').enter('google'); + expect(using('.doc-example-live').element('a').attr('href')). + toBe('http://www.google.com/search?q=google'); + }); + </doc:scenario> + </doc:example> */ angularDirective("ng:bind-attr", function(expression){ return function(element){ @@ -396,23 +415,28 @@ angularDirective("ng:bind-attr", function(expression){ * @name angular.directive.ng:click * * @description - * The ng:click allows you to specify custom behavior when + * The ng:click allows you to specify custom behavior when * element is clicked. - * + * * @element ANY * @param {expression} expression to eval upon click. * * @example - <button ng:click="count = count + 1" ng:init="count=0"> - Increment - </button> - count: {{count}} - * @scenario - it('should check ng:click', function(){ - expect(binding('count')).toBe('0'); - element('.doc-example-live :button').click(); - expect(binding('count')).toBe('1'); - }); + <doc:example> + <doc:source> + <button ng:click="count = count + 1" ng:init="count=0"> + Increment + </button> + count: {{count}} + </doc:source> + <doc:scenario> + it('should check ng:click', function(){ + expect(binding('count')).toBe('0'); + element('.doc-example-live :button').click(); + expect(binding('count')).toBe('1'); + }); + </doc:scenario> + </doc:example> */ /* * A directive that allows creation of custom onclick handlers that are defined as angular @@ -440,35 +464,37 @@ angularDirective("ng:click", function(expression, element){ * @name angular.directive.ng:submit * * @description - * - * @element form - * @param {expression} expression to eval. - * - * @exampleDescription - * @example - * <form ng:submit="list.push(text);text='';" ng:init="list=[]"> - * Enter text and hit enter: - * <input type="text" name="text" value="hello"/> - * </form> - * <pre>list={{list}}</pre> - * @scenario - it('should check ng:submit', function(){ - expect(binding('list')).toBe('list=[]'); - element('.doc-example-live form input').click(); - this.addFutureAction('submit from', function($window, $document, done) { - $window.angular.element( - $document.elements('.doc-example-live form')). - trigger('submit'); - done(); - }); - expect(binding('list')).toBe('list=["hello"]'); - }); - */ -/** * Enables binding angular expressions to onsubmit events. * * Additionally it prevents the default action (which for form means sending the request to the * server and reloading the current page). + * + * @element form + * @param {expression} expression to eval. + * + * @example + <doc:example> + <doc:source> + <form ng:submit="list.push(text);text='';" ng:init="list=[]"> + Enter text and hit enter: + <input type="text" name="text" value="hello"/> + </form> + <pre>list={{list}}</pre> + </doc:source> + <doc:scenario> + it('should check ng:submit', function(){ + expect(binding('list')).toBe('list=[]'); + element('.doc-example-live form input').click(); + this.addFutureAction('submit from', function($window, $document, done) { + $window.angular.element( + $document.elements('.doc-example-live form')). + trigger('submit'); + done(); + }); + expect(binding('list')).toBe('list=["hello"]'); + }); + </doc:scenario> + </doc:example> */ angularDirective("ng:submit", function(expression, element) { return injectUpdateView(function($updateView, element) { @@ -488,26 +514,30 @@ angularDirective("ng:submit", function(expression, element) { * @name angular.directive.ng:watch * * @description - * The `ng:watch` allows you watch a variable and then execute + * The `ng:watch` allows you watch a variable and then execute * an evaluation on variable change. - * + * * @element ANY * @param {expression} expression to eval. * - * @exampleDescription - * Notice that the counter is incremented - * every time you change the text. * @example - <div ng:init="counter=0" ng:watch="name: counter = counter+1"> - <input type="text" name="name" value="hello"><br/> - Change counter: {{counter}} Name: {{name}} - </div> - * @scenario - it('should check ng:watch', function(){ - expect(using('.doc-example-live').binding('counter')).toBe('2'); - using('.doc-example-live').input('name').enter('abc'); - expect(using('.doc-example-live').binding('counter')).toBe('3'); - }); + * Notice that the counter is incremented + * every time you change the text. + <doc:example> + <doc:source> + <div ng:init="counter=0" ng:watch="name: counter = counter+1"> + <input type="text" name="name" value="hello"><br/> + Change counter: {{counter}} Name: {{name}} + </div> + </doc:source> + <doc:scenario> + it('should check ng:watch', function(){ + expect(using('.doc-example-live').binding('counter')).toBe('2'); + using('.doc-example-live').input('name').enter('abc'); + expect(using('.doc-example-live').binding('counter')).toBe('3'); + }); + </doc:scenario> + </doc:example> */ //TODO: delete me, since having watch in UI is logic in UI. (leftover form getangular) angularDirective("ng:watch", function(expression, element){ @@ -544,34 +574,37 @@ function ngClass(selector) { * @name angular.directive.ng:class * * @description - * The `ng:class` allows you to set CSS class on HTML element + * The `ng:class` allows you to set CSS class on HTML element * conditionally. - * + * * @element ANY * @param {expression} expression to eval. * - * @exampleDescription * @example - <input type="button" value="set" ng:click="myVar='ng-input-indicator-wait'"> - <input type="button" value="clear" ng:click="myVar=''"> - <br> - <span ng:class="myVar">Sample Text </span> - * - * @scenario - it('should check ng:class', function(){ - expect(element('.doc-example-live span').attr('className')).not(). - toMatch(/ng-input-indicator-wait/); + <doc:example> + <doc:source> + <input type="button" value="set" ng:click="myVar='ng-input-indicator-wait'"> + <input type="button" value="clear" ng:click="myVar=''"> + <br> + <span ng:class="myVar">Sample Text </span> + </doc:source> + <doc:scenario> + it('should check ng:class', function(){ + expect(element('.doc-example-live span').attr('className')).not(). + toMatch(/ng-input-indicator-wait/); + + using('.doc-example-live').element(':button:first').click(); - using('.doc-example-live').element(':button:first').click(); + expect(element('.doc-example-live span').attr('className')). + toMatch(/ng-input-indicator-wait/); - expect(element('.doc-example-live span').attr('className')). - toMatch(/ng-input-indicator-wait/); + using('.doc-example-live').element(':button:last').click(); - using('.doc-example-live').element(':button:last').click(); - - expect(element('.doc-example-live span').attr('className')).not(). - toMatch(/ng-input-indicator-wait/); - }); + expect(element('.doc-example-live span').attr('className')).not(). + toMatch(/ng-input-indicator-wait/); + }); + </doc:scenario> + </doc:example> */ angularDirective("ng:class", ngClass(function(){return true;})); @@ -581,33 +614,35 @@ angularDirective("ng:class", ngClass(function(){return true;})); * @name angular.directive.ng:class-odd * * @description - * The `ng:class-odd` and `ng:class-even` works exactly as - * `ng:class`, except it works in conjunction with `ng:repeat` + * The `ng:class-odd` and `ng:class-even` works exactly as + * `ng:class`, except it works in conjunction with `ng:repeat` * and takes affect only on odd (even) rows. * * @element ANY - * @param {expression} expression to eval. Must be inside + * @param {expression} expression to eval. Must be inside * `ng:repeat`. - * - * @exampleDescription * @example - <ol ng:init="names=['John', 'Mary', 'Cate', 'Suz']"> - <li ng:repeat="name in names"> - <span ng:class-odd="'ng-format-negative'" - ng:class-even="'ng-input-indicator-wait'"> - {{name}} - </span> - </li> - </ol> - * - * @scenario - it('should check ng:class-odd and ng:class-even', function(){ - expect(element('.doc-example-live li:first span').attr('className')). - toMatch(/ng-format-negative/); - expect(element('.doc-example-live li:last span').attr('className')). - toMatch(/ng-input-indicator-wait/); - }); + <doc:example> + <doc:source> + <ol ng:init="names=['John', 'Mary', 'Cate', 'Suz']"> + <li ng:repeat="name in names"> + <span ng:class-odd="'ng-format-negative'" + ng:class-even="'ng-input-indicator-wait'"> + {{name}} + </span> + </li> + </ol> + </doc:source> + <doc:scenario> + it('should check ng:class-odd and ng:class-even', function(){ + expect(element('.doc-example-live li:first span').attr('className')). + toMatch(/ng-format-negative/); + expect(element('.doc-example-live li:last span').attr('className')). + toMatch(/ng-input-indicator-wait/); + }); + </doc:scenario> + </doc:example> */ angularDirective("ng:class-odd", ngClass(function(i){return i % 2 === 0;})); @@ -617,33 +652,35 @@ angularDirective("ng:class-odd", ngClass(function(i){return i % 2 === 0;})); * @name angular.directive.ng:class-even * * @description - * The `ng:class-odd` and `ng:class-even` works exactly as - * `ng:class`, except it works in conjunction with `ng:repeat` + * The `ng:class-odd` and `ng:class-even` works exactly as + * `ng:class`, except it works in conjunction with `ng:repeat` * and takes affect only on odd (even) rows. * * @element ANY - * @param {expression} expression to eval. Must be inside + * @param {expression} expression to eval. Must be inside * `ng:repeat`. - * - * @exampleDescription * @example - <ol ng:init="names=['John', 'Mary', 'Cate', 'Suz']"> - <li ng:repeat="name in names"> - <span ng:class-odd="'ng-format-negative'" - ng:class-even="'ng-input-indicator-wait'"> - {{name}} - </span> - </li> - </ol> - * - * @scenario - it('should check ng:class-odd and ng:class-even', function(){ - expect(element('.doc-example-live li:first span').attr('className')). - toMatch(/ng-format-negative/); - expect(element('.doc-example-live li:last span').attr('className')). - toMatch(/ng-input-indicator-wait/); - }); + <doc:example> + <doc:source> + <ol ng:init="names=['John', 'Mary', 'Cate', 'Suz']"> + <li ng:repeat="name in names"> + <span ng:class-odd="'ng-format-negative'" + ng:class-even="'ng-input-indicator-wait'"> + {{name}} + </span> + </li> + </ol> + </doc:source> + <doc:scenario> + it('should check ng:class-odd and ng:class-even', function(){ + expect(element('.doc-example-live li:first span').attr('className')). + toMatch(/ng-format-negative/); + expect(element('.doc-example-live li:last span').attr('className')). + toMatch(/ng-input-indicator-wait/); + }); + </doc:scenario> + </doc:example> */ angularDirective("ng:class-even", ngClass(function(i){return i % 2 === 1;})); @@ -655,27 +692,30 @@ angularDirective("ng:class-even", ngClass(function(i){return i % 2 === 1;})); * @description * The `ng:show` and `ng:hide` allows you to show or hide a portion * of the HTML conditionally. - * + * * @element ANY - * @param {expression} expression if truthy then the element is + * @param {expression} expression if truthy then the element is * shown or hidden respectively. * - * @exampleDescription * @example - Click me: <input type="checkbox" name="checked"><br/> - Show: <span ng:show="checked">I show up when you checkbox is checked?</span> <br/> - Hide: <span ng:hide="checked">I hide when you checkbox is checked?</span> - * - * @scenario - it('should check ng:show / ng:hide', function(){ - expect(element('.doc-example-live span:first:hidden').count()).toEqual(1); - expect(element('.doc-example-live span:last:visible').count()).toEqual(1); - - input('checked').check(); - - expect(element('.doc-example-live span:first:visible').count()).toEqual(1); - expect(element('.doc-example-live span:last:hidden').count()).toEqual(1); - }); + <doc:example> + <doc:source> + Click me: <input type="checkbox" name="checked"><br/> + Show: <span ng:show="checked">I show up when you checkbox is checked?</span> <br/> + Hide: <span ng:hide="checked">I hide when you checkbox is checked?</span> + </doc:source> + <doc:scenario> + it('should check ng:show / ng:hide', function(){ + expect(element('.doc-example-live span:first:hidden').count()).toEqual(1); + expect(element('.doc-example-live span:last:visible').count()).toEqual(1); + + input('checked').check(); + + expect(element('.doc-example-live span:first:visible').count()).toEqual(1); + expect(element('.doc-example-live span:last:hidden').count()).toEqual(1); + }); + </doc:scenario> + </doc:example> */ angularDirective("ng:show", function(expression, element){ return function(element){ @@ -693,27 +733,30 @@ angularDirective("ng:show", function(expression, element){ * @description * The `ng:show` and `ng:hide` allows you to show or hide a portion * of the HTML conditionally. - * + * * @element ANY - * @param {expression} expression if truthy then the element is + * @param {expression} expression if truthy then the element is * shown or hidden respectively. * - * @exampleDescription * @example - Click me: <input type="checkbox" name="checked"><br/> - Show: <span ng:show="checked">I show up when you checkbox is checked?</span> <br/> - Hide: <span ng:hide="checked">I hide when you checkbox is checked?</span> - * - * @scenario - it('should check ng:show / ng:hide', function(){ - expect(element('.doc-example-live span:first:hidden').count()).toEqual(1); - expect(element('.doc-example-live span:last:visible').count()).toEqual(1); - - input('checked').check(); - - expect(element('.doc-example-live span:first:visible').count()).toEqual(1); - expect(element('.doc-example-live span:last:hidden').count()).toEqual(1); - }); + <doc:example> + <doc:source> + Click me: <input type="checkbox" name="checked"><br/> + Show: <span ng:show="checked">I show up when you checkbox is checked?</span> <br/> + Hide: <span ng:hide="checked">I hide when you checkbox is checked?</span> + </doc:source> + <doc:scenario> + it('should check ng:show / ng:hide', function(){ + expect(element('.doc-example-live span:first:hidden').count()).toEqual(1); + expect(element('.doc-example-live span:last:visible').count()).toEqual(1); + + input('checked').check(); + + expect(element('.doc-example-live span:first:visible').count()).toEqual(1); + expect(element('.doc-example-live span:last:hidden').count()).toEqual(1); + }); + </doc:scenario> + </doc:example> */ angularDirective("ng:hide", function(expression, element){ return function(element){ @@ -730,28 +773,31 @@ angularDirective("ng:hide", function(expression, element){ * * @description * The ng:style allows you to set CSS style on an HTML element conditionally. - * + * * @element ANY - * @param {expression} expression which evals to an object whes key's are - * CSS style names and values are coresponding values for those + * @param {expression} expression which evals to an object whes key's are + * CSS style names and values are coresponding values for those * CSS keys. * - * @exampleDescription * @example - <input type="button" value="set" ng:click="myStyle={color:'red'}"> - <input type="button" value="clear" ng:click="myStyle={}"> - <br/> - <span ng:style="myStyle">Sample Text</span> - <pre>myStyle={{myStyle}}</pre> - * - * @scenario - it('should check ng:style', function(){ - expect(element('.doc-example-live span').css('color')).toBe('rgb(0, 0, 0)'); - element('.doc-example-live :button[value=set]').click(); - expect(element('.doc-example-live span').css('color')).toBe('red'); - element('.doc-example-live :button[value=clear]').click(); - expect(element('.doc-example-live span').css('color')).toBe('rgb(0, 0, 0)'); - }); + <doc:example> + <doc:source> + <input type="button" value="set" ng:click="myStyle={color:'red'}"> + <input type="button" value="clear" ng:click="myStyle={}"> + <br/> + <span ng:style="myStyle">Sample Text</span> + <pre>myStyle={{myStyle}}</pre> + </doc:source> + <doc:scenario> + it('should check ng:style', function(){ + expect(element('.doc-example-live span').css('color')).toBe('rgb(0, 0, 0)'); + element('.doc-example-live :button[value=set]').click(); + expect(element('.doc-example-live span').css('color')).toBe('red'); + element('.doc-example-live :button[value=clear]').click(); + expect(element('.doc-example-live span').css('color')).toBe('rgb(0, 0, 0)'); + }); + </doc:scenario> + </doc:example> */ angularDirective("ng:style", function(expression, element){ return function(element){ diff --git a/src/filters.js b/src/filters.js index 7fa7926d..0f6121ec 100644 --- a/src/filters.js +++ b/src/filters.js @@ -14,19 +14,23 @@ * When the value is negative, this css class is applied to the binding making it by default red. * * @example - <input type="text" name="amount" value="1234.56"/> <br/> - {{amount | currency}} - * - * @scenario - it('should init with 1234.56', function(){ - expect(binding('amount | currency')).toBe('$1,234.56'); - }); - it('should update', function(){ - input('amount').enter('-1234'); - expect(binding('amount | currency')).toBe('$-1,234.00'); - expect(element('.doc-example-live .ng-binding').attr('className')). - toMatch(/ng-format-negative/); - }); + <doc:example> + <doc:source> + <input type="text" name="amount" value="1234.56"/> <br/> + {{amount | currency}} + </doc:source> + <doc:scenario> + it('should init with 1234.56', function(){ + expect(binding('amount | currency')).toBe('$1,234.56'); + }); + it('should update', function(){ + input('amount').enter('-1234'); + expect(binding('amount | currency')).toBe('$-1,234.00'); + expect(element('.doc-example-live .ng-binding').attr('className')). + toMatch(/ng-format-negative/); + }); + </doc:scenario> + </doc:example> */ angularFilter.currency = function(amount){ this.$element.toggleClass('ng-format-negative', amount < 0); @@ -49,24 +53,28 @@ angularFilter.currency = function(amount){ * @returns {string} Number rounded to decimalPlaces and places a “,” after each third digit. * * @example - Enter number: <input name='val' value='1234.56789' /><br/> - Default formatting: {{val | number}}<br/> - No fractions: {{val | number:0}}<br/> - Negative number: {{-val | number:4}} - - * @scenario - it('should format numbers', function(){ - expect(binding('val | number')).toBe('1,234.57'); - expect(binding('val | number:0')).toBe('1,235'); - expect(binding('-val | number:4')).toBe('-1,234.5679'); - }); - - it('should update', function(){ - input('val').enter('3374.333'); - expect(binding('val | number')).toBe('3,374.33'); - expect(binding('val | number:0')).toBe('3,374'); - expect(binding('-val | number:4')).toBe('-3,374.3330'); - }); + <doc:example> + <doc:source> + Enter number: <input name='val' value='1234.56789' /><br/> + Default formatting: {{val | number}}<br/> + No fractions: {{val | number:0}}<br/> + Negative number: {{-val | number:4}} + </doc:source> + <doc:scenario> + it('should format numbers', function(){ + expect(binding('val | number')).toBe('1,234.57'); + expect(binding('val | number:0')).toBe('1,235'); + expect(binding('-val | number:4')).toBe('-1,234.5679'); + }); + + it('should update', function(){ + input('val').enter('3374.333'); + expect(binding('val | number')).toBe('3,374.33'); + expect(binding('val | number:0')).toBe('3,374'); + expect(binding('-val | number:4')).toBe('-3,374.3330'); + }); + </doc:scenario> + </doc:example> */ angularFilter.number = function(number, fractionSize){ if (isNaN(number) || !isFinite(number)) { @@ -183,19 +191,22 @@ var NUMBER_STRING = /^\d+$/; * @returns {string} Formatted string or the input if input is not recognized as date/millis. * * @example - <span ng:non-bindable>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span>: - {{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}<br/> - <span ng:non-bindable>{{1288323623006 | date:'MM/dd/yyyy @ h:mma'}}</span>: - {{'1288323623006' | date:'MM/dd/yyyy @ h:mma'}}<br/> - * - * @scenario - it('should format date', function(){ - expect(binding("1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'")). - toMatch(/2010\-10\-2\d \d{2}:\d{2}:\d{2} \-?\d{4}/); - expect(binding("'1288323623006' | date:'MM/dd/yyyy @ h:mma'")). - toMatch(/10\/2\d\/2010 @ \d{1,2}:\d{2}(am|pm)/); - }); - * + <doc:example> + <doc:source> + <span ng:non-bindable>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span>: + {{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}<br/> + <span ng:non-bindable>{{1288323623006 | date:'MM/dd/yyyy @ h:mma'}}</span>: + {{'1288323623006' | date:'MM/dd/yyyy @ h:mma'}}<br/> + </doc:source> + <doc:scenario> + it('should format date', function(){ + expect(binding("1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'")). + toMatch(/2010\-10\-2\d \d{2}:\d{2}:\d{2} \-?\d{4}/); + expect(binding("'1288323623006' | date:'MM/dd/yyyy @ h:mma'")). + toMatch(/10\/2\d\/2010 @ \d{1,2}:\d{2}(am|pm)/); + }); + </doc:scenario> + </doc:example> */ angularFilter.date = function(date, format) { if (isString(date)) { @@ -255,19 +266,23 @@ angularFilter.date = function(date, format) { * @css ng-monospace Always applied to the encapsulating element. * * @example: - <input type="text" name="objTxt" value="{a:1, b:[]}" - ng:eval="obj = $eval(objTxt)"/> - <pre>{{ obj | json }}</pre> - * - * @scenario - it('should jsonify filtered objects', function() { - expect(binding('obj | json')).toBe('{\n "a":1,\n "b":[]}'); - }); - - it('should update', function() { - input('objTxt').enter('[1, 2, 3]'); - expect(binding('obj | json')).toBe('[1,2,3]'); - }); + <doc:example> + <doc:source> + <input type="text" name="objTxt" value="{a:1, b:[]}" + ng:eval="obj = $eval(objTxt)"/> + <pre>{{ obj | json }}</pre> + </doc:source> + <doc:scenario> + it('should jsonify filtered objects', function() { + expect(binding('obj | json')).toBe('{\n "a":1,\n "b":[]}'); + }); + + it('should update', function() { + input('objTxt').enter('[1, 2, 3]'); + expect(binding('obj | json')).toBe('[1,2,3]'); + }); + </doc:scenario> + </doc:example> * */ angularFilter.json = function(object) { @@ -324,63 +339,67 @@ angularFilter.uppercase = uppercase; * @returns {string} Sanitized or raw html. * * @example - Snippet: <textarea name="snippet" cols="60" rows="3"> + <doc:example> + <doc:source> + Snippet: <textarea name="snippet" cols="60" rows="3"> <p style="color:blue">an html <em onmouseover="this.textContent='PWN3D!'">click here</em> snippet</p></textarea> - <table> - <tr> - <td>Filter</td> - <td>Source</td> - <td>Rendered</td> - </tr> - <tr id="html-filter"> - <td>html filter</td> - <td> - <pre><div ng:bind="snippet | html"><br/></div></pre> - </td> - <td> - <div ng:bind="snippet | html"></div> - </td> - </tr> - <tr id="escaped-html"> - <td>no filter</td> - <td><pre><div ng:bind="snippet"><br/></div></pre></td> - <td><div ng:bind="snippet"></div></td> - </tr> - <tr id="html-unsafe-filter"> - <td>unsafe html filter</td> - <td><pre><div ng:bind="snippet | html:'unsafe'"><br/></div></pre></td> - <td><div ng:bind="snippet | html:'unsafe'"></div></td> - </tr> - </table> - * - * @scenario - it('should sanitize the html snippet ', function(){ - expect(using('#html-filter').binding('snippet | html')). - toBe('<p>an html\n<em>click here</em>\nsnippet</p>'); - }); - - it ('should escape snippet without any filter', function() { - expect(using('#escaped-html').binding('snippet')). - toBe("<p style=\"color:blue\">an html\n" + - "<em onmouseover=\"this.textContent='PWN3D!'\">click here</em>\n" + - "snippet</p>"); - }); - - it ('should inline raw snippet if filtered as unsafe', function() { - expect(using('#html-unsafe-filter').binding("snippet | html:'unsafe'")). - toBe("<p style=\"color:blue\">an html\n" + - "<em onmouseover=\"this.textContent='PWN3D!'\">click here</em>\n" + - "snippet</p>"); - }); - - it('should update', function(){ - input('snippet').enter('new <b>text</b>'); - expect(using('#html-filter').binding('snippet | html')).toBe('new <b>text</b>'); - expect(using('#escaped-html').binding('snippet')).toBe("new <b>text</b>"); - expect(using('#html-unsafe-filter').binding("snippet | html:'unsafe'")).toBe('new <b>text</b>'); - }); + <table> + <tr> + <td>Filter</td> + <td>Source</td> + <td>Rendered</td> + </tr> + <tr id="html-filter"> + <td>html filter</td> + <td> + <pre><div ng:bind="snippet | html"><br/></div></pre> + </td> + <td> + <div ng:bind="snippet | html"></div> + </td> + </tr> + <tr id="escaped-html"> + <td>no filter</td> + <td><pre><div ng:bind="snippet"><br/></div></pre></td> + <td><div ng:bind="snippet"></div></td> + </tr> + <tr id="html-unsafe-filter"> + <td>unsafe html filter</td> + <td><pre><div ng:bind="snippet | html:'unsafe'"><br/></div></pre></td> + <td><div ng:bind="snippet | html:'unsafe'"></div></td> + </tr> + </table> + </doc:source> + <doc:scenario> + it('should sanitize the html snippet ', function(){ + expect(using('#html-filter').binding('snippet | html')). + toBe('<p>an html\n<em>click here</em>\nsnippet</p>'); + }); + + it('should escape snippet without any filter', function() { + expect(using('#escaped-html').binding('snippet')). + toBe("<p style=\"color:blue\">an html\n" + + "<em onmouseover=\"this.textContent='PWN3D!'\">click here</em>\n" + + "snippet</p>"); + }); + + it('should inline raw snippet if filtered as unsafe', function() { + expect(using('#html-unsafe-filter').binding("snippet | html:'unsafe'")). + toBe("<p style=\"color:blue\">an html\n" + + "<em onmouseover=\"this.textContent='PWN3D!'\">click here</em>\n" + + "snippet</p>"); + }); + + it('should update', function(){ + input('snippet').enter('new <b>text</b>'); + expect(using('#html-filter').binding('snippet | html')).toBe('new <b>text</b>'); + expect(using('#escaped-html').binding('snippet')).toBe("new <b>text</b>"); + expect(using('#html-unsafe-filter').binding("snippet | html:'unsafe'")).toBe('new <b>text</b>'); + }); + </doc:scenario> + </doc:example> */ angularFilter.html = function(html, option){ return new HTML(html, option); @@ -401,59 +420,63 @@ angularFilter.html = function(html, option){ * @returns {string} Html-linkified text. * * @example - Snippet: <textarea name="snippet" cols="60" rows="3"> -Pretty text with some links: -http://angularjs.org/, -mailto:us@somewhere.org, -another@somewhere.org, -and one more: ftp://127.0.0.1/.</textarea> - <table> - <tr> - <td>Filter</td> - <td>Source</td> - <td>Rendered</td> - </tr> - <tr id="linky-filter"> - <td>linky filter</td> - <td> - <pre><div ng:bind="snippet | linky"><br/></div></pre> - </td> - <td> - <div ng:bind="snippet | linky"></div> - </td> - </tr> - <tr id="escaped-html"> - <td>no filter</td> - <td><pre><div ng:bind="snippet"><br/></div></pre></td> - <td><div ng:bind="snippet"></div></td> - </tr> - </table> - - @scenario - it('should linkify the snippet with urls', function(){ - expect(using('#linky-filter').binding('snippet | linky')). - toBe('Pretty text with some links:\n' + - '<a href="http://angularjs.org/">http://angularjs.org/</a>,\n' + - '<a href="mailto:us@somewhere.org">us@somewhere.org</a>,\n' + - '<a href="mailto:another@somewhere.org">another@somewhere.org</a>,\n' + - 'and one more: <a href="ftp://127.0.0.1/">ftp://127.0.0.1/</a>.'); - }); - - it ('should not linkify snippet without the linky filter', function() { - expect(using('#escaped-html').binding('snippet')). - toBe("Pretty text with some links:\n" + - "http://angularjs.org/,\n" + - "mailto:us@somewhere.org,\n" + - "another@somewhere.org,\n" + - "and one more: ftp://127.0.0.1/."); - }); - - it('should update', function(){ - input('snippet').enter('new http://link.'); - expect(using('#linky-filter').binding('snippet | linky')). - toBe('new <a href="http://link">http://link</a>.'); - expect(using('#escaped-html').binding('snippet')).toBe('new http://link.'); - }); + <doc:example> + <doc:source> + Snippet: <textarea name="snippet" cols="60" rows="3"> + Pretty text with some links: + http://angularjs.org/, + mailto:us@somewhere.org, + another@somewhere.org, + and one more: ftp://127.0.0.1/.</textarea> + <table> + <tr> + <td>Filter</td> + <td>Source</td> + <td>Rendered</td> + </tr> + <tr id="linky-filter"> + <td>linky filter</td> + <td> + <pre><div ng:bind="snippet | linky"><br/></div></pre> + </td> + <td> + <div ng:bind="snippet | linky"></div> + </td> + </tr> + <tr id="escaped-html"> + <td>no filter</td> + <td><pre><div ng:bind="snippet"><br/></div></pre></td> + <td><div ng:bind="snippet"></div></td> + </tr> + </table> + </doc:source> + <doc:scenario> + it('should linkify the snippet with urls', function(){ + expect(using('#linky-filter').binding('snippet | linky')). + toBe('Pretty text with some links:\n' + + '<a href="http://angularjs.org/">http://angularjs.org/</a>,\n' + + '<a href="mailto:us@somewhere.org">us@somewhere.org</a>,\n' + + '<a href="mailto:another@somewhere.org">another@somewhere.org</a>,\n' + + 'and one more: <a href="ftp://127.0.0.1/">ftp://127.0.0.1/</a>.'); + }); + + it ('should not linkify snippet without the linky filter', function() { + expect(using('#escaped-html').binding('snippet')). + toBe("Pretty text with some links:\n" + + "http://angularjs.org/,\n" + + "mailto:us@somewhere.org,\n" + + "another@somewhere.org,\n" + + "and one more: ftp://127.0.0.1/."); + }); + + it('should update', function(){ + input('snippet').enter('new http://link.'); + expect(using('#linky-filter').binding('snippet | linky')). + toBe('new <a href="http://link">http://link</a>.'); + expect(using('#escaped-html').binding('snippet')).toBe('new http://link.'); + }); + </doc:scenario> + </doc:example> */ //TODO: externalize all regexps angularFilter.linky = function(text){ diff --git a/src/formatters.js b/src/formatters.js index e96e3634..d0fea46e 100644 --- a/src/formatters.js +++ b/src/formatters.js @@ -18,17 +18,21 @@ angularFormatter.noop = formatter(identity, identity); * @returns {?string} A JSON string representation of the model. * * @example - * <div ng:init="data={name:'misko', project:'angular'}"> - * <input type="text" size='50' name="data" ng:format="json"/> - * <pre>data={{data}}</pre> - * </div> - * - * @scenario - * it('should format json', function(){ - * expect(binding('data')).toEqual('data={\n \"name\":\"misko\",\n \"project\":\"angular\"}'); - * input('data').enter('{}'); - * expect(binding('data')).toEqual('data={\n }'); - * }); + <doc:example> + <doc:source> + <div ng:init="data={name:'misko', project:'angular'}"> + <input type="text" size='50' name="data" ng:format="json"/> + <pre>data={{data}}</pre> + </div> + </doc:source> + <doc:scenario> + it('should format json', function(){ + expect(binding('data')).toEqual('data={\n \"name\":\"misko\",\n \"project\":\"angular\"}'); + input('data').enter('{}'); + expect(binding('data')).toEqual('data={\n }'); + }); + </doc:scenario> + </doc:example> */ angularFormatter.json = formatter(toJson, function(value){ return fromJson(value || 'null'); @@ -45,17 +49,21 @@ angularFormatter.json = formatter(toJson, function(value){ * @returns {boolean} Converts to `true` unless user enters (blank), `f`, `false`, `0`, `no`, `[]`. * * @example - * Enter truthy text: - * <input type="text" name="value" ng:format="boolean" value="no"/> - * <input type="checkbox" name="value"/> - * <pre>value={{value}}</pre> - * - * @scenario - * it('should format boolean', function(){ - * expect(binding('value')).toEqual('value=false'); - * input('value').enter('truthy'); - * expect(binding('value')).toEqual('value=true'); - * }); + <doc:example> + <doc:source> + Enter truthy text: + <input type="text" name="value" ng:format="boolean" value="no"/> + <input type="checkbox" name="value"/> + <pre>value={{value}}</pre> + </doc:source> + <doc:scenario> + it('should format boolean', function(){ + expect(binding('value')).toEqual('value=false'); + input('value').enter('truthy'); + expect(binding('value')).toEqual('value=true'); + }); + </doc:scenario> + </doc:example> */ angularFormatter['boolean'] = formatter(toString, toBoolean); @@ -70,16 +78,20 @@ angularFormatter['boolean'] = formatter(toString, toBoolean); * @returns {number} Number from the parsed string. * * @example - * Enter valid number: - * <input type="text" name="value" ng:format="number" value="1234"/> - * <pre>value={{value}}</pre> - * - * @scenario - * it('should format numbers', function(){ - * expect(binding('value')).toEqual('value=1234'); - * input('value').enter('5678'); - * expect(binding('value')).toEqual('value=5678'); - * }); + <doc:example> + <doc:source> + Enter valid number: + <input type="text" name="value" ng:format="number" value="1234"/> + <pre>value={{value}}</pre> + </doc:source> + <doc:scenario> + it('should format numbers', function(){ + expect(binding('value')).toEqual('value=1234'); + input('value').enter('5678'); + expect(binding('value')).toEqual('value=5678'); + }); + </doc:scenario> + </doc:example> */ angularFormatter.number = formatter(toString, function(obj){ if (obj == _null || NUMBER.exec(obj)) { @@ -100,20 +112,24 @@ angularFormatter.number = formatter(toString, function(obj){ * @returns {Array} Array parsed from the entered string. * * @example - * Enter a list of items: - * <input type="text" name="value" ng:format="list" value=" chair ,, table"/> - * <input type="text" name="value" ng:format="list"/> - * <pre>value={{value}}</pre> - * - * @scenario - * it('should format lists', function(){ - * expect(binding('value')).toEqual('value=["chair","table"]'); - * this.addFutureAction('change to XYZ', function($window, $document, done){ - * $document.elements('.doc-example :input:last').val(',,a,b,').trigger('change'); - * done(); - * }); - * expect(binding('value')).toEqual('value=["a","b"]'); - * }); + <doc:example> + <doc:source> + Enter a list of items: + <input type="text" name="value" ng:format="list" value=" chair ,, table"/> + <input type="text" name="value" ng:format="list"/> + <pre>value={{value}}</pre> + </doc:source> + <doc:scenario> + it('should format lists', function(){ + expect(binding('value')).toEqual('value=["chair","table"]'); + this.addFutureAction('change to XYZ', function($window, $document, done){ + $document.elements('.doc-example :input:last').val(',,a,b,').trigger('change'); + done(); + }); + expect(binding('value')).toEqual('value=["a","b"]'); + }); + </doc:scenario> + </doc:example> */ angularFormatter.list = formatter( function(obj) { return obj ? obj.join(", ") : obj; }, @@ -138,20 +154,24 @@ angularFormatter.list = formatter( * @returns {String} Trim excess leading and trailing space. * * @example - * Enter text with leading/trailing spaces: - * <input type="text" name="value" ng:format="trim" value=" book "/> - * <input type="text" name="value" ng:format="trim"/> - * <pre>value={{value|json}}</pre> - * - * @scenario - * it('should format trim', function(){ - * expect(binding('value')).toEqual('value="book"'); - * this.addFutureAction('change to XYZ', function($window, $document, done){ - * $document.elements('.doc-example :input:last').val(' text ').trigger('change'); - * done(); - * }); - * expect(binding('value')).toEqual('value="text"'); - * }); + <doc:example> + <doc:source> + Enter text with leading/trailing spaces: + <input type="text" name="value" ng:format="trim" value=" book "/> + <input type="text" name="value" ng:format="trim"/> + <pre>value={{value|json}}</pre> + </doc:source> + <doc:scenario> + it('should format trim', function(){ + expect(binding('value')).toEqual('value="book"'); + this.addFutureAction('change to XYZ', function($window, $document, done){ + $document.elements('.doc-example :input:last').val(' text ').trigger('change'); + done(); + }); + expect(binding('value')).toEqual('value="text"'); + }); + </doc:scenario> + </doc:example> */ angularFormatter.trim = formatter( function(obj) { return obj ? trim("" + obj) : ""; } @@ -176,33 +196,36 @@ angularFormatter.trim = formatter( * @returns {object} object which is located at the selected position. * * @example - * <script> - * function DemoCntl(){ - * this.users = [ - * {name:'guest', password:'guest'}, - * {name:'user', password:'123'}, - * {name:'admin', password:'abc'} - * ]; - * } - * </script> - * <div ng:controller="DemoCntl"> - * User: - * <select name="currentUser" ng:format="index:users"> - * <option ng:repeat="user in users" value="{{$index}}">{{user.name}}</option> - * </select> - * <select name="currentUser" ng:format="index:users"> - * <option ng:repeat="user in users" value="{{$index}}">{{user.name}}</option> - * </select> - * user={{currentUser.name}}<br/> - * password={{currentUser.password}}<br/> - * </div> - * - * @scenario - * it('should retrieve object by index', function(){ - * expect(binding('currentUser.password')).toEqual('guest'); - * select('currentUser').option('2'); - * expect(binding('currentUser.password')).toEqual('abc'); - * }); + <doc:example> + <doc:source> + <script> + function DemoCntl(){ + this.users = [ + {name:'guest', password:'guest'}, + {name:'user', password:'123'}, + {name:'admin', password:'abc'} + ]; + } + </script> + <div ng:controller="DemoCntl"> + User: + <select name="currentUser" ng:format="index:users"> + <option ng:repeat="user in users" value="{{$index}}">{{user.name}}</option> + </select> + <select name="currentUser" ng:format="index:users"> + <option ng:repeat="user in users" value="{{$index}}">{{user.name}}</option> + </select> + user={{currentUser.name}}<br/> + password={{currentUser.password}}<br/> + </doc:source> + <doc:scenario> + it('should retrieve object by index', function(){ + expect(binding('currentUser.password')).toEqual('guest'); + select('currentUser').option('2'); + expect(binding('currentUser.password')).toEqual('abc'); + }); + </doc:scenario> + </doc:example> */ angularFormatter.index = formatter( function(object, array){ diff --git a/src/services.js b/src/services.js index 68860e22..f54234a6 100644 --- a/src/services.js +++ b/src/services.js @@ -22,8 +22,19 @@ function angularServiceInject(name, fn, inject, eager) { * suffer from window globality. * * @example +<<<<<<< HEAD <input ng:init="$window = $service('$window'); greeting='Hello World!'" type="text" name="greeting" /> <button ng:click="$window.alert(greeting)">ALERT</button> +======= + <doc:example> + <doc:source> + <input ng:init="greeting='Hello World!'" type="text" name="greeting" /> + <button ng:click="$window.alert(greeting)">ALERT</button> + </doc:source> + <doc:scenario> + </doc:scenario> + </doc:example> +>>>>>>> changed the documentation @example to use <doc:example> */ angularServiceInject("$window", bind(window, identity, window), [], EAGER); @@ -63,10 +74,16 @@ angularServiceInject("$document", function(window){ * Notice that using browser's forward/back buttons changes the $location. * * @example - <a href="#">clear hash</a> | - <a href="#myPath?name=misko">test hash</a><br/> - <input type='text' name="$location.hash"/> - <pre>$location = {{$location}}</pre> + <doc:example> + <doc:source> + <a href="#">clear hash</a> | + <a href="#myPath?name=misko">test hash</a><br/> + <input type='text' name="$location.hash"/> + <pre>$location = {{$location}}</pre> + </doc:source> + <doc:scenario> + </doc:scenario> + </doc:example> */ angularServiceInject("$location", function($browser) { var scope = this, @@ -98,9 +115,15 @@ angularServiceInject("$location", function($browser) { * Browser is updated at the end of $eval() * * @example - * scope.$location.update('http://www.angularjs.org/path#hash?search=x'); - * scope.$location.update({host: 'www.google.com', protocol: 'https'}); - * scope.$location.update({hashPath: '/path', hashSearch: {a: 'b', x: true}}); + <doc:example> + <doc:source> + scope.$location.update('http://www.angularjs.org/path#hash?search=x'); + scope.$location.update({host: 'www.google.com', protocol: 'https'}); + scope.$location.update({hashPath: '/path', hashSearch: {a: 'b', x: true}}); + </doc:source> + <doc:scenario> + </doc:scenario> + </doc:example> * * @param {(string|Object)} href Full href as a string or object with properties */ @@ -133,14 +156,18 @@ angularServiceInject("$location", function($browser) { * @see update() * * @example - * scope.$location.updateHash('/hp') - * ==> update({hashPath: '/hp'}) - * - * scope.$location.updateHash({a: true, b: 'val'}) - * ==> update({hashSearch: {a: true, b: 'val'}}) - * - * scope.$location.updateHash('/hp', {a: true}) - * ==> update({hashPath: '/hp', hashSearch: {a: true}}) + <doc:example> + <doc:source> + scope.$location.updateHash('/hp') + ==> update({hashPath: '/hp'}) + scope.$location.updateHash({a: true, b: 'val'}) + ==> update({hashSearch: {a: true, b: 'val'}}) + scope.$location.updateHash('/hp', {a: true}) + ==> update({hashPath: '/hp', hashSearch: {a: true}}) + </doc:source> + <doc:scenario> + </doc:scenario> + </doc:example> * * @param {(string|Object)} path A hashPath or hashSearch object * @param {Object=} search A hashSearch object @@ -176,7 +203,9 @@ angularServiceInject("$location", function($browser) { * - everything else * * @example - * scope.$location.href = 'http://www.angularjs.org/path#a/b' + * <pre> + * scope.$location.href = 'http://www.angularjs.org/path#a/b' + * </pre> * immediately after this call, other properties are still the old ones... * * This method checks the changes and update location to the consistent state @@ -298,13 +327,19 @@ angularServiceInject("$location", function($browser) { * The main purpose of this service is to simplify debugging and troubleshooting. * * @example - <p>Reload this page with open console, enter text and hit the log button...</p> - Message: - <input type="text" name="message" value="Hello World!"/> - <button ng:click="$log.log(message)">log</button> - <button ng:click="$log.warn(message)">warn</button> - <button ng:click="$log.info(message)">info</button> - <button ng:click="$log.error(message)">error</button> + <doc:example> + <doc:source> + <p>Reload this page with open console, enter text and hit the log button...</p> + Message: + <input type="text" name="message" value="Hello World!"/> + <button ng:click="$log.log(message)">log</button> + <button ng:click="$log.warn(message)">warn</button> + <button ng:click="$log.info(message)">info</button> + <button ng:click="$log.error(message)">error</button> + </doc:source> + <doc:scenario> + </doc:scenario> + </doc:example> */ var $logFactory; //reference to be used only in tests angularServiceInject("$log", $logFactory = function($window){ @@ -622,42 +657,46 @@ function switchRouteMatcher(on, when, dstName) { * widget. * * @example -<p> - This example shows how changing the URL hash causes the <tt>$route</tt> - to match a route against the URL, and the <tt>[[ng:include]]</tt> pulls in the partial. - Try changing the URL in the input box to see changes. -</p> - -<script> - angular.service('myApp', function($route) { - $route.when('/Book/:bookId', {template:'rsrc/book.html', controller:BookCntl}); - $route.when('/Book/:bookId/ch/:chapterId', {template:'rsrc/chapter.html', controller:ChapterCntl}); - $route.onChange(function() { - $route.current.scope.params = $route.current.params; - }); - }, {$inject: ['$route']}); - - function BookCntl() { - this.name = "BookCntl"; - } + This example shows how changing the URL hash causes the <tt>$route</tt> + to match a route against the URL, and the <tt>[[ng:include]]</tt> pulls in the partial. + Try changing the URL in the input box to see changes. + + <doc:example> + <doc:source> + <script> + angular.service('myApp', function($route) { + $route.when('/Book/:bookId', {template:'rsrc/book.html', controller:BookCntl}); + $route.when('/Book/:bookId/ch/:chapterId', {template:'rsrc/chapter.html', controller:ChapterCntl}); + $route.onChange(function() { + $route.current.scope.params = $route.current.params; + }); + }, {$inject: ['$route']}); + + function BookCntl() { + this.name = "BookCntl"; + } - function ChapterCntl() { - this.name = "ChapterCntl"; - } -</script> - -Chose: -<a href="#/Book/Moby">Moby</a> | -<a href="#/Book/Moby/ch/1">Moby: Ch1</a> | -<a href="#/Book/Gatsby">Gatsby</a> | -<a href="#/Book/Gatsby/ch/4?key=value">Gatsby: Ch4</a><br/> -<input type="text" name="$location.hashPath" size="80" /> -<pre>$location={{$location}}</pre> -<pre>$route.current.template={{$route.current.template}}</pre> -<pre>$route.current.params={{$route.current.params}}</pre> -<pre>$route.current.scope.name={{$route.current.scope.name}}</pre> -<hr/> -<ng:include src="$route.current.template" scope="$route.current.scope"/> + function ChapterCntl() { + this.name = "ChapterCntl"; + } + </script> + + Chose: + <a href="#/Book/Moby">Moby</a> | + <a href="#/Book/Moby/ch/1">Moby: Ch1</a> | + <a href="#/Book/Gatsby">Gatsby</a> | + <a href="#/Book/Gatsby/ch/4?key=value">Gatsby: Ch4</a><br/> + <input type="text" name="$location.hashPath" size="80" /> + <pre>$location={{$location}}</pre> + <pre>$route.current.template={{$route.current.template}}</pre> + <pre>$route.current.params={{$route.current.params}}</pre> + <pre>$route.current.scope.name={{$route.current.scope.name}}</pre> + <hr/> + <ng:include src="$route.current.template" scope="$route.current.scope"/> + </doc:source> + <doc:scenario> + </doc:scenario> + </doc:example> */ angularServiceInject('$route', function(location) { var routes = {}, @@ -1122,43 +1161,49 @@ angularServiceInject('$xhr.cache', function($xhr, $defer, $log){ * @returns {Object} A resource "class". * * @example - <script> - function BuzzController($resource) { - this.Activity = $resource( - 'https://www.googleapis.com/buzz/v1/activities/:userId/:visibility/:activityId/:comments', - {alt:'json', callback:'JSON_CALLBACK'}, - {get:{method:'JSON', params:{visibility:'@self'}}, replies: {method:'JSON', params:{visibility:'@self', comments:'@comments'}}} - ); - } - - BuzzController.prototype = { - fetch: function() { - this.activities = this.Activity.get({userId:this.userId}); - }, - expandReplies: function(activity) { - activity.replies = this.Activity.replies({userId:this.userId, activityId:activity.id}); - } - }; - BuzzController.$inject = ['$resource']; - </script> - - <div ng:controller="BuzzController"> - <input name="userId" value="googlebuzz"/> - <button ng:click="fetch()">fetch</button> - <hr/> - <div ng:repeat="item in activities.data.items"> - <h1 style="font-size: 15px;"> - <img src="{{item.actor.thumbnailUrl}}" style="max-height:30px;max-width:30px;"/> - <a href="{{item.actor.profileUrl}}">{{item.actor.name}}</a> - <a href ng:click="expandReplies(item)" style="float: right;">Expand replies: {{item.links.replies[0].count}}</a> - </h1> - {{item.object.content | html}} - <div ng:repeat="reply in item.replies.data.items" style="margin-left: 20px;"> - <img src="{{reply.actor.thumbnailUrl}}" style="max-height:30px;max-width:30px;"/> - <a href="{{reply.actor.profileUrl}}">{{reply.actor.name}}</a>: {{reply.content | html}} + <doc:example> + <doc:source> + <script> + function BuzzController($resource) { + this.Activity = $resource( + 'https://www.googleapis.com/buzz/v1/activities/:userId/:visibility/:activityId/:comments', + {alt:'json', callback:'JSON_CALLBACK'}, + {get:{method:'JSON', params:{visibility:'@self'}}, replies: {method:'JSON', params:{visibility:'@self', comments:'@comments'}}} + ); + } + + BuzzController.prototype = { + fetch: function() { + this.activities = this.Activity.get({userId:this.userId}); + }, + expandReplies: function(activity) { + activity.replies = this.Activity.replies({userId:this.userId, activityId:activity.id}); + } + }; + BuzzController.$inject = ['$resource']; + </script> + + <div ng:controller="BuzzController"> + <input name="userId" value="googlebuzz"/> + <button ng:click="fetch()">fetch</button> + <hr/> + <div ng:repeat="item in activities.data.items"> + <h1 style="font-size: 15px;"> + <img src="{{item.actor.thumbnailUrl}}" style="max-height:30px;max-width:30px;"/> + <a href="{{item.actor.profileUrl}}">{{item.actor.name}}</a> + <a href ng:click="expandReplies(item)" style="float: right;">Expand replies: {{item.links.replies[0].count}}</a> + </h1> + {{item.object.content | html}} + <div ng:repeat="reply in item.replies.data.items" style="margin-left: 20px;"> + <img src="{{reply.actor.thumbnailUrl}}" style="max-height:30px;max-width:30px;"/> + <a href="{{reply.actor.profileUrl}}">{{reply.actor.name}}</a>: {{reply.content | html}} + </div> + </div> </div> - </div> - </div> + </doc:source> + <doc:scenario> + </doc:scenario> + </doc:example> */ angularServiceInject('$resource', function($xhr){ var resource = new ResourceFactory($xhr); diff --git a/src/validators.js b/src/validators.js index 30936574..e2a9d7f6 100644 --- a/src/validators.js +++ b/src/validators.js @@ -14,24 +14,27 @@ extend(angularValidator, { * @css ng-validation-error * * @example - * <script> function Cntl(){ - * this.ssnRegExp = /^\d\d\d-\d\d-\d\d\d\d$/; - * } - * </script> - * Enter valid SSN: - * <div ng:controller="Cntl"> - * <input name="ssn" value="123-45-6789" ng:validate="regexp:ssnRegExp" > - * </div> - * - * @scenario - * it('should invalidate non ssn', function(){ - * var textBox = element('.doc-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/); - * }); + <doc:example> + <doc:source> + <script> function Cntl(){ + this.ssnRegExp = /^\d\d\d-\d\d-\d\d\d\d$/; + } + </script> + Enter valid SSN: + <div ng:controller="Cntl"> + <input name="ssn" value="123-45-6789" ng:validate="regexp:ssnRegExp" > + </div> + </doc:source> + <doc:scenario> + it('should invalidate non ssn', function(){ + var textBox = element('.doc-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/); + }); + </doc:scenario> + </doc:example> * */ 'regexp': function(value, regexp, msg) { @@ -57,28 +60,29 @@ extend(angularValidator, { * @css ng-validation-error * * @example - * Enter number: <input name="n1" ng:validate="number" > <br> - * Enter number greater than 10: <input name="n2" ng:validate="number:10" > <br> - * Enter number between 100 and 200: <input name="n3" ng:validate="number:100:200" > <br> - * - * @scenario - * it('should invalidate number', function(){ - * var n1 = element('.doc-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('.doc-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('.doc-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/); - * - * }); + <doc:example> + <doc:source> + Enter number: <input name="n1" ng:validate="number" > <br> + Enter number greater than 10: <input name="n2" ng:validate="number:10" > <br> + Enter number between 100 and 200: <input name="n3" ng:validate="number:100:200" > <br> + </doc:source> + <doc:scenario> + it('should invalidate number', function(){ + var n1 = element('.doc-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('.doc-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('.doc-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/); + }); + </doc:scenario> + </doc:example> * */ 'number': function(value, min, max) { @@ -110,28 +114,29 @@ extend(angularValidator, { * @css ng-validation-error * * @example - * Enter integer: <input name="n1" ng:validate="integer" > <br> - * Enter integer equal or greater than 10: <input name="n2" ng:validate="integer:10" > <br> - * Enter integer between 100 and 200 (inclusive): <input name="n3" ng:validate="integer:100:200" > <br> - * - * @scenario - * it('should invalidate integer', function(){ - * var n1 = element('.doc-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('.doc-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('.doc-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/); - * - * }); + <doc:example> + <doc:source> + Enter integer: <input name="n1" ng:validate="integer" > <br> + Enter integer equal or greater than 10: <input name="n2" ng:validate="integer:10" > <br> + Enter integer between 100 and 200 (inclusive): <input name="n3" ng:validate="integer:100:200" > <br> + </doc:source> + <doc:scenario> + it('should invalidate integer', function(){ + var n1 = element('.doc-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('.doc-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('.doc-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/); + }); + </doc:scenario> + </doc:example> */ 'integer': function(value, min, max) { var numberError = angularValidator['number'](value, min, max); @@ -154,16 +159,20 @@ extend(angularValidator, { * @css ng-validation-error * * @example - * Enter valid date: - * <input name="text" value="1/1/2009" ng:validate="date" > - * - * @scenario - * it('should invalidate date', function(){ - * var n1 = element('.doc-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/); - * }); + <doc:example> + <doc:source> + Enter valid date: + <input name="text" value="1/1/2009" ng:validate="date" > + </doc:source> + <doc:scenario> + it('should invalidate date', function(){ + var n1 = element('.doc-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/); + }); + </doc:scenario> + </doc:example> * */ 'date': function(value) { @@ -187,16 +196,20 @@ extend(angularValidator, { * @css ng-validation-error * * @example - * Enter valid email: - * <input name="text" ng:validate="email" value="me@example.com"> - * - * @scenario - * it('should invalidate email', function(){ - * var n1 = element('.doc-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/); - * }); + <doc:example> + <doc:source> + Enter valid email: + <input name="text" ng:validate="email" value="me@example.com"> + </doc:source> + <doc:scenario> + it('should invalidate email', function(){ + var n1 = element('.doc-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/); + }); + </doc:scenario> + </doc:example> * */ 'email': function(value) { @@ -217,16 +230,20 @@ extend(angularValidator, { * @css ng-validation-error * * @example - * Enter valid phone number: - * <input name="text" value="1(234)567-8901" ng:validate="phone" > - * - * @scenario - * it('should invalidate phone', function(){ - * var n1 = element('.doc-example :input'); - * expect(n1.attr('className')).not().toMatch(/ng-validation-error/); - * input('text').enter('+12345678'); - * expect(n1.attr('className')).toMatch(/ng-validation-error/); - * }); + <doc:example> + <doc:source> + Enter valid phone number: + <input name="text" value="1(234)567-8901" ng:validate="phone" > + </doc:source> + <doc:scenario> + it('should invalidate phone', function(){ + var n1 = element('.doc-example :input'); + expect(n1.attr('className')).not().toMatch(/ng-validation-error/); + input('text').enter('+12345678'); + expect(n1.attr('className')).toMatch(/ng-validation-error/); + }); + </doc:scenario> + </doc:example> * */ 'phone': function(value) { @@ -250,16 +267,20 @@ extend(angularValidator, { * @css ng-validation-error * * @example - * Enter valid phone number: - * <input name="text" value="http://example.com/abc.html" size="40" ng:validate="url" > - * - * @scenario - * it('should invalidate url', function(){ - * var n1 = element('.doc-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/); - * }); + <doc:example> + <doc:source> + Enter valid phone number: + <input name="text" value="http://example.com/abc.html" size="40" ng:validate="url" > + </doc:source> + <doc:scenario> + it('should invalidate url', function(){ + var n1 = element('.doc-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/); + }); + </doc:scenario> + </doc:example> * */ 'url': function(value) { @@ -280,17 +301,21 @@ extend(angularValidator, { * @css ng-validation-error * * @example - * <textarea name="json" cols="60" rows="5" ng:validate="json"> - * {name:'abc'} - * </textarea> - * - * @scenario - * it('should invalidate json', function(){ - * var n1 = element('.doc-example :input'); - * expect(n1.attr('className')).not().toMatch(/ng-validation-error/); - * input('json').enter('{name}'); - * expect(n1.attr('className')).toMatch(/ng-validation-error/); - * }); + <doc:example> + <doc:source> + <textarea name="json" cols="60" rows="5" ng:validate="json"> + {name:'abc'} + </textarea> + </doc:source> + <doc:scenario> + it('should invalidate json', function(){ + var n1 = element('.doc-example :input'); + expect(n1.attr('className')).not().toMatch(/ng-validation-error/); + input('json').enter('{name}'); + expect(n1.attr('className')).toMatch(/ng-validation-error/); + }); + </doc:scenario> + </doc:example> * */ 'json': function(value) { @@ -338,35 +363,35 @@ extend(angularValidator, { * @css ng-input-indicator-wait, ng-validation-error * * @example - * <script> - * function MyCntl(){ - * this.myValidator = function (inputToValidate, validationDone) { - * setTimeout(function(){ - * validationDone(inputToValidate.length % 2); - * }, 500); - * } - * } - * </script> - * This input is validated asynchronously: - * <div ng:controller="MyCntl"> - * <input name="text" ng:validate="asynchronous:myValidator"> - * </div> - * - * @scenario - * it('should change color in delayed way', function(){ - * var textBox = element('.doc-example :input'); - * expect(textBox.attr('className')).not().toMatch(/ng-input-indicator-wait/); - * expect(textBox.attr('className')).not().toMatch(/ng-validation-error/); - * - * input('text').enter('X'); - * expect(textBox.attr('className')).toMatch(/ng-input-indicator-wait/); - * - * pause(.6); - * - * expect(textBox.attr('className')).not().toMatch(/ng-input-indicator-wait/); - * expect(textBox.attr('className')).toMatch(/ng-validation-error/); - * - * }); + <doc:example> + <doc:source> + <script> + function MyCntl(){ + this.myValidator = function (inputToValidate, validationDone) { + setTimeout(function(){ + validationDone(inputToValidate.length % 2); + }, 500); + } + } + </script> + This input is validated asynchronously: + <div ng:controller="MyCntl"> + <input name="text" ng:validate="asynchronous:myValidator"> + </div> + </doc:source> + <doc:scenario> + it('should change color in delayed way', function(){ + var textBox = element('.doc-example :input'); + expect(textBox.attr('className')).not().toMatch(/ng-input-indicator-wait/); + expect(textBox.attr('className')).not().toMatch(/ng-validation-error/); + input('text').enter('X'); + expect(textBox.attr('className')).toMatch(/ng-input-indicator-wait/); + pause(.6); + expect(textBox.attr('className')).not().toMatch(/ng-input-indicator-wait/); + expect(textBox.attr('className')).toMatch(/ng-validation-error/); + }); + </doc:scenario> + </doc:example> * */ /* diff --git a/src/widgets.js b/src/widgets.js index cf65cd40..ea76cfc2 100644 --- a/src/widgets.js +++ b/src/widgets.js @@ -19,117 +19,122 @@ * </select> * * @example -<table style="font-size:.9em;"> - <tr> - <th>Name</th> - <th>Format</th> - <th>HTML</th> - <th>UI</th> - <th ng:non-bindable>{{input#}}</th> - </tr> - <tr> - <th>text</th> - <td>String</td> - <td><tt><input type="text" name="input1"></tt></td> - <td><input type="text" name="input1" size="4"></td> - <td><tt>{{input1|json}}</tt></td> - </tr> - <tr> - <th>textarea</th> - <td>String</td> - <td><tt><textarea name="input2"></textarea></tt></td> - <td><textarea name="input2" cols='6'></textarea></td> - <td><tt>{{input2|json}}</tt></td> - </tr> - <tr> - <th>radio</th> - <td>String</td> - <td><tt> - <input type="radio" name="input3" value="A"><br> - <input type="radio" name="input3" value="B"> - </tt></td> - <td> - <input type="radio" name="input3" value="A"> - <input type="radio" name="input3" value="B"> - </td> - <td><tt>{{input3|json}}</tt></td> - </tr> - <tr> - <th>checkbox</th> - <td>Boolean</td> - <td><tt><input type="checkbox" name="input4" value="checked"></tt></td> - <td><input type="checkbox" name="input4" value="checked"></td> - <td><tt>{{input4|json}}</tt></td> - </tr> - <tr> - <th>pulldown</th> - <td>String</td> - <td><tt> - <select name="input5"><br> - <option value="c">C</option><br> - <option value="d">D</option><br> - </select><br> - </tt></td> - <td> - <select name="input5"> - <option value="c">C</option> - <option value="d">D</option> - </select> - </td> - <td><tt>{{input5|json}}</tt></td> - </tr> - <tr> - <th>multiselect</th> - <td>Array</td> - <td><tt> - <select name="input6" multiple size="4"><br> - <option value="e">E</option><br> - <option value="f">F</option><br> - </select><br> - </tt></td> - <td> - <select name="input6" multiple size="4"> - <option value="e">E</option> - <option value="f">F</option> - </select> - </td> - <td><tt>{{input6|json}}</tt></td> - </tr> -</table> + <doc:example> + <doc:source> + <table style="font-size:.9em;"> + <tr> + <th>Name</th> + <th>Format</th> + <th>HTML</th> + <th>UI</th> + <th ng:non-bindable>{{input#}}</th> + </tr> + <tr> + <th>text</th> + <td>String</td> + <td><tt><input type="text" name="input1"></tt></td> + <td><input type="text" name="input1" size="4"></td> + <td><tt>{{input1|json}}</tt></td> + </tr> + <tr> + <th>textarea</th> + <td>String</td> + <td><tt><textarea name="input2"></textarea></tt></td> + <td><textarea name="input2" cols='6'></textarea></td> + <td><tt>{{input2|json}}</tt></td> + </tr> + <tr> + <th>radio</th> + <td>String</td> + <td><tt> + <input type="radio" name="input3" value="A"><br> + <input type="radio" name="input3" value="B"> + </tt></td> + <td> + <input type="radio" name="input3" value="A"> + <input type="radio" name="input3" value="B"> + </td> + <td><tt>{{input3|json}}</tt></td> + </tr> + <tr> + <th>checkbox</th> + <td>Boolean</td> + <td><tt><input type="checkbox" name="input4" value="checked"></tt></td> + <td><input type="checkbox" name="input4" value="checked"></td> + <td><tt>{{input4|json}}</tt></td> + </tr> + <tr> + <th>pulldown</th> + <td>String</td> + <td><tt> + <select name="input5"><br> + <option value="c">C</option><br> + <option value="d">D</option><br> + </select><br> + </tt></td> + <td> + <select name="input5"> + <option value="c">C</option> + <option value="d">D</option> + </select> + </td> + <td><tt>{{input5|json}}</tt></td> + </tr> + <tr> + <th>multiselect</th> + <td>Array</td> + <td><tt> + <select name="input6" multiple size="4"><br> + <option value="e">E</option><br> + <option value="f">F</option><br> + </select><br> + </tt></td> + <td> + <select name="input6" multiple size="4"> + <option value="e">E</option> + <option value="f">F</option> + </select> + </td> + <td><tt>{{input6|json}}</tt></td> + </tr> + </table> + </doc:source> + <doc:scenario> - * @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"]'); - * }); + 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"]'); + }); + </doc:scenario> + </doc:example> */ function modelAccessor(scope, element) { @@ -193,26 +198,29 @@ function compileFormatter(expr) { * @element INPUT * @css ng-validation-error * - * @exampleDescription + * @example * This example shows how the input element becomes red when it contains invalid input. Correct * the input to make the error disappear. * - * @example - I don't validate: - <input type="text" name="value" value="NotANumber"><br/> + <doc:example> + <doc:source> + I don't validate: + <input type="text" name="value" value="NotANumber"><br/> - I need an integer or nothing: - <input type="text" name="value" ng:validate="integer"><br/> - * - * @scenario - it('should check ng:validate', function(){ - expect(element('.doc-example-live :input:last').attr('className')). - toMatch(/ng-validation-error/); + I need an integer or nothing: + <input type="text" name="value" ng:validate="integer"><br/> + </doc:source> + <doc:scenario> + it('should check ng:validate', function(){ + expect(element('.doc-example-live :input:last').attr('className')). + toMatch(/ng-validation-error/); - input('value').enter('123'); - expect(element('.doc-example-live :input:last').attr('className')). - not().toMatch(/ng-validation-error/); - }); + input('value').enter('123'); + expect(element('.doc-example-live :input:last').attr('className')). + not().toMatch(/ng-validation-error/); + }); + </doc:scenario> + </doc:example> */ /** * @workInProgress @@ -226,19 +234,22 @@ function compileFormatter(expr) { * @element INPUT * @css ng-validation-error * - * @exampleDescription + * @example * This example shows how the input element becomes red when it contains invalid input. Correct * the input to make the error disappear. * - * @example - I cannot be blank: <input type="text" name="value" ng:required><br/> - * - * @scenario - it('should check ng:required', function(){ - expect(element('.doc-example-live :input').attr('className')).toMatch(/ng-validation-error/); - input('value').enter('123'); - expect(element('.doc-example-live :input').attr('className')).not().toMatch(/ng-validation-error/); - }); + <doc:example> + <doc:source> + I cannot be blank: <input type="text" name="value" ng:required><br/> + </doc:source> + <doc:scenario> + it('should check ng:required', function(){ + expect(element('.doc-example-live :input').attr('className')).toMatch(/ng-validation-error/); + input('value').enter('123'); + expect(element('.doc-example-live :input').attr('className')).not().toMatch(/ng-validation-error/); + }); + </doc:scenario> + </doc:example> */ /** * @workInProgress @@ -256,21 +267,24 @@ function compileFormatter(expr) { * * @element INPUT * - * @exampleDescription + * @example * This example shows how the user input is converted from a string and internally represented as an * array. * - * @example - Enter a comma separated list of items: - <input type="text" name="list" ng:format="list" value="table, chairs, plate"> - <pre>list={{list}}</pre> - * - * @scenario - it('should check ng:format', function(){ - expect(binding('list')).toBe('list=["table","chairs","plate"]'); - input('list').enter(',,, a ,,,'); - expect(binding('list')).toBe('list=["a"]'); - }); + <doc:example> + <doc:source> + Enter a comma separated list of items: + <input type="text" name="list" ng:format="list" value="table, chairs, plate"> + <pre>list={{list}}</pre> + </doc:source> + <doc:scenario> + it('should check ng:format', function(){ + expect(binding('list')).toBe('list=["table","chairs","plate"]'); + input('list').enter(',,, a ,,,'); + expect(binding('list')).toBe('list=["a"]'); + }); + </doc:scenario> + </doc:example> */ function valueAccessor(scope, element) { var validatorName = element.attr('ng:validate') || NOOP, @@ -453,28 +467,32 @@ function radioInit(model, view, element) { * @element INPUT * @param {expression} expression to execute. * - * @exampleDescription * @example - <div ng:init="checkboxCount=0; textCount=0"></div> - <input type="text" name="text" ng:change="textCount = 1 + textCount"> - changeCount {{textCount}}<br/> - <input type="checkbox" name="checkbox" ng:change="checkboxCount = 1 + checkboxCount"> - changeCount {{checkboxCount}}<br/> - * - * @scenario - it('should check ng:change', function(){ - expect(binding('textCount')).toBe('0'); - expect(binding('checkboxCount')).toBe('0'); + * @example + <doc:example> + <doc:source> + <div ng:init="checkboxCount=0; textCount=0"></div> + <input type="text" name="text" ng:change="textCount = 1 + textCount"> + changeCount {{textCount}}<br/> + <input type="checkbox" name="checkbox" ng:change="checkboxCount = 1 + checkboxCount"> + changeCount {{checkboxCount}}<br/> + </doc:source> + <doc:scenario> + it('should check ng:change', function(){ + expect(binding('textCount')).toBe('0'); + expect(binding('checkboxCount')).toBe('0'); - using('.doc-example-live').input('text').enter('abc'); - expect(binding('textCount')).toBe('1'); - expect(binding('checkboxCount')).toBe('0'); + using('.doc-example-live').input('text').enter('abc'); + expect(binding('textCount')).toBe('1'); + expect(binding('checkboxCount')).toBe('0'); - using('.doc-example-live').input('checkbox').check(); - expect(binding('textCount')).toBe('1'); - expect(binding('checkboxCount')).toBe('1'); - }); + using('.doc-example-live').input('checkbox').check(); + expect(binding('textCount')).toBe('1'); + expect(binding('checkboxCount')).toBe('1'); + }); + </doc:scenario> + </doc:example> */ function inputWidget(events, modelAccessor, viewAccessor, initFn, textBox) { return injectService(['$updateView', '$defer'], function($updateView, $defer, element) { @@ -594,27 +612,31 @@ angularWidget('option', function(){ * @param {string=} onload Expression to evaluate when a new partial is loaded. * * @example - * <select name="url"> - * <option value="angular.filter.date.html">date filter</option> - * <option value="angular.filter.html.html">html filter</option> - * <option value="">(blank)</option> - * </select> - * <tt>url = <a href="{{url}}">{{url}}</a></tt> - * <hr/> - * <ng:include src="url"></ng:include> - * - * @scenario - * it('should load date filter', function(){ - * expect(element('.doc-example ng\\:include').text()).toMatch(/angular\.filter\.date/); - * }); - * it('should change to hmtl filter', function(){ - * select('url').option('angular.filter.html.html'); - * expect(element('.doc-example ng\\:include').text()).toMatch(/angular\.filter\.html/); - * }); - * it('should change to blank', function(){ - * select('url').option('(blank)'); - * expect(element('.doc-example ng\\:include').text()).toEqual(''); - * }); + <doc:example> + <doc:source> + <select name="url"> + <option value="angular.filter.date.html">date filter</option> + <option value="angular.filter.html.html">html filter</option> + <option value="">(blank)</option> + </select> + <tt>url = <a href="{{url}}">{{url}}</a></tt> + <hr/> + <ng:include src="url"></ng:include> + </doc:source> + <doc:scenario> + it('should load date filter', function(){ + expect(element('.doc-example ng\\:include').text()).toMatch(/angular\.filter\.date/); + }); + it('should change to hmtl filter', function(){ + select('url').option('angular.filter.html.html'); + expect(element('.doc-example ng\\:include').text()).toMatch(/angular\.filter\.html/); + }); + it('should change to blank', function(){ + select('url').option('(blank)'); + expect(element('.doc-example ng\\:include').text()).toEqual(''); + }); + </doc:scenario> + </doc:example> */ angularWidget('ng:include', function(element){ var compiler = this, @@ -690,32 +712,36 @@ angularWidget('ng:include', function(element){ * * `ng:switch-default`: the default case when no other casses match. * * @example - <select name="switch"> - <option>settings</option> - <option>home</option> - <option>other</option> - </select> - <tt>switch={{switch}}</tt> - </hr> - <ng:switch on="switch" > - <div ng:switch-when="settings">Settings Div</div> - <span ng:switch-when="home">Home Span</span> - <span ng:switch-default>default</span> - </ng:switch> - </code> - * - * @scenario - * it('should start in settings', function(){ - * expect(element('.doc-example ng\\:switch').text()).toEqual('Settings Div'); - * }); - * it('should change to home', function(){ - * select('switch').option('home'); - * expect(element('.doc-example ng\\:switch').text()).toEqual('Home Span'); - * }); - * it('should select deafault', function(){ - * select('switch').option('other'); - * expect(element('.doc-example ng\\:switch').text()).toEqual('default'); - * }); + <doc:example> + <doc:source> + <select name="switch"> + <option>settings</option> + <option>home</option> + <option>other</option> + </select> + <tt>switch={{switch}}</tt> + </hr> + <ng:switch on="switch" > + <div ng:switch-when="settings">Settings Div</div> + <span ng:switch-when="home">Home Span</span> + <span ng:switch-default>default</span> + </ng:switch> + </code> + </doc:source> + <doc:scenario> + it('should start in settings', function(){ + expect(element('.doc-example ng\\:switch').text()).toEqual('Settings Div'); + }); + it('should change to home', function(){ + select('switch').option('home'); + expect(element('.doc-example ng\\:switch').text()).toEqual('Home Span'); + }); + it('should select deafault', function(){ + select('switch').option('other'); + expect(element('.doc-example ng\\:switch').text()).toEqual('default'); + }); + </doc:scenario> + </doc:example> */ var ngSwitch = angularWidget('ng:switch', function (element){ var compiler = this, @@ -838,25 +864,29 @@ angularWidget('a', function() { * * For example: `(name, age) in {'adam':10, 'amalie':12}`. * - * @exampleDescription + * @example * This example initializes the scope to a list of names and * than uses `ng:repeat` to display every person. - * @example - <div ng:init="friends = [{name:'John', age:25}, {name:'Mary', age:28}]"> - I have {{friends.length}} friends. They are: - <ul> - <li ng:repeat="friend in friends"> - [{{$index + 1}}] {{friend.name}} who is {{friend.age}} years old. - </li> - </ul> - </div> - * @scenario - it('should check ng:repeat', function(){ - var r = using('.doc-example-live').repeater('ul li'); - expect(r.count()).toBe(2); - expect(r.row(0)).toEqual(["1","John","25"]); - expect(r.row(1)).toEqual(["2","Mary","28"]); - }); + <doc:example> + <doc:source> + <div ng:init="friends = [{name:'John', age:25}, {name:'Mary', age:28}]"> + I have {{friends.length}} friends. They are: + <ul> + <li ng:repeat="friend in friends"> + [{{$index + 1}}] {{friend.name}} who is {{friend.age}} years old. + </li> + </ul> + </div> + </doc:source> + <doc:scenario> + it('should check ng:repeat', function(){ + var r = using('.doc-example-live').repeater('ul li'); + expect(r.count()).toBe(2); + expect(r.row(0)).toEqual(["1","John","25"]); + expect(r.row(1)).toEqual(["2","Mary","28"]); + }); + </doc:scenario> + </doc:example> */ angularWidget("@ng:repeat", function(expression, element){ element.removeAttr('ng:repeat'); @@ -946,20 +976,24 @@ angularWidget("@ng:repeat", function(expression, element){ * * @element ANY * - * @exampleDescription + * @example * In this example there are two location where a siple binding (`{{}}`) is present, but the one * wrapped in `ng:non-bindable` is left alone. * * @example - <div>Normal: {{1 + 2}}</div> - <div ng:non-bindable>Ignored: {{1 + 2}}</div> - * - * @scenario - it('should check ng:non-bindable', function(){ - expect(using('.doc-example-live').binding('1 + 2')).toBe('3'); - expect(using('.doc-example-live').element('div:last').text()). - toMatch(/1 \+ 2/); - }); + <doc:example> + <doc:source> + <div>Normal: {{1 + 2}}</div> + <div ng:non-bindable>Ignored: {{1 + 2}}</div> + </doc:source> + <doc:scenario> + it('should check ng:non-bindable', function(){ + expect(using('.doc-example-live').binding('1 + 2')).toBe('3'); + expect(using('.doc-example-live').element('div:last').text()). + toMatch(/1 \+ 2/); + }); + </doc:scenario> + </doc:example> */ angularWidget("@ng:non-bindable", noop); @@ -989,26 +1023,30 @@ angularWidget("@ng:non-bindable", noop); * - doesn't require `$route` service to be available on the root scope * * - * # Example - * Because of the nature of this widget, we can't include the usual live example for it. Instead - * following is a code snippet showing the typical usage: - * - <pre> - <script> - angular.service('routeConfig', function($route) { - $route.when('/foo', {controller: MyCtrl, template: 'foo.html'}); - $route.when('/bar', {controller: MyCtrl, template: 'bar.html'}); - }, {$inject: ['$route'], $eager: true}); + * @example + <doc:example> + <doc:source> + <script> + function MyCtrl($route) { + $route.when('/overview', {controller: OverviewCtrl, template: 'guide.overview.html'}); + $route.when('/bootstrap', {controller: BootstrapCtrl, template: 'guide.bootstrap.html'}); + console.log(window.$route = $route); + }; + MyCtrl.$inject = ['$route']; - function MyCtrl() {}; - </script> - <div> - <a href="#/foo">foo</a> | <a href="#/bar">bar</a> | <a href="#/undefined">undefined</a><br/> - The view is included below: - <hr/> - <ng:view></ng:view> - </div> - </pre> + function BootstrapCtrl(){} + function OverviewCtrl(){} + </script> + <div ng:controller="MyCtrl"> + <a href="#/overview">overview</a> | <a href="#/bootstrap">bootstrap</a> | <a href="#/undefined">undefined</a><br/> + The view is included below: + <hr/> + <ng:view></ng:view> + </div> + </doc:source> + <doc:scenario> + </doc:scenario> + </doc:example> */ angularWidget('ng:view', function(element) { var compiler = this; |
