Compare commits
34 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 30cd764b6d | |||
| 38b75cdb2d | |||
| 6cb8b39af8 | |||
| ebaa336614 | |||
| ef5f567f91 | |||
| 64e5afc478 | |||
| 1e582e4fa4 | |||
| 7421235f24 | |||
| 09ba69078d | |||
| 3536e83d8a | |||
| 3bb1dd5d7f | |||
| 95f964b827 | |||
| c8f78a8ca9 | |||
| f34d48087b | |||
| 2c9ecd01b1 | |||
| a584fb6e15 | |||
| 1f13313f40 | |||
| 5b60303781 | |||
| 10e2552a7d | |||
| ef48b0aa55 | |||
| f57872bca0 | |||
| 2deaf2877e | |||
| 7a146c9cd5 | |||
| 2796ec172b | |||
| 6997c1bf0c | |||
| 4a030f3834 | |||
| f78d8b8ff3 | |||
| f27d19ed60 | |||
| 4a5eaf7bec | |||
| 8513674911 | |||
| 97b74ad6fb | |||
| a47ea79023 | |||
| 5ca0de6487 | |||
| 50a449f053 |
+134
@@ -1,3 +1,137 @@
|
||||
<a name="1.6.3"></a>
|
||||
# 1.6.3 scriptalicious-bootstrapping (2017-03-08)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
- **Angular:**
|
||||
- do not auto-bootstrap if the `src` exists but is empty
|
||||
([3536e8](https://github.com/angular/angular.js/commit/3536e83d8a085b02bd6dcec8324800b7e6c734e4))
|
||||
- do not auto bootstrap if the currentScript has been clobbered
|
||||
([95f964](https://github.com/angular/angular.js/commit/95f964b827b6f5b5aab10af54f7831316c7a9935))
|
||||
- do not auto-bootstrap if the script source is bad and inside SVG
|
||||
([c8f78a](https://github.com/angular/angular.js/commit/c8f78a8ca9debc33a6deaf951f344b8d372bf210))
|
||||
- **$log:** don't parse error stacks manually outside of IE/Edge
|
||||
([64e5af](https://github.com/angular/angular.js/commit/64e5afc4786fdfd850c6bdb488a5aa2b8b077f74),
|
||||
[#15590](https://github.com/angular/angular.js/issues/15590),
|
||||
[#15767](https://github.com/angular/angular.js/issues/15767))
|
||||
- **$sanitize:** prevent clobbered elements from freezing the browser
|
||||
([3bb1dd](https://github.com/angular/angular.js/commit/3bb1dd5d7f7dcde6fea5a3148f8f10e92f451e9d),
|
||||
[#15699](https://github.com/angular/angular.js/issues/15699))
|
||||
- **$animate:**
|
||||
- reset `classNameFilter` to `null` when a disallowed RegExp is used
|
||||
([a584fb](https://github.com/angular/angular.js/commit/a584fb6e1569fc1dd85e23b251a7c126edc2dd5b),
|
||||
[#14913](https://github.com/angular/angular.js/issues/14913))
|
||||
- improve detection on `ng-animate` in `classNameFilter` RegExp
|
||||
([1f1331](https://github.com/angular/angular.js/commit/1f13313f403381581e1c31c57ebfe7a96546c6e4),
|
||||
[#14806](https://github.com/angular/angular.js/issues/14806))
|
||||
- **filterFilter:** don't throw if `key.charAt` is not a function
|
||||
([f27d19](https://github.com/angular/angular.js/commit/f27d19ed606bf05ba41698159ebbc5fbc195033e),
|
||||
[#15644](https://github.com/angular/angular.js/issues/15644),
|
||||
[#15660](https://github.com/angular/angular.js/issues/15660))
|
||||
- **select:**
|
||||
- add attribute "selected" for `select[multiple]`
|
||||
([851367](https://github.com/angular/angular.js/commit/8513674911300b27d518383a905fde9b3f25f7ae))
|
||||
- keep original selection when using shift to add options in IE/Edge
|
||||
([97b74a](https://github.com/angular/angular.js/commit/97b74ad6fbcbc4b63e37e9eb44962d6f8de83e8b),
|
||||
[#15675](https://github.com/angular/angular.js/issues/15675),
|
||||
[#15676](https://github.com/angular/angular.js/issues/15676))
|
||||
- **$jsonpCallbacks:** allow `$window` to be mocked in unit tests
|
||||
([5ca0de](https://github.com/angular/angular.js/commit/5ca0de64873c32ab2f540a3226e73c4175a15c50),
|
||||
[#15685](https://github.com/angular/angular.js/issues/15685),
|
||||
[#15686](https://github.com/angular/angular.js/issues/15686))
|
||||
|
||||
|
||||
## New Features
|
||||
- **info:** add `angularVersion` info to each module
|
||||
([1e582e](https://github.com/angular/angular.js/commit/1e582e4fa486f340150bba95927f1b26d9142de2))
|
||||
- **$injector:** add new `modules` property
|
||||
([742123](https://github.com/angular/angular.js/commit/7421235f247e5b7113345401bc5727cfbf81ddc2))
|
||||
- **Module:** add `info()` method
|
||||
([09ba69](https://github.com/angular/angular.js/commit/09ba69078de6ba52c70571b82b6205929f6facc5),
|
||||
[#15225](https://github.com/angular/angular.js/issues/15225))
|
||||
- **errorHandlingConfig:** make the depth for object stringification in errors configurable
|
||||
([4a5eaf](https://github.com/angular/angular.js/commit/4a5eaf7bec85ceca8b934ebaff4d1834a1a09f57),
|
||||
[#15402](https://github.com/angular/angular.js/issues/15402),
|
||||
[#15433](https://github.com/angular/angular.js/issues/15433))
|
||||
|
||||
|
||||
<a name="1.6.2"></a>
|
||||
# 1.6.2 llamacorn-lovehug (2017-02-07)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
- **$compile:**
|
||||
- do not swallow thrown errors in testsg
|
||||
([0377c6](https://github.com/angular/angular.js/commit/0377c6f0e890cb4ed3eb020b96720b4b34f75df3),
|
||||
[#15629](https://github.com/angular/angular.js/issues/15629),
|
||||
[#15631](https://github.com/angular/angular.js/issues/15631))
|
||||
- allow the usage of "$" in isolate scope property alias
|
||||
([7f2af3](https://github.com/angular/angular.js/commit/7f2af3f923e7a3f85c8862d0ed57d21c72eae904),
|
||||
[#15594](https://github.com/angular/angular.js/issues/15594))
|
||||
- **$location:** correctly handle external URL change during `$digest`
|
||||
([b60761](https://github.com/angular/angular.js/commit/b607618342d6c4fab364966fe05f152be6bd4d5f),
|
||||
[#11075](https://github.com/angular/angular.js/issues/11075),
|
||||
[#12571](https://github.com/angular/angular.js/issues/12571),
|
||||
[#15556](https://github.com/angular/angular.js/issues/15556),
|
||||
[#15561](https://github.com/angular/angular.js/issues/15561))
|
||||
- **$browser:** detect external changes in `history.state`
|
||||
([fa50fb](https://github.com/angular/angular.js/commit/fa50fbaf57b3437be7a410ecaba7008dbe0ef239))
|
||||
- **$resource:**
|
||||
- do not swallow errors in `success` callback
|
||||
([27146e](https://github.com/angular/angular.js/commit/27146e8a7fad54c1342179b6d291b1b5c2ebe816),
|
||||
[#15624](https://github.com/angular/angular.js/issues/15624),
|
||||
[#15628](https://github.com/angular/angular.js/issues/15628))
|
||||
- correctly unescape `/\.` even if `\.` comes from a param value
|
||||
([419a48](https://github.com/angular/angular.js/commit/419a4813e354496bdf0df44e3f8afaa198df1ab1),
|
||||
[#15627](https://github.com/angular/angular.js/issues/15627))
|
||||
- delete `$cancelRequest()` in `toJSON()`
|
||||
([086c5d](https://github.com/angular/angular.js/commit/086c5d0354db8cb3d106b9ff966fb48d6fb46ef8),
|
||||
[#15244](https://github.com/angular/angular.js/issues/15244))
|
||||
- **$animate:** correctly animate transcluded clones with `templateUrl`
|
||||
([f01212](https://github.com/angular/angular.js/commit/f01212ab5287ac7a154da7d75037ed444e81eb34),
|
||||
[#15510](https://github.com/angular/angular.js/issues/15510),
|
||||
[#15514](https://github.com/angular/angular.js/issues/15514))
|
||||
- **$route:** make asynchronous tasks count as pending requests
|
||||
([eb968c](https://github.com/angular/angular.js/commit/eb968c4a6884838db05369a04459066424c5bba8),
|
||||
[#14159](https://github.com/angular/angular.js/issues/14159))
|
||||
- **$parse:** make sure ES6 object computed properties are watched
|
||||
([5e418b](https://github.com/angular/angular.js/commit/5e418b1145a1045da598c7863e785d647ea83850),
|
||||
[#15678](https://github.com/angular/angular.js/issues/15678))
|
||||
- **$sniffer:** allow `history` for NW.js apps
|
||||
([4a593d](https://github.com/angular/angular.js/commit/4a593db79ba1e21a6aa600a82cf6d757cad94d01),
|
||||
[#15474](https://github.com/angular/angular.js/issues/15474),
|
||||
[#15633](https://github.com/angular/angular.js/issues/15633))
|
||||
- **input:** fix `step` validation for `input[type=number/range]`
|
||||
([c95a67](https://github.com/angular/angular.js/commit/c95a6737fbd277e40c064bd9f68f383bf119505c),
|
||||
[#15504](https://github.com/angular/angular.js/issues/15504),
|
||||
[#15506](https://github.com/angular/angular.js/issues/15506))
|
||||
- **select:** keep `ngModel` when selected option is recreated by `ngRepeat`
|
||||
([131af8](https://github.com/angular/angular.js/commit/131af8272d269a541d04cb522c264a91e0ec8b6a),
|
||||
[#15630](https://github.com/angular/angular.js/issues/15630),
|
||||
[#15632](https://github.com/angular/angular.js/issues/15632))
|
||||
- **ngValue:** correctly update the `value` property when `value` is undefined
|
||||
([05aab6](https://github.com/angular/angular.js/commit/05aab660ce74f526f2110d3b5faf9a5b4f4e664b)
|
||||
[#15603](https://github.com/angular/angular.js/issues/15603),
|
||||
[#15605](https://github.com/angular/angular.js/issues/15605))
|
||||
- **angularInit:** allow auto-bootstrapping from inline script
|
||||
([bb464d](https://github.com/angular/angular.js/commit/bb464d16b434b9e2de2fecf80c192d4741cba879),
|
||||
[#15567](https://github.com/angular/angular.js/issues/15567),
|
||||
[#15571](https://github.com/angular/angular.js/issues/15571))
|
||||
- **ngMockE2E:** ensure that mocked `$httpBackend` uses correct `$browser`
|
||||
([bd63b2](https://github.com/angular/angular.js/commit/bd63b2235cd410251cb83eebd9a47d3102830b6b),
|
||||
[#15593](https://github.com/angular/angular.js/issues/15593))
|
||||
|
||||
|
||||
## New Features
|
||||
- **ngModel:** add `$overrideModelOptions` support
|
||||
([2546c2](https://github.com/angular/angular.js/commit/2546c29f811b68eea4d68be7fa1c8f7bb562dc11),
|
||||
[#15415](https://github.com/angular/angular.js/issues/15415))
|
||||
- **$parse:** allow watching array/object literals with non-primitive values
|
||||
([25f008](https://github.com/angular/angular.js/commit/25f008f541d68b09efd7b428b648c6d4899e6972),
|
||||
[#15301](https://github.com/angular/angular.js/issues/15301))
|
||||
|
||||
|
||||
|
||||
<a name="1.5.11"></a>
|
||||
# 1.5.11 princely-quest (2017-01-13)
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
.visible-phone{display:none}.visible-desktop{display:block}.navbar{display:block}.navbar .container{padding:0 16px;width:auto}.navbar .brand{float:left;margin:8px 80px 0 8px;padding:0}.navbar .brand a{display:block;height:30px;margin:6px 0 5px 0;overflow:hidden;padding:0;width:117px}.navbar .nav{float:right}.navbar .nav .dropdown-toggle{color:rgba(255,255,255,0.87);font-size:16px;font-weight:300;line-height:56px;padding:0 24px;text-transform:uppercase;transition:all .3s}.navbar .nav .dropdown-toggle:hover,.navbar .nav .dropdown-toggle:active,.navbar .nav .dropdown-toggle:focus{background:#37474F;color:#fff}.navbar .nav .dropdown-menu{background:#37474F;border:none;border-radius:0;box-shadow:0 0 16px rgba(0,0,0,0.12),0 16px 16px rgba(0,0,0,0.24);color:#fff;left:auto;margin:0;padding:0;right:0}.navbar .nav .dropdown-menu:after,.navbar .nav .dropdown-menu:before{display:none}.navbar .nav .dropdown-menu li{border-bottom:1px solid rgba(38,50,56,0.56);box-sizing:border-box;line-height:48px}.navbar .nav .dropdown-menu li:last-child{border:none}.navbar .nav .dropdown-menu a{background:#37474F;color:#fff;font-weight:300;line-height:48px;padding:0 16px;transition:all .2s}.navbar .nav .dropdown-menu a:hover,.navbar .nav .dropdown-menu a:focus{background:#455A64}.navbar .navbar-search{left:200px;margin:0;position:absolute;right:440px;top:8px;width:auto}.navbar .navbar-search i{color:#546E7A;font-size:16px;left:12px;position:absolute;top:11px}.navbar .navbar-search .search-query{background:#37474F;border:none;border-radius:2px;box-shadow:none;box-sizing:border-box;color:#546E7A;font-size:14px;height:40px;width:100%;padding:0 16px 0 32px;text-shadow:none;transition:all .3s}.navbar .navbar-search .search-query:-webkit-autofill,.navbar .navbar-search .search-query:-webkit-autofill:hover,.navbar .navbar-search .search-query:-webkit-autofill:focus{background-color:#fff;transition:background-color 5000s ease-in-out 0s;-webkit-text-fill-color:#455A64}.navbar .navbar-search .search-query:hover,.navbar .navbar-search .search-query:active,.navbar .navbar-search .search-query:focus{background:#fff;box-shadow:inset 0 2px 4px rgba(0,0,0,0.24);color:#2196F3}.navbar .navbar-search .search-query::-webkit-input-placeholder{color:#546E7A}.navbar .navbar-search .search-query::-moz-placeholder{color:#546E7A}.navbar .navbar-search .search-query:-ms-input-placeholder{color:#546E7A}.navbar .navbar-search .search-query:-moz-placeholder{color:#546E7A}#navbar-main .navbar-inner{background:#263238;height:56px}#navbar-notice{z-index:1029;top:56px}#navbar-notice .navbar-inner{background:#ECEFF1;box-shadow:0 0 3px rgba(0,0,0,0.12),0 3px 3px rgba(0,0,0,0.24);height:auto}.site-notice{padding:4px 0;text-align:center;font-size:13px;margin:0}@media handheld and (max-width: 800px), screen and (max-device-width: 800px), screen and (max-width: 800px){.visible-phone{display:block}.visible-desktop{display:none}}@media handheld and (max-width: 800px), screen and (max-device-width: 800px), screen and (max-width: 800px){.homepage .container{padding:16px;width:auto}.homepage .span1{width:auto}.homepage .span2{width:auto}.homepage .span3{width:auto}.homepage .span4{width:auto}.homepage .span5{width:auto}.homepage .span6{width:auto}.homepage .span7{width:auto}.homepage .span8{width:auto}.homepage .span9{width:auto}.homepage .span10{width:auto}.homepage .navbar .container{padding:0 8px}.homepage #navbar-main .navbar-inner{height:40px}.homepage #navbar-main .brand{margin:6px 0 0 0}.homepage #navbar-main .brand a{margin:0}.homepage #navbar-main .nav{margin:0}.homepage #navbar-main .nav .dropdown-toggle{font-size:12px;line-height:40px;padding:0 8px}.homepage #navbar-main .dropdown-menu a{padding:0 8px}.homepage #navbar-main .navbar-search{background:#263238;border-bottom:1px solid #263238;left:0;right:0;top:100%}.homepage #navbar-main .navbar-search i{left:12px;top:7px}.homepage #navbar-main .navbar-search .search-query{border-radius:0;height:32px}.homepage #navbar-notice{top:40px}.homepage #navbar-notice .site-notice{font-size:11px}.homepage .hero{padding:80px 32px 32px 32px}.homepage .hero h2{background-size:230px 60px;height:60px;width:230px}}
|
||||
@@ -53,13 +53,13 @@ h1,h2,h3,h4,h5,h6 {
|
||||
}
|
||||
|
||||
.header .brand {
|
||||
padding-top: 6px;
|
||||
padding-bottom: 0px;
|
||||
}
|
||||
|
||||
.header .brand img {
|
||||
margin-top: 5px;
|
||||
height: 30px;
|
||||
margin-top: 0;
|
||||
height: auto;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.docs-search {
|
||||
@@ -82,6 +82,11 @@ h1,h2,h3,h4,h5,h6 {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.navbar .navbar-search i {
|
||||
top: 13px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.docs-search > .search-query:focus {
|
||||
outline: 0;
|
||||
}
|
||||
@@ -297,6 +302,7 @@ iframe.example {
|
||||
}
|
||||
|
||||
.search-results-container {
|
||||
position: relative;
|
||||
padding-bottom: 1em;
|
||||
border-top: 1px solid #111;
|
||||
background: #181818;
|
||||
@@ -435,15 +441,17 @@ iframe.example {
|
||||
background: #f1f1f1;
|
||||
}
|
||||
|
||||
.sup-header {
|
||||
#navbar-sub {
|
||||
padding-top: 10px;
|
||||
padding-bottom: 5px;
|
||||
background: rgba(245,245,245,0.88);
|
||||
box-shadow: 0 0 2px #999;
|
||||
z-index: 1028;
|
||||
top: 83px;
|
||||
}
|
||||
|
||||
.main-body-grid {
|
||||
margin-top: 120px;
|
||||
margin-top: 144px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
@@ -454,7 +462,7 @@ iframe.example {
|
||||
|
||||
.main-body-grid > .grid-left {
|
||||
position: fixed;
|
||||
top: 120px;
|
||||
top: 144px;
|
||||
bottom: 0;
|
||||
overflow: auto;
|
||||
}
|
||||
@@ -827,3 +835,86 @@ ul.events > li {
|
||||
iframe[name="example-anchoringExample"] {
|
||||
height: 400px;
|
||||
}
|
||||
|
||||
/*
|
||||
angular-topnav.css and bootstrap overrides
|
||||
*/
|
||||
|
||||
.navbar .navbar-inner .container {
|
||||
padding: 0 16px;
|
||||
width: auto;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.navbar .nav > li {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.navbar-nav .open .dropdown-menu {
|
||||
position: absolute;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.navbar-nav .open .dropdown-menu > li > a {
|
||||
line-height: 48px;
|
||||
}
|
||||
|
||||
#navbar-main .navbar-inner, #navbar-notice .navbar-inner {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
#navbar-sub .container {
|
||||
max-width: 970px;
|
||||
}
|
||||
|
||||
.nav .open > a, .nav .open > a:hover, .nav .open > a:focus {
|
||||
background-color: inherit;
|
||||
}
|
||||
|
||||
@media handheld and (max-width:800px), screen and (max-device-width:800px), screen and (max-width:800px) {
|
||||
.navbar {
|
||||
min-height: auto;
|
||||
}
|
||||
|
||||
.search-results-container {
|
||||
top: 32px;
|
||||
overflow: auto;
|
||||
max-height: 85vh;
|
||||
padding-bottom: 0;
|
||||
position: static;
|
||||
}
|
||||
|
||||
.search-close {
|
||||
right: 1px;
|
||||
margin-left: 0;
|
||||
top: 41px;
|
||||
padding: 5px 10px;
|
||||
border-top-right-radius: 0;
|
||||
border-top-left-radius: 0;
|
||||
box-shadow: none;
|
||||
width: auto;
|
||||
bottom: auto;
|
||||
left: auto;
|
||||
}
|
||||
|
||||
.navbar-nav .open .dropdown-menu > li > a, .navbar-nav .open .dropdown-menu .dropdown-header {
|
||||
padding: 0 8px;
|
||||
}
|
||||
|
||||
.homepage #navbar-notice {
|
||||
top: 72px;
|
||||
}
|
||||
|
||||
#navbar-notice .navbar-inner {
|
||||
box-shadow: 0 0 3px rgba(0, 0, 0, .12), 0 3px 3px rgba(0, 0, 0, .24)
|
||||
}
|
||||
|
||||
#navbar-sub {
|
||||
position: relative;
|
||||
top: 17px;
|
||||
margin-top: 80px;
|
||||
padding-bottom: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,8 +18,8 @@ describe('doc.angularjs.org', function() {
|
||||
var ngBindLink = element(by.css('.definition-table td a[href="api/ng/directive/ngClick"]'));
|
||||
ngBindLink.click();
|
||||
|
||||
var pageBody = element(by.css('h1'));
|
||||
expect(pageBody.getText()).toEqual('ngClick');
|
||||
var mainHeader = element(by.css('.main-body h1 '));
|
||||
expect(mainHeader.getText()).toEqual('ngClick');
|
||||
});
|
||||
|
||||
|
||||
|
||||
@@ -44,30 +44,31 @@ describe('docs.angularjs.org', function() {
|
||||
var ngBindLink = element(by.css('.definition-table td a[href="api/ng/directive/ngClick"]'));
|
||||
ngBindLink.click();
|
||||
|
||||
var pageBody = element(by.css('h1'));
|
||||
expect(pageBody.getText()).toEqual('ngClick');
|
||||
var mainHeader = element(by.css('.main-body h1 '));
|
||||
expect(mainHeader.getText()).toEqual('ngClick');
|
||||
});
|
||||
|
||||
|
||||
|
||||
it('should be resilient to trailing slashes', function() {
|
||||
browser.get('build/docs/index-production.html#!/api/ng/function/angular.noop/');
|
||||
var pageBody = element(by.css('h1'));
|
||||
expect(pageBody.getText()).toEqual('angular.noop');
|
||||
|
||||
var mainHeader = element(by.css('.main-body h1 '));
|
||||
expect(mainHeader.getText()).toEqual('angular.noop');
|
||||
});
|
||||
|
||||
|
||||
it('should be resilient to trailing "index"', function() {
|
||||
browser.get('build/docs/index-production.html#!/api/ng/function/angular.noop/index');
|
||||
var pageBody = element(by.css('h1'));
|
||||
expect(pageBody.getText()).toEqual('angular.noop');
|
||||
var mainHeader = element(by.css('.main-body h1 '));
|
||||
expect(mainHeader.getText()).toEqual('angular.noop');
|
||||
});
|
||||
|
||||
|
||||
it('should be resilient to trailing "index/"', function() {
|
||||
browser.get('build/docs/index-production.html#!/api/ng/function/angular.noop/index/');
|
||||
var pageBody = element(by.css('h1'));
|
||||
expect(pageBody.getText()).toEqual('angular.noop');
|
||||
var mainHeader = element(by.css('.main-body h1 '));
|
||||
expect(mainHeader.getText()).toEqual('angular.noop');
|
||||
});
|
||||
|
||||
|
||||
@@ -78,7 +79,8 @@ describe('docs.angularjs.org', function() {
|
||||
|
||||
it('should display an error if the page does not exist', function() {
|
||||
browser.get('build/docs/index-production.html#!/api/does/not/exist');
|
||||
expect(element(by.css('h1')).getText()).toBe('Oops!');
|
||||
var mainHeader = element(by.css('.main-body h1 '));
|
||||
expect(mainHeader.getText()).toEqual('Oops!');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -32,6 +32,7 @@ module.exports = function debugDeployment(getVersion) {
|
||||
'components/bootstrap-' + getVersion('bootstrap') + '/css/bootstrap.css',
|
||||
'components/open-sans-fontface-' + getVersion('open-sans-fontface') + '/open-sans.css',
|
||||
'css/prettify-theme.css',
|
||||
'css/angular-topnav.css',
|
||||
'css/docs.css',
|
||||
'css/animations.css'
|
||||
]
|
||||
|
||||
@@ -32,6 +32,7 @@ module.exports = function defaultDeployment(getVersion) {
|
||||
'components/bootstrap-' + getVersion('bootstrap') + '/css/bootstrap.min.css',
|
||||
'components/open-sans-fontface-' + getVersion('open-sans-fontface') + '/open-sans.css',
|
||||
'css/prettify-theme.css',
|
||||
'css/angular-topnav.css',
|
||||
'css/docs.css',
|
||||
'css/animations.css'
|
||||
]
|
||||
|
||||
+1
@@ -36,6 +36,7 @@ module.exports = function jqueryDeployment(getVersion) {
|
||||
'components/bootstrap-' + getVersion('bootstrap') + '/css/bootstrap.min.css',
|
||||
'components/open-sans-fontface-' + getVersion('open-sans-fontface') + '/open-sans.css',
|
||||
'css/prettify-theme.css',
|
||||
'css/angular-topnav.css',
|
||||
'css/docs.css',
|
||||
'css/animations.css'
|
||||
]
|
||||
|
||||
@@ -49,6 +49,7 @@ module.exports = function productionDeployment(getVersion) {
|
||||
'components/bootstrap-' + getVersion('bootstrap') + '/css/bootstrap.min.css',
|
||||
'components/open-sans-fontface-' + getVersion('open-sans-fontface') + '/open-sans.css',
|
||||
'css/prettify-theme.css',
|
||||
'css/angular-topnav.css',
|
||||
'css/docs.css',
|
||||
'css/animations.css'
|
||||
]
|
||||
|
||||
@@ -68,101 +68,95 @@
|
||||
})();
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<body class="homepage">
|
||||
<div id="wrapper">
|
||||
<header scroll-y-offset-element class="header header-fixed">
|
||||
<section class="navbar navbar-inverse docs-navbar-primary" ng-controller="DocsSearchCtrl">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-9 header-branding">
|
||||
<a class="brand navbar-brand" href="http://angularjs.org">
|
||||
<img width="117" height="30" class="logo" alt="Link to Angular JS Homepage" ng-src="img/angularjs-for-header-only.svg">
|
||||
</a>
|
||||
<ul class="nav navbar-nav">
|
||||
<li class="divider-vertical"></li>
|
||||
<li><a href="http://angularjs.org"><i class="icon-home icon-white"></i> Home</a></li>
|
||||
<li class="divider-vertical"></li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
|
||||
<i class="icon-eye-open icon-white"></i> Learn <b class="caret"></b>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li class="disabled"><a href="http://angularjs.org/">Why AngularJS?</a></li>
|
||||
<li><a href="http://www.youtube.com/user/angularjs">Watch</a></li>
|
||||
<li><a href="tutorial">Tutorial</a></li>
|
||||
<li><a href="https://www.madewithangular.com/">Case Studies</a></li>
|
||||
<li><a href="https://github.com/angular/angular-seed">Seed App project template</a></li>
|
||||
<li><a href="misc/faq">FAQ</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="divider-vertical"></li>
|
||||
<li class="dropdown active">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
|
||||
<i class="icon-book icon-white"></i> Develop <b class="caret"></b>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="tutorial">Tutorial</a></li>
|
||||
<li><a href="guide">Developer Guide</a></li>
|
||||
<li><a href="api">API Reference</a></li>
|
||||
<li><a href="error">Error Reference</a></li>
|
||||
<li><a href="misc/contribute">Contribute</a></li>
|
||||
<li><a href="http://code.angularjs.org/">Download</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="divider-vertical"></li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
|
||||
<i class="icon-comment icon-white"></i> Discuss <b class="caret"></b>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="http://blog.angularjs.org">Blog</a></li>
|
||||
<li><a href="http://groups.google.com/group/angular">Mailing List</a></li>
|
||||
<li><a href="http://webchat.freenode.net/?channels=angularjs&uio=d4">Chat Room</a></li>
|
||||
<li class="divider"></li>
|
||||
<li><a href="https://twitter.com/#!/angularjs">Twitter</a></li>
|
||||
<li><a href="https://plus.google.com/110323587230527980117">Google+</a></li>
|
||||
<li class="divider"></li>
|
||||
<li><a href="https://github.com/angular/angular.js">GitHub</a></li>
|
||||
<li><a href="https://github.com/angular/angular.js/issues">Issue Tracker</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="divider-vertical"></li>
|
||||
</ul>
|
||||
</div>
|
||||
<form ng-class="{focus:focus}" class="navbar-search col-md-3 docs-search" ng-submit="submit()">
|
||||
<span class="glyphicon glyphicon-search search-icon"></span>
|
||||
<input type="text"
|
||||
name="as_q"
|
||||
class="search-query"
|
||||
placeholder="Click or press / to search"
|
||||
ng-focus="focus=true"
|
||||
ng-blur="focus=false"
|
||||
ng-change="search(q)"
|
||||
ng-model="q"
|
||||
docs-search-input
|
||||
autocomplete="off" />
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="search-results-container" ng-show="hasResults">
|
||||
<header class="header" scroll-y-offset-element>
|
||||
<nav id="navbar-main" class="navbar navbar-fixed-top">
|
||||
<div class="navbar-inner" ng-controller="DocsSearchCtrl">
|
||||
<div class="container">
|
||||
<div class="search-results-frame">
|
||||
<div ng-repeat="(key, value) in results track by key" class="search-results-group" ng-class="colClassName + ' col-group-' + key" ng-show="value.length > 0">
|
||||
<h4 class="search-results-group-heading">{{ key }}</h4>
|
||||
<ul class="search-results">
|
||||
<!-- Do not insert a line break between li and a. Chrome will insert an actual line-break, which breaks the list item view.
|
||||
TODO: use a html minifier instead -->
|
||||
<li ng-repeat="item in value" class="search-result"><a ng-click="hideResults()" ng-href="{{ item.path }}">{{ item.name }}</a></li>
|
||||
<h1 class="brand"><a href="http://angularjs.org"><img width="117" height="30" src="img/angularjs-for-header-only.svg" alt="AngularJS"></a></h1>
|
||||
|
||||
<form class="navbar-search" ng-submit="submit()">
|
||||
<i class="glyphicon glyphicon-search search-icon"></i>
|
||||
<input type="text" name="as_q" class="search-query" placeholder="SEARCH"
|
||||
ng-focus="focus=true"
|
||||
ng-blur="focus=false"
|
||||
ng-change="search(q)"
|
||||
ng-model="q"
|
||||
ng-model-options="{debounce: 150}"
|
||||
docs-search-input
|
||||
autocomplete="off">
|
||||
</form>
|
||||
|
||||
<ul class="nav navbar-nav">
|
||||
<li class="dropdown" uib-dropdown>
|
||||
<a href="#" class="dropdown-toggle" uib-dropdown-toggle>Learn</a>
|
||||
<ul class="dropdown-menu" uib-dropdown-menu>
|
||||
<li><a href="tutorial">Tutorial</a></li>
|
||||
<li><a href="misc/faq">FAQ</a></li>
|
||||
<li><a href="https://www.youtube.com/user/angularjs">Videos</a></li>
|
||||
<li><a href="http://angular.codeschool.com/">Free Course</a></li>
|
||||
<li><a href="https://www.madewithangular.com/">Case Studies</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown" uib-dropdown>
|
||||
<a href="#" class="dropdown-toggle" uib-dropdown-toggle>Develop</a>
|
||||
<ul class="dropdown-menu" uib-dropdown-menu>
|
||||
<li><a href="guide">Developer Guide</a></li>
|
||||
<li><a href="api">API Reference</a></li>
|
||||
<li><a href="error">Error Reference</a></li>
|
||||
<li><a href="misc/contribute">Contribute</a></li>
|
||||
<li><a href="https://github.com/angular/angular-seed">Seed App project template</a></li>
|
||||
<li><a href="https://github.com/angular/angular.js">GitHub</a></li>
|
||||
<li><a href="http://code.angularjs.org/">Download</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown" uib-dropdown>
|
||||
<a href="#" class="dropdown-toggle" uib-dropdown-toggle>Discuss</a>
|
||||
<ul class="dropdown-menu" uib-dropdown-menu>
|
||||
<li><a href="http://blog.angularjs.org">Blog</a></li>
|
||||
<li><a href="https://twitter.com/angular">Twitter</a></li>
|
||||
<li><a href="https://plus.google.com/110323587230527980117">Google+</a></li>
|
||||
<li><a href="https://github.com/angular/angular.js/issues">Feature & Bug Tracker</a></li>
|
||||
<li><a href="http://groups.google.com/group/angular">Mailing List</a></li>
|
||||
<li><a href="http://webchat.freenode.net/?channels=angularjs&uio=d4">IRC</a></li>
|
||||
<li><a href="https://gitter.im/angular/angular.js">Gitter</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
<div class="search-results-container" ng-show="hasResults">
|
||||
<div class="container">
|
||||
<div class="search-results-frame">
|
||||
<div ng-repeat="(key, value) in results track by key" class="search-results-group" ng-class="colClassName + ' col-group-' + key" ng-show="value.length > 0">
|
||||
<h4 class="search-results-group-heading">{{ key }}</h4>
|
||||
<ul class="search-results">
|
||||
<li ng-repeat="item in value" class="search-result"><a ng-click="hideResults()" ng-href="{{ item.path }}">{{ item.name }}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<a href="" ng-click="hideResults()" class="search-close">
|
||||
<span class="glyphicon glyphicon-remove search-close-icon"></span> Close
|
||||
</a>
|
||||
</div>
|
||||
<a href="" ng-click="hideResults()" class="search-close">
|
||||
<span class="glyphicon glyphicon-remove search-close-icon"></span> Close
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section class="sup-header">
|
||||
</nav>
|
||||
<nav id="navbar-notice" class="navbar navbar-fixed-top">
|
||||
<div class="navbar-inner">
|
||||
<div class="container">
|
||||
<p class="site-notice visible-phone">
|
||||
This site refers to AngularJS (v1.x). <a href="https://angular.io/">Go to the latest Angular</a>.
|
||||
</p>
|
||||
<p class="site-notice visible-desktop">
|
||||
This site and all of its contents are referring to AngularJS (version 1.x),
|
||||
if you are looking for the latest Angular, please visit <a href="https://angular.io/">angular.io</a>.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<nav id="navbar-sub" class="sup-header navbar navbar-fixed-top">
|
||||
<div class="container main-grid main-header-grid">
|
||||
<div class="grid-left">
|
||||
<version-picker></version-picker>
|
||||
@@ -176,7 +170,7 @@
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<section role="main" class="container main-body">
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
@ngdoc error
|
||||
@name $animate:nongcls
|
||||
@fullName `ng-animate` class not allowed
|
||||
@description
|
||||
|
||||
This error occurs, when trying to set `$animateProvider.classNameFilter()` to a RegExp containing
|
||||
the reserved `ng-animate` class. Since `.ng-animate` will be added/removed by `$animate` itself,
|
||||
using it as part of the `classNameFilter` RegExp is not allowed.
|
||||
@@ -0,0 +1,11 @@
|
||||
@ngdoc error
|
||||
@name $sanitize:elclob
|
||||
@fullName Failed to sanitize html because the element is clobbered
|
||||
@description
|
||||
|
||||
This error occurs when `$sanitize` sanitizer is unable to traverse the HTML because one or more of the elements in the
|
||||
HTML have been "clobbered". This could be a sign that the payload contains code attempting to cause a DoS attack on the
|
||||
browser.
|
||||
|
||||
Typically clobbering breaks the `nextSibling` property on an element so that it points to one of its child nodes. This
|
||||
makes it impossible to walk the HTML tree without getting stuck in an infinite loop, which causes the browser to freeze.
|
||||
@@ -0,0 +1,7 @@
|
||||
@ngdoc error
|
||||
@name ng:aobj
|
||||
@fullName Invalid Argument
|
||||
@description
|
||||
|
||||
The argument passed should be an object. Check the value that was passed to the function where
|
||||
this error was thrown.
|
||||
@@ -120,11 +120,13 @@ The other forms shown above are accepted for legacy reasons but we advise you to
|
||||
|
||||
### Directive types
|
||||
|
||||
`$compile` can match directives based on element names, attributes, class names, as well as comments.
|
||||
`$compile` can match directives based on element names (E), attributes (A), class names (C),
|
||||
and comments (M).
|
||||
|
||||
All of the Angular-provided directives match attribute name, tag name, comments, or class name.
|
||||
The following demonstrates the various ways a directive (`myDir` in this case) can be referenced
|
||||
from within a template:
|
||||
The built-in the AngularJS directives show in their documentation page which type of matching they support.
|
||||
|
||||
The following demonstrates the various ways a directive that matches all 4 types
|
||||
(`myDir` in this case) can be referenced from within a template.
|
||||
|
||||
```html
|
||||
<my-dir></my-dir>
|
||||
@@ -133,6 +135,10 @@ from within a template:
|
||||
<span class="my-dir: exp;"></span>
|
||||
```
|
||||
|
||||
A directive can specify which of the 4 matching types it supports in the
|
||||
{@link ng.$compile#-restrict- `restrict`} property of the directive definition object.
|
||||
The default is `EA`.
|
||||
|
||||
<div class="alert alert-success">
|
||||
**Best Practice:** Prefer using directives via tag name and attributes over comment and class names.
|
||||
Doing so generally makes it easier to determine what directives a given element matches.
|
||||
|
||||
@@ -1454,9 +1454,8 @@ For more info on the topic, you can take a look at this
|
||||
|
||||
## Migrating from 1.3 to 1.4
|
||||
|
||||
Angular 1.4 fixes major animation issues and introduces a new API for `ngCookies`. Further, there
|
||||
are changes to `ngMessages`, `$compile`, `ngRepeat`, `ngOptions `and some fixes to core filters:
|
||||
`limitTo` and `filter`.
|
||||
AngularJS 1.4 fixes major animation issues and introduces a new API for `ngCookies`. Further, there
|
||||
are changes to `ngMessages`, `$compile`, `ngRepeat`, `ngOptions`, `ngPattern`, `pattern` and some fixes to core filters: `limitTo` and `filter`.
|
||||
|
||||
The reason for the ngAnimate refactor was to fix timing issues and to expose new APIs to allow
|
||||
for developers to construct more versatile animations. We now have access to `$animateCss`
|
||||
@@ -1469,9 +1468,9 @@ to render error messages with ngMessages that are listed with a directive such a
|
||||
involves pulling error message data from a server and then displaying that data via the mechanics of ngMessages. Be
|
||||
sure to read the breaking change involved with `ngMessagesInclude` to upgrade your template code.
|
||||
|
||||
Other changes, such as the ordering of elements with ngRepeat and ngOptions, may also affect the behavior of your
|
||||
application. And be sure to also read up on the changes to `$cookies`. The migration jump from 1.3 to 1.4 should be
|
||||
relatively straightforward otherwise.
|
||||
Other changes, such as the ordering of elements with ngRepeat and ngOptions and the way ngPattern and pattern directives
|
||||
validate the regex, may also affect the behavior of your application. And be sure to also read up on the changes to `$cookies`.
|
||||
The migration jump from 1.3 to 1.4 should be relatively straightforward otherwise.
|
||||
|
||||
|
||||
|
||||
@@ -1575,7 +1574,7 @@ class based animations (animations triggered via ngClass) in order to ensure tha
|
||||
|
||||
|
||||
|
||||
### Forms (`ngMessages`, `ngOptions`, `select`)
|
||||
### Forms (`ngMessages`, `ngOptions`, `select`, `ngPattern` and `pattern`)
|
||||
|
||||
#### ngMessages
|
||||
The ngMessages module has also been subject to an internal refactor to allow it to be more flexible
|
||||
@@ -1683,6 +1682,79 @@ ngModelCtrl.$formatters.push(function(value) {
|
||||
});
|
||||
```
|
||||
|
||||
#### ngPattern and pattern
|
||||
|
||||
Due to [0e001084](https://github.com/angular/angular.js/commit/0e001084ffff8674efad289d37cb16cc4e46b50a),
|
||||
The `ngPattern` and `pattern` directives will validate the regex
|
||||
against the `$viewValue` of `ngModel`, i.e. the value of the model
|
||||
before the $parsers are applied. Previously, the `$modelValue`
|
||||
(the result of the $parsers) was validated.
|
||||
|
||||
This fixes issues where `input[date]` and `input[number]` cannot
|
||||
be validated because the `$viewValue` string is parsed into
|
||||
`Date` and `Number` respectively (starting with Angular 1.3).
|
||||
It also brings the directives in line with HTML5 constraint
|
||||
validation, which validates against the input value.
|
||||
|
||||
This change is unlikely to cause applications to fail, because even
|
||||
in Angular 1.2, the value that was validated by pattern could have
|
||||
been manipulated by the $parsers, as all validation was done
|
||||
inside this pipeline.
|
||||
|
||||
If you rely on the pattern being validated against the `$modelValue`,
|
||||
you must create your own validator directive that overwrites
|
||||
the built-in pattern validator:
|
||||
|
||||
```
|
||||
.directive('patternModelOverwrite', function patternModelOverwriteDirective() {
|
||||
return {
|
||||
restrict: 'A',
|
||||
require: '?ngModel',
|
||||
priority: 1,
|
||||
compile: function() {
|
||||
var regexp, patternExp;
|
||||
|
||||
return {
|
||||
pre: function(scope, elm, attr, ctrl) {
|
||||
if (!ctrl) return;
|
||||
|
||||
attr.$observe('pattern', function(regex) {
|
||||
/**
|
||||
* The built-in directive will call our overwritten validator
|
||||
* (see below). We just need to update the regex.
|
||||
* The preLink fn guaranetees our observer is called first.
|
||||
*/
|
||||
if (isString(regex) && regex.length > 0) {
|
||||
regex = new RegExp('^' + regex + '$');
|
||||
}
|
||||
|
||||
if (regex && !regex.test) {
|
||||
//The built-in validator will throw at this point
|
||||
return;
|
||||
}
|
||||
|
||||
regexp = regex || undefined;
|
||||
});
|
||||
|
||||
},
|
||||
post: function(scope, elm, attr, ctrl) {
|
||||
if (!ctrl) return;
|
||||
|
||||
regexp, patternExp = attr.ngPattern || attr.pattern;
|
||||
|
||||
//The postLink fn guarantees we overwrite the built-in pattern validator
|
||||
ctrl.$validators.pattern = function(value) {
|
||||
return ctrl.$isEmpty(value) ||
|
||||
isUndefined(regexp) ||
|
||||
regexp.test(value);
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
### form
|
||||
|
||||
|
||||
@@ -140,13 +140,13 @@ tests once on Chrome run:
|
||||
grunt test:unit
|
||||
```
|
||||
|
||||
To run the tests on other browsers (Chrome, ChromeCanary, Firefox, Opera and Safari are pre-configured) use:
|
||||
To run the tests on other browsers (Chrome, ChromeCanary, Firefox and Safari are pre-configured) use:
|
||||
|
||||
```shell
|
||||
grunt test:unit --browsers=Opera,Firefox
|
||||
grunt test:unit --browsers=Chrome,Firefox
|
||||
```
|
||||
|
||||
Note there should be _no spaces between browsers_. `Opera, Firefox` is INVALID.
|
||||
Note there should be _no spaces between browsers_. `Chrome, Firefox` is INVALID.
|
||||
|
||||
During development, however, it's more productive to continuously run unit tests every time the source or test files
|
||||
change. To execute tests in this mode run:
|
||||
|
||||
+1
-1
@@ -27,7 +27,7 @@
|
||||
"browserstacktunnel-wrapper": "^1.4.2",
|
||||
"canonical-path": "0.0.2",
|
||||
"changez": "^2.1.1",
|
||||
"changez-angular": "^2.1.2",
|
||||
"changez-angular": "^2.1.3",
|
||||
"cheerio": "^0.17.0",
|
||||
"commitizen": "^2.3.0",
|
||||
"cross-spawn": "^4.0.0",
|
||||
|
||||
@@ -12,7 +12,7 @@ set -xe
|
||||
# This is the default set of browsers to use on the CI server unless overridden via env variable
|
||||
if [[ -z "$BROWSERS" ]]
|
||||
then
|
||||
BROWSERS="Chrome,Firefox,Opera,/Users/jenkins/bin/safari.sh"
|
||||
BROWSERS="Chrome,Firefox,/Users/jenkins/bin/safari.sh"
|
||||
fi
|
||||
|
||||
# CLEAN #
|
||||
|
||||
@@ -15,6 +15,9 @@
|
||||
"splice": false,
|
||||
"push": false,
|
||||
"toString": false,
|
||||
"minErrConfig": false,
|
||||
"errorHandlingConfig": false,
|
||||
"isValidObjectMaxDepth": false,
|
||||
"ngMinErr": false,
|
||||
"_angular": false,
|
||||
"angularModule": false,
|
||||
|
||||
+99
-30
@@ -10,6 +10,9 @@
|
||||
splice,
|
||||
push,
|
||||
toString,
|
||||
minErrConfig,
|
||||
errorHandlingConfig,
|
||||
isValidObjectMaxDepth,
|
||||
ngMinErr,
|
||||
angularModule,
|
||||
uid,
|
||||
@@ -125,6 +128,50 @@ var VALIDITY_STATE_PROPERTY = 'validity';
|
||||
|
||||
var hasOwnProperty = Object.prototype.hasOwnProperty;
|
||||
|
||||
var minErrConfig = {
|
||||
objectMaxDepth: 5
|
||||
};
|
||||
|
||||
/**
|
||||
* @ngdoc function
|
||||
* @name angular.errorHandlingConfig
|
||||
* @module ng
|
||||
* @kind function
|
||||
*
|
||||
* @description
|
||||
* Configure several aspects of error handling in AngularJS if used as a setter or return the
|
||||
* current configuration if used as a getter. The following options are supported:
|
||||
*
|
||||
* - **objectMaxDepth**: The maximum depth to which objects are traversed when stringified for error messages.
|
||||
*
|
||||
* Omitted or undefined options will leave the corresponding configuration values unchanged.
|
||||
*
|
||||
* @param {Object=} config - The configuration object. May only contain the options that need to be
|
||||
* updated. Supported keys:
|
||||
*
|
||||
* * `objectMaxDepth` **{Number}** - The max depth for stringifying objects. Setting to a
|
||||
* non-positive or non-numeric value, removes the max depth limit.
|
||||
* Default: 5
|
||||
*/
|
||||
function errorHandlingConfig(config) {
|
||||
if (isObject(config)) {
|
||||
if (isDefined(config.objectMaxDepth)) {
|
||||
minErrConfig.objectMaxDepth = isValidObjectMaxDepth(config.objectMaxDepth) ? config.objectMaxDepth : NaN;
|
||||
}
|
||||
} else {
|
||||
return minErrConfig;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {Number} maxDepth
|
||||
* @return {boolean}
|
||||
*/
|
||||
function isValidObjectMaxDepth(maxDepth) {
|
||||
return isNumber(maxDepth) && maxDepth > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ngdoc function
|
||||
* @name angular.lowercase
|
||||
@@ -847,9 +894,10 @@ function arrayRemove(array, value) {
|
||||
</file>
|
||||
</example>
|
||||
*/
|
||||
function copy(source, destination) {
|
||||
function copy(source, destination, maxDepth) {
|
||||
var stackSource = [];
|
||||
var stackDest = [];
|
||||
maxDepth = isValidObjectMaxDepth(maxDepth) ? maxDepth : NaN;
|
||||
|
||||
if (destination) {
|
||||
if (isTypedArray(destination) || isArrayBuffer(destination)) {
|
||||
@@ -872,35 +920,39 @@ function copy(source, destination) {
|
||||
|
||||
stackSource.push(source);
|
||||
stackDest.push(destination);
|
||||
return copyRecurse(source, destination);
|
||||
return copyRecurse(source, destination, maxDepth);
|
||||
}
|
||||
|
||||
return copyElement(source);
|
||||
return copyElement(source, maxDepth);
|
||||
|
||||
function copyRecurse(source, destination) {
|
||||
function copyRecurse(source, destination, maxDepth) {
|
||||
maxDepth--;
|
||||
if (maxDepth < 0) {
|
||||
return '...';
|
||||
}
|
||||
var h = destination.$$hashKey;
|
||||
var key;
|
||||
if (isArray(source)) {
|
||||
for (var i = 0, ii = source.length; i < ii; i++) {
|
||||
destination.push(copyElement(source[i]));
|
||||
destination.push(copyElement(source[i], maxDepth));
|
||||
}
|
||||
} else if (isBlankObject(source)) {
|
||||
// createMap() fast path --- Safe to avoid hasOwnProperty check because prototype chain is empty
|
||||
for (key in source) {
|
||||
destination[key] = copyElement(source[key]);
|
||||
destination[key] = copyElement(source[key], maxDepth);
|
||||
}
|
||||
} else if (source && typeof source.hasOwnProperty === 'function') {
|
||||
// Slow path, which must rely on hasOwnProperty
|
||||
for (key in source) {
|
||||
if (source.hasOwnProperty(key)) {
|
||||
destination[key] = copyElement(source[key]);
|
||||
destination[key] = copyElement(source[key], maxDepth);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Slowest path --- hasOwnProperty can't be called as a method
|
||||
for (key in source) {
|
||||
if (hasOwnProperty.call(source, key)) {
|
||||
destination[key] = copyElement(source[key]);
|
||||
destination[key] = copyElement(source[key], maxDepth);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -908,7 +960,7 @@ function copy(source, destination) {
|
||||
return destination;
|
||||
}
|
||||
|
||||
function copyElement(source) {
|
||||
function copyElement(source, maxDepth) {
|
||||
// Simple values
|
||||
if (!isObject(source)) {
|
||||
return source;
|
||||
@@ -937,7 +989,7 @@ function copy(source, destination) {
|
||||
stackDest.push(destination);
|
||||
|
||||
return needsRecurse
|
||||
? copyRecurse(source, destination)
|
||||
? copyRecurse(source, destination, maxDepth)
|
||||
: destination;
|
||||
}
|
||||
|
||||
@@ -1480,33 +1532,50 @@ function getNgAttribute(element, ngAttr) {
|
||||
|
||||
function allowAutoBootstrap(document) {
|
||||
var script = document.currentScript;
|
||||
var src = script && script.getAttribute('src');
|
||||
|
||||
if (!src) {
|
||||
if (!script) {
|
||||
// IE does not have `document.currentScript`
|
||||
return true;
|
||||
}
|
||||
|
||||
var link = document.createElement('a');
|
||||
link.href = src;
|
||||
|
||||
if (document.location.origin === link.origin) {
|
||||
// Same-origin resources are always allowed, even for non-whitelisted schemes.
|
||||
return true;
|
||||
// If the `currentScript` property has been clobbered just return false, since this indicates a probable attack
|
||||
if (!(script instanceof window.HTMLScriptElement || script instanceof window.SVGScriptElement)) {
|
||||
return false;
|
||||
}
|
||||
// Disabled bootstrapping unless angular.js was loaded from a known scheme used on the web.
|
||||
// This is to prevent angular.js bundled with browser extensions from being used to bypass the
|
||||
// content security policy in web pages and other browser extensions.
|
||||
switch (link.protocol) {
|
||||
case 'http:':
|
||||
case 'https:':
|
||||
case 'ftp:':
|
||||
case 'blob:':
|
||||
case 'file:':
|
||||
case 'data:':
|
||||
|
||||
var attributes = script.attributes;
|
||||
var srcs = [attributes.getNamedItem('src'), attributes.getNamedItem('href'), attributes.getNamedItem('xlink:href')];
|
||||
|
||||
return srcs.every(function(src) {
|
||||
if (!src) {
|
||||
return true;
|
||||
default:
|
||||
}
|
||||
if (!src.value) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
var link = document.createElement('a');
|
||||
link.href = src.value;
|
||||
|
||||
if (document.location.origin === link.origin) {
|
||||
// Same-origin resources are always allowed, even for non-whitelisted schemes.
|
||||
return true;
|
||||
}
|
||||
// Disabled bootstrapping unless angular.js was loaded from a known scheme used on the web.
|
||||
// This is to prevent angular.js bundled with browser extensions from being used to bypass the
|
||||
// content security policy in web pages and other browser extensions.
|
||||
switch (link.protocol) {
|
||||
case 'http:':
|
||||
case 'https:':
|
||||
case 'ftp:':
|
||||
case 'blob:':
|
||||
case 'file:':
|
||||
case 'data:':
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Cached as it has to run during loading so that document.currentScript is available.
|
||||
|
||||
@@ -126,6 +126,7 @@ var version = {
|
||||
|
||||
function publishExternalAPI(angular) {
|
||||
extend(angular, {
|
||||
'errorHandlingConfig': errorHandlingConfig,
|
||||
'bootstrap': bootstrap,
|
||||
'copy': copy,
|
||||
'extend': extend,
|
||||
@@ -264,5 +265,6 @@ function publishExternalAPI(angular) {
|
||||
$$cookieReader: $$CookieReaderProvider
|
||||
});
|
||||
}
|
||||
]);
|
||||
])
|
||||
.info({ angularVersion: '"NG_VERSION_FULL"' });
|
||||
}
|
||||
|
||||
@@ -180,6 +180,28 @@ function annotate(fn, strictDi, name) {
|
||||
* As an array of injection names, where the last item in the array is the function to call.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ngdoc property
|
||||
* @name $injector#modules
|
||||
* @type {Object}
|
||||
* @description
|
||||
* A hash containing all the modules that have been loaded into the
|
||||
* $injector.
|
||||
*
|
||||
* You can use this property to find out information about a module via the
|
||||
* {@link angular.Module#info `myModule.info(...)`} method.
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
* ```
|
||||
* var info = $injector.modules['ngAnimate'].info();
|
||||
* ```
|
||||
*
|
||||
* **Do not use this property to attempt to modify the modules after the application
|
||||
* has been bootstrapped.**
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name $injector#get
|
||||
@@ -673,6 +695,7 @@ function createInjector(modulesToLoad, strictDi) {
|
||||
instanceInjector = protoInstanceInjector;
|
||||
|
||||
providerCache['$injector' + providerSuffix] = { $get: valueFn(protoInstanceInjector) };
|
||||
instanceInjector.modules = providerInjector.modules = createMap();
|
||||
var runBlocks = loadModules(modulesToLoad);
|
||||
instanceInjector = protoInstanceInjector.get('$injector');
|
||||
instanceInjector.strictDi = strictDi;
|
||||
@@ -768,6 +791,7 @@ function createInjector(modulesToLoad, strictDi) {
|
||||
try {
|
||||
if (isString(module)) {
|
||||
moduleFn = angularModule(module);
|
||||
instanceInjector.modules[module] = moduleFn;
|
||||
runBlocks = runBlocks.concat(loadModules(moduleFn.requires)).concat(moduleFn._runBlocks);
|
||||
runInvokeQueue(moduleFn._invokeQueue);
|
||||
runInvokeQueue(moduleFn._configBlocks);
|
||||
|
||||
@@ -79,6 +79,9 @@ function setupModuleLoader(window) {
|
||||
* @returns {angular.Module} new module with the {@link angular.Module} api.
|
||||
*/
|
||||
return function module(name, requires, configFn) {
|
||||
|
||||
var info = {};
|
||||
|
||||
var assertNotHasOwnProperty = function(name, context) {
|
||||
if (name === 'hasOwnProperty') {
|
||||
throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context);
|
||||
@@ -114,6 +117,45 @@ function setupModuleLoader(window) {
|
||||
_configBlocks: configBlocks,
|
||||
_runBlocks: runBlocks,
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name angular.Module#info
|
||||
* @module ng
|
||||
*
|
||||
* @param {Object=} info Information about the module
|
||||
* @returns {Object|Module} The current info object for this module if called as a getter,
|
||||
* or `this` if called as a setter.
|
||||
*
|
||||
* @description
|
||||
* Read and write custom information about this module.
|
||||
* For example you could put the version of the module in here.
|
||||
*
|
||||
* ```js
|
||||
* angular.module('myModule', []).info({ version: '1.0.0' });
|
||||
* ```
|
||||
*
|
||||
* The version could then be read back out by accessing the module elsewhere:
|
||||
*
|
||||
* ```
|
||||
* var version = angular.module('myModule').info().version;
|
||||
* ```
|
||||
*
|
||||
* You can also retrieve this information during runtime via the
|
||||
* {@link $injector#modules `$injector.modules`} property:
|
||||
*
|
||||
* ```js
|
||||
* var version = $injector.modules['myModule'].info().version;
|
||||
* ```
|
||||
*/
|
||||
info: function(value) {
|
||||
if (isDefined(value)) {
|
||||
if (!isObject(value)) throw ngMinErr('aobj', 'Argument \'{0}\' must be an object', 'value');
|
||||
info = value;
|
||||
return this;
|
||||
}
|
||||
return info;
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc property
|
||||
* @name angular.Module#requires
|
||||
|
||||
+4
-1
@@ -5,4 +5,7 @@
|
||||
*/
|
||||
'use strict';
|
||||
(function() {
|
||||
function isFunction(value) {return typeof value === 'function';};
|
||||
function isFunction(value) {return typeof value === 'function';}
|
||||
function isDefined(value) {return typeof value !== 'undefined';}
|
||||
function isObject(value) {return value !== null && typeof value === 'object';}
|
||||
|
||||
|
||||
+10
-12
@@ -33,20 +33,19 @@
|
||||
function minErr(module, ErrorConstructor) {
|
||||
ErrorConstructor = ErrorConstructor || Error;
|
||||
return function() {
|
||||
var SKIP_INDEXES = 2;
|
||||
|
||||
var templateArgs = arguments,
|
||||
code = templateArgs[0],
|
||||
var code = arguments[0],
|
||||
template = arguments[1],
|
||||
message = '[' + (module ? module + ':' : '') + code + '] ',
|
||||
template = templateArgs[1],
|
||||
templateArgs = sliceArgs(arguments, 2).map(function(arg) {
|
||||
return toDebugString(arg, minErrConfig.objectMaxDepth);
|
||||
}),
|
||||
paramPrefix, i;
|
||||
|
||||
message += template.replace(/\{\d+\}/g, function(match) {
|
||||
var index = +match.slice(1, -1),
|
||||
shiftedIndex = index + SKIP_INDEXES;
|
||||
var index = +match.slice(1, -1);
|
||||
|
||||
if (shiftedIndex < templateArgs.length) {
|
||||
return toDebugString(templateArgs[shiftedIndex]);
|
||||
if (index < templateArgs.length) {
|
||||
return templateArgs[index];
|
||||
}
|
||||
|
||||
return match;
|
||||
@@ -55,9 +54,8 @@ function minErr(module, ErrorConstructor) {
|
||||
message += '\nhttp://errors.angularjs.org/"NG_VERSION_FULL"/' +
|
||||
(module ? module + '/' : '') + code;
|
||||
|
||||
for (i = SKIP_INDEXES, paramPrefix = '?'; i < templateArgs.length; i++, paramPrefix = '&') {
|
||||
message += paramPrefix + 'p' + (i - SKIP_INDEXES) + '=' +
|
||||
encodeURIComponent(toDebugString(templateArgs[i]));
|
||||
for (i = 0, paramPrefix = '?'; i < templateArgs.length; i++, paramPrefix = '&') {
|
||||
message += paramPrefix + 'p' + i + '=' + encodeURIComponent(templateArgs[i]);
|
||||
}
|
||||
|
||||
return new ErrorConstructor(message);
|
||||
|
||||
+8
-6
@@ -179,6 +179,7 @@ var $$CoreAnimateQueueProvider = /** @this */ function() {
|
||||
*/
|
||||
var $AnimateProvider = ['$provide', /** @this */ function($provide) {
|
||||
var provider = this;
|
||||
var classNameFilter = null;
|
||||
|
||||
this.$$registeredAnimations = Object.create(null);
|
||||
|
||||
@@ -247,15 +248,16 @@ var $AnimateProvider = ['$provide', /** @this */ function($provide) {
|
||||
*/
|
||||
this.classNameFilter = function(expression) {
|
||||
if (arguments.length === 1) {
|
||||
this.$$classNameFilter = (expression instanceof RegExp) ? expression : null;
|
||||
if (this.$$classNameFilter) {
|
||||
var reservedRegex = new RegExp('(\\s+|\\/)' + NG_ANIMATE_CLASSNAME + '(\\s+|\\/)');
|
||||
if (reservedRegex.test(this.$$classNameFilter.toString())) {
|
||||
throw $animateMinErr('nongcls','$animateProvider.classNameFilter(regex) prohibits accepting a regex value which matches/contains the "{0}" CSS class.', NG_ANIMATE_CLASSNAME);
|
||||
classNameFilter = (expression instanceof RegExp) ? expression : null;
|
||||
if (classNameFilter) {
|
||||
var reservedRegex = new RegExp('[(\\s|\\/)]' + NG_ANIMATE_CLASSNAME + '[(\\s|\\/)]');
|
||||
if (reservedRegex.test(classNameFilter.toString())) {
|
||||
classNameFilter = null;
|
||||
throw $animateMinErr('nongcls', '$animateProvider.classNameFilter(regex) prohibits accepting a regex value which matches/contains the "{0}" CSS class.', NG_ANIMATE_CLASSNAME);
|
||||
}
|
||||
}
|
||||
}
|
||||
return this.$$classNameFilter;
|
||||
return classNameFilter;
|
||||
};
|
||||
|
||||
this.$get = ['$$animateQueue', function($$animateQueue) {
|
||||
|
||||
+2
-2
@@ -255,8 +255,8 @@ function Browser(window, document, $log, $sniffer) {
|
||||
self.onUrlChange = function(callback) {
|
||||
// TODO(vojta): refactor to use node's syntax for events
|
||||
if (!urlChangeInit) {
|
||||
// We listen on both (hashchange/popstate) when available, as some browsers (e.g. Opera)
|
||||
// don't fire popstate when user change the address bar and don't fire hashchange when url
|
||||
// We listen on both (hashchange/popstate) when available, as some browsers don't
|
||||
// fire popstate when user changes the address bar and don't fire hashchange when url
|
||||
// changed by push/replaceState
|
||||
|
||||
// html5 history api - popstate event
|
||||
|
||||
+6
-4
@@ -277,10 +277,12 @@
|
||||
* the directive's element. If multiple directives on the same element request a new scope,
|
||||
* only one new scope is created.
|
||||
*
|
||||
* * **`{...}` (an object hash):** A new "isolate" scope is created for the directive's element. The
|
||||
* 'isolate' scope differs from normal scope in that it does not prototypically inherit from its parent
|
||||
* scope. This is useful when creating reusable components, which should not accidentally read or modify
|
||||
* data in the parent scope.
|
||||
* * **`{...}` (an object hash):** A new "isolate" scope is created for the directive's template.
|
||||
* The 'isolate' scope differs from normal scope in that it does not prototypically
|
||||
* inherit from its parent scope. This is useful when creating reusable components, which should not
|
||||
* accidentally read or modify data in the parent scope. Note that an isolate scope
|
||||
* directive without a `template` or `templateUrl` will not apply the isolate scope
|
||||
* to its children elements.
|
||||
*
|
||||
* The 'isolate' scope object hash defines a set of local scope properties derived from attributes on the
|
||||
* directive's element. These local properties are useful for aliasing values for templates. The keys in
|
||||
|
||||
+43
-17
@@ -31,32 +31,57 @@ var ngModelMinErr = minErr('ngModel');
|
||||
* @property {*} $viewValue The actual value from the control's view. For `input` elements, this is a
|
||||
* String. See {@link ngModel.NgModelController#$setViewValue} for information about when the $viewValue
|
||||
* is set.
|
||||
*
|
||||
* @property {*} $modelValue The value in the model that the control is bound to.
|
||||
*
|
||||
* @property {Array.<Function>} $parsers Array of functions to execute, as a pipeline, whenever
|
||||
the control reads value from the DOM. The functions are called in array order, each passing
|
||||
its return value through to the next. The last return value is forwarded to the
|
||||
{@link ngModel.NgModelController#$validators `$validators`} collection.
|
||||
* the control updates the ngModelController with a new {@link ngModel.NgModelController#$viewValue
|
||||
`$viewValue`} from the DOM, usually via user input.
|
||||
See {@link ngModel.NgModelController#$setViewValue `$setViewValue()`} for a detailed lifecycle explanation.
|
||||
Note that the `$parsers` are not called when the bound ngModel expression changes programmatically.
|
||||
|
||||
Parsers are used to sanitize / convert the {@link ngModel.NgModelController#$viewValue
|
||||
`$viewValue`}.
|
||||
The functions are called in array order, each passing
|
||||
its return value through to the next. The last return value is forwarded to the
|
||||
{@link ngModel.NgModelController#$validators `$validators`} collection.
|
||||
|
||||
Returning `undefined` from a parser means a parse error occurred. In that case,
|
||||
no {@link ngModel.NgModelController#$validators `$validators`} will run and the `ngModel`
|
||||
will be set to `undefined` unless {@link ngModelOptions `ngModelOptions.allowInvalid`}
|
||||
is set to `true`. The parse error is stored in `ngModel.$error.parse`.
|
||||
Parsers are used to sanitize / convert the {@link ngModel.NgModelController#$viewValue
|
||||
`$viewValue`}.
|
||||
|
||||
Returning `undefined` from a parser means a parse error occurred. In that case,
|
||||
no {@link ngModel.NgModelController#$validators `$validators`} will run and the `ngModel`
|
||||
will be set to `undefined` unless {@link ngModelOptions `ngModelOptions.allowInvalid`}
|
||||
is set to `true`. The parse error is stored in `ngModel.$error.parse`.
|
||||
|
||||
This simple example shows a parser that would convert text input value to lowercase:
|
||||
* ```js
|
||||
* function parse(value) {
|
||||
* if (value) {
|
||||
* return value.toLowerCase();
|
||||
* }
|
||||
* }
|
||||
* ngModelController.$parsers.push(parse);
|
||||
* ```
|
||||
|
||||
*
|
||||
* @property {Array.<Function>} $formatters Array of functions to execute, as a pipeline, whenever
|
||||
the model value changes. The functions are called in reverse array order, each passing the value through to the
|
||||
next. The last return value is used as the actual DOM value.
|
||||
Used to format / convert values for display in the control.
|
||||
the bound ngModel expression changes programmatically. The `$formatters` are not called when the
|
||||
value of the control is changed by user interaction.
|
||||
|
||||
Formatters are used to format / convert the {@link ngModel.NgModelController#$modelValue
|
||||
`$modelValue`} for display in the control.
|
||||
|
||||
The functions are called in reverse array order, each passing the value through to the
|
||||
next. The last return value is used as the actual DOM value.
|
||||
|
||||
This simple example shows a formatter that would convert the model value to uppercase:
|
||||
|
||||
* ```js
|
||||
* function formatter(value) {
|
||||
* function format(value) {
|
||||
* if (value) {
|
||||
* return value.toUpperCase();
|
||||
* }
|
||||
* }
|
||||
* ngModel.$formatters.push(formatter);
|
||||
* ngModel.$formatters.push(format);
|
||||
* ```
|
||||
*
|
||||
* @property {Object.<string, function>} $validators A collection of validators that are applied
|
||||
@@ -764,9 +789,10 @@ NgModelController.prototype = {
|
||||
*
|
||||
* When `$setViewValue` is called, the new `value` will be staged for committing through the `$parsers`
|
||||
* and `$validators` pipelines. If there are no special {@link ngModelOptions} specified then the staged
|
||||
* value sent directly for processing, finally to be applied to `$modelValue` and then the
|
||||
* **expression** specified in the `ng-model` attribute. Lastly, all the registered change listeners,
|
||||
* in the `$viewChangeListeners` list, are called.
|
||||
* value is sent directly for processing through the `$parsers` pipeline. After this, the `$validators` and
|
||||
* `$asyncValidators` are called and the value is applied to `$modelValue`.
|
||||
* Finally, the value is set to the **expression** specified in the `ng-model` attribute and
|
||||
* all the registered change listeners, in the `$viewChangeListeners` list are called.
|
||||
*
|
||||
* In case the {@link ng.directive:ngModelOptions ngModelOptions} directive is used with `updateOn`
|
||||
* and the `default` trigger is not listed, all those actions will remain pending until one of the
|
||||
|
||||
@@ -111,13 +111,8 @@ var ngOptionsMinErr = minErr('ngOptions');
|
||||
* is not matched against any `<option>` and the `<select>` appears as having no selected value.
|
||||
*
|
||||
*
|
||||
* @param {string} ngModel Assignable angular expression to data-bind to.
|
||||
* @param {string=} name Property name of the form under which the control is published.
|
||||
* @param {string=} required The control is considered valid only if value is entered.
|
||||
* @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
|
||||
* the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
|
||||
* `required` when you want to data-bind to the `required` attribute.
|
||||
* @param {comprehension_expression=} ngOptions in one of the following forms:
|
||||
* @param {string} ngModel Assignable AngularJS expression to data-bind to.
|
||||
* @param {comprehension_expression} ngOptions in one of the following forms:
|
||||
*
|
||||
* * for array data sources:
|
||||
* * `label` **`for`** `value` **`in`** `array`
|
||||
@@ -156,6 +151,13 @@ var ngOptionsMinErr = minErr('ngOptions');
|
||||
* used to identify the objects in the array. The `trackexpr` will most likely refer to the
|
||||
* `value` variable (e.g. `value.propertyName`). With this the selection is preserved
|
||||
* even when the options are recreated (e.g. reloaded from the server).
|
||||
* @param {string=} name Property name of the form under which the control is published.
|
||||
* @param {string=} required The control is considered valid only if value is entered.
|
||||
* @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
|
||||
* the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
|
||||
* `required` when you want to data-bind to the `required` attribute.
|
||||
* @param {string=} ngAttrSize sets the size of the select element dynamically. Uses the
|
||||
* {@link guide/interpolation#-ngattr-for-binding-to-arbitrary-attributes ngAttr} directive.
|
||||
*
|
||||
* @example
|
||||
<example module="selectExample" name="select">
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
* @ngdoc directive
|
||||
* @name ngRepeat
|
||||
* @multiElement
|
||||
* @restrict A
|
||||
*
|
||||
* @description
|
||||
* The `ngRepeat` directive instantiates a template once per item from a collection. Each template
|
||||
|
||||
+33
-12
@@ -4,6 +4,18 @@
|
||||
|
||||
var noopNgModelController = { $setViewValue: noop, $render: noop };
|
||||
|
||||
function setOptionSelectedStatus(optionEl, value) {
|
||||
optionEl.prop('selected', value); // needed for IE
|
||||
/**
|
||||
* When unselecting an option, setting the property to null / false should be enough
|
||||
* However, screenreaders might react to the selected attribute instead, see
|
||||
* https://github.com/angular/angular.js/issues/14419
|
||||
* Note: "selected" is a boolean attr and will be removed when the "value" arg in attr() is false
|
||||
* or null
|
||||
*/
|
||||
optionEl.attr('selected', value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ngdoc type
|
||||
* @name select.SelectController
|
||||
@@ -44,14 +56,14 @@ var SelectController =
|
||||
var unknownVal = self.generateUnknownOptionValue(val);
|
||||
self.unknownOption.val(unknownVal);
|
||||
$element.prepend(self.unknownOption);
|
||||
setOptionAsSelected(self.unknownOption);
|
||||
setOptionSelectedStatus(self.unknownOption, true);
|
||||
$element.val(unknownVal);
|
||||
};
|
||||
|
||||
self.updateUnknownOption = function(val) {
|
||||
var unknownVal = self.generateUnknownOptionValue(val);
|
||||
self.unknownOption.val(unknownVal);
|
||||
setOptionAsSelected(self.unknownOption);
|
||||
setOptionSelectedStatus(self.unknownOption, true);
|
||||
$element.val(unknownVal);
|
||||
};
|
||||
|
||||
@@ -66,7 +78,7 @@ var SelectController =
|
||||
self.selectEmptyOption = function() {
|
||||
if (self.emptyOption) {
|
||||
$element.val('');
|
||||
setOptionAsSelected(self.emptyOption);
|
||||
setOptionSelectedStatus(self.emptyOption, true);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -102,7 +114,7 @@ var SelectController =
|
||||
// Make sure to remove the selected attribute from the previously selected option
|
||||
// Otherwise, screen readers might get confused
|
||||
var currentlySelectedOption = $element[0].options[$element[0].selectedIndex];
|
||||
if (currentlySelectedOption) currentlySelectedOption.removeAttribute('selected');
|
||||
if (currentlySelectedOption) setOptionSelectedStatus(jqLite(currentlySelectedOption), false);
|
||||
|
||||
if (self.hasOption(value)) {
|
||||
self.removeUnknownOption();
|
||||
@@ -112,7 +124,7 @@ var SelectController =
|
||||
|
||||
// Set selected attribute and property on selected option for screen readers
|
||||
var selectedOption = $element[0].options[$element[0].selectedIndex];
|
||||
setOptionAsSelected(jqLite(selectedOption));
|
||||
setOptionSelectedStatus(jqLite(selectedOption), true);
|
||||
} else {
|
||||
if (value == null && self.emptyOption) {
|
||||
self.removeUnknownOption();
|
||||
@@ -292,11 +304,6 @@ var SelectController =
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
function setOptionAsSelected(optionEl) {
|
||||
optionEl.prop('selected', true); // needed for IE
|
||||
optionEl.attr('selected', true);
|
||||
}
|
||||
}];
|
||||
|
||||
/**
|
||||
@@ -366,6 +373,8 @@ var SelectController =
|
||||
* interaction with the select element.
|
||||
* @param {string=} ngOptions sets the options that the select is populated with and defines what is
|
||||
* set on the model on selection. See {@link ngOptions `ngOptions`}.
|
||||
* @param {string=} ngAttrSize sets the size of the select element dynamically. Uses the
|
||||
* {@link guide/interpolation#-ngattr-for-binding-to-arbitrary-attributes ngAttr} directive.
|
||||
*
|
||||
* @example
|
||||
* ### Simple `select` elements with static options
|
||||
@@ -607,8 +616,20 @@ var selectDirective = function() {
|
||||
// Write value now needs to set the selected property of each matching option
|
||||
selectCtrl.writeValue = function writeMultipleValue(value) {
|
||||
forEach(element.find('option'), function(option) {
|
||||
option.selected = !!value && (includes(value, option.value) ||
|
||||
includes(value, selectCtrl.selectValueMap[option.value]));
|
||||
var shouldBeSelected = !!value && (includes(value, option.value) ||
|
||||
includes(value, selectCtrl.selectValueMap[option.value]));
|
||||
var currentlySelected = option.selected;
|
||||
|
||||
// IE and Edge, adding options to the selection via shift+click/UP/DOWN,
|
||||
// will de-select already selected options if "selected" on those options was set
|
||||
// more than once (i.e. when the options were already selected)
|
||||
// So we only modify the selected property if neccessary.
|
||||
// Note: this behavior cannot be replicated via unit tests because it only shows in the
|
||||
// actual user interface.
|
||||
if (shouldBeSelected !== currentlySelected) {
|
||||
setOptionSelectedStatus(jqLite(option), shouldBeSelected);
|
||||
}
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -9,6 +9,9 @@
|
||||
* Selects a subset of items from `array` and returns it as a new array.
|
||||
*
|
||||
* @param {Array} array The source array.
|
||||
* <div class="alert alert-info">
|
||||
* **Note**: If the array contains objects that reference themselves, filtering is not possible.
|
||||
* </div>
|
||||
* @param {string|Object|function()} expression The predicate to be used for selecting items from
|
||||
* `array`.
|
||||
*
|
||||
@@ -226,7 +229,10 @@ function deepCompare(actual, expected, comparator, anyPropertyKey, matchAgainstA
|
||||
var key;
|
||||
if (matchAgainstAnyProp) {
|
||||
for (key in actual) {
|
||||
if ((key.charAt(0) !== '$') && deepCompare(actual[key], expected, comparator, anyPropertyKey, true)) {
|
||||
// Under certain, rare, circumstances, key may not be a string and `charAt` will be undefined
|
||||
// See: https://github.com/angular/angular.js/issues/15644
|
||||
if (key.charAt && (key.charAt(0) !== '$') &&
|
||||
deepCompare(actual[key], expected, comparator, anyPropertyKey, true)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
* how they vary compared to the requested url.
|
||||
*/
|
||||
var $jsonpCallbacksProvider = /** @this */ function() {
|
||||
this.$get = ['$window', function($window) {
|
||||
var callbacks = $window.angular.callbacks;
|
||||
this.$get = function() {
|
||||
var callbacks = angular.callbacks;
|
||||
var callbackMap = {};
|
||||
|
||||
function createCallback(callbackId) {
|
||||
@@ -78,5 +78,5 @@ var $jsonpCallbacksProvider = /** @this */ function() {
|
||||
delete callbackMap[callbackPath];
|
||||
}
|
||||
};
|
||||
}];
|
||||
};
|
||||
};
|
||||
|
||||
+10
-1
@@ -67,6 +67,15 @@ function $LogProvider() {
|
||||
};
|
||||
|
||||
this.$get = ['$window', function($window) {
|
||||
// Support: IE 9-11, Edge 12-14+
|
||||
// IE/Edge display errors in such a way that it requires the user to click in 4 places
|
||||
// to see the stack trace. There is no way to feature-detect it so there's a chance
|
||||
// of the user agent sniffing to go wrong but since it's only about logging, this shouldn't
|
||||
// break apps. Other browsers display errors in a sensible way and some of them map stack
|
||||
// traces along source maps if available so it makes sense to let browsers display it
|
||||
// as they want.
|
||||
var formatStackTrace = msie || /\bEdge\//.test($window.navigator && $window.navigator.userAgent);
|
||||
|
||||
return {
|
||||
/**
|
||||
* @ngdoc method
|
||||
@@ -124,7 +133,7 @@ function $LogProvider() {
|
||||
|
||||
function formatError(arg) {
|
||||
if (arg instanceof Error) {
|
||||
if (arg.stack) {
|
||||
if (arg.stack && formatStackTrace) {
|
||||
arg = (arg.message && arg.stack.indexOf(arg.message) === -1)
|
||||
? 'Error: ' + arg.message + '\n' + arg.stack
|
||||
: arg.stack;
|
||||
|
||||
+4
-3
@@ -786,12 +786,13 @@ function $RootScopeProvider() {
|
||||
current = target;
|
||||
|
||||
// It's safe for asyncQueuePosition to be a local variable here because this loop can't
|
||||
// be reentered recursively. Calling $digest from a function passed to $applyAsync would
|
||||
// be reentered recursively. Calling $digest from a function passed to $evalAsync would
|
||||
// lead to a '$digest already in progress' error.
|
||||
for (var asyncQueuePosition = 0; asyncQueuePosition < asyncQueue.length; asyncQueuePosition++) {
|
||||
try {
|
||||
asyncTask = asyncQueue[asyncQueuePosition];
|
||||
asyncTask.scope.$eval(asyncTask.expression, asyncTask.locals);
|
||||
fn = asyncTask.fn;
|
||||
fn(asyncTask.scope, asyncTask.locals);
|
||||
} catch (e) {
|
||||
$exceptionHandler(e);
|
||||
}
|
||||
@@ -1025,7 +1026,7 @@ function $RootScopeProvider() {
|
||||
});
|
||||
}
|
||||
|
||||
asyncQueue.push({scope: this, expression: $parse(expr), locals: locals});
|
||||
asyncQueue.push({scope: this, fn: $parse(expr), locals: locals});
|
||||
},
|
||||
|
||||
$$postDigest: function(fn) {
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@ var originUrl = urlResolve(window.location.href);
|
||||
* URL will be resolved into an absolute URL in the context of the application document.
|
||||
* Parsing means that the anchor node's host, hostname, protocol, port, pathname and related
|
||||
* properties are all populated to reflect the normalized URL. This approach has wide
|
||||
* compatibility - Safari 1+, Mozilla 1+, Opera 7+,e etc. See
|
||||
* compatibility - Safari 1+, Mozilla 1+ etc. See
|
||||
* http://www.aptana.com/reference/html/api/HTMLAnchorElement.html
|
||||
*
|
||||
* Implementation Notes for IE
|
||||
|
||||
@@ -177,6 +177,10 @@
|
||||
* /* As of 1.4.4, this must always be set: it signals ngAnimate
|
||||
* to not accidentally inherit a delay property from another CSS class */
|
||||
* transition-duration: 0s;
|
||||
*
|
||||
* /* if you are using animations instead of transitions you should configure as follows:
|
||||
* animation-delay: 0.1s;
|
||||
* animation-duration: 0s; */
|
||||
* }
|
||||
* .my-animation.ng-enter.ng-enter-active {
|
||||
* /* standard transition styles */
|
||||
@@ -756,6 +760,7 @@ angular.module('ngAnimate', [], function initAngularHelpers() {
|
||||
isFunction = angular.isFunction;
|
||||
isElement = angular.isElement;
|
||||
})
|
||||
.info({ angularVersion: '"NG_VERSION_FULL"' })
|
||||
.directive('ngAnimateSwap', ngAnimateSwapDirective)
|
||||
|
||||
.directive('ngAnimateChildren', $$AnimateChildrenDirective)
|
||||
|
||||
@@ -54,6 +54,7 @@
|
||||
* {@link guide/accessibility Developer Guide}.
|
||||
*/
|
||||
var ngAriaModule = angular.module('ngAria', ['ng']).
|
||||
info({ angularVersion: '"NG_VERSION_FULL"' }).
|
||||
provider('$aria', $AriaProvider);
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
|
||||
angular.module('ngCookies', ['ng']).
|
||||
info({ angularVersion: '"NG_VERSION_FULL"' }).
|
||||
/**
|
||||
* @ngdoc provider
|
||||
* @name $cookiesProvider
|
||||
|
||||
@@ -216,6 +216,7 @@ var toJson;
|
||||
var $$stringify;
|
||||
|
||||
var module = window['angular']['module']('ngMessageFormat', ['ng']);
|
||||
module['info']({ 'angularVersion': '"NG_VERSION_FULL"' });
|
||||
module['factory']('$$messageFormat', $$MessageFormatFactory);
|
||||
module['config'](['$provide', function($provide) {
|
||||
$interpolateMinErr = window['angular']['$interpolateMinErr'];
|
||||
|
||||
@@ -267,6 +267,7 @@ angular.module('ngMessages', [], function initAngularHelpers() {
|
||||
isString = angular.isString;
|
||||
jqLite = angular.element;
|
||||
})
|
||||
.info({ angularVersion: '"NG_VERSION_FULL"' })
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
|
||||
Vendored
+3
-2
@@ -790,6 +790,7 @@ angular.mock.TzDate.prototype = Date.prototype;
|
||||
* You need to require the `ngAnimateMock` module in your test suite for instance `beforeEach(module('ngAnimateMock'))`
|
||||
*/
|
||||
angular.mock.animate = angular.module('ngAnimateMock', ['ng'])
|
||||
.info({ angularVersion: '"NG_VERSION_FULL"' })
|
||||
|
||||
.config(['$provide', function($provide) {
|
||||
|
||||
@@ -2406,7 +2407,7 @@ angular.module('ngMock', ['ng']).provider({
|
||||
$provide.decorator('$rootScope', angular.mock.$RootScopeDecorator);
|
||||
$provide.decorator('$controller', createControllerDecorator($compileProvider));
|
||||
$provide.decorator('$httpBackend', angular.mock.$httpBackendDecorator);
|
||||
}]);
|
||||
}]).info({ angularVersion: '"NG_VERSION_FULL"' });
|
||||
|
||||
/**
|
||||
* @ngdoc module
|
||||
@@ -2421,7 +2422,7 @@ angular.module('ngMock', ['ng']).provider({
|
||||
*/
|
||||
angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
|
||||
$provide.decorator('$httpBackend', angular.mock.e2e.$httpBackendDecorator);
|
||||
}]);
|
||||
}]).info({ angularVersion: '"NG_VERSION_FULL"' });
|
||||
|
||||
/**
|
||||
* @ngdoc service
|
||||
|
||||
@@ -44,4 +44,5 @@ function isValidIdentifierContinue(ch, cp) {
|
||||
angular.module('ngParseExt', [])
|
||||
.config(['$parseProvider', function($parseProvider) {
|
||||
$parseProvider.setIdentifierFns(isValidIdentifierStart, isValidIdentifierContinue);
|
||||
}]);
|
||||
}])
|
||||
.info({ angularVersion: '"NG_VERSION_FULL"' });
|
||||
|
||||
@@ -174,7 +174,7 @@ function shallowClearAndCopy(src, dst) {
|
||||
* set `transformResponse` to an empty array: `transformResponse: []`
|
||||
* - **`cache`** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the
|
||||
* GET request, otherwise if a cache instance built with
|
||||
* {@link ng.$cacheFactory $cacheFactory}, this cache will be used for
|
||||
* {@link ng.$cacheFactory $cacheFactory} is supplied, this cache will be used for
|
||||
* caching.
|
||||
* - **`timeout`** – `{number}` – timeout in milliseconds.<br />
|
||||
* **Note:** In contrast to {@link ng.$http#usage $http.config}, {@link ng.$q promises} are
|
||||
@@ -429,6 +429,7 @@ function shallowClearAndCopy(src, dst) {
|
||||
*
|
||||
*/
|
||||
angular.module('ngResource', ['ng']).
|
||||
info({ angularVersion: '"NG_VERSION_FULL"' }).
|
||||
provider('$resource', function ResourceProvider() {
|
||||
var PROTOCOL_AND_IPV6_REGEX = /^https?:\/\/\[[^\]]*][^/]*/;
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ var noop;
|
||||
/* global -ngRouteModule */
|
||||
var ngRouteModule = angular.
|
||||
module('ngRoute', []).
|
||||
info({ angularVersion: '"NG_VERSION_FULL"' }).
|
||||
provider('$route', $RouteProvider).
|
||||
// Ensure `$route` will be instantiated in time to capture the initial `$locationChangeSuccess`
|
||||
// event (unless explicitly disabled). This is necessary in case `ngView` is included in an
|
||||
|
||||
@@ -18,6 +18,7 @@ var forEach;
|
||||
var isDefined;
|
||||
var lowercase;
|
||||
var noop;
|
||||
var nodeContains;
|
||||
var htmlParser;
|
||||
var htmlSanitizeWriter;
|
||||
|
||||
@@ -218,6 +219,11 @@ function $SanitizeProvider() {
|
||||
htmlParser = htmlParserImpl;
|
||||
htmlSanitizeWriter = htmlSanitizeWriterImpl;
|
||||
|
||||
nodeContains = window.Node.prototype.contains || /** @this */ function(arg) {
|
||||
// eslint-disable-next-line no-bitwise
|
||||
return !!(this.compareDocumentPosition(arg) & 16);
|
||||
};
|
||||
|
||||
// Regular Expressions for parsing tags and attributes
|
||||
var SURROGATE_PAIR_REGEXP = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g,
|
||||
// Match everything outside of normal chars and " (quote character)
|
||||
@@ -381,12 +387,12 @@ function $SanitizeProvider() {
|
||||
if (node.nodeType === 1) {
|
||||
handler.end(node.nodeName.toLowerCase());
|
||||
}
|
||||
nextNode = node.nextSibling;
|
||||
nextNode = getNonDescendant('nextSibling', node);
|
||||
if (!nextNode) {
|
||||
while (nextNode == null) {
|
||||
node = node.parentNode;
|
||||
node = getNonDescendant('parentNode', node);
|
||||
if (node === inertBodyElement) break;
|
||||
nextNode = node.nextSibling;
|
||||
nextNode = getNonDescendant('nextSibling', node);
|
||||
if (node.nodeType === 1) {
|
||||
handler.end(node.nodeName.toLowerCase());
|
||||
}
|
||||
@@ -518,9 +524,18 @@ function $SanitizeProvider() {
|
||||
stripCustomNsAttrs(nextNode);
|
||||
}
|
||||
|
||||
node = node.nextSibling;
|
||||
node = getNonDescendant('nextSibling', node);
|
||||
}
|
||||
}
|
||||
|
||||
function getNonDescendant(propName, node) {
|
||||
// An element is clobbered if its `propName` property points to one of its descendants
|
||||
var nextNode = node[propName];
|
||||
if (nextNode && nodeContains.call(node, nextNode)) {
|
||||
throw $sanitizeMinErr('elclob', 'Failed to sanitize html because the element is clobbered: {0}', node.outerHTML || node.outerText);
|
||||
}
|
||||
return nextNode;
|
||||
}
|
||||
}
|
||||
|
||||
function sanitizeText(chars) {
|
||||
@@ -532,4 +547,6 @@ function sanitizeText(chars) {
|
||||
|
||||
|
||||
// define ngSanitize module and register $sanitize service
|
||||
angular.module('ngSanitize', []).provider('$sanitize', $SanitizeProvider);
|
||||
angular.module('ngSanitize', [])
|
||||
.provider('$sanitize', $SanitizeProvider)
|
||||
.info({ angularVersion: '"NG_VERSION_FULL"' });
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
/* global -ngTouch */
|
||||
var ngTouch = angular.module('ngTouch', []);
|
||||
|
||||
ngTouch.info({ angularVersion: '"NG_VERSION_FULL"' });
|
||||
|
||||
ngTouch.provider('$touch', $TouchProvider);
|
||||
|
||||
function nodeName_(element) {
|
||||
|
||||
+9
-3
@@ -2,9 +2,15 @@
|
||||
|
||||
/* global toDebugString: true */
|
||||
|
||||
function serializeObject(obj) {
|
||||
function serializeObject(obj, maxDepth) {
|
||||
var seen = [];
|
||||
|
||||
// There is no direct way to stringify object until reaching a specific depth
|
||||
// and a very deep object can cause a performance issue, so we copy the object
|
||||
// based on this specific depth and then stringify it.
|
||||
if (isValidObjectMaxDepth(maxDepth)) {
|
||||
obj = copy(obj, null, maxDepth);
|
||||
}
|
||||
return JSON.stringify(obj, function(key, val) {
|
||||
val = toJsonReplacer(key, val);
|
||||
if (isObject(val)) {
|
||||
@@ -17,13 +23,13 @@ function serializeObject(obj) {
|
||||
});
|
||||
}
|
||||
|
||||
function toDebugString(obj) {
|
||||
function toDebugString(obj, maxDepth) {
|
||||
if (typeof obj === 'function') {
|
||||
return obj.toString().replace(/ \{[\s\S]*$/, '');
|
||||
} else if (isUndefined(obj)) {
|
||||
return 'undefined';
|
||||
} else if (typeof obj !== 'string') {
|
||||
return serializeObject(obj);
|
||||
return serializeObject(obj, maxDepth);
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
|
||||
/* angular.js */
|
||||
"angular": false,
|
||||
"minErrConfig": false,
|
||||
"errorHandlingConfig": false,
|
||||
"msie": false,
|
||||
"jqLite": false,
|
||||
"jQuery": false,
|
||||
@@ -37,6 +39,7 @@
|
||||
"nodeName_": false,
|
||||
"uid": false,
|
||||
"toDebugString": false,
|
||||
"serializeObject": false,
|
||||
|
||||
"lowercase": false,
|
||||
"uppercase": false,
|
||||
|
||||
+131
-65
@@ -7,6 +7,7 @@ Float32Array, Float64Array, */
|
||||
|
||||
describe('angular', function() {
|
||||
var element, document;
|
||||
var originalObjectMaxDepthInErrorMessage = minErrConfig.objectMaxDepth;
|
||||
|
||||
beforeEach(function() {
|
||||
document = window.document;
|
||||
@@ -14,6 +15,30 @@ describe('angular', function() {
|
||||
|
||||
afterEach(function() {
|
||||
dealoc(element);
|
||||
minErrConfig.objectMaxDepth = originalObjectMaxDepthInErrorMessage;
|
||||
});
|
||||
|
||||
describe('errorHandlingConfig', function() {
|
||||
it('should get default objectMaxDepth', function() {
|
||||
expect(errorHandlingConfig().objectMaxDepth).toBe(5);
|
||||
});
|
||||
|
||||
it('should set objectMaxDepth', function() {
|
||||
errorHandlingConfig({objectMaxDepth: 3});
|
||||
expect(errorHandlingConfig().objectMaxDepth).toBe(3);
|
||||
});
|
||||
|
||||
it('should not change objectMaxDepth when undefined is supplied', function() {
|
||||
errorHandlingConfig({objectMaxDepth: undefined});
|
||||
expect(errorHandlingConfig().objectMaxDepth).toBe(originalObjectMaxDepthInErrorMessage);
|
||||
});
|
||||
|
||||
they('should set objectMaxDepth to NaN when $prop is supplied',
|
||||
[NaN, null, true, false, -1, 0], function(maxDepth) {
|
||||
errorHandlingConfig({objectMaxDepth: maxDepth});
|
||||
expect(errorHandlingConfig().objectMaxDepth).toBeNaN();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
describe('case', function() {
|
||||
@@ -602,6 +627,31 @@ describe('angular', function() {
|
||||
expect(copy(new Number(NaN)).valueOf()).toBeNaN();
|
||||
/* eslint-enable */
|
||||
});
|
||||
|
||||
it('should copy source until reaching a given max depth', function() {
|
||||
var source = {a1: 1, b1: {b2: {b3: 1}}, c1: [1, {c2: 1}], d1: {d2: 1}};
|
||||
var dest;
|
||||
|
||||
dest = copy(source, {}, 1);
|
||||
expect(dest).toEqual({a1:1, b1:'...', c1:'...', d1:'...'});
|
||||
|
||||
dest = copy(source, {}, 2);
|
||||
expect(dest).toEqual({a1:1, b1:{b2:'...'}, c1:[1,'...'], d1:{d2:1}});
|
||||
|
||||
dest = copy(source, {}, 3);
|
||||
expect(dest).toEqual({a1: 1, b1: {b2: {b3: 1}}, c1: [1, {c2: 1}], d1: {d2: 1}});
|
||||
|
||||
dest = copy(source, {}, 4);
|
||||
expect(dest).toEqual({a1: 1, b1: {b2: {b3: 1}}, c1: [1, {c2: 1}], d1: {d2: 1}});
|
||||
});
|
||||
|
||||
they('should copy source and ignore max depth when maxDepth = $prop',
|
||||
[NaN, null, undefined, true, false, -1, 0], function(maxDepth) {
|
||||
var source = {a1: 1, b1: {b2: {b3: 1}}, c1: [1, {c2: 1}], d1: {d2: 1}};
|
||||
var dest = copy(source, {}, maxDepth);
|
||||
expect(dest).toEqual({a1: 1, b1: {b2: {b3: 1}}, c1: [1, {c2: 1}], d1: {d2: 1}});
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
describe('extend', function() {
|
||||
@@ -1683,84 +1733,100 @@ describe('angular', function() {
|
||||
dealoc(appElement);
|
||||
});
|
||||
|
||||
it('should bootstrap from an extension into an extension document for same-origin documents only', function() {
|
||||
// IE does not support `document.currentScript` (nor extensions with protocol), so skip test.
|
||||
if (msie) return;
|
||||
// IE does not support `document.currentScript` (nor extensions with protocol), so skip tests.
|
||||
if (!msie) {
|
||||
describe('auto bootstrap restrictions', function() {
|
||||
|
||||
// Extension URLs are browser-specific, so we must choose a scheme that is supported by the browser to make
|
||||
// sure that the URL is properly parsed.
|
||||
var extensionScheme;
|
||||
var userAgent = window.navigator.userAgent;
|
||||
if (/Firefox\//.test(userAgent)) {
|
||||
extensionScheme = 'moz-extension';
|
||||
} else if (/Edge\//.test(userAgent)) {
|
||||
extensionScheme = 'ms-browser-extension';
|
||||
} else if (/Chrome\//.test(userAgent)) {
|
||||
extensionScheme = 'chrome-extension';
|
||||
} else if (/Safari\//.test(userAgent)) {
|
||||
extensionScheme = 'safari-extension';
|
||||
} else {
|
||||
extensionScheme = 'browserext'; // Upcoming standard scheme.
|
||||
}
|
||||
function createFakeDoc(attrs, protocol, currentScript) {
|
||||
|
||||
var src = extensionScheme + '://something';
|
||||
// Fake a minimal document object (the actual document.currentScript is readonly).
|
||||
var fakeDoc = {
|
||||
currentScript: { getAttribute: function() { return src; } },
|
||||
location: {protocol: extensionScheme + ':', origin: extensionScheme + '://something'},
|
||||
createElement: document.createElement.bind(document)
|
||||
};
|
||||
expect(allowAutoBootstrap(fakeDoc)).toBe(true);
|
||||
protocol = protocol || 'http:';
|
||||
var origin = protocol + '//something';
|
||||
|
||||
src = extensionScheme + '://something-else';
|
||||
expect(allowAutoBootstrap(fakeDoc)).toBe(false);
|
||||
});
|
||||
if (currentScript === undefined) {
|
||||
currentScript = document.createElement('script');
|
||||
Object.keys(attrs).forEach(function(key) { currentScript.setAttribute(key, attrs[key]); });
|
||||
}
|
||||
|
||||
it('should bootstrap from a script with an empty or missing `src` attribute', function() {
|
||||
// IE does not support `document.currentScript` (nor extensions with protocol), so skip test.
|
||||
if (msie) return;
|
||||
// Fake a minimal document object (the actual document.currentScript is readonly).
|
||||
return {
|
||||
currentScript: currentScript,
|
||||
location: {protocol: protocol, origin: origin},
|
||||
createElement: document.createElement.bind(document)
|
||||
};
|
||||
}
|
||||
|
||||
// Fake a minimal document object (the actual document.currentScript is readonly).
|
||||
var src;
|
||||
var fakeDoc = {
|
||||
createElement: document.createElement.bind(document),
|
||||
currentScript: {getAttribute: function() { return src; }},
|
||||
location: {origin: 'some-value', protocol: 'http:'}
|
||||
};
|
||||
it('should bootstrap from an extension into an extension document for same-origin documents only', function() {
|
||||
|
||||
src = null;
|
||||
expect(allowAutoBootstrap(fakeDoc)).toBe(true);
|
||||
// Extension URLs are browser-specific, so we must choose a scheme that is supported by the browser to make
|
||||
// sure that the URL is properly parsed.
|
||||
var protocol;
|
||||
var userAgent = window.navigator.userAgent;
|
||||
if (/Firefox\//.test(userAgent)) {
|
||||
protocol = 'moz-extension:';
|
||||
} else if (/Edge\//.test(userAgent)) {
|
||||
protocol = 'ms-browser-extension:';
|
||||
} else if (/Chrome\//.test(userAgent)) {
|
||||
protocol = 'chrome-extension:';
|
||||
} else if (/Safari\//.test(userAgent)) {
|
||||
protocol = 'safari-extension:';
|
||||
} else {
|
||||
protocol = 'browserext:'; // Upcoming standard scheme.
|
||||
}
|
||||
|
||||
src = '';
|
||||
expect(allowAutoBootstrap(fakeDoc)).toBe(true);
|
||||
});
|
||||
expect(allowAutoBootstrap(createFakeDoc({src: protocol + '//something'}, protocol))).toBe(true);
|
||||
expect(allowAutoBootstrap(createFakeDoc({src: protocol + '//something-else'}, protocol))).toBe(false);
|
||||
});
|
||||
|
||||
it('should not bootstrap from an extension into a non-extension document', function() {
|
||||
// IE does not support `document.currentScript` (nor extensions with protocol), so skip test.
|
||||
if (msie) return;
|
||||
it('should bootstrap from a script with no source (e.g. src, href or xlink:href attributes)', function() {
|
||||
|
||||
var src = 'resource://something';
|
||||
// Fake a minimal document object (the actual document.currentScript is readonly).
|
||||
var fakeDoc = {
|
||||
currentScript: { getAttribute: function() { return src; } },
|
||||
location: {protocol: 'http:'},
|
||||
createElement: document.createElement.bind(document)
|
||||
};
|
||||
expect(allowAutoBootstrap(fakeDoc)).toBe(false);
|
||||
expect(allowAutoBootstrap(createFakeDoc({src: null}))).toBe(true);
|
||||
expect(allowAutoBootstrap(createFakeDoc({href: null}))).toBe(true);
|
||||
expect(allowAutoBootstrap(createFakeDoc({'xlink:href': null}))).toBe(true);
|
||||
});
|
||||
|
||||
src = 'file://whatever';
|
||||
expect(allowAutoBootstrap(fakeDoc)).toBe(true);
|
||||
});
|
||||
it('should not bootstrap from a script with an empty source (e.g. `src=""`)', function() {
|
||||
expect(allowAutoBootstrap(createFakeDoc({src: ''}))).toBe(false);
|
||||
expect(allowAutoBootstrap(createFakeDoc({href: ''}))).toBe(false);
|
||||
expect(allowAutoBootstrap(createFakeDoc({'xlink:href': ''}))).toBe(false);
|
||||
});
|
||||
|
||||
it('should not bootstrap if bootstrapping is disabled', function() {
|
||||
isAutoBootstrapAllowed = false;
|
||||
angularInit(jqLite('<div ng-app></div>')[0], bootstrapSpy);
|
||||
expect(bootstrapSpy).not.toHaveBeenCalled();
|
||||
isAutoBootstrapAllowed = true;
|
||||
});
|
||||
|
||||
it('should not bootstrap from an extension into a non-extension document', function() {
|
||||
|
||||
expect(allowAutoBootstrap(createFakeDoc({src: 'resource://something'}))).toBe(false);
|
||||
expect(allowAutoBootstrap(createFakeDoc({src: 'file://whatever'}))).toBe(true);
|
||||
});
|
||||
|
||||
it('should not bootstrap from an extension into a non-extension document, via SVG script', function() {
|
||||
|
||||
// SVG script tags don't use the `src` attribute to load their source.
|
||||
// Instead they use `href` or the deprecated `xlink:href` attributes.
|
||||
|
||||
expect(allowAutoBootstrap(createFakeDoc({href: 'resource://something'}))).toBe(false);
|
||||
expect(allowAutoBootstrap(createFakeDoc({'xlink:href': 'resource://something'}))).toBe(false);
|
||||
|
||||
expect(allowAutoBootstrap(createFakeDoc({src: 'http://something', href: 'resource://something'}))).toBe(false);
|
||||
expect(allowAutoBootstrap(createFakeDoc({href: 'http://something', 'xlink:href': 'resource://something'}))).toBe(false);
|
||||
expect(allowAutoBootstrap(createFakeDoc({src: 'resource://something', href: 'http://something', 'xlink:href': 'http://something'}))).toBe(false);
|
||||
});
|
||||
|
||||
it('should not bootstrap if the currentScript property has been clobbered', function() {
|
||||
|
||||
var img = document.createElement('img');
|
||||
img.setAttribute('src', '');
|
||||
expect(allowAutoBootstrap(createFakeDoc({}, 'http:', img))).toBe(false);
|
||||
});
|
||||
|
||||
it('should not bootstrap if bootstrapping is disabled', function() {
|
||||
isAutoBootstrapAllowed = false;
|
||||
angularInit(jqLite('<div ng-app></div>')[0], bootstrapSpy);
|
||||
expect(bootstrapSpy).not.toHaveBeenCalled();
|
||||
isAutoBootstrapAllowed = true;
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
describe('angular service', function() {
|
||||
it('should override services', function() {
|
||||
module(function($provide) {
|
||||
|
||||
@@ -2,6 +2,37 @@
|
||||
|
||||
/* globals support: false */
|
||||
|
||||
describe('injector.modules', function() {
|
||||
it('should expose the loaded module info on the instance injector', function() {
|
||||
var test1 = angular.module('test1', ['test2']).info({ version: '1.1' });
|
||||
var test2 = angular.module('test2', []).info({ version: '1.2' });
|
||||
module('test1');
|
||||
inject(['$injector', function($injector) {
|
||||
expect(Object.keys($injector.modules)).toEqual(['ng', 'ngLocale', 'ngMock', 'test1', 'test2']);
|
||||
expect($injector.modules['test1'].info()).toEqual({ version: '1.1' });
|
||||
expect($injector.modules['test2'].info()).toEqual({ version: '1.2' });
|
||||
}]);
|
||||
});
|
||||
|
||||
it('should expose the loaded module info on the provider injector', function() {
|
||||
var providerInjector;
|
||||
var test1 = angular.module('test1', ['test2']).info({ version: '1.1' });
|
||||
var test2 = angular.module('test2', [])
|
||||
.info({ version: '1.2' })
|
||||
.provider('test', ['$injector', function($injector) {
|
||||
providerInjector = $injector;
|
||||
return { $get: function() {} };
|
||||
}]);
|
||||
module('test1');
|
||||
// needed to ensure that the provider blocks are executed
|
||||
inject();
|
||||
|
||||
expect(Object.keys(providerInjector.modules)).toEqual(['ng', 'ngLocale', 'ngMock', 'test1', 'test2']);
|
||||
expect(providerInjector.modules['test1'].info()).toEqual({ version: '1.1' });
|
||||
expect(providerInjector.modules['test2'].info()).toEqual({ version: '1.2' });
|
||||
});
|
||||
});
|
||||
|
||||
describe('injector', function() {
|
||||
var providers;
|
||||
var injector;
|
||||
|
||||
@@ -156,4 +156,35 @@ describe('module loader', function() {
|
||||
it('should expose `$$minErr` on the `angular` object', function() {
|
||||
expect(window.angular.$$minErr).toEqual(jasmine.any(Function));
|
||||
});
|
||||
|
||||
describe('Module', function() {
|
||||
describe('info()', function() {
|
||||
var theModule;
|
||||
|
||||
beforeEach(function() {
|
||||
theModule = angular.module('theModule', []);
|
||||
});
|
||||
|
||||
it('should default to an empty object', function() {
|
||||
expect(theModule.info()).toEqual({});
|
||||
});
|
||||
|
||||
it('should store the object passed as a param', function() {
|
||||
theModule.info({ version: '1.2' });
|
||||
expect(theModule.info()).toEqual({ version: '1.2' });
|
||||
});
|
||||
|
||||
it('should throw if the parameter is not an object', function() {
|
||||
expect(function() {
|
||||
theModule.info('some text');
|
||||
}).toThrowMinErr('ng', 'aobj');
|
||||
});
|
||||
|
||||
it('should completely replace the previous info object', function() {
|
||||
theModule.info({ value: 'X' });
|
||||
theModule.info({ newValue: 'Y' });
|
||||
expect(theModule.info()).toEqual({ newValue: 'Y' });
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -9,6 +9,11 @@ describe('minErr', function() {
|
||||
var emptyTestError = minErr(),
|
||||
testError = minErr('test');
|
||||
|
||||
var originalObjectMaxDepthInErrorMessage = minErrConfig.objectMaxDepth;
|
||||
afterEach(function() {
|
||||
minErrConfig.objectMaxDepth = originalObjectMaxDepthInErrorMessage;
|
||||
});
|
||||
|
||||
it('should return an Error factory', function() {
|
||||
var myError = testError('test', 'Oops');
|
||||
expect(myError instanceof Error).toBe(true);
|
||||
@@ -68,6 +73,35 @@ describe('minErr', function() {
|
||||
expect(myError.message).toMatch(/a is {"b":{"a":"..."}}/);
|
||||
});
|
||||
|
||||
it('should handle arguments that are objects with max depth', function() {
|
||||
var a = {b: {c: {d: {e: {f: {g: 1}}}}}};
|
||||
|
||||
var myError = testError('26', 'a when objectMaxDepth is default=5 is {0}', a);
|
||||
expect(myError.message).toMatch(/a when objectMaxDepth is default=5 is {"b":{"c":{"d":{"e":{"f":"..."}}}}}/);
|
||||
|
||||
errorHandlingConfig({objectMaxDepth: 1});
|
||||
myError = testError('26', 'a when objectMaxDepth is set to 1 is {0}', a);
|
||||
expect(myError.message).toMatch(/a when objectMaxDepth is set to 1 is {"b":"..."}/);
|
||||
|
||||
errorHandlingConfig({objectMaxDepth: 2});
|
||||
myError = testError('26', 'a when objectMaxDepth is set to 2 is {0}', a);
|
||||
expect(myError.message).toMatch(/a when objectMaxDepth is set to 2 is {"b":{"c":"..."}}/);
|
||||
|
||||
errorHandlingConfig({objectMaxDepth: undefined});
|
||||
myError = testError('26', 'a when objectMaxDepth is set to undefined is {0}', a);
|
||||
expect(myError.message).toMatch(/a when objectMaxDepth is set to undefined is {"b":{"c":"..."}}/);
|
||||
});
|
||||
|
||||
they('should handle arguments that are objects and ignore max depth when objectMaxDepth = $prop',
|
||||
[NaN, null, true, false, -1, 0], function(maxDepth) {
|
||||
var a = {b: {c: {d: {e: {f: {g: 1}}}}}};
|
||||
|
||||
errorHandlingConfig({objectMaxDepth: maxDepth});
|
||||
var myError = testError('26', 'a is {0}', a);
|
||||
expect(myError.message).toMatch(/a is {"b":{"c":{"d":{"e":{"f":{"g":1}}}}}}/);
|
||||
}
|
||||
);
|
||||
|
||||
it('should preserve interpolation markers when fewer arguments than needed are provided', function() {
|
||||
// this way we can easily see if we are passing fewer args than needed
|
||||
|
||||
|
||||
@@ -1098,13 +1098,21 @@ describe('select', function() {
|
||||
scope.selection = ['A'];
|
||||
});
|
||||
|
||||
var optionElements = element.find('option');
|
||||
|
||||
expect(element).toEqualSelect(['A'], 'B');
|
||||
expect(optionElements[0]).toBeMarkedAsSelected();
|
||||
expect(optionElements[1]).not.toBeMarkedAsSelected();
|
||||
|
||||
scope.$apply(function() {
|
||||
scope.selection.push('B');
|
||||
});
|
||||
|
||||
optionElements = element.find('option');
|
||||
|
||||
expect(element).toEqualSelect(['A'], ['B']);
|
||||
expect(optionElements[0]).toBeMarkedAsSelected();
|
||||
expect(optionElements[1]).toBeMarkedAsSelected();
|
||||
});
|
||||
|
||||
it('should work with optgroups', function() {
|
||||
|
||||
@@ -1368,6 +1368,20 @@ describe('$http', function() {
|
||||
expect(callback.calls.argsFor(1)[0].data).toEqual('{"is": "not"} ["json"]');
|
||||
}
|
||||
);
|
||||
|
||||
it('should forward json deserialization errors to the http error handler',
|
||||
function() {
|
||||
var errCallback = jasmine.createSpy('error');
|
||||
|
||||
$httpBackend.expect('GET', '/url').respond('abcd', {'Content-Type': 'application/json'});
|
||||
$http({method: 'GET', url: '/url'}).then(callback).catch(errCallback);
|
||||
$httpBackend.flush();
|
||||
|
||||
expect(callback).not.toHaveBeenCalled();
|
||||
expect(errCallback).toHaveBeenCalledOnce();
|
||||
expect(errCallback.calls.mostRecent().args[0]).toEqual(jasmine.any(SyntaxError));
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
@@ -79,4 +79,17 @@ describe('$jsonpCallbacks', function() {
|
||||
expect($window.angular.callbacks._0).toBeUndefined();
|
||||
}));
|
||||
});
|
||||
|
||||
describe('mocked $window', function() {
|
||||
|
||||
beforeEach(module(function($provide) {
|
||||
$provide.value('$window', {});
|
||||
}));
|
||||
|
||||
it('should not throw when $window.angular does not exist', inject(function($injector) {
|
||||
expect(function() {
|
||||
$injector.get('$jsonpCallbacks');
|
||||
}).not.toThrow();
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
+39
-23
@@ -7,7 +7,10 @@ describe('$log', function() {
|
||||
|
||||
|
||||
beforeEach(module(function($provide) {
|
||||
$window = {navigator: {}, document: {}};
|
||||
$window = {
|
||||
navigator: {userAgent: window.navigator.userAgent},
|
||||
document: {}
|
||||
};
|
||||
logger = '';
|
||||
log = function() { logger += 'log;'; };
|
||||
warn = function() { logger += 'warn;'; };
|
||||
@@ -64,6 +67,13 @@ describe('$log', function() {
|
||||
}
|
||||
));
|
||||
|
||||
it('should work if $window.navigator not defined', inject(
|
||||
function() {
|
||||
delete $window.navigator;
|
||||
},
|
||||
function($log) {}
|
||||
));
|
||||
|
||||
describe('IE logging behavior', function() {
|
||||
function removeApplyFunctionForIE() {
|
||||
log.apply = log.call =
|
||||
@@ -131,12 +141,12 @@ describe('$log', function() {
|
||||
$log.debug();
|
||||
expect(logger).toEqual('log;warn;info;error;');
|
||||
}
|
||||
));
|
||||
));
|
||||
|
||||
});
|
||||
|
||||
describe('$log.error', function() {
|
||||
var e, $log, errorArgs;
|
||||
var e, $log;
|
||||
|
||||
function TestError() {
|
||||
Error.prototype.constructor.apply(this, arguments);
|
||||
@@ -148,38 +158,44 @@ describe('$log', function() {
|
||||
TestError.prototype = Object.create(Error.prototype);
|
||||
TestError.prototype.constructor = TestError;
|
||||
|
||||
beforeEach(function() {
|
||||
e = new TestError('');
|
||||
var mockWindow = {
|
||||
console: {
|
||||
error: function() {
|
||||
errorArgs = [].slice.call(arguments, 0);
|
||||
}
|
||||
}
|
||||
};
|
||||
$log = new $LogProvider().$get[1](mockWindow);
|
||||
});
|
||||
beforeEach(inject(
|
||||
function() {
|
||||
e = new TestError('');
|
||||
$window.console = {
|
||||
error: jasmine.createSpy('error')
|
||||
};
|
||||
},
|
||||
|
||||
function(_$log_) {
|
||||
$log = _$log_;
|
||||
}
|
||||
));
|
||||
|
||||
it('should pass error if does not have trace', function() {
|
||||
$log.error('abc', e);
|
||||
expect(errorArgs).toEqual(['abc', e]);
|
||||
});
|
||||
|
||||
|
||||
it('should print stack', function() {
|
||||
e.stack = 'stack';
|
||||
$log.error('abc', e);
|
||||
expect(errorArgs).toEqual(['abc', 'stack']);
|
||||
expect($window.console.error).toHaveBeenCalledWith('abc', e);
|
||||
});
|
||||
|
||||
if (msie || /\bEdge\//.test(window.navigator.userAgent)) {
|
||||
it('should print stack', function() {
|
||||
e.stack = 'stack';
|
||||
$log.error('abc', e);
|
||||
expect($window.console.error).toHaveBeenCalledWith('abc', 'stack');
|
||||
});
|
||||
} else {
|
||||
it('should print a raw error', function() {
|
||||
e.stack = 'stack';
|
||||
$log.error('abc', e);
|
||||
expect($window.console.error).toHaveBeenCalledWith('abc', e);
|
||||
});
|
||||
}
|
||||
|
||||
it('should print line', function() {
|
||||
e.message = 'message';
|
||||
e.sourceURL = 'sourceURL';
|
||||
e.line = '123';
|
||||
$log.error('abc', e);
|
||||
expect(errorArgs).toEqual(['abc', 'message\nsourceURL:123']);
|
||||
expect($window.console.error).toHaveBeenCalledWith('abc', 'message\nsourceURL:123');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -1444,9 +1444,9 @@ describe('Scope', function() {
|
||||
expect(childScope.$$asyncQueue).toBe($rootScope.$$asyncQueue);
|
||||
expect(isolateScope.$$asyncQueue).toBeUndefined();
|
||||
expect($rootScope.$$asyncQueue).toEqual([
|
||||
{scope: $rootScope, expression: $parse('rootExpression'), locals: undefined},
|
||||
{scope: childScope, expression: $parse('childExpression'), locals: undefined},
|
||||
{scope: isolateScope, expression: $parse('isolateExpression'), locals: undefined}
|
||||
{scope: $rootScope, fn: $parse('rootExpression'), locals: undefined},
|
||||
{scope: childScope, fn: $parse('childExpression'), locals: undefined},
|
||||
{scope: isolateScope, fn: $parse('isolateExpression'), locals: undefined}
|
||||
]);
|
||||
}));
|
||||
|
||||
@@ -1499,6 +1499,14 @@ describe('Scope', function() {
|
||||
expect(log).toEqual(['eval-ed 1!', 'eval-ed 2!']);
|
||||
});
|
||||
});
|
||||
|
||||
it('should not pass anything as `this` to scheduled functions', inject(function($rootScope) {
|
||||
var this1 = {};
|
||||
var this2 = (function() { return this; })();
|
||||
$rootScope.$evalAsync(function() { this1 = this; });
|
||||
$rootScope.$digest();
|
||||
expect(this1).toEqual(this2);
|
||||
}));
|
||||
});
|
||||
|
||||
|
||||
|
||||
@@ -255,29 +255,41 @@ describe('animations', function() {
|
||||
});
|
||||
});
|
||||
|
||||
it('should throw a minErr if a regex value is used which partially contains or fully matches the `ng-animate` CSS class', function() {
|
||||
it('should throw a minErr if a regex value is used which partially contains or fully matches the `ng-animate` CSS class',
|
||||
module(function($animateProvider) {
|
||||
assertError(/ng-animate/, true);
|
||||
assertError(/first ng-animate last/, true);
|
||||
assertError(/ng-animate-special/, false);
|
||||
assertError(/first ng-animate-special last/, false);
|
||||
assertError(/first ng-animate ng-animate-special last/, true);
|
||||
expect(setFilter(/ng-animate/)).toThrowMinErr('$animate', 'nongcls');
|
||||
expect(setFilter(/first ng-animate last/)).toThrowMinErr('$animate', 'nongcls');
|
||||
expect(setFilter(/first ng-animate ng-animate-special last/)).toThrowMinErr('$animate', 'nongcls');
|
||||
expect(setFilter(/(ng-animate)/)).toThrowMinErr('$animate', 'nongcls');
|
||||
expect(setFilter(/(foo|ng-animate|bar)/)).toThrowMinErr('$animate', 'nongcls');
|
||||
expect(setFilter(/(foo|)ng-animate(|bar)/)).toThrowMinErr('$animate', 'nongcls');
|
||||
|
||||
function assertError(regex, bool) {
|
||||
var expectation = expect(function() {
|
||||
expect(setFilter(/ng-animater/)).not.toThrow();
|
||||
expect(setFilter(/my-ng-animate/)).not.toThrow();
|
||||
expect(setFilter(/first ng-animater last/)).not.toThrow();
|
||||
expect(setFilter(/first my-ng-animate last/)).not.toThrow();
|
||||
|
||||
function setFilter(regex) {
|
||||
return function() {
|
||||
$animateProvider.classNameFilter(regex);
|
||||
});
|
||||
|
||||
var message = '$animateProvider.classNameFilter(regex) prohibits accepting a regex value which matches/contains the "ng-animate" CSS class.';
|
||||
|
||||
if (bool) {
|
||||
expectation.toThrowMinErr('$animate', 'nongcls', message);
|
||||
} else {
|
||||
expectation.not.toThrowMinErr('$animate', 'nongcls', message);
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
it('should clear the `classNameFilter` if a disallowed RegExp is passed',
|
||||
module(function($animateProvider) {
|
||||
var validRegex = /no-ng-animate/;
|
||||
var invalidRegex = /no ng-animate/;
|
||||
|
||||
$animateProvider.classNameFilter(validRegex);
|
||||
expect($animateProvider.classNameFilter()).toEqual(validRegex);
|
||||
|
||||
// eslint-disable-next-line no-empty
|
||||
try { $animateProvider.classNameFilter(invalidRegex); } catch (err) {}
|
||||
expect($animateProvider.classNameFilter()).toBeNull();
|
||||
})
|
||||
);
|
||||
|
||||
it('should complete the leave DOM operation in case the classNameFilter fails', function() {
|
||||
module(function($animateProvider) {
|
||||
|
||||
Vendored
+1
-1
@@ -923,7 +923,7 @@ describe('ngMock', function() {
|
||||
}));
|
||||
|
||||
describe('error stack trace when called outside of spec context', function() {
|
||||
// - Chrome, Firefox, Edge, Opera give us the stack trace as soon as an Error is created
|
||||
// - Chrome, Firefox, Edge give us the stack trace as soon as an Error is created
|
||||
// - IE10+, PhantomJS give us the stack trace only once the error is thrown
|
||||
// - IE9 does not provide stack traces
|
||||
var stackTraceSupported = (function() {
|
||||
|
||||
@@ -246,6 +246,26 @@ describe('HTML', function() {
|
||||
.toEqual('<p>text1text2</p>');
|
||||
});
|
||||
|
||||
it('should remove clobbered elements', function() {
|
||||
inject(function($sanitize) {
|
||||
expect(function() {
|
||||
$sanitize('<form><input name="parentNode" /></form>');
|
||||
}).toThrowMinErr('$sanitize', 'elclob');
|
||||
|
||||
expect(function() {
|
||||
$sanitize('<form><div><div><input name="parentNode" /></div></div></form>');
|
||||
}).toThrowMinErr('$sanitize', 'elclob');
|
||||
|
||||
expect(function() {
|
||||
$sanitize('<form><input name="nextSibling" /></form>');
|
||||
}).toThrowMinErr('$sanitize', 'elclob');
|
||||
|
||||
expect(function() {
|
||||
$sanitize('<form><div><div><input name="nextSibling" /></div></div></form>');
|
||||
}).toThrowMinErr('$sanitize', 'elclob');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('SVG support', function() {
|
||||
|
||||
|
||||
@@ -12,4 +12,43 @@ describe('toDebugString', function() {
|
||||
expect(toDebugString(a)).toEqual('{"a":"..."}');
|
||||
expect(toDebugString([a,a])).toEqual('[{"a":"..."},"..."]');
|
||||
});
|
||||
|
||||
it('should convert its argument that are objects to string based on maxDepth', function() {
|
||||
var a = {b: {c: {d: 1}}};
|
||||
expect(toDebugString(a, 1)).toEqual('{"b":"..."}');
|
||||
expect(toDebugString(a, 2)).toEqual('{"b":{"c":"..."}}');
|
||||
expect(toDebugString(a, 3)).toEqual('{"b":{"c":{"d":1}}}');
|
||||
});
|
||||
|
||||
they('should convert its argument that object to string and ignore max depth when maxDepth = $prop',
|
||||
[NaN, null, undefined, true, false, -1, 0], function(maxDepth) {
|
||||
var a = {b: {c: {d: 1}}};
|
||||
expect(toDebugString(a, maxDepth)).toEqual('{"b":{"c":{"d":1}}}');
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
describe('serializeObject', function() {
|
||||
it('should convert its argument to a string', function() {
|
||||
expect(serializeObject({a:{b:'c'}})).toEqual('{"a":{"b":"c"}}');
|
||||
|
||||
var a = { };
|
||||
a.a = a;
|
||||
expect(serializeObject(a)).toEqual('{"a":"..."}');
|
||||
expect(serializeObject([a,a])).toEqual('[{"a":"..."},"..."]');
|
||||
});
|
||||
|
||||
it('should convert its argument that are objects to string based on maxDepth', function() {
|
||||
var a = {b: {c: {d: 1}}};
|
||||
expect(serializeObject(a, 1)).toEqual('{"b":"..."}');
|
||||
expect(serializeObject(a, 2)).toEqual('{"b":{"c":"..."}}');
|
||||
expect(serializeObject(a, 3)).toEqual('{"b":{"c":{"d":1}}}');
|
||||
});
|
||||
|
||||
they('should convert its argument that object to string and ignore max depth when maxDepth = $prop',
|
||||
[NaN, null, undefined, true, false, -1, 0], function(maxDepth) {
|
||||
var a = {b: {c: {d: 1}}};
|
||||
expect(serializeObject(a, maxDepth)).toEqual('{"b":{"c":{"d":1}}}');
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
@@ -954,9 +954,9 @@ change-case@3.0.0:
|
||||
upper-case "^1.1.1"
|
||||
upper-case-first "^1.1.0"
|
||||
|
||||
changez-angular@^2.1.2:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/changez-angular/-/changez-angular-2.1.2.tgz#9f32fc5439a949eee426087dd5d108bc4bf6de23"
|
||||
changez-angular@^2.1.3:
|
||||
version "2.1.3"
|
||||
resolved "https://registry.yarnpkg.com/changez-angular/-/changez-angular-2.1.3.tgz#4bf25429baf121818008a1d7b720c72ea7d55c57"
|
||||
dependencies:
|
||||
changez "^2.1.0"
|
||||
nunjucks-date "^1.2.0"
|
||||
@@ -1207,15 +1207,7 @@ concat-map@0.0.1:
|
||||
version "0.0.1"
|
||||
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
|
||||
|
||||
concat-stream@^1.4.6, concat-stream@^1.4.7:
|
||||
version "1.6.0"
|
||||
resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7"
|
||||
dependencies:
|
||||
inherits "^2.0.3"
|
||||
readable-stream "^2.2.2"
|
||||
typedarray "^0.0.6"
|
||||
|
||||
concat-stream@~1.4.1, concat-stream@~1.4.5:
|
||||
concat-stream@^1.4.6, concat-stream@^1.4.7, concat-stream@~1.4.1, concat-stream@~1.4.5:
|
||||
version "1.4.10"
|
||||
resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.4.10.tgz#acc3bbf5602cb8cc980c6ac840fa7d8603e3ef36"
|
||||
dependencies:
|
||||
@@ -2233,7 +2225,7 @@ find-up@^1.0.0:
|
||||
path-exists "^2.0.0"
|
||||
pinkie-promise "^2.0.0"
|
||||
|
||||
findup-sync@0.4.2:
|
||||
findup-sync@0.4.2, findup-sync@^0.4.2:
|
||||
version "0.4.2"
|
||||
resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-0.4.2.tgz#a8117d0f73124f5a4546839579fe52d7129fb5e5"
|
||||
dependencies:
|
||||
@@ -2242,15 +2234,6 @@ findup-sync@0.4.2:
|
||||
micromatch "^2.3.7"
|
||||
resolve-dir "^0.1.0"
|
||||
|
||||
findup-sync@^0.4.2:
|
||||
version "0.4.3"
|
||||
resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-0.4.3.tgz#40043929e7bc60adf0b7f4827c4c6e75a0deca12"
|
||||
dependencies:
|
||||
detect-file "^0.1.0"
|
||||
is-glob "^2.0.1"
|
||||
micromatch "^2.3.7"
|
||||
resolve-dir "^0.1.0"
|
||||
|
||||
findup-sync@~0.3.0:
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-0.3.0.tgz#37930aa5d816b777c03445e1966cc6790a4c0b16"
|
||||
@@ -3110,7 +3093,7 @@ inherits@1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/inherits/-/inherits-1.0.2.tgz#ca4309dadee6b54cc0b8d247e8d7c7a0975bdc9b"
|
||||
|
||||
inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1:
|
||||
inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@~2.0.0, inherits@~2.0.1:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
|
||||
|
||||
@@ -3997,14 +3980,10 @@ lodash@4.16.2:
|
||||
version "4.16.2"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.16.2.tgz#3e626db827048a699281a8a125226326cfc0e652"
|
||||
|
||||
lodash@4.17.2:
|
||||
lodash@4.17.2, lodash@^4.0.0, lodash@^4.13.1, lodash@^4.14.0, lodash@^4.17.2, lodash@^4.3.0, lodash@^4.5.0, lodash@^4.7.0, lodash@^4.8.0:
|
||||
version "4.17.2"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.2.tgz#34a3055babe04ce42467b607d700072c7ff6bf42"
|
||||
|
||||
lodash@^4.0.0, lodash@^4.13.1, lodash@^4.14.0, lodash@^4.17.2, lodash@^4.3.0, lodash@^4.5.0, lodash@^4.7.0, lodash@^4.8.0:
|
||||
version "4.17.4"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae"
|
||||
|
||||
lodash@~1.0.1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-1.0.2.tgz#8f57560c83b59fc270bd3d561b690043430e2551"
|
||||
@@ -5023,14 +5002,10 @@ pump@^0.3.5:
|
||||
end-of-stream "~1.0.0"
|
||||
once "~1.2.0"
|
||||
|
||||
punycode@1.3.2:
|
||||
punycode@1.3.2, punycode@>=0.2.0:
|
||||
version "1.3.2"
|
||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d"
|
||||
|
||||
punycode@>=0.2.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.0.tgz#5f863edc89b96db09074bad7947bf09056ca4e7d"
|
||||
|
||||
punycode@^1.4.1:
|
||||
version "1.4.1"
|
||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
|
||||
@@ -5168,7 +5143,7 @@ read@~1.0.4:
|
||||
dependencies:
|
||||
mute-stream "~0.0.4"
|
||||
|
||||
readable-stream@1.1, "readable-stream@>=1.1.13-1 <1.2.0-0", readable-stream@^1.0.27-1, readable-stream@^1.0.33-1, readable-stream@^1.1.13, readable-stream@^1.1.13-1, readable-stream@~1.1.8, readable-stream@~1.1.9:
|
||||
readable-stream@1.1, "readable-stream@>=1.1.13-1 <1.2.0-0", readable-stream@^1.0.27-1, readable-stream@^1.1.13, readable-stream@^1.1.13-1, readable-stream@~1.1.8, readable-stream@~1.1.9:
|
||||
version "1.1.14"
|
||||
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9"
|
||||
dependencies:
|
||||
@@ -5177,7 +5152,7 @@ readable-stream@1.1, "readable-stream@>=1.1.13-1 <1.2.0-0", readable-stream@^1.0
|
||||
isarray "0.0.1"
|
||||
string_decoder "~0.10.x"
|
||||
|
||||
"readable-stream@>=1.0.33-1 <1.1.0-0", readable-stream@~1.0.0, readable-stream@~1.0.17, readable-stream@~1.0.2, readable-stream@~1.0.26, readable-stream@~1.0.31:
|
||||
"readable-stream@>=1.0.33-1 <1.1.0-0", readable-stream@^1.0.33-1, readable-stream@~1.0.0, readable-stream@~1.0.17, readable-stream@~1.0.2, readable-stream@~1.0.26, readable-stream@~1.0.31:
|
||||
version "1.0.34"
|
||||
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c"
|
||||
dependencies:
|
||||
@@ -5186,7 +5161,7 @@ readable-stream@1.1, "readable-stream@>=1.1.13-1 <1.2.0-0", readable-stream@^1.0
|
||||
isarray "0.0.1"
|
||||
string_decoder "~0.10.x"
|
||||
|
||||
readable-stream@^2.0.0, "readable-stream@^2.0.0 || ^1.1.13", readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.1.5, readable-stream@^2.2.2:
|
||||
readable-stream@^2.0.0, "readable-stream@^2.0.0 || ^1.1.13", readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.1.5:
|
||||
version "2.2.2"
|
||||
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.2.tgz#a9e6fec3c7dda85f8bb1b3ba7028604556fc825e"
|
||||
dependencies:
|
||||
@@ -5541,18 +5516,14 @@ rx-lite@^3.1.2:
|
||||
version "3.1.2"
|
||||
resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102"
|
||||
|
||||
rx@^2.2.27:
|
||||
version "2.5.3"
|
||||
resolved "https://registry.yarnpkg.com/rx/-/rx-2.5.3.tgz#21adc7d80f02002af50dae97fd9dbf248755f566"
|
||||
rx@^2.2.27, rx@~2.3.20:
|
||||
version "2.3.25"
|
||||
resolved "https://registry.yarnpkg.com/rx/-/rx-2.3.25.tgz#2f7c0550532777b41fa692bb790a7886eaff9731"
|
||||
|
||||
rx@^4.1.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782"
|
||||
|
||||
rx@~2.3.20:
|
||||
version "2.3.25"
|
||||
resolved "https://registry.yarnpkg.com/rx/-/rx-2.3.25.tgz#2f7c0550532777b41fa692bb790a7886eaff9731"
|
||||
|
||||
samsam@1.1.2, samsam@~1.1:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/samsam/-/samsam-1.1.2.tgz#bec11fdc83a9fda063401210e40176c3024d1567"
|
||||
@@ -6358,7 +6329,7 @@ type-is@~1.6.13:
|
||||
media-typer "0.3.0"
|
||||
mime-types "~2.1.13"
|
||||
|
||||
typedarray@^0.0.6, typedarray@~0.0.5:
|
||||
typedarray@~0.0.5:
|
||||
version "0.0.6"
|
||||
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user