Skip to content

Commit

Permalink
Merge branch 'master' into 192_dev
Browse files Browse the repository at this point in the history
  • Loading branch information
TMSWhite committed May 13, 2012
2 parents 7b60783 + df114e3 commit 57944a5
Show file tree
Hide file tree
Showing 4 changed files with 144 additions and 91 deletions.
2 changes: 1 addition & 1 deletion admin/database.php
Original file line number Diff line number Diff line change
Expand Up @@ -1057,7 +1057,7 @@ function get_max_question_order($gid)
db_switchIDInsert('questions',true);
$query='INSERT into '.db_table_name('questions').' (qid, sid, gid, question_order, title, question, parent_qid, language, scale_id) values ('.$insertqid[$scale_id][$position].','.$surveyid.','.$gid.','.($position+1).','.db_quoteall($codes[$scale_id][$position]).','.db_quoteall($subquestionvalue).','.$qid.','.db_quoteall($language).','.$scale_id.')';
$connect->execute($query);
db_switchIDInsert('questions',true);
db_switchIDInsert('questions',false);
}
}
$position++;
Expand Down
12 changes: 8 additions & 4 deletions admin/scripts/updateset.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// $Id$

$(document).ready(function(){

if ($(".answertable tbody").children().length == 0)
Expand Down Expand Up @@ -160,8 +158,14 @@ function sort_complete(event, ui){
function add_label(event)
{


next_code=getNextCode($(this).parent().parent().find('.codeval').val());
if ($(this).parent().parent().find('.codeval').size()>0)
{
next_code=getNextCode($(this).parent().parent().find('.codeval').val());
}
else
{
next_code='L001';
}
while ($(this).parent().parent().parent().find('input[value="'+next_code+'"]').length>0)
{
next_code=getNextCode(next_code);
Expand Down
217 changes: 133 additions & 84 deletions classes/expressions/LimeExpressionManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,7 @@ class LimeExpressionManager {
* 'varName' => 'afSrcFilter_sq1' // the full qcode variable name - note, if there are sub-questions, don't use this one.
* 'type' => 'M' // the one-letter question type
* 'fieldname' => '26626X34X702sq1' // the fieldname (used as JavaScript variable name, and also as database column name
* 'rootVarName' => 'afDS' // the root variable name
* 'subqs' => array() of sub-questions, where each contains:
* 'rowdivid' => '26626X34X702sq1' // the javascript id identifying the question row (so array_filter can hide rows)
* 'varName' => 'afSrcFilter_sq1' // the full variable name for the sub-question
Expand Down Expand Up @@ -602,6 +603,11 @@ class LimeExpressionManager {
* @var integer
*/
private $numQuestions=0;
/**
* Linked list of array filters
* @var array
*/
private $qrootVarName2arrayFilter = array();

/**
* A private constructor; prevents direct creation of object
Expand Down Expand Up @@ -959,67 +965,39 @@ public function _CreateSubQLevelRelevanceAndValidationEqns($onlyThisQseq=NULL)
// array_filter
// If want to filter question Q2 on Q1, where each have subquestions SQ1-SQ3, this is equivalent to relevance equations of:
// relevance for Q2_SQ1 is Q1_SQ1!=''
$array_filter = NULL;
if (isset($qattr['array_filter']) && trim($qattr['array_filter']) != '')
{
$array_filter = $qattr['array_filter'];
$sgq = ((isset($this->qcode2sgq[$array_filter])) ? $this->qcode2sgq[$array_filter] : $array_filter);
if ($hasSubqs) {
$subqs = $qinfo['subqs'];
foreach ($subqs as $sq) {
$sq_name = NULL;
switch ($type)
{
case '1': //Array (Flexible Labels) dual scale
case ':': //ARRAY (Multi Flexi) 1 to 10
case ';': //ARRAY (Multi Flexi) Text
case 'A': //ARRAY (5 POINT CHOICE) radio-buttons
case 'B': //ARRAY (10 POINT CHOICE) radio-buttons
case 'C': //ARRAY (YES/UNCERTAIN/NO) radio-buttons
case 'E': //ARRAY (Increase/Same/Decrease) radio-buttons
case 'F': //ARRAY (Flexible) - Row Format
case 'L': //LIST drop-down/radio-button list
case 'M': //Multiple choice checkbox
case 'P': //Multiple choice with comments checkbox + text
case 'K': //MULTIPLE NUMERICAL QUESTION
case 'Q': //MULTIPLE SHORT TEXT
if ($this->sgqaNaming)
{
$sq_name = $sgq . substr($sq['sqsuffix'],1);
}
else
{
$sq_name = $array_filter . $sq['sqsuffix'];
}
break;
default:
break;
}
if (!is_null($sq_name)) {
$subQrels[] = array(
'qtype' => $type,
'type' => 'array_filter',
'rowdivid' => $sq['rowdivid'],
'eqn' => '(' . $sq_name . ' != "")',
'qid' => $questionNum,
'sgqa' => $qinfo['sgqa'],
);
}
}
}
$this->qrootVarName2arrayFilter[$qinfo['rootVarName']]['array_filter'] = $array_filter;
}

// array_filter_exclude
// If want to filter question Q2 on Q1, where each have subquestions SQ1-SQ3, this is equivalent to relevance equations of:
// relevance for Q2_SQ1 is Q1_SQ1==''
$array_filter_exclude = NULL;
if (isset($qattr['array_filter_exclude']) && trim($qattr['array_filter_exclude']) != '')
{
$array_filter_exclude = $qattr['array_filter_exclude'];
$sgq = ((isset($this->qcode2sgq[$array_filter_exclude])) ? $this->qcode2sgq[$array_filter_exclude] : $array_filter_exclude);
$this->qrootVarName2arrayFilter[$qinfo['rootVarName']]['array_filter_exclude'] = $array_filter_exclude;
}

// array_filter and array_filter_exclude get processed together
if (!is_null($array_filter) || !is_null($array_filter_exclude))
{
if ($hasSubqs) {
$cascadedAF = array();
$cascadedAFE = array();

list($cascadedAF, $cascadedAFE) = $this->_recursivelyFindAntecdentArrayFilters($qinfo['rootVarName'],array(),array());

$cascadedAF = array_reverse($cascadedAF);
$cascadedAFE = array_reverse($cascadedAFE);

$subqs = $qinfo['subqs'];
$sq_names = array();
foreach ($subqs as $sq) {
$sq_name = NULL;
$af_names = array();
$afe_names = array();
switch ($type)
{
case '1': //Array (Flexible Labels) dual scale
Expand All @@ -1037,22 +1015,55 @@ public function _CreateSubQLevelRelevanceAndValidationEqns($onlyThisQseq=NULL)
case 'Q': //MULTIPLE SHORT TEXT
if ($this->sgqaNaming)
{
$sq_name = $sgq . substr($sq['sqsuffix'],1);
foreach ($cascadedAF as $_caf)
{
$sgq = ((isset($this->qcode2sgq[$_caf])) ? $this->qcode2sgq[$_caf] : $_caf);
$af_names[] = $sgq . substr($sq['sqsuffix'],1);;
}
foreach ($cascadedAFE as $_cafe)
{
$sgq = ((isset($this->qcode2sgq[$_cafe])) ? $this->qcode2sgq[$_cafe] : $_cafe);
$afe_names[] = $sgq . substr($sq['sqsuffix'],1);;
}
}
else
{
$sq_name = $array_filter_exclude . $sq['sqsuffix'];
foreach ($cascadedAF as $_caf)
{
$af_names[] = $_caf . $sq['sqsuffix'];
}
foreach ($cascadedAFE as $_cafe)
{
$afe_names[] = $_cafe . $sq['sqsuffix'];
}
}
break;
default:
break;
}
if (!is_null($sq_name)) {
$af_names = array_unique($af_names);
$afe_names= array_unique($afe_names);

if (count($af_names) > 0 || count($afe_names) > 0) {
$afs_eqn = '';
if (count($af_names) > 0)
{
$afs_eqn .= implode(' != "" && ', $af_names) . ' != ""';
}
if (count($afe_names) > 0)
{
if ($afs_eqn != '')
{
$afs_eqn .= ' && ';
}
$afs_eqn .= implode(' == "" && ', array_unique($afe_names)) . ' == ""';
}

$subQrels[] = array(
'qtype' => $type,
'type' => 'array_filter_exclude',
'type' => 'array_filter',
'rowdivid' => $sq['rowdivid'],
'eqn' => '(' . $sq_name . ' == "")',
'eqn' => '(' . $afs_eqn . ')',
'qid' => $questionNum,
'sgqa' => $qinfo['sgqa'],
);
Expand Down Expand Up @@ -2319,6 +2330,50 @@ public function _CreateSubQLevelRelevanceAndValidationEqns($onlyThisQseq=NULL)
// $this->runtimeTimings[] = array(__METHOD__,(microtime(true) - $now));
}

/**
* Recursively find all questions that logically preceded the current array_filter or array_filter_exclude request
* Note, must support:
* (a) semicolon-separated list of $qroot codes for either array_filter or array_filter_exclude
* (b) mixed history of array_filter and array_filter_exclude values
* @param type $qroot - the question root variable name
* @param type $aflist - the list of array_filter $qroot codes
* @param type $afelist - the list of array_filter_exclude $qroot codes
* @return type
*/
private function _recursivelyFindAntecdentArrayFilters($qroot, $aflist, $afelist)
{
if (isset($this->qrootVarName2arrayFilter[$qroot]))
{
if (isset($this->qrootVarName2arrayFilter[$qroot]['array_filter']))
{
$_afs = explode(';',$this->qrootVarName2arrayFilter[$qroot]['array_filter']);
foreach ($_afs as $_af)
{
if (in_array($_af,$aflist))
{
continue;
}
$aflist[] = $_af;
list($aflist, $afelist) = $this->_recursivelyFindAntecdentArrayFilters($_af, $aflist, $afelist);
}
}
if (isset($this->qrootVarName2arrayFilter[$qroot]['array_filter_exclude']))
{
$_afes = explode(';',$this->qrootVarName2arrayFilter[$qroot]['array_filter_exclude']);
foreach ($_afes as $_afe)
{
if (in_array($_afe,$afelist))
{
continue;
}
$afelist[] = $_afe;
list($aflist, $afelist) = $this->_recursivelyFindAntecdentArrayFilters($_afe, $aflist, $afelist);
}
}
}
return array($aflist, $afelist);
}

/**
* Create the arrays needed by ExpressionManager to process LimeSurvey strings.
* The long part of this function should only be called once per page display (e.g. only if $fieldMap changes)
Expand Down Expand Up @@ -2770,6 +2825,7 @@ private function setVariableAndTokenMappingsForExpressionManager($surveyid,$forc
'type' => $type,
'fieldname' => $sgqa,
'preg' => $preg,
'rootVarName' => $fielddata['title'],
);
}
if (!isset($q2subqInfo[$questionNum]['subqs'])) {
Expand Down Expand Up @@ -3433,6 +3489,7 @@ static function StartSurvey($surveyid,$surveyMode='group',$options=NULL,$forceRe
$LEM->currentQuestionSeq=-1; // for question-by-question mode
$LEM->indexGseq=array();
$LEM->indexQseq=array();
$LEM->qrootVarName2arrayFilter=array();

if (isset($_SESSION['startingValues']) && is_array($_SESSION['startingValues']) && count($_SESSION['startingValues']) > 0)
{
Expand Down Expand Up @@ -5554,40 +5611,32 @@ static function GetRelevanceAndTailoringJavaScript()
foreach ($subqParts as $sq)
{
$rowdividList[$sq['rowdivid']] = $sq['result'];
if ($sq['result'] == false && !($LEM->surveyMode == 'survey'))
{
// then cascading array filter and can never be active
$relParts[] = " $('#relevance" . $sq['rowdivid'] . "').val('');\n";
}
else

$relParts[] = " if ( " . $sq['relevancejs'] . " ) {\n";
$relParts[] = " $('#javatbd" . $sq['rowdivid'] . "').show();\n";
$relParts[] = " if ($('#relevance" . $sq['rowdivid'] . "').val()!='1') { relChange" . $arg['qid'] . "=true; }\n";
$relParts[] = " $('#relevance" . $sq['rowdivid'] . "').val('1');\n";
$relParts[] = " }\n else {\n";
$relParts[] = " $('#javatbd" . $sq['rowdivid'] . "').hide();\n";
$relParts[] = " if ($('#relevance" . $sq['rowdivid'] . "').val()=='1') { relChange" . $arg['qid'] . "=true; }\n";
$relParts[] = " $('#relevance" . $sq['rowdivid'] . "').val('');\n";
switch ($sq['qtype'])
{
// $relParts[] = " // Apply " . $sq['type'] . ": " . $sq['eqn'] ."\n";
$relParts[] = " if ( " . $sq['relevancejs'] . " ) {\n";
$relParts[] = " $('#javatbd" . $sq['rowdivid'] . "').show();\n";
$relParts[] = " if ($('#relevance" . $sq['rowdivid'] . "').val()!='1') { relChange" . $arg['qid'] . "=true; }\n";
$relParts[] = " $('#relevance" . $sq['rowdivid'] . "').val('1');\n";
$relParts[] = " }\n else {\n";
$relParts[] = " $('#javatbd" . $sq['rowdivid'] . "').hide();\n";
$relParts[] = " if ($('#relevance" . $sq['rowdivid'] . "').val()=='1') { relChange" . $arg['qid'] . "=true; }\n";
$relParts[] = " $('#relevance" . $sq['rowdivid'] . "').val('');\n";
switch ($sq['qtype'])
{
case 'L': //LIST drop-down/radio-button list
$listItem = substr($sq['rowdivid'],strlen($sq['sgqa'])); // gets the part of the rowdiv id past the end of the sgqa code.
$relParts[] = " if (($('#java" . $sq['sgqa'] ."').val() == '" . $listItem . "')";
if ($listItem == 'other') {
$relParts[] = " || ($('#java" . $sq['sgqa'] ."').val() == '-oth-')";
}
$relParts[] = "){\n";
$relParts[] = " $('#java" . $sq['sgqa'] . "').val('');\n";
$relParts[] = " $('#answer" . $sq['sgqa'] . "NANS').attr('checked',true);\n";
$relParts[] = " }\n";
break;
default:
break;
}
$relParts[] = " }\n";
case 'L': //LIST drop-down/radio-button list
$listItem = substr($sq['rowdivid'],strlen($sq['sgqa'])); // gets the part of the rowdiv id past the end of the sgqa code.
$relParts[] = " if (($('#java" . $sq['sgqa'] ."').val() == '" . $listItem . "')";
if ($listItem == 'other') {
$relParts[] = " || ($('#java" . $sq['sgqa'] ."').val() == '-oth-')";
}
$relParts[] = "){\n";
$relParts[] = " $('#java" . $sq['sgqa'] . "').val('');\n";
$relParts[] = " $('#answer" . $sq['sgqa'] . "NANS').attr('checked',true);\n";
$relParts[] = " }\n";
break;
default:
break;
}
$relParts[] = " }\n";

$sqvars = explode('|',$sq['relevanceVars']);
if (is_array($sqvars))
Expand Down
4 changes: 2 additions & 2 deletions common_functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -3222,15 +3222,15 @@ function questionAttributes($returnByName=false)
'category'=>$clang->gT('Logic'),
'sortorder'=>100,
'inputtype'=>'text',
"help"=>$clang->gT("Enter the code of a Multiple choice question to only show the matching answer options in this question."),
"help"=>$clang->gT("Enter the code(s) of a Multiple choice question(s) (separated by semicolons) to only show the matching answer options in this question."),
"caption"=>$clang->gT('Array filter'));

$qattributes["array_filter_exclude"]=array(
"types"=>"1ABCEF:;MPLKQ",
'category'=>$clang->gT('Logic'),
'sortorder'=>100,
'inputtype'=>'text',
"help"=>$clang->gT("Enter the code of a Multiple choice question to exclude the matching answer options in this question."),
"help"=>$clang->gT("Enter the code(s) of a Multiple choice question(s) (separated by semicolons) to exclude the matching answer options in this question."),
"caption"=>$clang->gT('Array filter exclusion'));

$qattributes["assessment_value"]=array(
Expand Down

0 comments on commit 57944a5

Please sign in to comment.