aboutsummaryrefslogtreecommitdiffstats
path: root/src/widgets2.js
blob: b67694b16b8855fcb30dd37a8db98b733d6f61d5 (plain)
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
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 valueAccessor(element) {
  var validatorName = element.attr('ng-validate') || NOOP,
      validator = angularValidator(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(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 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':      [null,  'change'],
//      'select-multiple': [[],    'change'],
//      'file':            [{},    'click']
    };

function inputWidget(events, modelAccessor, viewAccessor, initValue) {
  return function(element) {
    var scope = this,
        model = modelAccessor(scope, element),
        view = viewAccessor(element),
        action = element.attr('ng-action') || '';
    var value = view.get() || initValue;
    if (isDefined(value)) model.set(value);
    element.bind(events, function(){
      model.set(view.get());
      scope.$eval(action);
    });
    scope.$watch(model.get, view.set);
  };
}

angularWidget('INPUT', function input(element){
  return function(element) {
    this.$eval(element.attr('ng-init')||'');
    (INPUT_TYPE[lowercase(element[0].type)] || noop).call(this, element);
  };
});

angularWidget('TEXTAREA', function(){
  return textWidget;
});