Compare commits

...

65 Commits

Author SHA1 Message Date
Peter Bacon Darwin 19a0c9324c chore(jenkins): do not publish to code.angularjs.org snapshot
While the firewall continues to block the update ports
we will not try to publish there. This will be fixed when we move to hosting
the sites on Firebase.

This means that successful builds on master will not automatically update
code.angularjs.org, this will affect:

* https://code.angularjs.org/snapshot, which people often use to check latest features
* https://docs.angularjs.org, which is supposed to display the docs for the latest master

As it turns out we can manually partially trigger an update by browsing to
https://code.angularjs.org/gitFetchSite.php but we just can’t guarantee that we will update
both the round robin servers.
2017-07-03 22:34:52 +03:00
Georgios Kalpakas 9ef02e72ab docs(changelog): add release notes for 1.6.5 2017-07-03 15:19:52 +03:00
ksvitkovsky 2101126ce7 feat($compile): overload .component() to accept object map of components
Register multiple components with single call as it is possible with other module units.

Closes #14579 
Closes #16062
2017-07-03 11:10:07 +02:00
Jason Bedard a222d0b452 fix($timeout/$interval): do not trigger a digest on cancel
Previously, `.catch(noop)` was used on a rejected timeout/interval to prevent an unhandled rejection error (introduced in #c9dffde1cb). However this would schedule a deferred task to run the `noop`. If the cancelling was outside a digest this could cause a new digest such as with the ng-model `debounce` option.

For unit testing, this means that it's no longer necessary to use `$timeout.flush()` when a `$timeout` has been cancelled outside of a digest. Previously, this was necessary to execute the deferred task added by `.catch(noop).
There's an example of such a change in this commit's changeset in the file `/test/ngAnimate/animateCssSpec.js`.

Fixes #16057
Closes #16064
2017-07-03 11:10:00 +02:00
davesidious 1b8eb231c9 docs($log): add note about blackboxing
Add browser-agnostic hint about blackboxing and the benefits it brings developers when using $log.

Closes #15592
2017-06-30 12:04:21 +02:00
Martin Staffa 06baf1869b docs($rootScope.Scope): clarify $watchGroup "oldValues" argument
This should help to prevent issues such as #8671, #12452, #16004.

Note that the behavior will change in 1.7 (see https://github.com/angular/angular.js/pull/15854)

Closes #12643
Closes #16005
2017-06-29 18:18:32 +02:00
Martin Staffa 82597fc12b test(ngOptions): ensure options are only painted once on compile 2017-06-29 10:54:57 +02:00
Pol Bonastre ff52b188a7 perf(ngOptions): prevent initial options repainting
Avoid double execution of `updateOptions()` method,
which causes a complete repainting of all `<option>` elements.

Fixes #15801
Closes #15812
Close #16071
2017-06-29 10:54:53 +02:00
Martin Staffa dc41f465ba fix(Angular): deprecate angular.merge
This function has problems with special object types but since it's not used in core,
it is not worth implementing fixes for these cases.
A general purpose library like lodash (provides `merge`) should be used instead.

Closes #12653
Closes #14941
Closes #15180
Closes #15992
Closes #16036
2017-06-29 10:53:40 +02:00
Jason Bedard 6e3b5a57cd fix($parse): do not shallow-watch inputs to one-time intercepted expressions 2017-06-19 21:27:31 -07:00
Jason Bedard f003d93a3d Revert "fix($parse): standardize one-time literal vs non-literal and interceptors"
This reverts commit 60394a9d91.
2017-06-19 19:20:43 -07:00
Jason Bedard aac5623247 fix($parse): do not shallow-watch inputs when wrapped in an interceptor fn
Fixes #15905
2017-06-12 21:32:14 -07:00
Saurav Bhattacharya aa03812fd0 docs(external-resources.ngdoc): fix broken link
Closes #16042
2017-06-12 15:04:15 +03:00
Georgios Kalpakas bcb6a494de test(ngMock): fix Firefox craches on Travis
This test keeps causing Firefox 47 (currently used on Travis) to crash and fail
the build. The test passes locally (on Firefox 53). Lowering the loop count from
1000 to 100 seems to fix the issue.
(Note: The crach only affects the mocked implementation of `$interval` and does
not happen locally.)

Closes #16040
2017-06-12 14:45:27 +03:00
Lucio Martinez a1e3f8728e fix(ngMock/$interval): add support for zero-delay intervals in tests
Previously, trying to test code thaat contained zero-delay intervals (e.g.
`$interval(fn, 0)` or `$interval(fn)`) would result in an infinite loop.
This commit avoids the infinite loop, by treating zero-delay intervals as one
second intervals (except for the initial trigger, where they can also be
executed with `$interval.flush(0)`).

Fixes #15952

Closes #15953
2017-06-06 13:36:08 +03:00
Georgios Kalpakas 9e8e3e187d chore(i18n): update CLDR to v30.0.1
Fixes #15976

Closes #15997
2017-06-06 13:17:08 +03:00
Georgios Kalpakas c6554433cf chore(i18n): fix parser for currency patterns without fraction digits
Previously, it was assumed that all currency pattern would have fraction digits.
However, in [closure-library@b9155d5][1] the `agq_CM` locale was modified to
have such a pattern (namely `#,##0\u00A4`).
This commit modifies the parser implementation to account for pattern without a
decimal point (and thus no fraction digits).

[1]: https://github.com/google/closure-library/commit/b9155d5966a228cb33f367c30c275c833b30e3ff#diff-02793124214ad0470ccea6f86b90d786R711
2017-06-06 13:17:07 +03:00
Georgios Kalpakas 43d2a75f4e chore(i18n): fix relative paths in scripts 2017-06-06 13:17:07 +03:00
Georgios Kalpakas 37d2b50812 test(i18n): remove bad assertion 2017-06-06 13:17:06 +03:00
Peter Bacon Darwin 8f31f1ff43 fix($sanitize): use appropriate inert document strategy for Firefox and Safari
Both Firefox and Safari are vulnerable to XSS if we use an inert document
created via `document.implementation.createHTMLDocument()`.

Now we check for those vulnerabilities and then use a DOMParser or XHR
strategy if needed.

Thanks to @cure53 for the heads up on this issue.
2017-06-05 21:03:55 +01:00
Michał Gołębiowski cf84fcf544 chore(package.json): backport package.json/yarn.lock changes from master 2017-06-05 11:33:28 +02:00
Michał Gołębiowski f63bc3cfde test(support): verify support tests results in all tested browsers (#16008)
Closes #16008
2017-05-30 20:21:15 +02:00
Jason Bedard a77943110e test($parse): reorganize $parse tests 2017-05-24 21:49:21 -07:00
Jason Bedard ec97686f2f fix($parse): always re-evaluate filters within literals when an input is an object
Fixes #15964
Closes #15990
2017-05-24 21:49:12 -07:00
Michał Gołębiowski 4ff7b7aa48 chore(testabilityPatch): fix a typo 2017-05-24 10:25:37 +02:00
Michał Gołębiowski 57b837bd5c test($log): run all $log tests in IE9 & non-IE9 logging mode (#15995)
In IE 9 console methods don't inherit from Function.prototype and, hence, don't
have apply. Until recently IE 9 logging in AngularJS was restricted to the
first 2 parameters but that changed as we could just reuse
Function.prototype.apply everywhere, creating one code path for all browsers.
Therefore, we can now run all tests in modes where apply exists on logging
methods and where it doesn't.

Ref #15911
Ref b277e3ead7
Closes #15995
2017-05-24 10:15:21 +02:00
Thomas Grainger 6daca023e4 fix(*): correctly detect Error instances from different contexts
Previously, errors thrown from different contexts (such as an iframe or
webworker) were not detected as `Error` instances and handled accordingly.
This commit fixes it by introducing an `isError()` helper, that is able to
correctly detect such instances.

Fixes #15868

Closes #15872
2017-05-22 14:09:52 +03:00
Sercan Eraslan 91b4eb0f69 docs(guide/component): remove redundant empty controller from example
There is no need for empty controller functions on components, since this is the
default.

Closes #16003
2017-05-22 11:51:40 +03:00
BobChao87 e50ed4da9e fix(orderBy): guarantee stable sort
If a user-provided comparator fails to differentiate between two items, fall
back to the built-in comparator (using the tie-breaker predicate).

Fixes #14881

Closes #15914
2017-05-19 14:41:41 +03:00
Georgios Kalpakas fe5dd1da8f docs(*): fix dangling links
Closes #15984
2017-05-12 18:13:10 +03:00
Georgios Kalpakas df4c03fa33 docs(form): improve the docs for FormController.$setValidity()
Fixes #15963
2017-05-12 18:13:10 +03:00
tsclaus 8d4e626326 docs(ngRepeat): fix argument name in comment to match actual argument (element --> clone)
Closes #15975
2017-05-11 11:41:28 +03:00
Jake Danforth 92aef5d456 docs(error/badrestrict): fix typo (of --> or)
Closes #15979
2017-05-11 11:35:51 +03:00
Michał Gołębiowski eed13cf732 test(*): run class-related tests everywhere; fix eval syntax
1. Wrap an evaled class definition in parens; previously they weren't; the test
   wasn't failing only because it was disabled everywhere outside of Chrome
   and Chrome <59 incorrectly accepted such input.
2. There's no reason to restrict class-related tests just to Chrome; now they
   run in every browser that supports ES6 classes. The classes support test
   was modified to check not only if a class definition parses but also if
   it stringifies correctly which is required by AngularJS. This restriction
   disables class-related tests in current Firefox (53) but will work in v55
   or newer.

Closes #15967
2017-05-09 15:12:00 +02:00
musclor e90200b4de docs(guide/component): remove redundant unit test
Fixes #15968
Closes #15974
2017-05-09 10:20:07 +03:00
Michał Gołębiowski 7f36ba77a0 chore(*): update all Karma-related packages except Karma
The updated karma-chrome-launcher adds support for ChromeHeadless &
ChromeCanaryHeadless launchers; test with:

    karma start karma-jqlite.conf.js --browsers=ChromeCanaryHeadless

The updated karma-firefox-launcher disables multi-process which may increase
stability on Jenkins.

Closes #15966
2017-05-06 17:52:19 +02:00
Valentin 457c58827b docs(guide/templates): add missing closing <script> tag
Closes #15961
2017-05-04 14:20:34 +03:00
Leonardo Souza aae768611f docs(guide/interpolation): fix typo in markdown (code highlight)
Closes #15935
2017-05-02 15:42:32 +03:00
Georgios Kalpakas ce5ffbf667 perf(animate): avoid unnecessary computations if animations are globally disabled
Closes #14914
2017-05-02 15:39:44 +03:00
Georgios Kalpakas ab114af850 feat($animate): add support for customFilter
This commit adds a new `customFilter()` function on `$animateProvider` (similar
to `classNameFilter()`), which can be used to filter animations (i.e. decide
whether they are allowed or not), based on the return value of a custom filter
function.
This allows to easily create arbitrarily complex rules for filtering animations,
such as allowing specific events only, or enabling animations on specific
subtrees of the DOM, etc.

Fixes #14891
2017-05-02 15:39:11 +03:00
Georgios Kalpakas 2759788737 perf($animate): do not retrieve className unless classNameFilter is used 2017-05-02 15:38:27 +03:00
Georgios Kalpakas c643323c17 docs(guide/animations): list missing animated directives (and other improvements)
- List missing animation-aware directives.
- Fix/Improve wording/formatting.
- Fix typos.
- Limit lines to 100 chars.
2017-05-02 15:38:04 +03:00
Dimitri Tarasiuk 9b97a033b0 docs($q): fix typo in qFactory documentation
Closes #15946
2017-04-28 12:22:00 +03:00
Georgios Kalpakas a3226d01fa fix(angular-loader): do not depend on "closure" globals that may not be available
Code that is distributed as part of both `angular.js` and `angular-loader.js`
should not depend on "closure" globals that may not be available in
`angular-loader`.

Fixes #15880

Closes #15881
2017-04-27 22:47:11 +03:00
Martin Staffa 510d0f946f fix(ngOptions): re-render after empty option has been removed 2017-04-27 21:40:59 +02:00
Martin Staffa 0b962d4881 feat(select): expose info about selection state in controller
This allows custom directives to manipulate the select's and
ngModel's behavior based on the state of the unknown and
the empty option.

Closes #13172
Closes #10127
2017-04-27 21:40:59 +02:00
Pol Bonastre 71b4daa4e1 fix(ngOptions): allow empty option to be removed and re-added
This bug was reported as part of angular/angular.js#15801
2017-04-27 21:40:58 +02:00
Martin Staffa e0b02a5040 docs(select): add known issue about Firefox selection behavior
Related to #9134
2017-04-27 21:40:58 +02:00
Martin Staffa a0dd9b0fdd refactor(select, ngOptions): extract common methods; make consistent 2017-04-27 21:40:32 +02:00
Martin Staffa 498bef199a chore(matchers): improve output for toBeMarkedAsSelected 2017-04-27 21:40:32 +02:00
Martin Staffa 17d34b7a98 fix(ngOptions): select unknown option if unmatched model does not match empty option
When a regular / ngOptions select has an explicit *empty* option, this option can be selected
by the user and will set the model to `null`. It is also selected when the model is set to
`null` or `undefined`.

When the model is set to a value that does not match any option value, and is also not
`null` or `undefined`, the *unknown* option is inserted and selected - this is an explicit marker
that the select is in an invalid / unknown state, which is different from an allowed empty state.

Previously, regular selects followed this logic, whereas ngOptions selects selected the empty
option in the case described above.

This patch makes the behavior consistent between regular / ngOptions select - the latter will now
insert and select the unknown option. The order of the options has been fixed to unknown -> empty
-> actual options.
2017-04-27 21:40:32 +02:00
Martin Staffa 72359fd097 test(select, ngOptions): add more tests for "required" with "empty" or "unknown" option 2017-04-27 21:40:32 +02:00
Georgios Kalpakas 72882190f2 chore(docs-app): fix vertical scrolling offset after recent re-design
Previously, the `yOffset` pointed to the `<header>` element, which had a height
of 0 (since all its children have fixed positions). This caused scrolled items
to have 0 vertical offset, essentially hiding the top part behind the static
`<nav>` items.
This commit fixes the vertical scrolling offset, by setting `yOffset` to the
last (lowest) `<nav>` item.

Closes #15945
2017-04-27 19:40:08 +03:00
Michał Gołębiowski fd2d8a5755 chore(*): make package.json & yarn.lock identical to master 2017-04-25 22:11:37 +02:00
Michał Gołębiowski fbe84f95a1 chore(browserstack): Update browserstacktunnel-wrapper, fix options
Only the latest version of the package works correctly (the backend for it at
BrowserStack is not versioned) and the options have changed in the new version
of the package.

Also, iOS 8.0 is no longer available on BrowserStack, only 8.3 is. Instead,
this commit changes it to 9.3 as we shouldn't be testing on 8 anymore anyway.

(a late cherry-pick of ad0bb83819)

Closes #15892
2017-04-25 21:46:01 +02:00
Michał Gołębiowski 3671a43be4 feat($log): log all parameters in IE 9, not just the first two.
IE 9 lacks apply on console methods but it's possible to borrow the apply
method from Function.prototype.
2017-04-25 21:38:30 +02:00
Michał Gołębiowski f6a1ad528d refactor(*): remove workarounds for IE <9, update IE/Edge-related comments 2017-04-25 21:34:26 +02:00
Jacob Hansson d9128e7b23 feat(ngMock): describe unflushed http requests
The current implementation of $httpBackend.verifyNoOutstandingRequest
gives an integer number describing how many requests are unflushed.

While it's superficially easy to solve test errors from that message
by simply adding an additional $httpBackend.flush(), if a developer
is truly not expecting the code to make further requests this is
not ideal.

This change explicitly prints out which additional requests remain
unflushed in the error message, helping her determine if the code
needs changing, or if an additional flush is appropriate.

Before this change:

    Unflushed requests: 1

After this change:

    Unflushed requests: 1
      GET /some

Closes #10596
Closes #15928
2017-04-21 13:49:05 +02:00
TheHalcyonSavant 0b54c1d4a9 docs(guide/migration): remove duplicate entry for commit 13c252
Closes #15919
2017-04-21 13:48:49 +02:00
Martin Staffa 608d623b55 docs($http): correct and clarify default transforms
- baddata error described incorrect http behavior, and workarounds
- httpProvider defaults were missing transformResponse / transformRequest
- http was not clear about JSON detection strategy

Closes #15897 
Closes #15906
2017-04-21 13:48:49 +02:00
Eli Sadoff 9f30bb5475 docs(filter/uppercase): add an example
I saw that the uppercase filter had no example so I decided to add a minimal example to explain how the uppercase filter works.

Thank you very much to @narretz for helping me through this process.

Closes #15885
2017-04-21 13:48:08 +02:00
Martin Staffa 182fb18f00 docs(filter/filter): remove duplicate 'the'
Closes #15893
2017-04-21 13:48:02 +02:00
Atef Ben Ali 3a9fdceeee docs(guide/directive): delete redundant 'the'
Closes #15891
2017-04-21 13:47:55 +02:00
Atul Shimpi ee4ac72170 docs(README): improve vocabulary and orthography
Closes #15876
Closes #15875
2017-04-21 13:47:48 +02:00
michaelb958 eb9fc571a0 docs(guide/i18n): fix links to CLDR
The old link target is dead, deceased, pushing up daisies. I quote:
> The cldr-tmp repository is no longer available.
> For access to CLDR sources and data, please see the [CLDR pages](link to new one).

Closes #15879
2017-04-02 16:13:59 +03:00
520 changed files with 18423 additions and 23032 deletions
+93
View File
@@ -1,3 +1,96 @@
<a name="1.6.5"></a>
# 1.6.5 toffee-salinization (2017-07-03)
## Bug Fixes
- **core:**
- correctly detect Error instances from different contexts
([6daca0](https://github.com/angular/angular.js/commit/6daca023e42098f7098b9bf153c8e53a17af84f1),
[#15868](https://github.com/angular/angular.js/issues/15868),
[#15872](https://github.com/angular/angular.js/issues/15872))
- deprecate `angular.merge`
([dc41f4](https://github.com/angular/angular.js/commit/dc41f465baae9bc91418a61f446596157c530b6e),
[#12653](https://github.com/angular/angular.js/issues/12653),
[#14941](https://github.com/angular/angular.js/issues/14941),
[#15180](https://github.com/angular/angular.js/issues/15180),
[#15992](https://github.com/angular/angular.js/issues/15992),
[#16036](https://github.com/angular/angular.js/issues/16036))
- **ngOptions:**
- re-render after empty option has been removed
([510d0f](https://github.com/angular/angular.js/commit/510d0f946fa1a443ad43fa31bc9337676ef31332))
- allow empty option to be removed and re-added
([71b4da](https://github.com/angular/angular.js/commit/71b4daa4e10b6912891927ee2a7930c604b538f8))
- select unknown option if unmatched model does not match empty option
([17d34b](https://github.com/angular/angular.js/commit/17d34b7a983a0ef63f6cf404490385c696fb0da1))
- **orderBy:** guarantee stable sort
([e50ed4](https://github.com/angular/angular.js/commit/e50ed4da9e8177168f67da68bdf02f07da4e7bcf),
[#14881](https://github.com/angular/angular.js/issues/14881),
[#15914](https://github.com/angular/angular.js/issues/15914))
- **$parse:**
- do not shallow-watch inputs to one-time intercepted expressions
([6e3b5a](https://github.com/angular/angular.js/commit/6e3b5a57cd921823f3eca7200a79ac5c2ef0567a))
- standardize one-time literal vs non-literal and interceptors
([f003d9](https://github.com/angular/angular.js/commit/f003d93a3dd052dccddef41125d9c51034ac3605))
- do not shallow-watch inputs when wrapped in an interceptor fn
([aac562](https://github.com/angular/angular.js/commit/aac5623247a86681cbe0e1c8179617b816394c1d),
[#15905](https://github.com/angular/angular.js/issues/15905))
- always re-evaluate filters within literals when an input is an object
([ec9768](https://github.com/angular/angular.js/commit/ec97686f2f4a5481cc806462313a664fc7a1c893),
[#15964](https://github.com/angular/angular.js/issues/15964),
[#15990](https://github.com/angular/angular.js/issues/15990))
- **$sanitize:** use appropriate inert document strategy for Firefox and Safari
([8f31f1](https://github.com/angular/angular.js/commit/8f31f1ff43b673a24f84422d5c13d6312b2c4d94))
- **$timeout/$interval:** do not trigger a digest on cancel
([a222d0](https://github.com/angular/angular.js/commit/a222d0b452622624dc498ef0b9d3c43647fd4fbc),
[#16057](https://github.com/angular/angular.js/issues/16057),
[#16064](https://github.com/angular/angular.js/issues/16064))<br>
This change might affect the use of `$timeout.flush()` in unit tests. See the commit message for
more info.
- **ngMock/$interval:** add support for zero-delay intervals in tests
([a1e3f8](https://github.com/angular/angular.js/commit/a1e3f8728e0a80396f980e48f8dc68dde6721b2b),
[#15952](https://github.com/angular/angular.js/issues/15952),
[#15953](https://github.com/angular/angular.js/issues/15953))
- **angular-loader:** do not depend on "closure" globals that may not be available
([a3226d](https://github.com/angular/angular.js/commit/a3226d01fadaf145713518dc5b8022b581c34e81),
[#15880](https://github.com/angular/angular.js/issues/15880),
[#15881](https://github.com/angular/angular.js/issues/15881))
## New Features
- **select:** expose info about selection state in controller
([0b962d](https://github.com/angular/angular.js/commit/0b962d4881e98327a91c37f7317da557aa991663),
[#13172](https://github.com/angular/angular.js/issues/13172),
[#10127](https://github.com/angular/angular.js/issues/10127))
- **$animate:** add support for `customFilter`
([ab114a](https://github.com/angular/angular.js/commit/ab114af8508bdbdb1fa5fd1e070d08818d882e28),
[#14891](https://github.com/angular/angular.js/issues/14891))
- **$compile:** overload `.component()` to accept object map of components
([210112](https://github.com/angular/angular.js/commit/2101126ce72308d8fc468ca2411bb9972e614f79),
[#14579](https://github.com/angular/angular.js/issues/14579),
[#16062](https://github.com/angular/angular.js/issues/16062))
- **$log:** log all parameters in IE 9, not just the first two.
([3671a4](https://github.com/angular/angular.js/commit/3671a43be43d05b00c90dfb3a3f746c013139581))
- **ngMock:** describe unflushed http requests
([d9128e](https://github.com/angular/angular.js/commit/d9128e7b2371ab2bb5169ba854b21c78baa784d2),
[#10596](https://github.com/angular/angular.js/issues/10596),
[#15928](https://github.com/angular/angular.js/issues/15928))
## Performance Improvements
- **ngOptions:** prevent initial options repainting
([ff52b1](https://github.com/angular/angular.js/commit/ff52b188a759f2cc7ee6ee78a8c646c2354a47eb),
[#15801](https://github.com/angular/angular.js/issues/15801),
[#15812](https://github.com/angular/angular.js/issues/15812),
[#16071](https://github.com/angular/angular.js/issues/16071))
- **$animate:**
- avoid unnecessary computations if animations are globally disabled
([ce5ffb](https://github.com/angular/angular.js/commit/ce5ffbf667464bd58eae4c4af0917eb2685f1f6a),
[#14914](https://github.com/angular/angular.js/issues/14914))
- do not retrieve `className` unless `classNameFilter` is used
([275978](https://github.com/angular/angular.js/commit/27597887379a1904cd86832602e286894b449a75))
<a name="1.6.4"></a>
# 1.6.4 phenomenal-footnote (2017-03-31)
+2 -2
View File
@@ -8,8 +8,8 @@ synchronizes data from your UI (view) with your JavaScript objects (model) throu
binding. To help you structure your application better and make it easy to test, AngularJS teaches
the browser how to do dependency injection and inversion of control.
It also helps with server-side communication, taming async callbacks with promises and deferreds,
and it makes client-side navigation and deeplinking with hashbang urls or HTML5 pushState a
It also helps with server-side communication, taming async callbacks with promises and deferred objects,
and it makes client-side navigation and deep linking with hashbang urls or HTML5 pushState a
piece of cake. Best of all? It makes development fun!
* Web site: https://angularjs.org
@@ -70,7 +70,7 @@
</head>
<body class="homepage">
<div id="wrapper">
<header class="header" scroll-y-offset-element>
<header class="header">
<nav id="navbar-main" class="navbar navbar-fixed-top">
<div class="navbar-inner" ng-controller="DocsSearchCtrl">
<div class="container">
@@ -156,7 +156,7 @@
</div>
</div>
</nav>
<nav id="navbar-sub" class="sup-header navbar navbar-fixed-top">
<nav id="navbar-sub" class="sup-header navbar navbar-fixed-top" scroll-y-offset-element>
<div class="container main-grid main-header-grid">
<div class="grid-left">
<version-picker></version-picker>
@@ -18,9 +18,6 @@
<ul>
{% if doc.restrict.element %}
<li>as element:
{% if doc.name.indexOf('ng') == 0 -%}
(This directive can be used as custom element, but be aware of <a href="guide/ie">IE restrictions</a>).
{%- endif %}
{% code %}
<{$ doc.name | dashCase $}
{%- for param in doc.params %}
@@ -5,7 +5,7 @@
This error occurs when the restrict property of a directive is not valid.
The directive restrict property must be a string including one of more of the following characters:
The directive restrict property must be a string including one or more of the following characters:
* E (element)
* A (attribute)
* C (class)
@@ -15,4 +15,4 @@ For example:
```javascript
restrict: 'E'
restrict: 'EAC'
```
```
+6 -6
View File
@@ -3,12 +3,12 @@
@fullName Bad JSON Data
@description
The default @{link ng.$http#default-transformations `transformResponse`} will try to parse the
response as JSON if the `Content-Type` header is `application/json` or the response looks like a
The default {@link ng.$http#default-transformations `transformResponse`} will try to parse the
response as JSON if the `Content-Type` header is `application/json`, or the response looks like a
valid JSON-stringified object or array.
This error occurs when that data is not a valid JSON object.
The error message should provide additional context such as the actual response.
To resolve this error, make sure you pass valid JSON data to `transformResponse` or use an
appropriate `Content-Type` header for non-JSON data.
To resolve this error, make sure you pass valid JSON data to `transformResponse`. If the response
data looks like JSON, but has a different `Content-Type` header, you must
{@link ng.$http#overriding-the-default-transformations-per-request implement your own response
transformer on a per request basis}, or {@link ng.$http#default-transformations modify the default `$http` responseTransform}.
+244 -197
View File
@@ -6,20 +6,26 @@
# Animations
AngularJS provides animation hooks for common directives such as `ngRepeat`, `ngSwitch`, and `ngView`, as well as custom directives
via the `$animate` service. These animation hooks are set in place to trigger animations during the life cycle of various directives and when
triggered, will attempt to perform a CSS Transition, CSS Keyframe Animation or a JavaScript callback Animation (depending on if an animation is
placed on the given directive). Animations can be placed using vanilla CSS by following the naming conventions set in place by AngularJS
or with JavaScript code when it's defined as a factory.
AngularJS provides animation hooks for common directives such as
{@link ng.directive:ngRepeat ngRepeat}, {@link ng.directive:ngSwitch ngSwitch}, and
{@link ngRoute.directive:ngView ngView}, as well as custom directives via the `$animate` service.
These animation hooks are set in place to trigger animations during the life cycle of various
directives and when triggered, will attempt to perform a CSS Transition, CSS Keyframe Animation or a
JavaScript callback Animation (depending on whether an animation is placed on the given directive).
Animations can be placed using vanilla CSS by following the naming conventions set in place by
AngularJS or with JavaScript code, defined as a factory.
<div class="alert alert-info">
Note that we have used non-prefixed CSS transition properties in our examples as the major browsers now support non-prefixed
properties. If you intend to support older browsers or certain mobile browsers then you will need to include prefixed
versions of the transition properties. Take a look at http://caniuse.com/#feat=css-transitions for what browsers require prefixes,
and https://github.com/postcss/autoprefixer for a tool that can automatically generate the prefixes for you.
Note that we have used non-prefixed CSS transition properties in our examples as the major
browsers now support non-prefixed properties. If you intend to support older browsers or certain
mobile browsers then you will need to include prefixed versions of the transition properties. Take
a look at http://caniuse.com/#feat=css-transitions for what browsers require prefixes, and
https://github.com/postcss/autoprefixer for a tool that can automatically generate the prefixes
for you.
</div>
Animations are not available unless you include the {@link ngAnimate `ngAnimate` module} as a dependency within your application.
Animations are not available unless you include the {@link ngAnimate `ngAnimate` module} as a
dependency of your application.
Below is a quick example of animations being enabled for `ngShow` and `ngHide`:
@@ -59,8 +65,9 @@ You may also want to setup a separate CSS file for defining CSS-based animations
## How they work
Animations in AngularJS are completely based on CSS classes. As long as you have a CSS class attached to a HTML element within
your website, you can apply animations to it. Lets say for example that we have an HTML template with a repeater in it like so:
Animations in AngularJS are completely based on CSS classes. As long as you have a CSS class
attached to a HTML element within your application, you can apply animations to it. Lets say for
example that we have an HTML template with a repeater like so:
```html
<div ng-repeat="item in items" class="repeated-item">
@@ -68,22 +75,21 @@ your website, you can apply animations to it. Lets say for example that we have
</div>
```
As you can see, the `.repeated-item` class is present on the element that will be repeated and this class will be
used as a reference within our application's CSS and/or JavaScript animation code to tell AngularJS to perform an animation.
As you can see, the `repeated-item` class is present on the element that will be repeated and this
class will be used as a reference within our application's CSS and/or JavaScript animation code to
tell AngularJS to perform an animation.
As ngRepeat does its thing, each time a new item is added into the list, ngRepeat will add
a `ng-enter` class name to the element that is being added. When removed it will apply a `ng-leave` class name and when moved around
it will apply a `ng-move` class name.
As `ngRepeat` does its thing, each time a new item is added into the list, `ngRepeat` will add an
`ng-enter` class to the element that is being added. When removed it will apply an `ng-leave` class
and when moved around it will apply an `ng-move` class.
Taking a look at the following CSS code, we can see some transition and keyframe animation code set for each of those events that
occur when ngRepeat triggers them:
Taking a look at the following CSS code, we can see some transition and keyframe animation code set
up for each of those events that occur when `ngRepeat` triggers them:
```css
/*
We're using CSS transitions for when
the enter and move events are triggered
for the element that has the .repeated-item
class
We are using CSS transitions for when the enter and move events
are triggered for the element that has the `repeated-item` class
*/
.repeated-item.ng-enter, .repeated-item.ng-move {
transition: all 0.5s linear;
@@ -91,10 +97,8 @@ occur when ngRepeat triggers them:
}
/*
The ng-enter-active and ng-move-active
are where the transition destination properties
are set so that the animation knows what to
animate.
`.ng-enter-active` and `.ng-move-active` are where the transition destination
properties are set so that the animation knows what to animate
*/
.repeated-item.ng-enter.ng-enter-active,
.repeated-item.ng-move.ng-move-active {
@@ -102,73 +106,64 @@ occur when ngRepeat triggers them:
}
/*
We're using CSS keyframe animations for when
the leave event is triggered for the element
that has the .repeated-item class
We are using CSS keyframe animations for when the `leave` event
is triggered for the element that has the `repeated-item` class
*/
.repeated-item.ng-leave {
animation: 0.5s my_animation;
}
@keyframes my_animation {
from { opacity:1; }
to { opacity:0; }
from { opacity: 1; }
to { opacity: 0; }
}
```
The same approach to animation can be used using JavaScript code (**jQuery is used within to perform animations**):
The same approach to animation can be used using JavaScript code
(**for simplicity, we rely on jQuery to perform animations here**):
```js
myModule.animation('.repeated-item', function() {
return {
enter: function(element, done) {
element.css('opacity',0);
jQuery(element).animate({
opacity: 1
}, done);
// Initialize the element's opacity
element.css('opacity', 0);
// optional onDone or onCancel callback
// function to handle any post-animation
// cleanup operations
// Animate the element's opacity
// (`element.animate()` is provided by jQuery)
element.animate({opacity: 1}, done);
// Optional `onDone`/`onCancel` callback function
// to handle any post-animation cleanup operations
return function(isCancelled) {
if(isCancelled) {
jQuery(element).stop();
if (isCancelled) {
// Abort the animation if cancelled
// (`element.stop()` is provided by jQuery)
element.stop();
}
}
};
},
leave: function(element, done) {
// Initialize the element's opacity
element.css('opacity', 1);
jQuery(element).animate({
opacity: 0
}, done);
// optional onDone or onCancel callback
// function to handle any post-animation
// cleanup operations
return function(isCancelled) {
if(isCancelled) {
jQuery(element).stop();
}
}
},
move: function(element, done) {
element.css('opacity', 0);
jQuery(element).animate({
opacity: 1
}, done);
// Animate the element's opacity
// (`element.animate()` is provided by jQuery)
element.animate({opacity: 0}, done);
// optional onDone or onCancel callback
// function to handle any post-animation
// cleanup operations
// Optional `onDone`/`onCancel` callback function
// to handle any post-animation cleanup operations
return function(isCancelled) {
if(isCancelled) {
jQuery(element).stop();
if (isCancelled) {
// Abort the animation if cancelled
// (`element.stop()` is provided by jQuery)
element.stop();
}
}
};
},
// you can also capture these animation events
// We can also capture the following animation events:
move: function(element, done) {},
addClass: function(element, className, done) {},
removeClass: function(element, className, done) {}
}
@@ -176,74 +171,84 @@ myModule.animation('.repeated-item', function() {
```
With these generated CSS class names present on the element at the time, AngularJS automatically
figures out whether to perform a CSS and/or JavaScript animation. If both CSS and JavaScript animation
code is present, and match the CSS class name on the element, then AngularJS will run both animations at the same time.
figures out whether to perform a CSS and/or JavaScript animation. Note that you can't have both CSS
and JavaScript animations based on the same CSS class. See
{@link ngAnimate#css-js-animations-together here} for more details.
## Class and ngClass animation hooks
## Class and `ngClass` animation hooks
AngularJS also pays attention to CSS class changes on elements by triggering the **add** and **remove** hooks.
This means that if a CSS class is added to or removed from an element then an animation can be executed in between,
before the CSS class addition or removal is finalized. (Keep in mind that AngularJS will only be
able to capture class changes if an **expression** or the **ng-class** directive is used on the element.)
AngularJS also pays attention to CSS class changes on elements by triggering the **add** and
**remove** hooks. This means that if a CSS class is added to or removed from an element then an
animation can be executed in between, before the CSS class addition or removal is finalized.
(Keep in mind that AngularJS will only be able to capture class changes if an
**interpolated expression** or the **ng-class** directive is used on the element.)
The example below shows how to perform animations during class changes:
<example module="ngAnimate" deps="angular-animate.js" animations="true" name="animate-css-class">
<file name="index.html">
<p>
<input type="button" value="set" ng-click="myCssVar='css-class'">
<input type="button" value="clear" ng-click="myCssVar=''">
<br>
<span ng-class="myCssVar">CSS-Animated Text</span>
</p>
</file>
<file name="style.css">
.css-class-add, .css-class-remove {
transition: all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
}
<file name="index.html">
<p>
<button ng-click="myCssVar='css-class'">Set</button>
<button ng-click="myCssVar=''">Clear</button>
<br>
<span ng-class="myCssVar">CSS-Animated Text</span>
</p>
</file>
<file name="style.css">
.css-class-add, .css-class-remove {
transition: all 0.5s cubic-bezier(0.250, 0.460, 0.450, 0.940);
}
.css-class,
.css-class-add.css-class-add-active {
color: red;
font-size:3em;
}
.css-class,
.css-class-add.css-class-add-active {
color: red;
font-size: 3em;
}
.css-class-remove.css-class-remove-active {
font-size:1.0em;
color: black;
}
</file>
.css-class-remove.css-class-remove-active {
font-size: 1em;
color: black;
}
</file>
</example>
Although the CSS is a little different than what we saw before, the idea is the same.
## Which directives support animations?
A handful of common AngularJS directives support and trigger animation hooks whenever any major event occurs during its life cycle.
The table below explains in detail which animation events are triggered
A handful of common AngularJS directives support and trigger animation hooks whenever any major
event occurs during their life cycle. The table below explains in detail which animation events are
triggered:
| Directive | Supported Animations |
|-------------------------------------------------------------------------------------|------------------------------------------|
| {@link ng.directive:ngRepeat#animations ngRepeat} | enter, leave, and move |
| {@link ngRoute.directive:ngView#animations ngView} | enter and leave |
| {@link ng.directive:ngInclude#animations ngInclude} | enter and leave |
| {@link ng.directive:ngSwitch#animations ngSwitch} | enter and leave |
| {@link ng.directive:ngIf#animations ngIf} | enter and leave |
| {@link ng.directive:ngClass#animations ngClass or &#123;&#123;class&#125;&#125;} | add and remove |
| {@link ng.directive:ngShow#animations ngShow & ngHide} | add and remove (the ng-hide class value) |
| Directive | Supported Animations |
|-------------------------------------------------------------------------------|---------------------------------------------------------------------------|
| {@link ng.directive:ngRepeat#animations ngRepeat} | enter, leave, and move |
| {@link ng.directive:ngIf#animations ngIf} | enter and leave |
| {@link ng.directive:ngSwitch#animations ngSwitch} | enter and leave |
| {@link ng.directive:ngInclude#animations ngInclude} | enter and leave |
| {@link ngRoute.directive:ngView#animations ngView} | enter and leave |
| {@link module:ngMessages#animations ngMessage / ngMessageExp} | enter and leave |
| {@link ng.directive:ngClass#animations ngClass / {{class&#125;&#8203;&#125;} | add and remove |
| {@link ng.directive:ngClass#animations ngClassEven / ngClassOdd} | add and remove |
| {@link ng.directive:ngHide#animations ngHide} | add and remove (the `ng-hide` class) |
| {@link ng.directive:ngShow#animations ngShow} | add and remove (the `ng-hide` class) |
| {@link ng.directive:ngModel#animation-hooks ngModel} | add and remove ({@link ng.directive:ngModel#css-classes various classes}) |
| {@link ng.directive:form#animation-hooks form / ngForm} | add and remove ({@link ng.directive:form#css-classes various classes}) |
| {@link module:ngMessages#animations ngMessages} | add and remove (the `ng-active`/`ng-inactive` classes) |
For a full breakdown of the steps involved during each animation event, refer to the {@link ng.$animate API docs}.
For a full breakdown of the steps involved during each animation event, refer to the
{@link ng.$animate API docs}.
## How do I use animations in my own directives?
Animations within custom directives can also be established by injecting `$animate` directly into your directive and
making calls to it when needed.
Animations within custom directives can also be established by injecting `$animate` directly into
your directive and making calls to it when needed.
```js
myModule.directive('my-directive', ['$animate', function($animate) {
return function(scope, element, attrs) {
return function(scope, element) {
element.on('click', function() {
if(element.hasClass('clicked')) {
if (element.hasClass('clicked')) {
$animate.removeClass(element, 'clicked');
} else {
$animate.addClass(element, 'clicked');
@@ -255,17 +260,19 @@ myModule.directive('my-directive', ['$animate', function($animate) {
## Animations on app bootstrap / page load
By default, animations are disabled when the Angular app {@link guide/bootstrap bootstraps}. If you are using the {@link ngApp} directive,
this happens in the `DOMContentLoaded` event, so immediately after the page has been loaded.
Animations are disabled, so that UI and content are instantly visible. Otherwise, with many animations on
the page, the loading process may become too visually overwhelming, and the performance may suffer.
By default, animations are disabled when the AngularJS app {@link guide/bootstrap bootstraps}. If you
are using the {@link ngApp} directive, this happens in the `DOMContentLoaded` event, so immediately
after the page has been loaded. Animations are disabled, so that UI and content are instantly
visible. Otherwise, with many animations on the page, the loading process may become too visually
overwhelming, and the performance may suffer.
Internally, `ngAnimate` waits until all template downloads that are started right after bootstrap have finished.
Then, it waits for the currently running {@link ng.$rootScope.Scope#$digest} and the one after that to finish.
This ensures that the whole app has been compiled fully before animations are attempted.
Internally, `ngAnimate` waits until all template downloads that are started right after bootstrap
have finished. Then, it waits for the currently running {@link ng.$rootScope.Scope#$digest $digest}
and one more after that, to finish. This ensures that the whole app has been compiled fully before
animations are attempted.
If you do want your animations to play when the app bootstraps, you can enable animations globally in
your main module's {@link angular.Module#run run} function:
If you do want your animations to play when the app bootstraps, you can enable animations globally
in your main module's {@link angular.Module#run run} function:
```js
myModule.run(function($animate) {
@@ -275,17 +282,50 @@ myModule.run(function($animate) {
## How to (selectively) enable, disable and skip animations
There are three different ways to disable animations, both globally and for specific animations.
Disabling specific animations can help to speed up the render performance, for example for large `ngRepeat`
lists that don't actually have animations. Because ngAnimate checks at runtime if animations are present,
performance will take a hit even if an element has no animation.
There are several different ways to disable animations, both globally and for specific animations.
Disabling specific animations can help to speed up the render performance, for example for large
`ngRepeat` lists that don't actually have animations. Because `ngAnimate` checks at runtime if
animations are present, performance will take a hit even if an element has no animation.
### In the config: {@link $animateProvider#classNameFilter $animateProvider.classNameFilter()}
### During the config: {@link $animateProvider#customFilter $animateProvider.customFilter()}
This function can be called in the {@link angular.Module#config config} phase of an app. It takes a regex as the only argument,
which will then be matched against the classes of any element that is about to be animated. The regex
allows a lot of flexibility - you can either allow animations only for specific classes (useful when
you are working with 3rd party animations), or exclude specific classes from getting animated.
This function can be called during the {@link angular.Module#config config} phase of an app. It
takes a filter function as the only argument, which will then be used to "filter" animations (based
on the animated element, the event type, and the animation options). Only when the filter function
returns `true`, will the animation be performed. This allows great flexibility - you can easily
create complex rules, such as allowing specific events only or enabling animations on specific
subtrees of the DOM, and dynamically modify them, for example disabling animations at certain points
in time or under certain circumstances.
```js
app.config(function($animateProvider) {
$animateProvider.customFilter(function(node, event, options) {
// Example: Only animate `enter` and `leave` operations.
return event === 'enter' || event === 'leave';
});
});
```
The `customFilter` approach generally gives a big speed boost compared to other strategies, because
the matching is done before other animation disabling strategies are checked.
<div class="alert alert-success">
**Best Practice:**
Keep the filtering function as lean as possible, because it will be called for each DOM
action (e.g. insertion, removal, class change) performed by "animation-aware" directives.
See {@link guide/animations#which-directives-support-animations- here} for a list of built-in
directives that support animations.
Performing computationally expensive or time-consuming operations on each call of the
filtering function can make your animations sluggish.
</div>
### During the config: {@link $animateProvider#classNameFilter $animateProvider.classNameFilter()}
This function too can be called during the {@link angular.Module#config config} phase of an app. It
takes a regex as the only argument, which will then be matched against the classes of any element
that is about to be animated. The regex allows a lot of flexibility - you can either allow
animations for specific classes only (useful when you are working with 3rd party animations), or
exclude specific classes from getting animated.
```js
app.config(function($animateProvider) {
@@ -294,42 +334,43 @@ app.config(function($animateProvider) {
```
```css
/&#42; prefixed with animate- &#42;/
/&#42; prefixed with `animate-` &#42;/
.animate-fade-add.animate-fade-add-active {
transition: all 1s linear;
opacity: 0;
}
```
The classNameFilter approach generally applies the biggest speed boost, because the matching is
done before any other animation disabling strategies are checked. However, that also means it is not
possible to override class name matching with the two following strategies. It's of course still possible
to enable / disable animations by changing an element's class name at runtime.
The `classNameFilter` approach generally gives a big speed boost compared to other strategies,
because the matching is done before other animation disabling strategies are checked. However, that
also means it is not possible to override class name matching with the two following strategies.
It's of course still possible to enable / disable animations by changing an element's class name at
runtime.
### At runtime: {@link ng.$animate#enabled $animate.enabled()}
This function can be used to enable / disable animations in two different ways:
With a single `boolean` argument, it enables / disables animations globally: `$animate.enabled(false)`
disables all animations in your app.
With a single `boolean` argument, it enables / disables animations globally:
`$animate.enabled(false)` disables all animations in your app.
When the first argument is a native DOM or jqLite/jQuery element, the function enables / disables
animations on this element *and all its children*: `$animate.enabled(myElement, false)`. This is the
most flexible way to change the animation state. For example, even if you have used it to disable
animations on a parent element, you can still re-enable it for a child element. And compared to the
`classNameFilter`, you can change the animation status at runtime instead of during the config phase.
animations on this element *and all its children*: `$animate.enabled(myElement, false)`. You can
still use it to re-enable animations for a child element, even if you have disabled them on a parent
element. And compared to the `classNameFilter`, you can change the animation status at runtime
instead of during the config phase.
Note however that the `$animate.enabled()` state for individual elements does not overwrite disabling
rules that have been set in the {@link $animateProvider#classNameFilter classNameFilter}.
Note however that the `$animate.enabled()` state for individual elements does not overwrite
disabling rules that have been set in the {@link $animateProvider#classNameFilter classNameFilter}.
### Via CSS styles: overwriting styles in the `ng-animate` CSS class
Whenever an animation is started, ngAnimate applies the `ng-animate` class to the element for the
whole duration of the animation. By applying CSS transition / animation styling to the class,
you can skip an animation:
Whenever an animation is started, `ngAnimate` applies the `ng-animate` class to the element for the
whole duration of the animation. By applying CSS transition / animation styling to that class, you
can skip an animation:
```css
.my-class{
.my-class {
transition: transform 2s;
}
@@ -340,23 +381,23 @@ you can skip an animation:
my-class.ng-animate {
transition: 0s;
}
```
By setting `transition: 0s`, ngAnimate will ignore the existing transition styles, and not try to animate them (Javascript
animations will still execute, though). This can be used to prevent {@link guide/animations#preventing-collisions-with-existing-animations-and-third-party-libraries
issues with existing animations interfering with ngAnimate}.
By setting `transition: 0s`, `ngAnimate` will ignore the existing transition styles, and not try to
animate them (Javascript animations will still execute, though). This can be used to prevent
{@link guide/animations#preventing-collisions-with-existing-animations-and-third-party-libraries
issues with existing animations interfering with `ngAnimate`}.
## Preventing flicker before an animation starts
When nesting elements with structural animations such as `ngIf` into elements that have class-based
animations such as `ngClass`, it sometimes happens that before the actual animation starts, there is a brief flicker or flash of content
where the animated element is briefly visible.
When nesting elements with structural animations, such as `ngIf`, into elements that have
class-based animations such as `ngClass`, it sometimes happens that before the actual animation
starts, there is a brief flicker or flash of content where the animated element is briefly visible.
To prevent this, you can apply styles to the `ng-[event]-prepare` class, which is added as soon as an animation is initialized,
but removed before the actual animation starts (after waiting for a $digest). This class is only added for *structural*
animations (`enter`, `move`, and `leave`).
To prevent this, you can apply styles to the `ng-[event]-prepare` class, which is added as soon as
an animation is initialized, but removed before the actual animation starts (after waiting for a
`$digest`). This class is only added for *structural* animations (`enter`, `move`, and `leave`).
Here's an example where you might see flickering:
@@ -368,8 +409,9 @@ Here's an example where you might see flickering:
</div>
```
It is possible that during the `enter` event, the `.message` div will be briefly visible before it starts animating.
In that case, you can add styles to the CSS that make sure the element stays hidden before the animation starts:
It is possible that during the `enter` event, the `.message` div will be briefly visible before it
starts animating. In that case, you can add styles to the CSS that make sure the element stays
hidden before the animation starts:
```css
.message.ng-enter-prepare {
@@ -379,66 +421,71 @@ In that case, you can add styles to the CSS that make sure the element stays hid
/* Other animation styles ... */
```
## Preventing Collisions with Existing Animations and Third Party Libraries
By default, any `ngAnimate` enabled directives will assume any transition / animation styles on the
element are part of an `ngAnimate` animation. This can lead to problems when the styles are actually
for animations that are independent of `ngAnimate`.
## Preventing collisions with existing animations and third-party libraries
For example, an element acts as a loading spinner. It has an infinite css animation on it, and also an
{@link ngIf `ngIf`} directive, for which no animations are defined:
By default, any `ngAnimate`-enabled directives will assume that `transition` / `animation` styles on
the element are part of an `ngAnimate` animation. This can lead to problems when the styles are
actually for animations that are independent of `ngAnimate`.
For example, an element acts as a loading spinner. It has an infinite css animation on it, and also
an {@link ngIf `ngIf`} directive, for which no animations are defined:
```css
@keyframes rotating {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
.spinner {
animation: rotating 2s linear infinite;
}
.spinner {
animation: rotating 2s linear infinite;
@keyframes rotating {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
```
Now, when the `ngIf` changes, `ngAnimate` will see the spinner animation and use
it to animate the `enter`/`leave` event, which doesn't work because
the animation is infinite. The element will still be added / removed after a timeout, but there will be a
noticable delay.
Now, when the `ngIf` expression changes, `ngAnimate` will see the spinner animation and use it to
animate the `enter`/`leave` event, which doesn't work because the animation is infinite. The element
will still be added / removed after a timeout, but there will be a noticeable delay.
This might also happen because some third-party frameworks place animation duration defaults
across many element or className selectors in order to make their code small and reuseable.
This might also happen because some third-party frameworks place animation duration defaults across
many element or className selectors in order to make their code small and reusable.
You can prevent this unwanted behavior by adding CSS to the `.ng-animate` class that is added
for the whole duration of an animation. Simply overwrite the transition / animation duration. In the
You can prevent this unwanted behavior by adding CSS to the `.ng-animate` class, that is added for
the whole duration of each animation. Simply overwrite the transition / animation duration. In the
case of the spinner, this would be:
```css
.spinner.ng-animate {
transition: 0s none;
animation: 0s none;
animation: 0s none;
transition: 0s none;
}
```
If you do have CSS transitions / animations defined for the animation events, make sure they have higher priority
than any styles that are independent from ngAnimate.
If you do have CSS transitions / animations defined for the animation events, make sure they have a
higher priority than any styles that are not related to `ngAnimate`.
You can also use one of the two other {@link guide/animations#how-to-selectively-enable-disable-and-skip-animations strategies to disable animations}.
You can also use one of the other
{@link guide/animations#how-to-selectively-enable-disable-and-skip-animations
strategies to disable animations}.
### Enable animations for elements outside of the Angular application DOM tree: {@link ng.$animate#pin $animate.pin()}
## Enable animations outside of the application DOM tree: {@link ng.$animate#pin $animate.pin()}
Before animating, `ngAnimate` checks to see if the element being animated is inside the application DOM tree,
and if it is not, no animation is run. Usually, this is not a problem as most apps use the `ngApp`
attribute / bootstrap the app on the `html` or `body` element.
Before animating, `ngAnimate` checks if the animated element is inside the application DOM tree. If
not, no animation is run. Usually, this is not a problem since most apps use the `html` or `body`
elements as their root.
Problems arise when the application is bootstrapped on a different element, and animations are
attempted on elements that are outside the application tree, e.g. when libraries append popup and modal
elements as the last child in the body tag.
attempted on elements that are outside the application tree, e.g. when libraries append popup or
modal elements to the body tag.
You can use {@link ng.$animate#pin `$animate.pin(elementToAnimate, parentHost)`} to specify that an
element belongs to your application. Simply call it before the element is added to the DOM / before
the animation starts, with the element you want to animate, and the element which should be its
assumed parent.
You can use {@link ng.$animate#pin `$animate.pin(element, parentHost)`} to associate an element with
another element that belongs to your application. Simply call it before the element is added to the
DOM / before the animation starts, with the element you want to animate, and the element which
should be its assumed parent.
## More about animations
For a full breakdown of each method available on `$animate`, see the {@link ng.$animate API documentation}.
For a full breakdown of each method available on `$animate`, see the
{@link ng.$animate API documentation}.
To see a complete demo, see the {@link tutorial/step_14 animation step within the AngularJS phonecat tutorial}.
To see a complete demo, see the {@link tutorial/step_14 animation step in the phonecat tutorial}.
+2 -2
View File
@@ -40,8 +40,8 @@ initialization.
<html ng-app>
3. If you choose to use the old style directive syntax `ng:` then include xml-namespace in `html`
to make IE happy. (This is here for historical reasons, and we no longer recommend use of
`ng:`.)
when running the page in the XHTML mode. (This is here for historical reasons, and we no longer
recommend use of `ng:`.)
<html xmlns:ng="http://angularjs.org">
+1 -16
View File
@@ -39,14 +39,8 @@ Components can be registered using the `.component()` method of an Angular modul
});
</file>
<file name="heroDetail.js">
function HeroDetailController() {
}
angular.module('heroApp').component('heroDetail', {
templateUrl: 'heroDetail.html',
controller: HeroDetailController,
bindings: {
hero: '='
}
@@ -462,7 +456,7 @@ The examples use the [Jasmine](http://jasmine.github.io/) testing framework.
**Controller Test:**
```js
describe('component: heroDetail', function() {
describe('HeroDetailController', function() {
var $componentController;
beforeEach(module('heroApp'));
@@ -470,15 +464,6 @@ describe('component: heroDetail', function() {
$componentController = _$componentController_;
}));
it('should expose a `hero` object', function() {
// Here we are passing actual bindings to the component
var bindings = {hero: {name: 'Wolverine'}};
var ctrl = $componentController('heroDetail', null, bindings);
expect(ctrl.hero).toBeDefined();
expect(ctrl.hero.name).toBe('Wolverine');
});
it('should call the `onDelete` binding, when deleting the hero', function() {
var onDeleteSpy = jasmine.createSpy('onDelete');
var bindings = {hero: {}, onDelete: onDeleteSpy};
+1 -1
View File
@@ -123,7 +123,7 @@ The other forms shown above are accepted for legacy reasons but we advise you to
`$compile` can match directives based on element names (E), attributes (A), class names (C),
and comments (M).
The built-in the AngularJS directives show in their documentation page which type of matching they support.
The built-in AngularJS directives show in their documentation page which type of matching they support.
The following demonstrates the various ways a directive that matches all 4 types
(`myDir` in this case) can be referenced from within a template.
+1 -1
View File
@@ -139,7 +139,7 @@ You can find a larger list of Angular external libraries at [ngmodules.org](http
[CodeAcademy](http://www.codecademy.com/courses/javascript-advanced-en-2hJ3J/0/1),
[CodeSchool](https://www.codeschool.com/courses/shaping-up-with-angular-js)
* **Paid online:**
[Pluralsight (3 courses)](http://www.pluralsight.com/training/Courses/Find?highlight=true&searchTerm=angularjs),
[Pluralsight](https://www.pluralsight.com/search?q=angularjs),
[Tuts+](https://tutsplus.com/course/easier-js-apps-with-angular/),
[lynda.com](http://www.lynda.com/AngularJS-tutorials/Up-Running-AngularJS/133318-2.html),
[WintellectNOW (4 lessons)](http://www.wintellectnow.com/Course/Detail/mastering-angularjs),
+6 -6
View File
@@ -281,18 +281,18 @@ categories as you need.
#### Selection Keywords
The selection keywords can be either exact matches or language dependent [plural
categories](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html).
categories](http://cldr.unicode.org/index/cldr-spec/plural-rules).
Exact matches are written as the equal sign followed by the exact value. `=0`, `=1`, `=2` and
`=123` are all examples of exact matches. Note that there should be no space between the equal sign
and the numeric value.
Plural category matches are single words corresponding to the [plural
categories](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html) of
the CLDR plural category spec. These categories vary by locale. The "en" (English) locale, for
example, defines just "one" and "other" while the "ga" (Irish) locale defines "one", "two", "few",
"many" and "other". Typically, you would just write the categories for your language. During
translation, the translators will add or remove more categories depending on the target locale.
categories](http://cldr.unicode.org/index/cldr-spec/plural-rules) of the CLDR plural category spec.
These categories vary by locale. The "en" (English) locale, for example, defines just "one" and
"other" while the "ga" (Irish) locale defines "one", "two", "few", "many" and "other". Typically,
you would just write the categories for your language. During translation, the translators will add
or remove more categories depending on the target locale.
Exact matches always win over keyword matches. Therefore, if you define both `=0` and `zero`, when
the value of the expression is zero, the `=0` message is the one that will be selected. (The
+4 -4
View File
@@ -7,7 +7,7 @@
<div class="alert alert-warning">
**Note:** AngularJS 1.3 has dropped support for IE8. Read more about it on
[our blog](http://blog.angularjs.org/2013/12/angularjs-13-new-release-approaches.html).
[our blog](https://blog.angularjs.org/2013/12/angularjs-13-new-release-approaches.html).
AngularJS 1.2 will continue to support IE8, but the core team does not plan to spend time
addressing issues specific to IE8 or earlier.
</div>
@@ -19,7 +19,7 @@ on IE.
The project currently supports and will attempt to fix bugs for IE9 and above. The continuous
integration server runs all the tests against IE9, IE10, and IE11. See
[Travis CI](https://travis-ci.org/angular/angular.js) and
[ci.angularjs.org](http://ci.angularjs.org).
[ci.angularjs.org](https://ci.angularjs.org).
We do not run tests on IE8 and below. A subset of the AngularJS functionality may work on these
browsers, but it is up to you to test and decide whether it works for your particular app.
@@ -27,8 +27,8 @@ browsers, but it is up to you to test and decide whether it works for your parti
To ensure your Angular application works on IE please consider:
1. Use `ng-style` tags instead of `style="{{ someCss }}"`. The latter works in Chrome and Firefox
but does not work in Internet Explorer <= 11 (the most recent version at time of writing).
1. Use `ng-style` tags instead of `style="{{ someCss }}"`. The latter works in Chrome, Firefox,
Safari and Edge but does not work in Internet Explorer (even 11).
2. For the `type` attribute of buttons, use `ng-attr-type` tags instead of
`type="{{ someExpression }}"`. If using the latter, Internet Explorer overwrites the expression
with `type="submit"` before Angular has a chance to interpolate it.
+1 -1
View File
@@ -32,7 +32,7 @@ If the interpolated value is not a `String`, it is computed as follows:
- `undefined` and `null` are converted to `''`
- if the value is an object that is not a `Number`, `Date` or `Array`, $interpolate looks for
a custom `toString()` function on the object, and uses that. Custom means that
`myObject.toString !== `Object.prototype.toString`.
`myObject.toString !== Object.prototype.toString`.
- if the above doesn't apply, `JSON.stringify` is used.
### Binding to boolean attributes
+1 -9
View File
@@ -484,14 +484,6 @@ lifecycle hook), you may need to manually call `$onInit()` from your constructor
})
```
<hr />
<minor />
**Due to [13c252](https://github.com/angular/angular.js/commit/13c2522baf7c8f616b2efcaab4bffd54c8736591)**,
on **IE11 only**, consecutive text nodes will always get merged. Previously, they would not get
merged if they had no parent. The new behavior, which fixes an IE11 bug affecting interpolation
under certain circumstances, might in some edge-cases have unexpected side effects that you should
be aware of. Please, check the commit message for more details.
<hr />
<minor />
**Due to [04cad4](https://github.com/angular/angular.js/commit/04cad41d26ebaf44b5ee0c29a152d61f235f3efa)**,
@@ -1320,7 +1312,7 @@ jqLite/jQuery collections
#### Helper Functions:
The {@link angular.lowercase `angular.lowercase`} and {@link angular.uppercase `angular.uppercase`} functions have been **deprecated** and will be removed
The `angular.lowercase` and `angular.uppercase` functions have been **deprecated** and will be removed
in version 1.7.0. It is recommended to use [String.prototype.toLowerCase](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String/toLowerCase) and [String.prototype.toUpperCase](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String/toUpperCase) functions instead.
+1 -1
View File
@@ -30,7 +30,7 @@ curly-brace {@link expression expression} bindings:
string expression 'buttonText'
wrapped in "{{ }}" markup -->
<button ng-click="changeFoo()">{{buttonText}}</button>
<script src="angular.js">
<script src="angular.js"></script>
</body>
</html>
```
+2 -4
View File
@@ -142,10 +142,8 @@ We run our extensive test suite against the following browsers: the latest versi
Firefox, Safari, and Safari for iOS, as well as Internet Explorer versions 9-11. See
{@link guide/ie Internet Explorer Compatibility} for more details on supporting legacy IE browsers.
If a browser is untested, it doesn't mean it won't work; for example, older Android (2.3.x)
is supported in the sense that we avoid the dot notation for reserved words as property names,
but we don't actively test changes against it. You can also expect browsers to work that share
a large part of their codebase with a browser we test, such as Opera > version 12
If a browser is untested, it doesn't mean it won't work. You can also expect browsers to work that
share a large part of their codebase with a browser we test, such as Opera 15 or newer
(uses the Blink engine), or the various Firefox derivatives.
+45 -4
View File
@@ -65,6 +65,21 @@ goog.i18n.currency.SPACE_FLAG_ = 0x20;
goog.i18n.currency.tier2Enabled_ = false;
/**
* Tests if currency is available.
*
* Note: If the currency is not available it might be in the tier2 currency set:
* {@link goog.i18n.currency.CurrencyInfoTier2}. If that is the case call
* {@link goog.i18n.currency.addTier2Support} before calling any other function
* in this namespace.
*
* @param {string} currencyCode Currency code to tested.
* @return {boolean} If the currency is available.
*/
goog.i18n.currency.isAvailable = function(currencyCode) {
return currencyCode in goog.i18n.currency.CurrencyInfo;
};
/**
* This function will add tier2 currency support. Be default, only tier1
* (most popular currencies) are supported. If an application really needs
@@ -84,6 +99,7 @@ goog.i18n.currency.addTier2Support = function() {
/**
* Deprecated.
* Global currency pattern always uses ISO-4217 currency code as prefix. Local
* currency sign is added if it is different from currency code. Each currency
* is unique in this form. The negative side is that ISO code looks weird in
@@ -92,6 +108,9 @@ goog.i18n.currency.addTier2Support = function() {
*
* @param {string} currencyCode ISO-4217 3-letter currency code.
* @return {string} Global currency pattern string for given currency.
* @deprecated Format numbers using {@link goog.i18n.NumberFormat} with
* {@link goog.i18n.NumberFormat.Format.CURRENCY} and
* {@link goog.i18n.NumberFormat.CurrencyStyle.GLOBAL}
*/
goog.i18n.currency.getGlobalCurrencyPattern = function(currencyCode) {
var info = goog.i18n.currency.CurrencyInfo[currencyCode];
@@ -119,12 +138,16 @@ goog.i18n.currency.getGlobalCurrencySign = function(currencyCode) {
/**
* Deprecated.
* Local currency pattern is the most frequently used pattern in currency's
* native region. It does not care about how it is distinguished from other
* currencies.
*
* @param {string} currencyCode ISO-4217 3-letter currency code.
* @return {string} Local currency pattern string for given currency.
* @deprecated Format numbers using {@link goog.i18n.NumberFormat} with
* {@link goog.i18n.NumberFormat.Format.CURRENCY} and
* {@link goog.i18n.NumberFormat.CurrencyStyle.LOCAL}
*/
goog.i18n.currency.getLocalCurrencyPattern = function(currencyCode) {
var info = goog.i18n.currency.CurrencyInfo[currencyCode];
@@ -145,6 +168,7 @@ goog.i18n.currency.getLocalCurrencySign = function(currencyCode) {
/**
* Deprecated.
* Portable currency pattern is a compromise between local and global. It is
* not a mere blend or mid-way between the two. Currency sign is chosen so that
* it looks familiar to native users. It also has enough information to
@@ -154,6 +178,9 @@ goog.i18n.currency.getLocalCurrencySign = function(currencyCode) {
*
* @param {string} currencyCode ISO-4217 3-letter currency code.
* @return {string} Portable currency pattern string for given currency.
* @deprecated Format numbers using {@link goog.i18n.NumberFormat} with
* {@link goog.i18n.NumberFormat.Format.CURRENCY} and
* {@link goog.i18n.NumberFormat.CurrencyStyle.PORTABLE}
*/
goog.i18n.currency.getPortableCurrencyPattern = function(currencyCode) {
var info = goog.i18n.currency.CurrencyInfo[currencyCode];
@@ -174,12 +201,17 @@ goog.i18n.currency.getPortableCurrencySign = function(currencyCode) {
/**
* This function returns the default currency sign position. Some applications
* This function returns the default currency sign's position. Some applications
* may want to handle currency sign and currency amount separately. This
* function can be used in such situations to correctly position the currency
* sign relative to the amount.
*
* To match the behavior of ICU, position is not determined by display locale.
* Use {@link goog.i18n.NumberFormat#isCurrencyCodeBeforeValue} for a locale
* aware version of this API (recommended). isPrefixSignPosition() returns the
* default currency sign's position in the currency's default locale (e.g. 'en'
* for 'USD'), but most commonly the position is needed for the locale in which
* the number is going to be displayed. For example, in 'fr' 10.10 USD would be
* displayed as '10,10 $'.
*
* @param {string} currencyCode ISO-4217 3-letter currency code.
* @return {boolean} true if currency should be positioned before amount field.
@@ -267,6 +299,10 @@ 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)
*
* It's not recommended to read this data directly. Format numbers using
* {@link goog.i18n.NumberFormat} with
* {@link goog.i18n.NumberFormat.Format.CURRENCY} instead.
*
* @const {!Object<!Array<?>>}
*/
goog.i18n.currency.CurrencyInfo = {
@@ -310,7 +346,7 @@ goog.i18n.currency.CurrencyInfo = {
'NOK': [50, 'kr', 'NOkr'],
'PAB': [2, 'B/.', 'B/.'],
'PEN': [2, 'S/.', 'S/.'],
'PHP': [2, '\u20B1', 'Php'],
'PHP': [2, '\u20B1', 'PHP'],
'PKR': [0, 'Rs', 'PKRs.'],
'PLN': [50, 'z\u0142', 'z\u0142'],
'RON': [2, 'RON', 'RON'],
@@ -334,6 +370,11 @@ goog.i18n.currency.CurrencyInfo = {
/**
* Tier 2 currency information.
*
* It's not recommended to read this data directly. Format numbers using
* {@link goog.i18n.NumberFormat} with
* {@link goog.i18n.NumberFormat.Format.CURRENCY} instead.
*
* @const {!Object<!Array<?>>}
*/
goog.i18n.currency.CurrencyInfoTier2 = {
@@ -431,7 +472,7 @@ goog.i18n.currency.CurrencyInfoTier2 = {
'XAF': [0, 'FCFA', 'FCFA'],
'XCD': [2, '$', 'EC$'],
'XOF': [0, 'CFA', 'CFA'],
'XPF': [0, 'FCFP', 'FCFP'],
'XPF': [48, 'FCFP', 'FCFP'],
'ZMW': [0, 'ZMW', 'ZMW'],
'ZWD': [0, '$', 'Z$']
};
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+21 -33
View File
@@ -17,7 +17,7 @@
*
* This file is autogenerated by script:
* http://go/generate_pluralrules.py
* File generated from CLDR ver. 29
* File generated from CLDR ver. 31.0.1
*
* 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
@@ -128,22 +128,6 @@ goog.i18n.pluralRules.filSelect_ = function(n, opt_precision) {
return goog.i18n.pluralRules.Keyword.OTHER;
};
/**
* Plural select rules for pt_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.pt_PTSelect_ = function(n, opt_precision) {
var vf = goog.i18n.pluralRules.get_vf_(n, opt_precision);
if (n == 1 && vf.v == 0) {
return goog.i18n.pluralRules.Keyword.ONE;
}
return goog.i18n.pluralRules.Keyword.OTHER;
};
/**
* Plural select rules for br locale
*
@@ -240,6 +224,22 @@ goog.i18n.pluralRules.frSelect_ = 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;
if (i >= 0 && i <= 1) {
return goog.i18n.pluralRules.Keyword.ONE;
}
return goog.i18n.pluralRules.Keyword.OTHER;
};
/**
* Plural select rules for cs locale
*
@@ -559,21 +559,6 @@ goog.i18n.pluralRules.gaSelect_ = 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) {
if (n >= 0 && n <= 2 && n != 2) {
return goog.i18n.pluralRules.Keyword.ONE;
}
return goog.i18n.pluralRules.Keyword.OTHER;
};
/**
* Plural select rules for es locale
*
@@ -820,6 +805,9 @@ if (goog.LOCALE == 'am') {
if (goog.LOCALE == 'ar') {
goog.i18n.pluralRules.select = goog.i18n.pluralRules.arSelect_;
}
if (goog.LOCALE == 'ar_DZ' || goog.LOCALE == 'ar-DZ') {
goog.i18n.pluralRules.select = goog.i18n.pluralRules.arSelect_;
}
if (goog.LOCALE == 'az') {
goog.i18n.pluralRules.select = goog.i18n.pluralRules.esSelect_;
}
@@ -1061,7 +1049,7 @@ if (goog.LOCALE == 'pt_BR' || goog.LOCALE == 'pt-BR') {
goog.i18n.pluralRules.select = goog.i18n.pluralRules.ptSelect_;
}
if (goog.LOCALE == 'pt_PT' || goog.LOCALE == 'pt-PT') {
goog.i18n.pluralRules.select = goog.i18n.pluralRules.pt_PTSelect_;
goog.i18n.pluralRules.select = goog.i18n.pluralRules.ptSelect_;
}
if (goog.LOCALE == 'ro') {
goog.i18n.pluralRules.select = goog.i18n.pluralRules.roSelect_;
-1
View File
@@ -75,7 +75,6 @@ describe('findLocaleId', function() {
it('should not find localeId if data is missing', function() {
expect(findLocaleId('', 'num')).toBeUndefined();
expect(findLocaleId('aa', 'datetime')).toBeUndefined();
expect(findLocaleId('aa', 'randomType')).toBeUndefined();
expect(findLocaleId('NumberFormatSymbols_en', 'datetime')).toBeUndefined();
expect(findLocaleId('DateTimeSymbols_en', 'num')).toBeUndefined();
});
+49 -1
View File
@@ -1,6 +1,43 @@
'use strict';
var parsePattern = require('../src/parser.js').parsePattern;
var parser = require('../src/parser');
var ensureDecimalSep = parser.ensureDecimalSep;
var parsePattern = parser.parsePattern;
describe('ensureDecimalSep', function() {
it('should leave patterns with DECIMAL_SEP untouched', function() {
[
'#,##0.00',
'$#,##0.00',
'#,##0.00$',
'$0.00',
'0.00$',
'0.0',
'#,##0.',
'0.'
].forEach(function(pattern) {
expect(ensureDecimalSep(pattern)).toBe(pattern);
});
});
it('should add a DECIMAL_SEP in patterns that don\'t have one (after the last ZERO)', function() {
var patterns = {
'#,##000': '#,##000.',
'$#,#0#00': '$#,#0#00.',
'#,##000$': '#,##000.$',
'$000': '$000.',
'000$': '000.$',
'00': '00.',
'#,##0': '#,##0.',
'0': '0.'
};
Object.keys(patterns).forEach(function(input) {
var output = patterns[input];
expect(ensureDecimalSep(input)).toBe(output);
});
});
});
describe('parsePattern', function() {
function parseAndExpect(pattern, pp, np, ps, ns, mii, mif, maf, g, lg) {
@@ -28,6 +65,11 @@ describe('parsePattern', function() {
'', '\u202A-', '', '\u202C', 1, 0, 3, 3, 3);
parseAndExpect('#0.###;#0.###-', '', '', '', '-', 1, 0, 3, 0, 0);
// Even patterns without a DECIMAL_SEP
parseAndExpect('#,##0', '', '-', '', '', 1, 0, 0, 3, 3);
parseAndExpect('+#,##0', '+', '-+', '', '', 1, 0, 0, 3, 3);
parseAndExpect('#,#0;+#,#0', '', '+', '', '', 1, 0, 0, 2, 2);
parseAndExpect('#,##,##0+;(#,##,##0)', '', '(', '+', ')', 1, 0, 0, 2, 3);
});
it('should parse CURRENCY patterns', function() {
@@ -51,5 +93,11 @@ describe('parsePattern', function() {
parseAndExpect('\u00A4 #,##0.00;\u00A4 #,##0.00-',
'\u00A4 ', '\u00A4 ', '', '-', 1, 2, 2, 3, 3);
parseAndExpect('\u00A4 #,##,##0.00', '\u00A4 ', '-\u00A4 ', '', '', 1, 2, 2, 2, 3);
// Even patterns without a DECIMAL_SEP
parseAndExpect('#,##0 \u00A4', '', '-', ' \u00A4', ' \u00A4', 1, 0, 0, 3, 3);
parseAndExpect('\u00A4 #,##0', '\u00A4 ', '-\u00A4 ', '', '', 1, 0, 0, 3, 3);
parseAndExpect('#,#0 \u00A4;+#,#0\u00A4', '', '+', ' \u00A4', '\u00A4', 1, 0, 0, 2, 2);
parseAndExpect('\u00A4 #,##,##0;(\u00A4 #,##,##0)', '\u00A4 ', '(\u00A4 ', '', ')', 1, 0, 0, 2, 3);
});
});
+1 -1
View File
@@ -7,7 +7,7 @@ var Q = require('q'),
localeInfo = {};
var NG_LOCALE_DIR = '../src/ngLocale/';
var NG_LOCALE_DIR = __dirname + '/../../src/ngLocale/';
function readSymbols() {
+28 -6
View File
@@ -4,13 +4,26 @@
* A simple parser to parse a number format into a pattern object
*/
exports.ensureDecimalSep = ensureDecimalSep;
exports.parsePattern = parsePattern;
var PATTERN_SEP = ';',
DECIMAL_SEP = '.',
GROUP_SEP = ',',
ZERO = '0',
DIGIT = '#';
var PATTERN_SEP = ';',
DECIMAL_SEP = '.',
GROUP_SEP = ',',
DIGIT = '#',
ZERO = '0',
LAST_ZERO_RE = /^(.*0)(?!0)(.*)$/;
/**
* Helper function for parser.
* Ensures that `pattern` (e.g #,##0.###) contains a DECIMAL_SEP, which is necessary for further
* parsing. If a pattern does not include one, it is added after the last ZERO (which is the last
* thing before the `posSuf` - if any).
*/
function ensureDecimalSep(pattern) {
return (pattern.indexOf(DECIMAL_SEP) !== -1)
? pattern : pattern.replace(LAST_ZERO_RE, '$1' + DECIMAL_SEP + '$2');
}
/**
* main function for parser
@@ -33,7 +46,16 @@ function parsePattern(pattern) {
positive = patternParts[0],
negative = patternParts[1];
var positiveParts = positive.split(DECIMAL_SEP),
// The parsing logic further below assumes that there will always be a DECIMAL_SEP in the pattern.
// However, some locales (e.g. agq_CM) do not have one, thus we add one after the last ZERO
// (which is the last thing before the `posSuf` - if any). Since there will be no ZEROs or DIGITs
// after DECIMAL_SEP, `min/maxFrac` will remain 0 (which is accurate - no fraction digits) and
// `posSuf` will be processed correctly.
// For example `#,##0$` would be converted to `#,##0.$`, which would (correctly) result in:
// `minFrac: 0`, `maxFrac: 0`, `posSuf: '$'`
// Note: We shouldn't modify `positive` directly, because it is used to parse the negative part.)
var positiveWithDecimalSep = ensureDecimalSep(positive),
positiveParts = positiveWithDecimalSep.split(DECIMAL_SEP),
integer = positiveParts[0],
fraction = positiveParts[1];
+4 -4
View File
@@ -9,18 +9,18 @@ var propertiesToExtract = {'IDS': 'Y', 'IDC': 'Y'};
function main() {
extractValues(
fs.createReadStream('./ucd/src/ucd.all.flat.xml.gz').pipe(zlib.createGunzip()),
fs.createReadStream(__dirname + '/ucd.all.flat.xml.gz').pipe(zlib.createGunzip()),
propertiesToExtract,
writeFile);
function writeFile(validRanges) {
var code = generateCode(validRanges);
try {
fs.lstatSync('../src/ngParseExt');
fs.lstatSync(__dirname + '/../../../src/ngParseExt');
} catch (e) {
fs.mkdirSync('../src/ngParseExt');
fs.mkdirSync(__dirname + '/../../../src/ngParseExt');
}
fs.writeFile('../src/ngParseExt/ucd.js', code);
fs.writeFile(__dirname + '/../../../src/ngParseExt/ucd.js', code);
}
}
+2 -2
View File
@@ -122,9 +122,9 @@ module.exports = function(config, specificOptions) {
},
'BS_iOS': {
base: 'BrowserStack',
device: 'iPhone 6',
device: 'iPhone 6S',
os: 'ios',
os_version: '8.0'
os_version: '9.3'
}
}
});
+1 -1
View File
@@ -25,7 +25,7 @@ PORTS.forEach(function(port) {
var tunnel = new BrowserStackTunnel({
key: ACCESS_KEY,
tunnelIdentifier: TUNNEL_IDENTIFIER,
localIdentifier: TUNNEL_IDENTIFIER,
hosts: hosts
});
+11 -11
View File
@@ -24,10 +24,10 @@
"benchmark": "1.x.x",
"bootstrap": "3.1.1",
"bower": "~1.3.9",
"browserstacktunnel-wrapper": "^1.4.2",
"browserstacktunnel-wrapper": "2.0.0",
"canonical-path": "0.0.2",
"changez": "^2.1.1",
"changez-angular": "^2.1.3",
"changez-angular": "^2.1.2",
"cheerio": "^0.17.0",
"commitizen": "^2.3.0",
"cross-spawn": "^4.0.0",
@@ -56,18 +56,18 @@
"gulp-sourcemaps": "^1.2.2",
"gulp-uglify": "^1.0.1",
"gulp-util": "^3.0.1",
"jasmine-core": "^2.4.0",
"jasmine-core": "2.5.2",
"jasmine-node": "^2.0.0",
"jasmine-reporters": "^2.2.0",
"jquery": "^3.2.1",
"karma": "^1.1.2",
"karma-browserstack-launcher": "^1.0.1",
"karma-chrome-launcher": "^1.0.1",
"karma-firefox-launcher": "^1.0.0",
"karma-jasmine": "^1.0.2",
"karma-junit-reporter": "^1.1.0",
"karma": "^1.7.0",
"karma-browserstack-launcher": "^1.2.0",
"karma-chrome-launcher": "^2.1.1",
"karma-firefox-launcher": "^1.0.1",
"karma-jasmine": "^1.1.0",
"karma-junit-reporter": "^1.2.0",
"karma-ng-scenario": "^1.0.0",
"karma-sauce-launcher": "^1.0.0",
"karma-sauce-launcher": "^1.1.0",
"karma-script-launcher": "^1.0.0",
"load-grunt-tasks": "^3.5.0",
"lodash": "~2.4.1",
@@ -78,7 +78,7 @@
"npm-run": "^4.1.0",
"open-sans-fontface": "^1.4.0",
"promises-aplus-tests": "~2.1.0",
"protractor": "^4.0.10",
"protractor": "^5.1.2",
"q": "~1.0.0",
"q-io": "^1.10.9",
"qq": "^0.3.5",
+5 -1
View File
@@ -62,7 +62,11 @@ function _update_code() {
for backend in "$@" ; do
echo "-- Refreshing code.angularjs.org: backend=$backend"
curl http://$backend:8003/gitFetchSite.php
# FIXME: We gave up publishing to code.angularjs.org because the GCE automatically removes firewall
# rules that allow access to port 8003.
# curl http://$backend:8003/gitFetchSite.php
done
}
+4
View File
@@ -50,6 +50,7 @@
"isNumber": false,
"isNumberNaN": false,
"isDate": false,
"isError": false,
"isArray": false,
"isFunction": false,
"isRegExp": false,
@@ -166,6 +167,9 @@
/* ng/compile.js */
"directiveNormalize": false,
/* ng/q.js */
"markQExceptionHandled": false,
/* ng/directive/directives.js */
"ngDirective": false,
+36 -51
View File
@@ -45,6 +45,7 @@
isNumber,
isNumberNaN,
isDate,
isError,
isArray,
isFunction,
isRegExp,
@@ -129,50 +130,6 @@ var VALIDITY_STATE_PROPERTY = 'validity';
var hasOwnProperty = Object.prototype.hasOwnProperty;
var minErrConfig = {
objectMaxDepth: 5
};
/**
* @ngdoc function
* @name angular.errorHandlingConfig
* @module ng
* @kind function
*
* @description
* Configure several aspects of error handling in AngularJS if used as a setter or return the
* current configuration if used as a getter. The following options are supported:
*
* - **objectMaxDepth**: The maximum depth to which objects are traversed when stringified for error messages.
*
* Omitted or undefined options will leave the corresponding configuration values unchanged.
*
* @param {Object=} config - The configuration object. May only contain the options that need to be
* updated. Supported keys:
*
* * `objectMaxDepth` **{Number}** - The max depth for stringifying objects. Setting to a
* non-positive or non-numeric value, removes the max depth limit.
* Default: 5
*/
function errorHandlingConfig(config) {
if (isObject(config)) {
if (isDefined(config.objectMaxDepth)) {
minErrConfig.objectMaxDepth = isValidObjectMaxDepth(config.objectMaxDepth) ? config.objectMaxDepth : NaN;
}
} else {
return minErrConfig;
}
}
/**
* @private
* @param {Number} maxDepth
* @return {boolean}
*/
function isValidObjectMaxDepth(maxDepth) {
return isNumber(maxDepth) && maxDepth > 0;
}
/**
* @ngdoc function
* @name angular.lowercase
@@ -480,6 +437,20 @@ function extend(dst) {
* Unlike {@link angular.extend extend()}, `merge()` recursively descends into object properties of source
* objects, performing a deep copy.
*
* @deprecated
* sinceVersion="1.6.5"
* This function is deprecated, but will not be removed in the 1.x lifecycle.
* There are edge cases (see {@link angular.merge#known-issues known issues}) that are not
* supported by this function. We suggest
* using [lodash's merge()](https://lodash.com/docs/4.17.4#merge) instead.
*
* @knownIssue
* This is a list of (known) object types that are not handled correctly by this function:
* - [`Blob`](https://developer.mozilla.org/docs/Web/API/Blob)
* - [`MediaStream`](https://developer.mozilla.org/docs/Web/API/MediaStream)
* - [`CanvasGradient`](https://developer.mozilla.org/docs/Web/API/CanvasGradient)
* - AngularJS {@link $rootScope.Scope scopes};
*
* @param {Object} dst Destination object.
* @param {...Object} src Source object(s).
* @returns {Object} Reference to `dst`.
@@ -689,6 +660,24 @@ function isDate(value) {
*/
var isArray = Array.isArray;
/**
* @description
* Determines if a reference is an `Error`.
* Loosely based on https://www.npmjs.com/package/iserror
*
* @param {*} value Reference to check.
* @returns {boolean} True if `value` is an `Error`.
*/
function isError(value) {
var tag = toString.call(value);
switch (tag) {
case '[object Error]': return true;
case '[object Exception]': return true;
case '[object DOMException]': return true;
default: return value instanceof Error;
}
}
/**
* @ngdoc function
* @name angular.isFunction
@@ -1369,7 +1358,7 @@ function fromJson(json) {
var ALL_COLONS = /:/g;
function timezoneToOffset(timezone, fallback) {
// Support: IE 9-11 only, Edge 13-14+
// Support: IE 9-11 only, Edge 13-15+
// IE/Edge do not "understand" colon (`:`) in timezone
timezone = timezone.replace(ALL_COLONS, '');
var requestedTimezoneOffset = Date.parse('Jan 01, 1970 00:00:00 ' + timezone) / 60000;
@@ -1396,12 +1385,7 @@ function convertTimezoneToLocal(date, timezone, reverse) {
* @returns {string} Returns the string representation of the element.
*/
function startingTag(element) {
element = jqLite(element).clone();
try {
// turns out IE does not let you set .html() on elements which
// are not allowed to have children. So we just ignore it.
element.empty();
} catch (e) { /* empty */ }
element = jqLite(element).clone().empty();
var elemHtml = jqLite('<div>').append(element).html();
try {
return element[0].nodeType === NODE_TYPE_TEXT ? lowercase(elemHtml) :
@@ -1539,6 +1523,7 @@ function allowAutoBootstrap(document) {
var script = document.currentScript;
if (!script) {
// Support: IE 9-11 only
// IE does not have `document.currentScript`
return true;
}
+24
View File
@@ -5,7 +5,31 @@
*/
'use strict';
(function() {
// NOTE:
// These functions are copied here from `src/Angular.js`, because they are needed inside the
// `angular-loader.js` closure and need to be available before the main `angular.js` script has
// been loaded.
function isFunction(value) {return typeof value === 'function';}
function isDefined(value) {return typeof value !== 'undefined';}
function isNumber(value) {return typeof value === 'number';}
function isObject(value) {return value !== null && typeof value === 'object';}
function isScope(obj) {return obj && obj.$evalAsync && obj.$watch;}
function isUndefined(value) {return typeof value === 'undefined';}
function isWindow(obj) {return obj && obj.window === obj;}
function sliceArgs(args, startIndex) {return Array.prototype.slice.call(args, startIndex || 0);}
function toJsonReplacer(key, value) {
var val = value;
if (typeof key === 'string' && key.charAt(0) === '$' && key.charAt(1) === '$') {
val = undefined;
} else if (isWindow(value)) {
val = '$WINDOW';
} else if (value && window.document === value) {
val = '$DOCUMENT';
} else if (isScope(value)) {
val = '$SCOPE';
}
return val;
}
+50
View File
@@ -1,5 +1,55 @@
'use strict';
/* exported
minErrConfig,
errorHandlingConfig,
isValidObjectMaxDepth
*/
var minErrConfig = {
objectMaxDepth: 5
};
/**
* @ngdoc function
* @name angular.errorHandlingConfig
* @module ng
* @kind function
*
* @description
* Configure several aspects of error handling in AngularJS if used as a setter or return the
* current configuration if used as a getter. The following options are supported:
*
* - **objectMaxDepth**: The maximum depth to which objects are traversed when stringified for error messages.
*
* Omitted or undefined options will leave the corresponding configuration values unchanged.
*
* @param {Object=} config - The configuration object. May only contain the options that need to be
* updated. Supported keys:
*
* * `objectMaxDepth` **{Number}** - The max depth for stringifying objects. Setting to a
* non-positive or non-numeric value, removes the max depth limit.
* Default: 5
*/
function errorHandlingConfig(config) {
if (isObject(config)) {
if (isDefined(config.objectMaxDepth)) {
minErrConfig.objectMaxDepth = isValidObjectMaxDepth(config.objectMaxDepth) ? config.objectMaxDepth : NaN;
}
} else {
return minErrConfig;
}
}
/**
* @private
* @param {Number} maxDepth
* @return {boolean}
*/
function isValidObjectMaxDepth(maxDepth) {
return isNumber(maxDepth) && maxDepth > 0;
}
/**
* @description
*
+51
View File
@@ -180,6 +180,7 @@ var $$CoreAnimateQueueProvider = /** @this */ function() {
var $AnimateProvider = ['$provide', /** @this */ function($provide) {
var provider = this;
var classNameFilter = null;
var customFilter = null;
this.$$registeredAnimations = Object.create(null);
@@ -232,6 +233,51 @@ var $AnimateProvider = ['$provide', /** @this */ function($provide) {
$provide.factory(key, factory);
};
/**
* @ngdoc method
* @name $animateProvider#customFilter
*
* @description
* Sets and/or returns the custom filter function that is used to "filter" animations, i.e.
* determine if an animation is allowed or not. When no filter is specified (the default), no
* animation will be blocked. Setting the `customFilter` value will only allow animations for
* which the filter function's return value is truthy.
*
* This allows to easily create arbitrarily complex rules for filtering animations, such as
* allowing specific events only, or enabling animations on specific subtrees of the DOM, etc.
* Filtering animations can also boost performance for low-powered devices, as well as
* applications containing a lot of structural operations.
*
* <div class="alert alert-success">
* **Best Practice:**
* Keep the filtering function as lean as possible, because it will be called for each DOM
* action (e.g. insertion, removal, class change) performed by "animation-aware" directives.
* See {@link guide/animations#which-directives-support-animations- here} for a list of built-in
* directives that support animations.
* Performing computationally expensive or time-consuming operations on each call of the
* filtering function can make your animations sluggish.
* </div>
*
* **Note:** If present, `customFilter` will be checked before
* {@link $animateProvider#classNameFilter classNameFilter}.
*
* @param {Function=} filterFn - The filter function which will be used to filter all animations.
* If a falsy value is returned, no animation will be performed. The function will be called
* with the following arguments:
* - **node** `{DOMElement}` - The DOM element to be animated.
* - **event** `{String}` - The name of the animation event (e.g. `enter`, `leave`, `addClass`
* etc).
* - **options** `{Object}` - A collection of options/styles used for the animation.
* @return {Function} The current filter function or `null` if there is none set.
*/
this.customFilter = function(filterFn) {
if (arguments.length === 1) {
customFilter = isFunction(filterFn) ? filterFn : null;
}
return customFilter;
};
/**
* @ngdoc method
* @name $animateProvider#classNameFilter
@@ -243,6 +289,11 @@ var $AnimateProvider = ['$provide', /** @this */ function($provide) {
* When setting the `classNameFilter` value, animations will only be performed on elements
* that successfully match the filter expression. This in turn can boost performance
* for low-powered devices as well as applications containing a lot of structural operations.
*
* **Note:** If present, `classNameFilter` will be checked after
* {@link $animateProvider#customFilter customFilter}. If `customFilter` is present and returns
* false, `classNameFilter` will not be checked.
*
* @param {RegExp=} expression The className expression which will be checked against all animations
* @return {RegExp} The current CSS className expression value. If null then there is no expression value
*/
+8 -2
View File
@@ -1144,7 +1144,8 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
* @ngdoc method
* @name $compileProvider#component
* @module ng
* @param {string} name Name of the component in camelCase (i.e. `myComp` which will match `<my-comp>`)
* @param {string|Object} name Name of the component in camelCase (i.e. `myComp` which will match `<my-comp>`),
* or an object map of components where the keys are the names and the values are the component definition objects.
* @param {Object} options Component definition object (a simplified
* {@link ng.$compile#directive-definition-object directive definition object}),
* with the following properties (all optional):
@@ -1227,6 +1228,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
* See also {@link ng.$compileProvider#directive $compileProvider.directive()}.
*/
this.component = function registerComponent(name, options) {
if (!isString(name)) {
forEach(name, reverseParams(bind(this, registerComponent)));
return this;
}
var controller = options.controller || function() {};
function factory($injector) {
@@ -3162,7 +3168,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
}
linkQueue = null;
}).catch(function(error) {
if (error instanceof Error) {
if (isError(error)) {
$exceptionHandler(error);
}
});
+28 -7
View File
@@ -26,17 +26,23 @@ function nullFormRenameControl(control, name) {
* @property {boolean} $dirty True if user has already interacted with the form.
* @property {boolean} $valid True if all of the containing forms and controls are valid.
* @property {boolean} $invalid True if at least one containing control or form is invalid.
* @property {boolean} $pending True if at least one containing control or form is pending.
* @property {boolean} $submitted True if user has submitted the form even if its invalid.
*
* @property {Object} $error Is an object hash, containing references to controls or
* forms with failing validators, where:
* @property {Object} $pending An object hash, containing references to controls or forms with
* pending validators, where:
*
* - keys are validations tokens (error names).
* - values are arrays of controls or forms that have a pending validator for the given error name.
*
* See {@link form.FormController#$error $error} for a list of built-in validation tokens.
*
* @property {Object} $error An object hash, containing references to controls or forms with failing
* validators, where:
*
* - keys are validation tokens (error names),
* - values are arrays of controls or forms that have a failing validator for given error name.
* - values are arrays of controls or forms that have a failing validator for the given error name.
*
* Built-in validation tokens:
*
* - `email`
* - `max`
* - `maxlength`
@@ -282,9 +288,24 @@ FormController.prototype = {
* @name form.FormController#$setValidity
*
* @description
* Sets the validity of a form control.
* Change the validity state of the form, and notify the parent form (if any).
*
* This method will also propagate to parent forms.
* Application developers will rarely need to call this method directly. It is used internally, by
* {@link ngModel.NgModelController#$setValidity NgModelController.$setValidity()}, to propagate a
* control's validity state to the parent `FormController`.
*
* @param {string} validationErrorKey Name of the validator. The `validationErrorKey` will be
* assigned to either `$error[validationErrorKey]` or `$pending[validationErrorKey]` (for
* unfulfilled `$asyncValidators`), so that it is available for data-binding. The
* `validationErrorKey` should be in camelCase and will get converted into dash-case for
* class name. Example: `myError` will result in `ng-valid-my-error` and
* `ng-invalid-my-error` classes and can be bound to as `{{ someForm.$error.myError }}`.
* @param {boolean} isValid Whether the current state is valid (true), invalid (false), pending
* (undefined), or skipped (null). Pending is used for unfulfilled `$asyncValidators`.
* Skipped is used by AngularJS when validators do not run because of parse errors and when
* `$asyncValidators` do not run because any of the `$validators` failed.
* @param {NgModelController | FormController} controller - The controller whose validity state is
* triggering the change.
*/
addSetValidityMethod({
clazz: FormController,
+46 -9
View File
@@ -14,6 +14,13 @@ function classDirective(name, selector) {
return {
restrict: 'AC',
link: function(scope, element, attr) {
var expression = attr[name].trim();
var isOneTime = (expression.charAt(0) === ':') && (expression.charAt(1) === ':');
var watchInterceptor = isOneTime ? toFlatValue : toClassString;
var watchExpression = $parse(expression, watchInterceptor);
var watchAction = isOneTime ? ngClassOneTimeWatchAction : ngClassWatchAction;
var classCounts = element.data('$classCounts');
var oldModulo = true;
var oldClassString;
@@ -36,7 +43,7 @@ function classDirective(name, selector) {
scope.$watch(indexWatchExpression, ngClassIndexWatchAction);
}
scope.$watch($parse(attr[name], toClassString), ngClassWatchAction);
scope.$watch(watchExpression, watchAction, isOneTime);
function addClasses(classString) {
classString = digestClassCounts(split(classString), 1);
@@ -78,9 +85,9 @@ function classDirective(name, selector) {
}
function ngClassIndexWatchAction(newModulo) {
// This watch-action should run before the `ngClassWatchAction()`, thus it
// This watch-action should run before the `ngClass[OneTime]WatchAction()`, thus it
// adds/removes `oldClassString`. If the `ngClass` expression has changed as well, the
// `ngClassWatchAction()` will update the classes.
// `ngClass[OneTime]WatchAction()` will update the classes.
if (newModulo === selector) {
addClasses(oldClassString);
} else {
@@ -90,13 +97,15 @@ function classDirective(name, selector) {
oldModulo = newModulo;
}
function ngClassWatchAction(newClassString) {
// When using a one-time binding the newClassString will return
// the pre-interceptor value until the one-time is complete
if (!isString(newClassString)) {
newClassString = toClassString(newClassString);
}
function ngClassOneTimeWatchAction(newClassValue) {
var newClassString = toClassString(newClassValue);
if (newClassString !== oldClassString) {
ngClassWatchAction(newClassString);
}
}
function ngClassWatchAction(newClassString) {
if (oldModulo === selector) {
updateClasses(oldClassString, newClassString);
}
@@ -143,6 +152,34 @@ function classDirective(name, selector) {
return classString;
}
function toFlatValue(classValue) {
var flatValue = classValue;
if (isArray(classValue)) {
flatValue = classValue.map(toFlatValue);
} else if (isObject(classValue)) {
var hasUndefined = false;
flatValue = Object.keys(classValue).filter(function(key) {
var value = classValue[key];
if (!hasUndefined && isUndefined(value)) {
hasUndefined = true;
}
return value;
});
if (hasUndefined) {
// Prevent the `oneTimeLiteralWatchInterceptor` from unregistering
// the watcher, by including at least one `undefined` value.
flatValue.push(undefined);
}
}
return flatValue;
}
}
/**
+1 -1
View File
@@ -942,7 +942,7 @@ function setupModelWatcher(ctrl) {
* (for unfulfilled `$asyncValidators`), so that it is available for data-binding.
* The `validationErrorKey` should be in camelCase and will get converted into dash-case
* for class name. Example: `myError` will result in `ng-valid-my-error` and `ng-invalid-my-error`
* class and can be bound to as `{{someForm.someControl.$error.myError}}` .
* classes and can be bound to as `{{ someForm.someControl.$error.myError }}`.
* @param {boolean} isValid Whether the current state is valid (true), invalid (false), pending (undefined),
* or skipped (null). Pending is used for unfulfilled `$asyncValidators`.
* Skipped is used by Angular when validators do not run because of parse errors and
+22 -30
View File
@@ -407,7 +407,8 @@ var ngOptionsDirective = ['$compile', '$document', '$parse', function($compile,
}
// we can't just jqLite('<option>') since jqLite is not smart enough
// Support: IE 9 only
// We can't just jqLite('<option>') since jqLite is not smart enough
// to create it in <select> and IE barfs otherwise.
var optionTemplate = window.document.createElement('option'),
optGroupTemplate = window.document.createElement('optgroup');
@@ -428,6 +429,9 @@ var ngOptionsDirective = ['$compile', '$document', '$parse', function($compile,
}
}
// The empty option will be compiled and rendered before we first generate the options
selectElement.empty();
var providedEmptyOption = !!selectCtrl.emptyOption;
var unknownOption = jqLite(optionTemplate.cloneNode(false));
@@ -449,12 +453,15 @@ var ngOptionsDirective = ['$compile', '$document', '$parse', function($compile,
if (!multiple) {
selectCtrl.writeValue = function writeNgOptionsValue(value) {
var selectedOption = options.selectValueMap[selectElement.val()];
// The options might not be defined yet when ngModel tries to render
if (!options) return;
var selectedOption = selectElement[0].options[selectElement[0].selectedIndex];
var option = options.getOptionFromViewValue(value);
// Make sure to remove the selected attribute from the previously selected option
// Otherwise, screen readers might get confused
if (selectedOption) selectedOption.element.removeAttribute('selected');
if (selectedOption) selectedOption.removeAttribute('selected');
if (option) {
// Don't update the option when it is already selected.
@@ -464,7 +471,6 @@ var ngOptionsDirective = ['$compile', '$document', '$parse', function($compile,
if (selectElement[0].value !== option.selectValue) {
selectCtrl.removeUnknownOption();
selectCtrl.unselectEmptyOption();
selectElement[0].value = option.selectValue;
option.element.selected = true;
@@ -472,14 +478,7 @@ var ngOptionsDirective = ['$compile', '$document', '$parse', function($compile,
option.element.setAttribute('selected', 'selected');
} else {
if (providedEmptyOption) {
selectCtrl.selectEmptyOption();
} else if (selectCtrl.unknownOption.parent().length) {
selectCtrl.updateUnknownOption(value);
} else {
selectCtrl.renderUnknownOption(value);
}
selectCtrl.selectUnknownOrEmptyOption(value);
}
};
@@ -508,9 +507,11 @@ var ngOptionsDirective = ['$compile', '$document', '$parse', function($compile,
} else {
selectCtrl.writeValue = function writeNgOptionsMultiple(values) {
// The options might not be defined yet when ngModel tries to render
if (!options) return;
// Only set `<option>.selected` if necessary, in order to prevent some browsers from
// scrolling to `<option>` elements that are outside the `<select>` element's viewport.
var selectedOptions = values && values.map(getAndUpdateSelectedOption) || [];
options.items.forEach(function(option) {
@@ -552,13 +553,11 @@ var ngOptionsDirective = ['$compile', '$document', '$parse', function($compile,
if (providedEmptyOption) {
// we need to remove it before calling selectElement.empty() because otherwise IE will
// remove the label from the element. wtf?
selectCtrl.emptyOption.remove();
// compile the element since there might be bindings in it
$compile(selectCtrl.emptyOption)(scope);
selectElement.prepend(selectCtrl.emptyOption);
if (selectCtrl.emptyOption[0].nodeType === NODE_TYPE_COMMENT) {
// This means the empty option has currently no actual DOM node, probably because
// it has been modified by a transclusion directive.
@@ -576,8 +575,12 @@ var ngOptionsDirective = ['$compile', '$document', '$parse', function($compile,
ngModelCtrl.$render();
optionEl.on('$destroy', function() {
var needsRerender = selectCtrl.$isEmptyOptionSelected();
selectCtrl.hasEmptyOption = false;
selectCtrl.emptyOption = undefined;
if (needsRerender) ngModelCtrl.$render();
});
}
};
@@ -590,12 +593,6 @@ var ngOptionsDirective = ['$compile', '$document', '$parse', function($compile,
}
selectElement.empty();
// We need to do this here to ensure that the options object is defined
// when we first hit it in writeNgOptionsValue
updateOptions();
// We will re-render the option elements if the option values or labels change
scope.$watchCollection(ngOptions.getWatchables, updateOptions);
@@ -619,7 +616,8 @@ var ngOptionsDirective = ['$compile', '$document', '$parse', function($compile,
function updateOptionElement(option, element) {
option.element = element;
element.disabled = option.disabled;
// NOTE: The label must be set before the value, otherwise IE10/11/EDGE create unresponsive
// Support: IE 11 only, Edge 12-13 only
// NOTE: The label must be set before the value, otherwise IE 11 & Edge create unresponsive
// selects in certain circumstances when multiple selects are next to each other and display
// the option list in listbox style, i.e. the select is [multiple], or specifies a [size].
// See https://github.com/angular/angular.js/issues/11314 for more info.
@@ -655,11 +653,6 @@ var ngOptionsDirective = ['$compile', '$document', '$parse', function($compile,
var groupElementMap = {};
// Ensure that the empty option is always there if it was explicitly provided
if (providedEmptyOption) {
selectElement.prepend(selectCtrl.emptyOption);
}
options.items.forEach(function addOption(option) {
var groupElement;
@@ -704,7 +697,6 @@ var ngOptionsDirective = ['$compile', '$document', '$parse', function($compile,
ngModelCtrl.$render();
}
}
}
}
+1 -1
View File
@@ -429,7 +429,7 @@ var ngRepeatDirective = ['$parse', '$animate', '$compile', function($parse, $ani
// Store a list of elements from previous run. This is a hash where key is the item from the
// iterator, and the value is objects with following properties.
// - scope: bound scope
// - element: previous element.
// - clone: previous element.
// - index: position
//
// We are using no-proto object so that we don't need to guard against inherited props via
+196 -20
View File
@@ -5,7 +5,7 @@
var noopNgModelController = { $setViewValue: noop, $render: noop };
function setOptionSelectedStatus(optionEl, value) {
optionEl.prop('selected', value); // needed for IE
optionEl.prop('selected', value);
/**
* When unselecting an option, setting the property to null / false should be enough
* However, screenreaders might react to the selected attribute instead, see
@@ -19,10 +19,120 @@ function setOptionSelectedStatus(optionEl, value) {
/**
* @ngdoc type
* @name select.SelectController
*
* @description
* The controller for the `<select>` directive. This provides support for reading
* and writing the selected value(s) of the control and also coordinates dynamically
* added `<option>` elements, perhaps by an `ngRepeat` directive.
* The controller for the {@link ng.select select} directive. The controller exposes
* a few utility methods that can be used to augment the behavior of a regular or an
* {@link ng.ngOptions ngOptions} select element.
*
* @example
* ### Set a custom error when the unknown option is selected
*
* This example sets a custom error "unknownValue" on the ngModelController
* when the select element's unknown option is selected, i.e. when the model is set to a value
* that is not matched by any option.
*
* <example name="select-unknown-value-error" module="staticSelect">
* <file name="index.html">
* <div ng-controller="ExampleController">
* <form name="myForm">
* <label for="testSelect"> Single select: </label><br>
* <select name="testSelect" ng-model="selected" unknown-value-error>
* <option value="option-1">Option 1</option>
* <option value="option-2">Option 2</option>
* </select><br>
* <span ng-if="myForm.testSelect.$error.unknownValue">Error: The current model doesn't match any option</span>
*
* <button ng-click="forceUnknownOption()">Force unknown option</button><br>
* </form>
* </div>
* </file>
* <file name="app.js">
* angular.module('staticSelect', [])
* .controller('ExampleController', ['$scope', function($scope) {
* $scope.selected = null;
*
* $scope.forceUnknownOption = function() {
* $scope.selected = 'nonsense';
* };
* }])
* .directive('unknownValueError', function() {
* return {
* require: ['ngModel', 'select'],
* link: function(scope, element, attrs, ctrls) {
* var ngModelCtrl = ctrls[0];
* var selectCtrl = ctrls[1];
*
* ngModelCtrl.$validators.unknownValue = function(modelValue, viewValue) {
* if (selectCtrl.$isUnknownOptionSelected()) {
* return false;
* }
*
* return true;
* };
* }
*
* };
* });
* </file>
*</example>
*
*
* @example
* ### Set the "required" error when the unknown option is selected.
*
* By default, the "required" error on the ngModelController is only set on a required select
* when the empty option is selected. This example adds a custom directive that also sets the
* error when the unknown option is selected.
*
* <example name="select-unknown-value-required" module="staticSelect">
* <file name="index.html">
* <div ng-controller="ExampleController">
* <form name="myForm">
* <label for="testSelect"> Select: </label><br>
* <select name="testSelect" ng-model="selected" unknown-value-required>
* <option value="option-1">Option 1</option>
* <option value="option-2">Option 2</option>
* </select><br>
* <span ng-if="myForm.testSelect.$error.required">Error: Please select a value</span><br>
*
* <button ng-click="forceUnknownOption()">Force unknown option</button><br>
* </form>
* </div>
* </file>
* <file name="app.js">
* angular.module('staticSelect', [])
* .controller('ExampleController', ['$scope', function($scope) {
* $scope.selected = null;
*
* $scope.forceUnknownOption = function() {
* $scope.selected = 'nonsense';
* };
* }])
* .directive('unknownValueRequired', function() {
* return {
* priority: 1, // This directive must run after the required directive has added its validator
* require: ['ngModel', 'select'],
* link: function(scope, element, attrs, ctrls) {
* var ngModelCtrl = ctrls[0];
* var selectCtrl = ctrls[1];
*
* var originalRequiredValidator = ngModelCtrl.$validators.required;
*
* ngModelCtrl.$validators.required = function() {
* if (attrs.required && selectCtrl.$isUnknownOptionSelected()) {
* return false;
* }
*
* return originalRequiredValidator.apply(this, arguments);
* };
* }
* };
* });
* </file>
*</example>
*
*
*/
var SelectController =
['$element', '$scope', /** @this */ function($element, $scope) {
@@ -40,15 +150,18 @@ var SelectController =
// does not match any of the options. When it is rendered the value of the unknown
// option is '? XXX ?' where XXX is the hashKey of the value that is not known.
//
// Support: IE 9 only
// We can't just jqLite('<option>') since jqLite is not smart enough
// to create it in <select> and IE barfs otherwise.
self.unknownOption = jqLite(window.document.createElement('option'));
// The empty option is an option with the value '' that te application developer can
// provide inside the select. When the model changes to a value that doesn't match an option,
// it is selected - so if an empty option is provided, no unknown option is generated.
// However, the empty option is not removed when the model matches an option. It is always selectable
// and indicates that a "null" selection has been made.
// The empty option is an option with the value '' that the application developer can
// provide inside the select. It is always selectable and indicates that a "null" selection has
// been made by the user.
// If the select has an empty option, and the model of the select is set to "undefined" or "null",
// the empty option is selected.
// If the model is set to a different unmatched value, the unknown option is rendered and
// selected, i.e both are present, because a "null" selection and an unknown value are different.
self.hasEmptyOption = false;
self.emptyOption = undefined;
@@ -84,7 +197,7 @@ var SelectController =
self.unselectEmptyOption = function() {
if (self.hasEmptyOption) {
self.emptyOption.removeAttr('selected');
setOptionSelectedStatus(self.emptyOption, false);
}
};
@@ -126,14 +239,7 @@ var SelectController =
var selectedOption = $element[0].options[$element[0].selectedIndex];
setOptionSelectedStatus(jqLite(selectedOption), true);
} else {
if (value == null && self.emptyOption) {
self.removeUnknownOption();
self.selectEmptyOption();
} else if (self.unknownOption.parent().length) {
self.updateUnknownOption(value);
} else {
self.renderUnknownOption(value);
}
self.selectUnknownOrEmptyOption(value);
}
};
@@ -176,6 +282,59 @@ var SelectController =
return !!optionsMap.get(value);
};
/**
* @ngdoc method
* @name select.SelectController#$hasEmptyOption
*
* @description
*
* Returns `true` if the select element currently has an empty option
* element, i.e. an option that signifies that the select is empty / the selection is null.
*
*/
self.$hasEmptyOption = function() {
return self.hasEmptyOption;
};
/**
* @ngdoc method
* @name select.SelectController#$isUnknownOptionSelected
*
* @description
*
* Returns `true` if the select element's unknown option is selected. The unknown option is added
* and automatically selected whenever the select model doesn't match any option.
*
*/
self.$isUnknownOptionSelected = function() {
// Presence of the unknown option means it is selected
return $element[0].options[0] === self.unknownOption[0];
};
/**
* @ngdoc method
* @name select.SelectController#$isEmptyOptionSelected
*
* @description
*
* Returns `true` if the select element has an empty option and this empty option is currently
* selected. Returns `false` if the select element has no empty option or it is not selected.
*
*/
self.$isEmptyOptionSelected = function() {
return self.hasEmptyOption && $element[0].options[$element[0].selectedIndex] === self.emptyOption[0];
};
self.selectUnknownOrEmptyOption = function(value) {
if (value == null && self.emptyOption) {
self.removeUnknownOption();
self.selectEmptyOption();
} else if (self.unknownOption.parent().length) {
self.updateUnknownOption(value);
} else {
self.renderUnknownOption(value);
}
};
var renderScheduled = false;
function scheduleRender() {
@@ -324,6 +483,9 @@ var SelectController =
* the content of the `value` attribute or the textContent of the `<option>`, if the value attribute is missing.
* Value and textContent can be interpolated.
*
* The {@link select.SelectController select controller} exposes utility functions that can be used
* to manipulate the select's behavior.
*
* ## Matching model and option values
*
* In general, the match between the model and an option is evaluated by strictly comparing the model
@@ -376,6 +538,19 @@ var SelectController =
* @param {string=} ngAttrSize sets the size of the select element dynamically. Uses the
* {@link guide/interpolation#-ngattr-for-binding-to-arbitrary-attributes ngAttr} directive.
*
*
* @knownIssue
*
* In Firefox, the select model is only updated when the select element is blurred. For example,
* when switching between options with the keyboard, the select model is only set to the
* currently selected option when the select is blurred, e.g via tab key or clicking the mouse
* outside the select.
*
* This is due to an ambiguity in the select element specification. See the
* [issue on the Firefox bug tracker](https://bugzilla.mozilla.org/show_bug.cgi?id=126379)
* for more information, and this
* [Github comment for a workaround](https://github.com/angular/angular.js/issues/9134#issuecomment-130800488)
*
* @example
* ### Simple `select` elements with static options
*
@@ -620,10 +795,11 @@ var selectDirective = function() {
includes(value, selectCtrl.selectValueMap[option.value]));
var currentlySelected = option.selected;
// IE and Edge, adding options to the selection via shift+click/UP/DOWN,
// Support: IE 9-11 only, Edge 12-15+
// In IE and Edge adding options to the selection via shift+click/UP/DOWN
// will de-select already selected options if "selected" on those options was set
// more than once (i.e. when the options were already selected)
// So we only modify the selected property if neccessary.
// So we only modify the selected property if necessary.
// Note: this behavior cannot be replicated via unit tests because it only shows in the
// actual user interface.
if (shouldBeSelected !== currentlySelected) {
+1 -1
View File
@@ -46,7 +46,7 @@
*
* @param {function(actual, expected)|true|false} [comparator] Comparator which is used in
* determining if values retrieved using `expression` (when it is not a function) should be
* considered a match based on the the expected value (from the filter expression) and actual
* considered a match based on the expected value (from the filter expression) and actual
* value (from the object in the array).
*
* Can be one of:
+20 -1
View File
@@ -698,6 +698,9 @@ function jsonFilter() {
* @kind function
* @description
* Converts string to lowercase.
*
* See the {@link ng.uppercase uppercase filter documentation} for a functionally identical example.
*
* @see angular.lowercase
*/
var lowercaseFilter = valueFn(lowercase);
@@ -709,6 +712,22 @@ var lowercaseFilter = valueFn(lowercase);
* @kind function
* @description
* Converts string to uppercase.
* @see angular.uppercase
* @example
<example module="uppercaseFilterExample" name="filter-uppercase">
<file name="index.html">
<script>
angular.module('uppercaseFilterExample', [])
.controller('ExampleController', ['$scope', function($scope) {
$scope.title = 'This is a title';
}]);
</script>
<div ng-controller="ExampleController">
<!-- This title should be formatted normally -->
<h1>{{title}}</h1>
<!-- This title should be capitalized -->
<h1>{{title | uppercase}}</h1>
</div>
</file>
</example>
*/
var uppercaseFilter = valueFn(uppercase);
+4 -1
View File
@@ -53,6 +53,9 @@
* dummy predicate that returns the item's index as `value`.
* (If you are using a custom comparator, make sure it can handle this predicate as well.)
*
* If a custom comparator still can't distinguish between two items, then they will be sorted based
* on their index using the built-in comparator.
*
* Finally, in an attempt to simplify things, if a predicate returns an object as the extracted
* value for an item, `orderBy` will try to convert that object to a primitive value, before passing
* it to the comparator. The following rules govern the conversion:
@@ -599,7 +602,7 @@ function orderByFilter($parse) {
}
}
return compare(v1.tieBreaker, v2.tieBreaker) * descending;
return (compare(v1.tieBreaker, v2.tieBreaker) || defaultCompare(v1.tieBreaker, v2.tieBreaker)) * descending;
}
};
+32 -12
View File
@@ -266,12 +266,6 @@ function $HttpProvider() {
* {@link ng.$cacheFactory `$cacheFactory`} to enable or disable caching of HTTP responses
* by default. See {@link $http#caching $http Caching} for more information.
*
* - **`defaults.xsrfCookieName`** - {string} - Name of cookie containing the XSRF token.
* Defaults value is `'XSRF-TOKEN'`.
*
* - **`defaults.xsrfHeaderName`** - {string} - Name of HTTP header to populate with the
* XSRF token. Defaults value is `'X-XSRF-TOKEN'`.
*
* - **`defaults.headers`** - {Object} - Default headers for all $http requests.
* Refer to {@link ng.$http#setting-http-headers $http} for documentation on
* setting default headers.
@@ -280,15 +274,38 @@ function $HttpProvider() {
* - **`defaults.headers.put`**
* - **`defaults.headers.patch`**
*
* - **`defaults.jsonpCallbackParam`** - `{string}` - the name of the query parameter that passes the name of the
* callback in a JSONP request. The value of this parameter will be replaced with the expression generated by the
* {@link $jsonpCallbacks} service. Defaults to `'callback'`.
*
* - **`defaults.paramSerializer`** - `{string|function(Object<string,string>):string}` - A function
* used to the prepare string representation of request parameters (specified as an object).
* If specified as string, it is interpreted as a function registered with the {@link auto.$injector $injector}.
* Defaults to {@link ng.$httpParamSerializer $httpParamSerializer}.
*
* - **`defaults.jsonpCallbackParam`** - `{string}` - the name of the query parameter that passes the name of the
* callback in a JSONP request. The value of this parameter will be replaced with the expression generated by the
* {@link $jsonpCallbacks} service. Defaults to `'callback'`.
* - **`defaults.transformRequest`** -
* `{Array<function(data, headersGetter)>|function(data, headersGetter)}` -
* An array of functions (or a single function) which are applied to the request data.
* By default, this is an array with one request transformation function:
*
* - If the `data` property of the request configuration object contains an object, serialize it
* into JSON format.
*
* - **`defaults.transformResponse`** -
* `{Array<function(data, headersGetter, status)>|function(data, headersGetter, status)}` -
* An array of functions (or a single function) which are applied to the response data. By default,
* this is an array which applies one response transformation function that does two things:
*
* - If XSRF prefix is detected, strip it
* (see {@link ng.$http#security-considerations Security Considerations in the $http docs}).
* - If the `Content-Type` is `application/json` or the response looks like JSON,
* deserialize it using a JSON parser.
*
* - **`defaults.xsrfCookieName`** - {string} - Name of cookie containing the XSRF token.
* Defaults value is `'XSRF-TOKEN'`.
*
* - **`defaults.xsrfHeaderName`** - {string} - Name of HTTP header to populate with the
* XSRF token. Defaults value is `'X-XSRF-TOKEN'`.
*
**/
var defaults = this.defaults = {
@@ -552,15 +569,18 @@ function $HttpProvider() {
*
* Angular provides the following default transformations:
*
* Request transformations (`$httpProvider.defaults.transformRequest` and `$http.defaults.transformRequest`):
* Request transformations (`$httpProvider.defaults.transformRequest` and `$http.defaults.transformRequest`) is
* an array with one function that does the following:
*
* - If the `data` property of the request configuration object contains an object, serialize it
* into JSON format.
*
* Response transformations (`$httpProvider.defaults.transformResponse` and `$http.defaults.transformResponse`):
* Response transformations (`$httpProvider.defaults.transformResponse` and `$http.defaults.transformResponse`) is
* an array with one function that does the following:
*
* - If XSRF prefix is detected, strip it (see Security Considerations section below).
* - If JSON response is detected, deserialize it using a JSON parser.
* - If the `Content-Type` is `application/json` or the response looks like JSON,
* deserialize it using a JSON parser.
*
*
* ### Overriding the Default Transformations Per Request
+1 -1
View File
@@ -190,7 +190,7 @@ function $IntervalProvider() {
interval.cancel = function(promise) {
if (promise && promise.$$intervalId in intervals) {
// Interval cancels should not report as unhandled promise.
intervals[promise.$$intervalId].promise.catch(noop);
markQExceptionHandled(intervals[promise.$$intervalId].promise);
intervals[promise.$$intervalId].reject('canceled');
$window.clearInterval(promise.$$intervalId);
delete intervals[promise.$$intervalId];
+19 -23
View File
@@ -11,6 +11,14 @@
*
* The main purpose of this service is to simplify debugging and troubleshooting.
*
* To reveal the location of the calls to `$log` in the JavaScript console,
* you can "blackbox" the AngularJS source in your browser:
*
* [Mozilla description of blackboxing](https://developer.mozilla.org/en-US/docs/Tools/Debugger/How_to/Black_box_a_source).
* [Chrome description of blackboxing](https://developer.chrome.com/devtools/docs/blackboxing).
*
* Note: Not all browsers support blackboxing.
*
* The default is to log `debug` messages. You can use
* {@link ng.$logProvider ng.$logProvider#debugEnabled} to change this.
*
@@ -132,7 +140,7 @@ function $LogProvider() {
};
function formatError(arg) {
if (arg instanceof Error) {
if (isError(arg)) {
if (arg.stack && formatStackTrace) {
arg = (arg.message && arg.stack.indexOf(arg.message) === -1)
? 'Error: ' + arg.message + '\n' + arg.stack
@@ -146,29 +154,17 @@ function $LogProvider() {
function consoleLog(type) {
var console = $window.console || {},
logFn = console[type] || console.log || noop,
hasApply = false;
logFn = console[type] || console.log || noop;
// Note: reading logFn.apply throws an error in IE11 in IE8 document mode.
// The reason behind this is that console.log has type "object" in IE8...
try {
hasApply = !!logFn.apply;
} catch (e) { /* empty */ }
if (hasApply) {
return function() {
var args = [];
forEach(arguments, function(arg) {
args.push(formatError(arg));
});
return logFn.apply(console, args);
};
}
// we are IE which either doesn't have window.console => this is noop and we do nothing,
// or we are IE where console.log doesn't have apply so we log at least first 2 args
return function(arg1, arg2) {
logFn(arg1, arg2 == null ? '' : arg2);
return function() {
var args = [];
forEach(arguments, function(arg) {
args.push(formatError(arg));
});
// Support: IE 9 only
// console methods don't inherit from Function.prototype in IE 9 so we can't
// call `logFn.apply(console, args)` directly.
return Function.prototype.apply.call(logFn, console, args);
};
}
}];
+112 -54
View File
@@ -622,15 +622,47 @@ function isStateless($filter, filterName) {
return !fn.$stateful;
}
function findConstantAndWatchExpressions(ast, $filter) {
var PURITY_ABSOLUTE = 1;
var PURITY_RELATIVE = 2;
// Detect nodes which could depend on non-shallow state of objects
function isPure(node, parentIsPure) {
switch (node.type) {
// Computed members might invoke a stateful toString()
case AST.MemberExpression:
if (node.computed) {
return false;
}
break;
// Unary always convert to primative
case AST.UnaryExpression:
return PURITY_ABSOLUTE;
// The binary + operator can invoke a stateful toString().
case AST.BinaryExpression:
return node.operator !== '+' ? PURITY_ABSOLUTE : false;
// Functions / filters probably read state from within objects
case AST.CallExpression:
return false;
}
return (undefined === parentIsPure) ? PURITY_RELATIVE : parentIsPure;
}
function findConstantAndWatchExpressions(ast, $filter, parentIsPure) {
var allConstants;
var argsToWatch;
var isStatelessFilter;
var astIsPure = ast.isPure = isPure(ast, parentIsPure);
switch (ast.type) {
case AST.Program:
allConstants = true;
forEach(ast.body, function(expr) {
findConstantAndWatchExpressions(expr.expression, $filter);
findConstantAndWatchExpressions(expr.expression, $filter, astIsPure);
allConstants = allConstants && expr.expression.constant;
});
ast.constant = allConstants;
@@ -640,26 +672,26 @@ function findConstantAndWatchExpressions(ast, $filter) {
ast.toWatch = [];
break;
case AST.UnaryExpression:
findConstantAndWatchExpressions(ast.argument, $filter);
findConstantAndWatchExpressions(ast.argument, $filter, astIsPure);
ast.constant = ast.argument.constant;
ast.toWatch = ast.argument.toWatch;
break;
case AST.BinaryExpression:
findConstantAndWatchExpressions(ast.left, $filter);
findConstantAndWatchExpressions(ast.right, $filter);
findConstantAndWatchExpressions(ast.left, $filter, astIsPure);
findConstantAndWatchExpressions(ast.right, $filter, astIsPure);
ast.constant = ast.left.constant && ast.right.constant;
ast.toWatch = ast.left.toWatch.concat(ast.right.toWatch);
break;
case AST.LogicalExpression:
findConstantAndWatchExpressions(ast.left, $filter);
findConstantAndWatchExpressions(ast.right, $filter);
findConstantAndWatchExpressions(ast.left, $filter, astIsPure);
findConstantAndWatchExpressions(ast.right, $filter, astIsPure);
ast.constant = ast.left.constant && ast.right.constant;
ast.toWatch = ast.constant ? [] : [ast];
break;
case AST.ConditionalExpression:
findConstantAndWatchExpressions(ast.test, $filter);
findConstantAndWatchExpressions(ast.alternate, $filter);
findConstantAndWatchExpressions(ast.consequent, $filter);
findConstantAndWatchExpressions(ast.test, $filter, astIsPure);
findConstantAndWatchExpressions(ast.alternate, $filter, astIsPure);
findConstantAndWatchExpressions(ast.consequent, $filter, astIsPure);
ast.constant = ast.test.constant && ast.alternate.constant && ast.consequent.constant;
ast.toWatch = ast.constant ? [] : [ast];
break;
@@ -668,9 +700,9 @@ function findConstantAndWatchExpressions(ast, $filter) {
ast.toWatch = [ast];
break;
case AST.MemberExpression:
findConstantAndWatchExpressions(ast.object, $filter);
findConstantAndWatchExpressions(ast.object, $filter, astIsPure);
if (ast.computed) {
findConstantAndWatchExpressions(ast.property, $filter);
findConstantAndWatchExpressions(ast.property, $filter, astIsPure);
}
ast.constant = ast.object.constant && (!ast.computed || ast.property.constant);
ast.toWatch = [ast];
@@ -680,7 +712,7 @@ function findConstantAndWatchExpressions(ast, $filter) {
allConstants = isStatelessFilter;
argsToWatch = [];
forEach(ast.arguments, function(expr) {
findConstantAndWatchExpressions(expr, $filter);
findConstantAndWatchExpressions(expr, $filter, astIsPure);
allConstants = allConstants && expr.constant;
if (!expr.constant) {
argsToWatch.push.apply(argsToWatch, expr.toWatch);
@@ -690,8 +722,8 @@ function findConstantAndWatchExpressions(ast, $filter) {
ast.toWatch = isStatelessFilter ? argsToWatch : [ast];
break;
case AST.AssignmentExpression:
findConstantAndWatchExpressions(ast.left, $filter);
findConstantAndWatchExpressions(ast.right, $filter);
findConstantAndWatchExpressions(ast.left, $filter, astIsPure);
findConstantAndWatchExpressions(ast.right, $filter, astIsPure);
ast.constant = ast.left.constant && ast.right.constant;
ast.toWatch = [ast];
break;
@@ -699,7 +731,7 @@ function findConstantAndWatchExpressions(ast, $filter) {
allConstants = true;
argsToWatch = [];
forEach(ast.elements, function(expr) {
findConstantAndWatchExpressions(expr, $filter);
findConstantAndWatchExpressions(expr, $filter, astIsPure);
allConstants = allConstants && expr.constant;
if (!expr.constant) {
argsToWatch.push.apply(argsToWatch, expr.toWatch);
@@ -712,13 +744,13 @@ function findConstantAndWatchExpressions(ast, $filter) {
allConstants = true;
argsToWatch = [];
forEach(ast.properties, function(property) {
findConstantAndWatchExpressions(property.value, $filter);
findConstantAndWatchExpressions(property.value, $filter, astIsPure);
allConstants = allConstants && property.value.constant && !property.computed;
if (!property.value.constant) {
argsToWatch.push.apply(argsToWatch, property.value.toWatch);
}
if (property.computed) {
findConstantAndWatchExpressions(property.key, $filter);
findConstantAndWatchExpressions(property.key, $filter, astIsPure);
if (!property.key.constant) {
argsToWatch.push.apply(argsToWatch, property.key.toWatch);
}
@@ -803,7 +835,7 @@ ASTCompiler.prototype = {
var intoId = self.nextId();
self.recurse(watch, intoId);
self.return_(intoId);
self.state.inputs.push(fnKey);
self.state.inputs.push({name: fnKey, isPure: watch.isPure});
watch.watchId = key;
});
this.state.computing = 'fn';
@@ -839,13 +871,16 @@ ASTCompiler.prototype = {
watchFns: function() {
var result = [];
var fns = this.state.inputs;
var inputs = this.state.inputs;
var self = this;
forEach(fns, function(name) {
result.push('var ' + name + '=' + self.generateFunction(name, 's'));
forEach(inputs, function(input) {
result.push('var ' + input.name + '=' + self.generateFunction(input.name, 's'));
if (input.isPure) {
result.push(input.name, '.isPure=' + JSON.stringify(input.isPure) + ';');
}
});
if (fns.length) {
result.push('fn.inputs=[' + fns.join(',') + '];');
if (inputs.length) {
result.push('fn.inputs=[' + inputs.map(function(i) { return i.name; }).join(',') + '];');
}
return result.join('');
},
@@ -1251,6 +1286,7 @@ ASTInterpreter.prototype = {
inputs = [];
forEach(toWatch, function(watch, key) {
var input = self.recurse(watch);
input.isPure = watch.isPure;
watch.input = input;
inputs.push(input);
watch.watchId = key;
@@ -1765,8 +1801,8 @@ function $ParseProvider() {
if (parsedExpression.constant) {
parsedExpression.$$watchDelegate = constantWatchDelegate;
} else if (oneTime) {
parsedExpression.oneTime = true;
parsedExpression.$$watchDelegate = oneTimeWatchDelegate;
parsedExpression.$$watchDelegate = parsedExpression.literal ?
oneTimeLiteralWatchDelegate : oneTimeWatchDelegate;
} else if (parsedExpression.inputs) {
parsedExpression.$$watchDelegate = inputsWatchDelegate;
}
@@ -1817,7 +1853,7 @@ function $ParseProvider() {
inputExpressions = inputExpressions[0];
return scope.$watch(function expressionInputWatch(scope) {
var newInputValue = inputExpressions(scope);
if (!expressionInputDirtyCheck(newInputValue, oldInputValueOf, parsedExpression.literal)) {
if (!expressionInputDirtyCheck(newInputValue, oldInputValueOf, inputExpressions.isPure)) {
lastResult = parsedExpression(scope, undefined, undefined, [newInputValue]);
oldInputValueOf = newInputValue && getValueOf(newInputValue);
}
@@ -1837,7 +1873,7 @@ function $ParseProvider() {
for (var i = 0, ii = inputExpressions.length; i < ii; i++) {
var newInputValue = inputExpressions[i](scope);
if (changed || (changed = !expressionInputDirtyCheck(newInputValue, oldInputValueOfValues[i], parsedExpression.literal))) {
if (changed || (changed = !expressionInputDirtyCheck(newInputValue, oldInputValueOfValues[i], inputExpressions[i].isPure))) {
oldInputValues[i] = newInputValue;
oldInputValueOfValues[i] = newInputValue && getValueOf(newInputValue);
}
@@ -1852,7 +1888,6 @@ function $ParseProvider() {
}
function oneTimeWatchDelegate(scope, listener, objectEquality, parsedExpression, prettyPrintExpression) {
var isDone = parsedExpression.literal ? isAllDefined : isDefined;
var unwatch, lastValue;
if (parsedExpression.inputs) {
unwatch = inputsWatchDelegate(scope, oneTimeListener, objectEquality, parsedExpression, prettyPrintExpression);
@@ -1869,9 +1904,9 @@ function $ParseProvider() {
if (isFunction(listener)) {
listener(value, old, scope);
}
if (isDone(value)) {
if (isDefined(value)) {
scope.$$postDigest(function() {
if (isDone(lastValue)) {
if (isDefined(lastValue)) {
unwatch();
}
});
@@ -1879,12 +1914,31 @@ function $ParseProvider() {
}
}
function isAllDefined(value) {
var allDefined = true;
forEach(value, function(val) {
if (!isDefined(val)) allDefined = false;
});
return allDefined;
function oneTimeLiteralWatchDelegate(scope, listener, objectEquality, parsedExpression) {
var unwatch, lastValue;
unwatch = scope.$watch(function oneTimeWatch(scope) {
return parsedExpression(scope);
}, function oneTimeListener(value, old, scope) {
lastValue = value;
if (isFunction(listener)) {
listener(value, old, scope);
}
if (isAllDefined(value)) {
scope.$$postDigest(function() {
if (isAllDefined(lastValue)) unwatch();
});
}
}, objectEquality);
return unwatch;
function isAllDefined(value) {
var allDefined = true;
forEach(value, function(val) {
if (!isDefined(val)) allDefined = false;
});
return allDefined;
}
}
function constantWatchDelegate(scope, listener, objectEquality, parsedExpression) {
@@ -1900,39 +1954,43 @@ function $ParseProvider() {
var watchDelegate = parsedExpression.$$watchDelegate;
var useInputs = false;
var isDone = parsedExpression.literal ? isAllDefined : isDefined;
var regularWatch =
watchDelegate !== oneTimeLiteralWatchDelegate &&
watchDelegate !== oneTimeWatchDelegate;
function regularInterceptedExpression(scope, locals, assign, inputs) {
var fn = regularWatch ? function regularInterceptedExpression(scope, locals, assign, inputs) {
var value = useInputs && inputs ? inputs[0] : parsedExpression(scope, locals, assign, inputs);
return interceptorFn(value, scope, locals);
}
function oneTimeInterceptedExpression(scope, locals, assign, inputs) {
var value = useInputs && inputs ? inputs[0] : parsedExpression(scope, locals, assign, inputs);
} : function oneTimeInterceptedExpression(scope, locals, assign, inputs) {
var value = parsedExpression(scope, locals, assign, inputs);
var result = interceptorFn(value, scope, locals);
// we only return the interceptor's result if the
// initial value is defined (for bind-once)
return isDone(value) ? result : value;
}
return isDefined(value) ? result : value;
};
var fn = parsedExpression.oneTime ? oneTimeInterceptedExpression : regularInterceptedExpression;
// Propogate the literal/oneTime attributes
fn.literal = parsedExpression.literal;
fn.oneTime = parsedExpression.oneTime;
// Propagate or create inputs / $$watchDelegates
// Propagate $$watchDelegates other then inputsWatchDelegate
useInputs = !parsedExpression.inputs;
if (watchDelegate && watchDelegate !== inputsWatchDelegate) {
fn.$$watchDelegate = watchDelegate;
fn.inputs = parsedExpression.inputs;
} else if (!interceptorFn.$stateful) {
// If there is an interceptor, but no watchDelegate then treat the interceptor like
// we treat filters - it is assumed to be a pure function unless flagged with $stateful
// Treat interceptor like filters - assume non-stateful by default and use the inputsWatchDelegate
fn.$$watchDelegate = inputsWatchDelegate;
fn.inputs = parsedExpression.inputs ? parsedExpression.inputs : [parsedExpression];
}
if (fn.inputs) {
fn.inputs = fn.inputs.map(function(e) {
// Remove the isPure flag of inputs when it is not absolute because they are now wrapped in a
// potentially non-pure interceptor function.
if (e.isPure === PURITY_RELATIVE) {
return function depurifier(s) { return e(s); };
}
return e;
});
}
return fn;
}
}];
+16 -6
View File
@@ -280,7 +280,7 @@ function $$QProvider() {
* @param {function(function)} nextTick Function for executing functions in the next turn.
* @param {function(...*)} exceptionHandler Function into which unexpected exceptions are passed for
* debugging purposes.
@ param {=boolean} errorOnUnhandledRejections Whether an error should be generated on unhandled
* @param {boolean=} errorOnUnhandledRejections Whether an error should be generated on unhandled
* promises rejections.
* @returns {object} Promise manager.
*/
@@ -351,7 +351,7 @@ function qFactory(nextTick, exceptionHandler, errorOnUnhandledRejections) {
state.pending = undefined;
try {
for (var i = 0, ii = pending.length; i < ii; ++i) {
state.pur = true;
markQStateExceptionHandled(state);
promise = pending[i][0];
fn = pending[i][state.status];
try {
@@ -378,10 +378,10 @@ function qFactory(nextTick, exceptionHandler, errorOnUnhandledRejections) {
// eslint-disable-next-line no-unmodified-loop-condition
while (!queueSize && checkQueue.length) {
var toCheck = checkQueue.shift();
if (!toCheck.pur) {
toCheck.pur = true;
if (!isStateExceptionHandled(toCheck)) {
markQStateExceptionHandled(toCheck);
var errorMessage = 'Possibly unhandled rejection: ' + toDebugString(toCheck.value);
if (toCheck.value instanceof Error) {
if (isError(toCheck.value)) {
exceptionHandler(toCheck.value, errorMessage);
} else {
exceptionHandler(errorMessage);
@@ -391,7 +391,7 @@ function qFactory(nextTick, exceptionHandler, errorOnUnhandledRejections) {
}
function scheduleProcessQueue(state) {
if (errorOnUnhandledRejections && !state.pending && state.status === 2 && !state.pur) {
if (errorOnUnhandledRejections && !state.pending && state.status === 2 && !isStateExceptionHandled(state)) {
if (queueSize === 0 && checkQueue.length === 0) {
nextTick(processChecks);
}
@@ -671,3 +671,13 @@ function qFactory(nextTick, exceptionHandler, errorOnUnhandledRejections) {
return $Q;
}
function isStateExceptionHandled(state) {
return !!state.pur;
}
function markQStateExceptionHandled(state) {
state.pur = true;
}
function markQExceptionHandled(q) {
markQStateExceptionHandled(q.$$state);
}
+34 -1
View File
@@ -449,6 +449,12 @@ function $RootScopeProvider() {
* values are examined for changes on every call to `$digest`.
* - The `listener` is called whenever any expression in the `watchExpressions` array changes.
*
* `$watchGroup` is more performant than watching each expression individually, and should be
* used when the listener does not need to know which expression has changed.
* If the listener needs to know which expression has changed,
* {@link ng.$rootScope.Scope#$watch $watch()} or
* {@link ng.$rootScope.Scope#$watchCollection $watchCollection()} should be used.
*
* @param {Array.<string|Function(scope)>} watchExpressions Array of expressions that will be individually
* watched using {@link ng.$rootScope.Scope#$watch $watch()}
*
@@ -457,7 +463,34 @@ function $RootScopeProvider() {
* The `newValues` array contains the current values of the `watchExpressions`, with the indexes matching
* those of `watchExpression`
* and the `oldValues` array contains the previous values of the `watchExpressions`, with the indexes matching
* those of `watchExpression`
* those of `watchExpression`.
*
* Note that `newValues` and `oldValues` reflect the differences in each **individual**
* expression, and not the difference of the values between each call of the listener.
* That means the difference between `newValues` and `oldValues` cannot be used to determine
* which expression has changed / remained stable:
*
* ```js
*
* $scope.$watchGroup(['v1', 'v2'], function(newValues, oldValues) {
* console.log(newValues, oldValues);
* });
*
* // newValues, oldValues initially
* // [undefined, undefined], [undefined, undefined]
*
* $scope.v1 = 'a';
* $scope.v2 = 'a';
*
* // ['a', 'a'], [undefined, undefined]
*
* $scope.v2 = 'b'
*
* // v1 hasn't changed since it became `'a'`, therefore its oldValue is still `undefined`
* // ['a', 'b'], [undefined, 'a']
*
* ```
*
* The `scope` refers to the current scope.
* @returns {function()} Returns a de-registration function for all listeners.
*/
+1 -1
View File
@@ -85,7 +85,7 @@ function $TimeoutProvider() {
timeout.cancel = function(promise) {
if (promise && promise.$$timeoutId in deferreds) {
// Timeout cancels should not report an unhandled promise.
deferreds[promise.$$timeoutId].promise.catch(noop);
markQExceptionHandled(deferreds[promise.$$timeoutId].promise);
deferreds[promise.$$timeoutId].reject('canceled');
delete deferreds[promise.$$timeoutId];
return $browser.defer.cancel(promise.$$timeoutId);
+20 -21
View File
@@ -160,14 +160,17 @@ var $$AnimateQueueProvider = ['$animateProvider', /** @this */ function($animate
var callbackRegistry = Object.create(null);
// remember that the classNameFilter is set during the provider/config
// stage therefore we can optimize here and setup a helper function
// remember that the `customFilter`/`classNameFilter` are set during the
// provider/config stage therefore we can optimize here and setup helper functions
var customFilter = $animateProvider.customFilter();
var classNameFilter = $animateProvider.classNameFilter();
var isAnimatableClassName = !classNameFilter
? function() { return true; }
: function(className) {
return classNameFilter.test(className);
};
var returnTrue = function() { return true; };
var isAnimatableByFilter = customFilter || returnTrue;
var isAnimatableClassName = !classNameFilter ? returnTrue : function(node, options) {
var className = [node.getAttribute('class'), options.addClass, options.removeClass].join(' ');
return classNameFilter.test(className);
};
var applyAnimationClasses = applyAnimationClassesFactory($$jqLite);
@@ -345,16 +348,13 @@ var $$AnimateQueueProvider = ['$animateProvider', /** @this */ function($animate
options.to = null;
}
// there are situations where a directive issues an animation for
// a jqLite wrapper that contains only comment nodes... If this
// happens then there is no way we can perform an animation
if (!node) {
close();
return runner;
}
var className = [node.getAttribute('class'), options.addClass, options.removeClass].join(' ');
if (!isAnimatableClassName(className)) {
// If animations are hard-disabled for the whole application there is no need to continue.
// There are also situations where a directive issues an animation for a jqLite wrapper that
// contains only comment nodes. In this case, there is no way we can perform an animation.
if (!animationsEnabled ||
!node ||
!isAnimatableByFilter(node, event, initialOptions) ||
!isAnimatableClassName(node, options)) {
close();
return runner;
}
@@ -363,12 +363,11 @@ var $$AnimateQueueProvider = ['$animateProvider', /** @this */ function($animate
var documentHidden = $$isDocumentHidden();
// this is a hard disable of all animations for the application or on
// the element itself, therefore there is no need to continue further
// past this point if not enabled
// This is a hard disable of all animations the element itself, therefore there is no need to
// continue further past this point if not enabled
// Animations are also disabled if the document is currently hidden (page is not visible
// to the user), because browsers slow down or do not flush calls to requestAnimationFrame
var skipAnimations = !animationsEnabled || documentHidden || disabledElementsLookup.get(node);
var skipAnimations = documentHidden || disabledElementsLookup.get(node);
var existingAnimation = (!skipAnimations && activeAnimationsLookup.get(node)) || {};
var hasExistingAnimation = !!existingAnimation.state;
+7 -7
View File
@@ -80,14 +80,14 @@ $provide.value("$locale", {
5,
6
],
"fullDate": "EEEE d MMMM y",
"longDate": "d MMMM y",
"medium": "d MMM y h:mm:ss a",
"mediumDate": "d MMM y",
"mediumTime": "h:mm:ss a",
"short": "y-MM-dd h:mm a",
"fullDate": "EEEE, dd MMMM y",
"longDate": "dd MMMM y",
"medium": "dd MMM y HH:mm:ss",
"mediumDate": "dd MMM y",
"mediumTime": "HH:mm:ss",
"short": "y-MM-dd HH:mm",
"shortDate": "y-MM-dd",
"shortTime": "h:mm a"
"shortTime": "HH:mm"
},
"NUMBER_FORMATS": {
"CURRENCY_SYM": "$",
+4 -4
View File
@@ -82,12 +82,12 @@ $provide.value("$locale", {
],
"fullDate": "EEEE, dd MMMM y",
"longDate": "dd MMMM y",
"medium": "dd MMM y h:mm:ss a",
"medium": "dd MMM y HH:mm:ss",
"mediumDate": "dd MMM y",
"mediumTime": "h:mm:ss a",
"short": "y-MM-dd h:mm a",
"mediumTime": "HH:mm:ss",
"short": "y-MM-dd HH:mm",
"shortDate": "y-MM-dd",
"shortTime": "h:mm a"
"shortTime": "HH:mm"
},
"NUMBER_FORMATS": {
"CURRENCY_SYM": "R",
+4 -4
View File
@@ -82,12 +82,12 @@ $provide.value("$locale", {
],
"fullDate": "EEEE, dd MMMM y",
"longDate": "dd MMMM y",
"medium": "dd MMM y h:mm:ss a",
"medium": "dd MMM y HH:mm:ss",
"mediumDate": "dd MMM y",
"mediumTime": "h:mm:ss a",
"short": "y-MM-dd h:mm a",
"mediumTime": "HH:mm:ss",
"short": "y-MM-dd HH:mm",
"shortDate": "y-MM-dd",
"shortTime": "h:mm a"
"shortTime": "HH:mm"
},
"NUMBER_FORMATS": {
"CURRENCY_SYM": "R",
+2 -2
View File
@@ -126,8 +126,8 @@ $provide.value("$locale", {
{
"gSize": 3,
"lgSize": 3,
"maxFrac": 2,
"minFrac": 2,
"maxFrac": 0,
"minFrac": 0,
"minInt": 1,
"negPre": "-",
"negSuf": "\u00a4",
+7 -7
View File
@@ -24,7 +24,7 @@ $provide.value("$locale", {
"\u0642.\u0645",
"\u0645"
],
"FIRSTDAYOFWEEK": 5,
"FIRSTDAYOFWEEK": 0,
"MONTH": [
"\u064a\u0646\u0627\u064a\u0631",
"\u0641\u0628\u0631\u0627\u064a\u0631",
@@ -77,8 +77,8 @@ $provide.value("$locale", {
"\u062f\u064a\u0633\u0645\u0628\u0631"
],
"WEEKENDRANGE": [
4,
5
5,
6
],
"fullDate": "EEEE\u060c d MMMM\u060c y",
"longDate": "d MMMM\u060c y",
@@ -111,10 +111,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"
}
]
},
+4 -4
View File
@@ -111,10 +111,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"
}
]
},
+6 -6
View File
@@ -108,13 +108,13 @@ $provide.value("$locale", {
{
"gSize": 3,
"lgSize": 3,
"maxFrac": 2,
"minFrac": 2,
"maxFrac": 3,
"minFrac": 3,
"minInt": 1,
"negPre": "-\u00a4\u00a0",
"negSuf": "",
"posPre": "\u00a4\u00a0",
"posSuf": ""
"negPre": "-",
"negSuf": "\u00a0\u00a4",
"posPre": "",
"posSuf": "\u00a0\u00a4"
}
]
},
+6 -6
View File
@@ -108,13 +108,13 @@ $provide.value("$locale", {
{
"gSize": 3,
"lgSize": 3,
"maxFrac": 2,
"minFrac": 2,
"maxFrac": 0,
"minFrac": 0,
"minInt": 1,
"negPre": "-\u00a4\u00a0",
"negSuf": "",
"posPre": "\u00a4\u00a0",
"posSuf": ""
"negPre": "-",
"negSuf": "\u00a0\u00a4",
"posPre": "",
"posSuf": "\u00a0\u00a4"
}
]
},
+4 -4
View File
@@ -111,10 +111,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"
}
]
},
+4 -4
View File
@@ -111,10 +111,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"
}
]
},
+4 -4
View File
@@ -111,10 +111,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"
}
]
},
+6 -6
View File
@@ -108,13 +108,13 @@ $provide.value("$locale", {
{
"gSize": 3,
"lgSize": 3,
"maxFrac": 2,
"minFrac": 2,
"maxFrac": 0,
"minFrac": 0,
"minInt": 1,
"negPre": "-\u00a4\u00a0",
"negSuf": "",
"posPre": "\u00a4\u00a0",
"posSuf": ""
"negPre": "-",
"negSuf": "\u00a0\u00a4",
"posPre": "",
"posSuf": "\u00a0\u00a4"
}
]
},
+6 -6
View File
@@ -108,13 +108,13 @@ $provide.value("$locale", {
{
"gSize": 3,
"lgSize": 3,
"maxFrac": 2,
"minFrac": 2,
"maxFrac": 3,
"minFrac": 3,
"minInt": 1,
"negPre": "-\u00a4\u00a0",
"negSuf": "",
"posPre": "\u00a4\u00a0",
"posSuf": ""
"negPre": "-",
"negSuf": "\u00a0\u00a4",
"posPre": "",
"posSuf": "\u00a0\u00a4"
}
]
},
+6 -6
View File
@@ -108,13 +108,13 @@ $provide.value("$locale", {
{
"gSize": 3,
"lgSize": 3,
"maxFrac": 2,
"minFrac": 2,
"maxFrac": 0,
"minFrac": 0,
"minInt": 1,
"negPre": "-\u00a4\u00a0",
"negSuf": "",
"posPre": "\u00a4\u00a0",
"posSuf": ""
"negPre": "-",
"negSuf": "\u00a0\u00a4",
"posPre": "",
"posSuf": "\u00a0\u00a4"
}
]
},
+6 -6
View File
@@ -108,13 +108,13 @@ $provide.value("$locale", {
{
"gSize": 3,
"lgSize": 3,
"maxFrac": 2,
"minFrac": 2,
"maxFrac": 3,
"minFrac": 3,
"minInt": 1,
"negPre": "-\u00a4\u00a0",
"negSuf": "",
"posPre": "\u00a4\u00a0",
"posSuf": ""
"negPre": "-",
"negSuf": "\u00a0\u00a4",
"posPre": "",
"posSuf": "\u00a0\u00a4"
}
]
},
+6 -6
View File
@@ -108,13 +108,13 @@ $provide.value("$locale", {
{
"gSize": 3,
"lgSize": 3,
"maxFrac": 2,
"minFrac": 2,
"maxFrac": 0,
"minFrac": 0,
"minInt": 1,
"negPre": "-\u00a4\u00a0",
"negSuf": "",
"posPre": "\u00a4\u00a0",
"posSuf": ""
"negPre": "-",
"negSuf": "\u00a0\u00a4",
"posPre": "",
"posSuf": "\u00a0\u00a4"
}
]
},
+2 -2
View File
@@ -108,8 +108,8 @@ $provide.value("$locale", {
{
"gSize": 3,
"lgSize": 3,
"maxFrac": 2,
"minFrac": 2,
"maxFrac": 3,
"minFrac": 3,
"minInt": 1,
"negPre": "-\u00a4\u00a0",
"negSuf": "",
+6 -6
View File
@@ -108,13 +108,13 @@ $provide.value("$locale", {
{
"gSize": 3,
"lgSize": 3,
"maxFrac": 2,
"minFrac": 2,
"maxFrac": 0,
"minFrac": 0,
"minInt": 1,
"negPre": "-\u00a4\u00a0",
"negSuf": "",
"posPre": "\u00a4\u00a0",
"posSuf": ""
"negPre": "-",
"negSuf": "\u00a0\u00a4",
"posPre": "",
"posSuf": "\u00a0\u00a4"
}
]
},
+6 -6
View File
@@ -108,13 +108,13 @@ $provide.value("$locale", {
{
"gSize": 3,
"lgSize": 3,
"maxFrac": 2,
"minFrac": 2,
"maxFrac": 3,
"minFrac": 3,
"minInt": 1,
"negPre": "-\u00a4\u00a0",
"negSuf": "",
"posPre": "\u00a4\u00a0",
"posSuf": ""
"negPre": "-",
"negSuf": "\u00a0\u00a4",
"posPre": "",
"posSuf": "\u00a0\u00a4"
}
]
},
+4 -4
View File
@@ -111,10 +111,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"
}
]
},
+4 -4
View File
@@ -111,10 +111,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"
}
]
},
+4 -4
View File
@@ -111,10 +111,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"
}
]
},
+4 -4
View File
@@ -111,10 +111,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"
}
]
},
+6 -6
View File
@@ -108,13 +108,13 @@ $provide.value("$locale", {
{
"gSize": 3,
"lgSize": 3,
"maxFrac": 2,
"minFrac": 2,
"maxFrac": 0,
"minFrac": 0,
"minInt": 1,
"negPre": "-\u00a4\u00a0",
"negSuf": "",
"posPre": "\u00a4\u00a0",
"posSuf": ""
"negPre": "-",
"negSuf": "\u00a0\u00a4",
"posPre": "",
"posSuf": "\u00a0\u00a4"
}
]
},
+4 -4
View File
@@ -111,10 +111,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"
}
]
},
+6 -6
View File
@@ -108,13 +108,13 @@ $provide.value("$locale", {
{
"gSize": 3,
"lgSize": 3,
"maxFrac": 2,
"minFrac": 2,
"maxFrac": 0,
"minFrac": 0,
"minInt": 1,
"negPre": "-\u00a4\u00a0",
"negSuf": "",
"posPre": "\u00a4\u00a0",
"posSuf": ""
"negPre": "-",
"negSuf": "\u00a0\u00a4",
"posPre": "",
"posSuf": "\u00a0\u00a4"
}
]
},
+6 -6
View File
@@ -108,13 +108,13 @@ $provide.value("$locale", {
{
"gSize": 3,
"lgSize": 3,
"maxFrac": 2,
"minFrac": 2,
"maxFrac": 0,
"minFrac": 0,
"minInt": 1,
"negPre": "-\u00a4\u00a0",
"negSuf": "",
"posPre": "\u00a4\u00a0",
"posSuf": ""
"negPre": "-",
"negSuf": "\u00a0\u00a4",
"posPre": "",
"posSuf": "\u00a0\u00a4"
}
]
},
+2 -2
View File
@@ -108,8 +108,8 @@ $provide.value("$locale", {
{
"gSize": 3,
"lgSize": 3,
"maxFrac": 2,
"minFrac": 2,
"maxFrac": 3,
"minFrac": 3,
"minInt": 1,
"negPre": "-\u00a4\u00a0",
"negSuf": "",
+46 -46
View File
@@ -4,63 +4,63 @@ var PLURAL_CATEGORY = {ZERO: "zero", ONE: "one", TWO: "two", FEW: "few", MANY: "
$provide.value("$locale", {
"DATETIME_FORMATS": {
"AMPMS": [
"\u202eAM\u202c",
"\u202ePM\u202c"
"\u061c\u202eAM\u202c\u061c",
"\u061c\u202ePM\u202c\u061c"
],
"DAY": [
"\u202eSunday\u202c",
"\u202eMonday\u202c",
"\u202eTuesday\u202c",
"\u202eWednesday\u202c",
"\u202eThursday\u202c",
"\u202eFriday\u202c",
"\u202eSaturday\u202c"
"\u061c\u202eSunday\u202c\u061c",
"\u061c\u202eMonday\u202c\u061c",
"\u061c\u202eTuesday\u202c\u061c",
"\u061c\u202eWednesday\u202c\u061c",
"\u061c\u202eThursday\u202c\u061c",
"\u061c\u202eFriday\u202c\u061c",
"\u061c\u202eSaturday\u202c\u061c"
],
"ERANAMES": [
"\u202eBefore\u202c \u202eChrist\u202c",
"\u202eAnno\u202c \u202eDomini\u202c"
"\u061c\u202eBefore\u202c\u061c \u061c\u202eChrist\u202c\u061c",
"\u061c\u202eAnno\u202c\u061c \u061c\u202eDomini\u202c\u061c"
],
"ERAS": [
"\u202eBC\u202c",
"\u202eAD\u202c"
"\u061c\u202eBC\u202c\u061c",
"\u061c\u202eAD\u202c\u061c"
],
"FIRSTDAYOFWEEK": 0,
"MONTH": [
"\u202eJanuary\u202c",
"\u202eFebruary\u202c",
"\u202eMarch\u202c",
"\u202eApril\u202c",
"\u202eMay\u202c",
"\u202eJune\u202c",
"\u202eJuly\u202c",
"\u202eAugust\u202c",
"\u202eSeptember\u202c",
"\u202eOctober\u202c",
"\u202eNovember\u202c",
"\u202eDecember\u202c"
"\u061c\u202eJanuary\u202c\u061c",
"\u061c\u202eFebruary\u202c\u061c",
"\u061c\u202eMarch\u202c\u061c",
"\u061c\u202eApril\u202c\u061c",
"\u061c\u202eMay\u202c\u061c",
"\u061c\u202eJune\u202c\u061c",
"\u061c\u202eJuly\u202c\u061c",
"\u061c\u202eAugust\u202c\u061c",
"\u061c\u202eSeptember\u202c\u061c",
"\u061c\u202eOctober\u202c\u061c",
"\u061c\u202eNovember\u202c\u061c",
"\u061c\u202eDecember\u202c\u061c"
],
"SHORTDAY": [
"\u202eSun\u202c",
"\u202eMon\u202c",
"\u202eTue\u202c",
"\u202eWed\u202c",
"\u202eThu\u202c",
"\u202eFri\u202c",
"\u202eSat\u202c"
"\u061c\u202eSun\u202c\u061c",
"\u061c\u202eMon\u202c\u061c",
"\u061c\u202eTue\u202c\u061c",
"\u061c\u202eWed\u202c\u061c",
"\u061c\u202eThu\u202c\u061c",
"\u061c\u202eFri\u202c\u061c",
"\u061c\u202eSat\u202c\u061c"
],
"SHORTMONTH": [
"\u202eJan\u202c",
"\u202eFeb\u202c",
"\u202eMar\u202c",
"\u202eApr\u202c",
"\u202eMay\u202c",
"\u202eJun\u202c",
"\u202eJul\u202c",
"\u202eAug\u202c",
"\u202eSep\u202c",
"\u202eOct\u202c",
"\u202eNov\u202c",
"\u202eDec\u202c"
"\u061c\u202eJan\u202c\u061c",
"\u061c\u202eFeb\u202c\u061c",
"\u061c\u202eMar\u202c\u061c",
"\u061c\u202eApr\u202c\u061c",
"\u061c\u202eMay\u202c\u061c",
"\u061c\u202eJun\u202c\u061c",
"\u061c\u202eJul\u202c\u061c",
"\u061c\u202eAug\u202c\u061c",
"\u061c\u202eSep\u202c\u061c",
"\u061c\u202eOct\u202c\u061c",
"\u061c\u202eNov\u202c\u061c",
"\u061c\u202eDec\u202c\u061c"
],
"STANDALONEMONTH": [
"\u064a\u0646\u0627\u064a\u0631",
@@ -91,8 +91,8 @@ $provide.value("$locale", {
},
"NUMBER_FORMATS": {
"CURRENCY_SYM": "\u00a3",
"DECIMAL_SEP": "\u066b",
"GROUP_SEP": "\u066c",
"DECIMAL_SEP": ".",
"GROUP_SEP": ",",
"PATTERNS": [
{
"gSize": 3,
+6 -6
View File
@@ -108,13 +108,13 @@ $provide.value("$locale", {
{
"gSize": 3,
"lgSize": 3,
"maxFrac": 2,
"minFrac": 2,
"maxFrac": 0,
"minFrac": 0,
"minInt": 1,
"negPre": "-\u00a4\u00a0",
"negSuf": "",
"posPre": "\u00a4\u00a0",
"posSuf": ""
"negPre": "-",
"negSuf": "\u00a0\u00a4",
"posPre": "",
"posSuf": "\u00a0\u00a4"
}
]
},
+4 -4
View File
@@ -111,10 +111,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"
}
]
},
+8 -8
View File
@@ -98,14 +98,14 @@ $provide.value("$locale", {
6,
6
],
"fullDate": "EEEE, d MMMM, y",
"longDate": "d MMMM, y",
"medium": "dd-MM-y h.mm.ss a",
"mediumDate": "dd-MM-y",
"mediumTime": "h.mm.ss a",
"short": "d-M-y h.mm. a",
"shortDate": "d-M-y",
"shortTime": "h.mm. a"
"fullDate": "y MMMM d, EEEE",
"longDate": "y MMMM d",
"medium": "y MMM d HH:mm:ss",
"mediumDate": "y MMM d",
"mediumTime": "HH:mm:ss",
"short": "y-MM-dd HH:mm",
"shortDate": "y-MM-dd",
"shortTime": "HH:mm"
},
"NUMBER_FORMATS": {
"CURRENCY_SYM": "\u20b9",
+8 -8
View File
@@ -98,14 +98,14 @@ $provide.value("$locale", {
6,
6
],
"fullDate": "EEEE, d MMMM, y",
"longDate": "d MMMM, y",
"medium": "dd-MM-y h.mm.ss a",
"mediumDate": "dd-MM-y",
"mediumTime": "h.mm.ss a",
"short": "d-M-y h.mm. a",
"shortDate": "d-M-y",
"shortTime": "h.mm. a"
"fullDate": "y MMMM d, EEEE",
"longDate": "y MMMM d",
"medium": "y MMM d HH:mm:ss",
"mediumDate": "y MMM d",
"mediumTime": "HH:mm:ss",
"short": "y-MM-dd HH:mm",
"shortDate": "y-MM-dd",
"shortTime": "HH:mm"
},
"NUMBER_FORMATS": {
"CURRENCY_SYM": "\u20b9",
+2 -2
View File
@@ -126,8 +126,8 @@ $provide.value("$locale", {
{
"gSize": 3,
"lgSize": 3,
"maxFrac": 2,
"minFrac": 2,
"maxFrac": 0,
"minFrac": 0,
"minInt": 1,
"negPre": "-",
"negSuf": "\u00a0\u00a4",
+3 -3
View File
@@ -23,7 +23,7 @@ $provide.value("$locale", {
"DATETIME_FORMATS": {
"AMPMS": [
"de la ma\u00f1ana",
"de la tardi"
"de la tarde"
],
"DAY": [
"domingu",
@@ -35,11 +35,11 @@ $provide.value("$locale", {
"s\u00e1badu"
],
"ERANAMES": [
"a.C.",
"enantes de Cristu",
"despu\u00e9s de Cristu"
],
"ERAS": [
"a.C.",
"e.C.",
"d.C."
],
"FIRSTDAYOFWEEK": 0,
+3 -3
View File
@@ -23,7 +23,7 @@ $provide.value("$locale", {
"DATETIME_FORMATS": {
"AMPMS": [
"de la ma\u00f1ana",
"de la tardi"
"de la tarde"
],
"DAY": [
"domingu",
@@ -35,11 +35,11 @@ $provide.value("$locale", {
"s\u00e1badu"
],
"ERANAMES": [
"a.C.",
"enantes de Cristu",
"despu\u00e9s de Cristu"
],
"ERAS": [
"a.C.",
"e.C.",
"d.C."
],
"FIRSTDAYOFWEEK": 0,
+40 -40
View File
@@ -4,8 +4,8 @@ var PLURAL_CATEGORY = {ZERO: "zero", ONE: "one", TWO: "two", FEW: "few", MANY: "
$provide.value("$locale", {
"DATETIME_FORMATS": {
"AMPMS": [
"AM",
"PM"
"\u0410\u041c",
"\u041f\u041c"
],
"DAY": [
"\u0431\u0430\u0437\u0430\u0440",
@@ -17,12 +17,12 @@ $provide.value("$locale", {
"\u0448\u04d9\u043d\u0431\u04d9"
],
"ERANAMES": [
"BCE",
"CE"
"\u0435\u0440\u0430\u043c\u044b\u0437\u0434\u0430\u043d \u04d9\u0432\u0432\u04d9\u043b",
"\u0458\u0435\u043d\u0438 \u0435\u0440\u0430"
],
"ERAS": [
"BCE",
"CE"
"\u0435.\u04d9.",
"\u0458.\u0435."
],
"FIRSTDAYOFWEEK": 0,
"MONTH": [
@@ -40,50 +40,50 @@ $provide.value("$locale", {
"\u0434\u0435\u043a\u0430\u0431\u0440"
],
"SHORTDAY": [
"\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"
"\u0411.",
"\u0411.\u0415.",
"\u0427.\u0410.",
"\u0427.",
"\u04b8.\u0410.",
"\u04b8.",
"\u0428."
],
"SHORTMONTH": [
"\u0458\u0430\u043d\u0432\u0430\u0440",
"\u0444\u0435\u0432\u0440\u0430\u043b",
"\u043c\u0430\u0440\u0442",
"\u0430\u043f\u0440\u0435\u043b",
"\u0458\u0430\u043d",
"\u0444\u0435\u0432",
"\u043c\u0430\u0440",
"\u0430\u043f\u0440",
"\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"
"\u0438\u0458\u043d",
"\u0438\u0458\u043b",
"\u0430\u0432\u0433",
"\u0441\u0435\u043d",
"\u043e\u043a\u0442",
"\u043d\u043e\u0458",
"\u0434\u0435\u043a"
],
"STANDALONEMONTH": [
"\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"
"\u0408\u0430\u043d\u0432\u0430\u0440",
"\u0424\u0435\u0432\u0440\u0430\u043b",
"\u041c\u0430\u0440\u0442",
"\u0410\u043f\u0440\u0435\u043b",
"\u041c\u0430\u0439",
"\u0418\u0458\u0443\u043d",
"\u0418\u0458\u0443\u043b",
"\u0410\u0432\u0433\u0443\u0441\u0442",
"\u0421\u0435\u043d\u0442\u0458\u0430\u0431\u0440",
"\u041e\u043a\u0442\u0458\u0430\u0431\u0440",
"\u041d\u043e\u0458\u0430\u0431\u0440",
"\u0414\u0435\u043a\u0430\u0431\u0440"
],
"WEEKENDRANGE": [
5,
6
],
"fullDate": "EEEE, d, MMMM, y",
"longDate": "d MMMM, y",
"medium": "d MMM, y HH:mm:ss",
"mediumDate": "d MMM, y",
"fullDate": "d MMMM y, EEEE",
"longDate": "d MMMM y",
"medium": "d MMM y HH:mm:ss",
"mediumDate": "d MMM y",
"mediumTime": "HH:mm:ss",
"short": "dd.MM.yy HH:mm",
"shortDate": "dd.MM.yy",
+40 -40
View File
@@ -4,8 +4,8 @@ var PLURAL_CATEGORY = {ZERO: "zero", ONE: "one", TWO: "two", FEW: "few", MANY: "
$provide.value("$locale", {
"DATETIME_FORMATS": {
"AMPMS": [
"AM",
"PM"
"\u0410\u041c",
"\u041f\u041c"
],
"DAY": [
"\u0431\u0430\u0437\u0430\u0440",
@@ -17,12 +17,12 @@ $provide.value("$locale", {
"\u0448\u04d9\u043d\u0431\u04d9"
],
"ERANAMES": [
"BCE",
"CE"
"\u0435\u0440\u0430\u043c\u044b\u0437\u0434\u0430\u043d \u04d9\u0432\u0432\u04d9\u043b",
"\u0458\u0435\u043d\u0438 \u0435\u0440\u0430"
],
"ERAS": [
"BCE",
"CE"
"\u0435.\u04d9.",
"\u0458.\u0435."
],
"FIRSTDAYOFWEEK": 0,
"MONTH": [
@@ -40,50 +40,50 @@ $provide.value("$locale", {
"\u0434\u0435\u043a\u0430\u0431\u0440"
],
"SHORTDAY": [
"\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"
"\u0411.",
"\u0411.\u0415.",
"\u0427.\u0410.",
"\u0427.",
"\u04b8.\u0410.",
"\u04b8.",
"\u0428."
],
"SHORTMONTH": [
"\u0458\u0430\u043d\u0432\u0430\u0440",
"\u0444\u0435\u0432\u0440\u0430\u043b",
"\u043c\u0430\u0440\u0442",
"\u0430\u043f\u0440\u0435\u043b",
"\u0458\u0430\u043d",
"\u0444\u0435\u0432",
"\u043c\u0430\u0440",
"\u0430\u043f\u0440",
"\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"
"\u0438\u0458\u043d",
"\u0438\u0458\u043b",
"\u0430\u0432\u0433",
"\u0441\u0435\u043d",
"\u043e\u043a\u0442",
"\u043d\u043e\u0458",
"\u0434\u0435\u043a"
],
"STANDALONEMONTH": [
"\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"
"\u0408\u0430\u043d\u0432\u0430\u0440",
"\u0424\u0435\u0432\u0440\u0430\u043b",
"\u041c\u0430\u0440\u0442",
"\u0410\u043f\u0440\u0435\u043b",
"\u041c\u0430\u0439",
"\u0418\u0458\u0443\u043d",
"\u0418\u0458\u0443\u043b",
"\u0410\u0432\u0433\u0443\u0441\u0442",
"\u0421\u0435\u043d\u0442\u0458\u0430\u0431\u0440",
"\u041e\u043a\u0442\u0458\u0430\u0431\u0440",
"\u041d\u043e\u0458\u0430\u0431\u0440",
"\u0414\u0435\u043a\u0430\u0431\u0440"
],
"WEEKENDRANGE": [
5,
6
],
"fullDate": "EEEE, d, MMMM, y",
"longDate": "d MMMM, y",
"medium": "d MMM, y HH:mm:ss",
"mediumDate": "d MMM, y",
"fullDate": "d MMMM y, EEEE",
"longDate": "d MMMM y",
"medium": "d MMM y HH:mm:ss",
"mediumDate": "d MMM y",
"mediumTime": "HH:mm:ss",
"short": "dd.MM.yy HH:mm",
"shortDate": "dd.MM.yy",
+2 -2
View File
@@ -18,11 +18,11 @@ $provide.value("$locale", {
],
"ERANAMES": [
"eram\u0131zdan \u0259vv\u0259l",
"eram\u0131z"
"yeni era"
],
"ERAS": [
"e.\u0259.",
"b.e."
"y.e."
],
"FIRSTDAYOFWEEK": 0,
"MONTH": [
+2 -2
View File
@@ -18,11 +18,11 @@ $provide.value("$locale", {
],
"ERANAMES": [
"eram\u0131zdan \u0259vv\u0259l",
"eram\u0131z"
"yeni era"
],
"ERAS": [
"e.\u0259.",
"b.e."
"y.e."
],
"FIRSTDAYOFWEEK": 0,
"MONTH": [
+2 -2
View File
@@ -18,11 +18,11 @@ $provide.value("$locale", {
],
"ERANAMES": [
"eram\u0131zdan \u0259vv\u0259l",
"eram\u0131z"
"yeni era"
],
"ERAS": [
"e.\u0259.",
"b.e."
"y.e."
],
"FIRSTDAYOFWEEK": 0,
"MONTH": [
+2 -2
View File
@@ -126,8 +126,8 @@ $provide.value("$locale", {
{
"gSize": 3,
"lgSize": 3,
"maxFrac": 2,
"minFrac": 2,
"maxFrac": 0,
"minFrac": 0,
"minInt": 1,
"negPre": "-",
"negSuf": "\u00a0\u00a4",
+13 -13
View File
@@ -4,8 +4,8 @@ var PLURAL_CATEGORY = {ZERO: "zero", ONE: "one", TWO: "two", FEW: "few", MANY: "
$provide.value("$locale", {
"DATETIME_FORMATS": {
"AMPMS": [
"\u0434\u0430 \u043f\u0430\u045e\u0434\u043d\u044f",
"\u043f\u0430\u0441\u043b\u044f \u043f\u0430\u045e\u0434\u043d\u044f"
"AM",
"PM"
],
"DAY": [
"\u043d\u044f\u0434\u0437\u0435\u043b\u044f",
@@ -17,8 +17,8 @@ $provide.value("$locale", {
"\u0441\u0443\u0431\u043e\u0442\u0430"
],
"ERANAMES": [
"\u0434\u0430 \u043d\u0430\u0448\u0430\u0439 \u044d\u0440\u044b",
"\u043d\u0430\u0448\u0430\u0439 \u044d\u0440\u044b"
"\u0434\u0430 \u043d\u0430\u0440\u0430\u0434\u0436\u044d\u043d\u043d\u044f \u0425\u0440\u044b\u0441\u0442\u043e\u0432\u0430",
"\u0430\u0434 \u043d\u0430\u0440\u0430\u0434\u0436\u044d\u043d\u043d\u044f \u0425\u0440\u044b\u0441\u0442\u043e\u0432\u0430"
],
"ERAS": [
"\u0434\u0430 \u043d.\u044d.",
@@ -80,17 +80,17 @@ $provide.value("$locale", {
5,
6
],
"fullDate": "EEEE, d MMMM y",
"longDate": "d MMMM y",
"medium": "d.M.y HH.mm.ss",
"mediumDate": "d.M.y",
"mediumTime": "HH.mm.ss",
"short": "d.M.yy HH.mm",
"shortDate": "d.M.yy",
"shortTime": "HH.mm"
"fullDate": "EEEE, d MMMM y '\u0433'.",
"longDate": "d MMMM y '\u0433'.",
"medium": "d.MM.y HH:mm:ss",
"mediumDate": "d.MM.y",
"mediumTime": "HH:mm:ss",
"short": "d.MM.yy HH:mm",
"shortDate": "d.MM.yy",
"shortTime": "HH:mm"
},
"NUMBER_FORMATS": {
"CURRENCY_SYM": "p.",
"CURRENCY_SYM": "BYN",
"DECIMAL_SEP": ",",
"GROUP_SEP": "\u00a0",
"PATTERNS": [
+13 -13
View File
@@ -4,8 +4,8 @@ var PLURAL_CATEGORY = {ZERO: "zero", ONE: "one", TWO: "two", FEW: "few", MANY: "
$provide.value("$locale", {
"DATETIME_FORMATS": {
"AMPMS": [
"\u0434\u0430 \u043f\u0430\u045e\u0434\u043d\u044f",
"\u043f\u0430\u0441\u043b\u044f \u043f\u0430\u045e\u0434\u043d\u044f"
"AM",
"PM"
],
"DAY": [
"\u043d\u044f\u0434\u0437\u0435\u043b\u044f",
@@ -17,8 +17,8 @@ $provide.value("$locale", {
"\u0441\u0443\u0431\u043e\u0442\u0430"
],
"ERANAMES": [
"\u0434\u0430 \u043d\u0430\u0448\u0430\u0439 \u044d\u0440\u044b",
"\u043d\u0430\u0448\u0430\u0439 \u044d\u0440\u044b"
"\u0434\u0430 \u043d\u0430\u0440\u0430\u0434\u0436\u044d\u043d\u043d\u044f \u0425\u0440\u044b\u0441\u0442\u043e\u0432\u0430",
"\u0430\u0434 \u043d\u0430\u0440\u0430\u0434\u0436\u044d\u043d\u043d\u044f \u0425\u0440\u044b\u0441\u0442\u043e\u0432\u0430"
],
"ERAS": [
"\u0434\u0430 \u043d.\u044d.",
@@ -80,17 +80,17 @@ $provide.value("$locale", {
5,
6
],
"fullDate": "EEEE, d MMMM y",
"longDate": "d MMMM y",
"medium": "d.M.y HH.mm.ss",
"mediumDate": "d.M.y",
"mediumTime": "HH.mm.ss",
"short": "d.M.yy HH.mm",
"shortDate": "d.M.yy",
"shortTime": "HH.mm"
"fullDate": "EEEE, d MMMM y '\u0433'.",
"longDate": "d MMMM y '\u0433'.",
"medium": "d.MM.y HH:mm:ss",
"mediumDate": "d.MM.y",
"mediumTime": "HH:mm:ss",
"short": "d.MM.yy HH:mm",
"shortDate": "d.MM.yy",
"shortTime": "HH:mm"
},
"NUMBER_FORMATS": {
"CURRENCY_SYM": "p.",
"CURRENCY_SYM": "BYN",
"DECIMAL_SEP": ",",
"GROUP_SEP": "\u00a0",
"PATTERNS": [
+2 -2
View File
@@ -126,8 +126,8 @@ $provide.value("$locale", {
{
"gSize": 3,
"lgSize": 3,
"maxFrac": 2,
"minFrac": 2,
"maxFrac": 0,
"minFrac": 0,
"minInt": 1,
"negPre": "-",
"negSuf": "\u00a4",

Some files were not shown because too many files have changed in this diff Show More