angular-gem 1.2.12 → 1.2.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license AngularJS v1.2.9
2
+ * @license AngularJS v1.2.13
3
3
  * (c) 2010-2014 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license AngularJS v1.2.9
2
+ * @license AngularJS v1.2.13
3
3
  * (c) 2010-2014 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
@@ -69,7 +69,7 @@ function minErr(module) {
69
69
  return match;
70
70
  });
71
71
 
72
- message = message + '\nhttp://errors.angularjs.org/1.2.9/' +
72
+ message = message + '\nhttp://errors.angularjs.org/1.2.13/' +
73
73
  (module ? module + '/' : '') + code;
74
74
  for (i = 2; i < arguments.length; i++) {
75
75
  message = message + (i == 2 ? '?' : '&') + 'p' + (i-2) + '=' +
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license AngularJS v1.2.9
2
+ * @license AngularJS v1.2.13
3
3
  * (c) 2010-2014 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
@@ -386,7 +386,7 @@ angular.mock.$LogProvider = function() {
386
386
  *
387
387
  * @example
388
388
  * <pre>
389
- * $log.log('Some Error');
389
+ * $log.error('Some Error');
390
390
  * var first = $log.error.logs.unshift();
391
391
  * </pre>
392
392
  */
@@ -511,6 +511,7 @@ angular.mock.$IntervalProvider = function() {
511
511
  };
512
512
 
513
513
  $interval.cancel = function(promise) {
514
+ if(!promise) return false;
514
515
  var fnIndex;
515
516
 
516
517
  angular.forEach(repeatFns, function(fn, index) {
@@ -763,70 +764,40 @@ angular.mock.TzDate = function (offset, timestamp) {
763
764
  angular.mock.TzDate.prototype = Date.prototype;
764
765
  /* jshint +W101 */
765
766
 
766
- // TODO(matias): remove this IMMEDIATELY once we can properly detect the
767
- // presence of a registered module
768
- var animateLoaded;
769
- try {
770
- angular.module('ngAnimate');
771
- animateLoaded = true;
772
- } catch(e) {}
767
+ angular.mock.animate = angular.module('ngAnimateMock', ['ng'])
773
768
 
774
- if(animateLoaded) {
775
- angular.module('ngAnimate').config(['$provide', function($provide) {
769
+ .config(['$provide', function($provide) {
776
770
  var reflowQueue = [];
771
+
777
772
  $provide.value('$$animateReflow', function(fn) {
778
773
  reflowQueue.push(fn);
779
774
  return angular.noop;
780
775
  });
781
- $provide.decorator('$animate', function($delegate) {
782
- $delegate.triggerReflow = function() {
783
- if(reflowQueue.length === 0) {
784
- throw new Error('No animation reflows present');
785
- }
786
- angular.forEach(reflowQueue, function(fn) {
787
- fn();
788
- });
789
- reflowQueue = [];
790
- };
791
- return $delegate;
792
- });
793
- }]);
794
- }
795
-
796
- angular.mock.animate = angular.module('mock.animate', ['ng'])
797
-
798
- .config(['$provide', function($provide) {
799
776
 
800
777
  $provide.decorator('$animate', function($delegate) {
801
778
  var animate = {
802
779
  queue : [],
803
780
  enabled : $delegate.enabled,
804
- flushNext : function(name) {
805
- var tick = animate.queue.shift();
806
-
807
- if (!tick) throw new Error('No animation to be flushed');
808
- if(tick.method !== name) {
809
- throw new Error('The next animation is not "' + name +
810
- '", but is "' + tick.method + '"');
781
+ triggerReflow : function() {
782
+ if(reflowQueue.length === 0) {
783
+ throw new Error('No animation reflows present');
811
784
  }
812
- tick.fn();
813
- return tick;
785
+ angular.forEach(reflowQueue, function(fn) {
786
+ fn();
787
+ });
788
+ reflowQueue = [];
814
789
  }
815
790
  };
816
791
 
817
- angular.forEach(['enter','leave','move','addClass','removeClass'], function(method) {
792
+ angular.forEach(
793
+ ['enter','leave','move','addClass','removeClass','setClass'], function(method) {
818
794
  animate[method] = function() {
819
- var params = arguments;
820
795
  animate.queue.push({
821
- method : method,
822
- params : params,
823
- element : angular.isElement(params[0]) && params[0],
824
- parent : angular.isElement(params[1]) && params[1],
825
- after : angular.isElement(params[2]) && params[2],
826
- fn : function() {
827
- $delegate[method].apply($delegate, params);
828
- }
796
+ event : method,
797
+ element : arguments[0],
798
+ args : arguments
829
799
  });
800
+ $delegate[method].apply($delegate, arguments);
830
801
  };
831
802
  });
832
803
 
@@ -996,18 +967,18 @@ angular.mock.dump = function(object) {
996
967
  *
997
968
  * # Flushing HTTP requests
998
969
  *
999
- * The $httpBackend used in production, always responds to requests with responses asynchronously.
1000
- * If we preserved this behavior in unit testing, we'd have to create async unit tests, which are
1001
- * hard to write, follow and maintain. At the same time the testing mock, can't respond
970
+ * The $httpBackend used in production always responds to requests with responses asynchronously.
971
+ * If we preserved this behavior in unit testing we'd have to create async unit tests, which are
972
+ * hard to write, understand, and maintain. However, the testing mock can't respond
1002
973
  * synchronously because that would change the execution of the code under test. For this reason the
1003
974
  * mock $httpBackend has a `flush()` method, which allows the test to explicitly flush pending
1004
- * requests and thus preserving the async api of the backend, while allowing the test to execute
975
+ * requests and thus preserve the async api of the backend while allowing the test to execute
1005
976
  * synchronously.
1006
977
  *
1007
978
  *
1008
979
  * # Unit testing with mock $httpBackend
1009
- * The following code shows how to setup and use the mock backend in unit testing a controller.
1010
- * First we create the controller under test
980
+ * The following code shows how to setup and use the mock backend when unit testing a controller.
981
+ * First we create the controller under test:
1011
982
  *
1012
983
  <pre>
1013
984
  // The controller code
@@ -1032,7 +1003,7 @@ angular.mock.dump = function(object) {
1032
1003
  }
1033
1004
  </pre>
1034
1005
  *
1035
- * Now we setup the mock backend and create the test specs.
1006
+ * Now we setup the mock backend and create the test specs:
1036
1007
  *
1037
1008
  <pre>
1038
1009
  // testing controller
@@ -1736,7 +1707,7 @@ angular.mock.$RootElementProvider = function() {
1736
1707
  * In addition, ngMock also extends various core ng services such that they can be
1737
1708
  * inspected and controlled in a synchronous manner within test code.
1738
1709
  *
1739
- * {@installModule mocks}
1710
+ * {@installModule mock}
1740
1711
  *
1741
1712
  * <div doc-module-components="ngMock"></div>
1742
1713
  *
@@ -1954,7 +1925,7 @@ if(window.jasmine || window.mocha) {
1954
1925
 
1955
1926
  var currentSpec = null,
1956
1927
  isSpecRunning = function() {
1957
- return currentSpec && (window.mocha || currentSpec.queue.running);
1928
+ return !!currentSpec;
1958
1929
  };
1959
1930
 
1960
1931
 
@@ -2132,7 +2103,7 @@ if(window.jasmine || window.mocha) {
2132
2103
  window.inject = angular.mock.inject = function() {
2133
2104
  var blockFns = Array.prototype.slice.call(arguments, 0);
2134
2105
  var errorForStack = new Error('Declaration Location');
2135
- return isSpecRunning() ? workFn() : workFn;
2106
+ return isSpecRunning() ? workFn.call(currentSpec) : workFn;
2136
2107
  /////////////////////
2137
2108
  function workFn() {
2138
2109
  var modules = currentSpec.$modules || [];
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license AngularJS v1.2.9
2
+ * @license AngularJS v1.2.13
3
3
  * (c) 2010-2014 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
@@ -40,7 +40,7 @@ function shallowClearAndCopy(src, dst) {
40
40
  });
41
41
 
42
42
  for (var key in src) {
43
- if (src.hasOwnProperty(key) && key.charAt(0) !== '$' && key.charAt(1) !== '$') {
43
+ if (src.hasOwnProperty(key) && !(key.charAt(0) === '$' && key.charAt(1) === '$')) {
44
44
  dst[key] = src[key];
45
45
  }
46
46
  }
@@ -392,7 +392,9 @@ angular.module('ngResource', ['ng']).
392
392
  val = params.hasOwnProperty(urlParam) ? params[urlParam] : self.defaults[urlParam];
393
393
  if (angular.isDefined(val) && val !== null) {
394
394
  encodedVal = encodeUriSegment(val);
395
- url = url.replace(new RegExp(":" + urlParam + "(\\W|$)", "g"), encodedVal + "$1");
395
+ url = url.replace(new RegExp(":" + urlParam + "(\\W|$)", "g"), function(match, p1) {
396
+ return encodedVal + p1;
397
+ });
396
398
  } else {
397
399
  url = url.replace(new RegExp("(\/?):" + urlParam + "(\\W|$)", "g"), function(match,
398
400
  leadingSlashes, tail) {
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license AngularJS v1.2.9
2
+ * @license AngularJS v1.2.13
3
3
  * (c) 2010-2014 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
@@ -190,7 +190,7 @@ function $RouteProvider(){
190
190
 
191
191
  path = path
192
192
  .replace(/([().])/g, '\\$1')
193
- .replace(/(\/)?:(\w+)([\?|\*])?/g, function(_, slash, key, option){
193
+ .replace(/(\/)?:(\w+)([\?\*])?/g, function(_, slash, key, option){
194
194
  var optional = option === '?' ? option : null;
195
195
  var star = option === '*' ? option : null;
196
196
  keys.push({ name: key, optional: !!optional });
@@ -350,17 +350,17 @@ function $RouteProvider(){
350
350
  }
351
351
  </file>
352
352
 
353
- <file name="scenario.js">
353
+ <file name="protractorTest.js">
354
354
  it('should load and compile correct template', function() {
355
- element('a:contains("Moby: Ch1")').click();
356
- var content = element('.doc-example-live [ng-view]').text();
355
+ element(by.linkText('Moby: Ch1')).click();
356
+ var content = element(by.css('.doc-example-live [ng-view]')).getText();
357
357
  expect(content).toMatch(/controller\: ChapterCntl/);
358
358
  expect(content).toMatch(/Book Id\: Moby/);
359
359
  expect(content).toMatch(/Chapter Id\: 1/);
360
360
 
361
- element('a:contains("Scarlet")').click();
362
- sleep(2); // promises are not part of scenario waiting
363
- content = element('.doc-example-live [ng-view]').text();
361
+ element(by.partialLinkText('Scarlet')).click();
362
+
363
+ content = element(by.css('.doc-example-live [ng-view]')).getText();
364
364
  expect(content).toMatch(/controller\: BookCntl/);
365
365
  expect(content).toMatch(/Book Id\: Scarlet/);
366
366
  });
@@ -375,7 +375,7 @@ function $RouteProvider(){
375
375
  * @eventType broadcast on root scope
376
376
  * @description
377
377
  * Broadcasted before a route change. At this point the route services starts
378
- * resolving all of the dependencies needed for the route change to occurs.
378
+ * resolving all of the dependencies needed for the route change to occur.
379
379
  * Typically this involves fetching the view template as well as any dependencies
380
380
  * defined in `resolve` route property. Once all of the dependencies are resolved
381
381
  * `$routeChangeSuccess` is fired.
@@ -794,16 +794,17 @@ ngRouteModule.directive('ngView', ngViewFillContentFactory);
794
794
  }
795
795
  </file>
796
796
 
797
- <file name="scenario.js">
797
+ <file name="protractorTest.js">
798
798
  it('should load and compile correct template', function() {
799
- element('a:contains("Moby: Ch1")').click();
800
- var content = element('.doc-example-live [ng-view]').text();
799
+ element(by.linkText('Moby: Ch1')).click();
800
+ var content = element(by.css('.doc-example-live [ng-view]')).getText();
801
801
  expect(content).toMatch(/controller\: ChapterCntl/);
802
802
  expect(content).toMatch(/Book Id\: Moby/);
803
803
  expect(content).toMatch(/Chapter Id\: 1/);
804
804
 
805
- element('a:contains("Scarlet")').click();
806
- content = element('.doc-example-live [ng-view]').text();
805
+ element(by.partialLinkText('Scarlet')).click();
806
+
807
+ content = element(by.css('.doc-example-live [ng-view]')).getText();
807
808
  expect(content).toMatch(/controller\: BookCntl/);
808
809
  expect(content).toMatch(/Book Id\: Scarlet/);
809
810
  });
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license AngularJS v1.2.9
2
+ * @license AngularJS v1.2.13
3
3
  * (c) 2010-2014 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
@@ -104,35 +104,37 @@ var $sanitizeMinErr = angular.$$minErr('$sanitize');
104
104
  </table>
105
105
  </div>
106
106
  </doc:source>
107
- <doc:scenario>
107
+ <doc:protractor>
108
108
  it('should sanitize the html snippet by default', function() {
109
- expect(using('#bind-html-with-sanitize').element('div').html()).
109
+ expect(element(by.css('#bind-html-with-sanitize div')).getInnerHtml()).
110
110
  toBe('<p>an html\n<em>click here</em>\nsnippet</p>');
111
111
  });
112
112
 
113
113
  it('should inline raw snippet if bound to a trusted value', function() {
114
- expect(using('#bind-html-with-trust').element("div").html()).
114
+ expect(element(by.css('#bind-html-with-trust div')).getInnerHtml()).
115
115
  toBe("<p style=\"color:blue\">an html\n" +
116
116
  "<em onmouseover=\"this.textContent='PWN3D!'\">click here</em>\n" +
117
117
  "snippet</p>");
118
118
  });
119
119
 
120
120
  it('should escape snippet without any filter', function() {
121
- expect(using('#bind-default').element('div').html()).
121
+ expect(element(by.css('#bind-default div')).getInnerHtml()).
122
122
  toBe("&lt;p style=\"color:blue\"&gt;an html\n" +
123
123
  "&lt;em onmouseover=\"this.textContent='PWN3D!'\"&gt;click here&lt;/em&gt;\n" +
124
124
  "snippet&lt;/p&gt;");
125
125
  });
126
126
 
127
127
  it('should update', function() {
128
- input('snippet').enter('new <b onclick="alert(1)">text</b>');
129
- expect(using('#bind-html-with-sanitize').element('div').html()).toBe('new <b>text</b>');
130
- expect(using('#bind-html-with-trust').element('div').html()).toBe(
128
+ element(by.model('snippet')).clear();
129
+ element(by.model('snippet')).sendKeys('new <b onclick="alert(1)">text</b>');
130
+ expect(element(by.css('#bind-html-with-sanitize div')).getInnerHtml()).
131
+ toBe('new <b>text</b>');
132
+ expect(element(by.css('#bind-html-with-trust div')).getInnerHtml()).toBe(
131
133
  'new <b onclick="alert(1)">text</b>');
132
- expect(using('#bind-default').element('div').html()).toBe(
134
+ expect(element(by.css('#bind-default div')).getInnerHtml()).toBe(
133
135
  "new &lt;b onclick=\"alert(1)\"&gt;text&lt;/b&gt;");
134
136
  });
135
- </doc:scenario>
137
+ </doc:protractor>
136
138
  </doc:example>
137
139
  */
138
140
  function $SanitizeProvider() {
@@ -537,37 +539,38 @@ angular.module('ngSanitize', []).provider('$sanitize', $SanitizeProvider);
537
539
  </tr>
538
540
  </table>
539
541
  </doc:source>
540
- <doc:scenario>
542
+ <doc:protractor>
541
543
  it('should linkify the snippet with urls', function() {
542
- expect(using('#linky-filter').binding('snippet | linky')).
543
- toBe('Pretty text with some links:&#10;' +
544
- '<a href="http://angularjs.org/">http://angularjs.org/</a>,&#10;' +
545
- '<a href="mailto:us@somewhere.org">us@somewhere.org</a>,&#10;' +
546
- '<a href="mailto:another@somewhere.org">another@somewhere.org</a>,&#10;' +
547
- 'and one more: <a href="ftp://127.0.0.1/">ftp://127.0.0.1/</a>.');
544
+ expect(element(by.id('linky-filter')).element(by.binding('snippet | linky')).getText()).
545
+ toBe('Pretty text with some links: http://angularjs.org/, us@somewhere.org, ' +
546
+ 'another@somewhere.org, and one more: ftp://127.0.0.1/.');
547
+ expect(element.all(by.css('#linky-filter a')).count()).toEqual(4);
548
548
  });
549
549
 
550
- it ('should not linkify snippet without the linky filter', function() {
551
- expect(using('#escaped-html').binding('snippet')).
552
- toBe("Pretty text with some links:\n" +
553
- "http://angularjs.org/,\n" +
554
- "mailto:us@somewhere.org,\n" +
555
- "another@somewhere.org,\n" +
556
- "and one more: ftp://127.0.0.1/.");
550
+ it('should not linkify snippet without the linky filter', function() {
551
+ expect(element(by.id('escaped-html')).element(by.binding('snippet')).getText()).
552
+ toBe('Pretty text with some links: http://angularjs.org/, mailto:us@somewhere.org, ' +
553
+ 'another@somewhere.org, and one more: ftp://127.0.0.1/.');
554
+ expect(element.all(by.css('#escaped-html a')).count()).toEqual(0);
557
555
  });
558
556
 
559
557
  it('should update', function() {
560
- input('snippet').enter('new http://link.');
561
- expect(using('#linky-filter').binding('snippet | linky')).
562
- toBe('new <a href="http://link">http://link</a>.');
563
- expect(using('#escaped-html').binding('snippet')).toBe('new http://link.');
558
+ element(by.model('snippet')).clear();
559
+ element(by.model('snippet')).sendKeys('new http://link.');
560
+ expect(element(by.id('linky-filter')).element(by.binding('snippet | linky')).getText()).
561
+ toBe('new http://link.');
562
+ expect(element.all(by.css('#linky-filter a')).count()).toEqual(1);
563
+ expect(element(by.id('escaped-html')).element(by.binding('snippet')).getText())
564
+ .toBe('new http://link.');
564
565
  });
565
566
 
566
567
  it('should work with the target property', function() {
567
- expect(using('#linky-target').binding("snippetWithTarget | linky:'_blank'")).
568
- toBe('<a target="_blank" href="http://angularjs.org/">http://angularjs.org/</a>');
568
+ expect(element(by.id('linky-target')).
569
+ element(by.binding("snippetWithTarget | linky:'_blank'")).getText()).
570
+ toBe('http://angularjs.org/');
571
+ expect(element(by.css('#linky-target a')).getAttribute('target')).toEqual('_blank');
569
572
  });
570
- </doc:scenario>
573
+ </doc:protractor>
571
574
  </doc:example>
572
575
  */
573
576
  angular.module('ngSanitize').filter('linky', ['$sanitize', function($sanitize) {
@@ -9790,7 +9790,7 @@ if ( typeof module === "object" && module && typeof module.exports === "object"
9790
9790
  })( window );
9791
9791
 
9792
9792
  /**
9793
- * @license AngularJS v1.2.9
9793
+ * @license AngularJS v1.2.13
9794
9794
  * (c) 2010-2014 Google, Inc. http://angularjs.org
9795
9795
  * License: MIT
9796
9796
  */
@@ -9860,7 +9860,7 @@ function minErr(module) {
9860
9860
  return match;
9861
9861
  });
9862
9862
 
9863
- message = message + '\nhttp://errors.angularjs.org/1.2.9/' +
9863
+ message = message + '\nhttp://errors.angularjs.org/1.2.13/' +
9864
9864
  (module ? module + '/' : '') + code;
9865
9865
  for (i = 2; i < arguments.length; i++) {
9866
9866
  message = message + (i == 2 ? '?' : '&') + 'p' + (i-2) + '=' +
@@ -9952,6 +9952,7 @@ function minErr(module) {
9952
9952
  -assertNotHasOwnProperty,
9953
9953
  -getter,
9954
9954
  -getBlockElements,
9955
+ -hasOwnProperty,
9955
9956
 
9956
9957
  */
9957
9958
 
@@ -9967,7 +9968,7 @@ function minErr(module) {
9967
9968
  * @returns {string} Lowercased string.
9968
9969
  */
9969
9970
  var lowercase = function(string){return isString(string) ? string.toLowerCase() : string;};
9970
-
9971
+ var hasOwnProperty = Object.prototype.hasOwnProperty;
9971
9972
 
9972
9973
  /**
9973
9974
  * @ngdoc function
@@ -10063,7 +10064,7 @@ function isArrayLike(obj) {
10063
10064
  * is the value of an object property or an array element and `key` is the object property key or
10064
10065
  * array element index. Specifying a `context` for the function is optional.
10065
10066
  *
10066
- * It is worth nothing that `.forEach` does not iterate over inherited properties because it filters
10067
+ * It is worth noting that `.forEach` does not iterate over inherited properties because it filters
10067
10068
  * using the `hasOwnProperty` method.
10068
10069
  *
10069
10070
  <pre>
@@ -10072,7 +10073,7 @@ function isArrayLike(obj) {
10072
10073
  angular.forEach(values, function(value, key){
10073
10074
  this.push(key + ': ' + value);
10074
10075
  }, log);
10075
- expect(log).toEqual(['name: misko', 'gender:male']);
10076
+ expect(log).toEqual(['name: misko', 'gender: male']);
10076
10077
  </pre>
10077
10078
  *
10078
10079
  * @param {Object|Array} obj Object to iterate over.
@@ -10643,7 +10644,7 @@ function shallowCopy(src, dst) {
10643
10644
  for(var key in src) {
10644
10645
  // shallowCopy is only ever called by $compile nodeLinkFn, which has control over src
10645
10646
  // so we don't need to worry about using our custom hasOwnProperty here
10646
- if (src.hasOwnProperty(key) && key.charAt(0) !== '$' && key.charAt(1) !== '$') {
10647
+ if (src.hasOwnProperty(key) && !(key.charAt(0) === '$' && key.charAt(1) === '$')) {
10647
10648
  dst[key] = src[key];
10648
10649
  }
10649
10650
  }
@@ -11002,6 +11003,7 @@ function encodeUriQuery(val, pctEncodeSpaces) {
11002
11003
  <file name="index.html">
11003
11004
  <div ng-controller="ngAppDemoController">
11004
11005
  I can add: {{a}} + {{b}} = {{ a+b }}
11006
+ </div>
11005
11007
  </file>
11006
11008
  <file name="script.js">
11007
11009
  angular.module('ngAppDemo', []).controller('ngAppDemoController', function($scope) {
@@ -11626,11 +11628,11 @@ function setupModuleLoader(window) {
11626
11628
  * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
11627
11629
  */
11628
11630
  var version = {
11629
- full: '1.2.9', // all of these placeholder strings will be replaced by grunt's
11631
+ full: '1.2.13', // all of these placeholder strings will be replaced by grunt's
11630
11632
  major: 1, // package task
11631
11633
  minor: 2,
11632
- dot: 9,
11633
- codeName: 'enchanted-articulacy'
11634
+ dot: 13,
11635
+ codeName: 'romantic-transclusion'
11634
11636
  };
11635
11637
 
11636
11638
 
@@ -11792,7 +11794,7 @@ function publishExternalAPI(angular){
11792
11794
  * - [`after()`](http://api.jquery.com/after/)
11793
11795
  * - [`append()`](http://api.jquery.com/append/)
11794
11796
  * - [`attr()`](http://api.jquery.com/attr/)
11795
- * - [`bind()`](http://api.jquery.com/on/) - Does not support namespaces, selectors or eventData
11797
+ * - [`bind()`](http://api.jquery.com/bind/) - Does not support namespaces, selectors or eventData
11796
11798
  * - [`children()`](http://api.jquery.com/children/) - Does not support selectors
11797
11799
  * - [`clone()`](http://api.jquery.com/clone/)
11798
11800
  * - [`contents()`](http://api.jquery.com/contents/)
@@ -11819,7 +11821,7 @@ function publishExternalAPI(angular){
11819
11821
  * - [`text()`](http://api.jquery.com/text/)
11820
11822
  * - [`toggleClass()`](http://api.jquery.com/toggleClass/)
11821
11823
  * - [`triggerHandler()`](http://api.jquery.com/triggerHandler/) - Passes a dummy event object to handlers.
11822
- * - [`unbind()`](http://api.jquery.com/off/) - Does not support namespaces
11824
+ * - [`unbind()`](http://api.jquery.com/unbind/) - Does not support namespaces
11823
11825
  * - [`val()`](http://api.jquery.com/val/)
11824
11826
  * - [`wrap()`](http://api.jquery.com/wrap/)
11825
11827
  *
@@ -11859,6 +11861,14 @@ var jqCache = JQLite.cache = {},
11859
11861
  ? function(element, type, fn) {element.removeEventListener(type, fn, false); }
11860
11862
  : function(element, type, fn) {element.detachEvent('on' + type, fn); });
11861
11863
 
11864
+ /*
11865
+ * !!! This is an undocumented "private" function !!!
11866
+ */
11867
+ var jqData = JQLite._data = function(node) {
11868
+ //jQuery always returns an object on cache miss
11869
+ return this.cache[node[this.expando]] || {};
11870
+ };
11871
+
11862
11872
  function jqNextId() { return ++jqId; }
11863
11873
 
11864
11874
 
@@ -11927,6 +11937,9 @@ function JQLite(element) {
11927
11937
  if (element instanceof JQLite) {
11928
11938
  return element;
11929
11939
  }
11940
+ if (isString(element)) {
11941
+ element = trim(element);
11942
+ }
11930
11943
  if (!(this instanceof JQLite)) {
11931
11944
  if (isString(element) && element.charAt(0) != '<') {
11932
11945
  throw jqLiteMinErr('nosel', 'Looking up elements via selectors is not supported by jqLite! See: http://docs.angularjs.org/api/angular.element');
@@ -13072,11 +13085,9 @@ function annotate(fn) {
13072
13085
  * @param {(Object|function())} provider If the provider is:
13073
13086
  *
13074
13087
  * - `Object`: then it should have a `$get` method. The `$get` method will be invoked using
13075
- * {@link AUTO.$injector#invoke $injector.invoke()} when an instance needs to be
13076
- * created.
13077
- * - `Constructor`: a new instance of the provider will be created using
13078
- * {@link AUTO.$injector#instantiate $injector.instantiate()}, then treated as
13079
- * `object`.
13088
+ * {@link AUTO.$injector#invoke $injector.invoke()} when an instance needs to be created.
13089
+ * - `Constructor`: a new instance of the provider will be created using
13090
+ * {@link AUTO.$injector#instantiate $injector.instantiate()}, then treated as `object`.
13080
13091
  *
13081
13092
  * @returns {Object} registered provider instance
13082
13093
 
@@ -13202,17 +13213,16 @@ function annotate(fn) {
13202
13213
  * Here is an example of registering a service using
13203
13214
  * {@link AUTO.$provide#methods_service $provide.service(class)}.
13204
13215
  * <pre>
13205
- * $provide.service('ping', ['$http', function($http) {
13206
- * var Ping = function() {
13207
- * this.$http = $http;
13208
- * };
13209
- *
13210
- * Ping.prototype.send = function() {
13211
- * return this.$http.get('/ping');
13212
- * };
13216
+ * var Ping = function($http) {
13217
+ * this.$http = $http;
13218
+ * };
13219
+ *
13220
+ * Ping.$inject = ['$http'];
13213
13221
  *
13214
- * return Ping;
13215
- * }]);
13222
+ * Ping.prototype.send = function() {
13223
+ * return this.$http.get('/ping');
13224
+ * };
13225
+ * $provide.service('ping', Ping);
13216
13226
  * </pre>
13217
13227
  * You would then inject and use this service like this:
13218
13228
  * <pre>
@@ -13310,7 +13320,7 @@ function annotate(fn) {
13310
13320
  * Here we decorate the {@link ng.$log $log} service to convert warnings to errors by intercepting
13311
13321
  * calls to {@link ng.$log#error $log.warn()}.
13312
13322
  * <pre>
13313
- * $provider.decorator('$log', ['$delegate', function($delegate) {
13323
+ * $provide.decorator('$log', ['$delegate', function($delegate) {
13314
13324
  * $delegate.warn = $delegate.error;
13315
13325
  * return $delegate;
13316
13326
  * }]);
@@ -13849,6 +13859,29 @@ var $AnimateProvider = ['$provide', function($provide) {
13849
13859
  done && $timeout(done, 0, false);
13850
13860
  },
13851
13861
 
13862
+ /**
13863
+ *
13864
+ * @ngdoc function
13865
+ * @name ng.$animate#setClass
13866
+ * @methodOf ng.$animate
13867
+ * @function
13868
+ * @description Adds and/or removes the given CSS classes to and from the element.
13869
+ * Once complete, the done() callback will be fired (if provided).
13870
+ * @param {jQuery/jqLite element} element the element which will it's CSS classes changed
13871
+ * removed from it
13872
+ * @param {string} add the CSS classes which will be added to the element
13873
+ * @param {string} remove the CSS class which will be removed from the element
13874
+ * @param {function=} done the callback function (if provided) that will be fired after the
13875
+ * CSS classes have been set on the element
13876
+ */
13877
+ setClass : function(element, add, remove, done) {
13878
+ forEach(element, function (element) {
13879
+ jqLiteAddClass(element, add);
13880
+ jqLiteRemoveClass(element, remove);
13881
+ });
13882
+ done && $timeout(done, 0, false);
13883
+ },
13884
+
13852
13885
  enabled : noop
13853
13886
  };
13854
13887
  }];
@@ -14913,13 +14946,17 @@ function $TemplateCacheProvider() {
14913
14946
  <div compile="html"></div>
14914
14947
  </div>
14915
14948
  </doc:source>
14916
- <doc:scenario>
14949
+ <doc:protractor>
14917
14950
  it('should auto compile', function() {
14918
- expect(element('div[compile]').text()).toBe('Hello Angular');
14919
- input('html').enter('{{name}}!');
14920
- expect(element('div[compile]').text()).toBe('Angular!');
14951
+ var textarea = $('textarea');
14952
+ var output = $('div[compile]');
14953
+ // The initial state reads 'Hello Angular'.
14954
+ expect(output.getText()).toBe('Hello Angular');
14955
+ textarea.clear();
14956
+ textarea.sendKeys('{{name}}!');
14957
+ expect(output.getText()).toBe('Angular!');
14921
14958
  });
14922
- </doc:scenario>
14959
+ </doc:protractor>
14923
14960
  </doc:example>
14924
14961
 
14925
14962
  *
@@ -14987,7 +15024,8 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
14987
15024
  var hasDirectives = {},
14988
15025
  Suffix = 'Directive',
14989
15026
  COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\d\w\-_]+)\s+(.*)$/,
14990
- CLASS_DIRECTIVE_REGEXP = /(([\d\w\-_]+)(?:\:([^;]+))?;?)/;
15027
+ CLASS_DIRECTIVE_REGEXP = /(([\d\w\-_]+)(?:\:([^;]+))?;?)/,
15028
+ TABLE_CONTENT_REGEXP = /^<\s*(tr|th|td|tbody)(\s+[^>]*)?>/i;
14991
15029
 
14992
15030
  // Ref: http://developers.whatwg.org/webappapis.html#event-handler-idl-attributes
14993
15031
  // The assumption is that future DOM event attribute names will begin with
@@ -15174,8 +15212,16 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
15174
15212
  * @param {string} oldClasses The former CSS className value
15175
15213
  */
15176
15214
  $updateClass : function(newClasses, oldClasses) {
15177
- this.$removeClass(tokenDifference(oldClasses, newClasses));
15178
- this.$addClass(tokenDifference(newClasses, oldClasses));
15215
+ var toAdd = tokenDifference(newClasses, oldClasses);
15216
+ var toRemove = tokenDifference(oldClasses, newClasses);
15217
+
15218
+ if(toAdd.length === 0) {
15219
+ $animate.removeClass(this.$$element, toRemove);
15220
+ } else if(toRemove.length === 0) {
15221
+ $animate.addClass(this.$$element, toAdd);
15222
+ } else {
15223
+ $animate.setClass(this.$$element, toAdd, toRemove);
15224
+ }
15179
15225
  },
15180
15226
 
15181
15227
  /**
@@ -15627,7 +15673,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
15627
15673
  templateDirective = previousCompileContext.templateDirective,
15628
15674
  nonTlbTranscludeDirective = previousCompileContext.nonTlbTranscludeDirective,
15629
15675
  hasTranscludeDirective = false,
15630
- hasElementTranscludeDirective = false,
15676
+ hasElementTranscludeDirective = previousCompileContext.hasElementTranscludeDirective,
15631
15677
  $compileNode = templateAttrs.$$element = jqLite(compileNode),
15632
15678
  directive,
15633
15679
  directiveName,
@@ -15681,7 +15727,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
15681
15727
  hasTranscludeDirective = true;
15682
15728
 
15683
15729
  // Special case ngIf and ngRepeat so that we don't complain about duplicate transclusion.
15684
- // This option should only be used by directives that know how to how to safely handle element transclusion,
15730
+ // This option should only be used by directives that know how to safely handle element transclusion,
15685
15731
  // where the transcluded nodes are added or replaced after linking.
15686
15732
  if (!directive.$$tlb) {
15687
15733
  assertNoDuplicate('transclusion', nonTlbTranscludeDirective, directive, $compileNode);
@@ -15728,9 +15774,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
15728
15774
 
15729
15775
  if (directive.replace) {
15730
15776
  replaceDirective = directive;
15731
- $template = jqLite('<div>' +
15732
- trim(directiveValue) +
15733
- '</div>').contents();
15777
+ $template = directiveTemplateContents(directiveValue);
15734
15778
  compileNode = $template[0];
15735
15779
 
15736
15780
  if ($template.length != 1 || compileNode.nodeType !== 1) {
@@ -15801,6 +15845,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
15801
15845
 
15802
15846
  nodeLinkFn.scope = newScopeDirective && newScopeDirective.scope === true;
15803
15847
  nodeLinkFn.transclude = hasTranscludeDirective && childTranscludeFn;
15848
+ previousCompileContext.hasElementTranscludeDirective = hasElementTranscludeDirective;
15804
15849
 
15805
15850
  // might be normal or delayed nodeLinkFn depending on if templateUrl is present
15806
15851
  return nodeLinkFn;
@@ -16128,6 +16173,28 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
16128
16173
  }
16129
16174
 
16130
16175
 
16176
+ function directiveTemplateContents(template) {
16177
+ var type;
16178
+ template = trim(template);
16179
+ if ((type = TABLE_CONTENT_REGEXP.exec(template))) {
16180
+ type = type[1].toLowerCase();
16181
+ var table = jqLite('<table>' + template + '</table>'),
16182
+ tbody = table.children('tbody'),
16183
+ leaf = /(td|th)/.test(type) && table.find('tr');
16184
+ if (tbody.length && type !== 'tbody') {
16185
+ table = tbody;
16186
+ }
16187
+ if (leaf && leaf.length) {
16188
+ table = leaf;
16189
+ }
16190
+ return table.contents();
16191
+ }
16192
+ return jqLite('<div>' +
16193
+ template +
16194
+ '</div>').contents();
16195
+ }
16196
+
16197
+
16131
16198
  function compileTemplateUrl(directives, $compileNode, tAttrs,
16132
16199
  $rootElement, childTranscludeFn, preLinkFns, postLinkFns, previousCompileContext) {
16133
16200
  var linkQueue = [],
@@ -16152,7 +16219,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
16152
16219
  content = denormalizeTemplate(content);
16153
16220
 
16154
16221
  if (origAsyncDirective.replace) {
16155
- $template = jqLite('<div>' + trim(content) + '</div>').contents();
16222
+ $template = directiveTemplateContents(content);
16156
16223
  compileNode = $template[0];
16157
16224
 
16158
16225
  if ($template.length != 1 || compileNode.nodeType !== 1) {
@@ -16196,9 +16263,18 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
16196
16263
  linkNode = $compileNode[0];
16197
16264
 
16198
16265
  if (beforeTemplateLinkNode !== beforeTemplateCompileNode) {
16199
- // it was cloned therefore we have to clone as well.
16200
- linkNode = jqLiteClone(compileNode);
16266
+ var oldClasses = beforeTemplateLinkNode.className;
16267
+
16268
+ if (!(previousCompileContext.hasElementTranscludeDirective &&
16269
+ origAsyncDirective.replace)) {
16270
+ // it was cloned therefore we have to clone as well.
16271
+ linkNode = jqLiteClone(compileNode);
16272
+ }
16273
+
16201
16274
  replaceWith(linkRootElement, jqLite(beforeTemplateLinkNode), linkNode);
16275
+
16276
+ // Copy in CSS classes from original node
16277
+ safeAddClass(jqLite(linkNode), oldClasses);
16202
16278
  }
16203
16279
  if (afterTemplateNodeLinkFn.transclude) {
16204
16280
  childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude);
@@ -16855,31 +16931,14 @@ function $HttpProvider() {
16855
16931
  * XMLHttpRequest will transparently follow it, meaning that the error callback will not be
16856
16932
  * called for such responses.
16857
16933
  *
16858
- * # Calling $http from outside AngularJS
16859
- * The `$http` service will not actually send the request until the next `$digest()` is
16860
- * executed. Normally this is not an issue, since almost all the time your call to `$http` will
16861
- * be from within a `$apply()` block.
16862
- * If you are calling `$http` from outside Angular, then you should wrap it in a call to
16863
- * `$apply` to cause a $digest to occur and also to handle errors in the block correctly.
16864
- *
16865
- * ```
16866
- * $scope.$apply(function() {
16867
- * $http(...);
16868
- * });
16869
- * ```
16870
- *
16871
16934
  * # Writing Unit Tests that use $http
16872
- * When unit testing you are mostly responsible for scheduling the `$digest` cycle. If you do
16873
- * not trigger a `$digest` before calling `$httpBackend.flush()` then the request will not have
16874
- * been made and `$httpBackend.expect(...)` expectations will fail. The solution is to run the
16875
- * code that calls the `$http()` method inside a $apply block as explained in the previous
16876
- * section.
16935
+ * When unit testing (using {@link api/ngMock ngMock}), it is necessary to call
16936
+ * {@link api/ngMock.$httpBackend#methods_flush $httpBackend.flush()} to flush each pending
16937
+ * request using trained responses.
16877
16938
  *
16878
16939
  * ```
16879
16940
  * $httpBackend.expectGET(...);
16880
- * $scope.$apply(function() {
16881
- * $http.get(...);
16882
- * });
16941
+ * $http.get(...);
16883
16942
  * $httpBackend.flush();
16884
16943
  * ```
16885
16944
  *
@@ -17236,14 +17295,14 @@ function $HttpProvider() {
17236
17295
  <option>JSONP</option>
17237
17296
  </select>
17238
17297
  <input type="text" ng-model="url" size="80"/>
17239
- <button ng-click="fetch()">fetch</button><br>
17240
- <button ng-click="updateModel('GET', 'http-hello.html')">Sample GET</button>
17241
- <button
17298
+ <button id="fetchbtn" ng-click="fetch()">fetch</button><br>
17299
+ <button id="samplegetbtn" ng-click="updateModel('GET', 'http-hello.html')">Sample GET</button>
17300
+ <button id="samplejsonpbtn"
17242
17301
  ng-click="updateModel('JSONP',
17243
17302
  'http://angularjs.org/greet.php?callback=JSON_CALLBACK&name=Super%20Hero')">
17244
17303
  Sample JSONP
17245
17304
  </button>
17246
- <button
17305
+ <button id="invalidjsonpbtn"
17247
17306
  ng-click="updateModel('JSONP', 'http://angularjs.org/doesntexist&callback=JSON_CALLBACK')">
17248
17307
  Invalid JSONP
17249
17308
  </button>
@@ -17280,27 +17339,34 @@ function $HttpProvider() {
17280
17339
  <file name="http-hello.html">
17281
17340
  Hello, $http!
17282
17341
  </file>
17283
- <file name="scenario.js">
17342
+ <file name="protractorTest.js">
17343
+ var status = element(by.binding('status'));
17344
+ var data = element(by.binding('data'));
17345
+ var fetchBtn = element(by.id('fetchbtn'));
17346
+ var sampleGetBtn = element(by.id('samplegetbtn'));
17347
+ var sampleJsonpBtn = element(by.id('samplejsonpbtn'));
17348
+ var invalidJsonpBtn = element(by.id('invalidjsonpbtn'));
17349
+
17284
17350
  it('should make an xhr GET request', function() {
17285
- element(':button:contains("Sample GET")').click();
17286
- element(':button:contains("fetch")').click();
17287
- expect(binding('status')).toBe('200');
17288
- expect(binding('data')).toMatch(/Hello, \$http!/);
17351
+ sampleGetBtn.click();
17352
+ fetchBtn.click();
17353
+ expect(status.getText()).toMatch('200');
17354
+ expect(data.getText()).toMatch(/Hello, \$http!/)
17289
17355
  });
17290
17356
 
17291
17357
  it('should make a JSONP request to angularjs.org', function() {
17292
- element(':button:contains("Sample JSONP")').click();
17293
- element(':button:contains("fetch")').click();
17294
- expect(binding('status')).toBe('200');
17295
- expect(binding('data')).toMatch(/Super Hero!/);
17358
+ sampleJsonpBtn.click();
17359
+ fetchBtn.click();
17360
+ expect(status.getText()).toMatch('200');
17361
+ expect(data.getText()).toMatch(/Super Hero!/);
17296
17362
  });
17297
17363
 
17298
17364
  it('should make JSONP request to invalid URL and invoke the error handler',
17299
17365
  function() {
17300
- element(':button:contains("Invalid JSONP")').click();
17301
- element(':button:contains("fetch")').click();
17302
- expect(binding('status')).toBe('0');
17303
- expect(binding('data')).toBe('Request failed');
17366
+ invalidJsonpBtn.click();
17367
+ fetchBtn.click();
17368
+ expect(status.getText()).toMatch('0');
17369
+ expect(data.getText()).toMatch('Request failed');
17304
17370
  });
17305
17371
  </file>
17306
17372
  </example>
@@ -17682,13 +17748,18 @@ function $HttpProvider() {
17682
17748
  }
17683
17749
 
17684
17750
  function createXhr(method) {
17685
- // IE8 doesn't support PATCH method, but the ActiveX object does
17686
- /* global ActiveXObject */
17687
- return (msie <= 8 && lowercase(method) === 'patch')
17688
- ? new ActiveXObject('Microsoft.XMLHTTP')
17689
- : new window.XMLHttpRequest();
17690
- }
17751
+ //if IE and the method is not RFC2616 compliant, or if XMLHttpRequest
17752
+ //is not available, try getting an ActiveXObject. Otherwise, use XMLHttpRequest
17753
+ //if it is available
17754
+ if (msie <= 8 && (!method.match(/^(get|post|head|put|delete|options)$/i) ||
17755
+ !window.XMLHttpRequest)) {
17756
+ return new window.ActiveXObject("Microsoft.XMLHTTP");
17757
+ } else if (window.XMLHttpRequest) {
17758
+ return new window.XMLHttpRequest();
17759
+ }
17691
17760
 
17761
+ throw minErr('$httpBackend')('noxhr', "This browser does not support XMLHttpRequest.");
17762
+ }
17692
17763
 
17693
17764
  /**
17694
17765
  * @ngdoc object
@@ -17783,7 +17854,20 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
17783
17854
  }
17784
17855
 
17785
17856
  if (responseType) {
17786
- xhr.responseType = responseType;
17857
+ try {
17858
+ xhr.responseType = responseType;
17859
+ } catch (e) {
17860
+ // WebKit added support for the json responseType value on 09/03/2013
17861
+ // https://bugs.webkit.org/show_bug.cgi?id=73648. Versions of Safari prior to 7 are
17862
+ // known to throw when setting the value "json" as the response type. Other older
17863
+ // browsers implementing the responseType
17864
+ //
17865
+ // The json response type can be ignored if not supported, because JSON payloads are
17866
+ // parsed on the client-side regardless.
17867
+ if (responseType !== 'json') {
17868
+ throw e;
17869
+ }
17870
+ }
17787
17871
  }
17788
17872
 
17789
17873
  xhr.send(post || null);
@@ -17882,11 +17966,11 @@ var $interpolateMinErr = minErr('$interpolate');
17882
17966
  //demo.label//
17883
17967
  </div>
17884
17968
  </doc:source>
17885
- <doc:scenario>
17886
- it('should interpolate binding with custom symbols', function() {
17887
- expect(binding('demo.label')).toBe('This binding is brought you by // interpolation symbols.');
17888
- });
17889
- </doc:scenario>
17969
+ <doc:protractor>
17970
+ it('should interpolate binding with custom symbols', function() {
17971
+ expect(element(by.binding('demo.label')).getText()).toBe('This binding is brought you by // interpolation symbols.');
17972
+ });
17973
+ </doc:protractor>
17890
17974
  </doc:example>
17891
17975
  */
17892
17976
  function $InterpolateProvider() {
@@ -18078,7 +18162,7 @@ function $InterpolateProvider() {
18078
18162
  * @description
18079
18163
  * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
18080
18164
  *
18081
- * Use {@link ng.$interpolateProvider#endSymbol $interpolateProvider#endSymbol} to change
18165
+ * Use {@link ng.$interpolateProvider#methods_endSymbol $interpolateProvider#endSymbol} to change
18082
18166
  * the symbol.
18083
18167
  *
18084
18168
  * @returns {string} start symbol.
@@ -18114,7 +18198,7 @@ function $IntervalProvider() {
18114
18198
  * In tests you can use {@link ngMock.$interval#methods_flush `$interval.flush(millis)`} to
18115
18199
  * move forward by `millis` milliseconds and trigger any functions scheduled to run in that
18116
18200
  * time.
18117
- *
18201
+ *
18118
18202
  * <div class="alert alert-warning">
18119
18203
  * **Note**: Intervals created by this service must be explicitly destroyed when you are finished
18120
18204
  * with them. In particular they are not automatically destroyed when a controller's scope or a
@@ -18227,8 +18311,8 @@ function $IntervalProvider() {
18227
18311
  promise = deferred.promise,
18228
18312
  iteration = 0,
18229
18313
  skipApply = (isDefined(invokeApply) && !invokeApply);
18230
-
18231
- count = isDefined(count) ? count : 0,
18314
+
18315
+ count = isDefined(count) ? count : 0;
18232
18316
 
18233
18317
  promise.then(null, null, fn);
18234
18318
 
@@ -18922,7 +19006,7 @@ function $LocationProvider(){
18922
19006
  * @eventType broadcast on root scope
18923
19007
  * @description
18924
19008
  * Broadcasted before a URL will change. This change can be prevented by calling
18925
- * `preventDefault` method of the event. See {@link ng.$rootScope.Scope#$on} for more
19009
+ * `preventDefault` method of the event. See {@link ng.$rootScope.Scope#methods_$on} for more
18926
19010
  * details about event object. Upon successful change
18927
19011
  * {@link ng.$location#events_$locationChangeSuccess $locationChangeSuccess} is fired.
18928
19012
  *
@@ -19105,7 +19189,7 @@ function $LogProvider(){
19105
19189
  * @name ng.$logProvider#debugEnabled
19106
19190
  * @methodOf ng.$logProvider
19107
19191
  * @description
19108
- * @param {string=} flag enable or disable debug level messages
19192
+ * @param {boolean=} flag enable or disable debug level messages
19109
19193
  * @returns {*} current value if used as getter or itself (chaining) if used as setter
19110
19194
  */
19111
19195
  this.debugEnabled = function(flag) {
@@ -19928,7 +20012,7 @@ Parser.prototype = {
19928
20012
  var getter = getterFn(field, this.options, this.text);
19929
20013
 
19930
20014
  return extend(function(scope, locals, self) {
19931
- return getter(self || object(scope, locals), locals);
20015
+ return getter(self || object(scope, locals));
19932
20016
  }, {
19933
20017
  assign: function(scope, value, locals) {
19934
20018
  return setter(object(scope, locals), field, value, parser.text, parser.options);
@@ -20504,9 +20588,9 @@ function $ParseProvider() {
20504
20588
  * asynchronous programming what `try`, `catch` and `throw` keywords are to synchronous programming.
20505
20589
  *
20506
20590
  * <pre>
20507
- * // for the purpose of this example let's assume that variables `$q` and `scope` are
20508
- * // available in the current lexical scope (they could have been injected or passed in).
20509
- *
20591
+ * // for the purpose of this example let's assume that variables `$q`, `scope` and `okToGreet`
20592
+ * // are available in the current lexical scope (they could have been injected or passed in).
20593
+ *
20510
20594
  * function asyncGreet(name) {
20511
20595
  * var deferred = $q.defer();
20512
20596
  *
@@ -20561,7 +20645,7 @@ function $ParseProvider() {
20561
20645
  * constructed via `$q.reject`, the promise will be rejected instead.
20562
20646
  * - `reject(reason)` – rejects the derived promise with the `reason`. This is equivalent to
20563
20647
  * resolving it with a rejection constructed via `$q.reject`.
20564
- * - `notify(value)` - provides updates on the status of the promises execution. This may be called
20648
+ * - `notify(value)` - provides updates on the status of the promise's execution. This may be called
20565
20649
  * multiple times before the promise is either resolved or rejected.
20566
20650
  *
20567
20651
  * **Properties**
@@ -20711,7 +20795,7 @@ function qFactory(nextTick, exceptionHandler) {
20711
20795
 
20712
20796
 
20713
20797
  reject: function(reason) {
20714
- deferred.resolve(reject(reason));
20798
+ deferred.resolve(createInternalRejectedPromise(reason));
20715
20799
  },
20716
20800
 
20717
20801
 
@@ -20868,6 +20952,12 @@ function qFactory(nextTick, exceptionHandler) {
20868
20952
  * @returns {Promise} Returns a promise that was already resolved as rejected with the `reason`.
20869
20953
  */
20870
20954
  var reject = function(reason) {
20955
+ var result = defer();
20956
+ result.reject(reason);
20957
+ return result.promise;
20958
+ };
20959
+
20960
+ var createInternalRejectedPromise = function(reason) {
20871
20961
  return {
20872
20962
  then: function(callback, errback) {
20873
20963
  var result = defer();
@@ -21928,7 +22018,7 @@ function $RootScopeProvider(){
21928
22018
  * onto the {@link ng.$exceptionHandler $exceptionHandler} service.
21929
22019
  *
21930
22020
  * @param {string} name Event name to emit.
21931
- * @param {...*} args Optional set of arguments which will be passed onto the event listeners.
22021
+ * @param {...*} args Optional one or more arguments which will be passed onto the event listeners.
21932
22022
  * @return {Object} Event object (see {@link ng.$rootScope.Scope#methods_$on}).
21933
22023
  */
21934
22024
  $emit: function(name, args) {
@@ -21996,7 +22086,7 @@ function $RootScopeProvider(){
21996
22086
  * onto the {@link ng.$exceptionHandler $exceptionHandler} service.
21997
22087
  *
21998
22088
  * @param {string} name Event name to broadcast.
21999
- * @param {...*} args Optional set of arguments which will be passed onto the event listeners.
22089
+ * @param {...*} args Optional one or more arguments which will be passed onto the event listeners.
22000
22090
  * @return {Object} Event object, see {@link ng.$rootScope.Scope#methods_$on}
22001
22091
  */
22002
22092
  $broadcast: function(name, args) {
@@ -22439,7 +22529,7 @@ function $SceDelegateProvider() {
22439
22529
  *
22440
22530
  * @description
22441
22531
  * Returns an object that is trusted by angular for use in specified strict
22442
- * contextual escaping contexts (such as ng-html-bind-unsafe, ng-include, any src
22532
+ * contextual escaping contexts (such as ng-bind-html, ng-include, any src
22443
22533
  * attribute interpolation, any dom event binding attribute interpolation
22444
22534
  * such as for onclick, etc.) that uses the provided value.
22445
22535
  * See {@link ng.$sce $sce} for enabling strict contextual escaping.
@@ -22666,8 +22756,8 @@ function $SceDelegateProvider() {
22666
22756
  * It's important to remember that SCE only applies to interpolation expressions.
22667
22757
  *
22668
22758
  * If your expressions are constant literals, they're automatically trusted and you don't need to
22669
- * call `$sce.trustAs` on them. (e.g.
22670
- * `<div ng-html-bind-unsafe="'<b>implicitly trusted</b>'"></div>`) just works.
22759
+ * call `$sce.trustAs` on them (remember to include the `ngSanitize` module) (e.g.
22760
+ * `<div ng-bind-html="'<b>implicitly trusted</b>'"></div>`) just works.
22671
22761
  *
22672
22762
  * Additionally, `a[href]` and `img[src]` automatically sanitize their URLs and do not pass them
22673
22763
  * through {@link ng.$sce#methods_getTrusted $sce.getTrusted}. SCE doesn't play a role here.
@@ -22727,7 +22817,7 @@ function $SceDelegateProvider() {
22727
22817
  * matched against the **entire** *normalized / absolute URL* of the resource being tested
22728
22818
  * (even when the RegExp did not have the `^` and `$` codes.) In addition, any flags
22729
22819
  * present on the RegExp (such as multiline, global, ignoreCase) are ignored.
22730
- * - If you are generating your Javascript from some other templating engine (not
22820
+ * - If you are generating your JavaScript from some other templating engine (not
22731
22821
  * recommended, e.g. in issue [#4006](https://github.com/angular/angular.js/issues/4006)),
22732
22822
  * remember to escape your regular expression (and be aware that you might need more than
22733
22823
  * one level of escaping depending on your templating engine and the way you interpolated
@@ -22744,7 +22834,7 @@ function $SceDelegateProvider() {
22744
22834
  * ## Show me an example using SCE.
22745
22835
  *
22746
22836
  * @example
22747
- <example module="mySceApp">
22837
+ <example module="mySceApp" deps="angular-sanitize.js">
22748
22838
  <file name="index.html">
22749
22839
  <div ng-controller="myAppController as myCtrl">
22750
22840
  <i ng-bind-html="myCtrl.explicitlyTrustedHtml" id="explicitlyTrustedHtml"></i><br><br>
@@ -22788,13 +22878,15 @@ function $SceDelegateProvider() {
22788
22878
  ]
22789
22879
  </file>
22790
22880
 
22791
- <file name="scenario.js">
22881
+ <file name="protractorTest.js">
22792
22882
  describe('SCE doc demo', function() {
22793
22883
  it('should sanitize untrusted values', function() {
22794
- expect(element('.htmlComment').html()).toBe('<span>Is <i>anyone</i> reading this?</span>');
22884
+ expect(element(by.css('.htmlComment')).getInnerHtml())
22885
+ .toBe('<span>Is <i>anyone</i> reading this?</span>');
22795
22886
  });
22887
+
22796
22888
  it('should NOT sanitize explicitly trusted values', function() {
22797
- expect(element('#explicitlyTrustedHtml').html()).toBe(
22889
+ expect(element(by.id('explicitlyTrustedHtml')).getInnerHtml()).toBe(
22798
22890
  '<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
22799
22891
  'sanitization.&quot;">Hover over this text.</span>');
22800
22892
  });
@@ -22969,8 +23061,8 @@ function $SceProvider() {
22969
23061
  *
22970
23062
  * @description
22971
23063
  * Delegates to {@link ng.$sceDelegate#methods_trustAs `$sceDelegate.trustAs`}. As such,
22972
- * returns an objectthat is trusted by angular for use in specified strict contextual
22973
- * escaping contexts (such as ng-html-bind-unsafe, ng-include, any src attribute
23064
+ * returns an object that is trusted by angular for use in specified strict contextual
23065
+ * escaping contexts (such as ng-bind-html, ng-include, any src attribute
22974
23066
  * interpolation, any dom event binding attribute interpolation such as for onclick, etc.)
22975
23067
  * that uses the provided value. See * {@link ng.$sce $sce} for enabling strict contextual
22976
23068
  * escaping.
@@ -23553,13 +23645,13 @@ function urlIsSameOrigin(requestUrl) {
23553
23645
  <button ng-click="doGreeting(greeting)">ALERT</button>
23554
23646
  </div>
23555
23647
  </doc:source>
23556
- <doc:scenario>
23648
+ <doc:protractor>
23557
23649
  it('should display the greeting in the input box', function() {
23558
- input('greeting').enter('Hello, E2E Tests');
23650
+ element(by.model('greeting')).sendKeys('Hello, E2E Tests');
23559
23651
  // If we click the button it will block the test runner
23560
23652
  // element(':button').click();
23561
23653
  });
23562
- </doc:scenario>
23654
+ </doc:protractor>
23563
23655
  </doc:example>
23564
23656
  */
23565
23657
  function $WindowProvider(){
@@ -23768,35 +23860,47 @@ function $FilterProvider($provide) {
23768
23860
  Equality <input type="checkbox" ng-model="strict"><br>
23769
23861
  <table id="searchObjResults">
23770
23862
  <tr><th>Name</th><th>Phone</th></tr>
23771
- <tr ng-repeat="friend in friends | filter:search:strict">
23772
- <td>{{friend.name}}</td>
23773
- <td>{{friend.phone}}</td>
23863
+ <tr ng-repeat="friendObj in friends | filter:search:strict">
23864
+ <td>{{friendObj.name}}</td>
23865
+ <td>{{friendObj.phone}}</td>
23774
23866
  </tr>
23775
23867
  </table>
23776
23868
  </doc:source>
23777
- <doc:scenario>
23778
- it('should search across all fields when filtering with a string', function() {
23779
- input('searchText').enter('m');
23780
- expect(repeater('#searchTextResults tr', 'friend in friends').column('friend.name')).
23781
- toEqual(['Mary', 'Mike', 'Adam']);
23869
+ <doc:protractor>
23870
+ var expectFriendNames = function(expectedNames, key) {
23871
+ element.all(by.repeater(key + ' in friends').column(key + '.name')).then(function(arr) {
23872
+ arr.forEach(function(wd, i) {
23873
+ expect(wd.getText()).toMatch(expectedNames[i]);
23874
+ });
23875
+ });
23876
+ };
23782
23877
 
23783
- input('searchText').enter('76');
23784
- expect(repeater('#searchTextResults tr', 'friend in friends').column('friend.name')).
23785
- toEqual(['John', 'Julie']);
23878
+ it('should search across all fields when filtering with a string', function() {
23879
+ var searchText = element(by.model('searchText'));
23880
+ searchText.clear();
23881
+ searchText.sendKeys('m');
23882
+ expectFriendNames(['Mary', 'Mike', 'Adam'], 'friend');
23883
+
23884
+ searchText.clear();
23885
+ searchText.sendKeys('76');
23886
+ expectFriendNames(['John', 'Julie'], 'friend');
23786
23887
  });
23787
23888
 
23788
23889
  it('should search in specific fields when filtering with a predicate object', function() {
23789
- input('search.$').enter('i');
23790
- expect(repeater('#searchObjResults tr', 'friend in friends').column('friend.name')).
23791
- toEqual(['Mary', 'Mike', 'Julie', 'Juliette']);
23890
+ var searchAny = element(by.model('search.$'));
23891
+ searchAny.clear();
23892
+ searchAny.sendKeys('i');
23893
+ expectFriendNames(['Mary', 'Mike', 'Julie', 'Juliette'], 'friendObj');
23792
23894
  });
23793
23895
  it('should use a equal comparison when comparator is true', function() {
23794
- input('search.name').enter('Julie');
23795
- input('strict').check();
23796
- expect(repeater('#searchObjResults tr', 'friend in friends').column('friend.name')).
23797
- toEqual(['Julie']);
23896
+ var searchName = element(by.model('search.name'));
23897
+ var strict = element(by.model('strict'));
23898
+ searchName.clear();
23899
+ searchName.sendKeys('Julie');
23900
+ strict.click();
23901
+ expectFriendNames(['Julie'], 'friendObj');
23798
23902
  });
23799
- </doc:scenario>
23903
+ </doc:protractor>
23800
23904
  </doc:example>
23801
23905
  */
23802
23906
  function filterFilter() {
@@ -23822,6 +23926,15 @@ function filterFilter() {
23822
23926
  };
23823
23927
  } else {
23824
23928
  comparator = function(obj, text) {
23929
+ if (obj && text && typeof obj === 'object' && typeof text === 'object') {
23930
+ for (var objKey in obj) {
23931
+ if (objKey.charAt(0) !== '$' && hasOwnProperty.call(obj, objKey) &&
23932
+ comparator(obj[objKey], text[objKey])) {
23933
+ return true;
23934
+ }
23935
+ }
23936
+ return false;
23937
+ }
23825
23938
  text = (''+text).toLowerCase();
23826
23939
  return (''+obj).toLowerCase().indexOf(text) > -1;
23827
23940
  };
@@ -23874,7 +23987,7 @@ function filterFilter() {
23874
23987
  (function(path) {
23875
23988
  if (typeof expression[path] == 'undefined') return;
23876
23989
  predicates.push(function(value) {
23877
- return search(path == '$' ? value : getter(value, path), expression[path]);
23990
+ return search(path == '$' ? value : (value && value[path]), expression[path]);
23878
23991
  });
23879
23992
  })(key);
23880
23993
  }
@@ -23920,21 +24033,27 @@ function filterFilter() {
23920
24033
  </script>
23921
24034
  <div ng-controller="Ctrl">
23922
24035
  <input type="number" ng-model="amount"> <br>
23923
- default currency symbol ($): {{amount | currency}}<br>
23924
- custom currency identifier (USD$): {{amount | currency:"USD$"}}
24036
+ default currency symbol ($): <span id="currency-default">{{amount | currency}}</span><br>
24037
+ custom currency identifier (USD$): <span>{{amount | currency:"USD$"}}</span>
23925
24038
  </div>
23926
24039
  </doc:source>
23927
- <doc:scenario>
24040
+ <doc:protractor>
23928
24041
  it('should init with 1234.56', function() {
23929
- expect(binding('amount | currency')).toBe('$1,234.56');
23930
- expect(binding('amount | currency:"USD$"')).toBe('USD$1,234.56');
24042
+ expect(element(by.id('currency-default')).getText()).toBe('$1,234.56');
24043
+ expect(element(by.binding('amount | currency:"USD$"')).getText()).toBe('USD$1,234.56');
23931
24044
  });
23932
24045
  it('should update', function() {
23933
- input('amount').enter('-1234');
23934
- expect(binding('amount | currency')).toBe('($1,234.00)');
23935
- expect(binding('amount | currency:"USD$"')).toBe('(USD$1,234.00)');
24046
+ if (browser.params.browser == 'safari') {
24047
+ // Safari does not understand the minus key. See
24048
+ // https://github.com/angular/protractor/issues/481
24049
+ return;
24050
+ }
24051
+ element(by.model('amount')).clear();
24052
+ element(by.model('amount')).sendKeys('-1234');
24053
+ expect(element(by.id('currency-default')).getText()).toBe('($1,234.00)');
24054
+ expect(element(by.binding('amount | currency:"USD$"')).getText()).toBe('(USD$1,234.00)');
23936
24055
  });
23937
- </doc:scenario>
24056
+ </doc:protractor>
23938
24057
  </doc:example>
23939
24058
  */
23940
24059
  currencyFilter.$inject = ['$locale'];
@@ -23973,25 +24092,26 @@ function currencyFilter($locale) {
23973
24092
  </script>
23974
24093
  <div ng-controller="Ctrl">
23975
24094
  Enter number: <input ng-model='val'><br>
23976
- Default formatting: {{val | number}}<br>
23977
- No fractions: {{val | number:0}}<br>
23978
- Negative number: {{-val | number:4}}
24095
+ Default formatting: <span id='number-default'>{{val | number}}</span><br>
24096
+ No fractions: <span>{{val | number:0}}</span><br>
24097
+ Negative number: <span>{{-val | number:4}}</span>
23979
24098
  </div>
23980
24099
  </doc:source>
23981
- <doc:scenario>
24100
+ <doc:protractor>
23982
24101
  it('should format numbers', function() {
23983
- expect(binding('val | number')).toBe('1,234.568');
23984
- expect(binding('val | number:0')).toBe('1,235');
23985
- expect(binding('-val | number:4')).toBe('-1,234.5679');
24102
+ expect(element(by.id('number-default')).getText()).toBe('1,234.568');
24103
+ expect(element(by.binding('val | number:0')).getText()).toBe('1,235');
24104
+ expect(element(by.binding('-val | number:4')).getText()).toBe('-1,234.5679');
23986
24105
  });
23987
24106
 
23988
24107
  it('should update', function() {
23989
- input('val').enter('3374.333');
23990
- expect(binding('val | number')).toBe('3,374.333');
23991
- expect(binding('val | number:0')).toBe('3,374');
23992
- expect(binding('-val | number:4')).toBe('-3,374.3330');
23993
- });
23994
- </doc:scenario>
24108
+ element(by.model('val')).clear();
24109
+ element(by.model('val')).sendKeys('3374.333');
24110
+ expect(element(by.id('number-default')).getText()).toBe('3,374.333');
24111
+ expect(element(by.binding('val | number:0')).getText()).toBe('3,374');
24112
+ expect(element(by.binding('-val | number:4')).getText()).toBe('-3,374.3330');
24113
+ });
24114
+ </doc:protractor>
23995
24115
  </doc:example>
23996
24116
  */
23997
24117
 
@@ -24221,22 +24341,22 @@ var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+
24221
24341
  <doc:example>
24222
24342
  <doc:source>
24223
24343
  <span ng-non-bindable>{{1288323623006 | date:'medium'}}</span>:
24224
- {{1288323623006 | date:'medium'}}<br>
24344
+ <span>{{1288323623006 | date:'medium'}}</span><br>
24225
24345
  <span ng-non-bindable>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span>:
24226
- {{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}<br>
24346
+ <span>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span><br>
24227
24347
  <span ng-non-bindable>{{1288323623006 | date:'MM/dd/yyyy @ h:mma'}}</span>:
24228
- {{'1288323623006' | date:'MM/dd/yyyy @ h:mma'}}<br>
24348
+ <span>{{'1288323623006' | date:'MM/dd/yyyy @ h:mma'}}</span><br>
24229
24349
  </doc:source>
24230
- <doc:scenario>
24350
+ <doc:protractor>
24231
24351
  it('should format date', function() {
24232
- expect(binding("1288323623006 | date:'medium'")).
24352
+ expect(element(by.binding("1288323623006 | date:'medium'")).getText()).
24233
24353
  toMatch(/Oct 2\d, 2010 \d{1,2}:\d{2}:\d{2} (AM|PM)/);
24234
- expect(binding("1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'")).
24354
+ expect(element(by.binding("1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'")).getText()).
24235
24355
  toMatch(/2010\-10\-2\d \d{2}:\d{2}:\d{2} (\-|\+)?\d{4}/);
24236
- expect(binding("'1288323623006' | date:'MM/dd/yyyy @ h:mma'")).
24356
+ expect(element(by.binding("'1288323623006' | date:'MM/dd/yyyy @ h:mma'")).getText()).
24237
24357
  toMatch(/10\/2\d\/2010 @ \d{1,2}:\d{2}(AM|PM)/);
24238
24358
  });
24239
- </doc:scenario>
24359
+ </doc:protractor>
24240
24360
  </doc:example>
24241
24361
  */
24242
24362
  dateFilter.$inject = ['$locale'];
@@ -24335,11 +24455,11 @@ function dateFilter($locale) {
24335
24455
  <doc:source>
24336
24456
  <pre>{{ {'name':'value'} | json }}</pre>
24337
24457
  </doc:source>
24338
- <doc:scenario>
24458
+ <doc:protractor>
24339
24459
  it('should jsonify filtered objects', function() {
24340
- expect(binding("{'name':'value'}")).toMatch(/\{\n "name": ?"value"\n}/);
24460
+ expect(element(by.binding("{'name':'value'}")).getText()).toMatch(/\{\n "name": ?"value"\n}/);
24341
24461
  });
24342
- </doc:scenario>
24462
+ </doc:protractor>
24343
24463
  </doc:example>
24344
24464
  *
24345
24465
  */
@@ -24407,28 +24527,37 @@ var uppercaseFilter = valueFn(uppercase);
24407
24527
  <p>Output letters: {{ letters | limitTo:letterLimit }}</p>
24408
24528
  </div>
24409
24529
  </doc:source>
24410
- <doc:scenario>
24530
+ <doc:protractor>
24531
+ var numLimitInput = element(by.model('numLimit'));
24532
+ var letterLimitInput = element(by.model('letterLimit'));
24533
+ var limitedNumbers = element(by.binding('numbers | limitTo:numLimit'));
24534
+ var limitedLetters = element(by.binding('letters | limitTo:letterLimit'));
24535
+
24411
24536
  it('should limit the number array to first three items', function() {
24412
- expect(element('.doc-example-live input[ng-model=numLimit]').val()).toBe('3');
24413
- expect(element('.doc-example-live input[ng-model=letterLimit]').val()).toBe('3');
24414
- expect(binding('numbers | limitTo:numLimit')).toEqual('[1,2,3]');
24415
- expect(binding('letters | limitTo:letterLimit')).toEqual('abc');
24537
+ expect(numLimitInput.getAttribute('value')).toBe('3');
24538
+ expect(letterLimitInput.getAttribute('value')).toBe('3');
24539
+ expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3]');
24540
+ expect(limitedLetters.getText()).toEqual('Output letters: abc');
24416
24541
  });
24417
24542
 
24418
24543
  it('should update the output when -3 is entered', function() {
24419
- input('numLimit').enter(-3);
24420
- input('letterLimit').enter(-3);
24421
- expect(binding('numbers | limitTo:numLimit')).toEqual('[7,8,9]');
24422
- expect(binding('letters | limitTo:letterLimit')).toEqual('ghi');
24544
+ numLimitInput.clear();
24545
+ numLimitInput.sendKeys('-3');
24546
+ letterLimitInput.clear();
24547
+ letterLimitInput.sendKeys('-3');
24548
+ expect(limitedNumbers.getText()).toEqual('Output numbers: [7,8,9]');
24549
+ expect(limitedLetters.getText()).toEqual('Output letters: ghi');
24423
24550
  });
24424
24551
 
24425
24552
  it('should not exceed the maximum size of input array', function() {
24426
- input('numLimit').enter(100);
24427
- input('letterLimit').enter(100);
24428
- expect(binding('numbers | limitTo:numLimit')).toEqual('[1,2,3,4,5,6,7,8,9]');
24429
- expect(binding('letters | limitTo:letterLimit')).toEqual('abcdefghi');
24553
+ numLimitInput.clear();
24554
+ numLimitInput.sendKeys('100');
24555
+ letterLimitInput.clear();
24556
+ letterLimitInput.sendKeys('100');
24557
+ expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3,4,5,6,7,8,9]');
24558
+ expect(limitedLetters.getText()).toEqual('Output letters: abcdefghi');
24430
24559
  });
24431
- </doc:scenario>
24560
+ </doc:protractor>
24432
24561
  </doc:example>
24433
24562
  */
24434
24563
  function limitToFilter(){
@@ -24529,29 +24658,6 @@ function limitToFilter(){
24529
24658
  </table>
24530
24659
  </div>
24531
24660
  </doc:source>
24532
- <doc:scenario>
24533
- it('should be reverse ordered by aged', function() {
24534
- expect(binding('predicate')).toBe('-age');
24535
- expect(repeater('table.friend', 'friend in friends').column('friend.age')).
24536
- toEqual(['35', '29', '21', '19', '10']);
24537
- expect(repeater('table.friend', 'friend in friends').column('friend.name')).
24538
- toEqual(['Adam', 'Julie', 'Mike', 'Mary', 'John']);
24539
- });
24540
-
24541
- it('should reorder the table when user selects different predicate', function() {
24542
- element('.doc-example-live a:contains("Name")').click();
24543
- expect(repeater('table.friend', 'friend in friends').column('friend.name')).
24544
- toEqual(['Adam', 'John', 'Julie', 'Mary', 'Mike']);
24545
- expect(repeater('table.friend', 'friend in friends').column('friend.age')).
24546
- toEqual(['35', '10', '29', '19', '21']);
24547
-
24548
- element('.doc-example-live a:contains("Phone")').click();
24549
- expect(repeater('table.friend', 'friend in friends').column('friend.phone')).
24550
- toEqual(['555-9876', '555-8765', '555-5678', '555-4321', '555-1212']);
24551
- expect(repeater('table.friend', 'friend in friends').column('friend.name')).
24552
- toEqual(['Mary', 'Julie', 'Adam', 'Mike', 'John']);
24553
- });
24554
- </doc:scenario>
24555
24661
  </doc:example>
24556
24662
  */
24557
24663
  orderByFilter.$inject = ['$parse'];
@@ -24648,11 +24754,14 @@ var htmlAnchorDirective = valueFn({
24648
24754
  element.append(document.createComment('IE fix'));
24649
24755
  }
24650
24756
 
24651
- if (!attr.href && !attr.name) {
24757
+ if (!attr.href && !attr.xlinkHref && !attr.name) {
24652
24758
  return function(scope, element) {
24759
+ // SVGAElement does not use the href attribute, but rather the 'xlinkHref' attribute.
24760
+ var href = toString.call(element.prop('href')) === '[object SVGAnimatedString]' ?
24761
+ 'xlink:href' : 'href';
24653
24762
  element.on('click', function(event){
24654
24763
  // if we have no href url, then don't navigate anywhere.
24655
- if (!element.attr('href')) {
24764
+ if (!element.attr(href)) {
24656
24765
  event.preventDefault();
24657
24766
  }
24658
24767
  });
@@ -24702,46 +24811,55 @@ var htmlAnchorDirective = valueFn({
24702
24811
  <a id="link-5" name="xxx" ng-click="value = 5">anchor</a> (no link)<br />
24703
24812
  <a id="link-6" ng-href="{{value}}">link</a> (link, change location)
24704
24813
  </doc:source>
24705
- <doc:scenario>
24814
+ <doc:protractor>
24706
24815
  it('should execute ng-click but not reload when href without value', function() {
24707
- element('#link-1').click();
24708
- expect(input('value').val()).toEqual('1');
24709
- expect(element('#link-1').attr('href')).toBe("");
24816
+ element(by.id('link-1')).click();
24817
+ expect(element(by.model('value')).getAttribute('value')).toEqual('1');
24818
+ expect(element(by.id('link-1')).getAttribute('href')).toBe('');
24710
24819
  });
24711
24820
 
24712
24821
  it('should execute ng-click but not reload when href empty string', function() {
24713
- element('#link-2').click();
24714
- expect(input('value').val()).toEqual('2');
24715
- expect(element('#link-2').attr('href')).toBe("");
24822
+ element(by.id('link-2')).click();
24823
+ expect(element(by.model('value')).getAttribute('value')).toEqual('2');
24824
+ expect(element(by.id('link-2')).getAttribute('href')).toBe('');
24716
24825
  });
24717
24826
 
24718
24827
  it('should execute ng-click and change url when ng-href specified', function() {
24719
- expect(element('#link-3').attr('href')).toBe("/123");
24828
+ expect(element(by.id('link-3')).getAttribute('href')).toMatch(/\/123$/);
24829
+
24830
+ element(by.id('link-3')).click();
24720
24831
 
24721
- element('#link-3').click();
24722
- expect(browser().window().path()).toEqual('/123');
24832
+ // At this point, we navigate away from an Angular page, so we need
24833
+ // to use browser.driver to get the base webdriver.
24834
+
24835
+ browser.wait(function() {
24836
+ return browser.driver.getCurrentUrl().then(function(url) {
24837
+ return url.match(/\/123$/);
24838
+ });
24839
+ }, 1000, 'page should navigate to /123');
24723
24840
  });
24724
24841
 
24725
24842
  it('should execute ng-click but not reload when href empty string and name specified', function() {
24726
- element('#link-4').click();
24727
- expect(input('value').val()).toEqual('4');
24728
- expect(element('#link-4').attr('href')).toBe('');
24843
+ element(by.id('link-4')).click();
24844
+ expect(element(by.model('value')).getAttribute('value')).toEqual('4');
24845
+ expect(element(by.id('link-4')).getAttribute('href')).toBe('');
24729
24846
  });
24730
24847
 
24731
24848
  it('should execute ng-click but not reload when no href but name specified', function() {
24732
- element('#link-5').click();
24733
- expect(input('value').val()).toEqual('5');
24734
- expect(element('#link-5').attr('href')).toBe(undefined);
24849
+ element(by.id('link-5')).click();
24850
+ expect(element(by.model('value')).getAttribute('value')).toEqual('5');
24851
+ expect(element(by.id('link-5')).getAttribute('href')).toBe(null);
24735
24852
  });
24736
24853
 
24737
24854
  it('should only change url when only ng-href', function() {
24738
- input('value').enter('6');
24739
- expect(element('#link-6').attr('href')).toBe('6');
24855
+ element(by.model('value')).clear();
24856
+ element(by.model('value')).sendKeys('6');
24857
+ expect(element(by.id('link-6')).getAttribute('href')).toMatch(/\/6$/);
24740
24858
 
24741
- element('#link-6').click();
24742
- expect(browser().location().url()).toEqual('/6');
24859
+ element(by.id('link-6')).click();
24860
+ expect(browser.getCurrentUrl()).toMatch(/\/6$/);
24743
24861
  });
24744
- </doc:scenario>
24862
+ </doc:protractor>
24745
24863
  </doc:example>
24746
24864
  */
24747
24865
 
@@ -24826,13 +24944,13 @@ var htmlAnchorDirective = valueFn({
24826
24944
  Click me to toggle: <input type="checkbox" ng-model="checked"><br/>
24827
24945
  <button ng-model="button" ng-disabled="checked">Button</button>
24828
24946
  </doc:source>
24829
- <doc:scenario>
24947
+ <doc:protractor>
24830
24948
  it('should toggle button', function() {
24831
- expect(element('.doc-example-live :button').prop('disabled')).toBeFalsy();
24832
- input('checked').check();
24833
- expect(element('.doc-example-live :button').prop('disabled')).toBeTruthy();
24949
+ expect(element(by.css('.doc-example-live button')).getAttribute('disabled')).toBeFalsy();
24950
+ element(by.model('checked')).click();
24951
+ expect(element(by.css('.doc-example-live button')).getAttribute('disabled')).toBeTruthy();
24834
24952
  });
24835
- </doc:scenario>
24953
+ </doc:protractor>
24836
24954
  </doc:example>
24837
24955
  *
24838
24956
  * @element INPUT
@@ -24861,13 +24979,13 @@ var htmlAnchorDirective = valueFn({
24861
24979
  Check me to check both: <input type="checkbox" ng-model="master"><br/>
24862
24980
  <input id="checkSlave" type="checkbox" ng-checked="master">
24863
24981
  </doc:source>
24864
- <doc:scenario>
24982
+ <doc:protractor>
24865
24983
  it('should check both checkBoxes', function() {
24866
- expect(element('.doc-example-live #checkSlave').prop('checked')).toBeFalsy();
24867
- input('master').check();
24868
- expect(element('.doc-example-live #checkSlave').prop('checked')).toBeTruthy();
24984
+ expect(element(by.id('checkSlave')).getAttribute('checked')).toBeFalsy();
24985
+ element(by.model('master')).click();
24986
+ expect(element(by.id('checkSlave')).getAttribute('checked')).toBeTruthy();
24869
24987
  });
24870
- </doc:scenario>
24988
+ </doc:protractor>
24871
24989
  </doc:example>
24872
24990
  *
24873
24991
  * @element INPUT
@@ -24896,13 +25014,13 @@ var htmlAnchorDirective = valueFn({
24896
25014
  Check me to make text readonly: <input type="checkbox" ng-model="checked"><br/>
24897
25015
  <input type="text" ng-readonly="checked" value="I'm Angular"/>
24898
25016
  </doc:source>
24899
- <doc:scenario>
25017
+ <doc:protractor>
24900
25018
  it('should toggle readonly attr', function() {
24901
- expect(element('.doc-example-live :text').prop('readonly')).toBeFalsy();
24902
- input('checked').check();
24903
- expect(element('.doc-example-live :text').prop('readonly')).toBeTruthy();
25019
+ expect(element(by.css('.doc-example-live [type="text"]')).getAttribute('readonly')).toBeFalsy();
25020
+ element(by.model('checked')).click();
25021
+ expect(element(by.css('.doc-example-live [type="text"]')).getAttribute('readonly')).toBeTruthy();
24904
25022
  });
24905
- </doc:scenario>
25023
+ </doc:protractor>
24906
25024
  </doc:example>
24907
25025
  *
24908
25026
  * @element INPUT
@@ -24935,13 +25053,13 @@ var htmlAnchorDirective = valueFn({
24935
25053
  <option id="greet" ng-selected="selected">Greetings!</option>
24936
25054
  </select>
24937
25055
  </doc:source>
24938
- <doc:scenario>
25056
+ <doc:protractor>
24939
25057
  it('should select Greetings!', function() {
24940
- expect(element('.doc-example-live #greet').prop('selected')).toBeFalsy();
24941
- input('selected').check();
24942
- expect(element('.doc-example-live #greet').prop('selected')).toBeTruthy();
25058
+ expect(element(by.id('greet')).getAttribute('selected')).toBeFalsy();
25059
+ element(by.model('selected')).click();
25060
+ expect(element(by.id('greet')).getAttribute('selected')).toBeTruthy();
24943
25061
  });
24944
- </doc:scenario>
25062
+ </doc:protractor>
24945
25063
  </doc:example>
24946
25064
  *
24947
25065
  * @element OPTION
@@ -24971,13 +25089,13 @@ var htmlAnchorDirective = valueFn({
24971
25089
  <summary>Show/Hide me</summary>
24972
25090
  </details>
24973
25091
  </doc:source>
24974
- <doc:scenario>
25092
+ <doc:protractor>
24975
25093
  it('should toggle open', function() {
24976
- expect(element('#details').prop('open')).toBeFalsy();
24977
- input('open').check();
24978
- expect(element('#details').prop('open')).toBeTruthy();
25094
+ expect(element(by.id('details')).getAttribute('open')).toBeFalsy();
25095
+ element(by.model('open')).click();
25096
+ expect(element(by.id('details')).getAttribute('open')).toBeTruthy();
24979
25097
  });
24980
- </doc:scenario>
25098
+ </doc:protractor>
24981
25099
  </doc:example>
24982
25100
  *
24983
25101
  * @element DETAILS
@@ -25336,18 +25454,27 @@ function FormController(element, attrs) {
25336
25454
  <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br>
25337
25455
  </form>
25338
25456
  </doc:source>
25339
- <doc:scenario>
25457
+ <doc:protractor>
25340
25458
  it('should initialize to model', function() {
25341
- expect(binding('userType')).toEqual('guest');
25342
- expect(binding('myForm.input.$valid')).toEqual('true');
25459
+ var userType = element(by.binding('userType'));
25460
+ var valid = element(by.binding('myForm.input.$valid'));
25461
+
25462
+ expect(userType.getText()).toContain('guest');
25463
+ expect(valid.getText()).toContain('true');
25343
25464
  });
25344
25465
 
25345
25466
  it('should be invalid if empty', function() {
25346
- input('userType').enter('');
25347
- expect(binding('userType')).toEqual('');
25348
- expect(binding('myForm.input.$valid')).toEqual('false');
25467
+ var userType = element(by.binding('userType'));
25468
+ var valid = element(by.binding('myForm.input.$valid'));
25469
+ var userInput = element(by.model('userType'));
25470
+
25471
+ userInput.clear();
25472
+ userInput.sendKeys('');
25473
+
25474
+ expect(userType.getText()).toEqual('userType =');
25475
+ expect(valid.getText()).toContain('false');
25349
25476
  });
25350
- </doc:scenario>
25477
+ </doc:protractor>
25351
25478
  </doc:example>
25352
25479
  */
25353
25480
  var formDirectiveFactory = function(isNgForm) {
@@ -25419,7 +25546,7 @@ var ngFormDirective = formDirectiveFactory(true);
25419
25546
  */
25420
25547
 
25421
25548
  var URL_REGEXP = /^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/;
25422
- var EMAIL_REGEXP = /^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}$/;
25549
+ var EMAIL_REGEXP = /^[a-z0-9!#$%&'*+/=?^_`{|}~.-]+@[a-z0-9-]+(\.[a-z0-9-]+)*$/i;
25423
25550
  var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))\s*$/;
25424
25551
 
25425
25552
  var inputType = {
@@ -25472,29 +25599,31 @@ var inputType = {
25472
25599
  <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
25473
25600
  </form>
25474
25601
  </doc:source>
25475
- <doc:scenario>
25602
+ <doc:protractor>
25603
+ var text = element(by.binding('text'));
25604
+ var valid = element(by.binding('myForm.input.$valid'));
25605
+ var input = element(by.model('text'));
25606
+
25476
25607
  it('should initialize to model', function() {
25477
- expect(binding('text')).toEqual('guest');
25478
- expect(binding('myForm.input.$valid')).toEqual('true');
25608
+ expect(text.getText()).toContain('guest');
25609
+ expect(valid.getText()).toContain('true');
25479
25610
  });
25480
25611
 
25481
25612
  it('should be invalid if empty', function() {
25482
- input('text').enter('');
25483
- expect(binding('text')).toEqual('');
25484
- expect(binding('myForm.input.$valid')).toEqual('false');
25613
+ input.clear();
25614
+ input.sendKeys('');
25615
+
25616
+ expect(text.getText()).toEqual('text =');
25617
+ expect(valid.getText()).toContain('false');
25485
25618
  });
25486
25619
 
25487
25620
  it('should be invalid if multi word', function() {
25488
- input('text').enter('hello world');
25489
- expect(binding('myForm.input.$valid')).toEqual('false');
25490
- });
25621
+ input.clear();
25622
+ input.sendKeys('hello world');
25491
25623
 
25492
- it('should not be trimmed', function() {
25493
- input('text').enter('untrimmed ');
25494
- expect(binding('text')).toEqual('untrimmed ');
25495
- expect(binding('myForm.input.$valid')).toEqual('true');
25624
+ expect(valid.getText()).toContain('false');
25496
25625
  });
25497
- </doc:scenario>
25626
+ </doc:protractor>
25498
25627
  </doc:example>
25499
25628
  */
25500
25629
  'text': textInputType,
@@ -25548,24 +25677,30 @@ var inputType = {
25548
25677
  <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
25549
25678
  </form>
25550
25679
  </doc:source>
25551
- <doc:scenario>
25680
+ <doc:protractor>
25681
+ var value = element(by.binding('value'));
25682
+ var valid = element(by.binding('myForm.input.$valid'));
25683
+ var input = element(by.model('value'));
25684
+
25552
25685
  it('should initialize to model', function() {
25553
- expect(binding('value')).toEqual('12');
25554
- expect(binding('myForm.input.$valid')).toEqual('true');
25686
+ expect(value.getText()).toContain('12');
25687
+ expect(valid.getText()).toContain('true');
25555
25688
  });
25556
25689
 
25557
25690
  it('should be invalid if empty', function() {
25558
- input('value').enter('');
25559
- expect(binding('value')).toEqual('');
25560
- expect(binding('myForm.input.$valid')).toEqual('false');
25691
+ input.clear();
25692
+ input.sendKeys('');
25693
+ expect(value.getText()).toEqual('value =');
25694
+ expect(valid.getText()).toContain('false');
25561
25695
  });
25562
25696
 
25563
25697
  it('should be invalid if over max', function() {
25564
- input('value').enter('123');
25565
- expect(binding('value')).toEqual('');
25566
- expect(binding('myForm.input.$valid')).toEqual('false');
25698
+ input.clear();
25699
+ input.sendKeys('123');
25700
+ expect(value.getText()).toEqual('value =');
25701
+ expect(valid.getText()).toContain('false');
25567
25702
  });
25568
- </doc:scenario>
25703
+ </doc:protractor>
25569
25704
  </doc:example>
25570
25705
  */
25571
25706
  'number': numberInputType,
@@ -25617,23 +25752,31 @@ var inputType = {
25617
25752
  <tt>myForm.$error.url = {{!!myForm.$error.url}}</tt><br/>
25618
25753
  </form>
25619
25754
  </doc:source>
25620
- <doc:scenario>
25755
+ <doc:protractor>
25756
+ var text = element(by.binding('text'));
25757
+ var valid = element(by.binding('myForm.input.$valid'));
25758
+ var input = element(by.model('text'));
25759
+
25621
25760
  it('should initialize to model', function() {
25622
- expect(binding('text')).toEqual('http://google.com');
25623
- expect(binding('myForm.input.$valid')).toEqual('true');
25761
+ expect(text.getText()).toContain('http://google.com');
25762
+ expect(valid.getText()).toContain('true');
25624
25763
  });
25625
25764
 
25626
25765
  it('should be invalid if empty', function() {
25627
- input('text').enter('');
25628
- expect(binding('text')).toEqual('');
25629
- expect(binding('myForm.input.$valid')).toEqual('false');
25766
+ input.clear();
25767
+ input.sendKeys('');
25768
+
25769
+ expect(text.getText()).toEqual('text =');
25770
+ expect(valid.getText()).toContain('false');
25630
25771
  });
25631
25772
 
25632
25773
  it('should be invalid if not url', function() {
25633
- input('text').enter('xxx');
25634
- expect(binding('myForm.input.$valid')).toEqual('false');
25774
+ input.clear();
25775
+ input.sendKeys('box');
25776
+
25777
+ expect(valid.getText()).toContain('false');
25635
25778
  });
25636
- </doc:scenario>
25779
+ </doc:protractor>
25637
25780
  </doc:example>
25638
25781
  */
25639
25782
  'url': urlInputType,
@@ -25685,23 +25828,30 @@ var inputType = {
25685
25828
  <tt>myForm.$error.email = {{!!myForm.$error.email}}</tt><br/>
25686
25829
  </form>
25687
25830
  </doc:source>
25688
- <doc:scenario>
25831
+ <doc:protractor>
25832
+ var text = element(by.binding('text'));
25833
+ var valid = element(by.binding('myForm.input.$valid'));
25834
+ var input = element(by.model('text'));
25835
+
25689
25836
  it('should initialize to model', function() {
25690
- expect(binding('text')).toEqual('me@example.com');
25691
- expect(binding('myForm.input.$valid')).toEqual('true');
25837
+ expect(text.getText()).toContain('me@example.com');
25838
+ expect(valid.getText()).toContain('true');
25692
25839
  });
25693
25840
 
25694
25841
  it('should be invalid if empty', function() {
25695
- input('text').enter('');
25696
- expect(binding('text')).toEqual('');
25697
- expect(binding('myForm.input.$valid')).toEqual('false');
25842
+ input.clear();
25843
+ input.sendKeys('');
25844
+ expect(text.getText()).toEqual('text =');
25845
+ expect(valid.getText()).toContain('false');
25698
25846
  });
25699
25847
 
25700
25848
  it('should be invalid if not email', function() {
25701
- input('text').enter('xxx');
25702
- expect(binding('myForm.input.$valid')).toEqual('false');
25849
+ input.clear();
25850
+ input.sendKeys('xxx');
25851
+
25852
+ expect(valid.getText()).toContain('false');
25703
25853
  });
25704
- </doc:scenario>
25854
+ </doc:protractor>
25705
25855
  </doc:example>
25706
25856
  */
25707
25857
  'email': emailInputType,
@@ -25719,6 +25869,8 @@ var inputType = {
25719
25869
  * @param {string=} name Property name of the form under which the control is published.
25720
25870
  * @param {string=} ngChange Angular expression to be executed when input changes due to user
25721
25871
  * interaction with the input element.
25872
+ * @param {string} ngValue Angular expression which sets the value to which the expression should
25873
+ * be set when selected.
25722
25874
  *
25723
25875
  * @example
25724
25876
  <doc:example>
@@ -25726,23 +25878,31 @@ var inputType = {
25726
25878
  <script>
25727
25879
  function Ctrl($scope) {
25728
25880
  $scope.color = 'blue';
25881
+ $scope.specialValue = {
25882
+ "id": "12345",
25883
+ "value": "green"
25884
+ };
25729
25885
  }
25730
25886
  </script>
25731
25887
  <form name="myForm" ng-controller="Ctrl">
25732
25888
  <input type="radio" ng-model="color" value="red"> Red <br/>
25733
- <input type="radio" ng-model="color" value="green"> Green <br/>
25889
+ <input type="radio" ng-model="color" ng-value="specialValue"> Green <br/>
25734
25890
  <input type="radio" ng-model="color" value="blue"> Blue <br/>
25735
- <tt>color = {{color}}</tt><br/>
25891
+ <tt>color = {{color | json}}</tt><br/>
25736
25892
  </form>
25893
+ Note that `ng-value="specialValue"` sets radio item's value to be the value of `$scope.specialValue`.
25737
25894
  </doc:source>
25738
- <doc:scenario>
25895
+ <doc:protractor>
25739
25896
  it('should change state', function() {
25740
- expect(binding('color')).toEqual('blue');
25897
+ var color = element(by.binding('color'));
25898
+
25899
+ expect(color.getText()).toContain('blue');
25741
25900
 
25742
- input('color').select('red');
25743
- expect(binding('color')).toEqual('red');
25901
+ element.all(by.model('color')).get(0).click();
25902
+
25903
+ expect(color.getText()).toContain('red');
25744
25904
  });
25745
- </doc:scenario>
25905
+ </doc:protractor>
25746
25906
  </doc:example>
25747
25907
  */
25748
25908
  'radio': radioInputType,
@@ -25779,17 +25939,21 @@ var inputType = {
25779
25939
  <tt>value2 = {{value2}}</tt><br/>
25780
25940
  </form>
25781
25941
  </doc:source>
25782
- <doc:scenario>
25942
+ <doc:protractor>
25783
25943
  it('should change state', function() {
25784
- expect(binding('value1')).toEqual('true');
25785
- expect(binding('value2')).toEqual('YES');
25944
+ var value1 = element(by.binding('value1'));
25945
+ var value2 = element(by.binding('value2'));
25946
+
25947
+ expect(value1.getText()).toContain('true');
25948
+ expect(value2.getText()).toContain('YES');
25949
+
25950
+ element(by.model('value1')).click();
25951
+ element(by.model('value2')).click();
25786
25952
 
25787
- input('value1').check();
25788
- input('value2').check();
25789
- expect(binding('value1')).toEqual('false');
25790
- expect(binding('value2')).toEqual('NO');
25953
+ expect(value1.getText()).toContain('false');
25954
+ expect(value2.getText()).toContain('NO');
25791
25955
  });
25792
- </doc:scenario>
25956
+ </doc:protractor>
25793
25957
  </doc:example>
25794
25958
  */
25795
25959
  'checkbox': checkboxInputType,
@@ -25797,7 +25961,8 @@ var inputType = {
25797
25961
  'hidden': noop,
25798
25962
  'button': noop,
25799
25963
  'submit': noop,
25800
- 'reset': noop
25964
+ 'reset': noop,
25965
+ 'file': noop
25801
25966
  };
25802
25967
 
25803
25968
  // A helper function to call $setValidity and return the value / undefined,
@@ -25820,6 +25985,7 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
25820
25985
 
25821
25986
  element.on('compositionend', function() {
25822
25987
  composing = false;
25988
+ listener();
25823
25989
  });
25824
25990
  }
25825
25991
 
@@ -26142,44 +26308,59 @@ function checkboxInputType(scope, element, attr, ctrl) {
26142
26308
  <tt>myForm.$error.maxlength = {{!!myForm.$error.maxlength}}</tt><br>
26143
26309
  </div>
26144
26310
  </doc:source>
26145
- <doc:scenario>
26311
+ <doc:protractor>
26312
+ var user = element(by.binding('{{user}}'));
26313
+ var userNameValid = element(by.binding('myForm.userName.$valid'));
26314
+ var lastNameValid = element(by.binding('myForm.lastName.$valid'));
26315
+ var lastNameError = element(by.binding('myForm.lastName.$error'));
26316
+ var formValid = element(by.binding('myForm.$valid'));
26317
+ var userNameInput = element(by.model('user.name'));
26318
+ var userLastInput = element(by.model('user.last'));
26319
+
26146
26320
  it('should initialize to model', function() {
26147
- expect(binding('user')).toEqual('{"name":"guest","last":"visitor"}');
26148
- expect(binding('myForm.userName.$valid')).toEqual('true');
26149
- expect(binding('myForm.$valid')).toEqual('true');
26321
+ expect(user.getText()).toContain('{"name":"guest","last":"visitor"}');
26322
+ expect(userNameValid.getText()).toContain('true');
26323
+ expect(formValid.getText()).toContain('true');
26150
26324
  });
26151
26325
 
26152
26326
  it('should be invalid if empty when required', function() {
26153
- input('user.name').enter('');
26154
- expect(binding('user')).toEqual('{"last":"visitor"}');
26155
- expect(binding('myForm.userName.$valid')).toEqual('false');
26156
- expect(binding('myForm.$valid')).toEqual('false');
26327
+ userNameInput.clear();
26328
+ userNameInput.sendKeys('');
26329
+
26330
+ expect(user.getText()).toContain('{"last":"visitor"}');
26331
+ expect(userNameValid.getText()).toContain('false');
26332
+ expect(formValid.getText()).toContain('false');
26157
26333
  });
26158
26334
 
26159
26335
  it('should be valid if empty when min length is set', function() {
26160
- input('user.last').enter('');
26161
- expect(binding('user')).toEqual('{"name":"guest","last":""}');
26162
- expect(binding('myForm.lastName.$valid')).toEqual('true');
26163
- expect(binding('myForm.$valid')).toEqual('true');
26336
+ userLastInput.clear();
26337
+ userLastInput.sendKeys('');
26338
+
26339
+ expect(user.getText()).toContain('{"name":"guest","last":""}');
26340
+ expect(lastNameValid.getText()).toContain('true');
26341
+ expect(formValid.getText()).toContain('true');
26164
26342
  });
26165
26343
 
26166
26344
  it('should be invalid if less than required min length', function() {
26167
- input('user.last').enter('xx');
26168
- expect(binding('user')).toEqual('{"name":"guest"}');
26169
- expect(binding('myForm.lastName.$valid')).toEqual('false');
26170
- expect(binding('myForm.lastName.$error')).toMatch(/minlength/);
26171
- expect(binding('myForm.$valid')).toEqual('false');
26345
+ userLastInput.clear();
26346
+ userLastInput.sendKeys('xx');
26347
+
26348
+ expect(user.getText()).toContain('{"name":"guest"}');
26349
+ expect(lastNameValid.getText()).toContain('false');
26350
+ expect(lastNameError.getText()).toContain('minlength');
26351
+ expect(formValid.getText()).toContain('false');
26172
26352
  });
26173
26353
 
26174
26354
  it('should be invalid if longer than max length', function() {
26175
- input('user.last').enter('some ridiculously long name');
26176
- expect(binding('user'))
26177
- .toEqual('{"name":"guest"}');
26178
- expect(binding('myForm.lastName.$valid')).toEqual('false');
26179
- expect(binding('myForm.lastName.$error')).toMatch(/maxlength/);
26180
- expect(binding('myForm.$valid')).toEqual('false');
26355
+ userLastInput.clear();
26356
+ userLastInput.sendKeys('some ridiculously long name');
26357
+
26358
+ expect(user.getText()).toContain('{"name":"guest"}');
26359
+ expect(lastNameValid.getText()).toContain('false');
26360
+ expect(lastNameError.getText()).toContain('maxlength');
26361
+ expect(formValid.getText()).toContain('false');
26181
26362
  });
26182
- </doc:scenario>
26363
+ </doc:protractor>
26183
26364
  </doc:example>
26184
26365
  */
26185
26366
  var inputDirective = ['$browser', '$sniffer', function($browser, $sniffer) {
@@ -26311,14 +26492,23 @@ var VALID_CLASS = 'ng-valid',
26311
26492
  <textarea ng-model="userContent"></textarea>
26312
26493
  </form>
26313
26494
  </file>
26314
- <file name="scenario.js">
26495
+ <file name="protractorTest.js">
26315
26496
  it('should data-bind and become invalid', function() {
26316
- var contentEditable = element('[contenteditable]');
26497
+ if (browser.params.browser = 'safari') {
26498
+ // SafariDriver can't handle contenteditable.
26499
+ return;
26500
+ };
26501
+ var contentEditable = element(by.css('.doc-example-live [contenteditable]'));
26317
26502
 
26318
- expect(contentEditable.text()).toEqual('Change me!');
26319
- input('userContent').enter('');
26320
- expect(contentEditable.text()).toEqual('');
26321
- expect(contentEditable.prop('className')).toMatch(/ng-invalid-required/);
26503
+ expect(contentEditable.getText()).toEqual('Change me!');
26504
+
26505
+ // Firefox driver doesn't trigger the proper events on 'clear', so do this hack
26506
+ contentEditable.click();
26507
+ contentEditable.sendKeys(protractor.Key.chord(protractor.Key.COMMAND, "a"));
26508
+ contentEditable.sendKeys(protractor.Key.BACK_SPACE);
26509
+
26510
+ expect(contentEditable.getText()).toEqual('');
26511
+ expect(contentEditable.getAttribute('class')).toMatch(/ng-invalid-required/);
26322
26512
  });
26323
26513
  </file>
26324
26514
  * </example>
@@ -26371,6 +26561,9 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
26371
26561
  * You can override this for input directives whose concept of being empty is different to the
26372
26562
  * default. The `checkboxInputType` directive does this because in its case a value of `false`
26373
26563
  * implies empty.
26564
+ *
26565
+ * @param {*} value Reference to check.
26566
+ * @returns {boolean} True if `value` is empty.
26374
26567
  */
26375
26568
  this.$isEmpty = function(value) {
26376
26569
  return isUndefined(value) || value === '' || value === null || value !== value;
@@ -26598,7 +26791,10 @@ var ngModelDirective = function() {
26598
26791
  * @name ng.directive:ngChange
26599
26792
  *
26600
26793
  * @description
26601
- * Evaluate given expression when user changes the input.
26794
+ * Evaluate the given expression when the user changes the input.
26795
+ * The expression is evaluated immediately, unlike the JavaScript onchange event
26796
+ * which only triggers at the end of a change (usually, when the user leaves the
26797
+ * form element or presses the return key).
26602
26798
  * The expression is not evaluated when the value change is coming from the model.
26603
26799
  *
26604
26800
  * Note, this directive requires `ngModel` to be present.
@@ -26622,24 +26818,30 @@ var ngModelDirective = function() {
26622
26818
  * <input type="checkbox" ng-model="confirmed" ng-change="change()" id="ng-change-example1" />
26623
26819
  * <input type="checkbox" ng-model="confirmed" id="ng-change-example2" />
26624
26820
  * <label for="ng-change-example2">Confirmed</label><br />
26625
- * debug = {{confirmed}}<br />
26626
- * counter = {{counter}}
26821
+ * <tt>debug = {{confirmed}}</tt><br/>
26822
+ * <tt>counter = {{counter}}</tt><br/>
26627
26823
  * </div>
26628
26824
  * </doc:source>
26629
- * <doc:scenario>
26825
+ * <doc:protractor>
26826
+ * var counter = element(by.binding('counter'));
26827
+ * var debug = element(by.binding('confirmed'));
26828
+ *
26630
26829
  * it('should evaluate the expression if changing from view', function() {
26631
- * expect(binding('counter')).toEqual('0');
26632
- * element('#ng-change-example1').click();
26633
- * expect(binding('counter')).toEqual('1');
26634
- * expect(binding('confirmed')).toEqual('true');
26830
+ * expect(counter.getText()).toContain('0');
26831
+ *
26832
+ * element(by.id('ng-change-example1')).click();
26833
+ *
26834
+ * expect(counter.getText()).toContain('1');
26835
+ * expect(debug.getText()).toContain('true');
26635
26836
  * });
26636
26837
  *
26637
26838
  * it('should not evaluate the expression if changing from model', function() {
26638
- * element('#ng-change-example2').click();
26639
- * expect(binding('counter')).toEqual('0');
26640
- * expect(binding('confirmed')).toEqual('true');
26839
+ * element(by.id('ng-change-example2')).click();
26840
+
26841
+ * expect(counter.getText()).toContain('0');
26842
+ * expect(debug.getText()).toContain('true');
26641
26843
  * });
26642
- * </doc:scenario>
26844
+ * </doc:protractor>
26643
26845
  * </doc:example>
26644
26846
  */
26645
26847
  var ngChangeDirective = valueFn({
@@ -26712,20 +26914,26 @@ var requiredDirective = function() {
26712
26914
  <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
26713
26915
  </form>
26714
26916
  </doc:source>
26715
- <doc:scenario>
26917
+ <doc:protractor>
26918
+ var listInput = element(by.model('names'));
26919
+ var names = element(by.binding('{{names}}'));
26920
+ var valid = element(by.binding('myForm.namesInput.$valid'));
26921
+ var error = element(by.css('span.error'));
26922
+
26716
26923
  it('should initialize to model', function() {
26717
- expect(binding('names')).toEqual('["igor","misko","vojta"]');
26718
- expect(binding('myForm.namesInput.$valid')).toEqual('true');
26719
- expect(element('span.error').css('display')).toBe('none');
26924
+ expect(names.getText()).toContain('["igor","misko","vojta"]');
26925
+ expect(valid.getText()).toContain('true');
26926
+ expect(error.getCssValue('display')).toBe('none');
26720
26927
  });
26721
26928
 
26722
26929
  it('should be invalid if empty', function() {
26723
- input('names').enter('');
26724
- expect(binding('names')).toEqual('');
26725
- expect(binding('myForm.namesInput.$valid')).toEqual('false');
26726
- expect(element('span.error').css('display')).not().toBe('none');
26727
- });
26728
- </doc:scenario>
26930
+ listInput.clear();
26931
+ listInput.sendKeys('');
26932
+
26933
+ expect(names.getText()).toContain('');
26934
+ expect(valid.getText()).toContain('false');
26935
+ expect(error.getCssValue('display')).not.toBe('none'); });
26936
+ </doc:protractor>
26729
26937
  </doc:example>
26730
26938
  */
26731
26939
  var ngListDirective = function() {
@@ -26807,15 +27015,17 @@ var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
26807
27015
  <div>You chose {{my.favorite}}</div>
26808
27016
  </form>
26809
27017
  </doc:source>
26810
- <doc:scenario>
27018
+ <doc:protractor>
27019
+ var favorite = element(by.binding('my.favorite'));
27020
+
26811
27021
  it('should initialize to model', function() {
26812
- expect(binding('my.favorite')).toEqual('unicorns');
27022
+ expect(favorite.getText()).toContain('unicorns');
26813
27023
  });
26814
27024
  it('should bind the values to the inputs', function() {
26815
- input('my.favorite').select('pizza');
26816
- expect(binding('my.favorite')).toEqual('pizza');
27025
+ element.all(by.model('my.favorite')).get(0).click();
27026
+ expect(favorite.getText()).toContain('pizza');
26817
27027
  });
26818
- </doc:scenario>
27028
+ </doc:protractor>
26819
27029
  </doc:example>
26820
27030
  */
26821
27031
  var ngValueDirective = function() {
@@ -26875,13 +27085,17 @@ var ngValueDirective = function() {
26875
27085
  Hello <span ng-bind="name"></span>!
26876
27086
  </div>
26877
27087
  </doc:source>
26878
- <doc:scenario>
27088
+ <doc:protractor>
26879
27089
  it('should check ng-bind', function() {
26880
- expect(using('.doc-example-live').binding('name')).toBe('Whirled');
26881
- using('.doc-example-live').input('name').enter('world');
26882
- expect(using('.doc-example-live').binding('name')).toBe('world');
27090
+ var exampleContainer = $('.doc-example-live');
27091
+ var nameInput = element(by.model('name'));
27092
+
27093
+ expect(exampleContainer.findElement(by.binding('name')).getText()).toBe('Whirled');
27094
+ nameInput.clear();
27095
+ nameInput.sendKeys('world');
27096
+ expect(exampleContainer.findElement(by.binding('name')).getText()).toBe('world');
26883
27097
  });
26884
- </doc:scenario>
27098
+ </doc:protractor>
26885
27099
  </doc:example>
26886
27100
  */
26887
27101
  var ngBindDirective = ngDirective(function(scope, element, attr) {
@@ -26927,20 +27141,22 @@ var ngBindDirective = ngDirective(function(scope, element, attr) {
26927
27141
  <pre ng-bind-template="{{salutation}} {{name}}!"></pre>
26928
27142
  </div>
26929
27143
  </doc:source>
26930
- <doc:scenario>
27144
+ <doc:protractor>
26931
27145
  it('should check ng-bind', function() {
26932
- expect(using('.doc-example-live').binding('salutation')).
26933
- toBe('Hello');
26934
- expect(using('.doc-example-live').binding('name')).
26935
- toBe('World');
26936
- using('.doc-example-live').input('salutation').enter('Greetings');
26937
- using('.doc-example-live').input('name').enter('user');
26938
- expect(using('.doc-example-live').binding('salutation')).
26939
- toBe('Greetings');
26940
- expect(using('.doc-example-live').binding('name')).
26941
- toBe('user');
27146
+ var salutationElem = element(by.binding('salutation'));
27147
+ var salutationInput = element(by.model('salutation'));
27148
+ var nameInput = element(by.model('name'));
27149
+
27150
+ expect(salutationElem.getText()).toBe('Hello World!');
27151
+
27152
+ salutationInput.clear();
27153
+ salutationInput.sendKeys('Greetings');
27154
+ nameInput.clear();
27155
+ nameInput.sendKeys('user');
27156
+
27157
+ expect(salutationElem.getText()).toBe('Greetings user!');
26942
27158
  });
26943
- </doc:scenario>
27159
+ </doc:protractor>
26944
27160
  </doc:example>
26945
27161
  */
26946
27162
  var ngBindTemplateDirective = ['$interpolate', function($interpolate) {
@@ -26993,12 +27209,10 @@ var ngBindTemplateDirective = ['$interpolate', function($interpolate) {
26993
27209
  }]);
26994
27210
  </file>
26995
27211
 
26996
- <file name="scenario.js">
27212
+ <file name="protractorTest.js">
26997
27213
  it('should check ng-bind-html', function() {
26998
- expect(using('.doc-example-live').binding('myHTML')).
26999
- toBe(
27000
- 'I am an <code>HTML</code>string with <a href="#">links!</a> and other <em>stuff</em>'
27001
- );
27214
+ expect(element(by.binding('myHTML')).getText()).toBe(
27215
+ 'I am an HTMLstring with links! and other stuff');
27002
27216
  });
27003
27217
  </file>
27004
27218
  </example>
@@ -27130,31 +27344,34 @@ function classDirective(name, selector) {
27130
27344
  color: red;
27131
27345
  }
27132
27346
  </file>
27133
- <file name="scenario.js">
27347
+ <file name="protractorTest.js">
27348
+ var ps = element.all(by.css('.doc-example-live p'));
27349
+
27134
27350
  it('should let you toggle the class', function() {
27135
27351
 
27136
- expect(element('.doc-example-live p:first').prop('className')).not().toMatch(/bold/);
27137
- expect(element('.doc-example-live p:first').prop('className')).not().toMatch(/red/);
27352
+ expect(ps.first().getAttribute('class')).not.toMatch(/bold/);
27353
+ expect(ps.first().getAttribute('class')).not.toMatch(/red/);
27138
27354
 
27139
- input('important').check();
27140
- expect(element('.doc-example-live p:first').prop('className')).toMatch(/bold/);
27355
+ element(by.model('important')).click();
27356
+ expect(ps.first().getAttribute('class')).toMatch(/bold/);
27141
27357
 
27142
- input('error').check();
27143
- expect(element('.doc-example-live p:first').prop('className')).toMatch(/red/);
27358
+ element(by.model('error')).click();
27359
+ expect(ps.first().getAttribute('class')).toMatch(/red/);
27144
27360
  });
27145
27361
 
27146
27362
  it('should let you toggle string example', function() {
27147
- expect(element('.doc-example-live p:nth-of-type(2)').prop('className')).toBe('');
27148
- input('style').enter('red');
27149
- expect(element('.doc-example-live p:nth-of-type(2)').prop('className')).toBe('red');
27363
+ expect(ps.get(1).getAttribute('class')).toBe('');
27364
+ element(by.model('style')).clear();
27365
+ element(by.model('style')).sendKeys('red');
27366
+ expect(ps.get(1).getAttribute('class')).toBe('red');
27150
27367
  });
27151
27368
 
27152
27369
  it('array example should have 3 classes', function() {
27153
- expect(element('.doc-example-live p:last').prop('className')).toBe('');
27154
- input('style1').enter('bold');
27155
- input('style2').enter('strike');
27156
- input('style3').enter('red');
27157
- expect(element('.doc-example-live p:last').prop('className')).toBe('bold strike red');
27370
+ expect(ps.last().getAttribute('class')).toBe('');
27371
+ element(by.model('style1')).sendKeys('bold');
27372
+ element(by.model('style2')).sendKeys('strike');
27373
+ element(by.model('style3')).sendKeys('red');
27374
+ expect(ps.last().getAttribute('class')).toBe('bold strike red');
27158
27375
  });
27159
27376
  </file>
27160
27377
  </example>
@@ -27165,8 +27382,8 @@ function classDirective(name, selector) {
27165
27382
 
27166
27383
  <example animations="true">
27167
27384
  <file name="index.html">
27168
- <input type="button" value="set" ng-click="myVar='my-class'">
27169
- <input type="button" value="clear" ng-click="myVar=''">
27385
+ <input id="setbtn" type="button" value="set" ng-click="myVar='my-class'">
27386
+ <input id="clearbtn" type="button" value="clear" ng-click="myVar=''">
27170
27387
  <br>
27171
27388
  <span class="base-class" ng-class="myVar">Sample Text</span>
27172
27389
  </file>
@@ -27181,19 +27398,19 @@ function classDirective(name, selector) {
27181
27398
  font-size:3em;
27182
27399
  }
27183
27400
  </file>
27184
- <file name="scenario.js">
27401
+ <file name="protractorTest.js">
27185
27402
  it('should check ng-class', function() {
27186
- expect(element('.doc-example-live span').prop('className')).not().
27403
+ expect(element(by.css('.base-class')).getAttribute('class')).not.
27187
27404
  toMatch(/my-class/);
27188
27405
 
27189
- using('.doc-example-live').element(':button:first').click();
27406
+ element(by.id('setbtn')).click();
27190
27407
 
27191
- expect(element('.doc-example-live span').prop('className')).
27408
+ expect(element(by.css('.base-class')).getAttribute('class')).
27192
27409
  toMatch(/my-class/);
27193
27410
 
27194
- using('.doc-example-live').element(':button:last').click();
27411
+ element(by.id('clearbtn')).click();
27195
27412
 
27196
- expect(element('.doc-example-live span').prop('className')).not().
27413
+ expect(element(by.css('.base-class')).getAttribute('class')).not.
27197
27414
  toMatch(/my-class/);
27198
27415
  });
27199
27416
  </file>
@@ -27245,11 +27462,11 @@ var ngClassDirective = classDirective('', true);
27245
27462
  color: blue;
27246
27463
  }
27247
27464
  </file>
27248
- <file name="scenario.js">
27465
+ <file name="protractorTest.js">
27249
27466
  it('should check ng-class-odd and ng-class-even', function() {
27250
- expect(element('.doc-example-live li:first span').prop('className')).
27467
+ expect(element(by.repeater('name in names').row(0).column('name')).getAttribute('class')).
27251
27468
  toMatch(/odd/);
27252
- expect(element('.doc-example-live li:last span').prop('className')).
27469
+ expect(element(by.repeater('name in names').row(1).column('name')).getAttribute('class')).
27253
27470
  toMatch(/even/);
27254
27471
  });
27255
27472
  </file>
@@ -27293,11 +27510,11 @@ var ngClassOddDirective = classDirective('Odd', 0);
27293
27510
  color: blue;
27294
27511
  }
27295
27512
  </file>
27296
- <file name="scenario.js">
27513
+ <file name="protractorTest.js">
27297
27514
  it('should check ng-class-odd and ng-class-even', function() {
27298
- expect(element('.doc-example-live li:first span').prop('className')).
27515
+ expect(element(by.repeater('name in names').row(0).column('name')).getAttribute('class')).
27299
27516
  toMatch(/odd/);
27300
- expect(element('.doc-example-live li:last span').prop('className')).
27517
+ expect(element(by.repeater('name in names').row(1).column('name')).getAttribute('class')).
27301
27518
  toMatch(/even/);
27302
27519
  });
27303
27520
  </file>
@@ -27350,14 +27567,14 @@ var ngClassEvenDirective = classDirective('Even', 1);
27350
27567
  <div id="template1" ng-cloak>{{ 'hello' }}</div>
27351
27568
  <div id="template2" ng-cloak class="ng-cloak">{{ 'hello IE7' }}</div>
27352
27569
  </doc:source>
27353
- <doc:scenario>
27570
+ <doc:protractor>
27354
27571
  it('should remove the template directive and css class', function() {
27355
- expect(element('.doc-example-live #template1').attr('ng-cloak')).
27356
- not().toBeDefined();
27357
- expect(element('.doc-example-live #template2').attr('ng-cloak')).
27358
- not().toBeDefined();
27572
+ expect($('.doc-example-live #template1').getAttribute('ng-cloak')).
27573
+ toBeNull();
27574
+ expect($('.doc-example-live #template2').getAttribute('ng-cloak')).
27575
+ toBeNull();
27359
27576
  });
27360
- </doc:scenario>
27577
+ </doc:protractor>
27361
27578
  </doc:example>
27362
27579
  *
27363
27580
  */
@@ -27450,22 +27667,36 @@ var ngCloakDirective = ngDirective({
27450
27667
  </ul>
27451
27668
  </div>
27452
27669
  </doc:source>
27453
- <doc:scenario>
27670
+ <doc:protractor>
27454
27671
  it('should check controller as', function() {
27455
- expect(element('#ctrl-as-exmpl>:input').val()).toBe('John Smith');
27456
- expect(element('#ctrl-as-exmpl li:nth-child(1) input').val())
27457
- .toBe('408 555 1212');
27458
- expect(element('#ctrl-as-exmpl li:nth-child(2) input').val())
27459
- .toBe('john.smith@example.org');
27460
-
27461
- element('#ctrl-as-exmpl li:first a:contains("clear")').click();
27462
- expect(element('#ctrl-as-exmpl li:first input').val()).toBe('');
27463
-
27464
- element('#ctrl-as-exmpl li:last a:contains("add")').click();
27465
- expect(element('#ctrl-as-exmpl li:nth-child(3) input').val())
27466
- .toBe('yourname@example.org');
27672
+ var container = element(by.id('ctrl-as-exmpl'));
27673
+
27674
+ expect(container.findElement(by.model('settings.name'))
27675
+ .getAttribute('value')).toBe('John Smith');
27676
+
27677
+ var firstRepeat =
27678
+ container.findElement(by.repeater('contact in settings.contacts').row(0));
27679
+ var secondRepeat =
27680
+ container.findElement(by.repeater('contact in settings.contacts').row(1));
27681
+
27682
+ expect(firstRepeat.findElement(by.model('contact.value')).getAttribute('value'))
27683
+ .toBe('408 555 1212');
27684
+ expect(secondRepeat.findElement(by.model('contact.value')).getAttribute('value'))
27685
+ .toBe('john.smith@example.org');
27686
+
27687
+ firstRepeat.findElement(by.linkText('clear')).click()
27688
+
27689
+ expect(firstRepeat.findElement(by.model('contact.value')).getAttribute('value'))
27690
+ .toBe('');
27691
+
27692
+ container.findElement(by.linkText('add')).click();
27693
+
27694
+ expect(container.findElement(by.repeater('contact in settings.contacts').row(2))
27695
+ .findElement(by.model('contact.value'))
27696
+ .getAttribute('value'))
27697
+ .toBe('yourname@example.org');
27467
27698
  });
27468
- </doc:scenario>
27699
+ </doc:protractor>
27469
27700
  </doc:example>
27470
27701
  <doc:example>
27471
27702
  <doc:source>
@@ -27513,22 +27744,36 @@ var ngCloakDirective = ngDirective({
27513
27744
  </ul>
27514
27745
  </div>
27515
27746
  </doc:source>
27516
- <doc:scenario>
27747
+ <doc:protractor>
27517
27748
  it('should check controller', function() {
27518
- expect(element('#ctrl-exmpl>:input').val()).toBe('John Smith');
27519
- expect(element('#ctrl-exmpl li:nth-child(1) input').val())
27520
- .toBe('408 555 1212');
27521
- expect(element('#ctrl-exmpl li:nth-child(2) input').val())
27522
- .toBe('john.smith@example.org');
27523
-
27524
- element('#ctrl-exmpl li:first a:contains("clear")').click();
27525
- expect(element('#ctrl-exmpl li:first input').val()).toBe('');
27526
-
27527
- element('#ctrl-exmpl li:last a:contains("add")').click();
27528
- expect(element('#ctrl-exmpl li:nth-child(3) input').val())
27529
- .toBe('yourname@example.org');
27749
+ var container = element(by.id('ctrl-exmpl'));
27750
+
27751
+ expect(container.findElement(by.model('name'))
27752
+ .getAttribute('value')).toBe('John Smith');
27753
+
27754
+ var firstRepeat =
27755
+ container.findElement(by.repeater('contact in contacts').row(0));
27756
+ var secondRepeat =
27757
+ container.findElement(by.repeater('contact in contacts').row(1));
27758
+
27759
+ expect(firstRepeat.findElement(by.model('contact.value')).getAttribute('value'))
27760
+ .toBe('408 555 1212');
27761
+ expect(secondRepeat.findElement(by.model('contact.value')).getAttribute('value'))
27762
+ .toBe('john.smith@example.org');
27763
+
27764
+ firstRepeat.findElement(by.linkText('clear')).click()
27765
+
27766
+ expect(firstRepeat.findElement(by.model('contact.value')).getAttribute('value'))
27767
+ .toBe('');
27768
+
27769
+ container.findElement(by.linkText('add')).click();
27770
+
27771
+ expect(container.findElement(by.repeater('contact in contacts').row(2))
27772
+ .findElement(by.model('contact.value'))
27773
+ .getAttribute('value'))
27774
+ .toBe('yourname@example.org');
27530
27775
  });
27531
- </doc:scenario>
27776
+ </doc:protractor>
27532
27777
  </doc:example>
27533
27778
 
27534
27779
  */
@@ -27591,6 +27836,7 @@ var ngControllerDirective = [function() {
27591
27836
  * an element is clicked.
27592
27837
  *
27593
27838
  * @element ANY
27839
+ * @priority 0
27594
27840
  * @param {expression} ngClick {@link guide/expression Expression} to evaluate upon
27595
27841
  * click. (Event object is available as `$event`)
27596
27842
  *
@@ -27647,6 +27893,7 @@ forEach(
27647
27893
  * The `ngDblclick` directive allows you to specify custom behavior on a dblclick event.
27648
27894
  *
27649
27895
  * @element ANY
27896
+ * @priority 0
27650
27897
  * @param {expression} ngDblclick {@link guide/expression Expression} to evaluate upon
27651
27898
  * a dblclick. (The Event object is available as `$event`)
27652
27899
  *
@@ -27670,6 +27917,7 @@ forEach(
27670
27917
  * The ngMousedown directive allows you to specify custom behavior on mousedown event.
27671
27918
  *
27672
27919
  * @element ANY
27920
+ * @priority 0
27673
27921
  * @param {expression} ngMousedown {@link guide/expression Expression} to evaluate upon
27674
27922
  * mousedown. (Event object is available as `$event`)
27675
27923
  *
@@ -27693,6 +27941,7 @@ forEach(
27693
27941
  * Specify custom behavior on mouseup event.
27694
27942
  *
27695
27943
  * @element ANY
27944
+ * @priority 0
27696
27945
  * @param {expression} ngMouseup {@link guide/expression Expression} to evaluate upon
27697
27946
  * mouseup. (Event object is available as `$event`)
27698
27947
  *
@@ -27715,6 +27964,7 @@ forEach(
27715
27964
  * Specify custom behavior on mouseover event.
27716
27965
  *
27717
27966
  * @element ANY
27967
+ * @priority 0
27718
27968
  * @param {expression} ngMouseover {@link guide/expression Expression} to evaluate upon
27719
27969
  * mouseover. (Event object is available as `$event`)
27720
27970
  *
@@ -27738,6 +27988,7 @@ forEach(
27738
27988
  * Specify custom behavior on mouseenter event.
27739
27989
  *
27740
27990
  * @element ANY
27991
+ * @priority 0
27741
27992
  * @param {expression} ngMouseenter {@link guide/expression Expression} to evaluate upon
27742
27993
  * mouseenter. (Event object is available as `$event`)
27743
27994
  *
@@ -27761,6 +28012,7 @@ forEach(
27761
28012
  * Specify custom behavior on mouseleave event.
27762
28013
  *
27763
28014
  * @element ANY
28015
+ * @priority 0
27764
28016
  * @param {expression} ngMouseleave {@link guide/expression Expression} to evaluate upon
27765
28017
  * mouseleave. (Event object is available as `$event`)
27766
28018
  *
@@ -27784,6 +28036,7 @@ forEach(
27784
28036
  * Specify custom behavior on mousemove event.
27785
28037
  *
27786
28038
  * @element ANY
28039
+ * @priority 0
27787
28040
  * @param {expression} ngMousemove {@link guide/expression Expression} to evaluate upon
27788
28041
  * mousemove. (Event object is available as `$event`)
27789
28042
  *
@@ -27807,6 +28060,7 @@ forEach(
27807
28060
  * Specify custom behavior on keydown event.
27808
28061
  *
27809
28062
  * @element ANY
28063
+ * @priority 0
27810
28064
  * @param {expression} ngKeydown {@link guide/expression Expression} to evaluate upon
27811
28065
  * keydown. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
27812
28066
  *
@@ -27828,6 +28082,7 @@ forEach(
27828
28082
  * Specify custom behavior on keyup event.
27829
28083
  *
27830
28084
  * @element ANY
28085
+ * @priority 0
27831
28086
  * @param {expression} ngKeyup {@link guide/expression Expression} to evaluate upon
27832
28087
  * keyup. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
27833
28088
  *
@@ -27870,10 +28125,11 @@ forEach(
27870
28125
  * Enables binding angular expressions to onsubmit events.
27871
28126
  *
27872
28127
  * Additionally it prevents the default action (which for form means sending the request to the
27873
- * server and reloading the current page) **but only if the form does not contain an `action`
27874
- * attribute**.
28128
+ * server and reloading the current page), but only if the form does not contain `action`,
28129
+ * `data-action`, or `x-action` attributes.
27875
28130
  *
27876
28131
  * @element form
28132
+ * @priority 0
27877
28133
  * @param {expression} ngSubmit {@link guide/expression Expression} to eval. (Event object is available as `$event`)
27878
28134
  *
27879
28135
  * @example
@@ -27898,20 +28154,20 @@ forEach(
27898
28154
  <pre>list={{list}}</pre>
27899
28155
  </form>
27900
28156
  </doc:source>
27901
- <doc:scenario>
28157
+ <doc:protractor>
27902
28158
  it('should check ng-submit', function() {
27903
- expect(binding('list')).toBe('[]');
27904
- element('.doc-example-live #submit').click();
27905
- expect(binding('list')).toBe('["hello"]');
27906
- expect(input('text').val()).toBe('');
28159
+ expect(element(by.binding('list')).getText()).toBe('list=[]');
28160
+ element(by.css('.doc-example-live #submit')).click();
28161
+ expect(element(by.binding('list')).getText()).toContain('hello');
28162
+ expect(element(by.input('text')).getAttribute('value')).toBe('');
27907
28163
  });
27908
28164
  it('should ignore empty strings', function() {
27909
- expect(binding('list')).toBe('[]');
27910
- element('.doc-example-live #submit').click();
27911
- element('.doc-example-live #submit').click();
27912
- expect(binding('list')).toBe('["hello"]');
27913
- });
27914
- </doc:scenario>
28165
+ expect(element(by.binding('list')).getText()).toBe('list=[]');
28166
+ element(by.css('.doc-example-live #submit')).click();
28167
+ element(by.css('.doc-example-live #submit')).click();
28168
+ expect(element(by.binding('list')).getText()).toContain('hello');
28169
+ });
28170
+ </doc:protractor>
27915
28171
  </doc:example>
27916
28172
  */
27917
28173
 
@@ -27923,6 +28179,7 @@ forEach(
27923
28179
  * Specify custom behavior on focus event.
27924
28180
  *
27925
28181
  * @element window, input, select, textarea, a
28182
+ * @priority 0
27926
28183
  * @param {expression} ngFocus {@link guide/expression Expression} to evaluate upon
27927
28184
  * focus. (Event object is available as `$event`)
27928
28185
  *
@@ -27938,6 +28195,7 @@ forEach(
27938
28195
  * Specify custom behavior on blur event.
27939
28196
  *
27940
28197
  * @element window, input, select, textarea, a
28198
+ * @priority 0
27941
28199
  * @param {expression} ngBlur {@link guide/expression Expression} to evaluate upon
27942
28200
  * blur. (Event object is available as `$event`)
27943
28201
  *
@@ -27953,6 +28211,7 @@ forEach(
27953
28211
  * Specify custom behavior on copy event.
27954
28212
  *
27955
28213
  * @element window, input, select, textarea, a
28214
+ * @priority 0
27956
28215
  * @param {expression} ngCopy {@link guide/expression Expression} to evaluate upon
27957
28216
  * copy. (Event object is available as `$event`)
27958
28217
  *
@@ -27973,6 +28232,7 @@ forEach(
27973
28232
  * Specify custom behavior on cut event.
27974
28233
  *
27975
28234
  * @element window, input, select, textarea, a
28235
+ * @priority 0
27976
28236
  * @param {expression} ngCut {@link guide/expression Expression} to evaluate upon
27977
28237
  * cut. (Event object is available as `$event`)
27978
28238
  *
@@ -27993,6 +28253,7 @@ forEach(
27993
28253
  * Specify custom behavior on paste event.
27994
28254
  *
27995
28255
  * @element window, input, select, textarea, a
28256
+ * @priority 0
27996
28257
  * @param {expression} ngPaste {@link guide/expression Expression} to evaluate upon
27997
28258
  * paste. (Event object is available as `$event`)
27998
28259
  *
@@ -28233,19 +28494,33 @@ var ngIfDirective = ['$animate', function($animate) {
28233
28494
  top:50px;
28234
28495
  }
28235
28496
  </file>
28236
- <file name="scenario.js">
28497
+ <file name="protractorTest.js">
28498
+ var templateSelect = element(by.model('template'));
28499
+ var includeElem = element(by.css('.doc-example-live [ng-include]'));
28500
+
28237
28501
  it('should load template1.html', function() {
28238
- expect(element('.doc-example-live [ng-include]').text()).
28239
- toMatch(/Content of template1.html/);
28502
+ expect(includeElem.getText()).toMatch(/Content of template1.html/);
28240
28503
  });
28504
+
28241
28505
  it('should load template2.html', function() {
28242
- select('template').option('1');
28243
- expect(element('.doc-example-live [ng-include]').text()).
28244
- toMatch(/Content of template2.html/);
28506
+ if (browser.params.browser == 'firefox') {
28507
+ // Firefox can't handle using selects
28508
+ // See https://github.com/angular/protractor/issues/480
28509
+ return;
28510
+ }
28511
+ templateSelect.click();
28512
+ templateSelect.element.all(by.css('option')).get(2).click();
28513
+ expect(includeElem.getText()).toMatch(/Content of template2.html/);
28245
28514
  });
28515
+
28246
28516
  it('should change to blank', function() {
28247
- select('template').option('');
28248
- expect(element('.doc-example-live [ng-include]')).toBe(undefined);
28517
+ if (browser.params.browser == 'firefox') {
28518
+ // Firefox can't handle using selects
28519
+ return;
28520
+ }
28521
+ templateSelect.click();
28522
+ templateSelect.element.all(by.css('option')).get(0).click();
28523
+ expect(includeElem.isPresent()).toBe(false);
28249
28524
  });
28250
28525
  </file>
28251
28526
  </example>
@@ -28376,6 +28651,13 @@ var ngIncludeFillContentDirective = ['$compile',
28376
28651
  * should use {@link guide/controller controllers} rather than `ngInit`
28377
28652
  * to initialize values on a scope.
28378
28653
  * </div>
28654
+ * <div class="alert alert-warning">
28655
+ * **Note**: If you have assignment in `ngInit` along with {@link api/ng.$filter `$filter`}, make
28656
+ * sure you have parenthesis for correct precedence:
28657
+ * <pre class="prettyprint">
28658
+ * <div ng-init="test1 = (data | orderBy:'name')"></div>
28659
+ * </pre>
28660
+ * </div>
28379
28661
  *
28380
28662
  * @priority 450
28381
28663
  *
@@ -28398,15 +28680,15 @@ var ngIncludeFillContentDirective = ['$compile',
28398
28680
  </div>
28399
28681
  </div>
28400
28682
  </doc:source>
28401
- <doc:scenario>
28683
+ <doc:protractor>
28402
28684
  it('should alias index positions', function() {
28403
- expect(element('.example-init').text())
28404
- .toBe('list[ 0 ][ 0 ] = a;' +
28405
- 'list[ 0 ][ 1 ] = b;' +
28406
- 'list[ 1 ][ 0 ] = c;' +
28407
- 'list[ 1 ][ 1 ] = d;');
28685
+ var elements = element.all(by.css('.example-init'));
28686
+ expect(elements.get(0).getText()).toBe('list[ 0 ][ 0 ] = a;');
28687
+ expect(elements.get(1).getText()).toBe('list[ 0 ][ 1 ] = b;');
28688
+ expect(elements.get(2).getText()).toBe('list[ 1 ][ 0 ] = c;');
28689
+ expect(elements.get(3).getText()).toBe('list[ 1 ][ 1 ] = d;');
28408
28690
  });
28409
- </doc:scenario>
28691
+ </doc:protractor>
28410
28692
  </doc:example>
28411
28693
  */
28412
28694
  var ngInitDirective = ngDirective({
@@ -28444,13 +28726,12 @@ var ngInitDirective = ngDirective({
28444
28726
  <div>Normal: {{1 + 2}}</div>
28445
28727
  <div ng-non-bindable>Ignored: {{1 + 2}}</div>
28446
28728
  </doc:source>
28447
- <doc:scenario>
28729
+ <doc:protractor>
28448
28730
  it('should check ng-non-bindable', function() {
28449
- expect(using('.doc-example-live').binding('1 + 2')).toBe('3');
28450
- expect(using('.doc-example-live').element('div:last').text()).
28451
- toMatch(/1 \+ 2/);
28731
+ expect(element(by.binding('1 + 2')).getText()).toContain('3');
28732
+ expect(element.all(by.css('.doc-example-live div')).last().getText()).toMatch(/1 \+ 2/);
28452
28733
  });
28453
- </doc:scenario>
28734
+ </doc:protractor>
28454
28735
  </doc:example>
28455
28736
  */
28456
28737
  var ngNonBindableDirective = ngDirective({ terminal: true, priority: 1000 });
@@ -28578,49 +28859,53 @@ var ngNonBindableDirective = ngDirective({ terminal: true, priority: 1000 });
28578
28859
  </ng-pluralize>
28579
28860
  </div>
28580
28861
  </doc:source>
28581
- <doc:scenario>
28862
+ <doc:protractor>
28582
28863
  it('should show correct pluralized string', function() {
28583
- expect(element('.doc-example-live ng-pluralize:first').text()).
28584
- toBe('1 person is viewing.');
28585
- expect(element('.doc-example-live ng-pluralize:last').text()).
28586
- toBe('Igor is viewing.');
28587
-
28588
- using('.doc-example-live').input('personCount').enter('0');
28589
- expect(element('.doc-example-live ng-pluralize:first').text()).
28590
- toBe('Nobody is viewing.');
28591
- expect(element('.doc-example-live ng-pluralize:last').text()).
28592
- toBe('Nobody is viewing.');
28593
-
28594
- using('.doc-example-live').input('personCount').enter('2');
28595
- expect(element('.doc-example-live ng-pluralize:first').text()).
28596
- toBe('2 people are viewing.');
28597
- expect(element('.doc-example-live ng-pluralize:last').text()).
28598
- toBe('Igor and Misko are viewing.');
28599
-
28600
- using('.doc-example-live').input('personCount').enter('3');
28601
- expect(element('.doc-example-live ng-pluralize:first').text()).
28602
- toBe('3 people are viewing.');
28603
- expect(element('.doc-example-live ng-pluralize:last').text()).
28604
- toBe('Igor, Misko and one other person are viewing.');
28605
-
28606
- using('.doc-example-live').input('personCount').enter('4');
28607
- expect(element('.doc-example-live ng-pluralize:first').text()).
28608
- toBe('4 people are viewing.');
28609
- expect(element('.doc-example-live ng-pluralize:last').text()).
28610
- toBe('Igor, Misko and 2 other people are viewing.');
28611
- });
28864
+ var withoutOffset = element.all(by.css('ng-pluralize')).get(0);
28865
+ var withOffset = element.all(by.css('ng-pluralize')).get(1);
28866
+ var countInput = element(by.model('personCount'));
28867
+
28868
+ expect(withoutOffset.getText()).toEqual('1 person is viewing.');
28869
+ expect(withOffset.getText()).toEqual('Igor is viewing.');
28870
+
28871
+ countInput.clear();
28872
+ countInput.sendKeys('0');
28873
+
28874
+ expect(withoutOffset.getText()).toEqual('Nobody is viewing.');
28875
+ expect(withOffset.getText()).toEqual('Nobody is viewing.');
28612
28876
 
28613
- it('should show data-binded names', function() {
28614
- using('.doc-example-live').input('personCount').enter('4');
28615
- expect(element('.doc-example-live ng-pluralize:last').text()).
28616
- toBe('Igor, Misko and 2 other people are viewing.');
28877
+ countInput.clear();
28878
+ countInput.sendKeys('2');
28617
28879
 
28618
- using('.doc-example-live').input('person1').enter('Di');
28619
- using('.doc-example-live').input('person2').enter('Vojta');
28620
- expect(element('.doc-example-live ng-pluralize:last').text()).
28621
- toBe('Di, Vojta and 2 other people are viewing.');
28880
+ expect(withoutOffset.getText()).toEqual('2 people are viewing.');
28881
+ expect(withOffset.getText()).toEqual('Igor and Misko are viewing.');
28882
+
28883
+ countInput.clear();
28884
+ countInput.sendKeys('3');
28885
+
28886
+ expect(withoutOffset.getText()).toEqual('3 people are viewing.');
28887
+ expect(withOffset.getText()).toEqual('Igor, Misko and one other person are viewing.');
28888
+
28889
+ countInput.clear();
28890
+ countInput.sendKeys('4');
28891
+
28892
+ expect(withoutOffset.getText()).toEqual('4 people are viewing.');
28893
+ expect(withOffset.getText()).toEqual('Igor, Misko and 2 other people are viewing.');
28894
+ });
28895
+ it('should show data-bound names', function() {
28896
+ var withOffset = element.all(by.css('ng-pluralize')).get(1);
28897
+ var personCount = element(by.model('personCount'));
28898
+ var person1 = element(by.model('person1'));
28899
+ var person2 = element(by.model('person2'));
28900
+ personCount.clear();
28901
+ personCount.sendKeys('4');
28902
+ person1.clear();
28903
+ person1.sendKeys('Di');
28904
+ person2.clear();
28905
+ person2.sendKeys('Vojta');
28906
+ expect(withOffset.getText()).toEqual('Di, Vojta and 2 other people are viewing.');
28622
28907
  });
28623
- </doc:scenario>
28908
+ </doc:protractor>
28624
28909
  </doc:example>
28625
28910
  */
28626
28911
  var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interpolate) {
@@ -28839,25 +29124,27 @@ var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interp
28839
29124
  max-height:40px;
28840
29125
  }
28841
29126
  </file>
28842
- <file name="scenario.js">
28843
- it('should render initial data set', function() {
28844
- var r = using('.doc-example-live').repeater('ul li');
28845
- expect(r.count()).toBe(10);
28846
- expect(r.row(0)).toEqual(["1","John","25"]);
28847
- expect(r.row(1)).toEqual(["2","Jessie","30"]);
28848
- expect(r.row(9)).toEqual(["10","Samantha","60"]);
28849
- expect(binding('friends.length')).toBe("10");
28850
- });
29127
+ <file name="protractorTest.js">
29128
+ var friends = element(by.css('.doc-example-live'))
29129
+ .element.all(by.repeater('friend in friends'));
29130
+
29131
+ it('should render initial data set', function() {
29132
+ expect(friends.count()).toBe(10);
29133
+ expect(friends.get(0).getText()).toEqual('[1] John who is 25 years old.');
29134
+ expect(friends.get(1).getText()).toEqual('[2] Jessie who is 30 years old.');
29135
+ expect(friends.last().getText()).toEqual('[10] Samantha who is 60 years old.');
29136
+ expect(element(by.binding('friends.length')).getText())
29137
+ .toMatch("I have 10 friends. They are:");
29138
+ });
28851
29139
 
28852
29140
  it('should update repeater when filter predicate changes', function() {
28853
- var r = using('.doc-example-live').repeater('ul li');
28854
- expect(r.count()).toBe(10);
29141
+ expect(friends.count()).toBe(10);
28855
29142
 
28856
- input('q').enter('ma');
29143
+ element(by.css('.doc-example-live')).element(by.model('q')).sendKeys('ma');
28857
29144
 
28858
- expect(r.count()).toBe(2);
28859
- expect(r.row(0)).toEqual(["1","Mary","28"]);
28860
- expect(r.row(1)).toEqual(["2","Samantha","60"]);
29145
+ expect(friends.count()).toBe(2);
29146
+ expect(friends.get(0).getText()).toEqual('[1] Mary who is 28 years old.');
29147
+ expect(friends.last().getText()).toEqual('[2] Samantha who is 60 years old.');
28861
29148
  });
28862
29149
  </file>
28863
29150
  </example>
@@ -29111,6 +29398,11 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
29111
29398
  *
29112
29399
  * Just remember to include the important flag so the CSS override will function.
29113
29400
  *
29401
+ * <div class="alert alert-warning">
29402
+ * **Note:** Here is a list of values that ngShow will consider as a falsy value (case insensitive):<br />
29403
+ * "f" / "0" / "false" / "no" / "n" / "[]"
29404
+ * </div>
29405
+ *
29114
29406
  * ## A note about animations with ngShow
29115
29407
  *
29116
29408
  * Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression
@@ -29186,16 +29478,19 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
29186
29478
  background:white;
29187
29479
  }
29188
29480
  </file>
29189
- <file name="scenario.js">
29190
- it('should check ng-show / ng-hide', function() {
29191
- expect(element('.doc-example-live span:first:hidden').count()).toEqual(1);
29192
- expect(element('.doc-example-live span:last:visible').count()).toEqual(1);
29481
+ <file name="protractorTest.js">
29482
+ var thumbsUp = element(by.css('.doc-example-live span.icon-thumbs-up'));
29483
+ var thumbsDown = element(by.css('.doc-example-live span.icon-thumbs-down'));
29193
29484
 
29194
- input('checked').check();
29485
+ it('should check ng-show / ng-hide', function() {
29486
+ expect(thumbsUp.isDisplayed()).toBeFalsy();
29487
+ expect(thumbsDown.isDisplayed()).toBeTruthy();
29195
29488
 
29196
- expect(element('.doc-example-live span:first:visible').count()).toEqual(1);
29197
- expect(element('.doc-example-live span:last:hidden').count()).toEqual(1);
29198
- });
29489
+ element(by.model('checked')).click();
29490
+
29491
+ expect(thumbsUp.isDisplayed()).toBeTruthy();
29492
+ expect(thumbsDown.isDisplayed()).toBeFalsy();
29493
+ });
29199
29494
  </file>
29200
29495
  </example>
29201
29496
  */
@@ -29259,6 +29554,11 @@ var ngShowDirective = ['$animate', function($animate) {
29259
29554
  * </pre>
29260
29555
  *
29261
29556
  * Just remember to include the important flag so the CSS override will function.
29557
+ *
29558
+ * <div class="alert alert-warning">
29559
+ * **Note:** Here is a list of values that ngHide will consider as a falsy value (case insensitive):<br />
29560
+ * "f" / "0" / "false" / "no" / "n" / "[]"
29561
+ * </div>
29262
29562
  *
29263
29563
  * ## A note about animations with ngHide
29264
29564
  *
@@ -29335,16 +29635,19 @@ var ngShowDirective = ['$animate', function($animate) {
29335
29635
  background:white;
29336
29636
  }
29337
29637
  </file>
29338
- <file name="scenario.js">
29339
- it('should check ng-show / ng-hide', function() {
29340
- expect(element('.doc-example-live .check-element:first:hidden').count()).toEqual(1);
29341
- expect(element('.doc-example-live .check-element:last:visible').count()).toEqual(1);
29638
+ <file name="protractorTest.js">
29639
+ var thumbsUp = element(by.css('.doc-example-live span.icon-thumbs-up'));
29640
+ var thumbsDown = element(by.css('.doc-example-live span.icon-thumbs-down'));
29342
29641
 
29343
- input('checked').check();
29642
+ it('should check ng-show / ng-hide', function() {
29643
+ expect(thumbsUp.isDisplayed()).toBeFalsy();
29644
+ expect(thumbsDown.isDisplayed()).toBeTruthy();
29344
29645
 
29345
- expect(element('.doc-example-live .check-element:first:visible').count()).toEqual(1);
29346
- expect(element('.doc-example-live .check-element:last:hidden').count()).toEqual(1);
29347
- });
29646
+ element(by.model('checked')).click();
29647
+
29648
+ expect(thumbsUp.isDisplayed()).toBeTruthy();
29649
+ expect(thumbsDown.isDisplayed()).toBeFalsy();
29650
+ });
29348
29651
  </file>
29349
29652
  </example>
29350
29653
  */
@@ -29383,13 +29686,15 @@ var ngHideDirective = ['$animate', function($animate) {
29383
29686
  color: black;
29384
29687
  }
29385
29688
  </file>
29386
- <file name="scenario.js">
29689
+ <file name="protractorTest.js">
29690
+ var colorSpan = element(by.css('.doc-example-live span'));
29691
+
29387
29692
  it('should check ng-style', function() {
29388
- expect(element('.doc-example-live span').css('color')).toBe('rgb(0, 0, 0)');
29389
- element('.doc-example-live :button[value=set]').click();
29390
- expect(element('.doc-example-live span').css('color')).toBe('rgb(255, 0, 0)');
29391
- element('.doc-example-live :button[value=clear]').click();
29392
- expect(element('.doc-example-live span').css('color')).toBe('rgb(0, 0, 0)');
29693
+ expect(colorSpan.getCssValue('color')).toBe('rgba(0, 0, 0, 1)');
29694
+ element(by.css('.doc-example-live input[value=set]')).click();
29695
+ expect(colorSpan.getCssValue('color')).toBe('rgba(255, 0, 0, 1)');
29696
+ element(by.css('.doc-example-live input[value=clear]')).click();
29697
+ expect(colorSpan.getCssValue('color')).toBe('rgba(0, 0, 0, 1)');
29393
29698
  });
29394
29699
  </file>
29395
29700
  </example>
@@ -29414,7 +29719,7 @@ var ngStyleDirective = ngDirective(function(scope, element, attr) {
29414
29719
  * as specified in the template.
29415
29720
  *
29416
29721
  * The directive itself works similar to ngInclude, however, instead of downloading template code (or loading it
29417
- * from the template cache), `ngSwitch` simply choses one of the nested elements and makes it visible based on which element
29722
+ * from the template cache), `ngSwitch` simply chooses one of the nested elements and makes it visible based on which element
29418
29723
  * matches the value obtained from the evaluated expression. In other words, you define a container element
29419
29724
  * (where you place the directive), place an expression on the **`on="..."` attribute**
29420
29725
  * (or the **`ng-switch="..."` attribute**), define any inner elements inside of the directive and place
@@ -29510,17 +29815,20 @@ var ngStyleDirective = ngDirective(function(scope, element, attr) {
29510
29815
  top:0;
29511
29816
  }
29512
29817
  </file>
29513
- <file name="scenario.js">
29818
+ <file name="protractorTest.js">
29819
+ var switchElem = element(by.css('.doc-example-live [ng-switch]'));
29820
+ var select = element(by.model('selection'));
29821
+
29514
29822
  it('should start in settings', function() {
29515
- expect(element('.doc-example-live [ng-switch]').text()).toMatch(/Settings Div/);
29823
+ expect(switchElem.getText()).toMatch(/Settings Div/);
29516
29824
  });
29517
29825
  it('should change to home', function() {
29518
- select('selection').option('home');
29519
- expect(element('.doc-example-live [ng-switch]').text()).toMatch(/Home Span/);
29826
+ select.element.all(by.css('option')).get(1).click();
29827
+ expect(switchElem.getText()).toMatch(/Home Span/);
29520
29828
  });
29521
29829
  it('should select default', function() {
29522
- select('selection').option('other');
29523
- expect(element('.doc-example-live [ng-switch]').text()).toMatch(/default/);
29830
+ select.element.all(by.css('option')).get(2).click();
29831
+ expect(switchElem.getText()).toMatch(/default/);
29524
29832
  });
29525
29833
  </file>
29526
29834
  </example>
@@ -29627,35 +29935,32 @@ var ngSwitchDefaultDirective = ngDirective({
29627
29935
  <pane title="{{title}}">{{text}}</pane>
29628
29936
  </div>
29629
29937
  </doc:source>
29630
- <doc:scenario>
29938
+ <doc:protractor>
29631
29939
  it('should have transcluded', function() {
29632
- input('title').enter('TITLE');
29633
- input('text').enter('TEXT');
29634
- expect(binding('title')).toEqual('TITLE');
29635
- expect(binding('text')).toEqual('TEXT');
29940
+ var titleElement = element(by.model('title'));
29941
+ titleElement.clear();
29942
+ titleElement.sendKeys('TITLE');
29943
+ var textElement = element(by.model('text'));
29944
+ textElement.clear();
29945
+ textElement.sendKeys('TEXT');
29946
+ expect(element(by.binding('title')).getText()).toEqual('TITLE');
29947
+ expect(element(by.binding('text')).getText()).toEqual('TEXT');
29636
29948
  });
29637
- </doc:scenario>
29949
+ </doc:protractor>
29638
29950
  </doc:example>
29639
29951
  *
29640
29952
  */
29641
29953
  var ngTranscludeDirective = ngDirective({
29642
- controller: ['$element', '$transclude', function($element, $transclude) {
29954
+ link: function($scope, $element, $attrs, controller, $transclude) {
29643
29955
  if (!$transclude) {
29644
29956
  throw minErr('ngTransclude')('orphan',
29645
- 'Illegal use of ngTransclude directive in the template! ' +
29646
- 'No parent directive that requires a transclusion found. ' +
29647
- 'Element: {0}',
29648
- startingTag($element));
29957
+ 'Illegal use of ngTransclude directive in the template! ' +
29958
+ 'No parent directive that requires a transclusion found. ' +
29959
+ 'Element: {0}',
29960
+ startingTag($element));
29649
29961
  }
29650
-
29651
- // remember the transclusion fn but call it during linking so that we don't process transclusion before directives on
29652
- // the parent element even when the transclusion replaces the current element. (we can't use priority here because
29653
- // that applies only to compile fns and not controllers
29654
- this.$transclude = $transclude;
29655
- }],
29656
-
29657
- link: function($scope, $element, $attrs, controller) {
29658
- controller.$transclude(function(clone) {
29962
+
29963
+ $transclude(function(clone) {
29659
29964
  $element.empty();
29660
29965
  $element.append(clone);
29661
29966
  });
@@ -29687,12 +29992,12 @@ var ngTranscludeDirective = ngDirective({
29687
29992
  <a ng-click="currentTpl='/tpl.html'" id="tpl-link">Load inlined template</a>
29688
29993
  <div id="tpl-content" ng-include src="currentTpl"></div>
29689
29994
  </doc:source>
29690
- <doc:scenario>
29995
+ <doc:protractor>
29691
29996
  it('should load template defined inside script tag', function() {
29692
- element('#tpl-link').click();
29693
- expect(element('#tpl-content').text()).toMatch(/Content of the template/);
29997
+ element(by.css('#tpl-link')).click();
29998
+ expect(element(by.css('#tpl-content')).getText()).toMatch(/Content of the template/);
29694
29999
  });
29695
- </doc:scenario>
30000
+ </doc:protractor>
29696
30001
  </doc:example>
29697
30002
  */
29698
30003
  var scriptDirective = ['$templateCache', function($templateCache) {
@@ -29730,14 +30035,21 @@ var ngOptionsMinErr = minErr('ngOptions');
29730
30035
  * represented by the selected option will be bound to the model identified by the `ngModel`
29731
30036
  * directive.
29732
30037
  *
30038
+ * <div class="alert alert-warning">
30039
+ * **Note:** `ngModel` compares by reference, not value. This is important when binding to an
30040
+ * array of objects. See an example {@link http://jsfiddle.net/qWzTb/ in this jsfiddle}.
30041
+ * </div>
30042
+ *
29733
30043
  * Optionally, a single hard-coded `<option>` element, with the value set to an empty string, can
29734
30044
  * be nested into the `<select>` element. This element will then represent the `null` or "not selected"
29735
30045
  * option. See example below for demonstration.
29736
30046
  *
29737
- * Note: `ngOptions` provides iterator facility for `<option>` element which should be used instead
30047
+ * <div class="alert alert-warning">
30048
+ * **Note:** `ngOptions` provides an iterator facility for the `<option>` element which should be used instead
29738
30049
  * of {@link ng.directive:ngRepeat ngRepeat} when you want the
29739
30050
  * `select` model to be bound to a non-string value. This is because an option element can only
29740
30051
  * be bound to string values at present.
30052
+ * </div>
29741
30053
  *
29742
30054
  * @param {string} ngModel Assignable angular expression to data-bind to.
29743
30055
  * @param {string=} name Property name of the form under which the control is published.
@@ -29824,15 +30136,17 @@ var ngOptionsMinErr = minErr('ngOptions');
29824
30136
  </div>
29825
30137
  </div>
29826
30138
  </doc:source>
29827
- <doc:scenario>
30139
+ <doc:protractor>
29828
30140
  it('should check ng-options', function() {
29829
- expect(binding('{selected_color:color}')).toMatch('red');
29830
- select('color').option('0');
29831
- expect(binding('{selected_color:color}')).toMatch('black');
29832
- using('.nullable').select('color').option('');
29833
- expect(binding('{selected_color:color}')).toMatch('null');
30141
+ expect(element(by.binding('{selected_color:color}')).getText()).toMatch('red');
30142
+ element.all(by.select('color')).first().click();
30143
+ element.all(by.css('select[ng-model="color"] option')).first().click();
30144
+ expect(element(by.binding('{selected_color:color}')).getText()).toMatch('black');
30145
+ element(by.css('.nullable select[ng-model="color"]')).click();
30146
+ element.all(by.css('.nullable select[ng-model="color"] option')).first().click();
30147
+ expect(element(by.binding('{selected_color:color}')).getText()).toMatch('null');
29834
30148
  });
29835
- </doc:scenario>
30149
+ </doc:protractor>
29836
30150
  </doc:example>
29837
30151
  */
29838
30152
 
@@ -30141,7 +30455,7 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
30141
30455
 
30142
30456
  // We now build up the list of options we need (we merge later)
30143
30457
  for (index = 0; length = keys.length, index < length; index++) {
30144
-
30458
+
30145
30459
  key = index;
30146
30460
  if (keyName) {
30147
30461
  key = keys[index];
@@ -32562,5 +32876,5 @@ if (config.autotest) {
32562
32876
  })(window, document);
32563
32877
 
32564
32878
 
32565
- !angular.$$csp() && angular.element(document).find('head').prepend('<style type="text/css">@charset "UTF-8";\n\n[ng\\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak],\n.ng-cloak, .x-ng-cloak,\n.ng-hide {\n display: none !important;\n}\n\nng\\:form {\n display: block;\n}\n</style>');
32879
+ !angular.$$csp() && angular.element(document).find('head').prepend('<style type="text/css">@charset "UTF-8";\n\n[ng\\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak],\n.ng-cloak, .x-ng-cloak,\n.ng-hide {\n display: none !important;\n}\n\nng\\:form {\n display: block;\n}\n\n.ng-animate-block-transitions {\n transition:0s all!important;\n -webkit-transition:0s all!important;\n}\n</style>');
32566
32880
  !angular.$$csp() && angular.element(document).find('head').prepend('<style type="text/css">@charset "UTF-8";\n/* CSS Document */\n\n/** Structure */\nbody {\n font-family: Arial, sans-serif;\n margin: 0;\n font-size: 14px;\n}\n\n#system-error {\n font-size: 1.5em;\n text-align: center;\n}\n\n#json, #xml {\n display: none;\n}\n\n#header {\n position: fixed;\n width: 100%;\n}\n\n#specs {\n padding-top: 50px;\n}\n\n#header .angular {\n font-family: Courier New, monospace;\n font-weight: bold;\n}\n\n#header h1 {\n font-weight: normal;\n float: left;\n font-size: 30px;\n line-height: 30px;\n margin: 0;\n padding: 10px 10px;\n height: 30px;\n}\n\n#application h2,\n#specs h2 {\n margin: 0;\n padding: 0.5em;\n font-size: 1.1em;\n}\n\n#status-legend {\n margin-top: 10px;\n margin-right: 10px;\n}\n\n#header,\n#application,\n.test-info,\n.test-actions li {\n overflow: hidden;\n}\n\n#application {\n margin: 10px;\n}\n\n#application iframe {\n width: 100%;\n height: 758px;\n}\n\n#application .popout {\n float: right;\n}\n\n#application iframe {\n border: none;\n}\n\n.tests li,\n.test-actions li,\n.test-it li,\n.test-it ol,\n.status-display {\n list-style-type: none;\n}\n\n.tests,\n.test-it ol,\n.status-display {\n margin: 0;\n padding: 0;\n}\n\n.test-info {\n margin-left: 1em;\n margin-top: 0.5em;\n border-radius: 8px 0 0 8px;\n -webkit-border-radius: 8px 0 0 8px;\n -moz-border-radius: 8px 0 0 8px;\n cursor: pointer;\n}\n\n.test-info:hover .test-name {\n text-decoration: underline;\n}\n\n.test-info .closed:before {\n content: \'\\25b8\\00A0\';\n}\n\n.test-info .open:before {\n content: \'\\25be\\00A0\';\n font-weight: bold;\n}\n\n.test-it ol {\n margin-left: 2.5em;\n}\n\n.status-display,\n.status-display li {\n float: right;\n}\n\n.status-display li {\n padding: 5px 10px;\n}\n\n.timer-result,\n.test-title {\n display: inline-block;\n margin: 0;\n padding: 4px;\n}\n\n.test-actions .test-title,\n.test-actions .test-result {\n display: table-cell;\n padding-left: 0.5em;\n padding-right: 0.5em;\n}\n\n.test-actions {\n display: table;\n}\n\n.test-actions li {\n display: table-row;\n}\n\n.timer-result {\n width: 4em;\n padding: 0 10px;\n text-align: right;\n font-family: monospace;\n}\n\n.test-it pre,\n.test-actions pre {\n clear: left;\n color: black;\n margin-left: 6em;\n}\n\n.test-describe {\n padding-bottom: 0.5em;\n}\n\n.test-describe .test-describe {\n margin: 5px 5px 10px 2em;\n}\n\n.test-actions .status-pending .test-title:before {\n content: \'\\00bb\\00A0\';\n}\n\n.scrollpane {\n max-height: 20em;\n overflow: auto;\n}\n\n/** Colors */\n\n#header {\n background-color: #F2C200;\n}\n\n#specs h2 {\n border-top: 2px solid #BABAD1;\n}\n\n#specs h2,\n#application h2 {\n background-color: #efefef;\n}\n\n#application {\n border: 1px solid #BABAD1;\n}\n\n.test-describe .test-describe {\n border-left: 1px solid #BABAD1;\n border-right: 1px solid #BABAD1;\n border-bottom: 1px solid #BABAD1;\n}\n\n.status-display {\n border: 1px solid #777;\n}\n\n.status-display .status-pending,\n.status-pending .test-info {\n background-color: #F9EEBC;\n}\n\n.status-display .status-success,\n.status-success .test-info {\n background-color: #B1D7A1;\n}\n\n.status-display .status-failure,\n.status-failure .test-info {\n background-color: #FF8286;\n}\n\n.status-display .status-error,\n.status-error .test-info {\n background-color: black;\n color: white;\n}\n\n.test-actions .status-success .test-title {\n color: #30B30A;\n}\n\n.test-actions .status-failure .test-title {\n color: #DF0000;\n}\n\n.test-actions .status-error .test-title {\n color: black;\n}\n\n.test-actions .timer-result {\n color: #888;\n}\n</style>');