forked from ibm-js/delite
-
Notifications
You must be signed in to change notification settings - Fork 0
/
FormValueWidget.js
123 lines (116 loc) · 4.06 KB
/
FormValueWidget.js
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
/** @module delite/FormValueWidget */
define([
"dcl/dcl",
"./FormWidget",
"./focus"
], function (dcl, FormWidget) {
/**
* Returns a method to set a new value and fire an event (change or input) if the value changed since the last
* call. Widget should use `handleOnChange()` or `handleOnInput()`.
* @param {string} eventType - The event type. Can be "change" or "input".
* @param {string} prevValueProp - The name of the property to hold the previous value.
* @param {string} deferHandleProp - The name of the property to hold the defer method that fire the event.
* @returns {Function}
* @private
*/
function genHandler(eventType, prevValueProp, deferHandleProp) {
// Set value and fire an input event if the value changed since the last call.
// @param {*} newValue - The new value.
return function (newValue) {
if ((typeof newValue !== typeof this[prevValueProp]) ||
(this.compare(newValue, this[prevValueProp]) !== 0)) {
this[prevValueProp] = this.value = newValue;
if (this[deferHandleProp]) {
this[deferHandleProp].remove();
}
// defer allows hidden value processing to run and
// also the onChange handler can safely adjust focus, etc
this[deferHandleProp] = this.defer(function () {
this[deferHandleProp] = null;
// make sure rendering is in sync when event handlers are called
this.deliver();
this.emit(eventType);
});
}
};
}
/**
* Mixin for widgets corresponding to native HTML elements such as `<input>` or `<select>`
* that have user changeable values.
*
* Each FormValueWidget represents a single input value, and has a (possibly hidden) `<input>` element,
* to which it serializes its input value, so that form submission works as expected.
*
* The subclass should call `handleOnChange()` and `handleOnInput()` to make the widget fire `change` and
* `input`events as the value changes.
*
* @mixin module:delite/FormValueWidget
* @augments module:delite/FormWidget
*/
return dcl(FormWidget, /** @lends module:delite/FormValueWidget# */{
/**
* If true, this widget won't respond to user input.
* Similar to disabled except readOnly form values are submitted.
* @member {boolean}
* @default false
*/
readOnly: false,
refreshRendering: function (oldValues) {
if ("readOnly" in oldValues) {
var isReadOnly = this.readOnly;
if (this.valueNode && this.valueNode !== this) {
this.valueNode.readOnly = isReadOnly; // inform screen reader
}
if (!isReadOnly) {
this.removeAttribute("readonly");
}
}
},
/**
* Compare two values (of this widget).
* @param {*} val1
* @param {*} val2
* @returns {number}
* @protected
*/
compare: function (val1, val2) {
if (typeof val1 === "number" && typeof val2 === "number") {
return (isNaN(val1) && isNaN(val2)) ? 0 : val1 - val2;
} else if (val1 > val2) {
return 1;
} else if (val1 < val2) {
return -1;
} else {
return 0;
}
},
_onFocus: dcl.superCall(function (sup) {
return function () {
// Called when user may be about to start input.
// Saves the widget's current value, which is the most recent of:
//
// 1. the original value set on widget construction
// 2. the value the user set when he previously used the widget
// 3. the value the application set programatically
//
// This is all to avoid firing unnecessary change/input events in the corner case where the
// user just selects and releases the Slider handle for example.
sup.call(this);
this._previousOnChangeValue = this.value;
this._previousOnInputValue = this.value;
};
}),
/**
* Set value and fire a change event if the value changed since the last call.
* @param {*} newValue - The new value.
* @protected
*/
handleOnChange: genHandler("change", "_previousOnChangeValue", "_onChangeHandle"),
/**
* Set value and fire an input event if the value changed since the last call.
* @param {*} newValue - The new value.
* @protected
*/
handleOnInput: genHandler("input", "_previousOnInputValue", "_onInputHandle")
});
});