]>
Commit | Line | Data |
---|---|---|
2f01fe57 | 1 | /* |
81bea17a | 2 | Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved. |
2f01fe57 AD |
3 | Available via Academic Free License >= 2.1 OR the modified BSD license. |
4 | see: http://dojotoolkit.org/license for details | |
5 | */ | |
6 | ||
7 | ||
81bea17a AD |
8 | if(!dojo._hasResource["dijit._Widget"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
9 | dojo._hasResource["dijit._Widget"] = true; | |
2f01fe57 | 10 | dojo.provide("dijit._Widget"); |
81bea17a | 11 | dojo.require("dijit._WidgetBase"); |
2f01fe57 | 12 | dojo.require("dijit._base"); |
81bea17a AD |
13 | |
14 | ||
15 | ||
16 | ////////////////// DEFERRED CONNECTS /////////////////// | |
17 | ||
18 | // This code is to assist deferring dojo.connect() calls in widgets (connecting to events on the widgets' | |
19 | // DOM nodes) until someone actually needs to monitor that event. | |
20 | dojo.connect(dojo, "_connect", | |
21 | function(/*dijit._Widget*/ widget, /*String*/ event){ | |
22 | if(widget && dojo.isFunction(widget._onConnect)){ | |
23 | widget._onConnect(event); | |
24 | } | |
25 | }); | |
26 | ||
27 | dijit._connectOnUseEventHandler = function(/*Event*/ event){}; | |
28 | ||
29 | ////////////////// ONDIJITCLICK SUPPORT /////////////////// | |
30 | ||
31 | // Keep track of where the last keydown event was, to help avoid generating | |
32 | // spurious ondijitclick events when: | |
33 | // 1. focus is on a <button> or <a> | |
34 | // 2. user presses then releases the ENTER key | |
35 | // 3. onclick handler fires and shifts focus to another node, with an ondijitclick handler | |
36 | // 4. onkeyup event fires, causing the ondijitclick handler to fire | |
37 | dijit._lastKeyDownNode = null; | |
2f01fe57 | 38 | if(dojo.isIE){ |
81bea17a AD |
39 | (function(){ |
40 | var keydownCallback = function(evt){ | |
41 | dijit._lastKeyDownNode = evt.srcElement; | |
42 | }; | |
43 | dojo.doc.attachEvent('onkeydown', keydownCallback); | |
44 | dojo.addOnWindowUnload(function(){ | |
45 | dojo.doc.detachEvent('onkeydown', keydownCallback); | |
46 | }); | |
47 | })(); | |
2f01fe57 | 48 | }else{ |
81bea17a AD |
49 | dojo.doc.addEventListener('keydown', function(evt){ |
50 | dijit._lastKeyDownNode = evt.target; | |
51 | }, true); | |
2f01fe57 | 52 | } |
81bea17a | 53 | |
2f01fe57 | 54 | (function(){ |
81bea17a AD |
55 | |
56 | dojo.declare("dijit._Widget", dijit._WidgetBase, { | |
57 | // summary: | |
58 | // Base class for all Dijit widgets. | |
59 | // | |
60 | // Extends _WidgetBase, adding support for: | |
61 | // - deferred connections | |
62 | // A call like dojo.connect(myWidget, "onMouseMove", func) | |
63 | // will essentially do a dojo.connect(myWidget.domNode, "onMouseMove", func) | |
64 | // - ondijitclick | |
65 | // Support new dojoAttachEvent="ondijitclick: ..." that is triggered by a mouse click or a SPACE/ENTER keypress | |
66 | // - focus related functions | |
67 | // In particular, the onFocus()/onBlur() callbacks. Driven internally by | |
68 | // dijit/_base/focus.js. | |
69 | // - deprecated methods | |
70 | // - onShow(), onHide(), onClose() | |
71 | // | |
72 | // Also, by loading code in dijit/_base, turns on: | |
73 | // - browser sniffing (putting browser id like .dj_ie on <html> node) | |
74 | // - high contrast mode sniffing (add .dijit_a11y class to <body> if machine is in high contrast mode) | |
75 | ||
76 | ||
77 | ////////////////// DEFERRED CONNECTS /////////////////// | |
78 | ||
79 | // _deferredConnects: [protected] Object | |
80 | // attributeMap addendum for event handlers that should be connected only on first use | |
81 | _deferredConnects: { | |
82 | onClick: "", | |
83 | onDblClick: "", | |
84 | onKeyDown: "", | |
85 | onKeyPress: "", | |
86 | onKeyUp: "", | |
87 | onMouseMove: "", | |
88 | onMouseDown: "", | |
89 | onMouseOut: "", | |
90 | onMouseOver: "", | |
91 | onMouseLeave: "", | |
92 | onMouseEnter: "", | |
93 | onMouseUp: "" | |
94 | }, | |
95 | ||
96 | onClick: dijit._connectOnUseEventHandler, | |
97 | /*===== | |
98 | onClick: function(event){ | |
99 | // summary: | |
100 | // Connect to this function to receive notifications of mouse click events. | |
101 | // event: | |
102 | // mouse Event | |
103 | // tags: | |
104 | // callback | |
105 | }, | |
106 | =====*/ | |
107 | onDblClick: dijit._connectOnUseEventHandler, | |
108 | /*===== | |
109 | onDblClick: function(event){ | |
110 | // summary: | |
111 | // Connect to this function to receive notifications of mouse double click events. | |
112 | // event: | |
113 | // mouse Event | |
114 | // tags: | |
115 | // callback | |
116 | }, | |
117 | =====*/ | |
118 | onKeyDown: dijit._connectOnUseEventHandler, | |
119 | /*===== | |
120 | onKeyDown: function(event){ | |
121 | // summary: | |
122 | // Connect to this function to receive notifications of keys being pressed down. | |
123 | // event: | |
124 | // key Event | |
125 | // tags: | |
126 | // callback | |
127 | }, | |
128 | =====*/ | |
129 | onKeyPress: dijit._connectOnUseEventHandler, | |
130 | /*===== | |
131 | onKeyPress: function(event){ | |
132 | // summary: | |
133 | // Connect to this function to receive notifications of printable keys being typed. | |
134 | // event: | |
135 | // key Event | |
136 | // tags: | |
137 | // callback | |
138 | }, | |
139 | =====*/ | |
140 | onKeyUp: dijit._connectOnUseEventHandler, | |
141 | /*===== | |
142 | onKeyUp: function(event){ | |
143 | // summary: | |
144 | // Connect to this function to receive notifications of keys being released. | |
145 | // event: | |
146 | // key Event | |
147 | // tags: | |
148 | // callback | |
149 | }, | |
150 | =====*/ | |
151 | onMouseDown: dijit._connectOnUseEventHandler, | |
152 | /*===== | |
153 | onMouseDown: function(event){ | |
154 | // summary: | |
155 | // Connect to this function to receive notifications of when the mouse button is pressed down. | |
156 | // event: | |
157 | // mouse Event | |
158 | // tags: | |
159 | // callback | |
160 | }, | |
161 | =====*/ | |
162 | onMouseMove: dijit._connectOnUseEventHandler, | |
163 | /*===== | |
164 | onMouseMove: function(event){ | |
165 | // summary: | |
166 | // Connect to this function to receive notifications of when the mouse moves over nodes contained within this widget. | |
167 | // event: | |
168 | // mouse Event | |
169 | // tags: | |
170 | // callback | |
171 | }, | |
172 | =====*/ | |
173 | onMouseOut: dijit._connectOnUseEventHandler, | |
174 | /*===== | |
175 | onMouseOut: function(event){ | |
176 | // summary: | |
177 | // Connect to this function to receive notifications of when the mouse moves off of nodes contained within this widget. | |
178 | // event: | |
179 | // mouse Event | |
180 | // tags: | |
181 | // callback | |
182 | }, | |
183 | =====*/ | |
184 | onMouseOver: dijit._connectOnUseEventHandler, | |
185 | /*===== | |
186 | onMouseOver: function(event){ | |
187 | // summary: | |
188 | // Connect to this function to receive notifications of when the mouse moves onto nodes contained within this widget. | |
189 | // event: | |
190 | // mouse Event | |
191 | // tags: | |
192 | // callback | |
193 | }, | |
194 | =====*/ | |
195 | onMouseLeave: dijit._connectOnUseEventHandler, | |
196 | /*===== | |
197 | onMouseLeave: function(event){ | |
198 | // summary: | |
199 | // Connect to this function to receive notifications of when the mouse moves off of this widget. | |
200 | // event: | |
201 | // mouse Event | |
202 | // tags: | |
203 | // callback | |
204 | }, | |
205 | =====*/ | |
206 | onMouseEnter: dijit._connectOnUseEventHandler, | |
207 | /*===== | |
208 | onMouseEnter: function(event){ | |
209 | // summary: | |
210 | // Connect to this function to receive notifications of when the mouse moves onto this widget. | |
211 | // event: | |
212 | // mouse Event | |
213 | // tags: | |
214 | // callback | |
215 | }, | |
216 | =====*/ | |
217 | onMouseUp: dijit._connectOnUseEventHandler, | |
218 | /*===== | |
219 | onMouseUp: function(event){ | |
220 | // summary: | |
221 | // Connect to this function to receive notifications of when the mouse button is released. | |
222 | // event: | |
223 | // mouse Event | |
224 | // tags: | |
225 | // callback | |
226 | }, | |
227 | =====*/ | |
228 | ||
229 | create: function(/*Object?*/params, /*DomNode|String?*/srcNodeRef){ | |
230 | // To avoid double-connects, remove entries from _deferredConnects | |
231 | // that have been setup manually by a subclass (ex, by dojoAttachEvent). | |
232 | // If a subclass has redefined a callback (ex: onClick) then assume it's being | |
233 | // connected to manually. | |
234 | this._deferredConnects = dojo.clone(this._deferredConnects); | |
235 | for(var attr in this.attributeMap){ | |
236 | delete this._deferredConnects[attr]; // can't be in both attributeMap and _deferredConnects | |
237 | } | |
238 | for(attr in this._deferredConnects){ | |
239 | if(this[attr] !== dijit._connectOnUseEventHandler){ | |
240 | delete this._deferredConnects[attr]; // redefined, probably dojoAttachEvent exists | |
241 | } | |
242 | } | |
243 | ||
244 | this.inherited(arguments); | |
245 | ||
246 | if(this.domNode){ | |
247 | // If the developer has specified a handler as a widget parameter | |
248 | // (ex: new Button({onClick: ...}) | |
249 | // then naturally need to connect from DOM node to that handler immediately, | |
250 | for(attr in this.params){ | |
251 | this._onConnect(attr); | |
252 | } | |
253 | } | |
254 | }, | |
255 | ||
256 | _onConnect: function(/*String*/ event){ | |
257 | // summary: | |
258 | // Called when someone connects to one of my handlers. | |
259 | // "Turn on" that handler if it isn't active yet. | |
260 | // | |
261 | // This is also called for every single initialization parameter | |
262 | // so need to do nothing for parameters like "id". | |
263 | // tags: | |
264 | // private | |
265 | if(event in this._deferredConnects){ | |
266 | var mapNode = this[this._deferredConnects[event] || 'domNode']; | |
267 | this.connect(mapNode, event.toLowerCase(), event); | |
268 | delete this._deferredConnects[event]; | |
269 | } | |
270 | }, | |
271 | ||
272 | ////////////////// FOCUS RELATED /////////////////// | |
273 | // _onFocus() and _onBlur() are called by the focus manager | |
274 | ||
275 | // focused: [readonly] Boolean | |
276 | // This widget or a widget it contains has focus, or is "active" because | |
277 | // it was recently clicked. | |
278 | focused: false, | |
279 | ||
280 | isFocusable: function(){ | |
281 | // summary: | |
282 | // Return true if this widget can currently be focused | |
283 | // and false if not | |
284 | return this.focus && (dojo.style(this.domNode, "display") != "none"); | |
285 | }, | |
286 | ||
287 | onFocus: function(){ | |
288 | // summary: | |
289 | // Called when the widget becomes "active" because | |
290 | // it or a widget inside of it either has focus, or has recently | |
291 | // been clicked. | |
292 | // tags: | |
293 | // callback | |
294 | }, | |
295 | ||
296 | onBlur: function(){ | |
297 | // summary: | |
298 | // Called when the widget stops being "active" because | |
299 | // focus moved to something outside of it, or the user | |
300 | // clicked somewhere outside of it, or the widget was | |
301 | // hidden. | |
302 | // tags: | |
303 | // callback | |
304 | }, | |
305 | ||
306 | _onFocus: function(e){ | |
307 | // summary: | |
308 | // This is where widgets do processing for when they are active, | |
309 | // such as changing CSS classes. See onFocus() for more details. | |
310 | // tags: | |
311 | // protected | |
312 | this.onFocus(); | |
313 | }, | |
314 | ||
315 | _onBlur: function(){ | |
316 | // summary: | |
317 | // This is where widgets do processing for when they stop being active, | |
318 | // such as changing CSS classes. See onBlur() for more details. | |
319 | // tags: | |
320 | // protected | |
321 | this.onBlur(); | |
322 | }, | |
323 | ||
324 | ////////////////// DEPRECATED METHODS /////////////////// | |
325 | ||
326 | setAttribute: function(/*String*/ attr, /*anything*/ value){ | |
327 | // summary: | |
328 | // Deprecated. Use set() instead. | |
329 | // tags: | |
330 | // deprecated | |
331 | dojo.deprecated(this.declaredClass+"::setAttribute(attr, value) is deprecated. Use set() instead.", "", "2.0"); | |
332 | this.set(attr, value); | |
333 | }, | |
334 | ||
335 | attr: function(/*String|Object*/name, /*Object?*/value){ | |
336 | // summary: | |
337 | // Set or get properties on a widget instance. | |
338 | // name: | |
339 | // The property to get or set. If an object is passed here and not | |
340 | // a string, its keys are used as names of attributes to be set | |
341 | // and the value of the object as values to set in the widget. | |
342 | // value: | |
343 | // Optional. If provided, attr() operates as a setter. If omitted, | |
344 | // the current value of the named property is returned. | |
345 | // description: | |
346 | // This method is deprecated, use get() or set() directly. | |
347 | ||
348 | // Print deprecation warning but only once per calling function | |
349 | if(dojo.config.isDebug){ | |
350 | var alreadyCalledHash = arguments.callee._ach || (arguments.callee._ach = {}), | |
351 | caller = (arguments.callee.caller || "unknown caller").toString(); | |
352 | if(!alreadyCalledHash[caller]){ | |
353 | dojo.deprecated(this.declaredClass + "::attr() is deprecated. Use get() or set() instead, called from " + | |
354 | caller, "", "2.0"); | |
355 | alreadyCalledHash[caller] = true; | |
356 | } | |
357 | } | |
358 | ||
359 | var args = arguments.length; | |
360 | if(args >= 2 || typeof name === "object"){ // setter | |
361 | return this.set.apply(this, arguments); | |
362 | }else{ // getter | |
363 | return this.get(name); | |
364 | } | |
365 | }, | |
366 | ||
367 | ////////////////// ONDIJITCLICK SUPPORT /////////////////// | |
368 | ||
369 | // nodesWithKeyClick: [private] String[] | |
370 | // List of nodes that correctly handle click events via native browser support, | |
371 | // and don't need dijit's help | |
372 | nodesWithKeyClick: ["input", "button"], | |
373 | ||
374 | connect: function( | |
375 | /*Object|null*/ obj, | |
376 | /*String|Function*/ event, | |
377 | /*String|Function*/ method){ | |
378 | // summary: | |
379 | // Connects specified obj/event to specified method of this object | |
380 | // and registers for disconnect() on widget destroy. | |
381 | // description: | |
382 | // Provide widget-specific analog to dojo.connect, except with the | |
383 | // implicit use of this widget as the target object. | |
384 | // This version of connect also provides a special "ondijitclick" | |
385 | // event which triggers on a click or space or enter keyup. | |
386 | // Events connected with `this.connect` are disconnected upon | |
387 | // destruction. | |
388 | // returns: | |
389 | // A handle that can be passed to `disconnect` in order to disconnect before | |
390 | // the widget is destroyed. | |
391 | // example: | |
392 | // | var btn = new dijit.form.Button(); | |
393 | // | // when foo.bar() is called, call the listener we're going to | |
394 | // | // provide in the scope of btn | |
395 | // | btn.connect(foo, "bar", function(){ | |
396 | // | console.debug(this.toString()); | |
397 | // | }); | |
398 | // tags: | |
399 | // protected | |
400 | ||
401 | var d = dojo, | |
402 | dc = d._connect, | |
403 | handles = this.inherited(arguments, [obj, event == "ondijitclick" ? "onclick" : event, method]); | |
404 | ||
405 | if(event == "ondijitclick"){ | |
406 | // add key based click activation for unsupported nodes. | |
407 | // do all processing onkey up to prevent spurious clicks | |
408 | // for details see comments at top of this file where _lastKeyDownNode is defined | |
409 | if(d.indexOf(this.nodesWithKeyClick, obj.nodeName.toLowerCase()) == -1){ // is NOT input or button | |
410 | var m = d.hitch(this, method); | |
411 | handles.push( | |
412 | dc(obj, "onkeydown", this, function(e){ | |
413 | //console.log(this.id + ": onkeydown, e.target = ", e.target, ", lastKeyDownNode was ", dijit._lastKeyDownNode, ", equality is ", (e.target === dijit._lastKeyDownNode)); | |
414 | if((e.keyCode == d.keys.ENTER || e.keyCode == d.keys.SPACE) && | |
415 | !e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey){ | |
416 | // needed on IE for when focus changes between keydown and keyup - otherwise dropdown menus do not work | |
417 | dijit._lastKeyDownNode = e.target; | |
418 | ||
419 | // Stop event to prevent scrolling on space key in IE. | |
420 | // But don't do this for _HasDropDown because it surpresses the onkeypress | |
421 | // event needed to open the drop down when the user presses the SPACE key. | |
422 | if(!("openDropDown" in this && obj == this._buttonNode)){ | |
423 | e.preventDefault(); | |
424 | } | |
425 | } | |
426 | }), | |
427 | dc(obj, "onkeyup", this, function(e){ | |
428 | //console.log(this.id + ": onkeyup, e.target = ", e.target, ", lastKeyDownNode was ", dijit._lastKeyDownNode, ", equality is ", (e.target === dijit._lastKeyDownNode)); | |
429 | if( (e.keyCode == d.keys.ENTER || e.keyCode == d.keys.SPACE) && | |
430 | e.target == dijit._lastKeyDownNode && // === breaks greasemonkey | |
431 | !e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey){ | |
432 | //need reset here or have problems in FF when focus returns to trigger element after closing popup/alert | |
433 | dijit._lastKeyDownNode = null; | |
434 | return m(e); | |
435 | } | |
436 | }) | |
437 | ); | |
438 | } | |
439 | } | |
440 | ||
441 | return handles; // _Widget.Handle | |
442 | }, | |
443 | ||
444 | ////////////////// MISCELLANEOUS METHODS /////////////////// | |
445 | ||
446 | _onShow: function(){ | |
447 | // summary: | |
448 | // Internal method called when this widget is made visible. | |
449 | // See `onShow` for details. | |
450 | this.onShow(); | |
451 | }, | |
452 | ||
453 | onShow: function(){ | |
454 | // summary: | |
455 | // Called when this widget becomes the selected pane in a | |
456 | // `dijit.layout.TabContainer`, `dijit.layout.StackContainer`, | |
457 | // `dijit.layout.AccordionContainer`, etc. | |
458 | // | |
459 | // Also called to indicate display of a `dijit.Dialog`, `dijit.TooltipDialog`, or `dijit.TitlePane`. | |
460 | // tags: | |
461 | // callback | |
462 | }, | |
463 | ||
464 | onHide: function(){ | |
465 | // summary: | |
466 | // Called when another widget becomes the selected pane in a | |
467 | // `dijit.layout.TabContainer`, `dijit.layout.StackContainer`, | |
468 | // `dijit.layout.AccordionContainer`, etc. | |
469 | // | |
470 | // Also called to indicate hide of a `dijit.Dialog`, `dijit.TooltipDialog`, or `dijit.TitlePane`. | |
471 | // tags: | |
472 | // callback | |
473 | }, | |
474 | ||
475 | onClose: function(){ | |
476 | // summary: | |
477 | // Called when this widget is being displayed as a popup (ex: a Calendar popped | |
478 | // up from a DateTextBox), and it is hidden. | |
479 | // This is called from the dijit.popup code, and should not be called directly. | |
480 | // | |
481 | // Also used as a parameter for children of `dijit.layout.StackContainer` or subclasses. | |
482 | // Callback if a user tries to close the child. Child will be closed if this function returns true. | |
483 | // tags: | |
484 | // extension | |
485 | ||
486 | return true; // Boolean | |
487 | } | |
2f01fe57 | 488 | }); |
81bea17a | 489 | |
2f01fe57 | 490 | })(); |
81bea17a | 491 | |
2f01fe57 | 492 | } |