diff options
| author | Misko Hevery | 2010-11-10 12:02:49 -0800 | 
|---|---|---|
| committer | Misko Hevery | 2010-11-10 12:02:49 -0800 | 
| commit | 6b8ed42670039f53d2b20dc1079f742840f62ae9 (patch) | |
| tree | 4fe8b80e2d3245a388921a05cbbb1c1f82744d76 | |
| parent | c57df3dc776f8a35aaad35fc399960f0d7fee06d (diff) | |
| download | angular.js-6b8ed42670039f53d2b20dc1079f742840f62ae9.tar.bz2 | |
Added Directives
| -rw-r--r-- | docs/collect.js | 14 | ||||
| -rw-r--r-- | docs/directive.template | 37 | ||||
| -rw-r--r-- | docs/doc_widgets.js | 4 | ||||
| -rw-r--r-- | docs/index.html | 30 | ||||
| -rw-r--r-- | docs/spec/collectSpec.js | 4 | ||||
| -rw-r--r-- | src/Angular.js | 29 | ||||
| -rw-r--r-- | src/directives.js | 560 | ||||
| -rw-r--r-- | src/filters.js | 4 | 
8 files changed, 655 insertions, 27 deletions
| diff --git a/docs/collect.js b/docs/collect.js index 2d43669a..08bb6be3 100644 --- a/docs/collect.js +++ b/docs/collect.js @@ -127,7 +127,8 @@ function escapedHtmlTag(doc, name, value) {  }  function markdownTag(doc, name, value) { -  doc[name] = markdown(value.replace(/^#/gm, '##')); +  doc[name] = markdown(value.replace(/^#/gm, '##')). +    replace(/\<pre\>/gmi, '<pre class="brush: xml; brush: js;" ng:non-bindable>');  }  function markdown(text) { @@ -135,6 +136,14 @@ function markdown(text) {    return new Showdown.converter().makeHtml(text);  } +function markdownNoP(text) { +  var lines = markdown(text).split(NEW_LINE); +  var last = lines.length - 1; +  lines[0] = lines[0].replace(/^<p>/, ''); +  lines[last] = lines[last].replace(/<\/p>$/, ''); +  return lines.join('\n'); +} +  var TAG = {    ngdoc: valueTag,    example: escapedHtmlTag, @@ -149,6 +158,7 @@ var TAG = {    returns: markdownTag,    paramDescription: markdownTag,    exampleDescription: markdownTag, +  element: valueTag,    name: function(doc, name, value) {      doc.name = value;      var match = value.match(/^angular[\.\#](([^\.]+)\.(.*)|(.*))/); @@ -163,7 +173,7 @@ var TAG = {            type: match[2],            name: match[6] || match[5],            'default':match[7], -          description:value.replace(match[0], match[8]) +          description:markdownNoP(value.replace(match[0], match[8]))          };        doc.param.push(param);        if (!doc.paramFirst) { diff --git a/docs/directive.template b/docs/directive.template new file mode 100644 index 00000000..84b87ca7 --- /dev/null +++ b/docs/directive.template @@ -0,0 +1,37 @@ +<h1>{{name}}</h1> +<h2>Description</h2> +{{{description}}} + +<h2>Usage</h2> +<h3>In HTML Template Binding</h3> +<tt> +  <pre> +<{{element}} {{shortName}}="{{paramFirst.name}}"> +  ... +</{{element}}> +  </pre> +</tt> + +<h3>Parameters</h3> +<ul> +  {{#param}} +  <li><tt>{{name}}:{{#type}}{{type}}{{/type}}{{^type}}:*{{/type}}{{#default}}={{default}}{{/default}}</tt>: {{{description}}}</li> +  {{/param}} +</ul> +{{{paramDescription}}} + +{{#css}}<h3>CSS</h3>{{/css}} +{{{css}}} + +{{#example}} +<h2>Example</h2> +{{{exampleDescription}}} +<doc:example> +  <doc:source> +{{/example}} +    {{{example}}} +{{#example}} +  </doc:source> +  <doc:scenario>{{{scenario}}}</doc:scenario> +</doc:example> +{{/example}} diff --git a/docs/doc_widgets.js b/docs/doc_widgets.js index 7d723bb3..f865548c 100644 --- a/docs/doc_widgets.js +++ b/docs/doc_widgets.js @@ -23,7 +23,7 @@      var tabs = angular.element(          '<ul class="doc-example">' +            '<li class="doc-example-heading"><h3>Source</h3></li>' + -          '<li class="doc-example-source" ng:non-bindable><pre class="brush: js"></pre></li>' + +          '<li class="doc-example-source" ng:non-bindable><pre class="brush: js; brush: xml;"></pre></li>' +            '<li class="doc-example-heading"><h3>Live Preview</h3></li>' +            '<li class="doc-example-live">' + exampleSrc +'</li>' +            '<li class="doc-example-heading"><h3>Scenario Test</h3></li>' + @@ -44,6 +44,6 @@      return function() {        SyntaxHighlighter.highlight(); -    } +    };    });  })();
\ No newline at end of file diff --git a/docs/index.html b/docs/index.html index 4939dc9c..b9dfebc0 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1,5 +1,5 @@  <!DOCTYPE HTML> -<html xmlns:ng="http://angularjs.org/" xmlns:doc="http://docs.angularjs.org/"> +<html xmlns:ng="http://angularjs.org/" xmlns:doc="http://docs.angularjs.org/" ng:controller="DocsController">  <head>    <title><Angular/> Docs</title>    <link rel="stylesheet" href="wiki_widgets.css" type="text/css" media="screen"> @@ -11,32 +11,33 @@    <script type="text/javascript" src="doc_widgets.js"></script>    <script type="text/javascript" src="http://alexgorbatchev.com/pub/sh/current/scripts/shCore.js"></script>    <script type="text/javascript" src="http://alexgorbatchev.com/pub/sh/current/scripts/shBrushJScript.js"></script> +  <script type="text/javascript" src="http://alexgorbatchev.com/pub/sh/current/scripts/shBrushXml.js"></script>    <script type="text/javascript" src="docs-data.js"></script>    <script type="text/javascript">      SyntaxHighlighter['defaults'].toolbar = false; -    DocsController.$inject = ['$location'] -  	function DocsController($location) { +    DocsController.$inject = ['$location', '$browser'] +  	function DocsController($location, $browser) {    	  this.docs = NG_DOC;    	  window.$root = this.$root; - +  	      	  this.getUrl = function(page){    	    return '#' + encodeURIComponent(page.name);    	  }; -  	  this.getTitle = function() { -        if ($location.hashPath.match(/^angular\./)) { -          return $location.hashPath; -        } -        return ''; -	    }; -    	  this.getCurrentPartial = function(){    	    if ($location.hashPath.match(/^angular\./)) {    	      this.partialUrl = './' + $location.hashPath + '.html';    	    }    	    return this.partialUrl; -  	  }; +  	  } +  	   +  	  this.getTitle = function(){ +  	    if ($location.hashPath.match(/^angular\./)) { +  	      this.partialTitle = $location.hashPath; +  	    } +  	    return this.partialTitle; +  	  }    	}    </script>    <style type="text/css" media="screen"> @@ -122,8 +123,9 @@        float: right;      }    </style> +  <title><angular/>: {{getTitle()}}</title>  </head> -<body ng:controller="DocsController"> +<body>    <div id="header">      <h1>        <span class="section-title">{{getTitle()}}</span> @@ -134,7 +136,7 @@      <div ng:repeat="(name, type) in docs.section" class="nav-section">        <h2>{{name}}</h2>        <ul> -        <li ng:repeat="page in type"> +        <li ng:repeat="page in type.$orderBy('shortName')">            <a href="{{getUrl(page)}}" ng:click="">{{page.shortName}}</a>          </li>        </ul> diff --git a/docs/spec/collectSpec.js b/docs/spec/collectSpec.js index fbc6c489..4df04b9f 100644 --- a/docs/spec/collectSpec.js +++ b/docs/spec/collectSpec.js @@ -43,8 +43,8 @@ describe('collect', function(){      describe('@describe', function(){        it('should support pre blocks', function(){ -        TAG.description(doc, 'description', '<pre>abc</pre>'); -        expect(doc.description).toEqual('<pre>abc</pre>'); +        TAG.description(doc, 'description', '<pre class="brush: xml;" ng:non-bindable>abc</pre>'); +        expect(doc.description).toEqual('<pre class="brush: xml;" ng:non-bindable>abc</pre>');        });        describe('@example', function(){ diff --git a/src/Angular.js b/src/Angular.js index e6e7be8d..a1477e35 100644 --- a/src/Angular.js +++ b/src/Angular.js @@ -17,7 +17,7 @@ var lowercase = function (value){ return isString(value) ? value.toLowerCase() :  /**   * @ngdoc - * @name angular#uppercase + * @name angular.uppercase   * @function   *   * @description Converts string to uppercase. @@ -150,6 +150,21 @@ var _undefined        = undefined,       *   };       * });       * </pre> +     *  +     * @example +     * <script> +     *   angular.widget('my:time', function(compileElement){ +     *     compileElement.css('display', 'block'); +     *     return function(linkElement){ +     *       function update(){ +     *         linkElement.text('Current time is: ' + new Date()); +     *         setTimeout(update, 1000); +     *       } +     *       update(); +     *     }; +     *   }); +     * </script> +     * <my:time></my:time>       */      angularWidget     = extensionMap(angular, 'widget', lowercase), @@ -366,15 +381,19 @@ var _undefined        = undefined,       * });       * </script>       * -     * Formatted: <input type="text" name="data" value="<angular/>" ng:format="reverse"/><br/> -     * Stored: <input type="text" name="data"/><br/> +     * Formatted:  +     * <input type="text" name="data" value="angular" ng:format="reverse"/> +     * <br/> +     *  +     * Stored:  +     * <input type="text" name="data"/><br/>       * <pre>{{data}}</pre>       *       *        * @scenario       * it('should store reverse', function(){ -     *  expect(element('.doc-example input:first').val()).toEqual('<angular/>'); -     *  expect(element('.doc-example input:last').val()).toEqual('>/RALUGNA<'); +     *  expect(element('.doc-example input:first').val()).toEqual('angular'); +     *  expect(element('.doc-example input:last').val()).toEqual('RALUGNA');       *         *  this.addFutureAction('change to XYZ', function($window, $document, done){       *    $document.elements('.doc-example input:last').val('XYZ').trigger('change'); diff --git a/src/directives.js b/src/directives.js index e21dca89..7dcc7f39 100644 --- a/src/directives.js +++ b/src/directives.js @@ -1,9 +1,97 @@ +/** + * @ngdoc directive + * @name angular.directive.ng:init + * + * @description + * `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 +    <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'); +   }); + */  angularDirective("ng:init", function(expression){    return function(element){      this.$tryEval(expression, element);    };  }); +/** + * @ngdoc directive + * @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.  + * 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'); +   }); + */  angularDirective("ng:controller", function(expression){    this.scope(true);    return function(element){ @@ -16,12 +104,75 @@ angularDirective("ng:controller", function(expression){    };  }); +/** + * @ngdoc directive + * @name angular.directive.ng:eval + * + * @description + * 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'); +   }); + */  angularDirective("ng:eval", function(expression){    return function(element){      this.$onEval(expression, element);    };  }); +/** + * @ngdoc directive + * @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  + * <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'); +   }); + */  angularDirective("ng:bind", function(expression, element){    element.addClass('ng-binding');    return function(element) { @@ -98,6 +249,38 @@ function compileBindTemplate(template){    return fn;  } +/** + * @ngdoc directive + * @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  + * 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!'); +   }); + */  angularDirective("ng:bind-template", function(expression, element){    element.addClass('ng-binding');    var templateFn = compileBindTemplate(expression); @@ -118,6 +301,55 @@ var REMOVE_ATTRIBUTES = {    'readonly':'readOnly',    'checked':'checked'  }; +/** + * @ngdoc directive + * @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  + * 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  + *    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'); +   }); + */  angularDirective("ng:bind-attr", function(expression){    return function(element){      var lastValue = {}; @@ -146,8 +378,82 @@ angularDirective("ng:bind-attr", function(expression){    };  }); +/** + * @ngdoc directive + * @name angular.directive.ng:non-bindable + * + * @description + * Sometimes it is necessary to write code which looks like  + * bindings but which should be left alone by <angular/>.  + * Use `ng:non-bindable` to ignore a chunk of HTML. + *  + * @element ANY + * @param {string} ignore  + * + * @exampleDescription + * In this example there are two location where  + * <tt ng:non-bindable>{{1 + 2}}</tt> 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/); +   }); + */  angularWidget("@ng:non-bindable", noop); +/** + * @ngdoc directive + * @name angular.directive.ng:repeat + * + * @description + * `ng:repeat` instantiates a template once per item from a  + * collection. The collection is enumerated with  + * `ng:repeat-index` attribute starting from 0. Each template  + * instance gets its own scope where the given loop variable  + * is set to the current collection item and `$index` is set  + * to the item index or key. + *  + * NOTE: `ng:repeat` looks like a directive, but is actually a  + * attribute widget. + *  + * @element ANY + * @param {repeat} repeat_expression to itterate over. + *  + *   * `variable in expression`, where variable is the user  + *     defined loop variable and expression is a scope expression  + *     giving the collection to enumerate. For example:  + *     `track in cd.tracks`. + *   * `(key, value) in expression`, where key and value can  + *     be any user defined identifiers, and expression is the  + *     scope expression giving the collection to enumerate.  + *     For example: `(name, age) in {'adam':10, 'amalie':12}`. + * + * @exampleDescription + * 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"]); +   }); + */  angularWidget("@ng:repeat", function(expression, element){    element.removeAttr('ng:repeat');    element.replaceWith(this.comment("ng:repeat: " + expression)); @@ -205,6 +511,29 @@ angularWidget("@ng:repeat", function(expression, element){  }); +/** + * @ngdoc directive + * @name angular.directive.ng:click + * + * @description + * 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'); +   }); + */  /*   * A directive that allows creation of custom onclick handlers that are defined as angular   * expressions and are compiled and executed within the current scope. @@ -226,6 +555,35 @@ angularDirective("ng:click", function(expression, element){  /** + * @ngdoc directive + * @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 @@ -243,6 +601,32 @@ angularDirective("ng:submit", function(expression, element) {  }); +/** + * @ngdoc directive + * @name angular.directive.ng:watch + * + * @description + * 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('1'); +     using('.doc-example-live').input('name').enter('abc'); +     expect(using('.doc-example-live').binding('counter')).toBe('2'); +   }); + */  angularDirective("ng:watch", function(expression, element){    return function(element){      var self = this; @@ -271,10 +655,141 @@ function ngClass(selector) {    };  } +/** + * @ngdoc directive + * @name angular.directive.ng:class + * + * @description + * 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/); + +     using('.doc-example-live').element(':button:first').click(); + +     expect(element('.doc-example-live span').attr('className')). +       toMatch(/ng-input-indicator-wait/); + +     using('.doc-example-live').element(':button:last').click(); +      +     expect(element('.doc-example-live span').attr('className')).not(). +       toMatch(/ng-input-indicator-wait/); +   }); + */  angularDirective("ng:class", ngClass(function(){return true;})); + +/** + * @ngdoc directive + * @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`  + * and takes affect only on odd (even) rows. + * + * @element ANY + * @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/); +   }); + */  angularDirective("ng:class-odd", ngClass(function(i){return i % 2 === 0;})); + +/** + * @ngdoc directive + * @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`  + * and takes affect only on odd (even) rows. + * + * @element ANY + * @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/); +   }); + */  angularDirective("ng:class-even", ngClass(function(i){return i % 2 === 1;})); +/** + * @ngdoc directive + * @name angular.directive.ng:show + * + * @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  + * 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); +   }); + */  angularDirective("ng:show", function(expression, element){    return function(element){      this.$onEval(function(){ @@ -283,6 +798,35 @@ angularDirective("ng:show", function(expression, element){    };  }); +/** + * @ngdoc directive + * @name angular.directive.ng:hide + * + * @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  + * 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); +   }); + */  angularDirective("ng:hide", function(expression, element){    return function(element){      this.$onEval(function(){ @@ -291,6 +835,22 @@ angularDirective("ng:hide", function(expression, element){    };  }); +/** + * @ngdoc directive + * @name angular.directive.ng:style + * + * @description + *  + * @element ANY + * @param {expression} expression to eval. + * + * @exampleDescription + * @example + *  + * @scenario +   it('should check ng:style', function(){ +   }); + */  angularDirective("ng:style", function(expression, element){    return function(element){      var resetStyle = getStyle(element); diff --git a/src/filters.js b/src/filters.js index 2fec3cd2..2f41d12c 100644 --- a/src/filters.js +++ b/src/filters.js @@ -23,8 +23,8 @@       it('should update', function(){         input('amount').enter('-1234');         expect(binding('amount | currency')).toBe('$-1,234.00'); -       expect(element('span[ng\\:bind="amount | currency"]').attr('class')). -          toMatch(/ng-format-negative/); +       expect(element('.doc-example-live .ng-binding').attr('className')). +         toMatch(/ng-format-negative/);       });   */  angularFilter.currency = function(amount){ | 
