Compare commits
160 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0f9a1c21e6 | |||
| ece7854972 | |||
| 8ace8073fd | |||
| 43a2f3d0bf | |||
| a9cccbe14f | |||
| 36c9e42de2 | |||
| 9f566db33c | |||
| c77b2bcca3 | |||
| 5a4145fe16 | |||
| 039b990d8d | |||
| 5a9cb8be3f | |||
| 63cd873fef | |||
| 69452fa94f | |||
| 2ed4ad5502 | |||
| 1d2a388830 | |||
| ac05276a51 | |||
| cb9c0f200a | |||
| b1d676b7f7 | |||
| 9ddef840b6 | |||
| 28fc80bba0 | |||
| b6c42d5e81 | |||
| 1c045f1b46 | |||
| 95e1b2d612 | |||
| 75345e3487 | |||
| f4fe28bd92 | |||
| ace13b94e6 | |||
| 5df7e73adf | |||
| e115342fce | |||
| e89150ca0f | |||
| 9693a426e3 | |||
| 162485d303 | |||
| affcbad501 | |||
| 7e916455b3 | |||
| cdc4d485a6 | |||
| c894470d41 | |||
| 1b0718bf89 | |||
| 53fd24ffcb | |||
| eb90672aae | |||
| 28cfd96fdc | |||
| 99d5defb1a | |||
| efbc242875 | |||
| d4d58f287f | |||
| dc89db33df | |||
| 5dc27959d5 | |||
| 4c21355940 | |||
| 6f6cb5c8d8 | |||
| 821ed310a7 | |||
| a7aa4cc0a9 | |||
| e0ce9ed36d | |||
| caeb740265 | |||
| 1bb33cccbe | |||
| d9ed9c5ac1 | |||
| 00cac6ed10 | |||
| 2e9d7cc6cb | |||
| 32cc6cbb6f | |||
| 3b1a4fe0c8 | |||
| 9569778f2f | |||
| 0f61316b24 | |||
| 86151b0cea | |||
| 1b7a6c66f8 | |||
| 0ef76dde41 | |||
| c6d04b3a3d | |||
| e31560cf6b | |||
| 3d38fff8b4 | |||
| bc492c0fc1 | |||
| 162144202c | |||
| 05596527ed | |||
| 5fea3471e8 | |||
| 131e4014b8 | |||
| 01c5be4681 | |||
| fd9a03e147 | |||
| 6c17d02bc4 | |||
| 6a6f71f238 | |||
| cf686285c2 | |||
| 7dfedb732d | |||
| 760f2fb731 | |||
| c9705b7556 | |||
| 53ec33f07f | |||
| 884ef0dbcd | |||
| 010413f90a | |||
| 4f57236614 | |||
| 50bf029625 | |||
| eff52ad877 | |||
| e9ee492d35 | |||
| e415e916e8 | |||
| 07084e1c8b | |||
| 186a591228 | |||
| a80049fd0a | |||
| d158dd131e | |||
| 1147f21999 | |||
| bddd46c8ec | |||
| 80e7a45584 | |||
| 498365f219 | |||
| 056c849352 | |||
| 7d6e5a2d01 | |||
| d1c4766d14 | |||
| 98473835a2 | |||
| 870232bd05 | |||
| c31df32ca0 | |||
| df2b88e230 | |||
| 83451d552e | |||
| af7203e0b8 | |||
| 98ee3719f9 | |||
| 94b5f2dadb | |||
| fe7decd1b0 | |||
| cef084ade9 | |||
| 937caab647 | |||
| 3fc8017119 | |||
| 54637a335f | |||
| 277a5ea05d | |||
| 9865a7c0ad | |||
| efba4731e4 | |||
| a965984733 | |||
| 14d3e559d4 | |||
| 3d156a76e3 | |||
| c7a1d1ab0b | |||
| 26d43cacdc | |||
| 4f5758e666 | |||
| 274a6734ef | |||
| f0e3dfd008 | |||
| bc3ff2cecd | |||
| 8f329ffb82 | |||
| 864b2596b2 | |||
| f3a796e522 | |||
| 09f8962df2 | |||
| a13c4ba770 | |||
| 040e743b39 | |||
| bf816d3ade | |||
| 74b4ab8867 | |||
| 6e2359caa0 | |||
| 41534816a4 | |||
| 30252a0504 | |||
| 3dc18037e8 | |||
| 57d50582aa | |||
| 73c66715c9 | |||
| cb29632a58 | |||
| 5c97731a22 | |||
| b2e472e7a2 | |||
| 6ac773f350 | |||
| 3174f73336 | |||
| 3c62e4244e | |||
| c432999572 | |||
| f8d319c11a | |||
| 4f72433392 | |||
| 2f91cfd0d2 | |||
| d5c5e2b584 | |||
| cbb3ce2c30 | |||
| 45af02de04 | |||
| 6144df52af | |||
| b0474cb984 | |||
| 9a4c9e6487 | |||
| 11fff8fa0d | |||
| da8ab2f928 | |||
| 6d01384a55 | |||
| 109ffac975 | |||
| 8c10db3847 | |||
| 03088d6010 | |||
| 18e0768a2b | |||
| ed4a1fddce | |||
| cfde6f507c |
+164
@@ -1,3 +1,164 @@
|
||||
<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)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$animate:**
|
||||
- ensue class-based animations are always skipped before structural post-digest tasks are run
|
||||
([bc492c0f](https://github.com/angular/angular.js/commit/bc492c0fc17257ddf2bc5964e205379aa766b3d8),
|
||||
[#5582](https://github.com/angular/angular.js/issues/5582))
|
||||
- remove trailing `s` from computed transition duration styles
|
||||
([50bf0296](https://github.com/angular/angular.js/commit/50bf029625d603fc652f0f413e709f43803743db))
|
||||
- **$http:**
|
||||
([3d38fff8](https://github.com/angular/angular.js/commit/3d38fff8b4ea2fd60fadef2028ea4dcddfccb1a4))
|
||||
- use ActiveX XHR when making PATCH requests on IE8
|
||||
([6c17d02b](https://github.com/angular/angular.js/commit/6c17d02bc4cc02f478775d62e1f9f77da9da82ad),
|
||||
[#2518](https://github.com/angular/angular.js/issues/2518), [#5043](https://github.com/angular/angular.js/issues/5043))
|
||||
- fix 'type mismatch' error on IE8 after each request
|
||||
([fd9a03e1](https://github.com/angular/angular.js/commit/fd9a03e147aac7e952c6dda1f381fd4662276ba2))
|
||||
- Ignore multiple calls to onreadystatechange with readyState=4
|
||||
([4f572366](https://github.com/angular/angular.js/commit/4f57236614415eea919221ea5f99c4d8689b3267),
|
||||
[#5426](https://github.com/angular/angular.js/issues/5426))
|
||||
- **$injector:** remove the `INSTANTIATING` flag properly when done
|
||||
([186a5912](https://github.com/angular/angular.js/commit/186a5912288acfff0ee59dae29af83c37c987921),
|
||||
[#4361](https://github.com/angular/angular.js/issues/4361), [#5577](https://github.com/angular/angular.js/issues/5577))
|
||||
- **$location:**
|
||||
- remove base href domain if the URL begins with '//'
|
||||
([760f2fb7](https://github.com/angular/angular.js/commit/760f2fb73178e56c37397b3c5876f7dac96f0455),
|
||||
[#5606](https://github.com/angular/angular.js/issues/5606))
|
||||
- fix $location.path() behaviour when $locationChangeStart is triggered by the browser
|
||||
([cf686285](https://github.com/angular/angular.js/commit/cf686285c22d528440e173fdb65ad1052d96df3c),
|
||||
[#4989](https://github.com/angular/angular.js/issues/4989), [#5089](https://github.com/angular/angular.js/issues/5089), [#5118](https://github.com/angular/angular.js/issues/5118), [#5580](https://github.com/angular/angular.js/issues/5580))
|
||||
- re-assign history after BFCache back on Android browser
|
||||
([bddd46c8](https://github.com/angular/angular.js/commit/bddd46c8ecf49cfe6c999cd6b4a69b7d7e1f9a33),
|
||||
[#5425](https://github.com/angular/angular.js/issues/5425))
|
||||
- **$resource:** prevent URL template from collapsing into an empty string
|
||||
([131e4014](https://github.com/angular/angular.js/commit/131e4014b831ac81b7979c4523da81ebc5861c70),
|
||||
[#5455](https://github.com/angular/angular.js/issues/5455), [#5493](https://github.com/angular/angular.js/issues/5493))
|
||||
- **$sanitize:** consider the `size` attribute as a valid/allowed attribute
|
||||
([056c8493](https://github.com/angular/angular.js/commit/056c8493521988dbb330c6636135b505737da918),
|
||||
[#5522](https://github.com/angular/angular.js/issues/5522))
|
||||
- **Scope:** don't let watch deregistration mess up the dirty-checking digest loop
|
||||
([884ef0db](https://github.com/angular/angular.js/commit/884ef0dbcdfe614cedc824d079361b53e675d033),
|
||||
[#5525](https://github.com/angular/angular.js/issues/5525))
|
||||
- **input:**
|
||||
- use apply on the change event only when one isn't already in progress
|
||||
([a80049fd](https://github.com/angular/angular.js/commit/a80049fd0ac858eeeb645a4209cb2a661d0b4c33),
|
||||
[#5293](https://github.com/angular/angular.js/issues/5293))
|
||||
- prevent double $digest when using jQuery trigger.
|
||||
([1147f219](https://github.com/angular/angular.js/commit/1147f21999edf9a434cd8d24865a6455e744d858),
|
||||
[#5293](https://github.com/angular/angular.js/issues/5293))
|
||||
- **ngRepeat:** allow for more flexible coding style in ngRepeat expression
|
||||
([c9705b75](https://github.com/angular/angular.js/commit/c9705b755645a4bfe066243f2ba15a733c3787e1),
|
||||
[#5537](https://github.com/angular/angular.js/issues/5537), [#5598](https://github.com/angular/angular.js/issues/5598))
|
||||
- **ngRoute:** instantiate controller when template is empty
|
||||
([498365f2](https://github.com/angular/angular.js/commit/498365f219f65d6c29bdf2f03610a4d3646009bb),
|
||||
[#5550](https://github.com/angular/angular.js/issues/5550))
|
||||
- **ngShow/ngHide, ngIf:** functions with zero args should be truthy
|
||||
([01c5be46](https://github.com/angular/angular.js/commit/01c5be4681e34cdc5f5c461b7a618fefe8038919),
|
||||
[#5414](https://github.com/angular/angular.js/issues/5414))
|
||||
|
||||
|
||||
## Performance Improvements
|
||||
|
||||
- **Scope:** limit propagation of $broadcast to scopes that have listeners for the event
|
||||
([80e7a455](https://github.com/angular/angular.js/commit/80e7a4558490f7ffd33d142844b9153a5ed00e86),
|
||||
[#5341](https://github.com/angular/angular.js/issues/5341), [#5371](https://github.com/angular/angular.js/issues/5371))
|
||||
|
||||
<a name="1.2.6"></a>
|
||||
# 1.2.6 taco-salsafication (2013-12-19)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$animate:** use a scheduled timeout in favor of a fallback property to close transitions
|
||||
([54637a33](https://github.com/angular/angular.js/commit/54637a335f885110efaa702a3bab29c77644b36c),
|
||||
[#5255](https://github.com/angular/angular.js/issues/5255), [#5241](https://github.com/angular/angular.js/issues/5241), [#5405](https://github.com/angular/angular.js/issues/5405))
|
||||
- **$compile:** remove invalid IE exceptional case for `href`
|
||||
([c7a1d1ab](https://github.com/angular/angular.js/commit/c7a1d1ab0b663edffc1ac7b54deea847e372468d),
|
||||
[#5479](https://github.com/angular/angular.js/issues/5479))
|
||||
- **$location:** parse xlink:href for SVGAElements
|
||||
([bc3ff2ce](https://github.com/angular/angular.js/commit/bc3ff2cecd0861766a9e8606f3cc2c582d9875df),
|
||||
[#5472](https://github.com/angular/angular.js/issues/5472), [#5198](https://github.com/angular/angular.js/issues/5198), [#5199](https://github.com/angular/angular.js/issues/5199), [#4098](https://github.com/angular/angular.js/issues/4098), [#1420](https://github.com/angular/angular.js/issues/1420))
|
||||
- **$log:** should work in IE8
|
||||
([4f5758e6](https://github.com/angular/angular.js/commit/4f5758e6669222369889c9e789601d25ff885530),
|
||||
[#5400](https://github.com/angular/angular.js/issues/5400))
|
||||
- **$parse:** return `undefined` if an intermetiate property's value is `null`
|
||||
([26d43cac](https://github.com/angular/angular.js/commit/26d43cacdc106765bd928d41600352198f887aef),
|
||||
[#5480](https://github.com/angular/angular.js/issues/5480))
|
||||
- **closure:** add type definition for `Scope#$watchCollection`
|
||||
([8f329ffb](https://github.com/angular/angular.js/commit/8f329ffb829410e1fd8f86a766929134e736e3e5),
|
||||
[#5475](https://github.com/angular/angular.js/issues/5475))
|
||||
- **forEach:** allow looping over result of `querySelectorAll` in IE8
|
||||
([274a6734](https://github.com/angular/angular.js/commit/274a6734ef1fff543cc50388a0958d1988baeb57))
|
||||
- **input:** do not hold input for composition on Android
|
||||
([3dc18037](https://github.com/angular/angular.js/commit/3dc18037e8db8766641a4d39f0fee96077db1fcb),
|
||||
[#5308](https://github.com/angular/angular.js/issues/5308))
|
||||
- **jqLite:** support unbind self within handler
|
||||
([2f91cfd0](https://github.com/angular/angular.js/commit/2f91cfd0d2986899c38641100c1851b2f9d3888a))
|
||||
- **ngRepeat:** allow multiline expressions
|
||||
([cbb3ce2c](https://github.com/angular/angular.js/commit/cbb3ce2c309052b951d0cc87e4c6daa9c48a3dd8),
|
||||
[#5000](https://github.com/angular/angular.js/issues/5000))
|
||||
- **select:** invalidate when `multiple`, `required`, and model is `[]`
|
||||
([5c97731a](https://github.com/angular/angular.js/commit/5c97731a22ed87d64712e673efea0e8a05eae65f),
|
||||
[#5337](https://github.com/angular/angular.js/issues/5337))
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
- **jqLite:** provide support for `element.one()`
|
||||
([937caab6](https://github.com/angular/angular.js/commit/937caab6475e53a7ea0206e992f8a52449232e78))
|
||||
- **ngAnimate:** provide configuration support to match specific className values to trigger animations
|
||||
([cef084ad](https://github.com/angular/angular.js/commit/cef084ade9072090259d8c679751cac3ffeaed51),
|
||||
[#5357](https://github.com/angular/angular.js/issues/5357), [#5283](https://github.com/angular/angular.js/issues/5283))
|
||||
|
||||
|
||||
## Performance Improvements
|
||||
|
||||
- **compile:** add class 'ng-scope' before cloning and other micro-optimizations
|
||||
([f3a796e5](https://github.com/angular/angular.js/commit/f3a796e522afdbd3b640d14426edb2fbfab463c5),
|
||||
[#5471](https://github.com/angular/angular.js/issues/5471))
|
||||
- **$parse:** use a faster path when the number of path parts is low
|
||||
([f4462319](https://github.com/angular/angular.js/commit/864b2596b246470cca9d4e223eaed720f4462319))
|
||||
- use faster check for `$$` prefix
|
||||
([06c5cfc7](https://github.com/angular/angular.js/commit/cb29632a5802e930262919b3db64ca4806c5cfc7))
|
||||
|
||||
<a name="1.2.5"></a>
|
||||
# 1.2.5 singularity-expansion (2013-12-13)
|
||||
|
||||
@@ -4326,3 +4487,6 @@ with the `$route` service
|
||||
[module]: http://docs-next.angularjs.org/api/angular.mock.module
|
||||
[guide2.di]: http://docs-next.angularjs.org/guide/dev_guide.di
|
||||
[jqLite2]: http://docs.angularjs.org/#!/api/angular.element
|
||||
|
||||
|
||||
[](https://github.com/igrigorik/ga-beacon)
|
||||
|
||||
@@ -258,3 +258,6 @@ You can find out more detailed information about contributing in the
|
||||
[corporate-cla]: http://code.google.com/legal/corporate-cla-v1.0.html
|
||||
[commit-message-format]: https://docs.google.com/document/d/1QrDFcIiPjSLDn3EL15IJygNPiHORgU1_OOAqWjiDU5Y/edit#
|
||||
[github-pr-helper]: https://chrome.google.com/webstore/detail/github-pr-helper/mokbklfnaddkkbolfldepnkfmanfhpen
|
||||
|
||||
|
||||
[](https://github.com/igrigorik/ga-beacon)
|
||||
|
||||
+19
-2
@@ -4,6 +4,7 @@ var path = require('path');
|
||||
|
||||
module.exports = function(grunt) {
|
||||
//grunt plugins
|
||||
grunt.loadNpmTasks('grunt-bump');
|
||||
grunt.loadNpmTasks('grunt-contrib-clean');
|
||||
grunt.loadNpmTasks('grunt-contrib-copy');
|
||||
grunt.loadNpmTasks('grunt-contrib-connect');
|
||||
@@ -100,6 +101,11 @@ module.exports = function(grunt) {
|
||||
},
|
||||
|
||||
|
||||
runprotractor: {
|
||||
normal: 'protractor-conf.js'
|
||||
},
|
||||
|
||||
|
||||
clean: {
|
||||
build: ['build'],
|
||||
tmp: ['tmp']
|
||||
@@ -268,18 +274,29 @@ module.exports = function(grunt) {
|
||||
write: {
|
||||
versionTXT: {file: 'build/version.txt', val: NG_VERSION.full},
|
||||
versionJSON: {file: 'build/version.json', val: JSON.stringify(NG_VERSION)}
|
||||
},
|
||||
|
||||
bump: {
|
||||
options: {
|
||||
files: ['package.json'],
|
||||
commit: false,
|
||||
createTag: false,
|
||||
push: false
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
//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']);
|
||||
|
||||
@@ -287,6 +304,6 @@ module.exports = function(grunt) {
|
||||
grunt.registerTask('webserver', ['connect:devserver']);
|
||||
grunt.registerTask('package', ['bower','clean', 'buildall', 'minall', 'collect-errors', 'docs', 'copy', 'write', 'compress']);
|
||||
grunt.registerTask('package-without-bower', ['clean', 'buildall', 'minall', 'collect-errors', 'docs', 'copy', 'write', 'compress']);
|
||||
grunt.registerTask('ci-checks', ['ddescribe-iit', 'merge-conflict', 'jshint', 'test:docgen']);
|
||||
grunt.registerTask('ci-checks', ['ddescribe-iit', 'merge-conflict', 'jshint']);
|
||||
grunt.registerTask('default', ['package']);
|
||||
};
|
||||
|
||||
@@ -38,3 +38,7 @@ To execute end-to-end (e2e) tests, use:
|
||||
|
||||
To learn more about the grunt tasks, run `grunt --help` and also read our
|
||||
[contribution guidelines](http://docs.angularjs.org/misc/contribute).
|
||||
|
||||
|
||||
[](https://github.com/igrigorik/ga-beacon)
|
||||
|
||||
|
||||
@@ -59,3 +59,5 @@ The following is done automatically and should not be done manually:
|
||||
|
||||
1. Unassign yourself from the issue
|
||||
|
||||
|
||||
[](https://github.com/igrigorik/ga-beacon)
|
||||
|
||||
Vendored
+10
-1
@@ -762,7 +762,9 @@ angular.Module.requires;
|
||||
* $parent: angular.Scope,
|
||||
* $root: angular.Scope,
|
||||
* $watch: function(
|
||||
* (string|Function), (string|Function)=, boolean=):function()
|
||||
* (string|Function), (string|Function)=, boolean=):function(),
|
||||
* $watchCollection: function(
|
||||
* (string|Function), (string|Function)=):function()
|
||||
* }}
|
||||
*/
|
||||
angular.Scope;
|
||||
@@ -834,6 +836,13 @@ angular.Scope.$root;
|
||||
*/
|
||||
angular.Scope.$watch = function(exp, opt_listener, opt_objectEquality) {};
|
||||
|
||||
/**
|
||||
* @param {string|Function} exp
|
||||
* @param {(string|Function)=} opt_listener
|
||||
* @return {function()}
|
||||
*/
|
||||
angular.Scope.$watchCollection = function(exp, opt_listener) {};
|
||||
|
||||
/**
|
||||
* @typedef {{
|
||||
* currentScope: angular.Scope,
|
||||
|
||||
@@ -9,14 +9,3 @@
|
||||
ng\:form {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* The styles below ensure that the CSS transition will ALWAYS
|
||||
* animate and close. A nasty bug occurs with CSS transitions where
|
||||
* when the active class isn't set, or if the active class doesn't
|
||||
* contain any styles to transition to, then, if ngAnimate is used,
|
||||
* it will appear as if the webpage is broken due to the forever hanging
|
||||
* animations. The border-spacing (!ie) and zoom (ie) CSS properties are
|
||||
* used below since they trigger a transition without making the browser
|
||||
* animate anything and they're both highly underused CSS properties */
|
||||
.ng-animate-start { border-spacing:1px 1px; -ms-zoom:1.0001; }
|
||||
.ng-animate-active { border-spacing:0px 0px; -ms-zoom:1; }
|
||||
|
||||
+1
-11
@@ -215,17 +215,7 @@ directive.ngEmbedApp = ['$templateCache', '$browser', '$rootScope', '$location',
|
||||
}];
|
||||
this.html5Mode = angular.noop;
|
||||
});
|
||||
$provide.decorator('$timeout', ['$rootScope', '$delegate', function($rootScope, $delegate) {
|
||||
return angular.extend(function(fn, delay) {
|
||||
if (delay && delay > 50) {
|
||||
return setTimeout(function() {
|
||||
$rootScope.$apply(fn);
|
||||
}, delay);
|
||||
} else {
|
||||
return $delegate.apply(this, arguments);
|
||||
}
|
||||
}, $delegate);
|
||||
}]);
|
||||
|
||||
$provide.decorator('$rootScope', ['$delegate', function($delegate) {
|
||||
embedRootScope = $delegate;
|
||||
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
@description
|
||||
|
||||
# ng (core module)
|
||||
The ng module is loaded by default when an AngularJS application is started. The module itself contains the essential components to for an AngularJS application to function. The table below lists a high level breakdown of each of the services/factories, filters, directives and testing components available within this core module.
|
||||
The ng module is loaded by default when an AngularJS application is started. The module itself
|
||||
contains the essential components for an AngularJS application to function. The table below
|
||||
lists a high level breakdown of each of the services/factories, filters, directives and testing
|
||||
components available within this core module.
|
||||
|
||||
<div doc-module-components="ng"></div>
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
@ngdoc error
|
||||
@name $httpBackend:noxhr
|
||||
@fullName Unsupported XHR
|
||||
@description
|
||||
|
||||
This error occurs in browsers that do not support XmlHttpRequest. AngularJS
|
||||
supports Safari, Chrome, Firefox, Opera, IE8 and higher, and mobile browsers
|
||||
(Android, Chrome Mobile, iOS Safari). To avoid this error, use an officially
|
||||
supported browser.
|
||||
@@ -4,4 +4,4 @@
|
||||
@description
|
||||
This error occurs when 'ngPattern' is passed an expression that isn't a regular expression or doesn't have the expected format.
|
||||
|
||||
For more information on valid expression syntax, see 'ngPattern' in {@link api/ng.directive:select input} directive docs.
|
||||
For more information on valid expression syntax, see 'ngPattern' in {@link api/ng.directive:input input} directive docs.
|
||||
|
||||
@@ -13,7 +13,7 @@ For example the issue can be triggered by this *invalid* code:
|
||||
<div ng-repeat="value in [4, 4]"></div>
|
||||
```
|
||||
|
||||
To resolve this error either ensure that the items in the collection have unique identity of use the `track by` syntax to specify how to track the association between models and DOM.
|
||||
To resolve this error either ensure that the items in the collection have unique identity or use the `track by` syntax to specify how to track the association between models and DOM.
|
||||
|
||||
To resolve the example above can be resolved by using `track by $index`, which will cause the items to be keyed by their position in the array instead of their value:
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -50,7 +50,7 @@ of which depend on other services that are provided by the Angular framework:
|
||||
* @param {*} message Message to be logged.
|
||||
*/
|
||||
function batchLogModule($provide){
|
||||
$provide.factory('batchLog', ['$timeout', '$log', function($timeout, $log) {
|
||||
$provide.factory('batchLog', ['$interval', '$log', function($interval, $log) {
|
||||
var messageQueue = [];
|
||||
|
||||
function log() {
|
||||
@@ -58,11 +58,10 @@ of which depend on other services that are provided by the Angular framework:
|
||||
$log('batchLog messages: ', messageQueue);
|
||||
messageQueue = [];
|
||||
}
|
||||
$timeout(log, 50000);
|
||||
}
|
||||
|
||||
// start periodic checking
|
||||
log();
|
||||
$interval(log, 50000);
|
||||
|
||||
return function(message) {
|
||||
messageQueue.push(message);
|
||||
@@ -82,13 +81,13 @@ of which depend on other services that are provided by the Angular framework:
|
||||
}]);
|
||||
}
|
||||
|
||||
// get the main service to kick of the application
|
||||
// get the main service to kick off the application
|
||||
angular.injector([batchLogModule]).get('routeTemplateMonitor');
|
||||
</pre>
|
||||
|
||||
Things to notice in this example:
|
||||
|
||||
* The `batchLog` service depends on the built-in {@link api/ng.$timeout $timeout} and
|
||||
* The `batchLog` service depends on the built-in {@link api/ng.$interval $interval} and
|
||||
{@link api/ng.$log $log} services, and allows messages to be logged into the
|
||||
`console.log` in batches.
|
||||
* The `routeTemplateMonitor` service depends on the built-in {@link api/ngRoute.$route
|
||||
|
||||
@@ -163,7 +163,7 @@ function MyClass(xhr) {
|
||||
This is the preferred method since the code makes no assumptions about the origin of `xhr` and cares
|
||||
instead about whoever created the class responsible for passing it in. Since the creator of the
|
||||
class should be different code than the user of the class, it separates the responsibility of
|
||||
creation from the logic. This is dependency-injection is in a nutshell.
|
||||
creation from the logic. This is dependency-injection in a nutshell.
|
||||
|
||||
The class above is testable, since in the test we can write:
|
||||
<pre>
|
||||
|
||||
@@ -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
|
||||
@@ -506,6 +506,8 @@ that you explicitly pass in.
|
||||
|
||||
<div class="alert alert-warning">
|
||||
**Note:** Normally, a scope prototypically inherits from its parent. An isolated scope does not.
|
||||
See the {@link guide/directive#creating-custom-directives_demo_isolating-the-scope-of-a-directive
|
||||
"Isolating the Scope of a Directive"} section for more information about isolate scopes.
|
||||
</div>
|
||||
|
||||
<div class="alert alert-success">
|
||||
@@ -528,8 +530,10 @@ where:
|
||||
* `attrs` is an object with the normalized attribute names and their corresponding values.
|
||||
|
||||
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 also want to remove the timeout
|
||||
if the directive is deleted so we don't introduce a memory leak.
|
||||
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 2 end testing, where we want to ensure that all $timeouts 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">
|
||||
<file name="script.js">
|
||||
@@ -537,7 +541,7 @@ if the directive is deleted so we don't introduce a memory leak.
|
||||
.controller('Ctrl2', function($scope) {
|
||||
$scope.format = 'M/d/yy h:mm:ss a';
|
||||
})
|
||||
.directive('myCurrentTime', function($timeout, dateFilter) {
|
||||
.directive('myCurrentTime', function($interval, dateFilter) {
|
||||
|
||||
function link(scope, element, attrs) {
|
||||
var format,
|
||||
@@ -552,20 +556,14 @@ if the directive is deleted so we don't introduce a memory leak.
|
||||
updateTime();
|
||||
});
|
||||
|
||||
function scheduleUpdate() {
|
||||
// save the timeoutId for canceling
|
||||
timeoutId = $timeout(function() {
|
||||
updateTime(); // update DOM
|
||||
scheduleUpdate(); // schedule the next update
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
element.on('$destroy', function() {
|
||||
$timeout.cancel(timeoutId);
|
||||
$interval.cancel(timeoutId);
|
||||
});
|
||||
|
||||
// start the UI update process.
|
||||
scheduleUpdate();
|
||||
// start the UI update process; save the timeoutId for canceling
|
||||
timeoutId = $interval(function() {
|
||||
updateTime(); // update DOM
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -583,7 +581,7 @@ if the directive is deleted so we don't introduce a memory leak.
|
||||
|
||||
There are a couple of things to note here.
|
||||
Just like the `module.controller` API, the function argument in `module.directive` is dependency
|
||||
injected. Because of this, we can use `$timeout` and `dateFilter` inside our directive's `link`
|
||||
injected. Because of this, we can use `$interval` and `dateFilter` inside our directive's `link`
|
||||
function.
|
||||
|
||||
We register an event `element.on('$destroy', ...)`. What fires this `$destroy` event?
|
||||
|
||||
@@ -33,10 +33,10 @@ In addition it provides an {@link api/ng.directive:ngModel.NgModelController API
|
||||
|
||||
<script>
|
||||
function Controller($scope) {
|
||||
$scope.master= {};
|
||||
$scope.master = {};
|
||||
|
||||
$scope.update = function(user) {
|
||||
$scope.master= angular.copy(user);
|
||||
$scope.master = angular.copy(user);
|
||||
};
|
||||
|
||||
$scope.reset = function() {
|
||||
@@ -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:ng-model} 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.
|
||||
@@ -235,7 +235,7 @@ In the following example we create two directives.
|
||||
<script>
|
||||
var app = angular.module('form-example1', []);
|
||||
|
||||
var INTEGER_REGEXP = /^\-?\d*$/;
|
||||
var INTEGER_REGEXP = /^\-?\d+$/;
|
||||
app.directive('integer', function() {
|
||||
return {
|
||||
require: 'ngModel',
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -18,8 +18,12 @@ watch {@link guide/expression expressions} and propagate events.
|
||||
propagate any model changes through the system into the view from outside of the "Angular
|
||||
realm" (controllers, services, Angular event handlers).
|
||||
|
||||
- Scopes can be nested to isolate application components while providing access to shared model
|
||||
properties. A scope (prototypically) inherits properties from its parent scope.
|
||||
- Scopes can be nested to limit access to the properties of application components while providing
|
||||
access to shared model properties. Nested scopes are either "child scopes" or "isolate scopes".
|
||||
A "child scope" (prototypically) inherits properties from its parent scope. An "isolate scope"
|
||||
does not. See {@link
|
||||
guide/directive#creating-custom-directives_demo_isolating-the-scope-of-a-directive isolated
|
||||
scopes} for more information.
|
||||
|
||||
- Scopes provide context against which {@link guide/expression expressions} are evaluated. For
|
||||
example `{{username}}` expression is meaningless, unless it is evaluated against a specific
|
||||
@@ -259,8 +263,8 @@ the `$digest` phase. This delay is desirable, since it coalesces multiple model
|
||||
For mutations to be properly observed, you should make them only within the {@link
|
||||
api/ng.$rootScope.Scope#methods_$apply scope.$apply()}. (Angular APIs do this
|
||||
implicitly, so no extra `$apply` call is needed when doing synchronous work in controllers,
|
||||
or asynchronous work with {@link api/ng.$http $http} or {@link
|
||||
api/ng.$timeout $timeout} services.
|
||||
or asynchronous work with {@link api/ng.$http $http}, {@link api/ng.$timeout $timeout}
|
||||
or {@link api/ng.$interval $interval} services.
|
||||
|
||||
4. **Mutation observation**
|
||||
|
||||
@@ -306,6 +310,8 @@ api/ng.directive:ngController ng-controller} and {@link
|
||||
api/ng.directive:ngRepeat ng-repeat}, create new child scopes
|
||||
and attach the child scope to the corresponding DOM element. You can retrieve a scope for any DOM
|
||||
element by using an `angular.element(aDomElement).scope()` method call.
|
||||
See the {@link guide/directive#creating-custom-directives_demo_isolating-the-scope-of-a-directive
|
||||
directives guide} for more information about isolate scopes.
|
||||
|
||||
### Controllers and Scopes
|
||||
|
||||
|
||||
@@ -46,6 +46,8 @@ and included in your {@link http://docs.oracle.com/javase/tutorial/essential/env
|
||||
npm install -g bower
|
||||
```
|
||||
|
||||
**Note:** You may need to use sudo (for OSX, *nix, BSD etc) or run your command shell as Administrator (for Windows) to install Grunt &
|
||||
Bower globally.
|
||||
|
||||
## Forking Angular on Github
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -179,7 +179,7 @@ For the purposes of this tutorial, we modified the angular-seed with the followi
|
||||
* Removed the example app
|
||||
* Added phone images to `app/img/phones/`
|
||||
* Added phone data files (JSON) to `app/phones/`
|
||||
* Added [Bootstrap](http://twitter.github.com/bootstrap/) files to `app/css/` and `app/img/`
|
||||
* Added [Bootstrap](http://getbootstrap.com) files to `app/css/` and `app/img/`
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@ phonecatApp.controller('PhoneListCtrl', function ($scope) {
|
||||
record. This property is used to order phones by age.
|
||||
|
||||
* We added a line to the controller that sets the default value of `orderProp` to `age`. If we had
|
||||
not set the default value here, the model would stay uninitialized until our user would pick an
|
||||
not set the default value here, the model would stay uninitialized until our user picks an
|
||||
option from the drop down menu.
|
||||
|
||||
This is a good time to talk about two-way data-binding. Notice that when the app is loaded in the
|
||||
|
||||
@@ -199,7 +199,7 @@ isolated from the work done in other tests.
|
||||
|
||||
* We created a new scope for our controller by calling `$rootScope.$new()`
|
||||
|
||||
* We called the injected `$controller` function passing the name of the`PhoneListCtrl` controller
|
||||
* We called the injected `$controller` function passing the name of the `PhoneListCtrl` controller
|
||||
and the created scope as parameters.
|
||||
|
||||
Because our code now uses the `$http` service to fetch the phone list data in our controller, before
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -11,7 +11,7 @@ In this step, you will improve the way our app fetches data.
|
||||
<div doc-tutorial-reset="11"></div>
|
||||
|
||||
|
||||
The last improvement we will make to our app is to define a custom service that represents a {@link
|
||||
The next improvement we will make to our app is to define a custom service that represents a {@link
|
||||
http://en.wikipedia.org/wiki/Representational_State_Transfer RESTful} client. Using this client we
|
||||
can make XHR requests for data in an easier way, without having to deal with the lower-level {@link
|
||||
api/ng.$http $http} API, HTTP methods and URLs.
|
||||
@@ -185,7 +185,7 @@ describe('PhoneCat controllers', function() {
|
||||
xyzPhoneData = function() {
|
||||
return {
|
||||
name: 'phone xyz',
|
||||
images: ['image/url1.png', 'image/url2.png']
|
||||
images: ['image/url1.png', 'image/url2.png']
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*/
|
||||
|
||||
exports.appCache = appCache;
|
||||
var fs = require('q-fs');
|
||||
var fs = require('q-io/fs');
|
||||
var Q = require('qq');
|
||||
function identity($) {return $;}
|
||||
|
||||
|
||||
+16
-3
@@ -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' +
|
||||
|
||||
+10
-4
@@ -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);
|
||||
@@ -74,10 +80,10 @@ function writeTheRest(writesFuture) {
|
||||
var versions = ngdoc.ngVersions();
|
||||
var currentVersion = ngdoc.ngCurrentVersion();
|
||||
|
||||
writesFuture.push(writer.symlink('../../docs/content/notes', 'build/docs/notes', 'dir'));
|
||||
writesFuture.push(writer.symlinkTemplate('css', 'dir'));
|
||||
writesFuture.push(writer.symlink('../../docs/img', 'build/docs/img', 'dir'));
|
||||
writesFuture.push(writer.symlinkTemplate('js', 'dir'));
|
||||
writesFuture.push(writer.symlink('../../docs/content/notes', 'build/docs/notes', 'directory'));
|
||||
writesFuture.push(writer.symlinkTemplate('css', 'directory'));
|
||||
writesFuture.push(writer.symlink('../../docs/img', 'build/docs/img', 'directory'));
|
||||
writesFuture.push(writer.symlinkTemplate('js', 'directory'));
|
||||
|
||||
var manifest = 'manifest="/build/docs/appcache.manifest"';
|
||||
|
||||
|
||||
+23
-3
@@ -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){
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ exports.collect = collect;
|
||||
|
||||
var ngdoc = require('./ngdoc.js'),
|
||||
Q = require('qq'),
|
||||
qfs = require('q-fs'),
|
||||
qfs = require('q-io/fs'),
|
||||
PATH = require('path');
|
||||
|
||||
var NEW_LINE = /\n\r?/;
|
||||
|
||||
@@ -167,6 +167,11 @@
|
||||
margin-top: .5em;
|
||||
}
|
||||
|
||||
.content h6 {
|
||||
text-transform:none;
|
||||
color:black;
|
||||
}
|
||||
|
||||
ul.parameters > li > p,
|
||||
.returns > p {
|
||||
display: inline;
|
||||
@@ -543,6 +548,10 @@ pre ol li {
|
||||
margin-bottom:30px;
|
||||
}
|
||||
|
||||
.definition-table td {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.component-heading {
|
||||
text-transform:capitalize;
|
||||
}
|
||||
|
||||
+2
-2
@@ -3,7 +3,7 @@
|
||||
* for testability
|
||||
*/
|
||||
var pathUtils = require('path');
|
||||
var qfs = require('q-fs');
|
||||
var qfs = require('q-io/fs');
|
||||
var Q = require('qq');
|
||||
var OUTPUT_DIR = pathUtils.join('build','docs');
|
||||
var TEMPLATES_DIR = pathUtils.join('docs','src','templates');
|
||||
@@ -76,7 +76,7 @@ function symlink(from, to, type) {
|
||||
// qfs will normalize the path arguments for us here
|
||||
return qfs.exists(to).then(function(exists) {
|
||||
if (!exists) {
|
||||
return qfs.symbolicLink(to, from, type);
|
||||
return qfs.symbolicLink(to, from, type || 'file');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
+7
-2
@@ -1,9 +1,12 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "#################################"
|
||||
echo "#### Jenkins Build ############"
|
||||
echo "#################################"
|
||||
|
||||
# Enable tracing and exit on first failure
|
||||
set -xe
|
||||
|
||||
|
||||
# Define reasonable set of browsers in case we are running manually from commandline
|
||||
if [[ -z "$BROWSERS" ]]
|
||||
then
|
||||
@@ -25,13 +28,15 @@ rm -f angular.js.size
|
||||
npm install --color false
|
||||
grunt ci-checks package --no-color
|
||||
|
||||
# DOCS generator unit tests #
|
||||
grunt test:docgen --no-color
|
||||
|
||||
# UNIT TESTS #
|
||||
grunt test:unit --browsers $BROWSERS --reporters=dots,junit --no-colors --no-color
|
||||
|
||||
|
||||
# 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
|
||||
|
||||
@@ -13,7 +13,10 @@ module.exports = function(config, specificOptions) {
|
||||
// SauceLabs config for local development.
|
||||
sauceLabs: {
|
||||
testName: specificOptions.testName || 'AngularJS',
|
||||
startConnect: true
|
||||
startConnect: true,
|
||||
options: {
|
||||
'selenium-version': '2.37.0'
|
||||
}
|
||||
},
|
||||
|
||||
// BrowserStack config for local development.
|
||||
@@ -33,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',
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
|
||||
+39
-2
@@ -36,13 +36,12 @@ module.exports = {
|
||||
var package = JSON.parse(fs.readFileSync('package.json', 'UTF-8'));
|
||||
var match = package.version.match(/^([^\-]*)(?:\-(.+))?$/);
|
||||
var semver = match[1].split('.');
|
||||
var hash = shell.exec('git rev-parse --short HEAD', {silent: true}).output.replace('\n', '');
|
||||
|
||||
var fullVersion = match[1];
|
||||
|
||||
if (match[2]) {
|
||||
fullVersion += '-';
|
||||
fullVersion += (match[2] == 'snapshot') ? hash : match[2];
|
||||
fullVersion += (match[2] == 'snapshot') ? getSnapshotSuffix() : match[2];
|
||||
}
|
||||
|
||||
version = {
|
||||
@@ -55,6 +54,12 @@ module.exports = {
|
||||
};
|
||||
|
||||
return version;
|
||||
|
||||
function getSnapshotSuffix() {
|
||||
var jenkinsBuild = process.env.BUILD_NUMBER || 'local';
|
||||
var hash = shell.exec('git rev-parse --short HEAD', {silent: true}).output.replace('\n', '');
|
||||
return 'build.'+jenkinsBuild+'+sha.'+hash;
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -79,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');
|
||||
|
||||
+15
-13
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"name": "angularjs",
|
||||
"version": "1.2.5",
|
||||
"cdnVersion": "1.2.4",
|
||||
"codename": "singularity-expansion",
|
||||
"version": "1.2.8",
|
||||
"cdnVersion": "1.2.7",
|
||||
"codename": "interdimensional-cartography",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/angular/angular.js.git"
|
||||
@@ -10,23 +10,26 @@
|
||||
"devDependencies": {
|
||||
"grunt": "~0.4.1",
|
||||
"bower": "~1.2.2",
|
||||
"grunt-bump": "~0.0.13",
|
||||
"grunt-contrib-clean": "~0.5.0",
|
||||
"grunt-contrib-compress": "~0.5.2",
|
||||
"grunt-contrib-connect": "~0.5.0",
|
||||
"grunt-contrib-copy": "~0.4.1",
|
||||
"jasmine-node": "~1.11.0",
|
||||
"q": "~0.9.2",
|
||||
"q-fs": "~0.1.36",
|
||||
"q-io": "~1.10.6",
|
||||
"qq": "~0.3.5",
|
||||
"shelljs": "~0.2.6",
|
||||
"karma": "~0.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.1.1",
|
||||
"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",
|
||||
@@ -38,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": [
|
||||
|
||||
@@ -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
|
||||
}
|
||||
};
|
||||
@@ -1,34 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
function catch_errors() {
|
||||
echo "ERROR. That's life."
|
||||
exit 1
|
||||
}
|
||||
|
||||
trap catch_errors ERR
|
||||
|
||||
TMP_FILE='changelog.tmp'
|
||||
CHANGELOG_FILE='CHANGELOG.md'
|
||||
|
||||
echo "Getting current version..."
|
||||
VERSION=`./version.js --current`
|
||||
|
||||
echo "Generating changelog..."
|
||||
./changelog.js $VERSION $TMP_FILE
|
||||
|
||||
cat $CHANGELOG_FILE >> $TMP_FILE
|
||||
mv -f $TMP_FILE $CHANGELOG_FILE
|
||||
|
||||
|
||||
echo "Updating version..."
|
||||
./version.js --remove-snapshot
|
||||
|
||||
echo "CONFIRM TO COMMIT"
|
||||
read WHATEVER
|
||||
|
||||
|
||||
echo "Creating commit..."
|
||||
git commit version.yaml CHANGELOG.md -m "chore(relase): cutting the v$VERSION release"
|
||||
|
||||
echo "Creating tag..."
|
||||
git tag "v$VERSION"
|
||||
Executable
+54
@@ -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
|
||||
Executable
+44
@@ -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
|
||||
Executable
+20
@@ -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
|
||||
Executable
+24
@@ -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
|
||||
Executable
+30
@@ -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
|
||||
Executable
+42
@@ -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
|
||||
Executable
+47
@@ -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
|
||||
@@ -1,23 +0,0 @@
|
||||
# Angular Bower Script
|
||||
|
||||
Script for updating the Angular bower repos from a code.angularjs.org package
|
||||
|
||||
Requires `node` (for parsing `bower.json`) and `wget` (for fetching the `angular.zip` from `code.angularjs.org`)
|
||||
|
||||
|
||||
## Instructions
|
||||
|
||||
You need to run `./init.sh` the first time you use this script to clone all the repos.
|
||||
|
||||
For subsequent updates:
|
||||
|
||||
```shell
|
||||
./publish.sh NEW_VERSION
|
||||
```
|
||||
|
||||
Where `NEW_VERSION` is a version number like `1.2.3`.
|
||||
|
||||
|
||||
## License
|
||||
MIT
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
#
|
||||
# init all of the bower repos
|
||||
#
|
||||
|
||||
set -e # fail if any command fails
|
||||
|
||||
REPOS=(
|
||||
angular \
|
||||
angular-animate \
|
||||
angular-cookies \
|
||||
angular-i18n \
|
||||
angular-loader \
|
||||
angular-mocks \
|
||||
angular-route \
|
||||
angular-resource \
|
||||
angular-sanitize \
|
||||
angular-scenario \
|
||||
angular-touch \
|
||||
)
|
||||
|
||||
cd `dirname $0`
|
||||
|
||||
for repo in "${REPOS[@]}"
|
||||
do
|
||||
git clone git@github.com:angular/bower-$repo.git
|
||||
done
|
||||
+88
-77
@@ -1,90 +1,101 @@
|
||||
#!/bin/bash
|
||||
|
||||
#
|
||||
# update all the things
|
||||
#
|
||||
# Script for updating the Angular bower repos from current local build.
|
||||
|
||||
set -e # fail if any command fails
|
||||
echo "#################################"
|
||||
echo "#### Update bower ###############"
|
||||
echo "#################################"
|
||||
|
||||
cd `dirname $0`
|
||||
|
||||
NEW_VERSION=$1
|
||||
|
||||
ZIP_FILE=angular-$NEW_VERSION.zip
|
||||
ZIP_FILE_URL=http://code.angularjs.org/$NEW_VERSION/angular-$NEW_VERSION.zip
|
||||
ZIP_DIR=angular-$NEW_VERSION
|
||||
|
||||
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)"
|
||||
)
|
||||
|
||||
|
||||
#
|
||||
# download and unzip the file
|
||||
#
|
||||
|
||||
if [ ! -f $ZIP_FILE ]; then
|
||||
wget $ZIP_FILE_URL
|
||||
unzip $ZIP_FILE
|
||||
fi
|
||||
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 zip
|
||||
#
|
||||
|
||||
for repo in "${REPOS[@]}"
|
||||
do
|
||||
if [ -f $ZIP_DIR/$repo.js ] # ignore i18l
|
||||
then
|
||||
cd bower-$repo
|
||||
git reset --hard HEAD
|
||||
git checkout master
|
||||
git fetch --all
|
||||
git reset --hard origin/master
|
||||
cd ..
|
||||
mv $ZIP_DIR/$repo.* bower-$repo/
|
||||
fi
|
||||
done
|
||||
|
||||
# move i18n files
|
||||
mv $ZIP_DIR/i18n/*.js bower-angular-i18n/
|
||||
|
||||
# move csp.css
|
||||
mv $ZIP_DIR/angular-csp.css 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
|
||||
|
||||
|
||||
#
|
||||
# get the old version number
|
||||
#
|
||||
#
|
||||
# move the files from the build
|
||||
#
|
||||
|
||||
OLD_VERSION=$(node -e "console.log(require('./bower-angular/bower').version)" | sed -e 's/\r//g')
|
||||
echo $OLD_VERSION
|
||||
echo $NEW_VERSION
|
||||
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
|
||||
|
||||
#
|
||||
# update bower.json
|
||||
# tag each repo
|
||||
#
|
||||
# move i18n files
|
||||
cp $BUILD_DIR/i18n/*.js $TMP_DIR/bower-angular-i18n/
|
||||
|
||||
for repo in "${REPOS[@]}"
|
||||
do
|
||||
cd bower-$repo
|
||||
sed -i '' -e "s/$OLD_VERSION/$NEW_VERSION/g" bower.json
|
||||
git add -A
|
||||
git commit -m "v$NEW_VERSION"
|
||||
git tag v$NEW_VERSION
|
||||
git push origin master
|
||||
git push origin v$NEW_VERSION
|
||||
cd ..
|
||||
done
|
||||
# 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
|
||||
|
||||
Executable
+73
@@ -0,0 +1,73 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Script for updating code.angularjs.org repo from current local build.
|
||||
|
||||
echo "#################################"
|
||||
echo "## Update code.angular.js.org ###"
|
||||
echo "#################################"
|
||||
|
||||
ARG_DEFS=(
|
||||
"--action=(prepare|publish)"
|
||||
)
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
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/
|
||||
|
||||
#
|
||||
# commit
|
||||
#
|
||||
echo "-- Committing code.angularjs.org"
|
||||
cd $REPO_DIR
|
||||
git add -A
|
||||
git commit -m "v$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
|
||||
|
||||
cd $REPO_DIR
|
||||
echo "-- Pushing code.angularjs.org"
|
||||
git push origin master
|
||||
|
||||
echo "-- Refreshing code.angularjs.org"
|
||||
curl http://code.angularjs.org/gitFetchSite.php
|
||||
}
|
||||
|
||||
source $(dirname $0)/../utils.inc
|
||||
Executable
+47
@@ -0,0 +1,47 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "#################################"
|
||||
echo "#### Update master ##############"
|
||||
echo "#################################"
|
||||
|
||||
ARG_DEFS=(
|
||||
"[--no-test=(true|false)]"
|
||||
)
|
||||
|
||||
function init {
|
||||
if [[ ! $VERBOSE ]]; then
|
||||
VERBOSE=false
|
||||
fi
|
||||
VERBOSE_ARG="--verbose=$VERBOSE"
|
||||
}
|
||||
|
||||
function build {
|
||||
cd ../..
|
||||
|
||||
if [[ $NO_TEST == "true" ]]; then
|
||||
npm install --color false
|
||||
grunt ci-checks package --no-color
|
||||
else
|
||||
./jenkins_build.sh
|
||||
fi
|
||||
|
||||
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
|
||||
Executable
+41
@@ -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
|
||||
Executable
+46
@@ -0,0 +1,46 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "#################################"
|
||||
echo "#### Cut release ################"
|
||||
echo "#################################"
|
||||
|
||||
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)]"
|
||||
)
|
||||
|
||||
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"
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
source $(dirname $0)/../utils.inc
|
||||
@@ -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
|
||||
|
||||
@@ -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 "$@"
|
||||
+7
-3
@@ -213,7 +213,9 @@ function forEach(obj, iterator, context) {
|
||||
if (obj) {
|
||||
if (isFunction(obj)){
|
||||
for (key in obj) {
|
||||
if (key != 'prototype' && key != 'length' && key != 'name' && obj.hasOwnProperty(key)) {
|
||||
// Need to check if hasOwnProperty exists,
|
||||
// as on IE8 the result of querySelectorAll is an object without a hasOwnProperty function
|
||||
if (key != 'prototype' && key != 'length' && key != 'name' && (!obj.hasOwnProperty || obj.hasOwnProperty(key))) {
|
||||
iterator.call(context, obj[key], key);
|
||||
}
|
||||
}
|
||||
@@ -769,7 +771,7 @@ function shallowCopy(src, dst) {
|
||||
for(var key in src) {
|
||||
// shallowCopy is only ever called by $compile nodeLinkFn, which has control over src
|
||||
// so we don't need to worry about using our custom hasOwnProperty here
|
||||
if (src.hasOwnProperty(key) && key.substr(0, 2) !== '$$') {
|
||||
if (src.hasOwnProperty(key) && key.charAt(0) !== '$' && key.charAt(1) !== '$') {
|
||||
dst[key] = src[key];
|
||||
}
|
||||
}
|
||||
@@ -957,7 +959,9 @@ function fromJson(json) {
|
||||
|
||||
|
||||
function toBoolean(value) {
|
||||
if (value && value.length !== 0) {
|
||||
if (typeof value === 'function') {
|
||||
value = true;
|
||||
} else if (value && value.length !== 0) {
|
||||
var v = lowercase("" + value);
|
||||
value = !(v == 'f' || v == '0' || v == 'false' || v == 'no' || v == 'n' || v == '[]');
|
||||
} else {
|
||||
|
||||
@@ -485,15 +485,15 @@ function annotate(fn) {
|
||||
* {@link AUTO.$provide#methods_service $provide.service(class)} that is defined as a CoffeeScript class.
|
||||
* <pre>
|
||||
* class Ping
|
||||
* constructor: (@$http)->
|
||||
* send: ()=>
|
||||
* constructor: (@$http) ->
|
||||
* send: () =>
|
||||
* @$http.get('/ping')
|
||||
*
|
||||
* $provide.service('ping', ['$http', Ping])
|
||||
* </pre>
|
||||
* You would then inject and use this service like this:
|
||||
* <pre>
|
||||
* someModule.controller 'Ctrl', ['ping', (ping)->
|
||||
* someModule.controller 'Ctrl', ['ping', (ping) ->
|
||||
* ping.send()
|
||||
* ]
|
||||
* </pre>
|
||||
@@ -740,6 +740,11 @@ function createInjector(modulesToLoad) {
|
||||
path.unshift(serviceName);
|
||||
cache[serviceName] = INSTANTIATING;
|
||||
return cache[serviceName] = factory(serviceName);
|
||||
} catch (err) {
|
||||
if (cache[serviceName] === INSTANTIATING) {
|
||||
delete cache[serviceName];
|
||||
}
|
||||
throw err;
|
||||
} finally {
|
||||
path.shift();
|
||||
}
|
||||
|
||||
+18
-1
@@ -54,6 +54,7 @@
|
||||
* - [`next()`](http://api.jquery.com/next/) - Does not support selectors
|
||||
* - [`on()`](http://api.jquery.com/on/) - Does not support namespaces, selectors or eventData
|
||||
* - [`off()`](http://api.jquery.com/off/) - Does not support namespaces or selectors
|
||||
* - [`one()`](http://api.jquery.com/one/) - Does not support namespaces or selectors
|
||||
* - [`parent()`](http://api.jquery.com/parent/) - Does not support selectors
|
||||
* - [`prepend()`](http://api.jquery.com/prepend/)
|
||||
* - [`prop()`](http://api.jquery.com/prop/)
|
||||
@@ -645,7 +646,10 @@ function createEventHandler(element, events) {
|
||||
return event.defaultPrevented || event.returnValue === false;
|
||||
};
|
||||
|
||||
forEach(events[type || event.type], function(fn) {
|
||||
// Copy event handlers in case event handlers array is modified during execution.
|
||||
var eventHandlersCopy = shallowCopy(events[type || event.type] || []);
|
||||
|
||||
forEach(eventHandlersCopy, function(fn) {
|
||||
fn.call(element, event);
|
||||
});
|
||||
|
||||
@@ -741,6 +745,19 @@ forEach({
|
||||
|
||||
off: jqLiteOff,
|
||||
|
||||
one: function(element, type, fn) {
|
||||
element = jqLite(element);
|
||||
|
||||
//add the listener twice so that when it is called
|
||||
//you can remove the original function and still be
|
||||
//able to call element.off(ev, fn) normally
|
||||
element.on(type, function onFn() {
|
||||
element.off(type, fn);
|
||||
element.off(type, onFn);
|
||||
});
|
||||
element.on(type, fn);
|
||||
},
|
||||
|
||||
replaceWith: function(element, replaceNode) {
|
||||
var index, parent = element.parentNode;
|
||||
jqLiteDealoc(element);
|
||||
|
||||
@@ -61,6 +61,28 @@ var $AnimateProvider = ['$provide', function($provide) {
|
||||
$provide.factory(key, factory);
|
||||
};
|
||||
|
||||
/**
|
||||
* @ngdoc function
|
||||
* @name ng.$animateProvider#classNameFilter
|
||||
* @methodOf ng.$animateProvider
|
||||
*
|
||||
* @description
|
||||
* Sets and/or returns the CSS class regular expression that is checked when performing
|
||||
* an animation. Upon bootstrap the classNameFilter value is not set at all and will
|
||||
* therefore enable $animate to attempt to perform an animation on any element.
|
||||
* When setting the classNameFilter value, animations will only be performed on elements
|
||||
* that successfully match the filter expression. This in turn can boost performance
|
||||
* for low-powered devices as well as applications containing a lot of structural operations.
|
||||
* @param {RegExp=} expression The className expression which will be checked against all animations
|
||||
* @return {RegExp} The current CSS className expression value. If null then there is no expression value
|
||||
*/
|
||||
this.classNameFilter = function(expression) {
|
||||
if(arguments.length === 1) {
|
||||
this.$$classNameFilter = (expression instanceof RegExp) ? expression : null;
|
||||
}
|
||||
return this.$$classNameFilter;
|
||||
};
|
||||
|
||||
this.$get = ['$timeout', function($timeout) {
|
||||
|
||||
/**
|
||||
|
||||
+7
-6
@@ -148,8 +148,9 @@ function Browser(window, document, $log, $sniffer) {
|
||||
* @param {boolean=} replace Should new url replace current history record ?
|
||||
*/
|
||||
self.url = function(url, replace) {
|
||||
// Android Browser BFCache causes location reference to become stale.
|
||||
// Android Browser BFCache causes location, history reference to become stale.
|
||||
if (location !== window.location) location = window.location;
|
||||
if (history !== window.history) history = window.history;
|
||||
|
||||
// setter
|
||||
if (url) {
|
||||
@@ -201,7 +202,7 @@ function Browser(window, document, $log, $sniffer) {
|
||||
* @description
|
||||
* Register callback function that will be called, when url changes.
|
||||
*
|
||||
* It's only called when the url is changed by outside of angular:
|
||||
* It's only called when the url is changed from outside of angular:
|
||||
* - user types different url into address bar
|
||||
* - user clicks on history (forward/back) button
|
||||
* - user clicks on a link
|
||||
@@ -243,7 +244,7 @@ function Browser(window, document, $log, $sniffer) {
|
||||
/**
|
||||
* @name ng.$browser#baseHref
|
||||
* @methodOf ng.$browser
|
||||
*
|
||||
*
|
||||
* @description
|
||||
* Returns current <base href>
|
||||
* (always relative - without domain)
|
||||
@@ -252,7 +253,7 @@ function Browser(window, document, $log, $sniffer) {
|
||||
*/
|
||||
self.baseHref = function() {
|
||||
var href = baseElement.attr('href');
|
||||
return href ? href.replace(/^https?\:\/\/[^\/]*/, '') : '';
|
||||
return href ? href.replace(/^(https?\:)?\/\/[^\/]*/, '') : '';
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
@@ -274,13 +275,13 @@ function Browser(window, document, $log, $sniffer) {
|
||||
* It is not meant to be used directly, use the $cookie service instead.
|
||||
*
|
||||
* The return values vary depending on the arguments that the method was called with as follows:
|
||||
*
|
||||
*
|
||||
* - cookies() -> hash of all cookies, this is NOT a copy of the internal state, so do not modify
|
||||
* it
|
||||
* - cookies(name, value) -> set name to value, if value is undefined delete the cookie
|
||||
* - cookies(name) -> the same as (name, undefined) == DELETES (no one calls it right now that
|
||||
* way)
|
||||
*
|
||||
*
|
||||
* @returns {Object} Hash of all cookies (if called without any parameter)
|
||||
*/
|
||||
self.cookies = function(name, value) {
|
||||
|
||||
+27
-24
@@ -24,7 +24,7 @@
|
||||
* @function
|
||||
*
|
||||
* @description
|
||||
* Compiles a piece of HTML string or DOM into a template and produces a template function, which
|
||||
* Compiles an HTML string or DOM into a template and produces a template function, which
|
||||
* can then be used to link {@link ng.$rootScope.Scope `scope`} and the template together.
|
||||
*
|
||||
* The compilation is a process of walking the DOM tree and matching DOM elements to
|
||||
@@ -469,14 +469,14 @@
|
||||
* example would not point to the clone, but rather to the original template that was cloned. In
|
||||
* this case, you can access the clone via the cloneAttachFn:
|
||||
* <pre>
|
||||
* var templateHTML = angular.element('<p>{{total}}</p>'),
|
||||
* var templateElement = angular.element('<p>{{total}}</p>'),
|
||||
* scope = ....;
|
||||
*
|
||||
* var clonedElement = $compile(templateHTML)(scope, function(clonedElement, scope) {
|
||||
* var clonedElement = $compile(templateElement)(scope, function(clonedElement, scope) {
|
||||
* //attach the clone to DOM document at the right place
|
||||
* });
|
||||
*
|
||||
* //now we have reference to the cloned DOM via `clone`
|
||||
* //now we have reference to the cloned DOM via `clonedElement`
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
@@ -818,6 +818,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
var compositeLinkFn =
|
||||
compileNodes($compileNodes, transcludeFn, $compileNodes,
|
||||
maxPriority, ignoreDirective, previousCompileContext);
|
||||
safeAddClass($compileNodes, 'ng-scope');
|
||||
return function publicLinkFn(scope, cloneConnectFn, transcludeControllers){
|
||||
assertArg(scope, 'scope');
|
||||
// important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart
|
||||
@@ -832,12 +833,13 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
|
||||
// Attach scope only to non-text nodes.
|
||||
for(var i = 0, ii = $linkNode.length; i<ii; i++) {
|
||||
var node = $linkNode[i];
|
||||
if (node.nodeType == 1 /* element */ || node.nodeType == 9 /* document */) {
|
||||
var node = $linkNode[i],
|
||||
nodeType = node.nodeType;
|
||||
if (nodeType === 1 /* element */ || nodeType === 9 /* document */) {
|
||||
$linkNode.eq(i).data('$scope', scope);
|
||||
}
|
||||
}
|
||||
safeAddClass($linkNode, 'ng-scope');
|
||||
|
||||
if (cloneConnectFn) cloneConnectFn($linkNode, scope);
|
||||
if (compositeLinkFn) compositeLinkFn(scope, $linkNode, $linkNode);
|
||||
return $linkNode;
|
||||
@@ -865,15 +867,15 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
* @param {DOMElement=} $rootElement If the nodeList is the root of the compilation tree then
|
||||
* the rootElement must be set the jqLite collection of the compile root. This is
|
||||
* needed so that the jqLite collection items can be replaced with widgets.
|
||||
* @param {number=} max directive priority
|
||||
* @param {number=} maxPriority Max directive priority.
|
||||
* @returns {?function} A composite linking function of all of the matched directives or null.
|
||||
*/
|
||||
function compileNodes(nodeList, transcludeFn, $rootElement, maxPriority, ignoreDirective,
|
||||
previousCompileContext) {
|
||||
var linkFns = [],
|
||||
nodeLinkFn, childLinkFn, directives, attrs, linkFnFound;
|
||||
attrs, directives, nodeLinkFn, childNodes, childLinkFn, linkFnFound;
|
||||
|
||||
for(var i = 0; i < nodeList.length; i++) {
|
||||
for (var i = 0; i < nodeList.length; i++) {
|
||||
attrs = new Attributes();
|
||||
|
||||
// we must always refer to nodeList[i] since the nodes can be replaced underneath us.
|
||||
@@ -885,16 +887,19 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
null, [], [], previousCompileContext)
|
||||
: null;
|
||||
|
||||
if (nodeLinkFn && nodeLinkFn.scope) {
|
||||
safeAddClass(jqLite(nodeList[i]), 'ng-scope');
|
||||
}
|
||||
|
||||
childLinkFn = (nodeLinkFn && nodeLinkFn.terminal ||
|
||||
!nodeList[i].childNodes ||
|
||||
!nodeList[i].childNodes.length)
|
||||
!(childNodes = nodeList[i].childNodes) ||
|
||||
!childNodes.length)
|
||||
? null
|
||||
: compileNodes(nodeList[i].childNodes,
|
||||
: compileNodes(childNodes,
|
||||
nodeLinkFn ? nodeLinkFn.transclude : transcludeFn);
|
||||
|
||||
linkFns.push(nodeLinkFn);
|
||||
linkFns.push(childLinkFn);
|
||||
linkFnFound = (linkFnFound || nodeLinkFn || childLinkFn);
|
||||
linkFns.push(nodeLinkFn, childLinkFn);
|
||||
linkFnFound = linkFnFound || nodeLinkFn || childLinkFn;
|
||||
//use the previous context only for the first element in the virtual group
|
||||
previousCompileContext = null;
|
||||
}
|
||||
@@ -906,9 +911,10 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
var nodeLinkFn, childLinkFn, node, $node, childScope, childTranscludeFn, i, ii, n;
|
||||
|
||||
// copy nodeList so that linking doesn't break due to live list updates.
|
||||
var stableNodeList = [];
|
||||
for (i = 0, ii = nodeList.length; i < ii; i++) {
|
||||
stableNodeList.push(nodeList[i]);
|
||||
var nodeListLength = nodeList.length,
|
||||
stableNodeList = new Array(nodeListLength);
|
||||
for (i = 0; i < nodeListLength; i++) {
|
||||
stableNodeList[i] = nodeList[i];
|
||||
}
|
||||
|
||||
for(i = 0, n = 0, ii = linkFns.length; i < ii; n++) {
|
||||
@@ -921,7 +927,6 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
if (nodeLinkFn.scope) {
|
||||
childScope = scope.$new();
|
||||
$node.data('$scope', childScope);
|
||||
safeAddClass($node, 'ng-scope');
|
||||
} else {
|
||||
childScope = scope;
|
||||
}
|
||||
@@ -1004,9 +1009,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
|
||||
nName = directiveNormalize(name.toLowerCase());
|
||||
attrsMap[nName] = name;
|
||||
attrs[nName] = value = trim((msie && name == 'href')
|
||||
? decodeURIComponent(node.getAttribute(name, 2))
|
||||
: attr.value);
|
||||
attrs[nName] = value = trim(attr.value);
|
||||
if (getBooleanAttrName(node, nName)) {
|
||||
attrs[nName] = true; // presence means true
|
||||
}
|
||||
@@ -1954,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 +4,7 @@
|
||||
* @ngdoc directive
|
||||
* @name ng.directive:ngHref
|
||||
* @restrict A
|
||||
* @priority 99
|
||||
*
|
||||
* @description
|
||||
* Using Angular markup like `{{hash}}` in an href attribute will
|
||||
@@ -87,6 +88,7 @@
|
||||
* @ngdoc directive
|
||||
* @name ng.directive:ngSrc
|
||||
* @restrict A
|
||||
* @priority 99
|
||||
*
|
||||
* @description
|
||||
* Using Angular markup like `{{hash}}` in a `src` attribute doesn't
|
||||
@@ -112,6 +114,7 @@
|
||||
* @ngdoc directive
|
||||
* @name ng.directive:ngSrcset
|
||||
* @restrict A
|
||||
* @priority 99
|
||||
*
|
||||
* @description
|
||||
* Using Angular markup like `{{hash}}` in a `srcset` attribute doesn't
|
||||
@@ -137,6 +140,7 @@
|
||||
* @ngdoc directive
|
||||
* @name ng.directive:ngDisabled
|
||||
* @restrict A
|
||||
* @priority 100
|
||||
*
|
||||
* @description
|
||||
*
|
||||
@@ -180,6 +184,7 @@
|
||||
* @ngdoc directive
|
||||
* @name ng.directive:ngChecked
|
||||
* @restrict A
|
||||
* @priority 100
|
||||
*
|
||||
* @description
|
||||
* The HTML specification does not require browsers to preserve the values of boolean attributes
|
||||
@@ -214,6 +219,7 @@
|
||||
* @ngdoc directive
|
||||
* @name ng.directive:ngReadonly
|
||||
* @restrict A
|
||||
* @priority 100
|
||||
*
|
||||
* @description
|
||||
* The HTML specification does not require browsers to preserve the values of boolean attributes
|
||||
@@ -223,7 +229,6 @@
|
||||
* The `ngReadonly` directive solves this problem for the `readonly` attribute.
|
||||
* This complementary directive is not removed by the browser and so provides
|
||||
* a permanent reliable place to store the binding information.
|
||||
|
||||
* @example
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
@@ -249,6 +254,7 @@
|
||||
* @ngdoc directive
|
||||
* @name ng.directive:ngSelected
|
||||
* @restrict A
|
||||
* @priority 100
|
||||
*
|
||||
* @description
|
||||
* The HTML specification does not require browsers to preserve the values of boolean attributes
|
||||
@@ -258,6 +264,7 @@
|
||||
* The `ngSelected` directive solves this problem for the `selected` atttribute.
|
||||
* This complementary directive is not removed by the browser and so provides
|
||||
* a permanent reliable place to store the binding information.
|
||||
*
|
||||
* @example
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
@@ -285,6 +292,7 @@
|
||||
* @ngdoc directive
|
||||
* @name ng.directive:ngOpen
|
||||
* @restrict A
|
||||
* @priority 100
|
||||
*
|
||||
* @description
|
||||
* The HTML specification does not require browsers to preserve the values of boolean attributes
|
||||
@@ -294,8 +302,6 @@
|
||||
* The `ngOpen` directive solves this problem for the `open` attribute.
|
||||
* This complementary directive is not removed by the browser and so provides
|
||||
* a permanent reliable place to store the binding information.
|
||||
|
||||
*
|
||||
* @example
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
@@ -330,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);
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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
|
||||
|
||||
+33
-71
@@ -390,20 +390,28 @@ 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,
|
||||
// hold the listener until composition is done.
|
||||
// More about composition events: https://developer.mozilla.org/en-US/docs/Web/API/CompositionEvent
|
||||
var composing = false;
|
||||
if (!$sniffer.android) {
|
||||
var composing = false;
|
||||
|
||||
element.on('compositionstart', function() {
|
||||
composing = true;
|
||||
});
|
||||
element.on('compositionstart', function(data) {
|
||||
composing = true;
|
||||
});
|
||||
|
||||
element.on('compositionend', function() {
|
||||
composing = false;
|
||||
});
|
||||
element.on('compositionend', function() {
|
||||
composing = false;
|
||||
});
|
||||
}
|
||||
|
||||
var listener = function() {
|
||||
if (composing) return;
|
||||
@@ -417,9 +425,13 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
|
||||
}
|
||||
|
||||
if (ctrl.$viewValue !== value) {
|
||||
scope.$apply(function() {
|
||||
if (scope.$$phase) {
|
||||
ctrl.$setViewValue(value);
|
||||
});
|
||||
} else {
|
||||
scope.$apply(function() {
|
||||
ctrl.$setViewValue(value);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -468,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) {
|
||||
@@ -494,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);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -506,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);
|
||||
@@ -523,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);
|
||||
@@ -558,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);
|
||||
@@ -574,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);
|
||||
@@ -588,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);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -603,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);
|
||||
@@ -620,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);
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
*
|
||||
* Legacy browsers, like IE7, do not provide attribute selector support (added in CSS 2.1) so they
|
||||
* cannot match the `[ng\:cloak]` selector. To work around this limitation, you must add the css
|
||||
* class `ngCloak` in addition to the `ngCloak` directive as shown in the example below.
|
||||
* class `ng-cloak` in addition to the `ngCloak` directive as shown in the example below.
|
||||
*
|
||||
* @element ANY
|
||||
*
|
||||
|
||||
@@ -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>
|
||||
*/
|
||||
/*
|
||||
@@ -69,7 +69,14 @@ forEach(
|
||||
* a dblclick. (The Event object is available as `$event`)
|
||||
*
|
||||
* @example
|
||||
* See {@link ng.directive:ngClick ngClick}
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
<button ng-dblclick="count = count + 1" ng-init="count=0">
|
||||
Increment (on double click)
|
||||
</button>
|
||||
count: {{count}}
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
*/
|
||||
|
||||
|
||||
@@ -85,7 +92,14 @@ forEach(
|
||||
* mousedown. (Event object is available as `$event`)
|
||||
*
|
||||
* @example
|
||||
* See {@link ng.directive:ngClick ngClick}
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
<button ng-mousedown="count = count + 1" ng-init="count=0">
|
||||
Increment (on mouse down)
|
||||
</button>
|
||||
count: {{count}}
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
*/
|
||||
|
||||
|
||||
@@ -101,7 +115,14 @@ forEach(
|
||||
* mouseup. (Event object is available as `$event`)
|
||||
*
|
||||
* @example
|
||||
* See {@link ng.directive:ngClick ngClick}
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
<button ng-mouseup="count = count + 1" ng-init="count=0">
|
||||
Increment (on mouse up)
|
||||
</button>
|
||||
count: {{count}}
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -116,7 +137,14 @@ forEach(
|
||||
* mouseover. (Event object is available as `$event`)
|
||||
*
|
||||
* @example
|
||||
* See {@link ng.directive:ngClick ngClick}
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
<button ng-mouseover="count = count + 1" ng-init="count=0">
|
||||
Increment (when mouse is over)
|
||||
</button>
|
||||
count: {{count}}
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
*/
|
||||
|
||||
|
||||
@@ -132,7 +160,14 @@ forEach(
|
||||
* mouseenter. (Event object is available as `$event`)
|
||||
*
|
||||
* @example
|
||||
* See {@link ng.directive:ngClick ngClick}
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
<button ng-mouseenter="count = count + 1" ng-init="count=0">
|
||||
Increment (when mouse enters)
|
||||
</button>
|
||||
count: {{count}}
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
*/
|
||||
|
||||
|
||||
@@ -148,7 +183,14 @@ forEach(
|
||||
* mouseleave. (Event object is available as `$event`)
|
||||
*
|
||||
* @example
|
||||
* See {@link ng.directive:ngClick ngClick}
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
<button ng-mouseleave="count = count + 1" ng-init="count=0">
|
||||
Increment (when mouse leaves)
|
||||
</button>
|
||||
count: {{count}}
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
*/
|
||||
|
||||
|
||||
@@ -164,7 +206,14 @@ forEach(
|
||||
* mousemove. (Event object is available as `$event`)
|
||||
*
|
||||
* @example
|
||||
* See {@link ng.directive:ngClick ngClick}
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
<button ng-mousemove="count = count + 1" ng-init="count=0">
|
||||
Increment (when mouse moves)
|
||||
</button>
|
||||
count: {{count}}
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
*/
|
||||
|
||||
|
||||
@@ -180,7 +229,12 @@ forEach(
|
||||
* keydown. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
|
||||
*
|
||||
* @example
|
||||
* See {@link ng.directive:ngClick ngClick}
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
<input ng-keydown="count = count + 1" ng-init="count=0">
|
||||
key down count: {{count}}
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
*/
|
||||
|
||||
|
||||
@@ -196,7 +250,12 @@ forEach(
|
||||
* keyup. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
|
||||
*
|
||||
* @example
|
||||
* See {@link ng.directive:ngClick ngClick}
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
<input ng-keyup="count = count + 1" ng-init="count=0">
|
||||
key up count: {{count}}
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
*/
|
||||
|
||||
|
||||
@@ -212,7 +271,12 @@ forEach(
|
||||
* keypress. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
|
||||
*
|
||||
* @example
|
||||
* See {@link ng.directive:ngClick ngClick}
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
<input ng-keypress="count = count + 1" ng-init="count=0">
|
||||
key press count: {{count}}
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
*/
|
||||
|
||||
|
||||
@@ -311,7 +375,12 @@ forEach(
|
||||
* copy. (Event object is available as `$event`)
|
||||
*
|
||||
* @example
|
||||
* See {@link ng.directive:ngClick ngClick}
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
<input ng-copy="copied=true" ng-init="copied=false; value='copy me'" ng-model="value">
|
||||
copied: {{copied}}
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -326,7 +395,12 @@ forEach(
|
||||
* cut. (Event object is available as `$event`)
|
||||
*
|
||||
* @example
|
||||
* See {@link ng.directive:ngClick ngClick}
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
<input ng-cut="cut=true" ng-init="cut=false; value='cut me'" ng-model="value">
|
||||
cut: {{cut}}
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -341,5 +415,10 @@ forEach(
|
||||
* paste. (Event object is available as `$event`)
|
||||
*
|
||||
* @example
|
||||
* See {@link ng.directive:ngClick ngClick}
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
<input ng-paste="paste=true" ng-init="paste=false" placeholder='paste here'>
|
||||
pasted: {{paste}}
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
*/
|
||||
|
||||
@@ -59,9 +59,6 @@
|
||||
padding:10px;
|
||||
}
|
||||
|
||||
/*
|
||||
The transition styles can also be placed on the CSS base class above
|
||||
*/
|
||||
.animate-if.ng-enter, .animate-if.ng-leave {
|
||||
-webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
|
||||
transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
* current scope.
|
||||
*
|
||||
* <div class="alert alert-error">
|
||||
* The only appropriate use of `ngInit` for aliasing special properties of
|
||||
* The only appropriate use of `ngInit` is for aliasing special properties of
|
||||
* {@link api/ng.directive:ngRepeat `ngRepeat`}, as seen in the demo below. Besides this case, you
|
||||
* should use {@link guide/controller controllers} rather than `ngInit`
|
||||
* to initialize values on a scope.
|
||||
|
||||
@@ -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
|
||||
@@ -203,7 +205,7 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
|
||||
$$tlb: true,
|
||||
link: function($scope, $element, $attr, ctrl, $transclude){
|
||||
var expression = $attr.ngRepeat;
|
||||
var match = expression.match(/^\s*(.+)\s+in\s+(.*?)\s*(\s+track\s+by\s+(.+)\s*)?$/),
|
||||
var match = expression.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?\s*$/),
|
||||
trackByExp, trackByExpGetter, trackByIdExpFn, trackByIdArrayFn, trackByIdObjFn,
|
||||
lhs, rhs, valueIdentifier, keyIdentifier,
|
||||
hashFnLocals = {$id: hashKey};
|
||||
@@ -215,7 +217,7 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
|
||||
|
||||
lhs = match[1];
|
||||
rhs = match[2];
|
||||
trackByExp = match[4];
|
||||
trackByExp = match[3];
|
||||
|
||||
if (trackByExp) {
|
||||
trackByExpGetter = $parse(trackByExp);
|
||||
|
||||
@@ -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 });
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -221,18 +221,10 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
|
||||
selectCtrl.init(ngModelCtrl, nullOption, unknownOption);
|
||||
|
||||
// required validator
|
||||
if (multiple && (attr.required || attr.ngRequired)) {
|
||||
var requiredValidator = function(value) {
|
||||
ngModelCtrl.$setValidity('required', !attr.required || (value && value.length));
|
||||
return value;
|
||||
if (multiple) {
|
||||
ngModelCtrl.$isEmpty = function(value) {
|
||||
return !value || value.length === 0;
|
||||
};
|
||||
|
||||
ngModelCtrl.$parsers.push(requiredValidator);
|
||||
ngModelCtrl.$formatters.unshift(requiredValidator);
|
||||
|
||||
attr.$observe('required', function() {
|
||||
requiredValidator(ngModelCtrl.$viewValue);
|
||||
});
|
||||
}
|
||||
|
||||
if (optionsExp) setupAsOptions(scope, element, ngModelCtrl);
|
||||
|
||||
+1
-2
@@ -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){
|
||||
|
||||
+12
-23
@@ -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
|
||||
@@ -25,21 +25,21 @@
|
||||
* property of the object. That's equivalent to the simple substring match with a `string`
|
||||
* as described above.
|
||||
*
|
||||
* - `function`: A predicate function can be used to write arbitrary filters. The function is
|
||||
* - `function(value)`: A predicate function can be used to write arbitrary filters. The function is
|
||||
* called for each element of `array`. The final result is an array of those elements that
|
||||
* the predicate returned true for.
|
||||
*
|
||||
* @param {function(expected, actual)|true|undefined} comparator Comparator which is used in
|
||||
* @param {function(actual, expected)|true|undefined} comparator Comparator which is used in
|
||||
* determining if the expected value (from the filter expression) and actual value (from
|
||||
* the object in the array) should be considered a match.
|
||||
*
|
||||
* Can be one of:
|
||||
*
|
||||
* - `function(expected, actual)`:
|
||||
* - `function(actual, expected)`:
|
||||
* The function will be given the object value and the predicate value to compare and
|
||||
* should return true if the item should be included in filtered result.
|
||||
*
|
||||
* - `true`: A shorthand for `function(expected, actual) { return angular.equals(expected, actual)}`.
|
||||
* - `true`: A shorthand for `function(actual, expected) { return angular.equals(expected, actual)}`.
|
||||
* this is essentially strict comparison of expected and actual.
|
||||
*
|
||||
* - `false|undefined`: A short hand for a function which will look for a substring match in case
|
||||
@@ -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':
|
||||
|
||||
+19
-7
@@ -222,7 +222,7 @@ function $HttpProvider() {
|
||||
* will result in the success callback being called. Note that if the response is a redirect,
|
||||
* XMLHttpRequest will transparently follow it, meaning that the error callback will not be
|
||||
* called for such responses.
|
||||
*
|
||||
*
|
||||
* # Calling $http from outside AngularJS
|
||||
* The `$http` service will not actually send the request until the next `$digest()` is
|
||||
* executed. Normally this is not an issue, since almost all the time your call to `$http` will
|
||||
@@ -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
|
||||
@@ -409,19 +419,20 @@ function $HttpProvider() {
|
||||
* return responseOrNewPromise
|
||||
* }
|
||||
* return $q.reject(rejection);
|
||||
* };
|
||||
* }
|
||||
* }
|
||||
* };
|
||||
* });
|
||||
*
|
||||
* $httpProvider.interceptors.push('myHttpInterceptor');
|
||||
*
|
||||
*
|
||||
* // register the interceptor via an anonymous factory
|
||||
* // alternatively, register the interceptor via an anonymous factory
|
||||
* $httpProvider.interceptors.push(function($q, dependency1, dependency2) {
|
||||
* return {
|
||||
* 'request': function(config) {
|
||||
* // same as above
|
||||
* },
|
||||
*
|
||||
* 'response': function(response) {
|
||||
* // same as above
|
||||
* }
|
||||
@@ -528,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
|
||||
|
||||
+28
-18
@@ -1,12 +1,12 @@
|
||||
'use strict';
|
||||
|
||||
var XHR = window.XMLHttpRequest || function() {
|
||||
function createXhr(method) {
|
||||
// IE8 doesn't support PATCH method, but the ActiveX object does
|
||||
/* global ActiveXObject */
|
||||
try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); } catch (e1) {}
|
||||
try { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); } catch (e2) {}
|
||||
try { return new ActiveXObject("Msxml2.XMLHTTP"); } catch (e3) {}
|
||||
throw minErr('$httpBackend')('noxhr', "This browser does not support XMLHttpRequest.");
|
||||
};
|
||||
return (msie <= 8 && lowercase(method) === 'patch')
|
||||
? new ActiveXObject('Microsoft.XMLHTTP')
|
||||
: new window.XMLHttpRequest();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@@ -28,11 +28,11 @@ var XHR = window.XMLHttpRequest || function() {
|
||||
*/
|
||||
function $HttpBackendProvider() {
|
||||
this.$get = ['$browser', '$window', '$document', function($browser, $window, $document) {
|
||||
return createHttpBackend($browser, XHR, $browser.defer, $window.angular.callbacks, $document[0]);
|
||||
return createHttpBackend($browser, createXhr, $browser.defer, $window.angular.callbacks, $document[0]);
|
||||
}];
|
||||
}
|
||||
|
||||
function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument) {
|
||||
function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDocument) {
|
||||
var ABORTED = -1;
|
||||
|
||||
// TODO(vojta): fix the signature
|
||||
@@ -54,10 +54,12 @@ function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument)
|
||||
} else {
|
||||
completeRequest(callback, status || -2);
|
||||
}
|
||||
delete callbacks[callbackId];
|
||||
callbacks[callbackId] = angular.noop;
|
||||
});
|
||||
} else {
|
||||
var xhr = new XHR();
|
||||
|
||||
var xhr = createXhr(method);
|
||||
|
||||
xhr.open(method, url, true);
|
||||
forEach(headers, function(value, key) {
|
||||
if (isDefined(value)) {
|
||||
@@ -69,17 +71,25 @@ function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument)
|
||||
// response is in the cache. the promise api will ensure that to the app code the api is
|
||||
// always async
|
||||
xhr.onreadystatechange = function() {
|
||||
if (xhr.readyState == 4) {
|
||||
// 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
|
||||
//
|
||||
// we can't set xhr.onreadystatechange to undefined or delete it because that breaks IE8 (method=PATCH) and
|
||||
// Safari respectively.
|
||||
if (xhr && xhr.readyState == 4) {
|
||||
var responseHeaders = null,
|
||||
response = null;
|
||||
|
||||
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,
|
||||
@@ -112,14 +122,14 @@ function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument)
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@@ -24,6 +24,14 @@ function $IntervalProvider() {
|
||||
* In tests you can use {@link ngMock.$interval#methods_flush `$interval.flush(millis)`} to
|
||||
* move forward by `millis` milliseconds and trigger any functions scheduled to run in that
|
||||
* time.
|
||||
*
|
||||
* <div class="alert alert-warning">
|
||||
* **Note**: Intervals created by this service must be explicitly destroyed when you are finished
|
||||
* with them. In particular they are not automatically destroyed when a controller's scope or a
|
||||
* directive's element are destroyed.
|
||||
* You should take this into consideration and make sure to always cancel the interval at the
|
||||
* appropriate moment. See the example below for more details on how and when to do this.
|
||||
* </div>
|
||||
*
|
||||
* @param {function()} fn A function that should be called repeatedly.
|
||||
* @param {number} delay Number of milliseconds between each function call.
|
||||
@@ -32,6 +40,95 @@ function $IntervalProvider() {
|
||||
* @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
|
||||
* will invoke `fn` within the {@link ng.$rootScope.Scope#methods_$apply $apply} block.
|
||||
* @returns {promise} A promise which will be notified on each iteration.
|
||||
*
|
||||
* @example
|
||||
<doc:example module="time">
|
||||
<doc:source>
|
||||
<script>
|
||||
function Ctrl2($scope,$interval) {
|
||||
$scope.format = 'M/d/yy h:mm:ss a';
|
||||
$scope.blood_1 = 100;
|
||||
$scope.blood_2 = 120;
|
||||
|
||||
var stop;
|
||||
$scope.fight = function() {
|
||||
// Don't start a new fight if we are already fighting
|
||||
if ( angular.isDefined(stop) ) return;
|
||||
|
||||
stop = $interval(function() {
|
||||
if ($scope.blood_1 > 0 && $scope.blood_2 > 0) {
|
||||
$scope.blood_1 = $scope.blood_1 - 3;
|
||||
$scope.blood_2 = $scope.blood_2 - 4;
|
||||
} else {
|
||||
$scope.stopFight();
|
||||
}
|
||||
}, 100);
|
||||
};
|
||||
|
||||
$scope.stopFight = function() {
|
||||
if (angular.isDefined(stop)) {
|
||||
$interval.cancel(stop);
|
||||
stop = undefined;
|
||||
}
|
||||
};
|
||||
|
||||
$scope.resetFight = function() {
|
||||
$scope.blood_1 = 100;
|
||||
$scope.blood_2 = 120;
|
||||
}
|
||||
|
||||
$scope.$on('$destroy', function() {
|
||||
// Make sure that the interval is destroyed too
|
||||
$scope.stopFight();
|
||||
});
|
||||
}
|
||||
|
||||
angular.module('time', [])
|
||||
// Register the 'myCurrentTime' directive factory method.
|
||||
// We inject $interval and dateFilter service since the factory method is DI.
|
||||
.directive('myCurrentTime', function($interval, dateFilter) {
|
||||
// return the directive link function. (compile function not needed)
|
||||
return function(scope, element, attrs) {
|
||||
var format, // date format
|
||||
stopTime; // so that we can cancel the time updates
|
||||
|
||||
// used to update the UI
|
||||
function updateTime() {
|
||||
element.text(dateFilter(new Date(), format));
|
||||
}
|
||||
|
||||
// watch the expression, and update the UI on change.
|
||||
scope.$watch(attrs.myCurrentTime, function(value) {
|
||||
format = value;
|
||||
updateTime();
|
||||
});
|
||||
|
||||
stopTime = $interval(updateTime, 1000);
|
||||
|
||||
// listen on DOM destroy (removal) event, and cancel the next UI update
|
||||
// to prevent updating time ofter the DOM element was removed.
|
||||
element.bind('$destroy', function() {
|
||||
$interval.cancel(stopTime);
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<div ng-controller="Ctrl2">
|
||||
Date format: <input ng-model="format"> <hr/>
|
||||
Current time is: <span my-current-time="format"></span>
|
||||
<hr/>
|
||||
Blood 1 : <font color='red'>{{blood_1}}</font>
|
||||
Blood 2 : <font color='red'>{{blood_2}}</font>
|
||||
<button type="button" data-ng-click="fight()">Fight</button>
|
||||
<button type="button" data-ng-click="stopFight()">StopFight</button>
|
||||
<button type="button" data-ng-click="resetFight()">resetFight</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
*/
|
||||
function interval(fn, delay, count, invokeApply) {
|
||||
var setInterval = $window.setInterval,
|
||||
|
||||
+15
-7
@@ -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
|
||||
@@ -629,6 +629,13 @@ function $LocationProvider(){
|
||||
}
|
||||
|
||||
var absHref = elm.prop('href');
|
||||
|
||||
if (isObject(absHref) && absHref.toString() === '[object SVGAnimatedString]') {
|
||||
// SVGAnimatedString.animVal should be identical to SVGAnimatedString.baseVal, unless during
|
||||
// an animation.
|
||||
absHref = urlResolve(absHref.animVal).href;
|
||||
}
|
||||
|
||||
var rewrittenUrl = $location.$$rewrite(absHref);
|
||||
|
||||
if (absHref && !elm.attr('target') && rewrittenUrl && !event.isDefaultPrevented()) {
|
||||
@@ -652,16 +659,17 @@ function $LocationProvider(){
|
||||
// update $location when $browser url changes
|
||||
$browser.onUrlChange(function(newUrl) {
|
||||
if ($location.absUrl() != newUrl) {
|
||||
if ($rootScope.$broadcast('$locationChangeStart', newUrl,
|
||||
$location.absUrl()).defaultPrevented) {
|
||||
$browser.url($location.absUrl());
|
||||
return;
|
||||
}
|
||||
$rootScope.$evalAsync(function() {
|
||||
var oldUrl = $location.absUrl();
|
||||
|
||||
$location.$$parse(newUrl);
|
||||
afterLocationChange(oldUrl);
|
||||
if ($rootScope.$broadcast('$locationChangeStart', newUrl,
|
||||
oldUrl).defaultPrevented) {
|
||||
$location.$$parse(oldUrl);
|
||||
$browser.url(oldUrl);
|
||||
} else {
|
||||
afterLocationChange(oldUrl);
|
||||
}
|
||||
});
|
||||
if (!$rootScope.$$phase) $rootScope.$digest();
|
||||
}
|
||||
|
||||
+9
-2
@@ -139,9 +139,16 @@ function $LogProvider(){
|
||||
|
||||
function consoleLog(type) {
|
||||
var console = $window.console || {},
|
||||
logFn = console[type] || console.log || noop;
|
||||
logFn = console[type] || console.log || noop,
|
||||
hasApply = false;
|
||||
|
||||
if (logFn.apply) {
|
||||
// Note: reading logFn.apply throws an error in IE11 in IE8 document mode.
|
||||
// The reason behind this is that console.log has type "object" in IE8...
|
||||
try {
|
||||
hasApply = !! logFn.apply;
|
||||
} catch (e) {}
|
||||
|
||||
if (hasApply) {
|
||||
return function() {
|
||||
var args = [];
|
||||
forEach(arguments, function(arg) {
|
||||
|
||||
+50
-17
@@ -891,19 +891,23 @@ function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
|
||||
? function cspSafeGetter(scope, locals) {
|
||||
var pathVal = (locals && locals.hasOwnProperty(key0)) ? locals : scope;
|
||||
|
||||
if (pathVal === null || pathVal === undefined) return pathVal;
|
||||
if (pathVal == null) return pathVal;
|
||||
pathVal = pathVal[key0];
|
||||
|
||||
if (!key1 || pathVal === null || pathVal === undefined) return pathVal;
|
||||
if (!key1) return pathVal;
|
||||
if (pathVal == null) return undefined;
|
||||
pathVal = pathVal[key1];
|
||||
|
||||
if (!key2 || pathVal === null || pathVal === undefined) return pathVal;
|
||||
if (!key2) return pathVal;
|
||||
if (pathVal == null) return undefined;
|
||||
pathVal = pathVal[key2];
|
||||
|
||||
if (!key3 || pathVal === null || pathVal === undefined) return pathVal;
|
||||
if (!key3) return pathVal;
|
||||
if (pathVal == null) return undefined;
|
||||
pathVal = pathVal[key3];
|
||||
|
||||
if (!key4 || pathVal === null || pathVal === undefined) return pathVal;
|
||||
if (!key4) return pathVal;
|
||||
if (pathVal == null) return undefined;
|
||||
pathVal = pathVal[key4];
|
||||
|
||||
return pathVal;
|
||||
@@ -912,7 +916,7 @@ function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
|
||||
var pathVal = (locals && locals.hasOwnProperty(key0)) ? locals : scope,
|
||||
promise;
|
||||
|
||||
if (pathVal === null || pathVal === undefined) return pathVal;
|
||||
if (pathVal == null) return pathVal;
|
||||
|
||||
pathVal = pathVal[key0];
|
||||
if (pathVal && pathVal.then) {
|
||||
@@ -924,8 +928,9 @@ function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
|
||||
}
|
||||
pathVal = pathVal.$$v;
|
||||
}
|
||||
if (!key1 || pathVal === null || pathVal === undefined) return 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 (!key2 || pathVal === null || pathVal === undefined) return 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 (!key3 || pathVal === null || pathVal === undefined) return 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 (!key4 || pathVal === null || pathVal === undefined) return pathVal;
|
||||
|
||||
if (!key4) return pathVal;
|
||||
if (pathVal == null) return undefined;
|
||||
pathVal = pathVal[key4];
|
||||
if (pathVal && pathVal.then) {
|
||||
promiseWarning(fullExp);
|
||||
@@ -976,6 +984,26 @@ function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
|
||||
};
|
||||
}
|
||||
|
||||
function simpleGetterFn1(key0, fullExp) {
|
||||
ensureSafeMemberName(key0, fullExp);
|
||||
|
||||
return function simpleGetterFn1(scope, locals) {
|
||||
if (scope == null) return undefined;
|
||||
return ((locals && locals.hasOwnProperty(key0)) ? locals : scope)[key0];
|
||||
};
|
||||
}
|
||||
|
||||
function simpleGetterFn2(key0, key1, fullExp) {
|
||||
ensureSafeMemberName(key0, fullExp);
|
||||
ensureSafeMemberName(key1, fullExp);
|
||||
|
||||
return function simpleGetterFn2(scope, locals) {
|
||||
if (scope == null) return undefined;
|
||||
scope = ((locals && locals.hasOwnProperty(key0)) ? locals : scope)[key0];
|
||||
return scope == null ? undefined : scope[key1];
|
||||
};
|
||||
}
|
||||
|
||||
function getterFn(path, options, fullExp) {
|
||||
// Check whether the cache has this getter already.
|
||||
// We can use hasOwnProperty directly on the cache because we ensure,
|
||||
@@ -988,7 +1016,13 @@ function getterFn(path, options, fullExp) {
|
||||
pathKeysLength = pathKeys.length,
|
||||
fn;
|
||||
|
||||
if (options.csp) {
|
||||
// When we have only 1 or 2 tokens, use optimized special case closures.
|
||||
// http://jsperf.com/angularjs-parse-getter/6
|
||||
if (!options.unwrapPromises && pathKeysLength === 1) {
|
||||
fn = simpleGetterFn1(pathKeys[0], fullExp);
|
||||
} else if (!options.unwrapPromises && pathKeysLength === 2) {
|
||||
fn = simpleGetterFn2(pathKeys[0], pathKeys[1], fullExp);
|
||||
} else if (options.csp) {
|
||||
if (pathKeysLength < 6) {
|
||||
fn = cspSafeGetterFn(pathKeys[0], pathKeys[1], pathKeys[2], pathKeys[3], pathKeys[4], fullExp,
|
||||
options);
|
||||
@@ -1006,11 +1040,10 @@ function getterFn(path, options, fullExp) {
|
||||
};
|
||||
}
|
||||
} else {
|
||||
var code = 'var l, fn, p;\n';
|
||||
var code = 'var p;\n';
|
||||
forEach(pathKeys, function(key, index) {
|
||||
ensureSafeMemberName(key, fullExp);
|
||||
code += 'if(s === null || s === undefined) return s;\n' +
|
||||
'l=s;\n' +
|
||||
code += 'if(s == null) return undefined;\n' +
|
||||
's='+ (index
|
||||
// we simply dereference 's' on any .dot notation
|
||||
? 's'
|
||||
@@ -1033,10 +1066,10 @@ function getterFn(path, options, fullExp) {
|
||||
/* jshint -W054 */
|
||||
var evaledFnGetter = new Function('s', 'k', 'pw', code); // s=scope, k=locals, pw=promiseWarning
|
||||
/* jshint +W054 */
|
||||
evaledFnGetter.toString = function() { return code; };
|
||||
fn = function(scope, locals) {
|
||||
evaledFnGetter.toString = valueFn(code);
|
||||
fn = options.unwrapPromises ? function(scope, locals) {
|
||||
return evaledFnGetter(scope, locals, promiseWarning);
|
||||
};
|
||||
} : evaledFnGetter;
|
||||
}
|
||||
|
||||
// Only cache the value if it's not going to mess up the cache object
|
||||
|
||||
+32
-6
@@ -133,6 +133,7 @@ function $RootScopeProvider(){
|
||||
this.$$asyncQueue = [];
|
||||
this.$$postDigestQueue = [];
|
||||
this.$$listeners = {};
|
||||
this.$$listenerCount = {};
|
||||
this.$$isolateBindings = {};
|
||||
}
|
||||
|
||||
@@ -185,13 +186,14 @@ 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();
|
||||
}
|
||||
child['this'] = child;
|
||||
child.$$listeners = {};
|
||||
child.$$listenerCount = {};
|
||||
child.$parent = this;
|
||||
child.$$watchers = child.$$nextSibling = child.$$childHead = child.$$childTail = null;
|
||||
child.$$prevSibling = this.$$childTail;
|
||||
@@ -285,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);
|
||||
|
||||
@@ -351,6 +353,7 @@ function $RootScopeProvider(){
|
||||
|
||||
return function() {
|
||||
arrayRemove(array, watcher);
|
||||
lastDirtyWatch = null;
|
||||
};
|
||||
},
|
||||
|
||||
@@ -696,6 +699,8 @@ function $RootScopeProvider(){
|
||||
this.$$destroyed = true;
|
||||
if (this === $rootScope) return;
|
||||
|
||||
forEach(this.$$listenerCount, bind(null, decrementListenerCount, this));
|
||||
|
||||
if (parent.$$childHead == this) parent.$$childHead = this.$$nextSibling;
|
||||
if (parent.$$childTail == this) parent.$$childTail = this.$$prevSibling;
|
||||
if (this.$$prevSibling) this.$$prevSibling.$$nextSibling = this.$$nextSibling;
|
||||
@@ -885,8 +890,18 @@ function $RootScopeProvider(){
|
||||
}
|
||||
namedListeners.push(listener);
|
||||
|
||||
var current = this;
|
||||
do {
|
||||
if (!current.$$listenerCount[name]) {
|
||||
current.$$listenerCount[name] = 0;
|
||||
}
|
||||
current.$$listenerCount[name]++;
|
||||
} while ((current = current.$parent));
|
||||
|
||||
var self = this;
|
||||
return function() {
|
||||
namedListeners[indexOf(namedListeners, listener)] = null;
|
||||
decrementListenerCount(self, 1, name);
|
||||
};
|
||||
},
|
||||
|
||||
@@ -998,8 +1013,7 @@ function $RootScopeProvider(){
|
||||
listeners, i, length;
|
||||
|
||||
//down while you can, then up and next sibling or up and next sibling until back at root
|
||||
do {
|
||||
current = next;
|
||||
while ((current = next)) {
|
||||
event.currentScope = current;
|
||||
listeners = current.$$listeners[name] || [];
|
||||
for (i=0, length = listeners.length; i<length; i++) {
|
||||
@@ -1021,12 +1035,14 @@ function $RootScopeProvider(){
|
||||
// Insanity Warning: scope depth-first traversal
|
||||
// yes, this code is a bit crazy, but it works and we have tests to prove it!
|
||||
// this piece should be kept in sync with the traversal in $digest
|
||||
if (!(next = (current.$$childHead || (current !== target && current.$$nextSibling)))) {
|
||||
// (though it differs due to having the extra check for $$listenerCount)
|
||||
if (!(next = ((current.$$listenerCount[name] && current.$$childHead) ||
|
||||
(current !== target && current.$$nextSibling)))) {
|
||||
while(current !== target && !(next = current.$$nextSibling)) {
|
||||
current = current.$parent;
|
||||
}
|
||||
}
|
||||
} while ((current = next));
|
||||
}
|
||||
|
||||
return event;
|
||||
}
|
||||
@@ -1055,6 +1071,16 @@ function $RootScopeProvider(){
|
||||
return fn;
|
||||
}
|
||||
|
||||
function decrementListenerCount(current, count, name) {
|
||||
do {
|
||||
current.$$listenerCount[name] -= count;
|
||||
|
||||
if (current.$$listenerCount[name] === 0) {
|
||||
delete current.$$listenerCount[name];
|
||||
}
|
||||
} while ((current = current.$parent));
|
||||
}
|
||||
|
||||
/**
|
||||
* function used as an initial value for watchers.
|
||||
* because it's unique we can easily tell it apart from other values
|
||||
|
||||
+2
-1
@@ -59,7 +59,7 @@ function $SnifferProvider() {
|
||||
// http://code.google.com/p/android/issues/detail?id=17471
|
||||
// https://github.com/angular/angular.js/issues/904
|
||||
|
||||
// older webit browser (533.9) on Boxee box has exactly the same problem as Android has
|
||||
// older webkit browser (533.9) on Boxee box has exactly the same problem as Android has
|
||||
// so let's not use the history API also
|
||||
// We are purposefully using `!(android < 4)` to cover the case when `android` is undefined
|
||||
// jshint -W018
|
||||
@@ -85,6 +85,7 @@ function $SnifferProvider() {
|
||||
vendorPrefix: vendorPrefix,
|
||||
transitions : transitions,
|
||||
animations : animations,
|
||||
android: android,
|
||||
msie : msie,
|
||||
msieDocumentMode: documentMode
|
||||
};
|
||||
|
||||
@@ -32,93 +32,6 @@ function $TimeoutProvider() {
|
||||
* @returns {Promise} Promise that will be resolved when the timeout is reached. The value this
|
||||
* promise will be resolved with is the return value of the `fn` function.
|
||||
*
|
||||
* @example
|
||||
<doc:example module="time">
|
||||
<doc:source>
|
||||
<script>
|
||||
function Ctrl2($scope,$timeout) {
|
||||
$scope.format = 'M/d/yy h:mm:ss a';
|
||||
$scope.blood_1 = 100;
|
||||
$scope.blood_2 = 120;
|
||||
|
||||
var stop;
|
||||
$scope.fight = function() {
|
||||
stop = $timeout(function() {
|
||||
if ($scope.blood_1 > 0 && $scope.blood_2 > 0) {
|
||||
$scope.blood_1 = $scope.blood_1 - 3;
|
||||
$scope.blood_2 = $scope.blood_2 - 4;
|
||||
$scope.fight();
|
||||
} else {
|
||||
$timeout.cancel(stop);
|
||||
}
|
||||
}, 100);
|
||||
};
|
||||
|
||||
$scope.stopFight = function() {
|
||||
$timeout.cancel(stop);
|
||||
};
|
||||
|
||||
$scope.resetFight = function() {
|
||||
$scope.blood_1 = 100;
|
||||
$scope.blood_2 = 120;
|
||||
}
|
||||
}
|
||||
|
||||
angular.module('time', [])
|
||||
// Register the 'myCurrentTime' directive factory method.
|
||||
// We inject $timeout and dateFilter service since the factory method is DI.
|
||||
.directive('myCurrentTime', function($timeout, dateFilter) {
|
||||
// return the directive link function. (compile function not needed)
|
||||
return function(scope, element, attrs) {
|
||||
var format, // date format
|
||||
timeoutId; // timeoutId, so that we can cancel the time updates
|
||||
|
||||
// used to update the UI
|
||||
function updateTime() {
|
||||
element.text(dateFilter(new Date(), format));
|
||||
}
|
||||
|
||||
// watch the expression, and update the UI on change.
|
||||
scope.$watch(attrs.myCurrentTime, function(value) {
|
||||
format = value;
|
||||
updateTime();
|
||||
});
|
||||
|
||||
// schedule update in one second
|
||||
function updateLater() {
|
||||
// save the timeoutId for canceling
|
||||
timeoutId = $timeout(function() {
|
||||
updateTime(); // update DOM
|
||||
updateLater(); // schedule another update
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
// listen on DOM destroy (removal) event, and cancel the next UI update
|
||||
// to prevent updating time ofter the DOM element was removed.
|
||||
element.bind('$destroy', function() {
|
||||
$timeout.cancel(timeoutId);
|
||||
});
|
||||
|
||||
updateLater(); // kick off the UI update process.
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<div ng-controller="Ctrl2">
|
||||
Date format: <input ng-model="format"> <hr/>
|
||||
Current time is: <span my-current-time="format"></span>
|
||||
<hr/>
|
||||
Blood 1 : <font color='red'>{{blood_1}}</font>
|
||||
Blood 2 : <font color='red'>{{blood_2}}</font>
|
||||
<button type="button" data-ng-click="fight()">Fight</button>
|
||||
<button type="button" data-ng-click="stopFight()">StopFight</button>
|
||||
<button type="button" data-ng-click="resetFight()">resetFight</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
*/
|
||||
function timeout(fn, delay, invokeApply) {
|
||||
var deferred = $q.defer(),
|
||||
|
||||
+97
-40
@@ -288,6 +288,13 @@ angular.module('ngAnimate', ['ng'])
|
||||
});
|
||||
});
|
||||
|
||||
var classNameFilter = $animateProvider.classNameFilter();
|
||||
var isAnimatableClassName = !classNameFilter
|
||||
? function() { return true; }
|
||||
: function(className) {
|
||||
return classNameFilter.test(className);
|
||||
};
|
||||
|
||||
function lookup(name) {
|
||||
if (name) {
|
||||
var matches = [],
|
||||
@@ -569,17 +576,20 @@ angular.module('ngAnimate', ['ng'])
|
||||
and the onComplete callback will be fired once the animation is fully complete.
|
||||
*/
|
||||
function performAnimation(animationEvent, className, element, parentElement, afterElement, domOperation, doneCallback) {
|
||||
var node = extractElementNode(element);
|
||||
var currentClassName, classes, node = extractElementNode(element);
|
||||
if(node) {
|
||||
currentClassName = node.className;
|
||||
classes = currentClassName + ' ' + className;
|
||||
}
|
||||
|
||||
//transcluded directives may sometimes fire an animation using only comment nodes
|
||||
//best to catch this early on to prevent any animation operations from occurring
|
||||
if(!node) {
|
||||
if(!node || !isAnimatableClassName(classes)) {
|
||||
fireDOMOperation();
|
||||
closeAnimation();
|
||||
return;
|
||||
}
|
||||
|
||||
var currentClassName = node.className;
|
||||
var classes = currentClassName + ' ' + className;
|
||||
var animationLookup = (' ' + classes).replace(/\s+/g,'.');
|
||||
if (!parentElement) {
|
||||
parentElement = afterElement ? afterElement.parent() : element.parent();
|
||||
@@ -600,9 +610,14 @@ angular.module('ngAnimate', ['ng'])
|
||||
}
|
||||
|
||||
var animations = [];
|
||||
|
||||
//only add animations if the currently running animation is not structural
|
||||
//or if there is no animation running at all
|
||||
if(!ngAnimateState.running || !(isClassBased && ngAnimateState.structural)) {
|
||||
var allowAnimations = isClassBased ?
|
||||
!ngAnimateState.disabled && (!ngAnimateState.running || !ngAnimateState.structural) :
|
||||
true;
|
||||
|
||||
if(allowAnimations) {
|
||||
forEach(matches, function(animation) {
|
||||
//add the animation to the queue to if it is allowed to be cancelled
|
||||
if(!animation.allowCancel || animation.allowCancel(element, animationEvent, className)) {
|
||||
@@ -881,27 +896,73 @@ angular.module('ngAnimate', ['ng'])
|
||||
var ANIMATION_ITERATION_COUNT_KEY = 'IterationCount';
|
||||
var NG_ANIMATE_PARENT_KEY = '$$ngAnimateKey';
|
||||
var NG_ANIMATE_CSS_DATA_KEY = '$$ngAnimateCSS3Data';
|
||||
var NG_ANIMATE_FALLBACK_CLASS_NAME = 'ng-animate-start';
|
||||
var NG_ANIMATE_FALLBACK_ACTIVE_CLASS_NAME = 'ng-animate-active';
|
||||
var ELAPSED_TIME_MAX_DECIMAL_PLACES = 3;
|
||||
var CLOSING_TIME_BUFFER = 1.5;
|
||||
var ONE_SECOND = 1000;
|
||||
|
||||
var animationCounter = 0;
|
||||
var lookupCache = {};
|
||||
var parentCounter = 0;
|
||||
|
||||
var animationReflowQueue = [], animationTimer, timeOut = false;
|
||||
function afterReflow(callback) {
|
||||
animationReflowQueue.push(callback);
|
||||
var animationReflowQueue = [];
|
||||
var animationElementQueue = [];
|
||||
var animationTimer;
|
||||
var closingAnimationTime = 0;
|
||||
var timeOut = false;
|
||||
function afterReflow(element, callback) {
|
||||
$timeout.cancel(animationTimer);
|
||||
|
||||
animationReflowQueue.push(callback);
|
||||
|
||||
var node = extractElementNode(element);
|
||||
element = angular.element(node);
|
||||
animationElementQueue.push(element);
|
||||
|
||||
var elementData = element.data(NG_ANIMATE_CSS_DATA_KEY);
|
||||
closingAnimationTime = Math.max(closingAnimationTime,
|
||||
(elementData.maxDelay + elementData.maxDuration) * CLOSING_TIME_BUFFER * ONE_SECOND);
|
||||
|
||||
//by placing a counter we can avoid an accidental
|
||||
//race condition which may close an animation when
|
||||
//a follow-up animation is midway in its animation
|
||||
elementData.animationCount = animationCounter;
|
||||
|
||||
animationTimer = $timeout(function() {
|
||||
forEach(animationReflowQueue, function(fn) {
|
||||
fn();
|
||||
});
|
||||
|
||||
//copy the list of elements so that successive
|
||||
//animations won't conflict if they're added before
|
||||
//the closing animation timeout has run
|
||||
var elementQueueSnapshot = [];
|
||||
var animationCounterSnapshot = animationCounter;
|
||||
forEach(animationElementQueue, function(elm) {
|
||||
elementQueueSnapshot.push(elm);
|
||||
});
|
||||
|
||||
$timeout(function() {
|
||||
closeAllAnimations(elementQueueSnapshot, animationCounterSnapshot);
|
||||
elementQueueSnapshot = null;
|
||||
}, closingAnimationTime, false);
|
||||
|
||||
animationReflowQueue = [];
|
||||
animationElementQueue = [];
|
||||
animationTimer = null;
|
||||
lookupCache = {};
|
||||
closingAnimationTime = 0;
|
||||
animationCounter++;
|
||||
}, 10, false);
|
||||
}
|
||||
|
||||
function closeAllAnimations(elements, count) {
|
||||
forEach(elements, function(element) {
|
||||
var elementData = element.data(NG_ANIMATE_CSS_DATA_KEY);
|
||||
if(elementData && elementData.animationCount == count) {
|
||||
(elementData.closeAnimationFn || noop)();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function getElementAnimationDetails(element, cacheKey) {
|
||||
var data = cacheKey ? lookupCache[cacheKey] : null;
|
||||
if(!data) {
|
||||
@@ -1007,6 +1068,7 @@ angular.module('ngAnimate', ['ng'])
|
||||
timeout is empty (this would cause a flicker bug normally
|
||||
in the page. There is also no point in performing an animation
|
||||
that only has a delay and no duration */
|
||||
var maxDelay = Math.max(timings.transitionDelay, timings.animationDelay);
|
||||
var maxDuration = Math.max(timings.transitionDuration, timings.animationDuration);
|
||||
if(maxDuration === 0) {
|
||||
element.removeClass(className);
|
||||
@@ -1016,13 +1078,9 @@ angular.module('ngAnimate', ['ng'])
|
||||
//temporarily disable the transition so that the enter styles
|
||||
//don't animate twice (this is here to avoid a bug in Chrome/FF).
|
||||
var activeClassName = '';
|
||||
if(timings.transitionDuration > 0) {
|
||||
element.addClass(NG_ANIMATE_FALLBACK_CLASS_NAME);
|
||||
activeClassName += NG_ANIMATE_FALLBACK_ACTIVE_CLASS_NAME + ' ';
|
||||
blockTransitions(element);
|
||||
} else {
|
||||
timings.transitionDuration > 0 ?
|
||||
blockTransitions(element) :
|
||||
blockKeyframeAnimations(element);
|
||||
}
|
||||
|
||||
forEach(className.split(' '), function(klass, i) {
|
||||
activeClassName += (i > 0 ? ' ' : '') + klass + '-active';
|
||||
@@ -1032,6 +1090,7 @@ angular.module('ngAnimate', ['ng'])
|
||||
className : className,
|
||||
activeClassName : activeClassName,
|
||||
maxDuration : maxDuration,
|
||||
maxDelay : maxDelay,
|
||||
classes : className + ' ' + activeClassName,
|
||||
timings : timings,
|
||||
stagger : stagger,
|
||||
@@ -1066,30 +1125,28 @@ angular.module('ngAnimate', ['ng'])
|
||||
}
|
||||
|
||||
function animateRun(element, className, activeAnimationComplete) {
|
||||
var data = element.data(NG_ANIMATE_CSS_DATA_KEY);
|
||||
var elementData = element.data(NG_ANIMATE_CSS_DATA_KEY);
|
||||
var node = extractElementNode(element);
|
||||
if(node.className.indexOf(className) == -1 || !data) {
|
||||
if(node.className.indexOf(className) == -1 || !elementData) {
|
||||
activeAnimationComplete();
|
||||
return;
|
||||
}
|
||||
|
||||
var timings = data.timings;
|
||||
var stagger = data.stagger;
|
||||
var maxDuration = data.maxDuration;
|
||||
var activeClassName = data.activeClassName;
|
||||
var maxDelayTime = Math.max(timings.transitionDelay, timings.animationDelay) * 1000;
|
||||
var timings = elementData.timings;
|
||||
var stagger = elementData.stagger;
|
||||
var maxDuration = elementData.maxDuration;
|
||||
var activeClassName = elementData.activeClassName;
|
||||
var maxDelayTime = Math.max(timings.transitionDelay, timings.animationDelay) * ONE_SECOND;
|
||||
var startTime = Date.now();
|
||||
var css3AnimationEvents = ANIMATIONEND_EVENT + ' ' + TRANSITIONEND_EVENT;
|
||||
var ii = data.ii;
|
||||
var ii = elementData.ii;
|
||||
|
||||
var applyFallbackStyle, style = '', appliedStyles = [];
|
||||
var style = '', appliedStyles = [];
|
||||
if(timings.transitionDuration > 0) {
|
||||
var propertyStyle = timings.transitionPropertyStyle;
|
||||
if(propertyStyle.indexOf('all') == -1) {
|
||||
applyFallbackStyle = true;
|
||||
var fallbackProperty = $sniffer.msie ? '-ms-zoom' : 'border-spacing';
|
||||
style += CSS_PREFIX + 'transition-property: ' + propertyStyle + ', ' + fallbackProperty + '; ';
|
||||
style += CSS_PREFIX + 'transition-duration: ' + timings.transitionDurationStyle + ', ' + timings.transitionDuration + 's; ';
|
||||
style += CSS_PREFIX + 'transition-property: ' + propertyStyle + ';';
|
||||
style += CSS_PREFIX + 'transition-duration: ' + timings.transitionDurationStyle + ';';
|
||||
appliedStyles.push(CSS_PREFIX + 'transition-property');
|
||||
appliedStyles.push(CSS_PREFIX + 'transition-duration');
|
||||
}
|
||||
@@ -1098,10 +1155,6 @@ angular.module('ngAnimate', ['ng'])
|
||||
if(ii > 0) {
|
||||
if(stagger.transitionDelay > 0 && stagger.transitionDuration === 0) {
|
||||
var delayStyle = timings.transitionDelayStyle;
|
||||
if(applyFallbackStyle) {
|
||||
delayStyle += ', ' + timings.transitionDelay + 's';
|
||||
}
|
||||
|
||||
style += CSS_PREFIX + 'transition-delay: ' +
|
||||
prepareStaggerDelay(delayStyle, stagger.transitionDelay, ii) + '; ';
|
||||
appliedStyles.push(CSS_PREFIX + 'transition-delay');
|
||||
@@ -1124,11 +1177,16 @@ angular.module('ngAnimate', ['ng'])
|
||||
|
||||
element.on(css3AnimationEvents, onAnimationProgress);
|
||||
element.addClass(activeClassName);
|
||||
elementData.closeAnimationFn = function() {
|
||||
onEnd();
|
||||
activeAnimationComplete();
|
||||
};
|
||||
return onEnd;
|
||||
|
||||
// This will automatically be called by $animate so
|
||||
// there is no need to attach this internally to the
|
||||
// timeout done method.
|
||||
return function onEnd(cancelled) {
|
||||
function onEnd(cancelled) {
|
||||
element.off(css3AnimationEvents, onAnimationProgress);
|
||||
element.removeClass(activeClassName);
|
||||
animateClose(element, className);
|
||||
@@ -1136,7 +1194,7 @@ angular.module('ngAnimate', ['ng'])
|
||||
for (var i in appliedStyles) {
|
||||
node.style.removeProperty(appliedStyles[i]);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function onAnimationProgress(event) {
|
||||
event.stopPropagation();
|
||||
@@ -1202,7 +1260,7 @@ angular.module('ngAnimate', ['ng'])
|
||||
//data from the element which will not make the 2nd animation
|
||||
//happen in the first place
|
||||
var cancel = preReflowCancellation;
|
||||
afterReflow(function() {
|
||||
afterReflow(element, function() {
|
||||
unblockTransitions(element);
|
||||
unblockKeyframeAnimations(element);
|
||||
//once the reflow is complete then we point cancel to
|
||||
@@ -1218,7 +1276,6 @@ angular.module('ngAnimate', ['ng'])
|
||||
|
||||
function animateClose(element, className) {
|
||||
element.removeClass(className);
|
||||
element.removeClass(NG_ANIMATE_FALLBACK_CLASS_NAME);
|
||||
element.removeData(NG_ANIMATE_CSS_DATA_KEY);
|
||||
}
|
||||
|
||||
@@ -1268,7 +1325,7 @@ angular.module('ngAnimate', ['ng'])
|
||||
beforeAddClass : function(element, className, animationCompleted) {
|
||||
var cancellationMethod = animateBefore(element, suffixClasses(className, '-add'));
|
||||
if(cancellationMethod) {
|
||||
afterReflow(function() {
|
||||
afterReflow(element, function() {
|
||||
unblockTransitions(element);
|
||||
unblockKeyframeAnimations(element);
|
||||
animationCompleted();
|
||||
@@ -1285,7 +1342,7 @@ angular.module('ngAnimate', ['ng'])
|
||||
beforeRemoveClass : function(element, className, animationCompleted) {
|
||||
var cancellationMethod = animateBefore(element, suffixClasses(className, '-remove'));
|
||||
if(cancellationMethod) {
|
||||
afterReflow(function() {
|
||||
afterReflow(element, function() {
|
||||
unblockTransitions(element);
|
||||
unblockKeyframeAnimations(element);
|
||||
animationCompleted();
|
||||
|
||||
Vendored
+21
-1
@@ -1572,6 +1572,10 @@ function MockHttpExpectation(method, url, data, headers) {
|
||||
};
|
||||
}
|
||||
|
||||
function createMockXhr() {
|
||||
return new MockXhr();
|
||||
}
|
||||
|
||||
function MockXhr() {
|
||||
|
||||
// hack for testing $http, $httpBackend
|
||||
@@ -2075,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');
|
||||
@@ -2095,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;
|
||||
|
||||
@@ -35,7 +35,7 @@ function shallowClearAndCopy(src, dst) {
|
||||
});
|
||||
|
||||
for (var key in src) {
|
||||
if (src.hasOwnProperty(key) && key.substr(0, 2) !== '$$') {
|
||||
if (src.hasOwnProperty(key) && key.charAt(0) !== '$' && key.charAt(1) !== '$') {
|
||||
dst[key] = src[key];
|
||||
}
|
||||
}
|
||||
@@ -237,7 +237,7 @@ function shallowClearAndCopy(src, dst) {
|
||||
newCard.name = "Mike Smith";
|
||||
newCard.$save();
|
||||
// POST: /user/123/card {number:'0123', name:'Mike Smith'}
|
||||
// server returns: {id:789, number:'01234', name: 'Mike Smith'};
|
||||
// server returns: {id:789, number:'0123', name: 'Mike Smith'};
|
||||
expect(newCard.id).toEqual(789);
|
||||
* </pre>
|
||||
*
|
||||
@@ -272,6 +272,35 @@ function shallowClearAndCopy(src, dst) {
|
||||
});
|
||||
});
|
||||
</pre>
|
||||
|
||||
* # Creating a custom 'PUT' request
|
||||
* In this example we create a custom method on our resource to make a PUT request
|
||||
* <pre>
|
||||
* var app = angular.module('app', ['ngResource', 'ngRoute']);
|
||||
*
|
||||
* // Some APIs expect a PUT request in the format URL/object/ID
|
||||
* // Here we are creating an 'update' method
|
||||
* app.factory('Notes', ['$resource', function($resource) {
|
||||
* return $resource('/notes/:id', null,
|
||||
* {
|
||||
* 'update': { method:'PUT' }
|
||||
* });
|
||||
* }]);
|
||||
*
|
||||
* // In our controller we get the ID from the URL using ngRoute and $routeParams
|
||||
* // We pass in $routeParams and our Notes factory along with $scope
|
||||
* app.controller('NotesCtrl', ['$scope', '$routeParams', 'Notes',
|
||||
function($scope, $routeParams, Notes) {
|
||||
* // First get a note object from the factory
|
||||
* var note = Notes.get({ id:$routeParams.id });
|
||||
* $id = note.id;
|
||||
*
|
||||
* // Now call update passing in the ID first then the object you are updating
|
||||
* Notes.update({ id:$id }, note);
|
||||
*
|
||||
* // This will PUT /notes/ID with the note object in the request payload
|
||||
* }]);
|
||||
* </pre>
|
||||
*/
|
||||
angular.module('ngResource', ['ng']).
|
||||
factory('$resource', ['$http', '$q', function($http, $q) {
|
||||
@@ -372,7 +401,7 @@ angular.module('ngResource', ['ng']).
|
||||
});
|
||||
|
||||
// strip trailing slashes and set the url
|
||||
url = url.replace(/\/+$/, '');
|
||||
url = url.replace(/\/+$/, '') || '/';
|
||||
// then replace collapse `/.` if found in the last URL path segment before the query
|
||||
// E.g. `http://url.com/id./format?q=x` becomes `http://url.com/id.format?q=x`
|
||||
url = url.replace(/\/\.(?=\w+($|\?))/, '.');
|
||||
|
||||
@@ -199,7 +199,7 @@ function ngViewFactory( $route, $anchorScroll, $animate) {
|
||||
var locals = $route.current && $route.current.locals,
|
||||
template = locals && locals.$template;
|
||||
|
||||
if (template) {
|
||||
if (angular.isDefined(template)) {
|
||||
var newScope = scope.$new();
|
||||
var current = $route.current;
|
||||
|
||||
|
||||
@@ -206,7 +206,7 @@ var validAttrs = angular.extend({}, uriAttrs, makeMap(
|
||||
'abbr,align,alt,axis,bgcolor,border,cellpadding,cellspacing,class,clear,'+
|
||||
'color,cols,colspan,compact,coords,dir,face,headers,height,hreflang,hspace,'+
|
||||
'ismap,lang,language,nohref,nowrap,rel,rev,rows,rowspan,rules,'+
|
||||
'scope,scrolling,shape,span,start,summary,target,title,type,'+
|
||||
'scope,scrolling,shape,size,span,start,summary,target,title,type,'+
|
||||
'valign,value,vspace,width'));
|
||||
|
||||
function makeMap(str) {
|
||||
|
||||
@@ -239,7 +239,8 @@ function callerFile(offset) {
|
||||
* To work around this we instead use our own handler that fires a real event.
|
||||
*/
|
||||
(function(fn){
|
||||
var parentTrigger = fn.trigger;
|
||||
// We need a handle to the original trigger function for input tests.
|
||||
var parentTrigger = fn._originalTrigger = fn.trigger;
|
||||
fn.trigger = function(type) {
|
||||
if (/(click|change|keydown|blur|input|mousedown|mouseup)/.test(type)) {
|
||||
var processDefaults = [];
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
./version.js --minor-bump
|
||||
VERSION=`./version.js --curent`
|
||||
git commit -a -m "chore(relase): start v$VERSION iteration"
|
||||
@@ -504,6 +504,21 @@ describe('angular', function() {
|
||||
expect(log).toEqual(['0:a', '1:c']);
|
||||
});
|
||||
|
||||
if (document.querySelectorAll) {
|
||||
it('should handle the result of querySelectorAll in IE8 as it has no hasOwnProperty function', function() {
|
||||
document.body.innerHTML = "<p>" +
|
||||
"<a name='x'>a</a>" +
|
||||
"<a name='y'>b</a>" +
|
||||
"<a name='x'>c</a>" +
|
||||
"</p>";
|
||||
|
||||
var htmlCollection = document.querySelectorAll('[name="x"]'),
|
||||
log = [];
|
||||
|
||||
forEach(htmlCollection, function(value, key) { log.push(key + ':' + value.innerHTML)});
|
||||
expect(log).toEqual(['0:a', '1:c']);
|
||||
});
|
||||
}
|
||||
|
||||
it('should handle arguments objects like arrays', function() {
|
||||
var args,
|
||||
|
||||
@@ -74,6 +74,17 @@ describe('injector', function() {
|
||||
});
|
||||
|
||||
|
||||
it('should not corrupt the cache when an object fails to get instantiated', function() {
|
||||
expect(function() {
|
||||
injector.get('idontexist');
|
||||
}).toThrowMinErr("$injector", "unpr", "Unknown provider: idontexistProvider <- idontexist");
|
||||
|
||||
expect(function() {
|
||||
injector.get('idontexist');
|
||||
}).toThrowMinErr("$injector", "unpr", "Unknown provider: idontexistProvider <- idontexist");
|
||||
});
|
||||
|
||||
|
||||
it('should provide path to the missing provider', function() {
|
||||
providers('a', function(idontexist) {return 1;});
|
||||
providers('b', function(a) {return 2;});
|
||||
|
||||
@@ -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!!!');
|
||||
});
|
||||
});
|
||||
})
|
||||
@@ -1120,6 +1120,26 @@ describe('jqLite', function() {
|
||||
});
|
||||
|
||||
|
||||
it('should deregister specific listener within the listener and call subsequent listeners', function() {
|
||||
var aElem = jqLite(a),
|
||||
clickSpy = jasmine.createSpy('click'),
|
||||
clickOnceSpy = jasmine.createSpy('clickOnce').andCallFake(function() {
|
||||
aElem.off('click', clickOnceSpy);
|
||||
});
|
||||
|
||||
aElem.on('click', clickOnceSpy);
|
||||
aElem.on('click', clickSpy);
|
||||
|
||||
browserTrigger(a, 'click');
|
||||
expect(clickOnceSpy).toHaveBeenCalledOnce();
|
||||
expect(clickSpy).toHaveBeenCalledOnce();
|
||||
|
||||
browserTrigger(a, 'click');
|
||||
expect(clickOnceSpy).toHaveBeenCalledOnce();
|
||||
expect(clickSpy.callCount).toBe(2);
|
||||
});
|
||||
|
||||
|
||||
it('should deregister specific listener for multiple types separated by spaces', function() {
|
||||
var aElem = jqLite(a),
|
||||
masterSpy = jasmine.createSpy('master'),
|
||||
@@ -1157,6 +1177,63 @@ describe('jqLite', function() {
|
||||
}
|
||||
});
|
||||
|
||||
describe('one', function() {
|
||||
|
||||
it('should only fire the callback once', function() {
|
||||
var element = jqLite(a);
|
||||
var spy = jasmine.createSpy('click');
|
||||
|
||||
element.one('click', spy);
|
||||
|
||||
browserTrigger(element, 'click');
|
||||
expect(spy).toHaveBeenCalledOnce();
|
||||
|
||||
browserTrigger(element, 'click');
|
||||
expect(spy).toHaveBeenCalledOnce();
|
||||
});
|
||||
|
||||
it('should deregister when off is called', function() {
|
||||
var element = jqLite(a);
|
||||
var spy = jasmine.createSpy('click');
|
||||
|
||||
element.one('click', spy);
|
||||
element.off('click', spy);
|
||||
|
||||
browserTrigger(element, 'click');
|
||||
expect(spy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should return the same event object just as on() does', function() {
|
||||
var element = jqLite(a);
|
||||
var eventA, eventB;
|
||||
element.on('click', function(event) {
|
||||
eventA = event;
|
||||
});
|
||||
element.one('click', function(event) {
|
||||
eventB = event;
|
||||
});
|
||||
|
||||
browserTrigger(element, 'click');
|
||||
expect(eventA).toEqual(eventB);
|
||||
});
|
||||
|
||||
it('should not remove other event handlers of the same type after execution', function() {
|
||||
var element = jqLite(a);
|
||||
var calls = [];
|
||||
element.one('click', function(event) {
|
||||
calls.push('one');
|
||||
});
|
||||
element.on('click', function(event) {
|
||||
calls.push('on');
|
||||
});
|
||||
|
||||
browserTrigger(element, 'click');
|
||||
browserTrigger(element, 'click');
|
||||
|
||||
expect(calls).toEqual(['one','on','on']);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('replaceWith', function() {
|
||||
it('should replaceWith', function() {
|
||||
|
||||
@@ -609,5 +609,10 @@ describe('browser', function() {
|
||||
fakeDocument.basePath = 'http://host.com/base/path/index.html';
|
||||
expect(browser.baseHref()).toEqual('/base/path/index.html');
|
||||
});
|
||||
|
||||
it('should remove domain from <base href> beginning with \'//\'', function() {
|
||||
fakeDocument.basePath = '//google.com/base/path/';
|
||||
expect(browser.baseHref()).toEqual('/base/path/');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user