Page Menu
Home
Code
Search
Configure Global Search
Log In
Files
F882230
StackContainer.js
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
13 KB
Subscribers
None
StackContainer.js
View Options
if
(
!
dojo
.
_hasResource
[
"dijit.layout.StackContainer"
]){
//_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo
.
_hasResource
[
"dijit.layout.StackContainer"
]
=
true
;
dojo
.
provide
(
"dijit.layout.StackContainer"
);
dojo
.
require
(
"dijit._Templated"
);
dojo
.
require
(
"dijit.layout._LayoutWidget"
);
dojo
.
require
(
"dijit.form.Button"
);
dojo
.
declare
(
"dijit.layout.StackContainer"
,
dijit
.
layout
.
_LayoutWidget
,
// summary
// A container that has multiple children, but shows only
// one child at a time (like looking at the pages in a book one by one).
//
// Publishes topics <widgetId>-addChild, <widgetId>-removeChild, and <widgetId>-selectChild
//
// Can be base class for container, Wizard, Show, etc.
{
// doLayout: Boolean
// if true, change the size of my currently displayed child to match my size
doLayout
:
true
,
_started
:
false
,
// selectedChildWidget: Widget
// References the currently selected child widget, if any
postCreate
:
function
(){
dijit
.
setWaiRole
((
this
.
containerNode
||
this
.
domNode
),
"tabpanel"
);
this
.
connect
(
this
.
domNode
,
"onkeypress"
,
this
.
_onKeyPress
);
},
startup
:
function
(){
if
(
this
.
_started
){
return
;
}
var
children
=
this
.
getChildren
();
// Setup each page panel
dojo
.
forEach
(
children
,
this
.
_setupChild
,
this
);
// Figure out which child to initially display
dojo
.
some
(
children
,
function
(
child
){
if
(
child
.
selected
){
this
.
selectedChildWidget
=
child
;
}
return
child
.
selected
;
},
this
);
var
selected
=
this
.
selectedChildWidget
;
// Default to the first child
if
(
!
selected
&&
children
[
0
]){
selected
=
this
.
selectedChildWidget
=
children
[
0
];
selected
.
selected
=
true
;
}
if
(
selected
){
this
.
_showChild
(
selected
);
}
// Now publish information about myself so any StackControllers can initialize..
dojo
.
publish
(
this
.
id
+
"-startup"
,
[{
children
:
children
,
selected
:
selected
}]);
this
.
inherited
(
"startup"
,
arguments
);
this
.
_started
=
true
;
},
_setupChild
:
function
(
/*Widget*/
page
){
// Summary: prepare the given child
page
.
domNode
.
style
.
display
=
"none"
;
// since we are setting the width/height of the child elements, they need
// to be position:relative, or IE has problems (See bug #2033)
page
.
domNode
.
style
.
position
=
"relative"
;
return
page
;
// dijit._Widget
},
addChild
:
function
(
/*Widget*/
child
,
/*Integer?*/
insertIndex
){
// summary: Adds a widget to the stack
dijit
.
_Container
.
prototype
.
addChild
.
apply
(
this
,
arguments
);
child
=
this
.
_setupChild
(
child
);
if
(
this
.
_started
){
// in case the tab titles have overflowed from one line to two lines
this
.
layout
();
dojo
.
publish
(
this
.
id
+
"-addChild"
,
[
child
,
insertIndex
]);
// if this is the first child, then select it
if
(
!
this
.
selectedChildWidget
){
this
.
selectChild
(
child
);
}
}
},
removeChild
:
function
(
/*Widget*/
page
){
// summary: Removes the pane from the stack
dijit
.
_Container
.
prototype
.
removeChild
.
apply
(
this
,
arguments
);
// If we are being destroyed than don't run the code below (to select another page), because we are deleting
// every page one by one
if
(
this
.
_beingDestroyed
){
return
;
}
if
(
this
.
_started
){
// this will notify any tablists to remove a button; do this first because it may affect sizing
dojo
.
publish
(
this
.
id
+
"-removeChild"
,
[
page
]);
// in case the tab titles now take up one line instead of two lines
this
.
layout
();
}
if
(
this
.
selectedChildWidget
===
page
){
this
.
selectedChildWidget
=
undefined
;
if
(
this
.
_started
){
var
children
=
this
.
getChildren
();
if
(
children
.
length
){
this
.
selectChild
(
children
[
0
]);
}
}
}
},
selectChild
:
function
(
/*Widget*/
page
){
// summary:
// Show the given widget (which must be one of my children)
page
=
dijit
.
byId
(
page
);
if
(
this
.
selectedChildWidget
!=
page
){
// Deselect old page and select new one
this
.
_transition
(
page
,
this
.
selectedChildWidget
);
this
.
selectedChildWidget
=
page
;
dojo
.
publish
(
this
.
id
+
"-selectChild"
,
[
page
]);
}
},
_transition
:
function
(
/*Widget*/
newWidget
,
/*Widget*/
oldWidget
){
if
(
oldWidget
){
this
.
_hideChild
(
oldWidget
);
}
this
.
_showChild
(
newWidget
);
// Size the new widget, in case this is the first time it's being shown,
// or I have been resized since the last time it was shown.
// page must be visible for resizing to work
if
(
this
.
doLayout
&&
newWidget
.
resize
){
newWidget
.
resize
(
this
.
_containerContentBox
||
this
.
_contentBox
);
}
},
_adjacent
:
function
(
/*Boolean*/
forward
){
// summary: Gets the next/previous child widget in this container from the current selection
var
children
=
this
.
getChildren
();
var
index
=
dojo
.
indexOf
(
children
,
this
.
selectedChildWidget
);
index
+=
forward
?
1
:
children
.
length
-
1
;
return
children
[
index
%
children
.
length
];
// dijit._Widget
},
forward
:
function
(){
// Summary: advance to next page
this
.
selectChild
(
this
.
_adjacent
(
true
));
},
back
:
function
(){
// Summary: go back to previous page
this
.
selectChild
(
this
.
_adjacent
(
false
));
},
_onKeyPress
:
function
(
e
){
dojo
.
publish
(
this
.
id
+
"-containerKeyPress"
,
[{
e
:
e
,
page
:
this
}]);
},
layout
:
function
(){
if
(
this
.
doLayout
&&
this
.
selectedChildWidget
&&
this
.
selectedChildWidget
.
resize
){
this
.
selectedChildWidget
.
resize
(
this
.
_contentBox
);
}
},
_showChild
:
function
(
/*Widget*/
page
){
var
children
=
this
.
getChildren
();
page
.
isFirstChild
=
(
page
==
children
[
0
]);
page
.
isLastChild
=
(
page
==
children
[
children
.
length
-
1
]);
page
.
selected
=
true
;
page
.
domNode
.
style
.
display
=
""
;
if
(
page
.
_loadCheck
){
page
.
_loadCheck
();
// trigger load in ContentPane
}
if
(
page
.
onShow
){
page
.
onShow
();
}
},
_hideChild
:
function
(
/*Widget*/
page
){
page
.
selected
=
false
;
page
.
domNode
.
style
.
display
=
"none"
;
if
(
page
.
onHide
){
page
.
onHide
();
}
},
closeChild
:
function
(
/*Widget*/
page
){
// summary
// callback when user clicks the [X] to remove a page
// if onClose() returns true then remove and destroy the childd
var
remove
=
page
.
onClose
(
this
,
page
);
if
(
remove
){
this
.
removeChild
(
page
);
// makes sure we can clean up executeScripts in ContentPane onUnLoad
page
.
destroy
();
}
},
destroy
:
function
(){
this
.
_beingDestroyed
=
true
;
this
.
inherited
(
"destroy"
,
arguments
);
}
});
dojo
.
declare
(
"dijit.layout.StackController"
,
[
dijit
.
_Widget
,
dijit
.
_Templated
,
dijit
.
_Container
],
{
// summary:
// Set of buttons to select a page in a page list.
// Monitors the specified StackContainer, and whenever a page is
// added, deleted, or selected, updates itself accordingly.
templateString
:
"<span wairole='tablist' dojoAttachEvent='onkeypress' class='dijitStackController'></span>"
,
// containerId: String
// the id of the page container that I point to
containerId
:
""
,
// buttonWidget: String
// the name of the button widget to create to correspond to each page
buttonWidget
:
"dijit.layout._StackButton"
,
postCreate
:
function
(){
dijit
.
setWaiRole
(
this
.
domNode
,
"tablist"
);
this
.
pane2button
=
{};
// mapping from panes to buttons
this
.
_subscriptions
=
[
dojo
.
subscribe
(
this
.
containerId
+
"-startup"
,
this
,
"onStartup"
),
dojo
.
subscribe
(
this
.
containerId
+
"-addChild"
,
this
,
"onAddChild"
),
dojo
.
subscribe
(
this
.
containerId
+
"-removeChild"
,
this
,
"onRemoveChild"
),
dojo
.
subscribe
(
this
.
containerId
+
"-selectChild"
,
this
,
"onSelectChild"
),
dojo
.
subscribe
(
this
.
containerId
+
"-containerKeyPress"
,
this
,
"onContainerKeyPress"
)
];
},
onStartup
:
function
(
/*Object*/
info
){
// summary: called after StackContainer has finished initializing
dojo
.
forEach
(
info
.
children
,
this
.
onAddChild
,
this
);
this
.
onSelectChild
(
info
.
selected
);
},
destroy
:
function
(){
dojo
.
forEach
(
this
.
_subscriptions
,
dojo
.
unsubscribe
);
this
.
inherited
(
"destroy"
,
arguments
);
},
onAddChild
:
function
(
/*Widget*/
page
,
/*Integer?*/
insertIndex
){
// summary:
// Called whenever a page is added to the container.
// Create button corresponding to the page.
// add a node that will be promoted to the button widget
var
refNode
=
document
.
createElement
(
"span"
);
this
.
domNode
.
appendChild
(
refNode
);
// create an instance of the button widget
var
cls
=
dojo
.
getObject
(
this
.
buttonWidget
);
var
button
=
new
cls
({
label
:
page
.
title
,
closeButton
:
page
.
closable
},
refNode
);
this
.
addChild
(
button
,
insertIndex
);
this
.
pane2button
[
page
]
=
button
;
page
.
controlButton
=
button
;
// this value might be overwritten if two tabs point to same container
dojo
.
connect
(
button
,
"onClick"
,
dojo
.
hitch
(
this
,
"onButtonClick"
,
page
));
dojo
.
connect
(
button
,
"onClickCloseButton"
,
dojo
.
hitch
(
this
,
"onCloseButtonClick"
,
page
));
if
(
!
this
.
_currentChild
){
// put the first child into the tab order
button
.
focusNode
.
setAttribute
(
"tabIndex"
,
"0"
);
this
.
_currentChild
=
page
;
}
},
onRemoveChild
:
function
(
/*Widget*/
page
){
// summary:
// Called whenever a page is removed from the container.
// Remove the button corresponding to the page.
if
(
this
.
_currentChild
===
page
){
this
.
_currentChild
=
null
;
}
var
button
=
this
.
pane2button
[
page
];
if
(
button
){
// TODO? if current child { reassign }
button
.
destroy
();
}
this
.
pane2button
[
page
]
=
null
;
},
onSelectChild
:
function
(
/*Widget*/
page
){
// summary:
// Called when a page has been selected in the StackContainer, either by me or by another StackController
if
(
!
page
){
return
;
}
if
(
this
.
_currentChild
){
var
oldButton
=
this
.
pane2button
[
this
.
_currentChild
];
oldButton
.
setChecked
(
false
);
oldButton
.
focusNode
.
setAttribute
(
"tabIndex"
,
"-1"
);
}
var
newButton
=
this
.
pane2button
[
page
];
newButton
.
setChecked
(
true
);
this
.
_currentChild
=
page
;
newButton
.
focusNode
.
setAttribute
(
"tabIndex"
,
"0"
);
},
onButtonClick
:
function
(
/*Widget*/
page
){
// summary:
// Called whenever one of my child buttons is pressed in an attempt to select a page
var
container
=
dijit
.
byId
(
this
.
containerId
);
// TODO: do this via topics?
container
.
selectChild
(
page
);
},
onCloseButtonClick
:
function
(
/*Widget*/
page
){
// summary:
// Called whenever one of my child buttons [X] is pressed in an attempt to close a page
var
container
=
dijit
.
byId
(
this
.
containerId
);
container
.
closeChild
(
page
);
var
b
=
this
.
pane2button
[
this
.
_currentChild
];
if
(
b
){
dijit
.
focus
(
b
.
focusNode
||
b
.
domNode
);
}
},
// TODO: this is a bit redundant with forward, back api in StackContainer
adjacent
:
function
(
/*Boolean*/
forward
){
// find currently focused button in children array
var
children
=
this
.
getChildren
();
var
current
=
dojo
.
indexOf
(
children
,
this
.
pane2button
[
this
.
_currentChild
]);
// pick next button to focus on
var
offset
=
forward
?
1
:
children
.
length
-
1
;
return
children
[
(
current
+
offset
)
%
children
.
length
];
// dijit._Widget
},
onkeypress
:
function
(
/*Event*/
e
){
// summary:
// Handle keystrokes on the page list, for advancing to next/previous button
// and closing the current page if the page is closable.
if
(
this
.
disabled
||
e
.
altKey
){
return
;
}
var
forward
=
true
;
if
(
e
.
ctrlKey
||
!
e
.
_djpage
){
var
k
=
dojo
.
keys
;
switch
(
e
.
keyCode
){
case
k
.
LEFT_ARROW
:
case
k
.
UP_ARROW
:
case
k
.
PAGE_UP
:
forward
=
false
;
// fall through
case
k
.
RIGHT_ARROW
:
case
k
.
DOWN_ARROW
:
case
k
.
PAGE_DOWN
:
this
.
adjacent
(
forward
).
onClick
();
dojo
.
stopEvent
(
e
);
break
;
case
k
.
DELETE
:
if
(
this
.
_currentChild
.
closable
){
this
.
onCloseButtonClick
(
this
.
_currentChild
);
}
dojo
.
stopEvent
(
e
);
break
;
default
:
if
(
e
.
ctrlKey
){
if
(
e
.
keyCode
==
k
.
TAB
){
this
.
adjacent
(
!
e
.
shiftKey
).
onClick
();
dojo
.
stopEvent
(
e
);
}
else
if
(
e
.
keyChar
==
"w"
){
if
(
this
.
_currentChild
.
closable
){
this
.
onCloseButtonClick
(
this
.
_currentChild
);
}
dojo
.
stopEvent
(
e
);
// avoid browser tab closing.
}
}
}
}
},
onContainerKeyPress
:
function
(
/*Object*/
info
){
info
.
e
.
_djpage
=
info
.
page
;
this
.
onkeypress
(
info
.
e
);
}
});
dojo
.
declare
(
"dijit.layout._StackButton"
,
dijit
.
form
.
ToggleButton
,
{
// summary
// Internal widget used by StackContainer.
// The button-like or tab-like object you click to select or delete a page
tabIndex
:
"-1"
,
// StackContainer buttons are not in the tab order by default
postCreate
:
function
(
/*Event*/
evt
){
dijit
.
setWaiRole
((
this
.
focusNode
||
this
.
domNode
),
"tab"
);
this
.
inherited
(
"postCreate"
,
arguments
);
},
onClick
:
function
(
/*Event*/
evt
){
// summary: This is for TabContainer where the tabs are <span> rather than button,
// so need to set focus explicitly (on some browsers)
dijit
.
focus
(
this
.
focusNode
);
// ... now let StackController catch the event and tell me what to do
},
onClickCloseButton
:
function
(
/*Event*/
evt
){
// summary
// StackContainer connects to this function; if your widget contains a close button
// then clicking it should call this function.
evt
.
stopPropagation
();
}
});
// These arguments can be specified for the children of a StackContainer.
// Since any widget can be specified as a StackContainer child, mix them
// into the base widget class. (This is a hack, but it's effective.)
dojo
.
extend
(
dijit
.
_Widget
,
{
// title: String
// Title of this widget. Used by TabContainer to the name the tab, etc.
title
:
""
,
// selected: Boolean
// Is this child currently selected?
selected
:
false
,
// closable: Boolean
// True if user can close (destroy) this child, such as (for example) clicking the X on the tab.
closable
:
false
,
// true if user can close this tab pane
onClose
:
function
(){
// summary: Callback if someone tries to close the child, child will be closed if func returns true
return
true
;
}
});
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Wed, Apr 2, 13:35 (3 w, 6 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
26794
Default Alt Text
StackContainer.js (13 KB)
Attached To
rZED Zed
Event Timeline
Log In to Comment