Compare commits

..

354 Commits

Author SHA1 Message Date
Martin Staffa 0d764b581d fix(ngAnimate): safe-guard against missing document
In tests, the $document service might be mocked out without providing a real
document, which can lead to errors when the animator is attempting to read properties from it.

This commit provides an object {hidden: true}, if the $document service doesn't have 
a document. This will prevent the animation process from trying to run any animations.

This commit also changes the check for document.hidden slightly. It
should be accessed independently of the current animationsEnabled state.
Since animations are only enabled after two digests, it's possible that
some tests never reach the animationsEnabled = true state and therefore
aren't actually checking the document.hidden state, which means that
the previous fix only works if no more than two digests happen in the test.

(#14633)
2016-05-24 16:44:11 +02:00
Igor Minar 57a37fcc20 fix(ngAnimate): guard $document[0].hidden access in case it was mocked out
Some tests mock out  and now that we always access the hidden property, existing
tests can get broken. This change keeps the existing tests working.
2016-05-17 12:52:01 -07:00
Sander Boom 7f6ba5534f docs(guide/$location): fix typo
Closes #14607
2016-05-14 01:55:18 +03:00
Martin Staffa b24bfae585 Revert: ngAnimate changes for listening on visibilitychange
Reverts d3e123b, bf1acf7 and aa28e48.
Backporting the changes is complicated because we don't destroy the rootScope
after each test in 1.4.x
(#14574)
2016-05-09 12:35:07 -07:00
Martin Staffa d3e123b0a6 test($$isDocumentHidden): really fix jasmine syntax 2016-05-06 17:12:17 +02:00
Martin Staffa bf1acf7b21 test($): fix jasmine syntax 2016-05-06 16:30:30 +02:00
Maksim Ryzhikov fdaf4d5e27 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-06 08:14:32 -06:00
FGasper 1c47abc462 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:56:24 +02:00
Stephen Barker 5222703444 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:56:15 +02:00
Michael Warner 4b38b44c91 docs(ngRequired): add 'restrict' info
The Angular Docs do not show the restrictions

Closes #14541
2016-05-06 15:56:01 +02:00
Martin Staffa aa28e48e17 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 #14066
2016-05-06 15:54:49 +02:00
Martin Probst f31586db41 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:26:03 +03:00
Weijing Jay Lin 8337b9b2d4 docs(identity): add example
Closes #14528
2016-04-28 11:07:30 +03:00
Perry Hooker 85a53ea9cd 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:20:54 +03:00
andrea 2d87ef8f23 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:34:11 +03:00
Tim van Dalen 3df8b637f3 docs($anchorScroll): fix link to HTML5 spec
Closes #14364
2016-04-26 00:31:52 +03:00
Georgios Kalpakas 28d3126fe5 test($templateRequest): fix code for jasmine 1.3 2016-04-25 22:14:41 +03:00
Raphael Jamet ad21f8feaf 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:54 +03:00
Georgios Kalpakas 7f2df141cd docs($interpolate): add known issue about end-symbol in expression
This has been discussed in #8642.

Closes #14494
2016-04-22 15:42:51 +03:00
Georgios Kalpakas 4e735e5363 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:42:01 +03:00
cloverharvest a9db6073c9 docs($http): fix a typo (his --> this)
Closes #14430
2016-04-15 01:25:40 +03:00
Martin Staffa e48e27aa2b test(ngAnimate): fix jasmine syntax 2016-04-13 04:00:26 -07:00
Jason Bedard 832b383cbc perf($compile): use createMap() for directive bindings to allow fast forEach
Closes #12529
2016-04-13 12:06:55 +03:00
Martin Staffa c4bff290e5 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-12 20:42:30 +02:00
Martin Staffa 55b00148dd test(ngAnimate): test calling callbacks for various constellations 2016-04-12 20:42:30 +02:00
Martin Staffa 23550b5e27 fix(ngAnimate): fire callbacks in the correct order for certain skipped animations 2016-04-12 20:42:29 +02:00
Georgii Dolzhykov 97d2a08c5a docs(Module): fix parameter names for .decorator()
Closes #14413
2016-04-12 14:52:48 +03:00
aortyl 7f6efb2822 docs(guide/scope): add comma for readability
Closes #14411
2016-04-11 22:23:03 +03:00
David Rodenas Pico b50867001b fix(ngClass): fix watching of an array expression containing an object
Closes #14405
2016-04-11 12:41:29 +03:00
Gene McCulley 8b9ce885d3 docs(numberFilter): fix the description of the returned value
Closes #14408
2016-04-11 12:28:56 +03:00
Jurko Gospodnetić 56dae6fa1b 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:56:16 +03:00
cscport 611dcbc035 docs(angular.bootstrap): fix capitalization in error message
Closes #14325
2016-03-27 15:45:11 +03:00
Martin Staffa 2c9066e012 test(ngMessages): fix most recent call syntax 2016-03-24 11:10:32 +01:00
Martin Staffa 8ecc9357ef test(ngMessages): fix callThrough syntax 2016-03-24 01:08:28 +01:00
Martin Staffa 71dca7c4c2 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:15:35 +01:00
Steve Mao ce77c25b06 docs($q): mention ES2015 (as a "synonym" for ES6) and remove "harmony"
Closes #14294
2016-03-22 12:09:31 +02:00
Owen Craig a1188721e1 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:12:18 +02:00
surya prakash singh 1917ff86c4 docs(input[time]): fix a typo in the example
Closes #14220
2016-03-21 01:26:54 +02:00
Georgios Kalpakas c60e1960c6 docs(CHANGELOG.md): add notes for v1.4.10 2016-03-20 22:49:46 +02:00
Peter Bacon Darwin 268e71eb8b chore(travis): update node and browser versions 2016-03-16 14:37:16 +00:00
Peter Bacon Darwin 03e6fb3df5 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 11:41:30 +00:00
Peter Bacon Darwin 4fc9cf6289 chore(jenkins): update node version to 4.4 2016-03-16 11:41:27 +00:00
Matias Niemela 8dee8f1b9e revert: fix(ngRoute): allow ngView to be included in an asynchronously loaded template
This reverts commit 88322c1af8.
2016-03-14 17:27:49 -04:00
Matias Niemela 1eef631ab5 revert: fix(ngMock): prevent memory leak due to data attached to $rootElement
This reverts commit 571e323f7d.
2016-03-14 17:27:49 -04:00
Matias Niemela 2ef92c329b revert: feat(ngMock): destroy $rootScope after each test 2016-03-14 17:27:49 -04:00
Matias Niemela 1467e15bca revert: fix(ngMock): don't break if $rootScope.$destroy() is not a function
This reverts commit 24a7f28f1e.
2016-03-14 17:27:49 -04:00
Peter Bacon Darwin 389349edc3 docs(guide/location): include section on base[href]
Closes #14018
2016-03-14 14:47:09 +00:00
Martin Staffa 722e97e8e6 docs($provide): clarify value and constant injectability
Closes #14168
2016-03-04 10:03:56 +01:00
Martin Staffa d3933a4181 docs(changelog, migration): add BC notice for allowed form name values
Introduced by https://github.com/angular/angular.js/commit/94533e570673e6b2eb92073955541fa289aabe02

Closes #13771
2016-03-02 19:30:42 +01:00
Georgios Kalpakas 8d02b07af4 docs(errorDisplay): encode < and > in error messages
When an error message contains an HTML string (e.g. `$location:nobase` containing `<base>`), it was
interpreted as a literal HTML element, instead of text. Error messages are not expected to render
as HTML, but we still need to use `.html()` in `errorDisplay`, so that the links created by
`errorLinkFilter` are properly displayed.
This commit solves this issue by replacing `<`/`>` with `&lt;`/`&gt;`.

Related to #14016.
2016-02-29 17:34:11 +01:00
Georgios Kalpakas 24af9e2a6e test(docs): add tests for the errors module 2016-02-29 17:34:04 +01:00
Jason Bedard 4879e49c93 refactor($compile): remove out of date jQuery vs jqLite comment/workaround 2016-02-29 17:33:05 +01:00
Nabil Hashmi aec25f1829 docs($http): fix typo in link text (TransformationjqLiks --> Transformations)
Closes #14149
2016-02-28 23:12:22 +02:00
Martin Staffa f87e8288fb fix(ngOptions): always set the 'selected' attribute for selected options
We don't set selected property / attribute on options that are already selected.
That happens for example if the browser has automatically selected the first
option in a select. In that case, the selected property is set automatically, but
the selected attribute is not

Closes #14115
2016-02-28 16:11:56 +01:00
lordg 9b1beb8e09 docs(guide/Interpolation): fix code example
The function getForm is receiving a variable from the view and should be using that.

Closes #14142
2016-02-28 16:11:55 +01:00
Georgii Dolzhykov 681e6246e3 docs(guide/Services): improve the code example
A factory that doesn't return anything is a bad example of a factory.

Closes #14139
2016-02-28 16:08:16 +01:00
lordg 13e2ea73b0 docs(guide/Templates): add title for consistency
Closes #14141
2016-02-28 16:08:14 +01:00
Martin Staffa f5295ea448 docs(guide/interpolation): make some minor improvements, add info
- highlight that interpolation inside expressions is bad practice
- add info about type attr in buttons in IE
2016-02-28 16:08:13 +01:00
lordg bb01b8bf89 docs(guide/Filters): add title for consistency
Closes #14143
2016-02-28 16:08:11 +01:00
mohamed amr 711aba7727 test(ngAria): remove incorrect closing div tag after input element
Closes #14146
Closes #14147
2016-02-28 16:08:09 +01:00
Georgios Kalpakas 88322c1af8 fix(ngRoute): allow ngView to be included in an asynchronously loaded template
During it's linking phase, `ngView` relies on the info provided in `$route.current` for
instantiating the initial view. `$route.current` is set in the callback of a listener to
`$locationChangeSuccess`, which is registered during the instantiation of the `$route` service.

Thus, it is crucial that the `$route` service is instantiated before the initial
`$locationChangeSuccess` is fired. Since `ngView` declares `$route` as a dependency, the service is
instantiated in time if `ngView` is present during the initial load of the page.

Yet, in cases where `ngView` is included in a template that is loaded asynchronously (e.g. in
another directive's template), the directive factory might not be called soon enough for `$route`
to be instantiated before the initial `$locationChangeSuccess` event is fired.

This commit fixes it, by always instantiating `$route` up front, during the initialization phase.

Fixes #1213
Fixes #6812

Closes #14088
2016-02-25 12:10:03 +02:00
Martin Staffa 18f055eea5 docs($http): add a note about modifying data in transformRequest
Closes #12468
2016-02-24 17:57:45 +01:00
Georgios Kalpakas 24a7f28f1e fix(ngMock): don't break if $rootScope.$destroy() is not a function
Previously, `angular-mocks` was calling `$rootScope.$destroy()` after each test as part of it's
cleaning up, assuming that it was always available. This could break if `$rootScope` was mocked
and the mocked version didn't provide the `$destroy()` method.
This commit prevents the error by first checking that `$rootScope.$destroy` is present.

Fixes #14106

Closes #14107
2016-02-23 23:26:03 +02:00
Igor Dolgov 146f9c1611 docs(ngMock): add missing ")" in example
Closes #14112
2016-02-23 13:56:35 +02:00
Andy Gurden e55829a1cd feat(ngMock): destroy $rootScope after each test
Previously $rootScope would be new for each test, but old $rootScopes would never be destroyed.
Now that we are able to destroy the $rootScope, doing so provides an opportunity for code to clean
up things like long-lived event handlers between tests.

Closes #13433
2016-02-22 17:02:25 +02:00
Georgios Kalpakas 571e323f7d fix(ngMock): prevent memory leak due to data attached to $rootElement
Starting with 88bb551, `ngMock` will attach the `$injector` to the `$rootElement`, but will never
clean it up, resulting in a memory leak. Since a new `$rootElement` is created for every test,
this leak causes Karma to crash on large test-suites.
The problem was not detected by our internal tests, because we do our own clean-up in
`testabilityPatch.js`.

88bb551 was revert with 1b8590a.
This commit incorporates the changes from 88bb551 and prevents the memory leak, by cleaning up all
data attached to `$rootElement` after each test.

Fixes #14094

Closes #14098
2016-02-22 16:42:01 +02:00
Ben Elliott bf11cf3095 docs(ngMessages): clarify ngMessages docs with clearer example
Closes #14103
2016-02-22 12:20:03 +01:00
Kin 5a1e148da6 docs(numberFilter): improve wording for infinity description
Closes #14100
2016-02-22 12:20:00 +01:00
Kin eec095a751 docs(angular.forEach): fix typo 2016-02-22 12:19:56 +01:00
Gordon Zhu 7b2c7cbab8 docs(guide/index): add Firebase Foundations and Angular Course
Closes #14097
2016-02-21 07:52:58 +00:00
Matias Niemelä b830f5b68e revert: fix(ngMock): attach $injector to $rootElement
This reverts commit fad4dc07d7.

The fixes applied in the reverted commit caused a memory leak
with JQuery + Karma.
2016-02-20 22:16:47 -08:00
MicCarr 7e7a0693e5 docs(ngMock): fix typo in example
Closes #14069
2016-02-18 14:58:30 +02:00
Jason Bedard 02929f82f3 fix(input): re-validate when partially editing date-family inputs
Fixes #12207
Closes #13886
2016-02-18 11:04:09 +02:00
ryanhart2 b9d3625e92 docs($http): improve description of caching
Included changes:

* Point out that only GET & JSONP requests are cached.
* Explain that the URL+search params are used as cache keys (headers not considered).
* Add note about cache-control headers on response not affecting Angular caching.
* Mention `$httpProvider.defaults.cache` (in addition to `$http.defaults.cache`).
* Clear up how `defaults.cache` and `config.cache` are taken into account for determining the
  caching behavior for each request.

Fixes #11101
Closes #13003
2016-02-18 01:03:27 +02:00
Georgios Kalpakas 863a4232a6 fix(copy): add support for copying Blob objects
Although `copy()` does not need to (and never will) support all kinds of objects, there is a
(not uncommon) usecase for supporting `Blob` objects:

`ngMock`'s `$httpBackend` will return a copy of the response data (so that changes in one test won't
affect others). Since returning `Blob` objects in response to HTTP requests is a valid usecase and
since `ngMocks`'s `$httpBackend` will use `copy()` to create a copy of that data, it is reasonable
to support `Blob` objects.
(I didn't run any benchmarks, but the additional check for the type of the copied element should
have negligible impact, compared to the other stuff that `copy()` is doing.)

Fixes #9669

Closes #14064
2016-02-17 15:04:52 +02:00
Martin Staffa 4a39ad475b chore(docs-app): fix middle/right dropdown clicks in FF
Closes #14024
2016-02-17 13:45:19 +01:00
Martin Staffa 696d65dcba chore(docs-app): remove obsolete directives
Most of the directives in bootstrap.js haven't been in use since
https://github.com/angular/angular.js/commit/389d4879da4aa620ee95d789b19ff9be44eb730a:
Dropdown-related directives were moved to dropdown-toggle.js, and for
foldout, popover and syntax, the uses and tests were removed, but not the directives themselves.

The last use of tabbable was removed in
https://github.com/angular/angular.js/commit/6b7a1b82bc26bbf4640506a9a3cf37ebf254d3d2
2016-02-17 13:45:17 +01:00
biohazardpb4 947cb4d145 fix(ngMockE2E): pass responseType to $delegate when using passThrough
The `ngMockE2E` `$httpBackend` has a mechanism to allow requests to pass through, if one wants to
send a real HTTP request instead of mocking. The specified `responseType` of the request was never
passed through to the "real" `$httpBackend` (of the `ng` module), resulting in it being effectively
ignored.

Fixes #5415

Closes #5783
2016-02-17 00:59:10 +02:00
Matias Niemelä 77fc41f499 chore: fix version typo 2016-02-16 13:09:11 -08:00
Georgios Kalpakas d98a12a6f2 docs(guide/forms): make required ngModel optional in custom e-mail RegExp example 2016-02-16 23:06:56 +02:00
Matias Niemelä ef2c6e39be chore(build): 1.4 versions should stick to 1.4.x 2016-02-16 12:53:19 -08:00
srijan c219a87ad7 docs(guide/scope): fix typo in image
Closes #13724
2016-02-16 21:51:44 +02:00
Georgios Kalpakas fad4dc07d7 fix(ngMock): attach $injector to $rootElement
Fixes #14022

Closes #14034
2016-02-16 21:44:18 +02:00
Martin Staffa 373f054d5e test(*): ensure console log doesn't break the app in IE9
When Angular is loaded more than once (by including the script multiple times),
a warning is logged in the console. IE9 only makes the console available when
the dev tools are open, so before this fix, the browser would throw an error

Note that Protractor doesn't actually support IE9.
2016-02-16 18:53:00 +01:00
lucienbertin beb00e44de fix(*): only call console.log when window.console exists
`window.console` only exists in IE 8 & 9 when the devtools are open

Fixes #14006
Closes #14007
Closes #14047
2016-02-16 18:52:54 +01:00
Sean Murphy 6a4403a118 fix($routeProvider): properly handle optional eager path named groups
Closes #14011
2016-02-16 14:32:55 +02:00
Lucas Mirelmann 77cdc37c65 fix($compile): allow directives to have decorators
Allow directives to have decorators that modify the directive `scope` property

Close: #10149
2016-02-12 13:22:11 +01:00
Daniel Herman ab95ba65c0 perf(ngAnimate): avoid jqLite/jQuery for upward DOM traversal
The `parentNode` property is well supported between all browsers.  Since
no other functionality was required here other than traversing upwards
using `.parent()`, we can use the DOM API directly.

Closes: #13879
2016-02-12 11:27:35 +01:00
Daniel Herman 86416bcbee perf(ngAnimate): avoid $.fn.data overhead with jQuery
Unlike jqLite, jquery scrapes the attributes of an element looking for
data- keys that match the requested property.  When many elements are
being animated due to something like `ngRepeat` unrolling within one
digest cycle, the amount of time spent in that one function quickly adds
up.

By changing our API to use the lower level data API, we can cut the time
spent in this function by half when jQuery is loaded.
2016-02-12 11:27:35 +01:00
Daniel Herman d04c38c489 perf(ngRepeat): avoid duplicate jqLite wrappers
Internally, `$animate` already wraps elements passed through with
`jqLite`, so we can avoid needless duplication here.
2016-02-12 11:27:34 +01:00
Aashish Nagpal bdc5a1cde1 docs(README.md): add purpose section
Add a new purpose section to enable newcomers (technical and non-technical)
better understand the purpose of AngularJS

Close #13963
2016-02-08 02:12:54 -08:00
John Mercer eccd618d76 docs(guide): add new book
Closes #13954
2016-02-08 02:06:55 -08:00
Martin Staffa 7f11af6b5e docs(error/iscp): extra spaces are allowed 2016-02-05 16:37:50 +01:00
Martin Staffa 437ba49a52 style(filters): squelch a closure compiler warning
Related #13932
2016-02-05 16:23:01 +01:00
Peter Bacon Darwin 9a576fa0fa chore(package): update the 1.4.x dist-tag 2016-02-05 12:52:27 +00:00
kuroky360 b5c317d672 refactor(toJson): use the isUndefined() function
Closes #13923
2016-02-04 10:36:58 +02:00
Georgios Kalpakas 05741ebf0b docs(guide/accessibility): fix links 2016-02-04 00:41:04 +02:00
Georgios Kalpakas 9e2c215779 docs(ngRequired): fix link 2016-02-04 00:20:37 +02:00
Georgii Dolzhykov 8a1f600c29 docs($compile): refine explanation of isolate scope =-binding
The current version of this paragraph is in many ways inaccurate and confusing.

Closes #13921
2016-02-03 15:00:55 +02:00
Georgios Kalpakas 8519b8a60f docs(guide/accessibility): fix links
Closes #13936
2016-02-03 12:21:15 +02:00
Georgios Kalpakas 4bc3031497 fix($route): allow preventing a route reload
Fixes #9824
Closes #13894
2016-02-02 23:16:09 +02:00
Lucas Mirelmann ab5c7698bb fix($rootScope): Set no context when calling helper functions for $watch
When calling a $watch getter or listener, do not expose the inner workings with `this`.

Closes: #13909
2016-02-01 23:59:54 +02:00
Georgios Kalpakas 89690502d1 docs(guide/directive): minor fixes/improvements
Closes #13908
2016-02-01 15:15:35 +01:00
Lucas Mirelmann f47e218006 fix($parse): prevent assignment on constructor properties
Prevent malicious attacks involving assignment on `constructor` properties.

Closes #13417
2016-01-31 20:21:41 +00:00
Wojciech Krzystek 8dc4c75ade docs($http): reword the XSRF attack overview
Previous version emphasised "gaining user's private data".
While this perfectly describes JSON vulnerability (which is based on XSRF),
data theft suits XSS more.
Pure XSRF is more about performing requests that have side effects.

Closes #13901
2016-01-31 13:23:16 +02:00
Prayag Verma e91811095b docs(misc/downloading): fix typo (it --> in)
Closes #13899
2016-01-31 10:46:35 +02:00
Smith afb298b7ff docs(error/$rootScope:inprog): fix typos ("a $apply" --> "an $apply")
Closes #13896
2016-01-31 10:35:33 +02:00
Georgios Kalpakas 571afd6558 fix(dateFilter, input): fix Date parsing in IE/Edge when timezone offset contains :
When `Date.parse`-ing a date string, IE and Edge don't recognize the timezone offset in the format
`+HH:mm` (but only without the `:`). According to [the spec][1], the timezone offset should
contain `:`. The [ISO 8601 Standard][2] allows both forms (with and without `:`).
Although the `Date` implementation in JavaScript does not 100% follow the ISO 8601 Standard (it's
just _based on it_), all other browsers seem to recognize both forms as well.

[1]: http://www.ecma-international.org/ecma-262/5.1/#sec-15.9.1.15
[2]: https://en.wikipedia.org/wiki/ISO_8601#Time_offsets_from_UTC

Fixes #13880

Closes #13887
2016-01-30 00:08:47 +02:00
Georgios Kalpakas df6e731506 fix(select): handle corner case of adding options via a custom directive
Under specific circumstances (e.g. adding options via a directive with `replace: true` and a
structural directive in its template), an error occurred when trying to call `hasAttribute()` on a
comment node (which doesn't support that method).
This commit fixes it by filtering out comment nodes in the `addOption()` method.

Fixes #13874
Closes #13878
2016-01-29 14:37:06 +02:00
Martin Staffa af9c2d71e2 docs(ngAnimateChildren) add docs 2016-01-28 21:40:22 +01:00
Martin Staffa dc158e7e40 fix(ngAnimateChildren): make it compatible with ngIf
Previously, ngAnimateChildren would set the data on the element
in an $observe listener, which means the data was available after one digest happend.
This is too late when the element is animated immediately after compilation, as happens with ngIf.
Now the data is also set right in the linking function.

Fixes #13865
Closes #13876
2016-01-28 21:40:22 +01:00
Lucas Mirelmann 0b7fff303f fix($parse): Copy inputs for expressions with expensive checks
Closes: #13871
2016-01-28 21:13:48 +02:00
Lucas Mirelmann 96d62cc0fc fix($parse): Preserve expensive checks when runnning $eval inside an expression
When running an expression with expensive checks, there is a call to `$eval` or `$evalAsync`
then that expression is also evaluated using expensive checks

Closes: #13850
2016-01-28 19:21:39 +02:00
Michael 5cb7d0e046 docs($compile): minor typo/style correction
Closes #13864
2016-01-28 19:19:40 +02:00
Martin Staffa a60bbc12e8 fix($animateCss): cancel fallback timeout when animation ends normally
Previously, css animations would not cancel the timeout when the
animation ends normally (calling end explicitly / transitionEnd event).
This meant that the timeout callback fn was always called after 150% of
the animation time was over. Since the animation was already closed at this
point, it would not do any work twice, but simply remove the timer data
from the element.
This commit changes the behavior to cancel the timeout and remove the data
when it is found during animation closing.

Closes #13787
2016-01-27 19:28:36 +01:00
Isaac ca23d5f68f docs($cookiesProvider): clarify parameters description
Fixed a grammatical mistake ("equals to"), made hyphenation consistent, fixed punctuation and
clarified the sentence structure.

Closes #13853
2016-01-27 16:32:48 +01:00
Thomas Moffett a398773b0c docs(guide): change concepts.graffle/data.plist to fix 'World' spelling
The change is only to concepts.graffle/data.plist to fix 'World' spelling.
Another PR, #13724, already fixed the actual image.

Closes #13704
Closes #13734
2016-01-27 15:01:10 +00:00
robw 1ef741563d docs(ngModel): add section explaining that ngModel watches by reference
The new section explains that changing only a property on an object doesn't
trigger re-rendering.

Closes #13224
Closes #13518
2016-01-27 14:25:01 +00:00
Georgios Kalpakas 2d44a681eb fix($compile): properly denormalize templates when only one of the start/end symbols is different
Previously, if either of the start/end interpolation symbols remained unchanged (i.e. `{{` or `}}`),
then directive templates would not be denormalized properly. Changing only one of the start/end
symbols (but not both) is an uncommon but legitimate usecase.

Closes #13848
2016-01-26 20:20:37 +02:00
Leo Gallucci 543af651d0 docs(guide/directives): improve Protractor test for bindings
This needs Protractor >= 1.3.0 to work.

Closes #9330
2016-01-26 15:33:23 +01:00
Peter Bacon Darwin e48666aeaf chore(ngLocale): regenerate locales to include original localeId
Closes #13390
2016-01-26 12:16:51 +00:00
Peter Bacon Darwin 87f80379ea style(i18n): improve indentation for readability 2016-01-26 11:44:49 +00:00
Peter Bacon Darwin 9cee054920 chore(i18n): fix up i18n testing tools 2016-01-26 11:44:43 +00:00
Peter Bacon Darwin e69f35507e feat($locale): Include original locale ID in $locale
Most systems use *IETF language tag* codes which are typically a combination
of the ISO 639 language code and ISO 3166-1 country code with an underscore
or hyphen delimiter. For example `en_US`, `en_AU`, etc.

Whilst the `$locale.id` comes close, the lowercase format makes it impossible
to transform to an IETF tag reliably. For example, it would be impossible
to deduce `en_Dsrt_US` from `en-dsrt-us`.

Closes #13390
2016-01-26 11:44:31 +00:00
Robert Reiz 379b8d9583 docs(bower.json): add MIT license
Closes #13405
2016-01-26 11:04:02 +00:00
Edgar Flores bf79770706 docs(guide/Interpolation): fix links
The links were not working, either `{` was missing or they were in the wrong location

Closes #13809
2016-01-25 23:03:29 +01:00
Martin Staffa 7b0a865c97 docs(guide/directives): link to the scope property docs
Closes #12500
2016-01-25 23:01:47 +01:00
Martin Staffa ce13cfd30a docs($sceDelegateProvider): fix markdown errors
Closes #13360
2016-01-25 23:00:58 +01:00
Robin Glauser c51fbcb7de docs(error/modulerr): add additional debugging help
This simple tip can help to diagnose the error.

Closes #12958
2016-01-25 17:08:03 +00:00
Martin Staffa 796f7ab414 feat(ngAnimate): provide ng-[event]-prepare class for structural animations
The new prepare class is added before the animation is pushed to the
queue and removed before the animation runs, i.e. it is immediately
available when a structural animation (enter, leave, move)
is initialized.

The class can be used to apply CSS to explicitly hide these elements
to prevent a flash of content before the animation runs.
This can happen if a structural animation (such as ng-if) sits at the
bottom of a tree which has ng-class animations on the parents.
Because child animations are spaced out with requestAnimationFrame,
the ng-enter class might not be applied in time, so the ng.if element is
briefly visible before its animation starts.
2016-01-25 16:38:46 +00:00
marianoc84 94d34beed4 docs(guide/Modules): update style guide link
The linked blog post recommends John Papa's Guide.

Closes #12898
2016-01-25 16:34:38 +00:00
Lucas Galfaso f476060de6 fix(dateFilter): follow the CLDR on pattern escape sequences
When there are two single quotes "''" (quotes for clarification) that are not
part of an escape sequence, then this sequence should be handled as one single
quote. See http://www.unicode.org/reports/tr35/tr35-dates.html#Date_Format_Patterns
second and forth examples

Closes #12839
2016-01-25 16:26:08 +00:00
Livvie Lin 6a953bb0cb style(src): delete whitespace and use single quotes
This change edits syntax for code consistency.

It removes whitespace to match the style of the rest of the code,
and changes double quotes to single quotes to conform with
Google's JavaScript Style Guide.

Closes #12889
2016-01-25 14:52:45 +00:00
Tobias Leugger - Vibes 3092fd31bb docs(error/unpr): add hint about using ngStrictDi
The unknown provider error often happens when code is minified and one
did not use the correct syntax that supports minification. It's
frustrating to have to hunt for a bug in minified code, so adding the
simple hint that `ngStrictDi` will tell you what is wrong in the original
code will save you quite some trouble.

Closes #12717
2016-01-25 14:41:43 +00:00
Martin Raifer dae4a2e736 docs(tutorial/step-7): add troubleshooting instructions
Show troubleshooting instructions as in step 11.

Closes #12715
2016-01-25 14:36:21 +00:00
Alireza Mirian 2632250a42 docs($injector): fix inaccuracy in $provide.service docs
Closes #12664
Closes #12665
2016-01-25 14:34:01 +00:00
Wesley Cho fdbd92ff99 docs($compile): improve nonassign error message
- Improve error message to mention attribute the expression errored on

Fixes #13827

Closes #13828
2016-01-24 17:20:17 +01:00
Matias Niemelä 3b27dd37a2 fix(ngAnimate): properly cancel-out previously running class-based animations
Prior to this fix the addition and removal of a CSS class via
ngAnimate would cause flicker effects because $animate was unable
to keep track of the CSS classes once they were applied to the
element. This fix ensures that ngAnimate always keeps a reference
to the classes in the currently running animation so that cancelling
works accordingly.

The commit also adds a test for a previously untested animation merge path.

Closes #10156
Closes #13822
2016-01-23 16:39:53 +01:00
Martin Staffa 76c6493c2b docs(guide/filter): clarify how to use filters in controllers
Closes #11915
2016-01-23 16:30:10 +01:00
Qingyu Zhou da03497f6b docs(tutorial/step_12): change "click" to "hover"
Should be "hover" not "click", since we trigger the change at "mouseenter", not "click".

Closes #13831
2016-01-23 14:25:52 +02:00
Peter Bacon Darwin a1fd2239c9 docs(CHANGELOG): fix animation grouping 2016-01-21 14:29:24 +00:00
Peter Bacon Darwin a39baef657 docs(CHANGELOG): add notes for 1.4.9 2016-01-21 12:40:38 +00:00
Lucas Galfaso 56508a1d5f test(input): test for #12106
Add a test that checks that an <input> value is not set when the value is equal
to the current value

Closes #12592
2016-01-21 10:43:18 +00:00
Adrian Roselli d7d8708a9b docs(tutorial/step-6): add alt attribute to images
See http://www.ssbbartgroup.com/blog/accessible-images-using-angular/

Closes #12569
2016-01-21 10:43:17 +00:00
Peter Bacon Darwin 2ffbfb0ad0 fix($compile): handle boolean attributes in @ bindings
Closes #13767
Closes #13769
2016-01-21 10:43:17 +00:00
Daniel Herman 946d9ae90b perf($compile): avoid needless overhead when wrapping text nodes
This commit positively affects performance in two main ways:

1,  When wrapping text nodes in the compile step, we do not need the overhead
of the `forEach` function versus a normal for loop since we do not make
use of the closure for anything.

2.  When actually wrapping the node, we can completely bypass jqLite which
avoids several function calls and the overhead of cloning the wrapper node
which we already know to be unique.

Tests in applications show about an 83% decrease in time spent in this
specific loop.
2016-01-21 10:43:17 +00:00
Matias Niemelä a84393eadb chore($AnimateRunner): examine the document more carefully
Some internal tests were failing because the `$document[0]` value
was null. This fix ensures that the if statement surrounding that
is more careful.
2016-01-20 10:11:04 -08:00
Daniel Herman c429ad82f5 chore($compile): remove an unused dependency
Fixes #13791

Closes #13801
2016-01-19 20:45:21 +02:00
Georgios Kalpakas 900c7cd923 docs(ngModel): rename $asyncValidators error to nopromise and add missing error page
Closes #13795
2016-01-19 16:07:05 +02:00
Martin Staffa 2d3303ddda perf(ngAnimate): speed up areAnimationsAllowed check
This commit speeds up the code that checks if an element can
be animated, for the following two cases:

The checks will be sped up in cases where the animation
is disabled via $animate.enabled(element, false) on any parent element.

A minor speed-up is also included for cases where the $rootElement of the
app (the bootstrap element) is on the body or lower in the DOM tree.
2016-01-19 13:32:36 +01:00
Martin Staffa a985adfdab fix($animate): correctly handle $animate.pin() host elements
This commit fixes two bugs:
1) Previously, animate would assume that a found host element
was part of the $rootElement (while it's possible that it is also outside the root).

2) Previously, if a parent of the animated element was pinned to a host element, the
host would not be checked regarding animations enabled status etc.

Closes #13783
2016-01-19 13:32:36 +01:00
Martin Staffa ca41996ef7 docs($compile): correct transcludeControllers definition
Closes #13793
2016-01-19 12:10:55 +01:00
Matias Niemelä 9a60408c80 fix(ngAnimate): ensure that animate promises resolve when the document is hidden
Prior to this fix any promise/callback chained on a call to the $animate
methods would only flush if and when the browser page is visible. This
fix ensures that a timeout will be used instead when the document
is hidden.
2016-01-17 20:08:49 +01:00
Matias Niemelä 09f6061a8e fix(ngAnimate): do not trigger animations if the document is hidden
Prior to this fix, ngAnimate would always trigger animations even if
the browser tab or browser window was not visible. This would cause
issues with class updates / DOM operations even if elements were not
using animations. The root cause is that browsers do not flush calls to
requestAnimationFrame when browser windows / tabs are not visible.

This fix disables animations if `document.hidden` is `true`.

Closes #12842
Closes #13776
2016-01-17 20:08:43 +01:00
Peter Bacon Darwin 2d1ee4bffd chore(doc-gen): filter out componentGroup doc types from search results
These doc types do not contain useful information from the point of view
of search results and are making the results less clear
2016-01-13 13:59:26 +00:00
Martin Staffa a412622f69 docs($animate): clarify info about from and to for animate() 2016-01-12 23:22:47 +01:00
dmitriz 63ffe5c360 docs(CONTRIBUTING): add warning about forced push
Add warning about the possible consequences of a forced push

Closes #13747
2016-01-12 18:03:24 +00:00
Matias Niemelä 2fc954d33a fix(ngAnimate): only copy over the animation options once
A bug in material has exposed that ngAnimate makes a copy of
the provided animation options twice. By making two copies,
the same DOM operations are performed during and at the end
of the animation. If the CSS classes being added/
removed contain existing transition code, then this will lead
to rendering issues.

Closes #13722
Closes #13578
2016-01-12 17:35:24 +01:00
Matias Niemelä 512c081187 feat(ngMock): add support for $animate.closeAndFlush()
Use `$animate.closeAndFlush()` to close all running animations.

Includes a fix that landed separately in the master branch:
a801df719e
2016-01-12 17:35:24 +01:00
Georgios Kalpakas 2563ff7ba9 fix($controller): allow identifiers containing $
As discussed in https://github.com/angular/angular.js/issues/13664#issuecomment-170536024.

Closes #13736
2016-01-12 13:21:39 +02:00
Georgios Kalpakas 0a641c0181 test: fix failing tests on MS Edge
Includes the following fixes (per component):

* `$sniffer`: Properly determine the expected `vendorPrefix` for MS Edge
* `input`: MS Edge does not support dates with years with more than 4 digits.
      Trying to set the value of an `input[datetime-local]` to `9999-12-31T23.59.59.999` throws an
      error (probably related to converting the date to one with a year with more than 4 digits,
      due to timezone offset).
* `$animateCss`: Although the detected `vendorPrefix` for MS Edge is "ms", it doesn't seem to
      recognize some vendor-prefixed CSS rules (e.g. `-ms-animation-*`). Other browsers (currently)
      recognize either vendor-prefixed rules only or both.
      Fixed by adding and retrieving styles using both prefixed and un-prefixed names.
* `$compile`: Skip failing `foreignObject` test on MS Edge.
      For unknown reasons, an `<svg>` element inside a `<foreignObject>` element on MS Edge has no
      size, causing the included `<circle>` element to also have no size and thus fails an
      assertion (relying on the element having a non-zero size).
      This seems to be an MS Edge issue; i.e. it is also reproducible without Angular.
      (Tested with MS Edge version 25.10586.0.0 on Windows 10.)

Closes #13686
2016-01-11 19:26:11 +02:00
Georgios Kalpakas da04571dbc refct(privateMocks): remove unused argument from createMockStyleSheet() 2016-01-11 19:26:11 +02:00
mohamed amr 7f1cd3e6a2 test(ngList): add missing '>' to textarea closing tag
Fixes #13728
Closes #13727
2016-01-10 17:59:25 +02:00
Matias Niemelä 6d85f24e20 fix($animate): allow enabled children to animate on disabled parents
Prior to this fix if a parent container disabled animations for
itself then no children could be enabled explicity via
`$animate.enabled`. This patch allows for that to work.

Closes #13179
Closes #13695
2016-01-09 15:20:10 +01:00
Peter Bacon Darwin 0afd775433 docs(tutorial/step-00): fix dangling link 2016-01-08 12:31:07 +00:00
Peter Bacon Darwin 8eb01216b4 chore(package): update karma to 0.13
This version of karma can sniff Microsoft Edge correctly.

Closes #13691
2016-01-07 20:18:15 +00:00
Georgios Kalpakas 323f9ab736 fix(isArrayLike): recognize empty instances of an Array subclass
Fixes #13560
Closes #13708
2016-01-07 19:43:49 +00:00
Martin Staffa 5ba4419e26 fix(ngAnimate): allow event listeners on document in IE
Fixes #13548
Closes #13696
2016-01-07 13:04:42 +00:00
Martin Staffa 529b2507bd fix(select): re-define ngModelCtrl.$render in the select postLink fn
Previously, the `$render` function was re-defined in the `select` directive's
`preLink` function. When a `select` element is compiled, every `option`
element inside it is linked and registered with the `selectCtrl`, which
calls `$render` to update the selected `option`. `$render` calls `selectCtrl.writeValue`,
which adds an unknown `option` in case no option is selected. In cases where
`optgroup` elements are followed by a line-break, adding the unknown `option`
confuses the html compiler and makes it call the link function of the following
`option` with a wrong element, which means this option is not correctly
registered.
Since manipulation of the DOM in the `preLink` function is wrong API usage,
the problem cannot be fixed in the compiler.

With this commit, the `$render` function is not re-defined until the `select` directive's
`postLink` function, at which point all `option` elements have been linked
already.

The commit also changes the `toEqualSelectWithOptions` matcher to
take selected options in groups into account.

Closes #13583

Closes #13583
Closes #13663
2016-01-07 12:06:40 +00:00
Martin Staffa 6d19aa2e7c docs($compile): add docs for bindToController with object hash
Closes #13228
Closes #13625
Closes #13658
Closes #13681
2016-01-06 16:18:42 +01:00
Georgios Kalpakas bf35d53855 docs(validators): fix typos and make minor layout improvements 2016-01-06 14:46:35 +01:00
Martin Staffa 6c4581fcb6 fix(ngAnimate): allow removing classes that are added by a running animation
This allows follow-up animations to remove a class that is currently
being added.

Fixes #13339
Fixes #13380
Closes #13414
Closes #13472
Closes #13678
2016-01-06 14:45:54 +01:00
Matias Niemelä 620a20d1b3 fix(ngAnimate): do not use event.timeStamp anymore for time tracking
Due to recent changes in Chrome, Firefox and Webkit use of the
event.timeStamp value will lead to unpredictable behaviour due to
precision changes. Therefore it's best to stick entirely to use
`Date.now()` when it comes to confirming the end of transition-
ending values. See #13494 for more info.

Applies to 1.2, 1.3, 1.4 and 1.5.

Closes #13494
Closes #13495
2016-01-05 12:53:00 +00:00
Andy Patterson 1f8431bfaa test(booleanAttrsSpec): add unit test for IE11 URL parsing failure
IE11/10/Edge fail when setting a href to a URL containing a % that isn't a valid escape sequence

See #13388
Closes #13458
2016-01-05 12:18:23 +00:00
Konstantin Ulitin b8773a71b5 docs(loader): fix type in @return tag for angular.module()
Closes #13655
2016-01-05 11:57:54 +00:00
Waitaya Krongapiradee 8a63071ab0 docs(error/$rootScope/inprog): add missing "$timeout"
Closes #13630
2016-01-04 22:22:09 +00:00
Kyle Pittman e2a0368726 docs(tutorial/2): add e2e test missing filename
Add `__`test/e2e/scenarios.js`:__` to denote which file we should change
to add the behavioral tests.

Closes #13673
2016-01-04 22:11:17 +00:00
Martin Staffa d9157849df fix($animateCss): remove animation end event listeners on close
Previously the transition/animation end events were not removed when the
animation was closed. This normally didn't matter, because
the close function knows the animations are closed and won't do work
twice.
However, the listeners themselves do computation that could fail when
the event was missing some data, for example when the event was
triggered instead of natural.

This commit includes the fix for a bug that was introduced by this change
and landed on master separately:
https://github.com/angular/angular.js/commit/959f2bbb2d12c23a74902433c6247290d8f2fb89

Closes #13672
2016-01-04 22:18:11 +01:00
Martin Staffa d558dc5f95 docs: reorganize information about interpolation
- Move interpolation info from Directive guide into new interpolation guide
- Add information about boolean attributes to interpolation guide
- remove wroong examples from prefixed boolean attribute docs, link
to interpolation guide instead
- mention additional examples for attributes that benefit from ngAttr
- add docs for ngRequired directive
2015-12-31 18:17:38 +01:00
Martin Staffa 616695eb05 docs: add docs for ngPattern, ngMinlength, ngMaxlength
Closes #9991
2015-12-31 18:17:37 +01:00
Martin Staffa 9ac4e5a64b docs($interpolateProvider): remove superfluous ng-app attribute
The example processor is adding the module attr in the example tag as
the ng-app attr on the body.

Closes #13608
2015-12-31 18:17:37 +01:00
Waitaya Krongapiradee fcb6e1e96b docs(tutorial): fix some minor punctuation errors
Closes #13633
2015-12-31 18:17:36 +01:00
ammills01 cf972fd0bd docs(tutorial/6 - Templating Links): fix grammar
Corrected the grammar on line 62 by adding the word 'an' which forced
me to move 'only' down to line 63.

Closes #13651
2015-12-31 18:17:36 +01:00
Wesley Cho ffc3115705 docs($resource): fix wording for failure
- Fix mention of promise resolution on failure: resolved -> rejected

Closes #13638
Closes #13624
2015-12-31 18:17:36 +01:00
Alexander Zagumennikov 9590bcf062 fix(ngInclude): do not compile template if original scope is destroyed
With slow internet connection scope may be destroyed before template is loaded.
Previously in this case ngInclude compiled template that leaded to memory leaks
and errors in some cases.

Closes: #13515
Closes: #13543
2015-12-21 15:24:55 +02:00
thorn0 689c01f599 refactor($parse): remove unused variables
Closes: #13579
2015-12-21 13:51:12 +02:00
Peter Bacon Darwin 2334a5101d chore(Gruntfile): replace double quotes with single quotes 2015-12-17 22:08:53 +00:00
Peter Bacon Darwin ed7777d3e1 chore(GruntFile): fix whitespace in lists 2015-12-17 22:08:52 +00:00
Peter Bacon Darwin a1648737bd chore(GruntFile): move validate-angular-files task into its own file
Closes #13569
2015-12-17 22:08:52 +00:00
Matias Niemelä 420586bd09 chore(build): add a validation step for angularFiles
Closes #13553
2015-12-17 22:08:52 +00:00
Peter Bacon Darwin d89afc488f chore(angularFiles): add documentation only file to list of files
This prevents errors when checking `validate-angular-files`
2015-12-17 22:08:52 +00:00
Peter Bacon Darwin 0a8a6fa36b chore(npm-shrinkwrap): install glob package 2015-12-17 22:08:52 +00:00
Peter Bacon Darwin e1a182b105 chore(jenkins): remove unused argument definition 2015-12-17 14:15:30 +00:00
Peter Bacon Darwin 214f6822c3 chore(jenkins): run Jenkins builds on Node 4 (via nvm)
Closes #13568
2015-12-17 14:10:15 +00:00
Peter Bacon Darwin 9c5a1cd43c chore(jenkins): move jenkins_build.sh to scripts/jenkins/build.sh 2015-12-16 14:23:09 +00:00
Georgios Kalpakas 8120ab2f77 docs($compile): fix scope hierarchy indentation in HTML output 2015-12-16 15:28:56 +02:00
Peter Bacon Darwin 2f08eae48f chore(travis): update to use node 4.x 2015-12-16 11:15:01 +00:00
Georgios Kalpakas 6610ae816f fix(input): fix URL validation being too strict
Background:
Prior to ffb6b2f, there was a bug in `URL_REGEXP`, trying to match the hostname as `\S+` (meaning
any non-space character). This resulted in never actually validating the structure of the URL (e.g.
segments such as port, path, query, fragment).
Then ffb6b2f and subsequently e4bb838 fixed that bug, but revealed `URL_REGEXP`'s "strictness" wrt
certain parts of the URL.

Since browsers are too lenient when it comes to URL validation anyway, it doesn't make sense for
Angular to be much stricter, so this commit relaxes the "strictness" of `URL_REGEXP`, focusing more
on the general structure, than on the specific characters allowed in each segment.

Note 1: `URL_REGEXP` still seems to be stricter than browsers in some cases.
Note 2: Browsers don't always agree on what is a valid URL and what isn't.

Fixes #13528

Closes #13544
2015-12-16 12:42:26 +02:00
Georgios Kalpakas fa56f8eadb test(privateMocks): allow replacing $prop with strings with special RegExp semantics
`baseThey` used to construct the testcase description by replacing `$prop` using a RegExp.
If the replacement string contained `$&` (which has a special meaning with RegExps), the resulting
string was not as expected.x
2015-12-16 12:42:17 +02:00
Martin Staffa 7882c1c6ae chore(travis): add a new job that runs ci-checks
Previously, ddescribe, merge-conflicts, jshint, and jscs would run
after unit & e2e tests ran. The order was orginally changed as part of
https://github.com/angular/angular.js/pull/9792.

While the logic is sound that style errors shouldn't block tests from
running, ddescribe should always run. This was not guaraneteed; when
Travis exits with a warning after some browsers have run, ddescribe
doesn't get run and it doesn't become apparent that not
all tests have run.

Additionally, a separate job clearly separates style from test errors,
which e.g. means you can open a PR that includes an iit to speed up
the job, and see immediately if the test passes, because the ddescribe
error is in another job.
2015-12-16 10:24:42 +00:00
Justas Brazauskas 84a6ef4d21 docs: fix typos throughout the codebase
Closes #13519
2015-12-15 21:54:41 +02:00
Georgios Kalpakas 4d680c3fad docs(form): remove mention of interpolated control names not being supported
The docs state that interpolation cannot be used in control names.
This used to be true, but not anymore.

Closes #13520
2015-12-15 20:04:26 +02:00
ReneFerwerda bab3069dff docs(select): fix typo
Closes #13491
2015-12-13 22:16:22 -08:00
Martin Staffa 4cb8ac61c7 fix($animate): allow animations when pinned element is parent element
Previously, the animate queue would only detect pinned elements when
they were the same element as the to-be-animated element.

Related #12617
Closes #13466
2015-12-13 22:16:22 -08:00
Igor Minar 9d28a79219 test(ngOptionsSpec): remove ddescribe which caused CI to skip most of unit tests 2015-12-13 22:16:22 -08:00
Igor Minar c4489eb3cb revert: fix($animateCss): remove animation end event listeners on close
This reverts commit c98e08fd87.

This commit was identified as incompatible with ng-material at Google
and is causing broken builds there. Proper fix to be investigated once
the immediate regression is addressed.
2015-12-13 22:16:22 -08:00
Martin Staffa 7caf91300f test($animate): ensure that pin() arguments are elements 2015-12-10 15:20:48 +01:00
Martin Staffa 0c1b54f04c fix($animate): correctly access minErr
ngMinErr is available during unit tests, but not in the build. There's
currently no way to catch these access errors in automated testing.
2015-12-10 15:20:48 +01:00
Martin Staffa 85e392f354 fix(ngOptions): don't skip optgroup elements with value === ''
Internet Explorer 11 returns '' for optgroup elements without a value
attribute. We only want to skip option elements with value ''

Fixes #13487
Closes #13489
2015-12-10 15:18:24 +01:00
Martin Staffa c98e08fd87 fix($animateCss): remove animation end event listeners on close
Previously the transition/animation end events were not removed when the
animation was closed. This normally didn't matter, because
the close function knows the animations are closed and won't do work
twice.
However, the listeners themselves do computation that could fail when
the event was missing some data, for example when the event was
triggered instead of natural.

Closes #10387
2015-12-10 15:05:21 +01:00
Matias Niemelä 33cc75e6fc chore(angularFiles): the animateRunner.js file doesn't exist for ngAnimate anymore 2015-12-08 14:48:54 -08:00
Georgios Kalpakas 474865242c fix($resource): don't allow using promises as timeout and log a warning
Promises never worked correctly as values for `timeout` in `$resource`, because the same value has
to be re-used for multiple requests (and it is not possible to `angular.copy()` a promise).
Now (in addition to ignoring a non-numeric `timeout`), a warning is logged to the console using
`$log.debug()`.

Partly fixes #13393.

BREAKING CHANGE:

Possible breaking change for users who updated their code to provide a `timeout`
promise for a `$resource` request in version 1.4.8.

Up to v1.4.7 (included), using a promise as a timeout in `$resource`, would silently
fail (i.e. have no effect).

In v1.4.8, using a promise as timeout would have the (buggy) behaviour described
in https://github.com/angular/angular.js/pull/12657#issuecomment-152108887
(i.e. it will work as expected for the first time you resolve the promise and will
cancel all subsequent requests after that - one has to re-create the resource
class. This is feature was not documented.)

With this change, using a promise as timeout in 1.4.9 onwsards is not allowed.
It will log a warning and ignore the timeout value.

If you need support for cancellable `$resource` actions, you should upgrade to
version 1.5 or higher.
2015-12-08 16:39:33 +00:00
Georgios Kalpakas 0292e6a1a8 docs($resource): add note about _promises as timeout_ not being supported
Fixes part of #13393.
2015-12-08 16:34:27 +00:00
Georgios Kalpakas de193422a3 refactor($resource): change if-block to switch-block for readability 2015-12-08 16:34:26 +00:00
Georgios Kalpakas ff228fb524 revert: fix($resource): allow XHR request to be cancelled via timeout promise
This reverts commit 7170f9d9ca.

Fixes part of #13393.
2015-12-08 16:34:26 +00:00
Martin Staffa 8709539d4c docs(guide/migration): add info for 1.3 checkbox breaking change
Introduced in commit https://github.com/angular/angular.js/commit/c90cefe16142d973a123e945fc9058e8a874c357

Closes #13464
2015-12-08 13:21:39 +01:00
Andy Patterson 2995b54afd fix(input): add missing chars to URL validation regex
Update the list of permitted chars in URLs.

Closes #13379
Closes #13460
2015-12-07 22:33:32 +02:00
Georgios Kalpakas e26256fb70 docs(guide/$location): fix table header formatting
Closes #13456

Closes #13459
2015-12-07 19:50:10 +02:00
Martin Staffa e45f9b66fa docs(guide/Unit Testing): fix typo
Closes #13227
2015-12-07 14:37:32 +01:00
zainengineer 158f1aec86 docs(orderBy): make examples consistent
Updated example which manually injects the filter.
It matches sibling example in functionality.

Also put  html, js and css into separate files.

Also change anchors to buttons.

Closes #13402
2015-12-07 14:37:31 +01:00
Hovhannes Babayan f53a7f62bb docs(guide/Expressions): note that new operator is unavailable
You cannot create new objects inside Angular expressions. For example:
{{ new Date() }} expression fails.
2015-12-07 14:37:31 +01:00
Martin Staffa d2b08a0465 docs(changelog, guide/migration): add BC notes for observing unset attributes
Closes #11163
2015-12-07 13:45:02 +01:00
Mil4n 43c4029c8a docs(tutorial/step_08): fix tense
The original statement is in the past tense (as if it were referring to a previous step of the
tutorial). The mentioned changes, however, are being done in this setp.

Closes #13452
2015-12-07 13:53:22 +02:00
Marcus Nielsen 55ac985373 docs($resource): fix mixed singular/plural
"any of the parameter value" contains plural (any of the) as well as singular (value).
Fixed to be singular to match the rest of the text block.

Closes #13448
2015-12-04 20:57:15 +00:00
Martin Staffa 37b6ed3225 docs(ngModelController): improve $rollbackViewValue description & example
The example has been expanded to make it easier to provoke the
behavior that the description is talking about (rollbackViewValue
and programmatic model updates)

Related #13340
2015-12-04 00:02:17 +01:00
Utsav Shah c5bf9daef6 fix($http): throw if url passed is not a string
Throw to prevent hard to debug errors in functions that are
called later.

Fixes #12925
Closes #13444
2015-12-04 00:02:17 +01:00
Martin Staffa be01cebfae fix(ngAnimate): ignore children without animation data when closing them
During parent structural animations, ongoing animations on child elements
are closed. These child elements are identified by their data-ng-animate
attribute. If an element is the clone of an animating element,
it might have this attribute, but no animation runner associated with it,
so we need to ignore it.

Fixes #11992
Closes #13424
2015-12-02 21:01:53 +01:00
Matias Niemelä 7a81e6fe2d fix(ngAnimate): do not alter the provided options data
Prior to this fix the provided options object would be
altered as the animation kicks off due to the underlying
mechanics of ngAnimate. This patch ensures that a
copy of the provided options is used instead. This patch
also works for when `$animateCss` is used by itself.

Fixes #13040
Closes #13175
2015-12-02 12:28:37 +01:00
Peter Bacon Darwin 9c49eb131a fix(formatNumber): cope with large and small number corner cases
By manually parsing and rounding we can deal with the more tricky numbers

Closes #13394
Closes #8674
Closes #12709
Closes #8705
Closes #12707
Closes #10246
Closes #10252
2015-12-01 22:00:25 +00:00
xieranmaya 374a302b90 docs($controller): fix typo
Closes #13418
2015-12-01 19:12:02 +00:00
daviskoh b3da88077f docs($parse): fix typo in error message description
Closes #13409
2015-11-30 12:47:40 +01:00
Adam Zerner 6454f51741 docs(guide/Scopes): fix grammar
Closes #13413
2015-11-30 12:47:05 +01:00
Martin Staffa e509ab5be6 style($animateCssSpec): remove dump from test 2015-11-30 12:47:05 +01:00
Martin Staffa 592bf516e5 fix($animateCss): consider options.delay value for closing timeout
Previously, options.delay was only considered when a class added an
extra transition style (which leads to style recalculation).

Fixes #13355
Closes #13363
2015-11-26 18:57:44 +01:00
Joan Claret 8cdafe46e3 docs(tutorial/2 - Angular Templates): add closing parenthesis
Closes #13368
2015-11-26 18:57:44 +01:00
Peter Bacon Darwin 45c5688d42 test($compile): add test for undefined non-optional reference binding
Demonstrates that #13373 fixes #13367
2015-11-25 10:53:10 +00:00
Lucas Mirelmann 7bb2414bf6 fix($parse): handle interceptors with undefined expressions
When calling `$parse` with `undefined` as the expression and with
an interceptor, then when the function is evaluated, then call the
interceptor

Closes: #13367
Closes: #13373
2015-11-25 10:53:01 +00:00
Peter Bacon Darwin da11c1bcee chore(bower/publish): read dist-tag from correct package.json 2015-11-24 13:20:03 +00:00
J.P. Poveda a80697938e docs($timeout): reword sentence for clarity
Closes #13302
2015-11-23 13:16:23 +01:00
Matt Erickson 1d9ad76f1f docs($swipe): remove reference to ngCarousel
ngCarousel no longer exists (or has ever existed).

Closes #13322
Closes #13353
2015-11-23 13:16:22 +01:00
Rahat Ahmed 01387ba3c3 docs(numberFilter): change decimalPlaces to fractionSize
Replace `decimalPlaces` with `fractionSize`, as `decimalPlaces`
isn't defined anywhere and is most likely meant to be `fractionSize`.

Closes #13323
2015-11-23 13:16:21 +01:00
mohamed amr f163c90555 fix(ngOptions): don't $dirty multiple select after compilation
Closes #13211
Closes #13326
2015-11-23 13:16:19 +01:00
Martin Staffa 4e94864e54 chore(i18n): update locale files with standalone months
Closes #12844
2015-11-23 10:44:30 +00:00
Martin Staffa 54c4041ebc feat(ngLocale): add support for standalone months
This is needed for languages for which the month on its own has a
different format (case) than when used as part of a date.

Closes #3744
Fixes #10247
Fixes #12642
Closes #12844
2015-11-23 10:44:24 +00:00
Anita Perala f780aba434 docs(guide/Conceptual Overview): add missing object in sentence
docs: minor grammar fix
missing word in overview

Closes #13346
2015-11-20 18:16:53 +01:00
Martin Staffa 057f78de8b docs(angular.element): add more info, fix formatting
- add info about ngJq
- fix alert box
- add info about css function
2015-11-20 18:16:53 +01:00
Julián Salgado 7a36128efc docs(angular.element): note that it does not find elements by tag name / selector
Closes #13107
Closes #13113
2015-11-20 18:16:52 +01:00
Anas Qadrei d2cd8b9bb6 docs(error/nobase): making <base> visible in html
Closes #13350
2015-11-20 17:35:48 +01:00
Matias Niemelä 937942f5ad fix(core): ensure animate runner is the same with and without animations
The $$AnimateRunner class is now the same for the core $animate service
and the ngAnimate $animate service. Previously, the core used a different
implementation that didn't match the ngAnimate behavior with regard
to callbacks.

Closes #13205
Closes #13347
2015-11-20 17:34:34 +01:00
Matias Niemelä 75e876424d chore(CHANGELOG): update with changes for 1.4.8 2015-11-19 14:52:56 -08:00
Jason Bedard 19fab4a1d7 perf(copy): avoid regex in isTypedArray
Closes: #12054
2015-11-19 08:59:00 +00:00
Jason Bedard d1293540e1 perf(copy): only validate/clear user specified destination
Closes #12068
2015-11-19 08:58:47 +00:00
Peter Bacon Darwin 22f66025db fix(jqLite): deregister special mouseenter / mouseleave events correctly
Closes #12795
Closes #12799
2015-11-12 18:45:59 +00:00
rrsivabalan 6f8ddb6d43 fix($location): ensure $locationChangeSuccess fires even if URL ends with #
Closes #12175
Closes #13251
2015-11-12 13:40:29 +00:00
Eric Lee Carraway 34590e15d4 docs(readme): fix typo (setup => set up)
spell set up as two words
here, it is an adjective modifying the noun "environment"

Closes #13297
2015-11-12 10:31:06 +02:00
Eric Lee Carraway 83098b9add docs(contributing): fix typo (a unambiguous => an unambiguous)
use the article “an” before words that start with a vowel sound

Closes #13292
2015-11-11 14:26:39 +02:00
Peter Bacon Darwin 5d8861fb2f fix($compile): bind all directive controllers correctly when using bindToController
Previously only the first directive's controller would be bound correctly.

Closes #11343
Closes #11345
2015-11-10 20:56:33 +00:00
Georgios Kalpakas b9f7c453e0 fix($compile): evaluate against the correct scope with bindToController on new scope
Previously, the directive bindings were evaluated against the directive's
new (non-isolate) scope, instead of the correct (parent) scope.
This went unnoticed most of the time, since a property would be eventually
looked up in the parent scope due to prototypal inheritance. The incorrect
behaviour was exhibited when a property on the child scope was shadowing
that on the parent scope.

This commit fixes it.

Fixes #13021
Closes #13025
2015-11-10 20:56:33 +00:00
Jakub Torbicki 750344129e fix($compile): bind all directive controllers correctly when using bindToController
Previously only the first directive's controller would be bound correctly.

Closes #11343
Closes #11345
2015-11-10 20:56:33 +00:00
Peter Bacon Darwin 74da034077 fix($compile): fix scoping of transclusion directives inside replace directive
Closes #12975
Closes #12936
Closes #13244
2015-11-10 20:56:07 +00:00
Jason Bedard 91ef94d284 refactor($compile): simplify multi element directive check
Previously, we would check if an attribute indicates a multi-element
directive, now we only do this check if the attribute name actually
matches the multi-element name pattern.

Closes #12365
2015-11-10 20:48:33 +00:00
Martin Staffa ab9b021572 docs(changelog, migration): add BC notice for ngMessages evaluation
Introduced by

Closes #11616
Closes #12001
2015-11-06 17:19:16 +01:00
Martin Staffa b268c0b7b4 docs(changelog, migration): add BC notice for setting ngOptions as attribute
Caused by 7fda214c4f

Closes #13145
2015-11-06 17:19:16 +01:00
Doug Krugman b0c19f8b06 docs(guide/Concepts): remove unused refresh property
Closes #13257
2015-11-06 10:17:00 +02:00
jody tate bbc2a0ae48 docs(guide/Directives): change "it" to possessive
Closes #13253
2015-11-05 14:27:07 +02:00
Martin Staffa ca53dfcc18 docs(ngRepeat): add more info about watching and tracking
- mention $watchCollection
- highlight that track by "id" can improve render performance

Related #9508
2015-11-03 21:40:50 +01:00
Georgios Kalpakas ce6a96b0d7 perf(merge): remove unnecessary wrapping of jqLite element
Fixes https://github.com/angular/angular.js/commit/75292a6cb5e17d618902f7996e80eb3118eff7b0#commitcomment-14137538

Closes #13236
2015-11-03 17:49:54 +02:00
Peter Bacon Darwin d4b359f4b2 test(merge): fix check on jquery object 2015-11-02 20:13:14 +00:00
JonyD 8d841c3405 docs(ngRepeat): fix link to MDN
Closes #13226
2015-11-02 21:00:13 +01:00
Martin Staffa 2b285c75f4 docs(ngInclude): fix incorrect link 2015-11-02 21:00:12 +01:00
Martin Staffa 6e4464331d docs(tutorial/0 - Bootstrapping): mention that the setup must be completed
Closes #13106
2015-11-02 21:00:11 +01:00
Peter Bacon Darwin 2f8db1bf01 fix(merge): ensure that jqlite->jqlite and DOM->DOM
Previously we were wrapping DOM elements into jqlite objects when cloning
and vice versa.

Fixes https://github.com/angular/angular.js/pull/12286#discussion_r43656917
2015-11-02 19:56:13 +00:00
luckylooke 838cf4be3c fix(merge): clone elements instead of treating them like simple objects
Similar fix to #11720

Closes #12286
2015-11-02 17:22:26 +00:00
Matthew Hill de2a56bbc8 docs(angular-mocks): clarify angular.mock.module usage with objects
Closes #12354
2015-11-01 07:14:20 +00:00
Jason Bedard 55ad192e4a perf($compile): use static jquery data method to avoid creating new instances 2015-11-01 07:00:22 +00:00
Chris J. Lee 5b4713e43e chore(protractor-conf.js): remove dangling comma
Closes #13051
2015-11-01 06:46:08 +00:00
Peter Bacon Darwin 3fa9aba0cc chore(package.json): update dgeni-packages to 0.11.0 2015-10-31 20:44:55 +00:00
Peter Bacon Darwin 1bba358a75 chore(package.json): add commitizen, adapter and npm script
Closes #13194
2015-10-31 20:43:13 +00:00
Bert Verhelst 7a4124c298 docs($location): improve style
Closes #13072
2015-10-30 22:09:58 +01:00
Martin Staffa 2512a81e09 docs(error/ctreq): fix typo
Closes #13083
2015-10-30 22:09:58 +01:00
Michael George Attard 44c9d1616a docs($rootScope): improve clarity and consistency
Closes #13110
2015-10-30 22:09:57 +01:00
Pablo Villoslada Puigcerber 5758d73964 docs(select): document the multiple attribute
Add the `multiple` attribute to the documentation of the select directive.

Closes #13119
2015-10-30 20:41:58 +02:00
Sreenivasan K 6bd6dbff49 fix($animate): ensure leave animation calls close callback
Closes #12278
Closes #12096
Closes #13054
2015-10-29 07:55:36 +00:00
Stanislav Komanec 7170f9d9ca fix($resource): allow XHR request to be cancelled via timeout promise
Closes #12657
Closes #12675
Closes #10890
Closes #9332
2015-10-28 22:26:21 +00:00
Peter Bacon Darwin 1c0f721368 test($rootScope): ensure that only child scopes are disconnected
Related to #11786 and 8fe781fbe7
2015-10-28 22:06:25 +00:00
Alicia Lauerman 2a5a52a76c fix($cacheFactory): check key exists before decreasing cache size count
Previously, there was no check for the existence of an item in the
cache when calling `$cacheFactory.remove()` before modifying the cache size
count.

Closes #12321
Closes #12329
2015-10-28 21:50:17 +00:00
Georgios Kalpakas c690946469 fix($http): apply transformResponse even when data is empty
Note, that (as a by-product of the previous implementation) only non-empty
data was passed through the `transformResponse` pipeline. This is no
longer the case.

When using a custom `transformResponse` function, one should make sure it
can also handle an empty (i.e. falsy) `data` argument appropriately.

Fixes #12976
Closes #12979
2015-10-28 21:41:52 +00:00
Peter Bacon Darwin 87b0055c80 fix($rootScope): stop IE9 memory leak when destroying scopes
Ensure that all child scopes are completely disconnected when a parent is
destroyed.

Closes #10706
Closes #11786
2015-10-28 21:35:22 +00:00
Charlie-Hua 2116857a2a docs(ngModelOptions): add missing user.data result for updateOn: blur example
In the updateOn:blur example, there is an input for user.data but the
result is missing and nowhere to see how the value changes compared to user.name.

Closes #13129
2015-10-28 22:10:03 +01:00
Peter Bacon Darwin 0f58334b7b fix(ngOptions): skip comments and empty options when looking for options
Related #12952
Closes #12190
Closes #13029
Closes #13033
2015-10-28 18:33:08 +01:00
Stu Cox bcc257b459 docs($q): add a note re. difference in exception handling vs ES6
Closes #11472
Closes #13101
2015-10-28 08:18:00 +00:00
Ryan Hart 980fb395e4 docs(ngOptions): explain the caveats of using select as and track by together
Changes:

* Modify warning message to indicate that `track by` can be used with `select as`,
  but subject to certain limitations.
* Provide both a working and an non-working example.
* Explain why the latter does not work.

Closes #13007
2015-10-27 22:01:58 +02:00
Sam Rawlins 62ed26a84f docs($anchorScroll): fix link to HTML5 spec
Closes #13180
2015-10-27 20:40:43 +02:00
Marcy Sutton 59f1f4e19a fix(ngAria): don't add tabindex to radio and checkbox inputs
Closes #12492
Closes #13095
2015-10-27 17:52:02 +01:00
Andrew Austin cb51116dbd fix(ngInput): change URL_REGEXP to better match RFC3987
The URL_REGEXP in use to perform validation in ngInput is too restrictive and fails to
follow RFC3987. In particular, it only accepts ftp, http, and https scheme components and
rejects perfectly valid schemes such as "file", "mailto", "chrome-extension",
etc. The regex also requires the scheme to be followed by two "/" but the RFC says
0 to n are acceptable. This change fixes both of these issues to better align to
the standard.

Closes #11341
Closes #11381
2015-10-26 21:45:53 +00:00
Kuzminov Aleksandr Sergeevich c1f34e8eeb fix(jqLite): ensure mouseenter works with svg elements on IE
Closes #10259
Closes #10276
2015-10-26 21:27:04 +00:00
sevdog 7bf5429e3b docs($animateCss): add missing documentation for the structural option
Add missing documentation for structural option in `$animateCss` service

Closes #13049
2015-10-26 13:03:37 -07:00
Lucas Galfaso d3da55c40f fix(isArrayLike): handle jQuery objects of length 0
Closes: #13169
Closes: #13171
2015-10-26 18:01:15 +00:00
Jack Viers 70edec947c fix(Angular.js): fix isArrayLike for unusual cases
Closes #10186
Closes #8000
Closes #4855
Closes #4751
Closes #10272
2015-10-26 18:01:15 +00:00
Risan Bagja Pradana fe17c0e066 docs(tutorial): add a note about Chrome or Firefox not being available
Based on the current configuration, Karma will run the tests on both
Chrome and Firefox, which will result in an error if either browser is not
available on the user's machine. This commit adds a note and directions on
how to solve this.

Closes #13114
2015-10-26 15:44:43 +02:00
Lucas Mirelmann e403682444 fix($parse): evaluate once simple expressions in interpolations
For simple expressions without filters that have a stateless interceptor
then handle the 2nd phase parse evaluation using `inputs`.

TL;DR
This fixes the issue that interpolated simple expressions were evaluated twice
within one digest loop.

Long version, things happen in the following order:

* There was an overhaul on $interpolate, this overhaul changed $parse and
  incorporated the concept of an interceptor.
* Optimization on $parse landed  so expressions that have filters without
  parameters (or the parameters are constants) would be evaluated in 2 phases,
  first to evaluate the expression sans the filter evaluation and then with
  the filter evaluation. This also used interceptors [the second evaluation
  issue was added here]
* More optimizations on $parse landed and now expressions could be evaluated
  in 2 phases. One to get all the possible values that could change (lets call
  this state), the state was checked by $watch to know if an expression changed.
  The second to continue the evaluation (as long as this state is provided).
  This, once again, used interceptors

The last change, was supposed to fix the issue, but there was an assumption in
the existing code that the code would always generate the 2 phases functions,
but that is not true. If the expression is simple enough (just like the one in
your case) then the 2-phase evaluations functions are not generated. In this
case, if a stateless interceptor was added (just like what $interpolate adds)
then the state was not used and you see the function being evaluated twice.
This explains why, if you change the expression from
`Hello {{log('A')}} {{log('B')}}!` to `Hello {{log('A') + ' ' + log('B')}}!`,
then the repetition is not there.

Closes #12983
Closes #13002
2015-10-15 22:20:30 +02:00
zurin 27d441b0d6 docs(guide/Scopes): fix grammar
Added a comma to make reading more natural.

Closes #13084
2015-10-14 16:16:02 +03:00
Michael Salmon 8a944b0872 docs(guide/Directives): improve description of linking function
The `controller` and `transclude` parameters of the linking function were not
mentioned in the description, but used in the examples.
This commit improves the description and links to the `$compile` API docs
for more details.

Closes #13028
2015-10-14 10:53:12 +03:00
Martin Staffa 786a1a4429 docs(ngOptions): add info about preselecting complex models
Closes #12966
2015-10-08 15:56:17 +02:00
Chris J. Lee 8e5c4e92f7 test(ngResource): fix typos in tests
Closes #13044
2015-10-08 11:49:17 +03:00
Flavio Corpa Ríos 46d24ae4c8 docs(ngInclude): add workaround for using onload function with SVG in IE11
Closes #12493
Closes #13042
2015-10-07 23:04:31 +02:00
Jason Hopper 9dd33c09b1 docs(tutorial): update angular module versions to reflect tutorial files
Closes #12991
Closes #12992
2015-10-07 17:53:26 +02:00
Sugan Krishnan fea8240c81 docs($sce): fix typo
Closes #13030
2015-10-07 13:23:11 +01:00
Peter Bacon Darwin 3d2b1be211 refactor($compile): check removeWatches before calling
Previously we assigned `noop` if there was no function but there is no
performance advantage in doing this since the check would have to happen
either at assignment time or at call time.

Removing this use of `noop` makes the code clearer, IMO :-)

Closes #12528
2015-10-07 13:05:04 +01:00
Peter Bacon Darwin f08a0c5ad1 refactor($compile): initialize removeWatchCollection at the start
This check means that we don't have to keep checking whether the collection
has been created when adding a new watcher

Closes #12528
2015-10-07 13:05:03 +01:00
Peter Bacon Darwin 6f1e0ba563 refactor($compile): rename variables to clarify their purpose
Closes #12528
2015-10-07 13:05:03 +01:00
Jason Bedard 540338f9a5 refactor($compile): move $scope.$on('$destroy') handler out of initializeDirectiveBindings
Since only one of three invocations of `initializeDirectiveBindings` actually
adds a `$destroy` handler to the scope (the others just manually call unwatch
as needed), we can move that code out of this method.

This also has the benefit of simplifying what parameters need to be passed
through to the linking functions

Closes #12528
2015-10-07 13:05:03 +01:00
Martin Staffa 0e6a700807 Revert "fix(ngOptions): skip comments when looking for option elements"
This reverts commit 68d4dc5b71.
The fix only fixed a specific case and exhibited a flawed logic
(namely skipping every option if the emptyOption is a comment).
See https://github.com/angular/angular.js/issues/12190#issuecomment-145877914

Conflicts:
	test/ng/directive/ngOptionsSpec.js
2015-10-07 11:33:32 +02:00
Georgios Kalpakas 4fc40bc932 fix(limitTo): start at 0 if begin is negative and exceeds input length
Previously, specifying a negative `begin` whose abs value exceeds the
input's length, would behave unexpectedly (depending on the value of
`limit` relative to `begin`). E.g.:

```
limitToFilter('12345', 3, -7) === '1'
// but
limitToFilter('12345', 10, -7) === '123'
```

This commit fixes the unexpected behaviour, by setting `begin` to 0 in the
aforementioned cases. Thus, the previous examples become:

```
limitToFilter('12345', 3, -7) === limitToFilter('12345', 3, 0) === '123'
// and
limitToFilter('12345', 10, -7) === limitToFilter('12345', 10, 0) === '12345'
```

Fixes #12775
Closes #12781
2015-10-07 00:09:37 +03:00
Richard Harrington 216724b4cb docs(constant): fix pluralization
Closes #13024
2015-10-06 23:22:41 +03:00
Raghav 9bd1645970 docs($animate): fixed typo ("an animations" -> "any animations")
Closes #13020
2015-10-06 23:15:15 +03:00
Magnus Pedersen 3397a031a1 docs(ngOptions): rephrased a sentence for clarity
Closes #13010
2015-10-06 23:12:55 +03:00
Peter Bacon Darwin 5ec5aa7751 style(ngOptionsSpec): remove excess space
This was inadvertently added in 7b2ecf42c6
2015-10-06 14:36:47 +01:00
Peter Bacon Darwin bf5ac5261d style(ngOptions): fix missing closing brace
This was inadvertently added in 7b2ecf42c6
2015-10-06 14:20:37 +01:00
Peter Bacon Darwin 91b7cd9b74 fix(ngMock): reset cache before every test
We don't need to have values in the cache from previous tests. This was
causing failures in all subsequent tests when a single test failed due
to a memory leak.

Now that we reset the cache each time we do not need to store the cache
size at the start of each test

Closes #13013
2015-10-06 13:58:23 +01:00
Martin Staffa 7b2ecf42c6 fix(ngOptions): override select option registration
When ngOptions is present on a select, the option directive should not be able to
register options on the selectCtrl since this may cause errors during the
ngOptions lifecycle.

This can happen in the following cases:

- there is a blank option below the select element, an ngModel
directive, an ngOptions directive and some other directive on the select
element, which compiles the children of the select
(i.e. the option elements) before ngOptions is has finished linking.

- there is a blank option below the select element, an ngModel
directive, an ngOptions directive and another directive, which uses
templateUrl and replace:true.

What happens is:
- the option directive is compiled and adds an element `$destroy` listener
that will call `ngModel.$render` when the option element is removed.
- when `ngOptions` processes the option, it removes the element, and
triggers the `$destroy` listener on the option.
- the registered `$destroy` listener calls `$render` on `ngModel`.
- $render calls `selectCtrl.writeValue()`, which accesses the `options`
object in the `ngOptions` directive.
- Since `ngOptions` has not yet completed linking the `options` has not
yet been defined and we get an error.

This fix moves the registration code for the `option` directive into the
`SelectController.registerOption()` method, which is then overridden by
the `ngOptions` directive as a `noop`.

Fixes #11685
Closes #12972
Closes #12968
Closes #13012
2015-10-06 13:57:40 +01:00
Matias Niemelä 256d9a948c docs(ngAnimate): simplify $animateCss example code 2015-10-05 10:56:43 -07:00
spoonraker 99fc6cda98 docs(tutorial): updates for the text for animations in step 12
The grammar for the animation description has now been improved.

Closes #12740
2015-10-05 10:22:17 -07:00
Jason Hopper 690b69b9cd docs(tutorial): update tutorial copy to reflect updates to tutorial source @bower.json excerpt for animations
Code breaks if tutorial is followed without reset.
bower.js exceprt copy does not match source.
Changed to reflect in text body.

Closes #12993
2015-10-05 10:18:45 -07:00
Alexandr Gureev 4262f15e16 docs(ngAnimate): fix typos in examples
Closes #12995
2015-10-02 11:27:05 +03:00
John Zhang 3a8d1354ce docs($httpProvider): fix description of useLegacyPromiseExtensions
useLegacyPromiseExtensions's default value is true, and the  legacy
methods exist when it is set to true.

Closes #12974
2015-10-01 18:33:40 +02:00
Donghwan Kim f9387c6890 docs(guide/Running in Production): fix an incorrect indefinite article
Closes #12986
2015-10-01 18:33:29 +02:00
koyner 48d0ffcbc4 docs(guide/Forms): fix indentation.
Closes #12988
2015-10-01 18:23:51 +02:00
Martin Staffa 3485ba1e2b docs(guide/Using $location): note that the fakeBrowser is not for actual projects
Closes #12982
Closes #12987
2015-10-01 18:21:56 +02:00
Matias Niemelä 2f61145475 chore(CHANGELOG): update with changes for 1.4.7 2015-09-29 13:54:51 -07:00
Martin Staffa 8c618d896b docs($http): link to usage where config is mentioned; make drier
Linking to usage section makes it easier for beginners to find out what the config object looks like.
The General Usage section now features an example that actually uses $http(config), and the Shortcut Methods section has been moved so that it appears directly after.

Closes #12949
Closes #12950
2015-09-27 15:48:20 +02:00
Martin Staffa 68d4dc5b71 fix(ngOptions): skip comments when looking for option elements
When the empty/blank option has a directive that transcludes, ngIf for example,
a comment will be added into the select. Previously, ngOptions used this
comment as the empty option, which would mess up the displayed options.

Closes #12190
2015-09-27 15:48:13 +02:00
Martin Staffa 03a4a96cf9 test(ngOptions): clarify a test description 2015-09-27 15:48:06 +02:00
Stefan Krüger 655c52a621 docs(guide/Directives): let myTabs directive ctrl use inline array notation
modified `docsTabsExample` myTabs directive ctrl at
[Creating Directives that Communicate Example](https://docs.angularjs.org/guide/directive#creating-directives-that-communicate) so that it uses
[Inline Array Annotation](https://docs.angularjs.org/guide/di#inline-array-annotation)
and is compatible with
[Using Strict Dependency Injection](https://docs.angularjs.org/guide/di#using-strict-dependency-injection)

Closes #12767
2015-09-27 15:47:57 +02:00
Martin Staffa fa3ddba5f2 docs(ngModel): align $viewValue description with $setViewValue 2015-09-27 15:47:43 +02:00
Matias Niemelä c4a1b6124e docs($animateCss): options.transition should be options.transitionStyle 2015-09-24 10:06:22 -07:00
Matias Niemelä e52d731bfd feat($animateCss): add support for temporary styles via cleanupStyles
Some animations make use of the `from` and `to` styling only for the
lifetime of the animation. This patch allows for those styles to be
removed once the animation is closed automatically within `$animateCss`.

Closes #12930
2015-09-24 10:02:30 -07:00
Igor Minar 9b72843018 build(travis): make sauce connect process query a bit more specific 2015-09-23 14:01:32 -07:00
Georgios Kalpakas 9c1f8ea70b chore(check-node-modules): make check/reinstall node_modules work across platforms
The previous implementations (based on shell scripts) threw errors on
Windows, because it was not able to `rm -rf` 'node_modules' (due to the
255 character limit in file-paths).

This implementation works consistently across platforms and is heavily based on
'https://github.com/angular/angular/blob/3b9c08676a4c921bbfa847802e08566fb601ba7a/tools/npm/check-node-modules.js'.

Fixes #11143
Closes #11353

Closes #12792
2015-09-23 23:01:15 +03:00
Igor Minar 9fde5648e4 build(travis): fix typo in a comment 2015-09-23 11:01:00 -07:00
Igor Minar ea829620b2 build(travis): gracefully shut down the sauce connect tunnel after the tests are done running
This is to prevent sauce connect tunnel leaks.

Closes #12921
2015-09-23 09:40:27 -07:00
Martin Staffa 1731d091f8 docs(ngList): whitespace -> newline 2015-09-23 17:38:15 +02:00
Matias Niemelä 9d3704ca46 fix(ngAnimate): ensure anchoring uses body as a container when needed
Prior to this fix anchoring would allow for a container to be a document
node or something higher beyond the body tag. This patch makes it fall
back to body incase the rootElement node exists as a parent ancestor.

Closes #12872
2015-09-22 13:47:16 -07:00
Matias Niemelä 215dff34dd revert: chore(core): introduce $$body service
Relying on the body node to be present right at injection has
caused issues with unit testing as well as some animations on
the body element. Reverting this patch fixes these issues.

Closes #12874
2015-09-22 13:47:10 -07:00
Matias Niemelä fa8c399fad fix(ngAnimate): callback detection should only use RAF when necessary
Callbacks are detected within the internals of ngAnimate whenever an
animation starts and ends. In order to allow the user to set callbacks
the callback detection needs to happen during the next tick. Prior to
this fix we used $$rAF to do the tick detection, however, with this
patch we intelligently use $$postDigest to do that for us and then
only issue a call to `$$rAF` if necessary.
2015-09-22 13:47:04 -07:00
Peter Bacon Darwin 7295c60ffb fix(ngMessages): prevent race condition with ngAnimate
If `ngMessage` tried to add a message back in that was about to be removed
after an animation, the NgMessageController got confused and tried to detach
the newly added message, when the pending node was destroyed.

This change applies a unique `attachId` to the message object and its DOM
node when it is attached. This is then checked when a DOM node is being
destroyed to prevent unwanted calls to `detach`.

Closes #12856
Closes #12903
2015-09-22 20:53:40 +01:00
Martin Staffa fa01571036 docs(guide/Directives): fix link formatting
Closes #12909;
2015-09-22 13:12:52 +02:00
Martin Staffa dbc698517f fix(ngOptions): prevent frozen select ui in IE
In certain scenarios, IE10/11/Edge create unresponsive select elements.
The following contribute to the bug:
- There need to be at least 2 selects next to each other
- The option elements are added via javascript
- the option.value is accessed before it is set
- the option.label is added after the option.value has been set
- The first select is wrappend in an element with display: inline or
display: inline-block,

This cannot be tested in a unit-test or e2e test.

Closes #11314
Closes #11795
2015-09-22 13:05:06 +02:00
Lucas Galfaso a7f3761eda fix($parse): block assigning to fields of a constructor
Throw when assigning to a field of a constructor.

Closes #12860
2015-09-22 10:44:27 +01:00
Jason Bedard 5a98e806ef fix($compile): use createMap() for $$observe listeners when initialized from attr interpolation
Closes #10446
2015-09-21 19:05:20 +01:00
Ivan Verevkin 808f984ec0 docs($cacheFactory): fix call to isUndefined() in example
Closes #12899
2015-09-21 15:51:49 +03:00
Lucas Mirelmann 698af191de fix($parse): do not convert to string computed properties multiple times
Do not convert to string properties multiple times.
2015-09-19 22:21:59 +02:00
Sjur Bakka 7a413df5e4 feat($http): add $xhrFactory service to enable creation of custom xhr objects
Closes #2318
Closes #9319
Closes #12159
2015-09-18 19:52:50 +01:00
Peter Bacon Darwin 4994acd26e fix(filters): ensure formatNumber observes i18n decimal separators
Closes #10342
Closes #12850
2015-09-18 13:45:29 +01:00
202 changed files with 13284 additions and 18272 deletions
-27
View File
@@ -1,27 +0,0 @@
***Note*: for support questions, please use one of these channels: https://github.com/angular/angular.js/blob/master/CONTRIBUTING.md#question. This repository's issues are reserved for feature requests and bug reports.**
**Do you want to request a *feature* or report a *bug*?**
**What is the current behavior?**
**If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem via https://plnkr.co or similar (template: http://plnkr.co/edit/tpl:yBpEi4).**
**What is the expected behavior?**
**What is the motivation / use case for changing the behavior?**
**Which versions of Angular, and which browser / OS are affected by this issue? Did this work in previous versions of Angular? Please also test with the latest stable and snapshot (https://code.angularjs.org/snapshot/) versions.**
**Other information (e.g. stacktraces, related issues, suggestions how to fix)**
-23
View File
@@ -1,23 +0,0 @@
**What kind of change does this PR introduce? (Bug fix, feature, docs update, ...)**
**What is the current behavior? (You can also link to an open issue here)**
**What is the new behavior (if this is a feature change)?**
**Does this PR introduce a breaking change?**
**Please check if the PR fulfills these requirements**
- [ ] The commit message follows our guidelines: https://github.com/angular/angular.js/blob/master/CONTRIBUTING.md#commit-message-format
- [ ] Tests for the changes have been added (for bug fixes / features)
- [ ] Docs have been added / updated (for bug fixes / features)
**Other information**:
+2 -3
View File
@@ -62,7 +62,6 @@ notifications:
webhooks:
urls:
- https://webhooks.gitter.im/e/d2120f3f2bb39a4531b2
- http://104.197.9.155:8484/hubot/travis/activity #hubot-server
on_success: always # options: [always|never|change] default: always
on_success: change # options: [always|never|change] default: always
on_failure: always # options: [always|never|change] default: always
on_start: always # default: false
on_start: false # default: false
+61 -945
View File
File diff suppressed because it is too large Load Diff
-2
View File
@@ -193,8 +193,6 @@ We have very precise rules over how our git commit messages can be formatted. T
readable messages** that are easy to follow when looking through the **project history**. But also,
we use the git commit messages to **generate the AngularJS change log**.
The commit message formatting can be added using a typical git workflow or through the use of a CLI wizard ([Commitizen](https://github.com/commitizen/cz-cli)). To use the wizard, run `npm run commit` in your terminal after staging your changes in git.
### Commit Message Format
Each commit message consists of a **header**, a **body** and a **footer**. The header has a special
format that includes a **type**, a **scope** and a **subject**:
+1 -1
View File
@@ -1,6 +1,6 @@
The MIT License
Copyright (c) 2010-2016 Google, Inc. http://angularjs.org
Copyright (c) 2010-2015 Google, Inc. http://angularjs.org
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
+4 -4
View File
@@ -26,7 +26,7 @@ Building AngularJS
grunt package
Running tests
Running Tests
-------------
To execute all unit tests, use:
@@ -43,7 +43,7 @@ To learn more about the grunt tasks, run `grunt --help` and also read our
[![Analytics](https://ga-beacon.appspot.com/UA-8594346-11/angular.js/README.md?pixel)](https://github.com/igrigorik/ga-beacon)
What to use AngularJS for and when to use it
What to Use AngularJS for and When to Use it
---------
AngularJS is the next generation framework where each component is designed to work with every other component in an interconnected way like a well-oiled machine. AngularJS is JavaScript MVC made easy and done right. (Well it is not really MVC, read on, to understand what this means.)
@@ -61,8 +61,8 @@ Data and Data Models in AngularJS are plain JavaScript objects and one can add a
#### Two-way Data Binding
One of AngularJS's strongest features. Two-way Data Binding means that if something changes in the Model, the change gets reflected in the View instantaneously, and the same happens the other way around. This is also referred to as Reactive Programming, i.e. suppose `a = b + c` is being programmed and after this, if the value of `b` and/or `c` is changed then the value of `a` will be automatically updated to reflect the change. AngularJS uses its "scopes" as a glue between the Model and View and makes these updates in one available for the other.
#### Less Written Code and Easily Maintainable Code
Everything in AngularJS is created to enable the programmer to end up writing less code that is easily maintainable and readable by any other new person on the team. Believe it or not, one can write a complete working two-way data binded application in less than 10 lines of code. Try and see for yourself!
#### Less Written Code and Easily Maintable Code
Everything in AngularJS is created to enable the programmer ends up writing less code that is easily maintainable and readable by any other new person on the team. Believe it or not, one can write a complete working two-way data binded application in less than 10 lines of code. Try and see for yourself!
#### Testing Ready
AngularJS has Dependency Injection, i.e. it takes care of providing all the necessary dependencies to its controllers whenever required. This helps in making the AngularJS code ready for unit testing by making use of mock dependencies created and injected. This makes AngularJS more modular and easily testable thus in turn helping a team create more robust applications.
+1 -1
View File
@@ -20,7 +20,7 @@ The following is done automatically so you don't have to worry about it:
This process based on the idea of minimizing user pain
[from this blog post](http://www.lostgarden.com/2008/05/improving-bug-triage-with-user-pain.html).
1. Open the list of [non triaged issues](https://github.com/angular/angular.js/issues?q=is%3Aopen+sort%3Acreated-desc+no%3Amilestone)
1. Open the list of [non triaged issues](https://github.com/angular/angular.js/issues?direction=desc&milestone=none&page=1&sort=created&state=open)
* Sort by submit date, with the newest issues first
* You don't have to do issues in order; feel free to pick and choose issues as you please.
* You can triage older issues as well
-2
View File
@@ -102,7 +102,6 @@ var angularFiles = {
'src/ngAnimate/animateJsDriver.js',
'src/ngAnimate/animateQueue.js',
'src/ngAnimate/animation.js',
'src/ngAnimate/ngAnimateSwap.js',
'src/ngAnimate/module.js'
],
'ngCookies': [
@@ -205,7 +204,6 @@ var angularFiles = {
"karmaModules": [
'build/angular.js',
'@angularSrcModules',
'test/modules/no_bootstrap.js',
'src/ngScenario/browserTrigger.js',
'test/helpers/*.js',
'test/ngMessageFormat/*.js',
+14 -14
View File
@@ -8,20 +8,20 @@
Large table rendered with AngularJS
</p>
<div><label><input type="radio" ng-model="benchmarkType" value="none">none: </label></div>
<div><label><input type="radio" ng-model="benchmarkType" value="baselineBinding">baseline binding: </label></div>
<div><label><input type="radio" ng-model="benchmarkType" value="baselineInterpolation">baseline interpolation: </label></div>
<div><label><input type="radio" ng-model="benchmarkType" value="ngBind">ngBind: </label></div>
<div><label><input type="radio" ng-model="benchmarkType" value="ngBindOnce">ngBindOnce: </label></div>
<div><label><input type="radio" ng-model="benchmarkType" value="interpolation">interpolation: </label></div>
<div><label><input type="radio" ng-model="benchmarkType" value="bindOnceInterpolation">interpolation + bind-once: </label></div>
<div><label><input type="radio" ng-model="benchmarkType" value="interpolationAttr">attribute interpolation: </label></div>
<div><label><input type="radio" ng-model="benchmarkType" value="ngBindFn">ngBind + fnInvocation: </label></div>
<div><label><input type="radio" ng-model="benchmarkType" value="interpolationFn">interpolation + fnInvocation: </label></div>
<div><label><input type="radio" ng-model="benchmarkType" value="ngBindFilter">ngBind + filter: </label></div>
<div><label><input type="radio" ng-model="benchmarkType" value="interpolationFilter">interpolation + filter: </label></div>
<div><label><input type="radio" ng-model="benchmarkType" value="ngModelConstName">ngModel (const name): </label></div>
<div><label><input type="radio" ng-model="benchmarkType" value="ngModelInterpName">ngModel (interp name): </label></div>
<div>none: <input type="radio" ng-model="benchmarkType" value="none"></div>
<div>baseline binding: <input type="radio" ng-model="benchmarkType" value="baselineBinding"></div>
<div>baseline interpolation: <input type="radio" ng-model="benchmarkType" value="baselineInterpolation"></div>
<div>ngBind: <input type="radio" ng-model="benchmarkType" value="ngBind"></div>
<div>ngBindOnce: <input type="radio" ng-model="benchmarkType" value="ngBindOnce"></div>
<div>interpolation: <input type="radio" ng-model="benchmarkType" value="interpolation"></div>
<div>interpolation + bind-once: <input type="radio" ng-model="benchmarkType" value="bindOnceInterpolation"></div>
<div>attribute interpolation: <input type="radio" ng-model="benchmarkType" value="interpolationAttr"></div>
<div>ngBind + fnInvocation: <input type="radio" ng-model="benchmarkType" value="ngBindFn"></div>
<div>interpolation + fnInvocation: <input type="radio" ng-model="benchmarkType" value="interpolationFn"></div>
<div>ngBind + filter: <input type="radio" ng-model="benchmarkType" value="ngBindFilter"></div>
<div>interpolation + filter: <input type="radio" ng-model="benchmarkType" value="interpolationFilter"></div>
<div>ngModel (const name): <input type="radio" ng-model="benchmarkType" value="ngModelConstName"></div>
<div>ngModel (interp name): <input type="radio" ng-model="benchmarkType" value="ngModelInterpName"></div>
<ng-switch on="benchmarkType">
<baseline-binding-table ng-switch-when="baselineBinding">
+1 -86
View File
@@ -315,13 +315,8 @@ iframe.example {
color:white;
}
.search-results-group .search-results {
padding: 0 5px 0;
list-style-type: none;
}
.search-results-frame > .search-results-group:first-child > .search-results {
border-right:1px solid #222;
border-right:1px solid #050505;
}
.search-results-group.col-group-api { width:30%; }
@@ -330,57 +325,10 @@ iframe.example {
.search-results-group.col-group-misc,
.search-results-group.col-group-error { width:15%; float: right; }
@supports ((column-count: 2) or (-moz-column-count: 2) or (-ms-column-count: 2) or (-webkit-column-count: 2)) {
.search-results-group.col-group-api .search-results {
-moz-column-count: 2;
-ms-column-count: 2;
-webkit-column-count: 2;
column-count: 2;
/* Prevent bullets in the second column from being hidden in Chrome and IE */
-webkit-column-gap: 2em;
-ms-column-gap: 2em;
column-gap: 2em;
}
}
.search-results-group .search-result {
word-wrap: break-word;
-webkit-hyphens: auto;
-moz-hyphens: auto;
-ms-hyphens: auto;
hyphens: auto;
-ms-column-break-inside: avoid;
-webkit-column-break-inside: avoid;
-moz-column-break-inside: avoid; /* Unsupported */
column-break-inside: avoid;
text-indent: -0.65em; /* Make sure line wrapped words are aligned vertically */
}
@supports (-moz-column-count: 2) {
.search-results-group .search-result {
/* Prevents column breaks inside words in FF, but has adverse effects in IE11 and Chrome */
overflow: hidden;
padding-left: 1em; /* In FF the list item bullet is otherwise hidden */
margin-left: -1em; /* offset the padding left */
}
}
.search-result:before {
content: "\002D\00A0"; /* Dash and non-breaking space as List item type */
position: relative;
}
.search-results-group.col-group-api .search-result {
width:48%;
display:inline-block;
padding-left: 12px;
}
@supports ((column-count: 2) or (-moz-column-count: 2) or (-ms-column-count: 2) or (-webkit-column-count: 2)) {
.search-results-group.col-group-api .search-result {
width:auto;
display: list-item;
}
}
.search-close {
@@ -740,11 +688,6 @@ ul.events > li {
padding-bottom:60px;
text-align:left;
}
.search-results-frame > .search-results-group:first-child > .search-results {
border-right: none;
}
.search-results-group {
float:none!important;
display:block!important;
@@ -752,42 +695,14 @@ ul.events > li {
border:0!important;
padding:0!important;
}
@supports ((column-count: 2) or (-moz-column-count: 2) or (-ms-column-count: 2) or (-webkit-column-count: 2)) {
.search-results-group .search-results {
-moz-column-count: 2;
-ms-column-count: 2;
-webkit-column-count: 2;
column-count: 2;
}
}
.search-results-group .search-result {
display:inline-block!important;
padding:0 5px;
width:auto!important;
text-indent: initial;
margin-left: 0;
}
.search-results-group .search-result:after {
content:", ";
}
.search-results-group .search-result:before {
content: "";
}
@supports ((column-count: 2) or (-moz-column-count: 2) or (-ms-column-count: 2) or (-webkit-column-count: 2)) {
.search-results-group .search-result {
display: list-item !important;
}
.search-results-group .search-result:after {
content: "";
}
}
#wrapper {
padding-bottom:0px;
}
+1 -1
View File
@@ -3,7 +3,7 @@
/* global importScripts, onmessage: true, postMessage, lunr */
// Load up the lunr library
importScripts('../components/lunr.js-0.5.12/lunr.min.js');
importScripts('../components/lunr.js-0.4.2/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
+4 -2
View File
@@ -1,11 +1,13 @@
angular.module('DocsController', [])
.controller('DocsController', [
'$scope', '$rootScope', '$location', '$window', '$cookies',
'$scope', '$rootScope', '$location', '$window', '$cookies', 'openPlunkr',
'NG_PAGES', 'NG_NAVIGATION', 'NG_VERSION',
function($scope, $rootScope, $location, $window, $cookies,
function($scope, $rootScope, $location, $window, $cookies, openPlunkr,
NG_PAGES, NG_NAVIGATION, NG_VERSION) {
$scope.openPlunkr = openPlunkr;
$scope.docsVersion = NG_VERSION.isSnapshot ? 'snapshot' : NG_VERSION.version;
$scope.navClass = function(navItem) {
+28 -99
View File
@@ -72,110 +72,29 @@ angular.module('examples', [])
};
}])
.factory('createCopyrightNotice', function() {
var COPYRIGHT = 'Copyright ' + (new Date()).getFullYear() + ' Google Inc. All Rights Reserved.\n'
+ 'Use of this source code is governed by an MIT-style license that\n'
+ 'can be found in the LICENSE file at http://angular.io/license';
var COPYRIGHT_JS_CSS = '\n\n/*\n' + COPYRIGHT + '\n*/';
var COPYRIGHT_HTML = '\n\n<!-- \n' + COPYRIGHT + '\n-->';
return function getCopyright(filename) {
switch (filename.substr(filename.lastIndexOf('.'))) {
case '.html':
return COPYRIGHT_HTML;
case '.js':
case '.css':
return COPYRIGHT_JS_CSS;
case '.md':
return COPYRIGHT;
}
return '';
};
})
.factory('openPlunkr', ['formPostData', '$http', '$q', function(formPostData, $http, $q) {
return function(exampleFolder, clickEvent) {
.directive('plnkrOpener', ['$q', 'getExampleData', 'formPostData', 'createCopyrightNotice', function($q, getExampleData, formPostData, createCopyrightNotice) {
return {
scope: {},
bindToController: {
'examplePath': '@'
},
controllerAs: 'plnkr',
template: '<button ng-click="plnkr.open($event)" class="btn pull-right"> <i class="glyphicon glyphicon-edit">&nbsp;</i> Edit in Plunker</button> ',
controller: [function() {
var ctrl = this;
var exampleName = 'AngularJS Example';
var newWindow = clickEvent.ctrlKey || clickEvent.metaKey;
ctrl.example = {
path: ctrl.examplePath,
manifest: undefined,
files: undefined,
name: 'AngularJS Example'
};
ctrl.prepareExampleData = function() {
if (ctrl.example.manifest) {
return $q.when(ctrl.example);
}
return getExampleData(ctrl.examplePath).then(function(data) {
ctrl.example.files = data.files;
ctrl.example.manifest = data.manifest;
// Build a pretty title for the Plunkr
var exampleNameParts = data.manifest.name.split('-');
exampleNameParts.unshift('AngularJS');
angular.forEach(exampleNameParts, function(part, index) {
exampleNameParts[index] = part.charAt(0).toUpperCase() + part.substr(1);
});
ctrl.example.name = exampleNameParts.join(' - ');
return ctrl.example;
});
};
ctrl.open = function(clickEvent) {
var newWindow = clickEvent.ctrlKey || clickEvent.metaKey;
var postData = {
'tags[0]': "angularjs",
'tags[1]': "example",
'private': true
};
// Make sure the example data is available.
// If an XHR must be made, this might break some pop-up blockers when
// new window is requested
ctrl.prepareExampleData()
.then(function() {
angular.forEach(ctrl.example.files, function(file) {
postData['files[' + file.name + ']'] = file.content + createCopyrightNotice(file.name);
});
postData.description = ctrl.example.name;
formPostData('http://plnkr.co/edit/?p=preview', newWindow, postData);
});
};
// 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);
}]
};
}])
.factory('getExampleData', ['$http', '$q', function($http, $q) {
return function(exampleFolder){
// Load the manifest for the example
return $http.get(exampleFolder + '/manifest.json')
$http.get(exampleFolder + '/manifest.json')
.then(function(response) {
return response.data;
})
.then(function(manifest) {
var filePromises = [];
// Build a pretty title for the Plunkr
var exampleNameParts = manifest.name.split('-');
exampleNameParts.unshift('AngularJS');
angular.forEach(exampleNameParts, function(part, index) {
exampleNameParts[index] = part.charAt(0).toUpperCase() + part.substr(1);
});
exampleName = exampleNameParts.join(' - ');
angular.forEach(manifest.files, function(filename) {
filePromises.push($http.get(exampleFolder + '/' + filename, { transformResponse: [] })
.then(function(response) {
@@ -183,7 +102,7 @@ angular.module('examples', [])
// The manifests provide the production index file but Plunkr wants
// a straight index.html
if (filename === "index-production.html") {
filename = "index.html";
filename = "index.html"
}
return {
@@ -192,11 +111,21 @@ angular.module('examples', [])
};
}));
});
return $q.all(filePromises);
})
.then(function(files) {
var postData = {};
return $q.all({
manifest: manifest,
files: $q.all(filePromises)
angular.forEach(files, function(file) {
postData['files[' + file.name + ']'] = file.content;
});
postData['tags[0]'] = "angularjs";
postData['tags[1]'] = "example";
postData.private = true;
postData.description = exampleName;
formPostData('http://plnkr.co/edit/?p=preview', newWindow, postData);
});
};
}]);
}]);
+1 -9
View File
@@ -11,15 +11,7 @@ angular.module('search', [])
var MIN_SEARCH_LENGTH = 2;
if(q.length >= MIN_SEARCH_LENGTH) {
docsSearch(q).then(function(hits) {
// Make sure the areas are always in the same order
var results = {
api: [],
guide: [],
tutorial: [],
error: [],
misc: []
};
var results = {};
angular.forEach(hits, function(hit) {
var area = hit.area;
+2 -1
View File
@@ -3,6 +3,7 @@ describe("DocsController", function() {
angular.module('fake', [])
.value('$cookies', {})
.value('openPlunkr', function() {})
.value('NG_PAGES', {})
.value('NG_NAVIGATION', {})
.value('NG_VERSION', {});
@@ -25,7 +26,7 @@ describe("DocsController", function() {
it("should update the Google Analytics with $location.path if currentPage is missing", inject(function($window, $location) {
$window._gaq = [];
spyOn($location, 'path').and.returnValue('x/y/z');
spyOn($location, 'path').andReturn('x/y/z');
$scope.$broadcast('$includeContentLoaded');
expect($window._gaq.pop()).toEqual(['_trackPageview', 'x/y/z']);
}));
+7 -7
View File
@@ -4,7 +4,7 @@ describe('errors', function() {
// Mock `ngSanitize` module
angular.
module('ngSanitize', []).
value('$sanitize', jasmine.createSpy('$sanitize').and.callFake(angular.identity));
value('$sanitize', jasmine.createSpy('$sanitize').andCallFake(angular.identity));
beforeEach(module('errors'));
@@ -103,12 +103,12 @@ describe('errors', function() {
it('should pass the final string through `$sanitize`', function() {
$sanitize.calls.reset();
$sanitize.reset();
var input = 'start https://foo/bar?baz#qux end';
var output = errorLinkFilter(input);
expect($sanitize).toHaveBeenCalledTimes(1);
expect($sanitize.callCount).toBe(1);
expect($sanitize).toHaveBeenCalledWith(output);
});
});
@@ -123,7 +123,7 @@ describe('errors', function() {
beforeEach(module(function($provide) {
$provide.decorator('errorLinkFilter', function() {
errorLinkFilter = jasmine.createSpy('errorLinkFilter');
errorLinkFilter.and.callFake(angular.identity);
errorLinkFilter.andCallFake(angular.identity);
return errorLinkFilter;
});
@@ -142,7 +142,7 @@ describe('errors', function() {
it('should interpolate the contents against `$location.search()`', function() {
spyOn($location, 'search').and.returnValue({p0: 'foo', p1: 'bar'});
spyOn($location, 'search').andReturn({p0: 'foo', p1: 'bar'});
var elem = $compile('<span error-display="foo = {0}, bar = {1}"></span>')($rootScope);
expect(elem.html()).toBe('foo = foo, bar = bar');
@@ -150,10 +150,10 @@ describe('errors', function() {
it('should pass the interpolated text through `errorLinkFilter`', function() {
$location.search = jasmine.createSpy('search').and.returnValue({p0: 'foo'});
$location.search = jasmine.createSpy('search').andReturn({p0: 'foo'});
var elem = $compile('<span error-display="foo = {0}"></span>')($rootScope);
expect(errorLinkFilter).toHaveBeenCalledTimes(1);
expect(errorLinkFilter.callCount).toBe(1);
expect(errorLinkFilter).toHaveBeenCalledWith('foo = foo', '_blank');
});
+1 -1
View File
@@ -2,7 +2,7 @@
"name": "AngularJS-docs-app",
"dependencies": {
"jquery": "2.1.1",
"lunr.js": "0.5.12",
"lunr.js": "0.4.3",
"open-sans-fontface": "1.0.4",
"google-code-prettify": "1.0.1",
"bootstrap": "3.1.1"
@@ -147,13 +147,13 @@
<div class="search-results-container" ng-show="hasResults">
<div class="container">
<div class="search-results-frame">
<div ng-repeat="(key, value) in results track by key" class="search-results-group" ng-class="colClassName + ' col-group-' + key" ng-show="value.length > 0">
<div ng-repeat="(key, value) in results" class="search-results-group" ng-class="colClassName + ' col-group-' + key">
<h4 class="search-results-group-heading">{{ key }}</h4>
<ul class="search-results">
<!-- Do not insert a line break between li and a. Chrome will insert an actual line-break, which breaks the list item view.
TODO: use a html minifier instead -->
<li ng-repeat="item in value" class="search-result"><a ng-click="hideResults()" ng-href="{{ item.path }}">{{ item.name }}</a></li>
</ul>
<div class="search-results">
<div ng-repeat="item in value" class="search-result">
- <a ng-click="hideResults()" ng-href="{{ item.path }}">{{ item.name }}</a>
</div>
</div>
</div>
</div>
<a href="" ng-click="hideResults()" class="search-close">
@@ -220,7 +220,7 @@
<p class="pull-right"><a back-to-top>Back to top</a></p>
<p>
Super-powered by Google ©2010-2016
Super-powered by Google ©2010-2015
( <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">
@@ -2,7 +2,9 @@
is HTML and wrap each line in a <p> - thus breaking the HTML #}
<div>
<plnkr-opener example-path="{$ doc.path $}"></plnkr-opener>
<a ng-click="openPlunkr('{$ doc.path $}', $event)" class="btn pull-right">
<i class="glyphicon glyphicon-edit">&nbsp;</i>
Edit in Plunker</a>
<div class="runnable-example"
path="{$ doc.example.deployments.default.path $}"
+2 -2
View File
@@ -3,7 +3,7 @@
@fullName Invalid Isolate Scope Definition
@description
When declaring isolate scope the scope definition object must be in specific format which starts with mode character (`@&=<`), after which comes an optional `?`, and it ends with an optional local name.
When declaring isolate scope the scope definition object must be in specific format which starts with mode character (`@&=`) with an optional local name.
```
myModule.directive('directiveName', function factory() {
@@ -12,7 +12,7 @@ myModule.directive('directiveName', function factory() {
scope: {
'attrName': '@', // OK
'attrName2': '=localName', // OK
'attrName3': '<?localName', // OK
'attrName3': '&?localName', // OK
'attrName4': ' = name', // OK
'attrName5': 'name', // ERROR: missing mode @&=
'attrName6': 'name=', // ERROR: must be prefixed with @&=
+2 -2
View File
@@ -31,7 +31,7 @@ single root element, like the `div` element in this template:
<div><b>Hello</b> World!</div>
```
An invalid template to be used with this directive is one that defines multiple root nodes or
An an invalid template to be used with this directive is one that defines multiple root nodes or
elements. For example:
```
@@ -43,7 +43,7 @@ well. Consider the following template:
```
<div class='container'>
<div class='wrapper'>
<div class='wrapper>
...
</div> <!-- wrapper -->
</div> <!-- container -->
+1 -1
View File
@@ -1,6 +1,6 @@
@ngdoc error
@name $location:nobase
@fullName $location in HTML5 mode requires a &lt;base&gt; tag to be present!
@fullName $location in HTML5 mode requires a `<base>` tag to be present!
@description
If you configure {@link ng.$location `$location`} to use
@@ -14,32 +14,3 @@ perform this check - it's up to the developer to not expose such sensitive and p
directly on the scope chain.
To resolve this error, avoid 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;
```
@@ -0,0 +1,11 @@
@ngdoc error
@name $sanitize:badparse
@fullName Parsing Error while Sanitizing
@description
This error occurs when the HTML string passed to '$sanitize' can't be parsed by the sanitizer.
The error contains part of the html string that can't be parsed.
The parser is more strict than a typical browser parser, so it's possible that some obscure input would produce this error despite the string being recognized as valid HTML by a browser.
If a valid html code results in this error, please file a bug.
@@ -1,10 +0,0 @@
@ngdoc error
@name $sanitize:noinert
@fullName Can't create an inert html document
@description
This error occurs when `$sanitize` sanitizer determines that `document.implementation.createHTMLDocument ` api is not supported by the current browser.
This api is necessary for safe parsing of HTML strings into DOM trees and without it the sanitizer can't sanitize the input.
The api is present in all supported browsers including IE 9.0, so the presence of this error usually indicates that Angular's `$sanitize` is being used on an unsupported platform.
-13
View File
@@ -1,13 +0,0 @@
@ngdoc error
@name $sanitize:uinput
@fullName Failed to sanitize html because the input is unstable
@description
This error occurs when `$sanitize` sanitizer tries to check the input for possible mXSS payload and the verification
errors due to the input mutating indefinitely. This could be a sign that the payload contains code exploiting an mXSS
vulnerability in the browser.
mXSS attack exploit browser bugs that cause some browsers parse a certain html strings into DOM, which once serialized
doesn't match the original input. These browser bugs can be exploited by attackers to create payload which looks
harmless to sanitizers, but due to mutations caused by the browser are turned into dangerous code once processed after
sanitization.
-16
View File
@@ -1,16 +0,0 @@
@ngdoc error
@name linky:notstring
@fullName Not a string
@description
This error occurs when {@link ngSanitize.linky linky} is used with a non-empty, non-string value:
```html
<div ng-bind-html="42 | linky"></div>
```
`linky` is supposed to be used with string values only, and therefore assumes that several methods
(such as `.match()`) are available on the passed in value.
The value can be initialized asynchronously and therefore null or undefined won't throw this error.
If you want to pass non-string values to `linky` (e.g. Objects whose `.toString()` should be
utilized), you need to manually convert them to strings.
-52
View File
@@ -1,52 +0,0 @@
@ngdoc error
@name orderBy:notarray
@fullName Value is not array-like
@description
This error occurs when {@link ng.orderBy orderBy} is not passed an array-like value:
```html
<div ng-repeat="(key, value) in myObj | orderBy:someProp">
{{ key }} : {{ value }}
</div>
```
`orderBy` must be used with an array-like value so a subset of items can be returned.
The array can be initialized asynchronously and therefore `null` or `undefined` won't throw this error.
To use `orderBy` to order the properties of an object, you can create your own array based on that object:
```js
angular.module('aModule', [])
.controller('aController', function($scope) {
var myObj = {
one: {id: 1, name: 'Some thing'},
two: {id: 2, name: 'Another thing'},
three: {id: 3, name: 'A third thing'}
};
$scope.arrFromMyObj = Object.keys(myObj).map(function(key) {
return myObj[key];
});
});
```
That can be used as:
```html
<label>
Order by:
<select ng-model="orderProp" ng-options="prop for prop in ['id', 'name']"></select>
</label>
<div ng-repeat="item in arrFromMyObj | orderBy:orderProp">
[{{ item.id }}] {{ item.name }}
</div>
```
You could as well convert the object to an array using a filter such as
[toArrayFilter](https://github.com/petebacondarwin/angular-toArrayFilter):
```html
<label>
Order by:
<select ng-model="orderProp" ng-options="prop for prop in ['id', 'name']"></select>
</label>
<div ng-repeat="item in myObj | toArray:false | orderBy:orderProp">
[{{ item.id }}] {{ item.name }}
</div>
```
+1 -1
View File
@@ -350,7 +350,7 @@ base and the path that should be handled by the application.
### Base href constraints
The `$location` service is not able to function properly if the current URL is outside the URL given
as the base href. This can have subtle confusing consequencies...
as the base href. This can have subtle confusing consequences...
Consider a base href set as follows: `<base href="/base/">` (i.e. the application exists in the "folder"
called `/base`). The URL `/base` is actually outside the application (it refers to the `base` file found
+6 -49
View File
@@ -33,9 +33,6 @@ Currently, ngAria interfaces with the following directives:
* {@link guide/accessibility#ngmodel ngModel}
* {@link guide/accessibility#ngdisabled ngDisabled}
* {@link guide/accessibility#ngrequired ngRequired}
* {@link guide/accessibility#ngvaluechecked ngChecked}
* {@link guide/accessibility#ngvaluechecked ngValue}
* {@link guide/accessibility#ngshow ngShow}
* {@link guide/accessibility#nghide ngHide}
* {@link guide/accessibility#ngclick ngClick}
@@ -44,7 +41,7 @@ Currently, ngAria interfaces with the following directives:
<h2 id="ngmodel">ngModel</h2>
Much of ngAria's heavy lifting happens in the {@link ng.ngModel ngModel}
Much of ngAria's heavy lifting happens in the {@link ng.directive:ngModel ngModel}
directive. For elements using ngModel, special attention is paid by ngAria if that element also
has a role or type of `checkbox`, `radio`, `range` or `textbox`.
@@ -140,72 +137,32 @@ the keyboard. It is still up to **you** as a developer to **ensure custom contro
accessible**. As a rule, any time you create a widget involving user interaction, be sure to test
it with your keyboard and at least one mobile and desktop screen reader.
<h2 id="ngvaluechecked">ngValue and ngChecked</h2>
To ease the transition between native inputs and custom controls, ngAria now supports
{@link ng.ngValue ngValue} and {@link ng.ngChecked ngChecked}.
The original directives were created for native inputs only, so ngAria extends
support to custom elements by managing `aria-checked` for accessibility.
###Example
```html
<custom-checkbox ng-checked="val"></custom-checkbox>
<custom-radio-button ng-value="val"></custom-radio-button>
```
Becomes:
```html
<custom-checkbox ng-checked="val" aria-checked="true"></custom-checkbox>
<custom-radio-button ng-value="val" aria-checked="true"></custom-radio-button>
```
<h2 id="ngdisabled">ngDisabled</h2>
The `disabled` attribute is only valid for certain elements such as `button`, `input` and
`textarea`. To properly disable custom element directives such as `<md-checkbox>` or `<taco-tab>`,
using ngAria with {@link ng.ngDisabled ngDisabled} will also
using ngAria with {@link ng.directive:ngDisabled ngDisabled} will also
add `aria-disabled`. This tells assistive technologies when a non-native input is disabled, helping
custom controls to be more accessible.
###Example
```html
<md-checkbox ng-disabled="disabled"></md-checkbox>
<md-checkbox ng-disabled="disabled">
```
Becomes:
```html
<md-checkbox disabled aria-disabled="true"></md-checkbox>
<md-checkbox disabled aria-disabled="true">
```
>You can check whether a control is legitimately disabled for a screen reader by visiting
[chrome://accessibility](chrome://accessibility) and inspecting [the accessibility tree](http://www.paciellogroup.com/blog/2015/01/the-browser-accessibility-tree/).
<h2 id="ngrequired">ngRequired</h2>
The boolean `required` attribute is only valid for native form controls such as `input` and
`textarea`. To properly indicate custom element directives such as `<md-checkbox>` or `<custom-input>`
as required, using ngAria with {@link ng.ngRequired ngRequired} will also add
`aria-required`. This tells accessibility APIs when a custom control is required.
###Example
```html
<md-checkbox ng-required="val"></md-checkbox>
```
Becomes:
```html
<md-checkbox ng-required="val" aria-required="true"></md-checkbox>
```
<h2 id="ngshow">ngShow</h2>
>The {@link ng.ngShow ngShow} directive shows or hides the
>The {@link ng.directive:ngShow ngShow} directive shows or hides the
given HTML element based on the expression provided to the `ngShow` attribute. The element is
shown or hidden by removing or adding the `.ng-hide` CSS class onto the element.
@@ -242,7 +199,7 @@ Becomes:
<h2 id="nghide">ngHide</h2>
>The {@link ng.ngHide ngHide} directive shows or hides the
>The {@link ng.directive:ngHide ngHide} directive shows or hides the
given HTML element based on the expression provided to the `ngHide` attribute. The element is
shown or hidden by removing or adding the `.ng-hide` CSS class onto the element.
+1 -138
View File
@@ -6,7 +6,7 @@
# Animations
AngularJS provides animation hooks for common directives such as `ngRepeat`, `ngSwitch`, and `ngView`, as well as custom directives
AngularJS 1.3 provides animation hooks for common directives such as `ngRepeat`, `ngSwitch`, and `ngView`, as well as custom directives
via the `$animate` service. These animation hooks are set in place to trigger animations during the life cycle of various directives and when
triggered, will attempt to perform a CSS Transition, CSS Keyframe Animation or a JavaScript callback Animation (depending on if an animation is
placed on the given directive). Animations can be placed using vanilla CSS by following the naming conventions set in place by AngularJS
@@ -274,100 +274,6 @@ myModule.directive('my-directive', ['$animate', function($animate) {
}]);
```
## Animations on app bootstrap / page load
By default, animations are disabled when the Angular app {@link guide/bootstrap bootstraps}. If you are using the {@link ngApp} directive,
this happens in the `DOMContentLoaded` event, so immediately after the page has been loaded.
Animations are disabled, so that UI and content are instantly visible. Otherwise, with many animations on
the page, the loading process may become too visually overwhelming, and the performance may suffer.
Internally, `ngAnimate` waits until all template downloads that are started right after bootstrap have finished.
Then, it waits for the currently running {@link ng.$rootScope.Scope#$digest} and the one after that to finish.
This ensures that the whole app has been compiled fully before animations are attempted.
If you do want your animations to play when the app bootstraps, you can enable animations globally in
your main module's {@link angular.Module#run run} function:
```js
myModule.run(function($animate) {
$animate.enabled(true);
});
```
## How to (selectively) enable, disable and skip animations
There are three different ways to disable animations, both globally and for specific animations.
Disabling specific animations can help to speed up the render performance, for example for large `ngRepeat`
lists that don't actually have animations. Because ngAnimate checks at runtime if animations are present,
performance will take a hit even if an element has no animation.
### In the config: {@link $animateProvider#classNameFilter $animateProvider.classNameFilter()}
This function can be called in the {@link angular.Module#config config} phase of an app. It takes a regex as the only argument,
which will then be matched against the classes of any element that is about to be animated. The regex
allows a lot of flexibility - you can either allow animations only for specific classes (useful when
you are working with 3rd party animations), or exclude specific classes from getting animated.
```js
app.config(function($animateProvider) {
$animateProvider.classNameFilter(/animate-/);
});
```
```css
/&#42; prefixed with animate- &#42;/
.animate-fade-add.animate-fade-add-active {
transition:1s linear all;
opacity:0;
}
```
The classNameFilter approach generally applies the biggest speed boost, because the matching is
done before any other animation disabling strategies are checked. However, that also means it is not
possible to override class name matching with the two following strategies. It's of course still possible
to enable / disable animations by changing an element's class name at runtime.
### At runtime: {@link ng.$animate#enabled $animate.enabled()}
This function can be used to enable / disable animations in two different ways:
With a single `boolean` argument, it enables / disables animations globally: `$animate.enabled(false)`
disables all animations in your app.
When the second argument is a native DOM or jQuery element, the function enables / disables
animations on this element *and all its children*: `$animate.enabled(false, myElement)`. This is the
most flexible way to change the animation state. For example, even if you have used it to disable
animations on a parent element, you can still re-enable it for a child element. And compared to the
`classNameFilter`, you can change the animation status at runtime instead of during the config phase.
Note however that the `$animate.enabled()` state for individual elements does not overwrite disabling
rules that have been set in the {@link $animateProvider#classNameFilter classNameFilter}.
### Via CSS styles: overwriting styles in the `ng-animate` CSS class
Whenever an animation is started, ngAnimate applies the `ng-animate` class to the element for the
whole duration of the animation. By applying CSS transition / animation styling to the class,
you can skip an animation:
```css
.my-class{
transition: transform 2s;
}
.my-class:hover {
transform: translateX(50px);
}
my-class.ng-animate {
transition: 0s;
}
```
By setting `transition: 0s`, ngAnimate will ignore the existing transition styles, and not try to animate them (Javascript
animations will still execute, though). This can be used to prevent {@link guide/animations#preventing-collisions-with-existing-animations-and-third-party-libraries
issues with existing animations interfering with ngAnimate}.
## Preventing flicker before an animation starts
When nesting elements with structural animations such as `ngIf` into elements that have class-based
@@ -399,49 +305,6 @@ In that case, you can add styles to the CSS that make sure the element stays hid
/* Other animation styles ... */
```
## Preventing Collisions with Existing Animations and Third Party Libraries
By default, any `ngAnimate` enabled directives will assume any transition / animation styles on the
element are part of an `ngAnimate` animation. This can lead to problems when the styles are actually
for animations that are independent of `ngAnimate`.
For example, an element acts as a loading spinner. It has an inifinite css animation on it, and also an
{@link ngIf `ngIf`} directive, for which no animations are defined:
```css
@keyframes rotating {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.spinner {
animation: rotating 2s linear infinite;
}
```
Now, when the `ngIf` changes, `ngAnimate` will see the spinner animation and use
it to animate the `enter`/`leave` event, which doesn't work because
the animation is infinite. The element will still be added / removed after a timeout, but there will be a
noticable delay.
This might also happen because some third-party frameworks place animation duration defaults
across many element or className selectors in order to make their code small and reuseable.
You can prevent this unwanted behavior by adding CSS to the `.ng-animate` class that is added
for the whole duration of an animation. Simply overwrite the transition / animation duration. In the
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.
You can also use one of the two other {@link guide/animations#how-to-selectively-enable-disable-and-skip-animations strategies to disable animations}.
## More about animations
For a full breakdown of each method available on `$animate`, see the {@link ng.$animate API documentation}.
+3 -14
View File
@@ -53,13 +53,13 @@ initialization.
Angular initializes automatically upon `DOMContentLoaded` event or when the `angular.js` script is
evaluated if at that time `document.readyState` is set to `'complete'`. At this point Angular looks
for the {@link ng.directive:ngApp `ngApp`} directive which designates your application root.
If the {@link ng.directive:ngApp `ngApp`} directive is found then Angular will:
for the {@link ng.directive:ngApp `ng-app`} directive which designates your application root.
If the {@link ng.directive:ngApp `ng-app`} directive is found then Angular will:
* load the {@link guide/module module} associated with the directive.
* create the application {@link auto.$injector injector}
* compile the DOM treating the {@link ng.directive:ngApp
`ngApp`} directive as the root of the compilation. This allows you to tell it to treat only a
`ng-app`} directive as the root of the compilation. This allows you to tell it to treat only a
portion of the DOM as an Angular application.
@@ -142,17 +142,6 @@ This is the sequence that your code should follow:
2. Call {@link angular.bootstrap} to {@link compiler compile} the element into an
executable, bi-directionally bound application.
## Things to keep in mind
There a few things to keep in mind regardless of automatic or manual bootstrapping:
- While it's possible to bootstrap more than one AngularJS application per page, we don't actively
test against this scenario. It's possible that you'll run into problems, especially with complex apps, so
caution is advised.
- Do not bootstrap your app on an element with a directive that uses {@link ng.$compile#transclusion transclusion}, such as
{@link ng.ngIf `ngIf`}, {@link ng.ngInclude `ngInclude`} and {@link ngRoute.ngView `ngView`}.
Doing this misplaces the app {@link ng.$rootElement `$rootElement`} and the app's {@link auto.$injector injector},
causing animations to stop working and making the injector inaccessible from outside the app.
## Deferred Bootstrap
File diff suppressed because it is too large Load Diff
-471
View File
@@ -1,471 +0,0 @@
@ngdoc overview
@name Components
@sortOrder 305
@description
# Understanding Components
In Angular, a Component is a special kind of {@link guide/directive directive} that uses a simpler
configuration which is suitable for a component-based application structure.
This makes it easier to write an app in a way that's similar to using Web Components or using Angular
2's style of application architecture.
Advantages of Components:
- simpler configuration than plain directives
- promote sane defaults and best practices
- optimized for component-based architecture
- writing component directives will make it easier to upgrade to Angular 2
When not to use Components:
- for directives that rely on DOM manipulation, adding event listeners etc, because the compile
and link functions are unavailable
- when you need advanced directive definition options like priority, terminal, multi-element
- when you want a directive that is triggered by an attribute or CSS class, rather than an element
## Creating and configuring a Component
Components can be registered using the `.component()` method of an Angular module (returned by {@link module `angular.module()`}). The method takes two arguments:
* The name of the Component (as string).
* The Component config object (note that, unlike the `.directive()` method, this method does **not** take a factory function.
<example name="heroComponentSimple" module="heroApp">
<file name="index.js">
angular.module('heroApp', []).controller('mainCtrl', function() {
this.hero = {
name: 'Spawn'
};
});
</file>
<file name="heroDetail.js">
function HeroDetailController() {
}
angular.module('heroApp').component('heroDetail', {
templateUrl: 'heroDetail.html',
controller: HeroDetailController,
bindings: {
hero: '='
}
});
</file>
<file name="index.html">
<!-- components match only elements -->
<div ng-controller="mainCtrl as ctrl">
<b>Hero</b><br>
<hero-detail hero="ctrl.hero"></hero-detail>
</div>
</file>
<file name="heroDetail.html">
<span>Name: {{$ctrl.hero.name}}</span>
</file>
</example>
It's also possible to add components via {@link $compileProvider#component} in a module's config phase.
### Comparison between Directive definition and Component definition
| | Directive | Component |
|-------------------|----------------------|-----------------|
| bindings | No | Yes (binds to controller) |
| bindToController | Yes (default: false) | No (use bindings instead) |
| compile function | Yes | No |
| controller | Yes | Yes (default `function() {}`) |
| controllerAs | Yes (default: false) | Yes (default: `$ctrl`) |
| link functions | Yes | No |
| multiElement | Yes | No |
| priority | Yes | No |
| require | Yes | Yes |
| restrict | Yes | No (restricted to elements only) |
| scope | Yes (default: false) | No (scope is always isolate) |
| template | Yes | Yes, injectable |
| templateNamespace | Yes | No |
| templateUrl | Yes | Yes, injectable |
| terminal | Yes | No |
| transclude | Yes (default: false) | Yes (default: false) |
## Component-based application architecture
As already mentioned, the component helper makes it easier to structure your application with
a component-based architecture. But what makes a component beyond the options that
the component helper has?
- **Components only control their own View and Data:**
Components should never modify any data or DOM that is out of their own scope. Normally, in Angular
it is possible to modify data anywhere in the application through scope inheritance and watches. This
is practical, but can also lead to problems when it is not clear which part of the application is
responsible for modifying the data. That is why component directives use an isolate scope, so a whole
class of scope manipulation is not possible.
- **Components have a well-defined public API - Inputs and Outputs:**
However, scope isolation only goes so far, because Angular uses two-way binding. So if you pass
an object to a component like this - `bindings: {item: '='}`, and modify one of its properties, the
change will be reflected in the parent component. For components however, only the component that owns
the data should modify it, to make it easy to reason about what data is changed, and when. For that reason,
components should follow a few simple conventions:
- Inputs should be using `<` and `@` bindings. The `<` symbol denotes {@link $compile#-scope- one-way bindings} which are
available since 1.5. The difference to `=` is that the bound properties in the component scope are not watched, which means
if you assign a new value to the property in the component scope, it will not update the parent scope. Note however, that both parent
and component scope reference the same object, so if you are changing object properties or array elements in the
component, the parent will still reflect that change.
The general rule should therefore be to never change an object or array property in the component scope.
`@` bindings can be used when the input is a string, especially when the value of the binding doesn't change.
```js
bindings: {
hero: '<',
comment: '@'
}
```
- Outputs are realized with `&` bindings, which function as callbacks to component events.
```js
bindings: {
onDelete: '&',
onUpdate: '&'
}
```
- Instead of manipulating Input Data, the component calls the correct Output Event with the changed data.
For a deletion, that means the component doesn't delete the `hero` itself, but sends it back to
the owner component via the correct event.
```html
<button ng-click="$ctrl.onDelete({hero: $ctrl.hero})">Delete</button>
```
- That way, the parent component can decide what to do with the event (e.g. delete an item or update the properties)
```js
ctrl.deleteHero(hero) {
$http.delete(...).then(function() {
var idx = ctrl.list.indexOf(hero);
if (idx >= 0) {
ctrl.list.splice(idx, 1);
}
});
}
```
- **An application is a tree of components:**
Ideally, the whole application should be a tree of components that implement clearly defined inputs
and outputs, and minimize two-way data binding. That way, it's easier to predict when data changes and what the state
of a component is.
## Example of a component tree
The following example expands on the simple component example and incorporates the concepts we introduced
above:
Instead of an ngController, we now have a heroList component that holds the data of
different heroes, and creates a heroDetail for each of them.
The heroDetail component now contains new functionality:
- a delete button that calls the bound `onDelete` function of the heroList component
- an input to change the hero location, in the form of a reusable editableField component. Instead
of manipulating the hero object itself, it sends a changeset upwards to the heroDetail, which sends
it upwards to the heroList component, which updates the original data.
<example name="heroComponentTree" module="heroApp">
<file name="index.js">
var mode = angular.module('heroApp', []);
</file>
<file name="heroList.js">
function HeroListController($scope, $element, $attrs) {
var ctrl = this;
// This would be loaded by $http etc.
ctrl.list = [
{
name: 'Superman',
location: ''
},
{
name: 'Batman',
location: 'Wayne Manor'
}
];
ctrl.updateHero = function(hero, prop, value) {
hero[prop] = value;
};
ctrl.deleteHero = function(hero) {
var idx = ctrl.list.indexOf(hero);
if (idx >= 0) {
ctrl.list.splice(idx, 1);
}
};
}
angular.module('heroApp').component('heroList', {
templateUrl: 'heroList.html',
controller: HeroListController
});
</file>
<file name="heroDetail.js">
function HeroDetailController($scope, $element, $attrs) {
var ctrl = this;
ctrl.update = function(prop, value) {
ctrl.onUpdate({hero: ctrl.hero, prop: prop, value: value});
};
}
angular.module('heroApp').component('heroDetail', {
templateUrl: 'heroDetail.html',
controller: HeroDetailController,
bindings: {
hero: '<',
onDelete: '&',
onUpdate: '&'
}
});
</file>
<file name="editableField.js">
function EditableFieldController($scope, $element, $attrs) {
var ctrl = this;
ctrl.editMode = false;
ctrl.handleModeChange = function() {
if (ctrl.editMode) {
ctrl.onUpdate({value: ctrl.fieldValue});
ctrl.fieldValueCopy = ctrl.fieldValue;
}
ctrl.editMode = !ctrl.editMode;
};
ctrl.reset = function() {
ctrl.fieldValue = ctrl.fieldValueCopy;
};
ctrl.$onInit = function() {
// Make a copy of the initial value to be able to reset it later
ctrl.fieldValueCopy = ctrl.fieldValue;
// Set a default fieldType
if (!ctrl.fieldType) {
ctrl.fieldType = 'text';
}
};
}
angular.module('heroApp').component('editableField', {
templateUrl: 'editableField.html',
controller: EditableFieldController,
bindings: {
fieldValue: '<',
fieldType: '@?',
onUpdate: '&'
}
});
</file>
<file name="index.html">
<hero-list></hero-list>
</file>
<file name="heroList.html">
<b>Heroes</b><br>
<hero-detail ng-repeat="hero in $ctrl.list" hero="hero" on-delete="$ctrl.deleteHero(hero)" on-update="$ctrl.updateHero(hero, prop, value)"></hero-detail>
</file>
<file name="heroDetail.html">
<hr>
<div>
Name: {{$ctrl.hero.name}}<br>
Location: <editable-field field-value="$ctrl.hero.location" field-type="text" on-update="$ctrl.update('location', value)"></editable-field><br>
<button ng-click="$ctrl.onDelete({hero: $ctrl.hero})">Delete</button>
</div>
</file>
<file name="editableField.html">
<span ng-switch="$ctrl.editMode">
<input ng-switch-when="true" type="{{$ctrl.fieldType}}" ng-model="$ctrl.fieldValue">
<span ng-switch-default>{{$ctrl.fieldValue}}</span>
</span>
<button ng-click="$ctrl.handleModeChange()">{{$ctrl.editMode ? 'Save' : 'Edit'}}</button>
<button ng-if="$ctrl.editMode" ng-click="$ctrl.reset()">Reset</button>
</file>
</example>
## Components as route templates
Components are also useful as route templates (e.g. when using {@link ngRoute ngRoute}). In a component-based
application, every view is a component:
```js
var myMod = angular.module('myMod', ['ngRoute']);
myMod.component('home', {
template: '<h1>Home</h1><p>Hello, {{ $ctrl.user.name }} !</p>',
controller: function() {
this.user = {name: 'world'};
}
});
myMod.config(function($routeProvider) {
$routeProvider.when('/', {
template: '<home></home>'
});
});
```
<br />
When using {@link ngRoute.$routeProvider $routeProvider}, you can often avoid some
boilerplate, by passing the resolved route dependencies directly to the component. Since 1.5,
ngRoute automatically assigns the resolves to the route scope property `$resolve` (you can also
configure the property name via `resolveAs`). When using components, you can take advantage of this and pass resolves
directly into your component without creating an extra route controller:
```js
var myMod = angular.module('myMod', ['ngRoute']);
myMod.component('home', {
template: '<h1>Home</h1><p>Hello, {{ $ctrl.user.name }} !</p>',
bindings: {
user: '<'
}
});
myMod.config(function($routeProvider) {
$routeProvider.when('/', {
template: '<home user="$resolve.user"></home>',
resolve: {
user: function($http) { return $http.get('...'); }
}
});
});
```
## Intercomponent Communication
Directives can require the controllers of other directives to enable communication
between each other. This can be achieved in a component by providing an
object mapping for the `require` property. The object keys specify the property names under which
the required controllers (object values) will be bound to the requiring component's controller.
<div class="alert alert-warning">
Note that the required controllers will not be available during the instantiation of the controller,
but they are guaranteed to be available just before the `$onInit` method is executed!
</div>
Here is a tab pane example built from components:
<example module="docsTabsExample">
<file name="script.js">
angular.module('docsTabsExample', [])
.component('myTabs', {
transclude: true,
controller: function() {
var panes = this.panes = [];
this.select = function(pane) {
angular.forEach(panes, function(pane) {
pane.selected = false;
});
pane.selected = true;
};
this.addPane = function(pane) {
if (panes.length === 0) {
this.select(pane);
}
panes.push(pane);
};
},
templateUrl: 'my-tabs.html'
})
.component('myPane', {
transclude: true,
require: {
tabsCtrl: '^myTabs'
},
bindings: {
title: '@'
},
controller: function() {
this.$onInit = function() {
this.tabsCtrl.addPane(this);
console.log(this);
};
},
templateUrl: 'my-pane.html'
});
</file>
<file name="index.html">
<my-tabs>
<my-pane title="Hello">
<h4>Hello</h4>
<p>Lorem ipsum dolor sit amet</p>
</my-pane>
<my-pane title="World">
<h4>World</h4>
<em>Mauris elementum elementum enim at suscipit.</em>
<p><a href ng-click="i = i + 1">counter: {{i || 0}}</a></p>
</my-pane>
</my-tabs>
</file>
<file name="my-tabs.html">
<div class="tabbable">
<ul class="nav nav-tabs">
<li ng-repeat="pane in $ctrl.panes" ng-class="{active:pane.selected}">
<a href="" ng-click="$ctrl.select(pane)">{{pane.title}}</a>
</li>
</ul>
<div class="tab-content" ng-transclude></div>
</div>
</file>
<file name="my-pane.html">
<div class="tab-pane" ng-show="$ctrl.selected" ng-transclude></div>
</file>
</example>
# Unit-testing Component Controllers
The easiest way to unit-test a component controller is by using the {@link ngMock.$componentController $componentController}
that is included in {@link ngMock}. The advantage of this method is that you do not have
to create any DOM elements. The following example shows how to do this for the `heroDetail` component
from above.
The examples use the [Jasmine](http://jasmine.github.io/) testing framework.
**Controller Test:**
```js
describe('component: heroDetail', function() {
var component, scope, hero, $componentController;
beforeEach(module('simpleComponent'));
beforeEach(inject(function($rootScope, _$componentController_) {
scope = $rootScope.$new();
$componentController = _$componentController_;
hero = {name: 'Wolverine'};
}));
it('should set the default values of the hero', function() {
// It's necessary to always pass the scope in the locals, so that the controller instance can be bound to it
component = $componentController('heroDetail', {$scope: scope});
expect(component.hero).toEqual({
name: undefined,
location: 'unknown'
});
});
it('should assign the name bindings to the hero object', function() {
// Here we are passing actual bindings to the component
component = $componentController('heroDetail',
{$scope: scope},
{hero: hero}
);
expect(component.hero.name).toBe('Wolverine');
});
it('should call the onDelete binding when a hero is deleted', function() {
component = $componentController('heroDetail',
{$scope: scope},
{hero: hero, onDelete: jasmine.createSpy('deleteSpy')}
);
component.onDelete({hero: component.hero});
expect(spy('deleteSpy')).toHaveBeenCalledWith(component.hero);
});
});
```
+2 -2
View File
@@ -334,9 +334,9 @@ 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.jsonp(url).then(function(response) {
return $http.jsonp(url).success(function(data) {
var newUsdToForeignRates = {};
angular.forEach(response.data.query.results.rate, function(rate) {
angular.forEach(data.query.results.rate, function(rate) {
var currency = rate.id.substring(3,6);
newUsdToForeignRates[currency] = window.parseFloat(rate.Rate);
});
+486
View File
@@ -0,0 +1,486 @@
@ngdoc overview
@name Decorators
@sortOrder 345
@description
# Decorators in AngularJS
<div class="alert alert-warning">
**NOTE:** This guide is targeted towards developers who are already familiar with AngularJS basics.
If you're just getting started, we recommend the {@link tutorial/ tutorial} first.
</div>
## What are decorators?
Decorators are a design pattern that is used to separate modification or *decoration* of a class without modifying the
original source code. In Angular, decorators are functions that allow a service, directive or filter to be modified
prior to its usage.
## How to use decorators
There are two ways to register decorators
- `$provide.decorator`, and
- `module.decorator`
Each provide access to a `$delegate`, which is the instantiated service/directive/filter, prior to being passed to the
service that required it.
### $provide.decorator
The {@link api/auto/service/$provide#decorator decorator function} allows access to a $delegate of the service once it
has been instantiated. For example:
```js
angular.module('myApp', [])
.config([ '$provide', function($provide) {
$provide.decorator('$log', [
'$delegate',
function $logDecorator($delegate) {
var originalWarn = $delegate.warn;
$delegate.warn = function decoratedWarn(msg) {
msg = 'Decorated Warn: ' + msg;
originalWarn.apply($delegate, arguments);
};
return $delegate;
}
]);
}]);
```
After the `$log` service has been instantiated the decorator is fired. The decorator function has a `$delegate` object
injected to provide access to the service that matches the selector in the decorator. This `$delegate` will be the
service you are decorating. The return value of the function *provided to the decorator* will take place of the service,
directive, or filter being decorated.
<hr>
The `$delegate` may be either modified or completely replaced. Given a service `myService` with a method `someFn`, the
following could all be viable solutions:
#### Completely Replace the $delegate
```js
angular.module('myApp', [])
.config([ '$provide', function($provide) {
$provide.decorator('myService', [
'$delegate',
function myServiceDecorator($delegate) {
var myDecoratedService = {
// new service object to replace myService
};
return myDecoratedService;
}
]);
}]);
```
#### Patch the $delegate
```js
angular.module('myApp', [])
.config([ '$provide', function($provide) {
$provide.decorator('myService', [
'$delegate',
function myServiceDecorator($delegate) {
var someFn = $delegate.someFn;
function aNewFn() {
// new service function
someFn.apply($delegate, arguments);
}
$delegate.someFn = aNewFn;
return $delegate;
}
]);
}]);
```
#### Augment the $delegate
```js
angular.module('myApp', [])
.config([ '$provide', function($provide) {
$provide.decorator('myService', [
'$delegate',
function myServiceDecorator($delegate) {
function helperFn() {
// an additional fn to add to the service
}
$delegate.aHelpfulAddition = helperFn;
return $delegate;
}
]);
}]);
```
<div class="alert alert-info">
Note that whatever is returned by the decorator function will replace that which is being decorated. For example, a
missing return statement will wipe out the entire object being decorated.
</div>
<hr>
Decorators have different rules for different services. This is because services are registered in different ways.
Services are selected by name, however filters and directives are selected by appending `"Filter"` or `"Directive"` to
the end of the name. The `$delegate` provided is dictated by the type of service.
| Service Type | Selector | $delegate |
|--------------|-------------------------------|-----------------------------------------------------------------------|
| Service | `serviceName` | The `object` or `function` returned by the service |
| Directive | `directiveName + 'Directive'` | An `Array.<DirectiveObject>`<sub>{@link guide/decorators#drtvArray 1}</sub> |
| Filter | `filterName + 'Filter'` | The `function` returned by the filter |
<small id="drtvArray">1. Multiple directives may be registered to the same selector/name</small>
<div class="alert alert-warning">
**NOTE:** Developers should take care in how and why they are modifying the `$delegate` for the service. Not only
should expectations for the consumer be kept, but some functionality (such as directive registration) does not take
place after decoration, but during creation/registration of the original service. This means, for example, that
an action such as pushing a directive object to a directive `$delegate` will likely result in unexpected behavior.
Furthermore, great care should be taken when decorating core services, directives, or filters as this may unexpectedly
or adversely affect the functionality of the framework.
</div>
### 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. The
main caveat here is that you will need to take note the order in which you create your decorators.
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
// will cause an error since 'someService' hasn't been registered
angular.module('myApp').decorator('someService', ...);
angular.module('myApp').factory('someService', ...);
```
## Example Applications
The following sections provide examples each of a service decorator, a directive decorator, and a filter decorator.
### Service Decorator Example
This example shows how we can replace the $log service with our own to display log messages.
<example module="myServiceDecorator" name="service-decorator">
<file name="script.js">
angular.module('myServiceDecorator', []).
controller('Ctrl', [
'$scope',
'$log',
'$timeout',
function($scope, $log, $timeout) {
var types = ['error', 'warn', 'log', 'info' ,'debug'], i;
for (i = 0; i < types.length; i++) {
$log[types[i]](types[i] + ': message ' + (i + 1));
}
$timeout(function() {
$log.info('info: message logged in timeout');
});
}
]).
directive('myLog', [
'$log',
function($log) {
return {
restrict: 'E',
template: '<ul id="myLog"><li ng-repeat="l in myLog" class="{{l.type}}">{{l.message}}</li></ul>',
scope: {},
compile: function() {
return function(scope) {
scope.myLog = $log.stack;
};
}
};
}
]).
config([
'$provide',
function($provide) {
$provide.decorator('$log', [
'$delegate',
function logDecorator($delegate) {
var myLog = {
warn: function(msg) {
log(msg, 'warn');
},
error: function(msg) {
log(msg, 'error');
},
info: function(msg) {
log(msg, 'info');
},
debug: function(msg) {
log(msg, 'debug');
},
log: function(msg) {
log(msg, 'log');
},
stack: []
};
function log(msg, type) {
myLog.stack.push({ type: type, message: msg.toString() });
if (console && console[type]) console[type](msg);
}
return myLog;
}
]);
}
]);
</file>
<file name="index.html">
<div ng-controller="Ctrl">
<h1>Logs</h1>
<my-log></my-log>
</div>
</file>
<file name="style.css">
li.warn { color: yellow; }
li.error { color: red; }
li.info { color: blue }
li.log { color: black }
li.debug { color: green }
</file>
<file name="protractor.js" type="protractor">
it('should display log messages in dom', function() {
element.all(by.repeater('l in myLog')).count().then(function(count) {
expect(count).toEqual(6);
});
});
</file>
</example>
### Directive Decorator Example
Failed interpolated expressions in `ng-href` attributes can easily go unnoticed. We can decorate `ngHref` to warn us of
those conditions.
<example module="urlDecorator" name="directive-decorator">
<file name="script.js">
angular.module('urlDecorator', []).
controller('Ctrl', ['$scope', function ($scope) {
$scope.id = 3;
$scope.warnCount = 0; // for testing
}]).
config(['$provide', function($provide) {
// matchExpressions looks for interpolation markup in the directive attribute, extracts the expressions
// from that markup (if they exist) and returns an array of those expressions
function matchExpressions(str) {
var exps = str.match(/{{([^}]+)}}/g);
// if there isn't any, get out of here
if (exps === null) return;
exps = exps.map(function(exp) {
var prop = exp.match(/[^{}]+/);
return prop === null ? null : prop[0];
});
return exps;
}
// remember: directives must be selected by appending 'Directive' to the directive selector
$provide.decorator('ngHrefDirective', [
'$delegate',
'$log',
'$parse',
function($delegate, $log, $parse) {
// store the original link fn
var originalLinkFn = $delegate[0].link;
// replace the compile fn
$delegate[0].compile = function(tElem, tAttr) {
// store the original exp in the directive attribute for our warning message
var originalExp = tAttr.ngHref;
// get the interpolated expressions
var exps = matchExpressions(originalExp);
// create and store the getters using $parse
var getters = exps.map(function(el) {
if (el) return $parse(el);
});
return function newLinkFn(scope, elem, attr) {
// fire the originalLinkFn
originalLinkFn.apply($delegate[0], arguments);
// observe the directive attr and check the expressions
attr.$observe('ngHref', function(val) {
// if we have getters and getters is an array...
if (getters && angular.isArray(getters)) {
// loop through the getters and process them
angular.forEach(getters, function(g, idx) {
// if val is truthy, then the warning won't log
var val = angular.isFunction(g) ? g(scope) : true;
if (!val) {
$log.warn('NgHref Warning: "' + exps[idx] + '" in the expression "' + originalExp +
'" is falsy!');
scope.warnCount++; // for testing
}
});
}
});
};
};
// get rid of the old link function since we return a link function in compile
delete $delegate[0].link;
// return the $delegate
return $delegate;
}
]);
}]);
</file>
<file name="index.html">
<div ng-controller="Ctrl">
<a ng-href="/products/{{ id }}/view" id="id3">View Product {{ id }}</a>
- <strong>id == 3</strong>, so no warning<br>
<a ng-href="/products/{{ id + 5 }}/view" id="id8">View Product {{ id + 5 }}</a>
- <strong>id + 5 == 8</strong>, so no warning<br>
<a ng-href="/products/{{ someOtherId }}/view" id="someOtherId">View Product {{ someOtherId }}</a>
- <strong style="background-color: #ffff00;">someOtherId == undefined</strong>, so warn<br>
<a ng-href="/products/{{ someOtherId + 5 }}/view" id="someOtherId5">View Product {{ someOtherId + 5 }}</a>
- <strong>someOtherId + 5 == 5</strong>, so no warning<br>
<div>Warn Count: {{ warnCount }}</div>
</div>
</file>
<file name="protractor.js" type="protractor">
it('should warn when an expression in the interpolated value is falsy', function() {
var id3 = element(by.id('id3'));
var id8 = element(by.id('id8'));
var someOther = element(by.id('someOtherId'));
var someOther5 = element(by.id('someOtherId5'));
expect(id3.getText()).toEqual('View Product 3');
expect(id3.getAttribute('href')).toContain('/products/3/view');
expect(id8.getText()).toEqual('View Product 8');
expect(id8.getAttribute('href')).toContain('/products/8/view');
expect(someOther.getText()).toEqual('View Product');
expect(someOther.getAttribute('href')).toContain('/products//view');
expect(someOther5.getText()).toEqual('View Product 5');
expect(someOther5.getAttribute('href')).toContain('/products/5/view');
expect(element(by.binding('warnCount')).getText()).toEqual('Warn Count: 1');
});
</file>
</example>
### Filter Decorator Example
Let's say we have created an app that uses the default format for many of our `Date` filters. Suddenly requirements have
changed (that never happens) and we need all of our default dates to be `'shortDate'` instead of `'mediumDate'`.
<example module="filterDecorator" name="filter-decorator">
<file name="script.js">
angular.module('filterDecorator', []).
controller('Ctrl', ['$scope', function ($scope) {
$scope.genesis = new Date(2010, 0, 5);
$scope.ngConf = new Date(2016, 4, 4);
}]).
config(['$provide', function($provide) {
$provide.decorator('dateFilter', [
'$delegate',
function dateDecorator($delegate) {
// store the original filter
var originalFilter = $delegate;
// return our filter
return shortDateDefault;
// shortDateDefault sets the format to shortDate if it is falsy
function shortDateDefault(date, format, timezone) {
if (!format) format = 'shortDate';
// return the result of the original filter
return originalFilter(date, format, timezone);
}
}
]);
}]);
</file>
<file name="index.html">
<div ng-controller="Ctrl">
<div id="genesis">Initial Commit default to short date: {{ genesis | date }}</div>
<div>ng-conf 2016 default short date: {{ ngConf | date }}</div>
<div id="ngConf">ng-conf 2016 with full date format: {{ ngConf | date:'fullDate' }}</div>
</div>
</file>
<file name="protractor.js" type="protractor">
it('should default date filter to short date format', function() {
expect(element(by.id('genesis')).getText())
.toMatch(/Initial Commit default to short date: \d{1,2}\/\d{1,2}\/\d{2}/);
});
it('should still allow dates to be formatted', function() {
expect(element(by.id('ngConf')).getText())
.toMatch(/ng-conf 2016 with full date format\: [A-Za-z]+, [A-Za-z]+ \d{1,2}, \d{4}/);
});
</file>
</example>
-3
View File
@@ -116,9 +116,6 @@ This restriction is intentional. It prevents accidental access to the global sta
Instead use services like `$window` and `$location` in functions called from expressions. Such services
provide mockable access to globals.
It is possible to access the context object using the identifier `this` and the locals object using the
identifier `$locals`.
<example module="expressionExample">
<file name="index.html">
<div class="example2" ng-controller="ExampleController">
+1 -4
View File
@@ -28,7 +28,4 @@ browsers, but it is up to you to test and decide whether it works for your parti
To ensure your Angular application works on IE please consider:
1. Use `ng-style` tags instead of `style="{{ someCss }}"`. The latter works in Chrome and Firefox
but does not work in Internet Explorer <= 11 (the most recent version at time of writing).
2. For the `type` attribute of buttons, use `ng-attr-type` tags instead of
`type="{{ someExpression }}"`. If using the latter, Internet Explorer overwrites the expression
with `type="submit"` before Angular has a chance to interpolate it.
but does not work in Internet Explorer <= 11 (the most recent version at time of writing).
+2 -2
View File
@@ -101,7 +101,7 @@ This is a short list of libraries with specific support and documentation for wo
## Learning Resources
###Books
### Books
* [AngularJS: Up and Running](http://www.amazon.com/AngularJS-Running-Enhanced-Productivity-Structured/dp/1491901942) by Brad Green and Shyam Seshadri
* [Mastering Web App Development](http://www.amazon.com/Mastering-Web-Application-Development-AngularJS/dp/1782161821) by Pawel Kozlowski and Pete Bacon Darwin
* [AngularJS Directives](http://www.amazon.com/AngularJS-Directives-Alex-Vanston/dp/1783280336) by Alex Vanston
@@ -113,7 +113,7 @@ This is a short list of libraries with specific support and documentation for wo
* [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:
### Videos:
* [egghead.io](http://egghead.io/)
* [Angular on YouTube](http://youtube.com/angularjs)
* [Firebase Foundations for AngularJS](http://blog.watchandcode.com/firebase-foundations/)
+60 -289
View File
@@ -3,246 +3,17 @@
@sortOrder 550
@description
# Migrating an App to a newer version
Minor version releases in AngularJS introduce several breaking changes that may require changes to your
application's source code; for instance from 1.0 to 1.2 and from 1.2 to 1.3.
Although we try to avoid breaking changes, there are some cases where it is unavoidable:
Although we try to avoid breaking changes, there are some cases where it is unavoidable.
* AngularJS has undergone thorough security reviews to make applications safer by default,
which drives many of these changes.
* Several new features, especially animations, would not be possible without a few changes.
* Finally, some outstanding bugs were best fixed by changing an existing API.
## Contents
<ul class="nav nav-list">
<li>{@link guide/migration#migrating-from-1-4-to-1-5 Migrating from 1.4 to 1.5}</li>
<li>{@link guide/migration#migrating-from-1-3-to-1-4 Migrating from 1.3 to 1.4}</li>
<li>{@link guide/migration#migrating-from-1-2-to-1-3 Migrating from 1.2 to 1.3}</li>
<li>{@link guide/migration#migrating-from-1-0-to-1-2 Migrating from 1.0 to 1.2}</li>
</ul>
## Migrating from 1.4 to 1.5
Angular 1.5 takes a big step towards preparing developers for a smoother transition to Angular 2 in
the future. Architecturing your applications using components, multi-slot transclusion, one-way
bindings in isolate scopes, using lifecycle hooks in directive controllers and relying on native ES6
features (such as classes and arrow functions) are now all possible with Angular 1.5.
This release includes numerous bug and security fixes, as well as performance improvements to core
services, directives, filters and helper functions. Existing applications can start enjoying the
benefits of such changes in `$compile`, `$parse`, `$animate`, `$animateCss`, `$sanitize`, `ngOptions`,
`currencyFilter`, `numberFilter`, `copy()` (to name but a few) without any change in code.
New features have been added to more than a dozen services, directives and filters across 8 modules.
Among them, a few stand out:
* `angular.component()`: Introducing "components", a special sort of directive that are easy to
configure and promote best practices (plus can bring Angular 1 applications closer to Angular 2's
style of architecture).
* Multi-slot transclusion: Enabling the design of more powerful and complex UI elements with a much
simpler configuration and reduced boilerplate.
* `$onInit` lifecycle hook: Introducing a new lifecycle hook for directive controllers, called after
all required controllers have been constructed. This enables access to required controllers from
a directive's controller, without having to rely on the linking function.
* `ngAnimateSwap`: A new directive in `ngAnimate`, making it super easy to create rotating
banner-like components.
* Testing helpers: New helper functions in `ngMock`, simplifying testing for animations, component
controllers and routing.
Also, notable is the improved support for ES6 features, such as classes and arrow functions. These
features are now more reliably detected and correctly handled within the core.
All this goodness doesn't come without a price, though. Below is a list of breaking changes (grouped
by module) that need to be taken into account while migrating from 1.4. Fortunately, the majority of
them should have a pretty low impact on most applications.
### Core
We tried to keep the breaking changes inside the core components to a bare minimum. Still, a few of
them were unavoidable.
#### Services (`$parse`)
Due to [0ea53503](https://github.com/angular/angular.js/commit/0ea535035a3a1a992948490c3533bffb83235052),
a new special property, `$locals`, will be available for accessing the locals from an expression.
This is a breaking change, only if a `$locals` property does already exist (and needs to be
referenced) either on the `scope` or on the `locals` object. Your expressions should be changed to
access such existing properties as `this.$locals` and `$locals.$locals` respectively.
#### Directives (`ngOptions`)
A fair amount of work has been put into the `ngOptions` directive, fixing bugs and corner-cases and
neutralizing browser quirks. A couple of breaking changes were made in the process:
Due to [b71d7c3f](https://github.com/angular/angular.js/commit/b71d7c3f3c04e65b02d88b33c22dd90ae3cdfc27),
falsy values (`''`, `0`, `false` and `null`) are properly recognized as option group identifiers for
options passed to `ngOptions`. Previously, all of these values were ignored and the option was not
assigned to any group. `undefined` is still interpreted as "no group".
If you have options with falsy group indentifiers that should still not be assigned to any group,
then you must filter the values before passing them to `ngOptions`, converting falsy values to
`undefined`.
Due to [ded25187](https://github.com/angular/angular.js/commit/ded2518756d4409fdfda0d4af243f2125bea01b5),
`ngOptions` now explicitly requires `ngModel` on the same element, thus an error will be thrown if
`ngModel` is not found. Previously, `ngOptions` would silently fail, which could lead to
hard-to-debug errors.
This is not expected to have any significant impact on applications, since `ngOptions` didn't work
without `ngModel` before either. The main difference is that now it will fail with a more
informative error message.
#### Filters (`orderBy`)
Due to [2a85a634](https://github.com/angular/angular.js/commit/2a85a634f86c84f15b411ce009a3515fca7ba580),
passing a non-array-like value (other than `undefined` or `null`) through the `orderBy` filter will
throw an error. Previously, the input was returned unchanged, which could lead to hard-to-spot bugs
and was not consistent with other filters (e.g. `filter`).
Objects considered array-like include: arrays, array subclasses, strings, NodeLists,
jqLite/jQuery collections
### ngAria
Due to [d06431e](https://github.com/angular/angular.js/commit/d06431e5309bb0125588877451dc79b935808134),
the `ngAria`-enhanced directives (e.g. `ngModel`, `ngDisabled` etc) will not apply ARIA attributes
to native inputs, unless necessary. Previously, ARIA attributes were always applied to native
inputs, despite this being unnecessary in most cases.
In the context of `ngAria`, elements considered "native inputs" include:
`<a>`, `<button>`, `<details>`, `<input>`, `<select>`, `<summary>`, `<textarea>`
This change will not affect the accessibility of your applications (since native inputs are
accessible by default), but if you relied on ARIA attributes being present on native inputs (for
whatever reason), you'll have to add and update them manually.
Additionally, the `aria-multiline` attribute, which was previously added to elements with a `type`
or `role` of `textbox`, will not be added anymore, since there is no way `ngAria` can tell if the
textbox element is multiline or not.
If you relied on `aria-multiline="true"` being automatically added by `ngAria`, you need to apply it
yourself. E.g. change your code from `<div role="textbox" ng-model="..." ...>` to
`<div role="textbox" ng-model="..." ... aria-multiline="true">`.
### ngMessages (`ngMessage`)
Due to [4971ef12](https://github.com/angular/angular.js/commit/4971ef12d4c2c268cb8d26f90385dc96eba19db8),
the `ngMessage` directive is now compiled with a priority of 1, which means directives on the same
element as `ngMessage` with a priority lower than 1 will be applied when `ngMessage` calls its
`$transclude` function. Previously, they were applied during the initial compile phase and were
passed the comment element created by the transclusion of `ngMessage`.
If you have custom directives that relied on the previous behavior, you need to give them a priority
of 1 or greater.
### ngResource (`$resource`)
The `$resource` service underwent a minor internal refactoring to finally solve a long-standing bug
preventing requests from being cancelled using promises. Due to the nature of `$resource`'s
configuration, it was not possible to follow the `$http` convention. A new `$cancelRequest()` method
was introduced instead.
Due to [98528be3](https://github.com/angular/angular.js/commit/98528be311b48269ba0e15ba4e3e2ad9b89693a9),
using a promise as `timeout` in `$resource` is no longer supported and will log a warning. This is
hardly expected to affect the behavior of your application, since a promise as `timeout` didn't work
before either, but it will now warn you explicitly when trying to pass one.
If you need to be able to cancel pending requests, you can now use the new `$cancelRequest()` that
will be available on `$resource` instances.
### ngRoute (`ngView`)
Due to [983b0598](https://github.com/angular/angular.js/commit/983b0598121a8c5a3a51a30120e114d7e3085d4d),
a new property will be available on the scope of the route, allowing easy access to the route's
resolved values from the view's template. The default name for this property is `$resolve`. This is
a breaking change, only if a `$resolve` property is already available on the scope, in which case
the existing property will be hidden or overwritten.
To fix this, you should choose a custom name for this property, that does not collide with other
properties on the scope, by specifying the `resolveAs` property on the route.
### ngSanitize (`$sanitize`, `linky`)
The HTML sanitizer has been re-implemented using inert documents, increasing security, fixing some
corner-cases that were difficult to handle and reducing its size by about 20% (in terms of loc). In
order to make it more secure by default, a couple of breaking changes have been introduced:
Due to [181fc567](https://github.com/angular/angular.js/commit/181fc567d873df065f1e84af7225deb70a8d2eb9),
SVG support in `$sanitize` is now an opt-in feature (i.e. disabled by default), as it could make
an application vulnerable to click-hijacking attacks. If your application relies on it, you can
still turn it on with `$sanitizeProvider.enableSvg(true)`, but you extra precautions need to be
taken in order to keep your application secure. Read the documentation for more information about
the dangers and ways to mitigate them.
Due to [7a668cdd](https://github.com/angular/angular.js/commit/7a668cdd7d08a7016883eb3c671cbcd586223ae8),
the `$sanitize` service will now remove instances of the `<use>` tag from the content passed to it.
This element is used to import external SVG resources, which is a security risk as the `$sanitize`
service does not have access to the resource in order to sanitize it.
Similarly, due to [234053fc](https://github.com/angular/angular.js/commit/234053fc9ad90e0d05be7e8359c6af66be94c094),
the `$sanitize` service will now also remove instances of the `usemap` attribute from any elements
passed to it. This attribute is used to reference another element by `name` or `id`. Since the
`name` and `id` attributes are already blacklisted, a sanitized `usemap` attribute could only
reference unsanitized content, which is a security risk.
Due to [98c2db7f](https://github.com/angular/angular.js/commit/98c2db7f9c2d078a408576e722407d518c7ee10a),
passing a non-string value (other than `undefined` or `null`) through the `linky` filter will throw
an error. This is not expected to have any significant impact on applications, since the input was
always assumed to be of type 'string', so passing non-string values never worked correctly anyway.
The main difference is that now it will fail faster and with a more informative error message.
## ngTouch (`ngClick`)
Due to [0dfc1dfe](https://github.com/angular/angular.js/commit/0dfc1dfebf26af7f951f301c4e3848ac46f05d7f),
the `ngClick` override directive from the `ngTouch` module is **deprecated and disabled by default**.
This means that on touch-based devices, users might now experience a 300ms delay before a click
event is fired.
If you rely on this directive, you can still enable it using
`$touchProvider.ngClickOverrideEnabled()`:
```js
angular.module('myApp').config(function($touchProvider) {
$touchProvider.ngClickOverrideEnabled(true);
});
```
Going forward, we recommend using [FastClick](https://github.com/ftlabs/fastclick) or perhaps one of
the [Angular 3rd party touch-related modules](http://ngmodules.org/tags/touch) that provide similar
functionality.
Also note that modern browsers already remove the 300ms delay under some circumstances:
- **Chrome and Firefox for Android** remove the 300ms delay when the well-known
`<meta name="viewport" content="width=device-width">` is set.
- **Internet Explorer** removes the delay, when the `touch-action` css property is set to `none` or
`manipulation`.
- Since **iOS 8, Safari** removes the delay on so-called "slow taps".
For more info on the topic, you can take a look at this
[article by Telerik](http://developer.telerik.com/featured/300-ms-click-delay-ios-8/).
<div class="alert alert-warning">
**Note:** This change does **not** affect the `ngSwipe` directive.
</div>
## Migrating from 1.3 to 1.4
# Migrating from 1.3 to 1.4
Angular 1.4 fixes major animation issues and introduces a new API for `ngCookies`. Further, there
are changes to `ngMessages`, `$compile`, `ngRepeat`, `ngOptions `and some fixes to core filters:
@@ -266,7 +37,7 @@ relatively straightforward otherwise.
### Animation (`ngAnimate`)
## Animation (`ngAnimate`)
Animations in 1.4 have been refactored internally, but the API has stayed much the same. There are, however,
some breaking changes that need to be addressed when upgrading to 1.4.
@@ -365,9 +136,9 @@ class based animations (animations triggered via ngClass) in order to ensure tha
### Forms (`ngMessages`, `ngOptions`, `select`)
## Forms (`ngMessages`, `ngOptions`, `select`)
#### ngMessages
### ngMessages
The ngMessages module has also been subject to an internal refactor to allow it to be more flexible
and compatible with dynamic message data. The `ngMessage` directive now supports a new attribute
called `ng-message-exp` which will evaluate an expression and will keep track of that expression
@@ -418,7 +189,7 @@ ctrl.getMessages = function($index) {
}
```
#### ngOptions
### ngOptions
The `ngOptions` directive has also been refactored and as a result some long-standing bugs
have been fixed. The breaking changes are comparatively minor and should not affect most applications.
@@ -442,7 +213,7 @@ setting the ngOptions attribute expression after the element is compiled, will n
This worked previously because the ngOptions logic was part of the select directive, while
it is now implemented in the ngOptions directive itself.
#### select
### select
Due to [7fda214c](https://github.com/angular/angular.js/commit/7fda214c4f65a6a06b25cf5d5aff013a364e9cef),
the `select` directive will now use strict comparison of the `ngModel` scope value against `option`
@@ -473,7 +244,6 @@ ngModelCtrl.$formatters.push(function(value) {
});
```
### form
Due to [94533e57](https://github.com/angular/angular.js/commit/94533e570673e6b2eb92073955541fa289aabe02),
@@ -514,9 +284,9 @@ angular.module('myApp').directive('form', function() {
});
```
### Templating (`ngRepeat`, `$compile`)
## Templating (`ngRepeat`, `$compile`)
#### ngRepeat
### ngRepeat
Due to [c260e738](https://github.com/angular/angular.js/commit/c260e7386391877625eda086480de73e8a0ba921),
previously, the order of items when using ngRepeat to iterate over object properties was guaranteed to be consistent
@@ -535,7 +305,7 @@ https://github.com/petebacondarwin/angular-toArrayFilter
or some other mechanism, and then sort them manually in the order you need.
#### $compile
### $compile
Due to [6a38dbfd](https://github.com/angular/angular.js/commit/6a38dbfd3c34c8f9efff503d17eb3cbeb666d422),
previously, '&' expressions would always set up a function in the isolate scope. Now, if the binding
@@ -546,7 +316,7 @@ returning an object from a controller constructor function will now override the
controllerAs method will no longer get the this reference, but the returned object.
### Cookies (`ngCookies`)
## Cookies (`ngCookies`)
Due to [38fbe3ee](https://github.com/angular/angular.js/commit/38fbe3ee8370fc449b82d80df07b5c2ed2cd5fbe),
`$cookies` will no longer expose properties that represent the current browser cookie
@@ -585,7 +355,7 @@ delegates calls.
### Server Requests (`$http`)
## Server Requests (`$http`)
Due to [5da1256](https://github.com/angular/angular.js/commit/5da1256fc2812d5b28fb0af0de81256054856369),
`transformRequest` functions can no longer modify request headers.
@@ -618,9 +388,9 @@ $http.get(url, {
### Filters (`filter`, `limitTo`)
## Filters (`filter`, `limitTo`)
#### `filter` filter
### `filter` filter
Due to [cea8e751](https://github.com/angular/angular.js/commit/cea8e75144e6910b806b63a6ec2a6d118316fddd),
the `filter` filter will throw an error when used with a non-array. Beforehand it would silently
return an empty array.
@@ -628,7 +398,7 @@ return an empty array.
If necessary, this can be worked around by converting an object to an array,
using a filter such as https://github.com/petebacondarwin/angular-toArrayFilter.
#### `limitTo` filter
### `limitTo` filter
Due to [a3c3bf33](https://github.com/angular/angular.js/commit/a3c3bf3332e5685dc319c46faef882cb6ac246e1),
the limitTo filter has changed behavior when the provided limit value is invalid.
Now, instead of returning empty object/array, it returns unchanged input.
@@ -637,9 +407,9 @@ Now, instead of returning empty object/array, it returns unchanged input.
## Migrating from 1.2 to 1.3
# Migrating from 1.2 to 1.3
### Controllers
## Controllers
Due to [3f2232b5](https://github.com/angular/angular.js/commit/3f2232b5a181512fac23775b1df4a6ebda67d018),
`$controller` will no longer look for controllers on `window`.
@@ -677,7 +447,7 @@ angular.module('myModule').config(['$controllerProvider', function($controllerPr
}]);
```
### Angular Expression Parsing (`$parse` + `$interpolate`)
## Angular Expression Parsing (`$parse` + `$interpolate`)
- due to [77ada4c8](https://github.com/angular/angular.js/commit/77ada4c82d6b8fc6d977c26f3cdb48c2f5fbe5a5),
@@ -735,7 +505,7 @@ expression parser; there are six of them: false, null, undefined, NaN, 0 and "".
### Miscellaneous Angular helpers
## Miscellaneous Angular helpers
- **Angular.copy:** due to [b59b04f9](https://github.com/angular/angular.js/commit/b59b04f98a0b59eead53f6a53391ce1bbcbe9b57),
@@ -766,14 +536,15 @@ This change also makes our forEach behave more like Array#forEach.
- **angular.toJson:** due to [c054288c](https://github.com/angular/angular.js/commit/c054288c9722875e3595e6e6162193e0fb67a251),
`toJson()` will no longer strip properties starting with a single `$`. If you relied on
`toJson()`'s stripping these types of properties before, you will have to do it manually now.
It will still strip properties starting with `$$` though.
If you expected `toJson` to strip these types of properties before, you will have to
manually do this yourself now.
### jqLite / JQuery
## jqLite / JQuery
- **jqLite:** due to [a196c8bc](https://github.com/angular/angular.js/commit/a196c8bca82a28c08896d31f1863cf4ecd11401c),
previously it was possible to set jqLite data on Text/Comment
@@ -789,7 +560,7 @@ jQuery. We don't expect that app code actually depends on this accidental featur
### Angular HTML Compiler (`$compile`)
## Angular HTML Compiler (`$compile`)
- due to [2ee29c5d](https://github.com/angular/angular.js/commit/2ee29c5da81ffacdc1cabb438f5d125d5e116cb9),
@@ -886,7 +657,7 @@ link: function(scope, element, attr) {
### Forms, Inputs and ngModel
## Forms, Inputs and ngModel
- due to [1be9bb9d](https://github.com/angular/angular.js/commit/1be9bb9d3527e0758350c4f7417a4228d8571440),
@@ -966,7 +737,7 @@ $scope.resetWithCancel = function (e) {
See [c90cefe1614](https://github.com/angular/angular.js/commit/c90cefe16142d973a123e945fc9058e8a874c357)
### Scopes and Digests (`$scope`)
## Scopes and Digests (`$scope`)
- due to [8c6a8171](https://github.com/angular/angular.js/commit/8c6a8171f9bdaa5cdabc0cc3f7d3ce10af7b434d),
Scope#$id is now of type number rather than string. Since the
@@ -986,7 +757,7 @@ anyone.
### Server Requests (`$http`, `$resource`)
## Server Requests (`$http`, `$resource`)
- **$http:** due to [ad4336f9](https://github.com/angular/angular.js/commit/ad4336f9359a073e272930f8f9bcd36587a8648f),
@@ -1053,7 +824,7 @@ More details on the new interceptors API (which has been around as of v1.1.4) ca
### Modules and Injector (`$inject`)
## Modules and Injector (`$inject`)
- due to [c0b4e2db](https://github.com/angular/angular.js/commit/c0b4e2db9cbc8bc3164cedc4646145d3ab72536e),
@@ -1095,7 +866,7 @@ app. This is no longer possible within a single module.
### Animation (`ngAnimate`)
## Animation (`ngAnimate`)
- due to [1cb8584e](https://github.com/angular/angular.js/commit/1cb8584e8490ecdb1b410a8846c4478c6c2c0e53),
@@ -1117,7 +888,7 @@ to:
Any class-based animation code that makes use of transitions
and uses the setup CSS classes (such as class-add and class-remove) must now
provide an empty transition value to ensure that its styling is applied right
provide a empty transition value to ensure that its styling is applied right
away. In other words if your animation code is expecting any styling to be
applied that is defined in the setup class then it will not be applied
"instantly" unless a `transition:0s none` value is present in the styling
@@ -1148,7 +919,7 @@ After:
Please view the documentation for ngAnimate for more info.
### Testing
## Testing
- due to [85880a64](https://github.com/angular/angular.js/commit/85880a64900fa22a61feb926bf52de0965332ca5), some deprecated features of
Protractor tests no longer work.
@@ -1187,7 +958,7 @@ or simply use:
var el = element(by.repeater('foo in foos').row(2))
### Internet Explorer 8
## Internet Explorer 8
- due to [eaa1d00b](https://github.com/angular/angular.js/commit/eaa1d00b24008f590b95ad099241b4003688cdda),
As communicated before, IE8 is no longer supported.
@@ -1197,7 +968,7 @@ or simply use:
## Migrating from 1.0 to 1.2
# Migrating from 1.0 to 1.2
<div class="alert alert-warning">
@@ -1240,7 +1011,7 @@ below should still apply, but you may want to consult the
</ul>
### ngRoute has been moved into its own module
## ngRoute has been moved into its own module
Just like `ngResource`, `ngRoute` is now its own module.
@@ -1271,7 +1042,7 @@ var myApp = angular.module('myApp', ['ngRoute', 'someOtherModule']);
See [5599b55b](https://github.com/angular/angular.js/commit/5599b55b04788c2e327d7551a4a699d75516dd21).
### Templates no longer automatically unwrap promises
## Templates no longer automatically unwrap promises
`$parse` and templates in general will no longer automatically unwrap promises.
@@ -1305,7 +1076,7 @@ See [5dc35b52](https://github.com/angular/angular.js/commit/5dc35b527b3c99f6544b
[b6a37d11](https://github.com/angular/angular.js/commit/b6a37d112b3e1478f4d14a5f82faabf700443748).
### Syntax for named wildcard parameters changed in `$route`
## Syntax for named wildcard parameters changed in `$route`
To migrate the code, follow the example below. Here, `*highlight` becomes `:highlight*`
@@ -1326,7 +1097,7 @@ $routeProvider.when('/Book1/:book/Chapter/:chapter/:highlight*/edit',
See [04cebcc1](https://github.com/angular/angular.js/commit/04cebcc133c8b433a3ac5f72ed19f3631778142b).
### You can only bind one expression to `*[src]`, `*[ng-src]` or `action`
## You can only bind one expression to `*[src]`, `*[ng-src]` or `action`
With the exception of `<a>` and `<img>` elements, you cannot bind more than one expression to the
`src` or `action` attribute of elements.
@@ -1401,7 +1172,7 @@ scope.getIframeSrc = function() {
See [38deedd6](https://github.com/angular/angular.js/commit/38deedd6e3d806eb8262bb43f26d47245f6c2739).
### Interpolations inside DOM event handlers are now disallowed
## Interpolations inside DOM event handlers are now disallowed
DOM event handlers execute arbitrary Javascript code. Using an interpolation for such handlers
means that the interpolated value is a JS string that is evaluated. Storing or generating such
@@ -1428,7 +1199,7 @@ HTML: <div ng-click="foo()">
See [39841f2e](https://github.com/angular/angular.js/commit/39841f2ec9b17b3b2920fd1eb548d444251f4f56).
### Directives cannot end with -start or -end
## Directives cannot end with -start or -end
This change was necessary to enable multi-element directives. The best fix is to rename existing
directives so that they don't end with these suffixes.
@@ -1436,7 +1207,7 @@ directives so that they don't end with these suffixes.
See [e46100f7](https://github.com/angular/angular.js/commit/e46100f7097d9a8f174bdb9e15d4c6098395c3f2).
### In $q, promise.always has been renamed promise.finally
## In $q, promise.always has been renamed promise.finally
The reason for this change is to align `$q` with the [Q promise
library](https://github.com/kriskowal/q), despite the fact that this makes it a bit more difficult
@@ -1468,7 +1239,7 @@ $http.get('/foo')['finally'](doSomething);
See [f078762d](https://github.com/angular/angular.js/commit/f078762d48d0d5d9796dcdf2cb0241198677582c).
### ngMobile is now ngTouch
## ngMobile is now ngTouch
Many touch-enabled devices are not mobile devices, so we decided to rename this module to better
reflect its concerns.
@@ -1479,7 +1250,7 @@ To migrate, replace all references to `ngMobile` with `ngTouch` and `angular-mob
See [94ec84e7](https://github.com/angular/angular.js/commit/94ec84e7b9c89358dc00e4039009af9e287bbd05).
### resource.$then has been removed
## resource.$then has been removed
Resource instances do not have a `$then` function anymore. Use the `$promise.then` instead.
@@ -1498,7 +1269,7 @@ Resource.query().$promise.then(callback);
See [05772e15](https://github.com/angular/angular.js/commit/05772e15fbecfdc63d4977e2e8839d8b95d6a92d).
### Resource methods return the promise
## Resource methods return the promise
Methods of a resource instance return the promise rather than the instance itself.
@@ -1518,7 +1289,7 @@ resource.chaining = true;
See [05772e15](https://github.com/angular/angular.js/commit/05772e15fbecfdc63d4977e2e8839d8b95d6a92d).
### Resource promises are resolved with the resource instance
## Resource promises are resolved with the resource instance
On success, the resource promise is resolved with the resource instance rather than HTTP response object.
@@ -1549,7 +1320,7 @@ var Resource = $resource('/url', {}, {
See [05772e15](https://github.com/angular/angular.js/commit/05772e15fbecfdc63d4977e2e8839d8b95d6a92d).
### $location.search supports multiple keys
## $location.search supports multiple keys
{@link ng.$location#search `$location.search`} now supports multiple keys with the
same value provided that the values are stored in an array.
@@ -1566,7 +1337,7 @@ passing it to `$location`.
See [80739409](https://github.com/angular/angular.js/commit/807394095b991357225a03d5fed81fea5c9a1abe).
### ngBindHtmlUnsafe has been removed and replaced by ngBindHtml
## ngBindHtmlUnsafe has been removed and replaced by ngBindHtml
`ngBindHtml` provides `ngBindHtmlUnsafe` like
behavior (evaluate an expression and innerHTML the result into the DOM) when bound to the result
@@ -1582,7 +1353,7 @@ trusted.
See [dae69473](https://github.com/angular/angular.js/commit/dae694739b9581bea5dbc53522ec00d87b26ae55).
### Form names that are expressions are evaluated
## Form names that are expressions are evaluated
If you have form names that will evaluate as an expression:
@@ -1614,7 +1385,7 @@ Supporting the previous behavior offers no benefit.
See [8ea802a1](https://github.com/angular/angular.js/commit/8ea802a1d23ad8ecacab892a3a451a308d9c39d7).
### hasOwnProperty disallowed as an input name
## hasOwnProperty disallowed as an input name
Inputs with name equal to `hasOwnProperty` are not allowed inside form or ngForm directives.
@@ -1625,7 +1396,7 @@ and bad practice. To migrate, change your input name.
See [7a586e5c](https://github.com/angular/angular.js/commit/7a586e5c19f3d1ecc3fefef084ce992072ee7f60).
### Directives: Order of postLink functions reversed
## Directives: Order of postLink functions reversed
The order of postLink fn is now mirror opposite of the order in which corresponding preLinking and compile functions execute.
@@ -1681,7 +1452,7 @@ attribute interpolation directive was adjusted.
See [31f190d4](https://github.com/angular/angular.js/commit/31f190d4d53921d32253ba80d9ebe57d6c1de82b).
### Directive priority
## Directive priority
the priority of ngRepeat, ngSwitchWhen, ngIf, ngInclude and ngView has changed. This could affect directives that explicitly specify their priority.
@@ -1699,7 +1470,7 @@ ngView | 1000 | 400
See [b7af76b4](https://github.com/angular/angular.js/commit/b7af76b4c5aa77648cc1bfd49935b48583419023).
### ngScenario
## ngScenario
browserTrigger now uses an eventData object instead of direct parameters for mouse events.
To migrate, place the `keys`,`x` and `y` parameters inside of an object and place that as the
@@ -1708,7 +1479,7 @@ third parameter for the browserTrigger function.
See [28f56a38](https://github.com/angular/angular.js/commit/28f56a383e9d1ff378e3568a3039e941c7ffb1d8).
### ngInclude and ngView replace its entire element on update
## ngInclude and ngView replace its entire element on update
Previously `ngInclude` and `ngView` only updated its element's content. Now these directives will
recreate the element every time a new content is included.
@@ -1720,7 +1491,7 @@ See [7d69d52a](https://github.com/angular/angular.js/commit/7d69d52acff8578e0f7d
[aa2133ad](https://github.com/angular/angular.js/commit/aa2133ad818d2e5c27cbd3933061797096356c8a).
### URLs are now sanitized against a whitelist
## URLs are now sanitized against a whitelist
A whitelist configured via `$compileProvider` can be used to configure what URLs are considered safe.
By default all common protocol prefixes are whitelisted including `data:` URIs with mime types `image/*`.
@@ -1730,7 +1501,7 @@ See [1adf29af](https://github.com/angular/angular.js/commit/1adf29af13890d612868
[3e39ac7e](https://github.com/angular/angular.js/commit/3e39ac7e1b10d4812a44dad2f959a93361cd823b).
### Isolate scope only exposed to directives with `scope` property
## Isolate scope only exposed to directives with `scope` property
If you declare a scope option on a directive, that directive will have an
[isolate scope](https://github.com/angular/angular.js/wiki/Understanding-Scopes). In Angular 1.0, if a
@@ -1803,7 +1574,7 @@ See [909cabd3](https://github.com/angular/angular.js/commit/909cabd36d779598763c
[#2500](https://github.com/angular/angular.js/issues/2500).
### Change to interpolation priority
## Change to interpolation priority
Previously, the interpolation priority was `-100` in 1.2.0-rc.2, and `100` before 1.2.0-rc.2.
Before this change the binding was setup in the post-linking phase.
@@ -1816,7 +1587,7 @@ See [79223eae](https://github.com/angular/angular.js/commit/79223eae502283889334
[#4528](https://github.com/angular/angular.js/issues/4528), and
[#4649](https://github.com/angular/angular.js/issues/4649)
### Underscore-prefixed/suffixed properties are non-bindable
## Underscore-prefixed/suffixed properties are non-bindable
<div class="alert alert-info">
<p>**Reverted**: This breaking change has been reverted in 1.2.1, and so can be ignored if you're using **version 1.2.1 or higher**</p>
@@ -1855,7 +1626,7 @@ are actually needed by the expressions.
See [3d6a89e8](https://github.com/angular/angular.js/commit/3d6a89e8888b14ae5cb5640464e12b7811853c7e).
### You cannot bind to select[multiple]
## You cannot bind to select[multiple]
Switching between `select[single]` and `select[multiple]` has always been odd due to browser quirks.
This feature never worked with two-way data-binding so it's not expected that anyone is using it.
@@ -1865,7 +1636,7 @@ If you are interested in properly adding this feature, please submit a pull requ
See [d87fa004](https://github.com/angular/angular.js/commit/d87fa0042375b025b98c40bff05e5f42c00af114).
### Uncommon region-specific local files were removed from i18n
## Uncommon region-specific local files were removed from i18n
AngularJS uses the Google Closure library's locale files. The following locales were removed from
Closure, so Angular is not able to continue to support them:
@@ -1881,7 +1652,7 @@ load and use your copy of the locale file provided that you maintain it yourself
See [6382e21f](https://github.com/angular/angular.js/commit/6382e21fb28541a2484ac1a241d41cf9fbbe9d2c).
### Services can now return functions
## Services can now return functions
Previously, the service constructor only returned objects regardless of whether a function was returned.
+1 -1
View File
@@ -257,7 +257,7 @@ the `$digest` phase. This delay is desirable, since it coalesces multiple model
2. **Watcher registration**
During template linking directives register {@link
During template linking, directives register {@link
ng.$rootScope.Scope#$watch watches} on the scope. These watches will be
used to propagate model values to the DOM.
+10 -75
View File
@@ -9,27 +9,6 @@ This document explains some of AngularJS's security features and best practices
keep in mind as you build your application.
## Reporting a security issue
Email us at [security@angularjs.org](mailto:security@angularjs.org) to report any potential
security issues in AngularJS.
Please keep in mind the points below about Angular's expression language.
## Use the latest AngularJS possible
Like any software library, it is critical to keep AngularJS up to date. Please track the
[CHANGELOG](https://github.com/angular/angular.js/blob/master/CHANGELOG.md) and make sure you are aware
of upcoming security patches and other updates.
Be ready to update rapidly when new security-centric patches are available.
Those that stray from Angular standards (such as modifying Angular's core) may have difficulty updating,
so keeping to AngularJS standards is not just a functionality issue, it's also critical in order to
facilitate rapid security updates.
## Expression Sandboxing
AngularJS's expressions are sandboxed not for security reasons, but instead to maintain a proper
@@ -46,8 +25,7 @@ But if an attacker can change arbitrary HTML templates, there's nothing stopping
<script>somethingEvil();</script>
```
**It's better to design your application in such a way that users cannot change client-side templates.**
It's better to design your application in such a way that users cannot change client-side templates.
For instance:
* Do not mix client and server templates
@@ -55,8 +33,7 @@ For instance:
* Do not run user input through `$scope.$eval`
* Consider using {@link ng.directive:ngCsp CSP} (but don't rely only on CSP)
### Mixing client-side and server-side templates
## Mixing client-side and server-side templates
In general, we recommend against this because it can create unintended XSS vectors.
@@ -64,62 +41,20 @@ However, it's ok to mix server-side templating in the bootstrap template (`index
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.**
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
## Reporting a security issue
Whenever your application makes requests to a server there are potential security issues that need
to be blocked. Both server and the client must cooperate in order to eliminate these threats.
Angular comes pre-configured with strategies that address these issues, but for this to work backend
server cooperation is required.
Email us at [security@angularjs.org](mailto:security@angularjs.org) to report any potential
security issues in AngularJS.
Please keep in mind the above points about Angular's expression language.
### Cross Site Request Forgery (XSRF/CSRF)
Protection from XSRF is provided by using the double-submit cookie defense pattern.
For more information please visit {@link $http#cross-site-request-forgery-xsrf-protection XSRF protection}.
### JSON Hijacking Protection
Protection from JSON Hijacking is provided if the server prefixes all JSON requests with following string `")]}',\n"`.
Angular will automatically strip the prefix before processing it as JSON.
For more information please visit {@link $http#json-vulnerability-protection JSON Hijacking Protection}.
## Strict Contextual Escaping
Strict Contextual Escaping (SCE) is a mode in which AngularJS requires bindings in certain contexts to require
a value that is marked as safe to use for that context.
This mode is implemented by the {@link $sce} service and various core directives.
One example of such a context is rendering arbitrary content via the {@link ngBindHtml} directive. If the content is
provided by a user there is a chance of Cross Site Scripting (XSS) attacks. The {@link ngBindHtml} directive will not
render content that is not marked as safe by {@link $sce}. The {@link ngSanitize} module can be used to clean such
user provided content and mark the content as safe.
**Be aware that marking untrusted data as safe via calls to {@link $sce#trustAsHtml `$sce.trustAsHtml`}, etc is
dangerous and will lead to Cross Site Scripting exploits.**
For more information please visit {@link $sce} and {@link ngSanitize.$sanitize}.
## Using Local Caches
There are various places that the browser can store (or cache) data. Within Angular there are objects created by
the {@link $cacheFactory}. These objects, such as {@link $templateCache} are used to store and retrieve data,
primarily used by {@link $http} and the {@link script} directive to cache templates and other data.
Similarly the browser itself offers `localStorage` and `sessionStorage` objects for caching data.
**Attackers with local access can retrieve sensitive data from this cache even when users are not authenticated.**
For instance in a long running Single Page Application (SPA), one user may "log out", but then another user
may access the application without refreshing, in which case all the cached data is still available.
For more information please visit [Web Storage Security](https://www.whitehatsec.com/blog/web-storage-security/).
## See also
* {@link ng.directive:ngCsp Content Security Policy}
* {@link ng.$sce Strict Contextual Escaping}
* {@link ngSanitize.$sanitize $sanitize}
+1 -1
View File
@@ -43,7 +43,7 @@ subsystem takes care of the rest.
<file name="script.js">
angular.
module('myServiceModule', []).
controller('MyController', ['$scope', 'notify', function ($scope, notify) {
controller('MyController', ['$scope','notify', function ($scope, notify) {
$scope.callNotify = function(msg) {
notify(msg);
};
+6 -51
View File
@@ -6,7 +6,7 @@
JavaScript is a dynamically typed language which comes with great power of expression, but it also
comes with almost no help from the compiler. For this reason we feel very strongly that any code
written in JavaScript needs to come with a strong set of tests. We have built many features into
Angular which make testing your Angular applications easy. With Angular, there is no excuse for not testing.
Angular which makes testing your Angular applications easy. So there is no excuse for not testing.
## Separation of Concerns
@@ -20,13 +20,13 @@ related pieces such as the DOM elements, or making any XHR calls to fetch the da
While this may seem obvious it can be very difficult to call an individual function on a
typical project. The reason is that the developers often mix concerns resulting in a
piece of code which does everything. It makes an XHR request, it sorts the response data, and then it
piece of code which does everything. It makes an XHR request, it sorts the response data and then it
manipulates the DOM.
With Angular, we try to make it easy for you to do the right thing. For your XHR requests, we
provide dependency injection, so your requests can be simulated. For the DOM, we abstract it, so you can
test your model without having to manipulate the DOM directly. Your tests can then
assert that the data has been sorted without having to create or look at the state of the DOM or to
With Angular we try to make it easy for you to do the right thing, and so we
provide dependency injection for your XHR requests, which can be mocked, and we provide abstractions which
allow you to test your model without having to resort to manipulating the DOM. The test can then
assert that the data has been sorted without having to create or look at the state of the DOM or
wait for any XHR requests to return data. The individual sort function can be tested in isolation.
## With great power comes great responsibility
@@ -430,50 +430,5 @@ If your directive uses `templateUrl`, consider using
to pre-compile HTML templates and thus avoid having to load them over HTTP during test execution.
Otherwise you may run into issues if the test directory hierarchy differs from the application's.
## Testing Promises
When testing promises, it's important to know that the resolution of promises is tied to the {@link ng.$rootScope.Scope#$digest digest cycle}.
That means a promise's `then`, `catch` and `finally` callback functions are only called after a digest has run.
In tests, you can trigger a digest by calling a scope's {@link ng.$rootScope.Scope#$apply `$apply` function}.
If you don't have a scope in your test, you can inject the {@link ng.$rootScope $rootScope} and call `$apply` on it.
There is also an example of testing promises in the {@link ng.$q#testing `$q` service documentation}.
## 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 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.
In the example below we are testing a service that takes a long time to generate its answer. To avoid having all of the assertions we want to write in a single test case, {@link angular.mock.module.sharedInjector module.sharedInjector()} and Jasmine's `beforeAll()` are used to run the service only once. The test cases then all make assertions about the properties added to the service instance.
```javascript
describe("Deep Thought", function() {
module.sharedInjector();
beforeAll(module("UltimateQuestion"));
beforeAll(inject(function(DeepThought) {
expect(DeepThought.answer).toBeUndefined();
DeepThought.generateAnswer();
}));
it("has calculated the answer correctly", inject(function(DeepThought) {
// Because of sharedInjector, we have access to the instance of the DeepThought service
// that was provided to the beforeAll() hook. Therefore we can test the generated answer
expect(DeepThought.answer).toBe(42);
}));
it("has calculated the answer within the expected time", inject(function(DeepThought) {
expect(DeepThought.runTimeMillennia).toBeLessThan(8000);
}));
it("has double checked the answer", inject(function(DeepThought) {
expect(DeepThought.absolutelySureItIsTheRightAnswer).toBe(true);
}));
});
```
## Sample project
See the [angular-seed](https://github.com/angular/angular-seed) project for an example.
-10
View File
@@ -246,15 +246,6 @@ npm run update-webdriver
*(You should only need to do this once.)*
You will need to have Java present on your dev machine to allow the Selenium standalone to be started.
Check if you already have java installed by opening a terminal/command line window and typing
'''
java -version
'''
If java is already installed and exists in the PATH then you will be shown the version installed,
if, however you receive a message that "java is not recognized as an internal command or external
command" you will need to install [java].
Since Protractor works by interacting with a running application, we need to start our web server:
```
@@ -289,4 +280,3 @@ Now that you have set up your local machine, let's get started with the tutorial
[bower]: http://bower.io/
[http-server]: https://github.com/nodeapps/http-server
[karma]: https://github.com/karma-runner/karma
[java]: https://www.java.com/en/download/help/download_options.xml
File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 73 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 39 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

+1 -1
View File
@@ -20,7 +20,7 @@
* using the --for_closure flag.
* File generated from CLDR ver. 27.0.1
*
* This file covers those locales that are not covered in
* This file coveres those locales that are not covered in
* "numberformatsymbols.js".
*
* Before checkin, this file could have been manually edited. This is
+1 -1
View File
@@ -272,7 +272,7 @@ describe("serializeContent", function() {
it("should not transform arrays into objects", function() {
var serializedContent = closureI18nExtractor.serializeContent(newTestLocaleInfo().fr_CA);
var deserializedLocale = eval("(" + serializedContent + ")");
expect(deserializedLocale.DATETIME_FORMATS.MONTH.length).not.toBeUndefined();
expect(deserializedLocale.DATETIME_FORMATS.MONTH.length).not.toBe(undefined);
});
});
+1 -1
View File
@@ -11,7 +11,7 @@ var PATTERN_SEP = ';',
DIGIT = '#';
/**
* main function for parser
* main funciton for parser
* @param str {string} pattern to be parsed (e.g. #,##0.###).
*/
function parsePattern(pattern) {
+3 -9
View File
@@ -37,25 +37,19 @@ module.exports = function(config, specificOptions) {
'SL_Chrome': {
base: 'SauceLabs',
browserName: 'chrome',
version: '47'
version: '43'
},
'SL_Firefox': {
base: 'SauceLabs',
browserName: 'firefox',
version: '43'
version: '39'
},
'SL_Safari_8': {
'SL_Safari': {
base: 'SauceLabs',
browserName: 'safari',
platform: 'OS X 10.10',
version: '8'
},
'SL_Safari_9': {
base: 'SauceLabs',
browserName: 'safari',
platform: 'OS X 10.11',
version: '9'
},
'SL_IE_9': {
base: 'SauceLabs',
browserName: 'internet explorer',
+1 -1
View File
@@ -287,7 +287,7 @@ module.exports = {
rewrite: function(){
return function(req, res, next){
var REWRITE = /\/(guide|api|cookbook|misc|tutorial|error).*$/,
IGNORED = /(\.(css|js|png|jpg|gif|svg)$|partials\/.*\.html$)/,
IGNORED = /(\.(css|js|png|jpg|gif)$|partials\/.*\.html$)/,
match;
if (!IGNORED.test(req.url) && (match = req.url.match(REWRITE))) {
+309
View File
@@ -0,0 +1,309 @@
/*
* HTML Parser By John Resig (ejohn.org)
* Original code by Erik Arvidsson, Mozilla Public License
* http://erik.eae.net/simplehtmlparser/simplehtmlparser.js
*
* // Use like so:
* htmlParser(htmlString, {
* start: function(tag, attrs, unary) {},
* end: function(tag) {},
* chars: function(text) {},
* comment: function(text) {}
* });
*
* // or to get an XML string:
* HTMLtoXML(htmlString);
*
* // or to get an XML DOM Document
* HTMLtoDOM(htmlString);
*
* // or to inject into an existing document/DOM node
* HTMLtoDOM(htmlString, document);
* HTMLtoDOM(htmlString, document.body);
*
*/
(function(){
// Regular Expressions for parsing tags and attributes
var startTag = /^<(\w+)((?:\s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/,
endTag = /^<\/(\w+)[^>]*>/,
attr = /(\w+)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))?/g;
// Empty Elements - HTML 4.01
var empty = makeMap("area,base,basefont,br,col,frame,hr,img,input,isindex,link,meta,param,embed");
// Block Elements - HTML 4.01
var block = makeMap("address,applet,blockquote,button,center,dd,del,dir,div,dl,dt,fieldset,form,frameset,hr,iframe,ins,isindex,li,map,menu,noframes,noscript,object,ol,p,pre,script,table,tbody,td,tfoot,th,thead,tr,ul");
// Inline Elements - HTML 4.01
var inline = makeMap("a,abbr,acronym,applet,b,basefont,bdo,big,br,button,cite,code,del,dfn,em,font,i,iframe,img,input,ins,kbd,label,map,object,q,s,samp,script,select,small,span,strike,strong,sub,sup,textarea,tt,u,var");
// Elements that you can, intentionally, leave open
// (and which close themselves)
var closeSelf = makeMap("colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr");
// Attributes that have their values filled in disabled="disabled"
var fillAttrs = makeMap("checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected");
// Special Elements (can contain anything)
var special = makeMap("script,style");
var htmlParser = this.htmlParser = function( html, handler ) {
var index, chars, match, stack = [], last = html;
stack.last = function(){
return this[ this.length - 1 ];
};
while ( html ) {
chars = true;
// Make sure we're not in a script or style element
if ( !stack.last() || !special[ stack.last() ] ) {
// Comment
if ( html.indexOf("<!--") == 0 ) {
index = html.indexOf("-->");
if ( index >= 0 ) {
if ( handler.comment )
handler.comment( html.substring( 4, index ) );
html = html.substring( index + 3 );
chars = false;
}
// end tag
} else if ( html.indexOf("</") == 0 ) {
match = html.match( endTag );
if ( match ) {
html = html.substring( match[0].length );
match[0].replace( endTag, parseEndTag );
chars = false;
}
// start tag
} else if ( html.indexOf("<") == 0 ) {
match = html.match( startTag );
if ( match ) {
html = html.substring( match[0].length );
match[0].replace( startTag, parseStartTag );
chars = false;
}
}
if ( chars ) {
index = html.indexOf("<");
var text = index < 0 ? html : html.substring( 0, index );
html = index < 0 ? "" : html.substring( index );
if ( handler.chars )
handler.chars( text );
}
} else {
html = html.replace(new RegExp("(.*)<\/" + stack.last() + "[^>]*>"), function(all, text){
text = text.replace(/<!--(.*?)-->/g, "$1")
.replace(/<!\[CDATA\[(.*?)]]>/g, "$1");
if ( handler.chars )
handler.chars( text );
return "";
});
parseEndTag( "", stack.last() );
}
if ( html == last )
throw "Parse Error: " + html;
last = html;
}
// Clean up any remaining tags
parseEndTag();
function parseStartTag( tag, tagName, rest, unary ) {
if ( block[ tagName ] ) {
while ( stack.last() && inline[ stack.last() ] ) {
parseEndTag( "", stack.last() );
}
}
if ( closeSelf[ tagName ] && stack.last() == tagName ) {
parseEndTag( "", tagName );
}
unary = empty[ tagName ] || !!unary;
if ( !unary )
stack.push( tagName );
if ( handler.start ) {
var attrs = [];
rest.replace(attr, function(match, name) {
var value = arguments[2] ? arguments[2] :
arguments[3] ? arguments[3] :
arguments[4] ? arguments[4] :
fillAttrs[name] ? name : "";
attrs.push({
name: name,
value: value,
escaped: value.replace(/(^|[^\\])"/g, '$1\\\"') //"
});
});
if ( handler.start )
handler.start( tagName, attrs, unary );
}
}
function parseEndTag( tag, tagName ) {
// If no tag name is provided, clean shop
if ( !tagName )
var pos = 0;
// Find the closest opened tag of the same type
else
for ( var pos = stack.length - 1; pos >= 0; pos-- )
if ( stack[ pos ] == tagName )
break;
if ( pos >= 0 ) {
// Close all the open elements, up the stack
for ( var i = stack.length - 1; i >= pos; i-- )
if ( handler.end )
handler.end( stack[ i ] );
// Remove the open elements from the stack
stack.length = pos;
}
}
};
this.HTMLtoXML = function( html ) {
var results = "";
htmlParser(html, {
start: function( tag, attrs, unary ) {
results += "<" + tag;
for ( var i = 0; i < attrs.length; i++ )
results += " " + attrs[i].name + '="' + attrs[i].escaped + '"';
results += (unary ? "/" : "") + ">";
},
end: function( tag ) {
results += "</" + tag + ">";
},
chars: function( text ) {
results += text;
},
comment: function( text ) {
results += "<!--" + text + "-->";
}
});
return results;
};
this.HTMLtoDOM = function( html, doc ) {
// There can be only one of these elements
var one = makeMap("html,head,body,title");
// Enforce a structure for the document
var structure = {
link: "head",
base: "head"
};
if ( !doc ) {
if ( typeof DOMDocument != "undefined" )
doc = new DOMDocument();
else if ( typeof document != "undefined" && document.implementation && document.implementation.createDocument )
doc = document.implementation.createDocument("", "", null);
else if ( typeof ActiveX != "undefined" )
doc = new ActiveXObject("Msxml.DOMDocument");
} else
doc = doc.ownerDocument ||
doc.getOwnerDocument && doc.getOwnerDocument() ||
doc;
var elems = [],
documentElement = doc.documentElement ||
doc.getDocumentElement && doc.getDocumentElement();
// If we're dealing with an empty document then we
// need to pre-populate it with the HTML document structure
if ( !documentElement && doc.createElement ) (function(){
var html = doc.createElement("html");
var head = doc.createElement("head");
head.appendChild( doc.createElement("title") );
html.appendChild( head );
html.appendChild( doc.createElement("body") );
doc.appendChild( html );
})();
// Find all the unique elements
if ( doc.getElementsByTagName )
for ( var i in one )
one[ i ] = doc.getElementsByTagName( i )[0];
// If we're working with a document, inject contents into
// the body element
var curParentNode = one.body;
htmlParser( html, {
start: function( tagName, attrs, unary ) {
// If it's a pre-built element, then we can ignore
// its construction
if ( one[ tagName ] ) {
curParentNode = one[ tagName ];
return;
}
var elem = doc.createElement( tagName );
for ( var attr in attrs )
elem.setAttribute( attrs[ attr ].name, attrs[ attr ].value );
if ( structure[ tagName ] && typeof one[ structure[ tagName ] ] != "boolean" )
one[ structure[ tagName ] ].appendChild( elem );
else if ( curParentNode && curParentNode.appendChild )
curParentNode.appendChild( elem );
if ( !unary ) {
elems.push( elem );
curParentNode = elem;
}
},
end: function( tag ) {
elems.length -= 1;
// Init the new parentNode
curParentNode = elems[ elems.length - 1 ];
},
chars: function( text ) {
curParentNode.appendChild( doc.createTextNode( text ) );
},
comment: function( text ) {
// create comment node
}
});
return doc;
};
function makeMap(str){
var obj = {}, items = str.split(",");
for ( var i = 0; i < items.length; i++ )
obj[ items[i] ] = true;
return obj;
}
})();
+2 -1
View File
@@ -11,7 +11,8 @@ set -e
# Curl and run this script as part of your .travis.yml before_script section:
# before_script:
# - curl https://gist.github.com/santiycr/5139565/raw/sauce_connect_setup.sh | bash
CONNECT_URL="https://saucelabs.com/downloads/sc-4.3.13-linux.tar.gz"
CONNECT_URL="https://saucelabs.com/downloads/sc-4.3.7-linux.tar.gz"
CONNECT_DIR="/tmp/sauce-connect-$RANDOM"
CONNECT_DOWNLOAD="sc-4.3.7-linux.tar.gz"
+1 -1
View File
@@ -178,7 +178,7 @@ var getSnapshotVersion = function() {
// last release was a non beta release. Increment the patch level to
// indicate the next release that we will be doing.
// E.g. last release was 1.3.0, then the snapshot will be
// 1.3.1-build.1, which is lesser than 1.3.1 according to the semver!
// 1.3.1-build.1, which is lesser than 1.3.1 accorind the semver!
// If the last release was a beta release we don't update the
// beta number by purpose, as otherwise the semver comparison
+2938 -2046
View File
File diff suppressed because it is too large Load Diff
+5426 -4034
View File
File diff suppressed because it is too large Load Diff
+7 -8
View File
@@ -1,15 +1,15 @@
{
"name": "angularjs",
"license": "MIT",
"branchVersion": "1.5.x",
"branchPattern": "1.5.*",
"distTag": "latest",
"branchVersion": "1.4.x",
"branchPattern": "1.4.*",
"distTag": "previous_1_4",
"repository": {
"type": "git",
"url": "https://github.com/angular/angular.js.git"
},
"engines": {
"node": "<5",
"node": "~0.10",
"npm": "~2.5"
},
"engineStrict": true,
@@ -27,7 +27,7 @@
"canonical-path": "0.0.2",
"cheerio": "^0.17.0",
"commitizen": "^2.3.0",
"cz-conventional-changelog": "1.1.4",
"cz-conventional-changelog": "^1.1.4",
"dgeni": "^0.4.0",
"dgeni-packages": "^0.11.0",
"event-stream": "~3.1.0",
@@ -41,7 +41,7 @@
"grunt-contrib-jshint": "~0.10.0",
"grunt-ddescribe-iit": "~0.0.1",
"grunt-jasmine-node": "git://github.com/vojtajina/grunt-jasmine-node.git#fix-grunt-exit-code",
"grunt-jscs": "^2.1.0",
"grunt-jscs": "~1.2.0",
"grunt-merge-conflict": "~0.0.1",
"grunt-shell": "~1.1.1",
"gulp": "~3.8.0",
@@ -52,7 +52,6 @@
"gulp-sourcemaps": "^1.2.2",
"gulp-uglify": "^1.0.1",
"gulp-util": "^3.0.1",
"jasmine-core": "^2.4.0",
"jasmine-node": "^2.0.0",
"jasmine-reporters": "~1.0.1",
"jshint-stylish": "~1.0.0",
@@ -60,7 +59,7 @@
"karma-browserstack-launcher": "^0.1.8",
"karma-chrome-launcher": "^0.2.2",
"karma-firefox-launcher": "^0.1.7",
"karma-jasmine": "^0.3.7",
"karma-jasmine": "^0.1.6",
"karma-junit-reporter": "^0.3.8",
"karma-ng-scenario": "^0.1.0",
"karma-sauce-launcher": "^0.3.0",
+1 -1
View File
@@ -11,7 +11,7 @@ elif [ $JOB = "unit" ]; then
if [ "$BROWSER_PROVIDER" == "browserstack" ]; then
BROWSERS="BS_Chrome,BS_Safari,BS_Firefox,BS_IE_9,BS_IE_10,BS_IE_11,BS_iOS"
else
BROWSERS="SL_Chrome,SL_Firefox,SL_Safari_8,SL_Safari_9,SL_IE_9,SL_IE_10,SL_IE_11,SL_iOS"
BROWSERS="SL_Chrome,SL_Safari,SL_Firefox,SL_IE_9,SL_IE_10,SL_IE_11,SL_iOS"
fi
grunt test:promises-aplus
+2
View File
@@ -94,6 +94,8 @@
"VALIDITY_STATE_PROPERTY": false,
"reloadWithDebugInfo": false,
"skipDestroyOnNextJQueryCleanData": true,
"NODE_TYPE_ELEMENT": false,
"NODE_TYPE_ATTRIBUTE": false,
"NODE_TYPE_TEXT": false,
+104 -116
View File
@@ -119,9 +119,29 @@ 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';
/**
* @ngdoc function
* @name angular.lowercase
* @module ng
* @kind function
*
* @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;};
var hasOwnProperty = Object.prototype.hasOwnProperty;
var lowercase = function(string) {return isString(string) ? string.toLowerCase() : string;};
/**
* @ngdoc function
* @name angular.uppercase
* @module ng
* @kind function
*
* @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;};
@@ -141,7 +161,7 @@ var manualUppercase = function(s) {
// String#toLowerCase and String#toUpperCase don't produce correct results in browsers with Turkish
// locale, for this reason we need to detect this case and redefine lowercase/uppercase methods
// with correct but slower alternatives. See https://github.com/angular/angular.js/issues/11387
// with correct but slower alternatives.
if ('i' !== 'I'.toLowerCase()) {
lowercase = manualLowercase;
uppercase = manualUppercase;
@@ -184,7 +204,7 @@ function isArrayLike(obj) {
// arrays, strings and jQuery/jqLite objects are array like
// * jqLite is either the jQuery or jqLite constructor function
// * we have to check the existence of jqLite first as this method is called
// * we have to check the existance of jqLite first as this method is called
// via the forEach method when constructing the jqLite object in the first place
if (isArray(obj) || isString(obj) || (jqLite && obj instanceof jqLite)) return true;
@@ -446,18 +466,28 @@ noop.$inject = [];
* functional style.
*
```js
function transformer(transformationFn, value) {
return (transformationFn || angular.identity)(value);
};
function transformer(transformationFn, value) {
return (transformationFn || angular.identity)(value);
};
// E.g.
function getResult(fn, input) {
return (fn || angular.identity)(input);
};
getResult(function(n) { return n * 2; }, 21); // returns 42
getResult(null, 21); // returns 21
getResult(undefined, 21); // returns 21
```
* @param {*} value to be returned.
* @returns {*} the value passed in.
*
* @param {*} value to be returned.
* @returns {*} the value passed in.
*/
function identity($) {return $;}
identity.$inject = [];
function valueFn(value) {return function valueRef() {return value;};}
function valueFn(value) {return function() {return value;};}
function hasCustomToString(obj) {
return isFunction(obj.toString) && obj.toString !== toString;
@@ -664,10 +694,6 @@ function isTypedArray(value) {
return value && isNumber(value.length) && TYPED_ARRAY_REGEXP.test(toString.call(value));
}
function isArrayBuffer(obj) {
return toString.call(obj) === '[object ArrayBuffer]';
}
var trim = function(value) {
return isString(value) ? value.trim() : value;
@@ -792,7 +818,7 @@ function copy(source, destination) {
var stackDest = [];
if (destination) {
if (isTypedArray(destination) || isArrayBuffer(destination)) {
if (isTypedArray(destination)) {
throw ngMinErr('cpta', "Can't copy! TypedArray destination cannot be mutated.");
}
if (source === destination) {
@@ -819,7 +845,7 @@ function copy(source, destination) {
function copyRecurse(source, destination) {
var h = destination.$$hashKey;
var key;
var result, key;
if (isArray(source)) {
for (var i = 0, ii = source.length; i < ii; i++) {
destination.push(copyElement(source[i]));
@@ -866,10 +892,24 @@ function copy(source, destination) {
}
var needsRecurse = false;
var destination = copyType(source);
var destination;
if (destination === undefined) {
destination = isArray(source) ? [] : Object.create(getPrototypeOf(source));
if (isArray(source)) {
destination = [];
needsRecurse = true;
} else if (isTypedArray(source)) {
destination = new source.constructor(source);
} else if (isDate(source)) {
destination = new Date(source.getTime());
} else if (isRegExp(source)) {
destination = new RegExp(source.source, source.toString().match(/[^\/]*$/)[0]);
destination.lastIndex = source.lastIndex;
} else if (isBlob(source)) {
destination = new source.constructor([source], {type: source.type});
} else if (isFunction(source.cloneNode)) {
destination = source.cloneNode(true);
} else {
destination = Object.create(getPrototypeOf(source));
needsRecurse = true;
}
@@ -880,48 +920,6 @@ function copy(source, destination) {
? copyRecurse(source, destination)
: destination;
}
function copyType(source) {
switch (toString.call(source)) {
case '[object Int8Array]':
case '[object Int16Array]':
case '[object Int32Array]':
case '[object Float32Array]':
case '[object Float64Array]':
case '[object Uint8Array]':
case '[object Uint8ClampedArray]':
case '[object Uint16Array]':
case '[object Uint32Array]':
return new source.constructor(copyElement(source.buffer));
case '[object ArrayBuffer]':
//Support: IE10
if (!source.slice) {
var copied = new ArrayBuffer(source.byteLength);
new Uint8Array(copied).set(new Uint8Array(source));
return copied;
}
return source.slice(0);
case '[object Boolean]':
case '[object Number]':
case '[object String]':
case '[object Date]':
return new source.constructor(source.valueOf());
case '[object RegExp]':
var re = new RegExp(source.source, source.toString().match(/[^\/]*$/)[0]);
re.lastIndex = source.lastIndex;
return re;
case '[object Blob]':
return new source.constructor([source], {type: source.type});
}
if (isFunction(source.cloneNode)) {
return source.cloneNode(true);
}
}
}
/**
@@ -984,37 +982,38 @@ function equals(o1, o2) {
if (o1 === null || o2 === null) return false;
if (o1 !== o1 && o2 !== o2) return true; // NaN === NaN
var t1 = typeof o1, t2 = typeof o2, length, key, keySet;
if (t1 == t2 && t1 == 'object') {
if (isArray(o1)) {
if (!isArray(o2)) return false;
if ((length = o1.length) == o2.length) {
for (key = 0; key < length; key++) {
if (t1 == t2) {
if (t1 == 'object') {
if (isArray(o1)) {
if (!isArray(o2)) return false;
if ((length = o1.length) == o2.length) {
for (key = 0; key < length; key++) {
if (!equals(o1[key], o2[key])) return false;
}
return true;
}
} else if (isDate(o1)) {
if (!isDate(o2)) return false;
return equals(o1.getTime(), o2.getTime());
} else if (isRegExp(o1)) {
return isRegExp(o2) ? o1.toString() == o2.toString() : false;
} else {
if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) ||
isArray(o2) || isDate(o2) || isRegExp(o2)) return false;
keySet = createMap();
for (key in o1) {
if (key.charAt(0) === '$' || isFunction(o1[key])) continue;
if (!equals(o1[key], o2[key])) return false;
keySet[key] = true;
}
for (key in o2) {
if (!(key in keySet) &&
key.charAt(0) !== '$' &&
isDefined(o2[key]) &&
!isFunction(o2[key])) return false;
}
return true;
}
} else if (isDate(o1)) {
if (!isDate(o2)) return false;
return equals(o1.getTime(), o2.getTime());
} else if (isRegExp(o1)) {
if (!isRegExp(o2)) return false;
return o1.toString() == o2.toString();
} else {
if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) ||
isArray(o2) || isDate(o2) || isRegExp(o2)) return false;
keySet = createMap();
for (key in o1) {
if (key.charAt(0) === '$' || isFunction(o1[key])) continue;
if (!equals(o1[key], o2[key])) return false;
keySet[key] = true;
}
for (key in o2) {
if (!(key in keySet) &&
key.charAt(0) !== '$' &&
isDefined(o2[key]) &&
!isFunction(o2[key])) return false;
}
return true;
}
}
return false;
@@ -1405,17 +1404,10 @@ function getNgAttribute(element, ngAttr) {
* designates the **root element** of the application and is typically placed near the root element
* of the page - e.g. on the `<body>` or `<html>` tags.
*
* There are a few things to keep in mind when using `ngApp`:
* - only one AngularJS application can be auto-bootstrapped per HTML document. The first `ngApp`
* found in the document will be used to define the root element to auto-bootstrap as an
* application. To run multiple applications in an HTML document you must manually bootstrap them using
* {@link angular.bootstrap} instead.
* - AngularJS applications cannot be nested within each other.
* - Do not use a directive that uses {@link ng.$compile#transclusion transclusion} on the same element as `ngApp`.
* This includes directives such as {@link ng.ngIf `ngIf`}, {@link ng.ngInclude `ngInclude`} and
* {@link ngRoute.ngView `ngView`}.
* Doing this misplaces the app {@link ng.$rootElement `$rootElement`} and the app's {@link auto.$injector injector},
* causing animations to stop working and making the injector inaccessible from outside the app.
* Only one AngularJS application can be auto-bootstrapped per HTML document. The first `ngApp`
* found in the document will be used to define the root element to auto-bootstrap as an
* application. To run multiple applications in an HTML document you must manually bootstrap them using
* {@link angular.bootstrap} instead. AngularJS applications cannot be nested within each other.
*
* You can specify an **AngularJS module** to be used as the root module for the application. This
* module will be loaded into the {@link auto.$injector} when the application is bootstrapped. It
@@ -1555,25 +1547,16 @@ function angularInit(element, bootstrap) {
* @description
* Use this function to manually start up angular application.
*
* For more information, see the {@link guide/bootstrap Bootstrap guide}.
* See: {@link guide/bootstrap Bootstrap}
*
* Note that Protractor based end-to-end tests cannot use this function to bootstrap manually.
* They must use {@link ng.directive:ngApp ngApp}.
*
* Angular will detect if it has been loaded into the browser more than once and only allow the
* first loaded script to be bootstrapped and will report a warning to the browser console for
* each of the subsequent scripts. This prevents strange results in applications, where otherwise
* multiple instances of Angular try to work on the DOM.
*
* <div class="alert alert-warning">
* **Note:** Protractor based end-to-end tests cannot use this function to bootstrap manually.
* They must use {@link ng.directive:ngApp ngApp}.
* </div>
*
* <div class="alert alert-warning">
* **Note:** Do not bootstrap the app on an element with a directive that uses {@link ng.$compile#transclusion transclusion},
* such as {@link ng.ngIf `ngIf`}, {@link ng.ngInclude `ngInclude`} and {@link ngRoute.ngView `ngView`}.
* Doing this misplaces the app {@link ng.$rootElement `$rootElement`} and the app's {@link auto.$injector injector},
* causing animations to stop working and making the injector inaccessible from outside the app.
* </div>
*
* ```html
* <!doctype html>
* <html>
@@ -1621,7 +1604,7 @@ function bootstrap(element, modules, config) {
//Encode angle brackets to prevent input from being sanitized to empty string #8683
throw ngMinErr(
'btstrpd',
"App Already Bootstrapped with this Element '{0}'",
"App already bootstrapped with this element '{0}'",
tag.replace(/</,'&lt;').replace(/>/,'&gt;'));
}
@@ -1716,6 +1699,7 @@ function snake_case(name, separator) {
}
var bindJQueryFired = false;
var skipDestroyOnNextJQueryCleanData;
function bindJQuery() {
var originalCleanData;
@@ -1749,11 +1733,15 @@ function bindJQuery() {
originalCleanData = jQuery.cleanData;
jQuery.cleanData = function(elems) {
var events;
for (var i = 0, elem; (elem = elems[i]) != null; i++) {
events = jQuery._data(elem, "events");
if (events && events.$destroy) {
jQuery(elem).triggerHandler('$destroy');
if (!skipDestroyOnNextJQueryCleanData) {
for (var i = 0, elem; (elem = elems[i]) != null; i++) {
events = jQuery._data(elem, "events");
if (events && events.$destroy) {
jQuery(elem).triggerHandler('$destroy');
}
}
} else {
skipDestroyOnNextJQueryCleanData = false;
}
originalCleanData(elems);
};
-1
View File
@@ -63,7 +63,6 @@
$BrowserProvider,
$CacheFactoryProvider,
$ControllerProvider,
$DateProvider,
$DocumentProvider,
$ExceptionHandlerProvider,
$FilterProvider,
+1 -1
View File
@@ -1,6 +1,6 @@
/**
* @license AngularJS v"NG_VERSION_FULL"
* (c) 2010-2016 Google, Inc. http://angularjs.org
* (c) 2010-2015 Google, Inc. http://angularjs.org
* License: MIT
*/
(function(window, document, undefined) {
+36 -64
View File
@@ -62,23 +62,17 @@
* Implicit module which gets automatically added to each {@link auto.$injector $injector}.
*/
var ARROW_ARG = /^([^\(]+?)=>/;
var FN_ARGS = /^[^\(]*\(\s*([^\)]*)\)/m;
var FN_ARG_SPLIT = /,/;
var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
var $injectorMinErr = minErr('$injector');
function extractArgs(fn) {
var fnText = fn.toString().replace(STRIP_COMMENTS, ''),
args = fnText.match(ARROW_ARG) || fnText.match(FN_ARGS);
return args;
}
function anonFn(fn) {
// For anonymous functions, showing at the very least the function signature can help in
// debugging.
var args = extractArgs(fn);
var fnText = fn.toString().replace(STRIP_COMMENTS, ''),
args = fnText.match(FN_ARGS);
if (args) {
return 'function(' + (args[1] || '').replace(/[\s\r\n]+/, ' ') + ')';
}
@@ -87,6 +81,7 @@ function anonFn(fn) {
function annotate(fn, strictDi, name) {
var $inject,
fnText,
argDecl,
last;
@@ -101,7 +96,8 @@ function annotate(fn, strictDi, name) {
throw $injectorMinErr('strictdi',
'{0} is not using explicit annotation and cannot be invoked in strict mode', name);
}
argDecl = extractArgs(fn);
fnText = fn.toString().replace(STRIP_COMMENTS, '');
argDecl = fnText.match(FN_ARGS);
forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg) {
arg.replace(FN_ARG, function(all, underscore, name) {
$inject.push(name);
@@ -656,19 +652,14 @@ function createInjector(modulesToLoad, strictDi) {
throw $injectorMinErr('unpr', "Unknown provider: {0}", path.join(' <- '));
})),
instanceCache = {},
protoInstanceInjector =
instanceInjector = (instanceCache.$injector =
createInternalInjector(instanceCache, function(serviceName, caller) {
var provider = providerInjector.get(serviceName + providerSuffix, caller);
return instanceInjector.invoke(
provider.$get, provider, undefined, serviceName);
}),
instanceInjector = protoInstanceInjector;
return instanceInjector.invoke(provider.$get, provider, undefined, serviceName);
}));
providerCache['$injector' + providerSuffix] = { $get: valueFn(protoInstanceInjector) };
var runBlocks = loadModules(modulesToLoad);
instanceInjector = protoInstanceInjector.get('$injector');
instanceInjector.strictDi = strictDi;
forEach(runBlocks, function(fn) { if (fn) instanceInjector.invoke(fn); });
forEach(loadModules(modulesToLoad), function(fn) { if (fn) instanceInjector.invoke(fn); });
return instanceInjector;
@@ -818,66 +809,47 @@ function createInjector(modulesToLoad, strictDi) {
}
}
function injectionArgs(fn, locals, serviceName) {
var args = [],
$inject = createInjector.$$annotate(fn, strictDi, serviceName);
for (var i = 0, length = $inject.length; i < length; i++) {
var key = $inject[i];
if (typeof key !== 'string') {
throw $injectorMinErr('itkn',
'Incorrect injection token! Expected service name as string, got {0}', key);
}
args.push(locals && locals.hasOwnProperty(key) ? locals[key] :
getService(key, serviceName));
}
return args;
}
function isClass(func) {
// IE 9-11 do not support classes and IE9 leaks with the code below.
if (msie <= 11) {
return false;
}
// Workaround for MS Edge.
// Check https://connect.microsoft.com/IE/Feedback/Details/2211653
return typeof func === 'function'
&& /^(?:class\s|constructor\()/.test(Function.prototype.toString.call(func));
}
function invoke(fn, self, locals, serviceName) {
if (typeof locals === 'string') {
serviceName = locals;
locals = null;
}
var args = injectionArgs(fn, locals, serviceName);
var args = [],
$inject = createInjector.$$annotate(fn, strictDi, serviceName),
length, i,
key;
for (i = 0, length = $inject.length; i < length; i++) {
key = $inject[i];
if (typeof key !== 'string') {
throw $injectorMinErr('itkn',
'Incorrect injection token! Expected service name as string, got {0}', key);
}
args.push(
locals && locals.hasOwnProperty(key)
? locals[key]
: getService(key, serviceName)
);
}
if (isArray(fn)) {
fn = fn[fn.length - 1];
fn = fn[length];
}
if (!isClass(fn)) {
// http://jsperf.com/angularjs-invoke-apply-vs-switch
// #5388
return fn.apply(self, args);
} else {
args.unshift(null);
return new (Function.prototype.bind.apply(fn, args))();
}
// http://jsperf.com/angularjs-invoke-apply-vs-switch
// #5388
return fn.apply(self, args);
}
function instantiate(Type, locals, serviceName) {
// Check if Type is annotated and use just the given function at n-1 as parameter
// e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]);
var ctor = (isArray(Type) ? Type[Type.length - 1] : Type);
var args = injectionArgs(Type, locals, serviceName);
// Empty object at position 0 is ignored for invocation with `new`, but required.
args.unshift(null);
return new (Function.prototype.bind.apply(ctor, args))();
}
// Object creation: http://jsperf.com/create-constructor/2
var instance = Object.create((isArray(Type) ? Type[Type.length - 1] : Type).prototype || null);
var returnedValue = invoke(Type, instance, locals, serviceName);
return isObject(returnedValue) || isFunction(returnedValue) ? returnedValue : instance;
}
return {
invoke: invoke,
+2 -9
View File
@@ -196,12 +196,6 @@ function jqLiteHasData(node) {
return false;
}
function jqLiteCleanData(nodes) {
for (var i = 0, ii = nodes.length; i < ii; i++) {
jqLiteRemoveData(nodes[i]);
}
}
function jqLiteBuildFragment(html, context) {
var tmp, tag, wrap,
fragment = context.createDocumentFragment(),
@@ -514,7 +508,7 @@ function jqLiteRemove(element, keepData) {
function jqLiteDocumentLoaded(action, win) {
win = win || window;
if (win.document.readyState === 'complete') {
// Force the action to be run async for consistent behavior
// Force the action to be run async for consistent behaviour
// from the action's point of view
// i.e. it will definitely not be in a $apply
win.setTimeout(action);
@@ -600,8 +594,7 @@ function getAliasedAttrName(name) {
forEach({
data: jqLiteData,
removeData: jqLiteRemoveData,
hasData: jqLiteHasData,
cleanData: jqLiteCleanData
hasData: jqLiteHasData
}, function(fn, name) {
JQLite[name] = fn;
});
+3 -16
View File
@@ -197,9 +197,9 @@ function setupModuleLoader(window) {
* @ngdoc method
* @name angular.Module#decorator
* @module ng
* @param {string} The name of the service to decorate.
* @param {Function} This function will be invoked when the service needs to be
* instantiated and should return the decorated service instance.
* @param {string} name The name of the service to decorate.
* @param {Function} decorFn This function will be invoked when the service needs to be
* instantiated and should return the decorated service instance.
* @description
* See {@link auto.$provide#decorator $provide.decorator()}.
*/
@@ -282,19 +282,6 @@ function setupModuleLoader(window) {
*/
directive: invokeLaterAndSetModuleName('$compileProvider', 'directive'),
/**
* @ngdoc method
* @name angular.Module#component
* @module ng
* @param {string} name Name of the component in camel-case (i.e. myComp which will match as my-comp)
* @param {Object} options Component definition object (a simplified
* {@link ng.$compile#directive-definition-object directive definition object})
*
* @description
* See {@link ng.$compileProvider#component $compileProvider.component()}.
*/
component: invokeLaterAndSetModuleName('$compileProvider', 'component'),
/**
* @ngdoc method
* @name angular.Module#config
+2 -2
View File
@@ -1,8 +1,8 @@
/**
* @license AngularJS v"NG_VERSION_FULL"
* (c) 2010-2016 Google, Inc. http://angularjs.org
* (c) 2010-2015 Google, Inc. http://angularjs.org
* License: MIT
*/
'use strict';
(function() {
function isFunction(value) {return typeof value === 'function';};
function isFunction(value) {return typeof value === 'function';};
+1 -1
View File
@@ -1,6 +1,6 @@
/**
* @license AngularJS v"NG_VERSION_FULL"
* (c) 2010-2016 Google, Inc. http://angularjs.org
* (c) 2010-2015 Google, Inc. http://angularjs.org
* License: MIT
*/
(function(window, angular, undefined) {
+1 -1
View File
@@ -41,7 +41,7 @@ function $AnchorScrollProvider() {
* When called, it scrolls to the element related to the specified `hash` or (if omitted) to the
* current value of {@link ng.$location#hash $location.hash()}, according to the rules specified
* in the
* [HTML5 spec](http://www.w3.org/html/wg/drafts/html/master/browsers.html#the-indicated-part-of-the-document).
* [HTML5 spec](http://www.w3.org/html/wg/drafts/html/master/browsers.html#an-indicated-part-of-the-document).
*
* It also watches the {@link ng.$location#hash $location.hash()} and automatically scrolls to
* match any anchor whenever it changes. This can be disabled by calling
+5 -5
View File
@@ -54,7 +54,7 @@ function prepareAnimateOptions(options) {
}
var $$CoreAnimateJsProvider = function() {
this.$get = noop;
this.$get = function() {};
};
// this is prefixed with Core since it conflicts with
@@ -329,8 +329,8 @@ var $AnimateProvider = ['$provide', function($provide) {
* // remove all the animation event listeners listening for `enter` on the given element and its children
* $animate.off('enter', container);
*
* // remove the event listener function provided by `callback` that is set
* // to listen for `enter` on the given `container` as well as its children
* // remove the event listener function provided by `listenerFn` that is set
* // to listen for `enter` on the given `element` as well as its children
* $animate.off('enter', container, callback);
* ```
*
@@ -553,7 +553,7 @@ var $AnimateProvider = ['$provide', function($provide) {
*
* @description Performs an inline animation on the element which applies the provided to and from CSS styles to the element.
* If any detected CSS transition, keyframe or JavaScript matches the provided className value, then the animation will take
* on the provided styles. For example, if a transition animation is set for the given classNamem, then the provided `from` and
* on the provided styles. For example, if a transition animation is set for the given className, then the provided `from` and
* `to` styles will be applied alongside the given transition. If the CSS style provided in `from` does not have a corresponding
* style in `to`, the style in `from` is applied immediately, and no animation is run.
* If a JavaScript animation is detected then the provided styles will be given in as function parameters into the `animate`
@@ -575,7 +575,7 @@ var $AnimateProvider = ['$provide', function($provide) {
* @param {object} to the to (destination) CSS styles that will be applied to the element and across the animation.
* @param {string=} className an optional CSS class that will be applied to the element for the duration of the animation. If
* this value is left as empty then a CSS class of `ng-inline-animate` will be applied to the element.
* (Note that if no animation is detected then this value will not be applied to the element.)
* (Note that if no animation is detected then this value will not be appplied to the element.)
* @param {object=} options an optional collection of options/styles that will be applied to the element
*
* @return {Promise} the animation callback promise
+1 -1
View File
@@ -36,7 +36,7 @@ var $CoreAnimateCssProvider = function() {
options.from = null;
}
/* jshint newcap: false */
/* jshint newcap: false*/
var closed, runner = new $$AnimateRunner();
return {
start: run,
+1
View File
@@ -24,6 +24,7 @@
*/
function Browser(window, document, $log, $sniffer) {
var self = this,
rawDocument = document[0],
location = window.location,
history = window.history,
setTimeout = window.setTimeout,
+141 -534
View File
@@ -128,7 +128,7 @@
* When this property is set to true, the HTML compiler will collect DOM nodes between
* nodes with the attributes `directive-name-start` and `directive-name-end`, and group them
* together as the directive elements. It is recommended that this feature be used on directives
* which are not strictly behavioral (such as {@link ngClick}), and which
* which are not strictly behavioural (such as {@link ngClick}), and which
* do not manipulate or replace child nodes (such as {@link ngInclude}).
*
* #### `priority`
@@ -189,30 +189,6 @@
* equality check is done by value (using the {@link angular.equals} function). It's also possible
* to watch the evaluated value shallowly with {@link ng.$rootScope.Scope#$watchCollection
* `$watchCollection`}: use `=*` or `=*attr` (`=*?` or `=*?attr` if the attribute is optional).
*
* * `<` or `<attr` - set up a one-way (one-directional) binding between a local scope property and an
* expression passed via the attribute `attr`. The expression is evaluated in the context of the
* parent scope. If no `attr` name is specified then the attribute name is assumed to be the same as the
* local name. You can also make the binding optional by adding `?`: `<?` or `<?attr`.
*
* For example, given `<my-component my-attr="parentModel">` and directive definition of
* `scope: { localModel:'<myAttr' }`, then the isolated scope property `localModel` will reflect the
* value of `parentModel` on the parent scope. Any changes to `parentModel` will be reflected
* in `localModel`, but changes in `localModel` will not reflect in `parentModel`. There are however
* two caveats:
* 1. one-way binding does not copy the value from the parent to the isolate scope, it simply
* sets the same value. That means if your bound value is an object, changes to its properties
* in the isolated scope will be reflected in the parent scope (because both reference the same object).
* 2. one-way binding watches changes to the **identity** of the parent value. That means the
* {@link ng.$rootScope.Scope#$watch `$watch`} on the parent value only fires if the reference
* to the value has changed. In most cases, this should not be of concern, but can be important
* to know if you one-way bind to an object, and then replace that object in the isolated scope.
* If you now change a property of the object in your parent scope, the change will not be
* propagated to the isolated scope, because the identity of the object on the parent scope
* has not changed. Instead you must assign a new object.
*
* One-way binding is useful if you do not plan to propagate changes to your isolated scope bindings
* back to the parent. However, it does not make this completely impossible.
*
* * `&` or `&attr` - provides a way to execute an expression in the context of the parent scope. If
* no `attr` name is specified then the attribute name is assumed to be the same as the local name.
@@ -245,18 +221,8 @@
* definition: `controller: 'myCtrl as myAlias'`.
*
* When an isolate scope is used for a directive (see above), `bindToController: true` will
* allow a component to have its properties bound to the controller, rather than to scope.
*
* After the controller is instantiated, the initial values of the isolate scope bindings will be bound to the controller
* properties. You can access these bindings once they have been initialized by providing a controller method called
* `$onInit`, which is called after all the controllers on an element have been constructed and had their bindings
* initialized.
*
* <div class="alert alert-warning">
* **Deprecation warning:** although bindings for non-ES6 class controllers are currently
* bound to `this` before the controller constructor is called, this use is now deprecated. Please place initialization
* code that relies upon bindings inside a `$onInit` method on the controller, instead.
* </div>
* allow a component to have its properties bound to the controller, rather than to scope. When the controller
* is instantiated, the initial values of the isolate scope bindings are already available.
*
* It is also possible to set `bindToController` to an object hash with the same format as the `scope` property.
* This will set up the scope bindings to the controller directly. Note that `scope` can still be used
@@ -276,10 +242,10 @@
* * `$element` - Current element
* * `$attrs` - Current attributes object for the element
* * `$transclude` - A transclude linking function pre-bound to the correct transclusion scope:
* `function([scope], cloneLinkingFn, futureParentElement, slotName)`:
* * `scope`: (optional) override the scope.
* * `cloneLinkingFn`: (optional) argument to create clones of the original transcluded content.
* * `futureParentElement` (optional):
* `function([scope], cloneLinkingFn, futureParentElement)`.
* * `scope`: optional argument to override the scope.
* * `cloneLinkingFn`: optional argument to create clones of the original transcluded content.
* * `futureParentElement`:
* * defines the parent to which the `cloneLinkingFn` will add the cloned elements.
* * default: `$element.parent()` resp. `$element` for `transclude:'element'` resp. `transclude:true`.
* * only needed for transcludes that are allowed to contain non html elements (e.g. SVG elements)
@@ -287,34 +253,14 @@
* as those elements need to created and cloned in a special way when they are defined outside their
* usual containers (e.g. like `<svg>`).
* * See also the `directive.templateNamespace` property.
* * `slotName`: (optional) the name of the slot to transclude. If falsy (e.g. `null`, `undefined` or `''`)
* then the default translusion is provided.
* The `$transclude` function also has a method on it, `$transclude.isSlotFilled(slotName)`, which returns
* `true` if the specified slot contains content (i.e. one or more DOM nodes).
*
* The controller can provide the following methods that act as life-cycle hooks:
* * `$onInit` - Called on each controller after all the controllers on an element have been constructed and
* had their bindings initialized (and before the pre &amp; post linking functions for the directives on
* this element). This is a good place to put initialization code for your controller.
*
* #### `require`
* Require another directive and inject its controller as the fourth argument to the linking function. The
* `require` property can be a string, an array or an object:
* * a **string** containing the name of the directive to pass to the linking function
* * an **array** containing the names of directives to pass to the linking function. The argument passed to the
* linking function will be an array of controllers in the same order as the names in the `require` property
* * an **object** whose property values are the names of the directives to pass to the linking function. The argument
* passed to the linking function will also be an object with matching keys, whose values will hold the corresponding
* controllers.
*
* If the `require` property is an object and `bindToController` is truthy, then the required controllers are
* bound to the controller using the keys of the `require` property. This binding occurs after all the controllers
* have been constructed but before `$onInit` is called.
* See the {@link $compileProvider#component} helper for an example of how this can be used.
*
* If no such required directive(s) can be found, or if the directive does not have a controller, then an error is
* raised (unless no link function is specified and the required controllers are not being bound to the directive
* controller, in which case error checking is skipped). The name can be prefixed with:
* `require` takes a string name (or array of strings) of the directive(s) to pass in. If an array is used, the
* injected argument will be an array in corresponding order. If no such directive can be
* found, or if the directive does not have a controller, then an error is raised (unless no link function
* is specified, in which case error checking is skipped). The name can be prefixed with:
*
* * (no prefix) - Locate the required controller on the current element. Throw an error if not found.
* * `?` - Attempt to locate the required controller or pass `null` to the `link` fn if not found.
@@ -407,6 +353,14 @@
* The contents are compiled and provided to the directive as a **transclusion function**. See the
* {@link $compile#transclusion Transclusion} section below.
*
* There are two kinds of transclusion depending upon whether you want to transclude just the contents of the
* directive's element or the entire element:
*
* * `true` - transclude the content (i.e. the child nodes) of the directive's element.
* * `'element'` - transclude the whole of the directive's element including any directives on this
* element that defined at a lower priority than this directive. When used, the `template`
* property is ignored.
*
*
* #### `compile`
*
@@ -536,34 +490,6 @@
* Testing Transclusion Directives}.
* </div>
*
* There are three kinds of transclusion depending upon whether you want to transclude just the contents of the
* directive's element, the entire element or multiple parts of the element contents:
*
* * `true` - transclude the content (i.e. the child nodes) of the directive's element.
* * `'element'` - transclude the whole of the directive's element including any directives on this
* element that defined at a lower priority than this directive. When used, the `template`
* property is ignored.
* * **`{...}` (an object hash):** - map elements of the content onto transclusion "slots" in the template.
*
* **Mult-slot transclusion** is declared by providing an object for the `transclude` property.
*
* This object is a map where the keys are the name of the slot to fill and the value is an element selector
* used to match the HTML to the slot. The element selector should be in normalized form (e.g. `myElement`)
* and will match the standard element variants (e.g. `my-element`, `my:element`, `data-my-element`, etc).
*
* For further information check out the guide on {@link guide/directive#matching-directives Matching Directives}
*
* If the element selector is prefixed with a `?` then that slot is optional.
*
* For example, the transclude object `{ slotA: '?myCustomElement' }` maps `<my-custom-element>` elements to
* the `slotA` slot, which can be accessed via the `$transclude` function or via the {@link ngTransclude} directive.
*
* Slots that are not marked as optional (`?`) will trigger a compile time error if there are no matching elements
* in the transclude content. If you wish to know if an optional slot was filled with content, then you can call
* `$transclude.isSlotFilled(slotName)` on the transclude function passed to the directive's link function and
* injectable into the directive's controller.
*
*
* #### Transclusion Functions
*
* When a directive requests transclusion, the compiler extracts its contents and provides a **transclusion
@@ -584,7 +510,7 @@
* content and the `scope` is the newly created transclusion scope, to which the clone is bound.
*
* <div class="alert alert-info">
* **Best Practice**: Always provide a `cloneFn` (clone attach function) when you call a transclude function
* **Best Practice**: Always provide a `cloneFn` (clone attach function) when you call a translude function
* since you then get a fresh clone of the original DOM and also have access to the new transclusion scope.
* </div>
*
@@ -616,7 +542,7 @@
* </div>
*
* The built-in DOM manipulation directives, such as {@link ngIf}, {@link ngSwitch} and {@link ngRepeat}
* automatically destroy their transcluded clones as necessary so you do not need to worry about this if
* automatically destroy their transluded clones as necessary so you do not need to worry about this if
* you are simply using {@link ngTransclude} to inject the transclusion into your directive.
*
*
@@ -854,9 +780,9 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
var bindingCache = createMap();
function parseIsolateBindings(scope, directiveName, isController) {
var LOCAL_REGEXP = /^\s*([@&<]|=(\*?))(\??)\s*(\w*)\s*$/;
var LOCAL_REGEXP = /^\s*([@&]|=(\*?))(\??)\s*(\w*)\s*$/;
var bindings = {};
var bindings = createMap();
forEach(scope, function(definition, scopeName) {
if (definition in bindingCache) {
@@ -948,11 +874,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
* @param {string|Object} name Name of the directive in camel-case (i.e. <code>ngBind</code> which
* will match as <code>ng-bind</code>), or an object map of directives where the keys are the
* names and the values are the factories.
* @param {Function|Array} directiveFactory An injectable directive factory function. See the
* {@link guide/directive directive guide} and the {@link $compile compile API} for more info.
* @param {Function|Array} directiveFactory An injectable directive factory function. See
* {@link guide/directive} for more info.
* @returns {ng.$compileProvider} Self for chaining.
*/
this.directive = function registerDirective(name, directiveFactory) {
this.directive = function registerDirective(name, directiveFactory) {
assertNotHasOwnProperty(name, 'directive');
if (isString(name)) {
assertValidDirectiveName(name);
@@ -991,131 +917,6 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
return this;
};
/**
* @ngdoc method
* @name $compileProvider#component
* @module ng
* @param {string} name Name of the component in camelCase (i.e. `myComp` which will match `<my-comp>`)
* @param {Object} options Component definition object (a simplified
* {@link ng.$compile#directive-definition-object directive definition object}),
* with the following properties (all optional):
*
* - `controller` `{(string|function()=}` controller constructor function that should be
* associated with newly created scope or the name of a {@link ng.$compile#-controller-
* registered controller} if passed as a string. An empty `noop` function by default.
* - `controllerAs` `{string=}` identifier name for to reference the controller in the component's scope.
* If present, the controller will be published to scope under the `controllerAs` name.
* If not present, this will default to be `$ctrl`.
* - `template` `{string=|function()=}` html template as a string or a function that
* returns an html template as a string which should be used as the contents of this component.
* Empty string by default.
*
* If `template` is a function, then it is {@link auto.$injector#invoke injected} with
* the following locals:
*
* - `$element` - Current element
* - `$attrs` - Current attributes object for the element
*
* - `templateUrl` `{string=|function()=}` path or function that returns a path to an html
* template that should be used as the contents of this component.
*
* If `templateUrl` is a function, then it is {@link auto.$injector#invoke injected} with
* the following locals:
*
* - `$element` - Current element
* - `$attrs` - Current attributes object for the element
*
* - `bindings` `{object=}` defines bindings between DOM attributes and component properties.
* Component properties are always bound to the component controller and not to the scope.
* See {@link ng.$compile#-bindtocontroller- `bindToController`}.
* - `transclude` `{boolean=}` whether {@link $compile#transclusion content transclusion} is enabled.
* Disabled by default.
* - `$...` additional properties to attach to the directive factory function and the controller
* constructor function. (This is used by the component router to annotate)
*
* @returns {ng.$compileProvider} the compile provider itself, for chaining of function calls.
* @description
* Register a **component definition** with the compiler. This is a shorthand for registering a special
* type of directive, which represents a self-contained UI component in your application. Such components
* are always isolated (i.e. `scope: {}`) and are always restricted to elements (i.e. `restrict: 'E'`).
*
* Component definitions are very simple and do not require as much configuration as defining general
* directives. Component definitions usually consist only of a template and a controller backing it.
*
* In order to make the definition easier, components enforce best practices like use of `controllerAs`,
* `bindToController`. They always have **isolate scope** and are restricted to elements.
*
* Here are a few examples of how you would usually define components:
*
* ```js
* var myMod = angular.module(...);
* myMod.component('myComp', {
* template: '<div>My name is {{$ctrl.name}}</div>',
* controller: function() {
* this.name = 'shahar';
* }
* });
*
* myMod.component('myComp', {
* template: '<div>My name is {{$ctrl.name}}</div>',
* bindings: {name: '@'}
* });
*
* myMod.component('myComp', {
* templateUrl: 'views/my-comp.html',
* controller: 'MyCtrl',
* controllerAs: 'ctrl',
* bindings: {name: '@'}
* });
*
* ```
* For more examples, and an in-depth guide, see the {@link guide/component component guide}.
*
* <br />
* See also {@link ng.$compileProvider#directive $compileProvider.directive()}.
*/
this.component = function registerComponent(name, options) {
var controller = options.controller || noop;
function factory($injector) {
function makeInjectable(fn) {
if (isFunction(fn) || isArray(fn)) {
return function(tElement, tAttrs) {
return $injector.invoke(fn, this, {$element: tElement, $attrs: tAttrs});
};
} else {
return fn;
}
}
var template = (!options.template && !options.templateUrl ? '' : options.template);
return {
controller: controller,
controllerAs: identifierForController(options.controller) || options.controllerAs || '$ctrl',
template: makeInjectable(template),
templateUrl: makeInjectable(options.templateUrl),
transclude: options.transclude,
scope: {},
bindToController: options.bindings || {},
restrict: 'E',
require: options.require
};
}
// Copy any annotation properties (starting with $) over to the factory function
// These could be used by libraries such as the new component router
forEach(options, function(val, key) {
if (key.charAt(0) === '$') {
factory[key] = val;
controller[key] = val;
}
});
factory.$inject = ['$injector'];
return this.directive(name, factory);
};
/**
* @ngdoc method
@@ -1213,9 +1014,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
function($injector, $interpolate, $exceptionHandler, $templateRequest, $parse,
$controller, $rootScope, $sce, $animate, $$sanitizeUri) {
var SIMPLE_ATTR_NAME = /^\w/;
var specialAttrHolder = document.createElement('div');
function Attributes(element, attributesToCopy) {
var Attributes = function(element, attributesToCopy) {
if (attributesToCopy) {
var keys = Object.keys(attributesToCopy);
var i, l, key;
@@ -1229,7 +1028,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
}
this.$$element = element;
}
};
Attributes.prototype = {
/**
@@ -1350,11 +1149,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
nodeName = nodeName_(this.$$element);
if ((nodeName === 'a' && (key === 'href' || key === 'xlinkHref')) ||
if ((nodeName === 'a' && key === 'href') ||
(nodeName === 'img' && key === 'src')) {
// sanitize a[href] and img[src] values
this[key] = value = $$sanitizeUri(value, key === 'src');
} else if (nodeName === 'img' && key === 'srcset') {
} else if (nodeName === 'img' && key === 'srcset' && isDefined(value)) {
// sanitize img[srcset] values
var result = "";
@@ -1394,11 +1193,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
if (value === null || isUndefined(value)) {
this.$$element.removeAttr(attrName);
} else {
if (SIMPLE_ATTR_NAME.test(attrName)) {
this.$$element.attr(attrName, value);
} else {
setSpecialAttr(this.$$element[0], attrName, value);
}
this.$$element.attr(attrName, value);
}
}
@@ -1452,18 +1247,6 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
}
};
function setSpecialAttr(element, attrName, value) {
// Attributes names that do not start with letters (such as `(click)`) cannot be set using `setAttribute`
// so we have to jump through some hoops to get such an attribute
// https://github.com/angular/angular.js/pull/13318
specialAttrHolder.innerHTML = "<span " + attrName + ">";
var attributes = specialAttrHolder.firstChild.attributes;
var attribute = attributes[0];
// We have to remove the attribute from its container element before we can add it to the destination element
attributes.removeNamedItem(attribute.name);
attribute.value = value;
element.attributes.setNamedItem(attribute);
}
function safeAddClass($element, className) {
try {
@@ -1510,14 +1293,6 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
safeAddClass($element, isolated ? 'ng-isolate-scope' : 'ng-scope');
} : noop;
compile.$$createComment = function(directiveName, comment) {
var content = '';
if (debugInfoEnabled) {
content = ' ' + (directiveName || '') + ': ' + (comment || '') + ' ';
}
return document.createComment(content);
};
return compile;
//================================
@@ -1612,7 +1387,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
if (!node) {
return 'html';
} else {
return nodeName_(node) !== 'foreignobject' && toString.call(node).match(/SVG/) ? 'svg' : 'html';
return nodeName_(node) !== 'foreignobject' && node.toString().match(/SVG/) ? 'svg' : 'html';
}
}
@@ -1731,7 +1506,8 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
}
function createBoundTranscludeFn(scope, transcludeFn, previousBoundTranscludeFn) {
function boundTranscludeFn(transcludedScope, cloneFn, controllers, futureParentElement, containingScope) {
var boundTranscludeFn = function(transcludedScope, cloneFn, controllers, futureParentElement, containingScope) {
if (!transcludedScope) {
transcludedScope = scope.$new(false, containingScope);
@@ -1743,18 +1519,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
transcludeControllers: controllers,
futureParentElement: futureParentElement
});
}
// We need to attach the transclusion slots onto the `boundTranscludeFn`
// so that they are available inside the `controllersBoundTransclude` function
var boundSlots = boundTranscludeFn.$$slots = createMap();
for (var slotName in transcludeFn.$$slots) {
if (transcludeFn.$$slots[slotName]) {
boundSlots[slotName] = createBoundTranscludeFn(scope, transcludeFn.$$slots[slotName], previousBoundTranscludeFn);
} else {
boundSlots[slotName] = null;
}
}
};
return boundTranscludeFn;
}
@@ -1908,41 +1673,12 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
* @returns {Function}
*/
function groupElementsLinkFnWrapper(linkFn, attrStart, attrEnd) {
return function groupedElementsLink(scope, element, attrs, controllers, transcludeFn) {
return function(scope, element, attrs, controllers, transcludeFn) {
element = groupScan(element[0], attrStart, attrEnd);
return linkFn(scope, element, attrs, controllers, transcludeFn);
};
}
/**
* A function generator that is used to support both eager and lazy compilation
* linking function.
* @param eager
* @param $compileNodes
* @param transcludeFn
* @param maxPriority
* @param ignoreDirective
* @param previousCompileContext
* @returns {Function}
*/
function compilationGenerator(eager, $compileNodes, transcludeFn, maxPriority, ignoreDirective, previousCompileContext) {
var compiled;
if (eager) {
return compile($compileNodes, transcludeFn, maxPriority, ignoreDirective, previousCompileContext);
}
return function lazyCompilation() {
if (!compiled) {
compiled = compile($compileNodes, transcludeFn, maxPriority, ignoreDirective, previousCompileContext);
// Null out all of these references in order to make them eligible for garbage collection
// since this is a potentially long lived closure
$compileNodes = transcludeFn = previousCompileContext = null;
}
return compiled.apply(this, arguments);
};
}
/**
* Once the directives have been collected, their compile functions are executed. This method
* is responsible for inlining directive templates as well as terminating the application
@@ -1987,8 +1723,6 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
replaceDirective = originalReplaceDirective,
childTranscludeFn = transcludeFn,
linkFn,
didScanForMultipleTransclusion = false,
mightHaveMultipleTransclusionError = false,
directiveValue;
// executes all directives on the current element
@@ -2031,27 +1765,6 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
directiveName = directive.name;
// If we encounter a condition that can result in transclusion on the directive,
// then scan ahead in the remaining directives for others that may cause a multiple
// transclusion error to be thrown during the compilation process. If a matching directive
// is found, then we know that when we encounter a transcluded directive, we need to eagerly
// compile the `transclude` function rather than doing it lazily in order to throw
// exceptions at the correct time
if (!didScanForMultipleTransclusion && ((directive.replace && (directive.templateUrl || directive.template))
|| (directive.transclude && !directive.$$tlb))) {
var candidateDirective;
for (var scanningIndex = i + 1; candidateDirective = directives[scanningIndex++];) {
if ((candidateDirective.transclude && !candidateDirective.$$tlb)
|| (candidateDirective.replace && (candidateDirective.templateUrl || candidateDirective.template))) {
mightHaveMultipleTransclusionError = true;
break;
}
}
didScanForMultipleTransclusion = true;
}
if (!directive.templateUrl && directive.controller) {
directiveValue = directive.controller;
controllerDirectives = controllerDirectives || createMap();
@@ -2076,11 +1789,12 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
terminalPriority = directive.priority;
$template = $compileNode;
$compileNode = templateAttrs.$$element =
jqLite(compile.$$createComment(directiveName, templateAttrs[directiveName]));
jqLite(document.createComment(' ' + directiveName + ': ' +
templateAttrs[directiveName] + ' '));
compileNode = $compileNode[0];
replaceWith(jqCollection, sliceArgs($template), compileNode);
childTranscludeFn = compilationGenerator(mightHaveMultipleTransclusionError, $template, transcludeFn, terminalPriority,
childTranscludeFn = compile($template, transcludeFn, terminalPriority,
replaceDirective && replaceDirective.name, {
// Don't pass in:
// - controllerDirectives - otherwise we'll create duplicates controllers
@@ -2092,69 +1806,10 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
nonTlbTranscludeDirective: nonTlbTranscludeDirective
});
} else {
var slots = createMap();
$template = jqLite(jqLiteClone(compileNode)).contents();
if (isObject(directiveValue)) {
// We have transclusion slots,
// collect them up, compile them and store their transclusion functions
$template = [];
var slotMap = createMap();
var filledSlots = createMap();
// Parse the element selectors
forEach(directiveValue, function(elementSelector, slotName) {
// If an element selector starts with a ? then it is optional
var optional = (elementSelector.charAt(0) === '?');
elementSelector = optional ? elementSelector.substring(1) : elementSelector;
slotMap[elementSelector] = slotName;
// We explicitly assign `null` since this implies that a slot was defined but not filled.
// Later when calling boundTransclusion functions with a slot name we only error if the
// slot is `undefined`
slots[slotName] = null;
// filledSlots contains `true` for all slots that are either optional or have been
// filled. This is used to check that we have not missed any required slots
filledSlots[slotName] = optional;
});
// Add the matching elements into their slot
forEach($compileNode.contents(), function(node) {
var slotName = slotMap[directiveNormalize(nodeName_(node))];
if (slotName) {
filledSlots[slotName] = true;
slots[slotName] = slots[slotName] || [];
slots[slotName].push(node);
} else {
$template.push(node);
}
});
// Check for required slots that were not filled
forEach(filledSlots, function(filled, slotName) {
if (!filled) {
throw $compileMinErr('reqslot', 'Required transclusion slot `{0}` was not filled.', slotName);
}
});
for (var slotName in slots) {
if (slots[slotName]) {
// Only define a transclusion function if the slot was filled
slots[slotName] = compilationGenerator(mightHaveMultipleTransclusionError, slots[slotName], transcludeFn);
}
}
}
$compileNode.empty(); // clear contents
childTranscludeFn = compilationGenerator(mightHaveMultipleTransclusionError, $template, transcludeFn, undefined,
childTranscludeFn = compile($template, transcludeFn, undefined,
undefined, { needsNewScope: directive.$$isolateScope || directive.$$newScope});
childTranscludeFn.$$slots = slots;
}
}
@@ -2282,8 +1937,76 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
}
}
function getControllers(directiveName, require, $element, elementControllers) {
var value;
if (isString(require)) {
var match = require.match(REQUIRE_PREFIX_REGEXP);
var name = require.substring(match[0].length);
var inheritType = match[1] || match[3];
var optional = match[2] === '?';
//If only parents then start at the parent element
if (inheritType === '^^') {
$element = $element.parent();
//Otherwise attempt getting the controller from elementControllers in case
//the element is transcluded (and has no data) and to avoid .data if possible
} else {
value = elementControllers && elementControllers[name];
value = value && value.instance;
}
if (!value) {
var dataName = '$' + name + 'Controller';
value = inheritType ? $element.inheritedData(dataName) : $element.data(dataName);
}
if (!value && !optional) {
throw $compileMinErr('ctreq',
"Controller '{0}', required by directive '{1}', can't be found!",
name, directiveName);
}
} else if (isArray(require)) {
value = [];
for (var i = 0, ii = require.length; i < ii; i++) {
value[i] = getControllers(directiveName, require[i], $element, elementControllers);
}
}
return value || null;
}
function setupControllers($element, attrs, transcludeFn, controllerDirectives, isolateScope, scope) {
var elementControllers = createMap();
for (var controllerKey in controllerDirectives) {
var directive = controllerDirectives[controllerKey];
var locals = {
$scope: directive === newIsolateScopeDirective || directive.$$isolateScope ? isolateScope : scope,
$element: $element,
$attrs: attrs,
$transclude: transcludeFn
};
var controller = directive.controller;
if (controller == '@') {
controller = attrs[directive.name];
}
var controllerInstance = $controller(controller, locals, true, directive.controllerAs);
// For directives with element transclusion the element is a comment.
// In this case .data will not attach any data.
// Instead, we save the controllers for the element in a local hash and attach to .data
// later, once we have the actual element.
elementControllers[directive.name] = controllerInstance;
$element.data('$' + directive.name + 'Controller', controllerInstance.instance);
}
return elementControllers;
}
function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) {
var i, ii, linkFn, isolateScope, controllerScope, elementControllers, transcludeFn, $element,
var linkFn, isolateScope, controllerScope, elementControllers, transcludeFn, $element,
attrs, removeScopeBindingWatches, removeControllerBindingWatches;
if (compileNode === linkNode) {
@@ -2306,14 +2029,10 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
// is later passed as `parentBoundTranscludeFn` to `publicLinkFn`
transcludeFn = controllersBoundTransclude;
transcludeFn.$$boundTransclude = boundTranscludeFn;
// expose the slots on the `$transclude` function
transcludeFn.isSlotFilled = function(slotName) {
return !!boundTranscludeFn.$$slots[slotName];
};
}
if (controllerDirectives) {
elementControllers = setupControllers($element, attrs, transcludeFn, controllerDirectives, isolateScope, scope, newIsolateScopeDirective);
elementControllers = setupControllers($element, attrs, transcludeFn, controllerDirectives, isolateScope, scope);
}
if (newIsolateScopeDirective) {
@@ -2354,21 +2073,6 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
}
}
// Bind the required controllers to the controller, if `require` is an object and `bindToController` is truthy
forEach(controllerDirectives, function(controllerDirective, name) {
var require = controllerDirective.require;
if (controllerDirective.bindToController && !isArray(require) && isObject(require)) {
extend(elementControllers[name].instance, getControllers(name, require, $element, elementControllers));
}
});
// Trigger the `$onInit` method on all controllers that have one
forEach(elementControllers, function(controller) {
if (isFunction(controller.instance.$onInit)) {
controller.instance.$onInit();
}
});
// PRELINKING
for (i = 0, ii = preLinkFns.length; i < ii; i++) {
linkFn = preLinkFns[i];
@@ -2404,11 +2108,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
// This is the function that is injected as `$transclude`.
// Note: all arguments are optional!
function controllersBoundTransclude(scope, cloneAttachFn, futureParentElement, slotName) {
function controllersBoundTransclude(scope, cloneAttachFn, futureParentElement) {
var transcludeControllers;
// No scope passed in:
if (!isScope(scope)) {
slotName = futureParentElement;
futureParentElement = cloneAttachFn;
cloneAttachFn = scope;
scope = undefined;
@@ -2420,99 +2124,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
if (!futureParentElement) {
futureParentElement = hasElementTranscludeDirective ? $element.parent() : $element;
}
if (slotName) {
// slotTranscludeFn can be one of three things:
// * a transclude function - a filled slot
// * `null` - an optional slot that was not filled
// * `undefined` - a slot that was not declared (i.e. invalid)
var slotTranscludeFn = boundTranscludeFn.$$slots[slotName];
if (slotTranscludeFn) {
return slotTranscludeFn(scope, cloneAttachFn, transcludeControllers, futureParentElement, scopeToChild);
} else if (isUndefined(slotTranscludeFn)) {
throw $compileMinErr('noslot',
'No parent directive that requires a transclusion with slot name "{0}". ' +
'Element: {1}',
slotName, startingTag($element));
}
} else {
return boundTranscludeFn(scope, cloneAttachFn, transcludeControllers, futureParentElement, scopeToChild);
}
return boundTranscludeFn(scope, cloneAttachFn, transcludeControllers, futureParentElement, scopeToChild);
}
}
}
function getControllers(directiveName, require, $element, elementControllers) {
var value;
if (isString(require)) {
var match = require.match(REQUIRE_PREFIX_REGEXP);
var name = require.substring(match[0].length);
var inheritType = match[1] || match[3];
var optional = match[2] === '?';
//If only parents then start at the parent element
if (inheritType === '^^') {
$element = $element.parent();
//Otherwise attempt getting the controller from elementControllers in case
//the element is transcluded (and has no data) and to avoid .data if possible
} else {
value = elementControllers && elementControllers[name];
value = value && value.instance;
}
if (!value) {
var dataName = '$' + name + 'Controller';
value = inheritType ? $element.inheritedData(dataName) : $element.data(dataName);
}
if (!value && !optional) {
throw $compileMinErr('ctreq',
"Controller '{0}', required by directive '{1}', can't be found!",
name, directiveName);
}
} else if (isArray(require)) {
value = [];
for (var i = 0, ii = require.length; i < ii; i++) {
value[i] = getControllers(directiveName, require[i], $element, elementControllers);
}
} else if (isObject(require)) {
value = {};
forEach(require, function(controller, property) {
value[property] = getControllers(directiveName, controller, $element, elementControllers);
});
}
return value || null;
}
function setupControllers($element, attrs, transcludeFn, controllerDirectives, isolateScope, scope, newIsolateScopeDirective) {
var elementControllers = createMap();
for (var controllerKey in controllerDirectives) {
var directive = controllerDirectives[controllerKey];
var locals = {
$scope: directive === newIsolateScopeDirective || directive.$$isolateScope ? isolateScope : scope,
$element: $element,
$attrs: attrs,
$transclude: transcludeFn
};
var controller = directive.controller;
if (controller == '@') {
controller = attrs[directive.name];
}
var controllerInstance = $controller(controller, locals, true, directive.controllerAs);
// For directives with element transclusion the element is a comment.
// In this case .data will not attach any data.
// Instead, we save the controllers for the element in a local hash and attach to .data
// later, once we have the actual element.
elementControllers[directive.name] = controllerInstance;
$element.data('$' + directive.name + 'Controller', controllerInstance.instance);
}
return elementControllers;
}
// Depending upon the context in which a directive finds itself it might need to have a new isolated
// or child scope created. For instance:
// * if the directive has been pulled into a template because another directive with a higher priority
@@ -2947,14 +2563,9 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
parent.replaceChild(newNode, firstElementToRemove);
}
// Append all the `elementsToRemove` to a fragment. This will...
// - remove them from the DOM
// - allow them to still be traversed with .nextSibling
// - allow a single fragment.qSA to fetch all elements being removed
// TODO(perf): what's this document fragment for? is it needed? can we at least reuse it?
var fragment = document.createDocumentFragment();
for (i = 0; i < removeCount; i++) {
fragment.appendChild(elementsToRemove[i]);
}
fragment.appendChild(firstElementToRemove);
if (jqLite.hasData(firstElementToRemove)) {
// Copy over user data (that includes Angular's $scope etc.). Don't copy private
@@ -2962,18 +2573,31 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
// event listeners (which is the main use of private data) wouldn't work anyway.
jqLite.data(newNode, jqLite.data(firstElementToRemove));
// Remove $destroy event listeners from `firstElementToRemove`
jqLite(firstElementToRemove).off('$destroy');
// Remove data of the replaced element. We cannot just call .remove()
// on the element it since that would deallocate scope that is needed
// for the new node. Instead, remove the data "manually".
if (!jQuery) {
delete jqLite.cache[firstElementToRemove[jqLite.expando]];
} else {
// jQuery 2.x doesn't expose the data storage. Use jQuery.cleanData to clean up after
// the replaced element. The cleanData version monkey-patched by Angular would cause
// the scope to be trashed and we do need the very same scope to work with the new
// element. However, we cannot just cache the non-patched version and use it here as
// that would break if another library patches the method after Angular does (one
// example is jQuery UI). Instead, set a flag indicating scope destroying should be
// skipped this one time.
skipDestroyOnNextJQueryCleanData = true;
jQuery.cleanData([firstElementToRemove]);
}
}
// Cleanup any data/listeners on the elements and children.
// This includes invoking the $destroy event on any elements with listeners.
jqLite.cleanData(fragment.querySelectorAll('*'));
// Update the jqLite collection to only contain the `newNode`
for (i = 1; i < removeCount; i++) {
delete elementsToRemove[i];
for (var k = 1, kk = elementsToRemove.length; k < kk; k++) {
var element = elementsToRemove[k];
jqLite(element).remove(); // must do this way to clean up expando
fragment.appendChild(element);
delete elementsToRemove[k];
}
elementsToRemove[0] = newNode;
elementsToRemove.length = 1;
}
@@ -2997,12 +2621,12 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
// only occurs for isolate scopes and new scopes with controllerAs.
function initializeDirectiveBindings(scope, attrs, destination, bindings, directive) {
var removeWatchCollection = [];
forEach(bindings, function initializeBinding(definition, scopeName) {
forEach(bindings, function(definition, scopeName) {
var attrName = definition.attrName,
optional = definition.optional,
mode = definition.mode, // @, =, or &
lastValue,
parentGet, parentSet, compare, removeWatch;
parentGet, parentSet, compare;
switch (mode) {
@@ -3039,7 +2663,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
if (parentGet.literal) {
compare = equals;
} else {
compare = function simpleCompare(a, b) { return a === b || (a !== a && b !== b); };
compare = function(a, b) { return a === b || (a !== a && b !== b); };
}
parentSet = parentGet.assign || function() {
// reset the change, or we will throw this exception on every $digest
@@ -3063,6 +2687,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
return lastValue = parentValue;
};
parentValueWatch.$stateful = true;
var removeWatch;
if (definition.collection) {
removeWatch = scope.$watchCollection(attrs[attrName], parentValueWatch);
} else {
@@ -3071,24 +2696,6 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
removeWatchCollection.push(removeWatch);
break;
case '<':
if (!hasOwnProperty.call(attrs, attrName)) {
if (optional) break;
attrs[attrName] = void 0;
}
if (optional && !attrs[attrName]) break;
parentGet = $parse(attrs[attrName]);
destination[scopeName] = parentGet(scope);
removeWatch = scope.$watch(parentGet, function parentValueWatchAction(newParentValue) {
destination[scopeName] = newParentValue;
}, parentGet.literal);
removeWatchCollection.push(removeWatch);
break;
case '&':
// Don't assign Object.prototype method to scope
parentGet = attrs.hasOwnProperty(attrName) ? $parse(attrs[attrName]) : noop;
+2 -11
View File
@@ -27,15 +27,6 @@ function $ControllerProvider() {
var controllers = {},
globals = false;
/**
* @ngdoc method
* @name $controllerProvider#has
* @param {string} name Controller name to check.
*/
this.has = function(name) {
return controllers.hasOwnProperty(name);
};
/**
* @ngdoc method
* @name $controllerProvider#register
@@ -92,7 +83,7 @@ function $ControllerProvider() {
* It's just a simple call to {@link auto.$injector $injector}, but extracted into
* a service, so that one can override this service with [BC version](https://gist.github.com/1649788).
*/
return function $controller(expression, locals, later, ident) {
return function(expression, locals, later, ident) {
// PRIVATE API:
// param `later` --- indicates that the controller's constructor is invoked at a later time.
// If true, $controller will allocate the object with the correct
@@ -143,7 +134,7 @@ function $ControllerProvider() {
}
var instantiate;
return instantiate = extend(function $controllerInit() {
return instantiate = extend(function() {
var result = $injector.invoke(expression, instance, locals, constructor);
if (result !== instance && (isObject(result) || isFunction(result))) {
instance = result;
+1 -1
View File
@@ -127,7 +127,7 @@ function FormController(element, attrs, $scope, $animate, $interpolate) {
*
* However, if the method is used programmatically, for example by adding dynamically created controls,
* or controls that have been previously removed without destroying their corresponding DOM element,
* it's the developers responsibility to make sure the current state propagates to the parent form.
* it's the developers responsiblity to make sure the current state propagates to the parent form.
*
* 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.
+26 -22
View File
@@ -9,8 +9,8 @@
ngModelMinErr: false,
*/
// Regex code was initially obtained from SO prior to modification: https://stackoverflow.com/questions/3143070/javascript-regex-iso-datetime#answer-3143231
var ISO_DATE_REGEXP = /^\d{4,}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+(?:[+-][0-2]\d:[0-5]\d|Z)$/;
// Regex code is obtained from SO: https://stackoverflow.com/questions/3143070/javascript-regex-iso-datetime#answer-3143231
var ISO_DATE_REGEXP = /\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z)/;
// See valid URLs in RFC3987 (http://tools.ietf.org/html/rfc3987)
// Note: We are being more lenient, because browsers are too.
// 1. Scheme
@@ -26,10 +26,10 @@ var ISO_DATE_REGEXP = /^\d{4,}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+(?:[+-
var URL_REGEXP = /^[a-z][a-z\d.+-]*:\/*(?:[^:@]+(?::[^@]+)?@)?(?:[^\s:/?#]+|\[[a-f\d:]+\])(?::\d+)?(?:\/[^?#]*)?(?:\?[^#]*)?(?:#.*)?$/i;
var EMAIL_REGEXP = /^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i;
var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))([eE][+-]?\d+)?\s*$/;
var DATE_REGEXP = /^(\d{4,})-(\d{2})-(\d{2})$/;
var DATETIMELOCAL_REGEXP = /^(\d{4,})-(\d\d)-(\d\d)T(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/;
var WEEK_REGEXP = /^(\d{4,})-W(\d\d)$/;
var MONTH_REGEXP = /^(\d{4,})-(\d\d)$/;
var DATE_REGEXP = /^(\d{4})-(\d{2})-(\d{2})$/;
var DATETIMELOCAL_REGEXP = /^(\d{4})-(\d\d)-(\d\d)T(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/;
var WEEK_REGEXP = /^(\d{4})-W(\d\d)$/;
var MONTH_REGEXP = /^(\d{4})-(\d\d)$/;
var TIME_REGEXP = /^(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/;
var PARTIAL_VALIDATION_EVENTS = 'keydown wheel mousedown';
@@ -62,8 +62,8 @@ var inputType = {
* @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
* that contains the regular expression body that will be converted to a regular expression
* as in the ngPattern directive.
* @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
* does not match a RegExp found by evaluating the Angular expression given in the attribute value.
* @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
* a RegExp found by evaluating the Angular expression given in the attribute value.
* If the expression evaluates to a RegExp object, then this is used directly.
* If the expression evaluates to a string, then it will be converted to a RegExp
* after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
@@ -350,7 +350,7 @@ var inputType = {
*
* @description
* Input with time validation and transformation. In browsers that do not yet support
* the HTML5 time input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
* the HTML5 date input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
* local time format (HH:mm:ss), for example: `14:57:00`. Model must be a Date object. This binding will always output a
* Date object to the model of January 1, 1970, or local date `new Date(1970, 0, 1, HH, mm, ss)`.
*
@@ -393,7 +393,7 @@ var inputType = {
}]);
</script>
<form name="myForm" ng-controller="DateController as dateCtrl">
<label for="exampleInput">Pick a between 8am and 5pm:</label>
<label for="exampleInput">Pick a time between 8am and 5pm:</label>
<input type="time" id="exampleInput" name="input" ng-model="example.value"
placeholder="HH:mm:ss" min="08:00:00" max="17:00:00" required />
<div role="alert">
@@ -697,8 +697,8 @@ var inputType = {
* @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
* that contains the regular expression body that will be converted to a regular expression
* as in the ngPattern directive.
* @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
* does not match a RegExp found by evaluating the Angular expression given in the attribute value.
* @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
* a RegExp found by evaluating the Angular expression given in the attribute value.
* If the expression evaluates to a RegExp object, then this is used directly.
* If the expression evaluates to a string, then it will be converted to a RegExp
* after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
@@ -795,8 +795,8 @@ var inputType = {
* @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
* that contains the regular expression body that will be converted to a regular expression
* as in the ngPattern directive.
* @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
* does not match a RegExp found by evaluating the Angular expression given in the attribute value.
* @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
* a RegExp found by evaluating the Angular expression given in the attribute value.
* If the expression evaluates to a RegExp object, then this is used directly.
* If the expression evaluates to a string, then it will be converted to a RegExp
* after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
@@ -894,8 +894,8 @@ var inputType = {
* @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
* that contains the regular expression body that will be converted to a regular expression
* as in the ngPattern directive.
* @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
* does not match a RegExp found by evaluating the Angular expression given in the attribute value.
* @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
* a RegExp found by evaluating the Angular expression given in the attribute value.
* If the expression evaluates to a RegExp object, then this is used directly.
* If the expression evaluates to a string, then it will be converted to a RegExp
* after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
@@ -1114,7 +1114,7 @@ function baseInputType(scope, element, attr, ctrl, $sniffer, $browser) {
if (!$sniffer.android) {
var composing = false;
element.on('compositionstart', function() {
element.on('compositionstart', function(data) {
composing = true;
});
@@ -1375,7 +1375,11 @@ function badInputChecker(scope, element, attr, ctrl) {
if (nativeValidation) {
ctrl.$parsers.push(function(value) {
var validity = element.prop(VALIDITY_STATE_PROPERTY) || {};
return validity.badInput || validity.typeMismatch ? undefined : value;
// Detect bug in FF35 for input[email] (https://bugzilla.mozilla.org/show_bug.cgi?id=1064430):
// - also sets validity.badInput (should only be validity.typeMismatch).
// - see http://www.whatwg.org/specs/web-apps/current-work/multipage/forms.html#e-mail-state-(type=email)
// - can ignore this case as we can still read out the erroneous email...
return validity.badInput && !validity.typeMismatch ? undefined : value;
});
}
}
@@ -1547,8 +1551,8 @@ function checkboxInputType(scope, element, attr, ctrl, $sniffer, $browser, $filt
* @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
* maxlength. Setting the attribute to a negative or non-numeric value, allows view values of any
* length.
* @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
* does not match a RegExp found by evaluating the Angular expression given in the attribute value.
* @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
* a RegExp found by evaluating the Angular expression given in the attribute value.
* If the expression evaluates to a RegExp object, then this is used directly.
* If the expression evaluates to a string, then it will be converted to a RegExp
* after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
@@ -1586,8 +1590,8 @@ function checkboxInputType(scope, element, attr, ctrl, $sniffer, $browser, $filt
* @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
* maxlength. Setting the attribute to a negative or non-numeric value, allows view values of any
* length.
* @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
* value does not match a RegExp found by evaluating the Angular expression given in the attribute value.
* @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
* a RegExp found by evaluating the Angular expression given in the attribute value.
* If the expression evaluates to a RegExp object, then this is used directly.
* If the expression evaluates to a string, then it will be converted to a RegExp
* after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
+6 -5
View File
@@ -188,8 +188,9 @@ var ngBindHtmlDirective = ['$sce', '$parse', '$compile', function($sce, $parse,
restrict: 'A',
compile: function ngBindHtmlCompile(tElement, tAttrs) {
var ngBindHtmlGetter = $parse(tAttrs.ngBindHtml);
var ngBindHtmlWatch = $parse(tAttrs.ngBindHtml, function getStringValue(value) {
return (value || '').toString();
var ngBindHtmlWatch = $parse(tAttrs.ngBindHtml, function sceValueOf(val) {
// Unwrap the value to compare the actual inner safe value, not the wrapper object.
return $sce.valueOf(val);
});
$compile.$$addBindingClass(tElement);
@@ -197,9 +198,9 @@ var ngBindHtmlDirective = ['$sce', '$parse', '$compile', function($sce, $parse,
$compile.$$addBindingInfo(element, attr.ngBindHtml);
scope.$watch(ngBindHtmlWatch, function ngBindHtmlWatchAction() {
// we re-evaluate the expr because we want a TrustedValueHolderType
// for $sce, not a string
element.html($sce.getTrustedHtml(ngBindHtmlGetter(scope)) || '');
// The watched value is the unwrapped value. To avoid re-escaping, use the direct getter.
var value = ngBindHtmlGetter(scope);
element.html($sce.getTrustedHtml(value) || '');
});
};
}
+8 -5
View File
@@ -78,7 +78,11 @@ function classDirective(name, selector) {
updateClasses(oldClasses, newClasses);
}
}
oldVal = shallowCopy(newVal);
if (isArray(newVal)) {
oldVal = newVal.map(function(v) { return shallowCopy(v); });
} else {
oldVal = shallowCopy(newVal);
}
}
}
};
@@ -148,10 +152,9 @@ function classDirective(name, selector) {
* new classes added.
*
* @animations
* | Animation | Occurs |
* |----------------------------------|-------------------------------------|
* | {@link ng.$animate#addClass addClass} | just before the class is applied to the element |
* | {@link ng.$animate#removeClass removeClass} | just before the class is removed from the element |
* **add** - happens just before the class is applied to the elements
*
* **remove** - happens just before the class is removed from the element
*
* @element ANY
* @param {expression} ngClass {@link guide/expression Expression} to eval. The result
+2 -2
View File
@@ -47,7 +47,7 @@
*
* * no-inline-style: this stops Angular from injecting CSS styles into the DOM
*
* * no-unsafe-eval: this stops Angular from optimizing $parse with unsafe eval of strings
* * no-unsafe-eval: this stops Angular from optimising $parse with unsafe eval of strings
*
* You can use these values in the following combinations:
*
@@ -64,7 +64,7 @@
* inline styles. E.g. `<body ng-csp="no-unsafe-eval">`.
*
* * Specifying only `no-inline-style` tells Angular that we must not inject styles, but that we can
* run eval - no automatic check for unsafe eval will occur. E.g. `<body ng-csp="no-inline-style">`
* run eval - no automcatic check for unsafe eval will occur. E.g. `<body ng-csp="no-inline-style">`
*
* * Specifying both `no-unsafe-eval` and `no-inline-style` tells Angular that we must not inject
* styles nor use eval, which is the same as an empty: ng-csp.
+4 -6
View File
@@ -34,10 +34,8 @@
* and `leave` effects.
*
* @animations
* | Animation | Occurs |
* |----------------------------------|-------------------------------------|
* | {@link ng.$animate#enter enter} | just after the `ngIf` contents change and a new DOM element is created and injected into the `ngIf` container |
* | {@link ng.$animate#leave leave} | just before the `ngIf` contents are removed from the DOM |
* enter - happens just after the `ngIf` contents change and a new DOM element is created and injected into the `ngIf` container
* leave - happens just before the `ngIf` contents are removed from the DOM
*
* @element ANY
* @scope
@@ -78,7 +76,7 @@
</file>
</example>
*/
var ngIfDirective = ['$animate', '$compile', function($animate, $compile) {
var ngIfDirective = ['$animate', function($animate) {
return {
multiElement: true,
transclude: 'element',
@@ -94,7 +92,7 @@ var ngIfDirective = ['$animate', '$compile', function($animate, $compile) {
if (!childScope) {
$transclude(function(clone, newScope) {
childScope = newScope;
clone[clone.length++] = $compile.$$createComment('end ngIf', $attr.ngIf);
clone[clone.length++] = document.createComment(' end ngIf: ' + $attr.ngIf + ' ');
// Note: We only need the first/last node of the cloned nodes.
// However, we need to keep the reference to the jqlite wrapper as it might be changed later
// by a directive with templateUrl when its template arrives.
+3 -5
View File
@@ -23,10 +23,8 @@
* access on some browsers.
*
* @animations
* | Animation | Occurs |
* |----------------------------------|-------------------------------------|
* | {@link ng.$animate#enter enter} | when the expression changes, on the new include |
* | {@link ng.$animate#leave leave} | when the expression changes, on the old include |
* enter - animation is used to bring new content into the browser.
* leave - animation is used to animate existing content away.
*
* The enter and leave animation occur concurrently.
*
@@ -287,7 +285,7 @@ var ngIncludeFillContentDirective = ['$compile',
priority: -400,
require: 'ngInclude',
link: function(scope, $element, $attr, ctrl) {
if (toString.call($element[0]).match(/SVG/)) {
if (/SVG/.test($element[0].toString())) {
// WebKit: https://bugs.webkit.org/show_bug.cgi?id=135698 --- SVG elements do not
// support innerHTML, so detect this here and try to generate the contents
// specially.
+9 -28
View File
@@ -14,9 +14,7 @@ var VALID_CLASS = 'ng-valid',
DIRTY_CLASS = 'ng-dirty',
UNTOUCHED_CLASS = 'ng-untouched',
TOUCHED_CLASS = 'ng-touched',
PENDING_CLASS = 'ng-pending',
EMPTY_CLASS = 'ng-empty',
NOT_EMPTY_CLASS = 'ng-not-empty';
PENDING_CLASS = 'ng-pending';
var ngModelMinErr = minErr('ngModel');
@@ -265,9 +263,9 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
};
ngModelSet = function($scope, newValue) {
if (isFunction(parsedNgModel($scope))) {
invokeModelSetter($scope, {$$$p: newValue});
invokeModelSetter($scope, {$$$p: ctrl.$modelValue});
} else {
parsedNgModelAssign($scope, newValue);
parsedNgModelAssign($scope, ctrl.$modelValue);
}
};
} else if (!parsedNgModel.assign) {
@@ -292,7 +290,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
* the `$viewValue` are different from last time.
*
* Since `ng-model` does not do a deep watch, `$render()` is only invoked if the values of
* `$modelValue` and `$viewValue` are actually different from their previous values. If `$modelValue`
* `$modelValue` and `$viewValue` are actually different from their previous value. If `$modelValue`
* or `$viewValue` are objects (rather than a string or number) then `$render()` will not be
* invoked if you only change a property on the objects.
*/
@@ -320,17 +318,6 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
return isUndefined(value) || value === '' || value === null || value !== value;
};
this.$$updateEmptyClasses = function(value) {
if (ctrl.$isEmpty(value)) {
$animate.removeClass($element, NOT_EMPTY_CLASS);
$animate.addClass($element, EMPTY_CLASS);
} else {
$animate.removeClass($element, EMPTY_CLASS);
$animate.addClass($element, NOT_EMPTY_CLASS);
}
};
var currentValidationRunId = 0;
/**
@@ -644,7 +631,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
setValidity(name, undefined);
validatorPromises.push(promise.then(function() {
setValidity(name, true);
}, function() {
}, function(error) {
allValid = false;
setValidity(name, false);
}));
@@ -694,7 +681,6 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
if (ctrl.$$lastCommittedViewValue === viewValue && (viewValue !== '' || !ctrl.$$hasNativeValidators)) {
return;
}
ctrl.$$updateEmptyClasses(viewValue);
ctrl.$$lastCommittedViewValue = viewValue;
// change to dirty
@@ -793,7 +779,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
* However, custom controls might also pass objects to this method. In this case, we should make
* a copy of the object before passing it to `$setViewValue`. This is because `ngModel` does not
* perform a deep watch of objects, it only looks for a change of identity. If you only change
* the property of the object then ngModel will not realize that the object has changed and
* the property of the object then ngModel will not realise that the object has changed and
* will not invoke the `$parsers` and `$validators` pipelines. For this reason, you should
* not change properties of the copy once it has been passed to `$setViewValue`.
* Otherwise you may cause the model value on the scope to change incorrectly.
@@ -877,7 +863,6 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
viewValue = formatters[idx](viewValue);
}
if (ctrl.$viewValue !== viewValue) {
ctrl.$$updateEmptyClasses(viewValue);
ctrl.$viewValue = ctrl.$$lastCommittedViewValue = viewValue;
ctrl.$render();
@@ -908,8 +893,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
* require.
* - Providing validation behavior (i.e. required, number, email, url).
* - Keeping the state of the control (valid/invalid, dirty/pristine, touched/untouched, validation errors).
* - Setting related css classes on the element (`ng-valid`, `ng-invalid`, `ng-dirty`, `ng-pristine`, `ng-touched`,
* `ng-untouched`, `ng-empty`, `ng-not-empty`) including animations.
* - Setting related css classes on the element (`ng-valid`, `ng-invalid`, `ng-dirty`, `ng-pristine`, `ng-touched`, `ng-untouched`) including animations.
* - Registering the control with its parent {@link ng.directive:form form}.
*
* Note: `ngModel` will try to bind to the property given by evaluating the expression on the
@@ -966,16 +950,13 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
* - `ng-touched`: the control has been blurred
* - `ng-untouched`: the control hasn't been blurred
* - `ng-pending`: any `$asyncValidators` are unfulfilled
* - `ng-empty`: the view does not contain a value or the value is deemed "empty", as defined
* by the {@link ngModel.NgModelController#$isEmpty} method
* - `ng-not-empty`: the view contains a non-empty value
*
* Keep in mind that ngAnimate can detect each of these classes when added and removed.
*
* ## Animation Hooks
*
* Animations within models are triggered when any of the associated CSS classes are added and removed
* on the input element which is attached to the model. These classes include: `.ng-pristine`, `.ng-dirty`,
* on the input element which is attached to the model. These classes are: `.ng-pristine`, `.ng-dirty`,
* `.ng-invalid` and `.ng-valid` as well as any other validations that are performed on the model itself.
* The animations that are triggered within ngModel are similar to how they work in ngClass and
* animations can be hooked into using CSS transitions, keyframes as well as JS animations.
@@ -1118,7 +1099,7 @@ var ngModelDirective = ['$rootScope', function($rootScope) {
});
}
element.on('blur', function() {
element.on('blur', function(ev) {
if (modelCtrl.$touched) return;
if ($rootScope.$$phase) {
+9 -5
View File
@@ -342,8 +342,8 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
var key = (optionValues === optionValuesKeys) ? index : optionValuesKeys[index];
var value = optionValues[key];
var locals = getLocals(value, key);
var selectValue = getTrackByValueFn(value, locals);
var locals = getLocals(optionValues[key], key);
var selectValue = getTrackByValueFn(optionValues[key], locals);
watchedArray.push(selectValue);
// Only need to watch the displayFn if there is a specific label expression
@@ -409,10 +409,14 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
var optionTemplate = document.createElement('option'),
optGroupTemplate = document.createElement('optgroup');
function ngOptionsPostLink(scope, selectElement, 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;
var selectCtrl = ctrls[0];
var multiple = attr.multiple;
// The emptyOption allows the application developer to provide their own custom "empty"
@@ -678,7 +682,7 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
var groupElement;
var optionElement;
if (isDefined(option.group)) {
if (option.group) {
// This option is to live in a group
// See if we have already created this group
@@ -752,7 +756,7 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
return {
restrict: 'A',
terminal: true,
require: ['select', 'ngModel'],
require: ['select', '?ngModel'],
link: {
pre: function ngOptionsPreLink(scope, selectElement, attr, ctrls) {
// Deactivate the SelectController.register method to prevent
+1 -1
View File
@@ -215,7 +215,7 @@ var ngPluralizeDirective = ['$locale', '$interpolate', '$log', function($locale,
}
// If both `count` and `lastCount` are NaN, we don't need to re-register a watch.
// In JS `NaN !== NaN`, so we have to explicitly check.
// In JS `NaN !== NaN`, so we have to exlicitly check.
if ((count !== lastCount) && !(countIsNaN && isNumber(lastCount) && isNaN(lastCount))) {
watchRemover();
var whenExpFn = whensExpFns[count];
+33 -46
View File
@@ -36,23 +36,17 @@
* <div ng-repeat="(key, value) in myObj"> ... </div>
* ```
*
* However, there are a limitations compared to array iteration:
* You need to be aware that the JavaScript specification does not define the order of keys
* returned for an object. (To mitigate this in Angular 1.3 the `ngRepeat` directive
* used to sort the keys alphabetically.)
*
* - The JavaScript specification does not define the order of keys
* returned for an object, so Angular relies on the order returned by the browser
* when running `for key in myObj`. Browsers generally follow the strategy of providing
* keys in the order in which they were defined, although there are exceptions when keys are deleted
* and reinstated. See the
* [MDN page on `delete` for more info](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/delete#Cross-browser_notes).
* Version 1.4 removed the alphabetic sorting. We now rely on the order returned by the browser
* when running `for key in myObj`. It seems that browsers generally follow the strategy of providing
* keys in the order in which they were defined, although there are exceptions when keys are deleted
* and reinstated. See the [MDN page on `delete` for more info](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/delete#Cross-browser_notes).
*
* - `ngRepeat` will silently *ignore* object keys starting with `$`, because
* it's a prefix used by Angular for public (`$`) and private (`$$`) properties.
*
* - The built-in filters {@link ng.orderBy orderBy} and {@link ng.filter filter} do not work with
* objects, and will throw if used with one.
*
* If you are hitting any of these limitations, the recommended workaround is to convert your object into an array
* that is sorted into the order that you prefer before providing it to `ngRepeat`. You could
* If this is not desired, the recommended workaround is to convert your object into an array
* that is sorted into the order that you prefer before providing it to `ngRepeat`. You could
* do this with a filter such as [toArrayFilter](http://ngmodules.org/modules/angular-toArrayFilter)
* or implement a `$watch` on the object yourself.
*
@@ -99,7 +93,7 @@
* by the identifier instead of the whole object. Should you reload your data later, `ngRepeat`
* will not have to rebuild the DOM elements for items it has already rendered, even if the
* JavaScript objects in the collection have been substituted for new ones. For large collections,
* this significantly improves rendering performance. If you don't have a unique identifier,
* this signifincantly improves rendering performance. If you don't have a unique identifier,
* `track by $index` can also provide a performance boost.
* </div>
* ```html
@@ -170,13 +164,11 @@
* as **data-ng-repeat-start**, **x-ng-repeat-start** and **ng:repeat-start**).
*
* @animations
* | Animation | Occurs |
* |----------------------------------|-------------------------------------|
* | {@link ng.$animate#enter enter} | when a new item is added to the list or when an item is revealed after a filter |
* | {@link ng.$animate#leave leave} | when an item is removed from the list or when an item is filtered out |
* | {@link ng.$animate#move move } | when an adjacent item is filtered out causing a reorder or when the item contents are reordered |
* **.enter** - when a new item is added to the list or when an item is revealed after a filter
*
* See the example below for defining CSS animations with ngRepeat.
* **.leave** - when an item is removed from the list or when an item is filtered out
*
* **.move** - when an adjacent item is filtered out causing a reorder or when the item contents are reordered
*
* @element ANY
* @scope
@@ -230,11 +222,22 @@
* For example: `item in items | filter : x | orderBy : order | limitTo : limit as results` .
*
* @example
* This example uses `ngRepeat` to display a list of people. A filter is used to restrict the displayed
* results by name. New (entering) and removed (leaving) items are animated.
<example module="ngRepeat" name="ngRepeat" deps="angular-animate.js" animations="true">
* This example initializes the scope to a list of names and
* then uses `ngRepeat` to display every person:
<example module="ngAnimate" deps="angular-animate.js" animations="true">
<file name="index.html">
<div ng-controller="repeatController">
<div ng-init="friends = [
{name:'John', age:25, gender:'boy'},
{name:'Jessie', age:30, gender:'girl'},
{name:'Johanna', age:28, gender:'girl'},
{name:'Joy', age:15, gender:'girl'},
{name:'Mary', age:28, gender:'girl'},
{name:'Peter', age:95, gender:'boy'},
{name:'Sebastian', age:50, gender:'boy'},
{name:'Erika', age:27, gender:'girl'},
{name:'Patrick', age:40, gender:'boy'},
{name:'Samantha', age:60, gender:'girl'}
]">
I have {{friends.length}} friends. They are:
<input type="search" ng-model="q" placeholder="filter friends..." aria-label="filter friends" />
<ul class="example-animate-container">
@@ -247,22 +250,6 @@
</ul>
</div>
</file>
<file name="script.js">
angular.module('ngRepeat', ['ngAnimate']).controller('repeatController', function($scope) {
$scope.friends = [
{name:'John', age:25, gender:'boy'},
{name:'Jessie', age:30, gender:'girl'},
{name:'Johanna', age:28, gender:'girl'},
{name:'Joy', age:15, gender:'girl'},
{name:'Mary', age:28, gender:'girl'},
{name:'Peter', age:95, gender:'boy'},
{name:'Sebastian', age:50, gender:'boy'},
{name:'Erika', age:27, gender:'girl'},
{name:'Patrick', age:40, gender:'boy'},
{name:'Samantha', age:60, gender:'girl'}
];
});
</file>
<file name="animations.css">
.example-animate-container {
background:white;
@@ -273,7 +260,7 @@
}
.animate-repeat {
line-height:30px;
line-height:40px;
list-style:none;
box-sizing:border-box;
}
@@ -295,7 +282,7 @@
.animate-repeat.ng-move.ng-move-active,
.animate-repeat.ng-enter.ng-enter-active {
opacity:1;
max-height:30px;
max-height:40px;
}
</file>
<file name="protractor.js" type="protractor">
@@ -322,7 +309,7 @@
</file>
</example>
*/
var ngRepeatDirective = ['$parse', '$animate', '$compile', function($parse, $animate, $compile) {
var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
var NG_REMOVED = '$$NG_REMOVED';
var ngRepeatMinErr = minErr('ngRepeat');
@@ -357,7 +344,7 @@ var ngRepeatDirective = ['$parse', '$animate', '$compile', function($parse, $ani
$$tlb: true,
compile: function ngRepeatCompile($element, $attr) {
var expression = $attr.ngRepeat;
var ngRepeatEndComment = $compile.$$createComment('end ngRepeat', expression);
var ngRepeatEndComment = document.createComment(' end ngRepeat: ' + expression + ' ');
var match = expression.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+track\s+by\s+([\s\S]+?))?\s*$/);
+6 -11
View File
@@ -85,14 +85,12 @@ var NG_HIDE_IN_PROGRESS_CLASS = 'ng-hide-animate';
* .my-element.ng-hide-remove.ng-hide-remove-active { ... }
* ```
*
* Keep in mind that, as of AngularJS version 1.3, there is no need to change the display
* Keep in mind that, as of AngularJS version 1.3.0-beta.11, there is no need to change the display
* property to block during animation states--ngAnimate will handle the style toggling automatically for you.
*
* @animations
* | Animation | Occurs |
* |----------------------------------|-------------------------------------|
* | {@link $animate#addClass addClass} `.ng-hide` | after the `ngShow` expression evaluates to a non truthy value and just before the contents are set to hidden |
* | {@link $animate#removeClass removeClass} `.ng-hide` | after the `ngShow` expression evaluates to a truthy value and just before contents are set to visible |
* addClass: `.ng-hide` - happens after the `ngShow` expression evaluates to a truthy value and the just before contents are set to visible
* removeClass: `.ng-hide` - happens after the `ngShow` expression evaluates to a non truthy value and just before the contents are set to hidden
*
* @element ANY
* @param {expression} ngShow If the {@link guide/expression expression} is truthy
@@ -251,15 +249,12 @@ var ngShowDirective = ['$animate', function($animate) {
* .my-element.ng-hide-remove.ng-hide-remove-active { ... }
* ```
*
* Keep in mind that, as of AngularJS version 1.3, there is no need to change the display
* Keep in mind that, as of AngularJS version 1.3.0-beta.11, there is no need to change the display
* property to block during animation states--ngAnimate will handle the style toggling automatically for you.
*
* @animations
* | Animation | Occurs |
* |----------------------------------|-------------------------------------|
* | {@link $animate#addClass addClass} `.ng-hide` | after the `ngHide` expression evaluates to a truthy value and just before the contents are set to hidden |
* | {@link $animate#removeClass removeClass} `.ng-hide` | after the `ngHide` expression evaluates to a non truthy value and just before contents are set to visible |
*
* removeClass: `.ng-hide` - happens after the `ngHide` expression evaluates to a truthy value and just before the contents are set to hidden
* addClass: `.ng-hide` - happens after the `ngHide` expression evaluates to a non truthy value and just before the contents are set to visible
*
* @element ANY
* @param {expression} ngHide If the {@link guide/expression expression} is truthy then
+4 -6
View File
@@ -27,10 +27,8 @@
* </div>
* @animations
* | Animation | Occurs |
* |----------------------------------|-------------------------------------|
* | {@link ng.$animate#enter enter} | after the ngSwitch contents change and the matched child element is placed inside the container |
* | {@link ng.$animate#leave leave} | after the ngSwitch contents change and just before the former contents are removed from the DOM |
* enter - happens after the ngSwitch contents change and the matched child element is placed inside the container
* leave - happens just after the ngSwitch contents change and just before the former contents are removed from the DOM
*
* @usage
*
@@ -129,7 +127,7 @@
</file>
</example>
*/
var ngSwitchDirective = ['$animate', '$compile', function($animate, $compile) {
var ngSwitchDirective = ['$animate', function($animate) {
return {
require: 'ngSwitch',
@@ -170,7 +168,7 @@ var ngSwitchDirective = ['$animate', '$compile', function($animate, $compile) {
selectedTransclude.transclude(function(caseElement, selectedScope) {
selectedScopes.push(selectedScope);
var anchor = selectedTransclude.element;
caseElement[caseElement.length++] = $compile.$$createComment('end ngSwitchWhen');
caseElement[caseElement.length++] = document.createComment(' end ngSwitchWhen: ');
var block = { clone: caseElement };
selectedElements.push(block);
+45 -165
View File
@@ -8,186 +8,66 @@
* @description
* Directive that marks the insertion point for the transcluded DOM of the nearest parent directive that uses transclusion.
*
* You can specify that you want to insert a named transclusion slot, instead of the default slot, by providing the slot name
* as the value of the `ng-transclude` or `ng-transclude-slot` attribute.
*
* 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, the existing content is left intact. This lets you provide fallback content in the case
* that no transcluded content is provided.
* Any existing content of the element that this directive is placed on will be removed before the transcluded content is inserted.
*
* @element ANY
*
* @param {string} ngTransclude|ngTranscludeSlot the name of the slot to insert at this point. If this is not provided, is empty
* or its value is the same as the name of the attribute then the default slot is used.
*
* @example
* ### Basic transclusion
* This example demonstrates basic transclusion of content into a component directive.
* <example name="simpleTranscludeExample" module="transcludeExample">
* <file name="index.html">
* <script>
* angular.module('transcludeExample', [])
* .directive('pane', function(){
* return {
* restrict: 'E',
* transclude: true,
* scope: { title:'@' },
* template: '<div style="border: 1px solid black;">' +
* '<div style="background-color: gray">{{title}}</div>' +
* '<ng-transclude></ng-transclude>' +
* '</div>'
* };
* })
* .controller('ExampleController', ['$scope', function($scope) {
* $scope.title = 'Lorem Ipsum';
* $scope.text = 'Neque porro quisquam est qui dolorem ipsum quia dolor...';
* }]);
* </script>
* <div ng-controller="ExampleController">
* <input ng-model="title" aria-label="title"> <br/>
* <textarea ng-model="text" aria-label="text"></textarea> <br/>
* <pane title="{{title}}">{{text}}</pane>
* </div>
* </file>
* <file name="protractor.js" type="protractor">
* it('should have transcluded', function() {
* var titleElement = element(by.model('title'));
* titleElement.clear();
* titleElement.sendKeys('TITLE');
* var textElement = element(by.model('text'));
* textElement.clear();
* textElement.sendKeys('TEXT');
* expect(element(by.binding('title')).getText()).toEqual('TITLE');
* expect(element(by.binding('text')).getText()).toEqual('TEXT');
* });
* </file>
* </example>
<example module="transcludeExample">
<file name="index.html">
<script>
angular.module('transcludeExample', [])
.directive('pane', function(){
return {
restrict: 'E',
transclude: true,
scope: { title:'@' },
template: '<div style="border: 1px solid black;">' +
'<div style="background-color: gray">{{title}}</div>' +
'<ng-transclude></ng-transclude>' +
'</div>'
};
})
.controller('ExampleController', ['$scope', function($scope) {
$scope.title = 'Lorem Ipsum';
$scope.text = 'Neque porro quisquam est qui dolorem ipsum quia dolor...';
}]);
</script>
<div ng-controller="ExampleController">
<input ng-model="title" aria-label="title"> <br/>
<textarea ng-model="text" aria-label="text"></textarea> <br/>
<pane title="{{title}}">{{text}}</pane>
</div>
</file>
<file name="protractor.js" type="protractor">
it('should have transcluded', function() {
var titleElement = element(by.model('title'));
titleElement.clear();
titleElement.sendKeys('TITLE');
var textElement = element(by.model('text'));
textElement.clear();
textElement.sendKeys('TEXT');
expect(element(by.binding('title')).getText()).toEqual('TITLE');
expect(element(by.binding('text')).getText()).toEqual('TEXT');
});
</file>
</example>
*
* @example
* ### Transclude fallback content
* This example shows how to use `NgTransclude` with fallback content, that
* is displayed if no transcluded content is provided.
*
* <example module="transcludeFallbackContentExample">
* <file name="index.html">
* <script>
* angular.module('transcludeFallbackContentExample', [])
* .directive('myButton', function(){
* return {
* restrict: 'E',
* transclude: true,
* scope: true,
* template: '<button style="cursor: pointer;">' +
* '<ng-transclude>' +
* '<b style="color: red;">Button1</b>' +
* '</ng-transclude>' +
* '</button>'
* };
* });
* </script>
* <!-- fallback button content -->
* <my-button id="fallback"></my-button>
* <!-- modified button content -->
* <my-button id="modified">
* <i style="color: green;">Button2</i>
* </my-button>
* </file>
* <file name="protractor.js" type="protractor">
* it('should have different transclude element content', function() {
* expect(element(by.id('fallback')).getText()).toBe('Button1');
* expect(element(by.id('modified')).getText()).toBe('Button2');
* });
* </file>
* </example>
*
* @example
* ### Multi-slot transclusion
* This example demonstrates using multi-slot transclusion in a component directive.
* <example name="multiSlotTranscludeExample" module="multiSlotTranscludeExample">
* <file name="index.html">
* <style>
* .title, .footer {
* background-color: gray
* }
* </style>
* <div ng-controller="ExampleController">
* <input ng-model="title" aria-label="title"> <br/>
* <textarea ng-model="text" aria-label="text"></textarea> <br/>
* <pane>
* <pane-title><a ng-href="{{link}}">{{title}}</a></pane-title>
* <pane-body><p>{{text}}</p></pane-body>
* </pane>
* </div>
* </file>
* <file name="app.js">
* angular.module('multiSlotTranscludeExample', [])
* .directive('pane', function(){
* return {
* restrict: 'E',
* transclude: {
* 'title': '?paneTitle',
* 'body': 'paneBody',
* 'footer': '?paneFooter'
* },
* template: '<div style="border: 1px solid black;">' +
* '<div class="title" ng-transclude="title">Fallback Title</div>' +
* '<div ng-transclude="body"></div>' +
* '<div class="footer" ng-transclude="footer">Fallback Footer</div>' +
* '</div>'
* };
* })
* .controller('ExampleController', ['$scope', function($scope) {
* $scope.title = 'Lorem Ipsum';
* $scope.link = "https://google.com";
* $scope.text = 'Neque porro quisquam est qui dolorem ipsum quia dolor...';
* }]);
* </file>
* <file name="protractor.js" type="protractor">
* it('should have transcluded the title and the body', function() {
* var titleElement = element(by.model('title'));
* titleElement.clear();
* titleElement.sendKeys('TITLE');
* var textElement = element(by.model('text'));
* textElement.clear();
* textElement.sendKeys('TEXT');
* expect(element(by.css('.title')).getText()).toEqual('TITLE');
* expect(element(by.binding('text')).getText()).toEqual('TEXT');
* expect(element(by.css('.footer')).getText()).toEqual('Fallback Footer');
* });
* </file>
* </example>
*/
var ngTranscludeMinErr = minErr('ngTransclude');
var ngTranscludeDirective = ngDirective({
restrict: 'EAC',
link: function($scope, $element, $attrs, controller, $transclude) {
if ($attrs.ngTransclude === $attrs.$attr.ngTransclude) {
// If the attribute is of the form: `ng-transclude="ng-transclude"`
// then treat it like the default
$attrs.ngTransclude = '';
}
function ngTranscludeCloneAttachFn(clone) {
if (clone.length) {
$element.empty();
$element.append(clone);
}
}
if (!$transclude) {
throw ngTranscludeMinErr('orphan',
throw minErr('ngTransclude')('orphan',
'Illegal use of ngTransclude directive in the template! ' +
'No parent directive that requires a transclusion found. ' +
'Element: {0}',
startingTag($element));
}
// If there is no slot name defined or the slot name is not optional
// then transclude the slot
var slotName = $attrs.ngTransclude || $attrs.ngTranscludeSlot;
$transclude(ngTranscludeCloneAttachFn, null, slotName);
$transclude(function(clone) {
$element.empty();
$element.append(clone);
});
}
});
+2 -2
View File
@@ -20,7 +20,7 @@ function chromeHack(optionElement) {
* added `<option>` elements, perhaps by an `ngRepeat` directive.
*/
var SelectController =
['$element', '$scope', function($element, $scope) {
['$element', '$scope', '$attrs', function($element, $scope, $attrs) {
var self = this,
optionsMap = new HashMap();
@@ -167,7 +167,7 @@ var SelectController =
*
* <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
* When the model needs to be bound to a non-string value, you must either explictly 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>
+1
View File
@@ -2,6 +2,7 @@
/**
* @ngdoc directive
* @name ngRequired
* @restrict A
*
* @description
*
+24 -48
View File
@@ -93,7 +93,9 @@ function currencyFilter($locale) {
* @param {(number|string)=} fractionSize Number of decimal places to round the number to.
* If this is not provided then the fraction size is computed from the current locale's number
* formatting pattern. In the case of the default locale, it will be 3.
* @returns {string} Number rounded to fractionSize and places a “,” after each third digit.
* @returns {string} Number rounded to `fractionSize` appropriately formatted based on the current
* locale (e.g., in the en_US locale it will have "." as the decimal separator and
* include "," group separators after each third digit).
*
* @example
<example module="numberFilterExample">
@@ -221,37 +223,18 @@ function roundNumber(parsedNumber, fractionSize, minFrac, maxFrac) {
var digit = digits[roundAt];
if (roundAt > 0) {
// Drop fractional digits beyond `roundAt`
digits.splice(Math.max(parsedNumber.i, roundAt));
// Set non-fractional digits beyond `roundAt` to 0
for (var j = roundAt; j < digits.length; j++) {
digits[j] = 0;
}
digits.splice(roundAt);
} else {
// We rounded to zero so reset the parsedNumber
fractionLen = Math.max(0, fractionLen);
parsedNumber.i = 1;
digits.length = Math.max(1, roundAt = fractionSize + 1);
digits[0] = 0;
for (var i = 1; i < roundAt; i++) digits[i] = 0;
digits.length = roundAt = fractionSize + 1;
for (var i=0; i < roundAt; i++) digits[i] = 0;
}
if (digit >= 5) {
if (roundAt - 1 < 0) {
for (var k = 0; k > roundAt; k--) {
digits.unshift(0);
parsedNumber.i++;
}
digits.unshift(1);
parsedNumber.i++;
} else {
digits[roundAt - 1]++;
}
}
if (digit >= 5) digits[roundAt - 1]++;
// Pad out with zeros to get the required fraction length
for (; fractionLen < Math.max(0, fractionSize); fractionLen++) digits.push(0);
for (; fractionLen < fractionSize; fractionLen++) digits.push(0);
// Do any carrying, e.g. a digit was rounded up to 10
@@ -315,7 +298,7 @@ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
// extract decimals digits
if (integerLen > 0) {
decimals = digits.splice(integerLen);
decimals = digits.splice(integerLen, digits.length);
} else {
decimals = digits;
digits = [0];
@@ -323,11 +306,11 @@ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
// format the integer digits with grouping separators
var groups = [];
if (digits.length > pattern.lgSize) {
groups.unshift(digits.splice(-pattern.lgSize).join(''));
if (digits.length >= pattern.lgSize) {
groups.unshift(digits.splice(-pattern.lgSize, digits.length).join(''));
}
while (digits.length > pattern.gSize) {
groups.unshift(digits.splice(-pattern.gSize).join(''));
groups.unshift(digits.splice(-pattern.gSize, digits.length).join(''));
}
if (digits.length) {
groups.unshift(digits.join(''));
@@ -350,15 +333,11 @@ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
}
}
function padNumber(num, digits, trim, negWrap) {
function padNumber(num, digits, trim) {
var neg = '';
if (num < 0 || (negWrap && num <= 0)) {
if (negWrap) {
num = -num + 1;
} else {
num = -num;
neg = '-';
}
if (num < 0) {
neg = '-';
num = -num;
}
num = '' + num;
while (num.length < digits) num = ZERO_CHAR + num;
@@ -369,7 +348,7 @@ function padNumber(num, digits, trim, negWrap) {
}
function dateGetter(name, size, offset, trim, negWrap) {
function dateGetter(name, size, offset, trim) {
offset = offset || 0;
return function(date) {
var value = date['get' + name]();
@@ -377,15 +356,14 @@ function dateGetter(name, size, offset, trim, negWrap) {
value += offset;
}
if (value === 0 && offset == -12) value = 12;
return padNumber(value, size, trim, negWrap);
return padNumber(value, size, trim);
};
}
function dateStrGetter(name, shortForm, standAlone) {
function dateStrGetter(name, shortForm) {
return function(date, formats) {
var value = date['get' + name]();
var propPrefix = (standAlone ? 'STANDALONE' : '') + (shortForm ? 'SHORT' : '');
var get = uppercase(propPrefix + name);
var get = uppercase(shortForm ? ('SHORT' + name) : name);
return formats[get][value];
};
@@ -440,14 +418,13 @@ function longEraGetter(date, formats) {
}
var DATE_FORMATS = {
yyyy: dateGetter('FullYear', 4, 0, false, true),
yy: dateGetter('FullYear', 2, 0, true, true),
y: dateGetter('FullYear', 1, 0, false, true),
yyyy: dateGetter('FullYear', 4),
yy: dateGetter('FullYear', 2, 0, true),
y: dateGetter('FullYear', 1),
MMMM: dateStrGetter('Month'),
MMM: dateStrGetter('Month', true),
MM: dateGetter('Month', 2, 1),
M: dateGetter('Month', 1, 1),
LLLL: dateStrGetter('Month', false, true),
dd: dateGetter('Date', 2),
d: dateGetter('Date', 1),
HH: dateGetter('Hours', 2),
@@ -473,7 +450,7 @@ var DATE_FORMATS = {
GGGG: longEraGetter
};
var DATE_FORMATS_SPLIT = /((?:[^yMLdHhmsaZEwG']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|L+|d+|H+|h+|m+|s+|a|Z|G+|w+))(.*)/,
var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZEwG']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z|G+|w+))(.*)/,
NUMBER_STRING = /^\-?\d+$/;
/**
@@ -493,7 +470,6 @@ var DATE_FORMATS_SPLIT = /((?:[^yMLdHhmsaZEwG']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+
* * `'MMM'`: Month in year (Jan-Dec)
* * `'MM'`: Month in year, padded (01-12)
* * `'M'`: Month in year (1-12)
* * `'LLLL'`: Stand-alone month in year (January-December)
* * `'dd'`: Day in month, padded (01-31)
* * `'d'`: Day in month (1-31)
* * `'EEEE'`: Day in Week,(Sunday-Saturday)
+2 -6
View File
@@ -9,9 +9,8 @@
* Orders a specified `array` by the `expression` predicate. It is ordered alphabetically
* for strings and numerically for numbers. Note: if you notice numbers are not being sorted
* as expected, make sure they are actually being saved as numbers and not strings.
* Array-like values (e.g. NodeLists, jQuery objects, TypedArrays, Strings, etc) are also supported.
*
* @param {Array} array The array (or array-like object) to sort.
* @param {Array} array The array to sort.
* @param {function(*)|string|Array.<(function(*)|string)>=} expression A predicate to be
* used by the comparator to determine the order of elements.
*
@@ -198,10 +197,7 @@ orderByFilter.$inject = ['$parse'];
function orderByFilter($parse) {
return function(array, sortPredicate, reverseOrder) {
if (array == null) return array;
if (!isArrayLike(array)) {
throw minErr('orderBy')('notarray', 'Expected array but received: {0}', array);
}
if (!(isArrayLike(array))) return array;
if (!isArray(sortPredicate)) { sortPredicate = [sortPredicate]; }
if (sortPredicate.length === 0) { sortPredicate = ['+']; }
+5 -5
View File
@@ -47,7 +47,7 @@ function $HttpParamSerializerProvider() {
forEachSorted(params, function(value, key) {
if (value === null || isUndefined(value)) return;
if (isArray(value)) {
forEach(value, function(v) {
forEach(value, function(v, k) {
parts.push(encodeUriQuery(key) + '=' + encodeUriQuery(serializeValue(v)));
});
} else {
@@ -520,7 +520,7 @@ function $HttpProvider() {
*
* ```
* module.run(function($http) {
* $http.defaults.headers.common.Authorization = 'Basic YmVlcDpib29w';
* $http.defaults.headers.common.Authorization = 'Basic YmVlcDpib29w'
* });
* ```
*
@@ -555,7 +555,7 @@ function $HttpProvider() {
* That means changes to the properties of `data` are not local to the transform function (since Javascript passes objects by reference).
* For example, when calling `$http.get(url, $scope.myObject)`, modifications to the object's properties in a transformRequest
* function will be reflected on the scope and in any templates where the object is data-bound.
* To prevent his, transform functions should have no side-effects.
* To prevent this, transform functions should have no side-effects.
* If you need to modify properties, it is recommended to make a copy of the data, or create new object to return.
* </div>
*
@@ -930,7 +930,7 @@ function $HttpProvider() {
*/
function $http(requestConfig) {
if (!isObject(requestConfig)) {
if (!angular.isObject(requestConfig)) {
throw minErr('$http')('badreq', 'Http request configuration must be an object. Received: {0}', requestConfig);
}
@@ -1050,7 +1050,7 @@ function $HttpProvider() {
defHeaders = extend({}, defHeaders.common, defHeaders[lowercase(config.method)]);
// using for-in instead of forEach to avoid unnecessary iteration after header has been found
// using for-in instead of forEach to avoid unecessary iteration after header has been found
defaultHeadersIteration:
for (defHeaderName in defHeaders) {
lowercaseDefHeaderName = lowercase(defHeaderName);
+5 -30
View File
@@ -20,14 +20,6 @@ $interpolateMinErr.interr = function(text, err) {
*
* Used for configuring the interpolation markup. Defaults to `{{` and `}}`.
*
* <div class="alert alert-danger">
* This feature is sometimes used to mix different markup languages, e.g. to wrap an Angular
* template within a Python Jinja template (or any other template language). Mixing templating
* languages is **very dangerous**. The embedding template language will not safely escape Angular
* expressions, so any user-controlled values in the template will cause Cross Site Scripting (XSS)
* security bugs!
* </div>
*
* @example
<example name="custom-interpolation-markup" module="customInterpolationApp">
<file name="index.html">
@@ -128,15 +120,6 @@ function $InterpolateProvider() {
return value;
}
//TODO: this is the same as the constantWatchDelegate in parse.js
function constantWatchDelegate(scope, listener, objectEquality, constantInterp) {
var unwatch;
return unwatch = scope.$watch(function constantInterpolateWatch(scope) {
unwatch();
return constantInterp(scope);
}, listener, objectEquality);
}
/**
* @ngdoc service
* @name $interpolate
@@ -216,6 +199,11 @@ function $InterpolateProvider() {
* </file>
* </example>
*
* @knownIssue
* It is currently not possible for an interpolated expression to contain the interpolation end
* symbol. For example, `{{ '}}' }}` will be incorrectly interpreted as `{{ ' }}` + `' }}`, i.e.
* an interpolated expression consisting of a single-quote (`'`) and the `' }}` string.
*
* @param {string} text The text with markup to interpolate.
* @param {boolean=} mustHaveExpression if set to true then the interpolation string must have
* embedded expression in order to return an interpolation function. Strings with no
@@ -232,19 +220,6 @@ function $InterpolateProvider() {
* - `context`: evaluation context for all expressions embedded in the interpolated text
*/
function $interpolate(text, mustHaveExpression, trustedContext, allOrNothing) {
// Provide a quick exit and simplified result function for text with no interpolation
if (!text.length || text.indexOf(startSymbol) === -1) {
var constantInterp;
if (!mustHaveExpression) {
var unescapedText = unescapeText(text);
constantInterp = valueFn(unescapedText);
constantInterp.exp = text;
constantInterp.expressions = [];
constantInterp.$$watchDelegate = constantWatchDelegate;
}
return constantInterp;
}
allOrNothing = !!allOrNothing;
var startIndex,
endIndex,

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