diff --git a/application/helpers/SurveyRuntimeHelper.php b/application/helpers/SurveyRuntimeHelper.php
index 88154ab3025..67afbcb3ca0 100644
--- a/application/helpers/SurveyRuntimeHelper.php
+++ b/application/helpers/SurveyRuntimeHelper.php
@@ -874,7 +874,13 @@ function checkconditions(value, name, type, evt_type)
$redata = compact(array_keys(get_defined_vars()));
echo "\n\n\n";
- echo "\n\n
\n";
+ echo "\n\n
\n";
echo templatereplace(file_get_contents("$thistpl/startgroup.pstpl"), array(), $redata);
echo "\n";
diff --git a/application/helpers/expressions/em_manager_helper.php b/application/helpers/expressions/em_manager_helper.php
index 795cd87883d..49a19e84191 100644
--- a/application/helpers/expressions/em_manager_helper.php
+++ b/application/helpers/expressions/em_manager_helper.php
@@ -2496,12 +2496,13 @@ static function QuestionIsRelevant($qid)
* @param $gid
* @return boolean
*/
- static function GroupIsRelevant($gid)
+ static function GroupIsIrrelevantOrHidden($gid)
{
$LEM =& LimeExpressionManager::singleton();
$grel = (isset($_SESSION['relevanceStatus']['G' . $gid]) ? $_SESSION['relevanceStatus']['G' . $gid] : 1); // group-level relevance based upon grelevance equation
- $qgrel = (isset($LEM->gid2relevanceStatus[$gid]) ? isset($LEM->gid2relevanceStatus[$gid]) : 1); // group-level relevance based upon ensuring at least one contained question is relevant
- return ($grel && $qgrel);
+ $gseq = (isset($LEM->groupId2groupSeq[$gid]) ? $LEM->groupId2groupSeq[$gid] : -1);
+ $gshow = (isset($LEM->indexGseq[$gseq]['show']) ? $LEM->indexGseq[$gseq]['show'] : true); // default to true?
+ return !($grel && $gshow);
}
/**
@@ -3781,13 +3782,13 @@ private function _ValidateSurvey()
if ($gStatus['relevant']) {
$srel = true;
}
- if (!$gStatus['hidden']) {
+ if ($gStatus['relevant'] && !$gStatus['hidden']) {
$shidden=false;
}
- if ($gStatus['mandViolation']) {
+ if ($gStatus['relevant'] && !$gStatus['hidden'] && $gStatus['mandViolation']) {
$smandViolation = true;
}
- if (!$gStatus['valid']) {
+ if ($gStatus['relevant'] && !$gStatus['hidden'] && !$gStatus['valid']) {
$svalid=false;
}
if ($gStatus['anyUnanswered']) {
@@ -3866,19 +3867,19 @@ function _ValidateGroup($groupSeq)
$updatedValues = array_merge($updatedValues,$qStatus['updatedValues']);
- if ($qStatus['relevant']==true) {
+ if ($gRelInfo['result']==true && $qStatus['relevant']==true) {
$grel = $gRelInfo['result']; // true; // at least one question relevant
}
if ($qStatus['hidden']==false && $qStatus['relevant'] == true) {
$ghidden=false; // at least one question is visible
}
- if ($qStatus['mandViolation']==true) {
+ if ($qStatus['relevant']==true && $qStatus['hidden']==false && $qStatus['mandViolation']==true) {
$gmandViolation=true; // at least one relevant question fails mandatory test
}
if ($qStatus['anyUnanswered']==true) {
$ganyUnanswered=true;
}
- if ($qStatus['valid']==false) {
+ if ($qStatus['relevant']==true && $qStatus['hidden']==false && $qStatus['valid']==false) {
$gvalid=false; // at least one question fails validity constraints
}
$currentQset[$qStatus['info']['qid']] = $qStatus;
@@ -4008,6 +4009,9 @@ function _ValidateQuestion($questionSeq)
$qhidden = $qInfo['hidden'];
$debug_qmessage='';
+ $gRelInfo = $LEM->gRelInfo[$qInfo['gseq']];
+ $grel = $gRelInfo['result'];
+
///////////////////////////
// IS QUESTION RELEVANT? //
///////////////////////////
@@ -4544,7 +4548,7 @@ function _ValidateQuestion($questionSeq)
// CREATE ARRAY OF VALUES THAT NEED TO BE SILENTLY UPDATED //
/////////////////////////////////////////////////////////////
$updatedValues=array();
- if (!$qrel)
+ if (!$qrel || !$grel)
{
// If not relevant, then always NULL it in the database
$sgqas = explode('|',$LEM->qid2code[$qid]);
@@ -4927,6 +4931,7 @@ static function GetRelevanceAndTailoringJavaScript()
$pageRelevanceInfo=array();
$qidList = array(); // list of questions used in relevance and tailoring
$gidList = array(); // list of groups on this page
+ $gid_qidList = array(); // list of qids using relevance/tailoring within each group
if (is_array($LEM->pageRelevanceInfo))
{
@@ -4942,7 +4947,6 @@ static function GetRelevanceAndTailoringJavaScript()
$valEqns = array();
$relEqns = array();
$relChangeVars = array();
- $relFnCalls = array();
if (is_array($pageRelevanceInfo))
{
@@ -4989,6 +4993,11 @@ static function GetRelevanceAndTailoringJavaScript()
}
$qidList[$arg['qid']] = $arg['qid'];
+ if (!isset($gid_qidList[$arg['gid']]))
+ {
+ $gid_qidList[$arg['gid']] = array();
+ }
+ $gid_qidList[$arg['gid']][$arg['qid']] = '0'; // means the qid is within this gid, but may not have a relevance equation
// Now check whether any sub-question validation needs to be performed
$subqValidations = array();
@@ -5013,6 +5022,7 @@ static function GetRelevanceAndTailoringJavaScript()
$validationEqns = $LEM->qid2validationEqn[$arg['qid']]['eqn'];
}
+ // Process relevance for question $arg['qid'];
$relevance = $arg['relevancejs'];
$relChangeVars[] = " relChange" . $arg['qid'] . "=false;\n"; // detect change in relevance status
@@ -5020,17 +5030,10 @@ static function GetRelevanceAndTailoringJavaScript()
if (($relevance == '' || $relevance == '1') && count($tailorParts) == 0 && count($subqParts) == 0 && count($subqValidations) == 0 && count($validationEqns) == 0)
{
// Only show constitutively true relevances if there is tailoring that should be done.
-// $jsParts[] = "document.getElementById('relevance" . $arg['qid'] . "').value='1'; // always true\n";
$relParts[] = "$('#relevance" . $arg['qid'] . "').val('1'); // always true\n";
continue;
}
$relevance = ($relevance == '') ? '1' : $relevance;
-// $jsResultVar = $LEM->em->GetJsVarFor($arg['jsResultVar']);
-// $relParts[] = "\n// Process Relevance for Question " . $arg['qid'];
-// if ($relevance != 1)
-// {
-// $relParts[] = ": { " . $arg['eqn'] . " }";
-// }
$relParts[] = "\nif (" . $relevance . ")\n{\n";
////////////////////////////////////////////////////////////////////////
// DO ALL ARRAY FILTERING FIRST - MAY AFFECT VALIDATION AND TAILORING //
@@ -5268,7 +5271,7 @@ static function GetRelevanceAndTailoringJavaScript()
$jsResultVar = $LEM->em->GetJsVarFor($arg['jsResultVar']);
$relParts[] = " $('#" . substr($jsResultVar,1,-1) . "').val(escape(jQuery.trim(LEMstrip_tags($('#question" . $arg['qid'] . " .em_equation').find('span').html()))).replace(/%20/g,' '));\n";
}
- $relParts[] = " relChange" . $arg['qid'] . "=true;\n";
+ $relParts[] = " relChange" . $arg['qid'] . "=true;\n"; // any change to this value should trigger a propagation of changess
$relParts[] = " $('#relevance" . $arg['qid'] . "').val('1');\n";
$relParts[] = "}\n";
@@ -5277,7 +5280,7 @@ static function GetRelevanceAndTailoringJavaScript()
$relParts[] = "else {\n";
$relParts[] = " $('#question" . $arg['qid'] . "').hide();\n";
$relParts[] = " $('#display" . $arg['qid'] . "').val('');\n";
- $relParts[] = " if ($('#relevance" . $arg['qid'] . "').val()=='1') { relChange" . $arg['qid'] . "=true; }\n";
+ $relParts[] = " if ($('#relevance" . $arg['qid'] . "').val()=='1') { relChange" . $arg['qid'] . "=true; }\n"; // only propagate changes if changing from relevant to irrelevant
$relParts[] = " $('#relevance" . $arg['qid'] . "').val('0');\n";
$relParts[] = "}\n";
}
@@ -5292,6 +5295,7 @@ static function GetRelevanceAndTailoringJavaScript()
$relJsVarsUsed = array_merge($relJsVarsUsed,$valJsVarsUsed);
$relJsVarsUsed = array_unique($relJsVarsUsed);
$qrelQIDs = array();
+ $qrelGIDs = array(); // so that any group-level change is also propagated
foreach ($relJsVarsUsed as $jsVar)
{
if ($jsVar != '' && isset($LEM->knownVars[substr($jsVar,4)]['qid']))
@@ -5305,12 +5309,16 @@ static function GetRelevanceAndTailoringJavaScript()
continue; // don't make dependent upon itself
}
$qrelQIDs[] = 'relChange' . $_qid;
+ $qrelGIDs[] = 'relChangeG' . $knownVar['gid'];
}
}
+ $qrelGIDs[] = 'relChangeG' . $arg['gid']; // so if current group changes visibility, re-tailor it.
$qrelQIDs = array_unique($qrelQIDs);
+ $qrelGIDs = array_unique($qrelGIDs);
if ($LEM->surveyMode=='question')
{
$qrelQIDs=array(); // in question-by-questin mode, should never test for dependencies on self or other questions.
+ $qrelGIDs=array();
}
$qrelJS = "function LEMrel" . $arg['qid'] . "(sgqa){\n";
@@ -5319,16 +5327,26 @@ static function GetRelevanceAndTailoringJavaScript()
{
$qrelJS .= " if(" . implode(' || ', $qrelQIDs) . "){\n ;\n }\n else";
}
+ if (count($qrelGIDs) > 0)
+ {
+ $qrelJS .= " if(" . implode(' || ', $qrelGIDs) . "){\n ;\n }\n else";
+ }
$qrelJS .= " if (typeof sgqa !== 'undefined' && !LEMregexMatch('/ java' + sgqa + ' /', UsesVars)) {\n return;\n }\n";
$qrelJS .= implode("",$relParts);
$qrelJS .= "}\n";
$relEqns[] = $qrelJS;
- $relFnCalls[] = " LEMrel" . $arg['qid'] . "(sgqa);\n";
+ $gid_qidList[$arg['gid']][$arg['qid']] = '1'; // means has an explicit LEMrel() function
}
}
- // Finally do Group-level Relevance. Might consider surrounding questions with group-level relevance, but might message up Q.NAOK - not sure.
+ foreach(array_keys($gid_qidList) as $_gid)
+ {
+ $relChangeVars[] = " relChangeG" . $_gid . "=false;\n";
+ }
+ $jsParts[] = implode("",$relChangeVars);
+
+ // Process relevance for each group; and if group is relevant, process each contained question in order
foreach ($LEM->gRelInfo as $gr)
{
if (!array_key_exists($gr['gid'],$gidList)) {
@@ -5340,12 +5358,35 @@ static function GetRelevanceAndTailoringJavaScript()
// $jsParts[] = ": { " . $gr['eqn'] . " }";
$jsParts[] = "\nif (" . $gr['relevancejs'] . ") {\n";
$jsParts[] = " $('#group-" . $gr['gid'] . "').show();\n";
+ $jsParts[] = " relChangeG" . $gr['gid'] . "=true;\n";
$jsParts[] = " $('#relevanceG" . $gr['gid'] . "').val(1);\n";
+
+ $qids = $gid_qidList[$gr['gid']];
+ foreach ($qids as $_qid=>$_val)
+ {
+ if ($_val==1)
+ {
+ $jsParts[] = " LEMrel" . $_qid . "(sgqa);\n";
+ }
+ }
+
$jsParts[] = "}\nelse {\n";
$jsParts[] = " $('#group-" . $gr['gid'] . "').hide();\n";
+ $jsParts[] = " if ($('#relevanceG" . $gr['gid'] . "').val()=='1') { relChangeG" . $gr['gid'] . "=true; }\n";
$jsParts[] = " $('#relevanceG" . $gr['gid'] . "').val(0);\n";
$jsParts[] = "}\n";
}
+ else
+ {
+ $qids = $gid_qidList[$gr['gid']];
+ foreach ($qids as $_qid=>$_val)
+ {
+ if ($_val == 1)
+ {
+ $jsParts[] = " LEMrel" . $_qid . "(sgqa);\n";
+ }
+ }
+ }
// now make sure any needed variables are accessible
$vars = explode('|',$gr['relevanceVars']);
if (is_array($vars))
@@ -5354,9 +5395,6 @@ static function GetRelevanceAndTailoringJavaScript()
}
}
- $jsParts[] = implode("",$relChangeVars);
- $jsParts[] = implode("",$relFnCalls);
-
$jsParts[] = "\n}\n";
$jsParts[] = implode("\n",$relEqns);
@@ -5456,7 +5494,6 @@ static function GetRelevanceAndTailoringJavaScript()
$jsParts[] = "\n";
}
}
- sort($qidList,SORT_NUMERIC);
foreach ($qidList as $qid)
{
if (isset($_SESSION['relevanceStatus'])) {
@@ -6107,8 +6144,11 @@ static function ProcessCurrentResponses()
{
$relevant=false;
$qid = $qinfo['info']['qid'];
+ $gid = $qinfo['info']['gid'];
$relevant = (isset($_POST['relevance' . $qid]) ? ($_POST['relevance' . $qid] == 1) : false);
+ $grelevant = (isset($_POST['relevanceG' . $gid]) ? ($_POST['relevanceG' . $gid] == 1) : false);
$_SESSION['relevanceStatus'][$qid] = $relevant;
+ $_SESSION['relevanceStatus']['G' . $gid] = $grelevant;
if (isset($qinfo['info']['rowdivid']) && $qinfo['info']['rowdivid']!='')
{
$rowdivid=$qinfo['info']['rowdivid'];
@@ -6120,7 +6160,7 @@ static function ProcessCurrentResponses()
}
foreach (explode('|',$qinfo['sgqa']) as $sq)
{
- if ($relevant)
+ if ($relevant && $grelevant)
{
$value = (isset($_POST[$sq]) ? $_POST[$sq] : '');
$type = $qinfo['info']['type'];