]> git.wh0rd.org - tt-rss.git/blame - lib/dijit/_WidgetBase.js
remove call-by-reference to comply with php 5.4
[tt-rss.git] / lib / dijit / _WidgetBase.js
CommitLineData
81bea17a
AD
1/*
2 Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved.
3 Available via Academic Free License >= 2.1 OR the modified BSD license.
4 see: http://dojotoolkit.org/license for details
5*/
6
7
8if(!dojo._hasResource["dijit._WidgetBase"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
9dojo._hasResource["dijit._WidgetBase"] = true;
10dojo.provide("dijit._WidgetBase");
11dojo.require("dijit._base.manager");
12dojo.require("dojo.Stateful");
13
14
15(function(){
16
17dojo.declare("dijit._WidgetBase", dojo.Stateful, {
18 // summary:
19 // Future base class for all Dijit widgets.
20 // _Widget extends this class adding support for various features needed by desktop.
21
22 // id: [const] String
23 // A unique, opaque ID string that can be assigned by users or by the
24 // system. If the developer passes an ID which is known not to be
25 // unique, the specified ID is ignored and the system-generated ID is
26 // used instead.
27 id: "",
28
29 // lang: [const] String
30 // Rarely used. Overrides the default Dojo locale used to render this widget,
31 // as defined by the [HTML LANG](http://www.w3.org/TR/html401/struct/dirlang.html#adef-lang) attribute.
32 // Value must be among the list of locales specified during by the Dojo bootstrap,
33 // formatted according to [RFC 3066](http://www.ietf.org/rfc/rfc3066.txt) (like en-us).
34 lang: "",
35
36 // dir: [const] String
37 // Bi-directional support, as defined by the [HTML DIR](http://www.w3.org/TR/html401/struct/dirlang.html#adef-dir)
38 // attribute. Either left-to-right "ltr" or right-to-left "rtl". If undefined, widgets renders in page's
39 // default direction.
40 dir: "",
41
42 // class: String
43 // HTML class attribute
44 "class": "",
45
46 // style: String||Object
47 // HTML style attributes as cssText string or name/value hash
48 style: "",
49
50 // title: String
51 // HTML title attribute.
52 //
53 // For form widgets this specifies a tooltip to display when hovering over
54 // the widget (just like the native HTML title attribute).
55 //
56 // For TitlePane or for when this widget is a child of a TabContainer, AccordionContainer,
57 // etc., it's used to specify the tab label, accordion pane title, etc.
58 title: "",
59
60 // tooltip: String
61 // When this widget's title attribute is used to for a tab label, accordion pane title, etc.,
62 // this specifies the tooltip to appear when the mouse is hovered over that text.
63 tooltip: "",
64
65 // baseClass: [protected] String
66 // Root CSS class of the widget (ex: dijitTextBox), used to construct CSS classes to indicate
67 // widget state.
68 baseClass: "",
69
70 // srcNodeRef: [readonly] DomNode
71 // pointer to original DOM node
72 srcNodeRef: null,
73
74 // domNode: [readonly] DomNode
75 // This is our visible representation of the widget! Other DOM
76 // Nodes may by assigned to other properties, usually through the
77 // template system's dojoAttachPoint syntax, but the domNode
78 // property is the canonical "top level" node in widget UI.
79 domNode: null,
80
81 // containerNode: [readonly] DomNode
82 // Designates where children of the source DOM node will be placed.
83 // "Children" in this case refers to both DOM nodes and widgets.
84 // For example, for myWidget:
85 //
86 // | <div dojoType=myWidget>
87 // | <b> here's a plain DOM node
88 // | <span dojoType=subWidget>and a widget</span>
89 // | <i> and another plain DOM node </i>
90 // | </div>
91 //
92 // containerNode would point to:
93 //
94 // | <b> here's a plain DOM node
95 // | <span dojoType=subWidget>and a widget</span>
96 // | <i> and another plain DOM node </i>
97 //
98 // In templated widgets, "containerNode" is set via a
99 // dojoAttachPoint assignment.
100 //
101 // containerNode must be defined for any widget that accepts innerHTML
102 // (like ContentPane or BorderContainer or even Button), and conversely
103 // is null for widgets that don't, like TextBox.
104 containerNode: null,
105
106/*=====
107 // _started: Boolean
108 // startup() has completed.
109 _started: false,
110=====*/
111
112 // attributeMap: [protected] Object
113 // attributeMap sets up a "binding" between attributes (aka properties)
114 // of the widget and the widget's DOM.
115 // Changes to widget attributes listed in attributeMap will be
116 // reflected into the DOM.
117 //
118 // For example, calling set('title', 'hello')
119 // on a TitlePane will automatically cause the TitlePane's DOM to update
120 // with the new title.
121 //
122 // attributeMap is a hash where the key is an attribute of the widget,
123 // and the value reflects a binding to a:
124 //
125 // - DOM node attribute
126 // | focus: {node: "focusNode", type: "attribute"}
127 // Maps this.focus to this.focusNode.focus
128 //
129 // - DOM node innerHTML
130 // | title: { node: "titleNode", type: "innerHTML" }
131 // Maps this.title to this.titleNode.innerHTML
132 //
133 // - DOM node innerText
134 // | title: { node: "titleNode", type: "innerText" }
135 // Maps this.title to this.titleNode.innerText
136 //
137 // - DOM node CSS class
138 // | myClass: { node: "domNode", type: "class" }
139 // Maps this.myClass to this.domNode.className
140 //
141 // If the value is an array, then each element in the array matches one of the
142 // formats of the above list.
143 //
144 // There are also some shorthands for backwards compatibility:
145 // - string --> { node: string, type: "attribute" }, for example:
146 // | "focusNode" ---> { node: "focusNode", type: "attribute" }
147 // - "" --> { node: "domNode", type: "attribute" }
148 attributeMap: {id:"", dir:"", lang:"", "class":"", style:"", title:""},
149
150 // _blankGif: [protected] String
151 // Path to a blank 1x1 image.
152 // Used by <img> nodes in templates that really get their image via CSS background-image.
153 _blankGif: (dojo.config.blankGif || dojo.moduleUrl("dojo", "resources/blank.gif")).toString(),
154
155 //////////// INITIALIZATION METHODS ///////////////////////////////////////
156
157 postscript: function(/*Object?*/params, /*DomNode|String*/srcNodeRef){
158 // summary:
159 // Kicks off widget instantiation. See create() for details.
160 // tags:
161 // private
162 this.create(params, srcNodeRef);
163 },
164
165 create: function(/*Object?*/params, /*DomNode|String?*/srcNodeRef){
166 // summary:
167 // Kick off the life-cycle of a widget
168 // params:
169 // Hash of initialization parameters for widget, including
170 // scalar values (like title, duration etc.) and functions,
171 // typically callbacks like onClick.
172 // srcNodeRef:
173 // If a srcNodeRef (DOM node) is specified:
174 // - use srcNodeRef.innerHTML as my contents
175 // - if this is a behavioral widget then apply behavior
176 // to that srcNodeRef
177 // - otherwise, replace srcNodeRef with my generated DOM
178 // tree
179 // description:
180 // Create calls a number of widget methods (postMixInProperties, buildRendering, postCreate,
181 // etc.), some of which of you'll want to override. See http://docs.dojocampus.org/dijit/_Widget
182 // for a discussion of the widget creation lifecycle.
183 //
184 // Of course, adventurous developers could override create entirely, but this should
185 // only be done as a last resort.
186 // tags:
187 // private
188
189 // store pointer to original DOM tree
190 this.srcNodeRef = dojo.byId(srcNodeRef);
191
192 // For garbage collection. An array of handles returned by Widget.connect()
193 // Each handle returned from Widget.connect() is an array of handles from dojo.connect()
194 this._connects = [];
195
196 // For garbage collection. An array of handles returned by Widget.subscribe()
197 // The handle returned from Widget.subscribe() is the handle returned from dojo.subscribe()
198 this._subscribes = [];
199
200 // mix in our passed parameters
201 if(this.srcNodeRef && (typeof this.srcNodeRef.id == "string")){ this.id = this.srcNodeRef.id; }
202 if(params){
203 this.params = params;
204 dojo._mixin(this, params);
205 }
206 this.postMixInProperties();
207
208 // generate an id for the widget if one wasn't specified
209 // (be sure to do this before buildRendering() because that function might
210 // expect the id to be there.)
211 if(!this.id){
212 this.id = dijit.getUniqueId(this.declaredClass.replace(/\./g,"_"));
213 }
214 dijit.registry.add(this);
215
216 this.buildRendering();
217
218 if(this.domNode){
219 // Copy attributes listed in attributeMap into the [newly created] DOM for the widget.
220 // Also calls custom setters for all attributes with custom setters.
221 this._applyAttributes();
222
223 // If srcNodeRef was specified, then swap out original srcNode for this widget's DOM tree.
224 // For 2.0, move this after postCreate(). postCreate() shouldn't depend on the
225 // widget being attached to the DOM since it isn't when a widget is created programmatically like
226 // new MyWidget({}). See #11635.
227 var source = this.srcNodeRef;
228 if(source && source.parentNode && this.domNode !== source){
229 source.parentNode.replaceChild(this.domNode, source);
230 }
231 }
232
233 if(this.domNode){
234 // Note: for 2.0 may want to rename widgetId to dojo._scopeName + "_widgetId",
235 // assuming that dojo._scopeName even exists in 2.0
236 this.domNode.setAttribute("widgetId", this.id);
237 }
238 this.postCreate();
239
240 // If srcNodeRef has been processed and removed from the DOM (e.g. TemplatedWidget) then delete it to allow GC.
241 if(this.srcNodeRef && !this.srcNodeRef.parentNode){
242 delete this.srcNodeRef;
243 }
244
245 this._created = true;
246 },
247
248 _applyAttributes: function(){
249 // summary:
250 // Step during widget creation to copy all widget attributes to the
251 // DOM as per attributeMap and _setXXXAttr functions.
252 // description:
253 // Skips over blank/false attribute values, unless they were explicitly specified
254 // as parameters to the widget, since those are the default anyway,
255 // and setting tabIndex="" is different than not setting tabIndex at all.
256 //
257 // It processes the attributes in the attribute map first, and then
258 // it goes through and processes the attributes for the _setXXXAttr
259 // functions that have been specified
260 // tags:
261 // private
262 var condAttrApply = function(attr, scope){
263 if((scope.params && attr in scope.params) || scope[attr]){
264 scope.set(attr, scope[attr]);
265 }
266 };
267
268 // Do the attributes in attributeMap
269 for(var attr in this.attributeMap){
270 condAttrApply(attr, this);
271 }
272
273 // And also any attributes with custom setters
274 dojo.forEach(this._getSetterAttributes(), function(a){
275 if(!(a in this.attributeMap)){
276 condAttrApply(a, this);
277 }
278 }, this);
279 },
280
281 _getSetterAttributes: function(){
282 // summary:
283 // Returns list of attributes with custom setters for this widget
284 var ctor = this.constructor;
285 if(!ctor._setterAttrs){
286 var r = (ctor._setterAttrs = []),
287 attrs,
288 proto = ctor.prototype;
289 for(var fxName in proto){
290 if(dojo.isFunction(proto[fxName]) && (attrs = fxName.match(/^_set([a-zA-Z]*)Attr$/)) && attrs[1]){
291 r.push(attrs[1].charAt(0).toLowerCase() + attrs[1].substr(1));
292 }
293 }
294 }
295 return ctor._setterAttrs; // String[]
296 },
297
298 postMixInProperties: function(){
299 // summary:
300 // Called after the parameters to the widget have been read-in,
301 // but before the widget template is instantiated. Especially
302 // useful to set properties that are referenced in the widget
303 // template.
304 // tags:
305 // protected
306 },
307
308 buildRendering: function(){
309 // summary:
310 // Construct the UI for this widget, setting this.domNode
311 // description:
312 // Most widgets will mixin `dijit._Templated`, which implements this
313 // method.
314 // tags:
315 // protected
316
317 if(!this.domNode){
318 // Create root node if it wasn't created by _Templated
319 this.domNode = this.srcNodeRef || dojo.create('div');
320 }
321
322 // baseClass is a single class name or occasionally a space-separated list of names.
323 // Add those classes to the DOMNode. If RTL mode then also add with Rtl suffix.
324 // TODO: make baseClass custom setter
325 if(this.baseClass){
326 var classes = this.baseClass.split(" ");
327 if(!this.isLeftToRight()){
328 classes = classes.concat( dojo.map(classes, function(name){ return name+"Rtl"; }));
329 }
330 dojo.addClass(this.domNode, classes);
331 }
332 },
333
334 postCreate: function(){
335 // summary:
336 // Processing after the DOM fragment is created
337 // description:
338 // Called after the DOM fragment has been created, but not necessarily
339 // added to the document. Do not include any operations which rely on
340 // node dimensions or placement.
341 // tags:
342 // protected
343 },
344
345 startup: function(){
346 // summary:
347 // Processing after the DOM fragment is added to the document
348 // description:
349 // Called after a widget and its children have been created and added to the page,
350 // and all related widgets have finished their create() cycle, up through postCreate().
351 // This is useful for composite widgets that need to control or layout sub-widgets.
352 // Many layout widgets can use this as a wiring phase.
353 this._started = true;
354 },
355
356 //////////// DESTROY FUNCTIONS ////////////////////////////////
357
358 destroyRecursive: function(/*Boolean?*/ preserveDom){
359 // summary:
360 // Destroy this widget and its descendants
361 // description:
362 // This is the generic "destructor" function that all widget users
363 // should call to cleanly discard with a widget. Once a widget is
364 // destroyed, it is removed from the manager object.
365 // preserveDom:
366 // If true, this method will leave the original DOM structure
367 // alone of descendant Widgets. Note: This will NOT work with
368 // dijit._Templated widgets.
369
370 this._beingDestroyed = true;
371 this.destroyDescendants(preserveDom);
372 this.destroy(preserveDom);
373 },
374
375 destroy: function(/*Boolean*/ preserveDom){
376 // summary:
377 // Destroy this widget, but not its descendants.
378 // This method will, however, destroy internal widgets such as those used within a template.
379 // preserveDom: Boolean
380 // If true, this method will leave the original DOM structure alone.
381 // Note: This will not yet work with _Templated widgets
382
383 this._beingDestroyed = true;
384 this.uninitialize();
385 var d = dojo,
386 dfe = d.forEach,
387 dun = d.unsubscribe;
388 dfe(this._connects, function(array){
389 dfe(array, d.disconnect);
390 });
391 dfe(this._subscribes, function(handle){
392 dun(handle);
393 });
394
395 // destroy widgets created as part of template, etc.
396 dfe(this._supportingWidgets || [], function(w){
397 if(w.destroyRecursive){
398 w.destroyRecursive();
399 }else if(w.destroy){
400 w.destroy();
401 }
402 });
403
404 this.destroyRendering(preserveDom);
405 dijit.registry.remove(this.id);
406 this._destroyed = true;
407 },
408
409 destroyRendering: function(/*Boolean?*/ preserveDom){
410 // summary:
411 // Destroys the DOM nodes associated with this widget
412 // preserveDom:
413 // If true, this method will leave the original DOM structure alone
414 // during tear-down. Note: this will not work with _Templated
415 // widgets yet.
416 // tags:
417 // protected
418
419 if(this.bgIframe){
420 this.bgIframe.destroy(preserveDom);
421 delete this.bgIframe;
422 }
423
424 if(this.domNode){
425 if(preserveDom){
426 dojo.removeAttr(this.domNode, "widgetId");
427 }else{
428 dojo.destroy(this.domNode);
429 }
430 delete this.domNode;
431 }
432
433 if(this.srcNodeRef){
434 if(!preserveDom){
435 dojo.destroy(this.srcNodeRef);
436 }
437 delete this.srcNodeRef;
438 }
439 },
440
441 destroyDescendants: function(/*Boolean?*/ preserveDom){
442 // summary:
443 // Recursively destroy the children of this widget and their
444 // descendants.
445 // preserveDom:
446 // If true, the preserveDom attribute is passed to all descendant
447 // widget's .destroy() method. Not for use with _Templated
448 // widgets.
449
450 // get all direct descendants and destroy them recursively
451 dojo.forEach(this.getChildren(), function(widget){
452 if(widget.destroyRecursive){
453 widget.destroyRecursive(preserveDom);
454 }
455 });
456 },
457
458 uninitialize: function(){
459 // summary:
460 // Stub function. Override to implement custom widget tear-down
461 // behavior.
462 // tags:
463 // protected
464 return false;
465 },
466
467 ////////////////// GET/SET, CUSTOM SETTERS, ETC. ///////////////////
468
469 _setClassAttr: function(/*String*/ value){
470 // summary:
471 // Custom setter for the CSS "class" attribute
472 // tags:
473 // protected
474 var mapNode = this[this.attributeMap["class"] || 'domNode'];
475 dojo.replaceClass(mapNode, value, this["class"]);
476 this._set("class", value);
477 },
478
479 _setStyleAttr: function(/*String||Object*/ value){
480 // summary:
481 // Sets the style attribute of the widget according to value,
482 // which is either a hash like {height: "5px", width: "3px"}
483 // or a plain string
484 // description:
485 // Determines which node to set the style on based on style setting
486 // in attributeMap.
487 // tags:
488 // protected
489
490 var mapNode = this[this.attributeMap.style || 'domNode'];
491
492 // Note: technically we should revert any style setting made in a previous call
493 // to his method, but that's difficult to keep track of.
494
495 if(dojo.isObject(value)){
496 dojo.style(mapNode, value);
497 }else{
498 if(mapNode.style.cssText){
499 mapNode.style.cssText += "; " + value;
500 }else{
501 mapNode.style.cssText = value;
502 }
503 }
504
505 this._set("style", value);
506 },
507
508 _attrToDom: function(/*String*/ attr, /*String*/ value){
509 // summary:
510 // Reflect a widget attribute (title, tabIndex, duration etc.) to
511 // the widget DOM, as specified in attributeMap.
512 // Note some attributes like "type"
513 // cannot be processed this way as they are not mutable.
514 //
515 // tags:
516 // private
517
518 var commands = this.attributeMap[attr];
519 dojo.forEach(dojo.isArray(commands) ? commands : [commands], function(command){
520
521 // Get target node and what we are doing to that node
522 var mapNode = this[command.node || command || "domNode"]; // DOM node
523 var type = command.type || "attribute"; // class, innerHTML, innerText, or attribute
524
525 switch(type){
526 case "attribute":
527 if(dojo.isFunction(value)){ // functions execute in the context of the widget
528 value = dojo.hitch(this, value);
529 }
530
531 // Get the name of the DOM node attribute; usually it's the same
532 // as the name of the attribute in the widget (attr), but can be overridden.
533 // Also maps handler names to lowercase, like onSubmit --> onsubmit
534 var attrName = command.attribute ? command.attribute :
535 (/^on[A-Z][a-zA-Z]*$/.test(attr) ? attr.toLowerCase() : attr);
536
537 dojo.attr(mapNode, attrName, value);
538 break;
539 case "innerText":
540 mapNode.innerHTML = "";
541 mapNode.appendChild(dojo.doc.createTextNode(value));
542 break;
543 case "innerHTML":
544 mapNode.innerHTML = value;
545 break;
546 case "class":
547 dojo.replaceClass(mapNode, value, this[attr]);
548 break;
549 }
550 }, this);
551 },
552
553 get: function(name){
554 // summary:
555 // Get a property from a widget.
556 // name:
557 // The property to get.
558 // description:
559 // Get a named property from a widget. The property may
560 // potentially be retrieved via a getter method. If no getter is defined, this
561 // just retrieves the object's property.
562 // For example, if the widget has a properties "foo"
563 // and "bar" and a method named "_getFooAttr", calling:
564 // | myWidget.get("foo");
565 // would be equivalent to writing:
566 // | widget._getFooAttr();
567 // and:
568 // | myWidget.get("bar");
569 // would be equivalent to writing:
570 // | widget.bar;
571 var names = this._getAttrNames(name);
572 return this[names.g] ? this[names.g]() : this[name];
573 },
574
575 set: function(name, value){
576 // summary:
577 // Set a property on a widget
578 // name:
579 // The property to set.
580 // value:
581 // The value to set in the property.
582 // description:
583 // Sets named properties on a widget which may potentially be handled by a
584 // setter in the widget.
585 // For example, if the widget has a properties "foo"
586 // and "bar" and a method named "_setFooAttr", calling:
587 // | myWidget.set("foo", "Howdy!");
588 // would be equivalent to writing:
589 // | widget._setFooAttr("Howdy!");
590 // and:
591 // | myWidget.set("bar", 3);
592 // would be equivalent to writing:
593 // | widget.bar = 3;
594 //
595 // set() may also be called with a hash of name/value pairs, ex:
596 // | myWidget.set({
597 // | foo: "Howdy",
598 // | bar: 3
599 // | })
600 // This is equivalent to calling set(foo, "Howdy") and set(bar, 3)
601
602 if(typeof name === "object"){
603 for(var x in name){
604 this.set(x, name[x]);
605 }
606 return this;
607 }
608 var names = this._getAttrNames(name);
609 if(this[names.s]){
610 // use the explicit setter
611 var result = this[names.s].apply(this, Array.prototype.slice.call(arguments, 1));
612 }else{
613 // if param is specified as DOM node attribute, copy it
614 if(name in this.attributeMap){
615 this._attrToDom(name, value);
616 }
617 this._set(name, value);
618 }
619 return result || this;
620 },
621
622 _attrPairNames: {}, // shared between all widgets
623 _getAttrNames: function(name){
624 // summary:
625 // Helper function for get() and set().
626 // Caches attribute name values so we don't do the string ops every time.
627 // tags:
628 // private
629
630 var apn = this._attrPairNames;
631 if(apn[name]){ return apn[name]; }
632 var uc = name.charAt(0).toUpperCase() + name.substr(1);
633 return (apn[name] = {
634 n: name+"Node",
635 s: "_set"+uc+"Attr",
636 g: "_get"+uc+"Attr"
637 });
638 },
639
640 _set: function(/*String*/ name, /*anything*/ value){
641 // summary:
642 // Helper function to set new value for specified attribute, and call handlers
643 // registered with watch() if the value has changed.
644 var oldValue = this[name];
645 this[name] = value;
646 if(this._watchCallbacks && this._created && value !== oldValue){
647 this._watchCallbacks(name, oldValue, value);
648 }
649 },
650
651 toString: function(){
652 // summary:
653 // Returns a string that represents the widget
654 // description:
655 // When a widget is cast to a string, this method will be used to generate the
656 // output. Currently, it does not implement any sort of reversible
657 // serialization.
658 return '[Widget ' + this.declaredClass + ', ' + (this.id || 'NO ID') + ']'; // String
659 },
660
661 getDescendants: function(){
662 // summary:
663 // Returns all the widgets contained by this, i.e., all widgets underneath this.containerNode.
664 // This method should generally be avoided as it returns widgets declared in templates, which are
665 // supposed to be internal/hidden, but it's left here for back-compat reasons.
666
667 return this.containerNode ? dojo.query('[widgetId]', this.containerNode).map(dijit.byNode) : []; // dijit._Widget[]
668 },
669
670 getChildren: function(){
671 // summary:
672 // Returns all the widgets contained by this, i.e., all widgets underneath this.containerNode.
673 // Does not return nested widgets, nor widgets that are part of this widget's template.
674 return this.containerNode ? dijit.findWidgets(this.containerNode) : []; // dijit._Widget[]
675 },
676
677 connect: function(
678 /*Object|null*/ obj,
679 /*String|Function*/ event,
680 /*String|Function*/ method){
681 // summary:
682 // Connects specified obj/event to specified method of this object
683 // and registers for disconnect() on widget destroy.
684 // description:
685 // Provide widget-specific analog to dojo.connect, except with the
686 // implicit use of this widget as the target object.
687 // Events connected with `this.connect` are disconnected upon
688 // destruction.
689 // returns:
690 // A handle that can be passed to `disconnect` in order to disconnect before
691 // the widget is destroyed.
692 // example:
693 // | var btn = new dijit.form.Button();
694 // | // when foo.bar() is called, call the listener we're going to
695 // | // provide in the scope of btn
696 // | btn.connect(foo, "bar", function(){
697 // | console.debug(this.toString());
698 // | });
699 // tags:
700 // protected
701
702 var handles = [dojo._connect(obj, event, this, method)];
703 this._connects.push(handles);
704 return handles; // _Widget.Handle
705 },
706
707 disconnect: function(/* _Widget.Handle */ handles){
708 // summary:
709 // Disconnects handle created by `connect`.
710 // Also removes handle from this widget's list of connects.
711 // tags:
712 // protected
713 for(var i=0; i<this._connects.length; i++){
714 if(this._connects[i] == handles){
715 dojo.forEach(handles, dojo.disconnect);
716 this._connects.splice(i, 1);
717 return;
718 }
719 }
720 },
721
722 subscribe: function(
723 /*String*/ topic,
724 /*String|Function*/ method){
725 // summary:
726 // Subscribes to the specified topic and calls the specified method
727 // of this object and registers for unsubscribe() on widget destroy.
728 // description:
729 // Provide widget-specific analog to dojo.subscribe, except with the
730 // implicit use of this widget as the target object.
731 // example:
732 // | var btn = new dijit.form.Button();
733 // | // when /my/topic is published, this button changes its label to
734 // | // be the parameter of the topic.
735 // | btn.subscribe("/my/topic", function(v){
736 // | this.set("label", v);
737 // | });
738 var handle = dojo.subscribe(topic, this, method);
739
740 // return handles for Any widget that may need them
741 this._subscribes.push(handle);
742 return handle;
743 },
744
745 unsubscribe: function(/*Object*/ handle){
746 // summary:
747 // Unsubscribes handle created by this.subscribe.
748 // Also removes handle from this widget's list of subscriptions
749 for(var i=0; i<this._subscribes.length; i++){
750 if(this._subscribes[i] == handle){
751 dojo.unsubscribe(handle);
752 this._subscribes.splice(i, 1);
753 return;
754 }
755 }
756 },
757
758 isLeftToRight: function(){
759 // summary:
760 // Return this widget's explicit or implicit orientation (true for LTR, false for RTL)
761 // tags:
762 // protected
763 return this.dir ? (this.dir == "ltr") : dojo._isBodyLtr(); //Boolean
764 },
765
766 placeAt: function(/* String|DomNode|_Widget */reference, /* String?|Int? */position){
767 // summary:
768 // Place this widget's domNode reference somewhere in the DOM based
769 // on standard dojo.place conventions, or passing a Widget reference that
770 // contains and addChild member.
771 //
772 // description:
773 // A convenience function provided in all _Widgets, providing a simple
774 // shorthand mechanism to put an existing (or newly created) Widget
775 // somewhere in the dom, and allow chaining.
776 //
777 // reference:
778 // The String id of a domNode, a domNode reference, or a reference to a Widget posessing
779 // an addChild method.
780 //
781 // position:
782 // If passed a string or domNode reference, the position argument
783 // accepts a string just as dojo.place does, one of: "first", "last",
784 // "before", or "after".
785 //
786 // If passed a _Widget reference, and that widget reference has an ".addChild" method,
787 // it will be called passing this widget instance into that method, supplying the optional
788 // position index passed.
789 //
790 // returns:
791 // dijit._Widget
792 // Provides a useful return of the newly created dijit._Widget instance so you
793 // can "chain" this function by instantiating, placing, then saving the return value
794 // to a variable.
795 //
796 // example:
797 // | // create a Button with no srcNodeRef, and place it in the body:
798 // | var button = new dijit.form.Button({ label:"click" }).placeAt(dojo.body());
799 // | // now, 'button' is still the widget reference to the newly created button
800 // | dojo.connect(button, "onClick", function(e){ console.log('click'); });
801 //
802 // example:
803 // | // create a button out of a node with id="src" and append it to id="wrapper":
804 // | var button = new dijit.form.Button({},"src").placeAt("wrapper");
805 //
806 // example:
807 // | // place a new button as the first element of some div
808 // | var button = new dijit.form.Button({ label:"click" }).placeAt("wrapper","first");
809 //
810 // example:
811 // | // create a contentpane and add it to a TabContainer
812 // | var tc = dijit.byId("myTabs");
813 // | new dijit.layout.ContentPane({ href:"foo.html", title:"Wow!" }).placeAt(tc)
814
815 if(reference.declaredClass && reference.addChild){
816 reference.addChild(this, position);
817 }else{
818 dojo.place(this.domNode, reference, position);
819 }
820 return this;
821 }
822});
823
824})();
825
826}