Login Register

StackContainer

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). This container is good for wizards, slide shows, and long lists or text blocks.

Examples

Here's a freely pageable document.

This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below.

As used herein, "this License" refers to version 3 of the GNU Lesser General Public License, and the "GNU GPL" refers to version 3 of the GNU General Public License. "The Library" refers to a covered work governed by this License, other than an Application or a Combined Work as defined below.

You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
            "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Stack Container Demo</title>
    <style type="text/css">
        @import "http://o.aolcdn.com/dojo/1.0.0/dijit/themes/tundra/tundra.css";
        @import "http://o.aolcdn.com/dojo/1.0.0/dojo/resources/dojo.css"
    </style>
    <script type="text/javascript" src="http://o.aolcdn.com/dojo/1.0.0/dojo/dojo.xd.js"
        djConfig="parseOnLoad: true">
</script>
    <script type="text/javascript">
        dojo.require("dojo.parser");
        dojo.require("dijit.layout.ContentPane");
        dojo.require("dijit.layout.StackContainer");
        dojo.require("dijit.form.Button");
     </script>
</head>
<body class="tundra">
        <button id="previous" onClick="dijit.byId('mainTabContainer').back()"><</button>
        <button id="next" onClick="dijit.byId('mainTabContainer').forward()">></button>
        <div id="mainTabContainer" dojoType="dijit.layout.StackContainer"
             style="width: 90%; border:1px solid #9b9b9b; height: 20em;
                         margin: 0.5em 0 0.5em 0; padding: 0.5em;"
>

        <p id="Page1" dojoType="dijit.layout.ContentPane" label="Intro">
                This version of the GNU Lesser General Public License incorporates
                the terms and conditions of version 3 of the GNU General Public
                License, supplemented by the additional permissions listed below.
       
        <p id="Page2" dojoType="dijit.layout.ContentPane">
                As used herein, "this License" refers to version 3 of the GNU Lesser
                General Public License, and the "GNU GPL" refers to version 3 of the GNU
                General Public License. "The Library" refers to a covered work governed by
                this License, other than an Application or a Combined Work as defined below.
       
        <p id="Page3" dojoType="dijit.layout.ContentPane" >
                You may convey a covered work under sections 3 and 4 of this License
                without being bound by section 3 of the GNU GPL.
       
   </div>
</body></html>

Indication of the current child

As standard, there are no styles on the buttons associated with the StackContainer to indicate which child is currently being shown. However, Dijit adds a "dijitToggleButtonChecked" class to the button for the child being shown and we can use this class to provide styling ourselves. For example, we could use the following rules to highlight the button with a white background and, in Windows high contrast mode, a dashed border:
.dijitStackController .dijitToggleButtonChecked button {
    background-color: white;
    background-image: none;
}
.dijit_a11y .dijitStackController .dijitToggleButtonChecked button {
    border-style: dashed !important;
}
dijit.layout.StackContainer
A container of panes, one of which is always on top. Developer must provide navigation controls.
Attributes
doLayout Boolean
true
if true, change the size of my currently displayed child to match my size
Methods
addChild(/*Widget*/ child, /*Integer?*/ insertIndex) Process the given child widget, inserting its dom node as a child of our dom node
back() New for 1.0Select previous page.
forward() New for 1.0Select next page.
Widget[] getChildren() returns array of children widgets
Widget getNextSibling() returns the widget "to the right"
Widget getParent() returns the parent widget of this widget, assuming the parent implements dijit._Container
Widget getPreviousSibling() returns the widget "to the left"
removeChild(/*Widget*/ page) removes the passed widget instance from this widget but does not destroy it
resize(/* Object */ args) Explicitly set this widget size (in pixels), and then call layout() to resize contents (and maybe adjust child widgets). Args is of form {w: int, h: int, l: int, t: int}.
selectChild(/*Widget*/ page) Show the given widget (which must be one of my children)

Accessibility

Keyboard

ActionKey
Navigate to next tab buttonRight arrow
Navigate to previous tab buttonLeft arrow
Navigate into pageTab
Navigate to next pageCtrl + page down, ctrl + tab (except IE7)
Navigate to previous pageCtrl + page up
Delete a tabDelete, ctrl + w (updated for 1.0 - delete is not supported in stack container)

Pub/Sub For this Widget

Pub/Sub:

  • Topic : Object Expected -> Local Function it routes to
  • <widgetid>-startup : [{children: children, selected: selected}] -> onStartup(obj)
  • <widgetid>-addChild : [childPage, insertIndex] -> onAddChild(childPage, insertIndex)
  • <widgetid>-removeChild : [pageWidget] -> onRemoveChild(pageWidget)
  • <widgetid>-selectChild : [pageWidget] -> onSelectChild(pageWidget)
  • <widgetid>-containerKeyPress : [{ e: e, page: thisWidget}] -> onContainerKeyPress(obj)

(Let me know if I've missed any or if the format is funky)

Pagination component using toolbar (Works only with IE)

A pagination component I tried using IE and dojo

1. Toolbar component is used for this
2. Works only with IE
3. Uni button functionality is not done yet

var pageIndex = 0;
var nextIndex = 0;

var createPaginationBar = function(toolbarId) {
	console.debug("Creating the pagination bar " + toolbarId);
	
	var toolbarContainer = dojo.byId(toolbarId);
	var totalResults = 0;
	var pagesLimit = 0;
	var resultsLimit = 0;
	var totalPages = 0;
	var targetDiv = "";
	var url = "";
	var inputFields = new Array;
	var enableSingleRowNavigation = false;
	
	if (toolbarContainer) {
	
		/*
		 * url to be called
		 */
		url = toolbarContainer.url;
		
		console.debug("Pagination bar attribute : total number of records present : " + toolbarContainer.totalResults + " with url " + url);
		/*
		 * Total number of records present for pagination
		 */
		totalResults = (isNaN(toolbarContainer.totalResults) ? 0 : ((toolbarContainer.totalResults) * 1));
		
		/*
		 * Number of pages to be present to the user at a given point of time
		 */
		pagesLimit = (isNaN(toolbarContainer.pagesLimit) ? 5 : ((toolbarContainer.pagesLimit) * 1));
		
		/*
		 * Number of results to be shown to the user per page
		 */
		resultsLimit = (isNaN(toolbarContainer.resultsLimit) ? 10 : ((toolbarContainer.resultsLimit) * 1));
		
		/*
		 * Total number of pages present for calculation of number of pages to be shown
		 */
		totalPages = (totalResults > 0) ? Math.ceil((totalResults/resultsLimit)) : 0;
		
		/*
		 * Taget div to be populated
		 */
		targetDiv = toolbarContainer.target;
		
		/*
		 * Input fields if present any
		 */
		inputFields = toolbarContainer.inputFields;
		
		/*
		 * Enable single row navigation
		 */
		enableSingleRowNavigation = toolbarContainer.enableSingleRowNavigation;
		
		console.debug("Total number of pages present : " + totalPages);
		
		/*
		 * Creating the pagination tool bar
		 */
		var toolsbar = new dijit.Toolbar({
			id: toolbarId + "_toolbarContainer", 
			totalResults: totalResults
		}, toolbarContainer);
		
		/*
		 * Container for the pagination bar which contains the following 
		 * Title div - for title
		 * Pagination bar div - which contains the buttons necessary for pagination
		 * Pagination bar div -> Pagination div contains the following:
		 * Pagination bar div -> Pagination div -> Previous button div -> previous button
		 * Pagination bar div -> Pagination div -> Page button div -> set of page buttons
		 * Pagination bar div -> Pagination div -> Goto page div -> Goto text -> goto page spinner -> go to button
		 * Pagination bar div -> Pagination div -> Next button div -> next button
		 */
		var containerDiv = document.createElement("div");
		containerDiv.style.width="98%";
		
		/*
		 * Title bar
		 */
		var titleTxt = document.createElement("div");
		titleTxt.style.cssText = "float:left; padding-top: 5px;";
		titleTxt.innerHTML = toolbarContainer.title;
		
		containerDiv.appendChild(titleTxt);
		
		/*
		 * Pagination bar
		 */
		var pgnBar = document.createElement("div");
		
		/*
		 * Previous button div
		 */
		var prevButtonDiv = document.createElement("div");
		prevButtonDiv.style.cssText = "float:right";
		
		var upperLimit = 0;
		var lowerLimit = 0;
				
		/*
		 * Creating the previous button
		 */
		var prevButton = new dijit.form.Button({
			label: "", 
			disabled: true,
			style:"backgroundColor:#CCFFCC", 
			onClick: function() {
				console.debug("Previous button clicked");
				nextButton.domNode.style.backgroundColor="";
				nextButton.disabled = false;
				setLoadingMessage(targetDiv);
				
				/*
				 * Removing previous set of pages (buttons)
				 */
				
				clearPageButtonNodes(toolbarId);
				/*
				 * set the page index to the original value itself if it is less than
				 */
				pageIndex = (pageIndex - pagesLimit) >= 0 ? (pageIndex - pagesLimit) : 0;
				/*
				 * Adding next set of page buttons to the bar
				 */
				lowerLimit = pageIndex;
				upperLimit = ((pageIndex + pagesLimit) >= totalPages) ? totalPages - 1: (pageIndex + pagesLimit);
				
				//upperLimit = (lowerLimit >= (upperLimit - 1)) ? upperLimit + (totalPages - (upperLimit - 1)) : upperLimit;
				
				/*
				 * Calling the function to populate the result
				 */
				getResult(url, targetDiv, lowerLimit, resultsLimit, inputFields);
				 
				console.debug("Adding from pages " + lowerLimit + " : till : " + upperLimit);
				 
				/*
				 * If the displayed set is the first set of buttons
				 * disable the previous button
				 */
				 
				if(lowerLimit <= 0) {
					this.disabled = true;
				}
				 
				for (p = lowerLimit; p < upperLimit; p++) {
				 	
				 	if (p == lowerLimit) {
						pgButton[p].domNode.style.cssText = "background-color: #CCFFCC";
						pgButton[p].domNode.disabled = true;
					} else {
						pgButton[p].domNode.style.cssText = "background-color: #";
						pgButton[p].domNode.disabled = false;
					}
					
				 	pageButtonsDiv.appendChild(pgButton[p].domNode);
				}
				nextButton.focus();
				prevButton.focus();
			}
		}, prevButtonDiv);
		prevButton.style.cssText = prevButton.style.cssText + ";float:right;";
		
		prevButtonDiv.appendChild(prevButton.domNode);
		
		/*
		 * Creating the page buttons
		 */
		var pageButtonsDiv = document.createElement("div");
		pageButtonsDiv.id = toolbarId + "_pgButtons";
		pageButtonsDiv.style.cssText = "float:right; padding-top: 5px; text-align: center; width: 40%;";
		
		var pgButton = new Array;
		var pgNum = 0;
		var calc = 0;
		
		for (var p = 0; p < totalPages; p++) {
			
			pgNum = p;
			pgButton[pgButton.length] = new dijit.form.Button({
				id: ( toolbarId + "_pgButton_" + p), 
				label: ("" + (p + 1)), 
				onClick: function() {
					
					console.debug("Clicked: " + this.label);
					setLoadingMessage(targetDiv);
					/*
					 * Calling the function to populate the result
					 */
					getResult(url, targetDiv, ((this.label * 1) - 1), resultsLimit, inputFields);
					
					for (var q = 0; q < pgButton.length; q++) {
						pgButton[q].domNode.style.backgroundColor="";
						pgButton[q].domNode.disabled = false;
					}
					this.domNode.style.backgroundColor="#CCFFCC";
					this.domNode.disabled = true;
				}
			}, pageButtonsDiv);
		}
		pgNum = 0;
		for (var p = 0; p < ((pagesLimit <= totalPages) ? pagesLimit : totalPages); p++) {
			
			if (p == 0) {
				pgButton[p].domNode.style.backgroundColor="#CCFFCC";
				pgButton[p].domNode.disabled = true;
			}
			
			pageButtonsDiv.appendChild(pgButton[p].domNode);
		}
			
		
		/*
		 * Creating the next button
		 */
		var nextButtonDiv = document.createElement("div");
		nextButtonDiv.style.cssText = "float:right";
		
		var nextButton = new dijit.form.Button({
			label: "", 
			disabled:(totalPages <= pagesLimit) ? true : false,
			style:(totalPages <= pagesLimit) ? "backgroundColor:#CCFFCC" : "backgroundColor:#", 
			onClick: function() {
				console.debug("Next button clicked");
				prevButton.domNode.style.backgroundColor="";
				prevButton.disabled = false;
				setLoadingMessage(targetDiv);
				
				/*
				 * Fetching next set of pages (buttons)
				 */
				
				/* 
				 * Removing the existing set of displayed buttons
				 */
				 clearPageButtonNodes(toolbarId);
				 
				 //console.debug("Removing pages displayed from " + pageIndex + " : till : " + upperLimit);
				 
				 /*
				  * set the page index to the original value itself if it is less than
				  */
				 pageIndex = (pageIndex + pagesLimit) >= (totalPages - 1) ? (pageIndex + (totalPages - pageIndex)) : (pageIndex + pagesLimit);
				 /*
				  * Adding next set of page buttons to the bar
				  */
				 if (pageIndex == totalPages) {
				 	pageIndex = pageIndex - 1;
				 }
				 lowerLimit = pageIndex;
				 upperLimit = (pageIndex + pagesLimit) > (totalPages - 1) ? totalPages : (pageIndex + pagesLimit);
				 
				 upperLimit = (lowerLimit >= (upperLimit - 1)) ? (upperLimit + (totalPages - (upperLimit - 1)) - 1) : upperLimit;
				 
				 /*
				  * Calling the function to populate the result
				  */
				 getResult(url, targetDiv, lowerLimit, resultsLimit, inputFields);
				 
				 console.debug("Adding from pages " + lowerLimit + " : till : " + upperLimit);
				 
				 for (p = lowerLimit; p < upperLimit; p++) {
				 	
				 	pgButton[p].domNode.style.backgroundColor="";
					pgButton[p].domNode.disabled = false;
					
				 	pageButtonsDiv.appendChild(pgButton[p].domNode);
				 }
				 
				 pgButton[lowerLimit].domNode.style.backgroundColor="#CCFFCC";
				 pgButton[lowerLimit].domNode.disabled = true;
				 
				 /*
				  * If the displayed set is the last set of buttons
				  * disable the next button
				  */
				 if((totalPages - pageIndex) <= (pagesLimit)) {
				 	this.disabled = true;
				 }
				 //console.debug("Now the page index is : " + pageIndex);
				prevButton.focus();
				nextButton.focus();
			}
		}, nextButtonDiv);
		nextButton.style.cssText = nextButton.style.cssText + ";float:right;";
		
		nextButtonDiv.appendChild(nextButton.domNode);
		
		/*
		 * Goto page div
		 */
		var pgGotoDiv = document.createElement("div");
		
		var pageTxt = document.createElement("div");
		
		if (totalPages > pagesLimit) {
			var pgSpinnerDiv = document.createElement("div");
			pgSpinnerDiv.style.cssText = "float:right; padding-top: 5px;";
			
			var gotoButtonDiv = document.createElement("div");
			gotoButtonDiv.style.cssText = "float:right; padding-top: 5px;";
			
			pageTxt.style.cssText = "float:right; padding-top: 5px;";
			pageTxt.innerHTML = "   Page ";
			
			/*
			 * Adding the spinner for page numbers scroll
			 */
			var pgSpinner = new dijit.form.NumberSpinner({
				id: toolbarId + "_spinner", 
				name: toolbarId + "_spinner", 
				value: 1,
				style: "width: 70px;", 
				constraints: {min: 1, max: totalPages}, 
				invalidMessage: "Specified page does not exist!", 
				maxlength: 5
			}, pgSpinnerDiv);
			
			pgSpinnerDiv.appendChild(pgSpinner.domNode);
			
			/*
			 * Adding the goto button
			 */
			
			var gotoButton = new dijit.form.Button({
				id: toolbarId + "_gotoButton", 
				label: "Go!", 
				style:"background-color: lime; font-weight: bolder;", 
				onClick: function() {
					var selectedPage = dijit.byId((toolbarId + "_spinner")).getValue() - 1;
					//console.debug("Clicked on the goto button with " + selectedPage);
					
					if ((selectedPage < 0) || (selectedPage >= totalPages)) {
						alert("Specified page does not exists");
						
						return false;
						
					}
					
					setLoadingMessage(targetDiv);
					
					clearPageButtonNodes(toolbarId);
					
					var mod = (selectedPage % pagesLimit);
					
					lowerLimit = selectedPage - mod;
					upperLimit = ((totalPages - 1) - lowerLimit) <= pagesLimit ? totalPages : lowerLimit + pagesLimit;
					//console.debug("Mod is " + mod + " : Lower limit : " + lowerLimit + " : Upper limit : " + upperLimit);
					
					for (p = lowerLimit; p < upperLimit; p++) {
					 	
					 	pgButton[p].domNode.style.backgroundColor="";
						pgButton[p].domNode.disabled = false;
						
					 	pageButtonsDiv.appendChild(pgButton[p].domNode);
					}
					 
					pgButton[selectedPage].domNode.style.backgroundColor="#CCFFCC";
					pgButton[selectedPage].domNode.disabled = true;
					 
					pageIndex = lowerLimit;
					
					if (pageIndex < pagesLimit) {
						prevButton.disabled = true;
					} else {
						prevButton.disabled = false;
					}
					prevButton.focus();
					this.focus();
					
					if ((totalPages - (pageIndex + 1)) <= pagesLimit) {
						nextButton.disabled = true;
					} else {
						nextButton.disabled = false;
					}
					nextButton.focus();
					this.focus();
					
					//console.debug("The page index after goto button click : " + pageIndex);
					
					/*
					 * Calling the function to populate the result
					 */
					getResult(url, targetDiv, selectedPage, resultsLimit, inputFields);
					 
				}
			}, gotoButtonDiv);
			
			gotoButtonDiv.appendChild(gotoButton.domNode);
			
			pgGotoDiv.appendChild(gotoButtonDiv);
			pgGotoDiv.appendChild(pgSpinnerDiv);
			pgGotoDiv.appendChild(pageTxt);
		}
		
		if ((enableSingleRowNavigation) && (enableSingleRowNavigation == "true")) {
			
			var uniButtonDiv = document.createElement("div");
			
			/*
			 * Adding single record navigation
			 */
			var uniButton = new dijit.form.Button({
					id: toolbarId + "_uniButton", 
					label: "", 
					onClick: function() {
						console.debug("Clicked single row navigation");
					}
			}, uniButtonDiv);
			uniButtonDiv.style.cssText = "float:right;";
			
			if (totalResults < 2) {
				uniButton.disabled = true;
				uniButton.focus();
			}
			
			uniButtonDiv.appendChild(uniButton.domNode);
			pgnBar.appendChild(uniButtonDiv);
		}
		
		/*
		 * Adding the buttons to the pagination bar
		 */
		pgnBar.appendChild(nextButtonDiv);
		pgnBar.appendChild(pgGotoDiv);
		pgnBar.appendChild(pageButtonsDiv);
		pgnBar.appendChild(prevButtonDiv);
		
		/*
		 * Adding the pagination bar div to the container div
		 */
		containerDiv.appendChild(pgnBar);
		
		
		
		/*
		 * Adding the container bar div to the toolsbar div
		 */
		toolsbar.domNode.appendChild(containerDiv);
		
		console.debug("Pagination bar title : " + toolbarContainer.title);
		
		toolsbar.startup();
		
	}
};

var clearPageButtonNodes = function(toolbarId) {

	var pageButtonsDiv = document.getElementById(toolbarId + "_pgButtons");
	
	if(pageButtonsDiv) {
		
		var pgNodes = pageButtonsDiv.childNodes;
		var len = 0;
		
		if(pgNodes) {
			console.debug("Length of the child nodes : " + pgNodes.length);
			len = pgNodes.length;
			for (p = 0; p < len; p++) {
				
				pageButtonsDiv.removeChild(pgNodes[0]);
				
			}
			
		}
	}
};

var getResult = function (pgurl, targetDiv, pageRef, resultsLimit, inputFields) {
	
	//console.debug("Getting the result from url : " + pgurl + " : to target : " + targetDiv + " : and page : " + pageRef);
	var items = new Array;
	
	if (inputFields) {
		
		
		items = inputFields.split(",");
		
		//console.debug("Input fields to be sent : " + items.length);
		for (var p = 0; p < items.length; p++) {
			items[p] = dojo.trim(items[p]);
			console.debug("Values : " + items[p]);
		}
		
	}
	
	/*
	 * Creating the content obj of what to pass
	 */
	var contentObj = new Object();
	var tempObj = null;
	var tempVal = null;
	
	contentObj.strResultsLimit = resultsLimit;
	contentObj.strSelectedPage = (pageRef * 1) + 1;
		
	for (var p = 0; p < items.length; p++) {
		
		tempObj = dojo.query("[ref^='" +items[p]+ "']");
		
		if ((tempObj) && (tempObj.length > 0)) {
		
			tempVal = tempObj[0].value;
			
		} else {
			
			tempObj = dojo.query("[name^='" +items[p]+ "']");
			if ((tempObj) && (tempObj.length > 0)) {
				
				tempVal = tempObj[0].value;
				
			}  else {
			
				tempObj = dojo.query("[id^='" +items[p]+ "']");
				if ((tempObj) && (tempObj.length > 0)) {
					
					tempVal = tempObj[0].value;
					
				} 
			}
		}
		
		contentObj[items[p]] = tempVal;
		
	}
	
	dojo.xhrPost({	url: pgurl,
					content: contentObj, 
					load: function (data, ioArgs) {
							//console.debug("Refreshing the panel");
							var resDiv = dijit.byId(targetDiv);
							resDiv.refresh();
							
							//console.debug("Setting the results in panel : " + targetDiv);
							resDiv.setContent(data);
							//console.debug("After setting the results in panel : " + targetDiv);
							return data;
						},
					error: setError
				});
	
};
var setLoadingMessage = function(targetDiv) {
	
	if (targetDiv) {
		var resultPane = dijit.byId(targetDiv);
		var loadingMsg = "

Processing..."; resultPane.setContent(loadingMsg); } }; var setError = function() { dojo.byId("errorDiv").innerHTML = "Error"; } javascript Code: var createPager = function() { createPaginationBar('tools'); }; jsp code: div style="width: 100%; height: 80px;"> div id="tools" totalResults="31" url="/MyPage.do" inputFields="strField1, strField2" target="gridTbl" enableSingleRowNavigation="true"> /div>

div id="paginator" style="width: 100%; height: 50%; background-color: #FAEBD7;" dojoType="dijit.layout.ContentPane" onDownloadEnd="createPager"> /div>

RE: Pagination component using toolbar (Works only with IE)

id Mandatory ID for the pagination component
url Mandatory URL to be called to fetch the results
totalResults Mandatory Total number of pages / records present for pagination
target Mandatory Target component in which the results are to be shown
pagesLimit Optional Number of pages buttons to be displayed by default 5
resultsLimit Optional Total number of results to be displayed per page
inputFields Optional Set of input fields that are to be passed as parameters (Separated by commas)
title Optional Title of the pagination content displayed