Compare commits

..

208 Commits

Author SHA1 Message Date
Matias Niemelä a84393eadb chore($AnimateRunner): examine the document more carefully
Some internal tests were failing because the `$document[0]` value
was null. This fix ensures that the if statement surrounding that
is more careful.
2016-01-20 10:11:04 -08:00
Daniel Herman c429ad82f5 chore($compile): remove an unused dependency
Fixes #13791

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Closes #13583

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

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

Applies to 1.2, 1.3, 1.4 and 1.5.

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

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

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

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

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

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

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

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

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

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

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

Fixes #13528

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

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

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

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

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

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

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

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

Partly fixes #13393.

BREAKING CHANGE:

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

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

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

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

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

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

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

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

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

Also put  html, js and css into separate files.

Also change anchors to buttons.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

This commit fixes it.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Long version, things happen in the following order:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

This can happen in the following cases:

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

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

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

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

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

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

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

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

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

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

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

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

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

Fixes #11143
Closes #11353

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

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

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

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

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

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

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

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

Closes #12860
2015-09-22 10:44:27 +01:00
Jason Bedard 5a98e806ef fix($compile): use createMap() for $$observe listeners when initialized from attr interpolation
Closes #10446
2015-09-21 19:05:20 +01:00
Ivan Verevkin 808f984ec0 docs($cacheFactory): fix call to isUndefined() in example
Closes #12899
2015-09-21 15:51:49 +03:00
Lucas Mirelmann 698af191de fix($parse): do not convert to string computed properties multiple times
Do not convert to string properties multiple times.
2015-09-19 22:21:59 +02:00
Sjur Bakka 7a413df5e4 feat($http): add $xhrFactory service to enable creation of custom xhr objects
Closes #2318
Closes #9319
Closes #12159
2015-09-18 19:52:50 +01:00
Peter Bacon Darwin 4994acd26e fix(filters): ensure formatNumber observes i18n decimal separators
Closes #10342
Closes #12850
2015-09-18 13:45:29 +01:00
943 changed files with 13014 additions and 21855 deletions
-27
View File
@@ -1,27 +0,0 @@
***Note*: for support questions, please use one of these channels: https://github.com/angular/angular.js/blob/master/CONTRIBUTING.md#question. This repository's issues are reserved for feature requests and bug reports.**
**Do you want to request a *feature* or report a *bug*?**
**What is the current behavior?**
**If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem via https://plnkr.co or similar (template: http://plnkr.co/edit/tpl:yBpEi4).**
**What is the expected behavior?**
**What is the motivation / use case for changing the behavior?**
**Which versions of Angular, and which browser / OS are affected by this issue? Did this work in previous versions of Angular? Please also test with the latest stable and snapshot (https://code.angularjs.org/snapshot/) versions.**
**Other information (e.g. stacktraces, related issues, suggestions how to fix)**
-23
View File
@@ -1,23 +0,0 @@
**What kind of change does this PR introduce? (Bug fix, feature, docs update, ...)**
**What is the current behavior? (You can also link to an open issue here)**
**What is the new behavior (if this is a feature change)?**
**Does this PR introduce a breaking change?**
**Please check if the PR fulfills these requirements**
- [ ] The commit message follows our guidelines: https://github.com/angular/angular.js/blob/master/CONTRIBUTING.md#commit-message-format
- [ ] Tests for the changes have been added (for bug fixes / features)
- [ ] Docs have been added / updated (for bug fixes / features)
**Other information**:
+3 -4
View File
@@ -1,7 +1,7 @@
language: node_js
sudo: false
node_js:
- '4.4'
- '4.2'
cache:
directories:
@@ -62,7 +62,6 @@ notifications:
webhooks:
urls:
- https://webhooks.gitter.im/e/d2120f3f2bb39a4531b2
- http://104.197.9.155:8484/hubot/travis/activity #hubot-server
on_success: always # options: [always|never|change] default: always
on_success: change # options: [always|never|change] default: always
on_failure: always # options: [always|never|change] default: always
on_start: always # default: false
on_start: false # default: false
+56 -1220
View File
File diff suppressed because it is too large Load Diff
-2
View File
@@ -193,8 +193,6 @@ We have very precise rules over how our git commit messages can be formatted. T
readable messages** that are easy to follow when looking through the **project history**. But also,
we use the git commit messages to **generate the AngularJS change log**.
The commit message formatting can be added using a typical git workflow or through the use of a CLI wizard ([Commitizen](https://github.com/commitizen/cz-cli)). To use the wizard, run `npm run commit` in your terminal after staging your changes in git.
### Commit Message Format
Each commit message consists of a **header**, a **body** and a **footer**. The header has a special
format that includes a **type**, a **scope** and a **subject**:
+1 -6
View File
@@ -264,17 +264,12 @@ module.exports = function(grunt) {
],
options: {
disallowed: [
'fit',
'iit',
'xit',
'fthey',
'tthey',
'xthey',
'fdescribe',
'ddescribe',
'xdescribe',
'it.only',
'describe.only'
'xdescribe'
]
}
},
+1 -1
View File
@@ -1,6 +1,6 @@
The MIT License
Copyright (c) 2010-2016 Google, Inc. http://angularjs.org
Copyright (c) 2010-2015 Google, Inc. http://angularjs.org
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
+2 -25
View File
@@ -18,7 +18,7 @@ piece of cake. Best of all?? It makes development fun!
* Developer Guide: http://docs.angularjs.org/guide
* Contribution guidelines: [CONTRIBUTING.md](https://github.com/angular/angular.js/blob/master/CONTRIBUTING.md)
* Dashboard: http://dashboard.angularjs.org
Building AngularJS
---------
[Once you have your environment set up](http://docs.angularjs.org/misc/contribute) just run:
@@ -26,7 +26,7 @@ Building AngularJS
grunt package
Running tests
Running Tests
-------------
To execute all unit tests, use:
@@ -43,26 +43,3 @@ To learn more about the grunt tasks, run `grunt --help` and also read our
[![Analytics](https://ga-beacon.appspot.com/UA-8594346-11/angular.js/README.md?pixel)](https://github.com/igrigorik/ga-beacon)
What to use AngularJS for and when to use it
---------
AngularJS is the next generation framework where each component is designed to work with every other component in an interconnected way like a well-oiled machine. AngularJS is JavaScript MVC made easy and done right. (Well it is not really MVC, read on, to understand what this means.)
#### MVC, no, MV* done the right way!
MVC, short for Model-View-Controller, is a design pattern, i.e. how the code should be organized and how the different parts of an application separated for proper readability and debugging. Model is the data and the database. View is the user interface and what the user sees. Controller is the main link between Model and View. These are the three pillars of major programming frameworks present on the market today. On the other hand AngularJS works on MV*, short for Model-View-_Whatever_. The _Whatever_ is AngularJS's way of telling that you may create any kind of linking between the Model and the View here.
Unlike other frameworks in any programming language, where MVC, the three separate components, each one has to be written and then connected by the programmer, AngularJS helps the programmer by asking him/her to just create these and everything else will be taken care of by AngularJS.
#### Interconnection with HTML at the root level
AngularJS uses HTML to define the user's interface. AngularJS also enables the programmer to write new HTML tags (AngularJS Directives) and increase the readability and understandability of the HTML code. Directives are AngularJSs way of bringing additional functionality to HTML. Directives achieve this by enabling us to invent our own HTML elements. This also helps in making the code DRY (Don't Repeat Yourself), which means once created, a new directive can be used anywhere within the application.
#### Data Handling made simple
Data and Data Models in AngularJS are plain JavaScript objects and one can add and change properties directly on it and loop over objects and arrays at will.
#### Two-way Data Binding
One of AngularJS's strongest features. Two-way Data Binding means that if something changes in the Model, the change gets reflected in the View instantaneously, and the same happens the other way around. This is also referred to as Reactive Programming, i.e. suppose `a = b + c` is being programmed and after this, if the value of `b` and/or `c` is changed then the value of `a` will be automatically updated to reflect the change. AngularJS uses its "scopes" as a glue between the Model and View and makes these updates in one available for the other.
#### Less Written Code and Easily Maintainable Code
Everything in AngularJS is created to enable the programmer to end up writing less code that is easily maintainable and readable by any other new person on the team. Believe it or not, one can write a complete working two-way data binded application in less than 10 lines of code. Try and see for yourself!
#### Testing Ready
AngularJS has Dependency Injection, i.e. it takes care of providing all the necessary dependencies to its controllers whenever required. This helps in making the AngularJS code ready for unit testing by making use of mock dependencies created and injected. This makes AngularJS more modular and easily testable thus in turn helping a team create more robust applications.
+1 -1
View File
@@ -20,7 +20,7 @@ The following is done automatically so you don't have to worry about it:
This process based on the idea of minimizing user pain
[from this blog post](http://www.lostgarden.com/2008/05/improving-bug-triage-with-user-pain.html).
1. Open the list of [non triaged issues](https://github.com/angular/angular.js/issues?q=is%3Aopen+sort%3Acreated-desc+no%3Amilestone)
1. Open the list of [non triaged issues](https://github.com/angular/angular.js/issues?direction=desc&milestone=none&page=1&sort=created&state=open)
* Sort by submit date, with the newest issues first
* You don't have to do issues in order; feel free to pick and choose issues as you please.
* You can triage older issues as well
-2
View File
@@ -102,7 +102,6 @@ var angularFiles = {
'src/ngAnimate/animateJsDriver.js',
'src/ngAnimate/animateQueue.js',
'src/ngAnimate/animation.js',
'src/ngAnimate/ngAnimateSwap.js',
'src/ngAnimate/module.js'
],
'ngCookies': [
@@ -205,7 +204,6 @@ var angularFiles = {
"karmaModules": [
'build/angular.js',
'@angularSrcModules',
'test/modules/no_bootstrap.js',
'src/ngScenario/browserTrigger.js',
'test/helpers/*.js',
'test/ngMessageFormat/*.js',
+14 -14
View File
@@ -8,20 +8,20 @@
Large table rendered with AngularJS
</p>
<div><label><input type="radio" ng-model="benchmarkType" value="none">none: </label></div>
<div><label><input type="radio" ng-model="benchmarkType" value="baselineBinding">baseline binding: </label></div>
<div><label><input type="radio" ng-model="benchmarkType" value="baselineInterpolation">baseline interpolation: </label></div>
<div><label><input type="radio" ng-model="benchmarkType" value="ngBind">ngBind: </label></div>
<div><label><input type="radio" ng-model="benchmarkType" value="ngBindOnce">ngBindOnce: </label></div>
<div><label><input type="radio" ng-model="benchmarkType" value="interpolation">interpolation: </label></div>
<div><label><input type="radio" ng-model="benchmarkType" value="bindOnceInterpolation">interpolation + bind-once: </label></div>
<div><label><input type="radio" ng-model="benchmarkType" value="interpolationAttr">attribute interpolation: </label></div>
<div><label><input type="radio" ng-model="benchmarkType" value="ngBindFn">ngBind + fnInvocation: </label></div>
<div><label><input type="radio" ng-model="benchmarkType" value="interpolationFn">interpolation + fnInvocation: </label></div>
<div><label><input type="radio" ng-model="benchmarkType" value="ngBindFilter">ngBind + filter: </label></div>
<div><label><input type="radio" ng-model="benchmarkType" value="interpolationFilter">interpolation + filter: </label></div>
<div><label><input type="radio" ng-model="benchmarkType" value="ngModelConstName">ngModel (const name): </label></div>
<div><label><input type="radio" ng-model="benchmarkType" value="ngModelInterpName">ngModel (interp name): </label></div>
<div>none: <input type="radio" ng-model="benchmarkType" value="none"></div>
<div>baseline binding: <input type="radio" ng-model="benchmarkType" value="baselineBinding"></div>
<div>baseline interpolation: <input type="radio" ng-model="benchmarkType" value="baselineInterpolation"></div>
<div>ngBind: <input type="radio" ng-model="benchmarkType" value="ngBind"></div>
<div>ngBindOnce: <input type="radio" ng-model="benchmarkType" value="ngBindOnce"></div>
<div>interpolation: <input type="radio" ng-model="benchmarkType" value="interpolation"></div>
<div>interpolation + bind-once: <input type="radio" ng-model="benchmarkType" value="bindOnceInterpolation"></div>
<div>attribute interpolation: <input type="radio" ng-model="benchmarkType" value="interpolationAttr"></div>
<div>ngBind + fnInvocation: <input type="radio" ng-model="benchmarkType" value="ngBindFn"></div>
<div>interpolation + fnInvocation: <input type="radio" ng-model="benchmarkType" value="interpolationFn"></div>
<div>ngBind + filter: <input type="radio" ng-model="benchmarkType" value="ngBindFilter"></div>
<div>interpolation + filter: <input type="radio" ng-model="benchmarkType" value="interpolationFilter"></div>
<div>ngModel (const name): <input type="radio" ng-model="benchmarkType" value="ngModelConstName"></div>
<div>ngModel (interp name): <input type="radio" ng-model="benchmarkType" value="ngModelInterpName"></div>
<ng-switch on="benchmarkType">
<baseline-binding-table ng-switch-when="baselineBinding">
-1
View File
@@ -1,6 +1,5 @@
{
"name": "AngularJS",
"license": "MIT",
"devDependencies": {
"jquery": "2.1.1",
"closure-compiler": "https://dl.google.com/closure-compiler/compiler-20140814.zip",
+1 -86
View File
@@ -315,13 +315,8 @@ iframe.example {
color:white;
}
.search-results-group .search-results {
padding: 0 5px 0;
list-style-type: none;
}
.search-results-frame > .search-results-group:first-child > .search-results {
border-right:1px solid #222;
border-right:1px solid #050505;
}
.search-results-group.col-group-api { width:30%; }
@@ -330,57 +325,10 @@ iframe.example {
.search-results-group.col-group-misc,
.search-results-group.col-group-error { width:15%; float: right; }
@supports ((column-count: 2) or (-moz-column-count: 2) or (-ms-column-count: 2) or (-webkit-column-count: 2)) {
.search-results-group.col-group-api .search-results {
-moz-column-count: 2;
-ms-column-count: 2;
-webkit-column-count: 2;
column-count: 2;
/* Prevent bullets in the second column from being hidden in Chrome and IE */
-webkit-column-gap: 2em;
-ms-column-gap: 2em;
column-gap: 2em;
}
}
.search-results-group .search-result {
word-wrap: break-word;
-webkit-hyphens: auto;
-moz-hyphens: auto;
-ms-hyphens: auto;
hyphens: auto;
-ms-column-break-inside: avoid;
-webkit-column-break-inside: avoid;
-moz-column-break-inside: avoid; /* Unsupported */
column-break-inside: avoid;
text-indent: -0.65em; /* Make sure line wrapped words are aligned vertically */
}
@supports (-moz-column-count: 2) {
.search-results-group .search-result {
/* Prevents column breaks inside words in FF, but has adverse effects in IE11 and Chrome */
overflow: hidden;
padding-left: 1em; /* In FF the list item bullet is otherwise hidden */
margin-left: -1em; /* offset the padding left */
}
}
.search-result:before {
content: "\002D\00A0"; /* Dash and non-breaking space as List item type */
position: relative;
}
.search-results-group.col-group-api .search-result {
width:48%;
display:inline-block;
padding-left: 12px;
}
@supports ((column-count: 2) or (-moz-column-count: 2) or (-ms-column-count: 2) or (-webkit-column-count: 2)) {
.search-results-group.col-group-api .search-result {
width:auto;
display: list-item;
}
}
.search-close {
@@ -740,11 +688,6 @@ ul.events > li {
padding-bottom:60px;
text-align:left;
}
.search-results-frame > .search-results-group:first-child > .search-results {
border-right: none;
}
.search-results-group {
float:none!important;
display:block!important;
@@ -752,42 +695,14 @@ ul.events > li {
border:0!important;
padding:0!important;
}
@supports ((column-count: 2) or (-moz-column-count: 2) or (-ms-column-count: 2) or (-webkit-column-count: 2)) {
.search-results-group .search-results {
-moz-column-count: 2;
-ms-column-count: 2;
-webkit-column-count: 2;
column-count: 2;
}
}
.search-results-group .search-result {
display:inline-block!important;
padding:0 5px;
width:auto!important;
text-indent: initial;
margin-left: 0;
}
.search-results-group .search-result:after {
content:", ";
}
.search-results-group .search-result:before {
content: "";
}
@supports ((column-count: 2) or (-moz-column-count: 2) or (-ms-column-count: 2) or (-webkit-column-count: 2)) {
.search-results-group .search-result {
display: list-item !important;
}
.search-results-group .search-result:after {
content: "";
}
}
#wrapper {
padding-bottom:0px;
}
+442
View File
@@ -0,0 +1,442 @@
'use strict';
var directive = {};
directive.runnableExample = ['$templateCache', '$document', function($templateCache, $document) {
var exampleClassNameSelector = '.runnable-example-file';
var doc = $document[0];
var tpl =
'<nav class="runnable-example-tabs" ng-if="tabs">' +
' <a ng-class="{active:$index==activeTabIndex}"' +
'ng-repeat="tab in tabs track by $index" ' +
'href="" ' +
'class="btn"' +
'ng-click="setTab($index)">' +
' {{ tab }}' +
' </a>' +
'</nav>';
return {
restrict: 'C',
scope : true,
controller : ['$scope', function($scope) {
$scope.setTab = function(index) {
var tab = $scope.tabs[index];
$scope.activeTabIndex = index;
$scope.$broadcast('tabChange', index, tab);
};
}],
compile : function(element) {
element.html(tpl + element.html());
return function(scope, element) {
var node = element[0];
var examples = node.querySelectorAll(exampleClassNameSelector);
var tabs = [], now = Date.now();
angular.forEach(examples, function(child, index) {
tabs.push(child.getAttribute('name'));
});
if(tabs.length > 0) {
scope.tabs = tabs;
scope.$on('tabChange', function(e, index, title) {
angular.forEach(examples, function(child) {
child.style.display = 'none';
});
var selected = examples[index];
selected.style.display = 'block';
});
scope.setTab(0);
}
}
}
};
}];
directive.dropdownToggle =
['$document', '$location', '$window',
function ($document, $location, $window) {
var openElement = null, close;
return {
restrict: 'C',
link: function(scope, element, attrs) {
scope.$watch(function dropdownTogglePathWatch(){return $location.path();}, function dropdownTogglePathWatchAction() {
close && close();
});
element.parent().on('click', function(event) {
close && close();
});
element.on('click', function(event) {
event.preventDefault();
event.stopPropagation();
var iWasOpen = false;
if (openElement) {
iWasOpen = openElement === element;
close();
}
if (!iWasOpen){
element.parent().addClass('open');
openElement = element;
close = function (event) {
event && event.preventDefault();
event && event.stopPropagation();
$document.off('click', close);
element.parent().removeClass('open');
close = null;
openElement = null;
}
$document.on('click', close);
}
});
}
};
}];
directive.syntax = function() {
return {
restrict: 'A',
link: function(scope, element, attrs) {
function makeLink(type, text, link, icon) {
return '<a href="' + link + '" class="btn syntax-' + type + '" target="_blank" rel="nofollow">' +
'<span class="' + icon + '"></span> ' + text +
'</a>';
};
var html = '';
var types = {
'github' : {
text : 'View on Github',
key : 'syntaxGithub',
icon : 'icon-github'
},
'plunkr' : {
text : 'View on Plunkr',
key : 'syntaxPlunkr',
icon : 'icon-arrow-down'
},
'jsfiddle' : {
text : 'View on JSFiddle',
key : 'syntaxFiddle',
icon : 'icon-cloud'
}
};
for(var type in types) {
var data = types[type];
var link = attrs[data.key];
if(link) {
html += makeLink(type, data.text, link, data.icon);
}
};
var nav = document.createElement('nav');
nav.className = 'syntax-links';
nav.innerHTML = html;
var node = element[0];
var par = node.parentNode;
par.insertBefore(nav, node);
}
}
}
directive.tabbable = function() {
return {
restrict: 'C',
compile: function(element) {
var navTabs = angular.element('<ul class="nav nav-tabs"></ul>'),
tabContent = angular.element('<div class="tab-content"></div>');
tabContent.append(element.contents());
element.append(navTabs).append(tabContent);
},
controller: ['$scope', '$element', function($scope, $element) {
var navTabs = $element.contents().eq(0),
ngModel = $element.controller('ngModel') || {},
tabs = [],
selectedTab;
ngModel.$render = function() {
var $viewValue = this.$viewValue;
if (selectedTab ? (selectedTab.value != $viewValue) : $viewValue) {
if(selectedTab) {
selectedTab.paneElement.removeClass('active');
selectedTab.tabElement.removeClass('active');
selectedTab = null;
}
if($viewValue) {
for(var i = 0, ii = tabs.length; i < ii; i++) {
if ($viewValue == tabs[i].value) {
selectedTab = tabs[i];
break;
}
}
if (selectedTab) {
selectedTab.paneElement.addClass('active');
selectedTab.tabElement.addClass('active');
}
}
}
};
this.addPane = function(element, attr) {
var li = angular.element('<li><a href></a></li>'),
a = li.find('a'),
tab = {
paneElement: element,
paneAttrs: attr,
tabElement: li
};
tabs.push(tab);
attr.$observe('value', update)();
attr.$observe('title', function(){ update(); a.text(tab.title); })();
function update() {
tab.title = attr.title;
tab.value = attr.value || attr.title;
if (!ngModel.$setViewValue && (!ngModel.$viewValue || tab == selectedTab)) {
// we are not part of angular
ngModel.$viewValue = tab.value;
}
ngModel.$render();
}
navTabs.append(li);
li.on('click', function(event) {
event.preventDefault();
event.stopPropagation();
if (ngModel.$setViewValue) {
$scope.$apply(function() {
ngModel.$setViewValue(tab.value);
ngModel.$render();
});
} else {
// we are not part of angular
ngModel.$viewValue = tab.value;
ngModel.$render();
}
});
return function() {
tab.tabElement.remove();
for(var i = 0, ii = tabs.length; i < ii; i++ ) {
if (tab == tabs[i]) {
tabs.splice(i, 1);
}
}
};
}
}]
};
};
directive.table = function() {
return {
restrict: 'E',
link: function(scope, element, attrs) {
if (!attrs['class']) {
element.addClass('table table-bordered table-striped code-table');
}
}
};
};
var popoverElement = function() {
var object = {
init : function() {
this.element = angular.element(
'<div class="popover popover-incode top">' +
'<div class="arrow"></div>' +
'<div class="popover-inner">' +
'<div class="popover-title"><code></code></div>' +
'<div class="popover-content"></div>' +
'</div>' +
'</div>'
);
this.node = this.element[0];
this.element.css({
'display':'block',
'position':'absolute'
});
angular.element(document.body).append(this.element);
var inner = this.element.children()[1];
this.titleElement = angular.element(inner.childNodes[0].firstChild);
this.contentElement = angular.element(inner.childNodes[1]);
//stop the click on the tooltip
this.element.on('click', function(event) {
event.preventDefault();
event.stopPropagation();
});
var self = this;
angular.element(document.body).on('click',function(event) {
if(self.visible()) self.hide();
});
},
show : function(x,y) {
this.element.addClass('visible');
this.position(x || 0, y || 0);
},
hide : function() {
this.element.removeClass('visible');
this.position(-9999,-9999);
},
visible : function() {
return this.position().y >= 0;
},
isSituatedAt : function(element) {
return this.besideElement ? element[0] == this.besideElement[0] : false;
},
title : function(value) {
return this.titleElement.html(value);
},
content : function(value) {
if(value && value.length > 0) {
value = marked(value);
}
return this.contentElement.html(value);
},
positionArrow : function(position) {
this.node.className = 'popover ' + position;
},
positionAway : function() {
this.besideElement = null;
this.hide();
},
positionBeside : function(element) {
this.besideElement = element;
var elm = element[0];
var x = elm.offsetLeft;
var y = elm.offsetTop;
x -= 30;
y -= this.node.offsetHeight + 10;
this.show(x,y);
},
position : function(x,y) {
if(x != null && y != null) {
this.element.css('left',x + 'px');
this.element.css('top', y + 'px');
}
else {
return {
x : this.node.offsetLeft,
y : this.node.offsetTop
};
}
}
};
object.init();
object.hide();
return object;
};
directive.popover = ['popoverElement', function(popover) {
return {
restrict: 'A',
priority : 500,
link: function(scope, element, attrs) {
element.on('click',function(event) {
event.preventDefault();
event.stopPropagation();
if(popover.isSituatedAt(element) && popover.visible()) {
popover.title('');
popover.content('');
popover.positionAway();
}
else {
popover.title(attrs.title);
popover.content(attrs.content);
popover.positionBeside(element);
}
});
}
}
}];
directive.tabPane = function() {
return {
require: '^tabbable',
restrict: 'C',
link: function(scope, element, attrs, tabsCtrl) {
element.on('$remove', tabsCtrl.addPane(element, attrs));
}
};
};
directive.foldout = ['$http', '$animate','$window', function($http, $animate, $window) {
return {
restrict: 'A',
priority : 500,
link: function(scope, element, attrs) {
var container, loading, url = attrs.url;
if(/\/build\//.test($window.location.href)) {
url = '/build/docs' + url;
}
element.on('click',function() {
scope.$apply(function() {
if(!container) {
if(loading) return;
loading = true;
var par = element.parent();
container = angular.element('<div class="foldout">loading...</div>');
$animate.enter(container, null, par);
$http.get(url, { cache : true }).success(function(html) {
loading = false;
html = '<div class="foldout-inner">' +
'<div calss="foldout-arrow"></div>' +
html +
'</div>';
container.html(html);
//avoid showing the element if the user has already closed it
if(container.css('display') == 'block') {
container.css('display','none');
$animate.addClass(container, 'ng-hide');
}
});
}
else {
container.hasClass('ng-hide') ? $animate.removeClass(container, 'ng-hide') : $animate.addClass(container, 'ng-hide');
}
});
});
}
}
}];
angular.module('bootstrap', [])
.directive(directive)
.factory('popoverElement', popoverElement)
.run(function() {
marked.setOptions({
gfm: true,
tables: true
});
});
+1 -3
View File
@@ -54,9 +54,7 @@ angular.module('ui.bootstrap.dropdown', [])
}
};
var closeDropdown = function(evt) {
if (evt && evt.which === 3) return;
var closeDropdown = function() {
openScope.$apply(function() {
openScope.isOpen = false;
});
+1 -1
View File
@@ -3,7 +3,7 @@
/* global importScripts, onmessage: true, postMessage, lunr */
// Load up the lunr library
importScripts('../components/lunr.js-0.5.12/lunr.min.js');
importScripts('../components/lunr.js-0.4.2/lunr.min.js');
// Create the lunr index - the docs should be an array of object, each object containing
// the path and search terms for a page
+1
View File
@@ -13,6 +13,7 @@ angular.module('docsApp', [
'search',
'tutorials',
'versions',
'bootstrap',
'ui.bootstrap.dropdown'
])
+1 -12
View File
@@ -34,15 +34,4 @@ angular.module('directives', [])
return function(scope, element) {
$anchorScroll.yOffset = element;
};
}])
.directive('table', function() {
return {
restrict: 'E',
link: function(scope, element, attrs) {
if (!attrs['class']) {
element.addClass('table table-bordered table-striped code-table');
}
}
};
});
}]);
+4 -2
View File
@@ -1,11 +1,13 @@
angular.module('DocsController', [])
.controller('DocsController', [
'$scope', '$rootScope', '$location', '$window', '$cookies',
'$scope', '$rootScope', '$location', '$window', '$cookies', 'openPlunkr',
'NG_PAGES', 'NG_NAVIGATION', 'NG_VERSION',
function($scope, $rootScope, $location, $window, $cookies,
function($scope, $rootScope, $location, $window, $cookies, openPlunkr,
NG_PAGES, NG_NAVIGATION, NG_VERSION) {
$scope.openPlunkr = openPlunkr;
$scope.docsVersion = NG_VERSION.isSnapshot ? 'snapshot' : NG_VERSION.version;
$scope.navClass = function(navItem) {
+3 -10
View File
@@ -13,10 +13,10 @@ angular.module('errors', ['ngSanitize'])
};
return function (text, target) {
if (!text) return text;
var targetHtml = target ? ' target="' + target + '"' : '';
if (!text) return text;
return $sanitize(text.replace(LINKY_URL_REGEXP, function (url) {
if (STACK_TRACE_REGEXP.test(url)) {
return url;
@@ -34,10 +34,6 @@ angular.module('errors', ['ngSanitize'])
.directive('errorDisplay', ['$location', 'errorLinkFilter', function ($location, errorLinkFilter) {
var encodeAngleBrackets = function (text) {
return text.replace(/</g, '&lt;').replace(/>/g, '&gt;');
};
var interpolate = function (formatString) {
var formatArgs = arguments;
return formatString.replace(/\{\d+\}/g, function (match) {
@@ -55,15 +51,12 @@ angular.module('errors', ['ngSanitize'])
link: function (scope, element, attrs) {
var search = $location.search(),
formatArgs = [attrs.errorDisplay],
formattedText,
i;
for (i = 0; angular.isDefined(search['p'+i]); i++) {
formatArgs.push(search['p'+i]);
}
formattedText = encodeAngleBrackets(interpolate.apply(null, formatArgs));
element.html(errorLinkFilter(formattedText, '_blank'));
element.html(errorLinkFilter(interpolate.apply(null, formatArgs), '_blank'));
}
};
}]);
+28 -149
View File
@@ -1,55 +1,5 @@
angular.module('examples', [])
.directive('runnableExample', ['$templateCache', '$document', function($templateCache, $document) {
var exampleClassNameSelector = '.runnable-example-file';
var doc = $document[0];
var tpl =
'<nav class="runnable-example-tabs" ng-if="tabs">' +
' <a ng-class="{active:$index==activeTabIndex}"' +
'ng-repeat="tab in tabs track by $index" ' +
'href="" ' +
'class="btn"' +
'ng-click="setTab($index)">' +
' {{ tab }}' +
' </a>' +
'</nav>';
return {
restrict: 'C',
scope : true,
controller : ['$scope', function($scope) {
$scope.setTab = function(index) {
var tab = $scope.tabs[index];
$scope.activeTabIndex = index;
$scope.$broadcast('tabChange', index, tab);
};
}],
compile : function(element) {
element.html(tpl + element.html());
return function(scope, element) {
var node = element[0];
var examples = node.querySelectorAll(exampleClassNameSelector);
var tabs = [], now = Date.now();
angular.forEach(examples, function(child, index) {
tabs.push(child.getAttribute('name'));
});
if(tabs.length > 0) {
scope.tabs = tabs;
scope.$on('tabChange', function(e, index, title) {
angular.forEach(examples, function(child) {
child.style.display = 'none';
});
var selected = examples[index];
selected.style.display = 'block';
});
scope.setTab(0);
}
};
}
};
}])
.factory('formPostData', ['$document', function($document) {
return function(url, newWindow, fields) {
/**
@@ -72,110 +22,29 @@ angular.module('examples', [])
};
}])
.factory('createCopyrightNotice', function() {
var COPYRIGHT = 'Copyright ' + (new Date()).getFullYear() + ' Google Inc. All Rights Reserved.\n'
+ 'Use of this source code is governed by an MIT-style license that\n'
+ 'can be found in the LICENSE file at http://angular.io/license';
var COPYRIGHT_JS_CSS = '\n\n/*\n' + COPYRIGHT + '\n*/';
var COPYRIGHT_HTML = '\n\n<!-- \n' + COPYRIGHT + '\n-->';
return function getCopyright(filename) {
switch (filename.substr(filename.lastIndexOf('.'))) {
case '.html':
return COPYRIGHT_HTML;
case '.js':
case '.css':
return COPYRIGHT_JS_CSS;
case '.md':
return COPYRIGHT;
}
return '';
};
})
.factory('openPlunkr', ['formPostData', '$http', '$q', function(formPostData, $http, $q) {
return function(exampleFolder, clickEvent) {
.directive('plnkrOpener', ['$q', 'getExampleData', 'formPostData', 'createCopyrightNotice', function($q, getExampleData, formPostData, createCopyrightNotice) {
return {
scope: {},
bindToController: {
'examplePath': '@'
},
controllerAs: 'plnkr',
template: '<button ng-click="plnkr.open($event)" class="btn pull-right"> <i class="glyphicon glyphicon-edit">&nbsp;</i> Edit in Plunker</button> ',
controller: [function() {
var ctrl = this;
var exampleName = 'AngularJS Example';
var newWindow = clickEvent.ctrlKey || clickEvent.metaKey;
ctrl.example = {
path: ctrl.examplePath,
manifest: undefined,
files: undefined,
name: 'AngularJS Example'
};
ctrl.prepareExampleData = function() {
if (ctrl.example.manifest) {
return $q.when(ctrl.example);
}
return getExampleData(ctrl.examplePath).then(function(data) {
ctrl.example.files = data.files;
ctrl.example.manifest = data.manifest;
// Build a pretty title for the Plunkr
var exampleNameParts = data.manifest.name.split('-');
exampleNameParts.unshift('AngularJS');
angular.forEach(exampleNameParts, function(part, index) {
exampleNameParts[index] = part.charAt(0).toUpperCase() + part.substr(1);
});
ctrl.example.name = exampleNameParts.join(' - ');
return ctrl.example;
});
};
ctrl.open = function(clickEvent) {
var newWindow = clickEvent.ctrlKey || clickEvent.metaKey;
var postData = {
'tags[0]': "angularjs",
'tags[1]': "example",
'private': true
};
// Make sure the example data is available.
// If an XHR must be made, this might break some pop-up blockers when
// new window is requested
ctrl.prepareExampleData()
.then(function() {
angular.forEach(ctrl.example.files, function(file) {
postData['files[' + file.name + ']'] = file.content + createCopyrightNotice(file.name);
});
postData.description = ctrl.example.name;
formPostData('http://plnkr.co/edit/?p=preview', newWindow, postData);
});
};
// Initialize the example data, so it's ready when clicking the open button.
// Otherwise pop-up blockers will prevent a new window from opening
ctrl.prepareExampleData(ctrl.example.path);
}]
};
}])
.factory('getExampleData', ['$http', '$q', function($http, $q) {
return function(exampleFolder){
// Load the manifest for the example
return $http.get(exampleFolder + '/manifest.json')
$http.get(exampleFolder + '/manifest.json')
.then(function(response) {
return response.data;
})
.then(function(manifest) {
var filePromises = [];
// Build a pretty title for the Plunkr
var exampleNameParts = manifest.name.split('-');
exampleNameParts.unshift('AngularJS');
angular.forEach(exampleNameParts, function(part, index) {
exampleNameParts[index] = part.charAt(0).toUpperCase() + part.substr(1);
});
exampleName = exampleNameParts.join(' - ');
angular.forEach(manifest.files, function(filename) {
filePromises.push($http.get(exampleFolder + '/' + filename, { transformResponse: [] })
.then(function(response) {
@@ -183,7 +52,7 @@ angular.module('examples', [])
// The manifests provide the production index file but Plunkr wants
// a straight index.html
if (filename === "index-production.html") {
filename = "index.html";
filename = "index.html"
}
return {
@@ -192,11 +61,21 @@ angular.module('examples', [])
};
}));
});
return $q.all(filePromises);
})
.then(function(files) {
var postData = {};
return $q.all({
manifest: manifest,
files: $q.all(filePromises)
angular.forEach(files, function(file) {
postData['files[' + file.name + ']'] = file.content;
});
postData['tags[0]'] = "angularjs";
postData['tags[1]'] = "example";
postData.private = true;
postData.description = exampleName;
formPostData('http://plnkr.co/edit/?p=preview', newWindow, postData);
});
};
}]);
}]);
+1 -9
View File
@@ -11,15 +11,7 @@ angular.module('search', [])
var MIN_SEARCH_LENGTH = 2;
if(q.length >= MIN_SEARCH_LENGTH) {
docsSearch(q).then(function(hits) {
// Make sure the areas are always in the same order
var results = {
api: [],
guide: [],
tutorial: [],
error: [],
misc: []
};
var results = {};
angular.forEach(hits, function(hit) {
var area = hit.area;
-25
View File
@@ -1,25 +0,0 @@
{
"extends": "../../../.jshintrc-base",
"browser": true,
"globals": {
// AngularJS
"angular": false,
// ngMocks
"module": false,
"inject": true,
// Jasmine
"jasmine": false,
"describe": false,
"ddescribe": false,
"xdescribe": false,
"it": false,
"iit": false,
"xit": false,
"beforeEach": false,
"afterEach": false,
"spyOn": false,
"expect": false
}
}
+2 -1
View File
@@ -3,6 +3,7 @@ describe("DocsController", function() {
angular.module('fake', [])
.value('$cookies', {})
.value('openPlunkr', function() {})
.value('NG_PAGES', {})
.value('NG_NAVIGATION', {})
.value('NG_VERSION', {});
@@ -25,7 +26,7 @@ describe("DocsController", function() {
it("should update the Google Analytics with $location.path if currentPage is missing", inject(function($window, $location) {
$window._gaq = [];
spyOn($location, 'path').and.returnValue('x/y/z');
spyOn($location, 'path').andReturn('x/y/z');
$scope.$broadcast('$includeContentLoaded');
expect($window._gaq.pop()).toEqual(['_trackPageview', 'x/y/z']);
}));
-166
View File
@@ -1,166 +0,0 @@
'use strict';
describe('errors', function() {
// Mock `ngSanitize` module
angular.
module('ngSanitize', []).
value('$sanitize', jasmine.createSpy('$sanitize').and.callFake(angular.identity));
beforeEach(module('errors'));
describe('errorDisplay', function() {
var $sanitize;
var errorLinkFilter;
beforeEach(inject(function(_$sanitize_, _errorLinkFilter_) {
$sanitize = _$sanitize_;
errorLinkFilter = _errorLinkFilter_;
}));
it('should return empty input unchanged', function() {
var inputs = [undefined, null, false, 0, ''];
var remaining = inputs.length;
inputs.forEach(function(falsyValue) {
expect(errorLinkFilter(falsyValue)).toBe(falsyValue);
remaining--;
});
expect(remaining).toBe(0);
});
it('should recognize URLs and convert them to `<a>`', function() {
var urls = [
['ftp://foo/bar?baz#qux'],
['http://foo/bar?baz#qux'],
['https://foo/bar?baz#qux'],
['mailto:foo_bar@baz.qux', null, 'foo_bar@baz.qux'],
['foo_bar@baz.qux', 'mailto:foo_bar@baz.qux', 'foo_bar@baz.qux']
];
var remaining = urls.length;
urls.forEach(function(values) {
var actualUrl = values[0];
var expectedUrl = values[1] || actualUrl;
var expectedText = values[2] || expectedUrl;
var anchor = '<a href="' + expectedUrl + '">' + expectedText + '</a>';
var input = 'start ' + actualUrl + ' end';
var output = 'start ' + anchor + ' end';
expect(errorLinkFilter(input)).toBe(output);
remaining--;
});
expect(remaining).toBe(0);
});
it('should not recognize stack-traces as URLs', function() {
var urls = [
'ftp://foo/bar?baz#qux:4:2',
'http://foo/bar?baz#qux:4:2',
'https://foo/bar?baz#qux:4:2',
'mailto:foo_bar@baz.qux:4:2',
'foo_bar@baz.qux:4:2'
];
var remaining = urls.length;
urls.forEach(function(url) {
var input = 'start ' + url + ' end';
expect(errorLinkFilter(input)).toBe(input);
remaining--;
});
expect(remaining).toBe(0);
});
it('should should set `[target]` if specified', function() {
var url = 'https://foo/bar?baz#qux';
var target = '_blank';
var outputWithoutTarget = '<a href="' + url + '">' + url + '</a>';
var outputWithTarget = '<a target="' + target + '" href="' + url + '">' + url + '</a>';
expect(errorLinkFilter(url)).toBe(outputWithoutTarget);
expect(errorLinkFilter(url, target)).toBe(outputWithTarget);
});
it('should truncate the contents of the generated `<a>` to 60 characters', function() {
var looongUrl = 'https://foooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo';
var truncatedUrl = 'https://foooooooooooooooooooooooooooooooooooooooooooooooo...';
var output = '<a href="' + looongUrl + '">' + truncatedUrl + '</a>';
expect(looongUrl.length).toBeGreaterThan(60);
expect(truncatedUrl.length).toBe(60);
expect(errorLinkFilter(looongUrl)).toBe(output);
});
it('should pass the final string through `$sanitize`', function() {
$sanitize.calls.reset();
var input = 'start https://foo/bar?baz#qux end';
var output = errorLinkFilter(input);
expect($sanitize).toHaveBeenCalledTimes(1);
expect($sanitize).toHaveBeenCalledWith(output);
});
});
describe('errorDisplay', function() {
var $compile;
var $location;
var $rootScope;
var errorLinkFilter;
beforeEach(module(function($provide) {
$provide.decorator('errorLinkFilter', function() {
errorLinkFilter = jasmine.createSpy('errorLinkFilter');
errorLinkFilter.and.callFake(angular.identity);
return errorLinkFilter;
});
}));
beforeEach(inject(function(_$compile_, _$location_, _$rootScope_) {
$compile = _$compile_;
$location = _$location_;
$rootScope = _$rootScope_;
}));
it('should set the element\s HTML', function() {
var elem = $compile('<span error-display="bar">foo</span>')($rootScope);
expect(elem.html()).toBe('bar');
});
it('should interpolate the contents against `$location.search()`', function() {
spyOn($location, 'search').and.returnValue({p0: 'foo', p1: 'bar'});
var elem = $compile('<span error-display="foo = {0}, bar = {1}"></span>')($rootScope);
expect(elem.html()).toBe('foo = foo, bar = bar');
});
it('should pass the interpolated text through `errorLinkFilter`', function() {
$location.search = jasmine.createSpy('search').and.returnValue({p0: 'foo'});
var elem = $compile('<span error-display="foo = {0}"></span>')($rootScope);
expect(errorLinkFilter).toHaveBeenCalledTimes(1);
expect(errorLinkFilter).toHaveBeenCalledWith('foo = foo', '_blank');
});
it('should encode `<` and `>`', function() {
var elem = $compile('<span error-display="&lt;xyz&gt;"></span>')($rootScope);
expect(elem.text()).toBe('<xyz>');
});
});
});
+1 -1
View File
@@ -2,7 +2,7 @@
"name": "AngularJS-docs-app",
"dependencies": {
"jquery": "2.1.1",
"lunr.js": "0.5.12",
"lunr.js": "0.4.3",
"open-sans-fontface": "1.0.4",
"google-code-prettify": "1.0.1",
"bootstrap": "3.1.1"
@@ -18,6 +18,7 @@ module.exports = function debugDeployment(getVersion) {
'../angular-touch.js',
'../angular-animate.js',
'components/marked-' + getVersion('marked', 'node_modules', 'package.json') + '/lib/marked.js',
'js/angular-bootstrap/bootstrap.js',
'js/angular-bootstrap/dropdown-toggle.js',
'components/lunr.js-' + getVersion('lunr.js') + '/lunr.js',
'components/google-code-prettify-' + getVersion('google-code-prettify') + '/src/prettify.js',
@@ -18,6 +18,7 @@ module.exports = function defaultDeployment(getVersion) {
'../angular-touch.min.js',
'../angular-animate.min.js',
'components/marked-' + getVersion('marked', 'node_modules', 'package.json') + '/lib/marked.js',
'js/angular-bootstrap/bootstrap.min.js',
'js/angular-bootstrap/dropdown-toggle.min.js',
'components/lunr.js-' + getVersion('lunr.js') + '/lunr.min.js',
'components/google-code-prettify-' + getVersion('google-code-prettify') + '/src/prettify.js',
+1
View File
@@ -22,6 +22,7 @@ module.exports = function jqueryDeployment(getVersion) {
'../angular-touch.min.js',
'../angular-animate.min.js',
'components/marked-' + getVersion('marked', 'node_modules', 'package.json') + '/lib/marked.js',
'js/angular-bootstrap/bootstrap.min.js',
'js/angular-bootstrap/dropdown-toggle.min.js',
'components/lunr.js-' + getVersion('lunr.js') + '/lunr.min.js',
'components/google-code-prettify-' + getVersion('google-code-prettify') + '/src/prettify.js',
@@ -21,6 +21,7 @@ module.exports = function productionDeployment(getVersion) {
cdnUrl + '/angular-touch.min.js',
cdnUrl + '/angular-animate.min.js',
'components/marked-' + getVersion('marked', 'node_modules', 'package.json') + '/lib/marked.js',
'js/angular-bootstrap/bootstrap.min.js',
'js/angular-bootstrap/dropdown-toggle.min.js',
'components/lunr.js-' + getVersion('lunr.js') + '/lunr.min.js',
'components/google-code-prettify-' + getVersion('google-code-prettify') + '/src/prettify.js',
@@ -147,13 +147,13 @@
<div class="search-results-container" ng-show="hasResults">
<div class="container">
<div class="search-results-frame">
<div ng-repeat="(key, value) in results track by key" class="search-results-group" ng-class="colClassName + ' col-group-' + key" ng-show="value.length > 0">
<div ng-repeat="(key, value) in results" class="search-results-group" ng-class="colClassName + ' col-group-' + key">
<h4 class="search-results-group-heading">{{ key }}</h4>
<ul class="search-results">
<!-- Do not insert a line break between li and a. Chrome will insert an actual line-break, which breaks the list item view.
TODO: use a html minifier instead -->
<li ng-repeat="item in value" class="search-result"><a ng-click="hideResults()" ng-href="{{ item.path }}">{{ item.name }}</a></li>
</ul>
<div class="search-results">
<div ng-repeat="item in value" class="search-result">
- <a ng-click="hideResults()" ng-href="{{ item.path }}">{{ item.name }}</a>
</div>
</div>
</div>
</div>
<a href="" ng-click="hideResults()" class="search-close">
@@ -220,7 +220,7 @@
<p class="pull-right"><a back-to-top>Back to top</a></p>
<p>
Super-powered by Google ©2010-2016
Super-powered by Google ©2010-2015
( <a id="version"
ng-href="https://github.com/angular/angular.js/blob/master/CHANGELOG.md#{{versionNumber}}"
ng-bind-template="v{{version}}" title="Changelog of this version of Angular JS">
@@ -2,7 +2,9 @@
is HTML and wrap each line in a <p> - thus breaking the HTML #}
<div>
<plnkr-opener example-path="{$ doc.path $}"></plnkr-opener>
<a ng-click="openPlunkr('{$ doc.path $}', $event)" class="btn pull-right">
<i class="glyphicon glyphicon-edit">&nbsp;</i>
Edit in Plunker</a>
<div class="runnable-example"
path="{$ doc.example.deployments.default.path $}"
+3 -3
View File
@@ -1,8 +1,8 @@
@ngdoc error
@name $compile:baddir
@fullName Invalid Directive/Component Name
@fullName Invalid Directive Name
@description
This error occurs when the name of a directive or component is not valid.
This error occurs when the name of a directive is not valid.
Directives and Components must start with a lowercase character and must not contain leading or trailing whitespaces.
Directives must start with a lowercase character and must not contain leading or trailing whitespaces.
-30
View File
@@ -1,30 +0,0 @@
@ngdoc error
@name $compile:infchng
@fullName Unstable `$onChanges` hooks
@description
This error occurs when the application's model becomes unstable because some `$onChanges` hooks are causing updates which then trigger
further calls to `$onChanges` that can never complete.
Angular detects this situation and prevents an infinite loop from causing the browser to become unresponsive.
For example, the situation can occur by setting up a `$onChanges()` hook which triggers an event on the component, which subsequently
triggers the component's bound inputs to be updated:
```html
<c1 prop="a" on-change="a = -a"></c1>
```
```js
function Controller1() {}
Controller1.$onChanges = function() {
this.onChange();
};
mod.component('c1', {
controller: Controller1,
bindings: {'prop': '<', onChange: '&'}
}
```
The maximum number of allowed iterations of the `$onChanges` hooks is controlled via TTL setting which can be configured via
{@link ng.$compileProvider#onChangesTtl `$compileProvider.onChangesTtl`}.
+4 -6
View File
@@ -3,7 +3,7 @@
@fullName Invalid Isolate Scope Definition
@description
When declaring isolate scope the scope definition object must be in specific format which starts with mode character (`@&=<`), after which comes an optional `?`, and it ends with an optional local name.
When declaring isolate scope the scope definition object must be in specific format which starts with mode character (`@&=`) with an optional local name.
```
myModule.directive('directiveName', function factory() {
@@ -12,11 +12,9 @@ myModule.directive('directiveName', function factory() {
scope: {
'attrName': '@', // OK
'attrName2': '=localName', // OK
'attrName3': '<?localName', // OK
'attrName4': ' = name', // OK
'attrName5': 'name', // ERROR: missing mode @&=
'attrName6': 'name=', // ERROR: must be prefixed with @&=
'attrName7': '=name?', // ERROR: ? must come directly after the mode
'attrName3': 'name', // ERROR: missing mode @&=
'attrName4': ' = name', // ERROR: extra spaces
'attrName5': 'name=', // ERROR: must be prefixed with @&=
}
...
}
+2 -2
View File
@@ -31,7 +31,7 @@ single root element, like the `div` element in this template:
<div><b>Hello</b> World!</div>
```
An invalid template to be used with this directive is one that defines multiple root nodes or
An an invalid template to be used with this directive is one that defines multiple root nodes or
elements. For example:
```
@@ -43,7 +43,7 @@ well. Consider the following template:
```
<div class='container'>
<div class='wrapper'>
<div class='wrapper>
...
</div> <!-- wrapper -->
</div> <!-- container -->
+1 -4
View File
@@ -6,9 +6,6 @@
This error occurs when a module fails to load due to some exception. The error
message above should provide additional context.
A common reason why the module fails to load is that you've forgotten to
include the file with the defined module or that the file couldn't be loaded.
### Using `ngRoute`
In AngularJS `1.2.0` and later, `ngRoute` has been moved to its own module.
@@ -27,4 +24,4 @@ angular.module('ng').filter('tel', function (){});
Instead create your own module and add it as a dependency to your application's top-level module.
See [#9692](https://github.com/angular/angular.js/issues/9692) and
[#7709](https://github.com/angular/angular.js/issues/7709) for more information
[#7709](https://github.com/angular/angular.js/issues/7709) for more information
-3
View File
@@ -81,6 +81,3 @@ angular.module('myModule', [])
// a scope object cannot be injected into a service.
}]);
```
If you encounter this error only with minified code, consider using `ngStrictDi` (see
{@link ng.directive:ngApp ngApp}) to provoke the error with the non-minified source.
+1 -1
View File
@@ -1,6 +1,6 @@
@ngdoc error
@name $location:nobase
@fullName $location in HTML5 mode requires a &lt;base&gt; tag to be present!
@fullName $location in HTML5 mode requires a `<base>` tag to be present!
@description
If you configure {@link ng.$location `$location`} to use
@@ -14,32 +14,3 @@ perform this check - it's up to the developer to not expose such sensitive and p
directly on the scope chain.
To resolve this error, avoid Window access.
### Common CoffeeScript Issue
Be aware that if you are using CoffeeScript, it automatically returns the value of the last statement in a
function. So for instance
```coffeescript
scope.foo = ->
window.open 'https://example.com'
```
compiles to something like
```js
scope.foo = function() {
return window.open('https://example.com');
};
```
You can see that this function will return the result of calling `window.open`, which is a `Window`
object.
You can avoid this by explicitly returning something else from the function:
```coffeescript
scope.foo = ->
window.open 'https://example.com'
return true;
```
+2 -2
View File
@@ -161,7 +161,7 @@ In this second scenario, we are already inside a `$digest` when the ngFocus dire
call to `$apply()`, causing this error to be thrown.
It is possible to workaround this problem by moving the call to set the focus outside of the digest,
by using `$timeout(fn, 0, false)`, where the `false` value tells Angular not to wrap this `fn` in an
by using `$timeout(fn, 0, false)`, where the `false` value tells Angular not to wrap this `fn` in a
`$apply` block:
```
@@ -200,7 +200,7 @@ the top of the call stack.
Once you have identified this call you work your way up the stack to see what the problem is.
* If the second call was made in your application code then you should look at why this code has been
called from within an `$apply`/`$digest`. It may be a simple oversight or maybe it fits with the
called from within a `$apply`/`$digest`. It may be a simple oversight or maybe it fits with the
sync/async scenario described earlier.
* If the second call was made inside an Angular directive then it is likely that it matches the second
@@ -0,0 +1,11 @@
@ngdoc error
@name $sanitize:badparse
@fullName Parsing Error while Sanitizing
@description
This error occurs when the HTML string passed to '$sanitize' can't be parsed by the sanitizer.
The error contains part of the html string that can't be parsed.
The parser is more strict than a typical browser parser, so it's possible that some obscure input would produce this error despite the string being recognized as valid HTML by a browser.
If a valid html code results in this error, please file a bug.
@@ -1,10 +0,0 @@
@ngdoc error
@name $sanitize:noinert
@fullName Can't create an inert html document
@description
This error occurs when `$sanitize` sanitizer determines that `document.implementation.createHTMLDocument ` api is not supported by the current browser.
This api is necessary for safe parsing of HTML strings into DOM trees and without it the sanitizer can't sanitize the input.
The api is present in all supported browsers including IE 9.0, so the presence of this error usually indicates that Angular's `$sanitize` is being used on an unsupported platform.
-13
View File
@@ -1,13 +0,0 @@
@ngdoc error
@name $sanitize:uinput
@fullName Failed to sanitize html because the input is unstable
@description
This error occurs when `$sanitize` sanitizer tries to check the input for possible mXSS payload and the verification
errors due to the input mutating indefinitely. This could be a sign that the payload contains code exploiting an mXSS
vulnerability in the browser.
mXSS attack exploit browser bugs that cause some browsers parse a certain html strings into DOM, which once serialized
doesn't match the original input. These browser bugs can be exploited by attackers to create payload which looks
harmless to sanitizers, but due to mutations caused by the browser are turned into dangerous code once processed after
sanitization.
-16
View File
@@ -1,16 +0,0 @@
@ngdoc error
@name linky:notstring
@fullName Not a string
@description
This error occurs when {@link ngSanitize.linky linky} is used with a non-empty, non-string value:
```html
<div ng-bind-html="42 | linky"></div>
```
`linky` is supposed to be used with string values only, and therefore assumes that several methods
(such as `.match()`) are available on the passed in value.
The value can be initialized asynchronously and therefore null or undefined won't throw this error.
If you want to pass non-string values to `linky` (e.g. Objects whose `.toString()` should be
utilized), you need to manually convert them to strings.
-52
View File
@@ -1,52 +0,0 @@
@ngdoc error
@name orderBy:notarray
@fullName Value is not array-like
@description
This error occurs when {@link ng.orderBy orderBy} is not passed an array-like value:
```html
<div ng-repeat="(key, value) in myObj | orderBy:someProp">
{{ key }} : {{ value }}
</div>
```
`orderBy` must be used with an array-like value so a subset of items can be returned.
The array can be initialized asynchronously and therefore `null` or `undefined` won't throw this error.
To use `orderBy` to order the properties of an object, you can create your own array based on that object:
```js
angular.module('aModule', [])
.controller('aController', function($scope) {
var myObj = {
one: {id: 1, name: 'Some thing'},
two: {id: 2, name: 'Another thing'},
three: {id: 3, name: 'A third thing'}
};
$scope.arrFromMyObj = Object.keys(myObj).map(function(key) {
return myObj[key];
});
});
```
That can be used as:
```html
<label>
Order by:
<select ng-model="orderProp" ng-options="prop for prop in ['id', 'name']"></select>
</label>
<div ng-repeat="item in arrFromMyObj | orderBy:orderProp">
[{{ item.id }}] {{ item.name }}
</div>
```
You could as well convert the object to an array using a filter such as
[toArrayFilter](https://github.com/petebacondarwin/angular-toArrayFilter):
```html
<label>
Order by:
<select ng-model="orderProp" ng-options="prop for prop in ['id', 'name']"></select>
</label>
<div ng-repeat="item in myObj | toArray:false | orderBy:orderProp">
[{{ item.id }}] {{ item.name }}
</div>
```
+2 -17
View File
@@ -330,8 +330,8 @@ reload to the original link.
### Relative links
Be sure to check all relative links, images, scripts etc. Angular requires you to specify the url
base in the head of your main html file (`<base href="/my-base/index.html">`) unless `html5Mode.requireBase`
is set to `false` in the html5Mode definition object passed to `$locationProvider.html5Mode()`. With
base in the head of your main html file (`<base href="/my-base">`) unless `html5Mode.requireBase` is
set to `false` in the html5Mode definition object passed to `$locationProvider.html5Mode()`. With
that, relative urls will always be resolved to this base url, even if the initial url of the
document was different.
@@ -339,7 +339,6 @@ There is one exception: Links that only contain a hash fragment (e.g. `<a href="
will only change `$location.hash()` and not modify the url otherwise. This is useful for scrolling
to anchors on the same page without needing to know on which page the user currently is.
### Server side
Using this mode requires URL rewriting on server side, basically you have to rewrite all your links
@@ -347,20 +346,6 @@ to entry point of your application (e.g. index.html). Requiring a `<base>` tag i
this case, as it allows Angular to differentiate between the part of the url that is the application
base and the path that should be handled by the application.
### Base href constraints
The `$location` service is not able to function properly if the current URL is outside the URL given
as the base href. This can have subtle confusing consequencies...
Consider a base href set as follows: `<base href="/base/">` (i.e. the application exists in the "folder"
called `/base`). The URL `/base` is actually outside the application (it refers to the `base` file found
in the root `/` folder).
If you wish to be able to navigate to the application via a URL such as `/base` then you should ensure that
you server is setup to redirect such requests to `/base/`.
See https://github.com/angular/angular.js/issues/14018 for more information.
### Sending links among different browsers
Because of rewriting capability in HTML5 mode, your users will be able to open regular url links in
+11 -54
View File
@@ -33,9 +33,6 @@ Currently, ngAria interfaces with the following directives:
* {@link guide/accessibility#ngmodel ngModel}
* {@link guide/accessibility#ngdisabled ngDisabled}
* {@link guide/accessibility#ngrequired ngRequired}
* {@link guide/accessibility#ngvaluechecked ngChecked}
* {@link guide/accessibility#ngvaluechecked ngValue}
* {@link guide/accessibility#ngshow ngShow}
* {@link guide/accessibility#nghide ngHide}
* {@link guide/accessibility#ngclick ngClick}
@@ -44,7 +41,7 @@ Currently, ngAria interfaces with the following directives:
<h2 id="ngmodel">ngModel</h2>
Much of ngAria's heavy lifting happens in the {@link ng.ngModel ngModel}
Much of ngAria's heavy lifting happens in the {@link ngModel ngModel}
directive. For elements using ngModel, special attention is paid by ngAria if that element also
has a role or type of `checkbox`, `radio`, `range` or `textbox`.
@@ -137,75 +134,35 @@ attributes (if they have not been explicitly specified by the developer):
ngAria will also add `tabIndex`, ensuring custom elements with these roles will be reachable from
the keyboard. It is still up to **you** as a developer to **ensure custom controls will be
accessible**. As a rule, any time you create a widget involving user interaction, be sure to test
accessible**. As a rule, any time you create a widget involving user interaction, be sure to test
it with your keyboard and at least one mobile and desktop screen reader.
<h2 id="ngvaluechecked">ngValue and ngChecked</h2>
To ease the transition between native inputs and custom controls, ngAria now supports
{@link ng.ngValue ngValue} and {@link ng.ngChecked ngChecked}.
The original directives were created for native inputs only, so ngAria extends
support to custom elements by managing `aria-checked` for accessibility.
###Example
```html
<custom-checkbox ng-checked="val"></custom-checkbox>
<custom-radio-button ng-value="val"></custom-radio-button>
```
Becomes:
```html
<custom-checkbox ng-checked="val" aria-checked="true"></custom-checkbox>
<custom-radio-button ng-value="val" aria-checked="true"></custom-radio-button>
```
<h2 id="ngdisabled">ngDisabled</h2>
The `disabled` attribute is only valid for certain elements such as `button`, `input` and
`textarea`. To properly disable custom element directives such as `<md-checkbox>` or `<taco-tab>`,
using ngAria with {@link ng.ngDisabled ngDisabled} will also
using ngAria with [ngDisabled](https://docs.angularjs.org/api/ng/directive/ngDisabled) will also
add `aria-disabled`. This tells assistive technologies when a non-native input is disabled, helping
custom controls to be more accessible.
###Example
```html
<md-checkbox ng-disabled="disabled"></md-checkbox>
<md-checkbox ng-disabled="disabled">
```
Becomes:
```html
<md-checkbox disabled aria-disabled="true"></md-checkbox>
<md-checkbox disabled aria-disabled="true">
```
>You can check whether a control is legitimately disabled for a screen reader by visiting
[chrome://accessibility](chrome://accessibility) and inspecting [the accessibility tree](http://www.paciellogroup.com/blog/2015/01/the-browser-accessibility-tree/).
<h2 id="ngrequired">ngRequired</h2>
The boolean `required` attribute is only valid for native form controls such as `input` and
`textarea`. To properly indicate custom element directives such as `<md-checkbox>` or `<custom-input>`
as required, using ngAria with {@link ng.ngRequired ngRequired} will also add
`aria-required`. This tells accessibility APIs when a custom control is required.
###Example
```html
<md-checkbox ng-required="val"></md-checkbox>
```
Becomes:
```html
<md-checkbox ng-required="val" aria-required="true"></md-checkbox>
```
<h2 id="ngshow">ngShow</h2>
>The {@link ng.ngShow ngShow} directive shows or hides the
>The [ngShow](https://docs.angularjs.org/api/ng/directive/ngShow) directive shows or hides the
given HTML element based on the expression provided to the `ngShow` attribute. The element is
shown or hidden by removing or adding the `.ng-hide` CSS class onto the element.
@@ -242,7 +199,7 @@ Becomes:
<h2 id="nghide">ngHide</h2>
>The {@link ng.ngHide ngHide} directive shows or hides the
>The [ngHide](https://docs.angularjs.org/api/ng/directive/ngHide) directive shows or hides the
given HTML element based on the expression provided to the `ngHide` attribute. The element is
shown or hidden by removing or adding the `.ng-hide` CSS class onto the element.
@@ -251,7 +208,7 @@ The default CSS for `ngHide`, the inverse method to `ngShow`, makes ngAria redun
`display: none`. See explanation for {@link guide/accessibility#ngshow ngShow} when overriding the default CSS.
<h2><span id="ngclick">ngClick</span> and <span id="ngdblclick">ngDblclick</span></h2>
If `ng-click` or `ng-dblclick` is encountered, ngAria will add `tabindex="0"` to any element not in
If `ng-click` or `ng-dblclick` is encountered, ngAria will add `tabindex="0"` to any element not in
a node blacklist:
* Button
@@ -261,14 +218,14 @@ a node blacklist:
* Select
* Details/Summary
To fix widespread accessibility problems with `ng-click` on `div` elements, ngAria will
To fix widespread accessibility problems with `ng-click` on `div` elements, ngAria will
dynamically bind a keypress event by default as long as the element isn't in the node blacklist.
You can turn this functionality on or off with the `bindKeypress` configuration option.
You can turn this functionality on or off with the `bindKeypress` configuration option.
ngAria will also add the `button` role to communicate to users of assistive technologies. This can
be disabled with the `bindRoleForClick` configuration option.
For `ng-dblclick`, you must still manually add `ng-keypress` and a role to non-interactive elements
For `ng-dblclick`, you must still manually add `ng-keypress` and a role to non-interactive elements
such as `div` or `taco-button` to enable keyboard access.
<h3>Example</h3>
+1 -169
View File
@@ -6,7 +6,7 @@
# Animations
AngularJS provides animation hooks for common directives such as `ngRepeat`, `ngSwitch`, and `ngView`, as well as custom directives
AngularJS 1.3 provides animation hooks for common directives such as `ngRepeat`, `ngSwitch`, and `ngView`, as well as custom directives
via the `$animate` service. These animation hooks are set in place to trigger animations during the life cycle of various directives and when
triggered, will attempt to perform a CSS Transition, CSS Keyframe Animation or a JavaScript callback Animation (depending on if an animation is
placed on the given directive). Animations can be placed using vanilla CSS by following the naming conventions set in place by AngularJS
@@ -274,174 +274,6 @@ myModule.directive('my-directive', ['$animate', function($animate) {
}]);
```
## Animations on app bootstrap / page load
By default, animations are disabled when the Angular app {@link guide/bootstrap bootstraps}. If you are using the {@link ngApp} directive,
this happens in the `DOMContentLoaded` event, so immediately after the page has been loaded.
Animations are disabled, so that UI and content are instantly visible. Otherwise, with many animations on
the page, the loading process may become too visually overwhelming, and the performance may suffer.
Internally, `ngAnimate` waits until all template downloads that are started right after bootstrap have finished.
Then, it waits for the currently running {@link ng.$rootScope.Scope#$digest} and the one after that to finish.
This ensures that the whole app has been compiled fully before animations are attempted.
If you do want your animations to play when the app bootstraps, you can enable animations globally in
your main module's {@link angular.Module#run run} function:
```js
myModule.run(function($animate) {
$animate.enabled(true);
});
```
## How to (selectively) enable, disable and skip animations
There are three different ways to disable animations, both globally and for specific animations.
Disabling specific animations can help to speed up the render performance, for example for large `ngRepeat`
lists that don't actually have animations. Because ngAnimate checks at runtime if animations are present,
performance will take a hit even if an element has no animation.
### In the config: {@link $animateProvider#classNameFilter $animateProvider.classNameFilter()}
This function can be called in the {@link angular.Module#config config} phase of an app. It takes a regex as the only argument,
which will then be matched against the classes of any element that is about to be animated. The regex
allows a lot of flexibility - you can either allow animations only for specific classes (useful when
you are working with 3rd party animations), or exclude specific classes from getting animated.
```js
app.config(function($animateProvider) {
$animateProvider.classNameFilter(/animate-/);
});
```
```css
/&#42; prefixed with animate- &#42;/
.animate-fade-add.animate-fade-add-active {
transition:1s linear all;
opacity:0;
}
```
The classNameFilter approach generally applies the biggest speed boost, because the matching is
done before any other animation disabling strategies are checked. However, that also means it is not
possible to override class name matching with the two following strategies. It's of course still possible
to enable / disable animations by changing an element's class name at runtime.
### At runtime: {@link ng.$animate#enabled $animate.enabled()}
This function can be used to enable / disable animations in two different ways:
With a single `boolean` argument, it enables / disables animations globally: `$animate.enabled(false)`
disables all animations in your app.
When the second argument is a native DOM or jQuery element, the function enables / disables
animations on this element *and all its children*: `$animate.enabled(false, myElement)`. This is the
most flexible way to change the animation state. For example, even if you have used it to disable
animations on a parent element, you can still re-enable it for a child element. And compared to the
`classNameFilter`, you can change the animation status at runtime instead of during the config phase.
Note however that the `$animate.enabled()` state for individual elements does not overwrite disabling
rules that have been set in the {@link $animateProvider#classNameFilter classNameFilter}.
### Via CSS styles: overwriting styles in the `ng-animate` CSS class
Whenever an animation is started, ngAnimate applies the `ng-animate` class to the element for the
whole duration of the animation. By applying CSS transition / animation styling to the class,
you can skip an animation:
```css
.my-class{
transition: transform 2s;
}
.my-class:hover {
transform: translateX(50px);
}
my-class.ng-animate {
transition: 0s;
}
```
By setting `transition: 0s`, ngAnimate will ignore the existing transition styles, and not try to animate them (Javascript
animations will still execute, though). This can be used to prevent {@link guide/animations#preventing-collisions-with-existing-animations-and-third-party-libraries
issues with existing animations interfering with ngAnimate}.
## Preventing flicker before an animation starts
When nesting elements with structural animations such as `ngIf` into elements that have class-based
animations such as `ngClass`, it sometimes happens that before the actual animation starts, there is a brief flicker or flash of content
where the animated element is briefly visible.
To prevent this, you can apply styles to the `ng-[event]-prepare` class, which is added as soon as an animation is initialized,
but removed before the actual animation starts (after waiting for a $digest). This class is only added for *structural*
animations (`enter`, `move`, and `leave`).
Here's an example where you might see flickering:
```html
<div ng-class="{red: myProp}">
<div ng-class="{blue: myProp}">
<div class="message" ng-if="myProp"></div>
</div>
</div>
```
It is possible that during the `enter` event, the `.message` div will be briefly visible before it starts animating.
In that case, you can add styles to the CSS that make sure the element stays hidden before the animation starts:
```css
.message.ng-enter-prepare {
opacity: 0;
}
/* Other animation styles ... */
```
## Preventing Collisions with Existing Animations and Third Party Libraries
By default, any `ngAnimate` enabled directives will assume any transition / animation styles on the
element are part of an `ngAnimate` animation. This can lead to problems when the styles are actually
for animations that are independent of `ngAnimate`.
For example, an element acts as a loading spinner. It has an inifinite css animation on it, and also an
{@link ngIf `ngIf`} directive, for which no animations are defined:
```css
@keyframes rotating {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.spinner {
animation: rotating 2s linear infinite;
}
```
Now, when the `ngIf` changes, `ngAnimate` will see the spinner animation and use
it to animate the `enter`/`leave` event, which doesn't work because
the animation is infinite. The element will still be added / removed after a timeout, but there will be a
noticable delay.
This might also happen because some third-party frameworks place animation duration defaults
across many element or className selectors in order to make their code small and reuseable.
You can prevent this unwanted behavior by adding CSS to the `.ng-animate` class that is added
for the whole duration of an animation. Simply overwrite the transition / animation duration. In the
case of the spinner, this would be:
```css
.spinner.ng-animate {
transition: 0s none;
animation: 0s none;
}
```
If you do have CSS transitions / animations defined for the animation events, make sure they have higher priority
than any styles that are independent from ngAnimate.
You can also use one of the two other {@link guide/animations#how-to-selectively-enable-disable-and-skip-animations strategies to disable animations}.
## More about animations
For a full breakdown of each method available on `$animate`, see the {@link ng.$animate API documentation}.
+3 -14
View File
@@ -53,13 +53,13 @@ initialization.
Angular initializes automatically upon `DOMContentLoaded` event or when the `angular.js` script is
evaluated if at that time `document.readyState` is set to `'complete'`. At this point Angular looks
for the {@link ng.directive:ngApp `ngApp`} directive which designates your application root.
If the {@link ng.directive:ngApp `ngApp`} directive is found then Angular will:
for the {@link ng.directive:ngApp `ng-app`} directive which designates your application root.
If the {@link ng.directive:ngApp `ng-app`} directive is found then Angular will:
* load the {@link guide/module module} associated with the directive.
* create the application {@link auto.$injector injector}
* compile the DOM treating the {@link ng.directive:ngApp
`ngApp`} directive as the root of the compilation. This allows you to tell it to treat only a
`ng-app`} directive as the root of the compilation. This allows you to tell it to treat only a
portion of the DOM as an Angular application.
@@ -142,17 +142,6 @@ This is the sequence that your code should follow:
2. Call {@link angular.bootstrap} to {@link compiler compile} the element into an
executable, bi-directionally bound application.
## Things to keep in mind
There a few things to keep in mind regardless of automatic or manual bootstrapping:
- While it's possible to bootstrap more than one AngularJS application per page, we don't actively
test against this scenario. It's possible that you'll run into problems, especially with complex apps, so
caution is advised.
- Do not bootstrap your app on an element with a directive that uses {@link ng.$compile#transclusion transclusion}, such as
{@link ng.ngIf `ngIf`}, {@link ng.ngInclude `ngInclude`} and {@link ngRoute.ngView `ngView`}.
Doing this misplaces the app {@link ng.$rootElement `$rootElement`} and the app's {@link auto.$injector injector},
causing animations to stop working and making the injector inaccessible from outside the app.
## Deferred Bootstrap
File diff suppressed because it is too large Load Diff
-495
View File
@@ -1,495 +0,0 @@
@ngdoc overview
@name Components
@sortOrder 305
@description
# Understanding Components
In Angular, a Component is a special kind of {@link guide/directive directive} that uses a simpler
configuration which is suitable for a component-based application structure.
This makes it easier to write an app in a way that's similar to using Web Components or using Angular
2's style of application architecture.
Advantages of Components:
- simpler configuration than plain directives
- promote sane defaults and best practices
- optimized for component-based architecture
- writing component directives will make it easier to upgrade to Angular 2
When not to use Components:
- for directives that rely on DOM manipulation, adding event listeners etc, because the compile
and link functions are unavailable
- when you need advanced directive definition options like priority, terminal, multi-element
- when you want a directive that is triggered by an attribute or CSS class, rather than an element
## Creating and configuring a Component
Components can be registered using the `.component()` method of an Angular module (returned by {@link module `angular.module()`}). The method takes two arguments:
* The name of the Component (as string).
* The Component config object. (Note that, unlike the `.directive()` method, this method does **not** take a factory function.)
<example name="heroComponentSimple" module="heroApp">
<file name="index.js">
angular.module('heroApp', []).controller('mainCtrl', function() {
this.hero = {
name: 'Spawn'
};
});
</file>
<file name="heroDetail.js">
function HeroDetailController() {
}
angular.module('heroApp').component('heroDetail', {
templateUrl: 'heroDetail.html',
controller: HeroDetailController,
bindings: {
hero: '='
}
});
</file>
<file name="index.html">
<!-- components match only elements -->
<div ng-controller="mainCtrl as ctrl">
<b>Hero</b><br>
<hero-detail hero="ctrl.hero"></hero-detail>
</div>
</file>
<file name="heroDetail.html">
<span>Name: {{$ctrl.hero.name}}</span>
</file>
</example>
It's also possible to add components via {@link $compileProvider#component} in a module's config phase.
### Comparison between Directive definition and Component definition
| | Directive | Component |
|-------------------|----------------------|-----------------|
| bindings | No | Yes (binds to controller) |
| bindToController | Yes (default: false) | No (use bindings instead) |
| compile function | Yes | No |
| controller | Yes | Yes (default `function() {}`) |
| controllerAs | Yes (default: false) | Yes (default: `$ctrl`) |
| link functions | Yes | No |
| multiElement | Yes | No |
| priority | Yes | No |
| require | Yes | Yes |
| restrict | Yes | No (restricted to elements only) |
| scope | Yes (default: false) | No (scope is always isolate) |
| template | Yes | Yes, injectable |
| templateNamespace | Yes | No |
| templateUrl | Yes | Yes, injectable |
| terminal | Yes | No |
| transclude | Yes (default: false) | Yes (default: false) |
## Component-based application architecture
As already mentioned, the component helper makes it easier to structure your application with
a component-based architecture. But what makes a component beyond the options that
the component helper has?
- **Components only control their own View and Data:**
Components should never modify any data or DOM that is out of their own scope. Normally, in Angular
it is possible to modify data anywhere in the application through scope inheritance and watches. This
is practical, but can also lead to problems when it is not clear which part of the application is
responsible for modifying the data. That is why component directives use an isolate scope, so a whole
class of scope manipulation is not possible.
- **Components have a well-defined public API - Inputs and Outputs:**
However, scope isolation only goes so far, because Angular uses two-way binding. So if you pass
an object to a component like this - `bindings: {item: '='}`, and modify one of its properties, the
change will be reflected in the parent component. For components however, only the component that owns
the data should modify it, to make it easy to reason about what data is changed, and when. For that reason,
components should follow a few simple conventions:
- Inputs should be using `<` and `@` bindings. The `<` symbol denotes {@link $compile#-scope- one-way bindings} which are
available since 1.5. The difference to `=` is that the bound properties in the component scope are not watched, which means
if you assign a new value to the property in the component scope, it will not update the parent scope. Note however, that both parent
and component scope reference the same object, so if you are changing object properties or array elements in the
component, the parent will still reflect that change.
The general rule should therefore be to never change an object or array property in the component scope.
`@` bindings can be used when the input is a string, especially when the value of the binding doesn't change.
```js
bindings: {
hero: '<',
comment: '@'
}
```
- Outputs are realized with `&` bindings, which function as callbacks to component events.
```js
bindings: {
onDelete: '&',
onUpdate: '&'
}
```
- Instead of manipulating Input Data, the component calls the correct Output Event with the changed data.
For a deletion, that means the component doesn't delete the `hero` itself, but sends it back to
the owner component via the correct event.
```html
<button ng-click="$ctrl.onDelete({hero: $ctrl.hero})">Delete</button>
```
- That way, the parent component can decide what to do with the event (e.g. delete an item or update the properties)
```js
ctrl.deleteHero(hero) {
$http.delete(...).then(function() {
var idx = ctrl.list.indexOf(hero);
if (idx >= 0) {
ctrl.list.splice(idx, 1);
}
});
}
```
- **Components have a well-defined lifecycle**
Each component can implement "lifecycle hooks". These are methods that will be called at certain points in the life
of the component. The following hook methods can be implemented:
* `$onInit()` - Called on each controller after all the controllers on an element have been constructed and
had their bindings initialized (and before the pre &amp; post linking functions for the directives on
this element). This is a good place to put initialization code for your controller.
* `$onChanges(changesObj)` - Called whenever one-way bindings are updated. The `changesObj` is a hash whose keys
are the names of the bound properties that have changed, and the values are an object of the form
`{ currentValue: ..., previousValue: ... }`. Use this hook to trigger updates within a component such as
cloning the bound value to prevent accidental mutation of the outer value.
* `$onDestroy()` - Called on a controller when its containing scope is destroyed. Use this hook for releasing
external resources, watches and event handlers.
* `$postLink()` - Called after this controller's element and its children have been linked. Similar to the post-link
function this hook can be used to set up DOM event handlers and do direct DOM manipulation.
Note that child elements that contain `templateUrl` directives will not have been compiled and linked since
they are waiting for their template to load asynchronously and their own compilation and linking has been
suspended until that occurs.
This hook can be considered analogous to the `ngAfterViewInit` and `ngAfterContentInit` hooks in Angular 2.
Since the compilation process is rather different in Angular 1 there is no direct mapping and care should
be taken when upgrading.
By implementing these methods, you component can take part in its lifecycle.
- **An application is a tree of components:**
Ideally, the whole application should be a tree of components that implement clearly defined inputs
and outputs, and minimize two-way data binding. That way, it's easier to predict when data changes and what the state
of a component is.
## Example of a component tree
The following example expands on the simple component example and incorporates the concepts we introduced
above:
Instead of an ngController, we now have a heroList component that holds the data of
different heroes, and creates a heroDetail for each of them.
The heroDetail component now contains new functionality:
- a delete button that calls the bound `onDelete` function of the heroList component
- an input to change the hero location, in the form of a reusable editableField component. Instead
of manipulating the hero object itself, it sends a changeset upwards to the heroDetail, which sends
it upwards to the heroList component, which updates the original data.
<example name="heroComponentTree" module="heroApp">
<file name="index.js">
var mode = angular.module('heroApp', []);
</file>
<file name="heroList.js">
function HeroListController($scope, $element, $attrs) {
var ctrl = this;
// This would be loaded by $http etc.
ctrl.list = [
{
name: 'Superman',
location: ''
},
{
name: 'Batman',
location: 'Wayne Manor'
}
];
ctrl.updateHero = function(hero, prop, value) {
hero[prop] = value;
};
ctrl.deleteHero = function(hero) {
var idx = ctrl.list.indexOf(hero);
if (idx >= 0) {
ctrl.list.splice(idx, 1);
}
};
}
angular.module('heroApp').component('heroList', {
templateUrl: 'heroList.html',
controller: HeroListController
});
</file>
<file name="heroDetail.js">
function HeroDetailController($scope, $element, $attrs) {
var ctrl = this;
ctrl.update = function(prop, value) {
ctrl.onUpdate({hero: ctrl.hero, prop: prop, value: value});
};
}
angular.module('heroApp').component('heroDetail', {
templateUrl: 'heroDetail.html',
controller: HeroDetailController,
bindings: {
hero: '<',
onDelete: '&',
onUpdate: '&'
}
});
</file>
<file name="editableField.js">
function EditableFieldController($scope, $element, $attrs) {
var ctrl = this;
ctrl.editMode = false;
ctrl.handleModeChange = function() {
if (ctrl.editMode) {
ctrl.onUpdate({value: ctrl.fieldValue});
ctrl.fieldValueCopy = ctrl.fieldValue;
}
ctrl.editMode = !ctrl.editMode;
};
ctrl.reset = function() {
ctrl.fieldValue = ctrl.fieldValueCopy;
};
ctrl.$onInit = function() {
// Make a copy of the initial value to be able to reset it later
ctrl.fieldValueCopy = ctrl.fieldValue;
// Set a default fieldType
if (!ctrl.fieldType) {
ctrl.fieldType = 'text';
}
};
}
angular.module('heroApp').component('editableField', {
templateUrl: 'editableField.html',
controller: EditableFieldController,
bindings: {
fieldValue: '<',
fieldType: '@?',
onUpdate: '&'
}
});
</file>
<file name="index.html">
<hero-list></hero-list>
</file>
<file name="heroList.html">
<b>Heroes</b><br>
<hero-detail ng-repeat="hero in $ctrl.list" hero="hero" on-delete="$ctrl.deleteHero(hero)" on-update="$ctrl.updateHero(hero, prop, value)"></hero-detail>
</file>
<file name="heroDetail.html">
<hr>
<div>
Name: {{$ctrl.hero.name}}<br>
Location: <editable-field field-value="$ctrl.hero.location" field-type="text" on-update="$ctrl.update('location', value)"></editable-field><br>
<button ng-click="$ctrl.onDelete({hero: $ctrl.hero})">Delete</button>
</div>
</file>
<file name="editableField.html">
<span ng-switch="$ctrl.editMode">
<input ng-switch-when="true" type="{{$ctrl.fieldType}}" ng-model="$ctrl.fieldValue">
<span ng-switch-default>{{$ctrl.fieldValue}}</span>
</span>
<button ng-click="$ctrl.handleModeChange()">{{$ctrl.editMode ? 'Save' : 'Edit'}}</button>
<button ng-if="$ctrl.editMode" ng-click="$ctrl.reset()">Reset</button>
</file>
</example>
## Components as route templates
Components are also useful as route templates (e.g. when using {@link ngRoute ngRoute}). In a component-based
application, every view is a component:
```js
var myMod = angular.module('myMod', ['ngRoute']);
myMod.component('home', {
template: '<h1>Home</h1><p>Hello, {{ $ctrl.user.name }} !</p>',
controller: function() {
this.user = {name: 'world'};
}
});
myMod.config(function($routeProvider) {
$routeProvider.when('/', {
template: '<home></home>'
});
});
```
<br />
When using {@link ngRoute.$routeProvider $routeProvider}, you can often avoid some
boilerplate, by passing the resolved route dependencies directly to the component. Since 1.5,
ngRoute automatically assigns the resolves to the route scope property `$resolve` (you can also
configure the property name via `resolveAs`). When using components, you can take advantage of this and pass resolves
directly into your component without creating an extra route controller:
```js
var myMod = angular.module('myMod', ['ngRoute']);
myMod.component('home', {
template: '<h1>Home</h1><p>Hello, {{ $ctrl.user.name }} !</p>',
bindings: {
user: '<'
}
});
myMod.config(function($routeProvider) {
$routeProvider.when('/', {
template: '<home user="$resolve.user"></home>',
resolve: {
user: function($http) { return $http.get('...'); }
}
});
});
```
## Intercomponent Communication
Directives can require the controllers of other directives to enable communication
between each other. This can be achieved in a component by providing an
object mapping for the `require` property. The object keys specify the property names under which
the required controllers (object values) will be bound to the requiring component's controller.
<div class="alert alert-warning">
Note that the required controllers will not be available during the instantiation of the controller,
but they are guaranteed to be available just before the `$onInit` method is executed!
</div>
Here is a tab pane example built from components:
<example module="docsTabsExample">
<file name="script.js">
angular.module('docsTabsExample', [])
.component('myTabs', {
transclude: true,
controller: function() {
var panes = this.panes = [];
this.select = function(pane) {
angular.forEach(panes, function(pane) {
pane.selected = false;
});
pane.selected = true;
};
this.addPane = function(pane) {
if (panes.length === 0) {
this.select(pane);
}
panes.push(pane);
};
},
templateUrl: 'my-tabs.html'
})
.component('myPane', {
transclude: true,
require: {
tabsCtrl: '^myTabs'
},
bindings: {
title: '@'
},
controller: function() {
this.$onInit = function() {
this.tabsCtrl.addPane(this);
console.log(this);
};
},
templateUrl: 'my-pane.html'
});
</file>
<file name="index.html">
<my-tabs>
<my-pane title="Hello">
<h4>Hello</h4>
<p>Lorem ipsum dolor sit amet</p>
</my-pane>
<my-pane title="World">
<h4>World</h4>
<em>Mauris elementum elementum enim at suscipit.</em>
<p><a href ng-click="i = i + 1">counter: {{i || 0}}</a></p>
</my-pane>
</my-tabs>
</file>
<file name="my-tabs.html">
<div class="tabbable">
<ul class="nav nav-tabs">
<li ng-repeat="pane in $ctrl.panes" ng-class="{active:pane.selected}">
<a href="" ng-click="$ctrl.select(pane)">{{pane.title}}</a>
</li>
</ul>
<div class="tab-content" ng-transclude></div>
</div>
</file>
<file name="my-pane.html">
<div class="tab-pane" ng-show="$ctrl.selected" ng-transclude></div>
</file>
</example>
# Unit-testing Component Controllers
The easiest way to unit-test a component controller is by using the {@link ngMock.$componentController $componentController}
that is included in {@link ngMock}. The advantage of this method is that you do not have
to create any DOM elements. The following example shows how to do this for the `heroDetail` component
from above.
The examples use the [Jasmine](http://jasmine.github.io/) testing framework.
**Controller Test:**
```js
describe('component: heroDetail', function() {
var component, scope, hero, $componentController;
beforeEach(module('simpleComponent'));
beforeEach(inject(function($rootScope, _$componentController_) {
scope = $rootScope.$new();
$componentController = _$componentController_;
hero = {name: 'Wolverine'};
}));
it('should set the default values of the hero', function() {
// It's necessary to always pass the scope in the locals, so that the controller instance can be bound to it
component = $componentController('heroDetail', {$scope: scope});
expect(component.hero).toEqual({
name: undefined,
location: 'unknown'
});
});
it('should assign the name bindings to the hero object', function() {
// Here we are passing actual bindings to the component
component = $componentController('heroDetail',
{$scope: scope},
{hero: hero}
);
expect(component.hero.name).toBe('Wolverine');
});
it('should call the onDelete binding when a hero is deleted', function() {
component = $componentController('heroDetail',
{$scope: scope},
{hero: hero, onDelete: jasmine.createSpy('deleteSpy')}
);
component.onDelete({hero: component.hero});
expect(spy('deleteSpy')).toHaveBeenCalledWith(component.hero);
});
});
```
+2 -2
View File
@@ -334,9 +334,9 @@ The following example shows how this is done with Angular:
var refresh = function() {
var url = YAHOO_FINANCE_URL_PATTERN.
replace('PAIRS', 'USD' + currencies.join('","USD'));
return $http.jsonp(url).then(function(response) {
return $http.jsonp(url).success(function(data) {
var newUsdToForeignRates = {};
angular.forEach(response.data.query.results.rate, function(rate) {
angular.forEach(data.query.results.rate, function(rate) {
var currency = rate.id.substring(3,6);
newUsdToForeignRates[currency] = window.parseFloat(rate.Rate);
});
+25 -30
View File
@@ -99,13 +99,8 @@ For example, the following forms are all equivalent and match the {@link ngBind}
</file>
<file name="protractor.js" type="protractor">
it('should show off bindings', function() {
var containerElm = element(by.css('div[ng-controller="Controller"]'));
var nameBindings = containerElm.all(by.binding('name'));
expect(nameBindings.count()).toBe(5);
nameBindings.each(function(elem) {
expect(elem.getText()).toEqual('Max Karl Ernst Ludwig Planck (April 23, 1858 October 4, 1947)');
});
expect(element(by.css('div[ng-controller="Controller"] span[ng-bind]')).getText())
.toBe('Max Karl Ernst Ludwig Planck (April 23, 1858 October 4, 1947)');
});
</file>
</example>
@@ -303,7 +298,6 @@ The `restrict` option is typically set to:
* `'A'` - only matches attribute name
* `'E'` - only matches element name
* `'C'` - only matches class name
* `'M'` - only matches comment
These restrictions can all be combined as needed:
@@ -407,7 +401,7 @@ This is clearly not a great solution.
What we want to be able to do is separate the scope inside a directive from the scope
outside, and then map the outer scope to a directive's inner scope. We can do this by creating what
we call an **isolate scope**. To do this, we can use a {@link $compile#-scope- directive's `scope`} option:
we call an **isolate scope**. To do this, we can use a directive's `scope` option:
<example module="docsIsolateScopeDirective">
<file name="script.js">
@@ -647,7 +641,6 @@ To do this, we need to use the `transclude` option.
return {
restrict: 'E',
transclude: true,
scope: {},
templateUrl: 'my-dialog.html'
};
});
@@ -658,7 +651,8 @@ To do this, we need to use the `transclude` option.
</div>
</file>
<file name="my-dialog.html">
<div class="alert" ng-transclude></div>
<div class="alert" ng-transclude>
</div>
</file>
</example>
@@ -680,7 +674,7 @@ that redefines `name` as `Jeff`. What do you think the `{{name}}` binding will r
transclude: true,
scope: {},
templateUrl: 'my-dialog.html',
link: function (scope) {
link: function (scope, element) {
scope.name = 'Jeff';
}
};
@@ -692,7 +686,8 @@ that redefines `name` as `Jeff`. What do you think the `{{name}}` binding will r
</div>
</file>
<file name="my-dialog.html">
<div class="alert" ng-transclude></div>
<div class="alert" ng-transclude>
</div>
</file>
</example>
@@ -703,7 +698,7 @@ The `transclude` option changes the way scopes are nested. It makes it so that t
transcluded directive have whatever scope is outside the directive, rather than whatever scope is on
the inside. In doing so, it gives the contents access to the outside scope.
Note that if the directive did not create its own scope, then `scope` in `scope.name = 'Jeff'` would
Note that if the directive did not create its own scope, then `scope` in `scope.name = 'Jeff';` would
reference the outside scope and we would see `Jeff` in the output.
This behavior makes sense for a directive that wraps some content, because otherwise you'd have to
@@ -776,9 +771,9 @@ function.
Often it's desirable to pass data from the isolate scope via an expression to the
parent scope, this can be done by passing a map of local variable names and values into the expression
wrapper function. For example, the `hideDialog` function takes a message to display when the dialog
is hidden. This is specified in the directive by calling `close({message: 'closing for now'})`.
Then the local variable `message` will be available within the `on-close` expression.
wrapper fn. For example, the hideDialog function takes a message to display when the dialog is hidden.
This is specified in the directive by calling `close({message: 'closing for now'})`. Then the local
variable `message` will be available within the `on-close` expression.
<div class="alert alert-success">
**Best Practice:** use `&attr` in the `scope` option when you want your directive
@@ -837,7 +832,7 @@ element?
}]);
</file>
<file name="index.html">
<span my-draggable>Drag Me</span>
<span my-draggable>Drag ME</span>
</file>
</example>
@@ -882,7 +877,7 @@ to which tab is active.
})
.directive('myPane', function() {
return {
require: '^^myTabs',
require: '^myTabs',
restrict: 'E',
transclude: true,
scope: {
@@ -898,9 +893,11 @@ to which tab is active.
<file name="index.html">
<my-tabs>
<my-pane title="Hello">
<h4>Hello</h4>
<p>Lorem ipsum dolor sit amet</p>
</my-pane>
<my-pane title="World">
<h4>World</h4>
<em>Mauris elementum elementum enim at suscipit.</em>
<p><a href ng-click="i = i + 1">counter: {{i || 0}}</a></p>
</my-pane>
@@ -917,25 +914,22 @@ to which tab is active.
</div>
</file>
<file name="my-pane.html">
<div class="tab-pane" ng-show="selected">
<h4>{{title}}</h4>
<div ng-transclude></div>
<div class="tab-pane" ng-show="selected" ng-transclude>
</div>
</file>
</example>
The `myPane` directive has a `require` option with value `^^myTabs`. When a directive uses this
option, `$compile` will throw an error unless the specified controller is found. The `^^` prefix
means that this directive searches for the controller on its parents. (A `^` prefix would make the
directive look for the controller on its own element or its parents; without any prefix, the
directive would look on its own element only.)
The `myPane` directive has a `require` option with value `^myTabs`. When a directive uses this
option, `$compile` will throw an error unless the specified controller is found. The `^` prefix
means that this directive searches for the controller on its parents (without the `^` prefix, the
directive would look for the controller on just its own element).
So where does this `myTabs` controller come from? Directives can specify controllers using
the unsurprisingly named `controller` option. As you can see, the `myTabs` directive uses this
option. Just like `ngController`, this option attaches a controller to the template of the directive.
If it is necessary to reference the controller or any functions bound to the controller from the
template, you can use the option `controllerAs` to specify the name of the controller as an alias.
If it is necessary to reference the controller or any functions bound to the controller's scope in
the template, you can use the option `controllerAs` to specify the name of the controller as an alias.
The directive needs to define a scope for this configuration to be used. This is particularly useful
in the case when the directive is used as a component.
@@ -950,7 +944,7 @@ The corresponding parameter being sent to the `link` function will also be an ar
angular.module('docsTabsExample', [])
.directive('myPane', function() {
return {
require: ['^^myTabs', 'ngModel'],
require: ['^myTabs', '^ngModel'],
restrict: 'E',
transclude: true,
scope: {
@@ -986,3 +980,4 @@ available in the {@link guide/compiler compiler guide}.
The {@link ng.$compile `$compile` API} page has a comprehensive list of directive options for
reference.
-3
View File
@@ -116,9 +116,6 @@ This restriction is intentional. It prevents accidental access to the global sta
Instead use services like `$window` and `$location` in functions called from expressions. Such services
provide mockable access to globals.
It is possible to access the context object using the identifier `this` and the locals object using the
identifier `$locals`.
<example module="expressionExample">
<file name="index.html">
<div class="example2" ng-controller="ExampleController">
+5 -12
View File
@@ -3,8 +3,6 @@
@sortOrder 280
@description
# Filters
A filter formats the value of an expression for display to the user. They can be used in view templates,
controllers or services and it is easy to define your own filter.
@@ -34,13 +32,10 @@ E.g. the markup `{{ 1234 | number:2 }}` formats the number 1234 with 2 decimal p
## Using filters in controllers, services, and directives
You can also use filters in controllers, services, and directives.
<div class="alert alert-info">
For this, inject a dependency with the name `<filterName>Filter` into your controller/service/directive.
E.g. a filter called `number` is injected by using the dependency `numberFilter`. The injected argument
is a function that takes the value to format as first argument, and filter parameters starting with the second argument.
</div>
You can also use filters in controllers, services, and directives. For this, inject a dependency
with the name `<filterName>Filter` to your controller/service/directive. E.g. using the dependency
`numberFilter` will inject the number filter. The injected argument is a function that takes the
value to format as first argument and filter parameters starting with the second argument.
The example below uses the filter called {@link ng.filter:filter `filter`}.
This filter reduces arrays into sub arrays based on
@@ -113,7 +108,6 @@ text upper-case.
No filter: {{greeting}}<br>
Reverse: {{greeting|reverse}}<br>
Reverse + uppercase: {{greeting|reverse:true}}<br>
Reverse, filtered in controller: {{filteredGreeting}}<br>
</div>
</file>
@@ -133,9 +127,8 @@ text upper-case.
return out;
};
})
.controller('MyController', ['$scope', 'reverseFilter', function($scope, reverseFilter) {
.controller('MyController', ['$scope', function($scope) {
$scope.greeting = 'hello';
$scope.filteredGreeting = reverseFilter($scope.greeting);
}]);
</file>
</example>
+2 -1
View File
@@ -440,7 +440,8 @@ Note that you can alternatively use `ng-pattern` to further restrict the validat
var EMAIL_REGEXP = /^[a-z0-9!#$%&'*+/=?^_`{|}~.-]+@example\.com$/i;
return {
require: '?ngModel',
require: 'ngModel',
restrict: '',
link: function(scope, elm, attrs, ctrl) {
// only apply the validator if ngModel is present and Angular has added the email validator
if (ctrl && ctrl.$validators.email) {
+1 -4
View File
@@ -28,7 +28,4 @@ browsers, but it is up to you to test and decide whether it works for your parti
To ensure your Angular application works on IE please consider:
1. Use `ng-style` tags instead of `style="{{ someCss }}"`. The latter works in Chrome and Firefox
but does not work in Internet Explorer <= 11 (the most recent version at time of writing).
2. For the `type` attribute of buttons, use `ng-attr-type` tags instead of
`type="{{ someExpression }}"`. If using the latter, Internet Explorer overwrites the expression
with `type="submit"` before Angular has a chance to interpolate it.
but does not work in Internet Explorer <= 11 (the most recent version at time of writing).
+1 -4
View File
@@ -91,7 +91,7 @@ This is a short list of libraries with specific support and documentation for wo
### Server-Specific
* **Django:** [Tutorial](http://blog.mourafiq.com/post/55034504632/end-to-end-web-app-with-django-rest-framework), [Integrating AngularJS with Django](http://django-angular.readthedocs.org/en/latest/integration.html), [Getting Started with Django Rest Framework and AngularJS](http://blog.kevinastone.com/getting-started-with-django-rest-framework-and-angularjs.html)
* **FireBase:** [AngularFire](http://angularfire.com/), [Firebase Foundations for AngularJS](http://blog.watchandcode.com/firebase-foundations/), [Realtime Apps with AngularJS and FireBase (video)](http://www.youtube.com/watch?v=C7ZI7z7qnHU)
* **FireBase:** [AngularFire](http://angularfire.com/), [Realtime Apps with AngularJS and FireBase (video)](http://www.youtube.com/watch?v=C7ZI7z7qnHU)
* **Google Cloud Platform: **[with Cloud Endpoints](https://cloud.google.com/developers/articles/angularjs-cloud-endpoints-recipe-for-building-modern-web-applications/), [with Go](https://github.com/GoogleCloudPlatform/appengine-angular-gotodos)
* **Hood.ie:** [60 Minutes to Awesome](http://www.roberthorvick.com/2013/06/30/todomvc-angularjs-hood-ie-60-minutes-to-awesome/)
* **MEAN Stack: **[Blog post](http://blog.mongodb.org/post/49262866911/the-mean-stack-mongodb-expressjs-angularjs-and), [Setup](http://thecodebarbarian.wordpress.com/2013/07/22/introduction-to-the-mean-stack-part-one-setting-up-your-tools/), [GDL Video](https://developers.google.com/live/shows/913996610)
@@ -111,12 +111,10 @@ This is a short list of libraries with specific support and documentation for wo
* [AngularJS : Novice to Ninja](http://www.amazon.in/AngularJS-Novice-Ninja-Sandeep-Panda/dp/0992279453) by Sandeep Panda
* [AngularJS UI Development](http://www.amazon.com/AngularJS-UI-Development-Amit-Ghart-ebook/dp/B00OXVAK7A) by Amit Gharat and Matthias Nehlsen
* [Responsive Web Design with AngularJS](http://www.amazon.com/Responsive-Design-AngularJS-Sandeep-Kumar/dp/178439842X) by Sandeep Kumar Patel
* [Professional AngularJS](http://www.amazon.com/Professional-AngularJS-Valeri-Karpov/dp/1118832078/)
###Videos:
* [egghead.io](http://egghead.io/)
* [Angular on YouTube](http://youtube.com/angularjs)
* [Firebase Foundations for AngularJS](http://blog.watchandcode.com/firebase-foundations/)
### Courses
* **Free online:**
@@ -124,7 +122,6 @@ This is a short list of libraries with specific support and documentation for wo
[CodeAcademy](http://www.codecademy.com/courses/javascript-advanced-en-2hJ3J/0/1),
[CodeSchool](https://www.codeschool.com/courses/shaping-up-with-angular-js)
* **Paid online:**
[The Angular Course (115 videos that show you how to build a full app)](http://watchandcode.com/courses/angular-course/),
[Pluralsite (3 courses)](http://www.pluralsight.com/training/Courses/Find?highlight=true&searchTerm=angularjs),
[Tuts+](https://tutsplus.com/course/easier-js-apps-with-angular/),
[lynda.com](http://www.lynda.com/AngularJS-tutorials/Up-Running-AngularJS/133318-2.html),
+10 -14
View File
@@ -5,7 +5,7 @@
# Interpolation and data-binding
Interpolation markup with embedded {@link guide/expression expressions} is used by Angular to
Interpolation markup with embedded @link {guide/expressions expressions} is used by Angular to
provide data-binding to text nodes and attribute values.
An example of interpolation is shown below:
@@ -43,8 +43,8 @@ interpret the attribute as present, meaning that the button would always be disa
```
For this reason, Angular provides special `ng`-prefixed directives for the following boolean attributes:
{@link ngDisabled `disabled`}, {@link ngRequired `required`}, {@link ngSelected `selected`},
{@link ngChecked `checked`}, {@link ngReadonly `readOnly`} , and {@link ngOpen `open`}.
{@link ngDisabled `disabled`}, [@link ngRequired `required`}, [@link ngSelected `selected`},
{@link ngChecked `checked`}, {@link ngReadonly `readOnly`} , and [@link ngOpen `open`}.
These directives take an expression inside the attribute, and set the corresponding boolean attribute
to true when the expression evaluates to truthy.
@@ -98,20 +98,16 @@ For example, to bind to `viewBox`, we can write:
</svg>
```
Other attributes may also not work as expected when they contain interpolation markup, and
can be used with `ngAttr` instead. The following is a list of known problematic attributes:
The following attributes are also known to cause problems when used with normal bindings:
- **size** in `<select>` elements (see [issue 1619](https://github.com/angular/angular.js/issues/1619))
- **placeholder** in `<textarea>` in Internet Explorer 10/11 (see [issue 5025](https://github.com/angular/angular.js/issues/5025))
- **type** in `<button>` in Internet Explorer 11 (see [issue 14117](https://github.com/angular/angular.js/issues/5025))
- **size** in `<select>` elements (see [Github issue 1619](https://github.com/angular/angular.js/issues/1619))
- **placeholder** in `<textarea>` in Internet Explorer 10/11 (see [Github issue 5025](https://github.com/angular/angular.js/issues/5025))
### Embedding interpolation markup inside expressions
<div class="alert alert-danger">
**Note:** Angular directive attributes take either expressions *or* interpolation markup with embedded expressions.
It is considered **bad practice** to embed interpolation markup inside an expression:
</div>
Angular directives take either expressions or interpolation markup with embedded expressions. So the
following example which embeds interpolation inside an expression is a bad practice:
```html
<div ng-show="form{{$index}}.$invalid"></div>
@@ -124,8 +120,8 @@ You should instead delegate the computation of complex expressions to the scope,
```
```js
function getForm(index) {
return $scope['form' + index];
function getForm() {
return $scope['form' + $index];
}
```
+60 -329
View File
@@ -3,246 +3,17 @@
@sortOrder 550
@description
# Migrating an App to a newer version
Minor version releases in AngularJS introduce several breaking changes that may require changes to your
application's source code; for instance from 1.0 to 1.2 and from 1.2 to 1.3.
Although we try to avoid breaking changes, there are some cases where it is unavoidable:
Although we try to avoid breaking changes, there are some cases where it is unavoidable.
* AngularJS has undergone thorough security reviews to make applications safer by default,
which drives many of these changes.
* Several new features, especially animations, would not be possible without a few changes.
* Finally, some outstanding bugs were best fixed by changing an existing API.
## Contents
<ul class="nav nav-list">
<li>{@link guide/migration#migrating-from-1-4-to-1-5 Migrating from 1.4 to 1.5}</li>
<li>{@link guide/migration#migrating-from-1-3-to-1-4 Migrating from 1.3 to 1.4}</li>
<li>{@link guide/migration#migrating-from-1-2-to-1-3 Migrating from 1.2 to 1.3}</li>
<li>{@link guide/migration#migrating-from-1-0-to-1-2 Migrating from 1.0 to 1.2}</li>
</ul>
## Migrating from 1.4 to 1.5
Angular 1.5 takes a big step towards preparing developers for a smoother transition to Angular 2 in
the future. Architecturing your applications using components, multi-slot transclusion, one-way
bindings in isolate scopes, using lifecycle hooks in directive controllers and relying on native ES6
features (such as classes and arrow functions) are now all possible with Angular 1.5.
This release includes numerous bug and security fixes, as well as performance improvements to core
services, directives, filters and helper functions. Existing applications can start enjoying the
benefits of such changes in `$compile`, `$parse`, `$animate`, `$animateCss`, `$sanitize`, `ngOptions`,
`currencyFilter`, `numberFilter`, `copy()` (to name but a few) without any change in code.
New features have been added to more than a dozen services, directives and filters across 8 modules.
Among them, a few stand out:
* `angular.component()`: Introducing "components", a special sort of directive that are easy to
configure and promote best practices (plus can bring Angular 1 applications closer to Angular 2's
style of architecture).
* Multi-slot transclusion: Enabling the design of more powerful and complex UI elements with a much
simpler configuration and reduced boilerplate.
* `$onInit` lifecycle hook: Introducing a new lifecycle hook for directive controllers, called after
all required controllers have been constructed. This enables access to required controllers from
a directive's controller, without having to rely on the linking function.
* `ngAnimateSwap`: A new directive in `ngAnimate`, making it super easy to create rotating
banner-like components.
* Testing helpers: New helper functions in `ngMock`, simplifying testing for animations, component
controllers and routing.
Also, notable is the improved support for ES6 features, such as classes and arrow functions. These
features are now more reliably detected and correctly handled within the core.
All this goodness doesn't come without a price, though. Below is a list of breaking changes (grouped
by module) that need to be taken into account while migrating from 1.4. Fortunately, the majority of
them should have a pretty low impact on most applications.
### Core
We tried to keep the breaking changes inside the core components to a bare minimum. Still, a few of
them were unavoidable.
#### Services (`$parse`)
Due to [0ea53503](https://github.com/angular/angular.js/commit/0ea535035a3a1a992948490c3533bffb83235052),
a new special property, `$locals`, will be available for accessing the locals from an expression.
This is a breaking change, only if a `$locals` property does already exist (and needs to be
referenced) either on the `scope` or on the `locals` object. Your expressions should be changed to
access such existing properties as `this.$locals` and `$locals.$locals` respectively.
#### Directives (`ngOptions`)
A fair amount of work has been put into the `ngOptions` directive, fixing bugs and corner-cases and
neutralizing browser quirks. A couple of breaking changes were made in the process:
Due to [b71d7c3f](https://github.com/angular/angular.js/commit/b71d7c3f3c04e65b02d88b33c22dd90ae3cdfc27),
falsy values (`''`, `0`, `false` and `null`) are properly recognized as option group identifiers for
options passed to `ngOptions`. Previously, all of these values were ignored and the option was not
assigned to any group. `undefined` is still interpreted as "no group".
If you have options with falsy group indentifiers that should still not be assigned to any group,
then you must filter the values before passing them to `ngOptions`, converting falsy values to
`undefined`.
Due to [ded25187](https://github.com/angular/angular.js/commit/ded2518756d4409fdfda0d4af243f2125bea01b5),
`ngOptions` now explicitly requires `ngModel` on the same element, thus an error will be thrown if
`ngModel` is not found. Previously, `ngOptions` would silently fail, which could lead to
hard-to-debug errors.
This is not expected to have any significant impact on applications, since `ngOptions` didn't work
without `ngModel` before either. The main difference is that now it will fail with a more
informative error message.
#### Filters (`orderBy`)
Due to [2a85a634](https://github.com/angular/angular.js/commit/2a85a634f86c84f15b411ce009a3515fca7ba580),
passing a non-array-like value (other than `undefined` or `null`) through the `orderBy` filter will
throw an error. Previously, the input was returned unchanged, which could lead to hard-to-spot bugs
and was not consistent with other filters (e.g. `filter`).
Objects considered array-like include: arrays, array subclasses, strings, NodeLists,
jqLite/jQuery collections
### ngAria
Due to [d06431e](https://github.com/angular/angular.js/commit/d06431e5309bb0125588877451dc79b935808134),
the `ngAria`-enhanced directives (e.g. `ngModel`, `ngDisabled` etc) will not apply ARIA attributes
to native inputs, unless necessary. Previously, ARIA attributes were always applied to native
inputs, despite this being unnecessary in most cases.
In the context of `ngAria`, elements considered "native inputs" include:
`<a>`, `<button>`, `<details>`, `<input>`, `<select>`, `<summary>`, `<textarea>`
This change will not affect the accessibility of your applications (since native inputs are
accessible by default), but if you relied on ARIA attributes being present on native inputs (for
whatever reason), you'll have to add and update them manually.
Additionally, the `aria-multiline` attribute, which was previously added to elements with a `type`
or `role` of `textbox`, will not be added anymore, since there is no way `ngAria` can tell if the
textbox element is multiline or not.
If you relied on `aria-multiline="true"` being automatically added by `ngAria`, you need to apply it
yourself. E.g. change your code from `<div role="textbox" ng-model="..." ...>` to
`<div role="textbox" ng-model="..." ... aria-multiline="true">`.
### ngMessages (`ngMessage`)
Due to [4971ef12](https://github.com/angular/angular.js/commit/4971ef12d4c2c268cb8d26f90385dc96eba19db8),
the `ngMessage` directive is now compiled with a priority of 1, which means directives on the same
element as `ngMessage` with a priority lower than 1 will be applied when `ngMessage` calls its
`$transclude` function. Previously, they were applied during the initial compile phase and were
passed the comment element created by the transclusion of `ngMessage`.
If you have custom directives that relied on the previous behavior, you need to give them a priority
of 1 or greater.
### ngResource (`$resource`)
The `$resource` service underwent a minor internal refactoring to finally solve a long-standing bug
preventing requests from being cancelled using promises. Due to the nature of `$resource`'s
configuration, it was not possible to follow the `$http` convention. A new `$cancelRequest()` method
was introduced instead.
Due to [98528be3](https://github.com/angular/angular.js/commit/98528be311b48269ba0e15ba4e3e2ad9b89693a9),
using a promise as `timeout` in `$resource` is no longer supported and will log a warning. This is
hardly expected to affect the behavior of your application, since a promise as `timeout` didn't work
before either, but it will now warn you explicitly when trying to pass one.
If you need to be able to cancel pending requests, you can now use the new `$cancelRequest()` that
will be available on `$resource` instances.
### ngRoute (`ngView`)
Due to [983b0598](https://github.com/angular/angular.js/commit/983b0598121a8c5a3a51a30120e114d7e3085d4d),
a new property will be available on the scope of the route, allowing easy access to the route's
resolved values from the view's template. The default name for this property is `$resolve`. This is
a breaking change, only if a `$resolve` property is already available on the scope, in which case
the existing property will be hidden or overwritten.
To fix this, you should choose a custom name for this property, that does not collide with other
properties on the scope, by specifying the `resolveAs` property on the route.
### ngSanitize (`$sanitize`, `linky`)
The HTML sanitizer has been re-implemented using inert documents, increasing security, fixing some
corner-cases that were difficult to handle and reducing its size by about 20% (in terms of loc). In
order to make it more secure by default, a couple of breaking changes have been introduced:
Due to [181fc567](https://github.com/angular/angular.js/commit/181fc567d873df065f1e84af7225deb70a8d2eb9),
SVG support in `$sanitize` is now an opt-in feature (i.e. disabled by default), as it could make
an application vulnerable to click-hijacking attacks. If your application relies on it, you can
still turn it on with `$sanitizeProvider.enableSvg(true)`, but you extra precautions need to be
taken in order to keep your application secure. Read the documentation for more information about
the dangers and ways to mitigate them.
Due to [7a668cdd](https://github.com/angular/angular.js/commit/7a668cdd7d08a7016883eb3c671cbcd586223ae8),
the `$sanitize` service will now remove instances of the `<use>` tag from the content passed to it.
This element is used to import external SVG resources, which is a security risk as the `$sanitize`
service does not have access to the resource in order to sanitize it.
Similarly, due to [234053fc](https://github.com/angular/angular.js/commit/234053fc9ad90e0d05be7e8359c6af66be94c094),
the `$sanitize` service will now also remove instances of the `usemap` attribute from any elements
passed to it. This attribute is used to reference another element by `name` or `id`. Since the
`name` and `id` attributes are already blacklisted, a sanitized `usemap` attribute could only
reference unsanitized content, which is a security risk.
Due to [98c2db7f](https://github.com/angular/angular.js/commit/98c2db7f9c2d078a408576e722407d518c7ee10a),
passing a non-string value (other than `undefined` or `null`) through the `linky` filter will throw
an error. This is not expected to have any significant impact on applications, since the input was
always assumed to be of type 'string', so passing non-string values never worked correctly anyway.
The main difference is that now it will fail faster and with a more informative error message.
## ngTouch (`ngClick`)
Due to [0dfc1dfe](https://github.com/angular/angular.js/commit/0dfc1dfebf26af7f951f301c4e3848ac46f05d7f),
the `ngClick` override directive from the `ngTouch` module is **deprecated and disabled by default**.
This means that on touch-based devices, users might now experience a 300ms delay before a click
event is fired.
If you rely on this directive, you can still enable it using
`$touchProvider.ngClickOverrideEnabled()`:
```js
angular.module('myApp').config(function($touchProvider) {
$touchProvider.ngClickOverrideEnabled(true);
});
```
Going forward, we recommend using [FastClick](https://github.com/ftlabs/fastclick) or perhaps one of
the [Angular 3rd party touch-related modules](http://ngmodules.org/tags/touch) that provide similar
functionality.
Also note that modern browsers already remove the 300ms delay under some circumstances:
- **Chrome and Firefox for Android** remove the 300ms delay when the well-known
`<meta name="viewport" content="width=device-width">` is set.
- **Internet Explorer** removes the delay, when the `touch-action` css property is set to `none` or
`manipulation`.
- Since **iOS 8, Safari** removes the delay on so-called "slow taps".
For more info on the topic, you can take a look at this
[article by Telerik](http://developer.telerik.com/featured/300-ms-click-delay-ios-8/).
<div class="alert alert-warning">
**Note:** This change does **not** affect the `ngSwipe` directive.
</div>
## Migrating from 1.3 to 1.4
# Migrating from 1.3 to 1.4
Angular 1.4 fixes major animation issues and introduces a new API for `ngCookies`. Further, there
are changes to `ngMessages`, `$compile`, `ngRepeat`, `ngOptions `and some fixes to core filters:
@@ -266,7 +37,7 @@ relatively straightforward otherwise.
### Animation (`ngAnimate`)
## Animation (`ngAnimate`)
Animations in 1.4 have been refactored internally, but the API has stayed much the same. There are, however,
some breaking changes that need to be addressed when upgrading to 1.4.
@@ -365,9 +136,9 @@ class based animations (animations triggered via ngClass) in order to ensure tha
### Forms (`ngMessages`, `ngOptions`, `select`)
## Forms (`ngMessages`, `ngOptions`, `select`)
#### ngMessages
### ngMessages
The ngMessages module has also been subject to an internal refactor to allow it to be more flexible
and compatible with dynamic message data. The `ngMessage` directive now supports a new attribute
called `ng-message-exp` which will evaluate an expression and will keep track of that expression
@@ -418,7 +189,7 @@ ctrl.getMessages = function($index) {
}
```
#### ngOptions
### ngOptions
The `ngOptions` directive has also been refactored and as a result some long-standing bugs
have been fixed. The breaking changes are comparatively minor and should not affect most applications.
@@ -442,7 +213,7 @@ setting the ngOptions attribute expression after the element is compiled, will n
This worked previously because the ngOptions logic was part of the select directive, while
it is now implemented in the ngOptions directive itself.
#### select
### select
Due to [7fda214c](https://github.com/angular/angular.js/commit/7fda214c4f65a6a06b25cf5d5aff013a364e9cef),
the `select` directive will now use strict comparison of the `ngModel` scope value against `option`
@@ -473,50 +244,9 @@ ngModelCtrl.$formatters.push(function(value) {
});
```
## Templating (`ngRepeat`, `$compile`)
### form
Due to [94533e57](https://github.com/angular/angular.js/commit/94533e570673e6b2eb92073955541fa289aabe02),
the `name` attribute of `form` elements can now only contain characters that can be evaluated as part
of an Angular expression. This is because Angular uses the value of `name` as an assignable expression
to set the form on the `$scope`. For example, `name="myForm"` assigns the form to `$scope.myForm` and
`name="myObj.myForm"` assigns it to `$scope.myObj.myForm`.
Previously, it was possible to also use names such `name="my:name"`, because Angular used a special setter
function for the form name. Now the general, more robust `$parse` setter is used.
The easiest way to migrate your code is therefore to remove all special characters from the `name` attribute.
If you need to keep the special characters, you can use the following directive, which will replace
the `name` with a value that can be evaluated as an expression in the compile function, and then
re-set the original name in the postLink function. This ensures that (1), the form is published on
the scope, and (2), the form has the original name, which might be important if you are doing server-side
form submission.
```js
angular.module('myApp').directive('form', function() {
return {
restrict: 'E',
priority: 1000,
compile: function(element, attrs) {
var unsupportedCharacter = ':'; // change accordingly
var originalName = attrs.name;
if (attrs.name && attrs.name.indexOf(unsupportedCharacter) > 0) {
attrs.$set('name', 'this["' + originalName + '"]');
}
return postLinkFunction(scope, element) {
// Don't trigger $observers
element.setAttribute('name', originalName);
}
}
};
});
```
### Templating (`ngRepeat`, `$compile`)
#### ngRepeat
### ngRepeat
Due to [c260e738](https://github.com/angular/angular.js/commit/c260e7386391877625eda086480de73e8a0ba921),
previously, the order of items when using ngRepeat to iterate over object properties was guaranteed to be consistent
@@ -535,7 +265,7 @@ https://github.com/petebacondarwin/angular-toArrayFilter
or some other mechanism, and then sort them manually in the order you need.
#### $compile
### $compile
Due to [6a38dbfd](https://github.com/angular/angular.js/commit/6a38dbfd3c34c8f9efff503d17eb3cbeb666d422),
previously, '&' expressions would always set up a function in the isolate scope. Now, if the binding
@@ -546,7 +276,7 @@ returning an object from a controller constructor function will now override the
controllerAs method will no longer get the this reference, but the returned object.
### Cookies (`ngCookies`)
## Cookies (`ngCookies`)
Due to [38fbe3ee](https://github.com/angular/angular.js/commit/38fbe3ee8370fc449b82d80df07b5c2ed2cd5fbe),
`$cookies` will no longer expose properties that represent the current browser cookie
@@ -585,7 +315,7 @@ delegates calls.
### Server Requests (`$http`)
## Server Requests (`$http`)
Due to [5da1256](https://github.com/angular/angular.js/commit/5da1256fc2812d5b28fb0af0de81256054856369),
`transformRequest` functions can no longer modify request headers.
@@ -618,9 +348,9 @@ $http.get(url, {
### Filters (`filter`, `limitTo`)
## Filters (`filter`, `limitTo`)
#### `filter` filter
### `filter` filter
Due to [cea8e751](https://github.com/angular/angular.js/commit/cea8e75144e6910b806b63a6ec2a6d118316fddd),
the `filter` filter will throw an error when used with a non-array. Beforehand it would silently
return an empty array.
@@ -628,7 +358,7 @@ return an empty array.
If necessary, this can be worked around by converting an object to an array,
using a filter such as https://github.com/petebacondarwin/angular-toArrayFilter.
#### `limitTo` filter
### `limitTo` filter
Due to [a3c3bf33](https://github.com/angular/angular.js/commit/a3c3bf3332e5685dc319c46faef882cb6ac246e1),
the limitTo filter has changed behavior when the provided limit value is invalid.
Now, instead of returning empty object/array, it returns unchanged input.
@@ -637,9 +367,9 @@ Now, instead of returning empty object/array, it returns unchanged input.
## Migrating from 1.2 to 1.3
# Migrating from 1.2 to 1.3
### Controllers
## Controllers
Due to [3f2232b5](https://github.com/angular/angular.js/commit/3f2232b5a181512fac23775b1df4a6ebda67d018),
`$controller` will no longer look for controllers on `window`.
@@ -677,7 +407,7 @@ angular.module('myModule').config(['$controllerProvider', function($controllerPr
}]);
```
### Angular Expression Parsing (`$parse` + `$interpolate`)
## Angular Expression Parsing (`$parse` + `$interpolate`)
- due to [77ada4c8](https://github.com/angular/angular.js/commit/77ada4c82d6b8fc6d977c26f3cdb48c2f5fbe5a5),
@@ -735,7 +465,7 @@ expression parser; there are six of them: false, null, undefined, NaN, 0 and "".
### Miscellaneous Angular helpers
## Miscellaneous Angular helpers
- **Angular.copy:** due to [b59b04f9](https://github.com/angular/angular.js/commit/b59b04f98a0b59eead53f6a53391ce1bbcbe9b57),
@@ -766,14 +496,15 @@ This change also makes our forEach behave more like Array#forEach.
- **angular.toJson:** due to [c054288c](https://github.com/angular/angular.js/commit/c054288c9722875e3595e6e6162193e0fb67a251),
`toJson()` will no longer strip properties starting with a single `$`. If you relied on
`toJson()`'s stripping these types of properties before, you will have to do it manually now.
It will still strip properties starting with `$$` though.
If you expected `toJson` to strip these types of properties before, you will have to
manually do this yourself now.
### jqLite / JQuery
## jqLite / JQuery
- **jqLite:** due to [a196c8bc](https://github.com/angular/angular.js/commit/a196c8bca82a28c08896d31f1863cf4ecd11401c),
previously it was possible to set jqLite data on Text/Comment
@@ -789,7 +520,7 @@ jQuery. We don't expect that app code actually depends on this accidental featur
### Angular HTML Compiler (`$compile`)
## Angular HTML Compiler (`$compile`)
- due to [2ee29c5d](https://github.com/angular/angular.js/commit/2ee29c5da81ffacdc1cabb438f5d125d5e116cb9),
@@ -886,7 +617,7 @@ link: function(scope, element, attr) {
### Forms, Inputs and ngModel
## Forms, Inputs and ngModel
- due to [1be9bb9d](https://github.com/angular/angular.js/commit/1be9bb9d3527e0758350c4f7417a4228d8571440),
@@ -966,7 +697,7 @@ $scope.resetWithCancel = function (e) {
See [c90cefe1614](https://github.com/angular/angular.js/commit/c90cefe16142d973a123e945fc9058e8a874c357)
### Scopes and Digests (`$scope`)
## Scopes and Digests (`$scope`)
- due to [8c6a8171](https://github.com/angular/angular.js/commit/8c6a8171f9bdaa5cdabc0cc3f7d3ce10af7b434d),
Scope#$id is now of type number rather than string. Since the
@@ -986,7 +717,7 @@ anyone.
### Server Requests (`$http`, `$resource`)
## Server Requests (`$http`, `$resource`)
- **$http:** due to [ad4336f9](https://github.com/angular/angular.js/commit/ad4336f9359a073e272930f8f9bcd36587a8648f),
@@ -1053,7 +784,7 @@ More details on the new interceptors API (which has been around as of v1.1.4) ca
### Modules and Injector (`$inject`)
## Modules and Injector (`$inject`)
- due to [c0b4e2db](https://github.com/angular/angular.js/commit/c0b4e2db9cbc8bc3164cedc4646145d3ab72536e),
@@ -1095,7 +826,7 @@ app. This is no longer possible within a single module.
### Animation (`ngAnimate`)
## Animation (`ngAnimate`)
- due to [1cb8584e](https://github.com/angular/angular.js/commit/1cb8584e8490ecdb1b410a8846c4478c6c2c0e53),
@@ -1117,7 +848,7 @@ to:
Any class-based animation code that makes use of transitions
and uses the setup CSS classes (such as class-add and class-remove) must now
provide an empty transition value to ensure that its styling is applied right
provide a empty transition value to ensure that its styling is applied right
away. In other words if your animation code is expecting any styling to be
applied that is defined in the setup class then it will not be applied
"instantly" unless a `transition:0s none` value is present in the styling
@@ -1148,7 +879,7 @@ After:
Please view the documentation for ngAnimate for more info.
### Testing
## Testing
- due to [85880a64](https://github.com/angular/angular.js/commit/85880a64900fa22a61feb926bf52de0965332ca5), some deprecated features of
Protractor tests no longer work.
@@ -1187,7 +918,7 @@ or simply use:
var el = element(by.repeater('foo in foos').row(2))
### Internet Explorer 8
## Internet Explorer 8
- due to [eaa1d00b](https://github.com/angular/angular.js/commit/eaa1d00b24008f590b95ad099241b4003688cdda),
As communicated before, IE8 is no longer supported.
@@ -1197,7 +928,7 @@ or simply use:
## Migrating from 1.0 to 1.2
# Migrating from 1.0 to 1.2
<div class="alert alert-warning">
@@ -1240,7 +971,7 @@ below should still apply, but you may want to consult the
</ul>
### ngRoute has been moved into its own module
## ngRoute has been moved into its own module
Just like `ngResource`, `ngRoute` is now its own module.
@@ -1271,7 +1002,7 @@ var myApp = angular.module('myApp', ['ngRoute', 'someOtherModule']);
See [5599b55b](https://github.com/angular/angular.js/commit/5599b55b04788c2e327d7551a4a699d75516dd21).
### Templates no longer automatically unwrap promises
## Templates no longer automatically unwrap promises
`$parse` and templates in general will no longer automatically unwrap promises.
@@ -1305,7 +1036,7 @@ See [5dc35b52](https://github.com/angular/angular.js/commit/5dc35b527b3c99f6544b
[b6a37d11](https://github.com/angular/angular.js/commit/b6a37d112b3e1478f4d14a5f82faabf700443748).
### Syntax for named wildcard parameters changed in `$route`
## Syntax for named wildcard parameters changed in `$route`
To migrate the code, follow the example below. Here, `*highlight` becomes `:highlight*`
@@ -1326,7 +1057,7 @@ $routeProvider.when('/Book1/:book/Chapter/:chapter/:highlight*/edit',
See [04cebcc1](https://github.com/angular/angular.js/commit/04cebcc133c8b433a3ac5f72ed19f3631778142b).
### You can only bind one expression to `*[src]`, `*[ng-src]` or `action`
## You can only bind one expression to `*[src]`, `*[ng-src]` or `action`
With the exception of `<a>` and `<img>` elements, you cannot bind more than one expression to the
`src` or `action` attribute of elements.
@@ -1401,7 +1132,7 @@ scope.getIframeSrc = function() {
See [38deedd6](https://github.com/angular/angular.js/commit/38deedd6e3d806eb8262bb43f26d47245f6c2739).
### Interpolations inside DOM event handlers are now disallowed
## Interpolations inside DOM event handlers are now disallowed
DOM event handlers execute arbitrary Javascript code. Using an interpolation for such handlers
means that the interpolated value is a JS string that is evaluated. Storing or generating such
@@ -1428,7 +1159,7 @@ HTML: <div ng-click="foo()">
See [39841f2e](https://github.com/angular/angular.js/commit/39841f2ec9b17b3b2920fd1eb548d444251f4f56).
### Directives cannot end with -start or -end
## Directives cannot end with -start or -end
This change was necessary to enable multi-element directives. The best fix is to rename existing
directives so that they don't end with these suffixes.
@@ -1436,7 +1167,7 @@ directives so that they don't end with these suffixes.
See [e46100f7](https://github.com/angular/angular.js/commit/e46100f7097d9a8f174bdb9e15d4c6098395c3f2).
### In $q, promise.always has been renamed promise.finally
## In $q, promise.always has been renamed promise.finally
The reason for this change is to align `$q` with the [Q promise
library](https://github.com/kriskowal/q), despite the fact that this makes it a bit more difficult
@@ -1468,7 +1199,7 @@ $http.get('/foo')['finally'](doSomething);
See [f078762d](https://github.com/angular/angular.js/commit/f078762d48d0d5d9796dcdf2cb0241198677582c).
### ngMobile is now ngTouch
## ngMobile is now ngTouch
Many touch-enabled devices are not mobile devices, so we decided to rename this module to better
reflect its concerns.
@@ -1479,7 +1210,7 @@ To migrate, replace all references to `ngMobile` with `ngTouch` and `angular-mob
See [94ec84e7](https://github.com/angular/angular.js/commit/94ec84e7b9c89358dc00e4039009af9e287bbd05).
### resource.$then has been removed
## resource.$then has been removed
Resource instances do not have a `$then` function anymore. Use the `$promise.then` instead.
@@ -1498,7 +1229,7 @@ Resource.query().$promise.then(callback);
See [05772e15](https://github.com/angular/angular.js/commit/05772e15fbecfdc63d4977e2e8839d8b95d6a92d).
### Resource methods return the promise
## Resource methods return the promise
Methods of a resource instance return the promise rather than the instance itself.
@@ -1518,7 +1249,7 @@ resource.chaining = true;
See [05772e15](https://github.com/angular/angular.js/commit/05772e15fbecfdc63d4977e2e8839d8b95d6a92d).
### Resource promises are resolved with the resource instance
## Resource promises are resolved with the resource instance
On success, the resource promise is resolved with the resource instance rather than HTTP response object.
@@ -1549,7 +1280,7 @@ var Resource = $resource('/url', {}, {
See [05772e15](https://github.com/angular/angular.js/commit/05772e15fbecfdc63d4977e2e8839d8b95d6a92d).
### $location.search supports multiple keys
## $location.search supports multiple keys
{@link ng.$location#search `$location.search`} now supports multiple keys with the
same value provided that the values are stored in an array.
@@ -1566,7 +1297,7 @@ passing it to `$location`.
See [80739409](https://github.com/angular/angular.js/commit/807394095b991357225a03d5fed81fea5c9a1abe).
### ngBindHtmlUnsafe has been removed and replaced by ngBindHtml
## ngBindHtmlUnsafe has been removed and replaced by ngBindHtml
`ngBindHtml` provides `ngBindHtmlUnsafe` like
behavior (evaluate an expression and innerHTML the result into the DOM) when bound to the result
@@ -1582,7 +1313,7 @@ trusted.
See [dae69473](https://github.com/angular/angular.js/commit/dae694739b9581bea5dbc53522ec00d87b26ae55).
### Form names that are expressions are evaluated
## Form names that are expressions are evaluated
If you have form names that will evaluate as an expression:
@@ -1614,7 +1345,7 @@ Supporting the previous behavior offers no benefit.
See [8ea802a1](https://github.com/angular/angular.js/commit/8ea802a1d23ad8ecacab892a3a451a308d9c39d7).
### hasOwnProperty disallowed as an input name
## hasOwnProperty disallowed as an input name
Inputs with name equal to `hasOwnProperty` are not allowed inside form or ngForm directives.
@@ -1625,7 +1356,7 @@ and bad practice. To migrate, change your input name.
See [7a586e5c](https://github.com/angular/angular.js/commit/7a586e5c19f3d1ecc3fefef084ce992072ee7f60).
### Directives: Order of postLink functions reversed
## Directives: Order of postLink functions reversed
The order of postLink fn is now mirror opposite of the order in which corresponding preLinking and compile functions execute.
@@ -1681,7 +1412,7 @@ attribute interpolation directive was adjusted.
See [31f190d4](https://github.com/angular/angular.js/commit/31f190d4d53921d32253ba80d9ebe57d6c1de82b).
### Directive priority
## Directive priority
the priority of ngRepeat, ngSwitchWhen, ngIf, ngInclude and ngView has changed. This could affect directives that explicitly specify their priority.
@@ -1699,7 +1430,7 @@ ngView | 1000 | 400
See [b7af76b4](https://github.com/angular/angular.js/commit/b7af76b4c5aa77648cc1bfd49935b48583419023).
### ngScenario
## ngScenario
browserTrigger now uses an eventData object instead of direct parameters for mouse events.
To migrate, place the `keys`,`x` and `y` parameters inside of an object and place that as the
@@ -1708,7 +1439,7 @@ third parameter for the browserTrigger function.
See [28f56a38](https://github.com/angular/angular.js/commit/28f56a383e9d1ff378e3568a3039e941c7ffb1d8).
### ngInclude and ngView replace its entire element on update
## ngInclude and ngView replace its entire element on update
Previously `ngInclude` and `ngView` only updated its element's content. Now these directives will
recreate the element every time a new content is included.
@@ -1720,7 +1451,7 @@ See [7d69d52a](https://github.com/angular/angular.js/commit/7d69d52acff8578e0f7d
[aa2133ad](https://github.com/angular/angular.js/commit/aa2133ad818d2e5c27cbd3933061797096356c8a).
### URLs are now sanitized against a whitelist
## URLs are now sanitized against a whitelist
A whitelist configured via `$compileProvider` can be used to configure what URLs are considered safe.
By default all common protocol prefixes are whitelisted including `data:` URIs with mime types `image/*`.
@@ -1730,7 +1461,7 @@ See [1adf29af](https://github.com/angular/angular.js/commit/1adf29af13890d612868
[3e39ac7e](https://github.com/angular/angular.js/commit/3e39ac7e1b10d4812a44dad2f959a93361cd823b).
### Isolate scope only exposed to directives with `scope` property
## Isolate scope only exposed to directives with `scope` property
If you declare a scope option on a directive, that directive will have an
[isolate scope](https://github.com/angular/angular.js/wiki/Understanding-Scopes). In Angular 1.0, if a
@@ -1803,7 +1534,7 @@ See [909cabd3](https://github.com/angular/angular.js/commit/909cabd36d779598763c
[#2500](https://github.com/angular/angular.js/issues/2500).
### Change to interpolation priority
## Change to interpolation priority
Previously, the interpolation priority was `-100` in 1.2.0-rc.2, and `100` before 1.2.0-rc.2.
Before this change the binding was setup in the post-linking phase.
@@ -1816,7 +1547,7 @@ See [79223eae](https://github.com/angular/angular.js/commit/79223eae502283889334
[#4528](https://github.com/angular/angular.js/issues/4528), and
[#4649](https://github.com/angular/angular.js/issues/4649)
### Underscore-prefixed/suffixed properties are non-bindable
## Underscore-prefixed/suffixed properties are non-bindable
<div class="alert alert-info">
<p>**Reverted**: This breaking change has been reverted in 1.2.1, and so can be ignored if you're using **version 1.2.1 or higher**</p>
@@ -1855,7 +1586,7 @@ are actually needed by the expressions.
See [3d6a89e8](https://github.com/angular/angular.js/commit/3d6a89e8888b14ae5cb5640464e12b7811853c7e).
### You cannot bind to select[multiple]
## You cannot bind to select[multiple]
Switching between `select[single]` and `select[multiple]` has always been odd due to browser quirks.
This feature never worked with two-way data-binding so it's not expected that anyone is using it.
@@ -1865,7 +1596,7 @@ If you are interested in properly adding this feature, please submit a pull requ
See [d87fa004](https://github.com/angular/angular.js/commit/d87fa0042375b025b98c40bff05e5f42c00af114).
### Uncommon region-specific local files were removed from i18n
## Uncommon region-specific local files were removed from i18n
AngularJS uses the Google Closure library's locale files. The following locales were removed from
Closure, so Angular is not able to continue to support them:
@@ -1881,7 +1612,7 @@ load and use your copy of the locale file provided that you maintain it yourself
See [6382e21f](https://github.com/angular/angular.js/commit/6382e21fb28541a2484ac1a241d41cf9fbbe9d2c).
### Services can now return functions
## Services can now return functions
Previously, the service constructor only returned objects regardless of whether a function was returned.
+3 -2
View File
@@ -75,8 +75,9 @@ that you break your application to multiple modules like this:
* And an application level module which depends on the above modules and contains any
initialization code.
You can find a community
[style guide](https://github.com/johnpapa/angular-styleguide) to help yourself when application grows.
We've also
[written a document](http://angularjs.blogspot.com/2014/02/an-angularjs-style-guide-and-best.html)
on how we organize large apps at Google.
The above is a suggestion. Tailor it to your needs.
+10 -75
View File
@@ -9,27 +9,6 @@ This document explains some of AngularJS's security features and best practices
keep in mind as you build your application.
## Reporting a security issue
Email us at [security@angularjs.org](mailto:security@angularjs.org) to report any potential
security issues in AngularJS.
Please keep in mind the points below about Angular's expression language.
## Use the latest AngularJS possible
Like any software library, it is critical to keep AngularJS up to date. Please track the
[CHANGELOG](https://github.com/angular/angular.js/blob/master/CHANGELOG.md) and make sure you are aware
of upcoming security patches and other updates.
Be ready to update rapidly when new security-centric patches are available.
Those that stray from Angular standards (such as modifying Angular's core) may have difficulty updating,
so keeping to AngularJS standards is not just a functionality issue, it's also critical in order to
facilitate rapid security updates.
## Expression Sandboxing
AngularJS's expressions are sandboxed not for security reasons, but instead to maintain a proper
@@ -46,8 +25,7 @@ But if an attacker can change arbitrary HTML templates, there's nothing stopping
<script>somethingEvil();</script>
```
**It's better to design your application in such a way that users cannot change client-side templates.**
It's better to design your application in such a way that users cannot change client-side templates.
For instance:
* Do not mix client and server templates
@@ -55,8 +33,7 @@ For instance:
* Do not run user input through `$scope.$eval`
* Consider using {@link ng.directive:ngCsp CSP} (but don't rely only on CSP)
### Mixing client-side and server-side templates
## Mixing client-side and server-side templates
In general, we recommend against this because it can create unintended XSS vectors.
@@ -64,62 +41,20 @@ However, it's ok to mix server-side templating in the bootstrap template (`index
as user input cannot be used on the server to output html that would then be processed by Angular
in a way that would allow for arbitrary code execution.
**For instance, you can use server-side templating to dynamically generate CSS, URLs, etc, but not
for generating templates that are bootstrapped/compiled by Angular.**
For instance, you can use server-side templating to dynamically generate CSS, URLs, etc, but not
for generating templates that are bootstrapped/compiled by Angular.
## HTTP Requests
## Reporting a security issue
Whenever your application makes requests to a server there are potential security issues that need
to be blocked. Both server and the client must cooperate in order to eliminate these threats.
Angular comes pre-configured with strategies that address these issues, but for this to work backend
server cooperation is required.
Email us at [security@angularjs.org](mailto:security@angularjs.org) to report any potential
security issues in AngularJS.
Please keep in mind the above points about Angular's expression language.
### Cross Site Request Forgery (XSRF/CSRF)
Protection from XSRF is provided by using the double-submit cookie defense pattern.
For more information please visit {@link $http#cross-site-request-forgery-xsrf-protection XSRF protection}.
### JSON Hijacking Protection
Protection from JSON Hijacking is provided if the server prefixes all JSON requests with following string `")]}',\n"`.
Angular will automatically strip the prefix before processing it as JSON.
For more information please visit {@link $http#json-vulnerability-protection JSON Hijacking Protection}.
## Strict Contextual Escaping
Strict Contextual Escaping (SCE) is a mode in which AngularJS requires bindings in certain contexts to require
a value that is marked as safe to use for that context.
This mode is implemented by the {@link $sce} service and various core directives.
One example of such a context is rendering arbitrary content via the {@link ngBindHtml} directive. If the content is
provided by a user there is a chance of Cross Site Scripting (XSS) attacks. The {@link ngBindHtml} directive will not
render content that is not marked as safe by {@link $sce}. The {@link ngSanitize} module can be used to clean such
user provided content and mark the content as safe.
**Be aware that marking untrusted data as safe via calls to {@link $sce#trustAsHtml `$sce.trustAsHtml`}, etc is
dangerous and will lead to Cross Site Scripting exploits.**
For more information please visit {@link $sce} and {@link ngSanitize.$sanitize}.
## Using Local Caches
There are various places that the browser can store (or cache) data. Within Angular there are objects created by
the {@link $cacheFactory}. These objects, such as {@link $templateCache} are used to store and retrieve data,
primarily used by {@link $http} and the {@link script} directive to cache templates and other data.
Similarly the browser itself offers `localStorage` and `sessionStorage` objects for caching data.
**Attackers with local access can retrieve sensitive data from this cache even when users are not authenticated.**
For instance in a long running Single Page Application (SPA), one user may "log out", but then another user
may access the application without refreshing, in which case all the cached data is still available.
For more information please visit [Web Storage Security](https://www.whitehatsec.com/blog/web-storage-security/).
## See also
* {@link ng.directive:ngCsp Content Security Policy}
* {@link ng.$sce Strict Contextual Escaping}
* {@link ngSanitize.$sanitize $sanitize}
+4 -8
View File
@@ -43,7 +43,7 @@ subsystem takes care of the rest.
<file name="script.js">
angular.
module('myServiceModule', []).
controller('MyController', ['$scope', 'notify', function ($scope, notify) {
controller('MyController', ['$scope','notify', function ($scope, notify) {
$scope.callNotify = function(msg) {
notify(msg);
};
@@ -138,13 +138,9 @@ batchModule.factory('batchLog', ['$interval', '$log', function($interval, $log)
*/
batchModule.factory('routeTemplateMonitor', ['$route', 'batchLog', '$rootScope',
function($route, batchLog, $rootScope) {
return {
startMonitoring: function() {
$rootScope.$on('$routeChangeSuccess', function() {
batchLog($route.current ? $route.current.template : null);
});
}
};
$rootScope.$on('$routeChangeSuccess', function() {
batchLog($route.current ? $route.current.template : null);
});
}]);
```
-2
View File
@@ -3,8 +3,6 @@
@sortOrder 260
@description
# Templates
In Angular, templates are written with HTML that contains Angular-specific elements and attributes.
Angular combines the template with information from the model and controller to render the dynamic
view that a user sees in the browser.
+6 -51
View File
@@ -6,7 +6,7 @@
JavaScript is a dynamically typed language which comes with great power of expression, but it also
comes with almost no help from the compiler. For this reason we feel very strongly that any code
written in JavaScript needs to come with a strong set of tests. We have built many features into
Angular which make testing your Angular applications easy. With Angular, there is no excuse for not testing.
Angular which makes testing your Angular applications easy. So there is no excuse for not testing.
## Separation of Concerns
@@ -20,13 +20,13 @@ related pieces such as the DOM elements, or making any XHR calls to fetch the da
While this may seem obvious it can be very difficult to call an individual function on a
typical project. The reason is that the developers often mix concerns resulting in a
piece of code which does everything. It makes an XHR request, it sorts the response data, and then it
piece of code which does everything. It makes an XHR request, it sorts the response data and then it
manipulates the DOM.
With Angular, we try to make it easy for you to do the right thing. For your XHR requests, we
provide dependency injection, so your requests can be simulated. For the DOM, we abstract it, so you can
test your model without having to manipulate the DOM directly. Your tests can then
assert that the data has been sorted without having to create or look at the state of the DOM or to
With Angular we try to make it easy for you to do the right thing, and so we
provide dependency injection for your XHR requests, which can be mocked, and we provide abstractions which
allow you to test your model without having to resort to manipulating the DOM. The test can then
assert that the data has been sorted without having to create or look at the state of the DOM or
wait for any XHR requests to return data. The individual sort function can be tested in isolation.
## With great power comes great responsibility
@@ -430,50 +430,5 @@ If your directive uses `templateUrl`, consider using
to pre-compile HTML templates and thus avoid having to load them over HTTP during test execution.
Otherwise you may run into issues if the test directory hierarchy differs from the application's.
## Testing Promises
When testing promises, it's important to know that the resolution of promises is tied to the {@link ng.$rootScope.Scope#$digest digest cycle}.
That means a promise's `then`, `catch` and `finally` callback functions are only called after a digest has run.
In tests, you can trigger a digest by calling a scope's {@link ng.$rootScope.Scope#$apply `$apply` function}.
If you don't have a scope in your test, you can inject the {@link ng.$rootScope $rootScope} and call `$apply` on it.
There is also an example of testing promises in the {@link ng.$q#testing `$q` service documentation}.
## Using `beforeAll()`
Jasmine's `beforeAll()` and mocha's `before()` hooks are often useful for sharing test setup - either to reduce test run-time or simply to make for more focussed test cases.
By default, ngMock will create an injector per test case to ensure your tests do not affect each other. However, if we want to use `beforeAll()`, ngMock will have to create the injector before any test cases are run, and share that injector through all the cases for that `describe`. That is where {@link angular.mock.module.sharedInjector module.sharedInjector()} comes in. When it's called within a `describe` block, a single injector is shared between all hooks and test cases run in that block.
In the example below we are testing a service that takes a long time to generate its answer. To avoid having all of the assertions we want to write in a single test case, {@link angular.mock.module.sharedInjector module.sharedInjector()} and Jasmine's `beforeAll()` are used to run the service only once. The test cases then all make assertions about the properties added to the service instance.
```javascript
describe("Deep Thought", function() {
module.sharedInjector();
beforeAll(module("UltimateQuestion"));
beforeAll(inject(function(DeepThought) {
expect(DeepThought.answer).toBeUndefined();
DeepThought.generateAnswer();
}));
it("has calculated the answer correctly", inject(function(DeepThought) {
// Because of sharedInjector, we have access to the instance of the DeepThought service
// that was provided to the beforeAll() hook. Therefore we can test the generated answer
expect(DeepThought.answer).toBe(42);
}));
it("has calculated the answer within the expected time", inject(function(DeepThought) {
expect(DeepThought.runTimeMillennia).toBeLessThan(8000);
}));
it("has double checked the answer", inject(function(DeepThought) {
expect(DeepThought.absolutelySureItIsTheRightAnswer).toBe(true);
}));
});
```
## Sample project
See the [angular-seed](https://github.com/angular/angular-seed) project for an example.
+1 -1
View File
@@ -46,7 +46,7 @@ Download the version you want and have fun.
Each directory under <http://code.angularjs.org/> includes the following set of files:
* __`angular.js`__ — This file is non-obfuscated, non-minified, and human-readable by
opening it in any editor or browser. In order to get better error messages during development, you
opening it it any editor or browser. In order to get better error messages during development, you
should always use this non-minified angular script.
* __`angular.min.js`__ — This is a minified and obfuscated version of
-10
View File
@@ -246,15 +246,6 @@ npm run update-webdriver
*(You should only need to do this once.)*
You will need to have Java present on your dev machine to allow the Selenium standalone to be started.
Check if you already have java installed by opening a terminal/command line window and typing
'''
java -version
'''
If java is already installed and exists in the PATH then you will be shown the version installed,
if, however you receive a message that "java is not recognized as an internal command or external
command" you will need to install [java].
Since Protractor works by interacting with a running application, we need to start our web server:
```
@@ -289,4 +280,3 @@ Now that you have set up your local machine, let's get started with the tutorial
[bower]: http://bower.io/
[http-server]: https://github.com/nodeapps/http-server
[karma]: https://github.com/karma-runner/karma
[java]: https://www.java.com/en/download/help/download_options.xml
+1 -1
View File
@@ -43,7 +43,7 @@ __`app/index.html`:__
...
<ul class="phones">
<li ng-repeat="phone in phones | filter:query | orderBy:orderProp" class="thumbnail">
<a href="#/phones/{{phone.id}}" class="thumb"><img ng-src="{{phone.imageUrl}}" alt="{{phone.name}}"></a>
<a href="#/phones/{{phone.id}}" class="thumb"><img ng-src="{{phone.imageUrl}}"></a>
<a href="#/phones/{{phone.id}}">{{phone.name}}</a>
<p>{{phone.snippet}}</p>
</li>
-12
View File
@@ -53,18 +53,6 @@ preconfigured npm to run bower install for us:
npm install
```
<div class="alert alert-warning">
**Warning:** If a new version of Angular has been released since you last ran `npm install`, then you may have a
problem with the `bower install` due to a conflict between the versions of angular.js that need to
be installed. If you get this then simply delete your `app/bower_components` folder before running
`npm install`.
</div>
<div class="alert alert-info">
**Note:** If you have bower installed globally then you can run `bower install` but for this project we have
preconfigured `npm install` to run bower for us.
</div>
## Multiple Views, Routing and Layout Template
+4 -4
View File
@@ -239,7 +239,7 @@ The name of the starting class is the name of the event that is fired (like `ent
The active class name is the same as the starting class's but with an `-active` suffix.
This two-class CSS naming convention allows the developer to craft an animation, beginning to end.
In our example above, elements are expanded from a height of **0** to **120 pixels** when they're added to the
In our example above, elements are expanded from a height of **0** to **120 pixels** when they're added to the
list and are collapsed back down to **0 pixels** before being removed from the list.
There's also a nice fade-in and fade-out effect that occurs at the same time. All of this is handled
by the CSS transition declarations at the top of the example code above.
@@ -357,10 +357,10 @@ For more on CSS animations, see the
## Animating `ngClass` with JavaScript
Let's add another animation to our application. Switching to our `phone-detail.html` page,
we see that we have a nice thumbnail swapper. By hovering over the thumbnails listed on the page,
we see that we have a nice thumbnail swapper. By clicking on the thumbnails listed on the page,
the profile phone image changes. But how can we change this around to add animations?
Let's think about it first. Basically, when you hover over a thumbnail image, you're changing the
Let's think about it first. Basically, when you click on a thumbnail image, you're changing the
state of the profile image to reflect the newly selected thumbnail image.
The best way to specify state changes within HTML is to use classes.
Much like before, how we used a CSS class to specify an animation, this time the animation will
@@ -369,7 +369,7 @@ occur whenever the CSS class itself changes.
Whenever a new phone thumbnail is selected, the state changes and the `.active` CSS class is added
to the matching profile image and the animation plays.
Let's get started and tweak our HTML code on the `phone-detail.html` page first. Notice that we
Let's get started and tweak our HTML code on the `phone-detail.html` page first. Notice that we
have changed the way we display our large image:
__`app/partials/phone-detail.html`.__
File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 73 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 39 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 KiB

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

+1 -1
View File
@@ -20,7 +20,7 @@
* using the --for_closure flag.
* File generated from CLDR ver. 27.0.1
*
* This file covers those locales that are not covered in
* This file coveres those locales that are not covered in
* "numberformatsymbols.js".
*
* Before checkin, this file could have been manually edited. This is
+1 -1
View File
@@ -5,7 +5,7 @@ set -e
BASE_DIR=`dirname $0`
cd $BASE_DIR
npm run test-i18n
./run-tests.sh
node src/closureSlurper.js
+6
View File
@@ -0,0 +1,6 @@
#!/bin/bash
set -e
PARENT_DIR="$(dirname "$0")"
../node_modules/.bin/jasmine-node "$PARENT_DIR"/spec/
+66 -77
View File
@@ -4,7 +4,6 @@ findLocaleId = closureI18nExtractor.findLocaleId;
extractNumberSymbols = closureI18nExtractor.extractNumberSymbols;
extractCurrencySymbols = closureI18nExtractor.extractCurrencySymbols;
extractDateTimeSymbols = closureI18nExtractor.extractDateTimeSymbols;
outputLocale = closureI18nExtractor.outputLocale;
function newTestLocaleInfo() {
@@ -73,7 +72,7 @@ describe("findLocaleId", function() {
it("should throw an error otherwise", function() {
expect(function() {
findLocaleId("str", "otherwise")
}).toThrowError("unknown type in findLocaleId: otherwise");
}).toThrow("unknown type in findLocaleId: otherwise");
});
});
@@ -132,10 +131,7 @@ describe("extractCurrencySymbols", function() {
].join('\n');
var localeInfo = {};
var currencySymbols = extractCurrencySymbols(CONTENT);
expect(currencySymbols.GBP).toEqual([2, '£', 'GB£']);
expect(currencySymbols.AOA).toEqual([2, 'Kz', 'Kz']);
expect(currencySymbols).toEqual({
expect(extractCurrencySymbols(CONTENT)).toEqual({
'GBP':[2, '£', 'GB£'],
'AOA':[2, 'Kz', 'Kz']
});
@@ -146,71 +142,71 @@ describe("extractCurrencySymbols", function() {
describe("extractDateTimeSymbols", function() {
it("should extract date time data", function() {
var CONTENT = [
"goog.i18n.DateTimeSymbols_fr_CA = {",
" ERAS: ['av. J.-C.', 'ap. J.-C.'],",
" ERANAMES: ['avant Jésus-Christ', 'après Jésus-Christ'],",
" NARROWMONTHS: ['J', 'F', 'M', 'A', 'M', 'J', 'J', 'A', 'S', 'O', 'N', 'D'],",
" STANDALONENARROWMONTHS: ['J', 'F', 'M', 'A', 'M', 'J', 'J', 'A', 'S', 'O',",
" 'N', 'D'],",
" MONTHS: ['janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet',",
" 'août', 'septembre', 'octobre', 'novembre', 'décembre'],",
" STANDALONEMONTHS: ['janvier', 'février', 'mars', 'avril', 'mai', 'juin',",
" 'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre'],",
" SHORTMONTHS: ['janv.', 'févr.', 'mars', 'avr.', 'mai', 'juin', 'juil.',",
" 'août', 'sept.', 'oct.', 'nov.', 'déc.'],",
" STANDALONESHORTMONTHS: ['janv.', 'févr.', 'mars', 'avr.', 'mai', 'juin',",
" 'juil.', 'août', 'sept.', 'oct.', 'nov.', 'déc.'],",
" WEEKDAYS: ['dimanche', 'lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi',",
" 'samedi'],",
" STANDALONEWEEKDAYS: ['dimanche', 'lundi', 'mardi', 'mercredi', 'jeudi',",
" 'vendredi', 'samedi'],",
" SHORTWEEKDAYS: ['dim.', 'lun.', 'mar.', 'mer.', 'jeu.', 'ven.', 'sam.'],",
" STANDALONESHORTWEEKDAYS: ['dim.', 'lun.', 'mar.', 'mer.', 'jeu.', 'ven.',",
" 'sam.'],",
" NARROWWEEKDAYS: ['D', 'L', 'M', 'M', 'J', 'V', 'S'],",
" STANDALONENARROWWEEKDAYS: ['D', 'L', 'M', 'M', 'J', 'V', 'S'],",
" SHORTQUARTERS: ['T1', 'T2', 'T3', 'T4'],",
" QUARTERS: ['1er trimestre', '2e trimestre', '3e trimestre', '4e trimestre'],",
" AMPMS: ['AM', 'PM'],",
" DATEFORMATS: ['EEEE d MMMM y', 'd MMMM y', 'yyyy-MM-dd', 'yy-MM-dd'],",
" TIMEFORMATS: ['HH \\'h\\' mm \\'min\\' ss \\'s\\' zzzz', 'HH:mm:ss z',",
" 'HH:mm:ss', 'HH:mm'],",
" FIRSTDAYOFWEEK: 6,",
" WEEKENDRANGE: [5, 6],",
" FIRSTWEEKCUTOFFDAY: 2",
"};"
"goog.i18n.DateTimeSymbols_fr_CA = {",
" ERAS: ['av. J.-C.', 'ap. J.-C.'],",
" ERANAMES: ['avant Jésus-Christ', 'après Jésus-Christ'],",
" NARROWMONTHS: ['J', 'F', 'M', 'A', 'M', 'J', 'J', 'A', 'S', 'O', 'N', 'D'],",
" STANDALONENARROWMONTHS: ['J', 'F', 'M', 'A', 'M', 'J', 'J', 'A', 'S', 'O',",
" 'N', 'D'],",
" MONTHS: ['janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet',",
" 'août', 'septembre', 'octobre', 'novembre', 'décembre'],",
" STANDALONEMONTHS: ['janvier', 'février', 'mars', 'avril', 'mai', 'juin',",
" 'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre'],",
" SHORTMONTHS: ['janv.', 'févr.', 'mars', 'avr.', 'mai', 'juin', 'juil.',",
" 'août', 'sept.', 'oct.', 'nov.', 'déc.'],",
" STANDALONESHORTMONTHS: ['janv.', 'févr.', 'mars', 'avr.', 'mai', 'juin',",
" 'juil.', 'août', 'sept.', 'oct.', 'nov.', 'déc.'],",
" WEEKDAYS: ['dimanche', 'lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi',",
" 'samedi'],",
" STANDALONEWEEKDAYS: ['dimanche', 'lundi', 'mardi', 'mercredi', 'jeudi',",
" 'vendredi', 'samedi'],",
" SHORTWEEKDAYS: ['dim.', 'lun.', 'mar.', 'mer.', 'jeu.', 'ven.', 'sam.'],",
" STANDALONESHORTWEEKDAYS: ['dim.', 'lun.', 'mar.', 'mer.', 'jeu.', 'ven.',",
" 'sam.'],",
" NARROWWEEKDAYS: ['D', 'L', 'M', 'M', 'J', 'V', 'S'],",
" STANDALONENARROWWEEKDAYS: ['D', 'L', 'M', 'M', 'J', 'V', 'S'],",
" SHORTQUARTERS: ['T1', 'T2', 'T3', 'T4'],",
" QUARTERS: ['1er trimestre', '2e trimestre', '3e trimestre', '4e trimestre'],",
" AMPMS: ['AM', 'PM'],",
" DATEFORMATS: ['EEEE d MMMM y', 'd MMMM y', 'yyyy-MM-dd', 'yy-MM-dd'],",
" TIMEFORMATS: ['HH \\'h\\' mm \\'min\\' ss \\'s\\' zzzz', 'HH:mm:ss z',",
" 'HH:mm:ss', 'HH:mm'],",
" FIRSTDAYOFWEEK: 6,",
" WEEKENDRANGE: [5, 6],",
" FIRSTWEEKCUTOFFDAY: 2",
"};"
].join('\n');
var localeInfo = {};
var expectedLocaleInfo = {
fr_CA: {
DATETIME_FORMATS: {
MONTH: ['janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet', 'août', 'septembre',
'octobre', 'novembre', 'décembre'],
STANDALONEMONTH: ['janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet',
'août', 'septembre', 'octobre', 'novembre', 'décembre'],
SHORTMONTH: ['janv.', 'févr.', 'mars', 'avr.', 'mai', 'juin', 'juil.', 'août', 'sept.', 'oct.',
'nov.', 'déc.'],
DAY: ['dimanche', 'lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi'],
SHORTDAY: ['dim.', 'lun.', 'mar.', 'mer.', 'jeu.', 'ven.', 'sam.'],
FIRSTDAYOFWEEK: 6,
WEEKENDRANGE: [5, 6],
AMPMS: ['AM', 'PM'],
ERAS: ['av. J.-C.', 'ap. J.-C.'],
ERANAMES: ['avant Jésus-Christ', 'après Jésus-Christ'],
medium: 'yyyy-MM-dd HH:mm:ss',
short: 'yy-MM-dd HH:mm',
fullDate: 'EEEE d MMMM y',
longDate: 'd MMMM y',
mediumDate: 'yyyy-MM-dd',
shortDate: 'yy-MM-dd',
mediumTime: 'HH:mm:ss',
shortTime: 'HH:mm'
var localeInfo = {};
var expectedLocaleInfo = {
fr_CA: {
DATETIME_FORMATS: {
MONTH: ['janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet', 'août', 'septembre',
'octobre', 'novembre', 'décembre'],
STANDALONEMONTH: ['janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet',
'août', 'septembre', 'octobre', 'novembre', 'décembre'],
SHORTMONTH: ['janv.', 'févr.', 'mars', 'avr.', 'mai', 'juin', 'juil.', 'août', 'sept.', 'oct.',
'nov.', 'déc.'],
DAY: ['dimanche', 'lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi'],
SHORTDAY: ['dim.', 'lun.', 'mar.', 'mer.', 'jeu.', 'ven.', 'sam.'],
FIRSTDAYOFWEEK: 6,
WEEKENDRANGE: [5, 6],
AMPMS: ['AM', 'PM'],
ERAS: ['av. J.-C.', 'ap. J.-C.'],
ERANAMES: ['avant Jésus-Christ', 'après Jésus-Christ'],
medium: 'yyyy-MM-dd HH:mm:ss',
short: 'yy-MM-dd HH:mm',
fullDate: 'EEEE d MMMM y',
longDate: 'd MMMM y',
mediumDate: 'yyyy-MM-dd',
shortDate: 'yy-MM-dd',
mediumTime: 'HH:mm:ss',
shortTime: 'HH:mm'
}
}
}
};
extractDateTimeSymbols(CONTENT, localeInfo);
expect(localeInfo).toEqual(expectedLocaleInfo);
});
};
extractDateTimeSymbols(CONTENT, localeInfo);
expect(localeInfo).toEqual(expectedLocaleInfo);
})
});
describe("pluralExtractor", function() {
@@ -272,14 +268,7 @@ describe("serializeContent", function() {
it("should not transform arrays into objects", function() {
var serializedContent = closureI18nExtractor.serializeContent(newTestLocaleInfo().fr_CA);
var deserializedLocale = eval("(" + serializedContent + ")");
expect(deserializedLocale.DATETIME_FORMATS.MONTH.length).not.toBeUndefined();
expect(deserializedLocale.DATETIME_FORMATS.MONTH.length).not.toBe(undefined);
});
});
describe("outputLocale", function() {
it("should render the correct locale ids", function() {
var output = outputLocale(newTestLocaleInfo(), 'fr_CA');
expect(output).toContain('"id": "fr-ca"');
expect(output).toContain('"localeID": "fr_CA"');
});
});
+7 -9
View File
@@ -50,10 +50,10 @@ function extractNumberSymbols(content, localeInfo, currencySymbols) {
function extractCurrencySymbols(content) {
//eval script in the current context so that we get access to all the symbols
eval(content.toString());
// var currencySymbols = goog.i18n.currency.CurrencyInfo;
// currencySymbols.__proto__ = goog.i18n.currency.CurrencyInfoTier2;
var currencySymbols = goog.i18n.currency.CurrencyInfo;
currencySymbols.__proto__ = goog.i18n.currency.CurrencyInfoTier2;
return Object.assign({}, goog.i18n.currency.CurrencyInfoTier2, goog.i18n.currency.CurrencyInfo);
return currencySymbols;
}
function extractDateTimeSymbols(content, localeInfo) {
@@ -79,7 +79,7 @@ function pluralExtractor(content, localeInfo) {
goog.LOCALE = localeIds[i].match(/[^_]+/)[0];
try {
eval(contentText);
} catch (e) {
} catch(e) {
console.log("Error in eval(contentText): " + e.stack);
}
if (!goog.i18n.pluralRules.select) {
@@ -133,7 +133,7 @@ function canonicalizeForJsonStringify(unused_key, object) {
function serializeContent(localeObj) {
return JSON.stringify(localeObj, canonicalizeForJsonStringify, ' ')
.replace(new RegExp('[\\u007f-\\uffff]', 'g'), function(c) { return '\\u' + ('0000' + c.charCodeAt(0).toString(16)).slice(-4); })
.replace(new RegExp('[\\u007f-\\uffff]', 'g'), function(c) { return '\\u'+('0000'+c.charCodeAt(0).toString(16)).slice(-4); })
.replace(/"@@|@@"/g, '');
}
@@ -161,7 +161,6 @@ function outputLocale(localeInfo, localeID) {
if (!localeObj.DATETIME_FORMATS) {
localeObj.DATETIME_FORMATS = fallBackObj.DATETIME_FORMATS;
}
localeObj.localeID = localeID;
localeObj.id = correctedLocaleId(localeID);
var getDecimals = [
@@ -202,11 +201,10 @@ function outputLocale(localeInfo, localeID) {
DATETIME_FORMATS: localeObj.DATETIME_FORMATS,
NUMBER_FORMATS: localeObj.NUMBER_FORMATS,
pluralCat: localeObj.pluralCat,
id: localeObj.id,
localeID: localeID
id: localeObj.id
};
var content = serializeContent(localeObj);
var content = serializeContent(localeInfo[localeID]);
if (content.indexOf('getVF(') < 0) {
getVF = '';
}
+1 -1
View File
@@ -11,7 +11,7 @@ var PATTERN_SEP = ';',
DIGIT = '#';
/**
* main function for parser
* main funciton for parser
* @param str {string} pattern to be parsed (e.g. #,##0.###).
*/
function parsePattern(pattern) {
@@ -2142,7 +2142,7 @@ queue}</string>
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qr
\f0\fs22 \cf2 $scope\
name='World'}</string>
name='Wold'}</string>
<key>VerticalPad</key>
<integer>0</integer>
</dict>
+3 -9
View File
@@ -37,25 +37,19 @@ module.exports = function(config, specificOptions) {
'SL_Chrome': {
base: 'SauceLabs',
browserName: 'chrome',
version: '47'
version: '43'
},
'SL_Firefox': {
base: 'SauceLabs',
browserName: 'firefox',
version: '43'
version: '39'
},
'SL_Safari_8': {
'SL_Safari': {
base: 'SauceLabs',
browserName: 'safari',
platform: 'OS X 10.10',
version: '8'
},
'SL_Safari_9': {
base: 'SauceLabs',
browserName: 'safari',
platform: 'OS X 10.11',
version: '9'
},
'SL_IE_9': {
base: 'SauceLabs',
browserName: 'internet explorer',
+1 -1
View File
@@ -287,7 +287,7 @@ module.exports = {
rewrite: function(){
return function(req, res, next){
var REWRITE = /\/(guide|api|cookbook|misc|tutorial|error).*$/,
IGNORED = /(\.(css|js|png|jpg|gif|svg)$|partials\/.*\.html$)/,
IGNORED = /(\.(css|js|png|jpg|gif)$|partials\/.*\.html$)/,
match;
if (!IGNORED.test(req.url) && (match = req.url.match(REWRITE))) {
+309
View File
@@ -0,0 +1,309 @@
/*
* HTML Parser By John Resig (ejohn.org)
* Original code by Erik Arvidsson, Mozilla Public License
* http://erik.eae.net/simplehtmlparser/simplehtmlparser.js
*
* // Use like so:
* htmlParser(htmlString, {
* start: function(tag, attrs, unary) {},
* end: function(tag) {},
* chars: function(text) {},
* comment: function(text) {}
* });
*
* // or to get an XML string:
* HTMLtoXML(htmlString);
*
* // or to get an XML DOM Document
* HTMLtoDOM(htmlString);
*
* // or to inject into an existing document/DOM node
* HTMLtoDOM(htmlString, document);
* HTMLtoDOM(htmlString, document.body);
*
*/
(function(){
// Regular Expressions for parsing tags and attributes
var startTag = /^<(\w+)((?:\s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/,
endTag = /^<\/(\w+)[^>]*>/,
attr = /(\w+)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))?/g;
// Empty Elements - HTML 4.01
var empty = makeMap("area,base,basefont,br,col,frame,hr,img,input,isindex,link,meta,param,embed");
// Block Elements - HTML 4.01
var block = makeMap("address,applet,blockquote,button,center,dd,del,dir,div,dl,dt,fieldset,form,frameset,hr,iframe,ins,isindex,li,map,menu,noframes,noscript,object,ol,p,pre,script,table,tbody,td,tfoot,th,thead,tr,ul");
// Inline Elements - HTML 4.01
var inline = makeMap("a,abbr,acronym,applet,b,basefont,bdo,big,br,button,cite,code,del,dfn,em,font,i,iframe,img,input,ins,kbd,label,map,object,q,s,samp,script,select,small,span,strike,strong,sub,sup,textarea,tt,u,var");
// Elements that you can, intentionally, leave open
// (and which close themselves)
var closeSelf = makeMap("colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr");
// Attributes that have their values filled in disabled="disabled"
var fillAttrs = makeMap("checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected");
// Special Elements (can contain anything)
var special = makeMap("script,style");
var htmlParser = this.htmlParser = function( html, handler ) {
var index, chars, match, stack = [], last = html;
stack.last = function(){
return this[ this.length - 1 ];
};
while ( html ) {
chars = true;
// Make sure we're not in a script or style element
if ( !stack.last() || !special[ stack.last() ] ) {
// Comment
if ( html.indexOf("<!--") == 0 ) {
index = html.indexOf("-->");
if ( index >= 0 ) {
if ( handler.comment )
handler.comment( html.substring( 4, index ) );
html = html.substring( index + 3 );
chars = false;
}
// end tag
} else if ( html.indexOf("</") == 0 ) {
match = html.match( endTag );
if ( match ) {
html = html.substring( match[0].length );
match[0].replace( endTag, parseEndTag );
chars = false;
}
// start tag
} else if ( html.indexOf("<") == 0 ) {
match = html.match( startTag );
if ( match ) {
html = html.substring( match[0].length );
match[0].replace( startTag, parseStartTag );
chars = false;
}
}
if ( chars ) {
index = html.indexOf("<");
var text = index < 0 ? html : html.substring( 0, index );
html = index < 0 ? "" : html.substring( index );
if ( handler.chars )
handler.chars( text );
}
} else {
html = html.replace(new RegExp("(.*)<\/" + stack.last() + "[^>]*>"), function(all, text){
text = text.replace(/<!--(.*?)-->/g, "$1")
.replace(/<!\[CDATA\[(.*?)]]>/g, "$1");
if ( handler.chars )
handler.chars( text );
return "";
});
parseEndTag( "", stack.last() );
}
if ( html == last )
throw "Parse Error: " + html;
last = html;
}
// Clean up any remaining tags
parseEndTag();
function parseStartTag( tag, tagName, rest, unary ) {
if ( block[ tagName ] ) {
while ( stack.last() && inline[ stack.last() ] ) {
parseEndTag( "", stack.last() );
}
}
if ( closeSelf[ tagName ] && stack.last() == tagName ) {
parseEndTag( "", tagName );
}
unary = empty[ tagName ] || !!unary;
if ( !unary )
stack.push( tagName );
if ( handler.start ) {
var attrs = [];
rest.replace(attr, function(match, name) {
var value = arguments[2] ? arguments[2] :
arguments[3] ? arguments[3] :
arguments[4] ? arguments[4] :
fillAttrs[name] ? name : "";
attrs.push({
name: name,
value: value,
escaped: value.replace(/(^|[^\\])"/g, '$1\\\"') //"
});
});
if ( handler.start )
handler.start( tagName, attrs, unary );
}
}
function parseEndTag( tag, tagName ) {
// If no tag name is provided, clean shop
if ( !tagName )
var pos = 0;
// Find the closest opened tag of the same type
else
for ( var pos = stack.length - 1; pos >= 0; pos-- )
if ( stack[ pos ] == tagName )
break;
if ( pos >= 0 ) {
// Close all the open elements, up the stack
for ( var i = stack.length - 1; i >= pos; i-- )
if ( handler.end )
handler.end( stack[ i ] );
// Remove the open elements from the stack
stack.length = pos;
}
}
};
this.HTMLtoXML = function( html ) {
var results = "";
htmlParser(html, {
start: function( tag, attrs, unary ) {
results += "<" + tag;
for ( var i = 0; i < attrs.length; i++ )
results += " " + attrs[i].name + '="' + attrs[i].escaped + '"';
results += (unary ? "/" : "") + ">";
},
end: function( tag ) {
results += "</" + tag + ">";
},
chars: function( text ) {
results += text;
},
comment: function( text ) {
results += "<!--" + text + "-->";
}
});
return results;
};
this.HTMLtoDOM = function( html, doc ) {
// There can be only one of these elements
var one = makeMap("html,head,body,title");
// Enforce a structure for the document
var structure = {
link: "head",
base: "head"
};
if ( !doc ) {
if ( typeof DOMDocument != "undefined" )
doc = new DOMDocument();
else if ( typeof document != "undefined" && document.implementation && document.implementation.createDocument )
doc = document.implementation.createDocument("", "", null);
else if ( typeof ActiveX != "undefined" )
doc = new ActiveXObject("Msxml.DOMDocument");
} else
doc = doc.ownerDocument ||
doc.getOwnerDocument && doc.getOwnerDocument() ||
doc;
var elems = [],
documentElement = doc.documentElement ||
doc.getDocumentElement && doc.getDocumentElement();
// If we're dealing with an empty document then we
// need to pre-populate it with the HTML document structure
if ( !documentElement && doc.createElement ) (function(){
var html = doc.createElement("html");
var head = doc.createElement("head");
head.appendChild( doc.createElement("title") );
html.appendChild( head );
html.appendChild( doc.createElement("body") );
doc.appendChild( html );
})();
// Find all the unique elements
if ( doc.getElementsByTagName )
for ( var i in one )
one[ i ] = doc.getElementsByTagName( i )[0];
// If we're working with a document, inject contents into
// the body element
var curParentNode = one.body;
htmlParser( html, {
start: function( tagName, attrs, unary ) {
// If it's a pre-built element, then we can ignore
// its construction
if ( one[ tagName ] ) {
curParentNode = one[ tagName ];
return;
}
var elem = doc.createElement( tagName );
for ( var attr in attrs )
elem.setAttribute( attrs[ attr ].name, attrs[ attr ].value );
if ( structure[ tagName ] && typeof one[ structure[ tagName ] ] != "boolean" )
one[ structure[ tagName ] ].appendChild( elem );
else if ( curParentNode && curParentNode.appendChild )
curParentNode.appendChild( elem );
if ( !unary ) {
elems.push( elem );
curParentNode = elem;
}
},
end: function( tag ) {
elems.length -= 1;
// Init the new parentNode
curParentNode = elems[ elems.length - 1 ];
},
chars: function( text ) {
curParentNode.appendChild( doc.createTextNode( text ) );
},
comment: function( text ) {
// create comment node
}
});
return doc;
};
function makeMap(str){
var obj = {}, items = str.split(",");
for ( var i = 0; i < items.length; i++ )
obj[ items[i] ] = true;
return obj;
}
})();
+2 -1
View File
@@ -11,7 +11,8 @@ set -e
# Curl and run this script as part of your .travis.yml before_script section:
# before_script:
# - curl https://gist.github.com/santiycr/5139565/raw/sauce_connect_setup.sh | bash
CONNECT_URL="https://saucelabs.com/downloads/sc-4.3.13-linux.tar.gz"
CONNECT_URL="https://saucelabs.com/downloads/sc-4.3.7-linux.tar.gz"
CONNECT_DIR="/tmp/sauce-connect-$RANDOM"
CONNECT_DOWNLOAD="sc-4.3.7-linux.tar.gz"
+1 -1
View File
@@ -178,7 +178,7 @@ var getSnapshotVersion = function() {
// last release was a non beta release. Increment the patch level to
// indicate the next release that we will be doing.
// E.g. last release was 1.3.0, then the snapshot will be
// 1.3.1-build.1, which is lesser than 1.3.1 according to the semver!
// 1.3.1-build.1, which is lesser than 1.3.1 accorind the semver!
// If the last release was a beta release we don't update the
// beta number by purpose, as otherwise the semver comparison
+2940 -2043
View File
File diff suppressed because it is too large Load Diff
+5132 -3733
View File
File diff suppressed because it is too large Load Diff
+8 -10
View File
@@ -1,23 +1,22 @@
{
"name": "angularjs",
"license": "MIT",
"branchVersion": "1.5.x",
"branchPattern": "1.5.*",
"branchVersion": "^1.4.0-beta.0",
"branchPattern": "1.4.*",
"distTag": "latest",
"repository": {
"type": "git",
"url": "https://github.com/angular/angular.js.git"
},
"engines": {
"node": "<5",
"node": "~0.10",
"npm": "~2.5"
},
"engineStrict": true,
"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"
"commit": "git-cz"
},
"devDependencies": {
"angular-benchpress": "0.x.x",
@@ -27,7 +26,7 @@
"canonical-path": "0.0.2",
"cheerio": "^0.17.0",
"commitizen": "^2.3.0",
"cz-conventional-changelog": "1.1.4",
"cz-conventional-changelog": "^1.1.4",
"dgeni": "^0.4.0",
"dgeni-packages": "^0.11.0",
"event-stream": "~3.1.0",
@@ -41,7 +40,7 @@
"grunt-contrib-jshint": "~0.10.0",
"grunt-ddescribe-iit": "~0.0.1",
"grunt-jasmine-node": "git://github.com/vojtajina/grunt-jasmine-node.git#fix-grunt-exit-code",
"grunt-jscs": "^2.1.0",
"grunt-jscs": "~1.2.0",
"grunt-merge-conflict": "~0.0.1",
"grunt-shell": "~1.1.1",
"gulp": "~3.8.0",
@@ -52,15 +51,14 @@
"gulp-sourcemaps": "^1.2.2",
"gulp-uglify": "^1.0.1",
"gulp-util": "^3.0.1",
"jasmine-core": "^2.4.0",
"jasmine-node": "^2.0.0",
"jasmine-node": "~1.14.5",
"jasmine-reporters": "~1.0.1",
"jshint-stylish": "~1.0.0",
"karma": "^0.13.19",
"karma-browserstack-launcher": "^0.1.8",
"karma-chrome-launcher": "^0.2.2",
"karma-firefox-launcher": "^0.1.7",
"karma-jasmine": "^0.3.7",
"karma-jasmine": "^0.1.6",
"karma-junit-reporter": "^0.3.8",
"karma-ng-scenario": "^0.1.0",
"karma-sauce-launcher": "^0.3.0",
+6 -6
View File
@@ -9,7 +9,7 @@ if (process.env.BROWSER_PROVIDER === 'browserstack') {
capabilitiesForBrowserStack({
browserName: 'chrome',
platform: 'MAC',
version: '49'
version: '34'
}),
capabilitiesForBrowserStack({
browserName: 'firefox',
@@ -18,7 +18,7 @@ if (process.env.BROWSER_PROVIDER === 'browserstack') {
capabilitiesForBrowserStack({
browserName: 'safari',
platform: 'MAC',
version: '9'
version: '7'
})
];
} else {
@@ -28,8 +28,8 @@ if (process.env.BROWSER_PROVIDER === 'browserstack') {
config.multiCapabilities = [
capabilitiesForSauceLabs({
browserName: 'chrome',
platform: 'OS X 10.11',
version: '48'
platform: 'OS X 10.9',
version: '34'
}),
capabilitiesForSauceLabs({
browserName: 'firefox',
@@ -37,8 +37,8 @@ if (process.env.BROWSER_PROVIDER === 'browserstack') {
}),
capabilitiesForSauceLabs({
browserName: 'safari',
platform: 'OS X 10.11',
version: '9'
platform: 'OS X 10.9',
version: '7'
})
];
}
+2 -2
View File
@@ -4,11 +4,11 @@ echo "#################################"
echo "#### Jenkins Build ############"
echo "#################################"
source scripts/jenkins/set-node-version.sh
# Enable tracing and exit on first failure
set -xe
scripts/jenkins/set-node-version.sh
# This is the default set of browsers to use on the CI server unless overridden via env variable
if [[ -z "$BROWSERS" ]]
then
+1 -1
View File
@@ -35,7 +35,7 @@ function init {
}
function build {
source ./set-node-version.sh
./set-node-version.sh
cd ../..
npm install -g grunt-cli
+1 -1
View File
@@ -4,4 +4,4 @@
source ~/.nvm/nvm.sh
# Use node.js at 4.2.x
nvm install 4.4
nvm install 4.2
+1 -1
View File
@@ -11,7 +11,7 @@ elif [ $JOB = "unit" ]; then
if [ "$BROWSER_PROVIDER" == "browserstack" ]; then
BROWSERS="BS_Chrome,BS_Safari,BS_Firefox,BS_IE_9,BS_IE_10,BS_IE_11,BS_iOS"
else
BROWSERS="SL_Chrome,SL_Firefox,SL_Safari_8,SL_Safari_9,SL_IE_9,SL_IE_10,SL_IE_11,SL_iOS"
BROWSERS="SL_Chrome,SL_Safari,SL_Firefox,SL_IE_9,SL_IE_10,SL_IE_11,SL_iOS"
fi
grunt test:promises-aplus
+2 -1
View File
@@ -94,6 +94,8 @@
"VALIDITY_STATE_PROPERTY": false,
"reloadWithDebugInfo": false,
"skipDestroyOnNextJQueryCleanData": true,
"NODE_TYPE_ELEMENT": false,
"NODE_TYPE_ATTRIBUTE": false,
"NODE_TYPE_TEXT": false,
@@ -138,7 +140,6 @@
"jqLiteInheritedData": false,
"jqLiteBuildFragment": false,
"jqLiteParseHTML": false,
"jqLiteWrapNode": false,
"getBooleanAttrName": false,
"getAliasedAttrName": false,
"createEventHandler": false,

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