Compare commits

...

61 Commits

Author SHA1 Message Date
jenkins 0f9a1c21e6 chore(release): cut v1.2.8 release 2014-01-10 12:37:49 -08:00
Brian Ford ece7854972 docs(changelog): release notes for 1.2.8 2014-01-10 11:49:06 -08:00
Ajay Roopakalu 8ace8073fd docs(select): update regexp grouping cheat-sheat
Update the regexp grouping comment to reflect the changes needed for
multiline expressions in ng-options for <select>.

Closes #5602
2014-01-10 09:50:28 -08:00
Ajay Roopakalu 43a2f3d0bf feat(select): allow multiline ng-options
This patch allows the ng-options value of a <select> element to span
multiple lines, which would previously throw an error when used with filters.

Closes #5602
2014-01-10 09:50:28 -08:00
Igor Minar a9cccbe14f fix($http): return responseText on IE8 for requests with responseType set
Closes #4464
Closes #4738
Closes #5636
2014-01-10 02:25:36 -08:00
Narretz 36c9e42de2 docs: fix the 'view source' button for snapshots
Closes #5590
Closes #5641
2014-01-10 02:22:27 -08:00
René Wilhelm 9f566db33c docs(\$resource): fixed typo (s/seapph/search)
Closes #5718
2014-01-10 01:10:19 -08:00
Caitlin Potter c77b2bcca3 docs($location): fix link to $locationChangeSuccess event
Closes #5717
2014-01-10 00:58:40 -08:00
Igor Minar 5a4145fe16 revert: fix($location): return '/' for root path in hashbang mode
This reverts commit 63cd873fef.

The change breaks existing tests of Google apps. The problem is that
while we tried to avoid adding #/ to window.location.href unnecessarily
we failed doing so. Likely because by setting $path, at some point
(during a digest) we try to check if $location changed and we mistake the
default '/' with an explicit settign of the path via the `path()` method.
This results in us writing the url with '#/' into $browser.url() which updates
the window.location by adding "#/" to the url - something we tried to avoid
in the first place.

I'll reopen PR #5712.
2014-01-09 23:47:35 -08:00
Jeff Cross 039b990d8d test(docs): add protractor tests for docs app
Closes #5437
2014-01-09 22:41:52 -08:00
Tobias Bosch 5a9cb8be3f chore(build): bugfix for script utils 2014-01-09 17:37:27 -08:00
Caitlin Potter 63cd873fef fix($location): return '/' for root path in hashbang mode
Before this change, on the root of the application, $location.path() would return
the empty string. Following this change, it will always return a root of '/'.

Closes #5650
Closes #5712
2014-01-09 17:35:25 -08:00
Igor Minar 69452fa94f docs(tutorial): improve experiment instructions
Closes #5697
2014-01-09 17:24:10 -08:00
Julie 2ed4ad5502 feat(build): add a grunt test for running protractor tests extracted from the docs 2014-01-09 17:21:46 -08:00
René Wilhelm 1d2a388830 fix(docs): Add missing whitespace 2014-01-09 16:51:47 -08:00
stucash ac05276a51 fix(docs): Update reference to $routeProvider.otherwise 2014-01-09 16:48:15 -08:00
Craig Younkins cb9c0f200a fix(docs): Clarifying versions of IE that need special fixes 2014-01-09 16:34:16 -08:00
Tobias Bosch b1d676b7f7 chore(build): check cdn before executing the release-after-cdn script 2014-01-09 15:29:02 -08:00
Tobias Bosch 9ddef840b6 chore(build): add relase-after-cdn script 2014-01-09 14:59:55 -08:00
Rafał Jagoda 28fc80bba0 fix($httpBackend): Allow status code 0 from any protocol
Android 4.1 stock browser also returns status code 0 when
a template is loaded via `http` and the application is cached using
appcache.

Fixes #1356.
Closes #5547.
2014-01-09 10:10:11 -08:00
Julie b6c42d5e81 feat(docs): adding the <doc:protractor> ngdoc-tag
This is the first step in migrating tests from <doc:scenario> to <doc:protractor>.
In-documentation examples with doc:protractor sections will have their contents
output to a tab on the docs site as well as output to a standalone test file in
build/docs/ptore2e.
2014-01-08 13:07:58 -08:00
Gias Kay Lee 1c045f1b46 docs(script): add more detailed information
Closes #5671
Closes #5676
2014-01-08 00:49:29 -08:00
Artemy Tregubenko 95e1b2d612 fix($httpBackend): cancelled JSONP requests will not print error in the console
When you cancel a JSONP request, angular deletes the callback for it. However the script still executes, and since the callback is now deleted and undefined, the script throws an exception visible in the console. The quick fix for this is not to delete the callback, but replace it with `angular.noop`.

Closes #5615
Closes #5616
2014-01-08 00:35:19 -08:00
Igor Minar 75345e3487 docs($document): moar better description
Closes #5678
2014-01-07 17:07:48 -08:00
Igor Minar f4fe28bd92 docs($document): improve the description
Closes #5678
2014-01-07 17:06:22 -08:00
Tobias Bosch ace13b94e6 chore(build): fix typo in release script 2014-01-07 17:00:53 -08:00
Gias Kay Lee 5df7e73adf refactor(booleanAttrs, ngSwitch): use link function instead of compile function where appropriate
Replace two compile functions that immediately return a post-link function with link function definitions instead.

Closes #5664
2014-01-07 16:54:35 -08:00
Zhong Liang Ong e115342fce docs(directives): Fixed typo from HMTL to HTML in line 283
HTML was mis-spelt as HMTL
2014-01-07 16:51:47 -08:00
Tobias Bosch e89150ca0f chore(build): Add angular-seed and angular-phonecat to the release 2014-01-07 15:49:03 -08:00
Vojta Jina 9693a426e3 chore(travis): use Safari 7 2014-01-07 11:53:50 -08:00
Vojta Jina 162485d303 chore(travis): use FF26
I think it's better to not specify the version as that should give the latest available version.
We should probably revert this commit at some point.
2014-01-07 11:53:17 -08:00
Vojta Jina affcbad501 test(ngMock): fix the tests to not use global msie
My bad when merging 7e916455b3.

These tests are run with compiled Angular and then the msie is not defined.
2014-01-06 19:08:05 -08:00
Andrew C. Greenberg 7e916455b3 fix(ngMock window.inject): Remove Error 'stack' property changes
Recent browsers, particularly PhantomJS 1.9.2 and Safari 7.0
treat the stack property as non-configurable and unwritable.

Because window.inject captures the stack at the time of the inject,
and attempts to insert it into a captured throw from the injected
function by modifying e.stack, a meaningless error message and
stack is thrown instead.

This commit inserts two tests exposing the problem, and implements
a proposed solution that builds a new error-like object that mimicks
the old Error object, but with the additional stack information, and
captures the toString function from the Error object prototype.  This
appears to work for the browsers suppoerted here.
2014-01-06 17:47:06 -08:00
Ben Wiklund cdc4d485a6 refactor(input): wrapped validation logic in helper function
Closes #5643
2014-01-06 17:35:13 -08:00
Gias Kay Lee c894470d41 docs($compile): fix a typo
Closes #5639
2014-01-06 17:35:13 -08:00
Jay Goldman 1b0718bf89 docs(tutorial/step-12): replaced a missing apostrophe and fixed grammar errors
Fixed a missing apostrophe and some grammar in the Animating 'ngClass' with JavaScript section
2014-01-06 20:06:27 -05:00
jesse 53fd24ffcb docs(form): changed capitalization in CSS classes section
In order to improve readability from "Is set" (confused on my screen as 'Ls set') updated the
capitalization describing the setting of 4 CSS classes.

Closes #5642
2014-01-06 16:44:52 -08:00
Ben Wiklund eb90672aae chore(inputSpec): fixed typo 2014-01-06 16:37:47 -08:00
Roy Ling 28cfd96fdc docs(forms): show directive name instead of link path 2014-01-06 16:34:49 -08:00
Tyler McGinnis 99d5defb1a docs(guide/i18n): fix a typo
Closes #5651
2014-01-06 16:11:53 -08:00
Tobias Bosch efbc242875 chore(build): bugfixes to build scripts on Jenkins 2014-01-06 15:48:30 -08:00
Vojta Jina d4d58f287f docs(tutorial): do not recommend global install of Karma
Closes #5498
2014-01-06 14:48:50 -08:00
Tobias Bosch dc89db33df chore(build): bugfixes to build scripts on Jenkins. 2014-01-06 14:11:44 -08:00
Tobias Bosch 5dc27959d5 chore(build): refactor build scripts in prepare/publish phase
Refactored all scripts so that they are divided into a `prepare`
and a `publish` phase. By this we can build, test, tag, commit
everything first. Only if all of this is ok we start pushing
to Github. By this we keep Github consistent even in error cases.

Extracted include script `/scripts/utils.inc`:
- parse and validate named arguments in the style
  `--name=value`
- proxy git command and deactivate `git push` based on
  command option `--git_push_dry_run=true`
  (will be inherited to child scripts)
- enable/disable bash debug mode by command option
  `--verbose=true`
- dispatch to functions based on command option
  `--action=...`
- helper functions for dealing with json files
2014-01-06 12:27:54 -08:00
Vojta Jina 4c21355940 chore: strict deps Karma and plugins
So that we have a better control when updating Karma.
2014-01-06 11:27:19 -08:00
Matias Niemelä 6f6cb5c8d8 chore(docs): remove uppercase heading styling
Closes #5593
2014-01-06 10:22:16 -05:00
Chris Chua 821ed310a7 refactor(animate): remove duplicate line 2014-01-06 00:07:44 -05:00
Igor Minar a7aa4cc0a9 revert: fix(closure): add Closure externs for angular.$q.Promise.finally
This reverts commit caeb740265.

The commit breaks Google apps because most don't use closure compiler
with the ES5 mode flag on. We are investigating a solution...
2014-01-05 01:19:35 -08:00
RoyLING e0ce9ed36d refactor(filterFilter): simplify code by a ternary op instead of if-else
- use only one IIFE and a ternary op in it, instead of invoking separate IIFEs in if-else
(this also completely fixed the same issue closed by PR #3597)
- also add a spec to verify usage of '$' property in expression object (e.g. `{$: 'a'}`)

Closes #5637
2014-01-05 00:36:04 -08:00
Daniel Aden caeb740265 fix(closure): add Closure externs for angular.$q.Promise.finally
Closes #4757
2014-01-05 00:27:38 -08:00
Kenneth Lynne 1bb33cccbe docs(rootScope): fix typo
Closes #5633
2014-01-04 20:51:58 -08:00
Igor Minar d9ed9c5ac1 docs(ng/filter/filter): make docs human readable 2014-01-04 00:14:38 -08:00
MikeMac 00cac6ed10 docs($http): makes clear $httpProvider.defaults are available at run-time
Clarifies some confusion around $http.defaults existing and able to be modified
at run-time, for when run-time services may be needed in a transformation.

Closes #5559
Closes #5630
2014-01-03 22:35:14 -08:00
Wojciech Krzystek 2e9d7cc6cb docs(ngRepeat): add info about aliasing special properties of ngRepeat
This will safe peoples' time, since ngRepeat's docs, not ngInit's, is the first
place where one would search for such info.

Closes #5622
2014-01-03 16:07:26 -08:00
Bastian Buchholz 32cc6cbb6f style($httpBackend): fix typo 2014-01-03 16:04:50 -08:00
Brian Nenninger 3b1a4fe0c8 fix($parse): fix CSP nested property evaluation, and issue that prevented its tests from failing
cspSafeGetterFn incorrectly returned undefined if any of its key parameters were undefined. This
wasn't caught by the $parse unit tests because of a timing problem where $ParseProvider was reading
the CSP flag before the tests manually set it, so the CSP property evaluation tests never ran. Add
test that verifies evaluation of nested properties of multiple lengths.

Closes #5591
Closes #5592
2014-01-03 14:33:54 -08:00
Brian Ford 9569778f2f chore(release): fix release name 2014-01-03 13:16:39 -08:00
Brian Ford 0f61316b24 chore(release): update cdn version 2014-01-03 13:09:26 -08:00
Tobias Bosch 86151b0cea chore(release): set next release name 2014-01-03 12:02:29 -08:00
Igor Minar 1b7a6c66f8 core(Scope): rename 'debugger' to 'web inspector' to avoid woes with g3 presubmits 2014-01-03 11:17:43 -08:00
chimney-sweeper 0ef76dde41 chore(release): start v1.2.8 2014-01-03 10:40:31 -08:00
66 changed files with 1341 additions and 443 deletions
+35
View File
@@ -1,3 +1,38 @@
<a name="1.2.8"></a>
# 1.2.8 interdimensional-cartography (2014-01-10)
## Bug Fixes
- **$http:**
- return responseText on IE8 for requests with responseType set
([a9cccbe1](https://github.com/angular/angular.js/commit/a9cccbe14f1bd9048f5dab4443f58c804d4259a1),
[#4464](https://github.com/angular/angular.js/issues/4464), [#4738](https://github.com/angular/angular.js/issues/4738), [#5636](https://github.com/angular/angular.js/issues/5636))
- Allow status code 0 from any protocol
([28fc80bb](https://github.com/angular/angular.js/commit/28fc80bba0107075ab371fd0a7634a38891626b2),
[#1356](https://github.com/angular/angular.js/issues/1356), [#5547](https://github.com/angular/angular.js/issues/5547))
- cancelled JSONP requests will not print error in the console
([95e1b2d6](https://github.com/angular/angular.js/commit/95e1b2d6121b4e26cf87dcf6746a7b8cb4c25e7f),
[#5615](https://github.com/angular/angular.js/issues/5615), [#5616](https://github.com/angular/angular.js/issues/5616))
- **$location:** return '/' for root path in hashbang mode
([63cd873f](https://github.com/angular/angular.js/commit/63cd873fef3207deef30c7a7ed66f4b8f647dc12),
[#5650](https://github.com/angular/angular.js/issues/5650), [#5712](https://github.com/angular/angular.js/issues/5712))
- **$parse:** fix CSP nested property evaluation, and issue that prevented its tests from failing
([3b1a4fe0](https://github.com/angular/angular.js/commit/3b1a4fe0c83c7898ecd7261ab4213998ee7be0ec),
[#5591](https://github.com/angular/angular.js/issues/5591), [#5592](https://github.com/angular/angular.js/issues/5592))
- **closure:** add Closure externs for angular.$q.Promise.finally
([caeb7402](https://github.com/angular/angular.js/commit/caeb7402651702cd13df2f1594e9827439a8b760),
[#4757](https://github.com/angular/angular.js/issues/4757))
- **ngMock window.inject:** Remove Error 'stack' property changes
([7e916455](https://github.com/angular/angular.js/commit/7e916455b36dc9ca4d4afc1e44cade90006d00e3))
## Features
- **select:** allow multiline ng-options
([43a2f3d0](https://github.com/angular/angular.js/commit/43a2f3d0bf435e3626cd679caff4281cfb3415bd),
[#5602](https://github.com/angular/angular.js/issues/5602))
<a name="1.2.7"></a>
# 1.2.7 emoji-clairvoyance (2014-01-03)
+8 -1
View File
@@ -101,6 +101,11 @@ module.exports = function(grunt) {
},
runprotractor: {
normal: 'protractor-conf.js'
},
clean: {
build: ['build'],
tmp: ['tmp']
@@ -283,13 +288,15 @@ module.exports = function(grunt) {
//alias tasks
grunt.registerTask('test', 'Run unit, docs and e2e tests with Karma', ['jshint', 'package','test:unit','test:promises-aplus', 'tests:docs', 'test:e2e']);
grunt.registerTask('test', 'Run unit, docs and e2e tests with Karma', ['jshint', 'package','test:unit','test:promises-aplus', 'tests:docs', 'test:e2e', 'webdriver', 'runprotractor:normal']);
grunt.registerTask('test:jqlite', 'Run the unit tests with Karma' , ['tests:jqlite']);
grunt.registerTask('test:jquery', 'Run the jQuery unit tests with Karma', ['tests:jquery']);
grunt.registerTask('test:modules', 'Run the Karma module tests with Karma', ['tests:modules']);
grunt.registerTask('test:docs', 'Run the doc-page tests with Karma', ['package', 'tests:docs']);
grunt.registerTask('test:unit', 'Run unit, jQuery and Karma module tests with Karma', ['tests:jqlite', 'tests:jquery', 'tests:modules']);
grunt.registerTask('test:e2e', 'Run the end to end tests with Karma and keep a test server running in the background', ['connect:testserver', 'tests:end2end']);
// This should eventually replace test:e2e
grunt.registerTask('test:protractor', 'Run the end to end tests with Protractor and keep a test server running in the background', ['webdriver', 'connect:testserver', 'runprotractor:normal']);
grunt.registerTask('test:docgen', ['jasmine_node']);
grunt.registerTask('test:promises-aplus',['build:promises-aplus-adapter','shell:promises-aplus-tests']);
@@ -19,7 +19,7 @@ testable.
To register a service, you must have a module that this service will be part of. Afterwards, you
can register the service with the module either via the {@link api/angular.Module Module api} or
by using the {@link api/AUTO.$provide $provide} service in the module configuration
function.The following pseudo-code shows both approaches:
function. The following pseudo-code shows both approaches:
Using the angular.Module api:
<pre>
+1 -1
View File
@@ -280,7 +280,7 @@ using `templateUrl` instead:
</example>
Great! But what if we wanted to have our directive match the tag name `<my-customer>` instead?
If we simply put a `<my-customer>` element into the HMTL, it doesn't work.
If we simply put a `<my-customer>` element into the HTML, it doesn't work.
<div class="alert alert-waring">
**Note:** When you create a directive, it is restricted to attribute only by default. In order to
+1 -1
View File
@@ -116,7 +116,7 @@ This ensures that the user is not distracted with an error until after interacti
A form is an instance of {@link api/ng.directive:form.FormController FormController}.
The form instance can optionally be published into the scope using the `name` attribute.
Similarly, an input control that has the {@link api/ng.directive:ngModel} directive holds an
Similarly, an input control that has the {@link api/ng.directive:ngModel ngModel} directive holds an
instance of {@link api/ng.directive:ngModel.NgModelController NgModelController}.
Such a control instance can be published as a property of the form instance using the `name` attribute
on the input control. The name attribute specifies the name of the property on the form instance.
+1 -1
View File
@@ -97,7 +97,7 @@ locale, it is fine to rely on the default currency symbol. However, if you antic
in other locales might use your app, you should provide your own currency symbol to make sure the
actual value is understood.
For example, if you want to display account balance of 1000 dollars with the following binding
For example, if you want to display an account balance of 1000 dollars with the following binding
containing currency filter: `{{ 1000 | currency }}`, and your app is currently in en-US locale.
'$1000.00' will be shown. However, if someone in a different local (say, Japan) views your app, her
browser will specify the locale as ja, and the balance of '¥1000.00' will be shown instead. This
+2 -2
View File
@@ -23,7 +23,7 @@ It is very unlikely that issues specific to IE7 or earlier will be given any tim
To make your Angular application work on IE please make sure that:
1. You polyfill JSON.stringify if necessary (IE7 will need this). You can use
1. You polyfill JSON.stringify for IE7 and below. You can use
[JSON2](https://github.com/douglascrockford/JSON-js) or
[JSON3](http://bestiejs.github.com/json3/) polyfills for this.
<pre>
@@ -51,7 +51,7 @@ To make your Angular application work on IE please make sure that:
3. you **do not** use custom element tags such as `<ng:view>` (use the attribute version
`<div ng-view>` instead), or
4. if you **do use** custom element tags, then you must take these steps to make IE happy:
4. if you **do use** custom element tags, then you must take these steps to make IE 8 and below happy:
<pre>
<!doctype html>
<html xmlns:ng="http://angularjs.org" id="ng-app" ng-app="optionalModuleName">
-1
View File
@@ -73,7 +73,6 @@ directory.</p></li>
<p>Additionally install <a href="http://karma-runner.github.io/">Karma</a> and its plugins if you
don't have it already:</p>
<pre>
npm install -g karma
npm install
</pre></li>
<li><p>You will need an http server running on your system. Mac and Linux machines typically
+6 -2
View File
@@ -217,9 +217,13 @@ is located at `./config/karma.conf.js`).
* Create a new model property in the controller and bind to it from the template. For example:
$scope.hello = "Hello, World!"
$scope.name = "World"
Refresh your browser to make sure it says, "Hello, World!"
Then add a new binding to `index.html`:
<p>Hello, {{name}}!</p>
Refresh your browser and verifies that it says "Hello, World!".
* Create a repeater that constructs a simple table:
+1 -1
View File
@@ -121,7 +121,7 @@ view, Angular will use the `phone-list.html` template and the `PhoneListCtrl` co
We reused the `PhoneListCtrl` controller that we constructed in previous steps and we added a new,
empty `PhoneDetailCtrl` controller to the `app/js/controllers.js` file for the phone details view.
`$route.otherwise({redirectTo: '/phones'})` triggers a redirection to `/phones` when the browser
`$routeProvider.otherwise({redirectTo: '/phones'})` triggers a redirection to `/phones` when the browser
address doesn't match either of our routes.
Note the use of the `:phoneId` parameter in the second route declaration. The `$route` service uses
+1 -2
View File
@@ -293,8 +293,7 @@ Let's add another animation to our application. Switching to our `phone-detail.h
we see that we have a nice thumbnail swapper. By clicking on the thumbnails listed on the page,
the profile phone image changes. But how can we change this around to add animations?
Lets think about it first,
basically when you click on a thumbnail image, you're changing the state of the profile image to reflect the newly
Let's think about it first. Basically, when you click on a thumbnail image, you're changing the state of the profile image to reflect the newly
selected thumbnail image.
The best way to specify state changes within HTML is to use classes.
Much like before, how we used a CSS class to specify
+29
View File
@@ -1,5 +1,7 @@
var ngdoc = require('../src/ngdoc.js');
var DOM = require('../src/dom.js').DOM;
var gruntUtil = require('../../lib/grunt/utils.js');
describe('ngdoc', function() {
var Doc = ngdoc.Doc;
@@ -287,6 +289,33 @@ describe('ngdoc', function() {
});
});
describe('api section', function() {
it('should render a "view source" button with link to the source in master', function() {
var doc = new Doc({
id: 'ng.abc',
name: 'ng.abc',
section: 'api',
ngdoc: 'service',
file: 'fooService.js',
line: '333'
});
if (gruntUtil.getVersion().full.indexOf('-') === -1) {
expect(doc.html().match(/^(<a .*?<\/a>)/)[1]).toMatch(
/<a href="http:\/\/github\.com\/angular\/angular\.js\/tree\/v\d+\.\d+\.\d+\/fooService\.js#L333" class="view-source/
);
} else {
expect(doc.html().match(/^(<a .*?<\/a>)/)[1]).toMatch(
/<a href="http:\/\/github\.com\/angular\/angular\.js\/tree\/[a-z0-9]{7}\/fooService\.js#L333" class="view-source/
);
}
});
});
////////////////////////////////////////
describe('TAG', function() {
+16 -3
View File
@@ -6,7 +6,8 @@ var makeUnique = {
'script.js': true,
'unit.js': true,
'spec.js': true,
'scenario.js': true
'scenario.js': true,
'protractorTest.js': true
}
function ids(list) {
@@ -14,7 +15,7 @@ function ids(list) {
};
exports.Example = function(scenarios) {
exports.Example = function(scenarios, protractorTests) {
this.module = '';
this.deps = ['angular.js'];
this.html = [];
@@ -24,6 +25,8 @@ exports.Example = function(scenarios) {
this.unit = [];
this.scenario = [];
this.scenarios = scenarios;
this.protractorTest = [];
this.protractorTests = protractorTests;
}
exports.Example.prototype.setModule = function(module) {
@@ -44,6 +47,10 @@ exports.Example.prototype.addSource = function(name, content) {
var ext = name == 'scenario.js' ? 'scenario' : name.split('.')[1],
id = name;
if (name == 'protractorTest.js') {
ext = 'protractorTest';
}
if (makeUnique[name] && usedIds[id]) {
id = name + '-' + (seqCount++);
}
@@ -56,6 +63,9 @@ exports.Example.prototype.addSource = function(name, content) {
if (ext == 'scenario') {
this.scenarios.push(content);
}
if (ext == 'protractorTest') {
this.protractorTests.push(content);
}
};
exports.Example.prototype.enableAnimations = function() {
@@ -92,6 +102,7 @@ exports.Example.prototype.toHtmlEdit = function() {
out.push(' source-edit-json="' + ids(this.json) + '"');
out.push(' source-edit-unit="' + ids(this.unit) + '"');
out.push(' source-edit-scenario="' + ids(this.scenario) + '"');
out.push(' source-edit-protractor="' + ids(this.protractorTest) + '"');
out.push('></div>\n');
return out.join('');
};
@@ -107,6 +118,7 @@ exports.Example.prototype.toHtmlTabs = function() {
htmlTabs(this.json);
htmlTabs(this.unit);
htmlTabs(this.scenario);
htmlTabs(this.protractorTest);
out.push('</div>');
return out.join('');
@@ -119,7 +131,8 @@ exports.Example.prototype.toHtmlTabs = function() {
if (name === 'index.html') {
wrap = ' ng-html-wrap="' + self.module + ' ' + self.deps.join(' ') + '"';
}
if (name == 'scenario.js') name = 'End to end test';
if (name == 'scenario.js') name = 'ngScenario e2e test';
if (name == 'protractorTest.js') name = 'Protractor e2e test';
out.push(
'<div class="tab-pane" title="' + name + '">\n' +
+6
View File
@@ -17,6 +17,8 @@ writer.makeDir('build/docs/', true).then(function() {
return writer.makeDir('build/docs/components/bootstrap');
}).then(function() {
return writer.makeDir('build/docs/components/font-awesome');
}).then(function() {
return writer.makeDir('build/docs/e2etests');
}).then(function() {
console.log('Generating AngularJS Reference Documentation...');
return reader.collect();
@@ -53,6 +55,10 @@ writer.makeDir('build/docs/', true).then(function() {
var id = doc.id.replace('angular.Module', 'angular.IModule');
fileFutures.push(writer.output('partials/' + doc.section + '/' + id + '.html', doc.html()));
// If it has a sample Protractor test, output that as well.
if (doc.protractorTests.length) {
fileFutures.push(writer.output('ptore2e/' + doc.section + '/' + id + '_test.js', ngdoc.writeProtractorTest(doc)));
}
});
ngdoc.checkBrokenLinks(docs);
+23 -3
View File
@@ -35,6 +35,7 @@ var lookupMinerrMsg = function (doc) {
exports.trim = trim;
exports.metadata = metadata;
exports.scenarios = scenarios;
exports.writeProtractorTest = writeProtractorTest;
exports.merge = merge;
exports.checkBrokenLinks = checkBrokenLinks;
exports.Doc = Doc;
@@ -155,6 +156,7 @@ function Doc(text, file, line) {
this.line = line;
}
this.scenarios = this.scenarios || [];
this.protractorTests = this.protractorTests || [];
this.requires = this.requires || [];
this.param = this.param || [];
this.properties = this.properties || [];
@@ -292,7 +294,7 @@ Doc.prototype = {
replace(/<example(?:\s+module="([^"]*)")?(?:\s+deps="([^"]*)")?(\s+animations="true")?>([\s\S]*?)<\/example>/gmi,
function(_, module, deps, animations, content) {
var example = new Example(self.scenarios);
var example = new Example(self.scenarios, self.protractorTests);
if(animations) {
example.enableAnimations();
example.addDeps('angular-animate.js');
@@ -329,7 +331,7 @@ Doc.prototype = {
}).
replace(/^<doc:example(\s+[^>]*)?>([\s\S]*)<\/doc:example>/mi, function(_, attrs, content) {
var html, script, scenario,
example = new Example(self.scenarios);
example = new Example(self.scenarios, self.protractorTests);
example.setModule((attrs||'module=""').match(/^\s*module=["'](.*)["']\s*$/)[1]);
content.
@@ -347,6 +349,8 @@ Doc.prototype = {
}).
replace(/(<doc:scenario>)([\s\S]*)(<\/doc:scenario>)/mi, function(_, before, content){
example.addSource('scenario.js', content);
}).replace(/(<doc:protractor>)([\s\S]*)(<\/doc:protractor>)/mi, function(_, before, content){
example.addSource('protractorTest.js', content);
});
return placeholder(example.toHtml());
@@ -548,7 +552,7 @@ Doc.prototype = {
minerrMsg;
var gitTagFromFullVersion = function(version) {
var match = version.match(/-(\w{7})/);
var match = version.match(/sha\.(\w{7})/);
if (match) {
// git sha
@@ -1106,6 +1110,22 @@ function scenarios(docs){
}
}
function writeProtractorTest(doc){
var lines = [];
lines.push('describe("' + doc.section + '/' + doc.id + '", function() {');
lines.push(' beforeEach(function() {');
lines.push(' browser.get("index-nocache.html#!/' + doc.section + '/' + doc.id + '");');
lines.push(' });');
lines.push('');
doc.protractorTests.forEach(function(test){
lines.push(indentCode(trim(test), 2));
lines.push('');
});
lines.push('});');
lines.push('');
return lines.join('\n');
}
//////////////////////////////////////////////////////////
function metadata(docs){
+5
View File
@@ -167,6 +167,11 @@
margin-top: .5em;
}
.content h6 {
text-transform:none;
color:black;
}
ul.parameters > li > p,
.returns > p {
display: inline;
+1
View File
@@ -36,6 +36,7 @@ grunt test:unit --browsers $BROWSERS --reporters=dots,junit --no-colors --no-col
# END TO END TESTS #
grunt test:e2e --browsers $BROWSERS_E2E --reporters=dots,junit --no-colors --no-color
grunt test:protractor
# Promises/A+ TESTS #
grunt test:promises-aplus --no-color
+4 -3
View File
@@ -36,13 +36,14 @@ module.exports = function(config, specificOptions) {
},
'SL_Firefox': {
base: 'SauceLabs',
browserName: 'firefox'
browserName: 'firefox',
version: '26'
},
'SL_Safari': {
base: 'SauceLabs',
browserName: 'safari',
platform: 'Mac 10.8',
version: '6'
platform: 'OS X 10.9',
version: '7'
},
'SL_IE_8': {
base: 'SauceLabs',
+8
View File
@@ -61,6 +61,14 @@ module.exports = function(grunt) {
util.startKarma.call(util, this.data, false, this.async());
});
grunt.registerTask('webdriver', 'Update webdriver', function() {
util.updateWebdriver.call(util, this.async());
});
grunt.registerMultiTask('runprotractor', 'Run Protractor integration tests', function() {
util.startProtractor.call(util, this.data, this.async());
});
grunt.registerTask('collect-errors', 'Combine stripped error files', function () {
util.collectErrors();
});
+32
View File
@@ -84,6 +84,38 @@ module.exports = {
},
updateWebdriver: function(done){
var p = spawn('node', ['node_modules/protractor/bin/webdriver-manager', 'update']);
p.stdout.pipe(process.stdout);
p.stderr.pipe(process.stderr);
p.on('exit', function(code){
if(code !== 0) grunt.fail.warn('Webdriver failed to update');
done();
});
},
startProtractor: function(config, done){
var sauceUser = grunt.option('sauceUser');
var sauceKey = grunt.option('sauceKey');
var tunnelIdentifier = grunt.option('capabilities.tunnel-identifier');
var sauceBuild = grunt.option('capabilities.build');
var args = ['node_modules/protractor/bin/protractor', config];
if (sauceUser) args.push('--sauceUser=' + sauceUser);
if (sauceKey) args.push('--sauceKey=' + sauceKey);
if (tunnelIdentifier) args.push('--capabilities.tunnel-identifier=' + tunnelIdentifier);
if (sauceBuild) args.push('--capabilities.build=' + sauceBuild);
var p = spawn('node', args);
p.stdout.pipe(process.stdout);
p.stderr.pipe(process.stderr);
p.on('exit', function(code){
if(code !== 0) grunt.fail.warn('Protractor test(s) failed. Exit code: ' + code);
done();
});
},
wrap: function(src, name){
src.unshift('src/' + name + '.prefix');
src.push('src/' + name + '.suffix');
+13 -12
View File
@@ -1,8 +1,8 @@
{
"name": "angularjs",
"version": "1.2.7",
"cdnVersion": "1.2.6",
"codename": "emoji-clairvoyance",
"version": "1.2.8",
"cdnVersion": "1.2.7",
"codename": "interdimensional-cartography",
"repository": {
"type": "git",
"url": "https://github.com/angular/angular.js.git"
@@ -20,14 +20,16 @@
"q-io": "~1.10.6",
"qq": "~0.3.5",
"shelljs": "~0.2.6",
"karma": "0.11.11",
"karma-jasmine": "~0.1.0",
"karma-chrome-launcher": "~0.1.0",
"karma-firefox-launcher": "~0.1.0",
"karma-ng-scenario": "~0.1.0",
"karma-junit-reporter": "~0.2.1",
"karma-sauce-launcher": "~0.2.0",
"karma-script-launcher": "~0.1.0",
"karma": "0.11.12",
"karma-jasmine": "0.1.5",
"karma-chrome-launcher": "0.1.2",
"karma-firefox-launcher": "0.1.3",
"karma-ng-scenario": "0.1.0",
"karma-junit-reporter": "0.2.1",
"karma-sauce-launcher": "0.2.0",
"karma-script-launcher": "0.1.0",
"karma-browserstack-launcher": "0.0.7",
"protractor": "~0.16.1",
"yaml-js": "~0.0.8",
"marked": "0.2.9",
"rewire": "1.1.3",
@@ -39,7 +41,6 @@
"grunt-shell": "~0.4.0",
"semver": "~2.1.0",
"lodash": "~2.1.0",
"karma-browserstack-launcher": "git://github.com/karma-runner/karma-browserstack-launcher.git#master",
"browserstacktunnel-wrapper": "~1.1.1"
},
"licenses": [
+20
View File
@@ -0,0 +1,20 @@
exports.config = {
allScriptsTimeout: 11000,
specs: [
'build/docs/ptore2e/**/*.js',
'test/e2e/docsAppE2E.js'
],
capabilities: {
'browserName': 'chrome'
},
baseUrl: 'http://localhost:8000/build/docs/',
framework: 'jasmine',
jasmineNodeOpts: {
defaultTimeoutInterval: 30000
}
};
+54
View File
@@ -0,0 +1,54 @@
#!/bin/bash
# Script for updating angular-phonecat repo from current local build.
echo "#################################"
echo "## Update angular-phonecat ###"
echo "#################################"
ARG_DEFS=(
"--action=(prepare|publish)"
"[--no-test=(true|false)]"
)
function init {
TMP_DIR=$(resolveDir ../../tmp)
BUILD_DIR=$(resolveDir ../../build)
REPO_DIR=$TMP_DIR/angular-phonecat
NEW_VERSION=$(cat $BUILD_DIR/version.txt)
}
function prepare {
echo "-- Cloning angular-phonecat"
git clone git@github.com:angular/angular-phonecat.git $REPO_DIR
#
# copy the files from the build
#
echo "-- Updating angular-phonecat"
cd $REPO_DIR
./scripts/private/update-angular.sh $BUILD_DIR
# Test
if [[ $NO_TEST != "true" ]]; then
./scripts/private/test-all.sh
fi
# Generate demo
./scripts/private/snapshot-web.sh
git checkout gh-pages
git pull
rm -r step*
mv angular-phonecat-snapshots-web/step* .
git add step*
git commit -am "Angular $NEW_VERSION release"
}
function publish {
cd $REPO_DIR
echo "-- Pushing angular-phonecat"
git push origin master -f --tags
git push origin gh-pages -f
}
source $(dirname $0)/../utils.inc
+44
View File
@@ -0,0 +1,44 @@
#!/bin/bash
# Script for updating angular-seed repo from current local build.
echo "#################################"
echo "## Update angular-seed ###"
echo "#################################"
ARG_DEFS=(
"--action=(prepare|publish)"
"[--no-test=(true|false)]"
)
function init {
TMP_DIR=$(resolveDir ../../tmp)
BUILD_DIR=$(resolveDir ../../build)
REPO_DIR=$TMP_DIR/angular-seed
NEW_VERSION=$(cat $BUILD_DIR/version.txt)
}
function prepare {
echo "-- Cloning angular-seed"
git clone git@github.com:angular/angular-seed.git $REPO_DIR
#
# copy the files from the build
#
echo "-- Updating angular-seed"
cd $REPO_DIR
./scripts/update-angular.sh $BUILD_DIR
# Test
if [[ $NO_TEST != "true" ]]; then
./scripts/test-all.sh
fi
}
function publish {
cd $REPO_DIR
echo "-- Pushing angular-seed"
git push origin master
}
source $(dirname $0)/../utils.inc
+20
View File
@@ -0,0 +1,20 @@
#!/bin/bash
echo "############################################"
echo "## Remove "-snapshot" from version ########"
echo "############################################"
ARG_DEFS=()
function run {
cd ../..
replaceJsonProp "package.json" "version" "(.*)-snapshot" "\2"
VERSION=$(readJsonProp "package.json" "version")
git add package.json
git commit -m "chore(release): cut v$VERSION release"
git tag -m "v$VERSION" v$VERSION
}
source $(dirname $0)/../utils.inc
+24
View File
@@ -0,0 +1,24 @@
#!/bin/bash
echo "############################################"
echo "## Increment version, add "-snapshot" and set version name ##"
echo "############################################"
ARG_DEFS=(
"--next-version-type=(patch|minor|major)"
"--next-version-name=(.+)"
)
function run {
cd ../..
grunt bump:$NEXT_VERSION_TYPE
NEXT_VERSION=$(readJsonProp "package.json" "version")
replaceJsonProp "package.json" "version" "(.*)" "\2-snapshot"
replaceJsonProp "package.json" "codename" ".*" "$NEXT_VERSION_NAME"
git add package.json
git commit -m "chore(release): start v$NEXT_VERSION ($NEXT_VERSION)"
}
source $(dirname $0)/../utils.inc
+30
View File
@@ -0,0 +1,30 @@
#!/bin/sh
# Script for updating cdnVersion of angular.js
echo "###################################"
echo "## Update angular.js cdnVersion ###"
echo "###################################"
ARG_DEFS=(
"--cdn-version=(.*)"
"--action=(prepare|publish)"
)
function init {
cd ../..
}
function prepare {
replaceJsonProp "package.json" "cdnVersion" "(.*)" "$CDN_VERSION"
git add package.json
git commit -m "chore(release): update cdn version"
}
function publish {
BRANCH=$(git rev-parse --abbrev-ref HEAD)
# push the commits to github
git push origin $BRANCH
}
source $(dirname $0)/../utils.inc
+42
View File
@@ -0,0 +1,42 @@
#!/bin/bash
# Script for updating angular.js repo from current local build.
echo "#################################"
echo "## Update angular.js ###"
echo "#################################"
ARG_DEFS=(
"--action=(prepare|publish)"
"--next-version-type=(patch|minor|major)"
"--next-version-name=(.+)"
"[--no-test=(true|false)]"
)
function init {
cd ../..
}
function prepare() {
./scripts/angular.js/finalize-version.sh
# Build
if [[ $NO_TEST == "true" ]]; then
npm install --color false
grunt ci-checks package --no-color
else
./jenkins_build.sh
fi
./scripts/angular.js/initialize-new-version.sh --next-version-type=$NEXT_VERSION_TYPE --next-version-name=$NEXT_VERSION_NAME
}
function publish() {
BRANCH=$(git rev-parse --abbrev-ref HEAD)
# push the commits to github
git push origin $BRANCH
# push the release tag
git push origin v`cat build/version.txt`
}
source $(dirname $0)/../utils.inc
+47
View File
@@ -0,0 +1,47 @@
#!/bin/sh
# Script for updating angularjs.org repo
echo "#################################"
echo "##### Update angularjs.org ######"
echo "#################################"
ARG_DEFS=(
"--action=(prepare|publish)"
"--cdn-version=(.*)"
)
function init {
TMP_DIR=$(resolveDir ../../tmp)
REPO_DIR=$TMP_DIR/angularjs.org
}
function prepare {
echo "-- Cloning angularjs.org"
git clone git@github.com:angular/angularjs.org.git $REPO_DIR
#
# update files
#
echo "-- Updating angularjs.org"
cd $REPO_DIR
VERSION_REGEX="[a-z0-9\-\.\+]+"
replaceInFile "index.html" "(ajax\/libs\/angularjs\/)$VERSION_REGEX" "\1$CDN_VERSION"
replaceInFile "index.html" "(<span class=\"version\">[^<]*<span>)$VERSION_REGEX" "\1$CDN_VERSION"
replaceInFile "index.html" "(code.angularjs.org\/)$VERSION_REGEX" "\1$CDN_VERSION"
replaceInFile "js/homepage.js" "($scope.CURRENT_STABLE_VERSION[ ]*=[ ]*')$VERSION_REGEX" "\1$CDN_VERSION"
replaceInFile "js/homepage.js" "($scope.CURRENT_UNSTABLE_VERSION[ ]*=[ ]*')$VERSION_REGEX" "\1$CDN_VERSION"
git add index.html
git add js/homepage.js
git commit -m "update(version): update angular version to $CDN_VERSION"
}
function publish {
cd $REPO_DIR
echo "-- Pushing angularjs.org"
git push origin master
}
source $(dirname $0)/../utils.inc
-15
View File
@@ -1,15 +0,0 @@
# Angular Bower Script
Script for updating the Angular bower repos from current local build.
## Instructions
`grunt package`: Build angular locally
```shell
./publish.sh
```
## License
MIT
+87 -74
View File
@@ -1,88 +1,101 @@
#!/bin/bash
# Script for updating the Angular bower repos from current local build.
echo "#################################"
echo "#### Update bower ###############"
echo "#################################"
# Enable tracing and exit on first failure
set -xe
# Normalize working dir to script dir
cd `dirname $0`
SCRIPT_DIR=`pwd`
TMP_DIR=../../tmp
BUILD_DIR=../../build
NEW_VERSION=`cat $BUILD_DIR/version.txt`
REPOS=(
angular \
angular-animate \
angular-cookies \
angular-i18n \
angular-loader \
angular-mocks \
angular-route \
angular-resource \
angular-sanitize \
angular-scenario \
angular-touch \
ARG_DEFS=(
"--action=(prepare|publish)"
)
#
# clone repos
#
for repo in "${REPOS[@]}"
do
echo "-- Cloning bower-$repo"
git clone git@github.com:angular/bower-$repo.git $TMP_DIR/bower-$repo
done
function init {
TMP_DIR=$(resolveDir ../../tmp)
BUILD_DIR=$(resolveDir ../../build)
NEW_VERSION=$(cat $BUILD_DIR/version.txt)
REPOS=(
angular
angular-animate
angular-cookies
angular-i18n
angular-loader
angular-mocks
angular-route
angular-resource
angular-sanitize
angular-scenario
angular-touch
)
}
#
# move the files from the build
#
for repo in "${REPOS[@]}"
do
if [ -f $BUILD_DIR/$repo.js ] # ignore i18l
then
echo "-- Updating files in bower-$repo"
cd $TMP_DIR/bower-$repo
git reset --hard HEAD
git checkout master
git fetch --all
git reset --hard origin/master
cd $SCRIPT_DIR
cp $BUILD_DIR/$repo.* $TMP_DIR/bower-$repo/
fi
done
# move i18n files
cp $BUILD_DIR/i18n/*.js $TMP_DIR/bower-angular-i18n/
# move csp.css
cp $BUILD_DIR/angular-csp.css $TMP_DIR/bower-angular
function prepare {
#
# clone repos
#
for repo in "${REPOS[@]}"
do
echo "-- Cloning bower-$repo"
git clone git@github.com:angular/bower-$repo.git $TMP_DIR/bower-$repo
done
#
# update bower.json
# tag each repo
#
#
# move the files from the build
#
for repo in "${REPOS[@]}"
do
echo "-- Updating version in bower-$repo to $NEW_VERSION"
cd $TMP_DIR/bower-$repo
sed -i .tmp -E 's/"(version)":[ ]*".*"/"\1": "'$NEW_VERSION'"/g' bower.json
sed -i .tmp -E 's/"(angular.*)":[ ]*".*"/"\1": "'$NEW_VERSION'"/g' bower.json
# delete tmp files
rm *.tmp
git add -A
for repo in "${REPOS[@]}"
do
if [ -f $BUILD_DIR/$repo.js ] # ignore i18l
then
echo "-- Updating files in bower-$repo"
cd $TMP_DIR/bower-$repo
git reset --hard HEAD
git checkout master
git fetch --all
git reset --hard origin/master
cd $SCRIPT_DIR
cp $BUILD_DIR/$repo.* $TMP_DIR/bower-$repo/
fi
done
echo "-- Committing, tagging and pushing bower-$repo"
git commit -m "v$NEW_VERSION"
git tag v$NEW_VERSION
git push origin master
git push origin v$NEW_VERSION
cd $SCRIPT_DIR
done
# move i18n files
cp $BUILD_DIR/i18n/*.js $TMP_DIR/bower-angular-i18n/
# move csp.css
cp $BUILD_DIR/angular-csp.css $TMP_DIR/bower-angular
#
# update bower.json
# tag each repo
#
for repo in "${REPOS[@]}"
do
echo "-- Updating version in bower-$repo to $NEW_VERSION"
cd $TMP_DIR/bower-$repo
replaceJsonProp "bower.json" "version" ".*" "$NEW_VERSION"
replaceJsonProp "bower.json" "angular.*" ".*" "$NEW_VERSION"
git add -A
echo "-- Committing and tagging bower-$repo"
git commit -m "v$NEW_VERSION"
git tag v$NEW_VERSION
cd $SCRIPT_DIR
done
}
function publish {
for repo in "${REPOS[@]}"
do
echo "-- Pushing bower-$repo"
cd $TMP_DIR/bower-$repo
git push origin master
git push origin v$NEW_VERSION
cd $SCRIPT_DIR
done
}
source $(dirname $0)/../utils.inc
-18
View File
@@ -1,18 +0,0 @@
# code.angular.js.org Script
Script for updating code.angularjs.org repo from current local build.
Note: For a snapshot build, this will fetch the data from the ci server
and NOT take the local build!
## Instructions
`grunt package`: Build angular locally
```shell
./publish.sh
```
## License
MIT
+59 -48
View File
@@ -1,62 +1,73 @@
#!/bin/bash
# Script for updating code.angularjs.org repo from current local build.
echo "#################################"
echo "## Update code.angular.js.org ###"
echo "#################################"
# Enable tracing and exit on first failure
set -xe
# Normalize working dir to script dir
cd `dirname $0`
ARG_DEFS=(
"--action=(prepare|publish)"
)
TMP_DIR=../../tmp
REPO_DIR=$TMP_DIR/code.angularjs.org
BUILD_DIR=../../build
SCRIPT_DIR=`pwd`
NEW_VERSION=`cat $BUILD_DIR/version.txt`
function init {
TMP_DIR=$(resolveDir ../../tmp)
BUILD_DIR=$(resolveDir ../../build)
REPO_DIR=$TMP_DIR/code.angularjs.org
NEW_VERSION=$(cat $BUILD_DIR/version.txt)
if [[ "$NEW_VERSION" =~ sha ]]; then
IS_SNAPSHOT_BUILD=true
else
IS_SNAPSHOT_BUILD=
fi
}
#
# Snapshot builds are kept in a temp directory in code.angularjs.org
# that is filled by calling a php script there.
#
if [[ "$NEW_VERSION" =~ sha ]] ;then
echo "-- updating snapshot version"
curl -G --data-urlencode "ver=$NEW_VERSION" http://code.angularjs.org/fetchLatestSnapshot.php
exit 0;
fi
function prepare {
if [[ $IS_SNAPSHOT_BUILD ]]; then
# nothing to prepare for snapshot builds as
# code.angularjs.org will fetch the current snapshot from
# the build server during publish
exit 0
fi
#
# clone
#
echo "-- Cloning code.angularjs.org"
git clone git@github.com:angular/code.angularjs.org.git $REPO_DIR
echo "-- Cloning code.angularjs.org"
git clone git@github.com:angular/code.angularjs.org.git $REPO_DIR
#
# copy the files from the build
#
echo "-- Updating code.angularjs.org"
mkdir $REPO_DIR/$NEW_VERSION
cd $REPO_DIR
git reset --hard HEAD
git checkout master
git fetch --all
git reset --hard origin/master
cd $SCRIPT_DIR
cp -r $BUILD_DIR/* $REPO_DIR/$NEW_VERSION/
#
# copy the files from the build
#
#
# commit
#
echo "-- Committing code.angularjs.org"
cd $REPO_DIR
git add -A
git commit -m "v$NEW_VERSION"
}
echo "-- Updating code.angularjs.org"
mkdir $REPO_DIR/$NEW_VERSION
cd $REPO_DIR
git reset --hard HEAD
git checkout master
git fetch --all
git reset --hard origin/master
cd $SCRIPT_DIR
cp -r $BUILD_DIR/* $REPO_DIR/$NEW_VERSION/
function publish {
if [[ $IS_SNAPSHOT_BUILD ]]; then
echo "-- Updating snapshot version"
curl -G --data-urlencode "ver=$NEW_VERSION" http://code.angularjs.org/fetchLatestSnapshot.php
exit 0;
fi
#
# commit and push
#
echo "-- Committing and pushing code.angularjs.org"
cd $REPO_DIR
git add -A
git commit -m "v$NEW_VERSION"
git push origin master
cd $SCRIPT_DIR
cd $REPO_DIR
echo "-- Pushing code.angularjs.org"
git push origin master
#
# refresh code.angularjs.org from github
#
curl http://code.angularjs.org/gitFetchSite.php
echo "-- Refreshing code.angularjs.org"
curl http://code.angularjs.org/gitFetchSite.php
}
source $(dirname $0)/../utils.inc
-25
View File
@@ -1,25 +0,0 @@
#!/bin/bash
echo "############################################"
echo "## Increment version and add "-snapshot" ##"
echo "############################################"
if [ "$1" != "patch" -a "$1" != "minor" -a "$1" != "major" ]; then
echo "Please specify the next version type: patch|minor|major"
exit 1
fi
BUMP_TYPE=$1
# Enable tracing and exit on first failure
set -xe
# Normalize working dir to script dir
cd `dirname $0`/../..
echo "-- increment version "
grunt bump:$BUMP_TYPE
NEXT_VERSION=`sed -En 's/.*"version"[ ]*:[ ]*"(.*)".*/\1/p' package.json`
sed -i .tmp -E 's/"version": "(.*)"/"version": "\1-snapshot"/' package.json
echo "-- new version: `grep '"version"' package.json`"
echo "-- commit"
git add package.json
git commit -m "chore(release): start v$NEXT_VERSION"
-20
View File
@@ -1,20 +0,0 @@
#!/bin/bash
echo "############################################"
echo "## Remove "-snapshot" from version ########"
echo "############################################"
# Enable tracing and exit on first failure
set -xe
# Normalize working dir to script dir
cd `dirname $0`/../..
echo "-- old version: `grep '"version"' package.json`"
sed -i .tmp -E 's/"version": "(.*)-snapshot"/"version": "\1"/' package.json
VERSION=`sed -En 's/.*"version"[ ]*:[ ]*"(.*)".*/\1/p' package.json`
echo "-- local version: $VERSION"
echo "-- commit and tag with v$VERSION"
git add package.json
git commit -m "chore(release): cut v$VERSION release"
git tag -m "v$VERSION" v$VERSION
+37 -15
View File
@@ -4,22 +4,44 @@ echo "#################################"
echo "#### Update master ##############"
echo "#################################"
# Enable tracing and exit on first failure
set -xe
ARG_DEFS=(
"[--no-test=(true|false)]"
)
cd `dirname $0`/../..
function init {
if [[ ! $VERBOSE ]]; then
VERBOSE=false
fi
VERBOSE_ARG="--verbose=$VERBOSE"
}
echo "#################################"
echo "#### Jenkins Build ############"
echo "#################################"
./jenkins_build.sh
function build {
cd ../..
echo "#################################"
echo "## Update code.angular.js.org ###"
echo "#################################"
./scripts/code.angularjs.org/publish.sh
if [[ $NO_TEST == "true" ]]; then
npm install --color false
grunt ci-checks package --no-color
else
./jenkins_build.sh
fi
echo "#################################"
echo "#### Update bower ###############"
echo "#################################"
./scripts/bower/publish.sh
cd $SCRIPT_DIR
}
function phase {
ACTION_ARG="--action=$1"
../code.angularjs.org/publish.sh $ACTION_ARG $VERBOSE_ARG
../bower/publish.sh $ACTION_ARG $VERBOSE_ARG
}
function run {
build
# First prepare all scripts (build, test, commit, tag, ...),
# so we are sure everything is all right
phase prepare
# only then publish to github
phase publish
}
source $(dirname $0)/../utils.inc
+41
View File
@@ -0,0 +1,41 @@
#!/bin/sh
ARG_DEFS=(
# require the git dryrun flag so the script can't be run without
# thinking about this!
"--git-push-dryrun=(true|false)"
"--cdn-version=(.*)"
)
function init {
NG_ARGS=("$@")
if [[ ! $VERBOSE ]]; then
VERBOSE=false
fi
VERBOSE_ARG="--verbose=$VERBOSE"
}
function phase {
ACTION_ARG="--action=$1"
CDN_VERSION_ARG="--cdn-version=$CDN_VERSION"
./scripts/angular.js/publish-cdn-version.sh $ACTION_ARG $CDN_VERSION_ARG $VERBOSE_ARG
./scripts/angularjs.org/publish.sh $ACTION_ARG $CDN_VERSION_ARG $VERBOSE_ARG
}
function checkCdn {
STATUS=$(curl http://ajax.googleapis.com/ajax/libs/angularjs/$CDN_VERSION/angular.min.js --write-out '%{http_code}' -o /dev/null -silent)
if [[ $STATUS != 200 ]]; then
echo "Could not find release $CDN_VERSION on CDN"
exit 1
fi
}
function run {
cd ../..
checkCdn
phase prepare
phase publish
}
source $(dirname $0)/../utils.inc
+36 -34
View File
@@ -4,41 +4,43 @@ echo "#################################"
echo "#### Cut release ################"
echo "#################################"
if [ "$1" != "patch" -a "$1" != "minor" -a "$1" != "major" ]; then
echo "Please specify the next version type: patch|minor|major"
exit 1
fi
BUMP_TYPE=$1
ARG_DEFS=(
"--next-version-type=(patch|minor|major)"
"--next-version-name=(.+)"
# require the git dryrun flag so the script can't be run without
# thinking about this!
"--git-push-dryrun=(true|false)"
"[--no-test=(true|false)]"
)
# Enable tracing and exit on first failure
set -xe
function init {
NG_ARGS=("$@")
if [[ ! $VERBOSE ]]; then
VERBOSE=false
fi
if [[ ! $NO_TEST ]]; then
NO_TEST=false
fi
VERBOSE_ARG="--verbose=$VERBOSE"
NO_TEST_ARG="--no_test=$NO_TEST"
}
# Jump onto the master branch and make sure we are using the latest
git checkout -f master
git merge --ff-only origin/master
function phase {
ACTION_ARG="--action=$1"
../angular.js/publish.sh $ACTION_ARG $VERBOSE_ARG $NO_TEST_ARG \
--next-version-type=$NEXT_VERSION_TYPE --next-version-name=$NEXT_VERSION_NAME
../code.angularjs.org/publish.sh $ACTION_ARG $VERBOSE_ARG
../bower/publish.sh $ACTION_ARG $VERBOSE_ARG
../angular-seed/publish.sh $ACTION_ARG $VERBOSE_ARG $NO_TEST_ARG
../angular-phonecat/publish.sh $ACTION_ARG $VERBOSE_ARG $NO_TEST_ARG
}
function run {
# First prepare all scripts (build, test, commit, tag, ...),
# so we are sure everything is all right
phase prepare
# only then publish to github
phase publish
}
# Normalize working dir to script dir
cd `dirname $0`/../..
# Bump versions: remove "-snapshot" suffix
./scripts/jenkins/bump-remove-snapshot.sh
# Build
./jenkins_build.sh
# Bump versions: Increment version and add "-snapshot"
./scripts/jenkins/bump-increment.sh $BUMP_TYPE
echo "-- push to Github"
# push the commits to github
git push origin master
# push the release tag
git push origin v`cat build/version.txt`
# Update code.angularjs.org
./scripts/code.angularjs.org/publish.sh
# Update bower
./scripts/bower/publish.sh
source $(dirname $0)/../utils.inc
+4
View File
@@ -11,6 +11,10 @@ if [ $JOB = "unit" ]; then
grunt test:unit --browsers SL_Chrome,SL_Safari,SL_Firefox,SL_IE_8,SL_IE_9,SL_IE_10,SL_IE_11 --reporters dots
elif [ $JOB = "e2e" ]; then
grunt test:e2e --browsers SL_Chrome --reporters dots
grunt test:protractor --sauceUser $SAUCE_USERNAME \
--sauceKey $SAUCE_ACCESS_KEY \
--capabilities.tunnel-identifier=$TRAVIS_JOB_NUMBER \
--capabilities.build=$TRAVIS_BUILD_NUMBER
else
echo "Unknown job type. Please set JOB=unit or JOB=e2e."
fi
+279
View File
@@ -0,0 +1,279 @@
# This file provides:
# - a default control flow
# * initializes the environment
# * able to mock "git push" in your script and in all sub scripts
# * call a function in your script based on the arguments
# - named argument parsing and automatic generation of the "usage" for your script
# - intercepting "git push" in your script and all sub scripts
# - utility functions
#
# Usage:
# - define the variable ARGS_DEF (see below) with the arguments for your script
# - include this file using `source utils.inc` at the end of your script.
#
# Default control flow:
# 0. Set the current directory to the directory of the script. By this
# the script can be called from anywhere.
# 1. Parse the named arguments
# 2. If the parameter "git_push_dryrun" is set, all calls the `git push` in this script
# or in child scripts will be intercepted so that the `--dry-run` and `--porcelain` is added
# to show what the push would do but not actually do it.
# 3. If the parameter "verbose" is set, the `-x` flag will be set in bash.
# 4. The function "init" will be called if it exists
# 5. If the parameter "action" is set, it will call the function with the name of that parameter.
# Otherwise the function "run" will be called.
#
# Named Argument Parsing:
# - The variable ARGS_DEF defines the valid command arguments
# * Required args syntax: --paramName=paramRegex
# * Optional args syntax: [--paramName=paramRegex]
# * e.g. ARG_DEFS=("--required_param=(.+)" "[--optional_param=(.+)]")
# - Checks that:
# * all arguments match to an entry in ARGS_DEF
# * all required arguments are present
# * all arguments match their regex
# - Afterwards, every paramter value will be stored in a variable
# with the name of the parameter in upper case (with dash converted to underscore).
#
# Special arguments that are always available:
# - "--action=.*": This parameter will be used to dispatch to a function with that name when the
# script is started
# - "--git_push_dryrun=true": This will intercept all calls to `git push` in this script
# or in child scripts so that the `--dry-run` and `--porcelain` is added
# to show what the push would do but not actually do it.
# - "--verbose=true": This will set the `-x` flag in bash so that all calls will be logged
#
# Utility functions:
# - readJsonProp
# - replaceJsonProp
# - resolveDir
# - getVar
# - serVar
# - isFunction
# always stop on errors
set -e
function usage {
echo "Usage: ${0} ${ARG_DEFS[@]}"
exit 1
}
function parseArgs {
local REQUIRED_ARG_NAMES=()
# -- helper functions
function varName {
# everything to upper case and dash to underscore
echo ${1//-/_} | tr '[:lower:]' '[:upper:]'
}
function readArgDefs {
local ARG_DEF
local AD_OPTIONAL
local AD_NAME
local AD_RE
# -- helper functions
function parseArgDef {
local ARG_DEF_REGEX="(\[?)--([^=]+)=(.*)"
if [[ ! $1 =~ $ARG_DEF_REGEX ]]; then
echo "Internal error: arg def has wrong format: $ARG_DEF"
exit 1
fi
AD_OPTIONAL="${BASH_REMATCH[1]}"
AD_NAME="${BASH_REMATCH[2]}"
AD_RE="${BASH_REMATCH[3]}"
if [[ $AD_OPTIONAL ]]; then
# Remove last bracket for optional args.
# Can't put this into the ARG_DEF_REGEX somehow...
AD_RE=${AD_RE%?}
fi
}
# -- run
for ARG_DEF in "${ARG_DEFS[@]}"
do
parseArgDef $ARG_DEF
local AD_NAME_UPPER=$(varName $AD_NAME)
setVar "${AD_NAME_UPPER}_OPTIONAL" "$AD_OPTIONAL"
setVar "${AD_NAME_UPPER}_RE" "$AD_RE"
if [[ ! $AD_OPTIONAL ]]; then
REQUIRED_ARG_NAMES+=($AD_NAME)
fi
done
}
function readAndValidateArgs {
local ARG_NAME
local ARG_VALUE
local ARG_NAME_UPPER
# -- helper functions
function parseArg {
local ARG_REGEX="--([^=]+)=?(.*)"
if [[ ! $1 =~ $ARG_REGEX ]]; then
echo "Can't parse argument $i"
usage
fi
ARG_NAME="${BASH_REMATCH[1]}"
ARG_VALUE="${BASH_REMATCH[2]}"
ARG_NAME_UPPER=$(varName $ARG_NAME)
}
function validateArg {
local AD_RE=$(getVar ${ARG_NAME_UPPER}_RE)
if [[ ! $AD_RE ]]; then
echo "Unknown option: $ARG_NAME"
usage
fi
if [[ ! $ARG_VALUE =~ ^${AD_RE}$ ]]; then
echo "Wrong format: $ARG_NAME"
usage;
fi
# validate that the "action" option points to a valid function
if [[ $ARG_NAME == "action" ]] && ! isFunction $ARG_VALUE; then
echo "No action $ARG_VALUE defined in this script"
usage;
fi
}
# -- run
for i in "$@"
do
parseArg $i
validateArg
setVar "${ARG_NAME_UPPER}" "$ARG_VALUE"
done
}
function checkMissingArgs {
local ARG_NAME
for ARG_NAME in "${REQUIRED_ARG_NAMES[@]}"
do
ARG_VALUE=$(getVar $(varName $ARG_NAME))
if [[ ! $ARG_VALUE ]]; then
echo "Missing: $ARG_NAME"
usage;
fi
done
}
# -- run
readArgDefs
readAndValidateArgs "$@"
checkMissingArgs
}
# getVar(varName)
function getVar {
echo ${!1}
}
# setVar(varName, varValue)
function setVar {
eval "$1=\"$2\""
}
# isFunction(name)
# - to be used in an if, so return 0 if successful and 1 if not!
function isFunction {
if [[ $(type -t $1) == "function" ]]; then
return 0
else
return 1
fi
}
# readJsonProp(jsonFile, property)
# - restriction: property needs to be on an own line!
function readJsonProp {
echo $(sed -En 's/.*"'$2'"[ ]*:[ ]*"(.*)".*/\1/p' $1)
}
# replaceJsonProp(jsonFile, propertyRegex, valueRegex, replacePattern)
# - note: propertyRegex will be automatically placed into a
# capturing group! -> all other groups start at index 2!
function replaceJsonProp {
replaceInFile $1 '"('$2')"[ ]*:[ ]*"'$3'"' '"\1": "'$4'"'
}
# replaceInFile(file, findPattern, replacePattern)
function replaceInFile {
sed -i .tmp -E "s/$2/$3/" $1
rm $1.tmp
}
# resolveDir(relativeDir)
# - resolves a directory relative to the current script
function resolveDir {
echo $(cd $SCRIPT_DIR; cd $1; pwd)
}
function git_push_dryrun_proxy {
echo "## git push dryrun proxy enabled!"
export ORIGIN_GIT=$(which git)
function git {
local ARGS=("$@")
local RC
if [[ $1 == "push" ]]; then
ARGS+=("--dry-run" "--porcelain")
echo "####### START GIT PUSH DRYRUN #######"
echo "${ARGS[@]}"
fi
if [[ $1 == "commit" ]]; then
echo "${ARGS[@]}"
fi
$ORIGIN_GIT "${ARGS[@]}"
RC=$?
if [[ $1 == "push" ]]; then
echo "####### END GIT PUSH DRYRUN #######"
fi
return $RC
}
export -f git
}
function main {
# normalize the working dir to the directory of the script
cd $(dirname $0);SCRIPT_DIR=$(pwd)
ARG_DEFS+=("[--git-push-dryrun=(true|false)]" "[--verbose=(true|false)]")
parseArgs "$@"
# --git_push_dryrun argument
if [[ $GIT_PUSH_DRYRUN == "true" ]]; then
git_push_dryrun_proxy
fi
# --verbose argument
if [[ $VERBOSE == "true" ]]; then
set -x
fi
if isFunction init; then
init "$@"
fi
# jump to the function denoted by the --action argument,
# otherwise call the "run" function
if [[ $ACTION ]]; then
$ACTION "$@"
else
run "$@"
fi
}
main "$@"
+1 -1
View File
@@ -1957,7 +1957,7 @@ function directiveNormalize(name) {
*
*
* @param {string} name Normalized element attribute name of the property to modify. The name is
* revers translated using the {@link ng.$compile.directive.Attributes#$attr $attr}
* reverse-translated using the {@link ng.$compile.directive.Attributes#$attr $attr}
* property to the original name.
* @param {string} value Value to set the attribute to. The value can be an interpolated string.
*/
+4 -6
View File
@@ -336,12 +336,10 @@ forEach(BOOLEAN_ATTR, function(propName, attrName) {
ngAttributeAliasDirectives[normalized] = function() {
return {
priority: 100,
compile: function() {
return function(scope, element, attr) {
scope.$watch(attr[normalized], function ngBooleanAttrWatchAction(value) {
attr.$set(attrName, !!value);
});
};
link: function(scope, element, attr) {
scope.$watch(attr[normalized], function ngBooleanAttrWatchAction(value) {
attr.$set(attrName, !!value);
});
}
};
};
+4 -4
View File
@@ -249,10 +249,10 @@ function FormController(element, attrs) {
*
*
* # CSS classes
* - `ng-valid` Is set if the form is valid.
* - `ng-invalid` Is set if the form is invalid.
* - `ng-pristine` Is set if the form is pristine.
* - `ng-dirty` Is set if the form is dirty.
* - `ng-valid` is set if the form is valid.
* - `ng-invalid` is set if the form is invalid.
* - `ng-pristine` is set if the form is pristine.
* - `ng-dirty` is set if the form is dirty.
*
*
* # Submitting a form and preventing the default action
+18 -62
View File
@@ -390,6 +390,12 @@ var inputType = {
'reset': noop
};
// A helper function to call $setValidity and return the value / undefined,
// a pattern that is repeated a lot in the input validation logic.
function validate(ctrl, validatorName, validity, value){
ctrl.$setValidity(validatorName, validity);
return validity ? value : undefined;
}
function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
// In composition mode, users are still inputing intermediate text buffer,
@@ -474,22 +480,15 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
patternValidator,
match;
var validate = function(regexp, value) {
if (ctrl.$isEmpty(value) || regexp.test(value)) {
ctrl.$setValidity('pattern', true);
return value;
} else {
ctrl.$setValidity('pattern', false);
return undefined;
}
};
if (pattern) {
var validateRegex = function(regexp, value) {
return validate(ctrl, 'pattern', ctrl.$isEmpty(value) || regexp.test(value), value);
};
match = pattern.match(/^\/(.*)\/([gim]*)$/);
if (match) {
pattern = new RegExp(match[1], match[2]);
patternValidator = function(value) {
return validate(pattern, value);
return validateRegex(pattern, value);
};
} else {
patternValidator = function(value) {
@@ -500,7 +499,7 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
'Expected {0} to be a RegExp but was {1}. Element: {2}', pattern,
patternObj, startingTag(element));
}
return validate(patternObj, value);
return validateRegex(patternObj, value);
};
}
@@ -512,13 +511,7 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
if (attr.ngMinlength) {
var minlength = int(attr.ngMinlength);
var minLengthValidator = function(value) {
if (!ctrl.$isEmpty(value) && value.length < minlength) {
ctrl.$setValidity('minlength', false);
return undefined;
} else {
ctrl.$setValidity('minlength', true);
return value;
}
return validate(ctrl, 'minlength', ctrl.$isEmpty(value) || value.length >= minlength, value);
};
ctrl.$parsers.push(minLengthValidator);
@@ -529,13 +522,7 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
if (attr.ngMaxlength) {
var maxlength = int(attr.ngMaxlength);
var maxLengthValidator = function(value) {
if (!ctrl.$isEmpty(value) && value.length > maxlength) {
ctrl.$setValidity('maxlength', false);
return undefined;
} else {
ctrl.$setValidity('maxlength', true);
return value;
}
return validate(ctrl, 'maxlength', ctrl.$isEmpty(value) || value.length <= maxlength, value);
};
ctrl.$parsers.push(maxLengthValidator);
@@ -564,13 +551,7 @@ function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
if (attr.min) {
var minValidator = function(value) {
var min = parseFloat(attr.min);
if (!ctrl.$isEmpty(value) && value < min) {
ctrl.$setValidity('min', false);
return undefined;
} else {
ctrl.$setValidity('min', true);
return value;
}
return validate(ctrl, 'min', ctrl.$isEmpty(value) || value >= min, value);
};
ctrl.$parsers.push(minValidator);
@@ -580,13 +561,7 @@ function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
if (attr.max) {
var maxValidator = function(value) {
var max = parseFloat(attr.max);
if (!ctrl.$isEmpty(value) && value > max) {
ctrl.$setValidity('max', false);
return undefined;
} else {
ctrl.$setValidity('max', true);
return value;
}
return validate(ctrl, 'max', ctrl.$isEmpty(value) || value <= max, value);
};
ctrl.$parsers.push(maxValidator);
@@ -594,14 +569,7 @@ function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
}
ctrl.$formatters.push(function(value) {
if (ctrl.$isEmpty(value) || isNumber(value)) {
ctrl.$setValidity('number', true);
return value;
} else {
ctrl.$setValidity('number', false);
return undefined;
}
return validate(ctrl, 'number', ctrl.$isEmpty(value) || isNumber(value), value);
});
}
@@ -609,13 +577,7 @@ function urlInputType(scope, element, attr, ctrl, $sniffer, $browser) {
textInputType(scope, element, attr, ctrl, $sniffer, $browser);
var urlValidator = function(value) {
if (ctrl.$isEmpty(value) || URL_REGEXP.test(value)) {
ctrl.$setValidity('url', true);
return value;
} else {
ctrl.$setValidity('url', false);
return undefined;
}
return validate(ctrl, 'url', ctrl.$isEmpty(value) || URL_REGEXP.test(value), value);
};
ctrl.$formatters.push(urlValidator);
@@ -626,13 +588,7 @@ function emailInputType(scope, element, attr, ctrl, $sniffer, $browser) {
textInputType(scope, element, attr, ctrl, $sniffer, $browser);
var emailValidator = function(value) {
if (ctrl.$isEmpty(value) || EMAIL_REGEXP.test(value)) {
ctrl.$setValidity('email', true);
return value;
} else {
ctrl.$setValidity('email', false);
return undefined;
}
return validate(ctrl, 'email', ctrl.$isEmpty(value) || EMAIL_REGEXP.test(value), value);
};
ctrl.$formatters.push(emailValidator);
+5 -5
View File
@@ -20,13 +20,13 @@
</button>
count: {{count}}
</doc:source>
<doc:scenario>
<doc:protractor>
it('should check ng-click', function() {
expect(binding('count')).toBe('0');
element('.doc-example-live :button').click();
expect(binding('count')).toBe('1');
expect(element(by.binding('count')).getText()).toMatch('0');
element(by.css('.doc-example-live button')).click();
expect(element(by.binding('count')).getText()).toMatch('1');
});
</doc:scenario>
</doc:protractor>
</doc:example>
*/
/*
+2
View File
@@ -20,6 +20,8 @@
* | `$even` | {@type boolean} | true if the iterator position `$index` is even (otherwise false). |
* | `$odd` | {@type boolean} | true if the iterator position `$index` is odd (otherwise false). |
*
* Creating aliases for these properties is possible with {@link api/ng.directive:ngInit `ngInit`}.
* This may be useful when, for instance, nesting ngRepeats.
*
* # Special repeat start and end points
* To repeat a series of elements instead of just one parent element, ngRepeat (as well as other ng directives) supports extending
+3 -5
View File
@@ -168,11 +168,9 @@ var ngSwitchWhenDirective = ngDirective({
transclude: 'element',
priority: 800,
require: '^ngSwitch',
compile: function(element, attrs) {
return function(scope, element, attr, ctrl, $transclude) {
ctrl.cases['!' + attrs.ngSwitchWhen] = (ctrl.cases['!' + attrs.ngSwitchWhen] || []);
ctrl.cases['!' + attrs.ngSwitchWhen].push({ transclude: $transclude, element: element });
};
link: function(scope, element, attrs, ctrl, $transclude) {
ctrl.cases['!' + attrs.ngSwitchWhen] = (ctrl.cases['!' + attrs.ngSwitchWhen] || []);
ctrl.cases['!' + attrs.ngSwitchWhen].push({ transclude: $transclude, element: element });
}
});
+7 -3
View File
@@ -6,10 +6,14 @@
* @restrict E
*
* @description
* Load content of a script tag, with type `text/ng-template`, into `$templateCache`, so that the
* template can be used by `ngInclude`, `ngView` or directive templates.
* Load the content of a `<script>` element into {@link api/ng.$templateCache `$templateCache`}, so that the
* template can be used by {@link api/ng.directive:ngInclude `ngInclude`},
* {@link api/ngRoute.directive:ngView `ngView`}, or {@link guide/directive directives}. The type of the
* `<script>` element must be specified as `text/ng-template`, and a cache name for the template must be
* assigned through the element's `id`, which can then be used as a directive's `templateUrl`.
*
* @param {'text/ng-template'} type must be set to `'text/ng-template'`
* @param {'text/ng-template'} type Must be set to `'text/ng-template'`.
* @param {string} id Cache name of the template.
*
* @example
<doc:example>
+2 -2
View File
@@ -128,8 +128,8 @@ var ngOptionsMinErr = minErr('ngOptions');
var ngOptionsDirective = valueFn({ terminal: true });
// jshint maxlen: false
var selectDirective = ['$compile', '$parse', function($compile, $parse) {
//0000111110000000000022220000000000000000000000333300000000000000444444444444444000000000555555555555555000000066666666666666600000000000000007777000000000000000000088888
var NG_OPTIONS_REGEXP = /^\s*(.*?)(?:\s+as\s+(.*?))?(?:\s+group\s+by\s+(.*))?\s+for\s+(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+(.*?)(?:\s+track\s+by\s+(.*?))?$/,
//000011111111110000000000022222222220000000000000000000003333333333000000000000004444444444444440000000005555555555555550000000666666666666666000000000000000777777777700000000000000000008888888888
var NG_OPTIONS_REGEXP = /^\s*([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+group\s+by\s+([\s\S]+?))?\s+for\s+(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?$/,
nullModelCtrl = {$setViewValue: noop};
// jshint maxlen: 100
+1 -2
View File
@@ -6,8 +6,7 @@
* @requires $window
*
* @description
* A {@link angular.element jQuery (lite)}-wrapped reference to the browser's `window.document`
* element.
* A {@link angular.element jQuery or jqLite} wrapper for the browser's `window.document` object.
*/
function $DocumentProvider(){
this.$get = ['$window', function(window){
+8 -19
View File
@@ -14,8 +14,8 @@
*
* Can be one of:
*
* - `string`: Predicate that results in a substring match using the value of `expression`
* string. All strings or objects with string properties in `array` that contain this string
* - `string`: The string is evaluated as an expression and the resulting value is used for substring match against
* the contents of the `array`. All strings or objects with string properties in `array` that contain this string
* will be returned. The predicate can be negated by prefixing the string with `!`.
*
* - `Object`: A pattern object can be used to filter specific properties on objects contained
@@ -173,23 +173,12 @@ function filterFilter() {
case "object":
// jshint +W086
for (var key in expression) {
if (key == '$') {
(function() {
if (!expression[key]) return;
var path = key;
predicates.push(function(value) {
return search(value, expression[path]);
});
})();
} else {
(function() {
if (typeof(expression[key]) == 'undefined') { return; }
var path = key;
predicates.push(function(value) {
return search(getter(value,path), expression[path]);
});
})();
}
(function(path) {
if (typeof expression[path] == 'undefined') return;
predicates.push(function(value) {
return search(path == '$' ? value : getter(value, path), expression[path]);
});
})(key);
}
break;
case 'function':
+14 -3
View File
@@ -291,7 +291,15 @@ function $HttpProvider() {
* `$httpProvider.defaults.headers.get = { 'My-Header' : 'value' }.
*
* The defaults can also be set at runtime via the `$http.defaults` object in the same
* fashion. In addition, you can supply a `headers` property in the config object passed when
* fashion. For example:
*
* ```
* module.run(function($http) {
* $http.defaults.headers.common.Authentication = 'Basic YmVlcDpib29w'
* });
* ```
*
* In addition, you can supply a `headers` property in the config object passed when
* calling `$http(config)`, which overrides the defaults without changing them globally.
*
*
@@ -315,7 +323,9 @@ function $HttpProvider() {
* properties. These properties are by default an array of transform functions, which allows you
* to `push` or `unshift` a new transformation function into the transformation chain. You can
* also decide to completely override any default transformations by assigning your
* transformation functions to these properties directly without the array wrapper.
* transformation functions to these properties directly without the array wrapper. These defaults
* are again available on the $http factory at run-time, which may be useful if you have run-time
* services you wish to be involved in your transformations.
*
* Similarly, to locally override the request/response transforms, augment the
* `transformRequest` and/or `transformResponse` properties of the configuration object passed
@@ -529,7 +539,8 @@ function $HttpProvider() {
* for added security.
*
* The name of the headers can be specified using the xsrfHeaderName and xsrfCookieName
* properties of either $httpProvider.defaults, or the per-request config object.
* properties of either $httpProvider.defaults at config-time, $http.defaults at run-time,
* or the per-request config object.
*
*
* @param {object} config Object describing the request to be made and how it should be
+10 -9
View File
@@ -54,7 +54,7 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
} else {
completeRequest(callback, status || -2);
}
delete callbacks[callbackId];
callbacks[callbackId] = angular.noop;
});
} else {
@@ -71,7 +71,7 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
// response is in the cache. the promise api will ensure that to the app code the api is
// always async
xhr.onreadystatechange = function() {
// onreadystatechange might by called multiple times with readyState === 4 on mobile webkit caused by
// onreadystatechange might get called multiple times with readyState === 4 on mobile webkit caused by
// xhrs that are resolved while the app is in the background (see #5426).
// since calling completeRequest sets the `xhr` variable to null, we just check if it's not null before
// continuing
@@ -84,11 +84,12 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
if(status !== ABORTED) {
responseHeaders = xhr.getAllResponseHeaders();
response = xhr.responseType ? xhr.response : xhr.responseText;
// responseText is the old-school way of retrieving response (supported by IE8 & 9)
// response/responseType properties were introduced in XHR Level2 spec (supported by IE10)
response = ('response' in xhr) ? xhr.response : xhr.responseText;
}
// responseText is the old-school way of retrieving response (supported by IE8 & 9)
// response/responseType properties were introduced in XHR Level2 spec (supported by IE10)
completeRequest(callback,
status || xhr.status,
response,
@@ -121,14 +122,14 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
}
function completeRequest(callback, status, response, headersString) {
var protocol = urlResolve(url).protocol;
// cancel timeout and subsequent timeout promise resolution
timeoutId && $browserDefer.cancel(timeoutId);
jsonpDone = xhr = null;
// fix status code for file protocol (it's always 0)
status = (protocol == 'file' && status === 0) ? (response ? 200 : 404) : status;
// fix status code when it is 0 (0 status is undocumented).
// Occurs when accessing file resources.
// On Android 4.1 stock browser it occurs while retrieving files from application cache.
status = (status === 0) ? (response ? 200 : 404) : status;
// normalize IE bug (http://bugs.jquery.com/ticket/1450)
status = status == 1223 ? 204 : status;
+1 -1
View File
@@ -576,7 +576,7 @@ function $LocationProvider(){
* Broadcasted before a URL will change. This change can be prevented by calling
* `preventDefault` method of the event. See {@link ng.$rootScope.Scope#$on} for more
* details about event object. Upon successful change
* {@link ng.$location#$locationChangeSuccess $locationChangeSuccess} is fired.
* {@link ng.$location#events_$locationChangeSuccess $locationChangeSuccess} is fired.
*
* @param {Object} angularEvent Synthetic event object.
* @param {string} newUrl New URL
+16 -8
View File
@@ -894,16 +894,20 @@ function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
if (pathVal == null) return pathVal;
pathVal = pathVal[key0];
if (pathVal == null) return key1 ? undefined : pathVal;
if (!key1) return pathVal;
if (pathVal == null) return undefined;
pathVal = pathVal[key1];
if (pathVal == null) return key2 ? undefined : pathVal;
if (!key2) return pathVal;
if (pathVal == null) return undefined;
pathVal = pathVal[key2];
if (pathVal == null) return key3 ? undefined : pathVal;
if (!key3) return pathVal;
if (pathVal == null) return undefined;
pathVal = pathVal[key3];
if (pathVal == null) return key4 ? undefined : pathVal;
if (!key4) return pathVal;
if (pathVal == null) return undefined;
pathVal = pathVal[key4];
return pathVal;
@@ -924,8 +928,9 @@ function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
}
pathVal = pathVal.$$v;
}
if (pathVal == null) return key1 ? undefined : pathVal;
if (!key1) return pathVal;
if (pathVal == null) return undefined;
pathVal = pathVal[key1];
if (pathVal && pathVal.then) {
promiseWarning(fullExp);
@@ -936,8 +941,9 @@ function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
}
pathVal = pathVal.$$v;
}
if (pathVal == null) return key2 ? undefined : pathVal;
if (!key2) return pathVal;
if (pathVal == null) return undefined;
pathVal = pathVal[key2];
if (pathVal && pathVal.then) {
promiseWarning(fullExp);
@@ -948,8 +954,9 @@ function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
}
pathVal = pathVal.$$v;
}
if (pathVal == null) return key3 ? undefined : pathVal;
if (!key3) return pathVal;
if (pathVal == null) return undefined;
pathVal = pathVal[key3];
if (pathVal && pathVal.then) {
promiseWarning(fullExp);
@@ -960,8 +967,9 @@ function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
}
pathVal = pathVal.$$v;
}
if (pathVal == null) return key4 ? undefined : pathVal;
if (!key4) return pathVal;
if (pathVal == null) return undefined;
pathVal = pathVal[key4];
if (pathVal && pathVal.then) {
promiseWarning(fullExp);
+2 -2
View File
@@ -186,7 +186,7 @@ function $RootScopeProvider(){
} else {
ChildScope = function() {}; // should be anonymous; This is so that when the minifier munges
// the name it does not become random set of chars. This will then show up as class
// name in the debugger.
// name in the web inspector.
ChildScope.prototype = this;
child = new ChildScope();
child.$id = nextUid();
@@ -287,7 +287,7 @@ function $RootScopeProvider(){
// No digest has been run so the counter will be zero
expect(scope.foodCounter).toEqual(0);
// Run the digest but since food has not changed cout will still be zero
// Run the digest but since food has not changed count will still be zero
scope.$digest();
expect(scope.foodCounter).toEqual(0);
+17 -1
View File
@@ -2079,6 +2079,20 @@ if(window.jasmine || window.mocha) {
*
* @param {...Function} fns any number of functions which will be injected using the injector.
*/
var ErrorAddingDeclarationLocationStack = function(e, errorForStack) {
this.message = e.message;
this.name = e.name;
if (e.line) this.line = e.line;
if (e.sourceId) this.sourceId = e.sourceId;
if (e.stack && errorForStack)
this.stack = e.stack + '\n' + errorForStack.stack;
if (e.stackArray) this.stackArray = e.stackArray;
};
ErrorAddingDeclarationLocationStack.prototype.toString = Error.prototype.toString;
window.inject = angular.mock.inject = function() {
var blockFns = Array.prototype.slice.call(arguments, 0);
var errorForStack = new Error('Declaration Location');
@@ -2099,7 +2113,9 @@ if(window.jasmine || window.mocha) {
injector.invoke(blockFns[i] || angular.noop, this);
/* jshint +W040 */
} catch (e) {
if(e.stack && errorForStack) e.stack += '\n' + errorForStack.stack;
if (e.stack && errorForStack) {
throw new ErrorAddingDeclarationLocationStack(e, errorForStack);
}
throw e;
} finally {
errorForStack = null;
+1 -1
View File
@@ -90,7 +90,7 @@ function shallowClearAndCopy(src, dst) {
* when a param value needs to be obtained for a request (unless the param was overridden).
*
* Each key value in the parameter object is first bound to url template if present and then any
* excess keys are appended to the url seapph query after the `?`.
* excess keys are appended to the url search query after the `?`.
*
* Given a template `/path/:verb` and parameter `{verb:'greet', salutation:'Hello'}` results in
* URL `/path/greet?salutation=Hello`.
+40
View File
@@ -0,0 +1,40 @@
describe('docs.angularjs.org', function () {
describe('App', function () {
// it('should filter the module list when searching', function () {
// browser.get();
// browser.waitForAngular();
// var search = element(by.input('q'));
// search.clear();
// search.sendKeys('ngBind');
// var firstModule = element(by.css('.search-results a'));
// expect(firstModule.getText()).toEqual('ngBind');
// });
it('should change the page content when clicking a link to a service', function () {
browser.get('');
var ngBindLink = element(by.css('.definition-table td a[href="api/ng.directive:ngClick"]'));
ngBindLink.click();
var pageBody = element(by.css('.content h1 code'));
expect(pageBody.getText()).toEqual('ngClick');
});
it('should show the functioning input directive example', function () {
browser.get('index-nocache.html#!/api/ng.directive:input');
//Wait for animation
browser.sleep(500);
var nameInput = element(by.input('user.name'));
nameInput.click();
nameInput.sendKeys('!!!');
var code = element(by.css('.doc-example-live tt'));
expect(code.getText()).toContain('guest!!!');
});
});
})
+2 -2
View File
@@ -724,7 +724,7 @@ describe('input', function() {
describe('minlength', function() {
it('should invalid shorter than given minlenght', function() {
it('should invalid shorter than given minlength', function() {
compileInput('<input type="text" ng-model="value" ng-minlength="3" />');
changeInputValueTo('aa');
@@ -738,7 +738,7 @@ describe('input', function() {
describe('maxlength', function() {
it('should invalid shorter than given maxlenght', function() {
it('should invalid shorter than given maxlength', function() {
compileInput('<input type="text" ng-model="value" ng-maxlength="5" />');
changeInputValueTo('aaaaaaaa');
+25
View File
@@ -708,6 +708,31 @@ describe('select', function() {
expect(sortedHtml(options[0])).toEqual('<option value="regularProperty">visible</option>');
});
it('should allow expressions over multiple lines', function() {
scope.isNotFoo = function(item) {
return item.name !== 'Foo';
};
createSelect({
'ng-options': 'key.id\n' +
'for key in object\n' +
'| filter:isNotFoo',
'ng-model': 'selected'
});
scope.$apply(function() {
scope.object = [{'id': 1, 'name': 'Foo'},
{'id': 2, 'name': 'Bar'},
{'id': 3, 'name': 'Baz'}];
scope.selected = scope.object[0];
});
var options = element.find('option');
expect(options.length).toEqual(3);
expect(sortedHtml(options[1])).toEqual('<option value="0">2</option>');
expect(sortedHtml(options[2])).toEqual('<option value="1">3</option>');
});
describe('binding', function() {
it('should bind to scope value', function() {
+11
View File
@@ -60,6 +60,17 @@ describe('Filter: filter', function() {
expect(filter(items, {first:'misko', last:'hevery'})[0]).toEqual(items[0]);
});
it('should match any properties for given "$" property', function() {
var items = [{first: 'tom', last: 'hevery'},
{first: 'adam', last: 'hevery', alias: 'tom', done: false},
{first: 'john', last: 'clark', middle: 'tommy'}];
expect(filter(items, {$: 'tom'}).length).toBe(3);
expect(filter(items, {$: 'a'}).length).toBe(2);
expect(filter(items, {$: false}).length).toBe(1);
expect(filter(items, {$: 10}).length).toBe(0);
expect(filter(items, {$: 'hevery'})[0]).toEqual(items[0]);
});
it('should support boolean properties', function() {
var items = [{name: 'tom', current: true},
{name: 'demi', current: false},
+46 -17
View File
@@ -264,21 +264,45 @@ describe('$httpBackend', function() {
});
it('should set responseType and return xhr.response', function() {
$backend('GET', '/whatever', null, callback, {}, null, null, 'blob');
describe('responseType', function() {
var xhrInstance = MockXhr.$$lastInstance;
expect(xhrInstance.responseType).toBe('blob');
it('should set responseType and return xhr.response', function() {
$backend('GET', '/whatever', null, callback, {}, null, null, 'blob');
callback.andCallFake(function(status, response) {
expect(response).toBe(xhrInstance.response);
var xhrInstance = MockXhr.$$lastInstance;
expect(xhrInstance.responseType).toBe('blob');
callback.andCallFake(function(status, response) {
expect(response).toBe(xhrInstance.response);
});
xhrInstance.response = {some: 'object'};
xhrInstance.readyState = 4;
xhrInstance.onreadystatechange();
expect(callback).toHaveBeenCalledOnce();
});
xhrInstance.response = {some: 'object'};
xhrInstance.readyState = 4;
xhrInstance.onreadystatechange();
expect(callback).toHaveBeenCalledOnce();
it('should read responseText if response was not defined', function() {
// old browsers like IE8, don't support responseType, so they always respond with responseText
$backend('GET', '/whatever', null, callback, {}, null, null, 'blob');
var xhrInstance = MockXhr.$$lastInstance;
var responseText = '{"some": "object"}';
expect(xhrInstance.responseType).toBe('blob');
callback.andCallFake(function(status, response) {
expect(response).toBe(responseText);
});
xhrInstance.responseText = responseText;
xhrInstance.readyState = 4;
xhrInstance.onreadystatechange();
expect(callback).toHaveBeenCalledOnce();
});
});
@@ -330,7 +354,7 @@ describe('$httpBackend', function() {
script.onload();
}
expect(callbacks[callbackId]).toBeUndefined();
expect(callbacks[callbackId]).toBe(angular.noop);
expect(fakeDocument.body.removeChild).toHaveBeenCalledOnceWith(script);
});
@@ -397,7 +421,7 @@ describe('$httpBackend', function() {
});
it('should abort request on timeout', function() {
it('should abort request on timeout and replace callback with noop', function() {
callback.andCallFake(function(status, response) {
expect(status).toBe(-1);
});
@@ -406,9 +430,14 @@ describe('$httpBackend', function() {
expect(fakeDocument.$$scripts.length).toBe(1);
expect(fakeTimeout.delays[0]).toBe(2000);
var script = fakeDocument.$$scripts.shift(),
callbackId = script.src.match(SCRIPT_URL)[2];
fakeTimeout.flush();
expect(fakeDocument.$$scripts.length).toBe(0);
expect(callback).toHaveBeenCalledOnce();
expect(callbacks[callbackId]).toBe(angular.noop);
});
@@ -416,7 +445,7 @@ describe('$httpBackend', function() {
// TODO(vojta): test whether it fires "async-end" on both success and error
});
describe('file protocol', function() {
describe('protocols that return 0 status code', function() {
function respond(status, content) {
xhr = MockXhr.$$lastInstance;
@@ -430,7 +459,7 @@ describe('$httpBackend', function() {
it('should convert 0 to 200 if content', function() {
$backend = createHttpBackend($browser, createMockXhr);
$backend('GET', 'file:///whatever/index.html', null, callback);
$backend('GET', 'someProtocol:///whatever/index.html', null, callback);
respond(0, 'SOME CONTENT');
expect(callback).toHaveBeenCalled();
@@ -441,7 +470,7 @@ describe('$httpBackend', function() {
it('should convert 0 to 404 if no content', function() {
$backend = createHttpBackend($browser, createMockXhr);
$backend('GET', 'file:///whatever/index.html', null, callback);
$backend('GET', 'someProtocol:///whatever/index.html', null, callback);
respond(0, '');
expect(callback).toHaveBeenCalled();
@@ -457,10 +486,10 @@ describe('$httpBackend', function() {
hash : "#/C:/",
host : "",
hostname : "",
href : "file:///C:/base#!/C:/foo",
href : "someProtocol:///C:/base#!/C:/foo",
pathname : "/C:/foo",
port : "",
protocol : "file:",
protocol : "someProtocol:",
search : "",
setAttribute: angular.noop
};
+58 -5
View File
@@ -204,13 +204,24 @@ describe('parser', function() {
describe('csp: ' + cspEnabled + ", unwrapPromises: " + unwrapPromisesEnabled, function() {
beforeEach(module(function ($parseProvider) {
var originalSecurityPolicy;
beforeEach(function() {
originalSecurityPolicy = window.document.securityPolicy;
window.document.securityPolicy = {isActive : cspEnabled};
});
afterEach(function() {
window.document.securityPolicy = originalSecurityPolicy;
});
beforeEach(module(function ($parseProvider, $provide) {
$parseProvider.unwrapPromises(unwrapPromisesEnabled);
}));
beforeEach(inject(function ($rootScope, $sniffer) {
beforeEach(inject(function ($rootScope) {
scope = $rootScope;
$sniffer.csp = cspEnabled;
}));
it('should parse expressions', function() {
@@ -344,6 +355,25 @@ describe('parser', function() {
expect(scope.$eval("a.b.c.d.e.f.g.h.i.j.k.l.m.n", scope)).toBe('nooo!');
});
forEach([2, 3, 4, 5, 6, 7, 8, 9, 10, 20, 42, 99], function(pathLength) {
it('should resolve nested paths of length ' + pathLength, function() {
// Create a nested object {x2: {x3: {x4: ... {x[n]: 42} ... }}}.
var obj = 42;
for (var i = pathLength; i >= 2; i--) {
var newObj = {};
newObj['x' + i] = obj;
obj = newObj;
}
// Assign to x1 and build path 'x1.x2.x3. ... .x[n]' to access the final value.
scope.x1 = obj;
var path = 'x1';
for (var i = 2; i <= pathLength; i++) {
path += '.x' + i;
}
expect(scope.$eval(path)).toBe(42);
});
});
it('should be forgiving', function() {
scope.a = {b: 23};
expect(scope.$eval('b')).toBeUndefined();
@@ -1069,6 +1099,17 @@ describe('parser', function() {
var $log;
var PROMISE_WARNING_REGEXP = /\[\$parse\] Promise found in the expression `[^`]+`. Automatic unwrapping of promises in Angular expressions is deprecated\./;
var originalSecurityPolicy;
beforeEach(function() {
originalSecurityPolicy = window.document.securityPolicy;
window.document.securityPolicy = {isActive : cspEnabled};
});
afterEach(function() {
window.document.securityPolicy = originalSecurityPolicy;
});
beforeEach(module(function($parseProvider) {
$parseProvider.unwrapPromises(true);
@@ -1142,15 +1183,27 @@ describe('parser', function() {
describe('csp ' + cspEnabled, function() {
var originalSecurityPolicy;
beforeEach(function() {
originalSecurityPolicy = window.document.securityPolicy;
window.document.securityPolicy = {isActive : cspEnabled};
});
afterEach(function() {
window.document.securityPolicy = originalSecurityPolicy;
});
beforeEach(module(function($parseProvider) {
$parseProvider.unwrapPromises(true);
$parseProvider.logPromiseWarnings(false);
}));
beforeEach(inject(function($rootScope, $sniffer, $q) {
beforeEach(inject(function($rootScope, $q) {
scope = $rootScope;
$sniffer.csp = cspEnabled;
q = $q;
deferred = q.defer();
-2
View File
@@ -1303,8 +1303,6 @@ describe("ngAnimate", function() {
it('should only append active to the newly append CSS className values',
inject(function($animate, $rootScope, $sniffer, $rootElement, $timeout) {
ss.addRule('.ng-enter', '-webkit-transition:9s linear all;' +
'transition:9s linear all;');
ss.addRule('.ng-enter', '-webkit-transition:9s linear all;' +
'transition:9s linear all;');
+25
View File
@@ -862,6 +862,31 @@ describe('ngMock', function() {
expect(log).toEqual('module;inject;')
});
});
// We don't run the following tests on IE8.
// IE8 throws "Object does not support this property or method." error,
// when thrown from a function defined on window (which `inject` is).
it('should not change thrown Errors', inject(function($sniffer) {
if ($sniffer.msie <= 8) return;
expect(function() {
inject(function() {
throw new Error('test message');
});
}).toThrow('test message');
}));
it('should not change thrown strings', inject(function($sniffer) {
if ($sniffer.msie <= 8) return;
expect(function() {
inject(function() {
throw 'test message';
});
}).toThrow('test message');
}));
});
});