← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 18192: tracker-capture: persiting dashboard layout - WIP

 

------------------------------------------------------------
revno: 18192
committer: Abyot Asalefew Gizaw <abyota@xxxxxxxxx>
branch nick: dhis2
timestamp: Fri 2015-02-06 21:22:45 +0100
message:
  tracker-capture: persiting dashboard layout - WIP
removed:
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/d2Directives.js
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/d2Services.js
modified:
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/dashboard/dashboard-controller.js
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/dashboard/dashboard-widgets.html
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/dashboard/dashboard.html
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/enrollment/enrollment-controller.js
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/relationship/relationship-controller.js
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/selected/selected.html
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/i18n/i18n_app.properties
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/index.html
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/services.js
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/styles/style.css
  dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/dhis2/dhis2.angular.directives.js
  dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/dhis2/dhis2.angular.services.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-apps/src/main/webapp/dhis-web-tracker-capture/components/dashboard/dashboard-controller.js'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/dashboard/dashboard-controller.js	2015-02-04 12:53:26 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/dashboard/dashboard-controller.js	2015-02-06 20:22:45 +0000
@@ -13,25 +13,37 @@
                 ProgramFactory,
                 CurrentSelection) {
     //dashboard items   
-    $rootScope.biggerDashboardWidgets = [];
-    $rootScope.smallerDashboardWidgets = [];
-    $rootScope.enrollmentWidget = {title: 'enrollment', view: "components/enrollment/enrollment.html", show: true, expand: true};
-    $rootScope.dataentryWidget = {title: 'dataentry', view: "components/dataentry/dataentry.html", show: true, expand: true};
-    $rootScope.reportWidget = {title: 'report', view: "components/report/tei-report.html", show: true, expand: true};
-    $rootScope.selectedWidget = {title: 'current_selections', view: "components/selected/selected.html", show: false, expand: true};
-    $rootScope.profileWidget = {title: 'profile', view: "components/profile/profile.html", show: true, expand: true};
-    $rootScope.relationshipWidget = {title: 'relationships', view: "components/relationship/relationship.html", show: true, expand: true};
-    $rootScope.notesWidget = {title: 'notes', view: "components/notes/notes.html", show: true, expand: true};    
-   
-    $rootScope.biggerDashboardWidgets.push($rootScope.enrollmentWidget);
-    $rootScope.biggerDashboardWidgets.push($rootScope.dataentryWidget);
-    $rootScope.biggerDashboardWidgets.push($rootScope.reportWidget);
-    $rootScope.smallerDashboardWidgets.push($rootScope.selectedWidget);
-    $rootScope.smallerDashboardWidgets.push($rootScope.profileWidget);
-    $rootScope.smallerDashboardWidgets.push($rootScope.relationshipWidget);
-    $rootScope.smallerDashboardWidgets.push($rootScope.notesWidget);
-    
-    //selections  
+    $rootScope.dashboardWidgets = [];
+    $rootScope.dashboardStatus = [];
+    $scope.widgetsChanged = [];
+    
+    $rootScope.enrollmentWidget = {title: 'enrollment', view: "components/enrollment/enrollment.html", show: true, expand: true, parent: 'biggerWidget', order: 0};
+    $rootScope.dataentryWidget = {title: 'dataentry', view: "components/dataentry/dataentry.html", show: true, expand: true, parent: 'biggerWidget', order: 1};
+    $rootScope.reportWidget = {title: 'report', view: "components/report/tei-report.html", show: true, expand: true, parent: 'biggerWidget', order: 2};
+    $rootScope.selectedWidget = {title: 'current_selections', view: "components/selected/selected.html", show: false, expand: true, parent: 'smallerWidget', order: 0};
+    $rootScope.profileWidget = {title: 'profile', view: "components/profile/profile.html", show: true, expand: true, parent: 'smallerWidget', order: 1};
+    $rootScope.relationshipWidget = {title: 'relationships', view: "components/relationship/relationship.html", show: true, expand: true, parent: 'smallerWidget', order: 2};
+    $rootScope.notesWidget = {title: 'notes', view: "components/notes/notes.html", show: true, expand: true, parent: 'smallerWidget', order: 3};  
+    
+    $scope.dashboardStatus['enrollment'] = {title: 'enrollment', view: "components/enrollment/enrollment.html", show: true, expand: true, parent: 'biggerWidget', order: 0};
+    $scope.dashboardStatus['dataentry'] = {title: 'dataentry', view: "components/dataentry/dataentry.html", show: true, expand: true, parent: 'biggerWidget', order: 1};
+    $scope.dashboardStatus['report'] = {title: 'report', view: "components/report/tei-report.html", show: true, expand: true, parent: 'biggerWidget', order: 2};
+    $scope.dashboardStatus['current_selections'] = {title: 'current_selections', view: "components/selected/selected.html", show: false, expand: true, parent: 'smallerWidget', order: 0};
+    $scope.dashboardStatus['profile'] = {title: 'profile', view: "components/profile/profile.html", show: true, expand: true, parent: 'smallerWidget', order: 1};
+    $scope.dashboardStatus['relationships'] = {title: 'relationships', view: "components/relationship/relationship.html", show: true, expand: true, parent: 'smallerWidget', order: 2};
+    $scope.dashboardStatus['notes'] = {title: 'notes', view: "components/notes/notes.html", show: true, expand: true, parent: 'smallerWidget', order: 3};  
+    
+    $scope.dashboardWidgetsOrder = {biggerWidgets: ['enrollment', 'dataentry', 'report'], smallerWidgets: ['current_selections', 'profile', 'relationships', 'notes']};
+    
+    $rootScope.dashboardWidgets.push($rootScope.enrollmentWidget);
+    $rootScope.dashboardWidgets.push($rootScope.dataentryWidget);
+    $rootScope.dashboardWidgets.push($rootScope.reportWidget);
+    $rootScope.dashboardWidgets.push($rootScope.selectedWidget);
+    $rootScope.dashboardWidgets.push($rootScope.profileWidget);
+    $rootScope.dashboardWidgets.push($rootScope.relationshipWidget);
+    $rootScope.dashboardWidgets.push($rootScope.notesWidget);
+    
+    //selections
     $scope.selectedTeiId = ($location.search()).tei; 
     $scope.selectedProgramId = ($location.search()).program; 
     $scope.selectedOrgUnit = storage.get('SELECTED_OU');
@@ -103,6 +115,32 @@
         $scope.broadCastSelections(); 
     }); 
     
+    //watch for widget sorting    
+    $scope.$watch('widgetsOrder', function() {        
+        if(angular.isObject($scope.widgetsOrder)){
+            $scope.orderChanged = false;
+            for(var i=0; i<$scope.widgetsOrder.smallerWidgets.length; i++){
+                if($scope.widgetsOrder.smallerWidgets.length === $scope.dashboardWidgetsOrder.smallerWidgets.length && $scope.widgetsOrder.smallerWidgets[i] !== $scope.dashboardWidgetsOrder.smallerWidgets[i]){
+                    $scope.orderChanged = true;
+                }
+                
+                if($scope.widgetsOrder.smallerWidgets.length !== $scope.dashboardWidgetsOrder.smallerWidgets.length){
+                    $scope.orderChanged = true;
+                }
+            }
+            
+            for(var i=0; i<$scope.widgetsOrder.biggerWidgets.length; i++){
+                if($scope.widgetsOrder.biggerWidgets.length === $scope.dashboardWidgetsOrder.biggerWidgets.length && $scope.widgetsOrder.biggerWidgets[i] !== $scope.dashboardWidgetsOrder.biggerWidgets[i]){
+                    $scope.orderChanged = true;
+                }
+                
+                if($scope.widgetsOrder.biggerWidgets.length !== $scope.dashboardWidgetsOrder.biggerWidgets.length){
+                    $scope.orderChanged = true;
+                }
+            }
+        }
+    });
+    
     $scope.broadCastSelections = function(){
         
         var selections = CurrentSelection.get();
@@ -127,10 +165,34 @@
     
     $scope.removeWidget = function(widget){        
         widget.show = false;
+        trackWidgetStatusChange(widget);
     };
     
     $scope.expandCollapse = function(widget){
         widget.expand = !widget.expand;
+        trackWidgetStatusChange(widget);
+    };
+    
+    var trackWidgetStatusChange = function(widget){
+        var w = $scope.dashboardStatus[widget.title];
+        
+        if(!angular.equals(w, widget) && $scope.widgetsChanged.indexOf(widget.title) === -1){
+            $scope.widgetsChanged.push(widget.title);
+        }        
+        if(angular.equals(w, widget) && $scope.widgetsChanged.indexOf(widget.title) !== -1){
+            var idx = $scope.widgetsChanged.indexOf(widget.title);
+            $scope.widgetsChanged.splice(idx,1);
+        }
+    };
+    
+    $scope.saveDashboardLayout = function(){
+        if($scope.widgetsChanged.length > 0){
+            console.log('dashboardWidgets:  ', $rootScope.dashboardWidgets);
+        }
+        
+        if($scope.orderChanged){
+            console.log('order:  ', $scope.widgetsOrder);
+        }
     };
     
     $scope.showHideWidgets = function(){
@@ -142,4 +204,8 @@
         modalInstance.result.then(function () {
         });
     };
+    
+    $rootScope.closeOpenWidget = function(widget){
+        trackWidgetStatusChange(widget);
+    };
 });

=== modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/dashboard/dashboard-widgets.html'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/dashboard/dashboard-widgets.html	2014-07-17 10:35:43 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/dashboard/dashboard-widgets.html	2015-02-06 20:22:45 +0000
@@ -1,4 +1,4 @@
-<div class="modal-header">
+<!--<div class="modal-header">
     <h1>{{'select_widgets_to_show'| translate}}</h1>
 </div>
 
@@ -9,7 +9,7 @@
                 {{biggerWidget.title | translate}}
             </td>
             <td>
-                <input type="checkbox" ng-model="biggerWidget.show">
+                <input type="checkbox" ng-model="biggerWidget.show" ng-change="applyWidgetChange(biggerWidget)">
             </td>
         </tr>
         <tr ng-repeat="smallerWidget in smallerDashboardWidgets">
@@ -17,12 +17,33 @@
                 {{smallerWidget.title | translate}}
             </td>
             <td>
-                <input type="checkbox" ng-model="smallerWidget.show">
-            </td>
-        </tr>
-    </table>    
-</div>
-
-<div class="modal-footer">     
-    <button type="button" class="btn btn-default" data-ng-click="close()">{{'close'| translate}}</button>
-</div> 
+                <input type="checkbox" ng-model="smallerWidget.show" ng-change="applyWidgetChange(smallerWidget)">
+            </td>
+        </tr>
+    </table>    
+</div>
+
+<div class="modal-footer">     
+    <button type="button" class="btn btn-default" data-ng-click="close()">{{'close'| translate}}</button>
+</div>--> 
+
+<div class="modal-header">
+    <h1>{{'select_widgets_to_show'| translate}}</h1>
+</div>
+
+<div class="modal-body">   
+    <table class="listTable dhis2-table-striped-border">
+        <tr ng-repeat="widget in dashboardWidgets">
+            <td>
+                {{widget.title | translate}}
+            </td>
+            <td>
+                <input type="checkbox" ng-model="widget.show" ng-change="closeOpenWidget(widget)">
+            </td>
+        </tr>
+    </table>    
+</div>
+
+<div class="modal-footer">     
+    <button type="button" class="btn btn-default" data-ng-click="close()">{{'close'| translate}}</button>
+</div>
\ No newline at end of file

=== modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/dashboard/dashboard.html'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/dashboard/dashboard.html	2014-08-18 10:01:22 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/dashboard/dashboard.html	2015-02-06 20:22:45 +0000
@@ -1,8 +1,58 @@
+<!--<div class="container-1-1">    
+    <div class="col-sm-12 vertical-spacing  not-printable">
+
+        <button type="button" class="btn btn-default" ng-click="back()">{{'back'| translate}}</button>
+
+        <select ng-model="selectedProgram"
+                class="form-control-program"
+                ng-options="program as program.name for program in programs | orderBy: 'name'" 
+                ng-disabled="programs.length < 1"
+                ng-change="broadCastSelections()">
+            <option value="">{{programs.length > 0 ? 'please_select_a_program' : 'no_program_exists' | translate}}</option>
+        </select>
+
+        <div class="pull-right">
+            <span ng-if="widgetsChanged.length > 0">
+                <span class="trimmed-alert alert-danger">{{'dashboard_layout_not_saved'| translate}}</span><button type="button" class="btn btn-primary small-horizonal-spacing" ng-click="saveDashboardLayout()">{{'save'| translate}}</button>
+            </span>
+            <div class="btn-group" dropdown is-open="status.isopen">
+                <button type="button" class="btn btn-default dropdown-toggle">
+                    <i class="fa fa-cog" title="{{'settings'| translate}}"></i>
+                </button>
+                <ul class="dropdown-menu pull-right" role="menu">
+                    <li><a href ng-click="showHideWidgets()">{{'show_hide_widgets'| translate}}</a></li>
+                </ul>
+            </div>
+        </div>
+    </div>
+
+    <div class='separator'></div>
+
+    <div class="col-sm-12">
+        <div class="row">            
+            <div class="col-sm-6 col-md-8">
+                <div d2-sortable class="row connectedSortable empty-dashboard-container">
+                    <div class="col-sm-12" ng-repeat="biggerWidget in biggerDashboardWidgets">
+                        <div ng-show="biggerWidget.show" ng-include="biggerWidget.view" ng-class="{true: 'not-printable'} [biggerWidget.title != 'report']"></div>
+                    </div>                                       
+                </div>                
+            </div>            
+            <div class="col-sm-6 col-md-4">
+                <div d2-sortable class="row connectedSortable empty-dashboard-container">                   
+                    <div class="col-sm-12" ng-repeat="smallerWidget in smallerDashboardWidgets">                        
+                        <div ng-show="smallerWidget.show" ng-include="smallerWidget.view" ng-class="{true: 'not-printable'} [smallerWidget.title != 'report']"></div>
+                    </div>                   
+                </div>
+            </div>
+        </div>
+    </div>    
+</div>-->
+
 <div class="container-1-1">    
     <div class="col-sm-12 vertical-spacing  not-printable">
 
         <button type="button" class="btn btn-default" ng-click="back()">{{'back'| translate}}</button>
-
+        
         <select ng-model="selectedProgram"
                 class="form-control-program"
                 ng-options="program as program.name for program in programs | orderBy: 'name'" 
@@ -12,6 +62,9 @@
         </select>
 
         <div class="pull-right">
+            <span ng-if="widgetsChanged.length > 0 || orderChanged">
+                <span class="trimmed-alert alert-danger">{{'dashboard_layout_not_saved'| translate}}</span><button type="button" class="btn btn-primary small-horizonal-spacing" ng-click="saveDashboardLayout()">{{'save'| translate}}</button>
+            </span>            
             <div class="btn-group" dropdown is-open="status.isopen">
                 <button type="button" class="btn btn-default dropdown-toggle">
                     <i class="fa fa-cog" title="{{'settings'| translate}}"></i>
@@ -24,19 +77,27 @@
     </div>
 
     <div class='separator'></div>
-
+    
     <div class="col-sm-12">
         <div class="row">            
             <div class="col-sm-6 col-md-8">
-                <div sortable class="row connectedSortable empty-dashboard-container">
-                    <div ng-repeat="biggerWidget in biggerDashboardWidgets">
-                        <div class="col-sm-12" ng-show="biggerWidget.show" ng-include="biggerWidget.view" ng-class="{true: 'not-printable'} [biggerWidget.title != 'report']"></div>
+                <div id="biggerWidget"
+                    d2-sortable  
+                    bigger-widgets={{ dashboardWidgets  | filter: {parent: 'biggerWidget'} }} 
+                    smaller-widgets={{ dashboardWidgets  | filter: {parent: 'smallerWidget'} }} 
+                    class="row connectedSortable empty-dashboard-container">
+                    <div class="col-sm-12" id={{biggerWidget.title}} ng-repeat="biggerWidget in dashboardWidgets | orderBy:'order' | filter: {parent: 'biggerWidget'}"">
+                        <div ng-show="biggerWidget.show" ng-include="biggerWidget.view" ng-class="{true: 'not-printable'} [biggerWidget.title != 'report']"></div>
                     </div>                                       
                 </div>                
             </div>            
             <div class="col-sm-6 col-md-4">
-                <div sortable class="row connectedSortable empty-dashboard-container">                   
-                    <div class="col-sm-12" ng-repeat="smallerWidget in smallerDashboardWidgets">                        
+                <div id="smallerWidget" 
+                    d2-sortable 
+                    bigger-widgets={{ dashboardWidgets  | filter: {parent: 'biggerWidget'} }} 
+                    smaller-widgets={{ dashboardWidgets  | filter: {parent: 'smallerWidget'} }} 
+                    class="row connectedSortable empty-dashboard-container">                   
+                    <div class="col-sm-12" id={{smallerWidget.title}} ng-repeat="smallerWidget in dashboardWidgets  | orderBy:'order' | filter: {parent: 'smallerWidget'}">                        
                         <div ng-show="smallerWidget.show" ng-include="smallerWidget.view" ng-class="{true: 'not-printable'} [smallerWidget.title != 'report']"></div>
                     </div>                   
                 </div>
@@ -45,4 +106,3 @@
     </div>    
 </div>
 
-

=== modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/enrollment/enrollment-controller.js'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/enrollment/enrollment-controller.js	2015-02-04 12:53:26 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/enrollment/enrollment-controller.js	2015-02-06 20:22:45 +0000
@@ -239,7 +239,7 @@
         var formEmpty = true;
         for(var k in $scope.attributesById){
             if( $scope.selectedTei[k] ){
-                tei.attributes.push({attribute: $scope.attributesById[k].id, value: $scope.selectedTei[k], type: $scope.attributesById[k].valueType});
+                tei.attributes.push({attribute: $scope.attributesById[k].id, value: $scope.selectedTei[k], displayName: $scope.attributesById[k].name, type: $scope.attributesById[k].valueType});
                 formEmpty = false;
             }
         }

=== modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/relationship/relationship-controller.js'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/relationship/relationship-controller.js	2015-01-27 12:48:23 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/relationship/relationship-controller.js	2015-02-06 20:22:45 +0000
@@ -24,7 +24,8 @@
         $scope.relatedTeis = [];
         $scope.selections = CurrentSelection.get();
         $scope.optionSets = $scope.selections.optionSets;
-        $scope.selectedTei = angular.copy($scope.selections.tei);        
+        $scope.selectedTei = angular.copy($scope.selections.tei);
+        
         $scope.trackedEntity = $scope.selections.te;
         $scope.selectedEnrollment = $scope.selections.selectedEnrollment;
         $scope.selectedProgram = $scope.selections.pr;
@@ -133,13 +134,13 @@
     $scope.programs = selections.prs;
 
     $scope.relationshipSources = ['search_from_existing','register_new'];
-    $scope.selectedRelationshipSource = {};   
+    $scope.selectedRelationshipSource = {};
     $scope.relationship = {};
     
     //Selection
     $scope.selectedOrgUnit = storage.get('SELECTED_OU');
     $scope.optionSets = selections.optionSets;
-    $scope.selectedTeiForDisplay = angular.copy($scope.selectedTei);       
+    $scope.selectedTeiForDisplay = angular.copy($scope.selectedTei);
     
     if(angular.isObject($scope.programs) && $scope.programs.length === 1){
         $scope.selectedProgramForRelative = $scope.programs[0];        
@@ -351,7 +352,7 @@
             }           
            
             if(column.type === 'date'){
-                 $scope.filterText[column.id]= {start: '', end: ''};
+                $scope.filterText[column.id]= {start: '', end: ''};
             }
         });        
         return columns;        

=== modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/selected/selected.html'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/selected/selected.html	2014-07-02 20:53:29 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/selected/selected.html	2015-02-06 20:22:45 +0000
@@ -1,7 +1,7 @@
-<div class="panel panel-default" ng-controller="SelectedInfoController">
+<div class="panel panel-info" ng-controller="SelectedInfoController">
     <div class="panel-heading handle bold">
         {{selectedWidget.title| translate}}
-        <span class="pull-right">
+        <span class="pull-right widget-link">
             <a class="small-horizonal-spacing" href ng-click="expandCollapse(selectedWidget)">
                 <span ng-show="selectedWidget.expand"><i class="fa fa-chevron-up" title="{{'collapse'| translate}}"></i></span>
                 <span ng-show="!selectedWidget.expand"><i class="fa fa-chevron-down" title="{{'expand'| translate}}"></i></span>

=== modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/i18n/i18n_app.properties'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/i18n/i18n_app.properties	2015-01-20 14:36:12 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/i18n/i18n_app.properties	2015-02-06 20:22:45 +0000
@@ -273,4 +273,5 @@
 capture=Capture
 point_and_click_for_coordinate=Point and click for coordinate
 value_must_be_between=Value must be between
-locate_organisation_unit_by_name=Locate organisation unit by name
\ No newline at end of file
+locate_organisation_unit_by_name=Locate organisation unit by name
+dashboard_layout_not_saved=Dashboard layout not saved
\ No newline at end of file

=== modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/index.html'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/index.html	2015-02-03 15:59:38 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/index.html	2015-02-06 20:22:45 +0000
@@ -74,18 +74,15 @@
         
         <script src="../dhis-web-commons/ouwt/ouwt.js"></script>
         <script src="scripts/tracker-capture.js"></script>
-        <!--<script src="scripts/idb.js"></script>-->
 
         <script type="text/javascript" src="../dhis-web-commons/javascripts/angular/plugins/select2.js"></script>
         <script type="text/javascript" src="../dhis-web-commons/javascripts/angular/plugins/angularjs-nvd3-directives.min.js"></script>
         <script type="text/javascript" src="../dhis-web-commons/javascripts/angular/plugins/angularLocalStorage.js"></script>
         <script type="text/javascript" src="../dhis-web-commons/javascripts/angular/plugins/angular-translate.min.js"></script>
-        <!--<script type="text/javascript" src="../dhis-web-commons/javascripts/dhis2/dhis2.angular.directives.js"></script>-->
+        <script type="text/javascript" src="../dhis-web-commons/javascripts/dhis2/dhis2.angular.directives.js"></script>
         <script type="text/javascript" src="../dhis-web-commons/javascripts/dhis2/dhis2.angular.filters.js"></script>
-        <!--<script type="text/javascript" src="../dhis-web-commons/javascripts/dhis2/dhis2.angular.services.js"></script>-->
+        <script type="text/javascript" src="../dhis-web-commons/javascripts/dhis2/dhis2.angular.services.js"></script>
         <script type="text/javascript" src="../dhis-web-commons/javascripts/dhis2/dhis2.angular.controllers.js"></script>
-        <script type="text/javascript" src="scripts/d2Services.js"></script>
-        <script type="text/javascript" src="scripts/d2Directives.js"></script>
 
         <script type="text/javascript" src="scripts/app.js"></script>
         <script type="text/javascript" src="scripts/services.js"></script>

=== removed file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/d2Directives.js'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/d2Directives.js	2015-02-03 15:59:38 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/d2Directives.js	1970-01-01 00:00:00 +0000
@@ -1,584 +0,0 @@
-'use strict';
-
-/* Directives */
-
-var d2Directives = angular.module('d2Directives', [])
-
-
-.directive('d2OuSearch', function() {
-    
-    return {
-        restrict: 'E',
-        template: '<div style="margin-top:20px">\n\
-                    <img id="searchIcon" src="../images/search.png" style="cursor: pointer" title="{{ \'locate_organisation_unit_by_name\' | translate}}">\n\
-                    <span id="searchSpan" style="width:100%;display:none;">\n\
-                        <input type="text" id="searchField" name="key"/>\n\
-                        <input type="button" value="{{\'find\' | translate}}" onclick="selection.findByName()"/>\n\
-                    </span>\n\
-                  </div>',
-        link: function (scope, element, attrs) {
-            
-            $("#searchIcon").click(function() {
-                $("#searchSpan").toggle();
-                $("#searchField").focus();
-            });
-
-            $("#searchField").autocomplete({
-                source: "../dhis-web-commons/ouwt/getOrganisationUnitsByName.action",
-                select: function(event, ui) {
-                    $("#searchField").val(ui.item.value);
-                    selection.findByName();
-                }
-            });
-        }
-    };
-})
-
-.directive('inputValidator', function() {
-    
-    return {
-        require: 'ngModel',
-        link: function (scope, element, attrs, ctrl) {  
-
-            ctrl.$parsers.push(function (value) {
-                return parseFloat(value || '');
-            });
-        }
-    };
-})
-
-.directive('selectedOrgUnit', function($timeout, storage) {        
-
-    return {        
-        restrict: 'A',        
-        link: function(scope, element, attrs){
-            
-            //once ou tree is loaded, start meta-data download
-            $(function() {
-                dhis2.ou.store.open().done( function() {
-                    selection.load();
-                    $( "#orgUnitTree" ).one( "ouwtLoaded", function(event, ids, names) {
-                        console.log('Finished loading orgunit tree');
-                        
-                        //Disable ou selection until meta-data has downloaded
-                        $( "#orgUnitTree" ).addClass( "disable-clicks" );
-                        
-                        $timeout(function() {
-                            scope.treeLoaded = true;
-                            scope.$apply();
-                        });
-                        
-                        downloadMetaData();
-                    });
-                });
-            });
-            
-            //listen to user selection, and inform angular         
-            selection.setListenerFunction( setSelectedOu, true );
-            
-            function setSelectedOu( ids, names ) {
-                var ou = {id: ids[0], name: names[0]};
-                $timeout(function() {
-                    scope.selectedOrgUnit = ou;
-                    scope.$apply();
-                });
-            }
-        }  
-    };
-})
-
-.directive('blurOrChange', function() {
-    
-    return function( scope, elem, attrs) {
-        elem.calendarsPicker({
-            onSelect: function() {
-                scope.$apply(attrs.blurOrChange);
-                $(this).change();                                        
-            }
-        }).change(function() {
-            scope.$apply(attrs.blurOrChange);
-        });
-    };
-})
-
-.directive('d2Enter', function () {
-    return function (scope, element, attrs) {
-        element.bind("keydown keypress", function (event) {
-            if(event.which === 13) {
-                scope.$apply(function (){
-                    scope.$eval(attrs.d2Enter);
-                });
-                event.preventDefault();
-            }
-        });
-    };
-})
-
-.directive('d2NumberValidation', function(ErrorMessageService, $translate) {
-    
-    return {
-        require: 'ngModel',
-        restrict: 'A',
-        link: function (scope, element, attrs, ctrl) {
-            
-            function checkValidity(numberType, value){
-                var isValid = false;
-                switch(numberType){
-                    case "number":
-                        isValid = dhis2.validation.isNumber(value);
-                        break;
-                    case "posInt":
-                        isValid = dhis2.validation.isPositiveInt(value);
-                        break;
-                    case "negInt":
-                        isValid = dhis2.validation.isNegativeInt(value);
-                        break;
-                    case "zeroPositiveInt":
-                        isValid = dhis2.validation.isZeroOrPositiveInt(value);
-                        break;
-                    case "int":
-                        isValid = dhis2.validation.isInt(value);
-                        break;
-                    default:
-                        isValid = true;
-                }
-                return isValid;
-            }
-            
-            var errorMessages = ErrorMessageService.getErrorMessages();
-            var fieldName = attrs.inputFieldId;
-            var numberType = attrs.numberType;
-            var isRequired = attrs.ngRequired === 'true';
-            var msg = $translate(numberType)+ ' ' + $translate('required');
-           
-            ctrl.$parsers.unshift(function(value) {
-            	if(value){
-                    var isValid = checkValidity(numberType, value);                    
-                    if(!isValid){
-                        errorMessages[fieldName] = $translate('value_must_be_' + numberType);
-                    }
-                    else{
-                        if(isRequired){
-                            errorMessages[fieldName] = msg;
-                        }
-                        else{
-                            errorMessages[fieldName] = "";
-                        }
-                    }
-                    
-                    ErrorMessageService.setErrorMessages(errorMessages);
-                	ctrl.$setValidity(fieldName, isValid);
-                    return value;
-                }
-                
-                if(value === ''){
-                    if(isRequired){
-                        errorMessages[fieldName] = msg;
-                    }
-                    else{
-                        ctrl.$setValidity(fieldName, true);
-                        errorMessages[fieldName] = "";
-                    }
-                    
-                    ErrorMessageService.setErrorMessages(errorMessages);
-                    return undefined;
-                }              
-            });
-           
-            ctrl.$formatters.unshift(function(value) {                
-                if(value){
-                    var isValid = checkValidity(numberType, value);
-                    ctrl.$setValidity(fieldName, isValid);
-                    return value;
-                }
-            });
-        }
-    };
-})
-
-.directive('typeaheadOpenOnFocus', function () {
-  	
-  	return {
-        require: ['typeahead', 'ngModel'],
-        link: function (scope, element, attr, ctrls) {
-            element.bind('focus', function () {
-                ctrls[0].getMatchesAsync(ctrls[1].$viewValue);                
-                scope.$watch(attr.ngModel, function(value) {
-                    if(value === '' || angular.isUndefined(value)){
-                        ctrls[0].getMatchesAsync(ctrls[1].$viewValue);
-                    }                
-                });
-            });
-        }
-    };
-})
-
-.directive('d2TypeaheadValidation', function() {
-    
-    return {
-        require: ['typeahead', 'ngModel'],
-        restrict: 'A',
-        link: function (scope, element, attrs, ctrls) {
-            element.bind('blur', function () {                
-                if(ctrls[1].$viewValue && !ctrls[1].$modelValue && ctrls[0].active === -1){
-                    ctrls[1].$setViewValue();
-                    ctrls[1].$render();
-                }                
-            });
-        }
-    };
-})
-
-.directive('d2PopOver', function($compile, $templateCache){
-    
-    return {        
-        restrict: 'EA',
-        link: function(scope, element, attrs){
-            var content = $templateCache.get("popover.html");
-            content = $compile(content)(scope);
-            var options = {
-                    content: content,
-                    placement: 'bottom',
-                    trigger: 'hover',
-                    html: true,
-                    title: scope.title               
-                };            
-            $(element).popover(options);
-        },
-        scope: {
-            content: '=',
-            title: '@details',
-            template: "@template"
-        }
-    };
-})
-
-.directive('sortable', function() {        
-
-    return {        
-        restrict: 'A',        
-        link: function(scope, element, attrs){
-            element.sortable({
-                connectWith: ".connectedSortable",
-                placeholder: "ui-state-highlight",
-                tolerance: "pointer",
-                handle: '.handle'
-            });
-        }  
-    };
-})
-
-.directive('serversidePaginator', function factory() {
-    
-    return {
-        restrict: 'E',
-        controller: function ($scope, Paginator) {
-            $scope.paginator = Paginator;
-        },
-        templateUrl: '../dhis-web-commons/paging/serverside-pagination.html'
-    };
-})
-
-.directive('draggableModal', function(){
-    
-    return {
-      	restrict: 'EA',
-      	link: function(scope, element) {
-        	element.draggable();
-      	}
-    };  
-})
-
-.directive('d2GoogleMap', function ($parse, $compile, storage) {
-    return {
-        restrict: 'E',
-        replace: true,
-        template: '<div></div>',
-        link: function(scope, element, attrs){
-            
-            //remove angular bootstrap ui modal draggable
-            $(".modal-content").draggable({ disabled: true });
-            
-            //get a default center
-            var latCenter = 12.31, lngCenter = 51.48;            
-            
-            //if there is any marker already - use it as center
-            if(angular.isObject(scope.location)){
-                if(scope.location.lat && scope.location.lng){
-                    latCenter = scope.location.lat;
-                    lngCenter = scope.location.lng;
-                }                
-            }
-            
-            //default map configurations 
-            var mapOptions = {
-                zoom: 3,
-                center: new google.maps.LatLng(latCenter, lngCenter),
-                mapTypeId: google.maps.MapTypeId.ROADMAP
-            },featureStyle = {
-                strokeWeight: 2,
-                strokeOpacity: 0.4,
-                fillOpacity: 0.4,
-                fillColor: 'green'
-            };
-            
-            var geojsons = $parse(attrs.geojsons)(scope);
-            var currentLayer = 0, currentGeojson = geojsons[0]; 
-            
-            var map = new google.maps.Map(document.getElementById(attrs.id), mapOptions);            
-            var currentGeojsonFeatures = map.data.addGeoJson(currentGeojson);
-            
-            var marker = new google.maps.Marker({
-                map: map
-            });
-            
-            if(angular.isObject(scope.location)){
-                if(scope.location.lat && scope.location.lng){                    
-                    addMarker({lat: scope.location.lat, lng: scope.location.lng});                    
-                }                
-            }
-            
-            function addMarker(loc){
-                var latLng = new google.maps.LatLng(loc.lat, loc.lng);
-                marker.setPosition(latLng);
-            }
-            
-            function centerMap(){
-                
-                if(currentGeojson && currentGeojson.features){
-                    var latLngBounds = new google.maps.LatLngBounds();
-                    angular.forEach(currentGeojson.features, function(feature){
-                        if(feature.geometry.type === 'MultiPolygon'){
-                            angular.forEach(feature.geometry.coordinates[0][0], function(coordinate){
-                                latLngBounds.extend(new google.maps.LatLng(coordinate[1],coordinate[0]));
-                            });
-                        }
-                        else if(feature.geometry.type === 'Point'){                        
-                            latLngBounds.extend(new google.maps.LatLng(feature.geometry.coordinates[1],feature.geometry.coordinates[0]));
-                        }
-                    });
-                    
-                    map.fitBounds(latLngBounds);
-                    map.panToBounds(latLngBounds);
-                }                
-            }
-            
-            function initializeMap(){                
-                google.maps.event.addListenerOnce(map, 'idle', function(){
-                    google.maps.event.trigger(map, 'resize');
-                    map.data.setStyle(featureStyle);
-                    centerMap();
-                });
-            }
-            
-            map.data.addListener('mouseover', function(e) {                
-                $("#polygon-label").text( e.feature.k.name );
-                map.data.revertStyle();
-                map.data.overrideStyle(e.feature, {fillOpacity: 0.8});
-            });
-            
-            map.data.addListener('mouseout', function() {                
-                $("#polygon-label").text( '' );
-                map.data.revertStyle();
-            });
-            
-            //drill-down based on polygons assigned to orgunits
-            map.data.addListener('rightclick', function(e){                
-                for (var i = 0; i < currentGeojsonFeatures.length; i++){
-                    map.data.remove(currentGeojsonFeatures[i]);
-                }
-                                
-                if(currentLayer >= geojsons.length-1){
-                    currentLayer = 0;
-                    currentGeojson = angular.copy(geojsons[currentLayer]);                    
-                }
-                else{
-                    currentLayer++;
-                    currentGeojson = angular.copy(geojsons[currentLayer]);
-                    currentGeojson.features = [];
-                    var selectedFeatures = [];
-                    angular.forEach(geojsons[currentLayer].features, function(feature){                    
-                        if(feature.properties.parent === e.feature.B){
-                            selectedFeatures.push(feature);
-                        }
-                    });
-                    
-                    if(selectedFeatures.length){
-                        currentGeojson.features = selectedFeatures;
-                    }                   
-                }                
-                currentGeojsonFeatures = map.data.addGeoJson(currentGeojson);
-                centerMap();         
-            });            
-            
-            //capturing coordinate from defined polygons
-            map.data.addListener('click', function(e) {                
-                scope.$apply(function(){
-                    addMarker({
-                       lat: e.latLng.lat(),
-                       lng: e.latLng.lng()
-                    });
-                    $parse(attrs.location).assign(scope.$parent, {lat: e.latLng.lat(), lng: e.latLng.lng()});                    
-                });                
-            });
-            
-            //capturing coordinate from anywhere in the map - incase no polygons are defined
-            google.maps.event.addListener(map, 'click', function(e){                
-                scope.$apply(function(){
-                    addMarker({
-                       lat: e.latLng.lat(),
-                       lng: e.latLng.lng()
-                    });
-                    $parse(attrs.location).assign(scope.$parent, {lat: e.latLng.lat(), lng: e.latLng.lng()});                    
-                });                
-            });
-            
-            initializeMap();
-        }
-    };
-})
-
-.directive('d2CustomForm', function($compile) {
-    return{ 
-        restrict: 'E',
-        link: function(scope, elm, attrs){
-            scope.$watch('customForm', function(){
-                if(angular.isObject(scope.customForm)){
-                    elm.html(scope.customForm.htmlCode);
-                    $compile(elm.contents())(scope);
-                }                
-            });
-        }
-    };
-})
-
-.directive('d2ContextMenu', function(ContextMenuSelectedItem) {
-        
-    return {        
-        restrict: 'A',
-        link: function(scope, element, attrs){
-            var contextMenu = $("#contextMenu");                   
-            
-            element.click(function (e) {
-                var selectedItem = $.parseJSON(attrs.selectedItem);
-                ContextMenuSelectedItem.setSelectedItem(selectedItem);
-                
-                var menuHeight = contextMenu.height();
-                var menuWidth = contextMenu.width();
-                var winHeight = $(window).height();
-                var winWidth = $(window).width();
-
-                var pageX = e.pageX;
-                var pageY = e.pageY;
-
-                contextMenu.show();
-
-                if( (menuWidth + pageX) > winWidth ) {
-                  pageX -= menuWidth;
-                }
-
-                if( (menuHeight + pageY) > winHeight ) {
-                  pageY -= menuHeight;
-
-                  if( pageY < 0 ) {
-                      pageY = e.pageY;
-                  }
-                }
-                
-                contextMenu.css({
-                    left: pageX,
-                    top: pageY
-                });
-
-                return false;
-            });
-            
-            contextMenu.on("click", "a", function () {                    
-                contextMenu.hide();
-            });
-
-            $(document).click(function () {                                        
-                contextMenu.hide();
-            });
-        }     
-    };
-})
-
-.directive('d2Date', function(DateUtils, CalendarService, ErrorMessageService, $translate, $parse) {
-    return {
-        restrict: 'A',
-        require: 'ngModel',        
-        link: function(scope, element, attrs, ctrl) {    
-            
-            var errorMessages = ErrorMessageService.getErrorMessages();
-            var fieldName = attrs.inputFieldId;
-            var isRequired = attrs.ngRequired === 'true';
-            var calendarSetting = CalendarService.getSetting();            
-            var dateFormat = 'yyyy-mm-dd';
-            if(calendarSetting.keyDateFormat === 'dd-MM-yyyy'){
-                dateFormat = 'dd-mm-yyyy';
-            }            
-            
-            var minDate = $parse(attrs.minDate)(scope), 
-                maxDate = $parse(attrs.maxDate)(scope),
-                calendar = $.calendars.instance(calendarSetting.keyCalendar);
-            
-            element.calendarsPicker({
-                changeMonth: true,
-                dateFormat: dateFormat,
-                yearRange: '-120:+30',
-                minDate: minDate,
-                maxDate: maxDate,
-                calendar: calendar,
-                duration: "fast",
-                showAnim: "",
-                renderer: $.calendars.picker.themeRollerRenderer,
-                onSelect: function(date) {
-                    $(this).change();
-                }
-            })
-            .change(function() {                
-                if(this.value){                    
-                    var rawDate = this.value;
-                    var convertedDate = DateUtils.format(this.value);
-
-                    var isValid = rawDate == convertedDate;
-                    
-                    if(!isValid){
-                        errorMessages[fieldName] = $translate('date_required');
-                    }
-                    else{
-                        if(isRequired){
-                            errorMessages[fieldName] = $translate('required');
-                        }
-                        else{
-                            errorMessages[fieldName] = "";
-                        }
-                        if(maxDate === 0){                    
-                            isValid = !moment(convertedDate, calendarSetting.momentFormat).isAfter(DateUtils.getToday());
-                            if(!isValid){
-                                errorMessages[fieldName] = $translate('future_date_not_allowed');                            
-                            }                           
-                        }
-                    }                                        
-                    ctrl.$setViewValue(this.value);
-                    ctrl.$setValidity(fieldName, isValid);
-                }
-                else{
-                    if(!isRequired){
-                        ctrl.$setViewValue(this.value);
-                        ctrl.$setValidity(fieldName, !isRequired);
-                        errorMessages[fieldName] = "";
-                    }
-                    else{
-                        errorMessages[fieldName] = $translate('required');                        
-                    }
-                }
-                
-                ErrorMessageService.setErrorMessages(errorMessages);
-                this.focus();
-                scope.$apply();
-            });    
-        }      
-    };   
-});
\ No newline at end of file

=== removed file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/d2Services.js'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/d2Services.js	2015-02-03 15:59:38 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/d2Services.js	1970-01-01 00:00:00 +0000
@@ -1,743 +0,0 @@
-/* Pagination service */
-var d2Services = angular.module('d2Services', ['ngResource'])
-
-/* Factory for loading translation strings */
-.factory('i18nLoader', function ($q, $http, storage, DialogService) {
- 
-    var getTranslationStrings = function(locale){
-        var defaultUrl = 'i18n/i18n_app.properties';
-        var url = '';
-        if(locale === 'en' || !locale){
-            url = defaultUrl;
-        }
-        else{
-            url = 'i18n/i18n_app_' + locale + '.properties';
-        }
-
-        var tx = {locale: locale};
-
-        var promise = $http.get(url).then(function(response){
-            tx= {locale: locale, keys: dhis2.util.parseJavaProperties(response.data)};
-            return tx;
-        }, function(){
-            var dialogOptions = {
-                headerText: 'missing_translation_file',
-                bodyText: 'missing_translation_using_default'
-            };
-
-            DialogService.showDialog({}, dialogOptions);
-            var p = $http.get(defaultUrl).then(function(response){
-                tx= {locale: locale, keys: dhis2.util.parseJavaProperties(response.data)};
-                return tx;
-            });
-            return p;
-        });
-        return promise;
-    };
-
-    var getLocale = function(){
-        var locale = 'en';
-
-        var promise = $http.get('../api/me/profile.json').then(function(response){
-            storage.set('USER_PROFILE', response.data);
-            if(response.data && response.data.settings && response.data.settings.keyUiLocale){
-                locale = response.data.settings.keyUiLocale;
-            }
-            return locale;
-        }, function(){
-            return locale;
-        });
-
-        return promise;
-    };
-    return function () {
-        var deferred = $q.defer(), translations;    
-        var userProfile = storage.get('USER_PROFILE');
-        if(userProfile && userProfile.settings && userProfile.settings.keyUiLocale){                
-            getTranslationStrings(userProfile.settings.keyUiLocale).then(function(response){
-                translations = response.keys;
-                deferred.resolve(translations);
-            });
-            return deferred.promise;
-        }
-        else{
-            getLocale().then(function(locale){
-                getTranslationStrings(locale).then(function(response){
-                    translations = response.keys;
-                    deferred.resolve(translations);
-                });
-            });
-            return deferred.promise;
-        }
-    };
-})
-
-/* Factory for loading external data */
-.factory('ExternalDataFactory', function($http) {
-
-    return {        
-        get: function(fileName) {
-            var promise = $http.get( fileName ).then(function(response){
-                return response.data;
-            });            
-            return promise;
-        }
-    };
-})
-
-/* service for getting calendar setting */
-.service('CalendarService', function(storage, $rootScope){    
-
-    return {
-        getSetting: function() {
-            
-            var dhis2CalendarFormat = {keyDateFormat: 'yyyy-MM-dd', keyCalendar: 'gregorian', momentFormat: 'YYYY-MM-DD'};                
-            var storedFormat = storage.get('CALENDAR_SETTING');
-            if(angular.isObject(storedFormat) && storedFormat.keyDateFormat && storedFormat.keyCalendar){
-                if(storedFormat.keyCalendar === 'iso8601'){
-                    storedFormat.keyCalendar = 'gregorian';
-                }
-
-                if(storedFormat.keyDateFormat === 'dd-MM-yyyy'){
-                    dhis2CalendarFormat.momentFormat = 'DD-MM-YYYY';
-                }
-                
-                dhis2CalendarFormat.keyCalendar = storedFormat.keyCalendar;
-                dhis2CalendarFormat.keyDateFormat = storedFormat.keyDateFormat;
-            }
-            $rootScope.dhis2CalendarFormat = dhis2CalendarFormat;
-            return dhis2CalendarFormat;
-        }
-    };            
-})
-
-/* service for dealing with dates */
-.service('DateUtils', function($filter, CalendarService){
-    
-    return {        
-        getDate: function(dateValue){
-            if(!dateValue){
-                return;
-            }            
-            var calendarSetting = CalendarService.getSetting();
-            dateValue = moment(dateValue, calendarSetting.momentFormat)._d;
-            return Date.parse(dateValue);
-        },
-        format: function(dateValue) {            
-            if(!dateValue){
-                return;
-            }
-
-            var calendarSetting = CalendarService.getSetting();            
-            dateValue = moment(dateValue, calendarSetting.momentFormat)._d;
-            dateValue = $filter('date')(dateValue, calendarSetting.keyDateFormat);            
-            return dateValue;
-        },
-        formatToHrsMins: function(dateValue) {
-            var calendarSetting = CalendarService.getSetting();
-            var dateFormat = 'YYYY-MM-DD @ hh:mm A';
-            if(calendarSetting.keyDateFormat === 'dd-MM-yyyy'){
-                dateFormat = 'DD-MM-YYYY @ hh:mm A';
-            }            
-            return moment(dateValue).format(dateFormat);
-        },
-        getToday: function(){  
-            var calendarSetting = CalendarService.getSetting();
-            var tdy = $.calendars.instance(calendarSetting.keyCalendar).newDate();            
-            var today = moment(tdy._year + '-' + tdy._month + '-' + tdy._day, 'YYYY-MM-DD')._d;            
-            today = Date.parse(today);     
-            today = $filter('date')(today,  calendarSetting.keyDateFormat);
-            return today;
-        },
-        formatFromUserToApi: function(dateValue){            
-            if(!dateValue){
-                return;
-            }
-            var calendarSetting = CalendarService.getSetting();
-            dateValue = moment(dateValue, calendarSetting.momentFormat)._d;
-            dateValue = Date.parse(dateValue);     
-            dateValue = $filter('date')(dateValue, 'yyyy-MM-dd'); 
-            return dateValue;            
-        },
-        formatFromApiToUser: function(dateValue){            
-            if(!dateValue){
-                return;
-            }            
-            var calendarSetting = CalendarService.getSetting();
-            dateValue = moment(dateValue, 'YYYY-MM-DD')._d;
-            return $filter('date')(dateValue, calendarSetting.keyDateFormat); 
-        }
-    };
-})
-
-/* service for dealing with custom form */
-.service('CustomFormService', function(){
-    
-    return {
-        getForProgramStage: function(programStage){
-            
-            var htmlCode = programStage.dataEntryForm ? programStage.dataEntryForm.htmlCode : null;  
-            
-            if(htmlCode){                
-            
-                var programStageDataElements = [];
-
-                angular.forEach(programStage.programStageDataElements, function(prStDe){
-                    programStageDataElements[prStDe.dataElement.id] = prStDe;
-                });
-
-                var inputRegex = /<input.*?\/>/g,
-                    match,
-                    inputFields = [],
-                    hasEventDate = false;                
-
-                while (match = inputRegex.exec(htmlCode)) {                
-                    inputFields.push(match[0]);
-                }
-                
-                for(var i=0; i<inputFields.length; i++){                    
-                    var inputField = inputFields[i];                    
-                    var inputElement = $.parseHTML( inputField );
-                    var attributes = {};
-                                       
-                    $(inputElement[0].attributes).each(function() {
-                        attributes[this.nodeName] = this.value;                       
-                    });
-                    
-                    var fieldId = '', errorMessageId = '', newInputField;   
-                    if(attributes.hasOwnProperty('id')){
-                        
-                        if(attributes['id'] === 'executionDate'){
-                            fieldId = 'eventDate';
-                            errorMessageId = '"' + 'eventDate' + '"';
-                            hasEventDate = true;
-                            
-                            //name needs to be unique so that it can be used for validation in angularjs
-                            if(attributes.hasOwnProperty('name')){
-                                attributes['name'] = fieldId;
-                            }
-                            
-                            newInputField = '<input type="text" ' +
-                                                this.getAttributesAsString(attributes) +
-                                                ' d2-validation ' +
-                                                ' ng-model="currentEvent.' + fieldId + '"' +
-                                                ' input-field-id="' + fieldId + '"' +
-                                                ' d2-date ' +
-                                                ' max-date="' + 0 + '"' + 
-                                                ' placeholder="{{dhis2CalendarFormat.keyDateFormat}}" ' +
-                                                ' ng-class="getInputNotifcationClass(prStDes.' + fieldId + '.dataElement.id,true)"' +
-                                                ' blur-or-change="saveDatavalue(prStDes.'+ fieldId + ')"' + 
-                                                ' ng-required="{{true}}">';
-                        }
-                        else{
-                            fieldId = attributes['id'].substring(4, attributes['id'].length-1).split("-")[1]; 
-                            errorMessageId = 'prStDes.' + fieldId + '.dataElement.id';
-                            
-                            //name needs to be unique so that it can be used for validation in angularjs
-                            if(attributes.hasOwnProperty('name')){
-                                attributes['name'] = fieldId;
-                            }
-
-                            //check data element type and generate corresponding angular input field
-                            if(programStageDataElements[fieldId].dataElement.type === "int"){
-                                newInputField = '<input type="text" ' +
-                                                this.getAttributesAsString(attributes) +
-                                                ' d2-validation ' +
-                                                ' d2-number-validation ' +
-                                                ' number-type="' + programStageDataElements[fieldId].dataElement.numberType + '" ' +
-                                                ' ng-model="currentEvent.' + fieldId + '"' +
-                                                ' input-field-id="' + fieldId + '"' +
-                                                ' ng-class="getInputNotifcationClass(prStDes.' + fieldId + '.dataElement.id,true)"' +
-                                                ' ng-disabled="selectedEnrollment.status===\'CANCELLED\' || selectedEnrollment.status===\'COMPLETED\'"' +
-                                                ' ng-blur="saveDatavalue(prStDes.'+ fieldId + ')"' + 
-                                                ' ng-required="{{prStDes.' + fieldId + '.compulsory}}">';
-                            }
-                            if(programStageDataElements[fieldId].dataElement.type === "string"){
-                                if(programStageDataElements[fieldId].dataElement.optionSet){
-                                    var optionSetId = programStageDataElements[fieldId].dataElement.optionSet.id;
-                                    newInputField = '<input type="text" ' +
-                                                this.getAttributesAsString(attributes) +
-                                                ' d2-validation ' +
-                                                ' ng-model="currentEvent.' + fieldId + '" ' +
-                                                ' input-field-id="' + fieldId + '"' +
-                                                ' ng-disabled="selectedEnrollment.status===\'CANCELLED\' || selectedEnrollment.status===\'COMPLETED\' || currentEvent[uid]==\'uid\'"' +
-                                                ' ng-required="{{prStDes.' + fieldId + '.compulsory}}"' +
-                                                ' typeahead="option.name as option.name for option in optionSets.'+optionSetId+'.options | filter:$viewValue | limitTo:20"' +
-                                                ' typeahead-editable="false" ' +
-                                                ' d2-typeahead-validation ' +
-                                                ' class="typeahead" ' +
-                                                ' placeholder="&#xf0d7;&nbsp;&nbsp;" ' +
-                                                ' ng-class="getInputNotifcationClass(prStDes.' + fieldId + '.dataElement.id,true)"' +                                            
-                                                ' ng-blur="saveDatavalue(prStDes.'+ fieldId + ')"' +
-                                                ' typeahead-open-on-focus ng-required="prStDes.'+fieldId+'.compulsory"> ';
-                                }
-                                else{
-                                    newInputField = '<input type="text" ' +
-                                                this.getAttributesAsString(attributes) +
-                                                ' d2-validation ' +
-                                                ' ng-model="currentEvent.' + fieldId + '" ' +
-                                                ' input-field-id="' + fieldId + '"' +
-                                                ' ng-disabled="selectedEnrollment.status===\'CANCELLED\' || selectedEnrollment.status===\'COMPLETED\' || currentEvent[uid]==\'uid\'"' +
-                                                ' ng-class="getInputNotifcationClass(prStDes.' + fieldId + '.dataElement.id,true)"' +
-                                                ' ng-blur="saveDatavalue(prStDes.'+ fieldId + ')"' +
-                                                ' ng-required="prStDes.' + fieldId + '.compulsory"> ';                                     
-                                }
-                            }
-                            if(programStageDataElements[fieldId].dataElement.type === "bool"){
-                                newInputField = '<select ' +
-                                                this.getAttributesAsString(attributes) +
-                                                ' d2-validation ' +
-                                                ' ng-model="currentEvent.' + fieldId + '" ' +
-                                                ' input-field-id="' + fieldId + '"' +
-                                                ' ng-class="getInputNotifcationClass(prStDes.' + fieldId + '.dataElement.id,true)"' +
-                                                ' ng-disabled="selectedEnrollment.status===\'CANCELLED\' || selectedEnrollment.status===\'COMPLETED\'"' +
-                                                ' ng-change="saveDatavalue(prStDes.'+ fieldId + ')"' + 
-                                                ' ng-required="{{prStDes.' + fieldId + '.compulsory}}">' + 
-                                                '<option value="">{{\'please_select\'| translate}}</option>' +
-                                                '<option value="false">{{\'no\'| translate}}</option>' + 
-                                                '<option value="true">{{\'yes\'| translate}}</option>' +
-                                                '</select> ';                                     
-                            }
-                            if(programStageDataElements[fieldId].dataElement.type === "date"){
-                                var maxDate = programStageDataElements[fieldId].allowFutureDate ? '' : 0;
-                                newInputField = '<input type="text" ' +
-                                                this.getAttributesAsString(attributes) +
-                                                ' d2-validation ' +
-                                                ' ng-model="currentEvent.' + fieldId + '"' +
-                                                ' input-field-id="' + fieldId + '"' +                                                
-                                                ' placeholder="{{dhis2CalendarFormat.keyDateFormat}}" ' +
-                                                ' d2-date ' +
-                                                ' max-date="' + maxDate + '"' +
-                                                ' ng-class="getInputNotifcationClass(prStDes.' + fieldId + '.dataElement.id,true)"' +
-                                                ' ng-disabled="selectedEnrollment.status===\'CANCELLED\' || selectedEnrollment.status===\'COMPLETED\'"' +
-                                                ' blur-or-change="saveDatavalue(prStDes.'+ fieldId + ')"' + 
-                                                ' ng-required="{{prStDes.' + fieldId + '.compulsory}}"> '; 
-                            }
-                            if(programStageDataElements[fieldId].dataElement.type === "trueOnly"){
-                                newInputField = '<input type="checkbox" ' +
-                                                this.getAttributesAsString(attributes) +
-                                                ' d2-validation ' +
-                                                ' ng-model="currentEvent.' + fieldId + '"' +
-                                                ' input-field-id="' + fieldId + '"' +
-                                                ' ng-class="getInputNotifcationClass(prStDes.' + fieldId + '.dataElement.id,true)"' +
-                                                ' ng-disabled="selectedEnrollment.status===\'CANCELLED\' || selectedEnrollment.status===\'COMPLETED\'"' +
-                                                ' ng-change="saveDatavalue(prStDes.'+ fieldId + ')"' +
-                                                ' ng-required="{{prStDes.' + fieldId + '.compulsory}}"> ';
-                            }                            
-                        }
-						
-                        newInputField = newInputField + ' <span ng-show="(outerForm.'+ fieldId +'.$dirty && outerForm.'+ fieldId +'.$invalid) || (outerForm.submitted && outerForm.'+ fieldId +'.$invalid) || (currentEvent.' + fieldId + ' && outerForm.' + fieldId + '.$invalid)" class="required">{{getErrorMessage(' + errorMessageId + ')}}</span> ';
-                        
-                        htmlCode = htmlCode.replace(inputField, newInputField);
-                    }
-                }
-                return {htmlCode: htmlCode, hasEventDate: hasEventDate};
-            }
-            return null;
-        },
-        getForTrackedEntity: function(trackedEntity, target){
-            if(!trackedEntity ){
-                return null;
-            }
-
-            var htmlCode = trackedEntity.dataEntryForm ? trackedEntity.dataEntryForm.htmlCode : null;
-            if(htmlCode){                
-            
-                var trackedEntityFormAttributes = [];
-                angular.forEach(trackedEntity.attributes, function(att){                    
-                    trackedEntityFormAttributes[att.id] = att;
-                });
-
-                
-                var inputRegex = /<input.*?\/>/g, match, inputFields = [];
-                var hasProgramDate = false;
-                while (match = inputRegex.exec(htmlCode)) {                
-                    inputFields.push(match[0]);                    
-                }
-
-                for(var i=0; i<inputFields.length; i++){                    
-                    var inputField = inputFields[i];                    
-                    var inputElement = $.parseHTML( inputField );
-                    var attributes = {};
-                                       
-                    $(inputElement[0].attributes).each(function() {
-                        attributes[this.nodeName] = this.value;                       
-                    });
-                    
-                    var attId = '', newInputField, programId;     
-                    if(attributes.hasOwnProperty('attributeid')){
-                        attId = attributes['attributeid'];
-
-                        var fieldName = attId;                        
-                        var attMaxDate = trackedEntityFormAttributes[attId].allowFutureDate ? '' : 0;
-                        
-                        //check attribute type and generate corresponding angular input field
-                        if(trackedEntityFormAttributes[attId].valueType === "number"){
-                            newInputField = '<input type="text" ' +
-                                            ' name="' + fieldName + '"' +                          
-                                            ' element-id="' + i + '"' +
-                                            this.getAttributesAsString(attributes) +
-                                            ' d2-validation ' +
-                                            ' d2-number-validation ' +
-                                            ' d2-focus-next-on-enter' + 
-                                            ' ng-model="selectedTei.' + attId + '" ' +
-                                            ' ng-disabled="editingDisabled"' +
-                                            ' ng-blur="validationAndSkipLogic(selectedTei,\'' + attId + '\')" ' +
-                                            ' ng-required=" ' + trackedEntityFormAttributes[attId].mandatory + '"> ';
-                        }                                               
-                        else if(trackedEntityFormAttributes[attId].valueType === "optionSet"){
-                            var optionSetId = trackedEntityFormAttributes[attId].optionSet.id;                            
-                            newInputField = '<input type="text" ' +
-                                            ' name="' + fieldName + '"' +
-                                            ' element-id="' + i + '"' +
-                                            this.getAttributesAsString(attributes) +
-                                            ' d2-focus-next-on-enter' + 
-                                            ' ng-model="selectedTei.' + attId + '" ' +
-                                            ' ng-disabled="editingDisabled"' +
-                                            ' d2-validation ' +
-                                            ' d2-typeahead-validation ' +
-                                            ' class="typeahead" ' +
-                                            ' placeholder="&#xf0d7;&nbsp;&nbsp;" ' +
-                                            ' typeahead-editable="false" ' + 
-                                            ' typeahead="option.name as option.name for option in optionSets.' + optionSetId + '.options | filter:$viewValue | limitTo:50"' +
-                                            ' typeahead-open-on-focus ' +
-                                            ' ng-blur="validationAndSkipLogic(selectedTei,\'' + attId + '\')" ' +
-                                            ' ng-required=" ' + trackedEntityFormAttributes[attId].mandatory + '"> ';                            
-                        }
-                        else if(trackedEntityFormAttributes[attId].valueType === "bool"){
-                            newInputField = '<select ' +
-                                            ' name="' + fieldName + '"' +
-                                            ' element-id="' + i + '"' +
-                                            this.getAttributesAsString(attributes) +
-                                            ' d2-focus-next-on-enter' + 
-                                            ' ng-model="selectedTei.' + attId + '" ' +
-                                            ' ng-disabled="editingDisabled"' +
-                                            ' ng-change="validationAndSkipLogic(selectedTei,\'' + attId + '\')" ' +
-                                            ' ng-required=" ' + trackedEntityFormAttributes[attId].mandatory + '"> ' +
-                                            ' <option value="">{{\'please_select\'| translate}}</option>' +
-                                            ' <option value="false">{{\'no\'| translate}}</option>' + 
-                                            ' <option value="true">{{\'yes\'| translate}}</option>' +
-                                            '</select> ';
-                        }
-                        else if(trackedEntityFormAttributes[attId].valueType === "date"){
-                            newInputField = '<input type="text" ' +
-                                            ' name="' + fieldName + '"' +
-                                            ' element-id="' + i + '"' +
-                                            this.getAttributesAsString(attributes) +
-                                            ' d2-focus-next-on-enter' + 
-                                            ' placeholder="{{dhis2CalendarFormat.keyDateFormat}}" ' +
-                                            ' ng-model="selectedTei.' + attId + '" ' +
-                                            ' ng-disabled="editingDisabled"' +
-                                            ' max-date="' + attMaxDate + '"' + '\'' +
-                                            ' d2-date' +
-                                            ' d2-validation ' +
-                                            ' blur-or-change="validationAndSkipLogic(selectedTei,\'' + attId + '\')" ' +
-                                            ' ng-required=" ' + trackedEntityFormAttributes[attId].mandatory + '"> ';
-                        }
-                        else if(trackedEntityFormAttributes[attId].valueType === "trueOnly"){
-                            newInputField = '<input type="checkbox" ' +  
-                                            ' name="' + fieldName + '"' +
-                                            ' element-id="' + i + '"' +
-                                            this.getAttributesAsString(attributes) + 
-                                            ' d2-validation ' +
-                                            ' d2-focus-next-on-enter' + 
-                                            ' ng-model="selectedTei.' + attId + '" ' +
-                                            ' ng-disabled="editingDisabled"' +
-                                            ' ng-change="validationAndSkipLogic(selectedTei,\'' + attId + '\')" ' +
-                                            ' ng-required=" ' + trackedEntityFormAttributes[attId].mandatory + '"> ';
-                        }
-                        else if(trackedEntityFormAttributes[attId].valueType === "email"){
-                            newInputField = '<input type="email" ' +    
-                                            ' name="' + fieldName + '"' +                                              
-                                            ' element-id="' + i + '"' +
-                                            this.getAttributesAsString(attributes) +
-                                            ' d2-validation ' +
-                                            ' d2-focus-next-on-enter' + 
-                                            ' ng-model="selectedTei.' + attId + '" ' +
-                                            ' ng-disabled="editingDisabled"' +
-                                            ' ng-blur="validationAndSkipLogic(selectedTei,\'' + attId + '\')" ' +
-                                            ' ng-required=" ' + trackedEntityFormAttributes[attId].mandatory + '"> ';
-                        }
-                        else {
-                            newInputField = '<input type="text" ' +
-                                            ' name="' + fieldName + '"' +
-                                            ' element-id="' + i + '"' +                                             
-                                            this.getAttributesAsString(attributes) +
-                                            ' d2-validation ' +
-                                            ' d2-focus-next-on-enter' + 
-                                            ' ng-model="selectedTei.' + attId + '" ' +
-                                            ' ng-disabled="editingDisabled"' +
-                                            ' ng-blur="validationAndSkipLogic(selectedTei,\'' + attId + '\')" ' +
-                                            ' ng-required=" ' + trackedEntityFormAttributes[attId].mandatory + '"> ';
-                        } 
-                    }                        
-                 
-                    if(attributes.hasOwnProperty('programid')){
-                        hasProgramDate = true;
-                        programId = attributes['programid'];                        
-                        if(programId === 'enrollmentDate'){
-                            fieldName = 'dateOfEnrollment';
-                            var enMaxDate = trackedEntity.selectEnrollmentDatesInFuture ? '' : 0;
-                            newInputField = '<input type="text" ' +
-                                            ' name="' + fieldName + '"' +
-                                            ' element-id="' + i + '"' +       
-                                            this.getAttributesAsString(attributes) +
-                                            ' d2-focus-next-on-enter' + 
-                                            ' placeholder="{{dhis2CalendarFormat.keyDateFormat}}" ' +
-                                            ' ng-model="selectedEnrollment.dateOfEnrollment" ' +
-                                            ' ng-disabled="\'' + target + '\' === \'PROFILE\'"' +
-                                            ' d2-date' +
-                                            ' max-date="' + enMaxDate + '"' +
-                                            ' ng-required="true"> ';
-                        }
-                        if(programId === 'dateOfIncident' && trackedEntity.displayIncidentDate){
-                            fieldName = 'dateOfIncident';
-                            var inMaxDate = trackedEntity.selectIncidentDatesInFuture ? '' : 0;                            
-                            newInputField = '<input type="text" ' +
-                                            ' name="' + fieldName + '"' +
-                                            ' element-id="' + i + '"' +    
-                                            this.getAttributesAsString(attributes) +
-                                            ' d2-focus-next-on-enter' + 
-                                            ' placeholder="{{dhis2CalendarFormat.keyDateFormat}}" ' +
-                                            ' ng-model="selectedEnrollment.dateOfIncident" ' +
-                                            ' ng-disabled="\'' + target + '\' === \'PROFILE\'"' +
-                                            ' d2-date ' +
-                                            ' max-date="' + inMaxDate + '"> ';
-                        }
-                    }
-                    
-                    newInputField = //'<ng-form name="innerForm">' + 
-                                        newInputField + 
-                                        ' <span ng-show="outerForm.submitted && outerForm.'+ fieldName +'.$invalid" class="required">{{\'required\' | translate}}</span> ';
-                                    //'</ng-form>';
-                                    
-                    htmlCode = htmlCode.replace(inputField, newInputField);                    
-                }                
-                return {htmlCode: htmlCode, hasProgramDate: hasProgramDate};
-            }            
-            return null;
-        },
-        getAttributesAsString: function(attributes){
-            if(attributes){
-                var attributesAsString = '';                
-                for(var prop in attributes){
-                    if(prop !== 'value'){
-                        attributesAsString += prop + '="' + attributes[prop] + '" ';
-                    }
-                }
-                return attributesAsString;
-            }
-            return null;
-        }
-    };            
-})
-
-/* Context menu for grid*/
-.service('ContextMenuSelectedItem', function(){
-    this.selectedItem = '';
-    
-    this.setSelectedItem = function(selectedItem){  
-        this.selectedItem = selectedItem;        
-    };
-    
-    this.getSelectedItem = function(){
-        return this.selectedItem;
-    };
-})
-
-/* Error messages*/
-.service('ErrorMessageService', function(){
-    this.errorMessages = {};
-    
-    this.setErrorMessages = function(errorMessages){  
-        this.errorMessages = errorMessages;        
-    };
-    
-    this.getErrorMessages = function(){
-        return this.errorMessages;
-    };
-    
-    this.get = function(id){
-        return this.errorMessages[id];
-    };
-})
-
-/* Modal service for user interaction */
-.service('ModalService', ['$modal', function($modal) {
-
-    var modalDefaults = {
-        backdrop: true,
-        keyboard: true,
-        modalFade: true,
-        templateUrl: 'views/modal.html'
-    };
-
-    var modalOptions = {
-        closeButtonText: 'Close',
-        actionButtonText: 'OK',
-        headerText: 'Proceed?',
-        bodyText: 'Perform this action?'
-    };
-
-    this.showModal = function(customModalDefaults, customModalOptions) {
-        if (!customModalDefaults)
-            customModalDefaults = {};
-        customModalDefaults.backdrop = 'static';
-        return this.show(customModalDefaults, customModalOptions);
-    };
-
-    this.show = function(customModalDefaults, customModalOptions) {
-        //Create temp objects to work with since we're in a singleton service
-        var tempModalDefaults = {};
-        var tempModalOptions = {};
-
-        //Map angular-ui modal custom defaults to modal defaults defined in service
-        angular.extend(tempModalDefaults, modalDefaults, customModalDefaults);
-
-        //Map modal.html $scope custom properties to defaults defined in service
-        angular.extend(tempModalOptions, modalOptions, customModalOptions);
-
-        if (!tempModalDefaults.controller) {
-            tempModalDefaults.controller = function($scope, $modalInstance) {
-                $scope.modalOptions = tempModalOptions;
-                $scope.modalOptions.ok = function(result) {
-                    $modalInstance.close(result);
-                };
-                $scope.modalOptions.close = function(result) {
-                    $modalInstance.dismiss('cancel');
-                };
-            };
-        }
-
-        return $modal.open(tempModalDefaults).result;
-    };
-
-}])
-
-/* Dialog service for user interaction */
-.service('DialogService', ['$modal', function($modal) {
-
-    var dialogDefaults = {
-        backdrop: true,
-        keyboard: true,
-        backdropClick: true,
-        modalFade: true,            
-        templateUrl: 'views/dialog.html'
-    };
-
-    var dialogOptions = {
-        closeButtonText: 'close',
-        actionButtonText: 'ok',
-        headerText: 'dhis2_tracker',
-        bodyText: 'Perform this action?'
-    };
-
-    this.showDialog = function(customDialogDefaults, customDialogOptions) {
-        if (!customDialogDefaults)
-            customDialogDefaults = {};
-        customDialogDefaults.backdropClick = false;
-        return this.show(customDialogDefaults, customDialogOptions);
-    };
-
-    this.show = function(customDialogDefaults, customDialogOptions) {
-        //Create temp objects to work with since we're in a singleton service
-        var tempDialogDefaults = {};
-        var tempDialogOptions = {};
-
-        //Map angular-ui modal custom defaults to modal defaults defined in service
-        angular.extend(tempDialogDefaults, dialogDefaults, customDialogDefaults);
-
-        //Map modal.html $scope custom properties to defaults defined in service
-        angular.extend(tempDialogOptions, dialogOptions, customDialogOptions);
-
-        if (!tempDialogDefaults.controller) {
-            tempDialogDefaults.controller = function($scope, $modalInstance) {
-                $scope.dialogOptions = tempDialogOptions;
-                $scope.dialogOptions.ok = function(result) {
-                    $modalInstance.close(result);
-                };                           
-            };
-        }
-
-        return $modal.open(tempDialogDefaults).result;
-    };
-
-}])
-
-.service('Paginator', function () {
-    this.page = 1;
-    this.pageSize = 50;
-    this.itemCount = 0;
-    this.pageCount = 0;
-    this.toolBarDisplay = 5;
-
-    this.setPage = function (page) {
-        if (page > this.getPageCount()) {
-            return;
-        }
-
-        this.page = page;
-    };
-    
-    this.getPage = function(){
-        return this.page;
-    };
-    
-    this.setPageSize = function(pageSize){
-      this.pageSize = pageSize;
-    };
-    
-    this.getPageSize = function(){
-        return this.pageSize;
-    };
-    
-    this.setItemCount = function(itemCount){
-      this.itemCount = itemCount;
-    };
-    
-    this.getItemCount = function(){
-        return this.itemCount;
-    };
-    
-    this.setPageCount = function(pageCount){
-        this.pageCount = pageCount;
-    };
-
-    this.getPageCount = function () {
-        return this.pageCount;
-    };
-
-    this.lowerLimit = function() { 
-        var pageCountLimitPerPageDiff = this.getPageCount() - this.toolBarDisplay;
-
-        if (pageCountLimitPerPageDiff < 0) { 
-            return 0; 
-        }
-
-        if (this.getPage() > pageCountLimitPerPageDiff + 1) { 
-            return pageCountLimitPerPageDiff; 
-        } 
-
-        var low = this.getPage() - (Math.ceil(this.toolBarDisplay/2) - 1); 
-
-        return Math.max(low, 0);
-    };
-})
-
-.service('GridColumnService', function(){
-    return {        
-        columnExists: function(cols, id) {
-            var colExists = false;
-            if(!angular.isObject(cols) || !id || angular.isObject(cols) && !cols.length){
-                return colExists;
-            }
-            
-            for(var i=0; i<cols.length && !colExists; i++){
-                if(cols[i].id === id){
-                    colExists = true;
-                }
-            }
-            return colExists;
-        }
-    };
-});

=== modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/services.js'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/services.js	2015-02-04 14:39:40 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/services.js	2015-02-06 20:22:45 +0000
@@ -429,6 +429,10 @@
                     });
 
                     angular.forEach(tei.attributes, function(att){
+                        if(attsById[att.attribute]){
+                            att.displayName = attsById[att.attribute].name;
+                        }
+                        
                         if(att.type === 'trueOnly'){
                             if(att.value === 'true'){
                                 att.value = true;

=== modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/styles/style.css'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/styles/style.css	2015-01-28 09:40:39 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/styles/style.css	2015-02-06 20:22:45 +0000
@@ -486,6 +486,13 @@
     margin-top: 5px;
 }
 
+.trimmed-alert {
+	padding: 10px;
+	margin-bottom: 20px;
+	border: 1px solid transparent;
+	border-radius: 4px
+}
+
 .remove-default-padding {
     margin: -15px !important;    
 }

=== modified file 'dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/dhis2/dhis2.angular.directives.js'
--- dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/dhis2/dhis2.angular.directives.js	2015-02-02 13:42:37 +0000
+++ dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/dhis2/dhis2.angular.directives.js	2015-02-06 20:22:45 +0000
@@ -253,7 +253,7 @@
     };
 })
 
-.directive('sortable', function() {        
+/*.directive('d2Sortable', function() {        
 
     return {        
         restrict: 'A',        
@@ -266,6 +266,57 @@
             });
         }  
     };
+})*/
+
+.directive('d2Sortable', function($timeout) {        
+
+    return {        
+        restrict: 'A',        
+        link: function(scope, element, attrs){
+            element.sortable({
+                connectWith: ".connectedSortable",
+                placeholder: "ui-state-highlight",
+                tolerance: "pointer",
+                handle: '.handle',
+                change: function(event, ui){
+                    $timeout(function() {
+                        scope.widgetsOrder = getSortedItems(ui);
+                        scope.$apply();
+                    });
+                    
+                },
+                receive: function(event, ui){
+                    $timeout(function() {
+                        scope.widgetsOrder = getSortedItems(ui);
+                        scope.$apply();
+                    });
+                }
+            });
+            
+            var getSortedItems = function(ui){
+                var biggerWidgets = $("#biggerWidget").sortable( "toArray");
+                var smallerWidgets = $("#smallerWidget").sortable( "toArray");
+                var movedIsIdentifeid = false;
+
+                //look for the moved item in the bigger block
+                for(var i=0; i<biggerWidgets.length && !movedIsIdentifeid; i++){
+                    if(biggerWidgets[i] === ""){
+                        biggerWidgets[i] = ui.item[0].id;
+                        movedIsIdentifeid = true;
+                    }
+                }
+
+                //look for the moved item in the smaller block
+                for(var i=0; i<smallerWidgets.length && !movedIsIdentifeid; i++){
+                    if(smallerWidgets[i] === ""){
+                        smallerWidgets[i] = ui.item[0].id;
+                        movedIsIdentifeid = true;
+                    }
+                }
+                return {smallerWidgets: smallerWidgets, biggerWidgets: biggerWidgets};
+            };
+        }  
+    };
 })
 
 .directive('serversidePaginator', function factory() {
@@ -438,14 +489,16 @@
     };
 })
 
-.directive('d2CustomForm', function($compile, $parse, CustomFormService) {
+.directive('d2CustomForm', function($compile) {
     return{ 
         restrict: 'E',
-        link: function(scope, elm, attrs){            
-             scope.$watch('customForm', function(){
-                 elm.html(scope.customForm.htmlCode);
-                 $compile(elm.contents())(scope);
-             });
+        link: function(scope, elm, attrs){
+            scope.$watch('customForm', function(){
+                if(angular.isObject(scope.customForm)){
+                    elm.html(scope.customForm.htmlCode);
+                    $compile(elm.contents())(scope);
+                }                
+            });
         }
     };
 })

=== modified file 'dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/dhis2/dhis2.angular.services.js'
--- dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/dhis2/dhis2.angular.services.js	2015-02-04 12:53:26 +0000
+++ dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/dhis2/dhis2.angular.services.js	2015-02-06 20:22:45 +0000
@@ -14,10 +14,10 @@
             url = 'i18n/i18n_app_' + locale + '.properties';
         }
 
-        var tx = {};
+        var tx = {locale: locale};
 
         var promise = $http.get(url).then(function(response){
-            tx = {locale: locale, keys: dhis2.util.parseJavaProperties(response.data)};
+            tx= {locale: locale, keys: dhis2.util.parseJavaProperties(response.data)};
             return tx;
         }, function(){
             var dialogOptions = {
@@ -27,7 +27,7 @@
 
             DialogService.showDialog({}, dialogOptions);
             var p = $http.get(defaultUrl).then(function(response){
-                tx = {locale: locale, keys: dhis2.util.parseJavaProperties(response.data)};
+                tx= {locale: locale, keys: dhis2.util.parseJavaProperties(response.data)};
                 return tx;
             });
             return p;
@@ -188,7 +188,8 @@
 
                 var inputRegex = /<input.*?\/>/g,
                     match,
-                    inputFields = [];                
+                    inputFields = [],
+                    hasEventDate = false;                
 
                 while (match = inputRegex.exec(htmlCode)) {                
                     inputFields.push(match[0]);
@@ -203,7 +204,7 @@
                         attributes[this.nodeName] = this.value;                       
                     });
                     
-                    var fieldId = '', errorMessageId = '', newInputField, hasEventDate = false;     
+                    var fieldId = '', errorMessageId = '', newInputField;   
                     if(attributes.hasOwnProperty('id')){
                         
                         if(attributes['id'] === 'executionDate'){
@@ -334,6 +335,188 @@
             }
             return null;
         },
+        getForTrackedEntity: function(trackedEntity, target){
+            if(!trackedEntity ){
+                return null;
+            }
+
+            var htmlCode = trackedEntity.dataEntryForm ? trackedEntity.dataEntryForm.htmlCode : null;
+            if(htmlCode){                
+            
+                var trackedEntityFormAttributes = [];
+                angular.forEach(trackedEntity.attributes, function(att){                    
+                    trackedEntityFormAttributes[att.id] = att;
+                });
+
+                
+                var inputRegex = /<input.*?\/>/g, match, inputFields = [];
+                var hasProgramDate = false;
+                while (match = inputRegex.exec(htmlCode)) {                
+                    inputFields.push(match[0]);                    
+                }
+
+                for(var i=0; i<inputFields.length; i++){                    
+                    var inputField = inputFields[i];                    
+                    var inputElement = $.parseHTML( inputField );
+                    var attributes = {};
+                                       
+                    $(inputElement[0].attributes).each(function() {
+                        attributes[this.nodeName] = this.value;                       
+                    });
+                    
+                    var attId = '', newInputField, programId;     
+                    if(attributes.hasOwnProperty('attributeid')){
+                        attId = attributes['attributeid'];
+
+                        var fieldName = attId;                        
+                        var attMaxDate = trackedEntityFormAttributes[attId].allowFutureDate ? '' : 0;
+                        
+                        //check attribute type and generate corresponding angular input field
+                        if(trackedEntityFormAttributes[attId].valueType === "number"){
+                            newInputField = '<input type="text" ' +
+                                            ' name="' + fieldName + '"' +                          
+                                            ' element-id="' + i + '"' +
+                                            this.getAttributesAsString(attributes) +
+                                            ' d2-validation ' +
+                                            ' d2-number-validation ' +
+                                            ' d2-focus-next-on-enter' + 
+                                            ' ng-model="selectedTei.' + attId + '" ' +
+                                            ' ng-disabled="editingDisabled"' +
+                                            ' ng-blur="validationAndSkipLogic(selectedTei,\'' + attId + '\')" ' +
+                                            ' ng-required=" ' + trackedEntityFormAttributes[attId].mandatory + '"> ';
+                        }                                               
+                        else if(trackedEntityFormAttributes[attId].valueType === "optionSet"){
+                            var optionSetId = trackedEntityFormAttributes[attId].optionSet.id;                            
+                            newInputField = '<input type="text" ' +
+                                            ' name="' + fieldName + '"' +
+                                            ' element-id="' + i + '"' +
+                                            this.getAttributesAsString(attributes) +
+                                            ' d2-focus-next-on-enter' + 
+                                            ' ng-model="selectedTei.' + attId + '" ' +
+                                            ' ng-disabled="editingDisabled"' +
+                                            ' d2-validation ' +
+                                            ' d2-typeahead-validation ' +
+                                            ' class="typeahead" ' +
+                                            ' placeholder="&#xf0d7;&nbsp;&nbsp;" ' +
+                                            ' typeahead-editable="false" ' + 
+                                            ' typeahead="option.name as option.name for option in optionSets.' + optionSetId + '.options | filter:$viewValue | limitTo:50"' +
+                                            ' typeahead-open-on-focus ' +
+                                            ' ng-blur="validationAndSkipLogic(selectedTei,\'' + attId + '\')" ' +
+                                            ' ng-required=" ' + trackedEntityFormAttributes[attId].mandatory + '"> ';                            
+                        }
+                        else if(trackedEntityFormAttributes[attId].valueType === "bool"){
+                            newInputField = '<select ' +
+                                            ' name="' + fieldName + '"' +
+                                            ' element-id="' + i + '"' +
+                                            this.getAttributesAsString(attributes) +
+                                            ' d2-focus-next-on-enter' + 
+                                            ' ng-model="selectedTei.' + attId + '" ' +
+                                            ' ng-disabled="editingDisabled"' +
+                                            ' ng-change="validationAndSkipLogic(selectedTei,\'' + attId + '\')" ' +
+                                            ' ng-required=" ' + trackedEntityFormAttributes[attId].mandatory + '"> ' +
+                                            ' <option value="">{{\'please_select\'| translate}}</option>' +
+                                            ' <option value="false">{{\'no\'| translate}}</option>' + 
+                                            ' <option value="true">{{\'yes\'| translate}}</option>' +
+                                            '</select> ';
+                        }
+                        else if(trackedEntityFormAttributes[attId].valueType === "date"){
+                            newInputField = '<input type="text" ' +
+                                            ' name="' + fieldName + '"' +
+                                            ' element-id="' + i + '"' +
+                                            this.getAttributesAsString(attributes) +
+                                            ' d2-focus-next-on-enter' + 
+                                            ' placeholder="{{dhis2CalendarFormat.keyDateFormat}}" ' +
+                                            ' ng-model="selectedTei.' + attId + '" ' +
+                                            ' ng-disabled="editingDisabled"' +
+                                            ' max-date="' + attMaxDate + '"' + '\'' +
+                                            ' d2-date' +
+                                            ' d2-validation ' +
+                                            ' blur-or-change="validationAndSkipLogic(selectedTei,\'' + attId + '\')" ' +
+                                            ' ng-required=" ' + trackedEntityFormAttributes[attId].mandatory + '"> ';
+                        }
+                        else if(trackedEntityFormAttributes[attId].valueType === "trueOnly"){
+                            newInputField = '<input type="checkbox" ' +  
+                                            ' name="' + fieldName + '"' +
+                                            ' element-id="' + i + '"' +
+                                            this.getAttributesAsString(attributes) + 
+                                            ' d2-validation ' +
+                                            ' d2-focus-next-on-enter' + 
+                                            ' ng-model="selectedTei.' + attId + '" ' +
+                                            ' ng-disabled="editingDisabled"' +
+                                            ' ng-change="validationAndSkipLogic(selectedTei,\'' + attId + '\')" ' +
+                                            ' ng-required=" ' + trackedEntityFormAttributes[attId].mandatory + '"> ';
+                        }
+                        else if(trackedEntityFormAttributes[attId].valueType === "email"){
+                            newInputField = '<input type="email" ' +    
+                                            ' name="' + fieldName + '"' +                                              
+                                            ' element-id="' + i + '"' +
+                                            this.getAttributesAsString(attributes) +
+                                            ' d2-validation ' +
+                                            ' d2-focus-next-on-enter' + 
+                                            ' ng-model="selectedTei.' + attId + '" ' +
+                                            ' ng-disabled="editingDisabled"' +
+                                            ' ng-blur="validationAndSkipLogic(selectedTei,\'' + attId + '\')" ' +
+                                            ' ng-required=" ' + trackedEntityFormAttributes[attId].mandatory + '"> ';
+                        }
+                        else {
+                            newInputField = '<input type="text" ' +
+                                            ' name="' + fieldName + '"' +
+                                            ' element-id="' + i + '"' +                                             
+                                            this.getAttributesAsString(attributes) +
+                                            ' d2-validation ' +
+                                            ' d2-focus-next-on-enter' + 
+                                            ' ng-model="selectedTei.' + attId + '" ' +
+                                            ' ng-disabled="editingDisabled"' +
+                                            ' ng-blur="validationAndSkipLogic(selectedTei,\'' + attId + '\')" ' +
+                                            ' ng-required=" ' + trackedEntityFormAttributes[attId].mandatory + '"> ';
+                        } 
+                    }                        
+                 
+                    if(attributes.hasOwnProperty('programid')){
+                        hasProgramDate = true;
+                        programId = attributes['programid'];                        
+                        if(programId === 'enrollmentDate'){
+                            fieldName = 'dateOfEnrollment';
+                            var enMaxDate = trackedEntity.selectEnrollmentDatesInFuture ? '' : 0;
+                            newInputField = '<input type="text" ' +
+                                            ' name="' + fieldName + '"' +
+                                            ' element-id="' + i + '"' +       
+                                            this.getAttributesAsString(attributes) +
+                                            ' d2-focus-next-on-enter' + 
+                                            ' placeholder="{{dhis2CalendarFormat.keyDateFormat}}" ' +
+                                            ' ng-model="selectedEnrollment.dateOfEnrollment" ' +
+                                            ' ng-disabled="\'' + target + '\' === \'PROFILE\'"' +
+                                            ' d2-date' +
+                                            ' max-date="' + enMaxDate + '"' +
+                                            ' ng-required="true"> ';
+                        }
+                        if(programId === 'dateOfIncident' && trackedEntity.displayIncidentDate){
+                            fieldName = 'dateOfIncident';
+                            var inMaxDate = trackedEntity.selectIncidentDatesInFuture ? '' : 0;                            
+                            newInputField = '<input type="text" ' +
+                                            ' name="' + fieldName + '"' +
+                                            ' element-id="' + i + '"' +    
+                                            this.getAttributesAsString(attributes) +
+                                            ' d2-focus-next-on-enter' + 
+                                            ' placeholder="{{dhis2CalendarFormat.keyDateFormat}}" ' +
+                                            ' ng-model="selectedEnrollment.dateOfIncident" ' +
+                                            ' ng-disabled="\'' + target + '\' === \'PROFILE\'"' +
+                                            ' d2-date ' +
+                                            ' max-date="' + inMaxDate + '"> ';
+                        }
+                    }
+                    
+                    newInputField = //'<ng-form name="innerForm">' + 
+                                        newInputField + 
+                                        ' <span ng-show="outerForm.submitted && outerForm.'+ fieldName +'.$invalid" class="required">{{\'required\' | translate}}</span> ';
+                                    //'</ng-form>';
+                                    
+                    htmlCode = htmlCode.replace(inputField, newInputField);                    
+                }                
+                return {htmlCode: htmlCode, hasProgramDate: hasProgramDate};
+            }            
+            return null;
+        },
         getAttributesAsString: function(attributes){
             if(attributes){
                 var attributesAsString = '';