Compare commits

..

563 Commits

Author SHA1 Message Date
Georgios Kalpakas f73a651461 revert: fix($sce): consider document base URL in 'self' URL policy
This reverts commit 5e28b6ea8c.
Reverting while investigating security implications of 5e28b6e without #15597
(which is possibly a breaking change, thus not suitable for this branch).
2017-01-12 11:22:40 +02:00
Georgios Kalpakas d65636988b test($compile): clean up stray statement after cherry-pick 2017-01-11 19:35:33 +02:00
frederikprijck e75fbc494e fix($compile): allow the usage of "$" in isolate scope property alias
Previously, when using an alias for an isolate scope or `bindings` property
(e.g. `alias: '<attrName'` instead of `attrName: '<'`), a `$compile:iscp` error
was thrown if the attribute name contained a "$".
This commit removes the error by changing the regex to allow "$" characters in
the attribute name when using a property alias.

Fixes: #15586

Closes #15594
2017-01-11 11:55:01 +02:00
Alex Dobkin 5e28b6ea8c fix($sce): consider document base URL in 'self' URL policy
Page authors can use the `<base>` tag in HTML to specify URL to use as a base
when resovling relative URLs. This can cause SCE to reject relative URLs on the
page, because they fail the same-origin test.

To improve compatibility with the `<base>` tag, this commit changes the logic
for matching URLs to the 'self' policy to allow URLs that match the protocol and
domain of the base URL in addition to URLs that match the loading origin.

**Security Note:**
If an attacker can inject a `<base>` tag into the page, they can circumvent SCE
protections. However, injecting a `<base>` tag typically requires the ability to
inject arbitrary HTML into the page, which is a more serious vulnerabilty than
bypassing SCE.

Fixes #15144

Closes #15145
2017-01-10 15:29:26 +02:00
David Jöch 586ec15398 style($log): fix indentation
Closes #15579
2017-01-05 13:04:26 +02:00
Nic Mitchell 8541d25ded chore(*): update copyright year
Closes #15573
2017-01-04 12:25:39 +02:00
Georgios Kalpakas a580f8132b docs(guide/$location): correctly format heading 2017-01-03 22:41:42 +02:00
Georgios Kalpakas 41aa9125b9 fix(angularInit): allow auto-bootstraping from inline script
Some browsers (e.g. Safari 9.x, PhantomJS) do not set `link.origin/protocol`
correctly, when setting `link.href` to `null`, which prevented auto-bootstraping
Angular from scripts without a `src` attribute (i.e. inline scripts).
Inline scripts are on the same origin as the loading page, so auto-bootstraping
should be allowed.

Fixes #15567

Closes #15571
2017-01-03 19:26:50 +02:00
Soumya Ranjan Mohanty b4581e3e99 docs(guide/services): fix syntax for Jasmine v2.x
Closes #15570
2017-01-03 16:17:01 +02:00
Georgios Kalpakas bdb5bc82a3 docs(ngShow/ngHide): improve docs and fix inconsistencies between ngShow/ngHide
Closes #15471
2017-01-03 12:56:59 +02:00
Deco 1cf93fd2b0 docs(tutorial/step_04): fix typo
Closes #15562
2016-12-31 12:32:52 +02:00
supasak 4f3858e7c3 fix($resource): delete $cancelRequest() in toJSON()
Closes #15244
2016-12-29 10:02:20 +02:00
Naomi Black 4993728819 docs(guide/forms): remove implicit bias from example
Closes #15543
2016-12-23 11:44:23 +02:00
sp00m 6933cf64fe fix($$cookieReader): correctly handle forbidden access to document.cookie
In certain cases (e.g. on LG webOS using the `file:` protocol), access to
`document.cookie` may not be allowed and throw an error. This could break
`$http` which relies on `$$cookieReader()` for retrieving the XSRF token.
This commit fixes it by treating `document.cookie` as empty, when access to it
is fordibben.

Fixes  #15523

Closes #15532
2016-12-20 23:35:50 +02:00
Peter Neave 32e656b769 docs(tutorial/step_13): add missing dependency phoneDetails module
Closes #15521
2016-12-19 21:10:02 +02:00
Georgios Kalpakas 11fbc17f65 chore(scripts): fix jenkins scripts 2016-12-16 12:27:04 +02:00
Matias Niemelä 02f045be8d revert: fix($resource): allow params in hostname (except for IPv6 addresses)
This reverts commit 7f45b5fee7.
2016-12-15 17:21:46 -05:00
Peter Bacon Darwin 71083a4455 chore(bower): use npm tool to publish 2016-12-15 20:22:00 +00:00
Peter Bacon Darwin 700aafe3ab chore(package.json): fix dist-tag for 1.5 branch 2016-12-15 20:21:24 +00:00
Jannick Fahlbusch 2b6bfc36ae docs($interval): improve fn description
If no additional arguments are passed, the function is called with the current iteration count.

Closes #15503
2016-12-13 14:16:55 +02:00
Georgios Kalpakas 31716eec4d refactor(testabilityPatch): remove code duplication 2016-12-13 00:14:05 +02:00
Aaron Brewer f670c451f4 docs(ngMessageExp): improve description
Closes #15486
2016-12-11 21:02:51 +02:00
idhindsight 6d0ff9fb7f docs(tutorial/step_09): fix typo (it's --> its)
Closes #15485
2016-12-10 22:28:37 +02:00
Georgios Kalpakas e3d02070ab fix(ngClassOdd/Even): add/remove the correct classes when expression/$index change simultaneously 2016-12-09 12:33:18 +02:00
Georgios Kalpakas a9708de84b fix($rootScope): when adding/removing watchers during $digest
Previously, adding a watcher during a `$digest` (i.e. from within a watcher),
would result in the next watcher getting skipped. Similarly, removing a watcher
during a `$digest` could result in the current watcher being run twice (if the
removed watcher had not run yet in the current `$digest`).

This commit fixes both cases by keeping track of the current watcher index
during a digest and properly updating it when adding/removing watchers.

Fixes #15422

Closes #15424
2016-12-09 10:45:32 +02:00
Georgios Kalpakas 77ed85bcd3 fix(jqLite): silently ignore after() if element has no parent
Previously, the element was always assumed to have a parent and an error was
thrown when that was not the case.
This commit makes jqLite consistent with jQuery, which silently ignores a call
on elements that do not have a parent.

Fixes #15331
Closes #15367

Closes #15475
2016-12-08 18:12:54 +02:00
Georgios Kalpakas 0ddbcafd9e docs(ngMockE2E): correctly document the data arg of $httpBackend.when(...) 2016-12-08 14:54:39 +02:00
Peter Bacon Darwin 536da55705 chore(jenkins): fix yarn and grunt installation 2016-12-07 10:55:54 +00:00
Rob Wu bdeb3392a8 feat(security): do not bootstrap from unknown schemes with a different origin 2016-12-05 21:35:17 +00:00
Georgios Kalpakas 7f45b5fee7 fix($resource): allow params in hostname (except for IPv6 addresses)
Support for IPv6 addresses (in b643f0d) was too aggressive and broke support for params in the
`hostname` part of a URL.
This commit restores support for params in the `hostname`, as long as it is not an IPv6 address.

Fixes #14542

Closes #14906
2016-12-03 10:01:10 +02:00
ojab a3cd7d8011 docs(guide/templates): camelCase directive name for consistency
Closes #15465
2016-12-02 23:41:46 +02:00
Martin Staffa 3a767a9943 chore(doc-gen): render @example tag in ngdoc @method
Currently, ngdoc `@method` ignores `@example` tags and does not output them.
This is usually not a problem, as examples are mostly defined directly
in the `@description` via code blocks or `<example>`
elements. However, some methods still have `@example` tags (possibly
from a previous docs version).

While not absolutely necessary, having special markup for Examples
makes them a) easier to find visually in the docs, and b) easier
to link to as they will have a unique id.

Closes #14722
Closes #15448
2016-12-02 18:29:51 +01:00
Martin Staffa 1d29c91c34 fix(ngOptions): don't add comment nodes as empty options
When the "empty option" element contains a transclusion directive, the result of the compilation always includes a comment node. Since we are adding / removing the "selected" attribute on the empty option, we need to make sure it's an actual element.

To solve this, we take advantage of the fact the each option element has an option directive that tries to register the option with the selectController. With ngOptions, this registerOption function is normally noop'd since it's not possible to add dynamic options. Now if the result of the empty option compilation is a comment, we re-define the function so that it catches empty options when they are actually linked / rendered.

Closes #15454
Closes #15456
2016-12-02 18:20:43 +01:00
Georgios Kalpakas 0e666eb0b9 test($compile): work around Chrome issue with reported size for <foreignObject>
Since Chrome 53-57+, the reported size of `<foreignObject>` elements and their
descendants is affected by global display settings (e.g. font size) and browser
settings (e.g. default zoom level). This could cause tests incorrectly failing
due to such settings.

In order to avoid false negatives, we now compare against the size of the
equivalent, hand-written SVG instead of fixed widths/heights.

Fixes #15333

Closes #15458
2016-12-01 14:51:38 +02:00
Peter Bacon Darwin b748046c04 docs(contribute): mention nvm-windows 2016-11-29 14:43:42 +00:00
Peter Bacon Darwin 3ecaccf719 docs(FAQ) add link to security guide 2016-11-29 14:43:41 +00:00
Peter Bacon Darwin 250fcecae1 chore(grunt): check node, yarn and grunt-cli versions
If global versions of node, yarn or grunt-cli don't match what we expect then blow up.
2016-11-29 14:43:41 +00:00
Peter Bacon Darwin 0b81a26045 chore(grunt): run gulp directly rather than through npm 2016-11-29 14:43:41 +00:00
Peter Bacon Darwin 3205e1c08c chore(utils): install npm-run to simplify scripts 2016-11-29 14:43:41 +00:00
Peter Bacon Darwin dcb5d32055 chore(travis): install grunt-cli globally to simplify scripts 2016-11-29 14:43:41 +00:00
Peter Bacon Darwin d69a64047b chore(jenkins): remove path to grunt
grunt is installed globally on jenkins so we can just use it directly.
2016-11-29 14:43:41 +00:00
Peter Bacon Darwin ebd841165d docs(ComponentRouter): it is unlikely ever to appear on bower or CDN 2016-11-29 14:43:41 +00:00
Peter Bacon Darwin f62079d452 chore(validate-commit): remove redundant scripts 2016-11-29 14:43:40 +00:00
Peter Bacon Darwin ad6ac68509 chore(saucelabs): update sauce-connect to 4.4.1 2016-11-29 14:43:40 +00:00
Peter Bacon Darwin 03ff634598 chore(bower): set clone depth to speed up releases
We already use `git clone ... --depth=1` for the `code.angularjs.org`
repository, which speeds up the cloning of the repository.
2016-11-29 14:43:40 +00:00
Peter Bacon Darwin bf1e3e0eac chore(npm-bundle-deps): remove unused script
This became reduntant as of 507ee2d9ba
2016-11-29 14:43:40 +00:00
Peter Bacon Darwin 0f001786d8 style(*): fix no-useless-escape eslint errors 2016-11-29 14:43:40 +00:00
Peter Bacon Darwin 97eca91927 docs(*): switch from npm to yarn 2016-11-29 14:39:33 +00:00
Peter Bacon Darwin 3821e8a951 chore(dependencies): USE YARN (and node 6) 2016-11-29 14:39:32 +00:00
Martin Staffa 1f61f30799 docs($compile, guide/compiler): add "double compilation" known issue
Related #15278
Closes #15392
2016-11-24 09:37:59 +00:00
Martin Staffa c57779d872 perf(*): don't trigger digests after enter/leave of structural directives
ngIf, ngInclude, ngSwitch, and ngView now use the `done` callback functions on animation runners returned
by leave/enter animations to do internal cleanup (and $anchorScroll for ngInclude and ngView).
Previously, they were using promise callbacks (`then`), which caused an unnessecary digest.

Background:

In https://github.com/angular/angular.js/commit/bf0f5502b1bbfddc5cdd2f138efd9188b8c652a9, animation
promises where introduced instead of animation callbacks. These promises were however not tied to
the digest cycle, so you had to manually call `$apply` inside them.

This was changed in https://github.com/angular/angular.js/commit/c8700f04fb6fb5dc21ac24de8665c0476d6db5ef,
so animation promise callbacks would always trigger a `$digest`. This meant that several built-in
directives would now trigger additional digests on leave (ngIf, ngSwitch) or enter/leave (ngInclude,
ngView). The `done` callback, which receives a single argument indicating success / failure was
introduced to allow digest-less responses, but wasn't applied to these directives.

Note that this applies to all calls to $animate.enter/leave, even if ngAnimate isn't included, and
no actual animations are running, because the animation runner code is in the core ng module.

Fixes #15322
Closes #15345
2016-11-24 09:37:59 +00:00
Martin Staffa 404046081d style(ngIfSpec.js, ngIncludeSpec.js): add top level describe 2016-11-24 09:37:59 +00:00
Martin Staffa 5b7ec8c84e fix(select): let ngValue take precedence over option text with multiple interpolations
Fixes #15413
Closes #15420
2016-11-24 09:37:59 +00:00
Martin Staffa 24471cf992 docs(*): add more info about deprecation versions 2016-11-24 09:37:59 +00:00
Georgios Kalpakas 8d644bd066 docs(guide/directive): minor wording and styling fixes 2016-11-24 09:37:59 +00:00
Santi Albo 78eecb43db fix($sce): fix adjustMatcher to replace multiple '*' and '**'
`adjustMatcher` was only replacing the first occurrences of '*' and '**'
that were found in whitelisted and blacklisted url strings.

Closes ##7897
2016-11-24 09:37:59 +00:00
Georgios Kalpakas 2791a855a6 docs(error/ng:areq): fix typo 2016-11-24 09:37:59 +00:00
Karthikeyan bbe8ad5698 docs(error/ng:areq): mention common error cause
Closes #15414
2016-11-24 09:37:59 +00:00
Peter Bacon Darwin 5041cf1f32 docs(*): fix up deprecation notices 2016-11-24 09:37:59 +00:00
Peter Bacon Darwin d1bbc2562d chore(docs): deprecation notices for methods and properties
Closes #15351
Closes #15394
2016-11-24 09:37:59 +00:00
Peter Bacon Darwin e19ad74ea4 chore(docs): bring in all templates from dgeni-packages 2016-11-24 09:37:59 +00:00
Arturo Romero 7586fa2b86 docs(guide/Forms): add labels to input elements
Closes #15403
2016-11-24 09:37:58 +00:00
Georgios Kalpakas 70fa4d308a docs(ngModel): fix typo and rephrase for simplicity 2016-11-24 09:37:58 +00:00
Georgios Kalpakas 75c83ff319 fix(ngMock/$controller): respect $compileProvider.preAssignBindingsEnabled()
Fixes #15387

Closes #15395
2016-11-24 09:37:58 +00:00
Peter Bacon Darwin e36dbab396 chore(Gruntfile): lengthen a+ promise test timeout to prevent flakes 2016-11-24 09:37:58 +00:00
Peter Bacon Darwin 4836278830 chore(docs): improve version picker
Closes #15385
2016-11-24 09:37:58 +00:00
Julio Borja Barra 3a8cc38b69 docs(ngModel): fix example
For the example to work correctly, the initial model values have to be empty strings.

Closes #15272
2016-11-24 09:37:58 +00:00
kentwalters a41efb2025 docs(guide/controller): change "hides" to "shadows"
"Shadows" should better convey the meaning of "overwriting the value of the property in the child
scope, while leaving the parent scope intact".
"Hides" could give the impression that it makes the property unavailable in the child scope and
leaving "overrides" only, could give the impression that the parent scope would be affected too,
especially to people not familiar with JavaScript's prototypal inheritance.

Closes #15375
2016-11-24 09:37:58 +00:00
Thomas Grainger b8ce60ac4a docs(angular.isArray): Document that isArray is an alias
Closes #15383
2016-11-24 09:37:58 +00:00
Peter Bacon Darwin 5386fe4316 test(): remove redundant hashPrefix params 2016-11-24 09:37:58 +00:00
Tim Black 82f85eda11 docs(ngRepeat): correct typo
Closes #15378
2016-11-24 09:37:58 +00:00
Kyle Wuolle 5b0e4cae49 docs(filterFilter): mark the comparator parameter as optional
Mark the `comparator` parameter as optional and mention that it defaults to `false`.

Fixes #15312

Closes #15371
2016-11-24 09:37:58 +00:00
Georgios Kalpakas 8c77aeb9b1 docs(ngRepeat): add warning about track by $index with one-time bindings 2016-11-24 09:37:58 +00:00
sathify f9354dc099 chore(docs): apply consistent css property spacing 2016-11-24 09:37:58 +00:00
sathify 7648811a94 chore(docs): use $document[0] 2016-11-24 09:37:58 +00:00
Martin Staffa e1c683be52 fix(docsApp): show correct version number in api index
Previously, the index would show the version of Angular that runs on
the page, not the version for which the docs are. This meant that in
that snapshot docs the stable version was displayed.

The `$scope.docsVersion` value was used in the plnkr opening code, but
has not been used since https://github.com/angular/angular.js/commit/bdec35cebc89e0d80a04eeffbd71ad999fc7e61a.

Closes #15265
2016-11-24 09:37:58 +00:00
Tom Harvey cd298d6272 docs($resourceProvider): correct JS syntax error in code example
Closes #15360
2016-11-24 09:37:58 +00:00
Corey Cacic 1cfb04d5c2 docs($cookiesProvider): add example for overwriting defaults on provider
Add an example on how to set default values on `$cookiesProvider`. Many similar services support
overriding the `defaults` object with a new one, but this service only supports changing individual
properties.

Closes #15362
2016-11-24 09:37:58 +00:00
Michał Gołębiowski 6c8450206e chore(*): switch URLs from npmcdn.com to unpkg.com
The domain changed, the old one redirects to the new one.
2016-11-24 09:37:58 +00:00
Kyle Lieber e269ad1244 perf(ngOptions): avoid calls to element.value
In some cases IE11/Edge calls to `element.value` are very slow when the
`element.value` has not been set. Normally, these calls are usualy 0-3 ms
but in these cases it can take 200-300 ms. This can easily add 3 or more
seconds to the load time on a view that has 10 or more select tags using
`ngOptions`.

The line this pull request is changing not only suffers from the performance
issue described above but it also appears to be broken. The code is checking
that `option.value` does not equal `element.value` but then sets `element.value`
to `option.selectValue`.

I don't believe `option.value` is actually defined anywhere and likely it
was always intended to be `option.selectValue`. This means that check would
always be true and since this code has been this way for quite a while and
is causing a performance issue I've just removed the check. This way a call
to `element.value` is never made prior to it's value being set.

Closes #15344
2016-11-24 09:37:58 +00:00
Erick Delfin 551983e7e1 docs(README.md): mention "Pug" (Jade's new name)
Closes #15338
2016-11-24 09:37:58 +00:00
Jason Bedard 87625a4581 refactor($compile): remove unnecessary assignment
Closes #15337
2016-11-24 09:37:58 +00:00
Josh Soref bcc44f13e5 docs(*): fix typos
* a
* allows
* angularytics
* animate
* architecting
* asynchronously
* attribute
* back
* browser
* callback
* component
* delimited
* dependencies
* dynamically
* empty
* encoded
* explicitly
* expression
* fails
* guarantees
* hierarchy
* highlight
* identifiers
* immediately
* infinite
* initialized
* inputting
* instance
* interprets
* linking
* location
* misformed
* numerically
* occurring
* overridden
* overwritten
* parameters
* Pluralsight
* precedence
* primitive
* properly
* prototypically
* representation
* response
* separately
* separator
* should
* specifying
* supported
* template
* thrown
* transclude
* transclusion
* transitions
* trigger
* useful
2016-11-24 09:37:58 +00:00
Josh Soref 1b6a1c30ee test(*): fix some inconsequential typos
* select
* synopsis
* params
* template
2016-11-24 09:37:57 +00:00
Martin Staffa a29fceadcd docs(a): remove outdated practice
Using a tags as buttons is bad for accessibility and usability
2016-11-24 09:37:57 +00:00
Martin Staffa 7b997ffa13 chore(docs-app): improve layout when loading partials
By setting the current partial content to hidden, the current height
of the window is maintained until the new content is loaded.
This prevents flickering caused by the scrollbar (dis)appearing and
the footer coming into view.
2016-11-24 09:37:57 +00:00
Erik Smith 89f2be1c10 docs(guide/production): fix typo ("3rd part" --> "3rd party")
Closes #15328
2016-11-24 09:37:57 +00:00
Allan Watson 600509bb67 docs(orderBy): clarify behavior of default comparator wrt null
Document how `orderBy`'s default comparator handles `null` values.

Fixes #15293

Closes #15304
2016-11-24 09:37:57 +00:00
emed 9aae7e8bb6 docs(error/ueoe): add another possible cause
Mention unescaped quotes as another possible cause for this error.

Closes #15313
2016-11-24 09:37:57 +00:00
Georgios Kalpakas 163f08ce86 chore(ng-closure-runner): upgrade to version 0.2.4
Version 0.2.4's `minErr` implementation is up to date with the one in core.

Fixes #14971

Closes #15307
2016-11-24 09:37:57 +00:00
Jonathan Yates f3cb6e309a fix($compile): clean up @-binding observers when re-assigning bindings
Fixes #15268

Closes #15298
2016-11-24 09:37:57 +00:00
Jason Bedard 0abf65b353 test($compile): ensure equal but different instance changes are detected in onChanges
Closes #15300
2016-11-24 09:37:57 +00:00
laranhee 136e65cc04 docs($rootScope): add missing round bracket
Closes #15299
2016-11-24 09:37:57 +00:00
Martin Staffa 593a503484 fix(input[radio]): use non-strict comparison for checkedness
This was introduced during the switch to ESLint (b1bc251#diff-c244afd8def7f268b16ee91a0341c4b2R1691),
but it is a breaking change. In master, we made an exception
for this comparison when we introduced jshint eqeqeq (which was not
backported to 1.5.x).

PR (#15289)
2016-11-24 09:37:57 +00:00
Martin Staffa 48dfeb2006 Revert "chore(doc-gen, docs-app): create plnkr examples with correct Angular version"
This patch relies on a change in the dgeni example package, which
has not been added yet.

This reverts commit 0a2b72360d.
2016-11-24 09:37:57 +00:00
Martin Staffa ffa46b95b9 chore(docs-app): show loader when loading view / partial
Closes #14385
PR (#15280)
2016-11-24 09:37:57 +00:00
Martin Staffa fddc534a13 chore(doc-gen, docs-app): create plnkr examples with correct Angular version
When the docs are based on the snapshot, the plnkr examples must use the snapshot files
from code.angularjs.org

Closes #15267
PR (#15269)
2016-11-24 09:37:57 +00:00
Martin Staffa 4bf8921813 fix($location): prevent infinite digest with IDN urls in Edge
Internationalized Domain Urls, for example urls with Umlaut (Ä, Ö, Ü)
cause infinite digest in Edge 38.14393.0.0 because lastIndexOf doesn't
work correctly in this version when the search string is the same as the haystack string.

The patch uses an implementation based on core.js: https://github.com/zloirock/core-js/blob/v2.4.1/modules/es6.string.starts-with.js#L16

Edge Bug: https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/9271625/

Fixes #15217
PR #15235
2016-11-24 09:37:57 +00:00
Georgios Kalpakas ee2e36d810 chore(tutorial): make diagram images responsive
Fixes angular/angular-phonecat#376

Closes #15275
2016-11-24 09:37:57 +00:00
Venkat Ganesan 87a31177b6 docs(input[checkbox]): mention ngChecked
Closes #14465
Closes #15277
2016-11-24 09:37:56 +00:00
Georgii Dolzhykov 95fa35afc4 docs($rootScope.Scope): grammar
Closes #15263
2016-11-24 09:37:56 +00:00
Martin Staffa dd0449c06f test($compile): fix tplrt tests for templateUrl 2016-11-24 09:37:56 +00:00
Martin Staffa e900f457fb refactor(compileSpec): make tests consistent
PR (#15141)
2016-11-24 09:37:56 +00:00
Peter Bacon Darwin b655744676 docs(CHANGELOG): add 1.2.31 release info 2016-11-24 09:37:56 +00:00
Michał Gołębiowski 748fee4ee7 refactor(jqLite): wrap the jqueryVersion binding in a span
Protractor's by.binding selector selects the whole element in which the binding
is contained as otherwise it can't know which bit of text has been interpolated.

It's safer to wrap the binding in a span so that we're sure what the e2e tests
are exactly testing.
2016-11-24 09:37:56 +00:00
Georgios Kalpakas 8e480d8d0c test(validators): fix broken test 2016-11-24 09:37:56 +00:00
Jason Bedard 4513dafd1a fix($parse): validate assignment lval in parser phase
The parser always threw an error in the case of an invalid left-value
assignment but it was an unhelpful:

```
Cannot set property 'undefined' of undefined
```

This commit provides a more meaningful error message, so it is not a
breaking change.

Closes #15234
2016-11-24 09:37:56 +00:00
BobChao87 9bc4ee89c8 refactor(ngModelSpec): use valueFn over curry
Refactor ngModelSpec to use internal helper function `valueFn`.
Use instead of multiple-defining a function called `curry`.

PR (#15231)

Addresses a quick change mentioned in PR 15208 from Issue #14734
2016-11-24 09:37:56 +00:00
Frank Stepanski b1c9075bcf docs(README.md): expand the "Interconnection with HTML" section
Closes #15150
2016-11-24 09:37:56 +00:00
Martin Staffa 44d70b384f docs(changelog): add missing commit and remove empty lines 2016-11-24 09:37:56 +00:00
Georgios Kalpakas 6de412311a docs($http): display the actual default Accept header 2016-11-24 09:37:56 +00:00
Vincent Gillot 49dce2ea4b docs(guide/component-router): fix typo ($routeOnReuse --> $routerOnReuse)
Closes #15224
2016-11-24 09:37:56 +00:00
Michał Gołębiowski 3ab1c3610b tests(jqLite): add basic tests for the bind/unbind aliases 2016-11-24 09:37:56 +00:00
Michał Gołębiowski 7717b96e95 perf(jqLite): move bind/unbind definitions out of the loop
The bind/unbind aliases to on/off were being assinged in every iteration
of the function assigning traversal methods to the prototype. Now it happens
only once.
2016-11-24 09:37:56 +00:00
Michał Gołębiowski cc54e433c2 chore(jqLite): fix a typo in a test name 2016-11-24 09:37:56 +00:00
Michał Gołębiowski 73ed7ef957 docs(jqLite): Document that removeAttr doesn't support multiple attributes
jQuery supports removing multiple attributes in one go, jqLite doesn't.
This is now documented.
2016-11-24 09:37:56 +00:00
Peter Bacon Darwin 2316ad7be9 chore(doc-gen): improve version dropdown info 2016-11-24 09:37:55 +00:00
Georgios Kalpakas e73dc0f31b test(*): introduce the toEqualMinErr() custom Jasmine matcher
Closes #15216
2016-11-24 09:37:55 +00:00
Georgios Kalpakas 9efe8426e5 refactor(*): use the toThrowMinErr() matcher when possible 2016-11-24 09:37:55 +00:00
Georgios Kalpakas feede20a3b docs($http): add deprecation notice for $httpProvider.useLegacyPromiseExtensions() 2016-11-24 09:37:55 +00:00
Justas Brazauskas b4735fdcbd docs(*): fix typos in comments and docs
Closes #15206
2016-11-24 09:37:55 +00:00
Georgios Kalpakas ed8aa16d30 docs($locationProvider): mention the default value for hash-prefix ('') 2016-11-24 09:37:55 +00:00
mrLarbi a5264090b6 feat($anchorScroll): convert numeric hash targets to string
This allows `$anchorScroll(7)` to scroll to `<div id="7">` (although technically, the target ID is a
string, not a number).

Fixes #14680

Closes #15182
2016-11-24 09:37:55 +00:00
Georgios Kalpakas 609264f8b0 docs(ngCsp): fix "directive"'s restrict and hide comment from output 2016-11-24 09:37:55 +00:00
Georgios Kalpakas f159e61893 docs(ngAnimate): fix typo ("an the" --> "an")
Fixes #15194
2016-11-24 09:37:55 +00:00
tijwelch 2875d9f6b0 docs($http): fix typo in headersGetter
Closes #15198
2016-11-24 09:37:55 +00:00
GregoryPorter 5a4e4e928e docs(tutorial): fix typos
- **step_04:** `controllers is one file` --> `controllers in one file`
- **step_06:** `.components.js` --> `.component.js`

Closes #15197
2016-11-24 09:37:55 +00:00
Georgii Dolzhykov eea9c597ac docs(angular.mock.inject): improve formatting
Without backticks, underscores are rendered as italics.

PR (#15186)
2016-11-24 09:37:55 +00:00
pharkare 6aeb442db4 docs(tutorial/index): fix spelling error for word 'standalone'
PR (#15187)
2016-11-24 09:37:55 +00:00
Georgios Kalpakas 22979904fb fix($compile): set attribute value even if ngAttr* contains no interpolation
Previoulsy, when the value of an `ngAttrXyz` attribute did not contain any interpolation, then the
`xyz` attribute was never set.

BTW, this commit adds a negligible overhead (since we have to set up a one-time watcher for
example), but it is justifiable for someone that is using `ngAttrXyz` (instead of `xyz` directly).

(There is also some irrelevant refactoring to remove unnecessary dependencies from tests.)

Fixes #15133

Closes #15149
2016-11-24 09:37:55 +00:00
Elliot Cameron 6c0fd3e26f docs(guide/filter): imrpove explanation of "pure function"
Improve the explanation of what a "pure function" is in simple words. The previous explanation
could be confusing, especially since the term "idempotent" (here used in it's broader
"Computer Science" meaning) is overloaded and has much stricter semantics in Mathematics or pure
Functional Programming.

Closes #15173
2016-11-24 09:37:54 +00:00
Adrian Bordinc db39512236 docs($compile): Fix a typo in the warning header
Closes #15184
2016-11-24 09:37:54 +00:00
Joao Dinis 57ef6a9237 docs(guide/concepts): insert comma
Closes #15166
2016-11-24 09:37:54 +00:00
Georgios Kalpakas 024bc1e160 refactor($resource): use route.defaults (already merged provider.defaults + options)
Closes #15160
2016-11-24 09:37:54 +00:00
Georgios Kalpakas 7e7b5151db refactor($resource): use local references of Angular helpers 2016-11-24 09:37:54 +00:00
Georgios Kalpakas 530395059f fix($resource): pass options when binding default params
`Resource.bind()`, which creates an new Resource class with the same propertiesexcept for the
additional bound default parameters, was not passing the original Resource class' `options`,
resulting in different behavior.
This commit fixes it by passing the `options` when creating the new Resource class.
2016-11-24 09:37:54 +00:00
davidcigital 9ea1e440ea docs(ngCsp): update explanation of CSP rules and how they affect Angular
Update the description of CSP, mainly regarding `unsafe-eval` and `unsafe-inline`. The way it was
presented previously was slightly misleading as it indicated that these were rules forbidding
certain things, when in fact it's a keyword in the CSP that disables the very rule that was
described. The updated text clarifies this better.

Closes #15142
2016-11-24 09:37:54 +00:00
Matt Gilson 9b9f14e52e docs(angular.toJson): add missing param type
Reference:
[JSON.stringify](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify).

Closes #15156
2016-11-24 09:37:54 +00:00
Georgios Kalpakas b11a513429 docs($templateCache): fix typo (template --> templateCache) 2016-11-24 09:37:54 +00:00
Stepan Suvorov a419ff03d4 docs(cacheFactory): remove ng-include practice from docs
Generally we don't use `ngInclude` any more, so this commit updates the
example snippet to use component instead.

Closes #15153
2016-11-24 09:37:54 +00:00
thorn0 9449893763 fix($compile): bindToController should work without controllerAs
Fixes #15088

Closes #15110
2016-11-24 09:37:54 +00:00
Georgios Kalpakas 07e1ba365f fix($compile): do not overwrite values set in $onInit() for <-bound literals
See #15118 for more details.

Fixes #15118

Closes #15123
2016-11-24 09:37:54 +00:00
Georgios Kalpakas 287a5dd4bd refactor(ngOptions): access copy() directly (angular.copy --> copy) 2016-11-24 09:37:54 +00:00
Prashant Singh Pawar 12752f66ac fix($compile): don't throw tplrt error when there is whitespace around a top-level comment
Added new conditional for NODE_TYPE_TEXT inside removeComments method of $compile
Added corresponding unit tests.

Closes #15108
PR (#15132)
2016-11-24 09:37:54 +00:00
Martin Staffa fbdfd193f7 chore(benchmarks): fix order-by benchmark 2016-11-24 09:37:54 +00:00
Austin O'Neil 05896d44ad docs(ngOptions): correct links
remove redundant link to ngOptions and add link to ngRepeat
2016-11-24 09:37:54 +00:00
Georgii Dolzhykov 00b01e09ca docs($compile): remove obsolete sentence
Fixes #15109

Closes #15119
2016-11-24 09:37:54 +00:00
Jason Bedard afc093b8b7 refactor($q): remove unnecessary checks/helpers/wrappers
- Remove internal `makePromise()` helper.
- Remove unnecessary wrapper functions.
- Remove unnecessary check for promises resolving multiple times.
  (By following the Promises/A+ spec, we know this will never happen.)
- Switch from function expressions to (named) function declarations.

Closes #15065
2016-11-24 09:37:54 +00:00
Mohsen Azimi fcffa181ce docs($q): fix typo in race() test description (array --> object)
Closes #15111
2016-11-24 09:37:53 +00:00
Martin Staffa e105dda1de docs(ngSwitch): add separator example 2016-11-24 09:37:53 +00:00
Lucas Galfaso 0e1651bfd2 feat(ngSwitch): allow multiple case matches via optional attribute ngSwitchWhenSeparator
Adds an optional attribute `ngSwitchWhenSeparator` that allows multiple tokens to match a given `ngSwitchWhen`.

Closes #3410
Closes #3516

Closes #10798
2016-11-24 09:37:53 +00:00
Austin O'Neil af4a44cbaf docs(guide/component): clarify when to use directives instead of components
Clarify that components cannot be used to perform actions in compile
and prelink functions.

Closes #15042
PR (#15100)
2016-11-24 09:37:53 +00:00
sethbattin ed89fc8ee6 docs($resourceProvider): include '$' in di in example
The injection argument is missing the '$' in the two examples.  The code fails as written.  This change corrects it.

(#15099)
2016-11-24 09:37:53 +00:00
Martin Staffa 6a7a3250cf docs($compile): link to sections from properties in examples 2016-11-24 09:37:53 +00:00
Martin Staffa 8455d2a797 docs(error/noident): add missing comma
Closes #15086
2016-11-24 09:37:53 +00:00
BobChao87 862dc2532f fix($sanitize): reduce stack height in IE <= 11
Update Internet Explorer-only helper function stripCustomNsAttrs to be less
recursive. Reduce stack height of function causing out of stack space error.

Closes #14928
Closes #15030
2016-11-24 09:37:53 +00:00
Michał Gołębiowski 7d11bc4f91 refactor(jqLite): use the toEqualOneOf matcher in jqLite tests 2016-11-24 09:37:53 +00:00
Michał Gołębiowski 006e05074a refactor(matchers): add the toEqualOneOf matcher 2016-11-24 09:37:53 +00:00
Michał Gołębiowski 1ea884ae7e refactor(jqLite): run more tests on jQuery 2.2, add version detection helpers
(cherry-picked from 6341f4260a)
2016-11-24 09:37:53 +00:00
Georgios Kalpakas c82bb89964 docs($compile): be more explicit about linking not having taken place inside cloneAttachFn
Fixes #15093
2016-11-24 09:37:53 +00:00
Georgios Kalpakas bb7f4a8733 test($compile): extend $onChanges() test to account for one more case
Discussed in https://github.com/angular/angular.js/pull/15098/files#r77770755.
2016-11-24 09:37:53 +00:00
Georgios Kalpakas 0cf5be5264 fix($compile): avoid calling $onChanges() twice for NaN initial values
Closes #15098
2016-11-24 09:37:53 +00:00
Peter Bacon Darwin 584a6b39e4 test($compile): add tests for provider settings
See https://github.com/angular/angular.js/pull/15095#issuecomment-244970426
2016-11-24 09:37:53 +00:00
Peter Bacon Darwin f86576def4 feat($compile): add preAssignBindingsEnabled option
A new option to enable/disable whether directive controllers are assigned bindings before
calling the controller's constructor.

If enabled (true), the compiler assigns the value of each of the bindings to the
properties of the controller object before the constructor of this object is called.

If disabled (false), the compiler calls the constructor first before assigning bindings.

The default value is enabled (true) in Angular 1.5.x but will switch to false in Angular 1.6.x.

See #14580
Closes #15095
2016-11-24 09:37:53 +00:00
Packt 609e807b04 docs(guide/External Resources): add a paid-online course
Closes #15075
2016-11-24 09:37:53 +00:00
Jason Bedard 31d464feef perf($compile): validate directive.restrict property on directive init
This allows the removal of try/catch from addDirective to avoid V8 deopt.

Previously the directive.restrict property was not validated. This would
potentially cause exceptions on each compilation of the directive
requiring a try/catch and potentially causing repeated errors.

New validation when directive.restrict is specified:
* must be a string
* must contain at least one valid character (E, A, C, M)

Cases which previously silently failed (now throw an error):
* values with an indexOf method (such as strings, arrays) which returned
 returned -1 for all valid restrict characters

Cases which previously worked unintentionally (now throw an error):
* arrays with single-character strings of valid restrict characters

PR (#13263)
2016-11-24 09:37:53 +00:00
Martin Staffa 5c9399d18a feat($compile): throw error when directive name or factory fn is invalid
Closes: #15056
PR (#15057)
2016-11-24 09:37:52 +00:00
Georgios Kalpakas a8da25c74d feat($resource): pass status/statusText to success callbacks
Fixes #8341
Closes #8841
PR (#14836)
2016-11-24 09:37:52 +00:00
Georgios Kalpakas 6bb775ccd1 docs(tutorial/step_03): improve explanation of camel-/kebab-casing
Related to #15051.
2016-11-24 09:37:52 +00:00
Wei Wang a4a22266f1 feat($location): add support for selectively rewriting links based on attribute
In HTML5 mode, links can now be selectively rewritten, by setting `mode.rewriteLinks` to a string
(denoting an attribute name). Anchor elements that have the specified attribute will be rewritten,
while other links will remain untouched.

This can be useful in situations where it is desirable to use HTML5 mode without a `<base>` tag, but
still support rewriting specific links only. See #14959 for more details on a possible usecase.

Closes #14976
2016-11-24 09:37:52 +00:00
Benjamin Blackwood 401da6873a docs($resource): add status param to transformResponse signature
Add `status` param to `transformResponse` signature to keep inline with 1b74097.

Closes #15041
2016-11-24 09:37:52 +00:00
Duly Bonheur 311b5faf08 docs(ngRepeat): improve example description
The example seems to also be filtering by age. It threw me off a bit because I was getting results when I entered numbers in the input field.

PR (#15037)
2016-11-24 09:37:52 +00:00
Martin Staffa 6cd911c132 docs($componentController): add more info 2016-11-24 09:37:52 +00:00
Martin Staffa 9ae793d8a6 feat($controller): throw when requested controller is not registered
Previously, it would throw the ng:areq error, which is less
specific and just informs that the requested controller is not defined.
Given how commonly controllers are used
in Angular, it makes sense to have a specific error.

The ng:areq error is still thrown when the registered controller
is not a function.

Closes #14980
PR (#15015)
2016-11-24 09:37:52 +00:00
Peter Bacon Darwin 7fa2fdba3b chore(package.json): update to latest dgeni-packages 2016-11-24 09:27:57 +00:00
Peter Bacon Darwin b871be1392 chore(package.json): update to latest version of shelljs 2016-11-24 09:27:57 +00:00
Peter Bacon Darwin 65bfce7d68 chore(protractor): upgrade to latest 4.0.10
This fixes problems with testing against Chrome 54.
2016-11-24 09:27:56 +00:00
Martin Staffa 67126bd3a0 chore(*): use binaries from node_modules/.bin
Closes #15071
2016-11-24 09:27:56 +00:00
John-David Dalton ce6558fd80 chore(npm): use require.resolve when possible to avoid hard coded module paths 2016-11-24 09:27:56 +00:00
Georgios Kalpakas 64f6a616d4 fix(input): fix step validation for input[number][ng-range-input]
Related to 9a8b8aa and #15257. Fixes the issue discussed in
https://github.com/angular/angular.js/commit/9a8b8aa#commitcomment-19108436.

Fixes #15257

Closes #15264
2016-11-24 09:27:56 +00:00
Georgios Kalpakas 07b8761233 fix(input[range]): make support for input[range] opt-in
Closes #15229
2016-11-24 09:27:56 +00:00
Georgios Kalpakas 2e7121b8e4 feat(input): re-add support for binding to input[range]
This commit re-applies the related (previously reverted) commits. A follow-up
commit will make the support opt-in in order to avoid a breaking change.

Included commits:

- 296da4b - `feat(input): add support for binding to input[type=range]`
  (previously reverted with 6a167e8)

- b78539b - `fix(input[range]): correctly handle min/max; remove ngMin/ngMax support`
  (previously reverted with aa60491)

- 90c08b8 - `feat(input[range]): support step`
  (previously reverted with 5b633d8)
2016-11-24 09:27:55 +00:00
Peter Bacon Darwin da3f2df163 revert:feat(input): add support for binding to input[type=range]
This reverts commit 296da4b561
2016-11-24 09:27:55 +00:00
Peter Bacon Darwin 51944b3999 revert: fix(input[range]): correctly handle min/max; remove ngMin/ngMax support
This reverts commit b78539bfc0
2016-11-24 09:27:55 +00:00
Peter Bacon Darwin 612589d0bc revert: feat(input[range]): support step
This reverts commit 90c08b844a
2016-11-24 09:27:55 +00:00
Peter Bacon Darwin 1b32fad833 revert: feat(input[number]): support step
This reverts from commit c0b42f0678
2016-11-24 09:27:55 +00:00
Jérome Freyre 3bf758063e docs(input[range]): fix erroneous examples
PR (#15135)
2016-11-24 09:27:54 +00:00
gdi2290 82ea2de3fb refactor(*): introduce isNumberNaN
window.isNaN(‘lol’); //=> true
Number.isNaN(‘lol’); //=> false

isNaN converts it’s arguments into a Number before checking if it’s NaN.
In various places in the code base, we are checking if a variable is a Number and
NaN (or not), so this can be simplified with this new method (which is not exported on the
global Angular object).

Closes #11242
2016-11-24 09:27:54 +00:00
Martin Staffa 8ace661ba5 feat(input[number]): support step
input[number] will now set the step error if the input value
(ngModel $viewValue) does not fit the step constraint set in the step / ngStep attribute.

Fixes #10597
2016-11-24 09:27:54 +00:00
Martin Staffa 8a9cd3e01d feat(input[range]): support step
Step support works like min / max, but with the following caveat.
Currently, only Firefox fully implements the spec. Other browsers
(Chrome, Safari, Edge) have issues when the step value changes
after the input has been changed. They do not adjust the input value
to a valid value, but instead set the stepMismatch validity state.

Angular will take this validity state, and forward it as the ngModel
"step" error. Adjusting the error ourselves would add too much code,
as the logic is quite involved.
2016-11-24 09:27:54 +00:00
Martin Staffa 9ea37de0f5 fix(input[range]): correctly handle min/max; remove ngMin/ngMax support
This commit fixes the handling of min/max, and removes support for ngMin/ngMax:

min/max:
Previously, interpolated min/max values on input range were not set when the first $render happens,
because the interpolation directive only sets the actual element attribute value after
a digest passes. That means that the browser would not adjust
the input value according to min/max and the range input and model would
not be initialzed as expected.
With this change, input range will set the actual element attribute value during its own
linking phase, as it is already available on the attrs argument passed to the link fn.

ngMin/ngMax
Since ng prefixed attributes do not set their corresponding element attribute, the range input would always have min = 0, and max = 100 (in supported browsers), regardless of the value
in ngMin/ngMax. This is confusing and not very useful, so it's better to not support these attributes at all.

The commit also fixes a test which used an interpolation inside an attribute that expects an expression.

Fixes #14982
PR (#14996)
2016-11-24 09:27:54 +00:00
Georgios Kalpakas b44432a719 docs(guide/concepts): improve wording 2016-11-24 09:27:53 +00:00
Georgios Kalpakas ac0e10d287 chore(build): fix version placeholder matching
During the `build` task, the version placeholders will be replaced with the actual values using a
RegExp, which expects the placeholders to be surrounded by double quotes. By replacing the quotes
from double to single in #15011, the RegExp was not able to match the placeholders.

(For reference, the RegExps that match and replace the version placeholders are in
[lib/grunt/utils.js][1].)

[1]: https://github.com/angular/angular.js/blob/859348c7f61ff5f93b9f81eb7f46842bd018d8e3/lib/grunt/utils.js#L125-L130

Closes #15016
2016-11-24 09:27:53 +00:00
Michał Gołębiowski 1237c77850 chore(*): change remaining /* @this */ to /** @this */
Ref ec565ddd9c
2016-11-24 09:26:24 +00:00
Michał Gołębiowski 9a9b07dea8 chore(eslint): enable quotes: ["error", "single"]
The quotes rule had to be disabled for e2e tests generated from ngdoc
because dgeni templates use double quotes as string delimiters.

Since we can't have guarantees that dgeni template wrappers will follow
the same JS code style the Angular 1 repo uses, we should find a way
to enforce our ESLint setup only for the parts in this repo, perhaps
via prepending a generated `/* eslint-enable OUR_RULES */` pragma.

(partially cherry-picked from 9360aa2d27)

Closes #15011
2016-11-24 09:26:24 +00:00
Peter Bacon Darwin 8b913b99d9 chore(protractor): upgrade to latest 4.0.10
This fixes problems with testing against Chrome 54.
2016-11-24 09:26:23 +00:00
Martin Probst 4edd2d95c1 feat(security): explicitly whitelist URL schemes for bootstrap. (#15427)
Many browsers have some extension URL scheme. It is unclear how many of
those have the security issue of allowing parser-inserted loads of
extension URLs.

To be conservative, this code whitelists the URL schemes that are known
to be subject to CSP, i.e. the ones that are expected and safe.
2016-11-24 09:25:34 +00:00
Peter Bacon Darwin 353e3a6cd8 fix($location): throw if the path starts with double (back)slashes
Previously `$location` was rewriting such paths to remove not only the
double slashes but also the first segment of the path, leading to an invalid
path.

In this change, we deem leading double (back)slashes an invalid path and
now throw a `$location:badpath` error if that occurs.

Closes #15365
2016-11-21 21:17:27 +00:00
Martin Probst 6ce2913d99 fix(security): do not auto-bootstrap when loaded from an extension.
Extension URIs (`resource://...`) bypass Content-Security-Policy in Chrome and
Firefox and can always be loaded. Now if a site already has a XSS bug, and uses
CSP to protect itself, but the user has an extension installed that uses
Angular, an attacked can load Angular from the extension, and Angular's
auto-bootstrapping can be used to bypass the victim site's CSP protection.

Notes:
- `isAutoBootstrapAllowed` must be initialized on load, so that `currentScript`
  is set correctly.
- The tests are a bit indirect as reproducing the actual scenario is too
  complicated to reproduce (requires signing an extension etc). I have confirmed
  this to be working manually.

Closes #15346
2016-11-21 21:17:27 +00:00
Peter Bacon Darwin 6a24885771 fix($compile): ensure that hidden input values are correct after history.back
Due to the nature of some browser's PageCache/BFCache, returning to an Angular
app sometimes causes `input[hidden]` elements to retain the last value
that was stored before the page was navigated away from previously.

This is particularly problematic if the input has an interpolated value.
E.g. `<input type="hidden" value="{{ 1 + 2 }}">` since when the browser
returns, instead of the original interpolation template, the HTML contains
the previous value `<input type="hidden" value="3">`.

This commit instructs the browser not to attempt to reinstate the previous
value when navigating back in history by setting `autocomplete="off"` on
the hidden input element element.
2016-11-21 21:17:26 +00:00
Tyler Romeo 367da583bc fix($sniffer): don't use history.pushState in sandboxed Chrome Packaged Apps
While sandboxed Chrome Packaged Apps (CPAs) have the same restrictions wrt
accessing `history.pushState` as "normal" CPAs, they can't be detected in the
same way, as they do not have access to the same APIs.
Previously, due to their differences from normal CPAs, `$sniffer` would fail to
detect sandboxed CPAs and incorrectly assume `history.pushState` is available
(which resulted in an error being thrown).
This commit fixes the detection of sandboxed CPAs in `$sniffer`.

See #11932 and #13945 for previous work.

Closes #15021
2016-11-21 21:16:11 +00:00
Raphael Jamet 68fb70ed29 fix($compile): lower the $sce context for src on video, audio, source, track
Previously, video, audio, source, and track sources were $sce.RESOURCE_URL. This is not justified as
no attacks (script execution) are possible through these attributes as far as we can tell.
Angular2 also uses the same categorization.

This change is not breaking, and uses of $sce.trustAsResourceUrl before assigning to src or ng-src
attributes will just be silently ignored.

This has also been given a LGTM by @mprobst via email.

Commit 485320129d on the master branch contains the same changes, but
is missing this commit description.

This commit does not backport the BC introduced in 04cad41d26.

PR (#15039)
Closes #14019
2016-11-21 21:16:11 +00:00
Georgios Kalpakas e8e8186d40 docs(CONTRIBUTING.md): minor improvements
Closes #15008
2016-08-10 20:50:15 +03:00
Benjamin Dopplinger 0f3385d45d docs(contributing.md): fix indentation for proper Markdown syntax
PR (#15007)
2016-08-10 11:35:16 +03:00
Georgios Kalpakas 4897430559 docs(ngMock/$httpBackend): improve description of .flush() 2016-08-09 00:37:05 +03:00
sarychev 098b6f519a feat(ngMock/$httpBackend): flush requests in any order
Previously, requests were flushed in the order in which they were made.
With this change, it is possible to flush requests in any order. This is useful for simulating more
realistic scenarios, where parallel requests may be completed in any order.

Partially addresses #13717.

Closes #14967
2016-08-09 00:36:13 +03:00
Georgios Kalpakas 549edc9d01 fix($httpBackend): complete the request on timeout
When using the [timeout attribute](https://xhr.spec.whatwg.org/#the-timeout-attribute) and an XHR
request times out, browsers trigger the `timeout` event (and execute the XHR's `ontimeout`
callback). Additionally, Safari 9 handles timed-out requests in the same way, even if no `timeout`
has been explicitly set on the XHR.
In the above cases, `$httpBackend` would fail to capture the XHR's completing (with an error), so
the corresponding `$http` promise would never get fulfilled.

Note that using `$http`'s `timeout` configuration option does **not** rely on the XHR's `timeout`
property (or its `ontimeout` callback).

Fixes #14969
Closes #14972
2016-08-08 19:16:30 +03:00
Georgios Kalpakas 6ed4c61e72 chore(package): fix some warnings/errors
Related to #14952. Fixed the following warnings/errors:

1. **Warning**: Closure Compiler complained about `/* @this */` (annotations in non-JSDoc comments).
   Fixed by changing `/* @this */` to `/** @this */`.

2. **Warning**: Dgeni complained about `/** @this */` (invalid tags found).
   Fixed by adding an empty `this` tag definition in `docs/config/tag-defs/`.

3. **Error**: ESLint complained about CRLF linebreaks in `build/docs/examples/`. These are generated
   by dgeni and (apparently) use the system's default linebreak (e.g. CRLF on Windows).
   Fixed by disabling the `linebreak-style` rule for `build/docs/examples/`.

Closes #14997
2016-08-08 18:45:10 +03:00
Georgios Kalpakas f83c3dea23 perf($parse): improve performance of assignment expressions
There was a ~5% improvement in the added `parsed-expressions-bp/assignment` benchmark (which only
contains assignment expressions). In real-world applications, the time spent in assignment
expressions will be a tiny fragment of the overall processing time, though.

Closes #14957
2016-08-08 16:00:18 +03:00
Michał Gołębiowski f60254f79a fix(travis): Don't run e2e tests with jQuery twice
The e2e tests were set up to be run twice; once with the latest supported
jQuery and once with jQuery 2.1. However, the latest jQuery was used in both
cases. The initial plan was to just run integration tests with the latest
jQuery and leave regression testing for jQuery 2.1 to unit tests as they're
way faster. This commit removes the jQuery 2.1 e2e tests entry.

This commit has been landed on master a few months ago but I forgot to
backport it to v1.5.x.

(cherry-picked from 038d990bc1)
2016-08-08 14:35:41 +02:00
Martin Staffa d2a57b9dff style(benchmarks): fix eslint errors 2016-08-08 15:24:35 +03:00
dherman 33a693ea62 chore(styleDirective): remove an unneccessary directive definition
Since the style directive is defined as a non-terminal element directive
with no behavior on link, we may as well not define anything at all.
PR (#14983)
2016-08-08 15:22:34 +03:00
Roshan Jossey dd1a957bb3 docs(guide/external-resources): add links to Atom and Vim packages
Add links to packages for Atom and Vim editors under editor support
subsection under tools section.
PR (#15000)
2016-08-08 15:19:29 +03:00
David Rodenas 775c247085 perf($compile): add provider option to turn off compilation of css class and comment directives
When the functions `cssClassDirectivesEnabled()` / `commentDirectivesEnabled()` on the `$compileProvider` are called with `false`, then the compiler won't look for directives on css classes / comment elements.

This can result in a compilation speed-up of around 10%.

PR (#14850)
2016-08-08 15:14:51 +03:00
Michał Gołębiowski 4d753d197a chore(*): minor code style tweaks
This is a followup to the migration to ESLint.

Ref #14952

Closes #15006
2016-08-08 15:06:24 +03:00
Kevin Visscher 8b51d03c83 docs(error/reqslot): fix typo
Closes #15003
2016-08-08 14:34:03 +03:00
Michał Gołębiowski b1bc25169e chore(*): switch from JSHint/JSCS to ESLint
Partially cherry-picked from c3220325a0

Ref #14952

Closes #14993
2016-08-08 13:53:52 +03:00
Michał Gołębiowski 9f10428651 fix(jenkins): Fix the format for passing parameters to Grunt tasks
The Jenkins build.sh script has to be updated as the previous way of
specifying parameters to the code run in Grunt tasks stopped working
with the newest Grunt. This has been previously fixed for the Travis
build.sh but wasn't done for the Jenkins one.

Also, the contribute docs were updated to account for the new format.

(cherry-picked from 5fc993361f)
2016-08-06 01:03:07 +02:00
Michał Gołębiowski 6b28705dbf chore(package.json): Remove the deprecated licenses field
The "licenses" field is deprecated in favor of the "license" field... which
we already have specified.
2016-08-05 22:22:02 +02:00
Michał Gołębiowski 802cdf6ccb chore(package.json): update Karma & BrowserStack-related packages 2016-08-05 22:21:58 +02:00
Michał Gołębiowski a19d026bff chore(package.json): remove the engineStrict field
The engineStrict field is deprecated in npm 2 and removed in npm 3.
2016-08-05 22:21:53 +02:00
Michał Gołębiowski d23512c7f3 chore(*): Add .nvmrc
If one uses nvm to manage Node.js versions, the .nvmrc file makes `nvm use`
switch to the version specified in .nvmrc. There are scripts that invoke
it automatically when cd'ing to directories containing .nvmrc so that you
never run build commands using a wrong Node version, see:
https://github.com/creationix/nvm/blob/v0.31.2/README.markdown#zsh
2016-08-05 22:21:49 +02:00
Michał Gołębiowski 8e58e22d93 chore(bower): change the name in bower.json
This avoids warnings with newer versions of Bower.
2016-08-05 22:21:44 +02:00
Michał Gołębiowski 42cff065b8 chore(package.json): upgrade Protractor
The previous version depended on a vulnerable request version.

Ref gh-14961
2016-08-05 22:21:40 +02:00
Michał Gołębiowski 2c852cf62a chore(package.json): add grunt-cli to devDependencies, update grunt-* packages
The Travis build.sh script has to be updated as the previous way of
specifying parameters to the code run in Grunt tasks stopped working
with the newest Grunt.
2016-08-05 22:21:26 +02:00
Georgios Kalpakas bf4f51573d docs($filter): improve description formatting 2016-07-31 10:47:08 +03:00
Vitaly P 5a7dc50f26 docs($filter): add link to built-in filters page 2016-07-31 08:29:56 +03:00
Georgios Kalpakas f9e7dabb2a docs(textarea): add known issue about interpolation in placeholder in IE
Closes #5025

Closes #14965
2016-07-31 08:25:12 +03:00
Martin Staffa 296da4b561 feat(input): add support for binding to input[type=range]
Thanks to @cironunes for the initial implementation in https://github.com/angular/angular.js/pull/9715

Adds support for binding to input[range] with the following behavior / features:

- Like input[number], it requires the model to be a Number, and will set the model to a Number
- it supports setting the min/max values via the min/max and ngMin/ngMax attributes
- it follows the browser behavior of never allowing an invalid value. That means, when the browser
converts an invalid value (empty: null, undefined, false ..., out of bounds: greater than max, less than min)
to a valid value, the input will in turn set the model to this new valid value via $setViewValue.
-- this means a range input will never be required and never have a non-Number model value, once the
ngModel directive is initialized.
-- this behavior is supported when the model changes and when the min/max attributes change in a way
that prompts the browser to update the input value.
-- ngMin / ngMax do not prompt the browser to update the values, as they don't set the attribute values.
Instead, they will set the min / max errors when appropriate
- browsers that do not support input[range] (IE9) handle the input like a number input (with validation etc.)

Closes #5892
Closes #9715
Close #14870
2016-07-29 14:30:48 +02:00
Georgios Kalpakas 9019c2dac5 test(e2e): fix e2e tests in Firefox 2016-07-29 11:44:20 +03:00
Peter Bacon Darwin 83a12a54a2 docs(examples): give all examples a name
Closes #14958
2016-07-28 11:07:20 +01:00
Chung-Min Cheng 9fdb4f8c51 docs(guide/animations): clean up example
Remove unnecessary inline styles, merge styles for identical selectors and clean up.

Closes #14960
2016-07-28 12:43:14 +03:00
Georgios Kalpakas fcce237902 docs(ngModel/numfmt): remove redundant argument 2016-07-27 12:05:24 +03:00
Georgios Kalpakas d7e31b5dc7 fix($parse): block assigning to fields of a constructor prototype
This commit also adds the missing `isecaf` error page and more tests for assignment to constructors.

Fixes #14939

Closes #14951
2016-07-27 11:03:34 +03:00
Georgios Kalpakas b014607030 fix($parse): correctly escape unsafe identifier characters
This commit also adds a couple of tests for `$parseProvider.setIdentifierFns()`.

Closes #14942
2016-07-26 10:31:24 +03:00
Georgios Kalpakas fd46fc80ee test($parse): test custom literals with CSP both enabled and disabled
(This commit also includes a minor clean-up.)
2016-07-26 10:31:23 +03:00
Georgios Kalpakas d26ba3b941 chore(travis): update sauce-connect
Closes #14936
2016-07-25 18:55:25 +03:00
Martin Staffa 6fa1bb03db chore(travis): use Firefox 47
This commit also adds a new capability to the protractor configs that
ensures that all angularjs.org tests run correctly on Firefox. See
https://github.com/SeleniumHQ/selenium/issues/1202
2016-07-25 17:42:12 +02:00
Martin Staffa 8ebd716c57 chore(npm): update protractor to 4.0.0
4.0.0 is the first version with Selenium 2.53.x, and we need that as lower versions have problems
with current Firefox versions.
See https://github.com/SeleniumHQ/selenium/issues/1202 and https://github.com/SeleniumHQ/selenium/issues/2110.

We are currently running tests on FF28.

As part of the update the deprecated webdriver fn getInnerHtml has been replaced with getAttribute('innerHTML')
2016-07-25 17:42:12 +02:00
Giuseppe Scoppino cb94d562df docs(guide/component): document $doCheck in the component guide
The docs for `$compile` were updated in e235f20 to include information about the recently
implemented `$doCheck` lifecycle hook for component controllers. The lifecycle hook documentation is
mirrored in the Component guide, and this change mirrors the update made to the `$compile` docs, to
the component guide docs.

Closes #14946
2016-07-25 18:20:07 +03:00
Martin Staffa d31b3a65b6 fix(ngOptions): remove selected attribute from unselected options
When the select model changes, we add the "selected" attribute to the selected option, so that
screen readers know which option is selected.

Previously, we failed to remove the attribute from the selected / empty option when the model changed
to match a different option, or the unknown / empty option.

When using "track by", the behavior would also show when a user selected an option, and then the
model was changed, because track by watches the tracked expression, and calls the $render function
on change.

This fix reads the current select value, finds the matching option and removes the "selected"
attribute.

IE9 had to be special cased, as it will report option.hasAttribute('selected') === true even
if the option's property and attribute have been unset (even the dev tools show not selected attribute).

I've added a custom matcher that accounts for this behavior. In all other browsers, property and
attribute should always be in the same state. Since few people will use screen readers with IE9, I
hope this is a satisfactory solution to the problem.

Fixes #14892
Fixes #14419
Related #12731
PR (#14894)
2016-07-23 17:20:48 +02:00
Martin Staffa 5a70888153 chore(travis): use Chrome 51 and FF 47 in unit tests
PR (#14943)
2016-07-23 17:20:47 +02:00
Martin Staffa 3475b19482 docs(form): clarify what $setPristine does 2016-07-22 21:36:01 +02:00
Martin Staffa 00a30fad82 docs(guide/External Resources): move it after the introduction 2016-07-22 21:36:01 +02:00
Peter Bacon Darwin 22b669407c docs(CHANGELOG.md): add release notes for v1.5.8 2016-07-22 16:01:46 +01:00
Georgios Kalpakas 99a063f9cb docs(CHANGELOG.md): add release notes for v1.2.30 2016-07-22 15:45:08 +01:00
Georgios Kalpakas 27db9f018e test($anchorScroll): add e2e tests
Fixes #9535
Closes #9583

Closes #14932
2016-07-20 11:45:09 +03:00
Brad 2ed2399d49 docs($httpParamSerializer): fix typo (remove superfluous quote)
Closes #14934
2016-07-20 10:48:32 +03:00
Georgios Kalpakas 9d2de344f5 refactor($http): clean up code
Closes #14921
2016-07-19 23:25:11 +03:00
Georgios Kalpakas 9c0659ca27 refactor($http): move functions together and order alphabetically
Closes #14921
2016-07-19 23:10:39 +03:00
Georgios Kalpakas 3b9963c54a refactor(test/e2e): make file/directory names consistent 2016-07-19 21:46:34 +03:00
Georgios Kalpakas 26db937377 test($resource): add some tests wrt handling response errors
The test currently fail on master, but should pass on 1.5.x.
A subsequent commit will fix the regressions on master.

(This commit should be backportable to 1.5.x.)

Related to #14837.
2016-07-18 14:55:55 +01:00
Georgios Kalpakas 1d0e582b3f chore(protractor): use directConnect locally to speed up tests
Closes #14919
2016-07-18 10:03:41 +01:00
Georgios Kalpakas a6b58019e1 refactor(test/e2e): remove explicit call to waitForAngular()
Protractor automatically calls `waitForAngular()`, before every WebDriver action.

Closes #14920
2016-07-18 10:03:40 +01:00
Georgios Kalpakas 38fd896b74 refactor(test/e2e): restore consistency across tests (just because) 2016-07-18 10:03:40 +01:00
Georgios Kalpakas f96d553822 docs(guide): fix links to tutorial steps 2016-07-15 20:07:10 +03:00
John (J5) Palmieri f4149b70bc doc(guide/Animations): point to $animate.pin() to enable animation for elements outside an Angular app
Add a section inside of the ngAnimate documentation to point to $animate.pin().
It was not clear in the documentation why animations were being disabled inside of
modals and popup menus. This documentation explains in what situations elements may
be dynamically placed outside of the application DOM and points to the API documentation
on how to enable animations for these types of elements.

Related #14907
Closes #14918
2016-07-15 18:07:37 +02:00
Martin Staffa 8a8c94c3d5 docs(ngSelected): note that it doesn't interact with ngModel
Related #14916
Related #14876
2016-07-15 17:49:22 +02:00
Michał Gołębiowski d9de526059 test(jQuery): Run tests with jQuery 3
(cherry-picked from 859b1e300c)

Closes #14874
2016-07-13 10:13:58 +02:00
Georgios Kalpakas 0318761f7a refactor($animate): avoid unnecessary lookup
Closes #14902
2016-07-12 22:32:38 +03:00
Ronan Connolly 74f7b57823 docs(guide/unit-testing): add missing heading
Closes #14901
2016-07-12 18:31:30 +03:00
Steve Berube 995ccfc9f6 docs(guide/animations): use the arguments of enabled() in correct order
Closes #14900
2016-07-12 17:52:05 +03:00
Georgios Kalpakas 72c244564a chore(Jenkins): fix e2e tests on Jenkins
Follow-up to c72e13f and a82a8a5.

Closes #14889
2016-07-11 13:37:43 +03:00
Georgios Kalpakas 4bfe7e8663 docs(guide/module): remove newline in the middle of sentence 2016-07-10 14:13:33 +03:00
Oliver Salzburg 63fe144397 docs($http): fix default $http cache name
The name of the cache is the string "$http", not the symbol itself.

Closes #14885
2016-07-09 10:23:30 +03:00
Martin Staffa 0f551e6109 chore(protractor): use jasmine2 as framework 2016-07-08 11:30:10 +02:00
Martin Staffa 541f4ba21f chore(package.json): update jasmine-reporters to 2.2.0 2016-07-08 11:30:08 +02:00
Georgios Kalpakas 6e7d04ddb2 docs(guide/component): improve tests
Fixes #14739
2016-07-06 13:40:47 +03:00
Jack 06fb391687 docs(guide/directive): remove confusing best practice
Prior to this point, the docs do not mention returning a postLink function, and all the examples use
the definition object form. So, this message is confusing to new readers who may misinterpret
"returning a function" as returning the factory function mentioned in the previous section.

Since this page is only a "gentle introduction" to directives, and using the definition object is a
best practice, it is best to just remove the message altogether.

Closes #14871
2016-07-06 12:07:15 +03:00
Georgios Kalpakas 203dd4d1e3 docs(tutorial): fix typo in images (phoneList --> phoneDetail)
Fixes #14858

Closes #14868
2016-07-05 21:52:37 +03:00
Georgios Kalpakas c991f93817 docs(guide/interpolation): add known issue (do not change the content of interpolated strings)
Closes #12813

Closes #14825
2016-07-05 00:11:26 +03:00
Peter Bacon Darwin 52ddc13bee chore(package.json): update dgeni-packages dependency to 0.14.0 2016-07-04 21:31:47 +01:00
Igor Zhukov 1645924d49 fix(copy): fix handling of typed subarrays
Previously, it would return a copy of the whole original typed array, not its slice.
Now, the `byteOffset` and `length` are also preserved.

Fixes #14842

Closes #14845
2016-07-04 23:24:16 +03:00
Georgios Kalpakas 6bee655679 docs(copy): mention ignoring non-enumerable properties
This also improves the example a bit:
- better code formatting
- initialization of `form` to an empty object
- avoid using `email`, which doesn't get coppied when invalid (and might confuse users)

Fixes #14853
2016-07-04 10:16:08 +03:00
David Rodenas Pico acd455181d perf($compile): wrap try/catch of collect comment directives into a function to avoid V8 deopt
Closes #14848
2016-07-04 08:56:52 +03:00
jfisher446 a89b6e27a9 docs(tutorial/step_04): fix syntactic error (add missing 'a')
Closes #14860
2016-07-04 08:43:16 +03:00
mmuppa 46d559dc8d docs(misc/Develop): using https:// works more widely than git@
Closes #14838
2016-07-01 11:18:33 +01:00
Peter Bacon Darwin 26212fb204 docs(guide): tweaks to the index and external resources guides
Closes #14843
2016-07-01 11:18:33 +01:00
Martin Staffa 244cfc7cd5 docs(guide): create new page for external resources
The official and external resources  have been split into two different guide sections. Official stays at the index, external gets its own page.

The external resources have also been reorganized and updated, but
I haven't checked if all material is still relevant.
2016-07-01 11:18:33 +01:00
Jeff Andrews c6074dc34c fix(ngMocks): allow ErrorAddingDeclarationLocationStack to be recognized as an Error
Change `ErrorAddingDeclarationLocationStack`'s prototype so test frameworks (such as Jasmine 2.x)
are able to recognize it as `Error`.

Fixes #13821

Closes #14344
2016-06-29 13:44:45 +03:00
atenhar 4930ef2bfe docs(tutorial/step_03): fix grammar and typos
Closes #14834
2016-06-28 11:08:41 +03:00
Georgios Kalpakas 1778d347cd fix($jsonpCallbacks): do not overwrite callbacks added by other apps
Closes #14824
2016-06-27 15:18:40 +03:00
Georgios Kalpakas 4724d56c93 fix($injector): fix class detection RegExp
Mentioned in https://github.com/angular/angular.js/pull/14531#discussion_r61410683.

Closes #14533
2016-06-27 13:35:50 +03:00
Georgios Kalpakas 70fcffc375 test($resource): make test for function as param more explicit
Related to aa8d783.

Closes #14820
2016-06-27 11:54:29 +03:00
Georgios Kalpakas 181e44019e fix($animate): do not get affected by custom, enumerable properties on Object.prototype
Fixes #14804

Closes #14830
2016-06-27 11:50:31 +03:00
Liran Tal 5ce859bcdd docs(guide/filter): add link to list of built-in filters
Closes #14828
2016-06-26 20:28:40 +03:00
Deplay fb994e4d90 refactor(jqLite): remove unused code in jqLiteBuildFragment()
Closes #14822
2016-06-25 22:09:43 +03:00
GARCIA Guillaume 55f26fc246 docs(*): correct bower version separator (@ --> #)
Closes #14819
2016-06-25 21:56:58 +03:00
Martin Staffa 1161002857 docs(ngReadonly): note input type restrictions
Closes #14816
2016-06-23 12:02:01 +02:00
Martin Staffa 7ccfe92bed fix(ngAnimate): allow removal of class that is scheduled to be added with requestAnimationFrame
Also affects the reverse case, adding a class that is scheduled to be removed with rAF.

The following case can happen when ngClass updates an element's classes in very quick order in the following way:

- First animation adds class "a"
- A digest passes, but "a" is not yet added to the element
- Second animation adds class "b"
- No digest passes, and "a" is still not added to the element,
  because requestAnimationFrame hasn't been flushed yet
- Third animation removes class "a"
- the third animation gets merged into the second animation

Before this change:

- Because the element doesn't have class "a" yet, ngAnimate
resolves that it cannot remove class "a". However,
the first animation is still running, and finally adds "a"

After this change:

- ngAnimate reacts to the temporary class "add-a", which indicates
that "a" is about to be added and decides that "a" can be removed
after all.

This is a very rare case where setting the element's class
is not fast enough, and subsequent animations operate on incorrect assumptions.

"In the wild", this is caused by rapidly updating ngClass,
which uses inidvidual addClass and removeClass calls when both operations happen in a single digest.

Fixes #14582
PR  (#14760)
2016-06-23 12:01:57 +02:00
Chirayu Krishnappa a126fcfee3 feat($resource): pass the resource to a dynamic param functions
Closes #4899
2016-06-22 12:22:16 +01:00
Peter Bacon Darwin f22af2b874 docs($http): fix a dangling link 2016-06-22 11:19:22 +01:00
Peter Bacon Darwin 2ca4170903 docs($compile): reorganize the life-cycle hooks docs
Closes #14811
2016-06-22 11:19:21 +01:00
Peter Bacon Darwin fd57df1235 docs($compile): add additional runnable examples for the $doCheck hook
Closes #14811
2016-06-22 11:19:21 +01:00
Peter Bacon Darwin 3010ed4ee5 fix($compile): ensure $doCheck hooks can be defined in the controller constructor
Closes #14811
2016-06-22 11:19:21 +01:00
Zach Bjornson de59ca7107 feat($compile): backport $doCheck
Backuport ngDoCheck from Angular 2.

Closes #14656
2016-06-22 11:19:21 +01:00
Peter Bacon Darwin fa3214cfb8 refact($http): use the $jsonpCallbacks service
Use the built-in service to handling callbacks to `$http.jsonp` requests.

Closes #3073
Closes #14795
2016-06-21 19:10:13 +01:00
Peter Bacon Darwin a8cacfe938 feat($jsonpCallbacks): new service to abstract how JSONP callbacks are handled
You can now override this service if you have specific requirements about
the behaviour and formatting of the JSON_CALLBACK that is sent to the server
for `$http.jsonp` requests.

Closes #14795
2016-06-21 19:08:28 +01:00
Lucas Galfasó 1a387ba5dd fix($timeout): make $flush handle new $timeouts added in $timeout callbacks
If a $timeout handler calls $timeout itself, this new $timeout should be
added to the mock deferred queue with a "now" time based on when the original
handler was triggered.

Previously it was being added with a now time of when the `$timeout.flush`
method was originally called.

Closes #5420
Closes #14686
2016-06-20 10:01:19 -07:00
Georgios Kalpakas 98e4a220fe fix(modules): allow modules to be loaded in any order when using angular-loader
Some modules used to assume that the angular helpers would always be available when their script was
executed. This could be a problem when using `angular-loader` and the module file happened to get
loaded before the core `angular.js` file.
This commit fixes the issue by delaying the access to angular helpers, until they are guaranteed to
be available.

Affected modules:
- `ngAnimate`
- `ngMessageFormat`
- `ngMessages`
- `ngRoute`
- `ngSanitize`

Fixes #9140

Closes #14794
2016-06-18 00:20:56 +03:00
Georgios Kalpakas 9001ae2822 docs(misc/downloading): mention ngMessageFormat 2016-06-18 00:20:54 +03:00
Peter Bacon Darwin c405f88bbc fix(ngTransclude): ensure that fallback content is compiled and linked correctly
Closes #14787
2016-06-17 10:59:51 +01:00
Daniel Herman 159a68ec7b fix(ngTransclude): only compile fallback content if necessary
If the instance of the directive does provide transcluded content, then the fallback
content should not be compiled and linked as it will never be used.

If the instance of the directive does not provide transcluded content, then the
transcluded scope that was created for this non-existent content is never used,
so it should be destroy in order to clean up unwanted memory use and digests.

Fixes #14768
Fixes #14765
Closes #14775
2016-06-17 10:52:57 +01:00
Yihang Ho b9a56d588f feat($q): implement $q.race
Implement $q.race. $q.race takes in an array or hash of promises and
returns a promise that resolves or rejects as soon as one of those promises
resolves or rejects, with the value or reason from that promise.

Closes #12929
Closes #14757
2016-06-17 10:21:31 +01:00
Abdulkader f797f83cd6 feat($swipe): add pointer support
Add pointer events to $swipe to support IE11 on touch devices

Closes #14061
Closes #14791
2016-06-17 09:52:43 +01:00
Georgios Kalpakas 6df970eb3c docs($resource): clarify how a @-prefix param is used 2016-06-17 00:45:34 +03:00
Georgios Kalpakas f88b4be92f docs(angular.mock.dump): remove incorrect statement
Fixes #14790
2016-06-17 00:26:43 +03:00
Roman Rodych a7bcc01581 refactor(input[number]): remove redandant second argument to parseFloat()
Closes #14793
2016-06-16 22:19:08 +03:00
Martin Staffa 40ed8094d1 chore(changelog.js): don't add empty breaking change section 2016-06-16 14:38:53 +02:00
Martin Staffa 1a722f7b19 docs($compile): add link to transcludeFn description
Closes #14764
2016-06-16 14:16:59 +02:00
Martin Staffa 4991207c7c chore(version-info): make online build compatible with Windows
Since we cannot write to dev/null on Windows, don't write to a file at all, but simply use stdout and extract the output from --write-out from the process response. Credit to @petebacondarwin for the idea.

The commit also avoids a premature error when no cdnVersion could be found online, and improves the log wrt the origin of the versions.

PR (#14780)
2016-06-16 14:16:59 +02:00
Georgios Kalpakas 33514ec384 feat(filterFilter): allow overwriting the special $ property name
Previously, the special property name that would match against any
property was hard-coded to `$`.
With this commit, the user can specify an arbitrary property name,
by passing a 4th argument to `filterFilter()`. E.g.:

```js
var items = [{foo: 'bar'}, {baz: 'qux'}];
var expr  =  {'%': 'bar'};

console.log(filterFilter(items, expr, null, '%'));   // [{foo: 'bar'}]
```

Fixes #13313
PR (#13356)
2016-06-16 14:15:55 +02:00
Georgios Kalpakas 28bd20ed30 docs($interpolate): fix heading 2016-06-16 14:15:55 +02:00
Martin Staffa c3bfd7f59d fix(ngOptions): don't duplicate groups with falsy values
Previously, ngOptions would fail to remove optgroups with falsy values when the options were changed / removed.

Related #14781 
PR (#14784)
2016-06-16 14:15:54 +02:00
Georgios Kalpakas 553cccdb85 docs(CHANGELOG.md): add release notes for v1.5.7 2016-06-16 14:15:06 +02:00
Martin Staffa c7dd2c24f4 docs(guide/filters): clarify when filters are executed
Closes #14590
PR  (#14758)
2016-06-16 14:13:01 +02:00
Peter Bacon Darwin fbf5aebda2 chore(version-info): add offline-build support
Previously it was slow and problematic to run builds if you were not connected
to the internet because the build scripts make requests to github and the
Google CDN to find out version information.

You can now disable these requests by setting the NG1_BUILD_NO_REMOTE_VERSION_REQUESTS
environment variable to a non-empty value

Closes #14769
2016-06-15 10:32:31 +01:00
Peter Bacon Darwin ab35c16ccf chore(app.scenario): test docs app against production libraries
We have had issues where the docs application has gone down because
our build included invalid URLs to the production angular libraries.

This change runs a subset of the docs e2e tests directly against these
production libraries to ensure that they are accessible. If not then these
tests will fail and the CI build will abort, preventing the docs app from
being updated.

Closes #14769
2016-06-15 10:32:18 +01:00
Peter Bacon Darwin 37b6a71678 chore(Gruntfile): kill the build if the CDN version was not found
Closes #14769
2016-06-15 10:32:07 +01:00
Martin Staffa e79ebff223 docs(changelog.md): add 1.5.0-beta.0 entry
This was a preparation release for the 1.5.x branch,
which only contains one fix over the previous 1.4.6
release.
2016-06-15 11:22:03 +02:00
Wesley Cho 36b38e1355 docs($q): add note about optional arguments for promise.then()
- Add note about optional arguments in the promise.then api

Closes #8562
PR (#14754)
2016-06-15 11:21:58 +02:00
Wesley Cho 3168d95793 docs(guide): add notes about using ngAttr for IE
- Add note about using the value attribute for the progress tag with IE in the IE compat / interpolation guide
- Add note about placeholder attribute in textarea to the ie compat guide

Closes #7218
PR (#14753)
2016-06-15 11:21:39 +02:00
Geoffrey Bauduin 538c63f057 docs($exceptionHandler): add missing end bracket in example
PR  (#14756)
2016-06-15 11:21:21 +02:00
Wesley Cho a9a1461351 docs(ngOpen): add note about browser compatibility
- Add note about browser compatibility and recommend ng-show/ng-hide

Closes ##7337
PR (#14752)
2016-06-15 11:21:11 +02:00
Peter Bacon Darwin 29190f9318 revert: chore(version-info): disable remote requests when offline
This reverts commit aa38ded59d, which
caused the docs to build incorrectly causing the docs website to crash.
2016-06-14 20:44:12 +01:00
Peter Bacon Darwin ca7d2b3b3f docs(ngMessageFormat): fix e2e test in example 2016-06-14 20:41:23 +01:00
Peter Bacon Darwin 81676f8323 style(ngMessageFormat): fix jscs whitespace error 2016-06-14 20:41:23 +01:00
Martin Staffa 6f9d07d9c7 chore(docsApp): don't display module components if none exist
Some modules (ngMessageFormat, ngParseExt) don't have their own api surface
because they integrate with core services ($interpolate and $parse respectively).

Closes #14770
2016-06-14 20:41:23 +01:00
Martin Staffa 5201b8146a docs(ngMessageFormat): move docs for $$messageFormat to module namespace.
This is a private service that should not be documented.
The docs have been moved to the ngMessageFormat module namespace.

Closes #14770
2016-06-14 20:41:23 +01:00
Martin Staffa 6aa83d04b7 docs(ngMessageFormat): add more examples
Closes #14770
2016-06-14 20:41:23 +01:00
Igor Minar cfbe1a701a revert: fix($timeout): make $flush handle new $timeouts added in $timeout callbacks
This reverts commit 1e5d36d4b0.

Breaks tests at google, needs more investigation.
2016-06-14 08:08:25 -07:00
Pete Bacon Darwin aa38ded59d chore(version-info): disable remote requests when offline
When the internet is not accessible build scripts are unnecessarily slow
because of failed attempts to download git tag and CDN version information
from remote servers.

This commit does a synchronous check of internet connectivity before attempting
any remote requests.

Closes #14759
2016-06-13 15:58:21 +01:00
Wesley Cho b03957f004 feat(limitTo): add support for array-like objects
Fixes #14657

Closes #14694
2016-06-10 21:14:04 +03:00
Martin Staffa 56f33af890 fix(ngMessages): create new scope for ngMessage, clean it up correctly
Previously, ngMessage elements used the same scope as ngMessages. When ngMessage
has interpolation in the textContent, then removing the message would not remove
the watcher from the scope - it would only be removed when the whole ngMessages
element was removed.

This commit changes the ngMessage transclude function to create a new child scope
instead, which can be destroyed safely when the message element is removed and
the message is detached

Fixes #14307
PR (#14308)
2016-06-10 14:49:08 +02:00
CarlosMiguelDesarrollo 41bea59eb7 chore(ngAnimate): delete an unused conditional statement
Delete a conditional statement that appears to have only been for debugging.
It is marked with a TODO tag to be deleted.

Closes #14282
2016-06-10 12:27:24 +01:00
Georgios Kalpakas 6d0dcca6f1 fix($routeProvider): do not deep-copy route definition objects
Deep-copying route definition objects can break specific custom implementations of `$sce` (used to
trust a `templateUrl` as RESOURCE_URL). The purpose of copying route definition objects was to guard
against the user's modifying the route definition object after route registration, while still
capturing inherited properties.
As suggested by @IgorMinar in https://github.com/angular/angular.js/pull/14699#discussion_r66480539,
we can achieve both _and_ support custom `$sce` implementations, by shallow-copying instead.

This is an alternative implementation for #14699, which avoids the breaking change.

Fixes #14478
Closes #14699

Closes #14750
2016-06-10 14:09:40 +03:00
mirabilos f423dc6b51 fix(input[email]): improve email address validation
**Limit size of local-part and total path size in eMail addresses**

RFC 5321 §4.5.3.1.1 ⇒ local-part can have up to 64 octets
RFC 5321 §4.5.3.1.3 ⇒ path “including the punctuation and
element separators” can have up to 256 octets
RFC 5321 §4.1.2 specifies path as ‘<’ + mailbox¹ + ‘>’ in
the best case, leaving us 254 octets

The limitation of the total path size to 254 octets leaves
at most 252 octets (one local-part, one ‘@’) for the domain,
which means we don’t need to explicitly check the domain
size any more (removing the assertion after the ‘@’).

① RFC 821/5321 “mailbox” is the same as RFC 822 “addr-spec”

**Optimise eMail address regex for speed**

There is no need to make it case-insensitive; the local-part
already catches the entire range, and the host part is easily
done. Furthermore, this makes the regex locale-independent,
avoiding issues with e.g. turkish case conversions.

cf. http://www.mirbsd.org/cvs.cgi/contrib/hosted/tg/mailfrom.php?rev=HEAD

**Limit eMail address total host part length**

RFC 1035 §2.3.4 imposes a maximum length for any DNS object;
RFC 5321 §2.3.5 references this (and requires FQDNs, but there
have been cases where a TLD had an MX RR and thus eMail addresses
like “localpart@tld” are valid).

Credits: Natureshadow <d.george@tarent.de>

**Limit eMail address individual host part length**

A “label” (each of the things between the dots (‘.’) after the ‘@’ in
the eMail address) MUST NOT be longer than 63 characters.

cf. http://www.mirbsd.org/cvs.cgi/contrib/hosted/tg/mailfrom.php?rev=HEAD
and RFC 1035 §2.3.4

**Fix eMail address local-part validation**

A period (‘.’) may not begin or end a local-part

cf. http://www.mirbsd.org/cvs.cgi/contrib/hosted/tg/mailfrom.php?rev=HEAD
and RFC 822 / 5321

Closes #14719
2016-06-10 10:46:21 +01:00
Georgios Kalpakas 9fca87ca5b docs(misc/downloading): update content - include missing modules
Closes #14746
2016-06-10 10:41:25 +01:00
Martin Staffa ebbaa4ac5e fix($compile): don't add merged attributes twice to $attrs
In replace directives, attribute values from the template are added twice
to the replaced element when both the replaced element and the template
element have the attribute. This does not affect the DOM, as it normalizes
duplicate values. The values are however duplicated in the $attrs object
that is available to directive link functions.

Fixes #8159
Closes #14737
2016-06-09 16:27:13 +01:00
J. Roberto Vidal 617137231e docs($resource): document Resource#toJSON
Document the `toJSON` method of `Resource` instances as part of its public API.

See #14637
Closes #14725
2016-06-09 16:00:59 +01:00
Stepan Suvorov 71b966ace7 docs(misc/downloading): update Angular version in example
Closes #14741
2016-06-09 11:17:37 +03:00
Stepan Suvorov 488d5b4288 updated version of angular for script src 2016-06-09 11:17:36 +03:00
Georgios Kalpakas 01b8772cca feat(ngMessagesInclude): don't break on empty (or whitespace-only) templates
Fixes #12941

Closes #14726
2016-06-07 23:22:15 +03:00
Georgios Kalpakas 05ac0ba926 style(ngMessages): fix indentation 2016-06-07 23:20:28 +03:00
mirabilos 399e872228 docs(guide/Security): warn about $http.jsonp()
Warn users about security issues with JSONP that are *not* mitigated by AngularJS

Closes #14727
2016-06-07 18:34:48 +01:00
Stephen Fluin 3115408be7 docs(guide/Component Router): improving comms 2016-06-07 16:33:20 +01:00
Martin Staffa aea39e9fdc docs(changelog, guide/migration): mention rare BC for ngInclude
See https://github.com/angular/angular.js/issues/13555#issuecomment-165118890
for detailed explanation.

Closes #13555
2016-06-07 10:43:40 +02:00
Georgios Kalpakas 51f6752cec style(ngMocks): remove unnecessary jsHint comment 2016-06-07 11:19:11 +03:00
Georgios Kalpakas db58801a55 fix(ngMock#$controller): properly assign bindings to all types of controllers (e.g. class-based)
The decorated version of `$controller` is able to assign bindings to a controller instance prior to
instantiation, emulating the behavior of `$compile` with directive controllers.

There are cases, that the actual controller instance is different than the pre-populated one (e.g.
when the controller constructor function returns a value or when the controller is an ES2015 Class).
While `$compile` accounts for such situation, by re-asigning the bindings after the controller has
been instantiated, `ngMock`'s `$controller` didn't.

This commit fixes it, by re-applying the bindings if the actual controller instance is different
than the original one (similar to how `$compile` would do it).

Fixes #14437

Closes #14439
2016-06-07 11:18:34 +03:00
Georgios Kalpakas 2e33d170be feat(orderBy): add support for custom comparators
Add an optional, 4th argument (`comparator`) for specifying a custom comparator function, used to
compare the values returned by the predicates. Omitting the argument, falls back to the default,
built-in comparator. The 3rd argument (`reverse`) can still be used for controlling the sorting
order (i.e. ascending/descending).

Additionally, the documentation has been expanded to cover the algorithm used by the built-in
comparator and a few more unit and e2e tests (unrelated to the change) have been added.

Helps with #12572 (maybe this is as close as we want to get).

Fixes #13238
Fixes #14455

Closes #5123
Closes #8112
Closes #10368

Closes #14468
2016-06-07 00:32:19 +03:00
Peter Bacon Darwin cc6dcb4bc2 fix($parse): allow arguments to contain filter chains
Thanks to @esarbanis for the original PR that got out-dated due to the
big $parse overhaul.

Closes #4175
Closes #4168
Closes #14720
2016-06-06 15:20:50 +01:00
Guillaume Salles 294d6793fd fix($location) : initialize $$absUrl to empty string
Initialize `$$absUrl` to an empty string, in order to avoid exception, when base href
and current location have different domains.

Fixes #11091
Fixes #13565

Closes #14488
2016-06-06 15:52:28 +03:00
Peter Bacon Darwin cefcc46e1b docs(tutorial/step-9): fix typo 2016-06-06 13:38:17 +01:00
Martin Staffa c10dba144e docs(ngComponentRouter): add deprecation notice and better install notes
Yes, that contradicts itself.

Closes #14655
Closes #14717
2016-06-06 13:30:31 +01:00
Peter Bacon Darwin f05ffd9bf1 test(browserTrigger): fix typo in eventData property 2016-06-06 13:28:17 +01:00
Peter Bacon Darwin e208d81293 test(browserTrigger): allow event bubbling
In some browsers, events don't bubble when they are dispatched on node inside
a detached tree. When this is the case, the bubbling is made manually.
This may be convenient when unit testing directives, for example.

Closes #5178
2016-06-06 11:57:23 +01:00
Peter Bacon Darwin b51fca1a2b test(browserTrigger): support key events
Support for key events like keypress, keyup or keydown.

Closes #8688
2016-06-06 11:57:21 +01:00
Andrew Schmadel 6685043ad4 fix(ngMockE2E): allow $httpBackend.passThrough() to work when ngMock is loaded
Allow $httpBackend.passThrough() to work normally when ngMock is loaded
concurrently with ngMockE2E, as is typically the case when writing tests with
angular.mock.module()

Fixes #1434
Closes #13124
2016-06-06 11:30:50 +01:00
Martin Staffa f176a2dbb7 docs(angular.element): note restrictions of addClass and removeClass
Closes #12851
Closes #12793
2016-06-03 21:50:00 +02:00
Georgios Kalpakas 3a366bd42b docs($exceptionHandler): include better example
The previous example overwrote the `$exceptionHandler` in order to re-throw the error. This is not
recommended, since it would leave the application in an inconsistent state and prevent proper
clean-up.
The new example simulates logging the error both to the backend and the console.

Fixes #14704
2016-06-03 21:34:48 +03:00
Georgios Kalpakas 1c5db02638 refactor($resource): explicitly set $resourceProvider.defaults.cancellable to false
Previously, it was just `undefined` and had the same behavior (since we only check for falsy-ness).
Just making it explicit, that this property is also available on `defaults` and is "not true" by
default.

Closes #14711
2016-06-03 20:15:45 +03:00
Georgios Kalpakas ffd5308d86 docs($resourceProvider): improve wording and formatting
Closes #11910
2016-06-03 20:15:02 +03:00
Yiling Lu aed9de9d37 docs($resourceProvider): provide info and example for configuring $resourceProvider 2016-06-03 20:14:37 +03:00
Wesley Cho aab6825e85 docs($animate): detail options object
- Document options object used in various $animate methods

Fixes #12645
PR: #14700
2016-06-03 13:28:44 +02:00
Martin Staffa c4fad6ad61 fix(ngSanitize): call attribute setter in linky for all links
Fixes #14707 
PR: #14710
2016-06-03 13:22:24 +02:00
ZachLamb 2a7c37cf01 docs(tutorial/step_04): fix type (JacaScript --> JavaScript)
Closes #14661
2016-06-01 11:08:42 +03:00
Peter Bacon Darwin 194c3adfed docs(CHANGELOG): fix typo 2016-05-27 22:34:51 +01:00
Martin Staffa 371957d9d5 docs(changelog): update with changes for 1.5.6 2016-05-27 17:59:43 +02:00
Lucas Galfasó 1e5d36d4b0 fix($timeout): make $flush handle new $timeouts added in $timeout callbacks
If a $timeout handler calls $timeout itself, this new $timeout should be
added to the mock deferred queue with a "now" time based on when the original
handler was triggered.

Previously it was being added with a now time of when the `$timeout.flush`
method was originally called.

Closes #5420
Closes #14686
2016-05-27 16:19:54 +01:00
Peter Bacon Darwin 3749c85829 fix($compile): cope with $onChanges hooks throwing
Previously, if one of these hooks threw an error, then the compilation
was terminated unceremoniously. In particular any other `$onChanges`
hooks that had been scheduled were not executed, nor was the queue cleaned
up properly.

Closes #14444
Closes #14463
2016-05-27 16:14:51 +01:00
Martin Staffa 886b59d317 chore(angularFiles): add missing files
ngMessageFormat test files were missing from angularTest
ngMessages and ngAnimate were missing from karmaModules.

This change highlighted a number of problems in the tests and code,
which are now fixed.

Closes #14314
Closes #14669
2016-05-27 16:13:31 +01:00
Victor Oliveira da Silva 2048b6df24 docs(ngRepeat): fix typo
Closes #14681
2016-05-26 22:22:57 +03:00
Georgii Dolzhykov 5ec0a50d39 chore(package.json): remove unused grunt-jasmine-node
Closes #14363
2016-05-26 01:43:24 +03:00
Peter Bacon Darwin 60689afe1c docs(tutorial/step-9): fix typo in inline link 2016-05-25 17:00:13 +01:00
Hadrien Tulipe 881fddaaba docs(ngAnimateMock): document how to require mocked service in tests
Closes #14668
Closes #14670
2016-05-25 16:57:37 +01:00
Robin Böhm fda338e8e2 refactor(ngMock): use exactly equal in browserTrigger
Closes #6763
2016-05-25 15:32:48 +02:00
David Goldberg 05c8d88126 style(src/Angular.js): make comment formatting consistent
Corrected formatting errors on lines 258, 695, 696, 1096, 1219, 1451, and 1536 by adding periods at the end of single line comments that were missing them in order to be consistent with the formatting found in the file.

Capitalized the first letter in the first word of the comments on lines 695, 696, 1096, to be consistent with the formatting of the rest of the file.

Added a space after the // in the comment on line 1536 to be consistent with the formatting of the file.
2016-05-25 15:17:20 +02:00
Martin Staffa aa57f57ccb docs(angular.element): note restriction in toggleClass 2016-05-25 15:12:08 +02:00
thorn0 51b78f61f9 perf($rootScope): make queues more efficient
By using a pointer to the current start of the queue and only clearing
up the queue storage later, we save lots of time that was spent manipulating
arrays with `slice`

Closes #14545
2016-05-25 13:22:12 +01:00
Ajay 739100e8a8 docs($provide): document decorator method
Closes #14562
2016-05-25 13:16:55 +01:00
Peter Briers 20e0c7f966 docs(ngAnimate): remove unnecessary transition prefixes
We can remove the vendor-prefixing from our docs, since all major browsers
support these properties, without prefixes.

Closes #14586
2016-05-25 12:38:46 +01:00
Jacob Reid f34e3413c7 docs(tutorial): fix typos
Closes #14662
Closes #14663
Closes #14664
2016-05-25 12:18:15 +01:00
Peter Bacon Darwin 4d28598b3d refactor(*): faster check for a string starting with a substring
Thanks to @spamdaemon for the original PR to make this improvement.

In naive tests on Chrome I got the following results:

```
             Matches   Misses
indexOf      33ms      1494ms
lastIndexOf  11ms      11ms
```

Closes #3711
2016-05-24 19:10:29 +01:00
Peter Bacon Darwin 16d6e89f3b refactor($route): consolidate route locals processing into a single handler 2016-05-24 19:02:09 +01:00
Peter Bacon Darwin 6e220ab612 refactor($route): move resolving locals into its own function 2016-05-24 19:02:09 +01:00
Peter Bacon Darwin ce14e4a6b7 refactor($route): move getting the template into its own function 2016-05-24 19:02:09 +01:00
Georgios Kalpakas b5dbc9834a docs(tutorial): update to use v1.5.x and best practices
This is a major re-structuring of the tutorial app's codebase, aiming at applying established best
practices (in terms of file naming/layout and code organization) and utilizing several new features
and enhancements (most notably components) introduced in recent versions of Angular (especially
v1.5).

Apart from the overall changes, two new chapters were introduced: one on components and one on code
organization.

--
In the process, several other things were (incidentally) taken care of, including:

* Dependencies were upgraded to latest versions.
* Animations were polished.
* Outdated links were updated.
* The app's base URL was changed to `/` (instead of `/app/`).

BTW, this has been tested with the following versions of Node (on Windows 10) and everything worked
fine:

* 0.11.16
* 4.2.6
* 4.4.2
* 5.10.0
* 6.2.0

--
This was inspired by (and loosely based on) #13834.
Again, mad props to @teropa for leading the way :)

--
**Note:**
The old version of the tutorial, that is compatible with Angular version 1.4 or older, has been
saved on the `pre-v1.5.0-snapshot` branch of
[angular-phonecat](https://github.com/angular/angular-phonecat). The `v1.4.x` version of the
tutorial should be pointed to that branch instead of `master`.

--
Related to angular/angular-phonecat#326.
Related to angular/angular-seed#341.

Closes #14416
2016-05-24 15:44:19 +03:00
Peter Bacon Darwin 57f10251db docs(tutorial): add svg and visio versions of the graffle images 2016-05-24 15:43:25 +03:00
Peter Bacon Darwin 48cd05a1ad docs(guide): add svg and visio versions of the graffle images 2016-05-24 15:42:33 +03:00
Peter Bacon Darwin 6a71ba17f0 docs(images): add svg and visio versions of the graffle image 2016-05-24 15:41:09 +03:00
marija cf1b175508 perf(ngClass): improve even-odd checking
This now uses the same technique as ngRepeat.
2016-05-23 23:31:52 +02:00
marija 5bba68c264 refactor($sniffer): avoid unnecessary call to substring 2016-05-23 23:31:51 +02:00
Alireza Mirian e5a4345aac docs(guide/Conceptual Overview): clarify service instantiation explanation
Change a sentence which describes how currencyConverter service is instantiated
2016-05-23 23:31:16 +02:00
Martin Staffa 49ef92041f docs(input[text]): remove deprecated tt tag
Closes #14547
2016-05-23 23:30:33 +02:00
Peter Bacon Darwin 081ae8bfca chore(docs): add horizontal rules between known issues 2016-05-23 22:19:23 +01:00
Peter Bacon Darwin 4f8aa6f5bb chore(docs): fix api.template.html to display git links 2016-05-23 22:19:19 +01:00
Xavier Haniquaut d7e888b8c6 docs(error/$compile): add reqslot error description
Explains what could generate a `reqslot` error.

Closes #14618
2016-05-23 14:21:00 +01:00
Peter Bacon Darwin 491b4af92e chore(docs): add horizontal rules between known issues 2016-05-23 14:03:00 +01:00
Peter Bacon Darwin 5930b8ee27 docs($interpolate): add known issue about custom interpolation symbols
Closes #14610
Closes #6493
2016-05-23 13:52:57 +01:00
Jukka 69d9072d5b fix(ngMessagesInclude): do not compile template if scope is destroyed
Messages imported with `ngMessagesInclude` are loaded asynchronously and
they can arrive after the ngMessages element has already been removed from DOM.

Previously we tried to compile these messages and that caused a `$compile:ctreq`
error. Now they are silently ignored if `ngMessagesInclude`'s scope has already
been destroyed.

Closes #12695
Closes #14640
2016-05-23 13:00:56 +01:00
Wesley Cho 9b5de0ac97 docs(contributing): fix the styleguide link
Update the link to Google's JavaScript style guide to the updated version

Closes #14652
2016-05-23 12:49:09 +01:00
Georgios Kalpakas 21b76aed06 fix($animate): don't break on anchored animations without duration
If the `from` element of an animation does not actually have an animation
then there will be no animation runner on that element. This is possible
if the element has the `ng-animate-ref` attribute but does not have any
CSS animations or transitions defined.

In this case, it is not necessary to try to update the host of the
non-existent runner.

Fixes #14641
Closes #14645
2016-05-22 19:02:45 +01:00
Bijay Deo 363fb16c10 fix(ngMock): match HTTP request regardless of the order of query params
Closes #12762
2016-05-21 10:44:37 +01:00
Peter Bacon Darwin e00f9f62e3 docs(toJson): documented the Safari RangeError known issue
Closes #14221
Closes #13415
2016-05-21 10:15:45 +01:00
Georgios Kalpakas 507c666d16 docs(ngMock/$exceptionHandler): fix formatting
Too much indentation, made text get formatted as code block.
2016-05-20 21:23:51 +03:00
Adrian Moos 743b33ab9d fix($brower): set the url even if the browser transforms it
While $location expects that $browser stores the URL unchanged, "some browsers" transform the URL
when setting or defer the acutal update. To work around this, $browser.url() kept the unchanged
URL in pendingLocation.

However, it failed to update pendingLocation in all code paths, causing
$browser.url() to sometimes incorrectly report previous URLs, which horribly confused $location.

This fix ensures that pendingLocation is always updated if set, causing url() to report the
current url.

Fixes #14427
Closes #14499
2016-05-20 15:44:53 +01:00
Peter Bacon Darwin 9f8fa79f25 docs(misc/contribute): specify node version 2016-05-18 16:46:44 +01:00
Peter Bacon Darwin fe3c1d44a5 docs(ngMock): final installation description fix 2016-05-18 08:42:05 +01:00
Georgios Kalpakas 5ae72dc7af fix($compile): properly bind context to linking functions for directives with templateUrl
Also, fix some styling issues.
2016-05-17 22:21:22 +03:00
Paulo Cesar 47bc98a1ea fix($compile): always use the DDO as this in pre-/post-linking functions
Closes #9306
2016-05-17 22:20:26 +03:00
Peter Bacon Darwin 10920a2857 docs(ngMock): fix installation instructions 2016-05-17 18:25:16 +01:00
Thomas Kowalski 90a9270dfa docs(guide/component-router): remove unused code
Closes #14613
2016-05-17 12:06:52 +03:00
Igor Minar d4b05dd13a revert: perf(ngAnimate): listen for document visibility changes
This reverts commit b377d6b043.

This commit introduces dependency on $document during the injector
bootstrap. This is usually fine, except for cases when $document is
mocked out in existing test suites. Since we don't provide an out
of box mock, people have created their owns that don't sufficiently
mock all apis. In these environments this change results in errors
like $document.on is not a function, etc.
2016-05-16 16:59:08 -07:00
Peter Bacon Darwin 59802bc790 docs(ngMock): fix installation formatting
The `@installation` section should be formatted with markdown, not
nunjucks template directives.

Closes #14604
2016-05-16 22:46:51 +01:00
Sander Boom b0a35a794a docs(guide/$location): fix typo
Closes #14607
2016-05-14 01:53:25 +03:00
Mark Pieszak a9545e3963 docs(readme): remove "(beta)" from Angular 2 link
Closes #14599
2016-05-13 23:17:18 +03:00
Georgios Kalpakas 269c15c74b docs(ngComponentRouter): specify correct version of npm package
The latest npm package does not contain the angular 1 version of the router.

Related to 824ce30.
2016-05-13 19:25:01 +03:00
Maksim Ryzhikov 9f48025733 fix(ngAnimate): properly handle empty jqLite collections
Previously `stripCommentsFromElement()` would return an empty Array (instead of a jqLite collection)
which would cause an exception to be thrown: "element.parent not a function".
This commit fixes it, by ensuring that the returned value is always a jqLite collection.

Closes #14558

Closes #14559
2016-05-13 18:17:43 +03:00
Peter Bacon Darwin 1d0ccd0d73 chore(package.json): update to use dgeni-packages@0.13.0 2016-05-12 11:05:27 +01:00
Peter Bacon Darwin 03e5164528 chore(npm/check-node-modules): cope with no npm-shrinkwrap file 2016-05-12 11:05:25 +01:00
Pete Bacon Darwin 3047964712 fix($compile): don't run unnecessary update to one-way bindings
The watch handler was triggering on its first invocation, even though
its change had already been dealt with when setting up the binding.

Closes #14546
Closes #14580
2016-05-10 22:31:29 +01:00
Peter Bacon Darwin 225afb9eb4 docs(guide/component-router): specify correct version of npm package
The latest npm package does not contain the angular 1 version of the router.

Closes #14564
Closes #14560
2016-05-07 21:40:13 +01:00
Martin Staffa b377d6b043 perf(ngAnimate): listen for document visibility changes
Accessing the document for the hidden state is costly for
platforms like Electron. Instead, listen for visibilitychange
and store the state.

Closes #14568
2016-05-06 15:53:24 +02:00
dmandelin ac650cb2e6 docs($sanitizeProvider): fix param comment for enableSvg
Change the text of the doc comment for the parameter of enableSvg to match the type of the comment and the behavior of the code (#14543).
2016-05-06 15:45:50 +02:00
FGasper 926088ba77 docs($location): clarify return value for path method
docs for return of path() inaccurately describe the function’s return when a value is passed in.

Closes #14544
2016-05-06 15:45:50 +02:00
Stephen Barker f94cf634d8 docs(guide/decorators): add decorator guide
+ explain decorators and how they are implemented in angular
+ explain how different types of services can be selected
+ explain `$delegate` objects and how they differ between services
+ warn of the risks/caveats of `$delegate` modification
+ note the exposure of `decorator` through the module api
+ show an example of decorating a core service
+ show an example of decorating a core directive
+ show an example of decorating a core filter

Closes #12163
Closes #14372
2016-05-06 15:45:49 +02:00
Michael Warner 85b3786f55 docs(ngRequired): add 'restrict' info
The Angular Docs do not show the restrictions

Closes #14541
2016-05-06 15:45:12 +02:00
Ivo Mirra 1116a96df6 fix($compile): removing unnecessary white space in element-transclusion comments
Fixes #14549

Closes #14550
2016-05-05 18:56:19 -06:00
Martin Probst 1c1c9b27cb fix(ng-bind-html): watch the unwrapped value using $sce.valueOf() (instead of toString())
Custom `$sce` implementations might not provide a `toString()` method on the wrapped object, or it
might be compiled away in non-debug mode. Watching the unwrapped value (retrieved using
`$sce.valueOf()`) fixes the problem.

The performance of this should be equivalent - `toString()` on objects usually touches all fields,
plus we will also avoid the (potentially big) string allocation.

Fixes #14526
Closes #14527
2016-04-28 20:25:13 +03:00
Mark Pieszak c5e7a5bc9b docs(README.md): add link to Angular 2 repo
Might be helpful for those completely new to Angular in general, that intended to view the upcoming
2.0 version.

Closes #14532
2016-04-28 19:46:57 +03:00
Georgios Kalpakas 7550b7bda8 fix($injector): add workaround for class stringification in Chrome v50/51
Partially fixes #14240.

Closes #14531
2016-04-28 14:31:50 +03:00
Petr Mikota 43b97b211b docs(guide/component-router): add missing backticks
Closes #14530
2016-04-28 11:40:39 +03:00
Weijing Jay Lin 76405897fc docs(identity): add example
Closes #14528
2016-04-28 11:07:00 +03:00
Georgios Kalpakas bb730704f2 fix($injector): add workaround for fat-arrow stringification in Chrome v50/51
Closes #14487

Closes #14495
2016-04-28 10:55:51 +03:00
Georgios Kalpakas 8965d57aa0 feat($compile): support omitting required controller name if same as the local name
Basically, making `require: {someDir: '?^someDir'}` equivalent to `require: {someDir: '?^'}`.

Closes #14513
2016-04-28 10:44:21 +03:00
Fabricio Ronchi 951a2743d5 docs(ngAria): remove redundant table column
Closes #14518
2016-04-28 10:38:35 +03:00
Michael de Wit a2a907e439 docs(guide/component): several unit-test fixes and remove obsolete testcase
Fixes #14426

Closes #14443
2016-04-26 20:24:56 +03:00
Perry Hooker 308f22ba9a fix($compile): properly handle setting srcset to undefined
Previously, calling `Attributes#$set('srcset', value)` on an `<img>` element would throw if `value`
were undefined, as it assumed `value` is always a string.
This commit fixes the issue, by skipping the unnecessary string manipulation when `value` is not
defined.

Closes #14470

Closes #14493
2016-04-26 09:17:51 +03:00
andrea 32e2643d90 docs(guide/index): fixed formatting with subtitles
The "Books" and "Videos" subtitles had no space between text and the '#' so it didn't render as a
subtitle.

Closes #14514
2016-04-26 08:33:36 +03:00
Tim van Dalen 3edaf0922f docs($anchorScroll): fix link to HTML5 spec
Closes #14364
2016-04-26 00:22:58 +03:00
Raphael Jamet 1095596962 fix($templateRequest): trust empty templates in $templateCache as well
Implicitly trust empty templates added to `$templateCache` as is the case for all other templates.

Fixes #14479

Closes #14496
2016-04-25 20:22:26 +03:00
Georgios Kalpakas ee0dac4d1d docs($interpolate): add known issue about end-symbol in expression
This has been discussed in #8642.

Closes #14494
2016-04-22 15:42:21 +03:00
Georgios Kalpakas 6f1fae8a91 fix(filters): always call splice() with 2 arguments or more
When calling `.splice()` without a 2nd argument (`deleteCount`), most browsers will splice to the
end of the array. As it turns out, this is the behavior specified in [ES2015][es6]. In [ES5][es5],
the spec seems to imply that nothing should happen.

To avoid inconsistent behavior among browsers implementing different versions of the EcmaScript
standart or when ES5 shims are included (e.g. https://github.com/es-shims/es5-shim/), this commit
ensures that all calls to `.splice()` provide at least two arguments.

[es5]: http://www.ecma-international.org/ecma-262/5.1/#sec-15.4.4.12
[es6]: http://www.ecma-international.org/ecma-262/6.0/#sec-array.prototype.splice

Fixes #14467

Closes #14489
2016-04-22 12:41:28 +03:00
Abhishek Garg f96485085a docs($http): add better explanation for error status codes
Add explanation for error status codes in `$http` and mention negative codes normalization.
This alleviates confusion about which status codes will trigger the error callback and what values
to expect in such callbacks.

Fixes #11945

Closes #14459
2016-04-22 12:24:11 +03:00
andreyjkee 147650b3be fix(ngMocks): pass eventHandlers to $httpBackend if passThrough is active
Closes #14471
2016-04-21 23:10:28 +02:00
Martin Staffa 10c426ffa3 docs(guide/Expressions): mention absence of bitwise operators
Closes #14485
2016-04-21 16:29:04 +02:00
Abhishek Garg 785647eb9d docs(changelog): make labels and list style consistent
Remove 'Breaking Changes' label where there are no breaking changes.

Only for '1.4.0-rc.2', breaking changes have different styling (bold without bulleted list). Change to be consistent with others

(#14482)
2016-04-21 16:29:04 +02:00
Amy a2a6279157 docs($sce): add missing article
...teeny letter missing.  Just a grammar change.
(#14480)
2016-04-21 16:29:03 +02:00
jody tate b50d2a4a1f docs(ngAria): fix markdown heading syntax
(#14477)
2016-04-21 16:29:03 +02:00
Martin Staffa f539fb1f7c docs(ngMock): add custom installation instructions
ngMock should be used in a test runner context, not directly in the application

Closes #14248
2016-04-21 16:01:26 +02:00
Martin Staffa 2dcb5acb7b docs: reorganize module overview page template 2016-04-21 16:01:23 +02:00
Michał Gołębiowski 905a8fd4a4 chore(jQuery): bump jQuery version from 2.2.1 to 2.2.3 2016-04-20 13:36:48 +02:00
Michał Gołębiowski df9b57a481 test(jqLite): make add/removeEventListener tests work with jQuery 2.1
The useCapture parameter defaults to false even in oldest of our supported
browsers; this is no longer needed so jQuery has removed it in 2.2.

In Angular 1.6 we apply the same refactoring, here in 1.5 we're just making
tests work with jQuery 2.2.
2016-04-20 13:30:46 +02:00
Michał Gołębiowski fee2077d0b chore(jqLite): stop patching the change jQuery special handler
Code patching the change event in jQuery doesn't exist in jQuery 2 so this patch
hasn't been needed since Angular 1.3
2016-04-20 12:29:40 +02:00
Michał Gołębiowski 691aafc981 tests(jQuery): test on both oldest & latest supported jQuery version 2016-04-20 12:26:36 +02:00
Ken Powers da7af937d6 docs(guide/Components): change snake to kebab case
The example given is not in snake_case, it is in kebab-case.

Closes #14464
2016-04-19 20:34:54 +02:00
Lucas Mirelmann 1c9b9e24ed feat($parse): Add support for ES6 object initializers
- Add support for computed property names
- Add support for short notation in properties definitions

Eg. The expressions `{x}` and `{[x + 'foo']: 1}` are now valid.

Closes: #14407
2016-04-18 22:09:17 +02:00
Martin Staffa 46a5b2c298 docs(ngMockE2E): add $httpBackend mock example 2016-04-18 14:09:24 +02:00
Peter Bacon Darwin 28e4707dc4 chore(CHANGELOG): fix version number for 1.5.5 2016-04-18 12:31:11 +01:00
Peter Bacon Darwin 420b5211da chore(CHANGELOG): add 1.5.5 release notes 2016-04-18 10:52:06 +01:00
Jeremy 04bccee099 docs(guide/Component Router): fix a typo in npm install instructions
Related #14452
2016-04-17 23:50:13 +02:00
Peter Bacon Darwin a404839795 docs(CHANGELOG): remove changes from 1.5.4
1.5.4 was only partially released.
These changes will be included in the 1.5.5 release
2016-04-16 09:29:37 +01:00
Georgios Kalpakas 25d4e5cca4 fix($http): pass event object to eventHandlers/uploadEventHandlers
Fixes #14436
2016-04-15 14:09:39 +01:00
Peter Bacon Darwin c67112563f revert: refactor($compile): move setting of controller data to single location
Reverted from commit 21d148aedc since it caused
the Angular Material tabs directive to fail.
2016-04-15 14:09:05 +01:00
Jannick Fahlbusch 2b2ec26a75 chore(docsApp): open plnkr.co with HTTPS
Plnkr should be opened via HTTPS instead of HTTP to supress warnings about an insecure connection

Closes #14445
2016-04-15 14:55:13 +02:00
cloverharvest 41f90e5fb0 docs($http): fix a typo (his --> this)
Closes #14430
2016-04-15 01:25:09 +03:00
Adam Demuri a85c591d36 docs(component): document 'require' in angular.component
Closes #14429
2016-04-15 01:12:43 +03:00
Peter Bacon Darwin f276ad0d51 docs(CHANGELOG): add release notes for 1.5.4 2016-04-14 09:13:48 +01:00
Pete Bacon Darwin 33f817b99c feat($componentController): provide isolated scope if none is passed (#14425)
Closes #14425
2016-04-13 18:34:39 +01:00
Martin Staffa 6a4124d0fb perf(ngOptions): use documentFragment to populate select
This changes the way option elements are generated when the ngOption collection changes.
Previously, we would re-use option elements when possible (updating their text and
label). Now, we first remove all currently displayed options and the create new options for the
collection. The new options are first appended to a documentFragment, which is in the end appended
to the selectElement.

Using documentFragment improves render performance in IE with large option collections
(> 100 elements) considerably.

Creating new options from scratch fixes issues in IE where the select would become unresponsive
to user input.

Fixes #13607
Fixes #13239
Fixes #12076
2016-04-13 18:42:10 +02:00
Georgios Kalpakas 26d1b34321 docs(ngView): add known issue about asynchronously loaded ngView
Closes #14424
2016-04-13 18:45:40 +03:00
Georgios Kalpakas 7fba6b603f revert: "fix(ngRoute): allow ngView to be included in an asynchronously loaded template"
This reverts commit 5e37b2a7fd.
Eagerly loading `$route`, could break tests, because it might request the root or default route
template (something `$httpBackend` would know nothing about).

It will be re-applied for `v1.6.x`, with a breaking change notice and possibly a way to disable
the feature is tests.

Fixes #14337
2016-04-13 18:45:06 +03:00
Jason Bedard c115b37c33 perf($compile): use createMap() for directive bindings to allow fast forEach
Closes #12529
2016-04-13 12:05:30 +03:00
Georgii Dolzhykov d20ba95e28 docs(Module): fix parameter names for .decorator()
Closes #14413
2016-04-12 14:52:18 +03:00
aortyl 7945e5010a docs(guide/scope): add comma for readability
Closes #14411
2016-04-11 22:22:36 +03:00
Jason Bedard 21d148aedc refactor($compile): move setting of controller data to single location
Closes #13421
2016-04-11 18:54:41 +01:00
Georgios Kalpakas 4c8aeefb62 fix($compile): do not use noop() as controller for multiple components
Currently, custom annotations are copied from the CDO onto the controller constructor.
Using `noop()` when no controller has been specified, pollutes it with custom annotations and
makes one component's annotations available to all other components that have `noop()` as their
controller.

Fixes #14391
Closes #14402
2016-04-11 18:43:17 +01:00
a510 d384834fde fix($injector): ensure functions with overridden toString() are annotated properly
Closes #14361
2016-04-11 13:03:56 +03:00
David Rodenas Pico f975d8d448 fix(ngClass): fix watching of an array expression containing an object
Closes #14405
2016-04-11 12:40:36 +03:00
Georgios Kalpakas 2602daf993 refactor($compile): remove unnecessary call to isDefined()
(As discussed in https://github.com/angular/angular.js/pull/14406/files#r59131398.)
2016-04-11 12:33:07 +03:00
Gene McCulley 9f681c459a docs(numberFilter): fix the description of the returned value
Closes #14408
2016-04-11 12:28:08 +03:00
Peter Bacon Darwin d9448dcb9f fix($compile): still trigger $onChanges even if the inner value already matches the new value
Closes #14406
2016-04-10 20:31:01 +01:00
Jurko Gospodnetić e9c718a465 fix(ngMock): fix collecting stack trace in inject() on IE10+, PhantomJS
Add support for collecting current stack trace information in browsers
(e.g. IE10+, PhantomJS) that do not automatically store the current stack trace
information in a newly created `Error` object's `stack` property, but
only add it there once the `Error` gets thrown.

The original implementation works fine in Firefox & Chrome, but fails on IE10+
and PhantomJS where it, for example, breaks Karma's error reporting in cases
when an exception is thrown in a test like the following:

```
it('the holy crusade', inject(function() {
  var x = {};
  x.holyGrail();
}));
```

In this case, the ngMock `inject()` implementation would incorrectly add the
word `undefined` at the end of the collected error stack trace information,
thus causing the main error description to be reported back to Karma as
`undefined`.

The added test makes sure this functionality:

- works as expected in browsers supporting JavaScript stack trace
  collection, e.g. Chrome, Firefox, IE10+, Opera & PhantomJS
- does not add any bogus stack track information in browsers that do
  not support JavaScript stack trace collection, e.g. IE9

Fixes #13591
Closes #13592

Closes #13593
2016-04-09 20:51:22 +03:00
Georgios Kalpakas 4dc44f7205 test(helpers): fix error message generation for toHaveBeenCalledOnce[With] matchers
Jasmine 2.4 (maybe earlier) does not support returning an array containing both the "normal" and the
negative error messages. It will always concatenate them.

Closes #14275
2016-04-09 17:06:47 +03:00
Jan Niehusmann 499e1b2adf fix($compile): handle boolean attributes in @ bindings
Commit db5e0ff handles initial values of boolean attributes. The same
change needs to be applied inside the attrs.$observe() call.

Closes #14070
2016-04-09 16:53:41 +03:00
Peter Bacon Darwin 28c6c4dae2 docs(jqlite): add known issue
Closes #14251
2016-04-08 21:27:21 +01:00
Peter Bacon Darwin 791148a328 chore(package.json): update dgeni-packages to 0.12.0
This gives us `@knownissues` tags
2016-04-08 21:27:05 +01:00
Peter Bacon Darwin 01b1845088 feat($http): support handling additional XHR events
Closes #14367
Closes #11547
Closes #1934
2016-04-08 19:16:56 +01:00
Chris Chua 56c861c9e1 feat($http): support handling additional XHR events
Closes #11547
Closes #1934
2016-04-08 19:16:49 +01:00
Martin Staffa 451e0f6175 docs(README): fix typo 2016-04-08 19:00:20 +02:00
Martin Staffa aee7f1c72f docs(guide/accessibility): make jshint happy 2016-04-08 18:55:22 +02:00
Pablo Iván G. Soto 5fe28a0422 docs(README): add https links, improve style 2016-04-08 18:37:04 +02:00
Martin Staffa f56586d9a9 docs(guide/Accessibility): fix markdown errors, tweak layout 2016-04-08 17:32:13 +02:00
mohamed amr ec0baadcb6 feat(ngAria): add support for aria-readonly based on ngReadonly
Closes #14140
Closes #14077
2016-04-08 17:32:12 +02:00
Martin Staffa 9147d5c04a docs(ngComponentRouter): add note about shims needed for IE 2016-04-08 17:32:12 +02:00
Josh cb801378c9 docs(ngComponentRouter): fix typo
Simple typo fix from `betweent he` to `between the`

Closes #14396
2016-04-08 15:47:01 +02:00
Martin Staffa 79604f4628 fix(ngAnimate): remove event listeners only after all listeners have been called
The fix for removing the event callbacks on destroy introduced in
ce7f400011 removed the events too early, so that the event callbacks
for the "close" phase in "leave" animations were not called.

This commit fixes the behavior so that the event callbacks are only removed during on('$destroy')
when no animation is currently active on the element. When an animation is active, the event callbacks
will be removed after all callbacks have run, and if the element has no parent (has been removed from
the DOM).

Closes #14321
2016-04-08 15:47:00 +02:00
Martin Staffa bf6cb8ab0d feat(ngAnimate): let $animate.off() remove all listeners for an element 2016-04-08 15:46:59 +02:00
Andrew de74b3fd85 docs(guide/Components): fix small single letter typo
line 136: 'not' should be 'note'

Closes #14390
2016-04-08 01:32:00 +02:00
Martin Staffa c7a92d2a9a fix(ngAnimate): fire callbacks when document is hidden
Since commit a3a7afd3aa, animations are not run
when the document is hidden (only their structural or class change effects are executed).
However, some libraries rely on the $animate.on() callbacks to be called even when no actual animation
runs.
This commit restores the behavior for the ngAnimate.$animate functions.
Note that callbacks still won't be called if animations are disabled, because this would be be a potential
breaking change, as some applications might rely on this implementation.

Fixes #14120
2016-04-08 01:31:59 +02:00
Martin Staffa da284fc354 test(ngAnimate): test calling callbacks for various constellations 2016-04-08 01:31:58 +02:00
Martin Staffa 90da3059ce fix(ngAnimate): fire callbacks in the correct order for certain skipped animations 2016-04-08 01:31:58 +02:00
SHAHRUKH-KHAN 651fd05eca docs(angular.equals): add example
This Pull requests improves the doc by adding a example to `angular.equals` function.

Closes #14232
2016-04-07 15:17:54 +02:00
glenr4 85d7e09bef docs(ngAnimate): fix toggle button in example
The toggle button code on line 153 only sets bool to true, rather than toggling it.
The proposed change fixes this.

Closes #14387
2016-04-07 15:17:54 +02:00
andykuszyk 243a57648b docs(misc/Getting Started): fix markdown for headings
Closes #14353
2016-04-07 15:17:54 +02:00
Maciej Kołodziejczak 158dec330c docs(ngComponentRouter): fix a typo
Closes #14357
2016-04-07 15:17:53 +02:00
Andrew a1e63c8d4a docs(guide/Components): clarify output events with extra example and note
Add additional line from example which demonstrates using the snake cased attribute binding in
parent component template.
Add note clarifying camelCase to snake-case requirement to use the Output binding callback feature.

Closes #14365
2016-04-07 15:17:53 +02:00
Artur 8cc9978d15 docs(guide/Components): fix typo, improve style
Closes #14384
2016-04-07 15:17:52 +02:00
Robin Janssens 78a404da0e docs($httpBackend): update response data types
Updated docs to reflect that response data can either be an array, object _or_ a string
Technically, response data can be anything that can be handled by angular.copy,
but since string and JSON data is most commonly mocked, the main types are sufficient.

Closes #14346
2016-04-07 15:17:52 +02:00
Michał Gołębiowski f1bb8369b5 refactor(jshint): don't assume browser-only globals
(cherry-picked from ddad26402b)

Fixes #13442
Closes #14345
2016-04-06 20:43:06 +02:00
Peter Bacon Darwin 76b6941b4c docs(componentRouter): add custom installation instructions 2016-04-05 21:10:19 +01:00
Peter Bacon Darwin e72990dc37 fix($compile): don't throw if controller is named 2016-04-04 21:26:13 +01:00
Peter Bacon Darwin f338e96ccc feat($compile): put custom annotations on DDO
Closes #14369
Closes #14279
Closes #14284
2016-04-04 20:07:31 +01:00
Peter Bacon Darwin 0ad2b70862 fix($compile): ensure that $onChanges hook is called correctly
Due to the way that we instantiate controllers, the `$onChanges` hook
was not always available at the time we were trying to trigger the initial
call to this hook. For instance, if the hook was actually defined inside
the constructor function.

This commit fixes that but also fixes the fact that the initial call was
being made in the postDigest anyway, which was incorrect because the
it should have been made before the `$onInit` call.

Closes #14355
Closes #14359
2016-04-01 17:41:41 +01:00
Georgios Kalpakas 5261a374a9 test($browser): fix typo in property name (histroy --> history)
(The semantics of the test aren't affected, because we just needed a falsy value.)
2016-03-31 13:30:25 +03:00
Martin Staffa 832eba5fc9 fix(ngOptions): set select value when model matches disabled option
When ngModel is set to a value that matches a disabled option, ngOptions will now select the option
in the select element, which will set select.val() to the option hash value and visually
show the option value / label as selected in the select box. Previously, disabled
options forced the unknown value.
The previous behavior is inconsistent with both default HTML behavior and select with
ngModel but without ngOptions. Both allow disabled values to be selected programmatically.

A common use case for this behavior is an option that was previously valid, but has
been disabled, and cannot be selected again.

This commit removes a duplicate test, and all other tests that previously checked that disabled
options are not set have been adjusted to the ensure the opposite.

Fixes #12756
2016-03-30 11:42:07 +02:00
cscport 2b569fc0b2 docs(angular.bootstrap): fix capitalization in error message
Closes #14325
2016-03-27 15:43:37 +03:00
Lucas Mirelmann ee6aeb08bf docs(ngParseExt): Fix package name 2016-03-27 00:00:14 +01:00
Peter Bacon Darwin 8d43d8b8e7 feat($compile): add isFirstChange() method to onChanges object
Closes #14318
Closes #14323
2016-03-26 20:06:13 +00:00
Lucas Mirelmann d08f5c6986 feat(ngParseExt): New ngParseExt module
New ngParseExt module

Including this module into an application will extend $parse to allow identifiers
following ES6 identifiers
2016-03-26 20:41:11 +01:00
Lucas Mirelmann 3e7fa19197 feat($parse): Add the ability to define the identifier characters
Add the ability to define the identifier starts and identifier continue characters
2016-03-26 20:41:01 +01:00
Lucas Mirelmann 5d379db72b chore(bower): Add parse-ext repository 2016-03-26 20:40:49 +01:00
Peter Bacon Darwin 514639b585 docs(CHANGELOG): add 1.5.3 release notes 2016-03-25 20:01:45 +00:00
Peter Bacon Darwin 9cd9956dcb feat($compile): add more lifecycle hooks to directive controllers
This change adds in the following new lifecycle hooks, which map in some
way to those in Angular 2:

 * `$onChanges(changesObj)` - Called whenever one-way bindings are updated. The `changesObj` is a hash whose keys
   are the names of the bound properties that have changed, and the values are an object of the form
   `{ currentValue: ..., previousValue: ... }`. Use this hook to trigger updates within a component such as
   cloning the bound value to prevent accidental mutation of the outer value.
 * `$onDestroy` - Called on a controller when its containing scope is destroyed. Use this hook for releasing
   external resources, watches and event handlers.
 * `$postLink` - Called after this controller's element and its children been linked. Similar to the post-link
   function this hook can be used to set up DOM event handlers and do direct DOM manipulation.
   Note that child elements that contain `templateUrl` directives will not have been compiled and linked since
   they are waiting for their template to load asynchronously and their own compilation and linking has been
   suspended until that occurs.

Closes #14127
Closes #14030
Closes #14020
Closes #13991
Closes #14302
2016-03-25 12:56:08 +00:00
Martin Staffa c7813e9ebf fix(ngAnimate): run structural animations with cancelled out class changes
When multiple animations on the same element are queued before a $digest passes,
the animator tries to create as few actual animations as possible by joining / canceling
redundant animations. Class-based animations for example are cancelled when the classes that
are added and removed are the same, and the result is no class-change. This however must only
happen if there's no structural animation currently queued.

Fixes #14249
2016-03-24 00:13:16 +01:00
Martin Staffa ef91b04cdd fix(ngMessages): don't crash when nested messages are removed
Under specific circumstances, ngMessages would go into an infinite loop and crash the
browser / page:
- At least two ngMessage elements are wrapped inside another element (e.g. ngTransclude)
- The first message is currently visible
- The first message is removed (e.g. when the whole ngMessages element is removed by an ngIf)

When a message is removed, it looks for a previous message - in this specific case it would misidentify
the second message for a previous message, which would then cause the first message to be marked as the
second message's next message, resulting in an infinite loop, and crash.

This fix ensures that when searching for previous messages, ngMessage walks the DOM in a way so
that messages that come after the current message are never identified as previous messages.

This commit also detaches and destroys all child ngMessage elements when the ngMessages element is
destroyed, which should improve performance slightly.

Fixes #14183
Closes #14242
2016-03-24 00:13:16 +01:00
Alex Chuev 1acd97e18f docs(guide/component): add missing closing bracket
Closes #14299
2016-03-23 23:58:35 +02:00
Daniel Herman 513199ee9f fix($compile): workaround a GC bug in Chrome < 50
In the version of V8 used in Chrome < 50, the parent of template nodes for
`transclude: "element"` directives would be improperly garbage collected
despite still having been referenced via `parentNode`.

This bug surfaced due to the introduction of lazy transclusion (652b83e),
and appears under certain circumstances when using directive start and end elements.

It should be removed some time after Chrome 50 has been released.

Fixes #14041
Closes #14286
2016-03-23 22:06:17 +01:00
pmadruga 33f3c40e93 docs(error/$compile.baddir): mention "components" in directive name error
Closes #14212
2016-03-23 22:18:54 +02:00
Steve Mao 696cb95d5e docs($q): mention ES2015 (as a "synonym" for ES6) and remove "harmony"
Closes #14294
2016-03-22 12:09:02 +02:00
Georgios Kalpakas 457fd21a1a fix($sniffer): fix history sniffing in Chrome Packaged Apps
Although `window.history` is present in the context of Chrome Packaged Apps, it is not allowed to
access `window.history.pushState` or `window.history.state`, resulting in errors when trying to
"sniff" history support.
This commit fixes it by detecting a Chrome Packaged App (through the presence of
`window.chrome.app.runtime`). Note that `window.chrome.app` is present in the context of "normal"
webpages as well, but it doesn't have the `runtime` property, which is only available to packaged
apps (e.g. see https://developer.chrome.com/apps/api_index).

(It also also contains some style changes for making the structure and layout of `$sniffer` tests
 more consistent.)

Fixes #11932

Closes #13945
2016-03-22 11:57:18 +02:00
Wassim Chegham 3c6dfbf67d docs(guide/component-router): fix typos
Closes #14278
2016-03-22 02:18:44 +02:00
Owen Craig 3277b885c4 fix(formatNumber): handle small numbers correctly when gSize !== lgSize
By using `>=` when comparing the number length to `lgSize`, we'll provide the correct value, when
formatting numbers with different `lgSize` than `gSize`.

Fixes #14289

Closes #14290
2016-03-22 00:11:26 +02:00
Georgios Kalpakas 48a256d04b test(TzDate): fix test in Australia
Probably due to implementation differences in browsers for pre-DST period (see
https://github.com/angular/angular.js/issues/5017 and especially
https://github.com/angular/angular.js/issues/5017#issuecomment-90775226 for context), some
`TzDate` tests had different behavior on different Timezones/Regions (e.g. failed in Australia,
which started to observe DST in 1971).
Since the used year (`1970`) didn't have any particular significance, this commit fixes the issue
by using a year that is more consistently handled by browsers (`2000`).

Fixes #14272

Closes #14285
2016-03-21 20:45:35 +02:00
surya prakash singh 0579430799 docs(input[time]): fix a typo in the example
Closes #14220
2016-03-21 01:26:17 +02:00
Rongduan Zhu 39ac68dac1 docs(guide/component-router): changed path to match diagram
Closes #14277
2016-03-21 00:00:12 +02:00
Georgios Kalpakas 87fb44a5d3 docs(CHANGELOG.md): rearrange v1.5.1 to be right below v1.5.2
Moved the `v1.5.1` section above the `v1.4.10` one, so that it is right below the `v1.5.2` section
for easier reference. Also removed an empty "Breaking Changes" sub-section.

Closes #14283
2016-03-20 22:54:53 +02:00
Georgios Kalpakas 5c76b406f7 chore(ci-checks): fix the ddescribe-iit task for Jasmine 2
Closes #14276
2016-03-20 22:26:06 +02:00
Matias Niemelä f665968daf chore(CHANGELOG): update version reference 2016-03-18 15:37:43 -07:00
Matias Niemelä 5d1291c29d docs(CHANGELOG): add notes for v1.5.2 2016-03-18 15:04:06 -07:00
Martin Staffa ce7f400011 fix(ngAnimate.$animate): remove animation callbacks when the element is removed
The test for this didn't actually test the listener removal. The addClass animation after
the element removal didn't start because the enter animation was still in progress.
2016-03-18 17:10:26 +01:00
Martin Staffa 0fc8516b0c Revert "tests(jQuery): test on both oldest & latest supported jQuery version"
This reverts commit 94572e89c2. The commit snuck
in while cherry-picking commits from master.
2016-03-18 17:08:46 +01:00
Jason Bedard 28b2a9b583 style($compile,$controller): adding function names for debug/tracing
Closes #13420
2016-03-18 15:53:09 +01:00
Jason Bedard e8549372fc style($templateRequest): rename minError var to avoid name conflict
Closes #13701
2016-03-18 15:53:08 +01:00
Jason Bedard 5a434eb74e style(ngModel,ngOptions): make use of declared but unused variables 2016-03-18 15:53:06 +01:00
Jason Bedard 318de4db66 style(*): remove unused variables 2016-03-18 15:53:05 +01:00
Martin Staffa a6c79bf15d docs(guide/Services): add whitespace in code example
Closes #14156
2016-03-18 15:53:04 +01:00
Huc Arnaud c6a10a755e docs(error/tplrt): add missing ' in example code
Missing a ' @ line 46 class='wrapper'

Closes #14258
2016-03-18 15:53:03 +01:00
Maxim Salnikov 1d7bd5bf4f docs(guide/Component Router): fix typo in example code
Closes #14262
2016-03-18 15:53:03 +01:00
Michał Gołębiowski 94572e89c2 tests(jQuery): test on both oldest & latest supported jQuery version 2016-03-18 15:51:30 +01:00
Peter Bacon Darwin fee7bac392 revert: fix($compile): do not add <span> elements to root text nodes
This commit reverts 7617c08da6 which was accidentally
merged into 1.5.x (by @petebacondarwin in a moment of rebase madness) despite
it containing a breaking change.
2016-03-17 09:56:30 +00:00
Georgios Kalpakas dbb3b0f561 docs(CHANGELOG.md): add notes for v1.4.10 2016-03-16 21:17:02 +02:00
Michał Gołębiowski b8bfed6a52 tests(jQuery): make the tests pass on jQuery 3.0.0-beta1
Closes #14229
2016-03-16 18:29:13 +00:00
Georgios Kalpakas 7215a89e7d docs(CHANGELOG.md): fix typo in anchor name 2016-03-16 19:56:23 +02:00
Georgios Kalpakas b7cca56091 docs(CHANGELOG.md): add notes for v1.5.1 2016-03-16 19:53:43 +02:00
Josh Schneider 7338e433f8 docs(guide/component-router): fix incorrect hook name for $canActivate
The hook will most likely be named back to `$routerCanActivate` in the future,
but for now this change is accurate.

Closes #14237
2016-03-16 16:46:03 +00:00
Peter Bacon Darwin 119ed07d5a chore(travis): update node and browser versions 2016-03-16 14:08:10 +00:00
Peter Bacon Darwin 5f98ae8323 chore(package.json): fix up dist-tag
Now that 1.5.x is out of beta we need to change the dist-tag to `latest`
2016-03-16 14:08:10 +00:00
Peter Bacon Darwin 8a598b43bb chore(jenkins): update node version to 4.4 2016-03-16 14:08:10 +00:00
Peter Bacon Darwin e5dff4cfbe chore(jenkins): fix node version chooser in build scripts
The `set-node-version.sh` script was being run in its own shell and so
was not actually changing the current version of node.
2016-03-16 14:08:10 +00:00
Lucas Mirelmann 6c7a9cdd5f chore(*): Upgrade to Jasmine 2.4
Highlights:
New mechanism to run async tests as Jasmine 2 removed `runs`, `waits` and `waitsFor`
The functions `iit`, `ddescribe` and `tthey` were renamed `fit`, `fdescribe` and
`fthey` as the originals came from Karma, Karma no longer bundles Jasmine and the
new function name comes from Jasmine.

Closes #14226
2016-03-16 14:08:09 +00:00
Matias Niemelä 3b34f762fe chore(build): 1.5 versions should stick to 1.5.x 2016-03-16 14:06:49 +00:00
Martin Staffa fa167ba747 docs(guide/animations): fix code block styling 2016-03-16 14:06:49 +00:00
643 changed files with 16801 additions and 27133 deletions
-3
View File
@@ -20,6 +20,3 @@ libpeerconnection.log
npm-debug.log
/tmp/
/scripts/bower/bower-*
.vscode
*.log
*.stackdump
+2 -3096
View File
File diff suppressed because it is too large Load Diff
+5 -13
View File
@@ -29,12 +29,9 @@ If you find a bug in the source code or a mistake in the documentation, you can
submitting an issue to our [GitHub Repository][github]. Even better you can submit a Pull Request
with a fix.
**Localization Issues:** Angular.js uses the [Google Closure I18N library] to generate
its own I18N files (the ngLocale module). This means that any changes to these files would be lost
the next time that we import the library.
Since the Closure library i18n data is itself auto-generated from the data of the
[Common Locale Data Repository (CLDR)] project, errors in the data should
be reported there. See also the [Closure guide to i18n changes].
***Localization Issue:*** *Angular.js uses the [Google Closure I18N library], to generate its own I18N files. This means that
any changes to these files would be lost the next time that we import the library. The recommended
approach is to submit a patch to the I18N project directly, instead of submitting it here.*
**Please see the [Submission Guidelines](#submit) below.**
@@ -244,7 +241,7 @@ Must be one of the following:
semi-colons, etc)
* **refactor**: A code change that neither fixes a bug nor adds a feature
* **perf**: A code change that improves performance
* **test**: Adding missing or correcting existing tests
* **test**: Adding missing tests
* **chore**: Changes to the build process or auxiliary tools and libraries such as documentation
generation
@@ -252,8 +249,6 @@ Must be one of the following:
The scope could be anything specifying place of the commit change. For example `$location`,
`$browser`, `$compile`, `$rootScope`, `ngHref`, `ngClick`, `ngView`, etc...
You can use `*` when the change affects more than a single scope.
### Subject
The subject contains succinct description of the change:
@@ -267,7 +262,7 @@ The body should include the motivation for the change and contrast this with pre
### Footer
The footer should contain any information about **Breaking Changes** and is also the place to
[reference GitHub issues that this commit closes][closing-issues].
reference GitHub issues that this commit **Closes**.
**Breaking Changes** should start with the word `BREAKING CHANGE:` with a space or two newlines.
The rest of the commit message is then used for this.
@@ -291,7 +286,6 @@ You can find out more detailed information about contributing in the
[Google Closure I18N library]: https://github.com/google/closure-library/tree/master/closure/goog/i18n
[angular-dev]: https://groups.google.com/forum/?fromgroups#!forum/angular-dev
[closing-issues]: https://help.github.com/articles/closing-issues-via-commit-messages/
[coc]: https://github.com/angular/code-of-conduct/blob/master/CODE_OF_CONDUCT.md
[commit-message-format]: https://docs.google.com/document/d/1QrDFcIiPjSLDn3EL15IJygNPiHORgU1_OOAqWjiDU5Y/edit#
[contribute]: http://docs.angularjs.org/misc/contribute
@@ -310,7 +304,5 @@ You can find out more detailed information about contributing in the
[plunker]: http://plnkr.co/edit
[stackoverflow]: http://stackoverflow.com/questions/tagged/angularjs
[unit-testing]: https://docs.angularjs.org/guide/unit-testing
[Common Locale Data Repository (CLDR)]: http://cldr.unicode.org
[Closure guide to i18n changes]: https://github.com/google/closure-library/wiki/Internationalization-%28i18n%29-changes-in-Closure-Library
[![Analytics](https://ga-beacon.appspot.com/UA-8594346-11/angular.js/CONTRIBUTING.md?pixel)](https://github.com/igrigorik/ga-beacon)
Vendored Regular → Executable
+3 -3
View File
@@ -70,7 +70,6 @@ var angularFiles = {
'src/ng/directive/ngInit.js',
'src/ng/directive/ngList.js',
'src/ng/directive/ngModel.js',
'src/ng/directive/ngModelOptions.js',
'src/ng/directive/ngNonBindable.js',
'src/ng/directive/ngOptions.js',
'src/ng/directive/ngPluralize.js',
@@ -140,8 +139,7 @@ var angularFiles = {
'src/ngSanitize/filter/linky.js'
],
'ngMock': [
'src/ngMock/angular-mocks.js',
'src/ngMock/browserTrigger.js'
'src/ngMock/angular-mocks.js'
],
'ngTouch': [
'src/ngTouch/touch.js',
@@ -156,6 +154,7 @@ var angularFiles = {
'angularScenario': [
'src/ngScenario/Scenario.js',
'src/ngScenario/browserTrigger.js',
'src/ngScenario/Application.js',
'src/ngScenario/Describe.js',
'src/ngScenario/Future.js',
@@ -214,6 +213,7 @@ var angularFiles = {
'build/angular.js',
'@angularSrcModules',
'test/modules/no_bootstrap.js',
'src/ngScenario/browserTrigger.js',
'test/helpers/*.js',
'test/ngAnimate/*.js',
'test/ngMessageFormat/*.js',
-44
View File
@@ -1,44 +0,0 @@
'use strict';
angular
.module('animationBenchmark', ['ngAnimate'], config)
.controller('BenchmarkController', BenchmarkController);
// Functions - Definitions
function config($compileProvider) {
$compileProvider
.commentDirectivesEnabled(false)
.cssClassDirectivesEnabled(false)
.debugInfoEnabled(false);
}
function BenchmarkController($scope) {
var self = this;
var itemCount = 1000;
var items = (new Array(itemCount + 1)).join('.').split('');
benchmarkSteps.push({
name: 'create',
fn: function() {
$scope.$apply(function() {
self.items = items;
});
}
});
benchmarkSteps.push({
name: '$digest',
fn: function() {
$scope.$root.$digest();
}
});
benchmarkSteps.push({
name: 'destroy',
fn: function() {
$scope.$apply(function() {
self.items = [];
});
}
});
}
-22
View File
@@ -1,22 +0,0 @@
/* eslint-env node */
'use strict';
module.exports = function(config) {
config.set({
scripts: [
{
id: 'jquery',
src: 'jquery-noop.js'
}, {
id: 'angular',
src: '/build/angular.js'
}, {
id: 'angular-animate',
src: '/build/angular-animate.js'
}, {
src: 'app.js'
}
]
});
};
-1
View File
@@ -1 +0,0 @@
// Override me with ?jquery=/bower_components/jquery/dist/jquery.js
-28
View File
@@ -1,28 +0,0 @@
<style>
[ng-cloak] { display: none !important; }
.animation-container .ng-enter,
.animation-container .ng-leave {
transition: all 0.1s;
}
.animation-container .ng-enter,
.animation-container .ng-leave.ng-leave-active {
opacity: 0;
}
.animation-container .ng-enter.ng-enter-active,
.animation-container .ng-leave {
opacity: 1;
}
</style>
<div ng-app="animationBenchmark" ng-cloak ng-controller="BenchmarkController as bm">
<div class="container-fluid">
<h2>Large collection of elements animated in and out with ngAnimate</h2>
<div class="animation-container">
<div ng-repeat="i in bm.items track by $index">
Just a plain ol' element
</div>
</div>
</div>
</div>
-108
View File
@@ -1,108 +0,0 @@
'use strict';
var app = angular.module('ngClassBenchmark', []);
app.controller('DataController', function DataController($scope) {
this.init = function() {
this.numberOfTodos = 1000;
this.implementation = 'tableOptimized';
this.completedPeriodicity = 3;
this.importantPeriodicity = 13;
this.urgentPeriodicity = 29;
this.createTodos(100);
this.setTodosValuesWithSeed(0);
};
this.clearTodos = function() {
this.todos = null;
};
this.createTodos = function(count) {
var i;
this.todos = [];
for (i = 0; i < count; i++) {
this.todos.push({
id: i + 1,
completed: false,
important: false,
urgent: false
});
}
};
this.setTodosValuesWithSeed = function(offset) {
var i, todo;
for (i = 0; i < this.todos.length; i++) {
todo = this.todos[i];
todo.completed = 0 === (i + offset) % this.completedPeriodicity;
todo.important = 0 === (i + offset) % this.importantPeriodicity;
todo.urgent = 0 === (i + offset) % this.urgentPeriodicity;
}
};
this.init();
benchmarkSteps.push({
name: 'setup',
fn: function() {
$scope.$apply();
this.clearTodos();
this.createTodos(this.numberOfTodos);
}.bind(this)
});
benchmarkSteps.push({
name: 'create',
fn: function() {
// initialize data for first time that will construct the DOM
this.setTodosValuesWithSeed(0);
$scope.$apply();
}.bind(this)
});
benchmarkSteps.push({
name: '$apply',
fn: function() {
$scope.$apply();
}
});
benchmarkSteps.push({
name: 'update',
fn: function() {
// move everything but completed
this.setTodosValuesWithSeed(3);
$scope.$apply();
}.bind(this)
});
benchmarkSteps.push({
name: 'unclass',
fn: function() {
// remove all classes
this.setTodosValuesWithSeed(NaN);
$scope.$apply();
}.bind(this)
});
benchmarkSteps.push({
name: 'class',
fn: function() {
// add all classes as the initial state
this.setTodosValuesWithSeed(0);
$scope.$apply();
}.bind(this)
});
benchmarkSteps.push({
name: 'destroy',
fn: function() {
this.clearTodos();
$scope.$apply();
}.bind(this)
});
});
-15
View File
@@ -1,15 +0,0 @@
/* eslint-env node */
'use strict';
module.exports = function(config) {
config.set({
scripts: [{
id: 'angular',
src: '/build/angular.js'
},
{
src: 'app.js'
}]
});
};
-177
View File
@@ -1,177 +0,0 @@
<style>
.gold {
background: gold;
}
.silver {
background: silver;
}
.table tbody tr > td.success {
background-color: #dff0d8;
}
.table tbody tr > td.error {
background-color: #f2dede;
}
.table tbody tr > td.warning {
background-color: #fcf8e3;
}
.table tbody tr > td.info {
background-color: #d9edf7;
}
.completed {
text-decoration: line-through;
}
.important {
font-weight: bold;
}
.urgent {
color: red;
}
</style>
<div ng-app="ngClassBenchmark" ng-cloak class="container-fluid">
<div ng-controller="DataController as benchmark" class="row">
<div class="col-lg-12">
<div class="well">
<h3>Parameters</h3>
<br>
<p>
<label>Number of todos</label><br>
<input type="number" ng-model="benchmark.numberOfTodos">
</p>
<br>
<p>
<label>Implementation</label><br>
<div class="radio">
<label>
<input ng-model="benchmark.implementation" value="tableOptimized"
type="radio" name="implementation">
Table optimized <br>
<code>ng-class="todo.completed && 'success'"</code>
</label>
</div>
<div class="radio">
<label>
<input ng-model="benchmark.implementation" value="table"
type="radio" name="implementation">
Table <br>
<code>ng-class="{success: todo.completed}"</code>
</label>
</div>
<div class="radio">
<label>
<input ng-model="benchmark.implementation" value="list"
type="radio" name="implementation">
List <br>
<code>ng-class="{completed: todo.completed, urgent: todo.urgent, important: todo.important"}</code>
</label>
</div>
<div class="radio">
<label>
<input ng-model="benchmark.implementation" value="singleOptimized"
type="radio" name="implementation">
Single ngClass optimized <br>
<code>
ng-class="{'panel-success': !!benchmark.todos, 'panel-danger': !benchmark.todos}"
</code>
</label>
</div>
<div class="radio">
<label>
<input ng-model="benchmark.implementation" value="single"
type="radio" name="implementation">
Single ngClass <br>
<code>
ng-class="{'panel-success': benchmark.todos, 'panel-danger': !benchmark.todos}"
</code>
</label>
</div>
</p>
</div>
<br>
<h3>Example</h3>
<div ng-switch="benchmark.implementation">
<table ng-switch-when="tableOptimized" class="table">
<thead>
<tr>
<th>todo #id</th>
<th>completed?</th>
<th>urgent?</th>
<th>important?</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="todo in benchmark.todos track by todo.id"
ng-class="todo.completed && 'active'"
ng-class-even="todo.completed && todo.important && 'gold'"
ng-class-odd="todo.completed && todo.important && 'silver'"
>
<td>#{{todo.id}}</td>
<td>{{todo.completed}}</td>
<td ng-class="todo.urgent && 'danger'">{{todo.urgent}}</td>
<td ng-class="todo.important && 'success'">{{todo.important}}</td>
</tr>
</tbody>
</table>
<table ng-switch-when="table" class="table">
<thead>
<tr>
<th>todo #id</th>
<th>completed?</th>
<th>urgent?</th>
<th>important?</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="todo in benchmark.todos track by todo.id"
ng-class="{active: todo.completed}"
ng-class-even="{gold: todo.completed && todo.important}"
ng-class-odd="{silver: todo.completed && todo.important}"
>
<td>#{{todo.id}}</td>
<td>{{todo.completed}}</td>
<td ng-class="{danger: todo.urgent}">{{todo.urgent}}</td>
<td ng-class="{success: todo.important}">{{todo.important}}</td>
</tr>
</tbody>
</table>
<ul ng-switch-when="list">
<li ng-repeat="todo in benchmark.todos track by todo.id"
ng-class="{
completed: todo.completed,
urgent: todo.urgent,
important: todo.important
}">#{{todo.id}}</li>
</ul>
<div ng-switch-when="singleOptimized"
class="panel"
ng-class="{'panel-success': !!benchmark.todos, 'panel-danger': !benchmark.todos}">
<div class="panel-heading">
<h3 class="panel-title">Information</h3>
</div>
<div class="panel-body"> The title is green because there are todos... </div>
</div>
<div ng-switch-when="single"
class="panel"
ng-class="{'panel-success': benchmark.todos, 'panel-danger': !benchmark.todos}">
<div class="panel-heading">
<h3 class="panel-title">Information</h3>
</div>
<div class="panel-body"> The title is green because there are todos... </div>
</div>
</div>
</div>
</div>
</div>
<br><br><br>
Regular → Executable
View File
View File
View File
View File
View File
View File
-104
View File
@@ -1,104 +0,0 @@
'use strict';
/* globals angular, benchmarkSteps */
var app = angular.module('selectBenchmark', []);
app.config(function($compileProvider) {
if ($compileProvider.debugInfoEnabled) {
$compileProvider.debugInfoEnabled(false);
}
});
app.controller('DataController', function($scope, $element) {
$scope.groups = [];
$scope.count = 10000;
function changeOptions() {
$scope.groups = [];
var i = 0;
var group;
while (i < $scope.count) {
if (i % 100 === 0) {
group = {
name: 'group-' + $scope.groups.length,
items: []
};
$scope.groups.push(group);
}
group.items.push({
id: i,
label: 'item-' + i
});
i++;
}
}
var selectElement = $element.find('select');
console.log(selectElement);
benchmarkSteps.push({
name: 'add-options',
fn: function() {
$scope.$apply(function() {
$scope.count = 10000;
changeOptions();
});
}
});
benchmarkSteps.push({
name: 'set-model-1',
fn: function() {
$scope.$apply(function() {
$scope.x = $scope.groups[10].items[0];
});
}
});
benchmarkSteps.push({
name: 'set-model-2',
fn: function() {
$scope.$apply(function() {
$scope.x = $scope.groups[0].items[10];
});
}
});
benchmarkSteps.push({
name: 'remove-options',
fn: function() {
$scope.count = 100;
changeOptions();
}
});
benchmarkSteps.push({
name: 'add-options',
fn: function() {
$scope.$apply(function() {
$scope.count = 10000;
changeOptions();
});
}
});
benchmarkSteps.push({
name: 'set-view-1',
fn: function() {
selectElement.val('2000');
selectElement.triggerHandler('change');
}
});
benchmarkSteps.push({
name: 'set-view-2',
fn: function() {
selectElement.val('1000');
selectElement.triggerHandler('change');
}
});
});
-15
View File
@@ -1,15 +0,0 @@
/* eslint-env node */
'use strict';
module.exports = function(config) {
config.set({
scripts: [{
id: 'angular',
src: '/build/angular.js'
},
{
src: 'app.js'
}]
});
};
-15
View File
@@ -1,15 +0,0 @@
<div ng-app="selectBenchmark" ng-cloak>
<div ng-controller="DataController">
<div class="container-fluid">
<p>
Tests the execution of a select with ngRepeat'ed options with ngValue for rendering during model
and option updates.
</p>
<select ng-model="x">
<optgroup ng-repeat="g in groups track by g.name" label="{{g.name}}">
<option ng-repeat="a in g.items track by a.id" ng-value="a">{{a.label}}</option>
</optgroup>
</select>
</div>
</div>
</div>
-4
View File
@@ -662,10 +662,6 @@ ul.events > li {
max-width: 100%;
}
.deprecation {
margin-top: 15px;
}
.deprecation .title {
float: left;
margin-right: 5px;
Regular → Executable
View File

Before

Width:  |  Height:  |  Size: 212 B

After

Width:  |  Height:  |  Size: 212 B

+1 -1
View File
@@ -4,7 +4,7 @@
/* global importScripts, lunr */
// Load up the lunr library
importScripts('../components/lunr-0.7.2/lunr.min.js');
importScripts('../components/lunr.js-0.5.12/lunr.min.js');
// Create the lunr index - the docs should be an array of object, each object containing
// the path and search terms for a page
@@ -10,7 +10,7 @@ describe('service pages', function() {
browser.get('build/docs/index.html#!/api/ng/service/$q');
providerLink = element.all(by.css('ol.api-profile-header-structure li a')).first();
expect(providerLink.getText()).not.toEqual('- $compileProvider');
expect(providerLink.getText()).not.toEqual('- $qProvider');
expect(providerLink.getAttribute('href')).not.toMatch(/api\/ng\/provider\/\$compileProvider/);
});
+5 -6
View File
@@ -114,7 +114,7 @@ angular.module('examples', [])
ctrl.prepareExampleData = function() {
if (ctrl.example.manifest) {
return $q.resolve(ctrl.example);
return $q.when(ctrl.example);
}
return getExampleData(ctrl.examplePath).then(function(data) {
@@ -159,11 +159,10 @@ angular.module('examples', [])
};
ctrl.$onInit = function() {
// Initialize the example data, so it's ready when clicking the open button.
// Otherwise pop-up blockers will prevent a new window from opening
ctrl.prepareExampleData(ctrl.example.path);
};
// Initialize the example data, so it's ready when clicking the open button.
// Otherwise pop-up blockers will prevent a new window from opening
ctrl.prepareExampleData(ctrl.example.path);
}]
};
}])
+10
View File
@@ -0,0 +1,10 @@
{
"name": "AngularJS-docs-app",
"dependencies": {
"jquery": "2.2.3",
"lunr.js": "0.5.12",
"open-sans-fontface": "1.0.4",
"google-code-prettify": "1.0.1",
"bootstrap": "3.1.1"
}
}
+2 -2
View File
@@ -17,9 +17,9 @@ module.exports = function debugDeployment(getVersion) {
'../angular-sanitize.js',
'../angular-touch.js',
'../angular-animate.js',
'components/marked-' + getVersion('marked') + '/lib/marked.js',
'components/marked-' + getVersion('marked', 'node_modules', 'package.json') + '/lib/marked.js',
'js/angular-bootstrap/dropdown-toggle.js',
'components/lunr-' + getVersion('lunr') + '/lunr.js',
'components/lunr.js-' + getVersion('lunr.js') + '/lunr.js',
'components/google-code-prettify-' + getVersion('google-code-prettify') + '/src/prettify.js',
'components/google-code-prettify-' + getVersion('google-code-prettify') + '/src/lang-css.js',
'js/current-version-data.js',
+2 -2
View File
@@ -17,9 +17,9 @@ module.exports = function defaultDeployment(getVersion) {
'../angular-sanitize.min.js',
'../angular-touch.min.js',
'../angular-animate.min.js',
'components/marked-' + getVersion('marked') + '/lib/marked.js',
'components/marked-' + getVersion('marked', 'node_modules', 'package.json') + '/lib/marked.js',
'js/angular-bootstrap/dropdown-toggle.min.js',
'components/lunr-' + getVersion('lunr') + '/lunr.min.js',
'components/lunr.js-' + getVersion('lunr.js') + '/lunr.min.js',
'components/google-code-prettify-' + getVersion('google-code-prettify') + '/src/prettify.js',
'components/google-code-prettify-' + getVersion('google-code-prettify') + '/src/lang-css.js',
'js/current-version-data.js',
+2 -2
View File
@@ -21,9 +21,9 @@ module.exports = function jqueryDeployment(getVersion) {
'../angular-sanitize.min.js',
'../angular-touch.min.js',
'../angular-animate.min.js',
'components/marked-' + getVersion('marked') + '/lib/marked.js',
'components/marked-' + getVersion('marked', 'node_modules', 'package.json') + '/lib/marked.js',
'js/angular-bootstrap/dropdown-toggle.min.js',
'components/lunr-' + getVersion('lunr') + '/lunr.min.js',
'components/lunr.js-' + getVersion('lunr.js') + '/lunr.min.js',
'components/google-code-prettify-' + getVersion('google-code-prettify') + '/src/prettify.js',
'components/google-code-prettify-' + getVersion('google-code-prettify') + '/src/lang-css.js',
'js/current-version-data.js',
+5 -19
View File
@@ -1,30 +1,16 @@
'use strict';
var versionInfo = require('../../../../lib/versions/version-info');
var googleCdnUrl = '//ajax.googleapis.com/ajax/libs/angularjs/';
var angularCodeUrl = '//code.angularjs.org/';
var cdnUrl = googleCdnUrl + versionInfo.cdnVersion;
// The plnkr examples must use the code.angularjs.org repo for the snapshot,
// and the cdn for the tagged version and, if the build is not tagged, the currentVersion.
//
// The currentVersion may not be available on the cdn (e.g. if built locally, or hasn't been pushed
// yet). This will lead to a 404, but this is preferable to loading a version with which the example
// might not work (possibly in subtle ways).
var examplesCdnUrl = versionInfo.currentVersion.isSnapshot ?
(angularCodeUrl + 'snapshot') :
(googleCdnUrl + (versionInfo.currentVersion.version || versionInfo.currentVersion));
var cdnUrl = '//ajax.googleapis.com/ajax/libs/angularjs/' + versionInfo.cdnVersion;
module.exports = function productionDeployment(getVersion) {
return {
name: 'production',
examples: {
commonFiles: {
scripts: [examplesCdnUrl + '/angular.min.js']
scripts: [cdnUrl + '/angular.min.js']
},
dependencyPath: examplesCdnUrl + '/'
dependencyPath: cdnUrl + '/'
},
scripts: [
cdnUrl + '/angular.min.js',
@@ -34,9 +20,9 @@ module.exports = function productionDeployment(getVersion) {
cdnUrl + '/angular-sanitize.min.js',
cdnUrl + '/angular-touch.min.js',
cdnUrl + '/angular-animate.min.js',
'components/marked-' + getVersion('marked') + '/lib/marked.js',
'components/marked-' + getVersion('marked', 'node_modules', 'package.json') + '/lib/marked.js',
'js/angular-bootstrap/dropdown-toggle.min.js',
'components/lunr-' + getVersion('lunr') + '/lunr.min.js',
'components/lunr.js-' + getVersion('lunr.js') + '/lunr.min.js',
'components/google-code-prettify-' + getVersion('google-code-prettify') + '/src/prettify.js',
'components/google-code-prettify-' + getVersion('google-code-prettify') + '/src/lang-css.js',
'js/current-version-data.js',
+2 -2
View File
@@ -10,8 +10,8 @@ module.exports = function getVersion(readFilesProcessor) {
var basePath = readFilesProcessor.basePath;
return function(component, sourceFolder, packageFile) {
sourceFolder = path.resolve(basePath, sourceFolder || 'node_modules');
packageFile = packageFile || 'package.json';
sourceFolder = path.resolve(basePath, sourceFolder || 'docs/bower_components');
packageFile = packageFile || 'bower.json';
return require(path.join(sourceFolder,component,packageFile)).version;
};
};
@@ -215,10 +215,11 @@
<p>
Super-powered by Google ©2010-2017
(<a id="version"
( <a id="version"
ng-href="https://github.com/angular/angular.js/blob/master/CHANGELOG.md#{{versionNumber}}"
ng-bind-template="v{{version}}" title="Changelog of this version of Angular JS">
</a>)
</a>
)
</p>
<p>
Code licensed under
@@ -61,12 +61,12 @@
</div>
{% endblock -%}
{% include "lib/params.template.html" %}
{% include "lib/events.template.html" %}
{%- if doc.animations %}
<h2 id="animations">Animations</h2>
{$ doc.animations | marked $}
{$ 'module:ngAnimate.$animate' | link('Click here', doc) $} to learn more about the steps involved in the animation.
{%- endif -%}
{% include "lib/params.template.html" %}
{% include "lib/events.template.html" %}
{% endblock %}
@@ -1,27 +0,0 @@
@ngdoc error
@name $compile:multilink
@fullName Linking Element Multiple Times
@description
This error occurs when a single element is linked more then once.
For example, if an element is compiled and linked twice without cloning:
```
var linker = $compile(template);
linker($scope); //=> ok
linker($scope); //=> multilink error
```
Linking an element as a clone multiple times is ok:
```
var linker = $compile(template);
linker($scope, function() { ... }); //=> ok
linker($scope, function() { ... }); //=> ok
```
However once an element has been linked it can not be re-linked as a clone:
```
var linker = $compile(template);
linker($scope); //=> ok
linker($scope, function() { ... }); //=> multilink error
```
-20
View File
@@ -1,20 +0,0 @@
@ngdoc error
@name $http:badjsonp
@fullName Bad JSONP Request Configuration
@description
This error occurs when the URL generated from the configuration object contains a parameter with the
same name as the configured `jsonpCallbackParam` property; or when it contains a parameter whose
value is `JSON_CALLBACK`.
`$http` JSONP requests need to attach a callback query parameter to the URL. The name of this
parameter is specified in the configuration object (or in the defaults) via the `jsonpCallbackParam`
property. You must not provide your own parameter with this name in the configuratio of the request.
In previous versions of Angular, you specified where to add the callback parameter value via the
`JSON_CALLBACK` placeholder. This is no longer allowed.
To resolve this error, remove any parameters that have the same name as the `jsonpCallbackParam`;
and/or remove any parameters that have a value of `JSON_CALLBACK`.
For more information, see the {@link ng.$http#jsonp `$http.jsonp()`} method API documentation.
+1 -5
View File
@@ -3,11 +3,7 @@
@fullName Bad Request Configuration
@description
This error occurs when the request configuration parameter passed to the {@link ng.$http `$http`} service is not a valid object.
`$http` expects a single parameter, the request configuration object, but received a parameter that was not an object or did not contain valid properties.
The error message should provide additional context such as the actual value of the parameter that was received.
If you passed a string parameter, perhaps you meant to call one of the shorthand methods on `$http` such as `$http.get(…)`, etc.
This error occurs when the request configuration parameter passed to the {@link ng.$http `$http`} service is not an object.  `$http` expects a single parameter, the request configuration object, but received a parameter that was not an object.  The error message should provide additional context such as the actual value of the parameter that was received.  If you passed a string parameter, perhaps you meant to call one of the shorthand methods on `$http` such as `$http.get(…)`, etc.
To resolve this error, make sure you pass a valid request configuration object to `$http`.
+45
View File
@@ -0,0 +1,45 @@
@ngdoc error
@name $http:legacy
@fullName The `success` and `error` methods on the promise returned from `$http` have been disabled.
@description
This error occurs when the legacy promise extensions (`success` and `error`)
{@link $httpProvider#useLegacyPromiseExtensions legacy `$http` promise extensions} have been disabled.
To resolve this error, either turn on the legacy extensions by adding
`$httpProvider.useLegacyPromiseExtensions(true);` to your application's configuration; or refactor you
use of `$http` to use `.then()` rather than `.success()` and `.error()`.
For example if you code looked like this:
```js
// Simple GET request example :
$http.get('/someUrl').
success(function(data, status, headers, config) {
// This callback will be called asynchronously
// when the response is available
}).
error(function(data, status, headers, config) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
```
then you would change it to look like:
```js
// Simple GET request example :
$http.get('/someUrl').
then(function(response) {
// (The response object contains the data, status, headers and config properties)
// This callback will be called asynchronously
// when the response is available.
}, function(response) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
```
For more information, see the
{@link $httpProvider#useLegacyPromiseExtensions `$httpProvider.useLegacyPromiseExtensions`}
documentation.
+12
View File
@@ -0,0 +1,12 @@
@ngdoc error
@name $parse:isecaf
@fullName Assigning to Fields of Disallowed Context
@description
Occurs when an expression attempts to assign a value on a field of any of the `Boolean`, `Number`,
`String`, `Array`, `Object`, or `Function` constructors or the corresponding prototypes.
Angular bans the modification of these constructors or their prototypes from within expressions,
since it is a known way to modify the behaviour of existing functions/operations.
To resolve this error, avoid assigning to fields of constructors or their prototypes in expressions.
+47
View File
@@ -0,0 +1,47 @@
@ngdoc error
@name $parse:isecdom
@fullName Referencing a DOM node in Expression
@description
Occurs when an expression attempts to access a DOM node.
AngularJS restricts access to DOM nodes from within expressions since it's a known way to
execute arbitrary Javascript code.
This check is only performed on object index and function calls in Angular expressions. These are
places that are harder for the developer to guard. Dotted member access (such as a.b.c) does not
perform this check - it's up to the developer to not expose such sensitive and powerful objects
directly on the scope chain.
To resolve this error, avoid access to DOM nodes.
# Event Handlers and Return Values
The `$parse:isecdom` error also occurs when an event handler invokes a function that returns a DOM
node.
```html
<button ng-click="iWillReturnDOM()">click me</button>
```
```js
$scope.iWillReturnDOM = function() {
return someDomNode;
}
```
To fix this issue, avoid returning DOM nodes from event handlers.
*Note: This error often means that you are accessing DOM from your controllers, which is usually
a sign of poor coding style that violates separation of concerns.*
# Implicit Returns in CoffeeScript
This error can occur more frequently when using CoffeeScript, which has a feature called implicit
returns. This language feature returns the last dereferenced object in the function when the
function has no explicit return statement.
The solution in this scenario is to add an explicit return statement. For example `return false` to
the function.
+17
View File
@@ -0,0 +1,17 @@
@ngdoc error
@name $parse:isecff
@fullName Referencing 'call', 'apply' and 'bind' Disallowed
@description
Occurs when an expression attempts to invoke Function's 'call', 'apply' or 'bind'.
Angular bans the invocation of 'call', 'apply' and 'bind' from within expressions
since access is a known way to modify the behaviour of existing functions.
To resolve this error, avoid using these methods in expressions.
Example expression that would result in this error:
```
<div>{{user.sendInfo.call({}, true)}}</div>
```
+27
View File
@@ -0,0 +1,27 @@
@ngdoc error
@name $parse:isecfld
@fullName Referencing Disallowed Field in Expression
@description
Occurs when an expression attempts to access one of the following fields:
* __proto__
* __defineGetter__
* __defineSetter__
* __lookupGetter__
* __lookupSetter__
AngularJS bans access to these fields from within expressions since
access is a known way to mess with native objects or
to execute arbitrary Javascript code.
To resolve this error, avoid using these fields in expressions. As a last resort,
alias their value and access them through the alias instead.
Example expressions that would result in this error:
```
<div>{{user.__proto__.hasOwnProperty = $emit}}</div>
<div>{{user.__defineGetter__('name', noop)}}</div>
```
+10
View File
@@ -0,0 +1,10 @@
@ngdoc error
@name $parse:isecfn
@fullName Referencing Function Disallowed
@description
Occurs when an expression attempts to access the 'Function' object (constructor for all functions in JavaScript).
Angular bans access to Function from within expressions since constructor access is a known way to execute arbitrary Javascript code.
To resolve this error, avoid Function access.
+11
View File
@@ -0,0 +1,11 @@
@ngdoc error
@name $parse:isecobj
@fullName Referencing Object Disallowed
@description
Occurs when an expression attempts to access the 'Object' object (Root object in JavaScript).
Angular bans access to Object from within expressions since access is a known way to modify
the behaviour of existing objects.
To resolve this error, avoid Object access.
@@ -0,0 +1,45 @@
@ngdoc error
@name $parse:isecwindow
@fullName Referencing Window object in Expression
@description
Occurs when an expression attempts to access a Window object.
AngularJS restricts access to the Window object from within expressions since it's a known way to
execute arbitrary Javascript code.
This check is only performed on object index and function calls in Angular expressions. These are
places that are harder for the developer to guard. Dotted member access (such as a.b.c) does not
perform this check - it's up to the developer to not expose such sensitive and powerful objects
directly on the scope chain.
To resolve this error, avoid Window access.
### Common CoffeeScript Issue
Be aware that if you are using CoffeeScript, it automatically returns the value of the last statement in a
function. So for instance
```coffeescript
scope.foo = ->
window.open 'https://example.com'
```
compiles to something like
```js
scope.foo = function() {
return window.open('https://example.com');
};
```
You can see that this function will return the result of calling `window.open`, which is a `Window`
object.
You can avoid this by explicitly returning something else from the function:
```coffeescript
scope.foo = ->
window.open 'https://example.com'
return true;
```
+3 -2
View File
@@ -3,7 +3,8 @@
@fullName Model is not of type `number`
@description
The `input[number]` and `input[range]` directives require the model to be a `number`.
The `input[type="number"]` and `input[type="range"][ng-input-range]` directives require the model to
be a `number`.
If the model is something else, this error will be thrown.
@@ -17,7 +18,7 @@ pipeline.
## Example
In this example, our model stores the number as a string, so we provide the `stringToNumber`
directive to convert it into the format the `input[number]` directive expects.
directive to convert it into the format the `input[type="number"]` directive expects.
<example module="numfmt-error-module" name="number-format-error">
+32 -42
View File
@@ -111,11 +111,11 @@ To configure the `$location` service, retrieve the
- **hashPrefix(prefix)**: `{string}`<br />
Prefix used for Hashbang URLs (used in Hashbang mode or in legacy browsers in HTML5 mode).<br />
Default: `'!'`
Default: `''`
### Example configuration
```js
$locationProvider.html5Mode(true).hashPrefix('*');
$locationProvider.html5Mode(true).hashPrefix('!');
```
## Getter and setter methods
@@ -232,27 +232,27 @@ than the hash fragment was changed.
### Example
```js
it('should show example', function() {
module(function($locationProvider) {
it('should show example', inject(
function($locationProvider) {
$locationProvider.html5Mode(false);
$locationProvider.hashPrefix('!');
});
inject(function($location) {
},
function($location) {
// open http://example.com/base/index.html#!/a
expect($location.absUrl()).toBe('http://example.com/base/index.html#!/a');
expect($location.path()).toBe('/a');
$location.absUrl() === 'http://example.com/base/index.html#!/a'
$location.path() === '/a'
$location.path('/foo');
expect($location.absUrl()).toBe('http://example.com/base/index.html#!/foo');
$location.path('/foo')
$location.absUrl() === 'http://example.com/base/index.html#!/foo'
expect($location.search()).toEqual({});
$location.search() === {}
$location.search({a: 'b', c: true});
expect($location.absUrl()).toBe('http://example.com/base/index.html#!/foo?a=b&c');
$location.absUrl() === 'http://example.com/base/index.html#!/foo?a=b&c'
$location.path('/new').search('x=y');
expect($location.absUrl()).toBe('http://example.com/base/index.html#!/new?x=y');
});
});
$location.absUrl() === 'http://example.com/base/index.html#!/new?x=y'
}
));
```
## HTML5 mode
@@ -274,50 +274,40 @@ and updates the url in a way that never performs a full page reload.
### Example
```js
it('should show example', function() {
module(function($locationProvider) {
it('should show example', inject(
function($locationProvider) {
$locationProvider.html5Mode(true);
$locationProvider.hashPrefix('!');
});
inject(function($location) {
},
function($location) {
// in browser with HTML5 history support:
// open http://example.com/#!/a -> rewrite to http://example.com/a
// (replacing the http://example.com/#!/a history record)
expect($location.path()).toBe('/a');
$location.path() === '/a'
$location.path('/foo');
expect($location.absUrl()).toBe('http://example.com/foo');
$location.absUrl() === 'http://example.com/foo'
expect($location.search()).toEqual({});
$location.search() === {}
$location.search({a: 'b', c: true});
expect($location.absUrl()).toBe('http://example.com/foo?a=b&c');
$location.absUrl() === 'http://example.com/foo?a=b&c'
$location.path('/new').search('x=y');
expect($location.url()).toBe('/new?x=y');
expect($location.absUrl()).toBe('http://example.com/new?x=y');
});
});
$location.url() === 'new?x=y'
$location.absUrl() === 'http://example.com/new?x=y'
it('should show example (when browser doesn\'t support HTML5 mode', function() {
module(function($provide, $locationProvider) {
$locationProvider.html5Mode(true);
$locationProvider.hashPrefix('!');
$provide.value('$sniffer', {history: false});
});
inject(initBrowser({ url: 'http://example.com/new?x=y', basePath: '/' }),
function($location) {
// in browser without html5 history support:
// open http://example.com/new?x=y -> redirect to http://example.com/#!/new?x=y
// (again replacing the http://example.com/new?x=y history item)
expect($location.path()).toBe('/new');
expect($location.search()).toEqual({x: 'y'});
$location.path() === '/new'
$location.search() === {x: 'y'}
$location.path('/foo/bar');
expect($location.path()).toBe('/foo/bar');
expect($location.url()).toBe('/foo/bar?x=y');
expect($location.absUrl()).toBe('http://example.com/#!/foo/bar?x=y');
});
});
$location.path() === '/foo/bar'
$location.url() === '/foo/bar?x=y'
$location.absUrl() === 'http://example.com/#!/foo/bar?x=y'
}
));
```
### Fallback for legacy browsers
+41 -95
View File
@@ -59,133 +59,79 @@ attributes (if they have not been explicitly specified by the developer):
* aria-invalid
* aria-required
* aria-readonly
* aria-disabled
### Example
<example module="ngAria_ngModelExample" deps="angular-aria.js" name="accessibility-ng-model">
<file name="index.html">
<form>
<custom-checkbox role="checkbox" ng-model="checked" required
aria-label="Custom checkbox" show-attrs>
Custom checkbox
</custom-checkbox>
<form ng-controller="formsController">
<some-checkbox role="checkbox" ng-model="checked" ng-class="{active: checked}"
ng-disabled="isDisabled" ng-click="toggleCheckbox()"
aria-label="Custom Checkbox" show-attrs>
<span class="icon" aria-hidden="true"></span>
Custom Checkbox
</some-checkbox>
</form>
<hr />
<b>Is checked:</b> {{ !!checked }}
</file>
<file name="script.js">
angular.
module('ngAria_ngModelExample', ['ngAria']).
directive('customCheckbox', customCheckboxDirective).
directive('showAttrs', showAttrsDirective);
function customCheckboxDirective() {
angular.module('ngAria_ngModelExample', ['ngAria'])
.controller('formsController', function($scope) {
$scope.checked = false;
$scope.toggleCheckbox = function() {
$scope.checked = !$scope.checked;
};
})
.directive('someCheckbox', function() {
return {
restrict: 'E',
require: 'ngModel',
transclude: true,
template:
'<span class="icon" aria-hidden="true"></span> ' +
'<ng-transclude></ng-transclude>',
link: function(scope, elem, attrs, ctrl) {
// Overwrite necessary `NgModelController` methods
ctrl.$isEmpty = isEmpty;
ctrl.$render = render;
// Bind to events
elem.on('click', function(event) {
event.preventDefault();
scope.$apply(toggleCheckbox);
});
elem.on('keypress', function(event) {
link: function($scope, $el, $attrs) {
$el.on('keypress', function(event) {
event.preventDefault();
if (event.keyCode === 32 || event.keyCode === 13) {
scope.$apply(toggleCheckbox);
$scope.toggleCheckbox();
$scope.$apply();
}
});
// Helpers
function isEmpty(value) {
return !value;
}
function render() {
elem[ctrl.$viewValue ? 'addClass' : 'removeClass']('checked');
}
function toggleCheckbox() {
ctrl.$setViewValue(!ctrl.$viewValue);
ctrl.$render();
}
}
};
}
function showAttrsDirective($timeout) {
return function(scope, elem, attrs) {
})
.directive('showAttrs', function() {
return function($scope, $el, $attrs) {
var pre = document.createElement('pre');
elem.after(pre);
scope.$watchCollection(function() {
return Array.prototype.slice.call(elem[0].attributes).reduce(function(aggr, attr) {
if (attr.name !== attrs.$attr.showAttrs) aggr[attr.name] = attr.value;
return aggr;
}, {});
}, function(newValues) {
$timeout(function() {
pre.textContent = angular.toJson(newValues, 2);
$el.after(pre);
$scope.$watch(function() {
var $attrs = {};
Array.prototype.slice.call($el[0].attributes, 0).forEach(function(item) {
if (item.name !== 'show-$attrs') {
$attrs[item.name] = item.value;
}
});
});
return $attrs;
}, function(newAttrs, oldAttrs) {
pre.textContent = JSON.stringify(newAttrs, null, 2);
}, true);
};
}
});
</file>
<file name="style.css">
custom-checkbox {
[role=checkbox] {
cursor: pointer;
display: inline-block;
}
custom-checkbox .icon:before {
[role=checkbox] .icon:before {
content: '\2610';
display: inline-block;
font-size: 2em;
line-height: 1;
speak: none;
vertical-align: middle;
speak: none;
}
custom-checkbox.checked .icon:before {
[role=checkbox].active .icon:before {
content: '\2611';
}
</file>
<file name="protractor.js" type="protractor">
var checkbox = element(by.css('custom-checkbox'));
var checkedCheckbox = element(by.css('custom-checkbox.checked'));
it('should have the `checked` class only when checked', function() {
expect(checkbox.isPresent()).toBe(true);
expect(checkedCheckbox.isPresent()).toBe(false);
checkbox.click();
expect(checkedCheckbox.isPresent()).toBe(true);
checkbox.click();
expect(checkedCheckbox.isPresent()).toBe(false);
});
it('should have the `aria-checked` attribute set to the appropriate value', function() {
expect(checkedCheckbox.isPresent()).toBe(false);
expect(checkbox.getAttribute('aria-checked')).toBe('false');
checkbox.click();
expect(checkedCheckbox.isPresent()).toBe(true);
expect(checkbox.getAttribute('aria-checked')).toBe('true');
checkbox.click();
expect(checkedCheckbox.isPresent()).toBe(false);
expect(checkbox.getAttribute('aria-checked')).toBe('false');
});
pre {
white-space: pre-wrap;
}
</file>
</example>
+7 -5
View File
@@ -122,7 +122,7 @@ The same approach to animation can be used using JavaScript code (**jQuery is us
```js
myModule.animation('.repeated-item', function() {
return {
enter: function(element, done) {
enter : function(element, done) {
element.css('opacity',0);
jQuery(element).animate({
opacity: 1
@@ -137,7 +137,7 @@ myModule.animation('.repeated-item', function() {
}
}
},
leave: function(element, done) {
leave : function(element, done) {
element.css('opacity', 1);
jQuery(element).animate({
opacity: 0
@@ -152,7 +152,7 @@ myModule.animation('.repeated-item', function() {
}
}
},
move: function(element, done) {
move : function(element, done) {
element.css('opacity', 0);
jQuery(element).animate({
opacity: 1
@@ -169,8 +169,8 @@ myModule.animation('.repeated-item', function() {
},
// you can also capture these animation events
addClass: function(element, className, done) {},
removeClass: function(element, className, done) {}
addClass : function(element, className, done) {},
removeClass : function(element, className, done) {}
}
});
```
@@ -410,10 +410,12 @@ You can prevent this unwanted behavior by adding CSS to the `.ng-animate` class
for the whole duration of an 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;
}
```
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.
+2 -2
View File
@@ -115,7 +115,7 @@ Here is an example of manually initializing Angular:
$scope.greetMe = 'World';
}]);
angular.element(function() {
angular.element(document).ready(function() {
angular.bootstrap(document, ['myApp']);
});
</script>
@@ -167,4 +167,4 @@ until `angular.resumeBootstrap()` is called.
`angular.resumeBootstrap()` takes an optional array of modules that
should be added to the original list of modules that the app was
about to be bootstrapped with.
about to be bootstrapped with.
+5 -5
View File
@@ -215,7 +215,7 @@ You can see the complete application running below.
function HeroService($q) {
var heroesPromise = $q.resolve([
var heroesPromise = $q.when([
{ id: 11, name: 'Mr. Nice' },
{ id: 12, name: 'Narco' },
{ id: 13, name: 'Bombasto' },
@@ -308,7 +308,7 @@ You can see the complete application running below.
function CrisisService($q) {
var crisesPromise = $q.resolve([
var crisesPromise = $q.when([
{id: 1, name: 'Princess Held Captive'},
{id: 2, name: 'Dragon Burning Cities'},
{id: 3, name: 'Giant Asteroid Heading For Earth'},
@@ -415,7 +415,7 @@ You can see the complete application running below.
function DialogService($q) {
this.confirm = function(message) {
return $q.resolve(window.confirm(message || 'Is it OK?'));
return $q.when(window.confirm(message || 'Is it OK?'));
};
}
</file>
@@ -713,7 +713,7 @@ making an actual server request, perhaps over HTTP.
```js
function HeroService($q) {
var heroesPromise = $q.resolve([
var heroesPromise = $q.when([
{ id: 11, name: 'Mr. Nice' },
...
]);
@@ -990,7 +990,7 @@ have made. The result of the prompt is a promise that can be used in a `$routerC
function DialogService($q) {
this.confirm = function(message) {
return $q.resolve(window.confirm(message || 'Is it OK?'));
return $q.when(window.confirm(message || 'Is it OK?'));
};
}
```
-1
View File
@@ -78,7 +78,6 @@ It's also possible to add components via {@link $compileProvider#component} in a
| link functions | Yes | No |
| multiElement | Yes | No |
| priority | Yes | No |
| replace | Yes (deprecated) | No |
| require | Yes | Yes |
| restrict | Yes | No (restricted to elements only) |
| scope | Yes (default: false) | No (scope is always isolate) |
+5 -5
View File
@@ -141,7 +141,7 @@ different currencies and also pay the invoice.
<b>Total:</b>
<span ng-repeat="c in invoice.currencies">
{{invoice.total(c) | currency:c}}
</span><br>
</span>
<button class="btn" ng-click="invoice.pay()">Pay</button>
</div>
</div>
@@ -242,7 +242,7 @@ Let's refactor our example and move the currency conversion into a service in an
<b>Total:</b>
<span ng-repeat="c in invoice.currencies">
{{invoice.total(c) | currency:c}}
</span><br>
</span>
<button class="btn" ng-click="invoice.pay()">Pay</button>
</div>
</div>
@@ -326,7 +326,7 @@ The following example shows how this is done with Angular:
var YAHOO_FINANCE_URL_PATTERN =
'//query.yahooapis.com/v1/public/yql?q=select * from ' +
'yahoo.finance.xchange where pair in ("PAIRS")&format=json&' +
'env=store://datatables.org/alltableswithkeys';
'env=store://datatables.org/alltableswithkeys&callback=JSON_CALLBACK';
var currencies = ['USD', 'EUR', 'CNY'];
var usdToForeignRates = {};
@@ -337,7 +337,7 @@ The following example shows how this is done with Angular:
var refresh = function() {
var url = YAHOO_FINANCE_URL_PATTERN.
replace('PAIRS', 'USD' + currencies.join('","USD'));
return $http.get(url).then(function(response) {
return $http.jsonp(url).then(function(response) {
var newUsdToForeignRates = {};
angular.forEach(response.data.query.results.rate, function(rate) {
var currency = rate.id.substring(3,6);
@@ -371,7 +371,7 @@ The following example shows how this is done with Angular:
<b>Total:</b>
<span ng-repeat="c in invoice.currencies">
{{invoice.total(c) | currency:c}}
</span><br>
</span>
<button class="btn" ng-click="invoice.pay()">Pay</button>
</div>
</div>
+9 -27
View File
@@ -159,37 +159,19 @@ the end of the name. The `$delegate` provided is dictated by the type of service
### module.decorator
This {@link api/ng/type/angular.Module#decorator function} is the same as the `$provide.decorator` function except it is
exposed through the module API. This allows you to separate your decorator patterns from your module config blocks.
exposed through the module API. This allows you to separate your decorator patterns from your module config blocks. The
main caveat here is that you will need to take note the order in which you create your decorators.
Like with `$provide.decorator`, the `module.decorator` function runs during the config phase of the app. That means
you can define a `module.decorator` before the decorated service is defined.
Since you can apply multiple decorators, it is noteworthy that decorator application always follows order
of declaration:
- If a service is decorated by both `$provide.decorator` and `module.decorator`, the decorators are applied in order:
Unlike in the module config block (which allows configuration of services prior to their creation), the service must be
registered prior to the decorator (see {@link guide/providers#provider-recipe Provider Recipe}). For example, the
following would not work because you are attempting to decorate outside of the configuration phase and the service
hasn't been created yet:
```js
angular
.module('theApp', [])
.factory('theFactory', theFactoryFn)
.config(function($provide) {
$provide.decorator('theFactory', provideDecoratorFn); // runs first
})
.decorator('theFactory', moduleDecoratorFn); // runs seconds
```
// will cause an error since 'someService' hasn't been registered
angular.module('myApp').decorator('someService', ...);
- If the service has been declared multiple times, a decorator will decorate the service that has been declared
last:
```js
angular
.module('theApp', [])
.factory('theFactory', theFactoryFn)
.decorator('theFactory', moduleDecoratorFn)
.factory('theFactory', theOtherFactoryFn);
// `theOtherFactoryFn` is selected as 'theFactory' provider and it is decorated via `moduleDecoratorFn`.
angular.module('myApp').factory('someService', ...);
```
## Example Applications
+11 -11
View File
@@ -42,7 +42,7 @@ Angular expressions are like JavaScript expressions with the following differenc
* **No Object Creation With New Operator:** You cannot use `new` operator in an Angular expression.
* **No Bitwise, Comma, And Void Operators:** You cannot use
[Bitwise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators),
[Bitwise](https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators),
`,` or `void` operators in an Angular expression.
@@ -113,11 +113,11 @@ You can try evaluating different expressions here:
Angular does not use JavaScript's `eval()` to evaluate expressions. Instead Angular's
{@link ng.$parse $parse} service processes these expressions.
Angular expressions do not have direct access to global variables like `window`, `document` or `location`.
Angular expressions do not have access to global variables like `window`, `document` or `location`.
This restriction is intentional. It prevents accidental access to the global state a common source of subtle bugs.
Instead use services like `$window` and `$location` in functions on controllers, which are then called from expressions.
Such services provide mockable access to globals.
Instead use services like `$window` and `$location` in functions called from expressions. Such services
provide mockable access to globals.
It is possible to access the context object using the identifier `this` and the locals object using the
identifier `$locals`.
@@ -241,7 +241,7 @@ An expression that starts with `::` is considered a one-time expression. One-tim
will stop recalculating once they are stable, which happens after the first digest if the expression
result is a non-undefined value (see value stabilization algorithm below).
<example module="oneTimeBindingExampleApp" name="expression-one-time">
<example module="oneTimeBidingExampleApp" name="expression-one-time">
<file name="index.html">
<div ng-controller="EventController">
<button ng-click="clickMe($event)">Click Me</button>
@@ -250,7 +250,7 @@ result is a non-undefined value (see value stabilization algorithm below).
</div>
</file>
<file name="script.js">
angular.module('oneTimeBindingExampleApp', []).
angular.module('oneTimeBidingExampleApp', []).
controller('EventController', ['$scope', function($scope) {
var counter = 0;
var names = ['Igor', 'Misko', 'Chirayu', 'Lucas'];
@@ -265,24 +265,24 @@ result is a non-undefined value (see value stabilization algorithm below).
</file>
<file name="protractor.js" type="protractor">
it('should freeze binding after its value has stabilized', function() {
var oneTimeBinding = element(by.id('one-time-binding-example'));
var oneTimeBiding = element(by.id('one-time-binding-example'));
var normalBinding = element(by.id('normal-binding-example'));
expect(oneTimeBinding.getText()).toEqual('One time binding:');
expect(oneTimeBiding.getText()).toEqual('One time binding:');
expect(normalBinding.getText()).toEqual('Normal binding:');
element(by.buttonText('Click Me')).click();
expect(oneTimeBinding.getText()).toEqual('One time binding: Igor');
expect(oneTimeBiding.getText()).toEqual('One time binding: Igor');
expect(normalBinding.getText()).toEqual('Normal binding: Igor');
element(by.buttonText('Click Me')).click();
expect(oneTimeBinding.getText()).toEqual('One time binding: Igor');
expect(oneTimeBiding.getText()).toEqual('One time binding: Igor');
expect(normalBinding.getText()).toEqual('Normal binding: Misko');
element(by.buttonText('Click Me')).click();
element(by.buttonText('Click Me')).click();
expect(oneTimeBinding.getText()).toEqual('One time binding: Igor');
expect(oneTimeBiding.getText()).toEqual('One time binding: Igor');
expect(normalBinding.getText()).toEqual('Normal binding: Lucas');
});
</file>
+8 -9
View File
@@ -47,7 +47,7 @@ This is a collection of external, 3rd party resources for learning and developin
##### Server-Specific
* **Django:** [Tutorial](http://blog.mourafiq.com/post/55034504632/end-to-end-web-app-with-django-rest-framework), [Integrating AngularJS with Django](http://django-angular.readthedocs.org/en/latest/integration.html), [Getting Started with Django Rest Framework and AngularJS](http://blog.kevinastone.com/getting-started-with-django-rest-framework-and-angularjs.html)
* **FireBase:** [AngularFire](http://angularfire.com/), [Realtime Apps with AngularJS and FireBase (video)](http://www.youtube.com/watch?v=C7ZI7z7qnHU)
* **FireBase:** [AngularFire](http://angularfire.com/), [Firebase Foundations for AngularJS](http://blog.watchandcode.com/firebase-foundations/), [Realtime Apps with AngularJS and FireBase (video)](http://www.youtube.com/watch?v=C7ZI7z7qnHU)
* **Google Cloud Platform: **[with Cloud Endpoints](https://cloud.google.com/developers/articles/angularjs-cloud-endpoints-recipe-for-building-modern-web-applications/), [with Go](https://github.com/GoogleCloudPlatform/appengine-angular-gotodos)
* **Hood.ie:** [60 Minutes to Awesome](http://www.roberthorvick.com/2013/06/30/todomvc-angularjs-hood-ie-60-minutes-to-awesome/)
* **MEAN Stack: **[Blog post](http://blog.mongodb.org/post/49262866911/the-mean-stack-mongodb-expressjs-angularjs-and), [Setup](http://thecodebarbarian.wordpress.com/2013/07/22/introduction-to-the-mean-stack-part-one-setting-up-your-tools/), [GDL Video](https://developers.google.com/live/shows/913996610)
@@ -117,18 +117,16 @@ You can find a larger list of Angular external libraries at [ngmodules.org](http
## General Learning Resources
### Books
* [AngularJS Directives](http://www.amazon.com/AngularJS-Directives-Alex-Vanston/dp/1783280336) by Alex Vanston
* [AngularJS Essentials (Free eBook)](https://www.packtpub.com/packt/free-ebook/angularjs-essentials) by Rodrigo Branas
* [AngularJS in Action](https://www.manning.com/books/angularjs-in-action) by Lukas Ruebbelke
* [AngularJS: Novice to Ninja](http://www.amazon.in/AngularJS-Novice-Ninja-Sandeep-Panda/dp/0992279453) by Sandeep Panda
* [AngularJS UI Development](http://www.amazon.com/AngularJS-UI-Development-Amit-Ghart-ebook/dp/B00OXVAK7A) by Amit Gharat and Matthias Nehlsen
* [AngularJS: Up and Running](http://www.amazon.com/AngularJS-Running-Enhanced-Productivity-Structured/dp/1491901942) by Brad Green and Shyam Seshadri
* [Developing an AngularJS Edge](http://www.amazon.com/Developing-AngularJS-Edge-Christopher-Hiller-ebook/dp/B00CJLFF8K) by Christopher Hiller
* [Mastering Web App Development](http://www.amazon.com/Mastering-Web-Application-Development-AngularJS/dp/1782161821) by Pawel Kozlowski and Pete Bacon Darwin
* [ng-book: The Complete Book on AngularJS](http://ng-book.com/) by Ari Lerner
* [Professional AngularJS](http://www.amazon.com/Professional-AngularJS-Valeri-Karpov/dp/1118832078/)
* [AngularJS Directives](http://www.amazon.com/AngularJS-Directives-Alex-Vanston/dp/1783280336) by Alex Vanston
* [Recipes With AngularJS](http://www.amazon.co.uk/Recipes-Angular-js-Frederik-Dietz-ebook/dp/B00DK95V48) by Frederik Dietz
* [Developing an AngularJS Edge](http://www.amazon.com/Developing-AngularJS-Edge-Christopher-Hiller-ebook/dp/B00CJLFF8K) by Christopher Hiller
* [ng-book: The Complete Book on AngularJS](http://ng-book.com/) by Ari Lerner
* [AngularJS : Novice to Ninja](http://www.amazon.in/AngularJS-Novice-Ninja-Sandeep-Panda/dp/0992279453) by Sandeep Panda
* [AngularJS UI Development](http://www.amazon.com/AngularJS-UI-Development-Amit-Ghart-ebook/dp/B00OXVAK7A) by Amit Gharat and Matthias Nehlsen
* [Responsive Web Design with AngularJS](http://www.amazon.com/Responsive-Design-AngularJS-Sandeep-Kumar/dp/178439842X) by Sandeep Kumar Patel
* [Professional AngularJS](http://www.amazon.com/Professional-AngularJS-Valeri-Karpov/dp/1118832078/)
### Videos:
* [egghead.io](http://egghead.io/)
@@ -139,6 +137,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:**
[The Angular Course (115 videos that show you how to build a full app)](http://watchandcode.com/courses/angular-course/),
[Pluralsight (3 courses)](http://www.pluralsight.com/training/Courses/Find?highlight=true&searchTerm=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),
+1 -1
View File
@@ -396,7 +396,7 @@ In the following example we create two directives:
if (ctrl.$isEmpty(modelValue)) {
// consider empty model valid
return $q.resolve();
return $q.when();
}
var def = $q.defer();
+2 -2
View File
@@ -26,7 +26,7 @@ directive}. Additionally, you can use {@link guide/i18n#messageformat-extension
All localizable Angular components depend on locale-specific rule sets managed by the {@link
ng.$locale `$locale` service}.
There are a few examples that showcase how to use Angular filters with various locale rule sets in the
There a few examples that showcase how to use Angular filters with various locale rule sets in the
[`i18n/e2e` directory](https://github.com/angular/angular.js/tree/master/i18n/e2e) of the Angular
source code.
@@ -85,7 +85,7 @@ requires German locale, you would serve index_de-de.html which will look somethi
Both approaches described above require you to prepare different `index.html` pages or JavaScript
files for each locale that your app may use. You also need to configure your server to serve
the correct file that corresponds to the desired locale.
the correct file that correspond to the desired locale.
The second approach (including the locale JavaScript file in `index.html`) may be slower because
an extra script needs to be loaded.
-9
View File
@@ -26,15 +26,6 @@ normal {@link ng.$rootScope.Scope#$digest digest} cycle.
Note that the interpolateDirective has a priority of 100 and sets up the watch in the preLink function.
### How the string representation is computed
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`.
- if the above doesn't apply, `JSON.stringify` is used.
### Binding to boolean attributes
Attributes such as `disabled` are called `boolean` attributes, because their presence means `true` and
File diff suppressed because it is too large Load Diff
+24 -37
View File
@@ -30,55 +30,42 @@ so keeping to AngularJS standards is not just a functionality issue, it's also c
facilitate rapid security updates.
## Angular Templates and Expressions
## Expression Sandboxing
**If an attacker has access to control Angular templates or expressions, they can exploit an Angular application
via an XSS attack, regardless of the version.**
AngularJS's expressions are sandboxed not for security reasons, but instead to maintain a proper
separation of application responsibilities. For example, access to `window` is disallowed
because it makes it easy to introduce brittle global state into your application.
There are a number of ways that templates and expressions can be controlled:
However, this sandbox is not intended to stop attackers who can edit the template before it's
processed by Angular. It may be possible to run arbitrary JavaScript inside double-curly bindings
if an attacker can modify them.
* **Generating Angular templates on the server containing user-provided content**. This is the most common pitfall
where you are generating HTML via some server-side engine such as PHP, Java or ASP.NET.
* **Passing an expression generated from user-provided content in calls to the following methods on a {@link scope scope}**:
* `$watch(userContent, ...)`
* `$watchGroup(userContent, ...)`
* `$watchCollection(userContent, ...)`
* `$eval(userContent)`
* `$evalAsync(userContent)`
* `$apply(userContent)`
* `$applyAsync(userContent)`
* **Passing an expression generated from user-provided content in calls to services that parse expressions**:
* `$compile(userContent)`
* `$parse(userContent)`
* `$interpolate(userContent)`
* **Passing an expression generated from user provided content as a predicate to `orderBy` pipe**:
`{{ value | orderBy : userContent }}`
But if an attacker can change arbitrary HTML templates, there's nothing stopping them from doing:
### Sandbox removal
Each version of Angular 1 up to, but not including 1.6, contained an expression sandbox, which reduced the surface area of
the vulnerability but never removed it. **In Angular 1.6 we removed this sandbox as developers kept relying upon it as a security
feature even though it was always possible to access arbitrary JavaScript code if one could control the Angular templates
or expressions of applications.**
```html
<script>somethingEvil();</script>
```
Control of the Angular templates makes applications vulnerable even if there was a completely secure sandbox:
* https://ryhanson.com/stealing-session-tokens-on-plunker-with-an-angular-expression-injection/ in this blog post the author shows
a (now closed) vulnerability in the Plunker application due to server-side rendering inside an Angular template.
* https://ryhanson.com/angular-expression-injection-walkthrough/ in this blog post the author describes an attack, which does not
rely upon an expression sandbox bypass, that can be made because the sample application is rendering a template on the server that
contains user entered content.
**It's better to design your application in such a way that users cannot change client-side templates.**
**It's best to design your application in such a way that users cannot change client-side templates.**
For instance:
* Do not mix client and server templates
* Do not use user input to generate templates dynamically
* Do not run user input through `$scope.$eval` (or any of the other expression parsing functions listed above)
* Do not run user input through `$scope.$eval`
* Consider using {@link ng.directive:ngCsp CSP} (but don't rely only on CSP)
**You can use suitably sanitized server-side templating to dynamically generate CSS, URLs, etc, but not for generating templates that are
bootstrapped/compiled by Angular.**
**If you must continue to allow user-provided content in an Angular template then the safest option is to ensure that it is only
present in the part of the template that is made inert via the {@link ngNonBindable} directive.**
### Mixing client-side and server-side templates
In general, we recommend against this because it can create unintended XSS vectors.
However, it's ok to mix server-side templating in the bootstrap template (`index.html`) as long
as user input cannot be used on the server to output html that would then be processed by Angular
in a way that would allow for arbitrary code execution.
**For instance, you can use server-side templating to dynamically generate CSS, URLs, etc, but not
for generating templates that are bootstrapped/compiled by Angular.**
## HTTP Requests
+1 -1
View File
@@ -442,7 +442,7 @@ There is also an example of testing promises in the {@link ng.$q#testing `$q` se
## Using `beforeAll()`
Jasmine's `beforeAll()` and mocha's `before()` hooks are often useful for sharing test setup - either to reduce test run-time or simply to make for more focused test cases.
Jasmine's `beforeAll()` and mocha's `before()` hooks are often useful for sharing test setup - either to reduce test run-time or simply to make for more focussed test cases.
By default, ngMock will create an injector per test case to ensure your tests do not affect each other. However, if we want to use `beforeAll()`, ngMock will have to create the injector before any test cases are run, and share that injector through all the cases for that `describe`. That is where {@link angular.mock.module.sharedInjector module.sharedInjector()} comes in. When it's called within a `describe` block, a single injector is shared between all hooks and test cases run in that block.
+1 -1
View File
@@ -2,7 +2,7 @@
@name FAQ
@description
# FAQ
#FAQ
## Questions
+1 -1
View File
@@ -32,7 +32,7 @@ tutorials.
## Subscribe
* Subscribe to the [mailing list](http://groups.google.com/forum/?fromgroups#!forum/angular). Ask questions here!
* Follow us on [Twitter](https://twitter.com/intent/follow?original_referer=http%3A%2F%2Fangularjs.org%2F&region=follow_link&screen_name=angular&source=followbutton&variant=2.0)
* Follow us on [Twitter](https://twitter.com/intent/follow?original_referer=http%3A%2F%2Fangularjs.org%2F&region=follow_link&screen_name=angularjs&source=followbutton&variant=2.0)
* Add us to your circles on [Google+](https://plus.google.com/110323587230527980117/posts)
## Read more
+19 -7
View File
@@ -1,8 +1,10 @@
'use strict';
var gulp = require('gulp');
var log = require('gulp-util').log;
var concat = require('gulp-concat');
var eslint = require('gulp-eslint');
var bower = require('bower');
var Dgeni = require('dgeni');
var merge = require('event-stream').merge;
var path = require('canonical-path');
@@ -16,6 +18,7 @@ var rename = require('gulp-rename');
// See clean and bower for async tasks, and see assets and doc-gen for dependent tasks below
var outputFolder = '../build/docs';
var bowerFolder = 'bower_components';
var src = 'app/src/**/*.js';
var ignoredFiles = '!src/angular.bind.js';
@@ -54,14 +57,24 @@ var getMergedEslintConfig = function(filepath) {
var copyComponent = function(component, pattern, sourceFolder, packageFile) {
pattern = pattern || '/**/*';
sourceFolder = sourceFolder || '../node_modules';
packageFile = packageFile || 'package.json';
sourceFolder = sourceFolder || bowerFolder;
packageFile = packageFile || 'bower.json';
var version = require(path.resolve(sourceFolder, component, packageFile)).version;
return gulp
.src(sourceFolder + '/' + component + pattern)
.pipe(gulp.dest(outputFolder + '/components/' + component + '-' + version));
};
gulp.task('bower', function() {
var bowerTask = bower.commands.install();
bowerTask.on('log', function(result) {
log('bower:', result.id, result.data.endpoint.name);
});
bowerTask.on('error', function(error) {
log(error);
});
return bowerTask;
});
gulp.task('build-app', function() {
var file = 'docs.js';
@@ -78,8 +91,7 @@ gulp.task('build-app', function() {
.pipe(gulp.dest(folder));
});
gulp.task('assets', function() {
gulp.task('assets', ['bower'], function() {
var JS_EXT = /\.js$/;
return merge(
gulp.src(['img/**/*']).pipe(gulp.dest(outputFolder + '/img')),
@@ -98,15 +110,15 @@ gulp.task('assets', function() {
})),
copyComponent('bootstrap', '/dist/**/*'),
copyComponent('open-sans-fontface'),
copyComponent('lunr', '/*.js'),
copyComponent('lunr.js', '/*.js'),
copyComponent('google-code-prettify'),
copyComponent('jquery', '/dist/*.js'),
copyComponent('marked', '/**/*.js')
copyComponent('marked', '/**/*.js', '../node_modules', 'package.json')
);
});
gulp.task('doc-gen', function() {
gulp.task('doc-gen', ['bower'], function() {
var dgeni = new Dgeni([require('./config')]);
return dgeni.generate().catch(function() {
process.exit(1);
+19 -19
View File
@@ -114,7 +114,7 @@ goog.i18n.currency.getGlobalCurrencyPattern = function(currencyCode) {
goog.i18n.currency.getGlobalCurrencySign = function(currencyCode) {
var info = goog.i18n.currency.CurrencyInfo[currencyCode];
return (currencyCode == info[1]) ? currencyCode :
currencyCode + ' ' + info[1];
currencyCode + ' ' + info[1];
};
@@ -210,13 +210,13 @@ goog.i18n.currency.getCurrencyPattern_ = function(patternNum, sign) {
}
}
if ((patternNum & goog.i18n.currency.POSITION_FLAG_) == 0) {
strParts.unshift(
(patternNum & goog.i18n.currency.SPACE_FLAG_) ? "' " : "'");
strParts.unshift((patternNum & goog.i18n.currency.SPACE_FLAG_) ?
"' " : "'");
strParts.unshift(sign);
strParts.unshift("'");
} else {
strParts.push(
(patternNum & goog.i18n.currency.SPACE_FLAG_) ? " '" : "'", sign, "'");
strParts.push((patternNum & goog.i18n.currency.SPACE_FLAG_) ? " '" : "'",
sign, "'");
}
return strParts.join('');
};
@@ -281,20 +281,20 @@ goog.i18n.currency.CurrencyInfo = {
'CHF': [2, 'CHF', 'CHF'],
'CLP': [0, '$', 'CL$'],
'CNY': [2, '¥', 'RMB¥'],
'COP': [32, '$', 'COL$'],
'COP': [0, '$', 'COL$'],
'CRC': [0, '\u20a1', 'CR\u20a1'],
'CZK': [50, 'K\u010d', 'K\u010d'],
'DKK': [50, 'kr.', 'kr.'],
'DOP': [2, 'RD$', 'RD$'],
'DKK': [18, 'kr', 'kr'],
'DOP': [2, '$', 'RD$'],
'EGP': [2, '£', 'LE'],
'ETB': [2, 'Birr', 'Birr'],
'EUR': [2, '€', '€'],
'GBP': [2, '£', 'GB£'],
'HKD': [2, '$', 'HK$'],
'HRK': [2, 'kn', 'kn'],
'HUF': [34, 'Ft', 'Ft'],
'HUF': [0, 'Ft', 'Ft'],
'IDR': [0, 'Rp', 'Rp'],
'ILS': [34, '\u20AA', 'IL\u20AA'],
'ILS': [2, '\u20AA', 'IL\u20AA'],
'INR': [2, '\u20B9', 'Rs'],
'IRR': [0, 'Rial', 'IRR'],
'ISK': [0, 'kr', 'kr'],
@@ -315,18 +315,18 @@ goog.i18n.currency.CurrencyInfo = {
'PLN': [50, 'z\u0142', 'z\u0142'],
'RON': [2, 'RON', 'RON'],
'RSD': [0, 'din', 'RSD'],
'RUB': [50, '\u20bd', 'RUB'],
'RUB': [50, 'руб.', 'руб.'],
'SAR': [2, 'Rial', 'Rial'],
'SEK': [50, 'kr', 'kr'],
'SEK': [2, 'kr', 'kr'],
'SGD': [2, '$', 'S$'],
'THB': [2, '\u0e3f', 'THB'],
'TRY': [2, 'TL', 'YTL'],
'TWD': [2, 'NT$', 'NT$'],
'TZS': [0, 'TSh', 'TSh'],
'UAH': [2, 'грн.', 'UAH'],
'UAH': [2, '\u20B4', 'UAH'],
'USD': [2, '$', 'US$'],
'UYU': [2, '$', '$U'],
'VND': [48, '\u20AB', 'VN\u20AB'],
'VND': [0, '\u20AB', 'VN\u20AB'],
'YER': [0, 'Rial', 'Rial'],
'ZAR': [2, 'R', 'ZAR']
};
@@ -338,12 +338,12 @@ goog.i18n.currency.CurrencyInfo = {
*/
goog.i18n.currency.CurrencyInfoTier2 = {
'AFN': [48, 'Af.', 'AFN'],
'AMD': [32, 'Dram', 'dram'],
'AMD': [0, 'Dram', 'dram'],
'ANG': [2, 'NAf.', 'ANG'],
'AOA': [2, 'Kz', 'Kz'],
'ARS': [34, '$', 'AR$'],
'ARS': [2, '$', 'AR$'],
'AWG': [2, 'Afl.', 'Afl.'],
'AZN': [34, '\u20bc', 'AZN'],
'AZN': [2, 'man.', 'man.'],
'BAM': [2, 'KM', 'KM'],
'BBD': [2, '$', 'Bds$'],
'BHD': [3, 'din', 'din'],
@@ -354,7 +354,7 @@ goog.i18n.currency.CurrencyInfoTier2 = {
'BSD': [2, '$', 'BS$'],
'BTN': [2, 'Nu.', 'Nu.'],
'BWP': [2, 'P', 'pula'],
'BYR': [48, 'p.', 'BYR'],
'BYR': [0, 'BYR', 'BYR'],
'BZD': [2, '$', 'BZ$'],
'CUC': [1, '$', 'CUC$'],
'CUP': [2, '$', 'CU$'],
@@ -405,7 +405,7 @@ goog.i18n.currency.CurrencyInfoTier2 = {
'NZD': [2, '$', 'NZ$'],
'OMR': [3, 'Rial', 'OMR'],
'PGK': [2, 'PGK', 'PGK'],
'PYG': [16, 'Gs.', 'PYG'],
'PYG': [0, 'Gs', 'PYG'],
'QAR': [2, 'Rial', 'QR'],
'RWF': [0, 'RF', 'RF'],
'SBD': [2, '$', 'SI$'],
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+80 -57
View File
@@ -18,7 +18,7 @@
* This file is autogenerated by script:
* http://go/generate_number_constants.py
* using the --for_closure flag.
* File generated from CLDR ver. 29
* File generated from CLDR ver. 27.0.1
*
* To reduce the file size (which may cause issues in some JS
* developing environments), this file will only contain locales
@@ -34,7 +34,6 @@
* removed after those changes land to CLDR.
*/
// clang-format off
goog.provide('goog.i18n.NumberFormatSymbols');
goog.provide('goog.i18n.NumberFormatSymbols_af');
goog.provide('goog.i18n.NumberFormatSymbols_af_ZA');
@@ -43,7 +42,6 @@ goog.provide('goog.i18n.NumberFormatSymbols_am_ET');
goog.provide('goog.i18n.NumberFormatSymbols_ar');
goog.provide('goog.i18n.NumberFormatSymbols_ar_001');
goog.provide('goog.i18n.NumberFormatSymbols_ar_EG');
goog.provide('goog.i18n.NumberFormatSymbols_ar_XB');
goog.provide('goog.i18n.NumberFormatSymbols_az');
goog.provide('goog.i18n.NumberFormatSymbols_az_Latn');
goog.provide('goog.i18n.NumberFormatSymbols_az_Latn_AZ');
@@ -104,7 +102,6 @@ goog.provide('goog.i18n.NumberFormatSymbols_en_UM');
goog.provide('goog.i18n.NumberFormatSymbols_en_US');
goog.provide('goog.i18n.NumberFormatSymbols_en_VG');
goog.provide('goog.i18n.NumberFormatSymbols_en_VI');
goog.provide('goog.i18n.NumberFormatSymbols_en_XA');
goog.provide('goog.i18n.NumberFormatSymbols_en_ZA');
goog.provide('goog.i18n.NumberFormatSymbols_en_ZW');
goog.provide('goog.i18n.NumberFormatSymbols_es');
@@ -171,7 +168,8 @@ goog.provide('goog.i18n.NumberFormatSymbols_ja_JP');
goog.provide('goog.i18n.NumberFormatSymbols_ka');
goog.provide('goog.i18n.NumberFormatSymbols_ka_GE');
goog.provide('goog.i18n.NumberFormatSymbols_kk');
goog.provide('goog.i18n.NumberFormatSymbols_kk_KZ');
goog.provide('goog.i18n.NumberFormatSymbols_kk_Cyrl');
goog.provide('goog.i18n.NumberFormatSymbols_kk_Cyrl_KZ');
goog.provide('goog.i18n.NumberFormatSymbols_km');
goog.provide('goog.i18n.NumberFormatSymbols_km_KH');
goog.provide('goog.i18n.NumberFormatSymbols_kn');
@@ -179,7 +177,8 @@ goog.provide('goog.i18n.NumberFormatSymbols_kn_IN');
goog.provide('goog.i18n.NumberFormatSymbols_ko');
goog.provide('goog.i18n.NumberFormatSymbols_ko_KR');
goog.provide('goog.i18n.NumberFormatSymbols_ky');
goog.provide('goog.i18n.NumberFormatSymbols_ky_KG');
goog.provide('goog.i18n.NumberFormatSymbols_ky_Cyrl');
goog.provide('goog.i18n.NumberFormatSymbols_ky_Cyrl_KG');
goog.provide('goog.i18n.NumberFormatSymbols_ln');
goog.provide('goog.i18n.NumberFormatSymbols_ln_CD');
goog.provide('goog.i18n.NumberFormatSymbols_lo');
@@ -193,11 +192,13 @@ goog.provide('goog.i18n.NumberFormatSymbols_mk_MK');
goog.provide('goog.i18n.NumberFormatSymbols_ml');
goog.provide('goog.i18n.NumberFormatSymbols_ml_IN');
goog.provide('goog.i18n.NumberFormatSymbols_mn');
goog.provide('goog.i18n.NumberFormatSymbols_mn_MN');
goog.provide('goog.i18n.NumberFormatSymbols_mn_Cyrl');
goog.provide('goog.i18n.NumberFormatSymbols_mn_Cyrl_MN');
goog.provide('goog.i18n.NumberFormatSymbols_mr');
goog.provide('goog.i18n.NumberFormatSymbols_mr_IN');
goog.provide('goog.i18n.NumberFormatSymbols_ms');
goog.provide('goog.i18n.NumberFormatSymbols_ms_MY');
goog.provide('goog.i18n.NumberFormatSymbols_ms_Latn');
goog.provide('goog.i18n.NumberFormatSymbols_ms_Latn_MY');
goog.provide('goog.i18n.NumberFormatSymbols_mt');
goog.provide('goog.i18n.NumberFormatSymbols_mt_MT');
goog.provide('goog.i18n.NumberFormatSymbols_my');
@@ -367,13 +368,6 @@ goog.i18n.NumberFormatSymbols_ar_001 = goog.i18n.NumberFormatSymbols_ar;
goog.i18n.NumberFormatSymbols_ar_EG = goog.i18n.NumberFormatSymbols_ar;
/**
* Number formatting symbols for locale ar_XB.
* @enum {string}
*/
goog.i18n.NumberFormatSymbols_ar_XB = goog.i18n.NumberFormatSymbols_ar;
/**
* Number formatting symbols for locale az.
* @enum {string}
@@ -428,8 +422,8 @@ goog.i18n.NumberFormatSymbols_be = {
NAN: 'NaN',
DECIMAL_PATTERN: '#,##0.###',
SCIENTIFIC_PATTERN: '#E0',
PERCENT_PATTERN: '#,##0\u00A0%',
CURRENCY_PATTERN: '#,##0.00\u00A0\u00A4',
PERCENT_PATTERN: '#,##0%',
CURRENCY_PATTERN: '\u00A4#,##0.00',
DEF_CURRENCY_CODE: 'BYR'
};
@@ -782,7 +776,7 @@ goog.i18n.NumberFormatSymbols_de = {
*/
goog.i18n.NumberFormatSymbols_de_AT = {
DECIMAL_SEP: ',',
GROUP_SEP: '\u00A0',
GROUP_SEP: '.',
PERCENT: '%',
ZERO_DIGIT: '0',
PLUS_SIGN: '+',
@@ -823,7 +817,7 @@ goog.i18n.NumberFormatSymbols_de_CH = {
NAN: 'NaN',
DECIMAL_PATTERN: '#,##0.###',
SCIENTIFIC_PATTERN: '#E0',
PERCENT_PATTERN: '#,##0%',
PERCENT_PATTERN: '#,##0\u00A0%',
CURRENCY_PATTERN: '\u00A4\u00A0#,##0.00;\u00A4-#,##0.00',
DEF_CURRENCY_CODE: 'CHF'
};
@@ -928,7 +922,7 @@ goog.i18n.NumberFormatSymbols_en_AU = {
ZERO_DIGIT: '0',
PLUS_SIGN: '+',
MINUS_SIGN: '-',
EXP_SYMBOL: 'e',
EXP_SYMBOL: 'E',
PERMILL: '\u2030',
INFINITY: '\u221E',
NAN: 'NaN',
@@ -1146,13 +1140,6 @@ goog.i18n.NumberFormatSymbols_en_VG = goog.i18n.NumberFormatSymbols_en;
goog.i18n.NumberFormatSymbols_en_VI = goog.i18n.NumberFormatSymbols_en;
/**
* Number formatting symbols for locale en_XA.
* @enum {string}
*/
goog.i18n.NumberFormatSymbols_en_XA = goog.i18n.NumberFormatSymbols_en;
/**
* Number formatting symbols for locale en_ZA.
* @enum {string}
@@ -1306,7 +1293,7 @@ goog.i18n.NumberFormatSymbols_et = {
PERCENT: '%',
ZERO_DIGIT: '0',
PLUS_SIGN: '+',
MINUS_SIGN: '\u2212',
MINUS_SIGN: '-',
EXP_SYMBOL: '\u00D710^',
PERMILL: '\u2030',
INFINITY: '\u221E',
@@ -1610,7 +1597,7 @@ goog.i18n.NumberFormatSymbols_gl = {
DECIMAL_PATTERN: '#,##0.###',
SCIENTIFIC_PATTERN: '#E0',
PERCENT_PATTERN: '#,##0%',
CURRENCY_PATTERN: '#,##0.00\u00A0\u00A4',
CURRENCY_PATTERN: '\u00A4#,##0.00',
DEF_CURRENCY_CODE: 'EUR'
};
@@ -1856,8 +1843,8 @@ goog.i18n.NumberFormatSymbols_hy = {
NAN: 'NaN',
DECIMAL_PATTERN: '#0.###',
SCIENTIFIC_PATTERN: '#E0',
PERCENT_PATTERN: '#,##0%',
CURRENCY_PATTERN: '\u00A4\u00A0#,##0.00',
PERCENT_PATTERN: '#0%',
CURRENCY_PATTERN: '#0.00\u00A0\u00A4',
DEF_CURRENCY_CODE: 'AMD'
};
@@ -2097,10 +2084,17 @@ goog.i18n.NumberFormatSymbols_kk = {
/**
* Number formatting symbols for locale kk_KZ.
* Number formatting symbols for locale kk_Cyrl.
* @enum {string}
*/
goog.i18n.NumberFormatSymbols_kk_KZ = goog.i18n.NumberFormatSymbols_kk;
goog.i18n.NumberFormatSymbols_kk_Cyrl = goog.i18n.NumberFormatSymbols_kk;
/**
* Number formatting symbols for locale kk_Cyrl_KZ.
* @enum {string}
*/
goog.i18n.NumberFormatSymbols_kk_Cyrl_KZ = goog.i18n.NumberFormatSymbols_kk;
/**
@@ -2217,10 +2211,17 @@ goog.i18n.NumberFormatSymbols_ky = {
/**
* Number formatting symbols for locale ky_KG.
* Number formatting symbols for locale ky_Cyrl.
* @enum {string}
*/
goog.i18n.NumberFormatSymbols_ky_KG = goog.i18n.NumberFormatSymbols_ky;
goog.i18n.NumberFormatSymbols_ky_Cyrl = goog.i18n.NumberFormatSymbols_ky;
/**
* Number formatting symbols for locale ky_Cyrl_KG.
* @enum {string}
*/
goog.i18n.NumberFormatSymbols_ky_Cyrl_KG = goog.i18n.NumberFormatSymbols_ky;
/**
@@ -2332,7 +2333,7 @@ goog.i18n.NumberFormatSymbols_lv = {
DECIMAL_PATTERN: '#,##0.###',
SCIENTIFIC_PATTERN: '#E0',
PERCENT_PATTERN: '#,##0%',
CURRENCY_PATTERN: '#0.00\u00A0\u00A4',
CURRENCY_PATTERN: '\u00A4#0.00',
DEF_CURRENCY_CODE: 'EUR'
};
@@ -2428,10 +2429,17 @@ goog.i18n.NumberFormatSymbols_mn = {
/**
* Number formatting symbols for locale mn_MN.
* Number formatting symbols for locale mn_Cyrl.
* @enum {string}
*/
goog.i18n.NumberFormatSymbols_mn_MN = goog.i18n.NumberFormatSymbols_mn;
goog.i18n.NumberFormatSymbols_mn_Cyrl = goog.i18n.NumberFormatSymbols_mn;
/**
* Number formatting symbols for locale mn_Cyrl_MN.
* @enum {string}
*/
goog.i18n.NumberFormatSymbols_mn_Cyrl_MN = goog.i18n.NumberFormatSymbols_mn;
/**
@@ -2488,10 +2496,17 @@ goog.i18n.NumberFormatSymbols_ms = {
/**
* Number formatting symbols for locale ms_MY.
* Number formatting symbols for locale ms_Latn.
* @enum {string}
*/
goog.i18n.NumberFormatSymbols_ms_MY = goog.i18n.NumberFormatSymbols_ms;
goog.i18n.NumberFormatSymbols_ms_Latn = goog.i18n.NumberFormatSymbols_ms;
/**
* Number formatting symbols for locale ms_Latn_MY.
* @enum {string}
*/
goog.i18n.NumberFormatSymbols_ms_Latn_MY = goog.i18n.NumberFormatSymbols_ms;
/**
@@ -3297,7 +3312,7 @@ goog.i18n.NumberFormatSymbols_uk = {
EXP_SYMBOL: '\u0415',
PERMILL: '\u2030',
INFINITY: '\u221E',
NAN: 'NaN',
NAN: '\u041D\u0435\u00A0\u0447\u0438\u0441\u043B\u043E',
DECIMAL_PATTERN: '#,##0.###',
SCIENTIFIC_PATTERN: '#E0',
PERCENT_PATTERN: '#,##0%',
@@ -3357,7 +3372,7 @@ goog.i18n.NumberFormatSymbols_uz = {
EXP_SYMBOL: 'E',
PERMILL: '\u2030',
INFINITY: '\u221E',
NAN: 'haqiqiy\u00A0son\u00A0emas',
NAN: 'NaN',
DECIMAL_PATTERN: '#,##0.###',
SCIENTIFIC_PATTERN: '#E0',
PERCENT_PATTERN: '#,##0%',
@@ -3398,7 +3413,7 @@ goog.i18n.NumberFormatSymbols_vi = {
DECIMAL_PATTERN: '#,##0.###',
SCIENTIFIC_PATTERN: '#E0',
PERCENT_PATTERN: '#,##0%',
CURRENCY_PATTERN: '\u00A4\u00A0#,##0.00',
CURRENCY_PATTERN: '#,##0.00\u00A0\u00A4',
DEF_CURRENCY_CODE: 'VND'
};
@@ -3428,7 +3443,7 @@ goog.i18n.NumberFormatSymbols_zh = {
DECIMAL_PATTERN: '#,##0.###',
SCIENTIFIC_PATTERN: '#E0',
PERCENT_PATTERN: '#,##0%',
CURRENCY_PATTERN: '\u00A4#,##0.00',
CURRENCY_PATTERN: '\u00A4\u00A0#,##0.00',
DEF_CURRENCY_CODE: 'CNY'
};
@@ -3514,7 +3529,7 @@ goog.i18n.NumberFormatSymbols_zu = {
EXP_SYMBOL: 'E',
PERMILL: '\u2030',
INFINITY: '\u221E',
NAN: 'NaN',
NAN: 'I-NaN',
DECIMAL_PATTERN: '#,##0.###',
SCIENTIFIC_PATTERN: '#E0',
PERCENT_PATTERN: '#,##0%',
@@ -3563,10 +3578,6 @@ if (goog.LOCALE == 'ar_EG' || goog.LOCALE == 'ar-EG') {
goog.i18n.NumberFormatSymbols = goog.i18n.NumberFormatSymbols_ar;
}
if (goog.LOCALE == 'ar_XB' || goog.LOCALE == 'ar-XB') {
goog.i18n.NumberFormatSymbols = goog.i18n.NumberFormatSymbols_ar;
}
if (goog.LOCALE == 'az') {
goog.i18n.NumberFormatSymbols = goog.i18n.NumberFormatSymbols_az;
}
@@ -3807,10 +3818,6 @@ if (goog.LOCALE == 'en_VI' || goog.LOCALE == 'en-VI') {
goog.i18n.NumberFormatSymbols = goog.i18n.NumberFormatSymbols_en;
}
if (goog.LOCALE == 'en_XA' || goog.LOCALE == 'en-XA') {
goog.i18n.NumberFormatSymbols = goog.i18n.NumberFormatSymbols_en;
}
if (goog.LOCALE == 'en_ZA' || goog.LOCALE == 'en-ZA') {
goog.i18n.NumberFormatSymbols = goog.i18n.NumberFormatSymbols_en_ZA;
}
@@ -4075,7 +4082,11 @@ if (goog.LOCALE == 'kk') {
goog.i18n.NumberFormatSymbols = goog.i18n.NumberFormatSymbols_kk;
}
if (goog.LOCALE == 'kk_KZ' || goog.LOCALE == 'kk-KZ') {
if (goog.LOCALE == 'kk_Cyrl' || goog.LOCALE == 'kk-Cyrl') {
goog.i18n.NumberFormatSymbols = goog.i18n.NumberFormatSymbols_kk;
}
if (goog.LOCALE == 'kk_Cyrl_KZ' || goog.LOCALE == 'kk-Cyrl-KZ') {
goog.i18n.NumberFormatSymbols = goog.i18n.NumberFormatSymbols_kk;
}
@@ -4107,7 +4118,11 @@ if (goog.LOCALE == 'ky') {
goog.i18n.NumberFormatSymbols = goog.i18n.NumberFormatSymbols_ky;
}
if (goog.LOCALE == 'ky_KG' || goog.LOCALE == 'ky-KG') {
if (goog.LOCALE == 'ky_Cyrl' || goog.LOCALE == 'ky-Cyrl') {
goog.i18n.NumberFormatSymbols = goog.i18n.NumberFormatSymbols_ky;
}
if (goog.LOCALE == 'ky_Cyrl_KG' || goog.LOCALE == 'ky-Cyrl-KG') {
goog.i18n.NumberFormatSymbols = goog.i18n.NumberFormatSymbols_ky;
}
@@ -4163,7 +4178,11 @@ if (goog.LOCALE == 'mn') {
goog.i18n.NumberFormatSymbols = goog.i18n.NumberFormatSymbols_mn;
}
if (goog.LOCALE == 'mn_MN' || goog.LOCALE == 'mn-MN') {
if (goog.LOCALE == 'mn_Cyrl' || goog.LOCALE == 'mn-Cyrl') {
goog.i18n.NumberFormatSymbols = goog.i18n.NumberFormatSymbols_mn;
}
if (goog.LOCALE == 'mn_Cyrl_MN' || goog.LOCALE == 'mn-Cyrl-MN') {
goog.i18n.NumberFormatSymbols = goog.i18n.NumberFormatSymbols_mn;
}
@@ -4179,7 +4198,11 @@ if (goog.LOCALE == 'ms') {
goog.i18n.NumberFormatSymbols = goog.i18n.NumberFormatSymbols_ms;
}
if (goog.LOCALE == 'ms_MY' || goog.LOCALE == 'ms-MY') {
if (goog.LOCALE == 'ms_Latn' || goog.LOCALE == 'ms-Latn') {
goog.i18n.NumberFormatSymbols = goog.i18n.NumberFormatSymbols_ms;
}
if (goog.LOCALE == 'ms_Latn_MY' || goog.LOCALE == 'ms-Latn-MY') {
goog.i18n.NumberFormatSymbols = goog.i18n.NumberFormatSymbols_ms;
}
File diff suppressed because it is too large Load Diff
+358 -360
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. 27.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
@@ -25,8 +25,6 @@
* CLDR.
*/
// clang-format off
goog.provide('goog.i18n.pluralRules');
/**
* Plural pattern keyword
@@ -71,7 +69,7 @@ goog.i18n.pluralRules.decimals_ = function(n) {
* (http://unicode.org/reports/tr35/tr35-numbers.html#Plural_rules_syntax)
* @param {number} n The count of items.
* @param {number=} opt_precision optional, precision.
* @return {!{v:number, f:number}} The v and f.
* @return {!Object} The v and f.
* @private
*/
goog.i18n.pluralRules.get_vf_ = function(n, opt_precision) {
@@ -95,7 +93,7 @@ goog.i18n.pluralRules.get_vf_ = function(n, opt_precision) {
* (http://unicode.org/reports/tr35/tr35-numbers.html#Plural_rules_syntax)
* @param {number} v Calculated previously.
* @param {number} f Calculated previously.
* @return {!{w:number, t:number}} The w and t.
* @return {!Object} The w and t.
* @private
*/
goog.i18n.pluralRules.get_wt_ = function(v, f) {
@@ -112,82 +110,29 @@ goog.i18n.pluralRules.get_wt_ = function(v, f) {
};
/**
* Plural select rules for fil locale
* Plural select rules for ga 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.filSelect_ = function(n, opt_precision) {
var i = n | 0;
var vf = goog.i18n.pluralRules.get_vf_(n, opt_precision);
if (vf.v == 0 && (i == 1 || i == 2 || i == 3) || vf.v == 0 && i % 10 != 4 && i % 10 != 6 && i % 10 != 9 || vf.v != 0 && vf.f % 10 != 4 && vf.f % 10 != 6 && vf.f % 10 != 9) {
goog.i18n.pluralRules.gaSelect_ = function(n, opt_precision) {
if (n == 1) {
return goog.i18n.pluralRules.Keyword.ONE;
}
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
*
* @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.brSelect_ = function(n, opt_precision) {
if (n % 10 == 1 && n % 100 != 11 && n % 100 != 71 && n % 100 != 91) {
return goog.i18n.pluralRules.Keyword.ONE;
}
if (n % 10 == 2 && n % 100 != 12 && n % 100 != 72 && n % 100 != 92) {
if (n == 2) {
return goog.i18n.pluralRules.Keyword.TWO;
}
if ((n % 10 >= 3 && n % 10 <= 4 || n % 10 == 9) && (n % 100 < 10 || n % 100 > 19) && (n % 100 < 70 || n % 100 > 79) && (n % 100 < 90 || n % 100 > 99)) {
if (n >= 3 && n <= 6) {
return goog.i18n.pluralRules.Keyword.FEW;
}
if (n != 0 && n % 1000000 == 0) {
if (n >= 7 && n <= 10) {
return goog.i18n.pluralRules.Keyword.MANY;
}
return goog.i18n.pluralRules.Keyword.OTHER;
};
/**
* Plural select rules for sr 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.srSelect_ = function(n, opt_precision) {
var i = n | 0;
var vf = goog.i18n.pluralRules.get_vf_(n, opt_precision);
if (vf.v == 0 && i % 10 == 1 && i % 100 != 11 || vf.f % 10 == 1 && vf.f % 100 != 11) {
return goog.i18n.pluralRules.Keyword.ONE;
}
if (vf.v == 0 && i % 10 >= 2 && i % 10 <= 4 && (i % 100 < 12 || i % 100 > 14) || vf.f % 10 >= 2 && vf.f % 10 <= 4 && (vf.f % 100 < 12 || vf.f % 100 > 14)) {
return goog.i18n.pluralRules.Keyword.FEW;
}
return goog.i18n.pluralRules.Keyword.OTHER;
};
/**
* Plural select rules for ro locale
*
@@ -209,16 +154,17 @@ goog.i18n.pluralRules.roSelect_ = function(n, opt_precision) {
};
/**
* Plural select rules for hi locale
* Plural select rules for fil 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.hiSelect_ = function(n, opt_precision) {
goog.i18n.pluralRules.filSelect_ = function(n, opt_precision) {
var i = n | 0;
if (i == 0 || n == 1) {
var vf = goog.i18n.pluralRules.get_vf_(n, opt_precision);
if (vf.v == 0 && (i == 1 || i == 2 || i == 3) || vf.v == 0 && i % 10 != 4 && i % 10 != 6 && i % 10 != 9 || vf.v != 0 && vf.f % 10 != 4 && vf.f % 10 != 6 && vf.f % 10 != 9) {
return goog.i18n.pluralRules.Keyword.ONE;
}
return goog.i18n.pluralRules.Keyword.OTHER;
@@ -241,127 +187,19 @@ goog.i18n.pluralRules.frSelect_ = function(n, opt_precision) {
};
/**
* Plural select rules for cs locale
* Plural select rules for en 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.csSelect_ = function(n, opt_precision) {
goog.i18n.pluralRules.enSelect_ = function(n, opt_precision) {
var i = n | 0;
var vf = goog.i18n.pluralRules.get_vf_(n, opt_precision);
if (i == 1 && vf.v == 0) {
return goog.i18n.pluralRules.Keyword.ONE;
}
if (i >= 2 && i <= 4 && vf.v == 0) {
return goog.i18n.pluralRules.Keyword.FEW;
}
if (vf.v != 0) {
return goog.i18n.pluralRules.Keyword.MANY;
}
return goog.i18n.pluralRules.Keyword.OTHER;
};
/**
* Plural select rules for pl 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.plSelect_ = function(n, opt_precision) {
var i = n | 0;
var vf = goog.i18n.pluralRules.get_vf_(n, opt_precision);
if (i == 1 && vf.v == 0) {
return goog.i18n.pluralRules.Keyword.ONE;
}
if (vf.v == 0 && i % 10 >= 2 && i % 10 <= 4 && (i % 100 < 12 || i % 100 > 14)) {
return goog.i18n.pluralRules.Keyword.FEW;
}
if (vf.v == 0 && i != 1 && i % 10 >= 0 && i % 10 <= 1 || vf.v == 0 && i % 10 >= 5 && i % 10 <= 9 || vf.v == 0 && i % 100 >= 12 && i % 100 <= 14) {
return goog.i18n.pluralRules.Keyword.MANY;
}
return goog.i18n.pluralRules.Keyword.OTHER;
};
/**
* Plural select rules for shi 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.shiSelect_ = function(n, opt_precision) {
var i = n | 0;
if (i == 0 || n == 1) {
return goog.i18n.pluralRules.Keyword.ONE;
}
if (n >= 2 && n <= 10) {
return goog.i18n.pluralRules.Keyword.FEW;
}
return goog.i18n.pluralRules.Keyword.OTHER;
};
/**
* Plural select rules for lv 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.lvSelect_ = function(n, opt_precision) {
var vf = goog.i18n.pluralRules.get_vf_(n, opt_precision);
if (n % 10 == 0 || n % 100 >= 11 && n % 100 <= 19 || vf.v == 2 && vf.f % 100 >= 11 && vf.f % 100 <= 19) {
return goog.i18n.pluralRules.Keyword.ZERO;
}
if (n % 10 == 1 && n % 100 != 11 || vf.v == 2 && vf.f % 10 == 1 && vf.f % 100 != 11 || vf.v != 2 && vf.f % 10 == 1) {
return goog.i18n.pluralRules.Keyword.ONE;
}
return goog.i18n.pluralRules.Keyword.OTHER;
};
/**
* Plural select rules for iu 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.iuSelect_ = function(n, opt_precision) {
if (n == 1) {
return goog.i18n.pluralRules.Keyword.ONE;
}
if (n == 2) {
return goog.i18n.pluralRules.Keyword.TWO;
}
return goog.i18n.pluralRules.Keyword.OTHER;
};
/**
* Plural select rules for he 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.heSelect_ = function(n, opt_precision) {
var i = n | 0;
var vf = goog.i18n.pluralRules.get_vf_(n, opt_precision);
if (i == 1 && vf.v == 0) {
return goog.i18n.pluralRules.Keyword.ONE;
}
if (i == 2 && vf.v == 0) {
return goog.i18n.pluralRules.Keyword.TWO;
}
if (vf.v == 0 && (n < 0 || n > 10) && n % 10 == 0) {
return goog.i18n.pluralRules.Keyword.MANY;
}
return goog.i18n.pluralRules.Keyword.OTHER;
};
@@ -387,22 +225,49 @@ goog.i18n.pluralRules.mtSelect_ = function(n, opt_precision) {
};
/**
* Plural select rules for si locale
* Plural select rules for da 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.siSelect_ = function(n, opt_precision) {
goog.i18n.pluralRules.daSelect_ = function(n, opt_precision) {
var i = n | 0;
var vf = goog.i18n.pluralRules.get_vf_(n, opt_precision);
if ((n == 0 || n == 1) || i == 0 && vf.f == 1) {
var wt = goog.i18n.pluralRules.get_wt_(vf.v, vf.f);
if (n == 1 || wt.t != 0 && (i == 0 || i == 1)) {
return goog.i18n.pluralRules.Keyword.ONE;
}
return goog.i18n.pluralRules.Keyword.OTHER;
};
/**
* Plural select rules for gv 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.gvSelect_ = function(n, opt_precision) {
var i = n | 0;
var vf = goog.i18n.pluralRules.get_vf_(n, opt_precision);
if (vf.v == 0 && i % 10 == 1) {
return goog.i18n.pluralRules.Keyword.ONE;
}
if (vf.v == 0 && i % 10 == 2) {
return goog.i18n.pluralRules.Keyword.TWO;
}
if (vf.v == 0 && (i % 100 == 0 || i % 100 == 20 || i % 100 == 40 || i % 100 == 60 || i % 100 == 80)) {
return goog.i18n.pluralRules.Keyword.FEW;
}
if (vf.v != 0) {
return goog.i18n.pluralRules.Keyword.MANY;
}
return goog.i18n.pluralRules.Keyword.OTHER;
};
/**
* Plural select rules for cy locale
*
@@ -431,89 +296,115 @@ goog.i18n.pluralRules.cySelect_ = function(n, opt_precision) {
};
/**
* Plural select rules for da locale
* Plural select rules for br 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.daSelect_ = function(n, opt_precision) {
var i = n | 0;
var vf = goog.i18n.pluralRules.get_vf_(n, opt_precision);
var wt = goog.i18n.pluralRules.get_wt_(vf.v, vf.f);
if (n == 1 || wt.t != 0 && (i == 0 || i == 1)) {
goog.i18n.pluralRules.brSelect_ = function(n, opt_precision) {
if (n % 10 == 1 && n % 100 != 11 && n % 100 != 71 && n % 100 != 91) {
return goog.i18n.pluralRules.Keyword.ONE;
}
return goog.i18n.pluralRules.Keyword.OTHER;
};
/**
* Plural select rules for ru 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.ruSelect_ = function(n, opt_precision) {
var i = n | 0;
var vf = goog.i18n.pluralRules.get_vf_(n, opt_precision);
if (vf.v == 0 && i % 10 == 1 && i % 100 != 11) {
return goog.i18n.pluralRules.Keyword.ONE;
}
if (vf.v == 0 && i % 10 >= 2 && i % 10 <= 4 && (i % 100 < 12 || i % 100 > 14)) {
return goog.i18n.pluralRules.Keyword.FEW;
}
if (vf.v == 0 && i % 10 == 0 || vf.v == 0 && i % 10 >= 5 && i % 10 <= 9 || vf.v == 0 && i % 100 >= 11 && i % 100 <= 14) {
return goog.i18n.pluralRules.Keyword.MANY;
}
return goog.i18n.pluralRules.Keyword.OTHER;
};
/**
* Plural select rules for gv 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.gvSelect_ = function(n, opt_precision) {
var i = n | 0;
var vf = goog.i18n.pluralRules.get_vf_(n, opt_precision);
if (vf.v == 0 && i % 10 == 1) {
return goog.i18n.pluralRules.Keyword.ONE;
}
if (vf.v == 0 && i % 10 == 2) {
if (n % 10 == 2 && n % 100 != 12 && n % 100 != 72 && n % 100 != 92) {
return goog.i18n.pluralRules.Keyword.TWO;
}
if (vf.v == 0 && (i % 100 == 0 || i % 100 == 20 || i % 100 == 40 || i % 100 == 60 || i % 100 == 80)) {
if ((n % 10 >= 3 && n % 10 <= 4 || n % 10 == 9) && (n % 100 < 10 || n % 100 > 19) && (n % 100 < 70 || n % 100 > 79) && (n % 100 < 90 || n % 100 > 99)) {
return goog.i18n.pluralRules.Keyword.FEW;
}
if (vf.v != 0) {
if (n != 0 && n % 1000000 == 0) {
return goog.i18n.pluralRules.Keyword.MANY;
}
return goog.i18n.pluralRules.Keyword.OTHER;
};
/**
* Plural select rules for be locale
* Plural select rules for es 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.beSelect_ = function(n, opt_precision) {
if (n % 10 == 1 && n % 100 != 11) {
goog.i18n.pluralRules.esSelect_ = function(n, opt_precision) {
if (n == 1) {
return goog.i18n.pluralRules.Keyword.ONE;
}
if (n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 12 || n % 100 > 14)) {
return goog.i18n.pluralRules.Keyword.OTHER;
};
/**
* Plural select rules for si 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.siSelect_ = function(n, opt_precision) {
var i = n | 0;
var vf = goog.i18n.pluralRules.get_vf_(n, opt_precision);
if ((n == 0 || n == 1) || i == 0 && vf.f == 1) {
return goog.i18n.pluralRules.Keyword.ONE;
}
return goog.i18n.pluralRules.Keyword.OTHER;
};
/**
* Plural select rules for sl 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.slSelect_ = function(n, opt_precision) {
var i = n | 0;
var vf = goog.i18n.pluralRules.get_vf_(n, opt_precision);
if (vf.v == 0 && i % 100 == 1) {
return goog.i18n.pluralRules.Keyword.ONE;
}
if (vf.v == 0 && i % 100 == 2) {
return goog.i18n.pluralRules.Keyword.TWO;
}
if (vf.v == 0 && i % 100 >= 3 && i % 100 <= 4 || vf.v != 0) {
return goog.i18n.pluralRules.Keyword.FEW;
}
if (n % 10 == 0 || n % 10 >= 5 && n % 10 <= 9 || n % 100 >= 11 && n % 100 <= 14) {
return goog.i18n.pluralRules.Keyword.MANY;
return goog.i18n.pluralRules.Keyword.OTHER;
};
/**
* Plural select rules for tzm 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.tzmSelect_ = function(n, opt_precision) {
if (n >= 0 && n <= 1 || n >= 11 && n <= 99) {
return goog.i18n.pluralRules.Keyword.ONE;
}
return goog.i18n.pluralRules.Keyword.OTHER;
};
/**
* Plural select rules for sr 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.srSelect_ = function(n, opt_precision) {
var i = n | 0;
var vf = goog.i18n.pluralRules.get_vf_(n, opt_precision);
if (vf.v == 0 && i % 10 == 1 && i % 100 != 11 || vf.f % 10 == 1 && vf.f % 100 != 11) {
return goog.i18n.pluralRules.Keyword.ONE;
}
if (vf.v == 0 && i % 10 >= 2 && i % 10 <= 4 && (i % 100 < 12 || i % 100 > 14) || vf.f % 10 >= 2 && vf.f % 10 <= 4 && (vf.f % 100 < 12 || vf.f % 100 > 14)) {
return goog.i18n.pluralRules.Keyword.FEW;
}
return goog.i18n.pluralRules.Keyword.OTHER;
};
@@ -536,26 +427,18 @@ goog.i18n.pluralRules.mkSelect_ = function(n, opt_precision) {
};
/**
* Plural select rules for ga locale
* Plural select rules for hi 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.gaSelect_ = function(n, opt_precision) {
if (n == 1) {
goog.i18n.pluralRules.hiSelect_ = function(n, opt_precision) {
var i = n | 0;
if (i == 0 || n == 1) {
return goog.i18n.pluralRules.Keyword.ONE;
}
if (n == 2) {
return goog.i18n.pluralRules.Keyword.TWO;
}
if (n >= 3 && n <= 6) {
return goog.i18n.pluralRules.Keyword.FEW;
}
if (n >= 7 && n <= 10) {
return goog.i18n.pluralRules.Keyword.MANY;
}
return goog.i18n.pluralRules.Keyword.OTHER;
};
@@ -574,99 +457,6 @@ goog.i18n.pluralRules.ptSelect_ = function(n, opt_precision) {
return goog.i18n.pluralRules.Keyword.OTHER;
};
/**
* Plural select rules for es 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.esSelect_ = function(n, opt_precision) {
if (n == 1) {
return goog.i18n.pluralRules.Keyword.ONE;
}
return goog.i18n.pluralRules.Keyword.OTHER;
};
/**
* Plural select rules for dsb locale
*
* @param {number} n The count of items.
* @param {number=} opt_precision Precision for number formatting, if not default.
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
* @private
*/
goog.i18n.pluralRules.dsbSelect_ = function(n, opt_precision) {
var i = n | 0;
var vf = goog.i18n.pluralRules.get_vf_(n, opt_precision);
if (vf.v == 0 && i % 100 == 1 || vf.f % 100 == 1) {
return goog.i18n.pluralRules.Keyword.ONE;
}
if (vf.v == 0 && i % 100 == 2 || vf.f % 100 == 2) {
return goog.i18n.pluralRules.Keyword.TWO;
}
if (vf.v == 0 && i % 100 >= 3 && i % 100 <= 4 || vf.f % 100 >= 3 && vf.f % 100 <= 4) {
return goog.i18n.pluralRules.Keyword.FEW;
}
return goog.i18n.pluralRules.Keyword.OTHER;
};
/**
* Plural select rules for lag 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.lagSelect_ = function(n, opt_precision) {
var i = n | 0;
if (n == 0) {
return goog.i18n.pluralRules.Keyword.ZERO;
}
if ((i == 0 || i == 1) && n != 0) {
return goog.i18n.pluralRules.Keyword.ONE;
}
return goog.i18n.pluralRules.Keyword.OTHER;
};
/**
* Plural select rules for is 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.isSelect_ = function(n, opt_precision) {
var i = n | 0;
var vf = goog.i18n.pluralRules.get_vf_(n, opt_precision);
var wt = goog.i18n.pluralRules.get_wt_(vf.v, vf.f);
if (wt.t == 0 && i % 10 == 1 && i % 100 != 11 || wt.t != 0) {
return goog.i18n.pluralRules.Keyword.ONE;
}
return goog.i18n.pluralRules.Keyword.OTHER;
};
/**
* Plural select rules for ksh 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.kshSelect_ = function(n, opt_precision) {
if (n == 0) {
return goog.i18n.pluralRules.Keyword.ZERO;
}
if (n == 1) {
return goog.i18n.pluralRules.Keyword.ONE;
}
return goog.i18n.pluralRules.Keyword.OTHER;
};
/**
* Plural select rules for ar locale
*
@@ -695,45 +485,219 @@ goog.i18n.pluralRules.arSelect_ = function(n, opt_precision) {
};
/**
* Plural select rules for gd locale
* Plural select rules for iu 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.gdSelect_ = function(n, opt_precision) {
if (n == 1 || n == 11) {
goog.i18n.pluralRules.iuSelect_ = function(n, opt_precision) {
if (n == 1) {
return goog.i18n.pluralRules.Keyword.ONE;
}
if (n == 2 || n == 12) {
if (n == 2) {
return goog.i18n.pluralRules.Keyword.TWO;
}
if (n >= 3 && n <= 10 || n >= 13 && n <= 19) {
return goog.i18n.pluralRules.Keyword.OTHER;
};
/**
* Plural select rules for cs 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.csSelect_ = function(n, opt_precision) {
var i = n | 0;
var vf = goog.i18n.pluralRules.get_vf_(n, opt_precision);
if (i == 1 && vf.v == 0) {
return goog.i18n.pluralRules.Keyword.ONE;
}
if (i >= 2 && i <= 4 && vf.v == 0) {
return goog.i18n.pluralRules.Keyword.FEW;
}
if (vf.v != 0) {
return goog.i18n.pluralRules.Keyword.MANY;
}
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 be 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.beSelect_ = function(n, opt_precision) {
if (n % 10 == 1 && n % 100 != 11) {
return goog.i18n.pluralRules.Keyword.ONE;
}
if (n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 12 || n % 100 > 14)) {
return goog.i18n.pluralRules.Keyword.FEW;
}
if (n % 10 == 0 || n % 10 >= 5 && n % 10 <= 9 || n % 100 >= 11 && n % 100 <= 14) {
return goog.i18n.pluralRules.Keyword.MANY;
}
return goog.i18n.pluralRules.Keyword.OTHER;
};
/**
* Plural select rules for ak 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.akSelect_ = function(n, opt_precision) {
if (n >= 0 && n <= 1) {
return goog.i18n.pluralRules.Keyword.ONE;
}
return goog.i18n.pluralRules.Keyword.OTHER;
};
/**
* Plural select rules for pl 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.plSelect_ = function(n, opt_precision) {
var i = n | 0;
var vf = goog.i18n.pluralRules.get_vf_(n, opt_precision);
if (i == 1 && vf.v == 0) {
return goog.i18n.pluralRules.Keyword.ONE;
}
if (vf.v == 0 && i % 10 >= 2 && i % 10 <= 4 && (i % 100 < 12 || i % 100 > 14)) {
return goog.i18n.pluralRules.Keyword.FEW;
}
if (vf.v == 0 && i != 1 && i % 10 >= 0 && i % 10 <= 1 || vf.v == 0 && i % 10 >= 5 && i % 10 <= 9 || vf.v == 0 && i % 100 >= 12 && i % 100 <= 14) {
return goog.i18n.pluralRules.Keyword.MANY;
}
return goog.i18n.pluralRules.Keyword.OTHER;
};
/**
* Plural select rules for ru 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.ruSelect_ = function(n, opt_precision) {
var i = n | 0;
var vf = goog.i18n.pluralRules.get_vf_(n, opt_precision);
if (vf.v == 0 && i % 10 == 1 && i % 100 != 11) {
return goog.i18n.pluralRules.Keyword.ONE;
}
if (vf.v == 0 && i % 10 >= 2 && i % 10 <= 4 && (i % 100 < 12 || i % 100 > 14)) {
return goog.i18n.pluralRules.Keyword.FEW;
}
if (vf.v == 0 && i % 10 == 0 || vf.v == 0 && i % 10 >= 5 && i % 10 <= 9 || vf.v == 0 && i % 100 >= 11 && i % 100 <= 14) {
return goog.i18n.pluralRules.Keyword.MANY;
}
return goog.i18n.pluralRules.Keyword.OTHER;
};
/**
* Plural select rules for lag 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.lagSelect_ = function(n, opt_precision) {
var i = n | 0;
if (n == 0) {
return goog.i18n.pluralRules.Keyword.ZERO;
}
if ((i == 0 || i == 1) && n != 0) {
return goog.i18n.pluralRules.Keyword.ONE;
}
return goog.i18n.pluralRules.Keyword.OTHER;
};
/**
* Plural select rules for shi 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.shiSelect_ = function(n, opt_precision) {
var i = n | 0;
if (i == 0 || n == 1) {
return goog.i18n.pluralRules.Keyword.ONE;
}
if (n >= 2 && n <= 10) {
return goog.i18n.pluralRules.Keyword.FEW;
}
return goog.i18n.pluralRules.Keyword.OTHER;
};
/**
* Plural select rules for sl locale
* Plural select rules for he 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.slSelect_ = function(n, opt_precision) {
goog.i18n.pluralRules.heSelect_ = function(n, opt_precision) {
var i = n | 0;
var vf = goog.i18n.pluralRules.get_vf_(n, opt_precision);
if (vf.v == 0 && i % 100 == 1) {
if (i == 1 && vf.v == 0) {
return goog.i18n.pluralRules.Keyword.ONE;
}
if (vf.v == 0 && i % 100 == 2) {
if (i == 2 && vf.v == 0) {
return goog.i18n.pluralRules.Keyword.TWO;
}
if (vf.v == 0 && i % 100 >= 3 && i % 100 <= 4 || vf.v != 0) {
return goog.i18n.pluralRules.Keyword.FEW;
if (vf.v == 0 && (n < 0 || n > 10) && n % 10 == 0) {
return goog.i18n.pluralRules.Keyword.MANY;
}
return goog.i18n.pluralRules.Keyword.OTHER;
};
/**
* Plural select rules for is 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.isSelect_ = function(n, opt_precision) {
var i = n | 0;
var vf = goog.i18n.pluralRules.get_vf_(n, opt_precision);
var wt = goog.i18n.pluralRules.get_wt_(vf.v, vf.f);
if (wt.t == 0 && i % 10 == 1 && i % 100 != 11 || wt.t != 0) {
return goog.i18n.pluralRules.Keyword.ONE;
}
return goog.i18n.pluralRules.Keyword.OTHER;
};
@@ -761,47 +725,81 @@ goog.i18n.pluralRules.ltSelect_ = function(n, opt_precision) {
};
/**
* Plural select rules for tzm locale
* Plural select rules for gd 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.tzmSelect_ = function(n, opt_precision) {
if (n >= 0 && n <= 1 || n >= 11 && n <= 99) {
goog.i18n.pluralRules.gdSelect_ = function(n, opt_precision) {
if (n == 1 || n == 11) {
return goog.i18n.pluralRules.Keyword.ONE;
}
if (n == 2 || n == 12) {
return goog.i18n.pluralRules.Keyword.TWO;
}
if (n >= 3 && n <= 10 || n >= 13 && n <= 19) {
return goog.i18n.pluralRules.Keyword.FEW;
}
return goog.i18n.pluralRules.Keyword.OTHER;
};
/**
* Plural select rules for en locale
* Plural select rules for dsb locale
*
* @param {number} n The count of items.
* @param {number=} opt_precision Precision for number formatting, if not default.
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
* @private
*/
goog.i18n.pluralRules.enSelect_ = function(n, opt_precision) {
goog.i18n.pluralRules.dsbSelect_ = function(n, opt_precision) {
var i = n | 0;
var vf = goog.i18n.pluralRules.get_vf_(n, opt_precision);
if (i == 1 && vf.v == 0) {
if (vf.v == 0 && i % 100 == 1 || vf.f % 100 == 1) {
return goog.i18n.pluralRules.Keyword.ONE;
}
if (vf.v == 0 && i % 100 == 2 || vf.f % 100 == 2) {
return goog.i18n.pluralRules.Keyword.TWO;
}
if (vf.v == 0 && i % 100 >= 3 && i % 100 <= 4 || vf.f % 100 >= 3 && vf.f % 100 <= 4) {
return goog.i18n.pluralRules.Keyword.FEW;
}
return goog.i18n.pluralRules.Keyword.OTHER;
};
/**
* Plural select rules for ak locale
* Plural select rules for lv 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.akSelect_ = function(n, opt_precision) {
if (n >= 0 && n <= 1) {
goog.i18n.pluralRules.lvSelect_ = function(n, opt_precision) {
var vf = goog.i18n.pluralRules.get_vf_(n, opt_precision);
if (n % 10 == 0 || n % 100 >= 11 && n % 100 <= 19 || vf.v == 2 && vf.f % 100 >= 11 && vf.f % 100 <= 19) {
return goog.i18n.pluralRules.Keyword.ZERO;
}
if (n % 10 == 1 && n % 100 != 11 || vf.v == 2 && vf.f % 10 == 1 && vf.f % 100 != 11 || vf.v != 2 && vf.f % 10 == 1) {
return goog.i18n.pluralRules.Keyword.ONE;
}
return goog.i18n.pluralRules.Keyword.OTHER;
};
/**
* Plural select rules for ksh 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.kshSelect_ = function(n, opt_precision) {
if (n == 0) {
return goog.i18n.pluralRules.Keyword.ZERO;
}
if (n == 1) {
return goog.i18n.pluralRules.Keyword.ONE;
}
return goog.i18n.pluralRules.Keyword.OTHER;
@@ -9,21 +9,21 @@
minErr,
extend
*/
/* eslint-disable no-unused-vars */
function isFunction(value) { return typeof value === 'function'; }
function isPromiseLike(obj) { return obj && isFunction(obj.then); }
function isObject(value) { return value !== null && typeof value === 'object'; }
function isUndefined(value) { return typeof value === 'undefined'; }
function minErr(module, constructor) {
var isFunction = function isFunction(value) {return typeof value === 'function';};
var isPromiseLike = function isPromiseLike(obj) {return obj && isFunction(obj.then);};
var isObject = function isObject(value) {return value != null && typeof value === 'object';};
var isUndefined = function isUndefined(value) {return typeof value === 'undefined';};
var minErr = function minErr(module, constructor) {
return function() {
var ErrorConstructor = constructor || Error;
throw new ErrorConstructor(module + arguments[0] + arguments[1]);
};
}
};
function extend(dst) {
var extend = function extend(dst) {
for (var i = 1, ii = arguments.length; i < ii; i++) {
var obj = arguments[i];
if (obj) {
@@ -35,11 +35,18 @@ function extend(dst) {
}
}
return dst;
}
/* eslint-enable */
};
var $q = qFactory(process.nextTick, function noopExceptionHandler() {});
exports.resolved = $q.resolve;
exports.rejected = $q.reject;
exports.deferred = $q.defer;
exports.deferred = function() {
var deferred = $q.defer();
return {
promise: deferred.promise,
resolve: deferred.resolve,
reject: deferred.reject
};
};
+1 -6
View File
@@ -73,11 +73,6 @@ function getBuild() {
return 'sha.' + hash;
}
function checkBranchPattern(version, branchPattern) {
// check that the version starts with the branch pattern minus its asterisk
// e.g. branchPattern = '1.6.*'; version = '1.6.0-rc.0' => '1.6.' === '1.6.'
return version.slice(0, branchPattern.length - 1) === branchPattern.replace('*', '');
}
/**
* If the current commit is tagged as a version get that version
@@ -90,7 +85,7 @@ var getTaggedVersion = function() {
var tag = gitTagResult.stdout.trim();
var version = semver.parse(tag);
if (version && checkBranchPattern(version.version, currentPackage.branchPattern)) {
if (version && semver.satisfies(version, currentPackage.branchVersion)) {
version.codeName = getCodeName(tag);
version.full = version.version;
version.branch = 'v' + currentPackage.branchPattern.replace('*', 'x');
+5 -12
View File
@@ -1,16 +1,16 @@
{
"name": "angularjs",
"license": "MIT",
"branchVersion": "^1.6.0",
"branchPattern": "1.6.*",
"distTag": "latest",
"branchVersion": "1.5.x",
"branchPattern": "1.5.*",
"distTag": "previous_1_5",
"repository": {
"type": "git",
"url": "https://github.com/angular/angular.js.git"
},
"engines": {
"node": "^6.9.1",
"yarn": ">=0.17.9",
"yarn": "^0.17.9",
"grunt": "^1.2.0"
},
"scripts": {
@@ -22,21 +22,17 @@
"devDependencies": {
"angular-benchpress": "0.x.x",
"benchmark": "1.x.x",
"bootstrap": "3.1.1",
"bower": "~1.3.9",
"browserstacktunnel-wrapper": "^1.4.2",
"canonical-path": "0.0.2",
"changez": "^2.1.1",
"changez-angular": "^2.1.2",
"cheerio": "^0.17.0",
"commitizen": "^2.3.0",
"cross-spawn": "^4.0.0",
"cz-conventional-changelog": "1.1.4",
"dgeni": "^0.4.0",
"dgeni-packages": "^0.16.4",
"dgeni-packages": "^0.16.0",
"event-stream": "~3.1.0",
"glob": "^6.0.1",
"google-code-prettify": "1.0.1",
"grunt": "^1.0.1",
"grunt-bump": "^0.8.0",
"grunt-cli": "^1.2.0",
@@ -59,7 +55,6 @@
"jasmine-core": "^2.4.0",
"jasmine-node": "^2.0.0",
"jasmine-reporters": "^2.2.0",
"jquery": "^3.1.1",
"karma": "^1.1.2",
"karma-browserstack-launcher": "^1.0.1",
"karma-chrome-launcher": "^1.0.1",
@@ -72,11 +67,9 @@
"load-grunt-tasks": "^3.5.0",
"lodash": "~2.4.1",
"log4js": "^0.6.27",
"lunr": "^0.7.2",
"marked": "~0.3.0",
"node-html-encoder": "0.0.2",
"npm-run": "^4.1.0",
"open-sans-fontface": "^1.4.0",
"promises-aplus-tests": "~2.1.0",
"protractor": "^4.0.10",
"q": "~1.0.0",
+5 -3
View File
@@ -95,12 +95,12 @@
"createMap": false,
"VALIDITY_STATE_PROPERTY": false,
"reloadWithDebugInfo": false,
"stringify": false,
"NODE_TYPE_ELEMENT": false,
"NODE_TYPE_ATTRIBUTE": false,
"NODE_TYPE_TEXT": false,
"NODE_TYPE_COMMENT": false,
"NODE_TYPE_COMMENT": false,
"NODE_TYPE_DOCUMENT": false,
"NODE_TYPE_DOCUMENT_FRAGMENT": false,
@@ -123,7 +123,7 @@
"BOOLEAN_ATTR": false,
"ALIASED_ATTR": false,
"jqNextId": false,
"fnCamelCaseReplace": false,
"camelCase": false,
"jqLitePatchJQueryRemove": false,
"JQLite": false,
"jqLiteClone": false,
@@ -145,12 +145,14 @@
"getAliasedAttrName": false,
"createEventHandler": false,
"JQLitePrototype": false,
"addEventListenerFn": false,
"removeEventListenerFn": false,
"jqLiteIsTextNode": false,
"jqLiteDocumentLoaded": false,
/* apis.js */
"hashKey": false,
"NgMap": false,
"HashMap": false,
/* urlUtils.js */
"urlResolve": false,
+5 -59
View File
@@ -88,7 +88,6 @@
getBlockNodes,
hasOwnProperty,
createMap,
stringify,
NODE_TYPE_ELEMENT,
NODE_TYPE_ATTRIBUTE,
@@ -122,41 +121,9 @@ var REGEX_STRING_REGEXP = /^\/(.+)\/([a-z]*)$/;
// This is used so that it's possible for internal tests to create mock ValidityStates.
var VALIDITY_STATE_PROPERTY = 'validity';
var hasOwnProperty = Object.prototype.hasOwnProperty;
/**
* @ngdoc function
* @name angular.lowercase
* @module ng
* @kind function
*
* @deprecated
* sinceVersion="1.5.0"
* removeVersion="1.7.0"
* Use [String.prototype.toLowerCase](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String/toLowerCase) instead.
*
* @description Converts the specified string to lowercase.
* @param {string} string String to be converted to lowercase.
* @returns {string} Lowercased string.
*/
var lowercase = function(string) {return isString(string) ? string.toLowerCase() : string;};
/**
* @ngdoc function
* @name angular.uppercase
* @module ng
* @kind function
*
* @deprecated
* sinceVersion="1.5.0"
* removeVersion="1.7.0"
* Use [String.prototype.toUpperCase](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String/toUpperCase) instead.
*
* @description Converts the specified string to uppercase.
* @param {string} string String to be converted to uppercase.
* @returns {string} Uppercased string.
*/
var uppercase = function(string) {return isString(string) ? string.toUpperCase() : string;};
@@ -201,7 +168,6 @@ var
angularModule,
uid = 0;
// Support: IE 9-11 only
/**
* documentMode is an IE-only property
* http://msdn.microsoft.com/en-us/library/ie/cc196988(v=vs.85).aspx
@@ -277,7 +243,9 @@ function forEach(obj, iterator, context) {
if (obj) {
if (isFunction(obj)) {
for (key in obj) {
if (key !== 'prototype' && key !== 'length' && key !== 'name' && obj.hasOwnProperty(key)) {
// Need to check if hasOwnProperty exists,
// as on IE8 the result of querySelectorAll is an object without a hasOwnProperty function
if (key !== 'prototype' && key !== 'length' && key !== 'name' && (!obj.hasOwnProperty || obj.hasOwnProperty(key))) {
iterator.call(context, obj[key], key, obj);
}
}
@@ -1312,7 +1280,6 @@ function fromJson(json) {
var ALL_COLONS = /:/g;
function timezoneToOffset(timezone, fallback) {
// Support: IE 9-11 only, Edge 13-14+
// 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;
@@ -1448,7 +1415,7 @@ function encodeUriSegment(val) {
* This method is intended for encoding *key* or *value* parts of query component. We need a custom
* method because encodeURIComponent is too aggressive and encodes stuff that doesn't have to be
* encoded per http://tools.ietf.org/html/rfc3986:
* query = *( pchar / "/" / "?" )
* query = *( pchar / "/" / "?" )
* pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
* unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
* pct-encoded = "%" HEXDIG HEXDIG
@@ -1870,7 +1837,7 @@ function bindJQuery() {
extend(jQuery.fn, {
scope: JQLitePrototype.scope,
isolateScope: JQLitePrototype.isolateScope,
controller: /** @type {?} */ (JQLitePrototype).controller,
controller: JQLitePrototype.controller,
injector: JQLitePrototype.injector,
inheritedData: JQLitePrototype.inheritedData
});
@@ -1996,27 +1963,6 @@ function createMap() {
return Object.create(null);
}
function stringify(value) {
if (value == null) { // null || undefined
return '';
}
switch (typeof value) {
case 'string':
break;
case 'number':
value = '' + value;
break;
default:
if (hasCustomToString(value) && !isArray(value) && !isDate(value)) {
value = value.toString();
} else {
value = toJson(value);
}
}
return value;
}
var NODE_TYPE_ELEMENT = 1;
var NODE_TYPE_ATTRIBUTE = 2;
var NODE_TYPE_TEXT = 3;
+3 -8
View File
@@ -64,12 +64,12 @@
$ControllerProvider,
$DateProvider,
$DocumentProvider,
$$IsDocumentHiddenProvider,
$ExceptionHandlerProvider,
$FilterProvider,
$$ForceReflowProvider,
$InterpolateProvider,
$IntervalProvider,
$$HashMapProvider,
$HttpProvider,
$HttpParamSerializerProvider,
$HttpParamSerializerJQLikeProvider,
@@ -78,7 +78,6 @@
$jsonpCallbacksProvider,
$LocationProvider,
$LogProvider,
$$MapProvider,
$ParseProvider,
$RootScopeProvider,
$QProvider,
@@ -153,12 +152,9 @@ function publishExternalAPI(angular) {
'uppercase': uppercase,
'callbacks': {$$counter: 0},
'getTestability': getTestability,
'reloadWithDebugInfo': reloadWithDebugInfo,
'$$minErr': minErr,
'$$csp': csp,
'$$encodeUriSegment': encodeUriSegment,
'$$encodeUriQuery': encodeUriQuery,
'$$stringify': stringify
'reloadWithDebugInfo': reloadWithDebugInfo
});
angularModule = setupModuleLoader(window);
@@ -232,7 +228,6 @@ function publishExternalAPI(angular) {
$cacheFactory: $CacheFactoryProvider,
$controller: $ControllerProvider,
$document: $DocumentProvider,
$$isDocumentHidden: $$IsDocumentHiddenProvider,
$exceptionHandler: $ExceptionHandlerProvider,
$filter: $FilterProvider,
$$forceReflow: $$ForceReflowProvider,
@@ -260,7 +255,7 @@ function publishExternalAPI(angular) {
$window: $WindowProvider,
$$rAF: $$RAFProvider,
$$jqLite: $$jqLiteProvider,
$$Map: $$MapProvider,
$$HashMap: $$HashMapProvider,
$$cookieReader: $$CookieReaderProvider
});
}
+4 -3
View File
@@ -1,11 +1,12 @@
if (window.angular.bootstrap) {
// AngularJS is already loaded, so we can return here...
//AngularJS is already loaded, so we can return here...
if (window.console) {
console.log('WARNING: Tried to load angular more than once.');
}
return;
}
// try to bind to jquery now so that one can write jqLite(fn)
// but we will rebind on bootstrap again.
//try to bind to jquery now so that one can write jqLite(document).ready()
//but we will rebind on bootstrap again.
bindJQuery();
+1 -1
View File
@@ -1,4 +1,4 @@
jqLite(function() {
jqLite(window.document).ready(function() {
angularInit(window.document, bootstrap);
});
+37 -56
View File
@@ -1,5 +1,6 @@
'use strict';
/**
* Computes a hash of an 'obj'.
* Hash of a:
@@ -32,69 +33,49 @@ function hashKey(obj, nextUidFn) {
return key;
}
// A minimal ES2015 Map implementation.
// Should be bug/feature equivalent to the native implementations of supported browsers
// (for the features required in Angular).
// See https://kangax.github.io/compat-table/es6/#test-Map
var nanKey = Object.create(null);
function NgMapShim() {
this._keys = [];
this._values = [];
this._lastKey = NaN;
this._lastIndex = -1;
/**
* HashMap which can use objects as keys
*/
function HashMap(array, isolatedUid) {
if (isolatedUid) {
var uid = 0;
this.nextUid = function() {
return ++uid;
};
}
forEach(array, this.put, this);
}
NgMapShim.prototype = {
_idx: function(key) {
if (key === this._lastKey) {
return this._lastIndex;
}
this._lastKey = key;
this._lastIndex = this._keys.indexOf(key);
return this._lastIndex;
HashMap.prototype = {
/**
* Store key value pair
* @param key key to store can be any type
* @param value value to store can be any type
*/
put: function(key, value) {
this[hashKey(key, this.nextUid)] = value;
},
_transformKey: function(key) {
return isNumberNaN(key) ? nanKey : key;
},
get: function(key) {
key = this._transformKey(key);
var idx = this._idx(key);
if (idx !== -1) {
return this._values[idx];
}
},
set: function(key, value) {
key = this._transformKey(key);
var idx = this._idx(key);
if (idx === -1) {
idx = this._lastIndex = this._keys.length;
}
this._keys[idx] = key;
this._values[idx] = value;
// Support: IE11
// Do not `return this` to simulate the partial IE11 implementation
/**
* @param key
* @returns {Object} the value for the key
*/
get: function(key) {
return this[hashKey(key, this.nextUid)];
},
delete: function(key) {
key = this._transformKey(key);
var idx = this._idx(key);
if (idx === -1) {
return false;
}
this._keys.splice(idx, 1);
this._values.splice(idx, 1);
this._lastKey = NaN;
this._lastIndex = -1;
return true;
/**
* Remove the key/value pair
* @param key
*/
remove: function(key) {
var value = this[key = hashKey(key, this.nextUid)];
delete this[key];
return value;
}
};
// For now, always use `NgMapShim`, even if `window.Map` is available. Some native implementations
// are still buggy (often in subtle ways) and can cause hard-to-debug failures. When native `Map`
// implementations get more stable, we can reconsider switching to `window.Map` (when available).
var NgMap = NgMapShim;
var $$MapProvider = [/** @this */function() {
var $$HashMapProvider = [/** @this */function() {
this.$get = [function() {
return NgMap;
return HashMap;
}];
}];
+12 -12
View File
@@ -71,7 +71,11 @@ var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
var $injectorMinErr = minErr('$injector');
function stringifyFn(fn) {
return Function.prototype.toString.call(fn);
// Support: Chrome 50-51 only
// Creating a new string by adding `' '` at the end, to hack around some bug in Chrome v50/51
// (See https://github.com/angular/angular.js/issues/14487.)
// TODO (gkalpak): Remove workaround when Chrome v52 is released
return Function.prototype.toString.call(fn) + ' ';
}
function extractArgs(fn) {
@@ -645,7 +649,7 @@ function createInjector(modulesToLoad, strictDi) {
var INSTANTIATING = {},
providerSuffix = 'Provider',
path = [],
loadedModules = new NgMap(),
loadedModules = new HashMap([], true),
providerCache = {
$provide: {
provider: supportObject(provider),
@@ -753,7 +757,7 @@ function createInjector(modulesToLoad, strictDi) {
var runBlocks = [], moduleFn;
forEach(modulesToLoad, function(module) {
if (loadedModules.get(module)) return;
loadedModules.set(module, true);
loadedModules.put(module, true);
function runInvokeQueue(queue) {
var i, ii;
@@ -845,18 +849,14 @@ function createInjector(modulesToLoad, strictDi) {
}
function isClass(func) {
// Support: IE 9-11 only
// IE 9-11 do not support classes and IE9 leaks with the code below.
if (msie || typeof func !== 'function') {
if (msie <= 11) {
return false;
}
var result = func.$$ngIsClass;
if (!isBoolean(result)) {
// Support: Edge 12-13 only
// See: https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/6156135/
result = func.$$ngIsClass = /^(?:class\b|constructor\()/.test(stringifyFn(func));
}
return result;
// Support: Edge 12-13 only
// See: https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/6156135/
return typeof func === 'function'
&& /^(?:class\b|constructor\()/.test(stringifyFn(func));
}
function invoke(fn, self, locals, serviceName) {
+72 -83
View File
@@ -11,8 +11,9 @@
* Or gives undesired access to variables likes document or window? *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* global
JQLitePrototype: true,
/* global JQLitePrototype: true,
addEventListenerFn: true,
removeEventListenerFn: true,
BOOLEAN_ATTR: true,
ALIASED_ATTR: true
*/
@@ -56,7 +57,7 @@
* - [`after()`](http://api.jquery.com/after/)
* - [`append()`](http://api.jquery.com/append/)
* - [`attr()`](http://api.jquery.com/attr/) - Does not support functions as parameters
* - [`bind()`](http://api.jquery.com/bind/) (_deprecated_, use [`on()`](http://api.jquery.com/on/)) - Does not support namespaces, selectors or eventData
* - [`bind()`](http://api.jquery.com/bind/) - Does not support namespaces, selectors or eventData
* - [`children()`](http://api.jquery.com/children/) - Does not support selectors
* - [`clone()`](http://api.jquery.com/clone/)
* - [`contents()`](http://api.jquery.com/contents/)
@@ -76,7 +77,7 @@
* - [`parent()`](http://api.jquery.com/parent/) - Does not support selectors
* - [`prepend()`](http://api.jquery.com/prepend/)
* - [`prop()`](http://api.jquery.com/prop/)
* - [`ready()`](http://api.jquery.com/ready/) (_deprecated_, use `angular.element(callback)` instead of `angular.element(document).ready(callback)`)
* - [`ready()`](http://api.jquery.com/ready/)
* - [`remove()`](http://api.jquery.com/remove/)
* - [`removeAttr()`](http://api.jquery.com/removeAttr/) - Does not support multiple attributes
* - [`removeClass()`](http://api.jquery.com/removeClass/) - Does not support a function as first argument
@@ -85,7 +86,7 @@
* - [`text()`](http://api.jquery.com/text/)
* - [`toggleClass()`](http://api.jquery.com/toggleClass/) - Does not support a function as first argument
* - [`triggerHandler()`](http://api.jquery.com/triggerHandler/) - Passes a dummy event object to handlers
* - [`unbind()`](http://api.jquery.com/unbind/) (_deprecated_, use [`off()`](http://api.jquery.com/off/)) - Does not support namespaces or event object as parameter
* - [`unbind()`](http://api.jquery.com/unbind/) - Does not support namespaces or event object as parameter
* - [`val()`](http://api.jquery.com/val/)
* - [`wrap()`](http://api.jquery.com/wrap/)
*
@@ -123,7 +124,13 @@
JQLite.expando = 'ng339';
var jqCache = JQLite.cache = {},
jqId = 1;
jqId = 1,
addEventListenerFn = function(element, type, fn) {
element.addEventListener(type, fn, false);
},
removeEventListenerFn = function(element, type, fn) {
element.removeEventListener(type, fn, false);
};
/*
* !!! This is an undocumented "private" function !!!
@@ -136,31 +143,22 @@ JQLite._data = function(node) {
function jqNextId() { return ++jqId; }
var DASH_LOWERCASE_REGEXP = /-([a-z])/g;
var MS_HACK_REGEXP = /^-ms-/;
var SPECIAL_CHARS_REGEXP = /([:\-_]+(.))/g;
var MOZ_HACK_REGEXP = /^moz([A-Z])/;
var MOUSE_EVENT_MAP = { mouseleave: 'mouseout', mouseenter: 'mouseover' };
var jqLiteMinErr = minErr('jqLite');
/**
* Converts kebab-case to camelCase.
* There is also a special case for the ms prefix starting with a lowercase letter.
* Converts snake_case to camelCase.
* Also there is special case for Moz prefix starting with upper case letter.
* @param name Name to normalize
*/
function cssKebabToCamel(name) {
return kebabToCamel(name.replace(MS_HACK_REGEXP, 'ms-'));
}
function fnCamelCaseReplace(all, letter) {
return letter.toUpperCase();
}
/**
* Converts kebab-case to camelCase.
* @param name Name to normalize
*/
function kebabToCamel(name) {
return name
.replace(DASH_LOWERCASE_REGEXP, fnCamelCaseReplace);
function camelCase(name) {
return name.
replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) {
return offset ? letter.toUpperCase() : letter;
}).
replace(MOZ_HACK_REGEXP, 'Moz$1');
}
var SINGLE_TAG_REGEXP = /^<([\w-]+)\s*\/?>(?:<\/\1>|)$/;
@@ -297,8 +295,6 @@ function JQLite(element) {
if (argIsString) {
jqLiteAddNodes(this, jqLiteParseHTML(element));
} else if (isFunction(element)) {
jqLiteReady(element);
} else {
jqLiteAddNodes(this, element);
}
@@ -331,7 +327,7 @@ function jqLiteOff(element, type, fn, unsupported) {
if (!type) {
for (type in events) {
if (type !== '$destroy') {
element.removeEventListener(type, handle);
removeEventListenerFn(element, type, handle);
}
delete events[type];
}
@@ -343,7 +339,7 @@ function jqLiteOff(element, type, fn, unsupported) {
arrayRemove(listenerFns || [], fn);
}
if (!(isDefined(fn) && listenerFns && listenerFns.length > 0)) {
element.removeEventListener(type, handle);
removeEventListenerFn(element, type, handle);
delete events[type];
}
};
@@ -394,7 +390,6 @@ function jqLiteExpandoStore(element, createIfNecessary) {
function jqLiteData(element, key, value) {
if (jqLiteAcceptsData(element)) {
var prop;
var isSimpleSetter = isDefined(value);
var isSimpleGetter = !isSimpleSetter && key && !isObject(key);
@@ -403,18 +398,16 @@ function jqLiteData(element, key, value) {
var data = expandoStore && expandoStore.data;
if (isSimpleSetter) { // data('key', value)
data[kebabToCamel(key)] = value;
data[key] = value;
} else {
if (massGetter) { // data()
return data;
} else {
if (isSimpleGetter) { // data('key')
// don't force creation of expandoStore if it doesn't exist yet
return data && data[kebabToCamel(key)];
return data && data[key];
} else { // mass-setter: data({key1: val1, key2: val2})
for (prop in key) {
data[kebabToCamel(prop)] = key[prop];
}
extend(data, key);
}
}
}
@@ -533,32 +526,29 @@ function jqLiteDocumentLoaded(action, win) {
}
}
function jqLiteReady(fn) {
function trigger() {
window.document.removeEventListener('DOMContentLoaded', trigger);
window.removeEventListener('load', trigger);
fn();
}
// check if document is already loaded
if (window.document.readyState === 'complete') {
window.setTimeout(fn);
} else {
// We can not use jqLite since we are not done loading and jQuery could be loaded later.
// Works for modern browsers and IE9
window.document.addEventListener('DOMContentLoaded', trigger);
// Fallback to window.onload for others
window.addEventListener('load', trigger);
}
}
//////////////////////////////////////////
// Functions which are declared directly.
//////////////////////////////////////////
var JQLitePrototype = JQLite.prototype = {
ready: jqLiteReady,
ready: function(fn) {
var fired = false;
function trigger() {
if (fired) return;
fired = true;
fn();
}
// check if document is already loaded
if (window.document.readyState === 'complete') {
window.setTimeout(trigger);
} else {
this.on('DOMContentLoaded', trigger); // works for modern browsers and IE9
// we can not use jqLite since we are not done loading and jQuery could be loaded later.
// eslint-disable-next-line new-cap
JQLite(window).on('load', trigger); // fallback to window.onload for others
}
},
toString: function() {
var value = [];
forEach(this, function(e) { value.push('' + e);});
@@ -593,8 +583,7 @@ var ALIASED_ATTR = {
'ngMaxlength': 'maxlength',
'ngMin': 'min',
'ngMax': 'max',
'ngPattern': 'pattern',
'ngStep': 'step'
'ngPattern': 'pattern'
};
function getBooleanAttrName(element, name) {
@@ -645,7 +634,7 @@ forEach({
hasClass: jqLiteHasClass,
css: function(element, name, value) {
name = cssKebabToCamel(name);
name = camelCase(name);
if (isDefined(value)) {
element.style[name] = value;
@@ -655,33 +644,33 @@ forEach({
},
attr: function(element, name, value) {
var ret;
var nodeType = element.nodeType;
if (nodeType === NODE_TYPE_TEXT || nodeType === NODE_TYPE_ATTRIBUTE || nodeType === NODE_TYPE_COMMENT ||
!element.getAttribute) {
if (nodeType === NODE_TYPE_TEXT || nodeType === NODE_TYPE_ATTRIBUTE || nodeType === NODE_TYPE_COMMENT) {
return;
}
var lowercasedName = lowercase(name);
var isBooleanAttr = BOOLEAN_ATTR[lowercasedName];
if (isDefined(value)) {
// setter
if (value === null || (value === false && isBooleanAttr)) {
element.removeAttribute(name);
if (BOOLEAN_ATTR[lowercasedName]) {
if (isDefined(value)) {
if (value) {
element[name] = true;
element.setAttribute(name, lowercasedName);
} else {
element[name] = false;
element.removeAttribute(lowercasedName);
}
} else {
element.setAttribute(name, isBooleanAttr ? lowercasedName : value);
return (element[name] ||
(element.attributes.getNamedItem(name) || noop).specified)
? lowercasedName
: undefined;
}
} else {
// getter
ret = element.getAttribute(name);
if (isBooleanAttr && ret !== null) {
ret = lowercasedName;
}
// Normalize non-existing attributes to undefined (as jQuery).
} else if (isDefined(value)) {
element.setAttribute(name, value);
} else if (element.getAttribute) {
// the extra argument "2" is to get the right thing for a.href in IE, see jQuery code
// some elements (e.g. Document) don't have get attribute, so return undefined
var ret = element.getAttribute(name, 2);
// normalize non-existing attributes to undefined (as jQuery)
return ret === null ? undefined : ret;
}
},
@@ -716,7 +705,7 @@ forEach({
result.push(option.value || option.text);
}
});
return result;
return result.length === 0 ? null : result;
}
return element.value;
}
@@ -886,7 +875,7 @@ forEach({
eventFns = events[type] = [];
eventFns.specialHandlerWrapper = specialHandlerWrapper;
if (type !== '$destroy' && !noEventListener) {
element.addEventListener(type, handle);
addEventListenerFn(element, type, handle);
}
}
+3 -4
View File
@@ -203,7 +203,7 @@ function setupModuleLoader(window) {
* @description
* See {@link auto.$provide#decorator $provide.decorator()}.
*/
decorator: invokeLaterAndSetModuleName('$provide', 'decorator', configBlocks),
decorator: invokeLaterAndSetModuleName('$provide', 'decorator'),
/**
* @ngdoc method
@@ -349,11 +349,10 @@ function setupModuleLoader(window) {
* @param {string} method
* @returns {angular.Module}
*/
function invokeLaterAndSetModuleName(provider, method, queue) {
if (!queue) queue = invokeQueue;
function invokeLaterAndSetModuleName(provider, method) {
return function(recipeName, factoryFunction) {
if (factoryFunction && isFunction(factoryFunction)) factoryFunction.$$moduleName = name;
queue.push([provider, method, arguments]);
invokeQueue.push([provider, method, arguments]);
return moduleInstance;
};
}
+4 -3
View File
@@ -60,7 +60,7 @@ var $$CoreAnimateJsProvider = /** @this */ function() {
// this is prefixed with Core since it conflicts with
// the animateQueueProvider defined in ngAnimate/animateQueue.js
var $$CoreAnimateQueueProvider = /** @this */ function() {
var postDigestQueue = new NgMap();
var postDigestQueue = new HashMap();
var postDigestElements = [];
this.$get = ['$$AnimateRunner', '$rootScope',
@@ -139,7 +139,7 @@ var $$CoreAnimateQueueProvider = /** @this */ function() {
jqLiteRemoveClass(elm, toRemove);
}
});
postDigestQueue.delete(element);
postDigestQueue.remove(element);
}
});
postDigestElements.length = 0;
@@ -154,7 +154,7 @@ var $$CoreAnimateQueueProvider = /** @this */ function() {
if (classesAdded || classesRemoved) {
postDigestQueue.set(element, data);
postDigestQueue.put(element, data);
postDigestElements.push(element);
if (postDigestElements.length === 1) {
@@ -252,6 +252,7 @@ var $AnimateProvider = ['$provide', /** @this */ function($provide) {
var reservedRegex = new RegExp('(\\s+|\\/)' + NG_ANIMATE_CLASSNAME + '(\\s+|\\/)');
if (reservedRegex.test(this.$$classNameFilter.toString())) {
throw $animateMinErr('nongcls','$animateProvider.classNameFilter(regex) prohibits accepting a regex value which matches/contains the "{0}" CSS class.', NG_ANIMATE_CLASSNAME);
}
}
}
+7 -3
View File
@@ -32,8 +32,8 @@ var $$AnimateAsyncRunFactoryProvider = /** @this */ function() {
};
var $$AnimateRunnerFactoryProvider = /** @this */ function() {
this.$get = ['$q', '$sniffer', '$$animateAsyncRun', '$$isDocumentHidden', '$timeout',
function($q, $sniffer, $$animateAsyncRun, $$isDocumentHidden, $timeout) {
this.$get = ['$q', '$sniffer', '$$animateAsyncRun', '$document', '$timeout',
function($q, $sniffer, $$animateAsyncRun, $document, $timeout) {
var INITIAL_STATE = 0;
var DONE_PENDING_STATE = 1;
@@ -85,7 +85,11 @@ var $$AnimateRunnerFactoryProvider = /** @this */ function() {
this._doneCallbacks = [];
this._tick = function(fn) {
if ($$isDocumentHidden()) {
var doc = $document[0];
// the document may not be ready or attached
// to the module for some internal tests
if (doc && doc.hidden) {
timeoutTick(fn);
} else {
rafTick(fn);
+8 -9
View File
@@ -96,6 +96,7 @@ function Browser(window, document, $log, $sniffer) {
};
cacheState();
lastHistoryState = cachedState;
/**
* @name $browser#url
@@ -149,6 +150,8 @@ function Browser(window, document, $log, $sniffer) {
if ($sniffer.history && (!sameBase || !sameState)) {
history[replace ? 'replaceState' : 'pushState'](state, '', url);
cacheState();
// Do the assignment again so that those two variables are referentially identical.
lastHistoryState = cachedState;
} else {
if (!sameBase) {
pendingLocation = url;
@@ -197,7 +200,8 @@ function Browser(window, document, $log, $sniffer) {
function cacheStateAndFireUrlChange() {
pendingLocation = null;
fireStateOrUrlChange();
cacheState();
fireUrlChange();
}
// This variable should be used *only* inside the cacheState function.
@@ -211,16 +215,11 @@ function Browser(window, document, $log, $sniffer) {
if (equals(cachedState, lastCachedState)) {
cachedState = lastCachedState;
}
lastCachedState = cachedState;
lastHistoryState = cachedState;
}
function fireStateOrUrlChange() {
var prevLastHistoryState = lastHistoryState;
cacheState();
if (lastBrowserUrl === self.url() && prevLastHistoryState === cachedState) {
function fireUrlChange() {
if (lastBrowserUrl === self.url() && lastHistoryState === cachedState) {
return;
}
@@ -286,7 +285,7 @@ function Browser(window, document, $log, $sniffer) {
* Needs to be exported to be able to check for changes that have been done in sync,
* as hashchange/popstate events fire in async.
*/
self.$$checkUrlChange = fireStateOrUrlChange;
self.$$checkUrlChange = fireUrlChange;
//////////////////////////////////////////////////////////////
// Misc API
+36 -75
View File
@@ -128,8 +128,7 @@
* * `$onChanges(changesObj)` - Called whenever one-way (`<`) or interpolation (`@`) bindings are updated. The
* `changesObj` is a hash whose keys are the names of the bound properties that have changed, and the values are an
* object of the form `{ currentValue, previousValue, isFirstChange() }`. Use this hook to trigger updates within a
* component such as cloning the bound value to prevent accidental mutation of the outer value. Note that this will
* also be called when your bindings are initialized.
* component such as cloning the bound value to prevent accidental mutation of the outer value.
* * `$doCheck()` - Called on each turn of the digest cycle. Provides an opportunity to detect and act on
* changes. Any actions that you wish to take in response to the changes that you detect must be
* invoked from this hook; implementing this has no effect on when `$onChanges` is called. For example, this hook
@@ -1390,7 +1389,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
*
* The default value is true in Angular 1.5.x but will switch to false in Angular 1.6.x.
*/
var preAssignBindingsEnabled = false;
var preAssignBindingsEnabled = true;
this.preAssignBindingsEnabled = function(enabled) {
if (isDefined(enabled)) {
preAssignBindingsEnabled = enabled;
@@ -1852,15 +1851,25 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
// modify it.
$compileNodes = jqLite($compileNodes);
}
var NOT_EMPTY = /\S+/;
// We can not compile top level text elements since text nodes can be merged and we will
// not be able to attach scope data to them, so we will wrap them in <span>
for (var i = 0, len = $compileNodes.length; i < len; i++) {
var domNode = $compileNodes[i];
if (domNode.nodeType === NODE_TYPE_TEXT && domNode.nodeValue.match(NOT_EMPTY) /* non-empty */) {
jqLiteWrapNode(domNode, $compileNodes[i] = window.document.createElement('span'));
}
}
var compositeLinkFn =
compileNodes($compileNodes, transcludeFn, $compileNodes,
maxPriority, ignoreDirective, previousCompileContext);
compile.$$addScopeClass($compileNodes);
var namespace = null;
return function publicLinkFn(scope, cloneConnectFn, options) {
if (!$compileNodes) {
throw $compileMinErr('multilink', 'This element has already been linked.');
}
assertArg(scope, 'scope');
if (previousCompileContext && previousCompileContext.needsNewScope) {
@@ -1915,10 +1924,6 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
if (cloneConnectFn) cloneConnectFn($linkNode, scope);
if (compositeLinkFn) compositeLinkFn(scope, $linkNode, $linkNode, parentBoundTranscludeFn);
if (!cloneConnectFn) {
$compileNodes = compositeLinkFn = null;
}
return $linkNode;
};
}
@@ -1951,23 +1956,12 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
function compileNodes(nodeList, transcludeFn, $rootElement, maxPriority, ignoreDirective,
previousCompileContext) {
var linkFns = [],
// `nodeList` can be either an element's `.childNodes` (live NodeList)
// or a jqLite/jQuery collection or an array
notLiveList = isArray(nodeList) || (nodeList instanceof jqLite),
attrs, directives, nodeLinkFn, childNodes, childLinkFn, linkFnFound, nodeLinkFnFound;
for (var i = 0; i < nodeList.length; i++) {
attrs = new Attributes();
// Support: IE 11 only
// Workaround for #11781 and #14924
if (msie === 11) {
mergeConsecutiveTextNodes(nodeList, i, notLiveList);
}
// We must always refer to `nodeList[i]` hereafter,
// since the nodes can be replaced underneath us.
// we must always refer to nodeList[i] since the nodes can be replaced underneath us.
directives = collectDirectives(nodeList[i], [], attrs, i === 0 ? maxPriority : undefined,
ignoreDirective);
@@ -2058,32 +2052,6 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
}
}
function mergeConsecutiveTextNodes(nodeList, idx, notLiveList) {
var node = nodeList[idx];
var parent = node.parentNode;
var sibling;
if (node.nodeType !== NODE_TYPE_TEXT) {
return;
}
while (true) {
sibling = parent ? node.nextSibling : nodeList[idx + 1];
if (!sibling || sibling.nodeType !== NODE_TYPE_TEXT) {
break;
}
node.nodeValue = node.nodeValue + sibling.nodeValue;
if (sibling.parentNode) {
sibling.parentNode.removeChild(sibling);
}
if (notLiveList && sibling === nodeList[idx + 1]) {
nodeList.splice(idx + 1, 1);
}
}
}
function createBoundTranscludeFn(scope, transcludeFn, previousBoundTranscludeFn) {
function boundTranscludeFn(transcludedScope, cloneFn, controllers, futureParentElement, containingScope) {
@@ -2147,7 +2115,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
attr = nAttrs[j];
name = attr.name;
value = attr.value;
value = trim(attr.value);
// support ngAttr attribute binding
ngAttrName = directiveNormalize(name);
@@ -2203,6 +2171,13 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
}
break;
case NODE_TYPE_TEXT: /* Text Node */
if (msie === 11) {
// Workaround for #11781
while (node.parentNode && node.nextSibling && node.nextSibling.nodeType === NODE_TYPE_TEXT) {
node.nodeValue = node.nodeValue + node.nextSibling.nodeValue;
node.parentNode.removeChild(node.nextSibling);
}
}
addTextInterpolateDirective(directives, node.nodeValue);
break;
case NODE_TYPE_COMMENT: /* Comment */
@@ -2475,9 +2450,9 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
var slots = createMap();
if (!isObject(directiveValue)) {
$template = jqLite(jqLiteClone(compileNode)).contents();
} else {
$template = jqLite(jqLiteClone(compileNode)).contents();
if (isObject(directiveValue)) {
// We have transclusion slots,
// collect them up, compile them and store their transclusion functions
@@ -3029,11 +3004,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
forEach(dst, function(value, key) {
if (key.charAt(0) !== '$') {
if (src[key] && src[key] !== value) {
if (value.length) {
value += (key === 'style' ? ';' : ' ') + src[key];
} else {
value = src[key];
}
value += (key === 'style' ? ';' : ' ') + src[key];
}
dst.$set(key, value, true, srcAttr[key]);
}
@@ -3152,10 +3123,6 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
childBoundTranscludeFn);
}
linkQueue = null;
}).catch(function(error) {
if (error instanceof Error) {
$exceptionHandler(error);
}
});
return function delayedNodeLinkFn(ignoreChildLinkFn, scope, node, rootElement, boundTranscludeFn) {
@@ -3256,9 +3223,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
}
// maction[xlink:href] can source SVG. It's not limited to <maction>.
} else if (attrNormalizedName === 'xlinkHref' ||
(tag === 'form' && attrNormalizedName === 'action') ||
// links can be stylesheets or imports, which can run script in the current origin
(tag === 'link' && attrNormalizedName === 'href')
(tag === 'form' && attrNormalizedName === 'action')
) {
return $sce.RESOURCE_URL;
}
@@ -3281,12 +3246,6 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
startingTag(node));
}
if (EVENT_HANDLER_ATTR_REGEXP.test(name)) {
throw $compileMinErr('nodomevents',
'Interpolations for HTML DOM event attributes are disallowed. Please use the ' +
'ng- versions (such as ng-click instead of onclick) instead.');
}
directives.push({
priority: 100,
compile: function() {
@@ -3294,6 +3253,12 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
pre: function attrInterpolatePreLinkFn(scope, element, attr) {
var $$observers = (attr.$$observers || (attr.$$observers = createMap()));
if (EVENT_HANDLER_ATTR_REGEXP.test(name)) {
throw $compileMinErr('nodomevents',
'Interpolations for HTML DOM event attributes are disallowed. Please use the ' +
'ng- versions (such as ng-click instead of onclick) instead.');
}
// If the attribute has changed since last $interpolate()ed
var newValue = attr[name];
if (newValue !== value) {
@@ -3602,16 +3567,12 @@ SimpleChange.prototype.isFirstChange = function() { return this.previousValue ==
var PREFIX_REGEXP = /^((?:x|data)[:\-_])/i;
var SPECIAL_CHARS_REGEXP = /[:\-_]+(.)/g;
/**
* Converts all accepted directives format into proper directive name.
* @param name Name to normalize
*/
function directiveNormalize(name) {
return name
.replace(PREFIX_REGEXP, '')
.replace(SPECIAL_CHARS_REGEXP, fnCamelCaseReplace);
return camelCase(name.replace(PREFIX_REGEXP, ''));
}
/**
+3 -2
View File
@@ -58,12 +58,13 @@ function $ControllerProvider() {
/**
* @ngdoc method
* @name $controllerProvider#allowGlobals
* @description If called, allows `$controller` to find controller constructors on `window`
*
* @deprecated
* sinceVersion="v1.3.0"
* removeVersion="v1.7.0"
* This method of finding controllers has been deprecated.
*
* @description If called, allows `$controller` to find controller constructors on `window` *
*/
this.allowGlobals = function() {
globals = true;
@@ -84,7 +85,7 @@ function $ControllerProvider() {
* * check if a controller with given name is registered via `$controllerProvider`
* * check if evaluating the string on the current scope returns a constructor
* * if $controllerProvider#allowGlobals, check `window[constructor]` on the global
* `window` object (deprecated, not recommended)
* `window` object (not recommended)
*
* The string can use the `controller as property` syntax, where the controller instance is published
* as the specified property on the `scope`; the `scope` must be injected into `locals` param for this
+3 -5
View File
@@ -159,8 +159,7 @@
*
* @description
*
* This directive sets the `disabled` attribute on the element (typically a form control,
* e.g. `input`, `button`, `select` etc.) if the
* This directive sets the `disabled` attribute on the element if the
* {@link guide/expression expression} inside `ngDisabled` evaluates to truthy.
*
* A special directive is necessary because we cannot use interpolation inside the `disabled`
@@ -427,11 +426,10 @@ forEach(['src', 'srcset', 'href'], function(attrName) {
attr.$set(name, value);
// Support: IE 9-11 only
// On IE, if "ng:src" directive declaration is used and "src" attribute doesn't exist
// on IE, if "ng:src" directive declaration is used and "src" attribute doesn't exist
// then calling element.setAttribute('src', 'foo') doesn't do anything, so we need
// to set the property as well to achieve the desired effect.
// We use attr[attrName] value since $set can sanitize the url.
// we use attr[attrName] value since $set can sanitize the url.
if (msie && propName) element.prop(propName, attr[name]);
});
}
+106 -218
View File
@@ -1,6 +1,6 @@
'use strict';
/* global -nullFormCtrl, -PENDING_CLASS, -SUBMITTED_CLASS
/* global -nullFormCtrl, -SUBMITTED_CLASS, addSetValidityMethod: true
*/
var nullFormCtrl = {
$addControl: noop,
@@ -11,7 +11,6 @@ var nullFormCtrl = {
$setPristine: noop,
$setSubmitted: noop
},
PENDING_CLASS = 'ng-pending',
SUBMITTED_CLASS = 'ng-submitted';
function nullFormRenameControl(control, name) {
@@ -62,28 +61,22 @@ function nullFormRenameControl(control, name) {
*/
//asks for $scope to fool the BC controller module
FormController.$inject = ['$element', '$attrs', '$scope', '$animate', '$interpolate'];
function FormController($element, $attrs, $scope, $animate, $interpolate) {
this.$$controls = [];
function FormController(element, attrs, $scope, $animate, $interpolate) {
var form = this,
controls = [];
// init state
this.$error = {};
this.$$success = {};
this.$pending = undefined;
this.$name = $interpolate($attrs.name || $attrs.ngForm || '')($scope);
this.$dirty = false;
this.$pristine = true;
this.$valid = true;
this.$invalid = false;
this.$submitted = false;
this.$$parentForm = nullFormCtrl;
form.$error = {};
form.$$success = {};
form.$pending = undefined;
form.$name = $interpolate(attrs.name || attrs.ngForm || '')($scope);
form.$dirty = false;
form.$pristine = true;
form.$valid = true;
form.$invalid = false;
form.$submitted = false;
form.$$parentForm = nullFormCtrl;
this.$$element = $element;
this.$$animate = $animate;
setupValidity(this);
}
FormController.prototype = {
/**
* @ngdoc method
* @name form.FormController#$rollbackViewValue
@@ -95,11 +88,11 @@ FormController.prototype = {
* event defined in `ng-model-options`. This method is typically needed by the reset button of
* a form that uses `ng-model-options` to pend updates.
*/
$rollbackViewValue: function() {
forEach(this.$$controls, function(control) {
form.$rollbackViewValue = function() {
forEach(controls, function(control) {
control.$rollbackViewValue();
});
},
};
/**
* @ngdoc method
@@ -112,11 +105,11 @@ FormController.prototype = {
* event defined in `ng-model-options`. This method is rarely needed as `NgModelController`
* usually handles calling this in response to input events.
*/
$commitViewValue: function() {
forEach(this.$$controls, function(control) {
form.$commitViewValue = function() {
forEach(controls, function(control) {
control.$commitViewValue();
});
},
};
/**
* @ngdoc method
@@ -139,29 +132,29 @@ FormController.prototype = {
* For example, if an input control is added that is already `$dirty` and has `$error` properties,
* calling `$setDirty()` and `$validate()` afterwards will propagate the state to the parent form.
*/
$addControl: function(control) {
form.$addControl = function(control) {
// Breaking change - before, inputs whose name was "hasOwnProperty" were quietly ignored
// and not added to the scope. Now we throw an error.
assertNotHasOwnProperty(control.$name, 'input');
this.$$controls.push(control);
controls.push(control);
if (control.$name) {
this[control.$name] = control;
form[control.$name] = control;
}
control.$$parentForm = this;
},
control.$$parentForm = form;
};
// Private API: rename a form control
$$renameControl: function(control, newName) {
form.$$renameControl = function(control, newName) {
var oldName = control.$name;
if (this[oldName] === control) {
delete this[oldName];
if (form[oldName] === control) {
delete form[oldName];
}
this[newName] = control;
form[newName] = control;
control.$name = newName;
},
};
/**
* @ngdoc method
@@ -179,26 +172,60 @@ FormController.prototype = {
* different from case to case. For example, removing the only `$dirty` control from a form may or
* may not mean that the form is still `$dirty`.
*/
$removeControl: function(control) {
if (control.$name && this[control.$name] === control) {
delete this[control.$name];
form.$removeControl = function(control) {
if (control.$name && form[control.$name] === control) {
delete form[control.$name];
}
forEach(this.$pending, function(value, name) {
// eslint-disable-next-line no-invalid-this
this.$setValidity(name, null, control);
}, this);
forEach(this.$error, function(value, name) {
// eslint-disable-next-line no-invalid-this
this.$setValidity(name, null, control);
}, this);
forEach(this.$$success, function(value, name) {
// eslint-disable-next-line no-invalid-this
this.$setValidity(name, null, control);
}, this);
forEach(form.$pending, function(value, name) {
form.$setValidity(name, null, control);
});
forEach(form.$error, function(value, name) {
form.$setValidity(name, null, control);
});
forEach(form.$$success, function(value, name) {
form.$setValidity(name, null, control);
});
arrayRemove(this.$$controls, control);
arrayRemove(controls, control);
control.$$parentForm = nullFormCtrl;
},
};
/**
* @ngdoc method
* @name form.FormController#$setValidity
*
* @description
* Sets the validity of a form control.
*
* This method will also propagate to parent forms.
*/
addSetValidityMethod({
ctrl: this,
$element: element,
set: function(object, property, controller) {
var list = object[property];
if (!list) {
object[property] = [controller];
} else {
var index = list.indexOf(controller);
if (index === -1) {
list.push(controller);
}
}
},
unset: function(object, property, controller) {
var list = object[property];
if (!list) {
return;
}
arrayRemove(list, controller);
if (list.length === 0) {
delete object[property];
}
},
$animate: $animate
});
/**
* @ngdoc method
@@ -210,13 +237,13 @@ FormController.prototype = {
* This method can be called to add the 'ng-dirty' class and set the form to a dirty
* state (ng-dirty class). This method will also propagate to parent forms.
*/
$setDirty: function() {
this.$$animate.removeClass(this.$$element, PRISTINE_CLASS);
this.$$animate.addClass(this.$$element, DIRTY_CLASS);
this.$dirty = true;
this.$pristine = false;
this.$$parentForm.$setDirty();
},
form.$setDirty = function() {
$animate.removeClass(element, PRISTINE_CLASS);
$animate.addClass(element, DIRTY_CLASS);
form.$dirty = true;
form.$pristine = false;
form.$$parentForm.$setDirty();
};
/**
* @ngdoc method
@@ -234,15 +261,15 @@ FormController.prototype = {
* Setting a form back to a pristine state is often useful when we want to 'reuse' a form after
* saving or resetting it.
*/
$setPristine: function() {
this.$$animate.setClass(this.$$element, PRISTINE_CLASS, DIRTY_CLASS + ' ' + SUBMITTED_CLASS);
this.$dirty = false;
this.$pristine = true;
this.$submitted = false;
forEach(this.$$controls, function(control) {
form.$setPristine = function() {
$animate.setClass(element, PRISTINE_CLASS, DIRTY_CLASS + ' ' + SUBMITTED_CLASS);
form.$dirty = false;
form.$pristine = true;
form.$submitted = false;
forEach(controls, function(control) {
control.$setPristine();
});
},
};
/**
* @ngdoc method
@@ -257,11 +284,11 @@ FormController.prototype = {
* Setting a form controls back to their untouched state is often useful when setting the form
* back to its pristine state.
*/
$setUntouched: function() {
forEach(this.$$controls, function(control) {
form.$setUntouched = function() {
forEach(controls, function(control) {
control.$setUntouched();
});
},
};
/**
* @ngdoc method
@@ -270,46 +297,12 @@ FormController.prototype = {
* @description
* Sets the form to its submitted state.
*/
$setSubmitted: function() {
this.$$animate.addClass(this.$$element, SUBMITTED_CLASS);
this.$submitted = true;
this.$$parentForm.$setSubmitted();
}
};
/**
* @ngdoc method
* @name form.FormController#$setValidity
*
* @description
* Sets the validity of a form control.
*
* This method will also propagate to parent forms.
*/
addSetValidityMethod({
clazz: FormController,
set: function(object, property, controller) {
var list = object[property];
if (!list) {
object[property] = [controller];
} else {
var index = list.indexOf(controller);
if (index === -1) {
list.push(controller);
}
}
},
unset: function(object, property, controller) {
var list = object[property];
if (!list) {
return;
}
arrayRemove(list, controller);
if (list.length === 0) {
delete object[property];
}
}
});
form.$setSubmitted = function() {
$animate.addClass(element, SUBMITTED_CLASS);
form.$submitted = true;
form.$$parentForm.$setSubmitted();
};
}
/**
* @ngdoc directive
@@ -506,13 +499,13 @@ var formDirectiveFactory = function(isNgForm) {
event.preventDefault();
};
formElement[0].addEventListener('submit', handleFormSubmission);
addEventListenerFn(formElement[0], 'submit', handleFormSubmission);
// unregister the preventDefault listener so that we don't not leak memory but in a
// way that will achieve the prevention of the default action.
formElement.on('$destroy', function() {
$timeout(function() {
formElement[0].removeEventListener('submit', handleFormSubmission);
removeEventListenerFn(formElement[0], 'submit', handleFormSubmission);
}, 0, false);
});
}
@@ -556,108 +549,3 @@ var formDirectiveFactory = function(isNgForm) {
var formDirective = formDirectiveFactory();
var ngFormDirective = formDirectiveFactory(true);
// helper methods
function setupValidity(instance) {
instance.$$classCache = {};
instance.$$classCache[INVALID_CLASS] = !(instance.$$classCache[VALID_CLASS] = instance.$$element.hasClass(VALID_CLASS));
}
function addSetValidityMethod(context) {
var clazz = context.clazz,
set = context.set,
unset = context.unset;
clazz.prototype.$setValidity = function(validationErrorKey, state, controller) {
if (isUndefined(state)) {
createAndSet(this, '$pending', validationErrorKey, controller);
} else {
unsetAndCleanup(this, '$pending', validationErrorKey, controller);
}
if (!isBoolean(state)) {
unset(this.$error, validationErrorKey, controller);
unset(this.$$success, validationErrorKey, controller);
} else {
if (state) {
unset(this.$error, validationErrorKey, controller);
set(this.$$success, validationErrorKey, controller);
} else {
set(this.$error, validationErrorKey, controller);
unset(this.$$success, validationErrorKey, controller);
}
}
if (this.$pending) {
cachedToggleClass(this, PENDING_CLASS, true);
this.$valid = this.$invalid = undefined;
toggleValidationCss(this, '', null);
} else {
cachedToggleClass(this, PENDING_CLASS, false);
this.$valid = isObjectEmpty(this.$error);
this.$invalid = !this.$valid;
toggleValidationCss(this, '', this.$valid);
}
// re-read the state as the set/unset methods could have
// combined state in this.$error[validationError] (used for forms),
// where setting/unsetting only increments/decrements the value,
// and does not replace it.
var combinedState;
if (this.$pending && this.$pending[validationErrorKey]) {
combinedState = undefined;
} else if (this.$error[validationErrorKey]) {
combinedState = false;
} else if (this.$$success[validationErrorKey]) {
combinedState = true;
} else {
combinedState = null;
}
toggleValidationCss(this, validationErrorKey, combinedState);
this.$$parentForm.$setValidity(validationErrorKey, combinedState, this);
};
function createAndSet(ctrl, name, value, controller) {
if (!ctrl[name]) {
ctrl[name] = {};
}
set(ctrl[name], value, controller);
}
function unsetAndCleanup(ctrl, name, value, controller) {
if (ctrl[name]) {
unset(ctrl[name], value, controller);
}
if (isObjectEmpty(ctrl[name])) {
ctrl[name] = undefined;
}
}
function cachedToggleClass(ctrl, className, switchValue) {
if (switchValue && !ctrl.$$classCache[className]) {
ctrl.$$animate.addClass(ctrl.$$element, className);
ctrl.$$classCache[className] = true;
} else if (!switchValue && ctrl.$$classCache[className]) {
ctrl.$$animate.removeClass(ctrl.$$element, className);
ctrl.$$classCache[className] = false;
}
}
function toggleValidationCss(ctrl, validationErrorKey, isValid) {
validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : '';
cachedToggleClass(ctrl, VALID_CLASS + validationErrorKey, isValid === true);
cachedToggleClass(ctrl, INVALID_CLASS + validationErrorKey, isValid === false);
}
}
function isObjectEmpty(obj) {
if (obj) {
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
return false;
}
}
}
return true;
}
+54 -81
View File
@@ -679,17 +679,7 @@ var inputType = {
* @param {string} ngModel Assignable angular expression to data-bind to.
* @param {string=} name Property name of the form under which the control is published.
* @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
* Can be interpolated.
* @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
* Can be interpolated.
* @param {string=} ngMin Like `min`, sets the `min` validation error key if the value entered is less than `ngMin`,
* but does not trigger HTML5 native validation. Takes an expression.
* @param {string=} ngMax Like `max`, sets the `max` validation error key if the value entered is greater than `ngMax`,
* but does not trigger HTML5 native validation. Takes an expression.
* @param {string=} step Sets the `step` validation error key if the value entered does not fit the `step` constraint.
* Can be interpolated.
* @param {string=} ngStep Like `step`, sets the `step` validation error key if the value entered does not fit the `ngStep` constraint,
* but does not trigger HTML5 native validation. Takes an expression.
* @param {string=} required Sets `required` validation error key if the value is not entered.
* @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
* the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
@@ -1044,6 +1034,28 @@ var inputType = {
* @description
* Native range input with validation and transformation.
*
* <div class="alert alert-warning">
* <p>
* In v1.5.9+, in order to avoid interfering with already existing, custom directives for
* `input[range]`, you need to let Angular know that you want to enable its built-in support.
* You can do this by adding the `ng-input-range` attribute to the input element. E.g.:
* `<input type="range" ng-input-range ... />`
* </p><br />
* <p>
* Input elements without the `ng-input-range` attibute will continue to be treated the same
* as in previous versions (e.g. their model value will be a string not a number and Angular
* will not take `min`/`max`/`step` attributes and properties into account).
* </p><br />
* <p>
* **Note:** From v1.6.x onwards, the support for `input[range]` will be always enabled and
* the `ng-input-range` attribute will have no effect.
* </p><br />
* <p>
* This documentation page refers to elements which have the built-in support enabled; i.e.
* elements _with_ the `ng-input-range` attribute.
* </p>
* </div>
*
* The model for the range input must always be a `Number`.
*
* IE9 and other browsers that do not support the `range` type fall back
@@ -1065,7 +1077,7 @@ var inputType = {
*
* Since the element value should always reflect the current model value, a range input
* will set the bound ngModel expression to the value that the browser has set for the
* input element. For example, in the following input `<input type="range" ng-model="model.value">`,
* input element. For example, in the following input `<input type="range" ng-input-range ng-model="model.value">`,
* if the application sets `model.value = null`, the browser will set the input to `'50'`.
* Angular will then set the model to `50`, to prevent input and model value being out of sync.
*
@@ -1084,10 +1096,12 @@ var inputType = {
* instead may set the `stepMismatch` error. If that's the case, the Angular will set the `step`
* error on the input, and set the model to `undefined`.
*
* Note that `input[range]` is not compatible with`ngMax`, `ngMin`, and `ngStep`, because they do
* Note that `input[range]` is not compatible with `ngMax`, `ngMin`, and `ngStep`, because they do
* not set the `min` and `max` attributes, which means that the browser won't automatically adjust
* the input value based on their values, and will always assume min = 0, max = 100, and step = 1.
*
* @param ngInputRange The presense of this attribute enables the built-in support for
* `input[range]`.
* @param {string} ngModel Assignable angular expression to data-bind to.
* @param {string=} name Property name of the form under which the control is published.
* @param {string=} min Sets the `min` validation to ensure that the value entered is greater
@@ -1115,7 +1129,7 @@ var inputType = {
</script>
<form name="myForm" ng-controller="ExampleController">
Model as range: <input type="range" name="range" ng-model="value" min="{{min}}" max="{{max}}">
Model as range: <input type="range" ng-input-range name="range" ng-model="value" min="{{min}}" max="{{max}}">
<hr>
Model as number: <input type="number" ng-model="value"><br>
Min: <input type="number" ng-model="min"><br>
@@ -1141,7 +1155,7 @@ var inputType = {
}]);
</script>
<form name="myForm" ng-controller="ExampleController">
Model as range: <input type="range" name="range" ng-model="value" ng-min="min" ng-max="max">
Model as range: <input type="range" ng-input-range name="range" ng-model="value" ng-min="min" ng-max="max">
<hr>
Model as number: <input type="number" ng-model="value"><br>
Min: <input type="number" ng-model="min"><br>
@@ -1427,7 +1441,7 @@ function createDateInputType(type, regexp, parseDate, format) {
return function dynamicDateInputType(scope, element, attr, ctrl, $sniffer, $browser, $filter) {
badInputChecker(scope, element, attr, ctrl);
baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
var timezone = ctrl && ctrl.$options.getOption('timezone');
var timezone = ctrl && ctrl.$options && ctrl.$options.timezone;
var previousDate;
ctrl.$$parserName = type;
@@ -1565,27 +1579,15 @@ function isValidForStep(viewValue, stepBase, step) {
// and `viewValue` is expected to be a valid stringified number.
var value = Number(viewValue);
var isNonIntegerValue = !isNumberInteger(value);
var isNonIntegerStepBase = !isNumberInteger(stepBase);
var isNonIntegerStep = !isNumberInteger(step);
// Due to limitations in Floating Point Arithmetic (e.g. `0.3 - 0.2 !== 0.1` or
// `0.5 % 0.1 !== 0`), we need to convert all numbers to integers.
if (isNonIntegerValue || isNonIntegerStepBase || isNonIntegerStep) {
var valueDecimals = isNonIntegerValue ? countDecimals(value) : 0;
var stepBaseDecimals = isNonIntegerStepBase ? countDecimals(stepBase) : 0;
var stepDecimals = isNonIntegerStep ? countDecimals(step) : 0;
var decimalCount = Math.max(valueDecimals, stepBaseDecimals, stepDecimals);
if (!isNumberInteger(value) || !isNumberInteger(stepBase) || !isNumberInteger(step)) {
var decimalCount = Math.max(countDecimals(value), countDecimals(stepBase), countDecimals(step));
var multiplier = Math.pow(10, decimalCount);
value = value * multiplier;
stepBase = stepBase * multiplier;
step = step * multiplier;
if (isNonIntegerValue) value = Math.round(value);
if (isNonIntegerStepBase) stepBase = Math.round(stepBase);
if (isNonIntegerStep) step = Math.round(step);
}
return (value - stepBase) % step === 0;
@@ -1593,8 +1595,8 @@ function isValidForStep(viewValue, stepBase, step) {
function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
badInputChecker(scope, element, attr, ctrl);
numberFormatterParser(ctrl);
baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
numberFormatterParser(ctrl);
var minVal;
var maxVal;
@@ -1622,20 +1624,6 @@ function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
ctrl.$validate();
});
}
if (isDefined(attr.step) || attr.ngStep) {
var stepVal;
ctrl.$validators.step = function(modelValue, viewValue) {
return ctrl.$isEmpty(viewValue) || isUndefined(stepVal) ||
isValidForStep(viewValue, minVal || 0, stepVal);
};
attr.$observe('step', function(val) {
stepVal = parseNumberAttrVal(val);
// TODO(matsko): implement validateLater to reduce number of validations
ctrl.$validate();
});
}
}
function rangeInputType(scope, element, attr, ctrl, $sniffer, $browser) {
@@ -1799,20 +1787,14 @@ function emailInputType(scope, element, attr, ctrl, $sniffer, $browser) {
}
function radioInputType(scope, element, attr, ctrl) {
var doTrim = !attr.ngTrim || trim(attr.ngTrim) !== 'false';
// make the name unique, if not defined
if (isUndefined(attr.name)) {
element.attr('name', nextUid());
}
var listener = function(ev) {
var value;
if (element[0].checked) {
value = attr.value;
if (doTrim) {
value = trim(value);
}
ctrl.$setViewValue(value, ev && ev.type);
ctrl.$setViewValue(attr.value, ev && ev.type);
}
};
@@ -1820,10 +1802,9 @@ function radioInputType(scope, element, attr, ctrl) {
ctrl.$render = function() {
var value = attr.value;
if (doTrim) {
value = trim(value);
}
element[0].checked = (value === ctrl.$viewValue);
// We generally use strict comparison. This is behavior we cannot change without a BC.
// eslint-disable-next-line eqeqeq
element[0].checked = (value == ctrl.$viewValue);
};
attr.$observe('value', ctrl.$render);
@@ -2068,7 +2049,11 @@ var inputDirective = ['$browser', '$sniffer', '$filter', '$parse',
link: {
pre: function(scope, element, attr, ctrls) {
if (ctrls[0]) {
(inputType[lowercase(attr.type)] || inputType.text)(scope, element, attr, ctrls[0], $sniffer,
var type = lowercase(attr.type);
if ((type === 'range') && !attr.hasOwnProperty('ngInputRange')) {
type = 'text';
}
(inputType[type] || inputType.text)(scope, element, attr, ctrls[0], $sniffer,
$browser, $filter, $parse);
}
}
@@ -2084,19 +2069,21 @@ var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
* @name ngValue
*
* @description
* Binds the given expression to the value of the element.
* Binds the given expression to the value of `<option>` or {@link input[radio] `input[radio]`},
* so that when the element is selected, the {@link ngModel `ngModel`} of that element is set to
* the bound value.
*
* It is mainly used on {@link input[radio] `input[radio]`} and option elements,
* so that when the element is selected, the {@link ngModel `ngModel`} of that element (or its
* {@link select `select`} parent element) is set to the bound value. It is especially useful
* for dynamically generated lists using {@link ngRepeat `ngRepeat`}, as shown below.
* `ngValue` is useful when dynamically generating lists of radio buttons using
* {@link ngRepeat `ngRepeat`}, as shown below.
*
* It can also be used to achieve one-way binding of a given expression to an input element
* such as an `input[text]` or a `textarea`, when that element does not use ngModel.
* Likewise, `ngValue` can be used to generate `<option>` elements for
* the {@link select `select`} element. In that case however, only strings are supported
* for the `value `attribute, so the resulting `ngModel` will always be a string.
* Support for `select` models with non-string values is available via `ngOptions`.
*
* @element input
* @param {string=} ngValue angular expression, whose value will be bound to the `value` attribute
* and `value` property of the element.
* of the `input` element
*
* @example
<example name="ngValue-directive" module="valueExample">
@@ -2135,36 +2122,22 @@ var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
</example>
*/
var ngValueDirective = function() {
/**
* inputs use the value attribute as their default value if the value property is not set.
* Once the value property has been set (by adding input), it will not react to changes to
* the value attribute anymore. Setting both attribute and property fixes this behavior, and
* makes it possible to use ngValue as a sort of one-way bind.
*/
function updateElementValue(element, attr, value) {
// Support: IE9 only
// In IE9 values are converted to string (e.g. `input.value = null` results in `input.value === 'null'`).
var propValue = isDefined(value) ? value : (msie === 9) ? '' : null;
element.prop('value', propValue);
attr.$set('value', value);
}
return {
restrict: 'A',
priority: 100,
compile: function(tpl, tplAttr) {
if (CONSTANT_VALUE_REGEXP.test(tplAttr.ngValue)) {
return function ngValueConstantLink(scope, elm, attr) {
var value = scope.$eval(attr.ngValue);
updateElementValue(elm, attr, value);
attr.$set('value', scope.$eval(attr.ngValue));
};
} else {
return function ngValueLink(scope, elm, attr) {
scope.$watch(attr.ngValue, function valueWatchAction(value) {
updateElementValue(elm, attr, value);
attr.$set('value', value);
});
};
}
}
};
};
+1 -1
View File
@@ -60,7 +60,7 @@ var ngBindDirective = ['$compile', function($compile) {
$compile.$$addBindingInfo(element, attr.ngBind);
element = element[0];
scope.$watch(attr.ngBind, function ngBindWatchAction(value) {
element.textContent = stringify(value);
element.textContent = isUndefined(value) ? '' : value;
});
};
}
+87 -136
View File
@@ -8,71 +8,51 @@
function classDirective(name, selector) {
name = 'ngClass' + name;
var indexWatchExpression;
return ['$parse', function($parse) {
return ['$animate', function($animate) {
return {
restrict: 'AC',
link: function(scope, element, attr) {
var expression = attr[name].trim();
var isOneTime = (expression.charAt(0) === ':') && (expression.charAt(1) === ':');
var oldVal;
var watchInterceptor = isOneTime ? toFlatValue : toClassString;
var watchExpression = $parse(expression, watchInterceptor);
var watchAction = isOneTime ? ngClassOneTimeWatchAction : ngClassWatchAction;
attr.$observe('class', function(value) {
ngClassWatchAction(scope.$eval(attr[name]));
});
var classCounts = element.data('$classCounts');
var oldModulo = true;
var oldClassString;
if (!classCounts) {
// Use createMap() to prevent class assumptions involving property
// names in Object.prototype
classCounts = createMap();
element.data('$classCounts', classCounts);
}
if (name !== 'ngClass') {
if (!indexWatchExpression) {
indexWatchExpression = $parse('$index', function moduloTwo($index) {
// eslint-disable-next-line no-bitwise
return $index & 1;
});
}
scope.$watch(indexWatchExpression, ngClassIndexWatchAction);
scope.$watch('$index', function($index, old$index) {
/* eslint-disable no-bitwise */
var mod = $index & 1;
if (mod !== (old$index & 1)) {
var classes = arrayClasses(oldVal);
if (mod === selector) {
addClasses(classes);
} else {
removeClasses(classes);
}
}
/* eslint-enable */
});
}
scope.$watch(watchExpression, watchAction, isOneTime);
scope.$watch(attr[name], ngClassWatchAction, true);
function addClasses(classString) {
classString = digestClassCounts(split(classString), 1);
attr.$addClass(classString);
function addClasses(classes) {
var newClasses = digestClassCounts(classes, 1);
attr.$addClass(newClasses);
}
function removeClasses(classString) {
classString = digestClassCounts(split(classString), -1);
attr.$removeClass(classString);
function removeClasses(classes) {
var newClasses = digestClassCounts(classes, -1);
attr.$removeClass(newClasses);
}
function updateClasses(oldClassString, newClassString) {
var oldClassArray = split(oldClassString);
var newClassArray = split(newClassString);
var toRemoveArray = arrayDifference(oldClassArray, newClassArray);
var toAddArray = arrayDifference(newClassArray, oldClassArray);
var toRemoveString = digestClassCounts(toRemoveArray, -1);
var toAddString = digestClassCounts(toAddArray, 1);
attr.$addClass(toAddString);
attr.$removeClass(toRemoveString);
}
function digestClassCounts(classArray, count) {
function digestClassCounts(classes, count) {
// Use createMap() to prevent class assumptions involving property
// names in Object.prototype
var classCounts = element.data('$classCounts') || createMap();
var classesToUpdate = [];
forEach(classArray, function(className) {
forEach(classes, function(className) {
if (count > 0 || classCounts[className]) {
classCounts[className] = (classCounts[className] || 0) + count;
if (classCounts[className] === +(count > 0)) {
@@ -80,106 +60,77 @@ function classDirective(name, selector) {
}
}
});
element.data('$classCounts', classCounts);
return classesToUpdate.join(' ');
}
function ngClassIndexWatchAction(newModulo) {
// This watch-action should run before the `ngClass[OneTime]WatchAction()`, thus it
// adds/removes `oldClassString`. If the `ngClass` expression has changed as well, the
// `ngClass[OneTime]WatchAction()` will update the classes.
if (newModulo === selector) {
addClasses(oldClassString);
function updateClasses(oldClasses, newClasses) {
var toAdd = arrayDifference(newClasses, oldClasses);
var toRemove = arrayDifference(oldClasses, newClasses);
toAdd = digestClassCounts(toAdd, 1);
toRemove = digestClassCounts(toRemove, -1);
if (toAdd && toAdd.length) {
$animate.addClass(element, toAdd);
}
if (toRemove && toRemove.length) {
$animate.removeClass(element, toRemove);
}
}
function ngClassWatchAction(newVal) {
// eslint-disable-next-line no-bitwise
if (selector === true || (scope.$index & 1) === selector) {
var newClasses = arrayClasses(newVal || []);
if (!oldVal) {
addClasses(newClasses);
} else if (!equals(newVal,oldVal)) {
var oldClasses = arrayClasses(oldVal);
updateClasses(oldClasses, newClasses);
}
}
if (isArray(newVal)) {
oldVal = newVal.map(function(v) { return shallowCopy(v); });
} else {
removeClasses(oldClassString);
oldVal = shallowCopy(newVal);
}
oldModulo = newModulo;
}
function ngClassOneTimeWatchAction(newClassValue) {
var newClassString = toClassString(newClassValue);
if (newClassString !== oldClassString) {
ngClassWatchAction(newClassString);
}
}
function ngClassWatchAction(newClassString) {
if (oldModulo === selector) {
updateClasses(oldClassString, newClassString);
}
oldClassString = newClassString;
}
}
};
}];
// Helpers
function arrayDifference(tokens1, tokens2) {
if (!tokens1 || !tokens1.length) return [];
if (!tokens2 || !tokens2.length) return tokens1;
function arrayDifference(tokens1, tokens2) {
var values = [];
var values = [];
outer:
for (var i = 0; i < tokens1.length; i++) {
var token = tokens1[i];
for (var j = 0; j < tokens2.length; j++) {
if (token === tokens2[j]) continue outer;
}
values.push(token);
}
return values;
}
function split(classString) {
return classString && classString.split(' ');
}
function toClassString(classValue) {
var classString = classValue;
if (isArray(classValue)) {
classString = classValue.map(toClassString).join(' ');
} else if (isObject(classValue)) {
classString = Object.keys(classValue).
filter(function(key) { return classValue[key]; }).
join(' ');
}
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;
outer:
for (var i = 0; i < tokens1.length; i++) {
var token = tokens1[i];
for (var j = 0; j < tokens2.length; j++) {
if (token === tokens2[j]) continue outer;
}
return value;
});
if (hasUndefined) {
// Prevent the `oneTimeLiteralWatchInterceptor` from unregistering
// the watcher, by including at least one `undefined` value.
flatValue.push(undefined);
values.push(token);
}
return values;
}
return flatValue;
}
function arrayClasses(classVal) {
var classes = [];
if (isArray(classVal)) {
forEach(classVal, function(v) {
classes = classes.concat(arrayClasses(v));
});
return classes;
} else if (isString(classVal)) {
return classVal.split(' ');
} else if (isObject(classVal)) {
forEach(classVal, function(v, k) {
if (v) {
classes = classes.concat(k.split(' '));
}
});
return classes;
}
return classVal;
}
}];
}
/**
+1 -1
View File
@@ -33,7 +33,7 @@
*
* If the current `$controllerProvider` is configured to use globals (via
* {@link ng.$controllerProvider#allowGlobals `$controllerProvider.allowGlobals()` }), this may
* also be the name of a globally accessible constructor function (deprecated, not recommended).
* also be the name of a globally accessible constructor function (not recommended).
*
* @example
* Here is a simple form for editing user contact information. Adding, removing, clearing, and
+6 -6
View File
@@ -53,15 +53,15 @@ forEach(
return {
restrict: 'A',
compile: function($element, attr) {
// NOTE:
// We expose the powerful `$event` object on the scope that provides access to the Window,
// etc. This is OK, because expressions are not sandboxed any more (and the expression
// sandbox was never meant to be a security feature anyway).
var fn = $parse(attr[directiveName]);
// We expose the powerful $event object on the scope that provides access to the Window,
// etc. that isn't protected by the fast paths in $parse. We explicitly request better
// checks at the cost of speed since event handler expressions are not executed as
// frequently as regular change detection.
var fn = $parse(attr[directiveName], /* interceptorFn */ null, /* expensiveChecks */ true);
return function ngEventHandler(scope, element) {
element.on(eventName, function(event) {
var callback = function() {
fn(scope, {$event: event});
fn(scope, {$event:event});
};
if (forceAsyncEvents[eventName] && $rootScope.$$phase) {
scope.$evalAsync(callback);
+3 -1
View File
@@ -91,7 +91,9 @@ var ngListDirective = function() {
priority: 100,
require: 'ngModel',
link: function(scope, element, attr, ctrl) {
var ngList = attr.ngList || ', ';
// We want to control whitespace trimming so we use this convoluted approach
// to access the ngList attribute, which doesn't pre-trim the attribute
var ngList = element.attr(attr.$attr.ngList) || ', ';
var trimValues = attr.ngTrim !== 'false';
var separator = trimValues ? trim(ngList) : ngList;
File diff suppressed because it is too large Load Diff
-366
View File
@@ -1,366 +0,0 @@
'use strict';
/* exported defaultModelOptions */
var defaultModelOptions;
var DEFAULT_REGEXP = /(\s+|^)default(\s+|$)/;
/**
* @ngdoc type
* @name ModelOptions
* @description
* A container for the options set by the {@link ngModelOptions} directive
*/
function ModelOptions(options) {
this.$$options = options;
}
ModelOptions.prototype = {
/**
* @ngdoc method
* @name ModelOptions#getOption
* @param {string} name the name of the option to retrieve
* @returns {*} the value of the option
* @description
* Returns the value of the given option
*/
getOption: function(name) {
return this.$$options[name];
},
/**
* @ngdoc method
* @name ModelOptions#createChild
* @param {Object} options a hash of options for the new child that will override the parent's options
* @return {ModelOptions} a new `ModelOptions` object initialized with the given options.
*/
createChild: function(options) {
var inheritAll = false;
// make a shallow copy
options = extend({}, options);
// Inherit options from the parent if specified by the value `"$inherit"`
forEach(options, /* @this */ function(option, key) {
if (option === '$inherit') {
if (key === '*') {
inheritAll = true;
} else {
options[key] = this.$$options[key];
// `updateOn` is special so we must also inherit the `updateOnDefault` option
if (key === 'updateOn') {
options.updateOnDefault = this.$$options.updateOnDefault;
}
}
} else {
if (key === 'updateOn') {
// If the `updateOn` property contains the `default` event then we have to remove
// it from the event list and set the `updateOnDefault` flag.
options.updateOnDefault = false;
options[key] = trim(option.replace(DEFAULT_REGEXP, function() {
options.updateOnDefault = true;
return ' ';
}));
}
}
}, this);
if (inheritAll) {
// We have a property of the form: `"*": "$inherit"`
delete options['*'];
defaults(options, this.$$options);
}
// Finally add in any missing defaults
defaults(options, defaultModelOptions.$$options);
return new ModelOptions(options);
}
};
defaultModelOptions = new ModelOptions({
updateOn: '',
updateOnDefault: true,
debounce: 0,
getterSetter: false,
allowInvalid: false,
timezone: null
});
/**
* @ngdoc directive
* @name ngModelOptions
*
* @description
* This directive allows you to modify the behaviour of {@link ngModel} directives within your
* application. You can specify an `ngModelOptions` directive on any element. All {@link ngModel}
* directives will use the options of their nearest `ngModelOptions` ancestor.
*
* The `ngModelOptions` settings are found by evaluating the value of the attribute directive as
* an Angular expression. This expression should evaluate to an object, whose properties contain
* the settings. For example: `<div "ng-model-options"="{ debounce: 100 }"`.
*
* ## Inheriting Options
*
* You can specify that an `ngModelOptions` setting should be inherited from a parent `ngModelOptions`
* directive by giving it the value of `"$inherit"`.
* Then it will inherit that setting from the first `ngModelOptions` directive found by traversing up the
* DOM tree. If there is no ancestor element containing an `ngModelOptions` directive then default settings
* will be used.
*
* For example given the following fragment of HTML
*
*
* ```html
* <div ng-model-options="{ allowInvalid: true, debounce: 200 }">
* <form ng-model-options="{ updateOn: 'blur', allowInvalid: '$inherit' }">
* <input ng-model-options="{ updateOn: 'default', allowInvalid: '$inherit' }" />
* </form>
* </div>
* ```
*
* the `input` element will have the following settings
*
* ```js
* { allowInvalid: true, updateOn: 'default', debounce: 0 }
* ```
*
* Notice that the `debounce` setting was not inherited and used the default value instead.
*
* You can specify that all undefined settings are automatically inherited from an ancestor by
* including a property with key of `"*"` and value of `"$inherit"`.
*
* For example given the following fragment of HTML
*
*
* ```html
* <div ng-model-options="{ allowInvalid: true, debounce: 200 }">
* <form ng-model-options="{ updateOn: 'blur', "*": '$inherit' }">
* <input ng-model-options="{ updateOn: 'default', "*": '$inherit' }" />
* </form>
* </div>
* ```
*
* the `input` element will have the following settings
*
* ```js
* { allowInvalid: true, updateOn: 'default', debounce: 200 }
* ```
*
* Notice that the `debounce` setting now inherits the value from the outer `<div>` element.
*
* If you are creating a reusable component then you should be careful when using `"*": "$inherit"`
* since you may inadvertently inherit a setting in the future that changes the behavior of your component.
*
*
* ## Triggering and debouncing model updates
*
* The `updateOn` and `debounce` properties allow you to specify a custom list of events that will
* trigger a model update and/or a debouncing delay so that the actual update only takes place when
* a timer expires; this timer will be reset after another change takes place.
*
* Given the nature of `ngModelOptions`, the value displayed inside input fields in the view might
* be different from the value in the actual model. This means that if you update the model you
* should also invoke {@link ngModel.NgModelController#$rollbackViewValue} on the relevant input field in
* order to make sure it is synchronized with the model and that any debounced action is canceled.
*
* The easiest way to reference the control's {@link ngModel.NgModelController#$rollbackViewValue}
* method is by making sure the input is placed inside a form that has a `name` attribute. This is
* important because `form` controllers are published to the related scope under the name in their
* `name` attribute.
*
* Any pending changes will take place immediately when an enclosing form is submitted via the
* `submit` event. Note that `ngClick` events will occur before the model is updated. Use `ngSubmit`
* to have access to the updated model.
*
* The following example shows how to override immediate updates. Changes on the inputs within the
* form will update the model only when the control loses focus (blur event). If `escape` key is
* pressed while the input field is focused, the value is reset to the value in the current model.
*
* <example name="ngModelOptions-directive-blur" module="optionsExample">
* <file name="index.html">
* <div ng-controller="ExampleController">
* <form name="userForm">
* <label>
* Name:
* <input type="text" name="userName"
* ng-model="user.name"
* ng-model-options="{ updateOn: 'blur' }"
* ng-keyup="cancel($event)" />
* </label><br />
* <label>
* Other data:
* <input type="text" ng-model="user.data" />
* </label><br />
* </form>
* <pre>user.name = <span ng-bind="user.name"></span></pre>
* </div>
* </file>
* <file name="app.js">
* angular.module('optionsExample', [])
* .controller('ExampleController', ['$scope', function($scope) {
* $scope.user = { name: 'say', data: '' };
*
* $scope.cancel = function(e) {
* if (e.keyCode === 27) {
* $scope.userForm.userName.$rollbackViewValue();
* }
* };
* }]);
* </file>
* <file name="protractor.js" type="protractor">
* var model = element(by.binding('user.name'));
* var input = element(by.model('user.name'));
* var other = element(by.model('user.data'));
*
* it('should allow custom events', function() {
* input.sendKeys(' hello');
* input.click();
* expect(model.getText()).toEqual('say');
* other.click();
* expect(model.getText()).toEqual('say hello');
* });
*
* it('should $rollbackViewValue when model changes', function() {
* input.sendKeys(' hello');
* expect(input.getAttribute('value')).toEqual('say hello');
* input.sendKeys(protractor.Key.ESCAPE);
* expect(input.getAttribute('value')).toEqual('say');
* other.click();
* expect(model.getText()).toEqual('say');
* });
* </file>
* </example>
*
* The next example shows how to debounce model changes. Model will be updated only 1 sec after last change.
* If the `Clear` button is pressed, any debounced action is canceled and the value becomes empty.
*
* <example name="ngModelOptions-directive-debounce" module="optionsExample">
* <file name="index.html">
* <div ng-controller="ExampleController">
* <form name="userForm">
* Name:
* <input type="text" name="userName"
* ng-model="user.name"
* ng-model-options="{ debounce: 1000 }" />
* <button ng-click="userForm.userName.$rollbackViewValue(); user.name=''">Clear</button><br />
* </form>
* <pre>user.name = <span ng-bind="user.name"></span></pre>
* </div>
* </file>
* <file name="app.js">
* angular.module('optionsExample', [])
* .controller('ExampleController', ['$scope', function($scope) {
* $scope.user = { name: 'say' };
* }]);
* </file>
* </example>
*
* ## Model updates and validation
*
* The default behaviour in `ngModel` is that the model value is set to `undefined` when the
* validation determines that the value is invalid. By setting the `allowInvalid` property to true,
* the model will still be updated even if the value is invalid.
*
*
* ## Connecting to the scope
*
* By setting the `getterSetter` property to true you are telling ngModel that the `ngModel` expression
* on the scope refers to a "getter/setter" function rather than the value itself.
*
* The following example shows how to bind to getter/setters:
*
* <example name="ngModelOptions-directive-getter-setter" module="getterSetterExample">
* <file name="index.html">
* <div ng-controller="ExampleController">
* <form name="userForm">
* <label>
* Name:
* <input type="text" name="userName"
* ng-model="user.name"
* ng-model-options="{ getterSetter: true }" />
* </label>
* </form>
* <pre>user.name = <span ng-bind="user.name()"></span></pre>
* </div>
* </file>
* <file name="app.js">
* angular.module('getterSetterExample', [])
* .controller('ExampleController', ['$scope', function($scope) {
* var _name = 'Brian';
* $scope.user = {
* name: function(newName) {
* return angular.isDefined(newName) ? (_name = newName) : _name;
* }
* };
* }]);
* </file>
* </example>
*
*
* ## Specifying timezones
*
* You can specify the timezone that date/time input directives expect by providing its name in the
* `timezone` property.
*
* @param {Object} ngModelOptions options to apply to {@link ngModel} directives on this element and
* and its descendents. Valid keys are:
* - `updateOn`: string specifying which event should the input be bound to. You can set several
* events using an space delimited list. There is a special event called `default` that
* matches the default events belonging to the control.
* - `debounce`: integer value which contains the debounce model update value in milliseconds. A
* value of 0 triggers an immediate update. If an object is supplied instead, you can specify a
* custom value for each event. For example:
* ```
* ng-model-options="{
* updateOn: 'default blur',
* debounce: { 'default': 500, 'blur': 0 }
* }"
* ```
* - `allowInvalid`: boolean value which indicates that the model can be set with values that did
* not validate correctly instead of the default behavior of setting the model to undefined.
* - `getterSetter`: boolean value which determines whether or not to treat functions bound to
* `ngModel` as getters/setters.
* - `timezone`: Defines the timezone to be used to read/write the `Date` instance in the model for
* `<input type="date" />`, `<input type="time" />`, ... . It understands UTC/GMT and the
* continental US time zone abbreviations, but for general use, use a time zone offset, for
* example, `'+0430'` (4 hours, 30 minutes east of the Greenwich meridian)
* If not specified, the timezone of the browser will be used.
*
*/
var ngModelOptionsDirective = function() {
NgModelOptionsController.$inject = ['$attrs', '$scope'];
function NgModelOptionsController($attrs, $scope) {
this.$$attrs = $attrs;
this.$$scope = $scope;
}
NgModelOptionsController.prototype = {
$onInit: function() {
var parentOptions = this.parentCtrl ? this.parentCtrl.$options : defaultModelOptions;
var modelOptionsDefinition = this.$$scope.$eval(this.$$attrs.ngModelOptions);
this.$options = parentOptions.createChild(modelOptionsDefinition);
}
};
return {
restrict: 'A',
// ngModelOptions needs to run before ngModel and input directives
priority: 10,
require: {parentCtrl: '?^^ngModelOptions'},
bindToController: true,
controller: NgModelOptionsController
};
};
// shallow copy over values from `src` that are not already specified on `dst`
function defaults(dst, src) {
forEach(src, function(value, key) {
if (!isDefined(dst[key])) {
dst[key] = value;
}
});
}
+77 -50
View File
@@ -17,12 +17,14 @@ var ngOptionsMinErr = minErr('ngOptions');
* elements for the `<select>` element using the array or object obtained by evaluating the
* `ngOptions` comprehension expression.
*
* In many cases, {@link ng.directive:ngRepeat ngRepeat} can be used on `<option>` elements instead of
* `ngOptions` to achieve a similar result. However, `ngOptions` provides some benefits:
* - more flexibility in how the `<select>`'s model is assigned via the `select` **`as`** part of the
* comprehension expression
* - reduced memory consumption by not creating a new scope for each repeated instance
* - increased render speed by creating the options in a documentFragment instead of individually
* In many cases, {@link ng.directive:ngRepeat ngRepeat} can be used on `<option>` elements
* instead of `ngOptions` to achieve a similar result.
* However, `ngOptions` provides some benefits such as reducing memory and
* increasing speed by not creating a new scope for each repeated instance, as well as providing
* more flexibility in how the `<select>`'s model is assigned via the `select` **`as`** part of the
* comprehension expression. `ngOptions` should be used when the `<select>` model needs to be bound
* to a non-string value. This is because an option element can only be bound to string values at
* present.
*
* When an item in the `<select>` menu is selected, the array element or object property
* represented by the selected option will be bound to the model identified by the `ngModel`
@@ -418,15 +420,16 @@ var ngOptionsDirective = ['$compile', '$document', '$parse', function($compile,
// The emptyOption allows the application developer to provide their own custom "empty"
// option when the viewValue does not match any of the option values.
var emptyOption;
for (var i = 0, children = selectElement.children(), ii = children.length; i < ii; i++) {
if (children[i].value === '') {
selectCtrl.hasEmptyOption = true;
selectCtrl.emptyOption = children.eq(i);
emptyOption = children.eq(i);
break;
}
}
var providedEmptyOption = !!selectCtrl.emptyOption;
var providedEmptyOption = !!emptyOption;
var emptyOptionRendered = false;
var unknownOption = jqLite(optionTemplate.cloneNode(false));
unknownOption.val('?');
@@ -438,9 +441,34 @@ var ngOptionsDirective = ['$compile', '$document', '$parse', function($compile,
// we only need to create it once.
var listFragment = $document[0].createDocumentFragment();
// Overwrite the implementation. ngOptions doesn't use hashes
selectCtrl.generateUnknownOptionValue = function(val) {
return '?';
var renderEmptyOption = function() {
if (!providedEmptyOption) {
selectElement.prepend(emptyOption);
}
selectElement.val('');
if (emptyOptionRendered) {
emptyOption.prop('selected', true); // needed for IE
emptyOption.attr('selected', true);
}
};
var removeEmptyOption = function() {
if (!providedEmptyOption) {
emptyOption.remove();
} else if (emptyOptionRendered) {
emptyOption.removeAttr('selected');
}
};
var renderUnknownOption = function() {
selectElement.prepend(unknownOption);
selectElement.val('?');
unknownOption.prop('selected', true); // needed for IE
unknownOption.attr('selected', true);
};
var removeUnknownOption = function() {
unknownOption.remove();
};
// Update the controller methods for multiple selectable options
@@ -461,8 +489,8 @@ var ngOptionsDirective = ['$compile', '$document', '$parse', function($compile,
// set always
if (selectElement[0].value !== option.selectValue) {
selectCtrl.removeUnknownOption();
selectCtrl.unselectEmptyOption();
removeUnknownOption();
removeEmptyOption();
selectElement[0].value = option.selectValue;
option.element.selected = true;
@@ -470,13 +498,12 @@ 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);
if (value === null || providedEmptyOption) {
removeUnknownOption();
renderEmptyOption();
} else {
selectCtrl.renderUnknownOption(value);
removeEmptyOption();
renderUnknownOption();
}
}
};
@@ -486,8 +513,8 @@ var ngOptionsDirective = ['$compile', '$document', '$parse', function($compile,
var selectedOption = options.selectValueMap[selectElement.val()];
if (selectedOption && !selectedOption.disabled) {
selectCtrl.unselectEmptyOption();
selectCtrl.removeUnknownOption();
removeEmptyOption();
removeUnknownOption();
return options.getViewValueFromOption(selectedOption);
}
return null;
@@ -505,17 +532,22 @@ var ngOptionsDirective = ['$compile', '$document', '$parse', function($compile,
} else {
selectCtrl.writeValue = function writeNgOptionsMultiple(values) {
// 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.
ngModelCtrl.$isEmpty = function(value) {
return !value || value.length === 0;
};
var selectedOptions = values && values.map(getAndUpdateSelectedOption) || [];
selectCtrl.writeValue = function writeNgOptionsMultiple(value) {
options.items.forEach(function(option) {
if (option.element.selected && !includes(selectedOptions, option)) {
option.element.selected = false;
}
option.element.selected = false;
});
if (value) {
value.forEach(function(item) {
var option = options.getOptionFromViewValue(item);
if (option) option.element.selected = true;
});
}
};
@@ -548,44 +580,47 @@ 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();
emptyOption.remove();
// compile the element since there might be bindings in it
$compile(selectCtrl.emptyOption)(scope);
$compile(emptyOption)(scope);
if (selectCtrl.emptyOption[0].nodeType === NODE_TYPE_COMMENT) {
if (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.
selectCtrl.hasEmptyOption = false;
emptyOptionRendered = false;
// Redefine the registerOption function, which will catch
// options that are added by ngIf etc. (rendering of the node is async because of
// lazy transclusion)
selectCtrl.registerOption = function(optionScope, optionEl) {
if (optionEl.val() === '') {
selectCtrl.hasEmptyOption = true;
selectCtrl.emptyOption = optionEl;
selectCtrl.emptyOption.removeClass('ng-scope');
emptyOptionRendered = true;
emptyOption = optionEl;
emptyOption.removeClass('ng-scope');
// This ensures the new empty option is selected if previously no option was selected
ngModelCtrl.$render();
optionEl.on('$destroy', function() {
selectCtrl.hasEmptyOption = false;
selectCtrl.emptyOption = undefined;
emptyOption = undefined;
emptyOptionRendered = false;
});
}
};
} else {
// remove the class, which is added automatically because we recompile the element and it
// becomes the compilation root
selectCtrl.emptyOption.removeClass('ng-scope');
emptyOption.removeClass('ng-scope');
emptyOptionRendered = true;
}
} else {
emptyOption = jqLite(optionTemplate.cloneNode(false));
}
selectElement.empty();
@@ -605,14 +640,6 @@ var ngOptionsDirective = ['$compile', '$document', '$parse', function($compile,
updateOptionElement(option, optionElement);
}
function getAndUpdateSelectedOption(viewValue) {
var option = options.getOptionFromViewValue(viewValue);
var element = option && option.element;
if (element && !element.selected) element.selected = true;
return option;
}
function updateOptionElement(option, element) {
option.element = element;
@@ -655,7 +682,7 @@ var ngOptionsDirective = ['$compile', '$document', '$parse', function($compile,
// Ensure that the empty option is always there if it was explicitly provided
if (providedEmptyOption) {
selectElement.prepend(selectCtrl.emptyOption);
selectElement.prepend(emptyOption);
}
options.items.forEach(function addOption(option) {
+4 -13
View File
@@ -13,8 +13,8 @@
*
* If the transcluded content is not empty (i.e. contains one or more DOM nodes, including whitespace text nodes), any existing
* content of this element will be removed before the transcluded content is inserted.
* If the transcluded content is empty (or only whitespace), the existing content is left intact. This lets you provide fallback
* content in the case that no transcluded content is provided.
* If the transcluded content is empty, the existing content is left intact. This lets you provide fallback content in the case
* that no transcluded content is provided.
*
* @element ANY
*
@@ -47,7 +47,7 @@
* <div ng-controller="ExampleController">
* <input ng-model="title" aria-label="title"> <br/>
* <textarea ng-model="text" aria-label="text"></textarea> <br/>
* <pane title="{{title}}"><span>{{text}}</span></pane>
* <pane title="{{title}}">{{text}}</pane>
* </div>
* </file>
* <file name="protractor.js" type="protractor">
@@ -195,7 +195,7 @@ var ngTranscludeDirective = ['$compile', function($compile) {
}
function ngTranscludeCloneAttachFn(clone, transcludedScope) {
if (clone.length && notWhitespace(clone)) {
if (clone.length) {
$element.append(clone);
} else {
useFallbackContent();
@@ -212,15 +212,6 @@ var ngTranscludeDirective = ['$compile', function($compile) {
$element.append(clone);
});
}
function notWhitespace(nodes) {
for (var i = 0, ii = nodes.length; i < ii; i++) {
var node = nodes[i];
if (node.nodeType !== NODE_TYPE_TEXT || node.nodeValue.trim()) {
return true;
}
}
}
};
}
};
+66 -265
View File
@@ -4,6 +4,15 @@
var noopNgModelController = { $setViewValue: noop, $render: noop };
function chromeHack(optionElement) {
// Workaround for https://code.google.com/p/chromium/issues/detail?id=381459
// Adding an <option selected="selected"> element to a <select required="required"> should
// automatically select the new element
if (optionElement[0].hasAttribute('selected')) {
optionElement[0].selected = true;
}
}
/**
* @ngdoc type
* @name select.SelectController
@@ -16,13 +25,10 @@ var SelectController =
['$element', '$scope', /** @this */ function($element, $scope) {
var self = this,
optionsMap = new NgMap();
self.selectValueMap = {}; // Keys are the hashed values, values the original values
optionsMap = new HashMap();
// If the ngModel doesn't get provided then provide a dummy noop version to prevent errors
self.ngModelCtrl = noopNgModelController;
self.multiple = false;
// The "unknown" option is one that is prepended to the list if the viewValue
// does not match any of the options. When it is rendered the value of the unknown
@@ -31,94 +37,42 @@ var SelectController =
// 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.
self.hasEmptyOption = false;
self.emptyOption = undefined;
self.renderUnknownOption = function(val) {
var unknownVal = self.generateUnknownOptionValue(val);
var unknownVal = '? ' + hashKey(val) + ' ?';
self.unknownOption.val(unknownVal);
$element.prepend(self.unknownOption);
setOptionAsSelected(self.unknownOption);
$element.val(unknownVal);
};
self.updateUnknownOption = function(val) {
var unknownVal = self.generateUnknownOptionValue(val);
self.unknownOption.val(unknownVal);
setOptionAsSelected(self.unknownOption);
$element.val(unknownVal);
};
self.generateUnknownOptionValue = function(val) {
return '? ' + hashKey(val) + ' ?';
};
self.removeUnknownOption = function() {
if (self.unknownOption.parent()) self.unknownOption.remove();
};
self.selectEmptyOption = function() {
if (self.emptyOption) {
$element.val('');
setOptionAsSelected(self.emptyOption);
}
};
self.unselectEmptyOption = function() {
if (self.hasEmptyOption) {
self.emptyOption.removeAttr('selected');
}
};
$scope.$on('$destroy', function() {
// disable unknown option so that we don't do work when the whole select is being destroyed
self.renderUnknownOption = noop;
});
self.removeUnknownOption = function() {
if (self.unknownOption.parent()) self.unknownOption.remove();
};
// Read the value of the select control, the implementation of this changes depending
// upon whether the select can have multiple values and whether ngOptions is at work.
self.readValue = function readSingleValue() {
var val = $element.val();
// ngValue added option values are stored in the selectValueMap, normal interpolations are not
var realVal = val in self.selectValueMap ? self.selectValueMap[val] : val;
if (self.hasOption(realVal)) {
return realVal;
}
return null;
self.removeUnknownOption();
return $element.val();
};
// Write the value to the select control, the implementation of this changes depending
// upon whether the select can have multiple values and whether ngOptions is at work.
self.writeValue = function writeSingleValue(value) {
// Make sure to remove the selected attribute from the previously selected option
// Otherwise, screen readers might get confused
var currentlySelectedOption = $element[0].options[$element[0].selectedIndex];
if (currentlySelectedOption) currentlySelectedOption.removeAttribute('selected');
if (self.hasOption(value)) {
self.removeUnknownOption();
var hashedVal = hashKey(value);
$element.val(hashedVal in self.selectValueMap ? hashedVal : value);
// Set selected attribute and property on selected option for screen readers
var selectedOption = $element[0].options[$element[0].selectedIndex];
setOptionAsSelected(jqLite(selectedOption));
$element.val(value);
if (value === '') self.emptyOption.prop('selected', true); // to make IE9 happy
} else {
if (value == null && self.emptyOption) {
self.removeUnknownOption();
self.selectEmptyOption();
} else if (self.unknownOption.parent().length) {
self.updateUnknownOption(value);
$element.val('');
} else {
self.renderUnknownOption(value);
}
@@ -133,14 +87,12 @@ var SelectController =
assertNotHasOwnProperty(value, '"option value"');
if (value === '') {
self.hasEmptyOption = true;
self.emptyOption = element;
}
var count = optionsMap.get(value) || 0;
optionsMap.set(value, count + 1);
// Only render at the end of a digest. This improves render performance when many options
// are added during a digest and ensures all relevant options are correctly marked as selected
scheduleRender();
optionsMap.put(value, count + 1);
self.ngModelCtrl.$render();
chromeHack(element);
};
// Tell the select control that an option, with the given value, has been removed
@@ -148,13 +100,12 @@ var SelectController =
var count = optionsMap.get(value);
if (count) {
if (count === 1) {
optionsMap.delete(value);
optionsMap.remove(value);
if (value === '') {
self.hasEmptyOption = false;
self.emptyOption = undefined;
}
} else {
optionsMap.set(value, count - 1);
optionsMap.put(value, count - 1);
}
}
};
@@ -165,138 +116,37 @@ var SelectController =
};
var renderScheduled = false;
function scheduleRender() {
if (renderScheduled) return;
renderScheduled = true;
$scope.$$postDigest(function() {
renderScheduled = false;
self.ngModelCtrl.$render();
});
}
self.registerOption = function(optionScope, optionElement, optionAttrs, hasDynamicValueAttr, interpolateTextFn) {
var updateScheduled = false;
function scheduleViewValueUpdate(renderAfter) {
if (updateScheduled) return;
updateScheduled = true;
$scope.$$postDigest(function() {
if ($scope.$$destroyed) return;
updateScheduled = false;
self.ngModelCtrl.$setViewValue(self.readValue());
if (renderAfter) self.ngModelCtrl.$render();
});
}
self.registerOption = function(optionScope, optionElement, optionAttrs, interpolateValueFn, interpolateTextFn) {
if (optionAttrs.$attr.ngValue) {
// The value attribute is set by ngValue
var oldVal, hashedVal = NaN;
if (hasDynamicValueAttr) {
// either "value" is interpolated directly, or set by ngValue
var oldVal;
optionAttrs.$observe('value', function valueAttributeObserveAction(newVal) {
var removal;
var previouslySelected = optionElement.prop('selected');
if (isDefined(hashedVal)) {
self.removeOption(oldVal);
delete self.selectValueMap[hashedVal];
removal = true;
}
hashedVal = hashKey(newVal);
oldVal = newVal;
self.selectValueMap[hashedVal] = newVal;
self.addOption(newVal, optionElement);
// Set the attribute directly instead of using optionAttrs.$set - this stops the observer
// from firing a second time. Other $observers on value will also get the result of the
// ngValue expression, not the hashed value
optionElement.attr('value', hashedVal);
if (removal && previouslySelected) {
scheduleViewValueUpdate();
}
});
} else if (interpolateValueFn) {
// The value attribute is interpolated
optionAttrs.$observe('value', function valueAttributeObserveAction(newVal) {
// This method is overwritten in ngOptions and has side-effects!
self.readValue();
var removal;
var previouslySelected = optionElement.prop('selected');
if (isDefined(oldVal)) {
self.removeOption(oldVal);
removal = true;
}
oldVal = newVal;
self.addOption(newVal, optionElement);
if (removal && previouslySelected) {
scheduleViewValueUpdate();
}
});
} else if (interpolateTextFn) {
// The text content is interpolated
optionScope.$watch(interpolateTextFn, function interpolateWatchAction(newVal, oldVal) {
optionAttrs.$set('value', newVal);
var previouslySelected = optionElement.prop('selected');
if (oldVal !== newVal) {
self.removeOption(oldVal);
}
self.addOption(newVal, optionElement);
if (oldVal && previouslySelected) {
scheduleViewValueUpdate();
}
});
} else {
// The value attribute is static
self.addOption(optionAttrs.value, optionElement);
}
optionAttrs.$observe('disabled', function(newVal) {
// Since model updates will also select disabled options (like ngOptions),
// we only have to handle options becoming disabled, not enabled
if (newVal === 'true' || newVal && optionElement.prop('selected')) {
if (self.multiple) {
scheduleViewValueUpdate(true);
} else {
self.ngModelCtrl.$setViewValue(null);
self.ngModelCtrl.$render();
}
}
});
optionElement.on('$destroy', function() {
var currentValue = self.readValue();
var removeValue = optionAttrs.value;
self.removeOption(removeValue);
scheduleRender();
if (self.multiple && currentValue && currentValue.indexOf(removeValue) !== -1 ||
currentValue === removeValue
) {
// When multiple (selected) options are destroyed at the same time, we don't want
// to run a model update for each of them. Instead, run a single update in the $$postDigest
scheduleViewValueUpdate(true);
}
self.removeOption(optionAttrs.value);
self.ngModelCtrl.$render();
});
};
function setOptionAsSelected(optionEl) {
optionEl.prop('selected', true); // needed for IE
optionEl.attr('selected', true);
}
}];
/**
@@ -305,7 +155,7 @@ var SelectController =
* @restrict E
*
* @description
* HTML `select` element with angular data-binding.
* HTML `SELECT` element with angular data-binding.
*
* The `select` directive is used together with {@link ngModel `ngModel`} to provide data-binding
* between the scope and the `<select>` control (including setting default values).
@@ -315,24 +165,16 @@ var SelectController =
* When an item in the `<select>` menu is selected, the value of the selected option will be bound
* to the model identified by the `ngModel` directive. With static or repeated options, this is
* the content of the `value` attribute or the textContent of the `<option>`, if the value attribute is missing.
* Value and textContent can be interpolated.
* For dynamic options, use interpolation inside the `value` attribute or the `textContent`. Using
* {@link ngValue ngValue} is also possible (as it sets the `value` attribute), and will take
* precedence over `value` and `textContent`.
*
* ## Matching model and option values
*
* In general, the match between the model and an option is evaluated by strictly comparing the model
* value against the value of the available options.
*
* If you are setting the option value with the option's `value` attribute, or textContent, the
* value will always be a `string` which means that the model value must also be a string.
* Otherwise the `select` directive cannot match them correctly.
*
* To bind the model to a non-string value, you can use one of the following strategies:
* - the {@link ng.ngOptions `ngOptions`} directive
* ({@link ng.select#using-select-with-ngoptions-and-setting-a-default-value})
* - the {@link ng.ngValue `ngValue`} directive, which allows arbitrary expressions to be
* option values ({@link ng.select#using-ngvalue-to-bind-the-model-to-an-array-of-objects Example})
* - model $parsers / $formatters to convert the string value
* ({@link ng.select#binding-select-to-a-non-string-value-via-ngmodel-parsing-formatting Example})
* <div class="alert alert-warning">
* Note that the value of a `select` directive used without `ngOptions` is always a string.
* When the model needs to be bound to a non-string value, you must either explicitly convert it
* using a directive (see example below) or use `ngOptions` to specify the set of options.
* This is because an option element can only be bound to string values at present.
* </div>
*
* If the viewValue of `ngModel` does not match any of the options, then the control
* will automatically add an "unknown" option, which it then removes when the mismatch is resolved.
@@ -341,17 +183,13 @@ var SelectController =
* be nested into the `<select>` element. This element will then represent the `null` or "not selected"
* option. See example below for demonstration.
*
* ## Choosing between `ngRepeat` and `ngOptions`
*
* <div class="alert alert-info">
* In many cases, `ngRepeat` can be used on `<option>` elements instead of {@link ng.directive:ngOptions
* ngOptions} to achieve a similar result. However, `ngOptions` provides some benefits:
* - more flexibility in how the `<select>`'s model is assigned via the `select` **`as`** part of the
* comprehension expression
* - reduced memory consumption by not creating a new scope for each repeated instance
* - increased render speed by creating the options in a documentFragment instead of individually
*
* Specifically, select with repeated options slows down significantly starting at 2000 options in
* Chrome and Internet Explorer / Edge.
* ngOptions} to achieve a similar result. However, `ngOptions` provides some benefits, such as
* more flexibility in how the `<select>`'s model is assigned via the `select` **`as`** part of the
* comprehension expression, and additionally in reducing memory and increasing speed by not creating
* a new scope for each repeated instance.
* </div>
*
*
* @param {string} ngModel Assignable angular expression to data-bind to.
@@ -417,24 +255,24 @@ var SelectController =
*</example>
*
* ### Using `ngRepeat` to generate `select` options
* <example name="select-ngrepeat" module="ngrepeatSelect">
* <example name="ngrepeat-select" module="ngrepeatSelect">
* <file name="index.html">
* <div ng-controller="ExampleController">
* <form name="myForm">
* <label for="repeatSelect"> Repeat select: </label>
* <select name="repeatSelect" id="repeatSelect" ng-model="data.model">
* <select name="repeatSelect" id="repeatSelect" ng-model="data.repeatSelect">
* <option ng-repeat="option in data.availableOptions" value="{{option.id}}">{{option.name}}</option>
* </select>
* </form>
* <hr>
* <tt>model = {{data.model}}</tt><br/>
* <tt>repeatSelect = {{data.repeatSelect}}</tt><br/>
* </div>
* </file>
* <file name="app.js">
* angular.module('ngrepeatSelect', [])
* .controller('ExampleController', ['$scope', function($scope) {
* $scope.data = {
* model: null,
* repeatSelect: null,
* availableOptions: [
* {id: '1', name: 'Option A'},
* {id: '2', name: 'Option B'},
@@ -445,37 +283,6 @@ var SelectController =
* </file>
*</example>
*
* ### Using `ngValue` to bind the model to an array of objects
* <example name="select-ngvalue" module="ngvalueSelect">
* <file name="index.html">
* <div ng-controller="ExampleController">
* <form name="myForm">
* <label for="ngvalueselect"> ngvalue select: </label>
* <select size="6" name="ngvalueselect" ng-model="data.model" multiple>
* <option ng-repeat="option in data.availableOptions" ng-value="option.value">{{option.name}}</option>
* </select>
* </form>
* <hr>
* <pre>model = {{data.model | json}}</pre><br/>
* </div>
* </file>
* <file name="app.js">
* angular.module('ngvalueSelect', [])
* .controller('ExampleController', ['$scope', function($scope) {
* $scope.data = {
* model: null,
* availableOptions: [
{value: 'myString', name: 'string'},
{value: 1, name: 'integer'},
{value: true, name: 'boolean'},
{value: null, name: 'null'},
{value: {prop: 'value'}, name: 'object'},
{value: ['a'], name: 'array'}
* ]
* };
* }]);
* </file>
*</example>
*
* ### Using `select` with `ngOptions` and setting a default value
* See the {@link ngOptions ngOptions documentation} for more `ngOptions` usage examples.
@@ -562,16 +369,11 @@ var selectDirective = function() {
function selectPreLink(scope, element, attr, ctrls) {
var selectCtrl = ctrls[0];
// if ngModel is not defined, we don't need to do anything
var ngModelCtrl = ctrls[1];
if (!ngModelCtrl) return;
// if ngModel is not defined, we don't need to do anything but set the registerOption
// function to noop, so options don't get added internally
if (!ngModelCtrl) {
selectCtrl.registerOption = noop;
return;
}
var selectCtrl = ctrls[0];
selectCtrl.ngModelCtrl = ngModelCtrl;
@@ -579,7 +381,6 @@ var selectDirective = function() {
// to the `readValue` method, which can be changed if the select can have multiple
// selected values or if the options are being generated by `ngOptions`
element.on('change', function() {
selectCtrl.removeUnknownOption();
scope.$apply(function() {
ngModelCtrl.$setViewValue(selectCtrl.readValue());
});
@@ -590,15 +391,13 @@ var selectDirective = function() {
// we have to add an extra watch since ngModel doesn't work well with arrays - it
// doesn't trigger rendering if only an item in the array changes.
if (attr.multiple) {
selectCtrl.multiple = true;
// Read value now needs to check each option to see if it is selected
selectCtrl.readValue = function readMultipleValue() {
var array = [];
forEach(element.find('option'), function(option) {
if (option.selected && !option.disabled) {
var val = option.value;
array.push(val in selectCtrl.selectValueMap ? selectCtrl.selectValueMap[val] : val);
if (option.selected) {
array.push(option.value);
}
});
return array;
@@ -606,9 +405,9 @@ var selectDirective = function() {
// Write value now needs to set the selected property of each matching option
selectCtrl.writeValue = function writeMultipleValue(value) {
var items = new HashMap(value);
forEach(element.find('option'), function(option) {
option.selected = !!value && (includes(value, option.value) ||
includes(value, selectCtrl.selectValueMap[option.value]));
option.selected = isDefined(items.get(option.value));
});
};
@@ -659,13 +458,15 @@ var optionDirective = ['$interpolate', function($interpolate) {
restrict: 'E',
priority: 100,
compile: function(element, attr) {
var interpolateValueFn, interpolateTextFn;
var hasDynamicValueAttr, interpolateTextFn;
if (isDefined(attr.ngValue)) {
// Will be handled by registerOption
// If ngValue is defined, then the value attr will be set to the result of the expression,
// and the selectCtrl must set up an observer
hasDynamicValueAttr = true;
} else if (isDefined(attr.value)) {
// If the value attribute is defined, check if it contains an interpolation
interpolateValueFn = $interpolate(attr.value, true);
// If the value attr contains an interpolation, the selectCtrl must set up an observer
hasDynamicValueAttr = $interpolate(attr.value, true);
} else {
// If the value attribute is not defined then we fall back to the
// text content of the option element, which may be interpolated
@@ -684,7 +485,7 @@ var optionDirective = ['$interpolate', function($interpolate) {
parent.parent().data(selectCtrlName); // in case we are in optgroup
if (selectCtrl) {
selectCtrl.registerOption(scope, element, attr, interpolateValueFn, interpolateTextFn);
selectCtrl.registerOption(scope, element, attr, hasDynamicValueAttr, interpolateTextFn);
}
};
}

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