angular-gem 1.2.12 → 1.2.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license AngularJS v1.2.9
2
+ * @license AngularJS v1.2.13
3
3
  * (c) 2010-2014 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license AngularJS v1.2.9
2
+ * @license AngularJS v1.2.13
3
3
  * (c) 2010-2014 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
@@ -68,7 +68,7 @@ function minErr(module) {
68
68
  return match;
69
69
  });
70
70
 
71
- message = message + '\nhttp://errors.angularjs.org/1.2.9/' +
71
+ message = message + '\nhttp://errors.angularjs.org/1.2.13/' +
72
72
  (module ? module + '/' : '') + code;
73
73
  for (i = 2; i < arguments.length; i++) {
74
74
  message = message + (i == 2 ? '?' : '&') + 'p' + (i-2) + '=' +
@@ -160,6 +160,7 @@ function minErr(module) {
160
160
  -assertNotHasOwnProperty,
161
161
  -getter,
162
162
  -getBlockElements,
163
+ -hasOwnProperty,
163
164
 
164
165
  */
165
166
 
@@ -175,7 +176,7 @@ function minErr(module) {
175
176
  * @returns {string} Lowercased string.
176
177
  */
177
178
  var lowercase = function(string){return isString(string) ? string.toLowerCase() : string;};
178
-
179
+ var hasOwnProperty = Object.prototype.hasOwnProperty;
179
180
 
180
181
  /**
181
182
  * @ngdoc function
@@ -271,7 +272,7 @@ function isArrayLike(obj) {
271
272
  * is the value of an object property or an array element and `key` is the object property key or
272
273
  * array element index. Specifying a `context` for the function is optional.
273
274
  *
274
- * It is worth nothing that `.forEach` does not iterate over inherited properties because it filters
275
+ * It is worth noting that `.forEach` does not iterate over inherited properties because it filters
275
276
  * using the `hasOwnProperty` method.
276
277
  *
277
278
  <pre>
@@ -280,7 +281,7 @@ function isArrayLike(obj) {
280
281
  angular.forEach(values, function(value, key){
281
282
  this.push(key + ': ' + value);
282
283
  }, log);
283
- expect(log).toEqual(['name: misko', 'gender:male']);
284
+ expect(log).toEqual(['name: misko', 'gender: male']);
284
285
  </pre>
285
286
  *
286
287
  * @param {Object|Array} obj Object to iterate over.
@@ -851,7 +852,7 @@ function shallowCopy(src, dst) {
851
852
  for(var key in src) {
852
853
  // shallowCopy is only ever called by $compile nodeLinkFn, which has control over src
853
854
  // so we don't need to worry about using our custom hasOwnProperty here
854
- if (src.hasOwnProperty(key) && key.charAt(0) !== '$' && key.charAt(1) !== '$') {
855
+ if (src.hasOwnProperty(key) && !(key.charAt(0) === '$' && key.charAt(1) === '$')) {
855
856
  dst[key] = src[key];
856
857
  }
857
858
  }
@@ -1210,6 +1211,7 @@ function encodeUriQuery(val, pctEncodeSpaces) {
1210
1211
  <file name="index.html">
1211
1212
  <div ng-controller="ngAppDemoController">
1212
1213
  I can add: {{a}} + {{b}} = {{ a+b }}
1214
+ </div>
1213
1215
  </file>
1214
1216
  <file name="script.js">
1215
1217
  angular.module('ngAppDemo', []).controller('ngAppDemoController', function($scope) {
@@ -1834,11 +1836,11 @@ function setupModuleLoader(window) {
1834
1836
  * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
1835
1837
  */
1836
1838
  var version = {
1837
- full: '1.2.9', // all of these placeholder strings will be replaced by grunt's
1839
+ full: '1.2.13', // all of these placeholder strings will be replaced by grunt's
1838
1840
  major: 1, // package task
1839
1841
  minor: 2,
1840
- dot: 9,
1841
- codeName: 'enchanted-articulacy'
1842
+ dot: 13,
1843
+ codeName: 'romantic-transclusion'
1842
1844
  };
1843
1845
 
1844
1846
 
@@ -2000,7 +2002,7 @@ function publishExternalAPI(angular){
2000
2002
  * - [`after()`](http://api.jquery.com/after/)
2001
2003
  * - [`append()`](http://api.jquery.com/append/)
2002
2004
  * - [`attr()`](http://api.jquery.com/attr/)
2003
- * - [`bind()`](http://api.jquery.com/on/) - Does not support namespaces, selectors or eventData
2005
+ * - [`bind()`](http://api.jquery.com/bind/) - Does not support namespaces, selectors or eventData
2004
2006
  * - [`children()`](http://api.jquery.com/children/) - Does not support selectors
2005
2007
  * - [`clone()`](http://api.jquery.com/clone/)
2006
2008
  * - [`contents()`](http://api.jquery.com/contents/)
@@ -2027,7 +2029,7 @@ function publishExternalAPI(angular){
2027
2029
  * - [`text()`](http://api.jquery.com/text/)
2028
2030
  * - [`toggleClass()`](http://api.jquery.com/toggleClass/)
2029
2031
  * - [`triggerHandler()`](http://api.jquery.com/triggerHandler/) - Passes a dummy event object to handlers.
2030
- * - [`unbind()`](http://api.jquery.com/off/) - Does not support namespaces
2032
+ * - [`unbind()`](http://api.jquery.com/unbind/) - Does not support namespaces
2031
2033
  * - [`val()`](http://api.jquery.com/val/)
2032
2034
  * - [`wrap()`](http://api.jquery.com/wrap/)
2033
2035
  *
@@ -2067,6 +2069,14 @@ var jqCache = JQLite.cache = {},
2067
2069
  ? function(element, type, fn) {element.removeEventListener(type, fn, false); }
2068
2070
  : function(element, type, fn) {element.detachEvent('on' + type, fn); });
2069
2071
 
2072
+ /*
2073
+ * !!! This is an undocumented "private" function !!!
2074
+ */
2075
+ var jqData = JQLite._data = function(node) {
2076
+ //jQuery always returns an object on cache miss
2077
+ return this.cache[node[this.expando]] || {};
2078
+ };
2079
+
2070
2080
  function jqNextId() { return ++jqId; }
2071
2081
 
2072
2082
 
@@ -2135,6 +2145,9 @@ function JQLite(element) {
2135
2145
  if (element instanceof JQLite) {
2136
2146
  return element;
2137
2147
  }
2148
+ if (isString(element)) {
2149
+ element = trim(element);
2150
+ }
2138
2151
  if (!(this instanceof JQLite)) {
2139
2152
  if (isString(element) && element.charAt(0) != '<') {
2140
2153
  throw jqLiteMinErr('nosel', 'Looking up elements via selectors is not supported by jqLite! See: http://docs.angularjs.org/api/angular.element');
@@ -3280,11 +3293,9 @@ function annotate(fn) {
3280
3293
  * @param {(Object|function())} provider If the provider is:
3281
3294
  *
3282
3295
  * - `Object`: then it should have a `$get` method. The `$get` method will be invoked using
3283
- * {@link AUTO.$injector#invoke $injector.invoke()} when an instance needs to be
3284
- * created.
3285
- * - `Constructor`: a new instance of the provider will be created using
3286
- * {@link AUTO.$injector#instantiate $injector.instantiate()}, then treated as
3287
- * `object`.
3296
+ * {@link AUTO.$injector#invoke $injector.invoke()} when an instance needs to be created.
3297
+ * - `Constructor`: a new instance of the provider will be created using
3298
+ * {@link AUTO.$injector#instantiate $injector.instantiate()}, then treated as `object`.
3288
3299
  *
3289
3300
  * @returns {Object} registered provider instance
3290
3301
 
@@ -3410,17 +3421,16 @@ function annotate(fn) {
3410
3421
  * Here is an example of registering a service using
3411
3422
  * {@link AUTO.$provide#methods_service $provide.service(class)}.
3412
3423
  * <pre>
3413
- * $provide.service('ping', ['$http', function($http) {
3414
- * var Ping = function() {
3415
- * this.$http = $http;
3416
- * };
3417
- *
3418
- * Ping.prototype.send = function() {
3419
- * return this.$http.get('/ping');
3420
- * };
3424
+ * var Ping = function($http) {
3425
+ * this.$http = $http;
3426
+ * };
3427
+ *
3428
+ * Ping.$inject = ['$http'];
3421
3429
  *
3422
- * return Ping;
3423
- * }]);
3430
+ * Ping.prototype.send = function() {
3431
+ * return this.$http.get('/ping');
3432
+ * };
3433
+ * $provide.service('ping', Ping);
3424
3434
  * </pre>
3425
3435
  * You would then inject and use this service like this:
3426
3436
  * <pre>
@@ -3518,7 +3528,7 @@ function annotate(fn) {
3518
3528
  * Here we decorate the {@link ng.$log $log} service to convert warnings to errors by intercepting
3519
3529
  * calls to {@link ng.$log#error $log.warn()}.
3520
3530
  * <pre>
3521
- * $provider.decorator('$log', ['$delegate', function($delegate) {
3531
+ * $provide.decorator('$log', ['$delegate', function($delegate) {
3522
3532
  * $delegate.warn = $delegate.error;
3523
3533
  * return $delegate;
3524
3534
  * }]);
@@ -4057,6 +4067,29 @@ var $AnimateProvider = ['$provide', function($provide) {
4057
4067
  done && $timeout(done, 0, false);
4058
4068
  },
4059
4069
 
4070
+ /**
4071
+ *
4072
+ * @ngdoc function
4073
+ * @name ng.$animate#setClass
4074
+ * @methodOf ng.$animate
4075
+ * @function
4076
+ * @description Adds and/or removes the given CSS classes to and from the element.
4077
+ * Once complete, the done() callback will be fired (if provided).
4078
+ * @param {jQuery/jqLite element} element the element which will it's CSS classes changed
4079
+ * removed from it
4080
+ * @param {string} add the CSS classes which will be added to the element
4081
+ * @param {string} remove the CSS class which will be removed from the element
4082
+ * @param {function=} done the callback function (if provided) that will be fired after the
4083
+ * CSS classes have been set on the element
4084
+ */
4085
+ setClass : function(element, add, remove, done) {
4086
+ forEach(element, function (element) {
4087
+ jqLiteAddClass(element, add);
4088
+ jqLiteRemoveClass(element, remove);
4089
+ });
4090
+ done && $timeout(done, 0, false);
4091
+ },
4092
+
4060
4093
  enabled : noop
4061
4094
  };
4062
4095
  }];
@@ -5121,13 +5154,17 @@ function $TemplateCacheProvider() {
5121
5154
  <div compile="html"></div>
5122
5155
  </div>
5123
5156
  </doc:source>
5124
- <doc:scenario>
5157
+ <doc:protractor>
5125
5158
  it('should auto compile', function() {
5126
- expect(element('div[compile]').text()).toBe('Hello Angular');
5127
- input('html').enter('{{name}}!');
5128
- expect(element('div[compile]').text()).toBe('Angular!');
5159
+ var textarea = $('textarea');
5160
+ var output = $('div[compile]');
5161
+ // The initial state reads 'Hello Angular'.
5162
+ expect(output.getText()).toBe('Hello Angular');
5163
+ textarea.clear();
5164
+ textarea.sendKeys('{{name}}!');
5165
+ expect(output.getText()).toBe('Angular!');
5129
5166
  });
5130
- </doc:scenario>
5167
+ </doc:protractor>
5131
5168
  </doc:example>
5132
5169
 
5133
5170
  *
@@ -5195,7 +5232,8 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
5195
5232
  var hasDirectives = {},
5196
5233
  Suffix = 'Directive',
5197
5234
  COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\d\w\-_]+)\s+(.*)$/,
5198
- CLASS_DIRECTIVE_REGEXP = /(([\d\w\-_]+)(?:\:([^;]+))?;?)/;
5235
+ CLASS_DIRECTIVE_REGEXP = /(([\d\w\-_]+)(?:\:([^;]+))?;?)/,
5236
+ TABLE_CONTENT_REGEXP = /^<\s*(tr|th|td|tbody)(\s+[^>]*)?>/i;
5199
5237
 
5200
5238
  // Ref: http://developers.whatwg.org/webappapis.html#event-handler-idl-attributes
5201
5239
  // The assumption is that future DOM event attribute names will begin with
@@ -5382,8 +5420,16 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
5382
5420
  * @param {string} oldClasses The former CSS className value
5383
5421
  */
5384
5422
  $updateClass : function(newClasses, oldClasses) {
5385
- this.$removeClass(tokenDifference(oldClasses, newClasses));
5386
- this.$addClass(tokenDifference(newClasses, oldClasses));
5423
+ var toAdd = tokenDifference(newClasses, oldClasses);
5424
+ var toRemove = tokenDifference(oldClasses, newClasses);
5425
+
5426
+ if(toAdd.length === 0) {
5427
+ $animate.removeClass(this.$$element, toRemove);
5428
+ } else if(toRemove.length === 0) {
5429
+ $animate.addClass(this.$$element, toAdd);
5430
+ } else {
5431
+ $animate.setClass(this.$$element, toAdd, toRemove);
5432
+ }
5387
5433
  },
5388
5434
 
5389
5435
  /**
@@ -5835,7 +5881,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
5835
5881
  templateDirective = previousCompileContext.templateDirective,
5836
5882
  nonTlbTranscludeDirective = previousCompileContext.nonTlbTranscludeDirective,
5837
5883
  hasTranscludeDirective = false,
5838
- hasElementTranscludeDirective = false,
5884
+ hasElementTranscludeDirective = previousCompileContext.hasElementTranscludeDirective,
5839
5885
  $compileNode = templateAttrs.$$element = jqLite(compileNode),
5840
5886
  directive,
5841
5887
  directiveName,
@@ -5889,7 +5935,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
5889
5935
  hasTranscludeDirective = true;
5890
5936
 
5891
5937
  // Special case ngIf and ngRepeat so that we don't complain about duplicate transclusion.
5892
- // This option should only be used by directives that know how to how to safely handle element transclusion,
5938
+ // This option should only be used by directives that know how to safely handle element transclusion,
5893
5939
  // where the transcluded nodes are added or replaced after linking.
5894
5940
  if (!directive.$$tlb) {
5895
5941
  assertNoDuplicate('transclusion', nonTlbTranscludeDirective, directive, $compileNode);
@@ -5936,9 +5982,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
5936
5982
 
5937
5983
  if (directive.replace) {
5938
5984
  replaceDirective = directive;
5939
- $template = jqLite('<div>' +
5940
- trim(directiveValue) +
5941
- '</div>').contents();
5985
+ $template = directiveTemplateContents(directiveValue);
5942
5986
  compileNode = $template[0];
5943
5987
 
5944
5988
  if ($template.length != 1 || compileNode.nodeType !== 1) {
@@ -6009,6 +6053,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
6009
6053
 
6010
6054
  nodeLinkFn.scope = newScopeDirective && newScopeDirective.scope === true;
6011
6055
  nodeLinkFn.transclude = hasTranscludeDirective && childTranscludeFn;
6056
+ previousCompileContext.hasElementTranscludeDirective = hasElementTranscludeDirective;
6012
6057
 
6013
6058
  // might be normal or delayed nodeLinkFn depending on if templateUrl is present
6014
6059
  return nodeLinkFn;
@@ -6336,6 +6381,28 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
6336
6381
  }
6337
6382
 
6338
6383
 
6384
+ function directiveTemplateContents(template) {
6385
+ var type;
6386
+ template = trim(template);
6387
+ if ((type = TABLE_CONTENT_REGEXP.exec(template))) {
6388
+ type = type[1].toLowerCase();
6389
+ var table = jqLite('<table>' + template + '</table>'),
6390
+ tbody = table.children('tbody'),
6391
+ leaf = /(td|th)/.test(type) && table.find('tr');
6392
+ if (tbody.length && type !== 'tbody') {
6393
+ table = tbody;
6394
+ }
6395
+ if (leaf && leaf.length) {
6396
+ table = leaf;
6397
+ }
6398
+ return table.contents();
6399
+ }
6400
+ return jqLite('<div>' +
6401
+ template +
6402
+ '</div>').contents();
6403
+ }
6404
+
6405
+
6339
6406
  function compileTemplateUrl(directives, $compileNode, tAttrs,
6340
6407
  $rootElement, childTranscludeFn, preLinkFns, postLinkFns, previousCompileContext) {
6341
6408
  var linkQueue = [],
@@ -6360,7 +6427,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
6360
6427
  content = denormalizeTemplate(content);
6361
6428
 
6362
6429
  if (origAsyncDirective.replace) {
6363
- $template = jqLite('<div>' + trim(content) + '</div>').contents();
6430
+ $template = directiveTemplateContents(content);
6364
6431
  compileNode = $template[0];
6365
6432
 
6366
6433
  if ($template.length != 1 || compileNode.nodeType !== 1) {
@@ -6404,9 +6471,18 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
6404
6471
  linkNode = $compileNode[0];
6405
6472
 
6406
6473
  if (beforeTemplateLinkNode !== beforeTemplateCompileNode) {
6407
- // it was cloned therefore we have to clone as well.
6408
- linkNode = jqLiteClone(compileNode);
6474
+ var oldClasses = beforeTemplateLinkNode.className;
6475
+
6476
+ if (!(previousCompileContext.hasElementTranscludeDirective &&
6477
+ origAsyncDirective.replace)) {
6478
+ // it was cloned therefore we have to clone as well.
6479
+ linkNode = jqLiteClone(compileNode);
6480
+ }
6481
+
6409
6482
  replaceWith(linkRootElement, jqLite(beforeTemplateLinkNode), linkNode);
6483
+
6484
+ // Copy in CSS classes from original node
6485
+ safeAddClass(jqLite(linkNode), oldClasses);
6410
6486
  }
6411
6487
  if (afterTemplateNodeLinkFn.transclude) {
6412
6488
  childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude);
@@ -7063,31 +7139,14 @@ function $HttpProvider() {
7063
7139
  * XMLHttpRequest will transparently follow it, meaning that the error callback will not be
7064
7140
  * called for such responses.
7065
7141
  *
7066
- * # Calling $http from outside AngularJS
7067
- * The `$http` service will not actually send the request until the next `$digest()` is
7068
- * executed. Normally this is not an issue, since almost all the time your call to `$http` will
7069
- * be from within a `$apply()` block.
7070
- * If you are calling `$http` from outside Angular, then you should wrap it in a call to
7071
- * `$apply` to cause a $digest to occur and also to handle errors in the block correctly.
7072
- *
7073
- * ```
7074
- * $scope.$apply(function() {
7075
- * $http(...);
7076
- * });
7077
- * ```
7078
- *
7079
7142
  * # Writing Unit Tests that use $http
7080
- * When unit testing you are mostly responsible for scheduling the `$digest` cycle. If you do
7081
- * not trigger a `$digest` before calling `$httpBackend.flush()` then the request will not have
7082
- * been made and `$httpBackend.expect(...)` expectations will fail. The solution is to run the
7083
- * code that calls the `$http()` method inside a $apply block as explained in the previous
7084
- * section.
7143
+ * When unit testing (using {@link api/ngMock ngMock}), it is necessary to call
7144
+ * {@link api/ngMock.$httpBackend#methods_flush $httpBackend.flush()} to flush each pending
7145
+ * request using trained responses.
7085
7146
  *
7086
7147
  * ```
7087
7148
  * $httpBackend.expectGET(...);
7088
- * $scope.$apply(function() {
7089
- * $http.get(...);
7090
- * });
7149
+ * $http.get(...);
7091
7150
  * $httpBackend.flush();
7092
7151
  * ```
7093
7152
  *
@@ -7444,14 +7503,14 @@ function $HttpProvider() {
7444
7503
  <option>JSONP</option>
7445
7504
  </select>
7446
7505
  <input type="text" ng-model="url" size="80"/>
7447
- <button ng-click="fetch()">fetch</button><br>
7448
- <button ng-click="updateModel('GET', 'http-hello.html')">Sample GET</button>
7449
- <button
7506
+ <button id="fetchbtn" ng-click="fetch()">fetch</button><br>
7507
+ <button id="samplegetbtn" ng-click="updateModel('GET', 'http-hello.html')">Sample GET</button>
7508
+ <button id="samplejsonpbtn"
7450
7509
  ng-click="updateModel('JSONP',
7451
7510
  'http://angularjs.org/greet.php?callback=JSON_CALLBACK&name=Super%20Hero')">
7452
7511
  Sample JSONP
7453
7512
  </button>
7454
- <button
7513
+ <button id="invalidjsonpbtn"
7455
7514
  ng-click="updateModel('JSONP', 'http://angularjs.org/doesntexist&callback=JSON_CALLBACK')">
7456
7515
  Invalid JSONP
7457
7516
  </button>
@@ -7488,27 +7547,34 @@ function $HttpProvider() {
7488
7547
  <file name="http-hello.html">
7489
7548
  Hello, $http!
7490
7549
  </file>
7491
- <file name="scenario.js">
7550
+ <file name="protractorTest.js">
7551
+ var status = element(by.binding('status'));
7552
+ var data = element(by.binding('data'));
7553
+ var fetchBtn = element(by.id('fetchbtn'));
7554
+ var sampleGetBtn = element(by.id('samplegetbtn'));
7555
+ var sampleJsonpBtn = element(by.id('samplejsonpbtn'));
7556
+ var invalidJsonpBtn = element(by.id('invalidjsonpbtn'));
7557
+
7492
7558
  it('should make an xhr GET request', function() {
7493
- element(':button:contains("Sample GET")').click();
7494
- element(':button:contains("fetch")').click();
7495
- expect(binding('status')).toBe('200');
7496
- expect(binding('data')).toMatch(/Hello, \$http!/);
7559
+ sampleGetBtn.click();
7560
+ fetchBtn.click();
7561
+ expect(status.getText()).toMatch('200');
7562
+ expect(data.getText()).toMatch(/Hello, \$http!/)
7497
7563
  });
7498
7564
 
7499
7565
  it('should make a JSONP request to angularjs.org', function() {
7500
- element(':button:contains("Sample JSONP")').click();
7501
- element(':button:contains("fetch")').click();
7502
- expect(binding('status')).toBe('200');
7503
- expect(binding('data')).toMatch(/Super Hero!/);
7566
+ sampleJsonpBtn.click();
7567
+ fetchBtn.click();
7568
+ expect(status.getText()).toMatch('200');
7569
+ expect(data.getText()).toMatch(/Super Hero!/);
7504
7570
  });
7505
7571
 
7506
7572
  it('should make JSONP request to invalid URL and invoke the error handler',
7507
7573
  function() {
7508
- element(':button:contains("Invalid JSONP")').click();
7509
- element(':button:contains("fetch")').click();
7510
- expect(binding('status')).toBe('0');
7511
- expect(binding('data')).toBe('Request failed');
7574
+ invalidJsonpBtn.click();
7575
+ fetchBtn.click();
7576
+ expect(status.getText()).toMatch('0');
7577
+ expect(data.getText()).toMatch('Request failed');
7512
7578
  });
7513
7579
  </file>
7514
7580
  </example>
@@ -7890,13 +7956,18 @@ function $HttpProvider() {
7890
7956
  }
7891
7957
 
7892
7958
  function createXhr(method) {
7893
- // IE8 doesn't support PATCH method, but the ActiveX object does
7894
- /* global ActiveXObject */
7895
- return (msie <= 8 && lowercase(method) === 'patch')
7896
- ? new ActiveXObject('Microsoft.XMLHTTP')
7897
- : new window.XMLHttpRequest();
7898
- }
7959
+ //if IE and the method is not RFC2616 compliant, or if XMLHttpRequest
7960
+ //is not available, try getting an ActiveXObject. Otherwise, use XMLHttpRequest
7961
+ //if it is available
7962
+ if (msie <= 8 && (!method.match(/^(get|post|head|put|delete|options)$/i) ||
7963
+ !window.XMLHttpRequest)) {
7964
+ return new window.ActiveXObject("Microsoft.XMLHTTP");
7965
+ } else if (window.XMLHttpRequest) {
7966
+ return new window.XMLHttpRequest();
7967
+ }
7899
7968
 
7969
+ throw minErr('$httpBackend')('noxhr', "This browser does not support XMLHttpRequest.");
7970
+ }
7900
7971
 
7901
7972
  /**
7902
7973
  * @ngdoc object
@@ -7991,7 +8062,20 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
7991
8062
  }
7992
8063
 
7993
8064
  if (responseType) {
7994
- xhr.responseType = responseType;
8065
+ try {
8066
+ xhr.responseType = responseType;
8067
+ } catch (e) {
8068
+ // WebKit added support for the json responseType value on 09/03/2013
8069
+ // https://bugs.webkit.org/show_bug.cgi?id=73648. Versions of Safari prior to 7 are
8070
+ // known to throw when setting the value "json" as the response type. Other older
8071
+ // browsers implementing the responseType
8072
+ //
8073
+ // The json response type can be ignored if not supported, because JSON payloads are
8074
+ // parsed on the client-side regardless.
8075
+ if (responseType !== 'json') {
8076
+ throw e;
8077
+ }
8078
+ }
7995
8079
  }
7996
8080
 
7997
8081
  xhr.send(post || null);
@@ -8090,11 +8174,11 @@ var $interpolateMinErr = minErr('$interpolate');
8090
8174
  //demo.label//
8091
8175
  </div>
8092
8176
  </doc:source>
8093
- <doc:scenario>
8094
- it('should interpolate binding with custom symbols', function() {
8095
- expect(binding('demo.label')).toBe('This binding is brought you by // interpolation symbols.');
8096
- });
8097
- </doc:scenario>
8177
+ <doc:protractor>
8178
+ it('should interpolate binding with custom symbols', function() {
8179
+ expect(element(by.binding('demo.label')).getText()).toBe('This binding is brought you by // interpolation symbols.');
8180
+ });
8181
+ </doc:protractor>
8098
8182
  </doc:example>
8099
8183
  */
8100
8184
  function $InterpolateProvider() {
@@ -8286,7 +8370,7 @@ function $InterpolateProvider() {
8286
8370
  * @description
8287
8371
  * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
8288
8372
  *
8289
- * Use {@link ng.$interpolateProvider#endSymbol $interpolateProvider#endSymbol} to change
8373
+ * Use {@link ng.$interpolateProvider#methods_endSymbol $interpolateProvider#endSymbol} to change
8290
8374
  * the symbol.
8291
8375
  *
8292
8376
  * @returns {string} start symbol.
@@ -8322,7 +8406,7 @@ function $IntervalProvider() {
8322
8406
  * In tests you can use {@link ngMock.$interval#methods_flush `$interval.flush(millis)`} to
8323
8407
  * move forward by `millis` milliseconds and trigger any functions scheduled to run in that
8324
8408
  * time.
8325
- *
8409
+ *
8326
8410
  * <div class="alert alert-warning">
8327
8411
  * **Note**: Intervals created by this service must be explicitly destroyed when you are finished
8328
8412
  * with them. In particular they are not automatically destroyed when a controller's scope or a
@@ -8435,8 +8519,8 @@ function $IntervalProvider() {
8435
8519
  promise = deferred.promise,
8436
8520
  iteration = 0,
8437
8521
  skipApply = (isDefined(invokeApply) && !invokeApply);
8438
-
8439
- count = isDefined(count) ? count : 0,
8522
+
8523
+ count = isDefined(count) ? count : 0;
8440
8524
 
8441
8525
  promise.then(null, null, fn);
8442
8526
 
@@ -9130,7 +9214,7 @@ function $LocationProvider(){
9130
9214
  * @eventType broadcast on root scope
9131
9215
  * @description
9132
9216
  * Broadcasted before a URL will change. This change can be prevented by calling
9133
- * `preventDefault` method of the event. See {@link ng.$rootScope.Scope#$on} for more
9217
+ * `preventDefault` method of the event. See {@link ng.$rootScope.Scope#methods_$on} for more
9134
9218
  * details about event object. Upon successful change
9135
9219
  * {@link ng.$location#events_$locationChangeSuccess $locationChangeSuccess} is fired.
9136
9220
  *
@@ -9313,7 +9397,7 @@ function $LogProvider(){
9313
9397
  * @name ng.$logProvider#debugEnabled
9314
9398
  * @methodOf ng.$logProvider
9315
9399
  * @description
9316
- * @param {string=} flag enable or disable debug level messages
9400
+ * @param {boolean=} flag enable or disable debug level messages
9317
9401
  * @returns {*} current value if used as getter or itself (chaining) if used as setter
9318
9402
  */
9319
9403
  this.debugEnabled = function(flag) {
@@ -10136,7 +10220,7 @@ Parser.prototype = {
10136
10220
  var getter = getterFn(field, this.options, this.text);
10137
10221
 
10138
10222
  return extend(function(scope, locals, self) {
10139
- return getter(self || object(scope, locals), locals);
10223
+ return getter(self || object(scope, locals));
10140
10224
  }, {
10141
10225
  assign: function(scope, value, locals) {
10142
10226
  return setter(object(scope, locals), field, value, parser.text, parser.options);
@@ -10712,9 +10796,9 @@ function $ParseProvider() {
10712
10796
  * asynchronous programming what `try`, `catch` and `throw` keywords are to synchronous programming.
10713
10797
  *
10714
10798
  * <pre>
10715
- * // for the purpose of this example let's assume that variables `$q` and `scope` are
10716
- * // available in the current lexical scope (they could have been injected or passed in).
10717
- *
10799
+ * // for the purpose of this example let's assume that variables `$q`, `scope` and `okToGreet`
10800
+ * // are available in the current lexical scope (they could have been injected or passed in).
10801
+ *
10718
10802
  * function asyncGreet(name) {
10719
10803
  * var deferred = $q.defer();
10720
10804
  *
@@ -10769,7 +10853,7 @@ function $ParseProvider() {
10769
10853
  * constructed via `$q.reject`, the promise will be rejected instead.
10770
10854
  * - `reject(reason)` – rejects the derived promise with the `reason`. This is equivalent to
10771
10855
  * resolving it with a rejection constructed via `$q.reject`.
10772
- * - `notify(value)` - provides updates on the status of the promises execution. This may be called
10856
+ * - `notify(value)` - provides updates on the status of the promise's execution. This may be called
10773
10857
  * multiple times before the promise is either resolved or rejected.
10774
10858
  *
10775
10859
  * **Properties**
@@ -10919,7 +11003,7 @@ function qFactory(nextTick, exceptionHandler) {
10919
11003
 
10920
11004
 
10921
11005
  reject: function(reason) {
10922
- deferred.resolve(reject(reason));
11006
+ deferred.resolve(createInternalRejectedPromise(reason));
10923
11007
  },
10924
11008
 
10925
11009
 
@@ -11076,6 +11160,12 @@ function qFactory(nextTick, exceptionHandler) {
11076
11160
  * @returns {Promise} Returns a promise that was already resolved as rejected with the `reason`.
11077
11161
  */
11078
11162
  var reject = function(reason) {
11163
+ var result = defer();
11164
+ result.reject(reason);
11165
+ return result.promise;
11166
+ };
11167
+
11168
+ var createInternalRejectedPromise = function(reason) {
11079
11169
  return {
11080
11170
  then: function(callback, errback) {
11081
11171
  var result = defer();
@@ -12136,7 +12226,7 @@ function $RootScopeProvider(){
12136
12226
  * onto the {@link ng.$exceptionHandler $exceptionHandler} service.
12137
12227
  *
12138
12228
  * @param {string} name Event name to emit.
12139
- * @param {...*} args Optional set of arguments which will be passed onto the event listeners.
12229
+ * @param {...*} args Optional one or more arguments which will be passed onto the event listeners.
12140
12230
  * @return {Object} Event object (see {@link ng.$rootScope.Scope#methods_$on}).
12141
12231
  */
12142
12232
  $emit: function(name, args) {
@@ -12204,7 +12294,7 @@ function $RootScopeProvider(){
12204
12294
  * onto the {@link ng.$exceptionHandler $exceptionHandler} service.
12205
12295
  *
12206
12296
  * @param {string} name Event name to broadcast.
12207
- * @param {...*} args Optional set of arguments which will be passed onto the event listeners.
12297
+ * @param {...*} args Optional one or more arguments which will be passed onto the event listeners.
12208
12298
  * @return {Object} Event object, see {@link ng.$rootScope.Scope#methods_$on}
12209
12299
  */
12210
12300
  $broadcast: function(name, args) {
@@ -12647,7 +12737,7 @@ function $SceDelegateProvider() {
12647
12737
  *
12648
12738
  * @description
12649
12739
  * Returns an object that is trusted by angular for use in specified strict
12650
- * contextual escaping contexts (such as ng-html-bind-unsafe, ng-include, any src
12740
+ * contextual escaping contexts (such as ng-bind-html, ng-include, any src
12651
12741
  * attribute interpolation, any dom event binding attribute interpolation
12652
12742
  * such as for onclick, etc.) that uses the provided value.
12653
12743
  * See {@link ng.$sce $sce} for enabling strict contextual escaping.
@@ -12874,8 +12964,8 @@ function $SceDelegateProvider() {
12874
12964
  * It's important to remember that SCE only applies to interpolation expressions.
12875
12965
  *
12876
12966
  * If your expressions are constant literals, they're automatically trusted and you don't need to
12877
- * call `$sce.trustAs` on them. (e.g.
12878
- * `<div ng-html-bind-unsafe="'<b>implicitly trusted</b>'"></div>`) just works.
12967
+ * call `$sce.trustAs` on them (remember to include the `ngSanitize` module) (e.g.
12968
+ * `<div ng-bind-html="'<b>implicitly trusted</b>'"></div>`) just works.
12879
12969
  *
12880
12970
  * Additionally, `a[href]` and `img[src]` automatically sanitize their URLs and do not pass them
12881
12971
  * through {@link ng.$sce#methods_getTrusted $sce.getTrusted}. SCE doesn't play a role here.
@@ -12935,7 +13025,7 @@ function $SceDelegateProvider() {
12935
13025
  * matched against the **entire** *normalized / absolute URL* of the resource being tested
12936
13026
  * (even when the RegExp did not have the `^` and `$` codes.) In addition, any flags
12937
13027
  * present on the RegExp (such as multiline, global, ignoreCase) are ignored.
12938
- * - If you are generating your Javascript from some other templating engine (not
13028
+ * - If you are generating your JavaScript from some other templating engine (not
12939
13029
  * recommended, e.g. in issue [#4006](https://github.com/angular/angular.js/issues/4006)),
12940
13030
  * remember to escape your regular expression (and be aware that you might need more than
12941
13031
  * one level of escaping depending on your templating engine and the way you interpolated
@@ -12952,7 +13042,7 @@ function $SceDelegateProvider() {
12952
13042
  * ## Show me an example using SCE.
12953
13043
  *
12954
13044
  * @example
12955
- <example module="mySceApp">
13045
+ <example module="mySceApp" deps="angular-sanitize.js">
12956
13046
  <file name="index.html">
12957
13047
  <div ng-controller="myAppController as myCtrl">
12958
13048
  <i ng-bind-html="myCtrl.explicitlyTrustedHtml" id="explicitlyTrustedHtml"></i><br><br>
@@ -12996,13 +13086,15 @@ function $SceDelegateProvider() {
12996
13086
  ]
12997
13087
  </file>
12998
13088
 
12999
- <file name="scenario.js">
13089
+ <file name="protractorTest.js">
13000
13090
  describe('SCE doc demo', function() {
13001
13091
  it('should sanitize untrusted values', function() {
13002
- expect(element('.htmlComment').html()).toBe('<span>Is <i>anyone</i> reading this?</span>');
13092
+ expect(element(by.css('.htmlComment')).getInnerHtml())
13093
+ .toBe('<span>Is <i>anyone</i> reading this?</span>');
13003
13094
  });
13095
+
13004
13096
  it('should NOT sanitize explicitly trusted values', function() {
13005
- expect(element('#explicitlyTrustedHtml').html()).toBe(
13097
+ expect(element(by.id('explicitlyTrustedHtml')).getInnerHtml()).toBe(
13006
13098
  '<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
13007
13099
  'sanitization.&quot;">Hover over this text.</span>');
13008
13100
  });
@@ -13177,8 +13269,8 @@ function $SceProvider() {
13177
13269
  *
13178
13270
  * @description
13179
13271
  * Delegates to {@link ng.$sceDelegate#methods_trustAs `$sceDelegate.trustAs`}. As such,
13180
- * returns an objectthat is trusted by angular for use in specified strict contextual
13181
- * escaping contexts (such as ng-html-bind-unsafe, ng-include, any src attribute
13272
+ * returns an object that is trusted by angular for use in specified strict contextual
13273
+ * escaping contexts (such as ng-bind-html, ng-include, any src attribute
13182
13274
  * interpolation, any dom event binding attribute interpolation such as for onclick, etc.)
13183
13275
  * that uses the provided value. See * {@link ng.$sce $sce} for enabling strict contextual
13184
13276
  * escaping.
@@ -13761,13 +13853,13 @@ function urlIsSameOrigin(requestUrl) {
13761
13853
  <button ng-click="doGreeting(greeting)">ALERT</button>
13762
13854
  </div>
13763
13855
  </doc:source>
13764
- <doc:scenario>
13856
+ <doc:protractor>
13765
13857
  it('should display the greeting in the input box', function() {
13766
- input('greeting').enter('Hello, E2E Tests');
13858
+ element(by.model('greeting')).sendKeys('Hello, E2E Tests');
13767
13859
  // If we click the button it will block the test runner
13768
13860
  // element(':button').click();
13769
13861
  });
13770
- </doc:scenario>
13862
+ </doc:protractor>
13771
13863
  </doc:example>
13772
13864
  */
13773
13865
  function $WindowProvider(){
@@ -13976,35 +14068,47 @@ function $FilterProvider($provide) {
13976
14068
  Equality <input type="checkbox" ng-model="strict"><br>
13977
14069
  <table id="searchObjResults">
13978
14070
  <tr><th>Name</th><th>Phone</th></tr>
13979
- <tr ng-repeat="friend in friends | filter:search:strict">
13980
- <td>{{friend.name}}</td>
13981
- <td>{{friend.phone}}</td>
14071
+ <tr ng-repeat="friendObj in friends | filter:search:strict">
14072
+ <td>{{friendObj.name}}</td>
14073
+ <td>{{friendObj.phone}}</td>
13982
14074
  </tr>
13983
14075
  </table>
13984
14076
  </doc:source>
13985
- <doc:scenario>
13986
- it('should search across all fields when filtering with a string', function() {
13987
- input('searchText').enter('m');
13988
- expect(repeater('#searchTextResults tr', 'friend in friends').column('friend.name')).
13989
- toEqual(['Mary', 'Mike', 'Adam']);
14077
+ <doc:protractor>
14078
+ var expectFriendNames = function(expectedNames, key) {
14079
+ element.all(by.repeater(key + ' in friends').column(key + '.name')).then(function(arr) {
14080
+ arr.forEach(function(wd, i) {
14081
+ expect(wd.getText()).toMatch(expectedNames[i]);
14082
+ });
14083
+ });
14084
+ };
13990
14085
 
13991
- input('searchText').enter('76');
13992
- expect(repeater('#searchTextResults tr', 'friend in friends').column('friend.name')).
13993
- toEqual(['John', 'Julie']);
14086
+ it('should search across all fields when filtering with a string', function() {
14087
+ var searchText = element(by.model('searchText'));
14088
+ searchText.clear();
14089
+ searchText.sendKeys('m');
14090
+ expectFriendNames(['Mary', 'Mike', 'Adam'], 'friend');
14091
+
14092
+ searchText.clear();
14093
+ searchText.sendKeys('76');
14094
+ expectFriendNames(['John', 'Julie'], 'friend');
13994
14095
  });
13995
14096
 
13996
14097
  it('should search in specific fields when filtering with a predicate object', function() {
13997
- input('search.$').enter('i');
13998
- expect(repeater('#searchObjResults tr', 'friend in friends').column('friend.name')).
13999
- toEqual(['Mary', 'Mike', 'Julie', 'Juliette']);
14098
+ var searchAny = element(by.model('search.$'));
14099
+ searchAny.clear();
14100
+ searchAny.sendKeys('i');
14101
+ expectFriendNames(['Mary', 'Mike', 'Julie', 'Juliette'], 'friendObj');
14000
14102
  });
14001
14103
  it('should use a equal comparison when comparator is true', function() {
14002
- input('search.name').enter('Julie');
14003
- input('strict').check();
14004
- expect(repeater('#searchObjResults tr', 'friend in friends').column('friend.name')).
14005
- toEqual(['Julie']);
14104
+ var searchName = element(by.model('search.name'));
14105
+ var strict = element(by.model('strict'));
14106
+ searchName.clear();
14107
+ searchName.sendKeys('Julie');
14108
+ strict.click();
14109
+ expectFriendNames(['Julie'], 'friendObj');
14006
14110
  });
14007
- </doc:scenario>
14111
+ </doc:protractor>
14008
14112
  </doc:example>
14009
14113
  */
14010
14114
  function filterFilter() {
@@ -14030,6 +14134,15 @@ function filterFilter() {
14030
14134
  };
14031
14135
  } else {
14032
14136
  comparator = function(obj, text) {
14137
+ if (obj && text && typeof obj === 'object' && typeof text === 'object') {
14138
+ for (var objKey in obj) {
14139
+ if (objKey.charAt(0) !== '$' && hasOwnProperty.call(obj, objKey) &&
14140
+ comparator(obj[objKey], text[objKey])) {
14141
+ return true;
14142
+ }
14143
+ }
14144
+ return false;
14145
+ }
14033
14146
  text = (''+text).toLowerCase();
14034
14147
  return (''+obj).toLowerCase().indexOf(text) > -1;
14035
14148
  };
@@ -14082,7 +14195,7 @@ function filterFilter() {
14082
14195
  (function(path) {
14083
14196
  if (typeof expression[path] == 'undefined') return;
14084
14197
  predicates.push(function(value) {
14085
- return search(path == '$' ? value : getter(value, path), expression[path]);
14198
+ return search(path == '$' ? value : (value && value[path]), expression[path]);
14086
14199
  });
14087
14200
  })(key);
14088
14201
  }
@@ -14128,21 +14241,27 @@ function filterFilter() {
14128
14241
  </script>
14129
14242
  <div ng-controller="Ctrl">
14130
14243
  <input type="number" ng-model="amount"> <br>
14131
- default currency symbol ($): {{amount | currency}}<br>
14132
- custom currency identifier (USD$): {{amount | currency:"USD$"}}
14244
+ default currency symbol ($): <span id="currency-default">{{amount | currency}}</span><br>
14245
+ custom currency identifier (USD$): <span>{{amount | currency:"USD$"}}</span>
14133
14246
  </div>
14134
14247
  </doc:source>
14135
- <doc:scenario>
14248
+ <doc:protractor>
14136
14249
  it('should init with 1234.56', function() {
14137
- expect(binding('amount | currency')).toBe('$1,234.56');
14138
- expect(binding('amount | currency:"USD$"')).toBe('USD$1,234.56');
14250
+ expect(element(by.id('currency-default')).getText()).toBe('$1,234.56');
14251
+ expect(element(by.binding('amount | currency:"USD$"')).getText()).toBe('USD$1,234.56');
14139
14252
  });
14140
14253
  it('should update', function() {
14141
- input('amount').enter('-1234');
14142
- expect(binding('amount | currency')).toBe('($1,234.00)');
14143
- expect(binding('amount | currency:"USD$"')).toBe('(USD$1,234.00)');
14254
+ if (browser.params.browser == 'safari') {
14255
+ // Safari does not understand the minus key. See
14256
+ // https://github.com/angular/protractor/issues/481
14257
+ return;
14258
+ }
14259
+ element(by.model('amount')).clear();
14260
+ element(by.model('amount')).sendKeys('-1234');
14261
+ expect(element(by.id('currency-default')).getText()).toBe('($1,234.00)');
14262
+ expect(element(by.binding('amount | currency:"USD$"')).getText()).toBe('(USD$1,234.00)');
14144
14263
  });
14145
- </doc:scenario>
14264
+ </doc:protractor>
14146
14265
  </doc:example>
14147
14266
  */
14148
14267
  currencyFilter.$inject = ['$locale'];
@@ -14181,25 +14300,26 @@ function currencyFilter($locale) {
14181
14300
  </script>
14182
14301
  <div ng-controller="Ctrl">
14183
14302
  Enter number: <input ng-model='val'><br>
14184
- Default formatting: {{val | number}}<br>
14185
- No fractions: {{val | number:0}}<br>
14186
- Negative number: {{-val | number:4}}
14303
+ Default formatting: <span id='number-default'>{{val | number}}</span><br>
14304
+ No fractions: <span>{{val | number:0}}</span><br>
14305
+ Negative number: <span>{{-val | number:4}}</span>
14187
14306
  </div>
14188
14307
  </doc:source>
14189
- <doc:scenario>
14308
+ <doc:protractor>
14190
14309
  it('should format numbers', function() {
14191
- expect(binding('val | number')).toBe('1,234.568');
14192
- expect(binding('val | number:0')).toBe('1,235');
14193
- expect(binding('-val | number:4')).toBe('-1,234.5679');
14310
+ expect(element(by.id('number-default')).getText()).toBe('1,234.568');
14311
+ expect(element(by.binding('val | number:0')).getText()).toBe('1,235');
14312
+ expect(element(by.binding('-val | number:4')).getText()).toBe('-1,234.5679');
14194
14313
  });
14195
14314
 
14196
14315
  it('should update', function() {
14197
- input('val').enter('3374.333');
14198
- expect(binding('val | number')).toBe('3,374.333');
14199
- expect(binding('val | number:0')).toBe('3,374');
14200
- expect(binding('-val | number:4')).toBe('-3,374.3330');
14201
- });
14202
- </doc:scenario>
14316
+ element(by.model('val')).clear();
14317
+ element(by.model('val')).sendKeys('3374.333');
14318
+ expect(element(by.id('number-default')).getText()).toBe('3,374.333');
14319
+ expect(element(by.binding('val | number:0')).getText()).toBe('3,374');
14320
+ expect(element(by.binding('-val | number:4')).getText()).toBe('-3,374.3330');
14321
+ });
14322
+ </doc:protractor>
14203
14323
  </doc:example>
14204
14324
  */
14205
14325
 
@@ -14429,22 +14549,22 @@ var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+
14429
14549
  <doc:example>
14430
14550
  <doc:source>
14431
14551
  <span ng-non-bindable>{{1288323623006 | date:'medium'}}</span>:
14432
- {{1288323623006 | date:'medium'}}<br>
14552
+ <span>{{1288323623006 | date:'medium'}}</span><br>
14433
14553
  <span ng-non-bindable>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span>:
14434
- {{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}<br>
14554
+ <span>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span><br>
14435
14555
  <span ng-non-bindable>{{1288323623006 | date:'MM/dd/yyyy @ h:mma'}}</span>:
14436
- {{'1288323623006' | date:'MM/dd/yyyy @ h:mma'}}<br>
14556
+ <span>{{'1288323623006' | date:'MM/dd/yyyy @ h:mma'}}</span><br>
14437
14557
  </doc:source>
14438
- <doc:scenario>
14558
+ <doc:protractor>
14439
14559
  it('should format date', function() {
14440
- expect(binding("1288323623006 | date:'medium'")).
14560
+ expect(element(by.binding("1288323623006 | date:'medium'")).getText()).
14441
14561
  toMatch(/Oct 2\d, 2010 \d{1,2}:\d{2}:\d{2} (AM|PM)/);
14442
- expect(binding("1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'")).
14562
+ expect(element(by.binding("1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'")).getText()).
14443
14563
  toMatch(/2010\-10\-2\d \d{2}:\d{2}:\d{2} (\-|\+)?\d{4}/);
14444
- expect(binding("'1288323623006' | date:'MM/dd/yyyy @ h:mma'")).
14564
+ expect(element(by.binding("'1288323623006' | date:'MM/dd/yyyy @ h:mma'")).getText()).
14445
14565
  toMatch(/10\/2\d\/2010 @ \d{1,2}:\d{2}(AM|PM)/);
14446
14566
  });
14447
- </doc:scenario>
14567
+ </doc:protractor>
14448
14568
  </doc:example>
14449
14569
  */
14450
14570
  dateFilter.$inject = ['$locale'];
@@ -14543,11 +14663,11 @@ function dateFilter($locale) {
14543
14663
  <doc:source>
14544
14664
  <pre>{{ {'name':'value'} | json }}</pre>
14545
14665
  </doc:source>
14546
- <doc:scenario>
14666
+ <doc:protractor>
14547
14667
  it('should jsonify filtered objects', function() {
14548
- expect(binding("{'name':'value'}")).toMatch(/\{\n "name": ?"value"\n}/);
14668
+ expect(element(by.binding("{'name':'value'}")).getText()).toMatch(/\{\n "name": ?"value"\n}/);
14549
14669
  });
14550
- </doc:scenario>
14670
+ </doc:protractor>
14551
14671
  </doc:example>
14552
14672
  *
14553
14673
  */
@@ -14615,28 +14735,37 @@ var uppercaseFilter = valueFn(uppercase);
14615
14735
  <p>Output letters: {{ letters | limitTo:letterLimit }}</p>
14616
14736
  </div>
14617
14737
  </doc:source>
14618
- <doc:scenario>
14738
+ <doc:protractor>
14739
+ var numLimitInput = element(by.model('numLimit'));
14740
+ var letterLimitInput = element(by.model('letterLimit'));
14741
+ var limitedNumbers = element(by.binding('numbers | limitTo:numLimit'));
14742
+ var limitedLetters = element(by.binding('letters | limitTo:letterLimit'));
14743
+
14619
14744
  it('should limit the number array to first three items', function() {
14620
- expect(element('.doc-example-live input[ng-model=numLimit]').val()).toBe('3');
14621
- expect(element('.doc-example-live input[ng-model=letterLimit]').val()).toBe('3');
14622
- expect(binding('numbers | limitTo:numLimit')).toEqual('[1,2,3]');
14623
- expect(binding('letters | limitTo:letterLimit')).toEqual('abc');
14745
+ expect(numLimitInput.getAttribute('value')).toBe('3');
14746
+ expect(letterLimitInput.getAttribute('value')).toBe('3');
14747
+ expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3]');
14748
+ expect(limitedLetters.getText()).toEqual('Output letters: abc');
14624
14749
  });
14625
14750
 
14626
14751
  it('should update the output when -3 is entered', function() {
14627
- input('numLimit').enter(-3);
14628
- input('letterLimit').enter(-3);
14629
- expect(binding('numbers | limitTo:numLimit')).toEqual('[7,8,9]');
14630
- expect(binding('letters | limitTo:letterLimit')).toEqual('ghi');
14752
+ numLimitInput.clear();
14753
+ numLimitInput.sendKeys('-3');
14754
+ letterLimitInput.clear();
14755
+ letterLimitInput.sendKeys('-3');
14756
+ expect(limitedNumbers.getText()).toEqual('Output numbers: [7,8,9]');
14757
+ expect(limitedLetters.getText()).toEqual('Output letters: ghi');
14631
14758
  });
14632
14759
 
14633
14760
  it('should not exceed the maximum size of input array', function() {
14634
- input('numLimit').enter(100);
14635
- input('letterLimit').enter(100);
14636
- expect(binding('numbers | limitTo:numLimit')).toEqual('[1,2,3,4,5,6,7,8,9]');
14637
- expect(binding('letters | limitTo:letterLimit')).toEqual('abcdefghi');
14761
+ numLimitInput.clear();
14762
+ numLimitInput.sendKeys('100');
14763
+ letterLimitInput.clear();
14764
+ letterLimitInput.sendKeys('100');
14765
+ expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3,4,5,6,7,8,9]');
14766
+ expect(limitedLetters.getText()).toEqual('Output letters: abcdefghi');
14638
14767
  });
14639
- </doc:scenario>
14768
+ </doc:protractor>
14640
14769
  </doc:example>
14641
14770
  */
14642
14771
  function limitToFilter(){
@@ -14737,29 +14866,6 @@ function limitToFilter(){
14737
14866
  </table>
14738
14867
  </div>
14739
14868
  </doc:source>
14740
- <doc:scenario>
14741
- it('should be reverse ordered by aged', function() {
14742
- expect(binding('predicate')).toBe('-age');
14743
- expect(repeater('table.friend', 'friend in friends').column('friend.age')).
14744
- toEqual(['35', '29', '21', '19', '10']);
14745
- expect(repeater('table.friend', 'friend in friends').column('friend.name')).
14746
- toEqual(['Adam', 'Julie', 'Mike', 'Mary', 'John']);
14747
- });
14748
-
14749
- it('should reorder the table when user selects different predicate', function() {
14750
- element('.doc-example-live a:contains("Name")').click();
14751
- expect(repeater('table.friend', 'friend in friends').column('friend.name')).
14752
- toEqual(['Adam', 'John', 'Julie', 'Mary', 'Mike']);
14753
- expect(repeater('table.friend', 'friend in friends').column('friend.age')).
14754
- toEqual(['35', '10', '29', '19', '21']);
14755
-
14756
- element('.doc-example-live a:contains("Phone")').click();
14757
- expect(repeater('table.friend', 'friend in friends').column('friend.phone')).
14758
- toEqual(['555-9876', '555-8765', '555-5678', '555-4321', '555-1212']);
14759
- expect(repeater('table.friend', 'friend in friends').column('friend.name')).
14760
- toEqual(['Mary', 'Julie', 'Adam', 'Mike', 'John']);
14761
- });
14762
- </doc:scenario>
14763
14869
  </doc:example>
14764
14870
  */
14765
14871
  orderByFilter.$inject = ['$parse'];
@@ -14856,11 +14962,14 @@ var htmlAnchorDirective = valueFn({
14856
14962
  element.append(document.createComment('IE fix'));
14857
14963
  }
14858
14964
 
14859
- if (!attr.href && !attr.name) {
14965
+ if (!attr.href && !attr.xlinkHref && !attr.name) {
14860
14966
  return function(scope, element) {
14967
+ // SVGAElement does not use the href attribute, but rather the 'xlinkHref' attribute.
14968
+ var href = toString.call(element.prop('href')) === '[object SVGAnimatedString]' ?
14969
+ 'xlink:href' : 'href';
14861
14970
  element.on('click', function(event){
14862
14971
  // if we have no href url, then don't navigate anywhere.
14863
- if (!element.attr('href')) {
14972
+ if (!element.attr(href)) {
14864
14973
  event.preventDefault();
14865
14974
  }
14866
14975
  });
@@ -14910,46 +15019,55 @@ var htmlAnchorDirective = valueFn({
14910
15019
  <a id="link-5" name="xxx" ng-click="value = 5">anchor</a> (no link)<br />
14911
15020
  <a id="link-6" ng-href="{{value}}">link</a> (link, change location)
14912
15021
  </doc:source>
14913
- <doc:scenario>
15022
+ <doc:protractor>
14914
15023
  it('should execute ng-click but not reload when href without value', function() {
14915
- element('#link-1').click();
14916
- expect(input('value').val()).toEqual('1');
14917
- expect(element('#link-1').attr('href')).toBe("");
15024
+ element(by.id('link-1')).click();
15025
+ expect(element(by.model('value')).getAttribute('value')).toEqual('1');
15026
+ expect(element(by.id('link-1')).getAttribute('href')).toBe('');
14918
15027
  });
14919
15028
 
14920
15029
  it('should execute ng-click but not reload when href empty string', function() {
14921
- element('#link-2').click();
14922
- expect(input('value').val()).toEqual('2');
14923
- expect(element('#link-2').attr('href')).toBe("");
15030
+ element(by.id('link-2')).click();
15031
+ expect(element(by.model('value')).getAttribute('value')).toEqual('2');
15032
+ expect(element(by.id('link-2')).getAttribute('href')).toBe('');
14924
15033
  });
14925
15034
 
14926
15035
  it('should execute ng-click and change url when ng-href specified', function() {
14927
- expect(element('#link-3').attr('href')).toBe("/123");
15036
+ expect(element(by.id('link-3')).getAttribute('href')).toMatch(/\/123$/);
15037
+
15038
+ element(by.id('link-3')).click();
14928
15039
 
14929
- element('#link-3').click();
14930
- expect(browser().window().path()).toEqual('/123');
15040
+ // At this point, we navigate away from an Angular page, so we need
15041
+ // to use browser.driver to get the base webdriver.
15042
+
15043
+ browser.wait(function() {
15044
+ return browser.driver.getCurrentUrl().then(function(url) {
15045
+ return url.match(/\/123$/);
15046
+ });
15047
+ }, 1000, 'page should navigate to /123');
14931
15048
  });
14932
15049
 
14933
15050
  it('should execute ng-click but not reload when href empty string and name specified', function() {
14934
- element('#link-4').click();
14935
- expect(input('value').val()).toEqual('4');
14936
- expect(element('#link-4').attr('href')).toBe('');
15051
+ element(by.id('link-4')).click();
15052
+ expect(element(by.model('value')).getAttribute('value')).toEqual('4');
15053
+ expect(element(by.id('link-4')).getAttribute('href')).toBe('');
14937
15054
  });
14938
15055
 
14939
15056
  it('should execute ng-click but not reload when no href but name specified', function() {
14940
- element('#link-5').click();
14941
- expect(input('value').val()).toEqual('5');
14942
- expect(element('#link-5').attr('href')).toBe(undefined);
15057
+ element(by.id('link-5')).click();
15058
+ expect(element(by.model('value')).getAttribute('value')).toEqual('5');
15059
+ expect(element(by.id('link-5')).getAttribute('href')).toBe(null);
14943
15060
  });
14944
15061
 
14945
15062
  it('should only change url when only ng-href', function() {
14946
- input('value').enter('6');
14947
- expect(element('#link-6').attr('href')).toBe('6');
15063
+ element(by.model('value')).clear();
15064
+ element(by.model('value')).sendKeys('6');
15065
+ expect(element(by.id('link-6')).getAttribute('href')).toMatch(/\/6$/);
14948
15066
 
14949
- element('#link-6').click();
14950
- expect(browser().location().url()).toEqual('/6');
15067
+ element(by.id('link-6')).click();
15068
+ expect(browser.getCurrentUrl()).toMatch(/\/6$/);
14951
15069
  });
14952
- </doc:scenario>
15070
+ </doc:protractor>
14953
15071
  </doc:example>
14954
15072
  */
14955
15073
 
@@ -15034,13 +15152,13 @@ var htmlAnchorDirective = valueFn({
15034
15152
  Click me to toggle: <input type="checkbox" ng-model="checked"><br/>
15035
15153
  <button ng-model="button" ng-disabled="checked">Button</button>
15036
15154
  </doc:source>
15037
- <doc:scenario>
15155
+ <doc:protractor>
15038
15156
  it('should toggle button', function() {
15039
- expect(element('.doc-example-live :button').prop('disabled')).toBeFalsy();
15040
- input('checked').check();
15041
- expect(element('.doc-example-live :button').prop('disabled')).toBeTruthy();
15157
+ expect(element(by.css('.doc-example-live button')).getAttribute('disabled')).toBeFalsy();
15158
+ element(by.model('checked')).click();
15159
+ expect(element(by.css('.doc-example-live button')).getAttribute('disabled')).toBeTruthy();
15042
15160
  });
15043
- </doc:scenario>
15161
+ </doc:protractor>
15044
15162
  </doc:example>
15045
15163
  *
15046
15164
  * @element INPUT
@@ -15069,13 +15187,13 @@ var htmlAnchorDirective = valueFn({
15069
15187
  Check me to check both: <input type="checkbox" ng-model="master"><br/>
15070
15188
  <input id="checkSlave" type="checkbox" ng-checked="master">
15071
15189
  </doc:source>
15072
- <doc:scenario>
15190
+ <doc:protractor>
15073
15191
  it('should check both checkBoxes', function() {
15074
- expect(element('.doc-example-live #checkSlave').prop('checked')).toBeFalsy();
15075
- input('master').check();
15076
- expect(element('.doc-example-live #checkSlave').prop('checked')).toBeTruthy();
15192
+ expect(element(by.id('checkSlave')).getAttribute('checked')).toBeFalsy();
15193
+ element(by.model('master')).click();
15194
+ expect(element(by.id('checkSlave')).getAttribute('checked')).toBeTruthy();
15077
15195
  });
15078
- </doc:scenario>
15196
+ </doc:protractor>
15079
15197
  </doc:example>
15080
15198
  *
15081
15199
  * @element INPUT
@@ -15104,13 +15222,13 @@ var htmlAnchorDirective = valueFn({
15104
15222
  Check me to make text readonly: <input type="checkbox" ng-model="checked"><br/>
15105
15223
  <input type="text" ng-readonly="checked" value="I'm Angular"/>
15106
15224
  </doc:source>
15107
- <doc:scenario>
15225
+ <doc:protractor>
15108
15226
  it('should toggle readonly attr', function() {
15109
- expect(element('.doc-example-live :text').prop('readonly')).toBeFalsy();
15110
- input('checked').check();
15111
- expect(element('.doc-example-live :text').prop('readonly')).toBeTruthy();
15227
+ expect(element(by.css('.doc-example-live [type="text"]')).getAttribute('readonly')).toBeFalsy();
15228
+ element(by.model('checked')).click();
15229
+ expect(element(by.css('.doc-example-live [type="text"]')).getAttribute('readonly')).toBeTruthy();
15112
15230
  });
15113
- </doc:scenario>
15231
+ </doc:protractor>
15114
15232
  </doc:example>
15115
15233
  *
15116
15234
  * @element INPUT
@@ -15143,13 +15261,13 @@ var htmlAnchorDirective = valueFn({
15143
15261
  <option id="greet" ng-selected="selected">Greetings!</option>
15144
15262
  </select>
15145
15263
  </doc:source>
15146
- <doc:scenario>
15264
+ <doc:protractor>
15147
15265
  it('should select Greetings!', function() {
15148
- expect(element('.doc-example-live #greet').prop('selected')).toBeFalsy();
15149
- input('selected').check();
15150
- expect(element('.doc-example-live #greet').prop('selected')).toBeTruthy();
15266
+ expect(element(by.id('greet')).getAttribute('selected')).toBeFalsy();
15267
+ element(by.model('selected')).click();
15268
+ expect(element(by.id('greet')).getAttribute('selected')).toBeTruthy();
15151
15269
  });
15152
- </doc:scenario>
15270
+ </doc:protractor>
15153
15271
  </doc:example>
15154
15272
  *
15155
15273
  * @element OPTION
@@ -15179,13 +15297,13 @@ var htmlAnchorDirective = valueFn({
15179
15297
  <summary>Show/Hide me</summary>
15180
15298
  </details>
15181
15299
  </doc:source>
15182
- <doc:scenario>
15300
+ <doc:protractor>
15183
15301
  it('should toggle open', function() {
15184
- expect(element('#details').prop('open')).toBeFalsy();
15185
- input('open').check();
15186
- expect(element('#details').prop('open')).toBeTruthy();
15302
+ expect(element(by.id('details')).getAttribute('open')).toBeFalsy();
15303
+ element(by.model('open')).click();
15304
+ expect(element(by.id('details')).getAttribute('open')).toBeTruthy();
15187
15305
  });
15188
- </doc:scenario>
15306
+ </doc:protractor>
15189
15307
  </doc:example>
15190
15308
  *
15191
15309
  * @element DETAILS
@@ -15544,18 +15662,27 @@ function FormController(element, attrs) {
15544
15662
  <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br>
15545
15663
  </form>
15546
15664
  </doc:source>
15547
- <doc:scenario>
15665
+ <doc:protractor>
15548
15666
  it('should initialize to model', function() {
15549
- expect(binding('userType')).toEqual('guest');
15550
- expect(binding('myForm.input.$valid')).toEqual('true');
15667
+ var userType = element(by.binding('userType'));
15668
+ var valid = element(by.binding('myForm.input.$valid'));
15669
+
15670
+ expect(userType.getText()).toContain('guest');
15671
+ expect(valid.getText()).toContain('true');
15551
15672
  });
15552
15673
 
15553
15674
  it('should be invalid if empty', function() {
15554
- input('userType').enter('');
15555
- expect(binding('userType')).toEqual('');
15556
- expect(binding('myForm.input.$valid')).toEqual('false');
15675
+ var userType = element(by.binding('userType'));
15676
+ var valid = element(by.binding('myForm.input.$valid'));
15677
+ var userInput = element(by.model('userType'));
15678
+
15679
+ userInput.clear();
15680
+ userInput.sendKeys('');
15681
+
15682
+ expect(userType.getText()).toEqual('userType =');
15683
+ expect(valid.getText()).toContain('false');
15557
15684
  });
15558
- </doc:scenario>
15685
+ </doc:protractor>
15559
15686
  </doc:example>
15560
15687
  */
15561
15688
  var formDirectiveFactory = function(isNgForm) {
@@ -15627,7 +15754,7 @@ var ngFormDirective = formDirectiveFactory(true);
15627
15754
  */
15628
15755
 
15629
15756
  var URL_REGEXP = /^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/;
15630
- var EMAIL_REGEXP = /^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}$/;
15757
+ var EMAIL_REGEXP = /^[a-z0-9!#$%&'*+/=?^_`{|}~.-]+@[a-z0-9-]+(\.[a-z0-9-]+)*$/i;
15631
15758
  var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))\s*$/;
15632
15759
 
15633
15760
  var inputType = {
@@ -15680,29 +15807,31 @@ var inputType = {
15680
15807
  <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
15681
15808
  </form>
15682
15809
  </doc:source>
15683
- <doc:scenario>
15810
+ <doc:protractor>
15811
+ var text = element(by.binding('text'));
15812
+ var valid = element(by.binding('myForm.input.$valid'));
15813
+ var input = element(by.model('text'));
15814
+
15684
15815
  it('should initialize to model', function() {
15685
- expect(binding('text')).toEqual('guest');
15686
- expect(binding('myForm.input.$valid')).toEqual('true');
15816
+ expect(text.getText()).toContain('guest');
15817
+ expect(valid.getText()).toContain('true');
15687
15818
  });
15688
15819
 
15689
15820
  it('should be invalid if empty', function() {
15690
- input('text').enter('');
15691
- expect(binding('text')).toEqual('');
15692
- expect(binding('myForm.input.$valid')).toEqual('false');
15821
+ input.clear();
15822
+ input.sendKeys('');
15823
+
15824
+ expect(text.getText()).toEqual('text =');
15825
+ expect(valid.getText()).toContain('false');
15693
15826
  });
15694
15827
 
15695
15828
  it('should be invalid if multi word', function() {
15696
- input('text').enter('hello world');
15697
- expect(binding('myForm.input.$valid')).toEqual('false');
15698
- });
15829
+ input.clear();
15830
+ input.sendKeys('hello world');
15699
15831
 
15700
- it('should not be trimmed', function() {
15701
- input('text').enter('untrimmed ');
15702
- expect(binding('text')).toEqual('untrimmed ');
15703
- expect(binding('myForm.input.$valid')).toEqual('true');
15832
+ expect(valid.getText()).toContain('false');
15704
15833
  });
15705
- </doc:scenario>
15834
+ </doc:protractor>
15706
15835
  </doc:example>
15707
15836
  */
15708
15837
  'text': textInputType,
@@ -15756,24 +15885,30 @@ var inputType = {
15756
15885
  <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
15757
15886
  </form>
15758
15887
  </doc:source>
15759
- <doc:scenario>
15888
+ <doc:protractor>
15889
+ var value = element(by.binding('value'));
15890
+ var valid = element(by.binding('myForm.input.$valid'));
15891
+ var input = element(by.model('value'));
15892
+
15760
15893
  it('should initialize to model', function() {
15761
- expect(binding('value')).toEqual('12');
15762
- expect(binding('myForm.input.$valid')).toEqual('true');
15894
+ expect(value.getText()).toContain('12');
15895
+ expect(valid.getText()).toContain('true');
15763
15896
  });
15764
15897
 
15765
15898
  it('should be invalid if empty', function() {
15766
- input('value').enter('');
15767
- expect(binding('value')).toEqual('');
15768
- expect(binding('myForm.input.$valid')).toEqual('false');
15899
+ input.clear();
15900
+ input.sendKeys('');
15901
+ expect(value.getText()).toEqual('value =');
15902
+ expect(valid.getText()).toContain('false');
15769
15903
  });
15770
15904
 
15771
15905
  it('should be invalid if over max', function() {
15772
- input('value').enter('123');
15773
- expect(binding('value')).toEqual('');
15774
- expect(binding('myForm.input.$valid')).toEqual('false');
15906
+ input.clear();
15907
+ input.sendKeys('123');
15908
+ expect(value.getText()).toEqual('value =');
15909
+ expect(valid.getText()).toContain('false');
15775
15910
  });
15776
- </doc:scenario>
15911
+ </doc:protractor>
15777
15912
  </doc:example>
15778
15913
  */
15779
15914
  'number': numberInputType,
@@ -15825,23 +15960,31 @@ var inputType = {
15825
15960
  <tt>myForm.$error.url = {{!!myForm.$error.url}}</tt><br/>
15826
15961
  </form>
15827
15962
  </doc:source>
15828
- <doc:scenario>
15963
+ <doc:protractor>
15964
+ var text = element(by.binding('text'));
15965
+ var valid = element(by.binding('myForm.input.$valid'));
15966
+ var input = element(by.model('text'));
15967
+
15829
15968
  it('should initialize to model', function() {
15830
- expect(binding('text')).toEqual('http://google.com');
15831
- expect(binding('myForm.input.$valid')).toEqual('true');
15969
+ expect(text.getText()).toContain('http://google.com');
15970
+ expect(valid.getText()).toContain('true');
15832
15971
  });
15833
15972
 
15834
15973
  it('should be invalid if empty', function() {
15835
- input('text').enter('');
15836
- expect(binding('text')).toEqual('');
15837
- expect(binding('myForm.input.$valid')).toEqual('false');
15974
+ input.clear();
15975
+ input.sendKeys('');
15976
+
15977
+ expect(text.getText()).toEqual('text =');
15978
+ expect(valid.getText()).toContain('false');
15838
15979
  });
15839
15980
 
15840
15981
  it('should be invalid if not url', function() {
15841
- input('text').enter('xxx');
15842
- expect(binding('myForm.input.$valid')).toEqual('false');
15982
+ input.clear();
15983
+ input.sendKeys('box');
15984
+
15985
+ expect(valid.getText()).toContain('false');
15843
15986
  });
15844
- </doc:scenario>
15987
+ </doc:protractor>
15845
15988
  </doc:example>
15846
15989
  */
15847
15990
  'url': urlInputType,
@@ -15893,23 +16036,30 @@ var inputType = {
15893
16036
  <tt>myForm.$error.email = {{!!myForm.$error.email}}</tt><br/>
15894
16037
  </form>
15895
16038
  </doc:source>
15896
- <doc:scenario>
16039
+ <doc:protractor>
16040
+ var text = element(by.binding('text'));
16041
+ var valid = element(by.binding('myForm.input.$valid'));
16042
+ var input = element(by.model('text'));
16043
+
15897
16044
  it('should initialize to model', function() {
15898
- expect(binding('text')).toEqual('me@example.com');
15899
- expect(binding('myForm.input.$valid')).toEqual('true');
16045
+ expect(text.getText()).toContain('me@example.com');
16046
+ expect(valid.getText()).toContain('true');
15900
16047
  });
15901
16048
 
15902
16049
  it('should be invalid if empty', function() {
15903
- input('text').enter('');
15904
- expect(binding('text')).toEqual('');
15905
- expect(binding('myForm.input.$valid')).toEqual('false');
16050
+ input.clear();
16051
+ input.sendKeys('');
16052
+ expect(text.getText()).toEqual('text =');
16053
+ expect(valid.getText()).toContain('false');
15906
16054
  });
15907
16055
 
15908
16056
  it('should be invalid if not email', function() {
15909
- input('text').enter('xxx');
15910
- expect(binding('myForm.input.$valid')).toEqual('false');
16057
+ input.clear();
16058
+ input.sendKeys('xxx');
16059
+
16060
+ expect(valid.getText()).toContain('false');
15911
16061
  });
15912
- </doc:scenario>
16062
+ </doc:protractor>
15913
16063
  </doc:example>
15914
16064
  */
15915
16065
  'email': emailInputType,
@@ -15927,6 +16077,8 @@ var inputType = {
15927
16077
  * @param {string=} name Property name of the form under which the control is published.
15928
16078
  * @param {string=} ngChange Angular expression to be executed when input changes due to user
15929
16079
  * interaction with the input element.
16080
+ * @param {string} ngValue Angular expression which sets the value to which the expression should
16081
+ * be set when selected.
15930
16082
  *
15931
16083
  * @example
15932
16084
  <doc:example>
@@ -15934,23 +16086,31 @@ var inputType = {
15934
16086
  <script>
15935
16087
  function Ctrl($scope) {
15936
16088
  $scope.color = 'blue';
16089
+ $scope.specialValue = {
16090
+ "id": "12345",
16091
+ "value": "green"
16092
+ };
15937
16093
  }
15938
16094
  </script>
15939
16095
  <form name="myForm" ng-controller="Ctrl">
15940
16096
  <input type="radio" ng-model="color" value="red"> Red <br/>
15941
- <input type="radio" ng-model="color" value="green"> Green <br/>
16097
+ <input type="radio" ng-model="color" ng-value="specialValue"> Green <br/>
15942
16098
  <input type="radio" ng-model="color" value="blue"> Blue <br/>
15943
- <tt>color = {{color}}</tt><br/>
16099
+ <tt>color = {{color | json}}</tt><br/>
15944
16100
  </form>
16101
+ Note that `ng-value="specialValue"` sets radio item's value to be the value of `$scope.specialValue`.
15945
16102
  </doc:source>
15946
- <doc:scenario>
16103
+ <doc:protractor>
15947
16104
  it('should change state', function() {
15948
- expect(binding('color')).toEqual('blue');
16105
+ var color = element(by.binding('color'));
16106
+
16107
+ expect(color.getText()).toContain('blue');
15949
16108
 
15950
- input('color').select('red');
15951
- expect(binding('color')).toEqual('red');
16109
+ element.all(by.model('color')).get(0).click();
16110
+
16111
+ expect(color.getText()).toContain('red');
15952
16112
  });
15953
- </doc:scenario>
16113
+ </doc:protractor>
15954
16114
  </doc:example>
15955
16115
  */
15956
16116
  'radio': radioInputType,
@@ -15987,17 +16147,21 @@ var inputType = {
15987
16147
  <tt>value2 = {{value2}}</tt><br/>
15988
16148
  </form>
15989
16149
  </doc:source>
15990
- <doc:scenario>
16150
+ <doc:protractor>
15991
16151
  it('should change state', function() {
15992
- expect(binding('value1')).toEqual('true');
15993
- expect(binding('value2')).toEqual('YES');
16152
+ var value1 = element(by.binding('value1'));
16153
+ var value2 = element(by.binding('value2'));
16154
+
16155
+ expect(value1.getText()).toContain('true');
16156
+ expect(value2.getText()).toContain('YES');
16157
+
16158
+ element(by.model('value1')).click();
16159
+ element(by.model('value2')).click();
15994
16160
 
15995
- input('value1').check();
15996
- input('value2').check();
15997
- expect(binding('value1')).toEqual('false');
15998
- expect(binding('value2')).toEqual('NO');
16161
+ expect(value1.getText()).toContain('false');
16162
+ expect(value2.getText()).toContain('NO');
15999
16163
  });
16000
- </doc:scenario>
16164
+ </doc:protractor>
16001
16165
  </doc:example>
16002
16166
  */
16003
16167
  'checkbox': checkboxInputType,
@@ -16005,7 +16169,8 @@ var inputType = {
16005
16169
  'hidden': noop,
16006
16170
  'button': noop,
16007
16171
  'submit': noop,
16008
- 'reset': noop
16172
+ 'reset': noop,
16173
+ 'file': noop
16009
16174
  };
16010
16175
 
16011
16176
  // A helper function to call $setValidity and return the value / undefined,
@@ -16028,6 +16193,7 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
16028
16193
 
16029
16194
  element.on('compositionend', function() {
16030
16195
  composing = false;
16196
+ listener();
16031
16197
  });
16032
16198
  }
16033
16199
 
@@ -16350,44 +16516,59 @@ function checkboxInputType(scope, element, attr, ctrl) {
16350
16516
  <tt>myForm.$error.maxlength = {{!!myForm.$error.maxlength}}</tt><br>
16351
16517
  </div>
16352
16518
  </doc:source>
16353
- <doc:scenario>
16519
+ <doc:protractor>
16520
+ var user = element(by.binding('{{user}}'));
16521
+ var userNameValid = element(by.binding('myForm.userName.$valid'));
16522
+ var lastNameValid = element(by.binding('myForm.lastName.$valid'));
16523
+ var lastNameError = element(by.binding('myForm.lastName.$error'));
16524
+ var formValid = element(by.binding('myForm.$valid'));
16525
+ var userNameInput = element(by.model('user.name'));
16526
+ var userLastInput = element(by.model('user.last'));
16527
+
16354
16528
  it('should initialize to model', function() {
16355
- expect(binding('user')).toEqual('{"name":"guest","last":"visitor"}');
16356
- expect(binding('myForm.userName.$valid')).toEqual('true');
16357
- expect(binding('myForm.$valid')).toEqual('true');
16529
+ expect(user.getText()).toContain('{"name":"guest","last":"visitor"}');
16530
+ expect(userNameValid.getText()).toContain('true');
16531
+ expect(formValid.getText()).toContain('true');
16358
16532
  });
16359
16533
 
16360
16534
  it('should be invalid if empty when required', function() {
16361
- input('user.name').enter('');
16362
- expect(binding('user')).toEqual('{"last":"visitor"}');
16363
- expect(binding('myForm.userName.$valid')).toEqual('false');
16364
- expect(binding('myForm.$valid')).toEqual('false');
16535
+ userNameInput.clear();
16536
+ userNameInput.sendKeys('');
16537
+
16538
+ expect(user.getText()).toContain('{"last":"visitor"}');
16539
+ expect(userNameValid.getText()).toContain('false');
16540
+ expect(formValid.getText()).toContain('false');
16365
16541
  });
16366
16542
 
16367
16543
  it('should be valid if empty when min length is set', function() {
16368
- input('user.last').enter('');
16369
- expect(binding('user')).toEqual('{"name":"guest","last":""}');
16370
- expect(binding('myForm.lastName.$valid')).toEqual('true');
16371
- expect(binding('myForm.$valid')).toEqual('true');
16544
+ userLastInput.clear();
16545
+ userLastInput.sendKeys('');
16546
+
16547
+ expect(user.getText()).toContain('{"name":"guest","last":""}');
16548
+ expect(lastNameValid.getText()).toContain('true');
16549
+ expect(formValid.getText()).toContain('true');
16372
16550
  });
16373
16551
 
16374
16552
  it('should be invalid if less than required min length', function() {
16375
- input('user.last').enter('xx');
16376
- expect(binding('user')).toEqual('{"name":"guest"}');
16377
- expect(binding('myForm.lastName.$valid')).toEqual('false');
16378
- expect(binding('myForm.lastName.$error')).toMatch(/minlength/);
16379
- expect(binding('myForm.$valid')).toEqual('false');
16553
+ userLastInput.clear();
16554
+ userLastInput.sendKeys('xx');
16555
+
16556
+ expect(user.getText()).toContain('{"name":"guest"}');
16557
+ expect(lastNameValid.getText()).toContain('false');
16558
+ expect(lastNameError.getText()).toContain('minlength');
16559
+ expect(formValid.getText()).toContain('false');
16380
16560
  });
16381
16561
 
16382
16562
  it('should be invalid if longer than max length', function() {
16383
- input('user.last').enter('some ridiculously long name');
16384
- expect(binding('user'))
16385
- .toEqual('{"name":"guest"}');
16386
- expect(binding('myForm.lastName.$valid')).toEqual('false');
16387
- expect(binding('myForm.lastName.$error')).toMatch(/maxlength/);
16388
- expect(binding('myForm.$valid')).toEqual('false');
16563
+ userLastInput.clear();
16564
+ userLastInput.sendKeys('some ridiculously long name');
16565
+
16566
+ expect(user.getText()).toContain('{"name":"guest"}');
16567
+ expect(lastNameValid.getText()).toContain('false');
16568
+ expect(lastNameError.getText()).toContain('maxlength');
16569
+ expect(formValid.getText()).toContain('false');
16389
16570
  });
16390
- </doc:scenario>
16571
+ </doc:protractor>
16391
16572
  </doc:example>
16392
16573
  */
16393
16574
  var inputDirective = ['$browser', '$sniffer', function($browser, $sniffer) {
@@ -16519,14 +16700,23 @@ var VALID_CLASS = 'ng-valid',
16519
16700
  <textarea ng-model="userContent"></textarea>
16520
16701
  </form>
16521
16702
  </file>
16522
- <file name="scenario.js">
16703
+ <file name="protractorTest.js">
16523
16704
  it('should data-bind and become invalid', function() {
16524
- var contentEditable = element('[contenteditable]');
16705
+ if (browser.params.browser = 'safari') {
16706
+ // SafariDriver can't handle contenteditable.
16707
+ return;
16708
+ };
16709
+ var contentEditable = element(by.css('.doc-example-live [contenteditable]'));
16525
16710
 
16526
- expect(contentEditable.text()).toEqual('Change me!');
16527
- input('userContent').enter('');
16528
- expect(contentEditable.text()).toEqual('');
16529
- expect(contentEditable.prop('className')).toMatch(/ng-invalid-required/);
16711
+ expect(contentEditable.getText()).toEqual('Change me!');
16712
+
16713
+ // Firefox driver doesn't trigger the proper events on 'clear', so do this hack
16714
+ contentEditable.click();
16715
+ contentEditable.sendKeys(protractor.Key.chord(protractor.Key.COMMAND, "a"));
16716
+ contentEditable.sendKeys(protractor.Key.BACK_SPACE);
16717
+
16718
+ expect(contentEditable.getText()).toEqual('');
16719
+ expect(contentEditable.getAttribute('class')).toMatch(/ng-invalid-required/);
16530
16720
  });
16531
16721
  </file>
16532
16722
  * </example>
@@ -16579,6 +16769,9 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
16579
16769
  * You can override this for input directives whose concept of being empty is different to the
16580
16770
  * default. The `checkboxInputType` directive does this because in its case a value of `false`
16581
16771
  * implies empty.
16772
+ *
16773
+ * @param {*} value Reference to check.
16774
+ * @returns {boolean} True if `value` is empty.
16582
16775
  */
16583
16776
  this.$isEmpty = function(value) {
16584
16777
  return isUndefined(value) || value === '' || value === null || value !== value;
@@ -16806,7 +16999,10 @@ var ngModelDirective = function() {
16806
16999
  * @name ng.directive:ngChange
16807
17000
  *
16808
17001
  * @description
16809
- * Evaluate given expression when user changes the input.
17002
+ * Evaluate the given expression when the user changes the input.
17003
+ * The expression is evaluated immediately, unlike the JavaScript onchange event
17004
+ * which only triggers at the end of a change (usually, when the user leaves the
17005
+ * form element or presses the return key).
16810
17006
  * The expression is not evaluated when the value change is coming from the model.
16811
17007
  *
16812
17008
  * Note, this directive requires `ngModel` to be present.
@@ -16830,24 +17026,30 @@ var ngModelDirective = function() {
16830
17026
  * <input type="checkbox" ng-model="confirmed" ng-change="change()" id="ng-change-example1" />
16831
17027
  * <input type="checkbox" ng-model="confirmed" id="ng-change-example2" />
16832
17028
  * <label for="ng-change-example2">Confirmed</label><br />
16833
- * debug = {{confirmed}}<br />
16834
- * counter = {{counter}}
17029
+ * <tt>debug = {{confirmed}}</tt><br/>
17030
+ * <tt>counter = {{counter}}</tt><br/>
16835
17031
  * </div>
16836
17032
  * </doc:source>
16837
- * <doc:scenario>
17033
+ * <doc:protractor>
17034
+ * var counter = element(by.binding('counter'));
17035
+ * var debug = element(by.binding('confirmed'));
17036
+ *
16838
17037
  * it('should evaluate the expression if changing from view', function() {
16839
- * expect(binding('counter')).toEqual('0');
16840
- * element('#ng-change-example1').click();
16841
- * expect(binding('counter')).toEqual('1');
16842
- * expect(binding('confirmed')).toEqual('true');
17038
+ * expect(counter.getText()).toContain('0');
17039
+ *
17040
+ * element(by.id('ng-change-example1')).click();
17041
+ *
17042
+ * expect(counter.getText()).toContain('1');
17043
+ * expect(debug.getText()).toContain('true');
16843
17044
  * });
16844
17045
  *
16845
17046
  * it('should not evaluate the expression if changing from model', function() {
16846
- * element('#ng-change-example2').click();
16847
- * expect(binding('counter')).toEqual('0');
16848
- * expect(binding('confirmed')).toEqual('true');
17047
+ * element(by.id('ng-change-example2')).click();
17048
+
17049
+ * expect(counter.getText()).toContain('0');
17050
+ * expect(debug.getText()).toContain('true');
16849
17051
  * });
16850
- * </doc:scenario>
17052
+ * </doc:protractor>
16851
17053
  * </doc:example>
16852
17054
  */
16853
17055
  var ngChangeDirective = valueFn({
@@ -16920,20 +17122,26 @@ var requiredDirective = function() {
16920
17122
  <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
16921
17123
  </form>
16922
17124
  </doc:source>
16923
- <doc:scenario>
17125
+ <doc:protractor>
17126
+ var listInput = element(by.model('names'));
17127
+ var names = element(by.binding('{{names}}'));
17128
+ var valid = element(by.binding('myForm.namesInput.$valid'));
17129
+ var error = element(by.css('span.error'));
17130
+
16924
17131
  it('should initialize to model', function() {
16925
- expect(binding('names')).toEqual('["igor","misko","vojta"]');
16926
- expect(binding('myForm.namesInput.$valid')).toEqual('true');
16927
- expect(element('span.error').css('display')).toBe('none');
17132
+ expect(names.getText()).toContain('["igor","misko","vojta"]');
17133
+ expect(valid.getText()).toContain('true');
17134
+ expect(error.getCssValue('display')).toBe('none');
16928
17135
  });
16929
17136
 
16930
17137
  it('should be invalid if empty', function() {
16931
- input('names').enter('');
16932
- expect(binding('names')).toEqual('');
16933
- expect(binding('myForm.namesInput.$valid')).toEqual('false');
16934
- expect(element('span.error').css('display')).not().toBe('none');
16935
- });
16936
- </doc:scenario>
17138
+ listInput.clear();
17139
+ listInput.sendKeys('');
17140
+
17141
+ expect(names.getText()).toContain('');
17142
+ expect(valid.getText()).toContain('false');
17143
+ expect(error.getCssValue('display')).not.toBe('none'); });
17144
+ </doc:protractor>
16937
17145
  </doc:example>
16938
17146
  */
16939
17147
  var ngListDirective = function() {
@@ -17015,15 +17223,17 @@ var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
17015
17223
  <div>You chose {{my.favorite}}</div>
17016
17224
  </form>
17017
17225
  </doc:source>
17018
- <doc:scenario>
17226
+ <doc:protractor>
17227
+ var favorite = element(by.binding('my.favorite'));
17228
+
17019
17229
  it('should initialize to model', function() {
17020
- expect(binding('my.favorite')).toEqual('unicorns');
17230
+ expect(favorite.getText()).toContain('unicorns');
17021
17231
  });
17022
17232
  it('should bind the values to the inputs', function() {
17023
- input('my.favorite').select('pizza');
17024
- expect(binding('my.favorite')).toEqual('pizza');
17233
+ element.all(by.model('my.favorite')).get(0).click();
17234
+ expect(favorite.getText()).toContain('pizza');
17025
17235
  });
17026
- </doc:scenario>
17236
+ </doc:protractor>
17027
17237
  </doc:example>
17028
17238
  */
17029
17239
  var ngValueDirective = function() {
@@ -17083,13 +17293,17 @@ var ngValueDirective = function() {
17083
17293
  Hello <span ng-bind="name"></span>!
17084
17294
  </div>
17085
17295
  </doc:source>
17086
- <doc:scenario>
17296
+ <doc:protractor>
17087
17297
  it('should check ng-bind', function() {
17088
- expect(using('.doc-example-live').binding('name')).toBe('Whirled');
17089
- using('.doc-example-live').input('name').enter('world');
17090
- expect(using('.doc-example-live').binding('name')).toBe('world');
17298
+ var exampleContainer = $('.doc-example-live');
17299
+ var nameInput = element(by.model('name'));
17300
+
17301
+ expect(exampleContainer.findElement(by.binding('name')).getText()).toBe('Whirled');
17302
+ nameInput.clear();
17303
+ nameInput.sendKeys('world');
17304
+ expect(exampleContainer.findElement(by.binding('name')).getText()).toBe('world');
17091
17305
  });
17092
- </doc:scenario>
17306
+ </doc:protractor>
17093
17307
  </doc:example>
17094
17308
  */
17095
17309
  var ngBindDirective = ngDirective(function(scope, element, attr) {
@@ -17135,20 +17349,22 @@ var ngBindDirective = ngDirective(function(scope, element, attr) {
17135
17349
  <pre ng-bind-template="{{salutation}} {{name}}!"></pre>
17136
17350
  </div>
17137
17351
  </doc:source>
17138
- <doc:scenario>
17352
+ <doc:protractor>
17139
17353
  it('should check ng-bind', function() {
17140
- expect(using('.doc-example-live').binding('salutation')).
17141
- toBe('Hello');
17142
- expect(using('.doc-example-live').binding('name')).
17143
- toBe('World');
17144
- using('.doc-example-live').input('salutation').enter('Greetings');
17145
- using('.doc-example-live').input('name').enter('user');
17146
- expect(using('.doc-example-live').binding('salutation')).
17147
- toBe('Greetings');
17148
- expect(using('.doc-example-live').binding('name')).
17149
- toBe('user');
17354
+ var salutationElem = element(by.binding('salutation'));
17355
+ var salutationInput = element(by.model('salutation'));
17356
+ var nameInput = element(by.model('name'));
17357
+
17358
+ expect(salutationElem.getText()).toBe('Hello World!');
17359
+
17360
+ salutationInput.clear();
17361
+ salutationInput.sendKeys('Greetings');
17362
+ nameInput.clear();
17363
+ nameInput.sendKeys('user');
17364
+
17365
+ expect(salutationElem.getText()).toBe('Greetings user!');
17150
17366
  });
17151
- </doc:scenario>
17367
+ </doc:protractor>
17152
17368
  </doc:example>
17153
17369
  */
17154
17370
  var ngBindTemplateDirective = ['$interpolate', function($interpolate) {
@@ -17201,12 +17417,10 @@ var ngBindTemplateDirective = ['$interpolate', function($interpolate) {
17201
17417
  }]);
17202
17418
  </file>
17203
17419
 
17204
- <file name="scenario.js">
17420
+ <file name="protractorTest.js">
17205
17421
  it('should check ng-bind-html', function() {
17206
- expect(using('.doc-example-live').binding('myHTML')).
17207
- toBe(
17208
- 'I am an <code>HTML</code>string with <a href="#">links!</a> and other <em>stuff</em>'
17209
- );
17422
+ expect(element(by.binding('myHTML')).getText()).toBe(
17423
+ 'I am an HTMLstring with links! and other stuff');
17210
17424
  });
17211
17425
  </file>
17212
17426
  </example>
@@ -17338,31 +17552,34 @@ function classDirective(name, selector) {
17338
17552
  color: red;
17339
17553
  }
17340
17554
  </file>
17341
- <file name="scenario.js">
17555
+ <file name="protractorTest.js">
17556
+ var ps = element.all(by.css('.doc-example-live p'));
17557
+
17342
17558
  it('should let you toggle the class', function() {
17343
17559
 
17344
- expect(element('.doc-example-live p:first').prop('className')).not().toMatch(/bold/);
17345
- expect(element('.doc-example-live p:first').prop('className')).not().toMatch(/red/);
17560
+ expect(ps.first().getAttribute('class')).not.toMatch(/bold/);
17561
+ expect(ps.first().getAttribute('class')).not.toMatch(/red/);
17346
17562
 
17347
- input('important').check();
17348
- expect(element('.doc-example-live p:first').prop('className')).toMatch(/bold/);
17563
+ element(by.model('important')).click();
17564
+ expect(ps.first().getAttribute('class')).toMatch(/bold/);
17349
17565
 
17350
- input('error').check();
17351
- expect(element('.doc-example-live p:first').prop('className')).toMatch(/red/);
17566
+ element(by.model('error')).click();
17567
+ expect(ps.first().getAttribute('class')).toMatch(/red/);
17352
17568
  });
17353
17569
 
17354
17570
  it('should let you toggle string example', function() {
17355
- expect(element('.doc-example-live p:nth-of-type(2)').prop('className')).toBe('');
17356
- input('style').enter('red');
17357
- expect(element('.doc-example-live p:nth-of-type(2)').prop('className')).toBe('red');
17571
+ expect(ps.get(1).getAttribute('class')).toBe('');
17572
+ element(by.model('style')).clear();
17573
+ element(by.model('style')).sendKeys('red');
17574
+ expect(ps.get(1).getAttribute('class')).toBe('red');
17358
17575
  });
17359
17576
 
17360
17577
  it('array example should have 3 classes', function() {
17361
- expect(element('.doc-example-live p:last').prop('className')).toBe('');
17362
- input('style1').enter('bold');
17363
- input('style2').enter('strike');
17364
- input('style3').enter('red');
17365
- expect(element('.doc-example-live p:last').prop('className')).toBe('bold strike red');
17578
+ expect(ps.last().getAttribute('class')).toBe('');
17579
+ element(by.model('style1')).sendKeys('bold');
17580
+ element(by.model('style2')).sendKeys('strike');
17581
+ element(by.model('style3')).sendKeys('red');
17582
+ expect(ps.last().getAttribute('class')).toBe('bold strike red');
17366
17583
  });
17367
17584
  </file>
17368
17585
  </example>
@@ -17373,8 +17590,8 @@ function classDirective(name, selector) {
17373
17590
 
17374
17591
  <example animations="true">
17375
17592
  <file name="index.html">
17376
- <input type="button" value="set" ng-click="myVar='my-class'">
17377
- <input type="button" value="clear" ng-click="myVar=''">
17593
+ <input id="setbtn" type="button" value="set" ng-click="myVar='my-class'">
17594
+ <input id="clearbtn" type="button" value="clear" ng-click="myVar=''">
17378
17595
  <br>
17379
17596
  <span class="base-class" ng-class="myVar">Sample Text</span>
17380
17597
  </file>
@@ -17389,19 +17606,19 @@ function classDirective(name, selector) {
17389
17606
  font-size:3em;
17390
17607
  }
17391
17608
  </file>
17392
- <file name="scenario.js">
17609
+ <file name="protractorTest.js">
17393
17610
  it('should check ng-class', function() {
17394
- expect(element('.doc-example-live span').prop('className')).not().
17611
+ expect(element(by.css('.base-class')).getAttribute('class')).not.
17395
17612
  toMatch(/my-class/);
17396
17613
 
17397
- using('.doc-example-live').element(':button:first').click();
17614
+ element(by.id('setbtn')).click();
17398
17615
 
17399
- expect(element('.doc-example-live span').prop('className')).
17616
+ expect(element(by.css('.base-class')).getAttribute('class')).
17400
17617
  toMatch(/my-class/);
17401
17618
 
17402
- using('.doc-example-live').element(':button:last').click();
17619
+ element(by.id('clearbtn')).click();
17403
17620
 
17404
- expect(element('.doc-example-live span').prop('className')).not().
17621
+ expect(element(by.css('.base-class')).getAttribute('class')).not.
17405
17622
  toMatch(/my-class/);
17406
17623
  });
17407
17624
  </file>
@@ -17453,11 +17670,11 @@ var ngClassDirective = classDirective('', true);
17453
17670
  color: blue;
17454
17671
  }
17455
17672
  </file>
17456
- <file name="scenario.js">
17673
+ <file name="protractorTest.js">
17457
17674
  it('should check ng-class-odd and ng-class-even', function() {
17458
- expect(element('.doc-example-live li:first span').prop('className')).
17675
+ expect(element(by.repeater('name in names').row(0).column('name')).getAttribute('class')).
17459
17676
  toMatch(/odd/);
17460
- expect(element('.doc-example-live li:last span').prop('className')).
17677
+ expect(element(by.repeater('name in names').row(1).column('name')).getAttribute('class')).
17461
17678
  toMatch(/even/);
17462
17679
  });
17463
17680
  </file>
@@ -17501,11 +17718,11 @@ var ngClassOddDirective = classDirective('Odd', 0);
17501
17718
  color: blue;
17502
17719
  }
17503
17720
  </file>
17504
- <file name="scenario.js">
17721
+ <file name="protractorTest.js">
17505
17722
  it('should check ng-class-odd and ng-class-even', function() {
17506
- expect(element('.doc-example-live li:first span').prop('className')).
17723
+ expect(element(by.repeater('name in names').row(0).column('name')).getAttribute('class')).
17507
17724
  toMatch(/odd/);
17508
- expect(element('.doc-example-live li:last span').prop('className')).
17725
+ expect(element(by.repeater('name in names').row(1).column('name')).getAttribute('class')).
17509
17726
  toMatch(/even/);
17510
17727
  });
17511
17728
  </file>
@@ -17558,14 +17775,14 @@ var ngClassEvenDirective = classDirective('Even', 1);
17558
17775
  <div id="template1" ng-cloak>{{ 'hello' }}</div>
17559
17776
  <div id="template2" ng-cloak class="ng-cloak">{{ 'hello IE7' }}</div>
17560
17777
  </doc:source>
17561
- <doc:scenario>
17778
+ <doc:protractor>
17562
17779
  it('should remove the template directive and css class', function() {
17563
- expect(element('.doc-example-live #template1').attr('ng-cloak')).
17564
- not().toBeDefined();
17565
- expect(element('.doc-example-live #template2').attr('ng-cloak')).
17566
- not().toBeDefined();
17780
+ expect($('.doc-example-live #template1').getAttribute('ng-cloak')).
17781
+ toBeNull();
17782
+ expect($('.doc-example-live #template2').getAttribute('ng-cloak')).
17783
+ toBeNull();
17567
17784
  });
17568
- </doc:scenario>
17785
+ </doc:protractor>
17569
17786
  </doc:example>
17570
17787
  *
17571
17788
  */
@@ -17658,22 +17875,36 @@ var ngCloakDirective = ngDirective({
17658
17875
  </ul>
17659
17876
  </div>
17660
17877
  </doc:source>
17661
- <doc:scenario>
17878
+ <doc:protractor>
17662
17879
  it('should check controller as', function() {
17663
- expect(element('#ctrl-as-exmpl>:input').val()).toBe('John Smith');
17664
- expect(element('#ctrl-as-exmpl li:nth-child(1) input').val())
17665
- .toBe('408 555 1212');
17666
- expect(element('#ctrl-as-exmpl li:nth-child(2) input').val())
17667
- .toBe('john.smith@example.org');
17668
-
17669
- element('#ctrl-as-exmpl li:first a:contains("clear")').click();
17670
- expect(element('#ctrl-as-exmpl li:first input').val()).toBe('');
17671
-
17672
- element('#ctrl-as-exmpl li:last a:contains("add")').click();
17673
- expect(element('#ctrl-as-exmpl li:nth-child(3) input').val())
17674
- .toBe('yourname@example.org');
17880
+ var container = element(by.id('ctrl-as-exmpl'));
17881
+
17882
+ expect(container.findElement(by.model('settings.name'))
17883
+ .getAttribute('value')).toBe('John Smith');
17884
+
17885
+ var firstRepeat =
17886
+ container.findElement(by.repeater('contact in settings.contacts').row(0));
17887
+ var secondRepeat =
17888
+ container.findElement(by.repeater('contact in settings.contacts').row(1));
17889
+
17890
+ expect(firstRepeat.findElement(by.model('contact.value')).getAttribute('value'))
17891
+ .toBe('408 555 1212');
17892
+ expect(secondRepeat.findElement(by.model('contact.value')).getAttribute('value'))
17893
+ .toBe('john.smith@example.org');
17894
+
17895
+ firstRepeat.findElement(by.linkText('clear')).click()
17896
+
17897
+ expect(firstRepeat.findElement(by.model('contact.value')).getAttribute('value'))
17898
+ .toBe('');
17899
+
17900
+ container.findElement(by.linkText('add')).click();
17901
+
17902
+ expect(container.findElement(by.repeater('contact in settings.contacts').row(2))
17903
+ .findElement(by.model('contact.value'))
17904
+ .getAttribute('value'))
17905
+ .toBe('yourname@example.org');
17675
17906
  });
17676
- </doc:scenario>
17907
+ </doc:protractor>
17677
17908
  </doc:example>
17678
17909
  <doc:example>
17679
17910
  <doc:source>
@@ -17721,22 +17952,36 @@ var ngCloakDirective = ngDirective({
17721
17952
  </ul>
17722
17953
  </div>
17723
17954
  </doc:source>
17724
- <doc:scenario>
17955
+ <doc:protractor>
17725
17956
  it('should check controller', function() {
17726
- expect(element('#ctrl-exmpl>:input').val()).toBe('John Smith');
17727
- expect(element('#ctrl-exmpl li:nth-child(1) input').val())
17728
- .toBe('408 555 1212');
17729
- expect(element('#ctrl-exmpl li:nth-child(2) input').val())
17730
- .toBe('john.smith@example.org');
17731
-
17732
- element('#ctrl-exmpl li:first a:contains("clear")').click();
17733
- expect(element('#ctrl-exmpl li:first input').val()).toBe('');
17734
-
17735
- element('#ctrl-exmpl li:last a:contains("add")').click();
17736
- expect(element('#ctrl-exmpl li:nth-child(3) input').val())
17737
- .toBe('yourname@example.org');
17957
+ var container = element(by.id('ctrl-exmpl'));
17958
+
17959
+ expect(container.findElement(by.model('name'))
17960
+ .getAttribute('value')).toBe('John Smith');
17961
+
17962
+ var firstRepeat =
17963
+ container.findElement(by.repeater('contact in contacts').row(0));
17964
+ var secondRepeat =
17965
+ container.findElement(by.repeater('contact in contacts').row(1));
17966
+
17967
+ expect(firstRepeat.findElement(by.model('contact.value')).getAttribute('value'))
17968
+ .toBe('408 555 1212');
17969
+ expect(secondRepeat.findElement(by.model('contact.value')).getAttribute('value'))
17970
+ .toBe('john.smith@example.org');
17971
+
17972
+ firstRepeat.findElement(by.linkText('clear')).click()
17973
+
17974
+ expect(firstRepeat.findElement(by.model('contact.value')).getAttribute('value'))
17975
+ .toBe('');
17976
+
17977
+ container.findElement(by.linkText('add')).click();
17978
+
17979
+ expect(container.findElement(by.repeater('contact in contacts').row(2))
17980
+ .findElement(by.model('contact.value'))
17981
+ .getAttribute('value'))
17982
+ .toBe('yourname@example.org');
17738
17983
  });
17739
- </doc:scenario>
17984
+ </doc:protractor>
17740
17985
  </doc:example>
17741
17986
 
17742
17987
  */
@@ -17799,6 +18044,7 @@ var ngControllerDirective = [function() {
17799
18044
  * an element is clicked.
17800
18045
  *
17801
18046
  * @element ANY
18047
+ * @priority 0
17802
18048
  * @param {expression} ngClick {@link guide/expression Expression} to evaluate upon
17803
18049
  * click. (Event object is available as `$event`)
17804
18050
  *
@@ -17855,6 +18101,7 @@ forEach(
17855
18101
  * The `ngDblclick` directive allows you to specify custom behavior on a dblclick event.
17856
18102
  *
17857
18103
  * @element ANY
18104
+ * @priority 0
17858
18105
  * @param {expression} ngDblclick {@link guide/expression Expression} to evaluate upon
17859
18106
  * a dblclick. (The Event object is available as `$event`)
17860
18107
  *
@@ -17878,6 +18125,7 @@ forEach(
17878
18125
  * The ngMousedown directive allows you to specify custom behavior on mousedown event.
17879
18126
  *
17880
18127
  * @element ANY
18128
+ * @priority 0
17881
18129
  * @param {expression} ngMousedown {@link guide/expression Expression} to evaluate upon
17882
18130
  * mousedown. (Event object is available as `$event`)
17883
18131
  *
@@ -17901,6 +18149,7 @@ forEach(
17901
18149
  * Specify custom behavior on mouseup event.
17902
18150
  *
17903
18151
  * @element ANY
18152
+ * @priority 0
17904
18153
  * @param {expression} ngMouseup {@link guide/expression Expression} to evaluate upon
17905
18154
  * mouseup. (Event object is available as `$event`)
17906
18155
  *
@@ -17923,6 +18172,7 @@ forEach(
17923
18172
  * Specify custom behavior on mouseover event.
17924
18173
  *
17925
18174
  * @element ANY
18175
+ * @priority 0
17926
18176
  * @param {expression} ngMouseover {@link guide/expression Expression} to evaluate upon
17927
18177
  * mouseover. (Event object is available as `$event`)
17928
18178
  *
@@ -17946,6 +18196,7 @@ forEach(
17946
18196
  * Specify custom behavior on mouseenter event.
17947
18197
  *
17948
18198
  * @element ANY
18199
+ * @priority 0
17949
18200
  * @param {expression} ngMouseenter {@link guide/expression Expression} to evaluate upon
17950
18201
  * mouseenter. (Event object is available as `$event`)
17951
18202
  *
@@ -17969,6 +18220,7 @@ forEach(
17969
18220
  * Specify custom behavior on mouseleave event.
17970
18221
  *
17971
18222
  * @element ANY
18223
+ * @priority 0
17972
18224
  * @param {expression} ngMouseleave {@link guide/expression Expression} to evaluate upon
17973
18225
  * mouseleave. (Event object is available as `$event`)
17974
18226
  *
@@ -17992,6 +18244,7 @@ forEach(
17992
18244
  * Specify custom behavior on mousemove event.
17993
18245
  *
17994
18246
  * @element ANY
18247
+ * @priority 0
17995
18248
  * @param {expression} ngMousemove {@link guide/expression Expression} to evaluate upon
17996
18249
  * mousemove. (Event object is available as `$event`)
17997
18250
  *
@@ -18015,6 +18268,7 @@ forEach(
18015
18268
  * Specify custom behavior on keydown event.
18016
18269
  *
18017
18270
  * @element ANY
18271
+ * @priority 0
18018
18272
  * @param {expression} ngKeydown {@link guide/expression Expression} to evaluate upon
18019
18273
  * keydown. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
18020
18274
  *
@@ -18036,6 +18290,7 @@ forEach(
18036
18290
  * Specify custom behavior on keyup event.
18037
18291
  *
18038
18292
  * @element ANY
18293
+ * @priority 0
18039
18294
  * @param {expression} ngKeyup {@link guide/expression Expression} to evaluate upon
18040
18295
  * keyup. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
18041
18296
  *
@@ -18078,10 +18333,11 @@ forEach(
18078
18333
  * Enables binding angular expressions to onsubmit events.
18079
18334
  *
18080
18335
  * Additionally it prevents the default action (which for form means sending the request to the
18081
- * server and reloading the current page) **but only if the form does not contain an `action`
18082
- * attribute**.
18336
+ * server and reloading the current page), but only if the form does not contain `action`,
18337
+ * `data-action`, or `x-action` attributes.
18083
18338
  *
18084
18339
  * @element form
18340
+ * @priority 0
18085
18341
  * @param {expression} ngSubmit {@link guide/expression Expression} to eval. (Event object is available as `$event`)
18086
18342
  *
18087
18343
  * @example
@@ -18106,20 +18362,20 @@ forEach(
18106
18362
  <pre>list={{list}}</pre>
18107
18363
  </form>
18108
18364
  </doc:source>
18109
- <doc:scenario>
18365
+ <doc:protractor>
18110
18366
  it('should check ng-submit', function() {
18111
- expect(binding('list')).toBe('[]');
18112
- element('.doc-example-live #submit').click();
18113
- expect(binding('list')).toBe('["hello"]');
18114
- expect(input('text').val()).toBe('');
18367
+ expect(element(by.binding('list')).getText()).toBe('list=[]');
18368
+ element(by.css('.doc-example-live #submit')).click();
18369
+ expect(element(by.binding('list')).getText()).toContain('hello');
18370
+ expect(element(by.input('text')).getAttribute('value')).toBe('');
18115
18371
  });
18116
18372
  it('should ignore empty strings', function() {
18117
- expect(binding('list')).toBe('[]');
18118
- element('.doc-example-live #submit').click();
18119
- element('.doc-example-live #submit').click();
18120
- expect(binding('list')).toBe('["hello"]');
18121
- });
18122
- </doc:scenario>
18373
+ expect(element(by.binding('list')).getText()).toBe('list=[]');
18374
+ element(by.css('.doc-example-live #submit')).click();
18375
+ element(by.css('.doc-example-live #submit')).click();
18376
+ expect(element(by.binding('list')).getText()).toContain('hello');
18377
+ });
18378
+ </doc:protractor>
18123
18379
  </doc:example>
18124
18380
  */
18125
18381
 
@@ -18131,6 +18387,7 @@ forEach(
18131
18387
  * Specify custom behavior on focus event.
18132
18388
  *
18133
18389
  * @element window, input, select, textarea, a
18390
+ * @priority 0
18134
18391
  * @param {expression} ngFocus {@link guide/expression Expression} to evaluate upon
18135
18392
  * focus. (Event object is available as `$event`)
18136
18393
  *
@@ -18146,6 +18403,7 @@ forEach(
18146
18403
  * Specify custom behavior on blur event.
18147
18404
  *
18148
18405
  * @element window, input, select, textarea, a
18406
+ * @priority 0
18149
18407
  * @param {expression} ngBlur {@link guide/expression Expression} to evaluate upon
18150
18408
  * blur. (Event object is available as `$event`)
18151
18409
  *
@@ -18161,6 +18419,7 @@ forEach(
18161
18419
  * Specify custom behavior on copy event.
18162
18420
  *
18163
18421
  * @element window, input, select, textarea, a
18422
+ * @priority 0
18164
18423
  * @param {expression} ngCopy {@link guide/expression Expression} to evaluate upon
18165
18424
  * copy. (Event object is available as `$event`)
18166
18425
  *
@@ -18181,6 +18440,7 @@ forEach(
18181
18440
  * Specify custom behavior on cut event.
18182
18441
  *
18183
18442
  * @element window, input, select, textarea, a
18443
+ * @priority 0
18184
18444
  * @param {expression} ngCut {@link guide/expression Expression} to evaluate upon
18185
18445
  * cut. (Event object is available as `$event`)
18186
18446
  *
@@ -18201,6 +18461,7 @@ forEach(
18201
18461
  * Specify custom behavior on paste event.
18202
18462
  *
18203
18463
  * @element window, input, select, textarea, a
18464
+ * @priority 0
18204
18465
  * @param {expression} ngPaste {@link guide/expression Expression} to evaluate upon
18205
18466
  * paste. (Event object is available as `$event`)
18206
18467
  *
@@ -18441,19 +18702,33 @@ var ngIfDirective = ['$animate', function($animate) {
18441
18702
  top:50px;
18442
18703
  }
18443
18704
  </file>
18444
- <file name="scenario.js">
18705
+ <file name="protractorTest.js">
18706
+ var templateSelect = element(by.model('template'));
18707
+ var includeElem = element(by.css('.doc-example-live [ng-include]'));
18708
+
18445
18709
  it('should load template1.html', function() {
18446
- expect(element('.doc-example-live [ng-include]').text()).
18447
- toMatch(/Content of template1.html/);
18710
+ expect(includeElem.getText()).toMatch(/Content of template1.html/);
18448
18711
  });
18712
+
18449
18713
  it('should load template2.html', function() {
18450
- select('template').option('1');
18451
- expect(element('.doc-example-live [ng-include]').text()).
18452
- toMatch(/Content of template2.html/);
18714
+ if (browser.params.browser == 'firefox') {
18715
+ // Firefox can't handle using selects
18716
+ // See https://github.com/angular/protractor/issues/480
18717
+ return;
18718
+ }
18719
+ templateSelect.click();
18720
+ templateSelect.element.all(by.css('option')).get(2).click();
18721
+ expect(includeElem.getText()).toMatch(/Content of template2.html/);
18453
18722
  });
18723
+
18454
18724
  it('should change to blank', function() {
18455
- select('template').option('');
18456
- expect(element('.doc-example-live [ng-include]')).toBe(undefined);
18725
+ if (browser.params.browser == 'firefox') {
18726
+ // Firefox can't handle using selects
18727
+ return;
18728
+ }
18729
+ templateSelect.click();
18730
+ templateSelect.element.all(by.css('option')).get(0).click();
18731
+ expect(includeElem.isPresent()).toBe(false);
18457
18732
  });
18458
18733
  </file>
18459
18734
  </example>
@@ -18584,6 +18859,13 @@ var ngIncludeFillContentDirective = ['$compile',
18584
18859
  * should use {@link guide/controller controllers} rather than `ngInit`
18585
18860
  * to initialize values on a scope.
18586
18861
  * </div>
18862
+ * <div class="alert alert-warning">
18863
+ * **Note**: If you have assignment in `ngInit` along with {@link api/ng.$filter `$filter`}, make
18864
+ * sure you have parenthesis for correct precedence:
18865
+ * <pre class="prettyprint">
18866
+ * <div ng-init="test1 = (data | orderBy:'name')"></div>
18867
+ * </pre>
18868
+ * </div>
18587
18869
  *
18588
18870
  * @priority 450
18589
18871
  *
@@ -18606,15 +18888,15 @@ var ngIncludeFillContentDirective = ['$compile',
18606
18888
  </div>
18607
18889
  </div>
18608
18890
  </doc:source>
18609
- <doc:scenario>
18891
+ <doc:protractor>
18610
18892
  it('should alias index positions', function() {
18611
- expect(element('.example-init').text())
18612
- .toBe('list[ 0 ][ 0 ] = a;' +
18613
- 'list[ 0 ][ 1 ] = b;' +
18614
- 'list[ 1 ][ 0 ] = c;' +
18615
- 'list[ 1 ][ 1 ] = d;');
18893
+ var elements = element.all(by.css('.example-init'));
18894
+ expect(elements.get(0).getText()).toBe('list[ 0 ][ 0 ] = a;');
18895
+ expect(elements.get(1).getText()).toBe('list[ 0 ][ 1 ] = b;');
18896
+ expect(elements.get(2).getText()).toBe('list[ 1 ][ 0 ] = c;');
18897
+ expect(elements.get(3).getText()).toBe('list[ 1 ][ 1 ] = d;');
18616
18898
  });
18617
- </doc:scenario>
18899
+ </doc:protractor>
18618
18900
  </doc:example>
18619
18901
  */
18620
18902
  var ngInitDirective = ngDirective({
@@ -18652,13 +18934,12 @@ var ngInitDirective = ngDirective({
18652
18934
  <div>Normal: {{1 + 2}}</div>
18653
18935
  <div ng-non-bindable>Ignored: {{1 + 2}}</div>
18654
18936
  </doc:source>
18655
- <doc:scenario>
18937
+ <doc:protractor>
18656
18938
  it('should check ng-non-bindable', function() {
18657
- expect(using('.doc-example-live').binding('1 + 2')).toBe('3');
18658
- expect(using('.doc-example-live').element('div:last').text()).
18659
- toMatch(/1 \+ 2/);
18939
+ expect(element(by.binding('1 + 2')).getText()).toContain('3');
18940
+ expect(element.all(by.css('.doc-example-live div')).last().getText()).toMatch(/1 \+ 2/);
18660
18941
  });
18661
- </doc:scenario>
18942
+ </doc:protractor>
18662
18943
  </doc:example>
18663
18944
  */
18664
18945
  var ngNonBindableDirective = ngDirective({ terminal: true, priority: 1000 });
@@ -18786,49 +19067,53 @@ var ngNonBindableDirective = ngDirective({ terminal: true, priority: 1000 });
18786
19067
  </ng-pluralize>
18787
19068
  </div>
18788
19069
  </doc:source>
18789
- <doc:scenario>
19070
+ <doc:protractor>
18790
19071
  it('should show correct pluralized string', function() {
18791
- expect(element('.doc-example-live ng-pluralize:first').text()).
18792
- toBe('1 person is viewing.');
18793
- expect(element('.doc-example-live ng-pluralize:last').text()).
18794
- toBe('Igor is viewing.');
18795
-
18796
- using('.doc-example-live').input('personCount').enter('0');
18797
- expect(element('.doc-example-live ng-pluralize:first').text()).
18798
- toBe('Nobody is viewing.');
18799
- expect(element('.doc-example-live ng-pluralize:last').text()).
18800
- toBe('Nobody is viewing.');
18801
-
18802
- using('.doc-example-live').input('personCount').enter('2');
18803
- expect(element('.doc-example-live ng-pluralize:first').text()).
18804
- toBe('2 people are viewing.');
18805
- expect(element('.doc-example-live ng-pluralize:last').text()).
18806
- toBe('Igor and Misko are viewing.');
18807
-
18808
- using('.doc-example-live').input('personCount').enter('3');
18809
- expect(element('.doc-example-live ng-pluralize:first').text()).
18810
- toBe('3 people are viewing.');
18811
- expect(element('.doc-example-live ng-pluralize:last').text()).
18812
- toBe('Igor, Misko and one other person are viewing.');
18813
-
18814
- using('.doc-example-live').input('personCount').enter('4');
18815
- expect(element('.doc-example-live ng-pluralize:first').text()).
18816
- toBe('4 people are viewing.');
18817
- expect(element('.doc-example-live ng-pluralize:last').text()).
18818
- toBe('Igor, Misko and 2 other people are viewing.');
18819
- });
19072
+ var withoutOffset = element.all(by.css('ng-pluralize')).get(0);
19073
+ var withOffset = element.all(by.css('ng-pluralize')).get(1);
19074
+ var countInput = element(by.model('personCount'));
19075
+
19076
+ expect(withoutOffset.getText()).toEqual('1 person is viewing.');
19077
+ expect(withOffset.getText()).toEqual('Igor is viewing.');
19078
+
19079
+ countInput.clear();
19080
+ countInput.sendKeys('0');
19081
+
19082
+ expect(withoutOffset.getText()).toEqual('Nobody is viewing.');
19083
+ expect(withOffset.getText()).toEqual('Nobody is viewing.');
18820
19084
 
18821
- it('should show data-binded names', function() {
18822
- using('.doc-example-live').input('personCount').enter('4');
18823
- expect(element('.doc-example-live ng-pluralize:last').text()).
18824
- toBe('Igor, Misko and 2 other people are viewing.');
19085
+ countInput.clear();
19086
+ countInput.sendKeys('2');
18825
19087
 
18826
- using('.doc-example-live').input('person1').enter('Di');
18827
- using('.doc-example-live').input('person2').enter('Vojta');
18828
- expect(element('.doc-example-live ng-pluralize:last').text()).
18829
- toBe('Di, Vojta and 2 other people are viewing.');
19088
+ expect(withoutOffset.getText()).toEqual('2 people are viewing.');
19089
+ expect(withOffset.getText()).toEqual('Igor and Misko are viewing.');
19090
+
19091
+ countInput.clear();
19092
+ countInput.sendKeys('3');
19093
+
19094
+ expect(withoutOffset.getText()).toEqual('3 people are viewing.');
19095
+ expect(withOffset.getText()).toEqual('Igor, Misko and one other person are viewing.');
19096
+
19097
+ countInput.clear();
19098
+ countInput.sendKeys('4');
19099
+
19100
+ expect(withoutOffset.getText()).toEqual('4 people are viewing.');
19101
+ expect(withOffset.getText()).toEqual('Igor, Misko and 2 other people are viewing.');
19102
+ });
19103
+ it('should show data-bound names', function() {
19104
+ var withOffset = element.all(by.css('ng-pluralize')).get(1);
19105
+ var personCount = element(by.model('personCount'));
19106
+ var person1 = element(by.model('person1'));
19107
+ var person2 = element(by.model('person2'));
19108
+ personCount.clear();
19109
+ personCount.sendKeys('4');
19110
+ person1.clear();
19111
+ person1.sendKeys('Di');
19112
+ person2.clear();
19113
+ person2.sendKeys('Vojta');
19114
+ expect(withOffset.getText()).toEqual('Di, Vojta and 2 other people are viewing.');
18830
19115
  });
18831
- </doc:scenario>
19116
+ </doc:protractor>
18832
19117
  </doc:example>
18833
19118
  */
18834
19119
  var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interpolate) {
@@ -19047,25 +19332,27 @@ var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interp
19047
19332
  max-height:40px;
19048
19333
  }
19049
19334
  </file>
19050
- <file name="scenario.js">
19051
- it('should render initial data set', function() {
19052
- var r = using('.doc-example-live').repeater('ul li');
19053
- expect(r.count()).toBe(10);
19054
- expect(r.row(0)).toEqual(["1","John","25"]);
19055
- expect(r.row(1)).toEqual(["2","Jessie","30"]);
19056
- expect(r.row(9)).toEqual(["10","Samantha","60"]);
19057
- expect(binding('friends.length')).toBe("10");
19058
- });
19335
+ <file name="protractorTest.js">
19336
+ var friends = element(by.css('.doc-example-live'))
19337
+ .element.all(by.repeater('friend in friends'));
19338
+
19339
+ it('should render initial data set', function() {
19340
+ expect(friends.count()).toBe(10);
19341
+ expect(friends.get(0).getText()).toEqual('[1] John who is 25 years old.');
19342
+ expect(friends.get(1).getText()).toEqual('[2] Jessie who is 30 years old.');
19343
+ expect(friends.last().getText()).toEqual('[10] Samantha who is 60 years old.');
19344
+ expect(element(by.binding('friends.length')).getText())
19345
+ .toMatch("I have 10 friends. They are:");
19346
+ });
19059
19347
 
19060
19348
  it('should update repeater when filter predicate changes', function() {
19061
- var r = using('.doc-example-live').repeater('ul li');
19062
- expect(r.count()).toBe(10);
19349
+ expect(friends.count()).toBe(10);
19063
19350
 
19064
- input('q').enter('ma');
19351
+ element(by.css('.doc-example-live')).element(by.model('q')).sendKeys('ma');
19065
19352
 
19066
- expect(r.count()).toBe(2);
19067
- expect(r.row(0)).toEqual(["1","Mary","28"]);
19068
- expect(r.row(1)).toEqual(["2","Samantha","60"]);
19353
+ expect(friends.count()).toBe(2);
19354
+ expect(friends.get(0).getText()).toEqual('[1] Mary who is 28 years old.');
19355
+ expect(friends.last().getText()).toEqual('[2] Samantha who is 60 years old.');
19069
19356
  });
19070
19357
  </file>
19071
19358
  </example>
@@ -19319,6 +19606,11 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
19319
19606
  *
19320
19607
  * Just remember to include the important flag so the CSS override will function.
19321
19608
  *
19609
+ * <div class="alert alert-warning">
19610
+ * **Note:** Here is a list of values that ngShow will consider as a falsy value (case insensitive):<br />
19611
+ * "f" / "0" / "false" / "no" / "n" / "[]"
19612
+ * </div>
19613
+ *
19322
19614
  * ## A note about animations with ngShow
19323
19615
  *
19324
19616
  * Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression
@@ -19394,16 +19686,19 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
19394
19686
  background:white;
19395
19687
  }
19396
19688
  </file>
19397
- <file name="scenario.js">
19398
- it('should check ng-show / ng-hide', function() {
19399
- expect(element('.doc-example-live span:first:hidden').count()).toEqual(1);
19400
- expect(element('.doc-example-live span:last:visible').count()).toEqual(1);
19689
+ <file name="protractorTest.js">
19690
+ var thumbsUp = element(by.css('.doc-example-live span.icon-thumbs-up'));
19691
+ var thumbsDown = element(by.css('.doc-example-live span.icon-thumbs-down'));
19401
19692
 
19402
- input('checked').check();
19693
+ it('should check ng-show / ng-hide', function() {
19694
+ expect(thumbsUp.isDisplayed()).toBeFalsy();
19695
+ expect(thumbsDown.isDisplayed()).toBeTruthy();
19403
19696
 
19404
- expect(element('.doc-example-live span:first:visible').count()).toEqual(1);
19405
- expect(element('.doc-example-live span:last:hidden').count()).toEqual(1);
19406
- });
19697
+ element(by.model('checked')).click();
19698
+
19699
+ expect(thumbsUp.isDisplayed()).toBeTruthy();
19700
+ expect(thumbsDown.isDisplayed()).toBeFalsy();
19701
+ });
19407
19702
  </file>
19408
19703
  </example>
19409
19704
  */
@@ -19467,6 +19762,11 @@ var ngShowDirective = ['$animate', function($animate) {
19467
19762
  * </pre>
19468
19763
  *
19469
19764
  * Just remember to include the important flag so the CSS override will function.
19765
+ *
19766
+ * <div class="alert alert-warning">
19767
+ * **Note:** Here is a list of values that ngHide will consider as a falsy value (case insensitive):<br />
19768
+ * "f" / "0" / "false" / "no" / "n" / "[]"
19769
+ * </div>
19470
19770
  *
19471
19771
  * ## A note about animations with ngHide
19472
19772
  *
@@ -19543,16 +19843,19 @@ var ngShowDirective = ['$animate', function($animate) {
19543
19843
  background:white;
19544
19844
  }
19545
19845
  </file>
19546
- <file name="scenario.js">
19547
- it('should check ng-show / ng-hide', function() {
19548
- expect(element('.doc-example-live .check-element:first:hidden').count()).toEqual(1);
19549
- expect(element('.doc-example-live .check-element:last:visible').count()).toEqual(1);
19846
+ <file name="protractorTest.js">
19847
+ var thumbsUp = element(by.css('.doc-example-live span.icon-thumbs-up'));
19848
+ var thumbsDown = element(by.css('.doc-example-live span.icon-thumbs-down'));
19550
19849
 
19551
- input('checked').check();
19850
+ it('should check ng-show / ng-hide', function() {
19851
+ expect(thumbsUp.isDisplayed()).toBeFalsy();
19852
+ expect(thumbsDown.isDisplayed()).toBeTruthy();
19552
19853
 
19553
- expect(element('.doc-example-live .check-element:first:visible').count()).toEqual(1);
19554
- expect(element('.doc-example-live .check-element:last:hidden').count()).toEqual(1);
19555
- });
19854
+ element(by.model('checked')).click();
19855
+
19856
+ expect(thumbsUp.isDisplayed()).toBeTruthy();
19857
+ expect(thumbsDown.isDisplayed()).toBeFalsy();
19858
+ });
19556
19859
  </file>
19557
19860
  </example>
19558
19861
  */
@@ -19591,13 +19894,15 @@ var ngHideDirective = ['$animate', function($animate) {
19591
19894
  color: black;
19592
19895
  }
19593
19896
  </file>
19594
- <file name="scenario.js">
19897
+ <file name="protractorTest.js">
19898
+ var colorSpan = element(by.css('.doc-example-live span'));
19899
+
19595
19900
  it('should check ng-style', function() {
19596
- expect(element('.doc-example-live span').css('color')).toBe('rgb(0, 0, 0)');
19597
- element('.doc-example-live :button[value=set]').click();
19598
- expect(element('.doc-example-live span').css('color')).toBe('rgb(255, 0, 0)');
19599
- element('.doc-example-live :button[value=clear]').click();
19600
- expect(element('.doc-example-live span').css('color')).toBe('rgb(0, 0, 0)');
19901
+ expect(colorSpan.getCssValue('color')).toBe('rgba(0, 0, 0, 1)');
19902
+ element(by.css('.doc-example-live input[value=set]')).click();
19903
+ expect(colorSpan.getCssValue('color')).toBe('rgba(255, 0, 0, 1)');
19904
+ element(by.css('.doc-example-live input[value=clear]')).click();
19905
+ expect(colorSpan.getCssValue('color')).toBe('rgba(0, 0, 0, 1)');
19601
19906
  });
19602
19907
  </file>
19603
19908
  </example>
@@ -19622,7 +19927,7 @@ var ngStyleDirective = ngDirective(function(scope, element, attr) {
19622
19927
  * as specified in the template.
19623
19928
  *
19624
19929
  * The directive itself works similar to ngInclude, however, instead of downloading template code (or loading it
19625
- * from the template cache), `ngSwitch` simply choses one of the nested elements and makes it visible based on which element
19930
+ * from the template cache), `ngSwitch` simply chooses one of the nested elements and makes it visible based on which element
19626
19931
  * matches the value obtained from the evaluated expression. In other words, you define a container element
19627
19932
  * (where you place the directive), place an expression on the **`on="..."` attribute**
19628
19933
  * (or the **`ng-switch="..."` attribute**), define any inner elements inside of the directive and place
@@ -19718,17 +20023,20 @@ var ngStyleDirective = ngDirective(function(scope, element, attr) {
19718
20023
  top:0;
19719
20024
  }
19720
20025
  </file>
19721
- <file name="scenario.js">
20026
+ <file name="protractorTest.js">
20027
+ var switchElem = element(by.css('.doc-example-live [ng-switch]'));
20028
+ var select = element(by.model('selection'));
20029
+
19722
20030
  it('should start in settings', function() {
19723
- expect(element('.doc-example-live [ng-switch]').text()).toMatch(/Settings Div/);
20031
+ expect(switchElem.getText()).toMatch(/Settings Div/);
19724
20032
  });
19725
20033
  it('should change to home', function() {
19726
- select('selection').option('home');
19727
- expect(element('.doc-example-live [ng-switch]').text()).toMatch(/Home Span/);
20034
+ select.element.all(by.css('option')).get(1).click();
20035
+ expect(switchElem.getText()).toMatch(/Home Span/);
19728
20036
  });
19729
20037
  it('should select default', function() {
19730
- select('selection').option('other');
19731
- expect(element('.doc-example-live [ng-switch]').text()).toMatch(/default/);
20038
+ select.element.all(by.css('option')).get(2).click();
20039
+ expect(switchElem.getText()).toMatch(/default/);
19732
20040
  });
19733
20041
  </file>
19734
20042
  </example>
@@ -19835,35 +20143,32 @@ var ngSwitchDefaultDirective = ngDirective({
19835
20143
  <pane title="{{title}}">{{text}}</pane>
19836
20144
  </div>
19837
20145
  </doc:source>
19838
- <doc:scenario>
20146
+ <doc:protractor>
19839
20147
  it('should have transcluded', function() {
19840
- input('title').enter('TITLE');
19841
- input('text').enter('TEXT');
19842
- expect(binding('title')).toEqual('TITLE');
19843
- expect(binding('text')).toEqual('TEXT');
20148
+ var titleElement = element(by.model('title'));
20149
+ titleElement.clear();
20150
+ titleElement.sendKeys('TITLE');
20151
+ var textElement = element(by.model('text'));
20152
+ textElement.clear();
20153
+ textElement.sendKeys('TEXT');
20154
+ expect(element(by.binding('title')).getText()).toEqual('TITLE');
20155
+ expect(element(by.binding('text')).getText()).toEqual('TEXT');
19844
20156
  });
19845
- </doc:scenario>
20157
+ </doc:protractor>
19846
20158
  </doc:example>
19847
20159
  *
19848
20160
  */
19849
20161
  var ngTranscludeDirective = ngDirective({
19850
- controller: ['$element', '$transclude', function($element, $transclude) {
20162
+ link: function($scope, $element, $attrs, controller, $transclude) {
19851
20163
  if (!$transclude) {
19852
20164
  throw minErr('ngTransclude')('orphan',
19853
- 'Illegal use of ngTransclude directive in the template! ' +
19854
- 'No parent directive that requires a transclusion found. ' +
19855
- 'Element: {0}',
19856
- startingTag($element));
20165
+ 'Illegal use of ngTransclude directive in the template! ' +
20166
+ 'No parent directive that requires a transclusion found. ' +
20167
+ 'Element: {0}',
20168
+ startingTag($element));
19857
20169
  }
19858
-
19859
- // remember the transclusion fn but call it during linking so that we don't process transclusion before directives on
19860
- // the parent element even when the transclusion replaces the current element. (we can't use priority here because
19861
- // that applies only to compile fns and not controllers
19862
- this.$transclude = $transclude;
19863
- }],
19864
-
19865
- link: function($scope, $element, $attrs, controller) {
19866
- controller.$transclude(function(clone) {
20170
+
20171
+ $transclude(function(clone) {
19867
20172
  $element.empty();
19868
20173
  $element.append(clone);
19869
20174
  });
@@ -19895,12 +20200,12 @@ var ngTranscludeDirective = ngDirective({
19895
20200
  <a ng-click="currentTpl='/tpl.html'" id="tpl-link">Load inlined template</a>
19896
20201
  <div id="tpl-content" ng-include src="currentTpl"></div>
19897
20202
  </doc:source>
19898
- <doc:scenario>
20203
+ <doc:protractor>
19899
20204
  it('should load template defined inside script tag', function() {
19900
- element('#tpl-link').click();
19901
- expect(element('#tpl-content').text()).toMatch(/Content of the template/);
20205
+ element(by.css('#tpl-link')).click();
20206
+ expect(element(by.css('#tpl-content')).getText()).toMatch(/Content of the template/);
19902
20207
  });
19903
- </doc:scenario>
20208
+ </doc:protractor>
19904
20209
  </doc:example>
19905
20210
  */
19906
20211
  var scriptDirective = ['$templateCache', function($templateCache) {
@@ -19938,14 +20243,21 @@ var ngOptionsMinErr = minErr('ngOptions');
19938
20243
  * represented by the selected option will be bound to the model identified by the `ngModel`
19939
20244
  * directive.
19940
20245
  *
20246
+ * <div class="alert alert-warning">
20247
+ * **Note:** `ngModel` compares by reference, not value. This is important when binding to an
20248
+ * array of objects. See an example {@link http://jsfiddle.net/qWzTb/ in this jsfiddle}.
20249
+ * </div>
20250
+ *
19941
20251
  * Optionally, a single hard-coded `<option>` element, with the value set to an empty string, can
19942
20252
  * be nested into the `<select>` element. This element will then represent the `null` or "not selected"
19943
20253
  * option. See example below for demonstration.
19944
20254
  *
19945
- * Note: `ngOptions` provides iterator facility for `<option>` element which should be used instead
20255
+ * <div class="alert alert-warning">
20256
+ * **Note:** `ngOptions` provides an iterator facility for the `<option>` element which should be used instead
19946
20257
  * of {@link ng.directive:ngRepeat ngRepeat} when you want the
19947
20258
  * `select` model to be bound to a non-string value. This is because an option element can only
19948
20259
  * be bound to string values at present.
20260
+ * </div>
19949
20261
  *
19950
20262
  * @param {string} ngModel Assignable angular expression to data-bind to.
19951
20263
  * @param {string=} name Property name of the form under which the control is published.
@@ -20032,15 +20344,17 @@ var ngOptionsMinErr = minErr('ngOptions');
20032
20344
  </div>
20033
20345
  </div>
20034
20346
  </doc:source>
20035
- <doc:scenario>
20347
+ <doc:protractor>
20036
20348
  it('should check ng-options', function() {
20037
- expect(binding('{selected_color:color}')).toMatch('red');
20038
- select('color').option('0');
20039
- expect(binding('{selected_color:color}')).toMatch('black');
20040
- using('.nullable').select('color').option('');
20041
- expect(binding('{selected_color:color}')).toMatch('null');
20349
+ expect(element(by.binding('{selected_color:color}')).getText()).toMatch('red');
20350
+ element.all(by.select('color')).first().click();
20351
+ element.all(by.css('select[ng-model="color"] option')).first().click();
20352
+ expect(element(by.binding('{selected_color:color}')).getText()).toMatch('black');
20353
+ element(by.css('.nullable select[ng-model="color"]')).click();
20354
+ element.all(by.css('.nullable select[ng-model="color"] option')).first().click();
20355
+ expect(element(by.binding('{selected_color:color}')).getText()).toMatch('null');
20042
20356
  });
20043
- </doc:scenario>
20357
+ </doc:protractor>
20044
20358
  </doc:example>
20045
20359
  */
20046
20360
 
@@ -20349,7 +20663,7 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
20349
20663
 
20350
20664
  // We now build up the list of options we need (we merge later)
20351
20665
  for (index = 0; length = keys.length, index < length; index++) {
20352
-
20666
+
20353
20667
  key = index;
20354
20668
  if (keyName) {
20355
20669
  key = keys[index];
@@ -20557,4 +20871,4 @@ var styleDirective = valueFn({
20557
20871
 
20558
20872
  })(window, document);
20559
20873
 
20560
- !angular.$$csp() && angular.element(document).find('head').prepend('<style type="text/css">@charset "UTF-8";[ng\\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak,.ng-hide{display:none !important;}ng\\:form{display:block;}</style>');
20874
+ !angular.$$csp() && angular.element(document).find('head').prepend('<style type="text/css">@charset "UTF-8";[ng\\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak,.ng-hide{display:none !important;}ng\\:form{display:block;}.ng-animate-block-transitions{transition:0s all!important;-webkit-transition:0s all!important;}</style>');