]> git.wh0rd.org - tt-rss.git/blob - lib/dijit/layout/StackContainer.js.uncompressed.js
modify dojo rebuild script to remove uncompressed files
[tt-rss.git] / lib / dijit / layout / StackContainer.js.uncompressed.js
1 define("dijit/layout/StackContainer", [
2 "dojo/_base/array", // array.forEach array.indexOf array.some
3 "dojo/cookie", // cookie
4 "dojo/_base/declare", // declare
5 "dojo/dom-class", // domClass.add domClass.replace
6 "dojo/has", // has("dijit-legacy-requires")
7 "dojo/_base/lang", // lang.extend
8 "dojo/ready",
9 "dojo/topic", // publish
10 "../registry", // registry.byId
11 "../_WidgetBase",
12 "./_LayoutWidget",
13 "dojo/i18n!../nls/common"
14 ], function(array, cookie, declare, domClass, has, lang, ready, topic,
15 registry, _WidgetBase, _LayoutWidget){
16
17 // module:
18 // dijit/layout/StackContainer
19
20 // Back compat w/1.6, remove for 2.0
21 if(has("dijit-legacy-requires")){
22 ready(0, function(){
23 var requires = ["dijit/layout/StackController"];
24 require(requires); // use indirection so modules not rolled into a build
25 });
26 }
27
28 var StackContainer = declare("dijit.layout.StackContainer", _LayoutWidget, {
29 // summary:
30 // A container that has multiple children, but shows only
31 // one child at a time
32 //
33 // description:
34 // A container for widgets (ContentPanes, for example) That displays
35 // only one Widget at a time.
36 //
37 // Publishes topics [widgetId]-addChild, [widgetId]-removeChild, and [widgetId]-selectChild
38 //
39 // Can be base class for container, Wizard, Show, etc.
40 //
41 // See `StackContainer.ChildWidgetProperties` for details on the properties that can be set on
42 // children of a `StackContainer`.
43
44 // doLayout: Boolean
45 // If true, change the size of my currently displayed child to match my size
46 doLayout: true,
47
48 // persist: Boolean
49 // Remembers the selected child across sessions
50 persist: false,
51
52 baseClass: "dijitStackContainer",
53
54 /*=====
55 // selectedChildWidget: [readonly] dijit._Widget
56 // References the currently selected child widget, if any.
57 // Adjust selected child with selectChild() method.
58 selectedChildWidget: null,
59 =====*/
60
61 buildRendering: function(){
62 this.inherited(arguments);
63 domClass.add(this.domNode, "dijitLayoutContainer");
64 this.containerNode.setAttribute("role", "tabpanel");
65 },
66
67 postCreate: function(){
68 this.inherited(arguments);
69 this.connect(this.domNode, "onkeypress", this._onKeyPress);
70 },
71
72 startup: function(){
73 if(this._started){ return; }
74
75 var children = this.getChildren();
76
77 // Setup each page panel to be initially hidden
78 array.forEach(children, this._setupChild, this);
79
80 // Figure out which child to initially display, defaulting to first one
81 if(this.persist){
82 this.selectedChildWidget = registry.byId(cookie(this.id + "_selectedChild"));
83 }else{
84 array.some(children, function(child){
85 if(child.selected){
86 this.selectedChildWidget = child;
87 }
88 return child.selected;
89 }, this);
90 }
91 var selected = this.selectedChildWidget;
92 if(!selected && children[0]){
93 selected = this.selectedChildWidget = children[0];
94 selected.selected = true;
95 }
96
97 // Publish information about myself so any StackControllers can initialize.
98 // This needs to happen before this.inherited(arguments) so that for
99 // TabContainer, this._contentBox doesn't include the space for the tab labels.
100 topic.publish(this.id+"-startup", {children: children, selected: selected});
101
102 // Startup each child widget, and do initial layout like setting this._contentBox,
103 // then calls this.resize() which does the initial sizing on the selected child.
104 this.inherited(arguments);
105 },
106
107 resize: function(){
108 // Overrides _LayoutWidget.resize()
109 // Resize is called when we are first made visible (it's called from startup()
110 // if we are initially visible). If this is the first time we've been made
111 // visible then show our first child.
112 if(!this._hasBeenShown){
113 this._hasBeenShown = true;
114 var selected = this.selectedChildWidget;
115 if(selected){
116 this._showChild(selected);
117 }
118 }
119 this.inherited(arguments);
120 },
121
122 _setupChild: function(/*dijit/_WidgetBase*/ child){
123 // Overrides _LayoutWidget._setupChild()
124
125 this.inherited(arguments);
126
127 domClass.replace(child.domNode, "dijitHidden", "dijitVisible");
128
129 // remove the title attribute so it doesn't show up when i hover
130 // over a node
131 child.domNode.title = "";
132 },
133
134 addChild: function(/*dijit/_WidgetBase*/ child, /*Integer?*/ insertIndex){
135 // Overrides _Container.addChild() to do layout and publish events
136
137 this.inherited(arguments);
138
139 if(this._started){
140 topic.publish(this.id+"-addChild", child, insertIndex); // publish
141
142 // in case the tab titles have overflowed from one line to two lines
143 // (or, if this if first child, from zero lines to one line)
144 // TODO: w/ScrollingTabController this is no longer necessary, although
145 // ScrollTabController.resize() does need to get called to show/hide
146 // the navigation buttons as appropriate, but that's handled in ScrollingTabController.onAddChild().
147 // If this is updated to not layout [except for initial child added / last child removed], update
148 // "childless startup" test in StackContainer.html to check for no resize event after second addChild()
149 this.layout();
150
151 // if this is the first child, then select it
152 if(!this.selectedChildWidget){
153 this.selectChild(child);
154 }
155 }
156 },
157
158 removeChild: function(/*dijit/_WidgetBase*/ page){
159 // Overrides _Container.removeChild() to do layout and publish events
160
161 this.inherited(arguments);
162
163 if(this._started){
164 // this will notify any tablists to remove a button; do this first because it may affect sizing
165 topic.publish(this.id + "-removeChild", page); // publish
166 }
167
168 // If all our children are being destroyed than don't run the code below (to select another page),
169 // because we are deleting every page one by one
170 if(this._descendantsBeingDestroyed){ return; }
171
172 // Select new page to display, also updating TabController to show the respective tab.
173 // Do this before layout call because it can affect the height of the TabController.
174 if(this.selectedChildWidget === page){
175 this.selectedChildWidget = undefined;
176 if(this._started){
177 var children = this.getChildren();
178 if(children.length){
179 this.selectChild(children[0]);
180 }
181 }
182 }
183
184 if(this._started){
185 // In case the tab titles now take up one line instead of two lines
186 // (note though that ScrollingTabController never overflows to multiple lines),
187 // or the height has changed slightly because of addition/removal of tab which close icon
188 this.layout();
189 }
190 },
191
192 selectChild: function(/*dijit/_WidgetBase|String*/ page, /*Boolean*/ animate){
193 // summary:
194 // Show the given widget (which must be one of my children)
195 // page:
196 // Reference to child widget or id of child widget
197
198 page = registry.byId(page);
199
200 if(this.selectedChildWidget != page){
201 // Deselect old page and select new one
202 var d = this._transition(page, this.selectedChildWidget, animate);
203 this._set("selectedChildWidget", page);
204 topic.publish(this.id+"-selectChild", page); // publish
205
206 if(this.persist){
207 cookie(this.id + "_selectedChild", this.selectedChildWidget.id);
208 }
209 }
210
211 return d; // If child has an href, promise that fires when the child's href finishes loading
212 },
213
214 _transition: function(newWidget, oldWidget /*===== , animate =====*/){
215 // summary:
216 // Hide the old widget and display the new widget.
217 // Subclasses should override this.
218 // newWidget: dijit/_WidgetBase
219 // The newly selected widget.
220 // oldWidget: dijit/_WidgetBase
221 // The previously selected widget.
222 // animate: Boolean
223 // Used by AccordionContainer to turn on/off slide effect.
224 // tags:
225 // protected extension
226 if(oldWidget){
227 this._hideChild(oldWidget);
228 }
229 var d = this._showChild(newWidget);
230
231 // Size the new widget, in case this is the first time it's being shown,
232 // or I have been resized since the last time it was shown.
233 // Note that page must be visible for resizing to work.
234 if(newWidget.resize){
235 if(this.doLayout){
236 newWidget.resize(this._containerContentBox || this._contentBox);
237 }else{
238 // the child should pick it's own size but we still need to call resize()
239 // (with no arguments) to let the widget lay itself out
240 newWidget.resize();
241 }
242 }
243
244 return d; // If child has an href, promise that fires when the child's href finishes loading
245 },
246
247 _adjacent: function(/*Boolean*/ forward){
248 // summary:
249 // Gets the next/previous child widget in this container from the current selection.
250
251 // TODO: remove for 2.0 if this isn't being used. Otherwise, fix to skip disabled tabs.
252
253 var children = this.getChildren();
254 var index = array.indexOf(children, this.selectedChildWidget);
255 index += forward ? 1 : children.length - 1;
256 return children[ index % children.length ]; // dijit/_WidgetBase
257 },
258
259 forward: function(){
260 // summary:
261 // Advance to next page.
262 return this.selectChild(this._adjacent(true), true);
263 },
264
265 back: function(){
266 // summary:
267 // Go back to previous page.
268 return this.selectChild(this._adjacent(false), true);
269 },
270
271 _onKeyPress: function(e){
272 topic.publish(this.id+"-containerKeyPress", { e: e, page: this}); // publish
273 },
274
275 layout: function(){
276 // Implement _LayoutWidget.layout() virtual method.
277 var child = this.selectedChildWidget;
278 if(child && child.resize){
279 if(this.doLayout){
280 child.resize(this._containerContentBox || this._contentBox);
281 }else{
282 child.resize();
283 }
284 }
285 },
286
287 _showChild: function(/*dijit/_WidgetBase*/ page){
288 // summary:
289 // Show the specified child by changing it's CSS, and call _onShow()/onShow() so
290 // it can do any updates it needs regarding loading href's etc.
291 // returns:
292 // Promise that fires when page has finished showing, or true if there's no href
293 var children = this.getChildren();
294 page.isFirstChild = (page == children[0]);
295 page.isLastChild = (page == children[children.length-1]);
296 page._set("selected", true);
297
298 domClass.replace(page.domNode, "dijitVisible", "dijitHidden");
299
300 return (page._onShow && page._onShow()) || true;
301 },
302
303 _hideChild: function(/*dijit/_WidgetBase*/ page){
304 // summary:
305 // Hide the specified child by changing it's CSS, and call _onHide() so
306 // it's notified.
307 page._set("selected", false);
308 domClass.replace(page.domNode, "dijitHidden", "dijitVisible");
309
310 page.onHide && page.onHide();
311 },
312
313 closeChild: function(/*dijit/_WidgetBase*/ page){
314 // summary:
315 // Callback when user clicks the [X] to remove a page.
316 // If onClose() returns true then remove and destroy the child.
317 // tags:
318 // private
319 var remove = page.onClose(this, page);
320 if(remove){
321 this.removeChild(page);
322 // makes sure we can clean up executeScripts in ContentPane onUnLoad
323 page.destroyRecursive();
324 }
325 },
326
327 destroyDescendants: function(/*Boolean*/ preserveDom){
328 this._descendantsBeingDestroyed = true;
329 this.selectedChildWidget = undefined;
330 array.forEach(this.getChildren(), function(child){
331 if(!preserveDom){
332 this.removeChild(child);
333 }
334 child.destroyRecursive(preserveDom);
335 }, this);
336 this._descendantsBeingDestroyed = false;
337 }
338 });
339
340 StackContainer.ChildWidgetProperties = {
341 // summary:
342 // These properties can be specified for the children of a StackContainer.
343
344 // selected: Boolean
345 // Specifies that this widget should be the initially displayed pane.
346 // Note: to change the selected child use `dijit/layout/StackContainer.selectChild`
347 selected: false,
348
349 // disabled: Boolean
350 // Specifies that the button to select this pane should be disabled.
351 // Doesn't affect programmatic selection of the pane, nor does it deselect the pane if it is currently selected.
352 disabled: false,
353
354 // closable: Boolean
355 // True if user can close (destroy) this child, such as (for example) clicking the X on the tab.
356 closable: false,
357
358 // iconClass: String
359 // CSS Class specifying icon to use in label associated with this pane.
360 iconClass: "dijitNoIcon",
361
362 // showTitle: Boolean
363 // When true, display title of this widget as tab label etc., rather than just using
364 // icon specified in iconClass
365 showTitle: true
366 };
367
368 // Since any widget can be specified as a StackContainer child, mix them
369 // into the base widget class. (This is a hack, but it's effective.)
370 // This is for the benefit of the parser. Remove for 2.0. Also, hide from doc viewer.
371 lang.extend(_WidgetBase, /*===== {} || =====*/ StackContainer.ChildWidgetProperties);
372
373 return StackContainer;
374 });