Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ef6fed3ef8 | |||
| 473dee5786 | |||
| 779e3f6b5f | |||
| 71bca00651 | |||
| 9a9fce0abc | |||
| 939ca37cfe | |||
| 4ae8a2a4b6 | |||
| 113d3954b9 | |||
| 7cb5983750 | |||
| 2b149ca6d4 | |||
| e77866c18c | |||
| 0dc6418d20 | |||
| 837a077578 | |||
| adf91fe6ee | |||
| dea1c0d34c | |||
| f533acc9aa |
+138
@@ -1,3 +1,141 @@
|
||||
<a name="1.4.0-beta.2"></a>
|
||||
# 1.4.0-beta.2 holographic-rooster (2015-01-26)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$location:** don't rewrite when link is shift-clicked
|
||||
([8b33de6f](https://github.com/angular/angular.js/commit/8b33de6fd0ec0eb785fed697f062763b5c1d8d23),
|
||||
[#9904](https://github.com/angular/angular.js/issues/9904), [#9906](https://github.com/angular/angular.js/issues/9906))
|
||||
- **$templateRequest:** cache downloaded templates as strings
|
||||
([b3a9bd3a](https://github.com/angular/angular.js/commit/b3a9bd3ae043e3042ea7ccfe08e3b36a84feb35e),
|
||||
[#10630](https://github.com/angular/angular.js/issues/10630), [#10646](https://github.com/angular/angular.js/issues/10646))
|
||||
- **filterFilter:** throw error if input is not an array
|
||||
([cea8e751](https://github.com/angular/angular.js/commit/cea8e75144e6910b806b63a6ec2a6d118316fddd),
|
||||
[#9992](https://github.com/angular/angular.js/issues/9992), [#10352](https://github.com/angular/angular.js/issues/10352))
|
||||
- **form:** ignore properties in $error prototype chain
|
||||
([31a5b835](https://github.com/angular/angular.js/commit/31a5b8353ae5f1a5cb283322829880995e877833),
|
||||
[#10469](https://github.com/angular/angular.js/issues/10469), [#10727](https://github.com/angular/angular.js/issues/10727))
|
||||
- **htmlAnchorDirective:**
|
||||
- remove "element !== target element" check
|
||||
([2958cd30](https://github.com/angular/angular.js/commit/2958cd308b5ebaf223a3e5df3fb5bf0f23408447),
|
||||
[#10866](https://github.com/angular/angular.js/issues/10866))
|
||||
- don't add event listener if replaced, ignore event if target is different element
|
||||
([b146af11](https://github.com/angular/angular.js/commit/b146af11271de8fa4c51c6db87df104269f41a33),
|
||||
[#4262](https://github.com/angular/angular.js/issues/4262), [#10849](https://github.com/angular/angular.js/issues/10849))
|
||||
- **ngPluralize:** fix wrong text content when count is null/undefined
|
||||
([3228d3b4](https://github.com/angular/angular.js/commit/3228d3b4991af681e57de5ab079c1e1c11cf35cb),
|
||||
[#10836](https://github.com/angular/angular.js/issues/10836), [#10841](https://github.com/angular/angular.js/issues/10841))
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
- **filterFilter:** due to [cea8e751](https://github.com/angular/angular.js/commit/cea8e75144e6910b806b63a6ec2a6d118316fddd),
|
||||
Previously, the filter was not applied if used with a non array.
|
||||
Now, it throws an error. This can be worked around by converting an object to an array, using
|
||||
a filter such as https://github.com/petebacondarwin/angular-toArrayFilter
|
||||
|
||||
Closes #9992
|
||||
Closes #10352
|
||||
|
||||
|
||||
<a name="1.3.11"></a>
|
||||
# 1.3.11 spiffy-manatee (2015-01-26)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$location:** don't rewrite when link is shift-clicked
|
||||
([939ca37c](https://github.com/angular/angular.js/commit/939ca37cfe5f6fc35b09b6705caabd1fcc3cf9d3),
|
||||
[#9904](https://github.com/angular/angular.js/issues/9904), [#9906](https://github.com/angular/angular.js/issues/9906))
|
||||
- **form:** ignore properties in $error prototype chain
|
||||
([adf91fe6](https://github.com/angular/angular.js/commit/adf91fe6ee77a84e8159c9a95e36f65276fe67bd),
|
||||
[#10469](https://github.com/angular/angular.js/issues/10469), [#10727](https://github.com/angular/angular.js/issues/10727))
|
||||
- **htmlAnchorDirective:**
|
||||
- remove "element !== target element" check
|
||||
([779e3f6b](https://github.com/angular/angular.js/commit/779e3f6b5f8d2550e758cb0c5f64187ba8e00e29),
|
||||
[#10866](https://github.com/angular/angular.js/issues/10866))
|
||||
- don't add event listener if replaced, ignore event if target is different element
|
||||
([837a0775](https://github.com/angular/angular.js/commit/837a077578081bbd07863bef85241537d19fa652),
|
||||
[#4262](https://github.com/angular/angular.js/issues/4262), [#10849](https://github.com/angular/angular.js/issues/10849))
|
||||
|
||||
|
||||
<a name="1.4.0-beta.1"></a>
|
||||
# 1.4.0-beta.1 trepidatious-salamander (2015-01-20)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$animate:** ensure no transitions are applied when an empty inline style object is provided
|
||||
([0db5b21b](https://github.com/angular/angular.js/commit/0db5b21b1d09431535e0c0bf8ac63d4b5b24d349),
|
||||
[#10613](https://github.com/angular/angular.js/issues/10613), [#10770](https://github.com/angular/angular.js/issues/10770))
|
||||
- **$compile:** support class directives on SVG elements
|
||||
([23c8a90d](https://github.com/angular/angular.js/commit/23c8a90d22f7c7b41b5a756b89498ffac828980a),
|
||||
[#10736](https://github.com/angular/angular.js/issues/10736), [#10756](https://github.com/angular/angular.js/issues/10756))
|
||||
- **form:** clean up success state of controls when they are removed
|
||||
([2408f2de](https://github.com/angular/angular.js/commit/2408f2ded5ead6e678c241e38ef474c1fadff92b),
|
||||
[#10509](https://github.com/angular/angular.js/issues/10509))
|
||||
- **ngController:** allow bound constructor fns as controllers
|
||||
([d17fbc38](https://github.com/angular/angular.js/commit/d17fbc3862e0a2e646db1222f184dbe663da4a1f),
|
||||
[#10784](https://github.com/angular/angular.js/issues/10784), [#10790](https://github.com/angular/angular.js/issues/10790))
|
||||
- **ngRepeat:** do not sort object keys alphabetically
|
||||
([c260e738](https://github.com/angular/angular.js/commit/c260e7386391877625eda086480de73e8a0ba921),
|
||||
[#6210](https://github.com/angular/angular.js/issues/6210), [#10538](https://github.com/angular/angular.js/issues/10538))
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
- **$http:** provide a config object as an argument to header functions
|
||||
([d435464c](https://github.com/angular/angular.js/commit/d435464c51d3912f56cfc830d86bfc64a1578327),
|
||||
[#7235](https://github.com/angular/angular.js/issues/7235), [#10622](https://github.com/angular/angular.js/issues/10622))
|
||||
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
- **ngRepeat:** due to [c260e738](https://github.com/angular/angular.js/commit/c260e7386391877625eda086480de73e8a0ba921),
|
||||
|
||||
|
||||
Previously, the order of items when using ngRepeat to iterate
|
||||
over object properties was guaranteed to be consistent by sorting the
|
||||
keys into alphabetic order.
|
||||
|
||||
Now, the order of the items is browser dependent based on the order returned
|
||||
from iterating over the object using the `for key in obj` syntax.
|
||||
|
||||
It seems that browsers generally follow the strategy of providing
|
||||
keys in the order in which they were defined, although there are exceptions
|
||||
when keys are deleted and reinstated. See
|
||||
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/delete#Cross-browser_issues
|
||||
|
||||
The best approach is to convert Objects into Arrays by a filter such as
|
||||
https://github.com/petebacondarwin/angular-toArrayFilter
|
||||
or some other mechanism, and then sort them manually in the order you need.
|
||||
|
||||
Closes #6210
|
||||
Closes #10538
|
||||
|
||||
|
||||
|
||||
<a name="1.3.10"></a>
|
||||
# 1.3.10 heliotropic-sundial (2015-01-20)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$animate:** ensure no transitions are applied when an empty inline style object is provided
|
||||
([9b8df52a](https://github.com/angular/angular.js/commit/9b8df52aa960b9b6288fc150d55ea2e35f56555e),
|
||||
[#10613](https://github.com/angular/angular.js/issues/10613), [#10770](https://github.com/angular/angular.js/issues/10770))
|
||||
- **$compile:** support class directives on SVG elements
|
||||
([7a9e3360](https://github.com/angular/angular.js/commit/7a9e3360284d58197a1fe34de57f5e0f6d1f4a76),
|
||||
[#10736](https://github.com/angular/angular.js/issues/10736), [#10756](https://github.com/angular/angular.js/issues/10756))
|
||||
- **form:** clean up success state of controls when they are removed
|
||||
([cdc7280d](https://github.com/angular/angular.js/commit/cdc7280dd3d5a2ded784c06dd55fe36c2053fb6f),
|
||||
[#10509](https://github.com/angular/angular.js/issues/10509))
|
||||
- **ngController:** allow bound constructor fns as controllers
|
||||
([d015c8a8](https://github.com/angular/angular.js/commit/d015c8a80b28754633c846fc50d11c9437519486),
|
||||
[#10784](https://github.com/angular/angular.js/issues/10784), [#10790](https://github.com/angular/angular.js/issues/10790))
|
||||
|
||||
|
||||
|
||||
<a name="1.4.0-beta.0"></a>
|
||||
# 1.4.0-beta.0 photonic-umbrakinesis (2015-01-13)
|
||||
|
||||
|
||||
+2
-2
@@ -316,9 +316,9 @@ module.exports = function(grunt) {
|
||||
grunt.registerTask('test', 'Run unit, docs and e2e tests with Karma', ['jshint', 'jscs', 'package','test:unit','test:promises-aplus', 'tests:docs', 'test:protractor']);
|
||||
grunt.registerTask('test:jqlite', 'Run the unit tests with Karma' , ['tests:jqlite']);
|
||||
grunt.registerTask('test:jquery', 'Run the jQuery unit tests with Karma', ['tests:jquery']);
|
||||
grunt.registerTask('test:modules', 'Run the Karma module tests with Karma', ['tests:modules']);
|
||||
grunt.registerTask('test:modules', 'Run the Karma module tests with Karma', ['build', 'tests:modules']);
|
||||
grunt.registerTask('test:docs', 'Run the doc-page tests with Karma', ['package', 'tests:docs']);
|
||||
grunt.registerTask('test:unit', 'Run unit, jQuery and Karma module tests with Karma', ['tests:jqlite', 'tests:jquery', 'tests:modules']);
|
||||
grunt.registerTask('test:unit', 'Run unit, jQuery and Karma module tests with Karma', ['test:jqlite', 'test:jquery', 'test:modules']);
|
||||
grunt.registerTask('test:protractor', 'Run the end to end tests with Protractor and keep a test server running in the background', ['webdriver', 'connect:testserver', 'protractor:normal']);
|
||||
grunt.registerTask('test:travis-protractor', 'Run the end to end tests with Protractor for Travis CI builds', ['connect:testserver', 'protractor:travis']);
|
||||
grunt.registerTask('test:ci-protractor', 'Run the end to end tests with Protractor for Jenkins CI builds', ['webdriver', 'connect:testserver', 'protractor:jenkins']);
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
angular.module('examples', [])
|
||||
|
||||
.factory('formPostData', ['$document', function($document) {
|
||||
return function(url, fields) {
|
||||
return function(url, newWindow, fields) {
|
||||
/**
|
||||
* Form previously posted to target="_blank", but pop-up blockers were causing this to not work.
|
||||
* If a user chose to bypass pop-up blocker one time and click the link, they would arrive at
|
||||
* a new default plnkr, not a plnkr with the desired template.
|
||||
* If the form posts to target="_blank", pop-up blockers can cause it not to work.
|
||||
* If a user choses to bypass pop-up blocker one time and click the link, they will arrive at
|
||||
* a new default plnkr, not a plnkr with the desired template. Given this undesired behavior,
|
||||
* some may still want to open the plnk in a new window by opting-in via ctrl+click. The
|
||||
* newWindow param allows for this possibility.
|
||||
*/
|
||||
var form = angular.element('<form style="display: none;" method="post" action="' + url + '"></form>');
|
||||
var target = newWindow ? '_blank' : '_self';
|
||||
var form = angular.element('<form style="display: none;" method="post" action="' + url + '" target="' + target + '"></form>');
|
||||
angular.forEach(fields, function(value, name) {
|
||||
var input = angular.element('<input type="hidden" name="' + name + '">');
|
||||
input.attr('value', value);
|
||||
@@ -21,9 +24,10 @@ angular.module('examples', [])
|
||||
|
||||
|
||||
.factory('openPlunkr', ['formPostData', '$http', '$q', function(formPostData, $http, $q) {
|
||||
return function(exampleFolder) {
|
||||
return function(exampleFolder, clickEvent) {
|
||||
|
||||
var exampleName = 'AngularJS Example';
|
||||
var newWindow = clickEvent.ctrlKey || clickEvent.metaKey;
|
||||
|
||||
// Load the manifest for the example
|
||||
$http.get(exampleFolder + '/manifest.json')
|
||||
@@ -71,7 +75,7 @@ angular.module('examples', [])
|
||||
postData.private = true;
|
||||
postData.description = exampleName;
|
||||
|
||||
formPostData('http://plnkr.co/edit/?p=preview', postData);
|
||||
formPostData('http://plnkr.co/edit/?p=preview', newWindow, postData);
|
||||
});
|
||||
};
|
||||
}]);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
is HTML and wrap each line in a <p> - thus breaking the HTML #}
|
||||
|
||||
<div>
|
||||
<a ng-click="openPlunkr('{$ doc.path $}')" class="btn pull-right">
|
||||
<a ng-click="openPlunkr('{$ doc.path $}', $event)" class="btn pull-right">
|
||||
<i class="glyphicon glyphicon-edit"> </i>
|
||||
Edit in Plunker</a>
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ succinctly. Angular's data binding and dependency injection eliminate much of th
|
||||
would otherwise have to write. And it all happens within the browser, making it
|
||||
an ideal partner with any server technology.
|
||||
|
||||
Angular is what HTML would have been had it been designed for applications. HTML is a great
|
||||
Angular is what HTML would have been, had it been designed for applications. HTML is a great
|
||||
declarative language for static documents. It does not contain much in the way of creating
|
||||
applications, and as a result building web applications is an exercise in *what do I have to do
|
||||
to trick the browser into doing what I want?*
|
||||
@@ -28,10 +28,10 @@ The impedance mismatch between dynamic applications and static documents is ofte
|
||||
|
||||
Angular takes another approach. It attempts to minimize the impedance mismatch between document
|
||||
centric HTML and what an application needs by creating new HTML constructs. Angular teaches the
|
||||
browser new syntax through a construct we call directives. Examples include:
|
||||
browser new syntax through a construct we call *directives*. Examples include:
|
||||
|
||||
* Data binding, as in `{{}}`.
|
||||
* DOM control structures for repeating/hiding DOM fragments.
|
||||
* DOM control structures for repeating, showing and hiding DOM fragments.
|
||||
* Support for forms and form validation.
|
||||
* Attaching new behavior to DOM elements, such as DOM event handling.
|
||||
* Grouping of HTML into reusable components.
|
||||
@@ -42,20 +42,20 @@ browser new syntax through a construct we call directives. Examples include:
|
||||
|
||||
Angular is not a single piece in the overall puzzle of building the client-side of a web
|
||||
application. It handles all of the DOM and AJAX glue code you once wrote by hand and puts it in a
|
||||
well-defined structure. This makes Angular opinionated about how a CRUD application should be
|
||||
built. But while it is opinionated, it also tries to make sure that its opinion is just a
|
||||
starting point you can easily change. Angular comes with the following out-of-the-box:
|
||||
well-defined structure. This makes Angular opinionated about how a CRUD (Create, Read, Update, Delete)
|
||||
application should be built. But while it is opinionated, it also tries to make sure that its opinion
|
||||
is just a starting point you can easily change. Angular comes with the following out-of-the-box:
|
||||
|
||||
* Everything you need to build a CRUD app in a cohesive set: data-binding, basic templating
|
||||
directives, form validation, routing, deep-linking, reusable components, dependency injection.
|
||||
* Testability story: unit-testing, end-to-end testing, mocks, test harnesses.
|
||||
* Everything you need to build a CRUD app in a cohesive set: Data-binding, basic templating
|
||||
directives, form validation, routing, deep-linking, reusable components and dependency injection.
|
||||
* Testability story: Unit-testing, end-to-end testing, mocks and test harnesses.
|
||||
* Seed application with directory layout and test scripts as a starting point.
|
||||
|
||||
|
||||
## Angular Sweet Spot
|
||||
## Angular's sweet spot
|
||||
|
||||
Angular simplifies application development by presenting a higher level of abstraction to the
|
||||
developer. Like any abstraction, it comes at a cost of flexibility. In other words not every app
|
||||
developer. Like any abstraction, it comes at a cost of flexibility. In other words, not every app
|
||||
is a good fit for Angular. Angular was built with the CRUD application in mind. Luckily CRUD
|
||||
applications represent the majority of web applications. To understand what Angular is
|
||||
good at, though, it helps to understand when an app is not a good fit for Angular.
|
||||
@@ -78,7 +78,7 @@ expressing business logic.
|
||||
* It is an excellent idea to decouple the client side of an app from the server side. This
|
||||
allows development work to progress in parallel, and allows for reuse of both sides.
|
||||
* It is very helpful indeed if the framework guides developers through the entire journey of
|
||||
building an app: from designing the UI, through writing the business logic, to testing.
|
||||
building an app: From designing the UI, through writing the business logic, to testing.
|
||||
* It is always good to make common tasks trivial and difficult tasks possible.
|
||||
|
||||
|
||||
|
||||
@@ -18,6 +18,9 @@ var htmlAnchorDirective = valueFn({
|
||||
compile: function(element, attr) {
|
||||
if (!attr.href && !attr.xlinkHref && !attr.name) {
|
||||
return function(scope, element) {
|
||||
// If the linked element is not an anchor tag anymore, do nothing
|
||||
if (element[0].nodeName.toLowerCase() !== 'a') return;
|
||||
|
||||
// SVGAElement does not use the href attribute, but rather the 'xlinkHref' attribute.
|
||||
var href = toString.call(element.prop('href')) === '[object SVGAnimatedString]' ?
|
||||
'xlink:href' : 'href';
|
||||
|
||||
+87
-65
@@ -61,19 +61,21 @@ var inputType = {
|
||||
<script>
|
||||
angular.module('textInputExample', [])
|
||||
.controller('ExampleController', ['$scope', function($scope) {
|
||||
$scope.text = 'guest';
|
||||
$scope.word = /^\s*\w*\s*$/;
|
||||
$scope.example = {
|
||||
text: 'guest',
|
||||
word: /^\s*\w*\s*$/
|
||||
};
|
||||
}]);
|
||||
</script>
|
||||
<form name="myForm" ng-controller="ExampleController">
|
||||
Single word: <input type="text" name="input" ng-model="text"
|
||||
ng-pattern="word" required ng-trim="false">
|
||||
Single word: <input type="text" name="input" ng-model="example.text"
|
||||
ng-pattern="example.word" required ng-trim="false">
|
||||
<span class="error" ng-show="myForm.input.$error.required">
|
||||
Required!</span>
|
||||
<span class="error" ng-show="myForm.input.$error.pattern">
|
||||
Single word only!</span>
|
||||
|
||||
<tt>text = {{text}}</tt><br/>
|
||||
<tt>text = {{example.text}}</tt><br/>
|
||||
<tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
|
||||
<tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
|
||||
<tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
|
||||
@@ -81,9 +83,9 @@ var inputType = {
|
||||
</form>
|
||||
</file>
|
||||
<file name="protractor.js" type="protractor">
|
||||
var text = element(by.binding('text'));
|
||||
var text = element(by.binding('example.text'));
|
||||
var valid = element(by.binding('myForm.input.$valid'));
|
||||
var input = element(by.model('text'));
|
||||
var input = element(by.model('example.text'));
|
||||
|
||||
it('should initialize to model', function() {
|
||||
expect(text.getText()).toContain('guest');
|
||||
@@ -145,18 +147,20 @@ var inputType = {
|
||||
<script>
|
||||
angular.module('dateInputExample', [])
|
||||
.controller('DateController', ['$scope', function($scope) {
|
||||
$scope.value = new Date(2013, 9, 22);
|
||||
$scope.example = {
|
||||
value: new Date(2013, 9, 22)
|
||||
};
|
||||
}]);
|
||||
</script>
|
||||
<form name="myForm" ng-controller="DateController as dateCtrl">
|
||||
Pick a date in 2013:
|
||||
<input type="date" id="exampleInput" name="input" ng-model="value"
|
||||
<input type="date" id="exampleInput" name="input" ng-model="example.value"
|
||||
placeholder="yyyy-MM-dd" min="2013-01-01" max="2013-12-31" required />
|
||||
<span class="error" ng-show="myForm.input.$error.required">
|
||||
Required!</span>
|
||||
<span class="error" ng-show="myForm.input.$error.date">
|
||||
Not a valid date!</span>
|
||||
<tt>value = {{value | date: "yyyy-MM-dd"}}</tt><br/>
|
||||
<tt>value = {{example.value | date: "yyyy-MM-dd"}}</tt><br/>
|
||||
<tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
|
||||
<tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
|
||||
<tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
|
||||
@@ -164,9 +168,9 @@ var inputType = {
|
||||
</form>
|
||||
</file>
|
||||
<file name="protractor.js" type="protractor">
|
||||
var value = element(by.binding('value | date: "yyyy-MM-dd"'));
|
||||
var value = element(by.binding('example.value | date: "yyyy-MM-dd"'));
|
||||
var valid = element(by.binding('myForm.input.$valid'));
|
||||
var input = element(by.model('value'));
|
||||
var input = element(by.model('example.value'));
|
||||
|
||||
// currently protractor/webdriver does not support
|
||||
// sending keys to all known HTML5 input controls
|
||||
@@ -236,18 +240,20 @@ var inputType = {
|
||||
<script>
|
||||
angular.module('dateExample', [])
|
||||
.controller('DateController', ['$scope', function($scope) {
|
||||
$scope.value = new Date(2010, 11, 28, 14, 57);
|
||||
$scope.example = {
|
||||
value: new Date(2010, 11, 28, 14, 57)
|
||||
};
|
||||
}]);
|
||||
</script>
|
||||
<form name="myForm" ng-controller="DateController as dateCtrl">
|
||||
Pick a date between in 2013:
|
||||
<input type="datetime-local" id="exampleInput" name="input" ng-model="value"
|
||||
<input type="datetime-local" id="exampleInput" name="input" ng-model="example.value"
|
||||
placeholder="yyyy-MM-ddTHH:mm:ss" min="2001-01-01T00:00:00" max="2013-12-31T00:00:00" required />
|
||||
<span class="error" ng-show="myForm.input.$error.required">
|
||||
Required!</span>
|
||||
<span class="error" ng-show="myForm.input.$error.datetimelocal">
|
||||
Not a valid date!</span>
|
||||
<tt>value = {{value | date: "yyyy-MM-ddTHH:mm:ss"}}</tt><br/>
|
||||
<tt>value = {{example.value | date: "yyyy-MM-ddTHH:mm:ss"}}</tt><br/>
|
||||
<tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
|
||||
<tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
|
||||
<tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
|
||||
@@ -255,9 +261,9 @@ var inputType = {
|
||||
</form>
|
||||
</file>
|
||||
<file name="protractor.js" type="protractor">
|
||||
var value = element(by.binding('value | date: "yyyy-MM-ddTHH:mm:ss"'));
|
||||
var value = element(by.binding('example.value | date: "yyyy-MM-ddTHH:mm:ss"'));
|
||||
var valid = element(by.binding('myForm.input.$valid'));
|
||||
var input = element(by.model('value'));
|
||||
var input = element(by.model('example.value'));
|
||||
|
||||
// currently protractor/webdriver does not support
|
||||
// sending keys to all known HTML5 input controls
|
||||
@@ -328,18 +334,20 @@ var inputType = {
|
||||
<script>
|
||||
angular.module('timeExample', [])
|
||||
.controller('DateController', ['$scope', function($scope) {
|
||||
$scope.value = new Date(1970, 0, 1, 14, 57, 0);
|
||||
$scope.example = {
|
||||
value: new Date(1970, 0, 1, 14, 57, 0)
|
||||
};
|
||||
}]);
|
||||
</script>
|
||||
<form name="myForm" ng-controller="DateController as dateCtrl">
|
||||
Pick a between 8am and 5pm:
|
||||
<input type="time" id="exampleInput" name="input" ng-model="value"
|
||||
<input type="time" id="exampleInput" name="input" ng-model="example.value"
|
||||
placeholder="HH:mm:ss" min="08:00:00" max="17:00:00" required />
|
||||
<span class="error" ng-show="myForm.input.$error.required">
|
||||
Required!</span>
|
||||
<span class="error" ng-show="myForm.input.$error.time">
|
||||
Not a valid date!</span>
|
||||
<tt>value = {{value | date: "HH:mm:ss"}}</tt><br/>
|
||||
<tt>value = {{example.value | date: "HH:mm:ss"}}</tt><br/>
|
||||
<tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
|
||||
<tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
|
||||
<tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
|
||||
@@ -347,9 +355,9 @@ var inputType = {
|
||||
</form>
|
||||
</file>
|
||||
<file name="protractor.js" type="protractor">
|
||||
var value = element(by.binding('value | date: "HH:mm:ss"'));
|
||||
var value = element(by.binding('example.value | date: "HH:mm:ss"'));
|
||||
var valid = element(by.binding('myForm.input.$valid'));
|
||||
var input = element(by.model('value'));
|
||||
var input = element(by.model('example.value'));
|
||||
|
||||
// currently protractor/webdriver does not support
|
||||
// sending keys to all known HTML5 input controls
|
||||
@@ -419,18 +427,20 @@ var inputType = {
|
||||
<script>
|
||||
angular.module('weekExample', [])
|
||||
.controller('DateController', ['$scope', function($scope) {
|
||||
$scope.value = new Date(2013, 0, 3);
|
||||
$scope.example = {
|
||||
value: new Date(2013, 0, 3)
|
||||
};
|
||||
}]);
|
||||
</script>
|
||||
<form name="myForm" ng-controller="DateController as dateCtrl">
|
||||
Pick a date between in 2013:
|
||||
<input id="exampleInput" type="week" name="input" ng-model="value"
|
||||
<input id="exampleInput" type="week" name="input" ng-model="example.value"
|
||||
placeholder="YYYY-W##" min="2012-W32" max="2013-W52" required />
|
||||
<span class="error" ng-show="myForm.input.$error.required">
|
||||
Required!</span>
|
||||
<span class="error" ng-show="myForm.input.$error.week">
|
||||
Not a valid date!</span>
|
||||
<tt>value = {{value | date: "yyyy-Www"}}</tt><br/>
|
||||
<tt>value = {{example.value | date: "yyyy-Www"}}</tt><br/>
|
||||
<tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
|
||||
<tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
|
||||
<tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
|
||||
@@ -438,9 +448,9 @@ var inputType = {
|
||||
</form>
|
||||
</file>
|
||||
<file name="protractor.js" type="protractor">
|
||||
var value = element(by.binding('value | date: "yyyy-Www"'));
|
||||
var value = element(by.binding('example.value | date: "yyyy-Www"'));
|
||||
var valid = element(by.binding('myForm.input.$valid'));
|
||||
var input = element(by.model('value'));
|
||||
var input = element(by.model('example.value'));
|
||||
|
||||
// currently protractor/webdriver does not support
|
||||
// sending keys to all known HTML5 input controls
|
||||
@@ -510,18 +520,20 @@ var inputType = {
|
||||
<script>
|
||||
angular.module('monthExample', [])
|
||||
.controller('DateController', ['$scope', function($scope) {
|
||||
$scope.value = new Date(2013, 9, 1);
|
||||
$scope.example = {
|
||||
value: new Date(2013, 9, 1)
|
||||
};
|
||||
}]);
|
||||
</script>
|
||||
<form name="myForm" ng-controller="DateController as dateCtrl">
|
||||
Pick a month int 2013:
|
||||
<input id="exampleInput" type="month" name="input" ng-model="value"
|
||||
Pick a month in 2013:
|
||||
<input id="exampleInput" type="month" name="input" ng-model="example.value"
|
||||
placeholder="yyyy-MM" min="2013-01" max="2013-12" required />
|
||||
<span class="error" ng-show="myForm.input.$error.required">
|
||||
Required!</span>
|
||||
<span class="error" ng-show="myForm.input.$error.month">
|
||||
Not a valid month!</span>
|
||||
<tt>value = {{value | date: "yyyy-MM"}}</tt><br/>
|
||||
<tt>value = {{example.value | date: "yyyy-MM"}}</tt><br/>
|
||||
<tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
|
||||
<tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
|
||||
<tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
|
||||
@@ -529,9 +541,9 @@ var inputType = {
|
||||
</form>
|
||||
</file>
|
||||
<file name="protractor.js" type="protractor">
|
||||
var value = element(by.binding('value | date: "yyyy-MM"'));
|
||||
var value = element(by.binding('example.value | date: "yyyy-MM"'));
|
||||
var valid = element(by.binding('myForm.input.$valid'));
|
||||
var input = element(by.model('value'));
|
||||
var input = element(by.model('example.value'));
|
||||
|
||||
// currently protractor/webdriver does not support
|
||||
// sending keys to all known HTML5 input controls
|
||||
@@ -607,17 +619,19 @@ var inputType = {
|
||||
<script>
|
||||
angular.module('numberExample', [])
|
||||
.controller('ExampleController', ['$scope', function($scope) {
|
||||
$scope.value = 12;
|
||||
$scope.example = {
|
||||
value: 12
|
||||
};
|
||||
}]);
|
||||
</script>
|
||||
<form name="myForm" ng-controller="ExampleController">
|
||||
Number: <input type="number" name="input" ng-model="value"
|
||||
Number: <input type="number" name="input" ng-model="example.value"
|
||||
min="0" max="99" required>
|
||||
<span class="error" ng-show="myForm.input.$error.required">
|
||||
Required!</span>
|
||||
<span class="error" ng-show="myForm.input.$error.number">
|
||||
Not valid number!</span>
|
||||
<tt>value = {{value}}</tt><br/>
|
||||
<tt>value = {{example.value}}</tt><br/>
|
||||
<tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
|
||||
<tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
|
||||
<tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
|
||||
@@ -625,9 +639,9 @@ var inputType = {
|
||||
</form>
|
||||
</file>
|
||||
<file name="protractor.js" type="protractor">
|
||||
var value = element(by.binding('value'));
|
||||
var value = element(by.binding('example.value'));
|
||||
var valid = element(by.binding('myForm.input.$valid'));
|
||||
var input = element(by.model('value'));
|
||||
var input = element(by.model('example.value'));
|
||||
|
||||
it('should initialize to model', function() {
|
||||
expect(value.getText()).toContain('12');
|
||||
@@ -695,16 +709,18 @@ var inputType = {
|
||||
<script>
|
||||
angular.module('urlExample', [])
|
||||
.controller('ExampleController', ['$scope', function($scope) {
|
||||
$scope.text = 'http://google.com';
|
||||
$scope.url = {
|
||||
text: 'http://google.com'
|
||||
};
|
||||
}]);
|
||||
</script>
|
||||
<form name="myForm" ng-controller="ExampleController">
|
||||
URL: <input type="url" name="input" ng-model="text" required>
|
||||
URL: <input type="url" name="input" ng-model="url.text" required>
|
||||
<span class="error" ng-show="myForm.input.$error.required">
|
||||
Required!</span>
|
||||
<span class="error" ng-show="myForm.input.$error.url">
|
||||
Not valid url!</span>
|
||||
<tt>text = {{text}}</tt><br/>
|
||||
<tt>text = {{url.text}}</tt><br/>
|
||||
<tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
|
||||
<tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
|
||||
<tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
|
||||
@@ -713,9 +729,9 @@ var inputType = {
|
||||
</form>
|
||||
</file>
|
||||
<file name="protractor.js" type="protractor">
|
||||
var text = element(by.binding('text'));
|
||||
var text = element(by.binding('url.text'));
|
||||
var valid = element(by.binding('myForm.input.$valid'));
|
||||
var input = element(by.model('text'));
|
||||
var input = element(by.model('url.text'));
|
||||
|
||||
it('should initialize to model', function() {
|
||||
expect(text.getText()).toContain('http://google.com');
|
||||
@@ -784,16 +800,18 @@ var inputType = {
|
||||
<script>
|
||||
angular.module('emailExample', [])
|
||||
.controller('ExampleController', ['$scope', function($scope) {
|
||||
$scope.text = 'me@example.com';
|
||||
$scope.email = {
|
||||
text: 'me@example.com'
|
||||
};
|
||||
}]);
|
||||
</script>
|
||||
<form name="myForm" ng-controller="ExampleController">
|
||||
Email: <input type="email" name="input" ng-model="text" required>
|
||||
Email: <input type="email" name="input" ng-model="email.text" required>
|
||||
<span class="error" ng-show="myForm.input.$error.required">
|
||||
Required!</span>
|
||||
<span class="error" ng-show="myForm.input.$error.email">
|
||||
Not valid email!</span>
|
||||
<tt>text = {{text}}</tt><br/>
|
||||
<tt>text = {{email.text}}</tt><br/>
|
||||
<tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
|
||||
<tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
|
||||
<tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
|
||||
@@ -802,9 +820,9 @@ var inputType = {
|
||||
</form>
|
||||
</file>
|
||||
<file name="protractor.js" type="protractor">
|
||||
var text = element(by.binding('text'));
|
||||
var text = element(by.binding('email.text'));
|
||||
var valid = element(by.binding('myForm.input.$valid'));
|
||||
var input = element(by.model('text'));
|
||||
var input = element(by.model('email.text'));
|
||||
|
||||
it('should initialize to model', function() {
|
||||
expect(text.getText()).toContain('me@example.com');
|
||||
@@ -851,7 +869,9 @@ var inputType = {
|
||||
<script>
|
||||
angular.module('radioExample', [])
|
||||
.controller('ExampleController', ['$scope', function($scope) {
|
||||
$scope.color = 'blue';
|
||||
$scope.color = {
|
||||
name: 'blue'
|
||||
};
|
||||
$scope.specialValue = {
|
||||
"id": "12345",
|
||||
"value": "green"
|
||||
@@ -859,20 +879,20 @@ var inputType = {
|
||||
}]);
|
||||
</script>
|
||||
<form name="myForm" ng-controller="ExampleController">
|
||||
<input type="radio" ng-model="color" value="red"> Red <br/>
|
||||
<input type="radio" ng-model="color" ng-value="specialValue"> Green <br/>
|
||||
<input type="radio" ng-model="color" value="blue"> Blue <br/>
|
||||
<tt>color = {{color | json}}</tt><br/>
|
||||
<input type="radio" ng-model="color.name" value="red"> Red <br/>
|
||||
<input type="radio" ng-model="color.name" ng-value="specialValue"> Green <br/>
|
||||
<input type="radio" ng-model="color.name" value="blue"> Blue <br/>
|
||||
<tt>color = {{color.name | json}}</tt><br/>
|
||||
</form>
|
||||
Note that `ng-value="specialValue"` sets radio item's value to be the value of `$scope.specialValue`.
|
||||
</file>
|
||||
<file name="protractor.js" type="protractor">
|
||||
it('should change state', function() {
|
||||
var color = element(by.binding('color'));
|
||||
var color = element(by.binding('color.name'));
|
||||
|
||||
expect(color.getText()).toContain('blue');
|
||||
|
||||
element.all(by.model('color')).get(0).click();
|
||||
element.all(by.model('color.name')).get(0).click();
|
||||
|
||||
expect(color.getText()).toContain('red');
|
||||
});
|
||||
@@ -902,28 +922,30 @@ var inputType = {
|
||||
<script>
|
||||
angular.module('checkboxExample', [])
|
||||
.controller('ExampleController', ['$scope', function($scope) {
|
||||
$scope.value1 = true;
|
||||
$scope.value2 = 'YES'
|
||||
$scope.checkboxModel = {
|
||||
value1 : true,
|
||||
value2 : 'YES'
|
||||
};
|
||||
}]);
|
||||
</script>
|
||||
<form name="myForm" ng-controller="ExampleController">
|
||||
Value1: <input type="checkbox" ng-model="value1"> <br/>
|
||||
Value2: <input type="checkbox" ng-model="value2"
|
||||
Value1: <input type="checkbox" ng-model="checkboxModel.value1"> <br/>
|
||||
Value2: <input type="checkbox" ng-model="checkboxModel.value2"
|
||||
ng-true-value="'YES'" ng-false-value="'NO'"> <br/>
|
||||
<tt>value1 = {{value1}}</tt><br/>
|
||||
<tt>value2 = {{value2}}</tt><br/>
|
||||
<tt>value1 = {{checkboxModel.value1}}</tt><br/>
|
||||
<tt>value2 = {{checkboxModel.value2}}</tt><br/>
|
||||
</form>
|
||||
</file>
|
||||
<file name="protractor.js" type="protractor">
|
||||
it('should change state', function() {
|
||||
var value1 = element(by.binding('value1'));
|
||||
var value2 = element(by.binding('value2'));
|
||||
var value1 = element(by.binding('checkboxModel.value1'));
|
||||
var value2 = element(by.binding('checkboxModel.value2'));
|
||||
|
||||
expect(value1.getText()).toContain('true');
|
||||
expect(value2.getText()).toContain('YES');
|
||||
|
||||
element(by.model('value1')).click();
|
||||
element(by.model('value2')).click();
|
||||
element(by.model('checkboxModel.value1')).click();
|
||||
element(by.model('checkboxModel.value2')).click();
|
||||
|
||||
expect(value1.getText()).toContain('false');
|
||||
expect(value2.getText()).toContain('NO');
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
* **Note**: If you have assignment in `ngInit` along with {@link ng.$filter `$filter`}, make
|
||||
* sure you have parenthesis for correct precedence:
|
||||
* <pre class="prettyprint">
|
||||
* <div ng-init="test1 = (data | orderBy:'name')"></div>
|
||||
* `<div ng-init="test1 = (data | orderBy:'name')"></div>`
|
||||
* </pre>
|
||||
* </div>
|
||||
*
|
||||
|
||||
+1
-1
@@ -837,7 +837,7 @@ function $LocationProvider() {
|
||||
// TODO(vojta): rewrite link when opening in new tab/window (in legacy browser)
|
||||
// currently we open nice url link and redirect then
|
||||
|
||||
if (!html5Mode.rewriteLinks || event.ctrlKey || event.metaKey || event.which == 2) return;
|
||||
if (!html5Mode.rewriteLinks || event.ctrlKey || event.metaKey || event.shiftKey || event.which == 2 || event.button == 2) return;
|
||||
|
||||
var elm = jqLite(event.target);
|
||||
|
||||
|
||||
@@ -3,6 +3,25 @@
|
||||
describe('a', function() {
|
||||
var element, $compile, $rootScope;
|
||||
|
||||
beforeEach(module(function($compileProvider) {
|
||||
$compileProvider.
|
||||
directive('linkTo', valueFn({
|
||||
restrict: 'A',
|
||||
template: '<div class="my-link"><a href="{{destination}}">{{destination}}</a></div>',
|
||||
replace: true,
|
||||
scope: {
|
||||
destination: '@linkTo'
|
||||
}
|
||||
})).
|
||||
directive('linkNot', valueFn({
|
||||
restrict: 'A',
|
||||
template: '<div class="my-link"><a href>{{destination}}</a></div>',
|
||||
replace: true,
|
||||
scope: {
|
||||
destination: '@linkNot'
|
||||
}
|
||||
}));
|
||||
}));
|
||||
|
||||
beforeEach(inject(function(_$compile_, _$rootScope_) {
|
||||
$compile = _$compile_;
|
||||
@@ -76,6 +95,40 @@ describe('a', function() {
|
||||
});
|
||||
|
||||
|
||||
it('should not preventDefault if anchor element is replaced with href-containing element', function() {
|
||||
spyOn(jqLite.prototype, 'on').andCallThrough();
|
||||
element = $compile('<a link-to="https://www.google.com">')($rootScope);
|
||||
$rootScope.$digest();
|
||||
|
||||
var child = element.children('a');
|
||||
var preventDefault = jasmine.createSpy('preventDefault');
|
||||
|
||||
child.triggerHandler({
|
||||
type: 'click',
|
||||
preventDefault: preventDefault
|
||||
});
|
||||
|
||||
expect(preventDefault).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
|
||||
it('should preventDefault if anchor element is replaced with element without href attribute', function() {
|
||||
spyOn(jqLite.prototype, 'on').andCallThrough();
|
||||
element = $compile('<a link-not="https://www.google.com">')($rootScope);
|
||||
$rootScope.$digest();
|
||||
|
||||
var child = element.children('a');
|
||||
var preventDefault = jasmine.createSpy('preventDefault');
|
||||
|
||||
child.triggerHandler({
|
||||
type: 'click',
|
||||
preventDefault: preventDefault
|
||||
});
|
||||
|
||||
expect(preventDefault).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
|
||||
if (isDefined(window.SVGElement)) {
|
||||
describe('SVGAElement', function() {
|
||||
it('should prevent default action to be executed when href is empty', function() {
|
||||
|
||||
+51
-4
@@ -1272,7 +1272,7 @@ describe('$location', function() {
|
||||
|
||||
|
||||
it('should not rewrite links with target="_blank"', function() {
|
||||
configureService({linkHref: '/a?b=c', html5Mode: true, supportHist: true, attrs: 'target="_blank"'});
|
||||
configureService({linkHref: 'base/a?b=c', html5Mode: true, supportHist: true, attrs: 'target="_blank"'});
|
||||
inject(
|
||||
initBrowser(),
|
||||
initLocation(),
|
||||
@@ -1285,7 +1285,7 @@ describe('$location', function() {
|
||||
|
||||
|
||||
it('should not rewrite links with target specified', function() {
|
||||
configureService({linkHref: '/a?b=c', html5Mode: true, supportHist: true, attrs: 'target="some-frame"'});
|
||||
configureService({linkHref: 'base/a?b=c', html5Mode: true, supportHist: true, attrs: 'target="some-frame"'});
|
||||
inject(
|
||||
initBrowser(),
|
||||
initLocation(),
|
||||
@@ -1480,7 +1480,7 @@ describe('$location', function() {
|
||||
});
|
||||
|
||||
it('should not rewrite when clicked with ctrl pressed', function() {
|
||||
configureService({linkHref: '/a?b=c', html5Mode: true, supportHist: true});
|
||||
configureService({linkHref: 'base/a?b=c', html5Mode: true, supportHist: true});
|
||||
inject(
|
||||
initBrowser(),
|
||||
initLocation(),
|
||||
@@ -1493,7 +1493,7 @@ describe('$location', function() {
|
||||
|
||||
|
||||
it('should not rewrite when clicked with meta pressed', function() {
|
||||
configureService({linkHref: '/a?b=c', html5Mode: true, supportHist: true});
|
||||
configureService({linkHref: 'base/a?b=c', html5Mode: true, supportHist: true});
|
||||
inject(
|
||||
initBrowser(),
|
||||
initLocation(),
|
||||
@@ -1504,6 +1504,53 @@ describe('$location', function() {
|
||||
);
|
||||
});
|
||||
|
||||
it('should not rewrite when right click pressed', function() {
|
||||
configureService({linkHref: 'base/a?b=c', html5Mode: true, supportHist: true});
|
||||
inject(
|
||||
initBrowser(),
|
||||
initLocation(),
|
||||
function($browser) {
|
||||
var rightClick;
|
||||
if (document.createEvent) {
|
||||
rightClick = document.createEvent('MouseEvents');
|
||||
rightClick.initMouseEvent('click', true, true, window, 1, 10, 10, 10, 10, false,
|
||||
false, false, false, 2, null);
|
||||
|
||||
link.dispatchEvent(rightClick);
|
||||
} else if (document.createEventObject) { // for IE
|
||||
rightClick = document.createEventObject();
|
||||
rightClick.type = 'click';
|
||||
rightClick.cancelBubble = true;
|
||||
rightClick.detail = 1;
|
||||
rightClick.screenX = 10;
|
||||
rightClick.screenY = 10;
|
||||
rightClick.clientX = 10;
|
||||
rightClick.clientY = 10;
|
||||
rightClick.ctrlKey = false;
|
||||
rightClick.altKey = false;
|
||||
rightClick.shiftKey = false;
|
||||
rightClick.metaKey = false;
|
||||
rightClick.button = 2;
|
||||
link.fireEvent('onclick', rightClick);
|
||||
}
|
||||
expectNoRewrite($browser);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
it('should not rewrite when clicked with shift pressed', function() {
|
||||
configureService({linkHref: 'base/a?b=c', html5Mode: true, supportHist: true});
|
||||
inject(
|
||||
initBrowser(),
|
||||
initLocation(),
|
||||
function($browser) {
|
||||
browserTrigger(link, 'click', { keys: ['shift'] });
|
||||
expectNoRewrite($browser);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
it('should not mess up hash urls when clicking on links in hashbang mode', function() {
|
||||
var base;
|
||||
|
||||
@@ -14,7 +14,7 @@ describe('Scope', function() {
|
||||
|
||||
it('should expose the constructor', inject(function($rootScope) {
|
||||
/* jshint -W103 */
|
||||
if (msie) return;
|
||||
if (msie < 11) return;
|
||||
expect($rootScope.__proto__).toBe($rootScope.constructor.prototype);
|
||||
}));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user