Compare commits
75 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 59205d7809 | |||
| 0cf170df16 | |||
| 05a3b088fd | |||
| 65df5da07a | |||
| 0689c3697f | |||
| 0f53c29954 | |||
| 11bfe85598 | |||
| 93c503fa16 | |||
| 9d4e948e82 | |||
| 26f19d0399 | |||
| 5cd2e2291b | |||
| 69bbbe675e | |||
| 825de1cdf2 | |||
| e5318c61ee | |||
| 67b40a19fb | |||
| 5fbac749c9 | |||
| 0daadeb3d3 | |||
| 6b7625a095 | |||
| ab7e0cd100 | |||
| dee5f7fea5 | |||
| 140d149cee | |||
| 4d65ddddf8 | |||
| abfce5327c | |||
| 944c150e6c | |||
| d8dc53d215 | |||
| 0ec206f5a6 | |||
| ce49d4d61b | |||
| 69ee593fd2 | |||
| 39ddef6829 | |||
| 11aedbd741 | |||
| e4d1e12f7f | |||
| 9c2b32d6f3 | |||
| 4b3a590b00 | |||
| 7f50e97628 | |||
| e5ee6123fc | |||
| 923b6aba0d | |||
| 955e20eb61 | |||
| 286a40751c | |||
| eca0535457 | |||
| 7ace77a5d7 | |||
| 7f362af153 | |||
| 35dee2abac | |||
| 29c926201d | |||
| 9b6852a8c9 | |||
| 53efc8d5d0 | |||
| 0b8461c9cb | |||
| abd8e2a9eb | |||
| bc4dadc894 | |||
| ec53089bb1 | |||
| 7bb50e2823 | |||
| 632b2ddd34 | |||
| 7caad2205a | |||
| 9bf5f89659 | |||
| f41ca4a53e | |||
| 0bcd0872d8 | |||
| 6ec5946094 | |||
| 784ea8e160 | |||
| 6ec53bdfd3 | |||
| d1b6480dcf | |||
| ef6fed3ef8 | |||
| 473dee5786 | |||
| 779e3f6b5f | |||
| 71bca00651 | |||
| 9a9fce0abc | |||
| 939ca37cfe | |||
| 4ae8a2a4b6 | |||
| 113d3954b9 | |||
| 7cb5983750 | |||
| 2b149ca6d4 | |||
| e77866c18c | |||
| 0dc6418d20 | |||
| 837a077578 | |||
| adf91fe6ee | |||
| dea1c0d34c | |||
| f533acc9aa |
+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
|
||||
|
||||
+14
-2
@@ -2,6 +2,12 @@ language: node_js
|
||||
node_js:
|
||||
- '0.10'
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- node_modules
|
||||
- bower_components
|
||||
- docs/bower_components
|
||||
|
||||
branches:
|
||||
except:
|
||||
- /^g3_.*$/
|
||||
@@ -27,15 +33,21 @@ env:
|
||||
matrix:
|
||||
allow_failures:
|
||||
- env: "JOB=unit BROWSER_PROVIDER=browserstack"
|
||||
- env: "JOB=docs-e2e BROWSER_PROVIDER=browserstack"
|
||||
- env: "JOB=e2e TEST_TARGET=jqlite BROWSER_PROVIDER=browserstack"
|
||||
- env: "JOB=e2e TEST_TARGET=jquery BROWSER_PROVIDER=browserstack"
|
||||
|
||||
install:
|
||||
# Check the size of caches
|
||||
- du -sh ./node_modules ./bower_components/ ./docs/bower_components/ || true
|
||||
# - npm config set registry http://23.251.144.68
|
||||
# Disable the spinner, it looks bad on Travis
|
||||
- npm config set spin false
|
||||
# Log HTTP requests
|
||||
- npm config set loglevel http
|
||||
- time ./scripts/travis/npm-bundle-deps.sh
|
||||
- time npm install
|
||||
- npm install -g npm@2.5
|
||||
# Instal npm dependecies and ensure that npm cache is not stale
|
||||
- scripts/npm/install-dependencies.sh
|
||||
|
||||
before_script:
|
||||
- mkdir -p $LOGS_DIR
|
||||
|
||||
+283
@@ -1,3 +1,286 @@
|
||||
<a name="1.4.0-beta.4"></a>
|
||||
# 1.4.0-beta.4 overlyexplosive-poprocks (2015-02-09)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$location:** prevent page reload if initial url has empty hash at the end
|
||||
([a509e9aa](https://github.com/angular/angular.js/commit/a509e9aa149d0f88cc39f703d539f7ffd4cd6103),
|
||||
[#10397](https://github.com/angular/angular.js/issues/10397), [#10960](https://github.com/angular/angular.js/issues/10960))
|
||||
- **$parse:** Initialize elements in an array from left to right
|
||||
([966f6d83](https://github.com/angular/angular.js/commit/966f6d831f9469a917601f9a10604612cd7bd792))
|
||||
- **ngAria:** ensure native controls fire a single click
|
||||
([9d53e5a3](https://github.com/angular/angular.js/commit/9d53e5a38dd369dec82d82e13e078df3d6054c8a),
|
||||
[#10388](https://github.com/angular/angular.js/issues/10388), [#10766](https://github.com/angular/angular.js/issues/10766))
|
||||
- **ngMock:** handle cases where injector is created before tests
|
||||
([898714df](https://github.com/angular/angular.js/commit/898714df9ea38f9ef700015ced5ddea52f096b77),
|
||||
[#10967](https://github.com/angular/angular.js/issues/10967))
|
||||
- **sanitize:** handle newline characters inside special tags
|
||||
([cc8755cd](https://github.com/angular/angular.js/commit/cc8755cda6efda0b52954388e8a8d5306e4bfbca),
|
||||
[030a42e7](https://github.com/angular/angular.js/commit/030a42e79dec8a4bb73053762f7a54d797a058f6)
|
||||
[#10943](https://github.com/angular/angular.js/issues/10943))
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
- **ng-jq:** adds the ability to force jqLite or a specific jQuery version
|
||||
([09ee82d8](https://github.com/angular/angular.js/commit/09ee82d84dcbea4a6e8d85903af82dcd087a78a7))
|
||||
|
||||
|
||||
|
||||
<a name="1.3.13"></a>
|
||||
# 1.3.13 meticulous-riffleshuffle (2015-02-09)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$location:** prevent page reload if initial url has empty hash at the end
|
||||
([4b3a590b](https://github.com/angular/angular.js/commit/4b3a590b009d7fdceda7f52e7ba0352a271b3256),
|
||||
[#10397](https://github.com/angular/angular.js/issues/10397), [#10960](https://github.com/angular/angular.js/issues/10960))
|
||||
- **ngAria:** ensure native controls fire a single click
|
||||
([69ee593f](https://github.com/angular/angular.js/commit/69ee593fd2cb5f1d7757efbe6b256e4458752fd7),
|
||||
[#10388](https://github.com/angular/angular.js/issues/10388), [#10766](https://github.com/angular/angular.js/issues/10766))
|
||||
- **ngMock:** handle cases where injector is created before tests
|
||||
([39ddef68](https://github.com/angular/angular.js/commit/39ddef682971d3b7282bf9d08f6eaf97b7f4bca4),
|
||||
[#10967](https://github.com/angular/angular.js/issues/10967))
|
||||
- **sanitize:** handle newline characters inside special tags
|
||||
([11aedbd7](https://github.com/angular/angular.js/commit/11aedbd741ccddba060a9805adba1779391731da),
|
||||
[ce49d4d6](https://github.com/angular/angular.js/commit/ce49d4d61bd02464b6c6376af8048f6eb09330a8)
|
||||
[#10943](https://github.com/angular/angular.js/issues/10943))
|
||||
|
||||
|
||||
|
||||
<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)
|
||||
|
||||
|
||||
+10
-6
@@ -17,10 +17,6 @@ module.exports = function(grunt) {
|
||||
NG_VERSION.cdn = versionInfo.cdnVersion;
|
||||
var dist = 'angular-'+ NG_VERSION.full;
|
||||
|
||||
//global beforeEach
|
||||
util.init();
|
||||
|
||||
|
||||
//config
|
||||
grunt.initConfig({
|
||||
NG_VERSION: NG_VERSION,
|
||||
@@ -285,6 +281,10 @@ module.exports = function(grunt) {
|
||||
},
|
||||
|
||||
shell: {
|
||||
"npm-install": {
|
||||
command: path.normalize('scripts/npm/install-dependencies.sh')
|
||||
},
|
||||
|
||||
"promises-aplus-tests": {
|
||||
options: {
|
||||
stdout: false,
|
||||
@@ -311,14 +311,18 @@ module.exports = function(grunt) {
|
||||
}
|
||||
});
|
||||
|
||||
// global beforeEach task
|
||||
if (!process.env.TRAVIS) {
|
||||
grunt.task.run('shell:npm-install');
|
||||
}
|
||||
|
||||
//alias tasks
|
||||
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']);
|
||||
|
||||
@@ -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,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.
|
||||
@@ -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()`.
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ illustration we typically build snappy apps with hundreds or thousands of active
|
||||
|
||||
### How big is the angular.js file that I need to include?
|
||||
|
||||
The size of the file is < 36KB compressed and minified.
|
||||
The size of the file is ~50KB compressed and minified.
|
||||
|
||||
|
||||
### Can I use the open-source Closure Library with Angular?
|
||||
|
||||
@@ -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'
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -14,13 +14,6 @@ var CSP_CSS_HEADER = '/* Include this file in your html if you are using the CSP
|
||||
|
||||
module.exports = {
|
||||
|
||||
init: function() {
|
||||
if (!process.env.TRAVIS) {
|
||||
shell.exec('npm install');
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
startKarma: function(config, singleRun, done){
|
||||
var browsers = grunt.option('browsers');
|
||||
var reporters = grunt.option('reporters');
|
||||
|
||||
@@ -12,9 +12,9 @@ set -e
|
||||
# before_script:
|
||||
# - curl https://gist.github.com/santiycr/5139565/raw/sauce_connect_setup.sh | bash
|
||||
|
||||
CONNECT_URL="https://saucelabs.com/downloads/sc-4.3-linux.tar.gz"
|
||||
CONNECT_URL="https://saucelabs.com/downloads/sc-4.3.6-linux.tar.gz"
|
||||
CONNECT_DIR="/tmp/sauce-connect-$RANDOM"
|
||||
CONNECT_DOWNLOAD="sc-4.3-linux.tar.gz"
|
||||
CONNECT_DOWNLOAD="sc-4.3.6-linux.tar.gz"
|
||||
|
||||
CONNECT_LOG="$LOGS_DIR/sauce-connect"
|
||||
CONNECT_STDOUT="$LOGS_DIR/sauce-connect.stdout"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Generated
+6092
-1490
File diff suppressed because it is too large
Load Diff
+7
-2
@@ -5,6 +5,11 @@
|
||||
"type": "git",
|
||||
"url": "https://github.com/angular/angular.js.git"
|
||||
},
|
||||
"engines": {
|
||||
"node": "~0.10",
|
||||
"npm": "~2.5"
|
||||
},
|
||||
"engineStrict": true,
|
||||
"devDependencies": {
|
||||
"angular-benchpress": "0.x.x",
|
||||
"benchmark": "1.x.x",
|
||||
@@ -24,7 +29,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",
|
||||
@@ -38,7 +43,7 @@
|
||||
"jasmine-node": "~1.14.5",
|
||||
"jasmine-reporters": "~1.0.1",
|
||||
"jshint-stylish": "~1.0.0",
|
||||
"karma": "vojtajina/karma#socketio_10",
|
||||
"karma": "~0.12.0",
|
||||
"karma-browserstack-launcher": "0.1.2",
|
||||
"karma-chrome-launcher": "0.1.5",
|
||||
"karma-firefox-launcher": "0.1.3",
|
||||
|
||||
@@ -63,6 +63,21 @@ function prepare {
|
||||
cp $BUILD_DIR/angular-csp.css $TMP_DIR/bower-angular
|
||||
|
||||
|
||||
#
|
||||
# Run local precommit script if there is one
|
||||
#
|
||||
for repo in "${REPOS[@]}"
|
||||
do
|
||||
if [ -f $TMP_DIR/bower-$repo/precommit.sh ]
|
||||
then
|
||||
echo "-- Running precommit.sh script for bower-$repo"
|
||||
cd $TMP_DIR/bower-$repo
|
||||
$TMP_DIR/bower-$repo/precommit.sh
|
||||
cd $SCRIPT_DIR
|
||||
fi
|
||||
done
|
||||
|
||||
|
||||
#
|
||||
# update bower.json
|
||||
# tag each repo
|
||||
|
||||
@@ -10,22 +10,17 @@
|
||||
var _ = require('lodash');
|
||||
var sorted = require('sorted-object');
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
|
||||
|
||||
function cleanModule(module, name) {
|
||||
|
||||
// keep `from` and `resolve` properties for git dependencies, delete otherwise
|
||||
if (!(module.resolved && module.resolved.match(/^git:\/\//))) {
|
||||
delete module.from;
|
||||
// keep `resolve` properties for git dependencies, delete otherwise
|
||||
delete module.from;
|
||||
if (!(module.resolved && module.resolved.match(/^git(\+[a-z]+)?:\/\//))) {
|
||||
delete module.resolved;
|
||||
}
|
||||
|
||||
if (name === 'chokidar') {
|
||||
if (module.version === '0.8.1') {
|
||||
delete module.dependencies;
|
||||
}
|
||||
}
|
||||
|
||||
_.forEach(module.dependencies, function(mod, name) {
|
||||
cleanModule(mod, name);
|
||||
});
|
||||
@@ -33,10 +28,11 @@ function cleanModule(module, name) {
|
||||
|
||||
|
||||
console.log('Reading npm-shrinkwrap.json');
|
||||
var shrinkwrap = require('./../npm-shrinkwrap.json');
|
||||
var shrinkwrap = require('../../npm-shrinkwrap.json');
|
||||
|
||||
console.log('Cleaning shrinkwrap object');
|
||||
cleanModule(shrinkwrap, shrinkwrap.name);
|
||||
|
||||
console.log('Writing cleaned npm-shrinkwrap.json');
|
||||
fs.writeFileSync('./npm-shrinkwrap.json', JSON.stringify(sorted(shrinkwrap), null, 2) + "\n");
|
||||
var cleanShrinkwrapPath = path.join(__dirname, '..', '..', 'npm-shrinkwrap.clean.json');
|
||||
console.log('Writing cleaned to', cleanShrinkwrapPath);
|
||||
fs.writeFileSync(cleanShrinkwrapPath, JSON.stringify(sorted(shrinkwrap), null, 2) + "\n");
|
||||
Executable
+16
@@ -0,0 +1,16 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
SHRINKWRAP_FILE=npm-shrinkwrap.json
|
||||
SHRINKWRAP_CACHED_FILE=node_modules/npm-shrinkwrap.cached.json
|
||||
|
||||
if diff -q $SHRINKWRAP_FILE $SHRINKWRAP_CACHED_FILE; then
|
||||
echo 'No shrinkwrap changes detected. npm install will be skipped...';
|
||||
else
|
||||
echo 'Blowing away node_modules and reinstalling npm dependencies...'
|
||||
rm -rf node_modules
|
||||
npm install
|
||||
cp $SHRINKWRAP_FILE $SHRINKWRAP_CACHED_FILE
|
||||
echo 'npm install successful!'
|
||||
fi
|
||||
+7
-4
@@ -317,8 +317,7 @@ function nextUid() {
|
||||
function setHashKey(obj, h) {
|
||||
if (h) {
|
||||
obj.$$hashKey = h;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
delete obj.$$hashKey;
|
||||
}
|
||||
}
|
||||
@@ -627,7 +626,7 @@ function isElement(node) {
|
||||
function makeMap(str) {
|
||||
var obj = {}, items = str.split(","), i;
|
||||
for (i = 0; i < items.length; i++)
|
||||
obj[ items[i] ] = true;
|
||||
obj[items[i]] = true;
|
||||
return obj;
|
||||
}
|
||||
|
||||
@@ -1408,8 +1407,12 @@ function bootstrap(element, modules, config) {
|
||||
forEach(extraModules, function(module) {
|
||||
modules.push(module);
|
||||
});
|
||||
doBootstrap();
|
||||
return doBootstrap();
|
||||
};
|
||||
|
||||
if (isFunction(angular.resumeDeferredBootstrap)) {
|
||||
angular.resumeDeferredBootstrap();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
+1
-2
@@ -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))
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
var $controllerMinErr = minErr('$controller');
|
||||
|
||||
/**
|
||||
* @ngdoc provider
|
||||
* @name $controllerProvider
|
||||
@@ -87,7 +89,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)
|
||||
|
||||
@@ -18,6 +18,9 @@ var htmlAnchorDirective = valueFn({
|
||||
compile: function(element, attr) {
|
||||
if (!attr.href && !attr.xlinkHref && !attr.name) {
|
||||
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';
|
||||
|
||||
@@ -159,20 +159,23 @@
|
||||
*
|
||||
* @description
|
||||
*
|
||||
* We shouldn't do this, because it will make the button enabled on Chrome/Firefox but not on IE8 and older IEs:
|
||||
* This directive sets the `disabled` attribute on the element if the
|
||||
* {@link guide/expression expression} inside `ngDisabled` evaluates to truthy.
|
||||
*
|
||||
* A special directive is necessary because we cannot use interpolation inside the `disabled`
|
||||
* attribute. The following example would make the button enabled on Chrome/Firefox
|
||||
* but not on older IEs:
|
||||
*
|
||||
* ```html
|
||||
* <div ng-init="scope = { isDisabled: false }">
|
||||
* <button disabled="{{scope.isDisabled}}">Disabled</button>
|
||||
* <div ng-init="isDisabled = false">
|
||||
* <button disabled="{{isDisabled}}">Disabled</button>
|
||||
* </div>
|
||||
* ```
|
||||
*
|
||||
* The HTML specification does not require browsers to preserve the values of boolean attributes
|
||||
* such as disabled. (Their presence means true and their absence means false.)
|
||||
* This is because the HTML specification does not require browsers to preserve the values of
|
||||
* boolean attributes such as `disabled` (Their presence means true and their absence means false.)
|
||||
* If we put an Angular interpolation expression into such an attribute then the
|
||||
* binding information would be lost when the browser removes the attribute.
|
||||
* The `ngDisabled` directive solves this problem for the `disabled` attribute.
|
||||
* This complementary directive is not removed by the browser and so provides
|
||||
* a permanent reliable place to store the binding information.
|
||||
*
|
||||
* @example
|
||||
<example>
|
||||
@@ -191,7 +194,7 @@
|
||||
*
|
||||
* @element INPUT
|
||||
* @param {expression} ngDisabled If the {@link guide/expression expression} is truthy,
|
||||
* then special attribute "disabled" will be set on the element
|
||||
* then the `disabled` attribute will be set on the element
|
||||
*/
|
||||
|
||||
|
||||
|
||||
+89
-67
@@ -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 int 2013:
|
||||
<input id="exampleInput" type="month" name="input" ng-model="value"
|
||||
Pick a month in 2013:
|
||||
<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');
|
||||
@@ -1228,7 +1250,7 @@ function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
|
||||
return value;
|
||||
});
|
||||
|
||||
if (attr.min || attr.ngMin) {
|
||||
if (isDefined(attr.min) || attr.ngMin) {
|
||||
var minVal;
|
||||
ctrl.$validators.min = function(value) {
|
||||
return ctrl.$isEmpty(value) || isUndefined(minVal) || value >= minVal;
|
||||
@@ -1244,7 +1266,7 @@ function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
|
||||
});
|
||||
}
|
||||
|
||||
if (attr.max || attr.ngMax) {
|
||||
if (isDefined(attr.max) || attr.ngMax) {
|
||||
var maxVal;
|
||||
ctrl.$validators.max = function(value) {
|
||||
return ctrl.$isEmpty(value) || isUndefined(maxVal) || value <= maxVal;
|
||||
|
||||
@@ -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>
|
||||
*
|
||||
|
||||
+14
-15
@@ -244,6 +244,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
|
||||
ngModelGet = parsedNgModel,
|
||||
ngModelSet = parsedNgModelAssign,
|
||||
pendingDebounce = null,
|
||||
parserValid,
|
||||
ctrl = this;
|
||||
|
||||
this.$$setOptions = function(options) {
|
||||
@@ -516,16 +517,12 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
|
||||
// the model although neither viewValue nor the model on the scope changed
|
||||
var modelValue = ctrl.$$rawModelValue;
|
||||
|
||||
// Check if the there's a parse error, so we don't unset it accidentially
|
||||
var parserName = ctrl.$$parserName || 'parse';
|
||||
var parserValid = ctrl.$error[parserName] ? false : undefined;
|
||||
|
||||
var prevValid = ctrl.$valid;
|
||||
var prevModelValue = ctrl.$modelValue;
|
||||
|
||||
var allowInvalid = ctrl.$options && ctrl.$options.allowInvalid;
|
||||
|
||||
ctrl.$$runValidators(parserValid, modelValue, viewValue, function(allValid) {
|
||||
ctrl.$$runValidators(modelValue, viewValue, function(allValid) {
|
||||
// If there was no change in validity, don't update the model
|
||||
// This prevents changing an invalid modelValue to undefined
|
||||
if (!allowInvalid && prevValid !== allValid) {
|
||||
@@ -543,12 +540,12 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
|
||||
|
||||
};
|
||||
|
||||
this.$$runValidators = function(parseValid, modelValue, viewValue, doneCallback) {
|
||||
this.$$runValidators = function(modelValue, viewValue, doneCallback) {
|
||||
currentValidationRunId++;
|
||||
var localValidationRunId = currentValidationRunId;
|
||||
|
||||
// check parser error
|
||||
if (!processParseErrors(parseValid)) {
|
||||
if (!processParseErrors()) {
|
||||
validationDone(false);
|
||||
return;
|
||||
}
|
||||
@@ -558,21 +555,22 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
|
||||
}
|
||||
processAsyncValidators();
|
||||
|
||||
function processParseErrors(parseValid) {
|
||||
function processParseErrors() {
|
||||
var errorKey = ctrl.$$parserName || 'parse';
|
||||
if (parseValid === undefined) {
|
||||
if (parserValid === undefined) {
|
||||
setValidity(errorKey, null);
|
||||
} else {
|
||||
setValidity(errorKey, parseValid);
|
||||
if (!parseValid) {
|
||||
if (!parserValid) {
|
||||
forEach(ctrl.$validators, function(v, name) {
|
||||
setValidity(name, null);
|
||||
});
|
||||
forEach(ctrl.$asyncValidators, function(v, name) {
|
||||
setValidity(name, null);
|
||||
});
|
||||
return false;
|
||||
}
|
||||
// Set the parse error last, to prevent unsetting it, should a $validators key == parserName
|
||||
setValidity(errorKey, parserValid);
|
||||
return parserValid;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -667,7 +665,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
|
||||
this.$$parseAndValidate = function() {
|
||||
var viewValue = ctrl.$$lastCommittedViewValue;
|
||||
var modelValue = viewValue;
|
||||
var parserValid = isUndefined(modelValue) ? undefined : true;
|
||||
parserValid = isUndefined(modelValue) ? undefined : true;
|
||||
|
||||
if (parserValid) {
|
||||
for (var i = 0; i < ctrl.$parsers.length; i++) {
|
||||
@@ -693,7 +691,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
|
||||
|
||||
// Pass the $$lastCommittedViewValue here, because the cached viewValue might be out of date.
|
||||
// This can happen if e.g. $setViewValue is called from inside a parser
|
||||
ctrl.$$runValidators(parserValid, modelValue, ctrl.$$lastCommittedViewValue, function(allValid) {
|
||||
ctrl.$$runValidators(modelValue, ctrl.$$lastCommittedViewValue, function(allValid) {
|
||||
if (!allowInvalid) {
|
||||
// Note: Don't check ctrl.$valid here, as we could have
|
||||
// external validators (e.g. calculated on the server),
|
||||
@@ -814,6 +812,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
|
||||
// TODO(perf): why not move this to the action fn?
|
||||
if (modelValue !== ctrl.$modelValue) {
|
||||
ctrl.$modelValue = ctrl.$$rawModelValue = modelValue;
|
||||
parserValid = undefined;
|
||||
|
||||
var formatters = ctrl.$formatters,
|
||||
idx = formatters.length;
|
||||
@@ -826,7 +825,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
|
||||
ctrl.$viewValue = ctrl.$$lastCommittedViewValue = viewValue;
|
||||
ctrl.$render();
|
||||
|
||||
ctrl.$$runValidators(undefined, modelValue, viewValue, noop);
|
||||
ctrl.$$runValidators(modelValue, viewValue, noop);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -46,6 +46,55 @@
|
||||
* when keys are deleted and reinstated.
|
||||
*
|
||||
*
|
||||
* # Tracking and Duplicates
|
||||
*
|
||||
* When the contents of the collection change, `ngRepeat` makes the corresponding changes to the DOM:
|
||||
*
|
||||
* * When an item is added, a new instance of the template is added to the DOM.
|
||||
* * When an item is removed, its template instance is removed from the DOM.
|
||||
* * When items are reordered, their respective templates are reordered in the DOM.
|
||||
*
|
||||
* By default, `ngRepeat` does not allow duplicate items in arrays. This is because when
|
||||
* there are duplicates, it is not possible to maintain a one-to-one mapping between collection
|
||||
* items and DOM elements.
|
||||
*
|
||||
* If you do need to repeat duplicate items, you can substitute the default tracking behavior
|
||||
* with your own using the `track by` expression.
|
||||
*
|
||||
* For example, you may track items by the index of each item in the collection, using the
|
||||
* special scope property `$index`:
|
||||
* ```html
|
||||
* <div ng-repeat="n in [42, 42, 43, 43] track by $index">
|
||||
* {{n}}
|
||||
* </div>
|
||||
* ```
|
||||
*
|
||||
* You may use arbitrary expressions in `track by`, including references to custom functions
|
||||
* on the scope:
|
||||
* ```html
|
||||
* <div ng-repeat="n in [42, 42, 43, 43] track by myTrackingFunction(n)">
|
||||
* {{n}}
|
||||
* </div>
|
||||
* ```
|
||||
*
|
||||
* If you are working with objects that have an identifier property, you can track
|
||||
* by the identifier instead of the whole object. Should you reload your data later, `ngRepeat`
|
||||
* will not have to rebuild the DOM elements for items it has already rendered, even if the
|
||||
* JavaScript objects in the collection have been substituted for new ones:
|
||||
* ```html
|
||||
* <div ng-repeat="model in collection track by model.id">
|
||||
* {{model.name}}
|
||||
* </div>
|
||||
* ```
|
||||
*
|
||||
* When no `track by` expression is provided, it is equivalent to tracking by the built-in
|
||||
* `$id` function, which tracks items by their identity:
|
||||
* ```html
|
||||
* <div ng-repeat="obj in collection track by $id(obj)">
|
||||
* {{obj.prop}}
|
||||
* </div>
|
||||
* ```
|
||||
*
|
||||
* # Special repeat start and end points
|
||||
* To repeat a series of elements instead of just one parent element, ngRepeat (as well as other ng directives) supports extending
|
||||
* the range of the repeater by defining explicit start and end points by using **ng-repeat-start** and **ng-repeat-end** respectively.
|
||||
@@ -113,12 +162,12 @@
|
||||
*
|
||||
* For example: `(name, age) in {'adam':10, 'amalie':12}`.
|
||||
*
|
||||
* * `variable in expression track by tracking_expression` – You can also provide an optional tracking function
|
||||
* which can be used to associate the objects in the collection with the DOM elements. If no tracking function
|
||||
* is specified the ng-repeat associates elements by identity in the collection. It is an error to have
|
||||
* more than one tracking function to resolve to the same key. (This would mean that two distinct objects are
|
||||
* mapped to the same DOM element, which is not possible.) Filters should be applied to the expression,
|
||||
* before specifying a tracking expression.
|
||||
* * `variable in expression track by tracking_expression` – You can also provide an optional tracking expression
|
||||
* which can be used to associate the objects in the collection with the DOM elements. If no tracking expression
|
||||
* is specified, ng-repeat associates elements by identity. It is an error to have
|
||||
* more than one tracking expression value resolve to the same key. (This would mean that two distinct objects are
|
||||
* mapped to the same DOM element, which is not possible.) If filters are used in the expression, they should be
|
||||
* applied before the tracking expression.
|
||||
*
|
||||
* For example: `item in items` is equivalent to `item in items track by $id(item)`. This implies that the DOM elements
|
||||
* will be associated by item identity in the array.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
+2
-2
@@ -837,7 +837,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) return;
|
||||
if (!html5Mode.rewriteLinks || event.ctrlKey || event.metaKey || event.shiftKey || event.which == 2 || event.button == 2) return;
|
||||
|
||||
var elm = jqLite(event.target);
|
||||
|
||||
@@ -879,7 +879,7 @@ function $LocationProvider() {
|
||||
|
||||
|
||||
// rewrite hashbang url <> html5 url
|
||||
if ($location.absUrl() != initialUrl) {
|
||||
if (trimEmptyHash($location.absUrl()) != trimEmptyHash(initialUrl)) {
|
||||
$browser.url($location.absUrl(), true);
|
||||
}
|
||||
|
||||
|
||||
@@ -728,6 +728,11 @@ Parser.prototype = {
|
||||
? fn.apply(context, args)
|
||||
: fn(args[0], args[1], args[2], args[3], args[4]);
|
||||
|
||||
if (args) {
|
||||
// Free-up the memory (arguments of the last function call).
|
||||
args.length = 0;
|
||||
}
|
||||
|
||||
return ensureSafeObject(v, expressionText);
|
||||
};
|
||||
},
|
||||
|
||||
+1
-2
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
+15
-5
@@ -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
|
||||
@@ -128,6 +129,7 @@ function $AriaProvider() {
|
||||
* @name $aria
|
||||
*
|
||||
* @description
|
||||
* @priority 200
|
||||
*
|
||||
* The $aria service contains helper methods for applying common
|
||||
* [ARIA](http://www.w3.org/TR/wai-aria/) attributes to HTML directives.
|
||||
@@ -204,6 +206,7 @@ ngAriaModule.directive('ngShow', ['$aria', function($aria) {
|
||||
return {
|
||||
restrict: 'A',
|
||||
require: '?ngModel',
|
||||
priority: 200, //Make sure watches are fired after any other directives that affect the ngModel value
|
||||
link: function(scope, elem, attr, ngModel) {
|
||||
var shape = getShape(attr, elem);
|
||||
var needsTabIndex = shouldAttachAttr('tabindex', 'tabindex', elem);
|
||||
@@ -216,19 +219,19 @@ ngAriaModule.directive('ngShow', ['$aria', function($aria) {
|
||||
if (needsTabIndex) {
|
||||
needsTabIndex = false;
|
||||
return function ngAriaRadioReaction(newVal) {
|
||||
var boolVal = newVal === attr.value;
|
||||
var boolVal = (attr.value == ngModel.$viewValue);
|
||||
elem.attr('aria-checked', boolVal);
|
||||
elem.attr('tabindex', 0 - !boolVal);
|
||||
};
|
||||
} else {
|
||||
return function ngAriaRadioReaction(newVal) {
|
||||
elem.attr('aria-checked', newVal === attr.value);
|
||||
elem.attr('aria-checked', (attr.value == ngModel.$viewValue));
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function ngAriaCheckboxReaction(newVal) {
|
||||
elem.attr('aria-checked', !!newVal);
|
||||
elem.attr('aria-checked', !ngModel.$isEmpty(ngModel.$viewValue));
|
||||
}
|
||||
|
||||
switch (shape) {
|
||||
@@ -303,11 +306,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": {
|
||||
|
||||
Vendored
+14
@@ -2127,18 +2127,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;
|
||||
|
||||
@@ -208,6 +208,7 @@ function shallowClearAndCopy(src, dst) {
|
||||
* - non-GET "class" actions: `Resource.action([parameters], postData, [success], [error])`
|
||||
* - non-GET instance actions: `instance.$action([parameters], [success], [error])`
|
||||
*
|
||||
*
|
||||
* Success callback is called with (value, responseHeaders) arguments. Error callback is called
|
||||
* with (httpResponse) argument.
|
||||
*
|
||||
|
||||
+4
-10
@@ -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');
|
||||
}
|
||||
}
|
||||
|
||||
+14
-26
@@ -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,17 +361,17 @@ 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)
|
||||
stack.push(tagName);
|
||||
@@ -395,13 +396,13 @@ function htmlParser(html, handler) {
|
||||
if (tagName)
|
||||
// Find the closest opened tag of the same type
|
||||
for (pos = stack.length - 1; pos >= 0; pos--)
|
||||
if (stack[ pos ] == tagName)
|
||||
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;
|
||||
@@ -410,7 +411,6 @@ function htmlParser(html, handler) {
|
||||
}
|
||||
|
||||
var hiddenPre=document.createElement("pre");
|
||||
var spaceRe = /^(\s*)([\s\S]*?)(\s*)$/;
|
||||
/**
|
||||
* decodes all entities into regular string
|
||||
* @param value
|
||||
@@ -419,22 +419,10 @@ var spaceRe = /^(\s*)([\s\S]*?)(\s*)$/;
|
||||
function decodeEntities(value) {
|
||||
if (!value) { return ''; }
|
||||
|
||||
// Note: IE8 does not preserve spaces at the start/end of innerHTML
|
||||
// so we must capture them and reattach them afterward
|
||||
var parts = spaceRe.exec(value);
|
||||
var spaceBefore = parts[1];
|
||||
var spaceAfter = parts[3];
|
||||
var content = parts[2];
|
||||
if (content) {
|
||||
hiddenPre.innerHTML=content.replace(/</g,"<");
|
||||
// innerText depends on styling as it doesn't display hidden elements.
|
||||
// Therefore, it's better to use textContent not to cause unnecessary
|
||||
// reflows. However, IE<9 don't support textContent so the innerText
|
||||
// fallback is necessary.
|
||||
content = 'textContent' in hiddenPre ?
|
||||
hiddenPre.textContent : hiddenPre.innerText;
|
||||
}
|
||||
return spaceBefore + content + spaceAfter;
|
||||
hiddenPre.innerHTML = value.replace(/</g,"<");
|
||||
// innerText depends on styling as it doesn't display hidden elements.
|
||||
// Therefore, it's better to use textContent not to cause unnecessary reflows.
|
||||
return hiddenPre.textContent;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -68,19 +68,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 +117,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 +137,5 @@ angular.scenario.Application.prototype.executeAction = function(action) {
|
||||
action.call(self, $window, $element);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -304,7 +304,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;
|
||||
|
||||
@@ -1081,6 +1081,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');
|
||||
});
|
||||
|
||||
@@ -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');
|
||||
});
|
||||
|
||||
+59
-19
@@ -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");
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
@@ -4610,8 +4653,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 +4938,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 +5769,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 +6105,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__`.");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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_;
|
||||
@@ -76,6 +95,40 @@ describe('a', function() {
|
||||
});
|
||||
|
||||
|
||||
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();
|
||||
|
||||
var child = element.children('a');
|
||||
var preventDefault = jasmine.createSpy('preventDefault');
|
||||
|
||||
child.triggerHandler({
|
||||
type: 'click',
|
||||
preventDefault: preventDefault
|
||||
});
|
||||
|
||||
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();
|
||||
});
|
||||
|
||||
|
||||
if (isDefined(window.SVGElement)) {
|
||||
describe('SVGAElement', function() {
|
||||
it('should prevent default action to be executed when href is empty', function() {
|
||||
|
||||
@@ -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();
|
||||
@@ -1869,12 +1869,17 @@ describe('input', function() {
|
||||
});
|
||||
|
||||
it('should validate even if min value changes on-the-fly', function() {
|
||||
$rootScope.min = 10;
|
||||
$rootScope.min = undefined;
|
||||
var inputElm = helper.compileInput('<input type="number" ng-model="value" name="alias" min="{{min}}" />');
|
||||
expect(inputElm).toBeValid();
|
||||
|
||||
helper.changeInputValueTo('15');
|
||||
expect(inputElm).toBeValid();
|
||||
|
||||
$rootScope.min = 10;
|
||||
$rootScope.$digest();
|
||||
expect(inputElm).toBeValid();
|
||||
|
||||
$rootScope.min = 20;
|
||||
$rootScope.$digest();
|
||||
expect(inputElm).toBeInvalid();
|
||||
@@ -1910,12 +1915,17 @@ describe('input', function() {
|
||||
});
|
||||
|
||||
it('should validate even if the ngMin value changes on-the-fly', function() {
|
||||
$rootScope.min = 10;
|
||||
$rootScope.min = undefined;
|
||||
var inputElm = helper.compileInput('<input type="number" ng-model="value" name="alias" ng-min="min" />');
|
||||
expect(inputElm).toBeValid();
|
||||
|
||||
helper.changeInputValueTo('15');
|
||||
expect(inputElm).toBeValid();
|
||||
|
||||
$rootScope.min = 10;
|
||||
$rootScope.$digest();
|
||||
expect(inputElm).toBeValid();
|
||||
|
||||
$rootScope.min = 20;
|
||||
$rootScope.$digest();
|
||||
expect(inputElm).toBeInvalid();
|
||||
@@ -1952,12 +1962,17 @@ describe('input', function() {
|
||||
});
|
||||
|
||||
it('should validate even if max value changes on-the-fly', function() {
|
||||
$rootScope.max = 10;
|
||||
$rootScope.max = undefined;
|
||||
var inputElm = helper.compileInput('<input type="number" ng-model="value" name="alias" max="{{max}}" />');
|
||||
expect(inputElm).toBeValid();
|
||||
|
||||
helper.changeInputValueTo('5');
|
||||
expect(inputElm).toBeValid();
|
||||
|
||||
$rootScope.max = 10;
|
||||
$rootScope.$digest();
|
||||
expect(inputElm).toBeValid();
|
||||
|
||||
$rootScope.max = 0;
|
||||
$rootScope.$digest();
|
||||
expect(inputElm).toBeInvalid();
|
||||
@@ -1993,12 +2008,17 @@ describe('input', function() {
|
||||
});
|
||||
|
||||
it('should validate even if the ngMax value changes on-the-fly', function() {
|
||||
$rootScope.max = 10;
|
||||
$rootScope.max = undefined;
|
||||
var inputElm = helper.compileInput('<input type="number" ng-model="value" name="alias" ng-max="max" />');
|
||||
expect(inputElm).toBeValid();
|
||||
|
||||
helper.changeInputValueTo('5');
|
||||
expect(inputElm).toBeValid();
|
||||
|
||||
$rootScope.max = 10;
|
||||
$rootScope.$digest();
|
||||
expect(inputElm).toBeValid();
|
||||
|
||||
$rootScope.max = 0;
|
||||
$rootScope.$digest();
|
||||
expect(inputElm).toBeInvalid();
|
||||
|
||||
@@ -1221,6 +1221,96 @@ describe('ngModel', function() {
|
||||
expect(ctrl.$validators.mock).toHaveBeenCalledWith('a', 'ab');
|
||||
expect(ctrl.$validators.mock.calls.length).toEqual(2);
|
||||
});
|
||||
|
||||
it('should validate correctly when $parser name equals $validator key', function() {
|
||||
|
||||
ctrl.$validators.parserOrValidator = function(value) {
|
||||
switch (value) {
|
||||
case 'allInvalid':
|
||||
case 'parseValid-validatorsInvalid':
|
||||
case 'stillParseValid-validatorsInvalid':
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
ctrl.$validators.validator = function(value) {
|
||||
switch (value) {
|
||||
case 'allInvalid':
|
||||
case 'parseValid-validatorsInvalid':
|
||||
case 'stillParseValid-validatorsInvalid':
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
ctrl.$$parserName = 'parserOrValidator';
|
||||
ctrl.$parsers.push(function(value) {
|
||||
switch (value) {
|
||||
case 'allInvalid':
|
||||
case 'stillAllInvalid':
|
||||
case 'parseInvalid-validatorsValid':
|
||||
case 'stillParseInvalid-validatorsValid':
|
||||
return undefined;
|
||||
default:
|
||||
return value;
|
||||
}
|
||||
});
|
||||
|
||||
//Parser and validators are invalid
|
||||
scope.$apply('value = "allInvalid"');
|
||||
expect(scope.value).toBe('allInvalid');
|
||||
expect(ctrl.$error).toEqual({parserOrValidator: true, validator: true});
|
||||
|
||||
ctrl.$validate();
|
||||
expect(scope.value).toEqual('allInvalid');
|
||||
expect(ctrl.$error).toEqual({parserOrValidator: true, validator: true});
|
||||
|
||||
ctrl.$setViewValue('stillAllInvalid');
|
||||
expect(scope.value).toBeUndefined();
|
||||
expect(ctrl.$error).toEqual({parserOrValidator: true});
|
||||
|
||||
ctrl.$validate();
|
||||
expect(scope.value).toBeUndefined();
|
||||
expect(ctrl.$error).toEqual({parserOrValidator: true});
|
||||
|
||||
//Parser is valid, validators are invalid
|
||||
scope.$apply('value = "parseValid-validatorsInvalid"');
|
||||
expect(scope.value).toBe('parseValid-validatorsInvalid');
|
||||
expect(ctrl.$error).toEqual({parserOrValidator: true, validator: true});
|
||||
|
||||
ctrl.$validate();
|
||||
expect(scope.value).toBe('parseValid-validatorsInvalid');
|
||||
expect(ctrl.$error).toEqual({parserOrValidator: true, validator: true});
|
||||
|
||||
ctrl.$setViewValue('stillParseValid-validatorsInvalid');
|
||||
expect(scope.value).toBeUndefined();
|
||||
expect(ctrl.$error).toEqual({parserOrValidator: true, validator: true});
|
||||
|
||||
ctrl.$validate();
|
||||
expect(scope.value).toBeUndefined();
|
||||
expect(ctrl.$error).toEqual({parserOrValidator: true, validator: true});
|
||||
|
||||
//Parser is invalid, validators are valid
|
||||
scope.$apply('value = "parseInvalid-validatorsValid"');
|
||||
expect(scope.value).toBe('parseInvalid-validatorsValid');
|
||||
expect(ctrl.$error).toEqual({});
|
||||
|
||||
ctrl.$validate();
|
||||
expect(scope.value).toBe('parseInvalid-validatorsValid');
|
||||
expect(ctrl.$error).toEqual({});
|
||||
|
||||
ctrl.$setViewValue('stillParseInvalid-validatorsValid');
|
||||
expect(scope.value).toBeUndefined();
|
||||
expect(ctrl.$error).toEqual({parserOrValidator: true});
|
||||
|
||||
ctrl.$validate();
|
||||
expect(scope.value).toBeUndefined();
|
||||
expect(ctrl.$error).toEqual({parserOrValidator: true});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -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');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
+63
-6
@@ -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(),
|
||||
@@ -1504,6 +1514,53 @@ describe('$location', function() {
|
||||
);
|
||||
});
|
||||
|
||||
it('should not rewrite when right click pressed', function() {
|
||||
configureService({linkHref: 'base/a?b=c', html5Mode: true, supportHist: true});
|
||||
inject(
|
||||
initBrowser(),
|
||||
initLocation(),
|
||||
function($browser) {
|
||||
var rightClick;
|
||||
if (document.createEvent) {
|
||||
rightClick = document.createEvent('MouseEvents');
|
||||
rightClick.initMouseEvent('click', true, true, window, 1, 10, 10, 10, 10, false,
|
||||
false, false, false, 2, null);
|
||||
|
||||
link.dispatchEvent(rightClick);
|
||||
} else if (document.createEventObject) { // for IE
|
||||
rightClick = document.createEventObject();
|
||||
rightClick.type = 'click';
|
||||
rightClick.cancelBubble = true;
|
||||
rightClick.detail = 1;
|
||||
rightClick.screenX = 10;
|
||||
rightClick.screenY = 10;
|
||||
rightClick.clientX = 10;
|
||||
rightClick.clientY = 10;
|
||||
rightClick.ctrlKey = false;
|
||||
rightClick.altKey = false;
|
||||
rightClick.shiftKey = false;
|
||||
rightClick.metaKey = false;
|
||||
rightClick.button = 2;
|
||||
link.fireEvent('onclick', rightClick);
|
||||
}
|
||||
expectNoRewrite($browser);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
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;
|
||||
@@ -1813,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
|
||||
|
||||
|
||||
@@ -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);
|
||||
}));
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
+76
-5
@@ -85,6 +85,28 @@ describe('$aria', function() {
|
||||
expect(element.attr('aria-checked')).toBe('false');
|
||||
});
|
||||
|
||||
it('should handle checkbox with string model values using ng(True|False)Value', function() {
|
||||
var element = $compile('<input type="checkbox" ng-model="val" ng-true-value="\'yes\'" ' +
|
||||
'ng-false-value="\'no\'">'
|
||||
)(scope);
|
||||
|
||||
scope.$apply('val="yes"');
|
||||
expect(element.eq(0).attr('aria-checked')).toBe('true');
|
||||
|
||||
scope.$apply('val="no"');
|
||||
expect(element.eq(0).attr('aria-checked')).toBe('false');
|
||||
});
|
||||
|
||||
it('should handle checkbox with integer model values using ngTrueValue', function() {
|
||||
var element = $compile('<input type="checkbox" ng-model="val" ng-true-value="0">')(scope);
|
||||
|
||||
scope.$apply('val=0');
|
||||
expect(element.eq(0).attr('aria-checked')).toBe('true');
|
||||
|
||||
scope.$apply('val=1');
|
||||
expect(element.eq(0).attr('aria-checked')).toBe('false');
|
||||
});
|
||||
|
||||
it('should attach itself to input type="radio"', function() {
|
||||
var element = $compile('<input type="radio" ng-model="val" value="one">' +
|
||||
'<input type="radio" ng-model="val" value="two">')(scope);
|
||||
@@ -98,6 +120,36 @@ describe('$aria', function() {
|
||||
expect(element.eq(1).attr('aria-checked')).toBe('true');
|
||||
});
|
||||
|
||||
it('should handle radios with integer model values', function() {
|
||||
var element = $compile('<input type="radio" ng-model="val" value="0">' +
|
||||
'<input type="radio" ng-model="val" value="1">')(scope);
|
||||
|
||||
scope.$apply('val=0');
|
||||
expect(element.eq(0).attr('aria-checked')).toBe('true');
|
||||
expect(element.eq(1).attr('aria-checked')).toBe('false');
|
||||
|
||||
scope.$apply('val=1');
|
||||
expect(element.eq(0).attr('aria-checked')).toBe('false');
|
||||
expect(element.eq(1).attr('aria-checked')).toBe('true');
|
||||
});
|
||||
|
||||
it('should handle radios with boolean model values using ngValue', function() {
|
||||
var element = $compile('<input type="radio" ng-model="val" ng-value="valExp">' +
|
||||
'<input type="radio" ng-model="val" ng-value="valExp2">')(scope);
|
||||
|
||||
scope.$apply(function() {
|
||||
scope.valExp = true;
|
||||
scope.valExp2 = false;
|
||||
scope.val = true;
|
||||
});
|
||||
expect(element.eq(0).attr('aria-checked')).toBe('true');
|
||||
expect(element.eq(1).attr('aria-checked')).toBe('false');
|
||||
|
||||
scope.$apply('val = false');
|
||||
expect(element.eq(0).attr('aria-checked')).toBe('false');
|
||||
expect(element.eq(1).attr('aria-checked')).toBe('true');
|
||||
});
|
||||
|
||||
it('should attach itself to role="radio"', function() {
|
||||
scope.$apply("val = 'one'");
|
||||
compileInput('<div role="radio" ng-model="val" value="{{val}}"></div>');
|
||||
@@ -488,12 +540,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 +590,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 +605,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.');
|
||||
});
|
||||
@@ -487,8 +495,7 @@ describe('HTML', function() {
|
||||
});
|
||||
|
||||
describe('decodeEntities', function() {
|
||||
var handler, text,
|
||||
origHiddenPre = window.hiddenPre;
|
||||
var handler, text;
|
||||
|
||||
beforeEach(function() {
|
||||
text = '';
|
||||
@@ -503,37 +510,13 @@ describe('decodeEntities', function() {
|
||||
module('ngSanitize');
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
window.hiddenPre = origHiddenPre;
|
||||
it('should unescape text', function() {
|
||||
htmlParser('a<div>&</div>c', handler);
|
||||
expect(text).toEqual('a<div>&</div>c');
|
||||
});
|
||||
|
||||
it('should use innerText if textContent is not available (IE<9)', function() {
|
||||
window.hiddenPre = {
|
||||
innerText: 'INNER_TEXT'
|
||||
};
|
||||
inject(function($sanitize) {
|
||||
htmlParser('<tag>text</tag>', handler);
|
||||
expect(text).toEqual('INNER_TEXT');
|
||||
});
|
||||
});
|
||||
it('should use textContent if available', function() {
|
||||
window.hiddenPre = {
|
||||
textContent: 'TEXT_CONTENT',
|
||||
innerText: 'INNER_TEXT'
|
||||
};
|
||||
inject(function($sanitize) {
|
||||
htmlParser('<tag>text</tag>', handler);
|
||||
expect(text).toEqual('TEXT_CONTENT');
|
||||
});
|
||||
});
|
||||
it('should use textContent even if empty', function() {
|
||||
window.hiddenPre = {
|
||||
textContent: '',
|
||||
innerText: 'INNER_TEXT'
|
||||
};
|
||||
inject(function($sanitize) {
|
||||
htmlParser('<tag>text</tag>', handler);
|
||||
expect(text).toEqual('');
|
||||
});
|
||||
it('should preserve whitespace', function() {
|
||||
htmlParser(' a&b ', handler);
|
||||
expect(text).toEqual(' a&b ');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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);
|
||||
}));
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user