-
Create a class with
declare()
. -
Any object created with
new()
will be initialised withpreamble()
,constructor()
andpostscript()
. -
Take as an example
SomeWidget = declare( [_WidgetBase], {} ); w = new SomeWidget( {param1: 'one', param2: 2} )
this.constructor( params, srcNodeRef )
is called . This will run before anything else. You can do whatever you like there_WidgetBase::postscript( params, srcNodeRef )
is called- All
postscript()
does is call_Widgetbase::create(params, srcNodeRef)
_Widgetbase::create(params, srcNodeRef)
is the real deal
- The following happens when you create
w
:this.srcNodeRef
, if present, is assigned to the DOM node with idsrcNodeRef
params
are mixed in with the objectw
.- CALLS:
postMixinProperties()
this.id
is created (unless it was part of params and got mixed in)- The variables
this.ownerDocument
andthis.ownerDocumentBody
are set (although you can passownerDocument
in params) - Widget is added to the registry
- CALLS:
buildRendering()
. NOTE:buildRendering()
will definethis.domNode
, which will be the DOM of the widget. The "stock"buildRendering()
from_WidgetBase
will make sure this.domNode is indeed set by assigning it tosrcNodeRef
(if passed as parameter) or, as a last resort, create an<div>
inownerDocument
(won't actually be displayed!). Most of the time, the "parent"buildRendering()
will createthis.domNode
before callingthis.inherited(arguments)
buildRendering
also assigns DOM classes to the widget according to the parameterthis.baseClass
- CALLS:
this._applyAttributes()
. Basically, if you passed { color: 'blue' } as an attribute, then_setColorAttr()
will be called with 'blue' as a parameter. (Note:this._setColorAttr()
is what is called when you runthis.set('color', 'blue')
) - If
this.domNode
is different tothis.srcNodeRef
(see above: it might be the same if none of the inherited widgets replacedthis.domNode
andthis.srcNodeRef
was set), thenthis.domNode
will replace outrightthis.srcNodeRef
. This is when the magic begins.- NOTE: basically, if
srcNodeRef
is specified, the widget will always replace it atcreate()
time!
- NOTE: basically, if
this.domNode
will have a VERY IMPORTANT attribute set:widgetId
. This is the "link" between the DOM node and the Dojo widget- CALLS:
postCreate()
- NOTE: You must call
this.inherited(arguments)
when redefiningpostMixinProperties()
,buildRendering()
,postCreate()
etc. but mustn't call it when defining theconstructor()
_WidgetBase::startup()
is not called after_WidgetBase::create()
. It's up to the developer to call it. It should only be called once the widget's DOM is in document flow, as its main goal is to contain any logic reliant on the widget's dimensions (whenpostCreate()
is called, the DOM structure has been created but it may or may not be rendered in the document.)this.placeAt()
willstartup()
the widget if the parent has already been started.- The stock
Widgetbase::startup()
method will also callstartup()
for all contained widgets returned by_WidgetBase::getChildren()
- Each widget might have a
containerNode
attribute, which will point to the widget's content _Widgetbase::getChildren()
will search for any DOM node with attributewidgetId
and a corresponding widget in the widget registry (it runsregistry.findWidgets(this.containerNode)
).
- Each widget might have a
- If you create a widget specifying srcNodeRef, it will be "placed" there (read above)
- If you don't, you can use
this.placeAt( dest, position )
. NOTE:dest
can be a widget withaddChild()
defined: in that case, that method will be useddest
can be a widget withoutaddchild()
defined: in that case, the widget will be added todest
'sdomNode
orcontainerNode
dest
can be a DOM element: it will be placed there
- CONTRACT: It implements
addChild()
,removeChild()
,hasChildren()
,getIndexOfChild()
, AND setsthis.containerNode
- It is a mixin for widgets that contain HTML and/or a set of widget children
addChild()
adds the child tothis.containerNode
and callsstartup()
for it (if containing widget has already started). It also callsdomConstruct.place()
which makes sure the widget's DOM node has the right widgetId (it will work with the registry)addChild()
won't work well if aContentPane
is nested in layout widgets asaddChild()
doesn't resize() (it's unclear if the ContentPane is visible or not, andresize()
doesn't work on hidden tabs).addChild()
also doesn't call_checkIfSingleChild()
to resize a single child widget to fill the whole ContentPane.
- CONTRACT: Defines
isLayoutContainer
: this widget will callresize()
on its children when they become visible, + followdoLayout
- NOTE: Since there is no concept of "hidden" in a ContentPane, it means call
resize()
on its children when ContentPane is visible
- NOTE: Since there is no concept of "hidden" in a ContentPane, it means call
- Implements
_onShow()
, which is run either at startup (normal visible contentPane) or by its parent (hidden tab) - If it's not the child of a
isLayoutContainer
, will listen to the viewport'sresize
event and runthis.resize()
this._isShown()
cheats: will returntrue
if it was ever shown, which is good enough- If
doLayout
:- If ContentPane only has a single child, the single child will be sized so that it takes the whole parent.
- Children will be told what size they should be (will be passed dimensions in Resize)
- It's a "sort of" a container of widget, but limited to simple widgets where everything is visible. This is due to
addChild()
's limits - Simply
WidgetBase
+_Container
+_ContentPaneResizeMixin
(which honours theisLayoutContainer
contract).
- It defines
getPreviousSibling()
,getNextSibling()
,getIndexInParent()
- Useful for widgets that are contained by a
isLayoutContainer
widget
- It includes
Widgetbase
+_Container
+_Contained
+ functions to honour theisLayoutContainer
contract - CONTRACT: Defines
isLayoutContainer
: this widget will callresize()
on its children when they become visible, + followdoLayout
- NOTE: unlike
_ContentPaneMixin
, children widgets might well be invisible (see:TabContainer
etc.).
- NOTE: unlike
- If it's not the child of a
isLayoutContainer
, will listen to the viewport'sresize
event and runthis.resize()
- When
this.resize()
, it will callthis.layout()
. It will be up to the Widget class to implementthis.layout()
to resize children - It's basically up to
this.layout()
to work on layout and call _onShow() on visible child (see CONTRACT) - It extends
addChild()
andremoveChild()
so that it adds (and remove) the right DOM classes (parent.baseClass+'-child'
andparent.baseClass+'-'+child.baseClass
) for theming - If
doLayout
:- If ContentPane only has a single child, the single child will be sized so that it takes the whole parent.
- Children will be told what size they should be (will be passed dimensions in Resize)
Note: this is a very simplified description of what _StackContainer
is, to give a rough idea of how it uses _LayoutWidget
- It simply inherits from
_LayoutWidget
this.layout()
is a function that will resize just the selected child (as required)- At
startup()
:- It looks through its children and sets the one with
child.selected
as the one to display. NOTE: might use cookies too (this.persist
) - Sets children's class as
dijitHidden
(instead ofdijitVisible
), so everything is hidden
- It looks through its children and sets the one with
- Publishes a topic
this.id+'-startup'
- In
this.resize()
, if it's the first time it's shown, it calls _onShow() for the child - In
this.addChild()
, it rerunsthis.layout()
and (if it's the only child) selects it - In
this.removeChild()
, the first child is selected andthis.layout()
is called
- dojo/on is the one-stop system to emit and subscribe to events
- Two main functions:
on()
andemit()
dojo/on(target, 'event', listener)
target
can be:- An object with
this.on()
defined:dojo/on
will delegate to that function. This is what happens in widgets! OR - An object with
this.addEventListener()
defined: it will use it using the same API as DOM, but it might be anything. OR - An object with
this.attachEvent()
defined (this is for retarded IE which up to v.9 didn't havethis.addEventListener
) OR - It will fail
- An object with
dojo/on.emit(target, 'event', event)
target
can be:- An object with
this.dispatchEvent()
defined (it's a DOM node): it will use native event emission (DOM) OR - An object with
this['on'+event]
: it will call that, and it will bubble up toparentNode
if event is meant to bubble up. This is done 100% synthetically, by following parentNode attributes. event
can be a simple object, which is then "transformed" into a native event. E.g. it could have{bubbles:true}
and nothing more
- An object with
*** QUESTION: Why doesn't dojo/on.emit()
get delegated to the widget just like dojo/on()
is? It seems like the obvious thing to do -- with the object's this.emit()
which then emits through the DOM, which will then bubble things up if requested... so that the "manual" bubbling wouldn't even be necessary?
*** QUESTION: dojo/emit(target, 'event', event)
seems to call, synthetically for objects, onevent rather than onEvent. Didn't this use to be onEvent? Is capitalisation after "on" going away as a convention for Dojo 2.0?
- Widgets also implement
this.on()
andthis.emit()
. However, everything is done through the DOMthis.on('success', listener)
- TEMPORARILY, before Dojo 2 IF this['on'+success] exists, will run
aspect.after(this, 'onsuccess', listener)
to piggyback on widget methods (e.g.this.onClick()
OR - Runs
dojo/on(this.domNode, 'event', listener)
. So, it will getthis.domNode
hooked up toevent
(which will firelistener
).
- TEMPORARILY, before Dojo 2 IF this['on'+success] exists, will run
this.emit('type')
- Calls
this['on'+type]
, that us this.on if it exists in the widget (note the lack of capitalisation in 'event'). The event will not bubble up synthetically in any case (unlike synthetic events emitted withdojo/emit()
over widgets) AND - Runs
dojo/on.emit(this.domNode, toLowerCase('type'), event)
. So, it emits down tothis.domNode
, through the widget's DOM. NOTE THATtoLowerCase
!!!
- Calls
*** QUESTION: with widget.emit()
, doesn't this mean that in some cases TWO callbacks will be called when emitting 'success': one will be the listener set up with widget.on('success', listener)
and one will be the widget's this.onsuccess()
method? Is that the behaviour to expect?
*** QUESTION: there is no logic to bubble up 'event' in _Widgetbase, I guess because the DOM will do that. But isn't this a bit inconsistent? (see question above)