Compare commits

..

159 Commits

Author SHA1 Message Date
Martin Staffa 30cd764b6d docs(changelog): move bootstrap fixes to Bug Fix section 2017-03-08 12:44:24 +01:00
Martin Staffa 38b75cdb2d docs(changelog): add release notes for 1.6.3 and 1.6.2 2017-03-08 12:27:00 +01:00
Pablo Targa 6cb8b39af8 docs(ngAnimate): update staggering config for use with css animations
Closes #15743
2017-03-07 20:25:09 +01:00
diegomrsantos ebaa336614 docs(guide/migration): add info for 1.4 (ng)Pattern BC
Breaking change was introduced in commit 0e001084ff.
This content being included in the migration guide is taken from the commit message of commit 0e001084ff.

Closes #15758
Closes #15765
2017-03-07 20:24:59 +01:00
mohamed amr ef5f567f91 test(errorHandlingConfig): add tests for errorHandlingConfig() (independent of minErr)
Closes #15770
2017-03-05 00:46:14 +02:00
Michał Gołębiowski 64e5afc478 fix($log): don't parse error stacks manually outside of IE/Edge
IE/Edge display errors in such a way that it requires the user to click in
4 places to see the stack trace. There is no way to feature-detect it so
there's a chance of the user agent sniffing to go wrong but since it's only
about logging, this shouldn't break apps. Other browsers display errors in
a sensible way and some of them map stack traces along source maps if available
so it makes sense to let browsers display it as they want.

Fixes #15590
Closes #15767
2017-03-03 11:41:02 +01:00
Peter Bacon Darwin 1e582e4fa4 feat(info): add angularVersion info to each module
You can now check what version of AngularJS a core module is designed for:

```
var angularVersion = $injector.modules['myModule'].info().angularVersion;
```
2017-03-02 08:25:16 +00:00
Peter Bacon Darwin 7421235f24 feat($injector): add new modules property
The `modules` property is a hash of the modules loaded into the injector
at bootstrap time. This can be used to access the module's info.
2017-03-02 08:25:09 +00:00
Peter Bacon Darwin 09ba69078d feat(Module): add info() method
The new `info()` method lets developers store arbitrary information about
their module for consumption later.

Closes #15225
2017-03-02 08:25:01 +00:00
Peter Bacon Darwin 3536e83d8a fix(Angular): do not autobootstrap if the src exists but is empty
In Chrome an empty `src` attribute will be ignored, but in Firefox it seems
happy to prepend the `base[href]` and try to load whatever that is.
2017-02-27 20:47:04 +00:00
Georgios Kalpakas 3bb1dd5d7f fix($sanitize): prevent clobbered elements from freezing the browser
Closes #15699
2017-02-24 17:42:14 +00:00
Peter Bacon Darwin 95f964b827 fix(Angular): do not auto bootstrap if the currentScript has been clobbered 2017-02-24 15:04:10 +00:00
Peter Bacon Darwin c8f78a8ca9 fix(Angular): do not auto bootstrap if the script source is bad and inside SVG 2017-02-24 15:04:03 +00:00
Peter Bacon Darwin f34d48087b test(Angular): refactor auto bootstrap tests 2017-02-24 15:03:56 +00:00
Martin Staffa 2c9ecd01b1 docs($compile): clarify to which element scope isolation applies
Closes #13556
2017-02-22 21:08:52 +01:00
Georgios Kalpakas a584fb6e15 fix($animate): reset classNameFilter to null when a disallowed RegExp is used
Closes #14913
2017-02-17 11:33:13 +02:00
Georgios Kalpakas 1f13313f40 fix($animate): improve detection on ng-animate in classNameFilter RegExp
Fixes #14806
2017-02-17 11:33:12 +02:00
Martin Staffa 5b60303781 chore(docs-app): add debounce to search input
This fixes issues where the search results do not correctly reflect
the search query. This happens in Firefox when you enter a search query
very rapidly.
There is probably an issue with the async behavior of the search / webworker,
so this is just a workaround.
2017-02-16 14:28:08 +01:00
Martin Staffa 10e2552a7d chore(docs-app): update links in header menu
They are now in the same order as angularjs.org

Closes #14351
2017-02-16 14:28:08 +01:00
Martin Staffa ef48b0aa55 chore(docs-app): update the header style
Also adds a new fixed strip / bar about the AngularJS version

Closes #14963
Closes #15670
2017-02-16 14:28:08 +01:00
Keith Walsh f57872bca0 docs($resource): add minor clarification
Closes #15711
2017-02-16 12:00:45 +02:00
Martin Staffa 2deaf2877e docs(select, ngOptions): add ngAttrSize as argument
Closes #1619
2017-02-15 15:28:08 +01:00
Martin Staffa 7a146c9cd5 docs(ngModelController): improve $formatters and $parsers info
Closes #11714
Closes #8194
2017-02-15 13:05:44 +01:00
Martin Staffa 2796ec172b docs(filterFilter): add note about self-referencing objects in array
Relate #6655, #6319
2017-02-15 12:21:58 +01:00
Martin Staffa 6997c1bf0c docs(guide/directive): clarify which type of matching directives support
Closes #15710
2017-02-15 12:21:22 +01:00
Georgii Dolzhykov 4a030f3834 refactor($rootScope): remove extraneous call to $parse in $evalAsync
Closes #15682
2017-02-09 23:39:56 +02:00
Michał Gołębiowski f78d8b8ff3 chore(jenkins): get rid of Opera from the Jenkins build script
The Opera launcher hasn't been installed for ages, but until Karma 1.4.0 the
error of Opera not being able to start was ignored. Karma has fixed the bug and
now Jenkins is failing.

This commit also removes Opera/Opera launcher mentions from the docs. We don't
support Opera officially anymore (it's sort-of supported via being based on
Blink).

Closes #15691
2017-02-09 12:59:43 +02:00
PRIJCK Frederik (FPRJ) f27d19ed60 fix(filterFilter): don't throw if key.charAt is not a function
Previously, when an object has keys which are not of type string, `filterFilter`
would throw an exception for trying to call `key.charAt()`, which is a string
method.

This commit checks whether `charAt` is defined before calling it.

Fixes #15644

Closes #15660
2017-02-08 23:18:01 +02:00
mohamed amr 4a5eaf7bec feat(errorHandlingConfig): make the depth for object stringification in errors configurable
Closes #15402
Closes #15433
2017-02-08 19:06:17 +02:00
Martin Staffa 8513674911 fix(select): add attribute "selected" for select[multiple]
This helps screen readers identify the selected options,
see #14419
2017-02-08 17:46:24 +01:00
Martin Staffa 97b74ad6fb fix(select): keep original selection when using shift to add options in IE/Edge
In IE9-11 + Edge, the selected options were previously incorrect under the following
circumstances:
- at least two options are selected
- shift+click or shift+down/up is used to add to the selection (any number of options)

In these cases, only the last of the previously selected options and the newly selected
options would be selected.

The problems seems to be that the render engine gets confused when an option that
already has selected = true gets selected = true set again.

Note that this is not testable via unit test because it's not possible to simulate
click / keyboard events on option elements (the events are delegated to the select element
change event), and the problem also doesn't appear when modifying the option elements directly
and then using the selectController API. It seems that this only happens when you manipulate the
select directly in the user interface.

Fixes #15675
Closes #15676
2017-02-08 17:46:21 +01:00
Martin Staffa a47ea79023 test($http): ensure json deserialization errors are forwarded to error handler
Since https://github.com/angular/angular.js/commit/e13eeabd7e34a78becec06cfbe72c23f2dcb85f9,
errors thrown from onFulfilled and onRejected handlers are passed to the regular http
error handlers. Before this, JSON deserialization errors lead to hard application errors, and could
not be handled by application code. This behavior was introduced in https://github.com/angular/angular.js/commit/7b6c1d08aceba6704a40302f373400aed9ed0e0b, and originally, a malformed JSON string was forwarded
as the data to the http success response handler.

This commit adds a specifc test case, even though the behavior is unlikely to break in the future without
a change in the $q rejection handling.

Related #11433
Closes #15689
2017-02-08 17:46:17 +01:00
Matt Lewis 5ca0de6487 fix($jsonpCallbacks): allow $window to be mocked in unit tests
Fixes #15685

Closes #15686
2017-02-08 18:35:55 +02:00
Georgios Kalpakas 50a449f053 chore(*): update changez-angular 2017-02-08 18:35:12 +02:00
Georgios Kalpakas d7422da7d7 test($resource): fix broken test
(Introduced while "cleaning up" the tests for in edfb691.)
2017-02-05 17:58:25 +02:00
Georgios Kalpakas c7cbc978c6 refactor(*): remove ignored expensiveChecks argument passed to $parse()
This is a follow-up to #15094.

Closes #15680
2017-02-05 15:39:10 +02:00
Kyle Wuolle 27146e8a7f fix($resource): do not swallow errors in success callback
Previously, errors thrown inside the `success` callback would be swallowed by a
noop `catch()` handler. The `catch()` handler was added in order to avoid an
unnecessary "Possibly Unhandled Rejection" error, in case the user provided an
`error` callback (which would handle request errors).

The handler was added too "eagrly" and as a result would swallow errors thrown
in the `success` callback, despite the fact that those errors would _not_ be
handled by the `error` callback.

This commit fixes this, by adding the `catch()` handler "lazily", only when it
is certain that a rejection will be handled by the `error` callback.

Fixes #15624

Closes #15628
2017-02-04 21:01:22 +02:00
Kindy Lin 5e418b1145 fix($parse): make sure ES6 object computed properties are watched
Add the missing watches for ES6 object computed properties which were
implemented in #14407.

Closes #15678
2017-02-04 16:18:21 +02:00
Dimitris Vardoulakis f4bb973eb7 refactor(*): avoid non-existent property warnings from Closure Compiler
Closes #15672
2017-02-02 22:38:27 +02:00
Chris 848857aa5b docs(misc/started): update Twitter handle (@angularjs --> @angular)
Closes #15671
2017-02-02 19:30:48 +02:00
Jessica Soltero ee8a05d3f1 docs(guide/expression): typo in one-time-binding
Closes #15668
2017-02-02 12:45:58 +02:00
Michał Gołębiowski 275ebbf0ec refactor($injector): remove the Chrome stringification hack
The Chrome stringification hack added in afcedff34c
is no longer needed. I verified that both of the commented out tests pass
on Chrome 56.
2017-02-01 15:02:52 +00:00
Michał Gołębiowski 0f23df4c06 chore(anchorScroll): remove a Jasmine toHaveBeenCalled workaround
The Jasmine fix landed long time ago and we've updated Jasmine since that
happened.
2017-02-01 13:36:20 +00:00
Michał Gołębiowski 11f700f7bd docs($location): fix examples
The examples contained tests with assertions in form of regular equality
comparisons which would be noops and in case of an error nothing would get
reported. Also, one of the test mixed a HTML5 browser scenario with a non-HTML5
one.
2017-02-01 13:35:15 +00:00
Michał Gołębiowski 5785f2a991 docs($animation): fix weird spaces around colons 2017-02-01 13:29:28 +00:00
Peter Bacon Darwin 2546c29f81 feat(ngModel): add $overrideModelOptions support
This change allows developers to modify the model options for an `ngModel`
directive programmatically.

Closes #15415
2017-02-01 12:20:41 +00:00
Patrick McElhaney 19ea708c9d docs(guide/component): add replace option
Add `replace` to the table comparing components to directives options. The
`replace` option is deprecated, but it is still documented for directives, so
it is worth pointing it out as a difference between directives and components.

Closes #15658
2017-01-31 19:37:47 +02:00
Frederik Prijck 5cf05d67f2 chore(doc-gen): show arguments as a subsection of the usage section
Previously, on the docs of directives which include the `animation` section, `arguments` are shown as an `h3` element below the `animation` `h2` element, making it look like it's a subsection of `animations`.

This commit ensures that the àrgument` `h3`element is rendered correctly after the `usage` `h2` element.

Fixes #15645
Closes #15646
2017-01-30 19:26:27 +02:00
Georgios Kalpakas 0377c6f0e8 fix($compile): do not swallow thrown errors in test
In e13eeab, errors/rejections produced during fetching the template or compiling
an asynchronous directive, where overzealously silenced. This doesn't make any
difference in (most) production apps, where `$exceptionHandler` does not rethrow
the errors. In tests though (where `$exceptionHandler` rethrows by default), it
can unexpectedly "swallow" thrown errors.

This commit fixes it by removing the extraneous `.catch(noop)`, thus letting
errors thrown by `$exceptionHandler` to surface.

The changes in 'compileSpec.js' essentially revert the modifications that were
unnecessarily (and incorrectly) done in e13eeab (and also one incorrect
modification from [c22615c][1]).

[1]: https://github.com/angular/angular.js/commit/c22615cbfbaa7d1712e79b6bf2ace6eb41313bac#diff-348c2f3781ed66a24894c2046a52c628L2084

Fixes #15629

Closes #15631
2017-01-30 19:25:06 +02:00
Peter Bacon Darwin 9c13866824 chore(docs): don't use bower for docs dependencies 2017-01-30 14:10:25 +00:00
vteremasov 419a4813e3 fix($resource): correctly unescape /\. even if \. comes from a param value
Closes #15627
2017-01-27 18:20:11 +02:00
Martin Staffa 131af8272d fix(select): keep ngModel when selected option is recreated by ngRepeat
Fixes #15630 
Closes #15632
2017-01-27 16:14:18 +01:00
Martin Staffa c219a46f59 docs(ngDisabled): list some elements that natively support
Closes #15473
2017-01-27 16:14:06 +01:00
Jason Bedard 25f008f541 feat($parse): allow watching array/object of inputs to literal values
The inputs of array/object literals are now watched for changes.
If the an input changes then a new instance of the literal will be
provided when the parsed expression is executed.

Closes #15301
2017-01-27 10:06:31 +00:00
frederikprijck 4a593db79b fix($sniffer): allow history for NW.js apps
Previously `$sniffer` incorrectly detected NW.js apps as Chrome Packaged Apps,
disallowing them to use the history API.

This commit correctly detects NW.js apps and allows them to use the History API.

Fixes #15474

Closes #15633
2017-01-27 00:16:54 +02:00
Georgios Kalpakas ad4fef0431 refactor(*): replace HashMap with NgMap
For the time being, we will be using `NgMap`, which is an API-compatible
implementation of native `Map` (for the features required in Angular). This will
make it easy to switch to using the native implementations, once they become
more stable.

Note:
At the moment some native implementations are still buggy (often in subtle ways)
and can cause hard-to-debug failures.)

Closes #15483
2017-01-25 23:57:16 +02:00
Georgios Kalpakas 8a15fcc1f5 test(hashKey): add tests for hashKey() 2017-01-25 23:57:15 +02:00
Georgios Kalpakas f01212ab52 fix(ngAnimate): correctly animate transcluded clones with templateUrl
Previously, `$animate` would decide whether an animation should be cancelled
based on some assumption that didn't hold in specific cases (e.g. when animating
transcluded clones with `templateUrl` directives on them for the first time). As
a result, the entering elements would not be animated in such cases. This
affected commonly used, structural built-in directives (`ngIf`, `ngRepeat`,
`ngSwitch` etc).
This commit fixes it by avoiding invalid assumptions (i.e. by taking into
account the transformations that take place while compiling such elements).

Partly addresses #14074 and #14124.

Fixes #15510

Closes #15514
2017-01-24 23:56:04 +02:00
Georgios Kalpakas 28693a1a67 test(ngAnimate): make expectations more specific 2017-01-24 23:56:04 +02:00
Georgios Kalpakas 29fd499552 refactor(ngAnimate): simplify functions and remove redundant args/calls
Simplifies/Optimizes the following functions:

- `areAnimationsAllowed()`
- `cleanupEventListeners()`
- `closeChildAnimations()`
- `clearElementAnimationState()`
- `markElementAnimationState()`
- `findCallbacks()`

Although not its primary aim, this commit also offers a small performance boost
to animations (~5% as measured with the `animation-bp` benchmark).
2017-01-24 23:56:03 +02:00
Georgios Kalpakas 2f97d9d647 chore(benchmarks): add basic animation benchmark 2017-01-24 23:56:03 +02:00
Georgios Kalpakas 4146b38459 docs(*): document the breaking change in 7ceb5f6 2017-01-20 22:51:21 +02:00
frederikprijck 05aab660ce fix(ngValue): correctly update the value property when value is undefined
Previously, when the expression evaluated to `undefined` the `value` property
was not updated. This happened because jqLite/jQuery's `prop(_, undefined)` is
treated as a getter, thus not apdating the property.

This commit fixes it by setting the property to `null` instead.
(On IE9 we use `''` - see inline comments for more info.)

Fixes #15603

Closes #15605
2017-01-19 14:45:28 +02:00
Peter Bacon Darwin 5ecb64849e chore(package): relax yarn version constraint 2017-01-19 09:26:25 +00:00
Martin Brown 59dfe1b5a0 docs(guide/i18n): fix typos
Closes #15616
2017-01-17 18:18:48 +02:00
Georgios Kalpakas 50ebfb735c docs(changelog): update with changes for 1.5.11 2017-01-13 01:13:18 +02:00
Georgios Kalpakas 0bdbfe5069 style($compile): remove trailing whitespace 2017-01-12 23:12:44 +02:00
Grace Benz 3fc4d6028c docs($compile): add some detail about $onChanges
Closes #15604
2017-01-12 22:42:50 +02:00
Georgios Kalpakas 2eb12a052b test(e2e): make test less flakey-prone 2017-01-12 22:25:47 +02:00
Peter Bacon Darwin bd63b2235c fix(ngMockE2E): ensure that mocked $httpBackend uses correct $browser
The fix from #13124 enabled ngMock and ngMockE2E to work together but
did it in a way that meant that the "real" `$httpBackend` service that
was used in pass-through depended upon a different `$browser` service
to the rest of the app.

This broke Protractor since it watches the `$browser` for outstanding
requests and the pass through requests were being tracked by the wrong
`$browser` instance.

Closes #15593
2017-01-12 10:59:26 +00:00
Georgios Kalpakas f418ffd083 revert: fix($sce): consider document base URL in 'self' URL policy
This reverts commit cce98ff53a.
Reverting while investigating security implications of cce98ff without #15597
(which is possibly a breaking change, thus not suitable for this branch).
2017-01-12 11:24:10 +02:00
Georgios Kalpakas 6ab5f8ce4b chore(*): fix yarn.lock
(It turns out cherry-picking it from master wasn't a great idea :/)
2017-01-12 01:08:55 +02:00
Georgios Kalpakas becfeb5aa3 chore(*): update dgeni-packages (and other devDependencies)
`dgeni-packages` prior to version 0.16.3 specified `engine.yarn: '^0.17.9'`,
which was unnecessarily strict and would cause any task to fail if someone had a
yarn version >=0.18.0.
Other devDependencies were also updated (because why not).

Closes #15600
2017-01-12 01:02:08 +02:00
Sammy Jelin eb968c4a68 fix($route): make asynchronous tasks count as pending requests
Protractor users were having a problem where if they had asynchonous code in a
`route.resolve` or `route.resolveRedirectTo` variable, Protractor was not
waiting for that code to complete before continuing. See
https://github.com/angular/protractor/issues/789#issuecomment-190983200 for
details.

This commit fixes it by ensuring that `$browser#outstandingRequestCount` is
properly increased/decreased while `$route` (asynchronously) processes a route.

Also, enhanced `ngMock` to wait for pending requests, before calling callbacks
from `$browser.notifyWhenNoOutstandingRequests()`.

Related to angular/protractor#789.

Closes #14159
2017-01-12 00:15:20 +02:00
frederikprijck 7f2af3f923 fix($compile): allow the usage of "$" in isolate scope property alias
Previously, when using an alias for an isolate scope or `bindings` property
(e.g. `alias: '<attrName'` instead of `attrName: '<'`), a `$compile:iscp` error
was thrown if the attribute name contained a "$".
This commit removes the error by changing the regex to allow "$" characters in
the attribute name when using a property alias.

Fixes: #15586

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

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

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

Fixes #15144

Closes #15145
2017-01-10 14:51:09 +02:00
Georgios Kalpakas b607618342 fix($location): correctly handle external URL change during $digest
Previously, when the URL was changed directly (e.g. via `location.href`) during
a `$digest` (e.g. via `scope.$evalAsync()` or `promise.then()`) the change was
not handled correctly, unless a `popstate` or `hashchange` event was fired
synchronously.

This was an issue when calling `history.pushState()/replaceState()` in all
browsers, since these methods do not emit any event. This was also an issue when
setting `location.href` in IE11, where (unlike other browsers) no `popstate`
event is fired at all for hash-only changes ([known bug][1]) and the
`hashchange` event is fired asynchronously (which is too late).

This commit fixes both usecases by:

1. Keeping track of `$location` setter methods being called and only processing
   a URL change if it originated from such a call. If there is a URL difference
   but no setter method has been called, this means that the browser URL/history
   has been updated directly and the change hasn't yet been propagated to
   `$location` (e.g. due to no event being fired synchronously or at all).
2. Checking for URL/state changes at the end of the `$digest`, in order to
   detect changes via `history` methods (that took place during the `$digest`).

[1]: https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/3740423/

Fixes #11075
Fixes #12571
Fixes #15556

Closes #15561
2017-01-10 00:03:10 +02:00
Georgios Kalpakas fa50fbaf57 fix(*): detect external changes in history.state
Previously, `$browser.$$checkUrlChange()` (which was run before each `$digest`)
would only detect an external change (i.e. not via `$location`) to the browser
URL. External changes to `history.state` would not be detected and propagated to
`$location`.

This would not be a problem if changes were followed by a `popstate` or
`hashchange` event (which would call `cacheStateAndFireUrlChange()`). But since
`history.pushState()/replaceState()` do not fire any events, calling these
methods manually would result in `$location` getting out-of-sync with the actual
history state.

This was not detected in tests, because the mocked `window.history` would
incorrectly trigger `popstate` when calling `pushState()/replaceState()`, which
"covered" the bug.

This commit fixes it by always calling `cacheState()`, before looking for and
propagating a URL/state change.
2017-01-10 00:03:09 +02:00
David Jöch f135e2dc05 style($log): fix indentation
Closes #15579
2017-01-05 13:02:59 +02:00
Florian Berger 780351db5e docs(*): fix typos
Closes #15577
2017-01-05 11:10:52 +02:00
Nic Mitchell a50bb0bfec chore(*): update copyright year
Closes #15573
2017-01-04 12:21:08 +02:00
Georgios Kalpakas 4d86df6f48 docs(guide/$location): correctly format heading 2017-01-03 22:37:17 +02:00
Georgios Kalpakas bb464d16b4 fix(angularInit): allow auto-bootstraping from inline script
Some browsers (e.g. Safari 9.x, PhantomJS) do not set `link.origin/protocol`
correctly, when setting `link.href` to `null`, which prevented auto-bootstraping
Angular from scripts without a `src` attribute (i.e. inline scripts).
Inline scripts are on the same origin as the loading page, so auto-bootstraping
should be allowed.

Fixes #15567

Closes #15571
2017-01-03 19:23:43 +02:00
Soumya Ranjan Mohanty 85b2eb1472 docs(guide/services): fix syntax for Jasmine v2.x
Closes #15570
2017-01-03 16:14:32 +02:00
Georgios Kalpakas 7608f92c6a docs(ngShow/ngHide): improve docs and fix inconsistencies between ngShow/ngHide
Closes #15471
2017-01-03 12:55:38 +02:00
Deco c0bf8db63c docs(tutorial/step_04): fix typo
Closes #15562
2016-12-31 12:32:22 +02:00
Georgios Kalpakas c95a6737fb fix(input): fix step validation for input[type=number/range]
Previously, the validation would incorrectly fail in certain cases (e.g.
`step: 0.01`, `value: 1.16 or 20.1`), due to Floating Point Arithmetic
limitations. The previous fix for FPA limitations (081d06ff) tried to solve the
issue by converting the numbers to integers, before doing the actual
calculation, but it failed to account for cases where the conversion itself
returned non-integer values (again due to FPA limitations).
This commit fixes it by ensuring that the values used in the final calculation
are always integers.

Fixes #15504

Closes #15506
2016-12-29 10:18:32 +02:00
Georgios Kalpakas cd43d24402 docs(CHANGELOG.md): add missing commas 2016-12-29 10:09:04 +02:00
supasak 086c5d0354 fix($resource): delete $cancelRequest() in toJSON()
Closes #15244
2016-12-29 10:01:11 +02:00
Peter Bacon Darwin 2a2ac5f53a docs(CHANGELOG): add 1.6.1 release info 2016-12-23 10:38:58 +00:00
Peter Bacon Darwin 21deaf637a chore(deps): update changez-angular version 2016-12-23 10:38:48 +00:00
Naomi Black 72e15a3a83 docs(guide/forms): remove implicit bias from example
Closes #15543
2016-12-23 11:43:47 +02:00
Thomas Grainger 174cb4a8c8 fix($q): Add traceback to unhandled promise rejections
Fixes #14631
Closes #15527
2016-12-21 20:12:29 +01:00
sp00m 33f769b0a1 fix($$cookieReader): correctly handle forbidden access to document.cookie
In certain cases (e.g. on LG webOS using the `file:` protocol), access to
`document.cookie` may not be allowed and throw an error. This could break
`$http` which relies on `$$cookieReader()` for retrieving the XSRF token.
This commit fixes it by treating `document.cookie` as empty, when access to it
is fordibben.

Fixes  #15523

Closes #15532
2016-12-20 23:34:07 +02:00
Simon Legner c8abf20558 docs(CHANGELOG): fix typo
Closes #15529
2016-12-20 10:33:14 +02:00
Thomas Grainger 6dbb183e75 docs(guide/migration): improve grammar
Closes #15526
2016-12-20 01:17:19 +02:00
Georgios Kalpakas bc4844d3b2 fix(ngOptions): do not unset the selected property unless necessary
Previously, when updating the value of a `select[multiple]` element, all options
were first set to `selected = false` and then the selected ones were set to
`true`. By setting an already selected option to `selected = false` and then
`true` again - essentially unselecting and reselecting it - caused some browsers
(including Firefox, IE and under some circumstances Chrome) to unexpectedly
scroll to the last selected option.

This commit fixes it by ensuring that the `selected` property is only set if its
current value is different than the new one and even then it is set to its final
value at once (i.e. without first setting it to `false`), thus avoiding the
undesirable behavior.

Fixes #15477

Closes #15478
2016-12-19 22:52:18 +02:00
Peter Neave 708f8b47de docs(tutorial/step_13): add missing dependency phoneDetails module
Closes #15521
2016-12-19 21:09:21 +02:00
Georgios Kalpakas 5518126d42 docs(CHANGELOG.md): remove reverted bug fix
Related to 02f045b.
2016-12-16 11:16:08 +02:00
Peter Bacon Darwin 5fe73fdc3a docs(CHANGELOG): add note to 1.5.0-beta.1 2016-12-16 11:16:08 +02:00
Georgios Kalpakas 394c496bf2 docs(CHANGELOG.md): add changes for v1.5.10 2016-12-15 19:29:37 +02:00
Georgios Kalpakas 8e1aeba715 docs(CHANGELOG.md): add missing entries for v1.6.0-rc.0/v1.6.0 2016-12-15 19:29:06 +02:00
Georgios Kalpakas 0e6e7eb477 docs($q): document the default value for errorOnUnhandledRejections 2016-12-14 00:44:36 +02:00
Jannick Fahlbusch 183f636816 docs($interval): improve fn description
If no additional arguments are passed, the function is called with the current iteration count.

Closes #15503
2016-12-13 14:16:20 +02:00
Georgios Kalpakas 5f8ed63f2a fix(ngModelOptions): work correctly when on the template of replace directives
Previously, in order for `ngModel` and `ngModelOptions` to work correctly
together, the latter's pre-linking function should be run before the former's
pre-linking function. This was typically what happened, except when `ngModel`
was used on an element which also had a `replace` directive, whose template
included `ngModelOptions`. In that case, the order was reversed.

This commit fixes it by moving the initialization logic of `ngModelOptions` from
its pre-linking function to its controller's `$onInit()` lifecycle hook.

Fixes #15492

Closes #15493
2016-12-13 00:12:34 +02:00
Georgios Kalpakas e4f3c94e31 refactor(testabilityPatch): remove code duplication 2016-12-13 00:11:18 +02:00
Aaron Brewer 1e5cbcbd93 docs(ngMessageExp): improve description
Closes #15486
2016-12-11 21:01:57 +02:00
idhindsight dcf3ec160f docs(tutorial/step_09): fix typo (it's --> its)
Closes #15485
2016-12-10 22:27:59 +02:00
David Rodenas Pico a7beb5b6d3 chore(benchpress): add an ngClass benchmark
Closes #15243
2016-12-09 12:21:21 +02:00
Georgios Kalpakas 1d3b65adc2 perf(ngClass): avoid unnecessary .data() accesses, deep-watching and copies
Includes the following commits (see #15246 for details):

- **perf(ngClass): only access the element's `data` once**

- **refactor(ngClass): simplify conditions**

- **refactor(ngClass): move helper functions outside the closure**

- **refactor(ngClass): exit `arrayDifference()` early if an input is empty**

- **perf(ngClass): avoid deep-watching (if possible) and unnecessary copies**

  The cases that should benefit most are:

  1. When using large objects as values (e.g.: `{loaded: $ctrl.data}`).
  2. When using objects/arrays and there are frequent changes.
  3. When there are many `$index` changes (e.g. addition/deletion/reordering in large `ngRepeat`s).

  The differences in operations per digest include:

  1. `Regular expression (when not changed)`
     **Before:** `equals()`
     **After:**  `toClassString()`

  2. `Regular expression (when changed)`
     **Before:** `copy()` + 2 x `arrayClasses()` + `shallowCopy()`
     **After:**  2 x `split()`

  3. `One-time expression (when not changed)`
     **Before:** `equals()`
     **After:**  `toFlatValue()` + `equals()`*

  4. `One-time expression (when changed)`
     **Before:** `copy()` + 2 x `arrayClasses()` + `shallowCopy()`
     **After:**  `copy()`* + `toClassString()`* + 2 x `split()`

  5. `$index modulo changed`
     **Before:** `arrayClasses()`
     **After:**  -

  (*): on flatter structure

  In large based on #14404. Kudos to @drpicox for the initial idea and a big part
  of the implementation.

Closes #14404

Closes #15246
2016-12-09 12:04:47 +02:00
Georgios Kalpakas d528644fe3 fix(ngClassOdd/Even): add/remove the correct classes when expression/$index change simultaneously 2016-12-09 12:03:38 +02:00
David Rodenas Pico 6f1bcfc14e test(ngClass): add some tests about one-time bindings and objects inside arrays 2016-12-09 12:01:37 +02:00
Georgios Kalpakas 996914c6b0 refactor(ngClass): remove redundant $observer and dependency on $animate
Includes the following commits (see #15246 for details):

- **refactor(ngClass): remove unnecessary dependency on `$animate`**

- **refactor(ngClass): remove redundant `$observe`r**

  The code was added in b41fe9f in order to support having both `ngClass` and
  interpolation in `class` work together. `ngClass` has changed considerably since
  b41fe9f and for simple cases to work the `$observe`r is no longer necessary (as
  indicated by the expanded test still passing).

  That said, it is a [documented known issue][1] that `ngClass` should not be used
  together with interpolation in `class` and more complicated cases do not work
  anyway.

[1]: https://docs.angularjs.org/api/ng/directive/ngClass#known-issues
2016-12-09 12:00:41 +02:00
Aman Mittal fff048d099 docs(guide/external-resources): add "AngularJS in Action" book
Closes #15480
2016-12-09 11:36:26 +02:00
Peter Bacon Darwin dcb0da8225 chore(docs): fix plnkrOpener to use $onInit
Since 1.6.0 does not preassign bindings before running the controller
constructor function, we must move initialisation into the `$onInit`
method.
2016-12-09 11:28:23 +02:00
Peter Bacon Darwin b664e20d12 chore(package): update docs app to run on 1.6.0 2016-12-09 11:27:20 +02:00
Georgios Kalpakas 3d68b95028 fix(jqLite): silently ignore after() if element has no parent
Previously, the element was always assumed to have a parent and an error was
thrown when that was not the case.
This commit makes jqLite consistent with jQuery, which silently ignores a call
on elements that do not have a parent.

Fixes #15331
Closes #15367

Closes #15475
2016-12-09 10:56:14 +02:00
Georgios Kalpakas 163aca336d fix($rootScope): when adding/removing watchers during $digest
Previously, adding a watcher during a `$digest` (i.e. from within a watcher),
would result in the next watcher getting skipped. Similarly, removing a watcher
during a `$digest` could result in the current watcher being run twice (if the
removed watcher had not run yet in the current `$digest`).

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

Fixes #15422

Closes #15424
2016-12-09 10:44:24 +02:00
Georgios Kalpakas e922c38612 docs(ngMockE2E): correctly document the data arg of $httpBackend.when(...) 2016-12-08 14:53:47 +02:00
Peter Bacon Darwin 1b7ddd3491 chore(bower/npm): use npm (not yarn) to publish
yarn has an annoying behaviour in that it wants to do the version bumping
for you and requires an interactive terminal to tell it what version.
2016-12-08 12:21:57 +00:00
Peter Bacon Darwin 4c5afb5cc2 chore(jenkins): ensure deps are installed before trying to use them 2016-12-08 11:07:52 +00:00
Peter Bacon Darwin f0dc288824 chore(jenkins): fix working directory to make yarn work 2016-12-08 10:53:07 +00:00
Peter Bacon Darwin 70490ef717 docs(CHANGELOG): fix 1.6.0 release name 2016-12-08 10:21:48 +00:00
Peter Bacon Darwin dfef3bf2d4 chore(package): update dist-tag for 1.6.0 release 2016-12-08 10:18:07 +00:00
Peter Bacon Darwin f727adddeb docs(CHANGELOG): 1.6.0 release notes 2016-12-08 10:15:05 +00:00
Peter Bacon Darwin fc89a85406 chore(jenkins): fix yarn and grunt installation 2016-12-07 10:53:37 +00:00
Georgios Kalpakas b4f5377a2f docs(guide/migration): fix typo 2016-12-07 01:55:48 +02:00
Georgios Kalpakas 7a667c77e3 fix(select): do not throw when removing the element (e.g. via ngIf)
Fixes #15466

Closes #15468
2016-12-06 12:43:34 +02:00
Georgios Kalpakas 752b1e69b7 fix($resource): allow params in hostname (except for IPv6 addresses)
Support for IPv6 addresses (in b643f0d) was too aggressive and broke support for params in the
`hostname` part of a URL.
This commit restores support for params in the `hostname`, as long as it is not an IPv6 address.

Fixes #14542

Closes #14906
2016-12-03 09:56:18 +02:00
ojab 1102c84f59 docs(guide/templates): camelCase directive name for consistency
Closes #15465
2016-12-02 23:40:22 +02:00
Martin Staffa 245b27101a fix(ngOptions): don't add comment nodes as empty options
When the "empty option" element contains a transclusion directive, the result of the compilation always includes a comment node. Since we are adding / removing the "selected" attribute on the empty option, we need to make sure it's an actual element.

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

Closes #15454
Closes #15459
2016-12-02 18:48:49 +01:00
Martin Staffa f5d2bf3d6e chore(doc-gen): render @example tag in ngdoc @method
Currently, ngdoc `@method` ignores `@example` tags and does not output them.
This is usually not a problem, as examples are mostly defined directly
in the `@description` via code blocks or `<example>`
elements. However, some methods still have `@example` tags (possibly
from a previous docs version).

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

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

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

Fixes #15333

Closes #15458
2016-12-01 14:28:39 +02:00
Rob Wu 465d173455 feat(security): do not bootstrap from unknown schemes with a different origin 2016-12-01 11:29:22 +00:00
Martin Staffa f1db7d735b docs(ngModelOptions): fix broken layout because of code section 2016-11-29 23:51:13 +01:00
Peter Bacon Darwin b77defde81 docs(contribute): mention nvm-windows 2016-11-29 13:25:59 +00:00
Peter Bacon Darwin afafb7a8ab docs(FAQ) add link to security guide 2016-11-29 13:25:58 +00:00
Peter Bacon Darwin f04fcdfe9f chore(grunt): check node, yarn and grunt-cli versions
If global versions of node, yarn or grunt-cli don't match what we expect then blow up.
2016-11-29 13:25:58 +00:00
Peter Bacon Darwin 5dd3a35f47 chore(grunt): run gulp directly rather than through npm 2016-11-29 13:25:58 +00:00
Peter Bacon Darwin ca139dee8e chore(utils): install npm-run to simplify scripts 2016-11-29 13:25:58 +00:00
Peter Bacon Darwin 099083352a chore(travis): install grunt-cli globally to simplify scripts 2016-11-29 13:25:57 +00:00
Peter Bacon Darwin f54e9242fc chore(jenkins): remove path to grunt
grunt is installed globally on jenkins so we can just use it directly.
2016-11-29 13:25:57 +00:00
Peter Bacon Darwin d003ec1d41 docs(ComponentRouter): it is unlikely ever to appear on bower or CDN 2016-11-29 13:25:57 +00:00
Peter Bacon Darwin aadee894da chore(validate-commit): remove redundant scripts 2016-11-29 13:25:57 +00:00
Peter Bacon Darwin ad4e86a582 chore(saucelabs): update sauce-connect to 4.4.1 2016-11-29 13:25:57 +00:00
Peter Bacon Darwin e8f9cbfdce chore(bower): set clone depth to speed up releases
We already use `git clone ... --depth=1` for the `code.angularjs.org`
repository, which speeds up the cloning of the repository.
2016-11-29 13:25:57 +00:00
Peter Bacon Darwin d4863a82fa chore(npm-bundle-deps): remove unused script
This became reduntant as of 507ee2d9ba
2016-11-29 13:25:57 +00:00
Peter Bacon Darwin 736b6c7fed style(*): fix no-useless-escape eslint errors 2016-11-29 13:25:56 +00:00
Peter Bacon Darwin 1dedcdf2bc docs(*): switch from npm to yarn 2016-11-29 13:25:56 +00:00
Peter Bacon Darwin 05c3336f92 chore(dependencies): USE YARN (and node 6) 2016-11-29 13:24:50 +00:00
Martin Staffa d1e4f5728c chore(docs-app): improve deprecation box layout
Deprecated boxes for APIs appear right under the header and were missing
a bit of margin. Boxes for methods still look good even with the
additional margin.
2016-11-28 19:01:43 +01:00
Wesley Cho 9f61e74be3 docs($rootScope): add note about watching File objects
- Add note recommending against watching `File` objects with deep watchers

Closes #15440
2016-11-28 18:50:36 +01:00
Wesley Cho 4059600d20 docs(*): add deprecation notice for angular.lowercase/uppercase
Closes #15441
Closes #14316
2016-11-28 18:50:36 +01:00
Georgios Kalpakas c625b0d568 chore(docs): use correct script-URL for plnkr on snapshot
Fixes #15437

Closes #15438
2016-11-28 12:14:55 +02:00
Wesley Cho 04cbe1e74f refactor($q): replace occurrences of .when() with .resolve()
Related to #13709.

Closes #15442
2016-11-28 12:02:10 +02:00
Georgios Kalpakas 9399d68d98 docs(*): document the breaking change introduced in e1da4be (#15434)
Closes #15434
2016-11-25 11:38:50 +00:00
Peter Bacon Darwin 4a320ab9f0 docs(CHANGELOG): add missing feature to 1.6.0-rc.0 2016-11-25 09:59:14 +00:00
Georgios Kalpakas 44f9ae6126 docs(input[number]): fix typo 2016-11-25 10:44:39 +02:00
Peter Bacon Darwin cdb9e08f4e docs(CHANGELOG): add missing "closes" link 2016-11-24 21:34:31 +00:00
178 changed files with 14108 additions and 29149 deletions
+1 -2
View File
@@ -1,2 +1 @@
4
6
+5 -12
View File
@@ -1,7 +1,7 @@
language: node_js
sudo: false
node_js:
- '4.4'
- '6'
cache:
directories:
@@ -36,19 +36,12 @@ addons:
packages:
- g++-4.8
install:
# Check the size of caches
- du -sh ./node_modules ./bower_components/ ./docs/bower_components/ || true
# - npm config set registry http://23.251.144.68
# Disable the spinner, it looks bad on Travis
- npm config set spin false
# Log HTTP requests
- npm config set loglevel http
#- npm install -g npm@2.5
# Install npm dependencies and ensure that npm cache is not stale
- npm install
before_install:
- curl -o- -L https://raw.githubusercontent.com/yarnpkg/yarn/2a0afc73210c7a82082585283e518eeb88ca19ae/scripts/install-latest.sh | bash -s -- --version 0.17.9
- export PATH=$HOME/.yarn/bin:$PATH
before_script:
- du -sh ./node_modules ./bower_components/ ./docs/bower_components/ || true
- ./scripts/travis/before_build.sh
script:
+1888 -12
View File
File diff suppressed because it is too large Load Diff
+7 -3
View File
@@ -209,7 +209,9 @@ 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.
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 `yarn 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
@@ -229,7 +231,8 @@ Any line of the commit message cannot be longer 100 characters! This allows the
to read on GitHub as well as in various git tools.
### Revert
If the commit reverts a previous commit, it should begin with `revert: `, followed by the header of the reverted commit. In the body it should say: `This reverts commit <hash>.`, where the hash is the SHA of the commit being reverted.
If the commit reverts a previous commit, it should begin with `revert: `, followed by the header of the reverted commit.
In the body it should say: `This reverts commit <hash>.`, where the hash is the SHA of the commit being reverted.
### Type
Must be one of the following:
@@ -266,7 +269,8 @@ The body should include the motivation for the change and contrast this with pre
The footer should contain any information about **Breaking Changes** and is also the place to
[reference GitHub issues that this commit closes][closing-issues].
**Breaking Changes** should start with the word `BREAKING CHANGE:` with a space or two newlines. The rest of the commit message is then used for this.
**Breaking Changes** should start with the word `BREAKING CHANGE:` with a space or two newlines.
The rest of the commit message is then used for this.
A detailed explanation can be found in this [document][commit-message-format].
+56 -16
View File
@@ -10,26 +10,63 @@ var path = require('path');
var e2e = require('./test/e2e/tools');
var semver = require('semver');
var fs = require('fs');
var exec = require('shelljs').exec;
var pkg = require(__dirname + '/package.json');
var useNodeVersion = fs.readFileSync('.nvmrc', 'utf8');
if (!semver.satisfies(process.version, useNodeVersion)) {
throw new Error('Invalid node version; please use node v' + useNodeVersion);
// Node.js version checks
if (!semver.satisfies(process.version, pkg.engines.node)) {
reportOrFail('Invalid node version (' + process.version + '). ' +
'Please use a version that satisfies ' + pkg.engines.node);
}
// Yarn version checks
var expectedYarnVersion = pkg.engines.yarn;
var currentYarnVersion = exec('yarn --version', {silent: true}).stdout.trim();
if (!semver.satisfies(currentYarnVersion, expectedYarnVersion)) {
reportOrFail('Invalid yarn version (' + currentYarnVersion + '). ' +
'Please use a version that satisfies ' + expectedYarnVersion);
}
// Grunt CLI version checks
var expectedGruntVersion = pkg.engines.grunt;
var currentGruntVersions = exec('grunt --version', {silent: true}).stdout;
var match = /^grunt-cli v(.+)$/m.exec(currentGruntVersions);
if (!match) {
reportOrFail('Unable to compute the current grunt-cli version. We found:\n' +
currentGruntVersions);
} else {
if (!semver.satisfies(match[1], expectedGruntVersion)) {
reportOrFail('Invalid grunt-cli version (' + match[1] + '). ' +
'Please use a version that satisfies ' + expectedGruntVersion);
}
}
// Ensure Node.js dependencies have been installed
if (!process.env.TRAVIS && !process.env.JENKINS_HOME) {
var yarnOutput = exec('yarn install');
if (yarnOutput.code !== 0) {
throw new Error('Yarn install failed: ' + yarnOutput.stderr);
}
}
module.exports = function(grunt) {
//grunt plugins
// this loads all the node_modules that start with `grunt-` as plugins
require('load-grunt-tasks')(grunt);
// load additional grunt tasks
grunt.loadTasks('lib/grunt');
grunt.loadNpmTasks('angular-benchpress');
// compute version related info for this build
var NG_VERSION = versionInfo.currentVersion;
NG_VERSION.cdn = versionInfo.cdnVersion;
var dist = 'angular-' + NG_VERSION.full;
if (versionInfo.cdnVersion == null) {
throw new Error('Unable to read CDN version, are you offline or has the CDN not been properly pushed?');
throw new Error('Unable to read CDN version, are you offline or has the CDN not been properly pushed?\n' +
'Perhaps you want to set the NG1_BUILD_NO_REMOTE_VERSION_REQUESTS environment variable?');
}
//config
@@ -292,10 +329,9 @@ module.exports = function(grunt) {
},
shell: {
'npm-install': {
command: 'node scripts/npm/check-node-modules.js'
'install-node-dependencies': {
command: 'yarn'
},
'promises-aplus-tests': {
options: {
stdout: false,
@@ -322,13 +358,6 @@ module.exports = function(grunt) {
}
});
// global beforeEach task
if (!process.env.TRAVIS) {
grunt.task.run('shell:npm-install');
}
//alias tasks
grunt.registerTask('test', 'Run unit, docs and e2e tests with Karma', ['eslint', 'package', 'test:unit', 'test:promises-aplus', 'tests:docs', 'test:protractor']);
grunt.registerTask('test:jqlite', 'Run the unit tests with Karma' , ['tests:jqlite']);
@@ -350,3 +379,14 @@ module.exports = function(grunt) {
grunt.registerTask('ci-checks', ['ddescribe-iit', 'merge-conflict', 'eslint']);
grunt.registerTask('default', ['package']);
};
function reportOrFail(message) {
if (process.env.TRAVIS || process.env.JENKINS_HOME) {
throw new Error(message);
} else {
console.log('===============================================================================');
console.log(message);
console.log('===============================================================================');
}
}
+1 -1
View File
@@ -1,6 +1,6 @@
The MIT License
Copyright (c) 2010-2016 Google, Inc. http://angularjs.org
Copyright (c) 2010-2017 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
+1 -1
View File
@@ -95,7 +95,7 @@ You can mention him in the relevant thread like this: `@btford`.
> Thanks for submitting this issue!
> Unfortunately, we don't think this functionality belongs in core.
> The good news is that you could easily implement this as a third-party module and publish it on Bower and/or npm.
> The good news is that you could easily implement this as a third-party module and publish it on Bower and/or to the npm repository.
## Assigning Work
+44
View File
@@ -0,0 +1,44 @@
'use strict';
angular
.module('animationBenchmark', ['ngAnimate'], config)
.controller('BenchmarkController', BenchmarkController);
// Functions - Definitions
function config($compileProvider) {
$compileProvider
.commentDirectivesEnabled(false)
.cssClassDirectivesEnabled(false)
.debugInfoEnabled(false);
}
function BenchmarkController($scope) {
var self = this;
var itemCount = 1000;
var items = (new Array(itemCount + 1)).join('.').split('');
benchmarkSteps.push({
name: 'create',
fn: function() {
$scope.$apply(function() {
self.items = items;
});
}
});
benchmarkSteps.push({
name: '$digest',
fn: function() {
$scope.$root.$digest();
}
});
benchmarkSteps.push({
name: 'destroy',
fn: function() {
$scope.$apply(function() {
self.items = [];
});
}
});
}
+22
View File
@@ -0,0 +1,22 @@
/* eslint-env node */
'use strict';
module.exports = function(config) {
config.set({
scripts: [
{
id: 'jquery',
src: 'jquery-noop.js'
}, {
id: 'angular',
src: '/build/angular.js'
}, {
id: 'angular-animate',
src: '/build/angular-animate.js'
}, {
src: 'app.js'
}
]
});
};
+1
View File
@@ -0,0 +1 @@
// Override me with ?jquery=/bower_components/jquery/dist/jquery.js
+28
View File
@@ -0,0 +1,28 @@
<style>
[ng-cloak] { display: none !important; }
.animation-container .ng-enter,
.animation-container .ng-leave {
transition: all 0.1s;
}
.animation-container .ng-enter,
.animation-container .ng-leave.ng-leave-active {
opacity: 0;
}
.animation-container .ng-enter.ng-enter-active,
.animation-container .ng-leave {
opacity: 1;
}
</style>
<div ng-app="animationBenchmark" ng-cloak ng-controller="BenchmarkController as bm">
<div class="container-fluid">
<h2>Large collection of elements animated in and out with ngAnimate</h2>
<div class="animation-container">
<div ng-repeat="i in bm.items track by $index">
Just a plain ol' element
</div>
</div>
</div>
</div>
+108
View File
@@ -0,0 +1,108 @@
'use strict';
var app = angular.module('ngClassBenchmark', []);
app.controller('DataController', function DataController($scope) {
this.init = function() {
this.numberOfTodos = 1000;
this.implementation = 'tableOptimized';
this.completedPeriodicity = 3;
this.importantPeriodicity = 13;
this.urgentPeriodicity = 29;
this.createTodos(100);
this.setTodosValuesWithSeed(0);
};
this.clearTodos = function() {
this.todos = null;
};
this.createTodos = function(count) {
var i;
this.todos = [];
for (i = 0; i < count; i++) {
this.todos.push({
id: i + 1,
completed: false,
important: false,
urgent: false
});
}
};
this.setTodosValuesWithSeed = function(offset) {
var i, todo;
for (i = 0; i < this.todos.length; i++) {
todo = this.todos[i];
todo.completed = 0 === (i + offset) % this.completedPeriodicity;
todo.important = 0 === (i + offset) % this.importantPeriodicity;
todo.urgent = 0 === (i + offset) % this.urgentPeriodicity;
}
};
this.init();
benchmarkSteps.push({
name: 'setup',
fn: function() {
$scope.$apply();
this.clearTodos();
this.createTodos(this.numberOfTodos);
}.bind(this)
});
benchmarkSteps.push({
name: 'create',
fn: function() {
// initialize data for first time that will construct the DOM
this.setTodosValuesWithSeed(0);
$scope.$apply();
}.bind(this)
});
benchmarkSteps.push({
name: '$apply',
fn: function() {
$scope.$apply();
}
});
benchmarkSteps.push({
name: 'update',
fn: function() {
// move everything but completed
this.setTodosValuesWithSeed(3);
$scope.$apply();
}.bind(this)
});
benchmarkSteps.push({
name: 'unclass',
fn: function() {
// remove all classes
this.setTodosValuesWithSeed(NaN);
$scope.$apply();
}.bind(this)
});
benchmarkSteps.push({
name: 'class',
fn: function() {
// add all classes as the initial state
this.setTodosValuesWithSeed(0);
$scope.$apply();
}.bind(this)
});
benchmarkSteps.push({
name: 'destroy',
fn: function() {
this.clearTodos();
$scope.$apply();
}.bind(this)
});
});
+15
View File
@@ -0,0 +1,15 @@
/* eslint-env node */
'use strict';
module.exports = function(config) {
config.set({
scripts: [{
id: 'angular',
src: '/build/angular.js'
},
{
src: 'app.js'
}]
});
};
+177
View File
@@ -0,0 +1,177 @@
<style>
.gold {
background: gold;
}
.silver {
background: silver;
}
.table tbody tr > td.success {
background-color: #dff0d8;
}
.table tbody tr > td.error {
background-color: #f2dede;
}
.table tbody tr > td.warning {
background-color: #fcf8e3;
}
.table tbody tr > td.info {
background-color: #d9edf7;
}
.completed {
text-decoration: line-through;
}
.important {
font-weight: bold;
}
.urgent {
color: red;
}
</style>
<div ng-app="ngClassBenchmark" ng-cloak class="container-fluid">
<div ng-controller="DataController as benchmark" class="row">
<div class="col-lg-12">
<div class="well">
<h3>Parameters</h3>
<br>
<p>
<label>Number of todos</label><br>
<input type="number" ng-model="benchmark.numberOfTodos">
</p>
<br>
<p>
<label>Implementation</label><br>
<div class="radio">
<label>
<input ng-model="benchmark.implementation" value="tableOptimized"
type="radio" name="implementation">
Table optimized <br>
<code>ng-class="todo.completed && 'success'"</code>
</label>
</div>
<div class="radio">
<label>
<input ng-model="benchmark.implementation" value="table"
type="radio" name="implementation">
Table <br>
<code>ng-class="{success: todo.completed}"</code>
</label>
</div>
<div class="radio">
<label>
<input ng-model="benchmark.implementation" value="list"
type="radio" name="implementation">
List <br>
<code>ng-class="{completed: todo.completed, urgent: todo.urgent, important: todo.important"}</code>
</label>
</div>
<div class="radio">
<label>
<input ng-model="benchmark.implementation" value="singleOptimized"
type="radio" name="implementation">
Single ngClass optimized <br>
<code>
ng-class="{'panel-success': !!benchmark.todos, 'panel-danger': !benchmark.todos}"
</code>
</label>
</div>
<div class="radio">
<label>
<input ng-model="benchmark.implementation" value="single"
type="radio" name="implementation">
Single ngClass <br>
<code>
ng-class="{'panel-success': benchmark.todos, 'panel-danger': !benchmark.todos}"
</code>
</label>
</div>
</p>
</div>
<br>
<h3>Example</h3>
<div ng-switch="benchmark.implementation">
<table ng-switch-when="tableOptimized" class="table">
<thead>
<tr>
<th>todo #id</th>
<th>completed?</th>
<th>urgent?</th>
<th>important?</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="todo in benchmark.todos track by todo.id"
ng-class="todo.completed && 'active'"
ng-class-even="todo.completed && todo.important && 'gold'"
ng-class-odd="todo.completed && todo.important && 'silver'"
>
<td>#{{todo.id}}</td>
<td>{{todo.completed}}</td>
<td ng-class="todo.urgent && 'danger'">{{todo.urgent}}</td>
<td ng-class="todo.important && 'success'">{{todo.important}}</td>
</tr>
</tbody>
</table>
<table ng-switch-when="table" class="table">
<thead>
<tr>
<th>todo #id</th>
<th>completed?</th>
<th>urgent?</th>
<th>important?</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="todo in benchmark.todos track by todo.id"
ng-class="{active: todo.completed}"
ng-class-even="{gold: todo.completed && todo.important}"
ng-class-odd="{silver: todo.completed && todo.important}"
>
<td>#{{todo.id}}</td>
<td>{{todo.completed}}</td>
<td ng-class="{danger: todo.urgent}">{{todo.urgent}}</td>
<td ng-class="{success: todo.important}">{{todo.important}}</td>
</tr>
</tbody>
</table>
<ul ng-switch-when="list">
<li ng-repeat="todo in benchmark.todos track by todo.id"
ng-class="{
completed: todo.completed,
urgent: todo.urgent,
important: todo.important
}">#{{todo.id}}</li>
</ul>
<div ng-switch-when="singleOptimized"
class="panel"
ng-class="{'panel-success': !!benchmark.todos, 'panel-danger': !benchmark.todos}">
<div class="panel-heading">
<h3 class="panel-title">Information</h3>
</div>
<div class="panel-body"> The title is green because there are todos... </div>
</div>
<div ng-switch-when="single"
class="panel"
ng-class="{'panel-success': benchmark.todos, 'panel-danger': !benchmark.todos}">
<div class="panel-heading">
<h3 class="panel-title">Information</h3>
</div>
<div class="panel-body"> The title is green because there are todos... </div>
</div>
</div>
</div>
</div>
</div>
<br><br><br>
-208
View File
@@ -1,208 +0,0 @@
#!/usr/bin/env node
// TODO(vojta): pre-commit hook for validating messages
// TODO(vojta): report errors, currently Q silence everything which really sucks
'use strict';
var child = require('child_process');
var fs = require('fs');
var util = require('util');
var q = require('qq');
var GIT_LOG_CMD = 'git log --grep="%s" -E --format=%s %s..HEAD';
var GIT_TAG_CMD = 'git describe --tags --abbrev=0';
var HEADER_TPL = '<a name="%s"></a>\n# %s (%s)\n\n';
var LINK_ISSUE = '[#%s](https://github.com/angular/angular.js/issues/%s)';
var LINK_COMMIT = '[%s](https://github.com/angular/angular.js/commit/%s)';
var EMPTY_COMPONENT = '$$';
var warn = function() {
console.log('WARNING:', util.format.apply(null, arguments));
};
var parseRawCommit = function(raw) {
if (!raw) return null;
var lines = raw.split('\n');
var msg = {}, match;
msg.hash = lines.shift();
msg.subject = lines.shift();
msg.closes = [];
msg.breaks = [];
lines.forEach(function(line) {
match = line.match(/(?:Closes|Fixes)\s#(\d+)/);
if (match) msg.closes.push(parseInt(match[1], 10));
});
match = raw.match(/BREAKING CHANGE:([\s\S]*)/);
if (match) {
msg.breaking = match[1];
}
msg.body = lines.join('\n');
match = msg.subject.match(/^(.*)\((.*)\):\s(.*)$/);
if (!match || !match[1] || !match[3]) {
warn('Incorrect message: %s %s', msg.hash, msg.subject);
return null;
}
msg.type = match[1];
msg.component = match[2];
msg.subject = match[3];
return msg;
};
var linkToIssue = function(issue) {
return util.format(LINK_ISSUE, issue, issue);
};
var linkToCommit = function(hash) {
return util.format(LINK_COMMIT, hash.substr(0, 8), hash);
};
var currentDate = function() {
var now = new Date();
var pad = function(i) {
return ('0' + i).substr(-2);
};
return util.format('%d-%s-%s', now.getFullYear(), pad(now.getMonth() + 1), pad(now.getDate()));
};
var printSection = function(stream, title, section, printCommitLinks) {
printCommitLinks = printCommitLinks === undefined ? true : printCommitLinks;
var components = Object.getOwnPropertyNames(section).sort();
if (!components.length) return;
stream.write(util.format('\n## %s\n\n', title));
components.forEach(function(name) {
var prefix = '-';
var nested = section[name].length > 1;
if (name !== EMPTY_COMPONENT) {
if (nested) {
stream.write(util.format('- **%s:**\n', name));
prefix = ' -';
} else {
prefix = util.format('- **%s:**', name);
}
}
section[name].forEach(function(commit) {
if (printCommitLinks) {
stream.write(util.format('%s %s\n (%s', prefix, commit.subject, linkToCommit(commit.hash)));
if (commit.closes.length) {
stream.write(',\n ' + commit.closes.map(linkToIssue).join(', '));
}
stream.write(')\n');
} else {
stream.write(util.format('%s %s\n', prefix, commit.subject));
}
});
});
stream.write('\n');
};
var readGitLog = function(grep, from) {
var deferred = q.defer();
// TODO(vojta): if it's slow, use spawn and stream it instead
child.exec(util.format(GIT_LOG_CMD, grep, '%H%n%s%n%b%n==END==', from), function(code, stdout, stderr) {
var commits = [];
stdout.split('\n==END==\n').forEach(function(rawCommit) {
var commit = parseRawCommit(rawCommit);
if (commit) commits.push(commit);
});
deferred.resolve(commits);
});
return deferred.promise;
};
var writeChangelog = function(stream, commits, version) {
var sections = {
fix: {},
feat: {},
perf: {},
breaks: {}
};
commits.forEach(function(commit) {
var section = sections[commit.type];
var component = commit.component || EMPTY_COMPONENT;
if (section) {
section[component] = section[component] || [];
section[component].push(commit);
}
if (commit.breaking) {
sections.breaks[component] = sections.breaks[component] || [];
sections.breaks[component].push({
subject: util.format('due to %s,\n %s', linkToCommit(commit.hash), commit.breaking),
hash: commit.hash,
closes: []
});
}
});
stream.write(util.format(HEADER_TPL, version, version, currentDate()));
printSection(stream, 'Bug Fixes', sections.fix);
printSection(stream, 'Features', sections.feat);
printSection(stream, 'Performance Improvements', sections.perf);
printSection(stream, 'Breaking Changes', sections.breaks, false);
};
var getPreviousTag = function() {
var deferred = q.defer();
child.exec(GIT_TAG_CMD, function(code, stdout, stderr) {
if (code) deferred.reject('Cannot get the previous tag.');
else deferred.resolve(stdout.replace('\n', ''));
});
return deferred.promise;
};
var generate = function(version, file) {
getPreviousTag().then(function(tag) {
console.log('Reading git log since', tag);
readGitLog('^fix|^feat|^perf|BREAKING', tag).then(function(commits) {
console.log('Parsed', commits.length, 'commits');
console.log('Generating changelog to', file || 'stdout', '(', version, ')');
writeChangelog(file ? fs.createWriteStream(file) : process.stdout, commits, version);
});
});
};
// publish for testing
exports.parseRawCommit = parseRawCommit;
exports.printSection = printSection;
// hacky start if not run by jasmine :-D
if (process.argv.join('').indexOf('jasmine-node') === -1) {
generate(process.argv[2], process.argv[3]);
}
-108
View File
@@ -1,108 +0,0 @@
/* global describe: false, beforeEach: false, afterEach: false, it: false, expect: false */
'use strict';
describe('changelog.js', function() {
var ch = require('./changelog');
describe('parseRawCommit', function() {
it('should parse raw commit', function() {
var msg = ch.parseRawCommit(
'9b1aff905b638aa274a5fc8f88662df446d374bd\n' +
'feat(scope): broadcast $destroy event on scope destruction\n' +
'perf testing shows that in chrome this change adds 5-15% overhead\n' +
'when destroying 10k nested scopes where each scope has a $destroy listener\n');
expect(msg.type).toBe('feat');
expect(msg.hash).toBe('9b1aff905b638aa274a5fc8f88662df446d374bd');
expect(msg.subject).toBe('broadcast $destroy event on scope destruction');
expect(msg.body).toBe('perf testing shows that in chrome this change adds 5-15% overhead\n' +
'when destroying 10k nested scopes where each scope has a $destroy listener\n');
expect(msg.component).toBe('scope');
});
it('should parse closed issues', function() {
var msg = ch.parseRawCommit(
'13f31602f396bc269076ab4d389cfd8ca94b20ba\n' +
'feat(ng-list): Allow custom separator\n' +
'bla bla bla\n\n' +
'Closes #123\nCloses #25\n');
expect(msg.closes).toEqual([123, 25]);
});
it('should parse breaking changes', function() {
var msg = ch.parseRawCommit(
'13f31602f396bc269076ab4d389cfd8ca94b20ba\n' +
'feat(ng-list): Allow custom separator\n' +
'bla bla bla\n\n' +
'BREAKING CHANGE: first breaking change\nsomething else\n' +
'another line with more info\n');
expect(msg.breaking).toEqual(' first breaking change\nsomething else\nanother line with more info\n');
});
});
describe('printSection', function() {
var output;
var streamMock = {
write: function(str) {
output += str;
}
};
beforeEach(function() {
output = '';
});
it('should add a new line at the end of each breaking change list item ' +
'when there is 1 item per component', function() {
var title = 'test';
var printCommitLinks = false;
var section = {
module1: [{subject: 'breaking change 1'}],
module2: [{subject: 'breaking change 2'}]
};
var expectedOutput =
'\n## test\n\n' +
'- **module1:** breaking change 1\n' +
'- **module2:** breaking change 2\n' +
'\n';
ch.printSection(streamMock, title, section, printCommitLinks);
expect(output).toBe(expectedOutput);
});
it('should add a new line at the end of each breaking change list item ' +
'when there are multiple items per component', function() {
var title = 'test';
var printCommitLinks = false;
var section = {
module1: [
{subject: 'breaking change 1.1'},
{subject: 'breaking change 1.2'}
],
module2: [
{subject: 'breaking change 2.1'},
{subject: 'breaking change 2.2'}
]
};
var expectedOutput =
'\n## test\n\n' +
'- **module1:**\n' +
' - breaking change 1.1\n' +
' - breaking change 1.2\n' +
'- **module2:**\n' +
' - breaking change 2.1\n' +
' - breaking change 2.2\n' +
'\n';
ch.printSection(streamMock, title, section, printCommitLinks);
expect(output).toBe(expectedOutput);
});
});
});
+1
View File
@@ -0,0 +1 @@
.visible-phone{display:none}.visible-desktop{display:block}.navbar{display:block}.navbar .container{padding:0 16px;width:auto}.navbar .brand{float:left;margin:8px 80px 0 8px;padding:0}.navbar .brand a{display:block;height:30px;margin:6px 0 5px 0;overflow:hidden;padding:0;width:117px}.navbar .nav{float:right}.navbar .nav .dropdown-toggle{color:rgba(255,255,255,0.87);font-size:16px;font-weight:300;line-height:56px;padding:0 24px;text-transform:uppercase;transition:all .3s}.navbar .nav .dropdown-toggle:hover,.navbar .nav .dropdown-toggle:active,.navbar .nav .dropdown-toggle:focus{background:#37474F;color:#fff}.navbar .nav .dropdown-menu{background:#37474F;border:none;border-radius:0;box-shadow:0 0 16px rgba(0,0,0,0.12),0 16px 16px rgba(0,0,0,0.24);color:#fff;left:auto;margin:0;padding:0;right:0}.navbar .nav .dropdown-menu:after,.navbar .nav .dropdown-menu:before{display:none}.navbar .nav .dropdown-menu li{border-bottom:1px solid rgba(38,50,56,0.56);box-sizing:border-box;line-height:48px}.navbar .nav .dropdown-menu li:last-child{border:none}.navbar .nav .dropdown-menu a{background:#37474F;color:#fff;font-weight:300;line-height:48px;padding:0 16px;transition:all .2s}.navbar .nav .dropdown-menu a:hover,.navbar .nav .dropdown-menu a:focus{background:#455A64}.navbar .navbar-search{left:200px;margin:0;position:absolute;right:440px;top:8px;width:auto}.navbar .navbar-search i{color:#546E7A;font-size:16px;left:12px;position:absolute;top:11px}.navbar .navbar-search .search-query{background:#37474F;border:none;border-radius:2px;box-shadow:none;box-sizing:border-box;color:#546E7A;font-size:14px;height:40px;width:100%;padding:0 16px 0 32px;text-shadow:none;transition:all .3s}.navbar .navbar-search .search-query:-webkit-autofill,.navbar .navbar-search .search-query:-webkit-autofill:hover,.navbar .navbar-search .search-query:-webkit-autofill:focus{background-color:#fff;transition:background-color 5000s ease-in-out 0s;-webkit-text-fill-color:#455A64}.navbar .navbar-search .search-query:hover,.navbar .navbar-search .search-query:active,.navbar .navbar-search .search-query:focus{background:#fff;box-shadow:inset 0 2px 4px rgba(0,0,0,0.24);color:#2196F3}.navbar .navbar-search .search-query::-webkit-input-placeholder{color:#546E7A}.navbar .navbar-search .search-query::-moz-placeholder{color:#546E7A}.navbar .navbar-search .search-query:-ms-input-placeholder{color:#546E7A}.navbar .navbar-search .search-query:-moz-placeholder{color:#546E7A}#navbar-main .navbar-inner{background:#263238;height:56px}#navbar-notice{z-index:1029;top:56px}#navbar-notice .navbar-inner{background:#ECEFF1;box-shadow:0 0 3px rgba(0,0,0,0.12),0 3px 3px rgba(0,0,0,0.24);height:auto}.site-notice{padding:4px 0;text-align:center;font-size:13px;margin:0}@media handheld and (max-width: 800px), screen and (max-device-width: 800px), screen and (max-width: 800px){.visible-phone{display:block}.visible-desktop{display:none}}@media handheld and (max-width: 800px), screen and (max-device-width: 800px), screen and (max-width: 800px){.homepage .container{padding:16px;width:auto}.homepage .span1{width:auto}.homepage .span2{width:auto}.homepage .span3{width:auto}.homepage .span4{width:auto}.homepage .span5{width:auto}.homepage .span6{width:auto}.homepage .span7{width:auto}.homepage .span8{width:auto}.homepage .span9{width:auto}.homepage .span10{width:auto}.homepage .navbar .container{padding:0 8px}.homepage #navbar-main .navbar-inner{height:40px}.homepage #navbar-main .brand{margin:6px 0 0 0}.homepage #navbar-main .brand a{margin:0}.homepage #navbar-main .nav{margin:0}.homepage #navbar-main .nav .dropdown-toggle{font-size:12px;line-height:40px;padding:0 8px}.homepage #navbar-main .dropdown-menu a{padding:0 8px}.homepage #navbar-main .navbar-search{background:#263238;border-bottom:1px solid #263238;left:0;right:0;top:100%}.homepage #navbar-main .navbar-search i{left:12px;top:7px}.homepage #navbar-main .navbar-search .search-query{border-radius:0;height:32px}.homepage #navbar-notice{top:40px}.homepage #navbar-notice .site-notice{font-size:11px}.homepage .hero{padding:80px 32px 32px 32px}.homepage .hero h2{background-size:230px 60px;height:60px;width:230px}}
+101 -6
View File
@@ -53,13 +53,13 @@ h1,h2,h3,h4,h5,h6 {
}
.header .brand {
padding-top: 6px;
padding-bottom: 0px;
}
.header .brand img {
margin-top: 5px;
height: 30px;
margin-top: 0;
height: auto;
vertical-align: top;
}
.docs-search {
@@ -82,6 +82,11 @@ h1,h2,h3,h4,h5,h6 {
margin-right: 10px;
}
.navbar .navbar-search i {
top: 13px;
font-size: 12px;
}
.docs-search > .search-query:focus {
outline: 0;
}
@@ -297,6 +302,7 @@ iframe.example {
}
.search-results-container {
position: relative;
padding-bottom: 1em;
border-top: 1px solid #111;
background: #181818;
@@ -435,15 +441,17 @@ iframe.example {
background: #f1f1f1;
}
.sup-header {
#navbar-sub {
padding-top: 10px;
padding-bottom: 5px;
background: rgba(245,245,245,0.88);
box-shadow: 0 0 2px #999;
z-index: 1028;
top: 83px;
}
.main-body-grid {
margin-top: 120px;
margin-top: 144px;
position: relative;
}
@@ -454,7 +462,7 @@ iframe.example {
.main-body-grid > .grid-left {
position: fixed;
top: 120px;
top: 144px;
bottom: 0;
overflow: auto;
}
@@ -662,6 +670,10 @@ ul.events > li {
max-width: 100%;
}
.deprecation {
margin-top: 15px;
}
.deprecation .title {
float: left;
margin-right: 5px;
@@ -823,3 +835,86 @@ ul.events > li {
iframe[name="example-anchoringExample"] {
height: 400px;
}
/*
angular-topnav.css and bootstrap overrides
*/
.navbar .navbar-inner .container {
padding: 0 16px;
width: auto;
height: auto;
}
.navbar .nav > li {
float: left;
}
.navbar-nav .open .dropdown-menu {
position: absolute;
float: left;
}
.navbar-nav .open .dropdown-menu > li > a {
line-height: 48px;
}
#navbar-main .navbar-inner, #navbar-notice .navbar-inner {
box-shadow: none;
}
#navbar-sub .container {
max-width: 970px;
}
.nav .open > a, .nav .open > a:hover, .nav .open > a:focus {
background-color: inherit;
}
@media handheld and (max-width:800px), screen and (max-device-width:800px), screen and (max-width:800px) {
.navbar {
min-height: auto;
}
.search-results-container {
top: 32px;
overflow: auto;
max-height: 85vh;
padding-bottom: 0;
position: static;
}
.search-close {
right: 1px;
margin-left: 0;
top: 41px;
padding: 5px 10px;
border-top-right-radius: 0;
border-top-left-radius: 0;
box-shadow: none;
width: auto;
bottom: auto;
left: auto;
}
.navbar-nav .open .dropdown-menu > li > a, .navbar-nav .open .dropdown-menu .dropdown-header {
padding: 0 8px;
}
.homepage #navbar-notice {
top: 72px;
}
#navbar-notice .navbar-inner {
box-shadow: 0 0 3px rgba(0, 0, 0, .12), 0 3px 3px rgba(0, 0, 0, .24)
}
#navbar-sub {
position: relative;
top: 17px;
margin-top: 80px;
padding-bottom: 0;
margin-bottom: 0;
}
}
+1 -1
View File
@@ -4,7 +4,7 @@
/* global importScripts, lunr */
// Load up the lunr library
importScripts('../components/lunr.js-0.5.12/lunr.min.js');
importScripts('../components/lunr-0.7.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
+2 -2
View File
@@ -18,8 +18,8 @@ describe('doc.angularjs.org', function() {
var ngBindLink = element(by.css('.definition-table td a[href="api/ng/directive/ngClick"]'));
ngBindLink.click();
var pageBody = element(by.css('h1'));
expect(pageBody.getText()).toEqual('ngClick');
var mainHeader = element(by.css('.main-body h1 '));
expect(mainHeader.getText()).toEqual('ngClick');
});
+11 -9
View File
@@ -44,30 +44,31 @@ describe('docs.angularjs.org', function() {
var ngBindLink = element(by.css('.definition-table td a[href="api/ng/directive/ngClick"]'));
ngBindLink.click();
var pageBody = element(by.css('h1'));
expect(pageBody.getText()).toEqual('ngClick');
var mainHeader = element(by.css('.main-body h1 '));
expect(mainHeader.getText()).toEqual('ngClick');
});
it('should be resilient to trailing slashes', function() {
browser.get('build/docs/index-production.html#!/api/ng/function/angular.noop/');
var pageBody = element(by.css('h1'));
expect(pageBody.getText()).toEqual('angular.noop');
var mainHeader = element(by.css('.main-body h1 '));
expect(mainHeader.getText()).toEqual('angular.noop');
});
it('should be resilient to trailing "index"', function() {
browser.get('build/docs/index-production.html#!/api/ng/function/angular.noop/index');
var pageBody = element(by.css('h1'));
expect(pageBody.getText()).toEqual('angular.noop');
var mainHeader = element(by.css('.main-body h1 '));
expect(mainHeader.getText()).toEqual('angular.noop');
});
it('should be resilient to trailing "index/"', function() {
browser.get('build/docs/index-production.html#!/api/ng/function/angular.noop/index/');
var pageBody = element(by.css('h1'));
expect(pageBody.getText()).toEqual('angular.noop');
var mainHeader = element(by.css('.main-body h1 '));
expect(mainHeader.getText()).toEqual('angular.noop');
});
@@ -78,7 +79,8 @@ describe('docs.angularjs.org', function() {
it('should display an error if the page does not exist', function() {
browser.get('build/docs/index-production.html#!/api/does/not/exist');
expect(element(by.css('h1')).getText()).toBe('Oops!');
var mainHeader = element(by.css('.main-body h1 '));
expect(mainHeader.getText()).toEqual('Oops!');
});
});
+1 -1
View File
@@ -63,7 +63,7 @@ angular.module('DocsController', ['currentVersionData'])
$scope.loading = 0;
var INDEX_PATH = /^(\/|\/index[^\.]*.html)$/;
var INDEX_PATH = /^(\/|\/index[^.]*.html)$/;
if (!$location.path() || INDEX_PATH.test($location.path())) {
$location.path('/api').replace();
}
+1 -1
View File
@@ -3,7 +3,7 @@
angular.module('errors', ['ngSanitize'])
.filter('errorLink', ['$sanitize', function($sanitize) {
var LINKY_URL_REGEXP = /((ftp|https?):\/\/|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s\.;,\(\)\{\}<>]/g,
var LINKY_URL_REGEXP = /((ftp|https?):\/\/|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s.;,(){}<>]/g,
MAILTO_REGEXP = /^mailto:/,
STACK_TRACE_REGEXP = /:\d+:\d+$/;
+6 -5
View File
@@ -114,7 +114,7 @@ angular.module('examples', [])
ctrl.prepareExampleData = function() {
if (ctrl.example.manifest) {
return $q.when(ctrl.example);
return $q.resolve(ctrl.example);
}
return getExampleData(ctrl.examplePath).then(function(data) {
@@ -159,10 +159,11 @@ angular.module('examples', [])
};
// 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);
ctrl.$onInit = function() {
// Initialize the example data, so it's ready when clicking the open button.
// Otherwise pop-up blockers will prevent a new window from opening
ctrl.prepareExampleData(ctrl.example.path);
};
}]
};
}])
+1 -1
View File
@@ -72,7 +72,7 @@ angular.module('search', [])
.controller('Error404SearchCtrl', ['$scope', '$location', 'docsSearch',
function($scope, $location, docsSearch) {
docsSearch($location.path().split(/[\/\.:]/).pop()).then(function(results) {
docsSearch($location.path().split(/[/.:]/).pop()).then(function(results) {
$scope.results = {};
angular.forEach(results, function(result) {
var area = $scope.results[result.area] || [];
-10
View File
@@ -1,10 +0,0 @@
{
"name": "AngularJS-docs-app",
"dependencies": {
"jquery": "2.2.3",
"lunr.js": "0.5.12",
"open-sans-fontface": "1.0.4",
"google-code-prettify": "1.0.1",
"bootstrap": "3.1.1"
}
}
+1 -1
View File
@@ -6,7 +6,7 @@ var packagePath = __dirname;
var Package = require('dgeni').Package;
// Create and export a new Dgeni package called angularjs. This package depends upon
// the ngdoc, nunjucks, and examples packages defined in the dgeni-packages npm module.
// the ngdoc, nunjucks, and examples packages defined in the dgeni-packages node module.
module.exports = new Package('angularjs', [
require('dgeni-packages/ngdoc'),
require('dgeni-packages/nunjucks'),
+2 -2
View File
@@ -34,7 +34,7 @@ module.exports = function generateKeywordsProcessor(log, readFilesProcessor) {
var areasToSearch;
// Keywords start with "ng:" or one of $, _ or a letter
var KEYWORD_REGEX = /^((ng:|[\$_a-z])[\w\-_]+)/;
var KEYWORD_REGEX = /^((ng:|[$_a-z])[\w\-_]+)/;
// Load up the keywords to ignore, if specified in the config
if (this.ignoreWordsFile) {
@@ -67,7 +67,7 @@ module.exports = function generateKeywordsProcessor(log, readFilesProcessor) {
function extractWords(text, words, keywordMap) {
var tokens = text.toLowerCase().split(/[\.\s,`'"#]+/mg);
var tokens = text.toLowerCase().split(/[.\s,`'"#]+/mg);
_.forEach(tokens, function(token) {
var match = token.match(KEYWORD_REGEX);
if (match) {
+3 -3
View File
@@ -13,14 +13,14 @@ module.exports = function generateVersionDocProcessor(gitData) {
return {
$runAfter: ['generatePagesDataProcessor'],
$runBefore: ['rendering-docs'],
// the blacklist is to remove rogue builds that are in npm but not on code.angularjs.org
// the blacklist is to remove rogue builds that are in the npm repository but not on code.angularjs.org
blacklist: ['1.3.4-build.3588'],
$process: function(docs) {
var blacklist = this.blacklist;
var currentVersion = require('../../../build/version.json');
var output = exec('npm info angular versions --json', { silent: true }).stdout;
var allVersions = processAllVersionsResponse(JSON.parse(output));
var output = exec('yarn info angular versions --json', { silent: true }).stdout.split('\n')[0];
var allVersions = processAllVersionsResponse(JSON.parse(output).data);
docs.push({
docType: 'current-version-data',
+3 -2
View File
@@ -17,9 +17,9 @@ module.exports = function debugDeployment(getVersion) {
'../angular-sanitize.js',
'../angular-touch.js',
'../angular-animate.js',
'components/marked-' + getVersion('marked', 'node_modules', 'package.json') + '/lib/marked.js',
'components/marked-' + getVersion('marked') + '/lib/marked.js',
'js/angular-bootstrap/dropdown-toggle.js',
'components/lunr.js-' + getVersion('lunr.js') + '/lunr.js',
'components/lunr-' + getVersion('lunr') + '/lunr.js',
'components/google-code-prettify-' + getVersion('google-code-prettify') + '/src/prettify.js',
'components/google-code-prettify-' + getVersion('google-code-prettify') + '/src/lang-css.js',
'js/current-version-data.js',
@@ -32,6 +32,7 @@ module.exports = function debugDeployment(getVersion) {
'components/bootstrap-' + getVersion('bootstrap') + '/css/bootstrap.css',
'components/open-sans-fontface-' + getVersion('open-sans-fontface') + '/open-sans.css',
'css/prettify-theme.css',
'css/angular-topnav.css',
'css/docs.css',
'css/animations.css'
]
+3 -2
View File
@@ -17,9 +17,9 @@ module.exports = function defaultDeployment(getVersion) {
'../angular-sanitize.min.js',
'../angular-touch.min.js',
'../angular-animate.min.js',
'components/marked-' + getVersion('marked', 'node_modules', 'package.json') + '/lib/marked.js',
'components/marked-' + getVersion('marked') + '/lib/marked.js',
'js/angular-bootstrap/dropdown-toggle.min.js',
'components/lunr.js-' + getVersion('lunr.js') + '/lunr.min.js',
'components/lunr-' + getVersion('lunr') + '/lunr.min.js',
'components/google-code-prettify-' + getVersion('google-code-prettify') + '/src/prettify.js',
'components/google-code-prettify-' + getVersion('google-code-prettify') + '/src/lang-css.js',
'js/current-version-data.js',
@@ -32,6 +32,7 @@ module.exports = function defaultDeployment(getVersion) {
'components/bootstrap-' + getVersion('bootstrap') + '/css/bootstrap.min.css',
'components/open-sans-fontface-' + getVersion('open-sans-fontface') + '/open-sans.css',
'css/prettify-theme.css',
'css/angular-topnav.css',
'css/docs.css',
'css/animations.css'
]
+3 -2
View File
@@ -21,9 +21,9 @@ module.exports = function jqueryDeployment(getVersion) {
'../angular-sanitize.min.js',
'../angular-touch.min.js',
'../angular-animate.min.js',
'components/marked-' + getVersion('marked', 'node_modules', 'package.json') + '/lib/marked.js',
'components/marked-' + getVersion('marked') + '/lib/marked.js',
'js/angular-bootstrap/dropdown-toggle.min.js',
'components/lunr.js-' + getVersion('lunr.js') + '/lunr.min.js',
'components/lunr-' + getVersion('lunr') + '/lunr.min.js',
'components/google-code-prettify-' + getVersion('google-code-prettify') + '/src/prettify.js',
'components/google-code-prettify-' + getVersion('google-code-prettify') + '/src/lang-css.js',
'js/current-version-data.js',
@@ -36,6 +36,7 @@ module.exports = function jqueryDeployment(getVersion) {
'components/bootstrap-' + getVersion('bootstrap') + '/css/bootstrap.min.css',
'components/open-sans-fontface-' + getVersion('open-sans-fontface') + '/open-sans.css',
'css/prettify-theme.css',
'css/angular-topnav.css',
'css/docs.css',
'css/animations.css'
]
@@ -13,9 +13,9 @@ var cdnUrl = googleCdnUrl + versionInfo.cdnVersion;
// The currentVersion may not be available on the cdn (e.g. if built locally, or hasn't been pushed
// yet). This will lead to a 404, but this is preferable to loading a version with which the example
// might not work (possibly in subtle ways).
var examplesCdnUrl = versionInfo.isSnapshot ?
var examplesCdnUrl = versionInfo.currentVersion.isSnapshot ?
(angularCodeUrl + 'snapshot') :
(googleCdnUrl + (versionInfo.version || versionInfo.currentVersion));
(googleCdnUrl + (versionInfo.currentVersion.version || versionInfo.currentVersion));
module.exports = function productionDeployment(getVersion) {
return {
@@ -34,9 +34,9 @@ module.exports = function productionDeployment(getVersion) {
cdnUrl + '/angular-sanitize.min.js',
cdnUrl + '/angular-touch.min.js',
cdnUrl + '/angular-animate.min.js',
'components/marked-' + getVersion('marked', 'node_modules', 'package.json') + '/lib/marked.js',
'components/marked-' + getVersion('marked') + '/lib/marked.js',
'js/angular-bootstrap/dropdown-toggle.min.js',
'components/lunr.js-' + getVersion('lunr.js') + '/lunr.min.js',
'components/lunr-' + getVersion('lunr') + '/lunr.min.js',
'components/google-code-prettify-' + getVersion('google-code-prettify') + '/src/prettify.js',
'components/google-code-prettify-' + getVersion('google-code-prettify') + '/src/lang-css.js',
'js/current-version-data.js',
@@ -49,6 +49,7 @@ module.exports = function productionDeployment(getVersion) {
'components/bootstrap-' + getVersion('bootstrap') + '/css/bootstrap.min.css',
'components/open-sans-fontface-' + getVersion('open-sans-fontface') + '/open-sans.css',
'css/prettify-theme.css',
'css/angular-topnav.css',
'css/docs.css',
'css/animations.css'
]
+3 -3
View File
@@ -4,14 +4,14 @@ var path = require('canonical-path');
/**
* dgService getVersion
* @description
* Find the current version of the bower component (or npm module)
* Find the current version of the bower component (or node module)
*/
module.exports = function getVersion(readFilesProcessor) {
var basePath = readFilesProcessor.basePath;
return function(component, sourceFolder, packageFile) {
sourceFolder = path.resolve(basePath, sourceFolder || 'docs/bower_components');
packageFile = packageFile || 'bower.json';
sourceFolder = path.resolve(basePath, sourceFolder || 'node_modules');
packageFile = packageFile || 'package.json';
return require(path.join(sourceFolder,component,packageFile)).version;
};
};
@@ -68,101 +68,95 @@
})();
</script>
</head>
<body>
<body class="homepage">
<div id="wrapper">
<header scroll-y-offset-element class="header header-fixed">
<section class="navbar navbar-inverse docs-navbar-primary" ng-controller="DocsSearchCtrl">
<div class="container">
<div class="row">
<div class="col-md-9 header-branding">
<a class="brand navbar-brand" href="http://angularjs.org">
<img width="117" height="30" class="logo" alt="Link to Angular JS Homepage" ng-src="img/angularjs-for-header-only.svg">
</a>
<ul class="nav navbar-nav">
<li class="divider-vertical"></li>
<li><a href="http://angularjs.org"><i class="icon-home icon-white"></i> Home</a></li>
<li class="divider-vertical"></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
<i class="icon-eye-open icon-white"></i> Learn <b class="caret"></b>
</a>
<ul class="dropdown-menu">
<li class="disabled"><a href="http://angularjs.org/">Why AngularJS?</a></li>
<li><a href="http://www.youtube.com/user/angularjs">Watch</a></li>
<li><a href="tutorial">Tutorial</a></li>
<li><a href="https://www.madewithangular.com/">Case Studies</a></li>
<li><a href="https://github.com/angular/angular-seed">Seed App project template</a></li>
<li><a href="misc/faq">FAQ</a></li>
</ul>
</li>
<li class="divider-vertical"></li>
<li class="dropdown active">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
<i class="icon-book icon-white"></i> Develop <b class="caret"></b>
</a>
<ul class="dropdown-menu">
<li><a href="tutorial">Tutorial</a></li>
<li><a href="guide">Developer Guide</a></li>
<li><a href="api">API Reference</a></li>
<li><a href="error">Error Reference</a></li>
<li><a href="misc/contribute">Contribute</a></li>
<li><a href="http://code.angularjs.org/">Download</a></li>
</ul>
</li>
<li class="divider-vertical"></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
<i class="icon-comment icon-white"></i> Discuss <b class="caret"></b>
</a>
<ul class="dropdown-menu">
<li><a href="http://blog.angularjs.org">Blog</a></li>
<li><a href="http://groups.google.com/group/angular">Mailing List</a></li>
<li><a href="http://webchat.freenode.net/?channels=angularjs&uio=d4">Chat Room</a></li>
<li class="divider"></li>
<li><a href="https://twitter.com/#!/angularjs">Twitter</a></li>
<li><a href="https://plus.google.com/110323587230527980117">Google+</a></li>
<li class="divider"></li>
<li><a href="https://github.com/angular/angular.js">GitHub</a></li>
<li><a href="https://github.com/angular/angular.js/issues">Issue Tracker</a></li>
</ul>
</li>
<li class="divider-vertical"></li>
</ul>
</div>
<form ng-class="{focus:focus}" class="navbar-search col-md-3 docs-search" ng-submit="submit()">
<span class="glyphicon glyphicon-search search-icon"></span>
<input type="text"
name="as_q"
class="search-query"
placeholder="Click or press / to search"
ng-focus="focus=true"
ng-blur="focus=false"
ng-change="search(q)"
ng-model="q"
docs-search-input
autocomplete="off" />
</form>
</div>
</div>
<div class="search-results-container" ng-show="hasResults">
<header class="header" scroll-y-offset-element>
<nav id="navbar-main" class="navbar navbar-fixed-top">
<div class="navbar-inner" ng-controller="DocsSearchCtrl">
<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">
<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>
<h1 class="brand"><a href="http://angularjs.org"><img width="117" height="30" src="img/angularjs-for-header-only.svg" alt="AngularJS"></a></h1>
<form class="navbar-search" ng-submit="submit()">
<i class="glyphicon glyphicon-search search-icon"></i>
<input type="text" name="as_q" class="search-query" placeholder="SEARCH"
ng-focus="focus=true"
ng-blur="focus=false"
ng-change="search(q)"
ng-model="q"
ng-model-options="{debounce: 150}"
docs-search-input
autocomplete="off">
</form>
<ul class="nav navbar-nav">
<li class="dropdown" uib-dropdown>
<a href="#" class="dropdown-toggle" uib-dropdown-toggle>Learn</a>
<ul class="dropdown-menu" uib-dropdown-menu>
<li><a href="tutorial">Tutorial</a></li>
<li><a href="misc/faq">FAQ</a></li>
<li><a href="https://www.youtube.com/user/angularjs">Videos</a></li>
<li><a href="http://angular.codeschool.com/">Free Course</a></li>
<li><a href="https://www.madewithangular.com/">Case Studies</a></li>
</ul>
</li>
<li class="dropdown" uib-dropdown>
<a href="#" class="dropdown-toggle" uib-dropdown-toggle>Develop</a>
<ul class="dropdown-menu" uib-dropdown-menu>
<li><a href="guide">Developer Guide</a></li>
<li><a href="api">API Reference</a></li>
<li><a href="error">Error Reference</a></li>
<li><a href="misc/contribute">Contribute</a></li>
<li><a href="https://github.com/angular/angular-seed">Seed App project template</a></li>
<li><a href="https://github.com/angular/angular.js">GitHub</a></li>
<li><a href="http://code.angularjs.org/">Download</a></li>
</ul>
</li>
<li class="dropdown" uib-dropdown>
<a href="#" class="dropdown-toggle" uib-dropdown-toggle>Discuss</a>
<ul class="dropdown-menu" uib-dropdown-menu>
<li><a href="http://blog.angularjs.org">Blog</a></li>
<li><a href="https://twitter.com/angular">Twitter</a></li>
<li><a href="https://plus.google.com/110323587230527980117">Google+</a></li>
<li><a href="https://github.com/angular/angular.js/issues">Feature &amp; Bug Tracker</a></li>
<li><a href="http://groups.google.com/group/angular">Mailing List</a></li>
<li><a href="http://webchat.freenode.net/?channels=angularjs&uio=d4">IRC</a></li>
<li><a href="https://gitter.im/angular/angular.js">Gitter</a></li>
</ul>
</li>
</ul>
</div>
<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">
<h4 class="search-results-group-heading">{{ key }}</h4>
<ul class="search-results">
<li ng-repeat="item in value" class="search-result"><a ng-click="hideResults()" ng-href="{{ item.path }}">{{ item.name }}</a></li>
</ul>
</div>
</div>
<a href="" ng-click="hideResults()" class="search-close">
<span class="glyphicon glyphicon-remove search-close-icon"></span> Close
</a>
</div>
<a href="" ng-click="hideResults()" class="search-close">
<span class="glyphicon glyphicon-remove search-close-icon"></span> Close
</a>
</div>
</div>
</section>
<section class="sup-header">
</nav>
<nav id="navbar-notice" class="navbar navbar-fixed-top">
<div class="navbar-inner">
<div class="container">
<p class="site-notice visible-phone">
This site refers to AngularJS (v1.x). <a href="https://angular.io/">Go to the latest Angular</a>.
</p>
<p class="site-notice visible-desktop">
This site and all of its contents are referring to AngularJS (version 1.x),
if you are looking for the latest Angular, please visit <a href="https://angular.io/">angular.io</a>.
</p>
</div>
</div>
</nav>
<nav id="navbar-sub" class="sup-header navbar navbar-fixed-top">
<div class="container main-grid main-header-grid">
<div class="grid-left">
<version-picker></version-picker>
@@ -176,7 +170,7 @@
</ul>
</div>
</div>
</section>
</nav>
</header>
<section role="main" class="container main-body">
@@ -214,7 +208,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-2017
(<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">
@@ -51,7 +51,7 @@
{% block examples %}
{%- if doc.examples %}
<h2 id="example">Example</h2>
<h2 id="example">Examples</h2>
{%- for example in doc.examples -%}
{$ example | marked $}
{%- endfor -%}
@@ -61,12 +61,12 @@
</div>
{% endblock -%}
{% include "lib/params.template.html" %}
{% include "lib/events.template.html" %}
{%- if doc.animations %}
<h2 id="animations">Animations</h2>
{$ doc.animations | marked $}
{$ 'module:ngAnimate.$animate' | link('Click here', doc) $} to learn more about the steps involved in the animation.
{%- endif -%}
{% include "lib/params.template.html" %}
{% include "lib/events.template.html" %}
{% endblock %}
@@ -21,7 +21,9 @@
</li>
<li>
<a href="https://www.npmjs.com/">NPM</a> e.g.
{% code %}npm install {$ doc.packageName $}@X.Y.Z{% endcode %}
{% code %}npm install --save {$ doc.packageName $}@X.Y.Z{% endcode %}
or
{% code %}yarn add {$ doc.packageName $}@X.Y.Z{% endcode %}
</li>
<li>
<a href="http://bower.io">Bower</a> e.g.
@@ -26,6 +26,13 @@
{$ lib.typeInfo(method.returns) $}
{% endif %}
{%- if method.examples %}
<h4 id="{$ doc.name $}.{$ method.name $}-examples">Examples</h4>
{%- for example in method.examples -%}
{$ example | marked $}
{%- endfor -%}
{% endif -%}
</li>
{% endfor -%}
</ul>
@@ -0,0 +1,8 @@
@ngdoc error
@name $animate:nongcls
@fullName `ng-animate` class not allowed
@description
This error occurs, when trying to set `$animateProvider.classNameFilter()` to a RegExp containing
the reserved `ng-animate` class. Since `.ng-animate` will be added/removed by `$animate` itself,
using it as part of the `classNameFilter` RegExp is not allowed.
+11
View File
@@ -0,0 +1,11 @@
@ngdoc error
@name $sanitize:elclob
@fullName Failed to sanitize html because the element is clobbered
@description
This error occurs when `$sanitize` sanitizer is unable to traverse the HTML because one or more of the elements in the
HTML have been "clobbered". This could be a sign that the payload contains code attempting to cause a DoS attack on the
browser.
Typically clobbering breaks the `nextSibling` property on an element so that it points to one of its child nodes. This
makes it impossible to walk the HTML tree without getting stuck in an infinite loop, which causes the browser to freeze.
+7
View File
@@ -0,0 +1,7 @@
@ngdoc error
@name ng:aobj
@fullName Invalid Argument
@description
The argument passed should be an object. Check the value that was passed to the function where
this error was thrown.
+41 -31
View File
@@ -232,27 +232,27 @@ than the hash fragment was changed.
### Example
```js
it('should show example', inject(
function($locationProvider) {
it('should show example', function() {
module(function($locationProvider) {
$locationProvider.html5Mode(false);
$locationProvider.hashPrefix('!');
},
function($location) {
});
inject(function($location) {
// open http://example.com/base/index.html#!/a
$location.absUrl() === 'http://example.com/base/index.html#!/a'
$location.path() === '/a'
expect($location.absUrl()).toBe('http://example.com/base/index.html#!/a');
expect($location.path()).toBe('/a');
$location.path('/foo')
$location.absUrl() === 'http://example.com/base/index.html#!/foo'
$location.path('/foo');
expect($location.absUrl()).toBe('http://example.com/base/index.html#!/foo');
$location.search() === {}
expect($location.search()).toEqual({});
$location.search({a: 'b', c: true});
$location.absUrl() === 'http://example.com/base/index.html#!/foo?a=b&c'
expect($location.absUrl()).toBe('http://example.com/base/index.html#!/foo?a=b&c');
$location.path('/new').search('x=y');
$location.absUrl() === 'http://example.com/base/index.html#!/new?x=y'
}
));
expect($location.absUrl()).toBe('http://example.com/base/index.html#!/new?x=y');
});
});
```
## HTML5 mode
@@ -274,40 +274,50 @@ and updates the url in a way that never performs a full page reload.
### Example
```js
it('should show example', inject(
function($locationProvider) {
it('should show example', function() {
module(function($locationProvider) {
$locationProvider.html5Mode(true);
$locationProvider.hashPrefix('!');
},
function($location) {
});
inject(function($location) {
// in browser with HTML5 history support:
// open http://example.com/#!/a -> rewrite to http://example.com/a
// (replacing the http://example.com/#!/a history record)
$location.path() === '/a'
expect($location.path()).toBe('/a');
$location.path('/foo');
$location.absUrl() === 'http://example.com/foo'
expect($location.absUrl()).toBe('http://example.com/foo');
$location.search() === {}
expect($location.search()).toEqual({});
$location.search({a: 'b', c: true});
$location.absUrl() === 'http://example.com/foo?a=b&c'
expect($location.absUrl()).toBe('http://example.com/foo?a=b&c');
$location.path('/new').search('x=y');
$location.url() === 'new?x=y'
$location.absUrl() === 'http://example.com/new?x=y'
expect($location.url()).toBe('/new?x=y');
expect($location.absUrl()).toBe('http://example.com/new?x=y');
});
});
it('should show example (when browser doesn\'t support HTML5 mode', function() {
module(function($provide, $locationProvider) {
$locationProvider.html5Mode(true);
$locationProvider.hashPrefix('!');
$provide.value('$sniffer', {history: false});
});
inject(initBrowser({ url: 'http://example.com/new?x=y', basePath: '/' }),
function($location) {
// in browser without html5 history support:
// open http://example.com/new?x=y -> redirect to http://example.com/#!/new?x=y
// (again replacing the http://example.com/new?x=y history item)
$location.path() === '/new'
$location.search() === {x: 'y'}
expect($location.path()).toBe('/new');
expect($location.search()).toEqual({x: 'y'});
$location.path('/foo/bar');
$location.path() === '/foo/bar'
$location.url() === '/foo/bar?x=y'
$location.absUrl() === 'http://example.com/#!/foo/bar?x=y'
}
));
expect($location.path()).toBe('/foo/bar');
expect($location.url()).toBe('/foo/bar?x=y');
expect($location.absUrl()).toBe('http://example.com/#!/foo/bar?x=y');
});
});
```
### Fallback for legacy browsers
@@ -555,7 +565,7 @@ In these examples we use `<base href="/base/index.html" />`. The inputs represen
</example>
####Browser in HTML5 Fallback mode (Hashbang mode)
#### Browser in HTML5 Fallback mode (Hashbang mode)
<example module="hashbang-mode" name="location-hashbang-mode">
<file name="index.html">
<div ng-controller="LocationController">
+5 -5
View File
@@ -122,7 +122,7 @@ The same approach to animation can be used using JavaScript code (**jQuery is us
```js
myModule.animation('.repeated-item', function() {
return {
enter : function(element, done) {
enter: function(element, done) {
element.css('opacity',0);
jQuery(element).animate({
opacity: 1
@@ -137,7 +137,7 @@ myModule.animation('.repeated-item', function() {
}
}
},
leave : function(element, done) {
leave: function(element, done) {
element.css('opacity', 1);
jQuery(element).animate({
opacity: 0
@@ -152,7 +152,7 @@ myModule.animation('.repeated-item', function() {
}
}
},
move : function(element, done) {
move: function(element, done) {
element.css('opacity', 0);
jQuery(element).animate({
opacity: 1
@@ -169,8 +169,8 @@ myModule.animation('.repeated-item', function() {
},
// you can also capture these animation events
addClass : function(element, className, done) {},
removeClass : function(element, className, done) {}
addClass: function(element, className, done) {},
removeClass: function(element, className, done) {}
}
});
```
+10 -11
View File
@@ -149,7 +149,7 @@ You can see the complete application running below.
<h1 class="title">Component Router</h1>
<app></app>
<!-- Load up the router library - normally you might use npm and host it locally -->
<!-- Load up the router library - normally you might use npm/yarn and host it locally -->
<script src="https://unpkg.com/@angular/router@0.2.0/angular1/angular_1_router.js"></script>
</file>
@@ -215,7 +215,7 @@ You can see the complete application running below.
function HeroService($q) {
var heroesPromise = $q.when([
var heroesPromise = $q.resolve([
{ id: 11, name: 'Mr. Nice' },
{ id: 12, name: 'Narco' },
{ id: 13, name: 'Bombasto' },
@@ -308,7 +308,7 @@ You can see the complete application running below.
function CrisisService($q) {
var crisesPromise = $q.when([
var crisesPromise = $q.resolve([
{id: 1, name: 'Princess Held Captive'},
{id: 2, name: 'Dragon Burning Cities'},
{id: 3, name: 'Giant Asteroid Heading For Earth'},
@@ -415,7 +415,7 @@ You can see the complete application running below.
function DialogService($q) {
this.confirm = function(message) {
return $q.when(window.confirm(message || 'Is it OK?'));
return $q.resolve(window.confirm(message || 'Is it OK?'));
};
}
</file>
@@ -467,13 +467,12 @@ to display list and detail views of Heroes and Crises.
## Install the libraries
It is easier to use npm to install the **Component Router** module. For this guide we will also install
AngularJS itself via npm:
It is easier to use [Yarn](https://yarnpkg.com) or [npm](https://www.npmjs.com) to install the
**Component Router** module. For this guide we will also install AngularJS itself via Yarn:
```bash
npm init
npm install angular@1.5.x --save
npm install @angular/router@0.2.0 --save
yarn init
yarn add angular@1.5.x @angular/router@0.2.0
```
@@ -714,7 +713,7 @@ making an actual server request, perhaps over HTTP.
```js
function HeroService($q) {
var heroesPromise = $q.when([
var heroesPromise = $q.resolve([
{ id: 11, name: 'Mr. Nice' },
...
]);
@@ -991,7 +990,7 @@ have made. The result of the prompt is a promise that can be used in a `$routerC
function DialogService($q) {
this.confirm = function(message) {
return $q.when(window.confirm(message || 'Is it OK?'));
return $q.resolve(window.confirm(message || 'Is it OK?'));
};
}
```
+1
View File
@@ -78,6 +78,7 @@ It's also possible to add components via {@link $compileProvider#component} in a
| link functions | Yes | No |
| multiElement | Yes | No |
| priority | Yes | No |
| replace | Yes (deprecated) | No |
| require | Yes | Yes |
| restrict | Yes | No (restricted to elements only) |
| scope | Yes (default: false) | No (scope is always isolate) |
+10 -4
View File
@@ -120,11 +120,13 @@ The other forms shown above are accepted for legacy reasons but we advise you to
### Directive types
`$compile` can match directives based on element names, attributes, class names, as well as comments.
`$compile` can match directives based on element names (E), attributes (A), class names (C),
and comments (M).
All of the Angular-provided directives match attribute name, tag name, comments, or class name.
The following demonstrates the various ways a directive (`myDir` in this case) can be referenced
from within a template:
The built-in the AngularJS directives show in their documentation page which type of matching they support.
The following demonstrates the various ways a directive that matches all 4 types
(`myDir` in this case) can be referenced from within a template.
```html
<my-dir></my-dir>
@@ -133,6 +135,10 @@ from within a template:
<span class="my-dir: exp;"></span>
```
A directive can specify which of the 4 matching types it supports in the
{@link ng.$compile#-restrict- `restrict`} property of the directive definition object.
The default is `EA`.
<div class="alert alert-success">
**Best Practice:** Prefer using directives via tag name and attributes over comment and class names.
Doing so generally makes it easier to determine what directives a given element matches.
+7 -7
View File
@@ -241,7 +241,7 @@ An expression that starts with `::` is considered a one-time expression. One-tim
will stop recalculating once they are stable, which happens after the first digest if the expression
result is a non-undefined value (see value stabilization algorithm below).
<example module="oneTimeBidingExampleApp" name="expression-one-time">
<example module="oneTimeBindingExampleApp" name="expression-one-time">
<file name="index.html">
<div ng-controller="EventController">
<button ng-click="clickMe($event)">Click Me</button>
@@ -250,7 +250,7 @@ result is a non-undefined value (see value stabilization algorithm below).
</div>
</file>
<file name="script.js">
angular.module('oneTimeBidingExampleApp', []).
angular.module('oneTimeBindingExampleApp', []).
controller('EventController', ['$scope', function($scope) {
var counter = 0;
var names = ['Igor', 'Misko', 'Chirayu', 'Lucas'];
@@ -265,24 +265,24 @@ result is a non-undefined value (see value stabilization algorithm below).
</file>
<file name="protractor.js" type="protractor">
it('should freeze binding after its value has stabilized', function() {
var oneTimeBiding = element(by.id('one-time-binding-example'));
var oneTimeBinding = element(by.id('one-time-binding-example'));
var normalBinding = element(by.id('normal-binding-example'));
expect(oneTimeBiding.getText()).toEqual('One time binding:');
expect(oneTimeBinding.getText()).toEqual('One time binding:');
expect(normalBinding.getText()).toEqual('Normal binding:');
element(by.buttonText('Click Me')).click();
expect(oneTimeBiding.getText()).toEqual('One time binding: Igor');
expect(oneTimeBinding.getText()).toEqual('One time binding: Igor');
expect(normalBinding.getText()).toEqual('Normal binding: Igor');
element(by.buttonText('Click Me')).click();
expect(oneTimeBiding.getText()).toEqual('One time binding: Igor');
expect(oneTimeBinding.getText()).toEqual('One time binding: Igor');
expect(normalBinding.getText()).toEqual('Normal binding: Misko');
element(by.buttonText('Click Me')).click();
element(by.buttonText('Click Me')).click();
expect(oneTimeBiding.getText()).toEqual('One time binding: Igor');
expect(oneTimeBinding.getText()).toEqual('One time binding: Igor');
expect(normalBinding.getText()).toEqual('Normal binding: Lucas');
});
</file>
+2 -1
View File
@@ -119,7 +119,8 @@ You can find a larger list of Angular external libraries at [ngmodules.org](http
### Books
* [AngularJS Directives](http://www.amazon.com/AngularJS-Directives-Alex-Vanston/dp/1783280336) by Alex Vanston
* [AngularJS Essentials (Free eBook)](https://www.packtpub.com/packt/free-ebook/angularjs-essentials) by Rodrigo Branas
* [AngularJS : Novice to Ninja](http://www.amazon.in/AngularJS-Novice-Ninja-Sandeep-Panda/dp/0992279453) by Sandeep Panda
* [AngularJS in Action](https://www.manning.com/books/angularjs-in-action) by Lukas Ruebbelke
* [AngularJS: Novice to Ninja](http://www.amazon.in/AngularJS-Novice-Ninja-Sandeep-Panda/dp/0992279453) by Sandeep Panda
* [AngularJS UI Development](http://www.amazon.com/AngularJS-UI-Development-Amit-Ghart-ebook/dp/B00OXVAK7A) by Amit Gharat and Matthias Nehlsen
* [AngularJS: Up and Running](http://www.amazon.com/AngularJS-Running-Enhanced-Productivity-Structured/dp/1491901942) by Brad Green and Shyam Seshadri
* [Developing an AngularJS Edge](http://www.amazon.com/Developing-AngularJS-Edge-Christopher-Hiller-ebook/dp/B00CJLFF8K) by Christopher Hiller
+4 -4
View File
@@ -28,8 +28,8 @@ for other directives to augment its behavior.
<form novalidate class="simple-form">
<label>Name: <input type="text" ng-model="user.name" /></label><br />
<label>E-mail: <input type="email" ng-model="user.email" /></label><br />
Gender: <label><input type="radio" ng-model="user.gender" value="male" />male</label>
<label><input type="radio" ng-model="user.gender" value="female" />female</label><br />
Best Editor: <label><input type="radio" ng-model="user.preference" value="vi" />vi</label>
<label><input type="radio" ng-model="user.preference" value="emacs" />emacs</label><br />
<input type="button" ng-click="reset()" value="Reset" />
<input type="submit" ng-click="update(user)" value="Save" />
</form>
@@ -363,7 +363,7 @@ In the following example we create two directives:
<file name="script.js">
var app = angular.module('form-example1', []);
var INTEGER_REGEXP = /^\-?\d+$/;
var INTEGER_REGEXP = /^-?\d+$/;
app.directive('integer', function() {
return {
require: 'ngModel',
@@ -396,7 +396,7 @@ In the following example we create two directives:
if (ctrl.$isEmpty(modelValue)) {
// consider empty model valid
return $q.when();
return $q.resolve();
}
var def = $q.defer();
+2 -2
View File
@@ -26,7 +26,7 @@ directive}. Additionally, you can use {@link guide/i18n#messageformat-extension
All localizable Angular components depend on locale-specific rule sets managed by the {@link
ng.$locale `$locale` service}.
There a few examples that showcase how to use Angular filters with various locale rule sets in the
There are a few examples that showcase how to use Angular filters with various locale rule sets in the
[`i18n/e2e` directory](https://github.com/angular/angular.js/tree/master/i18n/e2e) of the Angular
source code.
@@ -85,7 +85,7 @@ requires German locale, you would serve index_de-de.html which will look somethi
Both approaches described above require you to prepare different `index.html` pages or JavaScript
files for each locale that your app may use. You also need to configure your server to serve
the correct file that correspond to the desired locale.
the correct file that corresponds to the desired locale.
The second approach (including the locale JavaScript file in `index.html`) may be slower because
an extra script needs to be loaded.
+168 -14
View File
@@ -88,7 +88,9 @@ commits for more info.
- **jqLite** is more aligned to jQuery 3, which required the following changes
(see [details](guide/migration#migrate1.5to1.6-ng-misc-jqLite) below):
- Keys passed to `.data()` and `.css()` are now camelCased in the same as jQuery does it.
- Keys passed to `.data()` and `.css()` are now camelCased in the same way as the jQuery methods
do.
- Getting/setting boolean attributes no longer takes the corresponding properties into account.
- Setting boolean attributes to empty string no longer removes the attribute.
- Calling `.val()` on a multiple select will always return an array, even if no option is
selected.
@@ -114,6 +116,7 @@ Below is the full list of breaking changes:
- Core:
- [Directives](guide/migration#migrate1.5to1.6-ng-directives)
- [form](guide/migration#migrate1.5to1.6-ng-directives-form)
- [input[number]](guide/migration#migrate1.5to1.6-ng-directives-input[number])
- [input[radio]](guide/migration#migrate1.5to1.6-ng-directives-input[radio])
- [input[range]](guide/migration#migrate1.5to1.6-ng-directives-input[range])
- [ngBind](guide/migration#migrate1.5to1.6-ng-directives-ngBind)
@@ -166,6 +169,38 @@ $scope.$watch('something', function() {
or you can use `Function.prototype.bind` or `angular.bind`.
<a name="migrate1.5to1.6-ng-directives-input[number]"></a>
#### **input[type=number]**:
<minor />
**Due to [e1da4be](https://github.com/angular/angular.js/commit/e1da4bed8e291003d485a8ad346ab80bed8ae2e3)**,
number inputs that use `ngModel` and specify a `step` constraint (via `step`/`ngStep` attributes)
will now have a new validator (`step`), which will verify that the current value is valid under the
`step` constraint (according to the [spec](https://www.w3.org/TR/html5/forms.html#the-step-attribute)).
Previously, the `step` constraint was ignored by `ngModel`, treating values as valid even when there
was a step-mismatch.
If you want to restore the previous behavior (use the `step` attribute while disabling step
validation), you can overwrite the built-in `step` validator with a custom directive. For example:
```js
// For all `input` elements...
.directive('input', function() {
return {
restrict: 'E',
require: '?ngModel',
link: function (scope, elem, attrs, ngModelCtrl) {
// ...that are of type "number" and have `ngModel`...
if ((attrs.type === 'number') && ngModelCtrl) {
// ...remove the `step` validator.
delete ngModelCtrl.$validators.step;
}
}
};
})
```
<a name="migrate1.5to1.6-ng-directives-input[radio]"></a>
#### **input[type=radio]**:
@@ -382,9 +417,9 @@ it back on, which should help during the migration. Pre-assigning bindings has b
will be removed in a future version, so we strongly recommend migrating your applications to not
rely on it as soon as possible.
Initialization logic that relies on relies on bindings being present should be put in the
controller's `$onInit()` method, which is guarranteed to always be called _after_ the bindings have
been assigned.
Initialization logic that relies on bindings being present should be put in the controller's
`$onInit()` method, which is guaranteed to always be called _after_ the bindings have been
assigned.
Before:
@@ -468,7 +503,7 @@ running at `https://docs.angularjs.org` then the following will fail:
<link href="{{ 'http://mydomain.org/unsafe.css' }}" rel="stylesheet" />
```
By default, only URLs with the same domain and prototocl as the application document are considered
By default, only URLs with the same domain and protocol as the application document are considered
safe in the `RESOURCE_URL` context. To use URLs from other domains and/or protocols, you may either
whitelist them or wrap them into a trusted value by calling `$sce.trustAsResourceUrl(url)`.
@@ -847,6 +882,48 @@ var bgColor = elem.css('background-color');
var bgColor = elem.css('backgroundColor');
```
<hr />
<major />
**Due to [7ceb5f](https://github.com/angular/angular.js/commit/7ceb5f6fcc43d35d1b66c3151ce6a71c60309304)**,
getting/setting boolean attributes will no longer take the corresponding properties into account.
Previously, all boolean attributes were reflected into the corresponding property when calling a
setter and from the corresponding property when calling a getter, even on elements that don't treat
those attributes in a special way. Now Angular doesn't do it by itself, but relies on browsers to
know when to reflect the property. Note that this browser-level conversion differs between browsers;
if you need to dynamically change the state of an element, you should modify the property, not the
attribute. See https://jquery.com/upgrade-guide/1.9/#attr-versus-prop- for a more detailed
description about a related change in jQuery 1.9.
This change aligns jqLite with jQuery 3. To migrate the code follow the example below:
Before:
```css
/* CSS */
input[checked="checked"] { ... }
```
```js
// JS
elem1.attr('checked', 'checked');
elem2.attr('checked', false);
```
After:
```css
/* CSS */
input:checked { ... }
```
```js
// JS
elem1.prop('checked', true);
elem2.prop('checked', false);
```
<hr />
<major />
**Due to [3faf45](https://github.com/angular/angular.js/commit/3faf4505732758165083c9d21de71fa9b6983f4a)**,
@@ -1136,7 +1213,7 @@ with an unencoded `;` character.
Previously, in cases where `ngView` was loaded asynchronously, `$route` (and its dependencies) might
also have been instantiated asynchronously.
Although this is not expected to have unwanted side-effects in normal application bebavior, it may
Although this is not expected to have unwanted side-effects in normal application behavior, it may
affect your unit tests: When testing a module that (directly or indirectly) depends on `ngRoute`, a
request will be made for the default route's template. If not properly "trained", `$httpBackend`
will complain about this unexpected request. You can restore the previous behavior (and avoid
@@ -1241,6 +1318,11 @@ and was not consistent with other filters (e.g. `filter`).
Objects considered array-like include: arrays, array subclasses, strings, NodeLists,
jqLite/jQuery collections
#### Helper Functions:
The {@link angular.lowercase `angular.lowercase`} and {@link angular.uppercase `angular.uppercase`} functions have been **deprecated** and will be removed
in version 1.7.0. It is recommended to use [String.prototype.toLowerCase](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String/toLowerCase) and [String.prototype.toUpperCase](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String/toUpperCase) functions instead.
### ngAria
@@ -1372,9 +1454,8 @@ For more info on the topic, you can take a look at this
## 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:
`limitTo` and `filter`.
AngularJS 1.4 fixes major animation issues and introduces a new API for `ngCookies`. Further, there
are changes to `ngMessages`, `$compile`, `ngRepeat`, `ngOptions`, `ngPattern`, `pattern` and some fixes to core filters: `limitTo` and `filter`.
The reason for the ngAnimate refactor was to fix timing issues and to expose new APIs to allow
for developers to construct more versatile animations. We now have access to `$animateCss`
@@ -1387,9 +1468,9 @@ to render error messages with ngMessages that are listed with a directive such a
involves pulling error message data from a server and then displaying that data via the mechanics of ngMessages. Be
sure to read the breaking change involved with `ngMessagesInclude` to upgrade your template code.
Other changes, such as the ordering of elements with ngRepeat and ngOptions, may also affect the behavior of your
application. And be sure to also read up on the changes to `$cookies`. The migration jump from 1.3 to 1.4 should be
relatively straightforward otherwise.
Other changes, such as the ordering of elements with ngRepeat and ngOptions and the way ngPattern and pattern directives
validate the regex, may also affect the behavior of your application. And be sure to also read up on the changes to `$cookies`.
The migration jump from 1.3 to 1.4 should be relatively straightforward otherwise.
@@ -1493,7 +1574,7 @@ class based animations (animations triggered via ngClass) in order to ensure tha
### Forms (`ngMessages`, `ngOptions`, `select`)
### Forms (`ngMessages`, `ngOptions`, `select`, `ngPattern` and `pattern`)
#### ngMessages
The ngMessages module has also been subject to an internal refactor to allow it to be more flexible
@@ -1601,6 +1682,79 @@ ngModelCtrl.$formatters.push(function(value) {
});
```
#### ngPattern and pattern
Due to [0e001084](https://github.com/angular/angular.js/commit/0e001084ffff8674efad289d37cb16cc4e46b50a),
The `ngPattern` and `pattern` directives will validate the regex
against the `$viewValue` of `ngModel`, i.e. the value of the model
before the $parsers are applied. Previously, the `$modelValue`
(the result of the $parsers) was validated.
This fixes issues where `input[date]` and `input[number]` cannot
be validated because the `$viewValue` string is parsed into
`Date` and `Number` respectively (starting with Angular 1.3).
It also brings the directives in line with HTML5 constraint
validation, which validates against the input value.
This change is unlikely to cause applications to fail, because even
in Angular 1.2, the value that was validated by pattern could have
been manipulated by the $parsers, as all validation was done
inside this pipeline.
If you rely on the pattern being validated against the `$modelValue`,
you must create your own validator directive that overwrites
the built-in pattern validator:
```
.directive('patternModelOverwrite', function patternModelOverwriteDirective() {
return {
restrict: 'A',
require: '?ngModel',
priority: 1,
compile: function() {
var regexp, patternExp;
return {
pre: function(scope, elm, attr, ctrl) {
if (!ctrl) return;
attr.$observe('pattern', function(regex) {
/**
* The built-in directive will call our overwritten validator
* (see below). We just need to update the regex.
* The preLink fn guaranetees our observer is called first.
*/
if (isString(regex) && regex.length > 0) {
regex = new RegExp('^' + regex + '$');
}
if (regex && !regex.test) {
//The built-in validator will throw at this point
return;
}
regexp = regex || undefined;
});
},
post: function(scope, elm, attr, ctrl) {
if (!ctrl) return;
regexp, patternExp = attr.ngPattern || attr.pattern;
//The postLink fn guarantees we overwrite the built-in pattern validator
ctrl.$validators.pattern = function(value) {
return ctrl.$isEmpty(value) ||
isUndefined(regexp) ||
regexp.test(value);
};
}
};
}
};
});
```
### form
@@ -2567,7 +2721,7 @@ See [38deedd6](https://github.com/angular/angular.js/commit/38deedd6e3d806eb8262
### Interpolations inside DOM event handlers are now disallowed
DOM event handlers execute arbitrary Javascript code. Using an interpolation for such handlers
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
strings is error prone and leads to XSS vulnerabilities. On the other hand, `ngClick` and other
Angular specific event handlers evaluate Angular expressions in non-window (Scope) context which
+2 -2
View File
@@ -221,8 +221,8 @@ it('should clear messages after alert', function() {
notify('two');
notify('third');
expect(mock.alert.callCount).toEqual(2);
expect(mock.alert.mostRecentCall.args).toEqual(["more\ntwo\nthird"]);
expect(mock.alert.calls.count()).toEqual(2);
expect(mock.alert.calls.mostRecent().args).toEqual(["more\ntwo\nthird"]);
});
```
+1 -1
View File
@@ -26,7 +26,7 @@ curly-brace {@link expression expression} bindings:
<!-- Body tag augmented with ngController directive -->
<body ng-controller="MyController">
<input ng-model="foo" value="bar">
<!-- Button tag with ng-click directive, and
<!-- Button tag with ngClick directive, and
string expression 'buttonText'
wrapped in "{{ }}" markup -->
<button ng-click="changeFoo()">{{buttonText}}</button>
+2 -2
View File
@@ -59,7 +59,7 @@ Karma to run against a number of browsers, which is useful for being confident t
works on all browsers you need to support. Karma is executed on the command line and will display
the results of your tests on the command line once they have run in the browser.
Karma is a NodeJS application, and should be installed through npm. Full installation instructions
Karma is a NodeJS application, and should be installed through npm/yarn. Full installation instructions
are available on [the Karma website](http://karma-runner.github.io/0.12/intro/installation.html).
### Jasmine
@@ -461,7 +461,7 @@ describe("Deep Thought", function() {
}));
it("has calculated the answer correctly", inject(function(DeepThought) {
// Because of sharedInjector, we have access to the instance of the DeepThought service
// 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);
}));
+24 -20
View File
@@ -5,7 +5,7 @@
# Building and Testing AngularJS
This document describes how to set up your development environment to build and test AngularJS, and
explains the basic mechanics of using `git`, `node`, `npm`, `grunt`, and `bower`.
explains the basic mechanics of using `git`, `node`, `yarn`, `grunt`, and `bower`.
See the [contributing guidelines](https://github.com/angular/angular.js/blob/master/CONTRIBUTING.md)
for how to contribute your own code to AngularJS.
@@ -24,20 +24,27 @@ Before you can build AngularJS, you must install and configure the following dep
machine:
* [Git](http://git-scm.com/): The [Github Guide to
Installing Git](https://help.github.com/articles/set-up-git) is a good source of information.
Installing Git](https://help.github.com/articles/set-up-git) is a good source of information.
* [Node.js v4.x](http://nodejs.org): We use Node to generate the documentation, run a
development web server, run tests, and generate distributable files. Depending on your system, you can install Node either from source or as a
pre-packaged bundle. (Currently our build does not work properly on Node v5 or greater - please use v4.x.)
* [Node.js v6.x (LTS)](http://nodejs.org): We use Node to generate the documentation, run a
development web server, run tests, and generate distributable files. Depending on your system,
you can install Node either from source or as a pre-packaged bundle.
We recommend using [nvm](https://github.com/creationix/nvm) (or [nvm-windows](https://github.com/coreybutler/nvm-windows))
to manage and install Node.js, which makes it easy to change the version of Node.js per project.
* [Yarn](https://yarnpkg.com): We use Yarn to install our Node.js module dependencies (rather than using npm).
There are detailed installation instructions available at https://yarnpkg.com/en/docs/install.
* [Java](http://www.java.com): We minify JavaScript using our
[Closure Tools](https://developers.google.com/closure/) jar. Make sure you have Java (version 7 or higher) installed
and included in your [PATH](http://docs.oracle.com/javase/tutorial/essential/environment/paths.html) variable.
[Closure Tools](https://developers.google.com/closure/) jar. Make sure you have Java (version 7 or higher)
installed and included in your [PATH](http://docs.oracle.com/javase/tutorial/essential/environment/paths.html)
variable.
* [Grunt](http://gruntjs.com): We use Grunt as our build system. Install the grunt command-line tool globally with:
```shell
npm install -g grunt-cli
yarn global add grunt-cli
```
## Forking Angular on Github
@@ -62,12 +69,9 @@ cd angular.js
git remote add upstream "https://github.com/angular/angular.js.git"
# Install node.js dependencies:
npm install
yarn install
# Install bower components:
bower install
# Build AngularJS:
# Build AngularJS (which will install `bower` dependencies automatically):
grunt package
```
@@ -78,11 +82,11 @@ Administrator). This is because `grunt package` creates some symbolic links.
</div>
<div class="alert alert-warning">
**Note:** If you're using Linux, and npm install fails with the message
'Please try running this command again as root/Administrator.', you may need to globally install grunt and bower:
**Note:** If you're using Linux, and `yarn install` fails with the message
'Please try running this command again as root/Administrator.', you may need to globally install `grunt` and `bower`:
<ul>
<li>sudo npm install -g grunt-cli</li>
<li>sudo npm install -g bower</li>
<li>sudo yarn global add grunt-cli</li>
<li>sudo yarn global add bower</li>
</ul>
</div>
@@ -136,13 +140,13 @@ tests once on Chrome run:
grunt test:unit
```
To run the tests on other browsers (Chrome, ChromeCanary, Firefox, Opera and Safari are pre-configured) use:
To run the tests on other browsers (Chrome, ChromeCanary, Firefox and Safari are pre-configured) use:
```shell
grunt test:unit --browsers=Opera,Firefox
grunt test:unit --browsers=Chrome,Firefox
```
Note there should be _no spaces between browsers_. `Opera, Firefox` is INVALID.
Note there should be _no spaces between browsers_. `Chrome, Firefox` is INVALID.
During development, however, it's more productive to continuously run unit tests every time the source or test files
change. To execute tests in this mode run:
+2
View File
@@ -77,6 +77,8 @@ AngularJS was designed to be compatible with other security measures like Conten
(CSP), HTTPS (SSL/TLS) and server-side authentication and authorization that greatly reduce the
possible attack vectors and we highly recommend their use.
Please read {@link security} for more detailed information about securing Angular apps.
### Can I download the source, build, and host the AngularJS environment locally?
+1 -1
View File
@@ -32,7 +32,7 @@ tutorials.
## Subscribe
* Subscribe to the [mailing list](http://groups.google.com/forum/?fromgroups#!forum/angular). Ask questions here!
* Follow us on [Twitter](https://twitter.com/intent/follow?original_referer=http%3A%2F%2Fangularjs.org%2F&region=follow_link&screen_name=angularjs&source=followbutton&variant=2.0)
* Follow us on [Twitter](https://twitter.com/intent/follow?original_referer=http%3A%2F%2Fangularjs.org%2F&region=follow_link&screen_name=angular&source=followbutton&variant=2.0)
* Add us to your circles on [Google+](https://plus.google.com/110323587230527980117/posts)
## Read more
+1 -1
View File
@@ -54,7 +54,7 @@ We will keep this in mind though, as we add more features.
So, now that we learned we should put everything in its own file, our `app/` directory will soon be
full with dozens of files and specs (remember we keep our unit test files next to the corresponding
source code files). What's more important, logically related files will not be grouped together; it
will be really difficult of locate all files related to a specific section of the application and
will be really difficult to locate all files related to a specific section of the application and
make a change or fix a bug.
So, what shall we do?
+1 -1
View File
@@ -194,7 +194,7 @@ angular.module('phonecatApp', [
```
Now, in addition to the core services and directives, we can also configure the `$route` service
(using it's provider) for our application. In order to be able to quickly locate the configuration
(using its provider) for our application. In order to be able to quickly locate the configuration
code, we put it into a separate file and used the `.config` suffix.
<br />
+4 -1
View File
@@ -173,7 +173,10 @@ angular.module('phoneList', ['core.phone']);
**`app/phone-detail/phone-detail.module.js`:**
```js
angular.module('phoneDetail', ['core.phone']);
angular.module('phoneDetail', [
'ngRoute',
'core.phone'
]);
```
<br />
+6 -21
View File
@@ -1,10 +1,8 @@
'use strict';
var gulp = require('gulp');
var log = require('gulp-util').log;
var concat = require('gulp-concat');
var eslint = require('gulp-eslint');
var bower = require('bower');
var Dgeni = require('dgeni');
var merge = require('event-stream').merge;
var path = require('canonical-path');
@@ -18,7 +16,6 @@ var rename = require('gulp-rename');
// See clean and bower for async tasks, and see assets and doc-gen for dependent tasks below
var outputFolder = '../build/docs';
var bowerFolder = 'bower_components';
var src = 'app/src/**/*.js';
var ignoredFiles = '!src/angular.bind.js';
@@ -57,8 +54,8 @@ var getMergedEslintConfig = function(filepath) {
var copyComponent = function(component, pattern, sourceFolder, packageFile) {
pattern = pattern || '/**/*';
sourceFolder = sourceFolder || bowerFolder;
packageFile = packageFile || 'bower.json';
sourceFolder = sourceFolder || '../node_modules';
packageFile = packageFile || 'package.json';
var version = require(path.resolve(sourceFolder, component, packageFile)).version;
return gulp
.src(sourceFolder + '/' + component + pattern)
@@ -66,18 +63,6 @@ var copyComponent = function(component, pattern, sourceFolder, packageFile) {
};
gulp.task('bower', function() {
var bowerTask = bower.commands.install();
bowerTask.on('log', function(result) {
log('bower:', result.id, result.data.endpoint.name);
});
bowerTask.on('error', function(error) {
log(error);
});
return bowerTask;
});
gulp.task('build-app', function() {
var file = 'docs.js';
var minFile = 'docs.min.js';
@@ -94,7 +79,7 @@ gulp.task('build-app', function() {
});
gulp.task('assets', ['bower'], function() {
gulp.task('assets', function() {
var JS_EXT = /\.js$/;
return merge(
gulp.src(['img/**/*']).pipe(gulp.dest(outputFolder + '/img')),
@@ -113,15 +98,15 @@ gulp.task('assets', ['bower'], function() {
})),
copyComponent('bootstrap', '/dist/**/*'),
copyComponent('open-sans-fontface'),
copyComponent('lunr.js', '/*.js'),
copyComponent('lunr', '/*.js'),
copyComponent('google-code-prettify'),
copyComponent('jquery', '/dist/*.js'),
copyComponent('marked', '/**/*.js', '../node_modules', 'package.json')
copyComponent('marked', '/**/*.js')
);
});
gulp.task('doc-gen', ['bower'], function() {
gulp.task('doc-gen', function() {
var dgeni = new Dgeni([require('./config')]);
return dgeni.generate().catch(function() {
process.exit(1);
+4 -5
View File
@@ -3,14 +3,13 @@
set -e
BASE_DIR=`dirname $0`
cd $BASE_DIR
npm run test-i18n
yarn run test-i18n
node src/closureSlurper.js
node $BASE_DIR/src/closureSlurper.js
npm run test-i18n-ucd
yarn run test-i18n-ucd
echo "Generating ngParseExt"
node ucd/src/extract.js
node $BASE_DIR/ucd/src/extract.js
-32
View File
@@ -1,32 +0,0 @@
#!/usr/bin/env bash
#
# Script to initialize angular repo
# - install required node packages
# - install Karma
# - install git hooks
node=`which node 2>&1`
if [ $? -ne 0 ]; then
echo "Please install NodeJS."
echo "http://nodejs.org/"
exit 1
fi
npm=`which npm 2>&1`
if [ $? -ne 0 ]; then
echo "Please install NPM."
fi
echo "Installing required npm packages..."
npm install
karma=`which karma 2>&1`
if [ $? -ne 0 ]; then
echo "Installing Karma..."
npm install -g karma
fi
echo "Installing git hooks..."
ln -sf ../../validate-commit-msg.js .git/hooks/commit-msg
+2 -5
View File
@@ -4,7 +4,7 @@
var bower = require('bower');
var util = require('./utils.js');
var shelljs = require('shelljs');
var npmRun = require('npm-run');
module.exports = function(grunt) {
@@ -39,10 +39,7 @@ module.exports = function(grunt) {
grunt.registerTask('docs', 'create angular docs', function() {
var gruntProc = shelljs.exec('npm run gulp -- --gulpfile docs/gulpfile.js');
if (gruntProc.code !== 0) {
throw new Error('doc generation failed');
}
npmRun.execSync('gulp --gulpfile docs/gulpfile.js', {stdio: 'inherit'});
});
+5 -5
View File
@@ -3,7 +3,7 @@
var fs = require('fs');
var shell = require('shelljs');
var grunt = require('grunt');
var spawn = require('cross-spawn');
var spawn = require('npm-run').spawn;
var CSP_CSS_HEADER = '/* Include this file in your html if you are using the CSP mode. */\n\n';
@@ -15,7 +15,7 @@ module.exports = {
var reporters = grunt.option('reporters');
var noColor = grunt.option('no-colors');
var port = grunt.option('port');
var p = spawn('./node_modules/.bin/karma', ['start', config,
var p = spawn('karma', ['start', config,
singleRun ? '--single-run=true' : '',
reporters ? '--reporters=' + reporters : '',
browsers ? '--browsers=' + browsers : '',
@@ -38,7 +38,7 @@ module.exports = {
done();
return;
}
var p = spawn('./node_modules/.bin/webdriver-manager', ['update']);
var p = spawn('webdriver-manager', ['update']);
p.stdout.pipe(process.stdout);
p.stderr.pipe(process.stderr);
p.on('exit', function(code) {
@@ -65,7 +65,7 @@ module.exports = {
}
var p = spawn('./node_modules/.bin/protractor', args);
var p = spawn('protractor', args);
p.stdout.pipe(process.stdout);
p.stderr.pipe(process.stderr);
p.on('exit', function(code) {
@@ -178,7 +178,7 @@ module.exports = {
var classPathSep = (process.platform === 'win32') ? ';' : ':';
var minFile = file.replace(/\.js$/, '.min.js');
var mapFile = minFile + '.map';
var mapFileName = mapFile.match(/[^\/]+$/)[0];
var mapFileName = mapFile.match(/[^/]+$/)[0];
var errorFileName = file.replace(/\.js$/, '-errors.json');
var versionNumber = grunt.config('NG_VERSION').full;
var compilationLevel = (file === 'build/angular-message-format.js') ?
+1 -1
View File
@@ -11,7 +11,7 @@ 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
SC_VERSION="4.3.16"
SC_VERSION="4.4.1"
CONNECT_URL="https://saucelabs.com/downloads/sc-$SC_VERSION-linux.tar.gz"
CONNECT_DIR="/tmp/sauce-connect-$RANDOM"
CONNECT_DOWNLOAD="sc-$SC_VERSION-linux.tar.gz"
+1 -1
View File
@@ -35,7 +35,7 @@ var getPackage = function() {
* @return {Object} An object containing the github owner and repository name
*/
var getGitRepoInfo = function() {
var GITURL_REGEX = /^https:\/\/github.com\/([^\/]+)\/(.+).git$/;
var GITURL_REGEX = /^https:\/\/github.com\/([^/]+)\/(.+).git$/;
var match = GITURL_REGEX.exec(currentPackage.repository.url);
var git = {
owner: match[1],
File diff suppressed because it is too large Load Diff
-15811
View File
File diff suppressed because it is too large Load Diff
+14 -9
View File
@@ -1,41 +1,42 @@
{
"name": "angularjs",
"license": "MIT",
"branchVersion": "^1.5.8",
"branchVersion": "^1.6.0",
"branchPattern": "1.6.*",
"distTag": "next",
"distTag": "latest",
"repository": {
"type": "git",
"url": "https://github.com/angular/angular.js.git"
},
"engines": {
"node": "<5",
"npm": "~2.5"
"node": "^6.9.1",
"yarn": ">=0.17.9",
"grunt": "^1.2.0"
},
"scripts": {
"preinstall": "node scripts/npm/check-node-modules.js --purge",
"postinstall": "node scripts/npm/copy-npm-shrinkwrap.js",
"commit": "git-cz",
"test-i18n": "jasmine-node i18n/spec",
"test-i18n-ucd": "jasmine-node i18n/ucd/spec",
"gulp": "gulp"
"grunt": "grunt"
},
"devDependencies": {
"angular-benchpress": "0.x.x",
"benchmark": "1.x.x",
"bootstrap": "3.1.1",
"bower": "~1.3.9",
"browserstacktunnel-wrapper": "^1.4.2",
"canonical-path": "0.0.2",
"changez": "^2.1.1",
"changez-angular": "^2.1.0",
"changez-angular": "^2.1.3",
"cheerio": "^0.17.0",
"commitizen": "^2.3.0",
"cross-spawn": "^4.0.0",
"cz-conventional-changelog": "1.1.4",
"dgeni": "^0.4.0",
"dgeni-packages": "^0.16.0",
"dgeni-packages": "^0.16.4",
"event-stream": "~3.1.0",
"glob": "^6.0.1",
"google-code-prettify": "1.0.1",
"grunt": "^1.0.1",
"grunt-bump": "^0.8.0",
"grunt-cli": "^1.2.0",
@@ -58,6 +59,7 @@
"jasmine-core": "^2.4.0",
"jasmine-node": "^2.0.0",
"jasmine-reporters": "^2.2.0",
"jquery": "^3.1.1",
"karma": "^1.1.2",
"karma-browserstack-launcher": "^1.0.1",
"karma-chrome-launcher": "^1.0.1",
@@ -70,8 +72,11 @@
"load-grunt-tasks": "^3.5.0",
"lodash": "~2.4.1",
"log4js": "^0.6.27",
"lunr": "^0.7.2",
"marked": "~0.3.0",
"node-html-encoder": "0.0.2",
"npm-run": "^4.1.0",
"open-sans-fontface": "^1.4.0",
"promises-aplus-tests": "~2.1.0",
"protractor": "^4.0.10",
"q": "~1.0.0",
+4 -4
View File
@@ -15,7 +15,7 @@ function init {
BUILD_DIR=$(resolveDir ../../build)
NEW_VERSION=$(cat $BUILD_DIR/version.txt)
PROJECT_DIR=$(resolveDir ../..)
# get the npm dist-tag from a custom property (distTag) in package.json
# get the dist-tag for this release from a custom property (distTag) in package.json
DIST_TAG=$(readJsonProp "$PROJECT_DIR/package.json" "distTag")
}
@@ -27,7 +27,7 @@ function prepare {
for repo in "${REPOS[@]}"
do
echo "-- Cloning bower-$repo"
git clone git@github.com:angular/bower-$repo.git $TMP_DIR/bower-$repo
git clone git@github.com:angular/bower-$repo.git $TMP_DIR/bower-$repo --depth=1
done
@@ -96,9 +96,9 @@ function publish {
git push origin master
git push origin v$NEW_VERSION
# don't publish every build to npm
# don't publish every build to the npm repository
if [ "${NEW_VERSION/+sha}" = "$NEW_VERSION" ] ; then
echo "-- Publishing to npm as $DIST_TAG"
echo "-- Publishing to the npm repository as $DIST_TAG"
npm publish --tag=$DIST_TAG
fi
@@ -144,7 +144,7 @@ then(allInSeries(function(branch) {
line = line.split(' ');
var sha = line.shift();
var msg = line.join(' ');
return sha + ((/fix\([^\)]+\):/i.test(msg)) ? ' * ' : ' ') + msg;
return sha + ((/fix\([^)]+\):/i.test(msg)) ? ' * ' : ' ') + msg;
});
branch.log = log.map(function(line) {
return line.substr(41);
+7 -9
View File
@@ -4,7 +4,7 @@ echo "#################################"
echo "#### Jenkins Build ############"
echo "#################################"
source scripts/jenkins/set-node-version.sh
source scripts/jenkins/init-node.sh
# Enable tracing and exit on first failure
set -xe
@@ -12,7 +12,7 @@ set -xe
# This is the default set of browsers to use on the CI server unless overridden via env variable
if [[ -z "$BROWSERS" ]]
then
BROWSERS="Chrome,Firefox,Opera,/Users/jenkins/bin/safari.sh"
BROWSERS="Chrome,Firefox,/Users/jenkins/bin/safari.sh"
fi
# CLEAN #
@@ -21,23 +21,21 @@ rm -f angular.js.size
# BUILD #
npm install -g grunt-cli
npm install --color false
grunt ci-checks package --no-color
yarn run grunt -- ci-checks package --no-color
mkdir -p test_out
# UNIT TESTS #
grunt test:unit --browsers="$BROWSERS" --reporters=dots,junit --no-colors --no-color
yarn run grunt -- test:unit --browsers="$BROWSERS" --reporters=dots,junit --no-colors --no-color
# END TO END TESTS #
grunt test:ci-protractor
yarn run grunt -- test:ci-protractor
# DOCS APP TESTS #
grunt test:docs --browsers="$BROWSERS" --reporters=dots,junit --no-colors --no-color
yarn run grunt -- test:docs --browsers="$BROWSERS" --reporters=dots,junit --no-colors --no-color
# Promises/A+ TESTS #
grunt test:promises-aplus --no-color
yarn run grunt -- test:promises-aplus --no-color
# CHECK SIZE #
+18
View File
@@ -0,0 +1,18 @@
#!/bin/bash
# Install nvm for this shell
source ~/.nvm/nvm.sh
# Use version of node.js found in .nvmrc
nvm install
# clean out and install yarn
rm -rf ~/.yarn
curl -o- -L https://raw.githubusercontent.com/yarnpkg/yarn/2a0afc73210c7a82082585283e518eeb88ca19ae/scripts/install-latest.sh | bash -s -- --version 0.17.9
export PATH="$HOME/.yarn/bin:$PATH"
# Ensure that we have the local dependencies installed
yarn install
echo testing grunt version
yarn run grunt -- --version
+2 -5
View File
@@ -35,12 +35,9 @@ function init {
}
function build {
source ./set-node-version.sh
cd ../..
npm install -g grunt-cli
npm install --color false
grunt ci-checks package --no-color
source scripts/jenkins/init-node.sh
yarn run grunt -- ci-checks package --no-color
cd $SCRIPT_DIR
}
-7
View File
@@ -1,7 +0,0 @@
#!/bin/bash
# Install nvm for this shell
source ~/.nvm/nvm.sh
# Use node.js at 4.2.x
nvm install 4.4
-75
View File
@@ -1,75 +0,0 @@
// Implementation based on:
// https://github.com/angular/angular/blob/3b9c08676a4c921bbfa847802e08566fb601ba7a/tools/npm/check-node-modules.js
'use strict';
// Imports
var fs = require('fs');
var path = require('path');
// Constants
var PROJECT_ROOT = path.join(__dirname, '../../');
var NODE_MODULES_DIR = 'node_modules';
var NPM_SHRINKWRAP_FILE = 'npm-shrinkwrap.json';
var NPM_SHRINKWRAP_CACHED_FILE = NODE_MODULES_DIR + '/npm-shrinkwrap.cached.json';
// Run
_main();
// Functions - Definitions
function _main() {
var purgeIfStale = process.argv.indexOf('--purge') !== -1;
process.chdir(PROJECT_ROOT);
checkNodeModules(purgeIfStale);
}
function checkNodeModules(purgeIfStale) {
var nodeModulesOk = compareMarkerFiles(NPM_SHRINKWRAP_FILE, NPM_SHRINKWRAP_CACHED_FILE);
if (nodeModulesOk) {
console.log(':-) npm dependencies are looking good!');
} else if (purgeIfStale) {
console.log(':-( npm dependencies are stale or in an unknown state!');
console.log(' Purging \'' + NODE_MODULES_DIR + '\'...');
deleteDirSync(NODE_MODULES_DIR);
} else {
var separator = new Array(81).join('!');
console.warn(separator);
console.warn(':-( npm dependencies are stale or in an unknown state!');
console.warn('You can rebuild the dependencies by running `npm install`.');
console.warn(separator);
}
return nodeModulesOk;
}
function compareMarkerFiles(markerFilePath, cachedMarkerFilePath) {
if (!fs.existsSync(markerFilePath)) return false;
if (!fs.existsSync(cachedMarkerFilePath)) return false;
var opts = {encoding: 'utf-8'};
var markerContent = fs.readFileSync(markerFilePath, opts);
var cachedMarkerContent = fs.readFileSync(cachedMarkerFilePath, opts);
return markerContent === cachedMarkerContent;
}
// Custom implementation of `rm -rf` that works consistently across OSes
function deleteDirSync(path) {
if (fs.existsSync(path)) {
fs.readdirSync(path).forEach(deleteDirOrFileSync);
fs.rmdirSync(path);
}
// Helpers
function deleteDirOrFileSync(subpath) {
var curPath = path + '/' + subpath;
if (fs.lstatSync(curPath).isDirectory()) {
deleteDirSync(curPath);
} else {
fs.unlinkSync(curPath);
}
}
}
-40
View File
@@ -1,40 +0,0 @@
#!/usr/bin/env node
'use strict';
/**
* this script is just a temporary solution to deal with the issue of npm outputting the npm
* shrinkwrap file in an unstable manner.
*
* See: https://github.com/npm/npm/issues/3581
*/
var _ = require('lodash');
var sorted = require('sorted-object');
var fs = require('fs');
var path = require('path');
function cleanModule(module, name) {
// keep `resolve` properties for git dependencies, delete otherwise
delete module.from;
if (!(module.resolved && module.resolved.match(/^git(\+[a-z]+)?:\/\//))) {
delete module.resolved;
}
_.forEach(module.dependencies, function(mod, name) {
cleanModule(mod, name);
});
}
console.log('Reading npm-shrinkwrap.json');
var shrinkwrap = require('../../npm-shrinkwrap.json');
console.log('Cleaning shrinkwrap object');
cleanModule(shrinkwrap, shrinkwrap.name);
var cleanShrinkwrapPath = path.join(__dirname, '..', '..', 'npm-shrinkwrap.clean.json');
console.log('Writing cleaned to', cleanShrinkwrapPath);
fs.writeFileSync(cleanShrinkwrapPath, JSON.stringify(sorted(shrinkwrap), null, 2) + '\n');
-60
View File
@@ -1,60 +0,0 @@
'use strict';
// Imports
var fs = require('fs');
var path = require('path');
// Constants
var PROJECT_ROOT = path.join(__dirname, '../../');
var NODE_MODULES_DIR = 'node_modules';
var NPM_SHRINKWRAP_FILE = 'npm-shrinkwrap.json';
var NPM_SHRINKWRAP_CACHED_FILE = NODE_MODULES_DIR + '/npm-shrinkwrap.cached.json';
// Run
_main();
// Functions - Definitions
function _main() {
process.chdir(PROJECT_ROOT);
copyFile(NPM_SHRINKWRAP_FILE, NPM_SHRINKWRAP_CACHED_FILE, onCopied);
}
// Implementation based on:
// https://stackoverflow.com/questions/11293857/fastest-way-to-copy-file-in-node-js#answer-21995878
function copyFile(srcPath, dstPath, callback) {
var callbackCalled = false;
if (!fs.existsSync(srcPath)) {
done(new Error('Missing source file: ' + srcPath));
return;
}
var rs = fs.createReadStream(srcPath);
rs.on('error', done);
var ws = fs.createWriteStream(dstPath);
ws.on('error', done);
ws.on('finish', done);
rs.pipe(ws);
// Helpers
function done(err) {
if (callback && !callbackCalled) {
callbackCalled = true;
callback(err);
}
}
}
function onCopied(err) {
if (err) {
var separator = new Array(81).join('!');
console.error(separator);
console.error(
'Failed to copy `' + NPM_SHRINKWRAP_FILE + '` to `' + NPM_SHRINKWRAP_CACHED_FILE + '`:');
console.error(err);
console.error(separator);
}
}
+2 -2
View File
@@ -2,6 +2,8 @@
set -e
yarn global add grunt-cli@1.2.0
mkdir -p $LOGS_DIR
if [ $JOB != "ci-checks" ]; then
@@ -9,8 +11,6 @@ if [ $JOB != "ci-checks" ]; then
./scripts/travis/start_browser_provider.sh
fi
npm install -g grunt-cli
if [ $JOB != "ci-checks" ]; then
grunt package
echo "wait_for_browser_provider"
-9
View File
@@ -1,9 +0,0 @@
#!/bin/bash
set -e
# normalize the working dir to the directory of the script
cd $(dirname $0);
cd ../..
curl "http://23.251.148.50:8000/tar/$TRAVIS_REPO_SLUG/$TRAVIS_COMMIT" | tar xz || true
+4 -1
View File
@@ -15,6 +15,9 @@
"splice": false,
"push": false,
"toString": false,
"minErrConfig": false,
"errorHandlingConfig": false,
"isValidObjectMaxDepth": false,
"ngMinErr": false,
"_angular": false,
"angularModule": false,
@@ -150,7 +153,7 @@
/* apis.js */
"hashKey": false,
"HashMap": false,
"NgMap": false,
/* urlUtils.js */
"urlResolve": false,
+139 -32
View File
@@ -10,6 +10,9 @@
splice,
push,
toString,
minErrConfig,
errorHandlingConfig,
isValidObjectMaxDepth,
ngMinErr,
angularModule,
uid,
@@ -122,9 +125,85 @@ var REGEX_STRING_REGEXP = /^\/(.+)\/([a-z]*)$/;
// This is used so that it's possible for internal tests to create mock ValidityStates.
var VALIDITY_STATE_PROPERTY = 'validity';
var hasOwnProperty = Object.prototype.hasOwnProperty;
var minErrConfig = {
objectMaxDepth: 5
};
/**
* @ngdoc function
* @name angular.errorHandlingConfig
* @module ng
* @kind function
*
* @description
* Configure several aspects of error handling in AngularJS if used as a setter or return the
* current configuration if used as a getter. The following options are supported:
*
* - **objectMaxDepth**: The maximum depth to which objects are traversed when stringified for error messages.
*
* Omitted or undefined options will leave the corresponding configuration values unchanged.
*
* @param {Object=} config - The configuration object. May only contain the options that need to be
* updated. Supported keys:
*
* * `objectMaxDepth` **{Number}** - The max depth for stringifying objects. Setting to a
* non-positive or non-numeric value, removes the max depth limit.
* Default: 5
*/
function errorHandlingConfig(config) {
if (isObject(config)) {
if (isDefined(config.objectMaxDepth)) {
minErrConfig.objectMaxDepth = isValidObjectMaxDepth(config.objectMaxDepth) ? config.objectMaxDepth : NaN;
}
} else {
return minErrConfig;
}
}
/**
* @private
* @param {Number} maxDepth
* @return {boolean}
*/
function isValidObjectMaxDepth(maxDepth) {
return isNumber(maxDepth) && maxDepth > 0;
}
/**
* @ngdoc function
* @name angular.lowercase
* @module ng
* @kind function
*
* @deprecated
* sinceVersion="1.5.0"
* removeVersion="1.7.0"
* Use [String.prototype.toLowerCase](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String/toLowerCase) instead.
*
* @description Converts the specified string to lowercase.
* @param {string} string String to be converted to lowercase.
* @returns {string} Lowercased string.
*/
var lowercase = function(string) {return isString(string) ? string.toLowerCase() : string;};
/**
* @ngdoc function
* @name angular.uppercase
* @module ng
* @kind function
*
* @deprecated
* sinceVersion="1.5.0"
* removeVersion="1.7.0"
* Use [String.prototype.toUpperCase](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String/toUpperCase) instead.
*
* @description Converts the specified string to uppercase.
* @param {string} string String to be converted to uppercase.
* @returns {string} Uppercased string.
*/
var uppercase = function(string) {return isString(string) ? string.toUpperCase() : string;};
@@ -678,7 +757,7 @@ function isPromiseLike(obj) {
}
var TYPED_ARRAY_REGEXP = /^\[object (?:Uint8|Uint8Clamped|Uint16|Uint32|Int8|Int16|Int32|Float32|Float64)Array\]$/;
var TYPED_ARRAY_REGEXP = /^\[object (?:Uint8|Uint8Clamped|Uint16|Uint32|Int8|Int16|Int32|Float32|Float64)Array]$/;
function isTypedArray(value) {
return value && isNumber(value.length) && TYPED_ARRAY_REGEXP.test(toString.call(value));
}
@@ -697,7 +776,7 @@ var trim = function(value) {
// Prereq: s is a string.
var escapeForRegexp = function(s) {
return s
.replace(/([-()\[\]{}+?*.$\^|,:#<!\\])/g, '\\$1')
.replace(/([-()[\]{}+?*.$^|,:#<!\\])/g, '\\$1')
// eslint-disable-next-line no-control-regex
.replace(/\x08/g, '\\x08');
};
@@ -815,9 +894,10 @@ function arrayRemove(array, value) {
</file>
</example>
*/
function copy(source, destination) {
function copy(source, destination, maxDepth) {
var stackSource = [];
var stackDest = [];
maxDepth = isValidObjectMaxDepth(maxDepth) ? maxDepth : NaN;
if (destination) {
if (isTypedArray(destination) || isArrayBuffer(destination)) {
@@ -840,35 +920,39 @@ function copy(source, destination) {
stackSource.push(source);
stackDest.push(destination);
return copyRecurse(source, destination);
return copyRecurse(source, destination, maxDepth);
}
return copyElement(source);
return copyElement(source, maxDepth);
function copyRecurse(source, destination) {
function copyRecurse(source, destination, maxDepth) {
maxDepth--;
if (maxDepth < 0) {
return '...';
}
var h = destination.$$hashKey;
var key;
if (isArray(source)) {
for (var i = 0, ii = source.length; i < ii; i++) {
destination.push(copyElement(source[i]));
destination.push(copyElement(source[i], maxDepth));
}
} else if (isBlankObject(source)) {
// createMap() fast path --- Safe to avoid hasOwnProperty check because prototype chain is empty
for (key in source) {
destination[key] = copyElement(source[key]);
destination[key] = copyElement(source[key], maxDepth);
}
} else if (source && typeof source.hasOwnProperty === 'function') {
// Slow path, which must rely on hasOwnProperty
for (key in source) {
if (source.hasOwnProperty(key)) {
destination[key] = copyElement(source[key]);
destination[key] = copyElement(source[key], maxDepth);
}
}
} else {
// Slowest path --- hasOwnProperty can't be called as a method
for (key in source) {
if (hasOwnProperty.call(source, key)) {
destination[key] = copyElement(source[key]);
destination[key] = copyElement(source[key], maxDepth);
}
}
}
@@ -876,7 +960,7 @@ function copy(source, destination) {
return destination;
}
function copyElement(source) {
function copyElement(source, maxDepth) {
// Simple values
if (!isObject(source)) {
return source;
@@ -905,7 +989,7 @@ function copy(source, destination) {
stackDest.push(destination);
return needsRecurse
? copyRecurse(source, destination)
? copyRecurse(source, destination, maxDepth)
: destination;
}
@@ -941,7 +1025,7 @@ function copy(source, destination) {
return new source.constructor(source.valueOf());
case '[object RegExp]':
var re = new RegExp(source.source, source.toString().match(/[^\/]*$/)[0]);
var re = new RegExp(source.source, source.toString().match(/[^/]*$/)[0]);
re.lastIndex = source.lastIndex;
return re;
@@ -1318,7 +1402,7 @@ function startingTag(element) {
return element[0].nodeType === NODE_TYPE_TEXT ? lowercase(elemHtml) :
elemHtml.
match(/^(<[^>]+>)/)[1].
replace(/^<([\w\-]+)/, function(match, nodeName) {return '<' + lowercase(nodeName);});
replace(/^<([\w-]+)/, function(match, nodeName) {return '<' + lowercase(nodeName);});
} catch (e) {
return lowercase(elemHtml);
}
@@ -1447,28 +1531,51 @@ function getNgAttribute(element, ngAttr) {
}
function allowAutoBootstrap(document) {
if (!document.currentScript) {
var script = document.currentScript;
if (!script) {
// IE does not have `document.currentScript`
return true;
}
var src = document.currentScript.getAttribute('src');
var link = document.createElement('a');
link.href = src;
var scriptProtocol = link.protocol;
var docLoadProtocol = document.location.protocol;
if (docLoadProtocol === scriptProtocol) {
return true;
// If the `currentScript` property has been clobbered just return false, since this indicates a probable attack
if (!(script instanceof window.HTMLScriptElement || script instanceof window.SVGScriptElement)) {
return false;
}
switch (scriptProtocol) {
case 'http:':
case 'https:':
case 'ftp:':
case 'blob:':
case 'file:':
case 'data:':
var attributes = script.attributes;
var srcs = [attributes.getNamedItem('src'), attributes.getNamedItem('href'), attributes.getNamedItem('xlink:href')];
return srcs.every(function(src) {
if (!src) {
return true;
default:
}
if (!src.value) {
return false;
}
}
var link = document.createElement('a');
link.href = src.value;
if (document.location.origin === link.origin) {
// Same-origin resources are always allowed, even for non-whitelisted schemes.
return true;
}
// Disabled bootstrapping unless angular.js was loaded from a known scheme used on the web.
// This is to prevent angular.js bundled with browser extensions from being used to bypass the
// content security policy in web pages and other browser extensions.
switch (link.protocol) {
case 'http:':
case 'https:':
case 'ftp:':
case 'blob:':
case 'file:':
case 'data:':
return true;
default:
return false;
}
});
}
// Cached as it has to run during loading so that document.currentScript is available.
@@ -1832,7 +1939,7 @@ function bindJQuery() {
extend(jQuery.fn, {
scope: JQLitePrototype.scope,
isolateScope: JQLitePrototype.isolateScope,
controller: JQLitePrototype.controller,
controller: /** @type {?} */ (JQLitePrototype).controller,
injector: JQLitePrototype.injector,
inheritedData: JQLitePrototype.inheritedData
});
+5 -3
View File
@@ -70,7 +70,6 @@
$$ForceReflowProvider,
$InterpolateProvider,
$IntervalProvider,
$$HashMapProvider,
$HttpProvider,
$HttpParamSerializerProvider,
$HttpParamSerializerJQLikeProvider,
@@ -79,6 +78,7 @@
$jsonpCallbacksProvider,
$LocationProvider,
$LogProvider,
$$MapProvider,
$ParseProvider,
$RootScopeProvider,
$QProvider,
@@ -126,6 +126,7 @@ var version = {
function publishExternalAPI(angular) {
extend(angular, {
'errorHandlingConfig': errorHandlingConfig,
'bootstrap': bootstrap,
'copy': copy,
'extend': extend,
@@ -260,9 +261,10 @@ function publishExternalAPI(angular) {
$window: $WindowProvider,
$$rAF: $$RAFProvider,
$$jqLite: $$jqLiteProvider,
$$HashMap: $$HashMapProvider,
$$Map: $$MapProvider,
$$cookieReader: $$CookieReaderProvider
});
}
]);
])
.info({ angularVersion: '"NG_VERSION_FULL"' });
}
+1 -1
View File
@@ -1,6 +1,6 @@
/**
* @license AngularJS v"NG_VERSION_FULL"
* (c) 2010-2016 Google, Inc. http://angularjs.org
* (c) 2010-2017 Google, Inc. http://angularjs.org
* License: MIT
*/
(function(window) {
+55 -36
View File
@@ -1,6 +1,5 @@
'use strict';
/**
* Computes a hash of an 'obj'.
* Hash of a:
@@ -33,49 +32,69 @@ function hashKey(obj, nextUidFn) {
return key;
}
/**
* HashMap which can use objects as keys
*/
function HashMap(array, isolatedUid) {
if (isolatedUid) {
var uid = 0;
this.nextUid = function() {
return ++uid;
};
}
forEach(array, this.put, this);
// A minimal ES2015 Map implementation.
// Should be bug/feature equivalent to the native implementations of supported browsers
// (for the features required in Angular).
// See https://kangax.github.io/compat-table/es6/#test-Map
var nanKey = Object.create(null);
function NgMapShim() {
this._keys = [];
this._values = [];
this._lastKey = NaN;
this._lastIndex = -1;
}
HashMap.prototype = {
/**
* Store key value pair
* @param key key to store can be any type
* @param value value to store can be any type
*/
put: function(key, value) {
this[hashKey(key, this.nextUid)] = value;
NgMapShim.prototype = {
_idx: function(key) {
if (key === this._lastKey) {
return this._lastIndex;
}
this._lastKey = key;
this._lastIndex = this._keys.indexOf(key);
return this._lastIndex;
},
_transformKey: function(key) {
return isNumberNaN(key) ? nanKey : key;
},
/**
* @param key
* @returns {Object} the value for the key
*/
get: function(key) {
return this[hashKey(key, this.nextUid)];
key = this._transformKey(key);
var idx = this._idx(key);
if (idx !== -1) {
return this._values[idx];
}
},
set: function(key, value) {
key = this._transformKey(key);
var idx = this._idx(key);
if (idx === -1) {
idx = this._lastIndex = this._keys.length;
}
this._keys[idx] = key;
this._values[idx] = value;
/**
* Remove the key/value pair
* @param key
*/
remove: function(key) {
var value = this[key = hashKey(key, this.nextUid)];
delete this[key];
return value;
// Support: IE11
// Do not `return this` to simulate the partial IE11 implementation
},
delete: function(key) {
key = this._transformKey(key);
var idx = this._idx(key);
if (idx === -1) {
return false;
}
this._keys.splice(idx, 1);
this._values.splice(idx, 1);
this._lastKey = NaN;
this._lastIndex = -1;
return true;
}
};
var $$HashMapProvider = [/** @this */function() {
// For now, always use `NgMapShim`, even if `window.Map` is available. Some native implementations
// are still buggy (often in subtle ways) and can cause hard-to-debug failures. When native `Map`
// implementations get more stable, we can reconsider switching to `window.Map` (when available).
var NgMap = NgMapShim;
var $$MapProvider = [/** @this */function() {
this.$get = [function() {
return HashMap;
return NgMap;
}];
}];
+29 -9
View File
@@ -63,19 +63,15 @@
* Implicit module which gets automatically added to each {@link auto.$injector $injector}.
*/
var ARROW_ARG = /^([^\(]+?)=>/;
var FN_ARGS = /^[^\(]*\(\s*([^\)]*)\)/m;
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 stringifyFn(fn) {
// Support: Chrome 50-51 only
// Creating a new string by adding `' '` at the end, to hack around some bug in Chrome v50/51
// (See https://github.com/angular/angular.js/issues/14487.)
// TODO (gkalpak): Remove workaround when Chrome v52 is released
return Function.prototype.toString.call(fn) + ' ';
return Function.prototype.toString.call(fn);
}
function extractArgs(fn) {
@@ -184,6 +180,28 @@ function annotate(fn, strictDi, name) {
* As an array of injection names, where the last item in the array is the function to call.
*/
/**
* @ngdoc property
* @name $injector#modules
* @type {Object}
* @description
* A hash containing all the modules that have been loaded into the
* $injector.
*
* You can use this property to find out information about a module via the
* {@link angular.Module#info `myModule.info(...)`} method.
*
* For example:
*
* ```
* var info = $injector.modules['ngAnimate'].info();
* ```
*
* **Do not use this property to attempt to modify the modules after the application
* has been bootstrapped.**
*/
/**
* @ngdoc method
* @name $injector#get
@@ -649,7 +667,7 @@ function createInjector(modulesToLoad, strictDi) {
var INSTANTIATING = {},
providerSuffix = 'Provider',
path = [],
loadedModules = new HashMap([], true),
loadedModules = new NgMap(),
providerCache = {
$provide: {
provider: supportObject(provider),
@@ -677,6 +695,7 @@ function createInjector(modulesToLoad, strictDi) {
instanceInjector = protoInstanceInjector;
providerCache['$injector' + providerSuffix] = { $get: valueFn(protoInstanceInjector) };
instanceInjector.modules = providerInjector.modules = createMap();
var runBlocks = loadModules(modulesToLoad);
instanceInjector = protoInstanceInjector.get('$injector');
instanceInjector.strictDi = strictDi;
@@ -757,7 +776,7 @@ function createInjector(modulesToLoad, strictDi) {
var runBlocks = [], moduleFn;
forEach(modulesToLoad, function(module) {
if (loadedModules.get(module)) return;
loadedModules.put(module, true);
loadedModules.set(module, true);
function runInvokeQueue(queue) {
var i, ii;
@@ -772,6 +791,7 @@ function createInjector(modulesToLoad, strictDi) {
try {
if (isString(module)) {
moduleFn = angularModule(module);
instanceInjector.modules[module] = moduleFn;
runBlocks = runBlocks.concat(loadModules(moduleFn.requires)).concat(moduleFn._runBlocks);
runInvokeQueue(moduleFn._invokeQueue);
runInvokeQueue(moduleFn._configBlocks);
+8 -5
View File
@@ -979,12 +979,15 @@ forEach({
after: function(element, newElement) {
var index = element, parent = element.parentNode;
newElement = new JQLite(newElement);
for (var i = 0, ii = newElement.length; i < ii; i++) {
var node = newElement[i];
parent.insertBefore(node, index.nextSibling);
index = node;
if (parent) {
newElement = new JQLite(newElement);
for (var i = 0, ii = newElement.length; i < ii; i++) {
var node = newElement[i];
parent.insertBefore(node, index.nextSibling);
index = node;
}
}
},
+42
View File
@@ -79,6 +79,9 @@ function setupModuleLoader(window) {
* @returns {angular.Module} new module with the {@link angular.Module} api.
*/
return function module(name, requires, configFn) {
var info = {};
var assertNotHasOwnProperty = function(name, context) {
if (name === 'hasOwnProperty') {
throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context);
@@ -114,6 +117,45 @@ function setupModuleLoader(window) {
_configBlocks: configBlocks,
_runBlocks: runBlocks,
/**
* @ngdoc method
* @name angular.Module#info
* @module ng
*
* @param {Object=} info Information about the module
* @returns {Object|Module} The current info object for this module if called as a getter,
* or `this` if called as a setter.
*
* @description
* Read and write custom information about this module.
* For example you could put the version of the module in here.
*
* ```js
* angular.module('myModule', []).info({ version: '1.0.0' });
* ```
*
* The version could then be read back out by accessing the module elsewhere:
*
* ```
* var version = angular.module('myModule').info().version;
* ```
*
* You can also retrieve this information during runtime via the
* {@link $injector#modules `$injector.modules`} property:
*
* ```js
* var version = $injector.modules['myModule'].info().version;
* ```
*/
info: function(value) {
if (isDefined(value)) {
if (!isObject(value)) throw ngMinErr('aobj', 'Argument \'{0}\' must be an object', 'value');
info = value;
return this;
}
return info;
},
/**
* @ngdoc property
* @name angular.Module#requires
+5 -2
View File
@@ -1,8 +1,11 @@
/**
* @license AngularJS v"NG_VERSION_FULL"
* (c) 2010-2016 Google, Inc. http://angularjs.org
* (c) 2010-2017 Google, Inc. http://angularjs.org
* License: MIT
*/
'use strict';
(function() {
function isFunction(value) {return typeof value === 'function';};
function isFunction(value) {return typeof value === 'function';}
function isDefined(value) {return typeof value !== 'undefined';}
function isObject(value) {return value !== null && typeof value === 'object';}
+10 -12
View File
@@ -33,20 +33,19 @@
function minErr(module, ErrorConstructor) {
ErrorConstructor = ErrorConstructor || Error;
return function() {
var SKIP_INDEXES = 2;
var templateArgs = arguments,
code = templateArgs[0],
var code = arguments[0],
template = arguments[1],
message = '[' + (module ? module + ':' : '') + code + '] ',
template = templateArgs[1],
templateArgs = sliceArgs(arguments, 2).map(function(arg) {
return toDebugString(arg, minErrConfig.objectMaxDepth);
}),
paramPrefix, i;
message += template.replace(/\{\d+\}/g, function(match) {
var index = +match.slice(1, -1),
shiftedIndex = index + SKIP_INDEXES;
var index = +match.slice(1, -1);
if (shiftedIndex < templateArgs.length) {
return toDebugString(templateArgs[shiftedIndex]);
if (index < templateArgs.length) {
return templateArgs[index];
}
return match;
@@ -55,9 +54,8 @@ function minErr(module, ErrorConstructor) {
message += '\nhttp://errors.angularjs.org/"NG_VERSION_FULL"/' +
(module ? module + '/' : '') + code;
for (i = SKIP_INDEXES, paramPrefix = '?'; i < templateArgs.length; i++, paramPrefix = '&') {
message += paramPrefix + 'p' + (i - SKIP_INDEXES) + '=' +
encodeURIComponent(toDebugString(templateArgs[i]));
for (i = 0, paramPrefix = '?'; i < templateArgs.length; i++, paramPrefix = '&') {
message += paramPrefix + 'p' + i + '=' + encodeURIComponent(templateArgs[i]);
}
return new ErrorConstructor(message);
+1 -1
View File
@@ -1,6 +1,6 @@
/**
* @license AngularJS v"NG_VERSION_FULL"
* (c) 2010-2016 Google, Inc. http://angularjs.org
* (c) 2010-2017 Google, Inc. http://angularjs.org
* License: MIT
*/
(function(window, angular) {
+11 -9
View File
@@ -60,7 +60,7 @@ var $$CoreAnimateJsProvider = /** @this */ function() {
// this is prefixed with Core since it conflicts with
// the animateQueueProvider defined in ngAnimate/animateQueue.js
var $$CoreAnimateQueueProvider = /** @this */ function() {
var postDigestQueue = new HashMap();
var postDigestQueue = new NgMap();
var postDigestElements = [];
this.$get = ['$$AnimateRunner', '$rootScope',
@@ -139,7 +139,7 @@ var $$CoreAnimateQueueProvider = /** @this */ function() {
jqLiteRemoveClass(elm, toRemove);
}
});
postDigestQueue.remove(element);
postDigestQueue.delete(element);
}
});
postDigestElements.length = 0;
@@ -154,7 +154,7 @@ var $$CoreAnimateQueueProvider = /** @this */ function() {
if (classesAdded || classesRemoved) {
postDigestQueue.put(element, data);
postDigestQueue.set(element, data);
postDigestElements.push(element);
if (postDigestElements.length === 1) {
@@ -179,6 +179,7 @@ var $$CoreAnimateQueueProvider = /** @this */ function() {
*/
var $AnimateProvider = ['$provide', /** @this */ function($provide) {
var provider = this;
var classNameFilter = null;
this.$$registeredAnimations = Object.create(null);
@@ -247,15 +248,16 @@ var $AnimateProvider = ['$provide', /** @this */ function($provide) {
*/
this.classNameFilter = function(expression) {
if (arguments.length === 1) {
this.$$classNameFilter = (expression instanceof RegExp) ? expression : null;
if (this.$$classNameFilter) {
var reservedRegex = new RegExp('(\\s+|\\/)' + NG_ANIMATE_CLASSNAME + '(\\s+|\\/)');
if (reservedRegex.test(this.$$classNameFilter.toString())) {
throw $animateMinErr('nongcls','$animateProvider.classNameFilter(regex) prohibits accepting a regex value which matches/contains the "{0}" CSS class.', NG_ANIMATE_CLASSNAME);
classNameFilter = (expression instanceof RegExp) ? expression : null;
if (classNameFilter) {
var reservedRegex = new RegExp('[(\\s|\\/)]' + NG_ANIMATE_CLASSNAME + '[(\\s|\\/)]');
if (reservedRegex.test(classNameFilter.toString())) {
classNameFilter = null;
throw $animateMinErr('nongcls', '$animateProvider.classNameFilter(regex) prohibits accepting a regex value which matches/contains the "{0}" CSS class.', NG_ANIMATE_CLASSNAME);
}
}
}
return this.$$classNameFilter;
return classNameFilter;
};
this.$get = ['$$animateQueue', function($$animateQueue) {
+12 -11
View File
@@ -96,7 +96,6 @@ function Browser(window, document, $log, $sniffer) {
};
cacheState();
lastHistoryState = cachedState;
/**
* @name $browser#url
@@ -150,8 +149,6 @@ function Browser(window, document, $log, $sniffer) {
if ($sniffer.history && (!sameBase || !sameState)) {
history[replace ? 'replaceState' : 'pushState'](state, '', url);
cacheState();
// Do the assignment again so that those two variables are referentially identical.
lastHistoryState = cachedState;
} else {
if (!sameBase) {
pendingLocation = url;
@@ -200,8 +197,7 @@ function Browser(window, document, $log, $sniffer) {
function cacheStateAndFireUrlChange() {
pendingLocation = null;
cacheState();
fireUrlChange();
fireStateOrUrlChange();
}
// This variable should be used *only* inside the cacheState function.
@@ -215,11 +211,16 @@ function Browser(window, document, $log, $sniffer) {
if (equals(cachedState, lastCachedState)) {
cachedState = lastCachedState;
}
lastCachedState = cachedState;
lastHistoryState = cachedState;
}
function fireUrlChange() {
if (lastBrowserUrl === self.url() && lastHistoryState === cachedState) {
function fireStateOrUrlChange() {
var prevLastHistoryState = lastHistoryState;
cacheState();
if (lastBrowserUrl === self.url() && prevLastHistoryState === cachedState) {
return;
}
@@ -254,8 +255,8 @@ function Browser(window, document, $log, $sniffer) {
self.onUrlChange = function(callback) {
// TODO(vojta): refactor to use node's syntax for events
if (!urlChangeInit) {
// We listen on both (hashchange/popstate) when available, as some browsers (e.g. Opera)
// don't fire popstate when user change the address bar and don't fire hashchange when url
// We listen on both (hashchange/popstate) when available, as some browsers don't
// fire popstate when user changes the address bar and don't fire hashchange when url
// changed by push/replaceState
// html5 history api - popstate event
@@ -285,7 +286,7 @@ function Browser(window, document, $log, $sniffer) {
* Needs to be exported to be able to check for changes that have been done in sync,
* as hashchange/popstate events fire in async.
*/
self.$$checkUrlChange = fireUrlChange;
self.$$checkUrlChange = fireStateOrUrlChange;
//////////////////////////////////////////////////////////////
// Misc API
@@ -302,7 +303,7 @@ function Browser(window, document, $log, $sniffer) {
*/
self.baseHref = function() {
var href = baseElement.attr('href');
return href ? href.replace(/^(https?:)?\/\/[^\/]*/, '') : '';
return href ? href.replace(/^(https?:)?\/\/[^/]*/, '') : '';
};
/**
+12 -9
View File
@@ -128,7 +128,8 @@
* * `$onChanges(changesObj)` - Called whenever one-way (`<`) or interpolation (`@`) bindings are updated. The
* `changesObj` is a hash whose keys are the names of the bound properties that have changed, and the values are an
* object of the form `{ currentValue, previousValue, isFirstChange() }`. Use this hook to trigger updates within a
* component such as cloning the bound value to prevent accidental mutation of the outer value.
* component such as cloning the bound value to prevent accidental mutation of the outer value. Note that this will
* also be called when your bindings are initialized.
* * `$doCheck()` - Called on each turn of the digest cycle. Provides an opportunity to detect and act on
* changes. Any actions that you wish to take in response to the changes that you detect must be
* invoked from this hook; implementing this has no effect on when `$onChanges` is called. For example, this hook
@@ -276,10 +277,12 @@
* the directive's element. If multiple directives on the same element request a new scope,
* only one new scope is created.
*
* * **`{...}` (an object hash):** A new "isolate" scope is created for the directive's element. The
* 'isolate' scope differs from normal scope in that it does not prototypically inherit from its parent
* scope. This is useful when creating reusable components, which should not accidentally read or modify
* data in the parent scope.
* * **`{...}` (an object hash):** A new "isolate" scope is created for the directive's template.
* The 'isolate' scope differs from normal scope in that it does not prototypically
* inherit from its parent scope. This is useful when creating reusable components, which should not
* accidentally read or modify data in the parent scope. Note that an isolate scope
* directive without a `template` or `templateUrl` will not apply the isolate scope
* to its children elements.
*
* The 'isolate' scope object hash defines a set of local scope properties derived from attributes on the
* directive's element. These local properties are useful for aliasing values for templates. The keys in
@@ -971,8 +974,8 @@ $CompileProvider.$inject = ['$provide', '$$sanitizeUriProvider'];
function $CompileProvider($provide, $$sanitizeUriProvider) {
var hasDirectives = {},
Suffix = 'Directive',
COMMENT_DIRECTIVE_REGEXP = /^\s*directive:\s*([\w\-]+)\s+(.*)$/,
CLASS_DIRECTIVE_REGEXP = /(([\w\-]+)(?::([^;]+))?;?)/,
COMMENT_DIRECTIVE_REGEXP = /^\s*directive:\s*([\w-]+)\s+(.*)$/,
CLASS_DIRECTIVE_REGEXP = /(([\w-]+)(?::([^;]+))?;?)/,
ALL_OR_NOTHING_ATTRS = makeMap('ngSrc,ngSrcset,src,srcset'),
REQUIRE_PREFIX_REGEXP = /^(?:(\^\^?)?(\?)?(\^\^?)?)?/;
@@ -983,7 +986,7 @@ 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 = createMap();
@@ -3155,7 +3158,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
if (error instanceof Error) {
$exceptionHandler(error);
}
}).catch(noop);
});
return function delayedNodeLinkFn(ignoreChildLinkFn, scope, node, rootElement, boundTranscludeFn) {
var childBoundTranscludeFn = boundTranscludeFn;
+9 -1
View File
@@ -14,6 +14,14 @@ function $$CookieReader($document) {
var lastCookies = {};
var lastCookieString = '';
function safeGetCookie(rawDocument) {
try {
return rawDocument.cookie || '';
} catch (e) {
return '';
}
}
function safeDecodeURIComponent(str) {
try {
return decodeURIComponent(str);
@@ -24,7 +32,7 @@ function $$CookieReader($document) {
return function() {
var cookieArray, cookie, i, index, name;
var currentCookieString = rawDocument.cookie || '';
var currentCookieString = safeGetCookie(rawDocument);
if (currentCookieString !== lastCookieString) {
lastCookieString = currentCookieString;
+2 -1
View File
@@ -159,7 +159,8 @@
*
* @description
*
* This directive sets the `disabled` attribute on the element if the
* This directive sets the `disabled` attribute on the element (typically a form control,
* e.g. `input`, `button`, `select` etc.) if the
* {@link guide/expression expression} inside `ngDisabled` evaluates to truthy.
*
* A special directive is necessary because we cannot use interpolation inside the `disabled`
+23 -8
View File
@@ -21,11 +21,11 @@ var ISO_DATE_REGEXP = /^\d{4,}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+(?:[+-
// 7. Path
// 8. Query
// 9. Fragment
// 1111111111111111 222 333333 44444 555555555555555555555555 666 77777777 8888888 999
var URL_REGEXP = /^[a-z][a-z\d.+-]*:\/*(?:[^:@]+(?::[^@]+)?@)?(?:[^\s:/?#]+|\[[a-f\d:]+\])(?::\d+)?(?:\/[^?#]*)?(?:\?[^#]*)?(?:#.*)?$/i;
// 1111111111111111 222 333333 44444 55555555555555555555555 666 77777777 8888888 999
var URL_REGEXP = /^[a-z][a-z\d.+-]*:\/*(?:[^:@]+(?::[^@]+)?@)?(?:[^\s:/?#]+|\[[a-f\d:]+])(?::\d+)?(?:\/[^?#]*)?(?:\?[^#]*)?(?:#.*)?$/i;
// eslint-disable-next-line max-len
var EMAIL_REGEXP = /^(?=.{1,254}$)(?=.{1,64}@)[-!#$%&'*+\/0-9=?A-Z^_`a-z{|}~]+(\.[-!#$%&'*+\/0-9=?A-Z^_`a-z{|}~]+)*@[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?(\.[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?)*$/;
var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))([eE][+-]?\d+)?\s*$/;
var EMAIL_REGEXP = /^(?=.{1,254}$)(?=.{1,64}@)[-!#$%&'*+/0-9=?A-Z^_`a-z{|}~]+(\.[-!#$%&'*+/0-9=?A-Z^_`a-z{|}~]+)*@[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?(\.[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?)*$/;
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)$/;
@@ -688,7 +688,7 @@ var inputType = {
* but does not trigger HTML5 native validation. Takes an expression.
* @param {string=} step Sets the `step` validation error key if the value entered does not fit the `step` constraint.
* Can be interpolated.
* @param {string=} ngStep Like `step`, sets the `max` validation error key if the value entered does not fit the `ngStep` constraint,
* @param {string=} ngStep Like `step`, sets the `step` validation error key if the value entered does not fit the `ngStep` constraint,
* but does not trigger HTML5 native validation. Takes an expression.
* @param {string=} required Sets `required` validation error key if the value is not entered.
* @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
@@ -1565,15 +1565,27 @@ function isValidForStep(viewValue, stepBase, step) {
// and `viewValue` is expected to be a valid stringified number.
var value = Number(viewValue);
var isNonIntegerValue = !isNumberInteger(value);
var isNonIntegerStepBase = !isNumberInteger(stepBase);
var isNonIntegerStep = !isNumberInteger(step);
// Due to limitations in Floating Point Arithmetic (e.g. `0.3 - 0.2 !== 0.1` or
// `0.5 % 0.1 !== 0`), we need to convert all numbers to integers.
if (!isNumberInteger(value) || !isNumberInteger(stepBase) || !isNumberInteger(step)) {
var decimalCount = Math.max(countDecimals(value), countDecimals(stepBase), countDecimals(step));
if (isNonIntegerValue || isNonIntegerStepBase || isNonIntegerStep) {
var valueDecimals = isNonIntegerValue ? countDecimals(value) : 0;
var stepBaseDecimals = isNonIntegerStepBase ? countDecimals(stepBase) : 0;
var stepDecimals = isNonIntegerStep ? countDecimals(step) : 0;
var decimalCount = Math.max(valueDecimals, stepBaseDecimals, stepDecimals);
var multiplier = Math.pow(10, decimalCount);
value = value * multiplier;
stepBase = stepBase * multiplier;
step = step * multiplier;
if (isNonIntegerValue) value = Math.round(value);
if (isNonIntegerStepBase) stepBase = Math.round(stepBase);
if (isNonIntegerStep) step = Math.round(step);
}
return (value - stepBase) % step === 0;
@@ -2130,7 +2142,10 @@ var ngValueDirective = function() {
* makes it possible to use ngValue as a sort of one-way bind.
*/
function updateElementValue(element, attr, value) {
element.prop('value', value);
// Support: IE9 only
// In IE9 values are converted to string (e.g. `input.value = null` results in `input.value === 'null'`).
var propValue = isDefined(value) ? value : (msie === 9) ? '' : null;
element.prop('value', propValue);
attr.$set('value', value);
}

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