mongo_browser 0.2.0.rc2 → 0.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @license AngularJS v1.0.
|
|
2
|
+
* @license AngularJS v1.0.7
|
|
3
3
|
* (c) 2010-2012 Google, Inc. http://angularjs.org
|
|
4
4
|
* License: MIT
|
|
5
5
|
*/
|
|
@@ -34,12 +34,12 @@ var uppercase = function(string){return isString(string) ? string.toUpperCase()
|
|
|
34
34
|
|
|
35
35
|
var manualLowercase = function(s) {
|
|
36
36
|
return isString(s)
|
|
37
|
-
? s.replace(/[A-Z]/g, function(ch) {return fromCharCode(ch.charCodeAt(0) | 32);})
|
|
37
|
+
? s.replace(/[A-Z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) | 32);})
|
|
38
38
|
: s;
|
|
39
39
|
};
|
|
40
40
|
var manualUppercase = function(s) {
|
|
41
41
|
return isString(s)
|
|
42
|
-
? s.replace(/[a-z]/g, function(ch) {return fromCharCode(ch.charCodeAt(0) & ~32);})
|
|
42
|
+
? s.replace(/[a-z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) & ~32);})
|
|
43
43
|
: s;
|
|
44
44
|
};
|
|
45
45
|
|
|
@@ -52,11 +52,8 @@ if ('i' !== 'I'.toLowerCase()) {
|
|
|
52
52
|
uppercase = manualUppercase;
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
function fromCharCode(code) {return String.fromCharCode(code);}
|
|
56
55
|
|
|
57
|
-
|
|
58
|
-
var Error = window.Error,
|
|
59
|
-
/** holds major version number for IE or NaN for real browsers */
|
|
56
|
+
var /** holds major version number for IE or NaN for real browsers */
|
|
60
57
|
msie = int((/msie (\d+)/.exec(lowercase(navigator.userAgent)) || [])[1]),
|
|
61
58
|
jqLite, // delay binding since jQuery could be loaded after us.
|
|
62
59
|
jQuery, // delay binding
|
|
@@ -70,6 +67,29 @@ var Error = window.Error,
|
|
|
70
67
|
nodeName_,
|
|
71
68
|
uid = ['0', '0', '0'];
|
|
72
69
|
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* @private
|
|
73
|
+
* @param {*} obj
|
|
74
|
+
* @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments, ...)
|
|
75
|
+
*/
|
|
76
|
+
function isArrayLike(obj) {
|
|
77
|
+
if (!obj || (typeof obj.length !== 'number')) return false;
|
|
78
|
+
|
|
79
|
+
// We have on object which has length property. Should we treat it as array?
|
|
80
|
+
if (typeof obj.hasOwnProperty != 'function' &&
|
|
81
|
+
typeof obj.constructor != 'function') {
|
|
82
|
+
// This is here for IE8: it is a bogus object treat it as array;
|
|
83
|
+
return true;
|
|
84
|
+
} else {
|
|
85
|
+
return obj instanceof JQLite || // JQLite
|
|
86
|
+
(jQuery && obj instanceof jQuery) || // jQuery
|
|
87
|
+
toString.call(obj) !== '[object Object]' || // some browser native object
|
|
88
|
+
typeof obj.callee === 'function'; // arguments (on IE8 looks like regular obj)
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
|
|
73
93
|
/**
|
|
74
94
|
* @ngdoc function
|
|
75
95
|
* @name angular.forEach
|
|
@@ -108,7 +128,7 @@ function forEach(obj, iterator, context) {
|
|
|
108
128
|
}
|
|
109
129
|
} else if (obj.forEach && obj.forEach !== forEach) {
|
|
110
130
|
obj.forEach(iterator, context);
|
|
111
|
-
} else if (
|
|
131
|
+
} else if (isArrayLike(obj)) {
|
|
112
132
|
for (key = 0; key < obj.length; key++)
|
|
113
133
|
iterator.call(context, obj[key], key);
|
|
114
134
|
} else {
|
|
@@ -153,7 +173,7 @@ function reverseParams(iteratorFn) {
|
|
|
153
173
|
/**
|
|
154
174
|
* A consistent way of creating unique IDs in angular. The ID is a sequence of alpha numeric
|
|
155
175
|
* characters such as '012ABC'. The reason why we are not using simply a number counter is that
|
|
156
|
-
* the number string gets longer over time, and it can also overflow, where as the
|
|
176
|
+
* the number string gets longer over time, and it can also overflow, where as the nextId
|
|
157
177
|
* will grow much slower, it is a string, and it will never overflow.
|
|
158
178
|
*
|
|
159
179
|
* @returns an unique alpha-numeric string
|
|
@@ -180,6 +200,21 @@ function nextUid() {
|
|
|
180
200
|
return uid.join('');
|
|
181
201
|
}
|
|
182
202
|
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Set or clear the hashkey for an object.
|
|
206
|
+
* @param obj object
|
|
207
|
+
* @param h the hashkey (!truthy to delete the hashkey)
|
|
208
|
+
*/
|
|
209
|
+
function setHashKey(obj, h) {
|
|
210
|
+
if (h) {
|
|
211
|
+
obj.$$hashKey = h;
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
214
|
+
delete obj.$$hashKey;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
183
218
|
/**
|
|
184
219
|
* @ngdoc function
|
|
185
220
|
* @name angular.extend
|
|
@@ -191,8 +226,10 @@ function nextUid() {
|
|
|
191
226
|
*
|
|
192
227
|
* @param {Object} dst Destination object.
|
|
193
228
|
* @param {...Object} src Source object(s).
|
|
229
|
+
* @returns {Object} Reference to `dst`.
|
|
194
230
|
*/
|
|
195
231
|
function extend(dst) {
|
|
232
|
+
var h = dst.$$hashKey;
|
|
196
233
|
forEach(arguments, function(obj){
|
|
197
234
|
if (obj !== dst) {
|
|
198
235
|
forEach(obj, function(value, key){
|
|
@@ -200,6 +237,8 @@ function extend(dst) {
|
|
|
200
237
|
});
|
|
201
238
|
}
|
|
202
239
|
});
|
|
240
|
+
|
|
241
|
+
setHashKey(dst,h);
|
|
203
242
|
return dst;
|
|
204
243
|
}
|
|
205
244
|
|
|
@@ -549,19 +588,19 @@ function copy(source, destination){
|
|
|
549
588
|
} else {
|
|
550
589
|
if (source === destination) throw Error("Can't copy equivalent objects or arrays");
|
|
551
590
|
if (isArray(source)) {
|
|
552
|
-
|
|
553
|
-
destination.pop();
|
|
554
|
-
}
|
|
591
|
+
destination.length = 0;
|
|
555
592
|
for ( var i = 0; i < source.length; i++) {
|
|
556
593
|
destination.push(copy(source[i]));
|
|
557
594
|
}
|
|
558
595
|
} else {
|
|
596
|
+
var h = destination.$$hashKey;
|
|
559
597
|
forEach(destination, function(value, key){
|
|
560
598
|
delete destination[key];
|
|
561
599
|
});
|
|
562
600
|
for ( var key in source) {
|
|
563
601
|
destination[key] = copy(source[key]);
|
|
564
602
|
}
|
|
603
|
+
setHashKey(destination,h);
|
|
565
604
|
}
|
|
566
605
|
}
|
|
567
606
|
return destination;
|
|
@@ -601,7 +640,7 @@ function shallowCopy(src, dst) {
|
|
|
601
640
|
* During a property comparision, properties of `function` type and properties with names
|
|
602
641
|
* that begin with `$` are ignored.
|
|
603
642
|
*
|
|
604
|
-
* Scope and DOMWindow objects are being compared only
|
|
643
|
+
* Scope and DOMWindow objects are being compared only by identify (`===`).
|
|
605
644
|
*
|
|
606
645
|
* @param {*} o1 Object or value to compare.
|
|
607
646
|
* @param {*} o2 Object or value to compare.
|
|
@@ -627,13 +666,15 @@ function equals(o1, o2) {
|
|
|
627
666
|
if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2)) return false;
|
|
628
667
|
keySet = {};
|
|
629
668
|
for(key in o1) {
|
|
630
|
-
if (key.charAt(0)
|
|
631
|
-
|
|
632
|
-
}
|
|
669
|
+
if (key.charAt(0) === '$' || isFunction(o1[key])) continue;
|
|
670
|
+
if (!equals(o1[key], o2[key])) return false;
|
|
633
671
|
keySet[key] = true;
|
|
634
672
|
}
|
|
635
673
|
for(key in o2) {
|
|
636
|
-
if (!keySet[key] &&
|
|
674
|
+
if (!keySet[key] &&
|
|
675
|
+
key.charAt(0) !== '$' &&
|
|
676
|
+
o2[key] !== undefined &&
|
|
677
|
+
!isFunction(o2[key])) return false;
|
|
637
678
|
}
|
|
638
679
|
return true;
|
|
639
680
|
}
|
|
@@ -659,7 +700,7 @@ function sliceArgs(args, startIndex) {
|
|
|
659
700
|
*
|
|
660
701
|
* @description
|
|
661
702
|
* Returns a function which calls function `fn` bound to `self` (`self` becomes the `this` for
|
|
662
|
-
* `fn`). You can supply optional `args` that are
|
|
703
|
+
* `fn`). You can supply optional `args` that are prebound to the function. This feature is also
|
|
663
704
|
* known as [function currying](http://en.wikipedia.org/wiki/Currying).
|
|
664
705
|
*
|
|
665
706
|
* @param {Object} self Context which `fn` should be evaluated in.
|
|
@@ -760,9 +801,18 @@ function startingTag(element) {
|
|
|
760
801
|
// are not allowed to have children. So we just ignore it.
|
|
761
802
|
element.html('');
|
|
762
803
|
} catch(e) {}
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
804
|
+
// As Per DOM Standards
|
|
805
|
+
var TEXT_NODE = 3;
|
|
806
|
+
var elemHtml = jqLite('<div>').append(element).html();
|
|
807
|
+
try {
|
|
808
|
+
return element[0].nodeType === TEXT_NODE ? lowercase(elemHtml) :
|
|
809
|
+
elemHtml.
|
|
810
|
+
match(/^(<[^>]+>)/)[1].
|
|
811
|
+
replace(/^<([\w\-]+)/, function(match, nodeName) { return '<' + lowercase(nodeName); });
|
|
812
|
+
} catch(e) {
|
|
813
|
+
return lowercase(elemHtml);
|
|
814
|
+
}
|
|
815
|
+
|
|
766
816
|
}
|
|
767
817
|
|
|
768
818
|
|
|
@@ -829,7 +879,7 @@ function encodeUriQuery(val, pctEncodeSpaces) {
|
|
|
829
879
|
replace(/%3A/gi, ':').
|
|
830
880
|
replace(/%24/g, '$').
|
|
831
881
|
replace(/%2C/gi, ',').
|
|
832
|
-
replace((pctEncodeSpaces ?
|
|
882
|
+
replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
|
|
833
883
|
}
|
|
834
884
|
|
|
835
885
|
|
|
@@ -843,10 +893,10 @@ function encodeUriQuery(val, pctEncodeSpaces) {
|
|
|
843
893
|
*
|
|
844
894
|
* @description
|
|
845
895
|
*
|
|
846
|
-
* Use this directive to auto-bootstrap
|
|
896
|
+
* Use this directive to auto-bootstrap an application. Only
|
|
847
897
|
* one directive can be used per HTML document. The directive
|
|
848
898
|
* designates the root of the application and is typically placed
|
|
849
|
-
*
|
|
899
|
+
* at the root of the page.
|
|
850
900
|
*
|
|
851
901
|
* In the example below if the `ngApp` directive would not be placed
|
|
852
902
|
* on the `html` element then the document would not be compiled
|
|
@@ -918,22 +968,38 @@ function angularInit(element, bootstrap) {
|
|
|
918
968
|
* @returns {AUTO.$injector} Returns the newly created injector for this app.
|
|
919
969
|
*/
|
|
920
970
|
function bootstrap(element, modules) {
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
['$rootScope', '$rootElement', '$compile', '$injector',
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
971
|
+
var resumeBootstrapInternal = function() {
|
|
972
|
+
element = jqLite(element);
|
|
973
|
+
modules = modules || [];
|
|
974
|
+
modules.unshift(['$provide', function($provide) {
|
|
975
|
+
$provide.value('$rootElement', element);
|
|
976
|
+
}]);
|
|
977
|
+
modules.unshift('ng');
|
|
978
|
+
var injector = createInjector(modules);
|
|
979
|
+
injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector',
|
|
980
|
+
function(scope, element, compile, injector) {
|
|
981
|
+
scope.$apply(function() {
|
|
982
|
+
element.data('$injector', injector);
|
|
983
|
+
compile(element)(scope);
|
|
984
|
+
});
|
|
985
|
+
}]
|
|
986
|
+
);
|
|
987
|
+
return injector;
|
|
988
|
+
};
|
|
989
|
+
|
|
990
|
+
var NG_DEFER_BOOTSTRAP = /^NG_DEFER_BOOTSTRAP!/;
|
|
991
|
+
|
|
992
|
+
if (window && !NG_DEFER_BOOTSTRAP.test(window.name)) {
|
|
993
|
+
return resumeBootstrapInternal();
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
window.name = window.name.replace(NG_DEFER_BOOTSTRAP, '');
|
|
997
|
+
angular.resumeBootstrap = function(extraModules) {
|
|
998
|
+
forEach(extraModules, function(module) {
|
|
999
|
+
modules.push(module);
|
|
1000
|
+
});
|
|
1001
|
+
resumeBootstrapInternal();
|
|
1002
|
+
};
|
|
937
1003
|
}
|
|
938
1004
|
|
|
939
1005
|
var SNAKE_CASE_REGEXP = /[A-Z]/g;
|
|
@@ -966,7 +1032,7 @@ function bindJQuery() {
|
|
|
966
1032
|
}
|
|
967
1033
|
|
|
968
1034
|
/**
|
|
969
|
-
* throw error
|
|
1035
|
+
* throw error if the argument is falsy.
|
|
970
1036
|
*/
|
|
971
1037
|
function assertArg(arg, name, reason) {
|
|
972
1038
|
if (!arg) {
|
|
@@ -1247,11 +1313,11 @@ function setupModuleLoader(window) {
|
|
|
1247
1313
|
* - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
|
|
1248
1314
|
*/
|
|
1249
1315
|
var version = {
|
|
1250
|
-
full: '1.0.
|
|
1251
|
-
major: 1, //
|
|
1316
|
+
full: '1.0.7', // all of these placeholder strings will be replaced by grunt's
|
|
1317
|
+
major: 1, // package task
|
|
1252
1318
|
minor: 0,
|
|
1253
|
-
dot:
|
|
1254
|
-
codeName: '
|
|
1319
|
+
dot: 7,
|
|
1320
|
+
codeName: 'monochromatic-rainbow'
|
|
1255
1321
|
};
|
|
1256
1322
|
|
|
1257
1323
|
|
|
@@ -1396,18 +1462,18 @@ function publishExternalAPI(angular){
|
|
|
1396
1462
|
* - [after()](http://api.jquery.com/after/)
|
|
1397
1463
|
* - [append()](http://api.jquery.com/append/)
|
|
1398
1464
|
* - [attr()](http://api.jquery.com/attr/)
|
|
1399
|
-
* - [bind()](http://api.jquery.com/bind/)
|
|
1400
|
-
* - [children()](http://api.jquery.com/children/)
|
|
1465
|
+
* - [bind()](http://api.jquery.com/bind/) - Does not support namespaces
|
|
1466
|
+
* - [children()](http://api.jquery.com/children/) - Does not support selectors
|
|
1401
1467
|
* - [clone()](http://api.jquery.com/clone/)
|
|
1402
1468
|
* - [contents()](http://api.jquery.com/contents/)
|
|
1403
1469
|
* - [css()](http://api.jquery.com/css/)
|
|
1404
1470
|
* - [data()](http://api.jquery.com/data/)
|
|
1405
1471
|
* - [eq()](http://api.jquery.com/eq/)
|
|
1406
|
-
* - [find()](http://api.jquery.com/find/) - Limited to lookups by tag name
|
|
1472
|
+
* - [find()](http://api.jquery.com/find/) - Limited to lookups by tag name
|
|
1407
1473
|
* - [hasClass()](http://api.jquery.com/hasClass/)
|
|
1408
1474
|
* - [html()](http://api.jquery.com/html/)
|
|
1409
|
-
* - [next()](http://api.jquery.com/next/)
|
|
1410
|
-
* - [parent()](http://api.jquery.com/parent/)
|
|
1475
|
+
* - [next()](http://api.jquery.com/next/) - Does not support selectors
|
|
1476
|
+
* - [parent()](http://api.jquery.com/parent/) - Does not support selectors
|
|
1411
1477
|
* - [prepend()](http://api.jquery.com/prepend/)
|
|
1412
1478
|
* - [prop()](http://api.jquery.com/prop/)
|
|
1413
1479
|
* - [ready()](http://api.jquery.com/ready/)
|
|
@@ -1419,11 +1485,11 @@ function publishExternalAPI(angular){
|
|
|
1419
1485
|
* - [text()](http://api.jquery.com/text/)
|
|
1420
1486
|
* - [toggleClass()](http://api.jquery.com/toggleClass/)
|
|
1421
1487
|
* - [triggerHandler()](http://api.jquery.com/triggerHandler/) - Doesn't pass native event objects to handlers.
|
|
1422
|
-
* - [unbind()](http://api.jquery.com/unbind/)
|
|
1488
|
+
* - [unbind()](http://api.jquery.com/unbind/) - Does not support namespaces
|
|
1423
1489
|
* - [val()](http://api.jquery.com/val/)
|
|
1424
1490
|
* - [wrap()](http://api.jquery.com/wrap/)
|
|
1425
1491
|
*
|
|
1426
|
-
* ## In addtion to the above, Angular
|
|
1492
|
+
* ## In addtion to the above, Angular provides additional methods to both jQuery and jQuery lite:
|
|
1427
1493
|
*
|
|
1428
1494
|
* - `controller(name)` - retrieves the controller of the current element or its parent. By default
|
|
1429
1495
|
* retrieves controller associated with the `ngController` directive. If `name` is provided as
|
|
@@ -1966,23 +2032,43 @@ forEach({
|
|
|
1966
2032
|
|
|
1967
2033
|
if (!eventFns) {
|
|
1968
2034
|
if (type == 'mouseenter' || type == 'mouseleave') {
|
|
1969
|
-
var
|
|
2035
|
+
var contains = document.body.contains || document.body.compareDocumentPosition ?
|
|
2036
|
+
function( a, b ) {
|
|
2037
|
+
var adown = a.nodeType === 9 ? a.documentElement : a,
|
|
2038
|
+
bup = b && b.parentNode;
|
|
2039
|
+
return a === bup || !!( bup && bup.nodeType === 1 && (
|
|
2040
|
+
adown.contains ?
|
|
2041
|
+
adown.contains( bup ) :
|
|
2042
|
+
a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
|
|
2043
|
+
));
|
|
2044
|
+
} :
|
|
2045
|
+
function( a, b ) {
|
|
2046
|
+
if ( b ) {
|
|
2047
|
+
while ( (b = b.parentNode) ) {
|
|
2048
|
+
if ( b === a ) {
|
|
2049
|
+
return true;
|
|
2050
|
+
}
|
|
2051
|
+
}
|
|
2052
|
+
}
|
|
2053
|
+
return false;
|
|
2054
|
+
};
|
|
1970
2055
|
|
|
1971
|
-
events
|
|
1972
|
-
|
|
2056
|
+
events[type] = [];
|
|
2057
|
+
|
|
2058
|
+
// Refer to jQuery's implementation of mouseenter & mouseleave
|
|
2059
|
+
// Read about mouseenter and mouseleave:
|
|
2060
|
+
// http://www.quirksmode.org/js/events_mouse.html#link8
|
|
2061
|
+
var eventmap = { mouseleave : "mouseout", mouseenter : "mouseover"}
|
|
2062
|
+
bindFn(element, eventmap[type], function(event) {
|
|
2063
|
+
var ret, target = this, related = event.relatedTarget;
|
|
2064
|
+
// For mousenter/leave call the handler if related is outside the target.
|
|
2065
|
+
// NB: No relatedTarget if the mouse left/entered the browser window
|
|
2066
|
+
if ( !related || (related !== target && !contains(target, related)) ){
|
|
2067
|
+
handle(event, type);
|
|
2068
|
+
}
|
|
1973
2069
|
|
|
1974
|
-
bindFn(element, 'mouseover', function(event) {
|
|
1975
|
-
counter++;
|
|
1976
|
-
if (counter == 1) {
|
|
1977
|
-
handle(event, 'mouseenter');
|
|
1978
|
-
}
|
|
1979
|
-
});
|
|
1980
|
-
bindFn(element, 'mouseout', function(event) {
|
|
1981
|
-
counter --;
|
|
1982
|
-
if (counter == 0) {
|
|
1983
|
-
handle(event, 'mouseleave');
|
|
1984
|
-
}
|
|
1985
2070
|
});
|
|
2071
|
+
|
|
1986
2072
|
} else {
|
|
1987
2073
|
addEventListenerFn(element, type, handle);
|
|
1988
2074
|
events[type] = [];
|
|
@@ -2011,14 +2097,14 @@ forEach({
|
|
|
2011
2097
|
children: function(element) {
|
|
2012
2098
|
var children = [];
|
|
2013
2099
|
forEach(element.childNodes, function(element){
|
|
2014
|
-
if (element.
|
|
2100
|
+
if (element.nodeType === 1)
|
|
2015
2101
|
children.push(element);
|
|
2016
2102
|
});
|
|
2017
2103
|
return children;
|
|
2018
2104
|
},
|
|
2019
2105
|
|
|
2020
2106
|
contents: function(element) {
|
|
2021
|
-
return element.childNodes;
|
|
2107
|
+
return element.childNodes || [];
|
|
2022
2108
|
},
|
|
2023
2109
|
|
|
2024
2110
|
append: function(element, node) {
|
|
@@ -2081,7 +2167,16 @@ forEach({
|
|
|
2081
2167
|
},
|
|
2082
2168
|
|
|
2083
2169
|
next: function(element) {
|
|
2084
|
-
|
|
2170
|
+
if (element.nextElementSibling) {
|
|
2171
|
+
return element.nextElementSibling;
|
|
2172
|
+
}
|
|
2173
|
+
|
|
2174
|
+
// IE8 doesn't have nextElementSibling
|
|
2175
|
+
var elm = element.nextSibling;
|
|
2176
|
+
while (elm != null && elm.nodeType !== 1) {
|
|
2177
|
+
elm = elm.nextSibling;
|
|
2178
|
+
}
|
|
2179
|
+
return elm;
|
|
2085
2180
|
},
|
|
2086
2181
|
|
|
2087
2182
|
find: function(element, selector) {
|
|
@@ -2289,7 +2384,7 @@ function annotate(fn) {
|
|
|
2289
2384
|
}
|
|
2290
2385
|
} else if (isArray(fn)) {
|
|
2291
2386
|
last = fn.length - 1;
|
|
2292
|
-
assertArgFn(fn[last], 'fn')
|
|
2387
|
+
assertArgFn(fn[last], 'fn');
|
|
2293
2388
|
$inject = fn.slice(0, last);
|
|
2294
2389
|
} else {
|
|
2295
2390
|
assertArgFn(fn, 'fn', true);
|
|
@@ -2323,19 +2418,19 @@ function annotate(fn) {
|
|
|
2323
2418
|
* # Injection Function Annotation
|
|
2324
2419
|
*
|
|
2325
2420
|
* JavaScript does not have annotations, and annotations are needed for dependency injection. The
|
|
2326
|
-
* following
|
|
2421
|
+
* following are all valid ways of annotating function with injection arguments and are equivalent.
|
|
2327
2422
|
*
|
|
2328
2423
|
* <pre>
|
|
2329
2424
|
* // inferred (only works if code not minified/obfuscated)
|
|
2330
|
-
* $
|
|
2425
|
+
* $injector.invoke(function(serviceA){});
|
|
2331
2426
|
*
|
|
2332
2427
|
* // annotated
|
|
2333
2428
|
* function explicit(serviceA) {};
|
|
2334
2429
|
* explicit.$inject = ['serviceA'];
|
|
2335
|
-
* $
|
|
2430
|
+
* $injector.invoke(explicit);
|
|
2336
2431
|
*
|
|
2337
2432
|
* // inline
|
|
2338
|
-
* $
|
|
2433
|
+
* $injector.invoke(['serviceA', function(serviceA){}]);
|
|
2339
2434
|
* </pre>
|
|
2340
2435
|
*
|
|
2341
2436
|
* ## Inference
|
|
@@ -2419,7 +2514,7 @@ function annotate(fn) {
|
|
|
2419
2514
|
* This method does not work with code minfication / obfuscation. For this reason the following annotation strategies
|
|
2420
2515
|
* are supported.
|
|
2421
2516
|
*
|
|
2422
|
-
* # The `$
|
|
2517
|
+
* # The `$inject` property
|
|
2423
2518
|
*
|
|
2424
2519
|
* If a function has an `$inject` property and its value is an array of strings, then the strings represent names of
|
|
2425
2520
|
* services to be injected into the function.
|
|
@@ -2452,7 +2547,7 @@ function annotate(fn) {
|
|
|
2452
2547
|
* // ...
|
|
2453
2548
|
* };
|
|
2454
2549
|
* tmpFn.$inject = ['$compile', '$rootScope'];
|
|
2455
|
-
* injector.invoke(
|
|
2550
|
+
* injector.invoke(tmpFn);
|
|
2456
2551
|
*
|
|
2457
2552
|
* // To better support inline function the inline annotation is supported
|
|
2458
2553
|
* injector.invoke(['$compile', '$rootScope', function(obfCompile, obfRootScope) {
|
|
@@ -2481,7 +2576,7 @@ function annotate(fn) {
|
|
|
2481
2576
|
* @description
|
|
2482
2577
|
*
|
|
2483
2578
|
* Use `$provide` to register new providers with the `$injector`. The providers are the factories for the instance.
|
|
2484
|
-
* The providers share the same name as the instance they create with
|
|
2579
|
+
* The providers share the same name as the instance they create with `Provider` suffixed to them.
|
|
2485
2580
|
*
|
|
2486
2581
|
* A provider is an object with a `$get()` method. The injector calls the `$get` method to create a new instance of
|
|
2487
2582
|
* a service. The Provider can have additional methods which would allow for configuration of the provider.
|
|
@@ -2505,7 +2600,7 @@ function annotate(fn) {
|
|
|
2505
2600
|
*
|
|
2506
2601
|
* beforeEach(module(function($provide) {
|
|
2507
2602
|
* $provide.provider('greet', GreetProvider);
|
|
2508
|
-
* });
|
|
2603
|
+
* }));
|
|
2509
2604
|
*
|
|
2510
2605
|
* it('should greet', inject(function(greet) {
|
|
2511
2606
|
* expect(greet('angular')).toEqual('Hello angular!');
|
|
@@ -2518,9 +2613,7 @@ function annotate(fn) {
|
|
|
2518
2613
|
* inject(function(greet) {
|
|
2519
2614
|
* expect(greet('angular')).toEqual('Ahoj angular!');
|
|
2520
2615
|
* });
|
|
2521
|
-
* )
|
|
2522
|
-
*
|
|
2523
|
-
* });
|
|
2616
|
+
* });
|
|
2524
2617
|
* </pre>
|
|
2525
2618
|
*/
|
|
2526
2619
|
|
|
@@ -2614,7 +2707,7 @@ function annotate(fn) {
|
|
|
2614
2707
|
*
|
|
2615
2708
|
* @param {string} name The name of the service to decorate.
|
|
2616
2709
|
* @param {function()} decorator This function will be invoked when the service needs to be
|
|
2617
|
-
*
|
|
2710
|
+
* instantiated. The function is called using the {@link AUTO.$injector#invoke
|
|
2618
2711
|
* injector.invoke} method and is therefore fully injectable. Local injection arguments:
|
|
2619
2712
|
*
|
|
2620
2713
|
* * `$delegate` - The original service instance, which can be monkey patched, configured,
|
|
@@ -2667,7 +2760,7 @@ function createInjector(modulesToLoad) {
|
|
|
2667
2760
|
}
|
|
2668
2761
|
|
|
2669
2762
|
function provider(name, provider_) {
|
|
2670
|
-
if (isFunction(provider_)) {
|
|
2763
|
+
if (isFunction(provider_) || isArray(provider_)) {
|
|
2671
2764
|
provider_ = providerInjector.instantiate(provider_);
|
|
2672
2765
|
}
|
|
2673
2766
|
if (!provider_.$get) {
|
|
@@ -2784,7 +2877,7 @@ function createInjector(modulesToLoad) {
|
|
|
2784
2877
|
args.push(
|
|
2785
2878
|
locals && locals.hasOwnProperty(key)
|
|
2786
2879
|
? locals[key]
|
|
2787
|
-
: getService(key
|
|
2880
|
+
: getService(key)
|
|
2788
2881
|
);
|
|
2789
2882
|
}
|
|
2790
2883
|
if (!fn.$inject) {
|
|
@@ -2814,6 +2907,8 @@ function createInjector(modulesToLoad) {
|
|
|
2814
2907
|
var Constructor = function() {},
|
|
2815
2908
|
instance, returnedValue;
|
|
2816
2909
|
|
|
2910
|
+
// Check if Type is annotated and use just the given function at n-1 as parameter
|
|
2911
|
+
// e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]);
|
|
2817
2912
|
Constructor.prototype = (isArray(Type) ? Type[Type.length - 1] : Type).prototype;
|
|
2818
2913
|
instance = new Constructor();
|
|
2819
2914
|
returnedValue = invoke(Type, instance, locals);
|
|
@@ -2829,6 +2924,7 @@ function createInjector(modulesToLoad) {
|
|
|
2829
2924
|
};
|
|
2830
2925
|
}
|
|
2831
2926
|
}
|
|
2927
|
+
|
|
2832
2928
|
/**
|
|
2833
2929
|
* @ngdoc function
|
|
2834
2930
|
* @name ng.$anchorScroll
|
|
@@ -2884,7 +2980,7 @@ function $AnchorScrollProvider() {
|
|
|
2884
2980
|
}
|
|
2885
2981
|
|
|
2886
2982
|
// does not scroll when user clicks on anchor link that is currently on
|
|
2887
|
-
// (no url change, no $
|
|
2983
|
+
// (no url change, no $location.hash() change), browser native does scroll
|
|
2888
2984
|
if (autoScrollingEnabled) {
|
|
2889
2985
|
$rootScope.$watch(function autoScrollWatch() {return $location.hash();},
|
|
2890
2986
|
function autoScrollWatchAction() {
|
|
@@ -3133,7 +3229,7 @@ function Browser(window, document, $log, $sniffer) {
|
|
|
3133
3229
|
*/
|
|
3134
3230
|
self.baseHref = function() {
|
|
3135
3231
|
var href = baseElement.attr('href');
|
|
3136
|
-
return href ? href.replace(/^https?\:\/\/[^\/]*/, '') :
|
|
3232
|
+
return href ? href.replace(/^https?\:\/\/[^\/]*/, '') : '';
|
|
3137
3233
|
};
|
|
3138
3234
|
|
|
3139
3235
|
//////////////////////////////////////////////////////////////
|
|
@@ -3172,14 +3268,15 @@ function Browser(window, document, $log, $sniffer) {
|
|
|
3172
3268
|
} else {
|
|
3173
3269
|
if (isString(value)) {
|
|
3174
3270
|
cookieLength = (rawDocument.cookie = escape(name) + '=' + escape(value) + ';path=' + cookiePath).length + 1;
|
|
3271
|
+
|
|
3272
|
+
// per http://www.ietf.org/rfc/rfc2109.txt browser must allow at minimum:
|
|
3273
|
+
// - 300 cookies
|
|
3274
|
+
// - 20 cookies per unique domain
|
|
3275
|
+
// - 4096 bytes per cookie
|
|
3175
3276
|
if (cookieLength > 4096) {
|
|
3176
3277
|
$log.warn("Cookie '"+ name +"' possibly not set or overflowed because it was too large ("+
|
|
3177
3278
|
cookieLength + " > 4096 bytes)!");
|
|
3178
3279
|
}
|
|
3179
|
-
if (lastCookies.length > 20) {
|
|
3180
|
-
$log.warn("Cookie '"+ name +"' possibly not set or overflowed because too many cookies " +
|
|
3181
|
-
"were already set (" + lastCookies.length + " > 20 )");
|
|
3182
|
-
}
|
|
3183
3280
|
}
|
|
3184
3281
|
}
|
|
3185
3282
|
} else {
|
|
@@ -3192,7 +3289,13 @@ function Browser(window, document, $log, $sniffer) {
|
|
|
3192
3289
|
cookie = cookieArray[i];
|
|
3193
3290
|
index = cookie.indexOf('=');
|
|
3194
3291
|
if (index > 0) { //ignore nameless cookies
|
|
3195
|
-
|
|
3292
|
+
var name = unescape(cookie.substring(0, index));
|
|
3293
|
+
// the first value that is seen for a cookie is the most
|
|
3294
|
+
// specific one. values for the same cookie name that
|
|
3295
|
+
// follow are for less specific paths.
|
|
3296
|
+
if (lastCookies[name] === undefined) {
|
|
3297
|
+
lastCookies[name] = unescape(cookie.substring(index + 1));
|
|
3298
|
+
}
|
|
3196
3299
|
}
|
|
3197
3300
|
}
|
|
3198
3301
|
}
|
|
@@ -3256,6 +3359,7 @@ function $BrowserProvider(){
|
|
|
3256
3359
|
return new Browser($window, $document, $log, $sniffer);
|
|
3257
3360
|
}];
|
|
3258
3361
|
}
|
|
3362
|
+
|
|
3259
3363
|
/**
|
|
3260
3364
|
* @ngdoc object
|
|
3261
3365
|
* @name ng.$cacheFactory
|
|
@@ -3582,7 +3686,8 @@ function $CompileProvider($provide) {
|
|
|
3582
3686
|
Suffix = 'Directive',
|
|
3583
3687
|
COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\d\w\-_]+)\s+(.*)$/,
|
|
3584
3688
|
CLASS_DIRECTIVE_REGEXP = /(([\d\w\-_]+)(?:\:([^;]+))?;?)/,
|
|
3585
|
-
MULTI_ROOT_TEMPLATE_ERROR = 'Template must have exactly one root element. was: '
|
|
3689
|
+
MULTI_ROOT_TEMPLATE_ERROR = 'Template must have exactly one root element. was: ',
|
|
3690
|
+
urlSanitizationWhitelist = /^\s*(https?|ftp|mailto|file):/;
|
|
3586
3691
|
|
|
3587
3692
|
|
|
3588
3693
|
/**
|
|
@@ -3636,11 +3741,41 @@ function $CompileProvider($provide) {
|
|
|
3636
3741
|
};
|
|
3637
3742
|
|
|
3638
3743
|
|
|
3744
|
+
/**
|
|
3745
|
+
* @ngdoc function
|
|
3746
|
+
* @name ng.$compileProvider#urlSanitizationWhitelist
|
|
3747
|
+
* @methodOf ng.$compileProvider
|
|
3748
|
+
* @function
|
|
3749
|
+
*
|
|
3750
|
+
* @description
|
|
3751
|
+
* Retrieves or overrides the default regular expression that is used for whitelisting of safe
|
|
3752
|
+
* urls during a[href] sanitization.
|
|
3753
|
+
*
|
|
3754
|
+
* The sanitization is a security measure aimed at prevent XSS attacks via html links.
|
|
3755
|
+
*
|
|
3756
|
+
* Any url about to be assigned to a[href] via data-binding is first normalized and turned into an
|
|
3757
|
+
* absolute url. Afterwards the url is matched against the `urlSanitizationWhitelist` regular
|
|
3758
|
+
* expression. If a match is found the original url is written into the dom. Otherwise the
|
|
3759
|
+
* absolute url is prefixed with `'unsafe:'` string and only then it is written into the DOM.
|
|
3760
|
+
*
|
|
3761
|
+
* @param {RegExp=} regexp New regexp to whitelist urls with.
|
|
3762
|
+
* @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
|
|
3763
|
+
* chaining otherwise.
|
|
3764
|
+
*/
|
|
3765
|
+
this.urlSanitizationWhitelist = function(regexp) {
|
|
3766
|
+
if (isDefined(regexp)) {
|
|
3767
|
+
urlSanitizationWhitelist = regexp;
|
|
3768
|
+
return this;
|
|
3769
|
+
}
|
|
3770
|
+
return urlSanitizationWhitelist;
|
|
3771
|
+
};
|
|
3772
|
+
|
|
3773
|
+
|
|
3639
3774
|
this.$get = [
|
|
3640
3775
|
'$injector', '$interpolate', '$exceptionHandler', '$http', '$templateCache', '$parse',
|
|
3641
|
-
'$controller', '$rootScope',
|
|
3776
|
+
'$controller', '$rootScope', '$document',
|
|
3642
3777
|
function($injector, $interpolate, $exceptionHandler, $http, $templateCache, $parse,
|
|
3643
|
-
$controller, $rootScope) {
|
|
3778
|
+
$controller, $rootScope, $document) {
|
|
3644
3779
|
|
|
3645
3780
|
var Attributes = function(element, attr) {
|
|
3646
3781
|
this.$$element = element;
|
|
@@ -3662,7 +3797,8 @@ function $CompileProvider($provide) {
|
|
|
3662
3797
|
*/
|
|
3663
3798
|
$set: function(key, value, writeAttr, attrName) {
|
|
3664
3799
|
var booleanKey = getBooleanAttrName(this.$$element[0], key),
|
|
3665
|
-
$$observers = this.$$observers
|
|
3800
|
+
$$observers = this.$$observers,
|
|
3801
|
+
normalizedVal;
|
|
3666
3802
|
|
|
3667
3803
|
if (booleanKey) {
|
|
3668
3804
|
this.$$element.prop(key, value);
|
|
@@ -3681,6 +3817,19 @@ function $CompileProvider($provide) {
|
|
|
3681
3817
|
}
|
|
3682
3818
|
}
|
|
3683
3819
|
|
|
3820
|
+
|
|
3821
|
+
// sanitize a[href] values
|
|
3822
|
+
if (nodeName_(this.$$element[0]) === 'A' && key === 'href') {
|
|
3823
|
+
urlSanitizationNode.setAttribute('href', value);
|
|
3824
|
+
|
|
3825
|
+
// href property always returns normalized absolute url, so we can match against that
|
|
3826
|
+
normalizedVal = urlSanitizationNode.href;
|
|
3827
|
+
if (!normalizedVal.match(urlSanitizationWhitelist)) {
|
|
3828
|
+
this[key] = value = 'unsafe:' + normalizedVal;
|
|
3829
|
+
}
|
|
3830
|
+
}
|
|
3831
|
+
|
|
3832
|
+
|
|
3684
3833
|
if (writeAttr !== false) {
|
|
3685
3834
|
if (value === null || value === undefined) {
|
|
3686
3835
|
this.$$element.removeAttr(attrName);
|
|
@@ -3724,7 +3873,8 @@ function $CompileProvider($provide) {
|
|
|
3724
3873
|
}
|
|
3725
3874
|
};
|
|
3726
3875
|
|
|
3727
|
-
var
|
|
3876
|
+
var urlSanitizationNode = $document[0].createElement('a'),
|
|
3877
|
+
startSymbol = $interpolate.startSymbol(),
|
|
3728
3878
|
endSymbol = $interpolate.endSymbol(),
|
|
3729
3879
|
denormalizeTemplate = (startSymbol == '{{' || endSymbol == '}}')
|
|
3730
3880
|
? identity
|
|
@@ -3739,13 +3889,13 @@ function $CompileProvider($provide) {
|
|
|
3739
3889
|
|
|
3740
3890
|
function compile($compileNodes, transcludeFn, maxPriority) {
|
|
3741
3891
|
if (!($compileNodes instanceof jqLite)) {
|
|
3742
|
-
// jquery always rewraps,
|
|
3892
|
+
// jquery always rewraps, whereas we need to preserve the original selector so that we can modify it.
|
|
3743
3893
|
$compileNodes = jqLite($compileNodes);
|
|
3744
3894
|
}
|
|
3745
3895
|
// We can not compile top level text elements since text nodes can be merged and we will
|
|
3746
3896
|
// not be able to attach scope data to them, so we will wrap them in <span>
|
|
3747
3897
|
forEach($compileNodes, function(node, index){
|
|
3748
|
-
if (node.nodeType == 3 /* text node */) {
|
|
3898
|
+
if (node.nodeType == 3 /* text node */ && node.nodeValue.match(/\S+/) /* non-empty */ ) {
|
|
3749
3899
|
$compileNodes[index] = jqLite(node).wrap('<span></span>').parent()[0];
|
|
3750
3900
|
}
|
|
3751
3901
|
});
|
|
@@ -3757,7 +3907,14 @@ function $CompileProvider($provide) {
|
|
|
3757
3907
|
var $linkNode = cloneConnectFn
|
|
3758
3908
|
? JQLitePrototype.clone.call($compileNodes) // IMPORTANT!!!
|
|
3759
3909
|
: $compileNodes;
|
|
3760
|
-
|
|
3910
|
+
|
|
3911
|
+
// Attach scope only to non-text nodes.
|
|
3912
|
+
for(var i = 0, ii = $linkNode.length; i<ii; i++) {
|
|
3913
|
+
var node = $linkNode[i];
|
|
3914
|
+
if (node.nodeType == 1 /* element */ || node.nodeType == 9 /* document */) {
|
|
3915
|
+
$linkNode.eq(i).data('$scope', scope);
|
|
3916
|
+
}
|
|
3917
|
+
}
|
|
3761
3918
|
safeAddClass($linkNode, 'ng-scope');
|
|
3762
3919
|
if (cloneConnectFn) cloneConnectFn($linkNode, scope);
|
|
3763
3920
|
if (compositeLinkFn) compositeLinkFn(scope, $linkNode, $linkNode);
|
|
@@ -3784,7 +3941,7 @@ function $CompileProvider($provide) {
|
|
|
3784
3941
|
* functions return values - the linking functions - are combined into a composite linking
|
|
3785
3942
|
* function, which is the a linking function for the node.
|
|
3786
3943
|
*
|
|
3787
|
-
* @param {NodeList} nodeList an array of nodes to compile
|
|
3944
|
+
* @param {NodeList} nodeList an array of nodes or NodeList to compile
|
|
3788
3945
|
* @param {function(angular.Scope[, cloneAttachFn]} transcludeFn A linking function, where the
|
|
3789
3946
|
* scope argument is auto-generated to the new child of the transcluded parent scope.
|
|
3790
3947
|
* @param {DOMElement=} $rootElement If the nodeList is the root of the compilation tree then the
|
|
@@ -3794,68 +3951,75 @@ function $CompileProvider($provide) {
|
|
|
3794
3951
|
* @returns {?function} A composite linking function of all of the matched directives or null.
|
|
3795
3952
|
*/
|
|
3796
3953
|
function compileNodes(nodeList, transcludeFn, $rootElement, maxPriority) {
|
|
3797
|
-
|
|
3798
|
-
|
|
3954
|
+
var linkFns = [],
|
|
3955
|
+
nodeLinkFn, childLinkFn, directives, attrs, linkFnFound;
|
|
3799
3956
|
|
|
3800
|
-
|
|
3801
|
-
|
|
3957
|
+
for(var i = 0; i < nodeList.length; i++) {
|
|
3958
|
+
attrs = new Attributes();
|
|
3802
3959
|
|
|
3803
|
-
|
|
3804
|
-
|
|
3960
|
+
// we must always refer to nodeList[i] since the nodes can be replaced underneath us.
|
|
3961
|
+
directives = collectDirectives(nodeList[i], [], attrs, maxPriority);
|
|
3805
3962
|
|
|
3806
|
-
|
|
3807
|
-
|
|
3808
|
-
|
|
3963
|
+
nodeLinkFn = (directives.length)
|
|
3964
|
+
? applyDirectivesToNode(directives, nodeList[i], attrs, transcludeFn, $rootElement)
|
|
3965
|
+
: null;
|
|
3809
3966
|
|
|
3810
|
-
|
|
3811
|
-
|
|
3812
|
-
|
|
3813
|
-
|
|
3967
|
+
childLinkFn = (nodeLinkFn && nodeLinkFn.terminal || !nodeList[i].childNodes || !nodeList[i].childNodes.length)
|
|
3968
|
+
? null
|
|
3969
|
+
: compileNodes(nodeList[i].childNodes,
|
|
3970
|
+
nodeLinkFn ? nodeLinkFn.transclude : transcludeFn);
|
|
3814
3971
|
|
|
3815
|
-
|
|
3816
|
-
|
|
3817
|
-
|
|
3818
|
-
|
|
3972
|
+
linkFns.push(nodeLinkFn);
|
|
3973
|
+
linkFns.push(childLinkFn);
|
|
3974
|
+
linkFnFound = (linkFnFound || nodeLinkFn || childLinkFn);
|
|
3975
|
+
}
|
|
3819
3976
|
|
|
3820
|
-
|
|
3821
|
-
|
|
3977
|
+
// return a linking function if we have found anything, null otherwise
|
|
3978
|
+
return linkFnFound ? compositeLinkFn : null;
|
|
3822
3979
|
|
|
3823
|
-
|
|
3824
|
-
|
|
3980
|
+
function compositeLinkFn(scope, nodeList, $rootElement, boundTranscludeFn) {
|
|
3981
|
+
var nodeLinkFn, childLinkFn, node, childScope, childTranscludeFn, i, ii, n;
|
|
3825
3982
|
|
|
3826
|
-
|
|
3827
|
-
|
|
3828
|
-
|
|
3829
|
-
|
|
3983
|
+
// copy nodeList so that linking doesn't break due to live list updates.
|
|
3984
|
+
var stableNodeList = [];
|
|
3985
|
+
for (i = 0, ii = nodeList.length; i < ii; i++) {
|
|
3986
|
+
stableNodeList.push(nodeList[i]);
|
|
3987
|
+
}
|
|
3830
3988
|
|
|
3831
|
-
|
|
3832
|
-
|
|
3833
|
-
|
|
3834
|
-
|
|
3835
|
-
|
|
3836
|
-
|
|
3837
|
-
|
|
3838
|
-
|
|
3839
|
-
|
|
3840
|
-
|
|
3841
|
-
|
|
3842
|
-
|
|
3843
|
-
|
|
3844
|
-
|
|
3845
|
-
|
|
3846
|
-
|
|
3989
|
+
for(i = 0, n = 0, ii = linkFns.length; i < ii; n++) {
|
|
3990
|
+
node = stableNodeList[n];
|
|
3991
|
+
nodeLinkFn = linkFns[i++];
|
|
3992
|
+
childLinkFn = linkFns[i++];
|
|
3993
|
+
|
|
3994
|
+
if (nodeLinkFn) {
|
|
3995
|
+
if (nodeLinkFn.scope) {
|
|
3996
|
+
childScope = scope.$new(isObject(nodeLinkFn.scope));
|
|
3997
|
+
jqLite(node).data('$scope', childScope);
|
|
3998
|
+
} else {
|
|
3999
|
+
childScope = scope;
|
|
4000
|
+
}
|
|
4001
|
+
childTranscludeFn = nodeLinkFn.transclude;
|
|
4002
|
+
if (childTranscludeFn || (!boundTranscludeFn && transcludeFn)) {
|
|
4003
|
+
nodeLinkFn(childLinkFn, childScope, node, $rootElement,
|
|
4004
|
+
(function(transcludeFn) {
|
|
4005
|
+
return function(cloneFn) {
|
|
4006
|
+
var transcludeScope = scope.$new();
|
|
4007
|
+
transcludeScope.$$transcluded = true;
|
|
4008
|
+
|
|
4009
|
+
return transcludeFn(transcludeScope, cloneFn).
|
|
4010
|
+
bind('$destroy', bind(transcludeScope, transcludeScope.$destroy));
|
|
3847
4011
|
};
|
|
3848
4012
|
})(childTranscludeFn || transcludeFn)
|
|
3849
|
-
|
|
3850
|
-
|
|
3851
|
-
|
|
3852
|
-
|
|
3853
|
-
|
|
3854
|
-
|
|
3855
|
-
|
|
3856
|
-
|
|
3857
|
-
|
|
3858
|
-
|
|
4013
|
+
);
|
|
4014
|
+
} else {
|
|
4015
|
+
nodeLinkFn(childLinkFn, childScope, node, undefined, boundTranscludeFn);
|
|
4016
|
+
}
|
|
4017
|
+
} else if (childLinkFn) {
|
|
4018
|
+
childLinkFn(scope, node.childNodes, undefined, boundTranscludeFn);
|
|
4019
|
+
}
|
|
4020
|
+
}
|
|
4021
|
+
}
|
|
4022
|
+
}
|
|
3859
4023
|
|
|
3860
4024
|
|
|
3861
4025
|
/**
|
|
@@ -3936,9 +4100,9 @@ function $CompileProvider($provide) {
|
|
|
3936
4100
|
|
|
3937
4101
|
|
|
3938
4102
|
/**
|
|
3939
|
-
* Once the directives have been collected their compile functions
|
|
4103
|
+
* Once the directives have been collected, their compile functions are executed. This method
|
|
3940
4104
|
* is responsible for inlining directive templates as well as terminating the application
|
|
3941
|
-
* of the directives if the terminal directive has been reached
|
|
4105
|
+
* of the directives if the terminal directive has been reached.
|
|
3942
4106
|
*
|
|
3943
4107
|
* @param {Array} directives Array of collected directives to execute their compile function.
|
|
3944
4108
|
* this needs to be pre-sorted by priority order.
|
|
@@ -3946,11 +4110,11 @@ function $CompileProvider($provide) {
|
|
|
3946
4110
|
* @param {Object} templateAttrs The shared attribute function
|
|
3947
4111
|
* @param {function(angular.Scope[, cloneAttachFn]} transcludeFn A linking function, where the
|
|
3948
4112
|
* scope argument is auto-generated to the new child of the transcluded parent scope.
|
|
3949
|
-
* @param {
|
|
3950
|
-
* argument has the root jqLite array so that we can replace
|
|
4113
|
+
* @param {JQLite} jqCollection If we are working on the root of the compile tree then this
|
|
4114
|
+
* argument has the root jqLite array so that we can replace nodes on it.
|
|
3951
4115
|
* @returns linkFn
|
|
3952
4116
|
*/
|
|
3953
|
-
function applyDirectivesToNode(directives, compileNode, templateAttrs, transcludeFn,
|
|
4117
|
+
function applyDirectivesToNode(directives, compileNode, templateAttrs, transcludeFn, jqCollection) {
|
|
3954
4118
|
var terminalPriority = -Number.MAX_VALUE,
|
|
3955
4119
|
preLinkFns = [],
|
|
3956
4120
|
postLinkFns = [],
|
|
@@ -4002,9 +4166,9 @@ function $CompileProvider($provide) {
|
|
|
4002
4166
|
if (directiveValue == 'element') {
|
|
4003
4167
|
$template = jqLite(compileNode);
|
|
4004
4168
|
$compileNode = templateAttrs.$$element =
|
|
4005
|
-
jqLite('
|
|
4169
|
+
jqLite(document.createComment(' ' + directiveName + ': ' + templateAttrs[directiveName] + ' '));
|
|
4006
4170
|
compileNode = $compileNode[0];
|
|
4007
|
-
replaceWith(
|
|
4171
|
+
replaceWith(jqCollection, jqLite($template[0]), compileNode);
|
|
4008
4172
|
childTranscludeFn = compile($template, transcludeFn, terminalPriority);
|
|
4009
4173
|
} else {
|
|
4010
4174
|
$template = jqLite(JQLiteClone(compileNode)).contents();
|
|
@@ -4028,7 +4192,7 @@ function $CompileProvider($provide) {
|
|
|
4028
4192
|
throw new Error(MULTI_ROOT_TEMPLATE_ERROR + directiveValue);
|
|
4029
4193
|
}
|
|
4030
4194
|
|
|
4031
|
-
replaceWith(
|
|
4195
|
+
replaceWith(jqCollection, $compileNode, compileNode);
|
|
4032
4196
|
|
|
4033
4197
|
var newTemplateAttrs = {$attr: {}};
|
|
4034
4198
|
|
|
@@ -4056,7 +4220,7 @@ function $CompileProvider($provide) {
|
|
|
4056
4220
|
assertNoDuplicate('template', templateDirective, directive, $compileNode);
|
|
4057
4221
|
templateDirective = directive;
|
|
4058
4222
|
nodeLinkFn = compileTemplateUrl(directives.splice(i, directives.length - i),
|
|
4059
|
-
nodeLinkFn, $compileNode, templateAttrs,
|
|
4223
|
+
nodeLinkFn, $compileNode, templateAttrs, jqCollection, directive.replace,
|
|
4060
4224
|
childTranscludeFn);
|
|
4061
4225
|
ii = directives.length;
|
|
4062
4226
|
} else if (directive.compile) {
|
|
@@ -4146,6 +4310,8 @@ function $CompileProvider($provide) {
|
|
|
4146
4310
|
lastValue,
|
|
4147
4311
|
parentGet, parentSet;
|
|
4148
4312
|
|
|
4313
|
+
scope.$$isolateBindings[scopeName] = mode + attrName;
|
|
4314
|
+
|
|
4149
4315
|
switch (mode) {
|
|
4150
4316
|
|
|
4151
4317
|
case '@': {
|
|
@@ -4187,7 +4353,7 @@ function $CompileProvider($provide) {
|
|
|
4187
4353
|
parentGet = $parse(attrs[attrName]);
|
|
4188
4354
|
scope[scopeName] = function(locals) {
|
|
4189
4355
|
return parentGet(parentScope, locals);
|
|
4190
|
-
}
|
|
4356
|
+
};
|
|
4191
4357
|
break;
|
|
4192
4358
|
}
|
|
4193
4359
|
|
|
@@ -4356,8 +4522,8 @@ function $CompileProvider($provide) {
|
|
|
4356
4522
|
}
|
|
4357
4523
|
|
|
4358
4524
|
directives.unshift(derivedSyncDirective);
|
|
4359
|
-
afterTemplateNodeLinkFn = applyDirectivesToNode(directives,
|
|
4360
|
-
afterTemplateChildLinkFn = compileNodes($compileNode.
|
|
4525
|
+
afterTemplateNodeLinkFn = applyDirectivesToNode(directives, compileNode, tAttrs, childTranscludeFn);
|
|
4526
|
+
afterTemplateChildLinkFn = compileNodes($compileNode[0].childNodes, childTranscludeFn);
|
|
4361
4527
|
|
|
4362
4528
|
|
|
4363
4529
|
while(linkQueue.length) {
|
|
@@ -4436,10 +4602,10 @@ function $CompileProvider($provide) {
|
|
|
4436
4602
|
function addAttrInterpolateDirective(node, directives, value, name) {
|
|
4437
4603
|
var interpolateFn = $interpolate(value, true);
|
|
4438
4604
|
|
|
4439
|
-
|
|
4440
4605
|
// no interpolation found -> ignore
|
|
4441
4606
|
if (!interpolateFn) return;
|
|
4442
4607
|
|
|
4608
|
+
|
|
4443
4609
|
directives.push({
|
|
4444
4610
|
priority: 100,
|
|
4445
4611
|
compile: valueFn(function attrInterpolateLinkFn(scope, element, attr) {
|
|
@@ -4622,7 +4788,7 @@ function $ControllerProvider() {
|
|
|
4622
4788
|
* @description
|
|
4623
4789
|
* `$controller` service is responsible for instantiating controllers.
|
|
4624
4790
|
*
|
|
4625
|
-
* It's just simple call to {@link AUTO.$injector $injector}, but extracted into
|
|
4791
|
+
* It's just a simple call to {@link AUTO.$injector $injector}, but extracted into
|
|
4626
4792
|
* a service, so that one can override this service with {@link https://gist.github.com/1649788
|
|
4627
4793
|
* BC version}.
|
|
4628
4794
|
*/
|
|
@@ -4667,14 +4833,15 @@ function $DocumentProvider(){
|
|
|
4667
4833
|
* the browser console.
|
|
4668
4834
|
*
|
|
4669
4835
|
* In unit tests, if `angular-mocks.js` is loaded, this service is overridden by
|
|
4670
|
-
* {@link ngMock.$exceptionHandler mock $exceptionHandler}
|
|
4836
|
+
* {@link ngMock.$exceptionHandler mock $exceptionHandler} which aids in testing.
|
|
4671
4837
|
*
|
|
4672
4838
|
* @param {Error} exception Exception associated with the error.
|
|
4673
4839
|
* @param {string=} cause optional information about the context in which
|
|
4674
4840
|
* the error was thrown.
|
|
4841
|
+
*
|
|
4675
4842
|
*/
|
|
4676
4843
|
function $ExceptionHandlerProvider() {
|
|
4677
|
-
this.$get = ['$log', function($log){
|
|
4844
|
+
this.$get = ['$log', function($log) {
|
|
4678
4845
|
return function(exception, cause) {
|
|
4679
4846
|
$log.error.apply($log, arguments);
|
|
4680
4847
|
};
|
|
@@ -4862,7 +5029,7 @@ function $InterpolateProvider() {
|
|
|
4862
5029
|
}];
|
|
4863
5030
|
}
|
|
4864
5031
|
|
|
4865
|
-
var URL_MATCH = /^([^:]+):\/\/(\w+:{0,1}\w*@)?([\w\.-]
|
|
5032
|
+
var URL_MATCH = /^([^:]+):\/\/(\w+:{0,1}\w*@)?(\{?[\w\.-]*\}?)(:([0-9]+))?(\/[^\?#]*)?(\?([^#]*))?(#(.*))?$/,
|
|
4866
5033
|
PATH_MATCH = /^([^\?#]*)?(\?([^#]*))?(#(.*))?$/,
|
|
4867
5034
|
HASH_MATCH = PATH_MATCH,
|
|
4868
5035
|
DEFAULT_PORTS = {'http': 80, 'https': 443, 'ftp': 21};
|
|
@@ -4941,7 +5108,8 @@ function convertToHashbangUrl(url, basePath, hashPrefix) {
|
|
|
4941
5108
|
var match = matchUrl(url);
|
|
4942
5109
|
|
|
4943
5110
|
// already hashbang url
|
|
4944
|
-
if (decodeURIComponent(match.path) == basePath)
|
|
5111
|
+
if (decodeURIComponent(match.path) == basePath && !isUndefined(match.hash) &&
|
|
5112
|
+
match.hash.indexOf(hashPrefix) === 0) {
|
|
4945
5113
|
return url;
|
|
4946
5114
|
// convert html5 url -> hashbang url
|
|
4947
5115
|
} else {
|
|
@@ -5438,6 +5606,10 @@ function $LocationProvider(){
|
|
|
5438
5606
|
// update $location when $browser url changes
|
|
5439
5607
|
$browser.onUrlChange(function(newUrl) {
|
|
5440
5608
|
if ($location.absUrl() != newUrl) {
|
|
5609
|
+
if ($rootScope.$broadcast('$locationChangeStart', newUrl, $location.absUrl()).defaultPrevented) {
|
|
5610
|
+
$browser.url($location.absUrl());
|
|
5611
|
+
return;
|
|
5612
|
+
}
|
|
5441
5613
|
$rootScope.$evalAsync(function() {
|
|
5442
5614
|
var oldUrl = $location.absUrl();
|
|
5443
5615
|
|
|
@@ -5746,10 +5918,10 @@ function lex(text, csp){
|
|
|
5746
5918
|
function readIdent() {
|
|
5747
5919
|
var ident = "",
|
|
5748
5920
|
start = index,
|
|
5749
|
-
lastDot, peekIndex, methodName;
|
|
5921
|
+
lastDot, peekIndex, methodName, ch;
|
|
5750
5922
|
|
|
5751
5923
|
while (index < text.length) {
|
|
5752
|
-
|
|
5924
|
+
ch = text.charAt(index);
|
|
5753
5925
|
if (ch == '.' || isIdent(ch) || isNumber(ch)) {
|
|
5754
5926
|
if (ch == '.') lastDot = index;
|
|
5755
5927
|
ident += ch;
|
|
@@ -5763,7 +5935,7 @@ function lex(text, csp){
|
|
|
5763
5935
|
if (lastDot) {
|
|
5764
5936
|
peekIndex = index;
|
|
5765
5937
|
while(peekIndex < text.length) {
|
|
5766
|
-
|
|
5938
|
+
ch = text.charAt(peekIndex);
|
|
5767
5939
|
if (ch == '(') {
|
|
5768
5940
|
methodName = ident.substr(lastDot - start + 1);
|
|
5769
5941
|
ident = ident.substr(0, lastDot - start);
|
|
@@ -6016,8 +6188,8 @@ function parser(text, json, $filter, csp){
|
|
|
6016
6188
|
text.substring(0, token.index) + "] can not be assigned to", token);
|
|
6017
6189
|
}
|
|
6018
6190
|
right = logicalOR();
|
|
6019
|
-
return function(
|
|
6020
|
-
return left.assign(
|
|
6191
|
+
return function(scope, locals){
|
|
6192
|
+
return left.assign(scope, right(scope, locals), locals);
|
|
6021
6193
|
};
|
|
6022
6194
|
} else {
|
|
6023
6195
|
return left;
|
|
@@ -6134,12 +6306,12 @@ function parser(text, json, $filter, csp){
|
|
|
6134
6306
|
var field = expect().text;
|
|
6135
6307
|
var getter = getterFn(field, csp);
|
|
6136
6308
|
return extend(
|
|
6137
|
-
function(
|
|
6138
|
-
return getter(object(
|
|
6309
|
+
function(scope, locals, self) {
|
|
6310
|
+
return getter(self || object(scope, locals), locals);
|
|
6139
6311
|
},
|
|
6140
6312
|
{
|
|
6141
|
-
assign:function(
|
|
6142
|
-
return setter(object(
|
|
6313
|
+
assign:function(scope, value, locals) {
|
|
6314
|
+
return setter(object(scope, locals), field, value);
|
|
6143
6315
|
}
|
|
6144
6316
|
}
|
|
6145
6317
|
);
|
|
@@ -6180,14 +6352,14 @@ function parser(text, json, $filter, csp){
|
|
|
6180
6352
|
} while (expect(','));
|
|
6181
6353
|
}
|
|
6182
6354
|
consume(')');
|
|
6183
|
-
return function(
|
|
6355
|
+
return function(scope, locals){
|
|
6184
6356
|
var args = [],
|
|
6185
|
-
context = contextGetter ? contextGetter(
|
|
6357
|
+
context = contextGetter ? contextGetter(scope, locals) : scope;
|
|
6186
6358
|
|
|
6187
6359
|
for ( var i = 0; i < argsFn.length; i++) {
|
|
6188
|
-
args.push(argsFn[i](
|
|
6360
|
+
args.push(argsFn[i](scope, locals));
|
|
6189
6361
|
}
|
|
6190
|
-
var fnPtr = fn(
|
|
6362
|
+
var fnPtr = fn(scope, locals, context) || noop;
|
|
6191
6363
|
// IE stupidity!
|
|
6192
6364
|
return fnPtr.apply
|
|
6193
6365
|
? fnPtr.apply(context, args)
|
|
@@ -6229,8 +6401,7 @@ function parser(text, json, $filter, csp){
|
|
|
6229
6401
|
var object = {};
|
|
6230
6402
|
for ( var i = 0; i < keyValues.length; i++) {
|
|
6231
6403
|
var keyValue = keyValues[i];
|
|
6232
|
-
|
|
6233
|
-
object[keyValue.key] = value;
|
|
6404
|
+
object[keyValue.key] = keyValue.value(self, locals);
|
|
6234
6405
|
}
|
|
6235
6406
|
return object;
|
|
6236
6407
|
};
|
|
@@ -6352,7 +6523,7 @@ function cspSafeGetterFn(key0, key1, key2, key3, key4) {
|
|
|
6352
6523
|
}
|
|
6353
6524
|
return pathVal;
|
|
6354
6525
|
};
|
|
6355
|
-
}
|
|
6526
|
+
}
|
|
6356
6527
|
|
|
6357
6528
|
function getterFn(path, csp) {
|
|
6358
6529
|
if (getterFnCache.hasOwnProperty(path)) {
|
|
@@ -6367,7 +6538,7 @@ function getterFn(path, csp) {
|
|
|
6367
6538
|
fn = (pathKeysLength < 6)
|
|
6368
6539
|
? cspSafeGetterFn(pathKeys[0], pathKeys[1], pathKeys[2], pathKeys[3], pathKeys[4])
|
|
6369
6540
|
: function(scope, locals) {
|
|
6370
|
-
var i = 0, val
|
|
6541
|
+
var i = 0, val;
|
|
6371
6542
|
do {
|
|
6372
6543
|
val = cspSafeGetterFn(
|
|
6373
6544
|
pathKeys[i++], pathKeys[i++], pathKeys[i++], pathKeys[i++], pathKeys[i++]
|
|
@@ -6432,9 +6603,10 @@ function getterFn(path, csp) {
|
|
|
6432
6603
|
* @param {string} expression String expression to compile.
|
|
6433
6604
|
* @returns {function(context, locals)} a function which represents the compiled expression:
|
|
6434
6605
|
*
|
|
6435
|
-
* * `context
|
|
6436
|
-
* against (
|
|
6437
|
-
* * `locals
|
|
6606
|
+
* * `context` – `{object}` – an object against which any expressions embedded in the strings
|
|
6607
|
+
* are evaluated against (tipically a scope object).
|
|
6608
|
+
* * `locals` – `{object=}` – local variables context object, useful for overriding values in
|
|
6609
|
+
* `context`.
|
|
6438
6610
|
*
|
|
6439
6611
|
* The return function also has an `assign` property, if the expression is assignable, which
|
|
6440
6612
|
* allows one to set values to expressions.
|
|
@@ -6470,8 +6642,8 @@ function $ParseProvider() {
|
|
|
6470
6642
|
* interface for interacting with an object that represents the result of an action that is
|
|
6471
6643
|
* performed asynchronously, and may or may not be finished at any given point in time.
|
|
6472
6644
|
*
|
|
6473
|
-
* From the perspective of dealing with error handling, deferred and promise
|
|
6474
|
-
* asynchronous
|
|
6645
|
+
* From the perspective of dealing with error handling, deferred and promise APIs are to
|
|
6646
|
+
* asynchronous programming what `try`, `catch` and `throw` keywords are to synchronous programming.
|
|
6475
6647
|
*
|
|
6476
6648
|
* <pre>
|
|
6477
6649
|
* // for the purpose of this example let's assume that variables `$q` and `scope` are
|
|
@@ -6505,7 +6677,7 @@ function $ParseProvider() {
|
|
|
6505
6677
|
*
|
|
6506
6678
|
* At first it might not be obvious why this extra complexity is worth the trouble. The payoff
|
|
6507
6679
|
* comes in the way of
|
|
6508
|
-
* [guarantees that promise and deferred
|
|
6680
|
+
* [guarantees that promise and deferred APIs make](https://github.com/kriskowal/uncommonjs/blob/master/promises/specification.md).
|
|
6509
6681
|
*
|
|
6510
6682
|
* Additionally the promise api allows for composition that is very hard to do with the
|
|
6511
6683
|
* traditional callback ([CPS](http://en.wikipedia.org/wiki/Continuation-passing_style)) approach.
|
|
@@ -6517,7 +6689,7 @@ function $ParseProvider() {
|
|
|
6517
6689
|
*
|
|
6518
6690
|
* A new instance of deferred is constructed by calling `$q.defer()`.
|
|
6519
6691
|
*
|
|
6520
|
-
* The purpose of the deferred object is to expose the associated Promise instance as well as
|
|
6692
|
+
* The purpose of the deferred object is to expose the associated Promise instance as well as APIs
|
|
6521
6693
|
* that can be used for signaling the successful or unsuccessful completion of the task.
|
|
6522
6694
|
*
|
|
6523
6695
|
* **Methods**
|
|
@@ -6560,7 +6732,7 @@ function $ParseProvider() {
|
|
|
6560
6732
|
* return result + 1;
|
|
6561
6733
|
* });
|
|
6562
6734
|
*
|
|
6563
|
-
* // promiseB will be resolved immediately after promiseA is resolved and
|
|
6735
|
+
* // promiseB will be resolved immediately after promiseA is resolved and its value will be
|
|
6564
6736
|
* // the result of promiseA incremented by 1
|
|
6565
6737
|
* </pre>
|
|
6566
6738
|
*
|
|
@@ -6579,8 +6751,32 @@ function $ParseProvider() {
|
|
|
6579
6751
|
* models and avoiding unnecessary browser repaints, which would result in flickering UI.
|
|
6580
6752
|
* - $q promises are recognized by the templating engine in angular, which means that in templates
|
|
6581
6753
|
* you can treat promises attached to a scope as if they were the resulting values.
|
|
6582
|
-
* - Q has many more features
|
|
6754
|
+
* - Q has many more features than $q, but that comes at a cost of bytes. $q is tiny, but contains
|
|
6583
6755
|
* all the important functionality needed for common async tasks.
|
|
6756
|
+
*
|
|
6757
|
+
* # Testing
|
|
6758
|
+
*
|
|
6759
|
+
* <pre>
|
|
6760
|
+
* it('should simulate promise', inject(function($q, $rootScope) {
|
|
6761
|
+
* var deferred = $q.defer();
|
|
6762
|
+
* var promise = deferred.promise;
|
|
6763
|
+
* var resolvedValue;
|
|
6764
|
+
*
|
|
6765
|
+
* promise.then(function(value) { resolvedValue = value; });
|
|
6766
|
+
* expect(resolvedValue).toBeUndefined();
|
|
6767
|
+
*
|
|
6768
|
+
* // Simulate resolving of promise
|
|
6769
|
+
* deferred.resolve(123);
|
|
6770
|
+
* // Note that the 'then' function does not get called synchronously.
|
|
6771
|
+
* // This is because we want the promise API to always be async, whether or not
|
|
6772
|
+
* // it got called synchronously or asynchronously.
|
|
6773
|
+
* expect(resolvedValue).toBeUndefined();
|
|
6774
|
+
*
|
|
6775
|
+
* // Propagate promise resolution to 'then' functions using $apply().
|
|
6776
|
+
* $rootScope.$apply();
|
|
6777
|
+
* expect(resolvedValue).toEqual(123);
|
|
6778
|
+
* });
|
|
6779
|
+
* </pre>
|
|
6584
6780
|
*/
|
|
6585
6781
|
function $QProvider() {
|
|
6586
6782
|
|
|
@@ -6746,14 +6942,11 @@ function qFactory(nextTick, exceptionHandler) {
|
|
|
6746
6942
|
* @methodOf ng.$q
|
|
6747
6943
|
* @description
|
|
6748
6944
|
* Wraps an object that might be a value or a (3rd party) then-able promise into a $q promise.
|
|
6749
|
-
* This is useful when you are dealing with
|
|
6945
|
+
* This is useful when you are dealing with an object that might or might not be a promise, or if
|
|
6750
6946
|
* the promise comes from a source that can't be trusted.
|
|
6751
6947
|
*
|
|
6752
6948
|
* @param {*} value Value or a promise
|
|
6753
|
-
* @returns {Promise} Returns a
|
|
6754
|
-
* each value coresponding to the promise at the same index in the `promises` array. If any of
|
|
6755
|
-
* the promises is resolved with a rejection, this resulting promise will be resolved with the
|
|
6756
|
-
* same rejection.
|
|
6949
|
+
* @returns {Promise} Returns a promise of the passed value or promise
|
|
6757
6950
|
*/
|
|
6758
6951
|
var when = function(value, callback, errback) {
|
|
6759
6952
|
var result = defer(),
|
|
@@ -6813,7 +7006,7 @@ function qFactory(nextTick, exceptionHandler) {
|
|
|
6813
7006
|
*
|
|
6814
7007
|
* @param {Array.<Promise>} promises An array of promises.
|
|
6815
7008
|
* @returns {Promise} Returns a single promise that will be resolved with an array of values,
|
|
6816
|
-
* each value
|
|
7009
|
+
* each value corresponding to the promise at the same index in the `promises` array. If any of
|
|
6817
7010
|
* the promises is resolved with a rejection, this resulting promise will be resolved with the
|
|
6818
7011
|
* same rejection.
|
|
6819
7012
|
*/
|
|
@@ -6867,8 +7060,13 @@ function $RouteProvider(){
|
|
|
6867
7060
|
*
|
|
6868
7061
|
* @param {string} path Route path (matched against `$location.path`). If `$location.path`
|
|
6869
7062
|
* contains redundant trailing slash or is missing one, the route will still match and the
|
|
6870
|
-
* `$location.path` will be updated to add or drop the trailing slash to
|
|
7063
|
+
* `$location.path` will be updated to add or drop the trailing slash to exactly match the
|
|
6871
7064
|
* route definition.
|
|
7065
|
+
*
|
|
7066
|
+
* `path` can contain named groups starting with a colon (`:name`). All characters up to the
|
|
7067
|
+
* next slash are matched and stored in `$routeParams` under the given `name` when the route
|
|
7068
|
+
* matches.
|
|
7069
|
+
*
|
|
6872
7070
|
* @param {Object} route Mapping information to be assigned to `$route.current` on route
|
|
6873
7071
|
* match.
|
|
6874
7072
|
*
|
|
@@ -7105,8 +7303,9 @@ function $RouteProvider(){
|
|
|
7105
7303
|
* {@link ng.directive:ngView ngView} listens for the directive
|
|
7106
7304
|
* to instantiate the controller and render the view.
|
|
7107
7305
|
*
|
|
7306
|
+
* @param {Object} angularEvent Synthetic event object.
|
|
7108
7307
|
* @param {Route} current Current route information.
|
|
7109
|
-
* @param {Route} previous Previous route information.
|
|
7308
|
+
* @param {Route|Undefined} previous Previous route information, or undefined if current is first route entered.
|
|
7110
7309
|
*/
|
|
7111
7310
|
|
|
7112
7311
|
/**
|
|
@@ -7133,8 +7332,7 @@ function $RouteProvider(){
|
|
|
7133
7332
|
* instance of the Controller.
|
|
7134
7333
|
*/
|
|
7135
7334
|
|
|
7136
|
-
var
|
|
7137
|
-
forceReload = false,
|
|
7335
|
+
var forceReload = false,
|
|
7138
7336
|
$route = {
|
|
7139
7337
|
routes: routes,
|
|
7140
7338
|
|
|
@@ -7162,21 +7360,36 @@ function $RouteProvider(){
|
|
|
7162
7360
|
|
|
7163
7361
|
/////////////////////////////////////////////////////
|
|
7164
7362
|
|
|
7363
|
+
/**
|
|
7364
|
+
* @param on {string} current url
|
|
7365
|
+
* @param when {string} route when template to match the url against
|
|
7366
|
+
* @return {?Object}
|
|
7367
|
+
*/
|
|
7165
7368
|
function switchRouteMatcher(on, when) {
|
|
7166
7369
|
// TODO(i): this code is convoluted and inefficient, we should construct the route matching
|
|
7167
7370
|
// regex only once and then reuse it
|
|
7168
|
-
|
|
7371
|
+
|
|
7372
|
+
// Escape regexp special characters.
|
|
7373
|
+
when = '^' + when.replace(/[-\/\\^$*+?.()|[\]{}]/g, "\\$&") + '$';
|
|
7374
|
+
var regex = '',
|
|
7169
7375
|
params = [],
|
|
7170
7376
|
dst = {};
|
|
7171
|
-
|
|
7172
|
-
|
|
7173
|
-
|
|
7174
|
-
|
|
7175
|
-
|
|
7176
|
-
|
|
7177
|
-
|
|
7178
|
-
|
|
7179
|
-
|
|
7377
|
+
|
|
7378
|
+
var re = /:(\w+)/g,
|
|
7379
|
+
paramMatch,
|
|
7380
|
+
lastMatchedIndex = 0;
|
|
7381
|
+
|
|
7382
|
+
while ((paramMatch = re.exec(when)) !== null) {
|
|
7383
|
+
// Find each :param in `when` and replace it with a capturing group.
|
|
7384
|
+
// Append all other sections of when unchanged.
|
|
7385
|
+
regex += when.slice(lastMatchedIndex, paramMatch.index);
|
|
7386
|
+
regex += '([^\\/]*)';
|
|
7387
|
+
params.push(paramMatch[1]);
|
|
7388
|
+
lastMatchedIndex = re.lastIndex;
|
|
7389
|
+
}
|
|
7390
|
+
// Append trailing path part.
|
|
7391
|
+
regex += when.substr(lastMatchedIndex);
|
|
7392
|
+
|
|
7180
7393
|
var match = on.match(new RegExp(regex));
|
|
7181
7394
|
if (match) {
|
|
7182
7395
|
forEach(params, function(name, index) {
|
|
@@ -7190,7 +7403,7 @@ function $RouteProvider(){
|
|
|
7190
7403
|
var next = parseRoute(),
|
|
7191
7404
|
last = $route.current;
|
|
7192
7405
|
|
|
7193
|
-
if (next && last && next
|
|
7406
|
+
if (next && last && next.$$route === last.$$route
|
|
7194
7407
|
&& equals(next.pathParams, last.pathParams) && !next.reloadOnSearch && !forceReload) {
|
|
7195
7408
|
last.params = next.params;
|
|
7196
7409
|
copy(last.params, $routeParams);
|
|
@@ -7265,11 +7478,11 @@ function $RouteProvider(){
|
|
|
7265
7478
|
// Match a route
|
|
7266
7479
|
var params, match;
|
|
7267
7480
|
forEach(routes, function(route, path) {
|
|
7268
|
-
if (!match && (params =
|
|
7481
|
+
if (!match && (params = switchRouteMatcher($location.path(), path))) {
|
|
7269
7482
|
match = inherit(route, {
|
|
7270
7483
|
params: extend({}, $location.search(), params),
|
|
7271
7484
|
pathParams: params});
|
|
7272
|
-
match
|
|
7485
|
+
match.$$route = route;
|
|
7273
7486
|
}
|
|
7274
7487
|
});
|
|
7275
7488
|
// No route matched; fallback to "otherwise" route
|
|
@@ -7329,22 +7542,22 @@ function $RouteParamsProvider() {
|
|
|
7329
7542
|
/**
|
|
7330
7543
|
* DESIGN NOTES
|
|
7331
7544
|
*
|
|
7332
|
-
* The design decisions behind the scope
|
|
7545
|
+
* The design decisions behind the scope are heavily favored for speed and memory consumption.
|
|
7333
7546
|
*
|
|
7334
7547
|
* The typical use of scope is to watch the expressions, which most of the time return the same
|
|
7335
7548
|
* value as last time so we optimize the operation.
|
|
7336
7549
|
*
|
|
7337
|
-
* Closures construction is expensive
|
|
7338
|
-
* -
|
|
7550
|
+
* Closures construction is expensive in terms of speed as well as memory:
|
|
7551
|
+
* - No closures, instead use prototypical inheritance for API
|
|
7339
7552
|
* - Internal state needs to be stored on scope directly, which means that private state is
|
|
7340
7553
|
* exposed as $$____ properties
|
|
7341
7554
|
*
|
|
7342
7555
|
* Loop operations are optimized by using while(count--) { ... }
|
|
7343
7556
|
* - this means that in order to keep the same order of execution as addition we have to add
|
|
7344
|
-
* items to the array at the
|
|
7557
|
+
* items to the array at the beginning (shift) instead of at the end (push)
|
|
7345
7558
|
*
|
|
7346
7559
|
* Child scopes are created and removed often
|
|
7347
|
-
* - Using array would be slow since inserts in
|
|
7560
|
+
* - Using an array would be slow since inserts in middle are expensive so we use linked list
|
|
7348
7561
|
*
|
|
7349
7562
|
* There are few watches then a lot of observers. This is why you don't want the observer to be
|
|
7350
7563
|
* implemented in the same way as watch. Watch requires return of initialization function which
|
|
@@ -7366,7 +7579,7 @@ function $RouteParamsProvider() {
|
|
|
7366
7579
|
* @methodOf ng.$rootScopeProvider
|
|
7367
7580
|
* @description
|
|
7368
7581
|
*
|
|
7369
|
-
* Sets the number of digest
|
|
7582
|
+
* Sets the number of digest iterations the scope should attempt to execute before giving up and
|
|
7370
7583
|
* assuming that the model is unstable.
|
|
7371
7584
|
*
|
|
7372
7585
|
* The current default is 10 iterations.
|
|
@@ -7417,7 +7630,7 @@ function $RootScopeProvider(){
|
|
|
7417
7630
|
expect(scope.greeting).toEqual(undefined);
|
|
7418
7631
|
|
|
7419
7632
|
scope.$watch('name', function() {
|
|
7420
|
-
|
|
7633
|
+
scope.greeting = scope.salutation + ' ' + scope.name + '!';
|
|
7421
7634
|
}); // initialize the watch
|
|
7422
7635
|
|
|
7423
7636
|
expect(scope.greeting).toEqual(undefined);
|
|
@@ -7460,8 +7673,10 @@ function $RootScopeProvider(){
|
|
|
7460
7673
|
this.$$nextSibling = this.$$prevSibling =
|
|
7461
7674
|
this.$$childHead = this.$$childTail = null;
|
|
7462
7675
|
this['this'] = this.$root = this;
|
|
7676
|
+
this.$$destroyed = false;
|
|
7463
7677
|
this.$$asyncQueue = [];
|
|
7464
7678
|
this.$$listeners = {};
|
|
7679
|
+
this.$$isolateBindings = {};
|
|
7465
7680
|
}
|
|
7466
7681
|
|
|
7467
7682
|
/**
|
|
@@ -7578,7 +7793,7 @@ function $RootScopeProvider(){
|
|
|
7578
7793
|
scope.counter = 0;
|
|
7579
7794
|
|
|
7580
7795
|
expect(scope.counter).toEqual(0);
|
|
7581
|
-
scope.$watch('name', function(newValue, oldValue) { counter = counter + 1; });
|
|
7796
|
+
scope.$watch('name', function(newValue, oldValue) { scope.counter = scope.counter + 1; });
|
|
7582
7797
|
expect(scope.counter).toEqual(0);
|
|
7583
7798
|
|
|
7584
7799
|
scope.$digest();
|
|
@@ -7644,7 +7859,7 @@ function $RootScopeProvider(){
|
|
|
7644
7859
|
* @function
|
|
7645
7860
|
*
|
|
7646
7861
|
* @description
|
|
7647
|
-
*
|
|
7862
|
+
* Processes all of the {@link ng.$rootScope.Scope#$watch watchers} of the current scope and its children.
|
|
7648
7863
|
* Because a {@link ng.$rootScope.Scope#$watch watcher}'s listener can change the model, the
|
|
7649
7864
|
* `$digest()` keeps calling the {@link ng.$rootScope.Scope#$watch watchers} until no more listeners are
|
|
7650
7865
|
* firing. This means that it is possible to get into an infinite loop. This function will throw
|
|
@@ -7671,7 +7886,7 @@ function $RootScopeProvider(){
|
|
|
7671
7886
|
|
|
7672
7887
|
expect(scope.counter).toEqual(0);
|
|
7673
7888
|
scope.$watch('name', function(newValue, oldValue) {
|
|
7674
|
-
counter = counter + 1;
|
|
7889
|
+
scope.counter = scope.counter + 1;
|
|
7675
7890
|
});
|
|
7676
7891
|
expect(scope.counter).toEqual(0);
|
|
7677
7892
|
|
|
@@ -7793,10 +8008,12 @@ function $RootScopeProvider(){
|
|
|
7793
8008
|
* perform any necessary cleanup.
|
|
7794
8009
|
*/
|
|
7795
8010
|
$destroy: function() {
|
|
7796
|
-
|
|
8011
|
+
// we can't destroy the root scope or a scope that has been already destroyed
|
|
8012
|
+
if ($rootScope == this || this.$$destroyed) return;
|
|
7797
8013
|
var parent = this.$parent;
|
|
7798
8014
|
|
|
7799
8015
|
this.$broadcast('$destroy');
|
|
8016
|
+
this.$$destroyed = true;
|
|
7800
8017
|
|
|
7801
8018
|
if (parent.$$childHead == this) parent.$$childHead = this.$$nextSibling;
|
|
7802
8019
|
if (parent.$$childTail == this) parent.$$childTail = this.$$prevSibling;
|
|
@@ -7941,10 +8158,6 @@ function $RootScopeProvider(){
|
|
|
7941
8158
|
* Listens on events of a given type. See {@link ng.$rootScope.Scope#$emit $emit} for discussion of
|
|
7942
8159
|
* event life cycle.
|
|
7943
8160
|
*
|
|
7944
|
-
* @param {string} name Event name to listen on.
|
|
7945
|
-
* @param {function(event)} listener Function to call when the event is emitted.
|
|
7946
|
-
* @returns {function()} Returns a deregistration function for this listener.
|
|
7947
|
-
*
|
|
7948
8161
|
* The event listener function format is: `function(event, args...)`. The `event` object
|
|
7949
8162
|
* passed into the listener has the following attributes:
|
|
7950
8163
|
*
|
|
@@ -7955,6 +8168,10 @@ function $RootScopeProvider(){
|
|
|
7955
8168
|
* propagation (available only for events that were `$emit`-ed).
|
|
7956
8169
|
* - `preventDefault` - `{function}`: calling `preventDefault` sets `defaultPrevented` flag to true.
|
|
7957
8170
|
* - `defaultPrevented` - `{boolean}`: true if `preventDefault` was called.
|
|
8171
|
+
*
|
|
8172
|
+
* @param {string} name Event name to listen on.
|
|
8173
|
+
* @param {function(event, args...)} listener Function to call when the event is emitted.
|
|
8174
|
+
* @returns {function()} Returns a deregistration function for this listener.
|
|
7958
8175
|
*/
|
|
7959
8176
|
$on: function(name, listener) {
|
|
7960
8177
|
var namedListeners = this.$$listeners[name];
|
|
@@ -7984,7 +8201,7 @@ function $RootScopeProvider(){
|
|
|
7984
8201
|
* Afterwards, the event traverses upwards toward the root scope and calls all registered
|
|
7985
8202
|
* listeners along the way. The event will stop propagating if one of the listeners cancels it.
|
|
7986
8203
|
*
|
|
7987
|
-
* Any exception
|
|
8204
|
+
* Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed
|
|
7988
8205
|
* onto the {@link ng.$exceptionHandler $exceptionHandler} service.
|
|
7989
8206
|
*
|
|
7990
8207
|
* @param {string} name Event name to emit.
|
|
@@ -8053,7 +8270,7 @@ function $RootScopeProvider(){
|
|
|
8053
8270
|
* Any exception emmited from the {@link ng.$rootScope.Scope#$on listeners} will be passed
|
|
8054
8271
|
* onto the {@link ng.$exceptionHandler $exceptionHandler} service.
|
|
8055
8272
|
*
|
|
8056
|
-
* @param {string} name Event name to
|
|
8273
|
+
* @param {string} name Event name to broadcast.
|
|
8057
8274
|
* @param {...*} args Optional set of arguments which will be passed onto the event listeners.
|
|
8058
8275
|
* @return {Object} Event object, see {@link ng.$rootScope.Scope#$on}
|
|
8059
8276
|
*/
|
|
@@ -8132,7 +8349,7 @@ function $RootScopeProvider(){
|
|
|
8132
8349
|
|
|
8133
8350
|
/**
|
|
8134
8351
|
* function used as an initial value for watchers.
|
|
8135
|
-
* because it's
|
|
8352
|
+
* because it's unique we can easily tell it apart from other values
|
|
8136
8353
|
*/
|
|
8137
8354
|
function initWatchVal() {}
|
|
8138
8355
|
}];
|
|
@@ -8199,10 +8416,23 @@ function $SnifferProvider() {
|
|
|
8199
8416
|
* @example
|
|
8200
8417
|
<doc:example>
|
|
8201
8418
|
<doc:source>
|
|
8202
|
-
<
|
|
8203
|
-
|
|
8419
|
+
<script>
|
|
8420
|
+
function Ctrl($scope, $window) {
|
|
8421
|
+
$scope.$window = $window;
|
|
8422
|
+
$scope.greeting = 'Hello, World!';
|
|
8423
|
+
}
|
|
8424
|
+
</script>
|
|
8425
|
+
<div ng-controller="Ctrl">
|
|
8426
|
+
<input type="text" ng-model="greeting" />
|
|
8427
|
+
<button ng-click="$window.alert(greeting)">ALERT</button>
|
|
8428
|
+
</div>
|
|
8204
8429
|
</doc:source>
|
|
8205
8430
|
<doc:scenario>
|
|
8431
|
+
it('should display the greeting in the input box', function() {
|
|
8432
|
+
input('greeting').enter('Hello, E2E Tests');
|
|
8433
|
+
// If we click the button it will block the test runner
|
|
8434
|
+
// element(':button').click();
|
|
8435
|
+
});
|
|
8206
8436
|
</doc:scenario>
|
|
8207
8437
|
</doc:example>
|
|
8208
8438
|
*/
|
|
@@ -8346,7 +8576,7 @@ function $HttpProvider() {
|
|
|
8346
8576
|
/**
|
|
8347
8577
|
* @ngdoc function
|
|
8348
8578
|
* @name ng.$http
|
|
8349
|
-
* @requires $
|
|
8579
|
+
* @requires $httpBackend
|
|
8350
8580
|
* @requires $browser
|
|
8351
8581
|
* @requires $cacheFactory
|
|
8352
8582
|
* @requires $rootScope
|
|
@@ -8355,7 +8585,7 @@ function $HttpProvider() {
|
|
|
8355
8585
|
*
|
|
8356
8586
|
* @description
|
|
8357
8587
|
* The `$http` service is a core Angular service that facilitates communication with the remote
|
|
8358
|
-
* HTTP servers via browser's {@link https://developer.mozilla.org/en/xmlhttprequest
|
|
8588
|
+
* HTTP servers via the browser's {@link https://developer.mozilla.org/en/xmlhttprequest
|
|
8359
8589
|
* XMLHttpRequest} object or via {@link http://en.wikipedia.org/wiki/JSONP JSONP}.
|
|
8360
8590
|
*
|
|
8361
8591
|
* For unit testing applications that use `$http` service, see
|
|
@@ -8365,13 +8595,13 @@ function $HttpProvider() {
|
|
|
8365
8595
|
* $resource} service.
|
|
8366
8596
|
*
|
|
8367
8597
|
* The $http API is based on the {@link ng.$q deferred/promise APIs} exposed by
|
|
8368
|
-
* the $q service. While for simple usage
|
|
8369
|
-
* it is important to familiarize yourself with these
|
|
8598
|
+
* the $q service. While for simple usage patterns this doesn't matter much, for advanced usage
|
|
8599
|
+
* it is important to familiarize yourself with these APIs and the guarantees they provide.
|
|
8370
8600
|
*
|
|
8371
8601
|
*
|
|
8372
8602
|
* # General usage
|
|
8373
8603
|
* The `$http` service is a function which takes a single argument — a configuration object —
|
|
8374
|
-
* that is used to generate an
|
|
8604
|
+
* that is used to generate an HTTP request and returns a {@link ng.$q promise}
|
|
8375
8605
|
* with two $http specific methods: `success` and `error`.
|
|
8376
8606
|
*
|
|
8377
8607
|
* <pre>
|
|
@@ -8382,22 +8612,25 @@ function $HttpProvider() {
|
|
|
8382
8612
|
* }).
|
|
8383
8613
|
* error(function(data, status, headers, config) {
|
|
8384
8614
|
* // called asynchronously if an error occurs
|
|
8385
|
-
* // or server returns response with status
|
|
8386
|
-
* // code outside of the <200, 400) range
|
|
8615
|
+
* // or server returns response with an error status.
|
|
8387
8616
|
* });
|
|
8388
8617
|
* </pre>
|
|
8389
8618
|
*
|
|
8390
|
-
* Since the returned value of calling the $http function is a
|
|
8619
|
+
* Since the returned value of calling the $http function is a `promise`, you can also use
|
|
8391
8620
|
* the `then` method to register callbacks, and these callbacks will receive a single argument –
|
|
8392
|
-
* an object representing the response. See the
|
|
8621
|
+
* an object representing the response. See the API signature and type info below for more
|
|
8393
8622
|
* details.
|
|
8394
8623
|
*
|
|
8624
|
+
* A response status code between 200 and 299 is considered a success status and
|
|
8625
|
+
* will result in the success callback being called. Note that if the response is a redirect,
|
|
8626
|
+
* XMLHttpRequest will transparently follow it, meaning that the error callback will not be
|
|
8627
|
+
* called for such responses.
|
|
8395
8628
|
*
|
|
8396
8629
|
* # Shortcut methods
|
|
8397
8630
|
*
|
|
8398
|
-
* Since all
|
|
8399
|
-
* POST
|
|
8400
|
-
* were created
|
|
8631
|
+
* Since all invocations of the $http service require passing in an HTTP method and URL, and
|
|
8632
|
+
* POST/PUT requests require request data to be provided as well, shortcut methods
|
|
8633
|
+
* were created:
|
|
8401
8634
|
*
|
|
8402
8635
|
* <pre>
|
|
8403
8636
|
* $http.get('/someUrl').success(successCallback);
|
|
@@ -8416,25 +8649,25 @@ function $HttpProvider() {
|
|
|
8416
8649
|
*
|
|
8417
8650
|
* # Setting HTTP Headers
|
|
8418
8651
|
*
|
|
8419
|
-
* The $http service will automatically add certain
|
|
8652
|
+
* The $http service will automatically add certain HTTP headers to all requests. These defaults
|
|
8420
8653
|
* can be fully configured by accessing the `$httpProvider.defaults.headers` configuration
|
|
8421
8654
|
* object, which currently contains this default configuration:
|
|
8422
8655
|
*
|
|
8423
8656
|
* - `$httpProvider.defaults.headers.common` (headers that are common for all requests):
|
|
8424
8657
|
* - `Accept: application/json, text/plain, * / *`
|
|
8425
8658
|
* - `X-Requested-With: XMLHttpRequest`
|
|
8426
|
-
* - `$httpProvider.defaults.headers.post`: (header defaults for
|
|
8659
|
+
* - `$httpProvider.defaults.headers.post`: (header defaults for POST requests)
|
|
8427
8660
|
* - `Content-Type: application/json`
|
|
8428
|
-
* - `$httpProvider.defaults.headers.put` (header defaults for
|
|
8661
|
+
* - `$httpProvider.defaults.headers.put` (header defaults for PUT requests)
|
|
8429
8662
|
* - `Content-Type: application/json`
|
|
8430
8663
|
*
|
|
8431
|
-
* To add or overwrite these defaults, simply add or remove a property from
|
|
8664
|
+
* To add or overwrite these defaults, simply add or remove a property from these configuration
|
|
8432
8665
|
* objects. To add headers for an HTTP method other than POST or PUT, simply add a new object
|
|
8433
|
-
* with
|
|
8666
|
+
* with the lowercased HTTP method name as the key, e.g.
|
|
8434
8667
|
* `$httpProvider.defaults.headers.get['My-Header']='value'`.
|
|
8435
8668
|
*
|
|
8436
|
-
* Additionally, the defaults can be set at runtime via the `$http.defaults` object in
|
|
8437
|
-
*
|
|
8669
|
+
* Additionally, the defaults can be set at runtime via the `$http.defaults` object in the same
|
|
8670
|
+
* fashion.
|
|
8438
8671
|
*
|
|
8439
8672
|
*
|
|
8440
8673
|
* # Transforming Requests and Responses
|
|
@@ -8444,32 +8677,36 @@ function $HttpProvider() {
|
|
|
8444
8677
|
*
|
|
8445
8678
|
* Request transformations:
|
|
8446
8679
|
*
|
|
8447
|
-
* -
|
|
8680
|
+
* - If the `data` property of the request configuration object contains an object, serialize it into
|
|
8448
8681
|
* JSON format.
|
|
8449
8682
|
*
|
|
8450
8683
|
* Response transformations:
|
|
8451
8684
|
*
|
|
8452
|
-
* -
|
|
8453
|
-
* -
|
|
8685
|
+
* - If XSRF prefix is detected, strip it (see Security Considerations section below).
|
|
8686
|
+
* - If JSON response is detected, deserialize it using a JSON parser.
|
|
8454
8687
|
*
|
|
8455
|
-
* To override
|
|
8456
|
-
*
|
|
8457
|
-
*
|
|
8458
|
-
*
|
|
8688
|
+
* To globally augment or override the default transforms, modify the `$httpProvider.defaults.transformRequest` and
|
|
8689
|
+
* `$httpProvider.defaults.transformResponse` properties. These properties are by default an
|
|
8690
|
+
* array of transform functions, which allows you to `push` or `unshift` a new transformation function into the
|
|
8691
|
+
* transformation chain. You can also decide to completely override any default transformations by assigning your
|
|
8692
|
+
* transformation functions to these properties directly without the array wrapper.
|
|
8693
|
+
*
|
|
8694
|
+
* Similarly, to locally override the request/response transforms, augment the `transformRequest` and/or
|
|
8695
|
+
* `transformResponse` properties of the configuration object passed into `$http`.
|
|
8459
8696
|
*
|
|
8460
8697
|
*
|
|
8461
8698
|
* # Caching
|
|
8462
8699
|
*
|
|
8463
|
-
* To enable caching set the configuration property `cache` to `true`. When the cache is
|
|
8700
|
+
* To enable caching, set the configuration property `cache` to `true`. When the cache is
|
|
8464
8701
|
* enabled, `$http` stores the response from the server in local cache. Next time the
|
|
8465
8702
|
* response is served from the cache without sending a request to the server.
|
|
8466
8703
|
*
|
|
8467
8704
|
* Note that even if the response is served from cache, delivery of the data is asynchronous in
|
|
8468
8705
|
* the same way that real requests are.
|
|
8469
8706
|
*
|
|
8470
|
-
* If there are multiple GET requests for the same
|
|
8707
|
+
* If there are multiple GET requests for the same URL that should be cached using the same
|
|
8471
8708
|
* cache, but the cache is not populated yet, only one request to the server will be made and
|
|
8472
|
-
* the remaining requests will be fulfilled using the response
|
|
8709
|
+
* the remaining requests will be fulfilled using the response from the first request.
|
|
8473
8710
|
*
|
|
8474
8711
|
*
|
|
8475
8712
|
* # Response interceptors
|
|
@@ -8521,7 +8758,7 @@ function $HttpProvider() {
|
|
|
8521
8758
|
* When designing web applications, consider security threats from:
|
|
8522
8759
|
*
|
|
8523
8760
|
* - {@link http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx
|
|
8524
|
-
* JSON
|
|
8761
|
+
* JSON vulnerability}
|
|
8525
8762
|
* - {@link http://en.wikipedia.org/wiki/Cross-site_request_forgery XSRF}
|
|
8526
8763
|
*
|
|
8527
8764
|
* Both server and the client must cooperate in order to eliminate these threats. Angular comes
|
|
@@ -8531,8 +8768,8 @@ function $HttpProvider() {
|
|
|
8531
8768
|
* ## JSON Vulnerability Protection
|
|
8532
8769
|
*
|
|
8533
8770
|
* A {@link http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx
|
|
8534
|
-
* JSON
|
|
8535
|
-
* {@link http://en.wikipedia.org/wiki/
|
|
8771
|
+
* JSON vulnerability} allows third party website to turn your JSON resource URL into
|
|
8772
|
+
* {@link http://en.wikipedia.org/wiki/JSONP JSONP} request under some conditions. To
|
|
8536
8773
|
* counter this your server can prefix all JSON requests with following string `")]}',\n"`.
|
|
8537
8774
|
* Angular will automatically strip the prefix before processing it as JSON.
|
|
8538
8775
|
*
|
|
@@ -8553,19 +8790,19 @@ function $HttpProvider() {
|
|
|
8553
8790
|
* ## Cross Site Request Forgery (XSRF) Protection
|
|
8554
8791
|
*
|
|
8555
8792
|
* {@link http://en.wikipedia.org/wiki/Cross-site_request_forgery XSRF} is a technique by which
|
|
8556
|
-
* an unauthorized site can gain your user's private data. Angular provides
|
|
8793
|
+
* an unauthorized site can gain your user's private data. Angular provides a mechanism
|
|
8557
8794
|
* to counter XSRF. When performing XHR requests, the $http service reads a token from a cookie
|
|
8558
8795
|
* called `XSRF-TOKEN` and sets it as the HTTP header `X-XSRF-TOKEN`. Since only JavaScript that
|
|
8559
8796
|
* runs on your domain could read the cookie, your server can be assured that the XHR came from
|
|
8560
8797
|
* JavaScript running on your domain.
|
|
8561
8798
|
*
|
|
8562
8799
|
* To take advantage of this, your server needs to set a token in a JavaScript readable session
|
|
8563
|
-
* cookie called `XSRF-TOKEN` on first HTTP GET request. On subsequent
|
|
8800
|
+
* cookie called `XSRF-TOKEN` on the first HTTP GET request. On subsequent XHR requests the
|
|
8564
8801
|
* server can verify that the cookie matches `X-XSRF-TOKEN` HTTP header, and therefore be sure
|
|
8565
|
-
* that only JavaScript running on your domain could have
|
|
8566
|
-
* unique for each user and must be verifiable by the server (to prevent the JavaScript making
|
|
8802
|
+
* that only JavaScript running on your domain could have sent the request. The token must be
|
|
8803
|
+
* unique for each user and must be verifiable by the server (to prevent the JavaScript from making
|
|
8567
8804
|
* up its own tokens). We recommend that the token is a digest of your site's authentication
|
|
8568
|
-
* cookie with {@link
|
|
8805
|
+
* cookie with a {@link https://en.wikipedia.org/wiki/Salt_(cryptography) salt} for added security.
|
|
8569
8806
|
*
|
|
8570
8807
|
*
|
|
8571
8808
|
* @param {object} config Object describing the request to be made and how it should be
|
|
@@ -8743,7 +8980,7 @@ function $HttpProvider() {
|
|
|
8743
8980
|
* @methodOf ng.$http
|
|
8744
8981
|
*
|
|
8745
8982
|
* @description
|
|
8746
|
-
* Shortcut method to perform `GET` request
|
|
8983
|
+
* Shortcut method to perform `GET` request.
|
|
8747
8984
|
*
|
|
8748
8985
|
* @param {string} url Relative or absolute URL specifying the destination of the request
|
|
8749
8986
|
* @param {Object=} config Optional configuration object
|
|
@@ -8756,7 +8993,7 @@ function $HttpProvider() {
|
|
|
8756
8993
|
* @methodOf ng.$http
|
|
8757
8994
|
*
|
|
8758
8995
|
* @description
|
|
8759
|
-
* Shortcut method to perform `DELETE` request
|
|
8996
|
+
* Shortcut method to perform `DELETE` request.
|
|
8760
8997
|
*
|
|
8761
8998
|
* @param {string} url Relative or absolute URL specifying the destination of the request
|
|
8762
8999
|
* @param {Object=} config Optional configuration object
|
|
@@ -8769,7 +9006,7 @@ function $HttpProvider() {
|
|
|
8769
9006
|
* @methodOf ng.$http
|
|
8770
9007
|
*
|
|
8771
9008
|
* @description
|
|
8772
|
-
* Shortcut method to perform `HEAD` request
|
|
9009
|
+
* Shortcut method to perform `HEAD` request.
|
|
8773
9010
|
*
|
|
8774
9011
|
* @param {string} url Relative or absolute URL specifying the destination of the request
|
|
8775
9012
|
* @param {Object=} config Optional configuration object
|
|
@@ -8782,7 +9019,7 @@ function $HttpProvider() {
|
|
|
8782
9019
|
* @methodOf ng.$http
|
|
8783
9020
|
*
|
|
8784
9021
|
* @description
|
|
8785
|
-
* Shortcut method to perform `JSONP` request
|
|
9022
|
+
* Shortcut method to perform `JSONP` request.
|
|
8786
9023
|
*
|
|
8787
9024
|
* @param {string} url Relative or absolute URL specifying the destination of the request.
|
|
8788
9025
|
* Should contain `JSON_CALLBACK` string.
|
|
@@ -8797,7 +9034,7 @@ function $HttpProvider() {
|
|
|
8797
9034
|
* @methodOf ng.$http
|
|
8798
9035
|
*
|
|
8799
9036
|
* @description
|
|
8800
|
-
* Shortcut method to perform `POST` request
|
|
9037
|
+
* Shortcut method to perform `POST` request.
|
|
8801
9038
|
*
|
|
8802
9039
|
* @param {string} url Relative or absolute URL specifying the destination of the request
|
|
8803
9040
|
* @param {*} data Request content
|
|
@@ -8811,7 +9048,7 @@ function $HttpProvider() {
|
|
|
8811
9048
|
* @methodOf ng.$http
|
|
8812
9049
|
*
|
|
8813
9050
|
* @description
|
|
8814
|
-
* Shortcut method to perform `PUT` request
|
|
9051
|
+
* Shortcut method to perform `PUT` request.
|
|
8815
9052
|
*
|
|
8816
9053
|
* @param {string} url Relative or absolute URL specifying the destination of the request
|
|
8817
9054
|
* @param {*} data Request content
|
|
@@ -8863,7 +9100,7 @@ function $HttpProvider() {
|
|
|
8863
9100
|
|
|
8864
9101
|
|
|
8865
9102
|
/**
|
|
8866
|
-
* Makes the request
|
|
9103
|
+
* Makes the request.
|
|
8867
9104
|
*
|
|
8868
9105
|
* !!! ACCESSES CLOSURE VARS:
|
|
8869
9106
|
* $httpBackend, $config, $log, $rootScope, defaultCache, $http.pendingRequests
|
|
@@ -8973,6 +9210,7 @@ function $HttpProvider() {
|
|
|
8973
9210
|
|
|
8974
9211
|
}];
|
|
8975
9212
|
}
|
|
9213
|
+
|
|
8976
9214
|
var XHR = window.XMLHttpRequest || function() {
|
|
8977
9215
|
try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); } catch (e1) {}
|
|
8978
9216
|
try { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); } catch (e2) {}
|
|
@@ -9040,8 +9278,30 @@ function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument,
|
|
|
9040
9278
|
// always async
|
|
9041
9279
|
xhr.onreadystatechange = function() {
|
|
9042
9280
|
if (xhr.readyState == 4) {
|
|
9043
|
-
|
|
9044
|
-
|
|
9281
|
+
var responseHeaders = xhr.getAllResponseHeaders();
|
|
9282
|
+
|
|
9283
|
+
// TODO(vojta): remove once Firefox 21 gets released.
|
|
9284
|
+
// begin: workaround to overcome Firefox CORS http response headers bug
|
|
9285
|
+
// https://bugzilla.mozilla.org/show_bug.cgi?id=608735
|
|
9286
|
+
// Firefox already patched in nightly. Should land in Firefox 21.
|
|
9287
|
+
|
|
9288
|
+
// CORS "simple response headers" http://www.w3.org/TR/cors/
|
|
9289
|
+
var value,
|
|
9290
|
+
simpleHeaders = ["Cache-Control", "Content-Language", "Content-Type",
|
|
9291
|
+
"Expires", "Last-Modified", "Pragma"];
|
|
9292
|
+
if (!responseHeaders) {
|
|
9293
|
+
responseHeaders = "";
|
|
9294
|
+
forEach(simpleHeaders, function (header) {
|
|
9295
|
+
var value = xhr.getResponseHeader(header);
|
|
9296
|
+
if (value) {
|
|
9297
|
+
responseHeaders += header + ": " + value + "\n";
|
|
9298
|
+
}
|
|
9299
|
+
});
|
|
9300
|
+
}
|
|
9301
|
+
// end of the workaround.
|
|
9302
|
+
|
|
9303
|
+
completeRequest(callback, status || xhr.status, xhr.responseText,
|
|
9304
|
+
responseHeaders);
|
|
9045
9305
|
}
|
|
9046
9306
|
};
|
|
9047
9307
|
|
|
@@ -9187,17 +9447,17 @@ function $TimeoutProvider() {
|
|
|
9187
9447
|
* block and delegates any exceptions to
|
|
9188
9448
|
* {@link ng.$exceptionHandler $exceptionHandler} service.
|
|
9189
9449
|
*
|
|
9190
|
-
* The return value of registering a timeout function is a promise which will be resolved when
|
|
9450
|
+
* The return value of registering a timeout function is a promise, which will be resolved when
|
|
9191
9451
|
* the timeout is reached and the timeout function is executed.
|
|
9192
9452
|
*
|
|
9193
|
-
* To cancel a
|
|
9453
|
+
* To cancel a timeout request, call `$timeout.cancel(promise)`.
|
|
9194
9454
|
*
|
|
9195
9455
|
* In tests you can use {@link ngMock.$timeout `$timeout.flush()`} to
|
|
9196
9456
|
* synchronously flush the queue of deferred functions.
|
|
9197
9457
|
*
|
|
9198
|
-
* @param {function()} fn A function,
|
|
9458
|
+
* @param {function()} fn A function, whose execution should be delayed.
|
|
9199
9459
|
* @param {number=} [delay=0] Delay in milliseconds.
|
|
9200
|
-
* @param {boolean=} [invokeApply=true] If set to false skips model dirty checking, otherwise
|
|
9460
|
+
* @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
|
|
9201
9461
|
* will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
|
|
9202
9462
|
* @returns {Promise} Promise that will be resolved when the timeout is reached. The value this
|
|
9203
9463
|
* promise will be resolved with is the return value of the `fn` function.
|
|
@@ -9237,7 +9497,7 @@ function $TimeoutProvider() {
|
|
|
9237
9497
|
* @methodOf ng.$timeout
|
|
9238
9498
|
*
|
|
9239
9499
|
* @description
|
|
9240
|
-
* Cancels a task associated with the `promise`. As a result of this the promise will be
|
|
9500
|
+
* Cancels a task associated with the `promise`. As a result of this, the promise will be
|
|
9241
9501
|
* resolved with a rejection.
|
|
9242
9502
|
*
|
|
9243
9503
|
* @param {Promise=} promise Promise returned by the `$timeout` function.
|
|
@@ -9263,7 +9523,7 @@ function $TimeoutProvider() {
|
|
|
9263
9523
|
*
|
|
9264
9524
|
* Filters are just functions which transform input to an output. However filters need to be Dependency Injected. To
|
|
9265
9525
|
* achieve this a filter definition consists of a factory function which is annotated with dependencies and is
|
|
9266
|
-
* responsible for creating a
|
|
9526
|
+
* responsible for creating a filter function.
|
|
9267
9527
|
*
|
|
9268
9528
|
* <pre>
|
|
9269
9529
|
* // Filter registration
|
|
@@ -9325,7 +9585,7 @@ function $TimeoutProvider() {
|
|
|
9325
9585
|
*
|
|
9326
9586
|
* The general syntax in templates is as follows:
|
|
9327
9587
|
*
|
|
9328
|
-
* {{ expression | [
|
|
9588
|
+
* {{ expression [| filter_name[:parameter_value] ... ] }}
|
|
9329
9589
|
*
|
|
9330
9590
|
* @param {String} name Name of the filter function to retrieve
|
|
9331
9591
|
* @return {Function} the filter function
|
|
@@ -9401,22 +9661,22 @@ function $FilterProvider($provide) {
|
|
|
9401
9661
|
|
|
9402
9662
|
Search: <input ng-model="searchText">
|
|
9403
9663
|
<table id="searchTextResults">
|
|
9404
|
-
<tr><th>Name</th><th>Phone</th
|
|
9664
|
+
<tr><th>Name</th><th>Phone</th></tr>
|
|
9405
9665
|
<tr ng-repeat="friend in friends | filter:searchText">
|
|
9406
9666
|
<td>{{friend.name}}</td>
|
|
9407
9667
|
<td>{{friend.phone}}</td>
|
|
9408
|
-
|
|
9668
|
+
</tr>
|
|
9409
9669
|
</table>
|
|
9410
9670
|
<hr>
|
|
9411
9671
|
Any: <input ng-model="search.$"> <br>
|
|
9412
9672
|
Name only <input ng-model="search.name"><br>
|
|
9413
|
-
Phone only <input ng-model="search.phone"
|
|
9673
|
+
Phone only <input ng-model="search.phone"><br>
|
|
9414
9674
|
<table id="searchObjResults">
|
|
9415
|
-
<tr><th>Name</th><th>Phone</th
|
|
9675
|
+
<tr><th>Name</th><th>Phone</th></tr>
|
|
9416
9676
|
<tr ng-repeat="friend in friends | filter:search">
|
|
9417
9677
|
<td>{{friend.name}}</td>
|
|
9418
9678
|
<td>{{friend.phone}}</td>
|
|
9419
|
-
|
|
9679
|
+
</tr>
|
|
9420
9680
|
</table>
|
|
9421
9681
|
</doc:source>
|
|
9422
9682
|
<doc:scenario>
|
|
@@ -9440,7 +9700,7 @@ function $FilterProvider($provide) {
|
|
|
9440
9700
|
*/
|
|
9441
9701
|
function filterFilter() {
|
|
9442
9702
|
return function(array, expression) {
|
|
9443
|
-
if (!(array
|
|
9703
|
+
if (!isArray(array)) return array;
|
|
9444
9704
|
var predicates = [];
|
|
9445
9705
|
predicates.check = function(value) {
|
|
9446
9706
|
for (var j = 0; j < predicates.length; j++) {
|
|
@@ -9689,7 +9949,7 @@ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
|
|
|
9689
9949
|
fraction += '0';
|
|
9690
9950
|
}
|
|
9691
9951
|
|
|
9692
|
-
if (fractionSize) formatedText += decimalSep + fraction.substr(0, fractionSize);
|
|
9952
|
+
if (fractionSize && fractionSize !== "0") formatedText += decimalSep + fraction.substr(0, fractionSize);
|
|
9693
9953
|
}
|
|
9694
9954
|
|
|
9695
9955
|
parts.push(isNegative ? pattern.negPre : pattern.posPre);
|
|
@@ -9713,6 +9973,7 @@ function padNumber(num, digits, trim) {
|
|
|
9713
9973
|
|
|
9714
9974
|
|
|
9715
9975
|
function dateGetter(name, size, offset, trim) {
|
|
9976
|
+
offset = offset || 0;
|
|
9716
9977
|
return function(date) {
|
|
9717
9978
|
var value = date['get' + name]();
|
|
9718
9979
|
if (offset > 0 || value > -offset)
|
|
@@ -9732,8 +9993,13 @@ function dateStrGetter(name, shortForm) {
|
|
|
9732
9993
|
}
|
|
9733
9994
|
|
|
9734
9995
|
function timeZoneGetter(date) {
|
|
9735
|
-
var
|
|
9736
|
-
|
|
9996
|
+
var zone = -1 * date.getTimezoneOffset();
|
|
9997
|
+
var paddedZone = (zone >= 0) ? "+" : "";
|
|
9998
|
+
|
|
9999
|
+
paddedZone += padNumber(Math[zone > 0 ? 'floor' : 'ceil'](zone / 60), 2) +
|
|
10000
|
+
padNumber(Math.abs(zone % 60), 2);
|
|
10001
|
+
|
|
10002
|
+
return paddedZone;
|
|
9737
10003
|
}
|
|
9738
10004
|
|
|
9739
10005
|
function ampmGetter(date, formats) {
|
|
@@ -9797,7 +10063,7 @@ var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+
|
|
|
9797
10063
|
* * `'ss'`: Second in minute, padded (00-59)
|
|
9798
10064
|
* * `'s'`: Second in minute (0-59)
|
|
9799
10065
|
* * `'a'`: am/pm marker
|
|
9800
|
-
* * `'Z'`: 4 digit (+sign) representation of the timezone offset (-1200
|
|
10066
|
+
* * `'Z'`: 4 digit (+sign) representation of the timezone offset (-1200-+1200)
|
|
9801
10067
|
*
|
|
9802
10068
|
* `format` string can also be one of the following predefined
|
|
9803
10069
|
* {@link guide/i18n localizable formats}:
|
|
@@ -9818,8 +10084,9 @@ var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+
|
|
|
9818
10084
|
* (e.g. `"h o''clock"`).
|
|
9819
10085
|
*
|
|
9820
10086
|
* @param {(Date|number|string)} date Date to format either as Date object, milliseconds (string or
|
|
9821
|
-
* number) or various ISO 8601 datetime string formats (e.g. yyyy-MM-ddTHH:mm:ss.SSSZ and
|
|
9822
|
-
* shorter versions like yyyy-MM-ddTHH:mmZ, yyyy-MM-dd or yyyyMMddTHHmmssZ).
|
|
10087
|
+
* number) or various ISO 8601 datetime string formats (e.g. yyyy-MM-ddTHH:mm:ss.SSSZ and its
|
|
10088
|
+
* shorter versions like yyyy-MM-ddTHH:mmZ, yyyy-MM-dd or yyyyMMddTHHmmssZ). If no timezone is
|
|
10089
|
+
* specified in the string input, the time is considered to be in the local timezone.
|
|
9823
10090
|
* @param {string=} format Formatting rules (see Description). If not specified,
|
|
9824
10091
|
* `mediumDate` is used.
|
|
9825
10092
|
* @returns {string} Formatted string or the input if input is not recognized as date/millis.
|
|
@@ -9839,7 +10106,7 @@ var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+
|
|
|
9839
10106
|
expect(binding("1288323623006 | date:'medium'")).
|
|
9840
10107
|
toMatch(/Oct 2\d, 2010 \d{1,2}:\d{2}:\d{2} (AM|PM)/);
|
|
9841
10108
|
expect(binding("1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'")).
|
|
9842
|
-
toMatch(/2010\-10\-2\d \d{2}:\d{2}:\d{2}
|
|
10109
|
+
toMatch(/2010\-10\-2\d \d{2}:\d{2}:\d{2} (\-|\+)?\d{4}/);
|
|
9843
10110
|
expect(binding("'1288323623006' | date:'MM/dd/yyyy @ h:mma'")).
|
|
9844
10111
|
toMatch(/10\/2\d\/2010 @ \d{1,2}:\d{2}(AM|PM)/);
|
|
9845
10112
|
});
|
|
@@ -10108,12 +10375,12 @@ function limitToFilter(){
|
|
|
10108
10375
|
(<a href ng-click="predicate = '-name'; reverse=false">^</a>)</th>
|
|
10109
10376
|
<th><a href="" ng-click="predicate = 'phone'; reverse=!reverse">Phone Number</a></th>
|
|
10110
10377
|
<th><a href="" ng-click="predicate = 'age'; reverse=!reverse">Age</a></th>
|
|
10111
|
-
|
|
10378
|
+
</tr>
|
|
10112
10379
|
<tr ng-repeat="friend in friends | orderBy:predicate:reverse">
|
|
10113
10380
|
<td>{{friend.name}}</td>
|
|
10114
10381
|
<td>{{friend.phone}}</td>
|
|
10115
10382
|
<td>{{friend.age}}</td>
|
|
10116
|
-
|
|
10383
|
+
</tr>
|
|
10117
10384
|
</table>
|
|
10118
10385
|
</div>
|
|
10119
10386
|
</doc:source>
|
|
@@ -10145,7 +10412,7 @@ function limitToFilter(){
|
|
|
10145
10412
|
orderByFilter.$inject = ['$parse'];
|
|
10146
10413
|
function orderByFilter($parse){
|
|
10147
10414
|
return function(array, sortPredicate, reverseOrder) {
|
|
10148
|
-
if (!(array
|
|
10415
|
+
if (!isArray(array)) return array;
|
|
10149
10416
|
if (!sortPredicate) return array;
|
|
10150
10417
|
sortPredicate = isArray(sortPredicate) ? sortPredicate: [sortPredicate];
|
|
10151
10418
|
sortPredicate = map(sortPredicate, function(predicate){
|
|
@@ -10213,15 +10480,25 @@ function ngDirective(directive) {
|
|
|
10213
10480
|
*
|
|
10214
10481
|
* The reasoning for this change is to allow easy creation of action links with `ngClick` directive
|
|
10215
10482
|
* without changing the location or causing page reloads, e.g.:
|
|
10216
|
-
*
|
|
10483
|
+
* `<a href="" ng-click="model.$save()">Save</a>`
|
|
10217
10484
|
*/
|
|
10218
10485
|
var htmlAnchorDirective = valueFn({
|
|
10219
10486
|
restrict: 'E',
|
|
10220
10487
|
compile: function(element, attr) {
|
|
10221
|
-
|
|
10222
|
-
|
|
10223
|
-
|
|
10224
|
-
|
|
10488
|
+
|
|
10489
|
+
if (msie <= 8) {
|
|
10490
|
+
|
|
10491
|
+
// turn <a href ng-click="..">link</a> into a stylable link in IE
|
|
10492
|
+
// but only if it doesn't have name attribute, in which case it's an anchor
|
|
10493
|
+
if (!attr.href && !attr.name) {
|
|
10494
|
+
attr.$set('href', '');
|
|
10495
|
+
}
|
|
10496
|
+
|
|
10497
|
+
// add a comment node to anchors to workaround IE bug that causes element content to be reset
|
|
10498
|
+
// to new attribute content if attribute is updated with value containing @ and element also
|
|
10499
|
+
// contains value with @
|
|
10500
|
+
// see issue #1949
|
|
10501
|
+
element.append(document.createComment('IE fix'));
|
|
10225
10502
|
}
|
|
10226
10503
|
|
|
10227
10504
|
return function(scope, element) {
|
|
@@ -10229,7 +10506,6 @@ var htmlAnchorDirective = valueFn({
|
|
|
10229
10506
|
// if we have no href url, then don't navigate anywhere.
|
|
10230
10507
|
if (!element.attr('href')) {
|
|
10231
10508
|
event.preventDefault();
|
|
10232
|
-
return false; // Needed for opera
|
|
10233
10509
|
}
|
|
10234
10510
|
});
|
|
10235
10511
|
}
|
|
@@ -10302,7 +10578,7 @@ var htmlAnchorDirective = valueFn({
|
|
|
10302
10578
|
it('should execute ng-click but not reload when no href but name specified', function() {
|
|
10303
10579
|
element('#link-5').click();
|
|
10304
10580
|
expect(input('value').val()).toEqual('5');
|
|
10305
|
-
expect(element('#link-5').attr('href')).toBe(
|
|
10581
|
+
expect(element('#link-5').attr('href')).toBe(undefined);
|
|
10306
10582
|
});
|
|
10307
10583
|
|
|
10308
10584
|
it('should only change url when only ng-href', function() {
|
|
@@ -10545,8 +10821,9 @@ forEach(['src', 'href'], function(attrName) {
|
|
|
10545
10821
|
|
|
10546
10822
|
// on IE, if "ng:src" directive declaration is used and "src" attribute doesn't exist
|
|
10547
10823
|
// then calling element.setAttribute('src', 'foo') doesn't do anything, so we need
|
|
10548
|
-
// to set the property as well to achieve the desired effect
|
|
10549
|
-
|
|
10824
|
+
// to set the property as well to achieve the desired effect.
|
|
10825
|
+
// we use attr[attrName] value since $set can sanitize the url.
|
|
10826
|
+
if (msie) element.prop(attrName, attr[attrName]);
|
|
10550
10827
|
});
|
|
10551
10828
|
}
|
|
10552
10829
|
};
|
|
@@ -10566,13 +10843,13 @@ var nullFormCtrl = {
|
|
|
10566
10843
|
*
|
|
10567
10844
|
* @property {boolean} $pristine True if user has not interacted with the form yet.
|
|
10568
10845
|
* @property {boolean} $dirty True if user has already interacted with the form.
|
|
10569
|
-
* @property {boolean} $valid True if all of the
|
|
10846
|
+
* @property {boolean} $valid True if all of the containing forms and controls are valid.
|
|
10570
10847
|
* @property {boolean} $invalid True if at least one containing control or form is invalid.
|
|
10571
10848
|
*
|
|
10572
10849
|
* @property {Object} $error Is an object hash, containing references to all invalid controls or
|
|
10573
10850
|
* forms, where:
|
|
10574
10851
|
*
|
|
10575
|
-
* - keys are validation tokens (error names) — such as `
|
|
10852
|
+
* - keys are validation tokens (error names) — such as `required`, `url` or `email`),
|
|
10576
10853
|
* - values are arrays of controls or forms that are invalid with given error.
|
|
10577
10854
|
*
|
|
10578
10855
|
* @description
|
|
@@ -10685,7 +10962,7 @@ function FormController(element, attrs) {
|
|
|
10685
10962
|
* does not allow nesting of form elements. It is useful to nest forms, for example if the validity of a
|
|
10686
10963
|
* sub-group of controls needs to be determined.
|
|
10687
10964
|
*
|
|
10688
|
-
* @param {string=} ngForm
|
|
10965
|
+
* @param {string=} name|ngForm Name of the form. If specified, the form controller will be published into
|
|
10689
10966
|
* related scope, under this name.
|
|
10690
10967
|
*
|
|
10691
10968
|
*/
|
|
@@ -10758,12 +11035,12 @@ function FormController(element, attrs) {
|
|
|
10758
11035
|
</script>
|
|
10759
11036
|
<form name="myForm" ng-controller="Ctrl">
|
|
10760
11037
|
userType: <input name="input" ng-model="userType" required>
|
|
10761
|
-
<span class="error" ng-show="myForm.input.$error.
|
|
11038
|
+
<span class="error" ng-show="myForm.input.$error.required">Required!</span><br>
|
|
10762
11039
|
<tt>userType = {{userType}}</tt><br>
|
|
10763
11040
|
<tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br>
|
|
10764
11041
|
<tt>myForm.input.$error = {{myForm.input.$error}}</tt><br>
|
|
10765
11042
|
<tt>myForm.$valid = {{myForm.$valid}}</tt><br>
|
|
10766
|
-
<tt>myForm.$error.
|
|
11043
|
+
<tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br>
|
|
10767
11044
|
</form>
|
|
10768
11045
|
</doc:source>
|
|
10769
11046
|
<doc:scenario>
|
|
@@ -10925,8 +11202,8 @@ var inputType = {
|
|
|
10925
11202
|
*
|
|
10926
11203
|
* @param {string} ngModel Assignable angular expression to data-bind to.
|
|
10927
11204
|
* @param {string=} name Property name of the form under which the control is published.
|
|
10928
|
-
* @param {string=} min Sets the `min` validation error key if the value entered is less
|
|
10929
|
-
* @param {string=} max Sets the `max` validation error key if the value entered is greater
|
|
11205
|
+
* @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
|
|
11206
|
+
* @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
|
|
10930
11207
|
* @param {string=} required Sets `required` validation error key if the value is not entered.
|
|
10931
11208
|
* @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
|
|
10932
11209
|
* the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
|
|
@@ -11238,6 +11515,15 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
|
|
|
11238
11515
|
} else {
|
|
11239
11516
|
var timeout;
|
|
11240
11517
|
|
|
11518
|
+
var deferListener = function() {
|
|
11519
|
+
if (!timeout) {
|
|
11520
|
+
timeout = $browser.defer(function() {
|
|
11521
|
+
listener();
|
|
11522
|
+
timeout = null;
|
|
11523
|
+
});
|
|
11524
|
+
}
|
|
11525
|
+
};
|
|
11526
|
+
|
|
11241
11527
|
element.bind('keydown', function(event) {
|
|
11242
11528
|
var key = event.keyCode;
|
|
11243
11529
|
|
|
@@ -11245,16 +11531,16 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
|
|
|
11245
11531
|
// command modifiers arrows
|
|
11246
11532
|
if (key === 91 || (15 < key && key < 19) || (37 <= key && key <= 40)) return;
|
|
11247
11533
|
|
|
11248
|
-
|
|
11249
|
-
timeout = $browser.defer(function() {
|
|
11250
|
-
listener();
|
|
11251
|
-
timeout = null;
|
|
11252
|
-
});
|
|
11253
|
-
}
|
|
11534
|
+
deferListener();
|
|
11254
11535
|
});
|
|
11255
11536
|
|
|
11256
11537
|
// if user paste into input using mouse, we need "change" event to catch it
|
|
11257
11538
|
element.bind('change', listener);
|
|
11539
|
+
|
|
11540
|
+
// if user modifies input value using context menu in IE, we need "paste" and "cut" events to catch it
|
|
11541
|
+
if ($sniffer.hasEvent('paste')) {
|
|
11542
|
+
element.bind('paste cut', deferListener);
|
|
11543
|
+
}
|
|
11258
11544
|
}
|
|
11259
11545
|
|
|
11260
11546
|
|
|
@@ -11553,7 +11839,7 @@ function checkboxInputType(scope, element, attr, ctrl) {
|
|
|
11553
11839
|
<tt>myForm.userName.$valid = {{myForm.userName.$valid}}</tt><br>
|
|
11554
11840
|
<tt>myForm.userName.$error = {{myForm.userName.$error}}</tt><br>
|
|
11555
11841
|
<tt>myForm.lastName.$valid = {{myForm.lastName.$valid}}</tt><br>
|
|
11556
|
-
<tt>myForm.
|
|
11842
|
+
<tt>myForm.lastName.$error = {{myForm.lastName.$error}}</tt><br>
|
|
11557
11843
|
<tt>myForm.$valid = {{myForm.$valid}}</tt><br>
|
|
11558
11844
|
<tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br>
|
|
11559
11845
|
<tt>myForm.$error.minlength = {{!!myForm.$error.minlength}}</tt><br>
|
|
@@ -11816,7 +12102,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
|
|
|
11816
12102
|
* For example {@link ng.directive:input input} or
|
|
11817
12103
|
* {@link ng.directive:select select} directives call it.
|
|
11818
12104
|
*
|
|
11819
|
-
* It internally calls all `
|
|
12105
|
+
* It internally calls all `parsers` and if resulted value is valid, updates the model and
|
|
11820
12106
|
* calls all registered change listeners.
|
|
11821
12107
|
*
|
|
11822
12108
|
* @param {string} value Value from the view.
|
|
@@ -12122,7 +12408,7 @@ var ngValueDirective = function() {
|
|
|
12122
12408
|
* Typically, you don't use `ngBind` directly, but instead you use the double curly markup like
|
|
12123
12409
|
* `{{ expression }}` which is similar but less verbose.
|
|
12124
12410
|
*
|
|
12125
|
-
*
|
|
12411
|
+
* One scenario in which the use of `ngBind` is preferred over `{{ expression }}` binding is when
|
|
12126
12412
|
* it's desirable to put bindings into template that is momentarily displayed by the browser in its
|
|
12127
12413
|
* raw state before Angular compiles it. Since `ngBind` is an element attribute, it makes the
|
|
12128
12414
|
* bindings invisible to the user while the page is loading.
|
|
@@ -12251,6 +12537,7 @@ var ngBindHtmlUnsafeDirective = [function() {
|
|
|
12251
12537
|
function classDirective(name, selector) {
|
|
12252
12538
|
name = 'ngClass' + name;
|
|
12253
12539
|
return ngDirective(function(scope, element, attr) {
|
|
12540
|
+
var oldVal = undefined;
|
|
12254
12541
|
|
|
12255
12542
|
scope.$watch(attr[name], ngClassWatchAction, true);
|
|
12256
12543
|
|
|
@@ -12262,9 +12549,9 @@ function classDirective(name, selector) {
|
|
|
12262
12549
|
|
|
12263
12550
|
if (name !== 'ngClass') {
|
|
12264
12551
|
scope.$watch('$index', function($index, old$index) {
|
|
12265
|
-
var mod = $index
|
|
12266
|
-
if (mod !== old$index
|
|
12267
|
-
if (mod
|
|
12552
|
+
var mod = $index & 1;
|
|
12553
|
+
if (mod !== old$index & 1) {
|
|
12554
|
+
if (mod === selector) {
|
|
12268
12555
|
addClass(scope.$eval(attr[name]));
|
|
12269
12556
|
} else {
|
|
12270
12557
|
removeClass(scope.$eval(attr[name]));
|
|
@@ -12274,13 +12561,14 @@ function classDirective(name, selector) {
|
|
|
12274
12561
|
}
|
|
12275
12562
|
|
|
12276
12563
|
|
|
12277
|
-
function ngClassWatchAction(newVal
|
|
12564
|
+
function ngClassWatchAction(newVal) {
|
|
12278
12565
|
if (selector === true || scope.$index % 2 === selector) {
|
|
12279
|
-
if (oldVal && (newVal
|
|
12566
|
+
if (oldVal && !equals(newVal,oldVal)) {
|
|
12280
12567
|
removeClass(oldVal);
|
|
12281
12568
|
}
|
|
12282
12569
|
addClass(newVal);
|
|
12283
12570
|
}
|
|
12571
|
+
oldVal = copy(newVal);
|
|
12284
12572
|
}
|
|
12285
12573
|
|
|
12286
12574
|
|
|
@@ -12313,7 +12601,7 @@ function classDirective(name, selector) {
|
|
|
12313
12601
|
*
|
|
12314
12602
|
* The directive won't add duplicate classes if a particular class was already set.
|
|
12315
12603
|
*
|
|
12316
|
-
* When the expression changes, the previously added classes are removed and only then the
|
|
12604
|
+
* When the expression changes, the previously added classes are removed and only then the
|
|
12317
12605
|
* new classes are added.
|
|
12318
12606
|
*
|
|
12319
12607
|
* @element ANY
|
|
@@ -12406,7 +12694,7 @@ var ngClassOddDirective = classDirective('Odd', 0);
|
|
|
12406
12694
|
* @name ng.directive:ngClassEven
|
|
12407
12695
|
*
|
|
12408
12696
|
* @description
|
|
12409
|
-
* The `ngClassOdd` and `ngClassEven`
|
|
12697
|
+
* The `ngClassOdd` and `ngClassEven` directives work exactly as
|
|
12410
12698
|
* {@link ng.directive:ngClass ngClass}, except it works in
|
|
12411
12699
|
* conjunction with `ngRepeat` and takes affect only on odd (even) rows.
|
|
12412
12700
|
*
|
|
@@ -12464,7 +12752,7 @@ var ngClassEvenDirective = classDirective('Even', 1);
|
|
|
12464
12752
|
* `angular.min.js` files. Following is the css rule:
|
|
12465
12753
|
*
|
|
12466
12754
|
* <pre>
|
|
12467
|
-
* [ng\:cloak], [ng-cloak], .ng-cloak {
|
|
12755
|
+
* [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
|
|
12468
12756
|
* display: none;
|
|
12469
12757
|
* }
|
|
12470
12758
|
* </pre>
|
|
@@ -12523,8 +12811,7 @@ var ngCloakDirective = ngDirective({
|
|
|
12523
12811
|
* * Controller — The `ngController` directive specifies a Controller class; the class has
|
|
12524
12812
|
* methods that typically express the business logic behind the application.
|
|
12525
12813
|
*
|
|
12526
|
-
* Note that an alternative way to define controllers is via the
|
|
12527
|
-
* service.
|
|
12814
|
+
* Note that an alternative way to define controllers is via the {@link ng.$route $route} service.
|
|
12528
12815
|
*
|
|
12529
12816
|
* @element ANY
|
|
12530
12817
|
* @scope
|
|
@@ -12615,16 +12902,32 @@ var ngControllerDirective = [function() {
|
|
|
12615
12902
|
* @name ng.directive:ngCsp
|
|
12616
12903
|
* @priority 1000
|
|
12617
12904
|
*
|
|
12905
|
+
* @element html
|
|
12618
12906
|
* @description
|
|
12619
12907
|
* Enables [CSP (Content Security Policy)](https://developer.mozilla.org/en/Security/CSP) support.
|
|
12620
|
-
*
|
|
12621
|
-
*
|
|
12622
|
-
*
|
|
12623
|
-
*
|
|
12624
|
-
*
|
|
12625
|
-
*
|
|
12626
|
-
*
|
|
12627
|
-
*
|
|
12908
|
+
*
|
|
12909
|
+
* This is necessary when developing things like Google Chrome Extensions.
|
|
12910
|
+
*
|
|
12911
|
+
* CSP forbids apps to use `eval` or `Function(string)` generated functions (among other things).
|
|
12912
|
+
* For us to be compatible, we just need to implement the "getterFn" in $parse without violating
|
|
12913
|
+
* any of these restrictions.
|
|
12914
|
+
*
|
|
12915
|
+
* AngularJS uses `Function(string)` generated functions as a speed optimization. By applying `ngCsp`
|
|
12916
|
+
* it is be possible to opt into the CSP compatible mode. When this mode is on AngularJS will
|
|
12917
|
+
* evaluate all expressions up to 30% slower than in non-CSP mode, but no security violations will
|
|
12918
|
+
* be raised.
|
|
12919
|
+
*
|
|
12920
|
+
* In order to use this feature put `ngCsp` directive on the root element of the application.
|
|
12921
|
+
*
|
|
12922
|
+
* @example
|
|
12923
|
+
* This example shows how to apply the `ngCsp` directive to the `html` tag.
|
|
12924
|
+
<pre>
|
|
12925
|
+
<!doctype html>
|
|
12926
|
+
<html ng-app ng-csp>
|
|
12927
|
+
...
|
|
12928
|
+
...
|
|
12929
|
+
</html>
|
|
12930
|
+
</pre>
|
|
12628
12931
|
*/
|
|
12629
12932
|
|
|
12630
12933
|
var ngCspDirective = ['$sniffer', function($sniffer) {
|
|
@@ -13249,7 +13552,7 @@ var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interp
|
|
|
13249
13552
|
if (!isNaN(value)) {
|
|
13250
13553
|
//if explicit number rule such as 1, 2, 3... is defined, just use it. Otherwise,
|
|
13251
13554
|
//check it against pluralization rules in $locale service
|
|
13252
|
-
if (!whens
|
|
13555
|
+
if (!(value in whens)) value = $locale.pluralCat(value - offset);
|
|
13253
13556
|
return whensExpFns[value](scope, element, true);
|
|
13254
13557
|
} else {
|
|
13255
13558
|
return '';
|
|
@@ -13353,14 +13656,17 @@ var ngRepeatDirective = ngDirective({
|
|
|
13353
13656
|
scope.$watch(function ngRepeatWatch(scope){
|
|
13354
13657
|
var index, length,
|
|
13355
13658
|
collection = scope.$eval(rhs),
|
|
13356
|
-
|
|
13357
|
-
childScope,
|
|
13659
|
+
cursor = iterStartElement, // current position of the node
|
|
13358
13660
|
// Same as lastOrder but it has the current state. It will become the
|
|
13359
13661
|
// lastOrder on the next iteration.
|
|
13360
13662
|
nextOrder = new HashQueueMap(),
|
|
13663
|
+
arrayBound,
|
|
13664
|
+
childScope,
|
|
13361
13665
|
key, value, // key/value of iteration
|
|
13362
|
-
array,
|
|
13363
|
-
|
|
13666
|
+
array,
|
|
13667
|
+
last; // last object information {scope, element, index}
|
|
13668
|
+
|
|
13669
|
+
|
|
13364
13670
|
|
|
13365
13671
|
if (!isArray(collection)) {
|
|
13366
13672
|
// if object, extract keys, sort them and use to determine order of iteration over obj props
|
|
@@ -13375,6 +13681,8 @@ var ngRepeatDirective = ngDirective({
|
|
|
13375
13681
|
array = collection || [];
|
|
13376
13682
|
}
|
|
13377
13683
|
|
|
13684
|
+
arrayBound = array.length-1;
|
|
13685
|
+
|
|
13378
13686
|
// we are not using forEach for perf reasons (trying to avoid #call)
|
|
13379
13687
|
for (index = 0, length = array.length; index < length; index++) {
|
|
13380
13688
|
key = (collection === array) ? index : array[index];
|
|
@@ -13410,7 +13718,7 @@ var ngRepeatDirective = ngDirective({
|
|
|
13410
13718
|
childScope.$index = index;
|
|
13411
13719
|
|
|
13412
13720
|
childScope.$first = (index === 0);
|
|
13413
|
-
childScope.$last = (index ===
|
|
13721
|
+
childScope.$last = (index === arrayBound);
|
|
13414
13722
|
childScope.$middle = !(childScope.$first || childScope.$last);
|
|
13415
13723
|
|
|
13416
13724
|
if (!last) {
|
|
@@ -13577,11 +13885,13 @@ var ngStyleDirective = ngDirective(function(scope, element, attr) {
|
|
|
13577
13885
|
* @description
|
|
13578
13886
|
* Conditionally change the DOM structure.
|
|
13579
13887
|
*
|
|
13580
|
-
* @
|
|
13581
|
-
* <ANY ng-switch
|
|
13888
|
+
* @usage
|
|
13889
|
+
* <ANY ng-switch="expression">
|
|
13890
|
+
* <ANY ng-switch-when="matchValue1">...</ANY>
|
|
13582
13891
|
* <ANY ng-switch-when="matchValue2">...</ANY>
|
|
13583
13892
|
* ...
|
|
13584
13893
|
* <ANY ng-switch-default>...</ANY>
|
|
13894
|
+
* </ANY>
|
|
13585
13895
|
*
|
|
13586
13896
|
* @scope
|
|
13587
13897
|
* @param {*} ngSwitch|on expression to match against <tt>ng-switch-when</tt>.
|
|
@@ -13631,52 +13941,54 @@ var ngStyleDirective = ngDirective(function(scope, element, attr) {
|
|
|
13631
13941
|
var NG_SWITCH = 'ng-switch';
|
|
13632
13942
|
var ngSwitchDirective = valueFn({
|
|
13633
13943
|
restrict: 'EA',
|
|
13634
|
-
|
|
13944
|
+
require: 'ngSwitch',
|
|
13945
|
+
// asks for $scope to fool the BC controller module
|
|
13946
|
+
controller: ['$scope', function ngSwitchController() {
|
|
13947
|
+
this.cases = {};
|
|
13948
|
+
}],
|
|
13949
|
+
link: function(scope, element, attr, ctrl) {
|
|
13635
13950
|
var watchExpr = attr.ngSwitch || attr.on,
|
|
13636
|
-
|
|
13637
|
-
|
|
13638
|
-
|
|
13639
|
-
|
|
13640
|
-
|
|
13641
|
-
|
|
13642
|
-
|
|
13643
|
-
|
|
13644
|
-
|
|
13645
|
-
|
|
13646
|
-
|
|
13647
|
-
|
|
13648
|
-
|
|
13649
|
-
|
|
13650
|
-
|
|
13651
|
-
|
|
13652
|
-
|
|
13653
|
-
|
|
13654
|
-
|
|
13655
|
-
element.append(caseElement);
|
|
13656
|
-
});
|
|
13657
|
-
}
|
|
13658
|
-
});
|
|
13659
|
-
};
|
|
13951
|
+
selectedTransclude,
|
|
13952
|
+
selectedElement,
|
|
13953
|
+
selectedScope;
|
|
13954
|
+
|
|
13955
|
+
scope.$watch(watchExpr, function ngSwitchWatchAction(value) {
|
|
13956
|
+
if (selectedElement) {
|
|
13957
|
+
selectedScope.$destroy();
|
|
13958
|
+
selectedElement.remove();
|
|
13959
|
+
selectedElement = selectedScope = null;
|
|
13960
|
+
}
|
|
13961
|
+
if ((selectedTransclude = ctrl.cases['!' + value] || ctrl.cases['?'])) {
|
|
13962
|
+
scope.$eval(attr.change);
|
|
13963
|
+
selectedScope = scope.$new();
|
|
13964
|
+
selectedTransclude(selectedScope, function(caseElement) {
|
|
13965
|
+
selectedElement = caseElement;
|
|
13966
|
+
element.append(caseElement);
|
|
13967
|
+
});
|
|
13968
|
+
}
|
|
13969
|
+
});
|
|
13660
13970
|
}
|
|
13661
13971
|
});
|
|
13662
13972
|
|
|
13663
13973
|
var ngSwitchWhenDirective = ngDirective({
|
|
13664
13974
|
transclude: 'element',
|
|
13665
13975
|
priority: 500,
|
|
13976
|
+
require: '^ngSwitch',
|
|
13666
13977
|
compile: function(element, attrs, transclude) {
|
|
13667
|
-
|
|
13668
|
-
|
|
13669
|
-
|
|
13978
|
+
return function(scope, element, attr, ctrl) {
|
|
13979
|
+
ctrl.cases['!' + attrs.ngSwitchWhen] = transclude;
|
|
13980
|
+
};
|
|
13670
13981
|
}
|
|
13671
13982
|
});
|
|
13672
13983
|
|
|
13673
13984
|
var ngSwitchDefaultDirective = ngDirective({
|
|
13674
13985
|
transclude: 'element',
|
|
13675
13986
|
priority: 500,
|
|
13987
|
+
require: '^ngSwitch',
|
|
13676
13988
|
compile: function(element, attrs, transclude) {
|
|
13677
|
-
|
|
13678
|
-
|
|
13679
|
-
|
|
13989
|
+
return function(scope, element, attr, ctrl) {
|
|
13990
|
+
ctrl.cases['?'] = transclude;
|
|
13991
|
+
};
|
|
13680
13992
|
}
|
|
13681
13993
|
});
|
|
13682
13994
|
|
|
@@ -13765,7 +14077,7 @@ var ngTranscludeDirective = ngDirective({
|
|
|
13765
14077
|
<hr />
|
|
13766
14078
|
|
|
13767
14079
|
<pre>$location.path() = {{$location.path()}}</pre>
|
|
13768
|
-
<pre>$route.current.
|
|
14080
|
+
<pre>$route.current.templateUrl = {{$route.current.templateUrl}}</pre>
|
|
13769
14081
|
<pre>$route.current.params = {{$route.current.params}}</pre>
|
|
13770
14082
|
<pre>$route.current.scope.name = {{$route.current.scope.name}}</pre>
|
|
13771
14083
|
<pre>$routeParams = {{$routeParams}}</pre>
|
|
@@ -13884,7 +14196,7 @@ var ngViewDirective = ['$http', '$templateCache', '$route', '$anchorScroll', '$c
|
|
|
13884
14196
|
if (current.controller) {
|
|
13885
14197
|
locals.$scope = lastScope;
|
|
13886
14198
|
controller = $controller(current.controller, locals);
|
|
13887
|
-
element.
|
|
14199
|
+
element.children().data('$ngControllerController', controller);
|
|
13888
14200
|
}
|
|
13889
14201
|
|
|
13890
14202
|
link(lastScope);
|
|
@@ -13973,7 +14285,8 @@ var scriptDirective = ['$templateCache', function($templateCache) {
|
|
|
13973
14285
|
* `select` model to be bound to a non-string value. This is because an option element can currently
|
|
13974
14286
|
* be bound to string values only.
|
|
13975
14287
|
*
|
|
13976
|
-
* @param {string}
|
|
14288
|
+
* @param {string} ngModel Assignable angular expression to data-bind to.
|
|
14289
|
+
* @param {string=} name Property name of the form under which the control is published.
|
|
13977
14290
|
* @param {string=} required The control is considered valid only if value is entered.
|
|
13978
14291
|
* @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
|
|
13979
14292
|
* the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
|
|
@@ -14068,7 +14381,7 @@ var scriptDirective = ['$templateCache', function($templateCache) {
|
|
|
14068
14381
|
|
|
14069
14382
|
var ngOptionsDirective = valueFn({ terminal: true });
|
|
14070
14383
|
var selectDirective = ['$compile', '$parse', function($compile, $parse) {
|
|
14071
|
-
//
|
|
14384
|
+
//0000111110000000000022220000000000000000000000333300000000000000444444444444444440000000005555555555555555500000006666666666666666600000000000000077770
|
|
14072
14385
|
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+(.*)$/,
|
|
14073
14386
|
nullModelCtrl = {$setViewValue: noop};
|
|
14074
14387
|
|
|
@@ -14211,7 +14524,7 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
|
|
|
14211
14524
|
var lastView;
|
|
14212
14525
|
ctrl.$render = function() {
|
|
14213
14526
|
var items = new HashMap(ctrl.$viewValue);
|
|
14214
|
-
forEach(selectElement.
|
|
14527
|
+
forEach(selectElement.find('option'), function(option) {
|
|
14215
14528
|
option.selected = isDefined(items.get(option.value));
|
|
14216
14529
|
});
|
|
14217
14530
|
};
|
|
@@ -14228,7 +14541,7 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
|
|
|
14228
14541
|
selectElement.bind('change', function() {
|
|
14229
14542
|
scope.$apply(function() {
|
|
14230
14543
|
var array = [];
|
|
14231
|
-
forEach(selectElement.
|
|
14544
|
+
forEach(selectElement.find('option'), function(option) {
|
|
14232
14545
|
if (option.selected) {
|
|
14233
14546
|
array.push(option.value);
|
|
14234
14547
|
}
|
|
@@ -14340,10 +14653,6 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
|
|
|
14340
14653
|
|
|
14341
14654
|
if (multiple) {
|
|
14342
14655
|
selectedSet = new HashMap(modelValue);
|
|
14343
|
-
} else if (modelValue === null || nullOption) {
|
|
14344
|
-
// if we are not multiselect, and we are null then we have to add the nullOption
|
|
14345
|
-
optionGroups[''].push({selected:modelValue === null, id:'', label:''});
|
|
14346
|
-
selectedSet = true;
|
|
14347
14656
|
}
|
|
14348
14657
|
|
|
14349
14658
|
// We now build up the list of options we need (we merge later)
|
|
@@ -14368,9 +14677,14 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
|
|
|
14368
14677
|
selected: selected // determine if we should be selected
|
|
14369
14678
|
});
|
|
14370
14679
|
}
|
|
14371
|
-
if (!multiple
|
|
14372
|
-
|
|
14373
|
-
|
|
14680
|
+
if (!multiple) {
|
|
14681
|
+
if (nullOption || modelValue === null) {
|
|
14682
|
+
// insert null option if we have a placeholder, or the model is null
|
|
14683
|
+
optionGroups[''].unshift({id:'', label:'', selected:!selectedSet});
|
|
14684
|
+
} else if (!selectedSet) {
|
|
14685
|
+
// option could not be found, we have to insert the undefined item
|
|
14686
|
+
optionGroups[''].unshift({id:'?', label:'', selected:true});
|
|
14687
|
+
}
|
|
14374
14688
|
}
|
|
14375
14689
|
|
|
14376
14690
|
// Now we need to update the list of DOM nodes to match the optionGroups we computed above
|
|
@@ -14414,7 +14728,8 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
|
|
|
14414
14728
|
if (existingOption.id !== option.id) {
|
|
14415
14729
|
lastElement.val(existingOption.id = option.id);
|
|
14416
14730
|
}
|
|
14417
|
-
|
|
14731
|
+
// lastElement.prop('selected') provided by jQuery has side-effects
|
|
14732
|
+
if (lastElement[0].selected !== option.selected) {
|
|
14418
14733
|
lastElement.prop('selected', (existingOption.selected = option.selected));
|
|
14419
14734
|
}
|
|
14420
14735
|
} else {
|
|
@@ -14517,6 +14832,7 @@ var styleDirective = valueFn({
|
|
|
14517
14832
|
restrict: 'E',
|
|
14518
14833
|
terminal: true
|
|
14519
14834
|
});
|
|
14835
|
+
|
|
14520
14836
|
//try to bind to jquery now so that one can write angular.element().read()
|
|
14521
14837
|
//but we will rebind on bootstrap again.
|
|
14522
14838
|
bindJQuery();
|
|
@@ -14528,4 +14844,4 @@ var styleDirective = valueFn({
|
|
|
14528
14844
|
});
|
|
14529
14845
|
|
|
14530
14846
|
})(window, document);
|
|
14531
|
-
angular.element(document).find('head').append('<style type="text/css">@charset "UTF-8";[ng\\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak{display:none;}ng\\:form{display:block;}</style>');
|
|
14847
|
+
angular.element(document).find('head').append('<style type="text/css">@charset "UTF-8";[ng\\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak{display:none;}ng\\:form{display:block;}</style>');
|