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;  | 
