=== 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-05-22 16:41:30 +0000 +++ dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/app/scripts/app.js 2013-05-23 13:06:37 +0000 @@ -99,8 +99,7 @@ dimConf = pt.conf.finals.dimension, dx = dimConf.data.dimensionName, co = dimConf.category.dimensionName, - nameDimArrayMap = {}, - getDimension; + nameDimArrayMap = {}; config.columns = []; config.rows = []; @@ -141,8 +140,6 @@ } } else if (nameDimArrayMap.hasOwnProperty(dimName) && nameDimArrayMap[dimName]) { - //axes[i].push(Ext.clone(nameDimArrayMap[dimName])); - for (var k = 0; k < nameDimArrayMap[dimName].length; k++) { axes[i].push(Ext.clone(nameDimArrayMap[dimName][k])); } @@ -3712,6 +3709,7 @@ xLayout, dimMap, recMap, + graphMap, objectName, periodRecords, fixedPeriodRecords = [], @@ -3848,7 +3846,7 @@ userOrganisationUnitChildren.setValue(isOuc); // If fav has organisation units, wait for tree callback before update - if (recMap[dimConf.organisationUnit.objectName] && graphMap) { + if (recMap[dimConf.organisationUnit.objectName] && Ext.isObject(graphMap)) { treePanel.numberOfRecords = pt.util.object.getLength(graphMap); for (var key in graphMap) { if (graphMap.hasOwnProperty(key)) { === 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-05-22 16:41:30 +0000 +++ dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/app/scripts/core.js 2013-05-23 18:19:04 +0000 @@ -555,6 +555,8 @@ dimensionNameSortedIdsMap: {} }; + Ext.applyIf(xLayout, layout); + // Columns, rows, filters if (layout.columns) { for (var i = 0, dim, items, xDim; i < layout.columns.length; i++) { @@ -711,7 +713,8 @@ getSyncronizedXLayout = function(xLayout, response) { var removeDimensionFromXLayout, - getHeaderNames; + getHeaderNames, + dimensions = [].concat(xLayout.columns, xLayout.rows, xLayout.filters); removeDimensionFromXLayout = function(objectName) { var getUpdatedAxis; @@ -759,16 +762,30 @@ co = dimConf.category.objectName, layout; + // Use metaData ids if any + for (var i = 0, dim, metaDataDim, items; i < dimensions.length; i++) { + dim = dimensions[i]; + metaDataDim = response.metaData[dim.objectName]; + + if (Ext.isArray(metaDataDim)) { + items = []; + + for (var j = 0; j < metaDataDim.length; j++) { + items.push({id: metaDataDim[j]}); + } + + dim.items = items; + } + } + // Remove co from layout if it does not exist in response if (Ext.Array.contains(xLayout.axisDimensionNames, co) && !(Ext.Array.contains(headerNames, co))) { removeDimensionFromXLayout(co); - - layout = pt.api.layout.Layout(xLayout); - - return layout ? pt.util.pivot.getExtendedLayout(layout) : null; } - return xLayout; + layout = pt.api.layout.Layout(xLayout); + + return layout ? pt.util.pivot.getExtendedLayout(layout) : null; }(); }; @@ -827,28 +844,32 @@ 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) { - // categories - if (header.name === pt.conf.finals.dimension.category.dimensionName) { - header.items = [].concat(response.metaData[pt.conf.finals.dimension.category.dimensionName]); - } - // periods - else if (header.name === pt.conf.finals.dimension.period.dimensionName) { - header.items = [].concat(response.metaData[pt.conf.finals.dimension.period.dimensionName]); - } + // Items: get ids from metadata + if (Ext.isArray(response.metaData[header.name])) { + header.items = Ext.clone(response.metaData[header.name]); + } + // Items: get ids from xLayout else { header.items = xLayout.dimensionNameIdsMap[header.name]; } + // Collect ids + ids = ids.concat(header.items); + + // Size header.size = header.items.length; } } @@ -861,6 +882,17 @@ } }(); + 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 createValueIds = function() { var valueHeaderIndex = response.nameHeaderMap[pt.conf.finals.dimension.value.value].index, dimensionNames = xLayout.axisDimensionNames, @@ -1778,7 +1810,7 @@ } Ext.Ajax.request({ - url: pt.baseUrl + '/api/reportTables/' + id + '.json?links=false&viewClass=dimensional', + url: pt.baseUrl + '/api/reportTables/' + id + '.json?viewClass=dimensional&links=false', method: 'GET', failure: function(r) { pt.util.mask.hideMask(); @@ -1798,7 +1830,7 @@ return util; }; -PT.core.getAPI = function(pt) { +PT.core.getApi = function(pt) { var dimConf = pt.conf.finals.dimension, api = { layout: { @@ -1914,7 +1946,7 @@ // userOrganisationUnitChildren: boolean (false) - // parentGraphMap: string ('') + // parentGraphMap: object // reportingPeriod: boolean (false) //report tables only @@ -2001,11 +2033,11 @@ layout.userOrganisationUnit = Ext.isBoolean(config.userOrganisationUnit) ? config.userOrganisationUnit : false; layout.userOrganisationUnitChildren = Ext.isBoolean(config.userOrganisationUnitChildren) ? config.userOrganisationUnitChildren : false; - layout.parentGraphMap = Ext.isString(config.parentGraphMap) ? config.parentGraphMap : ''; + layout.parentGraphMap = Ext.isObject(config.parentGraphMap) ? config.parentGraphMap : undefined; - layout.reportingPeriod = Ext.isBoolean(config.reportParams.paramReportingPeriod) ? config.reportParams.paramReportingPeriod : (Ext.isBoolean(config.reportingPeriod) ? config.reportingPeriod : false); - layout.organisationUnit = Ext.isBoolean(config.reportParams.paramOrganisationUnit) ? config.reportParams.paramOrganisationUnit : (Ext.isBoolean(config.organisationUnit) ? config.organisationUnit : false); - layout.parentOrganisationUnit = Ext.isBoolean(config.reportParams.paramParentOrganisationUnit) ? config.reportParams.paramParentOrganisationUnit : (Ext.isBoolean(config.parentOrganisationUnit) ? config.parentOrganisationUnit : false); + 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; @@ -2112,7 +2144,7 @@ pt.conf = PT.core.getConfigs(); pt.util = PT.core.getUtils(pt); - pt.api = PT.core.getAPI(pt); + pt.api = PT.core.getApi(pt); return pt; }; === modified file 'dhis-2/dhis-web/dhis-web-visualizer/src/main/resources/org/hisp/dhis/visualizer/i18n_module.properties' --- dhis-2/dhis-web/dhis-web-visualizer/src/main/resources/org/hisp/dhis/visualizer/i18n_module.properties 2013-05-13 14:00:23 +0000 +++ dhis-2/dhis-web/dhis-web-visualizer/src/main/resources/org/hisp/dhis/visualizer/i18n_module.properties 2013-05-23 16:34:57 +0000 @@ -190,4 +190,5 @@ can_view=Can view can_edit_and_view=Can edit and view search_for_user_groups=Search for user group -public_access=Public access \ No newline at end of file +public_access=Public access +detailed_data_elements_cannot_be_specified_as_filter=Detailed data elements cannot be specified as filter \ No newline at end of file === modified file 'dhis-2/dhis-web/dhis-web-visualizer/src/main/webapp/dhis-web-visualizer/app/scripts/app.js' --- dhis-2/dhis-web/dhis-web-visualizer/src/main/webapp/dhis-web-visualizer/app/scripts/app.js 2013-05-22 14:06:23 +0000 +++ dhis-2/dhis-web/dhis-web-visualizer/src/main/webapp/dhis-web-visualizer/app/scripts/app.js 2013-05-23 18:19:04 +0000 @@ -115,52 +115,57 @@ util.chart.getLayoutConfig = function() { var panels = dv.cmp.dimension.panels, - seriesDimensionName = dv.viewport.series.getValue(), - categoryDimensionName = dv.viewport.category.getValue(), - filterDimensionNames = dv.viewport.filter.getValue(), + columnDimNames = [dv.viewport.series.getValue()], + rowDimNames = [dv.viewport.category.getValue()], + filterDimNames = dv.viewport.filter.getValue(), config = dv.viewport.optionsWindow.getOptions(), - getDimension; + dimConf = dv.conf.finals.dimension, + dx = dimConf.data.dimensionName, + co = dimConf.category.dimensionName, + nameDimArrayMap = {}; + + config.type = dv.viewport.chartType.getChartType(); config.columns = []; config.rows = []; config.filters = []; - getDimension = function(config) { - if (dv.api.objectNameDimensionClassMap[config.dimension]) { - return dv.api.objectNameDimensionClassMap[config.dimension](config); - } - else { - return dv.api.Dimension(config); - } - }; + // Panel data + for (var i = 0, dim, dimName; i < panels.length; i++) { + dim = panels[i].getDimension(); + + if (dim) { + nameDimArrayMap[dim.dimension] = [dim]; + } + } + + nameDimArrayMap[dx] = Ext.Array.clean([].concat( + nameDimArrayMap[dimConf.indicator.objectName], + nameDimArrayMap[dimConf.dataElement.objectName], + nameDimArrayMap[dimConf.operand.objectName], + nameDimArrayMap[dimConf.dataSet.objectName] + )); // Columns, rows, filters - for (var i = 0, dim; i < panels.length; i++) { - dim = panels[i].getData(); - - if (dim) { - if (dim.dimensionName === seriesDimensionName) { - config.columns.push(getDimension({ - dimension: dim.objectName, - items: dim.items - })); - } - else if (dim.dimensionName === categoryDimensionName) { - config.rows.push(getDimension({ - dimension: dim.objectName, - items: dim.items - })); - } - else if (Ext.Array.contains(filterDimensionNames, dim.dimensionName)) { - config.filters.push(getDimension({ - dimension: dim.objectName, - items: dim.items - })); + for (var i = 0, nameArrays = [columnDimNames, rowDimNames, filterDimNames], axes = [config.columns, config.rows, config.filters], dimNames; i < nameArrays.length; i++) { + dimNames = nameArrays[i]; + + for (var j = 0, dimName, dim; j < dimNames.length; j++) { + dimName = dimNames[j]; + + if (dimName === dx && nameDimArrayMap.hasOwnProperty(dimName) && nameDimArrayMap[dimName]) { + for (var k = 0; k < nameDimArrayMap[dx].length; k++) { + axes[i].push(Ext.clone(nameDimArrayMap[dx][k])); + } + } + else if (nameDimArrayMap.hasOwnProperty(dimName) && nameDimArrayMap[dimName]) { + for (var k = 0; k < nameDimArrayMap[dimName].length; k++) { + axes[i].push(Ext.clone(nameDimArrayMap[dimName][k])); + } } } } - config.type = dv.viewport.chartType.getChartType(); config.userOrganisationUnit = dv.viewport.userOrganisationUnit.getValue(); config.userOrganisationUnitChildren = dv.viewport.userOrganisationUnitChildren.getValue(); @@ -838,7 +843,7 @@ hideTitle = Ext.create('Ext.form.field.Checkbox', { boxLabel: DV.i18n.hide_chart_title, - style: 'margin-bottom:6px', + style: 'margin-bottom:7px', listeners: { change: function() { title.xable(); @@ -853,7 +858,6 @@ width: 310, fieldLabel: DV.i18n.chart_title, fieldLabel: 'Chart title', - labelStyle: 'padding-left:16px', labelWidth: 123, maxLength: 100, enforceMaxLength: true, @@ -868,7 +872,6 @@ style: 'margin-bottom:2px; margin-left:2px', width: 310, fieldLabel: DV.i18n.domain_axis_label, - labelStyle: 'padding-left:16px', labelWidth: 123, maxLength: 100, enforceMaxLength: true @@ -880,7 +883,6 @@ style: 'margin-bottom:0; margin-left:2px', width: 310, fieldLabel: DV.i18n.range_axis_label, - labelStyle: 'padding-left:16px', labelWidth: 123, maxLength: 100, enforceMaxLength: true @@ -899,7 +901,7 @@ bodyStyle: 'border:0 none', items: [ { - bodyStyle: 'border:0 none; padding-top:3px; padding-left:18px; margin-right:5px', + bodyStyle: 'border:0 none; padding-top:3px; padding-left:2px; margin-right:5px', width: 130, html: 'Target value / title:' }, @@ -913,7 +915,7 @@ bodyStyle: 'border:0 none', items: [ { - bodyStyle: 'border:0 none; padding-top:3px; padding-left:18px; margin-right:5px', + bodyStyle: 'border:0 none; padding-top:3px; padding-left:2px; margin-right:5px', width: 130, html: 'Base value / title:' }, @@ -1115,10 +1117,12 @@ }); getBody = function() { - var favorite = Ext.clone(dv.xLayout); + var favorite, + dimensions; - if (favorite) { - var dimensions = [].concat(favorite.columns, favorite.rows, favorite.filters); + if (dv.layout) { + favorite = Ext.clone(dv.layout); + dimensions = [].concat(favorite.columns, favorite.rows, favorite.filters); // Server sync: property names favorite.showData = favorite.showValues; @@ -1139,8 +1143,6 @@ favorite.rangeAxisLabel = favorite.rangeAxisTitle; delete favorite.rangeAxisTitle; - delete favorite.extended; - // Replace operand id characters for (var i = 0; i < dimensions.length; i++) { if (dimensions[i].dimension === dv.conf.finals.dimension.operand.objectName) { @@ -1149,27 +1151,9 @@ } } } - - // Server sync: user orgunit - if (favorite.userOrganisationUnit || favorite.userOrganisationUnitChildren) { - var dimensions = [].concat(favorite.columns, favorite.rows, favorite.filters); - - for (var i = 0; i < dimensions.length; i++) { - if (dimensions[i].dimension === dv.conf.finals.dimension.organisationUnit.objectName) { - if (favorite.userOrganisationUnit) { - dimensions[i].items.push({id: 'USER_ORGUNIT'}); - } - if (favorite.userOrganisationUnitChildren) { - dimensions[i].items.push({id: 'USER_ORGUNIT_CHILDREN'}); - } - } - } - } - - return favorite; } - return; + return favorite; }; NameWindow = function(id) { @@ -1196,32 +1180,29 @@ var favorite = getBody(); favorite.name = nameTextfield.getValue(); - if (!(favorite && favorite.name)) { - return; + if (favorite && favorite.name) { + Ext.Ajax.request({ + url: dv.baseUrl + '/api/charts/', + method: 'POST', + headers: {'Content-Type': 'application/json'}, + params: Ext.encode(favorite), + failure: function(r) { + dv.util.mask.hideMask(); + alert(r.responseText); + }, + success: function(r) { + var id = r.getAllResponseHeaders().location.split('/').pop(); + + dv.favorite = favorite; + + dv.store.charts.loadStore(); + + //dv.viewport.interpretationButton.enable(); + + window.destroy(); + } + }); } - - // Request - Ext.Ajax.request({ - url: dv.init.contextPath + '/api/charts/', - method: 'POST', - headers: {'Content-Type': 'application/json'}, - params: Ext.encode(favorite), - failure: function(r) { - dv.util.mask.hideMask(); - alert(r.responseText); - }, - success: function(r) { - var id = r.getAllResponseHeaders().location.split('/').pop(); - - dv.favorite = favorite; - - dv.store.charts.loadStore(); - - //dv.viewport.interpretationButton.enable(); - - window.destroy(); - } - }); } }); @@ -2338,18 +2319,17 @@ xtype: 'panel', title: '
' + DV.i18n.indicators + '
', hideCollapseTool: true, - getData: function() { - var data = { - dimensionName: dv.conf.finals.dimension.indicator.dimensionName, - objectName: dv.conf.finals.dimension.indicator.objectName, + getDimension: function() { + var config = { + dimension: dv.conf.finals.dimension.indicator.objectName, items: [] }; dv.store.indicatorSelected.each( function(r) { - data.items.push({id: r.data.id}); + config.items.push({id: r.data.id}); }); - return data.items.length ? data : null; + return config.items.length ? config : null; }, onExpand: function() { var h = dv.viewport.westRegion.hasScrollbar ? @@ -2624,27 +2604,17 @@ xtype: 'panel', title: '
' + DV.i18n.data_elements + '
', hideCollapseTool: true, - getData: function() { - var optionComboIds = [], - data = { - dimensionName: dv.conf.finals.dimension.dataElement.dimensionName, - objectName: dataElementDetailLevel.getValue(), - items: [] - }; + getDimension: function() { + var config = { + dimension: dataElementDetailLevel.getValue(), + items: [] + }; dv.store.dataElementSelected.each( function(r) { - data.items.push({id: r.data.id}); - - if (dataElementDetailLevel.getValue() === dv.conf.finals.dimension.operand.objectName) { - optionComboIds.push(r.data.optionComboId); - } + config.items.push({id: r.data.id}); }); - if (optionComboIds.length) { - data.optionComboIds = optionComboIds; - } - - return data.items.length ? data : null; + return config.items.length ? config : null; }, onExpand: function() { var h = dv.viewport.westRegion.hasScrollbar ? @@ -2768,18 +2738,17 @@ xtype: 'panel', title: '
' + DV.i18n.reporting_rates + '
', hideCollapseTool: true, - getData: function() { - var data = { - dimensionName: dv.conf.finals.dimension.dataSet.dimensionName, - objectName: dv.conf.finals.dimension.dataSet.objectName, + getDimension: function() { + var config = { + dimension: dv.conf.finals.dimension.dataSet.objectName, items: [] }; dv.store.dataSetSelected.each( function(r) { - data.items.push({id: r.data.id}); + config.items.push({id: r.data.id}); }); - return data.items.length ? data : null; + return config.items.length ? config : null; }, onExpand: function() { var h = dv.viewport.westRegion.hasScrollbar ? @@ -3235,25 +3204,24 @@ xtype: 'panel', title: '
Periods
', hideCollapseTool: true, - getData: function() { - var data = { - dimensionName: dv.conf.finals.dimension.period.dimensionName, - objectName: dv.conf.finals.dimension.period.objectName, + getDimension: function() { + var config = { + dimension: dv.conf.finals.dimension.period.objectName, items: [] }, chb = dv.cmp.dimension.relativePeriod.checkbox; dv.store.fixedPeriodSelected.each( function(r) { - data.items.push({id: r.data.id}); + config.items.push({id: r.data.id}); }); for (var i = 0; i < chb.length; i++) { if (chb[i].getValue()) { - data.items.push({id: chb[i].relativePeriodId}); + config.items.push({id: chb[i].relativePeriodId}); } } - return data.items.length ? data : null; + return config.items.length ? config : null; }, onExpand: function() { var h = dv.viewport.westRegion.hasScrollbar ? @@ -3520,29 +3488,28 @@ bodyStyle: 'padding-top:5px', hideCollapseTool: true, collapsed: false, - getData: function() { + getDimension: function() { var r = treePanel.getSelectionModel().getSelection(), - data = { - dimensionName: dv.conf.finals.dimension.organisationUnit.dimensionName, - objectName: dv.conf.finals.dimension.organisationUnit.objectName, + config = { + dimension: dv.conf.finals.dimension.organisationUnit.objectName, items: [] }; if (userOrganisationUnit.getValue() || userOrganisationUnitChildren.getValue()) { if (userOrganisationUnit.getValue()) { - data.items.push({id: 'USER_ORGUNIT'}); + config.items.push({id: 'USER_ORGUNIT'}); } if (userOrganisationUnitChildren.getValue()) { - data.items.push({id: 'USER_ORGUNIT_CHILDREN'}); + config.items.push({id: 'USER_ORGUNIT_CHILDREN'}); } } else { for (var i = 0; i < r.length; i++) { - data.items.push({id: r[i].data.id}); + config.items.push({id: r[i].data.id}); } } - return data.items.length ? data : null; + return config.items.length ? config : null; }, onExpand: function() { var h = dv.viewport.westRegion.hasScrollbar ? @@ -3730,18 +3697,17 @@ hideCollapseTool: true, availableStore: availableStore, selectedStore: selectedStore, - getData: function() { - var data = { - dimensionName: dimension.id, - objectName: dimension.id, + getDimension: function() { + var config = { + dimension: dimension.id, items: [] }; selectedStore.each( function(r) { - data.items.push({id: r.data.id}); + config.items.push({id: r.data.id}); }); - return data.items.length ? data : null; + return config.items.length ? config : null; }, onExpand: function() { if (!availableStore.isLoaded) { @@ -3806,11 +3772,31 @@ objectNameDimensionMap[dimensions[i].dimension] = dimensions[i]; } - // Indicator as filter - for (var i = 0; i < layout.filters.length; i++) { - if (layout.filters[i].dimension === dimConf.indicator.objectName) { - alert(DV.i18n.indicators_cannot_be_specified_as_filter); - return; + if (!layout) { + return; + } + + 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) { + alert(DV.i18n.indicators_cannot_be_specified_as_filter); + return; + } + + // Categories as filter + //if (layout.filters[i].dimension === dimConf.category.objectName) { + //alert(PT.i18n.categories_cannot_be_specified_as_filter); + //return; + //} + + // Operands as filter + if (layout.filters[i].dimension === dimConf.operand.objectName) { + alert(DV.i18n.detailed_data_elements_cannot_be_specified_as_filter); + return; + } + } } @@ -3853,11 +3839,8 @@ update = function() { var config = dv.util.chart.getLayoutConfig(), - layout = dv.api.Layout(config); + layout = dv.api.layout.Layout(config); - if (!layout) { - return; - } if (!validateSpecialCases(layout)) { return; } @@ -4099,38 +4082,31 @@ } }); - setFavorite = function(xLayout) { - var seriesId = xLayout.extended.columnsDimensionNames[0], - categoryId = xLayout.extended.rowsDimensionNames[0], - filterIds = xLayout.extended.filtersDimensionNames, - dimMap = xLayout.extended.objectNameDimensionMap, - recMap = xLayout.extended.objectNameRecordsMap, - graphMap = xLayout.extended.parentGraphMap, - dimConf = dv.conf.finals.dimension, + setFavorite = function(layout) { + var dimConf = dv.conf.finals.dimension, + xLayout, + dimMap, + recMap, + graphMap, objectName, periodRecords, fixedPeriodRecords = [], isOu = false, isOuc = false; - // Type - dv.viewport.chartType.setChartType(xLayout.type); - - // Series, category, filter - dv.viewport.series.setValue(seriesId); - dv.viewport.series.filterNext(); - - dv.viewport.category.setValue(categoryId); - dv.viewport.category.filterNext(); - - dv.viewport.filter.setValue(filterIds); + dv.util.chart.createChart(layout, dv); + + xLayout = dv.util.chart.getExtendedLayout(layout); + dimMap = xLayout.objectNameDimensionsMap; + recMap = xLayout.objectNameItemsMap; + graphMap = layout.parentGraphMap; // Indicators dv.store.indicatorSelected.removeAll(); objectName = dimConf.indicator.objectName; if (dimMap[objectName]) { dv.store.indicatorSelected.add(Ext.clone(recMap[objectName])); - pt.util.multiselect.filterAvailable({store: pt.store.indicatorAvailable}, {store: pt.store.indicatorSelected}); + dv.util.multiselect.filterAvailable({store: dv.store.indicatorAvailable}, {store: dv.store.indicatorSelected}); } // Data elements @@ -4138,7 +4114,7 @@ objectName = dimConf.dataElement.objectName; if (dimMap[objectName]) { dv.store.dataElementSelected.add(Ext.clone(recMap[objectName])); - pt.util.multiselect.filterAvailable({store: pt.store.dataElementAvailable}, {store: pt.store.dataElementSelected}); + dv.util.multiselect.filterAvailable({store: dv.store.dataElementAvailable}, {store: dv.store.dataElementSelected}); dv.viewport.dataElementDetailLevel.setValue(objectName); } @@ -4146,7 +4122,7 @@ objectName = dimConf.operand.objectName; if (dimMap[objectName]) { dv.store.dataElementSelected.add(Ext.clone(recMap[objectName])); - pt.util.multiselect.filterAvailable({store: pt.store.dataSetAvailable}, {store: pt.store.dataSetSelected}); + dv.util.multiselect.filterAvailable({store: dv.store.dataSetAvailable}, {store: dv.store.dataSetSelected}); dv.viewport.dataElementDetailLevel.setValue(objectName); } @@ -4172,7 +4148,7 @@ } } dv.store.fixedPeriodSelected.add(fixedPeriodRecords); - pt.util.multiselect.filterAvailable({store: pt.store.fixedPeriodAvailable}, {store: pt.store.fixedPeriodSelected}); + dv.util.multiselect.filterAvailable({store: dv.store.fixedPeriodAvailable}, {store: dv.store.fixedPeriodSelected}); // Group sets for (var key in dimensionIdSelectedStoreMap) { @@ -4192,8 +4168,19 @@ } } + // Layout + dv.viewport.chartType.setChartType(xLayout.type); + + dv.viewport.series.setValue(xLayout.columnDimensionNames[0]); + dv.viewport.series.filterNext(); + + dv.viewport.category.setValue(xLayout.rowDimensionNames[0]); + dv.viewport.category.filterNext(); + + dv.viewport.filter.setValue(xLayout.filterDimensionNames); + // Options - dv.viewport.optionsWindow.setOptions(xLayout); + dv.viewport.optionsWindow.setOptions(layout); // Organisation units if (recMap[dimConf.organisationUnit.objectName]) { @@ -4211,7 +4198,7 @@ userOrganisationUnitChildren.setValue(isOuc); // If fav has organisation units, wait for tree callback before update - if (recMap[dimConf.organisationUnit.objectName] && graphMap) { + if (recMap[dimConf.organisationUnit.objectName] && Ext.isObject(graphMap)) { treePanel.numberOfRecords = dv.util.object.getLength(graphMap); for (var key in graphMap) { if (graphMap.hasOwnProperty(key)) { @@ -4221,7 +4208,7 @@ } else { treePanel.reset(); - update(); + //update(); } }; === modified file 'dhis-2/dhis-web/dhis-web-visualizer/src/main/webapp/dhis-web-visualizer/app/scripts/core.js' --- dhis-2/dhis-web/dhis-web-visualizer/src/main/webapp/dhis-web-visualizer/app/scripts/core.js 2013-05-15 13:00:34 +0000 +++ dhis-2/dhis-web/dhis-web-visualizer/src/main/webapp/dhis-web-visualizer/app/scripts/core.js 2013-05-23 18:19:04 +0000 @@ -417,188 +417,208 @@ }; util.chart = { - extendLayout: function(layout) { - var xLayout = Ext.clone(layout), - dimConf = dv.conf.finals.dimension, - - axisDimensions = [].concat(Ext.clone(xLayout.columns) || [], Ext.clone(xLayout.rows) || []), - axisDimensionNames = [], - axisObjectNames = [], - axisItems = [], - - filterDimensions = Ext.clone(xLayout.filters) || [], - filterDimensionNames = [], - filterObjectNames = [], - filterItems = [], - - objectNameDimensionMap = {}, - dimensionNameItemsMap = {}, - - columns, - columnsDimensionNames = [], - rows, - rowsDimensionNames = [], - filters, - filtersDimensionNames = [], - - objectNameRecordsMap = {}; - - xLayout.extended = {}; - - // Axis - for (var i = 0, dim, items; i < axisDimensions.length; i++) { - dim = axisDimensions[i]; - items = []; - - dim.dimensionName = dv.conf.finals.dimension.objectNameMap[dim.dimension].dimensionName; - dim.objectName = dim.dimension; - - axisDimensionNames.push(dim.dimensionName); - axisObjectNames.push(dim.objectName); - - for (var j = 0; j < dim.items.length; j++) { - items.push(dim.items[j].id); - } - - dim.items = items; - - axisItems = axisItems.concat(items); - } - - // Filter - for (var i = 0, dim, items; i < filterDimensions.length; i++) { - dim = filterDimensions[i]; - items = []; - - dim.dimensionName = dv.conf.finals.dimension.objectNameMap[dim.dimension].dimensionName; - dim.objectName = dim.dimension; - - filterDimensionNames.push(dim.dimensionName); - filterObjectNames.push(dim.objectName); - - for (var j = 0; j < dim.items.length; j++) { - items.push(dim.items[j].id); - } - - dim.items = items; - - filterItems = filterItems.concat(items); - } - - // Axis - xLayout.extended.axisDimensions = axisDimensions; - xLayout.extended.axisDimensionNames = Ext.Array.unique(axisDimensionNames); - xLayout.extended.axisObjectNames = axisObjectNames; - xLayout.extended.axisItems = axisItems; - - // Filter - xLayout.extended.filterDimensions = filterDimensions; - xLayout.extended.filterDimensionNames = Ext.Array.unique(filterDimensionNames); - xLayout.extended.filterObjectNames = filterObjectNames; - xLayout.extended.filterItems = filterItems; + getExtendedLayout: function(layout) { + var dimConf = dv.conf.finals.dimension, + layout = Ext.clone(layout), + xLayout = { + columns: [], + rows: [], + filters: [], + + columnObjectNames: [], + columnDimensionNames: [], + columnItems: [], + columnIds: [], + rowObjectNames: [], + rowDimensionNames: [], + rowItems: [], + rowIds: [], + + // Axis + axisDimensions: [], + axisObjectNames: [], + axisDimensionNames: [], + + // For param string + sortedAxisDimensionNames: [], + + // Filter + filterDimensions: [], + filterObjectNames: [], + filterDimensionNames: [], + filterItems: [], + filterIds: [], + + // 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.columnItems = xLayout.columnItems.concat(xDim.items); + xLayout.columnIds = xLayout.columnIds.concat(xDim.ids); + + 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 = 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.rowItems = xLayout.rowItems.concat(xDim.items); + xLayout.rowIds = xLayout.rowIds.concat(xDim.ids); + + 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.filterItems = xLayout.filterItems.concat(xDim.items); + xLayout.filterIds = xLayout.filterIds.concat(xDim.ids); + + 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 = dv.util.array.sortDimensions(Ext.clone(xLayout.filterDimensions)); // All - xLayout.extended.dimensions = [].concat(axisDimensions, filterDimensions); - xLayout.extended.dimensionNames = Ext.Array.unique([].concat(axisDimensionNames, filterDimensionNames)); - xLayout.extended.objectNames = [].concat(axisObjectNames, filterObjectNames); - xLayout.extended.items = [].concat(axisItems, filterItems); - - // Sorted axis - xLayout.extended.sortedAxisDimensions = dv.util.array.sortDimensions(Ext.clone(axisDimensions)); - xLayout.extended.sortedAxisDimensionNames = Ext.Array.unique(Ext.clone(axisDimensionNames).sort()); - xLayout.extended.sortedAxisObjectNames = Ext.clone(axisObjectNames).sort(); - xLayout.extended.sortedAxisItems = Ext.clone(axisItems).sort(); - - // Sorted filter - xLayout.extended.sortedFilterDimensions = dv.util.array.sortDimensions(Ext.clone(filterDimensions)); - xLayout.extended.sortedFilterDimensionNames = Ext.Array.unique(Ext.clone(filterDimensionNames).sort()); - xLayout.extended.sortedFilterObjectNames = Ext.clone(filterObjectNames).sort(); - xLayout.extended.sortedFilterItems = Ext.clone(filterItems).sort(); - - // Sorted all - xLayout.extended.sortedDimensions = [].concat(xLayout.extended.sortedAxisDimensions, xLayout.extended.sortedFilterDimensions); - xLayout.extended.sortedDimensionNames = Ext.Array.unique([].concat(xLayout.extended.sortedAxisDimensionNames, xLayout.extended.sortedFilterDimensionNames)); - xLayout.extended.sortedObjectNames = [].concat(xLayout.extended.sortedAxisObjectNames, xLayout.extended.sortedFilterObjectNames); - xLayout.extended.sortedItems = [].concat(xLayout.extended.sortedAxisItems, xLayout.extended.sortedFilterItems); - - // Maps - - // Add dimensionName keys - for (var i = 0, name; i < xLayout.extended.dimensionNames.length; i++) { - name = xLayout.extended.dimensionNames[i]; - dimensionNameItemsMap[name] = []; - } - - // Add dimensions and items - for (var i = 0, dim; i < xLayout.extended.dimensions.length; i++) { - dim = xLayout.extended.dimensions[i]; - - // objectName : object - objectNameDimensionMap[dim.objectName] = dim; - - // dimensionName : items - dimensionNameItemsMap[dim.dimensionName] = dimensionNameItemsMap[dim.dimensionName].concat(Ext.clone(dim.items)); - } - - xLayout.extended.objectNameDimensionMap = objectNameDimensionMap; - xLayout.extended.dimensionNameItemsMap = dimensionNameItemsMap; - - // Columns, rows, filters - columns = Ext.clone(xLayout.columns); - for (var i = 0, dim; i < columns.length; i++) { - dim = columns[i]; - dim.objectName = dim.dimension; - dim.dimensionName = dimConf.objectNameMap[dim.objectName].dimensionName; - dim.records = Ext.clone(dim.items); - dim.items = xLayout.extended.objectNameDimensionMap[dim.objectName].items; - - objectNameRecordsMap[dim.objectName] = dim.records; - } - - rows = Ext.clone(xLayout.rows); - for (var i = 0, dim; i < rows.length; i++) { - dim = rows[i]; - dim.objectName = dim.dimension; - dim.dimensionName = dimConf.objectNameMap[dim.objectName].dimensionName; - dim.records = Ext.clone(dim.items); - dim.items = xLayout.extended.objectNameDimensionMap[dim.objectName].items; - - objectNameRecordsMap[dim.objectName] = Ext.clone(dim.records); - } - - filters = Ext.clone(xLayout.filters); - for (var i = 0, dim; i < filters.length; i++) { - dim = filters[i]; - dim.objectName = dim.dimension; - dim.dimensionName = dimConf.objectNameMap[dim.objectName].dimensionName; - dim.records = Ext.clone(dim.items); - dim.items = xLayout.extended.objectNameDimensionMap[dim.objectName].items; - - objectNameRecordsMap[dim.objectName] = Ext.clone(dim.records); - } - - xLayout.extended.columns = columns; - xLayout.extended.rows = rows; - xLayout.extended.filters = filters; - - xLayout.extended.objectNameRecordsMap = objectNameRecordsMap; - - // columnsDimensionNames, rowsDimensionNames, filtersDimensionNames - for (var i = 0; i < xLayout.extended.columns.length; i++) { - columnsDimensionNames.push(xLayout.extended.columns[i].dimensionName); - } - - for (var i = 0; i < xLayout.extended.rows.length; i++) { - rowsDimensionNames.push(xLayout.extended.rows[i].dimensionName); - } - - for (var i = 0; i < xLayout.extended.filters.length; i++) { - filtersDimensionNames.push(xLayout.extended.filters[i].dimensionName); - } - - xLayout.extended.columnsDimensionNames = columnsDimensionNames; - xLayout.extended.rowsDimensionNames = rowsDimensionNames; - xLayout.extended.filtersDimensionNames = filtersDimensionNames; + 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; }, @@ -607,8 +627,7 @@ var dimConf = dv.conf.finals.dimension, getSyncronizedXLayout, getParamString, - validateResponse, - extendResponse, + getExtendedResponse, getDefaultStore, getDefaultNumericAxis, getDefaultCategoryAxis, @@ -624,23 +643,23 @@ initialize; getParamString = function(xLayout) { - var sortedAxisDimensionNames = xLayout.extended.sortedAxisDimensionNames, - sortedFilterDimensions = xLayout.extended.sortedFilterDimensions, + var sortedAxisDimensionNames = xLayout.sortedAxisDimensionNames, + sortedFilterDimensions = xLayout.sortedFilterDimensions, + dimensionNameSortedIdsMap = xLayout.dimensionNameSortedIdsMap, paramString = '?', dimConf = dv.conf.finals.dimension, addCategoryDimension = false, - map = xLayout.extended.dimensionNameItemsMap, - dx = dimConf.indicator.dimensionName, - items; - - for (var i = 0, dimensionName; i < sortedAxisDimensionNames.length; i++) { - dimensionName = sortedAxisDimensionNames[i]; - - paramString += 'dimension=' + dimensionName; - - items = Ext.clone(xLayout.extended.dimensionNameItemsMap[dimensionName]).sort(); - - if (dimensionName === dx) { + map = xLayout.dimensionNameItemsMap, + dx = dimConf.indicator.dimensionName; + + for (var i = 0, dimName, items; i < sortedAxisDimensionNames.length; i++) { + dimName = sortedAxisDimensionNames[i]; + + paramString += 'dimension=' + dimName; + + items = Ext.clone(dimensionNameSortedIdsMap[dimName]); + + if (dimName === dx) { for (var j = 0, index; j < items.length; j++) { index = items[j].indexOf('-'); @@ -668,7 +687,7 @@ for (var i = 0, dim; i < sortedFilterDimensions.length; i++) { dim = sortedFilterDimensions[i]; - paramString += '&filter=' + dim.dimensionName + ':' + dim.items.join(';'); + paramString += '&filter=' + dim.dimensionName + ':' + dim.ids.join(';'); } } @@ -677,42 +696,32 @@ getSyncronizedXLayout = function(xLayout, response) { var dimensions = [].concat(xLayout.columns, xLayout.rows, xLayout.filters), - xOuDimension = xLayout.extended.objectNameDimensionMap[dimConf.organisationUnit.objectName], + xOuDimension = xLayout.objectNameDimensionsMap[dimConf.organisationUnit.objectName], isUserOrgunit = xOuDimension && Ext.Array.contains(xOuDimension.items, 'USER_ORGUNIT'), isUserOrgunitChildren = xOuDimension && Ext.Array.contains(xOuDimension.items, 'USER_ORGUNIT_CHILDREN'), peItems = [], - ouItems = []; - - // Relative periods - for (var i = 0, periodIds; i < dimensions.length; i++) { - if (dimensions[i].dimension === dimConf.period.objectName) { - periodIds = response.metaData.pe; - - for (var j = 0; j < periodIds.length; j++) { - peItems.push({id: periodIds[j]}); - } - - dimensions[i].items = peItems; - } - } - - // Add user orgunits - if (isUserOrgunit || isUserOrgunitChildren) { - if (isUserOrgunit) { - ouItems.push(Ext.clone(dv.init.user.ou)); - } - if (isUserOrgunitChildren) { - ouItems = ouItems.concat(Ext.clone(dv.init.user.ouc)); - } - - for (var i = 0; i < dimensions.length; i++) { - if (dimensions[i].dimension === dimConf.organisationUnit.objectName) { - dimensions[i].items = ouItems; - } - } - } - - return dv.util.chart.extendLayout(xLayout); + ouItems = [], + layout; + + // Use metaData ids if any + for (var i = 0, dim, metaDataDim, items; i < dimensions.length; i++) { + dim = dimensions[i]; + metaDataDim = response.metaData[dim.objectName]; + + if (Ext.isArray(metaDataDim)) { + items = []; + + for (var j = 0; j < metaDataDim.length; j++) { + items.push({id: metaDataDim[j]}); + } + + dim.items = items; + } + } + + layout = dv.api.layout.Layout(xLayout); + + return layout ? dv.util.chart.getExtendedLayout(layout) : null; }; validateResponse = function(response) { @@ -741,31 +750,35 @@ return true; }; - extendResponse = function(response, xLayout) { + 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) { - // Categories - if (header.name === dv.conf.finals.dimension.category.dimensionName) { - header.items = [].concat(response.metaData[dv.conf.finals.dimension.category.dimensionName]); - } - // Periods - else if (header.name === dv.conf.finals.dimension.period.dimensionName) { - header.items = [].concat(response.metaData[dv.conf.finals.dimension.period.dimensionName]); - } + // Items: get ids from metadata + if (Ext.isArray(response.metaData[header.name])) { + header.items = Ext.clone(response.metaData[header.name]); + } + // Items: get ids from xLayout else { - header.items = xLayout.extended.dimensionNameItemsMap[header.name]; + header.items = xLayout.dimensionNameIdsMap[header.name]; } + // Collect ids + ids = ids.concat(header.items); + + // Size header.size = header.items.length; } } @@ -778,10 +791,21 @@ } }(); + 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[dv.conf.finals.dimension.value.value].index, coHeader = response.nameHeaderMap[dv.conf.finals.dimension.category.dimensionName], - axisDimensionNames = xLayout.extended.axisDimensionNames, + axisDimensionNames = xLayout.axisDimensionNames, idIndexOrder = []; // idIndexOrder @@ -834,12 +858,13 @@ getDefaultStore = function(xResponse, xLayout) { var pe = dv.conf.finals.dimension.period.dimensionName, - columnDimensionName = xLayout.extended.columns[0].dimensionName, - rowDimensionName = xLayout.extended.rows[0].dimensionName, + columnDimensionName = xLayout.columns[0].dimensionName, + rowDimensionName = xLayout.rows[0].dimensionName, data = [], - columnIds = columnDimensionName === pe ? xResponse.metaData.pe : xLayout.extended.dimensionNameItemsMap[columnDimensionName], - rowIds = rowDimensionName === pe ? xResponse.metaData.pe : xLayout.extended.dimensionNameItemsMap[rowDimensionName], + //columnIds = columnDimensionName === pe ? xResponse.metaData.pe : xLayout.extended.dimensionNameItemsMap[columnDimensionName], + columnIds = Ext.isArray(xResponse.metaData[columnDimensionName]) ? xResponse.metaData[columnDimensionName] : xLayout.dimensionNameIdsMap[columnDimensionName], + rowIds = Ext.isArray(xResponse.metaData[rowDimensionName]) ? xResponse.metaData[rowDimensionName] : xLayout.dimensionNameIdsMap[rowDimensionName], trendLineFields = [], targetLineFields = [], baseLineFields = [], @@ -852,7 +877,9 @@ obj[dv.conf.finals.data.domain] = xResponse.metaData.names[category]; for (var j = 0, id; j < columnIds.length; j++) { - id = dv.util.str.replaceAll(columnIds[j], '-', '') + rowIds[i]; + id = dv.util.str.replaceAll(columnIds[j], '-', '') + dv.util.str.replaceAll(rowIds[i], '-', ''); + //id = columnIds[j].replace('-', '') + rowIds[i].replace('-', ''); + obj[columnIds[j]] = xResponse.idValueMap[id]; } @@ -1029,26 +1056,11 @@ }; getDefaultSeriesTitle = function(store, xResponse) { - var a = [], - ids; + var a = []; - for (var i = 0, id; i < store.rangeFields.length; i++) { + for (var i = 0, id, ids; i < store.rangeFields.length; i++) { id = store.rangeFields[i]; - - if (id.indexOf('-') !== -1) { - ids = id.split('-'); - id = ''; - - for (var j = 0; j < ids.length; j++) { - id += j !== 0 ? ' ' : ''; - id += xResponse.metaData.names[ids[j]]; - } - - a.push(id); - } - else { - a.push(xResponse.metaData.names[id]); - } + a.push(xResponse.metaData.names[id]); } return a; @@ -1225,14 +1237,19 @@ }; getDefaultChartTitle = function(store, xResponse, xLayout) { - var filterItems = xLayout.extended.filterItems, + var ids = xLayout.filterIds, a = [], - text = ''; - - if (Ext.isArray(filterItems) && filterItems.length) { - for (var i = 0; i < filterItems.length; i++) { - text += xResponse.metaData.names[filterItems[i]]; - text += i < filterItems.length - 1 ? ', ' : ''; + text = '', + fontSize; + + if (xLayout.type === dv.conf.finals.chart.pie) { + ids = ids.concat(xLayout.columnIds); + } + + if (Ext.isArray(ids) && ids.length) { + for (var i = 0; i < ids.length; i++) { + text += xResponse.metaData.names[ids[i]]; + text += i < ids.length - 1 ? ', ' : ''; } } @@ -1240,10 +1257,12 @@ text = xLayout.title; } + fontSize = (dv.viewport.centerRegion.getWidth() / text.length) < 11.6 ? 13 : 18; + return Ext.create('Ext.draw.Sprite', { type: 'text', text: text, - font: 'bold 19px ' + dv.conf.chart.style.fontFamily, + font: 'bold ' + fontSize + 'px ' + dv.conf.chart.style.fontFamily, fill: '#111', height: 20, y: 20 @@ -1459,7 +1478,8 @@ categoryAxis = getDefaultCategoryAxis(store, xLayout), axes = [numericAxis, categoryAxis], series = [], - colors = dv.conf.chart.theme.dv1.slice(0, store.rangeFields.length); + colors = dv.conf.chart.theme.dv1.slice(0, store.rangeFields.length), + seriesTitles = getDefaultSeriesTitle(store, xResponse); // Series for (var i = 0, line; i < store.rangeFields.length; i++) { @@ -1477,7 +1497,7 @@ radius: 4 }, tips: getDefaultTips(), - title: getDefaultSeriesTitle(store, xResponse) + title: seriesTitles[i] }; //if (xLayout.showValues) { @@ -1596,7 +1616,7 @@ chart; // Theme - colors = dv.conf.chart.theme.dv1.slice(0, xResponse.nameHeaderMap[xLayout.extended.rows[0].dimensionName].items.length); + colors = dv.conf.chart.theme.dv1.slice(0, xResponse.nameHeaderMap[xLayout.rowDimensionNames[0]].items.length); Ext.chart.theme.dv1 = Ext.extend(Ext.chart.theme.Base, { constructor: function(config) { @@ -1612,7 +1632,7 @@ chart.legend.position = 'right'; chart.legend.isVertical = true; - chart.insetPadding = 20; + chart.insetPadding = 40; chart.shadow = true; return chart; @@ -1624,7 +1644,7 @@ xResponse, chart; - xLayout = dv.util.chart.extendLayout(layout); + xLayout = dv.util.chart.getExtendedLayout(layout); dv.paramString = getParamString(xLayout); url = dv.init.contextPath + '/api/analytics.json' + dv.paramString; @@ -1665,7 +1685,7 @@ return; } - xResponse = extendResponse(response, xLayout); + xResponse = getExtendedResponse(response, xLayout); chart = generator[xLayout.type](xResponse, xLayout); @@ -1680,12 +1700,13 @@ } dv.chart = chart; + dv.layout = layout; dv.xLayout = xLayout; dv.xResponse = xResponse; console.log("xResponse", xResponse); console.log("xLayout", xLayout); -console.log("chart", chart); +console.log("layout", layout); } }); @@ -1706,15 +1727,10 @@ alert(r.responseText); }, success: function(r) { - var layout, - xLayout; - - r = Ext.decode(r.responseText); - layout = dv.api.Layout(r); - xLayout = dv.util.chart.extendLayout(layout); - - if (xLayout) { - dv.viewport.setFavorite(xLayout); + var layout = dv.api.layout.Layout(Ext.decode(r.responseText)); + + if (layout) { + dv.viewport.setFavorite(layout); } } }); @@ -1727,481 +1743,313 @@ DV.core.getApi = function(dv) { var dimConf = dv.conf.finals.dimension, api = { - objectNameDimensionClassMap: {} - }; - - // Dimension - - api.DimensionSuper = function() { - return { - dimension: null, // string - - items: null // array of records - }; - }; - - api.Indicator = function(config) { - var indicator = api.DimensionSuper(), - validateConfig; - - validateConfig = function() { - if (!Ext.isObject(config)) { - alert('Indicator config is not an object'); - return; - } - - if (!Ext.isString(config.dimension)) { - alert('Indicator dimension name is illegal'); - return; - } - - if (!Ext.isArray(config.items)) { - alert('Indicator items is not an array'); - return; - } - - if (!config.items.length) { - alert('Indicator has no items'); - return; - } - - return true; - }; - - return function() { - if (!validateConfig()) { - return; - } - - indicator.dimension = config.dimension; - indicator.dimensionName = dimConf.indicator.dimensionName; - indicator.objectName = dimConf.indicator.objectName; - indicator.items = Ext.clone(config.items); - - return indicator; - }(); - }; - - api.DataElement = function(config) { - var dataElement = api.DimensionSuper(), - validateConfig; - - validateConfig = function() { - if (!Ext.isObject(config)) { - alert('Data element config is not an object'); - return; - } - - if (!Ext.isString(config.dimension)) { - alert('Data element dimension name is illegal'); - return; - } - - if (!Ext.isArray(config.items)) { - alert('Data element items is not an array'); - return; - } - - if (!config.items.length) { - alert('Data element has no items'); - return; - } - - return true; - }; - - return function() { - if (!validateConfig()) { - return; - } - - dataElement.dimension = config.dimension; - dataElement.dimensionName = dimConf.dataElement.dimensionName; - dataElement.objectName = dimConf.dataElement.objectName; - dataElement.items = Ext.clone(config.items); - - return dataElement; - }(); - }; - - api.Operand = function(config) { - var operand = api.DimensionSuper(), - validateConfig; - - validateConfig = function() { - if (!Ext.isObject(config)) { - alert('Operand config is not an object'); - return; - } - - if (!Ext.isString(config.dimension)) { - alert('Operand dimension name is illegal'); - return; - } - - if (!Ext.isArray(config.items)) { - alert('Operand items is not an array'); - return; - } - - if (!config.items.length) { - alert('Operand has no items'); - return; - } - - return true; - }; - - return function() { - if (!validateConfig()) { - return; - } - - operand.dimension = config.dimension; - operand.dimensionName = dimConf.operand.dimensionName; - operand.objectName = dimConf.operand.objectName; - operand.items = Ext.clone(config.items); - - // Replace operand id characters - for (var i = 0, id; i < operand.items.length; i++) { - id = operand.items[i].id; - - if (id.indexOf('.') !== -1) { - id = id.replace('.', '-'); - operand.items[i].id = id; - } - } - - return operand; - }(); - }; - - api.DataSet = function(config) { - var dataSet = api.DimensionSuper(), - validateConfig; - - validateConfig = function() { - if (!Ext.isObject(config)) { - alert('Data set config is not an object'); - return; - } - - if (!Ext.isString(config.dimension)) { - alert('Data set dimension name is illegal'); - return; - } - - if (!Ext.isArray(config.items)) { - alert('Data set items is not an array'); - return; - } - - if (!config.items.length) { - alert('Data set has no items'); - return; - } - - return true; - }; - - return function() { - if (!validateConfig()) { - return; - } - - dataSet.dimension = config.dimension; - dataSet.dimensionName = dimConf.dataSet.dimensionName; - dataSet.objectName = dimConf.dataSet.objectName; - dataSet.items = Ext.clone(config.items); - - return dataSet; - }(); - }; - - api.Period = function(config) { - var period = api.DimensionSuper(), - validateConfig; - - validateConfig = function() { - if (!Ext.isObject(config)) { - alert('Period config is not an object'); - return; - } - - if (!Ext.isString(config.dimension)) { - alert('Period dimension name is illegal'); - return; - } - - if (!Ext.isArray(config.items)) { - alert('Period items is not an array'); - return; - } - - if (!config.items.length) { - alert('Period has no items'); - return; - } - - return true; - }; - - return function() { - if (!validateConfig()) { - return; - } - - period.dimension = config.dimension; - period.dimensionName = dimConf.period.dimensionName; - period.objectName = dimConf.period.objectName; - period.items = Ext.clone(config.items); - - return period; - }(); - }; - - api.OrganisationUnit = function(config) { - var organisationUnit = api.DimensionSuper(), - validateConfig; - - validateConfig = function() { - if (!Ext.isObject(config)) { - alert('Organisation unit config is not an object'); - return; - } - - if (!Ext.isString(config.dimension)) { - alert('Organisation unit dimension name is illegal'); - return; - } - - if (!Ext.isArray(config.items)) { - alert('Organisation unit items is not an array'); - return; - } - - if (!config.items.length) { - alert('Organisation unit has no items'); - return; - } - - return true; - }; - - return function() { - if (!validateConfig()) { - return; - } - - organisationUnit.dimension = config.dimension; - organisationUnit.dimensionName = dimConf.organisationUnit.dimensionName; - organisationUnit.objectName = dimConf.organisationUnit.objectName; - organisationUnit.items = Ext.clone(config.items); - - return organisationUnit; - }(); - }; - - api.Dimension = function(config) { - var dimension = api.DimensionSuper(), - validateConfig; - - validateConfig = function() { - if (!Ext.isObject(config)) { - alert('Dimension config is not an object'); - return; - } - - if (!Ext.isString(config.dimension)) { - alert('Dimension name is illegal'); - return; - } - - if (!Ext.isArray(config.items)) { - alert('Dimension items is not an array'); - return; - } - - if (!config.items.length) { - alert('Dimension has no items'); - return; - } - - return true; - }; - - return function() { - if (!validateConfig()) { - return; + layout: { + Record: null, + Dimension: null, + Layout: null + }, + response: { + Header: null, + Response: null + } + }; + + // 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 !== dv.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.dimensionName = config.dimension; - dimension.objectName = config.dimension; - dimension.items = Ext.clone(config.items); + dimension.items = config.items; - return dimension; + return Ext.clone(dimension); }(); }; - // Layout - - api.Layout = function(config) { - var layout = { - type: 'column', // string - - columns: null, // array of {dimension: , items: [{id, name, code}]} - - rows: null, // array of {dimension: , items: [{id, name, code}]} - - filters: null, // array of {dimension: , items: [{id, name, code}]} - - showTrendLine: false, // boolean - - targetLineValue: null, // number - - targetLineTitle: null, // string - - baseLineValue: null, // number - - baseLineTitle: null, // string - - showValues: true, // boolean - - hideLegend: false, // boolean - - hideTitle: false, // boolean - - title: null, // string - - domainAxisTitle: null, // string - - rangeAxisTitle: null, // string - - userOrganisationUnit: false, // boolean - - userOrganisationUnitChildren: false // boolean + api.layout.Layout = function(config) { + var layout = {}; + + // type: string ('column') - 'column', 'stackedColumn', 'bar', 'stackedBar', 'line', 'area', 'pie' + + // columns: [Dimension] + + // rows: [Dimension] + + // filters: [Dimension] + + // showTrendLine: boolean (false) + + // targetLineValue: number + + // targetLineTitle: string + + // baseLineValue: number + + // baseLineTitle: string + + // showValues: boolean (true) + + // hideLegend: boolean (false) + + // hideTitle: boolean (false) + + // domainAxisTitle: string + + // rangeAxisTitle: string + + // userOrganisationUnit: boolean (false) + + // userOrganisationUnitChildren: boolean (false) + + // parentGraphMap: object + + var 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; }; - var validateConfig = function() { - var validateAxis; - - validateAxis = function(axis) { - if (!(axis && Ext.isArray(axis) && axis.length)) { - return; - } - - return true; - }; - + return function() { + var a = [], + objectNames = [], + dimConf = dv.conf.finals.dimension; + + 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(dv.el + ': Layout config is not an object'); - return; - } - - if (!(validateAxis(config.columns))) { - alert(dv.el + ': Columns config is invalid'); - return; - } - if (!(validateAxis(config.rows))) { - alert(dv.el + ': Rows config is invalid'); - return; - } - if (!(validateAxis(config.filters))) { - alert(dv.el + ': Filters config is invalid'); - return; - } - - if (!Ext.isBoolean(config.showTrendLine)) { - config.showTrendLine = layout.showTrendLine; - } - if (!Ext.isNumber(config.targetLineValue)) { - delete config.targetLineValue; - } - if (!Ext.isString(config.targetLineTitle) || Ext.isEmpty(config.targetLineTitle)) { - delete config.targetLineTitle; - } - if (!Ext.isNumber(config.baseLineValue)) { - delete config.baseLineValue; - } - if (!Ext.isString(config.baseLineTitle) || Ext.isEmpty(config.baseLineTitle)) { - delete config.baseLineTitle; - } - if (!Ext.isBoolean(config.showValues)) { - config.showValues = layout.showValues; - } - if (!Ext.isBoolean(config.hideLegend)) { - config.hideLegend = layout.hideLegend; - } - if (!Ext.isBoolean(config.hideTitle)) { - config.hideTitle = layout.hideTitle; - } - if (!Ext.isString(config.title) || Ext.isEmpty(config.title)) { - delete config.title; - } - if (!Ext.isString(config.domainAxisTitle) || Ext.isEmpty(config.domainAxisTitle)) { - delete config.domainAxisTitle; - } - if (!Ext.isString(config.rangeAxisTitle) || Ext.isEmpty(config.rangeAxisTitle)) { - delete config.rangeAxisTitle; - } - if (!Ext.isBoolean(config.userOrganisationUnit)) { - config.userOrganisationUnit = layout.userOrganisationUnit; - } - if (!Ext.isBoolean(config.userOrganisationUnitChildren)) { - config.userOrganisationUnitChildren = layout.userOrganisationUnitChildren; - } - - return true; - }; - - return function() { - if (!validateConfig()) { - return; - } - - for (var key in config) { - if (config.hasOwnProperty(key)) { - layout[key] = config[key]; + console.log(dv.el + ': Layout config is not an object'); + return; + } + + // Series, category, filter + if (!config.columns) { + alert('No series dimension specified'); + return; + } + if (!config.rows) { + alert('No category dimension specified'); + return; + } + if (!config.filters) { + alert('No filter dimensions specified'); + return; + } + + // At least one period specified + a = [].concat(config.columns, config.rows, config.filters); + for (var i = 0; i < a.length; i++) { + if (a[i]) { + objectNames.push(a[i].dimension); } } - // Clint sync - if (Ext.isString(layout.targetLineLabel)) { - layout.targetLineTitle = layout.targetLineLabel; - delete layout.targetLineLabel; - } - if (Ext.isString(layout.baseLineLabel)) { - layout.baseLineTitle = layout.baseLineLabel; - delete layout.baseLineLabel; - } - if (Ext.isString(layout.domainAxisLabel)) { - layout.domainAxisTitle = layout.domainAxisLabel; - delete layout.domainAxisLabel; - } - if (Ext.isString(layout.rangeAxisLabel)) { - layout.rangeAxisTitle = layout.rangeAxisLabel; - delete layout.rangeAxisLabel; - } - if (Ext.isBoolean(layout.regression)) { - layout.showTrendLine = layout.regression; - delete layout.regression; - } - if (Ext.isBoolean(layout.showData)) { - layout.showValues = layout.showData; - delete layout.showData; - } + if (!Ext.Array.contains(objectNames, dimConf.period.objectName)) { + alert('At least one period must be specified as series, category or filter'); + return; + } + + // Layout + layout.type = config.type; + + layout.columns = config.columns; + layout.rows = config.rows; + layout.filters = config.filters; + + // Properties + layout.showTrendLine = Ext.isBoolean(config.regression) ? config.regression : (Ext.isBoolean(config.showTrendLine) ? config.showTrendLine : false); + layout.showValues = Ext.isBoolean(config.showData) ? config.showData : (Ext.isBoolean(config.showValues) ? config.showValues : true); + + layout.hideLegend = Ext.isBoolean(config.hideLegend) ? config.hideLegend : false; + layout.hideTitle = Ext.isBoolean(config.hideTitle) ? config.hideTitle : false; + + layout.targetLineValue = Ext.isNumber(config.targetLineValue) ? config.targetLineValue : undefined; + layout.targetLineTitle = Ext.isString(config.targetLineLabel) && !Ext.isEmpty(config.targetLineLabel) ? config.targetLineLabel : + (Ext.isString(config.targetLineTitle) && !Ext.isEmpty(config.targetLineTitle) ? config.targetLineTitle : undefined); + layout.baseLineValue = Ext.isNumber(config.baseLineValue) ? config.baseLineValue : undefined; + layout.baseLineTitle = Ext.isString(config.baseLineLabel) && !Ext.isEmpty(config.baseLineLabel) ? config.baseLineLabel : + (Ext.isString(config.baseLineTitle) && !Ext.isEmpty(config.baseLineTitle) ? config.baseLineTitle : undefined); + + layout.title = Ext.isString(config.title) && !Ext.isEmpty(config.title) ? config.title : undefined; + layout.domainAxisTitle = Ext.isString(config.domainAxisLabel) && !Ext.isEmpty(config.domainAxisLabel) ? config.domainAxisLabel : + (Ext.isString(config.domainAxisTitle) && !Ext.isEmpty(config.domainAxisTitle) ? config.domainAxisTitle : undefined); + layout.rangeAxisTitle = Ext.isString(config.rangeAxisLabel) && !Ext.isEmpty(config.rangeAxisLabel) ? config.rangeAxisLabel : + (Ext.isString(config.rangeAxisTitle) && !Ext.isEmpty(config.rangeAxisTitle) ? config.rangeAxisTitle : undefined); + + layout.userOrganisationUnit = Ext.isBoolean(config.userOrganisationUnit) ? config.userOrganisationUnit : false; + layout.userOrganisationUnitChildren = Ext.isBoolean(config.userOrganisationUnitChildren) ? config.userOrganisationUnitChildren : false; + + layout.parentGraphMap = Ext.isObject(config.parentGraphMap) ? config.parentGraphMap : undefined; return Ext.clone(layout); }(); }; - api.objectNameDimensionClassMap[dimConf.indicator.objectName] = api.Indicator; - api.objectNameDimensionClassMap[dimConf.dataElement.objectName] = api.DataElement; - api.objectNameDimensionClassMap[dimConf.operand.objectName] = api.Operand; - api.objectNameDimensionClassMap[dimConf.dataSet.objectName] = api.DataSet; - api.objectNameDimensionClassMap[dimConf.period.objectName] = api.Period; - api.objectNameDimensionClassMap[dimConf.organisationUnit.objectName] = api.OrganisationUnit; + // 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; + }(); + }; return api; }; === modified file 'dhis-2/dhis-web/dhis-web-visualizer/src/main/webapp/dhis-web-visualizer/i18n.vm' --- dhis-2/dhis-web/dhis-web-visualizer/src/main/webapp/dhis-web-visualizer/i18n.vm 2013-05-13 14:00:23 +0000 +++ dhis-2/dhis-web/dhis-web-visualizer/src/main/webapp/dhis-web-visualizer/i18n.vm 2013-05-23 16:34:57 +0000 @@ -190,5 +190,6 @@ can_view: '$encoder.jsEscape($i18n.getString( 'can_view' ) , "'")', can_edit_and_view: '$encoder.jsEscape($i18n.getString( 'can_edit_and_view' ) , "'")', search_for_user_groups: '$encoder.jsEscape($i18n.getString( 'search_for_user_groups' ) , "'")', - public_access: '$encoder.jsEscape($i18n.getString( 'public_access' ) , "'")' + public_access: '$encoder.jsEscape($i18n.getString( 'public_access' ) , "'")', + detailed_data_elements_cannot_be_specified_as_filter: '$encoder.jsEscape($i18n.getString( 'detailed_data_elements_cannot_be_specified_as_filter' ) , "'")' };