Compare commits

...

75 Commits

Author SHA1 Message Date
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
131 changed files with 1493 additions and 776 deletions
+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
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 -2
View File
@@ -24,8 +24,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/fetch_bundle.sh
- time npm install
before_script:
- mkdir -p $LOGS_DIR
+182
View File
@@ -1,4 +1,186 @@
<a name="1.3.0-beta.16"></a>
# 1.3.0-beta.16 pizza-transubstantiation (2014-07-18)
## Bug Fixes
- **$cookie:** use `decodeURIComponent` instead of unescape for cookie reading
([1c9ab40d](https://github.com/angular/angular.js/commit/1c9ab40d286ffdb1b41d30ca8d861b53175bfc24),
[#8125](https://github.com/angular/angular.js/issues/8125))
- **$http:** fix double-quoted date issue when encoding params
([9dce42b3](https://github.com/angular/angular.js/commit/9dce42b3c26eb02621723172a68725980369b849),
[#8150](https://github.com/angular/angular.js/issues/8150), [#6128](https://github.com/angular/angular.js/issues/6128), [#8154](https://github.com/angular/angular.js/issues/8154))
- **$location:** handle plus character in query strings
([3f4ee151](https://github.com/angular/angular.js/commit/3f4ee1513901f55d6007e3fc3948458adf4ac656),
[#3042](https://github.com/angular/angular.js/issues/3042))
- **$rootScope:**
- `$watchCollection` should handle `NaN` in objects
([db9f2570](https://github.com/angular/angular.js/commit/db9f2570c18d77d0e51d5a7afa139d25d0bdc470),
[#7930](https://github.com/angular/angular.js/issues/7930))
- remove support for a watch action to be a string
([02c0ed27](https://github.com/angular/angular.js/commit/02c0ed27bc375d5352fefdd7e34aad9758621283),
[#8190](https://github.com/angular/angular.js/issues/8190))
- **csp:** fix autodetection of CSP + better docs
([0113f225](https://github.com/angular/angular.js/commit/0113f2257415422729d5c2a9bdba76c1d0a17a13),
[#8162](https://github.com/angular/angular.js/issues/8162), [#8191](https://github.com/angular/angular.js/issues/8191))
- **ngList:** use custom separators for re-joining list items
([c6c9d26e](https://github.com/angular/angular.js/commit/c6c9d26e3487ce24ece390c26994123964f805b0),
[#4008](https://github.com/angular/angular.js/issues/4008), [#2561](https://github.com/angular/angular.js/issues/2561), [#4344](https://github.com/angular/angular.js/issues/4344))
- **ngRoute:** remove unnecessary call to `decodeURIComponent`
([528f56a6](https://github.com/angular/angular.js/commit/528f56a690295650f54eeb2238609446635c5db0),
[#6326](https://github.com/angular/angular.js/issues/6326), [#6327](https://github.com/angular/angular.js/issues/6327))
- **ngSanitize:** follow HTML parser rules for start tags / allow < in text content
([f6681d41](https://github.com/angular/angular.js/commit/f6681d41a493efa6566f8a8a0b6ec39547e572ef),
[#8212](https://github.com/angular/angular.js/issues/8212), [#8193](https://github.com/angular/angular.js/issues/8193))
- **ngSwitch:**
- interoperate with multi-element transclude directives
([c20d438a](https://github.com/angular/angular.js/commit/c20d438ac9b9757331d096969a73c782c38e098a),
[#8235](https://github.com/angular/angular.js/issues/8235), [#8244](https://github.com/angular/angular.js/issues/8244))
- use the correct transclusion scope
([4f32e3ee](https://github.com/angular/angular.js/commit/4f32e3eef152bcaab7f7ab151fc824e71a591473),
[#8235](https://github.com/angular/angular.js/issues/8235))
- **orderBy:** correctly order by date values
([92bceb5c](https://github.com/angular/angular.js/commit/92bceb5c5b6e4a5a8fee01e1e0dfcf4674858cf2),
[#6675](https://github.com/angular/angular.js/issues/6675), [#6746](https://github.com/angular/angular.js/issues/6746))
- **select:** force visual update in IE
([d7f73022](https://github.com/angular/angular.js/commit/d7f730228d58d3a409846e64ba5d0120356691cc),
[#7692](https://github.com/angular/angular.js/issues/7692), [#8158](https://github.com/angular/angular.js/issues/8158))
## Features
- **$compile:** explicitly request multi-element directive behaviour
([e8066c4b](https://github.com/angular/angular.js/commit/e8066c4b4ce11496b0d8f39e41b4d753048bca2d),
[#5372](https://github.com/angular/angular.js/issues/5372), [#6574](https://github.com/angular/angular.js/issues/6574), [#5370](https://github.com/angular/angular.js/issues/5370), [#8044](https://github.com/angular/angular.js/issues/8044), [#7336](https://github.com/angular/angular.js/issues/7336))
- **ngList:** use ngTrim to manage whitespace handling when splitting
([8d18d20e](https://github.com/angular/angular.js/commit/8d18d20e316ed9d420f09f46f90027aef2940930))
- **ngTransclude:** allow ngTransclude to be used as an element
([3dafcba9](https://github.com/angular/angular.js/commit/3dafcba9c1738b85f3adceaac90b747a1b595ea8),
[#8141](https://github.com/angular/angular.js/issues/8141))
## Performance Improvements
- **$compile:** only create jqLite object when necessary
([a160f76f](https://github.com/angular/angular.js/commit/a160f76ffa9544cd2ed99f24ba65b5994108f9f5))
- **bindOnce** more performant interpolation and lazy one-time binding
([86d55c1d](https://github.com/angular/angular.js/commit/86d55c1ded21a5be6091344493d70c6dc4194e43))
- **jqLite:** expose the low-level jqLite.data/removeData calls
([e4ba8943](https://github.com/angular/angular.js/commit/e4ba89436aa0b96f126ce2c23d0c7f7c785573fe))
- **ngBindHtml:** move addClass to the compile phase
([903e7352](https://github.com/angular/angular.js/commit/903e7352c9943e4d3757dd1cff58178d4c5375d6),
[#8261](https://github.com/angular/angular.js/issues/8261))
## Breaking Changes
- **$compile:** due to [e8066c4b](https://github.com/angular/angular.js/commit/e8066c4b4ce11496b0d8f39e41b4d753048bca2d),
Directives which previously depended on the implicit grouping between
directive-start and directive-end attributes must be refactored in order to see this same behaviour.
Before:
```html
<div data-fancy-directive-start>{{start}}</div>
<p>Grouped content</p>
<div data-fancy-directive-end>{{end}}</div>
```
```javascript
.directive('fancyDirective', function() {
return {
link: angular.noop
};
})
```
After:
```html
<div data-fancy-directive-start>{{start}}</div>
<p>Grouped content</p>
<div data-fancy-directive-end>{{end}}</div>
```
```javascript
.directive('fancyDirective', function() {
return {
multiElement: true, // Explicitly mark as a multi-element directive.
link: angular.noop
};
})
```
Closes #5372
Closes #6574
Closes #5370
Closes #8044
Closes #7336
- **$rootScope:** due to [02c0ed27](https://github.com/angular/angular.js/commit/02c0ed27bc375d5352fefdd7e34aad9758621283),
Previously, it was possible for an action passed to $watch
to be a string, interpreted as an angular expresison. This is no longer supported.
The action now has to be a function.
Passing an action to $watch is still optional.
Before:
```javascript
$scope.$watch('state', ' name="" ');
```
After:
```javascript
$scope.$watch('state', function () {
$scope.name = "";
});
```
Closes #8190
- **bootstrap:** due to [666a3835](https://github.com/angular/angular.js/commit/666a3835d231b3f77f907276be18b3c0086e5d12),
If using any of the mechanisms specified above, then migrate by
specifying the attribute `ng-app` to the root element. E.g.
```html
<div ng-app="module">...</div>
```
Closes #8147
- **ngList:** due to [c6c9d26e](https://github.com/angular/angular.js/commit/c6c9d26e3487ce24ece390c26994123964f805b0),
The `ngList` directive no longer supports splitting the view value
via a regular expression. We need to be able to re-join list items back
together and doing this when you can split with regular expressions can
lead to inconsistent behaviour and would be much more complex to support.
If your application relies upon ngList splitting with a regular expression
then you should either try to convert the separator to a simple string or
you can implement your own version of this directive for you application.
Closes #4008
Closes #2561
Closes #4344
- **ngSwitch:** due to [4f32e3ee](https://github.com/angular/angular.js/commit/4f32e3eef152bcaab7f7ab151fc824e71a591473),
** Directive Priority Changed ** - this commit changes the priority
of `ngSwitchWhen` and `ngSwitchDefault` from `800` to `1200`. This makes their
priority higher than `ngRepeat`, which allows items to be repeated on
the switch case element reliably.
In general your directives should have a lower priority than these directives
if you want them to exist inside the case elements. If you relied on the
priority of these directives then you should check that your code still
operates correctly.
Closes #8235
<a name="1.3.0-beta.15"></a>
# 1.3.0-beta.15 unbelievable-advancement (2014-07-11)
+2 -2
View File
@@ -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):
@@ -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 + '/'
}
},
+4 -4
View File
@@ -44,11 +44,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
@@ -61,9 +61,9 @@ This process based on the idea of minimizing user pain
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',
+4 -2
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');
@@ -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() {
+5 -1
View File
@@ -1,3 +1,7 @@
/* global describe: 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');
});
+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;
});
+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;
+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);
}
+1 -1
View File
@@ -20,4 +20,4 @@ angular.module('docsApp', [
.config(function($locationProvider) {
$locationProvider.html5Mode(true).hashPrefix('!');
});
});
+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);
});
};
}]);
}]);
+1 -1
View File
@@ -21,4 +21,4 @@ angular.module('docsApp.navigationService', [])
}
};
});
});
+19 -3
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];
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.docs_versions = NG_VERSIONS;
$scope.getGroupName = function(v) {
return v.isLatest ? 'Latest' : (v.isStable ? 'Stable' : 'Unstable');
};
$scope.jumpToDocsVersion = function(version) {
var currentPagePath = $location.path();
// TODO: We need to do some munging of the path for different versions of the API...
$window.location = version.docsUrl + currentPagePath;
};
}]);
}]);
+1 -1
View File
@@ -31,4 +31,4 @@ describe("DocsController", function() {
expect($window._gaq.pop()).toEqual(['_trackPageview', 'x/y/z']);
}));
});
});
});
+1 -1
View File
@@ -9,7 +9,7 @@ module.exports = function(config) {
config = basePackage(config);
config = examplesPackage(config);
config.append('processing.processors', [
require('./processors/git-data'),
require('./processors/error-docs'),
+1 -1
View File
@@ -30,4 +30,4 @@ function writeFile(file, content) {
return fs.makeTree(fs.directory(file)).then(function() {
return fs.write(file, content, 'wb');
});
}
}
+1 -1
View File
@@ -56,4 +56,4 @@ module.exports = {
return docs.concat(_.values(errorNamespaces));
}
};
};
+1 -1
View File
@@ -17,4 +17,4 @@ module.exports = {
process: function(extraData, gitData) {
extraData.git = gitData;
}
};
};
+1 -1
View File
@@ -85,4 +85,4 @@ module.exports = {
});
}
};
};
+1 -1
View File
@@ -35,4 +35,4 @@ module.exports = {
docs.push(versionDoc);
}
};
};
+1 -1
View File
@@ -14,4 +14,4 @@
{$ doc.description | marked $}
</div>
{% endblock %}
{% endblock %}
@@ -25,4 +25,4 @@
</div>
</div>
{% endblock %}
{% endblock %}
@@ -175,7 +175,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">
@@ -4,4 +4,4 @@ describe("{$ doc.description $}", function() {
});
{$ doc.innerTest $}
});
});
@@ -24,4 +24,4 @@
</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' %}
+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.
+1 -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.
@@ -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.
+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.
+286 -96
View File
@@ -358,118 +358,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 -1
View File
@@ -90,7 +90,7 @@ Here is an example of manually initializing Angular:
<!doctype html>
<html>
<body>
Hello {{'World'}}!
Hello {{greetMe}}!
<script src="http://code.angularjs.org/snapshot/angular.js"></script>
<script>
+1 -1
View File
@@ -198,7 +198,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);
```
+5 -8
View File
@@ -37,10 +37,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}}
@@ -62,11 +62,8 @@ The first kind of new markup are the so called <a name="directive">"{@link direc
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
@@ -323,7 +320,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 -3
View File
@@ -352,7 +352,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 +475,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 +536,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">
+1 -1
View File
@@ -134,7 +134,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 />
+27 -12
View File
@@ -45,6 +45,12 @@ I'm in a hurry. How do I get a Hello World module working?
};
});
</file>
<file name="protractor.js" type="protractor">
it('should add Hello to the name', function() {
expect(element(by.binding("{{ 'World' | greet }}")).getText()).toEqual('Hello, World!');
});
</file>
</example>
Important things to notice:
@@ -75,13 +81,14 @@ The above is a suggestion. Tailor it to your needs.
<example module='xmpl'>
<file name="index.html">
<div ng-controller="XmplController">
{{ greeting }}!
{{ greeting }}
</div>
</file>
<file name="script.js">
angular.module('xmpl.service', []).
value('greeter', {
angular.module('xmpl.service', [])
.value('greeter', {
salutation: 'Hello',
localize: function(localization) {
this.salutation = localization.salutation;
@@ -89,8 +96,9 @@ The above is a suggestion. Tailor it to your needs.
greet: function(name) {
return this.salutation + ' ' + name + '!';
}
}).
value('user', {
})
.value('user', {
load: function(name) {
this.name = name;
}
@@ -100,21 +108,28 @@ The above is a suggestion. Tailor it to your needs.
angular.module('xmpl.filter', []);
angular.module('xmpl', ['xmpl.service', 'xmpl.directive', 'xmpl.filter']).
run(function(greeter, user) {
angular.module('xmpl', ['xmpl.service', 'xmpl.directive', 'xmpl.filter'])
.run(function(greeter, user) {
// This is effectively part of the main method initialization code
greeter.localize({
salutation: 'Bonjour'
});
user.load('World');
})
.controller('XmplController', function($scope, greeter, user){
$scope.greeting = greeter.greet(user.name);
});
// A Controller for your app
var XmplController = function($scope, greeter, user) {
$scope.greeting = greeter.greet(user.name);
};
</file>
<file name="protractor.js" type="protractor">
it('should add Hello to the name', function() {
expect(element(by.binding("{{ greeting }}")).getText()).toEqual('Bonjour World!');
});
</file>
</example>
+4 -3
View File
@@ -132,9 +132,11 @@ In the code above, we see how the `apiToken` service is defined via the Factory
on the `clientId` service. The factory service then uses NSA-proof encryption to produce an authentication
token.
Note: It is best practice to name the factory functions as `<serviceId>Factory`
<div class="alert alert-success">
**Best Practice:** name the factory functions as `<serviceId>Factory`
(e.g. apiTokenFactory). While this naming convention is not required, it helps when navigating the code base
or looking at stack traces in the debugger.
</div>
Just like with Value recipe, Factory recipe can create a service of any type, whether it be a
primitive, object literal, function, or even an instance of a custom type.
@@ -193,8 +195,7 @@ that would mess with the teachers.
## Provider Recipe
There are two more recipe types left to cover. They are both fairly specialized and are used
infrequently. As already mentioned in the intro, the Provider recipe is the core recipe type and
As already mentioned in the intro, the Provider recipe is the core recipe type and
all the other recipe types are just syntactic sugar on top of it. It is the most verbose recipe
with the most abilities, but for most services it's overkill.
+1 -1
View File
@@ -113,7 +113,7 @@ may have several child scopes.
The application can have multiple scopes, because some {@link guide/directive directives} create
new child scopes (refer to directive documentation to see which directives create new scopes).
When new scopes are created, they are added as children of their parent scope. This creates a tree
structure which parallels the DOM where they're attached
structure which parallels the DOM where they're attached.
When Angular evaluates `{{name}}`, it first looks at the scope associated with the given
element for the `name` property. If no such property is found, it searches the parent scope
+74
View File
@@ -337,6 +337,80 @@ We inject the $compile service and $rootScope before each jasmine test. The $com
to render the aGreatEye directive. After rendering the directive we ensure that the directive has
replaced the content and "lidless, wreathed in flame, 2 times" is present.
### Testing Transclusion Directives
Directives that use transclusion are treated specially by the compiler. Before their compile
function is called, the contents of the directive's element are removed from the element and
provided via a transclusion function. The directive's template is then appended to the directive's
element, to which it can then insert the transcluded content into its template.
Before compilation:
```html
<div translude-directive>
Some transcluded content
</div>
```
After transclusion extraction:
```html
<div transclude-directive></div>
```
After compilation:
```html
<div transclude-directive>
Some Template
<span ng-transclude>Some transcluded content</span>
</div>
```
If the directive is using 'element' transclusion, the compiler will actually remove the
directive's entire element from the DOM and replace it with a comment node. The compiler then
inserts the directive's template "after" this comment node, as a sibling.
Before compilation
```html
<div element-transclude>
Some Content
</div>
```
After transclusion extraction
```html
<!-- elementTransclude -->
```
After compilation:
```html
<!-- elementTransclude -->
<div element-transclude>
Some Template
<span ng-transclude>Some transcluded content</span>
</div>
```
It is important to be aware of this when writing tests for directives that use 'element'
transclusion. If you place the directive on the root element of the DOM fragment that you
pass to {@link $compile}, then the DOM node returned from the linking function will be the
comment node and you will lose the ability to access the template and transcluded content.
```javascript
var node = $compile('<div element-transclude></div>')($rootScope);
expect(node[0].nodeType).toEqual(node.COMMENT_NODE);
expect(node[1]).toBeUndefined();
```
To cope with this you simply ensure that your 'element' transclude directive is wrapped in an
element, such as a `<div>`.
```javascript
var node = $compile('<div><div element-transclude></div></div>')($rootScope);
var contents = node.contents();
expect(contents[0].nodeType).toEqual(node.COMMENT_NODE);
expect(contents[1].nodeType).toEqual(node.ELEMENT_NODE);
```
### Testing Directives With External Templates
If your directive uses `templateUrl`, consider using
+1 -1
View File
@@ -83,4 +83,4 @@ after the core `angular.js` file:
our docs, or even more importantly, view the docs offline.
* __`i18n`__ - this directory contains locale specific `ngLocale` angular modules to override the defaults
defined in the `ng` module.
defined in the `ng` module.
+2 -2
View File
@@ -16,7 +16,7 @@ Because HTML has Angular brackets and "ng" sounds like "Angular".
AngularJS fits the definition of a framework the best, even though it's much more lightweight than
a typical framework and that's why many confuse it with a library.
AngularJS is 100% JavaScript, 100% client side and compatible with both desktop and mobile browsers.
AngularJS is 100% JavaScript, 100% client-side and compatible with both desktop and mobile browsers.
So it's definitely not a plugin or some other native browser extension.
@@ -114,7 +114,7 @@ make our schwag will be happy to do a custom run for you, based on our existing
they'll waive the setup costs, and you can order any quantity you need.
**Stickers**
For orders of 250 stickers or more within Canada or the United States, contact Tom Witting (or anyone in sales) via email at tom@stickergiant.com, and tell him you want to order some AngularJS
For orders of 250 stickers or more within Canada or the United States, contact Tom Witting (or anyone in sales) via email at <tom@stickergiant.com>, and tell him you want to order some AngularJS
stickers just like the ones in job #42711. You'll have to give them your own info for billing and shipping.
As long as the design stays exactly the same, [StickerGiant](http://www.stickergiant.com) will give you a reorder discount.
+1 -1
View File
@@ -31,7 +31,7 @@ npm install
To see the app running in a browser, open a *separate* terminal/command line tab or window, then
run `npm start` to start the web server. Now, open a browser window for the app and navigate to
<a href="http://localhost:8000/app/index.html" target="_blank">`http://localhost:8000/app/index.html`</a>
<a href="http://localhost:8000/app/" target="_blank">`http://localhost:8000/app/`</a>
You can now see the page in your browser. It's not very exciting, but that's OK.
+6 -1
View File
@@ -65,6 +65,11 @@ __controller__ to the DOM at this point:
bindings, which are referring to our application model, which is set up in our `PhoneListCtrl`
controller.
<div class="alert alert-info">
Note: We have specified an {@link angular.Module Angular Module} to load using `ng-app="phonecatApp"`,
where `phonecatApp` is the name of our module. This module will contain the `PhoneListCtrl`.
</div>
<img class="diagram" src="img/tutorial/tutorial_02.png">
## Model and Controller
@@ -255,4 +260,4 @@ to the app.
[jasmine]: http://jasmine.github.io/
[jasmine-docs]: http://jasmine.github.io/1.3/introduction.html
[karma]: http://karma-runner.github.io/
[karma]: http://karma-runner.github.io/
+3 -1
View File
@@ -128,7 +128,9 @@ will exit after the test run and will not automatically rerun the test suite on
To rerun the test suite, execute `npm run protractor` again.
<div class="alert alert-info">
Note: You must ensure you've installed the protractor and updated webdriver prior to running the
Note: You must ensure your application is being served via a web-server to test with protractor.
You can do this using `npm start`.
You also need to ensure you've installed the protractor and updated webdriver prior to running the
`npm run protractor`. You can do this by issuing `npm install` and `npm run update-webdriver` into
your terminal.
</div>
+1 -1
View File
@@ -73,7 +73,7 @@ __`test/e2e/scenarios.js`__:
it('should render phone specific links', function() {
var query = element(by.model('query'));
query.sendKeys('nexus');
element(by.css('.phones li a')).click();
element.all(by.css('.phones li a')).first().click();
browser.getLocationAbsUrl().then(function(url) {
expect(url.split('#')[1]).toBe('/phones/nexus-s');
});
+4 -4
View File
@@ -80,14 +80,14 @@ AngularJS, so it's important for you to understand a thing or two about how it w
When the application bootstraps, Angular creates an injector that will be used to find and inject all
of the services that are required by your app. The injector itself doesn't know anything about what
`$http` or `$route` services do, in fact it doesn't even know about the existence of these services
unless it is configured with proper module definitions.
`$http` or `$route` services do, in fact it doesn't even know about the existence of these services
unless it is configured with proper module definitions.
The injector only carries out the following steps :
The injector only carries out the following steps :
* load the module definition(s) that you specify in your app
* register all Providers defined in these module definitions
* when asked to do so, inject a specified function and any necessary dependencies (services) that
* when asked to do so, inject a specified function and any necessary dependencies (services) that
it lazily instantiates via their Providers.
Providers are objects that provide (create) instances of services and expose configuration APIs
+1 -1
View File
@@ -120,7 +120,7 @@ You should now see the following output in the Karma tab:
# Experiments
* Let's experiment with some of the {@link ng.$filterProvider built-in Angular filters} and add the
* Let's experiment with some of the {@link api/ng/filter built-in Angular filters} and add the
following bindings to `index.html`:
* `{{ "lower cap string" | uppercase }}`
* `{{ {foo: "bar", baz: 23} | json }}`
+86 -81
View File
@@ -1,5 +1,7 @@
#!/usr/bin/env node
'use strict';
var http = require('http');
var https = require('https');
var fs = require('fs');
@@ -41,63 +43,63 @@ function help() {
console.log('gdocs.js --login <username>');
console.log('gdocs.js --fetch [<docs collection>]');
process.exit(-1);
};
}
function fetch(collection, url){
console.log('fetching a list of docs in collection ' + collection + '...');
request('GET', url, {
headers: {
'Gdata-Version': '3.0',
'Authorization': 'GoogleLogin auth=' + getAuthToken()
}
},
function(chunk){
var entries = chunk.split('<entry');
entries.shift();
entries.forEach(function(entry){
var title = entry.match(/<title>(.*?)<\/title>/)[1];
if (title.match(/\.ngdoc$/)) {
var exportUrl = entry.match(/<content type='text\/html' src='(.*?)'\/>/)[1];
download(collection, title, exportUrl);
};
});
headers: {
'Gdata-Version': '3.0',
'Authorization': 'GoogleLogin auth=' + getAuthToken()
}
);
},
function(chunk){
var entries = chunk.split('<entry');
entries.shift();
entries.forEach(function(entry){
var title = entry.match(/<title>(.*?)<\/title>/)[1];
if (title.match(/\.ngdoc$/)) {
var exportUrl = entry.match(/<content type='text\/html' src='(.*?)'\/>/)[1];
download(collection, title, exportUrl);
}
});
}
);
}
function download(collection, name, url) {
console.log('Downloading:', name, '...');
request('GET', url + '&exportFormat=txt',
{
headers: {
'Gdata-Version': '3.0',
'Authorization': 'GoogleLogin auth=' + getAuthToken()
}
},
function(data){
data = data.replace('\ufeff', '');
data = data.replace(/\r\n/mg, '\n');
// strip out all text annotations
data = data.replace(/\[[a-zA-Z]{1,2}\]/mg, '');
// strip out all docos comments
data = data.replace(/^[^\s_]+:\n\S+[\S\s]*$/m, '');
// fix smart-quotes
data = data.replace(/[“”]/g, '"');
data = data.replace(/[‘’]/g, "'");
data = data + '\n';
//this should be a bug in Google Doc API, hence need to remove this once the bug is fixed
data = data.replace(/\n\n/g, '\n');
fs.writeFileSync('docs/content/' + collection + '/' + name, reflow(data, 100));
{
headers: {
'Gdata-Version': '3.0',
'Authorization': 'GoogleLogin auth=' + getAuthToken()
}
);
},
function(data){
data = data.replace('\ufeff', '');
data = data.replace(/\r\n/mg, '\n');
// strip out all text annotations
data = data.replace(/\[[a-zA-Z]{1,2}\]/mg, '');
// strip out all docos comments
data = data.replace(/^[^\s_]+:\n\S+[\S\s]*$/m, '');
// fix smart-quotes
data = data.replace(/[“”]/g, '"');
data = data.replace(/[‘’]/g, "'");
data = data + '\n';
//this should be a bug in Google Doc API, hence need to remove this once the bug is fixed
data = data.replace(/\n\n/g, '\n');
fs.writeFileSync('docs/content/' + collection + '/' + name, reflow(data, 100));
}
);
}
/**
@@ -111,34 +113,34 @@ function download(collection, name, url) {
*/
function login(username, password){
request('POST', 'https://www.google.com/accounts/ClientLogin',
{
data: {
Email: username,
Passwd: password,
accountType: 'GOOGLE',
service: 'writely',
'Gdata-version': '3.0'
},
headers: {
'Content-type': 'application/x-www-form-urlencoded'
}
{
data: {
Email: username,
Passwd: password,
accountType: 'GOOGLE',
service: 'writely',
'Gdata-version': '3.0'
},
function(chunk){
var token;
chunk.split('\n').forEach(function(line){
var parts = line.split('=');
if (parts[0] == 'Auth') {
token = parts[1];
}
});
if (token) {
fs.writeFileSync('tmp/gdocs.auth', token);
console.log("logged in, token saved in 'tmp/gdocs.auth'");
} else {
console.log('failed to log in');
}
headers: {
'Content-type': 'application/x-www-form-urlencoded'
}
);
},
function(chunk){
var token;
chunk.split('\n').forEach(function(line){
var parts = line.split('=');
if (parts[0] == 'Auth') {
token = parts[1];
}
});
if (token) {
fs.writeFileSync('tmp/gdocs.auth', token);
console.log("logged in, token saved in 'tmp/gdocs.auth'");
} else {
console.log('failed to log in');
}
}
);
}
function getAuthToken() {
@@ -152,17 +154,18 @@ function getAuthToken() {
}
function request(method, url, options, response) {
var url = url.match(/http(s?):\/\/(.+?)(\/.*)/);
url = url.match(/http(s?):\/\/(.+?)(\/.*)/);
var isHttps = url[1];
var request = (isHttps ? https : http).request({
var req = (isHttps ? https : http).request({
host: url[2],
port: (url[1] ? 443 : 80),
path: url[3],
method: method
}, function(res){
var data;
switch (res.statusCode) {
case 200:
var data = [];
data = [];
res.setEncoding('utf8');
res.on('end', function () { response(data.join('')); });
res.on('close', function () { response(data.join('')); }); // https
@@ -173,7 +176,7 @@ function request(method, url, options, response) {
console.log('Eror: Login credentials expired! Please login.');
break;
default:
var data = [];
data = [];
console.log('ERROR: ', res.statusCode);
console.log('REQUEST URL: ', url[0]);
console.log('REQUEST POST: ', options.data);
@@ -186,14 +189,14 @@ function request(method, url, options, response) {
}
});
for(var header in options.headers) {
request.setHeader(header, options.headers[header]);
req.setHeader(header, options.headers[header]);
}
if (options.data)
request.write(encodeData(options.data));
request.on('end', function() {
req.write(encodeData(options.data));
req.on('end', function() {
console.log('end');
});
request.end();
req.end();
}
function encodeData(obj) {
@@ -215,7 +218,9 @@ function askPassword(callback) {
stdin.on("data", function(c) {
c = c + "";
switch (c) {
case "\n": case "\r": case "\u0004":
case "\n":
case "\r":
case "\u0004":
stdio.setRawMode(false);
stdin.pause();
callback(password);
@@ -227,7 +232,7 @@ function askPassword(callback) {
password += c;
break;
}
})
});
}
+2
View File
@@ -1,3 +1,5 @@
'use strict';
var sharedConfig = require('./karma-shared.conf');
module.exports = function(config) {
+3 -6
View File
@@ -1,3 +1,5 @@
'use strict';
var angularFiles = require('./angularFiles');
var sharedConfig = require('./karma-shared.conf');
@@ -5,12 +7,7 @@ module.exports = function(config) {
sharedConfig(config, {testName: 'AngularJS: jqLite', logFile: 'karma-jqlite.log'});
config.set({
files: angularFiles.mergeFilesFor('karma').concat({
pattern: "test/fixtures/**/*.html",
served: true,
watched: true,
included: false
}),
files: angularFiles.mergeFilesFor('karma'),
exclude: angularFiles.mergeFilesFor('karmaExclude'),
junitReporter: {
+3 -6
View File
@@ -1,3 +1,5 @@
'use strict';
var angularFiles = require('./angularFiles');
var sharedConfig = require('./karma-shared.conf');
@@ -5,12 +7,7 @@ module.exports = function(config) {
sharedConfig(config, {testName: 'AngularJS: jQuery', logFile: 'karma-jquery.log'});
config.set({
files: angularFiles.mergeFilesFor('karmaJquery').concat({
pattern: "test/fixtures/**/*.html",
served: true,
watched: true,
included: false
}),
files: angularFiles.mergeFilesFor('karmaJquery'),
exclude: angularFiles.mergeFilesFor('karmaJqueryExclude'),
junitReporter: {
+2
View File
@@ -1,3 +1,5 @@
'use strict';
var angularFiles = require('./angularFiles');
var sharedConfig = require('./karma-shared.conf');
+3 -1
View File
@@ -1,3 +1,5 @@
'use strict';
module.exports = function(config, specificOptions) {
config.set({
frameworks: ['jasmine'],
@@ -170,7 +172,7 @@ module.exports = function(config, specificOptions) {
// ignore web-server's 404s
if (log.categoryName === 'web-server' && log.level.levelStr === config.LOG_WARN &&
IGNORED_404.some(function(ignoredLog) {return msg.indexOf(ignoredLog) !== -1})) {
IGNORED_404.some(function(ignoredLog) {return msg.indexOf(ignoredLog) !== -1;})) {
return;
}
+2
View File
@@ -1,3 +1,5 @@
'use strict';
var fs = require('fs');
var http = require('http');
var BrowserStackTunnel = require('browserstacktunnel-wrapper');
+2
View File
@@ -1,3 +1,5 @@
'use strict';
var bower = require('bower');
var util = require('./utils.js');
var shelljs = require('shelljs');
+2
View File
@@ -1,3 +1,5 @@
'use strict';
var fs = require('fs');
var path = require('path');
var shell = require('shelljs');
@@ -1,4 +1,8 @@
var isFunction = function isFunction(value){return typeof value == 'function';}
/* global qFactory: false */
'use strict';
var isFunction = function isFunction(value){return typeof value == 'function';};
var isPromiseLike = function isPromiseLike(obj) {return obj && isFunction(obj.then);};
var $q = qFactory(process.nextTick, function noopExceptionHandler() {});
+5 -3
View File
@@ -1,10 +1,12 @@
'use strict';
var fs = require('fs');
var path = require('path');
var shell = require('shelljs');
var semver = require('semver');
var _ = require('lodash');
var currentPackage, previousVersions, cdnVersion;
var currentPackage, previousVersions, cdnVersion, gitRepoInfo;
/**
@@ -154,14 +156,14 @@ var getCdnVersion = function() {
}
return cdnVersion;
}, null);
}
};
/**
* Get the unstable snapshot version
* @return {SemVer} The snapshot version
*/
var getSnapshotVersion = function() {
version = _(previousVersions)
var version = _(previousVersions)
.filter(function(tag) {
return semver.satisfies(tag, currentPackage.branchVersion);
})
+68 -20
View File
@@ -502,7 +502,7 @@
}
},
"dgeni-packages": {
"version": "0.9.1",
"version": "0.9.6",
"dependencies": {
"lodash": {
"version": "2.4.1"
@@ -511,10 +511,13 @@
"version": "2.0.3"
},
"glob": {
"version": "3.2.9",
"version": "3.2.11",
"dependencies": {
"inherits": {
"version": "2.0.1"
},
"minimatch": {
"version": "0.2.14",
"version": "0.3.0",
"dependencies": {
"lru-cache": {
"version": "2.5.0"
@@ -523,9 +526,6 @@
"version": "1.0.0"
}
}
},
"inherits": {
"version": "2.0.1"
}
}
},
@@ -539,7 +539,7 @@
"version": "0.0.2"
},
"minimist": {
"version": "0.0.8"
"version": "0.0.10"
}
}
},
@@ -565,7 +565,7 @@
"version": "0.7.1"
},
"esprima": {
"version": "1.2.0"
"version": "1.2.2"
},
"change-case": {
"version": "2.1.1",
@@ -865,22 +865,22 @@
"version": "0.4.1"
},
"grunt-contrib-jshint": {
"version": "0.7.2",
"version": "0.10.0",
"dependencies": {
"jshint": {
"version": "2.3.0",
"version": "2.5.2",
"dependencies": {
"shelljs": {
"version": "0.1.4"
"version": "0.3.0"
},
"underscore": {
"version": "1.4.4"
"version": "1.6.0"
},
"cli": {
"version": "0.4.5",
"version": "0.6.3",
"dependencies": {
"glob": {
"version": "3.2.9",
"version": "3.2.11",
"dependencies": {
"inherits": {
"version": "2.0.1"
@@ -890,7 +890,7 @@
}
},
"minimatch": {
"version": "0.2.14",
"version": "0.3.0",
"dependencies": {
"lru-cache": {
"version": "2.5.0"
@@ -900,10 +900,58 @@
}
}
},
"htmlparser2": {
"version": "3.7.2",
"dependencies": {
"domhandler": {
"version": "2.2.0"
},
"domutils": {
"version": "1.5.0"
},
"domelementtype": {
"version": "1.1.1"
},
"readable-stream": {
"version": "1.1.13-1",
"dependencies": {
"core-util-is": {
"version": "1.0.1"
},
"isarray": {
"version": "0.0.1"
},
"string_decoder": {
"version": "0.10.25-1"
},
"inherits": {
"version": "2.0.1"
}
}
},
"entities": {
"version": "1.0.0"
}
}
},
"console-browserify": {
"version": "0.1.6"
"version": "1.1.0",
"dependencies": {
"date-now": {
"version": "0.1.4"
}
}
},
"exit": {
"version": "0.1.2"
},
"strip-json-comments": {
"version": "0.1.3"
}
}
},
"hooker": {
"version": "0.2.3"
}
}
},
@@ -2690,7 +2738,7 @@
}
},
"protractor": {
"version": "1.0.0-rc4",
"version": "1.0.0",
"dependencies": {
"request": {
"version": "2.36.0",
@@ -2714,7 +2762,7 @@
"version": "0.12.1",
"dependencies": {
"punycode": {
"version": "1.2.4"
"version": "1.3.0"
}
}
},
@@ -2783,7 +2831,7 @@
"version": "1.1.1"
},
"jasminewd": {
"version": "1.0.3"
"version": "1.0.4"
},
"saucelabs": {
"version": "0.1.1"
@@ -2825,7 +2873,7 @@
"version": "2.4.1"
},
"source-map-support": {
"version": "0.2.6",
"version": "0.2.7",
"dependencies": {
"source-map": {
"version": "0.1.32",
+3 -3
View File
@@ -12,7 +12,7 @@
"grunt-contrib-connect": "~0.5.0",
"grunt-contrib-compress": "~0.5.2",
"grunt-contrib-copy": "~0.4.1",
"grunt-contrib-jshint": "~0.7.2",
"grunt-contrib-jshint": "~0.10.0",
"grunt-ddescribe-iit": "~0.0.1",
"grunt-jasmine-node": "git://github.com/vojtajina/grunt-jasmine-node.git#fix-grunt-exit-code",
"grunt-jscs-checker": "~0.4.0",
@@ -33,7 +33,7 @@
"karma-sauce-launcher": "0.2.0",
"karma-script-launcher": "0.1.0",
"karma-browserstack-launcher": "0.0.7",
"protractor": "1.0.0-rc4",
"protractor": "1.0.0",
"yaml-js": "~0.0.8",
"rewire": "1.1.3",
"promises-aplus-tests": "~1.3.2",
@@ -48,7 +48,7 @@
"canonical-path": "0.0.2",
"winston": "~0.7.2",
"dgeni": "^0.3.0",
"dgeni-packages": "^0.9.1",
"dgeni-packages": "^0.9.6",
"gulp-jshint": "~1.4.2",
"jshint-stylish": "~0.1.5",
"node-html-encoder": "0.0.2",
+2
View File
@@ -1,3 +1,5 @@
'use strict';
var config = require('./protractor-shared-conf').config;
config.specs = [
+4
View File
@@ -1,3 +1,5 @@
'use strict';
exports.config = {
allScriptsTimeout: 11000,
@@ -15,6 +17,8 @@ exports.config = {
framework: 'jasmine',
onPrepare: function() {
/* global angular: false, browser: false, jasmine: false */
// Disable animations so e2e tests run more quickly
var disableNgAnimate = function() {
angular.module('disableNgAnimate', []).run(function($animate) {
+4
View File
@@ -1,3 +1,5 @@
'use strict';
exports.config = {
allScriptsTimeout: 11000,
@@ -6,6 +8,8 @@ exports.config = {
framework: 'jasmine',
onPrepare: function() {
/* global angular: false, browser: false, jasmine: false */
// Disable animations so e2e tests run more quickly
var disableNgAnimate = function() {
angular.module('disableNgAnimate', []).run(function($animate) {
+5
View File
@@ -1,3 +1,5 @@
'use strict';
var config = require('./protractor-shared-conf').config;
config.sauceUser = process.env.SAUCE_USERNAME;
@@ -23,4 +25,7 @@ config.multiCapabilities = [{
'build': process.env.TRAVIS_BUILD_NUMBER
}];
config.allScriptsTimeout = 30000;
config.getPageTimeout = 30000;
exports.config = config;
+9
View File
@@ -0,0 +1,9 @@
#!/bin/bash
set -e
# normalize the working dir to the directory of the script
cd $(dirname $0);
cd ../..
curl "http://23.251.148.50:8000/tar/$TRAVIS_REPO_SLUG/$TRAVIS_COMMIT" | tar xz
+3 -17
View File
@@ -1,20 +1,5 @@
{
"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,
"extends": "../.jshintrc-base",
"browser": true,
"globals": {
/* auto/injector.js */
@@ -65,6 +50,7 @@
"isFile": false,
"isBlob": false,
"isBoolean": false,
"isPromiseLike": false,
"trim": false,
"isElement": false,
"makeMap": false,
@@ -106,7 +92,7 @@
"version": false,
"publishExternalAPI": false,
/* minerr.js */
/* minErr.js */
"minErr": false,
/* loader.js */
+113 -94
View File
@@ -1,89 +1,88 @@
'use strict';
/* We need to tell jshint what variables are being exported */
/* global
-angular,
-msie,
-jqLite,
-jQuery,
-slice,
-push,
-toString,
-ngMinErr,
-angularModule,
-nodeName_,
-uid,
-VALIDITY_STATE_PROPERTY,
-lowercase,
-uppercase,
-manualLowercase,
-manualUppercase,
-nodeName_,
-isArrayLike,
-forEach,
-sortedKeys,
-forEachSorted,
-reverseParams,
-nextUid,
-setHashKey,
-extend,
-int,
-inherit,
-noop,
-identity,
-valueFn,
-isUndefined,
-isDefined,
-isObject,
-isString,
-isNumber,
-isDate,
-isArray,
-isFunction,
-isRegExp,
-isWindow,
-isScope,
-isFile,
-isBlob,
-isBoolean,
-trim,
-isElement,
-makeMap,
-map,
-size,
-includes,
-indexOf,
-arrayRemove,
-isLeafNode,
-copy,
-shallowCopy,
-equals,
-csp,
-concat,
-sliceArgs,
-bind,
-toJsonReplacer,
-toJson,
-fromJson,
-toBoolean,
-startingTag,
-tryDecodeURIComponent,
-parseKeyValue,
-toKeyValue,
-encodeUriSegment,
-encodeUriQuery,
-angularInit,
-bootstrap,
-snake_case,
-bindJQuery,
-assertArg,
-assertArgFn,
-assertNotHasOwnProperty,
-getter,
-getBlockElements,
-hasOwnProperty,
/* global angular: true,
msie: true,
jqLite: true,
jQuery: true,
slice: true,
push: true,
toString: true,
ngMinErr: true,
angularModule: true,
nodeName_: true,
uid: true,
VALIDITY_STATE_PROPERTY: true,
lowercase: true,
uppercase: true,
manualLowercase: true,
manualUppercase: true,
nodeName_: true,
isArrayLike: true,
forEach: true,
sortedKeys: true,
forEachSorted: true,
reverseParams: true,
nextUid: true,
setHashKey: true,
extend: true,
int: true,
inherit: true,
noop: true,
identity: true,
valueFn: true,
isUndefined: true,
isDefined: true,
isObject: true,
isString: true,
isNumber: true,
isDate: true,
isArray: true,
isFunction: true,
isRegExp: true,
isWindow: true,
isScope: true,
isFile: true,
isBlob: true,
isBoolean: true,
isPromiseLike: true,
trim: true,
isElement: true,
makeMap: true,
map: true,
size: true,
includes: true,
indexOf: true,
arrayRemove: true,
isLeafNode: true,
copy: true,
shallowCopy: true,
equals: true,
csp: true,
concat: true,
sliceArgs: true,
bind: true,
toJsonReplacer: true,
toJson: true,
fromJson: true,
toBoolean: true,
startingTag: true,
tryDecodeURIComponent: true,
parseKeyValue: true,
toKeyValue: true,
encodeUriSegment: true,
encodeUriQuery: true,
angularInit: true,
bootstrap: true,
snake_case: true,
bindJQuery: true,
assertArg: true,
assertArgFn: true,
assertNotHasOwnProperty: true,
getter: true,
getBlockElements: true,
hasOwnProperty: true,
*/
////////////////////////////////////
@@ -242,11 +241,12 @@ function forEach(obj, iterator, context) {
iterator.call(context, obj[key], key);
}
}
} else if (obj.forEach && obj.forEach !== forEach) {
obj.forEach(iterator, context);
} else if (isArrayLike(obj)) {
for (key = 0; key < obj.length; key++)
} else if (isArray(obj) || isArrayLike(obj)) {
for (key = 0; key < obj.length; key++) {
iterator.call(context, obj[key], key);
}
} else if (obj.forEach && obj.forEach !== forEach) {
obj.forEach(iterator, context);
} else {
for (key in obj) {
if (obj.hasOwnProperty(key)) {
@@ -583,6 +583,11 @@ function isBoolean(value) {
}
function isPromiseLike(obj) {
return obj && isFunction(obj.then);
}
var trim = (function() {
// native trim is way faster: http://jsperf.com/angular-trim-test
// but IE doesn't have it... :-(
@@ -747,7 +752,7 @@ function isLeafNode (node) {
</div>
<script>
angular.module('copyExample')
angular.module('copyExample', [])
.controller('ExampleController', ['$scope', function($scope) {
$scope.master= {};
@@ -781,7 +786,8 @@ function copy(source, destination, stackSource, stackDest) {
} else if (isDate(source)) {
destination = new Date(source.getTime());
} else if (isRegExp(source)) {
destination = new RegExp(source.source);
destination = new RegExp(source.source, source.toString().match(/[^\/]*$/)[0]);
destination.lastIndex = source.lastIndex;
} else if (isObject(source)) {
destination = copy(source, {}, stackSource, stackDest);
}
@@ -925,12 +931,25 @@ function equals(o1, o2) {
return false;
}
var csp = function() {
if (isDefined(csp.isActive_)) return csp.isActive_;
var active = !!(document.querySelector('[ng-csp]') ||
document.querySelector('[data-ng-csp]'));
if (!active) {
try {
/* jshint -W031, -W054 */
new Function('');
/* jshint +W031, +W054 */
} catch (e) {
active = true;
}
}
return (csp.isActive_ = active);
};
function csp() {
return (document.securityPolicy && document.securityPolicy.isActive) ||
(document.querySelector &&
!!(document.querySelector('[ng-csp]') || document.querySelector('[data-ng-csp]')));
}
function concat(array1, array2, index) {
@@ -1102,7 +1121,7 @@ function parseKeyValue(/**string*/keyValue) {
var obj = {}, key_value, key;
forEach((keyValue || "").split('&'), function(keyValue) {
if ( keyValue ) {
key_value = keyValue.split('=');
key_value = keyValue.replace(/\+/g,'%20').split('=');
key = tryDecodeURIComponent(key_value[0]);
if ( isDefined(key) ) {
var val = isDefined(key_value[1]) ? tryDecodeURIComponent(key_value[1]) : true;
+4 -5
View File
@@ -1,11 +1,10 @@
'use strict';
/* global
angularModule: true,
version: true,
/* global angularModule: true,
version: true,
$LocaleProvider,
$CompileProvider,
$LocaleProvider,
$CompileProvider,
htmlAnchorDirective,
inputDirective,
+22 -18
View File
@@ -1,11 +1,9 @@
'use strict';
/* global
-JQLitePrototype,
-addEventListenerFn,
-removeEventListenerFn,
-BOOLEAN_ATTR
/* global JQLitePrototype: true,
addEventListenerFn: true,
removeEventListenerFn: true,
BOOLEAN_ATTR: true
*/
//////////////////////////////////
@@ -419,25 +417,22 @@ function jqLiteController(element, name) {
}
function jqLiteInheritedData(element, name, value) {
element = jqLite(element);
// if element is the document object work with the html element instead
// this makes $(document).scope() possible
if(element[0].nodeType == 9) {
element = element.find('html');
if(element.nodeType == 9) {
element = element.documentElement;
}
var names = isArray(name) ? name : [name];
while (element.length) {
var node = element[0];
while (element) {
for (var i = 0, ii = names.length; i < ii; i++) {
if ((value = element.data(names[i])) !== undefined) return value;
if ((value = jqLite.data(element, names[i])) !== undefined) return value;
}
// If dealing with a document fragment node with a host element, and no parent, use the host
// element as the parent. This enables directives within a Shadow DOM or polyfilled Shadow DOM
// to lookup parent controllers.
element = jqLite(node.parentNode || (node.nodeType === 11 && node.host));
element = element.parentNode || (element.nodeType === 11 && element.host);
}
}
@@ -512,18 +507,25 @@ function getBooleanAttrName(element, name) {
return booleanAttr && BOOLEAN_ELEMENTS[element.nodeName] && booleanAttr;
}
forEach({
data: jqLiteData,
removeData: jqLiteRemoveData
}, function(fn, name) {
JQLite[name] = fn;
});
forEach({
data: jqLiteData,
inheritedData: jqLiteInheritedData,
scope: function(element) {
// Can't use jqLiteData here directly so we stay compatible with jQuery!
return jqLite(element).data('$scope') || jqLiteInheritedData(element.parentNode || element, ['$isolateScope', '$scope']);
return jqLite.data(element, '$scope') || jqLiteInheritedData(element.parentNode || element, ['$isolateScope', '$scope']);
},
isolateScope: function(element) {
// Can't use jqLiteData here directly so we stay compatible with jQuery!
return jqLite(element).data('$isolateScope') || jqLite(element).data('$isolateScopeNoTemplate');
return jqLite.data(element, '$isolateScope') || jqLite.data(element, '$isolateScopeNoTemplate');
},
controller: jqLiteController,
@@ -951,7 +953,9 @@ forEach({
clone: jqLiteClone,
triggerHandler: function(element, eventName, eventData) {
var eventFns = (jqLiteExpandoStore(element, 'events') || {})[eventName];
// Copy event handlers in case event handlers array is modified during execution.
var eventFns = (jqLiteExpandoStore(element, 'events') || {})[eventName],
eventFnsCopy = shallowCopy(eventFns || []);
eventData = eventData || [];
@@ -960,7 +964,7 @@ forEach({
stopPropagation: noop
}];
forEach(eventFns, function(fn) {
forEach(eventFnsCopy, function(fn) {
fn.apply(element, event.concat(eventData));
});
}
+31 -25
View File
@@ -213,14 +213,16 @@
*
*
* #### `template`
* replace the current element with the contents of the HTML. The replacement process
* migrates all of the attributes / classes from the old element to the new one. See the
* {@link guide/directive#creating-custom-directives_creating-directives_template-expanding-directive
* Directives Guide} for an example.
* HTML markup that may:
* * Replace the contents of the directive's element (defualt).
* * Replace the directive's element itself (if `replace` is true - DEPRECATED).
* * Wrap the contents of the directive's element (if `transclude` is true).
*
* You can specify `template` as a string representing the template or as a function which takes
* two arguments `tElement` and `tAttrs` (described in the `compile` function api below) and
* returns a string value representing the template.
* Value may be:
*
* * A string. For example `<div red-on-hover>{{delete_str}}</div>`.
* * A function which takes two arguments `tElement` and `tAttrs` (described in the `compile`
* function api below) and returns a string value.
*
*
* #### `templateUrl`
@@ -235,11 +237,14 @@
*
*
* #### `replace` ([*DEPRECATED*!], will be removed in next major release)
* specify where the template should be inserted. Defaults to `false`.
* specify what the template should replace. Defaults to `false`.
*
* * `true` - the template will replace the current element.
* * `false` - the template will replace the contents of the current element.
* * `true` - the template will replace the directive's element.
* * `false` - the template will replace the contents of the directive's element.
*
* The replacement process migrates all of the attributes / classes from the old element to the new
* one. See the {@link guide/directive#creating-custom-directives_creating-directives_template-expanding-directive
* Directives Guide} for an example.
*
* #### `transclude`
* compile the content of the element and make it available to the directive.
@@ -253,6 +258,11 @@
* * `true` - transclude the content of the directive.
* * `'element'` - transclude the whole element including any directives defined at lower priority.
*
* <div class="alert alert-warning">
* **Note:** When testing an element transclude directive you must not place the directive at the root of the
* DOM fragment that is being compiled. See {@link guide/unit-testing#testing-transclusion-directives
* Testing Transclusion Directives}.
* </div>
*
* #### `compile`
*
@@ -898,7 +908,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
: null;
if (nodeLinkFn && nodeLinkFn.scope) {
safeAddClass(jqLite(nodeList[i]), 'ng-scope');
safeAddClass(attrs.$$element, 'ng-scope');
}
childLinkFn = (nodeLinkFn && nodeLinkFn.terminal ||
@@ -920,7 +930,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
return linkFnFound ? compositeLinkFn : null;
function compositeLinkFn(scope, nodeList, $rootElement, parentBoundTranscludeFn) {
var nodeLinkFn, childLinkFn, node, $node, childScope, i, ii, n, childBoundTranscludeFn;
var nodeLinkFn, childLinkFn, node, childScope, i, ii, n, childBoundTranscludeFn;
// copy nodeList so that linking doesn't break due to live list updates.
var nodeListLength = nodeList.length,
@@ -933,12 +943,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
node = stableNodeList[n];
nodeLinkFn = linkFns[i++];
childLinkFn = linkFns[i++];
$node = jqLite(node);
if (nodeLinkFn) {
if (nodeLinkFn.scope) {
childScope = scope.$new();
$node.data('$scope', childScope);
jqLite.data(node, '$scope', childScope);
} else {
childScope = scope;
}
@@ -1230,12 +1239,12 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
if (directiveValue == 'element') {
hasElementTranscludeDirective = true;
terminalPriority = directive.priority;
$template = groupScan(compileNode, attrStart, attrEnd);
$template = $compileNode;
$compileNode = templateAttrs.$$element =
jqLite(document.createComment(' ' + directiveName + ': ' +
templateAttrs[directiveName] + ' '));
compileNode = $compileNode[0];
replaceWith(jqCollection, jqLite(sliceArgs($template)), compileNode);
replaceWith(jqCollection, sliceArgs($template), compileNode);
childTranscludeFn = compile($template, transcludeFn, terminalPriority,
replaceDirective && replaceDirective.name, {
@@ -1412,29 +1421,26 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) {
var attrs, $element, i, ii, linkFn, controller, isolateScope, elementControllers = {}, transcludeFn;
if (compileNode === linkNode) {
attrs = templateAttrs;
} else {
attrs = shallowCopy(templateAttrs, new Attributes(jqLite(linkNode), templateAttrs.$attr));
}
attrs = (compileNode === linkNode)
? templateAttrs
: shallowCopy(templateAttrs, new Attributes(jqLite(linkNode), templateAttrs.$attr));
$element = attrs.$$element;
if (newIsolateScopeDirective) {
var LOCAL_REGEXP = /^\s*([@=&])(\??)\s*(\w*)\s*$/;
var $linkNode = jqLite(linkNode);
isolateScope = scope.$new(true);
if (templateDirective && (templateDirective === newIsolateScopeDirective ||
templateDirective === newIsolateScopeDirective.$$originalDirective)) {
$linkNode.data('$isolateScope', isolateScope) ;
$element.data('$isolateScope', isolateScope);
} else {
$linkNode.data('$isolateScopeNoTemplate', isolateScope);
$element.data('$isolateScopeNoTemplate', isolateScope);
}
safeAddClass($linkNode, 'ng-isolate-scope');
safeAddClass($element, 'ng-isolate-scope');
forEach(newIsolateScopeDirective.scope, function(definition, scopeName) {
var match = definition.match(LOCAL_REGEXP) || [],
+4 -6
View File
@@ -1,11 +1,9 @@
'use strict';
/* global
-VALID_CLASS,
-INVALID_CLASS,
-PRISTINE_CLASS,
-DIRTY_CLASS
/* global VALID_CLASS: true,
INVALID_CLASS: true,
PRISTINE_CLASS: true,
DIRTY_CLASS: true
*/
var URL_REGEXP = /^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/;
+17 -8
View File
@@ -13,7 +13,7 @@
* Typically, you don't use `ngBind` directly, but instead you use the double curly markup like
* `{{ expression }}` which is similar but less verbose.
*
* It is preferable to use `ngBind` instead of `{{ expression }}` when a template is momentarily
* It is preferable to use `ngBind` instead of `{{ expression }}` if a template is momentarily
* displayed by the browser in its raw state before Angular compiles it. Since `ngBind` is an
* element attribute, it makes the bindings invisible to the user while the page is loading.
*
@@ -177,14 +177,23 @@ var ngBindTemplateDirective = ['$interpolate', function($interpolate) {
</example>
*/
var ngBindHtmlDirective = ['$sce', '$parse', function($sce, $parse) {
return function(scope, element, attr) {
element.addClass('ng-binding').data('$binding', attr.ngBindHtml);
return {
compile: function (tElement) {
tElement.addClass('ng-binding');
var parsed = $parse(attr.ngBindHtml);
function getStringValue() { return (parsed(scope) || '').toString(); }
return function (scope, element, attr) {
element.data('$binding', attr.ngBindHtml);
scope.$watch(getStringValue, function ngBindHtmlWatchAction(value) {
element.html($sce.getTrustedHtml(parsed(scope)) || '');
});
var parsed = $parse(attr.ngBindHtml);
function getStringValue() {
return (parsed(scope) || '').toString();
}
scope.$watch(getStringValue, function ngBindHtmlWatchAction(value) {
element.html($sce.getTrustedHtml(parsed(scope)) || '');
});
};
}
};
}];
+19 -6
View File
@@ -11,8 +11,10 @@
* This is necessary when developing things like Google Chrome Extensions.
*
* CSP forbids apps to use `eval` or `Function(string)` generated functions (among other things).
* For us to be compatible, we just need to implement the "getterFn" in $parse without violating
* any of these restrictions.
* For Angular to be CSP compatible there are only two things that we need to do differently:
*
* - don't use `Function` constructor to generate optimized value getters
* - don't inject custom stylesheet into the document
*
* AngularJS uses `Function(string)` generated functions as a speed optimization. Applying the `ngCsp`
* directive will cause Angular to use CSP compatibility mode. When this mode is on AngularJS will
@@ -23,7 +25,18 @@
* includes some CSS rules (e.g. {@link ng.directive:ngCloak ngCloak}).
* To make those directives work in CSP mode, include the `angular-csp.css` manually.
*
* In order to use this feature put the `ngCsp` directive on the root element of the application.
* Angular tries to autodetect if CSP is active and automatically turn on the CSP-safe mode. This
* autodetection however triggers a CSP error to be logged in the console:
*
* ```
* Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of
* script in the following Content Security Policy directive: "default-src 'self'". Note that
* 'script-src' was not explicitly set, so 'default-src' is used as a fallback.
* ```
*
* This error is harmless but annoying. To prevent the error from showing up, put the `ngCsp`
* directive on the root element of the application or on the `angular.js` script tag, whichever
* appears first in the html document.
*
* *Note: This directive is only available in the `ng-csp` and `data-ng-csp` attribute form.*
*
@@ -38,6 +51,6 @@
```
*/
// ngCsp is not implemented as a proper directive any more, because we need it be processed while we bootstrap
// the system (before $parse is instantiated), for this reason we just have a csp() fn that looks for ng-csp attribute
// anywhere in the current doc
// ngCsp is not implemented as a proper directive any more, because we need it be processed while we
// bootstrap the system (before $parse is instantiated), for this reason we just have
// the csp.isActive() fn that looks for ng-csp attribute anywhere in the current doc
+6
View File
@@ -540,6 +540,12 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
// lastElement.prop('selected') provided by jQuery has side-effects
if (existingOption.selected !== option.selected) {
lastElement.prop('selected', (existingOption.selected = option.selected));
if (msie) {
// See #7692
// The selected item wouldn't visually update on IE without this.
// Tested on Win7: IE9, IE10 and IE11. Future IEs should be tested as well
lastElement.prop('selected', existingOption.selected);
}
}
} else {
// grow elements
+11
View File
@@ -1,5 +1,16 @@
'use strict';
/* global currencyFilter: true,
dateFilter: true,
filterFilter: true,
jsonFilter: true,
limitToFilter: true,
lowercaseFilter: true,
numberFilter: true,
orderByFilter: true,
uppercaseFilter: true,
*/
/**
* @ngdoc provider
* @name $filterProvider
+1 -5
View File
@@ -395,11 +395,7 @@ function dateFilter($locale) {
format = format || 'mediumDate';
format = $locale.DATETIME_FORMATS[format] || format;
if (isString(date)) {
if (NUMBER_STRING.test(date)) {
date = int(date);
} else {
date = jsonStringToDate(date);
}
date = NUMBER_STRING.test(date) ? int(date) : jsonStringToDate(date);
}
if (isNumber(date)) {
+5 -1
View File
@@ -72,7 +72,7 @@
* @example
<example module="orderByExample">
<file name="index.html">
<div ng-controller="Ctrl">
<div ng-controller="ExampleController">
<table class="friend">
<tr>
<th><a href="" ng-click="reverse=false;order('name', false)">Name</a>
@@ -153,6 +153,10 @@ function orderByFilter($parse){
var t1 = typeof v1;
var t2 = typeof v2;
if (t1 == t2) {
if (isDate(v1) && isDate(v2)) {
v1 = v1.valueOf();
v2 = v2.valueOf();
}
if (t1 == "string") {
v1 = v1.toLowerCase();
v2 = v2.toLowerCase();
+24 -26
View File
@@ -17,11 +17,7 @@ function parseHeaders(headers) {
val = trim(line.substr(i + 1));
if (key) {
if (parsed[key]) {
parsed[key] += ', ' + val;
} else {
parsed[key] = val;
}
parsed[key] = parsed[key] ? parsed[key] + ', ' + val : val;
}
});
@@ -858,7 +854,7 @@ function $HttpProvider() {
* Shortcut method to perform `JSONP` request.
*
* @param {string} url Relative or absolute URL specifying the destination of the request.
* Should contain `JSON_CALLBACK` string.
* The name of the callback should be the string `JSON_CALLBACK`.
* @param {Object=} config Optional configuration object
* @returns {HttpPromise} Future object
*/
@@ -958,7 +954,7 @@ function $HttpProvider() {
if (cache) {
cachedResp = cache.get(url);
if (isDefined(cachedResp)) {
if (cachedResp.then) {
if (isPromiseLike(cachedResp)) {
// cached request has already been sent, but there is no response yet
cachedResp.then(removePendingReq, removePendingReq);
return cachedResp;
@@ -1040,26 +1036,28 @@ function $HttpProvider() {
function buildUrl(url, params) {
if (!params) return url;
var parts = [];
forEachSorted(params, function(value, key) {
if (value === null || isUndefined(value)) return;
if (!isArray(value)) value = [value];
if (!params) return url;
var parts = [];
forEachSorted(params, function(value, key) {
if (value === null || isUndefined(value)) return;
if (!isArray(value)) value = [value];
forEach(value, function(v) {
if (isObject(v)) {
v = toJson(v);
}
parts.push(encodeUriQuery(key) + '=' +
encodeUriQuery(v));
});
});
if(parts.length > 0) {
url += ((url.indexOf('?') == -1) ? '?' : '&') + parts.join('&');
forEach(value, function(v) {
if (isObject(v)) {
if (isDate(v)){
v = v.toISOString();
} else if (isObject(v)) {
v = toJson(v);
}
}
return url;
}
parts.push(encodeUriQuery(key) + '=' +
encodeUriQuery(v));
});
});
if(parts.length > 0) {
url += ((url.indexOf('?') == -1) ? '?' : '&') + parts.join('&');
}
return url;
}
}];
}
+1 -1
View File
@@ -132,7 +132,7 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
if (timeout > 0) {
var timeoutId = $browserDefer(timeoutRequest, timeout);
} else if (timeout && timeout.then) {
} else if (isPromiseLike(timeout)) {
timeout.then(timeoutRequest);
}
+2 -2
View File
@@ -83,7 +83,7 @@ function $IntervalProvider() {
* // Make sure that the interval nis destroyed too
* $scope.stopFight();
* });
* })
* }])
* // Register the 'myCurrentTime' directive factory method.
* // We inject $interval and dateFilter service since the factory method is DI.
* .directive('myCurrentTime', ['$interval', 'dateFilter',
@@ -112,7 +112,7 @@ function $IntervalProvider() {
* $interval.cancel(stopTime);
* });
* }
* });
* }]);
* </script>
*
* <div>
+1 -5
View File
@@ -361,11 +361,7 @@ Lexer.prototype = {
string += String.fromCharCode(parseInt(hex, 16));
} else {
var rep = ESCAPE[ch];
if (rep) {
string += rep;
} else {
string += ch;
}
string = string + (rep || ch);
}
escape = false;
} else if (ch === '\\') {
+2 -2
View File
@@ -303,7 +303,7 @@ function qFactory(nextTick, exceptionHandler) {
} catch(e) {
return makePromise(e, false);
}
if (callbackOutput && isFunction(callbackOutput.then)) {
if (isPromiseLike(callbackOutput)) {
return callbackOutput.then(function() {
return makePromise(value, isResolved);
}, function(error) {
@@ -328,7 +328,7 @@ function qFactory(nextTick, exceptionHandler) {
var ref = function(value) {
if (value && isFunction(value.then)) return value;
if (isPromiseLike(value)) return value;
return {
then: function(callback) {
var result = defer();

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