-
Notifications
You must be signed in to change notification settings - Fork 7
/
jquery.inputevent.js
138 lines (122 loc) · 5.06 KB
/
jquery.inputevent.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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
/*
jQuery `input` special event v1.2
http://whattheheadsaid.com/projects/input-special-event
(c) 2010-2011 Andy Earnshaw
forked by dodo (https://github.com/dodo)
MIT license
www.opensource.org/licenses/mit-license.php
*/
(function($, udf) {
var ns = ".inputEvent ",
// A bunch of data strings that we use regularly
dataBnd = "bound.inputEvent",
dataVal = "value.inputEvent",
dataDlg = "delegated.inputEvent",
// Set up our list of events
bindTo = [
"input", "textInput",
"propertychange",
"paste", "cut",
"keydown", "keyup",
"drop",
""].join(ns),
// Events required for delegate, mostly for IE support
dlgtTo = [ "focusin", "mouseover", "dragstart", "" ].join(ns) + bindTo,
// Elements supporting text input, not including contentEditable
supported = {TEXTAREA:udf, INPUT:udf},
// Events that fire before input value is updated
delay = { paste:udf, cut:udf, keydown:udf, drop:udf, textInput:udf };
// this checks if the tag is supported or has the contentEditable property
function isSupported(elem) {
return $(elem).prop('contenteditable') == "true" ||
elem.tagName in supported;
};
$.event.special.txtinput = {
setup: function(data, namespaces, handler, onChangeOnly) {
var timer,
bndCount,
// Get references to the element
elem = this,
$elem = $(this),
triggered = false;
if (isSupported(elem)) {
bndCount = $.data(elem, dataBnd) || 0;
if (!bndCount)
$elem.bind(bindTo, handler);
$.data(elem, dataBnd, ++bndCount);
$.data(elem, dataVal, elem.value);
} else {
$elem.bind(dlgtTo, function (e) {
var target = e.target;
if (isSupported(target) && !$.data(elem, dataDlg)) {
bndCount = $.data(target, dataBnd) || 0;
if (!bndCount) {
$(target).bind(bindTo, handler);
handler.apply(this, arguments);
}
// make sure we increase the count only once for each bound ancestor
$.data(elem, dataDlg, true);
$.data(target, dataBnd, ++bndCount);
$.data(target, dataVal, target.value);
}
});
}
function handler (e) {
var elem = e.target;
// Clear previous timers because we only need to know about 1 change
window.clearTimeout(timer), timer = null;
// Return if we've already triggered the event
if (triggered)
return;
// paste, cut, keydown and drop all fire before the value is updated
if (e.type in delay && !timer) {
// ...so we need to delay them until after the event has fired
timer = window.setTimeout(function () {
if (elem.value !== $.data(elem, dataVal)) {
$(elem).trigger("txtinput");
$.data(elem, dataVal, elem.value);
}
}, 0);
}
else if (e.type == "propertychange") {
if (e.originalEvent.propertyName == "value") {
$(elem).trigger("txtinput");
$.data(elem, dataVal, elem.value);
triggered = true;
window.setTimeout(function () {
triggered = false;
}, 0);
}
}
else {
var change = onChangeOnly !== undefined ? onChangeOnly :
$.fn.input.settings.onChangeOnly;
if ($.data(elem, dataVal) == elem.value && change)
return;
$(elem).trigger("txtinput");
$.data(elem, dataVal, elem.value);
triggered = true;
window.setTimeout(function () {
triggered = false;
}, 0);
}
}
},
teardown: function () {
var elem = $(this);
elem.unbind(dlgtTo);
elem.find("input, textarea").andSelf().each(function () {
bndCount = $.data(this, dataBnd, ($.data(this, dataBnd) || 1)-1);
if (!bndCount)
elem.unbind(bindTo);
});
}
};
// Setup our jQuery shorthand method
$.fn.input = function (handler) {
return handler ? $(this).bind("txtinput", handler) : this.trigger("txtinput");
}
$.fn.input.settings = {
onChangeOnly: false
};
})(jQuery);