Compare commits
228 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 93b0c2d892 | |||
| d262378b7c | |||
| 7729c84ec7 | |||
| dffeef29d7 | |||
| 2e22588ccf | |||
| 0b0acb0342 | |||
| 18fc43e828 | |||
| ed47d811e2 | |||
| a84f9f6178 | |||
| 4fbbe1152e | |||
| df3d941c57 | |||
| 2bd3214a55 | |||
| fc2abef327 | |||
| 76a0eb89fb | |||
| ee57b4c26b | |||
| 29eaabc000 | |||
| 2a6081057f | |||
| 79538afd7b | |||
| bcfa64e77c | |||
| b7a2deed30 | |||
| 98ff901bda | |||
| 428b81cba9 | |||
| 5dae9c230e | |||
| c3fad1157e | |||
| 9242c580a1 | |||
| c2860944c6 | |||
| e9a00fbdc3 | |||
| d018ac2a9a | |||
| b770c353bc | |||
| 812277c257 | |||
| 61871da9de | |||
| 9ee075518f | |||
| afe93eaff8 | |||
| d8f94d1a3f | |||
| f53b53df22 | |||
| eab5731afc | |||
| 986c446aaf | |||
| 60366c8d0b | |||
| 494c8aa0b3 | |||
| cd9459e129 | |||
| 2862883bd8 | |||
| bbb673a48a | |||
| cd9afd9961 | |||
| e25ed0d48d | |||
| cd6d21e78a | |||
| 9cf5b35e5c | |||
| 5d11e02008 | |||
| 209e600070 | |||
| ceaca57786 | |||
| cbdf0c2afb | |||
| 1111076552 | |||
| 948c86c602 | |||
| cd63ff497d | |||
| 9d6240561b | |||
| 05b5245790 | |||
| e6ebfc87c9 | |||
| 7f2bcc3933 | |||
| 492b0cdf28 | |||
| 51863f80d7 | |||
| 9d4000d689 | |||
| bc036c68ac | |||
| 580135a9cb | |||
| da0c5efa72 | |||
| c280d5ab02 | |||
| 28c8199cd6 | |||
| 0252a9889b | |||
| 1c15cdc2d0 | |||
| 0bd329d4fd | |||
| 8db84a16db | |||
| cffcfc73a0 | |||
| 25eb9b794f | |||
| 6941779543 | |||
| 65f40d2123 | |||
| e159f9626c | |||
| 685a9d040d | |||
| 8eede099cd | |||
| a17d42d706 | |||
| 60af504c18 | |||
| 243d9ac72c | |||
| cc8eb91665 | |||
| 8697c3bf4c | |||
| 3c46c94342 | |||
| 71eb1901f6 | |||
| 4e57e28589 | |||
| 13289c0903 | |||
| afdb4f1b76 | |||
| e7999e7447 | |||
| d175bb0131 | |||
| fe1188daf3 | |||
| e1a3a6251f | |||
| 25d3d3730d | |||
| af5aacce05 | |||
| 3abd0fb93c | |||
| 36d2658b94 | |||
| 6ce5a04d42 | |||
| 929064d9e4 | |||
| d0b873a4b7 | |||
| 2e10659472 | |||
| 2a8493f40c | |||
| 2f960f1530 | |||
| 3f5f20fe77 | |||
| 01387c0a8f | |||
| c0afbfaca5 | |||
| bf13d2683d | |||
| fe01a85a8e | |||
| 6b9a332959 | |||
| f1b28847c8 | |||
| 1b779028fd | |||
| 49b2a1c8cf | |||
| 3e82492fc6 | |||
| 856be44628 | |||
| dbb21b1531 | |||
| 3ce56b739c | |||
| ecbb374826 | |||
| 0e5d31908e | |||
| f1b0d21f97 | |||
| 58e94dcde9 | |||
| eba192b863 | |||
| 75099e6137 | |||
| 172a40931b | |||
| 23e5109b64 | |||
| cc84ce3bf5 | |||
| bee2d1fbb9 | |||
| 7101a02c93 | |||
| 888be00712 | |||
| 05597c24c7 | |||
| bf55f23325 | |||
| ab051e78ea | |||
| 87d46a84c3 | |||
| ae764f1844 | |||
| ad8092ed80 | |||
| 55e1b3e1c8 | |||
| 6f465a2b26 | |||
| 3ecac62251 | |||
| c64610269d | |||
| 5c2302949b | |||
| 7c84e2632f | |||
| 18d18f07db | |||
| 9f5be534fc | |||
| 1cd7912614 | |||
| 514da451fc | |||
| 2788cc4e12 | |||
| 7f6322df6a | |||
| 5bd8613168 | |||
| 32b507890e | |||
| bfedafdede | |||
| cdefbe3425 | |||
| f75f4bce82 | |||
| 4349de3d41 | |||
| df545d7eed | |||
| 3b5f346314 | |||
| 3aab87b381 | |||
| 0973175058 | |||
| 112da45c07 | |||
| e3dc85841d | |||
| ef1c352bc9 | |||
| a5b6444324 | |||
| dd18c00b1d | |||
| a0fad24dc2 | |||
| da0e3c99f5 | |||
| a41c58e285 | |||
| bce5b49133 | |||
| 816b84230c | |||
| 873acf8fab | |||
| 9063a0c2e7 | |||
| 03cbc0d6b1 | |||
| 931789ec14 | |||
| 9bc807783f | |||
| 2d6ee651b1 | |||
| 7ca24a8264 | |||
| 1d8e42070a | |||
| fe6b2fbfc4 | |||
| 5a222244fb | |||
| 4026074aba | |||
| d9a596addd | |||
| 8c0898b21c | |||
| d9b693bb7a | |||
| da94ab2e63 | |||
| 2fd8dc7061 | |||
| 01012a4d7a | |||
| ce84429adf | |||
| a26acb64fe | |||
| 7088ed1ed3 | |||
| 7027844d42 | |||
| 16c584ed7f | |||
| b586bfdfab | |||
| 1d69015e3d | |||
| f13c33bf10 | |||
| ba62e975f1 | |||
| b89d941cdf | |||
| 07fa87a8a8 | |||
| 0af70eb99e | |||
| cb713e6045 | |||
| 89ca859734 | |||
| bc6fb7cc94 | |||
| 0c80df21b6 | |||
| 3141dbf179 | |||
| aad502bad8 | |||
| dca8972367 | |||
| 284de57435 | |||
| f780ccfa1c | |||
| 55f99e0710 | |||
| 1a99ca9c08 | |||
| 37500fca83 | |||
| 4fe4fc5abf | |||
| 74e1cc683b | |||
| a4faa5cde7 | |||
| 32cb40b86d | |||
| d1cd677433 | |||
| 43c735a816 | |||
| ab2e83c8c8 | |||
| e5f454c8af | |||
| 67c11b9a39 | |||
| 5a306b7ba3 | |||
| 8ce61bf178 | |||
| 9d452bc845 | |||
| 192fecc790 | |||
| 32be6369e4 | |||
| 2a45cea0ba | |||
| ea653e4cdd | |||
| 03777445e8 | |||
| 8b25ea129a | |||
| d71f16e745 | |||
| ed59370d80 | |||
| d8e5acfe27 | |||
| af59f4e69a | |||
| 24aee81634 | |||
| f81d56e66c |
@@ -0,0 +1,21 @@
|
||||
# http://editorconfig.org
|
||||
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[src/ngLocale/**]
|
||||
insert_final_newline = false
|
||||
|
||||
[dropdown-toggle.js]
|
||||
trim_trailing_whitespace = false
|
||||
insert_final_newline = false
|
||||
|
||||
[htmlparser.js]
|
||||
insert_final_newline = false
|
||||
@@ -0,0 +1,2 @@
|
||||
node_modules/**
|
||||
lib/htmlparser/**
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"bitwise": true,
|
||||
"immed": true,
|
||||
"newcap": true,
|
||||
"noarg": true,
|
||||
"noempty": true,
|
||||
"nonew": true,
|
||||
"trailing": true,
|
||||
"maxlen": 200,
|
||||
"boss": true,
|
||||
"eqnull": true,
|
||||
"expr": true,
|
||||
"globalstrict": true,
|
||||
"laxbreak": true,
|
||||
"loopfunc": true,
|
||||
"sub": true,
|
||||
"undef": true,
|
||||
"indent": 2
|
||||
}
|
||||
+8
-3
@@ -1,6 +1,6 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- 0.10
|
||||
- '0.10'
|
||||
|
||||
branches:
|
||||
except:
|
||||
@@ -19,8 +19,13 @@ env:
|
||||
- BROWSER_PROVIDER_READY_FILE=/tmp/sauce-connect-ready
|
||||
|
||||
install:
|
||||
- npm config set registry http://23.251.144.68
|
||||
- npm install
|
||||
# - 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
|
||||
|
||||
before_script:
|
||||
- mkdir -p $LOGS_DIR
|
||||
|
||||
+923
@@ -1,3 +1,926 @@
|
||||
<a name="1.3.0-beta.17"></a>
|
||||
# 1.3.0-beta.17 turing-autocompletion (2014-07-25)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **angular.copy:** clone regexp flags correctly
|
||||
([86340a59](https://github.com/angular/angular.js/commit/86340a59bf9eb7bdfc4f99000cecf628cd10d9c8),
|
||||
[#5781](https://github.com/angular/angular.js/issues/5781), [#8337](https://github.com/angular/angular.js/issues/8337))
|
||||
- **docs:** change plnkr form to open in same window
|
||||
([925b2080](https://github.com/angular/angular.js/commit/925b2080a0341d9348feeb4f492957a2e2c80082))
|
||||
- **jqLite:** triggerHandler support unbind self
|
||||
([8a27abae](https://github.com/angular/angular.js/commit/8a27abae896de3c4d94c407e8bb381e099d2d7f7),
|
||||
[#5984](https://github.com/angular/angular.js/issues/5984))
|
||||
- **ngHref:** remove attribute when empty value instead of ignoring
|
||||
([469ea338](https://github.com/angular/angular.js/commit/469ea3384ad48ca4765af807c0f41201edb527f9),
|
||||
[#2755](https://github.com/angular/angular.js/issues/2755))
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
- **$compile:** change directive's restrict setting to default to EA (element/attribute)
|
||||
([11f5aeee](https://github.com/angular/angular.js/commit/11f5aeeee952a395edaf54e3277674f211a82fc7),
|
||||
[#8321](https://github.com/angular/angular.js/issues/8321))
|
||||
- **$q:** add streamlined ES6-style interface for using $q
|
||||
([f3a763fd](https://github.com/angular/angular.js/commit/f3a763fd2edd8a37b80c79a5aaa1444460cd2df7),
|
||||
[#8311](https://github.com/angular/angular.js/issues/8311), [#6427](https://github.com/angular/angular.js/issues/6427))
|
||||
- **ngRepeat:** provide support for aliasing filtered repeater results as a scope member
|
||||
([e0adb9c4](https://github.com/angular/angular.js/commit/e0adb9c452e172295209f785b62472688225fffb),
|
||||
[#5919](https://github.com/angular/angular.js/issues/5919), [#8046](https://github.com/angular/angular.js/issues/8046), [#8282](https://github.com/angular/angular.js/issues/8282))
|
||||
|
||||
|
||||
## Performance Improvements
|
||||
|
||||
- **$parse:** don't use reflective calls in generated functions
|
||||
([c54228fb](https://github.com/angular/angular.js/commit/c54228fbe9d42d8a3a159bf84dd1d2e99b259ece))
|
||||
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
- **$compile:** due to [11f5aeee](https://github.com/angular/angular.js/commit/11f5aeeee952a395edaf54e3277674f211a82fc7),
|
||||
directives now match elements by default unless specific restriction rules are set via `restrict` property.
|
||||
|
||||
This means that if a directive 'myFoo' previously didn't specify matching restrictrion, it will now match both the attribute
|
||||
and element form.
|
||||
|
||||
Before:
|
||||
|
||||
`<div my-foo></div>` <---- my-foo attribute matched the directive
|
||||
|
||||
`<my-foo></my-foo>` <---- no match
|
||||
|
||||
After:
|
||||
|
||||
`<div my-foo></div>` <---- my-foo attribute matched the directive
|
||||
|
||||
`<my-foo></my-foo>` <---- my-foo element matched the directive
|
||||
|
||||
It is not expected that this will be a problem in practice because of widespread use of prefixes that make `<my-foo>` like
|
||||
elements unlikely.
|
||||
|
||||
Closes #8321
|
||||
|
||||
|
||||
<a name="1.2.21"></a>
|
||||
# 1.2.21 wizard-props (2014-07-25)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$http:** fix double-quoted date issue when encoding params
|
||||
([2f960f15](https://github.com/angular/angular.js/commit/2f960f1530ed936c57df612a352a0d996368f6a1),
|
||||
[#8150](https://github.com/angular/angular.js/issues/8150), [#6128](https://github.com/angular/angular.js/issues/6128), [#8154](https://github.com/angular/angular.js/issues/8154))
|
||||
- **$location:** handle plus character in query strings
|
||||
([60af504c](https://github.com/angular/angular.js/commit/60af504c18dbdde9dfe90e9a2badef6d9e798512),
|
||||
[#3042](https://github.com/angular/angular.js/issues/3042))
|
||||
- **$rootScope:** $watchCollection should handle NaN in objects
|
||||
([bf13d268](https://github.com/angular/angular.js/commit/bf13d2683d5880b18db00087e80ee0fd5e1f429a),
|
||||
[#7930](https://github.com/angular/angular.js/issues/7930))
|
||||
- **angular.copy:** clone regexp flags correctly
|
||||
([e25ed0d4](https://github.com/angular/angular.js/commit/e25ed0d48d9a1c577e78b1c96098841572c764ea),
|
||||
[#5781](https://github.com/angular/angular.js/issues/5781), [#8337](https://github.com/angular/angular.js/issues/8337))
|
||||
- **csp:** fix autodetection of CSP + better docs
|
||||
([0e5d3190](https://github.com/angular/angular.js/commit/0e5d31908e122f013427164f7bbeea914a9a5961),
|
||||
[#8162](https://github.com/angular/angular.js/issues/8162), [#8191](https://github.com/angular/angular.js/issues/8191))
|
||||
- **docs:** change plnkr form to open in same window
|
||||
([5d11e020](https://github.com/angular/angular.js/commit/5d11e02008731a78f302841863a83fe7ed3c37b9))
|
||||
- **jqLite:** triggerHandler support unbind self
|
||||
([209e6000](https://github.com/angular/angular.js/commit/209e60007042f7e8b34c54ec6bf7d6f703c0ba2a),
|
||||
[#5984](https://github.com/angular/angular.js/issues/5984))
|
||||
- **ngHref:** remove attribute when empty value instead of ignoring
|
||||
([948c86c6](https://github.com/angular/angular.js/commit/948c86c6025fca8e07921869d21cfac1c6333b05),
|
||||
[#2755](https://github.com/angular/angular.js/issues/2755))
|
||||
- **ngRoute:** remove unnecessary call to decodeURIComponent
|
||||
([1b779028](https://github.com/angular/angular.js/commit/1b779028fdd339febaa1fff5f3bd4cfcda46cc09),
|
||||
[#6326](https://github.com/angular/angular.js/issues/6326), [#6327](https://github.com/angular/angular.js/issues/6327))
|
||||
- **ngSanitize:**
|
||||
- follow HTML parser rules for start tags / allow < in text content
|
||||
([d175bb01](https://github.com/angular/angular.js/commit/d175bb01314efdcbad5c3cb31b02e298e26c6e19),
|
||||
[#8212](https://github.com/angular/angular.js/issues/8212), [#8193](https://github.com/angular/angular.js/issues/8193))
|
||||
- **orderBy:** correctly order by date values
|
||||
([f1b28847](https://github.com/angular/angular.js/commit/f1b28847c8123483e03ac2410de86fd33a80b5f4),
|
||||
[#6675](https://github.com/angular/angular.js/issues/6675), [#6746](https://github.com/angular/angular.js/issues/6746))
|
||||
- **select:** force visual update in IE
|
||||
([c0afbfac](https://github.com/angular/angular.js/commit/c0afbfaca57893403d8d4b0990879ad5b9ffc3e5),
|
||||
[#7692](https://github.com/angular/angular.js/issues/7692), [#8158](https://github.com/angular/angular.js/issues/8158))
|
||||
|
||||
|
||||
## Performance Improvements
|
||||
|
||||
- **$compile:** only create jqLite object when necessary
|
||||
([71eb1901](https://github.com/angular/angular.js/commit/71eb1901f6b9a3a6d4b772aa95ce0dc78ff847bc))
|
||||
- **$parse:** don't use reflective calls in generated functions
|
||||
([cbdf0c2a](https://github.com/angular/angular.js/commit/cbdf0c2afb9836ae4cca6d70cf555ff28f55a1d1))
|
||||
- **forEach:** use native for loop instead of forEach for Arrays
|
||||
([492b0cdf](https://github.com/angular/angular.js/commit/492b0cdf28d02f1d508455245b7d8e1d641d9f40))
|
||||
- **jqLite:** expose the low-level jqLite.data/removeData calls
|
||||
([3c46c943](https://github.com/angular/angular.js/commit/3c46c94342aa35131f3ba0f8f4a6b39338b87d56))
|
||||
- **ngBindHtml:** move addClass to the compile phase
|
||||
([8eede099](https://github.com/angular/angular.js/commit/8eede099cd8aa6d524d1de385d08432072fd294e),
|
||||
[#8261](https://github.com/angular/angular.js/issues/8261))
|
||||
|
||||
|
||||
<a name="1.3.0-beta.16"></a>
|
||||
# 1.3.0-beta.16 pizza-transubstantiation (2014-07-18)
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$cookie:** use `decodeURIComponent` instead of unescape for cookie reading
|
||||
([1c9ab40d](https://github.com/angular/angular.js/commit/1c9ab40d286ffdb1b41d30ca8d861b53175bfc24),
|
||||
[#8125](https://github.com/angular/angular.js/issues/8125))
|
||||
- **$http:** fix double-quoted date issue when encoding params
|
||||
([9dce42b3](https://github.com/angular/angular.js/commit/9dce42b3c26eb02621723172a68725980369b849),
|
||||
[#8150](https://github.com/angular/angular.js/issues/8150), [#6128](https://github.com/angular/angular.js/issues/6128), [#8154](https://github.com/angular/angular.js/issues/8154))
|
||||
- **$location:** handle plus character in query strings
|
||||
([3f4ee151](https://github.com/angular/angular.js/commit/3f4ee1513901f55d6007e3fc3948458adf4ac656),
|
||||
[#3042](https://github.com/angular/angular.js/issues/3042))
|
||||
- **$rootScope:**
|
||||
- `$watchCollection` should handle `NaN` in objects
|
||||
([db9f2570](https://github.com/angular/angular.js/commit/db9f2570c18d77d0e51d5a7afa139d25d0bdc470),
|
||||
[#7930](https://github.com/angular/angular.js/issues/7930))
|
||||
- remove support for a watch action to be a string
|
||||
([02c0ed27](https://github.com/angular/angular.js/commit/02c0ed27bc375d5352fefdd7e34aad9758621283),
|
||||
[#8190](https://github.com/angular/angular.js/issues/8190))
|
||||
- **csp:** fix autodetection of CSP + better docs
|
||||
([0113f225](https://github.com/angular/angular.js/commit/0113f2257415422729d5c2a9bdba76c1d0a17a13),
|
||||
[#8162](https://github.com/angular/angular.js/issues/8162), [#8191](https://github.com/angular/angular.js/issues/8191))
|
||||
- **ngList:** use custom separators for re-joining list items
|
||||
([c6c9d26e](https://github.com/angular/angular.js/commit/c6c9d26e3487ce24ece390c26994123964f805b0),
|
||||
[#4008](https://github.com/angular/angular.js/issues/4008), [#2561](https://github.com/angular/angular.js/issues/2561), [#4344](https://github.com/angular/angular.js/issues/4344))
|
||||
- **ngRoute:** remove unnecessary call to `decodeURIComponent`
|
||||
([528f56a6](https://github.com/angular/angular.js/commit/528f56a690295650f54eeb2238609446635c5db0),
|
||||
[#6326](https://github.com/angular/angular.js/issues/6326), [#6327](https://github.com/angular/angular.js/issues/6327))
|
||||
- **ngSanitize:** follow HTML parser rules for start tags / allow < in text content
|
||||
([f6681d41](https://github.com/angular/angular.js/commit/f6681d41a493efa6566f8a8a0b6ec39547e572ef),
|
||||
[#8212](https://github.com/angular/angular.js/issues/8212), [#8193](https://github.com/angular/angular.js/issues/8193))
|
||||
- **ngSwitch:**
|
||||
- interoperate with multi-element transclude directives
|
||||
([c20d438a](https://github.com/angular/angular.js/commit/c20d438ac9b9757331d096969a73c782c38e098a),
|
||||
[#8235](https://github.com/angular/angular.js/issues/8235), [#8244](https://github.com/angular/angular.js/issues/8244))
|
||||
- use the correct transclusion scope
|
||||
([4f32e3ee](https://github.com/angular/angular.js/commit/4f32e3eef152bcaab7f7ab151fc824e71a591473),
|
||||
[#8235](https://github.com/angular/angular.js/issues/8235))
|
||||
- **orderBy:** correctly order by date values
|
||||
([92bceb5c](https://github.com/angular/angular.js/commit/92bceb5c5b6e4a5a8fee01e1e0dfcf4674858cf2),
|
||||
[#6675](https://github.com/angular/angular.js/issues/6675), [#6746](https://github.com/angular/angular.js/issues/6746))
|
||||
- **select:** force visual update in IE
|
||||
([d7f73022](https://github.com/angular/angular.js/commit/d7f730228d58d3a409846e64ba5d0120356691cc),
|
||||
[#7692](https://github.com/angular/angular.js/issues/7692), [#8158](https://github.com/angular/angular.js/issues/8158))
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
- **$compile:** explicitly request multi-element directive behaviour
|
||||
([e8066c4b](https://github.com/angular/angular.js/commit/e8066c4b4ce11496b0d8f39e41b4d753048bca2d),
|
||||
[#5372](https://github.com/angular/angular.js/issues/5372), [#6574](https://github.com/angular/angular.js/issues/6574), [#5370](https://github.com/angular/angular.js/issues/5370), [#8044](https://github.com/angular/angular.js/issues/8044), [#7336](https://github.com/angular/angular.js/issues/7336))
|
||||
- **ngList:** use ngTrim to manage whitespace handling when splitting
|
||||
([8d18d20e](https://github.com/angular/angular.js/commit/8d18d20e316ed9d420f09f46f90027aef2940930))
|
||||
- **ngTransclude:** allow ngTransclude to be used as an element
|
||||
([3dafcba9](https://github.com/angular/angular.js/commit/3dafcba9c1738b85f3adceaac90b747a1b595ea8),
|
||||
[#8141](https://github.com/angular/angular.js/issues/8141))
|
||||
|
||||
|
||||
## Performance Improvements
|
||||
|
||||
- **$compile:** only create jqLite object when necessary
|
||||
([a160f76f](https://github.com/angular/angular.js/commit/a160f76ffa9544cd2ed99f24ba65b5994108f9f5))
|
||||
- **bindOnce** more performant interpolation and lazy one-time binding
|
||||
([86d55c1d](https://github.com/angular/angular.js/commit/86d55c1ded21a5be6091344493d70c6dc4194e43))
|
||||
- **jqLite:** expose the low-level jqLite.data/removeData calls
|
||||
([e4ba8943](https://github.com/angular/angular.js/commit/e4ba89436aa0b96f126ce2c23d0c7f7c785573fe))
|
||||
- **ngBindHtml:** move addClass to the compile phase
|
||||
([903e7352](https://github.com/angular/angular.js/commit/903e7352c9943e4d3757dd1cff58178d4c5375d6),
|
||||
[#8261](https://github.com/angular/angular.js/issues/8261))
|
||||
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
- **$compile:** due to [e8066c4b](https://github.com/angular/angular.js/commit/e8066c4b4ce11496b0d8f39e41b4d753048bca2d),
|
||||
Directives which previously depended on the implicit grouping between
|
||||
directive-start and directive-end attributes must be refactored in order to see this same behaviour.
|
||||
|
||||
Before:
|
||||
|
||||
```html
|
||||
<div data-fancy-directive-start>{{start}}</div>
|
||||
<p>Grouped content</p>
|
||||
<div data-fancy-directive-end>{{end}}</div>
|
||||
```
|
||||
```javascript
|
||||
.directive('fancyDirective', function() {
|
||||
return {
|
||||
link: angular.noop
|
||||
};
|
||||
})
|
||||
```
|
||||
|
||||
After:
|
||||
|
||||
```html
|
||||
<div data-fancy-directive-start>{{start}}</div>
|
||||
<p>Grouped content</p>
|
||||
<div data-fancy-directive-end>{{end}}</div>
|
||||
```
|
||||
```javascript
|
||||
.directive('fancyDirective', function() {
|
||||
return {
|
||||
multiElement: true, // Explicitly mark as a multi-element directive.
|
||||
link: angular.noop
|
||||
};
|
||||
})
|
||||
```
|
||||
|
||||
Closes #5372
|
||||
Closes #6574
|
||||
Closes #5370
|
||||
Closes #8044
|
||||
Closes #7336
|
||||
|
||||
- **$rootScope:** due to [02c0ed27](https://github.com/angular/angular.js/commit/02c0ed27bc375d5352fefdd7e34aad9758621283),
|
||||
|
||||
|
||||
Previously, it was possible for an action passed to $watch
|
||||
to be a string, interpreted as an angular expresison. This is no longer supported.
|
||||
The action now has to be a function.
|
||||
Passing an action to $watch is still optional.
|
||||
|
||||
Before:
|
||||
|
||||
```javascript
|
||||
$scope.$watch('state', ' name="" ');
|
||||
```
|
||||
|
||||
After:
|
||||
|
||||
```javascript
|
||||
$scope.$watch('state', function () {
|
||||
$scope.name = "";
|
||||
});
|
||||
```
|
||||
|
||||
Closes #8190
|
||||
|
||||
- **bootstrap:** due to [666a3835](https://github.com/angular/angular.js/commit/666a3835d231b3f77f907276be18b3c0086e5d12),
|
||||
|
||||
|
||||
If using any of the mechanisms specified above, then migrate by
|
||||
specifying the attribute `ng-app` to the root element. E.g.
|
||||
|
||||
```html
|
||||
<div ng-app="module">...</div>
|
||||
```
|
||||
|
||||
Closes #8147
|
||||
|
||||
- **ngList:** due to [c6c9d26e](https://github.com/angular/angular.js/commit/c6c9d26e3487ce24ece390c26994123964f805b0),
|
||||
|
||||
|
||||
The `ngList` directive no longer supports splitting the view value
|
||||
via a regular expression. We need to be able to re-join list items back
|
||||
together and doing this when you can split with regular expressions can
|
||||
lead to inconsistent behaviour and would be much more complex to support.
|
||||
|
||||
If your application relies upon ngList splitting with a regular expression
|
||||
then you should either try to convert the separator to a simple string or
|
||||
you can implement your own version of this directive for you application.
|
||||
|
||||
Closes #4008
|
||||
Closes #2561
|
||||
Closes #4344
|
||||
|
||||
- **ngSwitch:** due to [4f32e3ee](https://github.com/angular/angular.js/commit/4f32e3eef152bcaab7f7ab151fc824e71a591473),
|
||||
|
||||
** Directive Priority Changed ** - this commit changes the priority
|
||||
of `ngSwitchWhen` and `ngSwitchDefault` from `800` to `1200`. This makes their
|
||||
priority higher than `ngRepeat`, which allows items to be repeated on
|
||||
the switch case element reliably.
|
||||
|
||||
In general your directives should have a lower priority than these directives
|
||||
if you want them to exist inside the case elements. If you relied on the
|
||||
priority of these directives then you should check that your code still
|
||||
operates correctly.
|
||||
|
||||
Closes #8235
|
||||
|
||||
<a name="1.3.0-beta.15"></a>
|
||||
# 1.3.0-beta.15 unbelievable-advancement (2014-07-11)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$animate:**
|
||||
- ensure that parallel class-based animations are all eventually closed
|
||||
([f07af61f](https://github.com/angular/angular.js/commit/f07af61f050fcdcece15c13ee8c6a6d32f86d3a1),
|
||||
[#7766](https://github.com/angular/angular.js/issues/7766))
|
||||
- remove the ng-animate className after canceling animation
|
||||
([e18db78d](https://github.com/angular/angular.js/commit/e18db78d7793b1e94d9b19ac15b89d39f21a5729),
|
||||
[#7784](https://github.com/angular/angular.js/issues/7784), [#7801](https://github.com/angular/angular.js/issues/7801), [#7894](https://github.com/angular/angular.js/issues/7894))
|
||||
- **$http:**
|
||||
- don't remove content-type header if data is set by request transform
|
||||
([c7c363cf](https://github.com/angular/angular.js/commit/c7c363cf8d4533f94c5534c83dd1c7135633ddd8),
|
||||
[#7910](https://github.com/angular/angular.js/issues/7910))
|
||||
- add ability to remove default headers
|
||||
([172a4093](https://github.com/angular/angular.js/commit/172a40931be5fe47e7732e5ba173895a1d59c5cd),
|
||||
[#5784](https://github.com/angular/angular.js/issues/5784))
|
||||
- **$location:** remove query args when passed in object
|
||||
([2c7d0857](https://github.com/angular/angular.js/commit/2c7d0857ccbdb3a0967acc20e4346a7e1a6be792),
|
||||
[#6565](https://github.com/angular/angular.js/issues/6565))
|
||||
- **input:**
|
||||
- escape forward slash in email regexp
|
||||
([a88c215f](https://github.com/angular/angular.js/commit/a88c215f17829c1cfdec36bc1ef40bae10c41dff),
|
||||
[#8096](https://github.com/angular/angular.js/issues/8096))
|
||||
- modify email validation regexp to match rfc1035
|
||||
([af6f943a](https://github.com/angular/angular.js/commit/af6f943a22f26cf2968f0ae3a1fab2fd09b52a2b),
|
||||
[#6026](https://github.com/angular/angular.js/issues/6026))
|
||||
- **jqLite:**
|
||||
- correctly dealoc svg elements in IE
|
||||
([012ab1f8](https://github.com/angular/angular.js/commit/012ab1f8745c8985d3f132c2dfa8fd84e7dc7041))
|
||||
- remove exposed dealoc method
|
||||
([9c5b407f](https://github.com/angular/angular.js/commit/9c5b407fd1e296dd525c129743f2b2b47da4dc0d))
|
||||
- **ngModel:** test & update correct model when running $validate
|
||||
([f3cb2741](https://github.com/angular/angular.js/commit/f3cb2741161353f387d02725637ce4ba062a9bc0),
|
||||
[#7836](https://github.com/angular/angular.js/issues/7836), [#7837](https://github.com/angular/angular.js/issues/7837))
|
||||
- **parseKeyValue:** ignore properties in prototype chain
|
||||
([cb42766a](https://github.com/angular/angular.js/commit/cb42766a14f8123aa288b6e20f879141970fb84d),
|
||||
[#8070](https://github.com/angular/angular.js/issues/8070), [#8068](https://github.com/angular/angular.js/issues/8068))
|
||||
- **select:** auto-select new option that is marked as selected
|
||||
([b8ae73e1](https://github.com/angular/angular.js/commit/b8ae73e17c19d9aebf572a75c05a7d981dcac807),
|
||||
[#6828](https://github.com/angular/angular.js/issues/6828))
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
- **$animate:** allow directives to cancel animation events
|
||||
([ca752790](https://github.com/angular/angular.js/commit/ca752790d95480b7ad1125a7ddb52b726b987a24),
|
||||
[#7722](https://github.com/angular/angular.js/issues/7722))
|
||||
- **$controller:** disable using global controller constructors
|
||||
([3f2232b5](https://github.com/angular/angular.js/commit/3f2232b5a181512fac23775b1df4a6ebda67d018))
|
||||
- **FormController:** add `$rollbackViewValue` to rollback all controls
|
||||
([85b77314](https://github.com/angular/angular.js/commit/85b77314ed8e4b45d7365a24a47349ed94672aeb),
|
||||
[#7595](https://github.com/angular/angular.js/issues/7595))
|
||||
- **input:** support constant expressions for ngTrueValue/ngFalseValue
|
||||
([c90cefe1](https://github.com/angular/angular.js/commit/c90cefe16142d973a123e945fc9058e8a874c357),
|
||||
[#8041](https://github.com/angular/angular.js/issues/8041), [#5346](https://github.com/angular/angular.js/issues/5346), [#1199](https://github.com/angular/angular.js/issues/1199))
|
||||
- **ngAnimate:** conditionally allow child animations to run in parallel with parent animations
|
||||
([8252b8be](https://github.com/angular/angular.js/commit/8252b8be946367f1759065adf528adc908da00a2),
|
||||
[#7946](https://github.com/angular/angular.js/issues/7946))
|
||||
- **ngModel:** bind to getters/setters
|
||||
([b9fcf017](https://github.com/angular/angular.js/commit/b9fcf017316d37e91959949f56692644ce09d54a),
|
||||
[#768](https://github.com/angular/angular.js/issues/768))
|
||||
|
||||
|
||||
## Performance Improvements
|
||||
|
||||
- **$compile:** no longer need nodeType filter when setting $scope data
|
||||
([b0ca5195](https://github.com/angular/angular.js/commit/b0ca5195e88a42611e933c49d7d2768b181b2d1b),
|
||||
[#7887](https://github.com/angular/angular.js/issues/7887))
|
||||
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
- **$controller:** due to [3f2232b5](https://github.com/angular/angular.js/commit/3f2232b5a181512fac23775b1df4a6ebda67d018),
|
||||
|
||||
`$controller` will no longer look for controllers on `window`.
|
||||
The old behavior of looking on `window` for controllers was originally intended
|
||||
for use in examples, demos, and toy apps. We found that allowing global controller
|
||||
functions encouraged poor practices, so we resolved to disable this behavior by
|
||||
default.
|
||||
|
||||
To migrate, register your controllers with modules rather than exposing them
|
||||
as globals:
|
||||
|
||||
Before:
|
||||
|
||||
```javascript
|
||||
function MyController() {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
After:
|
||||
|
||||
```javascript
|
||||
angular.module('myApp', []).controller('MyController', [function() {
|
||||
// ...
|
||||
}]);
|
||||
```
|
||||
|
||||
Although it's not recommended, you can re-enable the old behavior like this:
|
||||
|
||||
```javascript
|
||||
angular.module('myModule').config(['$controllerProvider', function($controllerProvider) {
|
||||
// this option might be handy for migrating old apps, but please don't use it
|
||||
// in new ones!
|
||||
$controllerProvider.allowGlobals();
|
||||
}]);
|
||||
```
|
||||
- **input:** due to [c90cefe1](https://github.com/angular/angular.js/commit/c90cefe16142d973a123e945fc9058e8a874c357),
|
||||
|
||||
|
||||
Previously, these attributes would always be treated as strings. However, they are now parsed as
|
||||
expressions, and will throw if an expression is non-constant.
|
||||
|
||||
To convert non-constant strings into constant expressions, simply wrap them in an extra pair of quotes, like so:
|
||||
|
||||
<input type="checkbox" ng-model="..." ng-true-value="'truthyValue'">
|
||||
|
||||
Closes #8041
|
||||
Closes #5346
|
||||
Closes #1199
|
||||
|
||||
<a name="1.2.20"></a>
|
||||
# 1.2.20 accidental-beautification (2014-07-11)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$http:**
|
||||
- don't remove content-type header if data is set by request transform
|
||||
([7027844d](https://github.com/angular/angular.js/commit/7027844d42cd428cb799f38f9e9b303da013ac4f),
|
||||
[#7910](https://github.com/angular/angular.js/issues/7910))
|
||||
- add ability to remove default headers
|
||||
([172a4093](https://github.com/angular/angular.js/commit/172a40931be5fe47e7732e5ba173895a1d59c5cd),
|
||||
[#5784](https://github.com/angular/angular.js/issues/5784))
|
||||
- **$location:** remove query args when passed in object
|
||||
([a26acb64](https://github.com/angular/angular.js/commit/a26acb64fe2ed3e05bf21ac1c058d6ac59b89870),
|
||||
[#6565](https://github.com/angular/angular.js/issues/6565))
|
||||
- **input:**
|
||||
- escape forward slash in email regexp
|
||||
([da0e3c99](https://github.com/angular/angular.js/commit/da0e3c99f51c196f58758841d4d8492a9fa09e20),
|
||||
[#8096](https://github.com/angular/angular.js/issues/8096))
|
||||
- modify email validation regexp to match rfc1035
|
||||
([816b8423](https://github.com/angular/angular.js/commit/816b84230cdd8273ba19e8dec3b6f2e800f76612),
|
||||
[#6026](https://github.com/angular/angular.js/issues/6026))
|
||||
- **parseKeyValue:** ignore properties in prototype chain
|
||||
([873acf8f](https://github.com/angular/angular.js/commit/873acf8fab3eb41914920259e713e1916e3c4f38),
|
||||
[#8070](https://github.com/angular/angular.js/issues/8070), [#8068](https://github.com/angular/angular.js/issues/8068))
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
- **ngAnimate:** conditionally allow child animations to run in parallel with parent animations
|
||||
([931789ec](https://github.com/angular/angular.js/commit/931789ec1476e1d06739e63cb423eb87172b5ebc),
|
||||
[#7946](https://github.com/angular/angular.js/issues/7946))
|
||||
|
||||
|
||||
<a name="1.3.0-beta.14"></a>
|
||||
# 1.3.0-beta.14 harmonious-cacophonies (2014-06-30)
|
||||
|
||||
|
||||
This release contains security fixes for $parse that prevent arbitrary code execution via Angular
|
||||
expressions under some very specific conditions. The only applications affected by these
|
||||
vulnerabilities are those that match all of the following conditions:
|
||||
|
||||
- application mixes server-side and client-side templating
|
||||
- the server-side templating contains XSS vulnerabilities
|
||||
- the vulnerabilities in the server-side templating are being guarded by server-side XSS filters or
|
||||
on the client-side via [CSP](http://en.wikipedia.org/wiki/Content_Security_Policy)
|
||||
- the server-side XSS vulnerabilities can be used to augment the client-side template processed by
|
||||
Angular
|
||||
|
||||
Applications not meeting all of the conditions are not vulnerable.
|
||||
|
||||
This fix is in both 1.3.0-beta.14 and 1.2.19 release.
|
||||
|
||||
The Angular team would like to thank [Jann Horn](http://thejh.net) for reporting these
|
||||
vulnerabilities via [security@angularjs.org].
|
||||
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$compile:** bind ng-attr-* even if unbound attribute follows ng-attr-*
|
||||
([8b0258d8](https://github.com/angular/angular.js/commit/8b0258d878cac20cd25c0958fd6e136a08b97df6),
|
||||
[#7739](https://github.com/angular/angular.js/issues/7739))
|
||||
- **$http:**
|
||||
- should not read statusText on IE<10 when request is aborted
|
||||
([31ae3e71](https://github.com/angular/angular.js/commit/31ae3e71647eadbbe1df40f9dedb55e1e0715f98))
|
||||
- add the PATCH shortcut back
|
||||
([b28b5caa](https://github.com/angular/angular.js/commit/b28b5caab1529b3970f10f0a4de43c0c975e3886),
|
||||
[#5894](https://github.com/angular/angular.js/issues/5894))
|
||||
- **$injector:** check if a fn is an array explicitly
|
||||
([b1a6baac](https://github.com/angular/angular.js/commit/b1a6baac2de84a1ecdc000085e8bbd016eb5c100),
|
||||
[#7904](https://github.com/angular/angular.js/issues/7904), [#2653](https://github.com/angular/angular.js/issues/2653))
|
||||
- **$interval:** when canceling, use clearInterval from $window instead of global scope.
|
||||
([a4904c0f](https://github.com/angular/angular.js/commit/a4904c0f83838222b98a875c56779a7f1a4a650a))
|
||||
- **$parse:**
|
||||
- prevent invocation of Function's bind, call and apply
|
||||
([77ada4c8](https://github.com/angular/angular.js/commit/77ada4c82d6b8fc6d977c26f3cdb48c2f5fbe5a5))
|
||||
- forbid __proto__ properties in angular expressions
|
||||
([6081f207](https://github.com/angular/angular.js/commit/6081f20769e64a800ee8075c168412b21f026d99))
|
||||
- forbid __{define,lookup}{Getter,Setter}__ properties
|
||||
([48fa3aad](https://github.com/angular/angular.js/commit/48fa3aadd546036c7e69f71046f659ab1de244c6))
|
||||
- forbid referencing Object in angular expressions
|
||||
([528be29d](https://github.com/angular/angular.js/commit/528be29d1662122a34e204dd607e1c0bd9c16bbc))
|
||||
- handle constants as one-time binding expressions
|
||||
([d9763f1b](https://github.com/angular/angular.js/commit/d9763f1bd355190b9d4e5723e4632cbc232f0543),
|
||||
[#7970](https://github.com/angular/angular.js/issues/7970))
|
||||
- **$timeout/$interval:** if invokeApply is false, do not use evalAsync
|
||||
([19b6b343](https://github.com/angular/angular.js/commit/19b6b3433ae9f8523cbc72ae97dbcf0c06960148),
|
||||
[#7999](https://github.com/angular/angular.js/issues/7999), [#7103](https://github.com/angular/angular.js/issues/7103))
|
||||
- **Angular:** nodeName should always be lowercase
|
||||
([dafb8a3c](https://github.com/angular/angular.js/commit/dafb8a3cd12e7c3247838f536c25eb796331658d),
|
||||
[#3987](https://github.com/angular/angular.js/issues/3987))
|
||||
- **Angular.copy:** preserve prototype chain when copying objects
|
||||
([b59b04f9](https://github.com/angular/angular.js/commit/b59b04f98a0b59eead53f6a53391ce1bbcbe9b57),
|
||||
[#5063](https://github.com/angular/angular.js/issues/5063), [#3767](https://github.com/angular/angular.js/issues/3767), [#4996](https://github.com/angular/angular.js/issues/4996))
|
||||
- **core:** drop the toBoolean function
|
||||
([bdfc9c02](https://github.com/angular/angular.js/commit/bdfc9c02d021e08babfbc966a007c71b4946d69d),
|
||||
[#3969](https://github.com/angular/angular.js/issues/3969), [#4277](https://github.com/angular/angular.js/issues/4277), [#7960](https://github.com/angular/angular.js/issues/7960))
|
||||
- **injector:** allow multiple loading of function modules
|
||||
([2f0a4488](https://github.com/angular/angular.js/commit/2f0a4488731fdb0e8217325dbb52a576defd09bd),
|
||||
[#7255](https://github.com/angular/angular.js/issues/7255))
|
||||
- **input:**
|
||||
- improve html5 validation support
|
||||
([1f6a5a1a](https://github.com/angular/angular.js/commit/1f6a5a1a9255a2db19a1ea4c04cdbcdbb2850b6c),
|
||||
[#7936](https://github.com/angular/angular.js/issues/7936), [#7937](https://github.com/angular/angular.js/issues/7937))
|
||||
- escape forward slash in email regexp
|
||||
([b775e2bc](https://github.com/angular/angular.js/commit/b775e2bca1093e9df62a269b5bda968555ea0ded),
|
||||
[#7938](https://github.com/angular/angular.js/issues/7938))
|
||||
- **jqLite:**
|
||||
- never add to the cache for non-element/document nodes
|
||||
([91754a76](https://github.com/angular/angular.js/commit/91754a76e0ef9a7456a5b9819d1c5807c0a575bb),
|
||||
[#7966](https://github.com/angular/angular.js/issues/7966))
|
||||
- don't attach event handlers to comments or text nodes
|
||||
([462dbb20](https://github.com/angular/angular.js/commit/462dbb2016a218d84760b6da171f1b15c9e416c3),
|
||||
[#7913](https://github.com/angular/angular.js/issues/7913), [#7942](https://github.com/angular/angular.js/issues/7942))
|
||||
- convert NodeList to an Array to make PhantomJS 1.x happy
|
||||
([ceaea861](https://github.com/angular/angular.js/commit/ceaea861ebec957c99bbca6fd88ed33fbc15afbf),
|
||||
[#7851](https://github.com/angular/angular.js/issues/7851))
|
||||
- **numberFilter:** correctly round fractions despite floating-point arithmetics issues in JS
|
||||
([189cd064](https://github.com/angular/angular.js/commit/189cd064feeb710fe54ee2ca83449b3eaf82b403),
|
||||
[#7870](https://github.com/angular/angular.js/issues/7870), [#7878](https://github.com/angular/angular.js/issues/7878))
|
||||
- **testabilityPatch:** fix invocations of angular.mock.dump
|
||||
([e8e07502](https://github.com/angular/angular.js/commit/e8e07502776e48bf48b83a836f7422d164cbb1d7))
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
- **NgModel:**
|
||||
- port the email input type to use the validators pipeline
|
||||
([67379242](https://github.com/angular/angular.js/commit/6737924210570e8369ab72415e3098c6df4d3f6b))
|
||||
- port the URL input type to use the validators pipeline
|
||||
([3ee65730](https://github.com/angular/angular.js/commit/3ee65730639fc61d76e1055a6ca74e35eb48b838))
|
||||
- **jqLite:** support isDefaultPrevented for triggerHandler dummies
|
||||
([7e71acd1](https://github.com/angular/angular.js/commit/7e71acd1781ed44a7306d94338388c90f4420a24),
|
||||
[#8008](https://github.com/angular/angular.js/issues/8008))
|
||||
|
||||
|
||||
## Performance Improvements
|
||||
|
||||
- **forEach:** use native for loop instead of forEach for Arrays
|
||||
([36625de0](https://github.com/angular/angular.js/commit/36625de0d3ebc1fc091af474d942c6ce16b0a1c0))
|
||||
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
- **$parse:**
|
||||
- due to [77ada4c8](https://github.com/angular/angular.js/commit/77ada4c82d6b8fc6d977c26f3cdb48c2f5fbe5a5),
|
||||
|
||||
You can no longer invoke .bind, .call or .apply on a function in angular expressions.
|
||||
This is to disallow changing the behaviour of existing functions
|
||||
in an unforseen fashion.
|
||||
- due to [6081f207](https://github.com/angular/angular.js/commit/6081f20769e64a800ee8075c168412b21f026d99),
|
||||
|
||||
The (deprecated) __proto__ propery does not work inside angular expressions
|
||||
anymore.
|
||||
- due to [48fa3aad](https://github.com/angular/angular.js/commit/48fa3aadd546036c7e69f71046f659ab1de244c6),
|
||||
|
||||
This prevents the use of __{define,lookup}{Getter,Setter}__ inside angular
|
||||
expressions. If you really need them for some reason, please wrap/bind them to make them
|
||||
less dangerous, then make them available through the scope object.
|
||||
- due to [528be29d](https://github.com/angular/angular.js/commit/528be29d1662122a34e204dd607e1c0bd9c16bbc),
|
||||
|
||||
This prevents the use of `Object` inside angular expressions.
|
||||
If you need Object.keys, make it accessible in the scope.
|
||||
- **Angular.copy:** due to [b59b04f9](https://github.com/angular/angular.js/commit/b59b04f98a0b59eead53f6a53391ce1bbcbe9b57),
|
||||
|
||||
|
||||
This changes `angular.copy` so that it applies the prototype of the original
|
||||
object to the copied object. Previously, `angular.copy` would copy properties
|
||||
of the original object's prototype chain directly onto the copied object.
|
||||
|
||||
This means that if you iterate over only the copied object's `hasOwnProperty`
|
||||
properties, it will no longer contain the properties from the prototype.
|
||||
This is actually much more reasonable behaviour and it is unlikely that
|
||||
applications are actually relying on this.
|
||||
|
||||
If this behaviour is relied upon, in an app, then one should simply iterate
|
||||
over all the properties on the object (and its inherited properties) and
|
||||
not filter them with `hasOwnProperty`.
|
||||
|
||||
**Be aware that this change also uses a feature that is not compatible with
|
||||
IE8.** If you need this to work on IE8 then you would need to provide a polyfill
|
||||
for `Object.create` and `Object.getPrototypeOf`.
|
||||
- **core:** due to [bdfc9c02](https://github.com/angular/angular.js/commit/bdfc9c02d021e08babfbc966a007c71b4946d69d),
|
||||
values 'f', '0', 'false', 'no', 'n', '[]' are no longer
|
||||
treated as falsy. Only JavaScript falsy values are now treated as falsy by the
|
||||
expression parser; there are six of them: false, null, undefined, NaN, 0 and "".
|
||||
|
||||
Closes #3969
|
||||
Closes #4277
|
||||
Closes #7960
|
||||
|
||||
- **$timeout/$interval:**
|
||||
- due to [19b6b343](https://github.com/angular/angular.js/commit/19b6b3433ae9f8523cbc72ae97dbcf0c06960148)
|
||||
|
||||
|
||||
Previously, even if invokeApply was set to false, a $rootScope digest would occur during promise
|
||||
resolution. This is no longer the case, as promises returned from $timeout and $interval will no
|
||||
longer trigger $evalAsync (which in turn causes a $digest) if `invokeApply` is false.
|
||||
|
||||
Workarounds include manually triggering $scope.$apply(), or returning $q.defer().promise from a
|
||||
promise callback, and resolving or rejecting it when appropriate.
|
||||
|
||||
var interval = $interval(function() {
|
||||
if (someRequirementFulfilled) {
|
||||
$interval.cancel(interval);
|
||||
$scope.$apply();
|
||||
}
|
||||
}, 100, 0, false);
|
||||
|
||||
or:
|
||||
|
||||
var interval = $interval(function (idx) {
|
||||
// make the magic happen
|
||||
}, 1000, 10, false);
|
||||
interval.then(function(idx) {
|
||||
var deferred = $q.defer();
|
||||
// do the asynchronous magic --- $evalAsync will cause a digest and cause
|
||||
// bindings to update.
|
||||
return deferred.promise;
|
||||
});
|
||||
|
||||
<a name="1.2.19"></a>
|
||||
# 1.2.19 precognitive-flashbacks (2014-06-30)
|
||||
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$compile:** bind ng-attr-* even if unbound attribute follows ng-attr-*
|
||||
([ed59370d](https://github.com/angular/angular.js/commit/ed59370d805a88c9ac012a8e417faf2a9f902776))
|
||||
- **$http:** should not read statusText on IE<10 when request is aborted
|
||||
([0c80df21](https://github.com/angular/angular.js/commit/0c80df21b66f4b147b6b55c27ad794be5802b411))
|
||||
- **$injector:** check if a fn is an array explicitly
|
||||
([67c11b9a](https://github.com/angular/angular.js/commit/67c11b9a3914a24aaf72f36bbe038ba5efa7ddf3),
|
||||
[#7904](https://github.com/angular/angular.js/issues/7904), [#2653](https://github.com/angular/angular.js/issues/2653))
|
||||
- **$interval:** when canceling, use clearInterval from $window instead of global scope.
|
||||
([f780ccfa](https://github.com/angular/angular.js/commit/f780ccfa1c9a8d4c6191b0756ff77dc5749cf8c5))
|
||||
- **$parse:**
|
||||
- make the window check in ensureSafeObject IE8 friendly
|
||||
([ba62e975](https://github.com/angular/angular.js/commit/ba62e975f1a0cebf08dedbb1501f72b166af66db))
|
||||
- prevent invocation of Function's bind, call and apply
|
||||
([07fa87a8](https://github.com/angular/angular.js/commit/07fa87a8a82b8be155d8c898bb79e5d9277adfb4))
|
||||
- forbid __proto__ properties in angular expressions
|
||||
([cb713e60](https://github.com/angular/angular.js/commit/cb713e6045413a25b54ad3267476fa29efd70646))
|
||||
- forbid __{define,lookup}{Getter,Setter}__ properties
|
||||
([89ca8597](https://github.com/angular/angular.js/commit/89ca8597341aa5585bcf728fa677022b7ec9c071))
|
||||
- forbid referencing Object in angular expressions
|
||||
([bc6fb7cc](https://github.com/angular/angular.js/commit/bc6fb7cc94afddcb11b94f74d13812a6be1cdb64))
|
||||
- **injector:** allow multiple loading of function modules
|
||||
([d71f16e7](https://github.com/angular/angular.js/commit/d71f16e7459f1d3705ccf47a13227d4727be9670),
|
||||
[#7255](https://github.com/angular/angular.js/issues/7255))
|
||||
- **input:**
|
||||
- improve html5 validation support
|
||||
([ab2e83c8](https://github.com/angular/angular.js/commit/ab2e83c8c8fa60ca15b1a9539a6587dc363b20f1),
|
||||
[#7937](https://github.com/angular/angular.js/issues/7937), [#7957](https://github.com/angular/angular.js/issues/7957))
|
||||
- escape forward slash in email regexp
|
||||
([2a45cea0](https://github.com/angular/angular.js/commit/2a45cea0baaf615b799b54897bfe40d32381e7a2),
|
||||
[#7938](https://github.com/angular/angular.js/issues/7938))
|
||||
- **jqLite:** change expando property to a more unique name
|
||||
([74e1cc68](https://github.com/angular/angular.js/commit/74e1cc683be315f6db05e22e185b3d27460d132a))
|
||||
- **numberFilter:** correctly round fractions despite floating-point arithmetics issues in JS
|
||||
([e5f454c8](https://github.com/angular/angular.js/commit/e5f454c8afc15336dc1faa52704a483cedfacd4a),
|
||||
[#7870](https://github.com/angular/angular.js/issues/7870), [#7878](https://github.com/angular/angular.js/issues/7878))
|
||||
- **testabilityPatch:** fix invocations of angular.mock.dump
|
||||
([5e944a1c](https://github.com/angular/angular.js/commit/5e944a1cf1356bd069d3616f24323a0cb3ace87c))
|
||||
|
||||
|
||||
## Performance Improvements
|
||||
|
||||
- **jqLite:** don't use reflection to access expandoId
|
||||
([a4faa5cd](https://github.com/angular/angular.js/commit/a4faa5cde722556bd41d75daf346c63a9b6962e9))
|
||||
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
- **$parse:**
|
||||
- due to [07fa87a8](https://github.com/angular/angular.js/commit/07fa87a8a82b8be155d8c898bb79e5d9277adfb4),
|
||||
|
||||
You can no longer invoke .bind, .call or .apply on a function in angular expressions.
|
||||
This is to disallow changing the behaviour of existing functions
|
||||
in an unforseen fashion.
|
||||
- due to [cb713e60](https://github.com/angular/angular.js/commit/cb713e6045413a25b54ad3267476fa29efd70646),
|
||||
|
||||
The (deprecated) __proto__ propery does not work inside angular expressions
|
||||
anymore.
|
||||
- due to [89ca8597](https://github.com/angular/angular.js/commit/89ca8597341aa5585bcf728fa677022b7ec9c071),
|
||||
|
||||
This prevents the use of __{define,lookup}{Getter,Setter}__ inside angular
|
||||
expressions. If you really need them for some reason, please wrap/bind them to make them
|
||||
less dangerous, then make them available through the scope object.
|
||||
- due to [bc6fb7cc](https://github.com/angular/angular.js/commit/bc6fb7cc94afddcb11b94f74d13812a6be1cdb64),
|
||||
|
||||
This prevents the use of `Object` inside angular expressions.
|
||||
If you need Object.keys, make it accessible in the scope.
|
||||
|
||||
<a name="1.3.0-beta.13"></a>
|
||||
# 1.3.0-beta.13 idiosyncratic-numerification (2014-06-16)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **jqLite:** change expando property to a more unique name
|
||||
([20c3c9e2](https://github.com/angular/angular.js/commit/20c3c9e25f6417773333727549ed2ca2d3505b44))
|
||||
|
||||
|
||||
|
||||
<a name="1.3.0-beta.12"></a>
|
||||
# 1.3.0-beta.12 ephemeral-acceleration (2014-06-13)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$compile:**
|
||||
- ensure transclude works at root of templateUrl
|
||||
([398053c5](https://github.com/angular/angular.js/commit/398053c56352487751d14ea41b3b892960397019),
|
||||
[#7183](https://github.com/angular/angular.js/issues/7183), [#7772](https://github.com/angular/angular.js/issues/7772))
|
||||
- always error if two directives add isolate-scope and new-scope
|
||||
([2cde927e](https://github.com/angular/angular.js/commit/2cde927e58c8d1588569d94a797e43cdfbcedaf9),
|
||||
[#4402](https://github.com/angular/angular.js/issues/4402), [#4421](https://github.com/angular/angular.js/issues/4421))
|
||||
- **$injector:** report circularity in circular dependency error message
|
||||
([545d22b4](https://github.com/angular/angular.js/commit/545d22b47006c1efa420ba551d4850affdba8016),
|
||||
[#7500](https://github.com/angular/angular.js/issues/7500))
|
||||
- **$parse:** Handle one-time to `null`
|
||||
([600a41a7](https://github.com/angular/angular.js/commit/600a41a7b65f2dd139664fca6331c40451db75be),
|
||||
[#7743](https://github.com/angular/angular.js/issues/7743), [#7787](https://github.com/angular/angular.js/issues/7787))
|
||||
- **NgModel:**
|
||||
- ensure pattern and ngPattern use the same validator
|
||||
([1be9bb9d](https://github.com/angular/angular.js/commit/1be9bb9d3527e0758350c4f7417a4228d8571440))
|
||||
- make ngMinlength and ngMaxlength as standalone directives
|
||||
([26d91b65](https://github.com/angular/angular.js/commit/26d91b653ac224d9d4166fea855346f5e4c4a7b4),
|
||||
[#6750](https://github.com/angular/angular.js/issues/6750))
|
||||
- make sure the ngMinlength and ngMaxlength validators use the $validators pipeline
|
||||
([5b8e7ecf](https://github.com/angular/angular.js/commit/5b8e7ecfeb722cfc7a5d92f05b57950a2aa6158b),
|
||||
[#6304](https://github.com/angular/angular.js/issues/6304))
|
||||
- make sure the pattern validator uses the $validators pipeline
|
||||
([e63d4253](https://github.com/angular/angular.js/commit/e63d4253d06ed7d344358e2c0b03311c548bc978))
|
||||
- make sure the required validator uses the $validators pipeline
|
||||
([e53554a0](https://github.com/angular/angular.js/commit/e53554a0e238cba7a150fd7ccf61e5e4cc0c0426),
|
||||
[#5164](https://github.com/angular/angular.js/issues/5164))
|
||||
- **jqLite:** data should store data only on Element and Document nodes
|
||||
([a196c8bc](https://github.com/angular/angular.js/commit/a196c8bca82a28c08896d31f1863cf4ecd11401c))
|
||||
- **ngResource:** don't convert literal values into Resource objects when isArray is true
|
||||
([16dfcb61](https://github.com/angular/angular.js/commit/16dfcb61aed28cdef3bfbed540e2deea6d9e9632),
|
||||
[#6314](https://github.com/angular/angular.js/issues/6314), [#7741](https://github.com/angular/angular.js/issues/7741))
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
- **NgModel:** introduce the $validators pipeline
|
||||
([a8c7cb81](https://github.com/angular/angular.js/commit/a8c7cb81c9e67b52d5c649bf3d8cec06c5976852))
|
||||
- **attrs:** trigger observers for specific ng-attributes
|
||||
([d9b90d7c](https://github.com/angular/angular.js/commit/d9b90d7c10a8e1bacbee0aeb7e86093cca9e8ed2),
|
||||
[#7758](https://github.com/angular/angular.js/issues/7758))
|
||||
- **input:** add $touched and $untouched states
|
||||
([adcc5a00](https://github.com/angular/angular.js/commit/adcc5a00bf582d2b291c18e99093bb0854f7217c))
|
||||
- **ngInclude:** emit $includeContentError when HTTP request fails
|
||||
([e4419daf](https://github.com/angular/angular.js/commit/e4419daf705d6d2d116ced573f72c24b5c53be1f),
|
||||
[#5803](https://github.com/angular/angular.js/issues/5803))
|
||||
|
||||
|
||||
## Performance Improvements
|
||||
|
||||
- **$compile:** move ng-binding class stamping for interpolation into compile phase
|
||||
([35358fdd](https://github.com/angular/angular.js/commit/35358fddc10652ef78c72cba7b7c2d5a810631d5))
|
||||
- **$http:** move xsrf cookie check to after cache check in $http
|
||||
([dd1d189e](https://github.com/angular/angular.js/commit/dd1d189ee785a37fe1d9bddf3818152db6aa210a),
|
||||
[#7717](https://github.com/angular/angular.js/issues/7717))
|
||||
- **Scope:** change Scope#id to be a simple number
|
||||
([8c6a8171](https://github.com/angular/angular.js/commit/8c6a8171f9bdaa5cdabc0cc3f7d3ce10af7b434d))
|
||||
- **forEach:** cache array length
|
||||
([55991e33](https://github.com/angular/angular.js/commit/55991e33af6fece07ea347a059da061b76fc95f5))
|
||||
- **isArray:** use native Array.isArray
|
||||
([751ebc17](https://github.com/angular/angular.js/commit/751ebc17f7fc7be26613db0a3cdee05fc401318b),
|
||||
[#7735](https://github.com/angular/angular.js/issues/7735))
|
||||
- **isWindow** optimize internal isWindow call
|
||||
([b68ac4cb](https://github.com/angular/angular.js/commit/b68ac4cb4c172447ba0022fe6e7ce0ca4cb9407e))
|
||||
- **jqLite:**
|
||||
- cache collection length for all methods that work on a single element
|
||||
([41d2eba5](https://github.com/angular/angular.js/commit/41d2eba5f8322903247280000bfc5e5e8a1c1a3e))
|
||||
- improve performance of jqLite#text
|
||||
([92489886](https://github.com/angular/angular.js/commit/92489886dcce3bca00fe827aeb0817297b8a175c))
|
||||
- optimize adding nodes to a jqLite collection
|
||||
([31faeaa7](https://github.com/angular/angular.js/commit/31faeaa7293716251ed437fa54432bb89d9d48de))
|
||||
- optimize element dealocation
|
||||
([e35abc9d](https://github.com/angular/angular.js/commit/e35abc9d2fac0471cbe8089dc0e33a72b8029ada))
|
||||
- don't use reflection to access expandoId
|
||||
([ea9a130a](https://github.com/angular/angular.js/commit/ea9a130a43d165f4f4389d01ac409dd3047efcb4))
|
||||
- **ngBind:** set the ng-binding class during compilation instead of linking
|
||||
([fd5f3896](https://github.com/angular/angular.js/commit/fd5f3896764107635310ae52df1d80a6e08fba31))
|
||||
- **shallowCopy:** use Object.keys to improve performance
|
||||
([04468db4](https://github.com/angular/angular.js/commit/04468db44185e3d7968abdb23d77bf623cb5021b))
|
||||
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
- **$compile:** due to [2cde927e](https://github.com/angular/angular.js/commit/2cde927e58c8d1588569d94a797e43cdfbcedaf9),
|
||||
|
||||
|
||||
Requesting isolate scope and any other scope on a single element is an error.
|
||||
Before this change, the compiler let two directives request a child scope
|
||||
and an isolate scope if the compiler applied them in the order of non-isolate
|
||||
scope directive followed by isolate scope directive.
|
||||
|
||||
Now the compiler will error regardless of the order.
|
||||
|
||||
If you find that your code is now throwing a `$compile:multidir` error,
|
||||
check that you do not have directives on the same element that are trying
|
||||
to request both an isolate and a non-isolate scope and fix your code.
|
||||
|
||||
Closes #4402
|
||||
Closes #4421
|
||||
- **NgModel:** due to [1be9bb9d](https://github.com/angular/angular.js/commit/1be9bb9d3527e0758350c4f7417a4228d8571440),
|
||||
|
||||
|
||||
If an expression is used on ng-pattern (such as `ng-pattern="exp"`) or on the
|
||||
pattern attribute (something like on `pattern="{{ exp }}"`) and the expression
|
||||
itself evaluates to a string then the validator will not parse the string as a
|
||||
literal regular expression object (a value like `/abc/i`). Instead, the entire
|
||||
string will be created as the regular expression to test against. This means
|
||||
that any expression flags will not be placed on the RegExp object. To get around
|
||||
this limitation, use a regular expression object as the value for the expression.
|
||||
|
||||
//before
|
||||
$scope.exp = '/abc/i';
|
||||
|
||||
//after
|
||||
$scope.exp = /abc/i;
|
||||
- **Scope:** due to [8c6a8171](https://github.com/angular/angular.js/commit/8c6a8171f9bdaa5cdabc0cc3f7d3ce10af7b434d),
|
||||
Scope#$id is now of time number rather than string. Since the
|
||||
id is primarily being used for debugging purposes this change should not affect
|
||||
anyone.
|
||||
- **forEach:** due to [55991e33](https://github.com/angular/angular.js/commit/55991e33af6fece07ea347a059da061b76fc95f5),
|
||||
forEach will iterate only over the initial number of items in
|
||||
the array. So if items are added to the array during the iteration, these won't
|
||||
be iterated over during the initial forEach call.
|
||||
|
||||
This change also makes our forEach behave more like Array#forEach.
|
||||
- **jqLite:** due to [a196c8bc](https://github.com/angular/angular.js/commit/a196c8bca82a28c08896d31f1863cf4ecd11401c),
|
||||
previously it was possible to set jqLite data on Text/Comment
|
||||
nodes, but now that is allowed only on Element and Document nodes just like in
|
||||
jQuery. We don't expect that app code actually depends on this accidental feature.
|
||||
|
||||
|
||||
|
||||
<a name="1.2.18"></a>
|
||||
# 1.2.18 ear-extendability (2014-06-13)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$compile:**
|
||||
- ensure transclude works at root of templateUrl
|
||||
([fd420c40](https://github.com/angular/angular.js/commit/fd420c40613d02b3a3f7b14d00a98664518c28f0),
|
||||
[#7183](https://github.com/angular/angular.js/issues/7183), [#7772](https://github.com/angular/angular.js/issues/7772))
|
||||
- bound transclusion to correct scope
|
||||
([1382d4e8](https://github.com/angular/angular.js/commit/1382d4e88ec486b7749e45e6ccc864b3ec388cfe))
|
||||
- don't pass transcludes to non-transclude templateUrl directives
|
||||
([b9ddef2a](https://github.com/angular/angular.js/commit/b9ddef2a495b44cb5fe678b8753de0b7a369244d))
|
||||
- don't pass transclude to template of non-transclude directive
|
||||
([eafba9e2](https://github.com/angular/angular.js/commit/eafba9e2e5ddc668c534e930d83031d2e8dc32b9))
|
||||
- fix nested isolated transclude directives
|
||||
([bb931097](https://github.com/angular/angular.js/commit/bb9310974b6765c2b87e74ee7b8485a6e9c24740),
|
||||
[#1809](https://github.com/angular/angular.js/issues/1809), [#7499](https://github.com/angular/angular.js/issues/7499))
|
||||
- pass transcludeFn down to nested transclude directives
|
||||
([8df5f325](https://github.com/angular/angular.js/commit/8df5f3259aa776f28bf3d869fb1c03e10a897c84),
|
||||
[#7240](https://github.com/angular/angular.js/issues/7240), [#7387](https://github.com/angular/angular.js/issues/7387))
|
||||
- **$injector:** report circularity in circular dependency error message
|
||||
([14e797c1](https://github.com/angular/angular.js/commit/14e797c1a10eabd15bf8e845b62213398bcc0f58),
|
||||
[#7500](https://github.com/angular/angular.js/issues/7500))
|
||||
- **ngResource:** don't convert literal values into Resource objects when isArray is true
|
||||
([f0904cf1](https://github.com/angular/angular.js/commit/f0904cf12e4f01daa2d4fcbb20c762050125ca55),
|
||||
[#6314](https://github.com/angular/angular.js/issues/6314), [#7741](https://github.com/angular/angular.js/issues/7741))
|
||||
|
||||
|
||||
## Performance Improvements
|
||||
|
||||
- **$compile:** move ng-binding class stamping for interpolation into compile phase
|
||||
([81b7e5ab](https://github.com/angular/angular.js/commit/81b7e5ab0ee3fea410b16b09144359ceb99f5191))
|
||||
- **$http:** move xsrf cookie check to after cache check in $http
|
||||
([8b86d363](https://github.com/angular/angular.js/commit/8b86d363aa252c3264201b54b57c3e34f9632d45),
|
||||
[#7717](https://github.com/angular/angular.js/issues/7717))
|
||||
- **isArray:** use native Array.isArray
|
||||
([6c14fb1e](https://github.com/angular/angular.js/commit/6c14fb1eb61dc0a0552fbcb2ca3ace11c9a2f6a5))
|
||||
- **jqLite:** cache collection length for all methods that work on a single element
|
||||
([6d418ef5](https://github.com/angular/angular.js/commit/6d418ef5e3a775577996caf0709f79f447f77025))
|
||||
- **ngBind:** set the ng-binding class during compilation instead of linking
|
||||
([1b189027](https://github.com/angular/angular.js/commit/1b1890274e5a75553ddf9915bb23da48800275f9))
|
||||
|
||||
|
||||
|
||||
<a name="1.2.17"></a>
|
||||
# 1.2.17 - quantum disentanglement (2014-06-06)
|
||||
|
||||
|
||||
+2
-2
@@ -119,7 +119,7 @@ Before you submit your pull request consider the following guidelines:
|
||||
```
|
||||
|
||||
* In GitHub, send a pull request to `angular:master`.
|
||||
* If we suggest changes then
|
||||
* If we suggest changes then
|
||||
* Make the required updates.
|
||||
* Re-run the Angular test suite to ensure tests are still passing.
|
||||
* Rebase your branch and force push to your GitHub repository (this will update your Pull Request):
|
||||
@@ -237,7 +237,7 @@ reference GitHub issues that this commit **Closes**.
|
||||
|
||||
A detailed explanation can be found in this [document][commit-message-format].
|
||||
|
||||
## <a name="cla"></a> Signing the CLA
|
||||
## <a name="cla"></a> Signing the CLA
|
||||
|
||||
Please sign our Contributor License Agreement (CLA) before sending pull requests. For any code
|
||||
changes to be accepted, the CLA must be signed. It's a quick process, we promise!
|
||||
|
||||
+17
-2
@@ -1,3 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
var files = require('./angularFiles').files;
|
||||
var util = require('./lib/grunt/utils.js');
|
||||
var versionInfo = require('./lib/versions/version-info');
|
||||
@@ -107,6 +109,12 @@ module.exports = function(grunt) {
|
||||
options: {
|
||||
jshintrc: true,
|
||||
},
|
||||
node: {
|
||||
files: { src: ['*.js', 'lib/**/*.js'] },
|
||||
},
|
||||
tests: {
|
||||
files: { src: 'test/**/*.js' },
|
||||
},
|
||||
ng: {
|
||||
files: { src: files['angularSrc'] },
|
||||
},
|
||||
@@ -220,8 +228,11 @@ module.exports = function(grunt) {
|
||||
|
||||
"ddescribe-iit": {
|
||||
files: [
|
||||
'src/**/*.js',
|
||||
'test/**/*.js',
|
||||
'!test/ngScenario/DescribeSpec.js'
|
||||
'!test/ngScenario/DescribeSpec.js',
|
||||
'!src/ng/directive/booleanAttrs.js', // legitimate xit here
|
||||
'!src/ngScenario/**/*.js'
|
||||
]
|
||||
},
|
||||
|
||||
@@ -246,7 +257,11 @@ module.exports = function(grunt) {
|
||||
compress: {
|
||||
build: {
|
||||
options: {archive: 'build/' + dist +'.zip', mode: 'zip'},
|
||||
src: ['**'], cwd: 'build', expand: true, dot: true, dest: dist + '/'
|
||||
src: ['**'],
|
||||
cwd: 'build',
|
||||
expand: true,
|
||||
dot: true,
|
||||
dest: dist + '/'
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
+4
-4
@@ -44,11 +44,11 @@ This process based on the idea of minimizing user pain
|
||||
* Label `needs: breaking change` - if needed
|
||||
* Label `needs: public api` - if the issue requires introduction of a new public API
|
||||
1. Label `browser: *` - if the issue **only** affects a certain browser
|
||||
1. Label `frequency: *` – How often does this issue come up? How many developers does this affect?
|
||||
1. Label `frequency: *` – How often does this issue come up? How many developers does this affect? Chose just one of the following:
|
||||
* low - obscure issue affecting a handful of developers
|
||||
* moderate - impacts a common usage pattern
|
||||
* high - impacts most or all Angular apps
|
||||
1. Label `severity: *` - How bad is the issue?
|
||||
1. Label `severity: *` - How bad is the issue? Chose just one of the following:
|
||||
* security issue
|
||||
* regression
|
||||
* memory leak
|
||||
@@ -61,9 +61,9 @@ This process based on the idea of minimizing user pain
|
||||
1. Label `origin: google` for issues from Google
|
||||
|
||||
1. Assign a milestone:
|
||||
* Backlog - triaged fixes and features, should be the default choice
|
||||
* Backlog - triaged fixes and features, should be the default choice
|
||||
* Current 1.x.y milestone (e.g. 1.3.0-beta-2) - regressions and urgent bugs only
|
||||
|
||||
|
||||
|
||||
1. Unassign yourself from the issue
|
||||
|
||||
|
||||
Vendored
+3
-1
@@ -1,4 +1,6 @@
|
||||
angularFiles = {
|
||||
'use strict';
|
||||
|
||||
var angularFiles = {
|
||||
'angularSrc': [
|
||||
'src/minErr.js',
|
||||
'src/Angular.js',
|
||||
|
||||
+4
-2
@@ -3,6 +3,8 @@
|
||||
// TODO(vojta): pre-commit hook for validating messages
|
||||
// TODO(vojta): report errors, currently Q silence everything which really sucks
|
||||
|
||||
'use strict';
|
||||
|
||||
var child = require('child_process');
|
||||
var fs = require('fs');
|
||||
var util = require('util');
|
||||
@@ -164,7 +166,7 @@ var writeChangelog = function(stream, commits, version) {
|
||||
hash: commit.hash,
|
||||
closes: []
|
||||
});
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
stream.write(util.format(HEADER_TPL, version, version, currentDate()));
|
||||
@@ -172,7 +174,7 @@ var writeChangelog = function(stream, commits, version) {
|
||||
printSection(stream, 'Features', sections.feat);
|
||||
printSection(stream, 'Performance Improvements', sections.perf);
|
||||
printSection(stream, 'Breaking Changes', sections.breaks, false);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
var getPreviousTag = function() {
|
||||
|
||||
+5
-1
@@ -1,3 +1,7 @@
|
||||
/* global describe: false, it: false, expect: false */
|
||||
|
||||
'use strict';
|
||||
|
||||
describe('changelog.js', function() {
|
||||
var ch = require('./changelog');
|
||||
|
||||
@@ -13,7 +17,7 @@ describe('changelog.js', function() {
|
||||
expect(msg.hash).toBe('9b1aff905b638aa274a5fc8f88662df446d374bd');
|
||||
expect(msg.subject).toBe('broadcast $destroy event on scope destruction');
|
||||
expect(msg.body).toBe('perf testing shows that in chrome this change adds 5-15% overhead\n' +
|
||||
'when destroying 10k nested scopes where each scope has a $destroy listener\n')
|
||||
'when destroying 10k nested scopes where each scope has a $destroy listener\n');
|
||||
expect(msg.component).toBe('scope');
|
||||
});
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#!/usr/local/bin/node
|
||||
|
||||
'use strict';
|
||||
|
||||
var util = require('util');
|
||||
var cp = require('child_process');
|
||||
|
||||
@@ -143,7 +145,7 @@ then(allInSeries(function (branch) {
|
||||
return sha + (msg.toLowerCase().indexOf('fix') === -1 ? ' ' : ' * ') + msg;
|
||||
});
|
||||
branch.log = log.map(function (line) {
|
||||
return line.substr(41)
|
||||
return line.substr(41);
|
||||
});
|
||||
return branch;
|
||||
});
|
||||
|
||||
@@ -211,6 +211,10 @@ code.highlighted {
|
||||
color:maroon;
|
||||
}
|
||||
|
||||
ul + p {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.docs-version-jump {
|
||||
min-width:100%;
|
||||
max-width:100%;
|
||||
|
||||
@@ -40,7 +40,7 @@ pre.prettyprint.linenums {
|
||||
}
|
||||
ol.linenums {
|
||||
margin: 0 0 0 33px; /* IE indents via margin-left */
|
||||
}
|
||||
}
|
||||
ol.linenums li {
|
||||
padding-left: 12px;
|
||||
font-size:12px;
|
||||
|
||||
+3
-3
@@ -11,7 +11,7 @@ directive.runnableExample = ['$templateCache', '$document', function($templateCa
|
||||
'ng-repeat="tab in tabs track by $index" ' +
|
||||
'href="" ' +
|
||||
'class="btn"' +
|
||||
'ng-click="setTab($index)">' +
|
||||
'ng-click="setTab($index)">' +
|
||||
' {{ tab }}' +
|
||||
' </a>' +
|
||||
'</nav>';
|
||||
@@ -103,7 +103,7 @@ directive.syntax = function() {
|
||||
restrict: 'A',
|
||||
link: function(scope, element, attrs) {
|
||||
function makeLink(type, text, link, icon) {
|
||||
return '<a href="' + link + '" class="btn syntax-' + type + '" target="_blank" rel="nofollow">' +
|
||||
return '<a href="' + link + '" class="btn syntax-' + type + '" target="_blank" rel="nofollow">' +
|
||||
'<span class="' + icon + '"></span> ' + text +
|
||||
'</a>';
|
||||
};
|
||||
@@ -307,7 +307,7 @@ var popoverElement = function() {
|
||||
return this.titleElement.html(value);
|
||||
},
|
||||
|
||||
content : function(value) {
|
||||
content : function(value) {
|
||||
if(value && value.length > 0) {
|
||||
value = marked(value);
|
||||
}
|
||||
|
||||
+1
-1
@@ -20,4 +20,4 @@ angular.module('docsApp', [
|
||||
|
||||
.config(function($locationProvider) {
|
||||
$locationProvider.html5Mode(true).hashPrefix('!');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -59,4 +59,4 @@ angular.module('errors', ['ngSanitize'])
|
||||
element.html(errorLinkFilter(interpolate.apply(null, formatArgs), '_blank'));
|
||||
}
|
||||
};
|
||||
}]);
|
||||
}]);
|
||||
|
||||
@@ -2,7 +2,12 @@ angular.module('examples', [])
|
||||
|
||||
.factory('formPostData', ['$document', function($document) {
|
||||
return function(url, fields) {
|
||||
var form = angular.element('<form style="display: none;" method="post" action="' + url + '" target="_blank"></form>');
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
var form = angular.element('<form style="display: none;" method="post" action="' + url + '"></form>');
|
||||
angular.forEach(fields, function(value, name) {
|
||||
var input = angular.element('<input type="hidden" name="' + name + '">');
|
||||
input.attr('value', value);
|
||||
@@ -69,4 +74,4 @@ angular.module('examples', [])
|
||||
formPostData('http://plnkr.co/edit/?p=preview', postData);
|
||||
});
|
||||
};
|
||||
}]);
|
||||
}]);
|
||||
|
||||
@@ -21,4 +21,4 @@ angular.module('docsApp.navigationService', [])
|
||||
|
||||
}
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,15 +1,31 @@
|
||||
"use strict";
|
||||
|
||||
angular.module('versions', [])
|
||||
|
||||
.controller('DocsVersionsCtrl', ['$scope', '$location', '$window', 'NG_VERSIONS', function($scope, $location, $window, NG_VERSIONS) {
|
||||
$scope.docs_versions = NG_VERSIONS;
|
||||
$scope.docs_version = NG_VERSIONS[0];
|
||||
|
||||
for(var i=0, minor = NaN; i < NG_VERSIONS.length; i++) {
|
||||
var version = NG_VERSIONS[i];
|
||||
// NaN will give false here
|
||||
if (minor <= version.minor) {
|
||||
continue;
|
||||
}
|
||||
version.isLatest = true;
|
||||
minor = version.minor;
|
||||
}
|
||||
|
||||
$scope.docs_versions = NG_VERSIONS;
|
||||
$scope.getGroupName = function(v) {
|
||||
return v.isLatest ? 'Latest' : (v.isStable ? 'Stable' : 'Unstable');
|
||||
};
|
||||
|
||||
$scope.jumpToDocsVersion = function(version) {
|
||||
var currentPagePath = $location.path();
|
||||
|
||||
// TODO: We need to do some munging of the path for different versions of the API...
|
||||
|
||||
|
||||
|
||||
$window.location = version.docsUrl + currentPagePath;
|
||||
};
|
||||
}]);
|
||||
}]);
|
||||
|
||||
@@ -31,4 +31,4 @@ describe("DocsController", function() {
|
||||
expect($window._gaq.pop()).toEqual(['_trackPageview', 'x/y/z']);
|
||||
}));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -9,7 +9,7 @@ module.exports = function(config) {
|
||||
|
||||
config = basePackage(config);
|
||||
config = examplesPackage(config);
|
||||
|
||||
|
||||
config.append('processing.processors', [
|
||||
require('./processors/git-data'),
|
||||
require('./processors/error-docs'),
|
||||
|
||||
@@ -30,4 +30,4 @@ function writeFile(file, content) {
|
||||
return fs.makeTree(fs.directory(file)).then(function() {
|
||||
return fs.write(file, content, 'wb');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,4 +56,4 @@ module.exports = {
|
||||
|
||||
return docs.concat(_.values(errorNamespaces));
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -17,4 +17,4 @@ module.exports = {
|
||||
process: function(extraData, gitData) {
|
||||
extraData.git = gitData;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -85,4 +85,4 @@ module.exports = {
|
||||
});
|
||||
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -35,4 +35,4 @@ module.exports = {
|
||||
|
||||
docs.push(versionDoc);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -14,4 +14,4 @@
|
||||
{$ doc.description | marked $}
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
|
||||
@@ -25,4 +25,4 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
|
||||
@@ -175,7 +175,7 @@
|
||||
<div class="container main-grid main-header-grid">
|
||||
<div class="grid-left">
|
||||
<div ng-controller="DocsVersionsCtrl" class="picker version-picker">
|
||||
<select ng-options="v as ('v' + v.version + (v.isSnapshot ? ' (snapshot)' : '')) group by (v.isStable?'Stable':'Unstable') for v in docs_versions"
|
||||
<select ng-options="v as ('v' + v.version + (v.isSnapshot ? ' (snapshot)' : '')) group by getGroupName(v) for v in docs_versions"
|
||||
ng-model="docs_version"
|
||||
ng-change="jumpToDocsVersion(docs_version)"
|
||||
class="docs-version-jump">
|
||||
|
||||
@@ -4,4 +4,4 @@ describe("{$ doc.description $}", function() {
|
||||
});
|
||||
|
||||
{$ doc.innerTest $}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -24,4 +24,4 @@
|
||||
</div>
|
||||
|
||||
{# Be aware that we need these extra new lines here or marked will not realise that the <div>
|
||||
above is HTML and wrap each line in a <p> - thus breaking the HTML #}
|
||||
above is HTML and wrap each line in a <p> - thus breaking the HTML #}
|
||||
|
||||
@@ -1 +1 @@
|
||||
{% include 'overview.template.html' %}
|
||||
{% include 'overview.template.html' %}
|
||||
|
||||
@@ -23,4 +23,4 @@ When an instance of `MyCtrl` is created, the service `myService` will be created
|
||||
by the `$injector`. `myService` depends on itself, which causes the `$injector`
|
||||
to detect a circular dependency and throw the error.
|
||||
|
||||
For more information, see the {@link guide/di Dependency Injection Guide}.
|
||||
For more information, see the {@link guide/di Dependency Injection Guide}.
|
||||
|
||||
@@ -23,4 +23,4 @@ To avoid the error, always use string literals for dependency injection annotati
|
||||
tokens.
|
||||
|
||||
For an explanation of what injection annotations are and how to use them, refer
|
||||
to the {@link guide/di Dependency Injection Guide}.
|
||||
to the {@link guide/di Dependency Injection Guide}.
|
||||
|
||||
@@ -23,4 +23,4 @@ angular.module("myApp", [])
|
||||
```
|
||||
|
||||
For more information, refer to the {@link auto.$provide#provider
|
||||
$provide.provider} api doc.
|
||||
$provide.provider} api doc.
|
||||
|
||||
@@ -14,7 +14,7 @@ angular.module('myApp', [])
|
||||
}]);
|
||||
```
|
||||
|
||||
The above code will fail with `$injector:unpr` if `myService` is not defined.
|
||||
The above code will fail with `$injector:unpr` if `myService` is not defined.
|
||||
|
||||
Making sure each dependency is defined will fix the problem, as noted below.
|
||||
|
||||
@@ -25,3 +25,33 @@ angular.module('myApp', [])
|
||||
// Do something with myService
|
||||
}]);
|
||||
```
|
||||
|
||||
An unknown provider error can also be caused by accidentally redefining a
|
||||
module using the `angular.module` API, as shown in the following example.
|
||||
|
||||
```
|
||||
angular.module('myModule', [])
|
||||
.service('myCoolService', function () { /* ... */ });
|
||||
|
||||
angular.module('myModule', [])
|
||||
// myModule has already been created! This is not what you want!
|
||||
.directive('myDirective', ['myCoolService', function (myCoolService) {
|
||||
// This directive definition throws unknown provider, because myCoolService
|
||||
// has been destroyed.
|
||||
}]);
|
||||
```
|
||||
|
||||
To fix this problem, make sure you only define each module with the
|
||||
`angular.module(name, [requires])` syntax once across your entire project.
|
||||
Retrieve it for subsequent use with `angular.module(name)`. The fixed example
|
||||
is shown below.
|
||||
|
||||
```
|
||||
angular.module('myModule', [])
|
||||
.service('myCoolService', function () { /* ... */ });
|
||||
|
||||
angular.module('myModule')
|
||||
.directive('myDirective', ['myCoolService', function (myCoolService) {
|
||||
// This directive definition does not throw unknown provider.
|
||||
}]);
|
||||
```
|
||||
@@ -9,4 +9,4 @@ it hard to reason about whether some combination of concatenated values are
|
||||
unsafe to use and could easily lead to XSS.
|
||||
|
||||
For more information about how AngularJS helps keep your app secure, refer to
|
||||
the {@link ng.$sce $sce} API doc.
|
||||
the {@link ng.$sce $sce} API doc.
|
||||
|
||||
@@ -14,3 +14,34 @@ perform this check - it's up to the developer to not expose such sensitive and p
|
||||
directly on the scope chain.
|
||||
|
||||
To resolve this error, avoid access to DOM nodes.
|
||||
|
||||
|
||||
# Event Handlers and Return Values
|
||||
|
||||
The `$parse:isecdom` error also occurs when an event handler invokes a function that returns a DOM
|
||||
node.
|
||||
|
||||
```html
|
||||
<button ng-click="iWillReturnDOM()">click me</button>
|
||||
```
|
||||
|
||||
```js
|
||||
$scope.iWillReturnDOM = function() {
|
||||
return someDomNode;
|
||||
}
|
||||
```
|
||||
|
||||
To fix this issue, avoid returning DOM nodes from event handlers.
|
||||
|
||||
*Note: This error often means that you are accessing DOM from your controllers, which is usually
|
||||
a sign of poor coding style that violates separation of concerns.*
|
||||
|
||||
|
||||
# Implicit Returns in CoffeeScript
|
||||
|
||||
This error can occur more frequently when using CoffeeScript, which has a feature called implicit
|
||||
returns. This language feature returns the last dereferenced object in the function when the
|
||||
function has no explicit return statement.
|
||||
|
||||
The solution in this scenario is to add an explicit return statement. For example `return false` to
|
||||
the function.
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
@ngdoc error
|
||||
@name $parse:isecff
|
||||
@fullName Referencing 'call', 'apply' and 'bind' Disallowed
|
||||
@description
|
||||
|
||||
Occurs when an expression attempts to invoke Function's 'call', 'apply' or 'bind'.
|
||||
|
||||
Angular bans the invocation of 'call', 'apply' and 'bind' from within expressions
|
||||
since access is a known way to modify the behaviour of existing functions.
|
||||
|
||||
To resolve this error, avoid using these methods in expressions.
|
||||
|
||||
Example expression that would result in this error:
|
||||
|
||||
```
|
||||
<div>{{user.sendInfo.call({}, true)}}</div>
|
||||
```
|
||||
@@ -1,18 +1,27 @@
|
||||
@ngdoc error
|
||||
@name $parse:isecfld
|
||||
@fullName Referencing 'constructor' Field in Expression
|
||||
@fullName Referencing Disallowed Field in Expression
|
||||
@description
|
||||
|
||||
Occurs when an expression attempts to access an objects constructor field.
|
||||
Occurs when an expression attempts to access one of the following fields:
|
||||
|
||||
AngularJS bans constructor access from within expressions since constructor
|
||||
access is a known way to execute arbitrary Javascript code.
|
||||
* __proto__
|
||||
* __defineGetter__
|
||||
* __defineSetter__
|
||||
* __lookupGetter__
|
||||
* __lookupSetter__
|
||||
|
||||
To resolve this error, avoid constructor access. As a last resort, alias
|
||||
the constructor and access it through the alias instead.
|
||||
AngularJS bans access to these fields from within expressions since
|
||||
access is a known way to mess with native objects or
|
||||
to execute arbitrary Javascript code.
|
||||
|
||||
Example expression that would result in this error:
|
||||
To resolve this error, avoid using these fields in expressions. As a last resort,
|
||||
alias their value and access them through the alias instead.
|
||||
|
||||
Example expressions that would result in this error:
|
||||
|
||||
```
|
||||
<div>{{user.constructor.name}}</div>
|
||||
<div>{{user.__proto__.hasOwnProperty = $emit}}</div>
|
||||
|
||||
<div>{{user.__defineGetter__('name', noop)}}</div>
|
||||
```
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
@ngdoc error
|
||||
@name $parse:isecobj
|
||||
@fullName Referencing Object Disallowed
|
||||
@description
|
||||
|
||||
Occurs when an expression attempts to access the 'Object' object (Root object in JavaScript).
|
||||
|
||||
Angular bans access to Object from within expressions since access is a known way to modify
|
||||
the behaviour of existing objects.
|
||||
|
||||
To resolve this error, avoid Object access.
|
||||
@@ -5,4 +5,4 @@
|
||||
|
||||
Occurs when you try to use the name `hasOwnProperty` as a name of a parameter.
|
||||
Generally, a name cannot be `hasOwnProperty` because it is used, internally, on a object
|
||||
and allowing such a name would break lookups on this object.
|
||||
and allowing such a name would break lookups on this object.
|
||||
|
||||
@@ -161,7 +161,7 @@ In this second scenario, we are already inside a `$digest` when the ngFocus dire
|
||||
call to `$apply()`, causing this error to be thrown.
|
||||
|
||||
It is possible to workaround this problem by moving the call to set the focus outside of the digest,
|
||||
by using `$timeOut(fn, 0, false)`, where the `false` value tells Angular not to wrap this `fn` in a
|
||||
by using `$timeout(fn, 0, false)`, where the `false` value tells Angular not to wrap this `fn` in a
|
||||
`$apply` block:
|
||||
|
||||
```
|
||||
|
||||
@@ -15,9 +15,9 @@ By default, only URLs that belong to the same origin are trusted. These are urls
|
||||
The {@link ng.directive:ngInclude ngInclude} directive and {@link guide/directive directives} that specify a `templateUrl` require a trusted resource URL.
|
||||
|
||||
To load templates from other domains and/or protocols, either adjust the {@link
|
||||
api/ng.$sceDelegateProvider#resourceUrlWhitelist whitelist}/ {@link
|
||||
api/ng.$sceDelegateProvider#resourceUrlBlacklist blacklist} or wrap the URL with a call to {@link
|
||||
api/ng.$sce#trustAsResourceUrl $sce.trustAsResourceUrl}.
|
||||
ng.$sceDelegateProvider#resourceUrlWhitelist whitelist}/ {@link
|
||||
ng.$sceDelegateProvider#resourceUrlBlacklist blacklist} or wrap the URL with a call to {@link
|
||||
ng.$sce#trustAsResourceUrl $sce.trustAsResourceUrl}.
|
||||
|
||||
**Note**: The browser's [Same Origin
|
||||
Policy](https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest) and
|
||||
|
||||
@@ -5,4 +5,4 @@
|
||||
|
||||
AngularJS often asserts that certain values will be present and truthy using a
|
||||
helper function. If the assertion fails, this error is thrown. To fix this problem,
|
||||
make sure that the value the assertion expects is defined and truthy.
|
||||
make sure that the value the assertion expects is defined and truthy.
|
||||
|
||||
@@ -5,4 +5,4 @@
|
||||
|
||||
Occurs when you try to use the name `hasOwnProperty` in a context where it is not allow.
|
||||
Generally, a name cannot be `hasOwnProperty` because it is used, internally, on a object
|
||||
and allowing such a name would break lookups on this object.
|
||||
and allowing such a name would break lookups on this object.
|
||||
|
||||
@@ -49,4 +49,4 @@ You can also get this error if you accidentally load AngularJS itself more than
|
||||
<script src="angular.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
```
|
||||
|
||||
@@ -7,4 +7,4 @@ This error occurs when attempting to copy an object to itself. Calling {@link
|
||||
api/angular.copy angular.copy} with a `destination` object deletes
|
||||
all of the elements or properties on `destination` before copying to it. Copying
|
||||
an object to itself is not supported. Make sure to check your calls to
|
||||
`angular.copy` and avoid copying objects or arrays to themselves.
|
||||
`angular.copy` and avoid copying objects or arrays to themselves.
|
||||
|
||||
@@ -7,4 +7,4 @@ Copying Window or Scope instances is not supported because of cyclical and self
|
||||
references. Avoid copying windows and scopes, as well as any other cyclical or
|
||||
self-referential structures. Note that trying to deep copy an object containing
|
||||
cyclical references that is neither a window nor a scope will cause infinite
|
||||
recursion and a stack overflow.
|
||||
recursion and a stack overflow.
|
||||
|
||||
+299
-108
@@ -60,7 +60,7 @@ changes to $location are reflected into the browser address bar.
|
||||
|
||||
<tr>
|
||||
<td class="head">aware of docroot/context from which the application is loaded</td>
|
||||
<td>no - window.location.path returns "/docroot/actual/path"</td>
|
||||
<td>no - window.location.pathname returns "/docroot/actual/path"</td>
|
||||
<td>yes - $location.path() returns "/actual/path"</td>
|
||||
</tr>
|
||||
|
||||
@@ -358,118 +358,308 @@ Note that when you type hashbang url into first browser (or vice versa) it doesn
|
||||
redirect to regular / hashbang url, as this conversion happens only during parsing the initial URL
|
||||
= on page reload.
|
||||
|
||||
In this examples we use `<base href="/base/index.html" />`
|
||||
<example>
|
||||
In these examples we use `<base href="/base/index.html" />`
|
||||
|
||||
#### Browser in HTML5 mode
|
||||
<example module="html5-mode" name="location-html5-mode">
|
||||
<file name="index.html">
|
||||
<div id="html5-mode" ng-controller="Html5Cntl">
|
||||
<h3>Browser with History API</h3>
|
||||
<div ng-address-bar browser="html5"></div><br><br>
|
||||
$location.protocol() = {{$location.protocol()}}<br>
|
||||
$location.host() = {{$location.host()}}<br>
|
||||
$location.port() = {{$location.port()}}<br>
|
||||
$location.path() = {{$location.path()}}<br>
|
||||
$location.search() = {{$location.search()}}<br>
|
||||
$location.hash() = {{$location.hash()}}<br>
|
||||
<a href="http://www.example.com/base/first?a=b">/base/first?a=b</a> |
|
||||
<a href="http://www.example.com/base/sec/ond?flag#hash">sec/ond?flag#hash</a> |
|
||||
<a href="/other-base/another?search">external</a>
|
||||
</div>
|
||||
|
||||
<div id="hashbang-mode" ng-controller="HashbangCntl">
|
||||
<h3>Browser without History API</h3>
|
||||
<div ng-address-bar browser="hashbang"></div><br><br>
|
||||
$location.protocol() = {{$location.protocol()}}<br>
|
||||
$location.host() = {{$location.host()}}<br>
|
||||
$location.port() = {{$location.port()}}<br>
|
||||
$location.path() = {{$location.path()}}<br>
|
||||
$location.search() = {{$location.search()}}<br>
|
||||
$location.hash() = {{$location.hash()}}<br>
|
||||
<a href="http://www.example.com/base/first?a=b">/base/first?a=b</a> |
|
||||
<a href="http://www.example.com/base/sec/ond?flag#hash">sec/ond?flag#hash</a> |
|
||||
<a href="/other-base/another?search">external</a>
|
||||
<div ng-controller="LocationController">
|
||||
<div ng-address-bar></div><br><br>
|
||||
<div>
|
||||
$location.protocol() = <span ng-bind="$location.protocol()"></span> <br>
|
||||
$location.host() = <span ng-bind="$location.host()"></span> <br>
|
||||
$location.port() = <span ng-bind="$location.port()"></span> <br>
|
||||
$location.path() = <span ng-bind="$location.path()"></span> <br>
|
||||
$location.search() = <span ng-bind="$location.search()"></span> <br>
|
||||
$location.hash() = <span ng-bind="$location.hash()"></span> <br>
|
||||
</div>
|
||||
<div id="navigation">
|
||||
<a href="http://www.example.com/base/first?a=b">/base/first?a=b</a> |
|
||||
<a href="http://www.example.com/base/sec/ond?flag#hash">sec/ond?flag#hash</a> |
|
||||
<a href="/other-base/another?search">external</a>
|
||||
</div>
|
||||
</div>
|
||||
</file>
|
||||
<file name="app.js">
|
||||
angular.module('html5-mode', ['fake-browser', 'address-bar'])
|
||||
|
||||
<file name="script.js">
|
||||
function FakeBrowser(initUrl, baseHref) {
|
||||
this.onUrlChange = function(fn) {
|
||||
this.urlChange = fn;
|
||||
.constant('initUrl', 'http://www.example.com/base/path?a=b#h')
|
||||
.constant('baseHref', '/base/index.html')
|
||||
.value('$sniffer', { history: true })
|
||||
|
||||
.controller("LocationController", function($scope, $location) {
|
||||
$scope.$location = {};
|
||||
angular.forEach("protocol host port path search hash".split(" "), function(method){
|
||||
$scope.$location[method] = function(){
|
||||
var result = $location[method].call($location);
|
||||
return angular.isObject(result) ? angular.toJson(result) : result;
|
||||
};
|
||||
});
|
||||
})
|
||||
|
||||
.config(function($locationProvider) {
|
||||
$locationProvider.html5Mode(true).hashPrefix('!');
|
||||
})
|
||||
|
||||
.run(function($rootElement) {
|
||||
$rootElement.on('click', function(e) { e.stopPropagation(); });
|
||||
});
|
||||
</file>
|
||||
|
||||
<file name="fakeBrowser.js">
|
||||
angular.module('fake-browser', [])
|
||||
|
||||
.config(function($provide) {
|
||||
$provide.decorator('$browser', function($delegate, baseHref, initUrl) {
|
||||
|
||||
$delegate.onUrlChange = function(fn) {
|
||||
this.urlChange = fn;
|
||||
};
|
||||
|
||||
$delegate.url = function() {
|
||||
return initUrl;
|
||||
};
|
||||
|
||||
this.url = function() {
|
||||
return initUrl;
|
||||
};
|
||||
$delegate.defer = function(fn, delay) {
|
||||
setTimeout(function() { fn(); }, delay || 0);
|
||||
};
|
||||
|
||||
this.defer = function(fn, delay) {
|
||||
setTimeout(function() { fn(); }, delay || 0);
|
||||
};
|
||||
$delegate.baseHref = function() {
|
||||
return baseHref;
|
||||
};
|
||||
|
||||
this.baseHref = function() {
|
||||
return baseHref;
|
||||
};
|
||||
return $delegate;
|
||||
});
|
||||
});
|
||||
</file>
|
||||
|
||||
this.notifyWhenOutstandingRequests = angular.noop;
|
||||
}
|
||||
<file name="addressBar.js">
|
||||
angular.module('address-bar', [])
|
||||
.directive('ngAddressBar', function($browser, $timeout) {
|
||||
return {
|
||||
template: 'Address: <input id="addressBar" type="text" style="width: 400px" >',
|
||||
link: function(scope, element, attrs){
|
||||
var input = element.children("input"), delay;
|
||||
|
||||
var browsers = {
|
||||
html5: new FakeBrowser('http://www.example.com/base/path?a=b#h', '/base/index.html'),
|
||||
hashbang: new FakeBrowser('http://www.example.com/base/index.html#!/path?a=b#h', '/base/index.html')
|
||||
};
|
||||
input.on('keypress keyup keydown', function(event) {
|
||||
delay = (!delay ? $timeout(fireUrlChange, 250) : null);
|
||||
event.stopPropagation();
|
||||
})
|
||||
.val($browser.url());
|
||||
|
||||
function Html5Cntl($scope, $location) {
|
||||
$scope.$location = $location;
|
||||
}
|
||||
|
||||
function HashbangCntl($scope, $location) {
|
||||
$scope.$location = $location;
|
||||
}
|
||||
|
||||
function initEnv(name) {
|
||||
var root = angular.element(document.getElementById(name + '-mode'));
|
||||
// We must kill a link to the injector for this element otherwise angular will
|
||||
// complain that it has been bootstrapped already.
|
||||
root.data('$injector', null);
|
||||
angular.bootstrap(root, [function($compileProvider, $locationProvider, $provide){
|
||||
$locationProvider.html5Mode(true).hashPrefix('!');
|
||||
|
||||
$provide.value('$browser', browsers[name]);
|
||||
$provide.value('$sniffer', {history: name == 'html5'});
|
||||
|
||||
$compileProvider.directive('ngAddressBar', function() {
|
||||
return function(scope, elm, attrs) {
|
||||
var browser = browsers[attrs.browser],
|
||||
input = angular.element('<input type="text" style="width: 400px">').val(browser.url()),
|
||||
delay;
|
||||
|
||||
input.on('keypress keyup keydown', function() {
|
||||
if (!delay) {
|
||||
delay = setTimeout(fireUrlChange, 250);
|
||||
}
|
||||
});
|
||||
|
||||
browser.url = function(url) {
|
||||
return input.val(url);
|
||||
};
|
||||
|
||||
elm.append('Address: ').append(input);
|
||||
|
||||
function fireUrlChange() {
|
||||
delay = null;
|
||||
browser.urlChange(input.val());
|
||||
}
|
||||
$browser.url = function(url) {
|
||||
return url ? input.val(url) : input.val();
|
||||
};
|
||||
});
|
||||
}]);
|
||||
root.on('click', function(e) {
|
||||
e.stopPropagation();
|
||||
});
|
||||
}
|
||||
|
||||
initEnv('html5');
|
||||
initEnv('hashbang');
|
||||
function fireUrlChange() {
|
||||
delay = null;
|
||||
$browser.urlChange(input.val());
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
</file>
|
||||
|
||||
<file name="protractor.js" type="protractor">
|
||||
|
||||
var addressBar = element(by.css("#addressBar")),
|
||||
url = 'http://www.example.com/base/path?a=b#h';
|
||||
|
||||
|
||||
it("should show fake browser info on load", function(){
|
||||
expect(addressBar.getAttribute('value')).toBe(url);
|
||||
|
||||
expect(element(by.binding('$location.protocol')).getText()).toBe('http');
|
||||
expect(element(by.binding('$location.host')).getText()).toBe('www.example.com');
|
||||
expect(element(by.binding('$location.port')).getText()).toBe('80');
|
||||
expect(element(by.binding('$location.path')).getText()).toBe('/path');
|
||||
expect(element(by.binding('$location.search')).getText()).toBe('{"a":"b"}');
|
||||
expect(element(by.binding('$location.hash')).getText()).toBe('h');
|
||||
|
||||
});
|
||||
|
||||
it("should change $location accordingly", function(){
|
||||
var navigation = element.all(by.css("#navigation a"));
|
||||
|
||||
navigation.get(0).click();
|
||||
|
||||
expect(addressBar.getAttribute('value')).toBe("http://www.example.com/base/first?a=b");
|
||||
|
||||
expect(element(by.binding('$location.protocol')).getText()).toBe('http');
|
||||
expect(element(by.binding('$location.host')).getText()).toBe('www.example.com');
|
||||
expect(element(by.binding('$location.port')).getText()).toBe('80');
|
||||
expect(element(by.binding('$location.path')).getText()).toBe('/first');
|
||||
expect(element(by.binding('$location.search')).getText()).toBe('{"a":"b"}');
|
||||
expect(element(by.binding('$location.hash')).getText()).toBe('');
|
||||
|
||||
|
||||
navigation.get(1).click();
|
||||
|
||||
expect(addressBar.getAttribute('value')).toBe("http://www.example.com/base/sec/ond?flag#hash");
|
||||
|
||||
expect(element(by.binding('$location.protocol')).getText()).toBe('http');
|
||||
expect(element(by.binding('$location.host')).getText()).toBe('www.example.com');
|
||||
expect(element(by.binding('$location.port')).getText()).toBe('80');
|
||||
expect(element(by.binding('$location.path')).getText()).toBe('/sec/ond');
|
||||
expect(element(by.binding('$location.search')).getText()).toBe('{"flag":true}');
|
||||
expect(element(by.binding('$location.hash')).getText()).toBe('hash');
|
||||
});
|
||||
|
||||
</file>
|
||||
|
||||
</example>
|
||||
|
||||
####Browser in HTML5 Fallback mode (Hashbang mode)
|
||||
<example module="hashbang-mode" name="location-hashbang-mode">
|
||||
<file name="index.html">
|
||||
<div ng-controller="LocationController">
|
||||
<div ng-address-bar></div><br><br>
|
||||
<div>
|
||||
$location.protocol() = <span ng-bind="$location.protocol()"></span> <br>
|
||||
$location.host() = <span ng-bind="$location.host()"></span> <br>
|
||||
$location.port() = <span ng-bind="$location.port()"></span> <br>
|
||||
$location.path() = <span ng-bind="$location.path()"></span> <br>
|
||||
$location.search() = <span ng-bind="$location.search()"></span> <br>
|
||||
$location.hash() = <span ng-bind="$location.hash()"></span> <br>
|
||||
</div>
|
||||
<div id="navigation">
|
||||
<a href="http://www.example.com/base/first?a=b">/base/first?a=b</a> |
|
||||
<a href="http://www.example.com/base/sec/ond?flag#hash">sec/ond?flag#hash</a> |
|
||||
<a href="/other-base/another?search">external</a>
|
||||
</div>
|
||||
</div>
|
||||
</file>
|
||||
<file name="app.js">
|
||||
angular.module('hashbang-mode', ['fake-browser', 'address-bar'])
|
||||
|
||||
.constant('initUrl', 'http://www.example.com/base/index.html#!/path?a=b#h')
|
||||
.constant('baseHref', '/base/index.html')
|
||||
.value('$sniffer', { history: false })
|
||||
|
||||
.config(function($locationProvider) {
|
||||
$locationProvider.html5Mode(true).hashPrefix('!');
|
||||
})
|
||||
|
||||
.controller("LocationController", function($scope, $location) {
|
||||
$scope.$location = {};
|
||||
angular.forEach("protocol host port path search hash".split(" "), function(method){
|
||||
$scope.$location[method] = function(){
|
||||
var result = $location[method].call($location);
|
||||
return angular.isObject(result) ? angular.toJson(result) : result;
|
||||
};
|
||||
});
|
||||
})
|
||||
|
||||
.run(function($rootElement) {
|
||||
$rootElement.on('click', function(e) {
|
||||
e.stopPropagation();
|
||||
});
|
||||
});
|
||||
|
||||
</file>
|
||||
|
||||
<file name="fakeBrowser.js">
|
||||
angular.module('fake-browser', [])
|
||||
|
||||
.config(function($provide) {
|
||||
$provide.decorator('$browser', function($delegate, baseHref, initUrl) {
|
||||
|
||||
$delegate.onUrlChange = function(fn) {
|
||||
this.urlChange = fn;
|
||||
};
|
||||
|
||||
$delegate.url = function() {
|
||||
return initUrl;
|
||||
};
|
||||
|
||||
$delegate.defer = function(fn, delay) {
|
||||
setTimeout(function() { fn(); }, delay || 0);
|
||||
};
|
||||
|
||||
$delegate.baseHref = function() {
|
||||
return baseHref;
|
||||
};
|
||||
|
||||
return $delegate;
|
||||
});
|
||||
});
|
||||
</file>
|
||||
|
||||
|
||||
<file name="addressBar.js">
|
||||
angular.module('address-bar', [])
|
||||
.directive('ngAddressBar', function($browser, $timeout) {
|
||||
return {
|
||||
template: 'Address: <input id="addressBar" type="text" style="width: 400px" >',
|
||||
link: function(scope, element, attrs){
|
||||
var input = element.children("input"), delay;
|
||||
|
||||
input.on('keypress keyup keydown', function(event) {
|
||||
delay = (!delay ? $timeout(fireUrlChange, 250) : null);
|
||||
event.stopPropagation();
|
||||
})
|
||||
.val($browser.url());
|
||||
|
||||
$browser.url = function(url) {
|
||||
return url ? input.val(url) : input.val();
|
||||
};
|
||||
|
||||
function fireUrlChange() {
|
||||
delay = null;
|
||||
$browser.urlChange(input.val());
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
</file>
|
||||
|
||||
<file name="protractor.js" type="protractor">
|
||||
|
||||
var addressBar = element(by.css("#addressBar")),
|
||||
url = 'http://www.example.com/base/index.html#!/path?a=b#h';
|
||||
|
||||
it("should show fake browser info on load", function(){
|
||||
expect(addressBar.getAttribute('value')).toBe(url);
|
||||
|
||||
expect(element(by.binding('$location.protocol')).getText()).toBe('http');
|
||||
expect(element(by.binding('$location.host')).getText()).toBe('www.example.com');
|
||||
expect(element(by.binding('$location.port')).getText()).toBe('80');
|
||||
expect(element(by.binding('$location.path')).getText()).toBe('/path');
|
||||
expect(element(by.binding('$location.search')).getText()).toBe('{"a":"b"}');
|
||||
expect(element(by.binding('$location.hash')).getText()).toBe('h');
|
||||
|
||||
});
|
||||
|
||||
it("should change $location accordingly", function(){
|
||||
var navigation = element.all(by.css("#navigation a"));
|
||||
|
||||
navigation.get(0).click();
|
||||
|
||||
expect(addressBar.getAttribute('value')).toBe("http://www.example.com/base/index.html#!/first?a=b");
|
||||
|
||||
expect(element(by.binding('$location.protocol')).getText()).toBe('http');
|
||||
expect(element(by.binding('$location.host')).getText()).toBe('www.example.com');
|
||||
expect(element(by.binding('$location.port')).getText()).toBe('80');
|
||||
expect(element(by.binding('$location.path')).getText()).toBe('/first');
|
||||
expect(element(by.binding('$location.search')).getText()).toBe('{"a":"b"}');
|
||||
expect(element(by.binding('$location.hash')).getText()).toBe('');
|
||||
|
||||
|
||||
navigation.get(1).click();
|
||||
|
||||
expect(addressBar.getAttribute('value')).toBe("http://www.example.com/base/index.html#!/sec/ond?flag#hash");
|
||||
|
||||
expect(element(by.binding('$location.protocol')).getText()).toBe('http');
|
||||
expect(element(by.binding('$location.host')).getText()).toBe('www.example.com');
|
||||
expect(element(by.binding('$location.port')).getText()).toBe('80');
|
||||
expect(element(by.binding('$location.path')).getText()).toBe('/sec/ond');
|
||||
expect(element(by.binding('$location.search')).getText()).toBe('{"flag":true}');
|
||||
expect(element(by.binding('$location.hash')).getText()).toBe('hash');
|
||||
|
||||
});
|
||||
</file>
|
||||
|
||||
</example>
|
||||
|
||||
# Caveats
|
||||
|
||||
@@ -622,23 +812,24 @@ The Angular's compiler currently does not support two-way binding for methods (s
|
||||
to the $location object (using {@link input[text] ngModel} directive on an input
|
||||
field), you will need to specify an extra model property (e.g. `locationPath`) with two {@link ng.$rootScope.Scope#$watch $watchers}
|
||||
which push $location updates in both directions. For example:
|
||||
<example>
|
||||
<example module="locationExample">
|
||||
<file name="index.html">
|
||||
<div ng-controller="LocationController">
|
||||
<input type="text" ng-model="locationPath" />
|
||||
</div>
|
||||
</file>
|
||||
<file name="script.js">
|
||||
function LocationController($scope, $location) {
|
||||
$scope.$watch('locationPath', function(path) {
|
||||
$location.path(path);
|
||||
});
|
||||
$scope.$watch(function() {
|
||||
return $location.path();
|
||||
}, function(path) {
|
||||
$scope.locationPath = path;
|
||||
});
|
||||
}
|
||||
angular.module('locationExample', [])
|
||||
.controller('LocationController', ['$scope', '$location', function ($scope, $location) {
|
||||
$scope.$watch('locationPath', function(path) {
|
||||
$location.path(path);
|
||||
});
|
||||
$scope.$watch(function() {
|
||||
return $location.path();
|
||||
}, function(path) {
|
||||
$scope.locationPath = path;
|
||||
});
|
||||
}]);
|
||||
</file>
|
||||
</example>
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ Here is an example of manually initializing Angular:
|
||||
<!doctype html>
|
||||
<html>
|
||||
<body>
|
||||
Hello {{'World'}}!
|
||||
Hello {{greetMe}}!
|
||||
<script src="http://code.angularjs.org/snapshot/angular.js"></script>
|
||||
|
||||
<script>
|
||||
|
||||
@@ -198,7 +198,7 @@ This should help give you an idea of what Angular does internally.
|
||||
|
||||
// Step 3: link the compiled template with the scope.
|
||||
var element = linkFn(scope);
|
||||
|
||||
|
||||
// Step 4: Append to DOM (optional)
|
||||
parent.appendChild(element);
|
||||
```
|
||||
@@ -226,7 +226,7 @@ moved to the compile function for performance reasons.
|
||||
To understand, let's look at a real-world example with `ngRepeat`:
|
||||
|
||||
```html
|
||||
Hello {{user}}, you have these actions:
|
||||
Hello {{user.name}}, you have these actions:
|
||||
<ul>
|
||||
<li ng-repeat="action in user.actions">
|
||||
{{action.description}}
|
||||
@@ -236,7 +236,7 @@ Hello {{user}}, you have these actions:
|
||||
|
||||
When the above example is compiled, the compiler visits every node and looks for directives.
|
||||
|
||||
`{{user}}` matches the {@link ng.$interpolate interpolation directive}
|
||||
`{{user.name}}` matches the {@link ng.$interpolate interpolation directive}
|
||||
and `ng-repeat` matches the {@link ng.directive:ngRepeat `ngRepeat` directive}.
|
||||
|
||||
But {@link ng.directive:ngRepeat ngRepeat} has a dilemma.
|
||||
|
||||
@@ -37,10 +37,10 @@ Let's start with input fields for quantity and cost whose values are multiplied
|
||||
<div ng-app ng-init="qty=1;cost=2">
|
||||
<b>Invoice:</b>
|
||||
<div>
|
||||
Quantity: <input type="number" ng-model="qty" required >
|
||||
Quantity: <input type="number" ng-model="qty">
|
||||
</div>
|
||||
<div>
|
||||
Costs: <input type="number" ng-model="cost" required >
|
||||
Costs: <input type="number" ng-model="cost">
|
||||
</div>
|
||||
<div>
|
||||
<b>Total:</b> {{qty * cost | currency}}
|
||||
@@ -62,11 +62,8 @@ The first kind of new markup are the so called <a name="directive">"{@link direc
|
||||
They apply special behavior to attributes or elements in the HTML. In the example above we use the
|
||||
{@link ng.directive:ngApp `ng-app`} attribute, which is linked to a directive that automatically
|
||||
initializes our application. Angular also defines a directive for the {@link ng.directive:input `input`}
|
||||
element that adds extra behavior to the element. E.g. it is able to automatically validate that the entered
|
||||
text is non empty by evaluating the `required` attribute.
|
||||
The {@link ng.directive:ngModel `ng-model`} directive stores/updates
|
||||
the value of the input field into/from a variable and shows the validation state of the input field by
|
||||
adding css classes. In the example we use these css classes to mark an empty input field with a red border.
|
||||
element that adds extra behavior to the element. The {@link ng.directive:ngModel `ng-model`} directive
|
||||
stores/updates the value of the input field into/from a variable.
|
||||
|
||||
<div class="alert alert-info">
|
||||
**Custom directives to access the DOM**: In Angular, the only place where an application touches the DOM is
|
||||
@@ -323,7 +320,7 @@ The following example shows how this is done with Angular:
|
||||
angular.module('finance3', [])
|
||||
.factory('currencyConverter', ['$http', function($http) {
|
||||
var YAHOO_FINANCE_URL_PATTERN =
|
||||
'http://query.yahooapis.com/v1/public/yql?q=select * from '+
|
||||
'//query.yahooapis.com/v1/public/yql?q=select * from '+
|
||||
'yahoo.finance.xchange where pair in ("PAIRS")&format=json&'+
|
||||
'env=store://datatables.org/alltableswithkeys&callback=JSON_CALLBACK';
|
||||
var currencies = ['USD', 'EUR', 'CNY'];
|
||||
|
||||
@@ -37,27 +37,8 @@ The properties contain the **view model** (the model that will be presented by t
|
||||
`$scope` properties will be available to the template at the point in the DOM where the Controller
|
||||
is registered.
|
||||
|
||||
The following example shows a very simple constructor function for a Controller, `GreetingController`,
|
||||
which attaches a `greeting` property containing the string `'Hola!'` to the `$scope`:
|
||||
|
||||
```js
|
||||
function GreetingController($scope) {
|
||||
$scope.greeting = 'Hola!';
|
||||
}
|
||||
```
|
||||
|
||||
Once the Controller has been attached to the DOM, the `greeting` property can be data-bound to the
|
||||
template:
|
||||
|
||||
```js
|
||||
<div ng-controller="GreetingController">
|
||||
{{ greeting }}
|
||||
</div>
|
||||
```
|
||||
|
||||
**NOTE**: Although Angular allows you to create Controller functions in the global scope, this is
|
||||
not recommended. In a real application you should use the `.controller` method of your
|
||||
{@link module Angular Module} for your application as follows:
|
||||
The following example demonstrates creating a `GreetingController`, which attaches a `greeting`
|
||||
property containing the string `'Hola!'` to the `$scope`:
|
||||
|
||||
```js
|
||||
var myApp = angular.module('myApp',[]);
|
||||
@@ -67,9 +48,24 @@ myApp.controller('GreetingController', ['$scope', function($scope) {
|
||||
}]);
|
||||
```
|
||||
|
||||
We create an {@link module Angular Module}, `myApp`, for our application. Then we add the controller's
|
||||
constructor function to the module using the `.controller()` method. This keeps the controller's
|
||||
constructor function out of the global scope.
|
||||
|
||||
<div class="alert alert-info">
|
||||
We have used an **inline injection annotation** to explicitly specify the dependency
|
||||
of the Controller on the `$scope` service provided by Angular. See the guide on
|
||||
[Dependency Injection](http://docs.angularjs.org/guide/di) for more information.
|
||||
{@link guide/di Dependency Injection} for more information.
|
||||
</div>
|
||||
|
||||
We attach our controller to the DOM using the `ng-controller` directive. The `greeting` property can
|
||||
now be data-bound to the template:
|
||||
|
||||
```js
|
||||
<div ng-controller="GreetingController">
|
||||
{{ greeting }}
|
||||
</div>
|
||||
```
|
||||
|
||||
|
||||
# Adding Behavior to a Scope Object
|
||||
@@ -333,6 +329,3 @@ describe('state', function() {
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -218,15 +218,22 @@ DI is pervasive throughout Angular. You can use it when defining components or w
|
||||
and `config` blocks for a module.
|
||||
|
||||
- Components such as services, directives, filters and animations are defined by an injectable factory
|
||||
method or constructor function. These components can be injected with "service" components as
|
||||
dependencies.
|
||||
|
||||
- The `run` and `config` methods accept a function, which can also be injected with "service"
|
||||
method or constructor function. These components can be injected with "service" and "value"
|
||||
components as dependencies.
|
||||
|
||||
- The `run` method accepts a function, which can be injected with "service", "value" and "constant"
|
||||
components as dependencies. Note that you cannot inject "providers" into `run` blocks.
|
||||
|
||||
- The `config` method accepts a function, which can be injected with "provider" and "constant"
|
||||
components as dependencies. Note that you cannot inject "service" or "value" components into
|
||||
configuration
|
||||
|
||||
- Controllers are defined by a constructor function, which can be injected with any of the "service"
|
||||
components as dependencies, but they can also be provided with special dependencies. See "DI in
|
||||
Controllers" below.
|
||||
and "value" components as dependencies, but they can also be provided with special dependencies. See
|
||||
{@link di#controllers Controllers} below for a list of these special dependencies.
|
||||
|
||||
See {@link module#module-loading-dependencies Modules} for more details about injecting dependencies
|
||||
into `run` and `config` blocks.
|
||||
|
||||
|
||||
### Factory Methods
|
||||
|
||||
@@ -352,7 +352,7 @@ element as a customer component.
|
||||
Our `myCustomer` directive above is great, but it has a fatal flaw. We can only use it once within a
|
||||
given scope.
|
||||
|
||||
In its current implementation, we'd need to create a different controller each time In order to
|
||||
In its current implementation, we'd need to create a different controller each time in order to
|
||||
re-use such a directive:
|
||||
|
||||
<example module="docsScopeProblemExample">
|
||||
@@ -475,7 +475,6 @@ within our directive's template:
|
||||
angular.module('docsIsolationExample', [])
|
||||
.controller('Controller', ['$scope', function($scope) {
|
||||
$scope.naomi = { name: 'Naomi', address: '1600 Amphitheatre' };
|
||||
|
||||
$scope.vojta = { name: 'Vojta', address: '3456 Somewhere Else' };
|
||||
}])
|
||||
.directive('myCustomer', function() {
|
||||
@@ -537,7 +536,7 @@ where:
|
||||
In our `link` function, we want to update the displayed time once a second, or whenever a user
|
||||
changes the time formatting string that our directive binds to. We will use the `$interval` service
|
||||
to call a handler on a regular basis. This is easier than using `$timeout` but also works better with
|
||||
end-to-end testing, where we want to ensure that all $timeouts have completed before completing the test.
|
||||
end-to-end testing, where we want to ensure that all `$timeout`s have completed before completing the test.
|
||||
We also want to remove the `$interval` if the directive is deleted so we don't introduce a memory leak.
|
||||
|
||||
<example module="docsTimeDirective">
|
||||
@@ -910,6 +909,30 @@ Looking back at `myPane`'s definition, notice the last argument in its `link` fu
|
||||
When a directive requires a controller, it receives that controller as the fourth argument of its
|
||||
`link` function. Taking advantage of this, `myPane` can call the `addPane` function of `myTabs`.
|
||||
|
||||
If multiple controllers are required, the `require` option of the directive can take an array argument.
|
||||
The corresponding parameter being sent to the `link` function will also be an array.
|
||||
|
||||
```js
|
||||
angular.module('docsTabsExample', [])
|
||||
.directive('myPane', function() {
|
||||
return {
|
||||
require: ['^myTabs', '^ngModel'],
|
||||
restrict: 'E',
|
||||
transclude: true,
|
||||
scope: {
|
||||
title: '@'
|
||||
},
|
||||
link: function(scope, element, attrs, controllers) {
|
||||
var tabsCtrl = controllers[0],
|
||||
modelCtrl = controllers[1];
|
||||
|
||||
tabsCtrl.addPane(scope);
|
||||
},
|
||||
templateUrl: 'my-pane.html'
|
||||
};
|
||||
});
|
||||
```
|
||||
|
||||
Savvy readers may be wondering what the difference is between `link` and `controller`.
|
||||
The basic difference is that `controller` can expose an API, and `link` functions can interact with
|
||||
controllers using `require`.
|
||||
|
||||
@@ -50,9 +50,9 @@ the method from your view. If you want to `eval()` an Angular expression yoursel
|
||||
|
||||
You can try evaluating different expressions here:
|
||||
|
||||
<example>
|
||||
<example module="expressionExample">
|
||||
<file name="index.html">
|
||||
<div ng-controller="Cntl2" class="expressions">
|
||||
<div ng-controller="ExampleController" class="expressions">
|
||||
Expression:
|
||||
<input type='text' ng-model="expr" size="80"/>
|
||||
<button ng-click="addExp(expr)">Evaluate</button>
|
||||
@@ -66,23 +66,24 @@ You can try evaluating different expressions here:
|
||||
</file>
|
||||
|
||||
<file name="script.js">
|
||||
function Cntl2($scope) {
|
||||
var exprs = $scope.exprs = [];
|
||||
$scope.expr = '3*10|currency';
|
||||
$scope.addExp = function(expr) {
|
||||
exprs.push(expr);
|
||||
};
|
||||
angular.module('expressionExample', [])
|
||||
.controller('ExampleController', ['$scope', function($scope) {
|
||||
var exprs = $scope.exprs = [];
|
||||
$scope.expr = '3*10|currency';
|
||||
$scope.addExp = function(expr) {
|
||||
exprs.push(expr);
|
||||
};
|
||||
|
||||
$scope.removeExp = function(index) {
|
||||
exprs.splice(index, 1);
|
||||
};
|
||||
}
|
||||
$scope.removeExp = function(index) {
|
||||
exprs.splice(index, 1);
|
||||
};
|
||||
}]);
|
||||
</file>
|
||||
|
||||
<file name="protractor.js" type="protractor">
|
||||
it('should allow user expression testing', function() {
|
||||
element(by.css('.expressions button')).click();
|
||||
var lis = element(by.css('.expressions ul')).element.all(by.repeater('expr in exprs'));
|
||||
var lis = element(by.css('.expressions ul')).all(by.repeater('expr in exprs'));
|
||||
expect(lis.count()).toBe(1);
|
||||
expect(lis.get(0).getText()).toEqual('[ X ] 3*10|currency => $30.00');
|
||||
});
|
||||
@@ -101,9 +102,9 @@ This restriction is intentional. It prevents accidental access to the global sta
|
||||
Instead use services like `$window` and `$location` in functions called from expressions. Such services
|
||||
provide mockable access to globals.
|
||||
|
||||
<example>
|
||||
<example module="expressionExample">
|
||||
<file name="index.html">
|
||||
<div class="example2" ng-controller="Cntl1">
|
||||
<div class="example2" ng-controller="ExampleController">
|
||||
Name: <input ng-model="name" type="text"/>
|
||||
<button ng-click="greet()">Greet</button>
|
||||
<button ng-click="window.alert('Should not see me')">Won't greet</button>
|
||||
@@ -111,13 +112,14 @@ provide mockable access to globals.
|
||||
</file>
|
||||
|
||||
<file name="script.js">
|
||||
function Cntl1($window, $scope){
|
||||
$scope.name = 'World';
|
||||
angular.module('expressionExample', [])
|
||||
.controller('ExampleController', ['$window', '$scope', function($window, $scope) {
|
||||
$scope.name = 'World';
|
||||
|
||||
$scope.greet = function() {
|
||||
$window.alert('Hello ' + $scope.name);
|
||||
};
|
||||
}
|
||||
$scope.greet = function() {
|
||||
$window.alert('Hello ' + $scope.name);
|
||||
};
|
||||
}]);
|
||||
</file>
|
||||
|
||||
<file name="protractor.js" type="protractor">
|
||||
|
||||
@@ -16,9 +16,9 @@ The key directive in understanding two-way data-binding is {@link ng.directive:n
|
||||
The `ngModel` directive provides the two-way data-binding by synchronizing the model to the view, as well as view to the model.
|
||||
In addition it provides an {@link ngModel.NgModelController API} for other directives to augment its behavior.
|
||||
|
||||
<example>
|
||||
<example module="formExample">
|
||||
<file name="index.html">
|
||||
<div ng-controller="Controller">
|
||||
<div ng-controller="ExampleController">
|
||||
<form novalidate class="simple-form">
|
||||
Name: <input type="text" ng-model="user.name" /><br />
|
||||
E-mail: <input type="email" ng-model="user.email" /><br />
|
||||
@@ -32,19 +32,20 @@ In addition it provides an {@link ngModel.NgModelController API} for other direc
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function Controller($scope) {
|
||||
$scope.master = {};
|
||||
angular.module('formExample', [])
|
||||
.controller('ExampleController', ['$scope', function($scope) {
|
||||
$scope.master = {};
|
||||
|
||||
$scope.update = function(user) {
|
||||
$scope.master = angular.copy(user);
|
||||
};
|
||||
$scope.update = function(user) {
|
||||
$scope.master = angular.copy(user);
|
||||
};
|
||||
|
||||
$scope.reset = function() {
|
||||
$scope.user = angular.copy($scope.master);
|
||||
};
|
||||
$scope.reset = function() {
|
||||
$scope.user = angular.copy($scope.master);
|
||||
};
|
||||
|
||||
$scope.reset();
|
||||
}
|
||||
$scope.reset();
|
||||
}]);
|
||||
</script>
|
||||
</file>
|
||||
</example>
|
||||
@@ -67,9 +68,9 @@ The following example uses the CSS to display validity of each form control.
|
||||
In the example both `user.name` and `user.email` are required, but are rendered with red background only when they are dirty.
|
||||
This ensures that the user is not distracted with an error until after interacting with the control, and failing to satisfy its validity.
|
||||
|
||||
<example>
|
||||
<example module="formExample">
|
||||
<file name="index.html">
|
||||
<div ng-controller="Controller">
|
||||
<div ng-controller="ExampleController">
|
||||
<form novalidate class="css-form">
|
||||
Name:
|
||||
<input type="text" ng-model="user.name" required /><br />
|
||||
@@ -92,19 +93,20 @@ This ensures that the user is not distracted with an error until after interacti
|
||||
</style>
|
||||
|
||||
<script>
|
||||
function Controller($scope) {
|
||||
$scope.master = {};
|
||||
angular.module('formExample', [])
|
||||
.controller('ExampleController', ['$scope', function($scope) {
|
||||
$scope.master = {};
|
||||
|
||||
$scope.update = function(user) {
|
||||
$scope.master = angular.copy(user);
|
||||
};
|
||||
$scope.update = function(user) {
|
||||
$scope.master = angular.copy(user);
|
||||
};
|
||||
|
||||
$scope.reset = function() {
|
||||
$scope.user = angular.copy($scope.master);
|
||||
};
|
||||
$scope.reset = function() {
|
||||
$scope.user = angular.copy($scope.master);
|
||||
};
|
||||
|
||||
$scope.reset();
|
||||
}
|
||||
$scope.reset();
|
||||
}]);
|
||||
</script>
|
||||
</file>
|
||||
</example>
|
||||
@@ -130,9 +132,9 @@ This allows us to extend the above example with these features:
|
||||
- SAVE button is enabled only if form has some changes and is valid
|
||||
- custom error messages for `user.email` and `user.agree`
|
||||
|
||||
<example>
|
||||
<example module="formExample">
|
||||
<file name="index.html">
|
||||
<div ng-controller="Controller">
|
||||
<div ng-controller="ExampleController">
|
||||
<form name="form" class="css-form" novalidate>
|
||||
Name:
|
||||
<input type="text" ng-model="user.name" name="uName" required /><br />
|
||||
@@ -159,23 +161,24 @@ This allows us to extend the above example with these features:
|
||||
</file>
|
||||
|
||||
<file name="script.js">
|
||||
function Controller($scope) {
|
||||
$scope.master = {};
|
||||
angular.module('formExample', [])
|
||||
.controller('ExampleController', ['$scope', function($scope) {
|
||||
$scope.master = {};
|
||||
|
||||
$scope.update = function(user) {
|
||||
$scope.master = angular.copy(user);
|
||||
};
|
||||
$scope.update = function(user) {
|
||||
$scope.master = angular.copy(user);
|
||||
};
|
||||
|
||||
$scope.reset = function() {
|
||||
$scope.user = angular.copy($scope.master);
|
||||
};
|
||||
$scope.reset = function() {
|
||||
$scope.user = angular.copy($scope.master);
|
||||
};
|
||||
|
||||
$scope.isUnchanged = function(user) {
|
||||
return angular.equals(user, $scope.master);
|
||||
};
|
||||
$scope.isUnchanged = function(user) {
|
||||
return angular.equals(user, $scope.master);
|
||||
};
|
||||
|
||||
$scope.reset();
|
||||
}
|
||||
$scope.reset();
|
||||
}]);
|
||||
</file>
|
||||
</example>
|
||||
|
||||
|
||||
@@ -114,7 +114,7 @@ You write the following binding using the currency filter:
|
||||
|
||||
If your app is currently in the `en-US` locale, the browser will show `$1000.00`. If someone in the
|
||||
Japanese locale (`ja`) views your app, their browser will show a balance of `¥1000.00` instead.
|
||||
This is problematinc because $1000 is not the same as ¥1000.
|
||||
This is problematic because $1000 is not the same as ¥1000.
|
||||
|
||||
In this case, you need to override the default currency symbol by providing the
|
||||
{@link ng.filter:currency} currency filter with a currency symbol as a parameter.
|
||||
|
||||
@@ -47,7 +47,7 @@ In Angular applications, you move the job of filling page templates with data fr
|
||||
|
||||
### Testing
|
||||
|
||||
* **Unit testing:** [Using Karma (video)](http://www.youtube.com/watch?v=YG5DEzaQBIc), {@link guide/dev_guide.unit-testing Unit testing}, {@link guide/dev_guide.services.testing_services Testing services}, [Karma in Webstorm](http://blog.jetbrains.com/webstorm/2013/10/running-javascript-tests-with-karma-in-webstorm-7/)
|
||||
* **Unit testing:** [Using Karma (video)](http://www.youtube.com/watch?v=YG5DEzaQBIc), {@link guide/unit-testing Unit testing}, {@link guide/services#unit-testing Testing services}, [Karma in Webstorm](http://blog.jetbrains.com/webstorm/2013/10/running-javascript-tests-with-karma-in-webstorm-7/)
|
||||
* **Scenario testing:** [Protractor](https://github.com/angular/protractor)
|
||||
|
||||
## Specific Topics
|
||||
|
||||
@@ -22,7 +22,7 @@ The impedance mismatch between dynamic applications and static documents is ofte
|
||||
in charge and it calls into the library when it sees fit. E.g., `jQuery`.
|
||||
* **frameworks** - a particular implementation of a web application, where your code fills in
|
||||
the details. The framework is in charge and it calls into your code when it needs something
|
||||
app specific. E.g., `knockout`, `ember`, etc.
|
||||
app specific. E.g., `durandal`, `ember`, etc.
|
||||
|
||||
|
||||
Angular takes another approach. It attempts to minimize the impedance mismatch between document
|
||||
|
||||
@@ -382,8 +382,6 @@ See [80739409](https://github.com/angular/angular.js/commit/807394095b991357225a
|
||||
|
||||
## ngBindHtmlUnsafe has been removed and replaced by ngBindHtml
|
||||
|
||||
`ngBindHtml` which has been moved from `ngSanitize` module to the core `ng` module.
|
||||
|
||||
`ngBindHtml` provides `ngBindHtmlUnsafe` like
|
||||
behavior (evaluate an expression and innerHTML the result into the DOM) when bound to the result
|
||||
of `$sce.trustAsHtml(string)`. When bound to a plain string, the string is sanitized via
|
||||
@@ -391,6 +389,10 @@ of `$sce.trustAsHtml(string)`. When bound to a plain string, the string is sanit
|
||||
module is not loaded) and the bound expression evaluates to a value that is not trusted an
|
||||
exception is thrown.
|
||||
|
||||
When using this directive you can either include `ngSanitize` in your module's dependencis (See the
|
||||
example at the {@link ngBindHtml} reference) or use the {@link $sce} service to set the value as
|
||||
trusted.
|
||||
|
||||
See [dae69473](https://github.com/angular/angular.js/commit/dae694739b9581bea5dbc53522ec00d87b26ae55).
|
||||
|
||||
|
||||
|
||||
@@ -45,6 +45,12 @@ I'm in a hurry. How do I get a Hello World module working?
|
||||
};
|
||||
});
|
||||
</file>
|
||||
|
||||
<file name="protractor.js" type="protractor">
|
||||
it('should add Hello to the name', function() {
|
||||
expect(element(by.binding("{{ 'World' | greet }}")).getText()).toEqual('Hello, World!');
|
||||
});
|
||||
</file>
|
||||
</example>
|
||||
|
||||
Important things to notice:
|
||||
@@ -75,13 +81,14 @@ The above is a suggestion. Tailor it to your needs.
|
||||
<example module='xmpl'>
|
||||
<file name="index.html">
|
||||
<div ng-controller="XmplController">
|
||||
{{ greeting }}!
|
||||
{{ greeting }}
|
||||
</div>
|
||||
</file>
|
||||
|
||||
<file name="script.js">
|
||||
angular.module('xmpl.service', []).
|
||||
value('greeter', {
|
||||
angular.module('xmpl.service', [])
|
||||
|
||||
.value('greeter', {
|
||||
salutation: 'Hello',
|
||||
localize: function(localization) {
|
||||
this.salutation = localization.salutation;
|
||||
@@ -89,8 +96,9 @@ The above is a suggestion. Tailor it to your needs.
|
||||
greet: function(name) {
|
||||
return this.salutation + ' ' + name + '!';
|
||||
}
|
||||
}).
|
||||
value('user', {
|
||||
})
|
||||
|
||||
.value('user', {
|
||||
load: function(name) {
|
||||
this.name = name;
|
||||
}
|
||||
@@ -100,21 +108,28 @@ The above is a suggestion. Tailor it to your needs.
|
||||
|
||||
angular.module('xmpl.filter', []);
|
||||
|
||||
angular.module('xmpl', ['xmpl.service', 'xmpl.directive', 'xmpl.filter']).
|
||||
run(function(greeter, user) {
|
||||
angular.module('xmpl', ['xmpl.service', 'xmpl.directive', 'xmpl.filter'])
|
||||
|
||||
.run(function(greeter, user) {
|
||||
// This is effectively part of the main method initialization code
|
||||
greeter.localize({
|
||||
salutation: 'Bonjour'
|
||||
});
|
||||
user.load('World');
|
||||
})
|
||||
|
||||
.controller('XmplController', function($scope, greeter, user){
|
||||
$scope.greeting = greeter.greet(user.name);
|
||||
});
|
||||
|
||||
|
||||
// A Controller for your app
|
||||
var XmplController = function($scope, greeter, user) {
|
||||
$scope.greeting = greeter.greet(user.name);
|
||||
};
|
||||
</file>
|
||||
|
||||
<file name="protractor.js" type="protractor">
|
||||
it('should add Hello to the name', function() {
|
||||
expect(element(by.binding("{{ greeting }}")).getText()).toEqual('Bonjour World!');
|
||||
});
|
||||
</file>
|
||||
|
||||
</example>
|
||||
|
||||
|
||||
|
||||
@@ -132,9 +132,11 @@ In the code above, we see how the `apiToken` service is defined via the Factory
|
||||
on the `clientId` service. The factory service then uses NSA-proof encryption to produce an authentication
|
||||
token.
|
||||
|
||||
Note: It is best practice to name the factory functions as `<serviceId>Factory`
|
||||
<div class="alert alert-success">
|
||||
**Best Practice:** name the factory functions as `<serviceId>Factory`
|
||||
(e.g. apiTokenFactory). While this naming convention is not required, it helps when navigating the code base
|
||||
or looking at stack traces in the debugger.
|
||||
</div>
|
||||
|
||||
Just like with Value recipe, Factory recipe can create a service of any type, whether it be a
|
||||
primitive, object literal, function, or even an instance of a custom type.
|
||||
@@ -193,8 +195,7 @@ that would mess with the teachers.
|
||||
|
||||
## Provider Recipe
|
||||
|
||||
There are two more recipe types left to cover. They are both fairly specialized and are used
|
||||
infrequently. As already mentioned in the intro, the Provider recipe is the core recipe type and
|
||||
As already mentioned in the intro, the Provider recipe is the core recipe type and
|
||||
all the other recipe types are just syntactic sugar on top of it. It is the most verbose recipe
|
||||
with the most abilities, but for most services it's overkill.
|
||||
|
||||
|
||||
@@ -42,15 +42,16 @@ arrangement isolates the controller from the directive as well as from DOM. This
|
||||
point since it makes the controllers view agnostic, which greatly improves the testing story of
|
||||
the applications.
|
||||
|
||||
<example>
|
||||
<example module="scopeExample">
|
||||
<file name="script.js">
|
||||
function MyController($scope) {
|
||||
$scope.username = 'World';
|
||||
angular.module('scopeExample', [])
|
||||
.controller('MyController', ['$scope', function($scope) {
|
||||
$scope.username = 'World';
|
||||
|
||||
$scope.sayHello = function() {
|
||||
$scope.greeting = 'Hello ' + $scope.username + '!';
|
||||
};
|
||||
}
|
||||
$scope.sayHello = function() {
|
||||
$scope.greeting = 'Hello ' + $scope.username + '!';
|
||||
};
|
||||
}]);
|
||||
</file>
|
||||
<file name="index.html">
|
||||
<div ng-controller="MyController">
|
||||
@@ -112,7 +113,7 @@ may have several child scopes.
|
||||
The application can have multiple scopes, because some {@link guide/directive directives} create
|
||||
new child scopes (refer to directive documentation to see which directives create new scopes).
|
||||
When new scopes are created, they are added as children of their parent scope. This creates a tree
|
||||
structure which parallels the DOM where they're attached
|
||||
structure which parallels the DOM where they're attached.
|
||||
|
||||
When Angular evaluates `{{name}}`, it first looks at the scope associated with the given
|
||||
element for the `name` property. If no such property is found, it searches the parent scope
|
||||
@@ -122,13 +123,13 @@ inheritance, and child scopes prototypically inherit from their parents.
|
||||
This example illustrates scopes in application, and prototypical inheritance of properties. The example is followed by
|
||||
a diagram depicting the scope boundaries.
|
||||
|
||||
<example>
|
||||
<example module="scopeExample">
|
||||
<file name="index.html">
|
||||
<div class="show-scope-demo">
|
||||
<div ng-controller="GreetCtrl">
|
||||
<div ng-controller="GreetController">
|
||||
Hello {{name}}!
|
||||
</div>
|
||||
<div ng-controller="ListCtrl">
|
||||
<div ng-controller="ListController">
|
||||
<ol>
|
||||
<li ng-repeat="name in names">{{name}} from {{department}}</li>
|
||||
</ol>
|
||||
@@ -136,14 +137,14 @@ a diagram depicting the scope boundaries.
|
||||
</div>
|
||||
</file>
|
||||
<file name="script.js">
|
||||
function GreetCtrl($scope, $rootScope) {
|
||||
$scope.name = 'World';
|
||||
$rootScope.department = 'Angular';
|
||||
}
|
||||
|
||||
function ListCtrl($scope) {
|
||||
$scope.names = ['Igor', 'Misko', 'Vojta'];
|
||||
}
|
||||
angular.module('scopeExample', [])
|
||||
.controller('GreetController', ['$scope', '$rootScope', function($scope, $rootScope) {
|
||||
$scope.name = 'World';
|
||||
$rootScope.department = 'Angular';
|
||||
}])
|
||||
.controller('ListController', ['$scope', function($scope) {
|
||||
$scope.names = ['Igor', 'Misko', 'Vojta'];
|
||||
}]);
|
||||
</file>
|
||||
<file name="style.css">
|
||||
.show-scope-demo.ng-scope,
|
||||
@@ -190,14 +191,15 @@ Scopes can propagate events in similar fashion to DOM events. The event can be {
|
||||
ng.$rootScope.Scope#$broadcast broadcasted} to the scope children or {@link
|
||||
ng.$rootScope.Scope#$emit emitted} to scope parents.
|
||||
|
||||
<example>
|
||||
<example module="eventExample">
|
||||
<file name="script.js">
|
||||
function EventController($scope) {
|
||||
$scope.count = 0;
|
||||
$scope.$on('MyEvent', function() {
|
||||
$scope.count++;
|
||||
});
|
||||
}
|
||||
angular.module('eventExample', [])
|
||||
.controller('EventController', ['$scope', function($scope) {
|
||||
$scope.count = 0;
|
||||
$scope.$on('MyEvent', function() {
|
||||
$scope.count++;
|
||||
});
|
||||
}]);
|
||||
</file>
|
||||
<file name="index.html">
|
||||
<div ng-controller="EventController">
|
||||
|
||||
@@ -49,7 +49,7 @@ Out of the four options in the list above, only the last one is testable. Let's
|
||||
### Using the `new` operator
|
||||
|
||||
While there is nothing wrong with the `new` operator fundamentally, a problem arises when calling `new`
|
||||
on a constructor. This permanently binds the call site to the type. For example, lets say that we try to
|
||||
on a constructor. This permanently binds the call site to the type. For example, let's say that we try to
|
||||
instantiate an `XHR` that will retrieve data from the server.
|
||||
|
||||
```js
|
||||
@@ -337,6 +337,80 @@ We inject the $compile service and $rootScope before each jasmine test. The $com
|
||||
to render the aGreatEye directive. After rendering the directive we ensure that the directive has
|
||||
replaced the content and "lidless, wreathed in flame, 2 times" is present.
|
||||
|
||||
### Testing Transclusion Directives
|
||||
|
||||
Directives that use transclusion are treated specially by the compiler. Before their compile
|
||||
function is called, the contents of the directive's element are removed from the element and
|
||||
provided via a transclusion function. The directive's template is then appended to the directive's
|
||||
element, to which it can then insert the transcluded content into its template.
|
||||
|
||||
|
||||
Before compilation:
|
||||
```html
|
||||
<div translude-directive>
|
||||
Some transcluded content
|
||||
</div>
|
||||
```
|
||||
|
||||
After transclusion extraction:
|
||||
```html
|
||||
<div transclude-directive></div>
|
||||
```
|
||||
|
||||
After compilation:
|
||||
```html
|
||||
<div transclude-directive>
|
||||
Some Template
|
||||
<span ng-transclude>Some transcluded content</span>
|
||||
</div>
|
||||
```
|
||||
|
||||
If the directive is using 'element' transclusion, the compiler will actually remove the
|
||||
directive's entire element from the DOM and replace it with a comment node. The compiler then
|
||||
inserts the directive's template "after" this comment node, as a sibling.
|
||||
|
||||
Before compilation
|
||||
```html
|
||||
<div element-transclude>
|
||||
Some Content
|
||||
</div>
|
||||
```
|
||||
|
||||
After transclusion extraction
|
||||
```html
|
||||
<!-- elementTransclude -->
|
||||
```
|
||||
|
||||
After compilation:
|
||||
```html
|
||||
<!-- elementTransclude -->
|
||||
<div element-transclude>
|
||||
Some Template
|
||||
<span ng-transclude>Some transcluded content</span>
|
||||
</div>
|
||||
```
|
||||
|
||||
It is important to be aware of this when writing tests for directives that use 'element'
|
||||
transclusion. If you place the directive on the root element of the DOM fragment that you
|
||||
pass to {@link $compile}, then the DOM node returned from the linking function will be the
|
||||
comment node and you will lose the ability to access the template and transcluded content.
|
||||
|
||||
```javascript
|
||||
var node = $compile('<div element-transclude></div>')($rootScope);
|
||||
expect(node[0].nodeType).toEqual(node.COMMENT_NODE);
|
||||
expect(node[1]).toBeUndefined();
|
||||
```
|
||||
|
||||
To cope with this you simply ensure that your 'element' transclude directive is wrapped in an
|
||||
element, such as a `<div>`.
|
||||
|
||||
```javascript
|
||||
var node = $compile('<div><div element-transclude></div></div>')($rootScope);
|
||||
var contents = node.contents();
|
||||
expect(contents[0].nodeType).toEqual(node.COMMENT_NODE);
|
||||
expect(contents[1].nodeType).toEqual(node.ELEMENT_NODE);
|
||||
```
|
||||
|
||||
### Testing Directives With External Templates
|
||||
|
||||
If your directive uses `templateUrl`, consider using
|
||||
|
||||
@@ -83,4 +83,4 @@ after the core `angular.js` file:
|
||||
our docs, or even more importantly, view the docs offline.
|
||||
|
||||
* __`i18n`__ - this directory contains locale specific `ngLocale` angular modules to override the defaults
|
||||
defined in the `ng` module.
|
||||
defined in the `ng` module.
|
||||
|
||||
@@ -16,7 +16,7 @@ Because HTML has Angular brackets and "ng" sounds like "Angular".
|
||||
AngularJS fits the definition of a framework the best, even though it's much more lightweight than
|
||||
a typical framework and that's why many confuse it with a library.
|
||||
|
||||
AngularJS is 100% JavaScript, 100% client side and compatible with both desktop and mobile browsers.
|
||||
AngularJS is 100% JavaScript, 100% client-side and compatible with both desktop and mobile browsers.
|
||||
So it's definitely not a plugin or some other native browser extension.
|
||||
|
||||
|
||||
@@ -114,7 +114,7 @@ make our schwag will be happy to do a custom run for you, based on our existing
|
||||
they'll waive the setup costs, and you can order any quantity you need.
|
||||
|
||||
**Stickers**
|
||||
For orders of 250 stickers or more within Canada or the United States, contact Tom Witting (or anyone in sales) via email at tom@stickergiant.com, and tell him you want to order some AngularJS
|
||||
For orders of 250 stickers or more within Canada or the United States, contact Tom Witting (or anyone in sales) via email at <tom@stickergiant.com>, and tell him you want to order some AngularJS
|
||||
stickers just like the ones in job #42711. You'll have to give them your own info for billing and shipping.
|
||||
|
||||
As long as the design stays exactly the same, [StickerGiant](http://www.stickergiant.com) will give you a reorder discount.
|
||||
|
||||
@@ -10,7 +10,7 @@ becoming an Angular expert.
|
||||
1. Read the {@link guide/concepts conceptual overview}.<br/>Understand Angular's vocabulary and how all the Angular
|
||||
components work together.
|
||||
1. Do the {@link tutorial/ AngularJS Tutorial}.<br/>Walk end-to-end through building an application complete with tests
|
||||
on top of a node.js web server. Covers every major AngularJS feature and show you how to set up your development
|
||||
on top of a node.js web server. Covers every major AngularJS feature and shows you how to set up your development
|
||||
environment.
|
||||
1. Download or clone the [Seed App project template](https://github.com/angular/angular-seed).<br/>Gives you a
|
||||
starter app with a directory layout, test harness, and scripts to begin building your application.
|
||||
|
||||
@@ -31,7 +31,7 @@ npm install
|
||||
|
||||
To see the app running in a browser, open a *separate* terminal/command line tab or window, then
|
||||
run `npm start` to start the web server. Now, open a browser window for the app and navigate to
|
||||
<a href="http://localhost:8000/app/index.html" target="_blank">`http://localhost:8000/app/index.html`</a>
|
||||
<a href="http://localhost:8000/app/" target="_blank">`http://localhost:8000/app/`</a>
|
||||
|
||||
You can now see the page in your browser. It's not very exciting, but that's OK.
|
||||
|
||||
@@ -88,8 +88,10 @@ being the element on which the `ngApp` directive was defined.
|
||||
|
||||
Nothing here {{'yet' + '!'}}
|
||||
|
||||
This line demonstrates the core feature of Angular's templating capabilities – a binding, denoted
|
||||
by double-curlies `{{ }}` as well as a simple expression `'yet' + '!'` used in this binding.
|
||||
This line demonstrates two core features of Angular's templating capabilities:
|
||||
|
||||
* a binding, denoted by double-curlies `{{ }}`
|
||||
* a simple expression `'yet' + '!'` used in this binding.
|
||||
|
||||
The binding tells Angular that it should evaluate an expression and insert the result into the
|
||||
DOM in place of the binding. Rather than a one-time insert, as we'll see in the next steps, a
|
||||
|
||||
@@ -59,12 +59,17 @@ tag as the template.
|
||||
by the value of the expressions.
|
||||
|
||||
We have added a new directive, called `ng-controller`, which attaches a `PhoneListCtrl`
|
||||
__controller__ to the DOM at this point:
|
||||
__controller__ to the <body> tag. At this point:
|
||||
|
||||
* The expressions in curly braces (`{{phone.name}}` and `{{phone.snippet}}` denote
|
||||
bindings, which are referring to our application model, which is set up in our `PhoneListCtrl`
|
||||
controller.
|
||||
|
||||
<div class="alert alert-info">
|
||||
Note: We have specified an {@link angular.Module Angular Module} to load using `ng-app="phonecatApp"`,
|
||||
where `phonecatApp` is the name of our module. This module will contain the `PhoneListCtrl`.
|
||||
</div>
|
||||
|
||||
<img class="diagram" src="img/tutorial/tutorial_02.png">
|
||||
|
||||
## Model and Controller
|
||||
@@ -205,6 +210,11 @@ To run the tests, and then watch the files for changes: `npm test`.
|
||||
* To rerun the tests, just change any of the source or test .js files. Karma will notice the change
|
||||
and will rerun the tests for you. Now isn't that sweet?
|
||||
|
||||
<div class="alert alert-info">
|
||||
Make sure you don't minimize the browser that Karma opened. On some OS, memory assigned to a minimized
|
||||
browser is limited, which results in your karma tests running extremely slow.
|
||||
</div>
|
||||
|
||||
# Experiments
|
||||
|
||||
* Add another binding to `index.html`. For example:
|
||||
@@ -255,4 +265,4 @@ to the app.
|
||||
|
||||
[jasmine]: http://jasmine.github.io/
|
||||
[jasmine-docs]: http://jasmine.github.io/1.3/introduction.html
|
||||
[karma]: http://karma-runner.github.io/
|
||||
[karma]: http://karma-runner.github.io/
|
||||
|
||||
@@ -128,7 +128,9 @@ will exit after the test run and will not automatically rerun the test suite on
|
||||
To rerun the test suite, execute `npm run protractor` again.
|
||||
|
||||
<div class="alert alert-info">
|
||||
Note: You must ensure you've installed the protractor and updated webdriver prior to running the
|
||||
Note: You must ensure your application is being served via a web-server to test with protractor.
|
||||
You can do this using `npm start`.
|
||||
You also need to ensure you've installed the protractor and updated webdriver prior to running the
|
||||
`npm run protractor`. You can do this by issuing `npm install` and `npm run update-webdriver` into
|
||||
your terminal.
|
||||
</div>
|
||||
@@ -143,16 +145,39 @@ Display the current value of the `query` model by adding a `{{query}}` binding i
|
||||
### Display Query in Title
|
||||
Let's see how we can get the current value of the `query` model to appear in the HTML page title.
|
||||
|
||||
* Add the following end-to-end test into the `describe` block within `test/e2e/scenarios.js`:
|
||||
* Add an end-to-end test into the `describe` block, `test/e2e/scenarios.js` should look like this:
|
||||
|
||||
```js
|
||||
it('should display the current filter value in the title bar', function() {
|
||||
describe('PhoneCat App', function() {
|
||||
|
||||
expect(browser.getTitle()).toMatch(/Google Phone Gallery:\s*$/);
|
||||
|
||||
element(by.model('query')).sendKeys('nexus');
|
||||
|
||||
expect(browser.getTitle()).toMatch(/Google Phone Gallery: nexus$/);
|
||||
describe('Phone list view', function() {
|
||||
|
||||
beforeEach(function() {
|
||||
browser.get('app/index.html');
|
||||
});
|
||||
|
||||
var phoneList = element.all(by.repeater('phone in phones'));
|
||||
var query = element(by.model('query'));
|
||||
|
||||
it('should filter the phone list as user types into the search box', function() {
|
||||
expect(phoneList.count()).toBe(3);
|
||||
|
||||
query.sendKeys('nexus');
|
||||
expect(phoneList.count()).toBe(1);
|
||||
|
||||
query.clear();
|
||||
query.sendKeys('motorola');
|
||||
expect(phoneList.count()).toBe(2);
|
||||
});
|
||||
|
||||
it('should display the current filter value in the title bar', function() {
|
||||
query.clear();
|
||||
expect(browser.getTitle()).toMatch(/Google Phone Gallery:\s*$/);
|
||||
|
||||
query.sendKeys('nexus');
|
||||
expect(browser.getTitle()).toMatch(/Google Phone Gallery: nexus$/);
|
||||
});
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
@@ -166,7 +166,7 @@ __`test/e2e/scenarios.js`:__
|
||||
"MOTOROLA XOOM\u2122"
|
||||
]);
|
||||
|
||||
element(by.model('orderProp')).findElement(by.css('option[value="name"]')).click();
|
||||
element(by.model('orderProp')).element(by.css('option[value="name"]')).click();
|
||||
|
||||
expect(getNames()).toEqual([
|
||||
"MOTOROLA XOOM\u2122",
|
||||
|
||||
@@ -73,7 +73,7 @@ __`test/e2e/scenarios.js`__:
|
||||
it('should render phone specific links', function() {
|
||||
var query = element(by.model('query'));
|
||||
query.sendKeys('nexus');
|
||||
element(by.css('.phones li a')).click();
|
||||
element.all(by.css('.phones li a')).first().click();
|
||||
browser.getLocationAbsUrl().then(function(url) {
|
||||
expect(url.split('#')[1]).toBe('/phones/nexus-s');
|
||||
});
|
||||
|
||||
@@ -78,12 +78,17 @@ utilize the browser's history (back and forward navigation) and bookmarks.
|
||||
As you {@link tutorial/step_05 noticed}, {@link guide/di dependency injection} (DI) is at the core of
|
||||
AngularJS, so it's important for you to understand a thing or two about how it works.
|
||||
|
||||
When the application bootstraps, Angular creates an injector that will be used for all DI stuff in
|
||||
this app. The injector itself doesn't know anything about what `$http` or `$route` services do, in
|
||||
fact it doesn't even know about the existence of these services unless it is configured with proper
|
||||
module definitions. The sole responsibilities of the injector are to load specified module
|
||||
definition(s), register all service providers defined in these modules, and when asked, inject
|
||||
a specified function with dependencies (services) that it lazily instantiates via their providers.
|
||||
When the application bootstraps, Angular creates an injector that will be used to find and inject all
|
||||
of the services that are required by your app. The injector itself doesn't know anything about what
|
||||
`$http` or `$route` services do, in fact it doesn't even know about the existence of these services
|
||||
unless it is configured with proper module definitions.
|
||||
|
||||
The injector only carries out the following steps :
|
||||
|
||||
* load the module definition(s) that you specify in your app
|
||||
* register all Providers defined in these module definitions
|
||||
* when asked to do so, inject a specified function and any necessary dependencies (services) that
|
||||
it lazily instantiates via their Providers.
|
||||
|
||||
Providers are objects that provide (create) instances of services and expose configuration APIs
|
||||
that can be used to control the creation and runtime behavior of a service. In case of the `$route`
|
||||
@@ -197,7 +202,7 @@ moved the controllers into their own module `phonecatControllers` (as shown belo
|
||||
|
||||
We added `angular-route.js` to `index.html` and created a new `phonecatControllers` module in
|
||||
`controllers.js`. That's not all we need to do to be able to use their code, however. We also have
|
||||
to add the modules dependencies of our app. By listing these two modules as dependencies of
|
||||
to add the modules as dependencies of our app. By listing these two modules as dependencies of
|
||||
`phonecatApp`, we can use the directives and services they provide.
|
||||
|
||||
|
||||
|
||||
@@ -120,7 +120,7 @@ You should now see the following output in the Karma tab:
|
||||
|
||||
# Experiments
|
||||
|
||||
* Let's experiment with some of the {@link ng.$filterProvider built-in Angular filters} and add the
|
||||
* Let's experiment with some of the {@link api/ng/filter built-in Angular filters} and add the
|
||||
following bindings to `index.html`:
|
||||
* `{{ "lower cap string" | uppercase }}`
|
||||
* `{{ {foo: "bar", baz: 23} | json }}`
|
||||
|
||||
@@ -102,6 +102,50 @@ __`test/e2e/scenarios.js`:__
|
||||
You can now rerun `npm run protractor` to see the tests run.
|
||||
|
||||
|
||||
You also have to refactor one of your unit tests because of the addition of the `mainImageUrl`
|
||||
model property to the `PhoneDetailCtrl` controller. Below, we create the function `xyzPhoneData`
|
||||
which returns the appropriate json with the `images` attribute in order to get the test to pass.
|
||||
|
||||
__`test/unit/controllersSpec.js`:__
|
||||
|
||||
```js
|
||||
...
|
||||
beforeEach(module('phonecatApp'));
|
||||
|
||||
...
|
||||
|
||||
describe('PhoneDetailCtrl', function(){
|
||||
var scope, $httpBackend, ctrl,
|
||||
xyzPhoneData = function() {
|
||||
return {
|
||||
name: 'phone xyz',
|
||||
images: ['image/url1.png', 'image/url2.png']
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
beforeEach(inject(function(_$httpBackend_, $rootScope, $routeParams, $controller) {
|
||||
$httpBackend = _$httpBackend_;
|
||||
$httpBackend.expectGET('phones/xyz.json').respond(xyzPhoneData());
|
||||
|
||||
$routeParams.phoneId = 'xyz';
|
||||
scope = $rootScope.$new();
|
||||
ctrl = $controller('PhoneDetailCtrl', {$scope: scope});
|
||||
}));
|
||||
|
||||
|
||||
it('should fetch phone detail', function() {
|
||||
expect(scope.phone).toBeUndefined();
|
||||
$httpBackend.flush();
|
||||
|
||||
expect(scope.phone).toEqual(xyzPhoneData());
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
Your unit tests should now be passing.
|
||||
|
||||
|
||||
# Experiments
|
||||
|
||||
* Let's add a new controller method to `PhoneDetailCtrl`:
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
'use strict';
|
||||
|
||||
var http = require('http');
|
||||
var https = require('https');
|
||||
var fs = require('fs');
|
||||
@@ -41,63 +43,63 @@ function help() {
|
||||
console.log('gdocs.js --login <username>');
|
||||
console.log('gdocs.js --fetch [<docs collection>]');
|
||||
process.exit(-1);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
function fetch(collection, url){
|
||||
console.log('fetching a list of docs in collection ' + collection + '...');
|
||||
request('GET', url, {
|
||||
headers: {
|
||||
'Gdata-Version': '3.0',
|
||||
'Authorization': 'GoogleLogin auth=' + getAuthToken()
|
||||
}
|
||||
},
|
||||
function(chunk){
|
||||
var entries = chunk.split('<entry');
|
||||
entries.shift();
|
||||
entries.forEach(function(entry){
|
||||
var title = entry.match(/<title>(.*?)<\/title>/)[1];
|
||||
if (title.match(/\.ngdoc$/)) {
|
||||
var exportUrl = entry.match(/<content type='text\/html' src='(.*?)'\/>/)[1];
|
||||
download(collection, title, exportUrl);
|
||||
};
|
||||
});
|
||||
headers: {
|
||||
'Gdata-Version': '3.0',
|
||||
'Authorization': 'GoogleLogin auth=' + getAuthToken()
|
||||
}
|
||||
);
|
||||
},
|
||||
function(chunk){
|
||||
var entries = chunk.split('<entry');
|
||||
entries.shift();
|
||||
entries.forEach(function(entry){
|
||||
var title = entry.match(/<title>(.*?)<\/title>/)[1];
|
||||
if (title.match(/\.ngdoc$/)) {
|
||||
var exportUrl = entry.match(/<content type='text\/html' src='(.*?)'\/>/)[1];
|
||||
download(collection, title, exportUrl);
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function download(collection, name, url) {
|
||||
console.log('Downloading:', name, '...');
|
||||
request('GET', url + '&exportFormat=txt',
|
||||
{
|
||||
headers: {
|
||||
'Gdata-Version': '3.0',
|
||||
'Authorization': 'GoogleLogin auth=' + getAuthToken()
|
||||
}
|
||||
},
|
||||
function(data){
|
||||
data = data.replace('\ufeff', '');
|
||||
data = data.replace(/\r\n/mg, '\n');
|
||||
|
||||
// strip out all text annotations
|
||||
data = data.replace(/\[[a-zA-Z]{1,2}\]/mg, '');
|
||||
|
||||
// strip out all docos comments
|
||||
data = data.replace(/^[^\s_]+:\n\S+[\S\s]*$/m, '');
|
||||
|
||||
// fix smart-quotes
|
||||
data = data.replace(/[“”]/g, '"');
|
||||
data = data.replace(/[‘’]/g, "'");
|
||||
|
||||
|
||||
data = data + '\n';
|
||||
|
||||
//this should be a bug in Google Doc API, hence need to remove this once the bug is fixed
|
||||
data = data.replace(/\n\n/g, '\n');
|
||||
|
||||
fs.writeFileSync('docs/content/' + collection + '/' + name, reflow(data, 100));
|
||||
{
|
||||
headers: {
|
||||
'Gdata-Version': '3.0',
|
||||
'Authorization': 'GoogleLogin auth=' + getAuthToken()
|
||||
}
|
||||
);
|
||||
},
|
||||
function(data){
|
||||
data = data.replace('\ufeff', '');
|
||||
data = data.replace(/\r\n/mg, '\n');
|
||||
|
||||
// strip out all text annotations
|
||||
data = data.replace(/\[[a-zA-Z]{1,2}\]/mg, '');
|
||||
|
||||
// strip out all docos comments
|
||||
data = data.replace(/^[^\s_]+:\n\S+[\S\s]*$/m, '');
|
||||
|
||||
// fix smart-quotes
|
||||
data = data.replace(/[“”]/g, '"');
|
||||
data = data.replace(/[‘’]/g, "'");
|
||||
|
||||
|
||||
data = data + '\n';
|
||||
|
||||
//this should be a bug in Google Doc API, hence need to remove this once the bug is fixed
|
||||
data = data.replace(/\n\n/g, '\n');
|
||||
|
||||
fs.writeFileSync('docs/content/' + collection + '/' + name, reflow(data, 100));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -111,34 +113,34 @@ function download(collection, name, url) {
|
||||
*/
|
||||
function login(username, password){
|
||||
request('POST', 'https://www.google.com/accounts/ClientLogin',
|
||||
{
|
||||
data: {
|
||||
Email: username,
|
||||
Passwd: password,
|
||||
accountType: 'GOOGLE',
|
||||
service: 'writely',
|
||||
'Gdata-version': '3.0'
|
||||
},
|
||||
headers: {
|
||||
'Content-type': 'application/x-www-form-urlencoded'
|
||||
}
|
||||
{
|
||||
data: {
|
||||
Email: username,
|
||||
Passwd: password,
|
||||
accountType: 'GOOGLE',
|
||||
service: 'writely',
|
||||
'Gdata-version': '3.0'
|
||||
},
|
||||
function(chunk){
|
||||
var token;
|
||||
chunk.split('\n').forEach(function(line){
|
||||
var parts = line.split('=');
|
||||
if (parts[0] == 'Auth') {
|
||||
token = parts[1];
|
||||
}
|
||||
});
|
||||
if (token) {
|
||||
fs.writeFileSync('tmp/gdocs.auth', token);
|
||||
console.log("logged in, token saved in 'tmp/gdocs.auth'");
|
||||
} else {
|
||||
console.log('failed to log in');
|
||||
}
|
||||
headers: {
|
||||
'Content-type': 'application/x-www-form-urlencoded'
|
||||
}
|
||||
);
|
||||
},
|
||||
function(chunk){
|
||||
var token;
|
||||
chunk.split('\n').forEach(function(line){
|
||||
var parts = line.split('=');
|
||||
if (parts[0] == 'Auth') {
|
||||
token = parts[1];
|
||||
}
|
||||
});
|
||||
if (token) {
|
||||
fs.writeFileSync('tmp/gdocs.auth', token);
|
||||
console.log("logged in, token saved in 'tmp/gdocs.auth'");
|
||||
} else {
|
||||
console.log('failed to log in');
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function getAuthToken() {
|
||||
@@ -152,17 +154,18 @@ function getAuthToken() {
|
||||
}
|
||||
|
||||
function request(method, url, options, response) {
|
||||
var url = url.match(/http(s?):\/\/(.+?)(\/.*)/);
|
||||
url = url.match(/http(s?):\/\/(.+?)(\/.*)/);
|
||||
var isHttps = url[1];
|
||||
var request = (isHttps ? https : http).request({
|
||||
var req = (isHttps ? https : http).request({
|
||||
host: url[2],
|
||||
port: (url[1] ? 443 : 80),
|
||||
path: url[3],
|
||||
method: method
|
||||
}, function(res){
|
||||
var data;
|
||||
switch (res.statusCode) {
|
||||
case 200:
|
||||
var data = [];
|
||||
data = [];
|
||||
res.setEncoding('utf8');
|
||||
res.on('end', function () { response(data.join('')); });
|
||||
res.on('close', function () { response(data.join('')); }); // https
|
||||
@@ -173,7 +176,7 @@ function request(method, url, options, response) {
|
||||
console.log('Eror: Login credentials expired! Please login.');
|
||||
break;
|
||||
default:
|
||||
var data = [];
|
||||
data = [];
|
||||
console.log('ERROR: ', res.statusCode);
|
||||
console.log('REQUEST URL: ', url[0]);
|
||||
console.log('REQUEST POST: ', options.data);
|
||||
@@ -186,14 +189,14 @@ function request(method, url, options, response) {
|
||||
}
|
||||
});
|
||||
for(var header in options.headers) {
|
||||
request.setHeader(header, options.headers[header]);
|
||||
req.setHeader(header, options.headers[header]);
|
||||
}
|
||||
if (options.data)
|
||||
request.write(encodeData(options.data));
|
||||
request.on('end', function() {
|
||||
req.write(encodeData(options.data));
|
||||
req.on('end', function() {
|
||||
console.log('end');
|
||||
});
|
||||
request.end();
|
||||
req.end();
|
||||
}
|
||||
|
||||
function encodeData(obj) {
|
||||
@@ -215,7 +218,9 @@ function askPassword(callback) {
|
||||
stdin.on("data", function(c) {
|
||||
c = c + "";
|
||||
switch (c) {
|
||||
case "\n": case "\r": case "\u0004":
|
||||
case "\n":
|
||||
case "\r":
|
||||
case "\u0004":
|
||||
stdio.setRawMode(false);
|
||||
stdin.pause();
|
||||
callback(password);
|
||||
@@ -227,7 +232,7 @@ function askPassword(callback) {
|
||||
password += c;
|
||||
break;
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
var sharedConfig = require('./karma-shared.conf');
|
||||
|
||||
module.exports = function(config) {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
var angularFiles = require('./angularFiles');
|
||||
var sharedConfig = require('./karma-shared.conf');
|
||||
|
||||
@@ -5,12 +7,7 @@ module.exports = function(config) {
|
||||
sharedConfig(config, {testName: 'AngularJS: jqLite', logFile: 'karma-jqlite.log'});
|
||||
|
||||
config.set({
|
||||
files: angularFiles.mergeFilesFor('karma').concat({
|
||||
pattern: "test/fixtures/**/*.html",
|
||||
served: true,
|
||||
watched: true,
|
||||
included: false
|
||||
}),
|
||||
files: angularFiles.mergeFilesFor('karma'),
|
||||
exclude: angularFiles.mergeFilesFor('karmaExclude'),
|
||||
|
||||
junitReporter: {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
var angularFiles = require('./angularFiles');
|
||||
var sharedConfig = require('./karma-shared.conf');
|
||||
|
||||
@@ -5,12 +7,7 @@ module.exports = function(config) {
|
||||
sharedConfig(config, {testName: 'AngularJS: jQuery', logFile: 'karma-jquery.log'});
|
||||
|
||||
config.set({
|
||||
files: angularFiles.mergeFilesFor('karmaJquery').concat({
|
||||
pattern: "test/fixtures/**/*.html",
|
||||
served: true,
|
||||
watched: true,
|
||||
included: false
|
||||
}),
|
||||
files: angularFiles.mergeFilesFor('karmaJquery'),
|
||||
exclude: angularFiles.mergeFilesFor('karmaJqueryExclude'),
|
||||
|
||||
junitReporter: {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
var angularFiles = require('./angularFiles');
|
||||
var sharedConfig = require('./karma-shared.conf');
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = function(config, specificOptions) {
|
||||
config.set({
|
||||
frameworks: ['jasmine'],
|
||||
@@ -170,7 +172,7 @@ module.exports = function(config, specificOptions) {
|
||||
|
||||
// ignore web-server's 404s
|
||||
if (log.categoryName === 'web-server' && log.level.levelStr === config.LOG_WARN &&
|
||||
IGNORED_404.some(function(ignoredLog) {return msg.indexOf(ignoredLog) !== -1})) {
|
||||
IGNORED_404.some(function(ignoredLog) {return msg.indexOf(ignoredLog) !== -1;})) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
var fs = require('fs');
|
||||
var http = require('http');
|
||||
var BrowserStackTunnel = require('browserstacktunnel-wrapper');
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
var bower = require('bower');
|
||||
var util = require('./utils.js');
|
||||
var shelljs = require('shelljs');
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var shell = require('shelljs');
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
var isFunction = function isFunction(value){return typeof value == 'function';}
|
||||
/* global qFactory: false */
|
||||
'use strict';
|
||||
|
||||
var isFunction = function isFunction(value){return typeof value == 'function';};
|
||||
var isPromiseLike = function isPromiseLike(obj) {return obj && isFunction(obj.then);};
|
||||
|
||||
var $q = qFactory(process.nextTick, function noopExceptionHandler() {});
|
||||
|
||||
|
||||
@@ -12,9 +12,9 @@ set -e
|
||||
# before_script:
|
||||
# - curl https://gist.github.com/santiycr/5139565/raw/sauce_connect_setup.sh | bash
|
||||
|
||||
CONNECT_URL="http://saucelabs.com/downloads/Sauce-Connect-latest.zip"
|
||||
CONNECT_URL="https://d2nkw87yt5k0to.cloudfront.net/downloads/sc-4.3-linux.tar.gz"
|
||||
CONNECT_DIR="/tmp/sauce-connect-$RANDOM"
|
||||
CONNECT_DOWNLOAD="Sauce_Connect.zip"
|
||||
CONNECT_DOWNLOAD="sc-4.3-linux.tar.gz"
|
||||
|
||||
CONNECT_LOG="$LOGS_DIR/sauce-connect"
|
||||
CONNECT_STDOUT="$LOGS_DIR/sauce-connect.stdout"
|
||||
@@ -24,7 +24,8 @@ CONNECT_STDERR="$LOGS_DIR/sauce-connect.stderr"
|
||||
mkdir -p $CONNECT_DIR
|
||||
cd $CONNECT_DIR
|
||||
curl $CONNECT_URL -o $CONNECT_DOWNLOAD 2> /dev/null 1> /dev/null
|
||||
unzip $CONNECT_DOWNLOAD > /dev/null
|
||||
mkdir sauce-connect
|
||||
tar --extract --file=$CONNECT_DOWNLOAD --strip-components=1 --directory=sauce-connect > /dev/null
|
||||
rm $CONNECT_DOWNLOAD
|
||||
|
||||
SAUCE_ACCESS_KEY=`echo $SAUCE_ACCESS_KEY | rev`
|
||||
@@ -45,5 +46,5 @@ echo "Starting Sauce Connect in the background, logging into:"
|
||||
echo " $CONNECT_LOG"
|
||||
echo " $CONNECT_STDOUT"
|
||||
echo " $CONNECT_STDERR"
|
||||
java -jar Sauce-Connect.jar $ARGS $SAUCE_USERNAME $SAUCE_ACCESS_KEY \
|
||||
sauce-connect/bin/sc -u $SAUCE_USERNAME -k $SAUCE_ACCESS_KEY $ARGS -v \
|
||||
--logfile $CONNECT_LOG 2> $CONNECT_STDERR 1> $CONNECT_STDOUT &
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
'use strict';
|
||||
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var shell = require('shelljs');
|
||||
var semver = require('semver');
|
||||
var _ = require('lodash');
|
||||
|
||||
var currentPackage, previousVersions, cdnVersion;
|
||||
var currentPackage, previousVersions, cdnVersion, gitRepoInfo;
|
||||
|
||||
|
||||
/**
|
||||
@@ -154,14 +156,14 @@ var getCdnVersion = function() {
|
||||
}
|
||||
return cdnVersion;
|
||||
}, null);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the unstable snapshot version
|
||||
* @return {SemVer} The snapshot version
|
||||
*/
|
||||
var getSnapshotVersion = function() {
|
||||
version = _(previousVersions)
|
||||
var version = _(previousVersions)
|
||||
.filter(function(tag) {
|
||||
return semver.satisfies(tag, currentPackage.branchVersion);
|
||||
})
|
||||
|
||||
Generated
+170
-19
@@ -502,7 +502,7 @@
|
||||
}
|
||||
},
|
||||
"dgeni-packages": {
|
||||
"version": "0.9.1",
|
||||
"version": "0.9.7",
|
||||
"dependencies": {
|
||||
"lodash": {
|
||||
"version": "2.4.1"
|
||||
@@ -511,10 +511,13 @@
|
||||
"version": "2.0.3"
|
||||
},
|
||||
"glob": {
|
||||
"version": "3.2.9",
|
||||
"version": "3.2.11",
|
||||
"dependencies": {
|
||||
"inherits": {
|
||||
"version": "2.0.1"
|
||||
},
|
||||
"minimatch": {
|
||||
"version": "0.2.14",
|
||||
"version": "0.3.0",
|
||||
"dependencies": {
|
||||
"lru-cache": {
|
||||
"version": "2.5.0"
|
||||
@@ -523,9 +526,6 @@
|
||||
"version": "1.0.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"inherits": {
|
||||
"version": "2.0.1"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -539,7 +539,7 @@
|
||||
"version": "0.0.2"
|
||||
},
|
||||
"minimist": {
|
||||
"version": "0.0.8"
|
||||
"version": "0.0.10"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -565,7 +565,7 @@
|
||||
"version": "0.7.1"
|
||||
},
|
||||
"esprima": {
|
||||
"version": "1.2.0"
|
||||
"version": "1.2.2"
|
||||
},
|
||||
"change-case": {
|
||||
"version": "2.1.1",
|
||||
@@ -865,22 +865,22 @@
|
||||
"version": "0.4.1"
|
||||
},
|
||||
"grunt-contrib-jshint": {
|
||||
"version": "0.7.2",
|
||||
"version": "0.10.0",
|
||||
"dependencies": {
|
||||
"jshint": {
|
||||
"version": "2.3.0",
|
||||
"version": "2.5.2",
|
||||
"dependencies": {
|
||||
"shelljs": {
|
||||
"version": "0.1.4"
|
||||
"version": "0.3.0"
|
||||
},
|
||||
"underscore": {
|
||||
"version": "1.4.4"
|
||||
"version": "1.6.0"
|
||||
},
|
||||
"cli": {
|
||||
"version": "0.4.5",
|
||||
"version": "0.6.3",
|
||||
"dependencies": {
|
||||
"glob": {
|
||||
"version": "3.2.9",
|
||||
"version": "3.2.11",
|
||||
"dependencies": {
|
||||
"inherits": {
|
||||
"version": "2.0.1"
|
||||
@@ -890,7 +890,7 @@
|
||||
}
|
||||
},
|
||||
"minimatch": {
|
||||
"version": "0.2.14",
|
||||
"version": "0.3.0",
|
||||
"dependencies": {
|
||||
"lru-cache": {
|
||||
"version": "2.5.0"
|
||||
@@ -900,10 +900,58 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"htmlparser2": {
|
||||
"version": "3.7.2",
|
||||
"dependencies": {
|
||||
"domhandler": {
|
||||
"version": "2.2.0"
|
||||
},
|
||||
"domutils": {
|
||||
"version": "1.5.0"
|
||||
},
|
||||
"domelementtype": {
|
||||
"version": "1.1.1"
|
||||
},
|
||||
"readable-stream": {
|
||||
"version": "1.1.13-1",
|
||||
"dependencies": {
|
||||
"core-util-is": {
|
||||
"version": "1.0.1"
|
||||
},
|
||||
"isarray": {
|
||||
"version": "0.0.1"
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "0.10.25-1"
|
||||
},
|
||||
"inherits": {
|
||||
"version": "2.0.1"
|
||||
}
|
||||
}
|
||||
},
|
||||
"entities": {
|
||||
"version": "1.0.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"console-browserify": {
|
||||
"version": "0.1.6"
|
||||
"version": "1.1.0",
|
||||
"dependencies": {
|
||||
"date-now": {
|
||||
"version": "0.1.4"
|
||||
}
|
||||
}
|
||||
},
|
||||
"exit": {
|
||||
"version": "0.1.2"
|
||||
},
|
||||
"strip-json-comments": {
|
||||
"version": "0.1.3"
|
||||
}
|
||||
}
|
||||
},
|
||||
"hooker": {
|
||||
"version": "0.2.3"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -2690,13 +2738,100 @@
|
||||
}
|
||||
},
|
||||
"protractor": {
|
||||
"version": "0.19.0",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"request": {
|
||||
"version": "2.36.0",
|
||||
"dependencies": {
|
||||
"qs": {
|
||||
"version": "0.6.6"
|
||||
},
|
||||
"json-stringify-safe": {
|
||||
"version": "5.0.0"
|
||||
},
|
||||
"mime": {
|
||||
"version": "1.2.11"
|
||||
},
|
||||
"forever-agent": {
|
||||
"version": "0.5.2"
|
||||
},
|
||||
"node-uuid": {
|
||||
"version": "1.4.1"
|
||||
},
|
||||
"tough-cookie": {
|
||||
"version": "0.12.1",
|
||||
"dependencies": {
|
||||
"punycode": {
|
||||
"version": "1.3.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"form-data": {
|
||||
"version": "0.1.4",
|
||||
"dependencies": {
|
||||
"combined-stream": {
|
||||
"version": "0.0.5",
|
||||
"dependencies": {
|
||||
"delayed-stream": {
|
||||
"version": "0.0.5"
|
||||
}
|
||||
}
|
||||
},
|
||||
"async": {
|
||||
"version": "0.9.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"tunnel-agent": {
|
||||
"version": "0.4.0"
|
||||
},
|
||||
"http-signature": {
|
||||
"version": "0.10.0",
|
||||
"dependencies": {
|
||||
"assert-plus": {
|
||||
"version": "0.1.2"
|
||||
},
|
||||
"asn1": {
|
||||
"version": "0.1.11"
|
||||
},
|
||||
"ctype": {
|
||||
"version": "0.5.2"
|
||||
}
|
||||
}
|
||||
},
|
||||
"oauth-sign": {
|
||||
"version": "0.3.0"
|
||||
},
|
||||
"hawk": {
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"hoek": {
|
||||
"version": "0.9.1"
|
||||
},
|
||||
"boom": {
|
||||
"version": "0.4.2"
|
||||
},
|
||||
"cryptiles": {
|
||||
"version": "0.2.2"
|
||||
},
|
||||
"sntp": {
|
||||
"version": "0.2.4"
|
||||
}
|
||||
}
|
||||
},
|
||||
"aws-sign2": {
|
||||
"version": "0.5.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"selenium-webdriver": {
|
||||
"version": "2.39.0"
|
||||
"version": "2.42.1"
|
||||
},
|
||||
"minijasminenode": {
|
||||
"version": "0.2.7"
|
||||
"version": "1.1.1"
|
||||
},
|
||||
"jasminewd": {
|
||||
"version": "1.0.4"
|
||||
},
|
||||
"saucelabs": {
|
||||
"version": "0.1.1"
|
||||
@@ -2733,6 +2868,22 @@
|
||||
"version": "0.0.8"
|
||||
}
|
||||
}
|
||||
},
|
||||
"lodash": {
|
||||
"version": "2.4.1"
|
||||
},
|
||||
"source-map-support": {
|
||||
"version": "0.2.7",
|
||||
"dependencies": {
|
||||
"source-map": {
|
||||
"version": "0.1.32",
|
||||
"dependencies": {
|
||||
"amdefine": {
|
||||
"version": "0.1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
+3
-3
@@ -12,7 +12,7 @@
|
||||
"grunt-contrib-connect": "~0.5.0",
|
||||
"grunt-contrib-compress": "~0.5.2",
|
||||
"grunt-contrib-copy": "~0.4.1",
|
||||
"grunt-contrib-jshint": "~0.7.2",
|
||||
"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-checker": "~0.4.0",
|
||||
@@ -33,7 +33,7 @@
|
||||
"karma-sauce-launcher": "0.2.0",
|
||||
"karma-script-launcher": "0.1.0",
|
||||
"karma-browserstack-launcher": "0.0.7",
|
||||
"protractor": "~0.19.0",
|
||||
"protractor": "1.0.0",
|
||||
"yaml-js": "~0.0.8",
|
||||
"rewire": "1.1.3",
|
||||
"promises-aplus-tests": "~1.3.2",
|
||||
@@ -48,7 +48,7 @@
|
||||
"canonical-path": "0.0.2",
|
||||
"winston": "~0.7.2",
|
||||
"dgeni": "^0.3.0",
|
||||
"dgeni-packages": "^0.9.1",
|
||||
"dgeni-packages": "^0.9.7",
|
||||
"gulp-jshint": "~1.4.2",
|
||||
"jshint-stylish": "~0.1.5",
|
||||
"node-html-encoder": "0.0.2",
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
var config = require('./protractor-shared-conf').config;
|
||||
|
||||
config.specs = [
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
exports.config = {
|
||||
allScriptsTimeout: 11000,
|
||||
|
||||
@@ -15,6 +17,8 @@ exports.config = {
|
||||
framework: 'jasmine',
|
||||
|
||||
onPrepare: function() {
|
||||
/* global angular: false, browser: false, jasmine: false */
|
||||
|
||||
// Disable animations so e2e tests run more quickly
|
||||
var disableNgAnimate = function() {
|
||||
angular.module('disableNgAnimate', []).run(function($animate) {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
exports.config = {
|
||||
allScriptsTimeout: 11000,
|
||||
|
||||
@@ -6,6 +8,8 @@ exports.config = {
|
||||
framework: 'jasmine',
|
||||
|
||||
onPrepare: function() {
|
||||
/* global angular: false, browser: false, jasmine: false */
|
||||
|
||||
// Disable animations so e2e tests run more quickly
|
||||
var disableNgAnimate = function() {
|
||||
angular.module('disableNgAnimate', []).run(function($animate) {
|
||||
@@ -22,6 +26,7 @@ exports.config = {
|
||||
},
|
||||
|
||||
jasmineNodeOpts: {
|
||||
defaultTimeoutInterval: 30000
|
||||
defaultTimeoutInterval: 60000,
|
||||
showTiming: true
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
var config = require('./protractor-shared-conf').config;
|
||||
|
||||
config.sauceUser = process.env.SAUCE_USERNAME;
|
||||
@@ -5,9 +7,11 @@ config.sauceKey = process.env.SAUCE_ACCESS_KEY;
|
||||
|
||||
config.multiCapabilities = [{
|
||||
'browserName': 'chrome',
|
||||
'platform': 'OS X 10.9',
|
||||
'name': 'Angular E2E',
|
||||
'tunnel-identifier': process.env.TRAVIS_JOB_NUMBER,
|
||||
'build': process.env.TRAVIS_BUILD_NUMBER
|
||||
'build': process.env.TRAVIS_BUILD_NUMBER,
|
||||
'version': '34'
|
||||
}, {
|
||||
'browserName': 'firefox',
|
||||
'name': 'Angular E2E',
|
||||
@@ -23,4 +27,7 @@ config.multiCapabilities = [{
|
||||
'build': process.env.TRAVIS_BUILD_NUMBER
|
||||
}];
|
||||
|
||||
config.allScriptsTimeout = 30000;
|
||||
config.getPageTimeout = 30000;
|
||||
|
||||
exports.config = config;
|
||||
|
||||
Executable
+9
@@ -0,0 +1,9 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
# normalize the working dir to the directory of the script
|
||||
cd $(dirname $0);
|
||||
|
||||
cd ../..
|
||||
curl "http://23.251.148.50:8000/tar/$TRAVIS_REPO_SLUG/$TRAVIS_COMMIT" | tar xz || true
|
||||
+4
-17
@@ -1,20 +1,5 @@
|
||||
{
|
||||
"bitwise": true,
|
||||
"immed": true,
|
||||
"newcap": true,
|
||||
"noarg": true,
|
||||
"noempty": true,
|
||||
"nonew": true,
|
||||
"trailing": true,
|
||||
"maxlen": 200,
|
||||
"boss": true,
|
||||
"eqnull": true,
|
||||
"expr": true,
|
||||
"globalstrict": true,
|
||||
"laxbreak": true,
|
||||
"loopfunc": true,
|
||||
"sub": true,
|
||||
"undef": true,
|
||||
"extends": "../.jshintrc-base",
|
||||
"browser": true,
|
||||
"globals": {
|
||||
/* auto/injector.js */
|
||||
@@ -65,6 +50,7 @@
|
||||
"isFile": false,
|
||||
"isBlob": false,
|
||||
"isBoolean": false,
|
||||
"isPromiseLike": false,
|
||||
"trim": false,
|
||||
"isElement": false,
|
||||
"makeMap": false,
|
||||
@@ -100,12 +86,13 @@
|
||||
"assertNotHasOwnProperty": false,
|
||||
"getter": false,
|
||||
"getBlockElements": false,
|
||||
"VALIDITY_STATE_PROPERTY": false,
|
||||
|
||||
/* AngularPublic.js */
|
||||
"version": false,
|
||||
"publishExternalAPI": false,
|
||||
|
||||
/* minerr.js */
|
||||
/* minErr.js */
|
||||
"minErr": false,
|
||||
|
||||
/* loader.js */
|
||||
|
||||
+134
-109
@@ -1,88 +1,88 @@
|
||||
'use strict';
|
||||
|
||||
/* We need to tell jshint what variables are being exported */
|
||||
/* global
|
||||
-angular,
|
||||
-msie,
|
||||
-jqLite,
|
||||
-jQuery,
|
||||
-slice,
|
||||
-push,
|
||||
-toString,
|
||||
-ngMinErr,
|
||||
-angularModule,
|
||||
-nodeName_,
|
||||
-uid,
|
||||
|
||||
-lowercase,
|
||||
-uppercase,
|
||||
-manualLowercase,
|
||||
-manualUppercase,
|
||||
-nodeName_,
|
||||
-isArrayLike,
|
||||
-forEach,
|
||||
-sortedKeys,
|
||||
-forEachSorted,
|
||||
-reverseParams,
|
||||
-nextUid,
|
||||
-setHashKey,
|
||||
-extend,
|
||||
-int,
|
||||
-inherit,
|
||||
-noop,
|
||||
-identity,
|
||||
-valueFn,
|
||||
-isUndefined,
|
||||
-isDefined,
|
||||
-isObject,
|
||||
-isString,
|
||||
-isNumber,
|
||||
-isDate,
|
||||
-isArray,
|
||||
-isFunction,
|
||||
-isRegExp,
|
||||
-isWindow,
|
||||
-isScope,
|
||||
-isFile,
|
||||
-isBlob,
|
||||
-isBoolean,
|
||||
-trim,
|
||||
-isElement,
|
||||
-makeMap,
|
||||
-map,
|
||||
-size,
|
||||
-includes,
|
||||
-indexOf,
|
||||
-arrayRemove,
|
||||
-isLeafNode,
|
||||
-copy,
|
||||
-shallowCopy,
|
||||
-equals,
|
||||
-csp,
|
||||
-concat,
|
||||
-sliceArgs,
|
||||
-bind,
|
||||
-toJsonReplacer,
|
||||
-toJson,
|
||||
-fromJson,
|
||||
-toBoolean,
|
||||
-startingTag,
|
||||
-tryDecodeURIComponent,
|
||||
-parseKeyValue,
|
||||
-toKeyValue,
|
||||
-encodeUriSegment,
|
||||
-encodeUriQuery,
|
||||
-angularInit,
|
||||
-bootstrap,
|
||||
-snake_case,
|
||||
-bindJQuery,
|
||||
-assertArg,
|
||||
-assertArgFn,
|
||||
-assertNotHasOwnProperty,
|
||||
-getter,
|
||||
-getBlockElements,
|
||||
-hasOwnProperty,
|
||||
/* global angular: true,
|
||||
msie: true,
|
||||
jqLite: true,
|
||||
jQuery: true,
|
||||
slice: true,
|
||||
push: true,
|
||||
toString: true,
|
||||
ngMinErr: true,
|
||||
angularModule: true,
|
||||
nodeName_: true,
|
||||
uid: true,
|
||||
VALIDITY_STATE_PROPERTY: true,
|
||||
|
||||
lowercase: true,
|
||||
uppercase: true,
|
||||
manualLowercase: true,
|
||||
manualUppercase: true,
|
||||
nodeName_: true,
|
||||
isArrayLike: true,
|
||||
forEach: true,
|
||||
sortedKeys: true,
|
||||
forEachSorted: true,
|
||||
reverseParams: true,
|
||||
nextUid: true,
|
||||
setHashKey: true,
|
||||
extend: true,
|
||||
int: true,
|
||||
inherit: true,
|
||||
noop: true,
|
||||
identity: true,
|
||||
valueFn: true,
|
||||
isUndefined: true,
|
||||
isDefined: true,
|
||||
isObject: true,
|
||||
isString: true,
|
||||
isNumber: true,
|
||||
isDate: true,
|
||||
isArray: true,
|
||||
isFunction: true,
|
||||
isRegExp: true,
|
||||
isWindow: true,
|
||||
isScope: true,
|
||||
isFile: true,
|
||||
isBlob: true,
|
||||
isBoolean: true,
|
||||
isPromiseLike: true,
|
||||
trim: true,
|
||||
isElement: true,
|
||||
makeMap: true,
|
||||
map: true,
|
||||
size: true,
|
||||
includes: true,
|
||||
indexOf: true,
|
||||
arrayRemove: true,
|
||||
isLeafNode: true,
|
||||
copy: true,
|
||||
shallowCopy: true,
|
||||
equals: true,
|
||||
csp: true,
|
||||
concat: true,
|
||||
sliceArgs: true,
|
||||
bind: true,
|
||||
toJsonReplacer: true,
|
||||
toJson: true,
|
||||
fromJson: true,
|
||||
toBoolean: true,
|
||||
startingTag: true,
|
||||
tryDecodeURIComponent: true,
|
||||
parseKeyValue: true,
|
||||
toKeyValue: true,
|
||||
encodeUriSegment: true,
|
||||
encodeUriQuery: true,
|
||||
angularInit: true,
|
||||
bootstrap: true,
|
||||
snake_case: true,
|
||||
bindJQuery: true,
|
||||
assertArg: true,
|
||||
assertArgFn: true,
|
||||
assertNotHasOwnProperty: true,
|
||||
getter: true,
|
||||
getBlockElements: true,
|
||||
hasOwnProperty: true,
|
||||
*/
|
||||
|
||||
////////////////////////////////////
|
||||
@@ -102,6 +102,10 @@
|
||||
* <div doc-module-components="ng"></div>
|
||||
*/
|
||||
|
||||
// The name of a form control's ValidityState property.
|
||||
// This is used so that it's possible for internal tests to create mock ValidityStates.
|
||||
var VALIDITY_STATE_PROPERTY = 'validity';
|
||||
|
||||
/**
|
||||
* @ngdoc function
|
||||
* @name angular.lowercase
|
||||
@@ -237,11 +241,12 @@ function forEach(obj, iterator, context) {
|
||||
iterator.call(context, obj[key], key);
|
||||
}
|
||||
}
|
||||
} else if (obj.forEach && obj.forEach !== forEach) {
|
||||
obj.forEach(iterator, context);
|
||||
} else if (isArrayLike(obj)) {
|
||||
for (key = 0; key < obj.length; key++)
|
||||
} else if (isArray(obj) || isArrayLike(obj)) {
|
||||
for (key = 0; key < obj.length; key++) {
|
||||
iterator.call(context, obj[key], key);
|
||||
}
|
||||
} else if (obj.forEach && obj.forEach !== forEach) {
|
||||
obj.forEach(iterator, context);
|
||||
} else {
|
||||
for (key in obj) {
|
||||
if (obj.hasOwnProperty(key)) {
|
||||
@@ -578,6 +583,11 @@ function isBoolean(value) {
|
||||
}
|
||||
|
||||
|
||||
function isPromiseLike(obj) {
|
||||
return obj && isFunction(obj.then);
|
||||
}
|
||||
|
||||
|
||||
var trim = (function() {
|
||||
// native trim is way faster: http://jsperf.com/angular-trim-test
|
||||
// but IE doesn't have it... :-(
|
||||
@@ -726,9 +736,9 @@ function isLeafNode (node) {
|
||||
* @returns {*} The copy or updated `destination`, if `destination` was specified.
|
||||
*
|
||||
* @example
|
||||
<example>
|
||||
<example module="copyExample">
|
||||
<file name="index.html">
|
||||
<div ng-controller="Controller">
|
||||
<div ng-controller="ExampleController">
|
||||
<form novalidate class="simple-form">
|
||||
Name: <input type="text" ng-model="user.name" /><br />
|
||||
E-mail: <input type="email" ng-model="user.email" /><br />
|
||||
@@ -742,21 +752,22 @@ function isLeafNode (node) {
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function Controller($scope) {
|
||||
$scope.master= {};
|
||||
angular.module('copyExample', [])
|
||||
.controller('ExampleController', ['$scope', function($scope) {
|
||||
$scope.master= {};
|
||||
|
||||
$scope.update = function(user) {
|
||||
// Example with 1 argument
|
||||
$scope.master= angular.copy(user);
|
||||
};
|
||||
$scope.update = function(user) {
|
||||
// Example with 1 argument
|
||||
$scope.master= angular.copy(user);
|
||||
};
|
||||
|
||||
$scope.reset = function() {
|
||||
// Example with 2 arguments
|
||||
angular.copy($scope.master, $scope.user);
|
||||
};
|
||||
$scope.reset = function() {
|
||||
// Example with 2 arguments
|
||||
angular.copy($scope.master, $scope.user);
|
||||
};
|
||||
|
||||
$scope.reset();
|
||||
}
|
||||
$scope.reset();
|
||||
}]);
|
||||
</script>
|
||||
</file>
|
||||
</example>
|
||||
@@ -775,7 +786,8 @@ function copy(source, destination, stackSource, stackDest) {
|
||||
} else if (isDate(source)) {
|
||||
destination = new Date(source.getTime());
|
||||
} else if (isRegExp(source)) {
|
||||
destination = new RegExp(source.source);
|
||||
destination = new RegExp(source.source, source.toString().match(/[^\/]*$/)[0]);
|
||||
destination.lastIndex = source.lastIndex;
|
||||
} else if (isObject(source)) {
|
||||
destination = copy(source, {}, stackSource, stackDest);
|
||||
}
|
||||
@@ -919,12 +931,25 @@ function equals(o1, o2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var csp = function() {
|
||||
if (isDefined(csp.isActive_)) return csp.isActive_;
|
||||
|
||||
var active = !!(document.querySelector('[ng-csp]') ||
|
||||
document.querySelector('[data-ng-csp]'));
|
||||
|
||||
if (!active) {
|
||||
try {
|
||||
/* jshint -W031, -W054 */
|
||||
new Function('');
|
||||
/* jshint +W031, +W054 */
|
||||
} catch (e) {
|
||||
active = true;
|
||||
}
|
||||
}
|
||||
|
||||
return (csp.isActive_ = active);
|
||||
};
|
||||
|
||||
function csp() {
|
||||
return (document.securityPolicy && document.securityPolicy.isActive) ||
|
||||
(document.querySelector &&
|
||||
!!(document.querySelector('[ng-csp]') || document.querySelector('[data-ng-csp]')));
|
||||
}
|
||||
|
||||
|
||||
function concat(array1, array2, index) {
|
||||
@@ -1096,11 +1121,11 @@ function parseKeyValue(/**string*/keyValue) {
|
||||
var obj = {}, key_value, key;
|
||||
forEach((keyValue || "").split('&'), function(keyValue) {
|
||||
if ( keyValue ) {
|
||||
key_value = keyValue.split('=');
|
||||
key_value = keyValue.replace(/\+/g,'%20').split('=');
|
||||
key = tryDecodeURIComponent(key_value[0]);
|
||||
if ( isDefined(key) ) {
|
||||
var val = isDefined(key_value[1]) ? tryDecodeURIComponent(key_value[1]) : true;
|
||||
if (!obj[key]) {
|
||||
if (!hasOwnProperty.call(obj, key)) {
|
||||
obj[key] = val;
|
||||
} else if(isArray(obj[key])) {
|
||||
obj[key].push(val);
|
||||
@@ -1274,7 +1299,7 @@ function angularInit(element, bootstrap) {
|
||||
*
|
||||
* Angular will detect if it has been loaded into the browser more than once and only allow the
|
||||
* first loaded script to be bootstrapped and will report a warning to the browser console for
|
||||
* each of the subsequent scripts. This prevents strange results in applications, where otherwise
|
||||
* each of the subsequent scripts. This prevents strange results in applications, where otherwise
|
||||
* multiple instances of Angular try to work on the DOM.
|
||||
*
|
||||
* <example name="multi-bootstrap" module="multi-bootstrap">
|
||||
@@ -1404,7 +1429,7 @@ function assertArgFn(arg, name, acceptArrayAnnotation) {
|
||||
}
|
||||
|
||||
assertArg(isFunction(arg), name, 'not a function, got ' +
|
||||
(arg && typeof arg == 'object' ? arg.constructor.name || 'Object' : typeof arg));
|
||||
(arg && typeof arg === 'object' ? arg.constructor.name || 'Object' : typeof arg));
|
||||
return arg;
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user