1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
|
function modelAccessor(scope, element) {
var expr = element.attr('name'),
farmatterName = element.attr('ng-format') || NOOP,
formatter = angularFormatter(farmatterName);
if (!expr) throw "Required field 'name' not found.";
if (!formatter) throw "Formatter named '" + farmatterName + "' not found.";
return {
get: function() {
return formatter['format'](scope.$eval(expr));
},
set: function(value) {
scope.$eval(expr + '=' + toJson(formatter['parse'](value)));
}
};
}
function compileValidator(expr) {
return new Parser(expr).validator()();
}
function valueAccessor(element) {
var validatorName = element.attr('ng-validate') || NOOP,
validator = compileValidator(validatorName),
required = element.attr('ng-required'),
lastError;
required = required || required == '';
if (!validator) throw "Validator named '" + validatorName + "' not found.";
function validate(value) {
var error = required && !trim(value) ? "Required" : validator.call(this, value);
if (error !== lastError) {
if (error) {
element.addClass(NG_VALIDATION_ERROR);
element.attr(NG_ERROR, error);
} else {
element.removeClass(NG_VALIDATION_ERROR);
element.removeAttr(NG_ERROR);
}
lastError = error;
}
return value;
}
return {
get: function(){ return validate(element.val()); },
set: function(value){ element.val(validate(value)); }
};
}
function checkedAccessor(element) {
var domElement = element[0];
return {
get: function(){ return !!domElement.checked; },
set: function(value){ domElement.checked = !!value; }
};
}
function radioAccessor(element) {
var domElement = element[0];
return {
get: function(){ return domElement.checked ? domElement.value : null; },
set: function(value){ domElement.checked = value == domElement.value; }
};
}
function optionsAccessor(element) {
var options = element[0].options;
return {
get: function(){
var values = [];
foreach(options, function(option){
if (option.selected) values.push(option.value);
});
return values;
},
set: function(values){
var keys = {};
foreach(values, function(value){ keys[value] = true; });
foreach(options, function(option){
option.selected = keys[option.value];
});
}
};
}
function noopAccessor() { return { get: noop, set: noop }; }
var NG_ERROR = 'ng-error',
NG_VALIDATION_ERROR = 'ng-validation-error',
textWidget = inputWidget('keyup change', modelAccessor, valueAccessor, ''),
buttonWidget = inputWidget('click', noopAccessor, noopAccessor, undefined),
INPUT_TYPE = {
'text': textWidget,
'textarea': textWidget,
'hidden': textWidget,
'password': textWidget,
'button': buttonWidget,
'submit': buttonWidget,
'reset': buttonWidget,
'image': buttonWidget,
'checkbox': inputWidget('click', modelAccessor, checkedAccessor, false),
'radio': inputWidget('click', modelAccessor, radioAccessor, undefined),
'select-one': inputWidget('click', modelAccessor, valueAccessor, null),
'select-multiple': inputWidget('click', modelAccessor, optionsAccessor, [])
// 'file': fileWidget???
};
function inputWidget(events, modelAccessor, viewAccessor, initValue) {
return function(element) {
var scope = this,
model = modelAccessor(scope, element),
view = viewAccessor(element),
action = element.attr('ng-action') || '',
value = view.get() || copy(initValue);
if (isDefined(value)) model.set(value);
this.$eval(element.attr('ng-init')||'');
element.bind(events, function(){
model.set(view.get());
scope.$tryEval(action, element);
scope.$root.$eval();
// if we have no initValue than we are just a button,
// therefore we want to prevent default action
return isDefined(initValue);
});
scope.$watch(model.get, view.set);
};
}
function inputWidgetSelector(element){
return INPUT_TYPE[lowercase(element[0].type)] || noop;
}
angularWidget('INPUT', inputWidgetSelector);
angularWidget('TEXTAREA', inputWidgetSelector);
angularWidget('BUTTON', inputWidgetSelector);
angularWidget('SELECT', function(element){
this.descend(true);
return inputWidgetSelector.call(this, element);
});
|