angular-gem 1.2.12 → 1.2.13

Sign up to get free protection for your applications and to get access to all the features.
@@ -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>');