angularjs-rails 1.5.8 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license AngularJS v1.5.8
2
+ * @license AngularJS v1.6.0
3
3
  * (c) 2010-2016 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
@@ -69,7 +69,7 @@ var jqLite;
69
69
  * By default, `ngMessages` will only display one message for a particular key/value collection at any time. If more
70
70
  * than one message (or error) key is currently true, then which message is shown is determined by the order of messages
71
71
  * in the HTML template code (messages declared first are prioritised). This mechanism means the developer does not have
72
- * to prioritise messages using custom JavaScript code.
72
+ * to prioritize messages using custom JavaScript code.
73
73
  *
74
74
  * Given the following error object for our example (which informs us that the field `myField` currently has both the
75
75
  * `required` and `email` errors):
@@ -352,7 +352,7 @@ angular.module('ngMessages', [], function initAngularHelpers() {
352
352
  return {
353
353
  require: 'ngMessages',
354
354
  restrict: 'AE',
355
- controller: ['$element', '$scope', '$attrs', function($element, $scope, $attrs) {
355
+ controller: ['$element', '$scope', '$attrs', function NgMessagesCtrl($element, $scope, $attrs) {
356
356
  var ctrl = this;
357
357
  var latestKey = 0;
358
358
  var nextAttachId = 0;
@@ -412,9 +412,11 @@ angular.module('ngMessages', [], function initAngularHelpers() {
412
412
  messageCtrl.detach();
413
413
  });
414
414
 
415
- unmatchedMessages.length !== totalMessages
416
- ? $animate.setClass($element, ACTIVE_CLASS, INACTIVE_CLASS)
417
- : $animate.setClass($element, INACTIVE_CLASS, ACTIVE_CLASS);
415
+ if (unmatchedMessages.length !== totalMessages) {
416
+ $animate.setClass($element, ACTIVE_CLASS, INACTIVE_CLASS);
417
+ } else {
418
+ $animate.setClass($element, INACTIVE_CLASS, ACTIVE_CLASS);
419
+ }
418
420
  };
419
421
 
420
422
  $scope.$watchCollection($attrs.ngMessages || $attrs['for'], ctrl.render);
@@ -430,8 +432,8 @@ angular.module('ngMessages', [], function initAngularHelpers() {
430
432
  if (!renderLater) {
431
433
  renderLater = true;
432
434
  $scope.$evalAsync(function() {
433
- if (renderLater) {
434
- cachedCollection && ctrl.render(cachedCollection);
435
+ if (renderLater && cachedCollection) {
436
+ ctrl.render(cachedCollection);
435
437
  }
436
438
  });
437
439
  }
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license AngularJS v1.5.8
2
+ * @license AngularJS v1.6.0
3
3
  * (c) 2010-2016 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
@@ -40,7 +40,7 @@ angular.mock.$Browser = function() {
40
40
  var self = this;
41
41
 
42
42
  this.isMock = true;
43
- self.$$url = "http://server/";
43
+ self.$$url = 'http://server/';
44
44
  self.$$lastUrl = self.$$url; // used by url polling fn
45
45
  self.pollFns = [];
46
46
 
@@ -252,19 +252,19 @@ angular.mock.$ExceptionHandlerProvider = function() {
252
252
  case 'rethrow':
253
253
  var errors = [];
254
254
  handler = function(e) {
255
- if (arguments.length == 1) {
255
+ if (arguments.length === 1) {
256
256
  errors.push(e);
257
257
  } else {
258
258
  errors.push([].slice.call(arguments, 0));
259
259
  }
260
- if (mode === "rethrow") {
260
+ if (mode === 'rethrow') {
261
261
  throw e;
262
262
  }
263
263
  };
264
264
  handler.errors = errors;
265
265
  break;
266
266
  default:
267
- throw new Error("Unknown mode '" + mode + "', only 'log'/'rethrow' modes are allowed!");
267
+ throw new Error('Unknown mode \'' + mode + '\', only \'log\'/\'rethrow\' modes are allowed!');
268
268
  }
269
269
  };
270
270
 
@@ -414,8 +414,8 @@ angular.mock.$LogProvider = function() {
414
414
  });
415
415
  });
416
416
  if (errors.length) {
417
- errors.unshift("Expected $log to be empty! Either a message was logged unexpectedly, or " +
418
- "an expected log message was not checked and removed:");
417
+ errors.unshift('Expected $log to be empty! Either a message was logged unexpectedly, or ' +
418
+ 'an expected log message was not checked and removed:');
419
419
  errors.push('');
420
420
  throw new Error(errors.join('\n---------\n'));
421
421
  }
@@ -463,7 +463,7 @@ angular.mock.$IntervalProvider = function() {
463
463
  promise = deferred.promise;
464
464
 
465
465
  count = (angular.isDefined(count)) ? count : 0;
466
- promise.then(null, null, (!hasParams) ? fn : function() {
466
+ promise.then(null, function() {}, (!hasParams) ? fn : function() {
467
467
  fn.apply(null, args);
468
468
  });
469
469
 
@@ -523,6 +523,7 @@ angular.mock.$IntervalProvider = function() {
523
523
  });
524
524
 
525
525
  if (angular.isDefined(fnIndex)) {
526
+ repeatFns[fnIndex].deferred.promise.then(undefined, function() {});
526
527
  repeatFns[fnIndex].deferred.reject('canceled');
527
528
  repeatFns.splice(fnIndex, 1);
528
529
  return true;
@@ -558,16 +559,13 @@ angular.mock.$IntervalProvider = function() {
558
559
  };
559
560
 
560
561
 
561
- /* jshint -W101 */
562
- /* The R_ISO8061_STR regex is never going to fit into the 100 char limit!
563
- * This directive should go inside the anonymous function but a bug in JSHint means that it would
564
- * not be enacted early enough to prevent the warning.
565
- */
566
- var R_ISO8061_STR = /^(-?\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?:\:?(\d\d)(?:\:?(\d\d)(?:\.(\d{3}))?)?)?(Z|([+-])(\d\d):?(\d\d)))?$/;
567
-
568
562
  function jsonStringToDate(string) {
563
+ // The R_ISO8061_STR regex is never going to fit into the 100 char limit!
564
+ // eslit-disable-next-line max-len
565
+ var R_ISO8061_STR = /^(-?\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d{3}))?)?)?(Z|([+-])(\d\d):?(\d\d)))?$/;
566
+
569
567
  var match;
570
- if (match = string.match(R_ISO8061_STR)) {
568
+ if ((match = string.match(R_ISO8061_STR))) {
571
569
  var date = new Date(0),
572
570
  tzHour = 0,
573
571
  tzMin = 0;
@@ -650,9 +648,10 @@ angular.mock.TzDate = function(offset, timestamp) {
650
648
 
651
649
  timestamp = self.origDate.getTime();
652
650
  if (isNaN(timestamp)) {
651
+ // eslint-disable-next-line no-throw-literal
653
652
  throw {
654
- name: "Illegal Argument",
655
- message: "Arg '" + tsStr + "' passed into TzDate constructor is not a valid date string"
653
+ name: 'Illegal Argument',
654
+ message: 'Arg \'' + tsStr + '\' passed into TzDate constructor is not a valid date string'
656
655
  };
657
656
  }
658
657
  } else {
@@ -758,7 +757,7 @@ angular.mock.TzDate = function(offset, timestamp) {
758
757
 
759
758
  angular.forEach(unimplementedMethods, function(methodName) {
760
759
  self[methodName] = function() {
761
- throw new Error("Method '" + methodName + "' is not implemented in the TzDate mock");
760
+ throw new Error('Method \'' + methodName + '\' is not implemented in the TzDate mock');
762
761
  };
763
762
  });
764
763
 
@@ -767,7 +766,6 @@ angular.mock.TzDate = function(offset, timestamp) {
767
766
 
768
767
  //make "tzDateInstance instanceof Date" return true
769
768
  angular.mock.TzDate.prototype = Date.prototype;
770
- /* jshint +W101 */
771
769
 
772
770
 
773
771
  /**
@@ -1215,7 +1213,7 @@ angular.mock.dump = function(object) {
1215
1213
  $httpBackend.expectPOST('/add-msg.py', undefined, function(headers) {
1216
1214
  // check if the header was sent, if it wasn't the expectation won't
1217
1215
  // match the request and the test will fail
1218
- return headers['Authorization'] == 'xxx';
1216
+ return headers['Authorization'] === 'xxx';
1219
1217
  }).respond(201, '');
1220
1218
 
1221
1219
  $rootScope.saveMessage('whatever');
@@ -1357,7 +1355,11 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
1357
1355
 
1358
1356
  function wrapResponse(wrapped) {
1359
1357
  if (!$browser && timeout) {
1360
- timeout.then ? timeout.then(handleTimeout) : $timeout(handleTimeout, timeout);
1358
+ if (timeout.then) {
1359
+ timeout.then(handleTimeout);
1360
+ } else {
1361
+ $timeout(handleTimeout, timeout);
1362
+ }
1361
1363
  }
1362
1364
 
1363
1365
  return handleResponse;
@@ -1426,7 +1428,7 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
1426
1428
  * Creates a new backend definition.
1427
1429
  *
1428
1430
  * @param {string} method HTTP method.
1429
- * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1431
+ * @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
1430
1432
  * and returns true if the url matches the current definition.
1431
1433
  * @param {(string|RegExp|function(string))=} data HTTP request body or function that receives
1432
1434
  * data string and returns true if the data is as expected.
@@ -1448,6 +1450,9 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
1448
1450
  * the `requestHandler` object for possible overrides.
1449
1451
  */
1450
1452
  $httpBackend.when = function(method, url, data, headers, keys) {
1453
+
1454
+ assertArgDefined(arguments, 1, 'url');
1455
+
1451
1456
  var definition = new MockHttpExpectation(method, url, data, headers, keys),
1452
1457
  chain = {
1453
1458
  respond: function(status, data, headers, statusText) {
@@ -1475,7 +1480,7 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
1475
1480
  * @description
1476
1481
  * Creates a new backend definition for GET requests. For more info see `when()`.
1477
1482
  *
1478
- * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1483
+ * @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
1479
1484
  * and returns true if the url matches the current definition.
1480
1485
  * @param {(Object|function(Object))=} headers HTTP headers.
1481
1486
  * @param {(Array)=} keys Array of keys to assign to regex matches in request url described above.
@@ -1490,7 +1495,7 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
1490
1495
  * @description
1491
1496
  * Creates a new backend definition for HEAD requests. For more info see `when()`.
1492
1497
  *
1493
- * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1498
+ * @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
1494
1499
  * and returns true if the url matches the current definition.
1495
1500
  * @param {(Object|function(Object))=} headers HTTP headers.
1496
1501
  * @param {(Array)=} keys Array of keys to assign to regex matches in request url described above.
@@ -1505,7 +1510,7 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
1505
1510
  * @description
1506
1511
  * Creates a new backend definition for DELETE requests. For more info see `when()`.
1507
1512
  *
1508
- * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1513
+ * @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
1509
1514
  * and returns true if the url matches the current definition.
1510
1515
  * @param {(Object|function(Object))=} headers HTTP headers.
1511
1516
  * @param {(Array)=} keys Array of keys to assign to regex matches in request url described above.
@@ -1520,7 +1525,7 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
1520
1525
  * @description
1521
1526
  * Creates a new backend definition for POST requests. For more info see `when()`.
1522
1527
  *
1523
- * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1528
+ * @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
1524
1529
  * and returns true if the url matches the current definition.
1525
1530
  * @param {(string|RegExp|function(string))=} data HTTP request body or function that receives
1526
1531
  * data string and returns true if the data is as expected.
@@ -1537,7 +1542,7 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
1537
1542
  * @description
1538
1543
  * Creates a new backend definition for PUT requests. For more info see `when()`.
1539
1544
  *
1540
- * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1545
+ * @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
1541
1546
  * and returns true if the url matches the current definition.
1542
1547
  * @param {(string|RegExp|function(string))=} data HTTP request body or function that receives
1543
1548
  * data string and returns true if the data is as expected.
@@ -1554,7 +1559,7 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
1554
1559
  * @description
1555
1560
  * Creates a new backend definition for JSONP requests. For more info see `when()`.
1556
1561
  *
1557
- * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1562
+ * @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
1558
1563
  * and returns true if the url matches the current definition.
1559
1564
  * @param {(Array)=} keys Array of keys to assign to regex matches in request url described above.
1560
1565
  * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
@@ -1590,7 +1595,7 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
1590
1595
 
1591
1596
  url = url
1592
1597
  .replace(/([().])/g, '\\$1')
1593
- .replace(/(\/)?:(\w+)([\?\*])?/g, function(_, slash, key, option) {
1598
+ .replace(/(\/)?:(\w+)([?*])?/g, function(_, slash, key, option) {
1594
1599
  var optional = option === '?' ? option : null;
1595
1600
  var star = option === '*' ? option : null;
1596
1601
  keys.push({ name: key, optional: !!optional });
@@ -1604,7 +1609,7 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
1604
1609
  + ')'
1605
1610
  + (optional || '');
1606
1611
  })
1607
- .replace(/([\/$\*])/g, '\\$1');
1612
+ .replace(/([/$*])/g, '\\$1');
1608
1613
 
1609
1614
  ret.regexp = new RegExp('^' + url, 'i');
1610
1615
  return ret;
@@ -1617,7 +1622,7 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
1617
1622
  * Creates a new request expectation.
1618
1623
  *
1619
1624
  * @param {string} method HTTP method.
1620
- * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1625
+ * @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
1621
1626
  * and returns true if the url matches the current definition.
1622
1627
  * @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that
1623
1628
  * receives data string and returns true if the data is as expected, or Object if request body
@@ -1640,6 +1645,9 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
1640
1645
  * the `requestHandler` object for possible overrides.
1641
1646
  */
1642
1647
  $httpBackend.expect = function(method, url, data, headers, keys) {
1648
+
1649
+ assertArgDefined(arguments, 1, 'url');
1650
+
1643
1651
  var expectation = new MockHttpExpectation(method, url, data, headers, keys),
1644
1652
  chain = {
1645
1653
  respond: function(status, data, headers, statusText) {
@@ -1658,7 +1666,7 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
1658
1666
  * @description
1659
1667
  * Creates a new request expectation for GET requests. For more info see `expect()`.
1660
1668
  *
1661
- * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1669
+ * @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
1662
1670
  * and returns true if the url matches the current definition.
1663
1671
  * @param {Object=} headers HTTP headers.
1664
1672
  * @param {(Array)=} keys Array of keys to assign to regex matches in request url described above.
@@ -1673,7 +1681,7 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
1673
1681
  * @description
1674
1682
  * Creates a new request expectation for HEAD requests. For more info see `expect()`.
1675
1683
  *
1676
- * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1684
+ * @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
1677
1685
  * and returns true if the url matches the current definition.
1678
1686
  * @param {Object=} headers HTTP headers.
1679
1687
  * @param {(Array)=} keys Array of keys to assign to regex matches in request url described above.
@@ -1688,7 +1696,7 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
1688
1696
  * @description
1689
1697
  * Creates a new request expectation for DELETE requests. For more info see `expect()`.
1690
1698
  *
1691
- * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1699
+ * @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
1692
1700
  * and returns true if the url matches the current definition.
1693
1701
  * @param {Object=} headers HTTP headers.
1694
1702
  * @param {(Array)=} keys Array of keys to assign to regex matches in request url described above.
@@ -1703,7 +1711,7 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
1703
1711
  * @description
1704
1712
  * Creates a new request expectation for POST requests. For more info see `expect()`.
1705
1713
  *
1706
- * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1714
+ * @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
1707
1715
  * and returns true if the url matches the current definition.
1708
1716
  * @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that
1709
1717
  * receives data string and returns true if the data is as expected, or Object if request body
@@ -1721,7 +1729,7 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
1721
1729
  * @description
1722
1730
  * Creates a new request expectation for PUT requests. For more info see `expect()`.
1723
1731
  *
1724
- * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1732
+ * @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
1725
1733
  * and returns true if the url matches the current definition.
1726
1734
  * @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that
1727
1735
  * receives data string and returns true if the data is as expected, or Object if request body
@@ -1739,7 +1747,7 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
1739
1747
  * @description
1740
1748
  * Creates a new request expectation for PATCH requests. For more info see `expect()`.
1741
1749
  *
1742
- * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1750
+ * @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
1743
1751
  * and returns true if the url matches the current definition.
1744
1752
  * @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that
1745
1753
  * receives data string and returns true if the data is as expected, or Object if request body
@@ -1757,7 +1765,7 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
1757
1765
  * @description
1758
1766
  * Creates a new request expectation for JSONP requests. For more info see `expect()`.
1759
1767
  *
1760
- * @param {string|RegExp|function(string)} url HTTP url or function that receives an url
1768
+ * @param {string|RegExp|function(string)=} url HTTP url or function that receives an url
1761
1769
  * and returns true if the url matches the current definition.
1762
1770
  * @param {(Array)=} keys Array of keys to assign to regex matches in request url described above.
1763
1771
  * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
@@ -1788,24 +1796,34 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
1788
1796
  * @ngdoc method
1789
1797
  * @name $httpBackend#flush
1790
1798
  * @description
1791
- * Flushes all pending requests using the trained responses.
1792
- *
1793
- * @param {number=} count Number of responses to flush (in the order they arrived). If undefined,
1794
- * all pending requests will be flushed. If there are no pending requests when the flush method
1795
- * is called an exception is thrown (as this typically a sign of programming error).
1799
+ * Flushes pending requests using the trained responses. Requests are flushed in the order they
1800
+ * were made, but it is also possible to skip one or more requests (for example to have them
1801
+ * flushed later). This is useful for simulating scenarios where responses arrive from the server
1802
+ * in any order.
1803
+ *
1804
+ * If there are no pending requests to flush when the method is called, an exception is thrown (as
1805
+ * this is typically a sign of programming error).
1806
+ *
1807
+ * @param {number=} count - Number of responses to flush. If undefined/null, all pending requests
1808
+ * (starting after `skip`) will be flushed.
1809
+ * @param {number=} [skip=0] - Number of pending requests to skip. For example, a value of `5`
1810
+ * would skip the first 5 pending requests and start flushing from the 6th onwards.
1796
1811
  */
1797
- $httpBackend.flush = function(count, digest) {
1812
+ $httpBackend.flush = function(count, skip, digest) {
1798
1813
  if (digest !== false) $rootScope.$digest();
1799
- if (!responses.length) throw new Error('No pending request to flush !');
1814
+
1815
+ skip = skip || 0;
1816
+ if (skip >= responses.length) throw new Error('No pending request to flush !');
1800
1817
 
1801
1818
  if (angular.isDefined(count) && count !== null) {
1802
1819
  while (count--) {
1803
- if (!responses.length) throw new Error('No more pending request to flush !');
1804
- responses.shift()();
1820
+ var part = responses.splice(skip, 1);
1821
+ if (!part.length) throw new Error('No more pending request to flush !');
1822
+ part[0]();
1805
1823
  }
1806
1824
  } else {
1807
- while (responses.length) {
1808
- responses.shift()();
1825
+ while (responses.length > skip) {
1826
+ responses.splice(skip, 1)[0]();
1809
1827
  }
1810
1828
  }
1811
1829
  $httpBackend.verifyNoOutstandingExpectation(digest);
@@ -1847,7 +1865,8 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
1847
1865
  * afterEach($httpBackend.verifyNoOutstandingRequest);
1848
1866
  * ```
1849
1867
  */
1850
- $httpBackend.verifyNoOutstandingRequest = function() {
1868
+ $httpBackend.verifyNoOutstandingRequest = function(digest) {
1869
+ if (digest !== false) $rootScope.$digest();
1851
1870
  if (responses.length) {
1852
1871
  throw new Error('Unflushed requests: ' + responses.length);
1853
1872
  }
@@ -1873,18 +1892,35 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
1873
1892
  function createShortMethods(prefix) {
1874
1893
  angular.forEach(['GET', 'DELETE', 'JSONP', 'HEAD'], function(method) {
1875
1894
  $httpBackend[prefix + method] = function(url, headers, keys) {
1895
+ assertArgDefined(arguments, 0, 'url');
1896
+
1897
+ // Change url to `null` if `undefined` to stop it throwing an exception further down
1898
+ if (angular.isUndefined(url)) url = null;
1899
+
1876
1900
  return $httpBackend[prefix](method, url, undefined, headers, keys);
1877
1901
  };
1878
1902
  });
1879
1903
 
1880
1904
  angular.forEach(['PUT', 'POST', 'PATCH'], function(method) {
1881
1905
  $httpBackend[prefix + method] = function(url, data, headers, keys) {
1906
+ assertArgDefined(arguments, 0, 'url');
1907
+
1908
+ // Change url to `null` if `undefined` to stop it throwing an exception further down
1909
+ if (angular.isUndefined(url)) url = null;
1910
+
1882
1911
  return $httpBackend[prefix](method, url, data, headers, keys);
1883
1912
  };
1884
1913
  });
1885
1914
  }
1886
1915
  }
1887
1916
 
1917
+ function assertArgDefined(args, index, name) {
1918
+ if (args.length > index && angular.isUndefined(args[index])) {
1919
+ throw new Error('Undefined argument `' + name + '`; the argument is provided but not defined');
1920
+ }
1921
+ }
1922
+
1923
+
1888
1924
  function MockHttpExpectation(method, url, data, headers, keys) {
1889
1925
 
1890
1926
  function getUrlParams(u) {
@@ -1893,14 +1929,15 @@ function MockHttpExpectation(method, url, data, headers, keys) {
1893
1929
  }
1894
1930
 
1895
1931
  function compareUrl(u) {
1896
- return (url.slice(0, url.indexOf('?')) == u.slice(0, u.indexOf('?')) && getUrlParams(url).join() == getUrlParams(u).join());
1932
+ return (url.slice(0, url.indexOf('?')) === u.slice(0, u.indexOf('?')) &&
1933
+ getUrlParams(url).join() === getUrlParams(u).join());
1897
1934
  }
1898
1935
 
1899
1936
  this.data = data;
1900
1937
  this.headers = headers;
1901
1938
 
1902
1939
  this.match = function(m, u, d, h) {
1903
- if (method != m) return false;
1940
+ if (method !== m) return false;
1904
1941
  if (!this.matchUrl(u)) return false;
1905
1942
  if (angular.isDefined(d) && !this.matchData(d)) return false;
1906
1943
  if (angular.isDefined(h) && !this.matchHeaders(h)) return false;
@@ -1911,7 +1948,7 @@ function MockHttpExpectation(method, url, data, headers, keys) {
1911
1948
  if (!url) return true;
1912
1949
  if (angular.isFunction(url.test)) return url.test(u);
1913
1950
  if (angular.isFunction(url)) return url(u);
1914
- return (url == u || compareUrl(u));
1951
+ return (url === u || compareUrl(u));
1915
1952
  };
1916
1953
 
1917
1954
  this.matchHeaders = function(h) {
@@ -1927,6 +1964,7 @@ function MockHttpExpectation(method, url, data, headers, keys) {
1927
1964
  if (data && !angular.isString(data)) {
1928
1965
  return angular.equals(angular.fromJson(angular.toJson(data)), angular.fromJson(d));
1929
1966
  }
1967
+ // eslint-disable-next-line eqeqeq
1930
1968
  return data == d;
1931
1969
  };
1932
1970
 
@@ -1958,7 +1996,7 @@ function MockHttpExpectation(method, url, data, headers, keys) {
1958
1996
  var obj = {}, key_value, key,
1959
1997
  queryStr = u.indexOf('?') > -1
1960
1998
  ? u.substring(u.indexOf('?') + 1)
1961
- : "";
1999
+ : '';
1962
2000
 
1963
2001
  angular.forEach(queryStr.split('&'), function(keyValue) {
1964
2002
  if (keyValue) {
@@ -2025,7 +2063,7 @@ function MockXhr() {
2025
2063
 
2026
2064
  header = undefined;
2027
2065
  angular.forEach(this.$$respHeaders, function(headerVal, headerName) {
2028
- if (!header && angular.lowercase(headerName) == name) header = headerVal;
2066
+ if (!header && angular.lowercase(headerName) === name) header = headerVal;
2029
2067
  });
2030
2068
  return header;
2031
2069
  };
@@ -2098,7 +2136,7 @@ angular.mock.$TimeoutDecorator = ['$delegate', '$browser', function($delegate, $
2098
2136
  function formatPendingTasksAsString(tasks) {
2099
2137
  var result = [];
2100
2138
  angular.forEach(tasks, function(task) {
2101
- result.push('{id: ' + task.id + ', ' + 'time: ' + task.time + '}');
2139
+ result.push('{id: ' + task.id + ', time: ' + task.time + '}');
2102
2140
  });
2103
2141
 
2104
2142
  return result.join(', ');
@@ -2153,6 +2191,10 @@ angular.mock.$RootElementProvider = function() {
2153
2191
  * A decorator for {@link ng.$controller} with additional `bindings` parameter, useful when testing
2154
2192
  * controllers of directives that use {@link $compile#-bindtocontroller- `bindToController`}.
2155
2193
  *
2194
+ * Depending on the value of
2195
+ * {@link ng.$compileProvider#preAssignBindingsEnabled `preAssignBindingsEnabled()`}, the properties
2196
+ * will be bound before or after invoking the constructor.
2197
+ *
2156
2198
  *
2157
2199
  * ## Example
2158
2200
  *
@@ -2171,18 +2213,24 @@ angular.mock.$RootElementProvider = function() {
2171
2213
  * // Controller definition ...
2172
2214
  *
2173
2215
  * myMod.controller('MyDirectiveController', ['$log', function($log) {
2174
- * $log.info(this.name);
2216
+ * this.log = function() {
2217
+ * $log.info(this.name);
2218
+ * };
2175
2219
  * }]);
2176
2220
  *
2177
2221
  *
2178
2222
  * // In a test ...
2179
2223
  *
2180
2224
  * describe('myDirectiveController', function() {
2181
- * it('should write the bound name to the log', inject(function($controller, $log) {
2182
- * var ctrl = $controller('MyDirectiveController', { /* no locals */ }, { name: 'Clark Kent' });
2183
- * expect(ctrl.name).toEqual('Clark Kent');
2184
- * expect($log.info.logs).toEqual(['Clark Kent']);
2185
- * }));
2225
+ * describe('log()', function() {
2226
+ * it('should write the bound name to the log', inject(function($controller, $log) {
2227
+ * var ctrl = $controller('MyDirectiveController', { /* no locals */ }, { name: 'Clark Kent' });
2228
+ * ctrl.log();
2229
+ *
2230
+ * expect(ctrl.name).toEqual('Clark Kent');
2231
+ * expect($log.info.logs).toEqual(['Clark Kent']);
2232
+ * }));
2233
+ * });
2186
2234
  * });
2187
2235
  *
2188
2236
  * ```
@@ -2194,44 +2242,61 @@ angular.mock.$RootElementProvider = function() {
2194
2242
  * * check if a controller with given name is registered via `$controllerProvider`
2195
2243
  * * check if evaluating the string on the current scope returns a constructor
2196
2244
  * * if $controllerProvider#allowGlobals, check `window[constructor]` on the global
2197
- * `window` object (not recommended)
2245
+ * `window` object (deprecated, not recommended)
2198
2246
  *
2199
2247
  * The string can use the `controller as property` syntax, where the controller instance is published
2200
2248
  * as the specified property on the `scope`; the `scope` must be injected into `locals` param for this
2201
2249
  * to work correctly.
2202
2250
  *
2203
2251
  * @param {Object} locals Injection locals for Controller.
2204
- * @param {Object=} bindings Properties to add to the controller before invoking the constructor. This is used
2205
- * to simulate the `bindToController` feature and simplify certain kinds of tests.
2252
+ * @param {Object=} bindings Properties to add to the controller instance. This is used to simulate
2253
+ * the `bindToController` feature and simplify certain kinds of tests.
2206
2254
  * @return {Object} Instance of given controller.
2207
2255
  */
2208
- angular.mock.$ControllerDecorator = ['$delegate', function($delegate) {
2209
- return function(expression, locals, later, ident) {
2210
- if (later && typeof later === 'object') {
2211
- var instantiate = $delegate(expression, locals, true, ident);
2212
- angular.extend(instantiate.instance, later);
2213
-
2214
- var instance = instantiate();
2215
- if (instance !== instantiate.instance) {
2216
- angular.extend(instance, later);
2256
+ function createControllerDecorator(compileProvider) {
2257
+ angular.mock.$ControllerDecorator = ['$delegate', function($delegate) {
2258
+ return function(expression, locals, later, ident) {
2259
+ if (later && typeof later === 'object') {
2260
+ var preAssignBindingsEnabled = compileProvider.preAssignBindingsEnabled();
2261
+
2262
+ var instantiate = $delegate(expression, locals, true, ident);
2263
+ if (preAssignBindingsEnabled) {
2264
+ angular.extend(instantiate.instance, later);
2265
+ }
2266
+
2267
+ var instance = instantiate();
2268
+ if (!preAssignBindingsEnabled || instance !== instantiate.instance) {
2269
+ angular.extend(instance, later);
2270
+ }
2271
+
2272
+ return instance;
2217
2273
  }
2274
+ return $delegate(expression, locals, later, ident);
2275
+ };
2276
+ }];
2218
2277
 
2219
- return instance;
2220
- }
2221
- return $delegate(expression, locals, later, ident);
2222
- };
2223
- }];
2278
+ return angular.mock.$ControllerDecorator;
2279
+ }
2224
2280
 
2225
2281
  /**
2226
2282
  * @ngdoc service
2227
2283
  * @name $componentController
2228
2284
  * @description
2229
- * A service that can be used to create instances of component controllers.
2230
- * <div class="alert alert-info">
2285
+ * A service that can be used to create instances of component controllers. Useful for unit-testing.
2286
+ *
2231
2287
  * Be aware that the controller will be instantiated and attached to the scope as specified in
2232
2288
  * the component definition object. If you do not provide a `$scope` object in the `locals` param
2233
2289
  * then the helper will create a new isolated scope as a child of `$rootScope`.
2234
- * </div>
2290
+ *
2291
+ * If you are using `$element` or `$attrs` in the controller, make sure to provide them as `locals`.
2292
+ * The `$element` must be a jqLite-wrapped DOM element, and `$attrs` should be an object that
2293
+ * has all properties / functions that you are using in the controller. If this is getting too complex,
2294
+ * you should compile the component instead and access the component's controller via the
2295
+ * {@link angular.element#methods `controller`} function.
2296
+ *
2297
+ * See also the section on {@link guide/component#unit-testing-component-controllers unit-testing component controllers}
2298
+ * in the guide.
2299
+ *
2235
2300
  * @param {string} componentName the name of the component whose controller we want to instantiate
2236
2301
  * @param {Object} locals Injection locals for Controller.
2237
2302
  * @param {Object=} bindings Properties to add to the controller before invoking the constructor. This is used
@@ -2239,7 +2304,8 @@ angular.mock.$ControllerDecorator = ['$delegate', function($delegate) {
2239
2304
  * @param {string=} ident Override the property name to use when attaching the controller to the scope.
2240
2305
  * @return {Object} Instance of requested controller.
2241
2306
  */
2242
- angular.mock.$ComponentControllerProvider = ['$compileProvider', function($compileProvider) {
2307
+ angular.mock.$ComponentControllerProvider = ['$compileProvider',
2308
+ function ComponentControllerProvider($compileProvider) {
2243
2309
  this.$get = ['$controller','$injector', '$rootScope', function($controller, $injector, $rootScope) {
2244
2310
  return function $componentController(componentName, locals, bindings, ident) {
2245
2311
  // get all directives associated to the component name
@@ -2288,6 +2354,7 @@ angular.mock.$ComponentControllerProvider = ['$compileProvider', function($compi
2288
2354
  * * [Google CDN](https://developers.google.com/speed/libraries/devguide#angularjs) e.g.
2289
2355
  * `"//ajax.googleapis.com/ajax/libs/angularjs/X.Y.Z/angular-mocks.js"`
2290
2356
  * * [NPM](https://www.npmjs.com/) e.g. `npm install angular-mocks@X.Y.Z`
2357
+ * * [Yarn](https://yarnpkg.com) e.g. `yarn add angular-mocks@X.Y.Z`
2291
2358
  * * [Bower](http://bower.io) e.g. `bower install angular-mocks#X.Y.Z`
2292
2359
  * * [code.angularjs.org](https://code.angularjs.org/) (discouraged for production use) e.g.
2293
2360
  * `"//code.angularjs.org/X.Y.Z/angular-mocks.js"`
@@ -2319,11 +2386,11 @@ angular.module('ngMock', ['ng']).provider({
2319
2386
  $httpBackend: angular.mock.$HttpBackendProvider,
2320
2387
  $rootElement: angular.mock.$RootElementProvider,
2321
2388
  $componentController: angular.mock.$ComponentControllerProvider
2322
- }).config(['$provide', function($provide) {
2389
+ }).config(['$provide', '$compileProvider', function($provide, $compileProvider) {
2323
2390
  $provide.decorator('$timeout', angular.mock.$TimeoutDecorator);
2324
2391
  $provide.decorator('$$rAF', angular.mock.$RAFDecorator);
2325
2392
  $provide.decorator('$rootScope', angular.mock.$RootScopeDecorator);
2326
- $provide.decorator('$controller', angular.mock.$ControllerDecorator);
2393
+ $provide.decorator('$controller', createControllerDecorator($compileProvider));
2327
2394
  }]);
2328
2395
 
2329
2396
  /**
@@ -2387,7 +2454,7 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
2387
2454
  * phones.push(phone);
2388
2455
  * return [200, phone, {}];
2389
2456
  * });
2390
- * $httpBackend.whenGET(/^\/templates\//).passThrough(); // Requests for templare are handled by the real server
2457
+ * $httpBackend.whenGET(/^\/templates\//).passThrough(); // Requests for templates are handled by the real server
2391
2458
  * //...
2392
2459
  * });
2393
2460
  * ```
@@ -2399,7 +2466,7 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
2399
2466
  * <file name="app.js">
2400
2467
  * var myApp = angular.module('myApp', []);
2401
2468
  *
2402
- * myApp.controller('main', function($http) {
2469
+ * myApp.controller('MainCtrl', function MainCtrl($http) {
2403
2470
  * var ctrl = this;
2404
2471
  *
2405
2472
  * ctrl.phones = [];
@@ -2441,7 +2508,7 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
2441
2508
  * });
2442
2509
  * </file>
2443
2510
  * <file name="index.html">
2444
- * <div ng-controller="main as $ctrl">
2511
+ * <div ng-controller="MainCtrl as $ctrl">
2445
2512
  * <form name="newPhoneForm" ng-submit="$ctrl.addPhone($ctrl.newPhone)">
2446
2513
  * <input type="text" ng-model="$ctrl.newPhone.name">
2447
2514
  * <input type="submit" value="Add Phone">
@@ -2465,7 +2532,7 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
2465
2532
  * Creates a new backend definition.
2466
2533
  *
2467
2534
  * @param {string} method HTTP method.
2468
- * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
2535
+ * @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
2469
2536
  * and returns true if the url matches the current definition.
2470
2537
  * @param {(string|RegExp)=} data HTTP request body.
2471
2538
  * @param {(Object|function(Object))=} headers HTTP headers or function that receives http header
@@ -2497,7 +2564,7 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
2497
2564
  * @description
2498
2565
  * Creates a new backend definition for GET requests. For more info see `when()`.
2499
2566
  *
2500
- * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
2567
+ * @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
2501
2568
  * and returns true if the url matches the current definition.
2502
2569
  * @param {(Object|function(Object))=} headers HTTP headers.
2503
2570
  * @param {(Array)=} keys Array of keys to assign to regex matches in request url described on
@@ -2514,7 +2581,7 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
2514
2581
  * @description
2515
2582
  * Creates a new backend definition for HEAD requests. For more info see `when()`.
2516
2583
  *
2517
- * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
2584
+ * @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
2518
2585
  * and returns true if the url matches the current definition.
2519
2586
  * @param {(Object|function(Object))=} headers HTTP headers.
2520
2587
  * @param {(Array)=} keys Array of keys to assign to regex matches in request url described on
@@ -2531,7 +2598,7 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
2531
2598
  * @description
2532
2599
  * Creates a new backend definition for DELETE requests. For more info see `when()`.
2533
2600
  *
2534
- * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
2601
+ * @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
2535
2602
  * and returns true if the url matches the current definition.
2536
2603
  * @param {(Object|function(Object))=} headers HTTP headers.
2537
2604
  * @param {(Array)=} keys Array of keys to assign to regex matches in request url described on
@@ -2548,7 +2615,7 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
2548
2615
  * @description
2549
2616
  * Creates a new backend definition for POST requests. For more info see `when()`.
2550
2617
  *
2551
- * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
2618
+ * @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
2552
2619
  * and returns true if the url matches the current definition.
2553
2620
  * @param {(string|RegExp)=} data HTTP request body.
2554
2621
  * @param {(Object|function(Object))=} headers HTTP headers.
@@ -2566,7 +2633,7 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
2566
2633
  * @description
2567
2634
  * Creates a new backend definition for PUT requests. For more info see `when()`.
2568
2635
  *
2569
- * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
2636
+ * @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
2570
2637
  * and returns true if the url matches the current definition.
2571
2638
  * @param {(string|RegExp)=} data HTTP request body.
2572
2639
  * @param {(Object|function(Object))=} headers HTTP headers.
@@ -2584,7 +2651,7 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
2584
2651
  * @description
2585
2652
  * Creates a new backend definition for PATCH requests. For more info see `when()`.
2586
2653
  *
2587
- * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
2654
+ * @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
2588
2655
  * and returns true if the url matches the current definition.
2589
2656
  * @param {(string|RegExp)=} data HTTP request body.
2590
2657
  * @param {(Object|function(Object))=} headers HTTP headers.
@@ -2602,7 +2669,7 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
2602
2669
  * @description
2603
2670
  * Creates a new backend definition for JSONP requests. For more info see `when()`.
2604
2671
  *
2605
- * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
2672
+ * @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
2606
2673
  * and returns true if the url matches the current definition.
2607
2674
  * @param {(Array)=} keys Array of keys to assign to regex matches in request url described on
2608
2675
  * {@link ngMock.$httpBackend $httpBackend mock}.
@@ -2654,6 +2721,7 @@ angular.mock.$RootScopeDecorator = ['$delegate', function($delegate) {
2654
2721
  * @ngdoc method
2655
2722
  * @name $rootScope.Scope#$countChildScopes
2656
2723
  * @module ngMock
2724
+ * @this $rootScope.Scope
2657
2725
  * @description
2658
2726
  * Counts all the direct and indirect child scopes of the current scope.
2659
2727
  *
@@ -2662,7 +2730,6 @@ angular.mock.$RootScopeDecorator = ['$delegate', function($delegate) {
2662
2730
  * @returns {number} Total number of child scopes.
2663
2731
  */
2664
2732
  function countChildScopes() {
2665
- // jshint validthis: true
2666
2733
  var count = 0; // exclude the current scope
2667
2734
  var pendingChildHeads = [this.$$childHead];
2668
2735
  var currentScope;
@@ -2684,6 +2751,7 @@ angular.mock.$RootScopeDecorator = ['$delegate', function($delegate) {
2684
2751
  /**
2685
2752
  * @ngdoc method
2686
2753
  * @name $rootScope.Scope#$countWatchers
2754
+ * @this $rootScope.Scope
2687
2755
  * @module ngMock
2688
2756
  * @description
2689
2757
  * Counts all the watchers of direct and indirect child scopes of the current scope.
@@ -2694,7 +2762,6 @@ angular.mock.$RootScopeDecorator = ['$delegate', function($delegate) {
2694
2762
  * @returns {number} Total number of watchers.
2695
2763
  */
2696
2764
  function countWatchers() {
2697
- // jshint validthis: true
2698
2765
  var count = this.$$watchers ? this.$$watchers.length : 0; // include the current scope
2699
2766
  var pendingChildHeads = [this.$$childHead];
2700
2767
  var currentScope;
@@ -2714,7 +2781,7 @@ angular.mock.$RootScopeDecorator = ['$delegate', function($delegate) {
2714
2781
  }];
2715
2782
 
2716
2783
 
2717
- !(function(jasmineOrMocha) {
2784
+ (function(jasmineOrMocha) {
2718
2785
 
2719
2786
  if (!jasmineOrMocha) {
2720
2787
  return;
@@ -2809,7 +2876,7 @@ angular.mock.$RootScopeDecorator = ['$delegate', function($delegate) {
2809
2876
  *
2810
2877
  * You cannot call `sharedInjector()` from within a context already using `sharedInjector()`.
2811
2878
  *
2812
- * ## Example
2879
+ * ## Example
2813
2880
  *
2814
2881
  * Typically beforeAll is used to make many assertions about a single operation. This can
2815
2882
  * cut down test run-time as the test setup doesn't need to be re-run, and enabling focussed
@@ -2847,14 +2914,14 @@ angular.mock.$RootScopeDecorator = ['$delegate', function($delegate) {
2847
2914
  */
2848
2915
  module.sharedInjector = function() {
2849
2916
  if (!(module.$$beforeAllHook && module.$$afterAllHook)) {
2850
- throw Error("sharedInjector() cannot be used unless your test runner defines beforeAll/afterAll");
2917
+ throw Error('sharedInjector() cannot be used unless your test runner defines beforeAll/afterAll');
2851
2918
  }
2852
2919
 
2853
2920
  var initialized = false;
2854
2921
 
2855
- module.$$beforeAllHook(function() {
2922
+ module.$$beforeAllHook(/** @this */ function() {
2856
2923
  if (injectorState.shared) {
2857
- injectorState.sharedError = Error("sharedInjector() cannot be called inside a context that has already called sharedInjector()");
2924
+ injectorState.sharedError = Error('sharedInjector() cannot be called inside a context that has already called sharedInjector()');
2858
2925
  throw injectorState.sharedError;
2859
2926
  }
2860
2927
  initialized = true;
@@ -2873,10 +2940,10 @@ angular.mock.$RootScopeDecorator = ['$delegate', function($delegate) {
2873
2940
  };
2874
2941
 
2875
2942
  module.$$beforeEach = function() {
2876
- if (injectorState.shared && currentSpec && currentSpec != this) {
2943
+ if (injectorState.shared && currentSpec && currentSpec !== this) {
2877
2944
  var state = currentSpec;
2878
2945
  currentSpec = this;
2879
- angular.forEach(["$injector","$modules","$providerInjector", "$injectorStrict"], function(k) {
2946
+ angular.forEach(['$injector','$modules','$providerInjector', '$injectorStrict'], function(k) {
2880
2947
  currentSpec[k] = state[k];
2881
2948
  state[k] = null;
2882
2949
  });
@@ -2967,7 +3034,7 @@ angular.mock.$RootScopeDecorator = ['$delegate', function($delegate) {
2967
3034
  * These are ignored by the injector when the reference name is resolved.
2968
3035
  *
2969
3036
  * For example, the parameter `_myService_` would be resolved as the reference `myService`.
2970
- * Since it is available in the function body as _myService_, we can then assign it to a variable
3037
+ * Since it is available in the function body as `_myService_`, we can then assign it to a variable
2971
3038
  * defined in an outer scope.
2972
3039
  *
2973
3040
  * ```
@@ -3031,7 +3098,7 @@ angular.mock.$RootScopeDecorator = ['$delegate', function($delegate) {
3031
3098
 
3032
3099
 
3033
3100
 
3034
- var ErrorAddingDeclarationLocationStack = function(e, errorForStack) {
3101
+ var ErrorAddingDeclarationLocationStack = function ErrorAddingDeclarationLocationStack(e, errorForStack) {
3035
3102
  this.message = e.message;
3036
3103
  this.name = e.name;
3037
3104
  if (e.line) this.line = e.line;
@@ -3049,11 +3116,11 @@ angular.mock.$RootScopeDecorator = ['$delegate', function($delegate) {
3049
3116
  if (!errorForStack.stack) {
3050
3117
  try {
3051
3118
  throw errorForStack;
3052
- } catch (e) {}
3119
+ } catch (e) { /* empty */ }
3053
3120
  }
3054
- return wasInjectorCreated() ? workFn.call(currentSpec) : workFn;
3121
+ return wasInjectorCreated() ? WorkFn.call(currentSpec) : WorkFn;
3055
3122
  /////////////////////
3056
- function workFn() {
3123
+ function WorkFn() {
3057
3124
  var modules = currentSpec.$modules || [];
3058
3125
  var strictDi = !!currentSpec.$injectorStrict;
3059
3126
  modules.unshift(['$injector', function($injector) {
@@ -3066,7 +3133,7 @@ angular.mock.$RootScopeDecorator = ['$delegate', function($delegate) {
3066
3133
  if (strictDi) {
3067
3134
  // If strictDi is enabled, annotate the providerInjector blocks
3068
3135
  angular.forEach(modules, function(moduleFn) {
3069
- if (typeof moduleFn === "function") {
3136
+ if (typeof moduleFn === 'function') {
3070
3137
  angular.injector.$$annotate(moduleFn);
3071
3138
  }
3072
3139
  });
@@ -3081,9 +3148,7 @@ angular.mock.$RootScopeDecorator = ['$delegate', function($delegate) {
3081
3148
  injector.annotate(blockFns[i]);
3082
3149
  }
3083
3150
  try {
3084
- /* jshint -W040 *//* Jasmine explicitly provides a `this` object when calling functions */
3085
3151
  injector.invoke(blockFns[i] || angular.noop, this);
3086
- /* jshint +W040 */
3087
3152
  } catch (e) {
3088
3153
  if (e.stack && errorForStack) {
3089
3154
  throw new ErrorAddingDeclarationLocationStack(e, errorForStack);
@@ -3122,5 +3187,218 @@ angular.mock.$RootScopeDecorator = ['$delegate', function($delegate) {
3122
3187
  }
3123
3188
  })(window.jasmine || window.mocha);
3124
3189
 
3190
+ 'use strict';
3191
+
3192
+ (function() {
3193
+ /**
3194
+ * Triggers a browser event. Attempts to choose the right event if one is
3195
+ * not specified.
3196
+ *
3197
+ * @param {Object} element Either a wrapped jQuery/jqLite node or a DOMElement
3198
+ * @param {string} eventType Optional event type
3199
+ * @param {Object=} eventData An optional object which contains additional event data (such as x,y
3200
+ * coordinates, keys, etc...) that are passed into the event when triggered
3201
+ */
3202
+ window.browserTrigger = function browserTrigger(element, eventType, eventData) {
3203
+ if (element && !element.nodeName) element = element[0];
3204
+ if (!element) return;
3205
+
3206
+ eventData = eventData || {};
3207
+ var relatedTarget = eventData.relatedTarget || element;
3208
+ var keys = eventData.keys;
3209
+ var x = eventData.x;
3210
+ var y = eventData.y;
3211
+
3212
+ var inputType = (element.type) ? element.type.toLowerCase() : null,
3213
+ nodeName = element.nodeName.toLowerCase();
3214
+ if (!eventType) {
3215
+ eventType = {
3216
+ 'text': 'change',
3217
+ 'textarea': 'change',
3218
+ 'hidden': 'change',
3219
+ 'password': 'change',
3220
+ 'button': 'click',
3221
+ 'submit': 'click',
3222
+ 'reset': 'click',
3223
+ 'image': 'click',
3224
+ 'checkbox': 'click',
3225
+ 'radio': 'click',
3226
+ 'select-one': 'change',
3227
+ 'select-multiple': 'change',
3228
+ '_default_': 'click'
3229
+ }[inputType || '_default_'];
3230
+ }
3231
+
3232
+ if (nodeName === 'option') {
3233
+ element.parentNode.value = element.value;
3234
+ element = element.parentNode;
3235
+ eventType = 'change';
3236
+ }
3237
+
3238
+ keys = keys || [];
3239
+ function pressed(key) {
3240
+ return keys.indexOf(key) !== -1;
3241
+ }
3242
+
3243
+ var evnt;
3244
+ if (/transitionend/.test(eventType)) {
3245
+ if (window.WebKitTransitionEvent) {
3246
+ evnt = new window.WebKitTransitionEvent(eventType, eventData);
3247
+ evnt.initEvent(eventType, false, true);
3248
+ } else {
3249
+ try {
3250
+ evnt = new window.TransitionEvent(eventType, eventData);
3251
+ } catch (e) {
3252
+ evnt = window.document.createEvent('TransitionEvent');
3253
+ evnt.initTransitionEvent(eventType, null, null, null, eventData.elapsedTime || 0);
3254
+ }
3255
+ }
3256
+ } else if (/animationend/.test(eventType)) {
3257
+ if (window.WebKitAnimationEvent) {
3258
+ evnt = new window.WebKitAnimationEvent(eventType, eventData);
3259
+ evnt.initEvent(eventType, false, true);
3260
+ } else {
3261
+ try {
3262
+ evnt = new window.AnimationEvent(eventType, eventData);
3263
+ } catch (e) {
3264
+ evnt = window.document.createEvent('AnimationEvent');
3265
+ evnt.initAnimationEvent(eventType, null, null, null, eventData.elapsedTime || 0);
3266
+ }
3267
+ }
3268
+ } else if (/touch/.test(eventType) && supportsTouchEvents()) {
3269
+ evnt = createTouchEvent(element, eventType, x, y);
3270
+ } else if (/key/.test(eventType)) {
3271
+ evnt = window.document.createEvent('Events');
3272
+ evnt.initEvent(eventType, eventData.bubbles, eventData.cancelable);
3273
+ evnt.view = window;
3274
+ evnt.ctrlKey = pressed('ctrl');
3275
+ evnt.altKey = pressed('alt');
3276
+ evnt.shiftKey = pressed('shift');
3277
+ evnt.metaKey = pressed('meta');
3278
+ evnt.keyCode = eventData.keyCode;
3279
+ evnt.charCode = eventData.charCode;
3280
+ evnt.which = eventData.which;
3281
+ } else {
3282
+ evnt = window.document.createEvent('MouseEvents');
3283
+ x = x || 0;
3284
+ y = y || 0;
3285
+ evnt.initMouseEvent(eventType, true, true, window, 0, x, y, x, y, pressed('ctrl'),
3286
+ pressed('alt'), pressed('shift'), pressed('meta'), 0, relatedTarget);
3287
+ }
3288
+
3289
+ /* we're unable to change the timeStamp value directly so this
3290
+ * is only here to allow for testing where the timeStamp value is
3291
+ * read */
3292
+ evnt.$manualTimeStamp = eventData.timeStamp;
3293
+
3294
+ if (!evnt) return;
3295
+
3296
+ var originalPreventDefault = evnt.preventDefault,
3297
+ appWindow = element.ownerDocument.defaultView,
3298
+ fakeProcessDefault = true,
3299
+ finalProcessDefault,
3300
+ angular = appWindow.angular || {};
3301
+
3302
+ // igor: temporary fix for https://bugzilla.mozilla.org/show_bug.cgi?id=684208
3303
+ angular['ff-684208-preventDefault'] = false;
3304
+ evnt.preventDefault = function() {
3305
+ fakeProcessDefault = false;
3306
+ return originalPreventDefault.apply(evnt, arguments);
3307
+ };
3308
+
3309
+ if (!eventData.bubbles || supportsEventBubblingInDetachedTree() || isAttachedToDocument(element)) {
3310
+ element.dispatchEvent(evnt);
3311
+ } else {
3312
+ triggerForPath(element, evnt);
3313
+ }
3314
+
3315
+ finalProcessDefault = !(angular['ff-684208-preventDefault'] || !fakeProcessDefault);
3316
+
3317
+ delete angular['ff-684208-preventDefault'];
3318
+
3319
+ return finalProcessDefault;
3320
+ };
3321
+
3322
+ function supportsTouchEvents() {
3323
+ if ('_cached' in supportsTouchEvents) {
3324
+ return supportsTouchEvents._cached;
3325
+ }
3326
+ if (!window.document.createTouch || !window.document.createTouchList) {
3327
+ supportsTouchEvents._cached = false;
3328
+ return false;
3329
+ }
3330
+ try {
3331
+ window.document.createEvent('TouchEvent');
3332
+ } catch (e) {
3333
+ supportsTouchEvents._cached = false;
3334
+ return false;
3335
+ }
3336
+ supportsTouchEvents._cached = true;
3337
+ return true;
3338
+ }
3339
+
3340
+ function createTouchEvent(element, eventType, x, y) {
3341
+ var evnt = new window.Event(eventType);
3342
+ x = x || 0;
3343
+ y = y || 0;
3344
+
3345
+ var touch = window.document.createTouch(window, element, Date.now(), x, y, x, y);
3346
+ var touches = window.document.createTouchList(touch);
3347
+
3348
+ evnt.touches = touches;
3349
+
3350
+ return evnt;
3351
+ }
3352
+
3353
+ function supportsEventBubblingInDetachedTree() {
3354
+ if ('_cached' in supportsEventBubblingInDetachedTree) {
3355
+ return supportsEventBubblingInDetachedTree._cached;
3356
+ }
3357
+ supportsEventBubblingInDetachedTree._cached = false;
3358
+ var doc = window.document;
3359
+ if (doc) {
3360
+ var parent = doc.createElement('div'),
3361
+ child = parent.cloneNode();
3362
+ parent.appendChild(child);
3363
+ parent.addEventListener('e', function() {
3364
+ supportsEventBubblingInDetachedTree._cached = true;
3365
+ });
3366
+ var evnt = window.document.createEvent('Events');
3367
+ evnt.initEvent('e', true, true);
3368
+ child.dispatchEvent(evnt);
3369
+ }
3370
+ return supportsEventBubblingInDetachedTree._cached;
3371
+ }
3372
+
3373
+ function triggerForPath(element, evnt) {
3374
+ var stop = false;
3375
+
3376
+ var _stopPropagation = evnt.stopPropagation;
3377
+ evnt.stopPropagation = function() {
3378
+ stop = true;
3379
+ _stopPropagation.apply(evnt, arguments);
3380
+ };
3381
+ patchEventTargetForBubbling(evnt, element);
3382
+ do {
3383
+ element.dispatchEvent(evnt);
3384
+ // eslint-disable-next-line no-unmodified-loop-condition
3385
+ } while (!stop && (element = element.parentNode));
3386
+ }
3387
+
3388
+ function patchEventTargetForBubbling(event, target) {
3389
+ event._target = target;
3390
+ Object.defineProperty(event, 'target', {get: function() { return this._target;}});
3391
+ }
3392
+
3393
+ function isAttachedToDocument(element) {
3394
+ while ((element = element.parentNode)) {
3395
+ if (element === window) {
3396
+ return true;
3397
+ }
3398
+ }
3399
+ return false;
3400
+ }
3401
+ })();
3402
+
3125
3403
 
3126
3404
  })(window, window.angular);