dhis2-devs team mailing list archive
-
dhis2-devs team
-
Mailing list archive
-
Message #13725
[Branch ~dhis2-devs-core/dhis2/trunk] Rev 4478: Reverted r4476
------------------------------------------------------------
revno: 4478
committer: Lars Helge Overland <larshelge@xxxxxxxxx>
branch nick: dhis2
timestamp: Mon 2011-08-29 21:28:09 +0200
message:
Reverted r4476
modified:
dhis-2/dhis-web/dhis-web-dataentry/src/main/webapp/dhis-web-dataentry/javascript/form.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
=== modified file 'dhis-2/dhis-web/dhis-web-dataentry/src/main/webapp/dhis-web-dataentry/javascript/form.js'
--- dhis-2/dhis-web/dhis-web-dataentry/src/main/webapp/dhis-web-dataentry/javascript/form.js 2011-08-29 08:32:52 +0000
+++ dhis-2/dhis-web/dhis-web-dataentry/src/main/webapp/dhis-web-dataentry/javascript/form.js 2011-08-29 19:28:09 +0000
@@ -1,1528 +1,1522 @@
-// Identifiers for which zero values are insignificant, also used in entry.js
-var significantZeros = [];
-
-// Array with associative arrays for each data element, populated in select.vm
-var dataElements = [];
-
-// Associative array with [indicator id, expression] for indicators in form,
-// also used in entry.js
-var indicatorFormulas = [];
-
-// Array with associative arrays for each data set, populated in select.vm
-var dataSets = [];
-
-// Associative array with identifier and array of assigned data sets
-var dataSetAssociationSets = [];
-
-// Associate array with mapping between organisation unit identifier and data
-// set association set identifier
-var organisationUnitAssociationSetMap = [];
-
-// Array with keys on form {dataelementid}-{optioncomboid}-min/max with min/max
-// values
-var currentMinMaxValueMap = [];
-
-// Indicates whether any data entry form has been loaded
-var dataEntryFormIsLoaded = false;
-
-// Indicates whether meta data is loaded
-var metaDataIsLoaded = false;
-
-// Currently selected organisation unit identifier
-var currentOrganisationUnitId = null;
-
-// Currently selected data set identifier
-var currentDataSetId = null;
-
-// Current offset, next or previous corresponding to increasing or decreasing
-// value with one
-var currentPeriodOffset = 0;
-
-// Period type object
-var periodTypeFactory = new PeriodType();
-
-// Instance of the StorageManager
-var storageManager = new StorageManager();
-
-var COLOR_GREEN = '#b9ffb9';
-var COLOR_YELLOW = '#fffe8c';
-var COLOR_RED = '#ff8a8a';
-var COLOR_ORANGE = '#ff6600';
-var COLOR_WHITE = '#ffffff';
-var COLOR_GREY = '#cccccc';
-
-var DEFAULT_TYPE = 'int';
-var DEFAULT_NAME = '[unknown]';
-
-var FORMTYPE_CUSTOM = 'custom';
-var FORMTYPE_SECTION = 'section';
-var FORMTYPE_DEFAULT = 'default';
-
-/**
- * Page init. The order of events is:
- *
- * 1. Load ouwt 2. Load meta-data (and notify ouwt) 3. Check and potentially
- * download updated forms from server
- */
-$( document ).ready( function()
-{
- $.ajaxSetup({
- type: 'POST'
- });
-
- selection.setListenerFunction( organisationUnitSelected );
- $( '#loaderSpan' ).show();
-
- $( '#orgUnitTree' ).one( 'ouwtLoaded', function()
- {
- log( 'Ouwt loaded' );
- loadMetaData();
- } );
-
- $( document ).bind( 'dhis2.online', function( event, loggedIn )
- {
- if ( loggedIn )
- {
- if ( storageManager.hasLocalData() )
- {
- var message = i18n_need_to_sync_notification
- + ' <button id="sync_button" type="button">' + i18n_sync_now
- + '</button>';
-
- setHeaderMessage( message );
-
- $( '#sync_button' ).bind( 'click', uploadLocalData );
- }
- else
- {
- setHeaderDelayMessage( i18n_online_notification );
- }
- }
- else
- {
- setHeaderMessage( '<form style="display:inline;"><label for="username">Username</label><input name="username" id="username" type="text" size="10"/><label for="password">Password</label><input name="password" id="password" type="password" size="10"/><button id="login_button" type="button">Login</button></form>' );
- ajax_login();
- }
- } );
-
- $( document ).bind( 'dhis2.offline', function()
- {
- setHeaderMessage( i18n_offline_notification );
- } );
-
- dhis2.availability.startAvailabilityCheck();
-} );
-
-function ajax_login()
-{
- $( '#login_button' ).bind( 'click', function()
- {
- var username = $( '#username' ).val();
- var password = $( '#password' ).val();
-
- $.post( '../dhis-web-commons-security/login.action', {
- 'j_username' : username,
- 'j_password' : password
- } ).success( function()
- {
- var ret = dhis2.availability.syncCheckAvailability();
-
- if ( !ret )
- {
- alert( i18n_ajax_login_failed );
- }
- } );
- } );
-}
-
-function loadMetaData()
-{
- var KEY_METADATA = 'metadata';
-
- $.ajax( {
- url: 'getMetaData.action',
- cache: false,
- dataType: 'json',
- success: function( json )
- {
- sessionStorage[KEY_METADATA] = JSON.stringify( json.metaData );
- },
- complete: function()
- {
- var metaData = JSON.parse( sessionStorage[KEY_METADATA] );
-
- significantZeros = metaData.significantZeros;
- dataElements = metaData.dataElements;
- indicatorFormulas = metaData.indicatorFormulas;
- dataSets = metaData.dataSets;
- dataSetAssociationSets = metaData.dataSetAssociationSets;
- organisationUnitAssociationSetMap = metaData.organisationUnitAssociationSetMap;
-
- metaDataIsLoaded = true;
- selection.responseReceived(); // Notify that meta data is loaded
- $( '#loaderSpan' ).hide();
- log( 'Meta-data loaded' );
-
- updateForms();
- }
- } );
-}
-
-function uploadLocalData()
-{
- if ( !storageManager.hasLocalData() )
- {
- return;
- }
-
- var dataValues = storageManager.getAllDataValues();
- var completeDataSets = storageManager.getCompleteDataSets();
-
- setHeaderWaitMessage( i18n_uploading_data_notification );
-
- var dataValuesArray = dataValues ? Object.keys( dataValues ) : [];
- var completeDataSetsArray = completeDataSets ? Object.keys( completeDataSets ) : [];
-
- function pushCompleteDataSets( array )
- {
- if ( array.length < 1 )
- {
- return;
- }
-
- var key = array[0];
- var value = completeDataSets[key];
-
- log( 'Uploaded complete data set: ' + key + ', with value: ' + value );
-
- $.ajax( {
- url: 'registerCompleteDataSet.action',
- data: value,
- dataType: 'json',
- cache: false,
- success: function( data, textStatus, jqXHR )
- {
- log( 'Successfully saved complete dataset with value: ' + value );
- storageManager.clearCompleteDataSet( value );
- ( array = array.slice( 1 ) ).length && pushCompleteDataSets( array );
-
- if ( array.length < 1 )
- {
- setHeaderDelayMessage( i18n_sync_success );
- }
- },
- error: function( jqXHR, textStatus, errorThrown )
- {
- var message = i18n_sync_failed
- + ' <button id="sync_button" type="button">' + i18n_sync_now
- + '</button>';
-
- setHeaderMessage( message );
-
- $( '#sync_button' ).bind( 'click', uploadLocalData );
- }
- } );
- };
-
- ( function pushDataValues( array )
- {
- if ( array.length < 1 )
- {
- setHeaderDelayMessage( i18n_online_notification );
-
- pushCompleteDataSets( completeDataSetsArray );
-
- return;
- }
-
- var key = array[0];
- var value = dataValues[key];
-
- log( 'Uploaded data value: ' + key + ', with value: ' + value );
-
- $.ajax( {
- url: 'saveValue.action',
- data: value,
- dataType: 'json',
- cache: false,
- success: function( data, textStatus, jqXHR )
- {
- storageManager.clearDataValueJSON( value );
- log( 'Successfully saved data value with value: ' + value );
- ( array = array.slice( 1 ) ).length && pushDataValues( array );
-
- if ( array.length < 1 && completeDataSetsArray.length > 0 )
- {
- pushCompleteDataSets( completeDataSetsArray );
- }
- else
- {
- setHeaderDelayMessage( i18n_sync_success );
- }
- },
- error: function( jqXHR, textStatus, errorThrown )
- {
- var message = i18n_sync_failed
- + ' <button id="sync_button" type="button">' + i18n_sync_now
- + '</button>';
-
- setHeaderMessage( message );
-
- $( '#sync_button' ).bind( 'click', uploadLocalData );
- }
- } );
- } )( dataValuesArray );
-}
-
-function addEventListeners()
-{
- var dataSetId = $( '#selectedDataSetId' ).val();
- var formType = dataSets[dataSetId].type;
-
- $( '[name="entryfield"]' ).each( function( i )
- {
- var id = $( this ).attr( 'id' );
- var dataElementId = id.split( '-' )[0];
- var optionComboId = id.split( '-' )[1];
- var type = getDataElementType( dataElementId );
-
- $( this ).unbind( 'focus' );
- $( this ).unbind( 'blur' );
- $( this ).unbind( 'change' );
- $( this ).unbind( 'dblclick' );
- $( this ).unbind( 'keyup' );
-
- $( this ).focus( valueFocus );
-
- $( this ).blur( valueBlur );
-
- $( this ).change( function()
- {
- saveVal( dataElementId, optionComboId );
- } );
-
- $( this ).dblclick( function()
- {
- viewHist( dataElementId, optionComboId );
- } );
-
- $( this ).keyup( function(event)
- {
- keyPress( event, this );
- } );
-
- if ( formType != FORMTYPE_CUSTOM )
- {
- $( this ).css( 'width', '100%' );
- $( this ).css( 'text-align', 'center' );
- }
-
- if ( type == 'date' )
- {
- $( this ).css( 'width', '80%' );
- datePicker( id );
- }
- } );
-
- $( '[name="entryselect"]' ).each( function( i )
- {
- var id = $( this ).attr( 'id' );
- var dataElementId = id.split( '-' )[0];
- var optionComboId = id.split( '-' )[1];
-
- $( this ).unbind( 'focus' );
- $( this ).unbind( 'change' );
-
- $( this ).focus( valueFocus );
-
- $( this ).change( function()
- {
- saveBoolean( dataElementId, optionComboId );
- } );
-
- $( this ).css( 'width', '100%' );
- } );
-}
-
-function clearPeriod()
-{
- clearListById( 'selectedPeriodId' );
- clearEntryForm();
-}
-
-function clearEntryForm()
-{
- $( '#contentDiv' ).html( '' );
-
- currentPeriodOffset = 0;
-
- dataEntryFormIsLoaded = false;
-
- $( '#completenessDiv' ).css( 'display', 'none' );
-}
-
-function loadForm( dataSetId )
-{
- if ( storageManager.formExists( dataSetId ) )
- {
- log( 'Loading form locally: ' + dataSetId );
-
- var html = storageManager.getForm( dataSetId );
-
- $( '#contentDiv' ).html( html );
-
- loadDataValues();
- }
- else
- {
- log( 'Loading form remotely: ' + dataSetId );
-
- $( '#contentDiv' ).load( 'loadForm.action', {
- dataSetId : dataSetId
- }, loadDataValues );
- }
-}
-
-function getDataElementType( dataElementId )
-{
- if ( dataElements[dataElementId] != null )
- {
- return dataElements[dataElementId].type;
- }
-
- log( 'Data element not present in data set, falling back to default type: ' + dataElementId );
- return DEFAULT_TYPE;
-}
-
-function getDataElementName( dataElementId )
-{
- if ( dataElements[dataElementId] != null )
- {
- return dataElements[dataElementId].name;
- }
-
- log( 'Data element present in data set, falling back to default name: ' + dataElementId );
- return DEFAULT_NAME;
-}
-
-// ----------------------------------------------------------------------------
-// OrganisationUnit Selection
-// -----------------------------------------------------------------------------
-
-/**
- * Returns an array containing associative array elements with id and name
- * properties. The array is sorted on the element name property.
- */
-function getSortedDataSetList()
-{
- var associationSet = organisationUnitAssociationSetMap[currentOrganisationUnitId];
- var orgUnitDataSets = dataSetAssociationSets[associationSet];
-
- var dataSetList = [];
-
- for ( i in orgUnitDataSets )
- {
- var dataSetId = orgUnitDataSets[i];
- var dataSetName = dataSets[dataSetId].name;
-
- var row = [];
- row['id'] = dataSetId;
- row['name'] = dataSetName;
- dataSetList[i] = row;
- }
-
- dataSetList.sort( function( a, b )
- {
- return a.name > b.name ? 1 : a.name < b.name ? -1 : 0;
- } );
-
- return dataSetList;
-}
-
-function organisationUnitSelected( orgUnits, orgUnitNames )
-{
- if ( metaDataIsLoaded == false )
- {
- return false;
- }
-
- currentOrganisationUnitId = orgUnits[0];
- var organisationUnitName = orgUnitNames[0];
-
- $( '#selectedOrganisationUnit' ).val( organisationUnitName );
- $( '#currentOrganisationUnit' ).html( organisationUnitName );
-
- var dataSetList = getSortedDataSetList();
-
- $( '#selectedDataSetId' ).removeAttr( 'disabled' );
-
- var dataSetId = $( '#selectedDataSetId' ).val();
- var periodId = $( '#selectedPeriodId' ).val();
-
- clearListById( 'selectedDataSetId' );
- addOptionById( 'selectedDataSetId', '-1', '[ ' + i18n_select_data_set + ' ]' );
-
- var dataSetValid = false;
-
- for ( i in dataSetList )
- {
- addOptionById( 'selectedDataSetId', dataSetList[i].id, dataSetList[i].name );
-
- if ( dataSetId == dataSetList[i].id )
- {
- dataSetValid = true;
- }
- }
-
- if ( dataSetValid && dataSetId != null )
- {
- $( '#selectedDataSetId' ).val( dataSetId );
-
- if ( periodId && periodId != -1 && dataEntryFormIsLoaded )
- {
- showLoader();
- loadDataValues();
- }
- }
- else
- {
- clearPeriod();
- }
-}
-
-// -----------------------------------------------------------------------------
-// Next/Previous Periods Selection
-// -----------------------------------------------------------------------------
-
-function nextPeriodsSelected()
-{
- if ( currentPeriodOffset < 0 ) // Cannot display future periods
- {
- currentPeriodOffset++;
- displayPeriodsInternal();
- }
-}
-
-function previousPeriodsSelected()
-{
- currentPeriodOffset--;
- displayPeriodsInternal();
-}
-
-function displayPeriodsInternal()
-{
- var dataSetId = $( '#selectedDataSetId' ).val();
- var periodType = dataSets[dataSetId].periodType;
- var periods = periodTypeFactory.get( periodType ).generatePeriods( currentPeriodOffset );
- periods = periodTypeFactory.filterFuturePeriods( periods );
-
- clearListById( 'selectedPeriodId' );
-
- addOptionById( 'selectedPeriodId', '-1', '[ ' + i18n_select_period + ' ]' );
-
- for ( i in periods )
- {
- addOptionById( 'selectedPeriodId', periods[i].id, periods[i].name );
- }
-}
-
-// -----------------------------------------------------------------------------
-// DataSet Selection
-// -----------------------------------------------------------------------------
-
-function dataSetSelected()
-{
- $( '#selectedPeriodId' ).removeAttr( 'disabled' );
- $( '#prevButton' ).removeAttr( 'disabled' );
- $( '#nextButton' ).removeAttr( 'disabled' );
-
- var dataSetId = $( '#selectedDataSetId' ).val();
- var periodId = $( '#selectedPeriodId' ).val();
- var periodType = dataSets[dataSetId].periodType;
- var periods = periodTypeFactory.get( periodType ).generatePeriods( currentPeriodOffset );
- periods = periodTypeFactory.filterFuturePeriods( periods );
-
- if ( dataSetId && dataSetId != -1 )
- {
- clearListById( 'selectedPeriodId' );
-
- addOptionById( 'selectedPeriodId', '-1', '[ ' + i18n_select_period + ' ]' );
-
- for ( i in periods )
- {
- addOptionById( 'selectedPeriodId', periods[i].id, periods[i].name );
- }
-
- var previousPeriodType = currentDataSetId ? dataSets[currentDataSetId].periodType : null;
-
- if ( periodId && periodId != -1 && previousPeriodType && previousPeriodType == periodType )
- {
- showLoader();
- $( '#selectedPeriodId' ).val( periodId );
- loadForm( dataSetId );
- }
- else
- {
- clearEntryForm();
- }
-
- currentDataSetId = dataSetId;
- }
-}
-
-// -----------------------------------------------------------------------------
-// Period Selection
-// -----------------------------------------------------------------------------
-
-function periodSelected()
-{
- var periodName = $( '#selectedPeriodId :selected' ).text();
- var dataSetId = $( '#selectedDataSetId' ).val();
-
- $( '#currentPeriod' ).html( periodName );
-
- var periodId = $( '#selectedPeriodId' ).val();
-
- if ( periodId && periodId != -1 )
- {
- showLoader();
-
- if ( dataEntryFormIsLoaded )
- {
- loadDataValues();
- }
- else
- {
- loadForm( dataSetId );
- }
- }
-}
-
-// -----------------------------------------------------------------------------
-// Form
-// -----------------------------------------------------------------------------
-
-function loadDataValues()
-{
- $( '#completeButton' ).removeAttr( 'disabled' );
- $( '#undoButton' ).attr( 'disabled', 'disabled' );
-
- insertDataValues();
- displayEntryFormCompleted();
-}
-
-function insertDataValues()
-{
- var dataValueMap = [];
- currentMinMaxValueMap = []; // Reset
-
- var periodId = $( '#selectedPeriodId' ).val();
- var dataSetId = $( '#selectedDataSetId' ).val();
-
- // Clear existing values and colors, grey disabled fields
-
- $( '[name="entryfield"]' ).val( '' );
- $( '[name="entryselect"]' ).val( '' );
-
- $( '[name="entryfield"]' ).css( 'background-color', COLOR_WHITE );
- $( '[name="entryselect"]' ).css( 'background-color', COLOR_WHITE );
-
- $( '[name="min"]' ).html( '' );
- $( '[name="max"]' ).html( '' );
-
- $( '[name="entryfield"]' ).filter( ':disabled' ).css( 'background-color', COLOR_GREY );
-
- $.ajax( {
- url: 'getDataValues.action',
- data:
- {
- periodId : periodId,
- dataSetId : dataSetId,
- organisationUnitId : currentOrganisationUnitId
- },
- cache: false,
- dataType: 'json',
- success: function( json )
- {
- // Set data values, works for select lists too as data
- // value = select value
-
- $.each( json.dataValues, function( i, value )
- {
- var fieldId = '#' + value.id + '-val';
-
- if ( $( fieldId ) )
- {
- $( fieldId ).val( value.val );
- }
-
- dataValueMap[value.id] = value.val;
- } );
-
- // Set min-max values and colorize violation fields
-
- $.each( json.minMaxDataElements, function( i, value )
- {
- var minId = value.id + '-min';
- var maxId = value.id + '-max';
-
- var valFieldId = '#' + value.id + '-val';
-
- var dataValue = dataValueMap[value.id];
-
- if ( dataValue && ( ( value.min && new Number( dataValue ) < new Number(
- value.min ) ) || ( value.max && new Number( dataValue ) > new Number( value.max ) ) ) )
- {
- $( valFieldId ).css( 'background-color', COLOR_ORANGE );
- }
-
- currentMinMaxValueMap[minId] = value.min;
- currentMinMaxValueMap[maxId] = value.max;
- } );
-
- // Update indicator values in form
-
- updateIndicators();
-
- // Set completeness button
-
- if ( json.complete )
- {
- $( '#completeButton' ).attr( 'disabled', 'disabled' );
- $( '#undoButton' ).removeAttr( 'disabled' );
- }
- else
- {
- $( '#completeButton' ).removeAttr( 'disabled' );
- $( '#undoButton' ).attr( 'disabled', 'disabled' );
- }
-
- // TODO locking
- }
- } );
-}
-
-function displayEntryFormCompleted()
-{
- addEventListeners();
-
- $( '#validationButton' ).removeAttr( 'disabled' );
- $( '#defaultForm' ).removeAttr( 'disabled' );
-
- dataEntryFormIsLoaded = true;
- hideLoader();
-
- $( '#completenessDiv' ).css( 'display', 'block' );
-}
-
-function valueFocus( e )
-{
- var id = e.target.id;
-
- var dataElementId = id.split( '-' )[0];
- var optionComboId = id.split( '-' )[1];
-
- var dataElementName = getDataElementName( dataElementId );
- var optionComboName = $( '#' + optionComboId + '-optioncombo' ).text();
-
- $( '#currentDataElement' ).html( dataElementName + ' ' + optionComboName );
-
- $( '#' + dataElementId + '-cell' ).addClass( 'currentRow' );
-}
-
-function valueBlur( e )
-{
- var id = e.target.id;
-
- var dataElementId = id.split( '-' )[0];
-
- $( '#' + dataElementId + '-cell' ).removeClass( 'currentRow' );
-}
-
-function keyPress( event, field )
-{
- var key = event.keyCoe || event.charCode || event.which;
-
- var focusField = ( key == 13 || key == 40 ) ? getNextEntryField( field )
- : ( key == 38 ) ? getPreviousEntryField( field ) : false;
-
- if ( focusField )
- {
- focusField.focus();
- }
-}
-
-function getNextEntryField( field )
-{
- var index = field.getAttribute( 'tabindex' );
-
- field = $( 'input[name="entryfield"][tabindex="' + ( ++index ) + '"]' );
-
- while ( field )
- {
- if ( field.is( ':disabled' ) || field.is( ':hidden' ) )
- {
- field = $( 'input[name="entryfield"][tabindex="' + ( ++index ) + '"]' );
- }
- else
- {
- return field;
- }
- }
-}
-
-function getPreviousEntryField( field )
-{
- var index = field.getAttribute( 'tabindex' );
-
- field = $( 'input[name="entryfield"][tabindex="' + ( --index ) + '"]' );
-
- while ( field )
- {
- if ( field.is( ':disabled' ) || field.is( ':hidden' ) )
- {
- field = $( 'input[name="entryfield"][tabindex="' + ( --index ) + '"]' );
- }
- else
- {
- return field;
- }
- }
-}
-
-// -----------------------------------------------------------------------------
-// Data completeness
-// -----------------------------------------------------------------------------
-
-function validateCompleteDataSet()
-{
- var confirmed = confirm( i18n_confirm_complete );
-
- if ( confirmed )
- {
- var params = storageManager.getCurrentCompleteDataSetParams();
-
- disableCompleteButton();
-
- $.ajax( { url: 'getValidationViolations.action',
- cache: false,
- data: params,
- dataType: 'json',
- success: function( data )
- {
- registerCompleteDataSet( data );
- },
- error: function()
- {
- // no response from server, fake a positive result and save it
- registerCompleteDataSet( { 'response' : 'success' } );
- }
- } );
- }
-}
-
-function registerCompleteDataSet( json )
-{
- var params = storageManager.getCurrentCompleteDataSetParams();
-
- if ( json.response == 'success' )
- {
- storageManager.saveCompleteDataSet( params );
-
- $.ajax( {
- url: 'registerCompleteDataSet.action',
- data: params,
- cache: false,
- success: function()
- {
- storageManager.clearCompleteDataSet( params );
- }
- } );
- }
- else
- {
- disableUndoButton();
-
- validate();
- }
-}
-
-function undoCompleteDataSet()
-{
- var confirmed = confirm( i18n_confirm_undo );
- var params = storageManager.getCurrentCompleteDataSetParams();
-
- if ( confirmed )
- {
- disableUndoButton();
-
- $.ajax( {
- url: 'undoCompleteDataSet.action',
- data: params,
- cache: false,
- success: function()
- {
- storageManager.clearCompleteDataSet( params );
- },
- error: function()
- {
- storageManager.clearCompleteDataSet( params );
- }
- } );
- }
-}
-
-function disableUndoButton()
-{
- $( '#completeButton' ).removeAttr( 'disabled' );
- $( '#undoButton' ).attr( 'disabled', 'disabled' );
-}
-
-function disableCompleteButton()
-{
- $( '#completeButton' ).attr( 'disabled', 'disabled' );
- $( '#undoButton' ).removeAttr( 'disabled' );
-}
-
-// -----------------------------------------------------------------------------
-// Validation
-// -----------------------------------------------------------------------------
-
-function displayValidationDialog()
-{
- $( '#validationDiv' ).dialog( {
- modal : true,
- title : 'Validation',
- width : 800,
- height : 400
- } );
-}
-
-function validate()
-{
- var periodId = $( '#selectedPeriodId' ).val();
- var dataSetId = $( '#selectedDataSetId' ).val();
-
- $( '#validationDiv' ).load( 'validate.action', {
- periodId : periodId,
- dataSetId : dataSetId,
- organisationUnitId : currentOrganisationUnitId
- }, function( response, status, xhr )
- {
- if ( status == 'error' )
- {
- window.alert( i18n_operation_not_available_offline );
- }
- else
- {
- displayValidationDialog();
- }
- } );
-}
-
-// -----------------------------------------------------------------------------
-// History
-// -----------------------------------------------------------------------------
-
-function displayHistoryDialog( operandName )
-{
- $( '#historyDiv' ).dialog( {
- modal : true,
- title : operandName,
- width : 580,
- height : 710
- } );
-}
-
-function viewHist( dataElementId, optionComboId )
-{
- var periodId = $( '#selectedPeriodId' ).val();
-
- var dataElementName = getDataElementName( dataElementId );
- var optionComboName = $( '#' + optionComboId + '-optioncombo' ).html();
- var operandName = dataElementName + ' ' + optionComboName;
-
- $( '#historyDiv' ).load( 'viewHistory.action', {
- dataElementId : dataElementId,
- optionComboId : optionComboId,
- periodId : periodId,
- organisationUnitId : currentOrganisationUnitId
- }, function( response, status, xhr )
- {
- if ( status == 'error' )
- {
- window.alert( i18n_operation_not_available_offline );
- }
- else
- {
- displayHistoryDialog( operandName );
- }
- } );
-}
-
-function closeCurrentSelection()
-{
- $( '#currentSelection' ).fadeOut();
-}
-
-// -----------------------------------------------------------------------------
-// Local storage of forms
-// -----------------------------------------------------------------------------
-
-function updateForms()
-{
- purgeLocalForms();
- updateExistingLocalForms();
- downloadRemoteForms();
-}
-
-function purgeLocalForms()
-{
- var formIds = storageManager.getAllForms();
-
- for ( i in formIds )
- {
- var localId = formIds[i];
-
- if ( dataSets[localId] == null )
- {
- storageManager.deleteForm( localId );
- storageManager.deleteFormVersion( localId );
- log( 'Deleted locally stored form: ' + localId );
- }
- }
-
- log( 'Purged local forms' );
-}
-
-function updateExistingLocalForms()
-{
- var formIds = storageManager.getAllForms();
- var formVersions = storageManager.getAllFormVersions();
-
- for ( i in formIds )
- {
- var localId = formIds[i];
-
- var remoteVersion = dataSets[localId].version;
- var localVersion = formVersions[localId];
-
- if ( remoteVersion == null || localVersion == null || remoteVersion != localVersion )
- {
- storageManager.downloadForm( localId, remoteVersion );
- }
- }
-}
-
-function downloadRemoteForms()
-{
- for ( dataSetId in dataSets )
- {
- var remoteVersion = dataSets[dataSetId].version;
-
- if ( !storageManager.formExists( dataSetId ) )
- {
- storageManager.downloadForm( dataSetId, remoteVersion );
- }
- }
-}
-
-// TODO break if local storage is full
-
-// -----------------------------------------------------------------------------
-// StorageManager
-// -----------------------------------------------------------------------------
-
-/**
- * This object provides utility methods for localStorage and manages data entry
- * forms and data values.
- */
-function StorageManager()
-{
- var MAX_SIZE = new Number( 2600000 );
- var MAX_SIZE_FORMS = new Number( 1600000 );
-
- var KEY_FORM_PREFIX = 'form-';
- var KEY_FORM_VERSIONS = 'formversions';
- var KEY_DATAVALUES = 'datavalues';
- var KEY_COMPLETEDATASETS = 'completedatasets';
-
- /**
- * Returns the total number of characters currently in the local storage.
- *
- * @return number of characters.
- */
- this.totalSize = function()
- {
- var totalSize = new Number();
-
- for ( var i = 0; i < localStorage.length; i++ )
- {
- var value = localStorage.key( i );
-
- if ( value )
- {
- totalSize += value.length;
- }
- }
-
- return totalSize;
- };
-
- /**
- * Returns the total numbers of characters in stored forms currently in the
- * local storage.
- *
- * @return number of characters.
- */
- this.totalFormSize = function()
- {
- var totalSize = new Number();
-
- for ( var i = 0; i < localStorage.length; i++ )
- {
- if ( localStorage.key( i ).substring( 0, KEY_FORM_PREFIX.length ) == KEY_FORM_PREFIX )
- {
- var value = localStorage.key( i );
-
- if ( value )
- {
- totalSize += value.length;
- }
- }
- }
-
- return totalSize;
- };
-
- /**
- * Return the remaining capacity of the local storage in characters, ie. the
- * maximum size minus the current size.
- */
- this.remainingStorage = function()
- {
- return MAX_SIZE - this.totalSize();
- };
-
- /**
- * Saves the content of a data entry form.
- *
- * @param dataSetId the identifier of the data set of the form.
- * @param html the form HTML content.
- * @return true if the form saved successfully, false otherwise.
- */
- this.saveForm = function( dataSetId, html )
- {
- var id = KEY_FORM_PREFIX + dataSetId;
-
- try
- {
- localStorage[id] = html;
-
- log( 'Successfully stored form: ' + dataSetId );
- } catch ( e )
- {
- log( 'Max local storage quota reached, ignored form: ' + dataSetId );
- return false;
- }
-
- if ( MAX_SIZE_FORMS < this.totalFormSize() )
- {
- this.deleteForm( dataSetId );
-
- log( 'Max local storage quota for forms reached, ignored form: ' + dataSetId );
- return false;
- }
-
- return true;
- };
-
- /**
- * Gets the content of a data entry form.
- *
- * @param dataSetId the identifier of the data set of the form.
- * @return the content of a data entry form.
- */
- this.getForm = function( dataSetId )
- {
- var id = KEY_FORM_PREFIX + dataSetId;
-
- return localStorage[id];
- };
-
- /**
- * Removes a form.
- *
- * @param dataSetId the identifier of the data set of the form.
- */
- this.deleteForm = function( dataSetId )
- {
- var id = KEY_FORM_PREFIX + dataSetId;
-
- localStorage.removeItem( id );
- };
-
- /**
- * Returns an array of the identifiers of all forms.
- *
- * @return array with form identifiers.
- */
- this.getAllForms = function()
- {
- var formIds = [];
-
- var formIndex = 0;
-
- for ( var i = 0; i < localStorage.length; i++ )
- {
- var key = localStorage.key( i );
-
- if ( key.substring( 0, KEY_FORM_PREFIX.length ) == KEY_FORM_PREFIX )
- {
- var id = key.split( '-' )[1];
-
- formIds[formIndex++] = id;
- }
- }
-
- return formIds;
- };
-
- /**
- * Indicates whether a form exists.
- *
- * @param dataSetId the identifier of the data set of the form.
- * @return true if a form exists, false otherwise.
- */
- this.formExists = function( dataSetId )
- {
- var id = KEY_FORM_PREFIX + dataSetId;
-
- return localStorage[id] != null;
- };
-
- /**
- * Downloads the form for the data set with the given identifier from the
- * remote server and saves the form locally. Potential existing forms with
- * the same identifier will be overwritten. Updates the form version.
- *
- * @param dataSetId the identifier of the data set of the form.
- * @param formVersion the version of the form of the remote data set.
- */
- this.downloadForm = function( dataSetId, formVersion )
- {
- $.ajax( {
- url: 'loadForm.action',
- data:
- {
- dataSetId : dataSetId
- },
- dataSetId: dataSetId,
- formVersion: formVersion,
- cache: false,
- dataType: 'text',
- success: function( data, textStatus, jqXHR )
- {
- storageManager.saveForm( this.dataSetId, data );
- storageManager.saveFormVersion( this.dataSetId, this.formVersion );
- }
- } );
- };
-
- /**
- * Saves a version for a form.
- *
- * @param the identifier of the data set of the form.
- * @param formVersion the version of the form.
- */
- this.saveFormVersion = function( dataSetId, formVersion )
- {
- var formVersions = {};
-
- if ( localStorage[KEY_FORM_VERSIONS] != null )
- {
- formVersions = JSON.parse( localStorage[KEY_FORM_VERSIONS] );
- }
-
- formVersions[dataSetId] = formVersion;
-
- try
- {
- localStorage[KEY_FORM_VERSIONS] = JSON.stringify( formVersions );
-
- log( 'Successfully stored form version: ' + dataSetId );
- } catch ( e )
- {
- log( 'Max local storage quota reached, ignored form version: ' + dataSetId );
- }
- };
-
- /**
- * Returns the version of the form of the data set with the given
- * identifier.
- *
- * @param dataSetId the identifier of the data set of the form.
- * @return the form version.
- */
- this.getFormVersion = function( dataSetId )
- {
- if ( localStorage[KEY_FORM_VERSIONS] != null )
- {
- var formVersions = JSON.parse( localStorage[KEY_FORM_VERSIONS] );
-
- return formVersions[dataSetId];
- }
-
- return null;
- };
-
- /**
- * Deletes the form version of the data set with the given identifier.
- *
- * @param dataSetId the identifier of the data set of the form.
- */
- this.deleteFormVersion = function( dataSetId )
- {
- if ( localStorage[KEY_FORM_VERSIONS] != null )
- {
- var formVersions = JSON.parse( localStorage[KEY_FORM_VERSIONS] );
-
- if ( formVersions[dataSetId] != null )
- {
- delete formVersions[dataSetId];
- localStorage[KEY_FORM_VERSIONS] = JSON.stringify( formVersions );
- }
- }
- }
-
- this.getAllFormVersions = function()
- {
- return localStorage[KEY_FORM_VERSIONS] != null ? JSON.parse( localStorage[KEY_FORM_VERSIONS] ) : null;
- };
-
- /**
- * Saves a data value.
- *
- * @param dataValue The datavalue and identifiers in json format.
- */
- this.saveDataValue = function( dataValue )
- {
- var id = this.getDataValueIdentifier( dataValue.dataElementId, dataValue.optionComboId, dataValue.periodId,
- dataValue.organisationUnitId );
-
- var dataValues = {};
-
- if ( localStorage[KEY_DATAVALUES] != null )
- {
- dataValues = JSON.parse( localStorage[KEY_DATAVALUES] );
- }
-
- dataValues[id] = dataValue;
-
- try
- {
- localStorage[KEY_DATAVALUES] = JSON.stringify( dataValues );
-
- log( 'Successfully stored data value' );
- } catch ( e )
- {
- log( 'Max local storage quota reached, ignored data value' );
- }
- };
-
- /**
- * Gets the value for the data value with the given arguments, or null if it
- * does not exist.
- *
- * @param dataElementId the data element identifier.
- * @param categoryOptionComboId the category option combo identifier.
- * @param periodId the period identifier.
- * @param organisationUnitId the organisation unit identifier.
- * @return the value for the data value with the given arguments, null if
- * non-existing.
- */
- this.getDataValue = function( dataElementId, categoryOptionComboId, periodId, organisationUnitId )
- {
- var id = this.getDataValueIdentifier( dataElementId, categoryOptionComboId, periodId, organisationUnitId );
-
- if ( localStorage[KEY_DATAVALUES] != null )
- {
- var dataValues = JSON.parse( localStorage[KEY_DATAVALUES] );
-
- return dataValues[id];
- }
-
- return null;
- };
-
- /**
- * Removes the given dataValue from localStorage.
- *
- * @param dataValue The datavalue and identifiers in json format.
- */
- this.clearDataValueJSON = function( dataValue )
- {
- this.clearDataValue( dataValue.dataElementId, dataValue.optionComboId, dataValue.periodId,
- dataValue.organisationUnitId );
- };
-
- /**
- * Removes the given dataValue from localStorage.
- *
- * @param dataElementId the data element identifier.
- * @param categoryOptionComboId the category option combo identifier.
- * @param periodId the period identifier.
- * @param organisationUnitId the organisation unit identifier.
- */
- this.clearDataValue = function( dataElementId, categoryOptionComboId, periodId, organisationUnitId )
- {
- var id = this.getDataValueIdentifier( dataElementId, categoryOptionComboId, periodId, organisationUnitId );
- var dataValues = this.getAllDataValues();
-
- if ( dataValues[id] != null )
- {
- delete dataValues[id];
- localStorage[KEY_DATAVALUES] = JSON.stringify( dataValues );
- }
- };
-
- /**
- * Returns a JSON associative array where the keys are on the form <data
- * element id>-<category option combo id>-<period id>-<organisation unit
- * id> and the data values are the values.
- *
- * @return a JSON associative array.
- */
- this.getAllDataValues = function()
- {
- return localStorage[KEY_DATAVALUES] != null ? JSON.parse( localStorage[KEY_DATAVALUES] ) : null;
- };
-
- /**
- * Supportive method.
- */
- this.getDataValueIdentifier = function( dataElementId, categoryOptionComboId, periodId, organisationUnitId )
- {
- return dataElementId + '-' + categoryOptionComboId + '-' + periodId + '-' + organisationUnitId;
- };
-
- /**
- * Supportive method.
- */
- this.getCompleteDataSetId = function( json )
- {
- return json.periodId + '-' + json.dataSetId + '-' + json.organisationUnitId;
- };
-
- /**
- * Returns current state in data entry form as associative array.
- *
- * @return an associative array.
- */
- this.getCurrentCompleteDataSetParams = function()
- {
- var params = {
- 'periodId' : $( '#selectedPeriodId' ).val(),
- 'dataSetId' : $( '#selectedDataSetId' ).val(),
- 'organisationUnitId' : currentOrganisationUnitId
- };
-
- return params;
- };
-
- /**
- * Gets all complete data set registrations as JSON.
- *
- * @return all complete data set registrations as JSON.
- */
- this.getCompleteDataSets = function()
- {
- if ( localStorage[KEY_COMPLETEDATASETS] != null )
- {
- return JSON.parse( localStorage[KEY_COMPLETEDATASETS] );
- }
-
- return null;
- };
-
- /**
- * Saves a complete data set registration.
- *
- * @param json the complete data set registration as JSON.
- */
- this.saveCompleteDataSet = function( json )
- {
- var completeDataSets = this.getCompleteDataSets();
- var completeDataSetId = this.getCompleteDataSetId( json );
-
- if ( completeDataSets != null )
- {
- completeDataSets[completeDataSetId] = json;
- }
- else
- {
- completeDataSets = {};
- completeDataSets[completeDataSetId] = json;
- }
-
- localStorage[KEY_COMPLETEDATASETS] = JSON.stringify( completeDataSets );
- };
-
- /**
- * Removes the given complete data set registration.
- *
- * @param the complete data set registration as JSON.
- */
- this.clearCompleteDataSet = function( json )
- {
- var completeDataSets = this.getCompleteDataSets();
- var completeDataSetId = this.getCompleteDataSetId( json );
-
- if ( completeDataSets != null )
- {
- delete completeDataSets[completeDataSetId];
-
- if ( completeDataSets.length > 0 )
- {
- localStorage.remoteItem( KEY_COMPLETEDATASETS );
- }
- else
- {
- localStorage[KEY_COMPLETEDATASETS] = JSON.stringify( completeDataSets );
- }
- }
- };
-
- /**
- * Indicators whether there exists data values or complete data set
- * registrations in the local storage.
- *
- * @return true if local data exists, false otherwise.
- */
- this.hasLocalData = function()
- {
- var dataValues = this.getAllDataValues();
- var completeDataSets = this.getCompleteDataSets();
-
- if ( dataValues == null && completeDataSets == null )
- {
- return false;
- }
- else if ( dataValues != null )
- {
- if ( Object.keys( dataValues ).length < 1 )
- {
- return false;
- }
- }
- else if ( completeDataSets != null )
- {
- if ( Object.keys( completeDataSets ).length < 1 )
- {
- return false;
- }
- }
-
- return true;
- };
-}
+// Identifiers for which zero values are insignificant, also used in entry.js
+var significantZeros = [];
+
+// Array with associative arrays for each data element, populated in select.vm
+var dataElements = [];
+
+// Associative array with [indicator id, expression] for indicators in form,
+// also used in entry.js
+var indicatorFormulas = [];
+
+// Array with associative arrays for each data set, populated in select.vm
+var dataSets = [];
+
+// Associative array with identifier and array of assigned data sets
+var dataSetAssociationSets = [];
+
+// Associate array with mapping between organisation unit identifier and data
+// set association set identifier
+var organisationUnitAssociationSetMap = [];
+
+// Array with keys on form {dataelementid}-{optioncomboid}-min/max with min/max
+// values
+var currentMinMaxValueMap = [];
+
+// Indicates whether any data entry form has been loaded
+var dataEntryFormIsLoaded = false;
+
+// Currently selected organisation unit identifier
+var currentOrganisationUnitId = null;
+
+// Currently selected data set identifier
+var currentDataSetId = null;
+
+// Current offset, next or previous corresponding to increasing or decreasing
+// value with one
+var currentPeriodOffset = 0;
+
+// Period type object
+var periodTypeFactory = new PeriodType();
+
+// Instance of the StorageManager
+var storageManager = new StorageManager();
+
+var COLOR_GREEN = '#b9ffb9';
+var COLOR_YELLOW = '#fffe8c';
+var COLOR_RED = '#ff8a8a';
+var COLOR_ORANGE = '#ff6600';
+var COLOR_WHITE = '#ffffff';
+var COLOR_GREY = '#cccccc';
+
+var DEFAULT_TYPE = 'int';
+var DEFAULT_NAME = '[unknown]';
+
+var FORMTYPE_CUSTOM = 'custom';
+var FORMTYPE_SECTION = 'section';
+var FORMTYPE_DEFAULT = 'default';
+
+/**
+ * Page init. The order of events is:
+ *
+ * 1. Load ouwt 2. Load meta-data (and notify ouwt) 3. Check and potentially
+ * download updated forms from server
+ */
+$( document ).ready( function()
+{
+ $.ajaxSetup({
+ type: 'POST'
+ });
+
+ selection.setListenerFunction( organisationUnitSelected );
+ $( '#loaderSpan' ).show();
+
+ $( '#orgUnitTree' ).one( 'ouwtLoaded', function()
+ {
+ log( 'Ouwt loaded' );
+ loadMetaData();
+ } );
+
+ $( document ).bind( 'dhis2.online', function( event, loggedIn )
+ {
+ if ( loggedIn )
+ {
+ if ( storageManager.hasLocalData() )
+ {
+ var message = i18n_need_to_sync_notification
+ + ' <button id="sync_button" type="button">' + i18n_sync_now
+ + '</button>';
+
+ setHeaderMessage( message );
+
+ $( '#sync_button' ).bind( 'click', uploadLocalData );
+ }
+ else
+ {
+ setHeaderDelayMessage( i18n_online_notification );
+ }
+ }
+ else
+ {
+ setHeaderMessage( '<form style="display:inline;"><label for="username">Username</label><input name="username" id="username" type="text" size="10"/><label for="password">Password</label><input name="password" id="password" type="password" size="10"/><button id="login_button" type="button">Login</button></form>' );
+ ajax_login();
+ }
+ } );
+
+ $( document ).bind( 'dhis2.offline', function()
+ {
+ setHeaderMessage( i18n_offline_notification );
+ } );
+
+ dhis2.availability.startAvailabilityCheck();
+} );
+
+function ajax_login()
+{
+ $( '#login_button' ).bind( 'click', function()
+ {
+ var username = $( '#username' ).val();
+ var password = $( '#password' ).val();
+
+ $.post( '../dhis-web-commons-security/login.action', {
+ 'j_username' : username,
+ 'j_password' : password
+ } ).success( function()
+ {
+ var ret = dhis2.availability.syncCheckAvailability();
+
+ if ( !ret )
+ {
+ alert( i18n_ajax_login_failed );
+ }
+ } );
+ } );
+}
+
+function loadMetaData()
+{
+ var KEY_METADATA = 'metadata';
+
+ $.ajax( {
+ url: 'getMetaData.action',
+ cache: false,
+ dataType: 'json',
+ success: function( json )
+ {
+ sessionStorage[KEY_METADATA] = JSON.stringify( json.metaData );
+ },
+ complete: function()
+ {
+ var metaData = JSON.parse( sessionStorage[KEY_METADATA] );
+
+ significantZeros = metaData.significantZeros;
+ dataElements = metaData.dataElements;
+ indicatorFormulas = metaData.indicatorFormulas;
+ dataSets = metaData.dataSets;
+ dataSetAssociationSets = metaData.dataSetAssociationSets;
+ organisationUnitAssociationSetMap = metaData.organisationUnitAssociationSetMap;
+
+ selection.responseReceived(); // Notify that meta data is loaded
+ $( '#loaderSpan' ).hide();
+ log( 'Meta-data loaded' );
+
+ updateForms();
+ }
+ } );
+}
+
+function uploadLocalData()
+{
+ if ( !storageManager.hasLocalData() )
+ {
+ return;
+ }
+
+ var dataValues = storageManager.getAllDataValues();
+ var completeDataSets = storageManager.getCompleteDataSets();
+
+ setHeaderWaitMessage( i18n_uploading_data_notification );
+
+ var dataValuesArray = dataValues ? Object.keys( dataValues ) : [];
+ var completeDataSetsArray = completeDataSets ? Object.keys( completeDataSets ) : [];
+
+ function pushCompleteDataSets( array )
+ {
+ if ( array.length < 1 )
+ {
+ return;
+ }
+
+ var key = array[0];
+ var value = completeDataSets[key];
+
+ log( 'Uploaded complete data set: ' + key + ', with value: ' + value );
+
+ $.ajax( {
+ url: 'registerCompleteDataSet.action',
+ data: value,
+ dataType: 'json',
+ cache: false,
+ success: function( data, textStatus, jqXHR )
+ {
+ log( 'Successfully saved complete dataset with value: ' + value );
+ storageManager.clearCompleteDataSet( value );
+ ( array = array.slice( 1 ) ).length && pushCompleteDataSets( array );
+
+ if ( array.length < 1 )
+ {
+ setHeaderDelayMessage( i18n_sync_success );
+ }
+ },
+ error: function( jqXHR, textStatus, errorThrown )
+ {
+ var message = i18n_sync_failed
+ + ' <button id="sync_button" type="button">' + i18n_sync_now
+ + '</button>';
+
+ setHeaderMessage( message );
+
+ $( '#sync_button' ).bind( 'click', uploadLocalData );
+ }
+ } );
+ };
+
+ ( function pushDataValues( array )
+ {
+ if ( array.length < 1 )
+ {
+ setHeaderDelayMessage( i18n_online_notification );
+
+ pushCompleteDataSets( completeDataSetsArray );
+
+ return;
+ }
+
+ var key = array[0];
+ var value = dataValues[key];
+
+ log( 'Uploaded data value: ' + key + ', with value: ' + value );
+
+ $.ajax( {
+ url: 'saveValue.action',
+ data: value,
+ dataType: 'json',
+ cache: false,
+ success: function( data, textStatus, jqXHR )
+ {
+ storageManager.clearDataValueJSON( value );
+ log( 'Successfully saved data value with value: ' + value );
+ ( array = array.slice( 1 ) ).length && pushDataValues( array );
+
+ if ( array.length < 1 && completeDataSetsArray.length > 0 )
+ {
+ pushCompleteDataSets( completeDataSetsArray );
+ }
+ else
+ {
+ setHeaderDelayMessage( i18n_sync_success );
+ }
+ },
+ error: function( jqXHR, textStatus, errorThrown )
+ {
+ var message = i18n_sync_failed
+ + ' <button id="sync_button" type="button">' + i18n_sync_now
+ + '</button>';
+
+ setHeaderMessage( message );
+
+ $( '#sync_button' ).bind( 'click', uploadLocalData );
+ }
+ } );
+ } )( dataValuesArray );
+}
+
+function addEventListeners()
+{
+ var dataSetId = $( '#selectedDataSetId' ).val();
+ var formType = dataSets[dataSetId].type;
+
+ $( '[name="entryfield"]' ).each( function( i )
+ {
+ var id = $( this ).attr( 'id' );
+ var dataElementId = id.split( '-' )[0];
+ var optionComboId = id.split( '-' )[1];
+ var type = getDataElementType( dataElementId );
+
+ $( this ).unbind( 'focus' );
+ $( this ).unbind( 'blur' );
+ $( this ).unbind( 'change' );
+ $( this ).unbind( 'dblclick' );
+ $( this ).unbind( 'keyup' );
+
+ $( this ).focus( valueFocus );
+
+ $( this ).blur( valueBlur );
+
+ $( this ).change( function()
+ {
+ saveVal( dataElementId, optionComboId );
+ } );
+
+ $( this ).dblclick( function()
+ {
+ viewHist( dataElementId, optionComboId );
+ } );
+
+ $( this ).keyup( function(event)
+ {
+ keyPress( event, this );
+ } );
+
+ if ( formType != FORMTYPE_CUSTOM )
+ {
+ $( this ).css( 'width', '100%' );
+ $( this ).css( 'text-align', 'center' );
+ }
+
+ if ( type == 'date' )
+ {
+ $( this ).css( 'width', '80%' );
+ datePicker( id );
+ }
+ } );
+
+ $( '[name="entryselect"]' ).each( function( i )
+ {
+ var id = $( this ).attr( 'id' );
+ var dataElementId = id.split( '-' )[0];
+ var optionComboId = id.split( '-' )[1];
+
+ $( this ).unbind( 'focus' );
+ $( this ).unbind( 'change' );
+
+ $( this ).focus( valueFocus );
+
+ $( this ).change( function()
+ {
+ saveBoolean( dataElementId, optionComboId );
+ } );
+
+ $( this ).css( 'width', '100%' );
+ } );
+}
+
+function clearPeriod()
+{
+ clearListById( 'selectedPeriodId' );
+ clearEntryForm();
+}
+
+function clearEntryForm()
+{
+ $( '#contentDiv' ).html( '' );
+
+ currentPeriodOffset = 0;
+
+ dataEntryFormIsLoaded = false;
+
+ $( '#completenessDiv' ).css( 'display', 'none' );
+}
+
+function loadForm( dataSetId )
+{
+ if ( storageManager.formExists( dataSetId ) )
+ {
+ log( 'Loading form locally: ' + dataSetId );
+
+ var html = storageManager.getForm( dataSetId );
+
+ $( '#contentDiv' ).html( html );
+
+ loadDataValues();
+ }
+ else
+ {
+ log( 'Loading form remotely: ' + dataSetId );
+
+ $( '#contentDiv' ).load( 'loadForm.action', {
+ dataSetId : dataSetId
+ }, loadDataValues );
+ }
+}
+
+function getDataElementType( dataElementId )
+{
+ if ( dataElements[dataElementId] != null )
+ {
+ return dataElements[dataElementId].type;
+ }
+
+ log( 'Data element not present in data set, falling back to default type: ' + dataElementId );
+ return DEFAULT_TYPE;
+}
+
+function getDataElementName( dataElementId )
+{
+ if ( dataElements[dataElementId] != null )
+ {
+ return dataElements[dataElementId].name;
+ }
+
+ log( 'Data element present in data set, falling back to default name: ' + dataElementId );
+ return DEFAULT_NAME;
+}
+
+// ----------------------------------------------------------------------------
+// OrganisationUnit Selection
+// -----------------------------------------------------------------------------
+
+/**
+ * Returns an array containing associative array elements with id and name
+ * properties. The array is sorted on the element name property.
+ */
+function getSortedDataSetList()
+{
+ var associationSet = organisationUnitAssociationSetMap[currentOrganisationUnitId];
+ var orgUnitDataSets = dataSetAssociationSets[associationSet];
+
+ var dataSetList = [];
+
+ for ( i in orgUnitDataSets )
+ {
+ var dataSetId = orgUnitDataSets[i];
+ var dataSetName = dataSets[dataSetId].name;
+
+ var row = [];
+ row['id'] = dataSetId;
+ row['name'] = dataSetName;
+ dataSetList[i] = row;
+ }
+
+ dataSetList.sort( function( a, b )
+ {
+ return a.name > b.name ? 1 : a.name < b.name ? -1 : 0;
+ } );
+
+ return dataSetList;
+}
+
+function organisationUnitSelected( orgUnits, orgUnitNames )
+{
+ currentOrganisationUnitId = orgUnits[0];
+ var organisationUnitName = orgUnitNames[0];
+
+ $( '#selectedOrganisationUnit' ).val( organisationUnitName );
+ $( '#currentOrganisationUnit' ).html( organisationUnitName );
+
+ var dataSetList = getSortedDataSetList();
+
+ if ( dataSetList.length )
+ {
+ $( '#selectedDataSetId' ).removeAttr( 'disabled' );
+
+ var dataSetId = $( '#selectedDataSetId' ).val();
+ var periodId = $( '#selectedPeriodId' ).val();
+
+ clearListById( 'selectedDataSetId' );
+ addOptionById( 'selectedDataSetId', '-1', '[ ' + i18n_select_data_set + ' ]' );
+
+ var dataSetValid = false;
+
+ for ( i in dataSetList )
+ {
+ addOptionById( 'selectedDataSetId', dataSetList[i].id, dataSetList[i].name );
+
+ if ( dataSetId == dataSetList[i].id )
+ {
+ dataSetValid = true;
+ }
+ }
+
+ if ( dataSetValid && dataSetId != null )
+ {
+ $( '#selectedDataSetId' ).val( dataSetId );
+
+ if ( periodId && periodId != -1 && dataEntryFormIsLoaded )
+ {
+ showLoader();
+ loadDataValues();
+ }
+ }
+ else
+ {
+ clearPeriod();
+ }
+ }
+}
+
+// -----------------------------------------------------------------------------
+// Next/Previous Periods Selection
+// -----------------------------------------------------------------------------
+
+function nextPeriodsSelected()
+{
+ if ( currentPeriodOffset < 0 ) // Cannot display future periods
+ {
+ currentPeriodOffset++;
+ displayPeriodsInternal();
+ }
+}
+
+function previousPeriodsSelected()
+{
+ currentPeriodOffset--;
+ displayPeriodsInternal();
+}
+
+function displayPeriodsInternal()
+{
+ var dataSetId = $( '#selectedDataSetId' ).val();
+ var periodType = dataSets[dataSetId].periodType;
+ var periods = periodTypeFactory.get( periodType ).generatePeriods( currentPeriodOffset );
+ periods = periodTypeFactory.filterFuturePeriods( periods );
+
+ clearListById( 'selectedPeriodId' );
+
+ addOptionById( 'selectedPeriodId', '-1', '[ ' + i18n_select_period + ' ]' );
+
+ for ( i in periods )
+ {
+ addOptionById( 'selectedPeriodId', periods[i].id, periods[i].name );
+ }
+}
+
+// -----------------------------------------------------------------------------
+// DataSet Selection
+// -----------------------------------------------------------------------------
+
+function dataSetSelected()
+{
+ $( '#selectedPeriodId' ).removeAttr( 'disabled' );
+ $( '#prevButton' ).removeAttr( 'disabled' );
+ $( '#nextButton' ).removeAttr( 'disabled' );
+
+ var dataSetId = $( '#selectedDataSetId' ).val();
+ var periodId = $( '#selectedPeriodId' ).val();
+ var periodType = dataSets[dataSetId].periodType;
+ var periods = periodTypeFactory.get( periodType ).generatePeriods( currentPeriodOffset );
+ periods = periodTypeFactory.filterFuturePeriods( periods );
+
+ if ( dataSetId && dataSetId != -1 )
+ {
+ clearListById( 'selectedPeriodId' );
+
+ addOptionById( 'selectedPeriodId', '-1', '[ ' + i18n_select_period + ' ]' );
+
+ for ( i in periods )
+ {
+ addOptionById( 'selectedPeriodId', periods[i].id, periods[i].name );
+ }
+
+ var previousPeriodType = currentDataSetId ? dataSets[currentDataSetId].periodType : null;
+
+ if ( periodId && periodId != -1 && previousPeriodType && previousPeriodType == periodType )
+ {
+ showLoader();
+ $( '#selectedPeriodId' ).val( periodId );
+ loadForm( dataSetId );
+ }
+ else
+ {
+ clearEntryForm();
+ }
+
+ currentDataSetId = dataSetId;
+ }
+}
+
+// -----------------------------------------------------------------------------
+// Period Selection
+// -----------------------------------------------------------------------------
+
+function periodSelected()
+{
+ var periodName = $( '#selectedPeriodId :selected' ).text();
+ var dataSetId = $( '#selectedDataSetId' ).val();
+
+ $( '#currentPeriod' ).html( periodName );
+
+ var periodId = $( '#selectedPeriodId' ).val();
+
+ if ( periodId && periodId != -1 )
+ {
+ showLoader();
+
+ if ( dataEntryFormIsLoaded )
+ {
+ loadDataValues();
+ }
+ else
+ {
+ loadForm( dataSetId );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------------
+// Form
+// -----------------------------------------------------------------------------
+
+function loadDataValues()
+{
+ $( '#completeButton' ).removeAttr( 'disabled' );
+ $( '#undoButton' ).attr( 'disabled', 'disabled' );
+
+ insertDataValues();
+ displayEntryFormCompleted();
+}
+
+function insertDataValues()
+{
+ var dataValueMap = [];
+ currentMinMaxValueMap = []; // Reset
+
+ var periodId = $( '#selectedPeriodId' ).val();
+ var dataSetId = $( '#selectedDataSetId' ).val();
+
+ // Clear existing values and colors, grey disabled fields
+
+ $( '[name="entryfield"]' ).val( '' );
+ $( '[name="entryselect"]' ).val( '' );
+
+ $( '[name="entryfield"]' ).css( 'background-color', COLOR_WHITE );
+ $( '[name="entryselect"]' ).css( 'background-color', COLOR_WHITE );
+
+ $( '[name="min"]' ).html( '' );
+ $( '[name="max"]' ).html( '' );
+
+ $( '[name="entryfield"]' ).filter( ':disabled' ).css( 'background-color', COLOR_GREY );
+
+ $.ajax( {
+ url: 'getDataValues.action',
+ data:
+ {
+ periodId : periodId,
+ dataSetId : dataSetId,
+ organisationUnitId : currentOrganisationUnitId
+ },
+ cache: false,
+ dataType: 'json',
+ success: function( json )
+ {
+ // Set data values, works for select lists too as data
+ // value = select value
+
+ $.each( json.dataValues, function( i, value )
+ {
+ var fieldId = '#' + value.id + '-val';
+
+ if ( $( fieldId ) )
+ {
+ $( fieldId ).val( value.val );
+ }
+
+ dataValueMap[value.id] = value.val;
+ } );
+
+ // Set min-max values and colorize violation fields
+
+ $.each( json.minMaxDataElements, function( i, value )
+ {
+ var minId = value.id + '-min';
+ var maxId = value.id + '-max';
+
+ var valFieldId = '#' + value.id + '-val';
+
+ var dataValue = dataValueMap[value.id];
+
+ if ( dataValue && ( ( value.min && new Number( dataValue ) < new Number(
+ value.min ) ) || ( value.max && new Number( dataValue ) > new Number( value.max ) ) ) )
+ {
+ $( valFieldId ).css( 'background-color', COLOR_ORANGE );
+ }
+
+ currentMinMaxValueMap[minId] = value.min;
+ currentMinMaxValueMap[maxId] = value.max;
+ } );
+
+ // Update indicator values in form
+
+ updateIndicators();
+
+ // Set completeness button
+
+ if ( json.complete )
+ {
+ $( '#completeButton' ).attr( 'disabled', 'disabled' );
+ $( '#undoButton' ).removeAttr( 'disabled' );
+ }
+ else
+ {
+ $( '#completeButton' ).removeAttr( 'disabled' );
+ $( '#undoButton' ).attr( 'disabled', 'disabled' );
+ }
+
+ // TODO locking
+ }
+ } );
+}
+
+function displayEntryFormCompleted()
+{
+ addEventListeners();
+
+ $( '#validationButton' ).removeAttr( 'disabled' );
+ $( '#defaultForm' ).removeAttr( 'disabled' );
+
+ dataEntryFormIsLoaded = true;
+ hideLoader();
+
+ $( '#completenessDiv' ).css( 'display', 'block' );
+}
+
+function valueFocus( e )
+{
+ var id = e.target.id;
+
+ var dataElementId = id.split( '-' )[0];
+ var optionComboId = id.split( '-' )[1];
+
+ var dataElementName = getDataElementName( dataElementId );
+ var optionComboName = $( '#' + optionComboId + '-optioncombo' ).text();
+
+ $( '#currentDataElement' ).html( dataElementName + ' ' + optionComboName );
+
+ $( '#' + dataElementId + '-cell' ).addClass( 'currentRow' );
+}
+
+function valueBlur( e )
+{
+ var id = e.target.id;
+
+ var dataElementId = id.split( '-' )[0];
+
+ $( '#' + dataElementId + '-cell' ).removeClass( 'currentRow' );
+}
+
+function keyPress( event, field )
+{
+ var key = event.keyCoe || event.charCode || event.which;
+
+ var focusField = ( key == 13 || key == 40 ) ? getNextEntryField( field )
+ : ( key == 38 ) ? getPreviousEntryField( field ) : false;
+
+ if ( focusField )
+ {
+ focusField.focus();
+ }
+}
+
+function getNextEntryField( field )
+{
+ var index = field.getAttribute( 'tabindex' );
+
+ field = $( 'input[name="entryfield"][tabindex="' + ( ++index ) + '"]' );
+
+ while ( field )
+ {
+ if ( field.is( ':disabled' ) || field.is( ':hidden' ) )
+ {
+ field = $( 'input[name="entryfield"][tabindex="' + ( ++index ) + '"]' );
+ }
+ else
+ {
+ return field;
+ }
+ }
+}
+
+function getPreviousEntryField( field )
+{
+ var index = field.getAttribute( 'tabindex' );
+
+ field = $( 'input[name="entryfield"][tabindex="' + ( --index ) + '"]' );
+
+ while ( field )
+ {
+ if ( field.is( ':disabled' ) || field.is( ':hidden' ) )
+ {
+ field = $( 'input[name="entryfield"][tabindex="' + ( --index ) + '"]' );
+ }
+ else
+ {
+ return field;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------------
+// Data completeness
+// -----------------------------------------------------------------------------
+
+function validateCompleteDataSet()
+{
+ var confirmed = confirm( i18n_confirm_complete );
+
+ if ( confirmed )
+ {
+ var params = storageManager.getCurrentCompleteDataSetParams();
+
+ disableCompleteButton();
+
+ $.ajax( { url: 'getValidationViolations.action',
+ cache: false,
+ data: params,
+ dataType: 'json',
+ success: function( data )
+ {
+ registerCompleteDataSet( data );
+ },
+ error: function()
+ {
+ // no response from server, fake a positive result and save it
+ registerCompleteDataSet( { 'response' : 'success' } );
+ }
+ } );
+ }
+}
+
+function registerCompleteDataSet( json )
+{
+ var params = storageManager.getCurrentCompleteDataSetParams();
+
+ if ( json.response == 'success' )
+ {
+ storageManager.saveCompleteDataSet( params );
+
+ $.ajax( {
+ url: 'registerCompleteDataSet.action',
+ data: params,
+ cache: false,
+ success: function()
+ {
+ storageManager.clearCompleteDataSet( params );
+ }
+ } );
+ }
+ else
+ {
+ disableUndoButton();
+
+ validate();
+ }
+}
+
+function undoCompleteDataSet()
+{
+ var confirmed = confirm( i18n_confirm_undo );
+ var params = storageManager.getCurrentCompleteDataSetParams();
+
+ if ( confirmed )
+ {
+ disableUndoButton();
+
+ $.ajax( {
+ url: 'undoCompleteDataSet.action',
+ data: params,
+ cache: false,
+ success: function()
+ {
+ storageManager.clearCompleteDataSet( params );
+ },
+ error: function()
+ {
+ storageManager.clearCompleteDataSet( params );
+ }
+ } );
+ }
+}
+
+function disableUndoButton()
+{
+ $( '#completeButton' ).removeAttr( 'disabled' );
+ $( '#undoButton' ).attr( 'disabled', 'disabled' );
+}
+
+function disableCompleteButton()
+{
+ $( '#completeButton' ).attr( 'disabled', 'disabled' );
+ $( '#undoButton' ).removeAttr( 'disabled' );
+}
+
+// -----------------------------------------------------------------------------
+// Validation
+// -----------------------------------------------------------------------------
+
+function displayValidationDialog()
+{
+ $( '#validationDiv' ).dialog( {
+ modal : true,
+ title : 'Validation',
+ width : 800,
+ height : 400
+ } );
+}
+
+function validate()
+{
+ var periodId = $( '#selectedPeriodId' ).val();
+ var dataSetId = $( '#selectedDataSetId' ).val();
+
+ $( '#validationDiv' ).load( 'validate.action', {
+ periodId : periodId,
+ dataSetId : dataSetId,
+ organisationUnitId : currentOrganisationUnitId
+ }, function( response, status, xhr )
+ {
+ if ( status == 'error' )
+ {
+ window.alert( i18n_operation_not_available_offline );
+ }
+ else
+ {
+ displayValidationDialog();
+ }
+ } );
+}
+
+// -----------------------------------------------------------------------------
+// History
+// -----------------------------------------------------------------------------
+
+function displayHistoryDialog( operandName )
+{
+ $( '#historyDiv' ).dialog( {
+ modal : true,
+ title : operandName,
+ width : 580,
+ height : 710
+ } );
+}
+
+function viewHist( dataElementId, optionComboId )
+{
+ var periodId = $( '#selectedPeriodId' ).val();
+
+ var dataElementName = getDataElementName( dataElementId );
+ var optionComboName = $( '#' + optionComboId + '-optioncombo' ).html();
+ var operandName = dataElementName + ' ' + optionComboName;
+
+ $( '#historyDiv' ).load( 'viewHistory.action', {
+ dataElementId : dataElementId,
+ optionComboId : optionComboId,
+ periodId : periodId,
+ organisationUnitId : currentOrganisationUnitId
+ }, function( response, status, xhr )
+ {
+ if ( status == 'error' )
+ {
+ window.alert( i18n_operation_not_available_offline );
+ }
+ else
+ {
+ displayHistoryDialog( operandName );
+ }
+ } );
+}
+
+function closeCurrentSelection()
+{
+ $( '#currentSelection' ).fadeOut();
+}
+
+// -----------------------------------------------------------------------------
+// Local storage of forms
+// -----------------------------------------------------------------------------
+
+function updateForms()
+{
+ purgeLocalForms();
+ updateExistingLocalForms();
+ downloadRemoteForms();
+}
+
+function purgeLocalForms()
+{
+ var formIds = storageManager.getAllForms();
+
+ for ( i in formIds )
+ {
+ var localId = formIds[i];
+
+ if ( dataSets[localId] == null )
+ {
+ storageManager.deleteForm( localId );
+ storageManager.deleteFormVersion( localId );
+ log( 'Deleted locally stored form: ' + localId );
+ }
+ }
+
+ log( 'Purged local forms' );
+}
+
+function updateExistingLocalForms()
+{
+ var formIds = storageManager.getAllForms();
+ var formVersions = storageManager.getAllFormVersions();
+
+ for ( i in formIds )
+ {
+ var localId = formIds[i];
+
+ var remoteVersion = dataSets[localId].version;
+ var localVersion = formVersions[localId];
+
+ if ( remoteVersion == null || localVersion == null || remoteVersion != localVersion )
+ {
+ storageManager.downloadForm( localId, remoteVersion );
+ }
+ }
+}
+
+function downloadRemoteForms()
+{
+ for ( dataSetId in dataSets )
+ {
+ var remoteVersion = dataSets[dataSetId].version;
+
+ if ( !storageManager.formExists( dataSetId ) )
+ {
+ storageManager.downloadForm( dataSetId, remoteVersion );
+ }
+ }
+}
+
+// TODO break if local storage is full
+
+// -----------------------------------------------------------------------------
+// StorageManager
+// -----------------------------------------------------------------------------
+
+/**
+ * This object provides utility methods for localStorage and manages data entry
+ * forms and data values.
+ */
+function StorageManager()
+{
+ var MAX_SIZE = new Number( 2600000 );
+ var MAX_SIZE_FORMS = new Number( 1600000 );
+
+ var KEY_FORM_PREFIX = 'form-';
+ var KEY_FORM_VERSIONS = 'formversions';
+ var KEY_DATAVALUES = 'datavalues';
+ var KEY_COMPLETEDATASETS = 'completedatasets';
+
+ /**
+ * Returns the total number of characters currently in the local storage.
+ *
+ * @return number of characters.
+ */
+ this.totalSize = function()
+ {
+ var totalSize = new Number();
+
+ for ( var i = 0; i < localStorage.length; i++ )
+ {
+ var value = localStorage.key( i );
+
+ if ( value )
+ {
+ totalSize += value.length;
+ }
+ }
+
+ return totalSize;
+ };
+
+ /**
+ * Returns the total numbers of characters in stored forms currently in the
+ * local storage.
+ *
+ * @return number of characters.
+ */
+ this.totalFormSize = function()
+ {
+ var totalSize = new Number();
+
+ for ( var i = 0; i < localStorage.length; i++ )
+ {
+ if ( localStorage.key( i ).substring( 0, KEY_FORM_PREFIX.length ) == KEY_FORM_PREFIX )
+ {
+ var value = localStorage.key( i );
+
+ if ( value )
+ {
+ totalSize += value.length;
+ }
+ }
+ }
+
+ return totalSize;
+ };
+
+ /**
+ * Return the remaining capacity of the local storage in characters, ie. the
+ * maximum size minus the current size.
+ */
+ this.remainingStorage = function()
+ {
+ return MAX_SIZE - this.totalSize();
+ };
+
+ /**
+ * Saves the content of a data entry form.
+ *
+ * @param dataSetId the identifier of the data set of the form.
+ * @param html the form HTML content.
+ * @return true if the form saved successfully, false otherwise.
+ */
+ this.saveForm = function( dataSetId, html )
+ {
+ var id = KEY_FORM_PREFIX + dataSetId;
+
+ try
+ {
+ localStorage[id] = html;
+
+ log( 'Successfully stored form: ' + dataSetId );
+ } catch ( e )
+ {
+ log( 'Max local storage quota reached, ignored form: ' + dataSetId );
+ return false;
+ }
+
+ if ( MAX_SIZE_FORMS < this.totalFormSize() )
+ {
+ this.deleteForm( dataSetId );
+
+ log( 'Max local storage quota for forms reached, ignored form: ' + dataSetId );
+ return false;
+ }
+
+ return true;
+ };
+
+ /**
+ * Gets the content of a data entry form.
+ *
+ * @param dataSetId the identifier of the data set of the form.
+ * @return the content of a data entry form.
+ */
+ this.getForm = function( dataSetId )
+ {
+ var id = KEY_FORM_PREFIX + dataSetId;
+
+ return localStorage[id];
+ };
+
+ /**
+ * Removes a form.
+ *
+ * @param dataSetId the identifier of the data set of the form.
+ */
+ this.deleteForm = function( dataSetId )
+ {
+ var id = KEY_FORM_PREFIX + dataSetId;
+
+ localStorage.removeItem( id );
+ };
+
+ /**
+ * Returns an array of the identifiers of all forms.
+ *
+ * @return array with form identifiers.
+ */
+ this.getAllForms = function()
+ {
+ var formIds = [];
+
+ var formIndex = 0;
+
+ for ( var i = 0; i < localStorage.length; i++ )
+ {
+ var key = localStorage.key( i );
+
+ if ( key.substring( 0, KEY_FORM_PREFIX.length ) == KEY_FORM_PREFIX )
+ {
+ var id = key.split( '-' )[1];
+
+ formIds[formIndex++] = id;
+ }
+ }
+
+ return formIds;
+ };
+
+ /**
+ * Indicates whether a form exists.
+ *
+ * @param dataSetId the identifier of the data set of the form.
+ * @return true if a form exists, false otherwise.
+ */
+ this.formExists = function( dataSetId )
+ {
+ var id = KEY_FORM_PREFIX + dataSetId;
+
+ return localStorage[id] != null;
+ };
+
+ /**
+ * Downloads the form for the data set with the given identifier from the
+ * remote server and saves the form locally. Potential existing forms with
+ * the same identifier will be overwritten. Updates the form version.
+ *
+ * @param dataSetId the identifier of the data set of the form.
+ * @param formVersion the version of the form of the remote data set.
+ */
+ this.downloadForm = function( dataSetId, formVersion )
+ {
+ $.ajax( {
+ url: 'loadForm.action',
+ data:
+ {
+ dataSetId : dataSetId
+ },
+ dataSetId: dataSetId,
+ formVersion: formVersion,
+ cache: false,
+ dataType: 'text',
+ success: function( data, textStatus, jqXHR )
+ {
+ storageManager.saveForm( this.dataSetId, data );
+ storageManager.saveFormVersion( this.dataSetId, this.formVersion );
+ }
+ } );
+ };
+
+ /**
+ * Saves a version for a form.
+ *
+ * @param the identifier of the data set of the form.
+ * @param formVersion the version of the form.
+ */
+ this.saveFormVersion = function( dataSetId, formVersion )
+ {
+ var formVersions = {};
+
+ if ( localStorage[KEY_FORM_VERSIONS] != null )
+ {
+ formVersions = JSON.parse( localStorage[KEY_FORM_VERSIONS] );
+ }
+
+ formVersions[dataSetId] = formVersion;
+
+ try
+ {
+ localStorage[KEY_FORM_VERSIONS] = JSON.stringify( formVersions );
+
+ log( 'Successfully stored form version: ' + dataSetId );
+ } catch ( e )
+ {
+ log( 'Max local storage quota reached, ignored form version: ' + dataSetId );
+ }
+ };
+
+ /**
+ * Returns the version of the form of the data set with the given
+ * identifier.
+ *
+ * @param dataSetId the identifier of the data set of the form.
+ * @return the form version.
+ */
+ this.getFormVersion = function( dataSetId )
+ {
+ if ( localStorage[KEY_FORM_VERSIONS] != null )
+ {
+ var formVersions = JSON.parse( localStorage[KEY_FORM_VERSIONS] );
+
+ return formVersions[dataSetId];
+ }
+
+ return null;
+ };
+
+ /**
+ * Deletes the form version of the data set with the given identifier.
+ *
+ * @param dataSetId the identifier of the data set of the form.
+ */
+ this.deleteFormVersion = function( dataSetId )
+ {
+ if ( localStorage[KEY_FORM_VERSIONS] != null )
+ {
+ var formVersions = JSON.parse( localStorage[KEY_FORM_VERSIONS] );
+
+ if ( formVersions[dataSetId] != null )
+ {
+ delete formVersions[dataSetId];
+ localStorage[KEY_FORM_VERSIONS] = JSON.stringify( formVersions );
+ }
+ }
+ }
+
+ this.getAllFormVersions = function()
+ {
+ return localStorage[KEY_FORM_VERSIONS] != null ? JSON.parse( localStorage[KEY_FORM_VERSIONS] ) : null;
+ };
+
+ /**
+ * Saves a data value.
+ *
+ * @param dataValue The datavalue and identifiers in json format.
+ */
+ this.saveDataValue = function( dataValue )
+ {
+ var id = this.getDataValueIdentifier( dataValue.dataElementId, dataValue.optionComboId, dataValue.periodId,
+ dataValue.organisationUnitId );
+
+ var dataValues = {};
+
+ if ( localStorage[KEY_DATAVALUES] != null )
+ {
+ dataValues = JSON.parse( localStorage[KEY_DATAVALUES] );
+ }
+
+ dataValues[id] = dataValue;
+
+ try
+ {
+ localStorage[KEY_DATAVALUES] = JSON.stringify( dataValues );
+
+ log( 'Successfully stored data value' );
+ } catch ( e )
+ {
+ log( 'Max local storage quota reached, ignored data value' );
+ }
+ };
+
+ /**
+ * Gets the value for the data value with the given arguments, or null if it
+ * does not exist.
+ *
+ * @param dataElementId the data element identifier.
+ * @param categoryOptionComboId the category option combo identifier.
+ * @param periodId the period identifier.
+ * @param organisationUnitId the organisation unit identifier.
+ * @return the value for the data value with the given arguments, null if
+ * non-existing.
+ */
+ this.getDataValue = function( dataElementId, categoryOptionComboId, periodId, organisationUnitId )
+ {
+ var id = this.getDataValueIdentifier( dataElementId, categoryOptionComboId, periodId, organisationUnitId );
+
+ if ( localStorage[KEY_DATAVALUES] != null )
+ {
+ var dataValues = JSON.parse( localStorage[KEY_DATAVALUES] );
+
+ return dataValues[id];
+ }
+
+ return null;
+ };
+
+ /**
+ * Removes the given dataValue from localStorage.
+ *
+ * @param dataValue The datavalue and identifiers in json format.
+ */
+ this.clearDataValueJSON = function( dataValue )
+ {
+ this.clearDataValue( dataValue.dataElementId, dataValue.optionComboId, dataValue.periodId,
+ dataValue.organisationUnitId );
+ };
+
+ /**
+ * Removes the given dataValue from localStorage.
+ *
+ * @param dataElementId the data element identifier.
+ * @param categoryOptionComboId the category option combo identifier.
+ * @param periodId the period identifier.
+ * @param organisationUnitId the organisation unit identifier.
+ */
+ this.clearDataValue = function( dataElementId, categoryOptionComboId, periodId, organisationUnitId )
+ {
+ var id = this.getDataValueIdentifier( dataElementId, categoryOptionComboId, periodId, organisationUnitId );
+ var dataValues = this.getAllDataValues();
+
+ if ( dataValues[id] != null )
+ {
+ delete dataValues[id];
+ localStorage[KEY_DATAVALUES] = JSON.stringify( dataValues );
+ }
+ };
+
+ /**
+ * Returns a JSON associative array where the keys are on the form <data
+ * element id>-<category option combo id>-<period id>-<organisation unit
+ * id> and the data values are the values.
+ *
+ * @return a JSON associative array.
+ */
+ this.getAllDataValues = function()
+ {
+ return localStorage[KEY_DATAVALUES] != null ? JSON.parse( localStorage[KEY_DATAVALUES] ) : null;
+ };
+
+ /**
+ * Supportive method.
+ */
+ this.getDataValueIdentifier = function( dataElementId, categoryOptionComboId, periodId, organisationUnitId )
+ {
+ return dataElementId + '-' + categoryOptionComboId + '-' + periodId + '-' + organisationUnitId;
+ };
+
+ /**
+ * Supportive method.
+ */
+ this.getCompleteDataSetId = function( json )
+ {
+ return json.periodId + '-' + json.dataSetId + '-' + json.organisationUnitId;
+ };
+
+ /**
+ * Returns current state in data entry form as associative array.
+ *
+ * @return an associative array.
+ */
+ this.getCurrentCompleteDataSetParams = function()
+ {
+ var params = {
+ 'periodId' : $( '#selectedPeriodId' ).val(),
+ 'dataSetId' : $( '#selectedDataSetId' ).val(),
+ 'organisationUnitId' : currentOrganisationUnitId
+ };
+
+ return params;
+ };
+
+ /**
+ * Gets all complete data set registrations as JSON.
+ *
+ * @return all complete data set registrations as JSON.
+ */
+ this.getCompleteDataSets = function()
+ {
+ if ( localStorage[KEY_COMPLETEDATASETS] != null )
+ {
+ return JSON.parse( localStorage[KEY_COMPLETEDATASETS] );
+ }
+
+ return null;
+ };
+
+ /**
+ * Saves a complete data set registration.
+ *
+ * @param json the complete data set registration as JSON.
+ */
+ this.saveCompleteDataSet = function( json )
+ {
+ var completeDataSets = this.getCompleteDataSets();
+ var completeDataSetId = this.getCompleteDataSetId( json );
+
+ if ( completeDataSets != null )
+ {
+ completeDataSets[completeDataSetId] = json;
+ }
+ else
+ {
+ completeDataSets = {};
+ completeDataSets[completeDataSetId] = json;
+ }
+
+ localStorage[KEY_COMPLETEDATASETS] = JSON.stringify( completeDataSets );
+ };
+
+ /**
+ * Removes the given complete data set registration.
+ *
+ * @param the complete data set registration as JSON.
+ */
+ this.clearCompleteDataSet = function( json )
+ {
+ var completeDataSets = this.getCompleteDataSets();
+ var completeDataSetId = this.getCompleteDataSetId( json );
+
+ if ( completeDataSets != null )
+ {
+ delete completeDataSets[completeDataSetId];
+
+ if ( completeDataSets.length > 0 )
+ {
+ localStorage.remoteItem( KEY_COMPLETEDATASETS );
+ }
+ else
+ {
+ localStorage[KEY_COMPLETEDATASETS] = JSON.stringify( completeDataSets );
+ }
+ }
+ };
+
+ /**
+ * Indicators whether there exists data values or complete data set
+ * registrations in the local storage.
+ *
+ * @return true if local data exists, false otherwise.
+ */
+ this.hasLocalData = function()
+ {
+ var dataValues = this.getAllDataValues();
+ var completeDataSets = this.getCompleteDataSets();
+
+ if ( dataValues == null && completeDataSets == null )
+ {
+ return false;
+ }
+ else if ( dataValues != null )
+ {
+ if ( Object.keys( dataValues ).length < 1 )
+ {
+ return false;
+ }
+ }
+ else if ( completeDataSets != null )
+ {
+ if ( Object.keys( completeDataSets ).length < 1 )
+ {
+ return false;
+ }
+ }
+
+ return true;
+ };
+}