← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 20205: Improved robustness for nested d2: function evaluation

 

------------------------------------------------------------
revno: 20205
committer: Markus Bekken <markus.bekken@xxxxxxxxx>
branch nick: dhis2
timestamp: Thu 2015-09-17 11:03:52 +0200
message:
  Improved robustness for nested d2: function evaluation
modified:
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/dataentry/default-form.html
  dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/dhis2/dhis2.angular.services.js


--
lp:dhis2
https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk

Your team DHIS 2 developers is subscribed to branch lp:dhis2.
To unsubscribe from this branch go to https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk/+edit-subscription
=== modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/dataentry/default-form.html'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/dataentry/default-form.html	2015-09-15 17:16:30 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/dataentry/default-form.html	2015-09-17 09:03:52 +0000
@@ -195,14 +195,14 @@
                     </div>
                     <div ng-messages="innerForm.foo.$error" ng-if="interacted(innerForm.foo)" class="required" ng-messages-include="../dhis-web-commons/angular-forms/error-messages.html">                                         
                     </div>
-                        <div class="alert alert-warning alert-dismissible" role="alert" ng-if="warningMessages[prStDe.dataElement.id]">
-                            <button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>
-                            {{warningMessages[prStDe.dataElement.id]}}
-                        </div>
-                        <div class="alert alert-danger alert-dismissible" role="alert" ng-if="errorMessages[prStDe.dataElement.id]">
-                            <button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>
-                            {{errorMessages[prStDe.dataElement.id]}}
-                        </div>
+                    <div class="alert alert-warning alert-dismissible" role="alert" ng-if="warningMessages[prStDe.dataElement.id]">
+                        <button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>
+                        {{warningMessages[prStDe.dataElement.id]}}
+                    </div>
+                    <div class="alert alert-danger alert-dismissible" role="alert" ng-if="errorMessages[prStDe.dataElement.id]">
+                        <button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>
+                        {{errorMessages[prStDe.dataElement.id]}}
+                    </div>
                 </ng-form>                
             </td>
             <td ng-if="allowProvidedElsewhereExists">                

=== modified file 'dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/dhis2/dhis2.angular.services.js'
--- dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/dhis2/dhis2.angular.services.js	2015-09-14 14:10:12 +0000
+++ dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/dhis2/dhis2.angular.services.js	2015-09-17 09:03:52 +0000
@@ -1133,194 +1133,219 @@
                                 {name:"d2:count",parameters:1},
                                 {name:"d2:countifzeropos",parameters:1},
                                 {name:"d2:countifvalue",parameters:2}];
-
-            angular.forEach(dhisFunctions, function(dhisFunction){
-                //Select the function call, with any number of parameters inside single quotations, or number parameters witout quotations
-                var regularExFunctionCall = new RegExp(dhisFunction.name + "\\( *((\d+)|( *'[^']*'))*( *, *((\d+)|'[^']*'))* *\\)",'g');
-                var callsToThisFunction = expression.match(regularExFunctionCall);
-                angular.forEach(callsToThisFunction, function(callToThisFunction){
-                    //Remove the function name and paranthesis:
-                    var justparameters = callToThisFunction.replace(/(^[^\(]+\()|\)$/g,"");
-                    //Then split into single parameters:
-                    var parameters = justparameters.match(/(('[^']+')|([^,]+))/g);
-
-                    //Show error if no parameters is given and the function requires parameters,
-                    //or if the number of parameters is wrong.
-                    if(angular.isDefined(dhisFunction.parameters)){
-                        //But we are only checking parameters where the dhisFunction actually has a defined set of parameters(concatenate, for example, does not have a fixed number);
-                        if((!angular.isDefined(parameters) && dhisFunction.parameters > 0)
-                                || parameters.length !== dhisFunction.parameters){
-                            $log.warn(dhisFunction.name + " was called with the incorrect number of parameters");
-                        }
-                    }
-
-                    //In case the function call is nested, the parameter itself contains an expression, run the expression.
-                    if(angular.isDefined(parameters)) {
-                        for (var i = 0; i < parameters.length; i++) {
-                            parameters[i] = runExpression(parameters[i],dhisFunction.name,"parameter:" + i, flag, variablesHash);
-                        }
-                    }
-
-                    //Special block for d2:weeksBetween(*,*) - add such a block for all other dhis functions.
-                    if(dhisFunction.name === "d2:daysbetween") {
-                        var firstdate = $filter('trimquotes')(parameters[0]);
-                        var seconddate = $filter('trimquotes')(parameters[1]);
-                        firstdate = moment(firstdate);
-                        seconddate = moment(seconddate);
-                        //Replace the end evaluation of the dhis function:
-                        expression = expression.replace(callToThisFunction, seconddate.diff(firstdate,'days'));
-                    } 
-                    else if(dhisFunction.name === "d2:yearsbetween") {
-                        var firstdate = $filter('trimquotes')(parameters[0]);
-                        var seconddate = $filter('trimquotes')(parameters[1]);
-                        firstdate = moment(firstdate);
-                        seconddate = moment(seconddate);
-                        //Replace the end evaluation of the dhis function:
-                        expression = expression.replace(callToThisFunction, seconddate.diff(firstdate,'years'));
-                    } 
-                    else if(dhisFunction.name === "d2:floor") {
-                        var floored = Math.floor(parameters[0]);
-                        //Replace the end evaluation of the dhis function:
-                        expression = expression.replace(callToThisFunction, floored);
-                    } 
-                    else if(dhisFunction.name === "d2:modulus") {
-                        var dividend = Number(parameters[0]);
-                        var divisor = Number(parameters[1]);
-                        var rest = dividend % divisor;
-                        //Replace the end evaluation of the dhis function:
-                        expression = expression.replace(callToThisFunction, rest);
-                    } 
-                    else if(dhisFunction.name === "d2:concatenate") {
-                        var returnString = "'";
-                        for (var i = 0; i < parameters.length; i++) {
-                            returnString += parameters[i];
-                        }
-                        returnString += "'";
-                        expression = expression.replace(callToThisFunction, returnString);
-                    } 
-                    else if(dhisFunction.name === "d2:adddays") {
-                        var date = $filter('trimquotes')(parameters[0]);
-                        var daystoadd = $filter('trimquotes')(parameters[1]);
-                        var newdate = DateUtils.format( moment(date, CalendarService.getSetting().momentFormat).add(daystoadd, 'days') );
-                        var newdatestring = "'" + newdate + "'";
-                        //Replace the end evaluation of the dhis function:
-                        expression = expression.replace(callToThisFunction, newdatestring);
-                    } 
-                    else if(dhisFunction.name === "d2:zing") {
-                        var number = parameters[0];
-                        if( number < 0 ) {
-                            number = 0;
-                        }
-                        
-                        //Replace the end evaluation of the dhis function:
-                        expression = expression.replace(callToThisFunction, number);
-                    } 
-                    else if(dhisFunction.name === "d2:oizp") {
-                        var number = parameters[0];
-                        var output = 1;
-                        if( number < 0 ) {
-                            output = 0;
-                        }
-                        
-                        //Replace the end evaluation of the dhis function:
-                        expression = expression.replace(callToThisFunction, output);
-                    }
-                    else if(dhisFunction.name === "d2:count") {
-                        var variableName = parameters[0];
-                        var variableObject = variablesHash[variableName];
-                        var count = 0;
-                        if(variableObject)
-                        {
-                            if(variableObject.hasValue){
-                                if(variableObject.allValues)
-                                {
-                                    count = variableObject.allValues.length;
-                                } else {
-                                    //If there is a value found for the variable, the count is 1 even if there is no list of alternate values
-                                    //This happens for variables of "DATAELEMENT_CURRENT_STAGE" and "TEI_ATTRIBUTE"
-                                    count = 1;
-                                }
-                            }
-                        }
-                        else
-                        {
-                            $log.warn("could not find variable to count: " + variableName);
-                        }
-                        
-                        //Replace the end evaluation of the dhis function:
-                        expression = expression.replace(callToThisFunction, count);
-                    }
-                    else if(dhisFunction.name === "d2:countifzeropos") {
-                        var variableName = $filter('trimvariablequalifiers') (parameters[0]);
-                        var variableObject = variablesHash[variableName];
-                        
-                        var count = 0;
-                        if(variableObject)
-                        {
-                            if( variableObject.hasValue ) {
-                                if(variableObject.allValues && variableObject.allValues.length > 0)
-                                {
-                                    for(var i = 0; i < variableObject.allValues.length; i++)
-                                    {
-                                        if(variableObject.allValues[i] >= 0) {
-                                            count++;
-                                        }
-                                    }
-                                }
-                                else {
-                                    //The variable has a value, but no list of alternates. This means we only compare the elements real value
-                                    if(variableObject.variableValue >= 0) {
-                                        count = 1;
-                                    }
-                                }
-                            }
-                        }
-                        else
-                        {
-                            $log.warn("could not find variable to countifzeropos: " + variableName);
-                        }
-                        
-                        //Replace the end evaluation of the dhis function:
-                        expression = expression.replace(callToThisFunction, count);
-                    }
-                    else if(dhisFunction.name === "d2:countifvalue") {
-                        var variableName = parameters[0];
-                        var variableObject = variablesHash[variableName];
-                        
-                        var valueToCompare = VariableService.processValue(parameters[1],variableObject.variableType);
-                                
-                        var count = 0;
-                        if(variableObject)
-                        {
-                            if( variableObject.hasValue )
-                            {
-                                if( variableObject.allValues )
-                                {
-                                    for(var i = 0; i < variableObject.allValues.length; i++)
-                                    {
-                                        if(valueToCompare === variableObject.allValues[i]) {
-                                            count++;
-                                        }
-                                    }
-                                } else {
-                                    //The variable has a value, but no list of alternates. This means we compare the standard variablevalue
-                                    if(valueToCompare === variableObject.variableValue) {
-                                        count = 1;
-                                    }
-                                }
-                                
-                            }
-                        }
-                        else
-                        {
-                            $log.warn("could not find variable to countifvalue: " + variableName);
-                        }
-                        
-                        //Replace the end evaluation of the dhis function:
-                        expression = expression.replace(callToThisFunction, count);
-                    }
+            var continueLooping = true;
+            //Safety harness on 10 loops, in case of unanticipated syntax causing unintencontinued looping
+            for(var i = 0; i < 10 && continueLooping; i++ ) { 
+                var successfulExecution = false;
+                angular.forEach(dhisFunctions, function(dhisFunction){
+                    //Select the function call, with any number of parameters inside single quotations, or number parameters witout quotations
+                    var regularExFunctionCall = new RegExp(dhisFunction.name + "\\( *(([\\d/\\*\\+\\-%]+)|( *'[^']*'))*( *, *(([\\d/\\*\\+\\-%]+)|'[^']*'))* *\\)",'g');
+                    var callsToThisFunction = expression.match(regularExFunctionCall);
+                    angular.forEach(callsToThisFunction, function(callToThisFunction){
+                        //Remove the function name and paranthesis:
+                        var justparameters = callToThisFunction.replace(/(^[^\(]+\()|\)$/g,"");
+                        //Then split into single parameters:
+                        var parameters = justparameters.match(/(('[^']+')|([^,]+))/g);
+
+                        //Show error if no parameters is given and the function requires parameters,
+                        //or if the number of parameters is wrong.
+                        if(angular.isDefined(dhisFunction.parameters)){
+                            //But we are only checking parameters where the dhisFunction actually has a defined set of parameters(concatenate, for example, does not have a fixed number);
+                            if((!angular.isDefined(parameters) && dhisFunction.parameters > 0)
+                                    || parameters.length !== dhisFunction.parameters){
+                                $log.warn(dhisFunction.name + " was called with the incorrect number of parameters");
+                            }
+                        }
+
+                        //In case the function call is nested, the parameter itself contains an expression, run the expression.
+                        if(angular.isDefined(parameters)) {
+                            for (var i = 0; i < parameters.length; i++) {
+                                parameters[i] = runExpression(parameters[i],dhisFunction.name,"parameter:" + i, flag, variablesHash);
+                            }
+                        }
+
+                        //Special block for d2:weeksBetween(*,*) - add such a block for all other dhis functions.
+                        if(dhisFunction.name === "d2:daysbetween") {
+                            var firstdate = $filter('trimquotes')(parameters[0]);
+                            var seconddate = $filter('trimquotes')(parameters[1]);
+                            firstdate = moment(firstdate);
+                            seconddate = moment(seconddate);
+                            //Replace the end evaluation of the dhis function:
+                            expression = expression.replace(callToThisFunction, seconddate.diff(firstdate,'days'));
+                            successfulExecution = true;
+                        } 
+                        else if(dhisFunction.name === "d2:yearsbetween") {
+                            var firstdate = $filter('trimquotes')(parameters[0]);
+                            var seconddate = $filter('trimquotes')(parameters[1]);
+                            firstdate = moment(firstdate);
+                            seconddate = moment(seconddate);
+                            //Replace the end evaluation of the dhis function:
+                            expression = expression.replace(callToThisFunction, seconddate.diff(firstdate,'years'));
+                            successfulExecution = true;
+                        } 
+                        else if(dhisFunction.name === "d2:floor") {
+                            var floored = Math.floor(parameters[0]);
+                            //Replace the end evaluation of the dhis function:
+                            expression = expression.replace(callToThisFunction, floored);
+                            successfulExecution = true;
+                        } 
+                        else if(dhisFunction.name === "d2:modulus") {
+                            var dividend = Number(parameters[0]);
+                            var divisor = Number(parameters[1]);
+                            var rest = dividend % divisor;
+                            //Replace the end evaluation of the dhis function:
+                            expression = expression.replace(callToThisFunction, rest);
+                            successfulExecution = true;
+                        } 
+                        else if(dhisFunction.name === "d2:concatenate") {
+                            var returnString = "'";
+                            for (var i = 0; i < parameters.length; i++) {
+                                returnString += parameters[i];
+                            }
+                            returnString += "'";
+                            expression = expression.replace(callToThisFunction, returnString);
+                            successfulExecution = true;
+                        } 
+                        else if(dhisFunction.name === "d2:adddays") {
+                            var date = $filter('trimquotes')(parameters[0]);
+                            var daystoadd = $filter('trimquotes')(parameters[1]);
+                            var newdate = DateUtils.format( moment(date, CalendarService.getSetting().momentFormat).add(daystoadd, 'days') );
+                            var newdatestring = "'" + newdate + "'";
+                            //Replace the end evaluation of the dhis function:
+                            expression = expression.replace(callToThisFunction, newdatestring);
+                            successfulExecution = true;
+                        } 
+                        else if(dhisFunction.name === "d2:zing") {
+                            var number = parameters[0];
+                            if( number < 0 ) {
+                                number = 0;
+                            }
+
+                            //Replace the end evaluation of the dhis function:
+                            expression = expression.replace(callToThisFunction, number);
+                            successfulExecution = true;
+                        } 
+                        else if(dhisFunction.name === "d2:oizp") {
+                            var number = parameters[0];
+                            var output = 1;
+                            if( number < 0 ) {
+                                output = 0;
+                            }
+
+                            //Replace the end evaluation of the dhis function:
+                            expression = expression.replace(callToThisFunction, output);
+                            successfulExecution = true;
+                        }
+                        else if(dhisFunction.name === "d2:count") {
+                            var variableName = parameters[0];
+                            var variableObject = variablesHash[variableName];
+                            var count = 0;
+                            if(variableObject)
+                            {
+                                if(variableObject.hasValue){
+                                    if(variableObject.allValues)
+                                    {
+                                        count = variableObject.allValues.length;
+                                    } else {
+                                        //If there is a value found for the variable, the count is 1 even if there is no list of alternate values
+                                        //This happens for variables of "DATAELEMENT_CURRENT_STAGE" and "TEI_ATTRIBUTE"
+                                        count = 1;
+                                    }
+                                }
+                            }
+                            else
+                            {
+                                $log.warn("could not find variable to count: " + variableName);
+                            }
+
+                            //Replace the end evaluation of the dhis function:
+                            expression = expression.replace(callToThisFunction, count);
+                            successfulExecution = true;
+                        }
+                        else if(dhisFunction.name === "d2:countifzeropos") {
+                            var variableName = $filter('trimvariablequalifiers') (parameters[0]);
+                            var variableObject = variablesHash[variableName];
+
+                            var count = 0;
+                            if(variableObject)
+                            {
+                                if( variableObject.hasValue ) {
+                                    if(variableObject.allValues && variableObject.allValues.length > 0)
+                                    {
+                                        for(var i = 0; i < variableObject.allValues.length; i++)
+                                        {
+                                            if(variableObject.allValues[i] >= 0) {
+                                                count++;
+                                            }
+                                        }
+                                    }
+                                    else {
+                                        //The variable has a value, but no list of alternates. This means we only compare the elements real value
+                                        if(variableObject.variableValue >= 0) {
+                                            count = 1;
+                                        }
+                                    }
+                                }
+                            }
+                            else
+                            {
+                                $log.warn("could not find variable to countifzeropos: " + variableName);
+                            }
+
+                            //Replace the end evaluation of the dhis function:
+                            expression = expression.replace(callToThisFunction, count);
+                            successfulExecution = true;
+                        }
+                        else if(dhisFunction.name === "d2:countifvalue") {
+                            var variableName = parameters[0];
+                            var variableObject = variablesHash[variableName];
+
+                            var valueToCompare = VariableService.processValue(parameters[1],variableObject.variableType);
+
+                            var count = 0;
+                            if(variableObject)
+                            {
+                                if( variableObject.hasValue )
+                                {
+                                    if( variableObject.allValues )
+                                    {
+                                        for(var i = 0; i < variableObject.allValues.length; i++)
+                                        {
+                                            if(valueToCompare === variableObject.allValues[i]) {
+                                                count++;
+                                            }
+                                        }
+                                    } else {
+                                        //The variable has a value, but no list of alternates. This means we compare the standard variablevalue
+                                        if(valueToCompare === variableObject.variableValue) {
+                                            count = 1;
+                                        }
+                                    }
+
+                                }
+                            }
+                            else
+                            {
+                                $log.warn("could not find variable to countifvalue: " + variableName);
+                            }
+
+                            //Replace the end evaluation of the dhis function:
+                            expression = expression.replace(callToThisFunction, count);
+                            successfulExecution = true;
+                        }
+                    });
                 });
-            });
+                //We only want to continue looping until we made a successful replacement,
+                //and there is still occurrences of "d2:" in the code. In cases where d2: occur outside
+                //the expected d2: function calls, one unneccesary iteration will be done and the 
+                //successfulExecution will be false coming back here, ending the loop. The last iteration
+                //should be zero to marginal performancewise.
+                if(successfulExecution && expression.indexOf("d2:") !== -1) {
+                    continueLooping = true;
+                } else {
+                    continueLooping = false;
+                }
+            }
         }
 
         return expression;