diff options
| author | Misko Hevery | 2010-03-26 16:27:18 -0700 | 
|---|---|---|
| committer | Misko Hevery | 2010-03-26 16:27:18 -0700 | 
| commit | 258ca5f16581f0e8befa493644225a02ae2fc002 (patch) | |
| tree | a7d67c586fb5c870619664ca84e17996f6dd2e6d /src/Widgets.js | |
| parent | 1990cbbf2817e04657ccd616da1d9d6b78cc2949 (diff) | |
| download | angular.js-258ca5f16581f0e8befa493644225a02ae2fc002.tar.bz2 | |
moved all uneeded files out, widgets.html works, tests horribly broken
Diffstat (limited to 'src/Widgets.js')
| -rw-r--r-- | src/Widgets.js | 927 | 
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); +}); | 
