Compare commits

...

375 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
Jeff Cross d396f42537 docs(CHANGELOG.md): add upcoming breaking change 2014-09-09 16:21:16 -07:00
Jeff Cross 5ec900a125 docs(CHANGELOG.md): fix wording and remove reverted change 2014-09-09 16:20:20 -07:00
Jeff Cross 66503a6e18 docs(CHANGELOG.md): add changes for 1.3.0-rc.1 and 1.2.24 2014-09-09 15:48:30 -07:00
Jeff Cross 2d8749e8c9 revert: "fix($compile): render nested transclusion at the root of a template"
This reverts commit 9d9cdfb575.

This commit was causing breakages because of its assumption that transcluded
content would be handled predictably, i.e. with ngTransclude, whereas many
use cases involve manipulating transcluded content in linking functions.
2014-09-09 11:08:39 -07:00
Chirayu Krishnappa b39e1d47b9 fix($parse): disallow passing Function to Array.sort
Fix the following exploit:

    hasOwnProperty.constructor.prototype.valueOf = valueOf.call;
    ["a", "alert(1)"].sort(hasOwnProperty.constructor);

The exploit:
• 1. Array.sort takes a comparison function and passes it 2 parameters to compare.
  2. It then calls .valueOf() if the result is not a primitive.
• The Function object conveniently accepts two string arguments so we can use this
  to construct a function.  However, this doesn't do much unless we can execute it.
• We set the valueOf function on Function.prototype to Function.prototype.call.
  This causes the function that we constructed to be executed when sort calls
  .valueOf() on the result of the comparison.

The fix is in two parts.
• Disallow passing unsafe objects to function calls as parameters.
• Do not traverse the Function object when setting a path.
2014-09-09 10:46:36 -07:00
Peter Bacon Darwin 5061d2c97c chore(npm-shrinkwrap): safely update karma to 0.12.23 2014-09-09 10:21:45 +01:00
Peter Bacon Darwin a961291aa2 chore(npm-shrinkwrap): fix karma dependencies
Updating to karma 0.12.13 (in commit 408508ad29)
caused `iit` and `ddescribe` to crash and disconnect the browser stopping the
test run.

It appears that the problem is with one of the dependencies of karma rather
than karma itself. At least one of the karma dependencies updated in line
with karma's dependencies' semver specifications but subtly changed their
behaviour to break karma.  Possibly this is related to chokidar, glob,
minimatch or fsevents.
2014-09-09 10:04:32 +01:00
Peter Bacon Darwin 3068d8e52a docs($filter): remove duplicate documentation of register method 2014-09-08 14:31:47 +01:00
Peter Bacon Darwin d2dd3581a9 docs(form): move param tag outside of main description 2014-09-08 14:31:47 +01:00
Peter Bacon Darwin 53feb272be chore(bower): refactor bower usage
The gulp bower task in the docs app was never actually running since it couldn't
find the bower.json file and was silently failing. Updating to a newer bower
highlighted this issue.

This commit moves the docs app specific bower components into the docs folder.
There are only jquery and closure compiler related components in the project
folder now.

It also improves the gulp bower task to provide better feedback of progress
and errors.
2014-09-08 14:31:47 +01:00
Peter Bacon Darwin 408508ad29 chore(package.json): tidy up dependencies
Sorted dependencies into alphabetic order. If we can keep them like this
it will be much easier to keep track of version changes.

Updated bower and gulp to newer versions.
2014-09-08 14:31:47 +01:00
Peter Bacon Darwin ece7d19115 chore(clean-shrinkwrap): chokidar is fixed since 0.8.2 2014-09-08 12:31:40 +01:00
Pawel Kozlowski 992101da10 refactor($http): simplify buildUrl function
Closes #8955
2014-09-05 20:22:20 -04:00
Peter Bacon Darwin 47f42ecf45 test(orderBy): remove IE8 incompatible test code 2014-09-05 19:46:40 +01:00
Julie Ralph fd995abc9a chore(tests): fix up test for protractor 1.2.0 update
These changes were made to master in 85880a6490
but never made it to the 1.2.x branch.
2014-09-05 11:16:18 -07:00
Julie Ralph 5f9a9747d2 chore(tests): update Protractor to v1.2.0 2014-09-05 10:51:31 -07:00
Vitali Tsevan 94b0f2d35d fix(orderBy): allow arrayLike objects to be ordered
Closes #8944
2014-09-05 11:56:41 +01:00
Jeff Cross c12e8d4665 fix($location): don't call toString on null values 2014-09-04 17:46:51 -07:00
thorn0 c65796d496 fix($location): remove an unused parameter of $location.url 2014-09-04 15:12:04 -07:00
John Reilly 34b43eab5f docs($location): update search description to include number param 2014-09-04 14:55:48 -07:00
Peter Bacon Darwin 9d9cdfb575 fix($compile): render nested transclusion at the root of a template
Closes #8914
Closes #8925
2014-09-04 19:33:03 +01:00
Pawel Kozlowski 68a09ba74d fix($location): allow numeric location setter arguments
Fixes #7054
2014-09-04 10:47:30 -07:00
Peter Bacon Darwin 239d0b1f49 docs(guide): add sortOrder to each page
Finally we can control the order of the guide pages
2014-09-04 17:15:26 +01:00
Peter Bacon Darwin 4e04c73cd3 chore(docs): enable page ordering by @sortOrder tag 2014-09-04 16:49:55 +01:00
Peter Bacon Darwin 6c863e5bba chore(docs): improve searching by member
The keywords processor now also extracts the members (i.e. method, properties
and events) into its own search term property. These are then used in the lunr
search index with higher weighting that normal keywords to push services that
contain the query term as a member higher up the search results.

Closes #7661
2014-09-04 14:23:29 +01:00
Peter Bacon Darwin e0cf7c5bf2 Revert "fix($compile): render nested transclusion at the root of a template"
This reverts commit 466320f691.
2014-09-04 14:15:38 +01:00
Peter Bacon Darwin 466320f691 fix($compile): render nested transclusion at the root of a template
Closes #8914
Closes #8925
2014-09-04 13:45:49 +01:00
Smitha Milli 7e02fa07eb fix(numberFilter): format numbers that round to zero as nonnegative
Previously when a negative number was rounded to 0 by the number filter
it would be formated as a negative number.  This means something like
{{ -0.01 | number: 1 }} would output -0.0.  Now it will ouput 0.0
instead.

Closes #8489
2014-09-03 15:42:07 -07:00
thorn0 9ed9777317 docs(docs.css): improve comma spacing in TOC on mobile 2014-09-03 14:37:43 -07:00
Juampy e661bc9f15 docs($sce:unsafe): fix link to $sce docs
The second link to Strict Contextual Escaping (SCE) points to a 404.

Closes #8514
2014-09-03 16:31:41 -04:00
thorn0 7af210f1de docs(README): fix 'Contribution guidelines' link
The current link leads to a page 'Building and Testing AngularJS'.
This same link is also included in the 'Building AngularJS' section
of the README where it's more relevant.
2014-09-03 13:25:40 -07:00
TLChan b48203f9f2 docs(tutorial/step_05): improve formatting of code identifier
Closes #8557
2014-09-03 16:25:08 -04:00
Zach Pomerantz 789f0f1809 docs(interpolate): fix link text 2014-09-03 13:20:27 -07:00
Vic Metcalfe 8366d545c5 docs(ngBlur): explain blur events 2014-09-03 13:05:07 -07:00
Caitlin Potter 1f5b4c95eb docs(CHANGELOG.md): add breaking change for a9fcb0d0 (v1.2.13)
Closes #8909
2014-09-03 13:14:02 -04:00
Peter Bacon Darwin 910d652ce5 chore(package.json): update to dgeni-packages v0.9.8
Closes #8860
2014-09-03 11:39:35 +01:00
Nicolai Skogheim e5e62a5479 docs(ngRepeat): update step_02.ngdoc with challenge
Add a simple task for the user to better understand ng-repeat.

Close #8757
2014-09-02 16:46:20 -04:00
Shahar Talmi 8f14b726b0 docs($rootScope): document scope properties 2014-09-02 13:35:41 -07:00
Tiago Ribeiro 88b6a9a288 docs(changelog): fix inline formatting 2014-09-02 13:05:07 -07:00
Matias Niemelä d4fc40c282 docs(changelog): release notes for 1.3.0-RC.0 sonic-boltification 2014-09-02 13:04:45 -07:00
Nima Mehanian 653700df5b docs(guide/providers): fix grammar and punctuation 2014-09-02 12:48:57 -07:00
Shahar Talmi 2712c2f197 fix(ngEventDirs): check scope.$$phase only on $rootScope
Closes #8891, #8849
2014-09-02 10:48:12 -07:00
Shahar Talmi 36e6de1d91 fix(input): check scope.$$phase only on $rootScope 2014-09-02 10:48:12 -07:00
Brian Ford 9bf964f1f3 style(ngRepeatSpec): make jshint happy 2014-08-29 15:51:02 -07:00
Tobias Bosch 54f0bc0fe0 fix(ngEventDirs): execute blur and focus expression using scope.$evalAsync
BREAKING CHANGE:
The `blur` and `focus` event fire synchronously, also during DOM operations
that remove elements. This lead to errors as the Angular model was not
in a consistent state. See this [fiddle](http://jsfiddle.net/fq1dq5yb/) for a demo.

This change executes the expression of those events using
`scope.$evalAsync` if an `$apply` is in progress, otherwise
keeps the old behavior.

Fixes #4979
Fixes #5945
Closes #8803
Closes #6910
Closes #5402
2014-08-29 15:31:27 -07:00
Tobias Bosch 2ece4d0347 fix($browser): detect changes to the browser url that happened in sync
Closes #6976.
2014-08-29 15:31:13 -07:00
Smitha Milli 1812af58c2 fix(ngRepeat): improve errors for duplicate items
-Log the value that had the duplicate key, as well as the key
The error that is thrown when items have duplicate track by keys can be
confusing because only the duplicate key is logged.  If the user didn't
provide that key themselves, they may not know what it is or what item
it corresponds to.
2014-08-29 13:54:57 -07:00
Michael Barton 19cb2e3d12 docs($rootScope): remove duplicate $digest()
Closes #8840
2014-08-29 14:38:31 -04:00
Guilbert c92ce4511b docs(filterFilter): add note on negation 2014-08-28 14:57:30 -07:00
Matias Niemelä d7548fdf1c fix(form): ensure concurrent animations use setClass
When addClass and removeClass are called in parallel it may
cause follow-up animations to get blocked. This fix ensures
that the validity state CSS classes are applied at the same
time via $animate.setClass.

Closes #8166
2014-08-27 23:29:44 -04:00
dennishall1 7e239f9485 docs(dateFilter): add example of string literals in format string
Also changes the wording to include the word "escaped" and "escape", which may help users find the
information they're looking for via searching. (ノ◕ヮ◕)ノ*:・゚✧

Closes #8770
2014-08-25 23:18:53 -04:00
Smith fa5daa7693 docs(guide/di): correct spelling behinds > behind
Closes #8749
2014-08-23 16:38:27 -04:00
Brian Ford 00456a8f93 docs(changelog): release notes for 1.2.23 superficial-malady 2014-08-22 15:56:49 -07:00
Brian Ford 0b3022e8e0 docs(changelog): release notes for 1.3.0-beta.19 rafter-ascension 2014-08-22 15:56:33 -07:00
Jeff Cross 456026eff1 fix(input): use lowercase method to account for undefined type 2014-08-22 00:41:02 -07:00
danrbergman 8ec3efd967 docs(guide/module): update tag in description
the reference to 'myApp' module changed in the example from <html> to a <div>. Updating description
to reflect the new <div> tag.

Closes #8720
2014-08-21 23:33:59 -04:00
danrbergman 8528781f85 docs(guide/module): make the use of ng-app explicit in example
Helpful for people new to Angular to see the ng-app declaration in context with the expression
example. This will help illustrate the "Important thing to notice" point which follows: "The
reference to myApp module in <html ng-app="myApp">. This is what bootstraps the app using your
module."

Closes #8673
2014-08-21 22:28:48 -04:00
Sekib Omazic 98f603722d fix(Angular): make Date comparison in equals() NaN-aware
Make angular.equals() Date comparison NaN-aware to prevent infinite digest errors when a dealy watched
date has an invalid value.

Closes #8650
Closes #8715
2014-08-21 21:17:46 -04:00
Caitlin Potter ebece0bcb9 fix(input): by default, do not trim input[type=password] values
Do not trim input[type=password] values

BREAKING CHANGE:

Previously, input[type=password] would trim values by default, and would require an explicit ng-trim="false"
to disable the trimming behaviour. After this CL, ng-trim no longer effects input[type=password], and will
never trim the password value.

Closes #8250
Closes #8230

Conflicts:
	src/ng/directive/input.js
2014-08-21 19:14:27 -04:00
Caitlin Potter 4b7398eeca chore(protractor): enable testing ng-app-included examples
/cc @petebacondarwin / @juliemr please review :>

Blocks #8673
Closes #8677
2014-08-21 18:55:12 -04:00
Casey Flynn 4e79decc30 docs($interval): fix typo in example
It's not "nis", it's "is"! 〜( ̄▽ ̄)〜

Closes #8711
2014-08-21 15:30:16 -04:00
Caitlin Potter 888b0f5400 fix(copy): clear array destinations correctly for non-array sources
Closes #8610
Closes #8702
2014-08-20 21:51:32 -04:00
Jeff Cross aaf9c5e598 fix(minErr): encode btstrpd error input to strip angle brackets
The $sanitize service was returning an empty string to the error page
because the input was usually a single html tag (sometimes it could be
`document`). This fix replaces angle brackets with html entities.

Closes #8683
2014-08-20 17:27:48 -07:00
Henrik Nyh 893d2f8000 docs(ngDisabled): clarify "don't do this" example
It's not clear until you read the whole thing that it's an explanation
of what *not* to do and why, so if you scan the page from the top, you
may use this bad solution.
2014-08-20 15:47:37 -07:00
Brian Ford effc98fdc9 fix(linky): handle quotes around email addresses
Closes #8520
2014-08-20 13:40:31 -07:00
mishoo78 64cdbf3ae9 docs(ngMock): note that inject/module helpers only defined for jasmine / mocha
Closes #8694
2014-08-20 13:44:24 -04:00
Ole Weitz 5bba892ffd docs($cacheFactory): prevent example breaking on key update
The example for $cacheFactory breaks when a user tries to update a value for a key.
Setting a new value for an existing key results in duplicate key entries in the key array, thus
breaking the ng-repeat directive. With this fix the key is only added if it isn't contained in the
cache.

Closes #8214
2014-08-20 10:49:14 -04:00
Izhaki ec27deacfd docs($compile): fix documentation for ?^ controller search
Fixed typo: 'parents parents' to 'parents'

Closes #8690
2014-08-20 09:32:20 -04:00
Caitlin Potter c6e4defcb6 fix($location): rewrite relative URI correctly if path==='/' in legacy html5Mode
Currently, legacy browsers get to use a clever scheme for resolving relative URIs in html5Mode,
and resolve the URI relative to $location.path().

Currently, $location.path() can be '/' under certain circumstances, which means that when we
split $location.path() on '/' and later join by '/' after adding another path component,
we end up with '//pathComponent'. $$rewrite fails to deal with this correctly, and effectively
the $location is never changed from the root path.

This CL corrects this by ensuring that the duplicate '/' situation does not occur when resolving
relative URIs.

Closes #8684
2014-08-19 21:31:20 -04:00
Caitlin Potter 74a7afcb31 fix($location): don't call indexOf() of undefined href attribute
Closes #7721
Closes #8681
2014-08-19 19:16:40 -04:00
Brian Ford 08cc6edd38 chore(jshint): add missing scripturl directive 2014-08-19 14:56:06 -07:00
Brian Ford 4f3870500d fix($sanitize): sanitize javascript urls with comments
Closes #8274
2014-08-19 14:16:01 -07:00
Marty Kane cd0507bc3a docs(guide/di): correct a few awkward sentences
Closes #8678
2014-08-19 16:51:45 -04:00
Izhaki 20eef05195 docs($compile): correct documentation for directive controller ^ notation
`^` searches the element and its parents, not exclusively the element's parents. This confuses
a lot of people :(

Closes #8622
2014-08-19 14:31:36 -04:00
Shahar Talmi a6d7b4bdbd docs(*): use @description instead of @returns for properties
Dgeni-packages was not actually rendering the `@returns` text.

Closes #8639
2014-08-19 14:26:06 -04:00
Baptiste Fontaine 5811c5c35b docs(ngBind): irrelevant text removed from ngBindHtml’s example
The ngBindHtml’s example had a copied line from ngBindTemplate’s that’s irrelevant here.

Closes #8668
2014-08-19 12:39:04 -04:00
Pawel Kozlowski e37e30e93f docs(orderBy): clarify expression usage in a predicate
Closes #8592
2014-08-18 13:32:21 -07:00
Tom Kadwill a0b8ab8d7d docs(tutorial/index): improve wording
Removed repetition of 'machine' and 'local machine'.
I think this change makes the sentence more concise
2014-08-18 13:23:56 -07:00
Jeff Sheets 129c53730c docs($http): correct link to "salt (cryptography)" wikipedia article
Closes #8654
2014-08-18 13:35:24 -04:00
Caitlin Potter 8695138aec docs(misc/contribute): fix syntax highlighting of URLS
Closes #8168
Closes #8169
2014-08-17 21:13:57 -04:00
Shahar Talmi ed56872bb2 fix(ngHref): remove attribute when empty value instead of ignoring
Closes #2755
2014-08-13 15:43:10 -07:00
Peter Bacon Darwin cb183433a0 chore(doc-gen): move e2e tests into docs folder
These tests didn't really fit in the test folder as the docs app is mostly
a separate entity from the AngularJS codebase.
2014-08-13 11:24:53 +01:00
Caitlin Potter 631fbda6a9 docs(CHANGELOG.md): fix typo, it's 1.2.22 not 1.2.2!
Whoops!
2014-08-12 16:53:05 -04:00
Caitlin Potter 4c33b56612 docs(CHANGELOG.md): add changelog for v1.3.0-beta.18 and v1.2.22
Closes #8581
2014-08-12 13:17:04 -04:00
rodyhaddad 93b0c2d892 feat($parse): allow for assignments in ternary operator branches
Closes #8512
Closes #8484
CLoses #5434

Conflicts:
	test/ng/parseSpec.js
2014-08-11 17:04:40 +01:00
Peter Bacon Darwin d262378b7c fix(jqLite): allow triggerHandler() to accept custom event
In some scenarios you want to be able to specify properties on the event
that is passed to the event handler. JQuery does this by overloading the
first parameter (`eventName`). If it is an object with a `type` property
then we assume that it must be a custom event.

In this case the custom event must provide the `type` property which is
the name of the event to be triggered.  `triggerHandler` will continue to
provide dummy default functions for `preventDefault()`, `isDefaultPrevented()`
and `stopPropagation()` but you may override these with your own versions
in your custom object if you wish.

In addition the commit provides some performance and memory usage
improvements by only creating objects and doing work that is necessary.

This commit also renames the parameters inline with jQuery.

Closes #8469
Closes #8505
2014-08-11 12:17:55 +01:00
Peter Bacon Darwin 7729c84ec7 test(docsAppE2E): check that param defaults are shown in docs
Closes https://github.com/angular/dgeni-packages/pull/58
2014-08-10 20:19:23 +01:00
Peter Bacon Darwin dffeef29d7 test(docsAppE2E): tighten CSS selector to only find one element 2014-08-10 20:19:23 +01:00
Peter Bacon Darwin 2e22588ccf chore(package.json): update to dgeni-packages 0.9.7 2014-08-10 17:43:23 +01:00
Caitlin Potter 0b0acb0342 fix($compile): make '='-bindings NaN-aware
Update parent and child scopes correctly when a '='-binding changes from a NaN value.

TBR by angular-core

Closes #8553
Closes #8554

Conflicts:
	test/ng/compileSpec.js
2014-08-10 03:32:13 -04:00
Eddie Hedges 18fc43e828 docs(guide): correct links to unit testing guides
Closes #8548
2014-08-09 14:01:54 -04:00
Caitlin Potter ed47d811e2 chore(travis): specify chrome m34 in protractor configuration
Closes #8541
2014-08-08 17:21:00 -04:00
Derrick Mar a84f9f6178 docs(tutorial/step-10): add mock image data to spec
Closes #8468
Closes #8535
2014-08-08 20:37:42 +01:00
Caitlin Potter 4fbbe1152e docs(http): don't use locale-specific uri for MDN link 2014-08-08 15:32:38 -04:00
Joey Yang df3d941c57 docs($http): fix broken markdown link in withCredentials description
Markdown typo in $http config documentation

Closes #7859
2014-08-08 15:29:50 -04:00
Juampy 2bd3214a55 docs(guide/migration): ngSanitize is out ng core at AngularJS 1.2.21
When using ngBindHTML directive, either ngSanitize or $sce must be used
or this will end in a non-trusted value error.

Closes #8519
2014-08-07 21:04:17 -04:00
James Kleeh fc2abef327 docs(guide/directive): explain how to require multiple controllers
Closes #8524
2014-08-07 15:14:39 +01:00
Andrew Silluron 76a0eb89fb docs($compile): fix typo 'default' spelling
Change spelling of 'defualt' to 'default'

Closes #8476
2014-08-04 18:48:29 -04:00
Caitlin Potter ee57b4c26b docs(CHANGELOG.md): add missing breaking change from 1.3.0-beta.14 2014-08-04 17:29:33 -04:00
Peter Bacon Darwin 29eaabc000 test(select): relax test for IE8 bug
There is a bug in IE8 (http://support.microsoft.com/kb/829907 and
http://yuilibrary.com/forum-archive/forum/viewtopic.php@p=14826.html):
when you clone an `<option>` element the selected attribute on the options
can become invalid.

This is not relevant to the proper behaviour of the `select` directive
since it uses `prop` not `attr` to store the selected status of each
option.

This test is only interested in there being at least on option with
the `selected` attribute, for conformance to accessibility guidelines.
So we can safely relax the test to check this rather than concerning
ourselves with which option actually has this attribute.

Fixes 79538afd7b
Closes #8465
2014-08-03 22:15:59 +01:00
Joseph Spencer 2a6081057f docs($resource): clarify the meaning of @ in paramDefaults
Closes #8457
2014-08-03 17:15:03 +01:00
Peter Bacon Darwin 79538afd7b fix(select): ensure that at least one option has the selected attribute set
Using `prop` to set selected is correct programmatically but accessibility
guidelines suggest that at least on item should have the `selected` attribute
set.

Closes #8366
Closes #8429

Conflicts:
	test/ng/directive/selectSpec.js
2014-08-03 16:37:32 +01:00
rodyhaddad bcfa64e77c chore(travis): rename fetch_bundle script and make it not abort a travis build if it fails
This is useful when the npm-bundle-deps server isn't running,
when the tar never gets served (there's a default timeout on the request),
or when the served file isn't a valid tar.
2014-08-01 19:14:48 -07:00
Peter Bacon Darwin b7a2deed30 docs(ngSubmit): add link to form docs to discourage double submission
Closes #6017
2014-07-31 21:27:04 +01:00
Ken Sheedlo 98ff901bda docs(error/$injector/unpr): inadvertently redefining a module can cause error
Closes #8421
2014-07-31 20:48:32 +01:00
k-funk 428b81cba9 docs($http): add link to $http.path()
Closes #8424
2014-07-31 13:43:48 +01:00
Danielle 5dae9c230e docs(ngMockE2E): remove repeated word
Closes #8411
2014-07-31 13:41:05 +01:00
winsontam c3fad1157e fix($location) don't rewrite location when clicking on "javascript:" or "mailto:" link
Previously, absent a specified target attribute, when clicking on an anchor tag with an href beginning
with either "javascript:" or "mailto:", the framework would rewrite the URL, when it ought not to.

With this change, the browser is prevented from rewriting if the URL begins with a case-insensitive match
for "javascript:" or "mailto:", optionally preceeded by whitespace.

Closes #8407
Closes #8425
Closes #8426
2014-07-31 07:31:33 -04:00
Peter Bacon Darwin 9242c580a1 refact(select): don't recreate selectedSet on every digest loop
In the case of a "multiple" select, the model value is an array, changes
to which don't get picked up by NgModelController as it only looks for
object identity change.

We were rebuilding the `selectedSet` (a hash map of selected items) from
the modelValue on every turn of the digest. This is not needed as we can
simply use `$watchCollection` directly on the `$modelValue` instead.
2014-07-31 07:14:14 +01:00
Peter Bacon Darwin c2860944c6 fix(select): do not update selected property of an option element on digest with no change event
The `render()` method was being invoked on every turn of the digest cycle,
which was inadvertently updating the DOM even when a `change` event had
not been triggered.

This change only calls the `render()` method when `ctrl.$render()` is called,
as part of the NgModelController` lifecycle and when the `modelValue` has
significantly changed.

Closes #8221
Closes #7715
2014-07-30 23:14:40 +01:00
Peter Bacon Darwin e9a00fbdc3 test(select): add extra expectations and comments for clarity 2014-07-30 23:14:40 +01:00
Erin Altenhof-Long d018ac2a9a test(select): add test of updating the model because of ng-change
A regression #7855 was introduced by
https://github.com/angular/angular.js/commit/dc149de9364c66b988f169f67cad39577ba43434
This test ensures that reverting that commit fixes this regression.
In the regression, changes to a bound model in ng-change were not propagated back to the view.

Test for #7855
2014-07-30 23:14:40 +01:00
Erin Altenhof-Long b770c353bc test(select): add test cases for selects with blank disabled options
An earlier commit dc149de936 caused an error where the first option of
a select would be skipped over if it had a blank disabled value. These tests demonstrate that with
that commit in place, blank disabled options are skipped in a select. When the commit is reverted,
the correct behavior is seen that the blank disabled option is still selected in both selects
marked with required and those that have optional choices.

Relates to #7715
2014-07-30 23:14:40 +01:00
Erin Altenhof-Long 812277c257 test(select): add test against updating selected property on digest with no change event
Commit dc149de936 was reverted to fix regressions #7715 and #7855.
This commit introduced this test case and a corresponding fix for preventing the update of the
selected property of an option element on a digest with no change event. Although the previous fix
introduced regressions, the test covers a valid issue and should be included.
2014-07-30 23:14:39 +01:00
Erin Altenhof-Long 61871da9de revert(select): avoid checking option element selected properties in render
This reverts commit dc149de936. That commit fixes a bug caused by
Firefox updating `select.value` on hover. However, it
causes other bugs with select including the issue described in #7715. This issue details how
selects with a blank disabled option skip to the second option. We filed a bug
with Firefox for the problematic behavior the reverted commit addresses
https://bugzilla.mozilla.org/show_bug.cgi?id=1039047, and alternate Angular fixes are being
investigated.

Closes #7715 #7855
2014-07-30 23:14:39 +01:00
Caitlin Potter 9ee075518f fix(ngSanitize): ensure html is a string in htmlParser()
Previously, $sanitize(nonString) would throw. Now, the type is converted to a string before any work
is done.

Closes #8417
Closes #8416
2014-07-30 13:34:14 -04:00
Misha Moroshko afe93eaff8 docs(dateFilter): fix milliseconds example
Closes #8389
2014-07-29 17:49:28 +01:00
Andrew Pham d8f94d1a3f docs(tutorial/step-2): warn reader not to minimise browser that Karma's running on
Closes #8386
2014-07-29 17:40:46 +01:00
Nathan Wiebe f53b53df22 docs(tutorial): clarify sentence in step 02
Separate two sentences with a period, and clarify the wording by making it less technical: "to the DOM"
vs "to the <body> tag".

Closes #8394
2014-07-29 11:42:15 -04:00
Shahar Talmi eab5731afc feat(http): allow caching for JSONP requests
Closes #1947
Closes #8356
2014-07-29 09:40:36 +01:00
Sergio Sanguanini 986c446aaf style(AngularPublic): add whitespace to jshint block
Closes #8360
2014-07-27 14:10:40 +01:00
rodyhaddad 60366c8d0b fix($parse): correctly assign expressions who's path is undefined and that use brackets notation
Closes #8039
2014-07-26 23:28:20 -07:00
Julie Ralph 494c8aa0b3 chore(ci): update sauce connect from 3 to 4.3 for the 1.2.x branch 2014-07-25 14:50:24 -07:00
Ivan Alvarez cd9459e129 docs(tutorial): update step_03.ngdoc
1) The original document is not clear to a new developer in where to place the code.
2) The query.clear() statement to clear the query before the second test is missing in the original document.
3) Refactored to use the query and phoneList variables in both tests, so its easier to read and understand.

Closes #7815
2014-07-25 14:26:49 -07:00
Mitch Robb 2862883bd8 docs(tutorial): update step7 ngdoc to fix grammar
This line was missing an 'as'

Previous:
We also have to add the modules dependencies of our app. By listing these two modules as dependencies of `phonecatApp`, ...

New:
We also have to add the modules *as* dependencies of our app.

Closes #8345
2014-07-25 14:12:59 -07:00
Jeff Cross bbb673a48a docs(changelog): release notes for 1.3.0-beta.17 and 1.2.21 2014-07-25 10:17:16 -07:00
Jeff Cross cd9afd9961 revert: fix(ngHref): remove attribute when empty value instead of ignoring
This reverts commit 948c86c602.

This commit caused tests to fail in IE8 due to a TypeError '0.childNodes is
null or not an object. The issue should be investigated and fixed. Issue #8340
has been opened to investigate.

See this job for failures: https://travis-ci.org/angular/angular.js/jobs/30792508
2014-07-25 09:01:43 -07:00
Shahar Talmi e25ed0d48d fix(angular.copy): clone regexp flags correctly
Closes #5781
Closes #8337
2014-07-25 16:40:14 +01:00
Peter Bacon Darwin cd6d21e78a docs(tutorial/step-2): note that ng-app now needs a module name
Closes #7655
2014-07-25 16:38:55 +01:00
TheMrSteve 9cf5b35e5c docs(tutorial/step-3): note that the server needs to be running before running Protractor
Closes #7142
2014-07-25 16:38:55 +01:00
Jeff Cross 5d11e02008 fix(docs): change plnkr form to open in same window
Form previously posted to target="_blank", but pop-up blockers were causing this to not work.
If a user chose to bypass pop-up blocker one time and click the link, they would arrive at
a new default plnkr, not a plnkr with the desired template.

This fix removes the _blank target, causing the plnkr to open in the current window/tab.
2014-07-24 14:37:49 -07:00
Chris Chua 209e600070 fix(jqLite): triggerHandler support unbind self
Fixes .one if the event is invoked from triggerHandler.

Closes #5984

Conflicts:
	test/jqLiteSpec.js
2014-07-24 13:50:28 -07:00
Igor Minar ceaca57786 revert: perf($parse): don't use reflective calls in generated functions
This reverts commit cbdf0c2afb.

The commit causes tests failures on IE8. I'm not quite sure why and I can't
investigate now.

Failed build: https://travis-ci.org/angular/angular.js/jobs/30756773
2014-07-24 09:07:57 -07:00
Igor Minar cbdf0c2afb perf($parse): don't use reflective calls in generated functions
Chrome and FF are smart enough to notice that the key is is a string literal, so this change doesn't
make a difference there. Safari gets a boost. I haven't tested IE, but it can't cause harm there. :)

http://jsperf.com/fn-dereferencing
2014-07-24 07:43:00 -07:00
Patrick Hallisey 1111076552 docs($resource): note methods list is non-exhaustive
The existing documentation for custom action methods implies that only a small
list of upper case methods can be used for custom $resource actions.
2014-07-23 15:02:44 -07:00
Shahar Talmi 948c86c602 fix(ngHref): remove attribute when empty value instead of ignoring
Closes #2755
2014-07-23 13:42:27 -07:00
Diego Plentz cd63ff497d docs(guide/concepts): update example
The "A first example: Data binding" section it implies that the `required` directive is
doing something, but it isn't.

I just removed the parts the refer to the required directive to avoid confusion.
2014-07-23 11:34:32 -07:00
Karl Yang 9d6240561b docs(tutorial): remove index.html from app url 2014-07-23 10:32:58 -07:00
Chad Smith 05b5245790 docs(guide): remove redundancy in providers guide
Highlighted the Best Practices section, and took the styling from the Services doc.
Also removed some superfluous wording that was in the "Provider Recipe"
2014-07-23 09:21:36 -07:00
Shahar Talmi e6ebfc87c9 refactor(Angular): add isPromiseLike helper function
This can be used internally to remove the repeating pattern of `obj && obj.then`. For now, I don't see a good reason to expose this in angular's public interface.

Conflicts:
	src/Angular.js
2014-07-22 16:35:02 -07:00
Julie Ralph 7f2bcc3933 chore(e2e): protractor version bump to 1.0 2014-07-22 15:29:00 -07:00
Igor Minar 492b0cdf28 perf(forEach): use native for loop instead of forEach for Arrays
Conflicts:
	src/Angular.js
2014-07-22 11:40:59 -07:00
hanstest 51863f80d7 docs(guide/directive): fix formatting 2014-07-22 10:34:08 -07:00
Peter Bacon Darwin 9d4000d689 docs(guide/$location): fix up example protractor tests
Closes #8255
2014-07-22 17:55:48 +01:00
vdyckn bc036c68ac docs(guide/$location) global cntl deprecated
Closes #8255
2014-07-22 17:55:48 +01:00
Shane Keller 580135a9cb docs(guide/scope): add missing period 2014-07-21 17:21:34 -07:00
Jason Hamm da0c5efa72 docs(guide/bootstrap): fix example 2014-07-21 16:53:43 -07:00
Vikram Soni c280d5ab02 Updated e2e spec to remove warning
on
element(by.css(.phones li a)).click();

selenium will throw a warning message that more then one element found.

element.all(by.css('.phones li a')).first().click(); fixes the issue
2014-07-21 16:10:42 -07:00
Jesse Palmer 28c8199cd6 docs(misc/faq): minor formatting fixes 2014-07-21 15:30:13 -07:00
garetht 0252a9889b docs($http) Clarify how to specify JSONP callback.
Make clear that it is the name of the callback that should be `JSON_CALLBACK`, instead of the current vague description.

Closes #8269
2014-07-21 14:55:15 -07:00
Trey Hunner 1c15cdc2d0 style: fix whitespace issues
Closes #8277

Conflicts:
	docs/content/guide/migration.ngdoc
2014-07-21 14:52:06 -07:00
Nick Van Dyck 0bd329d4fd docs(guide/concepts): use protocol relative URL
When accessing the docs from https, the "Accessing the backend example fails
because it contains a hard coded protocol. By making the URL protocol relative,
the example should work over http and https.
2014-07-21 14:45:16 -07:00
Trey Hunner 8db84a16db chore(.editorconfig): add .editorconfig file
Closes #8278
2014-07-21 14:43:59 -07:00
Igor Minar cffcfc73a0 style($http): fix indentation 2014-07-21 14:43:48 -07:00
Peter Bacon Darwin 25eb9b794f docs(ngMock) add @packageName tag to fix invalid module overview pages
Closes #7284
Closes #8038
2014-07-21 21:03:40 +01:00
Peter Bacon Darwin 6941779543 chore(package): update dgeni-package to v0.9.6
This version supports `@packageName` tag that will allow us to fix the docs
for ngMock and ngMockE2E
2014-07-21 21:03:40 +01:00
xi 65f40d2123 docs(ngBind): fix wording
You can not change the use of `{{}}`/`ngBind` based on the time when it is used.
So this should be "if".

Closes #7786
2014-07-18 15:54:57 -07:00
rodyhaddad e159f9626c chore(travis): get npm dependencies from npm-bundle-deps
npm-bundle-deps has been rewritten to be more robust
2014-07-18 15:37:20 -07:00
Peter Bacon Darwin 685a9d040d docs(indexPage): move latest versions to the top
Closes #7513
2014-07-18 22:04:08 +01:00
Igor Minar 8eede099cd perf(ngBindHtml): move addClass to the compile phase
Closes #8261

Conflicts:
	src/ng/directive/ngBind.js
2014-07-18 13:52:06 -07:00
Brian Ford a17d42d706 docs(changelog): release notes for 1.3.0-beta.16 pizza-transubstantiation 2014-07-18 12:21:28 -07:00
Carlo s A. Guillen 60af504c18 fix($location): handle plus character in query strings
Closes #3042
2014-07-18 08:37:59 -07:00
Peter Bacon Darwin 243d9ac72c docs(guide/module): add protractor tests 2014-07-18 11:12:49 +01:00
Peter Bacon Darwin cc8eb91665 style(guide/module): use dot first style when chaining 2014-07-18 11:12:49 +01:00
Nick Van Dyck 8697c3bf4c docs(guide/module) fixed global controller in example
Global controllers have been disallowed in Angular 1.3

Closes #8248
2014-07-18 11:12:49 +01:00
Jason Bedard 3c46c94342 perf(jqLite): expose the low-level jqLite.data/removeData calls
- updated the internal jqLite helpers to use the low-level jqLite.data/removeData to avoid unnecessary jq wrappers and loops
- updated $compile to use the low-level jqLite.data/removeData to avoid unnecessary jq wrappers at link time
2014-07-17 17:18:35 -07:00
Jason Bedard 71eb1901f6 perf($compile): only create jqLite object when necessary 2014-07-17 17:15:21 -07:00
Brian Ford 4e57e28589 docs(triaging): clarify severity and frequency labels 2014-07-17 12:32:23 -07:00
Peter Bacon Darwin 13289c0903 chore(package): update to latest dgeni-packages
This fixes an issue with HTML encoding HTML entities in code blocks
2014-07-17 13:05:00 +01:00
Julie Ralph afdb4f1b76 chore(ci): update protractor to 1.0.0-rc5 and increase global timeout for loading pages
This should help with occasional safari page load timeouts. In a test of
4500 page loads, the current 10 second limit caused 3 errors while a 30 second limit
caused none.

Closes #8231
2014-07-16 23:10:05 -07:00
Josh Schreuder e7999e7447 docs($interval): fix missing square brackets in example
Closes #8228
2014-07-16 20:42:43 -04:00
Caitlin Potter d175bb0131 fix(ngSanitize): follow HTML parser rules for start tags / allow < in text content
ngSanitize will now permit opening braces in text content, provided they are not followed by either
an unescaped backslash, or by an ASCII letter (u+0041 - u+005A, u+0061 - u+007A), in compliance with
rules of the parsing spec, without taking insertion mode into account.

BREAKING CHANGE

Previously, $sanitize would "fix" invalid markup in which a space preceded alphanumeric characters
in a start-tag. Following this change, any opening angle bracket which is not followed by either a
forward slash, or by an ASCII letter (a-z | A-Z) will not be considered a start tag delimiter, per
the HTML parsing spec (http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html).

Closes #8212
Closes #8193
2014-07-16 19:56:39 -04:00
Michał Gołębiowski fe1188daf3 refactor(jshint): reduce duplication & test all JS files
Conflicts:
	src/Angular.js
	src/AngularPublic.js
	src/jqLite.js
	src/ng/directive/input.js
2014-07-16 19:56:14 -04:00
Michał Gołębiowski e1a3a6251f chore(jshint): update grunt-contrib-jshint 2014-07-16 19:19:21 -04:00
Caitlin Potter 25d3d3730d revert: fix(ngSanitize): follow HTML parser rules for start tags / allow < in text content
This reverts commit 36d2658b94.

This commit broke the ci-checks task when ported into v1.2.x --- I will sort this out shortly.
2014-07-16 18:13:17 -04:00
Caitlin Potter af5aacce05 test(jqLite): make iframe contents() test less flaky 2014-07-16 17:47:57 -04:00
Paul Harris 3abd0fb93c test(filter): fix typo in descriptions
Two descriptions contain typo's to the word predicate.

Closes #8004
2014-07-16 17:05:01 -04:00
Caitlin Potter 36d2658b94 fix(ngSanitize): follow HTML parser rules for start tags / allow < in text content
ngSanitize will now permit opening braces in text content, provided they are not followed by either
an unescaped backslash, or by an ASCII letter (u+0041 - u+005A, u+0061 - u+007A), in compliance with
rules of the parsing spec, without taking insertion mode into account.

BREAKING CHANGE

Previously, $sanitize would "fix" invalid markup in which a space preceded alphanumeric characters
in a start-tag. Following this change, any opening angle bracket which is not followed by either a
forward slash, or by an ASCII letter (a-z | A-Z) will not be considered a start tag delimiter, per
the HTML parsing spec (http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html).

Closes #8212
Closes #8193
2014-07-16 16:59:04 -04:00
Izhaki 6ce5a04d42 docs($compile): fix template and replace properties' docs
Closes #8062
2014-07-16 13:43:05 -07:00
Caitlin Potter 929064d9e4 test($http): ignore date-toJSON test if running in IE8
IE8 does not implement Date.prototype.toISOString(), which is necessary for this feature. The
feature still works if this method is polyfilled, but these tests are not run with polyfills.
2014-07-16 12:06:48 -04:00
Caitlin Potter d0b873a4b7 revert: chore(travis): get npm dependencies from npm-bundle-deps
This commit was causing some issues with CI testing, so it's being temporarily removed until that's
resolved.

This reverts commit 8881606cd9.
2014-07-16 11:34:43 -04:00
Almar 2e10659472 docs(misc core): fixed broken angular.copy example
The module was not being registered, and this broke the example for who knows how long!

Closes #8218
2014-07-16 11:30:38 -04:00
Max 2a8493f40c docs(guide/forms): fix controller name in example
The "Binding to form and control state" sample had the wrong controller name

Closes #8206
2014-07-16 11:16:38 +01:00
Dan Barua 2f960f1530 fix($http): fix double-quoted date issue when encoding params
This commit special cases date handling rather than calling toJSON as we always need
a string representation of the object.

$http was wrapping dates in double quotes leading to query strings like this:
  ?date=%222014-07-07T23:00:00.000Z%22

Closes #8150
Closes #6128
Closes #8154
2014-07-15 17:18:38 -07:00
rodyhaddad 3f5f20fe77 chore(travis): get npm dependencies from npm-bundle-deps 2014-07-15 17:09:51 -07:00
Christian 01387c0a8f docs(orderBy filter): fix controller name in example
Closes #8133
Closes #8206
2014-07-15 17:57:03 +01:00
rodyhaddad c0afbfaca5 fix(select): force visual update in IE
IE9, IE10 and IE11 would always show the first <option> as
selected when the user moves from a null <option>
to a non-null one in a non-null <select>.
Even though the model was being updated correctly,
visually, the first <option> always appeared selected.

Setting the `selected` property twice in a row
seems to fix it in all the three versions mentioned above.

Closes #7692
Closes #8158
2014-07-15 09:47:22 -07:00
Shahar Talmi bf13d2683d fix($rootScope): $watchCollection should handle NaN in objects
This fixes a potential infinite digest in $watchCollection when one of the values is NaN. This was previously fixed for arrays, but needs to be handled for objects as well.

Closes #7930
2014-07-15 09:45:13 -07:00
Peter Bacon Darwin fe01a85a8e style(orderBySpec): fix indentation 2014-07-15 14:29:25 +01:00
Peter Bacon Darwin 6b9a332959 style($route): convert tab indent to spaces 2014-07-15 14:01:09 +01:00
Sekib Omazic f1b28847c8 fix(orderBy): correctly order by date values
Closes #6675
Closes #6746
2014-07-15 13:41:27 +01:00
Jason Miller 1b779028fd fix(ngRoute): remove unnecessary call to decodeURIComponent
Since `$location.$$path` is already decoded, doing an extra `decodeURIComponent` is both unnecessary
and can cause problems. Specifically, if the path originally includes an encoded `%` (aka `%25`),
then ngRoute will throw "URIError: URI malformed".

Closes #6326
Closes #6327
2014-07-15 13:24:40 +01:00
Wladimir Coka 49b2a1c8cf refactor($parse): improve readability on conditional assignment
Use logical OR operator instead of if statement

Closes #5065
2014-07-15 12:49:00 +01:00
Wladimir Coka 3e82492fc6 refactor($http): improve readability on conditional assignment
Use ternary operator instead of if statement

Closes #5065
2014-07-15 12:48:48 +01:00
Wladimir Coka 856be44628 refactor(dateFilter): improve readability on conditional assignment
Use ternary operator instead of if statement

Closes #5065
2014-07-15 12:48:39 +01:00
Wladimir Coka dbb21b1531 refactor($compile): improve readability on conditional assignment
Use ternary operator instead of if statement

Closes #5065
2014-07-15 12:48:09 +01:00
Peter Bacon Darwin 3ce56b739c docs(guide/unit-testing): add info on testing element transclude directives
Closes #4505
Closes #8197
2014-07-15 12:40:26 +01:00
Bill Neubauer ecbb374826 docs(tutorial/step-9): link to list of filters rather than filterProvider
Closes #8082
2014-07-15 12:40:26 +01:00
Igor Minar 0e5d31908e fix(csp): fix autodetection of CSP + better docs
CSP spec got changed and it is no longer possible to autodetect if a policy is
active without triggering a CSP error:

https://github.com/w3c/webappsec/commit/18882953ce2d8afca25f685557fef0e0471b2c9a

Now we use `new Function('')` to detect if CSP is on. To prevent error from this
detection to show up in console developers have to use the ngCsp directive.

(This problem became more severe after our recent removal of `simpleGetterFn`
 which made us depend on function constructor for all expressions.)

Closes #8162
Closes #8191
2014-07-14 17:20:06 -07:00
standup75 f1b0d21f97 docs(ngAnimate): ensure the CSS breakdown example uses a compound selector 2014-07-14 11:29:35 -04:00
Igor Minar 58e94dcde9 docs($parse:isecdom): add a section about return values and CoffeeScript
Closes #7973
2014-07-12 20:24:20 -07:00
968 changed files with 92678 additions and 14148 deletions
-4
View File
@@ -1,4 +0,0 @@
{
"directory": "bower_components",
"json": "bower.json"
}
+21
View File
@@ -0,0 +1,21 @@
# http://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[src/ngLocale/**]
insert_final_newline = false
[dropdown-toggle.js]
trim_trailing_whitespace = false
insert_final_newline = false
[htmlparser.js]
insert_final_newline = false
+2 -2
View File
@@ -9,10 +9,10 @@ performance/temp*.html
*.swp
angular.js.tmproj
/node_modules/
/components/
/bower_components/
bower_components/
angular.xcodeproj
.idea
*.iml
.agignore
libpeerconnection.log
npm-debug.log
+2
View File
@@ -0,0 +1,2 @@
node_modules/**
lib/htmlparser/**
+5
View File
@@ -0,0 +1,5 @@
{
"extends": ".jshintrc-base",
"node": true,
"globals": {}
}
+19
View File
@@ -0,0 +1,19 @@
{
"bitwise": true,
"immed": true,
"newcap": true,
"noarg": true,
"noempty": true,
"nonew": true,
"trailing": true,
"maxlen": 200,
"boss": true,
"eqnull": true,
"expr": true,
"globalstrict": true,
"laxbreak": true,
"loopfunc": true,
"sub": true,
"undef": true,
"indent": 2
}
+2 -3
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
@@ -24,8 +23,8 @@ install:
- npm config set spin false
# Log HTTP requests
- npm config set loglevel http
# Run npm install twice, because it is flaky.
- npm install || npm install
- time ./scripts/travis/npm-bundle-deps.sh
- time npm install
before_script:
- mkdir -p $LOGS_DIR
+2004
View File
File diff suppressed because it is too large Load Diff
+6 -6
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)
@@ -119,7 +119,7 @@ Before you submit your pull request consider the following guidelines:
```
* In GitHub, send a pull request to `angular:master`.
* If we suggest changes then
* If we suggest changes then
* Make the required updates.
* Re-run the Angular test suite to ensure tests are still passing.
* Rebase your branch and force push to your GitHub repository (this will update your Pull Request):
@@ -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
@@ -237,7 +237,7 @@ reference GitHub issues that this commit **Closes**.
A detailed explanation can be found in this [document][commit-message-format].
## <a name="cla"></a> Signing the CLA
## <a name="cla"></a> Signing the CLA
Please sign our Contributor License Agreement (CLA) before sending pull requests. For any code
changes to be accepted, the CLA must be signed. It's a quick process, we promise!
+10 -1
View File
@@ -1,3 +1,5 @@
'use strict';
var files = require('./angularFiles').files;
var util = require('./lib/grunt/utils.js');
var versionInfo = require('./lib/versions/version-info');
@@ -107,6 +109,9 @@ module.exports = function(grunt) {
options: {
jshintrc: true,
},
node: {
files: { src: ['*.js', 'lib/**/*.js'] },
},
tests: {
files: { src: 'test/**/*.js' },
},
@@ -252,7 +257,11 @@ module.exports = function(grunt) {
compress: {
build: {
options: {archive: 'build/' + dist +'.zip', mode: 'zip'},
src: ['**'], cwd: 'build', expand: true, dot: true, dest: dist + '/'
src: ['**'],
cwd: 'build',
expand: true,
dot: true,
dest: dist + '/'
}
},
+7 -6
View File
@@ -6,16 +6,17 @@ 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
* API Docs: http://docs.angularjs.org/api
* Developer Guide: http://docs.angularjs.org/guide
* Contribution guidelines: http://docs.angularjs.org/misc/contribute
* Contribution guidelines: [CONTRIBUTING.md](https://github.com/angular/angular.js/blob/master/CONTRIBUTING.md)
* Dashboard: http://dashboard.angularjs.org
Building AngularJS
@@ -37,7 +38,7 @@ To execute end-to-end (e2e) tests, use:
grunt test:e2e
To learn more about the grunt tasks, run `grunt --help` and also read our
[contribution guidelines](http://docs.angularjs.org/misc/contribute).
[contribution guidelines](https://github.com/angular/angular.js/blob/master/CONTRIBUTING.md).
[![Analytics](https://ga-beacon.appspot.com/UA-8594346-11/angular.js/README.md?pixel)](https://github.com/igrigorik/ga-beacon)
+4 -7
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.
@@ -44,11 +42,11 @@ This process based on the idea of minimizing user pain
* Label `needs: breaking change` - if needed
* Label `needs: public api` - if the issue requires introduction of a new public API
1. Label `browser: *` - if the issue **only** affects a certain browser
1. Label `frequency: *` How often does this issue come up? How many developers does this affect?
1. Label `frequency: *` How often does this issue come up? How many developers does this affect? Chose just one of the following:
* low - obscure issue affecting a handful of developers
* moderate - impacts a common usage pattern
* high - impacts most or all Angular apps
1. Label `severity: *` - How bad is the issue?
1. Label `severity: *` - How bad is the issue? Chose just one of the following:
* security issue
* regression
* memory leak
@@ -59,11 +57,10 @@ 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
* 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
1. Unassign yourself from the issue
+3 -1
View File
@@ -1,4 +1,6 @@
angularFiles = {
'use strict';
var angularFiles = {
'angularSrc': [
'src/minErr.js',
'src/Angular.js',
+1 -5
View File
@@ -2,11 +2,7 @@
"name": "AngularJS",
"devDependencies": {
"jquery": "1.10.2",
"lunr.js": "0.4.3",
"open-sans-fontface": "1.0.4",
"google-code-prettify": "1.0.1",
"closure-compiler": "https://closure-compiler.googlecode.com/files/compiler-20130603.zip",
"ng-closure-runner": "https://raw.github.com/angular/ng-closure-runner/v0.2.3/assets/ng-closure-runner.zip",
"bootstrap": "3.1.1"
"ng-closure-runner": "https://raw.github.com/angular/ng-closure-runner/v0.2.3/assets/ng-closure-runner.zip"
}
}
+7 -3
View File
@@ -3,6 +3,8 @@
// TODO(vojta): pre-commit hook for validating messages
// TODO(vojta): report errors, currently Q silence everything which really sucks
'use strict';
var child = require('child_process');
var fs = require('fs');
var util = require('util');
@@ -110,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));
}
});
});
@@ -164,7 +166,7 @@ var writeChangelog = function(stream, commits, version) {
hash: commit.hash,
closes: []
});
};
}
});
stream.write(util.format(HEADER_TPL, version, version, currentDate()));
@@ -172,7 +174,7 @@ var writeChangelog = function(stream, commits, version) {
printSection(stream, 'Features', sections.feat);
printSection(stream, 'Performance Improvements', sections.perf);
printSection(stream, 'Breaking Changes', sections.breaks, false);
}
};
var getPreviousTag = function() {
@@ -186,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) {
@@ -199,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) {
+66 -1
View File
@@ -1,3 +1,7 @@
/* global describe: false, beforeEach: false, afterEach: false, it: false, expect: false */
'use strict';
describe('changelog.js', function() {
var ch = require('./changelog');
@@ -13,7 +17,7 @@ describe('changelog.js', function() {
expect(msg.hash).toBe('9b1aff905b638aa274a5fc8f88662df446d374bd');
expect(msg.subject).toBe('broadcast $destroy event on scope destruction');
expect(msg.body).toBe('perf testing shows that in chrome this change adds 5-15% overhead\n' +
'when destroying 10k nested scopes where each scope has a $destroy listener\n')
'when destroying 10k nested scopes where each scope has a $destroy listener\n');
expect(msg.component).toBe('scope');
});
@@ -40,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);
});
});
});
+3 -1
View File
@@ -1,5 +1,7 @@
#!/usr/local/bin/node
'use strict';
var util = require('util');
var cp = require('child_process');
@@ -143,7 +145,7 @@ then(allInSeries(function (branch) {
return sha + (msg.toLowerCase().indexOf('fix') === -1 ? ' ' : ' * ') + msg;
});
branch.log = log.map(function (line) {
return line.substr(41)
return line.substr(41);
});
return branch;
});
+10 -8
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 {
@@ -635,12 +635,14 @@ ul.events > li {
display:inline-block;
padding:3px 0;
}
.nav-index-group .nav-index-listing:not(.nav-index-section) + .nav-index-listing:not(.nav-index-section):after {
padding-right:5px;
content:", ";
.nav-index-group .nav-index-listing:not(.nav-index-section):after {
padding-right:5px;
margin-left:-3px;
content:", ";
}
.nav-index-group .nav-index-listing:last-child {
.nav-index-group .nav-index-listing:last-child:after {
content:"";
display:inline-block;
}
.nav-index-group .nav-index-section {
display:block;
+4
View File
@@ -6,6 +6,10 @@
line-height: 1.5;
}
.lang-text * {
color: #333333!important;
}
.pln {
color: #333333;
}
+1 -1
View File
@@ -40,7 +40,7 @@ pre.prettyprint.linenums {
}
ol.linenums {
margin: 0 0 0 33px; /* IE indents via margin-left */
}
}
ol.linenums li {
padding-left: 12px;
font-size:12px;
@@ -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);
+3 -3
View File
@@ -11,7 +11,7 @@ directive.runnableExample = ['$templateCache', '$document', function($templateCa
'ng-repeat="tab in tabs track by $index" ' +
'href="" ' +
'class="btn"' +
'ng-click="setTab($index)">' +
'ng-click="setTab($index)">' +
' {{ tab }}' +
' </a>' +
'</nav>';
@@ -103,7 +103,7 @@ directive.syntax = function() {
restrict: 'A',
link: function(scope, element, attrs) {
function makeLink(type, text, link, icon) {
return '<a href="' + link + '" class="btn syntax-' + type + '" target="_blank" rel="nofollow">' +
return '<a href="' + link + '" class="btn syntax-' + type + '" target="_blank" rel="nofollow">' +
'<span class="' + icon + '"></span> ' + text +
'</a>';
};
@@ -307,7 +307,7 @@ var popoverElement = function() {
return this.titleElement.html(value);
},
content : function(value) {
content : function(value) {
if(value && value.length > 0) {
value = marked(value);
}
+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(by.css('tt'));
expect(code.getText()).toContain('guest!!!');
});
it('should be resilient to trailing slashes', function() {
browser.get('index-debug.html#!/api/ng/function/angular.noop/');
@@ -67,5 +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('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;
});
}
});
}]);
+1 -1
View File
@@ -59,4 +59,4 @@ angular.module('errors', ['ngSanitize'])
element.html(errorLinkFilter(interpolate.apply(null, formatArgs), '_blank'));
}
};
}]);
}]);
+7 -2
View File
@@ -2,7 +2,12 @@ angular.module('examples', [])
.factory('formPostData', ['$document', function($document) {
return function(url, fields) {
var form = angular.element('<form style="display: none;" method="post" action="' + url + '" target="_blank"></form>');
/**
* Form previously posted to target="_blank", but pop-up blockers were causing this to not work.
* If a user chose to bypass pop-up blocker one time and click the link, they would arrive at
* a new default plnkr, not a plnkr with the desired template.
*/
var form = angular.element('<form style="display: none;" method="post" action="' + url + '"></form>');
angular.forEach(fields, function(value, name) {
var input = angular.element('<input type="hidden" name="' + name + '">');
input.attr('value', value);
@@ -69,4 +74,4 @@ angular.module('examples', [])
formPostData('http://plnkr.co/edit/?p=preview', postData);
});
};
}]);
}]);
-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 -62
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,76 +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('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
// 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>'
};
});
});
+20 -4
View File
@@ -1,15 +1,31 @@
"use strict";
angular.module('versions', [])
.controller('DocsVersionsCtrl', ['$scope', '$location', '$window', 'NG_VERSIONS', function($scope, $location, $window, NG_VERSIONS) {
$scope.docs_versions = 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];
// NaN will give false here
if (minor <= version.minor) {
continue;
}
version.isLatest = true;
minor = version.minor;
}
$scope.getGroupName = function(v) {
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...
$window.location = version.docsUrl + currentPagePath;
};
}]);
}]);
+3 -3
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,8 +27,8 @@ 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']);
}));
});
});
});
+10
View File
@@ -0,0 +1,10 @@
{
"name": "AngularJS-docs-app",
"dependencies": {
"jquery": "2.1.1",
"lunr.js": "0.4.3",
"open-sans-fontface": "1.0.4",
"google-code-prettify": "1.0.1",
"bootstrap": "3.1.1"
}
}
+155 -32
View File
@@ -1,43 +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')
]);
config.append('processing.tagDefinitions', [
require('./tag-defs/tutorial-step')
]);
.factory(require('./services/errorNamespaceMap'))
.factory(require('./services/getMinerrInfo'))
.factory(require('./services/getVersion'))
.factory(require('./services/gitData'))
config.append('processing.defaultTagTransforms', [
require('dgeni-packages/jsdoc/tag-defs/transforms/trim-whitespace')
]);
.factory(require('./services/deployments/debug'))
.factory(require('./services/deployments/default'))
.factory(require('./services/deployments/jquery'))
.factory(require('./services/deployments/production'))
config.append('processing.inlineTagDefinitions', [
require('./inline-tag-defs/type')
]);
.factory(require('./inline-tag-defs/type'))
config.set('processing.search.ignoreWordsFile', path.resolve(packagePath, 'ignore.words'));
config.prepend('rendering.templateFolders', [
path.resolve(packagePath, 'templates')
]);
.processor(require('./processors/error-docs'))
.processor(require('./processors/index-page'))
.processor(require('./processors/keywords'))
.processor(require('./processors/pages-data'))
.processor(require('./processors/versions-data'))
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');
});
}
+42 -49
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);
});
}
};
};
};
+73 -47
View File
@@ -1,50 +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'],
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) {
@@ -52,37 +66,49 @@ module.exports = {
_.forEach(tokens, function(token){
var match = token.match(KEYWORD_REGEX);
if (match){
key = match[1];
var key = match[1];
if ( !keywordMap[key]) {
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);
var members = [];
var membersMap = {};
// Search each top level property of the document for search terms
_.forEach(doc, function(value, key) {
if ( _.isString(value) && !propertiesToIgnore[key] ) {
extractWords(value, words, keywordMap);
}
if ( key === 'methods' || key === 'properties' || key === 'events' ) {
_.forEach(value, function(member) {
extractWords(member.name, members, membersMap);
});
}
});
doc.searchTerms = {
titleWords: extractTitleWords(doc.name),
keywords: _.sortBy(words).join(' ')
keywords: _.sortBy(words).join(' '),
members: _.sortBy(members).join(' ')
};
});
});
}
};
}
};
};
+181 -156
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,182 +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, '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) {
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]
})];
},
error: function(pages, area) {
return [getNavGroup(pages, area, 'path', function(page) {
return {
name: page.name,
href: page.path,
type: page.docType === 'errorNamespace' ? 'section' : 'error'
};
areas[areaId] = area;
})];
},
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'
};
}
)];
}
};
var navGroupMapper = navGroupMappers[area.id] || navGroupMappers['pages'];
area.navGroups = navGroupMapper(pages, area);
return {
$runAfter: ['paths-computed', 'generateKeywordsProcessor'],
$runBefore: ['rendering-docs'],
$process: function(docs) {
// 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,49 +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
};
if (env === 'jquery') {
protractorDoc.examplePath = example.outputFolder + '/index-jquery.html';
} else {
protractorDoc.examplePath = example.outputFolder + '/index.html';
}
return protractorDoc;
}
}
};
+28 -32
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
};
};
+6
View File
@@ -0,0 +1,6 @@
module.exports = {
name: 'sortOrder',
transforms: function(doc, tag, value) {
return parseInt(value, 10);
}
};
+1 -1
View File
@@ -14,4 +14,4 @@
{$ doc.description | marked $}
</div>
{% endblock %}
{% endblock %}
@@ -25,4 +25,4 @@
</div>
</div>
{% endblock %}
{% endblock %}
+3 -12
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>
@@ -175,7 +166,7 @@
<div class="container main-grid main-header-grid">
<div class="grid-left">
<div ng-controller="DocsVersionsCtrl" class="picker version-picker">
<select ng-options="v as ('v' + v.version + (v.isSnapshot ? ' (snapshot)' : '')) group by (v.isStable?'Stable':'Unstable') for v in docs_versions"
<select ng-options="v as ('v' + v.version + (v.isSnapshot ? ' (snapshot)' : '')) group by getGroupName(v) for v in docs_versions"
ng-model="docs_version"
ng-change="jumpToDocsVersion(docs_version)"
class="docs-version-jump">
@@ -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,7 +0,0 @@
describe("{$ doc.description $}", function() {
beforeEach(function() {
browser.get("{$ doc.pathPrefix $}/{$ doc.examplePath $}");
});
{$ 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,9 +20,9 @@
</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>
{# Be aware that we need these extra new lines here or marked will not realise that the <div>
above is HTML and wrap each line in a <p> - thus breaking the HTML #}
above is HTML and wrap each line in a <p> - thus breaking the HTML #}
+1 -1
View File
@@ -1 +1 @@
{% include 'overview.template.html' %}
{% include 'overview.template.html' %}
+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.
+1 -1
View File
@@ -23,4 +23,4 @@ When an instance of `MyCtrl` is created, the service `myService` will be created
by the `$injector`. `myService` depends on itself, which causes the `$injector`
to detect a circular dependency and throw the error.
For more information, see the {@link guide/di Dependency Injection Guide}.
For more information, see the {@link guide/di Dependency Injection Guide}.
+1 -1
View File
@@ -23,4 +23,4 @@ To avoid the error, always use string literals for dependency injection annotati
tokens.
For an explanation of what injection annotations are and how to use them, refer
to the {@link guide/di Dependency Injection Guide}.
to the {@link guide/di Dependency Injection Guide}.
+1 -1
View File
@@ -23,4 +23,4 @@ angular.module("myApp", [])
```
For more information, refer to the {@link auto.$provide#provider
$provide.provider} api doc.
$provide.provider} api doc.
+45 -1
View File
@@ -14,7 +14,7 @@ angular.module('myApp', [])
}]);
```
The above code will fail with `$injector:unpr` if `myService` is not defined.
The above code will fail with `$injector:unpr` if `myService` is not defined.
Making sure each dependency is defined will fix the problem, as noted below.
@@ -25,3 +25,47 @@ angular.module('myApp', [])
// Do something with myService
}]);
```
An unknown provider error can also be caused by accidentally redefining a
module using the `angular.module` API, as shown in the following example.
```
angular.module('myModule', [])
.service('myCoolService', function () { /* ... */ });
angular.module('myModule', [])
// myModule has already been created! This is not what you want!
.directive('myDirective', ['myCoolService', function (myCoolService) {
// This directive definition throws unknown provider, because myCoolService
// has been destroyed.
}]);
```
To fix this problem, make sure you only define each module with the
`angular.module(name, [requires])` syntax once across your entire project.
Retrieve it for subsequent use with `angular.module(name)`. The fixed example
is shown below.
```
angular.module('myModule', [])
.service('myCoolService', function () { /* ... */ });
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.
@@ -9,4 +9,4 @@ it hard to reason about whether some combination of concatenated values are
unsafe to use and could easily lead to XSS.
For more information about how AngularJS helps keep your app secure, refer to
the {@link ng.$sce $sce} API doc.
the {@link ng.$sce $sce} API doc.
+31
View File
@@ -14,3 +14,34 @@ perform this check - it's up to the developer to not expose such sensitive and p
directly on the scope chain.
To resolve this error, avoid access to DOM nodes.
# Event Handlers and Return Values
The `$parse:isecdom` error also occurs when an event handler invokes a function that returns a DOM
node.
```html
<button ng-click="iWillReturnDOM()">click me</button>
```
```js
$scope.iWillReturnDOM = function() {
return someDomNode;
}
```
To fix this issue, avoid returning DOM nodes from event handlers.
*Note: This error often means that you are accessing DOM from your controllers, which is usually
a sign of poor coding style that violates separation of concerns.*
# Implicit Returns in CoffeeScript
This error can occur more frequently when using CoffeeScript, which has a feature called implicit
returns. This language feature returns the last dereferenced object in the function when the
function has no explicit return statement.
The solution in this scenario is to add an explicit return statement. For example `return false` to
the function.
+1 -1
View File
@@ -14,4 +14,4 @@ Example expression that would result in this error:
```
<div>{{user.sendInfo.call({}, true)}}</div>
```
```
+1 -1
View File
@@ -24,4 +24,4 @@ Example expressions that would result in this error:
<div>{{user.__proto__.hasOwnProperty = $emit}}</div>
<div>{{user.__defineGetter__('name', noop)}}</div>
```
```
+1 -1
View File
@@ -5,4 +5,4 @@
Occurs when you try to use the name `hasOwnProperty` as a name of a parameter.
Generally, a name cannot be `hasOwnProperty` because it is used, internally, on a object
and allowing such a name would break lookups on this object.
and allowing such a name would break lookups on this object.
+2 -2
View File
@@ -10,7 +10,7 @@ Angular's {@link ng.$sce Strict Contextual Escaping (SCE)} mode
contexts to result in a value that is trusted as safe for use in such a context. (e.g. loading an
Angular template from a URL requires that the URL is one considered safe for loading resources.)
This helps prevent XSS and other security issues. Read more at {@link
api/ng.$sce Strict Contextual Escaping (SCE)}
This helps prevent XSS and other security issues. Read more at
{@link ng.$sce Strict Contextual Escaping (SCE)}
You may want to include the ngSanitize module to use the automatic sanitizing.
+1 -1
View File
@@ -5,4 +5,4 @@
AngularJS often asserts that certain values will be present and truthy using a
helper function. If the assertion fails, this error is thrown. To fix this problem,
make sure that the value the assertion expects is defined and truthy.
make sure that the value the assertion expects is defined and truthy.
+1 -1
View File
@@ -5,4 +5,4 @@
Occurs when you try to use the name `hasOwnProperty` in a context where it is not allow.
Generally, a name cannot be `hasOwnProperty` because it is used, internally, on a object
and allowing such a name would break lookups on this object.
and allowing such a name would break lookups on this object.
+1 -1
View File
@@ -49,4 +49,4 @@ You can also get this error if you accidentally load AngularJS itself more than
<script src="angular.js"></script>
</body>
</html>
```
```
+1 -1
View File
@@ -7,4 +7,4 @@ This error occurs when attempting to copy an object to itself. Calling {@link
api/angular.copy angular.copy} with a `destination` object deletes
all of the elements or properties on `destination` before copying to it. Copying
an object to itself is not supported. Make sure to check your calls to
`angular.copy` and avoid copying objects or arrays to themselves.
`angular.copy` and avoid copying objects or arrays to themselves.
+1 -1
View File
@@ -7,4 +7,4 @@ Copying Window or Scope instances is not supported because of cyclical and self
references. Avoid copying windows and scopes, as well as any other cyclical or
self-referential structures. Note that trying to deep copy an object containing
cyclical references that is neither a window nor a scope will cause infinite
recursion and a stack overflow.
recursion and a stack overflow.
+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>
+300 -109
View File
@@ -1,5 +1,6 @@
@ngdoc overview
@name Using $location
@sortOrder 500
@description
# What does it do?
@@ -163,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.
@@ -210,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
@@ -240,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
@@ -249,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
@@ -297,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,
@@ -313,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
@@ -358,118 +359,308 @@ Note that when you type hashbang url into first browser (or vice versa) it doesn
redirect to regular / hashbang url, as this conversion happens only during parsing the initial URL
= on page reload.
In this examples we use `<base href="/base/index.html" />`
<example>
In these examples we use `<base href="/base/index.html" />`
#### Browser in HTML5 mode
<example module="html5-mode" name="location-html5-mode">
<file name="index.html">
<div id="html5-mode" ng-controller="Html5Cntl">
<h3>Browser with History API</h3>
<div ng-address-bar browser="html5"></div><br><br>
$location.protocol() = {{$location.protocol()}}<br>
$location.host() = {{$location.host()}}<br>
$location.port() = {{$location.port()}}<br>
$location.path() = {{$location.path()}}<br>
$location.search() = {{$location.search()}}<br>
$location.hash() = {{$location.hash()}}<br>
<a href="http://www.example.com/base/first?a=b">/base/first?a=b</a> |
<a href="http://www.example.com/base/sec/ond?flag#hash">sec/ond?flag#hash</a> |
<a href="/other-base/another?search">external</a>
</div>
<div id="hashbang-mode" ng-controller="HashbangCntl">
<h3>Browser without History API</h3>
<div ng-address-bar browser="hashbang"></div><br><br>
$location.protocol() = {{$location.protocol()}}<br>
$location.host() = {{$location.host()}}<br>
$location.port() = {{$location.port()}}<br>
$location.path() = {{$location.path()}}<br>
$location.search() = {{$location.search()}}<br>
$location.hash() = {{$location.hash()}}<br>
<a href="http://www.example.com/base/first?a=b">/base/first?a=b</a> |
<a href="http://www.example.com/base/sec/ond?flag#hash">sec/ond?flag#hash</a> |
<a href="/other-base/another?search">external</a>
<div ng-controller="LocationController">
<div ng-address-bar></div><br><br>
<div>
$location.protocol() = <span ng-bind="$location.protocol()"></span> <br>
$location.host() = <span ng-bind="$location.host()"></span> <br>
$location.port() = <span ng-bind="$location.port()"></span> <br>
$location.path() = <span ng-bind="$location.path()"></span> <br>
$location.search() = <span ng-bind="$location.search()"></span> <br>
$location.hash() = <span ng-bind="$location.hash()"></span> <br>
</div>
<div id="navigation">
<a href="http://www.example.com/base/first?a=b">/base/first?a=b</a> |
<a href="http://www.example.com/base/sec/ond?flag#hash">sec/ond?flag#hash</a> |
<a href="/other-base/another?search">external</a>
</div>
</div>
</file>
<file name="app.js">
angular.module('html5-mode', ['fake-browser', 'address-bar'])
<file name="script.js">
function FakeBrowser(initUrl, baseHref) {
this.onUrlChange = function(fn) {
this.urlChange = fn;
.constant('initUrl', 'http://www.example.com/base/path?a=b#h')
.constant('baseHref', '/base/index.html')
.value('$sniffer', { history: true })
.controller("LocationController", function($scope, $location) {
$scope.$location = {};
angular.forEach("protocol host port path search hash".split(" "), function(method){
$scope.$location[method] = function(){
var result = $location[method].call($location);
return angular.isObject(result) ? angular.toJson(result) : result;
};
});
})
.config(function($locationProvider) {
$locationProvider.html5Mode(true).hashPrefix('!');
})
.run(function($rootElement) {
$rootElement.on('click', function(e) { e.stopPropagation(); });
});
</file>
<file name="fakeBrowser.js">
angular.module('fake-browser', [])
.config(function($provide) {
$provide.decorator('$browser', function($delegate, baseHref, initUrl) {
$delegate.onUrlChange = function(fn) {
this.urlChange = fn;
};
$delegate.url = function() {
return initUrl;
};
this.url = function() {
return initUrl;
};
$delegate.defer = function(fn, delay) {
setTimeout(function() { fn(); }, delay || 0);
};
this.defer = function(fn, delay) {
setTimeout(function() { fn(); }, delay || 0);
};
$delegate.baseHref = function() {
return baseHref;
};
this.baseHref = function() {
return baseHref;
};
return $delegate;
});
});
</file>
this.notifyWhenOutstandingRequests = angular.noop;
}
<file name="addressBar.js">
angular.module('address-bar', [])
.directive('ngAddressBar', function($browser, $timeout) {
return {
template: 'Address: <input id="addressBar" type="text" style="width: 400px" >',
link: function(scope, element, attrs){
var input = element.children("input"), delay;
var browsers = {
html5: new FakeBrowser('http://www.example.com/base/path?a=b#h', '/base/index.html'),
hashbang: new FakeBrowser('http://www.example.com/base/index.html#!/path?a=b#h', '/base/index.html')
};
input.on('keypress keyup keydown', function(event) {
delay = (!delay ? $timeout(fireUrlChange, 250) : null);
event.stopPropagation();
})
.val($browser.url());
function Html5Cntl($scope, $location) {
$scope.$location = $location;
}
function HashbangCntl($scope, $location) {
$scope.$location = $location;
}
function initEnv(name) {
var root = angular.element(document.getElementById(name + '-mode'));
// We must kill a link to the injector for this element otherwise angular will
// complain that it has been bootstrapped already.
root.data('$injector', null);
angular.bootstrap(root, [function($compileProvider, $locationProvider, $provide){
$locationProvider.html5Mode(true).hashPrefix('!');
$provide.value('$browser', browsers[name]);
$provide.value('$sniffer', {history: name == 'html5'});
$compileProvider.directive('ngAddressBar', function() {
return function(scope, elm, attrs) {
var browser = browsers[attrs.browser],
input = angular.element('<input type="text" style="width: 400px">').val(browser.url()),
delay;
input.on('keypress keyup keydown', function() {
if (!delay) {
delay = setTimeout(fireUrlChange, 250);
}
});
browser.url = function(url) {
return input.val(url);
};
elm.append('Address: ').append(input);
function fireUrlChange() {
delay = null;
browser.urlChange(input.val());
}
$browser.url = function(url) {
return url ? input.val(url) : input.val();
};
});
}]);
root.on('click', function(e) {
e.stopPropagation();
});
}
initEnv('html5');
initEnv('hashbang');
function fireUrlChange() {
delay = null;
$browser.urlChange(input.val());
}
}
};
});
</file>
<file name="protractor.js" type="protractor">
var addressBar = element(by.css("#addressBar")),
url = 'http://www.example.com/base/path?a=b#h';
it("should show fake browser info on load", function(){
expect(addressBar.getAttribute('value')).toBe(url);
expect(element(by.binding('$location.protocol')).getText()).toBe('http');
expect(element(by.binding('$location.host')).getText()).toBe('www.example.com');
expect(element(by.binding('$location.port')).getText()).toBe('80');
expect(element(by.binding('$location.path')).getText()).toBe('/path');
expect(element(by.binding('$location.search')).getText()).toBe('{"a":"b"}');
expect(element(by.binding('$location.hash')).getText()).toBe('h');
});
it("should change $location accordingly", function(){
var navigation = element.all(by.css("#navigation a"));
navigation.get(0).click();
expect(addressBar.getAttribute('value')).toBe("http://www.example.com/base/first?a=b");
expect(element(by.binding('$location.protocol')).getText()).toBe('http');
expect(element(by.binding('$location.host')).getText()).toBe('www.example.com');
expect(element(by.binding('$location.port')).getText()).toBe('80');
expect(element(by.binding('$location.path')).getText()).toBe('/first');
expect(element(by.binding('$location.search')).getText()).toBe('{"a":"b"}');
expect(element(by.binding('$location.hash')).getText()).toBe('');
navigation.get(1).click();
expect(addressBar.getAttribute('value')).toBe("http://www.example.com/base/sec/ond?flag#hash");
expect(element(by.binding('$location.protocol')).getText()).toBe('http');
expect(element(by.binding('$location.host')).getText()).toBe('www.example.com');
expect(element(by.binding('$location.port')).getText()).toBe('80');
expect(element(by.binding('$location.path')).getText()).toBe('/sec/ond');
expect(element(by.binding('$location.search')).getText()).toBe('{"flag":true}');
expect(element(by.binding('$location.hash')).getText()).toBe('hash');
});
</file>
</example>
####Browser in HTML5 Fallback mode (Hashbang mode)
<example module="hashbang-mode" name="location-hashbang-mode">
<file name="index.html">
<div ng-controller="LocationController">
<div ng-address-bar></div><br><br>
<div>
$location.protocol() = <span ng-bind="$location.protocol()"></span> <br>
$location.host() = <span ng-bind="$location.host()"></span> <br>
$location.port() = <span ng-bind="$location.port()"></span> <br>
$location.path() = <span ng-bind="$location.path()"></span> <br>
$location.search() = <span ng-bind="$location.search()"></span> <br>
$location.hash() = <span ng-bind="$location.hash()"></span> <br>
</div>
<div id="navigation">
<a href="http://www.example.com/base/first?a=b">/base/first?a=b</a> |
<a href="http://www.example.com/base/sec/ond?flag#hash">sec/ond?flag#hash</a> |
<a href="/other-base/another?search">external</a>
</div>
</div>
</file>
<file name="app.js">
angular.module('hashbang-mode', ['fake-browser', 'address-bar'])
.constant('initUrl', 'http://www.example.com/base/index.html#!/path?a=b#h')
.constant('baseHref', '/base/index.html')
.value('$sniffer', { history: false })
.config(function($locationProvider) {
$locationProvider.html5Mode(true).hashPrefix('!');
})
.controller("LocationController", function($scope, $location) {
$scope.$location = {};
angular.forEach("protocol host port path search hash".split(" "), function(method){
$scope.$location[method] = function(){
var result = $location[method].call($location);
return angular.isObject(result) ? angular.toJson(result) : result;
};
});
})
.run(function($rootElement) {
$rootElement.on('click', function(e) {
e.stopPropagation();
});
});
</file>
<file name="fakeBrowser.js">
angular.module('fake-browser', [])
.config(function($provide) {
$provide.decorator('$browser', function($delegate, baseHref, initUrl) {
$delegate.onUrlChange = function(fn) {
this.urlChange = fn;
};
$delegate.url = function() {
return initUrl;
};
$delegate.defer = function(fn, delay) {
setTimeout(function() { fn(); }, delay || 0);
};
$delegate.baseHref = function() {
return baseHref;
};
return $delegate;
});
});
</file>
<file name="addressBar.js">
angular.module('address-bar', [])
.directive('ngAddressBar', function($browser, $timeout) {
return {
template: 'Address: <input id="addressBar" type="text" style="width: 400px" >',
link: function(scope, element, attrs){
var input = element.children("input"), delay;
input.on('keypress keyup keydown', function(event) {
delay = (!delay ? $timeout(fireUrlChange, 250) : null);
event.stopPropagation();
})
.val($browser.url());
$browser.url = function(url) {
return url ? input.val(url) : input.val();
};
function fireUrlChange() {
delay = null;
$browser.urlChange(input.val());
}
}
};
});
</file>
<file name="protractor.js" type="protractor">
var addressBar = element(by.css("#addressBar")),
url = 'http://www.example.com/base/index.html#!/path?a=b#h';
it("should show fake browser info on load", function(){
expect(addressBar.getAttribute('value')).toBe(url);
expect(element(by.binding('$location.protocol')).getText()).toBe('http');
expect(element(by.binding('$location.host')).getText()).toBe('www.example.com');
expect(element(by.binding('$location.port')).getText()).toBe('80');
expect(element(by.binding('$location.path')).getText()).toBe('/path');
expect(element(by.binding('$location.search')).getText()).toBe('{"a":"b"}');
expect(element(by.binding('$location.hash')).getText()).toBe('h');
});
it("should change $location accordingly", function(){
var navigation = element.all(by.css("#navigation a"));
navigation.get(0).click();
expect(addressBar.getAttribute('value')).toBe("http://www.example.com/base/index.html#!/first?a=b");
expect(element(by.binding('$location.protocol')).getText()).toBe('http');
expect(element(by.binding('$location.host')).getText()).toBe('www.example.com');
expect(element(by.binding('$location.port')).getText()).toBe('80');
expect(element(by.binding('$location.path')).getText()).toBe('/first');
expect(element(by.binding('$location.search')).getText()).toBe('{"a":"b"}');
expect(element(by.binding('$location.hash')).getText()).toBe('');
navigation.get(1).click();
expect(addressBar.getAttribute('value')).toBe("http://www.example.com/base/index.html#!/sec/ond?flag#hash");
expect(element(by.binding('$location.protocol')).getText()).toBe('http');
expect(element(by.binding('$location.host')).getText()).toBe('www.example.com');
expect(element(by.binding('$location.port')).getText()).toBe('80');
expect(element(by.binding('$location.path')).getText()).toBe('/sec/ond');
expect(element(by.binding('$location.search')).getText()).toBe('{"flag":true}');
expect(element(by.binding('$location.hash')).getText()).toBe('hash');
});
</file>
</example>
# Caveats
+1
View File
@@ -1,5 +1,6 @@
@ngdoc overview
@name Animations
@sortOrder 310
@description
+5 -2
View File
@@ -1,5 +1,6 @@
@ngdoc overview
@name Bootstrap
@sortOrder 350
@description
# Bootstrap
@@ -19,7 +20,7 @@ initialization.
<html xmlns:ng="http://angularjs.org" ng-app>
<body>
...
<script src="angular.js">
<script src="angular.js"></script>
</body>
</html>
```
@@ -90,7 +91,9 @@ Here is an example of manually initializing Angular:
<!doctype html>
<html>
<body>
Hello {{'World'}}!
<div ng-controller="MyController">
Hello {{greetMe}}!
</div>
<script src="http://code.angularjs.org/snapshot/angular.js"></script>
<script>
+9 -4
View File
@@ -1,7 +1,10 @@
@ngdoc overview
@name HTML Compiler
@sortOrder 330
@description
# HTML Compiler
<div class="alert alert-warning">
**Note:** this guide is targeted towards developers who are already familiar with AngularJS basics.
@@ -11,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
@@ -84,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
@@ -198,7 +203,7 @@ This should help give you an idea of what Angular does internally.
// Step 3: link the compiled template with the scope.
var element = linkFn(scope);
// Step 4: Append to DOM (optional)
parent.appendChild(element);
```
@@ -327,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
+14 -16
View File
@@ -1,5 +1,6 @@
@ngdoc overview
@name Conceptual Overview
@sortOrder 200
@description
# Conceptual Overview
@@ -37,10 +38,10 @@ Let's start with input fields for quantity and cost whose values are multiplied
<div ng-app ng-init="qty=1;cost=2">
<b>Invoice:</b>
<div>
Quantity: <input type="number" ng-model="qty" required >
Quantity: <input type="number" ng-model="qty">
</div>
<div>
Costs: <input type="number" ng-model="cost" required >
Costs: <input type="number" ng-model="cost">
</div>
<div>
<b>Total:</b> {{qty * cost | currency}}
@@ -55,22 +56,19 @@ 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`}
element that adds extra behavior to the element. E.g. it is able to automatically validate that the entered
text is non empty by evaluating the `required` attribute.
The {@link ng.directive:ngModel `ng-model`} directive stores/updates
the value of the input field into/from a variable and shows the validation state of the input field by
adding css classes. In the example we use these css classes to mark an empty input field with a red border.
element that adds extra behavior to the element. The {@link ng.directive:ngModel `ng-model`} directive
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>
@@ -91,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>.
@@ -152,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.
@@ -265,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.
@@ -323,7 +321,7 @@ The following example shows how this is done with Angular:
angular.module('finance3', [])
.factory('currencyConverter', ['$http', function($http) {
var YAHOO_FINANCE_URL_PATTERN =
'http://query.yahooapis.com/v1/public/yql?q=select * from '+
'//query.yahooapis.com/v1/public/yql?q=select * from '+
'yahoo.finance.xchange where pair in ("PAIRS")&format=json&'+
'env=store://datatables.org/alltableswithkeys&callback=JSON_CALLBACK';
var currencies = ['USD', 'EUR', 'CNY'];
+2 -1
View File
@@ -1,5 +1,6 @@
@ngdoc overview
@name Controllers
@sortOrder 220
@description
# Understanding Controllers
@@ -325,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
View File
@@ -1,5 +1,6 @@
@ngdoc overview
@name Working With CSS
@sortOrder 510
@description
+1
View File
@@ -1,5 +1,6 @@
@ngdoc overview
@name Data Binding
@sortOrder 210
@description
Data-binding in Angular apps is the automatic synchronization of data between the model and view
+7 -6
View File
@@ -1,5 +1,6 @@
@ngdoc overview
@name Dependency Injection
@sortOrder 250
@description
# Dependency Injection
@@ -109,7 +110,7 @@ asks the injector to create an instance of the controller and its dependencies.
injector.instantiate(MyController);
```
This is all done behinds the scenes. Notice that by having the `ng-controller` ask the injector to
This is all done behind the scenes. Notice that by having the `ng-controller` ask the injector to
instantiate the class, it can satisfy all of the dependencies of `MyController` without the
controller ever knowing about the injector.
@@ -135,7 +136,7 @@ These can be used interchangeably as you see fit and are equivalent.
### Implicit Dependencies
The simplest way to get hold of the dependencies, is to assume that the function parameter names
The simplest way to get hold of the dependencies is to assume that the function parameter names
are the names of the dependencies.
```js
@@ -144,7 +145,7 @@ function MyController($scope, greeter) {
}
```
Given a function the injector can infer the names of the service to inject by examining the
Given a function the injector can infer the names of the services to inject by examining the
function declaration and extracting the parameter names. In the above example `$scope`, and
`greeter` are two services which need to be injected into the function.
@@ -154,7 +155,7 @@ rename the method parameter names. This makes this way of annotating only useful
### `$inject` Property Annotation
To allow the minifiers to rename the function parameters and still be able to inject right services,
To allow the minifiers to rename the function parameters and still be able to inject the right services,
the function needs to be annotated with the `$inject` property. The `$inject` property is an array
of service names to inject.
@@ -166,7 +167,7 @@ MyController['$inject'] = ['$scope', 'greeter'];
```
In this scenario the ordering of the values in the `$inject` array must match the ordering of the
arguments to inject. Using above code snippet as an example, `$scope` will be injected into
arguments to inject. Using the above code snippet as an example, `$scope` will be injected into
`renamed$scope` and `greeter` into `renamedGreeter`. Care must be taken that the `$inject`
annotation is kept in sync with the actual arguments in the function declaration.
@@ -206,7 +207,7 @@ someModule.factory('greeter', ['$window', function(renamed$window) {
}]);
```
Here, instead of simply providing the factory function, we pass an array, whose elements consist of
Here, instead of simply providing the factory function, we pass an array whose elements consist of
a list of strings (the names of the dependencies) followed by the function itself.
Keep in mind that all of the annotation styles are equivalent and can be used anywhere in Angular
+28 -4
View File
@@ -1,5 +1,6 @@
@ngdoc overview
@name Directives
@sortOrder 300
@description
# Creating Custom Directives
@@ -159,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).
@@ -352,7 +353,7 @@ element as a customer component.
Our `myCustomer` directive above is great, but it has a fatal flaw. We can only use it once within a
given scope.
In its current implementation, we'd need to create a different controller each time In order to
In its current implementation, we'd need to create a different controller each time in order to
re-use such a directive:
<example module="docsScopeProblemExample">
@@ -475,7 +476,6 @@ within our directive's template:
angular.module('docsIsolationExample', [])
.controller('Controller', ['$scope', function($scope) {
$scope.naomi = { name: 'Naomi', address: '1600 Amphitheatre' };
$scope.vojta = { name: 'Vojta', address: '3456 Somewhere Else' };
}])
.directive('myCustomer', function() {
@@ -537,7 +537,7 @@ where:
In our `link` function, we want to update the displayed time once a second, or whenever a user
changes the time formatting string that our directive binds to. We will use the `$interval` service
to call a handler on a regular basis. This is easier than using `$timeout` but also works better with
end-to-end testing, where we want to ensure that all $timeouts have completed before completing the test.
end-to-end testing, where we want to ensure that all `$timeout`s have completed before completing the test.
We also want to remove the `$interval` if the directive is deleted so we don't introduce a memory leak.
<example module="docsTimeDirective">
@@ -910,6 +910,30 @@ Looking back at `myPane`'s definition, notice the last argument in its `link` fu
When a directive requires a controller, it receives that controller as the fourth argument of its
`link` function. Taking advantage of this, `myPane` can call the `addPane` function of `myTabs`.
If multiple controllers are required, the `require` option of the directive can take an array argument.
The corresponding parameter being sent to the `link` function will also be an array.
```js
angular.module('docsTabsExample', [])
.directive('myPane', function() {
return {
require: ['^myTabs', '^ngModel'],
restrict: 'E',
transclude: true,
scope: {
title: '@'
},
link: function(scope, element, attrs, controllers) {
var tabsCtrl = controllers[0],
modelCtrl = controllers[1];
tabsCtrl.addPane(scope);
},
templateUrl: 'my-pane.html'
};
});
```
Savvy readers may be wondering what the difference is between `link` and `controller`.
The basic difference is that `controller` can expose an API, and `link` functions can interact with
controllers using `require`.
+3 -3
View File
@@ -1,6 +1,6 @@
@workInProgress
@ngdoc overview
@name E2E Testing
@sortOrder 420
@description
# E2E Testing
@@ -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
+4 -1
View File
@@ -1,5 +1,6 @@
@ngdoc overview
@name Expressions
@sortOrder 270
@description
# Angular Expressions
@@ -38,7 +39,9 @@ the method from your view. If you want to `eval()` an Angular expression yoursel
## Example
<example>
<file name="index.html">
1+2={{1+2}}
<span>
1+2={{1+2}}
</span>
</file>
<file name="protractor.js" type="protractor">
+1
View File
@@ -1,5 +1,6 @@
@ngdoc overview
@name Filters
@sortOrder 280
@description
A filter formats the value of an expression for display to the user. They can be used in view templates,
+3 -2
View File
@@ -1,5 +1,6 @@
@ngdoc overview
@name Forms
@sortOrder 290
@description
Controls (`input`, `select`, `textarea`) are ways for a user to enter data.
@@ -134,7 +135,7 @@ This allows us to extend the above example with these features:
<example module="formExample">
<file name="index.html">
<div ng-controller="Controller">
<div ng-controller="ExampleController">
<form name="form" class="css-form" novalidate>
Name:
<input type="text" ng-model="user.name" name="uName" required /><br />
@@ -205,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`.
+1
View File
@@ -1,5 +1,6 @@
@ngdoc overview
@name i18n and l10n
@sortOrder 520
@description
# i18n and l10n
+1
View File
@@ -1,5 +1,6 @@
@ngdoc overview
@name Internet Explorer Compatibility
@sortOrder 530
@description
# Internet Explorer Compatibility

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