dhis2-devs team mailing list archive
-
dhis2-devs team
-
Mailing list archive
-
Message #25353
[Branch ~dhis2-devs-core/dhis2/trunk] Rev 12557: (PT) Plugin, work in progress.
Merge authors:
Jan Henrik Øverland (janhenrik-overland)
------------------------------------------------------------
revno: 12557 [merge]
committer: Jan Henrik Overland <janhenrik.overland@xxxxxxxxx>
branch nick: dhis2
timestamp: Thu 2013-10-10 13:50:29 +0200
message:
(PT) Plugin, work in progress.
added:
dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/plugin/table.js
--
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
=== added file 'dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/plugin/table.js'
--- dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/plugin/table.js 1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/plugin/table.js 2013-10-10 11:49:54 +0000
@@ -0,0 +1,2870 @@
+Ext.onReady( function() {
+
+ // ext config
+ Ext.Ajax.method = 'GET';
+
+ // pt
+ PT = {
+ core: {
+ instances: []
+ },
+ i18n: {},
+ isDebug: false,
+ isSessionStorage: 'sessionStorage' in window && window['sessionStorage'] !== null
+ };
+
+ // CORE
+
+ PT.core.getInstance = function(init) {
+ var conf = {},
+ util = {},
+ api = {},
+ service = {},
+ engine = {},
+ dimConf;
+
+ // conf
+ (function() {
+ conf.finals = {
+ url: {
+ path_module: '/dhis-web-pivot/',
+ path_api: '/api/',
+ path_commons: '/dhis-web-commons-ajax-json/',
+ data_get: 'chartValues.json',
+ indicator_get: 'indicatorGroups/',
+ indicator_getall: 'indicators.json?paging=false&links=false',
+ indicatorgroup_get: 'indicatorGroups.json?paging=false&links=false',
+ dataelement_get: 'dataElementGroups/',
+ dataelement_getall: 'dataElements.json?paging=false&links=false',
+ dataelementgroup_get: 'dataElementGroups.json?paging=false&links=false',
+ dataset_get: 'dataSets.json?paging=false&links=false',
+ organisationunit_getbygroup: 'getOrganisationUnitPathsByGroup.action',
+ organisationunit_getbylevel: 'getOrganisationUnitPathsByLevel.action',
+ organisationunit_getbyids: 'getOrganisationUnitPaths.action',
+ organisationunitgroup_getall: 'organisationUnitGroups.json?paging=false&links=false',
+ organisationunitgroupset_get: 'getOrganisationUnitGroupSetsMinified.action',
+ organisationunitlevel_getall: 'organisationUnitLevels.json?paging=false&links=false&viewClass=detailed',
+ organisationunitchildren_get: 'getOrganisationUnitChildren.action',
+ favorite_addorupdate: 'addOrUpdateChart.action',
+ favorite_addorupdatesystem: 'addOrUpdateSystemChart.action',
+ favorite_updatename: 'updateChartName.action',
+ favorite_get: 'charts/',
+ favorite_getall: 'getSystemAndCurrentUserCharts.action',
+ favorite_delete: 'deleteCharts.action'
+ },
+ dimension: {
+ data: {
+ value: 'data',
+ name: PT.i18n.data,
+ dimensionName: 'dx',
+ objectName: 'dx',
+ warning: {
+ filter: '...'//PT.i18n.wm_multiple_filter_ind_de
+ }
+ },
+ category: {
+ name: PT.i18n.categories,
+ dimensionName: 'co',
+ objectName: 'co',
+ },
+ indicator: {
+ value: 'indicators',
+ name: PT.i18n.indicators,
+ dimensionName: 'dx',
+ objectName: 'in'
+ },
+ dataElement: {
+ value: 'dataElements',
+ name: PT.i18n.data_elements,
+ dimensionName: 'dx',
+ objectName: 'de'
+ },
+ operand: {
+ value: 'operand',
+ name: 'Operand',
+ dimensionName: 'dx',
+ objectName: 'dc'
+ },
+ dataSet: {
+ value: 'dataSets',
+ name: PT.i18n.data_sets,
+ dimensionName: 'dx',
+ objectName: 'ds'
+ },
+ period: {
+ value: 'period',
+ name: PT.i18n.periods,
+ dimensionName: 'pe',
+ objectName: 'pe'
+ },
+ fixedPeriod: {
+ value: 'periods'
+ },
+ relativePeriod: {
+ value: 'relativePeriods'
+ },
+ organisationUnit: {
+ value: 'organisationUnits',
+ name: PT.i18n.organisation_units,
+ dimensionName: 'ou',
+ objectName: 'ou'
+ },
+ dimension: {
+ value: 'dimension'
+ //objectName: 'di'
+ },
+ value: {
+ value: 'value'
+ }
+ },
+ root: {
+ id: 'root'
+ }
+ };
+
+ dimConf = conf.finals.dimension;
+
+ dimConf.objectNameMap = {};
+ dimConf.objectNameMap[dimConf.data.objectName] = dimConf.data;
+ dimConf.objectNameMap[dimConf.indicator.objectName] = dimConf.indicator;
+ dimConf.objectNameMap[dimConf.dataElement.objectName] = dimConf.dataElement;
+ dimConf.objectNameMap[dimConf.operand.objectName] = dimConf.operand;
+ dimConf.objectNameMap[dimConf.dataSet.objectName] = dimConf.dataSet;
+ dimConf.objectNameMap[dimConf.category.objectName] = dimConf.category;
+ dimConf.objectNameMap[dimConf.period.objectName] = dimConf.period;
+ dimConf.objectNameMap[dimConf.organisationUnit.objectName] = dimConf.organisationUnit;
+ dimConf.objectNameMap[dimConf.dimension.objectName] = dimConf.dimension;
+
+ conf.period = {
+ relativePeriods: {
+ 'LAST_WEEK': 1,
+ 'LAST_4_WEEKS': 4,
+ 'LAST_12_WEEKS': 12,
+ 'LAST_MONTH': 1,
+ 'LAST_3_MONTHS': 3,
+ 'LAST_BIMONTH': 1,
+ 'LAST_6_BIMONTHS': 6,
+ 'LAST_12_MONTHS': 12,
+ 'LAST_QUARTER': 1,
+ 'LAST_4_QUARTERS': 4,
+ 'LAST_SIX_MONTH': 1,
+ 'LAST_2_SIXMONTHS': 2,
+ 'LAST_FINANCIAL_YEAR': 1,
+ 'LAST_5_FINANCIAL_YEARS': 6,
+ 'THIS_YEAR': 1,
+ 'LAST_YEAR': 1,
+ 'LAST_5_YEARS': 5
+ },
+ relativePeriodValueKeys: {
+ 'LAST_WEEK': 'lastWeek',
+ 'LAST_4_WEEKS': 'last4Weeks',
+ 'LAST_12_WEEKS': 'last12Weeks',
+ 'LAST_MONTH': 'lastMonth',
+ 'LAST_3_MONTHS': 'last3Months',
+ 'LAST_12_MONTHS': 'last12Months',
+ 'LAST_BIMONTH': 'lastBimonth',
+ 'LAST_6_BIMONTHS': 'last6BiMonths',
+ 'LAST_QUARTER': 'lastQuarter',
+ 'LAST_4_QUARTERS': 'last4Quarters',
+ 'LAST_SIX_MONTH': 'lastSixMonth',
+ 'LAST_2_SIXMONTHS': 'last2SixMonths',
+ 'LAST_FINANCIAL_YEAR': 'lastFinancialYear',
+ 'LAST_5_FINANCIAL_YEARS': 'last5FinancialYears',
+ 'THIS_YEAR': 'thisYear',
+ 'LAST_YEAR': 'lastYear',
+ 'LAST_5_YEARS': 'last5Years'
+ },
+ relativePeriodParamKeys: {
+ 'lastWeek': 'LAST_WEEK',
+ 'last4Weeks': 'LAST_4_WEEKS',
+ 'last12Weeks': 'LAST_12_WEEKS',
+ 'lastMonth': 'LAST_MONTH',
+ 'last3Months': 'LAST_3_MONTHS',
+ 'last12Months': 'LAST_12_MONTHS',
+ 'lastBimonth': 'LAST_BIMONTH',
+ 'last6BiMonths': 'LAST_6_BIMONTHS',
+ 'lastQuarter': 'LAST_QUARTER',
+ 'last4Quarters': 'LAST_4_QUARTERS',
+ 'lastSixMonth': 'LAST_SIX_MONTH',
+ 'last2SixMonths': 'LAST_2_SIXMONTHS',
+ 'lastFinancialYear': 'LAST_FINANCIAL_YEAR',
+ 'last5FinancialYears': 'LAST_5_FINANCIAL_YEARS',
+ 'thisYear': 'THIS_YEAR',
+ 'lastYear': 'LAST_YEAR',
+ 'last5Years': 'LAST_5_YEARS'
+ },
+ periodTypes: [
+ {id: 'Daily', name: 'Daily'},
+ {id: 'Weekly', name: 'Weekly'},
+ {id: 'Monthly', name: 'Monthly'},
+ {id: 'BiMonthly', name: 'BiMonthly'},
+ {id: 'Quarterly', name: 'Quarterly'},
+ {id: 'SixMonthly', name: 'SixMonthly'},
+ {id: 'Yearly', name: 'Yearly'},
+ {id: 'FinancialOct', name: 'FinancialOct'},
+ {id: 'FinancialJuly', name: 'FinancialJuly'},
+ {id: 'FinancialApril', name: 'FinancialApril'}
+ ]
+ };
+
+ conf.layout = {
+ west_width: 424,
+ west_fieldset_width: 416,
+ west_width_padding: 4,
+ west_fill: 2,
+ west_fill_accordion_indicator: 59,
+ west_fill_accordion_dataelement: 59,
+ west_fill_accordion_dataset: 33,
+ west_fill_accordion_period: 296,
+ west_fill_accordion_organisationunit: 62,
+ west_maxheight_accordion_indicator: 400,
+ west_maxheight_accordion_dataelement: 400,
+ west_maxheight_accordion_dataset: 400,
+ west_maxheight_accordion_period: 513,
+ west_maxheight_accordion_organisationunit: 900,
+ west_maxheight_accordion_group: 340,
+ west_maxheight_accordion_options: 449,
+ west_scrollbarheight_accordion_indicator: 300,
+ west_scrollbarheight_accordion_dataelement: 300,
+ west_scrollbarheight_accordion_dataset: 300,
+ west_scrollbarheight_accordion_period: 450,
+ west_scrollbarheight_accordion_organisationunit: 450,
+ west_scrollbarheight_accordion_group: 300,
+ east_tbar_height: 31,
+ east_gridcolumn_height: 30,
+ form_label_width: 55,
+ window_favorite_ypos: 100,
+ window_confirm_width: 250,
+ window_share_width: 500,
+ grid_favorite_width: 420,
+ grid_row_height: 27,
+ treepanel_minheight: 135,
+ treepanel_maxheight: 400,
+ treepanel_fill_default: 310,
+ treepanel_toolbar_menu_width_group: 140,
+ treepanel_toolbar_menu_width_level: 120,
+ multiselect_minheight: 100,
+ multiselect_maxheight: 250,
+ multiselect_fill_default: 345,
+ multiselect_fill_reportingrates: 315
+ };
+
+ conf.pivot = {
+ digitGroupSeparator: {
+ 'comma': ',',
+ 'space': ' '
+ },
+ displayDensity: {
+ 'compact': '3px',
+ 'normal': '5px',
+ 'comfortable': '10px',
+ },
+ fontSize: {
+ 'small': '10px',
+ 'normal': '11px',
+ 'large': '13px'
+ }
+ };
+ }());
+
+ // util
+ (function() {
+ util.object = {
+ getLength: function(object) {
+ var size = 0;
+
+ for (var key in object) {
+ if (object.hasOwnProperty(key)) {
+ size++;
+ }
+ }
+
+ return size;
+ }
+ };
+
+ util.mask = {
+ showMask: function(cmp, msg) {
+ msg = msg || 'Loading..';
+
+ if (cmp.mask) {
+ cmp.mask.destroy();
+ }
+ cmp.mask = new Ext.create('Ext.LoadMask', cmp, {
+ shadow: false,
+ msg: msg,
+ style: 'box-shadow:0',
+ bodyStyle: 'box-shadow:0'
+ });
+ cmp.mask.show();
+ },
+ hideMask: function(cmp) {
+ if (cmp.mask) {
+ cmp.mask.hide();
+ }
+ }
+ };
+
+ util.store = {
+ addToStorage: function(s, records) {
+ s.each( function(r) {
+ if (!s.storage[r.data.id]) {
+ s.storage[r.data.id] = {id: r.data.id, name: r.data.name, parent: s.parent};
+ }
+ });
+ if (records) {
+ Ext.Array.each(records, function(r) {
+ if (!s.storage[r.data.id]) {
+ s.storage[r.data.id] = {id: r.data.id, name: r.data.name, parent: s.parent};
+ }
+ });
+ }
+ },
+ loadFromStorage: function(s) {
+ var items = [];
+ s.removeAll();
+ for (var obj in s.storage) {
+ if (s.storage[obj].parent === s.parent) {
+ items.push(s.storage[obj]);
+ }
+ }
+ s.add(items);
+ s.sort('name', 'ASC');
+ },
+ containsParent: function(s) {
+ for (var obj in s.storage) {
+ if (s.storage[obj].parent === s.parent) {
+ return true;
+ }
+ }
+ return false;
+ }
+ };
+
+ util.array = {
+ sortDimensions: function(dimensions, key) {
+ key = key || 'dimensionName';
+
+ // Sort object order
+ Ext.Array.sort(dimensions, function(a,b) {
+ if (a[key] < b[key]) {
+ return -1;
+ }
+ if (a[key] > b[key]) {
+ return 1;
+ }
+ return 0;
+ });
+
+ // Sort object items, ids
+ for (var i = 0, dim; i < dimensions.length; i++) {
+ dim = dimensions[i];
+
+ if (dim.items) {
+ dimensions[i].items = util.array.sortDimensions(dim.items, 'id');
+ }
+
+ if (dim.ids) {
+ dimensions[i].ids = dim.ids.sort();
+ }
+ }
+
+ return dimensions;
+ },
+
+ sortObjectsByString: function(array, key) {
+ key = key || 'name';
+ array.sort( function(a, b) {
+ var nameA = a[key].toLowerCase(),
+ nameB = b[key].toLowerCase();
+
+ if (nameA < nameB) {
+ return -1;
+ }
+ if (nameA > nameB) {
+ return 1;
+ }
+ return 0;
+ });
+ return array;
+ }
+ };
+
+ util.number = {
+ getNumberOfDecimals: function(x) {
+ var tmp = new String(x);
+ return (tmp.indexOf('.') > -1) ? (tmp.length - tmp.indexOf('.') - 1) : 0;
+ },
+
+ roundIf: function(x, prec) {
+ x = parseFloat(x);
+ prec = parseFloat(prec);
+
+ if (Ext.isNumber(x) && Ext.isNumber(prec)) {
+ var dec = util.number.getNumberOfDecimals(x);
+ return dec > prec ? Ext.Number.toFixed(x, prec) : x;
+ }
+ return x;
+ },
+
+ pp: function(x, nf) {
+ nf = nf || 'space';
+
+ if (nf === 'none') {
+ return x;
+ }
+
+ return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, conf.pivot.digitGroupSeparator[nf]);
+ }
+ };
+
+ util.str = {
+ replaceAll: function(str, find, replace) {
+ return str.replace(new RegExp(find, 'g'), replace);
+ }
+ };
+
+ util.color = {
+ hexToRgb: function(hex) {
+ var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
+ hex = hex.replace(shorthandRegex, function(m, r, g, b) {
+ return r + r + g + g + b + b;
+ });
+
+ var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
+ return result ? {
+ r: parseInt(result[1], 16),
+ g: parseInt(result[2], 16),
+ b: parseInt(result[3], 16)
+ } : null;
+ },
+ getContrast: function(hex) {
+ if (Ext.isString(hex)) {
+ var rgb = util.color.hexToRgb(hex),
+ factor = (rgb.r + rgb.g + rgb.b);
+
+ if (factor < 210) {
+ return '#ffffff';
+ }
+ }
+
+ return '#000000';
+ }
+ };
+
+ util.message = {
+ alert: function(message) {
+ alert(message);
+ }
+ };
+ }());
+
+ // init
+ (function() {
+ // sort and extend dynamic dimensions
+ init.dimensions = util.array.sortObjectsByString(init.dimensions);
+
+ for (var i = 0, dim; i < init.dimensions.length; i++) {
+ dim = init.dimensions[i];
+ dim.dimensionName = dim.id;
+ dim.objectName = conf.finals.dimension.dimension.objectName;
+ conf.finals.dimension.objectNameMap[dim.id] = dim;
+ }
+
+ // legend set map
+ init.idLegendSetMap = {};
+
+ for (var i = 0, set; i < init.legendSets.length; i++) {
+ set = init.legendSets[i];
+ init.idLegendSetMap[set.id] = set;
+ }
+ }());
+
+ // api
+ (function() {
+ api.layout = {};
+
+ api.layout.Record = function(config) {
+ var record = {};
+
+ // id: string
+
+ return function() {
+ if (!Ext.isObject(config)) {
+ console.log('Record config is not an object: ' + config);
+ return;
+ }
+
+ if (!Ext.isString(config.id)) {
+ alert('Record id is not text: ' + config);
+ return;
+ }
+
+ record.id = config.id.replace('.', '-');
+
+ if (Ext.isString(config.name)) {
+ record.name = config.name;
+ }
+
+ return Ext.clone(record);
+ }();
+ };
+
+ api.layout.Dimension = function(config) {
+ var dimension = {};
+
+ // dimension: string
+
+ // items: [Record]
+
+ return function() {
+ if (!Ext.isObject(config)) {
+ console.log('Dimension config is not an object: ' + config);
+ return;
+ }
+
+ if (!Ext.isString(config.dimension)) {
+ console.log('Dimension name is not text: ' + config);
+ return;
+ }
+
+ if (config.dimension !== conf.finals.dimension.category.objectName) {
+ var records = [];
+
+ if (!Ext.isArray(config.items)) {
+ console.log('Dimension items is not an array: ' + config);
+ return;
+ }
+
+ for (var i = 0; i < config.items.length; i++) {
+ record = api.layout.Record(config.items[i]);
+
+ if (record) {
+ records.push(record);
+ }
+ }
+
+ config.items = records;
+
+ if (!config.items.length) {
+ console.log('Dimension has no valid items: ' + config);
+ return;
+ }
+ }
+
+ dimension.dimension = config.dimension;
+ dimension.items = config.items;
+
+ return Ext.clone(dimension);
+ }();
+ };
+
+ api.layout.Layout = function(config) {
+ var layout = {},
+ getValidatedDimensionArray,
+ validateSpecialCases;
+
+ // columns: [Dimension]
+
+ // rows: [Dimension]
+
+ // filters: [Dimension]
+
+ // showTotals: boolean (true)
+
+ // showSubTotals: boolean (true)
+
+ // hideEmptyRows: boolean (false)
+
+ // displayDensity: string ('normal') - 'compact', 'normal', 'comfortable'
+
+ // fontSize: string ('normal') - 'small', 'normal', 'large'
+
+ // digitGroupSeparator: string ('space') - 'none', 'comma', 'space'
+
+ // legendSet: object
+
+ // userOrganisationUnit: boolean (false)
+
+ // userOrganisationUnitChildren: boolean (false)
+
+ // parentGraphMap: object
+
+ // reportingPeriod: boolean (false) //report tables only
+
+ // organisationUnit: boolean (false) //report tables only
+
+ // parentOrganisationUnit: boolean (false) //report tables only
+
+ // regression: boolean (false)
+
+ // cumulative: boolean (false)
+
+ // sortOrder: integer (0) //-1, 0, 1
+
+ // topLimit: integer (100) //5, 10, 20, 50, 100
+
+ getValidatedDimensionArray = function(dimensionArray) {
+ var dimensions = [];
+
+ if (!(dimensionArray && Ext.isArray(dimensionArray) && dimensionArray.length)) {
+ return;
+ }
+
+ for (var i = 0, dimension; i < dimensionArray.length; i++) {
+ dimension = api.layout.Dimension(dimensionArray[i]);
+
+ if (dimension) {
+ dimensions.push(dimension);
+ }
+ }
+
+ dimensionArray = dimensions;
+
+ return dimensionArray.length ? dimensionArray : null;
+ };
+
+ validateSpecialCases = function() {
+ var dimConf = conf.finals.dimension,
+ dimensions,
+ objectNameDimensionMap = {};
+
+ if (!layout) {
+ return;
+ }
+
+ dimensions = Ext.Array.clean([].concat(layout.columns, layout.rows, layout.filters));
+
+ for (var i = 0; i < dimensions.length; i++) {
+ objectNameDimensionMap[dimensions[i].dimension] = dimensions[i];
+ }
+
+ if (layout.filters && layout.filters.length) {
+ for (var i = 0; i < layout.filters.length; i++) {
+
+ // Indicators as filter
+ if (layout.filters[i].dimension === dimConf.indicator.objectName) {
+ util.message.alert(PT.i18n.indicators_cannot_be_specified_as_filter || 'Indicators cannot be specified as filter');
+ return;
+ }
+
+ // Categories as filter
+ if (layout.filters[i].dimension === dimConf.category.objectName) {
+ util.message.alert(PT.i18n.categories_cannot_be_specified_as_filter || 'Categories cannot be specified as filter');
+ return;
+ }
+
+ // Data sets as filter
+ if (layout.filters[i].dimension === dimConf.dataSet.objectName) {
+ util.message.alert(PT.i18n.data_sets_cannot_be_specified_as_filter || 'Data sets cannot be specified as filter');
+ return;
+ }
+ }
+ }
+
+ // dc and in
+ if (objectNameDimensionMap[dimConf.operand.objectName] && objectNameDimensionMap[dimConf.indicator.objectName]) {
+ util.message.alert('Indicators and detailed data elements cannot be specified together');
+ return;
+ }
+
+ // dc and de
+ if (objectNameDimensionMap[dimConf.operand.objectName] && objectNameDimensionMap[dimConf.dataElement.objectName]) {
+ util.message.alert('Detailed data elements and totals cannot be specified together');
+ return;
+ }
+
+ // dc and ds
+ if (objectNameDimensionMap[dimConf.operand.objectName] && objectNameDimensionMap[dimConf.dataSet.objectName]) {
+ util.message.alert('Data sets and detailed data elements cannot be specified together');
+ return;
+ }
+
+ // dc and co
+ if (objectNameDimensionMap[dimConf.operand.objectName] && objectNameDimensionMap[dimConf.category.objectName]) {
+ util.message.alert('Categories and detailed data elements cannot be specified together');
+ return;
+ }
+
+ // Degs and datasets in the same query
+ //if (Ext.Array.contains(dimensionNames, dimConf.data.dimensionName) && store.dataSetSelected.data.length) {
+ //for (var i = 0; i < init.degs.length; i++) {
+ //if (Ext.Array.contains(dimensionNames, init.degs[i].id)) {
+ //alert(PT.i18n.data_element_group_sets_cannot_be_specified_together_with_data_sets);
+ //return;
+ //}
+ //}
+ //}
+
+ return true;
+ };
+
+ return function() {
+ var a = [],
+ objectNames = [],
+ dimConf = conf.finals.dimension,
+ dims,
+ isOu = false,
+ isOuc = false,
+ isOugc = false;
+
+ config.columns = getValidatedDimensionArray(config.columns);
+ config.rows = getValidatedDimensionArray(config.rows);
+ config.filters = getValidatedDimensionArray(config.filters);
+
+ // Config must be an object
+ if (!(config && Ext.isObject(config))) {
+ alert(init.el + ': Layout config is not an object');
+ return;
+ }
+
+ // At least one dimension specified as column or row
+ if (!(config.columns || config.rows)) {
+ alert(PT.i18n.at_least_one_dimension_must_be_specified_as_row_or_column);
+ return;
+ }
+
+ // Get object names and user orgunits
+ for (var i = 0, dim, dims = [].concat(config.columns || [], config.rows || [], config.filters || []); i < dims.length; i++) {
+ dim = dims[i];
+
+ if (dim) {
+
+ // Object names
+ if (Ext.isString(dim.dimension)) {
+ objectNames.push(dim.dimension);
+ }
+
+ // user orgunits
+ if (dim.dimension === dimConf.organisationUnit.objectName && Ext.isArray(dim.items)) {
+ for (var j = 0; j < dim.items.length; j++) {
+ if (dim.items[j].id === 'USER_ORGUNIT') {
+ isOu = true;
+ }
+ else if (dim.items[j].id === 'USER_ORGUNIT_CHILDREN') {
+ isOuc = true;
+ }
+ else if (dim.items[j].id === 'USER_ORGUNIT_GRANDCHILDREN') {
+ isOugc = true;
+ }
+ }
+ }
+ }
+ }
+
+ // At least one period
+ if (!Ext.Array.contains(objectNames, dimConf.period.objectName)) {
+ alert(PT.i18n.at_least_one_period_must_be_specified_as_column_row_or_filter);
+ return;
+ }
+
+ // Layout
+ layout.columns = config.columns;
+ layout.rows = config.rows;
+ layout.filters = config.filters;
+
+ // Properties
+ layout.showTotals = Ext.isBoolean(config.totals) ? config.totals : (Ext.isBoolean(config.showTotals) ? config.showTotals : true);
+ layout.showSubTotals = Ext.isBoolean(config.subtotals) ? config.subtotals : (Ext.isBoolean(config.showSubTotals) ? config.showSubTotals : true);
+ layout.hideEmptyRows = Ext.isBoolean(config.hideEmptyRows) ? config.hideEmptyRows : false;
+
+ layout.showHierarchy = Ext.isBoolean(config.showHierarchy) ? config.showHierarchy : false;
+
+ layout.displayDensity = Ext.isString(config.displayDensity) && !Ext.isEmpty(config.displayDensity) ? config.displayDensity : 'normal';
+ layout.fontSize = Ext.isString(config.fontSize) && !Ext.isEmpty(config.fontSize) ? config.fontSize : 'normal';
+ layout.digitGroupSeparator = Ext.isString(config.digitGroupSeparator) && !Ext.isEmpty(config.digitGroupSeparator) ? config.digitGroupSeparator : 'space';
+ layout.legendSet = Ext.isObject(config.legendSet) && Ext.isString(config.legendSet.id) ? config.legendSet : null;
+
+ layout.userOrganisationUnit = isOu;
+ layout.userOrganisationUnitChildren = isOuc;
+ layout.userOrganisationUnitGrandChildren = isOugc;
+
+ layout.parentGraphMap = Ext.isObject(config.parentGraphMap) ? config.parentGraphMap : null;
+
+ layout.reportingPeriod = Ext.isObject(config.reportParams) && Ext.isBoolean(config.reportParams.paramReportingPeriod) ? config.reportParams.paramReportingPeriod : (Ext.isBoolean(config.reportingPeriod) ? config.reportingPeriod : false);
+ layout.organisationUnit = Ext.isObject(config.reportParams) && Ext.isBoolean(config.reportParams.paramOrganisationUnit) ? config.reportParams.paramOrganisationUnit : (Ext.isBoolean(config.organisationUnit) ? config.organisationUnit : false);
+ layout.parentOrganisationUnit = Ext.isObject(config.reportParams) && Ext.isBoolean(config.reportParams.paramParentOrganisationUnit) ? config.reportParams.paramParentOrganisationUnit : (Ext.isBoolean(config.parentOrganisationUnit) ? config.parentOrganisationUnit : false);
+
+ layout.regression = Ext.isBoolean(config.regression) ? config.regression : false;
+ layout.cumulative = Ext.isBoolean(config.cumulative) ? config.cumulative : false;
+ layout.sortOrder = Ext.isNumber(config.sortOrder) ? config.sortOrder : 0;
+ layout.topLimit = Ext.isNumber(config.topLimit) ? config.topLimit : 0;
+
+ if (!validateSpecialCases()) {
+ return;
+ }
+
+ return Ext.clone(layout);
+ }();
+ };
+
+ api.response = {};
+
+ api.response.Header = function(config) {
+ var header = {};
+
+ // name: string
+
+ // meta: boolean
+
+ return function() {
+ if (!Ext.isObject(config)) {
+ console.log('Header is not an object: ' + config);
+ return;
+ }
+
+ if (!Ext.isString(config.name)) {
+ console.log('Header name is not text: ' + config);
+ return;
+ }
+
+ if (!Ext.isBoolean(config.meta)) {
+ console.log('Header meta is not boolean: ' + config);
+ return;
+ }
+
+ header.name = config.name;
+ header.meta = config.meta;
+
+ return Ext.clone(header);
+ }();
+ };
+
+ api.response.Response = function(config) {
+ var response = {};
+
+ // headers: [Header]
+
+ return function() {
+ var headers = [];
+
+ if (!(config && Ext.isObject(config))) {
+ alert('Data response invalid');
+ return false;
+ }
+
+ if (!(config.headers && Ext.isArray(config.headers))) {
+ alert('Data response invalid');
+ return false;
+ }
+
+ for (var i = 0, header; i < config.headers.length; i++) {
+ header = api.response.Header(config.headers[i]);
+
+ if (header) {
+ headers.push(header);
+ }
+ }
+
+ config.headers = headers;
+
+ if (!config.headers.length) {
+ alert('No valid response headers');
+ return;
+ }
+
+ if (!(Ext.isArray(config.rows) && config.rows.length > 0)) {
+ alert('No values found');
+ return false;
+ }
+
+ if (config.headers.length !== config.rows[0].length) {
+ alert('Data invalid');
+ return false;
+ }
+
+ response.headers = config.headers;
+ response.metaData = config.metaData;
+ response.width = config.width;
+ response.height = config.height;
+ response.rows = config.rows;
+
+ return response;
+ }();
+ };
+ }());
+
+ // service
+ (function() {
+ service.layout = {};
+
+ service.layout.getObjectNameDimensionMap = function(dimensionArray) {
+ var map = {};
+
+ if (Ext.isArray(dimensionArray) && dimensionArray.length) {
+ for (var i = 0, dim; i < dimensionArray.length; i++) {
+ dim = api.layout.Dimension(dimensionArray[i]);
+
+ if (dim) {
+ map[dim.dimension] = dim;
+ }
+ }
+ }
+
+ return map;
+ };
+
+ service.layout.getObjectNameDimensionItemsMap = function(dimensionArray) {
+ var map = {};
+
+ if (Ext.isArray(dimensionArray) && dimensionArray.length) {
+ for (var i = 0, dim; i < dimensionArray.length; i++) {
+ dim = api.layout.Dimension(dimensionArray[i]);
+
+ if (dim) {
+ map[dim.dimension] = dim.items;
+ }
+ }
+ }
+
+ return map;
+ };
+
+ service.response = {};
+ }());
+
+ // engine
+ (function() {
+ engine.getExtendedLayout = function(layout) {
+ var layout = Ext.clone(layout),
+ xLayout = {
+ columns: [],
+ rows: [],
+ filters: [],
+
+ columnObjectNames: [],
+ columnDimensionNames: [],
+ rowObjectNames: [],
+ rowDimensionNames: [],
+
+ // Axis
+ axisDimensions: [],
+ axisObjectNames: [],
+ axisDimensionNames: [],
+
+ // For param string
+ sortedAxisDimensionNames: [],
+
+ // Filter
+ filterDimensions: [],
+ filterObjectNames: [],
+ filterDimensionNames: [],
+
+ // For param string
+ sortedFilterDimensions: [],
+
+ // All
+ dimensions: [],
+ objectNames: [],
+ dimensionNames: [],
+
+ // Object name maps
+ objectNameDimensionsMap: {},
+ objectNameItemsMap: {},
+ objectNameIdsMap: {},
+
+ // Dimension name maps
+ dimensionNameDimensionsMap: {},
+ dimensionNameItemsMap: {},
+ dimensionNameIdsMap: {},
+
+ // For param string
+ dimensionNameSortedIdsMap: {}
+ };
+
+ Ext.applyIf(xLayout, layout);
+
+ // Columns, rows, filters
+ if (layout.columns) {
+ for (var i = 0, dim, items, xDim; i < layout.columns.length; i++) {
+ dim = layout.columns[i];
+ items = dim.items;
+ xDim = {};
+
+ xDim.dimension = dim.dimension;
+ xDim.objectName = dim.dimension;
+ xDim.dimensionName = dimConf.objectNameMap[dim.dimension].dimensionName;
+
+ if (items) {
+ xDim.items = items;
+ xDim.ids = [];
+
+ for (var j = 0; j < items.length; j++) {
+ xDim.ids.push(items[j].id);
+ }
+ }
+
+ xLayout.columns.push(xDim);
+
+ xLayout.columnObjectNames.push(xDim.objectName);
+ xLayout.columnDimensionNames.push(xDim.dimensionName);
+
+ xLayout.axisDimensions.push(xDim);
+ xLayout.axisObjectNames.push(xDim.objectName);
+ xLayout.axisDimensionNames.push(dimConf.objectNameMap[xDim.objectName].dimensionName);
+
+ xLayout.objectNameDimensionsMap[xDim.objectName] = xDim;
+ xLayout.objectNameItemsMap[xDim.objectName] = xDim.items;
+ xLayout.objectNameIdsMap[xDim.objectName] = xDim.ids;
+ }
+ }
+
+ if (layout.rows) {
+ for (var i = 0, dim, items, xDim; i < layout.rows.length; i++) {
+ dim = Ext.clone(layout.rows[i]);
+ items = dim.items;
+ xDim = {};
+
+ xDim.dimension = dim.dimension;
+ xDim.objectName = dim.dimension;
+ xDim.dimensionName = dimConf.objectNameMap[dim.dimension].dimensionName;
+
+ if (items) {
+ xDim.items = items;
+ xDim.ids = [];
+
+ for (var j = 0; j < items.length; j++) {
+ xDim.ids.push(items[j].id);
+ }
+ }
+
+ xLayout.rows.push(xDim);
+
+ xLayout.rowObjectNames.push(xDim.objectName);
+ xLayout.rowDimensionNames.push(xDim.dimensionName);
+
+ xLayout.axisDimensions.push(xDim);
+ xLayout.axisObjectNames.push(xDim.objectName);
+ xLayout.axisDimensionNames.push(dimConf.objectNameMap[xDim.objectName].dimensionName);
+
+ xLayout.objectNameDimensionsMap[xDim.objectName] = xDim;
+ xLayout.objectNameItemsMap[xDim.objectName] = xDim.items;
+ xLayout.objectNameIdsMap[xDim.objectName] = xDim.ids;
+ }
+ }
+
+ if (layout.filters) {
+ for (var i = 0, dim, items, xDim; i < layout.filters.length; i++) {
+ dim = layout.filters[i];
+ items = dim.items;
+ xDim = {};
+
+ xDim.dimension = dim.dimension;
+ xDim.objectName = dim.dimension;
+ xDim.dimensionName = dimConf.objectNameMap[dim.dimension].dimensionName;
+
+ if (items) {
+ xDim.items = items;
+ xDim.ids = [];
+
+ for (var j = 0; j < items.length; j++) {
+ xDim.ids.push(items[j].id);
+ }
+ }
+
+ xLayout.filters.push(xDim);
+
+ xLayout.filterDimensions.push(xDim);
+ xLayout.filterObjectNames.push(xDim.objectName);
+ xLayout.filterDimensionNames.push(dimConf.objectNameMap[xDim.objectName].dimensionName);
+
+ xLayout.objectNameDimensionsMap[xDim.objectName] = xDim;
+ xLayout.objectNameItemsMap[xDim.objectName] = xDim.items;
+ xLayout.objectNameIdsMap[xDim.objectName] = xDim.ids;
+ }
+ }
+
+ // Unique dimension names
+ xLayout.axisDimensionNames = Ext.Array.unique(xLayout.axisDimensionNames);
+ xLayout.filterDimensionNames = Ext.Array.unique(xLayout.filterDimensionNames);
+
+ xLayout.columnDimensionNames = Ext.Array.unique(xLayout.columnDimensionNames);
+ xLayout.rowDimensionNames = Ext.Array.unique(xLayout.rowDimensionNames);
+ xLayout.filterDimensionNames = Ext.Array.unique(xLayout.filterDimensionNames);
+
+ // For param string
+ xLayout.sortedAxisDimensionNames = Ext.clone(xLayout.axisDimensionNames).sort();
+ xLayout.sortedFilterDimensions = util.array.sortDimensions(Ext.clone(xLayout.filterDimensions));
+
+ // All
+ xLayout.dimensions = [].concat(xLayout.axisDimensions, xLayout.filterDimensions);
+ xLayout.objectNames = [].concat(xLayout.axisObjectNames, xLayout.filterObjectNames);
+ xLayout.dimensionNames = [].concat(xLayout.axisDimensionNames, xLayout.filterDimensionNames);
+
+ // Dimension name maps
+ for (var i = 0, dimName; i < xLayout.dimensionNames.length; i++) {
+ dimName = xLayout.dimensionNames[i];
+
+ xLayout.dimensionNameDimensionsMap[dimName] = [];
+ xLayout.dimensionNameItemsMap[dimName] = [];
+ xLayout.dimensionNameIdsMap[dimName] = [];
+ }
+
+ for (var i = 0, xDim; i < xLayout.dimensions.length; i++) {
+ xDim = xLayout.dimensions[i];
+
+ xLayout.dimensionNameDimensionsMap[xDim.dimensionName].push(xDim);
+ xLayout.dimensionNameItemsMap[xDim.dimensionName] = xLayout.dimensionNameItemsMap[xDim.dimensionName].concat(xDim.items);
+ xLayout.dimensionNameIdsMap[xDim.dimensionName] = xLayout.dimensionNameIdsMap[xDim.dimensionName].concat(xDim.ids);
+ }
+
+ // For param string
+ for (var key in xLayout.dimensionNameIdsMap) {
+ if (xLayout.dimensionNameIdsMap.hasOwnProperty(key)) {
+ xLayout.dimensionNameSortedIdsMap[key] = Ext.clone(xLayout.dimensionNameIdsMap[key]).sort();
+ }
+ }
+
+ return xLayout;
+ };
+
+ engine.getParamString = function(xLayout, isSorted) {
+ var axisDimensionNames = isSorted ? xLayout.sortedAxisDimensionNames : xLayout.axisDimensionNames,
+ filterDimensions = isSorted ? xLayout.sortedFilterDimensions : xLayout.filterDimensions,
+ dimensionNameIdsMap = isSorted ? xLayout.dimensionNameSortedIdsMap : xLayout.dimensionNameIdsMap,
+ paramString = '?',
+ dimConf = conf.finals.dimension,
+ addCategoryDimension = false,
+ map = xLayout.dimensionNameItemsMap,
+ dx = dimConf.indicator.dimensionName,
+ co = dimConf.category.dimensionName;
+
+ for (var i = 0, dimName, items; i < axisDimensionNames.length; i++) {
+ dimName = axisDimensionNames[i];
+
+ paramString += 'dimension=' + dimName;
+
+ items = Ext.clone(dimensionNameIdsMap[dimName]);
+
+ if (dimName === dx) {
+ for (var j = 0, index; j < items.length; j++) {
+ index = items[j].indexOf('-');
+
+ if (index > 0) {
+ addCategoryDimension = true;
+ items[j] = items[j].substr(0, index);
+ }
+ }
+
+ items = Ext.Array.unique(items);
+ }
+
+ if (dimName !== co) {
+ paramString += ':' + items.join(';');
+ }
+
+ if (i < (axisDimensionNames.length - 1)) {
+ paramString += '&';
+ }
+ }
+
+ if (addCategoryDimension) {
+ paramString += '&dimension=' + conf.finals.dimension.category.dimensionName;
+ }
+
+ if (Ext.isArray(filterDimensions) && filterDimensions.length) {
+ for (var i = 0, dim; i < filterDimensions.length; i++) {
+ dim = filterDimensions[i];
+
+ paramString += '&filter=' + dim.dimensionName + ':' + dim.ids.join(';');
+ }
+ }
+
+ if (xLayout.showHierarchy) {
+ paramString += '&hierarchyMeta=true';
+ }
+
+ return paramString;
+ };
+
+ engine.setSessionStorage = function(session, obj, url) {
+ if (PT.isSessionStorage) {
+ var dhis2 = JSON.parse(sessionStorage.getItem('dhis2')) || {};
+ dhis2[session] = obj;
+ sessionStorage.setItem('dhis2', JSON.stringify(dhis2));
+
+ if (Ext.isString(url)) {
+ window.location.href = url;
+ }
+ }
+ };
+
+ engine.createTable = function(layout, pt, updateGui, isFavorite) {
+ var legendSet = layout.legendSet ? pt.init.idLegendSetMap[layout.legendSet.id] : null,
+ isHierarchy,
+ getItemName,
+ getSyncronizedXLayout,
+ getExtendedResponse,
+ getExtendedAxis,
+ validateUrl,
+ setMouseHandlers,
+ getTableHtml,
+ initialize,
+ afterLoad,
+ tableUuid = pt.init.el + '_' + Ext.data.IdGenerator.get('uuid').generate(),
+ uuidDimUuidsMap = {},
+ uuidObjectMap = {};
+
+ isHierarchy = function(id, response) {
+ return layout.showHierarchy && Ext.isObject(response.metaData.ouHierarchy) && response.metaData.ouHierarchy.hasOwnProperty(id);
+ };
+
+ getItemName = function(id, response, isHtml) {
+ var metaData = response.metaData,
+ name = '';
+
+ if (isHierarchy(id, response)) {
+ var a = Ext.clean(metaData.ouHierarchy[id].split('/'));
+ a.shift();
+
+ for (var i = 0; i < a.length; i++) {
+ name += (isHtml ? '<span class="text-weak">' : '') + metaData.names[a[i]] + (isHtml ? '</span>' : '') + ' / ';
+ }
+ }
+
+ name += metaData.names[id];
+
+ return name;
+ };
+
+ getSyncronizedXLayout = function(xLayout, response) {
+ var removeDimensionFromXLayout,
+ getHeaderNames,
+ dimensions = [].concat(xLayout.columns || [], xLayout.rows || [], xLayout.filters || []);
+
+ removeDimensionFromXLayout = function(objectName) {
+ var getUpdatedAxis;
+
+ getUpdatedAxis = function(axis) {
+ var dimension;
+ axis = Ext.clone(axis);
+
+ for (var i = 0; i < axis.length; i++) {
+ if (axis[i].dimension === objectName) {
+ dimension = axis[i];
+ }
+ }
+
+ if (dimension) {
+ Ext.Array.remove(axis, dimension);
+ }
+
+ return axis;
+ };
+
+ if (xLayout.columns) {
+ xLayout.columns = getUpdatedAxis(xLayout.columns);
+ }
+ if (xLayout.rows) {
+ xLayout.rows = getUpdatedAxis(xLayout.rows);
+ }
+ if (xLayout.filters) {
+ xLayout.filters = getUpdatedAxis(xLayout.filters);
+ }
+ };
+
+ getHeaderNames = function() {
+ var headerNames = [];
+
+ for (var i = 0; i < response.headers.length; i++) {
+ headerNames.push(response.headers[i].name);
+ }
+
+ return headerNames;
+ };
+
+ return function() {
+ var headerNames = getHeaderNames(),
+ xOuDimension = xLayout.objectNameDimensionsMap[dimConf.organisationUnit.objectName],
+ isUserOrgunit = xOuDimension && Ext.Array.contains(xOuDimension.ids, 'USER_ORGUNIT'),
+ isUserOrgunitChildren = xOuDimension && Ext.Array.contains(xOuDimension.ids, 'USER_ORGUNIT_CHILDREN'),
+ isUserOrgunitGrandChildren = xOuDimension && Ext.Array.contains(xOuDimension.ids, 'USER_ORGUNIT_GRANDCHILDREN'),
+ isLevel = function() {
+ if (xOuDimension && Ext.isArray(xOuDimension.ids)) {
+ for (var i = 0; i < xOuDimension.ids.length; i++) {
+ if (xOuDimension.ids[i].substr(0,5) === 'LEVEL') {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }(),
+ isGroup = function() {
+ if (xOuDimension && Ext.isArray(xOuDimension.ids)) {
+ for (var i = 0; i < xOuDimension.ids.length; i++) {
+ if (xOuDimension.ids[i].substr(0,8) === 'OU_GROUP') {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }(),
+ co = dimConf.category.objectName,
+ ou = dimConf.organisationUnit.objectName,
+ layout;
+
+ // Set items from init/metaData/xLayout
+ for (var i = 0, dim, metaDataDim, items; i < dimensions.length; i++) {
+ dim = dimensions[i];
+ dim.items = [];
+ metaDataDim = response.metaData[dim.objectName];
+
+ // If ou and children
+ if (dim.dimensionName === ou) {
+ if (isUserOrgunit || isUserOrgunitChildren || isUserOrgunitGrandChildren) {
+ var userOu,
+ userOuc,
+ userOugc;
+
+ if (isUserOrgunit) {
+ userOu = [{
+ id: pt.init.user.ou,
+ name: getItemName(pt.init.user.ou, response)
+ }];
+ }
+ if (isUserOrgunitChildren) {
+ userOuc = [];
+
+ for (var j = 0; j < pt.init.user.ouc.length; j++) {
+ userOuc.push({
+ id: pt.init.user.ouc[j],
+ name: getItemName(pt.init.user.ouc[j], response)
+ });
+ }
+
+ userOuc = pt.util.array.sortObjectsByString(userOuc);
+ }
+ if (isUserOrgunitGrandChildren) {
+ var userOuOuc = [].concat(pt.init.user.ou, pt.init.user.ouc),
+ responseOu = response.metaData[ou];
+
+ userOugc = [];
+
+ for (var j = 0, id; j < responseOu.length; j++) {
+ id = responseOu[j];
+
+ if (!Ext.Array.contains(userOuOuc, id)) {
+ userOugc.push({
+ id: id,
+ name: getItemName(id, response)
+ });
+ }
+ }
+
+ userOugc = pt.util.array.sortObjectsByString(userOugc);
+ }
+
+ dim.items = [].concat(userOu || [], userOuc || [], userOugc || []);
+ }
+ else if (isLevel || isGroup) {
+ for (var j = 0, responseOu = response.metaData[ou], id; j < responseOu.length; j++) {
+ id = responseOu[j];
+
+ dim.items.push({
+ id: id,
+ name: getItemName(id, response)
+ });
+ }
+
+ dim.items = pt.util.array.sortObjectsByString(dim.items);
+ }
+ else {
+ dim.items = Ext.clone(xLayout.dimensionNameItemsMap[dim.dimensionName]);
+ }
+ }
+ else {
+ // Items: get ids from metadata -> items
+ if (Ext.isArray(metaDataDim) && metaDataDim.length) {
+ var ids = Ext.clone(response.metaData[dim.dimensionName]);
+ for (var j = 0; j < ids.length; j++) {
+ dim.items.push({
+ id: ids[j],
+ name: response.metaData.names[ids[j]]
+ });
+ }
+ }
+ // Items: get items from xLayout
+ else {
+ dim.items = Ext.clone(xLayout.objectNameItemsMap[dim.objectName]);
+ }
+ }
+ }
+
+ // Remove dimensions from layout that do not exist in response
+ for (var i = 0, dimensionName; i < xLayout.axisDimensionNames.length; i++) {
+ dimensionName = xLayout.axisDimensionNames[i];
+ if (!Ext.Array.contains(headerNames, dimensionName)) {
+ removeDimensionFromXLayout(dimensionName);
+ }
+ }
+
+ // Re-layout
+ layout = pt.api.layout.Layout(xLayout);
+
+ if (layout) {
+ dimensions = [].concat(layout.columns || [], layout.rows || [], layout.filters || []);
+
+ for (var i = 0, idNameMap = response.metaData.names, dimItems; i < dimensions.length; i++) {
+ dimItems = dimensions[i].items;
+
+ if (Ext.isArray(dimItems) && dimItems.length) {
+ for (var j = 0, item; j < dimItems.length; j++) {
+ item = dimItems[j];
+
+ if (Ext.isObject(item) && Ext.isString(idNameMap[item.id]) && !Ext.isString(item.name)) {
+ item.name = idNameMap[item.id] || '';
+ }
+ }
+ }
+ }
+
+ return engine.getExtendedLayout(layout);
+ }
+
+ return null;
+ }();
+ };
+
+ getExtendedResponse = function(response, xLayout) {
+ response.nameHeaderMap = {};
+ response.idValueMap = {};
+ ids = [];
+
+ var extendHeaders = function() {
+
+ // Extend headers: index, items, size
+ for (var i = 0, header; i < response.headers.length; i++) {
+ header = response.headers[i];
+
+ // Index
+ header.index = i;
+
+ if (header.meta) {
+
+ // Items
+ header.items = Ext.clone(xLayout.dimensionNameIdsMap[header.name]) || [];
+
+ // Size
+ header.size = header.items.length;
+
+ // Collect ids, used by extendMetaData
+ ids = ids.concat(header.items);
+ }
+ }
+
+ // nameHeaderMap (headerName: header)
+ for (var i = 0, header; i < response.headers.length; i++) {
+ header = response.headers[i];
+
+ response.nameHeaderMap[header.name] = header;
+ }
+ }();
+
+ var extendMetaData = function() {
+ for (var i = 0, id, splitId ; i < ids.length; i++) {
+ id = ids[i];
+
+ if (id.indexOf('-') !== -1) {
+ splitId = id.split('-');
+ response.metaData.names[id] = response.metaData.names[splitId[0]] + ' ' + response.metaData.names[splitId[1]];
+ }
+ }
+ }();
+
+ var createValueIdMap = function() {
+ var valueHeaderIndex = response.nameHeaderMap[conf.finals.dimension.value.value].index,
+ coHeader = response.nameHeaderMap[conf.finals.dimension.category.dimensionName],
+ dx = dimConf.data.dimensionName,
+ co = dimConf.category.dimensionName,
+ axisDimensionNames = xLayout.axisDimensionNames,
+ idIndexOrder = [];
+
+ // idIndexOrder
+ for (var i = 0; i < axisDimensionNames.length; i++) {
+ idIndexOrder.push(response.nameHeaderMap[axisDimensionNames[i]].index);
+
+ // If co exists in response and is not added in layout, add co after dx
+ if (coHeader && !Ext.Array.contains(axisDimensionNames, co) && axisDimensionNames[i] === dx) {
+ idIndexOrder.push(coHeader.index);
+ }
+ }
+
+ // idValueMap
+ for (var i = 0, row, id; i < response.rows.length; i++) {
+ row = response.rows[i];
+ id = '';
+
+ for (var j = 0; j < idIndexOrder.length; j++) {
+ id += row[idIndexOrder[j]];
+ }
+
+ response.idValueMap[id] = row[valueHeaderIndex];
+ }
+ }();
+
+ return response;
+ };
+
+ getExtendedAxis = function(type, dimensionNames, xResponse) {
+ if (!dimensionNames || (Ext.isArray(dimensionNames) && !dimensionNames.length)) {
+ return;
+ }
+
+ var dimensionNames = Ext.clone(dimensionNames),
+ mDimensions = [],
+ spanType = type === 'col' ? 'colSpan' : 'rowSpan',
+ nCols = 1,
+ aNumCols = [],
+ aAccNumCols = [],
+ aSpan = [],
+ aGuiItems = [],
+ aAllItems = [],
+ aColIds = [],
+ aAllObjects = [],
+ aUniqueIds;
+
+ for (var i = 0; i < dimensionNames.length; i++) {
+ mDimensions.push({
+ dimensionName: dimensionNames[i]
+ });
+ }
+
+ aUniqueIds = function() {
+ var a = [];
+
+ for (var i = 0, dim; i < mDimensions.length; i++) {
+ dim = mDimensions[i];
+
+ a.push(xResponse.nameHeaderMap[dim.dimensionName].items);
+ }
+
+ return a;
+ }();
+ //aUniqueIds = [ [de1, de2, de3],
+ // [p1],
+ // [ou1, ou2, ou3, ou4] ]
+
+
+ for (var i = 0, dim; i < aUniqueIds.length; i++) {
+ nNumCols = aUniqueIds[i].length;
+
+ aNumCols.push(nNumCols);
+ nCols = nCols * nNumCols;
+ aAccNumCols.push(nCols);
+ }
+ //aNumCols = [3, 1, 4]
+ //nCols = (12) [3, 3, 12] (3 * 1 * 4)
+ //aAccNumCols = [3, 3, 12]
+
+ //nCols = 12
+
+ for (var i = 0; i < aUniqueIds.length; i++) {
+ if (aNumCols[i] === 1) {
+ if (i === 0) {
+ aSpan.push(nCols); //if just one item and top level, span all
+ }
+ else {
+ if (layout.hideEmptyRows && type === 'row') {
+ aSpan.push(nCols / aAccNumCols[i]);
+ }
+ else {
+ aSpan.push(aSpan[0]); //if just one item and not top level, span same as top level
+ }
+ }
+ }
+ else {
+ aSpan.push(nCols / aAccNumCols[i]);
+ }
+ }
+ //aSpan = [4, 12, 1]
+
+
+ aGuiItems.push(aUniqueIds[0]);
+
+ if (aUniqueIds.length > 1) {
+ for (var i = 1, a, n; i < aUniqueIds.length; i++) {
+ a = [];
+ n = aNumCols[i] === 1 ? aNumCols[0] : aAccNumCols[i-1];
+
+ for (var j = 0; j < n; j++) {
+ a = a.concat(aUniqueIds[i]);
+ }
+
+ aGuiItems.push(a);
+ }
+ }
+ //aGuiItems = [ [d1, d2, d3], (3)
+ // [p1, p2, p3, p4, p5, p1, p2, p3, p4, p5, p1, p2, p3, p4, p5], (15)
+ // [o1, o2, o1, o2, o1, o2, o1, o2, o1, o2, o1, o2, o1, o2, o1, o2, o1, o2...] (30)
+ // ]
+
+ for (var i = 0, aAllRow, aUniqueRow, span, factor; i < aUniqueIds.length; i++) {
+ aAllRow = [];
+ aUniqueRow = aUniqueIds[i];
+ span = aSpan[i];
+ factor = nCols / (span * aUniqueRow.length);
+
+ for (var j = 0; j < factor; j++) {
+ for (var k = 0; k < aUniqueRow.length; k++) {
+ for (var l = 0; l < span; l++) {
+ aAllRow.push(aUniqueRow[k]);
+ }
+ }
+ }
+
+ aAllItems.push(aAllRow);
+ }
+ //aAllItems = [ [d1, d1, d1, d1, d1, d1, d1, d1, d1, d1, d2, d2, d2, d2, d2, d2, d2, d2, d2, d2, d3, d3, d3, d3, d3, d3, d3, d3, d3, d3], (30)
+ // [p1, p2, p3, p4, p5, p1, p2, p3, p4, p5, p1, p2, p3, p4, p5, p1, p2, p3, p4, p5, p1, p2, p3, p4, p5, p1, p2, p3, p4, p5], (30)
+ // [o1, o2, o1, o2, o1, o2, o1, o2, o1, o2, o1, o2, o1, o2, o1, o2, o1, o2, o1, o2, o1, o2, o1, o2, o1, o2, o1, o2, o1, o2] (30)
+ // ]
+
+
+ for (var i = 0, id; i < nCols; i++) {
+ id = '';
+
+ for (var j = 0; j < aAllItems.length; j++) {
+ id += aAllItems[j][i];
+ }
+
+ aColIds.push(id);
+ }
+ //aColIds = [ abc, bcd, ... ]
+
+
+ // 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],
+ uuid: Ext.data.IdGenerator.get('uuid').generate(),
+ dim: i,
+ axis: type
+ });
+ }
+
+ aAllObjects.push(allRow);
+ }
+
+ // add span and children
+ for (var i = 0; i < aAllObjects.length; i++) {
+ for (var j = 0, obj; j < aAllObjects[i].length; j += aSpan[i]) {
+ obj = aAllObjects[i][j];
+
+ // span
+ obj[spanType] = aSpan[i];
+
+ // children
+ obj.children = Ext.isDefined(aSpan[i + 1]) ? aSpan[i] / aSpan[i + 1] : 0;
+
+ 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;
+ }
+ }
+ }
+ }
+
+ // add uuids array to leaves
+ if (aAllObjects.length) {
+ for (var i = 0, leaf, parentUuids, obj, span = aAllObjects.length > 1 ? aSpan[aAllObjects.length - 2] : 1, leafUuids = []; i < aAllObjects[aAllObjects.length - 1].length; i++) {
+ leaf = aAllObjects[aAllObjects.length - 1][i];
+ leafUuids.push(leaf.uuid);
+ parentUuids = [];
+ obj = leaf;
+
+ // get parent uuids
+ while (obj.parent) {
+ obj = obj.parent;
+ parentUuids.push(obj.uuid);
+ }
+
+ // add parent uuids
+ leaf.uuids = Ext.clone(parentUuids);
+
+ // add uuid for all leaves
+ if (leafUuids.length === span) {
+ for (var j = i - span + 1, leaf; j <= i; j++) {
+ leaf = aAllObjects[aAllObjects.length - 1][j];
+ leaf.uuids = leaf.uuids.concat(Ext.clone(leafUuids));
+ }
+
+ leafUuids = [];
+ }
+ }
+ }
+
+ // populate uuid-object map
+ for (var i = 0; i < aAllObjects.length; i++) {
+ for (var j = 0, object; j < aAllObjects[i].length; j++) {
+ object = aAllObjects[i][j];
+ //console.log(object.uuid, object);
+ uuidObjectMap[object.uuid] = object;
+ }
+ }
+
+ //console.log("aAllObjects", aAllObjects);
+
+ return {
+ type: type,
+ items: mDimensions,
+ xItems: {
+ unique: aUniqueIds,
+ gui: aGuiItems,
+ all: aAllItems
+ },
+ objects: {
+ all: aAllObjects
+ },
+ ids: aColIds,
+ span: aSpan,
+ dims: aUniqueIds.length,
+ size: nCols
+ };
+ };
+
+ validateUrl = function(url) {
+ if (!Ext.isString(url) || url.length > 2000) {
+ var percent = ((url.length - 2000) / url.length) * 100;
+ alert('Too many parameters selected. Please reduce the number of parameters by at least ' + Ext.Number.toFixed(percent, 0) + '%.');
+ return;
+ }
+
+ return true;
+ };
+
+ setMouseHandlers = function() {
+ var valueElement;
+
+ for (var key in uuidDimUuidsMap) {
+ if (uuidDimUuidsMap.hasOwnProperty(key)) {
+ valueElement = Ext.get(key);
+
+ if (parseFloat(valueElement.dom.textContent)) {
+ valueElement.dom.pt = pt;
+ valueElement.dom.setAttribute('onclick', 'this.pt.engine.onMouseClick(this.id, this.pt);');
+ }
+ }
+ }
+ };
+
+ getTableHtml = function(xColAxis, xRowAxis, xResponse) {
+ var getRoundedHtmlValue,
+ getTdHtml,
+ doSubTotals,
+ doTotals,
+ getColAxisHtmlArray,
+ getRowHtmlArray,
+ rowAxisHtmlArray,
+ getColTotalHtmlArray,
+ getGrandTotalHtmlArray,
+ getTotalHtmlArray,
+ getHtml,
+ getUniqueFactor = function(xAxis) {
+ if (!xAxis) {
+ return null;
+ }
+
+ var unique = xAxis.xItems.unique;
+
+ if (unique) {
+ if (unique.length < 2) {
+ return 1;
+ }
+ else {
+ return xAxis.size / unique[0].length;
+ }
+ }
+
+ return null;
+ },
+ colUniqueFactor = getUniqueFactor(xColAxis),
+ rowUniqueFactor = getUniqueFactor(xRowAxis),
+ valueItems = [],
+ valueObjects = [],
+ totalColObjects = [],
+ htmlArray;
+
+ getRoundedHtmlValue = function(value, dec) {
+ dec = dec || 2;
+ return parseFloat(pt.util.number.roundIf(value, 2)).toString();
+ };
+
+ getTdHtml = function(config) {
+ var bgColor,
+ legends,
+ colSpan,
+ rowSpan,
+ htmlValue,
+ displayDensity,
+ fontSize,
+ isLegendSet = Ext.isObject(legendSet) && Ext.isArray(legendSet.legends) && legendSet.legends.length,
+ isNumeric = Ext.isObject(config) && Ext.isString(config.type) && config.type.substr(0,5) === 'value' && !config.empty,
+ isValue = Ext.isObject(config) && Ext.isString(config.type) && config.type === 'value' && !config.empty,
+ cls = '',
+ html = '';
+
+ if (!Ext.isObject(config)) {
+ return '';
+ }
+
+ // Background color from legend set
+ if (isNumeric && isLegendSet) {
+ legends = legendSet.legends;
+
+ for (var i = 0, value; i < legends.length; i++) {
+ value = parseFloat(config.value);
+
+ if (Ext.Number.constrain(value, legends[i].sv, legends[i].ev) === value) {
+ bgColor = legends[i].color;
+ }
+ }
+ }
+
+ colSpan = config.colSpan ? 'colspan="' + config.colSpan + '" ' : '';
+ rowSpan = config.rowSpan ? 'rowspan="' + config.rowSpan + '" ' : '';
+ htmlValue = config.collapsed ? '' : config.htmlValue || config.value || '';
+ htmlValue = config.type !== 'dimension' ? pt.util.number.pp(htmlValue, layout.digitGroupSeparator) : htmlValue;
+ displayDensity = conf.pivot.displayDensity[config.displayDensity] || conf.pivot.displayDensity[layout.displayDensity];
+ fontSize = conf.pivot.fontSize[config.fontSize] || conf.pivot.fontSize[layout.fontSize];
+
+ cls += config.hidden ? ' td-hidden' : '';
+ cls += config.collapsed ? ' td-collapsed' : '';
+ cls += isValue ? ' pointer' : '';
+ cls += bgColor ? ' legend' : (config.cls ? ' ' + config.cls : '');
+
+ html += '<td ' + (config.uuid ? ('id="' + config.uuid + '" ') : '') + ' class="' + cls + '" ' + colSpan + rowSpan;
+
+ if (bgColor) {
+ html += '>';
+ html += '<div class="legendCt">';
+ html += '<div class="number ' + config.cls + '" style="padding:' + displayDensity + '; padding-right:3px; font-size:' + fontSize + '">' + htmlValue + '</div>';
+ html += '<div class="arrowCt ' + config.cls + '">';
+ html += '<div class="arrow" style="border-bottom:8px solid transparent; border-right:8px solid ' + bgColor + '"> </div>';
+ html += '</div></div></div></td>';
+
+ //cls = 'legend';
+ //cls += config.hidden ? ' td-hidden' : '';
+ //cls += config.collapsed ? ' td-collapsed' : '';
+
+ //html += '<td class="' + cls + '" ';
+ //html += colSpan + rowSpan + '>';
+ //html += '<div class="legendCt">';
+ //html += '<div style="display:table-cell; padding:' + displayDensity + '; font-size:' + fontSize + '"';
+ //html += config.cls ? ' class="' + config.cls + '">' : '';
+ //html += htmlValue + '</div>';
+ //html += '<div class="legendColor" style="background-color:' + bgColor + '"> </div>';
+ //html += '</div></td>';
+ }
+ else {
+ html += 'style="padding:' + displayDensity + '; font-size:' + fontSize + ';"' + '>' + htmlValue + '</td>';
+ }
+
+ return html;
+ };
+
+ doSubTotals = function(xAxis) {
+ return !!layout.showSubTotals && xAxis && xAxis.dims > 1;
+
+ //var multiItemDimension = 0,
+ //unique;
+
+ //if (!(layout.showSubTotals && xAxis && xAxis.dims > 1)) {
+ //return false;
+ //}
+
+ //unique = xAxis.xItems.unique;
+
+ //for (var i = 0; i < unique.length; i++) {
+ //if (unique[i].length > 1) {
+ //multiItemDimension++;
+ //}
+ //}
+
+ //return (multiItemDimension > 1);
+ };
+
+ doTotals = function() {
+ return !!layout.showTotals;
+ };
+
+ getColAxisHtmlArray = function() {
+ var a = [],
+ getEmptyHtmlArray;
+
+ getEmptyHtmlArray = function() {
+ return (xColAxis && xRowAxis) ? getTdHtml({
+ cls: 'pivot-dim-empty',
+ colSpan: xRowAxis.dims,
+ rowSpan: xColAxis.dims
+ }) : '';
+ };
+
+ if (!(xColAxis && Ext.isObject(xColAxis))) {
+ return a;
+ }
+
+ for (var i = 0, dimHtml; i < xColAxis.dims; i++) {
+ dimHtml = [];
+
+ if (i === 0) {
+ dimHtml.push(getEmptyHtmlArray());
+ }
+
+ for (var j = 0, obj, spanCount = 0; j < xColAxis.size; j++) {
+ spanCount++;
+
+ obj = xColAxis.objects.all[i][j];
+ obj.type = 'dimension';
+ obj.cls = 'pivot-dim';
+ obj.noBreak = false;
+ obj.hidden = !(obj.rowSpan || obj.colSpan);
+ obj.htmlValue = getItemName(obj.id, xResponse, true);
+
+ dimHtml.push(getTdHtml(obj));
+
+ if (i === 0 && spanCount === xColAxis.span[i] && doSubTotals(xColAxis) ) {
+ dimHtml.push(getTdHtml({
+ type: 'dimensionSubtotal',
+ cls: 'pivot-dim-subtotal',
+ rowSpan: xColAxis.dims
+ }));
+
+ spanCount = 0;
+ }
+
+ if (i === 0 && (j === xColAxis.size - 1) && doTotals()) {
+ dimHtml.push(getTdHtml({
+ type: 'dimensionTotal',
+ cls: 'pivot-dim-total',
+ rowSpan: xColAxis.dims,
+ htmlValue: 'Total'
+ }));
+ }
+ }
+
+ a.push(dimHtml);
+ }
+
+ return a;
+ };
+
+ getRowHtmlArray = function() {
+ var a = [],
+ axisObjects = [],
+ xValueObjects,
+ totalValueObjects = [],
+ mergedObjects = [],
+ valueItemsCopy,
+ colSize = xColAxis ? xColAxis.size : 1,
+ rowSize = xRowAxis ? xRowAxis.size : 1,
+ recursiveReduce;
+
+ recursiveReduce = function(obj) {
+ if (!obj.children) {
+ obj.collapsed = true;
+
+ if (obj.parent) {
+ obj.parent.children = obj.parent.children - 1;
+ }
+ }
+
+ if (obj.parent) {
+ recursiveReduce(obj.parent);
+ }
+ };
+
+ // Populate dim objects
+ if (xRowAxis) {
+ for (var i = 0, row; i < xRowAxis.size; i++) {
+ row = [];
+
+ for (var j = 0, obj, newObj; j < xRowAxis.dims; j++) {
+ obj = xRowAxis.objects.all[j][i];
+ obj.type = 'dimension';
+ obj.cls = 'pivot-dim td-nobreak' + (isHierarchy(obj.id, xResponse) ? ' align-left' : '');
+ obj.noBreak = true;
+ obj.hidden = !(obj.rowSpan || obj.colSpan);
+ obj.htmlValue = getItemName(obj.id, xResponse, true);
+
+ row.push(obj);
+ }
+
+ axisObjects.push(row);
+ }
+ }
+
+ // Value objects
+ for (var i = 0, valueItemsRow, valueObjectsRow, idValueMap = Ext.clone(xResponse.idValueMap); i < rowSize; i++) {
+ valueItemsRow = [];
+ valueObjectsRow = [];
+
+ for (var j = 0, id, value, htmlValue, empty, uuid, uuids; j < colSize; j++) {
+ empty = false;
+ uuids = [];
+
+ // meta data uid
+ id = (xColAxis ? pt.util.str.replaceAll(xColAxis.ids[j], '-', '') : '') + (xRowAxis ? pt.util.str.replaceAll(xRowAxis.ids[i], '-', '') : '');
+
+ // value html element id
+ uuid = Ext.data.IdGenerator.get('uuid').generate();
+
+ // col and row dim element ids
+ if (xColAxis) {
+ uuids = uuids.concat(xColAxis.objects.all[xColAxis.dims - 1][j].uuids);
+ }
+ if (xRowAxis) {
+ uuids = uuids.concat(xRowAxis.objects.all[xRowAxis.dims - 1][i].uuids);
+ }
+
+ if (idValueMap[id]) {
+ value = parseFloat(idValueMap[id]);
+ htmlValue = value.toString();
+ }
+ else {
+ value = 0;
+ htmlValue = '';
+ empty = true;
+ }
+
+ valueItemsRow.push(value);
+ valueObjectsRow.push({
+ uuid: uuid,
+ type: 'value',
+ cls: 'pivot-value',
+ value: value,
+ htmlValue: htmlValue,
+ empty: empty,
+ uuids: uuids
+ });
+
+ // Map element id to dim element ids
+ uuidDimUuidsMap[uuid] = uuids;
+ }
+
+ valueItems.push(valueItemsRow);
+ valueObjects.push(valueObjectsRow);
+ }
+
+ // Value total objects
+ if (xColAxis && doTotals()) {
+ for (var i = 0, empty = [], total = 0; i < valueObjects.length; i++) {
+ for (j = 0, obj; j < valueObjects[i].length; j++) {
+ obj = valueObjects[i][j];
+
+ empty.push(obj.empty);
+ total += obj.value;
+ }
+
+ totalValueObjects.push({
+ type: 'valueTotal',
+ cls: 'pivot-value-total',
+ value: total,
+ htmlValue: Ext.Array.contains(empty, false) ? getRoundedHtmlValue(total) : '',
+ empty: !Ext.Array.contains(empty, false)
+ });
+
+ empty = [];
+ total = 0;
+ }
+ }
+
+ // Hide empty rows (dims/values/totals)
+ if (xColAxis && xRowAxis) {
+ if (layout.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
+ if (doTotals()) {
+ totalValueObjects[i].collapsed = true;
+ }
+
+ // Hide/reduce parent dim span
+ parent = axisObjects[i][xRowAxis.dims-1];
+ recursiveReduce(parent);
+ }
+ }
+ }
+ }
+
+ xValueObjects = Ext.clone(valueObjects);
+
+ // Col subtotals
+ if (doSubTotals(xColAxis)) {
+ var tmpValueObjects = [];
+
+ for (var i = 0, row, rowSubTotal, colCount; i < xValueObjects.length; i++) {
+ row = [];
+ rowSubTotal = 0;
+ colCount = 0;
+
+ for (var j = 0, item, collapsed = [], empty = []; j < xValueObjects[i].length; j++) {
+ item = xValueObjects[i][j];
+ rowSubTotal += item.value;
+ empty.push(!!item.empty);
+ collapsed.push(!!item.collapsed);
+ colCount++;
+
+ row.push(item);
+
+ if (colCount === colUniqueFactor) {
+ row.push({
+ type: 'valueSubtotal',
+ cls: 'pivot-value-subtotal',
+ value: rowSubTotal,
+ htmlValue: Ext.Array.contains(empty, false) ? getRoundedHtmlValue(rowSubTotal) : '',
+ empty: !Ext.Array.contains(empty, false),
+ collapsed: !Ext.Array.contains(collapsed, false)
+ });
+
+ colCount = 0;
+ rowSubTotal = 0;
+ empty = [];
+ collapsed = [];
+ }
+ }
+
+ tmpValueObjects.push(row);
+ }
+
+ xValueObjects = tmpValueObjects;
+ }
+
+ // Row subtotals
+ if (doSubTotals(xRowAxis)) {
+ var tmpAxisObjects = [],
+ tmpValueObjects = [],
+ tmpTotalValueObjects = [],
+ getAxisSubTotalRow;
+
+ 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, true);
+
+ if (i === 0) {
+ obj.htmlValue = '';
+ obj.colSpan = xRowAxis.dims;
+ }
+ else {
+ obj.hidden = true;
+ }
+
+ row.push(obj);
+ }
+
+ return row;
+ };
+
+ // tmpAxisObjects
+ for (var i = 0, row, collapsed = []; i < axisObjects.length; i++) {
+ tmpAxisObjects.push(axisObjects[i]);
+ collapsed.push(!!axisObjects[i][0].collapsed);
+
+ // Insert subtotal after last objects
+ if (!Ext.isArray(axisObjects[i+1]) || !!axisObjects[i+1][0].root) {
+ tmpAxisObjects.push(getAxisSubTotalRow(collapsed));
+
+ collapsed = [];
+ }
+ }
+
+ // tmpValueObjects
+ for (var i = 0; i < tmpAxisObjects.length; i++) {
+ tmpValueObjects.push([]);
+ }
+
+ for (var i = 0; i < xValueObjects[0].length; i++) {
+ for (var j = 0, rowCount = 0, tmpCount = 0, subTotal = 0, empty = [], collapsed, item; j < xValueObjects.length; j++) {
+ item = xValueObjects[j][i];
+ tmpValueObjects[tmpCount++].push(item);
+ subTotal += item.value;
+ empty.push(!!item.empty);
+ rowCount++;
+
+ if (axisObjects[j][0].root) {
+ collapsed = !!axisObjects[j][0].collapsed;
+ }
+
+ if (!Ext.isArray(axisObjects[j+1]) || axisObjects[j+1][0].root) {
+ tmpValueObjects[tmpCount++].push({
+ type: item.type === 'value' ? 'valueSubtotal' : 'valueSubtotalTotal',
+ value: subTotal,
+ htmlValue: Ext.Array.contains(empty, false) ? getRoundedHtmlValue(subTotal) : '',
+ collapsed: collapsed,
+ cls: item.type === 'value' ? 'pivot-value-subtotal' : 'pivot-value-subtotal-total'
+ });
+ rowCount = 0;
+ subTotal = 0;
+ empty = [];
+ }
+ }
+ }
+
+ // tmpTotalValueObjects
+ for (var i = 0, obj, collapsed = [], empty = [], subTotal = 0, count = 0; i < totalValueObjects.length; i++) {
+ obj = totalValueObjects[i];
+ tmpTotalValueObjects.push(obj);
+
+ collapsed.push(!!obj.collapsed);
+ empty.push(!!obj.empty);
+ subTotal += obj.value;
+ count++;
+
+ if (count === xRowAxis.span[0]) {
+ tmpTotalValueObjects.push({
+ type: 'valueTotalSubgrandtotal',
+ cls: 'pivot-value-total-subgrandtotal',
+ value: subTotal,
+ htmlValue: Ext.Array.contains(empty, false) ? getRoundedHtmlValue(subTotal) : '',
+ empty: !Ext.Array.contains(empty, false),
+ collapsed: !Ext.Array.contains(collapsed, false)
+ });
+
+ collapsed = [];
+ empty = [];
+ subTotal = 0;
+ count = 0;
+ }
+ }
+
+ axisObjects = tmpAxisObjects;
+ xValueObjects = tmpValueObjects;
+ totalValueObjects = tmpTotalValueObjects;
+ }
+
+ // Merge dim, value, total
+ for (var i = 0, row; i < xValueObjects.length; i++) {
+ row = [];
+
+ if (xRowAxis) {
+ row = row.concat(axisObjects[i]);
+ }
+
+ row = row.concat(xValueObjects[i]);
+
+ if (xColAxis) {
+ row = row.concat(totalValueObjects[i]);
+ }
+
+ mergedObjects.push(row);
+ }
+
+ // Create html items
+ for (var i = 0, row; i < mergedObjects.length; i++) {
+ row = [];
+
+ for (var j = 0; j < mergedObjects[i].length; j++) {
+ row.push(getTdHtml(mergedObjects[i][j]));
+ }
+
+ a.push(row);
+ }
+
+ return a;
+ };
+
+ getColTotalHtmlArray = function() {
+ var a = [];
+
+ if (xRowAxis && doTotals()) {
+ var xTotalColObjects;
+
+ // Total col items
+ for (var i = 0, total = 0, empty = []; i < valueObjects[0].length; i++) {
+ for (var j = 0, obj; j < valueObjects.length; j++) {
+ obj = valueObjects[j][i];
+
+ total += obj.value;
+ empty.push(!!obj.empty);
+ }
+
+ totalColObjects.push({
+ type: 'valueTotal',
+ value: total,
+ htmlValue: Ext.Array.contains(empty, false) ? getRoundedHtmlValue(total) : '',
+ empty: !Ext.Array.contains(empty, false),
+ cls: 'pivot-value-total'
+ });
+
+ total = 0;
+ empty = [];
+ }
+
+ xTotalColObjects = Ext.clone(totalColObjects);
+
+ if (xColAxis && doSubTotals(xColAxis)) {
+ var tmp = [];
+
+ for (var i = 0, item, subTotal = 0, empty = [], colCount = 0; i < xTotalColObjects.length; i++) {
+ item = xTotalColObjects[i];
+ tmp.push(item);
+ subTotal += item.value;
+ empty.push(!!item.empty);
+ colCount++;
+
+ if (colCount === colUniqueFactor) {
+ tmp.push({
+ type: 'valueTotalSubgrandtotal',
+ value: subTotal,
+ htmlValue: Ext.Array.contains(empty, false) ? getRoundedHtmlValue(subTotal) : '',
+ empty: !Ext.Array.contains(empty, false),
+ cls: 'pivot-value-total-subgrandtotal'
+ });
+
+ subTotal = 0;
+ colCount = 0;
+ }
+ }
+
+ xTotalColObjects = tmp;
+ }
+
+ // Total col html items
+ for (var i = 0; i < xTotalColObjects.length; i++) {
+ a.push(getTdHtml(xTotalColObjects[i]));
+ }
+ }
+
+ return a;
+ };
+
+ getGrandTotalHtmlArray = function() {
+ var total = 0,
+ empty = [],
+ a = [];
+
+ if (doTotals()) {
+ for (var i = 0, obj; i < totalColObjects.length; i++) {
+ obj = totalColObjects[i];
+
+ total += obj.value;
+ empty.push(obj.empty);
+ }
+
+ if (xColAxis && xRowAxis) {
+ a.push(getTdHtml({
+ type: 'valueGrandTotal',
+ cls: 'pivot-value-grandtotal',
+ htmlValue: Ext.Array.contains(empty, false) ? getRoundedHtmlValue(total) : '',
+ empty: !Ext.Array.contains(empty, false)
+ }));
+ }
+ }
+
+ return a;
+ };
+
+ getTotalHtmlArray = function() {
+ var dimTotalArray,
+ colTotal = getColTotalHtmlArray(),
+ grandTotal = getGrandTotalHtmlArray(),
+ row,
+ a = [];
+
+ if (doTotals()) {
+ if (xRowAxis) {
+ dimTotalArray = [getTdHtml({
+ type: 'dimensionSubtotal',
+ cls: 'pivot-dim-total',
+ colSpan: xRowAxis.dims,
+ htmlValue: 'Total'
+ })];
+ }
+
+ row = [].concat(dimTotalArray || [], Ext.clone(colTotal) || [], Ext.clone(grandTotal) || []);
+
+ a.push(row);
+ }
+
+ return a;
+ };
+
+ getHtml = function() {
+ var s = '<table id="' + tableUuid + '" class="pivot">';
+
+ for (var i = 0; i < htmlArray.length; i++) {
+ s += '<tr>' + htmlArray[i].join('') + '</tr>';
+ }
+
+ return s += '</table>';
+ };
+
+ htmlArray = [].concat(getColAxisHtmlArray(), getRowHtmlArray(), getTotalHtmlArray());
+ htmlArray = Ext.Array.clean(htmlArray);
+
+ return getHtml(htmlArray);
+ };
+
+ afterLoad = function(layout, xLayout, xResponse) {
+
+ if (pt.isPlugin) {
+
+ // Resize render elements
+ var baseEl = Ext.get(pt.init.el),
+ baseElBorderW = parseInt(baseEl.getStyle('border-left-width')) + parseInt(baseEl.getStyle('border-right-width')),
+ baseElBorderH = parseInt(baseEl.getStyle('border-top-width')) + parseInt(baseEl.getStyle('border-bottom-width')),
+ baseElPaddingW = parseInt(baseEl.getStyle('padding-left')) + parseInt(baseEl.getStyle('padding-right')),
+ baseElPaddingH = parseInt(baseEl.getStyle('padding-top')) + parseInt(baseEl.getStyle('padding-bottom')),
+ el = Ext.get(tableUuid);
+
+ pt.viewport.centerRegion.setWidth(el.getWidth());
+ pt.viewport.centerRegion.setHeight(el.getHeight());
+ baseEl.setWidth(el.getWidth() + baseElBorderW + baseElPaddingW);
+ baseEl.setHeight(el.getHeight() + baseElBorderH + baseElPaddingH);
+ }
+ else {
+ if (PT.isSessionStorage) {
+ setMouseHandlers();
+ engine.setSessionStorage('table', layout);
+ }
+
+ if (updateGui) {
+ pt.viewport.setGui(layout, xLayout, updateGui, isFavorite);
+ }
+ }
+
+ // Hide mask
+ util.mask.hideMask(pt.viewport.centerRegion);
+
+ // Add uuid maps to instance
+ pt.uuidDimUuidsMap = uuidDimUuidsMap;
+ pt.uuidObjectMap = uuidObjectMap;
+
+ // Add objects to instance
+ pt.layout = layout;
+ pt.xLayout = xLayout;
+ pt.xResponse = xResponse;
+
+ if (PT.isDebug) {
+ console.log("xResponse", xResponse);
+ console.log("xLayout", xLayout);
+ }
+ };
+
+ initialize = function() {
+ var url,
+ xLayout,
+ xResponse,
+ xColAxis,
+ xRowAxis;
+
+ // Extended layout
+ xLayout = engine.getExtendedLayout(layout);
+
+ // Param string
+ pt.paramString = engine.getParamString(xLayout, true);
+ url = pt.init.contextPath + '/api/analytics.json' + pt.paramString;
+
+ // Validate request size
+ if (!validateUrl(url)) {
+ return;
+ }
+
+ // Show load mask
+ pt.util.mask.showMask(pt.viewport.centerRegion);
+
+ Ext.Ajax.request({
+ method: 'GET',
+ url: url,
+ callbackName: 'analytics',
+ timeout: 60000,
+ headers: {
+ 'Content-Type': 'application/json',
+ 'Accept': 'application/json'
+ },
+ disableCaching: false,
+ failure: function(r) {
+ pt.util.mask.hideMask(pt.viewport.centerRegion);
+ alert(r.responseText);
+ },
+ success: function(r) {
+ var html,
+ response = pt.api.response.Response(Ext.decode(r.responseText));
+
+ if (!response) {
+ pt.util.mask.hideMask(pt.viewport.centerRegion);
+ return;
+ }
+
+ // Synchronize xLayout
+ xLayout = getSyncronizedXLayout(xLayout, response);
+
+ if (!xLayout) {
+ pt.util.mask.hideMask(pt.viewport.centerRegion);
+ return;
+ }
+
+ // Extended response
+ xResponse = getExtendedResponse(response, xLayout);
+
+ // Extended axes
+ xColAxis = getExtendedAxis('col', xLayout.columnDimensionNames, xResponse);
+ xRowAxis = getExtendedAxis('row', xLayout.rowDimensionNames, xResponse);
+
+ // Create html
+ html = getTableHtml(xColAxis, xRowAxis, xResponse);
+
+ // Update viewport
+ pt.viewport.centerRegion.removeAll(true);
+ pt.viewport.centerRegion.update(html);
+
+ afterLoad(layout, xLayout, xResponse);
+ }
+ });
+
+ }();
+ };
+
+ engine.loadTable = function(id, pt, updateGui, isFavorite) {
+ var url = init.contextPath + '/api/reportTables/' + id,
+ params = '?viewClass=dimensional&links=false',
+ method = 'GET',
+ success,
+ failure;
+
+ if (!Ext.isString(id)) {
+ alert('Invalid uid');
+ return;
+ }
+
+ success = function(layoutConfig) {
+ var layout = api.layout.Layout(layoutConfig);
+
+ if (layout) {
+ pt.favorite = Ext.clone(layout);
+ pt.favorite.id = layoutConfig.id;
+ pt.favorite.name = layoutConfig.name;
+
+ engine.createTable(layout, pt, updateGui, isFavorite);
+ }
+ };
+
+ failure = function(responseText) {
+ util.mask.hideMask(pt.viewport.centerRegion);
+ alert(responseText);
+ };
+
+ if (pt.isPlugin) {
+ Ext.data.JsonP.request({
+ url: url + '.jsonp' + params,
+ method: method,
+ failure: function(r) {
+ failure(r);
+ },
+ success: function(r) {
+ success(r);
+ }
+ });
+ }
+ else {
+ Ext.Ajax.request({
+ url: url + '.json' + params,
+ method: method,
+ failure: function(r) {
+ failure(r.responseText);
+ },
+ success: function(r) {
+ success(Ext.decode(r.responseText));
+ }
+ });
+ }
+ };
+
+ engine.onMouseHover = function(uuid, event, param, pt) {
+ var dimUuids;
+
+ if (param === 'chart') {
+ if (Ext.isString(uuid) && Ext.isArray(pt.uuidDimUuidsMap[uuid])) {
+ dimUuids = pt.uuidDimUuidsMap[uuid];
+
+ for (var i = 0, el; i < dimUuids.length; i++) {
+ el = Ext.get(dimUuids[i]);
+
+ if (el) {
+ if (event === 'mouseover') {
+ el.addCls('highlighted');
+ }
+ else if (event === 'mouseout') {
+ el.removeCls('highlighted');
+ }
+ }
+ }
+ }
+ }
+ };
+
+ engine.onMouseClick = function(uuid, pt) {
+ var that = this,
+ uuids = pt.uuidDimUuidsMap[uuid],
+ layoutConfig = Ext.clone(pt.layout),
+ objects = [],
+ menu;
+
+ // modify layout dimension items based on uuid objects
+
+ // get objects
+ for (var i = 0; i < uuids.length; i++) {
+ objects.push(pt.uuidObjectMap[uuids[i]]);
+ }
+
+ // clear layoutConfig dimension items
+ for (var i = 0, a = [].concat(layoutConfig.columns, layoutConfig.rows); i < a.length; i++) {
+ a[i].items = [];
+ }
+
+ // add new items
+ for (var i = 0, obj, axis; i < objects.length; i++) {
+ obj = objects[i];
+ axis = obj.axis === 'col' ? layoutConfig.columns || [] : layoutConfig.rows || [];
+
+ if (axis.length) {
+ axis[obj.dim].items.push({
+ id: obj.id,
+ name: pt.xResponse.metaData.names[obj.id]
+ });
+ }
+ }
+
+ // menu
+
+ menu = Ext.create('Ext.menu.Menu', {
+ shadow: true,
+ showSeparator: false,
+ items: [
+ {
+ text: 'Open selection as chart' + ' ', //i18n
+ iconCls: 'pt-button-icon-chart',
+ param: 'chart',
+ handler: function() {
+ that.setSessionStorage('analytical', layoutConfig, pt.init.contextPath + '/dhis-web-visualizer/app/index.html?s=analytical');
+ },
+ listeners: {
+ render: function() {
+ this.getEl().on('mouseover', function() {
+ that.onMouseHover(uuid, 'mouseover', 'chart', pt);
+ });
+
+ this.getEl().on('mouseout', function() {
+ that.onMouseHover(uuid, 'mouseout', 'chart', pt);
+ });
+ }
+ }
+ },
+ {
+ text: 'Open selection as map' + ' ', //i18n
+ iconCls: 'pt-button-icon-map',
+ param: 'map',
+ disabled: true,
+ handler: function() {
+ that.setSessionStorage('analytical', layoutConfig, pt.init.contextPath + '/dhis-web-mapping/app/index.html?s=analytical');
+ },
+ listeners: {
+ render: function() {
+ this.getEl().on('mouseover', function() {
+ that.onMouseHover(uuid, 'mouseover', 'map', pt);
+ });
+
+ this.getEl().on('mouseout', function() {
+ that.onMouseHover(uuid, 'mouseout', 'map', pt);
+ });
+ }
+ }
+ }
+ ]
+ });
+
+ menu.showAt(function() {
+ var el = Ext.get(uuid),
+ xy = el.getXY();
+
+ xy[0] += el.getWidth() - 5;
+ xy[1] += el.getHeight() - 5;
+
+ return xy;
+ }());
+ };
+ }());
+
+ // instance
+ PT.core.instances.push({
+ conf: conf,
+ util: util,
+ init: init,
+ api: api,
+ service: service,
+ engine: engine
+ });
+
+ return PT.core.instances[PT.core.instances.length - 1];
+ };
+
+ // PLUGIN
+
+ // css
+ css = 'table.pivot { \n font-family: arial,sans-serif,ubuntu,consolas; \n } \n';
+ css += '.td-nobreak { \n white-space: nowrap; \n } \n';
+ css += '.td-hidden { \n display: none; \n } \n';
+ css += '.td-collapsed { \n display: none; \n } \n';
+ css += 'table.pivot { \n border-collapse: collapse; \n border-spacing: 0px; \n border: 0 none; \n } \n';
+ css += '.pivot td { \n padding: 5px; \n border: \n 1px solid #b2b2b2; \n } \n';
+ css += '.pivot-dim { \n background-color: #dae6f8; \n text-align: center; \n } \n';
+ css += '.pivot-dim.highlighted { \n background-color: #c5d8f6; \n } \n';
+ css += '.pivot-dim-subtotal { \n background-color: #cad6e8; \n text-align: center; \n } \n';
+ css += '.pivot-dim-total { \n background-color: #bac6d8; \n text-align: center; \n } \n';
+ css += '.pivot-dim-empty { \n background-color: #dae6f8; \n text-align: center; \n } \n';
+ css += '.pivot-value { \n background-color: #fff; \n white-space: nowrap; \n text-align: right; \n } \n';
+ css += '.pivot-value-subtotal { \n background-color: #f4f4f4; \n white-space: nowrap; \n text-align: right; \n } \n';
+ css += '.pivot-value-subtotal-total { \n background-color: #e7e7e7; \n white-space: nowrap; \n text-align: right; \n } \n';
+ css += '.pivot-value-total { \n background-color: #e4e4e4; \n white-space: nowrap; \n text-align: right; \n } \n';
+ css += '.pivot-value-total-subgrandtotal { \n background-color: #d8d8d8; \n white-space: nowrap; \n text-align: right; \n } \n';
+ css += '.pivot-value-grandtotal { \n background-color: #c8c8c8; \n white-space: nowrap; \n text-align: right; \n } \n';
+
+ css += '.x-mask-msg { \n padding: 0; \n border: 0 none; \n background-image: none; \n background-color: transparent; \n } \n';
+ css += '.x-mask-msg div { \n background-position: 11px center; \n } \n';
+ css += '.x-mask-msg .x-mask-loading { \n border: 0 none; \n background-color: #000; \n color: #fff; \n border-radius: 2px; \n padding: 12px 14px 12px 30px; \n opacity: 0.65; \n } \n';
+
+ css += '.pivot td.legend { \n padding: 0; \n } \n';
+ css += '.pivot div.legendCt { \n display: table; \n float: right; \n width: 100%; \n } \n';
+ css += '.pivot div.arrowCt { \n display: table-cell; \n vertical-align: top; \n width: 8px; \n } \n';
+ css += '.pivot div.arrow { \n width: 0; \n height: 0; \n } \n';
+ css += '.pivot div.number { \n display: table-cell; \n } \n',
+ css += '.pivot div.legendColor { \n display: table-cell; \n width: 2px; \n } \n';
+
+ Ext.util.CSS.createStyleSheet(css);
+
+ // plugin
+ PT.plugin = {};
+
+ PT.plugin.getTable = function(config) {
+ var validateConfig,
+ extendInstance,
+ createViewport,
+ initialize,
+ pt;
+
+ validateConfig = function(config) {
+ if (!Ext.isObject(config)) {
+ console.log('Report table configuration is not an object');
+ return;
+ }
+
+ if (!Ext.isString(config.el)) {
+ console.log('No valid element id provided');
+ return;
+ }
+
+ if (!Ext.isString(config.url)) {
+ console.log('No valid url provided');
+ return;
+ }
+
+ return true;
+ };
+
+ extendInstance = function(pt) {
+ var util = pt.util || {},
+ init = pt.init || {};
+
+ init.el = config.el;
+
+ util.message = {
+ alert: function() {
+ console.log(pt.init.el + ': ' + message);
+ }
+ };
+ };
+
+ createViewport = function() {
+ var setFavorite,
+ centerRegion;
+
+ setFavorite = function(layout) {
+ pt.engine.createTable(layout, pt);
+ };
+
+ centerRegion = Ext.create('Ext.panel.Panel', {
+ renderTo: Ext.get(pt.init.el),
+ bodyStyle: 'border: 0 none',
+ layout: 'fit'
+ });
+
+ return {
+ setFavorite: setFavorite,
+ centerRegion: centerRegion
+ };
+ };
+
+ initialize = function() {
+
+ if (!validateConfig(config)) {
+ return;
+ }
+
+ Ext.data.JsonP.request({
+ url: config.url + '/dhis-web-pivot/initialize.action',
+ success: function(r) {
+ PT.i18n = r.i18n;
+
+ pt = PT.core.getInstance(r);
+ extendInstance(pt);
+
+ pt.viewport = createViewport();
+ pt.isPlugin = true;
+
+ if (config.uid) {
+ pt.engine.loadTable(config.uid, pt);
+ }
+ else {
+ layout = pt.api.layout.Layout(config);
+
+ if (!layout) {
+ return;
+ }
+
+ pt.engine.createTable(layout, pt);
+ }
+ }
+ });
+ }();
+ };
+});