Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit 4f78fd6

Browse files
mheveryIgorMinar
authored andcommitted
feat(forms): new and improved forms
1 parent df6d2ba commit 4f78fd6

File tree

104 files changed

+7051
-3970
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

104 files changed

+7051
-3970
lines changed

Rakefile

+1-60
Original file line numberDiff line numberDiff line change
@@ -77,66 +77,8 @@ task :compile_jstd_scenario_adapter => :init do
7777
end
7878

7979

80-
desc 'Generate IE css js patch'
81-
task :generate_ie_compat => :init do
82-
css = File.open('css/angular.css', 'r') {|f| f.read }
83-
84-
# finds all css rules that contain backround images and extracts the rule name(s), content type of
85-
# the image and base64 encoded image data
86-
r = /\n([^\{\n]+)\s*\{[^\}]*background-image:\s*url\("data:([^;]+);base64,([^"]+)"\);[^\}]*\}/
87-
88-
images = css.scan(r)
89-
90-
# create a js file with multipart header containing the extracted images. the entire file *must*
91-
# be CRLF (\r\n) delimited
92-
File.open(path_to('angular-ie-compat.js'), 'w') do |f|
93-
f.write("/*\r\n" +
94-
"Content-Type: multipart/related; boundary=\"_\"\r\n" +
95-
"\r\n")
96-
97-
images.each_index do |idx|
98-
f.write("--_\r\n" +
99-
"Content-Location:img#{idx}\r\n" +
100-
"Content-Transfer-Encoding:base64\r\n" +
101-
"\r\n" +
102-
images[idx][2] + "\r\n")
103-
end
104-
105-
f.write("--_--\r\n" +
106-
"*/\r\n")
107-
108-
# generate a css string containing *background-image rules for IE that point to the mime type
109-
# images in the header
110-
cssString = ''
111-
images.each_index do |idx|
112-
cssString += "#{images[idx][0]}{*background-image:url(\"mhtml:' + jsUri + '!img#{idx}\")}"
113-
end
114-
115-
# generate a javascript closure that contains a function which will append the generated css
116-
# string as a stylesheet to the current html document
117-
jsString = "(function(){ \r\n" +
118-
" var jsUri = document.location.href.replace(/\\/[^\\\/]+(#.*)?$/, '/') + \r\n" +
119-
" document.getElementById('ng-ie-compat').src,\r\n" +
120-
" css = '#{cssString}',\r\n" +
121-
" s = document.createElement('style'); \r\n" +
122-
"\r\n" +
123-
" s.setAttribute('type', 'text/css'); \r\n" +
124-
"\r\n" +
125-
" if (s.styleSheet) { \r\n" +
126-
" s.styleSheet.cssText = css; \r\n" +
127-
" } else { \r\n" +
128-
" s.appendChild(document.createTextNode(css)); \r\n" +
129-
" } \r\n" +
130-
" document.getElementsByTagName('head')[0].appendChild(s); \r\n" +
131-
"})();\r\n"
132-
133-
f.write(jsString)
134-
end
135-
end
136-
137-
13880
desc 'Compile JavaScript'
139-
task :compile => [:init, :compile_scenario, :compile_jstd_scenario_adapter, :generate_ie_compat] do
81+
task :compile => [:init, :compile_scenario, :compile_jstd_scenario_adapter] do
14082

14183
deps = [
14284
'src/angular.prefix',
@@ -193,7 +135,6 @@ task :package => [:clean, :compile, :docs] do
193135
['src/angular-mocks.js',
194136
path_to('angular.js'),
195137
path_to('angular.min.js'),
196-
path_to('angular-ie-compat.js'),
197138
path_to('angular-scenario.js'),
198139
path_to('jstd-scenario-adapter.js'),
199140
path_to('jstd-scenario-adapter-config.js'),

angularFiles.js

+5-3
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,12 @@ angularFiles = {
1212
'src/jqLite.js',
1313
'src/apis.js',
1414
'src/filters.js',
15-
'src/formatters.js',
16-
'src/validators.js',
1715
'src/service/cookieStore.js',
1816
'src/service/cookies.js',
1917
'src/service/defer.js',
2018
'src/service/document.js',
2119
'src/service/exceptionHandler.js',
22-
'src/service/invalidWidgets.js',
20+
'src/service/formFactory.js',
2321
'src/service/location.js',
2422
'src/service/log.js',
2523
'src/service/resource.js',
@@ -35,6 +33,9 @@ angularFiles = {
3533
'src/directives.js',
3634
'src/markups.js',
3735
'src/widgets.js',
36+
'src/widget/form.js',
37+
'src/widget/input.js',
38+
'src/widget/select.js',
3839
'src/AngularPublic.js',
3940
],
4041

@@ -74,6 +75,7 @@ angularFiles = {
7475
'test/jstd-scenario-adapter/*.js',
7576
'test/*.js',
7677
'test/service/*.js',
78+
'test/widget/*.js',
7779
'example/personalLog/test/*.js'
7880
],
7981

css/angular.css

-9
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,3 @@
77
.ng-format-negative {
88
color: red;
99
}
10-
11-
/*****************
12-
* indicators
13-
*****************/
14-
.ng-input-indicator-wait {
15-
background-image: url("data:image/png;base64,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");
16-
background-position: right;
17-
background-repeat: no-repeat;
18-
}
+92
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
@ngdoc overview
2+
@name angular.inputType
3+
@description
4+
5+
Angular {@link guide/dev_guide.forms forms} allow you to build complex widgets. However for
6+
simple widget which are based on HTML input text element a simpler way of providing the validation
7+
and parsing is also provided. `angular.inputType` is a short hand for creating a widget which
8+
already has the DOM listeners and `$render` method supplied. The only thing which needs to
9+
be provided by the developer are the optional `$validate` listener and
10+
`$parseModel` or `$parseModel` methods.
11+
12+
All `inputType` widgets support:
13+
14+
- CSS classes:
15+
- **`ng-valid`**: when widget is valid.
16+
- **`ng-invalid`**: when widget is invalid.
17+
- **`ng-pristine`**: when widget has not been modified by user action.
18+
- **`ng-dirty`**: when has been modified do to user action.
19+
20+
- Widget properties:
21+
- **`$valid`**: When widget is valid.
22+
- **`$invalid`**: When widget is invalid.
23+
- **`$pristine`**: When widget has not been modified by user interaction.
24+
- **`$dirty`**: When user has been modified do to user interaction.
25+
- **`$required`**: When the `<input>` element has `required` attribute. This means that the
26+
widget will have `REQUIRED` validation error if empty.
27+
- **`$disabled`**: When the `<input>` element has `disabled` attribute.
28+
- **`$readonly`**: When the `<input>` element has `readonly` attribute.
29+
30+
- Widget Attribute Validators:
31+
- **`required`**: Sets `REQUIRED` validation error key if the input is empty
32+
- **`ng:pattern`** Sets `PATTERN` validation error key if the value does not match the
33+
RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
34+
patterns defined as scope expressions.
35+
36+
37+
38+
# Example
39+
40+
<doc:example>
41+
<doc:source>
42+
<script>
43+
angular.inputType('json', function(){
44+
this.$parseView = function(){
45+
try {
46+
this.$modelValue = angular.fromJson(this.$viewValue);
47+
if (this.$error.JSON) {
48+
this.$emit('$valid', 'JSON');
49+
}
50+
} catch (e) {
51+
this.$emit('$invalid', 'JSON');
52+
}
53+
}
54+
55+
this.$parseModel = function(){
56+
this.$viewValue = angular.toJson(this.$modelValue);
57+
}
58+
});
59+
60+
function Ctrl(){
61+
this.data = {
62+
framework:'angular',
63+
codenames:'supper-powers'
64+
}
65+
this.required = false;
66+
this.disabled = false;
67+
this.readonly = false;
68+
}
69+
</script>
70+
<div ng:controller="Ctrl">
71+
<form name="myForm">
72+
<input type="json" ng:model="data" size="80"
73+
ng:required="{{required}}" ng:disabled="{{disabled}}"
74+
ng:readonly="{{readonly}}"/><br/>
75+
Required: <input type="checkbox" ng:model="required"> <br/>
76+
Disabled: <input type="checkbox" ng:model="disabled"> <br/>
77+
Readonly: <input type="checkbox" ng:model="readonly"> <br/>
78+
<pre>data={{data}}</pre>
79+
<pre>myForm={{myForm}}</pre>
80+
</form>
81+
</div>
82+
</doc:source>
83+
<doc:scenario>
84+
it('should invalidate on wrong input', function(){
85+
expect(element('form[name=myForm]').prop('className')).toMatch('ng-valid');
86+
input('data').enter('{}');
87+
expect(binding('data')).toEqual('data={\n }');
88+
input('data').enter('{');
89+
expect(element('form[name=myForm]').prop('className')).toMatch('ng-invalid');
90+
});
91+
</doc:scenario>
92+
</doc:example>

docs/content/api/angular.service.ngdoc

-2
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@ session cookies
1414
* {@link angular.service.$document $document } - Provides reference to `window.document` element
1515
* {@link angular.service.$exceptionHandler $exceptionHandler } - Receives uncaught angular
1616
exceptions
17-
* {@link angular.service.$hover $hover } -
18-
* {@link angular.service.$invalidWidgets $invalidWidgets } - Holds references to invalid widgets
1917
* {@link angular.service.$location $location } - Parses the browser location URL
2018
* {@link angular.service.$log $log } - Provides logging service
2119
* {@link angular.service.$resource $resource } - Creates objects for interacting with RESTful

docs/content/api/index.ngdoc

-2
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@
88
* {@link angular.directive Directives} - Angular DOM element attributes
99
* {@link angular.markup Markup} and {@link angular.attrMarkup Attribute Markup}
1010
* {@link angular.filter Filters} - Angular output filters
11-
* {@link angular.formatter Formatters} - Angular converters for form elements
12-
* {@link angular.validator Validators} - Angular input validators
1311
* {@link angular.compile angular.compile()} - Template compiler
1412

1513
## Angular Scope API

docs/content/cookbook/advancedform.ngdoc

+28-27
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,7 @@ detection, and preventing invalid form submission.
99
<doc:example>
1010
<doc:source>
1111
<script>
12-
UserForm.$inject = ['$invalidWidgets'];
13-
function UserForm($invalidWidgets){
14-
this.$invalidWidgets = $invalidWidgets;
12+
function UserForm(){
1513
this.state = /^\w\w$/;
1614
this.zip = /^\d\d\d\d\d$/;
1715
this.master = {
@@ -42,31 +40,34 @@ detection, and preventing invalid form submission.
4240
</script>
4341
<div ng:controller="UserForm">
4442

45-
<label>Name:</label><br/>
46-
<input type="text" name="form.name" ng:required/> <br/><br/>
43+
<form name="myForm">
4744

48-
<label>Address:</label><br/>
49-
<input type="text" name="form.address.line1" size="33" ng:required/> <br/>
50-
<input type="text" name="form.address.city" size="12" ng:required/>,
51-
<input type="text" name="form.address.state" size="2" ng:required ng:validate="regexp:state"/>
52-
<input type="text" name="form.address.zip" size="5" ng:required
53-
ng:validate="regexp:zip"/><br/><br/>
45+
<label>Name:</label><br/>
46+
<input type="text" ng:model="form.name" required/> <br/><br/>
5447

55-
<label>Contacts:</label>
56-
[ <a href="" ng:click="form.contacts.$add()">add</a> ]
57-
<div ng:repeat="contact in form.contacts">
58-
<select name="contact.type">
59-
<option>email</option>
60-
<option>phone</option>
61-
<option>pager</option>
62-
<option>IM</option>
63-
</select>
64-
<input type="text" name="contact.value" ng:required/>
65-
[ <a href="" ng:click="form.contacts.$remove(contact)">X</a> ]
66-
</div>
67-
<button ng:click="cancel()" ng:disabled="{{master.$equals(form)}}">Cancel</button>
68-
<button ng:click="save()" ng:disabled="{{$invalidWidgets.visible() ||
69-
master.$equals(form)}}">Save</button>
48+
<label>Address:</label> <br/>
49+
<input type="text" ng:model="form.address.line1" size="33" required/> <br/>
50+
<input type="text" ng:model="form.address.city" size="12" required/>,
51+
<input type="text" ng:model="form.address.state" size="2"
52+
ng:pattern="state" required/>
53+
<input type="text" ng:model="form.address.zip" size="5"
54+
ng:pattern="zip" required/><br/><br/>
55+
56+
<label>Contacts:</label>
57+
[ <a href="" ng:click="form.contacts.$add()">add</a> ]
58+
<div ng:repeat="contact in form.contacts">
59+
<select ng:model="contact.type">
60+
<option>email</option>
61+
<option>phone</option>
62+
<option>pager</option>
63+
<option>IM</option>
64+
</select>
65+
<input type="text" ng:model="contact.value" required/>
66+
[ <a href="" ng:click="form.contacts.$remove(contact)">X</a> ]
67+
</div>
68+
<button ng:click="cancel()" ng:disabled="{{master.$equals(form)}}">Cancel</button>
69+
<button ng:click="save()" ng:disabled="{{myForm.$invalid || master.$equals(form)}}">Save</button>
70+
</form>
7071

7172
<hr/>
7273
Debug View:
@@ -90,7 +91,7 @@ master.$equals(form)}}">Save</button>
9091
expect(element(':button:contains(Cancel)').attr('disabled')).toBeFalsy();
9192
element(':button:contains(Cancel)').click();
9293
expect(element(':button:contains(Cancel)').attr('disabled')).toBeTruthy();
93-
expect(element(':input[name="form.name"]').val()).toEqual('John Smith');
94+
expect(element(':input[ng\\:model="form.name"]').val()).toEqual('John Smith');
9495
});
9596
</doc:scenario>
9697
</doc:example>

docs/content/cookbook/buzz.ngdoc

+2-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ to retrieve Buzz activity and comments.
1515
<script>
1616
BuzzController.$inject = ['$resource'];
1717
function BuzzController($resource) {
18+
this.userId = 'googlebuzz';
1819
this.Activity = $resource(
1920
'https://www.googleapis.com/buzz/v1/activities/:userId/:visibility/:activityId/:comments',
2021
{alt: 'json', callback: 'JSON_CALLBACK'},
@@ -32,7 +33,7 @@ to retrieve Buzz activity and comments.
3233
};
3334
</script>
3435
<div ng:controller="BuzzController">
35-
<input name="userId" value="googlebuzz"/>
36+
<input ng:model="userId"/>
3637
<button ng:click="fetch()">fetch</button>
3738
<hr/>
3839
<div class="buzz" ng:repeat="item in activities.data.items">

0 commit comments

Comments
 (0)