]>
git.wh0rd.org - tt-rss.git/blob - lib/dijit/layout/StackController.js
e0d2075bbed743bac4e5c7917e635fd8a0a668db
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
8 if(!dojo
._hasResource
["dijit.layout.StackController"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
9 dojo
._hasResource
["dijit.layout.StackController"] = true;
10 dojo
.provide("dijit.layout.StackController");
11 dojo
.require("dijit._Widget");
12 dojo
.require("dijit._Templated");
13 dojo
.require("dijit._Container");
14 dojo
.require("dijit.form.ToggleButton");
15 dojo
.requireLocalization("dijit", "common", null, "ROOT,ar,ca,cs,da,de,el,es,fi,fr,he,hu,it,ja,kk,ko,nb,nl,pl,pt,pt-pt,ro,ru,sk,sl,sv,th,tr,zh,zh-tw");
19 "dijit.layout.StackController",
20 [dijit
._Widget
, dijit
._Templated
, dijit
._Container
],
23 // Set of buttons to select a page in a page list.
25 // Monitors the specified StackContainer, and whenever a page is
26 // added, deleted, or selected, updates itself accordingly.
28 templateString
: "<span role='tablist' dojoAttachEvent='onkeypress' class='dijitStackController'></span>",
30 // containerId: [const] String
31 // The id of the page container that I point to
34 // buttonWidget: [const] String
35 // The name of the button widget to create to correspond to each page
36 buttonWidget
: "dijit.layout._StackButton",
38 constructor: function(){
39 this.pane2button
= {}; // mapping from pane id to buttons
40 this.pane2connects
= {}; // mapping from pane id to this.connect() handles
41 this.pane2watches
= {}; // mapping from pane id to watch() handles
44 buildRendering: function(){
45 this.inherited(arguments
);
46 dijit
.setWaiRole(this.domNode
, "tablist"); // TODO: unneeded? it's in template above.
49 postCreate: function(){
50 this.inherited(arguments
);
52 // Listen to notifications from StackContainer
53 this.subscribe(this.containerId
+"-startup", "onStartup");
54 this.subscribe(this.containerId
+"-addChild", "onAddChild");
55 this.subscribe(this.containerId
+"-removeChild", "onRemoveChild");
56 this.subscribe(this.containerId
+"-selectChild", "onSelectChild");
57 this.subscribe(this.containerId
+"-containerKeyPress", "onContainerKeyPress");
60 onStartup: function(/*Object*/ info
){
62 // Called after StackContainer has finished initializing
65 dojo
.forEach(info
.children
, this.onAddChild
, this);
67 // Show button corresponding to selected pane (unless selected
68 // is null because there are no panes)
69 this.onSelectChild(info
.selected
);
74 for(var pane
in this.pane2button
){
75 this.onRemoveChild(dijit
.byId(pane
));
77 this.inherited(arguments
);
80 onAddChild: function(/*dijit._Widget*/ page
, /*Integer?*/ insertIndex
){
82 // Called whenever a page is added to the container.
83 // Create button corresponding to the page.
87 // create an instance of the button widget
88 var cls
= dojo
.getObject(this.buttonWidget
);
89 var button
= new cls({
90 id
: this.id
+ "_" + page
.id
,
94 showLabel
: page
.showTitle
,
95 iconClass
: page
.iconClass
,
96 closeButton
: page
.closable
,
99 dijit
.setWaiState(button
.focusNode
,"selected", "false");
102 // map from page attribute to corresponding tab button attribute
103 var pageAttrList
= ["title", "showTitle", "iconClass", "closable", "tooltip"],
104 buttonAttrList
= ["label", "showLabel", "iconClass", "closeButton", "title"];
106 // watch() so events like page title changes are reflected in tab button
107 this.pane2watches
[page
.id
] = dojo
.map(pageAttrList
, function(pageAttr
, idx
){
108 return page
.watch(pageAttr
, function(name
, oldVal
, newVal
){
109 button
.set(buttonAttrList
[idx
], newVal
);
113 // connections so that clicking a tab button selects the corresponding page
114 this.pane2connects
[page
.id
] = [
115 this.connect(button
, 'onClick', dojo
.hitch(this,"onButtonClick", page
)),
116 this.connect(button
, 'onClickCloseButton', dojo
.hitch(this,"onCloseButtonClick", page
))
119 this.addChild(button
, insertIndex
);
120 this.pane2button
[page
.id
] = button
;
121 page
.controlButton
= button
; // this value might be overwritten if two tabs point to same container
122 if(!this._currentChild
){ // put the first child into the tab order
123 button
.focusNode
.setAttribute("tabIndex", "0");
124 dijit
.setWaiState(button
.focusNode
, "selected", "true");
125 this._currentChild
= page
;
127 // make sure all tabs have the same length
128 if(!this.isLeftToRight() && dojo
.isIE
&& this._rectifyRtlTabList
){
129 this._rectifyRtlTabList();
133 onRemoveChild: function(/*dijit._Widget*/ page
){
135 // Called whenever a page is removed from the container.
136 // Remove the button corresponding to the page.
140 if(this._currentChild
=== page
){ this._currentChild
= null; }
142 // disconnect/unwatch connections/watches related to page being removed
143 dojo
.forEach(this.pane2connects
[page
.id
], dojo
.hitch(this, "disconnect"));
144 delete this.pane2connects
[page
.id
];
145 dojo
.forEach(this.pane2watches
[page
.id
], function(w
){ w
.unwatch(); });
146 delete this.pane2watches
[page
.id
];
148 var button
= this.pane2button
[page
.id
];
150 this.removeChild(button
);
151 delete this.pane2button
[page
.id
];
154 delete page
.controlButton
;
157 onSelectChild: function(/*dijit._Widget*/ page
){
159 // Called when a page has been selected in the StackContainer, either by me or by another StackController
165 if(this._currentChild
){
166 var oldButton
=this.pane2button
[this._currentChild
.id
];
167 oldButton
.set('checked', false);
168 dijit
.setWaiState(oldButton
.focusNode
, "selected", "false");
169 oldButton
.focusNode
.setAttribute("tabIndex", "-1");
172 var newButton
=this.pane2button
[page
.id
];
173 newButton
.set('checked', true);
174 dijit
.setWaiState(newButton
.focusNode
, "selected", "true");
175 this._currentChild
= page
;
176 newButton
.focusNode
.setAttribute("tabIndex", "0");
177 var container
= dijit
.byId(this.containerId
);
178 dijit
.setWaiState(container
.containerNode
, "labelledby", newButton
.id
);
181 onButtonClick: function(/*dijit._Widget*/ page
){
183 // Called whenever one of my child buttons is pressed in an attempt to select a page
187 var container
= dijit
.byId(this.containerId
);
188 container
.selectChild(page
);
191 onCloseButtonClick: function(/*dijit._Widget*/ page
){
193 // Called whenever one of my child buttons [X] is pressed in an attempt to close a page
197 var container
= dijit
.byId(this.containerId
);
198 container
.closeChild(page
);
199 if(this._currentChild
){
200 var b
= this.pane2button
[this._currentChild
.id
];
202 dijit
.focus(b
.focusNode
|| b
.domNode
);
207 // TODO: this is a bit redundant with forward, back api in StackContainer
208 adjacent: function(/*Boolean*/ forward
){
210 // Helper for onkeypress to find next/previous button
214 if(!this.isLeftToRight() && (!this.tabPosition
|| /top|bottom/.test(this.tabPosition
))){ forward
= !forward
; }
215 // find currently focused button in children array
216 var children
= this.getChildren();
217 var current
= dojo
.indexOf(children
, this.pane2button
[this._currentChild
.id
]);
218 // pick next button to focus on
219 var offset
= forward
? 1 : children
.length
- 1;
220 return children
[ (current
+ offset
) % children
.length
]; // dijit._Widget
223 onkeypress: function(/*Event*/ e
){
225 // Handle keystrokes on the page list, for advancing to next/previous button
226 // and closing the current page if the page is closable.
230 if(this.disabled
|| e
.altKey
){ return; }
232 if(e
.ctrlKey
|| !e
._djpage
){
234 switch(e
.charOrCode
){
237 if(!e
._djpage
){ forward
= false; }
240 if(e
.ctrlKey
){ forward
= false; }
244 if(!e
._djpage
){ forward
= true; }
247 if(e
.ctrlKey
){ forward
= true; }
251 var children
= this.getChildren();
252 if(children
&& children
.length
){
253 children
[e
.charOrCode
== k
.HOME
? 0 : children
.length
-1].onClick();
258 if(this._currentChild
.closable
){
259 this.onCloseButtonClick(this._currentChild
);
265 if(e
.charOrCode
=== k
.TAB
){
266 this.adjacent(!e
.shiftKey
).onClick();
268 }else if(e
.charOrCode
== "w"){
269 if(this._currentChild
.closable
){
270 this.onCloseButtonClick(this._currentChild
);
272 dojo
.stopEvent(e
); // avoid browser tab closing.
276 // handle next/previous page navigation (left/right arrow, etc.)
277 if(forward
!== null){
278 this.adjacent(forward
).onClick();
284 onContainerKeyPress: function(/*Object*/ info
){
286 // Called when there was a keypress on the container
289 info
.e
._djpage
= info
.page
;
290 this.onkeypress(info
.e
);
295 dojo
.declare("dijit.layout._StackButton",
296 dijit
.form
.ToggleButton
,
299 // Internal widget used by StackContainer.
301 // The button-like or tab-like object you click to select or delete a page
305 // Override _FormWidget.tabIndex.
306 // StackContainer buttons are not in the tab order by default.
307 // Probably we should be calling this.startupKeyNavChildren() instead.
310 buildRendering: function(/*Event*/ evt
){
311 this.inherited(arguments
);
312 dijit
.setWaiRole((this.focusNode
|| this.domNode
), "tab");
315 onClick: function(/*Event*/ evt
){
317 // This is for TabContainer where the tabs are <span> rather than button,
318 // so need to set focus explicitly (on some browsers)
319 // Note that you shouldn't override this method, but you can connect to it.
320 dijit
.focus(this.focusNode
);
322 // ... now let StackController catch the event and tell me what to do
325 onClickCloseButton: function(/*Event*/ evt
){
327 // StackContainer connects to this function; if your widget contains a close button
328 // then clicking it should call this function.
329 // Note that you shouldn't override this method, but you can connect to it.
330 evt
.stopPropagation();