Compare commits

..

174 Commits

Author SHA1 Message Date
Wes 37310e024d docs(Courses): fix syntax issue in developer guide
The courses section should use commas between links to differentiate the instances of each link

Closes #10448
2014-12-13 21:28:02 -05:00
Caitlin Potter 306e626196 revert feat($compile): add support for ng-attr with camelCased attributes
This reverts commit a1e7eb6360.

This change broke the stable branch builds.

/CC @petebacondarwin / @wesleycho
2014-12-13 20:39:15 -05:00
Dan Tennery-Spalding f31c7492ec docs(API Reference): corrected two typos - two missing commas
In the ngAnimate section, there were two commas missing from two sentences. This is inconsistent with the grammar used in the rest of the API documentation and made the document (slightly) more difficult to read. The two sentences are shown below, with the new commas added:

1. "Once defined, the animation can be triggered"
                           ^
                    comma added

2. "Once registered, the animation can be triggered"
                              ^
                    comma added

Closes #10447
2014-12-13 20:20:40 -05:00
Wesley Cho a1e7eb6360 feat($compile): add support for ng-attr with camelCased attributes
SVG attributes are case sensitive and some have upper case letters in them
This change ensures that we can identify these, when being used with the `ng-attr`
directive, by encoding upper case letters with a preceding underscore.

For example to apply `ng-attr` to the `viewBox` attribute we could write
`ng-attr-view_box` - or any of the other variants: `ng:attr:view_box`,
`data-ng-attr-view_box`, etc.

Closes #9845
Closes #10194
2014-12-09 12:06:04 +00:00
Tobias Davis 169e5326d1 docs($interval): correcting example code indentation
Bueno!

Closes #10372
2014-12-08 16:30:05 -05:00
Georgios Kalpakas bb3b65374d chore(changelog): add test for addition of trailing newline
Adds tests for the functionality added by #9550.

Closes #10358
2014-12-08 13:05:32 -05:00
Giuseppe Caruso ac9336b35a docs(guide/controllers): Just a typo
Gingerbreak would break testing. :)

Oh my gosh he's right, it totally w/ould. That is so embarrassing!

Closes #10353
2014-12-08 10:51:05 -05:00
Ciro Nunes 75787446ee docs(compile): document $attrs.$normalize
Closes #10345
2014-12-05 14:19:46 -05:00
Caitlin Potter 14409d7a7f style(ngHref): make jscs happy ;-; 2014-11-28 22:29:05 -06:00
Sagar Ranglani 370676d4d0 docs(ngHref): fix poor paragraph construction
It was bad.

In order to improve the docs, the inclusion of the last sentence would help define `ngHref` well.

Closes #10254
2014-11-28 22:10:28 -06:00
Caitlin Potter 4c218de4d3 style(*): IE is a real browser, and chakra is pretty solid
- IE9+ do not have issues with Function.prototype.apply() on builtin fns (asked Brian Terlson)
  (NOTE: there may still be corner cases where builtins will not have `apply()` --- this may
  need to be reverted on complaint).
- HTMLScriptElement#text is an IDL-spec'd attribute, and we use it in all cases --- so the
  comment was sort of nonsense.
- The value of `msie` does not depend on whether the user is using a "real" browser or not.

Closes #10242
2014-11-26 14:39:23 -06:00
Lucas Galfaso 929dd15b9b fix(linky): encode double quotes when serializing email addresses
Email addresses can (under certain restrictions) include double quote
characters. See http://tools.ietf.org/html/rfc3696#section-3.

For example, `"Jo Bloggs"@abc.com` is a valid email address.

When serializing emails to the `href` attribute of an anchor element,
we must HTML encode these double quote characters. See
http://www.w3.org/TR/html-markup/syntax.html#syntax-attr-double-quoted

This commit does not attempt to improve the functionality (i.e. regex)
that attempts to identify email addresses in a general string.

Closes #8945
Closes #8964
Closes #5946
Closes #10090
Closes #9256
2014-11-23 22:23:41 +00:00
Georgios Kalpakas 1b9e408ddb fix($route): fix redirection with optional/eager params
Fixes #9742
Closes #10202
2014-11-23 19:24:39 +01:00
thorn0 7505d126fa chore(docs): regroup version selector options into major branches and latest
Before this change we grouped by the  discontinued stable/unstable distinction.

Closes #10053
2014-11-23 14:50:31 +00:00
Caitlin Potter 7044e55feb style($http): make jscs happy 2014-11-21 00:27:45 -05:00
Dustin Chilson bd9e894fb7 docs($http): describe how to remove a header on a per request basis
Closes #10144
2014-11-21 00:27:38 -05:00
Brian Ford ba7e24ec6c chore(scripts): correctly update package.json 2014-11-20 15:21:33 -08:00
Brian Ford e1f98773c7 chore(scripts): fix 1.2.x tag name 2014-11-20 15:02:40 -08:00
Brian Ford 17d8a520ca chore(scripts): publish 1.2.x releases to npm with correct tag 2014-11-20 14:34:26 -08:00
Jeff Cross 84bf883f6d docs(CHANGELOG): update changelog with 1.2.27 2014-11-20 10:31:49 -08:00
samuel durand 38ff199a3c docs($anchorScrollProvider): document disableAutoScrolling method 2014-11-17 14:46:43 +00:00
Brian Westrich 7ff5ec254e docs(tutorial/step-5): include sort and filter in json view experiment
Closes #10082
2014-11-17 14:34:13 +00:00
Brian Westrich a2f2032a20 docs(tutorial/step-4): "unknown" option is actually blank
The name 'unknown' doesn't appear as a choice, the new choice is just blank.
Side note: once I choose one of the non-blank options, I no longer see the blank option.

Closes #10079
2014-11-17 13:47:56 +00:00
Peter Bacon Darwin 16833d0fb6 fix(select): ensure the label attribute is updated in Internet Explorer
Only changing the `<option>` text value is not enough to trigger a render
change in IE. We need to explicit update the `label` property too.

Closes #9621
Closes #10042
2014-11-15 22:55:55 +00:00
Peter Bacon Darwin 2a8a4e7fad test(select): refactor option elements expectations to use toEqualOption matcher
By using a new matcher our tests become less brittle with respect to unimportant
extra attributes.
2014-11-15 18:49:01 +00:00
Judy Tuan beeb64a6f6 docs(misc/Develop): update required Java version 2014-11-14 20:23:15 +00:00
Caitlin Potter e49e7d50c5 chore($q): make jscs happy
jscs loves to be happy and does not love trailing whitespace.
2014-11-14 11:12:37 -05:00
Bernie Telles 3b3de3f876 docs($q): explain what the $q service does in description
Explain what the $q service does in description, instead of origin document.

The original explanation was less accessible to people new to promises and JS in general.

Closes #10056
2014-11-14 11:12:27 -05:00
Chatchavan Wacharamanotham eec78e78d6 docs(guide/compiler): replaced 'locals' with 'scope'
In "Understanding How Scopes Work with Transcluded Directives" section, a text referred to an
obsolete 'locals' instead of 'scope'.

Closes #10018
2014-11-14 11:03:53 -05:00
Caitlin Potter b1f2917696 test(orderBy): add test cases for ordering array-like objects
Closes #10060
2014-11-14 10:23:46 -05:00
Karol Wypchło 409bcb3810 perf(orderBy): copy array with slice instead of for loop
Use array slice method to copy entire array instead of a for loop
http://jsperf.com/new-array-vs-splice-vs-slice/54

Closes #9942
2014-11-14 10:13:29 -05:00
codef0rmer e49a1433fd docs(guide/Index): add book AngularJS UI Development
Matthias and I wrote a book on AngularJS which might be helpful for Angular developers.

Merci~!

Closes #9971
2014-11-11 14:14:07 -05:00
AlexChan c26b5e3c88 docs(ngModel.NgModelController) use $evalAsync instead of $apply for event handling
Have the apply called safely during events by using `$evalAsync` rather than `$apply`
This will help ensure that an apply for a user directive is not called during a digest cycle.

Closes #9891
2014-11-11 13:59:48 -05:00
Chirayu Krishnappa 4d0614fd0d fix($parse, events): prevent accidental misuse of properties on $event
Closes #9969
2014-11-10 15:35:02 -08:00
Chirayu Krishnappa 756640f5aa fix($parse): add quick check for Function constructor in fast path 2014-11-10 15:34:58 -08:00
Michael James d87b7912df docs($q): added IE8 warning to promise.catch()
Closes #9987
2014-11-10 17:30:47 -05:00
Brian Ford bff8041bd0 docs(guide/index): link to security 2014-11-07 10:33:48 -08:00
Brian Ford e0ee491633 docs($parse): formatting, link to security docs 2014-11-07 10:33:31 -08:00
Brian Ford 7dfe82e135 docs(security): add security doc 2014-11-07 10:33:04 -08:00
Lucas Galfaso 9f2a53b33e docs(CHANGELOG): Document breaking change from 23bc92b1
Document the breaking change from 23bc92b1

Closes #9947
2014-11-06 15:28:10 -05:00
rsperberg 9128eac501 docs(guide/concepts): spell "Angular" with cap "A", fix typos
In these two instances, Angular was spelled with a lower-case "a." All occurrences should be spelled
consistently.

Compound adjectives preceding the noun they modify should generally be hyphenated (cf Chicago Manual
of Style, 6.40), e.g., "so-called directives."

Closes #9896
2014-11-06 14:17:24 -05:00
Adir 85e8d5ea67 docs(guide,tutorial): fix outdated Protractor API link
Link to the gh-pages deployment of protractor docs, it's much easier on the eyes.

Closes #9946
2014-11-06 13:58:55 -05:00
danielmbarlow a36863eea3 docs(tutorial/step_12): added 'see phone-detail change'
This one caught me out for a while because, despite the note underneath, I didn't notice the addition
of <div class="phone-images"> and it's repeater until later.

Closes #9924
2014-11-05 12:14:54 -05:00
danielmbarlow 98da7ade7a docs(tutorial/step_12): small change to overview
The bullet points at the beginning of the article were a little hard to understand because they
didn't follow the grammatical form of the preceding articles. I hope these small modifications make
it a little easier for someone else to read.

Closes #9922
2014-11-05 09:10:36 -05:00
danielmbarlow 846fe1b3ef docs(tutorial/step_05): explain need for $httpBackend.flush in tests
There is an excellent explanation for the need for this in the documentation that may be helpful to
tutorial users, so I added a link to it.

Closes #9919
2014-11-05 09:10:28 -05:00
Julie Ralph f4648abe03 chore(ci): update protractor to version 1.4.0 2014-11-04 17:18:30 -08:00
Tobias Gesellchen 5f9a1122e2 chore(.gitignore): ignore IntelliJ IDEA module files
Ignore IntelliJ IDEA modules files in the git repository

Closes #5273
2014-11-04 12:47:26 -05:00
Tero Parviainen 1afeb37756 docs(guide/scope): describe watch depths
Describe and visualize the three watch strategies: By reference, by collection items, and by value.

Closes #9388
2014-11-03 12:44:39 -08:00
Julie Ralph 7809e75a56 chore(ci): fix broken sauce connect download url 2014-10-31 09:24:37 -07:00
Uri Goldshtein 1472c31431 docs(guide/index): add link to angular-meteor
Bueno!

Closes #9844
2014-10-30 11:13:43 -04:00
Ralph Samuel d3b839d986 docs(guide/Scopes): add "the" in front of "DOM" on line 42
Closes #9818
2014-10-29 13:51:34 -04:00
ChristianKohler c8c2386296 chore(docs): clarify comment which was copy&paste from dgeni example
It makes people happy, so why not

Closes #9798
2014-10-27 12:24:02 -04:00
alindberg d0b5bfa454 docs(tutorial/tutorial): instructions to install npm on debian
Additional package required for a Debian install

Closes #9749
2014-10-22 14:17:04 -04:00
Martin Hochel 1fa2d56ba3 docs($http): document $httpProvider.interceptors in $httpProvider documentation
☆.。.:・゜☆ HASHBANG #NGEUROPE ☆.。.:・゜☆

Fixes #9366
Closes #9728
2014-10-22 11:26:43 -04:00
marcin-wosinek efedc643d1 docs($templateCache): clarify inline template
Current doc doesn't state required tag location clear enough. It was
[stack overflow|http://stackoverflow.com/a/16125138] where I've found that requirement

Closes #9741
2014-10-22 10:02:49 -04:00
Jackson Ray Hamilton 34230b30b7 docs(guide/bootstrap): close script tag
Closes #9739
2014-10-22 00:45:52 -04:00
Dwayne Crooks 8354d02805 docs(ngModel.NgModelController): remove extra 'to'
Closes #9702
2014-10-20 21:34:13 +01:00
Bastien Caudan 1426b02980 fix(ngMock): $httpBackend should match data containing Date objects correctly
If a response or expectation contained a date object then `$httpBackend.expect`
was not matching correctly.

This commit encodes then decodes the object being matched to ensure consistency.

Closes #5127
2014-10-20 13:07:07 +01:00
lguyot 29aeee2250 docs(tutorial/step-11): remove excess words
Closes #9690
2014-10-20 12:11:14 +01:00
Augustas 6a8348f715 docs(tutorial/step-7) - correct a url
Closes #9688
2014-10-20 11:44:04 +01:00
Peter Bacon Darwin 38e2856889 docs(guide/introduction): remove ambiguous "code-behind" jargon
This commit tries to remove the jargon and explain in plain English what
it means to add "code-behind" via a directive.

Closes #9684
2014-10-20 10:32:16 +01:00
Peter Bacon Darwin a56435f3ae fix($rootScope.$on) check listener existense while deregistering
Check that listener is still present in $$listeners before decrease
$$listenerCount. It fixes problem with incorrect $$listenerCount after
call deregistering function multiple times.

Closes #9666
Closes #9667
2014-10-19 12:10:58 +01:00
Juan M. Cuello 75082c975c docs(error/dupes): Little fix in explanation text.
Little fix in docs/content/error/ngRepeat/dupes.ngdoc.

Closes #9673
2014-10-18 15:39:12 -04:00
Daniel Luz 31b6bfaaf4 docs(ngEventDirs): update remarks on behavior
The event directives haven't stopped propagation by default in a long time.
If that behavior is desired, the handler may use the provided `$event` to call:

    $event.stopPropagation();

Closes #9640
2014-10-16 16:44:48 -04:00
Ciro Nunes 2d74323e3e docs(ngModel): fix anchor text
Closes #9604
2014-10-14 10:44:36 +01:00
Afshin Mokhtari edc2613ed5 docs(CONTRIBUTING): prototypical -> prototypal
Closes #9608
2014-10-14 10:43:10 +01:00
Richard 6eab8ab187 docs(guide/unit-testing): use whitespace to improve readability
☆.。.:・゜☆ Merci (◜௰◝) ☆.。.:・゜☆

Closes #9572
2014-10-12 23:04:02 -04:00
Georgios Kalpakas 80ce046fd1 chore(CHANGELOG): add an extra new line after each item in the "BREAKING CHANGES" list
This ensures that the next item will appear on a new line and be properly
parsed as new list item (and not as the continuation of the current item),
even if the current item does not end with a newline character.
Currently, it would result is something like this:

    - **item 1**: due to ...
      blah1 blah1 blah1- **item 2**: due to...
      blah2 blah2 blah2

instead of the intended:

    - **item 1**: duo to ...
      ...
    - **item 2**: due to ...
      ...
2014-10-10 19:07:22 +01:00
Chris Inch 315f320e2e docs(guide/compiler): add title to the page 2014-10-09 13:54:20 -07:00
Georgios Kalpakas ec4fe1bcab fix($http): add missing shortcut methods and missing docs
There was some inconsistency in version 1.2.25 regarding the definition
and documentation of shortcut methods in `ng.$http` and
`ngMock[E2E].$httpBackend`. Some methods didn't exist (although documented
as existing), whereas some methods did exist, but wheren't documented.
This commit fixes the above errors and adds tests to verify the existence
of all shortcut methods.
More specificcally, the following issues were addressed:
`ng.$http`: Add the missing `patch()` shortcut method and related docs.
`ng.$http` spec: Add test to verify the existence and functionality of the
`patch()` shortcut method.
`ngMock[E2E].$httpBackend`: Add docs for the (existing) `whenPATCH()`
shortcut method, add the missing `expectHEAD()`/`whenHEAD()` shortcut
methods, fix grammatical errors.
`ngMock[E2E].$httpBackend` spec: Add test to verify the existence of shortcut
methods for all HTTP verbs.

Closes #9180
Closes #9321
2014-10-09 20:13:08 +01:00
bolasblack 3303fe41e4 docs(versions): remove the trailing slash in URLs when switch versions
Because `https://docs.angularjs.org/api/` can handler the trailing slash,
but `https://code.angularjs.org/1.2.24/docs/api` can not.

Fix #9043
Closes #9045
2014-10-09 11:53:37 -07:00
thorn0 f22e5fd980 docs(angular.injector): correct return type 2014-10-09 11:49:30 -07:00
Jakub Zych b11d6c792f style(filters) use consistent quote style and strict equality
before change quotes where mixed and one if contained equality operator instead of identity

Closes #9349
2014-10-09 07:11:43 -04:00
Brian Ford e713f36d7c docs(changelog): more release notes for 1.3.0-rc.5 2014-10-08 15:52:27 -07:00
Brian Ford 8162a1d731 docs(changelog): release notes for 1.3.0-rc.5 2014-10-08 13:37:55 -07:00
Izhaki 1e6f8543e5 docs($compile): note template is ignored with element transclusion 2014-10-08 11:30:49 -07:00
Jesse Palmer 0e293d2a97 docs(ngIf): update out-of-date link 2014-10-08 10:43:19 -07:00
Tobias Bosch 434d7a0903 fix($browser): Cache location.href only during page reload phase
Adds caching for url changes while a reload is happening,
as browsers do not allow to read out the new location the browser
is navigating to.

Removes unnecessary caching from $browser, as IE7-IE9 all
have the new hash value in `location.href` after changing it.
There was a wrong assumption in the previous version of this code
introduced by dca23173e2 and d70711481e.

Adds more tests for #6976
Fixes #9235
Closes #9470
2014-10-07 14:55:54 -07:00
Tobias Bosch a6e6438dae fix($browser): don’t use history api when only the hash changes
Fixes a failing test on IE9 caused as a side effect
of 404b95fe30 being merged
before 0656484d3e.

The test should have been independent on the browser running it
and it is now.

Closes #9423
Closes #9424
2014-10-07 14:54:55 -07:00
Tobias Bosch 3691d2c15f fix($browser): don’t use history api when only the hash changes
Fix jshint error
2014-10-07 14:54:55 -07:00
Tobias Bosch 4cee5fde1b fix($browser): don’t use history api when only the hash changes
IE10/11 have the following problem: When changing the url hash
via `history.pushState()` and then reverting the hash via direct
changes to `location.href` (or via a link) does not fire a
`hashchange` nor `popstate` event.

This commit changes the default behavior as follows:
Uses `location.href`/`location.replace` if the new url differs from
the previous url only in the hash fragment or the browser
does not support history API.
Use `history.pushState`/ `history.replaceState` otherwise.

Fixes #9143
Closes #9406
2014-10-07 14:54:55 -07:00
Ben Harold 5d042592fc docs($injector): fix syntax error
There was a missing parenthesis in $injector test example

Closes #9469
2014-10-07 13:40:19 -04:00
Matias Niemelä f619d032c9 fix($animate): clear the GCS cache even when no animation is detected
$animate will cache subsequent calls to GCS in the event that the element
with the same CSS classes and the same parentNode is being animated. Once the
animation is started then $animate waits for one rAF before flushing the GCS
lookup cache. Prior to this fix, if GCS was unable to detect any transitions
or keyframes on the element then it would simply close the animation, but it
would not trigger the rAF code to flush the cache. This issue caused a bug
which made it difficult to detect why certain animations are not allowed to
fire if the element didn't contain any CSS-based animations beforehand.

Closes #8813
2014-10-07 09:44:44 +03:00
Casey Garland 95f5b86240 docs(guide/index): fix broken link 2014-10-06 16:02:25 -07:00
thorn0 483d91a624 docs($injector): injectors aren't functions
Closes #9453
2014-10-06 18:20:01 -04:00
thorn0 e9339935d4 docs($injector): clean up docs for $injector#has
Fixup return type and param info.

Closes #9452
2014-10-06 16:55:49 -04:00
tommyangelo 3e468523b7 docs(ngBindHtml): explain that angular-sanitize.js is needed to depend on ngSanitize
Added comment. You need to include angular-sanitize.js otherwise you cant use ngSanitize!

Closes #9400
2014-10-06 16:47:58 -04:00
Agam Rafaeli 99f3931e3d docs(guide/introduction): guice has moved to github
Closes #9416
2014-10-06 16:33:13 -04:00
Jesse Palmer 80b78f7461 docs(ngIf): wrap ngIf in code tags
Closes #9435
2014-10-06 16:11:05 -04:00
erikrahm 386c179a94 docs(misc/faq): grammatical error fixes
Merci beaucoup

Closes #9451
Closes #9450
2014-10-06 16:07:39 -04:00
thorn0 054893b555 docs($injector): $injector isn't a function
Closes #9448
2014-10-06 20:21:18 +01:00
Tim Kendrick e865726e00 chore(docs): remove unused gruntUtils import from docs config
As of commit 11c5bb7, the gruntUtils import is no longer needed in the
gitData docs config service.

Closes #9446
2014-10-06 20:19:32 +01:00
Bijan Boustani f9370755d4 docs(guide/introduction): fix grammar style
Changed "you would currently have to write" to "you would otherwise have to write".

Seems to make more sense this way since "currently" presupposes that someone new
to Angular would be coming from a different paradigm, which they may or may not be.

Closes #9428
2014-10-06 20:04:47 +01:00
Peter Bacon Darwin f906603dd6 chore(docs): update to dgeni 0.4.1 and dgeni-packages 0.10.1
Adds a new processor to identify dangling links
2014-10-06 18:08:57 +01:00
Tobias Bosch d7c084f9cf docs($location): clarify guide regarding link handling
The trick with setting `<base href=".">` has not worked since Angular 1.2.0.
It is also misleading that it talks about `$routeProvider.otherwise`
which is not important in this case.

Related to #8869
Closes #8908
2014-10-03 17:15:25 -07:00
Peter Bacon Darwin 5847fc48e7 test($location): fix use of browserTrigger
You must now pass `keys` to the function in a config object.
This bug in the test became apparent because in newer browsers, arrays
have a function called `keys()` and this was causing browserTrigger to
fail. Previously it was quietly passing this test despite being wrong.
2014-10-03 17:15:15 -07:00
Tobias Bosch 1ee9b4ef5e fix($location): revert erroneous logic and backport refactorings from master
Backport of 22948807e3 without enforcing the `<base>` tag and without the new handling for links that only contain hash fragments.

Related to #6162
Closes #8492
2014-10-03 17:15:10 -07:00
Tobias Bosch 430082e6bd refactor(locationSpec): make helper functions take an object
Makes tests more readable
2014-10-03 16:53:56 -07:00
Chris Chua fe7d9dedaa fix($browser): handle async href on url change in <=IE9
Closes #9235
2014-10-03 15:33:31 -07:00
Dominic Watson 029ac8cb80 docs(angular.element): css() method does not retrieve computed styles
The jQuery css() getter functionality utilises getComputedStyle() whereas
jqLite only retrieves what is declared inline on an element.

Closes #7599
2014-10-03 11:58:09 +01:00
Peter Bacon Darwin 45b896a16a fix(orderBy): sort by identity if no predicate is given
Closes #5847
Closes #4579
Closes #9403
2014-10-03 09:54:44 +01:00
Pawel Kozlowski f807d7ab4e fix($location): allow 0 in path() and hash() 2014-10-02 21:32:22 +01:00
Jeff Cross 07d62426f6 docs(CHANGELOG.md): update 1.2.26 release name 2014-10-02 09:46:40 -07:00
Jeff Cross 3a142e79bd docs(changelog.md): update changelog for 1.3.0-rc.4 and 1.2.26 2014-10-01 21:25:57 -07:00
Brian Feister b40130abcf docs(minerr/unpr): note that ctrls cant depend on other ctrls 2014-09-30 14:37:06 -07:00
active-low ee988d40d0 docs(guide/concepts): improve readability 2014-09-30 12:57:32 -07:00
Adam Humphrey ad4d26c525 docs(readme): fix formatting 2014-09-30 12:36:58 -07:00
Justin Walsh f58681564d docs(guide/compiler): change span to block element in draggable example
The draggable example does not work as expected in Chrome (37.0.2062.124 m).
The span disappears when dragged beyond what appears to be a small area.
Changing the span to a block element (with a width of 65px) resolves this issue.
An alternative solution would be to change the span to a div.
2014-09-30 12:30:09 -07:00
thorn0 d23f585f4a docs($compile): add header to example 2014-09-30 11:41:19 -07:00
Jeff Cross 1850f59765 revert: fix(input): always format viewValue as a string inputs with text controls
This reverts commit 1b8b41ad23.

This is a breaking change.
2014-09-30 09:21:53 -07:00
Peter Bacon Darwin 1f182853d4 revert: fix($compile): Resolve leak with asynchronous compilation
This reverts commit 5c9c197305.

This "fix" is not yet ready for 1.2.x as it has lots of issues when JQuery
is loaded.
2014-09-29 22:19:25 +01:00
Caitlin Potter 5036ac905b docs(CHANGELOG.md): put <base> in codeblock
Prevent the tag from being processed (and not rendered). Thanks @davidlehn.

Closes #9331
2014-09-29 17:16:36 -04:00
Brian Ford 11d2242df6 fix(select): make ctrl.hasOption method consistent
Prior to this fix, options added to a select by ngOptions would not cause
`selectCtrl.hasOption` to return `true`

Closes #8761
2014-09-29 13:59:54 -07:00
Peter Bacon Darwin cea23db3de chore(npm-shrinkwrap): update to dgeni-packages 0.10.0 2014-09-29 21:56:43 +01:00
Peter Bacon Darwin 5c9c197305 fix($compile): Resolve leak with asynchronous compilation
Stop an asynchronous compilation when this is performed on an
already destroyed scope

Closes #9199
Closes #9079
Closes #8504
Closes #9197
2014-09-29 21:56:43 +01:00
Peter Bacon Darwin ecb2222ea1 chore(testabilityPatch): add jqLiteCacheSize helper 2014-09-29 21:56:43 +01:00
Julie Ralph 276310e5b5 chore(ci): remove repeated tests running from Travis build
In b2902446eb the doce2e tests were moved
into the 'unit' test job on Travis, but only half of this change ever made
it into v1.2.x. This change fixes up the other half, so that the doce2e
tests are run only once.
2014-09-29 10:55:53 -07:00
Julie Ralph 6afe0dba39 chore(e2e): bump protractor to version 1.3.1 2014-09-29 10:21:05 -07:00
Peter Bacon Darwin 038ca9b9bf chore(docs): fix links to github 2014-09-26 21:22:02 +01:00
Sandeep Panda 44c451e9f5 docs(guide/index): add book AngularJS: Novice to Ninja
I wrote a book on AngularJS (AngularJS: Novice to Ninja).

Closes #9293
2014-09-26 12:29:09 -04:00
Caitlin Potter 1b8b41ad23 fix(input): always format viewValue as a string inputs with text controls
Backported from 1eda18365a

NgModel will format all scope-based values to string when setting the viewValue for
the associated input element. The formatting, however, only applies to input elements
that contain a text, email, url or blank input type. In the event of a null or undefined
scope or model value, the viewValue will be set to null or undefined instead of being
converted to an empty string.

Closes #5936
Closes #9277
2014-09-25 13:49:59 -04:00
Peter Bacon Darwin 37f2265b88 chore(docs): minify javascript 2014-09-25 06:05:17 +01:00
Peter Bacon Darwin 05a2a1d395 chore(docs): remove unused code 2014-09-25 05:50:52 +01:00
Peter Bacon Darwin fc913eea89 chore(docs): improve logo rendering performance 2014-09-25 05:45:33 +01:00
Peter Bacon Darwin f839e4944a chore(protractor): annotate $animate to allow tests to run under strict-di 2014-09-25 05:45:26 +01:00
Peter Bacon Darwin 2aead39486 chore(docs): ensure DI annotations are in place 2014-09-25 05:45:03 +01:00
Jeff Cross 54af406c2e docs(changelog): add release notes for 1.3.0-rc.3 2014-09-23 18:50:20 -07:00
Georgios Kalpakas 930bd40bac docs(ngController): Fix priority value mentioned in the docs
The `@priority 500` part was missing from the ngDoc comment, thus the docs mentioned a priority of 0
(instead of the correct 500).

Closes #9070
2014-09-23 16:25:43 -07:00
Peter Bacon Darwin 4aa4005f5f chore(docs): AngularJS 1.2.x doesn't support '$includeContentError' event 2014-09-23 19:26:04 +01:00
Peter Bacon Darwin d5c04121cb chore(docs): refactor the docs app search for better bootup time
This commit refactors how the search index is built. The docsSearch service
is now defined by a provider, which returns a different implementation of
the service depending upon whether the current browser supports WebWorkers
or now.

* **WebWorker supported**: The index is then built and stored in a new worker.
The service posts and receives messages to and from this worker to make
queries on the search index.

* **WebWorker no supported**: The index is built locally but with a 500ms
delay so that the initial page can render before the browser is blocked as
the index is built.

Also the way that the current app is identified has been modified so we can
slim down the js data files (pages-data.js) to again improve startup time.

Closes #9204
Closes #9203
2014-09-23 19:01:22 +01:00
Andrew Delikat e6996cc457 docs(tutorial/step_05): fix typo 2014-09-22 14:55:24 -07:00
William Chen 33793ec3e1 docs(triaging): fix formatting 2014-09-22 13:15:15 -07:00
Bocharsky Victor c9f8fb2559 docs(guide/$location): fix broken link 2014-09-22 13:12:52 -07:00
Christopher Rains a0229803de docs(tutorial/step_02): fix formatting 2014-09-22 13:09:39 -07:00
James Ferguson 38cb2b348e docs(readme): improve readability 2014-09-22 11:41:00 -07:00
Ariel Mashraki c54287bf8d docs(route): remove irrelevant note
Closes #9196
Closes #9200
2014-09-22 13:30:24 -04:00
Jeff Cross a36515289a chore($http): disable flaky JSONP test
See #9185
2014-09-19 17:20:32 -07:00
Peter Bacon Darwin c59da09d3e docs(limitTo): exclude the e2e test that fails on safari
Safari and doesn't like the minus key to be sent to it via Protractor.
Commenting out rather than using xit so that it passes the build
2014-09-19 22:57:11 +01:00
Peter Bacon Darwin 98ceda2194 docs(limitTo): exclude the e2e test that fails on safari
Safari and doesn't like the minus key to be sent to it via Protractor.
2014-09-19 22:40:30 +01:00
Sekib Omazic fbd620e8ae docs(angular.extend) actually only copies own enumerable properties
Closes #9007
2014-09-19 22:00:51 +01:00
Zahid Mahir 4cfc279d39 docs(tutorial/step-3): correct slight grammar issue
Closes #8996
2014-09-19 21:36:17 +01:00
jimmywarting 6a07009c12 docs(limitTo): fix input type in examples
Closes #8989
2014-09-19 21:33:55 +01:00
Sercan Eraslan f3f65caac2 docs(navigation): side navigation footer overlap problem fix
Closes #8923
2014-09-19 19:26:23 +01:00
Luke Schoen 130fe92cda docs(guide/directive): fix grammar 2014-09-18 16:12:37 -07:00
Matt Kim 3d83973fa4 docs(misc/faq): fix typo 2014-09-18 16:11:09 -07:00
Greg Fedirko 3b171a851d docs(guide/$location): improve readability 2014-09-18 16:08:59 -07:00
Luke Schoen 9782bc2aa2 docs(tutorial): improve readability 2014-09-18 16:01:13 -07:00
Christopher Rains 77be7cc7d9 docs(tutorial): fix formatting
- proper case "jQuery" vs "JQuery"
- wrap ng-view in markdown code `ng-view`
2014-09-18 15:56:23 -07:00
jeffavis 3da5847500 docs(guide/bootstrap): fix missing ngController in example 2014-09-18 15:51:59 -07:00
Rahul Doshi 53e6590e88 docs(guide): add angular-localization module to internationalization section
Closes #9158
2014-09-18 18:00:26 -04:00
Jose Martinez d1c05ad832 docs(error/$controller/noscp): fix example
Fix the "correct" example to have the proper syntax for creating the locals
object and provide a more explicit explanation as to how the scope object
should be provided.
2014-09-17 11:10:03 -07:00
Brian Ford f6f0791867 docs(changelog): release notes for 1.2.25 2014-09-16 15:05:22 -07:00
Brian Ford fb3d158be9 docs(changelog): release notes for 1.3.0-rc.2 2014-09-16 15:05:06 -07:00
Caitlin Potter 06c76694ac fix(ngLocale): Regenerate Locale Files
Fixes number formatting and symbols for many locales.
Adds support for additional locales.
2014-09-16 17:18:52 -04:00
Michael Gallagher b979ee1f03 chore(ngLocale): Include numberformatsymbolext.js in Closure Slurper Script
Adds missing number format and symbol rules to Closure slurper script.

Closes #6179
Closes #9013
2014-09-16 17:18:22 -04:00
Brian Ford d89d59f453 fix(select): update option labels when model changes
Closes #9025
2014-09-16 12:46:53 -07:00
Peter Bacon Darwin e251db9fb3 docs(ngView): remove obsolete comment from code sample
Closes #9086
2014-09-15 20:40:02 +01:00
Peter Bacon Darwin 9cc968689f chore(docs): remove excess indentation from code blocks
dgeni-packages 0.10.0-rc.5 has a fix for this problem, so this commit updates
to that version.
Adds a new e2e test to prove this is fixed.

Closes #8963
2014-09-15 20:39:55 +01:00
Peter Bacon Darwin dea705b2cf test(docs): fix url matching on api e2e tests 2014-09-15 20:39:43 +01:00
Peter Bacon Darwin c4d3e6fd43 chore(docs): ensure all docs e2e tests are run 2014-09-15 20:39:36 +01:00
Peter Bacon Darwin bf24ad144d docs(ngShowHide): use backticks to denote CSS classes and directive names
add backticks around directive names to improve documentation consistency, as it's used in some
parts of the docs already.

Closes #9081
2014-09-15 20:38:50 +01:00
Peter Bacon Darwin b4de7307c3 test(docs): add extra docs e2e tests 2014-09-15 20:35:40 +01:00
Peter Bacon Darwin 9b9a30c7ae test(docs): improve docs e2e tests 2014-09-15 20:35:20 +01:00
Peter Bacon Darwin 8be7b5d125 chore(docs): update to dgeni-0.4.0
* update package with new services and computeId config
* generateIndexPagesProcessor was not using log
* use StringMap not ES6-shim Map in errorNamespaceMap
* remove unused dependencies from generateErrorDocsProcessor
* ensure generatePagesDataProcessor adds its doc to the collection
* debugDumpProcessor was moved to dgeni-packages
2014-09-15 20:33:58 +01:00
Caitlin Potter a3fbf0ff5a test($parse): ensure CSP code paths are used when testing
Previously, the test suite was not actually taking CSP-mode paths when we were expecting it to.

Numerous CSP-mode tests are failing, working on fixing these.
2014-09-12 15:07:37 -04:00
Caitlin Potter f2894c0f1d test($parse): ensure CSP code paths are used when testing
Previously, the test suite was not actually taking CSP-mode paths when we were expecting it to.

Numerous CSP-mode tests are failing, working on fixing these.
2014-09-12 14:51:55 -04:00
Georgii 6d12e8990b refactor(ngEventDirs): remove a useless call
The event names are already lower-case.
2014-09-11 12:57:32 -07:00
Georgios Kalpakas 71d65821c8 docs(CHANGELOG.md): fix typos for ng-switch-changed workaround
Fix the JavaScript errors in the work-around proposed in 0f806d9 in order to emulate the behaviour
of the removed `change` attribute of ngSwitch.

Closes #9034
2014-09-11 15:42:30 -04:00
Justin Walsh ae92658ebf docs(guide/forms): correct grammar 2014-09-11 12:11:28 -07:00
SirTophamHatt 1a53863662 docs(guide/providers): note that services can create functions
The conclusion table incorrectly states that services can not create functions.
New table row added to separate "can create functions" and "can create primitives".
2014-09-10 16:07:53 -07:00
Lucas Galfaso 1b6d74cc9f fix(i18n): fix typo at i18n generation code
Fix typo at i18n generation code. This would remove the
property `macFrac` that has no meaning from all the
generated locales
2014-09-10 15:30:18 -07:00
Peter Bacon Darwin 6fd048a3b7 docs(tutorial/steps-11&12): add warning about bower conflict error
See: https://github.com/angular/angular-phonecat/issues/163#issuecomment-55181854
2014-09-10 22:52:58 +01:00
Michael Silver 50cd3a4210 docs(tutorial): update step 7 to reference angular-phonecat
This changes the example JSON to be the actual bower.json for angular-phonecat,
with name set to angular-phonecat.
2014-09-10 11:45:32 -07:00
standup75 57ac995b8b docs(ngResource): document steps to skip default json serialization/deserialization 2014-09-10 11:42:28 -07:00
867 changed files with 87538 additions and 12911 deletions
+1
View File
@@ -12,6 +12,7 @@ angular.js.tmproj
bower_components/
angular.xcodeproj
.idea
*.iml
.agignore
libpeerconnection.log
npm-debug.log
-1
View File
@@ -11,7 +11,6 @@ env:
- JOB=unit
- JOB=e2e TEST_TARGET=jqlite
- JOB=e2e TEST_TARGET=jquery
- JOB=e2e TEST_TARGET=doce2e
global:
- SAUCE_USERNAME=angular-ci
- SAUCE_ACCESS_KEY=9b988f434ff8-fbca-8aa4-4ae3-35442987
+707 -13
View File
@@ -1,21 +1,713 @@
# NOTICE: Pending Breaking Change
<a name="1.2.27"></a>
# 1.2.27 prime-factorization (2014-11-20)
The next 1.3.0 release candidate (1.3.0-rc.2) will contain a perf-related change that is likely to
introduce breakages in some applications. The change will affect filters and function call
expressions, and will not call the function if the variables passed to the function are primitive
values and have not changed since the last digest loop.
Example:
## Bug Fixes
```html
//date filter would only be called if the 'timeCreated' property has changed
<span ng-bind="timeCreated|date"></span>
- **$animate:** clear the GCS cache even when no animation is detected
([f619d032](https://github.com/angular/angular.js/commit/f619d032c932752313c646b5295bad8a68ef3871),
[#8813](https://github.com/angular/angular.js/issues/8813))
- **$browser:**
- Cache `location.href` only during page reload phase
([434d7a09](https://github.com/angular/angular.js/commit/434d7a09039151c1e627ac156213905d06b7df10),
[#9235](https://github.com/angular/angular.js/issues/9235), [#9470](https://github.com/angular/angular.js/issues/9470))
- dont use history api when only the hash changes
([a6e6438d](https://github.com/angular/angular.js/commit/a6e6438dae1ed92b29608d0b8830b0a7fbb624ef),
[#9423](https://github.com/angular/angular.js/issues/9423), [#9424](https://github.com/angular/angular.js/issues/9424))
- handle async href on url change in <=IE9
([fe7d9ded](https://github.com/angular/angular.js/commit/fe7d9dedaa5ec3b3f56d9eb9c513cf99e40121ce),
[#9235](https://github.com/angular/angular.js/issues/9235))
- **$http:** add missing shortcut methods and missing docs
([ec4fe1bc](https://github.com/angular/angular.js/commit/ec4fe1bcab6f981103a10f860a3a00122aa78607),
[#9180](https://github.com/angular/angular.js/issues/9180), [#9321](https://github.com/angular/angular.js/issues/9321))
- **$location:**
- revert erroneous logic and backport refactorings from master
([1ee9b4ef](https://github.com/angular/angular.js/commit/1ee9b4ef5e4a795061d3aa19adefdeb7e0209eeb),
[#8492](https://github.com/angular/angular.js/issues/8492))
- allow 0 in path() and hash()
([f807d7ab](https://github.com/angular/angular.js/commit/f807d7ab4ebd18899154528ea9ed50d5bc25c57a))
- **$parse:** add quick check for Function constructor in fast path
([756640f5](https://github.com/angular/angular.js/commit/756640f5aa8f3fd0084bff50534e23976a6fff00))
- **$parse, events:** prevent accidental misuse of properties on $event
([4d0614fd](https://github.com/angular/angular.js/commit/4d0614fd0da12c5783dfb4956c330edac87e62fe),
[#9969](https://github.com/angular/angular.js/issues/9969))
- **ngMock:** $httpBackend should match data containing Date objects correctly
([1426b029](https://github.com/angular/angular.js/commit/1426b02980badfd322eb960d71bfb1a14d657847),
[#5127](https://github.com/angular/angular.js/issues/5127))
- **orderBy:** sort by identity if no predicate is given
([45b896a1](https://github.com/angular/angular.js/commit/45b896a16abbcbfcdfb9a95c2d10c76a805b57cc),
[#5847](https://github.com/angular/angular.js/issues/5847), [#4579](https://github.com/angular/angular.js/issues/4579), [#9403](https://github.com/angular/angular.js/issues/9403))
- **select:** ensure the label attribute is updated in Internet Explorer
([16833d0f](https://github.com/angular/angular.js/commit/16833d0fb6585117e9978d1accc3ade83e22e797),
[#9621](https://github.com/angular/angular.js/issues/9621), [#10042](https://github.com/angular/angular.js/issues/10042))
//custom filter would break if depends on data changed by user other than 'cost'
<span ng-bind="cost|i18nLocalizer">
## Performance Improvements
- **orderBy:** copy array with slice instead of for loop
([409bcb38](https://github.com/angular/angular.js/commit/409bcb3810a1622178268f7ff7f4130887a1a3dc),
[#9942](https://github.com/angular/angular.js/issues/9942))
<a name="1.3.3"></a>
# 1.3.3 undersea-arithmetic (2014-11-17)
## Bug Fixes
- **$http:** don't parse single space responses as JSON
([6f19a6fd](https://github.com/angular/angular.js/commit/6f19a6fd33ab72d3908e3418fba47ee8e1598fa6),
[#9907](https://github.com/angular/angular.js/issues/9907))
- **minErr:** stringify non-JSON compatible objects in error messages
([cf43ccdf](https://github.com/angular/angular.js/commit/cf43ccdf9b8665a2fd5d6aa52f80cb2d7c9bb7e2),
[#10085](https://github.com/angular/angular.js/issues/10085))
- **$rootScope:** handle cyclic references in scopes when creating error messages
([e80053d9](https://github.com/angular/angular.js/commit/e80053d91fd7c722e092a23d326384de2e552eb6),
[#10085](https://github.com/angular/angular.js/issues/10085))
- **ngRepeat:** support cyclic object references in error messages
([fa12c3c8](https://github.com/angular/angular.js/commit/fa12c3c86af7965d1b9d9a5dd3434755e9e04635),
[#9838](https://github.com/angular/angular.js/issues/9838), [#10065](https://github.com/angular/angular.js/issues/10065), [#10085](https://github.com/angular/angular.js/issues/10085))
- **ngMock:** call $interval callbacks even when invokeApply is false
([d81ff888](https://github.com/angular/angular.js/commit/d81ff8885b77f70c6417d7be3124d86d07447375),
[#10032](https://github.com/angular/angular.js/issues/10032))
- **ngPattern:** match behaviour of native HTML pattern attribute
([85eb9660](https://github.com/angular/angular.js/commit/85eb9660ef67c24d5104a6a1921bedad0bd1b57e),
[#9881](https://github.com/angular/angular.js/issues/9881), [#9888](https://github.com/angular/angular.js/issues/9888))
- **select:** ensure the label attribute is updated in Internet Explorer
([6604c236](https://github.com/angular/angular.js/commit/6604c2361427fba8c43a39dc2e92197390dfbdbe),
[#9621](https://github.com/angular/angular.js/issues/9621), [#10042](https://github.com/angular/angular.js/issues/10042))
## Features
- **$location:** allow to location to be changed during $locationChangeStart
([a9352c19](https://github.com/angular/angular.js/commit/a9352c19ce33f0393d6581547c7ea8dfc2a8b78f),
[#9607](https://github.com/angular/angular.js/issues/9607), [#9678](https://github.com/angular/angular.js/issues/9678))
- **$routeProvider:** allow setting caseInsensitiveMatch on the provider
([0db573b7](https://github.com/angular/angular.js/commit/0db573b7493f76abd94ff65ce660017d617e865b),
[#6477](https://github.com/angular/angular.js/issues/6477), [#9873](https://github.com/angular/angular.js/issues/9873))
## Performance Improvements
- **orderBy:** copy array with slice instead of for loop
([8eabc546](https://github.com/angular/angular.js/commit/8eabc5463c795d87f37e5a9eacbbb14435024061),
[#9942](https://github.com/angular/angular.js/issues/9942))
<a name="1.3.2"></a>
# 1.3.2 cardiovasculatory-magnification (2014-11-07)
## Bug Fixes
- **$compile:** do not rebind parent bound transclude functions
([841c0907](https://github.com/angular/angular.js/commit/841c0907556f525dbc4223609d808319fe0dd7e2),
[#9413](https://github.com/angular/angular.js/issues/9413))
- **$parse:**
- stateful interceptors override an `undefined` expression
([ed99821e](https://github.com/angular/angular.js/commit/ed99821e4dc621864f7e2d9a6b5305fca27fb7fa),
[#9821](https://github.com/angular/angular.js/issues/9821), [#9825](https://github.com/angular/angular.js/issues/9825))
- add quick check for Function constructor in fast path
([e676d642](https://github.com/angular/angular.js/commit/e676d642f5feb8d3ba88944634afb479ba525c36))
- **$parse, events:** prevent accidental misuse of properties on $event
([e057a9aa](https://github.com/angular/angular.js/commit/e057a9aa398ead209bd6bbf76e22d2d5562904fb))
- **ngRoute:** allow proto inherited properties in route params object
([b4770582](https://github.com/angular/angular.js/commit/b4770582f84f26c8ff7f2320a36a6b0ceff6e6cc),
[#8181](https://github.com/angular/angular.js/issues/8181), [#9731](https://github.com/angular/angular.js/issues/9731))
- **select:** use strict comparison for isSelected with selectAs
([9e305948](https://github.com/angular/angular.js/commit/9e305948e4965fb86b0c79985dc6e8c59a9c66af),
[#9639](https://github.com/angular/angular.js/issues/9639), [#9949](https://github.com/angular/angular.js/issues/9949))
## Features
- **ngAria:** announce ngMessages with aria-live
([187e4318](https://github.com/angular/angular.js/commit/187e43185dfb1bce6a318d95958c73cfb789d33c),
[#9834](https://github.com/angular/angular.js/issues/9834))
- **ngMock:** decorator that adds Scope#$countChildScopes and Scope#$countWatchers
([74981c9f](https://github.com/angular/angular.js/commit/74981c9f208b3617cbf00beafd61138d25c5d546),
[#9926](https://github.com/angular/angular.js/issues/9926), [#9871](https://github.com/angular/angular.js/issues/9871))
## Security Note
This release also contains security fixes for expression sandbox bypasses.
These issues affect only applications with known server-side XSS holes that are also using [CSP](https://developer.mozilla.org/en-US/docs/Web/Security/CSP) to secure their client-side code. If your application falls into this rare category, we recommend updating your version of Angular.
We'd like to thank security researches [Sebastian Lekies](https://twitter.com/sebastianlekies), [Jann Horn](http://thejh.net/), and [Gábor Molnár](https://twitter.com/molnar_g) for reporting these issues to us.
We also added a documentation page focused on security, which contains some of the best practices, DOs and DON'Ts. Please check out [https://docs.angularjs.org/guide/security](https://docs.angularjs.org/guide/security).
<a name="1.3.1"></a>
# 1.3.1 spectral-lobster (2014-10-31)
## Bug Fixes
- **$compile:** returning null when an optional controller is not found
([2cd5b4ec](https://github.com/angular/angular.js/commit/2cd5b4ec4409a818ccd33a6fbdeb99a3443a1809),
[#9404](https://github.com/angular/angular.js/issues/9404), [#9392](https://github.com/angular/angular.js/issues/9392))
- **$observe:** check if the attribute is undefined
([531a8de7](https://github.com/angular/angular.js/commit/531a8de72c439d8ddd064874bf364c00cedabb11),
[#9707](https://github.com/angular/angular.js/issues/9707), [#9720](https://github.com/angular/angular.js/issues/9720))
- **$parse:** support dirty-checking objects with null prototype
([28661d1a](https://github.com/angular/angular.js/commit/28661d1a8cc3a8454bad7ae531e027b1256476c9),
[#9568](https://github.com/angular/angular.js/issues/9568))
- **$sce:** use msie instead of $document[0].documentMode
([45252c3a](https://github.com/angular/angular.js/commit/45252c3a545336a0bac93be6ee28cde6afaa3cb4),
[#9661](https://github.com/angular/angular.js/issues/9661))
- **$templateRequest:** ignore JSON Content-Type header and content
([1bd473eb](https://github.com/angular/angular.js/commit/1bd473eb4587900086e0b6b308dcf1dcfe9760d9),
[#5756](https://github.com/angular/angular.js/issues/5756), [#9619](https://github.com/angular/angular.js/issues/9619))
- **i18n:** rename datetimeSymbols to be camelCase
([94f5a285](https://github.com/angular/angular.js/commit/94f5a285bfcf04d800afc462a7a37a3469d77f1a))
- **loader:** fix double spaces
([8b2f1a47](https://github.com/angular/angular.js/commit/8b2f1a47b584ceb98689f48538a2af73cd65dfd8),
[#9630](https://github.com/angular/angular.js/issues/9630))
- **ngMock:** $httpBackend should match data containing Date objects correctly
([1025f6eb](https://github.com/angular/angular.js/commit/1025f6ebf4e5933a12920889be00cd8ac8a106fa),
[#5127](https://github.com/angular/angular.js/issues/5127))
- **ngSanitize:** attribute name: xmlns:href -> xlink:href
([4cccf0f2](https://github.com/angular/angular.js/commit/4cccf0f2a89b002d63cb443e1e7b15f76dcef425),
[#9769](https://github.com/angular/angular.js/issues/9769))
- **select:** assign result of track exp to element value
([4b4098bf](https://github.com/angular/angular.js/commit/4b4098bfcae64f69c70a22393de1f3d9a0d3dc46),
[#9718](https://github.com/angular/angular.js/issues/9718), [#9592](https://github.com/angular/angular.js/issues/9592))
- **templateRequest:** allow empty html template
([52ceec22](https://github.com/angular/angular.js/commit/52ceec2229dc132b76da4e022c91474344f2d906),
[#9581](https://github.com/angular/angular.js/issues/9581))
- **testability:** escape regex chars in `findBindings` if using `exactMatch`
([02aa4f4b](https://github.com/angular/angular.js/commit/02aa4f4b85ee15922a1f2de8ba78f562c18518d0),
[#9595](https://github.com/angular/angular.js/issues/9595), [#9600](https://github.com/angular/angular.js/issues/9600))
## Features
- **$compile:** allow $watchCollection to be used in bi-directional bindings
([40bbc981](https://github.com/angular/angular.js/commit/40bbc9817845bf75581daee5d0ec30980affb0f5),
[#9725](https://github.com/angular/angular.js/issues/9725))
- **ngSanitize:** accept SVG elements and attributes
([a54b25d7](https://github.com/angular/angular.js/commit/a54b25d77999a85701dfc5396fef78e586a99667),
[#9578](https://github.com/angular/angular.js/issues/9578), [#9751](https://github.com/angular/angular.js/issues/9751))
<a name="1.3.0"></a>
# 1.3.0 superluminal-nudge (2014-10-13)
## Bug Fixes
- **$browser:**
- account for IE deserializing history.state on each read
([1efaf3dc](https://github.com/angular/angular.js/commit/1efaf3dc136f822703a9cda55afac7895a923ccb),
[#9587](https://github.com/angular/angular.js/issues/9587), [#9545](https://github.com/angular/angular.js/issues/9545))
- do not decode cookies that do not appear encoded
([9c995905](https://github.com/angular/angular.js/commit/9c9959059eb84f0f1d748b70b50ec47b7d23d065),
[#9211](https://github.com/angular/angular.js/issues/9211), [#9225](https://github.com/angular/angular.js/issues/9225))
- **$http:**
- allow empty json response
([9ba24c54](https://github.com/angular/angular.js/commit/9ba24c54d60e643b1450cc5cfa8f990bd524c130),
[#9532](https://github.com/angular/angular.js/issues/9532), [#9562](https://github.com/angular/angular.js/issues/9562))
- don't run transformData on HEAD methods
([6e4955a3](https://github.com/angular/angular.js/commit/6e4955a3086555d8ca30c29955faa213b39c6f27),
[#9528](https://github.com/angular/angular.js/issues/9528), [#9529](https://github.com/angular/angular.js/issues/9529))
- **$injector:** ensure $get method invoked with provider context
([372fa699](https://github.com/angular/angular.js/commit/372fa6993b2b1b4848aa4be3c3e11f69244fca6f),
[#9511](https://github.com/angular/angular.js/issues/9511), [#9512](https://github.com/angular/angular.js/issues/9512))
- **$location:** use clone of passed search() object
([c7a9009e](https://github.com/angular/angular.js/commit/c7a9009e143299f0e45a85d715ff22fc676d3f93),
[#9445](https://github.com/angular/angular.js/issues/9445))
- **$parse:** stabilize one-time literal expressions correctly
([874cac82](https://github.com/angular/angular.js/commit/874cac825bf29a936cb1b35f9af239687bc5e036))
- **formController:** remove scope reference when form is destroyed
([01f50e1a](https://github.com/angular/angular.js/commit/01f50e1a7b2bff7070616494774ec493f8133204),
[#9315](https://github.com/angular/angular.js/issues/9315))
- **jqLite:** remove native listener when all jqLite listeners were deregistered
([d71fb6f2](https://github.com/angular/angular.js/commit/d71fb6f2713f1a636f6e9c25479870ee9941ad18),
[#9509](https://github.com/angular/angular.js/issues/9509))
- **select:**
- add basic track by and select as support
([addfff3c](https://github.com/angular/angular.js/commit/addfff3c46311f59bdcd100351260006d457316f),
[#6564](https://github.com/angular/angular.js/issues/6564))
- manage select controller options correctly
([2435e2b8](https://github.com/angular/angular.js/commit/2435e2b8f84fde9495b8e9440a2b4f865b1ff541),
[#9418](https://github.com/angular/angular.js/issues/9418))
## Features
- **$anchorScroll:** support a configurable vertical scroll offset
([09c39d2c](https://github.com/angular/angular.js/commit/09c39d2ce687cdf0ac35dbb34a91f0d198c9d83a),
[#9368](https://github.com/angular/angular.js/issues/9368), [#2070](https://github.com/angular/angular.js/issues/2070), [#9360](https://github.com/angular/angular.js/issues/9360))
- **$animate:**
- introduce the $animate.animate() method
([02be700b](https://github.com/angular/angular.js/commit/02be700bda191b454de393f2805916f374a1d764))
- allow $animate to pass custom styles into animations
([e5f4d7b1](https://github.com/angular/angular.js/commit/e5f4d7b10ae5e6a17ab349995451c33b7d294245))
- **currencyFilter:** add fractionSize as optional parameter
([20685ffe](https://github.com/angular/angular.js/commit/20685ffe11036d4d604d13f0d792ca46497af4a1),
[#3642](https://github.com/angular/angular.js/issues/3642), [#3461](https://github.com/angular/angular.js/issues/3461), [#3642](https://github.com/angular/angular.js/issues/3642), [#7922](https://github.com/angular/angular.js/issues/7922))
- **jqLite:** add private jqLiteDocumentLoaded function
([0dd316ef](https://github.com/angular/angular.js/commit/0dd316efea209e5e5de3e456b4e6562f011a1294))
## Breaking Changes
- **$animate:** due to [e5f4d7b1](https://github.com/angular/angular.js/commit/e5f4d7b10ae5e6a17ab349995451c33b7d294245),
staggering animations that use transitions will now
always block the transition from starting (via `transition: 0s none`)
up until the stagger step kicks in. The former behaviour was that the
block was removed as soon as the pending class was added. This fix
allows for styles to be applied in the pending class without causing
an animation to trigger prematurely.
<a name="1.3.0-rc.5"></a>
# 1.3.0-rc.5 impossible-choreography (2014-10-08)
## Bug Fixes
- **$anchorScroll:** don't scroll to top when initializing and location hash is empty
([d5445c60](https://github.com/angular/angular.js/commit/d5445c601fafd6ecd38befeaa4c9ec7bb044127c),
[#8848](https://github.com/angular/angular.js/issues/8848), [#9393](https://github.com/angular/angular.js/issues/9393))
- **$animate:**
- ensure hidden elements with ngShow/ngHide stay hidden during animations
([39d0b368](https://github.com/angular/angular.js/commit/39d0b36826a077f7549a70d0cf3edebe90a10aaa),
[#9103](https://github.com/angular/angular.js/issues/9103), [#9493](https://github.com/angular/angular.js/issues/9493))
- permit class-based animations for leave operations if ngAnimateChildren is enabled
([df1a00b1](https://github.com/angular/angular.js/commit/df1a00b11ac2722f4da441837795985f12682030),
[#8092](https://github.com/angular/angular.js/issues/8092), [#9491](https://github.com/angular/angular.js/issues/9491))
- ensure that class-based animations only consider the most recent DOM operations
([c93924ed](https://github.com/angular/angular.js/commit/c93924ed275a62683b85c82f1c6c2e19d5662c9a),
[#8946](https://github.com/angular/angular.js/issues/8946), [#9458](https://github.com/angular/angular.js/issues/9458))
- abort class-based animations if the element is removed during digest
([613d0a32](https://github.com/angular/angular.js/commit/613d0a3212de8dc01c817ca8526e09c57978a621),
[#8796](https://github.com/angular/angular.js/issues/8796))
- clear the GCS cache even when no animation is detected
([cb85cbce](https://github.com/angular/angular.js/commit/cb85cbcec1c876db6062a0dc0bad80f842782194),
[#8813](https://github.com/angular/angular.js/issues/8813))
- **$browser:**
- Cache `location.href` only during page reload phase
([8ee1ba4b](https://github.com/angular/angular.js/commit/8ee1ba4b94d6fccff06d8781f7ed256c6ce664ff),
[#9235](https://github.com/angular/angular.js/issues/9235), [#9455](https://github.com/angular/angular.js/issues/9455))
- dont use the history API when only the hash changes
([7cb01a80](https://github.com/angular/angular.js/commit/7cb01a80beec669d8f6aae1dc211d2f0b7d4eac4),
[#9423](https://github.com/angular/angular.js/issues/9423), [#9424](https://github.com/angular/angular.js/issues/9424),
[858360b6](https://github.com/angular/angular.js/commit/858360b680a2bb5c19429c1be1c9506700cda476),
[0656484d](https://github.com/angular/angular.js/commit/0656484d3e709c5162570b0dd6473b0b6140e5b2),
[#9143](https://github.com/angular/angular.js/issues/9143), [#9406](https://github.com/angular/angular.js/issues/9406))
- handle async href on url change in <=IE9
([404b95fe](https://github.com/angular/angular.js/commit/404b95fe30a1bcd1313adafbd0018578d5b21d3d),
[#9235](https://github.com/angular/angular.js/issues/9235))
- **$compile:**
- handle the removal of an interpolated attribute
([a75546af](https://github.com/angular/angular.js/commit/a75546afdf41adab786eda30c258190cd4c5f1ae),
[#9236](https://github.com/angular/angular.js/issues/9236), [#9240](https://github.com/angular/angular.js/issues/9240))
- remove comment nodes from templates before asserting single root node
([feba0174](https://github.com/angular/angular.js/commit/feba0174db0f8f929273beb8b90691734a9292e2),
[#9212](https://github.com/angular/angular.js/issues/9212), [#9215](https://github.com/angular/angular.js/issues/9215))
- use the correct namespace for transcluded svg elements
([f3539f3c](https://github.com/angular/angular.js/commit/f3539f3cb5d9477f50f065c6a0ac7d6ca0a31092),
[#9344](https://github.com/angular/angular.js/issues/9344), [#9415](https://github.com/angular/angular.js/issues/9415))
- **$http:** honor application/json response header and parse json primitives
([7b6c1d08](https://github.com/angular/angular.js/commit/7b6c1d08aceba6704a40302f373400aed9ed0e0b),
[#2973](https://github.com/angular/angular.js/issues/2973))
- **$injector:** throw when factory $get method does not return a value
([0d3b69a5](https://github.com/angular/angular.js/commit/0d3b69a5f27b41745b504c7ffd8d72653bac1f85),
[#4575](https://github.com/angular/angular.js/issues/4575), [#9210](https://github.com/angular/angular.js/issues/9210))
- **$location:** allow `0` in `path()` and `hash()`
([b8c5b871](https://github.com/angular/angular.js/commit/b8c5b87119a06edb8e8d1cefad81ee8d1f64f070))
- **form:** fix submit prevention
([86c7d122](https://github.com/angular/angular.js/commit/86c7d1221c706993044583d51a0c61423fee5bcf),
[#3370](https://github.com/angular/angular.js/issues/3370), [#3776](https://github.com/angular/angular.js/issues/3776))
- **ngAnimate:** defer DOM operations for changing classes to postDigest
([667183a8](https://github.com/angular/angular.js/commit/667183a8c79d6ffce571a2be78c05dc76503b222),
[#8234](https://github.com/angular/angular.js/issues/8234), [#9263](https://github.com/angular/angular.js/issues/9263))
- **orderBy:** sort by identity if no predicate is given
([607f016a](https://github.com/angular/angular.js/commit/607f016a0ba705ce40df0164360fb96a9d7f5912),
[#5847](https://github.com/angular/angular.js/issues/5847), [#4579](https://github.com/angular/angular.js/issues/4579), [#9403](https://github.com/angular/angular.js/issues/9403))
- **select:**
- throw for `selectAs` and `trackBy`
([30996f82](https://github.com/angular/angular.js/commit/30996f82afa03cd11771b3267e9367ecf9af6e6d))
- use `$viewValue` instead of `$modelValue`
([f7174169](https://github.com/angular/angular.js/commit/f7174169f4f710d605f6a67f39f90a67a07d4cab),
[#8929](https://github.com/angular/angular.js/issues/8929))
## Features
- **$location:**
- add support for History API state handling ([6fd36dee](https://github.com/angular/angular.js/commit/6fd36deed954b338e48390862971d465148dc1f2),
[#9027](https://github.com/angular/angular.js/issues/9027))
- allow automatic rewriting of links to be disabled
([b3e09be5](https://github.com/angular/angular.js/commit/b3e09be58960b913fee3869bf36e7de3305bbe00),
[#5487](https://github.com/angular/angular.js/issues/5487))
- **$route:** ability to cancel $routeChangeStart event
([f4ff11b0](https://github.com/angular/angular.js/commit/f4ff11b01e6a5f9a9eb25a38d327dfaadbd7c80c),
[#5581](https://github.com/angular/angular.js/issues/5581), [#5714](https://github.com/angular/angular.js/issues/5714), [#9502](https://github.com/angular/angular.js/issues/9502))
## Performance Improvements
- **$animate:**
- access DOM less in resolveElementClasses
([22358cf9](https://github.com/angular/angular.js/commit/22358cf9c703d67f3cf9eb4899404b09578a5fad))
- don't join classes before it's necessary in resolveElementClasses
([003c44ec](https://github.com/angular/angular.js/commit/003c44eceee54c3398b0d2971fd97a512d7f7cec))
- **ngBind:** set textContent rather than using element.text()
([074a146d](https://github.com/angular/angular.js/commit/074a146d8b1ee7c93bf6d5892448a5c2a0143a28),
[#9369](https://github.com/angular/angular.js/issues/9369), [#9396](https://github.com/angular/angular.js/issues/9396))
## Breaking Changes
- **$compile:** due to [feba0174](https://github.com/angular/angular.js/commit/feba0174db0f8f929273beb8b90691734a9292e2),
If a template contains directives within comment nodes, and there is more than a single node in the
template, those comment nodes are removed. The impact of this breaking change is expected to be
quite low.
Closes #9212
Closes #9215
- **ngAnimate:** due to [667183a8](https://github.com/angular/angular.js/commit/667183a8c79d6ffce571a2be78c05dc76503b222),
The `$animate` CSS class API will always defer changes until the end of the next digest. This allows ngAnimate
to coalesce class changes which occur over a short period of time into 1 or 2 DOM writes, rather than
many. This prevents jank in browsers such as IE, and is generally a good thing.
If you find that your classes are not being immediately applied, be sure to invoke `$digest()`.
Closes #8234
Closes #9263
- **$select:** due to [30996f8](https://github.com/angular/angular.js/commit/30996f82afa03cd11771b3267e9367ecf9af6e6d)
`ngOptions` will now throw an error when the comprehension expressions contains both a `select as`
and `track by` expression.
These expressions are fundamentally incompatible because it is not possible to reliably and
consistently determine the parent object of a model, since `select as` can assign any child of a
`value` as the model value.
Prior to refactorings in this release, neither of these expressions worked correctly independently,
and did not work at all when combined.
See #6564
- **$route:** due to [f4ff11b0](https://github.com/angular/angular.js/commit/f4ff11b01e6a5f9a9eb25a38d327dfaadbd7c80c),
Order of events has changed.
Previously: `$locationChangeStart` -> `$locationChangeSuccess`
-> `$routeChangeStart` -> `$routeChangeSuccess`
Now: `$locationChangeStart` -> `$routeChangeStart`
-> `$locationChangeSuccess` -> -> `$routeChangeSuccess`
Fixes #5581
Closes #5714
Closes #9502- **ngAnimate:** due to [667183a8](https://github.com/angular/angular.js/commit/667183a8c79d6ffce571a2be78c05dc76503b222),
The $animate class API will always defer changes until the end of the next digest. This allows ngAnimate
to coalesce class changes which occur over a short period of time into 1 or 2 DOM writes, rather than
many. This prevents jank in browsers such as IE, and is generally a good thing.
If you're finding that your classes are not being immediately applied, be sure to invoke $digest().
Closes #8234
Closes #9263
<a name="1.3.0-rc.4"></a>
# 1.3.0-rc.4 unicorn-hydrafication (2014-10-01)
## Bug Fixes
- **$compile:**
- get $$observe listeners array as own property
([a27d827c](https://github.com/angular/angular.js/commit/a27d827c22b0b6b3ba6b7495cf4fc338c6934b37),
[#9343](https://github.com/angular/angular.js/issues/9343), [#9345](https://github.com/angular/angular.js/issues/9345))
- Resolve leak with asynchronous compilation
([6303c3dc](https://github.com/angular/angular.js/commit/6303c3dcf64685458fc84aa12289f5c9d57f4e47),
[#9199](https://github.com/angular/angular.js/issues/9199), [#9079](https://github.com/angular/angular.js/issues/9079), [#8504](https://github.com/angular/angular.js/issues/8504), [#9197](https://github.com/angular/angular.js/issues/9197))
- connect transclude scopes to their containing scope to prevent memory leaks
([fb0c77f0](https://github.com/angular/angular.js/commit/fb0c77f0b66ed757a56af13f81b943419fdcbd7f),
[#9095](https://github.com/angular/angular.js/issues/9095), [#9281](https://github.com/angular/angular.js/issues/9281))
- sanitize srcset attribute
([ab80cd90](https://github.com/angular/angular.js/commit/ab80cd90661396dbb1c94c5f4dd2d11ee8f6b6af))
- **input:**
- register builtin parsers/formatters before anyone else
([10644432](https://github.com/angular/angular.js/commit/10644432ca9d5da69ce790a8d9e691640f333711),
[#9218](https://github.com/angular/angular.js/issues/9218), [#9358](https://github.com/angular/angular.js/issues/9358))
- correctly handle invalid model values for `input[date/time/…]`
([a0bfdd0d](https://github.com/angular/angular.js/commit/a0bfdd0d60882125f614a91c321f12f730735e7b),
[#8949](https://github.com/angular/angular.js/issues/8949), [#9375](https://github.com/angular/angular.js/issues/9375))
- **ngModel:** do not parse undefined viewValue when validating
([92f05e5a](https://github.com/angular/angular.js/commit/92f05e5a5900713301e64373d7b7daa45a88278b),
[#9106](https://github.com/angular/angular.js/issues/9106), [#9260](https://github.com/angular/angular.js/issues/9260))
- **ngView:** use animation promises ensure that only one leave animation occurs at a time
([3624e380](https://github.com/angular/angular.js/commit/3624e3800fb3ccd2e9ea361a763e20131fd42c29),
[#9355](https://github.com/angular/angular.js/issues/9355), [#7606](https://github.com/angular/angular.js/issues/7606), [#9374](https://github.com/angular/angular.js/issues/9374))
- **select:** make ctrl.hasOption method consistent
([2bcd02dc](https://github.com/angular/angular.js/commit/2bcd02dc1a6b28b357d47c83be3bed5c9a38417c),
[#8761](https://github.com/angular/angular.js/issues/8761))
## Features
- **$compile:** optionally get controllers from ancestors only
([07e3abc7](https://github.com/angular/angular.js/commit/07e3abc7dda872adc3fb25cb3e133f86f494b35d),
[#4518](https://github.com/angular/angular.js/issues/4518), [#4540](https://github.com/angular/angular.js/issues/4540), [#8240](https://github.com/angular/angular.js/issues/8240), [#8511](https://github.com/angular/angular.js/issues/8511))
- **Scope:** allow the parent of a new scope to be specified on creation
([6417a3e9](https://github.com/angular/angular.js/commit/6417a3e9eb7ab0011cefada8db855aa929a64ff8))
## Performance Improvements
- **$rootScope:** moving internal queues out of the Scope instances
([b1192518](https://github.com/angular/angular.js/commit/b119251827cea670051198e1b48af7ee0c9f2a1b),
[#9071](https://github.com/angular/angular.js/issues/9071))
- **benchmark:** add ngBindOnce benchmarks to largetable-bp
([2c8b4648](https://github.com/angular/angular.js/commit/2c8b4648526acf5c2645de8408a6d9ace2144b5f))
- **ngForm,ngModel:** move initial addClass to the compile phase
([b1ee5386](https://github.com/angular/angular.js/commit/b1ee5386d584f208bce6d3b613afdb3bae9df76a),
[#8268](https://github.com/angular/angular.js/issues/8268))
## Breaking Changes
- **$compile:** due to [fb0c77f0](https://github.com/angular/angular.js/commit/fb0c77f0b66ed757a56af13f81b943419fdcbd7f),
`$transclude` functions no longer attach `$destroy` event handlers to the
transcluded content, and so the associated transclude scope will not automatically
be destroyed if you remove a transcluded element from the DOM using direct DOM
manipulation such as the jquery `remove()` method.
If you want to explicitly remove DOM elements inside your directive that have
been compiled, and so potentially contain child (and transcluded) scopes, then
it is your responsibility to get hold of the scope and destroy it at the same time.
The suggested approach is to create a new child scope of your own around any DOM
elements that you wish to manipulate in this way and destroy those scopes if you
remove their contents - any child scopes will then be destroyed and cleaned up
automatically.
Note that all the built-in directives that manipulate the DOM (ngIf, ngRepeat,
ngSwitch, etc) already follow this best practice, so if you only use these for
manipulating the DOM then you do not have to worry about this change.
Closes #9095
Closes #9281
- **$parse:** due to [5572b40b](https://github.com/angular/angular.js/commit/5572b40b15ed06969c8e0e92866c5afd088484b4),
- $scope['this'] no longer exits on the $scope object
- $parse-ed expressions no longer allow chaining 'this' such as this['this'] or $parent['this']
- 'this' in $parse-ed expressions can no longer be overriden, if a variable named 'this' is put on the scope it must be accessed using this['this']
Closes #9105
- **input:** due to [1eda1836](https://github.com/angular/angular.js/commit/1eda18365a348c9597aafba9d195d345e4f13d1e),
(Note: this change landed in 1.3.0-rc.3, but was not considered a breaking change at the time).
For text based inputs (text, email, url), the `$viewValue` will now always be converted to a string,
regardless of what type the value is on the model.
To migrate, any code or expressions that expect the `$viewValue` to be anything other than string
should be updated to expect a string.
- **input:** due to a0bfdd0d60882125f614a91c321f12f730735e7b (see #8949),
Similar to `input[number]` Angular will now throw if the model value
for a `input[date]` is not a `Date` object. Previously, Angular only
showed an empty string instead.
Angular does not set validation errors on the `<input>` in this case
as those errors are shown to the user, but the erroneous state was
caused by incorrect application logic and not by the user.
<a name="1.2.26"></a>
# 1.2.26 captivating-disinterest (2014-10-01)
## Bug Fixes
- **$compile:** Resolve leak with asynchronous compilation
([5c9c1973](https://github.com/angular/angular.js/commit/5c9c19730526d5df6f16c523e578e5305f3796d0),
[#9199](https://github.com/angular/angular.js/issues/9199), [#9079](https://github.com/angular/angular.js/issues/9079), [#8504](https://github.com/angular/angular.js/issues/8504), [#9197](https://github.com/angular/angular.js/issues/9197))
- **select:** make ctrl.hasOption method consistent
([11d2242d](https://github.com/angular/angular.js/commit/11d2242df65b2ade0dabe366a0c42963b6d37df5),
[#8761](https://github.com/angular/angular.js/issues/8761))
<a name="1.3.0-rc.3"></a>
# 1.3.0-rc.3 aggressive-pacification (2014-09-23)
## Bug Fixes
- **ngModel:** support milliseconds in time and datetime
([4b83f6ca](https://github.com/angular/angular.js/commit/4b83f6ca2c15bd65fe2b3894a02c04f9967fbff4),
[#8874](https://github.com/angular/angular.js/issues/8874))
## Features
- **$location:** add ability to opt-out of `<base>` tag requirement in html5Mode
([dc3de7fb](https://github.com/angular/angular.js/commit/dc3de7fb7a14c38b5c3dc7decfafb0b51d422dd1),
[#8934](https://github.com/angular/angular.js/issues/8934))
- **formController:** add $setUntouched to propagate untouched state
([fd899755](https://github.com/angular/angular.js/commit/fd8997551f9ed4431f5e99d61f637139485076b9),
[#9050](https://github.com/angular/angular.js/issues/9050))
- **input:** support dynamic element validation
([729c238e](https://github.com/angular/angular.js/commit/729c238e19ab27deff01448d79342ea53721bfed),
[#4791](https://github.com/angular/angular.js/issues/4791), [#1404](https://github.com/angular/angular.js/issues/1404))
- **ngAria:** add an ngAria module to make a11y easier
([d1434c99](https://github.com/angular/angular.js/commit/d1434c999a66c6bb915ee1a8b091e497d288d940),
[#5486](https://github.com/angular/angular.js/issues/5486))
## Performance Improvements
- **map:** use Array.prototype.map
([a591e8b8](https://github.com/angular/angular.js/commit/a591e8b8d302efefd67bf0d5c4bad300a5f3aded))
## Breaking Changes
- **$location:** due to [dc3de7fb](https://github.com/angular/angular.js/commit/dc3de7fb7a14c38b5c3dc7decfafb0b51d422dd1),
The $location.html5Mode API has changed to allow enabling html5Mode by
passing an object (as well as still supporting passing a boolean). Symmetrically, the
method now returns an object instead of a boolean value.
To migrate, follow the code example below:
Before:
var mode = $locationProvider.html5Mode();
After:
var mode = $locationProvider.html5Mode().enabled;
Fixes #8934
<a name="1.2.25"></a>
# 1.2.25 hypnotic-gesticulation (2014-09-16)
## Bug Fixes
- **i18n:** fix typo at i18n generation code
([1b6d74cc](https://github.com/angular/angular.js/commit/1b6d74cc9f7f7b7bd529abe6ce612de3ae661601))
- **ngLocale:** Regenerate Locale Files
([06c76694](https://github.com/angular/angular.js/commit/06c76694ac9b2280594712e6a4b46a1d5987d098))
- **select:** update option labels when model changes
([d89d59f4](https://github.com/angular/angular.js/commit/d89d59f453d4e28be4f595fea7e2c4ff2338351f),
[#9025](https://github.com/angular/angular.js/issues/9025))
<a name="1.3.0-rc.2"></a>
# 1.3.0-rc.2 tactile-perception (2014-09-16)
## Bug Fixes
- **$compile:** update `'@'`-bindings in controller when `bindToController` is `true`
([e7ac08a0](https://github.com/angular/angular.js/commit/e7ac08a0619d2bdc91c125d341772b4fbc0d5a78),
[#9052](https://github.com/angular/angular.js/issues/9052), [#9077](https://github.com/angular/angular.js/issues/9077))
- **$parse:** ensure CSP assignable expressions have `assign()`
([d13b4bd1](https://github.com/angular/angular.js/commit/d13b4bd1f5f2abaad00f5d1bf81f79549a8d0e46),
[#9048](https://github.com/angular/angular.js/issues/9048))
- **i18n:** fix typo at i18n generation code
([eb4afd45](https://github.com/angular/angular.js/commit/eb4afd45f77d7d67744e01ce63a831c13c2b22e8))
- **input:** always pass in the model value to `ctrl.$isEmpty`
([3e51b84b](https://github.com/angular/angular.js/commit/3e51b84bc19f7e6acc61cb536ddcdbfed307c831),
[#5164](https://github.com/angular/angular.js/issues/5164), [#9017](https://github.com/angular/angular.js/issues/9017))
- **jqLite:** fix `event.stopImmediatePropagation()` so it works as expected
([30354c58](https://github.com/angular/angular.js/commit/30354c58fe2bd371df364f7a3f55b270692a4051),
[#4833](https://github.com/angular/angular.js/issues/4833))
- **ngLocale:** Regenerate Locale Files
([6a96a820](https://github.com/angular/angular.js/commit/6a96a8200aff4749bc84c44a1e8018b09d9ebdb4),
[#8931](https://github.com/angular/angular.js/issues/8931), [#8583](https://github.com/angular/angular.js/issues/8583), [#7799](https://github.com/angular/angular.js/issues/7799))
- **ngModel:**
- do not reset bound date objects
([1a1ef629](https://github.com/angular/angular.js/commit/1a1ef62903c8fdf4ceb81277d966a8eff67f0a96),
[#6666](https://github.com/angular/angular.js/issues/6666))
- dont clear the model when an external validator failed
([9314719d](https://github.com/angular/angular.js/commit/9314719d1eb5f480b877f5513f6e0e474edcb67d),
[#8357](https://github.com/angular/angular.js/issues/8357), [#8080](https://github.com/angular/angular.js/issues/8080))
- **ngResource:** make badcfg error message more helpful
([a3962f0d](https://github.com/angular/angular.js/commit/a3962f0df3f9b8382b47952f9e4fcb48a4cc098b),
[#9005](https://github.com/angular/angular.js/issues/9005), [#9010](https://github.com/angular/angular.js/issues/9010))
- **select:** update option labels when model changes
([46274102](https://github.com/angular/angular.js/commit/46274102454038ee7fd4543a32166e9bbbc98904),
[#9025](https://github.com/angular/angular.js/issues/9025))
## Features
- **limitTo:** support numeric input to limitTo
([1c8a7459](https://github.com/angular/angular.js/commit/1c8a7459c90efc77b1a0987f976e3bddab4565fe),
[#8926](https://github.com/angular/angular.js/issues/8926))
- **ngInclude:** add template url parameter to events
([fd2d6c02](https://github.com/angular/angular.js/commit/fd2d6c02f9654e753d3655a3377a9534f7a54de3),
[#8453](https://github.com/angular/angular.js/issues/8453), [#8454](https://github.com/angular/angular.js/issues/8454))
## Performance Improvements
- **$compile:** move `$$isolateBinding` creation to directive factory instead of on each link
([56f09f0b](https://github.com/angular/angular.js/commit/56f09f0b44048b62f964d29db4d3d2630662f6ea))
- **$parse:**
- execute watched expressions only when the inputs change
([fca6be71](https://github.com/angular/angular.js/commit/fca6be71274e537c7df86ae9e27a3bd1597e9ffa),
[#9006](https://github.com/angular/angular.js/issues/9006), [#9082](https://github.com/angular/angular.js/issues/9082))
- remove `binaryFn` and `valueFn` wrappers from filter expressions
([67919c80](https://github.com/angular/angular.js/commit/67919c808771a9b185a9d552cd32a90748d36666))
## Breaking Changes
- **$parse:** due to [fca6be71](https://github.com/angular/angular.js/commit/fca6be71274e537c7df86ae9e27a3bd1597e9ffa),
all filters are assumed to be stateless functions
Previously it was just a good practice to make all filters stateless. Now
it's a requirement in order for the model change-observation to pick up
all changes.
If an existing filter is statefull, it can be flagged as such but keep in
mind that this will result in a significant performance-penalty (or rather
lost opportunity to benefit from a major perf improvement) that will
affect the `$digest` duration.
To flag a filter as stateful do the following:
```javascript
myApp.filter('myFilter', function() {
function myFilter(input) { ... };
myFilter.$stateful = true;
return myFilter;
});
```
<a name="1.3.0-rc.1"></a>
# 1.3.0-rc.1 backyard-atomicity (2014-09-09)
@@ -136,8 +828,8 @@ Example:
angular.module("switchChangeWorkaround", []).
directive("onSwitchChanged", function() {
return {
linke: function($scope, $attrs) {
$scope.$parent.$eval($attrs.change);
link: function($scope, $element, $attrs) {
$scope.$parent.$eval($attrs.onSwitchChanged);
}
};
});
@@ -928,6 +1620,8 @@ Closes #8230
- **jQuery:** due to [9e7cb3c3](https://github.com/angular/angular.js/commit/9e7cb3c37543008e6236bb5a2c4536df2e1e43a9),
Angular no longer supports jQuery versions below 2.1.1.
- **$q:** due to [23bc92b1](https://github.com/angular/angular.js/commit/23bc92b17df882a907fb326320f0622717fefe7b),
Promises methods are no longer enumerated when using for-loops with `hasOwnProperty` check. E.g. `angular.extends`
<a name="1.2.22"></a>
+4 -4
View File
@@ -65,13 +65,13 @@ Help us to maximize the effort we can spend fixing issues and adding new
features, by not reporting duplicate issues. Providing the following information will increase the
chances of your issue being dealt with quickly:
* **Overview of the issue** - if an error is being thrown a non-minified stack trace helps
* **Overview of the Issue** - if an error is being thrown a non-minified stack trace helps
* **Motivation for or Use Case** - explain why this is a bug for you
* **Angular Version(s)** - is it a regression?
* **Browsers and Operating System** - is this a problem with all browsers or only IE8?
* **Reproduce the error** - provide a live example (using [Plunker][plunker] or
* **Reproduce the Error** - provide a live example (using [Plunker][plunker] or
[JSFiddle][jsfiddle]) or a unambiguous set of steps.
* **Related issues** - has a similar issue been reported before?
* **Related Issues** - has a similar issue been reported before?
* **Suggest a Fix** - if you can't fix the bug yourself, perhaps you can point to what might be
causing the problem (line of code or commit)
@@ -172,7 +172,7 @@ To ensure consistency throughout the source code, keep these rules in mind as yo
* **Do not use namespaces**: Instead, wrap the entire angular code base in an anonymous closure and
export our API explicitly rather than implicitly.
* Wrap all code at **100 characters**.
* Instead of complex inheritance hierarchies, we **prefer simple objects**. We use prototypical
* Instead of complex inheritance hierarchies, we **prefer simple objects**. We use prototypal
inheritance only when absolutely necessary.
* We **love functions and closures** and, whenever possible, prefer them over objects.
* To write concise code that can be better minified, we **use aliases internally** that map to the
+5 -4
View File
@@ -6,10 +6,11 @@ use good old HTML (or HAML, Jade and friends!) as your template language and let
syntax to express your applications components clearly and succinctly. It automatically
synchronizes data from your UI (view) with your JavaScript objects (model) through 2-way data
binding. To help you structure your application better and make it easy to test, AngularJS teaches
the browser how to do dependency injection and inversion of control. Oh yeah and it also helps with
server-side communication, taming async callbacks with promises and deferreds; and makes client-side
navigation and deeplinking with hashbang urls or HTML5 pushState a piece of cake. The best of all:
it makes development fun!
the browser how to do dependency injection and inversion of control.
Oh yeah and it helps with server-side communication, taming async callbacks with promises and
deferreds. It also makes client-side navigation and deeplinking with hashbang urls or HTML5 pushState a
piece of cake. The best of all: it makes development fun!
* Web site: http://angularjs.org
* Tutorial: http://docs.angularjs.org/tutorial
-3
View File
@@ -26,7 +26,6 @@ This process based on the idea of minimizing user pain
* You can triage older issues as well
* Triage to your heart's content
1. Assign yourself: Pick an issue that is not assigned to anyone and assign it to you
1. Understandable? - verify if the description of the request is clear.
* If not, [close it][] according to the instructions below and go to the last step.
1. Duplicate?
@@ -36,7 +35,6 @@ This process based on the idea of minimizing user pain
* Label `Type: Bug`
* Reproducible? - Steps to reproduce the bug are clear. If they are not, ask for a clarification. If there's no reply after a week, [close it][].
* Reproducible on master? - <http://code.angularjs.org/snapshot/>
1. Non bugs:
* Label `Type: Feature`, `Type: Chore`, or `Type: Perf`
* Belongs in core? Often new features should be implemented as a third-party module rather than an addition to the core.
@@ -59,7 +57,6 @@ This process based on the idea of minimizing user pain
* In rare cases, it's ok to have multiple components.
1. Label `PRs plz!` - These issues are good targets for PRs from the open source community. Apply to issues where the problem and solution are well defined in the comments, and it's not too complex.
1. Label `origin: google` for issues from Google
1. Assign a milestone:
* Backlog - triaged fixes and features, should be the default choice
* Current 1.x.y milestone (e.g. 1.3.0-beta-2) - regressions and urgent bugs only
+3 -1
View File
@@ -112,7 +112,7 @@ var printSection = function(stream, title, section, printCommitLinks) {
}
stream.write(')\n');
} else {
stream.write(util.format('%s %s', prefix, commit.subject));
stream.write(util.format('%s %s\n', prefix, commit.subject));
}
});
});
@@ -188,6 +188,7 @@ var getPreviousTag = function() {
var generate = function(version, file) {
getPreviousTag().then(function(tag) {
console.log('Reading git log since', tag);
readGitLog('^fix|^feat|^perf|BREAKING', tag).then(function(commits) {
@@ -201,6 +202,7 @@ var generate = function(version, file) {
// publish for testing
exports.parseRawCommit = parseRawCommit;
exports.printSection = printSection;
// hacky start if not run by jasmine :-D
if (process.argv.join('').indexOf('jasmine-node') === -1) {
+62 -1
View File
@@ -1,4 +1,4 @@
/* global describe: false, it: false, expect: false */
/* global describe: false, beforeEach: false, afterEach: false, it: false, expect: false */
'use strict';
@@ -44,4 +44,65 @@ describe('changelog.js', function() {
expect(msg.breaking).toEqual(' first breaking change\nsomething else\nanother line with more info\n');
});
});
describe('printSection', function() {
var output;
var streamMock = {
write: function(str) {
output += str;
}
};
beforeEach(function() {
output = '';
});
it('should add a new line at the end of each breaking change list item ' +
'when there is 1 item per component', function() {
var title = 'test';
var printCommitLinks = false;
var section = {
module1: [{subject: 'breaking change 1'}],
module2: [{subject: 'breaking change 2'}]
};
var expectedOutput =
'\n' + '## test\n\n' +
'- **module1:** breaking change 1\n' +
'- **module2:** breaking change 2\n' +
'\n';
ch.printSection(streamMock, title, section, printCommitLinks);
expect(output).toBe(expectedOutput);
});
it('should add a new line at the end of each breaking change list item ' +
'when there are multiple items per component', function() {
var title = 'test';
var printCommitLinks = false;
var section = {
module1: [
{subject: 'breaking change 1.1'},
{subject: 'breaking change 1.2'}
],
module2: [
{subject: 'breaking change 2.1'},
{subject: 'breaking change 2.2'}
]
};
var expectedOutput =
'\n' + '## test\n\n' +
'- **module1:**\n' +
' - breaking change 1.1\n' +
' - breaking change 1.2\n' +
'- **module2:**\n' +
' - breaking change 2.1\n' +
' - breaking change 2.2\n' +
'\n';
ch.printSection(streamMock, title, section, printCommitLinks);
expect(output).toBe(expectedOutput);
});
});
});
+4 -4
View File
@@ -316,10 +316,10 @@ iframe.example {
}
.search-results-group.col-group-api { width:30%; }
.search-results-group.col-group-guide { width:30%; }
.search-results-group.col-group-tutorial { width:25%; }
.search-results-group.col-group-guide,
.search-results-group.col-group-tutorial { width:20%; }
.search-results-group.col-group-misc,
.search-results-group.col-group-error { float:right; clear:both; width:15% }
.search-results-group.col-group-error { width:15%; float: right; }
.search-results-group.col-group-api .search-result {
@@ -391,7 +391,6 @@ iframe.example {
position:fixed;
top:120px;
bottom:0;
padding-bottom:120px;
overflow:auto;
}
@@ -412,6 +411,7 @@ iframe.example {
.main-body-grid .side-navigation {
position:relative;
padding-bottom:120px;
}
.main-body-grid .side-navigation.ng-hide {
@@ -1,284 +0,0 @@
'use strict';
var directive = {};
var service = { value: {} };
var DEPENDENCIES = {
'angular.js': 'http://code.angularjs.org/' + angular.version.full + '/angular.min.js',
'angular-resource.js': 'http://code.angularjs.org/' + angular.version.full + '/angular-resource.min.js',
'angular-route.js': 'http://code.angularjs.org/' + angular.version.full + '/angular-route.min.js',
'angular-animate.js': 'http://code.angularjs.org/' + angular.version.full + '/angular-animate.min.js',
'angular-sanitize.js': 'http://code.angularjs.org/' + angular.version.full + '/angular-sanitize.min.js',
'angular-cookies.js': 'http://code.angularjs.org/' + angular.version.full + '/angular-cookies.min.js'
};
function escape(text) {
return text.
replace(/\&/g, '&amp;').
replace(/\</g, '&lt;').
replace(/\>/g, '&gt;').
replace(/"/g, '&quot;');
}
/**
* http://stackoverflow.com/questions/451486/pre-tag-loses-line-breaks-when-setting-innerhtml-in-ie
* http://stackoverflow.com/questions/195363/inserting-a-newline-into-a-pre-tag-ie-javascript
*/
function setHtmlIe8SafeWay(element, html) {
var newElement = angular.element('<pre>' + html + '</pre>');
element.empty();
element.append(newElement.contents());
return element;
}
directive.jsFiddle = function(getEmbeddedTemplate, escape, script) {
return {
terminal: true,
link: function(scope, element, attr) {
var name = '',
stylesheet = '<link rel="stylesheet" href="http://twitter.github.com/bootstrap/assets/css/bootstrap.css">\n',
fields = {
html: '',
css: '',
js: ''
};
angular.forEach(attr.jsFiddle.split(' '), function(file, index) {
var fileType = file.split('.')[1];
if (fileType == 'html') {
if (index == 0) {
fields[fileType] +=
'<div ng-app' + (attr.module ? '="' + attr.module + '"' : '') + '>\n' +
getEmbeddedTemplate(file, 2);
} else {
fields[fileType] += '\n\n\n <!-- CACHE FILE: ' + file + ' -->\n' +
' <script type="text/ng-template" id="' + file + '">\n' +
getEmbeddedTemplate(file, 4) +
' </script>\n';
}
} else {
fields[fileType] += getEmbeddedTemplate(file) + '\n';
}
});
fields.html += '</div>\n';
setHtmlIe8SafeWay(element,
'<form class="jsfiddle" method="post" action="http://jsfiddle.net/api/post/library/pure/" target="_blank">' +
hiddenField('title', 'AngularJS Example: ' + name) +
hiddenField('css', '</style> <!-- Ugly Hack due to jsFiddle issue: http://goo.gl/BUfGZ --> \n' +
stylesheet +
script.angular +
(attr.resource ? script.resource : '') +
'<style>\n' +
fields.css) +
hiddenField('html', fields.html) +
hiddenField('js', fields.js) +
'<button class="btn btn-primary"><i class="icon-white icon-pencil"></i> Edit Me</button>' +
'</form>');
function hiddenField(name, value) {
return '<input type="hidden" name="' + name + '" value="' + escape(value) + '">';
}
}
}
};
directive.ngSetText = ['getEmbeddedTemplate', function(getEmbeddedTemplate) {
return {
restrict: 'CA',
priority: 10,
compile: function(element, attr) {
setHtmlIe8SafeWay(element, escape(getEmbeddedTemplate(attr.ngSetText)));
}
}
}]
directive.ngHtmlWrap = ['reindentCode', 'templateMerge', function(reindentCode, templateMerge) {
return {
compile: function(element, attr) {
var properties = {
head: '',
module: '',
body: element.text()
},
html = "<!doctype html>\n<html ng-app{{module}}>\n <head>\n{{head:4}} </head>\n <body>\n{{body:4}} </body>\n</html>";
angular.forEach((attr.ngHtmlWrap || '').split(' '), function(dep) {
if (!dep) return;
dep = DEPENDENCIES[dep] || dep;
var ext = dep.split(/\./).pop();
if (ext == 'css') {
properties.head += '<link rel="stylesheet" href="' + dep + '" type="text/css">\n';
} else if(ext == 'js') {
properties.head += '<script src="' + dep + '"></script>\n';
} else {
properties.module = '="' + dep + '"';
}
});
setHtmlIe8SafeWay(element, escape(templateMerge(html, properties)));
}
}
}];
directive.ngSetHtml = ['getEmbeddedTemplate', function(getEmbeddedTemplate) {
return {
restrict: 'CA',
priority: 10,
compile: function(element, attr) {
setHtmlIe8SafeWay(element, getEmbeddedTemplate(attr.ngSetHtml));
}
}
}];
directive.ngEvalJavascript = ['getEmbeddedTemplate', function(getEmbeddedTemplate) {
return {
compile: function (element, attr) {
var fileNames = attr.ngEvalJavascript.split(' ');
angular.forEach(fileNames, function(fileName) {
var script = getEmbeddedTemplate(fileName);
try {
if (window.execScript) { // IE
window.execScript(script || '""'); // IE complains when evaling empty string
} else {
window.eval(script + '//@ sourceURL=' + fileName);
}
} catch (e) {
if (window.console) {
window.console.log(script, '\n', e);
} else {
window.alert(e);
}
}
});
}
};
}];
directive.ngEmbedApp = ['$templateCache', '$browser', '$rootScope', '$location', '$sniffer', '$animate',
function($templateCache, $browser, docsRootScope, $location, $sniffer, $animate) {
return {
terminal: true,
link: function(scope, element, attrs) {
var modules = ['ngAnimate'],
embedRootScope,
deregisterEmbedRootScope;
modules.push(['$provide', function($provide) {
$provide.value('$templateCache', $templateCache);
$provide.value('$anchorScroll', angular.noop);
$provide.value('$browser', $browser);
$provide.value('$sniffer', $sniffer);
$provide.value('$animate', $animate);
$provide.provider('$location', function() {
this.$get = ['$rootScope', function($rootScope) {
docsRootScope.$on('$locationChangeSuccess', function(event, oldUrl, newUrl) {
$rootScope.$broadcast('$locationChangeSuccess', oldUrl, newUrl);
});
return $location;
}];
this.html5Mode = angular.noop;
});
$provide.decorator('$rootScope', ['$delegate', function($delegate) {
embedRootScope = $delegate;
// Since we are teleporting the $animate service, which relies on the $$postDigestQueue
// we need the embedded scope to use the same $$postDigestQueue as the outer scope
embedRootScope.$$postDigestQueue = docsRootScope.$$postDigestQueue;
deregisterEmbedRootScope = docsRootScope.$watch(function embedRootScopeDigestWatch() {
embedRootScope.$digest();
});
return embedRootScope;
}]);
}]);
if (attrs.ngEmbedApp) modules.push(attrs.ngEmbedApp);
element.on('click', function(event) {
if (event.target.attributes.getNamedItem('ng-click')) {
event.preventDefault();
}
});
element.bind('$destroy', function() {
deregisterEmbedRootScope();
embedRootScope.$destroy();
});
element.data('$injector', null);
angular.bootstrap(element, modules);
}
};
}];
service.reindentCode = function() {
return function (text, spaces) {
if (!text) return text;
var lines = text.split(/\r?\n/);
var prefix = ' '.substr(0, spaces || 0);
var i;
// remove any leading blank lines
while (lines.length && lines[0].match(/^\s*$/)) lines.shift();
// remove any trailing blank lines
while (lines.length && lines[lines.length - 1].match(/^\s*$/)) lines.pop();
var minIndent = 999;
for (i = 0; i < lines.length; i++) {
var line = lines[0];
var reindentCode = line.match(/^\s*/)[0];
if (reindentCode !== line && reindentCode.length < minIndent) {
minIndent = reindentCode.length;
}
}
for (i = 0; i < lines.length; i++) {
lines[i] = prefix + lines[i].substring(minIndent);
}
lines.push('');
return lines.join('\n');
}
};
service.templateMerge = ['reindentCode', function(indentCode) {
return function(template, properties) {
return template.replace(/\{\{(\w+)(?:\:(\d+))?\}\}/g, function(_, key, indent) {
var value = properties[key];
if (indent) {
value = indentCode(value, indent);
}
return value == undefined ? '' : value;
});
};
}];
service.getEmbeddedTemplate = ['reindentCode', function(reindentCode) {
return function (id) {
var element = document.getElementById(id);
if (!element) {
return null;
}
return reindentCode(angular.element(element).html(), 0);
}
}];
angular.module('bootstrapPrettify', []).directive(directive).factory(service);
+44
View File
@@ -0,0 +1,44 @@
"use strict";
/* jshint browser: true */
/* global importScripts, onmessage: true, postMessage, lunr */
// Load up the lunr library
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
var index = lunr(function() {
this.ref('path');
this.field('titleWords', {boost: 50});
this.field('members', { boost: 40});
this.field('keywords', { boost : 20 });
});
// Retrieve the searchData which contains the information about each page to be indexed
var searchData = {};
var searchDataRequest = new XMLHttpRequest();
searchDataRequest.onload = function() {
// Store the pages data to be used in mapping query results back to pages
searchData = JSON.parse(this.responseText);
// Add search terms from each page to the search index
searchData.forEach(function(page) {
index.add(page);
});
postMessage({ e: 'index-ready' });
};
searchDataRequest.open('GET', 'search-data.json');
searchDataRequest.send();
// The worker receives a message everytime the web app wants to query the index
onmessage = function(oEvent) {
var q = oEvent.data.q;
var hits = index.search(q);
var results = [];
// Only return the array of paths to pages
hits.forEach(function(hit) {
results.push(hit.ref);
});
// The results of the query are sent back to the web app via a new message
postMessage({ e: 'query-ready', q: q, d: results });
};
+42
View File
@@ -0,0 +1,42 @@
{
"extends": "../../../.jshintrc-base",
"globals": {
/* jasmine / karma */
"it": false,
"iit": false,
"describe": false,
"ddescribe": false,
"beforeEach": false,
"afterEach": false,
"expect": false,
"jasmine": false,
"spyOn": false,
"waits": false,
"waitsFor": false,
"runs": false,
"dump": false,
/* e2e */
"browser": false,
"element": false,
"by": false,
/* testabilityPatch / matchers */
"inject": false,
"module": false,
"dealoc": false,
"_jQuery": false,
"_jqLiteMode": false,
"sortedHtml": false,
"childrenTagsOf": false,
"assertHidden": false,
"assertVisible": false,
"provideLog": false,
"spyOnlyCallsWithArgs": false,
"createMockStyleSheet": false,
"browserTrigger": false,
"jqLiteCacheSize": false
}
}
@@ -0,0 +1,51 @@
'use strict';
describe("doc.angularjs.org", function() {
describe("API pages", function() {
it("should display links to code on GitHub", function() {
browser.get('index-debug.html#!/api/ng/service/$http');
expect(element(by.css('.improve-docs')).getAttribute('href')).toMatch(/https?:\/\/github\.com\/angular\/angular\.js\/edit\/.+\/src\/ng\/http\.js/);
browser.get('index-debug.html#!/api/ng/service/$http');
expect(element(by.css('.view-source')).getAttribute('href')).toMatch(/https?:\/\/github\.com\/angular\/angular\.js\/tree\/.+\/src\/ng\/http\.js#L\d+/);
});
it('should change the page content when clicking a link to a service', function () {
browser.get('');
var ngBindLink = element(by.css('.definition-table td a[href="api/ng/directive/ngClick"]'));
ngBindLink.click();
var pageBody = element(by.css('h1'));
expect(pageBody.getText()).toEqual('ngClick');
});
it('should show the functioning input directive example', function () {
browser.get('index-debug.html#!/api/ng/directive/input');
// Ensure that the page is loaded before trying to switch frames.
browser.waitForAngular();
browser.switchTo().frame('example-input-directive');
var nameInput = element(by.model('user.name'));
nameInput.sendKeys('!!!');
var code = element.all(by.css('tt')).first();
expect(code.getText()).toContain('guest!!!');
});
it("should trim indentation from code blocks", function() {
browser.get('index-debug.html#!/api/ng/type/$rootScope.Scope');
var codeBlocks = element.all(by.css('pre > code.lang-js'));
codeBlocks.each(function(codeBlock) {
var firstSpan = codeBlock.all(by.css('span')).first();
expect(firstSpan.getText()).not.toMatch(/^\W+$/);
});
});
});
});
@@ -0,0 +1,12 @@
'use strict';
describe("provider pages", function() {
it("should show the related service", function() {
browser.get('index-debug.html#!/api/ng/provider/$compileProvider');
var serviceLink = element.all(by.css('ol.api-profile-header-structure li a')).first();
expect(serviceLink.getText()).toEqual('- $compile');
expect(serviceLink.getAttribute('href')).toMatch(/api\/ng\/service\/\$compile/);
});
});
@@ -0,0 +1,22 @@
'use strict';
describe("service pages", function() {
it("should show the related provider if there is one", function() {
browser.get('index-debug.html#!/api/ng/service/$compile');
var providerLink = element.all(by.css('ol.api-profile-header-structure li a')).first();
expect(providerLink.getText()).toEqual('- $compileProvider');
expect(providerLink.getAttribute('href')).toMatch(/api\/ng\/provider\/\$compileProvider/);
browser.get('index-debug.html#!/api/ng/service/$q');
providerLink = element.all(by.css('ol.api-profile-header-structure li a')).first();
expect(providerLink.getText()).not.toEqual('- $qProvider');
expect(providerLink.getAttribute('href')).not.toMatch(/api\/ng\/provider\/\$compileProvider/);
});
it("should show parameter defaults", function() {
browser.get('index-debug.html#!/api/ng/service/$timeout');
expect(element.all(by.css('.input-arguments p em')).first().getText()).toContain('(default: 0)');
});
});
@@ -26,21 +26,6 @@ describe('docs.angularjs.org', function () {
});
it('should show the functioning input directive example', function () {
browser.get('index-debug.html#!/api/ng/directive/input');
// Ensure that the page is loaded before trying to switch frames.
browser.waitForAngular();
browser.switchTo().frame('example-input-directive');
var nameInput = element(by.model('user.name'));
nameInput.sendKeys('!!!');
var code = element.all(by.css('tt')).first();
expect(code.getText()).toContain('guest!!!');
});
it('should be resilient to trailing slashes', function() {
browser.get('index-debug.html#!/api/ng/function/angular.noop/');
@@ -67,22 +52,15 @@ describe('docs.angularjs.org', function () {
browser.get('index-debug.html#!error/ng/areq?p0=Missing&p1=not%20a%20function,%20got%20undefined');
expect(element(by.css('.minerr-errmsg')).getText()).toEqual("Argument 'Missing' is not a function, got undefined");
});
});
describe("templates", function() {
it("should show parameter defaults", function() {
browser.get('index-debug.html#!/api/ng/service/$timeout');
expect(element.all(by.css('.input-arguments p em')).first().getText()).toContain('(default: 0)');
});
});
});
describe("API pages", function() {
it("should display links to code on GitHub", function() {
browser.get('index-debug.html#!/api/ng/service/$http');
expect(element(by.css('.improve-docs')).getAttribute('href')).toMatch(/https?:\/\/github\.com\/angular\/angular\.js\/edit\/.+\/src\/ng\/http\.js/);
browser.get('index-debug.html#!/api/ng/service/$http');
expect(element(by.css('.view-source')).getAttribute('href')).toMatch(/https?:\/\/github\.com\/angular\/angular\.js\/tree\/.+\/src\/ng\/http\.js#L\d+/);
});
describe('Error Handling', function() {
it("should display an error if the page does not exist", function() {
browser.get('index-debug.html#!/api/does/not/exist');
expect(element(by.css('h1')).getText()).toBe('Oops!');
});
});
+3 -3
View File
@@ -6,6 +6,7 @@ angular.module('docsApp', [
'DocsController',
'versionsData',
'pagesData',
'navData',
'directives',
'errors',
'examples',
@@ -13,11 +14,10 @@ angular.module('docsApp', [
'tutorials',
'versions',
'bootstrap',
'bootstrapPrettify',
'ui.bootstrap.dropdown'
])
.config(function($locationProvider) {
.config(['$locationProvider', function($locationProvider) {
$locationProvider.html5Mode(true).hashPrefix('!');
});
}]);
+9 -74
View File
@@ -6,31 +6,10 @@ angular.module('DocsController', [])
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.fold = function(url) {
if(url) {
$scope.docs_fold = '/notes/' + url;
if(/\/build/.test($window.location.href)) {
$scope.docs_fold = '/build/docs' + $scope.docs_fold;
}
window.scrollTo(0,0);
}
else {
$scope.docs_fold = null;
}
};
var OFFLINE_COOKIE_NAME = 'ng-offline',
INDEX_PATH = /^(\/|\/index[^\.]*.html)$/;
/**********************************
Publish methods
***********************************/
$scope.navClass = function(navItem) {
return {
active: navItem.href && this.currentPage.path,
@@ -38,55 +17,22 @@ angular.module('DocsController', [])
};
};
$scope.afterPartialLoaded = function() {
$scope.$on('$includeContentLoaded', function() {
var pagePath = $scope.currentPage ? $scope.currentPage.path : $location.path();
$window._gaq.push(['_trackPageview', pagePath]);
};
/** stores a cookie that is used by apache to decide which manifest ot send */
$scope.enableOffline = function() {
//The cookie will be good for one year!
var date = new Date();
date.setTime(date.getTime()+(365*24*60*60*1000));
var expires = "; expires="+date.toGMTString();
var value = angular.version.full;
document.cookie = OFFLINE_COOKIE_NAME + "="+value+expires+"; path=" + $location.path;
//force the page to reload so server can serve new manifest file
window.location.reload(true);
};
/**********************************
Watches
***********************************/
});
$scope.$watch(function docsPathWatch() {return $location.path(); }, function docsPathWatchAction(path) {
var currentPage = $scope.currentPage = NG_PAGES[path];
if ( !currentPage && path.charAt(0)==='/' ) {
// Strip off leading slash
path = path.substr(1);
}
currentPage = $scope.currentPage = NG_PAGES[path];
if ( !currentPage && path.charAt(path.length-1) === '/' && path.length > 1 ) {
// Strip off trailing slash
path = path.substr(0, path.length-1);
}
currentPage = $scope.currentPage = NG_PAGES[path];
if ( !currentPage && /\/index$/.test(path) ) {
// Strip off index from the end
path = path.substr(0, path.length - 6);
}
path = path.replace(/^\/?(.+?)(\/index)?\/?$/, '$1');
currentPage = $scope.currentPage = NG_PAGES[path];
if ( currentPage ) {
$scope.currentArea = currentPage && NG_NAVIGATION[currentPage.area];
$scope.partialPath = 'partials/' + path + '.html';
$scope.currentArea = NG_NAVIGATION[currentPage.area];
var pathParts = currentPage.path.split('/');
var breadcrumb = $scope.breadcrumb = [];
var breadcrumbPath = '';
@@ -98,6 +44,7 @@ angular.module('DocsController', [])
} else {
$scope.currentArea = NG_NAVIGATION['api'];
$scope.breadcrumb = [];
$scope.partialPath = 'Error404.html';
}
});
@@ -107,24 +54,12 @@ angular.module('DocsController', [])
$scope.versionNumber = angular.version.full;
$scope.version = angular.version.full + " " + angular.version.codeName;
$scope.subpage = false;
$scope.offlineEnabled = ($cookies[OFFLINE_COOKIE_NAME] == angular.version.full);
$scope.futurePartialTitle = null;
$scope.loading = 0;
$scope.$cookies = $cookies;
$cookies.platformPreference = $cookies.platformPreference || 'gitUnix';
var INDEX_PATH = /^(\/|\/index[^\.]*.html)$/;
if (!$location.path() || INDEX_PATH.test($location.path())) {
$location.path('/api').replace();
}
// bind escape to hash reset callback
angular.element(window).on('keydown', function(e) {
if (e.keyCode === 27) {
$scope.$apply(function() {
$scope.subpage = false;
});
}
});
}]);
-24
View File
@@ -1,24 +0,0 @@
angular.module('docsApp.navigationService', [])
.factory('navigationService', function($window) {
var service = {
currentPage: null,
currentVersion: null,
changePage: function(newPage) {
},
changeVersion: function(newVersion) {
//TODO =========
// var currentPagePath = '';
// // preserve URL path when switching between doc versions
// if (angular.isObject($rootScope.currentPage) && $rootScope.currentPage.section && $rootScope.currentPage.id) {
// currentPagePath = '/' + $rootScope.currentPage.section + '/' + $rootScope.currentPage.id;
// }
// $window.location = version.url + currentPagePath;
}
};
});
+123 -64
View File
@@ -10,22 +10,35 @@ angular.module('search', [])
$scope.search = function(q) {
var MIN_SEARCH_LENGTH = 2;
if(q.length >= MIN_SEARCH_LENGTH) {
var results = docsSearch(q);
var totalAreas = 0;
for(var i in results) {
++totalAreas;
}
if(totalAreas > 0) {
$scope.colClassName = 'cols-' + totalAreas;
}
$scope.hasResults = totalAreas > 0;
$scope.results = results;
docsSearch(q).then(function(hits) {
var results = {};
angular.forEach(hits, function(hit) {
var area = hit.area;
var limit = (area == 'api') ? 40 : 14;
results[area] = results[area] || [];
if(results[area].length < limit) {
results[area].push(hit);
}
});
var totalAreas = 0;
for(var i in results) {
++totalAreas;
}
if(totalAreas > 0) {
$scope.colClassName = 'cols-' + totalAreas;
}
$scope.hasResults = totalAreas > 0;
$scope.results = results;
});
}
else {
clearResults();
}
if(!$scope.$$phase) $scope.$apply();
};
$scope.submit = function() {
var result;
for(var i in $scope.results) {
@@ -39,78 +52,124 @@ angular.module('search', [])
$scope.hideResults();
}
};
$scope.hideResults = function() {
clearResults();
$scope.q = '';
};
}])
.controller('Error404SearchCtrl', ['$scope', '$location', 'docsSearch', function($scope, $location, docsSearch) {
$scope.results = docsSearch($location.path().split(/[\/\.:]/).pop());
.controller('Error404SearchCtrl', ['$scope', '$location', 'docsSearch',
function($scope, $location, docsSearch) {
docsSearch($location.path().split(/[\/\.:]/).pop()).then(function(results) {
$scope.results = {};
angular.forEach(results, function(result) {
var area = $scope.results[result.area] || [];
area.push(result);
$scope.results[result.area] = area;
});
});
}])
.factory('lunrSearch', function() {
return function(properties) {
if (window.RUNNING_IN_NG_TEST_RUNNER) return null;
var engine = lunr(properties);
return {
store : function(values) {
engine.add(values);
},
search : function(q) {
return engine.search(q);
}
};
};
})
.provider('docsSearch', function() {
.factory('docsSearch', ['$rootScope','lunrSearch', 'NG_PAGES',
function($rootScope, lunrSearch, NG_PAGES) {
if (window.RUNNING_IN_NG_TEST_RUNNER) {
return null;
}
// This version of the service builds the index in the current thread,
// which blocks rendering and other browser activities.
// It should only be used where the browser does not support WebWorkers
function localSearchFactory($http, $timeout, NG_PAGES) {
var index = lunrSearch(function() {
this.ref('id');
this.field('title', {boost: 50});
this.field('members', { boost: 40});
this.field('keywords', { boost : 20 });
});
console.log('Using Local Search Index');
angular.forEach(NG_PAGES, function(page, key) {
if(page.searchTerms) {
index.store({
id : key,
title : page.searchTerms.titleWords,
keywords : page.searchTerms.keywords,
members : page.searchTerms.members
// Create the lunr index
var index = lunr(function() {
this.ref('path');
this.field('titleWords', {boost: 50});
this.field('members', { boost: 40});
this.field('keywords', { boost : 20 });
});
// Delay building the index by loading the data asynchronously
var indexReadyPromise = $http.get('js/search-data.json').then(function(response) {
var searchData = response.data;
// Delay building the index for 500ms to allow the page to render
return $timeout(function() {
// load the page data into the index
angular.forEach(searchData, function(page) {
index.add(page);
});
}, 500);
});
// The actual service is a function that takes a query string and
// returns a promise to the search results
// (In this case we just resolve the promise immediately as it is not
// inherently an async process)
return function(q) {
return indexReadyPromise.then(function() {
var hits = index.search(q);
var results = [];
angular.forEach(hits, function(hit) {
results.push(NG_PAGES[hit.ref]);
});
return results;
});
};
});
}
localSearchFactory.$inject = ['$http', '$timeout', 'NG_PAGES'];
return function(q) {
var results = {
api : [],
tutorial : [],
guide : [],
error : [],
misc : []
// This version of the service builds the index in a WebWorker,
// which does not block rendering and other browser activities.
// It should only be used where the browser does support WebWorkers
function webWorkerSearchFactory($q, $rootScope, NG_PAGES) {
console.log('Using WebWorker Search Index')
var searchIndex = $q.defer();
var results;
var worker = new Worker('js/search-worker.js');
// The worker will send us a message in two situations:
// - when the index has been built, ready to run a query
// - when it has completed a search query and the results are available
worker.onmessage = function(oEvent) {
$rootScope.$apply(function() {
switch(oEvent.data.e) {
case 'index-ready':
searchIndex.resolve();
break;
case 'query-ready':
var pages = oEvent.data.d.map(function(path) {
return NG_PAGES[path];
});
results.resolve(pages);
break;
}
});
};
angular.forEach(index.search(q), function(result) {
var key = result.ref;
var item = NG_PAGES[key];
var area = item.area;
item.path = key;
var limit = area == 'api' ? 40 : 14;
if(results[area].length < limit) {
results[area].push(item);
}
});
return results;
// The actual service is a function that takes a query string and
// returns a promise to the search results
return function(q) {
// We only run the query once the index is ready
return searchIndex.promise.then(function() {
results = $q.defer();
worker.postMessage({ q: q });
return results.promise;
});
};
}
webWorkerSearchFactory.$inject = ['$q', '$rootScope', 'NG_PAGES'];
return {
$get: window.Worker ? webWorkerSearchFactory : localSearchFactory
};
}])
})
.directive('focused', function($timeout) {
return function(scope, element, attrs) {
+15 -16
View File
@@ -1,6 +1,6 @@
angular.module('tutorials', [])
.directive('docTutorialNav', function(templateMerge) {
.directive('docTutorialNav', function() {
var pages = [
'',
'step_00', 'step_01', 'step_02', 'step_03', 'step_04',
@@ -8,23 +8,22 @@ angular.module('tutorials', [])
'step_10', 'step_11', 'step_12', 'the_end'
];
return {
compile: function(element, attrs) {
var seq = 1 * attrs.docTutorialNav,
props = {
seq: seq,
prev: pages[seq],
next: pages[2 + seq],
diffLo: seq ? (seq - 1): '0~1',
diffHi: seq
};
scope: {},
template:
'<a ng-href="tutorial/{{prev}}"><li class="btn btn-primary"><i class="glyphicon glyphicon-step-backward"></i> Previous</li></a>\n' +
'<a ng-href="http://angular.github.io/angular-phonecat/step-{{seq}}/app"><li class="btn btn-primary"><i class="glyphicon glyphicon-play"></i> Live Demo</li></a>\n' +
'<a ng-href="https://github.com/angular/angular-phonecat/compare/step-{{diffLo}}...step-{{diffHi}}"><li class="btn btn-primary"><i class="glyphicon glyphicon-search"></i> Code Diff</li></a>\n' +
'<a ng-href="tutorial/{{next}}"><li class="btn btn-primary">Next <i class="glyphicon glyphicon-step-forward"></i></li></a>',
link: function(scope, element, attrs) {
var seq = 1 * attrs.docTutorialNav;
scope.seq = seq;
scope.prev = pages[seq];
scope.next = pages[2 + seq];
scope.diffLo = seq ? (seq - 1): '0~1';
scope.diffHi = seq;
element.addClass('btn-group');
element.addClass('tutorial-nav');
element.append(templateMerge(
'<a href="tutorial/{{prev}}"><li class="btn btn-primary"><i class="glyphicon glyphicon-step-backward"></i> Previous</li></a>\n' +
'<a href="http://angular.github.io/angular-phonecat/step-{{seq}}/app"><li class="btn btn-primary"><i class="glyphicon glyphicon-play"></i> Live Demo</li></a>\n' +
'<a href="https://github.com/angular/angular-phonecat/compare/step-{{diffLo}}...step-{{diffHi}}"><li class="btn btn-primary"><i class="glyphicon glyphicon-search"></i> Code Diff</li></a>\n' +
'<a href="tutorial/{{next}}"><li class="btn btn-primary">Next <i class="glyphicon glyphicon-step-forward"></i></li></a>', props));
}
};
})
@@ -47,4 +46,4 @@ angular.module('tutorials', [])
'<a ng-href="https://github.com/angular/angular-phonecat/compare/step-{{step ? (step - 1): \'0~1\'}}...step-{{step}}">GitHub</a>\n' +
'</p>'
};
});
});
+3 -3
View File
@@ -4,6 +4,7 @@ angular.module('versions', [])
.controller('DocsVersionsCtrl', ['$scope', '$location', '$window', 'NG_VERSIONS', function($scope, $location, $window, NG_VERSIONS) {
$scope.docs_version = NG_VERSIONS[0];
$scope.docs_versions = NG_VERSIONS;
for(var i=0, minor = NaN; i < NG_VERSIONS.length; i++) {
var version = NG_VERSIONS[i];
@@ -15,13 +16,12 @@ angular.module('versions', [])
minor = version.minor;
}
$scope.docs_versions = NG_VERSIONS;
$scope.getGroupName = function(v) {
return v.isLatest ? 'Latest' : (v.isStable ? 'Stable' : 'Unstable');
return v.isLatest ? 'Latest' : ('v' + v.major + '.' + v.minor + '.x');
};
$scope.jumpToDocsVersion = function(version) {
var currentPagePath = $location.path();
var currentPagePath = $location.path().replace(/\/$/, '');
// TODO: We need to do some munging of the path for different versions of the API...
+2 -2
View File
@@ -19,7 +19,7 @@ describe("DocsController", function() {
it("should update the Google Analytics with currentPage path if currentPage exists", inject(function($window) {
$window._gaq = [];
$scope.currentPage = { path: 'a/b/c' };
$scope.afterPartialLoaded();
$scope.$broadcast('$includeContentLoaded');
expect($window._gaq.pop()).toEqual(['_trackPageview', 'a/b/c']);
}));
@@ -27,7 +27,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').andReturn('x/y/z');
$scope.afterPartialLoaded();
$scope.$broadcast('$includeContentLoaded');
expect($window._gaq.pop()).toEqual(['_trackPageview', 'x/y/z']);
}));
});
+154 -32
View File
@@ -1,44 +1,166 @@
var _ = require('lodash');
"use strict";
var path = require('canonical-path');
var packagePath = __dirname;
var basePackage = require('dgeni-packages/ngdoc');
var examplesPackage = require('dgeni-packages/examples');
var Package = require('dgeni').Package;
module.exports = function(config) {
// Create and export a new Dgeni package called angularjs. This package depends upon
// the ngdoc,nunjucks and examples packages defined in the dgeni-packages npm module.
module.exports = new Package('angularjs', [
require('dgeni-packages/ngdoc'),
require('dgeni-packages/nunjucks'),
require('dgeni-packages/examples')
])
config = basePackage(config);
config = examplesPackage(config);
config.append('processing.processors', [
require('./processors/git-data'),
require('./processors/error-docs'),
require('./processors/keywords'),
require('./processors/versions-data'),
require('./processors/pages-data'),
require('./processors/protractor-generate'),
require('./processors/index-page'),
require('./processors/debug-dump')
]);
.factory(require('./services/errorNamespaceMap'))
.factory(require('./services/getMinerrInfo'))
.factory(require('./services/getVersion'))
.factory(require('./services/gitData'))
config.append('processing.tagDefinitions', [
require('./tag-defs/tutorial-step'),
require('./tag-defs/sortOrder')
]);
.factory(require('./services/deployments/debug'))
.factory(require('./services/deployments/default'))
.factory(require('./services/deployments/jquery'))
.factory(require('./services/deployments/production'))
config.append('processing.defaultTagTransforms', [
require('dgeni-packages/jsdoc/tag-defs/transforms/trim-whitespace')
]);
.factory(require('./inline-tag-defs/type'))
config.append('processing.inlineTagDefinitions', [
require('./inline-tag-defs/type')
]);
config.set('processing.search.ignoreWordsFile', path.resolve(packagePath, 'ignore.words'));
.processor(require('./processors/error-docs'))
.processor(require('./processors/index-page'))
.processor(require('./processors/keywords'))
.processor(require('./processors/pages-data'))
.processor(require('./processors/versions-data'))
config.prepend('rendering.templateFolders', [
path.resolve(packagePath, 'templates')
]);
return config;
};
.config(function(dgeni, log, readFilesProcessor, writeFilesProcessor) {
dgeni.stopOnValidationError = true;
dgeni.stopOnProcessingError = true;
log.level = 'info';
readFilesProcessor.basePath = path.resolve(__dirname,'../..');
readFilesProcessor.sourceFiles = [
{ include: 'src/**/*.js', basePath: 'src' },
{ include: 'docs/content/**/*.ngdoc', basePath: 'docs/content' }
];
writeFilesProcessor.outputFolder = 'build/docs';
})
.config(function(parseTagsProcessor) {
parseTagsProcessor.tagDefinitions.push(require('./tag-defs/tutorial-step'));
parseTagsProcessor.tagDefinitions.push(require('./tag-defs/sortOrder'));
})
.config(function(inlineTagProcessor, typeInlineTagDef) {
inlineTagProcessor.inlineTagDefinitions.push(typeInlineTagDef);
})
.config(function(templateFinder, renderDocsProcessor, gitData) {
templateFinder.templateFolders.unshift(path.resolve(packagePath, 'templates'));
renderDocsProcessor.extraData.git = gitData;
})
.config(function(computePathsProcessor, computeIdsProcessor) {
computePathsProcessor.pathTemplates.push({
docTypes: ['error'],
pathTemplate: 'error/${namespace}/${name}',
outputPathTemplate: 'partials/error/${namespace}/${name}.html'
});
computePathsProcessor.pathTemplates.push({
docTypes: ['errorNamespace'],
pathTemplate: 'error/${name}',
outputPathTemplate: 'partials/error/${name}.html'
});
computePathsProcessor.pathTemplates.push({
docTypes: ['overview', 'tutorial'],
getPath: function(doc) {
var docPath = path.dirname(doc.fileInfo.relativePath);
if ( doc.fileInfo.baseName !== 'index' ) {
docPath = path.join(docPath, doc.fileInfo.baseName);
}
return docPath;
},
outputPathTemplate: 'partials/${path}.html'
});
computePathsProcessor.pathTemplates.push({
docTypes: ['e2e-test'],
getPath: function() {},
outputPathTemplate: 'ptore2e/${example.id}/${deployment.name}_test.js'
});
computePathsProcessor.pathTemplates.push({
docTypes: ['indexPage'],
pathTemplate: '.',
outputPathTemplate: '${id}.html'
});
computePathsProcessor.pathTemplates.push({
docTypes: ['module' ],
pathTemplate: '${area}/${name}',
outputPathTemplate: 'partials/${area}/${name}.html'
});
computePathsProcessor.pathTemplates.push({
docTypes: ['componentGroup' ],
pathTemplate: '${area}/${moduleName}/${groupType}',
outputPathTemplate: 'partials/${area}/${moduleName}/${groupType}.html'
});
computeIdsProcessor.idTemplates.push({
docTypes: ['overview', 'tutorial', 'e2e-test', 'indexPage'],
getId: function(doc) { return doc.fileInfo.baseName; },
getAliases: function(doc) { return [doc.id]; }
});
computeIdsProcessor.idTemplates.push({
docTypes: ['error', 'errorNamespace'],
getId: function(doc) { return 'error:' + doc.name; },
getAliases: function(doc) { return [doc.id]; }
});
})
.config(function(checkAnchorLinksProcessor) {
checkAnchorLinksProcessor.base = '/';
// We are only interested in docs that have an area (i.e. they are pages)
checkAnchorLinksProcessor.checkDoc = function(doc) { return doc.area; };
})
.config(function(
generateIndexPagesProcessor,
generateProtractorTestsProcessor,
generateExamplesProcessor,
debugDeployment, defaultDeployment,
jqueryDeployment, productionDeployment) {
generateIndexPagesProcessor.deployments = [
debugDeployment,
defaultDeployment,
jqueryDeployment,
productionDeployment
];
generateProtractorTestsProcessor.deployments = [
defaultDeployment,
jqueryDeployment
];
generateExamplesProcessor.deployments = [
debugDeployment,
defaultDeployment,
jqueryDeployment,
productionDeployment
];
});
+15 -10
View File
@@ -1,12 +1,17 @@
var typeClassFilter = require('dgeni-packages/ngdoc/rendering/filters/type-class');
"use strict";
var encoder = new require('node-html-encoder').Encoder();
module.exports = {
name: 'type',
description: 'Replace with markup that displays a nice type',
handlerFactory: function() {
return function(doc, tagName, tagDescription) {
return '<a href="" class="' + typeClassFilter.process(tagDescription) + '">'+encoder.htmlEncode(tagDescription) + '</a>';
};
}
};
/**
* @dgService typeInlineTagDef
* @description
* Replace with markup that displays a nice type
*/
module.exports = function typeInlineTagDef(getTypeClass) {
return {
name: 'type',
handler: function(doc, tagName, tagDescription) {
return '<a href="" class="' + getTypeClass(tagDescription) + '">'+encoder.htmlEncode(tagDescription) + '</a>';
}
};
};
-33
View File
@@ -1,33 +0,0 @@
var fs = require('q-io/fs');
var log = require('winston');
var util = require("util");
module.exports = {
name: 'debug-dump',
runBefore: ['write-files'],
description: 'This processor dumps docs that match a filter to a file',
process: function(docs, config) {
var filter, outputPath, depth;
filter = config.get('processing.debug-dump.filter');
outputPath = config.get('processing.debug-dump.outputPath');
depth = config.get('processing.debug-dump.depth', 2);
if ( filter && outputPath ) {
log.info('Dumping docs:', filter, outputPath);
var filteredDocs = filter(docs);
var dumpedDocs = util.inspect(filteredDocs, depth);
return writeFile(outputPath, dumpedDocs).then(function() {
return docs;
});
}
}
};
function writeFile(file, content) {
return fs.makeTree(fs.directory(file)).then(function() {
return fs.write(file, content, 'wb');
});
}
+43 -50
View File
@@ -1,59 +1,52 @@
"use strict";
var _ = require('lodash');
var log = require('winston');
var path = require('canonical-path');
module.exports = {
name: 'error-docs',
description: 'Compute the various fields for docs in the Error area',
runAfter: ['tags-extracted', 'compute-path'],
runBefore: ['extra-docs-added'],
exports: {
errorNamespaces: ['factory', function() { return {}; }],
minerrInfo: ['factory', function(config) {
var minerrInfoPath = config.get('processing.errors.minerrInfoPath');
if ( !minerrInfoPath ) {
throw new Error('Error in configuration: Please provide a path to the minerr info file (errors.json) ' +
'in the `config.processing.errors.minerrInfoPath` property');
}
return require(minerrInfoPath);
}]
},
process: function(docs, partialNames, errorNamespaces, minerrInfo) {
/**
* @dgProcessor errorDocsProcessor
* @description
* Process "error" docType docs and generate errorNamespace docs
*/
module.exports = function errorDocsProcessor(errorNamespaceMap, getMinerrInfo) {
return {
$runAfter: ['tags-extracted'],
$runBefore: ['extra-docs-added'],
$process: function(docs) {
// Create error namespace docs and attach error docs to each
_.forEach(docs, function(doc) {
if ( doc.docType === 'error' ) {
// Create error namespace docs and attach error docs to each
docs.forEach(function(doc) {
var parts, namespaceDoc;
// Parse out the error info from the id
parts = doc.name.split(':');
doc.namespace = parts[0];
doc.name = parts[1];
if ( doc.docType === 'error' ) {
// Parse out the error info from the id
parts = doc.name.split(':');
doc.namespace = parts[0];
doc.name = parts[1];
var namespaceDoc = errorNamespaces[doc.namespace];
if ( !namespaceDoc ) {
// First time we came across this namespace, so create a new one
namespaceDoc = errorNamespaces[doc.namespace] = {
area: doc.area,
name: doc.namespace,
errors: [],
path: path.dirname(doc.path),
outputPath: path.dirname(doc.outputPath) + '.html',
docType: 'errorNamespace'
};
// Get or create the relevant errorNamespace doc
namespaceDoc = errorNamespaceMap.get(doc.namespace);
if ( !namespaceDoc ) {
namespaceDoc = {
area: 'error',
name: doc.namespace,
errors: [],
docType: 'errorNamespace'
};
errorNamespaceMap.set(doc.namespace, namespaceDoc);
}
// Link this error doc to its namespace doc
namespaceDoc.errors.push(doc);
doc.namespaceDoc = namespaceDoc;
doc.formattedErrorMessage = getMinerrInfo().errors[doc.namespace][doc.name];
}
});
// Add this error to the namespace
namespaceDoc.errors.push(doc);
doc.namespace = namespaceDoc;
doc.formattedErrorMessage = minerrInfo.errors[doc.namespace.name][doc.name];
}
});
return docs.concat(_.values(errorNamespaces));
}
};
errorNamespaceMap.forEach(function(errorNamespace) {
docs.push(errorNamespace);
});
}
};
};
-20
View File
@@ -1,20 +0,0 @@
var gruntUtils = require('../../../lib/grunt/utils');
var versionInfo = require('../../../lib/versions/version-info');
module.exports = {
name: 'git-data',
runBefore: ['reading-files'],
description: 'This processor adds information from the local git repository to the extraData injectable',
exports: {
gitData: ['factory', function() {
return {
version: versionInfo.currentVersion,
versions: versionInfo.previousVersions,
info: versionInfo.gitRepoInfo
};
}]
},
process: function(extraData, gitData) {
extraData.git = gitData;
}
};
+38 -35
View File
@@ -1,40 +1,43 @@
"use strict";
var _ = require('lodash');
var log = require('winston');
var path = require('canonical-path');
module.exports = {
name: 'index-page',
runAfter: ['adding-extra-docs'],
runBefore: ['extra-docs-added'],
description: 'This processor creates docs that will be rendered as the index page for the app',
process: function(docs, config) {
/**
* @dgProcessor generateIndexPagesProcessor
* @description
* This processor creates docs that will be rendered as the index page for the app
*/
module.exports = function generateIndexPagesProcessor() {
return {
deployments: [],
$validate: {
deployments: { presence: true }
},
$runAfter: ['adding-extra-docs'],
$runBefore: ['extra-docs-added'],
$process: function(docs) {
var deployment = config.deployment;
if ( !deployment || !deployment.environments ) {
throw new Error('No deployment environments found in the config.');
// Collect up all the areas in the docs
var areas = {};
docs.forEach(function(doc) {
if ( doc.area ) {
areas[doc.area] = doc.area;
}
});
areas = _.keys(areas);
this.deployments.forEach(function(deployment) {
var indexDoc = _.defaults({
docType: 'indexPage',
areas: areas
}, deployment);
indexDoc.id = 'index' + (deployment.name === 'default' ? '' : '-' + deployment.name);
docs.push(indexDoc);
});
}
// Collect up all the areas in the docs
var areas = {};
_.forEach(docs, function(doc) {
if ( doc.area ) {
areas[doc.area] = doc.area;
}
});
areas = _.keys(areas);
_.forEach(deployment.environments, function(environment) {
var indexDoc = _.defaults({
docType: 'indexPage',
areas: areas
}, environment);
indexDoc.id = 'index' + (environment.name === 'default' ? '' : '-' + environment.name);
// Use .. to put it at the root of the build
indexDoc.outputPath = indexDoc.id + '.html';
docs.push(indexDoc);
});
}
};
};
};
+58 -44
View File
@@ -1,51 +1,64 @@
"use strict";
var _ = require('lodash');
var log = require('winston');
var fs = require('fs');
var path = require('canonical-path');
module.exports = {
name: 'keywords',
runAfter: ['docs-processed', 'api-docs'],
runBefore: ['adding-extra-docs'],
description: 'This processor extracts all the keywords from the document',
process: function(docs, config) {
/**
* @dgProcessor generateKeywordsProcessor
* @description
* This processor extracts all the keywords from each document and creates
* a new document that will be rendered as a JavaScript file containing all
* this data.
*/
module.exports = function generateKeywordsProcessor(log, readFilesProcessor) {
return {
ignoreWordsFile: undefined,
areasToSearch: ['api', 'guide', 'misc', 'error', 'tutorial'],
propertiesToIgnore: [],
$validate: {
ignoreWordsFile: { },
areasToSearch: { presence: true },
propertiesToIgnore: { }
},
$runAfter: ['memberDocsProcessor'],
$runBefore: ['rendering-docs'],
$process: function(docs) {
// Keywords to ignore
var wordsToIgnore = [];
var propertiesToIgnore;
var areasToSearch;
// Keywords to ignore
var wordsToIgnore = [];
var propertiesToIgnore;
var areasToSearch;
// Keywords start with "ng:" or one of $, _ or a letter
var KEYWORD_REGEX = /^((ng:|[\$_a-z])[\w\-_]+)/;
// Keywords start with "ng:" or one of $, _ or a letter
var KEYWORD_REGEX = /^((ng:|[\$_a-z])[\w\-_]+)/;
// Load up the keywords to ignore, if specified in the config
if ( config.processing.search && config.processing.search.ignoreWordsFile ) {
// Load up the keywords to ignore, if specified in the config
if ( this.ignoreWordsFile ) {
var ignoreWordsPath = path.resolve(config.basePath, config.processing.search.ignoreWordsFile);
wordsToIgnore = fs.readFileSync(ignoreWordsPath, 'utf8').toString().split(/[,\s\n\r]+/gm);
var ignoreWordsPath = path.resolve(readFilesProcessor.basePath, this.ignoreWordsFile);
wordsToIgnore = fs.readFileSync(ignoreWordsPath, 'utf8').toString().split(/[,\s\n\r]+/gm);
log.debug('Loaded ignore words from "' + ignoreWordsPath + '"');
log.silly(wordsToIgnore);
log.debug('Loaded ignore words from "' + ignoreWordsPath + '"');
log.silly(wordsToIgnore);
}
areasToSearch = _.indexBy(config.get('processing.search.areasToSearch', ['api', 'guide', 'misc', 'error', 'tutorial']));
propertiesToIgnore = _.indexBy(config.get('processing.search.propertiesToIgnore', []));
log.debug('Properties to ignore', propertiesToIgnore);
var ignoreWordsMap = _.indexBy(wordsToIgnore);
// If the title contains a name starting with ng, e.g. "ngController", then add the module name
// without the ng to the title text, e.g. "controller".
function extractTitleWords(title) {
var match = /ng([A-Z]\w*)/.exec(title);
if ( match ) {
title = title + ' ' + match[1].toLowerCase();
}
return title;
}
areasToSearch = _.indexBy(this.areasToSearch);
propertiesToIgnore = _.indexBy(this.propertiesToIgnore);
log.debug('Properties to ignore', propertiesToIgnore);
var ignoreWordsMap = _.indexBy(wordsToIgnore);
// If the title contains a name starting with ng, e.g. "ngController", then add the module name
// without the ng to the title text, e.g. "controller".
function extractTitleWords(title) {
var match = /ng([A-Z]\w*)/.exec(title);
if ( match ) {
title = title + ' ' + match[1].toLowerCase();
}
return title;
}
function extractWords(text, words, keywordMap) {
@@ -58,15 +71,15 @@ module.exports = {
keywordMap[key] = true;
words.push(key);
}
}
});
}
}
});
}
// We are only interested in docs that live in the right area
docs = _.filter(docs, function(doc) { return areasToSearch[doc.area]; });
// We are only interested in docs that live in the right area
docs = _.filter(docs, function(doc) { return areasToSearch[doc.area]; });
_.forEach(docs, function(doc) {
_.forEach(docs, function(doc) {
var words = [];
var keywordMap = _.clone(ignoreWordsMap);
@@ -94,7 +107,8 @@ module.exports = {
members: _.sortBy(members).join(' ')
};
});
});
}
}
};
};
+177 -159
View File
@@ -1,6 +1,7 @@
"use strict";
var _ = require('lodash');
var path = require('canonical-path');
var log = require('winston');
var AREA_NAMES = {
api: 'API',
@@ -33,189 +34,206 @@ function getNavGroup(pages, area, pageSorter, pageMapper) {
}
var navGroupMappers = {
api: function(areaPages, area) {
var navGroups = _(areaPages)
.filter('module') // We are not interested in docs that are not in a module
/**
* @dgProcessor generatePagesDataProcessor
* @description
* This processor will create a new doc that will be rendered as a JavaScript file
* containing meta information about the pages and navigation
*/
module.exports = function generatePagesDataProcessor(log) {
.groupBy('module')
.map(function(modulePages, moduleName) {
log.debug('moduleName: ' + moduleName);
var navItems = [];
var modulePage;
var navGroupMappers = {
api: function(areaPages, area) {
var navGroups = _(areaPages)
.filter('module') // We are not interested in docs that are not in a module
_(modulePages)
.groupBy('module')
.groupBy('docType')
.map(function(modulePages, moduleName) {
log.debug('moduleName: ' + moduleName);
var navItems = [];
var modulePage;
.tap(function(docTypes) {
log.debug(_.keys(docTypes));
// Extract the module page from the collection
modulePage = docTypes.module[0];
delete docTypes.module;
})
_(modulePages)
.tap(function(docTypes) {
if ( docTypes.input ) {
docTypes.directive = docTypes.directive || [];
// Combine input docTypes into directive docTypes
docTypes.directive = docTypes.directive.concat(docTypes.input);
delete docTypes.input;
}
})
.groupBy('docType')
.forEach(function(sectionPages, sectionName) {
.tap(function(docTypes) {
log.debug(moduleName, _.keys(docTypes));
// Extract the module page from the collection
modulePage = docTypes.module[0];
delete docTypes.module;
})
sectionPages = _.sortBy(sectionPages, 'name');
.tap(function(docTypes) {
if ( docTypes.input ) {
docTypes.directive = docTypes.directive || [];
// Combine input docTypes into directive docTypes
docTypes.directive = docTypes.directive.concat(docTypes.input);
delete docTypes.input;
}
})
if ( sectionPages.length > 0 ) {
// Push a navItem for this section
navItems.push({
name: sectionName,
type: 'section',
href: path.dirname(sectionPages[0].path)
});
.forEach(function(sectionPages, sectionName) {
// Push the rest of the sectionPages for this section
_.forEach(sectionPages, function(sectionPage) {
sectionPages = _.sortBy(sectionPages, 'name');
if ( sectionPages.length > 0 ) {
// Push a navItem for this section
navItems.push({
name: sectionPage.name,
href: sectionPage.path,
type: sectionPage.docType
name: sectionName,
type: 'section',
href: path.dirname(sectionPages[0].path)
});
});
}
});
// Push the rest of the sectionPages for this section
_.forEach(sectionPages, function(sectionPage) {
navItems.push({
name: sectionPage.name,
href: sectionPage.path,
type: sectionPage.docType
});
});
}
});
return {
name: moduleName,
href: modulePage.path,
type: 'group',
navItems: navItems
};
})
.value();
return navGroups;
},
tutorial: function(pages, area) {
return [getNavGroup(pages, area, 'step', function(page) {
return {
name: moduleName,
href: modulePage.path,
type: 'group',
navItems: navItems
name: page.name,
step: page.step,
href: page.path,
type: 'tutorial'
};
})
.value();
return navGroups;
},
tutorial: function(pages, area) {
return [getNavGroup(pages, area, 'step', function(page) {
return {
name: page.name,
step: page.step,
href: page.path,
type: 'tutorial'
};
})];
},
error: function(pages, area) {
return [getNavGroup(pages, area, 'path', function(page) {
return {
name: page.name,
href: page.path,
type: page.docType === 'errorNamespace' ? 'section' : 'error'
};
})];
},
pages: function(pages, area) {
return [getNavGroup(
pages,
area,
function(page) {
return page.sortOrder || page.path;
},
function(page) {
})];
},
error: function(pages, area) {
return [getNavGroup(pages, area, 'path', function(page) {
return {
name: page.name,
href: page.path,
type: 'page'
type: page.docType === 'errorNamespace' ? 'section' : 'error'
};
}
)];
}
};
})];
},
pages: function(pages, area) {
return [getNavGroup(
pages,
area,
function(page) {
return page.sortOrder || page.path;
},
function(page) {
return {
name: page.name,
href: page.path,
type: 'page'
};
}
)];
}
};
module.exports = {
name: 'pages-data',
description: 'This plugin will create a new doc that will be rendered as an angularjs module ' +
'which will contain meta information about the pages and navigation',
runAfter: ['adding-extra-docs', 'component-groups-generate', 'compute-path'],
runBefore: ['extra-docs-added'],
process: function(docs, config) {
return {
$runAfter: ['paths-computed', 'generateKeywordsProcessor'],
$runBefore: ['rendering-docs'],
$process: function(docs) {
var outputFolder = config.rendering.outputFolder;
_(docs)
.filter(function(doc) { return doc.area === 'api'; })
.filter(function(doc) { return doc.docType === 'module'; })
.forEach(function(doc) { if ( !doc.path ) {
log.warn('Missing path property for ', doc.id);
}})
.map(function(doc) { return _.pick(doc, ['id', 'module', 'docType', 'area']); })
.tap(function(docs) {
log.debug(docs);
});
// We are only interested in docs that are in a area and not landing pages
var navPages = _.filter(docs, function(page) {
return page.area &&
page.docType != 'componentGroup';
});
// Generate an object collection of pages that is grouped by area e.g.
// - area "api"
// - group "ng"
// - section "directive"
// - ngApp
// - ngBind
// - section "global"
// - angular.element
// - angular.bootstrap
// - section "service"
// - $compile
// - group "ngRoute"
// - section "directive"
// - ngView
// - section "service"
// - $route
//
var areas = {};
_(navPages)
.groupBy('area')
.forEach(function(pages, areaId) {
var area = {
id: areaId,
name: AREA_NAMES[areaId]
};
areas[areaId] = area;
var navGroupMapper = navGroupMappers[area.id] || navGroupMappers['pages'];
area.navGroups = navGroupMapper(pages, area);
// We are only interested in docs that are in an area
var pages = _.filter(docs, function(doc) {
return doc.area;
});
// Extract a list of basic page information for mapping paths to partials and for client side searching
var pages = _(docs)
.map(function(doc) {
var page = _.pick(doc, [
'docType', 'id', 'name', 'area', 'outputPath', 'path', 'searchTerms'
]);
return page;
})
.indexBy('path')
.value();
// We are only interested in pages that are not landing pages
var navPages = _.filter(pages, function(page) {
return page.docType != 'componentGroup';
});
// Generate an object collection of pages that is grouped by area e.g.
// - area "api"
// - group "ng"
// - section "directive"
// - ngApp
// - ngBind
// - section "global"
// - angular.element
// - angular.bootstrap
// - section "service"
// - $compile
// - group "ngRoute"
// - section "directive"
// - ngView
// - section "service"
// - $route
//
var areas = {};
_(navPages)
.groupBy('area')
.forEach(function(pages, areaId) {
var area = {
id: areaId,
name: AREA_NAMES[areaId]
};
areas[areaId] = area;
var navGroupMapper = navGroupMappers[area.id] || navGroupMappers['pages'];
area.navGroups = navGroupMapper(pages, area);
});
docs.push({
docType: 'nav-data',
id: 'nav-data',
template: 'nav-data.template.js',
outputPath: 'js/nav-data.js',
areas: areas
});
var docData = {
docType: 'pages-data',
id: 'pages-data',
template: 'pages-data.template.js',
outputPath: 'js/pages-data.js',
areas: areas,
pages: pages
};
docs.push(docData);
}
var searchData = _(pages)
.filter(function(page) {
return page.searchTerms;
})
.map(function(page) {
return _.extend({ path: page.path }, page.searchTerms);
})
.value();
docs.push({
docType: 'json-doc',
id: 'search-data-json',
template: 'json-doc.template.json',
outputPath: 'js/search-data.json',
data: searchData
});
// Extract a list of basic page information for mapping paths to partials and for client side searching
var pageData = _(docs)
.map(function(doc) {
return _.pick(doc, ['name', 'area', 'path']);
})
.indexBy('path')
.value();
docs.push({
docType: 'pages-data',
id: 'pages-data',
template: 'pages-data.template.js',
outputPath: 'js/pages-data.js',
pages: pageData
});
}
};
};
@@ -1,50 +0,0 @@
var _ = require('lodash');
var path = require('canonical-path');
module.exports = {
name: 'protractor-generate',
description: 'Generate a protractor test file from the e2e tests in the examples',
runAfter: ['adding-extra-docs'],
runBefore: ['extra-docs-added'],
process: function(docs, examples, config) {
var protractorFolder = config.get('rendering.protractor.outputFolder', 'ptore2e');
_.forEach(examples, function(example) {
_.forEach(example.files, function(file) {
// Check if it's a Protractor test.
if (file.type !== 'protractor') {
return;
}
// Create new files for the tests.
docs.push(createProtractorDoc(example, file, 'jquery'));
docs.push(createProtractorDoc(example, file, 'jqlite'));
});
});
function createProtractorDoc(example, file, env) {
var protractorDoc = {
docType: 'e2e-test',
id: 'protractorTest' + '-' + example.id,
template: 'protractorTests.template.js',
outputPath: path.join(protractorFolder, example.id, env + '_test.js'),
innerTest: file.fileContents,
pathPrefix: '.', // Hold for if we test with full jQuery
exampleId: example.id,
description: example.doc.id,
'ng-app-included': example['ng-app-included']
};
if (env === 'jquery') {
protractorDoc.examplePath = example.outputFolder + '/index-jquery.html';
} else {
protractorDoc.examplePath = example.outputFolder + '/index.html';
}
return protractorDoc;
}
}
};
+29 -33
View File
@@ -1,38 +1,34 @@
"use strict";
var _ = require('lodash');
module.exports = {
name: 'versions-data',
description: 'This plugin will create a new doc that will be rendered as an angularjs module ' +
'which will contain meta information about the versions of angular',
runAfter: ['adding-extra-docs', 'pages-data'],
runBefore: ['extra-docs-added'],
process: function(docs, gitData) {
/**
* @dgProcessor generateVersionDocProcessor
* @description
* This processor will create a new doc that will be rendered as a JavaScript file
* containing meta information about the current versions of AngularJS
*/
module.exports = function generateVersionDocProcessor(gitData) {
return {
$runAfter: ['generatePagesDataProcessor'],
$runBefore: ['rendering-docs'],
$process: function(docs) {
var version = gitData.version;
var versions = gitData.versions;
var versionDoc = {
docType: 'versions-data',
id: 'versions-data',
template: 'versions-data.template.js',
outputPath: 'js/versions-data.js',
currentVersion: gitData.version
};
if ( !version ) {
throw new Error('Invalid configuration. Please provide a valid `source.currentVersion` property');
versionDoc.versions = _(gitData.versions)
.filter(function(version) { return version.major > 0; })
.push(gitData.version)
.reverse()
.value();
docs.push(versionDoc);
}
if ( !versions ) {
throw new Error('Invalid configuration. Please provide a valid `source.previousVersions` property');
}
var versionDoc = {
docType: 'versions-data',
id: 'versions-data',
template: 'versions-data.template.js',
outputPath: 'js/versions-data.js',
};
versionDoc.currentVersion = version;
versionDoc.versions = _(versions)
.filter(function(version) { return version.major > 0; })
.push(version)
.reverse()
.value();
docs.push(versionDoc);
}
};
};
};
+39
View File
@@ -0,0 +1,39 @@
"use strict";
module.exports = function debugDeployment(getVersion) {
return {
name: 'debug',
examples: {
commonFiles: {
scripts: [ '../../../angular.js' ]
},
dependencyPath: '../../../'
},
scripts: [
'../angular.js',
'../angular-resource.js',
'../angular-route.js',
'../angular-cookies.js',
'../angular-sanitize.js',
'../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',
'components/google-code-prettify-' + getVersion('google-code-prettify') + '/src/lang-css.js',
'js/versions-data.js',
'js/pages-data.js',
'js/nav-data.js',
'js/docs.js'
],
stylesheets: [
'components/bootstrap-' + getVersion('bootstrap') + '/css/bootstrap.css',
'components/open-sans-fontface-' + getVersion('open-sans-fontface') + '/open-sans.css',
'css/prettify-theme.css',
'css/docs.css',
'css/animations.css'
]
};
};
@@ -0,0 +1,39 @@
"use strict";
module.exports = function defaultDeployment(getVersion) {
return {
name: 'default',
examples: {
commonFiles: {
scripts: [ '../../../angular.min.js' ]
},
dependencyPath: '../../../'
},
scripts: [
'../angular.min.js',
'../angular-resource.min.js',
'../angular-route.min.js',
'../angular-cookies.min.js',
'../angular-sanitize.min.js',
'../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',
'components/google-code-prettify-' + getVersion('google-code-prettify') + '/src/lang-css.js',
'js/versions-data.js',
'js/pages-data.js',
'js/nav-data.js',
'js/docs.min.js'
],
stylesheets: [
'components/bootstrap-' + getVersion('bootstrap') + '/css/bootstrap.min.css',
'components/open-sans-fontface-' + getVersion('open-sans-fontface') + '/open-sans.css',
'css/prettify-theme.css',
'css/docs.css',
'css/animations.css'
]
};
};
+43
View File
@@ -0,0 +1,43 @@
"use strict";
module.exports = function jqueryDeployment(getVersion) {
return {
name: 'jquery',
examples: {
commonFiles: {
scripts: [
'../../components/jquery-' + getVersion('jquery') + '/jquery.js',
'../../../angular.js'
]
},
dependencyPath: '../../../'
},
scripts: [
'components/jquery-' + getVersion('jquery') + '/jquery.js',
'../angular.min.js',
'../angular-resource.min.js',
'../angular-route.min.js',
'../angular-cookies.min.js',
'../angular-sanitize.min.js',
'../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',
'components/google-code-prettify-' + getVersion('google-code-prettify') + '/src/lang-css.js',
'js/versions-data.js',
'js/pages-data.js',
'js/nav-data.js',
'js/docs.min.js'
],
stylesheets: [
'components/bootstrap-' + getVersion('bootstrap') + '/css/bootstrap.min.css',
'components/open-sans-fontface-' + getVersion('open-sans-fontface') + '/open-sans.css',
'css/prettify-theme.css',
'css/docs.css',
'css/animations.css'
]
};
};
@@ -0,0 +1,42 @@
"use strict";
var versionInfo = require('../../../../lib/versions/version-info');
var cdnUrl = "//ajax.googleapis.com/ajax/libs/angularjs/" + versionInfo.cdnVersion;
module.exports = function productionDeployment(getVersion) {
return {
name: 'production',
examples: {
commonFiles: {
scripts: [ cdnUrl + '/angular.min.js' ]
},
dependencyPath: cdnUrl + '/'
},
scripts: [
cdnUrl + '/angular.min.js',
cdnUrl + '/angular-resource.min.js',
cdnUrl + '/angular-route.min.js',
cdnUrl + '/angular-cookies.min.js',
cdnUrl + '/angular-sanitize.min.js',
cdnUrl + '/angular-touch.min.js',
cdnUrl + '/angular-animate.min.js',
'components/marked-' + getVersion('marked', 'node_modules', 'package.json') + '/lib/marked.js',
'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',
'components/google-code-prettify-' + getVersion('google-code-prettify') + '/src/lang-css.js',
'js/versions-data.js',
'js/pages-data.js',
'js/nav-data.js',
'js/docs.min.js'
],
stylesheets: [
'components/bootstrap-' + getVersion('bootstrap') + '/css/bootstrap.min.css',
'components/open-sans-fontface-' + getVersion('open-sans-fontface') + '/open-sans.css',
'css/prettify-theme.css',
'css/docs.css',
'css/animations.css'
]
};
};
+10
View File
@@ -0,0 +1,10 @@
"use strict";
var StringMap = require('stringmap');
/**
* @dgService errorNamespaceMap
* A map of error namespaces by name.
*/
module.exports = function errorNamespaceMap() {
return new StringMap();
};
+15
View File
@@ -0,0 +1,15 @@
"use strict";
var path = require('canonical-path');
/**
* @dgService minErrInfo
* @description
* Load the error information that was generated during the AngularJS build.
*/
module.exports = function getMinerrInfo(readFilesProcessor) {
return function() {
var minerrInfoPath = path.resolve(readFilesProcessor.basePath, 'build/errors.json');
return require(minerrInfoPath);
};
};
+17
View File
@@ -0,0 +1,17 @@
"use strict";
var path = require('canonical-path');
/**
* dgService getVersion
* @description
* Find the current version of the bower component (or npm module)
*/
module.exports = function getVersion(readFilesProcessor) {
var basePath = readFilesProcessor.basePath;
return function(component, sourceFolder, packageFile) {
sourceFolder = path.resolve(basePath, sourceFolder || 'docs/bower_components');
packageFile = packageFile || 'bower.json';
return require(path.join(sourceFolder,component,packageFile)).version;
};
};
+16
View File
@@ -0,0 +1,16 @@
"use strict";
var versionInfo = require('../../../lib/versions/version-info');
/**
* @dgService gitData
* @description
* Information from the local git repository
*/
module.exports = function gitData() {
return {
version: versionInfo.currentVersion,
versions: versionInfo.previousVersions,
info: versionInfo.gitRepoInfo
};
};
+2 -11
View File
@@ -56,15 +56,6 @@
}
})();
// force page reload when new update is available
window.applicationCache && window.applicationCache.addEventListener('updateready', function(e) {
if (window.applicationCache.status == window.applicationCache.UPDATEREADY) {
window.applicationCache.swapCache();
window.location.reload();
}
}, false);
// GA asynchronous tracker
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-8594346-3']);
@@ -85,7 +76,7 @@
<div class="row">
<div class="col-md-9 header-branding">
<a class="brand navbar-brand" href="http://angularjs.org">
<img class="logo" src="img/angularjs-for-header-only.svg">
<img width="117" height="30" class="logo" ng-src="img/angularjs-for-header-only.svg">
</a>
<ul class="nav navbar-nav">
<li class="divider-vertical"></li>
@@ -219,7 +210,7 @@
</div>
<div class="grid-right">
<div id="loading" ng-show="loading">Loading...</div>
<div ng-hide="loading" ng-include="currentPage.outputPath || 'Error404.html'" onload="afterPartialLoaded()" autoscroll></div>
<div ng-hide="loading" ng-include="partialPath" autoscroll></div>
</div>
</div>
</section>
@@ -0,0 +1 @@
{$ doc.data | json $}
@@ -0,0 +1,3 @@
// Meta data used by the AngularJS docs app
angular.module('navData', [])
.value('NG_NAVIGATION', {$ doc.areas | json $});
+1 -2
View File
@@ -1,4 +1,3 @@
// Meta data used by the AngularJS docs app
angular.module('pagesData', [])
.value('NG_PAGES', {$ doc.pages | json $})
.value('NG_NAVIGATION', {$ doc.areas | json $});
.value('NG_PAGES', {$ doc.pages | json $});
@@ -1,10 +0,0 @@
describe("{$ doc.description $}", function() {
var rootEl;
beforeEach(function() {
rootEl = browser.rootEl;{% if doc['ng-app-included'] %}
browser.rootEl = '[ng-app]';{% endif %}
browser.get("{$ doc.pathPrefix $}/{$ doc.examplePath $}");
});
{% if doc['ng-app-included'] %}afterEach(function() { browser.rootEl = rootEl; });{% endif %}
{$ doc.innerTest $}
});
@@ -2,15 +2,16 @@
is HTML and wrap each line in a <p> - thus breaking the HTML #}
<div>
<a ng-click="openPlunkr('{$ doc.example.outputFolder $}')" class="btn pull-right">
<a ng-click="openPlunkr('{$ doc.path $}')" class="btn pull-right">
<i class="glyphicon glyphicon-edit">&nbsp;</i>
Edit in Plunker</a>
<div class="runnable-example"
path="{$ doc.example.outputFolder $}"
path="{$ doc.example.deployments.default.path $}"
{%- for attrName, attrValue in doc.example.attributes %}
{$ attrName $}="{$ attrValue $}"{% endfor %}>
{% for fileName, file in doc.example.files %}
{% for fileName, file in doc.example.files %}
<div class="runnable-example-file" {% for attrName, attrValue in file.attributes %}
{$ attrName $}="{$ attrValue $}"{% endfor %}>
{% code -%}
@@ -19,7 +20,7 @@
</div>
{% endfor %}
<iframe class="runnable-example-frame" src="{$ doc.example.outputFolder $}/index.html" name="{$ doc.example.id $}"></iframe>
<iframe class="runnable-example-frame" src="{$ doc.example.deployments.default.outputPath $}" name="{$ doc.example.id $}"></iframe>
</div>
</div>
+2 -2
View File
@@ -148,7 +148,7 @@ or JavaScript callbacks.
{@link ngAnimate CSS-based animations}
</td>
<td>
Follow ngAnimates CSS naming structure to reference CSS transitions / keyframe animations in AngularJS. Once defined the animation can be triggered by referencing the CSS class within the HTML template code.
Follow ngAnimates CSS naming structure to reference CSS transitions / keyframe animations in AngularJS. Once defined, the animation can be triggered by referencing the CSS class within the HTML template code.
</td>
</tr>
<tr>
@@ -156,7 +156,7 @@ or JavaScript callbacks.
{@link ngAnimate JS-based animations}
</td>
<td>
Use {@link angular.Module#animation module.animation()} to register a JavaScript animation. Once registered the animation can be triggered by referencing the CSS class within the HTML template code.
Use {@link angular.Module#animation module.animation()} to register a JavaScript animation. Once registered, the animation can be triggered by referencing the CSS class within the HTML template code.
</td>
</tr>
</table>
+2 -2
View File
@@ -12,10 +12,10 @@ $controller(MyController);
$controller(MyController, {scope: newScope});
```
To fix the example above please provide a scope to the $controller call:
To fix the example above please provide a scope (using the `$scope` property in the locals object) to the $controller call:
```
$controller(MyController, {$scope, newScope});
$controller(MyController, {$scope: newScope});
```
Please consult the {@link ng.$controller $controller} service api docs to learn more.
+15 -1
View File
@@ -54,4 +54,18 @@ angular.module('myModule')
.directive('myDirective', ['myCoolService', function (myCoolService) {
// This directive definition does not throw unknown provider.
}]);
```
```
Attempting to inject one controller into another will also throw an `Unknown provider` error:
```
angular.module('myModule', [])
.controller('MyFirstController', function() { /* ... */ });
.controller('MySecondController', ['MyFirstController', function(MyFirstController) {
// This controller throws an unknown provider error because
// MyFirstController cannot be injected.
}]);
```
Use the `$controller` service if you want to instantiate controllers yourself.
+1 -1
View File
@@ -15,7 +15,7 @@ For example the issue can be triggered by this *invalid* code:
To resolve this error either ensure that the items in the collection have unique identity or use the `track by` syntax to specify how to track the association between models and DOM.
To resolve the example above can be resolved by using `track by $index`, which will cause the items to be keyed by their position in the array instead of their value:
The example above can be resolved by using `track by $index`, which will cause the items to be keyed by their position in the array instead of their value:
```
<div ng-repeat="value in [4, 4] track by $index"></div>
+13 -13
View File
@@ -164,7 +164,7 @@ encoded.
`$location` service has two configuration modes which control the format of the URL in the browser
address bar: **Hashbang mode** (the default) and the **HTML5 mode** which is based on using the
HTML5 [History API](http://www.w3.org/TR/html5/history.html). Applications use the same API in
HTML5 [History API](http://www.w3.org/TR/html5/introduction.html#history-0). Applications use the same API in
both modes and the `$location` service will work with appropriate URL segments and browser APIs to
facilitate the browser URL change and history management.
@@ -211,6 +211,10 @@ facilitate the browser URL change and history management.
## Hashbang mode (default mode)
In this mode, `$location` uses Hashbang URLs in all browsers.
Angular also does not intercept and rewrite links in this mode. I.e. links work
as expected and also perform full page reloads when other parts of the url
than the hash fragment was changed.
### Example
@@ -241,7 +245,7 @@ it('should show example', inject(
## HTML5 mode
In HTML5 mode, the `$location` service getters and setters interact with the browser URL address
through the HTML5 history API, which allows for use of regular URL path and search segments,
through the HTML5 history API. This allows for use of regular URL path and search segments,
instead of their hashbang equivalents. If the HTML5 History API is not supported by a browser, the
`$location` service will fall back to using the hashbang URLs automatically. This frees you from
having to worry about whether the browser displaying your app supports the history API or not; the
@@ -250,6 +254,10 @@ having to worry about whether the browser displaying your app supports the histo
- Opening a regular URL in a legacy browser -> redirects to a hashbang URL
- Opening hashbang URL in a modern browser -> rewrites to a regular URL
Note that in this mode, Angular intercepts all links (subject to the "Html link rewriting" rules below)
and updates the url in a way that never performs a full page reload.
### Example
```js
@@ -298,8 +306,8 @@ history API or not; the `$location` service makes this transparent to you.
### Html link rewriting
When you use HTML5 history API mode, you will need different links in different browsers, but all you
have to do is specify regular URL links, such as: `<a href="/some?foo=bar">link</a>`
When you use HTML5 history API mode, you will not need special hashbang links. All you have to do
is specify regular URL links, such as: `<a href="/some?foo=bar">link</a>`
When a user clicks on this link,
@@ -314,17 +322,9 @@ reload to the original link.
Example: `<a href="/ext/link?a=b" target="_self">link</a>`
- Absolute links that go to a different domain<br>
Example: `<a href="http://angularjs.org/">link</a>`
- Links starting with '/' that lead to a different base path when base is defined<br>
- Links starting with '/' that lead to a different base path<br>
Example: `<a href="/not-my-base/link">link</a>`
When running Angular in the root of a domain, along side perhaps a normal application in the same
directory, the "otherwise" route handler will try to handle all the URLs, including ones that map
to static files.
To prevent this, you can set your base href for the app to `<base href=".">` and then prefix links
to URLs that should be handled with `.`. Now, links to locations, which are not to be routed by Angular,
are not prefixed with `.` and will not be intercepted by the `otherwise` rule in your `$routeProvider`.
### Server side
+4 -2
View File
@@ -20,7 +20,7 @@ initialization.
<html xmlns:ng="http://angularjs.org" ng-app>
<body>
...
<script src="angular.js">
<script src="angular.js"></script>
</body>
</html>
```
@@ -91,7 +91,9 @@ Here is an example of manually initializing Angular:
<!doctype html>
<html>
<body>
Hello {{greetMe}}!
<div ng-controller="MyController">
Hello {{greetMe}}!
</div>
<script src="http://code.angularjs.org/snapshot/angular.js"></script>
<script>
+7 -3
View File
@@ -3,6 +3,8 @@
@sortOrder 330
@description
# HTML Compiler
<div class="alert alert-warning">
**Note:** this guide is targeted towards developers who are already familiar with AngularJS basics.
@@ -12,7 +14,7 @@ If you want a deeper look into Angular's compilation process, you're in the righ
</div>
# Overview
## Overview
Angular's {@link ng.$compile HTML compiler} allows the developer to teach the
browser new HTML syntax. The compiler allows you to attach behavior to any HTML element or attribute
@@ -85,7 +87,9 @@ Here is a directive which makes any element draggable. Notice the `draggable` at
position: 'relative',
border: '1px solid red',
backgroundColor: 'lightgrey',
cursor: 'pointer'
cursor: 'pointer',
display: 'block',
width: '65px'
});
element.on('mousedown', function(event) {
// Prevent default dragging of selected content
@@ -328,7 +332,7 @@ The first issue we have to solve is that the dialog box template expects `title`
But we would like the template's scope property `title` to be the result of interpolating the
`<dialog>` element's `title` attribute (i.e. `"Hello {{username}}"`). Furthermore, the buttons expect
the `onOk` and `onCancel` functions to be present in the scope. This limits the usefulness of the
widget. To solve the mapping issue we use the `locals` to create local variables which the template
widget. To solve the mapping issue we use the `scope` to create local variables which the template
expects as follows:
```js
+8 -8
View File
@@ -56,10 +56,10 @@ Try out the Live Preview above, and then let's walk through the example and desc
This looks like normal HTML, with some new markup. In Angular, a file like this is called a
<a name="template">"{@link templates template}"</a>. When Angular starts your application, it parses and
processes this new markup from the template using the so called <a name="compiler">"{@link compiler compiler}"</a>.
processes this new markup from the template using the so-called <a name="compiler">"{@link compiler compiler}"</a>.
The loaded, transformed and rendered DOM is then called the <a name="view">"view"</a>.
The first kind of new markup are the so called <a name="directive">"{@link directive directives}"</a>.
The first kind of new markup are the so-called <a name="directive">"{@link directive directives}"</a>.
They apply special behavior to attributes or elements in the HTML. In the example above we use the
{@link ng.directive:ngApp `ng-app`} attribute, which is linked to a directive that automatically
initializes our application. Angular also defines a directive for the {@link ng.directive:input `input`}
@@ -67,8 +67,8 @@ element that adds extra behavior to the element. The {@link ng.directive:ngModel
stores/updates the value of the input field into/from a variable.
<div class="alert alert-info">
**Custom directives to access the DOM**: In Angular, the only place where an application touches the DOM is
within directives. This is good as artifacts that access the DOM are hard to test.
**Custom directives to access the DOM**: In Angular, the only place where an application should access the DOM is
within directives. This is important because artifacts that access the DOM are hard to test.
If you need to access the DOM directly you should write a custom directive for this. The
{@link directive directives guide} explains how to do this.
</div>
@@ -89,7 +89,7 @@ A filter formats the value of an expression for display to the user.
In the example above, the filter {@link ng.filter:currency `currency`} formats a number
into an output that looks like money.
The important thing in the example is that angular provides _live_ bindings:
The important thing in the example is that Angular provides _live_ bindings:
Whenever the input values change, the value of the expressions are automatically
recalculated and the DOM is updated with their values.
The concept behind this is <a name="databinding">"{@link databinding two-way data binding}"</a>.
@@ -150,13 +150,13 @@ different currencies and also pay the invoice.
What changed?
First, there is a new JavaScript file that contains a so called <a name="controller">"{@link controller controller}"</a>.
First, there is a new JavaScript file that contains a so-called <a name="controller">"{@link controller controller}"</a>.
More exactly, the file contains a constructor function that creates the actual controller instance.
The purpose of controllers is to expose variables and functionality to expressions and directives.
Besides the new file that contains the controller code we also added a
{@link ng.directive:ngController `ng-controller`} directive to the HTML.
This directive tells angular that the new `InvoiceController` is responsible for the element with the directive
This directive tells Angular that the new `InvoiceController` is responsible for the element with the directive
and all of the element's children.
The syntax `InvoiceController as invoice` tells Angular to instantiate the controller
and save it in the variable `invoice` in the current scope.
@@ -263,7 +263,7 @@ services, ...) is created and wired using dependency injection. Within Angular,
the DI container is called the <a name="injector">"{@link di injector}"</a>.
To use DI, there needs to be a place where all the things that should work together are registered.
In Angular, this is the purpose of the so called <a name="module">"{@link module modules}"</a>.
In Angular, this is the purpose of the so-called <a name="module">"{@link module modules}"</a>.
When Angular starts, it will use the configuration of the module with the name defined by the `ng-app` directive,
including the configuration of all modules that this module depends on.
+1 -1
View File
@@ -326,7 +326,7 @@ describe('state', function() {
expect(childScope.timeOfDay).toBe('morning');
expect(childScope.name).toBe('Mattie');
expect(grandChildScope.timeOfDay).toBe('evening');
expect(grandChildScope.name).toBe('Gingerbreak Baby');
expect(grandChildScope.name).toBe('Gingerbread Baby');
});
});
```
+1 -1
View File
@@ -160,7 +160,7 @@ restrictions, you cannot simply write `cx="{{cx}}"`.
With `ng-attr-cx` you can work around this problem.
If an attribute with a binding is prefixed with the `ngAttr` prefix (denormalized as `ng-attr-`)
then during the binding will be applied to the corresponding unprefixed attribute. This allows
then during the binding it will be applied to the corresponding unprefixed attribute. This allows
you to bind to attributes that would otherwise be eagerly processed by browsers
(e.g. an SVG element's `circle[cx]` attributes).
+2 -2
View File
@@ -27,8 +27,8 @@ Protractor is a [Node.js](http://nodejs.org) program, and runs end to end tests
written in JavaScript and run with node. Protractor uses [WebDriver](https://code.google.com/p/selenium/wiki/GettingStarted)
to control browsers and simulate user actions.
For more information on Protractor, view [getting started](https://github.com/angular/protractor/blob/master/docs/getting-started.md)
or the [api docs](https://github.com/angular/protractor/blob/master/docs/api.md).
For more information on Protractor, view [getting started](http://angular.github.io/protractor/#/getting-started)
or the [api docs](http://angular.github.io/protractor/#/api).
Protractor uses [Jasmine](http://jasmine.github.io/1.3/introduction.html) for its test syntax.
As in unit testing, a test file is comprised of one or
+1 -1
View File
@@ -206,7 +206,7 @@ In the following example we create two directives.
* The first one is `integer` and it validates whether the input is a valid integer.
For example `1.23` is an invalid value, since it contains a fraction.
Note that we unshift the array instead of pushing.
This is because we want to be first parser and consume the control string value, as we need to execute the validation function before a conversion to number occurs.
This is because we want it to be the first parser and consume the control string value, as we need to execute the validation function before a conversion to number occurs.
* The second directive is a `smart-float`.
It parses both `1.2` and `1,2` into a valid float number `1.2`.
+8 -5
View File
@@ -41,7 +41,7 @@ In Angular applications, you move the job of filling page templates with data fr
### Other AngularJS Features
* **Animation:** {@link guide/animations Core concepts}, {@link ngAnimate ngAnimate API}, and [Animation in AngularJS 1.2](http://www.yearofmoo.com/2013/08/remastered-animation-in-angularjs-1-2.html)
* **Security:** {@link ng.$sce Strict Contextual Escaping}, {@link ng.directive:ngCsp Content Security Policy}, {@link ngSanitize.$sanitize $sanitize}, [video](https://www.youtube.com/watch?v=18ifoT-Id54)
* **Security:** {@link guide/security Security Docs}, {@link ng.$sce Strict Contextual Escaping}, {@link ng.directive:ngCsp Content Security Policy}, {@link ngSanitize.$sanitize $sanitize}, [video](https://www.youtube.com/watch?v=18ifoT-Id54)
* **Internationalization and Localization:** {@link guide/i18n Angular Guide to i18n and l10n}, {@link ng.filter:date date filter}, {@link ng.filter:currency currency filter}, [Creating multilingual support](http://www.novanet.no/blog/hallstein-brotan/dates/2013/10/creating-multilingual-support-using-angularjs/)
* **Mobile:** {@link ngTouch Touch events}
@@ -70,7 +70,7 @@ In Angular applications, you move the job of filling page templates with data fr
This is a short list of libraries with specific support and documentation for working with Angular. You can find a full list of all known Angular external libraries at [ngmodules.org](http://ngmodules.org/).
* **Internationalization:** [angular-translate](http://angular-translate.github.io), [angular-gettext](http://angular-gettext.rocketeer.be/)
* **Internationalization:** [angular-translate](http://angular-translate.github.io), [angular-gettext](http://angular-gettext.rocketeer.be/), [angular-localization](http://doshprompt.github.io/angular-localization/)
* **RESTful services:** [Restangular](https://github.com/mgonto/restangular)
* **SQL and NoSQL backends:** [BreezeJS](http://www.breezejs.com/), [AngularFire](http://angularfire.com/)
* **UI Widgets: **[KendoUI](http://kendo-labs.github.io/angular-kendo/#/), [UI Bootstrap](http://angular-ui.github.io/bootstrap/), [Wijmo](http://wijmo.com/tag/angularjs-2/), [ngTagsInput](https://github.com/mbenford/ngTagsInput)
@@ -89,11 +89,12 @@ This is a short list of libraries with specific support and documentation for wo
* **Django:** [Tutorial](http://blog.mourafiq.com/post/55034504632/end-to-end-web-app-with-django-rest-framework), [Integrating AngularJS with Django](http://django-angular.readthedocs.org/en/latest/integration.html), [Getting Started with Django Rest Framework and AngularJS](http://blog.kevinastone.com/getting-started-with-django-rest-framework-and-angularjs.html)
* **FireBase:** [AngularFire](http://angularfire.com/), [Realtime Apps with AngularJS and FireBase (video)](http://www.youtube.com/watch?v=C7ZI7z7qnHU)
* **Google Cloud Platform: **[with Cloud Endpoints](https://cloud.google.com/resources/articles/angularjs-cloud-endpoints-recipe-for-building-modern-web-applications), [with Go](https://github.com/GoogleCloudPlatform/appengine-angular-gotodos)
* **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)
* **Rails: **[Tutorial](http://coderberry.me/blog/2013/04/22/angularjs-on-rails-4-part-1/), [AngularJS with Rails4](https://shellycloud.com/blog/2013/10/how-to-integrate-angularjs-with-rails-4), [angularjs-rails](https://github.com/hiravgandhi/angularjs-rails)
* **PHP: **[Building a RESTful web service](http://blog.brunoscopelliti.com/building-a-restful-web-service-with-angularjs-and-php-more-power-with-resource), [End to End with Laravel 4 (video)](http://www.youtube.com/watch?v=hqAyiqUs93c)
* **Meteor: **[angular-meteor package](https://github.com/Urigo/angular-meteor)
## Learning Resources
@@ -104,6 +105,8 @@ This is a short list of libraries with specific support and documentation for wo
* [Recipes With AngularJS](http://www.amazon.co.uk/Recipes-Angular-js-Frederik-Dietz-ebook/dp/B00DK95V48) by Frederik Dietz
* [Developing an AngularJS Edge](http://www.amazon.com/Developing-AngularJS-Edge-Christopher-Hiller-ebook/dp/B00CJLFF8K) by Christopher Hiller
* [ng-book: The Complete Book on AngularJS](http://ng-book.com/) by Ari Lerner
* [AngularJS : Novice to Ninja](http://www.amazon.in/AngularJS-Novice-Ninja-Sandeep-Panda/dp/0992279453) by Sandeep Panda
* [AngularJS UI Development](http://www.amazon.com/AngularJS-UI-Development-Amit-Ghart-ebook/dp/B00OXVAK7A) by Amit Gharat and Matthias Nehlsen
###Videos:
* [egghead.io](http://egghead.io/)
@@ -112,12 +115,12 @@ This is a short list of libraries with specific support and documentation for wo
### Courses
* **Free online:**
[thinkster.io](http://thinkster.io),
[CodeAcademy](http://www.codecademy.com/courses/javascript-advanced-en-2hJ3J/0/1)
[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:**
[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)
[lynda.com](http://www.lynda.com/AngularJS-tutorials/Up-Running-AngularJS/133318-2.html),
[WintellectNOW (4 lessons)](http://www.wintellectnow.com/Course/Detail/mastering-angularjs)
* **Paid onsite:**
[angularbootcamp.com](http://angularbootcamp.com/)
+3 -3
View File
@@ -9,7 +9,7 @@
AngularJS is a structural framework for dynamic web apps. It lets you use HTML as your template
language and lets you extend HTML's syntax to express your application's components clearly and
succinctly. Angular's data binding and dependency injection eliminate much of the code you
currently have to write. And it all happens within the browser, making it
would otherwise have to write. And it all happens within the browser, making it
an ideal partner with any server technology.
Angular is what HTML would have been had it been designed for applications. HTML is a great
@@ -33,7 +33,7 @@ browser new syntax through a construct we call directives. Examples include:
* Data binding, as in `{{}}`.
* DOM control structures for repeating/hiding DOM fragments.
* Support for forms and form validation.
* Attaching code-behind to DOM elements.
* Attaching new behavior to DOM elements, such as DOM event handling.
* Grouping of HTML into reusable components.
@@ -103,7 +103,7 @@ Angular frees you from the following pains:
* **Writing tons of initialization code just to get started:** Typically you need to write a lot
of plumbing just to get a basic "Hello World" AJAX app working. With Angular you can bootstrap
your app easily using services, which are auto-injected into your application in a
[Guice](http://code.google.com/p/google-guice/)-like dependency-injection style. This allows you
[Guice](https://github.com/google/guice)-like dependency-injection style. This allows you
to get started developing features quickly. As a bonus, you get full control over the
initialization process in automated tests.
+9 -1
View File
@@ -409,7 +409,15 @@ To wrap it up, let's summarize the most important points:
<td class="success">yes\*\*</td>
</tr>
<tr>
<td>can create functions/primitives</td>
<td>can create functions</td>
<td class="success">yes</td>
<td class="success">yes</td>
<td class="success">yes</td>
<td class="success">yes</td>
<td class="success">yes</td>
</tr>
<tr>
<td>can create primitives</td>
<td class="success">yes</td>
<td class="error">no</td>
<td class="success">yes</td>
+13 -1
View File
@@ -39,7 +39,7 @@ linking} phase the {@link ng.$compileProvider#directive directives} set up
render the updated value to the DOM.
Both controllers and directives have reference to the scope, but not to each other. This
arrangement isolates the controller from the directive as well as from DOM. This is an important
arrangement isolates the controller from the directive as well as from the DOM. This is an important
point since it makes the controllers view agnostic, which greatly improves the testing story of
the applications.
@@ -339,6 +339,18 @@ the dirty checking function must be efficient. Care should be taken that the dir
function does not do any DOM access, as DOM access is orders of magnitude slower than property
access on JavaScript object.
### Scope `$watch` Depths
<img class="pull-right" style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-scope-watch-strategies.png">
Dirty checking can be done with three strategies: By reference, by collection contents, and by value. The strategies differ in the kinds of changes they detect, and in their performance characteristics.
- Watching *by reference* ({@link
ng.$rootScope.Scope#$watch scope.$watch} `(watchExpression, listener)`) detects a change when the whole value returned by the watch expression switches to a new value. If the value is an array or an object, changes inside it are not detected. This is the most efficient stategy.
- Watching *collection contents* ({@link
ng.$rootScope.Scope#$watchCollection scope.$watchCollection} `(watchExpression, listener)`) detects changes that occur inside an array or an object: When items are added, removed, or reordered. The detection is shallow - it does not reach into nested collections. Watching collection contents is more expensive than watching by reference, because copies of the collection contents need to be maintained. However, the strategy attempts to minimize the amount of copying required.
- Watching *by value* ({@link
ng.$rootScope.Scope#$watch scope.$watch} `(watchExpression, listener, true)`) detects any change in an arbitrarily nested data structure. It is the most powerful change detection strategy, but also the most expensive. A full traversal of the nested data structure is needed on each digest, and a full copy of it needs to be held in memory.
## Integration with the browser event loop
<img class="pull-right" style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-runtime.png">
+60
View File
@@ -0,0 +1,60 @@
@ngdoc overview
@name Security
@sortOrder 525
@description
# Security
This document explains some of AngularJS's security features and best practices that you should
keep in mind as you build your application.
## Expression Sandboxing
AngularJS's expressions are sandboxed not for security reasons, but instead to maintain a proper
separation of application responsibilities. For example, access to `window` is disallowed
because it makes it easy to introduce brittle global state into your application.
However, this sandbox is not intended to stop attackers who can edit the template before it's
processed by Angular. It may be possible to run arbitrary JavaScript inside double-curly bindings
if an attacker can modify them.
But if an attacker can change arbitrary HTML templates, there's nothing stopping them from doing:
```html
<script>somethingEvil();</script>
```
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
* Do not use user input to generate templates dynamically
* 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
In general, we recommend against this because it can create unintended XSS vectors.
However, it's ok to mix server-side templating in the bootstrap template (`index.html`) as long
as user input cannot be used on the server to output html that would then be processed by Angular
in a way that would cause 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.
## 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 above points about Angular's expression language.
## See also
* {@link ng.directive:ngCsp Content Security Policy}
* {@link ng.$sce Strict Contextual Escaping}
* {@link ngSanitize.$sanitize $sanitize}
+2 -2
View File
@@ -268,8 +268,8 @@ logic, further simplifying the application logic.
```js
myModule.filter('length', function() {
return function(text){
return (''+(text||'')).length;
return function(text) {
return ('' + (text || '')).length;
}
});
+1 -1
View File
@@ -31,7 +31,7 @@ development web server, run tests, and generate distributable files. Depending o
pre-packaged bundle.
* [Java](http://www.java.com): We minify JavaScript using our
[Closure Tools](https://developers.google.com/closure/) jar. Make sure you have Java (version 6 or higher) installed
[Closure Tools](https://developers.google.com/closure/) jar. Make sure you have Java (version 7 or higher) installed
and included in your [PATH](http://docs.oracle.com/javase/tutorial/essential/environment/paths.html) variable.
* [Grunt](http://gruntjs.com): We use Grunt as our build system. Install the grunt command-line tool globally with:
+3 -3
View File
@@ -22,7 +22,7 @@ So it's definitely not a plugin or some other native browser extension.
### Is AngularJS a templating system?
At the highest level, Angular does look like a just another templating system. But there is one
At the highest level, Angular does look like just another templating system. But there is one
important reason why the Angular templating system is different, that makes it very good fit for
application development: bidirectional data binding. The template is compiled in the browser and
the compilation step produces a live view. This means you, the developers, don't need to write
@@ -39,7 +39,7 @@ for server-side communication.
AngularJS was designed to be compatible with other security measures like Content Security Policy
(CSP), HTTPS (SSL/TLS) and server-side authentication and authorization that greatly reduce the
possible attack vectors and we highly recommended their use.
possible attack vectors and we highly recommend their use.
### Can I download the source, build, and host the AngularJS environment locally?
@@ -204,7 +204,7 @@ If you want to apply a directive to each inner piece of the repeat, put it on a
### `$rootScope` exists, but it can be used for evil
Scopes in Angular form a hierarchy, prototypically inheriting from a root scope at the top of the tree.
Scopes in Angular form a hierarchy, prototypally inheriting from a root scope at the top of the tree.
Usually this can be ignored, since most views have a controller, and therefore a scope, of their own.
Occasionally there are pieces of data that you want to make global to the whole app.
+2 -1
View File
@@ -110,8 +110,9 @@ suggested solution is to also install the `nodejs-legacy` apt package, which ren
`nodejs`.
```
apt-get install nodejs-legacy
apt-get install nodejs-legacy npm
nodejs --version
npm --version
```
+2 -2
View File
@@ -233,7 +233,7 @@ browser is limited, which results in your karma tests running extremely slow.
Refresh your browser and verify that it says "Hello, World!".
* Update the unit test for the controller in ./test/unit/controllersSpec.js to reflect the previous change. For example by adding:
* Update the unit test for the controller in `./test/unit/controllersSpec.js` to reflect the previous change. For example by adding:
expect(scope.name).toBe('World');
@@ -251,7 +251,7 @@ browser is limited, which results in your karma tests running extremely slow.
<tr ng-repeat="i in [0, 1, 2, 3, 4, 5, 6, 7]"><td>{{i+1}}</td></tr>
</table>
Extra points: try and make an 8x8 table using an additional ng-repeat.
Extra points: try and make an 8x8 table using an additional `ng-repeat`.
* Make the unit test fail by changing `expect(scope.phones.length).toBe(3)` to instead use `toBe(4)`.
+3 -3
View File
@@ -95,7 +95,7 @@ describe('PhoneCat App', function() {
});
it('should filter the phone list as user types into the search box', function() {
it('should filter the phone list as a user types into the search box', function() {
var phoneList = element.all(by.repeater('phone in phones'));
var query = element(by.model('query'));
@@ -120,7 +120,7 @@ really is that easy to set up any functional, readable, end-to-end test.
### Running End to End Tests with Protractor
Even though the syntax of this test looks very much like our controller unit test written with
Jasmine, the end-to-end test uses APIs of [Protractor](https://github.com/angular/protractor). Read
about the Protractor APIs at https://github.com/angular/protractor/blob/master/docs/api.md.
about the Protractor APIs at http://angular.github.io/protractor/#/api.
Much like Karma is the test runner for unit tests, we use Protractor to run end-to-end tests.
Try it with `npm run protractor`. End-to-end tests are slow, so unlike with unit tests, Protractor
@@ -159,7 +159,7 @@ Let's see how we can get the current value of the `query` model to appear in the
var phoneList = element.all(by.repeater('phone in phones'));
var query = element(by.model('query'));
it('should filter the phone list as user types into the search box', function() {
it('should filter the phone list as a user types into the search box', function() {
expect(phoneList.count()).toBe(3);
query.sendKeys('nexus');
+1 -1
View File
@@ -182,7 +182,7 @@ You can now rerun `npm run protractor` to see the tests run.
# Experiments
* In the `PhoneListCtrl` controller, remove the statement that sets the `orderProp` value and
you'll see that Angular will temporarily add a new "unknown" option to the drop-down list and the
you'll see that Angular will temporarily add a new blank ("unknown") option to the drop-down list and the
ordering will default to unordered/natural order.
* Add an `{{orderProp}}` binding into the `index.html` template to display its current value as
+6 -4
View File
@@ -11,7 +11,7 @@ from our server using one of Angular's built-in {@link guide/services services}
ng.$http $http}. We will use Angular's {@link guide/di dependency
injection (DI)} to provide the service to the `PhoneListCtrl` controller.
* There are now a list of 20 phones, loaded from the server.
* There is now a list of 20 phones, loaded from the server.
<div doc-tutorial-reset="5"></div>
@@ -236,7 +236,9 @@ the response is received:
```
* We flush the request queue in the browser by calling `$httpBackend.flush()`. This causes the
promise returned by the `$http` service to be resolved with the trained response.
promise returned by the `$http` service to be resolved with the trained response. See
'Flushing HTTP requests' in the {@link ngMock.$httpBackend mock $httpBackend} documentation for
a full explanation of why this is necessary.
* We make the assertions, verifying that the phone model now exists on the scope.
@@ -256,8 +258,8 @@ You should now see the following output in the Karma tab:
# Experiments
* At the bottom of `index.html`, add a `<pre>{{phones | json}}</pre>` binding to see the list of phones
displayed in json format.
* At the bottom of `index.html`, add a `<pre>{{phones | filter:query | orderBy:orderProp | json}}</pre>`
binding to see the list of phones displayed in json format.
* In the `PhoneListCtrl` controller, pre-process the http response by limiting the number of phones
to the first 5 in the list. Use the following code in the `$http` callback:
+4 -3
View File
@@ -9,7 +9,7 @@
In this step, you will learn how to create a layout template and how to build an app that has
multiple views by adding routing, using an Angular module called 'ngRoute'.
* When you now navigate to `app/index.html`, you are redirected to `app/index.html#/phones`
* When you now navigate to `app/index.html`, you are redirected to `app/index.html/#/phones`
and the phone list appears in the browser.
* When you click on a phone link the url changes to one specific to that phone and the stub of a
phone detail page is displayed.
@@ -26,15 +26,16 @@ We are using [Bower][bower] to install client side dependencies. This step upda
```json
{
"name": "angular-seed",
"name": "angular-phonecat",
"description": "A starter project for AngularJS",
"version": "0.0.0",
"homepage": "https://github.com/angular/angular-seed",
"homepage": "https://github.com/angular/angular-phonecat",
"license": "MIT",
"private": true,
"dependencies": {
"angular": "1.2.x",
"angular-mocks": "~1.2.x",
"jquery": "1.10.2",
"bootstrap": "~3.1.1",
"angular-route": "~1.2.x"
}
+1 -1
View File
@@ -184,7 +184,7 @@ You can now rerun `npm run protractor` to see the tests run.
# Experiments
* Using the [Protractor API](https://github.com/angular/protractor/blob/master/docs/api.md),
* Using the [Protractor API](http://angular.github.io/protractor/#/api),
write a test that verifies that we display 4 thumbnail images on the Nexus S details page.
+9 -2
View File
@@ -49,8 +49,15 @@ and install this dependency. We can do this by running:
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">
If you have bower installed globally then you can run `bower install` but for this project we have
**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>
@@ -164,7 +171,7 @@ we require, so in these cases, we can add a callback to process the server respo
## Test
Because we're now using the {@link ngResource ngResource} module, it's necessary to also need to
Because we're now using the {@link ngResource ngResource} module, it's necessary to
update the Karma config file with angular-resource so the new tests will pass.
__`test/karma.conf.js`:__
+19 -11
View File
@@ -9,8 +9,8 @@
In this final step, we will enhance our phonecat web application by attaching CSS and JavaScript
animations on top of the template code we created before.
* Used the `ngAnimate` to enable animations throughout the application.
* Common `ng` directives automatically trigger hooks for animations to tap into.
* We now use the `ngAnimate` module to enable animations throughout the application.
* We also use common `ng` directives to automatically trigger hooks for animations to tap into.
* When an animation is found then the animation will run in between the standard DOM operation that
is being issued on the element at the given time (e.g. inserting and removing nodes on
{@link api/ng.directive:ngRepeat `ngRepeat`} or adding and removing classes on
@@ -21,7 +21,7 @@ animations on top of the template code we created before.
## Dependencies
The animation functionality is provided by Angular in the `ngAnimate` module, which is distributed
separately from the core Angular framework. In addition we will use `JQuery` in this project to do
separately from the core Angular framework. In addition we will use `jQuery` in this project to do
extra JavaScript animations.
We are using [Bower][bower] to install client side dependencies. This step updates the
@@ -49,8 +49,8 @@ We are using [Bower][bower] to install client side dependencies. This step upda
* `"angular-animate": "~1.2.x"` tells bower to install a version of the
angular-animate component that is compatible with version 1.2.x.
* `"jquery": "1.10.2"` tells bower to install the 1.10.2 version of JQuery. Note that this is not an
Angular library, it is the standard JQuery library. We can use bower to install a wide range of 3rd
* `"jquery": "1.10.2"` tells bower to install the 1.10.2 version of jQuery. Note that this is not an
Angular library, it is the standard jQuery library. We can use bower to install a wide range of 3rd
party libraries.
We must ask bower to download and install this dependency. We can do this by running:
@@ -59,8 +59,15 @@ We must ask bower to download and install this dependency. We can do this by run
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">
If you have bower installed globally then you can run `bower install` but for this project we have
**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>
@@ -247,7 +254,7 @@ which are described in detail below.
Next let's add an animation for transitions between route changes in {@link api/ngRoute.directive:ngView `ngView`}.
To start, let's add a new CSS class to our HTML like we did in the example above.
This time, instead of the `ng-repeat` element, let's add it to the element containing the ng-view directive.
This time, instead of the `ng-repeat` element, let's add it to the element containing the `ng-view` directive.
In order to do this, we'll have to make some small changes to the HTML code so that we can have more control over our
animations between view changes.
@@ -332,13 +339,13 @@ a cross fade animation in between. So as the previous page is just about to be r
while the new page fades in right on top of it.
Once the leave animation is over then element is removed and once the enter animation is complete
then the `ng-enter` and `ng-enter-active` CSS classes are removed from the element rendering it to
be position itself with its default CSS code (so no more absolute positioning once the animation is
then the `ng-enter` and `ng-enter-active` CSS classes are removed from the element, causing it to rerender and
reposition itself with its default CSS code (so no more absolute positioning once the animation is
over). This works fluidly so that pages flow naturally between route changes without anything
jumping around.
The CSS classes applied (the start and end classes) are much the same as with `ng-repeat`. Each time
a new page is loaded the ng-view directive will create a copy of itself, download the template and
a new page is loaded the `ng-view` directive will create a copy of itself, download the template and
append the contents. This ensures that all views are contained within a single HTML element which
allows for easy animation control.
@@ -361,7 +368,8 @@ 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:
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`.__
-188
View File
@@ -1,188 +0,0 @@
"use strict";
var path = require('canonical-path');
var versionInfo = require('../lib/versions/version-info');
var basePath = __dirname;
var basePackage = require('./config');
module.exports = function(config) {
var cdnUrl = "//ajax.googleapis.com/ajax/libs/angularjs/" + versionInfo.cdnVersion;
var getVersion = function(component, sourceFolder, packageFile) {
sourceFolder = sourceFolder || './bower_components';
packageFile = packageFile || 'bower.json';
return require(path.resolve(sourceFolder,component,packageFile)).version;
};
config = basePackage(config);
config.set('source.projectPath', path.resolve(basePath, '..'));
config.set('source.files', [
{ pattern: 'src/**/*.js', basePath: path.resolve(basePath,'..') },
{ pattern: '**/*.ngdoc', basePath: path.resolve(basePath, 'content') }
]);
config.set('processing.stopOnError', true);
config.set('processing.errors.minerrInfoPath', path.resolve(basePath, '../build/errors.json'));
config.set('rendering.outputFolder', '../build/docs');
config.set('rendering.contentsFolder', 'partials');
config.set('logging.level', 'info');
config.merge('deployment', {
environments: [{
name: 'debug',
examples: {
commonFiles: {
scripts: [ '../../../angular.js' ]
},
dependencyPath: '../../../'
},
scripts: [
'../angular.js',
'../angular-resource.js',
'../angular-route.js',
'../angular-cookies.js',
'../angular-sanitize.js',
'../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/bootstrap-prettify.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',
'components/google-code-prettify-' + getVersion('google-code-prettify') + '/src/lang-css.js',
'js/versions-data.js',
'js/pages-data.js',
'js/docs.js'
],
stylesheets: [
'components/bootstrap-' + getVersion('bootstrap') + '/css/bootstrap.css',
'components/open-sans-fontface-' + getVersion('open-sans-fontface') + '/open-sans.css',
'css/prettify-theme.css',
'css/docs.css',
'css/animations.css'
]
},
{
name: 'default',
examples: {
commonFiles: {
scripts: [ '../../../angular.min.js' ]
},
dependencyPath: '../../../'
},
scripts: [
'../angular.min.js',
'../angular-resource.min.js',
'../angular-route.min.js',
'../angular-cookies.min.js',
'../angular-sanitize.min.js',
'../angular-touch.min.js',
'../angular-animate.min.js',
'components/marked-' + getVersion('marked', '../node_modules', 'package.json') + '/lib/marked.js',
'js/angular-bootstrap/bootstrap.js',
'js/angular-bootstrap/bootstrap-prettify.js',
'js/angular-bootstrap/dropdown-toggle.js',
'components/lunr.js-' + getVersion('lunr.js') + '/lunr.min.js',
'components/google-code-prettify-' + getVersion('google-code-prettify') + '/src/prettify.js',
'components/google-code-prettify-' + getVersion('google-code-prettify') + '/src/lang-css.js',
'js/versions-data.js',
'js/pages-data.js',
'js/docs.js'
],
stylesheets: [
'components/bootstrap-' + getVersion('bootstrap') + '/css/bootstrap.min.css',
'components/open-sans-fontface-' + getVersion('open-sans-fontface') + '/open-sans.css',
'css/prettify-theme.css',
'css/docs.css',
'css/animations.css'
]
},
{
name: 'jquery',
examples: {
commonFiles: {
scripts: [
'../../components/jquery-' + getVersion('jquery') + '/jquery.js',
'../../../angular.js'
]
},
dependencyPath: '../../../'
},
scripts: [
'components/jquery-' + getVersion('jquery') + '/jquery.js',
'../angular.min.js',
'../angular-resource.min.js',
'../angular-route.min.js',
'../angular-cookies.min.js',
'../angular-sanitize.min.js',
'../angular-touch.min.js',
'../angular-animate.min.js',
'components/marked-' + getVersion('marked', '../node_modules', 'package.json') + '/lib/marked.js',
'js/angular-bootstrap/bootstrap.js',
'js/angular-bootstrap/bootstrap-prettify.js',
'js/angular-bootstrap/dropdown-toggle.js',
'components/lunr.js-' + getVersion('lunr.js') + '/lunr.min.js',
'components/google-code-prettify-' + getVersion('google-code-prettify') + '/src/prettify.js',
'components/google-code-prettify-' + getVersion('google-code-prettify') + '/src/lang-css.js',
'js/versions-data.js',
'js/pages-data.js',
'js/docs.js'
],
stylesheets: [
'components/bootstrap-' + getVersion('bootstrap') + '/css/bootstrap.min.css',
'components/open-sans-fontface-' + getVersion('open-sans-fontface') + '/open-sans.css',
'css/prettify-theme.css',
'css/docs.css',
'css/animations.css'
]
},
{
name: 'production',
examples: {
commonFiles: {
scripts: [ cdnUrl + '/angular.min.js' ]
},
dependencyPath: cdnUrl + '/'
},
scripts: [
cdnUrl + '/angular.min.js',
cdnUrl + '/angular-resource.min.js',
cdnUrl + '/angular-route.min.js',
cdnUrl + '/angular-cookies.min.js',
cdnUrl + '/angular-sanitize.min.js',
cdnUrl + '/angular-touch.min.js',
cdnUrl + '/angular-animate.min.js',
'components/marked-' + getVersion('marked', '../node_modules', 'package.json') + '/lib/marked.js',
'js/angular-bootstrap/bootstrap.js',
'js/angular-bootstrap/bootstrap-prettify.js',
'js/angular-bootstrap/dropdown-toggle.js',
'components/lunr.js-' + getVersion('lunr.js') + '/lunr.min.js',
'components/google-code-prettify-' + getVersion('google-code-prettify') + '/src/prettify.js',
'components/google-code-prettify-' + getVersion('google-code-prettify') + '/src/lang-css.js',
'js/versions-data.js',
'js/pages-data.js',
'js/docs.js'
],
stylesheets: [
'components/bootstrap-' + getVersion('bootstrap') + '/css/bootstrap.min.css',
'components/open-sans-fontface-' + getVersion('open-sans-fontface') + '/open-sans.css',
'css/prettify-theme.css',
'css/docs.css',
'css/animations.css'
]
}
]
});
return config;
};
+42 -11
View File
@@ -5,10 +5,13 @@ var log = require('gulp-util').log;
var concat = require('gulp-concat');
var jshint = require('gulp-jshint');
var bower = require('bower');
var dgeni = require('dgeni');
var Dgeni = require('dgeni');
var merge = require('event-stream').merge;
var path = require('canonical-path');
var foreach = require('gulp-foreach');
var uglify = require('gulp-uglify');
var sourcemaps = require('gulp-sourcemaps');
var rename = require('gulp-rename');
// We indicate to gulp that tasks are async by returning the stream.
// Gulp can then wait for the stream to close before starting dependent tasks.
@@ -17,6 +20,9 @@ var path = require('canonical-path');
var outputFolder = '../build/docs';
var bowerFolder = 'bower_components';
var src = 'app/src/**/*.js';
var assets = 'app/assets/**/*';
var copyComponent = function(component, pattern, sourceFolder, packageFile) {
pattern = pattern || '/**/*';
@@ -40,14 +46,37 @@ gulp.task('bower', function() {
});
gulp.task('build-app', function() {
gulp.src('app/src/**/*.js')
.pipe(concat('docs.js'))
.pipe(gulp.dest(outputFolder + '/js/'));
var file = 'docs.js';
var minFile = 'docs.min.js';
var folder = outputFolder + '/js/';
return gulp.src(src)
.pipe(sourcemaps.init())
.pipe(concat(file))
.pipe(gulp.dest(folder))
.pipe(rename(minFile))
.pipe(uglify())
.pipe(sourcemaps.write('.'))
.pipe(gulp.dest(folder));
});
gulp.task('assets', ['bower'], function() {
var JS_EXT = /\.js$/;
return merge(
gulp.src(['app/assets/**/*']).pipe(gulp.dest(outputFolder)),
gulp.src([assets])
.pipe(gulp.dest(outputFolder)),
gulp.src([assets])
.pipe(foreach(function(stream, file) {
if (JS_EXT.test(file.relative)) {
var minFile = file.relative.replace(JS_EXT, '.min.js');
return stream
.pipe(sourcemaps.init())
.pipe(concat(minFile))
.pipe(uglify())
.pipe(sourcemaps.write('.'))
.pipe(gulp.dest(outputFolder));
}
})),
copyComponent('bootstrap', '/dist/**/*'),
copyComponent('open-sans-fontface'),
copyComponent('lunr.js','/*.js'),
@@ -59,11 +88,10 @@ gulp.task('assets', ['bower'], function() {
gulp.task('doc-gen', ['bower'], function() {
var generateDocs = dgeni.generator('docs.config.js');
return generateDocs()
.catch(function(error) {
process.exit(1);
});
var dgeni = new Dgeni([require('./config')]);
return dgeni.generate().catch(function(error) {
process.exit(1);
});
});
// JSHint the example and protractor test files
@@ -78,3 +106,6 @@ gulp.task('jshint', ['doc-gen'], function() {
// The default task that will be run if no task is supplied
gulp.task('default', ['assets', 'doc-gen', 'build-app', 'jshint']);
gulp.task('watch', function() {
gulp.watch([src, assets], ['assets', 'build-app']);
});
Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

+13
View File
@@ -0,0 +1,13 @@
'use strict';
var config = require('../protractor-shared-conf').config;
config.specs = [
'app/e2e/**/*.scenario.js'
];
config.capabilities = {
browserName: 'chrome',
};
exports.config = config;
+42 -30
View File
@@ -33,6 +33,8 @@
goog.provide('goog.i18n.currency');
goog.provide('goog.i18n.currency.CurrencyInfo');
goog.provide('goog.i18n.currency.CurrencyInfoTier2');
/**
@@ -46,7 +48,7 @@ goog.i18n.currency.PRECISION_MASK_ = 0x07;
* Whether the currency sign should be positioned after the number.
* @private
*/
goog.i18n.currency.POSITION_FLAG_ = 0x08;
goog.i18n.currency.POSITION_FLAG_ = 0x10;
/**
@@ -56,6 +58,13 @@ goog.i18n.currency.POSITION_FLAG_ = 0x08;
goog.i18n.currency.SPACE_FLAG_ = 0x20;
/**
* Whether tier2 was enabled already by calling addTier2Support().
* @private
*/
goog.i18n.currency.tier2Enabled_ = false;
/**
* This function will add tier2 currency support. Be default, only tier1
* (most popular currencies) are supported. If an application really needs
@@ -63,9 +72,13 @@ goog.i18n.currency.SPACE_FLAG_ = 0x20;
* before any other functions in this namespace.
*/
goog.i18n.currency.addTier2Support = function() {
for (var key in goog.i18n.currency.CurrencyInfoTier2) {
goog.i18n.currency.CurrencyInfo[key] =
goog.i18n.currency.CurrencyInfoTier2[key];
// Protection from executing this these again and again.
if (!goog.i18n.currency.tier2Enabled_) {
for (var key in goog.i18n.currency.CurrencyInfoTier2) {
goog.i18n.currency.CurrencyInfo[key] =
goog.i18n.currency.CurrencyInfoTier2[key];
}
goog.i18n.currency.tier2Enabled_ = true;
}
};
@@ -244,7 +257,7 @@ goog.i18n.currency.adjustPrecision = function(pattern, currencyCode) {
* the currency sign should be positioned after the number. Valid values are 0
* (before the number) or 16 (after the number). The space flag indicates
* whether a space should be inserted between the currency sign and number.
* Valid values are 0 (no space) and 24 (space).
* Valid values are 0 (no space) and 32 (space).
*
* The number in the array is calculated by adding together the mask and flag
* values. For example:
@@ -252,52 +265,67 @@ goog.i18n.currency.adjustPrecision = function(pattern, currencyCode) {
* 0: no precision (0), currency sign first (0), no space (0)
* 2: two decimals precision (2), currency sign first (0), no space (0)
* 18: two decimals precision (2), currency sign last (16), no space (0)
* 42: two decimals precision (2), currency sign last (16), space (24)
* 50: two decimals precision (2), currency sign last (16), space (32)
*
* @type {!Object.<!Array>}
*/
goog.i18n.currency.CurrencyInfo = {
'AED': [2, 'dh', '\u062f.\u0625.', 'DH'],
'ALL': [0, 'Lek', 'Lek'],
'AUD': [2, '$', 'AU$'],
'BDT': [2, '\u09F3', 'Tk'],
'BGN': [2, 'lev', 'lev'],
'BRL': [2, 'R$', 'R$'],
'CAD': [2, '$', 'C$'],
'CDF': [2, 'FrCD', 'CDF'],
'CHF': [2, 'CHF', 'CHF'],
'CLP': [0, '$', 'CL$'],
'CNY': [2, '¥', 'RMB¥'],
'COP': [0, '$', 'COL$'],
'CRC': [0, '\u20a1', 'CR\u20a1'],
'CZK': [2, 'K\u010d', 'K\u010d'],
'CZK': [50, 'K\u010d', 'K\u010d'],
'DKK': [18, 'kr', 'kr'],
'DOP': [2, '$', 'RD$'],
'EGP': [2, '£', 'LE'],
'EUR': [18, '', ''],
'ETB': [2, 'Birr', 'Birr'],
'EUR': [2, '€', '€'],
'GBP': [2, '£', 'GB£'],
'HKD': [2, '$', 'HK$'],
'HRK': [2, 'kn', 'kn'],
'HUF': [0, 'Ft', 'Ft'],
'IDR': [0, 'Rp', 'Rp'],
'ILS': [2, '\u20AA', 'IL\u20AA'],
'INR': [2, '\u20B9', 'Rs'],
'IRR': [0, 'Rial', 'IRR'],
'ISK': [0, 'kr', 'kr'],
'JMD': [2, '$', 'JA$'],
'JPY': [0, '¥', 'JP¥'],
'KRW': [0, '\u20A9', 'KR₩'],
'LKR': [2, 'Rs', 'SLRs'],
'LTL': [2, 'Lt', 'Lt'],
'LVL': [2, 'Ls', 'Ls'],
'MNT': [0, '\u20AE', 'MN₮'],
'MXN': [2, '$', 'Mex$'],
'MYR': [2, 'RM', 'RM'],
'NOK': [18, 'kr', 'NOkr'],
'NOK': [50, 'kr', 'NOkr'],
'PAB': [2, 'B/.', 'B/.'],
'PEN': [2, 'S/.', 'S/.'],
'PHP': [2, '\u20B1', 'Php'],
'PKR': [0, 'Rs', 'PKRs.'],
'RUB': [42, 'руб.', 'руб.'],
'PLN': [50, 'z\u0142', 'z\u0142'],
'RON': [2, 'RON', 'RON'],
'RSD': [0, 'din', 'RSD'],
'RUB': [50, 'руб.', 'руб.'],
'SAR': [2, 'Rial', 'Rial'],
'SEK': [2, 'kr', 'kr'],
'SGD': [2, '$', 'S$'],
'THB': [2, '\u0e3f', 'THB'],
'TRY': [2, 'TL', 'YTL'],
'TWD': [2, 'NT$', 'NT$'],
'TZS': [0, 'TSh', 'TSh'],
'UAH': [2, '\u20B4', 'UAH'],
'USD': [2, '$', 'US$'],
'UYU': [2, '$', 'UY$'],
'UYU': [2, '$', '$U'],
'VND': [0, '\u20AB', 'VN\u20AB'],
'YER': [0, 'Rial', 'Rial'],
'ZAR': [2, 'R', 'ZAR']
@@ -309,16 +337,14 @@ goog.i18n.currency.CurrencyInfo = {
* @type {!Object.<!Array>}
*/
goog.i18n.currency.CurrencyInfoTier2 = {
'AFN': [16, 'Af.', 'AFN'],
'ALL': [0, 'Lek', 'Lek'],
'AFN': [48, 'Af.', 'AFN'],
'AMD': [0, 'Dram', 'dram'],
'AOA': [2, 'Kz', 'Kz'],
'ARS': [2, '$', 'AR$'],
'AWG': [2, 'Afl.', 'Afl.'],
'AZN': [2, 'man.', 'man.'],
'BAM': [18, 'KM', 'KM'],
'BAM': [2, 'KM', 'KM'],
'BBD': [2, '$', 'Bds$'],
'BGN': [2, 'lev', 'lev'],
'BHD': [3, 'din', 'din'],
'BIF': [0, 'FBu', 'FBu'],
'BMD': [2, '$', 'BD$'],
@@ -329,14 +355,12 @@ goog.i18n.currency.CurrencyInfoTier2 = {
'BWP': [2, 'P', 'pula'],
'BYR': [0, 'BYR', 'BYR'],
'BZD': [2, '$', 'BZ$'],
'CDF': [2, 'FrCD', 'CDF'],
'CUC': [1, '$', 'CUC$'],
'CUP': [2, '$', 'CU$'],
'CVE': [2, 'CVE', 'Esc'],
'DJF': [0, 'Fdj', 'Fdj'],
'DZD': [2, 'din', 'din'],
'ERN': [2, 'Nfk', 'Nfk'],
'ETB': [2, 'Birr', 'Birr'],
'FJD': [2, '$', 'FJ$'],
'FKP': [2, '£', 'FK£'],
'GEL': [2, 'GEL', 'GEL'],
@@ -347,12 +371,8 @@ goog.i18n.currency.CurrencyInfoTier2 = {
'GTQ': [2, 'Q', 'GTQ'],
'GYD': [0, '$', 'GY$'],
'HNL': [2, 'L', 'HNL'],
'HRK': [2, 'kn', 'kn'],
'HTG': [2, 'HTG', 'HTG'],
'HUF': [0, 'Ft', 'Ft'],
'IDR': [0, 'Rp', 'Rp'],
'IQD': [0, 'din', 'IQD'],
'IRR': [0, 'Rial', 'IRR'],
'JOD': [3, 'din', 'JOD'],
'KES': [2, 'Ksh', 'Ksh'],
'KGS': [2, 'KGS', 'KGS'],
@@ -366,8 +386,6 @@ goog.i18n.currency.CurrencyInfoTier2 = {
'LBP': [0, 'L£', 'LBP'],
'LRD': [2, '$', 'L$'],
'LSL': [2, 'LSL', 'LSL'],
'LTL': [2, 'Lt', 'Lt'],
'LVL': [2, 'Ls', 'Ls'],
'LYD': [3, 'din', 'LD'],
'MAD': [2, 'dh', 'MAD'],
'MDL': [2, 'MDL', 'MDL'],
@@ -386,11 +404,8 @@ goog.i18n.currency.CurrencyInfoTier2 = {
'NZD': [2, '$', 'NZ$'],
'OMR': [3, 'Rial', 'OMR'],
'PGK': [2, 'PGK', 'PGK'],
'PLN': [2, 'z\u0142', 'z\u0142'],
'PYG': [0, 'Gs', 'PYG'],
'QAR': [2, 'Rial', 'QR'],
'RON': [2, 'RON', 'RON'],
'RSD': [0, 'din', 'RSD'],
'RWF': [0, 'RF', 'RF'],
'SBD': [2, '$', 'SI$'],
'SCR': [2, 'SCR', 'SCR'],
@@ -400,16 +415,13 @@ goog.i18n.currency.CurrencyInfoTier2 = {
'SOS': [0, 'SOS', 'SOS'],
'SRD': [2, '$', 'SR$'],
'STD': [0, 'Db', 'Db'],
'SYP': [16, '£', 'SY£'],
'SYP': [0, '£', 'SY£'],
'SZL': [2, 'SZL', 'SZL'],
'TJS': [2, 'Som', 'TJS'],
'TND': [3, 'din', 'DT'],
'TOP': [2, 'T$', 'T$'],
'TTD': [2, '$', 'TT$'],
'TZS': [0, 'TSh', 'TSh'],
'UAH': [2, '\u20B4', 'UAH'],
'UGX': [0, 'UGX', 'UGX'],
'UYU': [1, '$', '$U'],
'UZS': [0, 'so\u02bcm', 'UZS'],
'VEF': [2, 'Bs', 'Bs'],
'VUV': [0, 'VUV', 'VUV'],
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+6 -1
View File
@@ -22,7 +22,12 @@ function readSymbols() {
.then(function(content) {
var currencySymbols = closureI18nExtractor.extractCurrencySymbols(content);
return qfs.read(__dirname + '/../closure/numberSymbols.js', 'b').then(function(content) {
closureI18nExtractor.extractNumberSymbols(content, localeInfo, currencySymbols);
var numberSymbols = content;
return qfs.read(__dirname + '/../closure/numberSymbolsExt.js', 'b')
.then(function(content) {
numberSymbols += content;
return closureI18nExtractor.extractNumberSymbols(numberSymbols, localeInfo, currencySymbols);
});
});
});
+1 -1
View File
@@ -18,7 +18,7 @@ function parsePattern(pattern) {
var p = {
minInt: 1,
minFrac: 0,
macFrac: 0,
maxFrac: 0,
posPre: '',
posSuf: '',
negPre: '',
+1
View File
@@ -14,4 +14,5 @@ curl "$I18N_BASE/currency.js" > closure/currencySymbols.js
curl "$I18N_BASE/datetimesymbols.js" > closure/datetimeSymbols.js
curl "$I18N_BASE/datetimesymbolsext.js" > closure/datetimeSymbolsExt.js
curl "$I18N_BASE/numberformatsymbols.js" > closure/numberSymbols.js
curl "$I18N_BASE/numberformatsymbolsext.js" > closure/numberSymbolsExt.js
curl "$I18N_BASE/pluralrules.js" > closure/pluralRules.js
+1 -1
View File
@@ -12,7 +12,7 @@ set -e
# before_script:
# - curl https://gist.github.com/santiycr/5139565/raw/sauce_connect_setup.sh | bash
CONNECT_URL="https://d2nkw87yt5k0to.cloudfront.net/downloads/sc-4.3-linux.tar.gz"
CONNECT_URL="https://saucelabs.com/downloads/sc-4.3-linux.tar.gz"
CONNECT_DIR="/tmp/sauce-connect-$RANDOM"
CONNECT_DOWNLOAD="sc-4.3-linux.tar.gz"
+2 -11
View File
@@ -83,6 +83,7 @@ var getTaggedVersion = function() {
if ( version && semver.satisfies(version, currentPackage.branchVersion)) {
version.codeName = getCodeName(tag);
version.full = version.version;
version.branch = 'v' + currentPackage.branchVersion.replace('*', 'x');
return version;
}
}
@@ -90,15 +91,6 @@ var getTaggedVersion = function() {
return null;
};
/**
* Stable versions have an even minor version and have no prerelease
* @param {SemVer} version The version to test
* @return {Boolean} True if the version is stable
*/
var isStable = function(version) {
return semver.satisfies(version, '1.0 || 1.2') && version.prerelease.length === 0;
};
/**
* Get a collection of all the previous versions sorted by semantic version
* @return {Array.<SemVer>} The collection of previous versions
@@ -118,8 +110,6 @@ var getPreviousVersions = function() {
})
.filter()
.map(function(version) {
version.isStable = isStable(version);
version.docsUrl = 'http://code.angularjs.org/' + version.version + '/docs';
// Versions before 1.0.2 had a different docs folder name
if ( version.major < 1 || (version.major === 1 && version.minor === 0 && version.dot < 2 ) ) {
@@ -197,6 +187,7 @@ var getSnapshotVersion = function() {
version.isSnapshot = true;
version.format();
version.full = version.version + '+' + version.build;
version.branch = 'master';
return version;
};
+923 -579
View File
File diff suppressed because it is too large Load Diff
+9 -8
View File
@@ -11,9 +11,8 @@
"bower": "~1.3.9",
"browserstacktunnel-wrapper": "~1.1.1",
"canonical-path": "0.0.2",
"dgeni": "^0.3.0",
"dgeni-packages": "^0.9.8",
"es6-shim": "^0.14.0",
"dgeni": "^0.4.0",
"dgeni-packages": "^0.10.0",
"event-stream": "~3.1.0",
"grunt": "~0.4.2",
"grunt-bump": "~0.0.13",
@@ -29,8 +28,12 @@
"grunt-parallel": "~0.3.1",
"grunt-shell": "~0.4.0",
"gulp": "~3.8.0",
"gulp-concat": "~2.1.7",
"gulp-concat": "^2.4.1",
"gulp-foreach": "0.0.1",
"gulp-jshint": "~1.4.2",
"gulp-rename": "^1.2.0",
"gulp-sourcemaps": "^1.2.2",
"gulp-uglify": "^1.0.1",
"gulp-util": "^3.0.1",
"jasmine-node": "~1.11.0",
"jasmine-reporters": "~0.2.1",
@@ -49,7 +52,7 @@
"marked": "~0.3.0",
"node-html-encoder": "0.0.2",
"promises-aplus-tests": "~1.3.2",
"protractor": "1.2.0",
"protractor": "1.4.0",
"q": "~1.0.0",
"q-io": "^1.10.9",
"qq": "^0.3.5",
@@ -57,9 +60,7 @@
"semver": "~2.1.0",
"shelljs": "~0.2.6",
"sorted-object": "^1.0.0",
"stringmap": "^0.2.2",
"winston": "~0.7.2",
"yaml-js": "~0.0.8"
"stringmap": "^0.2.2"
},
"licenses": [
{
+1 -1
View File
@@ -4,7 +4,7 @@ var config = require('./protractor-shared-conf').config;
config.specs = [
'build/docs/ptore2e/**/*.js',
'docs/app/e2e/docsAppE2E.js'
'docs/app/e2e/**/*.scenario.js'
];
config.capabilities = {
+3 -3
View File
@@ -5,7 +5,7 @@ exports.config = {
specs: [
'build/docs/ptore2e/**/*.js',
'docs/app/e2e/docsAppE2E.js'
'docs/app/e2e/*.scenario.js'
],
capabilities: {
@@ -21,9 +21,9 @@ exports.config = {
// Disable animations so e2e tests run more quickly
var disableNgAnimate = function() {
angular.module('disableNgAnimate', []).run(function($animate) {
angular.module('disableNgAnimate', []).run(['$animate', function($animate) {
$animate.enabled(false);
});
}]);
};
browser.addMockModule('disableNgAnimate', disableNgAnimate);
+2 -2
View File
@@ -12,9 +12,9 @@ exports.config = {
// Disable animations so e2e tests run more quickly
var disableNgAnimate = function() {
angular.module('disableNgAnimate', []).run(function($animate) {
angular.module('disableNgAnimate', []).run(['$animate', function($animate) {
$animate.enabled(false);
});
}]);
};
browser.addMockModule('disableNgAnimate', disableNgAnimate);
+20
View File
@@ -71,6 +71,8 @@ function prepare {
cd $TMP_DIR/bower-$repo
replaceJsonProp "bower.json" "version" ".*" "$NEW_VERSION"
replaceJsonProp "bower.json" "angular.*" ".*" "$NEW_VERSION"
replaceJsonProp "package.json" "version" ".*" "$NEW_VERSION"
replaceJsonProp "package.json" "angular.*" ".*" "$NEW_VERSION"
git add -A
@@ -88,6 +90,24 @@ function publish {
cd $TMP_DIR/bower-$repo
git push origin master
git push origin v$NEW_VERSION
# don't publish every build to npm
if [ "${NEW_VERSION/+sha}" = "$NEW_VERSION" ] ; then
if [ "${NEW_VERSION/-}" = "$NEW_VERSION" ] ; then
if [[ $NEW_VERSION =~ ^1\.2\.[0-9]+$ ]] ; then
# publish 1.2.x releases with the appropriate tag
# this ensures that `npm install` by default will not grab `1.2.x` releases
npm publish --tag=old
else
# publish releases as "latest"
npm publish
fi
else
# publish prerelease builds with the beta tag
npm publish --tag=beta
fi
fi
cd $SCRIPT_DIR
done
}
+3 -4
View File
@@ -9,12 +9,11 @@ if [ $JOB = "unit" ]; then
grunt test:promises-aplus
grunt test:unit --browsers SL_Chrome,SL_Safari,SL_Firefox,SL_IE_8,SL_IE_9,SL_IE_10,SL_IE_11 --reporters dots
grunt tests:docs --browsers SL_Chrome,SL_Safari,SL_Firefox,SL_IE_8,SL_IE_9,SL_IE_10,SL_IE_11 --reporters dots
grunt test:travis-protractor --specs "docs/app/e2e/**/*.scenario.js"
elif [ $JOB = "e2e" ]; then
export TARGET_SPECS="build/docs/ptore2e/**/*jqlite_test.js"
export TARGET_SPECS="build/docs/ptore2e/**/default_test.js"
if [ $TEST_TARGET = "jquery" ]; then
TARGET_SPECS="build/docs/ptore2e/**/*jquery_test.js"
elif [ $TEST_TARGET = "doce2e" ]; then
TARGET_SPECS="docs/app/e2e/docsAppE2E.js"
TARGET_SPECS="build/docs/ptore2e/**/jquery_test.js"
fi
grunt test:travis-protractor --specs "$TARGET_SPECS"
else
+3 -3
View File
@@ -155,8 +155,8 @@ if ('i' !== 'I'.toLowerCase()) {
}
var /** holds major version number for IE or NaN for real browsers */
msie,
var
msie, // holds major version number for IE, or NaN if UA is not IE.
jqLite, // delay binding since jQuery could be loaded after us.
jQuery, // delay binding
slice = [].slice,
@@ -338,7 +338,7 @@ function setHashKey(obj, h) {
* @kind function
*
* @description
* Extends the destination object `dst` by copying all of the properties from the `src` object(s)
* Extends the destination object `dst` by copying own enumerable properties from the `src` object(s)
* to `dst`. You can specify multiple `src` objects.
*
* @param {Object} dst Destination object.
+5 -6
View File
@@ -7,13 +7,13 @@
* @kind function
*
* @description
* Creates an injector function that can be used for retrieving services as well as for
* Creates an injector object that can be used for retrieving services as well as for
* dependency injection (see {@link guide/di dependency injection}).
*
* @param {Array.<string|Function>} modules A list of module functions or their aliases. See
* {@link angular.module}. The `ng` module must be explicitly added.
* @returns {function()} Injector function. See {@link auto.$injector $injector}.
* @returns {injector} Injector object. See {@link auto.$injector $injector}.
*
* @example
* Typical usage
@@ -101,7 +101,6 @@ function annotate(fn) {
/**
* @ngdoc service
* @name $injector
* @kind function
*
* @description
*
@@ -116,7 +115,7 @@ function annotate(fn) {
* expect($injector.get('$injector')).toBe($injector);
* expect($injector.invoke(function($injector){
* return $injector;
* }).toBe($injector);
* })).toBe($injector);
* ```
*
* # Injection Function Annotation
@@ -183,8 +182,8 @@ function annotate(fn) {
* @description
* Allows the user to query if the particular service exists.
*
* @param {string} Name of the service to query.
* @returns {boolean} returns true if injector has given service.
* @param {string} name Name of the service to query.
* @returns {boolean} `true` if injector has given service.
*/
/**

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