Compare commits
106 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9474ec120a | |||
| 09a9832358 | |||
| bf6a79c348 | |||
| 8ee8ffeba0 | |||
| 42d09f1772 | |||
| 8692f87a46 | |||
| 40406e2f22 | |||
| 4644c5840f | |||
| addb4bdd57 | |||
| 7496e8e5b7 | |||
| e9b9421cdb | |||
| 7a374691b9 | |||
| 3be6835e0f | |||
| a3d79775e1 | |||
| 920b595080 | |||
| 3109342679 | |||
| aa01be8b2c | |||
| bb4d3b73a1 | |||
| 6dbd606ad7 | |||
| 764fa869dd | |||
| 7812dfcee8 | |||
| 00b623e86b | |||
| 92f87b1142 | |||
| 5c1fdff691 | |||
| 891acf4c20 | |||
| 93552fed1c | |||
| b5fbd6a2f6 | |||
| 5c43b94fc4 | |||
| 7dd94b9595 | |||
| 95f8a8bab0 | |||
| dc5bba8615 | |||
| 16c8f29ef6 | |||
| d3fb8dd776 | |||
| 95e03bce7e | |||
| 5388ca5710 | |||
| 1b275fb00e | |||
| 1c68d00fbf | |||
| 158241e212 | |||
| eab271876c | |||
| 637d3b47d1 | |||
| 8ac369e829 | |||
| 5c611e898a | |||
| dc9775da96 | |||
| e8941c0fe5 | |||
| bb16759f0b | |||
| 2b41a5868a | |||
| 637c020f82 | |||
| f7fde935d5 | |||
| 5f552896ab | |||
| d5968c7853 | |||
| 4f4ff5f31b | |||
| e3764e30a3 | |||
| c9899c53ac | |||
| 4d4e6036a9 | |||
| 4d885cbd62 | |||
| eec2020518 | |||
| 2901c53f42 | |||
| e80053d91f | |||
| fa12c3c86a | |||
| cf43ccdf9b | |||
| a9352c19ce | |||
| 6f19a6fd33 | |||
| f30163e63a | |||
| 5b23bc9b07 | |||
| 9d1e87a3f1 | |||
| 6604c23614 | |||
| 195deca6e2 | |||
| 85eb9660ef | |||
| d81ff8885b | |||
| eca14d98a4 | |||
| 22ecbc50f4 | |||
| 7f857e44a2 | |||
| be6920b356 | |||
| 8eabc5463c | |||
| 14ff529fbb | |||
| fbad280570 | |||
| 8b775a0d58 | |||
| 0bbc6ee481 | |||
| 381b185117 | |||
| fa0d8c47c3 | |||
| 7e233eb58a | |||
| b7afd11d26 | |||
| 8582088b36 | |||
| 0db573b749 | |||
| 5e78af769e | |||
| 804e75045c | |||
| ebc3b7b1c3 | |||
| 830846f664 | |||
| 0462ee6659 | |||
| 9cc6835819 | |||
| ee1fc1dc13 | |||
| 41b36e689c | |||
| 52545e5a74 | |||
| 2abea7514a | |||
| f157d02793 | |||
| 77d8ae1d45 | |||
| e21b6ff3ff | |||
| 06016bb12c | |||
| 50e72fcae1 | |||
| b84e62bd28 | |||
| b6fd184a93 | |||
| 1db9e617ce | |||
| 0918f146e4 | |||
| 6dfd938bbc | |||
| 4f5a60bcca | |||
| e593939411 |
@@ -23,8 +23,16 @@
|
||||
"disallowTrailingWhitespace": true,
|
||||
"requireCommaBeforeLineBreak": true,
|
||||
"requireLineFeedAtFileEnd": true,
|
||||
"requireSpaceAfterBinaryOperators": ["?", ":", "+", "-", "/", "*", "%", "==", "===", "!=", "!==", ">", ">=", "<", "<=", "&&", "||"],
|
||||
"requireSpaceBeforeBinaryOperators": ["?", ":", "+", "-", "/", "*", "%", "==", "===", "!=", "!==", ">", ">=", "<", "<=", "&&", "||"],
|
||||
"requireSpaceAfterKeywords": ["if", "else", "for", "while", "do", "switch", "return", "try", "catch"],
|
||||
"requireSpaceBeforeBlockStatements": true,
|
||||
"requireSpacesInConditionalExpression": {
|
||||
"afterTest": true,
|
||||
"beforeConsequent": true,
|
||||
"afterConsequent": true,
|
||||
"beforeAlternate": true
|
||||
},
|
||||
"requireSpacesInFunction": {
|
||||
"beforeOpeningCurlyBrace": true
|
||||
},
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
|
||||
{
|
||||
"requireCurlyBraces": ["if", "else", "for", "while", "do", "try", "catch"],
|
||||
"requireSpaceAfterBinaryOperators": ["?", ":", "+", "-", "/", "*", "%", "==", "===", "!=", "!==", ">", ">=", "<", "<=", "&&", "||"],
|
||||
"requireSpaceBeforeBinaryOperators": ["?", ":", "+", "-", "/", "*", "%", "==", "===", "!=", "!==", ">", ">=", "<", "<=", "&&", "||"],
|
||||
"disallowImplicitTypeConversion": ["string"],
|
||||
"disallowMultipleLineBreaks": true,
|
||||
"disallowKeywordsOnNewLine": ["else"],
|
||||
|
||||
+235
@@ -1,3 +1,238 @@
|
||||
<a name="1.3.4"></a>
|
||||
# 1.3.4 highfalutin-petroglyph (2014-11-24)
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$browser:** allow chaining url() calls in setter mode
|
||||
([764fa869](https://github.com/angular/angular.js/commit/764fa869dd8809d494924c23f30ddaa4cac84249),
|
||||
[#10157](https://github.com/angular/angular.js/issues/10157))
|
||||
- **$http:** return empty headers, ignore properties in Object prototype
|
||||
([637c020f](https://github.com/angular/angular.js/commit/637c020f828a7ceeaacf83bb1a54ed3092e6c273),
|
||||
[#7779](https://github.com/angular/angular.js/issues/7779), [#10113](https://github.com/angular/angular.js/issues/10113), [#10091](https://github.com/angular/angular.js/issues/10091))
|
||||
- **$locale:** Allow currency filter to fall back to maxFrac from locale
|
||||
([6dbd606a](https://github.com/angular/angular.js/commit/6dbd606ad7b708d5886c0e7ffee20ae8f8719711),
|
||||
[#10179](https://github.com/angular/angular.js/issues/10179))
|
||||
- **$location:** allow empty string URLs to reset path, search, and hash
|
||||
([7812dfce](https://github.com/angular/angular.js/commit/7812dfcee8ab98cbf38261f9948d9541656bf554),
|
||||
[#10063](https://github.com/angular/angular.js/issues/10063), [#10064](https://github.com/angular/angular.js/issues/10064))
|
||||
- **$route:** fix redirection with optional/eager params
|
||||
([891acf4c](https://github.com/angular/angular.js/commit/891acf4c201823fd2c925ee321c70d06737d5944),
|
||||
[#9819](https://github.com/angular/angular.js/issues/9819), [#9827](https://github.com/angular/angular.js/issues/9827))
|
||||
- **Angular:** properly get node name for svg element wrapper
|
||||
([09a98323](https://github.com/angular/angular.js/commit/09a9832358960c98392c9df1a9fd9592f59bc844),
|
||||
[#10078](https://github.com/angular/angular.js/issues/10078), [#10172](https://github.com/angular/angular.js/issues/10172))
|
||||
- **NgModelController:** typo $rawModelValue -> $$rawModelValue
|
||||
([4f4ff5f3](https://github.com/angular/angular.js/commit/4f4ff5f31b82c6f7be409ea4edbad4c2913ac1f1))
|
||||
- **input:**
|
||||
- set ngTrueValue on required checkbox
|
||||
([8692f87a](https://github.com/angular/angular.js/commit/8692f87a4689fa0dd3640f4dcab5c6b6f960489b),
|
||||
[#5164](https://github.com/angular/angular.js/issues/5164))
|
||||
- call $setTouched in blur asynchronously if necessary
|
||||
([eab27187](https://github.com/angular/angular.js/commit/eab271876cb87c1f5f6c6f29e814fb8fecad87ff),
|
||||
[#8762](https://github.com/angular/angular.js/issues/8762), [#9808](https://github.com/angular/angular.js/issues/9808), [#10014](https://github.com/angular/angular.js/issues/10014))
|
||||
- **input[date]:** do not use `$isEmpty` to check the model validity
|
||||
([40406e2f](https://github.com/angular/angular.js/commit/40406e2f22713efbd37ef3eff408339727cb62d9))
|
||||
- **linky:** encode double quotes when serializing email addresses
|
||||
([8ee8ffeb](https://github.com/angular/angular.js/commit/8ee8ffeba0a5a133fa792745c1019d294ecfcef3),
|
||||
[#8945](https://github.com/angular/angular.js/issues/8945), [#8964](https://github.com/angular/angular.js/issues/8964), [#5946](https://github.com/angular/angular.js/issues/5946), [#10090](https://github.com/angular/angular.js/issues/10090), [#9256](https://github.com/angular/angular.js/issues/9256))
|
||||
- **ngMaxlength:** ignore maxlength when not set to a non-negative integer
|
||||
([92f87b11](https://github.com/angular/angular.js/commit/92f87b114242b01876e1dc5c6fddd061352ecb2c),
|
||||
[#9874](https://github.com/angular/angular.js/issues/9874))
|
||||
- **ngModel:** don't run parsers when executing $validate
|
||||
([e3764e30](https://github.com/angular/angular.js/commit/e3764e30a301ec6136c8e6b5493d39feb3cd1ecc))
|
||||
- **ngModelOptions:** preserve context of getter/setters
|
||||
([bb4d3b73](https://github.com/angular/angular.js/commit/bb4d3b73a1ccf3dee55b0c25baf031bae5cbb676),
|
||||
[#9394](https://github.com/angular/angular.js/issues/9394), [#9865](https://github.com/angular/angular.js/issues/9865))
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
- **ngMaxlength:** add support for disabling max length limit
|
||||
([5c1fdff6](https://github.com/angular/angular.js/commit/5c1fdff691b9367d73f72f6a0298cb6a6e259f35),
|
||||
[#9995](https://github.com/angular/angular.js/issues/9995))
|
||||
- **ngModelController:** add $setDirty method
|
||||
([e8941c0f](https://github.com/angular/angular.js/commit/e8941c0fe5217d2e705bad8253dc0162aff4c709),
|
||||
[#10038](https://github.com/angular/angular.js/issues/10038), [#10049](https://github.com/angular/angular.js/issues/10049))
|
||||
- **ngPluralize:** add support for `count` to be a one-time expression
|
||||
([2b41a586](https://github.com/angular/angular.js/commit/2b41a5868aee79e3872ad92db66e30959207d98e),
|
||||
[#10004](https://github.com/angular/angular.js/issues/10004))
|
||||
|
||||
|
||||
## Performance Improvements
|
||||
|
||||
- ***:** use Object.create instead of creating temporary constructors
|
||||
([bf6a79c3](https://github.com/angular/angular.js/commit/bf6a79c3484f474c300b5442ae73483030ef5782),
|
||||
[#10058](https://github.com/angular/angular.js/issues/10058))
|
||||
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
- **ngModelOptions:** due to [bb4d3b73](https://github.com/angular/angular.js/commit/bb4d3b73a1ccf3dee55b0c25baf031bae5cbb676),
|
||||
previously, ngModel invoked getter/setters in the global context.
|
||||
|
||||
For example:
|
||||
|
||||
```js
|
||||
<input ng-model="model.value" ng-model-options="{ getterSetter: true }">
|
||||
```
|
||||
|
||||
would previously invoke `model.value()` in the global context.
|
||||
|
||||
Now, ngModel invokes `value` with `model` as the context.
|
||||
|
||||
It's unlikely that real apps relied on this behavior. If they did they can use `.bind` to explicilty
|
||||
bind a getter/getter to the global context, or just reference globals normally without `this`.
|
||||
|
||||
|
||||
<a name="1.2.27"></a>
|
||||
# 1.2.27 prime-factorization (2014-11-20)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$animate:** clear the GCS cache even when no animation is detected
|
||||
([f619d032](https://github.com/angular/angular.js/commit/f619d032c932752313c646b5295bad8a68ef3871),
|
||||
[#8813](https://github.com/angular/angular.js/issues/8813))
|
||||
- **$browser:**
|
||||
- Cache `location.href` only during page reload phase
|
||||
([434d7a09](https://github.com/angular/angular.js/commit/434d7a09039151c1e627ac156213905d06b7df10),
|
||||
[#9235](https://github.com/angular/angular.js/issues/9235), [#9470](https://github.com/angular/angular.js/issues/9470))
|
||||
- don’t use history api when only the hash changes
|
||||
([a6e6438d](https://github.com/angular/angular.js/commit/a6e6438dae1ed92b29608d0b8830b0a7fbb624ef),
|
||||
[#9423](https://github.com/angular/angular.js/issues/9423), [#9424](https://github.com/angular/angular.js/issues/9424))
|
||||
- handle async href on url change in <=IE9
|
||||
([fe7d9ded](https://github.com/angular/angular.js/commit/fe7d9dedaa5ec3b3f56d9eb9c513cf99e40121ce),
|
||||
[#9235](https://github.com/angular/angular.js/issues/9235))
|
||||
- **$http:** add missing shortcut methods and missing docs
|
||||
([ec4fe1bc](https://github.com/angular/angular.js/commit/ec4fe1bcab6f981103a10f860a3a00122aa78607),
|
||||
[#9180](https://github.com/angular/angular.js/issues/9180), [#9321](https://github.com/angular/angular.js/issues/9321))
|
||||
- **$location:**
|
||||
- revert erroneous logic and backport refactorings from master
|
||||
([1ee9b4ef](https://github.com/angular/angular.js/commit/1ee9b4ef5e4a795061d3aa19adefdeb7e0209eeb),
|
||||
[#8492](https://github.com/angular/angular.js/issues/8492))
|
||||
- allow 0 in path() and hash()
|
||||
([f807d7ab](https://github.com/angular/angular.js/commit/f807d7ab4ebd18899154528ea9ed50d5bc25c57a))
|
||||
- **$parse:** add quick check for Function constructor in fast path
|
||||
([756640f5](https://github.com/angular/angular.js/commit/756640f5aa8f3fd0084bff50534e23976a6fff00))
|
||||
- **$parse, events:** prevent accidental misuse of properties on $event
|
||||
([4d0614fd](https://github.com/angular/angular.js/commit/4d0614fd0da12c5783dfb4956c330edac87e62fe),
|
||||
[#9969](https://github.com/angular/angular.js/issues/9969))
|
||||
- **ngMock:** $httpBackend should match data containing Date objects correctly
|
||||
([1426b029](https://github.com/angular/angular.js/commit/1426b02980badfd322eb960d71bfb1a14d657847),
|
||||
[#5127](https://github.com/angular/angular.js/issues/5127))
|
||||
- **orderBy:** sort by identity if no predicate is given
|
||||
([45b896a1](https://github.com/angular/angular.js/commit/45b896a16abbcbfcdfb9a95c2d10c76a805b57cc),
|
||||
[#5847](https://github.com/angular/angular.js/issues/5847), [#4579](https://github.com/angular/angular.js/issues/4579), [#9403](https://github.com/angular/angular.js/issues/9403))
|
||||
- **select:** ensure the label attribute is updated in Internet Explorer
|
||||
([16833d0f](https://github.com/angular/angular.js/commit/16833d0fb6585117e9978d1accc3ade83e22e797),
|
||||
[#9621](https://github.com/angular/angular.js/issues/9621), [#10042](https://github.com/angular/angular.js/issues/10042))
|
||||
|
||||
|
||||
## Performance Improvements
|
||||
|
||||
- **orderBy:** copy array with slice instead of for loop
|
||||
([409bcb38](https://github.com/angular/angular.js/commit/409bcb3810a1622178268f7ff7f4130887a1a3dc),
|
||||
[#9942](https://github.com/angular/angular.js/issues/9942))
|
||||
|
||||
|
||||
<a name="1.3.3"></a>
|
||||
# 1.3.3 undersea-arithmetic (2014-11-17)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$http:** don't parse single space responses as JSON
|
||||
([6f19a6fd](https://github.com/angular/angular.js/commit/6f19a6fd33ab72d3908e3418fba47ee8e1598fa6),
|
||||
[#9907](https://github.com/angular/angular.js/issues/9907))
|
||||
- **minErr:** stringify non-JSON compatible objects in error messages
|
||||
([cf43ccdf](https://github.com/angular/angular.js/commit/cf43ccdf9b8665a2fd5d6aa52f80cb2d7c9bb7e2),
|
||||
[#10085](https://github.com/angular/angular.js/issues/10085))
|
||||
- **$rootScope:** handle cyclic references in scopes when creating error messages
|
||||
([e80053d9](https://github.com/angular/angular.js/commit/e80053d91fd7c722e092a23d326384de2e552eb6),
|
||||
[#10085](https://github.com/angular/angular.js/issues/10085))
|
||||
- **ngRepeat:** support cyclic object references in error messages
|
||||
([fa12c3c8](https://github.com/angular/angular.js/commit/fa12c3c86af7965d1b9d9a5dd3434755e9e04635),
|
||||
[#9838](https://github.com/angular/angular.js/issues/9838), [#10065](https://github.com/angular/angular.js/issues/10065), [#10085](https://github.com/angular/angular.js/issues/10085))
|
||||
- **ngMock:** call $interval callbacks even when invokeApply is false
|
||||
([d81ff888](https://github.com/angular/angular.js/commit/d81ff8885b77f70c6417d7be3124d86d07447375),
|
||||
[#10032](https://github.com/angular/angular.js/issues/10032))
|
||||
- **ngPattern:** match behaviour of native HTML pattern attribute
|
||||
([85eb9660](https://github.com/angular/angular.js/commit/85eb9660ef67c24d5104a6a1921bedad0bd1b57e),
|
||||
[#9881](https://github.com/angular/angular.js/issues/9881), [#9888](https://github.com/angular/angular.js/issues/9888))
|
||||
- **select:** ensure the label attribute is updated in Internet Explorer
|
||||
([6604c236](https://github.com/angular/angular.js/commit/6604c2361427fba8c43a39dc2e92197390dfbdbe),
|
||||
[#9621](https://github.com/angular/angular.js/issues/9621), [#10042](https://github.com/angular/angular.js/issues/10042))
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
- **$location:** allow to location to be changed during $locationChangeStart
|
||||
([a9352c19](https://github.com/angular/angular.js/commit/a9352c19ce33f0393d6581547c7ea8dfc2a8b78f),
|
||||
[#9607](https://github.com/angular/angular.js/issues/9607), [#9678](https://github.com/angular/angular.js/issues/9678))
|
||||
- **$routeProvider:** allow setting caseInsensitiveMatch on the provider
|
||||
([0db573b7](https://github.com/angular/angular.js/commit/0db573b7493f76abd94ff65ce660017d617e865b),
|
||||
[#6477](https://github.com/angular/angular.js/issues/6477), [#9873](https://github.com/angular/angular.js/issues/9873))
|
||||
|
||||
|
||||
## Performance Improvements
|
||||
|
||||
- **orderBy:** copy array with slice instead of for loop
|
||||
([8eabc546](https://github.com/angular/angular.js/commit/8eabc5463c795d87f37e5a9eacbbb14435024061),
|
||||
[#9942](https://github.com/angular/angular.js/issues/9942))
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
- **$parse:** due to [fbad2805](https://github.com/angular/angular.js/commit/fbad2805703569058a4a860747b0e2d8aee36bdf),
|
||||
you can't use characters that have special meaning in AngularJS expressions (ex.: `.` or `-`)
|
||||
as part of filter's name. Before this commit custom filters could contain special characters
|
||||
(like a dot) in their name but this wasn't intentional.
|
||||
|
||||
<a name="1.3.2"></a>
|
||||
# 1.3.2 cardiovasculatory-magnification (2014-11-07)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$compile:** do not rebind parent bound transclude functions
|
||||
([841c0907](https://github.com/angular/angular.js/commit/841c0907556f525dbc4223609d808319fe0dd7e2),
|
||||
[#9413](https://github.com/angular/angular.js/issues/9413))
|
||||
- **$parse:**
|
||||
- stateful interceptors override an `undefined` expression
|
||||
([ed99821e](https://github.com/angular/angular.js/commit/ed99821e4dc621864f7e2d9a6b5305fca27fb7fa),
|
||||
[#9821](https://github.com/angular/angular.js/issues/9821), [#9825](https://github.com/angular/angular.js/issues/9825))
|
||||
- add quick check for Function constructor in fast path
|
||||
([e676d642](https://github.com/angular/angular.js/commit/e676d642f5feb8d3ba88944634afb479ba525c36))
|
||||
- **$parse, events:** prevent accidental misuse of properties on $event
|
||||
([e057a9aa](https://github.com/angular/angular.js/commit/e057a9aa398ead209bd6bbf76e22d2d5562904fb))
|
||||
- **ngRoute:** allow proto inherited properties in route params object
|
||||
([b4770582](https://github.com/angular/angular.js/commit/b4770582f84f26c8ff7f2320a36a6b0ceff6e6cc),
|
||||
[#8181](https://github.com/angular/angular.js/issues/8181), [#9731](https://github.com/angular/angular.js/issues/9731))
|
||||
- **select:** use strict comparison for isSelected with selectAs
|
||||
([9e305948](https://github.com/angular/angular.js/commit/9e305948e4965fb86b0c79985dc6e8c59a9c66af),
|
||||
[#9639](https://github.com/angular/angular.js/issues/9639), [#9949](https://github.com/angular/angular.js/issues/9949))
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
- **ngAria:** announce ngMessages with aria-live
|
||||
([187e4318](https://github.com/angular/angular.js/commit/187e43185dfb1bce6a318d95958c73cfb789d33c),
|
||||
[#9834](https://github.com/angular/angular.js/issues/9834))
|
||||
- **ngMock:** decorator that adds Scope#$countChildScopes and Scope#$countWatchers
|
||||
([74981c9f](https://github.com/angular/angular.js/commit/74981c9f208b3617cbf00beafd61138d25c5d546),
|
||||
[#9926](https://github.com/angular/angular.js/issues/9926), [#9871](https://github.com/angular/angular.js/issues/9871))
|
||||
|
||||
|
||||
## Security Note
|
||||
|
||||
This release also contains security fixes for expression sandbox bypasses.
|
||||
|
||||
These issues affect only applications with known server-side XSS holes that are also using [CSP](https://developer.mozilla.org/en-US/docs/Web/Security/CSP) to secure their client-side code. If your application falls into this rare category, we recommend updating your version of Angular.
|
||||
|
||||
We'd like to thank security researches [Sebastian Lekies](https://twitter.com/sebastianlekies), [Jann Horn](http://thejh.net/), and [Gábor Molnár](https://twitter.com/molnar_g) for reporting these issues to us.
|
||||
|
||||
We also added a documentation page focused on security, which contains some of the best practices, DOs and DON'Ts. Please check out [https://docs.angularjs.org/guide/security](https://docs.angularjs.org/guide/security).
|
||||
|
||||
|
||||
|
||||
<a name="1.3.1"></a>
|
||||
# 1.3.1 spectral-lobster (2014-10-31)
|
||||
|
||||
Vendored
+2
@@ -5,6 +5,7 @@ var angularFiles = {
|
||||
'src/minErr.js',
|
||||
'src/Angular.js',
|
||||
'src/loader.js',
|
||||
'src/stringify.js',
|
||||
'src/AngularPublic.js',
|
||||
'src/jqLite.js',
|
||||
'src/apis.js',
|
||||
@@ -73,6 +74,7 @@ var angularFiles = {
|
||||
],
|
||||
|
||||
'angularLoader': [
|
||||
'stringify.js',
|
||||
'src/minErr.js',
|
||||
'src/loader.js'
|
||||
],
|
||||
|
||||
@@ -128,6 +128,10 @@ h1,h2,h3,h4,h5,h6 {
|
||||
margin-bottom:5px;
|
||||
}
|
||||
|
||||
.nav-index-group .nav-index-listing.current a {
|
||||
color: #B52E31;
|
||||
}
|
||||
|
||||
.nav-breadcrumb {
|
||||
margin:4px 0;
|
||||
padding:0;
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 31 KiB |
@@ -13,6 +13,7 @@ angular.module('DocsController', [])
|
||||
$scope.navClass = function(navItem) {
|
||||
return {
|
||||
active: navItem.href && this.currentPage && this.currentPage.path,
|
||||
current: this.currentPage && this.currentPage.path === navItem.href,
|
||||
'nav-index-section': navItem.type === 'section'
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
"use strict";
|
||||
|
||||
angular.module('versions', [])
|
||||
|
||||
.controller('DocsVersionsCtrl', ['$scope', '$location', '$window', 'NG_VERSIONS', function($scope, $location, $window, NG_VERSIONS) {
|
||||
$scope.docs_version = NG_VERSIONS[0];
|
||||
$scope.docs_versions = NG_VERSIONS;
|
||||
|
||||
for(var i=0, minor = NaN; i < NG_VERSIONS.length; i++) {
|
||||
var version = NG_VERSIONS[i];
|
||||
@@ -13,9 +16,8 @@ angular.module('versions', [])
|
||||
minor = version.minor;
|
||||
}
|
||||
|
||||
$scope.docs_versions = NG_VERSIONS;
|
||||
$scope.getGroupName = function(v) {
|
||||
return v.isLatest ? 'Latest' : (v.isStable ? 'Stable' : 'Unstable');
|
||||
return v.isLatest ? 'Latest' : ('v' + v.major + '.' + v.minor + '.x');
|
||||
};
|
||||
|
||||
$scope.jumpToDocsVersion = function(version) {
|
||||
|
||||
@@ -161,6 +161,27 @@ or JavaScript callbacks.
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
## {@link ngAria ngAria}
|
||||
|
||||
Use ngAria to inject common accessibility attributes into directives and improve the experience for users with disabilities.
|
||||
|
||||
<div class="alert alert-info">Include the **angular-aria.js** file and set ngAria as a dependency for this to work in your application.</div>
|
||||
|
||||
<table class="definition-table spaced">
|
||||
<tr>
|
||||
<td>
|
||||
{@link ngAria#service Services}
|
||||
</td>
|
||||
<td>
|
||||
<p>
|
||||
The {@link ngAria.$aria $aria} service contains helper methods for applying ARIA attributes to HTML.
|
||||
<p>
|
||||
<p>
|
||||
{@link ngAria.$ariaProvider $ariaProvider} is used for configuring ARIA attributes.
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
## {@link ngResource ngResource}
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
@ngdoc error
|
||||
@name $http:badreq
|
||||
@fullName Bad Request Configuration
|
||||
@description
|
||||
|
||||
This error occurs when the request configuration parameter passed to the {@link ng.$http `$http`} service is not an object. `$http` expects a single parameter, the request configuration object, but received a parameter that was not an object. The error message should provide additional context such as the actual value of the parameter that was received. If you passed a string parameter, perhaps you meant to call one of the shorthand methods on `$http` such as `$http.get(…)`, etc.
|
||||
|
||||
To resolve this error, make sure you pass a valid request configuration object to `$http`.
|
||||
|
||||
For more information, see the {@link ng.$http `$http`} service API documentation.
|
||||
@@ -61,7 +61,7 @@ Attempting to inject one controller into another will also throw an `Unknown pro
|
||||
|
||||
```
|
||||
angular.module('myModule', [])
|
||||
.controller('MyFirstController', function() { /* ... */ });
|
||||
.controller('MyFirstController', function() { /* ... */ })
|
||||
.controller('MySecondController', ['MyFirstController', function(MyFirstController) {
|
||||
// This controller throws an unknown provider error because
|
||||
// MyFirstController cannot be injected.
|
||||
|
||||
@@ -8,10 +8,10 @@ This error occurs when {@link ng.$location $location} service is configured to u
|
||||
For example if you configure `$location` service with prefix `'!'`:
|
||||
```
|
||||
myApp.config(function($locationProvider) {
|
||||
$locationProvider.prefix('!');
|
||||
$locationProvider.hashPrefix('!');
|
||||
});
|
||||
```
|
||||
|
||||
If you enter the app at url `http:/myapp.com/#/myView` this error will be throw.
|
||||
If you enter the app at url `http://myapp.com/#/myView` this error will be thrown.
|
||||
|
||||
The correct url for this configuration is `http:/myapp.com/#!/myView` (note the `'!'` after `'#'` symbol).
|
||||
The correct url for this configuration is `http://myapp.com/#!/myView` (note the `'!'` after `'#'` symbol).
|
||||
|
||||
@@ -12,7 +12,7 @@ assistive technologies used by persons with disabilities.
|
||||
|
||||
##Including ngAria
|
||||
|
||||
Using ngAria is as simple as requiring the ngAria module in your application. ngAria hooks into
|
||||
Using {@link ngAria ngAria} is as simple as requiring the ngAria module in your application. ngAria hooks into
|
||||
standard AngularJS directives and quietly injects accessibility support into your application
|
||||
at runtime.
|
||||
|
||||
@@ -20,6 +20,15 @@ at runtime.
|
||||
angular.module('myApp', ['ngAria'])...
|
||||
```
|
||||
|
||||
###Using ngAria
|
||||
Most of what ngAria does is only visible "under the hood". To see the module in action, once you've
|
||||
added it as a dependency, you can test a few things:
|
||||
* Using your favorite element inspector, look for ngAria attributes in your own code.
|
||||
* Test using your keyboard to ensure `tabindex` is used correctly.
|
||||
* Fire up a screen reader such as VoiceOver to listen for ARIA support.
|
||||
[Helpful screen reader tips.](http://webaim.org/articles/screenreader_testing/)
|
||||
|
||||
##Supported directives
|
||||
Currently, ngAria interfaces with the following directives:
|
||||
|
||||
* <a href="#ngmodel">ngModel</a>
|
||||
@@ -31,7 +40,7 @@ Currently, ngAria interfaces with the following directives:
|
||||
|
||||
<h2 id="ngmodel">ngModel</h2>
|
||||
|
||||
Most of ngAria's heavy lifting happens in the [ngModel](https://docs.angularjs.org/api/ng/directive/ngModel)
|
||||
Most of ngAria's heavy lifting happens in the {@link ngModel ngModel}
|
||||
directive. For elements using ngModel, special attention is paid by ngAria if that element also
|
||||
has a a role or type of `checkbox`, `radio`, `range` or `textbox`.
|
||||
|
||||
@@ -47,15 +56,80 @@ attributes (if they have not been explicitly specified by the developer):
|
||||
|
||||
###Example
|
||||
|
||||
```html
|
||||
<md-checkbox ng-model="val" required>
|
||||
```
|
||||
|
||||
Becomes:
|
||||
|
||||
```html
|
||||
<md-checkbox ng-model="val" required aria-required="true" tabIndex="0">
|
||||
```
|
||||
<example module="ngAria_ngModelExample" deps="angular-aria.js">
|
||||
<file name="index.html">
|
||||
<style>
|
||||
[role=checkbox] {
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
}
|
||||
[role=checkbox] .icon:before {
|
||||
content: '\2610';
|
||||
display: inline-block;
|
||||
font-size: 2em;
|
||||
line-height: 1;
|
||||
vertical-align: middle;
|
||||
speak: none;
|
||||
}
|
||||
[role=checkbox].active .icon:before {
|
||||
content: '\2611';
|
||||
}
|
||||
pre {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
</style>
|
||||
<div>
|
||||
<form ng-controller="formsController">
|
||||
<some-checkbox role="checkbox" ng-model="checked" ng-class="{active: checked}"
|
||||
ng-disabled="isDisabled" ng-click="toggleCheckbox()"
|
||||
aria-label="Custom Checkbox" show-attrs>
|
||||
<span class="icon" aria-hidden="true"></span>
|
||||
Custom Checkbox
|
||||
</some-checkbox>
|
||||
</form>
|
||||
</div>
|
||||
<script>
|
||||
var app = angular.module('ngAria_ngModelExample', ['ngAria'])
|
||||
.controller('formsController', function($scope){
|
||||
$scope.checked = false;
|
||||
$scope.toggleCheckbox = function(){
|
||||
$scope.checked = !$scope.checked;
|
||||
}
|
||||
})
|
||||
.directive('someCheckbox', function(){
|
||||
return {
|
||||
restrict: 'E',
|
||||
link: function($scope, $el, $attrs) {
|
||||
$el.on('keypress', function(event){
|
||||
event.preventDefault();
|
||||
if(event.keyCode === 32 || event.keyCode === 13){
|
||||
$scope.toggleCheckbox();
|
||||
$scope.$apply();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
.directive('showAttrs', function() {
|
||||
return function($scope, $el, $attrs) {
|
||||
var pre = document.createElement('pre');
|
||||
$el.after(pre);
|
||||
$scope.$watch(function() {
|
||||
var $attrs = {};
|
||||
Array.prototype.slice.call($el[0].attributes, 0).forEach(function(item) {
|
||||
if (item.name !== 'show-$attrs') {
|
||||
$attrs[item.name] = item.value;
|
||||
}
|
||||
});
|
||||
return $attrs;
|
||||
}, function(newAttrs, oldAttrs) {
|
||||
pre.textContent = JSON.stringify(newAttrs, null, 2);
|
||||
}, true);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</file>
|
||||
</example>
|
||||
|
||||
ngAria will also add `tabIndex`, ensuring custom elements with these roles will be reachable from
|
||||
the keyboard. It is still up to **you** as a developer to **ensure custom controls will be
|
||||
@@ -106,6 +180,24 @@ screen reader users won't accidentally focus on "mystery elements". Managing tab
|
||||
child control can be complex and affect performance, so it’s best to just stick with the default
|
||||
`display: none` CSS. See the [fourth rule of ARIA use](http://www.w3.org/TR/aria-in-html/#fourth-rule-of-aria-use).
|
||||
|
||||
###Example
|
||||
```css
|
||||
.ng-hide {
|
||||
display: block;
|
||||
opacity: 0;
|
||||
}
|
||||
```
|
||||
```html
|
||||
<div ng-show="false" class="ng-hide" aria-hidden="true"></div>
|
||||
```
|
||||
|
||||
Becomes:
|
||||
|
||||
```html
|
||||
<div ng-show="true" aria-hidden="false"></div>
|
||||
```
|
||||
*Note: Child links, buttons or other interactive controls must also be removed from the tab order.*
|
||||
|
||||
<h2 id="nghide">ngHide</h2>
|
||||
|
||||
>The [ngHide](https://docs.angularjs.org/api/ng/directive/ngHide) directive shows or hides the
|
||||
@@ -116,26 +208,128 @@ The default CSS for `ngHide`, the inverse method to `ngShow`, makes ngAria redun
|
||||
`aria-hidden` on the directive when it is hidden or shown, but the content is already hidden with
|
||||
`display: none`. See explanation for <a href="#ngshow">ngShow</a> when overriding the default CSS.
|
||||
|
||||
<h2 id="ngclick">ngClick and ngDblClick</h2>
|
||||
If `ngClick` or `ngDblClick` is encountered, ngAria will add `tabIndex` if it isn't there already.
|
||||
Even with this, you must currently still add `ng-keypress` to non-interactive elements such as
|
||||
`<div>` or `<taco-button>` to enable keyboard access. I have recommended this also bind
|
||||
`ng-keypress` to be more useful; the conversation is [currently ongoing](https://github.com/angular/angular.js/issues/9254).
|
||||
<h2 id="ngclick-and-ngdblclick">ngClick and ngDblclick</h2>
|
||||
If `ng-click` or `ng-dblclick` is encountered, ngAria will add `tabindex` if it isn't there already.
|
||||
Even with this, you must currently still add `ng-keypress` to non-interactive elements such as `div`
|
||||
or `taco-button` to enable keyboard access. Conversation is currently ongoing about whether ngAria
|
||||
should also bind `ng-keypress`.
|
||||
|
||||
* * *
|
||||
<h3>Example</h3>
|
||||
```html
|
||||
<div ng-click="toggleMenu()"></div>
|
||||
```
|
||||
|
||||
Becomes:
|
||||
```html
|
||||
<div ng-click="toggleMenu()" tabindex="0"></div>
|
||||
```
|
||||
*Note: ngAria still requires `ng-keypress` to be added manually to non-native controls like divs.*
|
||||
|
||||
<h2 id="ngmessages">ngMessages</h2>
|
||||
|
||||
The new ngMessages module makes it easy to display form validation or other messages with priority
|
||||
sequencing and animation. To expose these visual messages to screen readers,
|
||||
ngAria injects `aria-live="polite"`, causing them to be read aloud any time a message is shown,
|
||||
regardless of the user's focus location.
|
||||
###Example
|
||||
|
||||
```html
|
||||
<div ng-messages="myForm.myName.$error">
|
||||
<div ng-message="required">You did not enter a field</div>
|
||||
<div ng-message="maxlength">Your field is too long</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
Becomes:
|
||||
|
||||
```html
|
||||
<div ng-messages="myForm.myName.$error" aria-live="polite">
|
||||
<div ng-message="required">You did not enter a field</div>
|
||||
<div ng-message="maxlength">Your field is too long</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
##Disabling attributes
|
||||
The attribute magic of ngAria may not work for every scenario. To disable individual attributes,
|
||||
you can use the `{@link ngAria.$ariaProvider#config config}` method:
|
||||
you can use the {@link ngAria.$ariaProvider#config config} method. Just keep in mind this will
|
||||
tell ngAria to ignore the attribute globally.
|
||||
|
||||
```
|
||||
angular.module('myApp', ['ngAria'], function config($ariaProvider) {
|
||||
$ariaProvider.config({
|
||||
tabindex: false
|
||||
<example module="ngAria_ngDisabledExample" deps="angular-aria.js">
|
||||
<file name="index.html">
|
||||
<style>
|
||||
[role=checkbox] {
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
}
|
||||
[role=checkbox] .icon:before {
|
||||
content: '\2610';
|
||||
display: inline-block;
|
||||
font-size: 2em;
|
||||
line-height: 1;
|
||||
vertical-align: middle;
|
||||
speak: none;
|
||||
}
|
||||
[role=checkbox].active .icon:before {
|
||||
content: '\2611';
|
||||
}
|
||||
</style>
|
||||
<form ng-controller="formsController">
|
||||
<div ng-model="someModel" show-attrs>
|
||||
Div with ngModel and aria-invalid disabled
|
||||
</div>
|
||||
<div role="checkbox" ng-model="checked" ng-class="{active: checked}"
|
||||
aria-label="Custom Checkbox" ng-click="toggleCheckbox()" some-checkbox show-attrs>
|
||||
<span class="icon" aria-hidden="true"></span>
|
||||
Custom Checkbox for comparison
|
||||
</div>
|
||||
</form>
|
||||
<script>
|
||||
angular.module('ngAria_ngDisabledExample', ['ngAria'], function config($ariaProvider) {
|
||||
$ariaProvider.config({
|
||||
ariaInvalid: false,
|
||||
tabindex: true
|
||||
});
|
||||
})
|
||||
.controller('formsController', function($scope){
|
||||
$scope.checked = false;
|
||||
$scope.toggleCheckbox = function(){
|
||||
$scope.checked = !$scope.checked;
|
||||
}
|
||||
})
|
||||
.directive('someCheckbox', function(){
|
||||
return {
|
||||
restrict: 'A',
|
||||
link: function($scope, $el, $attrs) {
|
||||
$el.on('keypress', function(event){
|
||||
event.preventDefault();
|
||||
if(event.keyCode === 32 || event.keyCode === 13){
|
||||
$scope.toggleCheckbox();
|
||||
$scope.$apply();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
.directive('showAttrs', function() {
|
||||
return function(scope, el, attrs) {
|
||||
var pre = document.createElement('pre');
|
||||
el.after(pre);
|
||||
scope.$watch(function() {
|
||||
var attrs = {};
|
||||
Array.prototype.slice.call(el[0].attributes, 0).forEach(function(item) {
|
||||
if (item.name !== 'show-attrs') {
|
||||
attrs[item.name] = item.value;
|
||||
}
|
||||
});
|
||||
return attrs;
|
||||
}, function(newAttrs, oldAttrs) {
|
||||
pre.textContent = JSON.stringify(newAttrs, null, 2);
|
||||
}, true);
|
||||
}
|
||||
});
|
||||
});
|
||||
```
|
||||
* * *
|
||||
</script>
|
||||
</file>
|
||||
</example>
|
||||
|
||||
##Common Accessibility Patterns
|
||||
|
||||
@@ -164,6 +358,7 @@ Accessibility best practices that apply to web apps in general also apply to Ang
|
||||
|
||||
* [Using ARIA in HTML](http://www.w3.org/TR/aria-in-html/)
|
||||
* [AngularJS Accessibility at ngEurope](https://www.youtube.com/watch?v=dmYDggEgU-s&list=UUEGUP3TJJfMsEM_1y8iviSQ)
|
||||
* [Testing with Screen Readers](http://webaim.org/articles/screenreader_testing/)
|
||||
* [Chrome Accessibility Developer Tools](https://chrome.google.com/webstore/detail/accessibility-developer-t/fpkknkljclfencbdbgkenhalefipecmb?hl=en)
|
||||
* [W3C Accessibility Testing](http://www.w3.org/wiki/Accessibility_testing)
|
||||
* [WebAIM](http://webaim.org)
|
||||
|
||||
@@ -145,7 +145,7 @@ This is the sequence that your code should follow:
|
||||
|
||||
## Deferred Bootstrap
|
||||
|
||||
This feature enables tools like [Batarang](github.com/angular/angularjs-batarang) and test runners
|
||||
This feature enables tools like [Batarang](https://github.com/angular/angularjs-batarang) and test runners
|
||||
to hook into angular's bootstrap process and sneak in more modules
|
||||
into the DI registry which can replace or augment DI services for
|
||||
the purpose of instrumentation or mocking out heavy dependencies.
|
||||
|
||||
@@ -332,7 +332,7 @@ The first issue we have to solve is that the dialog box template expects `title`
|
||||
But we would like the template's scope property `title` to be the result of interpolating the
|
||||
`<dialog>` element's `title` attribute (i.e. `"Hello {{username}}"`). Furthermore, the buttons expect
|
||||
the `onOk` and `onCancel` functions to be present in the scope. This limits the usefulness of the
|
||||
widget. To solve the mapping issue we use the `locals` to create local variables which the template
|
||||
widget. To solve the mapping issue we use the `scope` to create local variables which the template
|
||||
expects as follows:
|
||||
|
||||
```js
|
||||
|
||||
@@ -154,7 +154,7 @@ First, there is a new JavaScript file that contains a so-called <a name="control
|
||||
More exactly, the file contains a constructor function that creates the actual controller instance.
|
||||
The purpose of controllers is to expose variables and functionality to expressions and directives.
|
||||
|
||||
Besides the new file that contains the controller code we also added a
|
||||
Besides the new file that contains the controller code we also added an
|
||||
{@link ng.directive:ngController `ng-controller`} directive to the HTML.
|
||||
This directive tells Angular that the new `InvoiceController` is responsible for the element with the directive
|
||||
and all of the element's children.
|
||||
|
||||
@@ -164,6 +164,12 @@ expression. The reason behind this is core to the Angular philosophy that applic
|
||||
be in controllers, not the views. If you need a real conditional, loop, or to throw from a view
|
||||
expression, delegate to a JavaScript method instead.
|
||||
|
||||
## No RegExp creation with literal notation
|
||||
|
||||
You can't create regular expressions from within AngularJS expressions. This is to avoid complex
|
||||
model transformation logic inside templates. Such logic is better placed in a controller or in a dedicated
|
||||
filter where it can be tested properly.
|
||||
|
||||
## `$event`
|
||||
|
||||
Directives like {@link ng.directive:ngClick `ngClick`} and {@link ng.directive:ngFocus `ngFocus`}
|
||||
@@ -314,7 +320,7 @@ someModule.directive('someDirective', function() {
|
||||
```
|
||||
|
||||
```html
|
||||
<div some-directive name=“::myName” color=“My color is {{::myColor}}”></div>
|
||||
<div some-directive name="::myName" color="My color is {{::myColor}}"></div>
|
||||
```
|
||||
|
||||
|
||||
|
||||
@@ -91,6 +91,11 @@ The filter function should be a [pure function](http://en.wikipedia.org/wiki/Pur
|
||||
means that it should be stateless and idempotent. Angular relies on these properties and executes
|
||||
the filter only when the inputs to the function change.
|
||||
|
||||
<div class="alert alert-warning">
|
||||
**Note:** filter names must be valid angular expression identifiers, such as `uppercase` or `orderBy`.
|
||||
Names with special characters, such as hyphens and dots, are not allowed.
|
||||
</div>
|
||||
|
||||
The following sample filter reverses a text string. In addition, it conditionally makes the
|
||||
text upper-case.
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ In Angular applications, you move the job of filling page templates with data fr
|
||||
### Other AngularJS Features
|
||||
|
||||
* **Animation:** {@link guide/animations Core concepts}, {@link ngAnimate ngAnimate API}, and [Animation in AngularJS 1.2](http://www.yearofmoo.com/2013/08/remastered-animation-in-angularjs-1-2.html)
|
||||
* **Security:** {@link ng.$sce Strict Contextual Escaping}, {@link ng.directive:ngCsp Content Security Policy}, {@link ngSanitize.$sanitize $sanitize}, [video](https://www.youtube.com/watch?v=18ifoT-Id54)
|
||||
* **Security:** {@link guide/security Security Docs}, {@link ng.$sce Strict Contextual Escaping}, {@link ng.directive:ngCsp Content Security Policy}, {@link ngSanitize.$sanitize $sanitize}, [video](https://www.youtube.com/watch?v=18ifoT-Id54)
|
||||
* **Internationalization and Localization:** {@link guide/i18n Angular Guide to i18n and l10n}, {@link ng.filter:date date filter}, {@link ng.filter:currency currency filter}, [Creating multilingual support](http://www.novanet.no/blog/hallstein-brotan/dates/2013/10/creating-multilingual-support-using-angularjs/)
|
||||
* **Mobile:** {@link ngTouch Touch events}
|
||||
* **Accessibility:** {@link guide/accessibility ngAria}
|
||||
@@ -108,6 +108,7 @@ This is a short list of libraries with specific support and documentation for wo
|
||||
* [Developing an AngularJS Edge](http://www.amazon.com/Developing-AngularJS-Edge-Christopher-Hiller-ebook/dp/B00CJLFF8K) by Christopher Hiller
|
||||
* [ng-book: The Complete Book on AngularJS](http://ng-book.com/) by Ari Lerner
|
||||
* [AngularJS : Novice to Ninja](http://www.amazon.in/AngularJS-Novice-Ninja-Sandeep-Panda/dp/0992279453) by Sandeep Panda
|
||||
* [AngularJS UI Development](http://www.amazon.com/AngularJS-UI-Development-Amit-Ghart-ebook/dp/B00OXVAK7A) by Amit Gharat and Matthias Nehlsen
|
||||
|
||||
###Videos:
|
||||
* [egghead.io](http://egghead.io/)
|
||||
|
||||
@@ -23,7 +23,7 @@ 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
|
||||
The (deprecated) __proto__ property does not work inside angular expressions
|
||||
anymore.
|
||||
- due to [48fa3aad](https://github.com/angular/angular.js/commit/48fa3aadd546036c7e69f71046f659ab1de244c6),
|
||||
|
||||
|
||||
@@ -140,7 +140,7 @@ The above is a suggestion. Tailor it to your needs.
|
||||
# Module Loading & Dependencies
|
||||
|
||||
A module is a collection of configuration and run blocks which get applied to the application
|
||||
during the bootstrap process. In its simplest form the module consist of collection of two kinds
|
||||
during the bootstrap process. In its simplest form the module consist of a collection of two kinds
|
||||
of blocks:
|
||||
|
||||
1. **Configuration blocks** - get executed during the provider registrations and configuration
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
@ngdoc overview
|
||||
@name Security
|
||||
@sortOrder 525
|
||||
@description
|
||||
|
||||
# Security
|
||||
|
||||
This document explains some of AngularJS's security features and best practices that you should
|
||||
keep in mind as you build your application.
|
||||
|
||||
|
||||
## Expression Sandboxing
|
||||
|
||||
AngularJS's expressions are sandboxed not for security reasons, but instead to maintain a proper
|
||||
separation of application responsibilities. For example, access to `window` is disallowed
|
||||
because it makes it easy to introduce brittle global state into your application.
|
||||
|
||||
However, this sandbox is not intended to stop attackers who can edit the template before it's
|
||||
processed by Angular. It may be possible to run arbitrary JavaScript inside double-curly bindings
|
||||
if an attacker can modify them.
|
||||
|
||||
But if an attacker can change arbitrary HTML templates, there's nothing stopping them from doing:
|
||||
|
||||
```html
|
||||
<script>somethingEvil();</script>
|
||||
```
|
||||
|
||||
It's better to design your application in such a way that users cannot change client-side templates.
|
||||
For instance:
|
||||
|
||||
* Do not mix client and server templates
|
||||
* Do not use user input to generate templates dynamically
|
||||
* Do not run user input through `$scope.$eval`
|
||||
* Consider using {@link ng.directive:ngCsp CSP} (but don't rely only on CSP)
|
||||
|
||||
## Mixing client-side and server-side templates
|
||||
|
||||
In general, we recommend against this because it can create unintended XSS vectors.
|
||||
|
||||
However, it's ok to mix server-side templating in the bootstrap template (`index.html`) as long
|
||||
as user input cannot be used on the server to output html that would then be processed by Angular
|
||||
in a way that would cause allow for arbitrary code execution.
|
||||
|
||||
For instance, you can use server-side templating to dynamically generate CSS, URLs, etc, but not
|
||||
for generating templates that are bootstrapped/compiled by Angular.
|
||||
|
||||
|
||||
## Reporting a security issue
|
||||
|
||||
Email us at [security@angularjs.org](mailto:security@angularjs.org) to report any potential
|
||||
security issues in AngularJS.
|
||||
|
||||
Please keep in mind the above points about Angular's expression language.
|
||||
|
||||
|
||||
## See also
|
||||
|
||||
* {@link ng.directive:ngCsp Content Security Policy}
|
||||
* {@link ng.$sce Strict Contextual Escaping}
|
||||
* {@link ngSanitize.$sanitize $sanitize}
|
||||
@@ -8,15 +8,15 @@ comes with almost no help from the compiler. For this reason we feel very strong
|
||||
written in JavaScript needs to come with a strong set of tests. We have built many features into
|
||||
Angular which makes testing your Angular applications easy. So there is no excuse for not testing.
|
||||
|
||||
# Separation of Concerns
|
||||
## Separation of Concerns
|
||||
|
||||
Unit testing as the name implies is about testing individual units of code. Unit tests try to
|
||||
Unit testing, as the name implies, is about testing individual units of code. Unit tests try to
|
||||
answer questions such as "Did I think about the logic correctly?" or "Does the sort function order
|
||||
the list in the right order?"
|
||||
|
||||
In order to answer such a question it is very important that we can isolate the unit of code under test.
|
||||
That is because when we are testing the sort function we don't want to be forced into creating
|
||||
related pieces such as the DOM elements, or making any XHR calls in getting the data to sort.
|
||||
related pieces such as the DOM elements, or making any XHR calls to fetch the data to sort.
|
||||
|
||||
While this may seem obvious it can be very difficult to call an individual function on a
|
||||
typical project. The reason is that the developers often mix concerns resulting in a
|
||||
@@ -24,12 +24,10 @@ piece of code which does everything. It makes an XHR request, it sorts the respo
|
||||
manipulates the DOM.
|
||||
|
||||
With Angular we try to make it easy for you to do the right thing, and so we
|
||||
provide dependency injection for your XHR (which you can mock out) and we created abstractions which
|
||||
allow you to sort your model without having to resort to manipulating the DOM. So that in the end,
|
||||
it is easy to write a sort function which sorts some data, so that your test can create a data set,
|
||||
apply the function, and assert that the resulting model is in the correct order. The test does not
|
||||
have to wait for the XHR response to arrive, create the right kind of test DOM, nor assert that your
|
||||
function has mutated the DOM in the right way.
|
||||
provide dependency injection for your XHR requests, which can be mocked, and we provide abstractions which
|
||||
allow you to test your model without having to resort to manipulating the DOM. The test can then
|
||||
assert that the data has been sorted without having to create or look at the state of the DOM or
|
||||
wait for any XHR requests to return data. The individual sort function can be tested in isolation.
|
||||
|
||||
## With great power comes great responsibility
|
||||
|
||||
@@ -38,230 +36,218 @@ We tried to make the right thing easy, but if you ignore these guidelines you ma
|
||||
untestable application.
|
||||
|
||||
## Dependency Injection
|
||||
There are several ways in which you can get a hold of a dependency. You can:
|
||||
1. Create it using the `new` operator.
|
||||
2. Look for it in a well-known place, also known as a global singleton.
|
||||
3. Ask a registry (also known as service registry) for it. (But how do you get a hold of
|
||||
the registry? Most likely by looking it up in a well known place. See #2.)
|
||||
4. Expect it to be handed to you.
|
||||
|
||||
Out of the four options in the list above, only the last one is testable. Let's look at why:
|
||||
Angular comes with {@link di dependency injection} built-in, which makes testing components much
|
||||
easier, because you can pass in a component's dependencies and stub or mock them as you wish.
|
||||
|
||||
### Using the `new` operator
|
||||
Components that have their dependencies injected allow them to be easily mocked on a test by
|
||||
test basis, without having to mess with any global variables that could inadvertently affect
|
||||
another test.
|
||||
|
||||
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, let's say that we try to
|
||||
instantiate an `XHR` that will retrieve data from the server.
|
||||
## Additional tools for testing Angular applications
|
||||
|
||||
For testing Angular applications there are certain tools that you should use that will make testing much
|
||||
easier to set up and run.
|
||||
|
||||
### Karma
|
||||
|
||||
[Karma](http://karma-runner.github.io/) is a JavaScript command line tool that can be used to spawn
|
||||
a web server which loads your application's source code and executes your tests. You can configure
|
||||
Karma to run against a number of browsers, which is useful for being confident that your application
|
||||
works on all browsers you need to support. Karma is executed on the command line and will display
|
||||
the results of your tests on the command line once they have run in the browser.
|
||||
|
||||
Karma is a NodeJS application, and should be installed through npm. Full installation instructions
|
||||
are available on [the Karma website](http://karma-runner.github.io/0.12/intro/installation.html).
|
||||
|
||||
### Jasmine
|
||||
|
||||
[Jasmine](http://jasmine.github.io/1.3/introduction.html) is a test driven development framework for
|
||||
JavaScript that has become the most popular choice for testing Angular applications. Jasmine
|
||||
provides functions to help with structuring your tests and also making assertions. As your tests
|
||||
grow, keeping them well structured and documented is vital, and Jasmine helps achieve this.
|
||||
|
||||
In Jasmine we use the `describe` function to group our tests together:
|
||||
|
||||
```js
|
||||
function MyClass() {
|
||||
this.doWork = function() {
|
||||
var xhr = new XHR();
|
||||
xhr.open(method, url, true);
|
||||
xhr.onreadystatechange = function() {...}
|
||||
xhr.send();
|
||||
}
|
||||
}
|
||||
describe("sorting the list of users", function() {
|
||||
// individual tests go here
|
||||
});
|
||||
```
|
||||
|
||||
A problem surfaces in tests when we would like to instantiate a `MockXHR` that would
|
||||
allow us to return fake data and simulate network failures. By calling `new XHR()` we are
|
||||
permanently bound to the actual XHR and there is no way to replace it. Yes, we could monkey
|
||||
patch, but that is a bad idea for many reasons which are outside the scope of this document.
|
||||
|
||||
Here's an example of how the class above becomes hard to test when resorting to monkey patching:
|
||||
And then each individual test is defined within a call to the `it` function:
|
||||
|
||||
```js
|
||||
var oldXHR = XHR;
|
||||
XHR = function MockXHR() {};
|
||||
var myClass = new MyClass();
|
||||
myClass.doWork();
|
||||
// assert that MockXHR got called with the right arguments
|
||||
XHR = oldXHR; // if you forget this bad things will happen
|
||||
describe('sorting the list of users', function() {
|
||||
it('sorts in descending order by default', function() {
|
||||
// your test assertion goes here
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
Grouping related tests within `describe` blocks and describing each individual test within an
|
||||
`it` call keeps your tests self documenting.
|
||||
|
||||
### Global look-up:
|
||||
Another way to approach the problem is to look for the service in a well-known location.
|
||||
Finally, Jasmine provides matchers which let you make assertions:
|
||||
|
||||
```js
|
||||
function MyClass() {
|
||||
this.doWork = function() {
|
||||
global.xhr({
|
||||
method:'...',
|
||||
url:'...',
|
||||
complete:function(response){ ... }
|
||||
})
|
||||
}
|
||||
}
|
||||
describe('sorting the list of users', function() {
|
||||
it('sorts in descending order by default', function() {
|
||||
var users = ['jack', 'igor', 'jeff'];
|
||||
var sorted = sortUsers(users);
|
||||
expect(sorted).toEqual(['jeff', 'jack', 'igor']);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
While no new dependency instance is created, it is fundamentally the same as `new` in
|
||||
that no way exists to intercept the call to `global.xhr` for testing purposes, other than
|
||||
through monkey patching. The basic issue for testing is that a global variable needs to be mutated in
|
||||
order to replace it with call to a mock method. For further explanation of why this is bad see: [Brittle Global
|
||||
State & Singletons](http://misko.hevery.com/code-reviewers-guide/flaw-brittle-global-state-singletons/)
|
||||
Jasmine comes with a number of matchers that help you make a variety of assertions. You should [read
|
||||
the Jasmine documentation](http://jasmine.github.io/1.3/introduction.html#section-Matchers) to see
|
||||
what they are. To use Jasmine with Karma, we use the
|
||||
[karma-jasmine](https://github.com/karma-runner/karma-jasmine) test runner.
|
||||
|
||||
The class above is hard to test since we have to change the global state:
|
||||
### angular-mocks
|
||||
|
||||
Angular also provides the {@link ngMock} module, which provides mocking for your tests. This is used
|
||||
to inject and mock Angular services within unit tests. In addition, it is able to extend other
|
||||
modules so they are synchronous. Having tests synchronous keeps them much cleaner and easier to work
|
||||
with. One of the most useful parts of ngMock is {@link ngMock.$httpBackend}, which lets us mock XHR
|
||||
requests in tests, and return sample data instead.
|
||||
|
||||
## Testing a Controller
|
||||
|
||||
Because Angular separates logic from the view layer, it keeps controllers easy to test. Let's take a
|
||||
look at how we might test the controller below, which provides `$scope.grade`, which sets a property
|
||||
on the scope based on the length of the password.
|
||||
|
||||
```js
|
||||
var oldXHR = global.xhr;
|
||||
global.xhr = function mockXHR() {};
|
||||
var myClass = new MyClass();
|
||||
myClass.doWork();
|
||||
// assert that mockXHR got called with the right arguments
|
||||
global.xhr = oldXHR; // if you forget this bad things will happen
|
||||
angular.module('app', [])
|
||||
.controller('PasswordController', function PasswordController($scope) {
|
||||
$scope.password = '';
|
||||
$scope.grade = function() {
|
||||
var size = $scope.password.length;
|
||||
if (size > 8) {
|
||||
$scope.strength = 'strong';
|
||||
} else if (size > 3) {
|
||||
$scope.strength = 'medium';
|
||||
} else {
|
||||
$scope.strength = 'weak';
|
||||
}
|
||||
};
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
### Service Registry:
|
||||
|
||||
It may seem that this can be solved by having a registry of all the services and then
|
||||
having the tests replace the services as needed.
|
||||
Because controllers are not available on the global scope, we need to use {@link
|
||||
angular.mock.inject} to inject our controller first. The first step is to use the `module` function,
|
||||
which is provided by angular-mocks. This loads in the module it's given, so it is available in your
|
||||
tests. We pass this into `beforeEach`, which is a function Jasmine provides that lets us run code
|
||||
before each test. Then we can use `inject` to access `$controller`, the service that is responsible
|
||||
for instantiating controllers.
|
||||
|
||||
```js
|
||||
function MyClass() {
|
||||
var serviceRegistry = ????;
|
||||
this.doWork = function() {
|
||||
var xhr = serviceRegistry.get('xhr');
|
||||
xhr({
|
||||
method:'...',
|
||||
url:'...',
|
||||
complete:function(response){ ... }
|
||||
})
|
||||
}
|
||||
describe('PasswordController', function() {
|
||||
beforeEach(module('app'));
|
||||
|
||||
var $controller;
|
||||
|
||||
beforeEach(inject(function(_$controller_){
|
||||
// The injector unwraps the underscores (_) from around the parameter names when matching
|
||||
$controller = _$controller_;
|
||||
}));
|
||||
|
||||
describe('$scope.grade', function() {
|
||||
it('sets the strength to "strong" if the password length is >8 chars', function() {
|
||||
var $scope = {};
|
||||
var controller = $controller('PasswordController', { $scope: $scope });
|
||||
$scope.password = 'longerthaneightchars';
|
||||
$scope.grade();
|
||||
expect($scope.strength).toEqual('strong');
|
||||
});
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
However, where does the serviceRegistry come from? If it is:
|
||||
* `new`-ed up, the test has no chance to reset the services for testing.
|
||||
* a global look-up then the service returned is global as well (but resetting is easier, since
|
||||
only one global variable exists to be reset).
|
||||
|
||||
The class above is hard to test since we have to change the global state:
|
||||
Notice how by nesting the `describe` calls and being descriptive when calling them with strings, the
|
||||
test is very clear. It documents exactly what it is testing, and at a glance you can quickly see
|
||||
what is happening. Now let's add the test for when the password is less than three characters, which
|
||||
should see `$scope.strength` set to "weak":
|
||||
|
||||
```js
|
||||
var oldServiceLocator = global.serviceLocator;
|
||||
global.serviceLocator.set('xhr', function mockXHR() {});
|
||||
var myClass = new MyClass();
|
||||
myClass.doWork();
|
||||
// assert that mockXHR got called with the right arguments
|
||||
global.serviceLocator = oldServiceLocator; // if you forget this bad things will happen
|
||||
describe('PasswordController', function() {
|
||||
beforeEach(module('app'));
|
||||
|
||||
var $controller;
|
||||
|
||||
beforeEach(inject(function(_$controller_){
|
||||
// The injector unwraps the underscores (_) from around the parameter names when matching
|
||||
$controller = _$controller_;
|
||||
}));
|
||||
|
||||
describe('$scope.grade', function() {
|
||||
it('sets the strength to "strong" if the password length is >8 chars', function() {
|
||||
var $scope = {};
|
||||
var controller = $controller('PasswordController', { $scope: $scope });
|
||||
$scope.password = 'longerthaneightchars';
|
||||
$scope.grade();
|
||||
expect($scope.strength).toEqual('strong');
|
||||
});
|
||||
|
||||
it('sets the strength to "weak" if the password length <3 chars', function() {
|
||||
var $scope = {};
|
||||
var controller = $controller('PasswordController', { $scope: $scope });
|
||||
$scope.password = 'a';
|
||||
$scope.grade();
|
||||
expect($scope.strength).toEqual('weak');
|
||||
});
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
### Passing in Dependencies:
|
||||
Last, the dependency can be passed in.
|
||||
Now we have two tests, but notice the duplication between the tests. Both have to
|
||||
create the `$scope` variable and create the controller. As we add new tests, this duplication is
|
||||
only going to get worse. Thankfully, Jasmine provides `beforeEach`, which lets us run a function
|
||||
before each individual test. Let's see how that would tidy up our tests:
|
||||
|
||||
```js
|
||||
function MyClass(xhr) {
|
||||
this.doWork = function() {
|
||||
xhr({
|
||||
method:'...',
|
||||
url:'...',
|
||||
complete:function(response){ ... }
|
||||
})
|
||||
}
|
||||
describe('PasswordController', function() {
|
||||
beforeEach(module('app'));
|
||||
|
||||
var $controller;
|
||||
|
||||
beforeEach(inject(function(_$controller_){
|
||||
// The injector unwraps the underscores (_) from around the parameter names when matching
|
||||
$controller = _$controller_;
|
||||
}));
|
||||
|
||||
describe('$scope.grade', function() {
|
||||
var $scope, controller;
|
||||
|
||||
beforeEach(function() {
|
||||
$scope = {};
|
||||
controller = $controller('PasswordController', { $scope: $scope });
|
||||
});
|
||||
|
||||
it('sets the strength to "strong" if the password length is >8 chars', function() {
|
||||
$scope.password = 'longerthaneightchars';
|
||||
$scope.grade();
|
||||
expect($scope.strength).toEqual('strong');
|
||||
});
|
||||
|
||||
it('sets the strength to "weak" if the password length <3 chars', function() {
|
||||
$scope.password = 'a';
|
||||
$scope.grade();
|
||||
expect($scope.strength).toEqual('weak');
|
||||
});
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
This is the preferred method since the code makes no assumptions about the origin of `xhr` and cares
|
||||
instead about whoever created the class responsible for passing it in. Since the creator of the
|
||||
class should be different code than the user of the class, it separates the responsibility of
|
||||
creation from the logic. This is dependency-injection in a nutshell.
|
||||
We've moved the duplication out and into the `beforeEach` block. Each individual test now
|
||||
only contains the code specific to that test, and not code that is general across all tests. As you
|
||||
expand your tests, keep an eye out for locations where you can use `beforeEach` to tidy up tests.
|
||||
`beforeEach` isn't the only function of this sort that Jasmine provides, and the [documentation
|
||||
lists the others](http://jasmine.github.io/1.3/introduction.html#section-Setup_and_Teardown).
|
||||
|
||||
The class above is testable, since in the test we can write:
|
||||
|
||||
```js
|
||||
function xhrMock(args) {...}
|
||||
var myClass = new MyClass(xhrMock);
|
||||
myClass.doWork();
|
||||
// assert that xhrMock got called with the right arguments
|
||||
```
|
||||
|
||||
Notice that no global variables were harmed in the writing of this test.
|
||||
|
||||
Angular comes with {@link di dependency injection} built-in, making the right thing
|
||||
easy to do, but you still need to do it if you wish to take advantage of the testability story.
|
||||
|
||||
## Controllers
|
||||
What makes each application unique is its logic, and the logic is what we would like to test. If the logic
|
||||
for your application contains DOM manipulation, it will be hard to test. See the example
|
||||
below:
|
||||
|
||||
```js
|
||||
function PasswordCtrl() {
|
||||
// get references to DOM elements
|
||||
var msg = $('.ex1 span');
|
||||
var input = $('.ex1 input');
|
||||
var strength;
|
||||
|
||||
this.grade = function() {
|
||||
msg.removeClass(strength);
|
||||
var pwd = input.val();
|
||||
password.text(pwd);
|
||||
if (pwd.length > 8) {
|
||||
strength = 'strong';
|
||||
} else if (pwd.length > 3) {
|
||||
strength = 'medium';
|
||||
} else {
|
||||
strength = 'weak';
|
||||
}
|
||||
msg
|
||||
.addClass(strength)
|
||||
.text(strength);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The code above is problematic from a testability point of view since it requires your test to have the right kind
|
||||
of DOM present when the code executes. The test would look like this:
|
||||
|
||||
```js
|
||||
var input = $('<input type="text"/>');
|
||||
var span = $('<span>');
|
||||
$('body').html('<div class="ex1">')
|
||||
.find('div')
|
||||
.append(input)
|
||||
.append(span);
|
||||
var pc = new PasswordCtrl();
|
||||
input.val('abc');
|
||||
pc.grade();
|
||||
expect(span.text()).toEqual('weak');
|
||||
$('body').empty();
|
||||
```
|
||||
|
||||
In angular the controllers are strictly separated from the DOM manipulation logic and this results in
|
||||
a much easier testability story as the following example shows:
|
||||
|
||||
```js
|
||||
function PasswordCtrl($scope) {
|
||||
$scope.password = '';
|
||||
$scope.grade = function() {
|
||||
var size = $scope.password.length;
|
||||
if (size > 8) {
|
||||
$scope.strength = 'strong';
|
||||
} else if (size > 3) {
|
||||
$scope.strength = 'medium';
|
||||
} else {
|
||||
$scope.strength = 'weak';
|
||||
}
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
and the test is straight forward:
|
||||
|
||||
```js
|
||||
var $scope = {};
|
||||
var pc = $controller('PasswordCtrl', { $scope: $scope });
|
||||
$scope.password = 'abc';
|
||||
$scope.grade();
|
||||
expect($scope.strength).toEqual('weak');
|
||||
```
|
||||
|
||||
Notice that the test is not only much shorter, it is also easier to follow what is happening. We say
|
||||
that such a test tells a story, rather than asserting random bits which don't seem to be related.
|
||||
|
||||
## Filters
|
||||
## Testing Filters
|
||||
{@link ng.$filterProvider Filters} are functions which transform the data into a user readable
|
||||
format. They are important because they remove the formatting responsibility from the application
|
||||
logic, further simplifying the application logic.
|
||||
@@ -273,12 +259,20 @@ myModule.filter('length', function() {
|
||||
}
|
||||
});
|
||||
|
||||
var length = $filter('length');
|
||||
expect(length(null)).toEqual(0);
|
||||
expect(length('abc')).toEqual(3);
|
||||
describe('length filter', function() {
|
||||
it('returns 0 when given null', function() {
|
||||
var length = $filter('length');
|
||||
expect(length(null)).toEqual(0);
|
||||
});
|
||||
|
||||
it('returns the correct value when given a string of chars', function() {
|
||||
var length = $filter('length');
|
||||
expect(length('abc')).toEqual(3);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
## Directives
|
||||
## Testing Directives
|
||||
Directives in angular are responsible for encapsulating complex functionality within custom HTML tags,
|
||||
attributes, classes or comments. Unit tests are very important for directives because the components
|
||||
you create with directives may be used throughout your application and in many different contexts.
|
||||
@@ -309,28 +303,28 @@ verify this functionality. Note that the expression `{{1 + 1}}` times will also
|
||||
|
||||
```js
|
||||
describe('Unit testing great quotes', function() {
|
||||
var $compile;
|
||||
var $rootScope;
|
||||
var $compile,
|
||||
$rootScope;
|
||||
|
||||
// Load the myApp module, which contains the directive
|
||||
beforeEach(module('myApp'));
|
||||
// Load the myApp module, which contains the directive
|
||||
beforeEach(module('myApp'));
|
||||
|
||||
// Store references to $rootScope and $compile
|
||||
// so they are available to all tests in this describe block
|
||||
beforeEach(inject(function(_$compile_, _$rootScope_){
|
||||
// The injector unwraps the underscores (_) from around the parameter names when matching
|
||||
$compile = _$compile_;
|
||||
$rootScope = _$rootScope_;
|
||||
}));
|
||||
// Store references to $rootScope and $compile
|
||||
// so they are available to all tests in this describe block
|
||||
beforeEach(inject(function(_$compile_, _$rootScope_){
|
||||
// The injector unwraps the underscores (_) from around the parameter names when matching
|
||||
$compile = _$compile_;
|
||||
$rootScope = _$rootScope_;
|
||||
}));
|
||||
|
||||
it('Replaces the element with the appropriate content', function() {
|
||||
// Compile a piece of HTML containing the directive
|
||||
var element = $compile("<a-great-eye></a-great-eye>")($rootScope);
|
||||
// fire all the watches, so the scope expression {{1 + 1}} will be evaluated
|
||||
$rootScope.$digest();
|
||||
// Check that the compiled element contains the templated content
|
||||
expect(element.html()).toContain("lidless, wreathed in flame, 2 times");
|
||||
});
|
||||
it('Replaces the element with the appropriate content', function() {
|
||||
// Compile a piece of HTML containing the directive
|
||||
var element = $compile("<a-great-eye></a-great-eye>")($rootScope);
|
||||
// fire all the watches, so the scope expression {{1 + 1}} will be evaluated
|
||||
$rootScope.$digest();
|
||||
// Check that the compiled element contains the templated content
|
||||
expect(element.html()).toContain("lidless, wreathed in flame, 2 times");
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
@@ -431,4 +425,3 @@ Otherwise you may run into issues if the test directory hierarchy differs from t
|
||||
|
||||
## Sample project
|
||||
See the [angular-seed](https://github.com/angular/angular-seed) project for an example.
|
||||
|
||||
|
||||
@@ -182,7 +182,7 @@ You can now rerun `npm run protractor` to see the tests run.
|
||||
# Experiments
|
||||
|
||||
* In the `PhoneListCtrl` controller, remove the statement that sets the `orderProp` value and
|
||||
you'll see that Angular will temporarily add a new "unknown" option to the drop-down list and the
|
||||
you'll see that Angular will temporarily add a new blank ("unknown") option to the drop-down list and the
|
||||
ordering will default to unordered/natural order.
|
||||
|
||||
* Add an `{{orderProp}}` binding into the `index.html` template to display its current value as
|
||||
|
||||
@@ -258,8 +258,8 @@ You should now see the following output in the Karma tab:
|
||||
|
||||
# Experiments
|
||||
|
||||
* At the bottom of `index.html`, add a `<pre>{{phones | json}}</pre>` binding to see the list of phones
|
||||
displayed in json format.
|
||||
* At the bottom of `index.html`, add a `<pre>{{phones | filter:query | orderBy:orderProp | json}}</pre>`
|
||||
binding to see the list of phones displayed in json format.
|
||||
|
||||
* In the `PhoneListCtrl` controller, pre-process the http response by limiting the number of phones
|
||||
to the first 5 in the list. Use the following code in the `$http` callback:
|
||||
|
||||
@@ -267,7 +267,7 @@ goog.i18n.currency.adjustPrecision = function(pattern, currencyCode) {
|
||||
* 18: two decimals precision (2), currency sign last (16), no space (0)
|
||||
* 50: two decimals precision (2), currency sign last (16), space (32)
|
||||
*
|
||||
* @type {!Object.<!Array.<?>>}
|
||||
* @const {!Object<!Array<?>>}
|
||||
*/
|
||||
goog.i18n.currency.CurrencyInfo = {
|
||||
'AED': [2, 'dh', '\u062f.\u0625.', 'DH'],
|
||||
@@ -334,7 +334,7 @@ goog.i18n.currency.CurrencyInfo = {
|
||||
|
||||
/**
|
||||
* Tier 2 currency information.
|
||||
* @type {!Object.<!Array.<?>>}
|
||||
* @const {!Object<!Array<?>>}
|
||||
*/
|
||||
goog.i18n.currency.CurrencyInfoTier2 = {
|
||||
'AFN': [48, 'Af.', 'AFN'],
|
||||
|
||||
+354
-308
File diff suppressed because it is too large
Load Diff
+1820
-1710
File diff suppressed because it is too large
Load Diff
@@ -18,7 +18,7 @@
|
||||
* This file is autogenerated by script:
|
||||
* http://go/generate_number_constants.py
|
||||
* using the --for_closure flag.
|
||||
* File generated from CLDR ver. 25
|
||||
* File generated from CLDR ver. 26
|
||||
*
|
||||
* To reduce the file size (which may cause issues in some JS
|
||||
* developing environments), this file will only contain locales
|
||||
@@ -42,7 +42,6 @@ goog.provide('goog.i18n.NumberFormatSymbols_am_ET');
|
||||
goog.provide('goog.i18n.NumberFormatSymbols_ar');
|
||||
goog.provide('goog.i18n.NumberFormatSymbols_ar_001');
|
||||
goog.provide('goog.i18n.NumberFormatSymbols_az');
|
||||
goog.provide('goog.i18n.NumberFormatSymbols_az_Cyrl_AZ');
|
||||
goog.provide('goog.i18n.NumberFormatSymbols_az_Latn_AZ');
|
||||
goog.provide('goog.i18n.NumberFormatSymbols_bg');
|
||||
goog.provide('goog.i18n.NumberFormatSymbols_bg_BG');
|
||||
@@ -364,13 +363,6 @@ goog.i18n.NumberFormatSymbols_az = {
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Number formatting symbols for locale az_Cyrl_AZ.
|
||||
* @enum {string}
|
||||
*/
|
||||
goog.i18n.NumberFormatSymbols_az_Cyrl_AZ = goog.i18n.NumberFormatSymbols_az;
|
||||
|
||||
|
||||
/**
|
||||
* Number formatting symbols for locale az_Latn_AZ.
|
||||
* @enum {string}
|
||||
@@ -455,8 +447,8 @@ goog.i18n.NumberFormatSymbols_br = {
|
||||
NAN: 'NaN',
|
||||
DECIMAL_PATTERN: '#,##0.###',
|
||||
SCIENTIFIC_PATTERN: '#E0',
|
||||
PERCENT_PATTERN: '#,##0%',
|
||||
CURRENCY_PATTERN: '\u00A4\u00A0#,##0.00',
|
||||
PERCENT_PATTERN: '#,##0\u00A0%',
|
||||
CURRENCY_PATTERN: '#,##0.00\u00A0\u00A4',
|
||||
DEF_CURRENCY_CODE: 'EUR'
|
||||
};
|
||||
|
||||
@@ -1063,7 +1055,7 @@ goog.i18n.NumberFormatSymbols_es = {
|
||||
NAN: 'NaN',
|
||||
DECIMAL_PATTERN: '#,##0.###',
|
||||
SCIENTIFIC_PATTERN: '#E0',
|
||||
PERCENT_PATTERN: '#,##0%',
|
||||
PERCENT_PATTERN: '#,##0\u00A0%',
|
||||
CURRENCY_PATTERN: '#,##0.00\u00A0\u00A4',
|
||||
DEF_CURRENCY_CODE: 'EUR'
|
||||
};
|
||||
@@ -1086,7 +1078,7 @@ goog.i18n.NumberFormatSymbols_es_419 = {
|
||||
NAN: 'NaN',
|
||||
DECIMAL_PATTERN: '#,##0.###',
|
||||
SCIENTIFIC_PATTERN: '#E0',
|
||||
PERCENT_PATTERN: '#,##0%',
|
||||
PERCENT_PATTERN: '#,##0\u00A0%',
|
||||
CURRENCY_PATTERN: '\u00A4#,##0.00',
|
||||
DEF_CURRENCY_CODE: 'MXN'
|
||||
};
|
||||
@@ -1492,7 +1484,7 @@ goog.i18n.NumberFormatSymbols_gu = {
|
||||
INFINITY: '\u221E',
|
||||
NAN: 'NaN',
|
||||
DECIMAL_PATTERN: '#,##,##0.###',
|
||||
SCIENTIFIC_PATTERN: '#E0',
|
||||
SCIENTIFIC_PATTERN: '[#E0]',
|
||||
PERCENT_PATTERN: '#,##,##0%',
|
||||
CURRENCY_PATTERN: '\u00A4#,##,##0.00',
|
||||
DEF_CURRENCY_CODE: 'INR'
|
||||
@@ -1582,7 +1574,7 @@ goog.i18n.NumberFormatSymbols_hi = {
|
||||
INFINITY: '\u221E',
|
||||
NAN: 'NaN',
|
||||
DECIMAL_PATTERN: '#,##,##0.###',
|
||||
SCIENTIFIC_PATTERN: '#E0',
|
||||
SCIENTIFIC_PATTERN: '[#E0]',
|
||||
PERCENT_PATTERN: '#,##,##0%',
|
||||
CURRENCY_PATTERN: '\u00A4#,##,##0.00',
|
||||
DEF_CURRENCY_CODE: 'INR'
|
||||
@@ -1961,7 +1953,7 @@ goog.i18n.NumberFormatSymbols_kn = {
|
||||
ZERO_DIGIT: '0',
|
||||
PLUS_SIGN: '+',
|
||||
MINUS_SIGN: '-',
|
||||
EXP_SYMBOL: '\u0C88',
|
||||
EXP_SYMBOL: 'E',
|
||||
PERMILL: '\u2030',
|
||||
INFINITY: '\u221E',
|
||||
NAN: 'NaN',
|
||||
@@ -2085,7 +2077,7 @@ goog.i18n.NumberFormatSymbols_lo = {
|
||||
PERMILL: '\u2030',
|
||||
INFINITY: '\u221E',
|
||||
NAN:
|
||||
'\u0E9A\u0ECD\u0EC8\u0EC1\u0EA1\u0EC8\u0E99\u0EC2\u0E95\u0EC0\u0EA5\u0E81',
|
||||
'\u0E9A\u0ECD\u0EC8\u200B\u0EC1\u0EA1\u0EC8\u0E99\u200B\u0EC2\u0E95\u200B\u0EC0\u0EA5\u0E81',
|
||||
DECIMAL_PATTERN: '#,##0.###',
|
||||
SCIENTIFIC_PATTERN: '#',
|
||||
PERCENT_PATTERN: '#,##0%',
|
||||
@@ -2149,7 +2141,7 @@ goog.i18n.NumberFormatSymbols_lv = {
|
||||
DECIMAL_PATTERN: '#,##0.###',
|
||||
SCIENTIFIC_PATTERN: '#E0',
|
||||
PERCENT_PATTERN: '#,##0%',
|
||||
CURRENCY_PATTERN: '\u00A4#,##0.00',
|
||||
CURRENCY_PATTERN: '\u00A4#0.00',
|
||||
DEF_CURRENCY_CODE: 'EUR'
|
||||
};
|
||||
|
||||
@@ -2208,8 +2200,8 @@ goog.i18n.NumberFormatSymbols_ml = {
|
||||
NAN: 'NaN',
|
||||
DECIMAL_PATTERN: '#,##,##0.###',
|
||||
SCIENTIFIC_PATTERN: '#E0',
|
||||
PERCENT_PATTERN: '#,##,##0%',
|
||||
CURRENCY_PATTERN: '#,##,##0.00\u00A4',
|
||||
PERCENT_PATTERN: '#,##0%',
|
||||
CURRENCY_PATTERN: '\u00A4#,##0.00',
|
||||
DEF_CURRENCY_CODE: 'INR'
|
||||
};
|
||||
|
||||
@@ -2266,7 +2258,7 @@ goog.i18n.NumberFormatSymbols_mr = {
|
||||
PERMILL: '\u2030',
|
||||
INFINITY: '\u221E',
|
||||
NAN: 'NaN',
|
||||
DECIMAL_PATTERN: '#,##0.###',
|
||||
DECIMAL_PATTERN: '#,##,##0.###',
|
||||
SCIENTIFIC_PATTERN: '[#E0]',
|
||||
PERCENT_PATTERN: '#,##0%',
|
||||
CURRENCY_PATTERN: '\u00A4#,##0.00',
|
||||
@@ -2427,7 +2419,7 @@ goog.i18n.NumberFormatSymbols_ne = {
|
||||
DECIMAL_PATTERN: '#,##0.###',
|
||||
SCIENTIFIC_PATTERN: '#E0',
|
||||
PERCENT_PATTERN: '#,##0%',
|
||||
CURRENCY_PATTERN: '\u00A4#,##0.00',
|
||||
CURRENCY_PATTERN: '\u00A4\u00A0#,##0.00',
|
||||
DEF_CURRENCY_CODE: 'NPR'
|
||||
};
|
||||
|
||||
@@ -2545,7 +2537,7 @@ goog.i18n.NumberFormatSymbols_pa = {
|
||||
INFINITY: '\u221E',
|
||||
NAN: 'NaN',
|
||||
DECIMAL_PATTERN: '#,##,##0.###',
|
||||
SCIENTIFIC_PATTERN: '#E0',
|
||||
SCIENTIFIC_PATTERN: '[#E0]',
|
||||
PERCENT_PATTERN: '#,##,##0%',
|
||||
CURRENCY_PATTERN: '\u00A4#,##,##0.00',
|
||||
DEF_CURRENCY_CODE: 'INR'
|
||||
@@ -2718,7 +2710,7 @@ goog.i18n.NumberFormatSymbols_si = {
|
||||
INFINITY: '\u221E',
|
||||
NAN: 'NaN',
|
||||
DECIMAL_PATTERN: '#,##0.###',
|
||||
SCIENTIFIC_PATTERN: '#E0',
|
||||
SCIENTIFIC_PATTERN: '#',
|
||||
PERCENT_PATTERN: '#,##0%',
|
||||
CURRENCY_PATTERN: '\u00A4#,##0.00',
|
||||
DEF_CURRENCY_CODE: 'LKR'
|
||||
@@ -2957,10 +2949,10 @@ goog.i18n.NumberFormatSymbols_te = {
|
||||
PERMILL: '\u2030',
|
||||
INFINITY: '\u221E',
|
||||
NAN: 'NaN',
|
||||
DECIMAL_PATTERN: '#,##0.###',
|
||||
DECIMAL_PATTERN: '#,##,##0.###',
|
||||
SCIENTIFIC_PATTERN: '#E0',
|
||||
PERCENT_PATTERN: '#,##0%',
|
||||
CURRENCY_PATTERN: '\u00A4#,##0.00',
|
||||
CURRENCY_PATTERN: '\u00A4#,##,##0.00',
|
||||
DEF_CURRENCY_CODE: 'INR'
|
||||
};
|
||||
|
||||
@@ -3102,8 +3094,8 @@ goog.i18n.NumberFormatSymbols_ur = {
|
||||
NAN: 'NaN',
|
||||
DECIMAL_PATTERN: '#,##0.###',
|
||||
SCIENTIFIC_PATTERN: '#E0',
|
||||
PERCENT_PATTERN: '#,##0%',
|
||||
CURRENCY_PATTERN: '\u00A4#,##0.00\u200E',
|
||||
PERCENT_PATTERN: '#,##,##0%',
|
||||
CURRENCY_PATTERN: '\u00A4\u00A0#,##,##0.00',
|
||||
DEF_CURRENCY_CODE: 'PKR'
|
||||
};
|
||||
|
||||
@@ -3321,10 +3313,6 @@ if (goog.LOCALE == 'az') {
|
||||
goog.i18n.NumberFormatSymbols = goog.i18n.NumberFormatSymbols_az;
|
||||
}
|
||||
|
||||
if (goog.LOCALE == 'az_Cyrl_AZ' || goog.LOCALE == 'az-Cyrl-AZ') {
|
||||
goog.i18n.NumberFormatSymbols = goog.i18n.NumberFormatSymbols_az;
|
||||
}
|
||||
|
||||
if (goog.LOCALE == 'az_Latn_AZ' || goog.LOCALE == 'az-Latn-AZ') {
|
||||
goog.i18n.NumberFormatSymbols = goog.i18n.NumberFormatSymbols_az;
|
||||
}
|
||||
|
||||
+531
-375
File diff suppressed because it is too large
Load Diff
+44
-27
@@ -17,7 +17,7 @@
|
||||
*
|
||||
* This file is autogenerated by script:
|
||||
* http://go/generate_pluralrules.py
|
||||
* File generated from CLDR ver. 25
|
||||
* File generated from CLDR ver. 26
|
||||
*
|
||||
* Before check in, this file could have been manually edited. This is to
|
||||
* incorporate changes before we could fix CLDR. All manual modification must be
|
||||
@@ -409,6 +409,23 @@ goog.i18n.pluralRules.srSelect_ = function(n, opt_precision) {
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
|
||||
/**
|
||||
* Plural select rules for mk locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @param {number=} opt_precision Precision for number formatting, if not default.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.mkSelect_ = function(n, opt_precision) {
|
||||
var i = n | 0;
|
||||
var vf = goog.i18n.pluralRules.get_vf_(n, opt_precision);
|
||||
if (vf.v == 0 && i % 10 == 1 || vf.f % 10 == 1) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
|
||||
/**
|
||||
* Plural select rules for hi locale
|
||||
*
|
||||
@@ -426,17 +443,15 @@ goog.i18n.pluralRules.hiSelect_ = function(n, opt_precision) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Plural select rules for mk locale
|
||||
* Plural select rules for pt locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @param {number=} opt_precision Precision for number formatting, if not default.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.mkSelect_ = function(n, opt_precision) {
|
||||
var i = n | 0;
|
||||
var vf = goog.i18n.pluralRules.get_vf_(n, opt_precision);
|
||||
if (vf.v == 0 && i % 10 == 1 || vf.f % 10 == 1) {
|
||||
goog.i18n.pluralRules.ptSelect_ = function(n, opt_precision) {
|
||||
if (n >= 0 && n <= 2 && n != 2) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
@@ -562,24 +577,6 @@ goog.i18n.pluralRules.akSelect_ = function(n, opt_precision) {
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
|
||||
/**
|
||||
* Plural select rules for pt locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @param {number=} opt_precision Precision for number formatting, if not default.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.ptSelect_ = function(n, opt_precision) {
|
||||
var i = n | 0;
|
||||
var vf = goog.i18n.pluralRules.get_vf_(n, opt_precision);
|
||||
var wt = goog.i18n.pluralRules.get_wt_(vf.v, vf.f);
|
||||
if (i == 1 && vf.v == 0 || i == 0 && wt.t == 1) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
|
||||
/**
|
||||
* Plural select rules for pl locale
|
||||
*
|
||||
@@ -748,6 +745,29 @@ goog.i18n.pluralRules.gdSelect_ = function(n, opt_precision) {
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
|
||||
/**
|
||||
* Plural select rules for dsb locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @param {number=} opt_precision Precision for number formatting, if not default.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.dsbSelect_ = function(n, opt_precision) {
|
||||
var i = n | 0;
|
||||
var vf = goog.i18n.pluralRules.get_vf_(n, opt_precision);
|
||||
if (vf.v == 0 && i % 100 == 1 || vf.f % 100 == 1) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
if (vf.v == 0 && i % 100 == 2 || vf.f % 100 == 2) {
|
||||
return goog.i18n.pluralRules.Keyword.TWO;
|
||||
}
|
||||
if (vf.v == 0 && i % 100 >= 3 && i % 100 <= 4 || vf.f % 100 >= 3 && vf.f % 100 <= 4) {
|
||||
return goog.i18n.pluralRules.Keyword.FEW;
|
||||
}
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
|
||||
/**
|
||||
* Plural select rules for lv locale
|
||||
*
|
||||
@@ -852,9 +872,6 @@ if (goog.LOCALE == 'en_IE' || goog.LOCALE == 'en-IE') {
|
||||
if (goog.LOCALE == 'en_IN' || goog.LOCALE == 'en-IN') {
|
||||
goog.i18n.pluralRules.select = goog.i18n.pluralRules.enSelect_;
|
||||
}
|
||||
if (goog.LOCALE == 'en_ISO' || goog.LOCALE == 'en-ISO') {
|
||||
goog.i18n.pluralRules.select = goog.i18n.pluralRules.enSelect_;
|
||||
}
|
||||
if (goog.LOCALE == 'en_SG' || goog.LOCALE == 'en-SG') {
|
||||
goog.i18n.pluralRules.select = goog.i18n.pluralRules.enSelect_;
|
||||
}
|
||||
|
||||
@@ -91,15 +91,6 @@ var getTaggedVersion = function() {
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Stable versions have an even minor version and have no prerelease
|
||||
* @param {SemVer} version The version to test
|
||||
* @return {Boolean} True if the version is stable
|
||||
*/
|
||||
var isStable = function(version) {
|
||||
return semver.satisfies(version, '1.0 || 1.2') && version.prerelease.length === 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a collection of all the previous versions sorted by semantic version
|
||||
* @return {Array.<SemVer>} The collection of previous versions
|
||||
@@ -119,8 +110,6 @@ var getPreviousVersions = function() {
|
||||
})
|
||||
.filter()
|
||||
.map(function(version) {
|
||||
version.isStable = isStable(version);
|
||||
|
||||
version.docsUrl = 'http://code.angularjs.org/' + version.version + '/docs';
|
||||
// Versions before 1.0.2 had a different docs folder name
|
||||
if ( version.major < 1 || (version.major === 1 && version.minor === 0 && version.dot < 2 ) ) {
|
||||
|
||||
Generated
+7
-7
@@ -1395,7 +1395,7 @@
|
||||
}
|
||||
},
|
||||
"dgeni-packages": {
|
||||
"version": "0.10.5",
|
||||
"version": "0.10.7",
|
||||
"dependencies": {
|
||||
"catharsis": {
|
||||
"version": "0.7.1"
|
||||
@@ -1454,7 +1454,7 @@
|
||||
"version": "1.2.2"
|
||||
},
|
||||
"estraverse": {
|
||||
"version": "1.5.1"
|
||||
"version": "1.7.1"
|
||||
},
|
||||
"glob": {
|
||||
"version": "3.2.11",
|
||||
@@ -1465,16 +1465,16 @@
|
||||
}
|
||||
},
|
||||
"htmlparser2": {
|
||||
"version": "3.7.3",
|
||||
"version": "3.8.2",
|
||||
"dependencies": {
|
||||
"domhandler": {
|
||||
"version": "2.2.0"
|
||||
"version": "2.3.0"
|
||||
},
|
||||
"domutils": {
|
||||
"version": "1.5.0"
|
||||
},
|
||||
"domelementtype": {
|
||||
"version": "1.1.1"
|
||||
"version": "1.1.3"
|
||||
},
|
||||
"readable-stream": {
|
||||
"version": "1.1.13",
|
||||
@@ -1528,7 +1528,7 @@
|
||||
"dependencies": {
|
||||
"fsevents": {
|
||||
"version": "0.2.1",
|
||||
"from": "fsevents@git://github.com/pipobscure/fsevents#7dcdf9fa3f8956610fd6f69f72c67bace2de7138",
|
||||
"from": "git://github.com/pipobscure/fsevents#7dcdf9fa3f8956610fd6f69f72c67bace2de7138",
|
||||
"resolved": "git://github.com/pipobscure/fsevents#7dcdf9fa3f8956610fd6f69f72c67bace2de7138",
|
||||
"dependencies": {
|
||||
"nan": {
|
||||
@@ -1596,7 +1596,7 @@
|
||||
"version": "0.0.10",
|
||||
"dependencies": {
|
||||
"combined-stream": {
|
||||
"version": "0.0.5",
|
||||
"version": "0.0.7",
|
||||
"dependencies": {
|
||||
"delayed-stream": {
|
||||
"version": "0.0.5"
|
||||
|
||||
@@ -96,8 +96,14 @@ function publish {
|
||||
# don't publish every build to npm
|
||||
if [ "${NEW_VERSION/+sha}" = "$NEW_VERSION" ] ; then
|
||||
if [ "${NEW_VERSION/-}" = "$NEW_VERSION" ] ; then
|
||||
# publish releases as "latest"
|
||||
npm publish
|
||||
if [[ $NEW_VERSION =~ ^1\.2\.[0-9]+$ ]] ; then
|
||||
# publish 1.2.x releases with the appropriate tag
|
||||
# this ensures that `npm install` by default will not grab `1.2.x` releases
|
||||
npm publish --tag=old
|
||||
else
|
||||
# publish releases as "latest"
|
||||
npm publish
|
||||
fi
|
||||
else
|
||||
# publish prerelease builds with the beta tag
|
||||
npm publish --tag=beta
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
"angularModule": false,
|
||||
"nodeName_": false,
|
||||
"uid": false,
|
||||
"toDebugString": false,
|
||||
|
||||
"REGEX_STRING_REGEXP" : false,
|
||||
"lowercase": false,
|
||||
|
||||
+8
-8
@@ -362,7 +362,7 @@ function int(str) {
|
||||
|
||||
|
||||
function inherit(parent, extra) {
|
||||
return extend(new (extend(function() {}, {prototype:parent}))(), extra);
|
||||
return extend(Object.create(parent), extra);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -625,7 +625,7 @@ function makeMap(str) {
|
||||
|
||||
|
||||
function nodeName_(element) {
|
||||
return lowercase(element.nodeName || element[0].nodeName);
|
||||
return lowercase(element.nodeName || (element[0] && element[0].nodeName));
|
||||
}
|
||||
|
||||
function includes(array, obj) {
|
||||
@@ -634,7 +634,7 @@ function includes(array, obj) {
|
||||
|
||||
function arrayRemove(array, value) {
|
||||
var index = array.indexOf(value);
|
||||
if (index >=0)
|
||||
if (index >= 0)
|
||||
array.splice(index, 1);
|
||||
return value;
|
||||
}
|
||||
@@ -835,7 +835,7 @@ function equals(o1, o2) {
|
||||
if (isArray(o1)) {
|
||||
if (!isArray(o2)) return false;
|
||||
if ((length = o1.length) == o2.length) {
|
||||
for (key=0; key<length; key++) {
|
||||
for (key = 0; key < length; key++) {
|
||||
if (!equals(o1[key], o2[key])) return false;
|
||||
}
|
||||
return true;
|
||||
@@ -921,7 +921,7 @@ function bind(self, fn) {
|
||||
return curryArgs.length
|
||||
? function() {
|
||||
return arguments.length
|
||||
? fn.apply(self, curryArgs.concat(slice.call(arguments, 0)))
|
||||
? fn.apply(self, concat(curryArgs, arguments, 0))
|
||||
: fn.apply(self, curryArgs);
|
||||
}
|
||||
: function() {
|
||||
@@ -1121,7 +1121,7 @@ var ngAttrPrefixes = ['ng-', 'data-ng-', 'ng:', 'x-ng-'];
|
||||
function getNgAttribute(element, ngAttr) {
|
||||
var attr, i, ii = ngAttrPrefixes.length;
|
||||
element = jqLite(element);
|
||||
for (i=0; i<ii; ++i) {
|
||||
for (i = 0; i < ii; ++i) {
|
||||
attr = ngAttrPrefixes[i] + ngAttr;
|
||||
if (isString(attr = element.attr(attr))) {
|
||||
return attr;
|
||||
@@ -1331,8 +1331,8 @@ function angularInit(element, bootstrap) {
|
||||
* @param {Object=} config an object for defining configuration options for the application. The
|
||||
* following keys are supported:
|
||||
*
|
||||
* - `strictDi`: disable automatic function annotation for the application. This is meant to
|
||||
* assist in finding bugs which break minified code.
|
||||
* * `strictDi` - disable automatic function annotation for the application. This is meant to
|
||||
* assist in finding bugs which break minified code. Defaults to `false`.
|
||||
*
|
||||
* @returns {auto.$injector} Returns the newly created injector for this app.
|
||||
*/
|
||||
|
||||
+14
-10
@@ -10,9 +10,10 @@
|
||||
* Creates an injector object that can be used for retrieving services as well as for
|
||||
* dependency injection (see {@link guide/di dependency injection}).
|
||||
*
|
||||
|
||||
* @param {Array.<string|Function>} modules A list of module functions or their aliases. See
|
||||
* {@link angular.module}. The `ng` module must be explicitly added.
|
||||
* {@link angular.module}. The `ng` module must be explicitly added.
|
||||
* @param {boolean=} [strictDi=false] Whether the injector should be in strict mode, which
|
||||
* disallows argument name annotation inference.
|
||||
* @returns {injector} Injector object. See {@link auto.$injector $injector}.
|
||||
*
|
||||
* @example
|
||||
@@ -158,8 +159,10 @@ function annotate(fn, strictDi, name) {
|
||||
* ## Inference
|
||||
*
|
||||
* In JavaScript calling `toString()` on a function returns the function definition. The definition
|
||||
* can then be parsed and the function arguments can be extracted. *NOTE:* This does not work with
|
||||
* minification, and obfuscation tools since these tools change the argument names.
|
||||
* can then be parsed and the function arguments can be extracted. This method of discovering
|
||||
* annotations is disallowed when the injector is in strict mode.
|
||||
* *NOTE:* This does not work with minification, and obfuscation tools since these tools change the
|
||||
* argument names.
|
||||
*
|
||||
* ## `$inject` Annotation
|
||||
* By adding an `$inject` property onto a function the injection parameters can be specified.
|
||||
@@ -244,6 +247,8 @@ function annotate(fn, strictDi, name) {
|
||||
* expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
|
||||
* ```
|
||||
*
|
||||
* You can disallow this method by using strict injection mode.
|
||||
*
|
||||
* This method does not work with code minification / obfuscation. For this reason the following
|
||||
* annotation strategies are supported.
|
||||
*
|
||||
@@ -296,6 +301,8 @@ function annotate(fn, strictDi, name) {
|
||||
* @param {Function|Array.<string|Function>} fn Function for which dependent service names need to
|
||||
* be retrieved as described above.
|
||||
*
|
||||
* @param {boolean=} [strictDi=false] Disallow argument name annotation inference.
|
||||
*
|
||||
* @returns {Array.<string>} The names of the services which the function requires.
|
||||
*/
|
||||
|
||||
@@ -815,14 +822,11 @@ function createInjector(modulesToLoad, strictDi) {
|
||||
}
|
||||
|
||||
function instantiate(Type, locals, serviceName) {
|
||||
var Constructor = function() {},
|
||||
instance, returnedValue;
|
||||
|
||||
// Check if Type is annotated and use just the given function at n-1 as parameter
|
||||
// e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]);
|
||||
Constructor.prototype = (isArray(Type) ? Type[Type.length - 1] : Type).prototype;
|
||||
instance = new Constructor();
|
||||
returnedValue = invoke(Type, instance, locals, serviceName);
|
||||
// Object creation: http://jsperf.com/create-constructor/2
|
||||
var instance = Object.create((isArray(Type) ? Type[Type.length - 1] : Type).prototype);
|
||||
var returnedValue = invoke(Type, instance, locals, serviceName);
|
||||
|
||||
return isObject(returnedValue) || isFunction(returnedValue) ? returnedValue : instance;
|
||||
}
|
||||
|
||||
+4
-2
@@ -87,10 +87,12 @@
|
||||
* `'ngModel'`).
|
||||
* - `injector()` - retrieves the injector of the current element or its parent.
|
||||
* - `scope()` - retrieves the {@link ng.$rootScope.Scope scope} of the current
|
||||
* element or its parent.
|
||||
* element or its parent. Requires {@link guide/production#disabling-debug-data Debug Data} to
|
||||
* be enabled.
|
||||
* - `isolateScope()` - retrieves an isolate {@link ng.$rootScope.Scope scope} if one is attached directly to the
|
||||
* current element. This getter should be used only on elements that contain a directive which starts a new isolate
|
||||
* scope. Calling `scope()` on this element always returns the original non-isolate scope.
|
||||
* Requires {@link guide/production#disabling-debug-data Debug Data} to be enabled.
|
||||
* - `inheritedData()` - same as `data()`, but walks up the DOM until a value is found or the top
|
||||
* parent element is reached.
|
||||
*
|
||||
@@ -597,7 +599,7 @@ forEach({
|
||||
}
|
||||
} else {
|
||||
return (element[name] ||
|
||||
(element.attributes.getNamedItem(name)|| noop).specified)
|
||||
(element.attributes.getNamedItem(name) || noop).specified)
|
||||
? lowercasedName
|
||||
: undefined;
|
||||
}
|
||||
|
||||
+4
-21
@@ -37,31 +37,14 @@ function minErr(module, ErrorConstructor) {
|
||||
prefix = '[' + (module ? module + ':' : '') + code + '] ',
|
||||
template = arguments[1],
|
||||
templateArgs = arguments,
|
||||
stringify = function(obj) {
|
||||
if (typeof obj === 'function') {
|
||||
return obj.toString().replace(/ \{[\s\S]*$/, '');
|
||||
} else if (typeof obj === 'undefined') {
|
||||
return 'undefined';
|
||||
} else if (typeof obj !== 'string') {
|
||||
return JSON.stringify(obj);
|
||||
}
|
||||
return obj;
|
||||
},
|
||||
|
||||
message, i;
|
||||
|
||||
message = prefix + template.replace(/\{\d+\}/g, function(match) {
|
||||
var index = +match.slice(1, -1), arg;
|
||||
|
||||
if (index + 2 < templateArgs.length) {
|
||||
arg = templateArgs[index + 2];
|
||||
if (typeof arg === 'function') {
|
||||
return arg.toString().replace(/ ?\{[\s\S]*$/, '');
|
||||
} else if (typeof arg === 'undefined') {
|
||||
return 'undefined';
|
||||
} else if (typeof arg !== 'string') {
|
||||
return toJson(arg);
|
||||
}
|
||||
return arg;
|
||||
return toDebugString(templateArgs[index + 2]);
|
||||
}
|
||||
return match;
|
||||
});
|
||||
@@ -69,8 +52,8 @@ function minErr(module, ErrorConstructor) {
|
||||
message = message + '\nhttp://errors.angularjs.org/"NG_VERSION_FULL"/' +
|
||||
(module ? module + '/' : '') + code;
|
||||
for (i = 2; i < arguments.length; i++) {
|
||||
message = message + (i == 2 ? '?' : '&') + 'p' + (i-2) + '=' +
|
||||
encodeURIComponent(stringify(arguments[i]));
|
||||
message = message + (i == 2 ? '?' : '&') + 'p' + (i - 2) + '=' +
|
||||
encodeURIComponent(toDebugString(arguments[i]));
|
||||
}
|
||||
return new ErrorConstructor(message);
|
||||
};
|
||||
|
||||
@@ -17,7 +17,7 @@ function $AnchorScrollProvider() {
|
||||
* @name $anchorScrollProvider#disableAutoScrolling
|
||||
*
|
||||
* @description
|
||||
* By default, {@link ng.$anchorScroll $anchorScroll()} will automatically will detect changes to
|
||||
* By default, {@link ng.$anchorScroll $anchorScroll()} will automatically detect changes to
|
||||
* {@link ng.$location#hash $location.hash()} and scroll to the element matching the new hash.<br />
|
||||
* Use this method to disable automatic scrolling.
|
||||
*
|
||||
|
||||
+4
-5
@@ -19,8 +19,7 @@
|
||||
/**
|
||||
* @param {object} window The global window object.
|
||||
* @param {object} document jQuery wrapped document.
|
||||
* @param {function()} XHR XMLHttpRequest constructor.
|
||||
* @param {object} $log console.log or an object with the same interface.
|
||||
* @param {object} $log window.console or an object with the same interface.
|
||||
* @param {object} $sniffer $sniffer service
|
||||
*/
|
||||
function Browser(window, document, $log, $sniffer) {
|
||||
@@ -171,7 +170,7 @@ function Browser(window, document, $log, $sniffer) {
|
||||
// IE<10 from getting into redirect loop when in LocationHashbangInHtml5Url mode.
|
||||
// See https://github.com/angular/angular.js/commit/ffb2701
|
||||
if (lastBrowserUrl === url && (!$sniffer.history || sameState)) {
|
||||
return;
|
||||
return self;
|
||||
}
|
||||
var sameBase = lastBrowserUrl && stripHash(lastBrowserUrl) === stripHash(url);
|
||||
lastBrowserUrl = url;
|
||||
@@ -370,8 +369,8 @@ function Browser(window, document, $log, $sniffer) {
|
||||
// - 20 cookies per unique domain
|
||||
// - 4096 bytes per cookie
|
||||
if (cookieLength > 4096) {
|
||||
$log.warn("Cookie '"+ name +
|
||||
"' possibly not set or overflowed because it was too large ("+
|
||||
$log.warn("Cookie '" + name +
|
||||
"' possibly not set or overflowed because it was too large (" +
|
||||
cookieLength + " > 4096 bytes)!");
|
||||
}
|
||||
}
|
||||
|
||||
+13
-13
@@ -180,7 +180,7 @@
|
||||
*
|
||||
*
|
||||
* #### `bindToController`
|
||||
* When an isolate scope is used for a component (see above), and `controllerAs` is used, `bindToController` will
|
||||
* When an isolate scope is used for a component (see above), and `controllerAs` is used, `bindToController: true` will
|
||||
* allow a component to have its properties bound to the controller, rather than to scope. When the controller
|
||||
* is instantiated, the initial values of the isolate scope bindings are already available.
|
||||
*
|
||||
@@ -1029,16 +1029,16 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
|
||||
// for each tuples
|
||||
var nbrUrisWith2parts = Math.floor(rawUris.length / 2);
|
||||
for (var i=0; i<nbrUrisWith2parts; i++) {
|
||||
var innerIdx = i*2;
|
||||
for (var i = 0; i < nbrUrisWith2parts; i++) {
|
||||
var innerIdx = i * 2;
|
||||
// sanitize the uri
|
||||
result += $$sanitizeUri(trim(rawUris[innerIdx]), true);
|
||||
// add the descriptor
|
||||
result += (" " + trim(rawUris[innerIdx+1]));
|
||||
result += (" " + trim(rawUris[innerIdx + 1]));
|
||||
}
|
||||
|
||||
// split the last item into uri and descriptor
|
||||
var lastTuple = trim(rawUris[i*2]).split(/\s/);
|
||||
var lastTuple = trim(rawUris[i * 2]).split(/\s/);
|
||||
|
||||
// sanitize the last uri
|
||||
result += $$sanitizeUri(trim(lastTuple[0]), true);
|
||||
@@ -1232,7 +1232,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
if (!node) {
|
||||
return 'html';
|
||||
} else {
|
||||
return nodeName_(node) !== 'foreignobject' && node.toString().match(/SVG/) ? 'svg': 'html';
|
||||
return nodeName_(node) !== 'foreignobject' && node.toString().match(/SVG/) ? 'svg' : 'html';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2045,7 +2045,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
var match = null;
|
||||
if (hasDirectives.hasOwnProperty(name)) {
|
||||
for (var directive, directives = $injector.get(name + Suffix),
|
||||
i = 0, ii = directives.length; i<ii; i++) {
|
||||
i = 0, ii = directives.length; i < ii; i++) {
|
||||
try {
|
||||
directive = directives[i];
|
||||
if ((maxPriority === undefined || maxPriority > directive.priority) &&
|
||||
@@ -2074,7 +2074,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
function directiveIsMultiElement(name) {
|
||||
if (hasDirectives.hasOwnProperty(name)) {
|
||||
for (var directive, directives = $injector.get(name + Suffix),
|
||||
i = 0, ii = directives.length; i<ii; i++) {
|
||||
i = 0, ii = directives.length; i < ii; i++) {
|
||||
directive = directives[i];
|
||||
if (directive.multiElement) {
|
||||
return true;
|
||||
@@ -2227,10 +2227,10 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
var childBoundTranscludeFn = boundTranscludeFn;
|
||||
if (scope.$$destroyed) return;
|
||||
if (linkQueue) {
|
||||
linkQueue.push(scope);
|
||||
linkQueue.push(node);
|
||||
linkQueue.push(rootElement);
|
||||
linkQueue.push(childBoundTranscludeFn);
|
||||
linkQueue.push(scope,
|
||||
node,
|
||||
rootElement,
|
||||
childBoundTranscludeFn);
|
||||
} else {
|
||||
if (afterTemplateNodeLinkFn.transcludeOnThisElement) {
|
||||
childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude, boundTranscludeFn);
|
||||
@@ -2293,7 +2293,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
case 'svg':
|
||||
case 'math':
|
||||
var wrapper = document.createElement('div');
|
||||
wrapper.innerHTML = '<'+type+'>'+template+'</'+type+'>';
|
||||
wrapper.innerHTML = '<' + type + '>' + template + '</' + type + '>';
|
||||
return wrapper.childNodes[0].childNodes;
|
||||
default:
|
||||
return template;
|
||||
|
||||
@@ -59,6 +59,10 @@ function $ControllerProvider() {
|
||||
* * if $controllerProvider#allowGlobals, check `window[constructor]` on the global
|
||||
* `window` object (not recommended)
|
||||
*
|
||||
* The string can use the `controller as property` syntax, where the controller instance is published
|
||||
* as the specified property on the `scope`; the `scope` must be injected into `locals` param for this
|
||||
* to work correctly.
|
||||
*
|
||||
* @param {Object} locals Injection locals for Controller.
|
||||
* @return {Object} Instance of given controller.
|
||||
*
|
||||
@@ -104,10 +108,10 @@ function $ControllerProvider() {
|
||||
//
|
||||
// This feature is not intended for use by applications, and is thus not documented
|
||||
// publicly.
|
||||
var Constructor = function() {};
|
||||
Constructor.prototype = (isArray(expression) ?
|
||||
// Object creation: http://jsperf.com/create-constructor/2
|
||||
var controllerPrototype = (isArray(expression) ?
|
||||
expression[expression.length - 1] : expression).prototype;
|
||||
instance = new Constructor();
|
||||
instance = Object.create(controllerPrototype);
|
||||
|
||||
if (identifier) {
|
||||
addIdentifier(locals, identifier, instance, constructor || expression.name);
|
||||
|
||||
@@ -471,9 +471,7 @@ var formDirectiveFactory = function(isNgForm) {
|
||||
controller.$setSubmitted();
|
||||
});
|
||||
|
||||
event.preventDefault
|
||||
? event.preventDefault()
|
||||
: event.returnValue = false; // IE
|
||||
event.preventDefault();
|
||||
};
|
||||
|
||||
addEventListenerFn(formElement[0], 'submit', handleFormSubmission);
|
||||
|
||||
+203
-105
@@ -41,10 +41,16 @@ var inputType = {
|
||||
* @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
|
||||
* minlength.
|
||||
* @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
|
||||
* maxlength.
|
||||
* @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
|
||||
* RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
|
||||
* patterns defined as scope expressions.
|
||||
* maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
|
||||
* any length.
|
||||
* @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
|
||||
* that contains the regular expression body that will be converted to a regular expression
|
||||
* as in the ngPattern directive.
|
||||
* @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
|
||||
* a RegExp found by evaluating the Angular expression given in the attribute value.
|
||||
* If the expression evaluates to a RegExp object then this is used directly.
|
||||
* If the expression is a string then it will be converted to a RegExp after wrapping it in `^` and `$`
|
||||
* characters. For instance, `"abc"` will be converted to `new RegExp('^abc$')`.
|
||||
* @param {string=} ngChange Angular expression to be executed when input changes due to user
|
||||
* interaction with the input element.
|
||||
* @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
|
||||
@@ -584,10 +590,16 @@ var inputType = {
|
||||
* @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
|
||||
* minlength.
|
||||
* @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
|
||||
* maxlength.
|
||||
* @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
|
||||
* RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
|
||||
* patterns defined as scope expressions.
|
||||
* maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
|
||||
* any length.
|
||||
* @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
|
||||
* that contains the regular expression body that will be converted to a regular expression
|
||||
* as in the ngPattern directive.
|
||||
* @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
|
||||
* a RegExp found by evaluating the Angular expression given in the attribute value.
|
||||
* If the expression evaluates to a RegExp object then this is used directly.
|
||||
* If the expression is a string then it will be converted to a RegExp after wrapping it in `^` and `$`
|
||||
* characters. For instance, `"abc"` will be converted to `new RegExp('^abc$')`.
|
||||
* @param {string=} ngChange Angular expression to be executed when input changes due to user
|
||||
* interaction with the input element.
|
||||
*
|
||||
@@ -666,10 +678,16 @@ var inputType = {
|
||||
* @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
|
||||
* minlength.
|
||||
* @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
|
||||
* maxlength.
|
||||
* @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
|
||||
* RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
|
||||
* patterns defined as scope expressions.
|
||||
* maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
|
||||
* any length.
|
||||
* @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
|
||||
* that contains the regular expression body that will be converted to a regular expression
|
||||
* as in the ngPattern directive.
|
||||
* @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
|
||||
* a RegExp found by evaluating the Angular expression given in the attribute value.
|
||||
* If the expression evaluates to a RegExp object then this is used directly.
|
||||
* If the expression is a string then it will be converted to a RegExp after wrapping it in `^` and `$`
|
||||
* characters. For instance, `"abc"` will be converted to `new RegExp('^abc$')`.
|
||||
* @param {string=} ngChange Angular expression to be executed when input changes due to user
|
||||
* interaction with the input element.
|
||||
*
|
||||
@@ -749,10 +767,16 @@ var inputType = {
|
||||
* @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
|
||||
* minlength.
|
||||
* @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
|
||||
* maxlength.
|
||||
* @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
|
||||
* RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
|
||||
* patterns defined as scope expressions.
|
||||
* maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
|
||||
* any length.
|
||||
* @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
|
||||
* that contains the regular expression body that will be converted to a regular expression
|
||||
* as in the ngPattern directive.
|
||||
* @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
|
||||
* a RegExp found by evaluating the Angular expression given in the attribute value.
|
||||
* If the expression evaluates to a RegExp object then this is used directly.
|
||||
* If the expression is a string then it will be converted to a RegExp after wrapping it in `^` and `$`
|
||||
* characters. For instance, `"abc"` will be converted to `new RegExp('^abc$')`.
|
||||
* @param {string=} ngChange Angular expression to be executed when input changes due to user
|
||||
* interaction with the input element.
|
||||
*
|
||||
@@ -1015,7 +1039,7 @@ function baseInputType(scope, element, attr, ctrl, $sniffer, $browser) {
|
||||
element.on('change', listener);
|
||||
|
||||
ctrl.$render = function() {
|
||||
element.val(ctrl.$isEmpty(ctrl.$modelValue) ? '' : ctrl.$viewValue);
|
||||
element.val(ctrl.$isEmpty(ctrl.$viewValue) ? '' : ctrl.$viewValue);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1063,8 +1087,8 @@ function createDateParser(regexp, mapping) {
|
||||
// When a date is JSON'ified to wraps itself inside of an extra
|
||||
// set of double quotes. This makes the date parsing code unable
|
||||
// to match the date string and parse it as a date.
|
||||
if (iso.charAt(0) == '"' && iso.charAt(iso.length-1) == '"') {
|
||||
iso = iso.substring(1, iso.length-1);
|
||||
if (iso.charAt(0) == '"' && iso.charAt(iso.length - 1) == '"') {
|
||||
iso = iso.substring(1, iso.length - 1);
|
||||
}
|
||||
if (ISO_DATE_REGEXP.test(iso)) {
|
||||
return new Date(iso);
|
||||
@@ -1125,10 +1149,10 @@ function createDateInputType(type, regexp, parseDate, format) {
|
||||
});
|
||||
|
||||
ctrl.$formatters.push(function(value) {
|
||||
if (!ctrl.$isEmpty(value)) {
|
||||
if (!isDate(value)) {
|
||||
throw $ngModelMinErr('datefmt', 'Expected `{0}` to be a date', value);
|
||||
}
|
||||
if (value && !isDate(value)) {
|
||||
throw $ngModelMinErr('datefmt', 'Expected `{0}` to be a date', value);
|
||||
}
|
||||
if (isValidDate(value)) {
|
||||
previousDate = value;
|
||||
if (previousDate && timezone === 'UTC') {
|
||||
var timezoneOffset = 60000 * previousDate.getTimezoneOffset();
|
||||
@@ -1137,14 +1161,14 @@ function createDateInputType(type, regexp, parseDate, format) {
|
||||
return $filter('date')(value, format, timezone);
|
||||
} else {
|
||||
previousDate = null;
|
||||
return '';
|
||||
}
|
||||
return '';
|
||||
});
|
||||
|
||||
if (isDefined(attr.min) || attr.ngMin) {
|
||||
var minVal;
|
||||
ctrl.$validators.min = function(value) {
|
||||
return ctrl.$isEmpty(value) || isUndefined(minVal) || parseDate(value) >= minVal;
|
||||
return !isValidDate(value) || isUndefined(minVal) || parseDate(value) >= minVal;
|
||||
};
|
||||
attr.$observe('min', function(val) {
|
||||
minVal = parseObservedDateValue(val);
|
||||
@@ -1155,18 +1179,18 @@ function createDateInputType(type, regexp, parseDate, format) {
|
||||
if (isDefined(attr.max) || attr.ngMax) {
|
||||
var maxVal;
|
||||
ctrl.$validators.max = function(value) {
|
||||
return ctrl.$isEmpty(value) || isUndefined(maxVal) || parseDate(value) <= maxVal;
|
||||
return !isValidDate(value) || isUndefined(maxVal) || parseDate(value) <= maxVal;
|
||||
};
|
||||
attr.$observe('max', function(val) {
|
||||
maxVal = parseObservedDateValue(val);
|
||||
ctrl.$validate();
|
||||
});
|
||||
}
|
||||
// Override the standard $isEmpty to detect invalid dates as well
|
||||
ctrl.$isEmpty = function(value) {
|
||||
|
||||
function isValidDate(value) {
|
||||
// Invalid Date: getTime() returns NaN
|
||||
return !value || (value.getTime && value.getTime() !== value.getTime());
|
||||
};
|
||||
return value && !(value.getTime && value.getTime() !== value.getTime());
|
||||
}
|
||||
|
||||
function parseObservedDateValue(val) {
|
||||
return isDefined(val) ? (isDate(val) ? val : parseDate(val)) : undefined;
|
||||
@@ -1250,7 +1274,8 @@ function urlInputType(scope, element, attr, ctrl, $sniffer, $browser) {
|
||||
stringBasedInputType(ctrl);
|
||||
|
||||
ctrl.$$parserName = 'url';
|
||||
ctrl.$validators.url = function(value) {
|
||||
ctrl.$validators.url = function(modelValue, viewValue) {
|
||||
var value = modelValue || viewValue;
|
||||
return ctrl.$isEmpty(value) || URL_REGEXP.test(value);
|
||||
};
|
||||
}
|
||||
@@ -1262,7 +1287,8 @@ function emailInputType(scope, element, attr, ctrl, $sniffer, $browser) {
|
||||
stringBasedInputType(ctrl);
|
||||
|
||||
ctrl.$$parserName = 'email';
|
||||
ctrl.$validators.email = function(value) {
|
||||
ctrl.$validators.email = function(modelValue, viewValue) {
|
||||
var value = modelValue || viewValue;
|
||||
return ctrl.$isEmpty(value) || EMAIL_REGEXP.test(value);
|
||||
};
|
||||
}
|
||||
@@ -1316,9 +1342,11 @@ function checkboxInputType(scope, element, attr, ctrl, $sniffer, $browser, $filt
|
||||
element[0].checked = ctrl.$viewValue;
|
||||
};
|
||||
|
||||
// Override the standard `$isEmpty` because an empty checkbox is never equal to the trueValue
|
||||
// Override the standard `$isEmpty` because the $viewValue of an empty checkbox is always set to `false`
|
||||
// This is because of the parser below, which compares the `$modelValue` with `trueValue` to convert
|
||||
// it to a boolean.
|
||||
ctrl.$isEmpty = function(value) {
|
||||
return value !== trueValue;
|
||||
return value === false;
|
||||
};
|
||||
|
||||
ctrl.$formatters.push(function(value) {
|
||||
@@ -1350,7 +1378,8 @@ function checkboxInputType(scope, element, attr, ctrl, $sniffer, $browser, $filt
|
||||
* @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
|
||||
* minlength.
|
||||
* @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
|
||||
* maxlength.
|
||||
* maxlength. Setting the attribute to a negative or non-numeric value, allows view values of any
|
||||
* length.
|
||||
* @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
|
||||
* RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
|
||||
* patterns defined as scope expressions.
|
||||
@@ -1382,7 +1411,8 @@ function checkboxInputType(scope, element, attr, ctrl, $sniffer, $browser, $filt
|
||||
* @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
|
||||
* minlength.
|
||||
* @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
|
||||
* maxlength.
|
||||
* maxlength. Setting the attribute to a negative or non-numeric value, allows view values of any
|
||||
* length.
|
||||
* @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
|
||||
* RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
|
||||
* patterns defined as scope expressions.
|
||||
@@ -1511,12 +1541,17 @@ var VALID_CLASS = 'ng-valid',
|
||||
* @property {string} $viewValue Actual string value in the view.
|
||||
* @property {*} $modelValue The value in the model that the control is bound to.
|
||||
* @property {Array.<Function>} $parsers Array of functions to execute, as a pipeline, whenever
|
||||
the control reads value from the DOM. The functions are called in array order, each passing the value
|
||||
through to the next. The last return value is forwarded to the $validators collection.
|
||||
Used to sanitize / convert the value.
|
||||
Returning undefined from a parser means a parse error occurred. No $validators will
|
||||
run and the 'ngModel' will not be updated until the parse error is resolved. The parse error is stored
|
||||
in 'ngModel.$error.parse'.
|
||||
the control reads value from the DOM. The functions are called in array order, each passing
|
||||
its return value through to the next. The last return value is forwarded to the
|
||||
{@link ngModel.NgModelController#$validators `$validators`} collection.
|
||||
|
||||
Parsers are used to sanitize / convert the {@link ngModel.NgModelController#$viewValue
|
||||
`$viewValue`}.
|
||||
|
||||
Returning `undefined` from a parser means a parse error occurred. In that case,
|
||||
no {@link ngModel.NgModelController#$validators `$validators`} will run and the `ngModel`
|
||||
will be set to `undefined` unless {@link ngModelOptions `ngModelOptions.allowInvalid`}
|
||||
is set to `true`. The parse error is stored in `ngModel.$error.parse`.
|
||||
|
||||
*
|
||||
* @property {Array.<Function>} $formatters Array of functions to execute, as a pipeline, whenever
|
||||
@@ -1593,13 +1628,18 @@ var VALID_CLASS = 'ng-valid',
|
||||
*
|
||||
* @description
|
||||
*
|
||||
* `NgModelController` provides API for the `ng-model` directive. The controller contains
|
||||
* services for data-binding, validation, CSS updates, and value formatting and parsing. It
|
||||
* purposefully does not contain any logic which deals with DOM rendering or listening to
|
||||
* DOM events. Such DOM related logic should be provided by other directives which make use of
|
||||
* `NgModelController` for data-binding.
|
||||
* `NgModelController` provides API for the {@link ngModel `ngModel`} directive.
|
||||
* The controller contains services for data-binding, validation, CSS updates, and value formatting
|
||||
* and parsing. It purposefully does not contain any logic which deals with DOM rendering or
|
||||
* listening to DOM events.
|
||||
* Such DOM related logic should be provided by other directives which make use of
|
||||
* `NgModelController` for data-binding to control elements.
|
||||
* Angular provides this DOM logic for most {@link input `input`} elements.
|
||||
* At the end of this page you can find a {@link ngModel.NgModelController#custom-control-example
|
||||
* custom control example} that uses `ngModelController` to bind to `contenteditable` elements.
|
||||
*
|
||||
* ## Custom Control Example
|
||||
* @example
|
||||
* ### Custom Control Example
|
||||
* This example shows how to use `NgModelController` with a custom control to achieve
|
||||
* data-binding. Notice how different directives (`contenteditable`, `ng-model`, and `required`)
|
||||
* collaborate together to achieve the desired result.
|
||||
@@ -1641,7 +1681,7 @@ var VALID_CLASS = 'ng-valid',
|
||||
|
||||
// Listen for change events to enable binding
|
||||
element.on('blur keyup change', function() {
|
||||
scope.$apply(read);
|
||||
scope.$evalAsync(read);
|
||||
});
|
||||
read(); // initialize
|
||||
|
||||
@@ -1696,6 +1736,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
|
||||
function($scope, $exceptionHandler, $attr, $element, $parse, $animate, $timeout, $rootScope, $q, $interpolate) {
|
||||
this.$viewValue = Number.NaN;
|
||||
this.$modelValue = Number.NaN;
|
||||
this.$$rawModelValue = undefined; // stores the parsed modelValue / model set from scope regardless of validity.
|
||||
this.$validators = {};
|
||||
this.$asyncValidators = {};
|
||||
this.$parsers = [];
|
||||
@@ -1714,32 +1755,33 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
|
||||
|
||||
|
||||
var parsedNgModel = $parse($attr.ngModel),
|
||||
parsedNgModelAssign = parsedNgModel.assign,
|
||||
ngModelGet = parsedNgModel,
|
||||
ngModelSet = parsedNgModelAssign,
|
||||
pendingDebounce = null,
|
||||
ctrl = this;
|
||||
|
||||
var ngModelGet = function ngModelGet() {
|
||||
var modelValue = parsedNgModel($scope);
|
||||
if (ctrl.$options && ctrl.$options.getterSetter && isFunction(modelValue)) {
|
||||
modelValue = modelValue();
|
||||
}
|
||||
return modelValue;
|
||||
};
|
||||
|
||||
var ngModelSet = function ngModelSet(newValue) {
|
||||
var getterSetter;
|
||||
if (ctrl.$options && ctrl.$options.getterSetter &&
|
||||
isFunction(getterSetter = parsedNgModel($scope))) {
|
||||
|
||||
getterSetter(ctrl.$modelValue);
|
||||
} else {
|
||||
parsedNgModel.assign($scope, ctrl.$modelValue);
|
||||
}
|
||||
};
|
||||
|
||||
this.$$setOptions = function(options) {
|
||||
ctrl.$options = options;
|
||||
if (options && options.getterSetter) {
|
||||
var invokeModelGetter = $parse($attr.ngModel + '()'),
|
||||
invokeModelSetter = $parse($attr.ngModel + '($$$p)');
|
||||
|
||||
if (!parsedNgModel.assign && (!options || !options.getterSetter)) {
|
||||
ngModelGet = function($scope) {
|
||||
var modelValue = parsedNgModel($scope);
|
||||
if (isFunction(modelValue)) {
|
||||
modelValue = invokeModelGetter($scope);
|
||||
}
|
||||
return modelValue;
|
||||
};
|
||||
ngModelSet = function($scope, newValue) {
|
||||
if (isFunction(parsedNgModel($scope))) {
|
||||
invokeModelSetter($scope, {$$$p: ctrl.$modelValue});
|
||||
} else {
|
||||
parsedNgModelAssign($scope, ctrl.$modelValue);
|
||||
}
|
||||
};
|
||||
} else if (!parsedNgModel.assign) {
|
||||
throw $ngModelMinErr('nonassign', "Expression '{0}' is non-assignable. Element: {1}",
|
||||
$attr.ngModel, startingTag($element));
|
||||
}
|
||||
@@ -1772,17 +1814,18 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
|
||||
* @name ngModel.NgModelController#$isEmpty
|
||||
*
|
||||
* @description
|
||||
* This is called when we need to determine if the value of the input is empty.
|
||||
* This is called when we need to determine if the value of an input is empty.
|
||||
*
|
||||
* For instance, the required directive does this to work out if the input has data or not.
|
||||
*
|
||||
* The default `$isEmpty` function checks whether the value is `undefined`, `''`, `null` or `NaN`.
|
||||
*
|
||||
* You can override this for input directives whose concept of being empty is different to the
|
||||
* default. The `checkboxInputType` directive does this because in its case a value of `false`
|
||||
* implies empty.
|
||||
*
|
||||
* @param {*} value Model value to check.
|
||||
* @returns {boolean} True if `value` is empty.
|
||||
* @param {*} value The value of the input to check for emptiness.
|
||||
* @returns {boolean} True if `value` is "empty".
|
||||
*/
|
||||
this.$isEmpty = function(value) {
|
||||
return isUndefined(value) || value === '' || value === null || value !== value;
|
||||
@@ -1833,9 +1876,9 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
|
||||
* @description
|
||||
* Sets the control to its pristine state.
|
||||
*
|
||||
* This method can be called to remove the 'ng-dirty' class and set the control to its pristine
|
||||
* state (ng-pristine class). A model is considered to be pristine when the model has not been changed
|
||||
* from when first compiled within then form.
|
||||
* This method can be called to remove the `ng-dirty` class and set the control to its pristine
|
||||
* state (`ng-pristine` class). A model is considered to be pristine when the control
|
||||
* has not been changed from when first compiled.
|
||||
*/
|
||||
this.$setPristine = function() {
|
||||
ctrl.$dirty = false;
|
||||
@@ -1844,6 +1887,25 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
|
||||
$animate.addClass($element, PRISTINE_CLASS);
|
||||
};
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name ngModel.NgModelController#$setDirty
|
||||
*
|
||||
* @description
|
||||
* Sets the control to its dirty state.
|
||||
*
|
||||
* This method can be called to remove the `ng-pristine` class and set the control to its dirty
|
||||
* state (`ng-dirty` class). A model is considered to be dirty when the control has been changed
|
||||
* from when first compiled.
|
||||
*/
|
||||
this.$setDirty = function() {
|
||||
ctrl.$dirty = true;
|
||||
ctrl.$pristine = false;
|
||||
$animate.removeClass($element, PRISTINE_CLASS);
|
||||
$animate.addClass($element, DIRTY_CLASS);
|
||||
parentForm.$setDirty();
|
||||
};
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name ngModel.NgModelController#$setUntouched
|
||||
@@ -1851,8 +1913,8 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
|
||||
* @description
|
||||
* Sets the control to its untouched state.
|
||||
*
|
||||
* This method can be called to remove the 'ng-touched' class and set the control to its
|
||||
* untouched state (ng-untouched class). Upon compilation, a model is set as untouched
|
||||
* This method can be called to remove the `ng-touched` class and set the control to its
|
||||
* untouched state (`ng-untouched` class). Upon compilation, a model is set as untouched
|
||||
* by default, however this function can be used to restore that state if the model has
|
||||
* already been touched by the user.
|
||||
*/
|
||||
@@ -1869,10 +1931,9 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
|
||||
* @description
|
||||
* Sets the control to its touched state.
|
||||
*
|
||||
* This method can be called to remove the 'ng-untouched' class and set the control to its
|
||||
* touched state (ng-touched class). A model is considered to be touched when the user has
|
||||
* first interacted (focussed) on the model input element and then shifted focus away (blurred)
|
||||
* from the input element.
|
||||
* This method can be called to remove the `ng-untouched` class and set the control to its
|
||||
* touched state (`ng-touched` class). A model is considered to be touched when the user has
|
||||
* first focused the control element and then shifted focus away from the control (blur event).
|
||||
*/
|
||||
this.$setTouched = function() {
|
||||
ctrl.$touched = true;
|
||||
@@ -1950,14 +2011,51 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
|
||||
* @name ngModel.NgModelController#$validate
|
||||
*
|
||||
* @description
|
||||
* Runs each of the registered validators (first synchronous validators and then asynchronous validators).
|
||||
* Runs each of the registered validators (first synchronous validators and then
|
||||
* asynchronous validators).
|
||||
* If the validity changes to invalid, the model will be set to `undefined`,
|
||||
* unless {@link ngModelOptions `ngModelOptions.allowInvalid`} is `true`.
|
||||
* If the validity changes to valid, it will set the model to the last available valid
|
||||
* modelValue, i.e. either the last parsed value or the last value set from the scope.
|
||||
*/
|
||||
this.$validate = function() {
|
||||
// ignore $validate before model is initialized
|
||||
if (isNumber(ctrl.$modelValue) && isNaN(ctrl.$modelValue)) {
|
||||
return;
|
||||
}
|
||||
this.$$parseAndValidate();
|
||||
|
||||
var viewValue = ctrl.$$lastCommittedViewValue;
|
||||
// Note: we use the $$rawModelValue as $modelValue might have been
|
||||
// set to undefined during a view -> model update that found validation
|
||||
// errors. We can't parse the view here, since that could change
|
||||
// the model although neither viewValue nor the model on the scope changed
|
||||
var modelValue = ctrl.$$rawModelValue;
|
||||
|
||||
// Check if the there's a parse error, so we don't unset it accidentially
|
||||
var parserName = ctrl.$$parserName || 'parse';
|
||||
var parserValid = ctrl.$error[parserName] ? false : undefined;
|
||||
|
||||
var prevValid = ctrl.$valid;
|
||||
var prevModelValue = ctrl.$modelValue;
|
||||
|
||||
var allowInvalid = ctrl.$options && ctrl.$options.allowInvalid;
|
||||
|
||||
ctrl.$$runValidators(parserValid, modelValue, viewValue, function(allValid) {
|
||||
// If there was no change in validity, don't update the model
|
||||
// This prevents changing an invalid modelValue to undefined
|
||||
if (!allowInvalid && prevValid !== allValid) {
|
||||
// Note: Don't check ctrl.$valid here, as we could have
|
||||
// external validators (e.g. calculated on the server),
|
||||
// that just call $setValidity and need the model value
|
||||
// to calculate their validity.
|
||||
ctrl.$modelValue = allValid ? modelValue : undefined;
|
||||
|
||||
if (ctrl.$modelValue !== prevModelValue) {
|
||||
ctrl.$$writeModelToScope();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
this.$$runValidators = function(parseValid, modelValue, viewValue, doneCallback) {
|
||||
@@ -2076,11 +2174,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
|
||||
|
||||
// change to dirty
|
||||
if (ctrl.$pristine) {
|
||||
ctrl.$dirty = true;
|
||||
ctrl.$pristine = false;
|
||||
$animate.removeClass($element, PRISTINE_CLASS);
|
||||
$animate.addClass($element, DIRTY_CLASS);
|
||||
parentForm.$setDirty();
|
||||
this.$setDirty();
|
||||
}
|
||||
this.$$parseAndValidate();
|
||||
};
|
||||
@@ -2101,10 +2195,11 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
|
||||
}
|
||||
if (isNumber(ctrl.$modelValue) && isNaN(ctrl.$modelValue)) {
|
||||
// ctrl.$modelValue has not been touched yet...
|
||||
ctrl.$modelValue = ngModelGet();
|
||||
ctrl.$modelValue = ngModelGet($scope);
|
||||
}
|
||||
var prevModelValue = ctrl.$modelValue;
|
||||
var allowInvalid = ctrl.$options && ctrl.$options.allowInvalid;
|
||||
ctrl.$$rawModelValue = modelValue;
|
||||
if (allowInvalid) {
|
||||
ctrl.$modelValue = modelValue;
|
||||
writeToModelIfNeeded();
|
||||
@@ -2128,7 +2223,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
|
||||
};
|
||||
|
||||
this.$$writeModelToScope = function() {
|
||||
ngModelSet(ctrl.$modelValue);
|
||||
ngModelSet($scope, ctrl.$modelValue);
|
||||
forEach(ctrl.$viewChangeListeners, function(listener) {
|
||||
try {
|
||||
listener();
|
||||
@@ -2224,12 +2319,12 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
|
||||
// ng-change executes in apply phase
|
||||
// 4. view should be changed back to 'a'
|
||||
$scope.$watch(function ngModelWatch() {
|
||||
var modelValue = ngModelGet();
|
||||
var modelValue = ngModelGet($scope);
|
||||
|
||||
// if scope model value and ngModel value are out of sync
|
||||
// TODO(perf): why not move this to the action fn?
|
||||
if (modelValue !== ctrl.$modelValue) {
|
||||
ctrl.$modelValue = modelValue;
|
||||
ctrl.$modelValue = ctrl.$$rawModelValue = modelValue;
|
||||
|
||||
var formatters = ctrl.$formatters,
|
||||
idx = formatters.length;
|
||||
@@ -2414,7 +2509,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
|
||||
</file>
|
||||
* </example>
|
||||
*/
|
||||
var ngModelDirective = function() {
|
||||
var ngModelDirective = ['$rootScope', function($rootScope) {
|
||||
return {
|
||||
restrict: 'A',
|
||||
require: ['ngModel', '^?form', '^?ngModelOptions'],
|
||||
@@ -2458,15 +2553,17 @@ var ngModelDirective = function() {
|
||||
element.on('blur', function(ev) {
|
||||
if (modelCtrl.$touched) return;
|
||||
|
||||
scope.$apply(function() {
|
||||
modelCtrl.$setTouched();
|
||||
});
|
||||
if ($rootScope.$$phase) {
|
||||
scope.$evalAsync(modelCtrl.$setTouched);
|
||||
} else {
|
||||
scope.$apply(modelCtrl.$setTouched);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
};
|
||||
}];
|
||||
|
||||
|
||||
/**
|
||||
@@ -2555,8 +2652,8 @@ var requiredDirective = function() {
|
||||
if (!ctrl) return;
|
||||
attr.required = true; // force truthy in case we are on non input element
|
||||
|
||||
ctrl.$validators.required = function(value) {
|
||||
return !attr.required || !ctrl.$isEmpty(value);
|
||||
ctrl.$validators.required = function(modelValue, viewValue) {
|
||||
return !attr.required || !ctrl.$isEmpty(viewValue);
|
||||
};
|
||||
|
||||
attr.$observe('required', function() {
|
||||
@@ -2577,7 +2674,7 @@ var patternDirective = function() {
|
||||
var regexp, patternExp = attr.ngPattern || attr.pattern;
|
||||
attr.$observe('pattern', function(regex) {
|
||||
if (isString(regex) && regex.length > 0) {
|
||||
regex = new RegExp(regex);
|
||||
regex = new RegExp('^' + regex + '$');
|
||||
}
|
||||
|
||||
if (regex && !regex.test) {
|
||||
@@ -2605,13 +2702,14 @@ var maxlengthDirective = function() {
|
||||
link: function(scope, elm, attr, ctrl) {
|
||||
if (!ctrl) return;
|
||||
|
||||
var maxlength = 0;
|
||||
var maxlength = -1;
|
||||
attr.$observe('maxlength', function(value) {
|
||||
maxlength = int(value) || 0;
|
||||
var intVal = int(value);
|
||||
maxlength = isNaN(intVal) ? -1 : intVal;
|
||||
ctrl.$validate();
|
||||
});
|
||||
ctrl.$validators.maxlength = function(modelValue, viewValue) {
|
||||
return ctrl.$isEmpty(modelValue) || viewValue.length <= maxlength;
|
||||
return (maxlength < 0) || ctrl.$isEmpty(modelValue) || (viewValue.length <= maxlength);
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -2630,7 +2728,7 @@ var minlengthDirective = function() {
|
||||
ctrl.$validate();
|
||||
});
|
||||
ctrl.$validators.minlength = function(modelValue, viewValue) {
|
||||
return ctrl.$isEmpty(modelValue) || viewValue.length >= minlength;
|
||||
return ctrl.$isEmpty(viewValue) || viewValue.length >= minlength;
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -2868,7 +2966,7 @@ var ngValueDirective = function() {
|
||||
* `ngModelOptions` has an effect on the element it's declared on and its descendants.
|
||||
*
|
||||
* @param {Object} ngModelOptions options to apply to the current model. Valid keys are:
|
||||
* - `updateOn`: string specifying which event should be the input bound to. You can set several
|
||||
* - `updateOn`: string specifying which event should the input be bound to. You can set several
|
||||
* events using an space delimited list. There is a special event called `default` that
|
||||
* matches the default events belonging of the control.
|
||||
* - `debounce`: integer value which contains the debounce model update value in milliseconds. A
|
||||
|
||||
@@ -141,12 +141,11 @@ var ngBindTemplateDirective = ['$interpolate', '$compile', function($interpolate
|
||||
* @name ngBindHtml
|
||||
*
|
||||
* @description
|
||||
* Creates a binding that will innerHTML the result of evaluating the `expression` into the current
|
||||
* element in a secure way. By default, the innerHTML-ed content will be sanitized using the {@link
|
||||
* ngSanitize.$sanitize $sanitize} service. To utilize this functionality, ensure that `$sanitize`
|
||||
* is available, for example, by including {@link ngSanitize} in your module's dependencies (not in
|
||||
* core Angular). In order to use {@link ngSanitize} in your module's dependencies, you need to
|
||||
* include "angular-sanitize.js" in your application.
|
||||
* Evaluates the expression and inserts the resulting HTML into the element in a secure way. By default,
|
||||
* the resulting HTML content will be sanitized using the {@link ngSanitize.$sanitize $sanitize} service.
|
||||
* To utilize this functionality, ensure that `$sanitize` is available, for example, by including {@link
|
||||
* ngSanitize} in your module's dependencies (not in core Angular). In order to use {@link ngSanitize}
|
||||
* in your module's dependencies, you need to include "angular-sanitize.js" in your application.
|
||||
*
|
||||
* You may also bypass sanitization for values you know are safe. To do so, bind to
|
||||
* an explicitly trusted value via {@link ng.$sce#trustAsHtml $sce.trustAsHtml}. See the example
|
||||
|
||||
@@ -173,7 +173,9 @@
|
||||
</example>
|
||||
*/
|
||||
var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interpolate) {
|
||||
var BRACE = /{}/g;
|
||||
var BRACE = /{}/g,
|
||||
IS_WHEN = /^when(Minus)?(.+)$/;
|
||||
|
||||
return {
|
||||
restrict: 'EA',
|
||||
link: function(scope, element, attr) {
|
||||
@@ -184,34 +186,44 @@ var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interp
|
||||
whensExpFns = {},
|
||||
startSymbol = $interpolate.startSymbol(),
|
||||
endSymbol = $interpolate.endSymbol(),
|
||||
isWhen = /^when(Minus)?(.+)$/;
|
||||
braceReplacement = startSymbol + numberExp + '-' + offset + endSymbol,
|
||||
watchRemover = angular.noop,
|
||||
lastCount;
|
||||
|
||||
forEach(attr, function(expression, attributeName) {
|
||||
if (isWhen.test(attributeName)) {
|
||||
whens[lowercase(attributeName.replace('when', '').replace('Minus', '-'))] =
|
||||
element.attr(attr.$attr[attributeName]);
|
||||
var tmpMatch = IS_WHEN.exec(attributeName);
|
||||
if (tmpMatch) {
|
||||
var whenKey = (tmpMatch[1] ? '-' : '') + lowercase(tmpMatch[2]);
|
||||
whens[whenKey] = element.attr(attr.$attr[attributeName]);
|
||||
}
|
||||
});
|
||||
forEach(whens, function(expression, key) {
|
||||
whensExpFns[key] =
|
||||
$interpolate(expression.replace(BRACE, startSymbol + numberExp + '-' +
|
||||
offset + endSymbol));
|
||||
whensExpFns[key] = $interpolate(expression.replace(BRACE, braceReplacement));
|
||||
|
||||
});
|
||||
|
||||
scope.$watch(function ngPluralizeWatch() {
|
||||
var value = parseFloat(scope.$eval(numberExp));
|
||||
scope.$watch(numberExp, function ngPluralizeWatchAction(newVal) {
|
||||
var count = parseFloat(newVal);
|
||||
var countIsNaN = isNaN(count);
|
||||
|
||||
if (!isNaN(value)) {
|
||||
//if explicit number rule such as 1, 2, 3... is defined, just use it. Otherwise,
|
||||
//check it against pluralization rules in $locale service
|
||||
if (!(value in whens)) value = $locale.pluralCat(value - offset);
|
||||
return whensExpFns[value](scope);
|
||||
} else {
|
||||
return '';
|
||||
if (!countIsNaN && !(count in whens)) {
|
||||
// If an explicit number rule such as 1, 2, 3... is defined, just use it.
|
||||
// Otherwise, check it against pluralization rules in $locale service.
|
||||
count = $locale.pluralCat(count - offset);
|
||||
}
|
||||
|
||||
// If both `count` and `lastCount` are NaN, we don't need to re-register a watch.
|
||||
// In JS `NaN !== NaN`, so we have to exlicitly check.
|
||||
if ((count !== lastCount) && !(countIsNaN && isNaN(lastCount))) {
|
||||
watchRemover();
|
||||
watchRemover = scope.$watch(whensExpFns[count], updateElementText);
|
||||
lastCount = count;
|
||||
}
|
||||
}, function ngPluralizeWatchAction(newVal) {
|
||||
element.text(newVal);
|
||||
});
|
||||
|
||||
function updateElementText(newText) {
|
||||
element.text(newText || '');
|
||||
}
|
||||
}
|
||||
};
|
||||
}];
|
||||
|
||||
@@ -366,7 +366,7 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
|
||||
});
|
||||
throw ngRepeatMinErr('dupes',
|
||||
"Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: {0}, Duplicate key: {1}, Duplicate value: {2}",
|
||||
expression, trackById, toJson(value));
|
||||
expression, trackById, value);
|
||||
} else {
|
||||
// new never before seen block
|
||||
nextBlockOrder[index] = {id: trackById, scope: undefined, clone: undefined};
|
||||
|
||||
@@ -38,17 +38,17 @@ var NG_HIDE_IN_PROGRESS_CLASS = 'ng-hide-animate';
|
||||
*
|
||||
* ### Overriding `.ng-hide`
|
||||
*
|
||||
* By default, the `.ng-hide` class will style the element with `display:none!important`. If you wish to change
|
||||
* By default, the `.ng-hide` class will style the element with `display: none!important`. If you wish to change
|
||||
* the hide behavior with ngShow/ngHide then this can be achieved by restating the styles for the `.ng-hide`
|
||||
* class in CSS:
|
||||
*
|
||||
* ```css
|
||||
* .ng-hide {
|
||||
* /* this is just another form of hiding an element */
|
||||
* display:block!important;
|
||||
* position:absolute;
|
||||
* top:-9999px;
|
||||
* left:-9999px;
|
||||
* display: block!important;
|
||||
* position: absolute;
|
||||
* top: -9999px;
|
||||
* left: -9999px;
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
@@ -68,13 +68,13 @@ var NG_HIDE_IN_PROGRESS_CLASS = 'ng-hide-animate';
|
||||
* .my-element.ng-hide-add, .my-element.ng-hide-remove {
|
||||
* /* this is required as of 1.3x to properly
|
||||
* apply all styling in a show/hide animation */
|
||||
* transition:0s linear all;
|
||||
* transition: 0s linear all;
|
||||
* }
|
||||
*
|
||||
* .my-element.ng-hide-add-active,
|
||||
* .my-element.ng-hide-remove-active {
|
||||
* /* the transition is defined in the active class */
|
||||
* transition:1s linear all;
|
||||
* transition: 1s linear all;
|
||||
* }
|
||||
*
|
||||
* .my-element.ng-hide-add { ... }
|
||||
@@ -116,29 +116,29 @@ var NG_HIDE_IN_PROGRESS_CLASS = 'ng-hide-animate';
|
||||
</file>
|
||||
<file name="animations.css">
|
||||
.animate-show {
|
||||
line-height:20px;
|
||||
opacity:1;
|
||||
padding:10px;
|
||||
border:1px solid black;
|
||||
background:white;
|
||||
line-height: 20px;
|
||||
opacity: 1;
|
||||
padding: 10px;
|
||||
border: 1px solid black;
|
||||
background: white;
|
||||
}
|
||||
|
||||
.animate-show.ng-hide-add.ng-hide-add-active,
|
||||
.animate-show.ng-hide-remove.ng-hide-remove-active {
|
||||
-webkit-transition:all linear 0.5s;
|
||||
transition:all linear 0.5s;
|
||||
-webkit-transition: all linear 0.5s;
|
||||
transition: all linear 0.5s;
|
||||
}
|
||||
|
||||
.animate-show.ng-hide {
|
||||
line-height:0;
|
||||
opacity:0;
|
||||
padding:0 10px;
|
||||
line-height: 0;
|
||||
opacity: 0;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
.check-element {
|
||||
padding:10px;
|
||||
border:1px solid black;
|
||||
background:white;
|
||||
padding: 10px;
|
||||
border: 1px solid black;
|
||||
background: white;
|
||||
}
|
||||
</file>
|
||||
<file name="protractor.js" type="protractor">
|
||||
@@ -212,17 +212,17 @@ var ngShowDirective = ['$animate', function($animate) {
|
||||
*
|
||||
* ### Overriding `.ng-hide`
|
||||
*
|
||||
* By default, the `.ng-hide` class will style the element with `display:none!important`. If you wish to change
|
||||
* By default, the `.ng-hide` class will style the element with `display: none!important`. If you wish to change
|
||||
* the hide behavior with ngShow/ngHide then this can be achieved by restating the styles for the `.ng-hide`
|
||||
* class in CSS:
|
||||
*
|
||||
* ```css
|
||||
* .ng-hide {
|
||||
* /* this is just another form of hiding an element */
|
||||
* display:block!important;
|
||||
* position:absolute;
|
||||
* top:-9999px;
|
||||
* left:-9999px;
|
||||
* display: block!important;
|
||||
* position: absolute;
|
||||
* top: -9999px;
|
||||
* left: -9999px;
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
@@ -239,7 +239,7 @@ var ngShowDirective = ['$animate', function($animate) {
|
||||
* //a working example can be found at the bottom of this page
|
||||
* //
|
||||
* .my-element.ng-hide-add, .my-element.ng-hide-remove {
|
||||
* transition:0.5s linear all;
|
||||
* transition: 0.5s linear all;
|
||||
* }
|
||||
*
|
||||
* .my-element.ng-hide-add { ... }
|
||||
@@ -281,25 +281,25 @@ var ngShowDirective = ['$animate', function($animate) {
|
||||
</file>
|
||||
<file name="animations.css">
|
||||
.animate-hide {
|
||||
-webkit-transition:all linear 0.5s;
|
||||
transition:all linear 0.5s;
|
||||
line-height:20px;
|
||||
opacity:1;
|
||||
padding:10px;
|
||||
border:1px solid black;
|
||||
background:white;
|
||||
-webkit-transition: all linear 0.5s;
|
||||
transition: all linear 0.5s;
|
||||
line-height: 20px;
|
||||
opacity: 1;
|
||||
padding: 10px;
|
||||
border: 1px solid black;
|
||||
background: white;
|
||||
}
|
||||
|
||||
.animate-hide.ng-hide {
|
||||
line-height:0;
|
||||
opacity:0;
|
||||
padding:0 10px;
|
||||
line-height: 0;
|
||||
opacity: 0;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
.check-element {
|
||||
padding:10px;
|
||||
border:1px solid black;
|
||||
background:white;
|
||||
padding: 10px;
|
||||
border: 1px solid black;
|
||||
background: white;
|
||||
}
|
||||
</file>
|
||||
<file name="protractor.js" type="protractor">
|
||||
|
||||
@@ -18,7 +18,7 @@ var ngOptionsMinErr = minErr('ngOptions');
|
||||
* In many cases, `ngRepeat` can be used on `<option>` elements instead of `ngOptions` to achieve a
|
||||
* similar result. However, the `ngOptions` provides some benefits such as reducing memory and
|
||||
* increasing speed by not creating a new scope for each repeated instance, as well as providing
|
||||
* more flexibility in how the `select`'s model is assigned via `select as`. `ngOptions should be
|
||||
* more flexibility in how the `select`'s model is assigned via `select as`. `ngOptions` should be
|
||||
* used when the `select` model needs to be bound to a non-string value. This is because an option
|
||||
* element can only be bound to string values at present.
|
||||
*
|
||||
@@ -616,13 +616,14 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
|
||||
lastElement = null; // start at the beginning
|
||||
for (index = 0, length = optionGroup.length; index < length; index++) {
|
||||
option = optionGroup[index];
|
||||
if ((existingOption = existingOptions[index+1])) {
|
||||
if ((existingOption = existingOptions[index + 1])) {
|
||||
// reuse elements
|
||||
lastElement = existingOption.element;
|
||||
if (existingOption.label !== option.label) {
|
||||
updateLabelMap(labelMap, existingOption.label, false);
|
||||
updateLabelMap(labelMap, option.label, true);
|
||||
lastElement.text(existingOption.label = option.label);
|
||||
lastElement.prop('label', existingOption.label);
|
||||
}
|
||||
if (existingOption.id !== option.id) {
|
||||
lastElement.val(existingOption.id = option.id);
|
||||
@@ -652,6 +653,7 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
|
||||
.val(option.id)
|
||||
.prop('selected', option.selected)
|
||||
.attr('selected', option.selected)
|
||||
.prop('label', option.label)
|
||||
.text(option.label);
|
||||
}
|
||||
|
||||
|
||||
@@ -147,8 +147,8 @@ function filterFilter() {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
text = (''+text).toLowerCase();
|
||||
return (''+obj).toLowerCase().indexOf(text) > -1;
|
||||
text = ('' + text).toLowerCase();
|
||||
return ('' + obj).toLowerCase().indexOf(text) > -1;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
+11
-12
@@ -11,7 +11,7 @@
|
||||
*
|
||||
* @param {number} amount Input to filter.
|
||||
* @param {string=} symbol Currency symbol or identifier to be displayed.
|
||||
* @param {number=} fractionSize Number of decimal places to round the amount to.
|
||||
* @param {number=} fractionSize Number of decimal places to round the amount to, defaults to default max fraction size for current locale
|
||||
* @returns {string} Formatted number.
|
||||
*
|
||||
*
|
||||
@@ -61,8 +61,7 @@ function currencyFilter($locale) {
|
||||
}
|
||||
|
||||
if (isUndefined(fractionSize)) {
|
||||
// TODO: read the default value from the locale file
|
||||
fractionSize = 2;
|
||||
fractionSize = formats.PATTERNS[1].maxFrac;
|
||||
}
|
||||
|
||||
// if null or undefined pass it through
|
||||
@@ -187,7 +186,7 @@ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
|
||||
if (whole.length >= (lgroup + group)) {
|
||||
pos = whole.length - lgroup;
|
||||
for (i = 0; i < pos; i++) {
|
||||
if ((pos - i)%group === 0 && i !== 0) {
|
||||
if ((pos - i) % group === 0 && i !== 0) {
|
||||
formatedText += groupSep;
|
||||
}
|
||||
formatedText += whole.charAt(i);
|
||||
@@ -195,7 +194,7 @@ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
|
||||
}
|
||||
|
||||
for (i = pos; i < whole.length; i++) {
|
||||
if ((whole.length - i)%lgroup === 0 && i !== 0) {
|
||||
if ((whole.length - i) % lgroup === 0 && i !== 0) {
|
||||
formatedText += groupSep;
|
||||
}
|
||||
formatedText += whole.charAt(i);
|
||||
@@ -214,9 +213,9 @@ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
|
||||
}
|
||||
}
|
||||
|
||||
parts.push(isNegative ? pattern.negPre : pattern.posPre);
|
||||
parts.push(formatedText);
|
||||
parts.push(isNegative ? pattern.negSuf : pattern.posSuf);
|
||||
parts.push(isNegative ? pattern.negPre : pattern.posPre,
|
||||
formatedText,
|
||||
isNegative ? pattern.negSuf : pattern.posSuf);
|
||||
return parts.join('');
|
||||
}
|
||||
|
||||
@@ -435,10 +434,10 @@ function dateFilter($locale) {
|
||||
tzMin = int(match[9] + match[11]);
|
||||
}
|
||||
dateSetter.call(date, int(match[1]), int(match[2]) - 1, int(match[3]));
|
||||
var h = int(match[4]||0) - tzHour;
|
||||
var m = int(match[5]||0) - tzMin;
|
||||
var s = int(match[6]||0);
|
||||
var ms = Math.round(parseFloat('0.' + (match[7]||0)) * 1000);
|
||||
var h = int(match[4] || 0) - tzHour;
|
||||
var m = int(match[5] || 0) - tzMin;
|
||||
var s = int(match[6] || 0);
|
||||
var ms = Math.round(parseFloat('0.' + (match[7] || 0)) * 1000);
|
||||
timeSetter.call(date, h, m, s, ms);
|
||||
return date;
|
||||
}
|
||||
|
||||
@@ -123,7 +123,7 @@ function limitToFilter() {
|
||||
n = input.length;
|
||||
}
|
||||
|
||||
for (; i<n; i++) {
|
||||
for (; i < n; i++) {
|
||||
out.push(input[i]);
|
||||
}
|
||||
|
||||
|
||||
@@ -119,7 +119,7 @@ orderByFilter.$inject = ['$parse'];
|
||||
function orderByFilter($parse) {
|
||||
return function(array, sortPredicate, reverseOrder) {
|
||||
if (!(isArrayLike(array))) return array;
|
||||
sortPredicate = isArray(sortPredicate) ? sortPredicate: [sortPredicate];
|
||||
sortPredicate = isArray(sortPredicate) ? sortPredicate : [sortPredicate];
|
||||
if (sortPredicate.length === 0) { sortPredicate = ['+']; }
|
||||
sortPredicate = sortPredicate.map(function(predicate) {
|
||||
var descending = false, get = predicate || identity;
|
||||
@@ -146,9 +146,7 @@ function orderByFilter($parse) {
|
||||
return compare(get(a),get(b));
|
||||
}, descending);
|
||||
});
|
||||
var arrayCopy = [];
|
||||
for (var i = 0; i < array.length; i++) { arrayCopy.push(array[i]); }
|
||||
return arrayCopy.sort(reverseComparator(comparator, reverseOrder));
|
||||
return slice.call(array).sort(reverseComparator(comparator, reverseOrder));
|
||||
|
||||
function comparator(o1, o2) {
|
||||
for (var i = 0; i < sortPredicate.length; i++) {
|
||||
|
||||
+32
-3
@@ -11,7 +11,7 @@ function defaultHttpResponseTransform(data, headers) {
|
||||
// strip json vulnerability protection prefix
|
||||
data = data.replace(JSON_PROTECTION_PREFIX, '');
|
||||
var contentType = headers('Content-Type');
|
||||
if ((contentType && contentType.indexOf(APPLICATION_JSON) === 0) ||
|
||||
if ((contentType && contentType.indexOf(APPLICATION_JSON) === 0 && data.trim()) ||
|
||||
(JSON_START.test(data) && JSON_END.test(data))) {
|
||||
data = fromJson(data);
|
||||
}
|
||||
@@ -26,7 +26,7 @@ function defaultHttpResponseTransform(data, headers) {
|
||||
* @returns {Object} Parsed headers as key value object
|
||||
*/
|
||||
function parseHeaders(headers) {
|
||||
var parsed = {}, key, val, i;
|
||||
var parsed = createMap(), key, val, i;
|
||||
|
||||
if (!headers) return parsed;
|
||||
|
||||
@@ -63,7 +63,11 @@ function headersGetter(headers) {
|
||||
if (!headersObj) headersObj = parseHeaders(headers);
|
||||
|
||||
if (name) {
|
||||
return headersObj[lowercase(name)] || null;
|
||||
var value = headersObj[lowercase(name)];
|
||||
if (value === void 0) {
|
||||
value = null;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
return headersObj;
|
||||
@@ -112,6 +116,11 @@ function $HttpProvider() {
|
||||
*
|
||||
* Object containing default values for all {@link ng.$http $http} requests.
|
||||
*
|
||||
* - **`defaults.cache`** - {Object} - an object built with {@link ng.$cacheFactory `$cacheFactory`}
|
||||
* that will provide the cache for all requests who set their `cache` property to `true`.
|
||||
* If you set the `default.cache = false` then only requests that specify their own custom
|
||||
* cache object will be cached. See {@link $http#caching $http Caching} for more information.
|
||||
*
|
||||
* - **`defaults.xsrfCookieName`** - {string} - Name of cookie containing the XSRF token.
|
||||
* Defaults value is `'XSRF-TOKEN'`.
|
||||
*
|
||||
@@ -125,6 +134,7 @@ function $HttpProvider() {
|
||||
* - **`defaults.headers.post`**
|
||||
* - **`defaults.headers.put`**
|
||||
* - **`defaults.headers.patch`**
|
||||
*
|
||||
**/
|
||||
var defaults = this.defaults = {
|
||||
// transform incoming response data
|
||||
@@ -339,6 +349,21 @@ function $HttpProvider() {
|
||||
* In addition, you can supply a `headers` property in the config object passed when
|
||||
* calling `$http(config)`, which overrides the defaults without changing them globally.
|
||||
*
|
||||
* To explicitly remove a header automatically added via $httpProvider.defaults.headers on a per request basis,
|
||||
* Use the `headers` property, setting the desired header to `undefined`. For example:
|
||||
*
|
||||
* ```js
|
||||
* var req = {
|
||||
* method: 'POST',
|
||||
* url: 'http://example.com',
|
||||
* headers: {
|
||||
* 'Content-Type': undefined
|
||||
* },
|
||||
* data: { test: 'test' },
|
||||
* }
|
||||
*
|
||||
* $http(req).success(function(){...}).error(function(){...});
|
||||
* ```
|
||||
*
|
||||
* ## Transforming Requests and Responses
|
||||
*
|
||||
@@ -718,6 +743,10 @@ function $HttpProvider() {
|
||||
};
|
||||
var headers = mergeHeaders(requestConfig);
|
||||
|
||||
if (!angular.isObject(requestConfig)) {
|
||||
throw minErr('$http')('badreq', 'Http request configuration must be an object. Received: {0}', requestConfig);
|
||||
}
|
||||
|
||||
extend(config, requestConfig);
|
||||
config.headers = headers;
|
||||
config.method = uppercase(config.method);
|
||||
|
||||
@@ -301,7 +301,8 @@ function $InterpolateProvider() {
|
||||
|
||||
function parseStringifyInterceptor(value) {
|
||||
try {
|
||||
return stringify(getValue(value));
|
||||
value = getValue(value);
|
||||
return allOrNothing && !isDefined(value) ? value : stringify(value);
|
||||
} catch (err) {
|
||||
var newErr = $interpolateMinErr('interr', "Can't interpolate: {0}\n{1}", text,
|
||||
err.toString());
|
||||
|
||||
+80
-17
@@ -22,8 +22,8 @@ function encodePath(path) {
|
||||
return segments.join('/');
|
||||
}
|
||||
|
||||
function parseAbsoluteUrl(absoluteUrl, locationObj, appBase) {
|
||||
var parsedUrl = urlResolve(absoluteUrl, appBase);
|
||||
function parseAbsoluteUrl(absoluteUrl, locationObj) {
|
||||
var parsedUrl = urlResolve(absoluteUrl);
|
||||
|
||||
locationObj.$$protocol = parsedUrl.protocol;
|
||||
locationObj.$$host = parsedUrl.hostname;
|
||||
@@ -31,12 +31,12 @@ function parseAbsoluteUrl(absoluteUrl, locationObj, appBase) {
|
||||
}
|
||||
|
||||
|
||||
function parseAppUrl(relativeUrl, locationObj, appBase) {
|
||||
function parseAppUrl(relativeUrl, locationObj) {
|
||||
var prefixed = (relativeUrl.charAt(0) !== '/');
|
||||
if (prefixed) {
|
||||
relativeUrl = '/' + relativeUrl;
|
||||
}
|
||||
var match = urlResolve(relativeUrl, appBase);
|
||||
var match = urlResolve(relativeUrl);
|
||||
locationObj.$$path = decodeURIComponent(prefixed && match.pathname.charAt(0) === '/' ?
|
||||
match.pathname.substring(1) : match.pathname);
|
||||
locationObj.$$search = parseKeyValue(match.search);
|
||||
@@ -91,7 +91,7 @@ function LocationHtml5Url(appBase, basePrefix) {
|
||||
this.$$html5 = true;
|
||||
basePrefix = basePrefix || '';
|
||||
var appBaseNoFile = stripFile(appBase);
|
||||
parseAbsoluteUrl(appBase, this, appBase);
|
||||
parseAbsoluteUrl(appBase, this);
|
||||
|
||||
|
||||
/**
|
||||
@@ -106,7 +106,7 @@ function LocationHtml5Url(appBase, basePrefix) {
|
||||
appBaseNoFile);
|
||||
}
|
||||
|
||||
parseAppUrl(pathUrl, this, appBase);
|
||||
parseAppUrl(pathUrl, this);
|
||||
|
||||
if (!this.$$path) {
|
||||
this.$$path = '/';
|
||||
@@ -169,7 +169,7 @@ function LocationHtml5Url(appBase, basePrefix) {
|
||||
function LocationHashbangUrl(appBase, hashPrefix) {
|
||||
var appBaseNoFile = stripFile(appBase);
|
||||
|
||||
parseAbsoluteUrl(appBase, this, appBase);
|
||||
parseAbsoluteUrl(appBase, this);
|
||||
|
||||
|
||||
/**
|
||||
@@ -189,7 +189,7 @@ function LocationHashbangUrl(appBase, hashPrefix) {
|
||||
throw $locationMinErr('ihshprfx', 'Invalid url "{0}", missing hash prefix "{1}".', url,
|
||||
hashPrefix);
|
||||
}
|
||||
parseAppUrl(withoutHashUrl, this, appBase);
|
||||
parseAppUrl(withoutHashUrl, this);
|
||||
|
||||
this.$$path = removeWindowsDriveName(this.$$path, withoutHashUrl, appBase);
|
||||
|
||||
@@ -327,6 +327,13 @@ var locationPrototype = {
|
||||
* Return full url representation with all segments encoded according to rules specified in
|
||||
* [RFC 3986](http://www.ietf.org/rfc/rfc3986.txt).
|
||||
*
|
||||
*
|
||||
* ```js
|
||||
* // given url http://example.com/#/some/path?foo=bar&baz=xoxo
|
||||
* var absUrl = $location.absUrl();
|
||||
* // => "http://example.com/#/some/path?foo=bar&baz=xoxo"
|
||||
* ```
|
||||
*
|
||||
* @return {string} full url
|
||||
*/
|
||||
absUrl: locationGetter('$$absUrl'),
|
||||
@@ -342,6 +349,13 @@ var locationPrototype = {
|
||||
*
|
||||
* Change path, search and hash, when called with parameter and return `$location`.
|
||||
*
|
||||
*
|
||||
* ```js
|
||||
* // given url http://example.com/#/some/path?foo=bar&baz=xoxo
|
||||
* var url = $location.url();
|
||||
* // => "/some/path?foo=bar&baz=xoxo"
|
||||
* ```
|
||||
*
|
||||
* @param {string=} url New url without base prefix (e.g. `/path?a=b#hash`)
|
||||
* @return {string} url
|
||||
*/
|
||||
@@ -350,8 +364,8 @@ var locationPrototype = {
|
||||
return this.$$url;
|
||||
|
||||
var match = PATH_MATCH.exec(url);
|
||||
if (match[1]) this.path(decodeURIComponent(match[1]));
|
||||
if (match[2] || match[1]) this.search(match[3] || '');
|
||||
if (match[1] || url === '') this.path(decodeURIComponent(match[1]));
|
||||
if (match[2] || match[1] || url === '') this.search(match[3] || '');
|
||||
this.hash(match[5] || '');
|
||||
|
||||
return this;
|
||||
@@ -366,6 +380,13 @@ var locationPrototype = {
|
||||
*
|
||||
* Return protocol of current url.
|
||||
*
|
||||
*
|
||||
* ```js
|
||||
* // given url http://example.com/#/some/path?foo=bar&baz=xoxo
|
||||
* var protocol = $location.protocol();
|
||||
* // => "http"
|
||||
* ```
|
||||
*
|
||||
* @return {string} protocol of current url
|
||||
*/
|
||||
protocol: locationGetter('$$protocol'),
|
||||
@@ -379,6 +400,13 @@ var locationPrototype = {
|
||||
*
|
||||
* Return host of current url.
|
||||
*
|
||||
*
|
||||
* ```js
|
||||
* // given url http://example.com/#/some/path?foo=bar&baz=xoxo
|
||||
* var host = $location.host();
|
||||
* // => "example.com"
|
||||
* ```
|
||||
*
|
||||
* @return {string} host of current url.
|
||||
*/
|
||||
host: locationGetter('$$host'),
|
||||
@@ -392,6 +420,13 @@ var locationPrototype = {
|
||||
*
|
||||
* Return port of current url.
|
||||
*
|
||||
*
|
||||
* ```js
|
||||
* // given url http://example.com/#/some/path?foo=bar&baz=xoxo
|
||||
* var port = $location.port();
|
||||
* // => 80
|
||||
* ```
|
||||
*
|
||||
* @return {Number} port
|
||||
*/
|
||||
port: locationGetter('$$port'),
|
||||
@@ -410,6 +445,13 @@ var locationPrototype = {
|
||||
* Note: Path should always begin with forward slash (/), this method will add the forward slash
|
||||
* if it is missing.
|
||||
*
|
||||
*
|
||||
* ```js
|
||||
* // given url http://example.com/#/some/path?foo=bar&baz=xoxo
|
||||
* var path = $location.path();
|
||||
* // => "/some/path"
|
||||
* ```
|
||||
*
|
||||
* @param {(string|number)=} path New path
|
||||
* @return {string} path
|
||||
*/
|
||||
@@ -435,10 +477,9 @@ var locationPrototype = {
|
||||
* var searchObject = $location.search();
|
||||
* // => {foo: 'bar', baz: 'xoxo'}
|
||||
*
|
||||
*
|
||||
* // set foo to 'yipee'
|
||||
* $location.search('foo', 'yipee');
|
||||
* // => $location
|
||||
* // $location.search() => {foo: 'yipee', baz: 'xoxo'}
|
||||
* ```
|
||||
*
|
||||
* @param {string|Object.<string>|Object.<Array.<string>>} search New search params - string or
|
||||
@@ -508,6 +549,13 @@ var locationPrototype = {
|
||||
*
|
||||
* Change hash fragment when called with parameter and return `$location`.
|
||||
*
|
||||
*
|
||||
* ```js
|
||||
* // given url http://example.com/some/path?foo=bar&baz=xoxo#hashValue
|
||||
* var hash = $location.hash();
|
||||
* // => "hashValue"
|
||||
* ```
|
||||
*
|
||||
* @param {(string|number)=} hash New hash fragment
|
||||
* @return {string} hash
|
||||
*/
|
||||
@@ -829,11 +877,19 @@ function $LocationProvider() {
|
||||
$rootScope.$evalAsync(function() {
|
||||
var oldUrl = $location.absUrl();
|
||||
var oldState = $location.$$state;
|
||||
var defaultPrevented;
|
||||
|
||||
$location.$$parse(newUrl);
|
||||
$location.$$state = newState;
|
||||
if ($rootScope.$broadcast('$locationChangeStart', newUrl, oldUrl,
|
||||
newState, oldState).defaultPrevented) {
|
||||
|
||||
defaultPrevented = $rootScope.$broadcast('$locationChangeStart', newUrl, oldUrl,
|
||||
newState, oldState).defaultPrevented;
|
||||
|
||||
// if the location was changed by a `$locationChangeStart` handler then stop
|
||||
// processing this location change
|
||||
if ($location.absUrl() !== newUrl) return;
|
||||
|
||||
if (defaultPrevented) {
|
||||
$location.$$parse(oldUrl);
|
||||
$location.$$state = oldState;
|
||||
setBrowserUrlWithFallback(oldUrl, false, oldState);
|
||||
@@ -857,13 +913,20 @@ function $LocationProvider() {
|
||||
initializing = false;
|
||||
|
||||
$rootScope.$evalAsync(function() {
|
||||
if ($rootScope.$broadcast('$locationChangeStart', $location.absUrl(), oldUrl,
|
||||
$location.$$state, oldState).defaultPrevented) {
|
||||
var newUrl = $location.absUrl();
|
||||
var defaultPrevented = $rootScope.$broadcast('$locationChangeStart', newUrl, oldUrl,
|
||||
$location.$$state, oldState).defaultPrevented;
|
||||
|
||||
// if the location was changed by a `$locationChangeStart` handler then stop
|
||||
// processing this location change
|
||||
if ($location.absUrl() !== newUrl) return;
|
||||
|
||||
if (defaultPrevented) {
|
||||
$location.$$parse(oldUrl);
|
||||
$location.$$state = oldState;
|
||||
} else {
|
||||
if (urlOrStateChanged) {
|
||||
setBrowserUrlWithFallback($location.absUrl(), currentReplace,
|
||||
setBrowserUrlWithFallback(newUrl, currentReplace,
|
||||
oldState === $location.$$state ? null : $location.$$state);
|
||||
}
|
||||
afterLocationChange(oldUrl, oldState);
|
||||
|
||||
+119
-145
@@ -5,7 +5,7 @@ var $parseMinErr = minErr('$parse');
|
||||
// Sandboxing Angular Expressions
|
||||
// ------------------------------
|
||||
// Angular expressions are generally considered safe because these expressions only have direct
|
||||
// access to $scope and locals. However, one can obtain the ability to execute arbitrary JS code by
|
||||
// access to `$scope` and locals. However, one can obtain the ability to execute arbitrary JS code by
|
||||
// obtaining a reference to native JS functions such as the Function constructor.
|
||||
//
|
||||
// As an example, consider the following Angular expression:
|
||||
@@ -14,7 +14,7 @@ var $parseMinErr = minErr('$parse');
|
||||
//
|
||||
// This sandboxing technique is not perfect and doesn't aim to be. The goal is to prevent exploits
|
||||
// against the expression language, but not to prevent exploits that were enabled by exposing
|
||||
// sensitive JavaScript or browser apis on Scope. Exposing such objects on a Scope is never a good
|
||||
// sensitive JavaScript or browser APIs on Scope. Exposing such objects on a Scope is never a good
|
||||
// practice and therefore we are not even trying to protect against interaction with an object
|
||||
// explicitly exposed in this way.
|
||||
//
|
||||
@@ -22,6 +22,8 @@ var $parseMinErr = minErr('$parse');
|
||||
// window or some DOM object that has a reference to window is published onto a Scope.
|
||||
// Similarly we prevent invocations of function known to be dangerous, as well as assignments to
|
||||
// native objects.
|
||||
//
|
||||
// See https://docs.angularjs.org/guide/security
|
||||
|
||||
|
||||
function ensureSafeMemberName(name, fullExpression) {
|
||||
@@ -30,7 +32,7 @@ function ensureSafeMemberName(name, fullExpression) {
|
||||
|| name === "__proto__") {
|
||||
throw $parseMinErr('isecfld',
|
||||
'Attempting to access a disallowed field in Angular expressions! '
|
||||
+'Expression: {0}', fullExpression);
|
||||
+ 'Expression: {0}', fullExpression);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
@@ -107,24 +109,24 @@ var OPERATORS = extend(createMap(), {
|
||||
}
|
||||
return a;
|
||||
}
|
||||
return isDefined(b)?b:undefined;},
|
||||
return isDefined(b) ? b : undefined;},
|
||||
'-':function(self, locals, a, b) {
|
||||
a=a(self, locals); b=b(self, locals);
|
||||
return (isDefined(a)?a:0)-(isDefined(b)?b:0);
|
||||
return (isDefined(a) ? a : 0) - (isDefined(b) ? b : 0);
|
||||
},
|
||||
'*':function(self, locals, a, b) {return a(self, locals)*b(self, locals);},
|
||||
'/':function(self, locals, a, b) {return a(self, locals)/b(self, locals);},
|
||||
'%':function(self, locals, a, b) {return a(self, locals)%b(self, locals);},
|
||||
'===':function(self, locals, a, b) {return a(self, locals)===b(self, locals);},
|
||||
'!==':function(self, locals, a, b) {return a(self, locals)!==b(self, locals);},
|
||||
'==':function(self, locals, a, b) {return a(self, locals)==b(self, locals);},
|
||||
'!=':function(self, locals, a, b) {return a(self, locals)!=b(self, locals);},
|
||||
'<':function(self, locals, a, b) {return a(self, locals)<b(self, locals);},
|
||||
'>':function(self, locals, a, b) {return a(self, locals)>b(self, locals);},
|
||||
'<=':function(self, locals, a, b) {return a(self, locals)<=b(self, locals);},
|
||||
'>=':function(self, locals, a, b) {return a(self, locals)>=b(self, locals);},
|
||||
'&&':function(self, locals, a, b) {return a(self, locals)&&b(self, locals);},
|
||||
'||':function(self, locals, a, b) {return a(self, locals)||b(self, locals);},
|
||||
'*':function(self, locals, a, b) {return a(self, locals) * b(self, locals);},
|
||||
'/':function(self, locals, a, b) {return a(self, locals) / b(self, locals);},
|
||||
'%':function(self, locals, a, b) {return a(self, locals) % b(self, locals);},
|
||||
'===':function(self, locals, a, b) {return a(self, locals) === b(self, locals);},
|
||||
'!==':function(self, locals, a, b) {return a(self, locals) !== b(self, locals);},
|
||||
'==':function(self, locals, a, b) {return a(self, locals) == b(self, locals);},
|
||||
'!=':function(self, locals, a, b) {return a(self, locals) != b(self, locals);},
|
||||
'<':function(self, locals, a, b) {return a(self, locals) < b(self, locals);},
|
||||
'>':function(self, locals, a, b) {return a(self, locals) > b(self, locals);},
|
||||
'<=':function(self, locals, a, b) {return a(self, locals) <= b(self, locals);},
|
||||
'>=':function(self, locals, a, b) {return a(self, locals) >= b(self, locals);},
|
||||
'&&':function(self, locals, a, b) {return a(self, locals) && b(self, locals);},
|
||||
'||':function(self, locals, a, b) {return a(self, locals) || b(self, locals);},
|
||||
'!':function(self, locals, a) {return !a(self, locals);},
|
||||
|
||||
//Tokenized as operators but parsed as assignment/filters
|
||||
@@ -150,44 +152,31 @@ Lexer.prototype = {
|
||||
lex: function(text) {
|
||||
this.text = text;
|
||||
this.index = 0;
|
||||
this.ch = undefined;
|
||||
this.tokens = [];
|
||||
|
||||
while (this.index < this.text.length) {
|
||||
this.ch = this.text.charAt(this.index);
|
||||
if (this.is('"\'')) {
|
||||
this.readString(this.ch);
|
||||
} else if (this.isNumber(this.ch) || this.is('.') && this.isNumber(this.peek())) {
|
||||
var ch = this.text.charAt(this.index);
|
||||
if (ch === '"' || ch === "'") {
|
||||
this.readString(ch);
|
||||
} else if (this.isNumber(ch) || ch === '.' && this.isNumber(this.peek())) {
|
||||
this.readNumber();
|
||||
} else if (this.isIdent(this.ch)) {
|
||||
} else if (this.isIdent(ch)) {
|
||||
this.readIdent();
|
||||
} else if (this.is('(){}[].,;:?')) {
|
||||
this.tokens.push({
|
||||
index: this.index,
|
||||
text: this.ch
|
||||
});
|
||||
} else if (this.is(ch, '(){}[].,;:?')) {
|
||||
this.tokens.push({index: this.index, text: ch});
|
||||
this.index++;
|
||||
} else if (this.isWhitespace(this.ch)) {
|
||||
} else if (this.isWhitespace(ch)) {
|
||||
this.index++;
|
||||
} else {
|
||||
var ch2 = this.ch + this.peek();
|
||||
var ch2 = ch + this.peek();
|
||||
var ch3 = ch2 + this.peek(2);
|
||||
var fn = OPERATORS[this.ch];
|
||||
var fn2 = OPERATORS[ch2];
|
||||
var fn3 = OPERATORS[ch3];
|
||||
if (fn3) {
|
||||
this.tokens.push({index: this.index, text: ch3, fn: fn3});
|
||||
this.index += 3;
|
||||
} else if (fn2) {
|
||||
this.tokens.push({index: this.index, text: ch2, fn: fn2});
|
||||
this.index += 2;
|
||||
} else if (fn) {
|
||||
this.tokens.push({
|
||||
index: this.index,
|
||||
text: this.ch,
|
||||
fn: fn
|
||||
});
|
||||
this.index += 1;
|
||||
var op1 = OPERATORS[ch];
|
||||
var op2 = OPERATORS[ch2];
|
||||
var op3 = OPERATORS[ch3];
|
||||
if (op1 || op2 || op3) {
|
||||
var token = op3 ? ch3 : (op2 ? ch2 : ch);
|
||||
this.tokens.push({index: this.index, text: token, operator: true});
|
||||
this.index += token.length;
|
||||
} else {
|
||||
this.throwError('Unexpected next character ', this.index, this.index + 1);
|
||||
}
|
||||
@@ -196,8 +185,8 @@ Lexer.prototype = {
|
||||
return this.tokens;
|
||||
},
|
||||
|
||||
is: function(chars) {
|
||||
return chars.indexOf(this.ch) !== -1;
|
||||
is: function(ch, chars) {
|
||||
return chars.indexOf(ch) !== -1;
|
||||
},
|
||||
|
||||
peek: function(i) {
|
||||
@@ -206,7 +195,7 @@ Lexer.prototype = {
|
||||
},
|
||||
|
||||
isNumber: function(ch) {
|
||||
return ('0' <= ch && ch <= '9');
|
||||
return ('0' <= ch && ch <= '9') && typeof ch === "string";
|
||||
},
|
||||
|
||||
isWhitespace: function(ch) {
|
||||
@@ -259,79 +248,28 @@ Lexer.prototype = {
|
||||
}
|
||||
this.index++;
|
||||
}
|
||||
number = 1 * number;
|
||||
this.tokens.push({
|
||||
index: start,
|
||||
text: number,
|
||||
constant: true,
|
||||
fn: function() { return number; }
|
||||
value: Number(number)
|
||||
});
|
||||
},
|
||||
|
||||
readIdent: function() {
|
||||
var expression = this.text;
|
||||
|
||||
var ident = '';
|
||||
var start = this.index;
|
||||
|
||||
var lastDot, peekIndex, methodName, ch;
|
||||
|
||||
while (this.index < this.text.length) {
|
||||
ch = this.text.charAt(this.index);
|
||||
if (ch === '.' || this.isIdent(ch) || this.isNumber(ch)) {
|
||||
if (ch === '.') lastDot = this.index;
|
||||
ident += ch;
|
||||
} else {
|
||||
var ch = this.text.charAt(this.index);
|
||||
if (!(this.isIdent(ch) || this.isNumber(ch))) {
|
||||
break;
|
||||
}
|
||||
this.index++;
|
||||
}
|
||||
|
||||
//check if the identifier ends with . and if so move back one char
|
||||
if (lastDot && ident[ident.length - 1] === '.') {
|
||||
this.index--;
|
||||
ident = ident.slice(0, -1);
|
||||
lastDot = ident.lastIndexOf('.');
|
||||
if (lastDot === -1) {
|
||||
lastDot = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
//check if this is not a method invocation and if it is back out to last dot
|
||||
if (lastDot) {
|
||||
peekIndex = this.index;
|
||||
while (peekIndex < this.text.length) {
|
||||
ch = this.text.charAt(peekIndex);
|
||||
if (ch === '(') {
|
||||
methodName = ident.substr(lastDot - start + 1);
|
||||
ident = ident.substr(0, lastDot - start);
|
||||
this.index = peekIndex;
|
||||
break;
|
||||
}
|
||||
if (this.isWhitespace(ch)) {
|
||||
peekIndex++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.tokens.push({
|
||||
index: start,
|
||||
text: ident,
|
||||
fn: CONSTANTS[ident] || getterFn(ident, this.options, expression)
|
||||
text: this.text.slice(start, this.index),
|
||||
identifier: true
|
||||
});
|
||||
|
||||
if (methodName) {
|
||||
this.tokens.push({
|
||||
index: lastDot,
|
||||
text: '.'
|
||||
});
|
||||
this.tokens.push({
|
||||
index: lastDot + 1,
|
||||
text: methodName
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
readString: function(quote) {
|
||||
@@ -362,9 +300,8 @@ Lexer.prototype = {
|
||||
this.tokens.push({
|
||||
index: start,
|
||||
text: rawString,
|
||||
string: string,
|
||||
constant: true,
|
||||
fn: function() { return string; }
|
||||
value: string
|
||||
});
|
||||
return;
|
||||
} else {
|
||||
@@ -425,16 +362,12 @@ Parser.prototype = {
|
||||
primary = this.arrayDeclaration();
|
||||
} else if (this.expect('{')) {
|
||||
primary = this.object();
|
||||
} else if (this.peek().identifier) {
|
||||
primary = this.identifier();
|
||||
} else if (this.peek().constant) {
|
||||
primary = this.constant();
|
||||
} else {
|
||||
var token = this.expect();
|
||||
primary = token.fn;
|
||||
if (!primary) {
|
||||
this.throwError('not a primary expression', token);
|
||||
}
|
||||
if (token.constant) {
|
||||
primary.constant = true;
|
||||
primary.literal = true;
|
||||
}
|
||||
this.throwError('not a primary expression', this.peek());
|
||||
}
|
||||
|
||||
var next, context;
|
||||
@@ -468,8 +401,11 @@ Parser.prototype = {
|
||||
},
|
||||
|
||||
peek: function(e1, e2, e3, e4) {
|
||||
if (this.tokens.length > 0) {
|
||||
var token = this.tokens[0];
|
||||
return this.peekAhead(0, e1, e2, e3, e4);
|
||||
},
|
||||
peekAhead: function(i, e1, e2, e3, e4) {
|
||||
if (this.tokens.length > i) {
|
||||
var token = this.tokens[i];
|
||||
var t = token.text;
|
||||
if (t === e1 || t === e2 || t === e3 || t === e4 ||
|
||||
(!e1 && !e2 && !e3 && !e4)) {
|
||||
@@ -489,12 +425,19 @@ Parser.prototype = {
|
||||
},
|
||||
|
||||
consume: function(e1) {
|
||||
if (!this.expect(e1)) {
|
||||
if (this.tokens.length === 0) {
|
||||
throw $parseMinErr('ueoe', 'Unexpected end of expression: {0}', this.text);
|
||||
}
|
||||
|
||||
var token = this.expect(e1);
|
||||
if (!token) {
|
||||
this.throwError('is unexpected, expecting [' + e1 + ']', this.peek());
|
||||
}
|
||||
return token;
|
||||
},
|
||||
|
||||
unaryFn: function(fn, right) {
|
||||
unaryFn: function(op, right) {
|
||||
var fn = OPERATORS[op];
|
||||
return extend(function $parseUnaryFn(self, locals) {
|
||||
return fn(self, locals, right);
|
||||
}, {
|
||||
@@ -503,7 +446,8 @@ Parser.prototype = {
|
||||
});
|
||||
},
|
||||
|
||||
binaryFn: function(left, fn, right, isBranching) {
|
||||
binaryFn: function(left, op, right, isBranching) {
|
||||
var fn = OPERATORS[op];
|
||||
return extend(function $parseBinaryFn(self, locals) {
|
||||
return fn(self, locals, left, right);
|
||||
}, {
|
||||
@@ -512,6 +456,28 @@ Parser.prototype = {
|
||||
});
|
||||
},
|
||||
|
||||
identifier: function() {
|
||||
var id = this.consume().text;
|
||||
|
||||
//Continue reading each `.identifier` unless it is a method invocation
|
||||
while (this.peek('.') && this.peekAhead(1).identifier && !this.peekAhead(2, '(')) {
|
||||
id += this.consume().text + this.consume().text;
|
||||
}
|
||||
|
||||
return CONSTANTS[id] || getterFn(id, this.options, this.text);
|
||||
},
|
||||
|
||||
constant: function() {
|
||||
var value = this.consume().value;
|
||||
|
||||
return extend(function $parseConstant() {
|
||||
return value;
|
||||
}, {
|
||||
constant: true,
|
||||
literal: true
|
||||
});
|
||||
},
|
||||
|
||||
statements: function() {
|
||||
var statements = [];
|
||||
while (true) {
|
||||
@@ -543,8 +509,7 @@ Parser.prototype = {
|
||||
},
|
||||
|
||||
filter: function(inputFn) {
|
||||
var token = this.expect();
|
||||
var fn = this.$filter(token.text);
|
||||
var fn = this.$filter(this.consume().text);
|
||||
var argsFn;
|
||||
var args;
|
||||
|
||||
@@ -607,7 +572,7 @@ Parser.prototype = {
|
||||
var token;
|
||||
if ((token = this.expect('?'))) {
|
||||
middle = this.assignment();
|
||||
if ((token = this.expect(':'))) {
|
||||
if (this.consume(':')) {
|
||||
var right = this.assignment();
|
||||
|
||||
return extend(function $parseTernary(self, locals) {
|
||||
@@ -615,9 +580,6 @@ Parser.prototype = {
|
||||
}, {
|
||||
constant: left.constant && middle.constant && right.constant
|
||||
});
|
||||
|
||||
} else {
|
||||
this.throwError('expected :', token);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -628,7 +590,7 @@ Parser.prototype = {
|
||||
var left = this.logicalAND();
|
||||
var token;
|
||||
while ((token = this.expect('||'))) {
|
||||
left = this.binaryFn(left, token.fn, this.logicalAND(), true);
|
||||
left = this.binaryFn(left, token.text, this.logicalAND(), true);
|
||||
}
|
||||
return left;
|
||||
},
|
||||
@@ -637,7 +599,7 @@ Parser.prototype = {
|
||||
var left = this.equality();
|
||||
var token;
|
||||
if ((token = this.expect('&&'))) {
|
||||
left = this.binaryFn(left, token.fn, this.logicalAND(), true);
|
||||
left = this.binaryFn(left, token.text, this.logicalAND(), true);
|
||||
}
|
||||
return left;
|
||||
},
|
||||
@@ -646,7 +608,7 @@ Parser.prototype = {
|
||||
var left = this.relational();
|
||||
var token;
|
||||
if ((token = this.expect('==','!=','===','!=='))) {
|
||||
left = this.binaryFn(left, token.fn, this.equality());
|
||||
left = this.binaryFn(left, token.text, this.equality());
|
||||
}
|
||||
return left;
|
||||
},
|
||||
@@ -655,7 +617,7 @@ Parser.prototype = {
|
||||
var left = this.additive();
|
||||
var token;
|
||||
if ((token = this.expect('<', '>', '<=', '>='))) {
|
||||
left = this.binaryFn(left, token.fn, this.relational());
|
||||
left = this.binaryFn(left, token.text, this.relational());
|
||||
}
|
||||
return left;
|
||||
},
|
||||
@@ -664,7 +626,7 @@ Parser.prototype = {
|
||||
var left = this.multiplicative();
|
||||
var token;
|
||||
while ((token = this.expect('+','-'))) {
|
||||
left = this.binaryFn(left, token.fn, this.multiplicative());
|
||||
left = this.binaryFn(left, token.text, this.multiplicative());
|
||||
}
|
||||
return left;
|
||||
},
|
||||
@@ -673,7 +635,7 @@ Parser.prototype = {
|
||||
var left = this.unary();
|
||||
var token;
|
||||
while ((token = this.expect('*','/','%'))) {
|
||||
left = this.binaryFn(left, token.fn, this.unary());
|
||||
left = this.binaryFn(left, token.text, this.unary());
|
||||
}
|
||||
return left;
|
||||
},
|
||||
@@ -683,9 +645,9 @@ Parser.prototype = {
|
||||
if (this.expect('+')) {
|
||||
return this.primary();
|
||||
} else if ((token = this.expect('-'))) {
|
||||
return this.binaryFn(Parser.ZERO, token.fn, this.unary());
|
||||
return this.binaryFn(Parser.ZERO, token.text, this.unary());
|
||||
} else if ((token = this.expect('!'))) {
|
||||
return this.unaryFn(token.fn, this.unary());
|
||||
return this.unaryFn(token.text, this.unary());
|
||||
} else {
|
||||
return this.primary();
|
||||
}
|
||||
@@ -693,7 +655,7 @@ Parser.prototype = {
|
||||
|
||||
fieldAccess: function(object) {
|
||||
var expression = this.text;
|
||||
var field = this.expect().text;
|
||||
var field = this.consume().text;
|
||||
var getter = getterFn(field, this.options, expression);
|
||||
|
||||
return extend(function $parseFieldAccess(scope, locals, self) {
|
||||
@@ -778,8 +740,7 @@ Parser.prototype = {
|
||||
// Support trailing commas per ES5.1.
|
||||
break;
|
||||
}
|
||||
var elementFn = this.expression();
|
||||
elementFns.push(elementFn);
|
||||
elementFns.push(this.expression());
|
||||
} while (this.expect(','));
|
||||
}
|
||||
this.consume(']');
|
||||
@@ -805,11 +766,16 @@ Parser.prototype = {
|
||||
// Support trailing commas per ES5.1.
|
||||
break;
|
||||
}
|
||||
var token = this.expect();
|
||||
keys.push(token.string || token.text);
|
||||
var token = this.consume();
|
||||
if (token.constant) {
|
||||
keys.push(token.value);
|
||||
} else if (token.identifier) {
|
||||
keys.push(token.text);
|
||||
} else {
|
||||
this.throwError("invalid key", token);
|
||||
}
|
||||
this.consume(':');
|
||||
var value = this.expression();
|
||||
valueFns.push(value);
|
||||
valueFns.push(this.expression());
|
||||
} while (this.expect(','));
|
||||
}
|
||||
this.consume('}');
|
||||
@@ -1251,13 +1217,21 @@ function $ParseProvider() {
|
||||
|
||||
function addInterceptor(parsedExpression, interceptorFn) {
|
||||
if (!interceptorFn) return parsedExpression;
|
||||
var watchDelegate = parsedExpression.$$watchDelegate;
|
||||
|
||||
var fn = function interceptedExpression(scope, locals) {
|
||||
var regularWatch =
|
||||
watchDelegate !== oneTimeLiteralWatchDelegate &&
|
||||
watchDelegate !== oneTimeWatchDelegate;
|
||||
|
||||
var fn = regularWatch ? function regularInterceptedExpression(scope, locals) {
|
||||
var value = parsedExpression(scope, locals);
|
||||
return interceptorFn(value, scope, locals);
|
||||
} : function oneTimeInterceptedExpression(scope, locals) {
|
||||
var value = parsedExpression(scope, locals);
|
||||
var result = interceptorFn(value, scope, locals);
|
||||
// we only return the interceptor's result if the
|
||||
// initial value is defined (for bind-once)
|
||||
return isDefined(value) || interceptorFn.$stateful ? result : value;
|
||||
return isDefined(value) ? result : value;
|
||||
};
|
||||
|
||||
// Propagate $$watchDelegates other then inputsWatchDelegate
|
||||
|
||||
+6
-6
@@ -6,7 +6,11 @@
|
||||
* @requires $rootScope
|
||||
*
|
||||
* @description
|
||||
* A promise/deferred implementation inspired by [Kris Kowal's Q](https://github.com/kriskowal/q).
|
||||
* A service that helps you run functions asynchronously, and use their return values (or exceptions)
|
||||
* when they are done processing.
|
||||
*
|
||||
* This is an implementation of promises/deferred objects inspired by
|
||||
* [Kris Kowal's Q](https://github.com/kriskowal/q).
|
||||
*
|
||||
* $q can be used in two fashions --- one which is more similar to Kris Kowal's Q or jQuery's Deferred
|
||||
* implementations, and the other which resembles ES6 promises to some degree.
|
||||
@@ -142,16 +146,12 @@
|
||||
*
|
||||
* - `catch(errorCallback)` – shorthand for `promise.then(null, errorCallback)`
|
||||
*
|
||||
* - `finally(callback)` – allows you to observe either the fulfillment or rejection of a promise,
|
||||
* - `finally(callback, notifyCallback)` – allows you to observe either the fulfillment or rejection of a promise,
|
||||
* but to do so without modifying the final value. This is useful to release resources or do some
|
||||
* clean-up that needs to be done whether the promise was rejected or resolved. See the [full
|
||||
* specification](https://github.com/kriskowal/q/wiki/API-Reference#promisefinallycallback) for
|
||||
* more information.
|
||||
*
|
||||
* Because `finally` is a reserved word in JavaScript and reserved keywords are not supported as
|
||||
* property names by ES3, you'll need to invoke the method like `promise['finally'](callback)` to
|
||||
* make your code IE8 and Android 2.x compatible.
|
||||
*
|
||||
* # Chaining promises
|
||||
*
|
||||
* Because calling the `then` method of a promise returns a new derived promise, it is easily
|
||||
|
||||
+8
-8
@@ -773,11 +773,11 @@ function $RootScopeProvider() {
|
||||
if (ttl < 5) {
|
||||
logIdx = 4 - ttl;
|
||||
if (!watchLog[logIdx]) watchLog[logIdx] = [];
|
||||
logMsg = (isFunction(watch.exp))
|
||||
? 'fn: ' + (watch.exp.name || watch.exp.toString())
|
||||
: watch.exp;
|
||||
logMsg += '; newVal: ' + toJson(value) + '; oldVal: ' + toJson(last);
|
||||
watchLog[logIdx].push(logMsg);
|
||||
watchLog[logIdx].push({
|
||||
msg: isFunction(watch.exp) ? 'fn: ' + (watch.exp.name || watch.exp.toString()) : watch.exp,
|
||||
newVal: value,
|
||||
oldVal: last
|
||||
});
|
||||
}
|
||||
} else if (watch === lastDirtyWatch) {
|
||||
// If the most recently dirty watcher is now clean, short circuit since the remaining watchers
|
||||
@@ -810,7 +810,7 @@ function $RootScopeProvider() {
|
||||
throw $rootScopeMinErr('infdig',
|
||||
'{0} $digest() iterations reached. Aborting!\n' +
|
||||
'Watchers fired in the last 5 iterations: {1}',
|
||||
TTL, toJson(watchLog));
|
||||
TTL, watchLog);
|
||||
}
|
||||
|
||||
} while (dirty || asyncQueue.length);
|
||||
@@ -1161,7 +1161,7 @@ function $RootScopeProvider() {
|
||||
do {
|
||||
namedListeners = scope.$$listeners[name] || empty;
|
||||
event.currentScope = scope;
|
||||
for (i=0, length=namedListeners.length; i<length; i++) {
|
||||
for (i = 0, length = namedListeners.length; i < length; i++) {
|
||||
|
||||
// if listeners were deregistered, defragment the array
|
||||
if (!namedListeners[i]) {
|
||||
@@ -1235,7 +1235,7 @@ function $RootScopeProvider() {
|
||||
while ((current = next)) {
|
||||
event.currentScope = current;
|
||||
listeners = current.$$listeners[name] || [];
|
||||
for (i=0, length = listeners.length; i<length; i++) {
|
||||
for (i = 0, length = listeners.length; i < length; i++) {
|
||||
// if listeners were deregistered, defragment the array
|
||||
if (!listeners[i]) {
|
||||
listeners.splice(i, 1);
|
||||
|
||||
@@ -63,7 +63,7 @@ function $$SanitizeUriProvider() {
|
||||
var normalizedVal;
|
||||
normalizedVal = urlResolve(uri).href;
|
||||
if (normalizedVal !== '' && !normalizedVal.match(regex)) {
|
||||
return 'unsafe:'+normalizedVal;
|
||||
return 'unsafe:' + normalizedVal;
|
||||
}
|
||||
return uri;
|
||||
};
|
||||
|
||||
+1
-1
@@ -44,7 +44,7 @@ function $SnifferProvider() {
|
||||
transitions = !!(('transition' in bodyStyle) || (vendorPrefix + 'Transition' in bodyStyle));
|
||||
animations = !!(('animation' in bodyStyle) || (vendorPrefix + 'Animation' in bodyStyle));
|
||||
|
||||
if (android && (!transitions||!animations)) {
|
||||
if (android && (!transitions || !animations)) {
|
||||
transitions = isString(document.body.style.webkitTransition);
|
||||
animations = isString(document.body.style.webkitAnimation);
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ function $TemplateRequestProvider() {
|
||||
if (isArray(transformResponse)) {
|
||||
var original = transformResponse;
|
||||
transformResponse = [];
|
||||
for (var i=0; i<original.length; ++i) {
|
||||
for (var i = 0; i < original.length; ++i) {
|
||||
var transformer = original[i];
|
||||
if (transformer !== defaultHttpResponseTransform) {
|
||||
transformResponse.push(transformer);
|
||||
|
||||
+2
-2
@@ -7,7 +7,7 @@
|
||||
// exactly the behavior needed here. There is little value is mocking these out for this
|
||||
// service.
|
||||
var urlParsingNode = document.createElement("a");
|
||||
var originUrl = urlResolve(window.location.href, true);
|
||||
var originUrl = urlResolve(window.location.href);
|
||||
|
||||
|
||||
/**
|
||||
@@ -62,7 +62,7 @@ var originUrl = urlResolve(window.location.href, true);
|
||||
* | pathname | The pathname, beginning with "/"
|
||||
*
|
||||
*/
|
||||
function urlResolve(url, base) {
|
||||
function urlResolve(url) {
|
||||
var href = url;
|
||||
|
||||
if (msie) {
|
||||
|
||||
+14
-14
@@ -239,7 +239,7 @@
|
||||
* You then configure `$animate` to enforce this prefix:
|
||||
*
|
||||
* ```js
|
||||
* $animateProvider.classNamePrefix(/animate-/);
|
||||
* $animateProvider.classNameFilter(/animate-/);
|
||||
* ```
|
||||
* </div>
|
||||
*
|
||||
@@ -970,9 +970,9 @@ angular.module('ngAnimate', ['ng'])
|
||||
* | 3. $animate waits for the next digest to start the animation | class="my-animation ng-animate" |
|
||||
* | 4. the .ng-leave class is added to the element | class="my-animation ng-animate ng-leave" |
|
||||
* | 5. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation ng-animate ng-leave" |
|
||||
* | 6. $animate blocks all CSS transitions on the element to ensure the .ng-leave class styling is applied right away | class="my-animation ng-animate ng-leave” |
|
||||
* | 6. $animate blocks all CSS transitions on the element to ensure the .ng-leave class styling is applied right away | class="my-animation ng-animate ng-leave" |
|
||||
* | 7. $animate waits for a single animation frame (this performs a reflow) | class="my-animation ng-animate ng-leave" |
|
||||
* | 8. $animate removes the CSS transition block placed on the element | class="my-animation ng-animate ng-leave” |
|
||||
* | 8. $animate removes the CSS transition block placed on the element | class="my-animation ng-animate ng-leave" |
|
||||
* | 9. the .ng-leave-active class is added (this triggers the CSS transition/animation) | class="my-animation ng-animate ng-leave ng-leave-active" |
|
||||
* | 10. $animate waits for the animation to complete (via events and timeout) | class="my-animation ng-animate ng-leave ng-leave-active" |
|
||||
* | 11. The animation ends and all generated CSS classes are removed from the element | class="my-animation" |
|
||||
@@ -1016,9 +1016,9 @@ angular.module('ngAnimate', ['ng'])
|
||||
* | 4. $animate runs the JavaScript-defined animations detected on the element | class="my-animation ng-animate" |
|
||||
* | 5. the .ng-move class is added to the element | class="my-animation ng-animate ng-move" |
|
||||
* | 6. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation ng-animate ng-move" |
|
||||
* | 7. $animate blocks all CSS transitions on the element to ensure the .ng-move class styling is applied right away | class="my-animation ng-animate ng-move” |
|
||||
* | 7. $animate blocks all CSS transitions on the element to ensure the .ng-move class styling is applied right away | class="my-animation ng-animate ng-move" |
|
||||
* | 8. $animate waits for a single animation frame (this performs a reflow) | class="my-animation ng-animate ng-move" |
|
||||
* | 9. $animate removes the CSS transition block placed on the element | class="my-animation ng-animate ng-move” |
|
||||
* | 9. $animate removes the CSS transition block placed on the element | class="my-animation ng-animate ng-move" |
|
||||
* | 10. the .ng-move-active class is added (this triggers the CSS transition/animation) | class="my-animation ng-animate ng-move ng-move-active" |
|
||||
* | 11. $animate waits for the animation to complete (via events and timeout) | class="my-animation ng-animate ng-move ng-move-active" |
|
||||
* | 12. The animation ends and all generated CSS classes are removed from the element | class="my-animation" |
|
||||
@@ -1063,8 +1063,8 @@ angular.module('ngAnimate', ['ng'])
|
||||
* | 3. the .super-add class is added to the element | class="my-animation ng-animate super-add" |
|
||||
* | 4. $animate waits for a single animation frame (this performs a reflow) | class="my-animation ng-animate super-add" |
|
||||
* | 5. the .super and .super-add-active classes are added (this triggers the CSS transition/animation) | class="my-animation ng-animate super super-add super-add-active" |
|
||||
* | 6. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation ng-animate super-add" |
|
||||
* | 7. $animate waits for the animation to complete (via events and timeout) | class="my-animation super super-add super-add-active" |
|
||||
* | 6. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation ng-animate super super-add super-add-active" |
|
||||
* | 7. $animate waits for the animation to complete (via events and timeout) | class="my-animation ng-animate super super-add super-add-active" |
|
||||
* | 8. The animation ends and all generated CSS classes are removed from the element | class="my-animation super" |
|
||||
* | 9. The super class is kept on the element | class="my-animation super" |
|
||||
* | 10. The returned promise is resolved. | class="my-animation super" |
|
||||
@@ -1097,7 +1097,7 @@ angular.module('ngAnimate', ['ng'])
|
||||
* | 3. the .super-remove class is added to the element | class="my-animation super ng-animate super-remove" |
|
||||
* | 4. $animate waits for a single animation frame (this performs a reflow) | class="my-animation super ng-animate super-remove" |
|
||||
* | 5. the .super-remove-active classes are added and .super is removed (this triggers the CSS transition/animation) | class="my-animation ng-animate super-remove super-remove-active" |
|
||||
* | 6. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation super ng-animate super-remove" |
|
||||
* | 6. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation ng-animate super-remove super-remove-active" |
|
||||
* | 7. $animate waits for the animation to complete (via events and timeout) | class="my-animation ng-animate super-remove super-remove-active" |
|
||||
* | 8. The animation ends and all generated CSS classes are removed from the element | class="my-animation" |
|
||||
* | 9. The returned promise is resolved. | class="my-animation" |
|
||||
@@ -1122,11 +1122,11 @@ angular.module('ngAnimate', ['ng'])
|
||||
*
|
||||
* | Animation Step | What the element class attribute looks like |
|
||||
* |--------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------|
|
||||
* | 1. $animate.removeClass(element, ‘on’, ‘off’) is called | class="my-animation super off” |
|
||||
* | 2. $animate runs the JavaScript-defined animations detected on the element | class="my-animation super ng-animate off” |
|
||||
* | 3. the .on-add and .off-remove classes are added to the element | class="my-animation ng-animate on-add off-remove off” |
|
||||
* | 4. $animate waits for a single animation frame (this performs a reflow) | class="my-animation ng-animate on-add off-remove off” |
|
||||
* | 5. the .on, .on-add-active and .off-remove-active classes are added and .off is removed (this triggers the CSS transition/animation) | class="my-animation ng-animate on on-add on-add-active off-remove off-remove-active” |
|
||||
* | 1. $animate.setClass(element, 'on', 'off') is called | class="my-animation off" |
|
||||
* | 2. $animate runs the JavaScript-defined animations detected on the element | class="my-animation ng-animate off" |
|
||||
* | 3. the .on-add and .off-remove classes are added to the element | class="my-animation ng-animate on-add off-remove off" |
|
||||
* | 4. $animate waits for a single animation frame (this performs a reflow) | class="my-animation ng-animate on-add off-remove off" |
|
||||
* | 5. the .on, .on-add-active and .off-remove-active classes are added and .off is removed (this triggers the CSS transition/animation) | class="my-animation ng-animate on on-add on-add-active off-remove off-remove-active" |
|
||||
* | 6. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation ng-animate on on-add on-add-active off-remove off-remove-active" |
|
||||
* | 7. $animate waits for the animation to complete (via events and timeout) | class="my-animation ng-animate on on-add on-add-active off-remove off-remove-active" |
|
||||
* | 8. The animation ends and all generated CSS classes are removed from the element | class="my-animation on" |
|
||||
@@ -1883,7 +1883,7 @@ angular.module('ngAnimate', ['ng'])
|
||||
//the jqLite object, so we're safe to use a single variable to house
|
||||
//the styles since there is always only one element being animated
|
||||
var oldStyle = node.getAttribute('style') || '';
|
||||
if (oldStyle.charAt(oldStyle.length-1) !== ';') {
|
||||
if (oldStyle.charAt(oldStyle.length - 1) !== ';') {
|
||||
oldStyle += ';';
|
||||
}
|
||||
node.setAttribute('style', oldStyle + ' ' + style);
|
||||
|
||||
+82
-22
@@ -5,33 +5,49 @@
|
||||
* @name ngAria
|
||||
* @description
|
||||
*
|
||||
* The `ngAria` module provides support for adding <abbr title="Accessible Rich Internet Applications">ARIA</abbr>
|
||||
* attributes that convey state or semantic information about the application in order to allow assistive technologies
|
||||
* to convey appropriate information to persons with disabilities.
|
||||
* The `ngAria` module provides support for common
|
||||
* [<abbr title="Accessible Rich Internet Applications">ARIA</abbr>](http://www.w3.org/TR/wai-aria/)
|
||||
* attributes that convey state or semantic information about the application for users
|
||||
* of assistive technologies, such as screen readers.
|
||||
*
|
||||
* <div doc-module-components="ngAria"></div>
|
||||
*
|
||||
* # Usage
|
||||
* To enable the addition of the ARIA tags, just require the module into your application and the tags will
|
||||
* hook into your ng-show/ng-hide, input, textarea, button, select and ng-required directives and adds the
|
||||
* appropriate ARIA attributes.
|
||||
* ## Usage
|
||||
*
|
||||
* Currently, the following ARIA attributes are implemented:
|
||||
* For ngAria to do its magic, simply include the module as a dependency. The directives supported
|
||||
* by ngAria are:
|
||||
* `ngModel`, `ngDisabled`, `ngShow`, `ngHide`, `ngClick`, `ngDblClick`, and `ngMessages`.
|
||||
*
|
||||
* + aria-hidden
|
||||
* + aria-checked
|
||||
* + aria-disabled
|
||||
* + aria-required
|
||||
* + aria-invalid
|
||||
* + aria-multiline
|
||||
* + aria-valuenow
|
||||
* + aria-valuemin
|
||||
* + aria-valuemax
|
||||
* + tabindex
|
||||
* Below is a more detailed breakdown of the attributes handled by ngAria:
|
||||
*
|
||||
* You can disable individual ARIA attributes by using the {@link ngAria.$ariaProvider#config config} method.
|
||||
* | Directive | Supported Attributes |
|
||||
* |---------------------------------------------|----------------------------------------------------------------------------------------|
|
||||
* | {@link ng.directive:ngModel ngModel} | aria-checked, aria-valuemin, aria-valuemax, aria-valuenow, aria-invalid, aria-required |
|
||||
* | {@link ng.directive:ngDisabled ngDisabled} | aria-disabled |
|
||||
* | {@link ng.directive:ngShow ngShow} | aria-hidden |
|
||||
* | {@link ng.directive:ngHide ngHide} | aria-hidden |
|
||||
* | {@link ng.directive:ngClick ngClick} | tabindex |
|
||||
* | {@link ng.directive:ngDblclick ngDblclick} | tabindex |
|
||||
* | {@link module:ngMessages ngMessages} | aria-live |
|
||||
*
|
||||
* Find out more information about each directive by reading the
|
||||
* {@link guide/accessibility ngAria Developer Guide}.
|
||||
*
|
||||
* ##Example
|
||||
* Using ngDisabled with ngAria:
|
||||
* ```html
|
||||
* <md-checkbox ng-disabled="disabled">
|
||||
* ```
|
||||
* Becomes:
|
||||
* ```html
|
||||
* <md-checkbox ng-disabled="disabled" aria-disabled="true">
|
||||
* ```
|
||||
*
|
||||
* ##Disabling Attributes
|
||||
* It's possible to disable individual attributes added by ngAria with the
|
||||
* {@link ngAria.$ariaProvider#config config} method. For more details, see the
|
||||
* {@link guide/accessibility Developer Guide}.
|
||||
*/
|
||||
|
||||
/* global -ngAriaModule */
|
||||
var ngAriaModule = angular.module('ngAria', ['ng']).
|
||||
provider('$aria', $AriaProvider);
|
||||
@@ -42,10 +58,20 @@ var ngAriaModule = angular.module('ngAria', ['ng']).
|
||||
*
|
||||
* @description
|
||||
*
|
||||
* Used for configuring ARIA attributes.
|
||||
* Used for configuring the ARIA attributes injected and managed by ngAria.
|
||||
*
|
||||
* ```js
|
||||
* angular.module('myApp', ['ngAria'], function config($ariaProvider) {
|
||||
* $ariaProvider.config({
|
||||
* ariaValue: true,
|
||||
* tabindex: false
|
||||
* });
|
||||
* });
|
||||
*```
|
||||
*
|
||||
* ## Dependencies
|
||||
* Requires the {@link ngAria} module to be installed.
|
||||
*
|
||||
*/
|
||||
function $AriaProvider() {
|
||||
var config = {
|
||||
@@ -108,7 +134,41 @@ function $AriaProvider() {
|
||||
*
|
||||
* @description
|
||||
*
|
||||
* Contains helper methods for applying ARIA attributes to HTML
|
||||
* The $aria service contains helper methods for applying common
|
||||
* [ARIA](http://www.w3.org/TR/wai-aria/) attributes to HTML directives.
|
||||
*
|
||||
* ngAria injects common accessibility attributes that tell assistive technologies when HTML
|
||||
* elements are enabled, selected, hidden, and more. To see how this is performed with ngAria,
|
||||
* let's review a code snippet from ngAria itself:
|
||||
*
|
||||
*```js
|
||||
* ngAriaModule.directive('ngDisabled', ['$aria', function($aria) {
|
||||
* return $aria.$$watchExpr('ngDisabled', 'aria-disabled');
|
||||
* }])
|
||||
*```
|
||||
* Shown above, the ngAria module creates a directive with the same signature as the
|
||||
* traditional `ng-disabled` directive. But this ngAria version is dedicated to
|
||||
* solely managing accessibility attributes. The internal `$aria` service is used to watch the
|
||||
* boolean attribute `ngDisabled`. If it has not been explicitly set by the developer,
|
||||
* `aria-disabled` is injected as an attribute with its value synchronized to the value in
|
||||
* `ngDisabled`.
|
||||
*
|
||||
* Because ngAria hooks into the `ng-disabled` directive, developers do not have to do
|
||||
* anything to enable this feature. The `aria-disabled` attribute is automatically managed
|
||||
* simply as a silent side-effect of using `ng-disabled` with the ngAria module.
|
||||
*
|
||||
* The full list of directives that interface with ngAria:
|
||||
* * **ngModel**
|
||||
* * **ngShow**
|
||||
* * **ngHide**
|
||||
* * **ngClick**
|
||||
* * **ngDblclick**
|
||||
* * **ngMessages**
|
||||
* * **ngDisabled**
|
||||
*
|
||||
* Read the {@link guide/accessibility ngAria Developer Guide} for a thorough explanation of each
|
||||
* directive.
|
||||
*
|
||||
*
|
||||
* ## Dependencies
|
||||
* Requires the {@link ngAria} module to be installed.
|
||||
|
||||
Vendored
+3
-3
@@ -40,9 +40,9 @@ $provide.value("$locale", {
|
||||
"Sa"
|
||||
],
|
||||
"SHORTMONTH": [
|
||||
"Jan",
|
||||
"Feb",
|
||||
"Mar",
|
||||
"Jan.",
|
||||
"Feb.",
|
||||
"Mrt.",
|
||||
"Apr",
|
||||
"Mei",
|
||||
"Jun",
|
||||
|
||||
Vendored
+4
-4
@@ -40,9 +40,9 @@ $provide.value("$locale", {
|
||||
"Sa"
|
||||
],
|
||||
"SHORTMONTH": [
|
||||
"Jan",
|
||||
"Feb",
|
||||
"Mar",
|
||||
"Jan.",
|
||||
"Feb.",
|
||||
"Mrt.",
|
||||
"Apr",
|
||||
"Mei",
|
||||
"Jun",
|
||||
@@ -53,7 +53,7 @@ $provide.value("$locale", {
|
||||
"Nov",
|
||||
"Des"
|
||||
],
|
||||
"fullDate": "EEEE dd MMMM y",
|
||||
"fullDate": "EEEE, dd MMMM y",
|
||||
"longDate": "dd MMMM y",
|
||||
"medium": "dd MMM y h:mm:ss a",
|
||||
"mediumDate": "dd MMM y",
|
||||
|
||||
Vendored
+4
-4
@@ -40,9 +40,9 @@ $provide.value("$locale", {
|
||||
"Sa"
|
||||
],
|
||||
"SHORTMONTH": [
|
||||
"Jan",
|
||||
"Feb",
|
||||
"Mar",
|
||||
"Jan.",
|
||||
"Feb.",
|
||||
"Mrt.",
|
||||
"Apr",
|
||||
"Mei",
|
||||
"Jun",
|
||||
@@ -53,7 +53,7 @@ $provide.value("$locale", {
|
||||
"Nov",
|
||||
"Des"
|
||||
],
|
||||
"fullDate": "EEEE dd MMMM y",
|
||||
"fullDate": "EEEE, dd MMMM y",
|
||||
"longDate": "dd MMMM y",
|
||||
"medium": "dd MMM y h:mm:ss a",
|
||||
"mediumDate": "dd MMM y",
|
||||
|
||||
Vendored
+2
-2
@@ -26,7 +26,7 @@ $provide.value("$locale", {
|
||||
"\u1301\u120b\u12ed",
|
||||
"\u12a6\u1308\u1235\u1275",
|
||||
"\u1234\u1355\u1274\u121d\u1260\u122d",
|
||||
"\u12a6\u12ad\u1270\u12cd\u1260\u122d",
|
||||
"\u12a6\u12ad\u1276\u1260\u122d",
|
||||
"\u1296\u126c\u121d\u1260\u122d",
|
||||
"\u12f2\u1234\u121d\u1260\u122d"
|
||||
],
|
||||
@@ -49,7 +49,7 @@ $provide.value("$locale", {
|
||||
"\u1301\u120b\u12ed",
|
||||
"\u12a6\u1308\u1235",
|
||||
"\u1234\u1355\u1274",
|
||||
"\u12a6\u12ad\u1270",
|
||||
"\u12a6\u12ad\u1276",
|
||||
"\u1296\u126c\u121d",
|
||||
"\u12f2\u1234\u121d"
|
||||
],
|
||||
|
||||
Vendored
+2
-2
@@ -26,7 +26,7 @@ $provide.value("$locale", {
|
||||
"\u1301\u120b\u12ed",
|
||||
"\u12a6\u1308\u1235\u1275",
|
||||
"\u1234\u1355\u1274\u121d\u1260\u122d",
|
||||
"\u12a6\u12ad\u1270\u12cd\u1260\u122d",
|
||||
"\u12a6\u12ad\u1276\u1260\u122d",
|
||||
"\u1296\u126c\u121d\u1260\u122d",
|
||||
"\u12f2\u1234\u121d\u1260\u122d"
|
||||
],
|
||||
@@ -49,7 +49,7 @@ $provide.value("$locale", {
|
||||
"\u1301\u120b\u12ed",
|
||||
"\u12a6\u1308\u1235",
|
||||
"\u1234\u1355\u1274",
|
||||
"\u12a6\u12ad\u1270",
|
||||
"\u12a6\u12ad\u1276",
|
||||
"\u1296\u126c\u121d",
|
||||
"\u12f2\u1234\u121d"
|
||||
],
|
||||
|
||||
+5
-5
@@ -38,15 +38,15 @@ $provide.value("$locale", {
|
||||
"de xineru",
|
||||
"de febreru",
|
||||
"de marzu",
|
||||
"d'abril",
|
||||
"d\u2019abril",
|
||||
"de mayu",
|
||||
"de xunu",
|
||||
"de xunetu",
|
||||
"d'agostu",
|
||||
"d\u2019agostu",
|
||||
"de setiembre",
|
||||
"d'ochobre",
|
||||
"d\u2019ochobre",
|
||||
"de payares",
|
||||
"d'avientu"
|
||||
"d\u2019avientu"
|
||||
],
|
||||
"SHORTDAY": [
|
||||
"dom",
|
||||
@@ -71,7 +71,7 @@ $provide.value("$locale", {
|
||||
"pay",
|
||||
"avi"
|
||||
],
|
||||
"fullDate": "EEEE, dd MMMM 'de' y",
|
||||
"fullDate": "EEEE, d MMMM 'de' y",
|
||||
"longDate": "d MMMM 'de' y",
|
||||
"medium": "d MMM y HH:mm:ss",
|
||||
"mediumDate": "d MMM y",
|
||||
|
||||
Vendored
+5
-5
@@ -38,15 +38,15 @@ $provide.value("$locale", {
|
||||
"de xineru",
|
||||
"de febreru",
|
||||
"de marzu",
|
||||
"d'abril",
|
||||
"d\u2019abril",
|
||||
"de mayu",
|
||||
"de xunu",
|
||||
"de xunetu",
|
||||
"d'agostu",
|
||||
"d\u2019agostu",
|
||||
"de setiembre",
|
||||
"d'ochobre",
|
||||
"d\u2019ochobre",
|
||||
"de payares",
|
||||
"d'avientu"
|
||||
"d\u2019avientu"
|
||||
],
|
||||
"SHORTDAY": [
|
||||
"dom",
|
||||
@@ -71,7 +71,7 @@ $provide.value("$locale", {
|
||||
"pay",
|
||||
"avi"
|
||||
],
|
||||
"fullDate": "EEEE, dd MMMM 'de' y",
|
||||
"fullDate": "EEEE, d MMMM 'de' y",
|
||||
"longDate": "d MMMM 'de' y",
|
||||
"medium": "d MMM y HH:mm:ss",
|
||||
"mediumDate": "d MMM y",
|
||||
|
||||
+19
-19
@@ -31,27 +31,27 @@ $provide.value("$locale", {
|
||||
"\u0434\u0435\u043a\u0430\u0431\u0440"
|
||||
],
|
||||
"SHORTDAY": [
|
||||
"B.",
|
||||
"B.E.",
|
||||
"\u00c7.A.",
|
||||
"\u00c7.",
|
||||
"C.A.",
|
||||
"C",
|
||||
"\u015e."
|
||||
"\u0431\u0430\u0437\u0430\u0440",
|
||||
"\u0431\u0430\u0437\u0430\u0440 \u0435\u0440\u0442\u04d9\u0441\u0438",
|
||||
"\u0447\u04d9\u0440\u0448\u04d9\u043d\u0431\u04d9 \u0430\u0445\u0448\u0430\u043c\u044b",
|
||||
"\u0447\u04d9\u0440\u0448\u04d9\u043d\u0431\u04d9",
|
||||
"\u04b9\u04af\u043c\u04d9 \u0430\u0445\u0448\u0430\u043c\u044b",
|
||||
"\u04b9\u04af\u043c\u04d9",
|
||||
"\u0448\u04d9\u043d\u0431\u04d9"
|
||||
],
|
||||
"SHORTMONTH": [
|
||||
"yan",
|
||||
"fev",
|
||||
"mar",
|
||||
"apr",
|
||||
"may",
|
||||
"iyn",
|
||||
"iyl",
|
||||
"avq",
|
||||
"sen",
|
||||
"okt",
|
||||
"noy",
|
||||
"dek"
|
||||
"\u0458\u0430\u043d\u0432\u0430\u0440",
|
||||
"\u0444\u0435\u0432\u0440\u0430\u043b",
|
||||
"\u043c\u0430\u0440\u0442",
|
||||
"\u0430\u043f\u0440\u0435\u043b",
|
||||
"\u043c\u0430\u0439",
|
||||
"\u0438\u0458\u0443\u043d",
|
||||
"\u0438\u0458\u0443\u043b",
|
||||
"\u0430\u0432\u0433\u0443\u0441\u0442",
|
||||
"\u0441\u0435\u043d\u0442\u0458\u0430\u0431\u0440",
|
||||
"\u043e\u043a\u0442\u0458\u0430\u0431\u0440",
|
||||
"\u043d\u043e\u0458\u0430\u0431\u0440",
|
||||
"\u0434\u0435\u043a\u0430\u0431\u0440"
|
||||
],
|
||||
"fullDate": "EEEE, d, MMMM, y",
|
||||
"longDate": "d MMMM, y",
|
||||
|
||||
+19
-19
@@ -31,27 +31,27 @@ $provide.value("$locale", {
|
||||
"\u0434\u0435\u043a\u0430\u0431\u0440"
|
||||
],
|
||||
"SHORTDAY": [
|
||||
"B.",
|
||||
"B.E.",
|
||||
"\u00c7.A.",
|
||||
"\u00c7.",
|
||||
"C.A.",
|
||||
"C",
|
||||
"\u015e."
|
||||
"\u0431\u0430\u0437\u0430\u0440",
|
||||
"\u0431\u0430\u0437\u0430\u0440 \u0435\u0440\u0442\u04d9\u0441\u0438",
|
||||
"\u0447\u04d9\u0440\u0448\u04d9\u043d\u0431\u04d9 \u0430\u0445\u0448\u0430\u043c\u044b",
|
||||
"\u0447\u04d9\u0440\u0448\u04d9\u043d\u0431\u04d9",
|
||||
"\u04b9\u04af\u043c\u04d9 \u0430\u0445\u0448\u0430\u043c\u044b",
|
||||
"\u04b9\u04af\u043c\u04d9",
|
||||
"\u0448\u04d9\u043d\u0431\u04d9"
|
||||
],
|
||||
"SHORTMONTH": [
|
||||
"yan",
|
||||
"fev",
|
||||
"mar",
|
||||
"apr",
|
||||
"may",
|
||||
"iyn",
|
||||
"iyl",
|
||||
"avq",
|
||||
"sen",
|
||||
"okt",
|
||||
"noy",
|
||||
"dek"
|
||||
"\u0458\u0430\u043d\u0432\u0430\u0440",
|
||||
"\u0444\u0435\u0432\u0440\u0430\u043b",
|
||||
"\u043c\u0430\u0440\u0442",
|
||||
"\u0430\u043f\u0440\u0435\u043b",
|
||||
"\u043c\u0430\u0439",
|
||||
"\u0438\u0458\u0443\u043d",
|
||||
"\u0438\u0458\u0443\u043b",
|
||||
"\u0430\u0432\u0433\u0443\u0441\u0442",
|
||||
"\u0441\u0435\u043d\u0442\u0458\u0430\u0431\u0440",
|
||||
"\u043e\u043a\u0442\u0458\u0430\u0431\u0440",
|
||||
"\u043d\u043e\u0458\u0430\u0431\u0440",
|
||||
"\u0434\u0435\u043a\u0430\u0431\u0440"
|
||||
],
|
||||
"fullDate": "EEEE, d, MMMM, y",
|
||||
"longDate": "d MMMM, y",
|
||||
|
||||
+1
-1
@@ -36,7 +36,7 @@ $provide.value("$locale", {
|
||||
"\u00c7.A.",
|
||||
"\u00c7.",
|
||||
"C.A.",
|
||||
"C",
|
||||
"C.",
|
||||
"\u015e."
|
||||
],
|
||||
"SHORTMONTH": [
|
||||
|
||||
+1
-1
@@ -36,7 +36,7 @@ $provide.value("$locale", {
|
||||
"\u00c7.A.",
|
||||
"\u00c7.",
|
||||
"C.A.",
|
||||
"C",
|
||||
"C.",
|
||||
"\u015e."
|
||||
],
|
||||
"SHORTMONTH": [
|
||||
|
||||
Vendored
+1
-1
@@ -36,7 +36,7 @@ $provide.value("$locale", {
|
||||
"\u00c7.A.",
|
||||
"\u00c7.",
|
||||
"C.A.",
|
||||
"C",
|
||||
"C.",
|
||||
"\u015e."
|
||||
],
|
||||
"SHORTMONTH": [
|
||||
|
||||
Vendored
+2
-2
@@ -58,8 +58,8 @@ $provide.value("$locale", {
|
||||
"medium": "d.MM.y '\u0433'. H:mm:ss",
|
||||
"mediumDate": "d.MM.y '\u0433'.",
|
||||
"mediumTime": "H:mm:ss",
|
||||
"short": "d.MM.yy H:mm",
|
||||
"shortDate": "d.MM.yy",
|
||||
"short": "d.MM.yy '\u0433'. H:mm",
|
||||
"shortDate": "d.MM.yy '\u0433'.",
|
||||
"shortTime": "H:mm"
|
||||
},
|
||||
"NUMBER_FORMATS": {
|
||||
|
||||
Vendored
+2
-2
@@ -58,8 +58,8 @@ $provide.value("$locale", {
|
||||
"medium": "d.MM.y '\u0433'. H:mm:ss",
|
||||
"mediumDate": "d.MM.y '\u0433'.",
|
||||
"mediumTime": "H:mm:ss",
|
||||
"short": "d.MM.yy H:mm",
|
||||
"shortDate": "d.MM.yy",
|
||||
"short": "d.MM.yy '\u0433'. H:mm",
|
||||
"shortDate": "d.MM.yy '\u0433'.",
|
||||
"shortTime": "H:mm"
|
||||
},
|
||||
"NUMBER_FORMATS": {
|
||||
|
||||
+115
@@ -0,0 +1,115 @@
|
||||
'use strict';
|
||||
angular.module("ngLocale", [], ["$provide", function($provide) {
|
||||
var PLURAL_CATEGORY = {ZERO: "zero", ONE: "one", TWO: "two", FEW: "few", MANY: "many", OTHER: "other"};
|
||||
function getDecimals(n) {
|
||||
n = n + '';
|
||||
var i = n.indexOf('.');
|
||||
return (i == -1) ? 0 : n.length - i - 1;
|
||||
}
|
||||
|
||||
function getVF(n, opt_precision) {
|
||||
var v = opt_precision;
|
||||
|
||||
if (undefined === v) {
|
||||
v = Math.min(getDecimals(n), 3);
|
||||
}
|
||||
|
||||
var base = Math.pow(10, v);
|
||||
var f = ((n * base) | 0) % base;
|
||||
return {v: v, f: f};
|
||||
}
|
||||
|
||||
$provide.value("$locale", {
|
||||
"DATETIME_FORMATS": {
|
||||
"AMPMS": [
|
||||
"AM",
|
||||
"PM"
|
||||
],
|
||||
"DAY": [
|
||||
"kari",
|
||||
"nt\u025bn\u025b",
|
||||
"tarata",
|
||||
"araba",
|
||||
"alamisa",
|
||||
"juma",
|
||||
"sibiri"
|
||||
],
|
||||
"MONTH": [
|
||||
"zanwuye",
|
||||
"feburuye",
|
||||
"marisi",
|
||||
"awirili",
|
||||
"m\u025b",
|
||||
"zuw\u025bn",
|
||||
"zuluye",
|
||||
"uti",
|
||||
"s\u025btanburu",
|
||||
"\u0254kut\u0254buru",
|
||||
"nowanburu",
|
||||
"desanburu"
|
||||
],
|
||||
"SHORTDAY": [
|
||||
"kar",
|
||||
"nt\u025b",
|
||||
"tar",
|
||||
"ara",
|
||||
"ala",
|
||||
"jum",
|
||||
"sib"
|
||||
],
|
||||
"SHORTMONTH": [
|
||||
"zan",
|
||||
"feb",
|
||||
"mar",
|
||||
"awi",
|
||||
"m\u025b",
|
||||
"zuw",
|
||||
"zul",
|
||||
"uti",
|
||||
"s\u025bt",
|
||||
"\u0254ku",
|
||||
"now",
|
||||
"des"
|
||||
],
|
||||
"fullDate": "EEEE d MMMM y",
|
||||
"longDate": "d MMMM y",
|
||||
"medium": "d MMM, y HH:mm:ss",
|
||||
"mediumDate": "d MMM, y",
|
||||
"mediumTime": "HH:mm:ss",
|
||||
"short": "d/M/y HH:mm",
|
||||
"shortDate": "d/M/y",
|
||||
"shortTime": "HH:mm"
|
||||
},
|
||||
"NUMBER_FORMATS": {
|
||||
"CURRENCY_SYM": "CFA",
|
||||
"DECIMAL_SEP": ".",
|
||||
"GROUP_SEP": ",",
|
||||
"PATTERNS": [
|
||||
{
|
||||
"gSize": 3,
|
||||
"lgSize": 3,
|
||||
"maxFrac": 3,
|
||||
"minFrac": 0,
|
||||
"minInt": 1,
|
||||
"negPre": "-",
|
||||
"negSuf": "",
|
||||
"posPre": "",
|
||||
"posSuf": ""
|
||||
},
|
||||
{
|
||||
"gSize": 3,
|
||||
"lgSize": 3,
|
||||
"maxFrac": 2,
|
||||
"minFrac": 2,
|
||||
"minInt": 1,
|
||||
"negPre": "\u00a4-",
|
||||
"negSuf": "",
|
||||
"posPre": "\u00a4",
|
||||
"posSuf": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
"id": "bm-latn-ml",
|
||||
"pluralCat": function(n, opt_precision) { var i = n | 0; var vf = getVF(n, opt_precision); if (i == 1 && vf.v == 0) { return PLURAL_CATEGORY.ONE; } return PLURAL_CATEGORY.OTHER;}
|
||||
});
|
||||
}]);
|
||||
+115
@@ -0,0 +1,115 @@
|
||||
'use strict';
|
||||
angular.module("ngLocale", [], ["$provide", function($provide) {
|
||||
var PLURAL_CATEGORY = {ZERO: "zero", ONE: "one", TWO: "two", FEW: "few", MANY: "many", OTHER: "other"};
|
||||
function getDecimals(n) {
|
||||
n = n + '';
|
||||
var i = n.indexOf('.');
|
||||
return (i == -1) ? 0 : n.length - i - 1;
|
||||
}
|
||||
|
||||
function getVF(n, opt_precision) {
|
||||
var v = opt_precision;
|
||||
|
||||
if (undefined === v) {
|
||||
v = Math.min(getDecimals(n), 3);
|
||||
}
|
||||
|
||||
var base = Math.pow(10, v);
|
||||
var f = ((n * base) | 0) % base;
|
||||
return {v: v, f: f};
|
||||
}
|
||||
|
||||
$provide.value("$locale", {
|
||||
"DATETIME_FORMATS": {
|
||||
"AMPMS": [
|
||||
"AM",
|
||||
"PM"
|
||||
],
|
||||
"DAY": [
|
||||
"kari",
|
||||
"nt\u025bn\u025b",
|
||||
"tarata",
|
||||
"araba",
|
||||
"alamisa",
|
||||
"juma",
|
||||
"sibiri"
|
||||
],
|
||||
"MONTH": [
|
||||
"zanwuye",
|
||||
"feburuye",
|
||||
"marisi",
|
||||
"awirili",
|
||||
"m\u025b",
|
||||
"zuw\u025bn",
|
||||
"zuluye",
|
||||
"uti",
|
||||
"s\u025btanburu",
|
||||
"\u0254kut\u0254buru",
|
||||
"nowanburu",
|
||||
"desanburu"
|
||||
],
|
||||
"SHORTDAY": [
|
||||
"kar",
|
||||
"nt\u025b",
|
||||
"tar",
|
||||
"ara",
|
||||
"ala",
|
||||
"jum",
|
||||
"sib"
|
||||
],
|
||||
"SHORTMONTH": [
|
||||
"zan",
|
||||
"feb",
|
||||
"mar",
|
||||
"awi",
|
||||
"m\u025b",
|
||||
"zuw",
|
||||
"zul",
|
||||
"uti",
|
||||
"s\u025bt",
|
||||
"\u0254ku",
|
||||
"now",
|
||||
"des"
|
||||
],
|
||||
"fullDate": "EEEE d MMMM y",
|
||||
"longDate": "d MMMM y",
|
||||
"medium": "d MMM, y HH:mm:ss",
|
||||
"mediumDate": "d MMM, y",
|
||||
"mediumTime": "HH:mm:ss",
|
||||
"short": "d/M/y HH:mm",
|
||||
"shortDate": "d/M/y",
|
||||
"shortTime": "HH:mm"
|
||||
},
|
||||
"NUMBER_FORMATS": {
|
||||
"CURRENCY_SYM": "\u20ac",
|
||||
"DECIMAL_SEP": ".",
|
||||
"GROUP_SEP": ",",
|
||||
"PATTERNS": [
|
||||
{
|
||||
"gSize": 3,
|
||||
"lgSize": 3,
|
||||
"maxFrac": 3,
|
||||
"minFrac": 0,
|
||||
"minInt": 1,
|
||||
"negPre": "-",
|
||||
"negSuf": "",
|
||||
"posPre": "",
|
||||
"posSuf": ""
|
||||
},
|
||||
{
|
||||
"gSize": 3,
|
||||
"lgSize": 3,
|
||||
"maxFrac": 2,
|
||||
"minFrac": 2,
|
||||
"minInt": 1,
|
||||
"negPre": "\u00a4-",
|
||||
"negSuf": "",
|
||||
"posPre": "\u00a4",
|
||||
"posSuf": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
"id": "bm-latn",
|
||||
"pluralCat": function(n, opt_precision) { var i = n | 0; var vf = getVF(n, opt_precision); if (i == 1 && vf.v == 0) { return PLURAL_CATEGORY.ONE; } return PLURAL_CATEGORY.OTHER;}
|
||||
});
|
||||
}]);
|
||||
Vendored
+1
-1
@@ -12,7 +12,7 @@ $provide.value("$locale", {
|
||||
"\u09b8\u09cb\u09ae\u09ac\u09be\u09b0",
|
||||
"\u09ae\u0999\u09cd\u0997\u09b2\u09ac\u09be\u09b0",
|
||||
"\u09ac\u09c1\u09a7\u09ac\u09be\u09b0",
|
||||
"\u09ac\u09c3\u09b9\u09b7\u09cd\u09aa\u09a4\u09bf\u09ac\u09be\u09b0",
|
||||
"\u09ac\u09c3\u09b9\u09b8\u09cd\u09aa\u09a4\u09bf\u09ac\u09be\u09b0",
|
||||
"\u09b6\u09c1\u0995\u09cd\u09b0\u09ac\u09be\u09b0",
|
||||
"\u09b6\u09a8\u09bf\u09ac\u09be\u09b0"
|
||||
],
|
||||
|
||||
Vendored
+1
-1
@@ -12,7 +12,7 @@ $provide.value("$locale", {
|
||||
"\u09b8\u09cb\u09ae\u09ac\u09be\u09b0",
|
||||
"\u09ae\u0999\u09cd\u0997\u09b2\u09ac\u09be\u09b0",
|
||||
"\u09ac\u09c1\u09a7\u09ac\u09be\u09b0",
|
||||
"\u09ac\u09c3\u09b9\u09b7\u09cd\u09aa\u09a4\u09bf\u09ac\u09be\u09b0",
|
||||
"\u09ac\u09c3\u09b9\u09b8\u09cd\u09aa\u09a4\u09bf\u09ac\u09be\u09b0",
|
||||
"\u09b6\u09c1\u0995\u09cd\u09b0\u09ac\u09be\u09b0",
|
||||
"\u09b6\u09a8\u09bf\u09ac\u09be\u09b0"
|
||||
],
|
||||
|
||||
Vendored
+1
-1
@@ -12,7 +12,7 @@ $provide.value("$locale", {
|
||||
"\u09b8\u09cb\u09ae\u09ac\u09be\u09b0",
|
||||
"\u09ae\u0999\u09cd\u0997\u09b2\u09ac\u09be\u09b0",
|
||||
"\u09ac\u09c1\u09a7\u09ac\u09be\u09b0",
|
||||
"\u09ac\u09c3\u09b9\u09b7\u09cd\u09aa\u09a4\u09bf\u09ac\u09be\u09b0",
|
||||
"\u09ac\u09c3\u09b9\u09b8\u09cd\u09aa\u09a4\u09bf\u09ac\u09be\u09b0",
|
||||
"\u09b6\u09c1\u0995\u09cd\u09b0\u09ac\u09be\u09b0",
|
||||
"\u09b6\u09a8\u09bf\u09ac\u09be\u09b0"
|
||||
],
|
||||
|
||||
Vendored
+5
-5
@@ -29,9 +29,9 @@ $provide.value("$locale", {
|
||||
"\u0f42\u0f5f\u0f60\u0f0b\u0f49\u0f72\u0f0b\u0f58\u0f0b",
|
||||
"\u0f42\u0f5f\u0f60\u0f0b\u0f5f\u0fb3\u0f0b\u0f56\u0f0b",
|
||||
"\u0f42\u0f5f\u0f60\u0f0b\u0f58\u0f72\u0f42\u0f0b\u0f51\u0f58\u0f62\u0f0b",
|
||||
"\u0f42\u0f5f\u0f60\u0f0b\u0f67\u0fb3\u0f42\u0f0b\u0f54\u0f0b",
|
||||
"\u0f42\u0f5f\u0f60\u0f0b\u0f63\u0fb7\u0f42\u0f0b\u0f54\u0f0b",
|
||||
"\u0f42\u0f5f\u0f60\u0f0b\u0f55\u0f74\u0f62\u0f0b\u0f56\u0f74\u0f0b",
|
||||
"\u0f42\u0f5f\u0f60\u0f0b\u0f66\u0f44\u0f66\u0f0b",
|
||||
"\u0f42\u0f5f\u0f60\u0f0b\u0f54\u0f0b\u0f66\u0f44\u0f66\u0f0b",
|
||||
"\u0f42\u0f5f\u0f60\u0f0b\u0f66\u0fa4\u0f7a\u0f53\u0f0b\u0f54\u0f0b"
|
||||
],
|
||||
"MONTH": [
|
||||
@@ -52,9 +52,9 @@ $provide.value("$locale", {
|
||||
"\u0f49\u0f72\u0f0b\u0f58\u0f0b",
|
||||
"\u0f5f\u0fb3\u0f0b\u0f56\u0f0b",
|
||||
"\u0f58\u0f72\u0f42\u0f0b\u0f51\u0f58\u0f62\u0f0b",
|
||||
"\u0f67\u0fb3\u0f42\u0f0b\u0f54\u0f0b",
|
||||
"\u0f63\u0fb7\u0f42\u0f0b\u0f54\u0f0b",
|
||||
"\u0f55\u0f74\u0f62\u0f0b\u0f56\u0f74\u0f0b",
|
||||
"\u0f66\u0f44\u0f66\u0f0b",
|
||||
"\u0f54\u0f0b\u0f66\u0f44\u0f66\u0f0b",
|
||||
"\u0f66\u0fa4\u0f7a\u0f53\u0f0b\u0f54\u0f0b"
|
||||
],
|
||||
"SHORTMONTH": [
|
||||
@@ -72,7 +72,7 @@ $provide.value("$locale", {
|
||||
"\u0f5f\u0fb3\u0f0b\u0f21\u0f22"
|
||||
],
|
||||
"fullDate": "y MMMM d, EEEE",
|
||||
"longDate": "\u0f66\u0fa6\u0fb1\u0f72\u0f0b\u0f63\u0f7c\u0f0by MMMM\u0f60\u0f72\u0f0b\u0f59\u0f7a\u0f66\u0f0bd\u0f51",
|
||||
"longDate": "\u0f66\u0fa4\u0fb1\u0f72\u0f0b\u0f63\u0f7c\u0f0by MMMM\u0f60\u0f72\u0f0b\u0f59\u0f7a\u0f66\u0f0bd\u0f51",
|
||||
"medium": "y \u0f63\u0f7c\u0f0b\u0f60\u0f72\u0f0bMMM\u0f59\u0f7a\u0f66\u0f0bd HH:mm:ss",
|
||||
"mediumDate": "y \u0f63\u0f7c\u0f0b\u0f60\u0f72\u0f0bMMM\u0f59\u0f7a\u0f66\u0f0bd",
|
||||
"mediumTime": "HH:mm:ss",
|
||||
|
||||
Vendored
+5
-5
@@ -29,9 +29,9 @@ $provide.value("$locale", {
|
||||
"\u0f42\u0f5f\u0f60\u0f0b\u0f49\u0f72\u0f0b\u0f58\u0f0b",
|
||||
"\u0f42\u0f5f\u0f60\u0f0b\u0f5f\u0fb3\u0f0b\u0f56\u0f0b",
|
||||
"\u0f42\u0f5f\u0f60\u0f0b\u0f58\u0f72\u0f42\u0f0b\u0f51\u0f58\u0f62\u0f0b",
|
||||
"\u0f42\u0f5f\u0f60\u0f0b\u0f67\u0fb3\u0f42\u0f0b\u0f54\u0f0b",
|
||||
"\u0f42\u0f5f\u0f60\u0f0b\u0f63\u0fb7\u0f42\u0f0b\u0f54\u0f0b",
|
||||
"\u0f42\u0f5f\u0f60\u0f0b\u0f55\u0f74\u0f62\u0f0b\u0f56\u0f74\u0f0b",
|
||||
"\u0f42\u0f5f\u0f60\u0f0b\u0f66\u0f44\u0f66\u0f0b",
|
||||
"\u0f42\u0f5f\u0f60\u0f0b\u0f54\u0f0b\u0f66\u0f44\u0f66\u0f0b",
|
||||
"\u0f42\u0f5f\u0f60\u0f0b\u0f66\u0fa4\u0f7a\u0f53\u0f0b\u0f54\u0f0b"
|
||||
],
|
||||
"MONTH": [
|
||||
@@ -52,9 +52,9 @@ $provide.value("$locale", {
|
||||
"\u0f49\u0f72\u0f0b\u0f58\u0f0b",
|
||||
"\u0f5f\u0fb3\u0f0b\u0f56\u0f0b",
|
||||
"\u0f58\u0f72\u0f42\u0f0b\u0f51\u0f58\u0f62\u0f0b",
|
||||
"\u0f67\u0fb3\u0f42\u0f0b\u0f54\u0f0b",
|
||||
"\u0f63\u0fb7\u0f42\u0f0b\u0f54\u0f0b",
|
||||
"\u0f55\u0f74\u0f62\u0f0b\u0f56\u0f74\u0f0b",
|
||||
"\u0f66\u0f44\u0f66\u0f0b",
|
||||
"\u0f54\u0f0b\u0f66\u0f44\u0f66\u0f0b",
|
||||
"\u0f66\u0fa4\u0f7a\u0f53\u0f0b\u0f54\u0f0b"
|
||||
],
|
||||
"SHORTMONTH": [
|
||||
@@ -72,7 +72,7 @@ $provide.value("$locale", {
|
||||
"\u0f5f\u0fb3\u0f0b\u0f21\u0f22"
|
||||
],
|
||||
"fullDate": "y MMMM d, EEEE",
|
||||
"longDate": "\u0f66\u0fa6\u0fb1\u0f72\u0f0b\u0f63\u0f7c\u0f0by MMMM\u0f60\u0f72\u0f0b\u0f59\u0f7a\u0f66\u0f0bd\u0f51",
|
||||
"longDate": "\u0f66\u0fa4\u0fb1\u0f72\u0f0b\u0f63\u0f7c\u0f0by MMMM\u0f60\u0f72\u0f0b\u0f59\u0f7a\u0f66\u0f0bd\u0f51",
|
||||
"medium": "y \u0f63\u0f7c\u0f0b\u0f60\u0f72\u0f0bMMM\u0f59\u0f7a\u0f66\u0f0bd HH:mm:ss",
|
||||
"mediumDate": "y \u0f63\u0f7c\u0f0b\u0f60\u0f72\u0f0bMMM\u0f59\u0f7a\u0f66\u0f0bd",
|
||||
"mediumTime": "HH:mm:ss",
|
||||
|
||||
Vendored
+5
-5
@@ -29,9 +29,9 @@ $provide.value("$locale", {
|
||||
"\u0f42\u0f5f\u0f60\u0f0b\u0f49\u0f72\u0f0b\u0f58\u0f0b",
|
||||
"\u0f42\u0f5f\u0f60\u0f0b\u0f5f\u0fb3\u0f0b\u0f56\u0f0b",
|
||||
"\u0f42\u0f5f\u0f60\u0f0b\u0f58\u0f72\u0f42\u0f0b\u0f51\u0f58\u0f62\u0f0b",
|
||||
"\u0f42\u0f5f\u0f60\u0f0b\u0f67\u0fb3\u0f42\u0f0b\u0f54\u0f0b",
|
||||
"\u0f42\u0f5f\u0f60\u0f0b\u0f63\u0fb7\u0f42\u0f0b\u0f54\u0f0b",
|
||||
"\u0f42\u0f5f\u0f60\u0f0b\u0f55\u0f74\u0f62\u0f0b\u0f56\u0f74\u0f0b",
|
||||
"\u0f42\u0f5f\u0f60\u0f0b\u0f66\u0f44\u0f66\u0f0b",
|
||||
"\u0f42\u0f5f\u0f60\u0f0b\u0f54\u0f0b\u0f66\u0f44\u0f66\u0f0b",
|
||||
"\u0f42\u0f5f\u0f60\u0f0b\u0f66\u0fa4\u0f7a\u0f53\u0f0b\u0f54\u0f0b"
|
||||
],
|
||||
"MONTH": [
|
||||
@@ -52,9 +52,9 @@ $provide.value("$locale", {
|
||||
"\u0f49\u0f72\u0f0b\u0f58\u0f0b",
|
||||
"\u0f5f\u0fb3\u0f0b\u0f56\u0f0b",
|
||||
"\u0f58\u0f72\u0f42\u0f0b\u0f51\u0f58\u0f62\u0f0b",
|
||||
"\u0f67\u0fb3\u0f42\u0f0b\u0f54\u0f0b",
|
||||
"\u0f63\u0fb7\u0f42\u0f0b\u0f54\u0f0b",
|
||||
"\u0f55\u0f74\u0f62\u0f0b\u0f56\u0f74\u0f0b",
|
||||
"\u0f66\u0f44\u0f66\u0f0b",
|
||||
"\u0f54\u0f0b\u0f66\u0f44\u0f66\u0f0b",
|
||||
"\u0f66\u0fa4\u0f7a\u0f53\u0f0b\u0f54\u0f0b"
|
||||
],
|
||||
"SHORTMONTH": [
|
||||
@@ -72,7 +72,7 @@ $provide.value("$locale", {
|
||||
"\u0f5f\u0fb3\u0f0b\u0f21\u0f22"
|
||||
],
|
||||
"fullDate": "y MMMM d, EEEE",
|
||||
"longDate": "\u0f66\u0fa6\u0fb1\u0f72\u0f0b\u0f63\u0f7c\u0f0by MMMM\u0f60\u0f72\u0f0b\u0f59\u0f7a\u0f66\u0f0bd\u0f51",
|
||||
"longDate": "\u0f66\u0fa4\u0fb1\u0f72\u0f0b\u0f63\u0f7c\u0f0by MMMM\u0f60\u0f72\u0f0b\u0f59\u0f7a\u0f66\u0f0bd\u0f51",
|
||||
"medium": "y \u0f63\u0f7c\u0f0b\u0f60\u0f72\u0f0bMMM\u0f59\u0f7a\u0f66\u0f0bd HH:mm:ss",
|
||||
"mediumDate": "y \u0f63\u0f7c\u0f0b\u0f60\u0f72\u0f0bMMM\u0f59\u0f7a\u0f66\u0f0bd",
|
||||
"mediumTime": "HH:mm:ss",
|
||||
|
||||
Vendored
+13
-13
@@ -4,8 +4,8 @@ var PLURAL_CATEGORY = {ZERO: "zero", ONE: "one", TWO: "two", FEW: "few", MANY: "
|
||||
$provide.value("$locale", {
|
||||
"DATETIME_FORMATS": {
|
||||
"AMPMS": [
|
||||
"AM",
|
||||
"PM"
|
||||
"A.M.",
|
||||
"G.M."
|
||||
],
|
||||
"DAY": [
|
||||
"Sul",
|
||||
@@ -31,13 +31,13 @@ $provide.value("$locale", {
|
||||
"Kerzu"
|
||||
],
|
||||
"SHORTDAY": [
|
||||
"sul",
|
||||
"lun",
|
||||
"meu.",
|
||||
"mer.",
|
||||
"yaou",
|
||||
"gwe.",
|
||||
"sad."
|
||||
"Sul",
|
||||
"Lun",
|
||||
"Meu.",
|
||||
"Mer.",
|
||||
"Yaou",
|
||||
"Gwe.",
|
||||
"Sad."
|
||||
],
|
||||
"SHORTMONTH": [
|
||||
"Gen",
|
||||
@@ -84,10 +84,10 @@ $provide.value("$locale", {
|
||||
"maxFrac": 2,
|
||||
"minFrac": 2,
|
||||
"minInt": 1,
|
||||
"negPre": "\u00a4\u00a0-",
|
||||
"negSuf": "",
|
||||
"posPre": "\u00a4\u00a0",
|
||||
"posSuf": ""
|
||||
"negPre": "-",
|
||||
"negSuf": "\u00a0\u00a4",
|
||||
"posPre": "",
|
||||
"posSuf": "\u00a0\u00a4"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
Vendored
+13
-13
@@ -4,8 +4,8 @@ var PLURAL_CATEGORY = {ZERO: "zero", ONE: "one", TWO: "two", FEW: "few", MANY: "
|
||||
$provide.value("$locale", {
|
||||
"DATETIME_FORMATS": {
|
||||
"AMPMS": [
|
||||
"AM",
|
||||
"PM"
|
||||
"A.M.",
|
||||
"G.M."
|
||||
],
|
||||
"DAY": [
|
||||
"Sul",
|
||||
@@ -31,13 +31,13 @@ $provide.value("$locale", {
|
||||
"Kerzu"
|
||||
],
|
||||
"SHORTDAY": [
|
||||
"sul",
|
||||
"lun",
|
||||
"meu.",
|
||||
"mer.",
|
||||
"yaou",
|
||||
"gwe.",
|
||||
"sad."
|
||||
"Sul",
|
||||
"Lun",
|
||||
"Meu.",
|
||||
"Mer.",
|
||||
"Yaou",
|
||||
"Gwe.",
|
||||
"Sad."
|
||||
],
|
||||
"SHORTMONTH": [
|
||||
"Gen",
|
||||
@@ -84,10 +84,10 @@ $provide.value("$locale", {
|
||||
"maxFrac": 2,
|
||||
"minFrac": 2,
|
||||
"minInt": 1,
|
||||
"negPre": "\u00a4\u00a0-",
|
||||
"negSuf": "",
|
||||
"posPre": "\u00a4\u00a0",
|
||||
"posSuf": ""
|
||||
"negPre": "-",
|
||||
"negSuf": "\u00a0\u00a4",
|
||||
"posPre": "",
|
||||
"posSuf": "\u00a0\u00a4"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
+9
-9
@@ -22,7 +22,7 @@ function getVF(n, opt_precision) {
|
||||
$provide.value("$locale", {
|
||||
"DATETIME_FORMATS": {
|
||||
"AMPMS": [
|
||||
"pre podne",
|
||||
"prije podne",
|
||||
"popodne"
|
||||
],
|
||||
"DAY": [
|
||||
@@ -42,7 +42,7 @@ $provide.value("$locale", {
|
||||
"maj",
|
||||
"juni",
|
||||
"juli",
|
||||
"avgust",
|
||||
"august",
|
||||
"septembar",
|
||||
"oktobar",
|
||||
"novembar",
|
||||
@@ -65,7 +65,7 @@ $provide.value("$locale", {
|
||||
"maj",
|
||||
"jun",
|
||||
"jul",
|
||||
"avg",
|
||||
"aug",
|
||||
"sep",
|
||||
"okt",
|
||||
"nov",
|
||||
@@ -73,8 +73,8 @@ $provide.value("$locale", {
|
||||
],
|
||||
"fullDate": "EEEE, dd. MMMM y.",
|
||||
"longDate": "dd. MMMM y.",
|
||||
"medium": "dd.MM.y. HH:mm:ss",
|
||||
"mediumDate": "dd.MM.y.",
|
||||
"medium": "dd. MMM. y. HH:mm:ss",
|
||||
"mediumDate": "dd. MMM. y.",
|
||||
"mediumTime": "HH:mm:ss",
|
||||
"short": "dd.MM.yy. HH:mm",
|
||||
"shortDate": "dd.MM.yy.",
|
||||
@@ -102,10 +102,10 @@ $provide.value("$locale", {
|
||||
"maxFrac": 2,
|
||||
"minFrac": 2,
|
||||
"minInt": 1,
|
||||
"negPre": "\u00a4\u00a0-",
|
||||
"negSuf": "",
|
||||
"posPre": "\u00a4\u00a0",
|
||||
"posSuf": ""
|
||||
"negPre": "-",
|
||||
"negSuf": "\u00a0\u00a4",
|
||||
"posPre": "",
|
||||
"posSuf": "\u00a0\u00a4"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
+9
-9
@@ -22,7 +22,7 @@ function getVF(n, opt_precision) {
|
||||
$provide.value("$locale", {
|
||||
"DATETIME_FORMATS": {
|
||||
"AMPMS": [
|
||||
"pre podne",
|
||||
"prije podne",
|
||||
"popodne"
|
||||
],
|
||||
"DAY": [
|
||||
@@ -42,7 +42,7 @@ $provide.value("$locale", {
|
||||
"maj",
|
||||
"juni",
|
||||
"juli",
|
||||
"avgust",
|
||||
"august",
|
||||
"septembar",
|
||||
"oktobar",
|
||||
"novembar",
|
||||
@@ -65,7 +65,7 @@ $provide.value("$locale", {
|
||||
"maj",
|
||||
"jun",
|
||||
"jul",
|
||||
"avg",
|
||||
"aug",
|
||||
"sep",
|
||||
"okt",
|
||||
"nov",
|
||||
@@ -73,8 +73,8 @@ $provide.value("$locale", {
|
||||
],
|
||||
"fullDate": "EEEE, dd. MMMM y.",
|
||||
"longDate": "dd. MMMM y.",
|
||||
"medium": "dd.MM.y. HH:mm:ss",
|
||||
"mediumDate": "dd.MM.y.",
|
||||
"medium": "dd. MMM. y. HH:mm:ss",
|
||||
"mediumDate": "dd. MMM. y.",
|
||||
"mediumTime": "HH:mm:ss",
|
||||
"short": "dd.MM.yy. HH:mm",
|
||||
"shortDate": "dd.MM.yy.",
|
||||
@@ -102,10 +102,10 @@ $provide.value("$locale", {
|
||||
"maxFrac": 2,
|
||||
"minFrac": 2,
|
||||
"minInt": 1,
|
||||
"negPre": "\u00a4\u00a0-",
|
||||
"negSuf": "",
|
||||
"posPre": "\u00a4\u00a0",
|
||||
"posSuf": ""
|
||||
"negPre": "-",
|
||||
"negSuf": "\u00a0\u00a4",
|
||||
"posPre": "",
|
||||
"posSuf": "\u00a0\u00a4"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
Vendored
+9
-9
@@ -22,7 +22,7 @@ function getVF(n, opt_precision) {
|
||||
$provide.value("$locale", {
|
||||
"DATETIME_FORMATS": {
|
||||
"AMPMS": [
|
||||
"pre podne",
|
||||
"prije podne",
|
||||
"popodne"
|
||||
],
|
||||
"DAY": [
|
||||
@@ -42,7 +42,7 @@ $provide.value("$locale", {
|
||||
"maj",
|
||||
"juni",
|
||||
"juli",
|
||||
"avgust",
|
||||
"august",
|
||||
"septembar",
|
||||
"oktobar",
|
||||
"novembar",
|
||||
@@ -65,7 +65,7 @@ $provide.value("$locale", {
|
||||
"maj",
|
||||
"jun",
|
||||
"jul",
|
||||
"avg",
|
||||
"aug",
|
||||
"sep",
|
||||
"okt",
|
||||
"nov",
|
||||
@@ -73,8 +73,8 @@ $provide.value("$locale", {
|
||||
],
|
||||
"fullDate": "EEEE, dd. MMMM y.",
|
||||
"longDate": "dd. MMMM y.",
|
||||
"medium": "dd.MM.y. HH:mm:ss",
|
||||
"mediumDate": "dd.MM.y.",
|
||||
"medium": "dd. MMM. y. HH:mm:ss",
|
||||
"mediumDate": "dd. MMM. y.",
|
||||
"mediumTime": "HH:mm:ss",
|
||||
"short": "dd.MM.yy. HH:mm",
|
||||
"shortDate": "dd.MM.yy.",
|
||||
@@ -102,10 +102,10 @@ $provide.value("$locale", {
|
||||
"maxFrac": 2,
|
||||
"minFrac": 2,
|
||||
"minInt": 1,
|
||||
"negPre": "\u00a4\u00a0-",
|
||||
"negSuf": "",
|
||||
"posPre": "\u00a4\u00a0",
|
||||
"posSuf": ""
|
||||
"negPre": "-",
|
||||
"negSuf": "\u00a0\u00a4",
|
||||
"posPre": "",
|
||||
"posSuf": "\u00a0\u00a4"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
Vendored
+3
-3
@@ -59,7 +59,7 @@ $provide.value("$locale", {
|
||||
],
|
||||
"SHORTMONTH": [
|
||||
"gen.",
|
||||
"feb.",
|
||||
"febr.",
|
||||
"mar\u00e7",
|
||||
"abr.",
|
||||
"maig",
|
||||
@@ -73,8 +73,8 @@ $provide.value("$locale", {
|
||||
],
|
||||
"fullDate": "EEEE, d MMMM 'de' y",
|
||||
"longDate": "d MMMM 'de' y",
|
||||
"medium": "dd/MM/y H:mm:ss",
|
||||
"mediumDate": "dd/MM/y",
|
||||
"medium": "d MMM y H:mm:ss",
|
||||
"mediumDate": "d MMM y",
|
||||
"mediumTime": "H:mm:ss",
|
||||
"short": "d/M/yy H:mm",
|
||||
"shortDate": "d/M/yy",
|
||||
|
||||
+3
-3
@@ -59,7 +59,7 @@ $provide.value("$locale", {
|
||||
],
|
||||
"SHORTMONTH": [
|
||||
"gen.",
|
||||
"feb.",
|
||||
"febr.",
|
||||
"mar\u00e7",
|
||||
"abr.",
|
||||
"maig",
|
||||
@@ -73,8 +73,8 @@ $provide.value("$locale", {
|
||||
],
|
||||
"fullDate": "EEEE, d MMMM 'de' y",
|
||||
"longDate": "d MMMM 'de' y",
|
||||
"medium": "dd/MM/y H:mm:ss",
|
||||
"mediumDate": "dd/MM/y",
|
||||
"medium": "d MMM y H:mm:ss",
|
||||
"mediumDate": "d MMM y",
|
||||
"mediumTime": "H:mm:ss",
|
||||
"short": "d/M/yy H:mm",
|
||||
"shortDate": "d/M/yy",
|
||||
|
||||
Vendored
+3
-3
@@ -59,7 +59,7 @@ $provide.value("$locale", {
|
||||
],
|
||||
"SHORTMONTH": [
|
||||
"gen.",
|
||||
"feb.",
|
||||
"febr.",
|
||||
"mar\u00e7",
|
||||
"abr.",
|
||||
"maig",
|
||||
@@ -73,8 +73,8 @@ $provide.value("$locale", {
|
||||
],
|
||||
"fullDate": "EEEE, d MMMM 'de' y",
|
||||
"longDate": "d MMMM 'de' y",
|
||||
"medium": "dd/MM/y H:mm:ss",
|
||||
"mediumDate": "dd/MM/y",
|
||||
"medium": "d MMM y H:mm:ss",
|
||||
"mediumDate": "d MMM y",
|
||||
"mediumTime": "H:mm:ss",
|
||||
"short": "d/M/yy H:mm",
|
||||
"shortDate": "d/M/yy",
|
||||
|
||||
Vendored
+3
-3
@@ -59,7 +59,7 @@ $provide.value("$locale", {
|
||||
],
|
||||
"SHORTMONTH": [
|
||||
"gen.",
|
||||
"feb.",
|
||||
"febr.",
|
||||
"mar\u00e7",
|
||||
"abr.",
|
||||
"maig",
|
||||
@@ -73,8 +73,8 @@ $provide.value("$locale", {
|
||||
],
|
||||
"fullDate": "EEEE, d MMMM 'de' y",
|
||||
"longDate": "d MMMM 'de' y",
|
||||
"medium": "dd/MM/y H:mm:ss",
|
||||
"mediumDate": "dd/MM/y",
|
||||
"medium": "d MMM y H:mm:ss",
|
||||
"mediumDate": "d MMM y",
|
||||
"mediumTime": "H:mm:ss",
|
||||
"short": "d/M/yy H:mm",
|
||||
"shortDate": "d/M/yy",
|
||||
|
||||
Vendored
+3
-3
@@ -59,7 +59,7 @@ $provide.value("$locale", {
|
||||
],
|
||||
"SHORTMONTH": [
|
||||
"gen.",
|
||||
"feb.",
|
||||
"febr.",
|
||||
"mar\u00e7",
|
||||
"abr.",
|
||||
"maig",
|
||||
@@ -73,8 +73,8 @@ $provide.value("$locale", {
|
||||
],
|
||||
"fullDate": "EEEE, d MMMM 'de' y",
|
||||
"longDate": "d MMMM 'de' y",
|
||||
"medium": "dd/MM/y H:mm:ss",
|
||||
"mediumDate": "dd/MM/y",
|
||||
"medium": "d MMM y H:mm:ss",
|
||||
"mediumDate": "d MMM y",
|
||||
"mediumTime": "H:mm:ss",
|
||||
"short": "d/M/yy H:mm",
|
||||
"shortDate": "d/M/yy",
|
||||
|
||||
Vendored
+3
-3
@@ -59,7 +59,7 @@ $provide.value("$locale", {
|
||||
],
|
||||
"SHORTMONTH": [
|
||||
"gen.",
|
||||
"feb.",
|
||||
"febr.",
|
||||
"mar\u00e7",
|
||||
"abr.",
|
||||
"maig",
|
||||
@@ -73,8 +73,8 @@ $provide.value("$locale", {
|
||||
],
|
||||
"fullDate": "EEEE, d MMMM 'de' y",
|
||||
"longDate": "d MMMM 'de' y",
|
||||
"medium": "dd/MM/y H:mm:ss",
|
||||
"mediumDate": "dd/MM/y",
|
||||
"medium": "d MMM y H:mm:ss",
|
||||
"mediumDate": "d MMM y",
|
||||
"mediumTime": "H:mm:ss",
|
||||
"short": "d/M/yy H:mm",
|
||||
"shortDate": "d/M/yy",
|
||||
|
||||
Vendored
+2
-2
@@ -58,8 +58,8 @@ $provide.value("$locale", {
|
||||
"medium": "d MMM y HH:mm:ss",
|
||||
"mediumDate": "d MMM y",
|
||||
"mediumTime": "HH:mm:ss",
|
||||
"short": "dd/MM/y HH:mm",
|
||||
"shortDate": "dd/MM/y",
|
||||
"short": "dd/MM/yy HH:mm",
|
||||
"shortDate": "dd/MM/yy",
|
||||
"shortTime": "HH:mm"
|
||||
},
|
||||
"NUMBER_FORMATS": {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user