~ted/lazr-js/annoying-debug-message

« back to all changes in this revision

Viewing changes to src-js/lazrjs/yui/value-change/value-change.js

  • Committer: Launchpad Patch Queue Manager
  • Date: 2010-09-09 14:20:30 UTC
  • mfrom: (182.1.3 yui-3.2)
  • Revision ID: launchpad@pqm.canonical.com-20100909142030-13w6vo0ixfysxc15
[r=beuno] Update lazr-js to yui-3.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
Copyright (c) 2010, Yahoo! Inc. All rights reserved.
3
 
Code licensed under the BSD License:
4
 
http://developer.yahoo.com/yui/license.html
5
 
version: 3.1.2
6
 
build: 56
7
 
*/
8
 
YUI.add('value-change', function(Y) {
9
 
 
10
 
 
11
 
/**
12
 
 * <p>Event that fires when a text or input field has changed value as a result of a keystroke.
13
 
 * Attaches a timed-out listener on the keydown event, and keeps the value to provide support
14
 
 * for multi-keystroke character sets.</p>
15
 
 * <p>This event fires when the value of the element changes, either as a result of
16
 
 * a keystroke, or an IME input event.</p>
17
 
 * <p>This does not replace the DOM onchange event, but rather augments it to do onchange-like
18
 
 * logic as a result of key presses, even in multi-stroke character sets.</p>
19
 
 *
20
 
 * <p>Known issue: If attaching to elements that are not yet available, then only the first 
21
 
 * node will be guaranteed to have the event handler attached.</p>
22
 
 *
23
 
 * @event valueChange
24
 
 * @for YUI
25
 
 * @param type {String} 'valueChange'
26
 
 * @param fn {Function} the callback function
27
 
 * @param el {String|Node|etc} the element(s) to bind
28
 
 * @param o {Object} optional context object
29
 
 * @param args 0..n additional arguments that should be provided 
30
 
 * to the listener.
31
 
 * @return {Event.Handle} the detach handle
32
 
 **/
33
 
 
34
 
function toNodeList (el) { return (
35
 
    (Y.Lang.isString(el) || Y.Lang.isArray(el))
36
 
        ? Y.all(el)
37
 
    : (el instanceof Y.Node)
38
 
        ? Y.all([el._node])
39
 
    : (el instanceof Y.NodeList)
40
 
        ? el
41
 
    : Y.all([el])
42
 
)};
43
 
 
44
 
function onAvail (el, args) {
45
 
    var h = Y.on("available", function () {
46
 
        h.handle = Y.on.apply(Y, args);
47
 
    }, el);
48
 
    return h;
49
 
};
50
 
 
51
 
function attachProxy (node, args) {
52
 
    // args = [type, fn, el, o, ...]
53
 
    // node.on(type, fn, o, ...);
54
 
    args[0] = ceName(node);
55
 
    args.splice(2,1);
56
 
    
57
 
    // if event-custom is loaded, then this is gonna do something.
58
 
    // otherwise, it's basically just a no-op.
59
 
    node.publish(args[0], {
60
 
        broadcast : true,
61
 
        emitFacade : true
62
 
    });
63
 
 
64
 
    var registry = attachTriggers(node),
65
 
        proxyHandle = node.on.apply(node, args);
66
 
    
67
 
    return proxyHandle;
68
 
};
69
 
 
70
 
function ceName (node) {
71
 
    return Y.stamp(node) + "-" + eventName;
72
 
};
73
 
 
74
 
function attachDomEventHandlers (handlers, node) {
75
 
    var handles = {};
76
 
    for (var i in handlers) {
77
 
        handles[i] = handleDom(i, handlers[i], node);
78
 
    }
79
 
    return handles;
80
 
};
81
 
 
82
 
// attach the dom events that will trigger the CE
83
 
function attachTriggers (node) {
84
 
    var key = ceName(node);
85
 
    var reg = registry[ key ] = registry[ key ] || {
86
 
        count : 0,
87
 
        handles : attachDomEventHandlers(domEventHandlers, node)
88
 
    };
89
 
    reg.count++;
90
 
    return reg;
91
 
};
92
 
 
93
 
function handleDom (event, handler, node) {
94
 
    var handle = Y.on(event, handler, node);
95
 
    Y.after(Y.bind(afterDetach, null, node, true), handle, "detach");
96
 
    return handle;
97
 
};
98
 
 
99
 
// call this after detaching a CE handler
100
 
function afterDetach (node, force) {
101
 
    var reg = registry[ ceName(node) ];
102
 
    if (!reg) return;
103
 
    reg.count --;
104
 
    if (force) reg.count = 0;
105
 
    if (reg.count <= 0) {
106
 
        delete registry[ ceName(node) ];
107
 
        for (var i in reg.handles) reg.handles[i].detach();
108
 
    }
109
 
};
110
 
 
111
 
var registry = {},
112
 
    event = {
113
 
        on : function (type, fn, el, o) {
114
 
            var args = Y.Array(arguments, 0, true),
115
 
                nodeList = toNodeList(el);
116
 
            if (nodeList.size() === 0) return onAvail(el, args);
117
 
            
118
 
            args[3] = o = o || ((nodeList.size() === 1) ? nodeList.item(0) : nodeList);
119
 
            
120
 
            var handles = [];
121
 
            nodeList.each(function (node) {
122
 
                var proxyHandle = attachProxy(node, args);
123
 
                handles.push(proxyHandle);
124
 
                // hook into the detach event to remove it from that node.
125
 
                Y.after(Y.bind(afterDetach, null, node), proxyHandle, "detach");
126
 
            });
127
 
            // return a handle
128
 
            return { evt:handles, sub:nodeList, detach:function () {
129
 
                Y.Array.each(handles, function (h) { h.detach() });
130
 
            }};
131
 
        }
132
 
    },
133
 
    
134
 
    
135
 
    // IMPLEMENTATION SPECIFIC
136
 
    eventName = "valueChange",
137
 
    domEventHandlers = (function () {
138
 
        var valueHistory = {}, intervals = {}, timeouts = {};
139
 
        
140
 
        function startPolling (node, e) {
141
 
            var key = ceName(node);
142
 
            // avoid duplicates
143
 
            stopPolling(node);
144
 
            intervals[key] = setInterval(Y.bind(poller, null, node, e), 50);
145
 
            timeouts[key] = setTimeout(Y.bind(stopPolling, null, node), 10000);
146
 
        };
147
 
        function stopPolling (node) {
148
 
            var key = ceName(node);
149
 
            clearTimeout(timeouts[key]);
150
 
            clearInterval(intervals[key]);
151
 
        };
152
 
        function poller (node, e) {
153
 
            var key = ceName(node);
154
 
            var value = node.get("value");
155
 
            if (value === valueHistory[key]) return;
156
 
            node.fire(key, {
157
 
                type : eventName,
158
 
                value : value,
159
 
                oldValue : valueHistory[key],
160
 
                _event : e,
161
 
                target : node,
162
 
                currentTarget : node
163
 
            });
164
 
            
165
 
            valueHistory[key] = node.get("value");
166
 
            startPolling(node, e);
167
 
            
168
 
        };
169
 
        
170
 
        function keyUpHandler (e) {
171
 
            // indications that an IME has started.
172
 
            // poll for 10 seconds.
173
 
            if (e.charCode === 229 || e.charCode === 197) startPolling(
174
 
                e.currentTarget, e
175
 
            );
176
 
        };
177
 
        function blurHandler (e) {
178
 
            stopPolling(e.currentTarget);
179
 
        };
180
 
        function keyDownHandler (e) {
181
 
            startPolling(e.currentTarget, e);
182
 
        };
183
 
        
184
 
        return {
185
 
            keyup : keyUpHandler,
186
 
            blur : blurHandler,
187
 
            keydown : keyDownHandler
188
 
        };
189
 
    })();
190
 
    // /IMPLEMENTATION SPECIFIC
191
 
    
192
 
 
193
 
 
194
 
Y.Env.evt.plugins[eventName] = event;
195
 
if (Y.Node) Y.Node.DOM_EVENTS[eventName] = event;
196
 
 
197
 
 
198
 
}, '3.1.2' ,{optional:['event-custom'], requires:['node-base', 'event-focus']});