← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 15576: replaced localstorage with indexeddb in tracker capture

 

------------------------------------------------------------
revno: 15576
committer: Abyot Asalefew Gizaw abyota@xxxxxxxxx
branch nick: dhis2
timestamp: Fri 2014-06-06 15:35:06 +0200
message:
  replaced localstorage with indexeddb in tracker capture
modified:
  dhis-2/dhis-web/dhis-web-event-capture/src/main/webapp/dhis-web-event-capture/scripts/event-capture.js
  dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/components/dataentry/dataentry-controller.js
  dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/components/dataentry/dataentry.html
  dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/components/enrollment/enrollment-controller.js
  dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/components/enrollment/enrollment.html
  dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/components/profile/profile-controller.js
  dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/components/profile/profile.html
  dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/components/registration/registration-controller.js
  dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/components/relationship/relationship-controller.js
  dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/components/selected/selected-controller.js
  dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/index.html
  dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/scripts/app.js
  dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/scripts/controllers.js
  dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/scripts/directives.js
  dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/scripts/services.js
  dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/scripts/tracker-capture.js
  dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/styles/style.css
  dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/views/home.html


--
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-event-capture/src/main/webapp/dhis-web-event-capture/scripts/event-capture.js'
--- dhis-2/dhis-web/dhis-web-event-capture/src/main/webapp/dhis-web-event-capture/scripts/event-capture.js	2014-06-03 09:51:54 +0000
+++ dhis-2/dhis-web/dhis-web-event-capture/src/main/webapp/dhis-web-event-capture/scripts/event-capture.js	2014-06-06 13:35:06 +0000
@@ -344,7 +344,7 @@
 
     _.each( _.values( programs ), function ( program ) {
         _.each(_.values( program.programStages[0].programStageDataElements), function(prStDe){
-            if( prStDe.dataElement.optionSet && prStDe.dataElement.optionSet ){
+            if( prStDe.dataElement.optionSet && prStDe.dataElement.optionSet.id ){
                 build = build.then(function() {
                     var d = $.Deferred();
                     var p = d.promise();
@@ -650,4 +650,4 @@
     {
         return Math.random().toString(36).substr(2, 11);
     };
-}
\ No newline at end of file
+}

=== modified file 'dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/components/dataentry/dataentry-controller.js'
--- dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/components/dataentry/dataentry-controller.js	2014-05-28 13:36:26 +0000
+++ dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/components/dataentry/dataentry-controller.js	2014-06-06 13:35:06 +0000
@@ -3,8 +3,10 @@
                 $filter,
                 orderByFilter,
                 storage,
+                ProgramStageFactory,
                 DHIS2EventFactory,
                 OrgUnitService,
+                CurrentSelection,
                 TranslationService) {
 
     TranslationService.translate();
@@ -20,21 +22,22 @@
         $scope.allowEventCreation = false;
         $scope.repeatableStages = [];        
         $scope.dhis2Events = [];       
-    
-        $scope.selectedEntity = args.selectedEntity;
-        $scope.selectedOrgUnit = args.selectedOrgUnit;
-        $scope.selectedProgramId = args.selectedProgramId;        
-        $scope.selectedEnrollment = args.selectedEnrollment;        
+        
+        var selections = CurrentSelection.get();          
+        $scope.selectedOrgUnit = storage.get('SELECTED_OU');
+        $scope.selectedEntity = selections.tei;      
+        $scope.selectedProgram = selections.pr;        
+        $scope.selectedEnrollment = selections.enrollment;        
         
         if($scope.selectedOrgUnit && 
-                $scope.selectedProgramId && 
+                $scope.selectedProgram && 
                 $scope.selectedEntity && 
                 $scope.selectedEnrollment){
             
-            DHIS2EventFactory.getByEntity($scope.selectedEntity.trackedEntityInstance, $scope.selectedOrgUnit.id, $scope.selectedProgramId).then(function(data){
+            DHIS2EventFactory.getByEntity($scope.selectedEntity.trackedEntityInstance, $scope.selectedOrgUnit.id, $scope.selectedProgram.id).then(function(data){
                 $scope.dhis2Events = data;
                 
-                if(angular.isUndefined($scope.dhis2Events)){
+                /*if(angular.isUndefined($scope.dhis2Events)){
                     
                     $scope.dhis2Events = [];
                     
@@ -60,21 +63,22 @@
                             
                         });
                     }
-                }
-                
+                }*/                
+
                 angular.forEach($scope.dhis2Events, function(dhis2Event){
                     
-                    var ps = storage.get(dhis2Event.programStage);
-                    
-                    //check if a stage is repeatable
-                    if(ps.repeatable){
-                        $scope.allowEventCreation = true;
-                        if($scope.repeatableStages.indexOf(ps) === -1){
-                            $scope.repeatableStages.push(ps);
+                    ProgramStageFactory.get(dhis2Event.programStage).then(function(stage){
+                        //check if a stage is repeatable
+                        if(stage.repeatable){
+                            $scope.allowEventCreation = true;
+                            if($scope.repeatableStages.indexOf(stage) === -1){
+                                $scope.repeatableStages.push(stage);
+                            }
                         }
-                    }
-                            
-                    dhis2Event.name = ps.name;
+
+                        dhis2Event.name = stage.name;
+                    });
+                    
                     dhis2Event.eventDate = moment(dhis2Event.eventDate, 'YYYY-MM-DD')._d;
                     dhis2Event.eventDate = Date.parse(dhis2Event.eventDate);
                     dhis2Event.eventDate = $filter('date')(dhis2Event.eventDate, 'yyyy-MM-dd');
@@ -101,8 +105,8 @@
                     }                                                             
                 });
 
-                $scope.dhis2Events = orderByFilter($scope.dhis2Events, '-eventDate');
-                $scope.dhis2Events.reverse();              
+                //$scope.dhis2Events = orderByFilter($scope.dhis2Events, '-eventDate');
+                //$scope.dhis2Events.reverse();              
             });          
         }
     });
@@ -112,29 +116,39 @@
     };
     
     $scope.showDataEntry = function(event){
-        
         if(event){
             
             $scope.currentEvent = event;
             $scope.currentEvent.providedElsewhere = [];
             $scope.currentEvent.dataValues = [];
-            $scope.currentStage = storage.get($scope.currentEvent.programStage); 
+            
+            ProgramStageFactory.get($scope.currentEvent.programStage).then(function(stage){
+                $scope.currentStage = stage;
            
-            angular.forEach($scope.currentStage.programStageDataElements, function(prStDe){
-                $scope.currentStage.programStageDataElements[prStDe.dataElement.id] = prStDe.dataElement;
-                if(prStDe.allowProvidedElsewhere){
-                    $scope.currentEvent.providedElsewhere[prStDe.dataElement.id] = '';   
-                }                
-            });
-            
-            angular.forEach($scope.currentEvent.dataValues, function(dataValue){
-                var val = dataValue.value;
-                var de = $scope.currentStage.programStageDataElements[dataValue.dataElement];
-                if( de && de.type === 'int' && val){
-                    val = parseInt(val);
-                    dataValue.value = val;
-                }                   
-            });     
-        }     
+                angular.forEach($scope.currentStage.programStageDataElements, function(prStDe){
+                    $scope.currentStage.programStageDataElements[prStDe.dataElement.id] = prStDe.dataElement;
+                    if(prStDe.allowProvidedElsewhere){
+                        $scope.currentEvent.providedElsewhere[prStDe.dataElement.id] = '';   
+                    }                
+                });
+
+                angular.forEach($scope.currentEvent.dataValues, function(dataValue){
+                    var val = dataValue.value;
+                    var de = $scope.currentStage.programStageDataElements[dataValue.dataElement];
+                    if( de && de.type === 'int' && val){
+                        val = parseInt(val);
+                        dataValue.value = val;
+                    }
+                });
+            });                 
+        }
     };    
+    
+    $scope.savePatientDatavalue = function(currentEvent, dataElement){
+        
+        $scope.updateSuccess = false;
+        
+        //get the dataelement whose value is being saved/updated
+        $scope.currentDataElement = {id: dataElement};
+    };
 });
\ No newline at end of file

=== modified file 'dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/components/dataentry/dataentry.html'
--- dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/components/dataentry/dataentry.html	2014-05-27 12:38:36 +0000
+++ dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/components/dataentry/dataentry.html	2014-06-06 13:35:06 +0000
@@ -14,12 +14,12 @@
             <tbody>
                 <tr>
                     <td class="inline-block" ng-repeat="dhis2Event in dhis2Events track by $index">
-                        <span class="block orgunit-container">{{dhis2Event.orgUnitName}}</span>                                              
+                        <span class="block align-center">{{dhis2Event.orgUnitName}}</span>                                              
                         <span class="stage-container"                                                     
-                              ng-class="{'current-stage': currentEvent.programStage == dhis2Event.programStage, '{{dhis2Event.statusColor}}': true}"                                                      
+                              ng-class="{'current-stage': currentEvent && currentEvent.event == dhis2Event.event, '{{dhis2Event.statusColor}}': true}"                                                      
                               ng-click="showDataEntry(dhis2Event)">
                             {{dhis2Event.name}}<br/>
-                            {{dhis2Event.eventDate}}                                                    
+                            {{dhis2Event.eventDate}}         
                         </span>
                         <i class="fa fa-arrow-right" ng-show="$index < dhis2Events.length-1"></i>
                     </td>                        
@@ -29,15 +29,15 @@
         <hr>
         <div ng-show="currentEvent">
             <table class="table-borderless table-striped">
-                <thead>
+                <thead class="align-center">
                     <tr>
-                        <th>
+                        <th class="align-center">
                             {{'data_element' | translate}}
                         </th>
-                        <th>
+                        <th class="align-center">
                             {{'value' | translate}}
                         </th>
-                        <th>
+                        <th class="align-center">
                             {{'provided_elsewhere' | translate}}
                         </th>
                     </tr>
@@ -53,7 +53,8 @@
                                 <input type="number"
                                        class="form-control"
                                        ng-model="currentEvent[prStDe.dataElement.id]" 
-                                       ng-required={{prStDe.compulsory}} 
+                                       ng-required={{prStDe.compulsory}}
+                                       ng-blur="savePatientDatavalue(currentEvent, prStDe.dataElement.id)" 
                                        name="foo"/>
                             </div>
                             <div ng-switch-when="string">                                        
@@ -62,13 +63,15 @@
                                        ng-model="currentEvent[prStDe.dataElement.id]" 
                                        ng-required={{prStDe.compulsory}} 
                                        typeahead="option for option in prStDe.dataElement.optionSet.options | filter:$viewValue | limitTo:20" 
-                                       typeahead-open-on-focus                                                        
+                                       typeahead-open-on-focus    
+                                       ng-blur="savePatientDatavalue(currentEvent, prStDe.dataElement.id)" 
                                        name="foo"/>
                             </div>
                             <div ng-switch-when="bool">
                                 <select class="form-control"
                                         ng-model="currentEvent[prStDe.dataElement.id]" 
                                         ng-required={{prStDe.compulsory}} 
+                                        ng-change="savePatientDatavalue(currentEvent, prStDe.dataElement.id)" 
                                         name="foo">
                                     <option value="">{{'please_select'| translate}}</option>                        
                                     <option value="0">{{'no'| translate}}</option>
@@ -81,16 +84,19 @@
                                        placeholder="yyyy-mm-dd" 
                                        ng-date 
                                        class="form-control"
-                                       ng-model="currentEvent[prStDe.dataElement.id]" 
+                                       ng-model="savePatientDatavalue(currentEvent, prStDe.dataElement.id)" 
                                        ng-required={{prStDe.compulsory}}  
+                                       blur-or-change="savePatientDatavalue(dhis2Event, eventGridColumn.id)"
                                        name="foo"/>
                             </div>
                         </div>
                     </td>
                     <td>                        
-                        <span ng-if="prStDe.allowProvidedElsewhere">
-                            <input type="checkbox" ng-model="currentEvent.providedElsewhere[prStDe.dataElement.id]"/>
-                        </span>
+                        <div class="align-center" ng-if="prStDe.allowProvidedElsewhere">
+                            <input type="checkbox" 
+                                   ng-model="currentEvent.providedElsewhere[prStDe.dataElement.id]"
+                                   ng-change="savePatientDatavalue(currentEvent, prStDe.dataElement.id)"/>
+                        </div>
                     </td>
                 </tr>
             </table>    

=== modified file 'dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/components/enrollment/enrollment-controller.js'
--- dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/components/enrollment/enrollment-controller.js	2014-05-28 15:31:32 +0000
+++ dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/components/enrollment/enrollment-controller.js	2014-06-06 13:35:06 +0000
@@ -4,6 +4,7 @@
                 $filter,
                 storage,
                 ProgramFactory,
+                ProgramStageFactory,
                 AttributesFactory,
                 CurrentSelection,
                 TEIService,
@@ -26,41 +27,39 @@
     $scope.$on('selectedEntity', function(event, args) {   
         $scope.newEnrollment = {};
         var selections = CurrentSelection.get();
-        $scope.selectedEntity = selections.tei;      
-        
+        $scope.selectedEntity = selections.tei;        
         $scope.selectedOrgUnit = storage.get('SELECTED_OU');
         
-        angular.forEach(ProgramFactory.getAll(), function(program){
-            if(program.organisationUnits.hasOwnProperty($scope.selectedOrgUnit.id) &&
-               program.trackedEntity.id === $scope.selectedEntity.trackedEntity){
-                $scope.programs.push(program);
-            }
-        });
-        
-        EnrollmentService.get($scope.selectedEntity.trackedEntityInstance).then(function(data){
-            $scope.enrollments = data.enrollmentList;  
-            if(selections.pr){       
-                angular.forEach($scope.programs, function(program){
-                    if(selections.pr === program.id){
-                        $scope.selectedProgram = program;
-                        $scope.loadEvents();
-                    }
-                });
-            }
+        ProgramFactory.getAll().then(function(programs){  
             
-            CurrentSelection.set({tei: $scope.selectedEntity, pr: $scope.selectedProgram.id});
-            $rootScope.$broadcast('dashboard', {selectedEntity: $scope.selectedEntity,
-                                                selectedOrgUnit: $scope.selectedOrgUnit,
-                                                selectedProgramId: $scope.selectedProgram.id,
-                                                selectedEnrollment: $scope.selectedEnrollment});
+            angular.forEach(programs, function(program){
+                if(program.organisationUnits.hasOwnProperty($scope.selectedOrgUnit.id) &&
+                   program.trackedEntity.id === $scope.selectedEntity.trackedEntity){
+                    $scope.programs.push(program);
+                }
+            });
+
+            EnrollmentService.get($scope.selectedEntity.trackedEntityInstance).then(function(data){
+                $scope.enrollments = data.enrollmentList;  
+                if(selections.pr){   
+                    angular.forEach($scope.programs, function(program){
+                        if(selections.pr.id === program.id){
+                            $scope.selectedProgram = program;
+                            $scope.loadEvents();
+                        }
+                    });
+                }
+
+                CurrentSelection.set({tei: $scope.selectedEntity, pr: $scope.selectedProgram, enrollment: $scope.selectedEnrollment});
+                $rootScope.$broadcast('dashboard', {});
+            });                           
         });        
-        
     }); 
     
     $scope.loadEvents = function() {
         
         if($scope.selectedProgram){
-           
+          
             //check for possible enrollment
             $scope.selectedEnrollment = '';
             angular.forEach($scope.enrollments, function(enrollment){
@@ -73,34 +72,43 @@
                 $scope.selectedEnrollment.dateOfIncident = $filter('date')($scope.selectedEnrollment.dateOfIncident, 'yyyy-MM-dd');
             }
             else{//prepare for possible enrollment
-                $scope.attributesForEnrollment = AttributesFactory.getMissingAttributesForEnrollment($scope.selectedEntity, $scope.selectedProgram);
+                AttributesFactory.getByProgram($scope.selectedProgram).then(function(atts){
+                    
+                    $scope.attributesForEnrollment = [];
+                    for(var i=0; i<atts.length; i++){
+                        var exists = false;
+                        for(var j=0; j<$scope.selectedEntity.attributes.length && !exists; j++){
+                            if(atts[i].id === $scope.selectedEntity.attributes[j].attribute){
+                                exists = true;
+                            }
+                        }
+                        if(!exists){
+                            $scope.attributesForEnrollment.push(atts[i]);
+                        }
+                    }
+                });                
             }
 
             $scope.programStages = [];   
             var incidentDate = $scope.selectedEnrollment ? $scope.selectedEnrollment.dateOfIncident : new Date();
             
-            angular.forEach($scope.selectedProgram.programStages, function(stage){                
-                var ps = storage.get(stage.id);
-                ps.dueDate = moment(moment(incidentDate).add('d', ps.minDaysFromStart), 'YYYY-MM-DD')._d;
-                ps.dueDate = Date.parse(ps.dueDate);
-                ps.dueDate= $filter('date')(ps.dueDate, 'yyyy-MM-dd');
-                $scope.programStages.push(ps);               
+            ProgramStageFactory.getByProgram($scope.selectedProgram).then(function(stages){
+                angular.forEach(stages, function(stage){                
+                    stage.dueDate = moment(moment(incidentDate).add('d', stage.minDaysFromStart), 'YYYY-MM-DD')._d;
+                    stage.dueDate = Date.parse(stage.dueDate);
+                    stage.dueDate= $filter('date')(stage.dueDate, 'yyyy-MM-dd');
+                    $scope.programStages.push(stage);               
+                });                
             });
-            
-            CurrentSelection.set({tei: $scope.selectedEntity, pr: $scope.selectedProgram.id});
-            $rootScope.$broadcast('dashboard', {selectedEntity: $scope.selectedEntity,
-                                                selectedOrgUnit: $scope.selectedOrgUnit,
-                                                selectedProgramId: $scope.selectedProgram.id,
-                                                selectedEnrollment: $scope.selectedEnrollment});
+
+            CurrentSelection.set({tei: $scope.selectedEntity, pr: $scope.selectedProgram, enrollment: $scope.selectedEnrollment});
+            $rootScope.$broadcast('dashboard', {});
         }
         else{
             $scope.selectedProgram = '';
             $scope.selectedEnrollment = '';
-            CurrentSelection.set({tei: $scope.selectedEntity, pr: $scope.selectedProgram.id});
-            $rootScope.$broadcast('dashboard', {selectedEntity: $scope.selectedEntity,
-                                                selectedOrgUnit: $scope.selectedOrgUnit,
-                                                selectedProgramId: $scope.selectedProgram.id,
-                                                selectedEnrollment: $scope.selectedEnrollment});
+            CurrentSelection.set({tei: $scope.selectedEntity, pr: $scope.selectedProgram, enrollment: $scope.selectedEnrollment});
+            $rootScope.$broadcast('dashboard', {});
         }
     };
         
@@ -120,7 +128,6 @@
         //get enrollment attributes and their values - new attributes because of enrollment
         angular.forEach($scope.attributesForEnrollment, function(attribute){
             if(!angular.isUndefined(attribute.value)){
-                //$scope.selectedEntity.attributes.push({attribute: attribute.id, value: attribute.value, type: attribute.valueType, displayName: attribute.name});
                 tei.attributes.push({attribute: attribute.id, value: attribute.value});
             } 
         });

=== modified file 'dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/components/enrollment/enrollment.html'
--- dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/components/enrollment/enrollment.html	2014-05-28 13:36:26 +0000
+++ dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/components/enrollment/enrollment.html	2014-06-06 13:35:06 +0000
@@ -115,7 +115,7 @@
                                 <option value="1">{{'yes'| translate}}</option>
                             </select>
                         </div>
-                        <div ng-switch-when="combo">
+                        <div ng-switch-when="optionSet">
                             <input type="text" 
                                    class="form-control"
                                    ng-model="attribute.value"                                                 

=== modified file 'dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/components/profile/profile-controller.js'
--- dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/components/profile/profile-controller.js	2014-05-28 15:20:11 +0000
+++ dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/components/profile/profile-controller.js	2014-06-06 13:35:06 +0000
@@ -12,23 +12,18 @@
     $scope.attributes = {};    
     $scope.editProfile = false;    
     
-    angular.forEach(storage.get('ATTRIBUTES'), function(attribute){
-        $scope.attributes[attribute.id] = attribute;
+    AttributesFactory.getAll().then(function(atts){
+        angular.forEach(atts, function(att){
+            $scope.attributes[att.id] = att;
+        }); 
     }); 
     
-    //listen for the selected entity
-    /*$scope.$on('selectedEntity', function(event, args) { 
-        var selections = CurrentSelection.get();
-        $scope.selectedEntity = selections.tei; 
-        $scope.selectedProgram = selections.pr ? storage.get(selections.pr) : null;        
-        $scope.getTei();
-        
-    });*/
-    
+    //listen for the selected entity       
     $scope.$on('dashboard', function(event, args) { 
         var selections = CurrentSelection.get();
         $scope.selectedEntity = selections.tei; 
-        $scope.selectedProgram = selections.pr ? storage.get(selections.pr) : null; 
+        $scope.selectedProgram = selections.pr; 
+
         $scope.processTeiAttributes();
         
     });
@@ -36,9 +31,7 @@
     //display only those attributes that belong the selected program
     //if no program, display attributesInNoProgram
     $scope.processTeiAttributes = function(){
-        
-        $scope.entityAttributes = angular.copy($scope.selectedEntity.attributes);
-        
+       
         angular.forEach(storage.get('TRACKED_ENTITIES'), function(te){
             if($scope.selectedEntity.trackedEntity === te.id){
                 $scope.trackedEntity = te;
@@ -49,12 +42,42 @@
             if(att.type === 'number' && !isNaN(parseInt(att.value))){
                 att.value = parseInt(att.value);
             }
-        }); 
+        });
         
-        $scope.selectedEntity.attributes = AttributesFactory.hideAttributesNotInProgram($scope.selectedEntity, $scope.selectedProgram);
+        if($scope.selectedProgram){
+            //show only those attributes in selected program            
+            AttributesFactory.getByProgram($scope.selectedProgram).then(function(atts){
+                for(var i=0; i<$scope.selectedEntity.attributes.length; i++){
+                    $scope.selectedEntity.attributes[i].show = false;
+                    var processed = false;
+                    for(var j=0; j<atts.length && !processed; j++){
+                        if($scope.selectedEntity.attributes[i].attribute === atts[j].id){
+                            processed = true;
+                            $scope.selectedEntity.attributes[i].show = true;
+                        }
+                    }                                   
+                }
+            }); 
+        }
+        else{
+            //show attributes in no program
+            AttributesFactory.getWithoutProgram().then(function(atts){
+                for(var i=0; i<$scope.selectedEntity.attributes.length; i++){
+                    $scope.selectedEntity.attributes[i].show = false;
+                    var processed = false;
+                    for(var j=0; j<atts.length && !processed; j++){
+                        if($scope.selectedEntity.attributes[i].attribute === atts[j].id){
+                            processed = true;
+                            $scope.selectedEntity.attributes[i].show = true;
+                        }
+                    }                                   
+                }
+            });
+        }              
     };
     
     $scope.enableEdit = function(){
+        $scope.entityAttributes = angular.copy($scope.selectedEntity.attributes);
         $scope.editProfile = !$scope.editProfile; 
     };
     

=== modified file 'dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/components/profile/profile.html'
--- dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/components/profile/profile.html	2014-05-28 15:20:11 +0000
+++ dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/components/profile/profile.html	2014-06-06 13:35:06 +0000
@@ -29,7 +29,7 @@
                             <option value="1">{{'yes'| translate}}</option>
                         </select>
                     </div>
-                    <div ng-switch-when="combo">
+                    <div ng-switch-when="optionSet">
                         <input type="text"  
                                class="form-control"
                                ng-model="attribute.value"                                                 

=== modified file 'dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/components/registration/registration-controller.js'
--- dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/components/registration/registration-controller.js	2014-05-27 14:50:29 +0000
+++ dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/components/registration/registration-controller.js	2014-06-06 13:35:06 +0000
@@ -2,6 +2,7 @@
         function($scope,
                 $location,
                 AttributesFactory,
+                TEService,
                 TEIService,
                 EnrollmentService,
                 DialogService,
@@ -12,19 +13,25 @@
     TranslationService.translate();   
     
     $scope.selectedOrgUnit = storage.get('SELECTED_OU');
-    $scope.enrollment = {enrollmentDate: '', incidentDate: ''};    
+    $scope.enrollment = {enrollmentDate: '', incidentDate: ''};   
     
-    $scope.attributes = AttributesFactory.getWithoutProgram();
+    AttributesFactory.getWithoutProgram().then(function(atts){
+        $scope.attributes = atts;
+    });
+            
     $scope.trackedEntities = {available: []};
-    $scope.trackedEntities.available = storage.get('TRACKED_ENTITIES');
-   
-    $scope.trackedEntities.selected = $scope.trackedEntities.available[0];
-      
+    TEService.getAll().then(function(entities){
+        $scope.trackedEntities.available = entities;   
+        $scope.trackedEntities.selected = $scope.trackedEntities.available[0];
+    });
+    
     //watch for selection of org unit from tree
     $scope.$watch('selectedProgram', function() {        
         if( angular.isObject($scope.selectedProgram)){
             $scope.trackedEntityList = [];
-            $scope.attributes = AttributesFactory.getByProgram($scope.selectedProgram);
+            AttributesFactory.getByProgram($scope.selectedProgram).then(function(atts){
+                $scope.attributes = atts;
+            });
         }
     });    
     

=== modified file 'dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/components/relationship/relationship-controller.js'
--- dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/components/relationship/relationship-controller.js	2014-05-27 12:38:36 +0000
+++ dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/components/relationship/relationship-controller.js	2014-06-06 13:35:06 +0000
@@ -1,8 +1,7 @@
 trackerCapture.controller('RelationshipController',
-        function($scope,                
-                storage,
+        function($scope,
                 TranslationService) {
 
     TranslationService.translate();    
-    $scope.attributes = storage.get('ATTRIBUTES');    
+     
 });
\ No newline at end of file

=== modified file 'dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/components/selected/selected-controller.js'
--- dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/components/selected/selected-controller.js	2014-05-27 12:38:36 +0000
+++ dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/components/selected/selected-controller.js	2014-06-06 13:35:06 +0000
@@ -1,6 +1,7 @@
 trackerCapture.controller('SelectedInfoController',
         function($scope,                
                 storage,
+                CurrentSelection,
                 TranslationService) {
 
     TranslationService.translate();
@@ -8,13 +9,9 @@
     //listen for the selected items
     $scope.$on('selectedEntity', function(event, args) {
         
-        $scope.selectedEntity = args.selectedEntity;
-        $scope.selectedProgramId = args.selectedProgramId;        
-        $scope.selectedOrgUnitId = args.selectedOrgUnitId;        
-        
-        if($scope.selectedProgramId){
-            $scope.selectedProgram = storage.get($scope.selectedProgramId);        
-        }
+        var selections = CurrentSelection.get();
+        $scope.selectedEntity = selections.tei; 
+        $scope.selectedProgram = selections.pr; 
         
         $scope.selectedOrgUnit = storage.get('SELECTED_OU');
         $scope.selections = [];

=== modified file 'dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/index.html'
--- dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/index.html	2014-05-27 14:50:29 +0000
+++ dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/index.html	2014-06-06 13:35:06 +0000
@@ -26,8 +26,8 @@
         <script type="text/javascript" src="../dhis-web-commons/javascripts/angular/angular-animate.js"></script>        
         <script type="text/javascript" src="../dhis-web-commons/javascripts/angular/ui-bootstrap-tpls-0.10.0-draggable-modal.js"></script>
 
-        <script type="text/javascript" src="../dhis-web-commons/javascripts/moment/moment-with-langs.min.js"></script>       
-
+        <script type="text/javascript" src="../dhis-web-commons/javascripts/moment/moment-with-langs.min.js"></script>
+        
         <script type="text/javascript" src="../dhis-web-commons/javascripts/underscore.min.js"></script>
         <script type="text/javascript" src="../dhis-web-commons/javascripts/dhis2/dhis2.util.js"></script>
         <script type="text/javascript" src="../dhis-web-commons/javascripts/commons.js"></script>
@@ -81,6 +81,8 @@
         <link type="text/css" rel="stylesheet" media="screen" href="../dhis-web-commons/css/menu.css">
         
         <link type="text/css" rel="stylesheet" href="styles/style.css">
+        
+        <script type="text/javascript" src="../main.js"></script>
        
     </head>
     <body>

=== modified file 'dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/scripts/app.js'
--- dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/scripts/app.js	2014-05-14 13:04:39 +0000
+++ dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/scripts/app.js	2014-06-06 13:35:06 +0000
@@ -16,6 +16,8 @@
               
 .value('DHIS2URL', '..')
 
+
+
 .config(function($httpProvider, $routeProvider, $translateProvider) {    
             
     $httpProvider.defaults.useXDomain = true;

=== modified file 'dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/scripts/controllers.js'
--- dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/scripts/controllers.js	2014-05-28 15:31:32 +0000
+++ dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/scripts/controllers.js	2014-06-06 13:35:06 +0000
@@ -50,9 +50,7 @@
     $scope.showRegistrationDiv = false;
     
     //watch for selection of org unit from tree
-    $scope.$watch('selectedOrgUnit', function() {
-        
-        $scope.attributes = AttributesFactory.getWithoutProgram();    
+    $scope.$watch('selectedOrgUnit', function() {           
         
         if( angular.isObject($scope.selectedOrgUnit)){   
             
@@ -63,9 +61,13 @@
             
             //apply translation - by now user's profile is fetched from server.
             TranslationService.translate();
-            $scope.loadPrograms($scope.selectedOrgUnit);            
-            $scope.search($scope.searchMode.listAll);
-            
+            
+            $scope.loadPrograms($scope.selectedOrgUnit); 
+            
+            AttributesFactory.getWithoutProgram().then(function(atts){
+                $scope.attributes = atts;
+                $scope.search($scope.searchMode.listAll);
+            });           
         }
     });
     
@@ -78,39 +80,41 @@
         
         if (angular.isObject($scope.selectedOrgUnit)) {   
 
-            $scope.programs = [];
-            
-            var programs = ProgramFactory.getAll();
-            
-            if( programs && programs != 'undefined' ){
-                angular.forEach(programs, function(program){
-                    if(angular.isObject(program)){
-                        if(program.organisationUnits.hasOwnProperty(orgUnit.id)){
-                            $scope.programs.push(program);
-                        }
+            ProgramFactory.getAll().then(function(programs){
+                $scope.programs = [];
+                angular.forEach(programs, function(program){                            
+                    if(program.organisationUnits.hasOwnProperty($scope.selectedOrgUnit.id)){                                
+                        $scope.programs.push(program);
                     }
-                });                
+                });
                 
-                if( !angular.isUndefined($scope.programs)){                    
-                    if($scope.programs.length === 1){
-                        $scope.selectedProgram = $scope.programs[0];
-                        $scope.pr = $scope.selectedProgram;    
-                        $scope.attributes = AttributesFactory.getByProgram($scope.selectedProgram);
-                    }                    
-                }
-            }
+                if(angular.isObject($scope.programs) && $scope.programs.length === 1){
+                    $scope.selectedProgram = $scope.programs[0];
+                    
+                    AttributesFactory.getByProgram($scope.selectedProgram).then(function(atts){
+                        $scope.attributes = atts;
+                        $scope.generateGridColumns($scope.attributes);
+                    });
+                }                
+            });
         }        
     };
     
     $scope.getProgramAttributes = function(program, doSearch){ 
         $scope.trackedEntityList = null; 
         $scope.selectedProgram = program;
-        
+       
         if($scope.selectedProgram){
-            $scope.attributes = AttributesFactory.getByProgram($scope.selectedProgram);
+            AttributesFactory.getByProgram($scope.selectedProgram).then(function(atts){
+                $scope.attributes = atts;
+                $scope.gridColumns = $scope.generateGridColumns($scope.attributes);
+            });           
         }
         else{
-            $scope.attributes = AttributesFactory.getWithoutProgram();
+            AttributesFactory.getWithoutProgram().then(function(atts){
+                $scope.attributes = atts;
+                $scope.gridColumns = $scope.generateGridColumns($scope.attributes);
+            });
         }
         
         if(doSearch){
@@ -119,7 +123,7 @@
     };
     
     $scope.search = function(mode){ 
-        
+
         $scope.emptySearchText = false;
         $scope.emptySearchAttribute = false;
         $scope.showSearchDiv = false;
@@ -157,7 +161,7 @@
         else if( mode === $scope.searchMode.listAll ){   
             $scope.showTrackedEntityDiv = true;    
         }      
-        
+
         $scope.gridColumns = $scope.generateGridColumns($scope.attributes);
 
         //get events for the specified parameters
@@ -172,7 +176,7 @@
     
     //generate grid columns from teilist attributes
     $scope.generateGridColumns = function(attributes){
-        var columns = angular.copy(attributes);  
+        var columns = attributes ? angular.copy(attributes) : [];
        
         //also add extra columns which are not part of attributes (orgunit for example)
         columns.push({id: 'orgUnitName', name: 'Organisation unit', type: 'string', displayInListNoProgram: false});
@@ -251,7 +255,7 @@
         });
     };
     
-    $scope.showDashboard = function(currentEntity){        
+    $scope.showDashboard = function(currentEntity){   
         $location.path('/dashboard').search({selectedEntityId: currentEntity.id,                                            
                                             selectedProgramId: $scope.selectedProgram ? $scope.selectedProgram.id: null});                                    
     };
@@ -297,7 +301,8 @@
                 $modal,
                 $timeout,
                 storage,
-                TEIService,      
+                TEIService,  
+                ProgramFactory,
                 CurrentSelection,
                 TranslationService) {
 
@@ -306,7 +311,7 @@
     
     //dashboard items   
     $rootScope.dashboardWidgets = {bigger: [], smaller: []};       
-    $rootScope.enrollmentWidget = {title: 'enrollment', view: "components/enrollment/enrollment.html", show: true};
+    $rootScope.enrollmentWidget = {title: 'program', view: "components/enrollment/enrollment.html", show: true};
     $rootScope.dataentryWidget = {title: 'dataentry', view: "components/dataentry/dataentry.html", show: true};
     $rootScope.selectedWidget = {title: 'current_selections', view: "components/selected/selected.html", show: false};
     $rootScope.profileWidget = {title: 'profile', view: "components/profile/profile.html", show: true};
@@ -327,24 +332,30 @@
     $scope.selectedEntityId = ($location.search()).selectedEntityId; 
     $scope.selectedProgramId = ($location.search()).selectedProgramId; 
     $scope.selectedOrgUnit = storage.get('SELECTED_OU');
-    
-    if($scope.selectedProgramId && storage.get($scope.selectedProgramId)){
-        $scope.selectedProgram = storage.get($scope.selectedProgramId);
-    }
-    else{
-        $scope.selectedProgram = null;
-    }
         
     if( $scope.selectedEntityId ){
-        
+      
         //Fetch the selected entity
-        TEIService.get($scope.selectedEntityId).then(function(data){              
-            CurrentSelection.set({tei: data, pr: $scope.selectedProgram ? $scope.selectedProgram.id : null});
-         
-            //broadcast selected entity for dashboard controllers
-            $timeout(function() { 
-                $rootScope.$broadcast('selectedEntity', {});
-            }, 100);
+        TEIService.get($scope.selectedEntityId).then(function(data){     
+            
+            if($scope.selectedProgramId){
+                ProgramFactory.get($scope.selectedProgramId).then(function(program){
+                    $scope.selectedProgram = program;   
+                    
+                    //broadcast selected items for dashboard controllers
+                    CurrentSelection.set({tei: data, pr: $scope.selectedProgram});
+                    $timeout(function() { 
+                        $rootScope.$broadcast('selectedEntity', {});
+                    }, 100);
+                });
+            }
+            else{                
+                //broadcast selected items for dashboard controllers
+                CurrentSelection.set({tei: data, pr: ''});
+                $timeout(function() { 
+                    $rootScope.$broadcast('selectedEntity', {});
+                }, 100);
+            }
         });       
     }   
     
@@ -372,15 +383,6 @@
     };
 })
 
-//Controller for the profile section
-
-
-//Controller for the enrollment section
-
-
-//Controller for the data entry section
-
-
 //Controller for the dashboard widgets
 .controller('DashboardWidgetsController', 
     function($scope, 
@@ -394,15 +396,6 @@
     };       
 })
 
-//Controller for the relationship section
-
-
-//Controller for the notes section
-
-
-//Controller for the selected section
-
-
 //Controller for the header section
 .controller('HeaderController',
         function($scope,                

=== modified file 'dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/scripts/directives.js'
--- dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/scripts/directives.js	2014-05-27 12:38:36 +0000
+++ dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/scripts/directives.js	2014-06-06 13:35:06 +0000
@@ -23,6 +23,49 @@
         restrict: 'A',        
         link: function(scope, element, attrs){  
             
+            //when tree has loaded, get selected orgunit - if there is any - and inform angular           
+            $(function() {                 
+                
+                var adapters = [];
+                var partial_adapters = [];
+
+                if( dhis2.ou.memoryOnly ) {
+                    adapters = [ dhis2.storage.InMemoryAdapter ];
+                    partial_adapters = [ dhis2.storage.InMemoryAdapter ];
+                } else {
+                    adapters = [ dhis2.storage.IndexedDBAdapter, dhis2.storage.DomLocalStorageAdapter, dhis2.storage.InMemoryAdapter ];
+                    partial_adapters = [ dhis2.storage.IndexedDBAdapter, dhis2.storage.DomSessionStorageAdapter, dhis2.storage.InMemoryAdapter ];
+                }
+
+                dhis2.ou.store = new dhis2.storage.Store({
+                    name: OU_STORE_NAME,
+                    objectStores: [
+                        {
+                            name: OU_KEY,
+                            adapters: adapters
+                        },
+                        {
+                            name: OU_PARTIAL_KEY,
+                            adapters: partial_adapters
+                        }
+                    ]
+                });
+
+                dhis2.ou.store.open().done( function() {
+                    selection.load();
+                    $( "#orgUnitTree" ).one( "ouwtLoaded", function() {
+                        var selected = selection.getSelected()[0];
+                        selection.getOrganisationUnit(selected).done(function(data){                            
+                            if( data ){
+                                scope.selectedOrgUnit = {id: selected, name: data[selected].n};
+                                scope.$apply();                                                              
+                            }                        
+                        });
+                    });
+                    
+                });
+            });
+            
             //listen to user selection, and inform angular         
             selection.setListenerFunction( organisationUnitSelected );
             selection.responseReceived();

=== modified file 'dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/scripts/services.js'
--- dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/scripts/services.js	2014-05-28 15:20:11 +0000
+++ dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/scripts/services.js	2014-06-06 13:35:06 +0000
@@ -4,6 +4,17 @@
 
 var trackerCaptureServices = angular.module('trackerCaptureServices', ['ngResource'])
 
+
+.factory('StorageService', function(){
+    var store = new dhis2.storage.Store({
+        name: "dhis2tc",
+        adapters: [dhis2.storage.IndexedDBAdapter, dhis2.storage.DomSessionStorageAdapter, dhis2.storage.InMemoryAdapter],
+        objectStores: ['trackerCapturePrograms', 'programStages', 'trackedEntities','attributes','optionSets']
+    });
+    return{
+        currentStore: store
+    };
+})
 /* factory for loading logged in user profiles from DHIS2 */
 .factory('CurrentUserProfile', function($http) { 
            
@@ -22,71 +33,88 @@
 })
 
 /* Factory to fetch programs */
-.factory('ProgramFactory', function($http, storage) {
-    
-    var programUid, programPromise;
-    var programs, programsPromise;
-    var program;
+.factory('ProgramFactory', function($q, $rootScope, StorageService, ProgramStageFactory) { 
     return {
-        
+        getAll: function(){
+            
+            var def = $q.defer();
+            
+            StorageService.currentStore.open().done(function(){
+                StorageService.currentStore.getAll('trackerCapturePrograms').done(function(programs){
+                    $rootScope.$apply(function(){
+                        def.resolve(programs);
+                    });                    
+                });
+            });            
+            
+            return def.promise;            
+        },
         get: function(uid){
-            if( programUid !== uid ){
-                programPromise = $http.get( '../api/programs/' + uid + '.json?viewClass=detailed&paging=false').then(function(response){
-                    programUid = response.data.id; 
-                    program = response.data;                     
-                    return program;
-                });
-            }
-            return programPromise;
-        },       
-        
-        getMine: function(type){ 
-            if( !programsPromise ){
-                programsPromise = $http.get( '../api/me/programs?includeDescendants=true&type='+type).then(function(response){
-                   programs = response.data;
-                   return programs;
-                });
-            }
-            return programsPromise;    
-        },
-        
-        getEventProgramsByOrgUnit: function(orgUnit, type){
-                       
-            var promise = $http.get(  '../api/programs.json?orgUnit=' + orgUnit + '&type=' + type ).then(function(response){
-                programs = response.data;
-                return programs;
-            });            
-            return promise;
-        },
-        getAll: function(){
-            var programs = [];
-            angular.forEach(storage.get('TRACKER_PROGRAMS'), function(p){
-                programs.push(storage.get(p.id));
-            });
-            return programs;
+            
+            var def = $q.defer();
+            
+            StorageService.currentStore.open().done(function(){
+                StorageService.currentStore.get('trackerCapturePrograms', uid).done(function(pr){                    
+                    $rootScope.$apply(function(){
+                        def.resolve(pr);
+                    });
+                });
+            });                        
+            return def.promise;            
         }
     };
 })
 
 /* Factory to fetch programStages */
-.factory('ProgramStageFactory', function($http, storage) {  
+.factory('ProgramStageFactory', function($q, $rootScope, StorageService) {  
     
-    var programStage, promise;   
     return {        
-        get: function(uid){
-            if( programStage !== uid ){
-                promise = $http.get(  '../api/programStages/' + uid + '.json?viewClass=detailed&paging=false').then(function(response){
-                   programStage = response.data.id;
-
-                   //store locally - might need them for event data values
-                   angular.forEach(response.data.programStageDataElements, function(prStDe){      
-                       storage.set(prStDe.dataElement.id, prStDe);                       
-                   });
-                   
-                   return response.data;
+        get: function(uid){            
+            var def = $q.defer();
+            StorageService.currentStore.open().done(function(){
+                StorageService.currentStore.get('programStages', uid).done(function(pst){                    
+                    angular.forEach(pst.programStageDataElements, function(pstDe){   
+                        if(pstDe.dataElement.optionSet){
+                            StorageService.currentStore.get('optionSets', pstDe.dataElement.optionSet.id).done(function(optionSet){
+                                pstDe.dataElement.optionSet = optionSet;                                
+                            });                            
+                        }                        
+                    });
+                    $rootScope.$apply(function(){
+                        def.resolve(pst);
+                    });
                 });
-            }
-            return promise;
+            });            
+            return def.promise;
+        },
+        getByProgram: function(program){
+            var def = $q.defer();
+            var stageIds = [];
+            var programStages = [];
+            angular.forEach(program.programStages, function(stage){
+                stageIds.push(stage.id);
+            });
+            
+            StorageService.currentStore.open().done(function(){
+                StorageService.currentStore.getAll('programStages').done(function(stages){   
+                    angular.forEach(stages, function(stage){
+                        if(stageIds.indexOf(stage.id) !== -1){
+                            angular.forEach(stage.programStageDataElements, function(pstDe){   
+                                if(pstDe.dataElement.optionSet){
+                                    StorageService.currentStore.get('optionSets', pstDe.dataElement.optionSet.id).done(function(optionSet){
+                                        pstDe.dataElement.optionSet = optionSet;                                
+                                    });                            
+                                }                            
+                            });
+                            programStages.push(stage);                               
+                        }                        
+                    });                    
+                    $rootScope.$apply(function(){
+                        def.resolve(programStages);
+                    });
+                });                
+            });            
+            return def.promise;
         }
     };    
 })
@@ -159,6 +187,26 @@
 })
 
 /* Service for getting tracked entity instances */
+.factory('TEService', function(StorageService, $q, $rootScope) {
+
+    return {
+        
+        getAll: function(){            
+            var def = $q.defer();
+            
+            StorageService.currentStore.open().done(function(){
+                StorageService.currentStore.getAll('trackedEntities').done(function(entities){
+                    $rootScope.$apply(function(){
+                        def.resolve(entities);
+                    });                    
+                });
+            });            
+            return def.promise;
+        }
+    };
+})
+
+/* Service for getting tracked entity instances */
 .factory('TEIService', function($http, $filter, EntityService) {
     
     var promise;
@@ -241,84 +289,85 @@
 })
 
 /* Factory for getting tracked entity attributes */
-.factory('AttributesFactory', function(storage) { 
-    
+.factory('AttributesFactory', function($q, $rootScope, StorageService) {      
+
     return {
-        getAll: function(){  
-            return storage.get('ATTRIBUTES');
+        getAll: function(){
+            
+            var def = $q.defer();
+            
+            StorageService.currentStore.open().done(function(){
+                StorageService.currentStore.getAll('attributes').done(function(attributes){
+                    angular.forEach(attributes, function(att){
+                        if(att.optionSet){
+                           StorageService.currentStore.get('optionSets', att.optionSet.id).done(function(optionSet){
+                                att.optionSet = optionSet;
+                            });
+                        }
+                        $rootScope.$apply(function(){
+                            def.resolve(attributes);
+                        });
+                    });                    
+                });
+            });            
+            return def.promise;            
         }, 
         getByProgram: function(program){
             
-            if(program){
-                var attributes = [];
-                var programAttributes = [];
+            var attributes = [];
+            var programAttributes = [];
 
-                angular.forEach(this.getAll(), function(attribute){
+            var def = $q.defer();
+            this.getAll().then(function(atts){
+                angular.forEach(atts, function(attribute){
                     attributes[attribute.id] = attribute;
                 });
 
                 angular.forEach(program.programTrackedEntityAttributes, function(pAttribute){
-                   programAttributes.push(attributes[pAttribute.attribute.id]);                
-                }); 
+                    programAttributes.push(attributes[pAttribute.trackedEntityAttribute.id]);                
+                });
                 
-                return programAttributes;            
-            }
-            return this.getWithoutProgram();           
-        },
-        getWithoutProgram: function(){            
-            var attributes = [];
-            
-            angular.forEach(this.getAll(), function(attribute) {
-                if (attribute.displayInListNoProgram) {
-                    attributes.push(attribute);
-                }
-            });           
-
-            return attributes;
-        },
-        convertListingForToQuery: function(){
-            var param = '';
-            angular.forEach(this.getForListing(), function(attribute) {
-                param +=  '&' + 'attribute=' + attribute.id;
+                def.resolve(programAttributes);                                  
             });
+            return def.promise;    
+        },
+        getWithoutProgram: function(){   
             
-            return param;
-        },
+            var def = $q.defer();
+            this.getAll().then(function(atts){
+                var attributes = [];
+                angular.forEach(atts, function(attribute){
+                    if (attribute.displayInListNoProgram) {
+                        attributes.push(attribute);
+                    }
+                });     
+                def.resolve(attributes);             
+            });     
+            return def.promise;
+        },        
         getMissingAttributesForEnrollment: function(tei, program){
-            var programAttributes = this.getByProgram(program);
-            var existingAttributes = tei.attributes;
-            var missingAttributes = [];
-            for(var i=0; i<programAttributes.length; i++){
-                var exists = false;
-                for(var j=0; j<existingAttributes.length && !exists; j++){
-                    if(programAttributes[i].id === existingAttributes[j].attribute){
-                        exists = true;
-                    }
-                }
-                if(!exists){
-                    missingAttributes.push(programAttributes[i]);
-                }
-            }
-            return missingAttributes;
-        },
-        hideAttributesNotInProgram: function(tei, program){
-            var programAttributes = this.getByProgram(program);
-            var teiAttributes = tei.attributes;
-            
-            for(var i=0; i<teiAttributes.length; i++){
-                teiAttributes[i].show = true;
-                var inProgram = false;
-                for(var j=0; j<programAttributes.length && !inProgram; j++){
-                    if(teiAttributes[i].attribute === programAttributes[j].id){
-                        inProgram = true;
-                    }
-                }
-                if(!inProgram){
-                    teiAttributes[i].show = false;
-                }                
-            }            
-            return tei.attributes;
+            var def = $q.defer();
+            this.getByProgram(program).then(function(atts){
+                var programAttributes = atts;
+                var existingAttributes = tei.attributes;
+                var missingAttributes = [];
+                
+                for(var i=0; i<programAttributes.length; i++){
+                    var exists = false;
+                    for(var j=0; j<existingAttributes.length && !exists; j++){
+                        if(programAttributes[i].id === existingAttributes[j].attribute){
+                            exists = true;
+                        }
+                    }
+                    if(!exists){
+                        missingAttributes.push(programAttributes[i]);
+                    }
+                }
+                def.resolve(missingAttributes);
+            });            
+            return def.promise();            
         }
+
     };
 })
 

=== modified file 'dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/scripts/tracker-capture.js'
--- dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/scripts/tracker-capture.js	2014-05-27 12:38:36 +0000
+++ dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/scripts/tracker-capture.js	2014-06-06 13:35:06 +0000
@@ -6,8 +6,7 @@
 // Instance of the StorageManager
 dhis2.tc.storageManager = new StorageManager();
 
-var DAO = DAO || {};
-
+var TC_STORE_NAME = "dhis2tc";
 var i18n_no_orgunits = 'No organisation unit attached to current user, no data entry possible';
 var i18n_offline_notification = 'You are offline, data will be stored locally';
 var i18n_online_notification = 'You are online';
@@ -21,10 +20,10 @@
 
 var TRACKER_VALUES = 'TRACKER_VALUES';
 
-DAO.store = new dhis2.storage.Store({
-    name: 'dhis2',
-    adapters: [dhis2.storage.DomSessionStorageAdapter, dhis2.storage.InMemoryAdapter],
-    objectStores: ['optionSets']
+dhis2.tc.store = new dhis2.storage.Store({
+    name: TC_STORE_NAME,
+    adapters: [dhis2.storage.IndexedDBAdapter, dhis2.storage.DomSessionStorageAdapter, dhis2.storage.InMemoryAdapter],
+    objectStores: ['trackerCapturePrograms', 'programStages', 'trackedEntities','attributes','optionSets']
 });
 
 (function($) {
@@ -56,11 +55,16 @@
     {
         var def = $.Deferred();
         var promise = def.promise();
-
-        promise = promise.then(getUserProfile);
-        promise = promise.then(getAttributes);
-        promise = promise.then(getTrackedEntities);
-        promise = promise.then(getProgramsMetaData);
+        
+        promise = promise.then( dhis2.tc.store.open );
+        promise = promise.then( getUserProfile );
+        promise = promise.then( getAttributes );
+        promise = promise.then( getOptionSetsForAttributes );
+        promise = promise.then( getTrackedEntities );
+        promise = promise.then( getMetaPrograms );     
+        promise = promise.then( getPrograms );     
+        promise = promise.then( getProgramStages );    
+        promise = promise.then( getOptionSetsForPrograms );    
         promise.done(function() {
             selection.responseReceived();
         });
@@ -180,54 +184,6 @@
     return def.promise();
 }
 
-function getProgramsMetaData()
-{
-    var def = $.Deferred();
-
-    $.ajax({
-        url: '../api/programs.json',
-        type: 'GET',
-        data: 'paging=false&filter=type:eq:1&include=id,name,dateOfEnrollmentDescription,dateOfIncidentDescription,displayIncidentDate,ignoreOverdueEvents,realionshipText,trackedEntity[id,name,description],userRoles[id,name],organisationUnits[id,name],programStages[id,name,description,minDaysFromStart,repeatable,programStageDataElements[displayInReports,allowProvidedElsewhere,allowDateInFuture,compulsory,dataElement[id,name,type]]],programTrackedEntityAttributes[displayInList,mandatory,attribute[id,name,description,valueType,displayInListNoProgram,inherit,optionSet[id,name,options]]]'
-    }).done(function(response) {
-        var programs = [];
-        _.each(_.values(response.programs), function(p) {
-            var programForListing = {id: p.id, name: p.name};
-            programs.push(programForListing);           
-            
-            var programForStorage = _.clone(p); 
-            
-            //save program stages
-            programForStorage.programStages = [];
-            _.each(_.values(p.programStages), function(ps){
-                localStorage[ps.id] = JSON.stringify(ps);
-                programForStorage.programStages.push({id: ps.id, name: ps.name});
-            });
-            
-            var ou = {};
-            _.each(_.values(programForStorage.organisationUnits), function(o) {
-                ou[o.id] = o.name;
-            });
-
-            programForStorage.organisationUnits = ou;
-
-            var ur = {};
-            _.each(_.values(programForStorage.userRoles), function(u) {
-                ur[u.id] = u.name;
-            });
-
-            programForStorage.userRoles = ur;            
-            
-            localStorage[programForStorage.id] = JSON.stringify(programForStorage);
-            
-        });
-        
-        localStorage[PROGRAMS_METADATA] = JSON.stringify(programs);
-        def.resolve(response.programs);
-    });
-
-    return def.promise();
-}
-
 function getAttributes()
 {
     var def = $.Deferred();
@@ -235,13 +191,58 @@
     $.ajax({
         url: '../api/trackedEntityAttributes.json',
         type: 'GET',
-        data: 'paging=false&include=id,name,description,valueType,inherit,displayOnVisitSchedule,displayInListNoProgram,unique,optionSet[id,name,options]'
+        data: 'paging=false&include=id,name,version,description,valueType,inherit,displayOnVisitSchedule,displayInListNoProgram,unique,optionSet[id,version]'
     }).done(function(response) {
-        localStorage['ATTRIBUTES'] = JSON.stringify(response.trackedEntityAttributes);
+        dhis2.tc.store.setAll( 'attributes', response.trackedEntityAttributes );        
+        def.resolve(response.trackedEntityAttributes);        
+    });
+
+    return def.promise();
+}
+
+function getOptionSetsForAttributes( attributes )
+{
+    if( !attributes ){
+        return;
+    }
+    
+    var mainDef = $.Deferred();
+    var mainPromise = mainDef.promise();
+
+    var def = $.Deferred();
+    var promise = def.promise();
+
+    var builder = $.Deferred();
+    var build = builder.promise();    
+
+    _.each( _.values( attributes ), function ( attribute ) {
+        if( attribute.optionSet && attribute.optionSet.id ){
+            build = build.then(function() {
+                var d = $.Deferred();
+                var p = d.promise();
+                dhis2.tc.store.get('optionSets', attribute.optionSet.id).done(function(obj) {                    
+                    if(!obj || obj.version !== attribute.optionSet.version) {
+                        promise = promise.then( getOptionSet( attribute.optionSet.id ) );
+                    }
+                    d.resolve();
+                });
+
+                return p;
+            });
+        }                      
+    });
+
+    build.done(function() {
         def.resolve();
+
+        promise = promise.done( function () {
+            mainDef.resolve();
+        } );
     });
 
-    return def.promise();
+    builder.resolve();
+
+    return mainPromise;    
 }
 
 function getTrackedEntities()
@@ -253,13 +254,238 @@
         type: 'GET',
         data: 'viewClass=detailed&paging=false'
     }).done(function(response) {
-        localStorage['TRACKED_ENTITIES'] = JSON.stringify(response.trackedEntities);
+        dhis2.tc.store.setAll( 'trackedEntities', response.trackedEntities );        
         def.resolve();
     });
 
     return def.promise();
 }
 
+function getMetaPrograms()
+{
+    var def = $.Deferred();
+
+    $.ajax({
+        url: '../api/programs.json',
+        type: 'GET',
+        data:'type=1&paging=false&include=id,name,version,programTrackedEntityAttributes[displayInList,mandatory,attribute[id]],programStages[id,version,programStageDataElements[dataElement[id,optionSet[id,version]]]]'
+    }).done( function(response) {          
+        var programs = [];
+        _.each( _.values( response.programs ), function ( program ) { 
+            if( program.programStages &&
+                program.programStages.length &&
+                program.programStages[0].programStageDataElements &&
+                program.programStages[0].programStageDataElements.length ) {
+            
+                programs.push(program);
+            }  
+            
+        });
+        
+        def.resolve( programs );
+    });
+    
+    return def.promise(); 
+}
+
+function getPrograms( programs )
+{
+    if( !programs ){
+        return;
+    }
+    
+    var mainDef = $.Deferred();
+    var mainPromise = mainDef.promise();
+
+    var def = $.Deferred();
+    var promise = def.promise();
+
+    var builder = $.Deferred();
+    var build = builder.promise();
+
+    _.each( _.values( programs ), function ( program ) {
+        build = build.then(function() {
+            var d = $.Deferred();
+            var p = d.promise();
+            dhis2.tc.store.get('trackerCapturePrograms', program.id).done(function(obj) {
+                if(!obj || obj.version !== program.version) {
+                    promise = promise.then( getProgram( program.id ) );
+                }
+
+                d.resolve();
+            });
+
+            return p;
+        });
+    });
+
+    build.done(function() {
+        def.resolve();
+
+        promise = promise.done( function () {
+            mainDef.resolve( programs );
+        } );
+    });
+
+    builder.resolve();
+
+    return mainPromise;
+}
+
+function getProgram( id )
+{
+    return function() {
+        return $.ajax( {
+            url: '../api/programs.json',
+            type: 'GET',
+            data: 'paging=false&filter=id:eq:' + id +'&include=id,name,version,dateOfEnrollmentDescription,dateOfIncidentDescription,displayIncidentDate,ignoreOverdueEvents,realionshipText,trackedEntity[id,name,description],userRoles[id,name],organisationUnits[id,name],programStages[id,name,version,description,minDaysFromStart,repeatable],programTrackedEntityAttributes[displayInList,mandatory,attribute[id]]'            
+        }).done( function( response ){
+            
+            _.each( _.values( response.programs ), function ( program ) { 
+                
+                var ou = {};
+                _.each(_.values( program.organisationUnits), function(o){
+                    ou[o.id] = o.name;
+                });
+
+                program.organisationUnits = ou;
+
+                var ur = {};
+                _.each(_.values( program.userRoles), function(u){
+                    ur[u.id] = u.name;
+                });
+
+                program.userRoles = ur;
+
+                dhis2.tc.store.set( 'trackerCapturePrograms', program );
+
+            });         
+        });
+    };
+}
+
+function getProgramStages( programs )
+{
+    if( !programs ){
+        return;
+    }
+    
+    var mainDef = $.Deferred();
+    var mainPromise = mainDef.promise();
+
+    var def = $.Deferred();
+    var promise = def.promise();
+
+    var builder = $.Deferred();
+    var build = builder.promise();
+
+    _.each( _.values( programs ), function ( program ) {
+        
+        _.each(_.values(program.programStages), function(programStage){
+            build = build.then(function() {
+                var d = $.Deferred();
+                var p = d.promise();
+                dhis2.tc.store.get('programStages', programStage.id).done(function(obj) {
+                    if(!obj || obj.version !== programStage.version) {
+                        promise = promise.then( getProgramStage( programStage.id ) );
+                    }
+                    d.resolve();
+                });
+                return p;
+            });            
+        });                     
+    });
+
+    build.done(function() {
+        def.resolve();
+
+        promise = promise.done( function () {
+            mainDef.resolve( programs );
+        } );
+    });
+
+    builder.resolve();
+
+    return mainPromise;    
+}
+
+function getProgramStage( id )
+{
+    return function() {
+        return $.ajax( {
+            url: '../api/programStages.json',
+            type: 'GET',
+            data: 'filter=id:eq:' + id +'&include=id,name,dataEntryForm,description,minDaysFromStart,repeatable,programStageDataElements[displayInReports,allowProvidedElsewhere,allowDateInFuture,compulsory,dataElement[id,name,type,optionSet[id]]]'
+        }).done( function( response ){            
+            _.each( _.values( response.programStages ), function( programStage ) {                
+                dhis2.tc.store.set( 'programStages', programStage );
+            });
+        });
+    };
+}
+
+function getOptionSetsForPrograms( programs )
+{
+    if( !programs ){
+        return;
+    }
+    
+    var mainDef = $.Deferred();
+    var mainPromise = mainDef.promise();
+
+    var def = $.Deferred();
+    var promise = def.promise();
+
+    var builder = $.Deferred();
+    var build = builder.promise();    
+
+    _.each( _.values( programs ), function ( program ) {
+        _.each(_.values( program.programStages[0].programStageDataElements), function(prStDe){
+            if( prStDe.dataElement.optionSet && prStDe.dataElement.optionSet.id ){
+                build = build.then(function() {
+                    var d = $.Deferred();
+                    var p = d.promise();
+                    dhis2.tc.store.get('optionSets', prStDe.dataElement.optionSet.id).done(function(obj) {                    
+                        if(!obj || obj.version !== prStDe.dataElement.optionSet.version) {
+                            promise = promise.then( getOptionSet( prStDe.dataElement.optionSet.id ) );
+                        }
+                        d.resolve();
+                    });
+
+                    return p;
+                });
+            }            
+        });                      
+    });
+
+    build.done(function() {
+        def.resolve();
+
+        promise = promise.done( function () {
+            mainDef.resolve( programs );
+        } );
+    });
+
+    builder.resolve();
+
+    return mainPromise;    
+}
+
+function getOptionSet( id )
+{
+    return function() {
+        return $.ajax( {
+            url: '../api/optionSets.json',
+            type: 'GET',
+            data: 'filter=id:eq:' + id +'&include=id,name,version,options'
+        }).done( function( response ){            
+            _.each( _.values( response.optionSets ), function( optionSet ) {                
+                dhis2.tc.store.set( 'optionSets', optionSet );
+            });
+        });
+    };
+}
+
 function uploadLocalData()
 {
     if (!dhis2.tc.storageManager.hasLocalData())

=== modified file 'dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/styles/style.css'
--- dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/styles/style.css	2014-05-28 13:36:26 +0000
+++ dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/styles/style.css	2014-06-06 13:35:06 +0000
@@ -139,7 +139,7 @@
     width: 120px;
 }
 
-.orgunit-container
+.align-center
 {
     text-align: center;
 }

=== modified file 'dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/views/home.html'
--- dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/views/home.html	2014-05-27 14:50:29 +0000
+++ dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/views/home.html	2014-06-06 13:35:06 +0000
@@ -9,6 +9,8 @@
     <img id="ouwt_loader" src="../images/ajax-loader-bar.gif"/>
 </div>
 <div class="page" id="mainPage" ng-show="selectedOrgUnit">
+    
+    <!-- Search heading begins -->
     <h1>
         <span ng-if='showSearchDiv || !showRegistrationDiv'>
             {{'search'| translate}} {{selectedProgram.trackedEntity.name}}
@@ -18,8 +20,13 @@
         </span>          
         <a href ng-click="getHelpContent()" title="{{'help'| translate}}"><i class="fa fa-question-circle"></i></a>
     </h1>
-
+    <!-- Search heading ends -->
+    
+    <!--- Simple search field begins -->
     <input type="text" selected-org-unit ng-model="selectedOrgUnit.name" ng-hide=true>
+    <!--- Simple search input field beings -->
+    
+    <!--- Advanced search input field begins -->
     <div class="row">        
         <div id="searchDropDownParent" class="input-group col-md-6">
             <input type="text" placeholder="{{'your_search_input_here'| translate}}" ng-model="searchText" class="form-control" ng-class="{true: 'invalid - input'} [!searchText && emptySearchText]" ng-focus="hideSearch()" ng-disabled="showRegistrationDiv">
@@ -46,11 +53,15 @@
             </button>
         </div>        
     </div>
+    <!--- Advanced search input field begins -->
+    
+    <!--- Error display for search begins -->
     <div class="row" ng-if="emptySearchAttribute">
         <div class="col-md-6">
             <div class="alert alert-danger">{{'search_input_required'| translate}}</div>         
         </div>
     </div>
+    <!--- Error display for search ends -->
 
     <div class="row vertical-spacing">
         <div id="selectDropDownParent" class="input-group col-md-6">