← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 9968: (PT) Hide empty rows option implemented.

 

Merge authors:
  Jan Henrik Øverland (janhenrik-overland)
------------------------------------------------------------
revno: 9968 [merge]
committer: Jan Henrik Overland <janhenrik.overland@xxxxxxxxx>
branch nick: dhis2
timestamp: Mon 2013-03-04 17:34:23 +0100
message:
  (PT) Hide empty rows option implemented.
modified:
  dhis-2/dhis-web/dhis-web-pivot/src/main/java/org/hisp/dhis/pivot/action/InitializeAction.java
  dhis-2/dhis-web/dhis-web-pivot/src/main/resources/META-INF/dhis/beans.xml
  dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/app/scripts/app.js
  dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/app/scripts/core.js
  dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/app/styles/style.css
  dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/jsonInitialize.vm


--
lp:dhis2
https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk

Your team DHIS 2 developers is subscribed to branch lp:dhis2.
To unsubscribe from this branch go to https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk/+edit-subscription
=== modified file 'dhis-2/dhis-web/dhis-web-pivot/src/main/java/org/hisp/dhis/pivot/action/InitializeAction.java'
--- dhis-2/dhis-web/dhis-web-pivot/src/main/java/org/hisp/dhis/pivot/action/InitializeAction.java	2013-01-17 13:21:46 +0000
+++ dhis-2/dhis-web/dhis-web-pivot/src/main/java/org/hisp/dhis/pivot/action/InitializeAction.java	2013-02-25 15:39:41 +0000
@@ -33,6 +33,8 @@
 
 import org.apache.struts2.ServletActionContext;
 import org.hisp.dhis.api.utils.ContextUtils;
+import org.hisp.dhis.dataelement.DataElementGroupSet;
+import org.hisp.dhis.dataelement.DataElementService;
 import org.hisp.dhis.i18n.I18nFormat;
 import org.hisp.dhis.organisationunit.OrganisationUnit;
 import org.hisp.dhis.organisationunit.OrganisationUnitGroupService;
@@ -68,6 +70,13 @@
     {
         this.organisationUnitGroupService = organisationUnitGroupService;
     }
+    
+    private DataElementService dataElementService;
+
+    public void setDataElementService( DataElementService dataElementService )
+    {
+        this.dataElementService = dataElementService;
+    }
 
     private PeriodService periodService;
 
@@ -108,6 +117,13 @@
         return organisationUnitGroupSets;
     }
 
+    private Collection<DataElementGroupSet> dataElementGroupSets;
+
+    public Collection<DataElementGroupSet> getDataElementGroupSets()
+    {
+        return dataElementGroupSets;
+    }
+
     private List<Period> lastMonth;
 
     public List<Period> getLastMonth()
@@ -195,6 +211,8 @@
         }
 
         organisationUnitGroupSets = organisationUnitGroupService.getAllOrganisationUnitGroupSets();
+        
+        dataElementGroupSets = dataElementService.getAllDataElementGroupSets();
 
         RelativePeriods rp = new RelativePeriods();
 

=== modified file 'dhis-2/dhis-web/dhis-web-pivot/src/main/resources/META-INF/dhis/beans.xml'
--- dhis-2/dhis-web/dhis-web-pivot/src/main/resources/META-INF/dhis/beans.xml	2013-01-17 15:43:51 +0000
+++ dhis-2/dhis-web/dhis-web-pivot/src/main/resources/META-INF/dhis/beans.xml	2013-02-25 15:39:41 +0000
@@ -14,6 +14,7 @@
     class="org.hisp.dhis.pivot.action.InitializeAction"
     scope="prototype">
     <property name="organisationUnitService" ref="org.hisp.dhis.organisationunit.OrganisationUnitService" />
+    <property name="dataElementService" ref="org.hisp.dhis.dataelement.DataElementService" />
     <property name="periodService" ref="org.hisp.dhis.period.PeriodService" />
     <property name="organisationUnitGroupService" ref="org.hisp.dhis.organisationunit.OrganisationUnitGroupService" />
   </bean>

=== modified file 'dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/app/scripts/app.js'
--- dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/app/scripts/app.js	2013-02-25 13:47:24 +0000
+++ dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/app/scripts/app.js	2013-03-04 15:55:34 +0000
@@ -331,7 +331,7 @@
 		getData = function() {
 			var data = [{id: 'coc', name: 'Categories'}];
 
-			return data.concat(pt.init.ougs);
+			return data.concat(pt.init.ougs, pt.init.degs);
 		};
 
 		getStore = function(data) {
@@ -595,6 +595,7 @@
 
 	PT.app.OptionsWindow = function() {
 		var showSubTotals,
+			hideEmptyRows,
 			cellPadding,
 			fontSize,
 
@@ -603,7 +604,11 @@
 			window;
 
 		showSubTotals = Ext.create('Ext.form.field.Checkbox', {
-			boxLabel: 'Show sub totals'
+			boxLabel: 'Show sub totals' //i18n
+		});
+
+		hideEmptyRows = Ext.create('Ext.form.field.Checkbox', {
+			boxLabel: 'Hide empty rows' //i18n
 		});
 
 		cellPadding = Ext.create('Ext.form.field.ComboBox', {
@@ -649,7 +654,8 @@
 			bodyStyle: 'border:0 none',
 			style: 'margin-left:14px',
 			items: [
-				showSubTotals
+				showSubTotals,
+				hideEmptyRows
 			]
 		};
 
@@ -672,6 +678,7 @@
 			getOptions: function() {
 				return {
 					showSubTotals: showSubTotals.getValue(),
+					hideEmptyRows: hideEmptyRows.getValue(),
 					cellPadding: cellPadding.getValue(),
 					fontSize: fontSize.getValue()
 				};
@@ -1654,7 +1661,6 @@
 			};
 
 			organisationUnit = {
-				//id: 'organisationunit_t',
 				xtype: 'panel',
 				title: '<div class="pt-panel-title-organisationunit">Organisation units</div>', //i18n pt.i18n.organisation_units
 				bodyStyle: 'padding-top:5px',
@@ -1804,6 +1810,7 @@
 					{
 						xtype: 'treepanel',
 						cls: 'pt-tree',
+						style: 'border-top: 1px solid #ddd; padding-top: 1px',
 						width: pt.conf.layout.west_fieldset_width - pt.conf.layout.west_width_padding,
 						rootVisible: false,
 						autoScroll: true,
@@ -1957,24 +1964,17 @@
 				}
 			};
 
-			getOrganisationUnitGroupSetPanels = function() {
+			getGroupSetPanels = function(groupSets, url) {
 				var	getAvailableStore,
 					getSelectedStore,
 
 					createPanel,
 					getPanels;
 
-				getAvailableStore = function(groupSetId) {
+				getAvailableStore = function(groupSet) {
 					return Ext.create('Ext.data.Store', {
 						fields: ['id', 'name'],
-						proxy: {
-							type: 'ajax',
-							url: pt.conf.finals.ajax.path_api + 'organisationUnitGroupSets/' + groupSetId + '.json?links=false&paging=false',
-							reader: {
-								type: 'json',
-								root: 'organisationUnitGroups'
-							}
-						},
+						data: groupSet.items,
 						isLoaded: false,
 						storage: {},
 						sortStore: function() {
@@ -2093,7 +2093,7 @@
 						});
 					};
 
-					availableStore = getAvailableStore(groupSet.id);
+					availableStore = getAvailableStore(groupSet);
 					selectedStore = getSelectedStore();
 
 					available = getAvailable(availableStore);
@@ -2157,22 +2157,18 @@
 				};
 
 				getPanels = function() {
-					var ougs = pt.init.ougs,
-						panels = [],
+					var panels = [],
 						groupSet,
 						last;
 
-					for (var i = 0, panel; i < ougs.length; i++) {
-						groupSet = ougs[i];
+					for (var i = 0, panel; i < groupSets.length; i++) {
+						groupSet = groupSets[i];
 
 						panel = createPanel(groupSet);
 
 						panels.push(panel);
 					}
 
-					last = panels[panels.length - 1];
-					last.cls = 'pt-accordion-last';
-
 					return panels;
 				};
 
@@ -2211,7 +2207,7 @@
 				}
 
 				if (settings) {
-					pt.util.pivot.getTable(settings, pt, centerRegion);
+					pt.util.pivot.getTable(settings, pt);
 				}
 			};
 
@@ -2236,7 +2232,12 @@
 								organisationUnit
 							];
 
-							panels = panels.concat(getOrganisationUnitGroupSetPanels());
+							panels = panels.concat(getGroupSetPanels(pt.init.ougs, 'organisationUnitGroupSets'));
+
+							panels = panels.concat(getGroupSetPanels(pt.init.degs, 'dataElementGroupSets'));
+
+							last = panels[panels.length - 1];
+							last.cls = 'pt-accordion-last';
 
 							return panels;
 						}(),
@@ -2277,9 +2278,9 @@
 			optionsButton = Ext.create('Ext.button.Button', {
 				text: 'Options',
 				handler: function() {
-					//if (!pt.viewport.optionsWindow) {
-						//pt.viewport.optionsWindow = PT.app.OptionsWindow(pt);
-					//}
+					if (!pt.viewport.optionsWindow) {
+						pt.viewport.optionsWindow = PT.app.OptionsWindow();
+					}
 
 					pt.viewport.optionsWindow.show();
 				}
@@ -2428,6 +2429,8 @@
 				});
 			}();
 
+			pt.container = centerRegion;
+
 			return viewport;
 		};
 

=== modified file 'dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/app/scripts/core.js'
--- dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/app/scripts/core.js	2013-02-25 13:37:47 +0000
+++ dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/app/scripts/core.js	2013-03-04 16:31:27 +0000
@@ -130,7 +130,7 @@
         west_fill_accordion_dataelement: 63,
         west_fill_accordion_dataset: 33,
         west_fill_accordion_period: 256,
-        west_fill_accordion_organisationunit: 95,
+        west_fill_accordion_organisationunit: 62,
         west_maxheight_accordion_indicator: 620,
         west_maxheight_accordion_dataelement: 620,
         west_maxheight_accordion_dataset: 620,
@@ -427,27 +427,30 @@
 	util.pivot = {
 		getTdHtml: function(options, config) {
 			var cls,
-				colspan,
-				rowspan,
+				colSpan,
+				rowSpan,
 				htmlValue,
 				cellPadding,
 				fontSize;
 
 			if (!(config && Ext.isObject(config))) {
-				return '<td></td>';
+				return '';
 			}
 
-			cls = config.cls ? 'class="' + config.cls + '"' : '';
-			colspan = config.colspan ? 'colspan="' + config.colspan + '"' : '';
-			rowspan = config.rowspan ? 'rowspan="' + config.rowspan + '"' : '';
-			htmlValue = config.htmlValue || config.value || '&nbsp;';
+			cls = config.cls ? config.cls : '';
+			cls += config.hidden ? ' td-hidden' : '';
+			cls += config.collapsed ? ' td-collapsed' : '';
+			colSpan = config.colSpan ? 'colspan="' + config.colSpan + '"' : '';
+			rowSpan = config.rowSpan ? 'rowspan="' + config.rowSpan + '"' : '';
+			htmlValue = config.collapsed ? '' : config.htmlValue || config.value || '&nbsp;';
+			htmlValue = config.type !== 'dimension' ? pt.util.number.pp(htmlValue) : htmlValue;
 			cellPadding = pt.conf.pivot.cellPadding[config.cellPadding] || pt.conf.pivot.cellPadding[options.cellPadding];
 			fontSize = pt.conf.pivot.fontSize[config.fontSize] || pt.conf.pivot.fontSize[options.fontSize];
 
-			return '<td ' + cls + ' ' + colspan + ' ' + rowspan + ' style="padding:' + cellPadding + '; font-size:' + fontSize + ';">' + htmlValue + '</td>';
+			return '<td class="' + cls + '" ' + colSpan + ' ' + rowSpan + ' style="padding:' + cellPadding + '; font-size:' + fontSize + ';">' + htmlValue + '</td>';
 		},
 
-		getTable: function(settings, pt, container) {
+		getTable: function(settings, pt) {
 			var options = settings.options,
 				getParamStringFromDimensions,
 				extendSettings,
@@ -456,7 +459,6 @@
 				extendAxis,
 				extendRowAxis,
 				getTableHtmlArrays,
-				getTablePanel,
 				initialize;
 
 			extendSettings = function(settings) {
@@ -716,12 +718,13 @@
 				return response;
 			};
 
-			extendAxis = function(axis, xResponse) {
+			extendAxis = function(type, axis, xResponse) {
 				if (!axis || (Ext.isArray(axis) && !axis.length)) {
 					return;
 				}
 
 				var axis = Ext.clone(axis),
+					spanType = type === 'col' ? 'colSpan' : 'rowSpan',
 					nCols = 1,
 					aNumCols = [],
 					aAccNumCols = [],
@@ -729,6 +732,7 @@
 					aGuiItems = [],
 					aAllItems = [],
 					aColIds = [],
+					aAllObjects = [],
 					aUniqueIds;
 
 				aUniqueIds = function() {
@@ -831,13 +835,63 @@
 	//aColIds	= [ aaaaaaaaBBBBBBBBccccccc, aaaaaaaaaccccccccccbbbbbbbbbb, ... ]
 
 
+
+				// allObjects
+
+				for (var i = 0, allRow; i < aAllItems.length; i++) {
+					allRow = [];
+
+					for (var j = 0; j < aAllItems[i].length; j++) {
+						allRow.push({
+							id: aAllItems[i][j]
+						});
+					}
+
+					aAllObjects.push(allRow);
+				}
+
+				// add span
+				for (var i = 0; i < aAllObjects.length; i++) {
+					for (var j = 0, obj; j < aAllObjects[i].length; j += aSpan[i]) {
+						obj = aAllObjects[i][j];
+						obj[spanType] = aSpan[i];
+						obj.children = aSpan[i] === 1 ? 0 : aSpan[i];
+
+						if (i === 0) {
+							obj.root = true;
+						}
+					}
+				}
+
+				// add parents
+				if (aAllObjects.length > 1) {
+					for (var i = 1, allRow; i < aAllObjects.length; i++) {
+						allRow = aAllObjects[i];
+
+						for (var j = 0, obj, sizeCount = 0, span = aSpan[i - 1], parentObj = aAllObjects[i - 1][0]; j < allRow.length; j++) {
+							obj = allRow[j];
+							obj.parent = parentObj;
+							sizeCount++;
+
+							if (sizeCount === span) {
+								parentObj = aAllObjects[i - 1][j + 1];
+								sizeCount = 0;
+							}
+						}
+					}
+				}
+
 				return {
+					type: type,
 					items: axis,
 					xItems: {
 						unique: aUniqueIds,
 						gui: aGuiItems,
 						all: aAllItems
 					},
+					objects: {
+						all: aAllObjects
+					},
 					ids: aColIds,
 					span: aSpan,
 					dims: aUniqueIds.length,
@@ -845,43 +899,11 @@
 				};
 			};
 
-			extendRowAxis = function(rowAxis, xResponse) {
-				if (!rowAxis || (Ext.isArray(rowAxis) && !rowAxis.length)) {
-					return;
-				}
-
-				var xRowAxis = extendAxis(rowAxis, xResponse),
-					all = xRowAxis.xItems.all,
-					allObjects = [];
-
-				for (var i = 0, allRow; i < all.length; i++) {
-					allRow = [];
-
-					for (var j = 0; j < all[i].length; j++) {
-						allRow.push({
-							id: all[i][j]
-						});
-					}
-
-					allObjects.push(allRow);
-				}
-
-				for (var i = 0; i < allObjects.length; i++) {
-					for (var j = 0, object; j < allObjects[i].length; j += xRowAxis.span[i]) {
-						object = allObjects[i][j];
-						object.rowSpan = xRowAxis.span[i];
-					}
-				}
-
-				xRowAxis.xItems.allObjects = allObjects;
-
-				return xRowAxis;
-			};
-
 			getTableHtml = function(xColAxis, xRowAxis, xResponse) {
 				var getEmptyHtmlArray,
 					getColAxisHtmlArray,
 					getRowAxisHtmlArray,
+					rowAxisHtmlArray,
 					getValueHtmlArray,
 					getRowTotalHtmlArray,
 					getColTotalHtmlArray,
@@ -917,7 +939,7 @@
 					htmlArray;
 
 				doSubTotals = function(xAxis) {
-					return !!options.showSubTotals;
+					return !!options.showSubTotals && xAxis && xAxis.dims > 1;
 
 					//var multiItemDimension = 0,
 						//unique;
@@ -937,13 +959,14 @@
 					//return (multiItemDimension > 1);
 				};
 
-				getEmptyHtmlArray = function() {
-					return (xColAxis && xRowAxis) ?
-						pt.util.pivot.getTdHtml(options, {cls: 'pivot-dim-empty', colspan: xRowAxis.dims, rowspan: xColAxis.dims}) : '';
-				};
-
 				getColAxisHtmlArray = function() {
-					var a = [];
+					var a = [],
+						getEmptyHtmlArray;
+
+					getEmptyHtmlArray = function() {
+						return (xColAxis && xRowAxis) ?
+							pt.util.pivot.getTdHtml(options, {cls: 'pivot-dim-empty', colSpan: xRowAxis.dims, rowSpan: xColAxis.dims}) : '';
+					};
 
 					if (!(xColAxis && Ext.isObject(xColAxis))) {
 						return a;
@@ -962,21 +985,21 @@
 							id = dimItems[j];
 							dimHtml.push(pt.util.pivot.getTdHtml(options, {
 								cls: 'pivot-dim',
-								colspan: colSpan,
+								colSpan: colSpan,
 								htmlValue: xResponse.metaData[id]
 							}));
 
 							if (doSubTotals(xColAxis) && i === 0) {
 								dimHtml.push(pt.util.pivot.getTdHtml(options, {
 									cls: 'pivot-dim-subtotal',
-									rowspan: xColAxis.dims
+									rowSpan: xColAxis.dims
 								}));
 							}
 
 							if (i === 0 && j === (dimItems.length - 1)) {
 								dimHtml.push(pt.util.pivot.getTdHtml(options, {
 									cls: 'pivot-dim-total',
-									rowspan: xColAxis.dims,
+									rowSpan: xColAxis.dims,
 									htmlValue: 'Total'
 								}));
 							}
@@ -989,228 +1012,393 @@
 				};
 
 
-				getRowAxisHtmlArray = function() {
-					var a = [],
-						size,
-						allObjects,
-						uniqueSize,
-						count = 0;
-
-					if (!(xRowAxis && Ext.isObject(xRowAxis))) {
-						return a;
-					}
-
-					size = xRowAxis.size;
-					allObjects = xRowAxis.xItems.allObjects;
-					uniqueSize = xRowAxis.xItems.unique[xRowAxis.xItems.unique.length - 1].length;
-
-					// Dim html items
-					for (var i = 0, row, rowCount = 0; i < size; i++) {
-						row = [];
-						rowCount++;
-
-						for (var j = 0, object; j < xRowAxis.dims; j++) {
-							object = allObjects[j][i];
-
-							if (object.rowSpan) {
-								row.push(pt.util.pivot.getTdHtml(options, {
-									cls: 'pivot-dim nobreak',
-									rowspan: object.rowSpan,
-									htmlValue: xResponse.metaData[object.id]
-								}));
-							}
-						}
-
-						a.push(row);
-
-						//todo subtotal
-						if (doSubTotals(xRowAxis) && rowCount === rowUniqueFactor) {
-							row = [];
-							row.push(pt.util.pivot.getTdHtml(options, {
-								cls: 'pivot-dim-subtotal',
-								colspan: xRowAxis.dims
-							}));
-							a.push(row);
-							rowCount = 0;
-						}
-					}
-
-					return a;
-				};
+				//getRowAxisHtmlArray = function() {
+					//var a = [],
+						//size,
+						//allObjects,
+						//uniqueSize,
+						//count = 0;
+
+					//if (!(xRowAxis && Ext.isObject(xRowAxis))) {
+						//return a;
+					//}
+
+
+					//size = xRowAxis.size;
+					//allObjects = xRowAxis.objects.all;
+					//uniqueSize = xRowAxis.xItems.unique[xRowAxis.xItems.unique.length - 1].length;
+
+					//// Dim html items
+					//for (var i = 0, row, rowCount = 0; i < size; i++) {
+						//row = [];
+						//rowCount++;
+
+						//for (var j = 0, object; j < xRowAxis.dims; j++) {
+							//object = allObjects[j][i];
+
+							//if (object.rowSpan) {
+								//row.push(pt.util.pivot.getTdHtml(options, {
+									//cls: 'pivot-dim td-nobreak',
+									//rowSpan: object.rowSpan,
+									//htmlValue: xResponse.metaData[object.id]
+								//}));
+							//}
+						//}
+
+						//a.push(row);
+
+						////todo subtotal
+						//if (doSubTotals(xRowAxis) && rowCount === rowUniqueFactor) {
+							//row = [];
+							//row.push(pt.util.pivot.getTdHtml(options, {
+								//cls: 'pivot-dim-subtotal',
+								//colSpan: xRowAxis.dims
+							//}));
+							//a.push(row);
+							//rowCount = 0;
+						//}
+					//}
+
+					//rowAxisHtmlArray = a;
+
+					//return a;
+				//};
 
 				getValueHtmlArray = function() {
 					var a = [],
-						htmlValueItems = [],
-						htmlValueColItems = [],
+						axisObjects = [],
+						valueObjects = [],
+						totalValueObjects = [],
+						mergedObjects = [],
+						allObjects = [],
+						valueItemsCopy,
 						colSize = xColAxis ? xColAxis.size : 1,
 						rowSize = xRowAxis ? xRowAxis.size : 1,
 						rowRootSize = xRowAxis ? xRowAxis.xItems.unique[0].length : null,
-						hasSubtotals,
 						subtotal,
-						td;
-
-					// Value / htmlvalue items
-					for (var i = 0, valueItemRow, htmlValueItemRow; i < rowSize; i++) {
-						valueItemRow = [];
-						htmlValueItemRow = [];
+						td,
+						recursiveReduce;
+
+					recursiveReduce = function(obj) {
+						if (!obj.children) {
+							obj.collapsed = true;
+
+							if (obj.parent) {
+								obj.parent.children--;
+								obj.parent.rowSpan = obj.parent.parent ? obj.parent.rowSpan-- : obj.parent.rowSpan;
+							}
+						}
+
+						if (obj.parent) {
+							recursiveReduce(obj.parent);
+						}
+					};
+
+					// Populate dim objects
+					for (var i = 0, row; i < xRowAxis.objects.all[0].length; i++) {
+						row = [];
+
+						for (var j = 0, obj, newObj; j < xRowAxis.objects.all.length; j++) {
+							obj = xRowAxis.objects.all[j][i];
+							obj.type = 'dimension';
+							obj.cls = 'pivot-dim td-nobreak';
+							obj.noBreak = true;
+							obj.hidden = !(obj.rowSpan || obj.colSpan);
+							obj.htmlValue = xResponse.metaData[obj.id];
+
+							row.push(obj);
+						}
+
+						axisObjects.push(row);
+					}
+
+					// Value objects
+					for (var i = 0, valueItemsRow, valueObjectsRow; i < rowSize; i++) {
+						valueItemsRow = [];
+						valueObjectsRow = [];
 
 						for (var j = 0, id, value; j < colSize; j++) {
 							id = (xColAxis ? xColAxis.ids[j] : '') + (xRowAxis ? xRowAxis.ids[i] : '');
-
-							value = xResponse.idValueMap[id] ? parseFloat(xResponse.idValueMap[id]) : 0; //todo
-							htmlValue = xResponse.idValueMap[id] ? parseFloat(xResponse.idValueMap[id]) : '-'; //todo
-
-							valueItemRow.push(value);
-							htmlValueItemRow.push({value: value, htmlValue: htmlValue, cls: 'pivot-value'});
-						}
-
-						valueItems.push(valueItemRow);
-						htmlValueItems.push(htmlValueItemRow);
+							value = xResponse.idValueMap[id];
+
+							value = value ? parseFloat(value) : 0; //todo
+							htmlValue = value || '-'; //todo
+
+							valueItemsRow.push(value);
+							valueObjectsRow.push({
+								type: 'value',
+								cls: 'pivot-value',
+								value: value,
+								htmlValue: htmlValue,
+								empty: !!(htmlValue === '-')
+							});
+						}
+
+						valueItems.push(valueItemsRow);
+						valueObjects.push(valueObjectsRow);
+					}
+
+					// Value total objects
+					valueItemsCopy = Ext.clone(valueItems);
+
+					for (var i = 0, rowSum; i < valueItemsCopy.length; i++) {
+						rowSum = Ext.Array.sum(valueItemsCopy[i]);
+						totalValueObjects.push({
+							type: 'valueTotal',
+							value: rowSum,
+							htmlValue: rowSum,
+							cls: 'pivot-value-total'
+						});
+					}
+
+					// Hide empty rows/totals
+					if (options.hideEmptyRows) {
+						for (var i = 0, valueRow, empty, parent; i < valueObjects.length; i++) {
+							valueRow = valueObjects[i];
+							empty = [];
+
+							for (var j = 0; j < valueRow.length; j++) {
+								empty.push(!!valueRow[j].empty);
+							}
+
+							if (!Ext.Array.contains(empty, false) && xRowAxis) {
+
+								// Hide values
+								for (var j = 0; j < valueRow.length; j++) {
+									valueRow[j].collapsed = true;
+								}
+
+								// Hide total
+								totalValueObjects[i].collapsed = true;
+
+								// Hide/reduce parent dim span
+								parent = axisObjects[i][xRowAxis.dims-1];
+								recursiveReduce(parent);
+							}
+						}
 					}
 
 					if (doSubTotals(xColAxis)) {
-						var tmp = [];
+						var tmpValueObjects = [];
 
-						for (var i = 0, row, rowSubTotal, colCount; i < htmlValueItems.length; i++) {
+						for (var i = 0, row, rowSubTotal, colCount; i < valueObjects.length; i++) {
 							row = [];
 							rowSubTotal = 0;
 							colCount = 0;
 
-							for (var j = 0, item; j < htmlValueItems[i].length; j++) {
-								item = htmlValueItems[i][j];
+							for (var j = 0, item, collapsed = []; j < valueObjects[i].length; j++) {
+								item = valueObjects[i][j];
 								rowSubTotal += item.value;
+								collapsed.push(!!item.collapsed);
 								colCount++;
 
 								row.push(item);
 
 								if (colCount === colUniqueFactor) {
-									row.push({value: rowSubTotal, htmlValue: rowSubTotal, cls: 'pivot-value-subtotal'});
+									row.push({
+										type: 'valueSubtotal',
+										value: rowSubTotal,
+										htmlValue: rowSubTotal === 0 ? '-' : rowSubTotal.toString(),
+										cls: 'pivot-value-subtotal',
+										collapsed: !Ext.Array.contains(collapsed, false)
+									});
 									colCount = 0;
 									rowSubTotal = 0;
+									collapsed = [];
 								}
 							}
 
-							tmp.push(row);
+							tmpValueObjects.push(row);
 						}
 
-						htmlValueItems = tmp;
+						valueObjects = tmpValueObjects;
 					}
 
 					if (doSubTotals(xRowAxis)) {
-						var tmp = [],
-							subTotals = [],
-							count;
-
-						// Create sub total arrays
-						for (var i = 0; i < rowRootSize; i++) {
-							subTotals.push([]);
-						}
-
-						// Populate sub total arrays
-						for (var i = 0, subTotal, subTotalsIndex; i < htmlValueItems[0].length; i++) {
-							subTotal = 0;
-							subTotalsIndex = 0;
-
-							for (var j = 0, rowCount = 0, item; j < xRowAxis.size; j++) {
-								item = htmlValueItems[j][i];
+						var tmpAxisObjects = [],
+							tmpValueObjects = [],
+							tmpTotalValueObjects = [];
+
+						getAxisSubTotalRow = function(collapsed) {
+							var row = [];
+
+							for (var i = 0, obj; i < xRowAxis.dims; i++) {
+								obj = {};
+								obj.type = 'dimensionSubtotal';
+								obj.cls = 'pivot-dim-subtotal';
+								obj.collapsed = !Ext.Array.contains(collapsed, false);
+
+								if (i === 0) {
+									obj.htmlValue = '&nbsp;'; //i18n
+									obj.colSpan = xRowAxis.dims;
+								}
+								else {
+									obj.hidden = true;
+								}
+
+								row.push(obj);
+							}
+
+							return row;
+						};
+
+						// Row axis objects
+						for (var i = 0, row, collapsed = [], count = 0; i < axisObjects.length; i++) {
+							tmpAxisObjects.push(axisObjects[i]);
+							collapsed.push(!!axisObjects[i][0].collapsed);
+							count++;
+
+							if (count === xRowAxis.span[0]) {
+								tmpAxisObjects.push(getAxisSubTotalRow(collapsed));
+
+								collapsed = [];
+								count = 0;
+							}
+						}
+
+						// Create tmp value object arrays
+						for (var i = 0; i < tmpAxisObjects.length; i++) {
+							tmpValueObjects.push([]);
+						}
+
+						// Populate tmp value object arrays
+						for (var i = 0; i < valueObjects[0].length; i++) {
+							for (var j = 0, rowCount = 0, tmpCount = 0, subTotal = 0, empty, item; j < valueObjects.length; j++) {
+								item = valueObjects[j][i];
+								tmpValueObjects[tmpCount++].push(item);
 								subTotal += item.value;
 								rowCount++;
 
+								if (rowCount === 1) {
+									empty = !!tmpAxisObjects[j][0].collapsed;
+								}
+
 								if (rowCount === rowUniqueFactor) {
-									var cls = xColAxis && doSubTotals(xColAxis) && (item.cls === 'pivot-value-subtotal') ? 'pivot-value-subtotal-total' : 'pivot-value-subtotal';
-									subTotals[subTotalsIndex].push({value: subTotal, htmlValue: subTotal, cls: cls});
+									tmpValueObjects[tmpCount++].push({
+										type: item.cls === 'pivot-value-subtotal' ? 'valueSubtotal' : 'valueSubtotalTotal',
+										value: subTotal,
+										htmlValue: subTotal,
+										collapsed: empty,
+										cls: item.cls === 'pivot-value-subtotal' ? 'pivot-value-subtotal-total' : 'pivot-value-subtotal'
+									});
 									rowCount = 0;
 									subTotal = 0;
-									subTotalsIndex++;
 								}
 							}
 						}
 
-						// Add sub total arrays to htmlValueItems
-						for (var i = 0, count = 0; i < htmlValueItems.length; i++) {
-							tmp.push(htmlValueItems[i]);
+						// Total value objects
+						for (var i = 0, obj, collapsed = [], subTotal = 0, count = 0; i < totalValueObjects.length; i++) {
+							obj = totalValueObjects[i];
+							tmpTotalValueObjects.push(obj);
+
+							collapsed.push(!!obj.collapsed);
+							subTotal += obj.value;
 							count++;
 
-							if (count === rowUniqueFactor) {
+							if (count === xRowAxis.span[0]) {
+								tmpTotalValueObjects.push({
+									type: 'valueTotalSubgrandtotal',
+									cls: 'pivot-value-total-subgrandtotal',
+									value: subTotal,
+									htmlValue: subTotal,
+									collapsed: !Ext.Array.contains(collapsed, false)
+								});
+
+								collapsed = [];
+								subTotal = 0;
 								count = 0;
-
-								var sta = subTotals.shift();
-
-								tmp.push(sta);
 							}
 						}
 
-						htmlValueItems = tmp;
+						axisObjects = tmpAxisObjects;
+						valueObjects = tmpValueObjects;
+						totalValueObjects = tmpTotalValueObjects;
 					}
 
 					// Value html items
-					for (var i = 0, row; i < htmlValueItems.length; i++) {
+					//for (var i = 0, row; i < valueObjects.length; i++) {
+						//row = [];
+
+						//for (var j = 0, item, cls; j < valueObjects[i].length; j++) {
+							//item = valueObjects[i][j];
+
+							////if (Ext.isNumber(value)) {
+								////cls = value < 5000 ? 'bad' : (value < 20000 ? 'medium' : 'good'); //basic legendset
+							////}
+
+							//row.push(item);
+						//}
+
+						//a.push(row);
+					//}
+
+					// Merge dim, value, total
+					for (var i = 0, row; i < axisObjects.length; i++) {
+						row = [].concat(axisObjects[i], valueObjects[i], totalValueObjects[i]);
+
+						mergedObjects.push(row);
+					}
+
+					// Create html items
+					for (var i = 0, row; i < mergedObjects.length; i++) {
 						row = [];
 
-						for (var j = 0, item, cls; j < htmlValueItems[i].length; j++) {
-							item = htmlValueItems[i][j];
-
-							//if (Ext.isNumber(value)) {
-								//cls = value < 5000 ? 'bad' : (value < 20000 ? 'medium' : 'good'); //basic legendset
+						for (var j = 0; j < mergedObjects[i].length; j++) {
+							row.push(pt.util.pivot.getTdHtml(options, mergedObjects[i][j]));
+						}
+
+						a.push(row);
+					}
+
+					return a;
+				};
+
+				//getRowTotalHtmlArray = function() {
+					//var totalRowItems = [],
+						//vItems = Ext.clone(valueItems),
+						//a = [];
+
+					//if (xColAxis) {
+
+						//// Total row items
+						//for (var i = 0, rowSum; i < vItems.length; i++) {
+							//rowSum = Ext.Array.sum(vItems[i]);
+							//totalRowItems.push({value: rowSum, htmlValue: rowSum, cls: 'pivot-value-total'});
+						//}
+
+						//if (xRowAxis && doSubTotals(xRowAxis)) {
+							//var tmp = [];
+
+							//for (var i = 0, rowCount = 0, subTotal = 0; i < totalRowItems.length; i++) {
+								//tmp.push(totalRowItems[i]);
+								//rowCount++;
+								//subTotal += totalRowItems[i].value;
+
+								//if (rowCount === rowUniqueFactor) {
+									//tmp.push({value: subTotal, htmlValue: subTotal, cls: 'pivot-value-total-subgrandtotal'});
+									//rowCount = 0;
+									//subTotal = 0;
+								//}
 							//}
 
-							row.push(pt.util.pivot.getTdHtml(options, {
-								cls: item.cls,
-								htmlValue: pt.util.number.pp(item.htmlValue)
-							}));
-						}
-
-						a.push(row);
-					}
-
-					return a;
-				};
-
-				getRowTotalHtmlArray = function() {
-					var totalRowItems = [],
-						vItems = Ext.clone(valueItems),
-						a = [];
-
-					if (xColAxis) {
-
-						// Total row items
-						for (var i = 0, rowSum; i < vItems.length; i++) {
-							rowSum = Ext.Array.sum(vItems[i]);
-							totalRowItems.push({value: rowSum, htmlValue: rowSum, cls: 'pivot-value-total'});
-						}
-
-						if (xRowAxis && doSubTotals(xRowAxis)) {
-							var tmp = [];
-
-							for (var i = 0, rowCount = 0, subTotal = 0; i < totalRowItems.length; i++) {
-								tmp.push(totalRowItems[i]);
-								rowCount++;
-								subTotal += totalRowItems[i].value;
-
-								if (rowCount === rowUniqueFactor) {
-									tmp.push({value: subTotal, htmlValue: subTotal, cls: 'pivot-value-total-subgrandtotal'});
-									rowCount = 0;
-									subTotal = 0;
-								}
-							}
-
-							totalRowItems = tmp;
-						}
-
-						// Total row html items
-						for (var i = 0, item; i < totalRowItems.length; i++) {
-							item = totalRowItems[i];
-							item.htmlValue = pt.util.number.roundIf(item.htmlValue, 1);
-
-							a.push([pt.util.pivot.getTdHtml(options, {
-								cls: item.cls,
-								htmlValue: pt.util.number.pp(item.htmlValue)
-							})]);
-						}
-					}
-
-					return a;
-				};
+							//totalRowItems = tmp;
+						//}
+
+						//// Total row html items
+						//for (var i = 0, item; i < totalRowItems.length; i++) {
+							//item = totalRowItems[i];
+							//item.htmlValue = pt.util.number.roundIf(item.htmlValue, 1);
+
+							//a.push([pt.util.pivot.getTdHtml(options, {
+								//cls: item.cls,
+								//htmlValue: pt.util.number.pp(item.htmlValue)
+							//})]);
+						//}
+					//}
+
+					//return a;
+				//};
 
 
 				getColTotalHtmlArray = function() {
@@ -1311,7 +1499,7 @@
 					if (xRowAxis) {
 						dimTotalArray = [pt.util.pivot.getTdHtml(options, {
 							cls: 'pivot-dim-total',
-							colspan: xRowAxis.dims,
+							colSpan: xRowAxis.dims,
 							htmlValue: 'Total'
 						})];
 					}
@@ -1324,7 +1512,7 @@
 				};
 
 				getHtml = function() {
-					var s = '<table id="pivottable" class="pivot">';
+					var s = '<table id="' + pt.el + '" class="pivot">';
 
 					for (var i = 0; i < htmlArray.length; i++) {
 						s += '<tr>' + htmlArray[i].join('') + '</tr>';
@@ -1333,28 +1521,19 @@
 					return s += '</table>';
 				};
 
-				htmlArray = [].concat(getColAxisHtmlArray(), getRowHtmlArray(), getTotalHtmlArray());
+				htmlArray = [].concat(getColAxisHtmlArray(), getValueHtmlArray(), getTotalHtmlArray());
 				htmlArray = Ext.Array.clean(htmlArray);
 
 				return getHtml(htmlArray);
 			};
 
-			getTablePanel = function(html) {
-				return Ext.create('Ext.panel.Panel', {
-					bodyStyle: 'border:0 none',
-					autoScroll: true,
-					html: html
-				});
-			};
-
 			initialize = function() {
 				var xSettings,
 					xResponse,
 					xColAxis,
 					xRowAxis;
 
-				pt.util.mask.showMask(container);
-
+				pt.util.mask.showMask(pt.viewport);
 
 				xSettings = extendSettings(settings);
 
@@ -1372,8 +1551,7 @@
 						alert('Data request failed');
 					},
 					success: function(response) {
-						var html,
-							el;
+						var html;
 
 						if (!validateResponse(response)) {
 							pt.util.mask.hideMask();
@@ -1389,21 +1567,17 @@
 						}
 
 						xResponse = extendResponse(response, xSettings);
+console.log("xResponse", xResponse);
 
-						xColAxis = extendAxis(xSettings.col, xResponse);
-						xRowAxis = extendRowAxis(xSettings.row, xResponse);
+						xColAxis = extendAxis('col', xSettings.col, xResponse);
+						xRowAxis = extendAxis('row', xSettings.row, xResponse);
+console.log("xColAxis", xColAxis);
+console.log("xRowAxis", xRowAxis);
 
 						html = getTableHtml(xColAxis, xRowAxis, xResponse);
 
-						if (!pt.el && container) {
-							el = Ext.get('pivottable');
-
-							if (el) {
-								el.destroy();
-							}
-
-							container.update(html);
-						}
+						pt.container.removeAll(true);
+						pt.container.update(html);
 
 						pt.util.mask.hideMask();
 					}
@@ -1562,7 +1736,7 @@
 	var pt = {};
 
 	pt.baseUrl = config && config.baseUrl ? config.baseUrl : '../../';
-	pt.el = config && config.el ? config.el : null;
+	pt.el = config && config.el ? config.el : 'app';
 
 	pt.conf = PT.core.getConfigs();
 	pt.util = PT.core.getUtils(pt);

=== modified file 'dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/app/styles/style.css'
--- dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/app/styles/style.css	2013-02-25 13:37:19 +0000
+++ dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/app/styles/style.css	2013-03-01 10:57:44 +0000
@@ -54,7 +54,6 @@
 
 body {
     font-size: 10px;
-
 	-webkit-touch-callout: none;
 	-webkit-user-select: none;
 	-khtml-user-select: none;
@@ -63,6 +62,10 @@
 	user-select: none;
 }
 
+body.x-windows {
+	-webkit-text-stroke: 0.2px #888;
+}
+
 .pt-accordion-options .x-panel-body-default {
 	border: 0 none;
 }
@@ -81,10 +84,18 @@
 	position: fixed;
 }
 
-.nobreak {
+.td-nobreak {
 	white-space: nowrap;
 }
 
+.td-hidden {
+	display: none;
+}
+
+.td-collapsed {
+	display: none;
+}
+
 /*----------------------------------------------------------------------------
  * Pivot
  *--------------------------------------------------------------------------*/

=== modified file 'dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/jsonInitialize.vm'
--- dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/jsonInitialize.vm	2013-01-29 11:50:44 +0000
+++ dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/jsonInitialize.vm	2013-02-25 15:39:41 +0000
@@ -4,6 +4,7 @@
 "ou":{"id":"$currentUser.getOrganisationUnit().uid","name":"$currentUser.getOrganisationUnit().name"},
 "ouc":[#foreach($ou in $currentUser.getOrganisationUnit().getSortedChildren()){"id":"$ou.uid","name":"$ou.name"}#if($velocityCount < $oucSize),#end#end]},
 "rootNodes":[#foreach($node in $rootNodes){"id": "$!{node.uid}","text": "$!encoder.jsonEncode( ${node.name} )","level": 1,"hasChildrenWithCoordinates": $!{node.hasChildrenWithCoordinates()},"expanded": true}#if($velocityCount<$rootNodes.size()),#end#end],
-"ougs":[#foreach($ougs in $organisationUnitGroupSets){"id":"$!{ougs.uid}","name":"$!encoder.jsonEncode($!{ougs.name})","oug":[#foreach($oug in $ougs.getSortedGroups()){"id":"$!{oug.uid}","name":"$!encoder.jsonEncode($!{oug.name})"}#if($velocityCount<$ougs.getSortedGroups().size()),#end#end]}#if($velocityCount<$organisationUnitGroupSets.size()),#end#end]
+"ougs":[#foreach($ougs in $organisationUnitGroupSets){"id":"$!{ougs.uid}","name":"$!encoder.jsonEncode($!{ougs.name})","items":[#foreach($oug in $ougs.getSortedGroups()){"id":"$!{oug.uid}","name":"$!encoder.jsonEncode($!{oug.name})"}#if($velocityCount<$ougs.getSortedGroups().size()),#end#end]}#if($velocityCount<$organisationUnitGroupSets.size()),#end#end],
+"degs":[#foreach($degs in $dataElementGroupSets){"id":"$!{degs.uid}","name":"$!encoder.jsonEncode($!{degs.name})","items":[#foreach($deg in $degs.getSortedGroups()){"id":"$!{deg.uid}","name":"$!encoder.jsonEncode($!{deg.name})"}#if($velocityCount<$degs.getSortedGroups().size()),#end#end]}#if($velocityCount<$dataElementGroupSets.size()),#end#end]
 }
 															
\ No newline at end of file