Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
YUI.add('widget-uievents', function (Y, NAME) {
2
 
3
/**
4
 * Support for Widget UI Events (Custom Events fired by the widget, which wrap the underlying DOM events - e.g. widget:click, widget:mousedown)
5
 *
6
 * @module widget
7
 * @submodule widget-uievents
8
 */
9
 
10
var BOUNDING_BOX = "boundingBox",
11
    Widget = Y.Widget,
12
    RENDER = "render",
13
    L = Y.Lang,
14
    EVENT_PREFIX_DELIMITER = ":",
15
 
16
    //  Map of Node instances serving as a delegation containers for a specific
17
    //  event type to Widget instances using that delegation container.
18
    _uievts = Y.Widget._uievts = Y.Widget._uievts || {};
19
 
20
Y.mix(Widget.prototype, {
21
 
22
    /**
23
     * Destructor logic for UI event infrastructure,
24
     * invoked during Widget destruction.
25
     *
26
     * @method _destroyUIEvents
27
     * @for Widget
28
     * @private
29
     */
30
    _destroyUIEvents: function() {
31
 
32
        var widgetGuid = Y.stamp(this, true);
33
 
34
        Y.each(_uievts, function (info, key) {
35
            if (info.instances[widgetGuid]) {
36
                //  Unregister this Widget instance as needing this delegated
37
                //  event listener.
38
                delete info.instances[widgetGuid];
39
 
40
                //  There are no more Widget instances using this delegated
41
                //  event listener, so detach it.
42
 
43
                if (Y.Object.isEmpty(info.instances)) {
44
                    info.handle.detach();
45
 
46
                    if (_uievts[key]) {
47
                        delete _uievts[key];
48
                    }
49
                }
50
            }
51
        });
52
    },
53
 
54
    /**
55
     * Map of DOM events that should be fired as Custom Events by the
56
     * Widget instance.
57
     *
58
     * @property UI_EVENTS
59
     * @for Widget
60
     * @type Object
61
     */
62
    UI_EVENTS: Y.Node.DOM_EVENTS,
63
 
64
    /**
65
     * Returns the node on which to bind delegate listeners.
66
     *
67
     * @method _getUIEventNode
68
     * @for Widget
69
     * @protected
70
     */
71
    _getUIEventNode: function () {
72
        return this.get(BOUNDING_BOX);
73
    },
74
 
75
    /**
76
     * Binds a delegated DOM event listener of the specified type to the
77
     * Widget's outtermost DOM element to facilitate the firing of a Custom
78
     * Event of the same type for the Widget instance.
79
     *
80
     * @method _createUIEvent
81
     * @for Widget
82
     * @param type {String} String representing the name of the event
83
     * @private
84
     */
85
    _createUIEvent: function (type) {
86
 
87
        var uiEvtNode = this._getUIEventNode(),
88
            key = (Y.stamp(uiEvtNode) + type),
89
            info = _uievts[key],
90
            handle;
91
 
92
        //  For each Node instance: Ensure that there is only one delegated
93
        //  event listener used to fire Widget UI events.
94
 
95
        if (!info) {
96
 
97
            handle = uiEvtNode.delegate(type, function (evt) {
98
 
99
                var widget = Widget.getByNode(this);
100
 
101
                // Widget could be null if node instance belongs to
102
                // another Y instance.
103
 
104
                if (widget) {
105
                    if (widget._filterUIEvent(evt)) {
106
                        widget.fire(evt.type, { domEvent: evt });
107
                    }
108
                }
109
 
110
            }, "." + Y.Widget.getClassName());
111
 
112
            _uievts[key] = info = { instances: {}, handle: handle };
113
        }
114
 
115
        //  Register this Widget as using this Node as a delegation container.
116
        info.instances[Y.stamp(this)] = 1;
117
    },
118
 
119
    /**
120
     * This method is used to determine if we should fire
121
     * the UI Event or not. The default implementation makes sure
122
     * that for nested delegates (nested unrelated widgets), we don't
123
     * fire the UI event listener more than once at each level.
124
     *
125
     * <p>For example, without the additional filter, if you have nested
126
     * widgets, each widget will have a delegate listener. If you
127
     * click on the inner widget, the inner delegate listener's
128
     * filter will match once, but the outer will match twice
129
     * (based on delegate's design) - once for the inner widget,
130
     * and once for the outer.</p>
131
     *
132
     * @method _filterUIEvent
133
     * @for Widget
134
     * @param {DOMEventFacade} evt
135
     * @return {boolean} true if it's OK to fire the custom UI event, false if not.
136
     * @private
137
     *
138
     */
139
    _filterUIEvent: function(evt) {
140
        // Either it's hitting this widget's delegate container (and not some other widget's),
141
        // or the container it's hitting is handling this widget's ui events.
142
        return (evt.currentTarget.compareTo(evt.container) || evt.container.compareTo(this._getUIEventNode()));
143
    },
144
 
145
    /**
146
     * Determines if the specified event is a UI event.
147
     *
148
     * @private
149
     * @method _isUIEvent
150
     * @for Widget
151
     * @param type {String} String representing the name of the event
152
     * @return {String} Event Returns the name of the UI Event, otherwise
153
     * undefined.
154
     */
155
    _getUIEvent: function (type) {
156
 
157
        if (L.isString(type)) {
158
            var sType = this.parseType(type)[1],
159
                iDelim,
160
                returnVal;
161
 
162
            if (sType) {
163
                // TODO: Get delimiter from ET, or have ET support this.
164
                iDelim = sType.indexOf(EVENT_PREFIX_DELIMITER);
165
                if (iDelim > -1) {
166
                    sType = sType.substring(iDelim + EVENT_PREFIX_DELIMITER.length);
167
                }
168
 
169
                if (this.UI_EVENTS[sType]) {
170
                    returnVal = sType;
171
                }
172
            }
173
 
174
            return returnVal;
175
        }
176
    },
177
 
178
    /**
179
     * Sets up infrastructure required to fire a UI event.
180
     *
181
     * @private
182
     * @method _initUIEvent
183
     * @for Widget
184
     * @param type {String} String representing the name of the event
185
     * @return {String}
186
     */
187
    _initUIEvent: function (type) {
188
        var sType = this._getUIEvent(type),
189
            queue = this._uiEvtsInitQueue || {};
190
 
191
        if (sType && !queue[sType]) {
192
            Y.log("Deferring creation of " + type + " delegate until render.", "info", "widget");
193
 
194
            this._uiEvtsInitQueue = queue[sType] = 1;
195
 
196
            this.after(RENDER, function() {
197
                this._createUIEvent(sType);
198
                delete this._uiEvtsInitQueue[sType];
199
            });
200
        }
201
    },
202
 
203
    //  Override of "on" from Base to facilitate the firing of Widget events
204
    //  based on DOM events of the same name/type (e.g. "click", "mouseover").
205
    //  Temporary solution until we have the ability to listen to when
206
    //  someone adds an event listener (bug 2528230)
207
    on: function (type) {
208
        this._initUIEvent(type);
209
        return Widget.superclass.on.apply(this, arguments);
210
    },
211
 
212
    //  Override of "publish" from Base to facilitate the firing of Widget events
213
    //  based on DOM events of the same name/type (e.g. "click", "mouseover").
214
    //  Temporary solution until we have the ability to listen to when
215
    //  someone publishes an event (bug 2528230)
216
    publish: function (type, config) {
217
        var sType = this._getUIEvent(type);
218
        if (sType && config && config.defaultFn) {
219
            this._initUIEvent(sType);
220
        }
221
        return Widget.superclass.publish.apply(this, arguments);
222
    }
223
 
224
}, true); // overwrite existing EventTarget methods
225
 
226
 
227
}, '3.18.1', {"requires": ["node-event-delegate", "widget-base"]});