mongo_browser 0.2.0.rc2 → 0.2.5
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +3 -1
- data/.rspec +1 -1
- data/.travis.yml +6 -1
- data/CHANGELOG.md +15 -0
- data/{grunt.js → Gruntfile.js} +10 -8
- data/Procfile +1 -0
- data/README.md +44 -2
- data/Rakefile +1 -12
- data/app/assets/images/ajax-loader.gif +0 -0
- data/app/assets/javascripts/app/controllers/{breadcrumbs.js.coffee → breadcrumbs_controller.js.coffee} +4 -7
- data/app/assets/javascripts/app/controllers/collections/index_controller.js.coffee +38 -0
- data/app/assets/javascripts/app/controllers/collections/stats_controller.js.coffee +17 -0
- data/app/assets/javascripts/app/controllers/{databases.js.coffee → databases/index_controller.js.coffee} +11 -15
- data/app/assets/javascripts/app/controllers/databases/stats_controller.js.coffee +15 -0
- data/app/assets/javascripts/app/controllers/documents/index_controller.js.coffee +54 -0
- data/app/assets/javascripts/app/controllers/documents/show_controller.js.coffee +38 -0
- data/app/assets/javascripts/app/controllers/main_controller.js.coffee +15 -0
- data/app/assets/javascripts/app/controllers/servers/show_controller.js.coffee +17 -0
- data/app/assets/javascripts/app/directives.js.coffee +23 -0
- data/app/assets/javascripts/app/filters.js.coffee +14 -1
- data/app/assets/javascripts/app/modules/alerts.js.coffee +58 -0
- data/app/assets/javascripts/app/modules/pager.js.coffee +2 -2
- data/app/assets/javascripts/app/modules/spinner.js.coffee +29 -0
- data/app/assets/javascripts/app/modules/table_filter.js.coffee +4 -4
- data/app/assets/javascripts/app/resources.js.coffee +14 -8
- data/app/assets/javascripts/app/services.js.coffee +11 -33
- data/app/assets/javascripts/application.js.coffee +62 -34
- data/app/assets/javascripts/application.test.js.coffee +5 -0
- data/app/assets/javascripts/compiled_templates.js.coffee +1 -0
- data/app/assets/javascripts/vendor.js.coffee +0 -1
- data/app/assets/stylesheets/application.css.scss +36 -18
- data/{public/index.html → app/views/index.erb} +8 -8
- data/bin/mongo_browser +2 -13
- data/config.ru +3 -1
- data/lib/mongo_browser.rb +1 -0
- data/lib/mongo_browser/api.rb +11 -0
- data/lib/mongo_browser/api/collections.rb +34 -0
- data/lib/mongo_browser/api/databases.rb +32 -0
- data/lib/mongo_browser/api/documents.rb +37 -0
- data/lib/mongo_browser/api/mongo.rb +41 -0
- data/lib/mongo_browser/application.rb +8 -174
- data/lib/mongo_browser/application/development.rb +32 -0
- data/lib/mongo_browser/cli.rb +48 -0
- data/lib/mongo_browser/entities.rb +43 -0
- data/lib/mongo_browser/models/collection.rb +7 -12
- data/lib/mongo_browser/models/document.rb +5 -1
- data/lib/mongo_browser/models/pager.rb +22 -9
- data/lib/mongo_browser/version.rb +1 -1
- data/mongo_browser.gemspec +22 -15
- data/package.json +30 -0
- data/public/ng/templates/alerts.html +6 -0
- data/public/ng/templates/collections/index.html +39 -0
- data/public/ng/templates/collections/stats.html +18 -0
- data/public/ng/templates/databases/index.html +35 -0
- data/public/ng/templates/databases/stats.html +18 -0
- data/public/ng/templates/documents/index.html +40 -0
- data/public/ng/templates/documents/show.html +17 -0
- data/{app/assets → public/ng}/templates/pager.html +0 -0
- data/{app/assets/templates/server_info.html → public/ng/templates/server/show.html} +1 -1
- data/{app/assets → public/ng}/templates/table_filter.html +0 -0
- data/script/ci_all +5 -1
- data/script/ci_e2e +5 -2
- data/script/ci_javascripts +1 -1
- data/script/ci_rspec +1 -1
- data/spec/javascripts/app/controllers/{breadcrumbs_spec.js.coffee → breadcrumbs_controller_spec.js.coffee} +1 -1
- data/spec/javascripts/app/controllers/collections/index_controller_spec.js.coffee +95 -0
- data/spec/javascripts/app/controllers/collections/stats_controller_spec.js.coffee +34 -0
- data/spec/javascripts/app/controllers/databases/index_controller_spec.js.coffee +93 -0
- data/spec/javascripts/app/controllers/databases/stats_controller_spec.js.coffee +30 -0
- data/spec/javascripts/app/controllers/documents/index_controller_spec.js.coffee +108 -0
- data/spec/javascripts/app/controllers/documents/show_controller_spec.js.coffee +94 -0
- data/spec/javascripts/app/controllers/{main_spec.js.coffee → main_controller_spec.js.coffee} +2 -2
- data/spec/javascripts/app/controllers/{server_info_spec.js.coffee → server/show_controller_spec.js.coffee} +5 -6
- data/spec/javascripts/app/directives_spec.js.coffee +108 -24
- data/spec/javascripts/app/filters_spec.js.coffee +31 -5
- data/spec/javascripts/app/modules/alerts_spec.js.coffee +138 -0
- data/spec/javascripts/app/modules/dialogs_spec.js.coffee +1 -2
- data/spec/javascripts/app/modules/pager_spec.js.coffee +0 -1
- data/spec/javascripts/app/modules/spinner_spec.js.coffee +65 -0
- data/spec/javascripts/app/modules/table_filter_spec.js.coffee +9 -9
- data/spec/javascripts/app/resources_spec.js.coffee +99 -0
- data/spec/javascripts/app/services_spec.js.coffee +31 -71
- data/spec/javascripts/config/{testacular-e2e.conf.js → karma-e2e.conf.js} +1 -1
- data/spec/javascripts/config/{testacular.conf.js → karma.conf.js} +2 -3
- data/spec/javascripts/e2e/collection_stats_scenario.js.coffee +12 -0
- data/spec/javascripts/e2e/collections_scenario.js.coffee +59 -20
- data/spec/javascripts/e2e/database_stats_scenario.js.coffee +11 -0
- data/spec/javascripts/e2e/databases_scenario.js.coffee +37 -36
- data/spec/javascripts/e2e/document_show_scenario.js.coffee +31 -0
- data/spec/javascripts/e2e/documents_pagination_scenario.js.coffee +33 -0
- data/spec/javascripts/e2e/documents_scenario.js.coffee +43 -4
- data/spec/javascripts/e2e/server_info_scenario.js.coffee +8 -2
- data/spec/javascripts/helpers/mocks.js.coffee +2 -0
- data/spec/javascripts/helpers_e2e/dsl.js.coffee +20 -0
- data/spec/javascripts/lib/angular-mocks.js +64 -16
- data/spec/javascripts/lib/angular-scenario.js +724 -561
- data/spec/javascripts/runner.html +5 -5
- data/spec/lib/api/collections_spec.rb +62 -0
- data/spec/lib/api/databases_spec.rb +58 -0
- data/spec/lib/api/documents_spec.rb +135 -0
- data/spec/lib/api/mongo_spec.rb +27 -0
- data/spec/lib/cli_spec.rb +19 -0
- data/spec/lib/entities_spec.rb +39 -0
- data/spec/lib/models/collection_spec.rb +16 -10
- data/spec/lib/models/database_spec.rb +4 -4
- data/spec/lib/models/document_spec.rb +5 -5
- data/spec/lib/models/pager_spec.rb +20 -11
- data/spec/spec_helper.rb +7 -15
- data/spec/support/api_example_group.rb +45 -0
- data/spec/support/fixtures.rb +10 -6
- data/spec/support/matchers/expose.rb +18 -0
- data/vendor/assets/javascripts/angular/angular-bootstrap.js +1 -1
- data/vendor/assets/javascripts/angular/angular-resource.js +78 -56
- data/vendor/assets/javascripts/angular/angular-sanitize.js +3 -1
- data/vendor/assets/javascripts/angular/angular.js +720 -404
- metadata +323 -183
- data/app/assets/javascripts/app.js.coffee +0 -8
- data/app/assets/javascripts/app/controllers.js.coffee +0 -2
- data/app/assets/javascripts/app/controllers/alerts.js.coffee +0 -12
- data/app/assets/javascripts/app/controllers/collections.js.coffee +0 -40
- data/app/assets/javascripts/app/controllers/documents.js.coffee +0 -49
- data/app/assets/javascripts/app/controllers/main.js.coffee +0 -10
- data/app/assets/javascripts/app/controllers/server_info.js.coffee +0 -14
- data/app/assets/javascripts/templates.js.coffee +0 -1
- data/app/assets/javascripts/templates/.gitkeep +0 -0
- data/app/assets/templates/collections.html +0 -53
- data/app/assets/templates/databases.html +0 -32
- data/app/assets/templates/documents.html +0 -45
- data/config-e2e.ru +0 -20
- data/spec/features/collections_list_spec.rb +0 -64
- data/spec/features/documents_list_spec.rb +0 -139
- data/spec/features/server_info_spec.rb +0 -23
- data/spec/javascripts/app/controllers/alerts_spec.js.coffee +0 -36
- data/spec/javascripts/app/controllers/collections_spec.js.coffee +0 -78
- data/spec/javascripts/app/controllers/databases_spec.js.coffee +0 -55
- data/spec/javascripts/app/controllers/documents_spec.js.coffee +0 -62
- data/spec/javascripts/helpers_e2e/app_element.js.coffee +0 -6
- data/spec/support/feature_example_group.rb +0 -53
- data/spec/support/matchers/have_flash_message.rb +0 -16
- data/spec/support/mongod.rb +0 -91
- 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.
|
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
|
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 (
|
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
|
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
|
-
|
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
|
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)
|
10036
|
-
|
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] &&
|
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
|
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
|
-
|
10169
|
-
|
10170
|
-
|
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 ?
|
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
|
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
|
-
*
|
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
|
-
|
10327
|
-
|
10328
|
-
|
10329
|
-
|
10330
|
-
|
10331
|
-
|
10332
|
-
|
10333
|
-
|
10334
|
-
['$rootScope', '$rootElement', '$compile', '$injector',
|
10335
|
-
|
10336
|
-
|
10337
|
-
|
10338
|
-
|
10339
|
-
|
10340
|
-
|
10341
|
-
|
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
|
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.
|
10656
|
-
major: 1, //
|
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:
|
10659
|
-
codeName: '
|
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
|
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
|
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
|
11377
|
-
|
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.
|
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
|
-
|
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
|
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
|
-
* $
|
11831
|
+
* $injector.invoke(function(serviceA){});
|
11736
11832
|
*
|
11737
11833
|
* // annotated
|
11738
11834
|
* function explicit(serviceA) {};
|
11739
11835
|
* explicit.$inject = ['serviceA'];
|
11740
|
-
* $
|
11836
|
+
* $injector.invoke(explicit);
|
11741
11837
|
*
|
11742
11838
|
* // inline
|
11743
|
-
* $
|
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 `$
|
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(
|
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
|
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
|
-
*
|
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
|
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 $
|
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?\:\/\/[^\/]*/, '') :
|
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
|
-
|
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
|
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,
|
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
|
-
|
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
|
-
|
13203
|
-
|
13360
|
+
var linkFns = [],
|
13361
|
+
nodeLinkFn, childLinkFn, directives, attrs, linkFnFound;
|
13204
13362
|
|
13205
|
-
|
13206
|
-
|
13363
|
+
for(var i = 0; i < nodeList.length; i++) {
|
13364
|
+
attrs = new Attributes();
|
13207
13365
|
|
13208
|
-
|
13209
|
-
|
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
|
-
|
13212
|
-
|
13213
|
-
|
13369
|
+
nodeLinkFn = (directives.length)
|
13370
|
+
? applyDirectivesToNode(directives, nodeList[i], attrs, transcludeFn, $rootElement)
|
13371
|
+
: null;
|
13214
13372
|
|
13215
|
-
|
13216
|
-
|
13217
|
-
|
13218
|
-
|
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
|
-
|
13221
|
-
|
13222
|
-
|
13223
|
-
|
13378
|
+
linkFns.push(nodeLinkFn);
|
13379
|
+
linkFns.push(childLinkFn);
|
13380
|
+
linkFnFound = (linkFnFound || nodeLinkFn || childLinkFn);
|
13381
|
+
}
|
13224
13382
|
|
13225
|
-
|
13226
|
-
|
13383
|
+
// return a linking function if we have found anything, null otherwise
|
13384
|
+
return linkFnFound ? compositeLinkFn : null;
|
13227
13385
|
|
13228
|
-
|
13229
|
-
|
13386
|
+
function compositeLinkFn(scope, nodeList, $rootElement, boundTranscludeFn) {
|
13387
|
+
var nodeLinkFn, childLinkFn, node, childScope, childTranscludeFn, i, ii, n;
|
13230
13388
|
|
13231
|
-
|
13232
|
-
|
13233
|
-
|
13234
|
-
|
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
|
-
|
13237
|
-
|
13238
|
-
|
13239
|
-
|
13240
|
-
|
13241
|
-
|
13242
|
-
|
13243
|
-
|
13244
|
-
|
13245
|
-
|
13246
|
-
|
13247
|
-
|
13248
|
-
|
13249
|
-
|
13250
|
-
|
13251
|
-
|
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
|
-
|
13256
|
-
|
13257
|
-
|
13258
|
-
|
13259
|
-
|
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
|
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 {
|
13355
|
-
* argument has the root jqLite array so that we can replace
|
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,
|
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('
|
13575
|
+
jqLite(document.createComment(' ' + directiveName + ': ' + templateAttrs[directiveName] + ' '));
|
13411
13576
|
compileNode = $compileNode[0];
|
13412
|
-
replaceWith(
|
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(
|
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,
|
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,
|
13765
|
-
afterTemplateChildLinkFn = compileNodes($compileNode.
|
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\.-]
|
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
|
-
|
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
|
-
|
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(
|
15425
|
-
return left.assign(
|
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(
|
15543
|
-
return getter(object(
|
15715
|
+
function(scope, locals, self) {
|
15716
|
+
return getter(self || object(scope, locals), locals);
|
15544
15717
|
},
|
15545
15718
|
{
|
15546
|
-
assign:function(
|
15547
|
-
return setter(object(
|
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(
|
15761
|
+
return function(scope, locals){
|
15589
15762
|
var args = [],
|
15590
|
-
context = contextGetter ? contextGetter(
|
15763
|
+
context = contextGetter ? contextGetter(scope, locals) : scope;
|
15591
15764
|
|
15592
15765
|
for ( var i = 0; i < argsFn.length; i++) {
|
15593
|
-
args.push(argsFn[i](
|
15766
|
+
args.push(argsFn[i](scope, locals));
|
15594
15767
|
}
|
15595
|
-
var fnPtr = fn(
|
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
|
-
|
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
|
15841
|
-
* against (
|
15842
|
-
* * `locals
|
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
|
15879
|
-
* asynchronous
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
-
|
16777
|
+
|
16778
|
+
// Escape regexp special characters.
|
16779
|
+
when = '^' + when.replace(/[-\/\\^$*+?.()|[\]{}]/g, "\\$&") + '$';
|
16780
|
+
var regex = '',
|
16574
16781
|
params = [],
|
16575
16782
|
dst = {};
|
16576
|
-
|
16577
|
-
|
16578
|
-
|
16579
|
-
|
16580
|
-
|
16581
|
-
|
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
|
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 =
|
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
|
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
|
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
|
16743
|
-
* -
|
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
|
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
|
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
|
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
|
-
|
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
|
-
*
|
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
|
-
|
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
|
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
|
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
|
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
|
-
<
|
17608
|
-
|
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 $
|
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
|
17774
|
-
* it is important to familiarize yourself with these
|
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
|
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
|
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
|
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
|
17804
|
-
* POST
|
17805
|
-
* were created
|
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
|
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
|
18065
|
+
* - `$httpProvider.defaults.headers.post`: (header defaults for POST requests)
|
17832
18066
|
* - `Content-Type: application/json`
|
17833
|
-
* - `$httpProvider.defaults.headers.put` (header defaults for
|
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
|
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
|
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
|
17842
|
-
*
|
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
|
-
* -
|
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
|
-
* -
|
17858
|
-
* -
|
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
|
-
*
|
17861
|
-
*
|
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
|
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
|
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
|
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
|
17940
|
-
* {@link http://en.wikipedia.org/wiki/
|
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
|
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
|
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
|
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
|
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
|
-
|
18449
|
-
|
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
|
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,
|
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
|
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 | [
|
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
|
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
|
-
|
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"
|
19079
|
+
Phone only <input ng-model="search.phone"><br>
|
18819
19080
|
<table id="searchObjResults">
|
18820
|
-
<tr><th>Name</th><th>Phone</th
|
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
|
-
|
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
|
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
|
19141
|
-
|
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
|
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
|
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}
|
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
|
-
|
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
|
-
|
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
|
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
|
-
*
|
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
|
-
|
19627
|
-
|
19628
|
-
|
19629
|
-
|
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
|
-
|
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
|
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 `
|
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
|
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.
|
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.
|
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
|
20334
|
-
* @param {string=} max Sets the `max` validation error key if the value entered is greater
|
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
|
-
|
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.
|
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 `
|
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
|
-
*
|
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
|
21671
|
-
if (mod !== old$index
|
21672
|
-
if (mod
|
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
|
21970
|
+
function ngClassWatchAction(newVal) {
|
21683
21971
|
if (selector === true || scope.$index % 2 === selector) {
|
21684
|
-
if (oldVal && (newVal
|
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
|
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`
|
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
|
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
|
-
*
|
22026
|
-
*
|
22027
|
-
*
|
22028
|
-
*
|
22029
|
-
*
|
22030
|
-
*
|
22031
|
-
*
|
22032
|
-
*
|
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
|
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
|
-
|
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,
|
22768
|
-
|
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 ===
|
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
|
-
* @
|
22986
|
-
* <ANY ng-switch
|
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
|
-
|
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
|
-
|
23042
|
-
|
23043
|
-
|
23044
|
-
|
23045
|
-
|
23046
|
-
|
23047
|
-
|
23048
|
-
|
23049
|
-
|
23050
|
-
|
23051
|
-
|
23052
|
-
|
23053
|
-
|
23054
|
-
|
23055
|
-
|
23056
|
-
|
23057
|
-
|
23058
|
-
|
23059
|
-
|
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
|
-
|
23073
|
-
|
23074
|
-
|
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
|
-
|
23083
|
-
|
23084
|
-
|
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.
|
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.
|
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}
|
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
|
-
//
|
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.
|
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.
|
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
|
23777
|
-
|
23778
|
-
|
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
|
-
|
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 =
|
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
|
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(
|
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>');
|