angular.js/src/widgets.js

258 lines
7.9 KiB
JavaScript
Raw Normal View History

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) {
2010-03-30 21:55:04 +00:00
scope.$tryEval(expr + '=' + toJson(formatter['parse'](value)), element);
}
};
}
function compileValidator(expr) {
return new Parser(expr).validator()();
}
function valueAccessor(scope, element) {
var validatorName = element.attr('ng-validate') || NOOP,
validator = compileValidator(validatorName),
required = element.attr('ng-required'),
2010-04-08 20:43:40 +00:00
lastError, lastVisible,
2010-04-07 21:13:10 +00:00
invalidWidgets = scope.$invalidWidgets || {markValid:noop, markInvalid:noop};
2010-04-04 00:04:36 +00:00
required = required || required === '';
if (!validator) throw "Validator named '" + validatorName + "' not found.";
function validate(value) {
2010-04-08 20:43:40 +00:00
var error = required && !trim(value) ?
"Required" :
validator({state:scope, scope:{get:scope.$get, set:scope.$set}}, value),
visible = isVisible(element);
if (error !== lastError || visible !== lastVisible) {
2010-03-30 22:39:51 +00:00
elementError(element, NG_VALIDATION_ERROR, error);
lastError = error;
2010-04-08 20:43:40 +00:00
lastVisible = visible;
if (error && visible)
2010-04-07 21:13:10 +00:00
invalidWidgets.markInvalid(element);
else
invalidWidgets.markValid(element);
2010-01-12 01:32:33 +00:00
}
return value;
}
return {
get: function(){ return validate(element.val()); },
set: function(value){ element.val(validate(value)); }
};
}
function checkedAccessor(scope, element) {
var domElement = element[0];
return {
get: function(){
return !!domElement.checked;
},
set: function(value){
domElement.checked = !!value;
}
};
}
function radioAccessor(scope, element) {
var domElement = element[0];
return {
get: function(){
return domElement.checked ? domElement.value : null;
},
set: function(value){
domElement.checked = value == domElement.value;
}
};
}
function optionsAccessor(scope, 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];
2010-01-12 01:32:33 +00:00
});
}
};
}
function noopAccessor() { return { get: noop, set: noop }; }
2010-04-02 18:10:36 +00:00
var textWidget = inputWidget('keyup change', modelAccessor, valueAccessor, initWidgetValue('')),
buttonWidget = inputWidget('click', noopAccessor, noopAccessor, noop),
INPUT_TYPE = {
'text': textWidget,
'textarea': textWidget,
'hidden': textWidget,
'password': textWidget,
'button': buttonWidget,
'submit': buttonWidget,
'reset': buttonWidget,
'image': buttonWidget,
2010-04-02 18:10:36 +00:00
'checkbox': inputWidget('click', modelAccessor, checkedAccessor, initWidgetValue(false)),
'radio': inputWidget('click', modelAccessor, radioAccessor, radioInit),
'select-one': inputWidget('change', modelAccessor, valueAccessor, initWidgetValue(null)),
'select-multiple': inputWidget('change', modelAccessor, optionsAccessor, initWidgetValue([]))
// 'file': fileWidget???
};
2010-02-18 04:50:13 +00:00
2010-04-02 18:10:36 +00:00
function initWidgetValue(initValue) {
return function (model, view) {
var value = view.get() || copy(initValue);
if (isUndefined(model.get()) && isDefined(value))
model.set(value);
};
}
2010-04-02 18:49:48 +00:00
function radioInit(model, view, element) {
var modelValue = model.get(), viewValue = view.get(), input = element[0];
input.name = this.$id + '@' + input.name;
2010-04-02 18:10:36 +00:00
if (isUndefined(modelValue)) model.set(null);
2010-04-04 00:04:36 +00:00
if (viewValue !== null) model.set(viewValue);
2010-04-02 18:10:36 +00:00
}
function inputWidget(events, modelAccessor, viewAccessor, initFn) {
return function(element) {
var scope = this,
model = modelAccessor(scope, element),
view = viewAccessor(scope, element),
2010-04-02 18:10:36 +00:00
action = element.attr('ng-change') || '';
2010-04-02 18:49:48 +00:00
initFn.call(scope, model, view, element);
this.$eval(element.attr('ng-init')||'');
2010-04-04 00:04:36 +00:00
// Don't register a handler if we are a button (noopAccessor) and there is no action
if (action || modelAccessor !== noopAccessor) {
element.bind(events, function(){
model.set(view.get());
scope.$tryEval(action, element);
scope.$root.$eval();
// if we have noop initFn than we are just a button,
// therefore we want to prevent default action
return initFn != noop;
});
}
2010-03-31 20:57:25 +00:00
view.set(model.get());
scope.$watch(model.get, view.set);
};
}
function inputWidgetSelector(element){
2010-03-30 21:55:04 +00:00
this.directives(true);
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);
});
2010-04-02 18:10:36 +00:00
2010-04-05 18:46:53 +00:00
angularWidget('NG:INCLUDE', function(element){
2010-04-02 18:10:36 +00:00
var compiler = this,
2010-04-05 18:46:53 +00:00
src = element.attr("src");
2010-04-07 17:17:15 +00:00
if (element.attr('switch-instance')) {
this.descend(true);
this.directives(true);
} else {
return function(element){
var scope = this, childScope;
element.attr('switch-instance', 'compiled');
scope.$browser.xhr('GET', src, function(code, response){
element.html(response);
childScope = createScope(scope);
compiler.compile(element)(element, childScope);
childScope.$init();
scope.$root.$eval();
});
scope.$onEval(function(){
if (childScope) childScope.$eval();
});
};
}
2010-04-02 18:10:36 +00:00
});
2010-04-07 17:17:15 +00:00
angularWidget('NG:SWITCH', function ngSwitch(element){
2010-04-02 18:10:36 +00:00
var compiler = this,
2010-04-05 18:46:53 +00:00
watchExpr = element.attr("on"),
2010-04-07 17:17:15 +00:00
whenFn = ngSwitch[element.attr("using") || 'equals'];
changeExpr = element.attr('change') || '',
2010-04-05 18:46:53 +00:00
cases = [];
2010-04-07 17:17:15 +00:00
if (!whenFn) throw "Using expression '" + usingExpr + "' unknown.";
2010-04-05 18:46:53 +00:00
eachNode(element, function(caseElement){
var when = caseElement.attr('ng-switch-when');
if (when) {
cases.push({
2010-04-07 17:17:15 +00:00
when: function(scope, value){
return whenFn.call(scope, value, when);
},
change: changeExpr,
2010-04-05 18:46:53 +00:00
element: caseElement,
template: compiler.compile(caseElement)
});
}
});
element.html('');
return function(element){
2010-04-07 17:17:15 +00:00
var scope = this, childScope;
2010-04-02 18:10:36 +00:00
this.$watch(watchExpr, function(value){
2010-04-05 18:46:53 +00:00
element.html('');
2010-04-07 17:17:15 +00:00
childScope = null;
2010-04-07 21:14:25 +00:00
var params = {};
2010-04-05 18:46:53 +00:00
foreach(cases, function(switchCase){
2010-04-07 21:14:25 +00:00
if (switchCase.when(params, value)) {
2010-04-05 18:46:53 +00:00
element.append(switchCase.element);
2010-04-07 17:17:15 +00:00
childScope = createScope(scope);
2010-04-07 21:14:25 +00:00
extend(childScope, params);
2010-04-07 17:17:15 +00:00
childScope.$tryEval(switchCase.change, element);
2010-04-05 18:46:53 +00:00
switchCase.template(switchCase.element, childScope);
childScope.$init();
2010-04-02 18:10:36 +00:00
}
});
});
2010-04-07 17:17:15 +00:00
scope.$onEval(function(){
if (childScope) childScope.$eval();
});
2010-04-02 18:10:36 +00:00
};
2010-04-07 17:17:15 +00:00
}, {
equals: function(on, when) {
return on == when;
},
route: function(on, when) {
2010-04-07 21:14:25 +00:00
var regex = '^' + when.replace(/[\.\\\(\)\^\$]/g, "\$1") + '$', params = [], self = this;
foreach(when.split(/\W/), function(param){
if (param) {
var paramRegExp = new RegExp(":" + param + "([\\W])");
if (regex.match(paramRegExp)) {
regex = regex.replace(paramRegExp, "(.*)$1");
params.push(param);
}
}
});
var match = on.match(new RegExp(regex));
if (match) {
foreach(params, function(name, index){
self[name] = match[index + 1];
});
}
return match;
2010-04-07 17:17:15 +00:00
}
2010-04-02 18:10:36 +00:00
});