mongo_browser 0.2.0.rc2 → 0.2.5

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.
Files changed (141) hide show
  1. data/.gitignore +3 -1
  2. data/.rspec +1 -1
  3. data/.travis.yml +6 -1
  4. data/CHANGELOG.md +15 -0
  5. data/{grunt.js → Gruntfile.js} +10 -8
  6. data/Procfile +1 -0
  7. data/README.md +44 -2
  8. data/Rakefile +1 -12
  9. data/app/assets/images/ajax-loader.gif +0 -0
  10. data/app/assets/javascripts/app/controllers/{breadcrumbs.js.coffee → breadcrumbs_controller.js.coffee} +4 -7
  11. data/app/assets/javascripts/app/controllers/collections/index_controller.js.coffee +38 -0
  12. data/app/assets/javascripts/app/controllers/collections/stats_controller.js.coffee +17 -0
  13. data/app/assets/javascripts/app/controllers/{databases.js.coffee → databases/index_controller.js.coffee} +11 -15
  14. data/app/assets/javascripts/app/controllers/databases/stats_controller.js.coffee +15 -0
  15. data/app/assets/javascripts/app/controllers/documents/index_controller.js.coffee +54 -0
  16. data/app/assets/javascripts/app/controllers/documents/show_controller.js.coffee +38 -0
  17. data/app/assets/javascripts/app/controllers/main_controller.js.coffee +15 -0
  18. data/app/assets/javascripts/app/controllers/servers/show_controller.js.coffee +17 -0
  19. data/app/assets/javascripts/app/directives.js.coffee +23 -0
  20. data/app/assets/javascripts/app/filters.js.coffee +14 -1
  21. data/app/assets/javascripts/app/modules/alerts.js.coffee +58 -0
  22. data/app/assets/javascripts/app/modules/pager.js.coffee +2 -2
  23. data/app/assets/javascripts/app/modules/spinner.js.coffee +29 -0
  24. data/app/assets/javascripts/app/modules/table_filter.js.coffee +4 -4
  25. data/app/assets/javascripts/app/resources.js.coffee +14 -8
  26. data/app/assets/javascripts/app/services.js.coffee +11 -33
  27. data/app/assets/javascripts/application.js.coffee +62 -34
  28. data/app/assets/javascripts/application.test.js.coffee +5 -0
  29. data/app/assets/javascripts/compiled_templates.js.coffee +1 -0
  30. data/app/assets/javascripts/vendor.js.coffee +0 -1
  31. data/app/assets/stylesheets/application.css.scss +36 -18
  32. data/{public/index.html → app/views/index.erb} +8 -8
  33. data/bin/mongo_browser +2 -13
  34. data/config.ru +3 -1
  35. data/lib/mongo_browser.rb +1 -0
  36. data/lib/mongo_browser/api.rb +11 -0
  37. data/lib/mongo_browser/api/collections.rb +34 -0
  38. data/lib/mongo_browser/api/databases.rb +32 -0
  39. data/lib/mongo_browser/api/documents.rb +37 -0
  40. data/lib/mongo_browser/api/mongo.rb +41 -0
  41. data/lib/mongo_browser/application.rb +8 -174
  42. data/lib/mongo_browser/application/development.rb +32 -0
  43. data/lib/mongo_browser/cli.rb +48 -0
  44. data/lib/mongo_browser/entities.rb +43 -0
  45. data/lib/mongo_browser/models/collection.rb +7 -12
  46. data/lib/mongo_browser/models/document.rb +5 -1
  47. data/lib/mongo_browser/models/pager.rb +22 -9
  48. data/lib/mongo_browser/version.rb +1 -1
  49. data/mongo_browser.gemspec +22 -15
  50. data/package.json +30 -0
  51. data/public/ng/templates/alerts.html +6 -0
  52. data/public/ng/templates/collections/index.html +39 -0
  53. data/public/ng/templates/collections/stats.html +18 -0
  54. data/public/ng/templates/databases/index.html +35 -0
  55. data/public/ng/templates/databases/stats.html +18 -0
  56. data/public/ng/templates/documents/index.html +40 -0
  57. data/public/ng/templates/documents/show.html +17 -0
  58. data/{app/assets → public/ng}/templates/pager.html +0 -0
  59. data/{app/assets/templates/server_info.html → public/ng/templates/server/show.html} +1 -1
  60. data/{app/assets → public/ng}/templates/table_filter.html +0 -0
  61. data/script/ci_all +5 -1
  62. data/script/ci_e2e +5 -2
  63. data/script/ci_javascripts +1 -1
  64. data/script/ci_rspec +1 -1
  65. data/spec/javascripts/app/controllers/{breadcrumbs_spec.js.coffee → breadcrumbs_controller_spec.js.coffee} +1 -1
  66. data/spec/javascripts/app/controllers/collections/index_controller_spec.js.coffee +95 -0
  67. data/spec/javascripts/app/controllers/collections/stats_controller_spec.js.coffee +34 -0
  68. data/spec/javascripts/app/controllers/databases/index_controller_spec.js.coffee +93 -0
  69. data/spec/javascripts/app/controllers/databases/stats_controller_spec.js.coffee +30 -0
  70. data/spec/javascripts/app/controllers/documents/index_controller_spec.js.coffee +108 -0
  71. data/spec/javascripts/app/controllers/documents/show_controller_spec.js.coffee +94 -0
  72. data/spec/javascripts/app/controllers/{main_spec.js.coffee → main_controller_spec.js.coffee} +2 -2
  73. data/spec/javascripts/app/controllers/{server_info_spec.js.coffee → server/show_controller_spec.js.coffee} +5 -6
  74. data/spec/javascripts/app/directives_spec.js.coffee +108 -24
  75. data/spec/javascripts/app/filters_spec.js.coffee +31 -5
  76. data/spec/javascripts/app/modules/alerts_spec.js.coffee +138 -0
  77. data/spec/javascripts/app/modules/dialogs_spec.js.coffee +1 -2
  78. data/spec/javascripts/app/modules/pager_spec.js.coffee +0 -1
  79. data/spec/javascripts/app/modules/spinner_spec.js.coffee +65 -0
  80. data/spec/javascripts/app/modules/table_filter_spec.js.coffee +9 -9
  81. data/spec/javascripts/app/resources_spec.js.coffee +99 -0
  82. data/spec/javascripts/app/services_spec.js.coffee +31 -71
  83. data/spec/javascripts/config/{testacular-e2e.conf.js → karma-e2e.conf.js} +1 -1
  84. data/spec/javascripts/config/{testacular.conf.js → karma.conf.js} +2 -3
  85. data/spec/javascripts/e2e/collection_stats_scenario.js.coffee +12 -0
  86. data/spec/javascripts/e2e/collections_scenario.js.coffee +59 -20
  87. data/spec/javascripts/e2e/database_stats_scenario.js.coffee +11 -0
  88. data/spec/javascripts/e2e/databases_scenario.js.coffee +37 -36
  89. data/spec/javascripts/e2e/document_show_scenario.js.coffee +31 -0
  90. data/spec/javascripts/e2e/documents_pagination_scenario.js.coffee +33 -0
  91. data/spec/javascripts/e2e/documents_scenario.js.coffee +43 -4
  92. data/spec/javascripts/e2e/server_info_scenario.js.coffee +8 -2
  93. data/spec/javascripts/helpers/mocks.js.coffee +2 -0
  94. data/spec/javascripts/helpers_e2e/dsl.js.coffee +20 -0
  95. data/spec/javascripts/lib/angular-mocks.js +64 -16
  96. data/spec/javascripts/lib/angular-scenario.js +724 -561
  97. data/spec/javascripts/runner.html +5 -5
  98. data/spec/lib/api/collections_spec.rb +62 -0
  99. data/spec/lib/api/databases_spec.rb +58 -0
  100. data/spec/lib/api/documents_spec.rb +135 -0
  101. data/spec/lib/api/mongo_spec.rb +27 -0
  102. data/spec/lib/cli_spec.rb +19 -0
  103. data/spec/lib/entities_spec.rb +39 -0
  104. data/spec/lib/models/collection_spec.rb +16 -10
  105. data/spec/lib/models/database_spec.rb +4 -4
  106. data/spec/lib/models/document_spec.rb +5 -5
  107. data/spec/lib/models/pager_spec.rb +20 -11
  108. data/spec/spec_helper.rb +7 -15
  109. data/spec/support/api_example_group.rb +45 -0
  110. data/spec/support/fixtures.rb +10 -6
  111. data/spec/support/matchers/expose.rb +18 -0
  112. data/vendor/assets/javascripts/angular/angular-bootstrap.js +1 -1
  113. data/vendor/assets/javascripts/angular/angular-resource.js +78 -56
  114. data/vendor/assets/javascripts/angular/angular-sanitize.js +3 -1
  115. data/vendor/assets/javascripts/angular/angular.js +720 -404
  116. metadata +323 -183
  117. data/app/assets/javascripts/app.js.coffee +0 -8
  118. data/app/assets/javascripts/app/controllers.js.coffee +0 -2
  119. data/app/assets/javascripts/app/controllers/alerts.js.coffee +0 -12
  120. data/app/assets/javascripts/app/controllers/collections.js.coffee +0 -40
  121. data/app/assets/javascripts/app/controllers/documents.js.coffee +0 -49
  122. data/app/assets/javascripts/app/controllers/main.js.coffee +0 -10
  123. data/app/assets/javascripts/app/controllers/server_info.js.coffee +0 -14
  124. data/app/assets/javascripts/templates.js.coffee +0 -1
  125. data/app/assets/javascripts/templates/.gitkeep +0 -0
  126. data/app/assets/templates/collections.html +0 -53
  127. data/app/assets/templates/databases.html +0 -32
  128. data/app/assets/templates/documents.html +0 -45
  129. data/config-e2e.ru +0 -20
  130. data/spec/features/collections_list_spec.rb +0 -64
  131. data/spec/features/documents_list_spec.rb +0 -139
  132. data/spec/features/server_info_spec.rb +0 -23
  133. data/spec/javascripts/app/controllers/alerts_spec.js.coffee +0 -36
  134. data/spec/javascripts/app/controllers/collections_spec.js.coffee +0 -78
  135. data/spec/javascripts/app/controllers/databases_spec.js.coffee +0 -55
  136. data/spec/javascripts/app/controllers/documents_spec.js.coffee +0 -62
  137. data/spec/javascripts/helpers_e2e/app_element.js.coffee +0 -6
  138. data/spec/support/feature_example_group.rb +0 -53
  139. data/spec/support/matchers/have_flash_message.rb +0 -16
  140. data/spec/support/mongod.rb +0 -91
  141. data/spec/support/mongodb.conf +0 -47
@@ -9403,8 +9403,9 @@ if ( typeof define === "function" && define.amd && define.amd.jQuery ) {
9403
9403
 
9404
9404
 
9405
9405
  })( window );
9406
+
9406
9407
  /**
9407
- * @license AngularJS v1.0.3
9408
+ * @license AngularJS v1.0.7
9408
9409
  * (c) 2010-2012 Google, Inc. http://angularjs.org
9409
9410
  * License: MIT
9410
9411
  */
@@ -9439,12 +9440,12 @@ var uppercase = function(string){return isString(string) ? string.toUpperCase()
9439
9440
 
9440
9441
  var manualLowercase = function(s) {
9441
9442
  return isString(s)
9442
- ? s.replace(/[A-Z]/g, function(ch) {return fromCharCode(ch.charCodeAt(0) | 32);})
9443
+ ? s.replace(/[A-Z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) | 32);})
9443
9444
  : s;
9444
9445
  };
9445
9446
  var manualUppercase = function(s) {
9446
9447
  return isString(s)
9447
- ? s.replace(/[a-z]/g, function(ch) {return fromCharCode(ch.charCodeAt(0) & ~32);})
9448
+ ? s.replace(/[a-z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) & ~32);})
9448
9449
  : s;
9449
9450
  };
9450
9451
 
@@ -9457,11 +9458,8 @@ if ('i' !== 'I'.toLowerCase()) {
9457
9458
  uppercase = manualUppercase;
9458
9459
  }
9459
9460
 
9460
- function fromCharCode(code) {return String.fromCharCode(code);}
9461
-
9462
9461
 
9463
- var Error = window.Error,
9464
- /** holds major version number for IE or NaN for real browsers */
9462
+ var /** holds major version number for IE or NaN for real browsers */
9465
9463
  msie = int((/msie (\d+)/.exec(lowercase(navigator.userAgent)) || [])[1]),
9466
9464
  jqLite, // delay binding since jQuery could be loaded after us.
9467
9465
  jQuery, // delay binding
@@ -9475,6 +9473,29 @@ var Error = window.Error,
9475
9473
  nodeName_,
9476
9474
  uid = ['0', '0', '0'];
9477
9475
 
9476
+
9477
+ /**
9478
+ * @private
9479
+ * @param {*} obj
9480
+ * @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments, ...)
9481
+ */
9482
+ function isArrayLike(obj) {
9483
+ if (!obj || (typeof obj.length !== 'number')) return false;
9484
+
9485
+ // We have on object which has length property. Should we treat it as array?
9486
+ if (typeof obj.hasOwnProperty != 'function' &&
9487
+ typeof obj.constructor != 'function') {
9488
+ // This is here for IE8: it is a bogus object treat it as array;
9489
+ return true;
9490
+ } else {
9491
+ return obj instanceof JQLite || // JQLite
9492
+ (jQuery && obj instanceof jQuery) || // jQuery
9493
+ toString.call(obj) !== '[object Object]' || // some browser native object
9494
+ typeof obj.callee === 'function'; // arguments (on IE8 looks like regular obj)
9495
+ }
9496
+ }
9497
+
9498
+
9478
9499
  /**
9479
9500
  * @ngdoc function
9480
9501
  * @name angular.forEach
@@ -9513,7 +9534,7 @@ function forEach(obj, iterator, context) {
9513
9534
  }
9514
9535
  } else if (obj.forEach && obj.forEach !== forEach) {
9515
9536
  obj.forEach(iterator, context);
9516
- } else if (isObject(obj) && isNumber(obj.length)) {
9537
+ } else if (isArrayLike(obj)) {
9517
9538
  for (key = 0; key < obj.length; key++)
9518
9539
  iterator.call(context, obj[key], key);
9519
9540
  } else {
@@ -9558,7 +9579,7 @@ function reverseParams(iteratorFn) {
9558
9579
  /**
9559
9580
  * A consistent way of creating unique IDs in angular. The ID is a sequence of alpha numeric
9560
9581
  * characters such as '012ABC'. The reason why we are not using simply a number counter is that
9561
- * the number string gets longer over time, and it can also overflow, where as the the nextId
9582
+ * the number string gets longer over time, and it can also overflow, where as the nextId
9562
9583
  * will grow much slower, it is a string, and it will never overflow.
9563
9584
  *
9564
9585
  * @returns an unique alpha-numeric string
@@ -9585,6 +9606,21 @@ function nextUid() {
9585
9606
  return uid.join('');
9586
9607
  }
9587
9608
 
9609
+
9610
+ /**
9611
+ * Set or clear the hashkey for an object.
9612
+ * @param obj object
9613
+ * @param h the hashkey (!truthy to delete the hashkey)
9614
+ */
9615
+ function setHashKey(obj, h) {
9616
+ if (h) {
9617
+ obj.$$hashKey = h;
9618
+ }
9619
+ else {
9620
+ delete obj.$$hashKey;
9621
+ }
9622
+ }
9623
+
9588
9624
  /**
9589
9625
  * @ngdoc function
9590
9626
  * @name angular.extend
@@ -9596,8 +9632,10 @@ function nextUid() {
9596
9632
  *
9597
9633
  * @param {Object} dst Destination object.
9598
9634
  * @param {...Object} src Source object(s).
9635
+ * @returns {Object} Reference to `dst`.
9599
9636
  */
9600
9637
  function extend(dst) {
9638
+ var h = dst.$$hashKey;
9601
9639
  forEach(arguments, function(obj){
9602
9640
  if (obj !== dst) {
9603
9641
  forEach(obj, function(value, key){
@@ -9605,6 +9643,8 @@ function extend(dst) {
9605
9643
  });
9606
9644
  }
9607
9645
  });
9646
+
9647
+ setHashKey(dst,h);
9608
9648
  return dst;
9609
9649
  }
9610
9650
 
@@ -9954,19 +9994,19 @@ function copy(source, destination){
9954
9994
  } else {
9955
9995
  if (source === destination) throw Error("Can't copy equivalent objects or arrays");
9956
9996
  if (isArray(source)) {
9957
- while(destination.length) {
9958
- destination.pop();
9959
- }
9997
+ destination.length = 0;
9960
9998
  for ( var i = 0; i < source.length; i++) {
9961
9999
  destination.push(copy(source[i]));
9962
10000
  }
9963
10001
  } else {
10002
+ var h = destination.$$hashKey;
9964
10003
  forEach(destination, function(value, key){
9965
10004
  delete destination[key];
9966
10005
  });
9967
10006
  for ( var key in source) {
9968
10007
  destination[key] = copy(source[key]);
9969
10008
  }
10009
+ setHashKey(destination,h);
9970
10010
  }
9971
10011
  }
9972
10012
  return destination;
@@ -10006,7 +10046,7 @@ function shallowCopy(src, dst) {
10006
10046
  * During a property comparision, properties of `function` type and properties with names
10007
10047
  * that begin with `$` are ignored.
10008
10048
  *
10009
- * Scope and DOMWindow objects are being compared only be identify (`===`).
10049
+ * Scope and DOMWindow objects are being compared only by identify (`===`).
10010
10050
  *
10011
10051
  * @param {*} o1 Object or value to compare.
10012
10052
  * @param {*} o2 Object or value to compare.
@@ -10032,13 +10072,15 @@ function equals(o1, o2) {
10032
10072
  if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2)) return false;
10033
10073
  keySet = {};
10034
10074
  for(key in o1) {
10035
- if (key.charAt(0) !== '$' && !isFunction(o1[key]) && !equals(o1[key], o2[key])) {
10036
- return false;
10037
- }
10075
+ if (key.charAt(0) === '$' || isFunction(o1[key])) continue;
10076
+ if (!equals(o1[key], o2[key])) return false;
10038
10077
  keySet[key] = true;
10039
10078
  }
10040
10079
  for(key in o2) {
10041
- if (!keySet[key] && key.charAt(0) !== '$' && !isFunction(o2[key])) return false;
10080
+ if (!keySet[key] &&
10081
+ key.charAt(0) !== '$' &&
10082
+ o2[key] !== undefined &&
10083
+ !isFunction(o2[key])) return false;
10042
10084
  }
10043
10085
  return true;
10044
10086
  }
@@ -10064,7 +10106,7 @@ function sliceArgs(args, startIndex) {
10064
10106
  *
10065
10107
  * @description
10066
10108
  * Returns a function which calls function `fn` bound to `self` (`self` becomes the `this` for
10067
- * `fn`). You can supply optional `args` that are are prebound to the function. This feature is also
10109
+ * `fn`). You can supply optional `args` that are prebound to the function. This feature is also
10068
10110
  * known as [function currying](http://en.wikipedia.org/wiki/Currying).
10069
10111
  *
10070
10112
  * @param {Object} self Context which `fn` should be evaluated in.
@@ -10165,9 +10207,18 @@ function startingTag(element) {
10165
10207
  // are not allowed to have children. So we just ignore it.
10166
10208
  element.html('');
10167
10209
  } catch(e) {}
10168
- return jqLite('<div>').append(element).html().
10169
- match(/^(<[^>]+>)/)[1].
10170
- replace(/^<([\w\-]+)/, function(match, nodeName) { return '<' + lowercase(nodeName); });
10210
+ // As Per DOM Standards
10211
+ var TEXT_NODE = 3;
10212
+ var elemHtml = jqLite('<div>').append(element).html();
10213
+ try {
10214
+ return element[0].nodeType === TEXT_NODE ? lowercase(elemHtml) :
10215
+ elemHtml.
10216
+ match(/^(<[^>]+>)/)[1].
10217
+ replace(/^<([\w\-]+)/, function(match, nodeName) { return '<' + lowercase(nodeName); });
10218
+ } catch(e) {
10219
+ return lowercase(elemHtml);
10220
+ }
10221
+
10171
10222
  }
10172
10223
 
10173
10224
 
@@ -10234,7 +10285,7 @@ function encodeUriQuery(val, pctEncodeSpaces) {
10234
10285
  replace(/%3A/gi, ':').
10235
10286
  replace(/%24/g, '$').
10236
10287
  replace(/%2C/gi, ',').
10237
- replace((pctEncodeSpaces ? null : /%20/g), '+');
10288
+ replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
10238
10289
  }
10239
10290
 
10240
10291
 
@@ -10248,10 +10299,10 @@ function encodeUriQuery(val, pctEncodeSpaces) {
10248
10299
  *
10249
10300
  * @description
10250
10301
  *
10251
- * Use this directive to auto-bootstrap on application. Only
10302
+ * Use this directive to auto-bootstrap an application. Only
10252
10303
  * one directive can be used per HTML document. The directive
10253
10304
  * designates the root of the application and is typically placed
10254
- * ot the root of the page.
10305
+ * at the root of the page.
10255
10306
  *
10256
10307
  * In the example below if the `ngApp` directive would not be placed
10257
10308
  * on the `html` element then the document would not be compiled
@@ -10323,22 +10374,38 @@ function angularInit(element, bootstrap) {
10323
10374
  * @returns {AUTO.$injector} Returns the newly created injector for this app.
10324
10375
  */
10325
10376
  function bootstrap(element, modules) {
10326
- element = jqLite(element);
10327
- modules = modules || [];
10328
- modules.unshift(['$provide', function($provide) {
10329
- $provide.value('$rootElement', element);
10330
- }]);
10331
- modules.unshift('ng');
10332
- var injector = createInjector(modules);
10333
- injector.invoke(
10334
- ['$rootScope', '$rootElement', '$compile', '$injector', function(scope, element, compile, injector){
10335
- scope.$apply(function() {
10336
- element.data('$injector', injector);
10337
- compile(element)(scope);
10338
- });
10339
- }]
10340
- );
10341
- return injector;
10377
+ var resumeBootstrapInternal = function() {
10378
+ element = jqLite(element);
10379
+ modules = modules || [];
10380
+ modules.unshift(['$provide', function($provide) {
10381
+ $provide.value('$rootElement', element);
10382
+ }]);
10383
+ modules.unshift('ng');
10384
+ var injector = createInjector(modules);
10385
+ injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector',
10386
+ function(scope, element, compile, injector) {
10387
+ scope.$apply(function() {
10388
+ element.data('$injector', injector);
10389
+ compile(element)(scope);
10390
+ });
10391
+ }]
10392
+ );
10393
+ return injector;
10394
+ };
10395
+
10396
+ var NG_DEFER_BOOTSTRAP = /^NG_DEFER_BOOTSTRAP!/;
10397
+
10398
+ if (window && !NG_DEFER_BOOTSTRAP.test(window.name)) {
10399
+ return resumeBootstrapInternal();
10400
+ }
10401
+
10402
+ window.name = window.name.replace(NG_DEFER_BOOTSTRAP, '');
10403
+ angular.resumeBootstrap = function(extraModules) {
10404
+ forEach(extraModules, function(module) {
10405
+ modules.push(module);
10406
+ });
10407
+ resumeBootstrapInternal();
10408
+ };
10342
10409
  }
10343
10410
 
10344
10411
  var SNAKE_CASE_REGEXP = /[A-Z]/g;
@@ -10371,7 +10438,7 @@ function bindJQuery() {
10371
10438
  }
10372
10439
 
10373
10440
  /**
10374
- * throw error of the argument is falsy.
10441
+ * throw error if the argument is falsy.
10375
10442
  */
10376
10443
  function assertArg(arg, name, reason) {
10377
10444
  if (!arg) {
@@ -10652,11 +10719,11 @@ function setupModuleLoader(window) {
10652
10719
  * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
10653
10720
  */
10654
10721
  var version = {
10655
- full: '1.0.3', // all of these placeholder strings will be replaced by rake's
10656
- major: 1, // compile task
10722
+ full: '1.0.7', // all of these placeholder strings will be replaced by grunt's
10723
+ major: 1, // package task
10657
10724
  minor: 0,
10658
- dot: 3,
10659
- codeName: 'bouncy-thunder'
10725
+ dot: 7,
10726
+ codeName: 'monochromatic-rainbow'
10660
10727
  };
10661
10728
 
10662
10729
 
@@ -10801,18 +10868,18 @@ function publishExternalAPI(angular){
10801
10868
  * - [after()](http://api.jquery.com/after/)
10802
10869
  * - [append()](http://api.jquery.com/append/)
10803
10870
  * - [attr()](http://api.jquery.com/attr/)
10804
- * - [bind()](http://api.jquery.com/bind/)
10805
- * - [children()](http://api.jquery.com/children/)
10871
+ * - [bind()](http://api.jquery.com/bind/) - Does not support namespaces
10872
+ * - [children()](http://api.jquery.com/children/) - Does not support selectors
10806
10873
  * - [clone()](http://api.jquery.com/clone/)
10807
10874
  * - [contents()](http://api.jquery.com/contents/)
10808
10875
  * - [css()](http://api.jquery.com/css/)
10809
10876
  * - [data()](http://api.jquery.com/data/)
10810
10877
  * - [eq()](http://api.jquery.com/eq/)
10811
- * - [find()](http://api.jquery.com/find/) - Limited to lookups by tag name.
10878
+ * - [find()](http://api.jquery.com/find/) - Limited to lookups by tag name
10812
10879
  * - [hasClass()](http://api.jquery.com/hasClass/)
10813
10880
  * - [html()](http://api.jquery.com/html/)
10814
- * - [next()](http://api.jquery.com/next/)
10815
- * - [parent()](http://api.jquery.com/parent/)
10881
+ * - [next()](http://api.jquery.com/next/) - Does not support selectors
10882
+ * - [parent()](http://api.jquery.com/parent/) - Does not support selectors
10816
10883
  * - [prepend()](http://api.jquery.com/prepend/)
10817
10884
  * - [prop()](http://api.jquery.com/prop/)
10818
10885
  * - [ready()](http://api.jquery.com/ready/)
@@ -10824,11 +10891,11 @@ function publishExternalAPI(angular){
10824
10891
  * - [text()](http://api.jquery.com/text/)
10825
10892
  * - [toggleClass()](http://api.jquery.com/toggleClass/)
10826
10893
  * - [triggerHandler()](http://api.jquery.com/triggerHandler/) - Doesn't pass native event objects to handlers.
10827
- * - [unbind()](http://api.jquery.com/unbind/)
10894
+ * - [unbind()](http://api.jquery.com/unbind/) - Does not support namespaces
10828
10895
  * - [val()](http://api.jquery.com/val/)
10829
10896
  * - [wrap()](http://api.jquery.com/wrap/)
10830
10897
  *
10831
- * ## In addtion to the above, Angular privides an additional method to both jQuery and jQuery lite:
10898
+ * ## In addtion to the above, Angular provides additional methods to both jQuery and jQuery lite:
10832
10899
  *
10833
10900
  * - `controller(name)` - retrieves the controller of the current element or its parent. By default
10834
10901
  * retrieves controller associated with the `ngController` directive. If `name` is provided as
@@ -11371,23 +11438,43 @@ forEach({
11371
11438
 
11372
11439
  if (!eventFns) {
11373
11440
  if (type == 'mouseenter' || type == 'mouseleave') {
11374
- var counter = 0;
11441
+ var contains = document.body.contains || document.body.compareDocumentPosition ?
11442
+ function( a, b ) {
11443
+ var adown = a.nodeType === 9 ? a.documentElement : a,
11444
+ bup = b && b.parentNode;
11445
+ return a === bup || !!( bup && bup.nodeType === 1 && (
11446
+ adown.contains ?
11447
+ adown.contains( bup ) :
11448
+ a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
11449
+ ));
11450
+ } :
11451
+ function( a, b ) {
11452
+ if ( b ) {
11453
+ while ( (b = b.parentNode) ) {
11454
+ if ( b === a ) {
11455
+ return true;
11456
+ }
11457
+ }
11458
+ }
11459
+ return false;
11460
+ };
11375
11461
 
11376
- events.mouseenter = [];
11377
- events.mouseleave = [];
11462
+ events[type] = [];
11463
+
11464
+ // Refer to jQuery's implementation of mouseenter & mouseleave
11465
+ // Read about mouseenter and mouseleave:
11466
+ // http://www.quirksmode.org/js/events_mouse.html#link8
11467
+ var eventmap = { mouseleave : "mouseout", mouseenter : "mouseover"}
11468
+ bindFn(element, eventmap[type], function(event) {
11469
+ var ret, target = this, related = event.relatedTarget;
11470
+ // For mousenter/leave call the handler if related is outside the target.
11471
+ // NB: No relatedTarget if the mouse left/entered the browser window
11472
+ if ( !related || (related !== target && !contains(target, related)) ){
11473
+ handle(event, type);
11474
+ }
11378
11475
 
11379
- bindFn(element, 'mouseover', function(event) {
11380
- counter++;
11381
- if (counter == 1) {
11382
- handle(event, 'mouseenter');
11383
- }
11384
- });
11385
- bindFn(element, 'mouseout', function(event) {
11386
- counter --;
11387
- if (counter == 0) {
11388
- handle(event, 'mouseleave');
11389
- }
11390
11476
  });
11477
+
11391
11478
  } else {
11392
11479
  addEventListenerFn(element, type, handle);
11393
11480
  events[type] = [];
@@ -11416,14 +11503,14 @@ forEach({
11416
11503
  children: function(element) {
11417
11504
  var children = [];
11418
11505
  forEach(element.childNodes, function(element){
11419
- if (element.nodeName != '#text')
11506
+ if (element.nodeType === 1)
11420
11507
  children.push(element);
11421
11508
  });
11422
11509
  return children;
11423
11510
  },
11424
11511
 
11425
11512
  contents: function(element) {
11426
- return element.childNodes;
11513
+ return element.childNodes || [];
11427
11514
  },
11428
11515
 
11429
11516
  append: function(element, node) {
@@ -11486,7 +11573,16 @@ forEach({
11486
11573
  },
11487
11574
 
11488
11575
  next: function(element) {
11489
- return element.nextSibling;
11576
+ if (element.nextElementSibling) {
11577
+ return element.nextElementSibling;
11578
+ }
11579
+
11580
+ // IE8 doesn't have nextElementSibling
11581
+ var elm = element.nextSibling;
11582
+ while (elm != null && elm.nodeType !== 1) {
11583
+ elm = elm.nextSibling;
11584
+ }
11585
+ return elm;
11490
11586
  },
11491
11587
 
11492
11588
  find: function(element, selector) {
@@ -11694,7 +11790,7 @@ function annotate(fn) {
11694
11790
  }
11695
11791
  } else if (isArray(fn)) {
11696
11792
  last = fn.length - 1;
11697
- assertArgFn(fn[last], 'fn')
11793
+ assertArgFn(fn[last], 'fn');
11698
11794
  $inject = fn.slice(0, last);
11699
11795
  } else {
11700
11796
  assertArgFn(fn, 'fn', true);
@@ -11728,19 +11824,19 @@ function annotate(fn) {
11728
11824
  * # Injection Function Annotation
11729
11825
  *
11730
11826
  * JavaScript does not have annotations, and annotations are needed for dependency injection. The
11731
- * following ways are all valid way of annotating function with injection arguments and are equivalent.
11827
+ * following are all valid ways of annotating function with injection arguments and are equivalent.
11732
11828
  *
11733
11829
  * <pre>
11734
11830
  * // inferred (only works if code not minified/obfuscated)
11735
- * $inject.invoke(function(serviceA){});
11831
+ * $injector.invoke(function(serviceA){});
11736
11832
  *
11737
11833
  * // annotated
11738
11834
  * function explicit(serviceA) {};
11739
11835
  * explicit.$inject = ['serviceA'];
11740
- * $inject.invoke(explicit);
11836
+ * $injector.invoke(explicit);
11741
11837
  *
11742
11838
  * // inline
11743
- * $inject.invoke(['serviceA', function(serviceA){}]);
11839
+ * $injector.invoke(['serviceA', function(serviceA){}]);
11744
11840
  * </pre>
11745
11841
  *
11746
11842
  * ## Inference
@@ -11824,7 +11920,7 @@ function annotate(fn) {
11824
11920
  * This method does not work with code minfication / obfuscation. For this reason the following annotation strategies
11825
11921
  * are supported.
11826
11922
  *
11827
- * # The `$injector` property
11923
+ * # The `$inject` property
11828
11924
  *
11829
11925
  * If a function has an `$inject` property and its value is an array of strings, then the strings represent names of
11830
11926
  * services to be injected into the function.
@@ -11857,7 +11953,7 @@ function annotate(fn) {
11857
11953
  * // ...
11858
11954
  * };
11859
11955
  * tmpFn.$inject = ['$compile', '$rootScope'];
11860
- * injector.invoke(tempFn);
11956
+ * injector.invoke(tmpFn);
11861
11957
  *
11862
11958
  * // To better support inline function the inline annotation is supported
11863
11959
  * injector.invoke(['$compile', '$rootScope', function(obfCompile, obfRootScope) {
@@ -11886,7 +11982,7 @@ function annotate(fn) {
11886
11982
  * @description
11887
11983
  *
11888
11984
  * Use `$provide` to register new providers with the `$injector`. The providers are the factories for the instance.
11889
- * The providers share the same name as the instance they create with the `Provider` suffixed to them.
11985
+ * The providers share the same name as the instance they create with `Provider` suffixed to them.
11890
11986
  *
11891
11987
  * A provider is an object with a `$get()` method. The injector calls the `$get` method to create a new instance of
11892
11988
  * a service. The Provider can have additional methods which would allow for configuration of the provider.
@@ -11910,7 +12006,7 @@ function annotate(fn) {
11910
12006
  *
11911
12007
  * beforeEach(module(function($provide) {
11912
12008
  * $provide.provider('greet', GreetProvider);
11913
- * });
12009
+ * }));
11914
12010
  *
11915
12011
  * it('should greet', inject(function(greet) {
11916
12012
  * expect(greet('angular')).toEqual('Hello angular!');
@@ -11923,9 +12019,7 @@ function annotate(fn) {
11923
12019
  * inject(function(greet) {
11924
12020
  * expect(greet('angular')).toEqual('Ahoj angular!');
11925
12021
  * });
11926
- * )};
11927
- *
11928
- * });
12022
+ * });
11929
12023
  * </pre>
11930
12024
  */
11931
12025
 
@@ -12019,7 +12113,7 @@ function annotate(fn) {
12019
12113
  *
12020
12114
  * @param {string} name The name of the service to decorate.
12021
12115
  * @param {function()} decorator This function will be invoked when the service needs to be
12022
- * instanciated. The function is called using the {@link AUTO.$injector#invoke
12116
+ * instantiated. The function is called using the {@link AUTO.$injector#invoke
12023
12117
  * injector.invoke} method and is therefore fully injectable. Local injection arguments:
12024
12118
  *
12025
12119
  * * `$delegate` - The original service instance, which can be monkey patched, configured,
@@ -12072,7 +12166,7 @@ function createInjector(modulesToLoad) {
12072
12166
  }
12073
12167
 
12074
12168
  function provider(name, provider_) {
12075
- if (isFunction(provider_)) {
12169
+ if (isFunction(provider_) || isArray(provider_)) {
12076
12170
  provider_ = providerInjector.instantiate(provider_);
12077
12171
  }
12078
12172
  if (!provider_.$get) {
@@ -12189,7 +12283,7 @@ function createInjector(modulesToLoad) {
12189
12283
  args.push(
12190
12284
  locals && locals.hasOwnProperty(key)
12191
12285
  ? locals[key]
12192
- : getService(key, path)
12286
+ : getService(key)
12193
12287
  );
12194
12288
  }
12195
12289
  if (!fn.$inject) {
@@ -12219,6 +12313,8 @@ function createInjector(modulesToLoad) {
12219
12313
  var Constructor = function() {},
12220
12314
  instance, returnedValue;
12221
12315
 
12316
+ // Check if Type is annotated and use just the given function at n-1 as parameter
12317
+ // e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]);
12222
12318
  Constructor.prototype = (isArray(Type) ? Type[Type.length - 1] : Type).prototype;
12223
12319
  instance = new Constructor();
12224
12320
  returnedValue = invoke(Type, instance, locals);
@@ -12234,6 +12330,7 @@ function createInjector(modulesToLoad) {
12234
12330
  };
12235
12331
  }
12236
12332
  }
12333
+
12237
12334
  /**
12238
12335
  * @ngdoc function
12239
12336
  * @name ng.$anchorScroll
@@ -12289,7 +12386,7 @@ function $AnchorScrollProvider() {
12289
12386
  }
12290
12387
 
12291
12388
  // does not scroll when user clicks on anchor link that is currently on
12292
- // (no url change, no $locaiton.hash() change), browser native does scroll
12389
+ // (no url change, no $location.hash() change), browser native does scroll
12293
12390
  if (autoScrollingEnabled) {
12294
12391
  $rootScope.$watch(function autoScrollWatch() {return $location.hash();},
12295
12392
  function autoScrollWatchAction() {
@@ -12538,7 +12635,7 @@ function Browser(window, document, $log, $sniffer) {
12538
12635
  */
12539
12636
  self.baseHref = function() {
12540
12637
  var href = baseElement.attr('href');
12541
- return href ? href.replace(/^https?\:\/\/[^\/]*/, '') : href;
12638
+ return href ? href.replace(/^https?\:\/\/[^\/]*/, '') : '';
12542
12639
  };
12543
12640
 
12544
12641
  //////////////////////////////////////////////////////////////
@@ -12577,14 +12674,15 @@ function Browser(window, document, $log, $sniffer) {
12577
12674
  } else {
12578
12675
  if (isString(value)) {
12579
12676
  cookieLength = (rawDocument.cookie = escape(name) + '=' + escape(value) + ';path=' + cookiePath).length + 1;
12677
+
12678
+ // per http://www.ietf.org/rfc/rfc2109.txt browser must allow at minimum:
12679
+ // - 300 cookies
12680
+ // - 20 cookies per unique domain
12681
+ // - 4096 bytes per cookie
12580
12682
  if (cookieLength > 4096) {
12581
12683
  $log.warn("Cookie '"+ name +"' possibly not set or overflowed because it was too large ("+
12582
12684
  cookieLength + " > 4096 bytes)!");
12583
12685
  }
12584
- if (lastCookies.length > 20) {
12585
- $log.warn("Cookie '"+ name +"' possibly not set or overflowed because too many cookies " +
12586
- "were already set (" + lastCookies.length + " > 20 )");
12587
- }
12588
12686
  }
12589
12687
  }
12590
12688
  } else {
@@ -12597,7 +12695,13 @@ function Browser(window, document, $log, $sniffer) {
12597
12695
  cookie = cookieArray[i];
12598
12696
  index = cookie.indexOf('=');
12599
12697
  if (index > 0) { //ignore nameless cookies
12600
- lastCookies[unescape(cookie.substring(0, index))] = unescape(cookie.substring(index + 1));
12698
+ var name = unescape(cookie.substring(0, index));
12699
+ // the first value that is seen for a cookie is the most
12700
+ // specific one. values for the same cookie name that
12701
+ // follow are for less specific paths.
12702
+ if (lastCookies[name] === undefined) {
12703
+ lastCookies[name] = unescape(cookie.substring(index + 1));
12704
+ }
12601
12705
  }
12602
12706
  }
12603
12707
  }
@@ -12661,6 +12765,7 @@ function $BrowserProvider(){
12661
12765
  return new Browser($window, $document, $log, $sniffer);
12662
12766
  }];
12663
12767
  }
12768
+
12664
12769
  /**
12665
12770
  * @ngdoc object
12666
12771
  * @name ng.$cacheFactory
@@ -12987,7 +13092,8 @@ function $CompileProvider($provide) {
12987
13092
  Suffix = 'Directive',
12988
13093
  COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\d\w\-_]+)\s+(.*)$/,
12989
13094
  CLASS_DIRECTIVE_REGEXP = /(([\d\w\-_]+)(?:\:([^;]+))?;?)/,
12990
- MULTI_ROOT_TEMPLATE_ERROR = 'Template must have exactly one root element. was: ';
13095
+ MULTI_ROOT_TEMPLATE_ERROR = 'Template must have exactly one root element. was: ',
13096
+ urlSanitizationWhitelist = /^\s*(https?|ftp|mailto|file):/;
12991
13097
 
12992
13098
 
12993
13099
  /**
@@ -13041,11 +13147,41 @@ function $CompileProvider($provide) {
13041
13147
  };
13042
13148
 
13043
13149
 
13150
+ /**
13151
+ * @ngdoc function
13152
+ * @name ng.$compileProvider#urlSanitizationWhitelist
13153
+ * @methodOf ng.$compileProvider
13154
+ * @function
13155
+ *
13156
+ * @description
13157
+ * Retrieves or overrides the default regular expression that is used for whitelisting of safe
13158
+ * urls during a[href] sanitization.
13159
+ *
13160
+ * The sanitization is a security measure aimed at prevent XSS attacks via html links.
13161
+ *
13162
+ * Any url about to be assigned to a[href] via data-binding is first normalized and turned into an
13163
+ * absolute url. Afterwards the url is matched against the `urlSanitizationWhitelist` regular
13164
+ * expression. If a match is found the original url is written into the dom. Otherwise the
13165
+ * absolute url is prefixed with `'unsafe:'` string and only then it is written into the DOM.
13166
+ *
13167
+ * @param {RegExp=} regexp New regexp to whitelist urls with.
13168
+ * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
13169
+ * chaining otherwise.
13170
+ */
13171
+ this.urlSanitizationWhitelist = function(regexp) {
13172
+ if (isDefined(regexp)) {
13173
+ urlSanitizationWhitelist = regexp;
13174
+ return this;
13175
+ }
13176
+ return urlSanitizationWhitelist;
13177
+ };
13178
+
13179
+
13044
13180
  this.$get = [
13045
13181
  '$injector', '$interpolate', '$exceptionHandler', '$http', '$templateCache', '$parse',
13046
- '$controller', '$rootScope',
13182
+ '$controller', '$rootScope', '$document',
13047
13183
  function($injector, $interpolate, $exceptionHandler, $http, $templateCache, $parse,
13048
- $controller, $rootScope) {
13184
+ $controller, $rootScope, $document) {
13049
13185
 
13050
13186
  var Attributes = function(element, attr) {
13051
13187
  this.$$element = element;
@@ -13067,7 +13203,8 @@ function $CompileProvider($provide) {
13067
13203
  */
13068
13204
  $set: function(key, value, writeAttr, attrName) {
13069
13205
  var booleanKey = getBooleanAttrName(this.$$element[0], key),
13070
- $$observers = this.$$observers;
13206
+ $$observers = this.$$observers,
13207
+ normalizedVal;
13071
13208
 
13072
13209
  if (booleanKey) {
13073
13210
  this.$$element.prop(key, value);
@@ -13086,6 +13223,19 @@ function $CompileProvider($provide) {
13086
13223
  }
13087
13224
  }
13088
13225
 
13226
+
13227
+ // sanitize a[href] values
13228
+ if (nodeName_(this.$$element[0]) === 'A' && key === 'href') {
13229
+ urlSanitizationNode.setAttribute('href', value);
13230
+
13231
+ // href property always returns normalized absolute url, so we can match against that
13232
+ normalizedVal = urlSanitizationNode.href;
13233
+ if (!normalizedVal.match(urlSanitizationWhitelist)) {
13234
+ this[key] = value = 'unsafe:' + normalizedVal;
13235
+ }
13236
+ }
13237
+
13238
+
13089
13239
  if (writeAttr !== false) {
13090
13240
  if (value === null || value === undefined) {
13091
13241
  this.$$element.removeAttr(attrName);
@@ -13129,7 +13279,8 @@ function $CompileProvider($provide) {
13129
13279
  }
13130
13280
  };
13131
13281
 
13132
- var startSymbol = $interpolate.startSymbol(),
13282
+ var urlSanitizationNode = $document[0].createElement('a'),
13283
+ startSymbol = $interpolate.startSymbol(),
13133
13284
  endSymbol = $interpolate.endSymbol(),
13134
13285
  denormalizeTemplate = (startSymbol == '{{' || endSymbol == '}}')
13135
13286
  ? identity
@@ -13144,13 +13295,13 @@ function $CompileProvider($provide) {
13144
13295
 
13145
13296
  function compile($compileNodes, transcludeFn, maxPriority) {
13146
13297
  if (!($compileNodes instanceof jqLite)) {
13147
- // jquery always rewraps, where as we need to preserve the original selector so that we can modify it.
13298
+ // jquery always rewraps, whereas we need to preserve the original selector so that we can modify it.
13148
13299
  $compileNodes = jqLite($compileNodes);
13149
13300
  }
13150
13301
  // We can not compile top level text elements since text nodes can be merged and we will
13151
13302
  // not be able to attach scope data to them, so we will wrap them in <span>
13152
13303
  forEach($compileNodes, function(node, index){
13153
- if (node.nodeType == 3 /* text node */) {
13304
+ if (node.nodeType == 3 /* text node */ && node.nodeValue.match(/\S+/) /* non-empty */ ) {
13154
13305
  $compileNodes[index] = jqLite(node).wrap('<span></span>').parent()[0];
13155
13306
  }
13156
13307
  });
@@ -13162,7 +13313,14 @@ function $CompileProvider($provide) {
13162
13313
  var $linkNode = cloneConnectFn
13163
13314
  ? JQLitePrototype.clone.call($compileNodes) // IMPORTANT!!!
13164
13315
  : $compileNodes;
13165
- $linkNode.data('$scope', scope);
13316
+
13317
+ // Attach scope only to non-text nodes.
13318
+ for(var i = 0, ii = $linkNode.length; i<ii; i++) {
13319
+ var node = $linkNode[i];
13320
+ if (node.nodeType == 1 /* element */ || node.nodeType == 9 /* document */) {
13321
+ $linkNode.eq(i).data('$scope', scope);
13322
+ }
13323
+ }
13166
13324
  safeAddClass($linkNode, 'ng-scope');
13167
13325
  if (cloneConnectFn) cloneConnectFn($linkNode, scope);
13168
13326
  if (compositeLinkFn) compositeLinkFn(scope, $linkNode, $linkNode);
@@ -13189,7 +13347,7 @@ function $CompileProvider($provide) {
13189
13347
  * functions return values - the linking functions - are combined into a composite linking
13190
13348
  * function, which is the a linking function for the node.
13191
13349
  *
13192
- * @param {NodeList} nodeList an array of nodes to compile
13350
+ * @param {NodeList} nodeList an array of nodes or NodeList to compile
13193
13351
  * @param {function(angular.Scope[, cloneAttachFn]} transcludeFn A linking function, where the
13194
13352
  * scope argument is auto-generated to the new child of the transcluded parent scope.
13195
13353
  * @param {DOMElement=} $rootElement If the nodeList is the root of the compilation tree then the
@@ -13199,68 +13357,75 @@ function $CompileProvider($provide) {
13199
13357
  * @returns {?function} A composite linking function of all of the matched directives or null.
13200
13358
  */
13201
13359
  function compileNodes(nodeList, transcludeFn, $rootElement, maxPriority) {
13202
- var linkFns = [],
13203
- nodeLinkFn, childLinkFn, directives, attrs, linkFnFound;
13360
+ var linkFns = [],
13361
+ nodeLinkFn, childLinkFn, directives, attrs, linkFnFound;
13204
13362
 
13205
- for(var i = 0; i < nodeList.length; i++) {
13206
- attrs = new Attributes();
13363
+ for(var i = 0; i < nodeList.length; i++) {
13364
+ attrs = new Attributes();
13207
13365
 
13208
- // we must always refer to nodeList[i] since the nodes can be replaced underneath us.
13209
- directives = collectDirectives(nodeList[i], [], attrs, maxPriority);
13366
+ // we must always refer to nodeList[i] since the nodes can be replaced underneath us.
13367
+ directives = collectDirectives(nodeList[i], [], attrs, maxPriority);
13210
13368
 
13211
- nodeLinkFn = (directives.length)
13212
- ? applyDirectivesToNode(directives, nodeList[i], attrs, transcludeFn, $rootElement)
13213
- : null;
13369
+ nodeLinkFn = (directives.length)
13370
+ ? applyDirectivesToNode(directives, nodeList[i], attrs, transcludeFn, $rootElement)
13371
+ : null;
13214
13372
 
13215
- childLinkFn = (nodeLinkFn && nodeLinkFn.terminal || !nodeList[i].childNodes.length)
13216
- ? null
13217
- : compileNodes(nodeList[i].childNodes,
13218
- nodeLinkFn ? nodeLinkFn.transclude : transcludeFn);
13373
+ childLinkFn = (nodeLinkFn && nodeLinkFn.terminal || !nodeList[i].childNodes || !nodeList[i].childNodes.length)
13374
+ ? null
13375
+ : compileNodes(nodeList[i].childNodes,
13376
+ nodeLinkFn ? nodeLinkFn.transclude : transcludeFn);
13219
13377
 
13220
- linkFns.push(nodeLinkFn);
13221
- linkFns.push(childLinkFn);
13222
- linkFnFound = (linkFnFound || nodeLinkFn || childLinkFn);
13223
- }
13378
+ linkFns.push(nodeLinkFn);
13379
+ linkFns.push(childLinkFn);
13380
+ linkFnFound = (linkFnFound || nodeLinkFn || childLinkFn);
13381
+ }
13224
13382
 
13225
- // return a linking function if we have found anything, null otherwise
13226
- return linkFnFound ? compositeLinkFn : null;
13383
+ // return a linking function if we have found anything, null otherwise
13384
+ return linkFnFound ? compositeLinkFn : null;
13227
13385
 
13228
- function compositeLinkFn(scope, nodeList, $rootElement, boundTranscludeFn) {
13229
- var nodeLinkFn, childLinkFn, node, childScope, childTranscludeFn;
13386
+ function compositeLinkFn(scope, nodeList, $rootElement, boundTranscludeFn) {
13387
+ var nodeLinkFn, childLinkFn, node, childScope, childTranscludeFn, i, ii, n;
13230
13388
 
13231
- for(var i = 0, n = 0, ii = linkFns.length; i < ii; n++) {
13232
- node = nodeList[n];
13233
- nodeLinkFn = linkFns[i++];
13234
- childLinkFn = linkFns[i++];
13389
+ // copy nodeList so that linking doesn't break due to live list updates.
13390
+ var stableNodeList = [];
13391
+ for (i = 0, ii = nodeList.length; i < ii; i++) {
13392
+ stableNodeList.push(nodeList[i]);
13393
+ }
13235
13394
 
13236
- if (nodeLinkFn) {
13237
- if (nodeLinkFn.scope) {
13238
- childScope = scope.$new(isObject(nodeLinkFn.scope));
13239
- jqLite(node).data('$scope', childScope);
13240
- } else {
13241
- childScope = scope;
13242
- }
13243
- childTranscludeFn = nodeLinkFn.transclude;
13244
- if (childTranscludeFn || (!boundTranscludeFn && transcludeFn)) {
13245
- nodeLinkFn(childLinkFn, childScope, node, $rootElement,
13246
- (function(transcludeFn) {
13247
- return function(cloneFn) {
13248
- var transcludeScope = scope.$new();
13249
-
13250
- return transcludeFn(transcludeScope, cloneFn).
13251
- bind('$destroy', bind(transcludeScope, transcludeScope.$destroy));
13395
+ for(i = 0, n = 0, ii = linkFns.length; i < ii; n++) {
13396
+ node = stableNodeList[n];
13397
+ nodeLinkFn = linkFns[i++];
13398
+ childLinkFn = linkFns[i++];
13399
+
13400
+ if (nodeLinkFn) {
13401
+ if (nodeLinkFn.scope) {
13402
+ childScope = scope.$new(isObject(nodeLinkFn.scope));
13403
+ jqLite(node).data('$scope', childScope);
13404
+ } else {
13405
+ childScope = scope;
13406
+ }
13407
+ childTranscludeFn = nodeLinkFn.transclude;
13408
+ if (childTranscludeFn || (!boundTranscludeFn && transcludeFn)) {
13409
+ nodeLinkFn(childLinkFn, childScope, node, $rootElement,
13410
+ (function(transcludeFn) {
13411
+ return function(cloneFn) {
13412
+ var transcludeScope = scope.$new();
13413
+ transcludeScope.$$transcluded = true;
13414
+
13415
+ return transcludeFn(transcludeScope, cloneFn).
13416
+ bind('$destroy', bind(transcludeScope, transcludeScope.$destroy));
13252
13417
  };
13253
13418
  })(childTranscludeFn || transcludeFn)
13254
- );
13255
- } else {
13256
- nodeLinkFn(childLinkFn, childScope, node, undefined, boundTranscludeFn);
13257
- }
13258
- } else if (childLinkFn) {
13259
- childLinkFn(scope, node.childNodes, undefined, boundTranscludeFn);
13260
- }
13261
- }
13262
- }
13263
- }
13419
+ );
13420
+ } else {
13421
+ nodeLinkFn(childLinkFn, childScope, node, undefined, boundTranscludeFn);
13422
+ }
13423
+ } else if (childLinkFn) {
13424
+ childLinkFn(scope, node.childNodes, undefined, boundTranscludeFn);
13425
+ }
13426
+ }
13427
+ }
13428
+ }
13264
13429
 
13265
13430
 
13266
13431
  /**
@@ -13341,9 +13506,9 @@ function $CompileProvider($provide) {
13341
13506
 
13342
13507
 
13343
13508
  /**
13344
- * Once the directives have been collected their compile functions is executed. This method
13509
+ * Once the directives have been collected, their compile functions are executed. This method
13345
13510
  * is responsible for inlining directive templates as well as terminating the application
13346
- * of the directives if the terminal directive has been reached..
13511
+ * of the directives if the terminal directive has been reached.
13347
13512
  *
13348
13513
  * @param {Array} directives Array of collected directives to execute their compile function.
13349
13514
  * this needs to be pre-sorted by priority order.
@@ -13351,11 +13516,11 @@ function $CompileProvider($provide) {
13351
13516
  * @param {Object} templateAttrs The shared attribute function
13352
13517
  * @param {function(angular.Scope[, cloneAttachFn]} transcludeFn A linking function, where the
13353
13518
  * scope argument is auto-generated to the new child of the transcluded parent scope.
13354
- * @param {DOMElement} $rootElement If we are working on the root of the compile tree then this
13355
- * argument has the root jqLite array so that we can replace widgets on it.
13519
+ * @param {JQLite} jqCollection If we are working on the root of the compile tree then this
13520
+ * argument has the root jqLite array so that we can replace nodes on it.
13356
13521
  * @returns linkFn
13357
13522
  */
13358
- function applyDirectivesToNode(directives, compileNode, templateAttrs, transcludeFn, $rootElement) {
13523
+ function applyDirectivesToNode(directives, compileNode, templateAttrs, transcludeFn, jqCollection) {
13359
13524
  var terminalPriority = -Number.MAX_VALUE,
13360
13525
  preLinkFns = [],
13361
13526
  postLinkFns = [],
@@ -13407,9 +13572,9 @@ function $CompileProvider($provide) {
13407
13572
  if (directiveValue == 'element') {
13408
13573
  $template = jqLite(compileNode);
13409
13574
  $compileNode = templateAttrs.$$element =
13410
- jqLite('<!-- ' + directiveName + ': ' + templateAttrs[directiveName] + ' -->');
13575
+ jqLite(document.createComment(' ' + directiveName + ': ' + templateAttrs[directiveName] + ' '));
13411
13576
  compileNode = $compileNode[0];
13412
- replaceWith($rootElement, jqLite($template[0]), compileNode);
13577
+ replaceWith(jqCollection, jqLite($template[0]), compileNode);
13413
13578
  childTranscludeFn = compile($template, transcludeFn, terminalPriority);
13414
13579
  } else {
13415
13580
  $template = jqLite(JQLiteClone(compileNode)).contents();
@@ -13433,7 +13598,7 @@ function $CompileProvider($provide) {
13433
13598
  throw new Error(MULTI_ROOT_TEMPLATE_ERROR + directiveValue);
13434
13599
  }
13435
13600
 
13436
- replaceWith($rootElement, $compileNode, compileNode);
13601
+ replaceWith(jqCollection, $compileNode, compileNode);
13437
13602
 
13438
13603
  var newTemplateAttrs = {$attr: {}};
13439
13604
 
@@ -13461,7 +13626,7 @@ function $CompileProvider($provide) {
13461
13626
  assertNoDuplicate('template', templateDirective, directive, $compileNode);
13462
13627
  templateDirective = directive;
13463
13628
  nodeLinkFn = compileTemplateUrl(directives.splice(i, directives.length - i),
13464
- nodeLinkFn, $compileNode, templateAttrs, $rootElement, directive.replace,
13629
+ nodeLinkFn, $compileNode, templateAttrs, jqCollection, directive.replace,
13465
13630
  childTranscludeFn);
13466
13631
  ii = directives.length;
13467
13632
  } else if (directive.compile) {
@@ -13551,6 +13716,8 @@ function $CompileProvider($provide) {
13551
13716
  lastValue,
13552
13717
  parentGet, parentSet;
13553
13718
 
13719
+ scope.$$isolateBindings[scopeName] = mode + attrName;
13720
+
13554
13721
  switch (mode) {
13555
13722
 
13556
13723
  case '@': {
@@ -13592,7 +13759,7 @@ function $CompileProvider($provide) {
13592
13759
  parentGet = $parse(attrs[attrName]);
13593
13760
  scope[scopeName] = function(locals) {
13594
13761
  return parentGet(parentScope, locals);
13595
- }
13762
+ };
13596
13763
  break;
13597
13764
  }
13598
13765
 
@@ -13761,8 +13928,8 @@ function $CompileProvider($provide) {
13761
13928
  }
13762
13929
 
13763
13930
  directives.unshift(derivedSyncDirective);
13764
- afterTemplateNodeLinkFn = applyDirectivesToNode(directives, $compileNode, tAttrs, childTranscludeFn);
13765
- afterTemplateChildLinkFn = compileNodes($compileNode.contents(), childTranscludeFn);
13931
+ afterTemplateNodeLinkFn = applyDirectivesToNode(directives, compileNode, tAttrs, childTranscludeFn);
13932
+ afterTemplateChildLinkFn = compileNodes($compileNode[0].childNodes, childTranscludeFn);
13766
13933
 
13767
13934
 
13768
13935
  while(linkQueue.length) {
@@ -13841,10 +14008,10 @@ function $CompileProvider($provide) {
13841
14008
  function addAttrInterpolateDirective(node, directives, value, name) {
13842
14009
  var interpolateFn = $interpolate(value, true);
13843
14010
 
13844
-
13845
14011
  // no interpolation found -> ignore
13846
14012
  if (!interpolateFn) return;
13847
14013
 
14014
+
13848
14015
  directives.push({
13849
14016
  priority: 100,
13850
14017
  compile: valueFn(function attrInterpolateLinkFn(scope, element, attr) {
@@ -14027,7 +14194,7 @@ function $ControllerProvider() {
14027
14194
  * @description
14028
14195
  * `$controller` service is responsible for instantiating controllers.
14029
14196
  *
14030
- * It's just simple call to {@link AUTO.$injector $injector}, but extracted into
14197
+ * It's just a simple call to {@link AUTO.$injector $injector}, but extracted into
14031
14198
  * a service, so that one can override this service with {@link https://gist.github.com/1649788
14032
14199
  * BC version}.
14033
14200
  */
@@ -14072,14 +14239,15 @@ function $DocumentProvider(){
14072
14239
  * the browser console.
14073
14240
  *
14074
14241
  * In unit tests, if `angular-mocks.js` is loaded, this service is overridden by
14075
- * {@link ngMock.$exceptionHandler mock $exceptionHandler}
14242
+ * {@link ngMock.$exceptionHandler mock $exceptionHandler} which aids in testing.
14076
14243
  *
14077
14244
  * @param {Error} exception Exception associated with the error.
14078
14245
  * @param {string=} cause optional information about the context in which
14079
14246
  * the error was thrown.
14247
+ *
14080
14248
  */
14081
14249
  function $ExceptionHandlerProvider() {
14082
- this.$get = ['$log', function($log){
14250
+ this.$get = ['$log', function($log) {
14083
14251
  return function(exception, cause) {
14084
14252
  $log.error.apply($log, arguments);
14085
14253
  };
@@ -14267,7 +14435,7 @@ function $InterpolateProvider() {
14267
14435
  }];
14268
14436
  }
14269
14437
 
14270
- var URL_MATCH = /^([^:]+):\/\/(\w+:{0,1}\w*@)?([\w\.-]*)(:([0-9]+))?(\/[^\?#]*)?(\?([^#]*))?(#(.*))?$/,
14438
+ var URL_MATCH = /^([^:]+):\/\/(\w+:{0,1}\w*@)?(\{?[\w\.-]*\}?)(:([0-9]+))?(\/[^\?#]*)?(\?([^#]*))?(#(.*))?$/,
14271
14439
  PATH_MATCH = /^([^\?#]*)?(\?([^#]*))?(#(.*))?$/,
14272
14440
  HASH_MATCH = PATH_MATCH,
14273
14441
  DEFAULT_PORTS = {'http': 80, 'https': 443, 'ftp': 21};
@@ -14346,7 +14514,8 @@ function convertToHashbangUrl(url, basePath, hashPrefix) {
14346
14514
  var match = matchUrl(url);
14347
14515
 
14348
14516
  // already hashbang url
14349
- if (decodeURIComponent(match.path) == basePath) {
14517
+ if (decodeURIComponent(match.path) == basePath && !isUndefined(match.hash) &&
14518
+ match.hash.indexOf(hashPrefix) === 0) {
14350
14519
  return url;
14351
14520
  // convert html5 url -> hashbang url
14352
14521
  } else {
@@ -14843,6 +15012,10 @@ function $LocationProvider(){
14843
15012
  // update $location when $browser url changes
14844
15013
  $browser.onUrlChange(function(newUrl) {
14845
15014
  if ($location.absUrl() != newUrl) {
15015
+ if ($rootScope.$broadcast('$locationChangeStart', newUrl, $location.absUrl()).defaultPrevented) {
15016
+ $browser.url($location.absUrl());
15017
+ return;
15018
+ }
14846
15019
  $rootScope.$evalAsync(function() {
14847
15020
  var oldUrl = $location.absUrl();
14848
15021
 
@@ -15151,10 +15324,10 @@ function lex(text, csp){
15151
15324
  function readIdent() {
15152
15325
  var ident = "",
15153
15326
  start = index,
15154
- lastDot, peekIndex, methodName;
15327
+ lastDot, peekIndex, methodName, ch;
15155
15328
 
15156
15329
  while (index < text.length) {
15157
- var ch = text.charAt(index);
15330
+ ch = text.charAt(index);
15158
15331
  if (ch == '.' || isIdent(ch) || isNumber(ch)) {
15159
15332
  if (ch == '.') lastDot = index;
15160
15333
  ident += ch;
@@ -15168,7 +15341,7 @@ function lex(text, csp){
15168
15341
  if (lastDot) {
15169
15342
  peekIndex = index;
15170
15343
  while(peekIndex < text.length) {
15171
- var ch = text.charAt(peekIndex);
15344
+ ch = text.charAt(peekIndex);
15172
15345
  if (ch == '(') {
15173
15346
  methodName = ident.substr(lastDot - start + 1);
15174
15347
  ident = ident.substr(0, lastDot - start);
@@ -15421,8 +15594,8 @@ function parser(text, json, $filter, csp){
15421
15594
  text.substring(0, token.index) + "] can not be assigned to", token);
15422
15595
  }
15423
15596
  right = logicalOR();
15424
- return function(self, locals){
15425
- return left.assign(self, right(self, locals), locals);
15597
+ return function(scope, locals){
15598
+ return left.assign(scope, right(scope, locals), locals);
15426
15599
  };
15427
15600
  } else {
15428
15601
  return left;
@@ -15539,12 +15712,12 @@ function parser(text, json, $filter, csp){
15539
15712
  var field = expect().text;
15540
15713
  var getter = getterFn(field, csp);
15541
15714
  return extend(
15542
- function(self, locals) {
15543
- return getter(object(self, locals), locals);
15715
+ function(scope, locals, self) {
15716
+ return getter(self || object(scope, locals), locals);
15544
15717
  },
15545
15718
  {
15546
- assign:function(self, value, locals) {
15547
- return setter(object(self, locals), field, value);
15719
+ assign:function(scope, value, locals) {
15720
+ return setter(object(scope, locals), field, value);
15548
15721
  }
15549
15722
  }
15550
15723
  );
@@ -15585,14 +15758,14 @@ function parser(text, json, $filter, csp){
15585
15758
  } while (expect(','));
15586
15759
  }
15587
15760
  consume(')');
15588
- return function(self, locals){
15761
+ return function(scope, locals){
15589
15762
  var args = [],
15590
- context = contextGetter ? contextGetter(self, locals) : self;
15763
+ context = contextGetter ? contextGetter(scope, locals) : scope;
15591
15764
 
15592
15765
  for ( var i = 0; i < argsFn.length; i++) {
15593
- args.push(argsFn[i](self, locals));
15766
+ args.push(argsFn[i](scope, locals));
15594
15767
  }
15595
- var fnPtr = fn(self, locals) || noop;
15768
+ var fnPtr = fn(scope, locals, context) || noop;
15596
15769
  // IE stupidity!
15597
15770
  return fnPtr.apply
15598
15771
  ? fnPtr.apply(context, args)
@@ -15634,8 +15807,7 @@ function parser(text, json, $filter, csp){
15634
15807
  var object = {};
15635
15808
  for ( var i = 0; i < keyValues.length; i++) {
15636
15809
  var keyValue = keyValues[i];
15637
- var value = keyValue.value(self, locals);
15638
- object[keyValue.key] = value;
15810
+ object[keyValue.key] = keyValue.value(self, locals);
15639
15811
  }
15640
15812
  return object;
15641
15813
  };
@@ -15757,7 +15929,7 @@ function cspSafeGetterFn(key0, key1, key2, key3, key4) {
15757
15929
  }
15758
15930
  return pathVal;
15759
15931
  };
15760
- };
15932
+ }
15761
15933
 
15762
15934
  function getterFn(path, csp) {
15763
15935
  if (getterFnCache.hasOwnProperty(path)) {
@@ -15772,7 +15944,7 @@ function getterFn(path, csp) {
15772
15944
  fn = (pathKeysLength < 6)
15773
15945
  ? cspSafeGetterFn(pathKeys[0], pathKeys[1], pathKeys[2], pathKeys[3], pathKeys[4])
15774
15946
  : function(scope, locals) {
15775
- var i = 0, val
15947
+ var i = 0, val;
15776
15948
  do {
15777
15949
  val = cspSafeGetterFn(
15778
15950
  pathKeys[i++], pathKeys[i++], pathKeys[i++], pathKeys[i++], pathKeys[i++]
@@ -15837,9 +16009,10 @@ function getterFn(path, csp) {
15837
16009
  * @param {string} expression String expression to compile.
15838
16010
  * @returns {function(context, locals)} a function which represents the compiled expression:
15839
16011
  *
15840
- * * `context`: an object against which any expressions embedded in the strings are evaluated
15841
- * against (Topically a scope object).
15842
- * * `locals`: local variables context object, useful for overriding values in `context`.
16012
+ * * `context` – `{object}` – an object against which any expressions embedded in the strings
16013
+ * are evaluated against (tipically a scope object).
16014
+ * * `locals` – `{object=}` – local variables context object, useful for overriding values in
16015
+ * `context`.
15843
16016
  *
15844
16017
  * The return function also has an `assign` property, if the expression is assignable, which
15845
16018
  * allows one to set values to expressions.
@@ -15875,8 +16048,8 @@ function $ParseProvider() {
15875
16048
  * interface for interacting with an object that represents the result of an action that is
15876
16049
  * performed asynchronously, and may or may not be finished at any given point in time.
15877
16050
  *
15878
- * From the perspective of dealing with error handling, deferred and promise apis are to
15879
- * asynchronous programing what `try`, `catch` and `throw` keywords are to synchronous programing.
16051
+ * From the perspective of dealing with error handling, deferred and promise APIs are to
16052
+ * asynchronous programming what `try`, `catch` and `throw` keywords are to synchronous programming.
15880
16053
  *
15881
16054
  * <pre>
15882
16055
  * // for the purpose of this example let's assume that variables `$q` and `scope` are
@@ -15910,7 +16083,7 @@ function $ParseProvider() {
15910
16083
  *
15911
16084
  * At first it might not be obvious why this extra complexity is worth the trouble. The payoff
15912
16085
  * comes in the way of
15913
- * [guarantees that promise and deferred apis make](https://github.com/kriskowal/uncommonjs/blob/master/promises/specification.md).
16086
+ * [guarantees that promise and deferred APIs make](https://github.com/kriskowal/uncommonjs/blob/master/promises/specification.md).
15914
16087
  *
15915
16088
  * Additionally the promise api allows for composition that is very hard to do with the
15916
16089
  * traditional callback ([CPS](http://en.wikipedia.org/wiki/Continuation-passing_style)) approach.
@@ -15922,7 +16095,7 @@ function $ParseProvider() {
15922
16095
  *
15923
16096
  * A new instance of deferred is constructed by calling `$q.defer()`.
15924
16097
  *
15925
- * The purpose of the deferred object is to expose the associated Promise instance as well as apis
16098
+ * The purpose of the deferred object is to expose the associated Promise instance as well as APIs
15926
16099
  * that can be used for signaling the successful or unsuccessful completion of the task.
15927
16100
  *
15928
16101
  * **Methods**
@@ -15965,7 +16138,7 @@ function $ParseProvider() {
15965
16138
  * return result + 1;
15966
16139
  * });
15967
16140
  *
15968
- * // promiseB will be resolved immediately after promiseA is resolved and it's value will be
16141
+ * // promiseB will be resolved immediately after promiseA is resolved and its value will be
15969
16142
  * // the result of promiseA incremented by 1
15970
16143
  * </pre>
15971
16144
  *
@@ -15984,8 +16157,32 @@ function $ParseProvider() {
15984
16157
  * models and avoiding unnecessary browser repaints, which would result in flickering UI.
15985
16158
  * - $q promises are recognized by the templating engine in angular, which means that in templates
15986
16159
  * you can treat promises attached to a scope as if they were the resulting values.
15987
- * - Q has many more features that $q, but that comes at a cost of bytes. $q is tiny, but contains
16160
+ * - Q has many more features than $q, but that comes at a cost of bytes. $q is tiny, but contains
15988
16161
  * all the important functionality needed for common async tasks.
16162
+ *
16163
+ * # Testing
16164
+ *
16165
+ * <pre>
16166
+ * it('should simulate promise', inject(function($q, $rootScope) {
16167
+ * var deferred = $q.defer();
16168
+ * var promise = deferred.promise;
16169
+ * var resolvedValue;
16170
+ *
16171
+ * promise.then(function(value) { resolvedValue = value; });
16172
+ * expect(resolvedValue).toBeUndefined();
16173
+ *
16174
+ * // Simulate resolving of promise
16175
+ * deferred.resolve(123);
16176
+ * // Note that the 'then' function does not get called synchronously.
16177
+ * // This is because we want the promise API to always be async, whether or not
16178
+ * // it got called synchronously or asynchronously.
16179
+ * expect(resolvedValue).toBeUndefined();
16180
+ *
16181
+ * // Propagate promise resolution to 'then' functions using $apply().
16182
+ * $rootScope.$apply();
16183
+ * expect(resolvedValue).toEqual(123);
16184
+ * });
16185
+ * </pre>
15989
16186
  */
15990
16187
  function $QProvider() {
15991
16188
 
@@ -16151,14 +16348,11 @@ function qFactory(nextTick, exceptionHandler) {
16151
16348
  * @methodOf ng.$q
16152
16349
  * @description
16153
16350
  * Wraps an object that might be a value or a (3rd party) then-able promise into a $q promise.
16154
- * This is useful when you are dealing with on object that might or might not be a promise, or if
16351
+ * This is useful when you are dealing with an object that might or might not be a promise, or if
16155
16352
  * the promise comes from a source that can't be trusted.
16156
16353
  *
16157
16354
  * @param {*} value Value or a promise
16158
- * @returns {Promise} Returns a single promise that will be resolved with an array of values,
16159
- * each value coresponding to the promise at the same index in the `promises` array. If any of
16160
- * the promises is resolved with a rejection, this resulting promise will be resolved with the
16161
- * same rejection.
16355
+ * @returns {Promise} Returns a promise of the passed value or promise
16162
16356
  */
16163
16357
  var when = function(value, callback, errback) {
16164
16358
  var result = defer(),
@@ -16218,7 +16412,7 @@ function qFactory(nextTick, exceptionHandler) {
16218
16412
  *
16219
16413
  * @param {Array.<Promise>} promises An array of promises.
16220
16414
  * @returns {Promise} Returns a single promise that will be resolved with an array of values,
16221
- * each value coresponding to the promise at the same index in the `promises` array. If any of
16415
+ * each value corresponding to the promise at the same index in the `promises` array. If any of
16222
16416
  * the promises is resolved with a rejection, this resulting promise will be resolved with the
16223
16417
  * same rejection.
16224
16418
  */
@@ -16272,8 +16466,13 @@ function $RouteProvider(){
16272
16466
  *
16273
16467
  * @param {string} path Route path (matched against `$location.path`). If `$location.path`
16274
16468
  * contains redundant trailing slash or is missing one, the route will still match and the
16275
- * `$location.path` will be updated to add or drop the trailing slash to exacly match the
16469
+ * `$location.path` will be updated to add or drop the trailing slash to exactly match the
16276
16470
  * route definition.
16471
+ *
16472
+ * `path` can contain named groups starting with a colon (`:name`). All characters up to the
16473
+ * next slash are matched and stored in `$routeParams` under the given `name` when the route
16474
+ * matches.
16475
+ *
16277
16476
  * @param {Object} route Mapping information to be assigned to `$route.current` on route
16278
16477
  * match.
16279
16478
  *
@@ -16510,8 +16709,9 @@ function $RouteProvider(){
16510
16709
  * {@link ng.directive:ngView ngView} listens for the directive
16511
16710
  * to instantiate the controller and render the view.
16512
16711
  *
16712
+ * @param {Object} angularEvent Synthetic event object.
16513
16713
  * @param {Route} current Current route information.
16514
- * @param {Route} previous Previous route information.
16714
+ * @param {Route|Undefined} previous Previous route information, or undefined if current is first route entered.
16515
16715
  */
16516
16716
 
16517
16717
  /**
@@ -16538,8 +16738,7 @@ function $RouteProvider(){
16538
16738
  * instance of the Controller.
16539
16739
  */
16540
16740
 
16541
- var matcher = switchRouteMatcher,
16542
- forceReload = false,
16741
+ var forceReload = false,
16543
16742
  $route = {
16544
16743
  routes: routes,
16545
16744
 
@@ -16567,21 +16766,36 @@ function $RouteProvider(){
16567
16766
 
16568
16767
  /////////////////////////////////////////////////////
16569
16768
 
16769
+ /**
16770
+ * @param on {string} current url
16771
+ * @param when {string} route when template to match the url against
16772
+ * @return {?Object}
16773
+ */
16570
16774
  function switchRouteMatcher(on, when) {
16571
16775
  // TODO(i): this code is convoluted and inefficient, we should construct the route matching
16572
16776
  // regex only once and then reuse it
16573
- var regex = '^' + when.replace(/([\.\\\(\)\^\$])/g, "\\$1") + '$',
16777
+
16778
+ // Escape regexp special characters.
16779
+ when = '^' + when.replace(/[-\/\\^$*+?.()|[\]{}]/g, "\\$&") + '$';
16780
+ var regex = '',
16574
16781
  params = [],
16575
16782
  dst = {};
16576
- forEach(when.split(/\W/), function(param) {
16577
- if (param) {
16578
- var paramRegExp = new RegExp(":" + param + "([\\W])");
16579
- if (regex.match(paramRegExp)) {
16580
- regex = regex.replace(paramRegExp, "([^\\/]*)$1");
16581
- params.push(param);
16582
- }
16583
- }
16584
- });
16783
+
16784
+ var re = /:(\w+)/g,
16785
+ paramMatch,
16786
+ lastMatchedIndex = 0;
16787
+
16788
+ while ((paramMatch = re.exec(when)) !== null) {
16789
+ // Find each :param in `when` and replace it with a capturing group.
16790
+ // Append all other sections of when unchanged.
16791
+ regex += when.slice(lastMatchedIndex, paramMatch.index);
16792
+ regex += '([^\\/]*)';
16793
+ params.push(paramMatch[1]);
16794
+ lastMatchedIndex = re.lastIndex;
16795
+ }
16796
+ // Append trailing path part.
16797
+ regex += when.substr(lastMatchedIndex);
16798
+
16585
16799
  var match = on.match(new RegExp(regex));
16586
16800
  if (match) {
16587
16801
  forEach(params, function(name, index) {
@@ -16595,7 +16809,7 @@ function $RouteProvider(){
16595
16809
  var next = parseRoute(),
16596
16810
  last = $route.current;
16597
16811
 
16598
- if (next && last && next.$route === last.$route
16812
+ if (next && last && next.$$route === last.$$route
16599
16813
  && equals(next.pathParams, last.pathParams) && !next.reloadOnSearch && !forceReload) {
16600
16814
  last.params = next.params;
16601
16815
  copy(last.params, $routeParams);
@@ -16670,11 +16884,11 @@ function $RouteProvider(){
16670
16884
  // Match a route
16671
16885
  var params, match;
16672
16886
  forEach(routes, function(route, path) {
16673
- if (!match && (params = matcher($location.path(), path))) {
16887
+ if (!match && (params = switchRouteMatcher($location.path(), path))) {
16674
16888
  match = inherit(route, {
16675
16889
  params: extend({}, $location.search(), params),
16676
16890
  pathParams: params});
16677
- match.$route = route;
16891
+ match.$$route = route;
16678
16892
  }
16679
16893
  });
16680
16894
  // No route matched; fallback to "otherwise" route
@@ -16734,22 +16948,22 @@ function $RouteParamsProvider() {
16734
16948
  /**
16735
16949
  * DESIGN NOTES
16736
16950
  *
16737
- * The design decisions behind the scope ware heavily favored for speed and memory consumption.
16951
+ * The design decisions behind the scope are heavily favored for speed and memory consumption.
16738
16952
  *
16739
16953
  * The typical use of scope is to watch the expressions, which most of the time return the same
16740
16954
  * value as last time so we optimize the operation.
16741
16955
  *
16742
- * Closures construction is expensive from speed as well as memory:
16743
- * - no closures, instead ups prototypical inheritance for API
16956
+ * Closures construction is expensive in terms of speed as well as memory:
16957
+ * - No closures, instead use prototypical inheritance for API
16744
16958
  * - Internal state needs to be stored on scope directly, which means that private state is
16745
16959
  * exposed as $$____ properties
16746
16960
  *
16747
16961
  * Loop operations are optimized by using while(count--) { ... }
16748
16962
  * - this means that in order to keep the same order of execution as addition we have to add
16749
- * items to the array at the begging (shift) instead of at the end (push)
16963
+ * items to the array at the beginning (shift) instead of at the end (push)
16750
16964
  *
16751
16965
  * Child scopes are created and removed often
16752
- * - Using array would be slow since inserts in meddle are expensive so we use linked list
16966
+ * - Using an array would be slow since inserts in middle are expensive so we use linked list
16753
16967
  *
16754
16968
  * There are few watches then a lot of observers. This is why you don't want the observer to be
16755
16969
  * implemented in the same way as watch. Watch requires return of initialization function which
@@ -16771,7 +16985,7 @@ function $RouteParamsProvider() {
16771
16985
  * @methodOf ng.$rootScopeProvider
16772
16986
  * @description
16773
16987
  *
16774
- * Sets the number of digest iteration the scope should attempt to execute before giving up and
16988
+ * Sets the number of digest iterations the scope should attempt to execute before giving up and
16775
16989
  * assuming that the model is unstable.
16776
16990
  *
16777
16991
  * The current default is 10 iterations.
@@ -16822,7 +17036,7 @@ function $RootScopeProvider(){
16822
17036
  expect(scope.greeting).toEqual(undefined);
16823
17037
 
16824
17038
  scope.$watch('name', function() {
16825
- this.greeting = this.salutation + ' ' + this.name + '!';
17039
+ scope.greeting = scope.salutation + ' ' + scope.name + '!';
16826
17040
  }); // initialize the watch
16827
17041
 
16828
17042
  expect(scope.greeting).toEqual(undefined);
@@ -16865,8 +17079,10 @@ function $RootScopeProvider(){
16865
17079
  this.$$nextSibling = this.$$prevSibling =
16866
17080
  this.$$childHead = this.$$childTail = null;
16867
17081
  this['this'] = this.$root = this;
17082
+ this.$$destroyed = false;
16868
17083
  this.$$asyncQueue = [];
16869
17084
  this.$$listeners = {};
17085
+ this.$$isolateBindings = {};
16870
17086
  }
16871
17087
 
16872
17088
  /**
@@ -16983,7 +17199,7 @@ function $RootScopeProvider(){
16983
17199
  scope.counter = 0;
16984
17200
 
16985
17201
  expect(scope.counter).toEqual(0);
16986
- scope.$watch('name', function(newValue, oldValue) { counter = counter + 1; });
17202
+ scope.$watch('name', function(newValue, oldValue) { scope.counter = scope.counter + 1; });
16987
17203
  expect(scope.counter).toEqual(0);
16988
17204
 
16989
17205
  scope.$digest();
@@ -17049,7 +17265,7 @@ function $RootScopeProvider(){
17049
17265
  * @function
17050
17266
  *
17051
17267
  * @description
17052
- * Process all of the {@link ng.$rootScope.Scope#$watch watchers} of the current scope and its children.
17268
+ * Processes all of the {@link ng.$rootScope.Scope#$watch watchers} of the current scope and its children.
17053
17269
  * Because a {@link ng.$rootScope.Scope#$watch watcher}'s listener can change the model, the
17054
17270
  * `$digest()` keeps calling the {@link ng.$rootScope.Scope#$watch watchers} until no more listeners are
17055
17271
  * firing. This means that it is possible to get into an infinite loop. This function will throw
@@ -17076,7 +17292,7 @@ function $RootScopeProvider(){
17076
17292
 
17077
17293
  expect(scope.counter).toEqual(0);
17078
17294
  scope.$watch('name', function(newValue, oldValue) {
17079
- counter = counter + 1;
17295
+ scope.counter = scope.counter + 1;
17080
17296
  });
17081
17297
  expect(scope.counter).toEqual(0);
17082
17298
 
@@ -17198,10 +17414,12 @@ function $RootScopeProvider(){
17198
17414
  * perform any necessary cleanup.
17199
17415
  */
17200
17416
  $destroy: function() {
17201
- if ($rootScope == this) return; // we can't remove the root node;
17417
+ // we can't destroy the root scope or a scope that has been already destroyed
17418
+ if ($rootScope == this || this.$$destroyed) return;
17202
17419
  var parent = this.$parent;
17203
17420
 
17204
17421
  this.$broadcast('$destroy');
17422
+ this.$$destroyed = true;
17205
17423
 
17206
17424
  if (parent.$$childHead == this) parent.$$childHead = this.$$nextSibling;
17207
17425
  if (parent.$$childTail == this) parent.$$childTail = this.$$prevSibling;
@@ -17346,10 +17564,6 @@ function $RootScopeProvider(){
17346
17564
  * Listens on events of a given type. See {@link ng.$rootScope.Scope#$emit $emit} for discussion of
17347
17565
  * event life cycle.
17348
17566
  *
17349
- * @param {string} name Event name to listen on.
17350
- * @param {function(event)} listener Function to call when the event is emitted.
17351
- * @returns {function()} Returns a deregistration function for this listener.
17352
- *
17353
17567
  * The event listener function format is: `function(event, args...)`. The `event` object
17354
17568
  * passed into the listener has the following attributes:
17355
17569
  *
@@ -17360,6 +17574,10 @@ function $RootScopeProvider(){
17360
17574
  * propagation (available only for events that were `$emit`-ed).
17361
17575
  * - `preventDefault` - `{function}`: calling `preventDefault` sets `defaultPrevented` flag to true.
17362
17576
  * - `defaultPrevented` - `{boolean}`: true if `preventDefault` was called.
17577
+ *
17578
+ * @param {string} name Event name to listen on.
17579
+ * @param {function(event, args...)} listener Function to call when the event is emitted.
17580
+ * @returns {function()} Returns a deregistration function for this listener.
17363
17581
  */
17364
17582
  $on: function(name, listener) {
17365
17583
  var namedListeners = this.$$listeners[name];
@@ -17389,7 +17607,7 @@ function $RootScopeProvider(){
17389
17607
  * Afterwards, the event traverses upwards toward the root scope and calls all registered
17390
17608
  * listeners along the way. The event will stop propagating if one of the listeners cancels it.
17391
17609
  *
17392
- * Any exception emmited from the {@link ng.$rootScope.Scope#$on listeners} will be passed
17610
+ * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed
17393
17611
  * onto the {@link ng.$exceptionHandler $exceptionHandler} service.
17394
17612
  *
17395
17613
  * @param {string} name Event name to emit.
@@ -17458,7 +17676,7 @@ function $RootScopeProvider(){
17458
17676
  * Any exception emmited from the {@link ng.$rootScope.Scope#$on listeners} will be passed
17459
17677
  * onto the {@link ng.$exceptionHandler $exceptionHandler} service.
17460
17678
  *
17461
- * @param {string} name Event name to emit.
17679
+ * @param {string} name Event name to broadcast.
17462
17680
  * @param {...*} args Optional set of arguments which will be passed onto the event listeners.
17463
17681
  * @return {Object} Event object, see {@link ng.$rootScope.Scope#$on}
17464
17682
  */
@@ -17537,7 +17755,7 @@ function $RootScopeProvider(){
17537
17755
 
17538
17756
  /**
17539
17757
  * function used as an initial value for watchers.
17540
- * because it's uniqueue we can easily tell it apart from other values
17758
+ * because it's unique we can easily tell it apart from other values
17541
17759
  */
17542
17760
  function initWatchVal() {}
17543
17761
  }];
@@ -17604,10 +17822,23 @@ function $SnifferProvider() {
17604
17822
  * @example
17605
17823
  <doc:example>
17606
17824
  <doc:source>
17607
- <input ng-init="$window = $service('$window'); greeting='Hello World!'" type="text" ng-model="greeting" />
17608
- <button ng-click="$window.alert(greeting)">ALERT</button>
17825
+ <script>
17826
+ function Ctrl($scope, $window) {
17827
+ $scope.$window = $window;
17828
+ $scope.greeting = 'Hello, World!';
17829
+ }
17830
+ </script>
17831
+ <div ng-controller="Ctrl">
17832
+ <input type="text" ng-model="greeting" />
17833
+ <button ng-click="$window.alert(greeting)">ALERT</button>
17834
+ </div>
17609
17835
  </doc:source>
17610
17836
  <doc:scenario>
17837
+ it('should display the greeting in the input box', function() {
17838
+ input('greeting').enter('Hello, E2E Tests');
17839
+ // If we click the button it will block the test runner
17840
+ // element(':button').click();
17841
+ });
17611
17842
  </doc:scenario>
17612
17843
  </doc:example>
17613
17844
  */
@@ -17751,7 +17982,7 @@ function $HttpProvider() {
17751
17982
  /**
17752
17983
  * @ngdoc function
17753
17984
  * @name ng.$http
17754
- * @requires $httpBacked
17985
+ * @requires $httpBackend
17755
17986
  * @requires $browser
17756
17987
  * @requires $cacheFactory
17757
17988
  * @requires $rootScope
@@ -17760,7 +17991,7 @@ function $HttpProvider() {
17760
17991
  *
17761
17992
  * @description
17762
17993
  * The `$http` service is a core Angular service that facilitates communication with the remote
17763
- * HTTP servers via browser's {@link https://developer.mozilla.org/en/xmlhttprequest
17994
+ * HTTP servers via the browser's {@link https://developer.mozilla.org/en/xmlhttprequest
17764
17995
  * XMLHttpRequest} object or via {@link http://en.wikipedia.org/wiki/JSONP JSONP}.
17765
17996
  *
17766
17997
  * For unit testing applications that use `$http` service, see
@@ -17770,13 +18001,13 @@ function $HttpProvider() {
17770
18001
  * $resource} service.
17771
18002
  *
17772
18003
  * The $http API is based on the {@link ng.$q deferred/promise APIs} exposed by
17773
- * the $q service. While for simple usage patters this doesn't matter much, for advanced usage,
17774
- * it is important to familiarize yourself with these apis and guarantees they provide.
18004
+ * the $q service. While for simple usage patterns this doesn't matter much, for advanced usage
18005
+ * it is important to familiarize yourself with these APIs and the guarantees they provide.
17775
18006
  *
17776
18007
  *
17777
18008
  * # General usage
17778
18009
  * The `$http` service is a function which takes a single argument — a configuration object —
17779
- * that is used to generate an http request and returns a {@link ng.$q promise}
18010
+ * that is used to generate an HTTP request and returns a {@link ng.$q promise}
17780
18011
  * with two $http specific methods: `success` and `error`.
17781
18012
  *
17782
18013
  * <pre>
@@ -17787,22 +18018,25 @@ function $HttpProvider() {
17787
18018
  * }).
17788
18019
  * error(function(data, status, headers, config) {
17789
18020
  * // called asynchronously if an error occurs
17790
- * // or server returns response with status
17791
- * // code outside of the <200, 400) range
18021
+ * // or server returns response with an error status.
17792
18022
  * });
17793
18023
  * </pre>
17794
18024
  *
17795
- * Since the returned value of calling the $http function is a Promise object, you can also use
18025
+ * Since the returned value of calling the $http function is a `promise`, you can also use
17796
18026
  * the `then` method to register callbacks, and these callbacks will receive a single argument –
17797
- * an object representing the response. See the api signature and type info below for more
18027
+ * an object representing the response. See the API signature and type info below for more
17798
18028
  * details.
17799
18029
  *
18030
+ * A response status code between 200 and 299 is considered a success status and
18031
+ * will result in the success callback being called. Note that if the response is a redirect,
18032
+ * XMLHttpRequest will transparently follow it, meaning that the error callback will not be
18033
+ * called for such responses.
17800
18034
  *
17801
18035
  * # Shortcut methods
17802
18036
  *
17803
- * Since all invocation of the $http service require definition of the http method and url and
17804
- * POST and PUT requests require response body/data to be provided as well, shortcut methods
17805
- * were created to simplify using the api:
18037
+ * Since all invocations of the $http service require passing in an HTTP method and URL, and
18038
+ * POST/PUT requests require request data to be provided as well, shortcut methods
18039
+ * were created:
17806
18040
  *
17807
18041
  * <pre>
17808
18042
  * $http.get('/someUrl').success(successCallback);
@@ -17821,25 +18055,25 @@ function $HttpProvider() {
17821
18055
  *
17822
18056
  * # Setting HTTP Headers
17823
18057
  *
17824
- * The $http service will automatically add certain http headers to all requests. These defaults
18058
+ * The $http service will automatically add certain HTTP headers to all requests. These defaults
17825
18059
  * can be fully configured by accessing the `$httpProvider.defaults.headers` configuration
17826
18060
  * object, which currently contains this default configuration:
17827
18061
  *
17828
18062
  * - `$httpProvider.defaults.headers.common` (headers that are common for all requests):
17829
18063
  * - `Accept: application/json, text/plain, * / *`
17830
18064
  * - `X-Requested-With: XMLHttpRequest`
17831
- * - `$httpProvider.defaults.headers.post`: (header defaults for HTTP POST requests)
18065
+ * - `$httpProvider.defaults.headers.post`: (header defaults for POST requests)
17832
18066
  * - `Content-Type: application/json`
17833
- * - `$httpProvider.defaults.headers.put` (header defaults for HTTP PUT requests)
18067
+ * - `$httpProvider.defaults.headers.put` (header defaults for PUT requests)
17834
18068
  * - `Content-Type: application/json`
17835
18069
  *
17836
- * To add or overwrite these defaults, simply add or remove a property from this configuration
18070
+ * To add or overwrite these defaults, simply add or remove a property from these configuration
17837
18071
  * objects. To add headers for an HTTP method other than POST or PUT, simply add a new object
17838
- * with name equal to the lower-cased http method name, e.g.
18072
+ * with the lowercased HTTP method name as the key, e.g.
17839
18073
  * `$httpProvider.defaults.headers.get['My-Header']='value'`.
17840
18074
  *
17841
- * Additionally, the defaults can be set at runtime via the `$http.defaults` object in a similar
17842
- * fassion as described above.
18075
+ * Additionally, the defaults can be set at runtime via the `$http.defaults` object in the same
18076
+ * fashion.
17843
18077
  *
17844
18078
  *
17845
18079
  * # Transforming Requests and Responses
@@ -17849,32 +18083,36 @@ function $HttpProvider() {
17849
18083
  *
17850
18084
  * Request transformations:
17851
18085
  *
17852
- * - if the `data` property of the request config object contains an object, serialize it into
18086
+ * - If the `data` property of the request configuration object contains an object, serialize it into
17853
18087
  * JSON format.
17854
18088
  *
17855
18089
  * Response transformations:
17856
18090
  *
17857
- * - if XSRF prefix is detected, strip it (see Security Considerations section below)
17858
- * - if json response is detected, deserialize it using a JSON parser
18091
+ * - If XSRF prefix is detected, strip it (see Security Considerations section below).
18092
+ * - If JSON response is detected, deserialize it using a JSON parser.
18093
+ *
18094
+ * To globally augment or override the default transforms, modify the `$httpProvider.defaults.transformRequest` and
18095
+ * `$httpProvider.defaults.transformResponse` properties. These properties are by default an
18096
+ * array of transform functions, which allows you to `push` or `unshift` a new transformation function into the
18097
+ * transformation chain. You can also decide to completely override any default transformations by assigning your
18098
+ * transformation functions to these properties directly without the array wrapper.
17859
18099
  *
17860
- * To override these transformation locally, specify transform functions as `transformRequest`
17861
- * and/or `transformResponse` properties of the config object. To globally override the default
17862
- * transforms, override the `$httpProvider.defaults.transformRequest` and
17863
- * `$httpProvider.defaults.transformResponse` properties of the `$httpProvider`.
18100
+ * Similarly, to locally override the request/response transforms, augment the `transformRequest` and/or
18101
+ * `transformResponse` properties of the configuration object passed into `$http`.
17864
18102
  *
17865
18103
  *
17866
18104
  * # Caching
17867
18105
  *
17868
- * To enable caching set the configuration property `cache` to `true`. When the cache is
18106
+ * To enable caching, set the configuration property `cache` to `true`. When the cache is
17869
18107
  * enabled, `$http` stores the response from the server in local cache. Next time the
17870
18108
  * response is served from the cache without sending a request to the server.
17871
18109
  *
17872
18110
  * Note that even if the response is served from cache, delivery of the data is asynchronous in
17873
18111
  * the same way that real requests are.
17874
18112
  *
17875
- * If there are multiple GET requests for the same url that should be cached using the same
18113
+ * If there are multiple GET requests for the same URL that should be cached using the same
17876
18114
  * cache, but the cache is not populated yet, only one request to the server will be made and
17877
- * the remaining requests will be fulfilled using the response for the first request.
18115
+ * the remaining requests will be fulfilled using the response from the first request.
17878
18116
  *
17879
18117
  *
17880
18118
  * # Response interceptors
@@ -17926,7 +18164,7 @@ function $HttpProvider() {
17926
18164
  * When designing web applications, consider security threats from:
17927
18165
  *
17928
18166
  * - {@link http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx
17929
- * JSON Vulnerability}
18167
+ * JSON vulnerability}
17930
18168
  * - {@link http://en.wikipedia.org/wiki/Cross-site_request_forgery XSRF}
17931
18169
  *
17932
18170
  * Both server and the client must cooperate in order to eliminate these threats. Angular comes
@@ -17936,8 +18174,8 @@ function $HttpProvider() {
17936
18174
  * ## JSON Vulnerability Protection
17937
18175
  *
17938
18176
  * A {@link http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx
17939
- * JSON Vulnerability} allows third party web-site to turn your JSON resource URL into
17940
- * {@link http://en.wikipedia.org/wiki/JSON#JSONP JSONP} request under some conditions. To
18177
+ * JSON vulnerability} allows third party website to turn your JSON resource URL into
18178
+ * {@link http://en.wikipedia.org/wiki/JSONP JSONP} request under some conditions. To
17941
18179
  * counter this your server can prefix all JSON requests with following string `")]}',\n"`.
17942
18180
  * Angular will automatically strip the prefix before processing it as JSON.
17943
18181
  *
@@ -17958,19 +18196,19 @@ function $HttpProvider() {
17958
18196
  * ## Cross Site Request Forgery (XSRF) Protection
17959
18197
  *
17960
18198
  * {@link http://en.wikipedia.org/wiki/Cross-site_request_forgery XSRF} is a technique by which
17961
- * an unauthorized site can gain your user's private data. Angular provides following mechanism
18199
+ * an unauthorized site can gain your user's private data. Angular provides a mechanism
17962
18200
  * to counter XSRF. When performing XHR requests, the $http service reads a token from a cookie
17963
18201
  * called `XSRF-TOKEN` and sets it as the HTTP header `X-XSRF-TOKEN`. Since only JavaScript that
17964
18202
  * runs on your domain could read the cookie, your server can be assured that the XHR came from
17965
18203
  * JavaScript running on your domain.
17966
18204
  *
17967
18205
  * To take advantage of this, your server needs to set a token in a JavaScript readable session
17968
- * cookie called `XSRF-TOKEN` on first HTTP GET request. On subsequent non-GET requests the
18206
+ * cookie called `XSRF-TOKEN` on the first HTTP GET request. On subsequent XHR requests the
17969
18207
  * server can verify that the cookie matches `X-XSRF-TOKEN` HTTP header, and therefore be sure
17970
- * that only JavaScript running on your domain could have read the token. The token must be
17971
- * unique for each user and must be verifiable by the server (to prevent the JavaScript making
18208
+ * that only JavaScript running on your domain could have sent the request. The token must be
18209
+ * unique for each user and must be verifiable by the server (to prevent the JavaScript from making
17972
18210
  * up its own tokens). We recommend that the token is a digest of your site's authentication
17973
- * cookie with {@link http://en.wikipedia.org/wiki/Rainbow_table salt for added security}.
18211
+ * cookie with a {@link https://en.wikipedia.org/wiki/Salt_(cryptography) salt} for added security.
17974
18212
  *
17975
18213
  *
17976
18214
  * @param {object} config Object describing the request to be made and how it should be
@@ -18148,7 +18386,7 @@ function $HttpProvider() {
18148
18386
  * @methodOf ng.$http
18149
18387
  *
18150
18388
  * @description
18151
- * Shortcut method to perform `GET` request
18389
+ * Shortcut method to perform `GET` request.
18152
18390
  *
18153
18391
  * @param {string} url Relative or absolute URL specifying the destination of the request
18154
18392
  * @param {Object=} config Optional configuration object
@@ -18161,7 +18399,7 @@ function $HttpProvider() {
18161
18399
  * @methodOf ng.$http
18162
18400
  *
18163
18401
  * @description
18164
- * Shortcut method to perform `DELETE` request
18402
+ * Shortcut method to perform `DELETE` request.
18165
18403
  *
18166
18404
  * @param {string} url Relative or absolute URL specifying the destination of the request
18167
18405
  * @param {Object=} config Optional configuration object
@@ -18174,7 +18412,7 @@ function $HttpProvider() {
18174
18412
  * @methodOf ng.$http
18175
18413
  *
18176
18414
  * @description
18177
- * Shortcut method to perform `HEAD` request
18415
+ * Shortcut method to perform `HEAD` request.
18178
18416
  *
18179
18417
  * @param {string} url Relative or absolute URL specifying the destination of the request
18180
18418
  * @param {Object=} config Optional configuration object
@@ -18187,7 +18425,7 @@ function $HttpProvider() {
18187
18425
  * @methodOf ng.$http
18188
18426
  *
18189
18427
  * @description
18190
- * Shortcut method to perform `JSONP` request
18428
+ * Shortcut method to perform `JSONP` request.
18191
18429
  *
18192
18430
  * @param {string} url Relative or absolute URL specifying the destination of the request.
18193
18431
  * Should contain `JSON_CALLBACK` string.
@@ -18202,7 +18440,7 @@ function $HttpProvider() {
18202
18440
  * @methodOf ng.$http
18203
18441
  *
18204
18442
  * @description
18205
- * Shortcut method to perform `POST` request
18443
+ * Shortcut method to perform `POST` request.
18206
18444
  *
18207
18445
  * @param {string} url Relative or absolute URL specifying the destination of the request
18208
18446
  * @param {*} data Request content
@@ -18216,7 +18454,7 @@ function $HttpProvider() {
18216
18454
  * @methodOf ng.$http
18217
18455
  *
18218
18456
  * @description
18219
- * Shortcut method to perform `PUT` request
18457
+ * Shortcut method to perform `PUT` request.
18220
18458
  *
18221
18459
  * @param {string} url Relative or absolute URL specifying the destination of the request
18222
18460
  * @param {*} data Request content
@@ -18268,7 +18506,7 @@ function $HttpProvider() {
18268
18506
 
18269
18507
 
18270
18508
  /**
18271
- * Makes the request
18509
+ * Makes the request.
18272
18510
  *
18273
18511
  * !!! ACCESSES CLOSURE VARS:
18274
18512
  * $httpBackend, $config, $log, $rootScope, defaultCache, $http.pendingRequests
@@ -18378,6 +18616,7 @@ function $HttpProvider() {
18378
18616
 
18379
18617
  }];
18380
18618
  }
18619
+
18381
18620
  var XHR = window.XMLHttpRequest || function() {
18382
18621
  try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); } catch (e1) {}
18383
18622
  try { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); } catch (e2) {}
@@ -18445,8 +18684,30 @@ function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument,
18445
18684
  // always async
18446
18685
  xhr.onreadystatechange = function() {
18447
18686
  if (xhr.readyState == 4) {
18448
- completeRequest(
18449
- callback, status || xhr.status, xhr.responseText, xhr.getAllResponseHeaders());
18687
+ var responseHeaders = xhr.getAllResponseHeaders();
18688
+
18689
+ // TODO(vojta): remove once Firefox 21 gets released.
18690
+ // begin: workaround to overcome Firefox CORS http response headers bug
18691
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=608735
18692
+ // Firefox already patched in nightly. Should land in Firefox 21.
18693
+
18694
+ // CORS "simple response headers" http://www.w3.org/TR/cors/
18695
+ var value,
18696
+ simpleHeaders = ["Cache-Control", "Content-Language", "Content-Type",
18697
+ "Expires", "Last-Modified", "Pragma"];
18698
+ if (!responseHeaders) {
18699
+ responseHeaders = "";
18700
+ forEach(simpleHeaders, function (header) {
18701
+ var value = xhr.getResponseHeader(header);
18702
+ if (value) {
18703
+ responseHeaders += header + ": " + value + "\n";
18704
+ }
18705
+ });
18706
+ }
18707
+ // end of the workaround.
18708
+
18709
+ completeRequest(callback, status || xhr.status, xhr.responseText,
18710
+ responseHeaders);
18450
18711
  }
18451
18712
  };
18452
18713
 
@@ -18592,17 +18853,17 @@ function $TimeoutProvider() {
18592
18853
  * block and delegates any exceptions to
18593
18854
  * {@link ng.$exceptionHandler $exceptionHandler} service.
18594
18855
  *
18595
- * The return value of registering a timeout function is a promise which will be resolved when
18856
+ * The return value of registering a timeout function is a promise, which will be resolved when
18596
18857
  * the timeout is reached and the timeout function is executed.
18597
18858
  *
18598
- * To cancel a the timeout request, call `$timeout.cancel(promise)`.
18859
+ * To cancel a timeout request, call `$timeout.cancel(promise)`.
18599
18860
  *
18600
18861
  * In tests you can use {@link ngMock.$timeout `$timeout.flush()`} to
18601
18862
  * synchronously flush the queue of deferred functions.
18602
18863
  *
18603
- * @param {function()} fn A function, who's execution should be delayed.
18864
+ * @param {function()} fn A function, whose execution should be delayed.
18604
18865
  * @param {number=} [delay=0] Delay in milliseconds.
18605
- * @param {boolean=} [invokeApply=true] If set to false skips model dirty checking, otherwise
18866
+ * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
18606
18867
  * will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
18607
18868
  * @returns {Promise} Promise that will be resolved when the timeout is reached. The value this
18608
18869
  * promise will be resolved with is the return value of the `fn` function.
@@ -18642,7 +18903,7 @@ function $TimeoutProvider() {
18642
18903
  * @methodOf ng.$timeout
18643
18904
  *
18644
18905
  * @description
18645
- * Cancels a task associated with the `promise`. As a result of this the promise will be
18906
+ * Cancels a task associated with the `promise`. As a result of this, the promise will be
18646
18907
  * resolved with a rejection.
18647
18908
  *
18648
18909
  * @param {Promise=} promise Promise returned by the `$timeout` function.
@@ -18668,7 +18929,7 @@ function $TimeoutProvider() {
18668
18929
  *
18669
18930
  * Filters are just functions which transform input to an output. However filters need to be Dependency Injected. To
18670
18931
  * achieve this a filter definition consists of a factory function which is annotated with dependencies and is
18671
- * responsible for creating a the filter function.
18932
+ * responsible for creating a filter function.
18672
18933
  *
18673
18934
  * <pre>
18674
18935
  * // Filter registration
@@ -18730,7 +18991,7 @@ function $TimeoutProvider() {
18730
18991
  *
18731
18992
  * The general syntax in templates is as follows:
18732
18993
  *
18733
- * {{ expression | [ filter_name ] }}
18994
+ * {{ expression [| filter_name[:parameter_value] ... ] }}
18734
18995
  *
18735
18996
  * @param {String} name Name of the filter function to retrieve
18736
18997
  * @return {Function} the filter function
@@ -18806,22 +19067,22 @@ function $FilterProvider($provide) {
18806
19067
 
18807
19068
  Search: <input ng-model="searchText">
18808
19069
  <table id="searchTextResults">
18809
- <tr><th>Name</th><th>Phone</th><tr>
19070
+ <tr><th>Name</th><th>Phone</th></tr>
18810
19071
  <tr ng-repeat="friend in friends | filter:searchText">
18811
19072
  <td>{{friend.name}}</td>
18812
19073
  <td>{{friend.phone}}</td>
18813
- <tr>
19074
+ </tr>
18814
19075
  </table>
18815
19076
  <hr>
18816
19077
  Any: <input ng-model="search.$"> <br>
18817
19078
  Name only <input ng-model="search.name"><br>
18818
- Phone only <input ng-model="search.phone"å><br>
19079
+ Phone only <input ng-model="search.phone"><br>
18819
19080
  <table id="searchObjResults">
18820
- <tr><th>Name</th><th>Phone</th><tr>
19081
+ <tr><th>Name</th><th>Phone</th></tr>
18821
19082
  <tr ng-repeat="friend in friends | filter:search">
18822
19083
  <td>{{friend.name}}</td>
18823
19084
  <td>{{friend.phone}}</td>
18824
- <tr>
19085
+ </tr>
18825
19086
  </table>
18826
19087
  </doc:source>
18827
19088
  <doc:scenario>
@@ -18845,7 +19106,7 @@ function $FilterProvider($provide) {
18845
19106
  */
18846
19107
  function filterFilter() {
18847
19108
  return function(array, expression) {
18848
- if (!(array instanceof Array)) return array;
19109
+ if (!isArray(array)) return array;
18849
19110
  var predicates = [];
18850
19111
  predicates.check = function(value) {
18851
19112
  for (var j = 0; j < predicates.length; j++) {
@@ -19094,7 +19355,7 @@ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
19094
19355
  fraction += '0';
19095
19356
  }
19096
19357
 
19097
- if (fractionSize) formatedText += decimalSep + fraction.substr(0, fractionSize);
19358
+ if (fractionSize && fractionSize !== "0") formatedText += decimalSep + fraction.substr(0, fractionSize);
19098
19359
  }
19099
19360
 
19100
19361
  parts.push(isNegative ? pattern.negPre : pattern.posPre);
@@ -19118,6 +19379,7 @@ function padNumber(num, digits, trim) {
19118
19379
 
19119
19380
 
19120
19381
  function dateGetter(name, size, offset, trim) {
19382
+ offset = offset || 0;
19121
19383
  return function(date) {
19122
19384
  var value = date['get' + name]();
19123
19385
  if (offset > 0 || value > -offset)
@@ -19137,8 +19399,13 @@ function dateStrGetter(name, shortForm) {
19137
19399
  }
19138
19400
 
19139
19401
  function timeZoneGetter(date) {
19140
- var offset = date.getTimezoneOffset();
19141
- return padNumber(offset / 60, 2) + padNumber(Math.abs(offset % 60), 2);
19402
+ var zone = -1 * date.getTimezoneOffset();
19403
+ var paddedZone = (zone >= 0) ? "+" : "";
19404
+
19405
+ paddedZone += padNumber(Math[zone > 0 ? 'floor' : 'ceil'](zone / 60), 2) +
19406
+ padNumber(Math.abs(zone % 60), 2);
19407
+
19408
+ return paddedZone;
19142
19409
  }
19143
19410
 
19144
19411
  function ampmGetter(date, formats) {
@@ -19202,7 +19469,7 @@ var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+
19202
19469
  * * `'ss'`: Second in minute, padded (00-59)
19203
19470
  * * `'s'`: Second in minute (0-59)
19204
19471
  * * `'a'`: am/pm marker
19205
- * * `'Z'`: 4 digit (+sign) representation of the timezone offset (-1200-1200)
19472
+ * * `'Z'`: 4 digit (+sign) representation of the timezone offset (-1200-+1200)
19206
19473
  *
19207
19474
  * `format` string can also be one of the following predefined
19208
19475
  * {@link guide/i18n localizable formats}:
@@ -19223,8 +19490,9 @@ var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+
19223
19490
  * (e.g. `"h o''clock"`).
19224
19491
  *
19225
19492
  * @param {(Date|number|string)} date Date to format either as Date object, milliseconds (string or
19226
- * number) or various ISO 8601 datetime string formats (e.g. yyyy-MM-ddTHH:mm:ss.SSSZ and it's
19227
- * shorter versions like yyyy-MM-ddTHH:mmZ, yyyy-MM-dd or yyyyMMddTHHmmssZ).
19493
+ * number) or various ISO 8601 datetime string formats (e.g. yyyy-MM-ddTHH:mm:ss.SSSZ and its
19494
+ * shorter versions like yyyy-MM-ddTHH:mmZ, yyyy-MM-dd or yyyyMMddTHHmmssZ). If no timezone is
19495
+ * specified in the string input, the time is considered to be in the local timezone.
19228
19496
  * @param {string=} format Formatting rules (see Description). If not specified,
19229
19497
  * `mediumDate` is used.
19230
19498
  * @returns {string} Formatted string or the input if input is not recognized as date/millis.
@@ -19244,7 +19512,7 @@ var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+
19244
19512
  expect(binding("1288323623006 | date:'medium'")).
19245
19513
  toMatch(/Oct 2\d, 2010 \d{1,2}:\d{2}:\d{2} (AM|PM)/);
19246
19514
  expect(binding("1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'")).
19247
- toMatch(/2010\-10\-2\d \d{2}:\d{2}:\d{2} \-?\d{4}/);
19515
+ toMatch(/2010\-10\-2\d \d{2}:\d{2}:\d{2} (\-|\+)?\d{4}/);
19248
19516
  expect(binding("'1288323623006' | date:'MM/dd/yyyy @ h:mma'")).
19249
19517
  toMatch(/10\/2\d\/2010 @ \d{1,2}:\d{2}(AM|PM)/);
19250
19518
  });
@@ -19513,12 +19781,12 @@ function limitToFilter(){
19513
19781
  (<a href ng-click="predicate = '-name'; reverse=false">^</a>)</th>
19514
19782
  <th><a href="" ng-click="predicate = 'phone'; reverse=!reverse">Phone Number</a></th>
19515
19783
  <th><a href="" ng-click="predicate = 'age'; reverse=!reverse">Age</a></th>
19516
- <tr>
19784
+ </tr>
19517
19785
  <tr ng-repeat="friend in friends | orderBy:predicate:reverse">
19518
19786
  <td>{{friend.name}}</td>
19519
19787
  <td>{{friend.phone}}</td>
19520
19788
  <td>{{friend.age}}</td>
19521
- <tr>
19789
+ </tr>
19522
19790
  </table>
19523
19791
  </div>
19524
19792
  </doc:source>
@@ -19550,7 +19818,7 @@ function limitToFilter(){
19550
19818
  orderByFilter.$inject = ['$parse'];
19551
19819
  function orderByFilter($parse){
19552
19820
  return function(array, sortPredicate, reverseOrder) {
19553
- if (!(array instanceof Array)) return array;
19821
+ if (!isArray(array)) return array;
19554
19822
  if (!sortPredicate) return array;
19555
19823
  sortPredicate = isArray(sortPredicate) ? sortPredicate: [sortPredicate];
19556
19824
  sortPredicate = map(sortPredicate, function(predicate){
@@ -19618,15 +19886,25 @@ function ngDirective(directive) {
19618
19886
  *
19619
19887
  * The reasoning for this change is to allow easy creation of action links with `ngClick` directive
19620
19888
  * without changing the location or causing page reloads, e.g.:
19621
- * <a href="" ng-click="model.$save()">Save</a>
19889
+ * `<a href="" ng-click="model.$save()">Save</a>`
19622
19890
  */
19623
19891
  var htmlAnchorDirective = valueFn({
19624
19892
  restrict: 'E',
19625
19893
  compile: function(element, attr) {
19626
- // turn <a href ng-click="..">link</a> into a link in IE
19627
- // but only if it doesn't have name attribute, in which case it's an anchor
19628
- if (!attr.href) {
19629
- attr.$set('href', '');
19894
+
19895
+ if (msie <= 8) {
19896
+
19897
+ // turn <a href ng-click="..">link</a> into a stylable link in IE
19898
+ // but only if it doesn't have name attribute, in which case it's an anchor
19899
+ if (!attr.href && !attr.name) {
19900
+ attr.$set('href', '');
19901
+ }
19902
+
19903
+ // add a comment node to anchors to workaround IE bug that causes element content to be reset
19904
+ // to new attribute content if attribute is updated with value containing @ and element also
19905
+ // contains value with @
19906
+ // see issue #1949
19907
+ element.append(document.createComment('IE fix'));
19630
19908
  }
19631
19909
 
19632
19910
  return function(scope, element) {
@@ -19634,7 +19912,6 @@ var htmlAnchorDirective = valueFn({
19634
19912
  // if we have no href url, then don't navigate anywhere.
19635
19913
  if (!element.attr('href')) {
19636
19914
  event.preventDefault();
19637
- return false; // Needed for opera
19638
19915
  }
19639
19916
  });
19640
19917
  }
@@ -19707,7 +19984,7 @@ var htmlAnchorDirective = valueFn({
19707
19984
  it('should execute ng-click but not reload when no href but name specified', function() {
19708
19985
  element('#link-5').click();
19709
19986
  expect(input('value').val()).toEqual('5');
19710
- expect(element('#link-5').attr('href')).toBe('');
19987
+ expect(element('#link-5').attr('href')).toBe(undefined);
19711
19988
  });
19712
19989
 
19713
19990
  it('should only change url when only ng-href', function() {
@@ -19950,8 +20227,9 @@ forEach(['src', 'href'], function(attrName) {
19950
20227
 
19951
20228
  // on IE, if "ng:src" directive declaration is used and "src" attribute doesn't exist
19952
20229
  // then calling element.setAttribute('src', 'foo') doesn't do anything, so we need
19953
- // to set the property as well to achieve the desired effect
19954
- if (msie) element.prop(attrName, value);
20230
+ // to set the property as well to achieve the desired effect.
20231
+ // we use attr[attrName] value since $set can sanitize the url.
20232
+ if (msie) element.prop(attrName, attr[attrName]);
19955
20233
  });
19956
20234
  }
19957
20235
  };
@@ -19971,13 +20249,13 @@ var nullFormCtrl = {
19971
20249
  *
19972
20250
  * @property {boolean} $pristine True if user has not interacted with the form yet.
19973
20251
  * @property {boolean} $dirty True if user has already interacted with the form.
19974
- * @property {boolean} $valid True if all of the containg forms and controls are valid.
20252
+ * @property {boolean} $valid True if all of the containing forms and controls are valid.
19975
20253
  * @property {boolean} $invalid True if at least one containing control or form is invalid.
19976
20254
  *
19977
20255
  * @property {Object} $error Is an object hash, containing references to all invalid controls or
19978
20256
  * forms, where:
19979
20257
  *
19980
- * - keys are validation tokens (error names) — such as `REQUIRED`, `URL` or `EMAIL`),
20258
+ * - keys are validation tokens (error names) — such as `required`, `url` or `email`),
19981
20259
  * - values are arrays of controls or forms that are invalid with given error.
19982
20260
  *
19983
20261
  * @description
@@ -20090,7 +20368,7 @@ function FormController(element, attrs) {
20090
20368
  * does not allow nesting of form elements. It is useful to nest forms, for example if the validity of a
20091
20369
  * sub-group of controls needs to be determined.
20092
20370
  *
20093
- * @param {string=} ngForm|name Name of the form. If specified, the form controller will be published into
20371
+ * @param {string=} name|ngForm Name of the form. If specified, the form controller will be published into
20094
20372
  * related scope, under this name.
20095
20373
  *
20096
20374
  */
@@ -20163,12 +20441,12 @@ function FormController(element, attrs) {
20163
20441
  </script>
20164
20442
  <form name="myForm" ng-controller="Ctrl">
20165
20443
  userType: <input name="input" ng-model="userType" required>
20166
- <span class="error" ng-show="myForm.input.$error.REQUIRED">Required!</span><br>
20444
+ <span class="error" ng-show="myForm.input.$error.required">Required!</span><br>
20167
20445
  <tt>userType = {{userType}}</tt><br>
20168
20446
  <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br>
20169
20447
  <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br>
20170
20448
  <tt>myForm.$valid = {{myForm.$valid}}</tt><br>
20171
- <tt>myForm.$error.REQUIRED = {{!!myForm.$error.REQUIRED}}</tt><br>
20449
+ <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br>
20172
20450
  </form>
20173
20451
  </doc:source>
20174
20452
  <doc:scenario>
@@ -20330,8 +20608,8 @@ var inputType = {
20330
20608
  *
20331
20609
  * @param {string} ngModel Assignable angular expression to data-bind to.
20332
20610
  * @param {string=} name Property name of the form under which the control is published.
20333
- * @param {string=} min Sets the `min` validation error key if the value entered is less then `min`.
20334
- * @param {string=} max Sets the `max` validation error key if the value entered is greater then `min`.
20611
+ * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
20612
+ * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
20335
20613
  * @param {string=} required Sets `required` validation error key if the value is not entered.
20336
20614
  * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
20337
20615
  * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
@@ -20643,6 +20921,15 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
20643
20921
  } else {
20644
20922
  var timeout;
20645
20923
 
20924
+ var deferListener = function() {
20925
+ if (!timeout) {
20926
+ timeout = $browser.defer(function() {
20927
+ listener();
20928
+ timeout = null;
20929
+ });
20930
+ }
20931
+ };
20932
+
20646
20933
  element.bind('keydown', function(event) {
20647
20934
  var key = event.keyCode;
20648
20935
 
@@ -20650,16 +20937,16 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
20650
20937
  // command modifiers arrows
20651
20938
  if (key === 91 || (15 < key && key < 19) || (37 <= key && key <= 40)) return;
20652
20939
 
20653
- if (!timeout) {
20654
- timeout = $browser.defer(function() {
20655
- listener();
20656
- timeout = null;
20657
- });
20658
- }
20940
+ deferListener();
20659
20941
  });
20660
20942
 
20661
20943
  // if user paste into input using mouse, we need "change" event to catch it
20662
20944
  element.bind('change', listener);
20945
+
20946
+ // if user modifies input value using context menu in IE, we need "paste" and "cut" events to catch it
20947
+ if ($sniffer.hasEvent('paste')) {
20948
+ element.bind('paste cut', deferListener);
20949
+ }
20663
20950
  }
20664
20951
 
20665
20952
 
@@ -20958,7 +21245,7 @@ function checkboxInputType(scope, element, attr, ctrl) {
20958
21245
  <tt>myForm.userName.$valid = {{myForm.userName.$valid}}</tt><br>
20959
21246
  <tt>myForm.userName.$error = {{myForm.userName.$error}}</tt><br>
20960
21247
  <tt>myForm.lastName.$valid = {{myForm.lastName.$valid}}</tt><br>
20961
- <tt>myForm.userName.$error = {{myForm.lastName.$error}}</tt><br>
21248
+ <tt>myForm.lastName.$error = {{myForm.lastName.$error}}</tt><br>
20962
21249
  <tt>myForm.$valid = {{myForm.$valid}}</tt><br>
20963
21250
  <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br>
20964
21251
  <tt>myForm.$error.minlength = {{!!myForm.$error.minlength}}</tt><br>
@@ -21221,7 +21508,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
21221
21508
  * For example {@link ng.directive:input input} or
21222
21509
  * {@link ng.directive:select select} directives call it.
21223
21510
  *
21224
- * It internally calls all `formatters` and if resulted value is valid, updates the model and
21511
+ * It internally calls all `parsers` and if resulted value is valid, updates the model and
21225
21512
  * calls all registered change listeners.
21226
21513
  *
21227
21514
  * @param {string} value Value from the view.
@@ -21527,7 +21814,7 @@ var ngValueDirective = function() {
21527
21814
  * Typically, you don't use `ngBind` directly, but instead you use the double curly markup like
21528
21815
  * `{{ expression }}` which is similar but less verbose.
21529
21816
  *
21530
- * Once scenario in which the use of `ngBind` is prefered over `{{ expression }}` binding is when
21817
+ * One scenario in which the use of `ngBind` is preferred over `{{ expression }}` binding is when
21531
21818
  * it's desirable to put bindings into template that is momentarily displayed by the browser in its
21532
21819
  * raw state before Angular compiles it. Since `ngBind` is an element attribute, it makes the
21533
21820
  * bindings invisible to the user while the page is loading.
@@ -21656,6 +21943,7 @@ var ngBindHtmlUnsafeDirective = [function() {
21656
21943
  function classDirective(name, selector) {
21657
21944
  name = 'ngClass' + name;
21658
21945
  return ngDirective(function(scope, element, attr) {
21946
+ var oldVal = undefined;
21659
21947
 
21660
21948
  scope.$watch(attr[name], ngClassWatchAction, true);
21661
21949
 
@@ -21667,9 +21955,9 @@ function classDirective(name, selector) {
21667
21955
 
21668
21956
  if (name !== 'ngClass') {
21669
21957
  scope.$watch('$index', function($index, old$index) {
21670
- var mod = $index % 2;
21671
- if (mod !== old$index % 2) {
21672
- if (mod == selector) {
21958
+ var mod = $index & 1;
21959
+ if (mod !== old$index & 1) {
21960
+ if (mod === selector) {
21673
21961
  addClass(scope.$eval(attr[name]));
21674
21962
  } else {
21675
21963
  removeClass(scope.$eval(attr[name]));
@@ -21679,13 +21967,14 @@ function classDirective(name, selector) {
21679
21967
  }
21680
21968
 
21681
21969
 
21682
- function ngClassWatchAction(newVal, oldVal) {
21970
+ function ngClassWatchAction(newVal) {
21683
21971
  if (selector === true || scope.$index % 2 === selector) {
21684
- if (oldVal && (newVal !== oldVal)) {
21972
+ if (oldVal && !equals(newVal,oldVal)) {
21685
21973
  removeClass(oldVal);
21686
21974
  }
21687
21975
  addClass(newVal);
21688
21976
  }
21977
+ oldVal = copy(newVal);
21689
21978
  }
21690
21979
 
21691
21980
 
@@ -21718,7 +22007,7 @@ function classDirective(name, selector) {
21718
22007
  *
21719
22008
  * The directive won't add duplicate classes if a particular class was already set.
21720
22009
  *
21721
- * When the expression changes, the previously added classes are removed and only then the classes
22010
+ * When the expression changes, the previously added classes are removed and only then the
21722
22011
  * new classes are added.
21723
22012
  *
21724
22013
  * @element ANY
@@ -21811,7 +22100,7 @@ var ngClassOddDirective = classDirective('Odd', 0);
21811
22100
  * @name ng.directive:ngClassEven
21812
22101
  *
21813
22102
  * @description
21814
- * The `ngClassOdd` and `ngClassEven` works exactly as
22103
+ * The `ngClassOdd` and `ngClassEven` directives work exactly as
21815
22104
  * {@link ng.directive:ngClass ngClass}, except it works in
21816
22105
  * conjunction with `ngRepeat` and takes affect only on odd (even) rows.
21817
22106
  *
@@ -21869,7 +22158,7 @@ var ngClassEvenDirective = classDirective('Even', 1);
21869
22158
  * `angular.min.js` files. Following is the css rule:
21870
22159
  *
21871
22160
  * <pre>
21872
- * [ng\:cloak], [ng-cloak], .ng-cloak {
22161
+ * [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
21873
22162
  * display: none;
21874
22163
  * }
21875
22164
  * </pre>
@@ -21928,8 +22217,7 @@ var ngCloakDirective = ngDirective({
21928
22217
  * * Controller — The `ngController` directive specifies a Controller class; the class has
21929
22218
  * methods that typically express the business logic behind the application.
21930
22219
  *
21931
- * Note that an alternative way to define controllers is via the `{@link ng.$route}`
21932
- * service.
22220
+ * Note that an alternative way to define controllers is via the {@link ng.$route $route} service.
21933
22221
  *
21934
22222
  * @element ANY
21935
22223
  * @scope
@@ -22020,16 +22308,32 @@ var ngControllerDirective = [function() {
22020
22308
  * @name ng.directive:ngCsp
22021
22309
  * @priority 1000
22022
22310
  *
22311
+ * @element html
22023
22312
  * @description
22024
22313
  * Enables [CSP (Content Security Policy)](https://developer.mozilla.org/en/Security/CSP) support.
22025
- * This directive should be used on the root element of the application (typically the `<html>`
22026
- * element or other element with the {@link ng.directive:ngApp ngApp}
22027
- * directive).
22028
- *
22029
- * If enabled the performance of template expression evaluator will suffer slightly, so don't enable
22030
- * this mode unless you need it.
22031
- *
22032
- * @element html
22314
+ *
22315
+ * This is necessary when developing things like Google Chrome Extensions.
22316
+ *
22317
+ * CSP forbids apps to use `eval` or `Function(string)` generated functions (among other things).
22318
+ * For us to be compatible, we just need to implement the "getterFn" in $parse without violating
22319
+ * any of these restrictions.
22320
+ *
22321
+ * AngularJS uses `Function(string)` generated functions as a speed optimization. By applying `ngCsp`
22322
+ * it is be possible to opt into the CSP compatible mode. When this mode is on AngularJS will
22323
+ * evaluate all expressions up to 30% slower than in non-CSP mode, but no security violations will
22324
+ * be raised.
22325
+ *
22326
+ * In order to use this feature put `ngCsp` directive on the root element of the application.
22327
+ *
22328
+ * @example
22329
+ * This example shows how to apply the `ngCsp` directive to the `html` tag.
22330
+ <pre>
22331
+ <!doctype html>
22332
+ <html ng-app ng-csp>
22333
+ ...
22334
+ ...
22335
+ </html>
22336
+ </pre>
22033
22337
  */
22034
22338
 
22035
22339
  var ngCspDirective = ['$sniffer', function($sniffer) {
@@ -22654,7 +22958,7 @@ var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interp
22654
22958
  if (!isNaN(value)) {
22655
22959
  //if explicit number rule such as 1, 2, 3... is defined, just use it. Otherwise,
22656
22960
  //check it against pluralization rules in $locale service
22657
- if (!whens[value]) value = $locale.pluralCat(value - offset);
22961
+ if (!(value in whens)) value = $locale.pluralCat(value - offset);
22658
22962
  return whensExpFns[value](scope, element, true);
22659
22963
  } else {
22660
22964
  return '';
@@ -22758,14 +23062,17 @@ var ngRepeatDirective = ngDirective({
22758
23062
  scope.$watch(function ngRepeatWatch(scope){
22759
23063
  var index, length,
22760
23064
  collection = scope.$eval(rhs),
22761
- collectionLength = size(collection, true),
22762
- childScope,
23065
+ cursor = iterStartElement, // current position of the node
22763
23066
  // Same as lastOrder but it has the current state. It will become the
22764
23067
  // lastOrder on the next iteration.
22765
23068
  nextOrder = new HashQueueMap(),
23069
+ arrayBound,
23070
+ childScope,
22766
23071
  key, value, // key/value of iteration
22767
- array, last, // last object information {scope, element, index}
22768
- cursor = iterStartElement; // current position of the node
23072
+ array,
23073
+ last; // last object information {scope, element, index}
23074
+
23075
+
22769
23076
 
22770
23077
  if (!isArray(collection)) {
22771
23078
  // if object, extract keys, sort them and use to determine order of iteration over obj props
@@ -22780,6 +23087,8 @@ var ngRepeatDirective = ngDirective({
22780
23087
  array = collection || [];
22781
23088
  }
22782
23089
 
23090
+ arrayBound = array.length-1;
23091
+
22783
23092
  // we are not using forEach for perf reasons (trying to avoid #call)
22784
23093
  for (index = 0, length = array.length; index < length; index++) {
22785
23094
  key = (collection === array) ? index : array[index];
@@ -22815,7 +23124,7 @@ var ngRepeatDirective = ngDirective({
22815
23124
  childScope.$index = index;
22816
23125
 
22817
23126
  childScope.$first = (index === 0);
22818
- childScope.$last = (index === (collectionLength - 1));
23127
+ childScope.$last = (index === arrayBound);
22819
23128
  childScope.$middle = !(childScope.$first || childScope.$last);
22820
23129
 
22821
23130
  if (!last) {
@@ -22982,11 +23291,13 @@ var ngStyleDirective = ngDirective(function(scope, element, attr) {
22982
23291
  * @description
22983
23292
  * Conditionally change the DOM structure.
22984
23293
  *
22985
- * @usageContent
22986
- * <ANY ng-switch-when="matchValue1">...</ANY>
23294
+ * @usage
23295
+ * <ANY ng-switch="expression">
23296
+ * <ANY ng-switch-when="matchValue1">...</ANY>
22987
23297
  * <ANY ng-switch-when="matchValue2">...</ANY>
22988
23298
  * ...
22989
23299
  * <ANY ng-switch-default>...</ANY>
23300
+ * </ANY>
22990
23301
  *
22991
23302
  * @scope
22992
23303
  * @param {*} ngSwitch|on expression to match against <tt>ng-switch-when</tt>.
@@ -23036,52 +23347,54 @@ var ngStyleDirective = ngDirective(function(scope, element, attr) {
23036
23347
  var NG_SWITCH = 'ng-switch';
23037
23348
  var ngSwitchDirective = valueFn({
23038
23349
  restrict: 'EA',
23039
- compile: function(element, attr) {
23350
+ require: 'ngSwitch',
23351
+ // asks for $scope to fool the BC controller module
23352
+ controller: ['$scope', function ngSwitchController() {
23353
+ this.cases = {};
23354
+ }],
23355
+ link: function(scope, element, attr, ctrl) {
23040
23356
  var watchExpr = attr.ngSwitch || attr.on,
23041
- cases = {};
23042
-
23043
- element.data(NG_SWITCH, cases);
23044
- return function(scope, element){
23045
- var selectedTransclude,
23046
- selectedElement,
23047
- selectedScope;
23048
-
23049
- scope.$watch(watchExpr, function ngSwitchWatchAction(value) {
23050
- if (selectedElement) {
23051
- selectedScope.$destroy();
23052
- selectedElement.remove();
23053
- selectedElement = selectedScope = null;
23054
- }
23055
- if ((selectedTransclude = cases['!' + value] || cases['?'])) {
23056
- scope.$eval(attr.change);
23057
- selectedScope = scope.$new();
23058
- selectedTransclude(selectedScope, function(caseElement) {
23059
- selectedElement = caseElement;
23060
- element.append(caseElement);
23061
- });
23062
- }
23063
- });
23064
- };
23357
+ selectedTransclude,
23358
+ selectedElement,
23359
+ selectedScope;
23360
+
23361
+ scope.$watch(watchExpr, function ngSwitchWatchAction(value) {
23362
+ if (selectedElement) {
23363
+ selectedScope.$destroy();
23364
+ selectedElement.remove();
23365
+ selectedElement = selectedScope = null;
23366
+ }
23367
+ if ((selectedTransclude = ctrl.cases['!' + value] || ctrl.cases['?'])) {
23368
+ scope.$eval(attr.change);
23369
+ selectedScope = scope.$new();
23370
+ selectedTransclude(selectedScope, function(caseElement) {
23371
+ selectedElement = caseElement;
23372
+ element.append(caseElement);
23373
+ });
23374
+ }
23375
+ });
23065
23376
  }
23066
23377
  });
23067
23378
 
23068
23379
  var ngSwitchWhenDirective = ngDirective({
23069
23380
  transclude: 'element',
23070
23381
  priority: 500,
23382
+ require: '^ngSwitch',
23071
23383
  compile: function(element, attrs, transclude) {
23072
- var cases = element.inheritedData(NG_SWITCH);
23073
- assertArg(cases);
23074
- cases['!' + attrs.ngSwitchWhen] = transclude;
23384
+ return function(scope, element, attr, ctrl) {
23385
+ ctrl.cases['!' + attrs.ngSwitchWhen] = transclude;
23386
+ };
23075
23387
  }
23076
23388
  });
23077
23389
 
23078
23390
  var ngSwitchDefaultDirective = ngDirective({
23079
23391
  transclude: 'element',
23080
23392
  priority: 500,
23393
+ require: '^ngSwitch',
23081
23394
  compile: function(element, attrs, transclude) {
23082
- var cases = element.inheritedData(NG_SWITCH);
23083
- assertArg(cases);
23084
- cases['?'] = transclude;
23395
+ return function(scope, element, attr, ctrl) {
23396
+ ctrl.cases['?'] = transclude;
23397
+ };
23085
23398
  }
23086
23399
  });
23087
23400
 
@@ -23170,7 +23483,7 @@ var ngTranscludeDirective = ngDirective({
23170
23483
  <hr />
23171
23484
 
23172
23485
  <pre>$location.path() = {{$location.path()}}</pre>
23173
- <pre>$route.current.template = {{$route.current.template}}</pre>
23486
+ <pre>$route.current.templateUrl = {{$route.current.templateUrl}}</pre>
23174
23487
  <pre>$route.current.params = {{$route.current.params}}</pre>
23175
23488
  <pre>$route.current.scope.name = {{$route.current.scope.name}}</pre>
23176
23489
  <pre>$routeParams = {{$routeParams}}</pre>
@@ -23289,7 +23602,7 @@ var ngViewDirective = ['$http', '$templateCache', '$route', '$anchorScroll', '$c
23289
23602
  if (current.controller) {
23290
23603
  locals.$scope = lastScope;
23291
23604
  controller = $controller(current.controller, locals);
23292
- element.contents().data('$ngControllerController', controller);
23605
+ element.children().data('$ngControllerController', controller);
23293
23606
  }
23294
23607
 
23295
23608
  link(lastScope);
@@ -23378,7 +23691,8 @@ var scriptDirective = ['$templateCache', function($templateCache) {
23378
23691
  * `select` model to be bound to a non-string value. This is because an option element can currently
23379
23692
  * be bound to string values only.
23380
23693
  *
23381
- * @param {string} name assignable expression to data-bind to.
23694
+ * @param {string} ngModel Assignable angular expression to data-bind to.
23695
+ * @param {string=} name Property name of the form under which the control is published.
23382
23696
  * @param {string=} required The control is considered valid only if value is entered.
23383
23697
  * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
23384
23698
  * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
@@ -23473,7 +23787,7 @@ var scriptDirective = ['$templateCache', function($templateCache) {
23473
23787
 
23474
23788
  var ngOptionsDirective = valueFn({ terminal: true });
23475
23789
  var selectDirective = ['$compile', '$parse', function($compile, $parse) {
23476
- //00001111100000000000222200000000000000000000003333000000000000044444444444444444000000000555555555555555550000000666666666666666660000000000000007777
23790
+ //0000111110000000000022220000000000000000000000333300000000000000444444444444444440000000005555555555555555500000006666666666666666600000000000000077770
23477
23791
  var NG_OPTIONS_REGEXP = /^\s*(.*?)(?:\s+as\s+(.*?))?(?:\s+group\s+by\s+(.*))?\s+for\s+(?:([\$\w][\$\w\d]*)|(?:\(\s*([\$\w][\$\w\d]*)\s*,\s*([\$\w][\$\w\d]*)\s*\)))\s+in\s+(.*)$/,
23478
23792
  nullModelCtrl = {$setViewValue: noop};
23479
23793
 
@@ -23616,7 +23930,7 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
23616
23930
  var lastView;
23617
23931
  ctrl.$render = function() {
23618
23932
  var items = new HashMap(ctrl.$viewValue);
23619
- forEach(selectElement.children(), function(option) {
23933
+ forEach(selectElement.find('option'), function(option) {
23620
23934
  option.selected = isDefined(items.get(option.value));
23621
23935
  });
23622
23936
  };
@@ -23633,7 +23947,7 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
23633
23947
  selectElement.bind('change', function() {
23634
23948
  scope.$apply(function() {
23635
23949
  var array = [];
23636
- forEach(selectElement.children(), function(option) {
23950
+ forEach(selectElement.find('option'), function(option) {
23637
23951
  if (option.selected) {
23638
23952
  array.push(option.value);
23639
23953
  }
@@ -23745,10 +24059,6 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
23745
24059
 
23746
24060
  if (multiple) {
23747
24061
  selectedSet = new HashMap(modelValue);
23748
- } else if (modelValue === null || nullOption) {
23749
- // if we are not multiselect, and we are null then we have to add the nullOption
23750
- optionGroups[''].push({selected:modelValue === null, id:'', label:''});
23751
- selectedSet = true;
23752
24062
  }
23753
24063
 
23754
24064
  // We now build up the list of options we need (we merge later)
@@ -23773,9 +24083,14 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
23773
24083
  selected: selected // determine if we should be selected
23774
24084
  });
23775
24085
  }
23776
- if (!multiple && !selectedSet) {
23777
- // nothing was selected, we have to insert the undefined item
23778
- optionGroups[''].unshift({id:'?', label:'', selected:true});
24086
+ if (!multiple) {
24087
+ if (nullOption || modelValue === null) {
24088
+ // insert null option if we have a placeholder, or the model is null
24089
+ optionGroups[''].unshift({id:'', label:'', selected:!selectedSet});
24090
+ } else if (!selectedSet) {
24091
+ // option could not be found, we have to insert the undefined item
24092
+ optionGroups[''].unshift({id:'?', label:'', selected:true});
24093
+ }
23779
24094
  }
23780
24095
 
23781
24096
  // Now we need to update the list of DOM nodes to match the optionGroups we computed above
@@ -23819,7 +24134,8 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
23819
24134
  if (existingOption.id !== option.id) {
23820
24135
  lastElement.val(existingOption.id = option.id);
23821
24136
  }
23822
- if (existingOption.element.selected !== option.selected) {
24137
+ // lastElement.prop('selected') provided by jQuery has side-effects
24138
+ if (lastElement[0].selected !== option.selected) {
23823
24139
  lastElement.prop('selected', (existingOption.selected = option.selected));
23824
24140
  }
23825
24141
  } else {
@@ -24911,160 +25227,6 @@ angular.scenario.ObjectModel.Step.prototype.setErrorStatus = function(status, er
24911
25227
  this.line = line;
24912
25228
  };
24913
25229
 
24914
- /**
24915
- * The representation of define blocks. Don't used directly, instead use
24916
- * define() in your tests.
24917
- *
24918
- * @param {string} descName Name of the block
24919
- * @param {Object} parent describe or undefined if the root.
24920
- */
24921
- angular.scenario.Describe = function(descName, parent) {
24922
- this.only = parent && parent.only;
24923
- this.beforeEachFns = [];
24924
- this.afterEachFns = [];
24925
- this.its = [];
24926
- this.children = [];
24927
- this.name = descName;
24928
- this.parent = parent;
24929
- this.id = angular.scenario.Describe.id++;
24930
-
24931
- /**
24932
- * Calls all before functions.
24933
- */
24934
- var beforeEachFns = this.beforeEachFns;
24935
- this.setupBefore = function() {
24936
- if (parent) parent.setupBefore.call(this);
24937
- angular.forEach(beforeEachFns, function(fn) { fn.call(this); }, this);
24938
- };
24939
-
24940
- /**
24941
- * Calls all after functions.
24942
- */
24943
- var afterEachFns = this.afterEachFns;
24944
- this.setupAfter = function() {
24945
- angular.forEach(afterEachFns, function(fn) { fn.call(this); }, this);
24946
- if (parent) parent.setupAfter.call(this);
24947
- };
24948
- };
24949
-
24950
- // Shared Unique ID generator for every describe block
24951
- angular.scenario.Describe.id = 0;
24952
-
24953
- // Shared Unique ID generator for every it (spec)
24954
- angular.scenario.Describe.specId = 0;
24955
-
24956
- /**
24957
- * Defines a block to execute before each it or nested describe.
24958
- *
24959
- * @param {function()} body Body of the block.
24960
- */
24961
- angular.scenario.Describe.prototype.beforeEach = function(body) {
24962
- this.beforeEachFns.push(body);
24963
- };
24964
-
24965
- /**
24966
- * Defines a block to execute after each it or nested describe.
24967
- *
24968
- * @param {function()} body Body of the block.
24969
- */
24970
- angular.scenario.Describe.prototype.afterEach = function(body) {
24971
- this.afterEachFns.push(body);
24972
- };
24973
-
24974
- /**
24975
- * Creates a new describe block that's a child of this one.
24976
- *
24977
- * @param {string} name Name of the block. Appended to the parent block's name.
24978
- * @param {function()} body Body of the block.
24979
- */
24980
- angular.scenario.Describe.prototype.describe = function(name, body) {
24981
- var child = new angular.scenario.Describe(name, this);
24982
- this.children.push(child);
24983
- body.call(child);
24984
- };
24985
-
24986
- /**
24987
- * Same as describe() but makes ddescribe blocks the only to run.
24988
- *
24989
- * @param {string} name Name of the test.
24990
- * @param {function()} body Body of the block.
24991
- */
24992
- angular.scenario.Describe.prototype.ddescribe = function(name, body) {
24993
- var child = new angular.scenario.Describe(name, this);
24994
- child.only = true;
24995
- this.children.push(child);
24996
- body.call(child);
24997
- };
24998
-
24999
- /**
25000
- * Use to disable a describe block.
25001
- */
25002
- angular.scenario.Describe.prototype.xdescribe = angular.noop;
25003
-
25004
- /**
25005
- * Defines a test.
25006
- *
25007
- * @param {string} name Name of the test.
25008
- * @param {function()} vody Body of the block.
25009
- */
25010
- angular.scenario.Describe.prototype.it = function(name, body) {
25011
- this.its.push({
25012
- id: angular.scenario.Describe.specId++,
25013
- definition: this,
25014
- only: this.only,
25015
- name: name,
25016
- before: this.setupBefore,
25017
- body: body,
25018
- after: this.setupAfter
25019
- });
25020
- };
25021
-
25022
- /**
25023
- * Same as it() but makes iit tests the only test to run.
25024
- *
25025
- * @param {string} name Name of the test.
25026
- * @param {function()} body Body of the block.
25027
- */
25028
- angular.scenario.Describe.prototype.iit = function(name, body) {
25029
- this.it.apply(this, arguments);
25030
- this.its[this.its.length-1].only = true;
25031
- };
25032
-
25033
- /**
25034
- * Use to disable a test block.
25035
- */
25036
- angular.scenario.Describe.prototype.xit = angular.noop;
25037
-
25038
- /**
25039
- * Gets an array of functions representing all the tests (recursively).
25040
- * that can be executed with SpecRunner's.
25041
- *
25042
- * @return {Array<Object>} Array of it blocks {
25043
- * definition : Object // parent Describe
25044
- * only: boolean
25045
- * name: string
25046
- * before: Function
25047
- * body: Function
25048
- * after: Function
25049
- * }
25050
- */
25051
- angular.scenario.Describe.prototype.getSpecs = function() {
25052
- var specs = arguments[0] || [];
25053
- angular.forEach(this.children, function(child) {
25054
- child.getSpecs(specs);
25055
- });
25056
- angular.forEach(this.its, function(it) {
25057
- specs.push(it);
25058
- });
25059
- var only = [];
25060
- angular.forEach(specs, function(it) {
25061
- if (it.only) {
25062
- only.push(it);
25063
- }
25064
- });
25065
- return (only.length && only) || specs;
25066
- };
25067
-
25068
25230
  /**
25069
25231
  * Runner for scenarios
25070
25232
  *
@@ -25635,13 +25797,13 @@ angular.scenario.dsl('binding', function() {
25635
25797
  */
25636
25798
  angular.scenario.dsl('input', function() {
25637
25799
  var chain = {};
25638
- var supportInputEvent = 'oninput' in document.createElement('div');
25800
+ var supportInputEvent = 'oninput' in document.createElement('div') && msie != 9;
25639
25801
 
25640
25802
  chain.enter = function(value, event) {
25641
25803
  return this.addFutureAction("input '" + this.name + "' enter '" + value + "'", function($window, $document, done) {
25642
25804
  var input = $document.elements('[ng\\:model="$1"]', this.name).filter(':input');
25643
25805
  input.val(value);
25644
- input.trigger(event || supportInputEvent && 'input' || 'change');
25806
+ input.trigger(event || (supportInputEvent ? 'input' : 'change'));
25645
25807
  done();
25646
25808
  });
25647
25809
  };
@@ -26108,7 +26270,7 @@ angular.scenario.output('xml', function(context, runner, model) {
26108
26270
  if (step.error) {
26109
26271
  var error = $('<error></error>');
26110
26272
  stepContext.append(error);
26111
- error.text(formatException(stepContext.error));
26273
+ error.text(formatException(step.error));
26112
26274
  }
26113
26275
  });
26114
26276
  });
@@ -26121,6 +26283,7 @@ angular.scenario.output('xml', function(context, runner, model) {
26121
26283
  angular.scenario.output('object', function(context, runner, model) {
26122
26284
  runner.$window.$result = model.value;
26123
26285
  });
26286
+
26124
26287
  bindJQuery();
26125
26288
  publishExternalAPI(angular);
26126
26289
 
@@ -26144,4 +26307,4 @@ if (config.autotest) {
26144
26307
  })(window, document);
26145
26308
 
26146
26309
  angular.element(document).find('head').append('<style type="text/css">@charset "UTF-8";\n\n[ng\\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak],\n.ng-cloak, .x-ng-cloak {\n display: none;\n}\n\nng\\:form {\n display: block;\n}\n</style>');
26147
- angular.element(document).find('head').append('<style type="text/css">@charset "UTF-8";\n/* CSS Document */\n\n/** Structure */\nbody {\n font-family: Arial, sans-serif;\n margin: 0;\n font-size: 14px;\n}\n\n#system-error {\n font-size: 1.5em;\n text-align: center;\n}\n\n#json, #xml {\n display: none;\n}\n\n#header {\n position: fixed;\n width: 100%;\n}\n\n#specs {\n padding-top: 50px;\n}\n\n#header .angular {\n font-family: Courier New, monospace;\n font-weight: bold;\n}\n\n#header h1 {\n font-weight: normal;\n float: left;\n font-size: 30px;\n line-height: 30px;\n margin: 0;\n padding: 10px 10px;\n height: 30px;\n}\n\n#application h2,\n#specs h2 {\n margin: 0;\n padding: 0.5em;\n font-size: 1.1em;\n}\n\n#status-legend {\n margin-top: 10px;\n margin-right: 10px;\n}\n\n#header,\n#application,\n.test-info,\n.test-actions li {\n overflow: hidden;\n}\n\n#application {\n margin: 10px;\n}\n\n#application iframe {\n width: 100%;\n height: 758px;\n}\n\n#application .popout {\n float: right;\n}\n\n#application iframe {\n border: none;\n}\n\n.tests li,\n.test-actions li,\n.test-it li,\n.test-it ol,\n.status-display {\n list-style-type: none;\n}\n\n.tests,\n.test-it ol,\n.status-display {\n margin: 0;\n padding: 0;\n}\n\n.test-info {\n margin-left: 1em;\n margin-top: 0.5em;\n border-radius: 8px 0 0 8px;\n -webkit-border-radius: 8px 0 0 8px;\n -moz-border-radius: 8px 0 0 8px;\n cursor: pointer;\n}\n\n.test-info:hover .test-name {\n text-decoration: underline;\n}\n\n.test-info .closed:before {\n content: \'\\25b8\\00A0\';\n}\n\n.test-info .open:before {\n content: \'\\25be\\00A0\';\n font-weight: bold;\n}\n\n.test-it ol {\n margin-left: 2.5em;\n}\n\n.status-display,\n.status-display li {\n float: right;\n}\n\n.status-display li {\n padding: 5px 10px;\n}\n\n.timer-result,\n.test-title {\n display: inline-block;\n margin: 0;\n padding: 4px;\n}\n\n.test-actions .test-title,\n.test-actions .test-result {\n display: table-cell;\n padding-left: 0.5em;\n padding-right: 0.5em;\n}\n\n.test-actions {\n display: table;\n}\n\n.test-actions li {\n display: table-row;\n}\n\n.timer-result {\n width: 4em;\n padding: 0 10px;\n text-align: right;\n font-family: monospace;\n}\n\n.test-it pre,\n.test-actions pre {\n clear: left;\n color: black;\n margin-left: 6em;\n}\n\n.test-describe {\n padding-bottom: 0.5em;\n}\n\n.test-describe .test-describe {\n margin: 5px 5px 10px 2em;\n}\n\n.test-actions .status-pending .test-title:before {\n content: \'\\00bb\\00A0\';\n}\n\n.scrollpane {\n max-height: 20em;\n overflow: auto;\n}\n\n/** Colors */\n\n#header {\n background-color: #F2C200;\n}\n\n#specs h2 {\n border-top: 2px solid #BABAD1;\n}\n\n#specs h2,\n#application h2 {\n background-color: #efefef;\n}\n\n#application {\n border: 1px solid #BABAD1;\n}\n\n.test-describe .test-describe {\n border-left: 1px solid #BABAD1;\n border-right: 1px solid #BABAD1;\n border-bottom: 1px solid #BABAD1;\n}\n\n.status-display {\n border: 1px solid #777;\n}\n\n.status-display .status-pending,\n.status-pending .test-info {\n background-color: #F9EEBC;\n}\n\n.status-display .status-success,\n.status-success .test-info {\n background-color: #B1D7A1;\n}\n\n.status-display .status-failure,\n.status-failure .test-info {\n background-color: #FF8286;\n}\n\n.status-display .status-error,\n.status-error .test-info {\n background-color: black;\n color: white;\n}\n\n.test-actions .status-success .test-title {\n color: #30B30A;\n}\n\n.test-actions .status-failure .test-title {\n color: #DF0000;\n}\n\n.test-actions .status-error .test-title {\n color: black;\n}\n\n.test-actions .timer-result {\n color: #888;\n}\n</style>');
26310
+ angular.element(document).find('head').append('<style type="text/css">@charset "UTF-8";\n/* CSS Document */\n\n/** Structure */\nbody {\n font-family: Arial, sans-serif;\n margin: 0;\n font-size: 14px;\n}\n\n#system-error {\n font-size: 1.5em;\n text-align: center;\n}\n\n#json, #xml {\n display: none;\n}\n\n#header {\n position: fixed;\n width: 100%;\n}\n\n#specs {\n padding-top: 50px;\n}\n\n#header .angular {\n font-family: Courier New, monospace;\n font-weight: bold;\n}\n\n#header h1 {\n font-weight: normal;\n float: left;\n font-size: 30px;\n line-height: 30px;\n margin: 0;\n padding: 10px 10px;\n height: 30px;\n}\n\n#application h2,\n#specs h2 {\n margin: 0;\n padding: 0.5em;\n font-size: 1.1em;\n}\n\n#status-legend {\n margin-top: 10px;\n margin-right: 10px;\n}\n\n#header,\n#application,\n.test-info,\n.test-actions li {\n overflow: hidden;\n}\n\n#application {\n margin: 10px;\n}\n\n#application iframe {\n width: 100%;\n height: 758px;\n}\n\n#application .popout {\n float: right;\n}\n\n#application iframe {\n border: none;\n}\n\n.tests li,\n.test-actions li,\n.test-it li,\n.test-it ol,\n.status-display {\n list-style-type: none;\n}\n\n.tests,\n.test-it ol,\n.status-display {\n margin: 0;\n padding: 0;\n}\n\n.test-info {\n margin-left: 1em;\n margin-top: 0.5em;\n border-radius: 8px 0 0 8px;\n -webkit-border-radius: 8px 0 0 8px;\n -moz-border-radius: 8px 0 0 8px;\n cursor: pointer;\n}\n\n.test-info:hover .test-name {\n text-decoration: underline;\n}\n\n.test-info .closed:before {\n content: \'\\25b8\\00A0\';\n}\n\n.test-info .open:before {\n content: \'\\25be\\00A0\';\n font-weight: bold;\n}\n\n.test-it ol {\n margin-left: 2.5em;\n}\n\n.status-display,\n.status-display li {\n float: right;\n}\n\n.status-display li {\n padding: 5px 10px;\n}\n\n.timer-result,\n.test-title {\n display: inline-block;\n margin: 0;\n padding: 4px;\n}\n\n.test-actions .test-title,\n.test-actions .test-result {\n display: table-cell;\n padding-left: 0.5em;\n padding-right: 0.5em;\n}\n\n.test-actions {\n display: table;\n}\n\n.test-actions li {\n display: table-row;\n}\n\n.timer-result {\n width: 4em;\n padding: 0 10px;\n text-align: right;\n font-family: monospace;\n}\n\n.test-it pre,\n.test-actions pre {\n clear: left;\n color: black;\n margin-left: 6em;\n}\n\n.test-describe {\n padding-bottom: 0.5em;\n}\n\n.test-describe .test-describe {\n margin: 5px 5px 10px 2em;\n}\n\n.test-actions .status-pending .test-title:before {\n content: \'\\00bb\\00A0\';\n}\n\n.scrollpane {\n max-height: 20em;\n overflow: auto;\n}\n\n/** Colors */\n\n#header {\n background-color: #F2C200;\n}\n\n#specs h2 {\n border-top: 2px solid #BABAD1;\n}\n\n#specs h2,\n#application h2 {\n background-color: #efefef;\n}\n\n#application {\n border: 1px solid #BABAD1;\n}\n\n.test-describe .test-describe {\n border-left: 1px solid #BABAD1;\n border-right: 1px solid #BABAD1;\n border-bottom: 1px solid #BABAD1;\n}\n\n.status-display {\n border: 1px solid #777;\n}\n\n.status-display .status-pending,\n.status-pending .test-info {\n background-color: #F9EEBC;\n}\n\n.status-display .status-success,\n.status-success .test-info {\n background-color: #B1D7A1;\n}\n\n.status-display .status-failure,\n.status-failure .test-info {\n background-color: #FF8286;\n}\n\n.status-display .status-error,\n.status-error .test-info {\n background-color: black;\n color: white;\n}\n\n.test-actions .status-success .test-title {\n color: #30B30A;\n}\n\n.test-actions .status-failure .test-title {\n color: #DF0000;\n}\n\n.test-actions .status-error .test-title {\n color: black;\n}\n\n.test-actions .timer-result {\n color: #888;\n}\n</style>');