Compare commits
79 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9d53e5a38d | |||
| 030a42e79d | |||
| 898714df9e | |||
| 966f6d831f | |||
| 28114faff4 | |||
| cc8755cda6 | |||
| 7b7b56d36d | |||
| 9278ae67c6 | |||
| a509e9aa14 | |||
| 09ee82d84d | |||
| c1cf053f37 | |||
| 2e5a7e52a0 | |||
| 5dfa630555 | |||
| 452d1cd66e | |||
| c6d8512a1d | |||
| 8a2c80ce7f | |||
| 2f3633d68f | |||
| 6c6a4086b7 | |||
| 0d424263ea | |||
| 2003fcf0de | |||
| 3130a82b21 | |||
| 6a38dbfd3c | |||
| 30e5b52344 | |||
| ebde4681bd | |||
| ad68a41e88 | |||
| 1f3ab484a7 | |||
| d9498a173c | |||
| 29ad3b7f36 | |||
| c1500ea775 | |||
| 4bc89bfe6d | |||
| 54097f63d5 | |||
| 2264413beb | |||
| 8a6cbb3c94 | |||
| bfcf9946e1 | |||
| b462f5dcf2 | |||
| bb1c379b36 | |||
| 62d514b069 | |||
| 35498d7045 | |||
| 630b80fc00 | |||
| a80d9449b7 | |||
| dda65e992b | |||
| aa0f64496a | |||
| e61eae1b1f | |||
| 400fbbf1d6 | |||
| 27bf2ce40c | |||
| c69caa7bee | |||
| 8c46919199 | |||
| d729fcf030 | |||
| 0baa17a3b7 | |||
| 2ece1c927b | |||
| 7602cd5e7e | |||
| 560951e988 | |||
| 1735d5e8d5 | |||
| c88b119ef5 | |||
| 6cf6a1b975 | |||
| 76df116574 | |||
| 440c122556 | |||
| f7114d0c1c | |||
| 2958cd308b | |||
| 9f7c5ceba7 | |||
| 2f32614378 | |||
| 8b33de6fd0 | |||
| d40749caab | |||
| e13224b2df | |||
| 36a14e65d1 | |||
| 3228d3b499 | |||
| 6d173aeb5d | |||
| d0ceeaa37e | |||
| 301663e734 | |||
| dca5fa7b81 | |||
| d557875a8d | |||
| b146af1127 | |||
| cea8e75144 | |||
| b3a9bd3ae0 | |||
| 31a5b8353a | |||
| 301e7aae24 | |||
| f2e2b31ece | |||
| 331cac233f | |||
| 7e3557e96b |
+9
-2
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"excludeFiles": ["src/ngLocale/**"],
|
||||
"disallowKeywords": ["with"],
|
||||
"disallowKeywordsOnNewLine": ["else"],
|
||||
"disallowMixedSpacesAndTabs": true,
|
||||
"disallowMultipleLineStrings": true,
|
||||
"disallowNewlineBeforeBlockStatements": true,
|
||||
@@ -11,6 +12,7 @@
|
||||
"disallowSpacesInAnonymousFunctionExpression": {
|
||||
"beforeOpeningRoundBrace": true
|
||||
},
|
||||
"disallowSpacesInCallExpression": true,
|
||||
"disallowSpacesInFunctionDeclaration": {
|
||||
"beforeOpeningRoundBrace": true
|
||||
},
|
||||
@@ -18,6 +20,11 @@
|
||||
"beforeOpeningRoundBrace": true
|
||||
},
|
||||
"disallowSpacesInsideArrayBrackets": true,
|
||||
"requireSpaceBeforeKeywords": [
|
||||
"else",
|
||||
"while",
|
||||
"catch"
|
||||
],
|
||||
"disallowSpacesInsideParentheses": true,
|
||||
"disallowTrailingComma": true,
|
||||
"disallowTrailingWhitespace": true,
|
||||
@@ -33,9 +40,9 @@
|
||||
"afterConsequent": true,
|
||||
"beforeAlternate": true
|
||||
},
|
||||
"requireSpacesInForStatement": true,
|
||||
"requireSpacesInFunction": {
|
||||
"beforeOpeningCurlyBrace": true
|
||||
},
|
||||
"validateLineBreaks": "LF",
|
||||
"validateParameterSeparator": ", "
|
||||
"validateLineBreaks": "LF"
|
||||
}
|
||||
|
||||
+1
-1
@@ -4,10 +4,10 @@
|
||||
// that correct the existing code base issues and make the new check pass.
|
||||
|
||||
{
|
||||
"validateParameterSeparator": ", ", // Re-assert this rule when JSCS allows multiple spaces
|
||||
"requireCurlyBraces": ["if", "else", "for", "while", "do", "try", "catch"],
|
||||
"disallowImplicitTypeConversion": ["string"],
|
||||
"disallowMultipleLineBreaks": true,
|
||||
"disallowKeywordsOnNewLine": ["else"],
|
||||
"validateJSDoc": {
|
||||
"checkParamNames": true,
|
||||
"requireParamTypes": true
|
||||
|
||||
+231
@@ -1,3 +1,234 @@
|
||||
<a name="1.4.0-beta.3"></a>
|
||||
# 1.4.0-beta.3 substance-mimicry (2015-02-02)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$compile:**
|
||||
- do not initialize optional '&' binding if attribute not specified
|
||||
([6a38dbfd](https://github.com/angular/angular.js/commit/6a38dbfd3c34c8f9efff503d17eb3cbeb666d422),
|
||||
[#6404](https://github.com/angular/angular.js/issues/6404), [#9216](https://github.com/angular/angular.js/issues/9216))
|
||||
- respect return value from controller constructor
|
||||
([62d514b0](https://github.com/angular/angular.js/commit/62d514b06937cc7dd86e973ea11165c88343b42d))
|
||||
- **$controller:** throw better error when controller expression is bad
|
||||
([dda65e99](https://github.com/angular/angular.js/commit/dda65e992b72044c0fa0c8f5f33184028c0e3ad7),
|
||||
[#10875](https://github.com/angular/angular.js/issues/10875), [#10910](https://github.com/angular/angular.js/issues/10910))
|
||||
- **$parse:**
|
||||
- handle null targets at assign
|
||||
([2e5a7e52](https://github.com/angular/angular.js/commit/2e5a7e52a0385575bbb55a801471b009afafeca3))
|
||||
- remove references to last arguments to a fn call
|
||||
([e61eae1b](https://github.com/angular/angular.js/commit/e61eae1b1f2351c51bcfe4142749a4e68a2806ff),
|
||||
[#10894](https://github.com/angular/angular.js/issues/10894))
|
||||
- **a:** don't reload if there is only a name attribute
|
||||
([d729fcf0](https://github.com/angular/angular.js/commit/d729fcf030be1d3ef37196d36ea3bf3249ee3318),
|
||||
[#6273](https://github.com/angular/angular.js/issues/6273), [#10880](https://github.com/angular/angular.js/issues/10880))
|
||||
- **angular.copy:** support copying `TypedArray`s
|
||||
([aa0f6449](https://github.com/angular/angular.js/commit/aa0f64496a66d2a5d1a4d033f2eb075a8b084a78),
|
||||
[#10745](https://github.com/angular/angular.js/issues/10745))
|
||||
- **filter:** format timezone correctly in the case that UTC timezone is used
|
||||
([8c469191](https://github.com/angular/angular.js/commit/8c46919199090a05634789774124b38983430c76),
|
||||
[#9359](https://github.com/angular/angular.js/issues/9359))
|
||||
- **ngRoute:** dont duplicate optional params into query
|
||||
([27bf2ce4](https://github.com/angular/angular.js/commit/27bf2ce40c5adfb1494d69c9d0ac9cf433834a12),
|
||||
[#10689](https://github.com/angular/angular.js/issues/10689))
|
||||
- **ngScenario:** allow ngScenario to handle lazy-loaded and manually bootstrapped applications
|
||||
([c69caa7b](https://github.com/angular/angular.js/commit/c69caa7beee4e920f8f587eb3e943be99864a14f),
|
||||
[#10723](https://github.com/angular/angular.js/issues/10723))
|
||||
- **validators:** maxlength should use viewValue for $isEmpty
|
||||
([bfcf9946](https://github.com/angular/angular.js/commit/bfcf9946e16d21b55dde50d4d21c71c898b10215),
|
||||
[#10898](https://github.com/angular/angular.js/issues/10898))
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
- **$compile:** allow using bindToController as object, support both new/isolate scopes
|
||||
([35498d70](https://github.com/angular/angular.js/commit/35498d7045ba9138016464a344e2c145ce5264c1),
|
||||
[#10420](https://github.com/angular/angular.js/issues/10420), [#10467](https://github.com/angular/angular.js/issues/10467))
|
||||
- **filter:** support conversion to timezone other than UTC
|
||||
([c6d8512a](https://github.com/angular/angular.js/commit/c6d8512a1d7345516d1bd9a039d81821b9518bff),
|
||||
[#10858](https://github.com/angular/angular.js/issues/10858))
|
||||
- **ngMocks:** cleanup $inject annotations after each test
|
||||
([0baa17a3](https://github.com/angular/angular.js/commit/0baa17a3b7ad2b242df2b277b81cebdf75b04287))
|
||||
|
||||
|
||||
## Performance Improvements
|
||||
|
||||
- **$scope:** Add a property $$watchersCount to scope
|
||||
([c1500ea7](https://github.com/angular/angular.js/commit/c1500ea775c4cb130088b7d5bb5fb872bda50bae))
|
||||
- **$parse** new and more performant parser
|
||||
([0d42426](https://github.com/angular/angular.js/commit/0d424263ead16635afb582affab2b147f8e71626))
|
||||
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
- **$compile:** due to [6a38dbfd](https://github.com/angular/angular.js/commit/6a38dbfd3c34c8f9efff503d17eb3cbeb666d422),
|
||||
Previously, '&' expressions would always set up a function in the isolate scope. Now, if the binding
|
||||
is marked as optional and the attribute is not specified, no function will be added to the isolate scope.
|
||||
|
||||
|
||||
<a name="1.3.12"></a>
|
||||
# 1.3.12 outlandish-knitting (2015-02-02)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$controller:** throw better error when controller expression is bad
|
||||
([632b2ddd](https://github.com/angular/angular.js/commit/632b2ddd34c07b3b5a207bd83ca3a5e6e613e63b),
|
||||
[#10875](https://github.com/angular/angular.js/issues/10875), [#10910](https://github.com/angular/angular.js/issues/10910))
|
||||
- **$parse:** remove references to last arguments to a fn call
|
||||
([7caad220](https://github.com/angular/angular.js/commit/7caad2205a6e9927890192a3638f55532bdaaf75),
|
||||
[#10894](https://github.com/angular/angular.js/issues/10894))
|
||||
- **ngRoute:** dont duplicate optional params into query
|
||||
([f41ca4a5](https://github.com/angular/angular.js/commit/f41ca4a53ed53f172fb334911be56e42aad58794),
|
||||
[#10689](https://github.com/angular/angular.js/issues/10689))
|
||||
- **ngScenario:** Allow ngScenario to handle lazy-loaded and manually bootstrapped applications
|
||||
([0bcd0872](https://github.com/angular/angular.js/commit/0bcd0872d8d2e37e6cb7aa5bc5cb0c742b4294f9),
|
||||
[#10723](https://github.com/angular/angular.js/issues/10723))
|
||||
- **validators:** maxlength should use viewValue for $isEmpty
|
||||
([abd8e2a9](https://github.com/angular/angular.js/commit/abd8e2a9eb2d21ac67989c2f7b64c4c6547a1585),
|
||||
[#10898](https://github.com/angular/angular.js/issues/10898))
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
- **ngMocks:** cleanup $inject annotations after each test
|
||||
([6ec59460](https://github.com/angular/angular.js/commit/6ec5946094ee92b820bbacc886fa2367715e60b4))
|
||||
|
||||
|
||||
|
||||
|
||||
<a name="1.4.0-beta.2"></a>
|
||||
# 1.4.0-beta.2 holographic-rooster (2015-01-26)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$location:** don't rewrite when link is shift-clicked
|
||||
([8b33de6f](https://github.com/angular/angular.js/commit/8b33de6fd0ec0eb785fed697f062763b5c1d8d23),
|
||||
[#9904](https://github.com/angular/angular.js/issues/9904), [#9906](https://github.com/angular/angular.js/issues/9906))
|
||||
- **$templateRequest:** cache downloaded templates as strings
|
||||
([b3a9bd3a](https://github.com/angular/angular.js/commit/b3a9bd3ae043e3042ea7ccfe08e3b36a84feb35e),
|
||||
[#10630](https://github.com/angular/angular.js/issues/10630), [#10646](https://github.com/angular/angular.js/issues/10646))
|
||||
- **filterFilter:** throw error if input is not an array
|
||||
([cea8e751](https://github.com/angular/angular.js/commit/cea8e75144e6910b806b63a6ec2a6d118316fddd),
|
||||
[#9992](https://github.com/angular/angular.js/issues/9992), [#10352](https://github.com/angular/angular.js/issues/10352))
|
||||
- **htmlAnchorDirective:**
|
||||
- remove "element !== target element" check
|
||||
([2958cd30](https://github.com/angular/angular.js/commit/2958cd308b5ebaf223a3e5df3fb5bf0f23408447),
|
||||
[#10866](https://github.com/angular/angular.js/issues/10866))
|
||||
- don't add event listener if replaced, ignore event if target is different element
|
||||
([b146af11](https://github.com/angular/angular.js/commit/b146af11271de8fa4c51c6db87df104269f41a33),
|
||||
[#4262](https://github.com/angular/angular.js/issues/4262), [#10849](https://github.com/angular/angular.js/issues/10849))
|
||||
- **ngPluralize:** fix wrong text content when count is null/undefined
|
||||
([3228d3b4](https://github.com/angular/angular.js/commit/3228d3b4991af681e57de5ab079c1e1c11cf35cb),
|
||||
[#10836](https://github.com/angular/angular.js/issues/10836), [#10841](https://github.com/angular/angular.js/issues/10841))
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
- **filterFilter:** due to [cea8e751](https://github.com/angular/angular.js/commit/cea8e75144e6910b806b63a6ec2a6d118316fddd),
|
||||
Previously, the filter was not applied if used with a non array.
|
||||
Now, it throws an error. This can be worked around by converting an object to an array, using
|
||||
a filter such as https://github.com/petebacondarwin/angular-toArrayFilter
|
||||
|
||||
Closes #9992
|
||||
Closes #10352
|
||||
|
||||
|
||||
<a name="1.3.11"></a>
|
||||
# 1.3.11 spiffy-manatee (2015-01-26)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$location:** don't rewrite when link is shift-clicked
|
||||
([939ca37c](https://github.com/angular/angular.js/commit/939ca37cfe5f6fc35b09b6705caabd1fcc3cf9d3),
|
||||
[#9904](https://github.com/angular/angular.js/issues/9904), [#9906](https://github.com/angular/angular.js/issues/9906))
|
||||
- **htmlAnchorDirective:**
|
||||
- remove "element !== target element" check
|
||||
([779e3f6b](https://github.com/angular/angular.js/commit/779e3f6b5f8d2550e758cb0c5f64187ba8e00e29),
|
||||
[#10866](https://github.com/angular/angular.js/issues/10866))
|
||||
- don't add event listener if replaced, ignore event if target is different element
|
||||
([837a0775](https://github.com/angular/angular.js/commit/837a077578081bbd07863bef85241537d19fa652),
|
||||
[#4262](https://github.com/angular/angular.js/issues/4262), [#10849](https://github.com/angular/angular.js/issues/10849))
|
||||
|
||||
|
||||
<a name="1.4.0-beta.1"></a>
|
||||
# 1.4.0-beta.1 trepidatious-salamander (2015-01-20)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$animate:** ensure no transitions are applied when an empty inline style object is provided
|
||||
([0db5b21b](https://github.com/angular/angular.js/commit/0db5b21b1d09431535e0c0bf8ac63d4b5b24d349),
|
||||
[#10613](https://github.com/angular/angular.js/issues/10613), [#10770](https://github.com/angular/angular.js/issues/10770))
|
||||
- **$compile:** support class directives on SVG elements
|
||||
([23c8a90d](https://github.com/angular/angular.js/commit/23c8a90d22f7c7b41b5a756b89498ffac828980a),
|
||||
[#10736](https://github.com/angular/angular.js/issues/10736), [#10756](https://github.com/angular/angular.js/issues/10756))
|
||||
- **form:** clean up success state of controls when they are removed
|
||||
([2408f2de](https://github.com/angular/angular.js/commit/2408f2ded5ead6e678c241e38ef474c1fadff92b),
|
||||
[#10509](https://github.com/angular/angular.js/issues/10509))
|
||||
- **ngController:** allow bound constructor fns as controllers
|
||||
([d17fbc38](https://github.com/angular/angular.js/commit/d17fbc3862e0a2e646db1222f184dbe663da4a1f),
|
||||
[#10784](https://github.com/angular/angular.js/issues/10784), [#10790](https://github.com/angular/angular.js/issues/10790))
|
||||
- **ngRepeat:** do not sort object keys alphabetically
|
||||
([c260e738](https://github.com/angular/angular.js/commit/c260e7386391877625eda086480de73e8a0ba921),
|
||||
[#6210](https://github.com/angular/angular.js/issues/6210), [#10538](https://github.com/angular/angular.js/issues/10538))
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
- **$http:** provide a config object as an argument to header functions
|
||||
([d435464c](https://github.com/angular/angular.js/commit/d435464c51d3912f56cfc830d86bfc64a1578327),
|
||||
[#7235](https://github.com/angular/angular.js/issues/7235), [#10622](https://github.com/angular/angular.js/issues/10622))
|
||||
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
- **ngRepeat:** due to [c260e738](https://github.com/angular/angular.js/commit/c260e7386391877625eda086480de73e8a0ba921),
|
||||
|
||||
|
||||
Previously, the order of items when using ngRepeat to iterate
|
||||
over object properties was guaranteed to be consistent by sorting the
|
||||
keys into alphabetic order.
|
||||
|
||||
Now, the order of the items is browser dependent based on the order returned
|
||||
from iterating over the object using the `for key in obj` syntax.
|
||||
|
||||
It seems that browsers generally follow the strategy of providing
|
||||
keys in the order in which they were defined, although there are exceptions
|
||||
when keys are deleted and reinstated. See
|
||||
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/delete#Cross-browser_issues
|
||||
|
||||
The best approach is to convert Objects into Arrays by a filter such as
|
||||
https://github.com/petebacondarwin/angular-toArrayFilter
|
||||
or some other mechanism, and then sort them manually in the order you need.
|
||||
|
||||
Closes #6210
|
||||
Closes #10538
|
||||
|
||||
|
||||
|
||||
<a name="1.3.10"></a>
|
||||
# 1.3.10 heliotropic-sundial (2015-01-20)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$animate:** ensure no transitions are applied when an empty inline style object is provided
|
||||
([9b8df52a](https://github.com/angular/angular.js/commit/9b8df52aa960b9b6288fc150d55ea2e35f56555e),
|
||||
[#10613](https://github.com/angular/angular.js/issues/10613), [#10770](https://github.com/angular/angular.js/issues/10770))
|
||||
- **$compile:** support class directives on SVG elements
|
||||
([7a9e3360](https://github.com/angular/angular.js/commit/7a9e3360284d58197a1fe34de57f5e0f6d1f4a76),
|
||||
[#10736](https://github.com/angular/angular.js/issues/10736), [#10756](https://github.com/angular/angular.js/issues/10756))
|
||||
- **form:** clean up success state of controls when they are removed
|
||||
([cdc7280d](https://github.com/angular/angular.js/commit/cdc7280dd3d5a2ded784c06dd55fe36c2053fb6f),
|
||||
[#10509](https://github.com/angular/angular.js/issues/10509))
|
||||
- **ngController:** allow bound constructor fns as controllers
|
||||
([d015c8a8](https://github.com/angular/angular.js/commit/d015c8a80b28754633c846fc50d11c9437519486),
|
||||
[#10784](https://github.com/angular/angular.js/issues/10784), [#10790](https://github.com/angular/angular.js/issues/10790))
|
||||
|
||||
|
||||
|
||||
<a name="1.4.0-beta.0"></a>
|
||||
# 1.4.0-beta.0 photonic-umbrakinesis (2015-01-13)
|
||||
|
||||
|
||||
+2
-2
@@ -316,9 +316,9 @@ module.exports = function(grunt) {
|
||||
grunt.registerTask('test', 'Run unit, docs and e2e tests with Karma', ['jshint', 'jscs', 'package','test:unit','test:promises-aplus', 'tests:docs', 'test:protractor']);
|
||||
grunt.registerTask('test:jqlite', 'Run the unit tests with Karma' , ['tests:jqlite']);
|
||||
grunt.registerTask('test:jquery', 'Run the jQuery unit tests with Karma', ['tests:jquery']);
|
||||
grunt.registerTask('test:modules', 'Run the Karma module tests with Karma', ['tests:modules']);
|
||||
grunt.registerTask('test:modules', 'Run the Karma module tests with Karma', ['build', 'tests:modules']);
|
||||
grunt.registerTask('test:docs', 'Run the doc-page tests with Karma', ['package', 'tests:docs']);
|
||||
grunt.registerTask('test:unit', 'Run unit, jQuery and Karma module tests with Karma', ['tests:jqlite', 'tests:jquery', 'tests:modules']);
|
||||
grunt.registerTask('test:unit', 'Run unit, jQuery and Karma module tests with Karma', ['test:jqlite', 'test:jquery', 'test:modules']);
|
||||
grunt.registerTask('test:protractor', 'Run the end to end tests with Protractor and keep a test server running in the background', ['webdriver', 'connect:testserver', 'protractor:normal']);
|
||||
grunt.registerTask('test:travis-protractor', 'Run the end to end tests with Protractor for Travis CI builds', ['connect:testserver', 'protractor:travis']);
|
||||
grunt.registerTask('test:ci-protractor', 'Run the end to end tests with Protractor for Jenkins CI builds', ['webdriver', 'connect:testserver', 'protractor:jenkins']);
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
<div>ngBind: <input type="radio" ng-model="benchmarkType" value="ngBind"></div>
|
||||
<div>ngBindOnce: <input type="radio" ng-model="benchmarkType" value="ngBindOnce"></div>
|
||||
<div>interpolation: <input type="radio" ng-model="benchmarkType" value="interpolation"></div>
|
||||
<div>interpolation + bind-once: <input type="radio" ng-model="benchmarkType" value="bindOnceInterpolation"></div>
|
||||
<div>attribute interpolation: <input type="radio" ng-model="benchmarkType" value="interpolationAttr"></div>
|
||||
<div>ngBind + fnInvocation: <input type="radio" ng-model="benchmarkType" value="ngBindFn"></div>
|
||||
<div>interpolation + fnInvocation: <input type="radio" ng-model="benchmarkType" value="interpolationFn"></div>
|
||||
@@ -35,7 +36,7 @@
|
||||
</div>
|
||||
<div ng-switch-when="ngBindOnce">
|
||||
<h2>baseline binding once</h2>
|
||||
<div ng-repeat="row in data">
|
||||
<div ng-repeat="row in ::data">
|
||||
<span ng-repeat="column in ::row">
|
||||
<span ng-bind="::column.i"></span>:<span ng-bind="::column.j"></span>|
|
||||
</span>
|
||||
@@ -47,6 +48,12 @@
|
||||
<span ng-repeat="column in row">{{column.i}}:{{column.j}}|</span>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-switch-when="bindOnceInterpolation">
|
||||
<h2>baseline one-time interpolation</h2>
|
||||
<div ng-repeat="row in ::data">
|
||||
<span ng-repeat="column in ::row">{{::column.i}}:{{::column.j}}|</span>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-switch-when="interpolationAttr">
|
||||
<h2>attribute interpolation</h2>
|
||||
<div ng-repeat="row in data">
|
||||
@@ -80,4 +87,4 @@
|
||||
</ng-switch>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -103,10 +103,10 @@ then(function (tags) {
|
||||
sort(semver.rcompare);
|
||||
}).
|
||||
then(function (tags) {
|
||||
var major = tags[0].split('.')[0] + '.x';
|
||||
var major = tags[0].split('.')[0];
|
||||
return tags.
|
||||
filter(function (ver) {
|
||||
return semver.satisfies(ver, major);
|
||||
return semver(ver).major == major;
|
||||
});
|
||||
}).
|
||||
then(function (tags) {
|
||||
|
||||
@@ -415,7 +415,7 @@ iframe.example {
|
||||
|
||||
.main-body-grid .side-navigation {
|
||||
position:relative;
|
||||
padding-bottom:50px;
|
||||
padding-bottom:120px;
|
||||
}
|
||||
|
||||
.main-body-grid .side-navigation.ng-hide {
|
||||
@@ -631,6 +631,7 @@ ul.events > li {
|
||||
}
|
||||
.main-body-grid .side-navigation {
|
||||
display:block!important;
|
||||
padding-bottom:50px;
|
||||
}
|
||||
.main-body-grid .side-navigation.ng-hide {
|
||||
display:none!important;
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
angular.module('examples', [])
|
||||
|
||||
.factory('formPostData', ['$document', function($document) {
|
||||
return function(url, fields) {
|
||||
return function(url, newWindow, fields) {
|
||||
/**
|
||||
* Form previously posted to target="_blank", but pop-up blockers were causing this to not work.
|
||||
* If a user chose to bypass pop-up blocker one time and click the link, they would arrive at
|
||||
* a new default plnkr, not a plnkr with the desired template.
|
||||
* If the form posts to target="_blank", pop-up blockers can cause it not to work.
|
||||
* If a user choses to bypass pop-up blocker one time and click the link, they will arrive at
|
||||
* a new default plnkr, not a plnkr with the desired template. Given this undesired behavior,
|
||||
* some may still want to open the plnk in a new window by opting-in via ctrl+click. The
|
||||
* newWindow param allows for this possibility.
|
||||
*/
|
||||
var form = angular.element('<form style="display: none;" method="post" action="' + url + '"></form>');
|
||||
var target = newWindow ? '_blank' : '_self';
|
||||
var form = angular.element('<form style="display: none;" method="post" action="' + url + '" target="' + target + '"></form>');
|
||||
angular.forEach(fields, function(value, name) {
|
||||
var input = angular.element('<input type="hidden" name="' + name + '">');
|
||||
input.attr('value', value);
|
||||
@@ -21,9 +24,10 @@ angular.module('examples', [])
|
||||
|
||||
|
||||
.factory('openPlunkr', ['formPostData', '$http', '$q', function(formPostData, $http, $q) {
|
||||
return function(exampleFolder) {
|
||||
return function(exampleFolder, clickEvent) {
|
||||
|
||||
var exampleName = 'AngularJS Example';
|
||||
var newWindow = clickEvent.ctrlKey || clickEvent.metaKey;
|
||||
|
||||
// Load the manifest for the example
|
||||
$http.get(exampleFolder + '/manifest.json')
|
||||
@@ -71,7 +75,7 @@ angular.module('examples', [])
|
||||
postData.private = true;
|
||||
postData.description = exampleName;
|
||||
|
||||
formPostData('http://plnkr.co/edit/?p=preview', postData);
|
||||
formPostData('http://plnkr.co/edit/?p=preview', newWindow, postData);
|
||||
});
|
||||
};
|
||||
}]);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
is HTML and wrap each line in a <p> - thus breaking the HTML #}
|
||||
|
||||
<div>
|
||||
<a ng-click="openPlunkr('{$ doc.path $}')" class="btn pull-right">
|
||||
<a ng-click="openPlunkr('{$ doc.path $}', $event)" class="btn pull-right">
|
||||
<i class="glyphicon glyphicon-edit"> </i>
|
||||
Edit in Plunker</a>
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
@ngdoc error
|
||||
@name $compile:noctrl
|
||||
@fullName Controller is required.
|
||||
@description
|
||||
|
||||
When using the `bindToController` feature of AngularJS, a directive is required
|
||||
to have a Controller. A controller may be specified by adding a "controller"
|
||||
property to the directive definition object. Its value should be either a
|
||||
string, or an invokable object (a function, or an array whose last element is a
|
||||
function).
|
||||
|
||||
For more information, see the {@link guide/directive directives guide}.
|
||||
@@ -0,0 +1,71 @@
|
||||
@ngdoc error
|
||||
@name $compile:noident
|
||||
@fullName Controller identifier is required.
|
||||
@description
|
||||
|
||||
When using the `bindToController` feature of AngularJS, a directive is required
|
||||
to have a Controller identifier, which is initialized in scope with the value of
|
||||
the controller instance. This can be supplied using the "controllerAs" property
|
||||
of the directive object, or alternatively by adding " as IDENTIFIER" to the controller
|
||||
name.
|
||||
|
||||
For example, the following directives are valid:
|
||||
|
||||
```js
|
||||
// OKAY, because controller is a string with an identifier component.
|
||||
directive("okay", function() {
|
||||
return {
|
||||
bindToController: true,
|
||||
controller: "myCtrl as $ctrl"
|
||||
scope: {
|
||||
text: "@text"
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
// OKAY, because the directive uses the controllerAs property to override
|
||||
// the controller identifier.
|
||||
directive("okay2", function() {
|
||||
return {
|
||||
bindToController: true,
|
||||
controllerAs: "$ctrl",
|
||||
controller: function() {
|
||||
|
||||
},
|
||||
scope: {
|
||||
text: "@text"
|
||||
}
|
||||
};
|
||||
});
|
||||
```
|
||||
|
||||
While the following are invalid:
|
||||
|
||||
```js
|
||||
// BAD, because the controller property is a string with no identifier.
|
||||
directive("bad", function() {
|
||||
return {
|
||||
bindToController: true,
|
||||
controller: "noIdentCtrl",
|
||||
scope: {
|
||||
text: "@text"
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
// BAD because the controller is not a string (therefore has no identifier),
|
||||
// and there is no controllerAs property.
|
||||
directive("bad2", function() {
|
||||
return {
|
||||
bindToController: true,
|
||||
controller: function noControllerAs() {
|
||||
|
||||
},
|
||||
scope: {
|
||||
text: "@text"
|
||||
}
|
||||
};
|
||||
});
|
||||
```
|
||||
@@ -0,0 +1,46 @@
|
||||
@ngdoc error
|
||||
@name $controller:ctrlfmt
|
||||
@fullName Badly formed controller string
|
||||
@description
|
||||
|
||||
This error occurs when {@link ng.$controller $controller} service is called
|
||||
with a string that does not match the supported controller string formats.
|
||||
|
||||
Supported formats:
|
||||
|
||||
1. `__name__`
|
||||
2. `__name__ as __identifier__`
|
||||
|
||||
N'either `__name__` or `__identifier__` may contain spaces.
|
||||
|
||||
Example of incorrect usage that leads to this error:
|
||||
```html
|
||||
<!-- unclosed ng-controller attribute messes up the format -->
|
||||
<div ng-controller="myController>
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```js
|
||||
// does not match `__name__` or `__name__ as __identifier__`
|
||||
var myCtrl = $controller("mY contRoller", { $scope: newScope });
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```js
|
||||
directive("myDirective", function() {
|
||||
return {
|
||||
// does not match `__name__` or `__name__ as __identifier__`
|
||||
controller: "mY contRoller",
|
||||
link: function() {}
|
||||
};
|
||||
});
|
||||
```
|
||||
|
||||
To fix the examples above, ensure that the controller string matches the supported
|
||||
formats, and that any html attributes which are used as controller expressions are
|
||||
closed.
|
||||
|
||||
|
||||
Please consult the {@link ng.$controller $controller} service api docs to learn more.
|
||||
@@ -0,0 +1,51 @@
|
||||
@ngdoc error
|
||||
@name filter:notarray
|
||||
@fullName Not an array
|
||||
@description
|
||||
|
||||
This error occurs when {@link ng.filter filter} is not used with an array:
|
||||
```html
|
||||
<input ng-model="search">
|
||||
<div ng-repeat="(key, value) in myObj | filter:search">
|
||||
{{ key }} : {{ value }}
|
||||
</div>
|
||||
```
|
||||
|
||||
Filter must be used with an array so a subset of items can be returned.
|
||||
The array can be initialized asynchronously and therefore null or undefined won't throw this error.
|
||||
|
||||
To filter an object by the value of its properties you can create your own custom filter:
|
||||
```js
|
||||
angular.module('customFilter',[])
|
||||
.filter('custom', function() {
|
||||
return function(input, search) {
|
||||
if (!input) return input;
|
||||
if (!search) return input;
|
||||
var expected = ('' + search).toLowerCase();
|
||||
var result = {};
|
||||
angular.forEach(input, function(value, key) {
|
||||
var actual = ('' + value).toLowerCase();
|
||||
if (actual.indexOf(expected) !== -1) {
|
||||
result[key] = value;
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
});
|
||||
```
|
||||
That can be used as:
|
||||
```html
|
||||
<input ng-model="search">
|
||||
<div ng-repeat="(key, value) in myObj | custom:search">
|
||||
{{ key }} : {{ value }}
|
||||
</div>
|
||||
```
|
||||
|
||||
You could as well convert the object to an array using a filter such as
|
||||
[toArrayFilter](https://github.com/petebacondarwin/angular-toArrayFilter):
|
||||
```html
|
||||
<input ng-model="search">
|
||||
<div ng-repeat="item in myObj | toArray:false | filter:search">
|
||||
{{ item }}
|
||||
</div>
|
||||
```
|
||||
@@ -0,0 +1,7 @@
|
||||
@ngdoc error
|
||||
@name ng:cpta
|
||||
@fullName Copying TypedArray
|
||||
@description
|
||||
|
||||
Copying TypedArray's with a destination is not supported because TypedArray
|
||||
objects can not be mutated, they are fixed length.
|
||||
@@ -165,7 +165,7 @@ encoded.
|
||||
|
||||
`$location` service has two configuration modes which control the format of the URL in the browser
|
||||
address bar: **Hashbang mode** (the default) and the **HTML5 mode** which is based on using the
|
||||
HTML5 [History API](http://www.w3.org/TR/html5/introduction.html#history-0). Applications use the same API in
|
||||
[HTML5 History API](https://html.spec.whatwg.org/multipage/browsers.html#the-history-interface). Applications use the same API in
|
||||
both modes and the `$location` service will work with appropriate URL segments and browser APIs to
|
||||
facilitate the browser URL change and history management.
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ Currently, ngAria interfaces with the following directives:
|
||||
* {@link guide/accessibility#nghide ngHide}
|
||||
* {@link guide/accessibility#ngclick ngClick}
|
||||
* {@link guide/accessibility#ngdblclick ngDblClick}
|
||||
* {@link guide/accessibility#ngmessages ngMessages}
|
||||
|
||||
<h2 id="ngmodel">ngModel</h2>
|
||||
|
||||
@@ -209,10 +210,14 @@ The default CSS for `ngHide`, the inverse method to `ngShow`, makes ngAria redun
|
||||
`display: none`. See explanation for {@link guide/accessibility#ngshow ngShow} when overriding the default CSS.
|
||||
|
||||
<h2><span id="ngclick">ngClick</span> and <span id="ngdblclick">ngDblclick</span></h2>
|
||||
If `ng-click` or `ng-dblclick` is encountered, ngAria will add `tabindex` if it isn't there already.
|
||||
Even with this, you must currently still add `ng-keypress` to non-interactive elements such as `div`
|
||||
or `taco-button` to enable keyboard access. Conversation is currently ongoing about whether ngAria
|
||||
should also bind `ng-keypress`.
|
||||
If `ng-click` or `ng-dblclick` is encountered, ngAria will add `tabindex="0"` if it isn't there
|
||||
already.
|
||||
|
||||
For `ng-click`, keypress will also be bound to `div` and `li` elements. You can turn this
|
||||
functionality on or off with the `bindKeypress` configuration option.
|
||||
|
||||
For `ng-dblclick`, you must manually add `ng-keypress` to non-interactive elements such as `div`
|
||||
or `taco-button` to enable keyboard access.
|
||||
|
||||
<h3>Example</h3>
|
||||
```html
|
||||
@@ -223,7 +228,6 @@ Becomes:
|
||||
```html
|
||||
<div ng-click="toggleMenu()" tabindex="0"></div>
|
||||
```
|
||||
*Note: ngAria still requires `ng-keypress` to be added manually to non-native controls like divs.*
|
||||
|
||||
<h2 id="ngmessages">ngMessages</h2>
|
||||
|
||||
|
||||
@@ -6,11 +6,12 @@
|
||||
Controls (`input`, `select`, `textarea`) are ways for a user to enter data.
|
||||
A Form is a collection of controls for the purpose of grouping related controls together.
|
||||
|
||||
Form and controls provide validation services, so that the user can be notified of invalid input.
|
||||
This provides a better user experience, because the user gets instant feedback on how to
|
||||
correct the error. Keep in mind that while client-side validation plays an important role
|
||||
in providing good user experience, it can easily be circumvented and thus can not be trusted.
|
||||
Server-side validation is still necessary for a secure application.
|
||||
Form and controls provide validation services, so that the user can be notified of invalid input
|
||||
before submitting a form. This provides a better user experience than server-side validation alone
|
||||
because the user gets instant feedback on how to correct the error. Keep in mind that while
|
||||
client-side validation plays an important role in providing good user experience, it can easily
|
||||
be circumvented and thus can not be trusted. Server-side validation is still necessary for a
|
||||
secure application.
|
||||
|
||||
|
||||
# Simple form
|
||||
|
||||
@@ -102,7 +102,7 @@ This is a short list of libraries with specific support and documentation for wo
|
||||
## Learning Resources
|
||||
|
||||
###Books
|
||||
* [AngularJS](http://www.amazon.com/AngularJS-Brad-Green/dp/1449344852) by Brad Green and Shyam Seshadri
|
||||
* [AngularJS: Up and Running](http://www.amazon.com/AngularJS-Running-Enhanced-Productivity-Structured/dp/1491901942) by Brad Green and Shyam Seshadri
|
||||
* [Mastering Web App Development](http://www.amazon.com/Mastering-Web-Application-Development-AngularJS/dp/1782161821) by Pawel Kozlowski and Pete Bacon Darwin
|
||||
* [AngularJS Directives](http://www.amazon.com/AngularJS-Directives-Alex-Vanston/dp/1783280336) by Alex Vanston
|
||||
* [Recipes With AngularJS](http://www.amazon.co.uk/Recipes-Angular-js-Frederik-Dietz-ebook/dp/B00DK95V48) by Frederik Dietz
|
||||
|
||||
@@ -12,7 +12,7 @@ succinctly. Angular's data binding and dependency injection eliminate much of th
|
||||
would otherwise have to write. And it all happens within the browser, making it
|
||||
an ideal partner with any server technology.
|
||||
|
||||
Angular is what HTML would have been had it been designed for applications. HTML is a great
|
||||
Angular is what HTML would have been, had it been designed for applications. HTML is a great
|
||||
declarative language for static documents. It does not contain much in the way of creating
|
||||
applications, and as a result building web applications is an exercise in *what do I have to do
|
||||
to trick the browser into doing what I want?*
|
||||
@@ -28,10 +28,10 @@ The impedance mismatch between dynamic applications and static documents is ofte
|
||||
|
||||
Angular takes another approach. It attempts to minimize the impedance mismatch between document
|
||||
centric HTML and what an application needs by creating new HTML constructs. Angular teaches the
|
||||
browser new syntax through a construct we call directives. Examples include:
|
||||
browser new syntax through a construct we call *directives*. Examples include:
|
||||
|
||||
* Data binding, as in `{{}}`.
|
||||
* DOM control structures for repeating/hiding DOM fragments.
|
||||
* DOM control structures for repeating, showing and hiding DOM fragments.
|
||||
* Support for forms and form validation.
|
||||
* Attaching new behavior to DOM elements, such as DOM event handling.
|
||||
* Grouping of HTML into reusable components.
|
||||
@@ -42,20 +42,20 @@ browser new syntax through a construct we call directives. Examples include:
|
||||
|
||||
Angular is not a single piece in the overall puzzle of building the client-side of a web
|
||||
application. It handles all of the DOM and AJAX glue code you once wrote by hand and puts it in a
|
||||
well-defined structure. This makes Angular opinionated about how a CRUD application should be
|
||||
built. But while it is opinionated, it also tries to make sure that its opinion is just a
|
||||
starting point you can easily change. Angular comes with the following out-of-the-box:
|
||||
well-defined structure. This makes Angular opinionated about how a CRUD (Create, Read, Update, Delete)
|
||||
application should be built. But while it is opinionated, it also tries to make sure that its opinion
|
||||
is just a starting point you can easily change. Angular comes with the following out-of-the-box:
|
||||
|
||||
* Everything you need to build a CRUD app in a cohesive set: data-binding, basic templating
|
||||
directives, form validation, routing, deep-linking, reusable components, dependency injection.
|
||||
* Testability story: unit-testing, end-to-end testing, mocks, test harnesses.
|
||||
* Everything you need to build a CRUD app in a cohesive set: Data-binding, basic templating
|
||||
directives, form validation, routing, deep-linking, reusable components and dependency injection.
|
||||
* Testability story: Unit-testing, end-to-end testing, mocks and test harnesses.
|
||||
* Seed application with directory layout and test scripts as a starting point.
|
||||
|
||||
|
||||
## Angular Sweet Spot
|
||||
## Angular's sweet spot
|
||||
|
||||
Angular simplifies application development by presenting a higher level of abstraction to the
|
||||
developer. Like any abstraction, it comes at a cost of flexibility. In other words not every app
|
||||
developer. Like any abstraction, it comes at a cost of flexibility. In other words, not every app
|
||||
is a good fit for Angular. Angular was built with the CRUD application in mind. Luckily CRUD
|
||||
applications represent the majority of web applications. To understand what Angular is
|
||||
good at, though, it helps to understand when an app is not a good fit for Angular.
|
||||
@@ -78,7 +78,7 @@ expressing business logic.
|
||||
* It is an excellent idea to decouple the client side of an app from the server side. This
|
||||
allows development work to progress in parallel, and allows for reuse of both sides.
|
||||
* It is very helpful indeed if the framework guides developers through the entire journey of
|
||||
building an app: from designing the UI, through writing the business logic, to testing.
|
||||
building an app: From designing the UI, through writing the business logic, to testing.
|
||||
* It is always good to make common tasks trivial and difficult tasks possible.
|
||||
|
||||
|
||||
|
||||
@@ -10,13 +10,13 @@ There are a few things you might consider when running your AngularJS applicatio
|
||||
|
||||
## Disabling Debug Data
|
||||
|
||||
By default AngularJS attaches information about scopes to DOM nodes, and adds CSS classes
|
||||
to data-bound elements. The information that is not included is:
|
||||
By default AngularJS attaches information about binding and scopes to DOM nodes,
|
||||
and adds CSS classes to data-bound elements:
|
||||
|
||||
As a result of `ngBind`, `ngBindHtml` or `{{...}}` interpolations, binding data and CSS class
|
||||
`ng-class` is attached to the corresponding element.
|
||||
- As a result of `ngBind`, `ngBindHtml` or `{{...}}` interpolations, binding data and CSS class
|
||||
`ng-binding` are attached to the corresponding element.
|
||||
|
||||
Where the compiler has created a new scope, the scope and either `ng-scope` or `ng-isolated-scope`
|
||||
- Where the compiler has created a new scope, the scope and either `ng-scope` or `ng-isolated-scope`
|
||||
CSS class are attached to the corresponding element. These scope references can then be accessed via
|
||||
`element.scope()` and `element.isolateScope()`.
|
||||
|
||||
|
||||
@@ -15,14 +15,14 @@ development.
|
||||
production.
|
||||
|
||||
To point your code to an angular script on the Google CDN server, use the following template. This
|
||||
example points to the minified version 1.2.0:
|
||||
example points to the minified version 1.3.12:
|
||||
|
||||
```
|
||||
<!doctype html>
|
||||
<html ng-app>
|
||||
<head>
|
||||
<title>My Angular App</title>
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js"></script>
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.12/angular.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
|
||||
@@ -288,5 +288,5 @@ learn how to improve this application with animations.
|
||||
<ul doc-tutorial-nav="11"></ul>
|
||||
|
||||
[restful]: http://en.wikipedia.org/wiki/Representational_State_Transfer
|
||||
[jasmine-matchers]: https://github.com/pivotal/jasmine/wiki/Matchers
|
||||
[jasmine-matchers]: http://jasmine.github.io/1.3/introduction.html#section-Matchers
|
||||
[bower]: http://bower.io/
|
||||
|
||||
@@ -2912,16 +2912,12 @@ goog.i18n.DateTimeSymbols_my = {
|
||||
'ဇွန်', 'ဇူလိုင်', 'ဩဂုတ်',
|
||||
'စက်တင်ဘာ', 'အောက်တိုဘာ',
|
||||
'နိုဝင်ဘာ', 'ဒီဇင်ဘာ'],
|
||||
SHORTMONTHS: ['ဇန်နဝါရီ', 'ဖေဖော်ဝါရီ',
|
||||
'မတ်', 'ဧပြီ', 'မေ', 'ဇွန်',
|
||||
'ဇူလိုင်', 'ဩဂုတ်', 'စက်တင်ဘာ',
|
||||
'အောက်တိုဘာ', 'နိုဝင်ဘာ',
|
||||
'ဒီဇင်ဘာ'],
|
||||
STANDALONESHORTMONTHS: ['ဇန်နဝါရီ',
|
||||
'ဖေဖော်ဝါရီ', 'မတ်', 'ဧပြီ', 'မေ',
|
||||
'ဇွန်', 'ဇူလိုင်', 'ဩဂုတ်',
|
||||
'စက်တင်ဘာ', 'အောက်တိုဘာ',
|
||||
'နိုဝင်ဘာ', 'ဒီဇင်ဘာ'],
|
||||
SHORTMONTHS: ['ဇန်', 'ဖေ', 'မတ်', 'ဧပြီ', 'မေ',
|
||||
'ဇွန်', 'ဇူ', 'ဩ', 'စက်', 'အောက်',
|
||||
'နို', 'ဒီ'],
|
||||
STANDALONESHORTMONTHS: ['ဇန်', 'ဖေ', 'မတ်', 'ဧပြီ',
|
||||
'မေ', 'ဇွန်', 'ဇူ', 'ဩ', 'စက်', 'အောက်',
|
||||
'နို', 'ဒီ'],
|
||||
WEEKDAYS: ['တနင်္ဂနွေ', 'တနင်္လာ',
|
||||
'အင်္ဂါ', 'ဗုဒ္ဓဟူး',
|
||||
'ကြာသပတေး', 'သောကြာ', 'စနေ'],
|
||||
@@ -2945,7 +2941,7 @@ goog.i18n.DateTimeSymbols_my = {
|
||||
'တတိယ သုံးလပတ်',
|
||||
'စတုတ္ထ သုံးလပတ်'],
|
||||
AMPMS: ['နံနက်', 'ညနေ'],
|
||||
DATEFORMATS: ['EEEE, y MMMM dd', 'y MMMM d', 'y MMM d', 'yy/MM/dd'],
|
||||
DATEFORMATS: ['EEEE, dd MMMM y', 'd MMMM y', 'd MMM y', 'dd-MM-yy'],
|
||||
TIMEFORMATS: ['HH:mm:ss zzzz', 'HH:mm:ss z', 'HH:mm:ss', 'HH:mm'],
|
||||
DATETIMEFORMATS: ['{1}မှာ {0}', '{1} {0}', '{1} {0}', '{1} {0}'],
|
||||
FIRSTDAYOFWEEK: 6,
|
||||
|
||||
@@ -14493,16 +14493,12 @@ goog.i18n.DateTimeSymbols_my_MM = {
|
||||
'ဇွန်', 'ဇူလိုင်', 'ဩဂုတ်',
|
||||
'စက်တင်ဘာ', 'အောက်တိုဘာ',
|
||||
'နိုဝင်ဘာ', 'ဒီဇင်ဘာ'],
|
||||
SHORTMONTHS: ['ဇန်နဝါရီ', 'ဖေဖော်ဝါရီ',
|
||||
'မတ်', 'ဧပြီ', 'မေ', 'ဇွန်',
|
||||
'ဇူလိုင်', 'ဩဂုတ်', 'စက်တင်ဘာ',
|
||||
'အောက်တိုဘာ', 'နိုဝင်ဘာ',
|
||||
'ဒီဇင်ဘာ'],
|
||||
STANDALONESHORTMONTHS: ['ဇန်နဝါရီ',
|
||||
'ဖေဖော်ဝါရီ', 'မတ်', 'ဧပြီ', 'မေ',
|
||||
'ဇွန်', 'ဇူလိုင်', 'ဩဂုတ်',
|
||||
'စက်တင်ဘာ', 'အောက်တိုဘာ',
|
||||
'နိုဝင်ဘာ', 'ဒီဇင်ဘာ'],
|
||||
SHORTMONTHS: ['ဇန်', 'ဖေ', 'မတ်', 'ဧပြီ', 'မေ',
|
||||
'ဇွန်', 'ဇူ', 'ဩ', 'စက်', 'အောက်',
|
||||
'နို', 'ဒီ'],
|
||||
STANDALONESHORTMONTHS: ['ဇန်', 'ဖေ', 'မတ်', 'ဧပြီ',
|
||||
'မေ', 'ဇွန်', 'ဇူ', 'ဩ', 'စက်', 'အောက်',
|
||||
'နို', 'ဒီ'],
|
||||
WEEKDAYS: ['တနင်္ဂနွေ', 'တနင်္လာ',
|
||||
'အင်္ဂါ', 'ဗုဒ္ဓဟူး',
|
||||
'ကြာသပတေး', 'သောကြာ', 'စနေ'],
|
||||
@@ -14526,7 +14522,7 @@ goog.i18n.DateTimeSymbols_my_MM = {
|
||||
'တတိယ သုံးလပတ်',
|
||||
'စတုတ္ထ သုံးလပတ်'],
|
||||
AMPMS: ['နံနက်', 'ညနေ'],
|
||||
DATEFORMATS: ['EEEE, y MMMM dd', 'y MMMM d', 'y MMM d', 'yy/MM/dd'],
|
||||
DATEFORMATS: ['EEEE, dd MMMM y', 'd MMMM y', 'd MMM y', 'dd-MM-yy'],
|
||||
TIMEFORMATS: ['HH:mm:ss zzzz', 'HH:mm:ss z', 'HH:mm:ss', 'HH:mm'],
|
||||
DATETIMEFORMATS: ['{1}မှာ {0}', '{1} {0}', '{1} {0}', '{1} {0}'],
|
||||
FIRSTDAYOFWEEK: 6,
|
||||
|
||||
@@ -2112,7 +2112,7 @@ goog.i18n.NumberFormatSymbols_lt = {
|
||||
SCIENTIFIC_PATTERN: '#E0',
|
||||
PERCENT_PATTERN: '#,##0\u00A0%',
|
||||
CURRENCY_PATTERN: '#,##0.00\u00A0\u00A4',
|
||||
DEF_CURRENCY_CODE: 'LTL'
|
||||
DEF_CURRENCY_CODE: 'EUR'
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -16,9 +16,9 @@ var currentPackage, previousVersions, cdnVersion, gitRepoInfo;
|
||||
var getPackage = function() {
|
||||
// Search up the folder hierarchy for the first package.json
|
||||
var packageFolder = path.resolve('.');
|
||||
while ( !fs.existsSync(path.join(packageFolder, 'package.json')) ) {
|
||||
while (!fs.existsSync(path.join(packageFolder, 'package.json'))) {
|
||||
var parent = path.dirname(packageFolder);
|
||||
if ( parent === packageFolder) { break; }
|
||||
if (parent === packageFolder) { break; }
|
||||
packageFolder = parent;
|
||||
}
|
||||
return JSON.parse(fs.readFileSync(path.join(packageFolder,'package.json'), 'UTF-8'));
|
||||
@@ -48,11 +48,11 @@ var getGitRepoInfo = function() {
|
||||
* @return {String} The codename if found, otherwise null/undefined
|
||||
*/
|
||||
var getCodeName = function(tagName) {
|
||||
var gitCatOutput = shell.exec('git cat-file -p '+ tagName, {silent:true}).output;
|
||||
var gitCatOutput = shell.exec('git cat-file -p ' + tagName, {silent:true}).output;
|
||||
var tagMessage = gitCatOutput.match(/^.*codename.*$/mg)[0];
|
||||
var codeName = tagMessage && tagMessage.match(/codename\((.*)\)/)[1];
|
||||
if (!codeName) {
|
||||
throw new Error("Could not extract release code name. The message of tag "+tagName+
|
||||
throw new Error("Could not extract release code name. The message of tag " + tagName +
|
||||
" must match '*codename(some release name)*'");
|
||||
}
|
||||
return codeName;
|
||||
@@ -65,7 +65,7 @@ var getCodeName = function(tagName) {
|
||||
*/
|
||||
function getBuild() {
|
||||
var hash = shell.exec('git rev-parse --short HEAD', {silent: true}).output.replace('\n', '');
|
||||
return 'sha.'+hash;
|
||||
return 'sha.' + hash;
|
||||
}
|
||||
|
||||
|
||||
@@ -76,11 +76,11 @@ function getBuild() {
|
||||
var getTaggedVersion = function() {
|
||||
var gitTagResult = shell.exec('git describe --exact-match', {silent:true});
|
||||
|
||||
if ( gitTagResult.code === 0 ) {
|
||||
if (gitTagResult.code === 0) {
|
||||
var tag = gitTagResult.output.trim();
|
||||
var version = semver.parse(tag);
|
||||
|
||||
if ( version && semver.satisfies(version, currentPackage.branchVersion)) {
|
||||
if (version && semver.satisfies(version, currentPackage.branchVersion)) {
|
||||
version.codeName = getCodeName(tag);
|
||||
version.full = version.version;
|
||||
version.branch = 'v' + currentPackage.branchPattern.replace('*', 'x');
|
||||
@@ -102,7 +102,7 @@ var getPreviousVersions = function() {
|
||||
var repo_url = currentPackage.repository.url;
|
||||
var tagResults = shell.exec('git ls-remote --tags ' + repo_url,
|
||||
{silent: true});
|
||||
if ( tagResults.code === 0 ) {
|
||||
if (tagResults.code === 0) {
|
||||
return _(tagResults.output.match(/v[0-9].*[0-9]$/mg))
|
||||
.map(function(tag) {
|
||||
var version = semver.parse(tag);
|
||||
@@ -112,7 +112,7 @@ var getPreviousVersions = function() {
|
||||
.map(function(version) {
|
||||
version.docsUrl = 'http://code.angularjs.org/' + version.version + '/docs';
|
||||
// Versions before 1.0.2 had a different docs folder name
|
||||
if ( version.major < 1 || (version.major === 1 && version.minor === 0 && version.dot < 2 ) ) {
|
||||
if (version.major < 1 || (version.major === 1 && version.minor === 0 && version.dot < 2)) {
|
||||
version.docsUrl += '-' + version.version;
|
||||
}
|
||||
return version;
|
||||
@@ -130,18 +130,14 @@ var getCdnVersion = function() {
|
||||
return semver.satisfies(tag, currentPackage.branchVersion);
|
||||
})
|
||||
.reverse()
|
||||
.tap(function(versions) {
|
||||
console.log(versions);
|
||||
})
|
||||
.reduce(function(cdnVersion, version) {
|
||||
if (!cdnVersion) {
|
||||
// Note: need to use shell.exec and curl here
|
||||
// as version-infos returns its result synchronously...
|
||||
var cdnResult = shell.exec('curl http://ajax.googleapis.com/ajax/libs/angularjs/'+version+'/angular.min.js '+
|
||||
var cdnResult = shell.exec('curl http://ajax.googleapis.com/ajax/libs/angularjs/' + version + '/angular.min.js ' +
|
||||
'--head --write-out "%{http_code}" -o /dev/null -silent',
|
||||
{silent: false});
|
||||
console.log('http://ajax.googleapis.com/ajax/libs/angularjs/'+version+'/angular.min.js');
|
||||
if ( cdnResult.code === 0 ) {
|
||||
{silent: true});
|
||||
if (cdnResult.code === 0) {
|
||||
var statusCode = cdnResult.output.trim();
|
||||
if (statusCode === '200') {
|
||||
cdnVersion = version;
|
||||
@@ -163,7 +159,7 @@ var getSnapshotVersion = function() {
|
||||
})
|
||||
.last();
|
||||
|
||||
if ( !version ) {
|
||||
if (!version) {
|
||||
// a snapshot version before the first tag on the branch
|
||||
version = semver(currentPackage.branchPattern.replace('*','0-beta.1'));
|
||||
}
|
||||
|
||||
Generated
+90
-66
@@ -1395,66 +1395,66 @@
|
||||
}
|
||||
},
|
||||
"dgeni-packages": {
|
||||
"version": "0.10.7",
|
||||
"version": "0.10.8",
|
||||
"dependencies": {
|
||||
"catharsis": {
|
||||
"version": "0.7.1"
|
||||
},
|
||||
"change-case": {
|
||||
"version": "2.1.5",
|
||||
"version": "2.2.0",
|
||||
"dependencies": {
|
||||
"camel-case": {
|
||||
"version": "1.0.2"
|
||||
"version": "1.1.1"
|
||||
},
|
||||
"constant-case": {
|
||||
"version": "1.0.0"
|
||||
},
|
||||
"dot-case": {
|
||||
"version": "1.0.1"
|
||||
},
|
||||
"is-lower-case": {
|
||||
"version": "1.0.0"
|
||||
},
|
||||
"is-upper-case": {
|
||||
"version": "1.0.1"
|
||||
},
|
||||
"lower-case": {
|
||||
"version": "1.0.2"
|
||||
},
|
||||
"param-case": {
|
||||
"version": "1.0.1"
|
||||
},
|
||||
"pascal-case": {
|
||||
"version": "1.0.0"
|
||||
},
|
||||
"path-case": {
|
||||
"version": "1.0.1"
|
||||
},
|
||||
"sentence-case": {
|
||||
"version": "1.1.0"
|
||||
},
|
||||
"dot-case": {
|
||||
"version": "1.1.0"
|
||||
},
|
||||
"is-lower-case": {
|
||||
"version": "1.1.0"
|
||||
},
|
||||
"is-upper-case": {
|
||||
"version": "1.1.0"
|
||||
},
|
||||
"lower-case": {
|
||||
"version": "1.1.1"
|
||||
},
|
||||
"param-case": {
|
||||
"version": "1.1.0"
|
||||
},
|
||||
"pascal-case": {
|
||||
"version": "1.1.0"
|
||||
},
|
||||
"path-case": {
|
||||
"version": "1.1.0"
|
||||
},
|
||||
"sentence-case": {
|
||||
"version": "1.1.1"
|
||||
},
|
||||
"snake-case": {
|
||||
"version": "1.0.1"
|
||||
"version": "1.1.0"
|
||||
},
|
||||
"swap-case": {
|
||||
"version": "1.0.2"
|
||||
"version": "1.1.0"
|
||||
},
|
||||
"title-case": {
|
||||
"version": "1.0.1"
|
||||
"version": "1.1.0"
|
||||
},
|
||||
"upper-case": {
|
||||
"version": "1.0.3"
|
||||
"version": "1.1.1"
|
||||
},
|
||||
"upper-case-first": {
|
||||
"version": "1.0.1"
|
||||
"version": "1.1.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"esprima": {
|
||||
"version": "1.2.2"
|
||||
"version": "1.2.3"
|
||||
},
|
||||
"estraverse": {
|
||||
"version": "1.7.1"
|
||||
"version": "1.9.1"
|
||||
},
|
||||
"glob": {
|
||||
"version": "3.2.11",
|
||||
@@ -1626,7 +1626,7 @@
|
||||
}
|
||||
},
|
||||
"node-uuid": {
|
||||
"version": "1.4.1"
|
||||
"version": "1.4.2"
|
||||
},
|
||||
"cookie-jar": {
|
||||
"version": "0.2.0"
|
||||
@@ -2342,26 +2342,32 @@
|
||||
},
|
||||
"grunt-jasmine-node": {
|
||||
"version": "0.1.0",
|
||||
"from": "grunt-jasmine-node@git://github.com/vojtajina/grunt-jasmine-node.git#ced17cbe52c1412b2ada53160432a5b681f37cd7",
|
||||
"from": "grunt-jasmine-node@git://github.com/vojtajina/grunt-jasmine-node.git#fix-grunt-exit-code",
|
||||
"resolved": "git://github.com/vojtajina/grunt-jasmine-node.git#ced17cbe52c1412b2ada53160432a5b681f37cd7"
|
||||
},
|
||||
"grunt-jscs": {
|
||||
"version": "0.7.1",
|
||||
"version": "1.2.0",
|
||||
"dependencies": {
|
||||
"hooker": {
|
||||
"version": "0.2.3"
|
||||
},
|
||||
"jscs": {
|
||||
"version": "1.6.2",
|
||||
"version": "1.10.0",
|
||||
"dependencies": {
|
||||
"colors": {
|
||||
"version": "0.6.2"
|
||||
"version": "1.0.3"
|
||||
},
|
||||
"commander": {
|
||||
"version": "2.3.0"
|
||||
"version": "2.5.1"
|
||||
},
|
||||
"esprima": {
|
||||
"version": "1.2.2"
|
||||
"version": "1.2.3"
|
||||
},
|
||||
"esprima-harmony-jscs": {
|
||||
"version": "1.1.0-regex-token-fix"
|
||||
},
|
||||
"estraverse": {
|
||||
"version": "1.9.1"
|
||||
},
|
||||
"exit": {
|
||||
"version": "0.1.2"
|
||||
@@ -2370,11 +2376,22 @@
|
||||
"version": "4.0.6",
|
||||
"dependencies": {
|
||||
"graceful-fs": {
|
||||
"version": "3.0.4"
|
||||
"version": "3.0.5"
|
||||
},
|
||||
"inherits": {
|
||||
"version": "2.0.1"
|
||||
},
|
||||
"minimatch": {
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"lru-cache": {
|
||||
"version": "2.5.0"
|
||||
},
|
||||
"sigmund": {
|
||||
"version": "1.0.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"once": {
|
||||
"version": "1.3.1",
|
||||
"dependencies": {
|
||||
@@ -2386,54 +2403,61 @@
|
||||
}
|
||||
},
|
||||
"minimatch": {
|
||||
"version": "1.0.0",
|
||||
"version": "2.0.1",
|
||||
"dependencies": {
|
||||
"lru-cache": {
|
||||
"version": "2.5.0"
|
||||
},
|
||||
"sigmund": {
|
||||
"version": "1.0.0"
|
||||
"brace-expansion": {
|
||||
"version": "1.1.0",
|
||||
"dependencies": {
|
||||
"balanced-match": {
|
||||
"version": "0.2.0"
|
||||
},
|
||||
"concat-map": {
|
||||
"version": "0.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"strip-json-comments": {
|
||||
"version": "1.0.1"
|
||||
"version": "1.0.2"
|
||||
},
|
||||
"vow-fs": {
|
||||
"version": "0.3.2",
|
||||
"version": "0.3.4",
|
||||
"dependencies": {
|
||||
"node-uuid": {
|
||||
"version": "1.4.0"
|
||||
},
|
||||
"vow": {
|
||||
"version": "0.4.4"
|
||||
"version": "1.4.2"
|
||||
},
|
||||
"vow-queue": {
|
||||
"version": "0.3.1"
|
||||
"version": "0.4.1"
|
||||
},
|
||||
"glob": {
|
||||
"version": "3.2.8",
|
||||
"version": "4.3.5",
|
||||
"dependencies": {
|
||||
"minimatch": {
|
||||
"version": "0.2.14",
|
||||
"inflight": {
|
||||
"version": "1.0.4",
|
||||
"dependencies": {
|
||||
"lru-cache": {
|
||||
"version": "2.5.0"
|
||||
},
|
||||
"sigmund": {
|
||||
"version": "1.0.0"
|
||||
"wrappy": {
|
||||
"version": "1.0.1"
|
||||
}
|
||||
}
|
||||
},
|
||||
"inherits": {
|
||||
"version": "2.0.1"
|
||||
},
|
||||
"once": {
|
||||
"version": "1.3.1",
|
||||
"dependencies": {
|
||||
"wrappy": {
|
||||
"version": "1.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"xmlbuilder": {
|
||||
"version": "2.4.4",
|
||||
"version": "2.4.6",
|
||||
"dependencies": {
|
||||
"lodash-node": {
|
||||
"version": "2.4.1"
|
||||
@@ -2441,12 +2465,12 @@
|
||||
}
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "1.1.0"
|
||||
"version": "1.2.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"vow": {
|
||||
"version": "0.4.5"
|
||||
"version": "0.4.8"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@
|
||||
"grunt-contrib-jshint": "~0.10.0",
|
||||
"grunt-ddescribe-iit": "~0.0.1",
|
||||
"grunt-jasmine-node": "git://github.com/vojtajina/grunt-jasmine-node.git#fix-grunt-exit-code",
|
||||
"grunt-jscs": "~0.7.1",
|
||||
"grunt-jscs": "~1.2.0",
|
||||
"grunt-merge-conflict": "~0.0.1",
|
||||
"grunt-shell": "~1.1.1",
|
||||
"gulp": "~3.8.0",
|
||||
|
||||
+3
-1
@@ -28,7 +28,6 @@
|
||||
"manualUppercase": false,
|
||||
"isArrayLike": false,
|
||||
"forEach": false,
|
||||
"sortedKeys": false,
|
||||
"forEachSorted": false,
|
||||
"reverseParams": false,
|
||||
"nextUid": false,
|
||||
@@ -153,6 +152,9 @@
|
||||
"urlResolve": false,
|
||||
"urlIsSameOrigin": false,
|
||||
|
||||
/* ng/controller.js */
|
||||
"identifierForController": false,
|
||||
|
||||
/* ng/compile.js */
|
||||
"directiveNormalize": false,
|
||||
|
||||
|
||||
+86
-14
@@ -22,7 +22,6 @@
|
||||
nodeName_: true,
|
||||
isArrayLike: true,
|
||||
forEach: true,
|
||||
sortedKeys: true,
|
||||
forEachSorted: true,
|
||||
reverseParams: true,
|
||||
nextUid: true,
|
||||
@@ -59,6 +58,7 @@
|
||||
shallowCopy: true,
|
||||
equals: true,
|
||||
csp: true,
|
||||
jq: true,
|
||||
concat: true,
|
||||
sliceArgs: true,
|
||||
bind: true,
|
||||
@@ -272,12 +272,8 @@ function forEach(obj, iterator, context) {
|
||||
return obj;
|
||||
}
|
||||
|
||||
function sortedKeys(obj) {
|
||||
return Object.keys(obj).sort();
|
||||
}
|
||||
|
||||
function forEachSorted(obj, iterator, context) {
|
||||
var keys = sortedKeys(obj);
|
||||
var keys = Object.keys(obj).sort();
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
iterator.call(context, obj[keys[i]], keys[i]);
|
||||
}
|
||||
@@ -317,8 +313,7 @@ function nextUid() {
|
||||
function setHashKey(obj, h) {
|
||||
if (h) {
|
||||
obj.$$hashKey = h;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
delete obj.$$hashKey;
|
||||
}
|
||||
}
|
||||
@@ -589,6 +584,12 @@ function isPromiseLike(obj) {
|
||||
}
|
||||
|
||||
|
||||
var TYPED_ARRAY_REGEXP = /^\[object (Uint8(Clamped)?)|(Uint16)|(Uint32)|(Int8)|(Int16)|(Int32)|(Float(32)|(64))Array\]$/;
|
||||
function isTypedArray(value) {
|
||||
return TYPED_ARRAY_REGEXP.test(toString.call(value));
|
||||
}
|
||||
|
||||
|
||||
var trim = function(value) {
|
||||
return isString(value) ? value.trim() : value;
|
||||
};
|
||||
@@ -626,8 +627,9 @@ function isElement(node) {
|
||||
*/
|
||||
function makeMap(str) {
|
||||
var obj = {}, items = str.split(","), i;
|
||||
for (i = 0; i < items.length; i++)
|
||||
obj[ items[i] ] = true;
|
||||
for (i = 0; i < items.length; i++) {
|
||||
obj[items[i]] = true;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
@@ -642,9 +644,10 @@ function includes(array, obj) {
|
||||
|
||||
function arrayRemove(array, value) {
|
||||
var index = array.indexOf(value);
|
||||
if (index >= 0)
|
||||
if (index >= 0) {
|
||||
array.splice(index, 1);
|
||||
return value;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -710,12 +713,18 @@ function copy(source, destination, stackSource, stackDest) {
|
||||
throw ngMinErr('cpws',
|
||||
"Can't copy! Making copies of Window or Scope instances is not supported.");
|
||||
}
|
||||
if (isTypedArray(destination)) {
|
||||
throw ngMinErr('cpta',
|
||||
"Can't copy! TypedArray destination cannot be mutated.");
|
||||
}
|
||||
|
||||
if (!destination) {
|
||||
destination = source;
|
||||
if (source) {
|
||||
if (isArray(source)) {
|
||||
destination = copy(source, [], stackSource, stackDest);
|
||||
} else if (isTypedArray(source)) {
|
||||
destination = new source.constructor(source);
|
||||
} else if (isDate(source)) {
|
||||
destination = new Date(source.getTime());
|
||||
} else if (isRegExp(source)) {
|
||||
@@ -893,7 +902,61 @@ var csp = function() {
|
||||
return (csp.isActive_ = active);
|
||||
};
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @module ng
|
||||
* @name ngJq
|
||||
*
|
||||
* @element ANY
|
||||
* @param {string=} the name of the library available under `window`
|
||||
* to be used for angular.element
|
||||
* @description
|
||||
* Use this directive to force the angular.element library. This should be
|
||||
* used to force either jqLite by leaving ng-jq blank or setting the name of
|
||||
* the jquery variable under window (eg. jQuery).
|
||||
*
|
||||
* Since this directive is global for the angular library, it is recommended
|
||||
* that it's added to the same element as ng-app or the HTML element, but it is not mandatory.
|
||||
* It needs to be noted that only the first instance of `ng-jq` will be used and all others
|
||||
* ignored.
|
||||
*
|
||||
* @example
|
||||
* This example shows how to force jqLite using the `ngJq` directive to the `html` tag.
|
||||
```html
|
||||
<!doctype html>
|
||||
<html ng-app ng-jq>
|
||||
...
|
||||
...
|
||||
</html>
|
||||
```
|
||||
* @example
|
||||
* This example shows how to use a jQuery based library of a different name.
|
||||
* The library name must be available at the top most 'window'.
|
||||
```html
|
||||
<!doctype html>
|
||||
<html ng-app ng-jq="jQueryLib">
|
||||
...
|
||||
...
|
||||
</html>
|
||||
```
|
||||
*/
|
||||
var jq = function() {
|
||||
if (isDefined(jq.name_)) return jq.name_;
|
||||
var el;
|
||||
var i, ii = ngAttrPrefixes.length;
|
||||
for (i = 0; i < ii; ++i) {
|
||||
if (el = document.querySelector('[' + ngAttrPrefixes[i].replace(':', '\\:') + 'jq]')) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var name;
|
||||
if (el) {
|
||||
name = getNgAttribute(el, "jq");
|
||||
}
|
||||
|
||||
return (jq.name_ = name);
|
||||
};
|
||||
|
||||
function concat(array1, array2, index) {
|
||||
return array1.concat(slice.call(array2, index));
|
||||
@@ -1408,8 +1471,12 @@ function bootstrap(element, modules, config) {
|
||||
forEach(extraModules, function(module) {
|
||||
modules.push(module);
|
||||
});
|
||||
doBootstrap();
|
||||
return doBootstrap();
|
||||
};
|
||||
|
||||
if (isFunction(angular.resumeDeferredBootstrap)) {
|
||||
angular.resumeDeferredBootstrap();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1462,7 +1529,12 @@ function bindJQuery() {
|
||||
}
|
||||
|
||||
// bind to jQuery if present;
|
||||
jQuery = window.jQuery;
|
||||
var jqName = jq();
|
||||
jQuery = window.jQuery; // use default jQuery.
|
||||
if (isDefined(jqName)) { // `ngJq` present
|
||||
jQuery = jqName === null ? undefined : window[jqName]; // if empty; use jqLite. if not empty, use jQuery specified by `ngJq`.
|
||||
}
|
||||
|
||||
// Use jQuery if it exists with proper functionality, otherwise default to us.
|
||||
// Angular 1.2+ requires jQuery 1.7+ for on()/off() support.
|
||||
// Angular 1.3+ technically requires at least jQuery 2.1+ but it may work with older
|
||||
|
||||
@@ -800,7 +800,7 @@ function createInjector(modulesToLoad, strictDi) {
|
||||
}
|
||||
|
||||
var args = [],
|
||||
$inject = annotate(fn, strictDi, serviceName),
|
||||
$inject = createInjector.$$annotate(fn, strictDi, serviceName),
|
||||
length, i,
|
||||
key;
|
||||
|
||||
@@ -839,7 +839,7 @@ function createInjector(modulesToLoad, strictDi) {
|
||||
invoke: invoke,
|
||||
instantiate: instantiate,
|
||||
get: getService,
|
||||
annotate: annotate,
|
||||
annotate: createInjector.$$annotate,
|
||||
has: function(name) {
|
||||
return providerCache.hasOwnProperty(name + providerSuffix) || cache.hasOwnProperty(name);
|
||||
}
|
||||
|
||||
+2
-1
@@ -851,8 +851,9 @@ forEach({
|
||||
children: function(element) {
|
||||
var children = [];
|
||||
forEach(element.childNodes, function(element) {
|
||||
if (element.nodeType === NODE_TYPE_ELEMENT)
|
||||
if (element.nodeType === NODE_TYPE_ELEMENT) {
|
||||
children.push(element);
|
||||
}
|
||||
});
|
||||
return children;
|
||||
},
|
||||
|
||||
+190
-94
@@ -64,7 +64,7 @@
|
||||
* templateNamespace: 'html',
|
||||
* scope: false,
|
||||
* controller: function($scope, $element, $attrs, $transclude, otherInjectables) { ... },
|
||||
* controllerAs: 'stringAlias',
|
||||
* controllerAs: 'stringIdentifier',
|
||||
* require: 'siblingDirectiveName', // or // ['^parentDirectiveName', '?optionalDirectiveName', '?^optionalParent'],
|
||||
* compile: function compile(tElement, tAttrs, transclude) {
|
||||
* return {
|
||||
@@ -224,9 +224,10 @@
|
||||
*
|
||||
*
|
||||
* #### `controllerAs`
|
||||
* Controller alias at the directive scope. An alias for the controller so it
|
||||
* can be referenced at the directive template. The directive needs to define a scope for this
|
||||
* configuration to be used. Useful in the case when directive is used as component.
|
||||
* Identifier name for a reference to the controller in the directive's scope.
|
||||
* This allows the controller to be referenced from the directive template. The directive
|
||||
* needs to define a scope for this configuration to be used. Useful in the case when
|
||||
* directive is used as component.
|
||||
*
|
||||
*
|
||||
* #### `restrict`
|
||||
@@ -712,7 +713,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
// 'on' and be composed of only English letters.
|
||||
var EVENT_HANDLER_ATTR_REGEXP = /^(on[a-z]+|formaction)$/;
|
||||
|
||||
function parseIsolateBindings(scope, directiveName) {
|
||||
function parseIsolateBindings(scope, directiveName, isController) {
|
||||
var LOCAL_REGEXP = /^\s*([@&]|=(\*?))(\??)\s*(\w*)\s*$/;
|
||||
|
||||
var bindings = {};
|
||||
@@ -722,9 +723,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
|
||||
if (!match) {
|
||||
throw $compileMinErr('iscp',
|
||||
"Invalid isolate scope definition for directive '{0}'." +
|
||||
"Invalid {3} for directive '{0}'." +
|
||||
" Definition: {... {1}: '{2}' ...}",
|
||||
directiveName, scopeName, definition);
|
||||
directiveName, scopeName, definition,
|
||||
(isController ? "controller bindings definition" :
|
||||
"isolate scope definition"));
|
||||
}
|
||||
|
||||
bindings[scopeName] = {
|
||||
@@ -738,6 +741,43 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
return bindings;
|
||||
}
|
||||
|
||||
function parseDirectiveBindings(directive, directiveName) {
|
||||
var bindings = {
|
||||
isolateScope: null,
|
||||
bindToController: null
|
||||
};
|
||||
if (isObject(directive.scope)) {
|
||||
if (directive.bindToController === true) {
|
||||
bindings.bindToController = parseIsolateBindings(directive.scope,
|
||||
directiveName, true);
|
||||
bindings.isolateScope = {};
|
||||
} else {
|
||||
bindings.isolateScope = parseIsolateBindings(directive.scope,
|
||||
directiveName, false);
|
||||
}
|
||||
}
|
||||
if (isObject(directive.bindToController)) {
|
||||
bindings.bindToController =
|
||||
parseIsolateBindings(directive.bindToController, directiveName, true);
|
||||
}
|
||||
if (isObject(bindings.bindToController)) {
|
||||
var controller = directive.controller;
|
||||
var controllerAs = directive.controllerAs;
|
||||
if (!controller) {
|
||||
// There is no controller, there may or may not be a controllerAs property
|
||||
throw $compileMinErr('noctrl',
|
||||
"Cannot bind to controller without directive '{0}'s controller.",
|
||||
directiveName);
|
||||
} else if (!identifierForController(controller, controllerAs)) {
|
||||
// There is a controller, but no identifier or controllerAs property
|
||||
throw $compileMinErr('noident',
|
||||
"Cannot bind to controller without identifier for directive '{0}'.",
|
||||
directiveName);
|
||||
}
|
||||
}
|
||||
return bindings;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name $compileProvider#directive
|
||||
@@ -775,8 +815,10 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
directive.name = directive.name || name;
|
||||
directive.require = directive.require || (directive.controller && directive.name);
|
||||
directive.restrict = directive.restrict || 'EA';
|
||||
if (isObject(directive.scope)) {
|
||||
directive.$$isolateBindings = parseIsolateBindings(directive.scope, directive.name);
|
||||
var bindings = directive.$$bindings =
|
||||
parseDirectiveBindings(directive, directive.name);
|
||||
if (isObject(bindings.isolateScope)) {
|
||||
directive.$$isolateBindings = bindings.isolateScope;
|
||||
}
|
||||
directives.push(directive);
|
||||
} catch (e) {
|
||||
@@ -1338,6 +1380,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
if (nodeLinkFn.scope) {
|
||||
childScope = scope.$new();
|
||||
compile.$$addScopeInfo(jqLite(node), childScope);
|
||||
var destroyBindings = nodeLinkFn.$$destroyBindings;
|
||||
if (destroyBindings) {
|
||||
nodeLinkFn.$$destroyBindings = null;
|
||||
childScope.$on('$destroyed', destroyBindings);
|
||||
}
|
||||
} else {
|
||||
childScope = scope;
|
||||
}
|
||||
@@ -1357,7 +1404,8 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
childBoundTranscludeFn = null;
|
||||
}
|
||||
|
||||
nodeLinkFn(childLinkFn, childScope, node, $rootElement, childBoundTranscludeFn);
|
||||
nodeLinkFn(childLinkFn, childScope, node, $rootElement, childBoundTranscludeFn,
|
||||
nodeLinkFn);
|
||||
|
||||
} else if (childLinkFn) {
|
||||
childLinkFn(scope, node.childNodes, undefined, parentBoundTranscludeFn);
|
||||
@@ -1838,7 +1886,8 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
}
|
||||
|
||||
|
||||
function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) {
|
||||
function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn,
|
||||
thisLinkFn) {
|
||||
var i, ii, linkFn, controller, isolateScope, elementControllers, transcludeFn, $element,
|
||||
attrs;
|
||||
|
||||
@@ -1895,91 +1944,42 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
}
|
||||
|
||||
if (newIsolateScopeDirective) {
|
||||
// Initialize isolate scope bindings for new isolate scope directive.
|
||||
compile.$$addScopeInfo($element, isolateScope, true, !(templateDirective && (templateDirective === newIsolateScopeDirective ||
|
||||
templateDirective === newIsolateScopeDirective.$$originalDirective)));
|
||||
compile.$$addScopeClass($element, true);
|
||||
|
||||
var isolateScopeController = controllers && controllers[newIsolateScopeDirective.name];
|
||||
var isolateBindingContext = isolateScope;
|
||||
if (isolateScopeController && isolateScopeController.identifier &&
|
||||
newIsolateScopeDirective.bindToController === true) {
|
||||
isolateBindingContext = isolateScopeController.instance;
|
||||
}
|
||||
|
||||
forEach(isolateScope.$$isolateBindings = newIsolateScopeDirective.$$isolateBindings, function(definition, scopeName) {
|
||||
var attrName = definition.attrName,
|
||||
optional = definition.optional,
|
||||
mode = definition.mode, // @, =, or &
|
||||
lastValue,
|
||||
parentGet, parentSet, compare;
|
||||
|
||||
switch (mode) {
|
||||
|
||||
case '@':
|
||||
attrs.$observe(attrName, function(value) {
|
||||
isolateBindingContext[scopeName] = value;
|
||||
});
|
||||
attrs.$$observers[attrName].$$scope = scope;
|
||||
if (attrs[attrName]) {
|
||||
// If the attribute has been provided then we trigger an interpolation to ensure
|
||||
// the value is there for use in the link fn
|
||||
isolateBindingContext[scopeName] = $interpolate(attrs[attrName])(scope);
|
||||
}
|
||||
break;
|
||||
|
||||
case '=':
|
||||
if (optional && !attrs[attrName]) {
|
||||
return;
|
||||
}
|
||||
parentGet = $parse(attrs[attrName]);
|
||||
if (parentGet.literal) {
|
||||
compare = equals;
|
||||
} else {
|
||||
compare = function(a, b) { return a === b || (a !== a && b !== b); };
|
||||
}
|
||||
parentSet = parentGet.assign || function() {
|
||||
// reset the change, or we will throw this exception on every $digest
|
||||
lastValue = isolateBindingContext[scopeName] = parentGet(scope);
|
||||
throw $compileMinErr('nonassign',
|
||||
"Expression '{0}' used with directive '{1}' is non-assignable!",
|
||||
attrs[attrName], newIsolateScopeDirective.name);
|
||||
};
|
||||
lastValue = isolateBindingContext[scopeName] = parentGet(scope);
|
||||
var parentValueWatch = function parentValueWatch(parentValue) {
|
||||
if (!compare(parentValue, isolateBindingContext[scopeName])) {
|
||||
// we are out of sync and need to copy
|
||||
if (!compare(parentValue, lastValue)) {
|
||||
// parent changed and it has precedence
|
||||
isolateBindingContext[scopeName] = parentValue;
|
||||
} else {
|
||||
// if the parent can be assigned then do so
|
||||
parentSet(scope, parentValue = isolateBindingContext[scopeName]);
|
||||
}
|
||||
}
|
||||
return lastValue = parentValue;
|
||||
};
|
||||
parentValueWatch.$stateful = true;
|
||||
var unwatch;
|
||||
if (definition.collection) {
|
||||
unwatch = scope.$watchCollection(attrs[attrName], parentValueWatch);
|
||||
} else {
|
||||
unwatch = scope.$watch($parse(attrs[attrName], parentValueWatch), null, parentGet.literal);
|
||||
}
|
||||
isolateScope.$on('$destroy', unwatch);
|
||||
break;
|
||||
|
||||
case '&':
|
||||
parentGet = $parse(attrs[attrName]);
|
||||
isolateBindingContext[scopeName] = function(locals) {
|
||||
return parentGet(scope, locals);
|
||||
};
|
||||
break;
|
||||
}
|
||||
});
|
||||
isolateScope.$$isolateBindings =
|
||||
newIsolateScopeDirective.$$isolateBindings;
|
||||
initializeDirectiveBindings(scope, attrs, isolateScope,
|
||||
isolateScope.$$isolateBindings,
|
||||
newIsolateScopeDirective, isolateScope);
|
||||
}
|
||||
if (controllers) {
|
||||
// Initialize bindToController bindings for new/isolate scopes
|
||||
var scopeDirective = newIsolateScopeDirective || newScopeDirective;
|
||||
var bindings;
|
||||
var controllerForBindings;
|
||||
if (scopeDirective && controllers[scopeDirective.name]) {
|
||||
bindings = scopeDirective.$$bindings.bindToController;
|
||||
controller = controllers[scopeDirective.name];
|
||||
|
||||
if (controller && controller.identifier && bindings) {
|
||||
controllerForBindings = controller;
|
||||
thisLinkFn.$$destroyBindings =
|
||||
initializeDirectiveBindings(scope, attrs, controller.instance,
|
||||
bindings, scopeDirective);
|
||||
}
|
||||
}
|
||||
forEach(controllers, function(controller) {
|
||||
controller();
|
||||
var result = controller();
|
||||
if (result !== controller.instance &&
|
||||
controller === controllerForBindings) {
|
||||
// Remove and re-install bindToController bindings
|
||||
thisLinkFn.$$destroyBindings();
|
||||
thisLinkFn.$$destroyBindings =
|
||||
initializeDirectiveBindings(scope, attrs, result,
|
||||
bindings, scopeDirective);
|
||||
}
|
||||
});
|
||||
controllers = null;
|
||||
}
|
||||
@@ -2155,8 +2155,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
afterTemplateChildLinkFn,
|
||||
beforeTemplateCompileNode = $compileNode[0],
|
||||
origAsyncDirective = directives.shift(),
|
||||
// The fact that we have to copy and patch the directive seems wrong!
|
||||
derivedSyncDirective = extend({}, origAsyncDirective, {
|
||||
derivedSyncDirective = inherit(origAsyncDirective, {
|
||||
templateUrl: null, transclude: null, replace: null, $$originalDirective: origAsyncDirective
|
||||
}),
|
||||
templateUrl = (isFunction(origAsyncDirective.templateUrl))
|
||||
@@ -2240,7 +2239,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
childBoundTranscludeFn = boundTranscludeFn;
|
||||
}
|
||||
afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, linkNode, $rootElement,
|
||||
childBoundTranscludeFn);
|
||||
childBoundTranscludeFn, afterTemplateNodeLinkFn);
|
||||
}
|
||||
linkQueue = null;
|
||||
});
|
||||
@@ -2257,7 +2256,8 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
if (afterTemplateNodeLinkFn.transcludeOnThisElement) {
|
||||
childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude, boundTranscludeFn);
|
||||
}
|
||||
afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, node, rootElement, childBoundTranscludeFn);
|
||||
afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, node, rootElement, childBoundTranscludeFn,
|
||||
afterTemplateNodeLinkFn);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -2504,6 +2504,102 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
$exceptionHandler(e, startingTag($element));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Set up $watches for isolate scope and controller bindings. This process
|
||||
// only occurs for isolate scopes and new scopes with controllerAs.
|
||||
function initializeDirectiveBindings(scope, attrs, destination, bindings,
|
||||
directive, newScope) {
|
||||
var onNewScopeDestroyed;
|
||||
forEach(bindings, function(definition, scopeName) {
|
||||
var attrName = definition.attrName,
|
||||
optional = definition.optional,
|
||||
mode = definition.mode, // @, =, or &
|
||||
lastValue,
|
||||
parentGet, parentSet, compare;
|
||||
|
||||
switch (mode) {
|
||||
|
||||
case '@':
|
||||
attrs.$observe(attrName, function(value) {
|
||||
destination[scopeName] = value;
|
||||
});
|
||||
attrs.$$observers[attrName].$$scope = scope;
|
||||
if (attrs[attrName]) {
|
||||
// If the attribute has been provided then we trigger an interpolation to ensure
|
||||
// the value is there for use in the link fn
|
||||
destination[scopeName] = $interpolate(attrs[attrName])(scope);
|
||||
}
|
||||
break;
|
||||
|
||||
case '=':
|
||||
if (optional && !attrs[attrName]) {
|
||||
return;
|
||||
}
|
||||
parentGet = $parse(attrs[attrName]);
|
||||
if (parentGet.literal) {
|
||||
compare = equals;
|
||||
} else {
|
||||
compare = function(a, b) { return a === b || (a !== a && b !== b); };
|
||||
}
|
||||
parentSet = parentGet.assign || function() {
|
||||
// reset the change, or we will throw this exception on every $digest
|
||||
lastValue = destination[scopeName] = parentGet(scope);
|
||||
throw $compileMinErr('nonassign',
|
||||
"Expression '{0}' used with directive '{1}' is non-assignable!",
|
||||
attrs[attrName], directive.name);
|
||||
};
|
||||
lastValue = destination[scopeName] = parentGet(scope);
|
||||
var parentValueWatch = function parentValueWatch(parentValue) {
|
||||
if (!compare(parentValue, destination[scopeName])) {
|
||||
// we are out of sync and need to copy
|
||||
if (!compare(parentValue, lastValue)) {
|
||||
// parent changed and it has precedence
|
||||
destination[scopeName] = parentValue;
|
||||
} else {
|
||||
// if the parent can be assigned then do so
|
||||
parentSet(scope, parentValue = destination[scopeName]);
|
||||
}
|
||||
}
|
||||
return lastValue = parentValue;
|
||||
};
|
||||
parentValueWatch.$stateful = true;
|
||||
var unwatch;
|
||||
if (definition.collection) {
|
||||
unwatch = scope.$watchCollection(attrs[attrName], parentValueWatch);
|
||||
} else {
|
||||
unwatch = scope.$watch($parse(attrs[attrName], parentValueWatch), null, parentGet.literal);
|
||||
}
|
||||
onNewScopeDestroyed = (onNewScopeDestroyed || []);
|
||||
onNewScopeDestroyed.push(unwatch);
|
||||
break;
|
||||
|
||||
case '&':
|
||||
// Don't assign Object.prototype method to scope
|
||||
if (!attrs.hasOwnProperty(attrName) && optional) break;
|
||||
|
||||
parentGet = $parse(attrs[attrName]);
|
||||
|
||||
// Don't assign noop to destination if expression is not valid
|
||||
if (parentGet === noop && optional) break;
|
||||
|
||||
destination[scopeName] = function(locals) {
|
||||
return parentGet(scope, locals);
|
||||
};
|
||||
break;
|
||||
}
|
||||
});
|
||||
var destroyBindings = onNewScopeDestroyed ? function destroyBindings() {
|
||||
for (var i = 0, ii = onNewScopeDestroyed.length; i < ii; ++i) {
|
||||
onNewScopeDestroyed[i]();
|
||||
}
|
||||
} : noop;
|
||||
if (newScope && destroyBindings !== noop) {
|
||||
newScope.$on('$destroy', destroyBindings);
|
||||
return noop;
|
||||
}
|
||||
return destroyBindings;
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
|
||||
+30
-6
@@ -1,5 +1,18 @@
|
||||
'use strict';
|
||||
|
||||
var $controllerMinErr = minErr('$controller');
|
||||
|
||||
|
||||
var CNTRL_REG = /^(\S+)(\s+as\s+(\w+))?$/;
|
||||
function identifierForController(controller, ident) {
|
||||
if (ident && isString(ident)) return ident;
|
||||
if (isString(controller)) {
|
||||
var match = CNTRL_REG.exec(controller);
|
||||
if (match) return match[3];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc provider
|
||||
* @name $controllerProvider
|
||||
@@ -12,9 +25,7 @@
|
||||
*/
|
||||
function $ControllerProvider() {
|
||||
var controllers = {},
|
||||
globals = false,
|
||||
CNTRL_REG = /^(\S+)(\s+as\s+(\w+))?$/;
|
||||
|
||||
globals = false;
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
@@ -87,7 +98,12 @@ function $ControllerProvider() {
|
||||
}
|
||||
|
||||
if (isString(expression)) {
|
||||
match = expression.match(CNTRL_REG),
|
||||
match = expression.match(CNTRL_REG);
|
||||
if (!match) {
|
||||
throw $controllerMinErr('ctrlfmt',
|
||||
"Badly formed controller string '{0}'. " +
|
||||
"Must match `__name__ as __id__` or `__name__`.", expression);
|
||||
}
|
||||
constructor = match[1],
|
||||
identifier = identifier || match[3];
|
||||
expression = controllers.hasOwnProperty(constructor)
|
||||
@@ -117,8 +133,16 @@ function $ControllerProvider() {
|
||||
addIdentifier(locals, identifier, instance, constructor || expression.name);
|
||||
}
|
||||
|
||||
return extend(function() {
|
||||
$injector.invoke(expression, instance, locals, constructor);
|
||||
var instantiate;
|
||||
return instantiate = extend(function() {
|
||||
var result = $injector.invoke(expression, instance, locals, constructor);
|
||||
if (result !== instance && (isObject(result) || isFunction(result))) {
|
||||
instance = result;
|
||||
if (identifier) {
|
||||
// If result changed, re-assign controllerAs value to scope.
|
||||
addIdentifier(locals, identifier, instance, constructor || expression.name);
|
||||
}
|
||||
}
|
||||
return instance;
|
||||
}, {
|
||||
instance: instance,
|
||||
|
||||
@@ -16,8 +16,11 @@
|
||||
var htmlAnchorDirective = valueFn({
|
||||
restrict: 'E',
|
||||
compile: function(element, attr) {
|
||||
if (!attr.href && !attr.xlinkHref && !attr.name) {
|
||||
if (!attr.href && !attr.xlinkHref) {
|
||||
return function(scope, element) {
|
||||
// If the linked element is not an anchor tag anymore, do nothing
|
||||
if (element[0].nodeName.toLowerCase() !== 'a') return;
|
||||
|
||||
// SVGAElement does not use the href attribute, but rather the 'xlinkHref' attribute.
|
||||
var href = toString.call(element.prop('href')) === '[object SVGAnimatedString]' ?
|
||||
'xlink:href' : 'href';
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
}, 5000, 'page should navigate to /123');
|
||||
});
|
||||
|
||||
xit('should execute ng-click but not reload when href empty string and name specified', function() {
|
||||
it('should execute ng-click but not reload when href empty string and name specified', function() {
|
||||
element(by.id('link-4')).click();
|
||||
expect(element(by.model('value')).getAttribute('value')).toEqual('4');
|
||||
expect(element(by.id('link-4')).getAttribute('href')).toBe('');
|
||||
|
||||
+86
-64
@@ -61,19 +61,21 @@ var inputType = {
|
||||
<script>
|
||||
angular.module('textInputExample', [])
|
||||
.controller('ExampleController', ['$scope', function($scope) {
|
||||
$scope.text = 'guest';
|
||||
$scope.word = /^\s*\w*\s*$/;
|
||||
$scope.example = {
|
||||
text: 'guest',
|
||||
word: /^\s*\w*\s*$/
|
||||
};
|
||||
}]);
|
||||
</script>
|
||||
<form name="myForm" ng-controller="ExampleController">
|
||||
Single word: <input type="text" name="input" ng-model="text"
|
||||
ng-pattern="word" required ng-trim="false">
|
||||
Single word: <input type="text" name="input" ng-model="example.text"
|
||||
ng-pattern="example.word" required ng-trim="false">
|
||||
<span class="error" ng-show="myForm.input.$error.required">
|
||||
Required!</span>
|
||||
<span class="error" ng-show="myForm.input.$error.pattern">
|
||||
Single word only!</span>
|
||||
|
||||
<tt>text = {{text}}</tt><br/>
|
||||
<tt>text = {{example.text}}</tt><br/>
|
||||
<tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
|
||||
<tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
|
||||
<tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
|
||||
@@ -81,9 +83,9 @@ var inputType = {
|
||||
</form>
|
||||
</file>
|
||||
<file name="protractor.js" type="protractor">
|
||||
var text = element(by.binding('text'));
|
||||
var text = element(by.binding('example.text'));
|
||||
var valid = element(by.binding('myForm.input.$valid'));
|
||||
var input = element(by.model('text'));
|
||||
var input = element(by.model('example.text'));
|
||||
|
||||
it('should initialize to model', function() {
|
||||
expect(text.getText()).toContain('guest');
|
||||
@@ -145,18 +147,20 @@ var inputType = {
|
||||
<script>
|
||||
angular.module('dateInputExample', [])
|
||||
.controller('DateController', ['$scope', function($scope) {
|
||||
$scope.value = new Date(2013, 9, 22);
|
||||
$scope.example = {
|
||||
value: new Date(2013, 9, 22)
|
||||
};
|
||||
}]);
|
||||
</script>
|
||||
<form name="myForm" ng-controller="DateController as dateCtrl">
|
||||
Pick a date in 2013:
|
||||
<input type="date" id="exampleInput" name="input" ng-model="value"
|
||||
<input type="date" id="exampleInput" name="input" ng-model="example.value"
|
||||
placeholder="yyyy-MM-dd" min="2013-01-01" max="2013-12-31" required />
|
||||
<span class="error" ng-show="myForm.input.$error.required">
|
||||
Required!</span>
|
||||
<span class="error" ng-show="myForm.input.$error.date">
|
||||
Not a valid date!</span>
|
||||
<tt>value = {{value | date: "yyyy-MM-dd"}}</tt><br/>
|
||||
<tt>value = {{example.value | date: "yyyy-MM-dd"}}</tt><br/>
|
||||
<tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
|
||||
<tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
|
||||
<tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
|
||||
@@ -164,9 +168,9 @@ var inputType = {
|
||||
</form>
|
||||
</file>
|
||||
<file name="protractor.js" type="protractor">
|
||||
var value = element(by.binding('value | date: "yyyy-MM-dd"'));
|
||||
var value = element(by.binding('example.value | date: "yyyy-MM-dd"'));
|
||||
var valid = element(by.binding('myForm.input.$valid'));
|
||||
var input = element(by.model('value'));
|
||||
var input = element(by.model('example.value'));
|
||||
|
||||
// currently protractor/webdriver does not support
|
||||
// sending keys to all known HTML5 input controls
|
||||
@@ -236,18 +240,20 @@ var inputType = {
|
||||
<script>
|
||||
angular.module('dateExample', [])
|
||||
.controller('DateController', ['$scope', function($scope) {
|
||||
$scope.value = new Date(2010, 11, 28, 14, 57);
|
||||
$scope.example = {
|
||||
value: new Date(2010, 11, 28, 14, 57)
|
||||
};
|
||||
}]);
|
||||
</script>
|
||||
<form name="myForm" ng-controller="DateController as dateCtrl">
|
||||
Pick a date between in 2013:
|
||||
<input type="datetime-local" id="exampleInput" name="input" ng-model="value"
|
||||
<input type="datetime-local" id="exampleInput" name="input" ng-model="example.value"
|
||||
placeholder="yyyy-MM-ddTHH:mm:ss" min="2001-01-01T00:00:00" max="2013-12-31T00:00:00" required />
|
||||
<span class="error" ng-show="myForm.input.$error.required">
|
||||
Required!</span>
|
||||
<span class="error" ng-show="myForm.input.$error.datetimelocal">
|
||||
Not a valid date!</span>
|
||||
<tt>value = {{value | date: "yyyy-MM-ddTHH:mm:ss"}}</tt><br/>
|
||||
<tt>value = {{example.value | date: "yyyy-MM-ddTHH:mm:ss"}}</tt><br/>
|
||||
<tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
|
||||
<tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
|
||||
<tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
|
||||
@@ -255,9 +261,9 @@ var inputType = {
|
||||
</form>
|
||||
</file>
|
||||
<file name="protractor.js" type="protractor">
|
||||
var value = element(by.binding('value | date: "yyyy-MM-ddTHH:mm:ss"'));
|
||||
var value = element(by.binding('example.value | date: "yyyy-MM-ddTHH:mm:ss"'));
|
||||
var valid = element(by.binding('myForm.input.$valid'));
|
||||
var input = element(by.model('value'));
|
||||
var input = element(by.model('example.value'));
|
||||
|
||||
// currently protractor/webdriver does not support
|
||||
// sending keys to all known HTML5 input controls
|
||||
@@ -328,18 +334,20 @@ var inputType = {
|
||||
<script>
|
||||
angular.module('timeExample', [])
|
||||
.controller('DateController', ['$scope', function($scope) {
|
||||
$scope.value = new Date(1970, 0, 1, 14, 57, 0);
|
||||
$scope.example = {
|
||||
value: new Date(1970, 0, 1, 14, 57, 0)
|
||||
};
|
||||
}]);
|
||||
</script>
|
||||
<form name="myForm" ng-controller="DateController as dateCtrl">
|
||||
Pick a between 8am and 5pm:
|
||||
<input type="time" id="exampleInput" name="input" ng-model="value"
|
||||
<input type="time" id="exampleInput" name="input" ng-model="example.value"
|
||||
placeholder="HH:mm:ss" min="08:00:00" max="17:00:00" required />
|
||||
<span class="error" ng-show="myForm.input.$error.required">
|
||||
Required!</span>
|
||||
<span class="error" ng-show="myForm.input.$error.time">
|
||||
Not a valid date!</span>
|
||||
<tt>value = {{value | date: "HH:mm:ss"}}</tt><br/>
|
||||
<tt>value = {{example.value | date: "HH:mm:ss"}}</tt><br/>
|
||||
<tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
|
||||
<tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
|
||||
<tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
|
||||
@@ -347,9 +355,9 @@ var inputType = {
|
||||
</form>
|
||||
</file>
|
||||
<file name="protractor.js" type="protractor">
|
||||
var value = element(by.binding('value | date: "HH:mm:ss"'));
|
||||
var value = element(by.binding('example.value | date: "HH:mm:ss"'));
|
||||
var valid = element(by.binding('myForm.input.$valid'));
|
||||
var input = element(by.model('value'));
|
||||
var input = element(by.model('example.value'));
|
||||
|
||||
// currently protractor/webdriver does not support
|
||||
// sending keys to all known HTML5 input controls
|
||||
@@ -419,18 +427,20 @@ var inputType = {
|
||||
<script>
|
||||
angular.module('weekExample', [])
|
||||
.controller('DateController', ['$scope', function($scope) {
|
||||
$scope.value = new Date(2013, 0, 3);
|
||||
$scope.example = {
|
||||
value: new Date(2013, 0, 3)
|
||||
};
|
||||
}]);
|
||||
</script>
|
||||
<form name="myForm" ng-controller="DateController as dateCtrl">
|
||||
Pick a date between in 2013:
|
||||
<input id="exampleInput" type="week" name="input" ng-model="value"
|
||||
<input id="exampleInput" type="week" name="input" ng-model="example.value"
|
||||
placeholder="YYYY-W##" min="2012-W32" max="2013-W52" required />
|
||||
<span class="error" ng-show="myForm.input.$error.required">
|
||||
Required!</span>
|
||||
<span class="error" ng-show="myForm.input.$error.week">
|
||||
Not a valid date!</span>
|
||||
<tt>value = {{value | date: "yyyy-Www"}}</tt><br/>
|
||||
<tt>value = {{example.value | date: "yyyy-Www"}}</tt><br/>
|
||||
<tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
|
||||
<tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
|
||||
<tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
|
||||
@@ -438,9 +448,9 @@ var inputType = {
|
||||
</form>
|
||||
</file>
|
||||
<file name="protractor.js" type="protractor">
|
||||
var value = element(by.binding('value | date: "yyyy-Www"'));
|
||||
var value = element(by.binding('example.value | date: "yyyy-Www"'));
|
||||
var valid = element(by.binding('myForm.input.$valid'));
|
||||
var input = element(by.model('value'));
|
||||
var input = element(by.model('example.value'));
|
||||
|
||||
// currently protractor/webdriver does not support
|
||||
// sending keys to all known HTML5 input controls
|
||||
@@ -510,18 +520,20 @@ var inputType = {
|
||||
<script>
|
||||
angular.module('monthExample', [])
|
||||
.controller('DateController', ['$scope', function($scope) {
|
||||
$scope.value = new Date(2013, 9, 1);
|
||||
$scope.example = {
|
||||
value: new Date(2013, 9, 1)
|
||||
};
|
||||
}]);
|
||||
</script>
|
||||
<form name="myForm" ng-controller="DateController as dateCtrl">
|
||||
Pick a month in 2013:
|
||||
<input id="exampleInput" type="month" name="input" ng-model="value"
|
||||
<input id="exampleInput" type="month" name="input" ng-model="example.value"
|
||||
placeholder="yyyy-MM" min="2013-01" max="2013-12" required />
|
||||
<span class="error" ng-show="myForm.input.$error.required">
|
||||
Required!</span>
|
||||
<span class="error" ng-show="myForm.input.$error.month">
|
||||
Not a valid month!</span>
|
||||
<tt>value = {{value | date: "yyyy-MM"}}</tt><br/>
|
||||
<tt>value = {{example.value | date: "yyyy-MM"}}</tt><br/>
|
||||
<tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
|
||||
<tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
|
||||
<tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
|
||||
@@ -529,9 +541,9 @@ var inputType = {
|
||||
</form>
|
||||
</file>
|
||||
<file name="protractor.js" type="protractor">
|
||||
var value = element(by.binding('value | date: "yyyy-MM"'));
|
||||
var value = element(by.binding('example.value | date: "yyyy-MM"'));
|
||||
var valid = element(by.binding('myForm.input.$valid'));
|
||||
var input = element(by.model('value'));
|
||||
var input = element(by.model('example.value'));
|
||||
|
||||
// currently protractor/webdriver does not support
|
||||
// sending keys to all known HTML5 input controls
|
||||
@@ -607,17 +619,19 @@ var inputType = {
|
||||
<script>
|
||||
angular.module('numberExample', [])
|
||||
.controller('ExampleController', ['$scope', function($scope) {
|
||||
$scope.value = 12;
|
||||
$scope.example = {
|
||||
value: 12
|
||||
};
|
||||
}]);
|
||||
</script>
|
||||
<form name="myForm" ng-controller="ExampleController">
|
||||
Number: <input type="number" name="input" ng-model="value"
|
||||
Number: <input type="number" name="input" ng-model="example.value"
|
||||
min="0" max="99" required>
|
||||
<span class="error" ng-show="myForm.input.$error.required">
|
||||
Required!</span>
|
||||
<span class="error" ng-show="myForm.input.$error.number">
|
||||
Not valid number!</span>
|
||||
<tt>value = {{value}}</tt><br/>
|
||||
<tt>value = {{example.value}}</tt><br/>
|
||||
<tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
|
||||
<tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
|
||||
<tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
|
||||
@@ -625,9 +639,9 @@ var inputType = {
|
||||
</form>
|
||||
</file>
|
||||
<file name="protractor.js" type="protractor">
|
||||
var value = element(by.binding('value'));
|
||||
var value = element(by.binding('example.value'));
|
||||
var valid = element(by.binding('myForm.input.$valid'));
|
||||
var input = element(by.model('value'));
|
||||
var input = element(by.model('example.value'));
|
||||
|
||||
it('should initialize to model', function() {
|
||||
expect(value.getText()).toContain('12');
|
||||
@@ -695,16 +709,18 @@ var inputType = {
|
||||
<script>
|
||||
angular.module('urlExample', [])
|
||||
.controller('ExampleController', ['$scope', function($scope) {
|
||||
$scope.text = 'http://google.com';
|
||||
$scope.url = {
|
||||
text: 'http://google.com'
|
||||
};
|
||||
}]);
|
||||
</script>
|
||||
<form name="myForm" ng-controller="ExampleController">
|
||||
URL: <input type="url" name="input" ng-model="text" required>
|
||||
URL: <input type="url" name="input" ng-model="url.text" required>
|
||||
<span class="error" ng-show="myForm.input.$error.required">
|
||||
Required!</span>
|
||||
<span class="error" ng-show="myForm.input.$error.url">
|
||||
Not valid url!</span>
|
||||
<tt>text = {{text}}</tt><br/>
|
||||
<tt>text = {{url.text}}</tt><br/>
|
||||
<tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
|
||||
<tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
|
||||
<tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
|
||||
@@ -713,9 +729,9 @@ var inputType = {
|
||||
</form>
|
||||
</file>
|
||||
<file name="protractor.js" type="protractor">
|
||||
var text = element(by.binding('text'));
|
||||
var text = element(by.binding('url.text'));
|
||||
var valid = element(by.binding('myForm.input.$valid'));
|
||||
var input = element(by.model('text'));
|
||||
var input = element(by.model('url.text'));
|
||||
|
||||
it('should initialize to model', function() {
|
||||
expect(text.getText()).toContain('http://google.com');
|
||||
@@ -784,16 +800,18 @@ var inputType = {
|
||||
<script>
|
||||
angular.module('emailExample', [])
|
||||
.controller('ExampleController', ['$scope', function($scope) {
|
||||
$scope.text = 'me@example.com';
|
||||
$scope.email = {
|
||||
text: 'me@example.com'
|
||||
};
|
||||
}]);
|
||||
</script>
|
||||
<form name="myForm" ng-controller="ExampleController">
|
||||
Email: <input type="email" name="input" ng-model="text" required>
|
||||
Email: <input type="email" name="input" ng-model="email.text" required>
|
||||
<span class="error" ng-show="myForm.input.$error.required">
|
||||
Required!</span>
|
||||
<span class="error" ng-show="myForm.input.$error.email">
|
||||
Not valid email!</span>
|
||||
<tt>text = {{text}}</tt><br/>
|
||||
<tt>text = {{email.text}}</tt><br/>
|
||||
<tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
|
||||
<tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
|
||||
<tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
|
||||
@@ -802,9 +820,9 @@ var inputType = {
|
||||
</form>
|
||||
</file>
|
||||
<file name="protractor.js" type="protractor">
|
||||
var text = element(by.binding('text'));
|
||||
var text = element(by.binding('email.text'));
|
||||
var valid = element(by.binding('myForm.input.$valid'));
|
||||
var input = element(by.model('text'));
|
||||
var input = element(by.model('email.text'));
|
||||
|
||||
it('should initialize to model', function() {
|
||||
expect(text.getText()).toContain('me@example.com');
|
||||
@@ -851,7 +869,9 @@ var inputType = {
|
||||
<script>
|
||||
angular.module('radioExample', [])
|
||||
.controller('ExampleController', ['$scope', function($scope) {
|
||||
$scope.color = 'blue';
|
||||
$scope.color = {
|
||||
name: 'blue'
|
||||
};
|
||||
$scope.specialValue = {
|
||||
"id": "12345",
|
||||
"value": "green"
|
||||
@@ -859,20 +879,20 @@ var inputType = {
|
||||
}]);
|
||||
</script>
|
||||
<form name="myForm" ng-controller="ExampleController">
|
||||
<input type="radio" ng-model="color" value="red"> Red <br/>
|
||||
<input type="radio" ng-model="color" ng-value="specialValue"> Green <br/>
|
||||
<input type="radio" ng-model="color" value="blue"> Blue <br/>
|
||||
<tt>color = {{color | json}}</tt><br/>
|
||||
<input type="radio" ng-model="color.name" value="red"> Red <br/>
|
||||
<input type="radio" ng-model="color.name" ng-value="specialValue"> Green <br/>
|
||||
<input type="radio" ng-model="color.name" value="blue"> Blue <br/>
|
||||
<tt>color = {{color.name | json}}</tt><br/>
|
||||
</form>
|
||||
Note that `ng-value="specialValue"` sets radio item's value to be the value of `$scope.specialValue`.
|
||||
</file>
|
||||
<file name="protractor.js" type="protractor">
|
||||
it('should change state', function() {
|
||||
var color = element(by.binding('color'));
|
||||
var color = element(by.binding('color.name'));
|
||||
|
||||
expect(color.getText()).toContain('blue');
|
||||
|
||||
element.all(by.model('color')).get(0).click();
|
||||
element.all(by.model('color.name')).get(0).click();
|
||||
|
||||
expect(color.getText()).toContain('red');
|
||||
});
|
||||
@@ -902,28 +922,30 @@ var inputType = {
|
||||
<script>
|
||||
angular.module('checkboxExample', [])
|
||||
.controller('ExampleController', ['$scope', function($scope) {
|
||||
$scope.value1 = true;
|
||||
$scope.value2 = 'YES'
|
||||
$scope.checkboxModel = {
|
||||
value1 : true,
|
||||
value2 : 'YES'
|
||||
};
|
||||
}]);
|
||||
</script>
|
||||
<form name="myForm" ng-controller="ExampleController">
|
||||
Value1: <input type="checkbox" ng-model="value1"> <br/>
|
||||
Value2: <input type="checkbox" ng-model="value2"
|
||||
Value1: <input type="checkbox" ng-model="checkboxModel.value1"> <br/>
|
||||
Value2: <input type="checkbox" ng-model="checkboxModel.value2"
|
||||
ng-true-value="'YES'" ng-false-value="'NO'"> <br/>
|
||||
<tt>value1 = {{value1}}</tt><br/>
|
||||
<tt>value2 = {{value2}}</tt><br/>
|
||||
<tt>value1 = {{checkboxModel.value1}}</tt><br/>
|
||||
<tt>value2 = {{checkboxModel.value2}}</tt><br/>
|
||||
</form>
|
||||
</file>
|
||||
<file name="protractor.js" type="protractor">
|
||||
it('should change state', function() {
|
||||
var value1 = element(by.binding('value1'));
|
||||
var value2 = element(by.binding('value2'));
|
||||
var value1 = element(by.binding('checkboxModel.value1'));
|
||||
var value2 = element(by.binding('checkboxModel.value2'));
|
||||
|
||||
expect(value1.getText()).toContain('true');
|
||||
expect(value2.getText()).toContain('YES');
|
||||
|
||||
element(by.model('value1')).click();
|
||||
element(by.model('value2')).click();
|
||||
element(by.model('checkboxModel.value1')).click();
|
||||
element(by.model('checkboxModel.value2')).click();
|
||||
|
||||
expect(value1.getText()).toContain('false');
|
||||
expect(value2.getText()).toContain('NO');
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
* **Note**: If you have assignment in `ngInit` along with {@link ng.$filter `$filter`}, make
|
||||
* sure you have parenthesis for correct precedence:
|
||||
* <pre class="prettyprint">
|
||||
* <div ng-init="test1 = (data | orderBy:'name')"></div>
|
||||
* `<div ng-init="test1 = (data | orderBy:'name')"></div>`
|
||||
* </pre>
|
||||
* </div>
|
||||
*
|
||||
|
||||
@@ -217,11 +217,13 @@ var ngPluralizeDirective = ['$locale', '$interpolate', '$log', function($locale,
|
||||
|
||||
// If both `count` and `lastCount` are NaN, we don't need to re-register a watch.
|
||||
// In JS `NaN !== NaN`, so we have to exlicitly check.
|
||||
if ((count !== lastCount) && !(countIsNaN && isNaN(lastCount))) {
|
||||
if ((count !== lastCount) && !(countIsNaN && isNumber(lastCount) && isNaN(lastCount))) {
|
||||
watchRemover();
|
||||
var whenExpFn = whensExpFns[count];
|
||||
if (isUndefined(whenExpFn)) {
|
||||
$log.debug("ngPluralize: no rule defined for '" + count + "' in " + whenExp);
|
||||
if (newVal != null) {
|
||||
$log.debug("ngPluralize: no rule defined for '" + count + "' in " + whenExp);
|
||||
}
|
||||
watchRemover = noop;
|
||||
updateElementText();
|
||||
} else {
|
||||
|
||||
@@ -40,10 +40,11 @@ var NG_HIDE_IN_PROGRESS_CLASS = 'ng-hide-animate';
|
||||
*
|
||||
* By default, the `.ng-hide` class will style the element with `display: none!important`. If you wish to change
|
||||
* the hide behavior with ngShow/ngHide then this can be achieved by restating the styles for the `.ng-hide`
|
||||
* class in CSS:
|
||||
* class CSS. Note that the selector that needs to be used is actually `.ng-hide:not(.ng-hide-animate)` to cope
|
||||
* with extra animation classes that can be added.
|
||||
*
|
||||
* ```css
|
||||
* .ng-hide {
|
||||
* .ng-hide:not(.ng-hide-animate) {
|
||||
* /* this is just another form of hiding an element */
|
||||
* display: block!important;
|
||||
* position: absolute;
|
||||
|
||||
@@ -114,12 +114,12 @@ var SelectController =
|
||||
* @description
|
||||
* HTML `SELECT` element with angular data-binding.
|
||||
*
|
||||
* In many cases, `ngRepeat` can be used on `<option>` elements instead of `ngOptions` to achieve a
|
||||
* similar result. However, `ngOptions` provides some benefits such as reducing memory and
|
||||
* increasing speed by not creating a new scope for each repeated instance, as well as providing
|
||||
* In many cases, `ngRepeat` can be used on `<option>` elements instead of {@link ng.directive:ngOptions
|
||||
* ngOptions} to achieve a similar result. However, `ngOptions` provides some benefits such as reducing
|
||||
* memory and increasing speed by not creating a new scope for each repeated instance, as well as providing
|
||||
* more flexibility in how the `<select>`'s model is assigned via the `select` **`as`** part of the
|
||||
* comprehension expression. `ngOptions` should be used when the `<select>` model needs to be bound
|
||||
* to a non-string value. This is because an option element can only be bound to string values at
|
||||
* to a non-string value. This is because an option element can only be bound to string values at
|
||||
* present.
|
||||
*
|
||||
* When an item in the `<select>` menu is selected, the array element or object property
|
||||
|
||||
@@ -65,7 +65,7 @@ var maxlengthDirective = function() {
|
||||
ctrl.$validate();
|
||||
});
|
||||
ctrl.$validators.maxlength = function(modelValue, viewValue) {
|
||||
return (maxlength < 0) || ctrl.$isEmpty(modelValue) || (viewValue.length <= maxlength);
|
||||
return (maxlength < 0) || ctrl.$isEmpty(viewValue) || (viewValue.length <= maxlength);
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
@@ -124,7 +124,13 @@
|
||||
*/
|
||||
function filterFilter() {
|
||||
return function(array, expression, comparator) {
|
||||
if (!isArray(array)) return array;
|
||||
if (!isArray(array)) {
|
||||
if (array == null) {
|
||||
return array;
|
||||
} else {
|
||||
throw minErr('filter')('notarray', 'Expected array but received: {0}', array);
|
||||
}
|
||||
}
|
||||
|
||||
var predicateFn;
|
||||
var matchAgainstAnyProp;
|
||||
|
||||
@@ -234,8 +234,9 @@ function padNumber(num, digits, trim) {
|
||||
}
|
||||
num = '' + num;
|
||||
while (num.length < digits) num = '0' + num;
|
||||
if (trim)
|
||||
if (trim) {
|
||||
num = num.substr(num.length - digits);
|
||||
}
|
||||
return neg + num;
|
||||
}
|
||||
|
||||
@@ -244,8 +245,9 @@ function dateGetter(name, size, offset, trim) {
|
||||
offset = offset || 0;
|
||||
return function(date) {
|
||||
var value = date['get' + name]();
|
||||
if (offset > 0 || value > -offset)
|
||||
if (offset > 0 || value > -offset) {
|
||||
value += offset;
|
||||
}
|
||||
if (value === 0 && offset == -12) value = 12;
|
||||
return padNumber(value, size, trim);
|
||||
};
|
||||
@@ -260,8 +262,8 @@ function dateStrGetter(name, shortForm) {
|
||||
};
|
||||
}
|
||||
|
||||
function timeZoneGetter(date) {
|
||||
var zone = -1 * date.getTimezoneOffset();
|
||||
function timeZoneGetter(date, formats, offset) {
|
||||
var zone = -1 * offset;
|
||||
var paddedZone = (zone >= 0) ? "+" : "";
|
||||
|
||||
paddedZone += padNumber(Math[zone > 0 ? 'floor' : 'ceil'](zone / 60), 2) +
|
||||
@@ -482,13 +484,18 @@ function dateFilter($locale) {
|
||||
}
|
||||
}
|
||||
|
||||
if (timezone && timezone === 'UTC') {
|
||||
date = new Date(date.getTime());
|
||||
date.setMinutes(date.getMinutes() + date.getTimezoneOffset());
|
||||
var dateTimezoneOffset = date.getTimezoneOffset();
|
||||
if (timezone) {
|
||||
var requestedTimezoneOffset = Date.parse('Jan 01, 1970 00:00:00 ' + timezone) / 60000;
|
||||
if (!isNaN(requestedTimezoneOffset)) {
|
||||
date = new Date(date.getTime());
|
||||
date.setMinutes(date.getMinutes() + dateTimezoneOffset - requestedTimezoneOffset);
|
||||
dateTimezoneOffset = requestedTimezoneOffset;
|
||||
}
|
||||
}
|
||||
forEach(parts, function(value) {
|
||||
fn = DATE_FORMATS[value];
|
||||
text += fn ? fn(date, $locale.DATETIME_FORMATS)
|
||||
text += fn ? fn(date, $locale.DATETIME_FORMATS, dateTimezoneOffset)
|
||||
: value.replace(/(^'|'$)/g, '').replace(/''/g, "'");
|
||||
});
|
||||
|
||||
|
||||
+2
-1
@@ -98,8 +98,9 @@ function headersGetter(headers) {
|
||||
* @returns {*} Transformed data.
|
||||
*/
|
||||
function transformData(data, headers, status, fns) {
|
||||
if (isFunction(fns))
|
||||
if (isFunction(fns)) {
|
||||
return fns(data, headers, status);
|
||||
}
|
||||
|
||||
forEach(fns, function(fn) {
|
||||
data = fn(data, headers, status);
|
||||
|
||||
+22
-22
@@ -88,6 +88,28 @@ function $InterpolateProvider() {
|
||||
return '\\\\\\' + ch;
|
||||
}
|
||||
|
||||
function unescapeText(text) {
|
||||
return text.replace(escapedStartRegexp, startSymbol).
|
||||
replace(escapedEndRegexp, endSymbol);
|
||||
}
|
||||
|
||||
function stringify(value) {
|
||||
if (value == null) { // null || undefined
|
||||
return '';
|
||||
}
|
||||
switch (typeof value) {
|
||||
case 'string':
|
||||
break;
|
||||
case 'number':
|
||||
value = '' + value;
|
||||
break;
|
||||
default:
|
||||
value = toJson(value);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ngdoc service
|
||||
* @name $interpolate
|
||||
@@ -243,23 +265,6 @@ function $InterpolateProvider() {
|
||||
$sce.valueOf(value);
|
||||
};
|
||||
|
||||
var stringify = function(value) {
|
||||
if (value == null) { // null || undefined
|
||||
return '';
|
||||
}
|
||||
switch (typeof value) {
|
||||
case 'string':
|
||||
break;
|
||||
case 'number':
|
||||
value = '' + value;
|
||||
break;
|
||||
default:
|
||||
value = toJson(value);
|
||||
}
|
||||
|
||||
return value;
|
||||
};
|
||||
|
||||
return extend(function interpolationFn(context) {
|
||||
var i = 0;
|
||||
var ii = expressions.length;
|
||||
@@ -294,11 +299,6 @@ function $InterpolateProvider() {
|
||||
});
|
||||
}
|
||||
|
||||
function unescapeText(text) {
|
||||
return text.replace(escapedStartRegexp, startSymbol).
|
||||
replace(escapedEndRegexp, endSymbol);
|
||||
}
|
||||
|
||||
function parseStringifyInterceptor(value) {
|
||||
try {
|
||||
value = getValue(value);
|
||||
|
||||
+8
-5
@@ -373,8 +373,9 @@ var locationPrototype = {
|
||||
* @return {string} url
|
||||
*/
|
||||
url: function(url) {
|
||||
if (isUndefined(url))
|
||||
if (isUndefined(url)) {
|
||||
return this.$$url;
|
||||
}
|
||||
|
||||
var match = PATH_MATCH.exec(url);
|
||||
if (match[1] || url === '') this.path(decodeURIComponent(match[1]));
|
||||
@@ -613,8 +614,9 @@ forEach([LocationHashbangInHtml5Url, LocationHashbangUrl, LocationHtml5Url], fun
|
||||
* @return {object} state
|
||||
*/
|
||||
Location.prototype.state = function(state) {
|
||||
if (!arguments.length)
|
||||
if (!arguments.length) {
|
||||
return this.$$state;
|
||||
}
|
||||
|
||||
if (Location !== LocationHtml5Url || !this.$$html5) {
|
||||
throw $locationMinErr('nostate', 'History API state support is available only ' +
|
||||
@@ -639,8 +641,9 @@ function locationGetter(property) {
|
||||
|
||||
function locationGetterSetter(property, preprocess) {
|
||||
return function(value) {
|
||||
if (isUndefined(value))
|
||||
if (isUndefined(value)) {
|
||||
return this[property];
|
||||
}
|
||||
|
||||
this[property] = preprocess(value);
|
||||
this.$$compose();
|
||||
@@ -837,7 +840,7 @@ function $LocationProvider() {
|
||||
// TODO(vojta): rewrite link when opening in new tab/window (in legacy browser)
|
||||
// currently we open nice url link and redirect then
|
||||
|
||||
if (!html5Mode.rewriteLinks || event.ctrlKey || event.metaKey || event.which == 2 || event.button == 2) return;
|
||||
if (!html5Mode.rewriteLinks || event.ctrlKey || event.metaKey || event.shiftKey || event.which == 2 || event.button == 2) return;
|
||||
|
||||
var elm = jqLite(event.target);
|
||||
|
||||
@@ -879,7 +882,7 @@ function $LocationProvider() {
|
||||
|
||||
|
||||
// rewrite hashbang url <> html5 url
|
||||
if ($location.absUrl() != initialUrl) {
|
||||
if (trimEmptyHash($location.absUrl()) != trimEmptyHash(initialUrl)) {
|
||||
$browser.url($location.absUrl(), true);
|
||||
}
|
||||
|
||||
|
||||
+1271
-627
File diff suppressed because it is too large
Load Diff
+7
-8
@@ -302,24 +302,24 @@ function qFactory(nextTick, exceptionHandler) {
|
||||
}
|
||||
|
||||
function processQueue(state) {
|
||||
var fn, promise, pending;
|
||||
var fn, deferred, pending;
|
||||
|
||||
pending = state.pending;
|
||||
state.processScheduled = false;
|
||||
state.pending = undefined;
|
||||
for (var i = 0, ii = pending.length; i < ii; ++i) {
|
||||
promise = pending[i][0];
|
||||
deferred = pending[i][0];
|
||||
fn = pending[i][state.status];
|
||||
try {
|
||||
if (isFunction(fn)) {
|
||||
promise.resolve(fn(state.value));
|
||||
deferred.resolve(fn(state.value));
|
||||
} else if (state.status === 1) {
|
||||
promise.resolve(state.value);
|
||||
deferred.resolve(state.value);
|
||||
} else {
|
||||
promise.reject(state.value);
|
||||
deferred.reject(state.value);
|
||||
}
|
||||
} catch (e) {
|
||||
promise.reject(e);
|
||||
deferred.reject(e);
|
||||
exceptionHandler(e);
|
||||
}
|
||||
}
|
||||
@@ -347,8 +347,7 @@ function qFactory(nextTick, exceptionHandler) {
|
||||
'qcycle',
|
||||
"Expected promise to be resolved with value other than itself '{0}'",
|
||||
val));
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
this.$$resolve(val);
|
||||
}
|
||||
|
||||
|
||||
+16
-5
@@ -135,6 +135,7 @@ function $RootScopeProvider() {
|
||||
this.$$destroyed = false;
|
||||
this.$$listeners = {};
|
||||
this.$$listenerCount = {};
|
||||
this.$$watchersCount = 0;
|
||||
this.$$isolateBindings = null;
|
||||
}
|
||||
|
||||
@@ -210,6 +211,7 @@ function $RootScopeProvider() {
|
||||
this.$$childHead = this.$$childTail = null;
|
||||
this.$$listeners = {};
|
||||
this.$$listenerCount = {};
|
||||
this.$$watchersCount = 0;
|
||||
this.$id = nextUid();
|
||||
this.$$ChildScope = null;
|
||||
};
|
||||
@@ -356,11 +358,11 @@ function $RootScopeProvider() {
|
||||
* comparing for reference equality.
|
||||
* @returns {function()} Returns a deregistration function for this listener.
|
||||
*/
|
||||
$watch: function(watchExp, listener, objectEquality) {
|
||||
$watch: function(watchExp, listener, objectEquality, prettyPrintExpression) {
|
||||
var get = $parse(watchExp);
|
||||
|
||||
if (get.$$watchDelegate) {
|
||||
return get.$$watchDelegate(this, listener, objectEquality, get);
|
||||
return get.$$watchDelegate(this, listener, objectEquality, get, watchExp);
|
||||
}
|
||||
var scope = this,
|
||||
array = scope.$$watchers,
|
||||
@@ -368,7 +370,7 @@ function $RootScopeProvider() {
|
||||
fn: listener,
|
||||
last: initWatchVal,
|
||||
get: get,
|
||||
exp: watchExp,
|
||||
exp: prettyPrintExpression || watchExp,
|
||||
eq: !!objectEquality
|
||||
};
|
||||
|
||||
@@ -384,9 +386,12 @@ function $RootScopeProvider() {
|
||||
// we use unshift since we use a while loop in $digest for speed.
|
||||
// the while loop reads in reverse order.
|
||||
array.unshift(watcher);
|
||||
incrementWatchersCount(this, 1);
|
||||
|
||||
return function deregisterWatch() {
|
||||
arrayRemove(array, watcher);
|
||||
if (arrayRemove(array, watcher) >= 0) {
|
||||
incrementWatchersCount(scope, -1);
|
||||
}
|
||||
lastDirtyWatch = null;
|
||||
};
|
||||
},
|
||||
@@ -794,7 +799,7 @@ function $RootScopeProvider() {
|
||||
// Insanity Warning: scope depth-first traversal
|
||||
// yes, this code is a bit crazy, but it works and we have tests to prove it!
|
||||
// this piece should be kept in sync with the traversal in $broadcast
|
||||
if (!(next = (current.$$childHead ||
|
||||
if (!(next = ((current.$$watchersCount && current.$$childHead) ||
|
||||
(current !== target && current.$$nextSibling)))) {
|
||||
while (current !== target && !(next = current.$$nextSibling)) {
|
||||
current = current.$parent;
|
||||
@@ -869,6 +874,7 @@ function $RootScopeProvider() {
|
||||
this.$$destroyed = true;
|
||||
if (this === $rootScope) return;
|
||||
|
||||
incrementWatchersCount(this, -this.$$watchersCount);
|
||||
for (var eventName in this.$$listenerCount) {
|
||||
decrementListenerCount(this, this.$$listenerCount[eventName], eventName);
|
||||
}
|
||||
@@ -1290,6 +1296,11 @@ function $RootScopeProvider() {
|
||||
$rootScope.$$phase = null;
|
||||
}
|
||||
|
||||
function incrementWatchersCount(current, count) {
|
||||
do {
|
||||
current.$$watchersCount += count;
|
||||
} while ((current = current.$parent));
|
||||
}
|
||||
|
||||
function decrementListenerCount(current, count, name) {
|
||||
do {
|
||||
|
||||
@@ -44,6 +44,7 @@ function $TemplateRequestProvider() {
|
||||
handleRequestFn.totalPendingRequests--;
|
||||
})
|
||||
.then(function(response) {
|
||||
$templateCache.put(tpl, response.data);
|
||||
return response.data;
|
||||
}, handleError);
|
||||
|
||||
|
||||
@@ -1327,8 +1327,7 @@ angular.module('ngAnimate', ['ng'])
|
||||
} else if (lastAnimation.event == 'setClass') {
|
||||
animationsToCancel.push(lastAnimation);
|
||||
cleanup(element, className);
|
||||
}
|
||||
else if (runningAnimations[className]) {
|
||||
} else if (runningAnimations[className]) {
|
||||
var current = runningAnimations[className];
|
||||
if (current.event == animationEvent) {
|
||||
skipAnimation = true;
|
||||
|
||||
+10
-2
@@ -100,7 +100,8 @@ function $AriaProvider() {
|
||||
* - **ariaMultiline** – `{boolean}` – Enables/disables aria-multiline tags
|
||||
* - **ariaValue** – `{boolean}` – Enables/disables aria-valuemin, aria-valuemax and aria-valuenow tags
|
||||
* - **tabindex** – `{boolean}` – Enables/disables tabindex tags
|
||||
* - **bindKeypress** – `{boolean}` – Enables/disables keypress event binding on ng-click
|
||||
* - **bindKeypress** – `{boolean}` – Enables/disables keypress event binding on `<div>` and
|
||||
* `<li>` elements with ng-click
|
||||
*
|
||||
* @description
|
||||
* Enables/disables various ARIA attributes
|
||||
@@ -303,11 +304,18 @@ ngAriaModule.directive('ngShow', ['$aria', function($aria) {
|
||||
compile: function(elem, attr) {
|
||||
var fn = $parse(attr.ngClick, /* interceptorFn */ null, /* expensiveChecks */ true);
|
||||
return function(scope, elem, attr) {
|
||||
|
||||
function isNodeOneOf(elem, nodeTypeArray) {
|
||||
if (nodeTypeArray.indexOf(elem[0].nodeName) !== -1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($aria.config('tabindex') && !elem.attr('tabindex')) {
|
||||
elem.attr('tabindex', 0);
|
||||
}
|
||||
|
||||
if ($aria.config('bindKeypress') && !attr.ngKeypress) {
|
||||
if ($aria.config('bindKeypress') && !attr.ngKeypress && isNodeOneOf(elem, ['DIV', 'LI'])) {
|
||||
elem.on('keypress', function(event) {
|
||||
if (event.keyCode === 32 || event.keyCode === 13) {
|
||||
scope.$apply(callback);
|
||||
|
||||
Vendored
+1
-1
@@ -81,7 +81,7 @@ $provide.value("$locale", {
|
||||
"shortTime": "HH:mm"
|
||||
},
|
||||
"NUMBER_FORMATS": {
|
||||
"CURRENCY_SYM": "Lt",
|
||||
"CURRENCY_SYM": "\u20ac",
|
||||
"DECIMAL_SEP": ",",
|
||||
"GROUP_SEP": "\u00a0",
|
||||
"PATTERNS": [
|
||||
|
||||
Vendored
+1
-1
@@ -81,7 +81,7 @@ $provide.value("$locale", {
|
||||
"shortTime": "HH:mm"
|
||||
},
|
||||
"NUMBER_FORMATS": {
|
||||
"CURRENCY_SYM": "Lt",
|
||||
"CURRENCY_SYM": "\u20ac",
|
||||
"DECIMAL_SEP": ",",
|
||||
"GROUP_SEP": "\u00a0",
|
||||
"PATTERNS": [
|
||||
|
||||
Vendored
+14
-14
@@ -40,26 +40,26 @@ $provide.value("$locale", {
|
||||
"\u1005\u1014\u1031"
|
||||
],
|
||||
"SHORTMONTH": [
|
||||
"\u1007\u1014\u103a\u1014\u101d\u102b\u101b\u102e",
|
||||
"\u1016\u1031\u1016\u1031\u102c\u103a\u101d\u102b\u101b\u102e",
|
||||
"\u1007\u1014\u103a",
|
||||
"\u1016\u1031",
|
||||
"\u1019\u1010\u103a",
|
||||
"\u1027\u1015\u103c\u102e",
|
||||
"\u1019\u1031",
|
||||
"\u1007\u103d\u1014\u103a",
|
||||
"\u1007\u1030\u101c\u102d\u102f\u1004\u103a",
|
||||
"\u1029\u1002\u102f\u1010\u103a",
|
||||
"\u1005\u1000\u103a\u1010\u1004\u103a\u1018\u102c",
|
||||
"\u1021\u1031\u102c\u1000\u103a\u1010\u102d\u102f\u1018\u102c",
|
||||
"\u1014\u102d\u102f\u101d\u1004\u103a\u1018\u102c",
|
||||
"\u1012\u102e\u1007\u1004\u103a\u1018\u102c"
|
||||
"\u1007\u1030",
|
||||
"\u1029",
|
||||
"\u1005\u1000\u103a",
|
||||
"\u1021\u1031\u102c\u1000\u103a",
|
||||
"\u1014\u102d\u102f",
|
||||
"\u1012\u102e"
|
||||
],
|
||||
"fullDate": "EEEE, y MMMM dd",
|
||||
"longDate": "y MMMM d",
|
||||
"medium": "y MMM d HH:mm:ss",
|
||||
"mediumDate": "y MMM d",
|
||||
"fullDate": "EEEE, dd MMMM y",
|
||||
"longDate": "d MMMM y",
|
||||
"medium": "d MMM y HH:mm:ss",
|
||||
"mediumDate": "d MMM y",
|
||||
"mediumTime": "HH:mm:ss",
|
||||
"short": "yy/MM/dd HH:mm",
|
||||
"shortDate": "yy/MM/dd",
|
||||
"short": "dd-MM-yy HH:mm",
|
||||
"shortDate": "dd-MM-yy",
|
||||
"shortTime": "HH:mm"
|
||||
},
|
||||
"NUMBER_FORMATS": {
|
||||
|
||||
Vendored
+14
-14
@@ -40,26 +40,26 @@ $provide.value("$locale", {
|
||||
"\u1005\u1014\u1031"
|
||||
],
|
||||
"SHORTMONTH": [
|
||||
"\u1007\u1014\u103a\u1014\u101d\u102b\u101b\u102e",
|
||||
"\u1016\u1031\u1016\u1031\u102c\u103a\u101d\u102b\u101b\u102e",
|
||||
"\u1007\u1014\u103a",
|
||||
"\u1016\u1031",
|
||||
"\u1019\u1010\u103a",
|
||||
"\u1027\u1015\u103c\u102e",
|
||||
"\u1019\u1031",
|
||||
"\u1007\u103d\u1014\u103a",
|
||||
"\u1007\u1030\u101c\u102d\u102f\u1004\u103a",
|
||||
"\u1029\u1002\u102f\u1010\u103a",
|
||||
"\u1005\u1000\u103a\u1010\u1004\u103a\u1018\u102c",
|
||||
"\u1021\u1031\u102c\u1000\u103a\u1010\u102d\u102f\u1018\u102c",
|
||||
"\u1014\u102d\u102f\u101d\u1004\u103a\u1018\u102c",
|
||||
"\u1012\u102e\u1007\u1004\u103a\u1018\u102c"
|
||||
"\u1007\u1030",
|
||||
"\u1029",
|
||||
"\u1005\u1000\u103a",
|
||||
"\u1021\u1031\u102c\u1000\u103a",
|
||||
"\u1014\u102d\u102f",
|
||||
"\u1012\u102e"
|
||||
],
|
||||
"fullDate": "EEEE, y MMMM dd",
|
||||
"longDate": "y MMMM d",
|
||||
"medium": "y MMM d HH:mm:ss",
|
||||
"mediumDate": "y MMM d",
|
||||
"fullDate": "EEEE, dd MMMM y",
|
||||
"longDate": "d MMMM y",
|
||||
"medium": "d MMM y HH:mm:ss",
|
||||
"mediumDate": "d MMM y",
|
||||
"mediumTime": "HH:mm:ss",
|
||||
"short": "yy/MM/dd HH:mm",
|
||||
"shortDate": "yy/MM/dd",
|
||||
"short": "dd-MM-yy HH:mm",
|
||||
"shortDate": "dd-MM-yy",
|
||||
"shortTime": "HH:mm"
|
||||
},
|
||||
"NUMBER_FORMATS": {
|
||||
|
||||
@@ -70,7 +70,7 @@
|
||||
*
|
||||
* However, including generic messages may not be useful enough to match all input fields, therefore,
|
||||
* `ngMessages` provides the ability to override messages defined in the remote template by redefining
|
||||
* then within the directive container.
|
||||
* them within the directive container.
|
||||
*
|
||||
* ```html
|
||||
* <!-- a generic template of error messages known as "my-custom-messages" -->
|
||||
|
||||
Vendored
+68
-50
@@ -599,8 +599,9 @@ function padNumber(num, digits, trim) {
|
||||
}
|
||||
num = '' + num;
|
||||
while (num.length < digits) num = '0' + num;
|
||||
if (trim)
|
||||
if (trim) {
|
||||
num = num.substr(num.length - digits);
|
||||
}
|
||||
return neg + num;
|
||||
}
|
||||
|
||||
@@ -650,11 +651,12 @@ angular.mock.TzDate = function(offset, timestamp) {
|
||||
self.origDate = jsonStringToDate(timestamp);
|
||||
|
||||
timestamp = self.origDate.getTime();
|
||||
if (isNaN(timestamp))
|
||||
if (isNaN(timestamp)) {
|
||||
throw {
|
||||
name: "Illegal Argument",
|
||||
message: "Arg '" + tsStr + "' passed into TzDate constructor is not a valid date string"
|
||||
};
|
||||
}
|
||||
} else {
|
||||
self.origDate = new Date(timestamp);
|
||||
}
|
||||
@@ -1184,14 +1186,16 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
|
||||
}
|
||||
|
||||
if (expectation && expectation.match(method, url)) {
|
||||
if (!expectation.matchData(data))
|
||||
if (!expectation.matchData(data)) {
|
||||
throw new Error('Expected ' + expectation + ' with different data\n' +
|
||||
'EXPECTED: ' + prettyPrint(expectation.data) + '\nGOT: ' + data);
|
||||
}
|
||||
|
||||
if (!expectation.matchHeaders(headers))
|
||||
if (!expectation.matchHeaders(headers)) {
|
||||
throw new Error('Expected ' + expectation + ' with different headers\n' +
|
||||
'EXPECTED: ' + prettyPrint(expectation.headers) + '\nGOT: ' +
|
||||
prettyPrint(headers));
|
||||
}
|
||||
|
||||
expectations.shift();
|
||||
|
||||
@@ -1227,8 +1231,8 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
|
||||
* Creates a new backend definition.
|
||||
*
|
||||
* @param {string} method HTTP method.
|
||||
* @param {string|RegExp|function(string)} url HTTP url or function that receives the url
|
||||
* and returns true if the url match the current definition.
|
||||
* @param {string|RegExp|function(string)} url HTTP url or function that receives a url
|
||||
* and returns true if the url matches the current definition.
|
||||
* @param {(string|RegExp|function(string))=} data HTTP request body or function that receives
|
||||
* data string and returns true if the data is as expected.
|
||||
* @param {(Object|function(Object))=} headers HTTP headers or function that receives http header
|
||||
@@ -1273,8 +1277,8 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
|
||||
* @description
|
||||
* Creates a new backend definition for GET requests. For more info see `when()`.
|
||||
*
|
||||
* @param {string|RegExp|function(string)} url HTTP url or function that receives the url
|
||||
* and returns true if the url match the current definition.
|
||||
* @param {string|RegExp|function(string)} url HTTP url or function that receives a url
|
||||
* and returns true if the url matches the current definition.
|
||||
* @param {(Object|function(Object))=} headers HTTP headers.
|
||||
* @returns {requestHandler} Returns an object with `respond` method that controls how a matched
|
||||
* request is handled. You can save this object for later use and invoke `respond` again in
|
||||
@@ -1287,8 +1291,8 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
|
||||
* @description
|
||||
* Creates a new backend definition for HEAD requests. For more info see `when()`.
|
||||
*
|
||||
* @param {string|RegExp|function(string)} url HTTP url or function that receives the url
|
||||
* and returns true if the url match the current definition.
|
||||
* @param {string|RegExp|function(string)} url HTTP url or function that receives a url
|
||||
* and returns true if the url matches the current definition.
|
||||
* @param {(Object|function(Object))=} headers HTTP headers.
|
||||
* @returns {requestHandler} Returns an object with `respond` method that controls how a matched
|
||||
* request is handled. You can save this object for later use and invoke `respond` again in
|
||||
@@ -1301,8 +1305,8 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
|
||||
* @description
|
||||
* Creates a new backend definition for DELETE requests. For more info see `when()`.
|
||||
*
|
||||
* @param {string|RegExp|function(string)} url HTTP url or function that receives the url
|
||||
* and returns true if the url match the current definition.
|
||||
* @param {string|RegExp|function(string)} url HTTP url or function that receives a url
|
||||
* and returns true if the url matches the current definition.
|
||||
* @param {(Object|function(Object))=} headers HTTP headers.
|
||||
* @returns {requestHandler} Returns an object with `respond` method that controls how a matched
|
||||
* request is handled. You can save this object for later use and invoke `respond` again in
|
||||
@@ -1315,8 +1319,8 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
|
||||
* @description
|
||||
* Creates a new backend definition for POST requests. For more info see `when()`.
|
||||
*
|
||||
* @param {string|RegExp|function(string)} url HTTP url or function that receives the url
|
||||
* and returns true if the url match the current definition.
|
||||
* @param {string|RegExp|function(string)} url HTTP url or function that receives a url
|
||||
* and returns true if the url matches the current definition.
|
||||
* @param {(string|RegExp|function(string))=} data HTTP request body or function that receives
|
||||
* data string and returns true if the data is as expected.
|
||||
* @param {(Object|function(Object))=} headers HTTP headers.
|
||||
@@ -1331,8 +1335,8 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
|
||||
* @description
|
||||
* Creates a new backend definition for PUT requests. For more info see `when()`.
|
||||
*
|
||||
* @param {string|RegExp|function(string)} url HTTP url or function that receives the url
|
||||
* and returns true if the url match the current definition.
|
||||
* @param {string|RegExp|function(string)} url HTTP url or function that receives a url
|
||||
* and returns true if the url matches the current definition.
|
||||
* @param {(string|RegExp|function(string))=} data HTTP request body or function that receives
|
||||
* data string and returns true if the data is as expected.
|
||||
* @param {(Object|function(Object))=} headers HTTP headers.
|
||||
@@ -1347,8 +1351,8 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
|
||||
* @description
|
||||
* Creates a new backend definition for JSONP requests. For more info see `when()`.
|
||||
*
|
||||
* @param {string|RegExp|function(string)} url HTTP url or function that receives the url
|
||||
* and returns true if the url match the current definition.
|
||||
* @param {string|RegExp|function(string)} url HTTP url or function that receives a url
|
||||
* and returns true if the url matches the current definition.
|
||||
* @returns {requestHandler} Returns an object with `respond` method that controls how a matched
|
||||
* request is handled. You can save this object for later use and invoke `respond` again in
|
||||
* order to change how a matched request is handled.
|
||||
@@ -1363,8 +1367,8 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
|
||||
* Creates a new request expectation.
|
||||
*
|
||||
* @param {string} method HTTP method.
|
||||
* @param {string|RegExp|function(string)} url HTTP url or function that receives the url
|
||||
* and returns true if the url match the current definition.
|
||||
* @param {string|RegExp|function(string)} url HTTP url or function that receives a url
|
||||
* and returns true if the url matches the current definition.
|
||||
* @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that
|
||||
* receives data string and returns true if the data is as expected, or Object if request body
|
||||
* is in JSON format.
|
||||
@@ -1402,8 +1406,8 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
|
||||
* @description
|
||||
* Creates a new request expectation for GET requests. For more info see `expect()`.
|
||||
*
|
||||
* @param {string|RegExp|function(string)} url HTTP url or function that receives the url
|
||||
* and returns true if the url match the current definition.
|
||||
* @param {string|RegExp|function(string)} url HTTP url or function that receives a url
|
||||
* and returns true if the url matches the current definition.
|
||||
* @param {Object=} headers HTTP headers.
|
||||
* @returns {requestHandler} Returns an object with `respond` method that controls how a matched
|
||||
* request is handled. You can save this object for later use and invoke `respond` again in
|
||||
@@ -1416,8 +1420,8 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
|
||||
* @description
|
||||
* Creates a new request expectation for HEAD requests. For more info see `expect()`.
|
||||
*
|
||||
* @param {string|RegExp|function(string)} url HTTP url or function that receives the url
|
||||
* and returns true if the url match the current definition.
|
||||
* @param {string|RegExp|function(string)} url HTTP url or function that receives a url
|
||||
* and returns true if the url matches the current definition.
|
||||
* @param {Object=} headers HTTP headers.
|
||||
* @returns {requestHandler} Returns an object with `respond` method that controls how a matched
|
||||
* request is handled. You can save this object for later use and invoke `respond` again in
|
||||
@@ -1430,8 +1434,8 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
|
||||
* @description
|
||||
* Creates a new request expectation for DELETE requests. For more info see `expect()`.
|
||||
*
|
||||
* @param {string|RegExp|function(string)} url HTTP url or function that receives the url
|
||||
* and returns true if the url match the current definition.
|
||||
* @param {string|RegExp|function(string)} url HTTP url or function that receives a url
|
||||
* and returns true if the url matches the current definition.
|
||||
* @param {Object=} headers HTTP headers.
|
||||
* @returns {requestHandler} Returns an object with `respond` method that controls how a matched
|
||||
* request is handled. You can save this object for later use and invoke `respond` again in
|
||||
@@ -1444,8 +1448,8 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
|
||||
* @description
|
||||
* Creates a new request expectation for POST requests. For more info see `expect()`.
|
||||
*
|
||||
* @param {string|RegExp|function(string)} url HTTP url or function that receives the url
|
||||
* and returns true if the url match the current definition.
|
||||
* @param {string|RegExp|function(string)} url HTTP url or function that receives a url
|
||||
* and returns true if the url matches the current definition.
|
||||
* @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that
|
||||
* receives data string and returns true if the data is as expected, or Object if request body
|
||||
* is in JSON format.
|
||||
@@ -1461,8 +1465,8 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
|
||||
* @description
|
||||
* Creates a new request expectation for PUT requests. For more info see `expect()`.
|
||||
*
|
||||
* @param {string|RegExp|function(string)} url HTTP url or function that receives the url
|
||||
* and returns true if the url match the current definition.
|
||||
* @param {string|RegExp|function(string)} url HTTP url or function that receives a url
|
||||
* and returns true if the url matches the current definition.
|
||||
* @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that
|
||||
* receives data string and returns true if the data is as expected, or Object if request body
|
||||
* is in JSON format.
|
||||
@@ -1478,8 +1482,8 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
|
||||
* @description
|
||||
* Creates a new request expectation for PATCH requests. For more info see `expect()`.
|
||||
*
|
||||
* @param {string|RegExp|function(string)} url HTTP url or function that receives the url
|
||||
* and returns true if the url match the current definition.
|
||||
* @param {string|RegExp|function(string)} url HTTP url or function that receives a url
|
||||
* and returns true if the url matches the current definition.
|
||||
* @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that
|
||||
* receives data string and returns true if the data is as expected, or Object if request body
|
||||
* is in JSON format.
|
||||
@@ -1495,8 +1499,8 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
|
||||
* @description
|
||||
* Creates a new request expectation for JSONP requests. For more info see `expect()`.
|
||||
*
|
||||
* @param {string|RegExp|function(string)} url HTTP url or function that receives the url
|
||||
* and returns true if the url match the current definition.
|
||||
* @param {string|RegExp|function(string)} url HTTP url or function that receives an url
|
||||
* and returns true if the url matches the current definition.
|
||||
* @returns {requestHandler} Returns an object with `respond` method that controls how a matched
|
||||
* request is handled. You can save this object for later use and invoke `respond` again in
|
||||
* order to change how a matched request is handled.
|
||||
@@ -1906,8 +1910,8 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
|
||||
* Creates a new backend definition.
|
||||
*
|
||||
* @param {string} method HTTP method.
|
||||
* @param {string|RegExp|function(string)} url HTTP url or function that receives the url
|
||||
* and returns true if the url match the current definition.
|
||||
* @param {string|RegExp|function(string)} url HTTP url or function that receives a url
|
||||
* and returns true if the url matches the current definition.
|
||||
* @param {(string|RegExp)=} data HTTP request body.
|
||||
* @param {(Object|function(Object))=} headers HTTP headers or function that receives http header
|
||||
* object and returns true if the headers match the current definition.
|
||||
@@ -1934,8 +1938,8 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
|
||||
* @description
|
||||
* Creates a new backend definition for GET requests. For more info see `when()`.
|
||||
*
|
||||
* @param {string|RegExp|function(string)} url HTTP url or function that receives the url
|
||||
* and returns true if the url match the current definition.
|
||||
* @param {string|RegExp|function(string)} url HTTP url or function that receives a url
|
||||
* and returns true if the url matches the current definition.
|
||||
* @param {(Object|function(Object))=} headers HTTP headers.
|
||||
* @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
|
||||
* control how a matched request is handled. You can save this object for later use and invoke
|
||||
@@ -1949,8 +1953,8 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
|
||||
* @description
|
||||
* Creates a new backend definition for HEAD requests. For more info see `when()`.
|
||||
*
|
||||
* @param {string|RegExp|function(string)} url HTTP url or function that receives the url
|
||||
* and returns true if the url match the current definition.
|
||||
* @param {string|RegExp|function(string)} url HTTP url or function that receives a url
|
||||
* and returns true if the url matches the current definition.
|
||||
* @param {(Object|function(Object))=} headers HTTP headers.
|
||||
* @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
|
||||
* control how a matched request is handled. You can save this object for later use and invoke
|
||||
@@ -1964,8 +1968,8 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
|
||||
* @description
|
||||
* Creates a new backend definition for DELETE requests. For more info see `when()`.
|
||||
*
|
||||
* @param {string|RegExp|function(string)} url HTTP url or function that receives the url
|
||||
* and returns true if the url match the current definition.
|
||||
* @param {string|RegExp|function(string)} url HTTP url or function that receives a url
|
||||
* and returns true if the url matches the current definition.
|
||||
* @param {(Object|function(Object))=} headers HTTP headers.
|
||||
* @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
|
||||
* control how a matched request is handled. You can save this object for later use and invoke
|
||||
@@ -1979,8 +1983,8 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
|
||||
* @description
|
||||
* Creates a new backend definition for POST requests. For more info see `when()`.
|
||||
*
|
||||
* @param {string|RegExp|function(string)} url HTTP url or function that receives the url
|
||||
* and returns true if the url match the current definition.
|
||||
* @param {string|RegExp|function(string)} url HTTP url or function that receives a url
|
||||
* and returns true if the url matches the current definition.
|
||||
* @param {(string|RegExp)=} data HTTP request body.
|
||||
* @param {(Object|function(Object))=} headers HTTP headers.
|
||||
* @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
|
||||
@@ -1995,8 +1999,8 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
|
||||
* @description
|
||||
* Creates a new backend definition for PUT requests. For more info see `when()`.
|
||||
*
|
||||
* @param {string|RegExp|function(string)} url HTTP url or function that receives the url
|
||||
* and returns true if the url match the current definition.
|
||||
* @param {string|RegExp|function(string)} url HTTP url or function that receives a url
|
||||
* and returns true if the url matches the current definition.
|
||||
* @param {(string|RegExp)=} data HTTP request body.
|
||||
* @param {(Object|function(Object))=} headers HTTP headers.
|
||||
* @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
|
||||
@@ -2011,8 +2015,8 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
|
||||
* @description
|
||||
* Creates a new backend definition for PATCH requests. For more info see `when()`.
|
||||
*
|
||||
* @param {string|RegExp|function(string)} url HTTP url or function that receives the url
|
||||
* and returns true if the url match the current definition.
|
||||
* @param {string|RegExp|function(string)} url HTTP url or function that receives a url
|
||||
* and returns true if the url matches the current definition.
|
||||
* @param {(string|RegExp)=} data HTTP request body.
|
||||
* @param {(Object|function(Object))=} headers HTTP headers.
|
||||
* @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
|
||||
@@ -2027,8 +2031,8 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
|
||||
* @description
|
||||
* Creates a new backend definition for JSONP requests. For more info see `when()`.
|
||||
*
|
||||
* @param {string|RegExp|function(string)} url HTTP url or function that receives the url
|
||||
* and returns true if the url match the current definition.
|
||||
* @param {string|RegExp|function(string)} url HTTP url or function that receives a url
|
||||
* and returns true if the url matches the current definition.
|
||||
* @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
|
||||
* control how a matched request is handled. You can save this object for later use and invoke
|
||||
* `respond` or `passThrough` again in order to change how a matched request is handled.
|
||||
@@ -2127,18 +2131,32 @@ angular.mock.$RootScopeDecorator = ['$delegate', function($delegate) {
|
||||
if (window.jasmine || window.mocha) {
|
||||
|
||||
var currentSpec = null,
|
||||
annotatedFunctions = [],
|
||||
isSpecRunning = function() {
|
||||
return !!currentSpec;
|
||||
};
|
||||
|
||||
angular.mock.$$annotate = angular.injector.$$annotate;
|
||||
angular.injector.$$annotate = function(fn) {
|
||||
if (typeof fn === 'function' && !fn.$inject) {
|
||||
annotatedFunctions.push(fn);
|
||||
}
|
||||
return angular.mock.$$annotate.apply(this, arguments);
|
||||
};
|
||||
|
||||
|
||||
(window.beforeEach || window.setup)(function() {
|
||||
annotatedFunctions = [];
|
||||
currentSpec = this;
|
||||
});
|
||||
|
||||
(window.afterEach || window.teardown)(function() {
|
||||
var injector = currentSpec.$injector;
|
||||
|
||||
annotatedFunctions.forEach(function(fn) {
|
||||
delete fn.$inject;
|
||||
});
|
||||
|
||||
angular.forEach(currentSpec.$modules, function(module) {
|
||||
if (module && module.$$hashKey) {
|
||||
module.$$hashKey = undefined;
|
||||
|
||||
+6
-12
@@ -73,8 +73,8 @@ function $RouteProvider() {
|
||||
* - `controller` – `{(string|function()=}` – Controller fn that should be associated with
|
||||
* newly created scope or the name of a {@link angular.Module#controller registered
|
||||
* controller} if passed as a string.
|
||||
* - `controllerAs` – `{string=}` – A controller alias name. If present the controller will be
|
||||
* published to scope under the `controllerAs` name.
|
||||
* - `controllerAs` – `{string=}` – An identifier name for a reference to the controller.
|
||||
* If present, the controller will be published to scope under the `controllerAs` name.
|
||||
* - `template` – `{string=|function()=}` – html template as a string or a function that
|
||||
* returns an html template as a string which should be used by {@link
|
||||
* ngRoute.directive:ngView ngView} or {@link ng.directive:ngInclude ngInclude} directives.
|
||||
@@ -477,21 +477,15 @@ function $RouteProvider() {
|
||||
* definitions will be interpolated into the location's path, while
|
||||
* remaining properties will be treated as query params.
|
||||
*
|
||||
* @param {Object} newParams mapping of URL parameter names to values
|
||||
* @param {!Object<string, string>} newParams mapping of URL parameter names to values
|
||||
*/
|
||||
updateParams: function(newParams) {
|
||||
if (this.current && this.current.$$route) {
|
||||
var searchParams = {}, self=this;
|
||||
|
||||
angular.forEach(Object.keys(newParams), function(key) {
|
||||
if (!self.current.pathParams[key]) searchParams[key] = newParams[key];
|
||||
});
|
||||
|
||||
newParams = angular.extend({}, this.current.params, newParams);
|
||||
$location.path(interpolate(this.current.$$route.originalPath, newParams));
|
||||
$location.search(angular.extend({}, $location.search(), searchParams));
|
||||
}
|
||||
else {
|
||||
// interpolate modifies newParams, only query params are left
|
||||
$location.search(newParams);
|
||||
} else {
|
||||
throw $routeMinErr('norout', 'Tried updating route when with no current route');
|
||||
}
|
||||
}
|
||||
|
||||
+16
-13
@@ -271,14 +271,14 @@ function htmlParser(html, handler) {
|
||||
}
|
||||
}
|
||||
var index, chars, match, stack = [], last = html, text;
|
||||
stack.last = function() { return stack[ stack.length - 1 ]; };
|
||||
stack.last = function() { return stack[stack.length - 1]; };
|
||||
|
||||
while (html) {
|
||||
text = '';
|
||||
chars = true;
|
||||
|
||||
// Make sure we're not in a script or style element
|
||||
if (!stack.last() || !specialElements[ stack.last() ]) {
|
||||
if (!stack.last() || !specialElements[stack.last()]) {
|
||||
|
||||
// Comment
|
||||
if (html.indexOf("<!--") === 0) {
|
||||
@@ -336,7 +336,8 @@ function htmlParser(html, handler) {
|
||||
}
|
||||
|
||||
} else {
|
||||
html = html.replace(new RegExp("(.*)<\\s*\\/\\s*" + stack.last() + "[^>]*>", 'i'),
|
||||
// IE versions 9 and 10 do not understand the regex '[^]', so using a workaround with [\W\w].
|
||||
html = html.replace(new RegExp("([\\W\\w]*)<\\s*\\/\\s*" + stack.last() + "[^>]*>", 'i'),
|
||||
function(all, text) {
|
||||
text = text.replace(COMMENT_REGEXP, "$1").replace(CDATA_REGEXP, "$1");
|
||||
|
||||
@@ -360,20 +361,21 @@ function htmlParser(html, handler) {
|
||||
|
||||
function parseStartTag(tag, tagName, rest, unary) {
|
||||
tagName = angular.lowercase(tagName);
|
||||
if (blockElements[ tagName ]) {
|
||||
while (stack.last() && inlineElements[ stack.last() ]) {
|
||||
if (blockElements[tagName]) {
|
||||
while (stack.last() && inlineElements[stack.last()]) {
|
||||
parseEndTag("", stack.last());
|
||||
}
|
||||
}
|
||||
|
||||
if (optionalEndTagElements[ tagName ] && stack.last() == tagName) {
|
||||
if (optionalEndTagElements[tagName] && stack.last() == tagName) {
|
||||
parseEndTag("", tagName);
|
||||
}
|
||||
|
||||
unary = voidElements[ tagName ] || !!unary;
|
||||
unary = voidElements[tagName] || !!unary;
|
||||
|
||||
if (!unary)
|
||||
if (!unary) {
|
||||
stack.push(tagName);
|
||||
}
|
||||
|
||||
var attrs = {};
|
||||
|
||||
@@ -392,16 +394,17 @@ function htmlParser(html, handler) {
|
||||
function parseEndTag(tag, tagName) {
|
||||
var pos = 0, i;
|
||||
tagName = angular.lowercase(tagName);
|
||||
if (tagName)
|
||||
if (tagName) {
|
||||
// Find the closest opened tag of the same type
|
||||
for (pos = stack.length - 1; pos >= 0; pos--)
|
||||
if (stack[ pos ] == tagName)
|
||||
break;
|
||||
for (pos = stack.length - 1; pos >= 0; pos--) {
|
||||
if (stack[pos] == tagName) break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pos >= 0) {
|
||||
// Close all the open elements, up the stack
|
||||
for (i = stack.length - 1; i >= pos; i--)
|
||||
if (handler.end) handler.end(stack[ i ]);
|
||||
if (handler.end) handler.end(stack[i]);
|
||||
|
||||
// Remove the open elements from the stack
|
||||
stack.length = pos;
|
||||
|
||||
@@ -34,8 +34,9 @@ angular.scenario.Application.prototype.getFrame_ = function() {
|
||||
*/
|
||||
angular.scenario.Application.prototype.getWindow_ = function() {
|
||||
var contentWindow = this.getFrame_().prop('contentWindow');
|
||||
if (!contentWindow)
|
||||
if (!contentWindow) {
|
||||
throw 'Frame window is not accessible.';
|
||||
}
|
||||
return contentWindow;
|
||||
};
|
||||
|
||||
@@ -68,19 +69,31 @@ angular.scenario.Application.prototype.navigateTo = function(url, loadFn, errorF
|
||||
try {
|
||||
var $window = self.getWindow_();
|
||||
|
||||
if ($window.angular) {
|
||||
// Disable animations
|
||||
$window.angular.resumeBootstrap([['$provide', function($provide) {
|
||||
return ['$animate', function($animate) {
|
||||
$animate.enabled(false);
|
||||
}];
|
||||
}]]);
|
||||
if (!$window.angular) {
|
||||
self.executeAction(loadFn);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$window.angular.resumeBootstrap) {
|
||||
$window.angular.resumeDeferredBootstrap = resumeDeferredBootstrap;
|
||||
} else {
|
||||
resumeDeferredBootstrap();
|
||||
}
|
||||
|
||||
self.executeAction(loadFn);
|
||||
} catch (e) {
|
||||
errorFn(e);
|
||||
}
|
||||
|
||||
function resumeDeferredBootstrap() {
|
||||
// Disable animations
|
||||
var $injector = $window.angular.resumeBootstrap([['$provide', function($provide) {
|
||||
return ['$animate', function($animate) {
|
||||
$animate.enabled(false);
|
||||
}];
|
||||
}]]);
|
||||
self.rootElement = $injector.get('$rootElement')[0];
|
||||
self.executeAction(loadFn);
|
||||
}
|
||||
}).attr('src', url);
|
||||
|
||||
// for IE compatibility set the name *after* setting the frame url
|
||||
@@ -105,7 +118,14 @@ angular.scenario.Application.prototype.executeAction = function(action) {
|
||||
if (!$window.angular) {
|
||||
return action.call(this, $window, _jQuery($window.document));
|
||||
}
|
||||
angularInit($window.document, function(element) {
|
||||
|
||||
if (!!this.rootElement) {
|
||||
executeWithElement(this.rootElement);
|
||||
} else {
|
||||
angularInit($window.document, angular.bind(this, executeWithElement));
|
||||
}
|
||||
|
||||
function executeWithElement(element) {
|
||||
var $injector = $window.angular.element(element).injector();
|
||||
var $element = _jQuery(element);
|
||||
|
||||
@@ -118,5 +138,5 @@ angular.scenario.Application.prototype.executeAction = function(action) {
|
||||
action.call(self, $window, $element);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -76,8 +76,9 @@ angular.scenario.ObjectModel = function(runner) {
|
||||
runner.on('StepEnd', function(spec) {
|
||||
var it = self.getSpec(spec.id);
|
||||
var step = it.getLastStep();
|
||||
if (step.name !== step.name)
|
||||
if (step.name !== step.name) {
|
||||
throw 'Events fired in the wrong order. Step names don\'t match.';
|
||||
}
|
||||
complete(step);
|
||||
|
||||
// forward the event
|
||||
|
||||
@@ -36,8 +36,9 @@ angular.scenario.Runner.prototype.emit = function(eventName) {
|
||||
var self = this;
|
||||
var args = Array.prototype.slice.call(arguments, 1);
|
||||
eventName = eventName.toLowerCase();
|
||||
if (!this.listeners[eventName])
|
||||
if (!this.listeners[eventName]) {
|
||||
return;
|
||||
}
|
||||
angular.forEach(this.listeners[eventName], function(listener) {
|
||||
listener.apply(self, args);
|
||||
});
|
||||
@@ -157,8 +158,9 @@ angular.scenario.Runner.prototype.createSpecRunner_ = function(scope) {
|
||||
|
||||
// Export all the methods to child scope manually as now we don't mess controllers with scopes
|
||||
// TODO(vojta): refactor scenario runner so that these objects are not tightly coupled as current
|
||||
for (var name in Cls.prototype)
|
||||
for (var name in Cls.prototype) {
|
||||
child[name] = angular.bind(child, Cls.prototype[name]);
|
||||
}
|
||||
|
||||
Cls.call(child);
|
||||
return child;
|
||||
|
||||
@@ -42,8 +42,9 @@ angular.scenario.dsl = angular.scenario.dsl || function(name, fn) {
|
||||
/* jshint -W040 *//* The dsl binds `this` for us when calling chained functions */
|
||||
function executeStatement(statement, args) {
|
||||
var result = statement.apply(this, args);
|
||||
if (angular.isFunction(result) || result instanceof angular.scenario.Future)
|
||||
if (angular.isFunction(result) || result instanceof angular.scenario.Future) {
|
||||
return result;
|
||||
}
|
||||
var self = this;
|
||||
var chain = angular.extend({}, result);
|
||||
angular.forEach(chain, function(value, name) {
|
||||
@@ -304,7 +305,7 @@ _jQuery.fn.bindings = function(windowJquery, bindExp) {
|
||||
var element = windowJquery(this),
|
||||
bindings;
|
||||
if (bindings = element.data('$binding')) {
|
||||
for (var expressions = [], binding, j=0, jj=bindings.length; j < jj; j++) {
|
||||
for (var expressions = [], binding, j=0, jj=bindings.length; j < jj; j++) {
|
||||
binding = bindings[j];
|
||||
|
||||
if (binding.expressions) {
|
||||
|
||||
@@ -55,8 +55,7 @@
|
||||
if (window.WebKitTransitionEvent) {
|
||||
evnt = new WebKitTransitionEvent(eventType, eventData);
|
||||
evnt.initEvent(eventType, false, true);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
try {
|
||||
evnt = new TransitionEvent(eventType, eventData);
|
||||
}
|
||||
@@ -65,13 +64,11 @@
|
||||
evnt.initTransitionEvent(eventType, null, null, null, eventData.elapsedTime || 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (/animationend/.test(eventType)) {
|
||||
} else if (/animationend/.test(eventType)) {
|
||||
if (window.WebKitAnimationEvent) {
|
||||
evnt = new WebKitAnimationEvent(eventType, eventData);
|
||||
evnt.initEvent(eventType, false, true);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
try {
|
||||
evnt = new AnimationEvent(eventType, eventData);
|
||||
}
|
||||
@@ -80,8 +77,7 @@
|
||||
evnt.initAnimationEvent(eventType, null, null, null, eventData.elapsedTime || 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
evnt = document.createEvent('MouseEvents');
|
||||
x = x || 0;
|
||||
y = y || 0;
|
||||
|
||||
@@ -276,8 +276,9 @@ angular.scenario.dsl('repeater', function() {
|
||||
return this.addFutureAction("repeater '" + this.label + "' row '" + index + "'",
|
||||
function($window, $document, done) {
|
||||
var matches = $document.elements().slice(index, index + 1);
|
||||
if (!matches.length)
|
||||
if (!matches.length) {
|
||||
return done('row ' + index + ' out of bounds');
|
||||
}
|
||||
done(null, matches.bindings($window.angular.element));
|
||||
});
|
||||
};
|
||||
|
||||
+1
-1
@@ -26,7 +26,6 @@
|
||||
"manualUppercase": false,
|
||||
"isArrayLike": false,
|
||||
"forEach": false,
|
||||
"sortedKeys": false,
|
||||
"reverseParams": false,
|
||||
"nextUid": false,
|
||||
"setHashKey": false,
|
||||
@@ -61,6 +60,7 @@
|
||||
"shallowCopy": false,
|
||||
"equals": false,
|
||||
"csp": false,
|
||||
"jq": false,
|
||||
"concat": false,
|
||||
"sliceArgs": false,
|
||||
"bind": false,
|
||||
|
||||
+288
-7
@@ -78,6 +78,186 @@ describe('angular', function() {
|
||||
expect(copy(objWithRegExp.re) === objWithRegExp.re).toBeFalsy();
|
||||
});
|
||||
|
||||
it("should copy a Uint8Array with no destination", function() {
|
||||
if (typeof Uint8Array !== 'undefined') {
|
||||
var src = new Uint8Array(2);
|
||||
src[1] = 1;
|
||||
var dst = copy(src);
|
||||
expect(copy(src) instanceof Uint8Array).toBeTruthy();
|
||||
expect(dst).toEqual(src);
|
||||
expect(dst).not.toBe(src);
|
||||
}
|
||||
});
|
||||
|
||||
it("should copy a Uint8ClampedArray with no destination", function() {
|
||||
if (typeof Uint8ClampedArray !== 'undefined') {
|
||||
var src = new Uint8ClampedArray(2);
|
||||
src[1] = 1;
|
||||
var dst = copy(src);
|
||||
expect(copy(src) instanceof Uint8ClampedArray).toBeTruthy();
|
||||
expect(dst).toEqual(src);
|
||||
expect(dst).not.toBe(src);
|
||||
}
|
||||
});
|
||||
|
||||
it("should copy a Uint16Array with no destination", function() {
|
||||
if (typeof Uint16Array !== 'undefined') {
|
||||
var src = new Uint16Array(2);
|
||||
src[1] = 1;
|
||||
var dst = copy(src);
|
||||
expect(copy(src) instanceof Uint16Array).toBeTruthy();
|
||||
expect(dst).toEqual(src);
|
||||
expect(dst).not.toBe(src);
|
||||
}
|
||||
});
|
||||
|
||||
it("should copy a Uint32Array with no destination", function() {
|
||||
if (typeof Uint32Array !== 'undefined') {
|
||||
var src = new Uint32Array(2);
|
||||
src[1] = 1;
|
||||
var dst = copy(src);
|
||||
expect(copy(src) instanceof Uint32Array).toBeTruthy();
|
||||
expect(dst).toEqual(src);
|
||||
expect(dst).not.toBe(src);
|
||||
}
|
||||
});
|
||||
|
||||
it("should copy a Int8Array with no destination", function() {
|
||||
if (typeof Int8Array !== 'undefined') {
|
||||
var src = new Int8Array(2);
|
||||
src[1] = 1;
|
||||
var dst = copy(src);
|
||||
expect(copy(src) instanceof Int8Array).toBeTruthy();
|
||||
expect(dst).toEqual(src);
|
||||
expect(dst).not.toBe(src);
|
||||
}
|
||||
});
|
||||
|
||||
it("should copy a Int16Array with no destination", function() {
|
||||
if (typeof Int16Array !== 'undefined') {
|
||||
var src = new Int16Array(2);
|
||||
src[1] = 1;
|
||||
var dst = copy(src);
|
||||
expect(copy(src) instanceof Int16Array).toBeTruthy();
|
||||
expect(dst).toEqual(src);
|
||||
expect(dst).not.toBe(src);
|
||||
}
|
||||
});
|
||||
|
||||
it("should copy a Int32Array with no destination", function() {
|
||||
if (typeof Int32Array !== 'undefined') {
|
||||
var src = new Int32Array(2);
|
||||
src[1] = 1;
|
||||
var dst = copy(src);
|
||||
expect(copy(src) instanceof Int32Array).toBeTruthy();
|
||||
expect(dst).toEqual(src);
|
||||
expect(dst).not.toBe(src);
|
||||
}
|
||||
});
|
||||
|
||||
it("should copy a Float32Array with no destination", function() {
|
||||
if (typeof Float32Array !== 'undefined') {
|
||||
var src = new Float32Array(2);
|
||||
src[1] = 1;
|
||||
var dst = copy(src);
|
||||
expect(copy(src) instanceof Float32Array).toBeTruthy();
|
||||
expect(dst).toEqual(src);
|
||||
expect(dst).not.toBe(src);
|
||||
}
|
||||
});
|
||||
|
||||
it("should copy a Float64Array with no destination", function() {
|
||||
if (typeof Float64Array !== 'undefined') {
|
||||
var src = new Float64Array(2);
|
||||
src[1] = 1;
|
||||
var dst = copy(src);
|
||||
expect(copy(src) instanceof Float64Array).toBeTruthy();
|
||||
expect(dst).toEqual(src);
|
||||
expect(dst).not.toBe(src);
|
||||
}
|
||||
});
|
||||
|
||||
it("should throw an exception if a Uint8Array is the destination", function() {
|
||||
if (typeof Uint8Array !== 'undefined') {
|
||||
var src = new Uint8Array();
|
||||
var dst = new Uint8Array(5);
|
||||
expect(function() { copy(src, dst); })
|
||||
.toThrowMinErr("ng", "cpta", "Can't copy! TypedArray destination cannot be mutated.");
|
||||
}
|
||||
});
|
||||
|
||||
it("should throw an exception if a Uint8ClampedArray is the destination", function() {
|
||||
if (typeof Uint8ClampedArray !== 'undefined') {
|
||||
var src = new Uint8ClampedArray();
|
||||
var dst = new Uint8ClampedArray(5);
|
||||
expect(function() { copy(src, dst); })
|
||||
.toThrowMinErr("ng", "cpta", "Can't copy! TypedArray destination cannot be mutated.");
|
||||
}
|
||||
});
|
||||
|
||||
it("should throw an exception if a Uint16Array is the destination", function() {
|
||||
if (typeof Uint16Array !== 'undefined') {
|
||||
var src = new Uint16Array();
|
||||
var dst = new Uint16Array(5);
|
||||
expect(function() { copy(src, dst); })
|
||||
.toThrowMinErr("ng", "cpta", "Can't copy! TypedArray destination cannot be mutated.");
|
||||
}
|
||||
});
|
||||
|
||||
it("should throw an exception if a Uint32Array is the destination", function() {
|
||||
if (typeof Uint32Array !== 'undefined') {
|
||||
var src = new Uint32Array();
|
||||
var dst = new Uint32Array(5);
|
||||
expect(function() { copy(src, dst); })
|
||||
.toThrowMinErr("ng", "cpta", "Can't copy! TypedArray destination cannot be mutated.");
|
||||
}
|
||||
});
|
||||
|
||||
it("should throw an exception if a Int8Array is the destination", function() {
|
||||
if (typeof Int8Array !== 'undefined') {
|
||||
var src = new Int8Array();
|
||||
var dst = new Int8Array(5);
|
||||
expect(function() { copy(src, dst); })
|
||||
.toThrowMinErr("ng", "cpta", "Can't copy! TypedArray destination cannot be mutated.");
|
||||
}
|
||||
});
|
||||
|
||||
it("should throw an exception if a Int16Array is the destination", function() {
|
||||
if (typeof Int16Array !== 'undefined') {
|
||||
var src = new Int16Array();
|
||||
var dst = new Int16Array(5);
|
||||
expect(function() { copy(src, dst); })
|
||||
.toThrowMinErr("ng", "cpta", "Can't copy! TypedArray destination cannot be mutated.");
|
||||
}
|
||||
});
|
||||
|
||||
it("should throw an exception if a Int32Array is the destination", function() {
|
||||
if (typeof Int32Array !== 'undefined') {
|
||||
var src = new Int32Array();
|
||||
var dst = new Int32Array(5);
|
||||
expect(function() { copy(src, dst); })
|
||||
.toThrowMinErr("ng", "cpta", "Can't copy! TypedArray destination cannot be mutated.");
|
||||
}
|
||||
});
|
||||
|
||||
it("should throw an exception if a Float32Array is the destination", function() {
|
||||
if (typeof Float32Array !== 'undefined') {
|
||||
var src = new Float32Array();
|
||||
var dst = new Float32Array(5);
|
||||
expect(function() { copy(src, dst); })
|
||||
.toThrowMinErr("ng", "cpta", "Can't copy! TypedArray destination cannot be mutated.");
|
||||
}
|
||||
});
|
||||
|
||||
it("should throw an exception if a Float64Array is the destination", function() {
|
||||
if (typeof Float64Array !== 'undefined') {
|
||||
var src = new Float64Array();
|
||||
var dst = new Float64Array(5);
|
||||
expect(function() { copy(src, dst); })
|
||||
.toThrowMinErr("ng", "cpta", "Can't copy! TypedArray destination cannot be mutated.");
|
||||
}
|
||||
});
|
||||
|
||||
it("should deeply copy an array into an existing array", function() {
|
||||
var src = [1, {name:"value"}];
|
||||
var dst = [{key:"v"}];
|
||||
@@ -435,6 +615,94 @@ describe('angular', function() {
|
||||
});
|
||||
|
||||
|
||||
describe('jq', function() {
|
||||
var element;
|
||||
|
||||
beforeEach(function() {
|
||||
element = document.createElement('html');
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
delete jq.name_;
|
||||
});
|
||||
|
||||
it('should return undefined when jq is not set, no jQuery found (the default)', function() {
|
||||
expect(jq()).toBe(undefined);
|
||||
});
|
||||
|
||||
it('should return empty string when jq is enabled manually via [ng-jq] with empty string', function() {
|
||||
element.setAttribute('ng-jq', '');
|
||||
spyOn(document, 'querySelector').andCallFake(function(selector) {
|
||||
if (selector === '[ng-jq]') return element;
|
||||
});
|
||||
expect(jq()).toBe('');
|
||||
});
|
||||
|
||||
it('should return empty string when jq is enabled manually via [data-ng-jq] with empty string', function() {
|
||||
element.setAttribute('data-ng-jq', '');
|
||||
spyOn(document, 'querySelector').andCallFake(function(selector) {
|
||||
if (selector === '[data-ng-jq]') return element;
|
||||
});
|
||||
expect(jq()).toBe('');
|
||||
expect(document.querySelector).toHaveBeenCalledWith('[data-ng-jq]');
|
||||
});
|
||||
|
||||
it('should return empty string when jq is enabled manually via [x-ng-jq] with empty string', function() {
|
||||
element.setAttribute('x-ng-jq', '');
|
||||
spyOn(document, 'querySelector').andCallFake(function(selector) {
|
||||
if (selector === '[x-ng-jq]') return element;
|
||||
});
|
||||
expect(jq()).toBe('');
|
||||
expect(document.querySelector).toHaveBeenCalledWith('[x-ng-jq]');
|
||||
});
|
||||
|
||||
it('should return empty string when jq is enabled manually via [ng:jq] with empty string', function() {
|
||||
element.setAttribute('ng:jq', '');
|
||||
spyOn(document, 'querySelector').andCallFake(function(selector) {
|
||||
if (selector === '[ng\\:jq]') return element;
|
||||
});
|
||||
expect(jq()).toBe('');
|
||||
expect(document.querySelector).toHaveBeenCalledWith('[ng\\:jq]');
|
||||
});
|
||||
|
||||
it('should return "jQuery" when jq is enabled manually via [ng-jq] with value "jQuery"', function() {
|
||||
element.setAttribute('ng-jq', 'jQuery');
|
||||
spyOn(document, 'querySelector').andCallFake(function(selector) {
|
||||
if (selector === '[ng-jq]') return element;
|
||||
});
|
||||
expect(jq()).toBe('jQuery');
|
||||
expect(document.querySelector).toHaveBeenCalledWith('[ng-jq]');
|
||||
});
|
||||
|
||||
it('should return "jQuery" when jq is enabled manually via [data-ng-jq] with value "jQuery"', function() {
|
||||
element.setAttribute('data-ng-jq', 'jQuery');
|
||||
spyOn(document, 'querySelector').andCallFake(function(selector) {
|
||||
if (selector === '[data-ng-jq]') return element;
|
||||
});
|
||||
expect(jq()).toBe('jQuery');
|
||||
expect(document.querySelector).toHaveBeenCalledWith('[data-ng-jq]');
|
||||
});
|
||||
|
||||
it('should return "jQuery" when jq is enabled manually via [x-ng-jq] with value "jQuery"', function() {
|
||||
element.setAttribute('x-ng-jq', 'jQuery');
|
||||
spyOn(document, 'querySelector').andCallFake(function(selector) {
|
||||
if (selector === '[x-ng-jq]') return element;
|
||||
});
|
||||
expect(jq()).toBe('jQuery');
|
||||
expect(document.querySelector).toHaveBeenCalledWith('[x-ng-jq]');
|
||||
});
|
||||
|
||||
it('should return "jQuery" when jq is enabled manually via [ng:jq] with value "jQuery"', function() {
|
||||
element.setAttribute('ng:jq', 'jQuery');
|
||||
spyOn(document, 'querySelector').andCallFake(function(selector) {
|
||||
if (selector === '[ng\\:jq]') return element;
|
||||
});
|
||||
expect(jq()).toBe('jQuery');
|
||||
expect(document.querySelector).toHaveBeenCalledWith('[ng\\:jq]');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('parseKeyValue', function() {
|
||||
it('should parse a string into key-value pairs', function() {
|
||||
expect(parseKeyValue('')).toEqual({});
|
||||
@@ -699,13 +967,6 @@ describe('angular', function() {
|
||||
});
|
||||
|
||||
|
||||
describe('sortedKeys', function() {
|
||||
it('should collect keys from object', function() {
|
||||
expect(sortedKeys({c:0, b:0, a:0})).toEqual(['a', 'b', 'c']);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('encodeUriSegment', function() {
|
||||
it('should correctly encode uri segment and not encode chars defined as pchar set in rfc3986',
|
||||
function() {
|
||||
@@ -1081,6 +1342,26 @@ describe('angular', function() {
|
||||
window.name = originalName;
|
||||
});
|
||||
|
||||
it('should provide injector for deferred bootstrap', function() {
|
||||
var injector;
|
||||
window.name = 'NG_DEFER_BOOTSTRAP!';
|
||||
|
||||
injector = angular.bootstrap(element);
|
||||
expect(injector).toBeUndefined();
|
||||
|
||||
injector = angular.resumeBootstrap();
|
||||
expect(injector).toBeDefined();
|
||||
});
|
||||
|
||||
it('should resume deferred bootstrap, if defined', function() {
|
||||
var injector;
|
||||
window.name = 'NG_DEFER_BOOTSTRAP!';
|
||||
|
||||
angular.resumeDeferredBootstrap = noop;
|
||||
var spy = spyOn(angular, "resumeDeferredBootstrap");
|
||||
injector = angular.bootstrap(element);
|
||||
expect(spy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should wait for extra modules', function() {
|
||||
window.name = 'NG_DEFER_BOOTSTRAP!';
|
||||
|
||||
@@ -238,7 +238,11 @@ describe('injector', function() {
|
||||
|
||||
|
||||
it('should publish annotate API', function() {
|
||||
expect(injector.annotate).toBe(annotate);
|
||||
expect(angular.mock.$$annotate).toBe(annotate);
|
||||
spyOn(angular.mock, '$$annotate').andCallThrough();
|
||||
function fn() {}
|
||||
injector.annotate(fn);
|
||||
expect(angular.mock.$$annotate).toHaveBeenCalledWith(fn);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -972,7 +976,7 @@ describe('strict-di injector', function() {
|
||||
});
|
||||
});
|
||||
inject(function($injector) {
|
||||
expect (function() {
|
||||
expect(function() {
|
||||
$injector.invoke(function($test2) {});
|
||||
}).toThrowMinErr('$injector', 'strictdi');
|
||||
});
|
||||
@@ -986,7 +990,7 @@ describe('strict-di injector', function() {
|
||||
});
|
||||
});
|
||||
inject(function($injector) {
|
||||
expect (function() {
|
||||
expect(function() {
|
||||
$injector.invoke(['$test', function($test) {}]);
|
||||
}).toThrowMinErr('$injector', 'strictdi');
|
||||
});
|
||||
|
||||
@@ -74,19 +74,9 @@ afterEach(function() {
|
||||
|
||||
|
||||
// copied from Angular.js
|
||||
// we need these two methods here so that we can run module tests with wrapped angular.js
|
||||
function sortedKeys(obj) {
|
||||
var keys = [];
|
||||
for (var key in obj) {
|
||||
if (obj.hasOwnProperty(key)) {
|
||||
keys.push(key);
|
||||
}
|
||||
}
|
||||
return keys.sort();
|
||||
}
|
||||
|
||||
// we need this method here so that we can run module tests with wrapped angular.js
|
||||
function forEachSorted(obj, iterator, context) {
|
||||
var keys = sortedKeys(obj);
|
||||
var keys = Object.keys(obj).sort();
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
iterator.call(context, obj[keys[i]], keys[i]);
|
||||
}
|
||||
@@ -170,8 +160,9 @@ function sortedHtml(element, showNgClass) {
|
||||
attrs.push(' class="' + className + '"');
|
||||
}
|
||||
for (var i = 0; i < attributes.length; i++) {
|
||||
if (i > 0 && attributes[i] == attributes[i - 1])
|
||||
if (i > 0 && attributes[i] == attributes[i - 1]) {
|
||||
continue; //IE9 creates dupes. Ignore them!
|
||||
}
|
||||
|
||||
var attr = attributes[i];
|
||||
if (attr.name.match(/^ng[\:\-]/) ||
|
||||
@@ -231,8 +222,9 @@ function sortedHtml(element, showNgClass) {
|
||||
var tmp = style;
|
||||
style = [];
|
||||
forEach(tmp, function(value) {
|
||||
if (!value.match(/^max[^\-]/))
|
||||
if (!value.match(/^max[^\-]/)) {
|
||||
style.push(value);
|
||||
}
|
||||
});
|
||||
if (style.length) {
|
||||
html += ' style="' + style.join('; ') + ';"';
|
||||
|
||||
@@ -395,7 +395,7 @@ describe('browser', function() {
|
||||
});
|
||||
|
||||
|
||||
it ('should return a value for an existing cookie', function() {
|
||||
it('should return a value for an existing cookie', function() {
|
||||
document.cookie = "foo=bar=baz;path=/";
|
||||
expect(browser.cookies().foo).toEqual('bar=baz');
|
||||
});
|
||||
@@ -408,7 +408,7 @@ describe('browser', function() {
|
||||
expect(browser.cookies()['foo']).toBe('"first"');
|
||||
});
|
||||
|
||||
it ('should decode cookie values that were encoded by puts', function() {
|
||||
it('should decode cookie values that were encoded by puts', function() {
|
||||
document.cookie = "cookie2%3Dbar%3Bbaz=val%3Due;path=/";
|
||||
expect(browser.cookies()['cookie2=bar;baz']).toEqual('val=ue');
|
||||
});
|
||||
|
||||
+376
-20
@@ -423,8 +423,7 @@ describe('$compile', function() {
|
||||
describe('multiple directives per element', function() {
|
||||
it('should allow multiple directives per element', inject(function($compile, $rootScope, log) {
|
||||
element = $compile(
|
||||
'<span greet="angular" log="L" x-high-log="H" data-medium-log="M"></span>')
|
||||
($rootScope);
|
||||
'<span greet="angular" log="L" x-high-log="H" data-medium-log="M"></span>')($rootScope);
|
||||
expect(element.text()).toEqual('Hello angular');
|
||||
expect(log).toEqual('L; M; H');
|
||||
}));
|
||||
@@ -607,8 +606,7 @@ describe('$compile', function() {
|
||||
describe('priority', function() {
|
||||
it('should honor priority', inject(function($compile, $rootScope, log) {
|
||||
element = $compile(
|
||||
'<span log="L" x-high-log="H" data-medium-log="M"></span>')
|
||||
($rootScope);
|
||||
'<span log="L" x-high-log="H" data-medium-log="M"></span>')($rootScope);
|
||||
expect(log).toEqual('L; M; H');
|
||||
}));
|
||||
});
|
||||
@@ -809,8 +807,7 @@ describe('$compile', function() {
|
||||
|
||||
|
||||
it('should compile template when replacing', inject(function($compile, $rootScope, log) {
|
||||
element = $compile('<div><div replace medium-log>ignore</div><div>')
|
||||
($rootScope);
|
||||
element = $compile('<div><div replace medium-log>ignore</div><div>')($rootScope);
|
||||
$rootScope.$digest();
|
||||
expect(element.text()).toEqual('Replace!');
|
||||
expect(log).toEqual('LOG; HIGH; MEDIUM');
|
||||
@@ -818,8 +815,7 @@ describe('$compile', function() {
|
||||
|
||||
|
||||
it('should compile template when appending', inject(function($compile, $rootScope, log) {
|
||||
element = $compile('<div><div append medium-log>ignore</div><div>')
|
||||
($rootScope);
|
||||
element = $compile('<div><div append medium-log>ignore</div><div>')($rootScope);
|
||||
$rootScope.$digest();
|
||||
expect(element.text()).toEqual('Append!');
|
||||
expect(log).toEqual('LOG; HIGH; MEDIUM');
|
||||
@@ -828,8 +824,7 @@ describe('$compile', function() {
|
||||
|
||||
it('should merge attributes including style attr', inject(function($compile, $rootScope) {
|
||||
element = $compile(
|
||||
'<div><div replace class="medium-log" style="height: 20px" ></div><div>')
|
||||
($rootScope);
|
||||
'<div><div replace class="medium-log" style="height: 20px" ></div><div>')($rootScope);
|
||||
var div = element.find('div');
|
||||
expect(div.hasClass('medium-log')).toBe(true);
|
||||
expect(div.hasClass('log')).toBe(true);
|
||||
@@ -841,8 +836,7 @@ describe('$compile', function() {
|
||||
|
||||
it('should not merge attributes if they are the same', inject(function($compile, $rootScope) {
|
||||
element = $compile(
|
||||
'<div><div nomerge class="medium-log" id="myid"></div><div>')
|
||||
($rootScope);
|
||||
'<div><div nomerge class="medium-log" id="myid"></div><div>')($rootScope);
|
||||
var div = element.find('div');
|
||||
expect(div.hasClass('medium-log')).toBe(true);
|
||||
expect(div.hasClass('log')).toBe(true);
|
||||
@@ -1115,6 +1109,29 @@ describe('$compile', function() {
|
||||
expect(element.find('p').text()).toBe('Hello, world!');
|
||||
});
|
||||
});
|
||||
|
||||
it('should keep prototype properties on directive', function() {
|
||||
module(function() {
|
||||
function DirectiveClass() {
|
||||
this.restrict = 'E';
|
||||
this.template = "<p>{{value}}</p>";
|
||||
}
|
||||
|
||||
DirectiveClass.prototype.compile = function() {
|
||||
return function(scope, element, attrs) {
|
||||
scope.value = "Test Value";
|
||||
};
|
||||
};
|
||||
|
||||
directive('templateUrlWithPrototype', valueFn(new DirectiveClass()));
|
||||
});
|
||||
|
||||
inject(function($compile, $rootScope) {
|
||||
element = $compile('<template-url-with-prototype><template-url-with-prototype>')($rootScope);
|
||||
$rootScope.$digest();
|
||||
expect(element.find("p")[0].innerHTML).toEqual("Test Value");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -2034,6 +2051,32 @@ describe('$compile', function() {
|
||||
});
|
||||
});
|
||||
|
||||
it('should keep prototype properties on sync version of async directive', function() {
|
||||
module(function() {
|
||||
function DirectiveClass() {
|
||||
this.restrict = 'E';
|
||||
this.templateUrl = "test.html";
|
||||
}
|
||||
|
||||
DirectiveClass.prototype.compile = function() {
|
||||
return function(scope, element, attrs) {
|
||||
scope.value = "Test Value";
|
||||
};
|
||||
};
|
||||
|
||||
directive('templateUrlWithPrototype', valueFn(new DirectiveClass()));
|
||||
});
|
||||
|
||||
inject(function($compile, $rootScope, $httpBackend) {
|
||||
$httpBackend.whenGET('test.html').
|
||||
respond('<p>{{value}}</p>');
|
||||
element = $compile('<template-url-with-prototype><template-url-with-prototype>')($rootScope);
|
||||
$httpBackend.flush();
|
||||
$rootScope.$digest();
|
||||
expect(element.find("p")[0].innerHTML).toEqual("Test Value");
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
@@ -3090,7 +3133,9 @@ describe('$compile', function() {
|
||||
colref: '=*',
|
||||
colrefAlias: '=* colref',
|
||||
expr: '&',
|
||||
exprAlias: '&expr'
|
||||
optExpr: '&?',
|
||||
exprAlias: '&expr',
|
||||
constructor: '&?'
|
||||
},
|
||||
link: function(scope) {
|
||||
componentScope = scope;
|
||||
@@ -3230,6 +3275,38 @@ describe('$compile', function() {
|
||||
});
|
||||
|
||||
|
||||
it('should not initialize scope value if optional expression binding is not passed', inject(function($compile) {
|
||||
compile('<div my-component></div>');
|
||||
var isolateScope = element.isolateScope();
|
||||
expect(isolateScope.optExpr).toBeUndefined();
|
||||
}));
|
||||
|
||||
|
||||
it('should not initialize scope value if optional expression binding with Object.prototype name is not passed', inject(function($compile) {
|
||||
compile('<div my-component></div>');
|
||||
var isolateScope = element.isolateScope();
|
||||
expect(isolateScope.constructor).toBe($rootScope.constructor);
|
||||
}));
|
||||
|
||||
|
||||
it('should initialize scope value if optional expression binding is passed', inject(function($compile) {
|
||||
compile('<div my-component opt-expr="value = \'did!\'"></div>');
|
||||
var isolateScope = element.isolateScope();
|
||||
expect(typeof isolateScope.optExpr).toBe('function');
|
||||
expect(isolateScope.optExpr()).toBe('did!');
|
||||
expect($rootScope.value).toBe('did!');
|
||||
}));
|
||||
|
||||
|
||||
it('should initialize scope value if optional expression binding with Object.prototype name is passed', inject(function($compile) {
|
||||
compile('<div my-component constructor="value = \'did!\'"></div>');
|
||||
var isolateScope = element.isolateScope();
|
||||
expect(typeof isolateScope.constructor).toBe('function');
|
||||
expect(isolateScope.constructor()).toBe('did!');
|
||||
expect($rootScope.value).toBe('did!');
|
||||
}));
|
||||
|
||||
|
||||
describe('bind-once', function() {
|
||||
|
||||
function countWatches(scope) {
|
||||
@@ -3809,6 +3886,288 @@ describe('$compile', function() {
|
||||
expect(controllerCalled).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should throw noctrl when missing controller', function() {
|
||||
module(function($compileProvider) {
|
||||
$compileProvider.directive('noCtrl', valueFn({
|
||||
templateUrl: 'test.html',
|
||||
scope: {
|
||||
'data': '=dirData',
|
||||
'str': '@dirStr',
|
||||
'fn': '&dirFn'
|
||||
},
|
||||
controllerAs: 'test',
|
||||
bindToController: true
|
||||
}));
|
||||
});
|
||||
inject(function($compile, $rootScope) {
|
||||
expect(function() {
|
||||
$compile('<div no-ctrl>')($rootScope);
|
||||
}).toThrowMinErr('$compile', 'noctrl',
|
||||
'Cannot bind to controller without directive \'noCtrl\'s controller.');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should throw noident when missing controllerAs directive property', function() {
|
||||
module(function($compileProvider) {
|
||||
$compileProvider.directive('noIdent', valueFn({
|
||||
templateUrl: 'test.html',
|
||||
scope: {
|
||||
'data': '=dirData',
|
||||
'str': '@dirStr',
|
||||
'fn': '&dirFn'
|
||||
},
|
||||
controller: function() {},
|
||||
bindToController: true
|
||||
}));
|
||||
});
|
||||
inject(function($compile, $rootScope) {
|
||||
expect(function() {
|
||||
$compile('<div no-ident>')($rootScope);
|
||||
}).toThrowMinErr('$compile', 'noident',
|
||||
'Cannot bind to controller without identifier for directive \'noIdent\'.');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should throw noident when missing controller identifier', function() {
|
||||
module(function($compileProvider, $controllerProvider) {
|
||||
$controllerProvider.register('myCtrl', function() {});
|
||||
$compileProvider.directive('noIdent', valueFn({
|
||||
templateUrl: 'test.html',
|
||||
scope: {
|
||||
'data': '=dirData',
|
||||
'str': '@dirStr',
|
||||
'fn': '&dirFn'
|
||||
},
|
||||
controller: 'myCtrl',
|
||||
bindToController: true
|
||||
}));
|
||||
});
|
||||
inject(function($compile, $rootScope) {
|
||||
expect(function() {
|
||||
$compile('<div no-ident>')($rootScope);
|
||||
}).toThrowMinErr('$compile', 'noident',
|
||||
'Cannot bind to controller without identifier for directive \'noIdent\'.');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should bind to controller via object notation (isolate scope)', function() {
|
||||
var controllerCalled = false;
|
||||
module(function($compileProvider, $controllerProvider) {
|
||||
$controllerProvider.register('myCtrl', function() {
|
||||
expect(this.data).toEqualData({
|
||||
'foo': 'bar',
|
||||
'baz': 'biz'
|
||||
});
|
||||
expect(this.str).toBe('Hello, world!');
|
||||
expect(this.fn()).toBe('called!');
|
||||
controllerCalled = true;
|
||||
});
|
||||
$compileProvider.directive('fooDir', valueFn({
|
||||
templateUrl: 'test.html',
|
||||
bindToController: {
|
||||
'data': '=dirData',
|
||||
'str': '@dirStr',
|
||||
'fn': '&dirFn'
|
||||
},
|
||||
scope: {},
|
||||
controller: 'myCtrl as myCtrl'
|
||||
}));
|
||||
});
|
||||
inject(function($compile, $rootScope, $templateCache) {
|
||||
$templateCache.put('test.html', '<p>isolate</p>');
|
||||
$rootScope.fn = valueFn('called!');
|
||||
$rootScope.whom = 'world';
|
||||
$rootScope.remoteData = {
|
||||
'foo': 'bar',
|
||||
'baz': 'biz'
|
||||
};
|
||||
element = $compile('<div foo-dir dir-data="remoteData" ' +
|
||||
'dir-str="Hello, {{whom}}!" ' +
|
||||
'dir-fn="fn()"></div>')($rootScope);
|
||||
$rootScope.$digest();
|
||||
expect(controllerCalled).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should bind to controller via object notation (new scope)', function() {
|
||||
var controllerCalled = false;
|
||||
module(function($compileProvider, $controllerProvider) {
|
||||
$controllerProvider.register('myCtrl', function() {
|
||||
expect(this.data).toEqualData({
|
||||
'foo': 'bar',
|
||||
'baz': 'biz'
|
||||
});
|
||||
expect(this.str).toBe('Hello, world!');
|
||||
expect(this.fn()).toBe('called!');
|
||||
controllerCalled = true;
|
||||
});
|
||||
$compileProvider.directive('fooDir', valueFn({
|
||||
templateUrl: 'test.html',
|
||||
bindToController: {
|
||||
'data': '=dirData',
|
||||
'str': '@dirStr',
|
||||
'fn': '&dirFn'
|
||||
},
|
||||
scope: true,
|
||||
controller: 'myCtrl as myCtrl'
|
||||
}));
|
||||
});
|
||||
inject(function($compile, $rootScope, $templateCache) {
|
||||
$templateCache.put('test.html', '<p>isolate</p>');
|
||||
$rootScope.fn = valueFn('called!');
|
||||
$rootScope.whom = 'world';
|
||||
$rootScope.remoteData = {
|
||||
'foo': 'bar',
|
||||
'baz': 'biz'
|
||||
};
|
||||
element = $compile('<div foo-dir dir-data="remoteData" ' +
|
||||
'dir-str="Hello, {{whom}}!" ' +
|
||||
'dir-fn="fn()"></div>')($rootScope);
|
||||
$rootScope.$digest();
|
||||
expect(controllerCalled).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should put controller in scope when controller identifier present but not using controllerAs', function() {
|
||||
var controllerCalled = false;
|
||||
var myCtrl;
|
||||
module(function($compileProvider, $controllerProvider) {
|
||||
$controllerProvider.register('myCtrl', function() {
|
||||
controllerCalled = true;
|
||||
myCtrl = this;
|
||||
});
|
||||
$compileProvider.directive('fooDir', valueFn({
|
||||
templateUrl: 'test.html',
|
||||
bindToController: {},
|
||||
scope: true,
|
||||
controller: 'myCtrl as theCtrl'
|
||||
}));
|
||||
});
|
||||
inject(function($compile, $rootScope, $templateCache) {
|
||||
$templateCache.put('test.html', '<p>isolate</p>');
|
||||
element = $compile('<div foo-dir>')($rootScope);
|
||||
$rootScope.$digest();
|
||||
expect(controllerCalled).toBe(true);
|
||||
var childScope = element.children().scope();
|
||||
expect(childScope).not.toBe($rootScope);
|
||||
expect(childScope.theCtrl).toBe(myCtrl);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should re-install controllerAs and bindings for returned value from controller (new scope)', function() {
|
||||
var controllerCalled = false;
|
||||
var myCtrl;
|
||||
|
||||
function MyCtrl() {
|
||||
}
|
||||
MyCtrl.prototype.test = function() {
|
||||
expect(this.data).toEqualData({
|
||||
'foo': 'bar',
|
||||
'baz': 'biz'
|
||||
});
|
||||
expect(this.str).toBe('Hello, world!');
|
||||
expect(this.fn()).toBe('called!');
|
||||
};
|
||||
|
||||
module(function($compileProvider, $controllerProvider) {
|
||||
$controllerProvider.register('myCtrl', function() {
|
||||
controllerCalled = true;
|
||||
myCtrl = this;
|
||||
return new MyCtrl();
|
||||
});
|
||||
$compileProvider.directive('fooDir', valueFn({
|
||||
templateUrl: 'test.html',
|
||||
bindToController: {
|
||||
'data': '=dirData',
|
||||
'str': '@dirStr',
|
||||
'fn': '&dirFn'
|
||||
},
|
||||
scope: true,
|
||||
controller: 'myCtrl as theCtrl'
|
||||
}));
|
||||
});
|
||||
inject(function($compile, $rootScope, $templateCache) {
|
||||
$templateCache.put('test.html', '<p>isolate</p>');
|
||||
$rootScope.fn = valueFn('called!');
|
||||
$rootScope.whom = 'world';
|
||||
$rootScope.remoteData = {
|
||||
'foo': 'bar',
|
||||
'baz': 'biz'
|
||||
};
|
||||
element = $compile('<div foo-dir dir-data="remoteData" ' +
|
||||
'dir-str="Hello, {{whom}}!" ' +
|
||||
'dir-fn="fn()"></div>')($rootScope);
|
||||
$rootScope.$digest();
|
||||
expect(controllerCalled).toBe(true);
|
||||
var childScope = element.children().scope();
|
||||
expect(childScope).not.toBe($rootScope);
|
||||
expect(childScope.theCtrl).not.toBe(myCtrl);
|
||||
expect(childScope.theCtrl.constructor).toBe(MyCtrl);
|
||||
childScope.theCtrl.test();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should re-install controllerAs and bindings for returned value from controller (isolate scope)', function() {
|
||||
var controllerCalled = false;
|
||||
var myCtrl;
|
||||
|
||||
function MyCtrl() {
|
||||
}
|
||||
MyCtrl.prototype.test = function() {
|
||||
expect(this.data).toEqualData({
|
||||
'foo': 'bar',
|
||||
'baz': 'biz'
|
||||
});
|
||||
expect(this.str).toBe('Hello, world!');
|
||||
expect(this.fn()).toBe('called!');
|
||||
};
|
||||
|
||||
module(function($compileProvider, $controllerProvider) {
|
||||
$controllerProvider.register('myCtrl', function() {
|
||||
controllerCalled = true;
|
||||
myCtrl = this;
|
||||
return new MyCtrl();
|
||||
});
|
||||
$compileProvider.directive('fooDir', valueFn({
|
||||
templateUrl: 'test.html',
|
||||
bindToController: true,
|
||||
scope: {
|
||||
'data': '=dirData',
|
||||
'str': '@dirStr',
|
||||
'fn': '&dirFn'
|
||||
},
|
||||
controller: 'myCtrl as theCtrl'
|
||||
}));
|
||||
});
|
||||
inject(function($compile, $rootScope, $templateCache) {
|
||||
$templateCache.put('test.html', '<p>isolate</p>');
|
||||
$rootScope.fn = valueFn('called!');
|
||||
$rootScope.whom = 'world';
|
||||
$rootScope.remoteData = {
|
||||
'foo': 'bar',
|
||||
'baz': 'biz'
|
||||
};
|
||||
element = $compile('<div foo-dir dir-data="remoteData" ' +
|
||||
'dir-str="Hello, {{whom}}!" ' +
|
||||
'dir-fn="fn()"></div>')($rootScope);
|
||||
$rootScope.$digest();
|
||||
expect(controllerCalled).toBe(true);
|
||||
var childScope = element.children().scope();
|
||||
expect(childScope).not.toBe($rootScope);
|
||||
expect(childScope.theCtrl).not.toBe(myCtrl);
|
||||
expect(childScope.theCtrl.constructor).toBe(MyCtrl);
|
||||
childScope.theCtrl.test();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -4610,8 +4969,7 @@ describe('$compile', function() {
|
||||
});
|
||||
});
|
||||
inject(function(log, $rootScope, $compile) {
|
||||
element = $compile('<div><div trans>T:{{x}}-{{$parent.$id}}-{{$id}}<span>;</span></div></div>')
|
||||
($rootScope);
|
||||
element = $compile('<div><div trans>T:{{x}}-{{$parent.$id}}-{{$id}}<span>;</span></div></div>')($rootScope);
|
||||
$rootScope.x = 'root';
|
||||
$rootScope.$apply();
|
||||
expect(element.text()).toEqual('W:iso-1-2;T:root-2-3;');
|
||||
@@ -4896,8 +5254,7 @@ describe('$compile', function() {
|
||||
});
|
||||
});
|
||||
inject(function(log, $rootScope, $compile) {
|
||||
element = $compile('<div><div trans>T:{{$$transcluded}}</div></div>')
|
||||
($rootScope);
|
||||
element = $compile('<div><div trans>T:{{$$transcluded}}</div></div>')($rootScope);
|
||||
$rootScope.$apply();
|
||||
expect(jqLite(element.find('span')[0]).text()).toEqual('I:');
|
||||
expect(jqLite(element.find('span')[1]).text()).toEqual('T:true');
|
||||
@@ -5728,8 +6085,7 @@ describe('$compile', function() {
|
||||
});
|
||||
});
|
||||
inject(function(log, $rootScope, $compile) {
|
||||
element = $compile('<div><div high-log trans="text" log>{{$parent.$id}}-{{$id}};</div></div>')
|
||||
($rootScope);
|
||||
element = $compile('<div><div high-log trans="text" log>{{$parent.$id}}-{{$id}};</div></div>')($rootScope);
|
||||
$rootScope.$apply();
|
||||
expect(log).toEqual('compile: <!-- trans: text -->; link; LOG; LOG; HIGH');
|
||||
expect(element.text()).toEqual('1-2;1-3;');
|
||||
@@ -6065,7 +6421,7 @@ describe('$compile', function() {
|
||||
link: function(scope, element, attrs, ctrl, transclude) {
|
||||
|
||||
// We use timeout here to simulate how ng-if works
|
||||
$timeout(function() {
|
||||
$timeout(function() {
|
||||
transclude(function(child) { element.append(child); });
|
||||
});
|
||||
}
|
||||
|
||||
@@ -90,7 +90,16 @@ describe('$controller', function() {
|
||||
var foo = $controller('a.Foo', {$scope: scope});
|
||||
expect(foo).toBeDefined();
|
||||
expect(foo instanceof Foo).toBe(true);
|
||||
}));
|
||||
}));
|
||||
|
||||
|
||||
it('should throw ctrlfmt if name contains spaces', function() {
|
||||
expect(function() {
|
||||
$controller('ctrl doom');
|
||||
}).toThrowMinErr("$controller", "ctrlfmt",
|
||||
"Badly formed controller string 'ctrl doom'. " +
|
||||
"Must match `__name__ as __id__` or `__name__`.");
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -168,5 +177,37 @@ describe('$controller', function() {
|
||||
}).toThrowMinErr("$controller", "noscp", "Cannot export controller 'a.b.FooCtrl' as 'foo'! No $scope object provided via `locals`.");
|
||||
|
||||
});
|
||||
|
||||
|
||||
it('should throw ctrlfmt if identifier contains non-ident characters', function() {
|
||||
expect(function() {
|
||||
$controller('ctrl as foo<bar');
|
||||
}).toThrowMinErr("$controller", "ctrlfmt",
|
||||
"Badly formed controller string 'ctrl as foo<bar'. " +
|
||||
"Must match `__name__ as __id__` or `__name__`.");
|
||||
});
|
||||
|
||||
|
||||
it('should throw ctrlfmt if identifier contains spaces', function() {
|
||||
expect(function() {
|
||||
$controller('ctrl as foo bar');
|
||||
}).toThrowMinErr("$controller", "ctrlfmt",
|
||||
"Badly formed controller string 'ctrl as foo bar'. " +
|
||||
"Must match `__name__ as __id__` or `__name__`.");
|
||||
});
|
||||
|
||||
|
||||
it('should throw ctrlfmt if identifier missing after " as "', function() {
|
||||
expect(function() {
|
||||
$controller('ctrl as ');
|
||||
}).toThrowMinErr("$controller", "ctrlfmt",
|
||||
"Badly formed controller string 'ctrl as '. " +
|
||||
"Must match `__name__ as __id__` or `__name__`.");
|
||||
expect(function() {
|
||||
$controller('ctrl as');
|
||||
}).toThrowMinErr("$controller", "ctrlfmt",
|
||||
"Badly formed controller string 'ctrl as'. " +
|
||||
"Must match `__name__ as __id__` or `__name__`.");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
+47
-20
@@ -3,6 +3,25 @@
|
||||
describe('a', function() {
|
||||
var element, $compile, $rootScope;
|
||||
|
||||
beforeEach(module(function($compileProvider) {
|
||||
$compileProvider.
|
||||
directive('linkTo', valueFn({
|
||||
restrict: 'A',
|
||||
template: '<div class="my-link"><a href="{{destination}}">{{destination}}</a></div>',
|
||||
replace: true,
|
||||
scope: {
|
||||
destination: '@linkTo'
|
||||
}
|
||||
})).
|
||||
directive('linkNot', valueFn({
|
||||
restrict: 'A',
|
||||
template: '<div class="my-link"><a href>{{destination}}</a></div>',
|
||||
replace: true,
|
||||
scope: {
|
||||
destination: '@linkNot'
|
||||
}
|
||||
}));
|
||||
}));
|
||||
|
||||
beforeEach(inject(function(_$compile_, _$rootScope_) {
|
||||
$compile = _$compile_;
|
||||
@@ -63,16 +82,37 @@ describe('a', function() {
|
||||
});
|
||||
|
||||
|
||||
it('should not link and hookup an event if name is present at compile', function() {
|
||||
var jq = jQuery || jqLite;
|
||||
element = jq('<a name="bobby">hello@you</a>');
|
||||
var linker = $compile(element);
|
||||
it('should not preventDefault if anchor element is replaced with href-containing element', function() {
|
||||
spyOn(jqLite.prototype, 'on').andCallThrough();
|
||||
element = $compile('<a link-to="https://www.google.com">')($rootScope);
|
||||
$rootScope.$digest();
|
||||
|
||||
spyOn(jq.prototype, 'on');
|
||||
var child = element.children('a');
|
||||
var preventDefault = jasmine.createSpy('preventDefault');
|
||||
|
||||
linker($rootScope);
|
||||
child.triggerHandler({
|
||||
type: 'click',
|
||||
preventDefault: preventDefault
|
||||
});
|
||||
|
||||
expect(jq.prototype.on).not.toHaveBeenCalled();
|
||||
expect(preventDefault).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
|
||||
it('should preventDefault if anchor element is replaced with element without href attribute', function() {
|
||||
spyOn(jqLite.prototype, 'on').andCallThrough();
|
||||
element = $compile('<a link-not="https://www.google.com">')($rootScope);
|
||||
$rootScope.$digest();
|
||||
|
||||
var child = element.children('a');
|
||||
var preventDefault = jasmine.createSpy('preventDefault');
|
||||
|
||||
child.triggerHandler({
|
||||
type: 'click',
|
||||
preventDefault: preventDefault
|
||||
});
|
||||
|
||||
expect(preventDefault).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
|
||||
@@ -115,19 +155,6 @@ describe('a', function() {
|
||||
|
||||
expect(jq.prototype.on).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
|
||||
it('should not link and hookup an event if name is present at compile', function() {
|
||||
var jq = jQuery || jqLite;
|
||||
element = jq('<svg><a name="bobby">hello@you</a></svg>');
|
||||
var linker = $compile(element);
|
||||
|
||||
spyOn(jq.prototype, 'on');
|
||||
|
||||
linker($rootScope);
|
||||
|
||||
expect(jq.prototype.on).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1641,9 +1641,9 @@ describe('input', function() {
|
||||
});
|
||||
});
|
||||
|
||||
describe('max', function() {
|
||||
describe('max', function() {
|
||||
|
||||
it('should invalidate', function() {
|
||||
it('should invalidate', function() {
|
||||
var inputElm = helper.compileInput('<input type="date" ng-model="value" name="alias" max="2019-01-01" />');
|
||||
helper.changeInputValueTo('2019-12-31');
|
||||
expect(inputElm).toBeInvalid();
|
||||
|
||||
@@ -83,52 +83,64 @@ describe('ngPluralize', function() {
|
||||
}));
|
||||
|
||||
|
||||
it('should show single/plural strings with mal-formed inputs', inject(function($rootScope) {
|
||||
$rootScope.email = '';
|
||||
$rootScope.$digest();
|
||||
expect(element.text()).toBe('');
|
||||
expect(elementAlt.text()).toBe('');
|
||||
it('should show single/plural strings with mal-formed inputs', inject(
|
||||
function($log, $rootScope) {
|
||||
$rootScope.email = '';
|
||||
$rootScope.$digest();
|
||||
expect(element.text()).toBe('');
|
||||
expect(elementAlt.text()).toBe('');
|
||||
expect($log.debug.logs.shift()).toEqual([
|
||||
"ngPluralize: no rule defined for 'NaN' in {" +
|
||||
"'-1': 'You have negative email. Whohoo!'," +
|
||||
"'0': 'You have no new email'," +
|
||||
"'one': 'You have one new email'," +
|
||||
"'other': 'You have {} new emails'}"
|
||||
]);
|
||||
expect($log.debug.logs.shift()).toEqual([
|
||||
"ngPluralize: no rule defined for 'NaN' in undefined"
|
||||
]);
|
||||
|
||||
$rootScope.email = null;
|
||||
$rootScope.$digest();
|
||||
expect(element.text()).toBe('');
|
||||
expect(elementAlt.text()).toBe('');
|
||||
$rootScope.email = null;
|
||||
$rootScope.$digest();
|
||||
expect(element.text()).toBe('');
|
||||
expect(elementAlt.text()).toBe('');
|
||||
|
||||
$rootScope.email = undefined;
|
||||
$rootScope.$digest();
|
||||
expect(element.text()).toBe('');
|
||||
expect(elementAlt.text()).toBe('');
|
||||
$rootScope.email = undefined;
|
||||
$rootScope.$digest();
|
||||
expect(element.text()).toBe('');
|
||||
expect(elementAlt.text()).toBe('');
|
||||
|
||||
$rootScope.email = 'a3';
|
||||
$rootScope.$digest();
|
||||
expect(element.text()).toBe('');
|
||||
expect(elementAlt.text()).toBe('');
|
||||
$rootScope.email = 'a3';
|
||||
$rootScope.$digest();
|
||||
expect(element.text()).toBe('');
|
||||
expect(elementAlt.text()).toBe('');
|
||||
|
||||
$rootScope.email = '011';
|
||||
$rootScope.$digest();
|
||||
expect(element.text()).toBe('You have 11 new emails');
|
||||
expect(elementAlt.text()).toBe('You have 11 new emails');
|
||||
$rootScope.email = '011';
|
||||
$rootScope.$digest();
|
||||
expect(element.text()).toBe('You have 11 new emails');
|
||||
expect(elementAlt.text()).toBe('You have 11 new emails');
|
||||
|
||||
$rootScope.email = '-011';
|
||||
$rootScope.$digest();
|
||||
expect(element.text()).toBe('You have -11 new emails');
|
||||
expect(elementAlt.text()).toBe('You have -11 new emails');
|
||||
$rootScope.email = '-011';
|
||||
$rootScope.$digest();
|
||||
expect(element.text()).toBe('You have -11 new emails');
|
||||
expect(elementAlt.text()).toBe('You have -11 new emails');
|
||||
|
||||
$rootScope.email = '1fff';
|
||||
$rootScope.$digest();
|
||||
expect(element.text()).toBe('You have one new email');
|
||||
expect(elementAlt.text()).toBe('You have one new email');
|
||||
$rootScope.email = '1fff';
|
||||
$rootScope.$digest();
|
||||
expect(element.text()).toBe('You have one new email');
|
||||
expect(elementAlt.text()).toBe('You have one new email');
|
||||
|
||||
$rootScope.email = '0aa22';
|
||||
$rootScope.$digest();
|
||||
expect(element.text()).toBe('You have no new email');
|
||||
expect(elementAlt.text()).toBe('You have no new email');
|
||||
$rootScope.email = '0aa22';
|
||||
$rootScope.$digest();
|
||||
expect(element.text()).toBe('You have no new email');
|
||||
expect(elementAlt.text()).toBe('You have no new email');
|
||||
|
||||
$rootScope.email = '000001';
|
||||
$rootScope.$digest();
|
||||
expect(element.text()).toBe('You have one new email');
|
||||
expect(elementAlt.text()).toBe('You have one new email');
|
||||
}));
|
||||
$rootScope.email = '000001';
|
||||
$rootScope.$digest();
|
||||
expect(element.text()).toBe('You have one new email');
|
||||
expect(elementAlt.text()).toBe('You have one new email');
|
||||
}
|
||||
));
|
||||
});
|
||||
|
||||
|
||||
@@ -144,6 +156,33 @@ describe('ngPluralize', function() {
|
||||
$rootScope.$digest();
|
||||
expect(element.text()).toBe('');
|
||||
}));
|
||||
|
||||
it('should be able to specify a message for null/undefined values', inject(
|
||||
function($compile, $rootScope) {
|
||||
element = $compile(
|
||||
'<ng:pluralize count="email"' +
|
||||
"when=\"{'NaN': 'Unspecified email count'," +
|
||||
"'0': ''," +
|
||||
"'one': 'Some text'," +
|
||||
"'other': 'Some text'}\">" +
|
||||
'</ng:pluralize>')($rootScope);
|
||||
|
||||
$rootScope.email = '0';
|
||||
$rootScope.$digest();
|
||||
expect(element.text()).toBe('');
|
||||
|
||||
$rootScope.email = undefined;
|
||||
$rootScope.$digest();
|
||||
expect(element.text()).toBe('Unspecified email count');
|
||||
|
||||
$rootScope.email = '1';
|
||||
$rootScope.$digest();
|
||||
expect(element.text()).toBe('Some text');
|
||||
|
||||
$rootScope.email = null;
|
||||
$rootScope.$digest();
|
||||
expect(element.text()).toBe('Unspecified email count');
|
||||
}));
|
||||
});
|
||||
|
||||
describe('undefined rule cases', function() {
|
||||
@@ -195,6 +234,10 @@ describe('ngPluralize', function() {
|
||||
$rootScope.email = '1';
|
||||
$rootScope.$digest();
|
||||
expect(element.text()).toBe('Some text');
|
||||
|
||||
$rootScope.email = null;
|
||||
$rootScope.$digest();
|
||||
expect(element.text()).toBe('');
|
||||
}));
|
||||
});
|
||||
|
||||
@@ -243,6 +286,11 @@ describe('ngPluralize', function() {
|
||||
$rootScope.$digest();
|
||||
expect(element.text()).toBe('Igor, Misko and 2 other people are viewing.');
|
||||
expect(elementAlt.text()).toBe('Igor, Misko and 2 other people are viewing.');
|
||||
|
||||
$rootScope.viewCount = null;
|
||||
$rootScope.$digest();
|
||||
expect(element.text()).toBe('');
|
||||
expect(elementAlt.text()).toBe('');
|
||||
}));
|
||||
});
|
||||
|
||||
@@ -296,7 +344,6 @@ describe('ngPluralize', function() {
|
||||
|
||||
|
||||
describe('bind-once', function() {
|
||||
|
||||
it('should support for `count` to be a one-time expression',
|
||||
inject(function($compile, $rootScope) {
|
||||
element = $compile(
|
||||
@@ -320,6 +367,11 @@ describe('ngPluralize', function() {
|
||||
expect(element.text()).toBe('You have 3 new emails');
|
||||
expect(elementAlt.text()).toBe('You have 3 new emails');
|
||||
|
||||
$rootScope.email = null;
|
||||
$rootScope.$digest();
|
||||
expect(element.text()).toBe('You have 3 new emails');
|
||||
expect(elementAlt.text()).toBe('You have 3 new emails');
|
||||
|
||||
$rootScope.email = 2;
|
||||
$rootScope.$digest();
|
||||
expect(element.text()).toBe('You have 3 new emails');
|
||||
|
||||
@@ -254,6 +254,20 @@ describe('validators', function() {
|
||||
expect($rootScope.value).toBe(12345);
|
||||
expect($rootScope.form.input.$error.minlength).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should validate emptiness against the viewValue', function() {
|
||||
var inputElm = helper.compileInput('<input type="text" name="input" ng-model="value" minlength="3" />');
|
||||
|
||||
var ctrl = inputElm.controller('ngModel');
|
||||
spyOn(ctrl, '$isEmpty').andCallThrough();
|
||||
|
||||
ctrl.$parsers.push(function(value) {
|
||||
return value + '678';
|
||||
});
|
||||
|
||||
helper.changeInputValueTo('12345');
|
||||
expect(ctrl.$isEmpty).toHaveBeenCalledWith('12345');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -410,6 +424,20 @@ describe('validators', function() {
|
||||
expect($rootScope.value).toBe(12345);
|
||||
expect($rootScope.form.input.$error.maxlength).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should validate emptiness against the viewValue', function() {
|
||||
var inputElm = helper.compileInput('<input type="text" name="input" ng-model="value" maxlength="10" />');
|
||||
|
||||
var ctrl = inputElm.controller('ngModel');
|
||||
spyOn(ctrl, '$isEmpty').andCallThrough();
|
||||
|
||||
ctrl.$parsers.push(function(value) {
|
||||
return value + '678';
|
||||
});
|
||||
|
||||
helper.changeInputValueTo('12345');
|
||||
expect(ctrl.$isEmpty).toHaveBeenCalledWith('12345');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -503,5 +531,19 @@ describe('validators', function() {
|
||||
$rootScope.$apply("answer = false");
|
||||
expect(inputElm).toBeValid();
|
||||
});
|
||||
|
||||
it('should validate emptiness against the viewValue', function() {
|
||||
var inputElm = helper.compileInput('<input type="text" name="input" ng-model="value" required />');
|
||||
|
||||
var ctrl = inputElm.controller('ngModel');
|
||||
spyOn(ctrl, '$isEmpty').andCallThrough();
|
||||
|
||||
ctrl.$parsers.push(function(value) {
|
||||
return value + '678';
|
||||
});
|
||||
|
||||
helper.changeInputValueTo('12345');
|
||||
expect(ctrl.$isEmpty).toHaveBeenCalledWith('12345');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -271,7 +271,7 @@ describe('Filter: filter', function() {
|
||||
expect(filter(items, expr, true).length).toBe(1);
|
||||
expect(filter(items, expr, true)[0]).toBe(items[0]);
|
||||
|
||||
// Inherited function proprties
|
||||
// Inherited function properties
|
||||
function Item(text) {
|
||||
this.text = text;
|
||||
}
|
||||
@@ -399,6 +399,35 @@ describe('Filter: filter', function() {
|
||||
});
|
||||
|
||||
|
||||
it('should throw an error when is not used with an array', function() {
|
||||
var item = {'not': 'array'};
|
||||
expect(function() { filter(item, {}); }).
|
||||
toThrowMinErr('filter', 'notarray', 'Expected array but received: {"not":"array"}');
|
||||
|
||||
item = Object.create(null);
|
||||
expect(function() { filter(item, {}); }).
|
||||
toThrowMinErr('filter', 'notarray', 'Expected array but received: {}');
|
||||
|
||||
item = {
|
||||
toString: null,
|
||||
valueOf: null
|
||||
};
|
||||
expect(function() { filter(item, {}); }).
|
||||
toThrowMinErr('filter', 'notarray', 'Expected array but received: {"toString":null,"valueOf":null}');
|
||||
});
|
||||
|
||||
|
||||
it('should return undefined when the array is undefined', function() {
|
||||
expect(filter(undefined, {})).toBeUndefined();
|
||||
});
|
||||
|
||||
|
||||
it('should return null when the value of the array is null', function() {
|
||||
var item = null;
|
||||
expect(filter(item, {})).toBe(null);
|
||||
});
|
||||
|
||||
|
||||
describe('should support comparator', function() {
|
||||
|
||||
it('not consider `object === "[object Object]"` in non-strict comparison', function() {
|
||||
|
||||
@@ -456,6 +456,16 @@ describe('filters', function() {
|
||||
it('should use UTC if the timezone is set to "UTC"', function() {
|
||||
expect(date(new Date(2003, 8, 10, 3, 2, 4), 'yyyy-MM-dd HH-mm-ss')).toEqual('2003-09-10 03-02-04');
|
||||
expect(date(new Date(Date.UTC(2003, 8, 10, 3, 2, 4)), 'yyyy-MM-dd HH-mm-ss', 'UTC')).toEqual('2003-09-10 03-02-04');
|
||||
expect(date(new Date(Date.UTC(2003, 8, 10, 3, 2, 4)), 'yyyy-MM-dd HH-mm-ssZ', 'UTC')).toEqual('2003-09-10 03-02-04+0000');
|
||||
});
|
||||
|
||||
it('should support conversion to any timezone', function() {
|
||||
expect(date(new Date(Date.UTC(2003, 8, 10, 3, 2, 4)), 'yyyy-MM-dd HH-mm-ssZ', 'GMT+0500')).toEqual('2003-09-10 08-02-04+0500');
|
||||
});
|
||||
|
||||
it('should fallback to default timezone in case an unknown timezone was passed', function() {
|
||||
var value = new angular.mock.TzDate(-2, '2003-09-10T01:02:04.000Z');
|
||||
expect(date(value, 'yyyy-MM-dd HH-mm-ssZ', 'WTF')).toEqual('2003-09-10 03-02-04+0200');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
+30
-7
@@ -673,6 +673,16 @@ describe('$location', function() {
|
||||
}));
|
||||
});
|
||||
|
||||
describe('rewrite hashbang url <> html5 url', function() {
|
||||
beforeEach(initService({html5Mode: true, supportHistory: true}));
|
||||
beforeEach(inject(initBrowser({url:'http://new.com/#', basePath: '/'})));
|
||||
|
||||
it('should not replace browser url if only the empty hash fragment is cleared', inject(function($browser, $location) {
|
||||
expect($browser.url()).toBe('http://new.com/#');
|
||||
expect($location.absUrl()).toBe('http://new.com/');
|
||||
}));
|
||||
});
|
||||
|
||||
describe('wiring', function() {
|
||||
|
||||
beforeEach(initService({html5Mode:false,hashPrefix: '!',supportHistory: true}));
|
||||
@@ -1272,7 +1282,7 @@ describe('$location', function() {
|
||||
|
||||
|
||||
it('should not rewrite links with target="_blank"', function() {
|
||||
configureService({linkHref: '/a?b=c', html5Mode: true, supportHist: true, attrs: 'target="_blank"'});
|
||||
configureService({linkHref: 'base/a?b=c', html5Mode: true, supportHist: true, attrs: 'target="_blank"'});
|
||||
inject(
|
||||
initBrowser(),
|
||||
initLocation(),
|
||||
@@ -1285,7 +1295,7 @@ describe('$location', function() {
|
||||
|
||||
|
||||
it('should not rewrite links with target specified', function() {
|
||||
configureService({linkHref: '/a?b=c', html5Mode: true, supportHist: true, attrs: 'target="some-frame"'});
|
||||
configureService({linkHref: 'base/a?b=c', html5Mode: true, supportHist: true, attrs: 'target="some-frame"'});
|
||||
inject(
|
||||
initBrowser(),
|
||||
initLocation(),
|
||||
@@ -1323,7 +1333,7 @@ describe('$location', function() {
|
||||
});
|
||||
|
||||
|
||||
it ('should not rewrite links when rewriting links is disabled', function() {
|
||||
it('should not rewrite links when rewriting links is disabled', function() {
|
||||
configureService({linkHref: 'link?a#b', html5Mode: {enabled: true, rewriteLinks:false}, supportHist: true});
|
||||
inject(
|
||||
initBrowser(),
|
||||
@@ -1480,7 +1490,7 @@ describe('$location', function() {
|
||||
});
|
||||
|
||||
it('should not rewrite when clicked with ctrl pressed', function() {
|
||||
configureService({linkHref: '/a?b=c', html5Mode: true, supportHist: true});
|
||||
configureService({linkHref: 'base/a?b=c', html5Mode: true, supportHist: true});
|
||||
inject(
|
||||
initBrowser(),
|
||||
initLocation(),
|
||||
@@ -1493,7 +1503,7 @@ describe('$location', function() {
|
||||
|
||||
|
||||
it('should not rewrite when clicked with meta pressed', function() {
|
||||
configureService({linkHref: '/a?b=c', html5Mode: true, supportHist: true});
|
||||
configureService({linkHref: 'base/a?b=c', html5Mode: true, supportHist: true});
|
||||
inject(
|
||||
initBrowser(),
|
||||
initLocation(),
|
||||
@@ -1505,7 +1515,7 @@ describe('$location', function() {
|
||||
});
|
||||
|
||||
it('should not rewrite when right click pressed', function() {
|
||||
configureService({linkHref: '/a?b=c', html5Mode: true, supportHist: true});
|
||||
configureService({linkHref: 'base/a?b=c', html5Mode: true, supportHist: true});
|
||||
inject(
|
||||
initBrowser(),
|
||||
initLocation(),
|
||||
@@ -1539,6 +1549,19 @@ describe('$location', function() {
|
||||
});
|
||||
|
||||
|
||||
it('should not rewrite when clicked with shift pressed', function() {
|
||||
configureService({linkHref: 'base/a?b=c', html5Mode: true, supportHist: true});
|
||||
inject(
|
||||
initBrowser(),
|
||||
initLocation(),
|
||||
function($browser) {
|
||||
browserTrigger(link, 'click', { keys: ['shift'] });
|
||||
expectNoRewrite($browser);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
it('should not mess up hash urls when clicking on links in hashbang mode', function() {
|
||||
var base;
|
||||
module(function() {
|
||||
@@ -1847,7 +1870,7 @@ describe('$location', function() {
|
||||
})
|
||||
);
|
||||
|
||||
it ('should fire $locationChangeSuccess event when change from browser location bar',
|
||||
it('should fire $locationChangeSuccess event when change from browser location bar',
|
||||
inject(function($log, $location, $browser, $rootScope) {
|
||||
$rootScope.$apply(); // clear initial $locationChangeStart
|
||||
|
||||
|
||||
+1663
-7
File diff suppressed because it is too large
Load Diff
@@ -14,7 +14,7 @@ describe('Scope', function() {
|
||||
|
||||
it('should expose the constructor', inject(function($rootScope) {
|
||||
/* jshint -W103 */
|
||||
if (msie) return;
|
||||
if (msie < 11) return;
|
||||
expect($rootScope.__proto__).toBe($rootScope.constructor.prototype);
|
||||
}));
|
||||
|
||||
@@ -135,9 +135,67 @@ describe('Scope', function() {
|
||||
it('should not keep constant expressions on watch queue', inject(function($rootScope) {
|
||||
$rootScope.$watch('1 + 1', function() {});
|
||||
expect($rootScope.$$watchers.length).toEqual(1);
|
||||
expect($rootScope.$$watchersCount).toEqual(1);
|
||||
$rootScope.$digest();
|
||||
|
||||
expect($rootScope.$$watchers.length).toEqual(0);
|
||||
expect($rootScope.$$watchersCount).toEqual(0);
|
||||
}));
|
||||
|
||||
it('should decrement the watcherCount when destroying a child scope', inject(function($rootScope) {
|
||||
var child1 = $rootScope.$new(),
|
||||
child2 = $rootScope.$new(),
|
||||
grandChild1 = child1.$new(),
|
||||
grandChild2 = child2.$new();
|
||||
|
||||
child1.$watch('a', function() {});
|
||||
child2.$watch('a', function() {});
|
||||
grandChild1.$watch('a', function() {});
|
||||
grandChild2.$watch('a', function() {});
|
||||
|
||||
expect($rootScope.$$watchersCount).toBe(4);
|
||||
expect(child1.$$watchersCount).toBe(2);
|
||||
expect(child2.$$watchersCount).toBe(2);
|
||||
expect(grandChild1.$$watchersCount).toBe(1);
|
||||
expect(grandChild2.$$watchersCount).toBe(1);
|
||||
|
||||
grandChild2.$destroy();
|
||||
expect(child2.$$watchersCount).toBe(1);
|
||||
expect($rootScope.$$watchersCount).toBe(3);
|
||||
child1.$destroy();
|
||||
expect($rootScope.$$watchersCount).toBe(1);
|
||||
}));
|
||||
|
||||
it('should decrement the watcherCount when calling the remove function', inject(function($rootScope) {
|
||||
var child1 = $rootScope.$new(),
|
||||
child2 = $rootScope.$new(),
|
||||
grandChild1 = child1.$new(),
|
||||
grandChild2 = child2.$new(),
|
||||
remove1,
|
||||
remove2;
|
||||
|
||||
remove1 = child1.$watch('a', function() {});
|
||||
child2.$watch('a', function() {});
|
||||
grandChild1.$watch('a', function() {});
|
||||
remove2 = grandChild2.$watch('a', function() {});
|
||||
|
||||
remove2();
|
||||
expect(grandChild2.$$watchersCount).toBe(0);
|
||||
expect(child2.$$watchersCount).toBe(1);
|
||||
expect($rootScope.$$watchersCount).toBe(3);
|
||||
remove1();
|
||||
expect(grandChild1.$$watchersCount).toBe(1);
|
||||
expect(child1.$$watchersCount).toBe(1);
|
||||
expect($rootScope.$$watchersCount).toBe(2);
|
||||
|
||||
// Execute everything a second time to be sure that calling the remove funciton
|
||||
// several times, it only decrements the counter once
|
||||
remove2();
|
||||
expect(child2.$$watchersCount).toBe(1);
|
||||
expect($rootScope.$$watchersCount).toBe(2);
|
||||
remove1();
|
||||
expect(child1.$$watchersCount).toBe(1);
|
||||
expect($rootScope.$$watchersCount).toBe(2);
|
||||
}));
|
||||
|
||||
it('should not keep constant literals on the watch queue', inject(function($rootScope) {
|
||||
|
||||
@@ -87,11 +87,9 @@ describe('$sniffer', function() {
|
||||
var ua = $window.navigator.userAgent.toLowerCase();
|
||||
if (/chrome/i.test(ua) || /safari/i.test(ua) || /webkit/i.test(ua)) {
|
||||
expectedPrefix = 'Webkit';
|
||||
}
|
||||
else if (/firefox/i.test(ua)) {
|
||||
} else if (/firefox/i.test(ua)) {
|
||||
expectedPrefix = 'Moz';
|
||||
}
|
||||
else if (/ie/i.test(ua) || /trident/i.test(ua)) {
|
||||
} else if (/ie/i.test(ua) || /trident/i.test(ua)) {
|
||||
expectedPrefix = 'Ms';
|
||||
}
|
||||
expect($sniffer.vendorPrefix).toBe(expectedPrefix);
|
||||
|
||||
@@ -17,7 +17,7 @@ describe('$templateRequest', function() {
|
||||
}));
|
||||
|
||||
it('should cache the request to prevent extra downloads',
|
||||
inject(function($rootScope, $templateRequest, $httpBackend) {
|
||||
inject(function($rootScope, $templateRequest, $templateCache, $httpBackend) {
|
||||
|
||||
$httpBackend.expectGET('tpl.html').respond('matias');
|
||||
|
||||
@@ -34,6 +34,7 @@ describe('$templateRequest', function() {
|
||||
|
||||
expect(content[0]).toBe('matias');
|
||||
expect(content[1]).toBe('matias');
|
||||
expect($templateCache.get('tpl.html')).toBe('matias');
|
||||
}));
|
||||
|
||||
it('should throw an error when the template is not found',
|
||||
|
||||
+24
-5
@@ -488,12 +488,24 @@ describe('$aria', function() {
|
||||
|
||||
it('should a trigger click from the keyboard', function() {
|
||||
scope.someAction = function() {};
|
||||
compileInput('<div ng-click="someAction()" tabindex="0"></div>');
|
||||
|
||||
var elements = $compile('<section>' +
|
||||
'<div class="div-click" ng-click="someAction(\'div\')" tabindex="0"></div>' +
|
||||
'<ul><li ng-click="someAction( \'li\')" tabindex="0"></li></ul>' +
|
||||
'</section>')(scope);
|
||||
|
||||
scope.$digest();
|
||||
|
||||
clickFn = spyOn(scope, 'someAction');
|
||||
|
||||
element.triggerHandler({type: 'keypress', keyCode: 32});
|
||||
var divElement = elements.find('div');
|
||||
var liElement = elements.find('li');
|
||||
|
||||
expect(clickFn).toHaveBeenCalled();
|
||||
divElement.triggerHandler({type: 'keypress', keyCode: 32});
|
||||
liElement.triggerHandler({type: 'keypress', keyCode: 32});
|
||||
|
||||
expect(clickFn).toHaveBeenCalledWith('div');
|
||||
expect(clickFn).toHaveBeenCalledWith('li');
|
||||
});
|
||||
|
||||
it('should not override existing ng-keypress', function() {
|
||||
@@ -526,6 +538,13 @@ describe('$aria', function() {
|
||||
element.triggerHandler({ type: 'keypress', keyCode: 13 });
|
||||
expect(element.text()).toBe('keypress13');
|
||||
});
|
||||
|
||||
it('should not bind keypress to elements not in the default config', function() {
|
||||
compileInput('<button ng-click="event = $event">{{event.type}}{{event.keyCode}}</button>');
|
||||
expect(element.text()).toBe('');
|
||||
element.triggerHandler({ type: 'keypress', keyCode: 13 });
|
||||
expect(element.text()).toBe('');
|
||||
});
|
||||
});
|
||||
|
||||
describe('actions when bindKeypress set to false', function() {
|
||||
@@ -534,11 +553,11 @@ describe('$aria', function() {
|
||||
}));
|
||||
beforeEach(injectScopeAndCompiler);
|
||||
|
||||
it('should not a trigger click from the keyboard', function() {
|
||||
it('should not a trigger click', function() {
|
||||
scope.someAction = function() {};
|
||||
var clickFn = spyOn(scope, 'someAction');
|
||||
|
||||
element = $compile('<div ng-click="someAction()" tabindex="0">></div>')(scope);
|
||||
element = $compile('<div ng-click="someAction()" tabindex="0"></div>')(scope);
|
||||
|
||||
element.triggerHandler({type: 'keypress', keyCode: 32});
|
||||
|
||||
|
||||
Vendored
+44
-4
@@ -787,6 +787,39 @@ describe('ngMock', function() {
|
||||
expect(testFn.$$hashKey).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('$inject cleanup', function() {
|
||||
function testFn() {
|
||||
|
||||
}
|
||||
|
||||
it('should add $inject when invoking test function', inject(function($injector) {
|
||||
$injector.invoke(testFn);
|
||||
expect(testFn.$inject).toBeDefined();
|
||||
}));
|
||||
|
||||
it('should cleanup $inject after previous test', function() {
|
||||
expect(testFn.$inject).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should add $inject when annotating test function', inject(function($injector) {
|
||||
$injector.annotate(testFn);
|
||||
expect(testFn.$inject).toBeDefined();
|
||||
}));
|
||||
|
||||
it('should cleanup $inject after previous test', function() {
|
||||
expect(testFn.$inject).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should invoke an already annotated function', inject(function($injector) {
|
||||
testFn.$inject = [];
|
||||
$injector.invoke(testFn);
|
||||
}));
|
||||
|
||||
it('should not cleanup $inject after previous test', function() {
|
||||
expect(testFn.$inject).toBeDefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('in DSL', function() {
|
||||
@@ -1193,7 +1226,7 @@ describe('ngMock', function() {
|
||||
});
|
||||
|
||||
|
||||
it ('should throw exception when only headers differs from expectation', function() {
|
||||
it('should throw exception when only headers differs from expectation', function() {
|
||||
hb.when('GET').respond(200, '', {});
|
||||
hb.expect('GET', '/match', undefined, {'Content-Type': 'application/json'});
|
||||
|
||||
@@ -1204,7 +1237,7 @@ describe('ngMock', function() {
|
||||
});
|
||||
|
||||
|
||||
it ('should throw exception when only data differs from expectation', function() {
|
||||
it('should throw exception when only data differs from expectation', function() {
|
||||
hb.when('GET').respond(200, '', {});
|
||||
hb.expect('GET', '/match', 'some-data');
|
||||
|
||||
@@ -1215,7 +1248,7 @@ describe('ngMock', function() {
|
||||
});
|
||||
|
||||
|
||||
it ('should not throw an exception when parsed body is equal to expected body object', function() {
|
||||
it('should not throw an exception when parsed body is equal to expected body object', function() {
|
||||
hb.when('GET').respond(200, '', {});
|
||||
|
||||
hb.expect('GET', '/match', {a: 1, b: 2});
|
||||
@@ -1230,7 +1263,7 @@ describe('ngMock', function() {
|
||||
});
|
||||
|
||||
|
||||
it ('should throw exception when only parsed body differs from expected body object', function() {
|
||||
it('should throw exception when only parsed body differs from expected body object', function() {
|
||||
hb.when('GET').respond(200, '', {});
|
||||
hb.expect('GET', '/match', {a: 1, b: 2});
|
||||
|
||||
@@ -1780,3 +1813,10 @@ describe('ngMockE2E', function() {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('make sure that we can create an injector outside of tests', function() {
|
||||
//since some libraries create custom injectors outside of tests,
|
||||
//we want to make sure that this is not breaking the internals of
|
||||
//how we manage annotated function cleanup during tests. See #10967
|
||||
angular.injector([function($injector) {}]);
|
||||
});
|
||||
|
||||
@@ -1341,6 +1341,30 @@ describe('$route', function() {
|
||||
});
|
||||
});
|
||||
|
||||
it('should not update query params when an optional property was previously not in path', function() {
|
||||
var routeChangeSpy = jasmine.createSpy('route change');
|
||||
|
||||
module(function($routeProvider) {
|
||||
$routeProvider.when('/bar/:barId/:fooId/:spamId/:eggId?', {controller: angular.noop});
|
||||
});
|
||||
|
||||
inject(function($route, $routeParams, $location, $rootScope) {
|
||||
$rootScope.$on('$routeChangeSuccess', routeChangeSpy);
|
||||
|
||||
$location.path('/bar/1/2/3');
|
||||
$location.search({initial: 'true'});
|
||||
$rootScope.$digest();
|
||||
routeChangeSpy.reset();
|
||||
|
||||
$route.updateParams({barId: '5', fooId: '6', eggId: '4'});
|
||||
$rootScope.$digest();
|
||||
|
||||
expect($routeParams).toEqual({barId: '5', fooId: '6', spamId: '3', eggId: '4', initial: 'true'});
|
||||
expect(routeChangeSpy).toHaveBeenCalledOnce();
|
||||
expect($location.path()).toEqual('/bar/5/6/3/4');
|
||||
expect($location.search()).toEqual({initial: 'true'});
|
||||
});
|
||||
});
|
||||
|
||||
it('should complain if called without an existing route', inject(function($route) {
|
||||
expect($route.updateParams).toThrowMinErr('ngRoute', 'norout');
|
||||
|
||||
@@ -140,6 +140,10 @@ describe('HTML', function() {
|
||||
expectHTML('a<SCRIPT>evil< / scrIpt >c.').toEqual('ac.');
|
||||
});
|
||||
|
||||
it('should remove script that has newline characters', function() {
|
||||
expectHTML('a<SCRIPT\n>\n\revil\n\r< / scrIpt\n >c.').toEqual('ac.');
|
||||
});
|
||||
|
||||
it('should remove DOCTYPE header', function() {
|
||||
expectHTML('<!DOCTYPE html>').toEqual('');
|
||||
expectHTML('<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"\n"http://www.w3.org/TR/html4/strict.dtd">').toEqual('');
|
||||
@@ -160,6 +164,10 @@ describe('HTML', function() {
|
||||
expectHTML('a<STyle>evil</stYle>c.').toEqual('ac.');
|
||||
});
|
||||
|
||||
it('should remove style that has newline characters', function() {
|
||||
expectHTML('a<STyle \n>\n\revil\n\r</stYle\n>c.').toEqual('ac.');
|
||||
});
|
||||
|
||||
it('should remove script and style', function() {
|
||||
expectHTML('a<STyle>evil<script></script></stYle>c.').toEqual('ac.');
|
||||
});
|
||||
|
||||
@@ -118,6 +118,75 @@ describe('angular.scenario.Application', function() {
|
||||
expect(called).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should set rootElement when navigateTo instigates bootstrap', inject(function($injector, $browser) {
|
||||
var called;
|
||||
var testWindow = {
|
||||
document: jqLite('<div class="test-foo"></div>')[0],
|
||||
angular: {
|
||||
element: jqLite,
|
||||
service: {},
|
||||
resumeBootstrap: noop
|
||||
}
|
||||
};
|
||||
jqLite(testWindow.document).data('$injector', $injector);
|
||||
var resumeBootstrapSpy = spyOn(testWindow.angular, 'resumeBootstrap').andReturn($injector);
|
||||
|
||||
var injectorGet = $injector.get;
|
||||
spyOn($injector, 'get').andCallFake(function(name) {
|
||||
switch (name) {
|
||||
case "$rootElement": return jqLite(testWindow.document);
|
||||
default: return injectorGet(name);
|
||||
}
|
||||
});
|
||||
|
||||
app.getWindow_ = function() {
|
||||
return testWindow;
|
||||
};
|
||||
app.navigateTo('http://localhost/', noop);
|
||||
callLoadHandlers(app);
|
||||
expect(app.rootElement).toBe(testWindow.document);
|
||||
expect(resumeBootstrapSpy).toHaveBeenCalled();
|
||||
dealoc(testWindow.document);
|
||||
}));
|
||||
|
||||
it('should set setup resumeDeferredBootstrap if resumeBootstrap is not yet defined', inject(function($injector, $browser) {
|
||||
var called;
|
||||
var testWindow = {
|
||||
document: jqLite('<div class="test-foo"></div>')[0],
|
||||
angular: {
|
||||
element: jqLite,
|
||||
service: {},
|
||||
resumeBootstrap: null
|
||||
}
|
||||
};
|
||||
jqLite(testWindow.document).data('$injector', $injector);
|
||||
|
||||
var injectorGet = $injector.get;
|
||||
var injectorSpy = spyOn($injector, 'get').andCallFake(function(name) {
|
||||
switch (name) {
|
||||
case "$rootElement": return jqLite(testWindow.document);
|
||||
default: return injectorGet(name);
|
||||
}
|
||||
});
|
||||
|
||||
app.getWindow_ = function() {
|
||||
return testWindow;
|
||||
};
|
||||
app.navigateTo('http://localhost/', noop);
|
||||
expect(testWindow.angular.resumeDeferredBootstrap).toBeUndefined();
|
||||
callLoadHandlers(app);
|
||||
expect(testWindow.angular.resumeDeferredBootstrap).toBeDefined();
|
||||
expect(app.rootElement).toBeUndefined;
|
||||
expect(injectorSpy).not.toHaveBeenCalled();
|
||||
|
||||
var resumeBootstrapSpy = spyOn(testWindow.angular, 'resumeBootstrap').andReturn($injector);
|
||||
testWindow.angular.resumeDeferredBootstrap();
|
||||
expect(app.rootElement).toBe(testWindow.document);
|
||||
expect(resumeBootstrapSpy).toHaveBeenCalled();
|
||||
expect(injectorSpy).toHaveBeenCalledWith("$rootElement");
|
||||
dealoc(testWindow.document);
|
||||
}));
|
||||
|
||||
it('should wait for pending requests in executeAction', inject(function($injector, $browser) {
|
||||
var called, polled;
|
||||
var handlers = [];
|
||||
@@ -144,4 +213,32 @@ describe('angular.scenario.Application', function() {
|
||||
handlers[0]();
|
||||
dealoc(testWindow.document);
|
||||
}));
|
||||
|
||||
it('should allow explicit rootElement', inject(function($injector, $browser) {
|
||||
var called, polled;
|
||||
var handlers = [];
|
||||
var testWindow = {
|
||||
document: jqLite('<div class="test-foo"></div>')[0],
|
||||
angular: {
|
||||
element: jqLite,
|
||||
service: {}
|
||||
}
|
||||
};
|
||||
$browser.notifyWhenNoOutstandingRequests = function(fn) {
|
||||
handlers.push(fn);
|
||||
};
|
||||
app.rootElement = testWindow.document;
|
||||
jqLite(testWindow.document).data('$injector', $injector);
|
||||
app.getWindow_ = function() {
|
||||
return testWindow;
|
||||
};
|
||||
app.executeAction(function($window, $document) {
|
||||
expect($window).toEqual(testWindow);
|
||||
expect($document).toBeDefined();
|
||||
expect($document[0].className).toEqual('test-foo');
|
||||
});
|
||||
expect(handlers.length).toEqual(1);
|
||||
handlers[0]();
|
||||
dealoc(testWindow.document);
|
||||
}));
|
||||
});
|
||||
|
||||
@@ -43,8 +43,9 @@ describe('angular.scenario.SpecRunner', function() {
|
||||
runner = $root.$new();
|
||||
|
||||
var Cls = angular.scenario.SpecRunner;
|
||||
for (var name in Cls.prototype)
|
||||
for (var name in Cls.prototype) {
|
||||
runner[name] = angular.bind(runner, Cls.prototype[name]);
|
||||
}
|
||||
|
||||
Cls.call(runner);
|
||||
}));
|
||||
|
||||
@@ -624,7 +624,7 @@ describe("angular.scenario.dsl", function() {
|
||||
});
|
||||
|
||||
it('should match bindings by substring match', function() {
|
||||
compile('<pre ng-bind="foo.bar | filter"></pre>', 'binding value');
|
||||
compile('<pre ng-bind="foo.bar | lowercase"></pre>', 'binding value');
|
||||
$root.dsl.binding('foo . bar');
|
||||
expect($root.futureResult).toEqual('binding value');
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user