=== modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-cache-cleaner/index.html' --- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-cache-cleaner/index.html 2015-01-28 19:03:29 +0000 +++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-cache-cleaner/index.html 2015-02-02 13:42:37 +0000 @@ -49,8 +49,8 @@ - - + + === modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/event-capture.appcache' --- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/event-capture.appcache 2015-01-23 14:07:46 +0000 +++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/event-capture.appcache 2015-02-02 13:42:37 +0000 @@ -56,16 +56,14 @@ ../dhis-web-commons/javascripts/angular/angular-animate.js ../dhis-web-commons/javascripts/angular/ui-bootstrap-tpls-0.10.0-draggable-modal.js - -#scripts/angular-translate.min.js ../dhis-web-commons/javascripts/angular/plugins/angularLocalStorage.js ../dhis-web-commons/javascripts/angular/plugins/angular-translate.min.js ../dhis-web-commons/javascripts/angular/plugins/angular-translate-loader-static-files.min.js ../dhis-web-commons/javascripts/angular/plugins/angular-translate-loader-url.min.js -../dhis-web-commons/javascripts/angular/plugins/dhis2/directives.js -../dhis-web-commons/javascripts/angular/plugins/dhis2/filters.js -../dhis-web-commons/javascripts/angular/plugins/dhis2/services.js -../dhis-web-commons/javascripts/angular/plugins/dhis2/controllers.js +../dhis-web-commons/javascripts/dhis2/angular.directives.js +../dhis-web-commons/javascripts/dhis2/angular.filters.js +../dhis-web-commons/javascripts/dhis2/angular.services.js +../dhis-web-commons/javascripts/dhis2/angular.controllers.js ../dhis-web-commons/javascripts/moment/moment-with-langs.min.js === modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/index.html' --- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/index.html 2015-01-29 17:13:36 +0000 +++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/index.html 2015-02-02 13:42:37 +0000 @@ -66,10 +66,10 @@ - - - - + + + + === modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/scripts/controllers.js' --- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/scripts/controllers.js 2015-01-29 17:13:36 +0000 +++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/scripts/controllers.js 2015-02-02 13:42:37 +0000 @@ -196,11 +196,7 @@ ErrorMessageService.setErrorMessages(errorMessages); ProgramValidationService.getByProgram($scope.selectedProgram.id).then(function(pvs){ - $scope.programValidations = pvs; - - console.log('the validations: ', $scope.programValidations); - $scope.loadEvents(); }); }); === modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/profile/profile-controller.js' --- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/profile/profile-controller.js 2015-01-14 11:21:15 +0000 +++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/profile/profile-controller.js 2015-02-02 13:42:37 +0000 @@ -2,7 +2,8 @@ function($rootScope, $scope, CurrentSelection, - DateUtils, + CustomFormService, + TEFormService, TEIService, DialogService, AttributesFactory) { @@ -31,6 +32,24 @@ //if no program, display attributesInNoProgram TEIService.processAttributes($scope.selectedTei, $scope.selectedProgram, $scope.selectedEnrollment).then(function(tei){ $scope.selectedTei = tei; + if($scope.selectedProgram && $scope.selectedProgram.id){ + AttributesFactory.getByProgram($scope.selectedProgram).then(function(atts){ + $scope.attributesById = []; + angular.forEach(atts, function(att){ + $scope.attributesById[att.id] = att; + }); + + $scope.selectedProgram.hasCustomForm = false; + TEFormService.getByProgram($scope.selectedProgram, atts).then(function(teForm){ + if(angular.isObject(teForm)){ + $scope.selectedProgram.hasCustomForm = true; + $scope.selectedProgram.displayCustomForm = $scope.selectedProgram.hasCustomForm ? true:false; + $scope.trackedEntityForm = teForm; + $scope.customForm = CustomFormService.getForTrackedEntity($scope.trackedEntityForm, 'PROFILE'); + } + }); + }); + } }); }); === added file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/registration/custom-form.html' === added file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/registration/default-form.html' --- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/registration/default-form.html 1970-01-01 00:00:00 +0000 +++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/registration/default-form.html 2015-02-02 13:42:37 +0000 @@ -0,0 +1,138 @@ +
+

{{'category'| translate}}

+ + + + + +
+ {{'entity_type'| translate}} + + +
+
+
+

{{'profile'| translate}}

+ + + + + +
+ {{attribute.name}} + + +
+
+ + {{'required'| translate}} +
+
+ + {{'required'| translate}} +
+
+ + {{'required'| translate}} +
+
+
+ +
+
+
+ +
+
+
+ +
+
+
+
+ {{'required'| translate}} +
+
+ + {{'required'| translate}} +
+
+ + {{'required'| translate}} +
+
+ + {{'required'| translate}} +
+
+
+
+ +
+
+

{{'enrollment'| translate}}

+ + + + + + + + + +
+ {{selectedProgram.dateOfEnrollmentDescription}} + + + {{'required'| translate}} +
+ {{selectedProgram.dateOfIncidentDescription}} + + +
+
\ No newline at end of file === modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/registration/registration-controller.js' --- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/registration/registration-controller.js 2015-01-05 15:31:59 +0000 +++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/registration/registration-controller.js 2015-02-02 13:42:37 +0000 @@ -7,6 +7,8 @@ DHIS2EventFactory, TEService, TEIService, + TEFormService, + CustomFormService, EnrollmentService, DialogService, CurrentSelection, @@ -16,7 +18,8 @@ storage) { $scope.today = DateUtils.getToday(); - + $scope.trackedEntityForm = null; + $scope.customForm = null; $scope.optionSets = CurrentSelection.getOptionSets(); if(!$scope.optionSets){ @@ -45,19 +48,30 @@ //watch for selection of program $scope.$watch('selectedProgram', function() { + $scope.trackedEntityForm = null; + $scope.customForm = null; $scope.getAttributes(); }); $scope.getAttributes = function(){ - - if($scope.selectedProgram){ + if($scope.selectedProgram && $scope.selectedProgram.id){ AttributesFactory.getByProgram($scope.selectedProgram).then(function(atts){ $scope.attributes = atts; $scope.attributesById = []; angular.forEach(atts, function(att){ $scope.attributesById[att.id] = att; }); - }); + + $scope.selectedProgram.hasCustomForm = false; + TEFormService.getByProgram($scope.selectedProgram, $scope.attributes).then(function(teForm){ + if(angular.isObject(teForm)){ + $scope.selectedProgram.hasCustomForm = true; + $scope.selectedProgram.displayCustomForm = $scope.selectedProgram.hasCustomForm ? true:false; + $scope.trackedEntityForm = teForm; + $scope.customForm = CustomFormService.getForTrackedEntity($scope.trackedEntityForm, 'ENROLLMENT'); + } + }); + }); } else{ AttributesFactory.getWithoutProgram().then(function(atts){ @@ -70,8 +84,7 @@ } }; - $scope.registerEntity = function(destination){ - + $scope.registerEntity = function(destination){ //check for form validity $scope.outerForm.submitted = true; if( $scope.outerForm.$invalid ){ === modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/registration/registration.html' --- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/registration/registration.html 2015-01-05 15:31:59 +0000 +++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/registration/registration.html 2015-02-02 13:42:37 +0000 @@ -1,147 +1,50 @@
-
- -
-

{{'category' | translate}}

- - - - - -
- {{'entity_type' | translate}} - - -
-
-
- -

{{'profile' | translate}}

- - - - - -
- {{attribute.name}} - - -
-
- - {{'required'| translate}} -
-
- - {{'required'| translate}} -
-
- - {{'required'| translate}} -
-
-
- -
-
-
- -
-
-
- -
-
-
-
- {{'required'| translate}} -
-
- - {{'required'| translate}} -
-
- - {{'required'| translate}} -
-
- - {{'required'| translate}} -
-
-
-
- -
-
-

{{'enrollment' | translate}}

- - - - - - - - - -
- {{selectedProgram.dateOfEnrollmentDescription}} - - - {{'required'| translate}} -
- {{selectedProgram.dateOfIncidentDescription}} - - -
-
- -
+ +
+
+ +
+ + + + + + + + +
+ {{selectedProgram.dateOfEnrollmentDescription}} + + + {{'required'| translate}} +
+ {{selectedProgram.dateOfIncidentDescription}} + + +
+
+
+
+
+
+
+ +
{{'form_is_empty_fill_at_least_one'| translate}}
=== 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-01-28 19:03:29 +0000 +++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/index.html 2015-02-02 13:42:37 +0000 @@ -79,10 +79,12 @@ - - - - + + + + + + === added 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 1970-01-01 00:00:00 +0000 +++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/d2Directives.js 2015-02-02 13:42:37 +0000 @@ -0,0 +1,582 @@ +'use strict'; + +/* Directives */ + +var d2Directives = angular.module('d2Directives', []) + + +.directive('d2OuSearch', function() { + + return { + restrict: 'E', + template: '
\n\ + \n\ + \n\ +
', + 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: '
', + 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(){ + 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 === added 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 1970-01-01 00:00:00 +0000 +++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/d2Services.js 2015-02-02 13:42:37 +0000 @@ -0,0 +1,743 @@ +/* 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 = //g, + match, + inputFields = [], + hasEventDate = false; + + while (match = inputRegex.exec(htmlCode)) { + inputFields.push(match[0]); + } + + for(var i=0; i'; + } + 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 = ''; + } + if(programStageDataElements[fieldId].dataElement.type === "string"){ + if(programStageDataElements[fieldId].dataElement.optionSet){ + var optionSetId = programStageDataElements[fieldId].dataElement.optionSet.id; + newInputField = ' '; + } + else{ + newInputField = ' '; + } + } + if(programStageDataElements[fieldId].dataElement.type === "bool"){ + newInputField = ' '; + } + if(programStageDataElements[fieldId].dataElement.type === "date"){ + var maxDate = programStageDataElements[fieldId].allowFutureDate ? '' : 0; + newInputField = ' '; + } + if(programStageDataElements[fieldId].dataElement.type === "trueOnly"){ + newInputField = ' '; + } + } + + newInputField = newInputField + ' {{getErrorMessage(' + errorMessageId + ')}} '; + + 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 = //g, match, inputFields = []; + var hasProgramDate = false; + while (match = inputRegex.exec(htmlCode)) { + inputFields.push(match[0]); + } + + for(var i=0; i '; + } + else if(trackedEntityFormAttributes[attId].valueType === "optionSet"){ + var optionSetId = trackedEntityFormAttributes[attId].optionSet.id; + newInputField = ' '; + } + else if(trackedEntityFormAttributes[attId].valueType === "bool"){ + newInputField = ' '; + } + else if(trackedEntityFormAttributes[attId].valueType === "date"){ + newInputField = ' '; + } + else if(trackedEntityFormAttributes[attId].valueType === "trueOnly"){ + newInputField = ' '; + } + else if(trackedEntityFormAttributes[attId].valueType === "email"){ + newInputField = ' '; + } + else { + newInputField = ' '; + } + } + + if(target === 'ENROLLMENT' && attributes.hasOwnProperty('programid')){ + hasProgramDate = true; + programId = attributes['programid']; + if(programId === 'enrollmentDate'){ + fieldName = 'dateOfEnrollment'; + var enMaxDate = trackedEntity.selectEnrollmentDatesInFuture ? '' : 0; + newInputField = ' '; + } + if(programId === 'dateOfIncident'){ + fieldName = 'dateOfEnrollment'; + var inMaxDate = trackedEntity.selectIncidentDatesInFuture ? '' : 0; + newInputField = ' '; + } + } + + newInputField = //'' + + newInputField + + ' {{required}} ' + + ' {{invalidInputLabel}} '; + //''; + + 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\n\ - \n\ - \n\ -
', - 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: '
', - 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, $parse, CustomFormService) { - return{ - restrict: 'E', - link: function(scope, elm, attrs){ - scope.$watch('customForm', function(){ - 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-commons-resources/src/main/webapp/dhis-web-commons/javascripts/angular/plugins/dhis2/filters.js' --- dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/angular/plugins/dhis2/filters.js 2014-12-04 13:04:31 +0000 +++ dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/angular/plugins/dhis2/filters.js 1970-01-01 00:00:00 +0000 @@ -1,97 +0,0 @@ -'use strict'; - -/* Filters */ - -var d2Filters = angular.module('d2Filters', []) - -.filter('gridFilter', function($filter, CalendarService){ - - return function(data, filters, filterTypes){ - - if(!data ){ - return; - } - - if(!filters){ - return data; - } - else{ - - var dateFilter = {}, - textFilter = {}, - numberFilter = {}, - filteredData = data; - - for(var key in filters){ - - if(filterTypes[key] === 'date'){ - if(filters[key].start || filters[key].end){ - dateFilter[key] = filters[key]; - } - } - else if(filterTypes[key] === 'int'){ - if(filters[key].start || filters[key].end){ - numberFilter[key] = filters[key]; - } - } - else{ - textFilter[key] = filters[key]; - } - } - - filteredData = $filter('filter')(filteredData, textFilter); - filteredData = $filter('filter')(filteredData, dateFilter, dateComparator); - filteredData = $filter('filter')(filteredData, numberFilter, numberComparator); - - return filteredData; - } - }; - - function dateComparator(data,filter){ - var calendarSetting = CalendarService.getSetting(); - var start = moment(filter.start, calendarSetting.momentFormat); - var end = moment(filter.end, calendarSetting.momentFormat); - var date = moment(data, calendarSetting.momentFormat); - - if(filter.start && filter.end){ - return ( Date.parse(date) <= Date.parse(end) ) && (Date.parse(date) >= Date.parse(start)); - } - return ( Date.parse(date) <= Date.parse(end) ) || (Date.parse(date) >= Date.parse(start)); - } - - function numberComparator(data,filter){ - var start = filter.start; - var end = filter.end; - - if(filter.start && filter.end){ - return ( data <= end ) && ( data >= start ); - } - return ( data <= end ) || ( data >= start ); - } -}) - -.filter('paginate', function(Paginator) { - return function(input, rowsPerPage) { - if (!input) { - return input; - } - - if (rowsPerPage) { - Paginator.rowsPerPage = rowsPerPage; - } - - Paginator.itemCount = input.length; - - return input.slice(parseInt(Paginator.page * Paginator.rowsPerPage), parseInt((Paginator.page + 1) * Paginator.rowsPerPage + 1) - 1); - }; -}) - -.filter('forLoop', function() { - return function(input, start, end) { - input = new Array(end - start); - for (var i = 0; start < end; start++, i++) { - input[i] = start; - } - return input; - }; -}); \ No newline at end of file === removed file 'dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/angular/plugins/dhis2/services.js' --- dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/angular/plugins/dhis2/services.js 2015-01-26 17:47:09 +0000 +++ dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/angular/plugins/dhis2/services.js 1970-01-01 00:00:00 +0000 @@ -1,560 +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 = //g, - match, - inputFields = []; - - while (match = inputRegex.exec(htmlCode)) { - inputFields.push(match[0]); - } - - for(var i=0; i'; - } - 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 = ''; - } - if(programStageDataElements[fieldId].dataElement.type === "string"){ - if(programStageDataElements[fieldId].dataElement.optionSet){ - var optionSetId = programStageDataElements[fieldId].dataElement.optionSet.id; - newInputField = ' '; - } - else{ - newInputField = ' '; - } - } - if(programStageDataElements[fieldId].dataElement.type === "bool"){ - newInputField = ' '; - } - if(programStageDataElements[fieldId].dataElement.type === "date"){ - var maxDate = programStageDataElements[fieldId].allowFutureDate ? '' : 0; - newInputField = ' '; - } - if(programStageDataElements[fieldId].dataElement.type === "trueOnly"){ - newInputField = ' '; - } - } - - newInputField = newInputField + ' {{getErrorMessage(' + errorMessageId + ')}} '; - - htmlCode = htmlCode.replace(inputField, newInputField); - } - } - return {htmlCode: htmlCode, hasEventDate: hasEventDate}; - } - 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\n\ + \n\ + \n\ +
', + 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: '
', + 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, $parse, CustomFormService) { + return{ + restrict: 'E', + link: function(scope, elm, attrs){ + scope.$watch('customForm', function(){ + 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 === added file 'dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/dhis2/dhis2.angular.filters.js' --- dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/dhis2/dhis2.angular.filters.js 1970-01-01 00:00:00 +0000 +++ dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/dhis2/dhis2.angular.filters.js 2015-02-02 13:42:37 +0000 @@ -0,0 +1,97 @@ +'use strict'; + +/* Filters */ + +var d2Filters = angular.module('d2Filters', []) + +.filter('gridFilter', function($filter, CalendarService){ + + return function(data, filters, filterTypes){ + + if(!data ){ + return; + } + + if(!filters){ + return data; + } + else{ + + var dateFilter = {}, + textFilter = {}, + numberFilter = {}, + filteredData = data; + + for(var key in filters){ + + if(filterTypes[key] === 'date'){ + if(filters[key].start || filters[key].end){ + dateFilter[key] = filters[key]; + } + } + else if(filterTypes[key] === 'int'){ + if(filters[key].start || filters[key].end){ + numberFilter[key] = filters[key]; + } + } + else{ + textFilter[key] = filters[key]; + } + } + + filteredData = $filter('filter')(filteredData, textFilter); + filteredData = $filter('filter')(filteredData, dateFilter, dateComparator); + filteredData = $filter('filter')(filteredData, numberFilter, numberComparator); + + return filteredData; + } + }; + + function dateComparator(data,filter){ + var calendarSetting = CalendarService.getSetting(); + var start = moment(filter.start, calendarSetting.momentFormat); + var end = moment(filter.end, calendarSetting.momentFormat); + var date = moment(data, calendarSetting.momentFormat); + + if(filter.start && filter.end){ + return ( Date.parse(date) <= Date.parse(end) ) && (Date.parse(date) >= Date.parse(start)); + } + return ( Date.parse(date) <= Date.parse(end) ) || (Date.parse(date) >= Date.parse(start)); + } + + function numberComparator(data,filter){ + var start = filter.start; + var end = filter.end; + + if(filter.start && filter.end){ + return ( data <= end ) && ( data >= start ); + } + return ( data <= end ) || ( data >= start ); + } +}) + +.filter('paginate', function(Paginator) { + return function(input, rowsPerPage) { + if (!input) { + return input; + } + + if (rowsPerPage) { + Paginator.rowsPerPage = rowsPerPage; + } + + Paginator.itemCount = input.length; + + return input.slice(parseInt(Paginator.page * Paginator.rowsPerPage), parseInt((Paginator.page + 1) * Paginator.rowsPerPage + 1) - 1); + }; +}) + +.filter('forLoop', function() { + return function(input, start, end) { + input = new Array(end - start); + for (var i = 0; start < end; start++, i++) { + input[i] = start; + } + return input; + }; +}); \ No newline at end of file === added 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 1970-01-01 00:00:00 +0000 +++ dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/dhis2/dhis2.angular.services.js 2015-02-02 13:42:37 +0000 @@ -0,0 +1,560 @@ +/* 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 = //g, + match, + inputFields = []; + + while (match = inputRegex.exec(htmlCode)) { + inputFields.push(match[0]); + } + + for(var i=0; i'; + } + 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 = ''; + } + if(programStageDataElements[fieldId].dataElement.type === "string"){ + if(programStageDataElements[fieldId].dataElement.optionSet){ + var optionSetId = programStageDataElements[fieldId].dataElement.optionSet.id; + newInputField = ' '; + } + else{ + newInputField = ' '; + } + } + if(programStageDataElements[fieldId].dataElement.type === "bool"){ + newInputField = ' '; + } + if(programStageDataElements[fieldId].dataElement.type === "date"){ + var maxDate = programStageDataElements[fieldId].allowFutureDate ? '' : 0; + newInputField = ' '; + } + if(programStageDataElements[fieldId].dataElement.type === "trueOnly"){ + newInputField = ' '; + } + } + + newInputField = newInputField + ' {{getErrorMessage(' + errorMessageId + ')}} '; + + htmlCode = htmlCode.replace(inputField, newInputField); + } + } + return {htmlCode: htmlCode, hasEventDate: hasEventDate}; + } + 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