aboutsummaryrefslogtreecommitdiffstats
path: root/src/Widgets.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/Widgets.js')
-rw-r--r--src/Widgets.js927
1 files changed, 129 insertions, 798 deletions
diff --git a/src/Widgets.js b/src/Widgets.js
index 74f70f21..42b9e916 100644
--- a/src/Widgets.js
+++ b/src/Widgets.js
@@ -1,806 +1,137 @@
-function WidgetFactory(serverUrl, database) {
- this.nextUploadId = 0;
- this.serverUrl = serverUrl;
- this.database = database;
- if (window['swfobject']) {
- this.createSWF = window['swfobject']['createSWF'];
- } else {
- this.createSWF = function(){
- alert("ERROR: swfobject not loaded!");
- };
- }
-};
-
-WidgetFactory.prototype = {
- createController: function(input, scope) {
- var controller;
- var type = input.attr('type').toLowerCase();
- var exp = input.attr('name');
- if (exp) exp = exp.split(':').pop();
- var event = "change";
- var bubbleEvent = true;
- var formatter = angularFormatter[input.attr('ng-format')] || angularFormatter['noop'];
- if (type == 'button' || type == 'submit' || type == 'reset' || type == 'image') {
- controller = new ButtonController(input[0], exp, formatter);
- event = "click";
- bubbleEvent = false;
- } else if (type == 'text' || type == 'textarea' || type == 'hidden' || type == 'password') {
- controller = new TextController(input[0], exp, formatter);
- event = "keyup change";
- } else if (type == 'checkbox') {
- controller = new CheckboxController(input[0], exp, formatter);
- event = "click";
- } else if (type == 'radio') {
- controller = new RadioController(input[0], exp, formatter);
- event="click";
- } else if (type == 'select-one') {
- controller = new SelectController(input[0], exp, formatter);
- } else if (type == 'select-multiple') {
- controller = new MultiSelectController(input[0], exp, formatter);
- } else if (type == 'file') {
- controller = this.createFileController(input, exp, formatter);
- } else {
- throw 'Unknown type: ' + type;
- }
- input.data('controller', controller);
- var updateView = scope.get('$updateView');
- var action = function() {
- if (controller.updateModel(scope)) {
- var action = jQuery(controller.view).attr('ng-action') || "";
- if (scope.evalWidget(controller, action)) {
- updateView(scope);
- }
- }
- return bubbleEvent;
- };
- jQuery(controller.view, ":input").
- bind(event, action);
- return controller;
- },
-
- createFileController: function(fileInput) {
- var uploadId = '__uploadWidget_' + (this.nextUploadId++);
- var view = FileController.template(uploadId);
- fileInput.after(view);
- var att = {
- 'data':this.serverUrl + "/admin/ServerAPI.swf",
- 'width':"95", 'height':"20", 'align':"top",
- 'wmode':"transparent"};
- var par = {
- 'flashvars':"uploadWidgetId=" + uploadId,
- 'allowScriptAccess':"always"};
- var swfNode = this.createSWF(att, par, uploadId);
- fileInput.remove();
- var cntl = new FileController(view, fileInput[0].name, swfNode, this.serverUrl + "/data/" + this.database);
- jQuery(swfNode).parent().data('controller', cntl);
- return cntl;
- }
-};
-/////////////////////
-// FileController
-///////////////////////
-
-function FileController(view, scopeName, uploader, databaseUrl) {
- this.view = view;
- this.uploader = uploader;
- this.scopeName = scopeName;
- this.attachmentsPath = databaseUrl + '/_attachments';
- this.value = null;
- this.lastValue = undefined;
-};
-
-angularCallbacks['flashEvent'] = function(id, event, args) {
- var object = document.getElementById(id);
- var jobject = jQuery(object);
- var controller = jobject.parent().data("controller");
- FileController.prototype[event].apply(controller, args);
- _.defer(jobject.scope().get('$updateView'));
-};
-
-FileController.template = function(id) {
- return jQuery('<span class="ng-upload-widget">' +
- '<input type="checkbox" ng-non-bindable="true"/>' +
- '<object id="' + id + '" />' +
- '<a></a>' +
- '<span/>' +
- '</span>');
-};
-
-extend(FileController.prototype, {
- 'cancel': noop,
- 'complete': noop,
- 'httpStatus': function(status) {
- alert("httpStatus:" + this.scopeName + " status:" + status);
- },
- 'ioError': function() {
- alert("ioError:" + this.scopeName);
- },
- 'open': function() {
- alert("open:" + this.scopeName);
- },
- 'progress':noop,
- 'securityError': function() {
- alert("securityError:" + this.scopeName);
- },
- 'uploadCompleteData': function(data) {
- var value = fromJson(data);
- value.url = this.attachmentsPath + '/' + value.id + '/' + value.text;
- this.view.find("input").attr('checked', true);
- var scope = this.view.scope();
- this.value = value;
- this.updateModel(scope);
- this.value = null;
- },
- 'select': function(name, size, type) {
- this.name = name;
- this.view.find("a").text(name).attr('href', name);
- this.view.find("span").text(angular['filter']['bytes'](size));
- this.upload();
- },
-
- updateModel: function(scope) {
- var isChecked = this.view.find("input").attr('checked');
- var value = isChecked ? this.value : null;
- if (this.lastValue === value) {
- return false;
- } else {
- scope.set(this.scopeName, value);
- return true;
- }
- },
-
- updateView: function(scope) {
- var modelValue = scope.get(this.scopeName);
- if (modelValue && this.value !== modelValue) {
- this.value = modelValue;
- this.view.find("a").
- attr("href", this.value.url).
- text(this.value.text);
- this.view.find("span").text(angular['filter']['bytes'](this.value.size));
- }
- this.view.find("input").attr('checked', !!modelValue);
- },
-
- upload: function() {
- if (this.name) {
- this.uploader['uploadFile'](this.attachmentsPath);
- }
- }
-});
-
-///////////////////////
-// NullController
-///////////////////////
-function NullController(view) {this.view = view;};
-NullController.prototype = {
- updateModel: function() { return true; },
- updateView: noop
-};
-NullController.instance = new NullController();
-
-
-///////////////////////
-// ButtonController
-///////////////////////
-var ButtonController = NullController;
-
-///////////////////////
-// TextController
-///////////////////////
-function TextController(view, exp, formatter) {
- this.view = view;
- this.formatter = formatter;
- this.exp = exp;
- this.validator = view.getAttribute('ng-validate');
- this.required = typeof view.attributes['ng-required'] != "undefined";
- this.lastErrorText = null;
- this.lastValue = undefined;
- this.initialValue = this.formatter['parse'](view.value);
- var widget = view.getAttribute('ng-widget');
- if (widget === 'datepicker') {
- jQuery(view).datepicker();
- }
-};
-
-TextController.prototype = {
- updateModel: function(scope) {
- var value = this.formatter['parse'](this.view.value);
- if (this.lastValue === value) {
- return false;
- } else {
- scope.setEval(this.exp, value);
- this.lastValue = value;
- return true;
- }
- },
-
- updateView: function(scope) {
- var view = this.view;
- var value = scope.get(this.exp);
- if (typeof value === "undefined") {
- value = this.initialValue;
- scope.setEval(this.exp, value);
- }
- value = value ? value : '';
- if (!_(this.lastValue).isEqual(value)) {
- view.value = this.formatter['format'](value);
- this.lastValue = value;
- }
-
- var isValidationError = false;
- view.removeAttribute('ng-error');
- if (this.required) {
- isValidationError = !(value && $.trim("" + value).length > 0);
- }
- var errorText = isValidationError ? "Required Value" : null;
- if (!isValidationError && this.validator && value) {
- errorText = scope.validate(this.validator, value, view);
- isValidationError = !!errorText;
- }
- if (this.lastErrorText !== errorText) {
- this.lastErrorText = isValidationError;
- if (errorText && isVisible(view)) {
- view.setAttribute('ng-error', errorText);
- scope.markInvalid(this);
- }
- jQuery(view).toggleClass('ng-validation-error', isValidationError);
- }
- }
-};
-
-///////////////////////
-// CheckboxController
-///////////////////////
-function CheckboxController(view, exp, formatter) {
- this.view = view;
- this.exp = exp;
- this.lastValue = undefined;
- this.formatter = formatter;
- this.initialValue = this.formatter['parse'](view.checked ? view.value : "");
-};
-
-CheckboxController.prototype = {
- updateModel: function(scope) {
- var input = this.view;
- var value = input.checked ? input.value : '';
- value = this.formatter['parse'](value);
- value = this.formatter['format'](value);
- if (this.lastValue === value) {
- return false;
- } else {
- scope.setEval(this.exp, this.formatter['parse'](value));
- this.lastValue = value;
- return true;
- }
- },
-
- updateView: function(scope) {
- var input = this.view;
- var value = scope.eval(this.exp);
- if (typeof value === "undefined") {
- value = this.initialValue;
- scope.setEval(this.exp, value);
- }
- input.checked = this.formatter['parse'](input.value) == value;
- }
-};
-
-///////////////////////
-// SelectController
-///////////////////////
-function SelectController(view, exp) {
- this.view = view;
- this.exp = exp;
- this.lastValue = undefined;
- this.initialValue = view.value;
-};
-
-SelectController.prototype = {
- updateModel: function(scope) {
- var input = this.view;
- if (input.selectedIndex < 0) {
- scope.setEval(this.exp, null);
- } else {
- var value = this.view.value;
- if (this.lastValue === value) {
- return false;
+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 {
- scope.setEval(this.exp, value);
- this.lastValue = value;
- return true;
- }
- }
- },
-
- updateView: function(scope) {
- var input = this.view;
- var value = scope.get(this.exp);
- if (typeof value === 'undefined') {
- value = this.initialValue;
- scope.setEval(this.exp, value);
- }
- if (value !== this.lastValue) {
- input.value = value ? value : "";
- this.lastValue = value;
- }
- }
-};
-
-///////////////////////
-// MultiSelectController
-///////////////////////
-function MultiSelectController(view, exp) {
- this.view = view;
- this.exp = exp;
- this.lastValue = undefined;
- this.initialValue = this.selected();
-};
-
-MultiSelectController.prototype = {
- selected: function () {
- var value = [];
- var options = this.view.options;
- for ( var i = 0; i < options.length; i++) {
- var option = options[i];
- if (option.selected) {
- value.push(option.value);
+ element.removeClass(NG_VALIDATION_ERROR);
+ element.removeAttr(NG_ERROR);
}
+ lastError = error;
}
return value;
- },
-
- updateModel: function(scope) {
- var value = this.selected();
- // TODO: This is wrong! no caching going on here as we are always comparing arrays
- if (this.lastValue === value) {
- return false;
- } else {
- scope.setEval(this.exp, value);
- this.lastValue = value;
- return true;
- }
- },
-
- updateView: function(scope) {
- var input = this.view;
- var selected = scope.get(this.exp);
- if (typeof selected === "undefined") {
- selected = this.initialValue;
- scope.setEval(this.exp, selected);
- }
- if (selected !== this.lastValue) {
- var options = input.options;
- for ( var i = 0; i < options.length; i++) {
- var option = options[i];
- option.selected = _.include(selected, option.value);
- }
- this.lastValue = selected;
- }
- }
-};
-
-///////////////////////
-// RadioController
-///////////////////////
-function RadioController(view, exp) {
- this.view = view;
- this.exp = exp;
- this.lastChecked = undefined;
- this.lastValue = undefined;
- this.inputValue = view.value;
- this.initialValue = view.checked ? view.value : null;
-};
-
-RadioController.prototype = {
- updateModel: function(scope) {
- var input = this.view;
- if (this.lastChecked) {
- return false;
- } else {
- input.checked = true;
- this.lastValue = scope.setEval(this.exp, this.inputValue);
- this.lastChecked = true;
- return true;
- }
- },
-
- updateView: function(scope) {
- var input = this.view;
- var value = scope.get(this.exp);
- if (this.initialValue && typeof value === "undefined") {
- value = this.initialValue;
- scope.setEval(this.exp, value);
- }
- if (this.lastValue != value) {
- this.lastChecked = input.checked = this.inputValue == (''+value);
- this.lastValue = value;
- }
- }
-};
-
-///////////////////////
-//ElementController
-///////////////////////
-function BindUpdater(view, exp) {
- this.view = view;
- this.exp = Binder.parseBindings(exp);
- this.hasError = false;
-};
-
-BindUpdater.toText = function(obj) {
- var e = escapeHtml;
- switch(typeof obj) {
- case "string":
- case "boolean":
- case "number":
- return e(obj);
- case "function":
- return BindUpdater.toText(obj());
- case "object":
- if (isNode(obj)) {
- return outerHTML(obj);
- } else if (obj instanceof angular.filter.Meta) {
- switch(typeof obj.html) {
- case "string":
- case "number":
- return obj.html;
- case "function":
- return obj.html();
- case "object":
- if (isNode(obj.html))
- return outerHTML(obj.html);
- default:
- break;
- }
- switch(typeof obj.text) {
- case "string":
- case "number":
- return e(obj.text);
- case "function":
- return e(obj.text());
- default:
- break;
- }
- }
- if (obj === null)
- return "";
- return e(toJson(obj, true));
- default:
- return "";
- }
-};
-
-BindUpdater.prototype = {
- updateModel: noop,
- updateView: function(scope) {
- var html = [];
- var parts = this.exp;
- var length = parts.length;
- for(var i=0; i<length; i++) {
- var part = parts[i];
- var binding = Binder.binding(part);
- if (binding) {
- scope.evalWidget(this, binding, {$element:this.view}, function(value){
- html.push(BindUpdater.toText(value));
- }, function(e, text){
- setHtml(this.view, text);
- });
- if (this.hasError) {
- return;
- }
- } else {
- html.push(escapeHtml(part));
- }
- }
- setHtml(this.view, html.join(''));
- }
-};
-
-function BindAttrUpdater(view, attrs) {
- this.view = view;
- this.attrs = attrs;
-};
-
-BindAttrUpdater.prototype = {
- updateModel: noop,
- updateView: function(scope) {
- var jNode = jQuery(this.view);
- var attributeTemplates = this.attrs;
- if (this.hasError) {
- this.hasError = false;
- jNode.
- removeClass('ng-exception').
- removeAttr('ng-error');
- }
- var isImage = jNode.is('img');
- for (var attrName in attributeTemplates) {
- var attributeTemplate = Binder.parseBindings(attributeTemplates[attrName]);
- var attrValues = [];
- for ( var i = 0; i < attributeTemplate.length; i++) {
- var binding = Binder.binding(attributeTemplate[i]);
- if (binding) {
- try {
- var value = scope.eval(binding, {$element:jNode[0], attrName:attrName});
- if (value && (value.constructor !== array || value.length !== 0))
- attrValues.push(value);
- } catch (e) {
- this.hasError = true;
- error('BindAttrUpdater', e);
- var jsonError = toJson(e, true);
- attrValues.push('[' + jsonError + ']');
- jNode.
- addClass('ng-exception').
- attr('ng-error', jsonError);
- }
- } else {
- attrValues.push(attributeTemplate[i]);
- }
- }
- var attrValue = attrValues.length ? attrValues.join('') : null;
- if(isImage && attrName == 'src' && !attrValue)
- attrValue = scope.get('$config.blankImage');
- jNode.attr(attrName, attrValue);
- }
- }
-};
-
-function EvalUpdater(view, exp) {
- this.view = view;
- this.exp = exp;
- this.hasError = false;
-};
-EvalUpdater.prototype = {
- updateModel: noop,
- updateView: function(scope) {
- scope.evalWidget(this, this.exp);
- }
-};
-
-function HideUpdater(view, exp) { this.view = view; this.exp = exp; };
-HideUpdater.prototype = {
- updateModel: noop,
- updateView: function(scope) {
- scope.evalWidget(this, this.exp, {}, function(hideValue){
- var view = jQuery(this.view);
- if (toBoolean(hideValue)) {
- view.hide();
- } else {
- view.show();
- }
- });
- }
-};
-
-function ShowUpdater(view, exp) { this.view = view; this.exp = exp; };
-ShowUpdater.prototype = {
- updateModel: noop,
- updateView: function(scope) {
- scope.evalWidget(this, this.exp, {}, function(hideValue){
- var view = jQuery(this.view);
- if (toBoolean(hideValue)) {
- view.show();
- } else {
- view.hide();
- }
- });
- }
-};
-
-function ClassUpdater(view, exp) { this.view = view; this.exp = exp; };
-ClassUpdater.prototype = {
- updateModel: noop,
- updateView: function(scope) {
- scope.evalWidget(this, this.exp, {}, function(classValue){
- if (classValue !== null && classValue !== undefined) {
- this.view.className = classValue;
- }
- });
- }
-};
-
-function ClassEvenUpdater(view, exp) { this.view = view; this.exp = exp; };
-ClassEvenUpdater.prototype = {
- updateModel: noop,
- updateView: function(scope) {
- scope.evalWidget(this, this.exp, {}, function(classValue){
- var index = scope.get('$index');
- jQuery(this.view).toggleClass(classValue, index % 2 === 1);
- });
- }
-};
-
-function ClassOddUpdater(view, exp) { this.view = view; this.exp = exp; };
-ClassOddUpdater.prototype = {
- updateModel: noop,
- updateView: function(scope) {
- scope.evalWidget(this, this.exp, {}, function(classValue){
- var index = scope.get('$index');
- jQuery(this.view).toggleClass(classValue, index % 2 === 0);
- });
}
-};
-
-function StyleUpdater(view, exp) { this.view = view; this.exp = exp; };
-StyleUpdater.prototype = {
- updateModel: noop,
- updateView: function(scope) {
- scope.evalWidget(this, this.exp, {}, function(styleValue){
- jQuery(this.view).attr('style', "").css(styleValue);
- });
- }
-};
-
-///////////////////////
-// RepeaterUpdater
-///////////////////////
-function RepeaterUpdater(view, repeaterExpression, template, prefix) {
- this.view = view;
- this.template = template;
- this.prefix = prefix;
- this.children = [];
- var match = repeaterExpression.match(/^\s*(.+)\s+in\s+(.*)\s*$/);
- if (! match) {
- throw "Expected ng-repeat in form of 'item in collection' but got '" +
- repeaterExpression + "'.";
- }
- var keyValue = match[1];
- this.iteratorExp = match[2];
- match = keyValue.match(/^([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\)$/);
- if (!match) {
- throw "'item' in 'item in collection' should be identifier or (key, value) but get '" +
- keyValue + "'.";
- }
- this.valueExp = match[3] || match[1];
- this.keyExp = match[2];
-};
-
-RepeaterUpdater.prototype = {
- updateModel: noop,
- updateView: function(scope) {
- scope.evalWidget(this, this.iteratorExp, {}, function(iterator){
- var self = this;
- if (!iterator) {
- iterator = [];
- if (scope.isProperty(this.iteratorExp)) {
- scope.set(this.iteratorExp, iterator);
- }
- }
- var childrenLength = this.children.length;
- var cursor = this.view;
- var time = 0;
- var child = null;
- var keyExp = this.keyExp;
- var valueExp = this.valueExp;
- var iteratorCounter = 0;
- foreach(iterator, function(value, key){
- if (iteratorCounter < childrenLength) {
- // reuse children
- child = self.children[iteratorCounter];
- child.scope.set(valueExp, value);
- } else {
- // grow children
- var name = self.prefix +
- valueExp + " in " + self.iteratorExp + "[" + iteratorCounter + "]";
- var childScope = new Scope(scope.state, name);
- childScope.set('$index', iteratorCounter);
- if (keyExp)
- childScope.set(keyExp, key);
- childScope.set(valueExp, value);
- child = { scope:childScope, element:self.template(childScope, self.prefix, iteratorCounter) };
- cursor.after(child.element);
- self.children.push(child);
- }
- cursor = child.element;
- var s = new Date().getTime();
- child.scope.updateView();
- time += new Date().getTime() - s;
- iteratorCounter++;
+ 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];
});
- // shrink children
- for ( var r = childrenLength; r > iteratorCounter; --r) {
- this.children.pop().element.remove();
- }
- // Special case for option in select
- if (child && child.element[0].nodeName === "OPTION") {
- var select = jQuery(child.element[0].parentNode);
- var cntl = select.data('controller');
- if (cntl) {
- cntl.lastValue = undefined;
- cntl.updateView(scope);
- }
- }
- });
- }
-};
-
-//////////////////////////////////
-// PopUp
-//////////////////////////////////
-
-function PopUp(doc) {
- this.doc = doc;
-};
-
-PopUp.OUT_EVENT = "mouseleave mouseout click dblclick keypress keyup";
-
-PopUp.onOver = function(e) {
- PopUp.onOut();
- var jNode = jQuery(this);
- jNode.bind(PopUp.OUT_EVENT, PopUp.onOut);
- var position = jNode.position();
- var de = document.documentElement;
- var w = self.innerWidth || (de&&de.clientWidth) || document.body.clientWidth;
- var hasArea = w - position.left;
- var width = 300;
- var title = jNode.hasClass("ng-exception") ? "EXCEPTION:" : "Validation error...";
- var msg = jNode.attr("ng-error");
-
- var x;
- var arrowPos = hasArea>(width+75) ? "left" : "right";
- var tip = jQuery(
- "<div id='ng-callout' style='width:"+width+"px'>" +
- "<div class='ng-arrow-"+arrowPos+"'/>" +
- "<div class='ng-title'>"+title+"</div>" +
- "<div class='ng-content'>"+msg+"</div>" +
- "</div>");
- jQuery("body").append(tip);
- if(arrowPos === 'left'){
- x = position.left + this.offsetWidth + 11;
- }else{
- x = position.left - (width + 15);
- tip.find('.ng-arrow-right').css({left:width+1});
- }
-
- tip.css({left: x+"px", top: (position.top - 3)+"px"});
- return true;
-};
-
-PopUp.onOut = function() {
- jQuery('#ng-callout').
- unbind(PopUp.OUT_EVENT, PopUp.onOut).
- remove();
- return true;
-};
-
-PopUp.prototype = {
- bind: function () {
- var self = this;
- this.doc.find('.ng-validation-error,.ng-exception').
- live("mouseover", PopUp.onOver);
- }
-};
-
-//////////////////////////////////
-// Status
-//////////////////////////////////
-
-function NullStatus(body) {
-};
-
-NullStatus.prototype = {
- beginRequest:function(){},
- endRequest:function(){}
-};
-
-function Status(body) {
- this.requestCount = 0;
- this.body = body;
-};
-
-Status.DOM ='<div id="ng-spacer"></div><div id="ng-loading">loading....</div>';
-
-Status.prototype = {
- beginRequest: function () {
- if (this.requestCount === 0) {
- (this.loader = this.loader || this.body.append(Status.DOM).find("#ng-loading")).show();
}
- this.requestCount++;
- },
+ };
+}
+
+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???
+ };
- endRequest: function () {
- this.requestCount--;
- if (this.requestCount === 0) {
- this.loader.hide("fold");
- }
- }
-};
+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);
+});