angular-gem 1.2.12 → 1.2.13

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license AngularJS v1.2.9
2
+ * @license AngularJS v1.2.13
3
3
  * (c) 2010-2014 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license AngularJS v1.2.9
2
+ * @license AngularJS v1.2.13
3
3
  * (c) 2010-2014 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
@@ -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>');