diff --git a/docs/upgrades/packages-7.7.7/root_import_survey_default-questions.wgpkg b/docs/upgrades/packages-7.7.7/root_import_survey_default-questions.wgpkg new file mode 100644 index 000000000..7fcac5696 Binary files /dev/null and b/docs/upgrades/packages-7.7.7/root_import_survey_default-questions.wgpkg differ diff --git a/docs/upgrades/packages-7.7.7/survey.css.wgpkg b/docs/upgrades/packages-7.7.7/survey.css.wgpkg new file mode 100644 index 000000000..e7169fa17 Binary files /dev/null and b/docs/upgrades/packages-7.7.7/survey.css.wgpkg differ diff --git a/lib/WebGUI/Asset/Wobject/Survey/ResponseJSON.pm b/lib/WebGUI/Asset/Wobject/Survey/ResponseJSON.pm index 3783b1eaa..082b5f342 100644 --- a/lib/WebGUI/Asset/Wobject/Survey/ResponseJSON.pm +++ b/lib/WebGUI/Asset/Wobject/Survey/ResponseJSON.pm @@ -102,11 +102,11 @@ sub reset { startTime => time(), surveyOrder => undef, tags => {}, - - # And then data overrides - %{$data}, }; + # And then data overrides (via a hash slice) + @{$self->{_response}}{keys %{$data}} = values %{$data}; + # If first section is logical, process it immediately $self->checkForLogicalSection; return $self; @@ -1141,6 +1141,15 @@ sub nextQuestions { last; } + # In rare cases where you change the structure of your survey after + # someone has already started a response, it's possible for this + # to be triggered, in which case the easiest course of action is + # to just skip over the question. + if (!$self->survey->question( $address )) { + $self->session->log->debug("Unable to retrieve question for address $sIndex-$qIndex"); + next; + } + # Make a safe copy of the question my %questionCopy = %{$self->survey->question( $address )}; @@ -1190,7 +1199,10 @@ sub nextQuestions { } } else { for my $aIndex ( aIndexes($address) ) { - my %answerCopy = %{ $self->survey->answer( [ $sIndex, $qIndex, $aIndex ] ) }; + my %answerCopy + = %{ $self->survey->answer( [ $sIndex, $qIndex, $aIndex ] ) + || $self->survey->newAnswer # in case the lookup fails, use a default answer + }; # Do text replacement $answerCopy{text} = $self->getTemplatedText($answerCopy{text}, \%templateValues); diff --git a/lib/WebGUI/Asset/Wobject/Survey/Test.pm b/lib/WebGUI/Asset/Wobject/Survey/Test.pm index 7f376cb0f..3d42e2a3a 100644 --- a/lib/WebGUI/Asset/Wobject/Survey/Test.pm +++ b/lib/WebGUI/Asset/Wobject/Survey/Test.pm @@ -133,9 +133,6 @@ sub run { $self->session->db->write( 'delete from Survey_response where assetId = ? and userId = ?', [ $self->getId, $self->session->user->userId() ] ); - # disable cookies so that test code doesn't die - $survey->responseIdCookies(0); - # Start a response as current user my $responseId = $survey->responseId($self->session->user->userId) or return { tap => "Bail Out! Unable to start survey response" }; @@ -144,7 +141,6 @@ sub run { my $rJSON = $survey->responseJSON or return { tap => "Bail Out! Unable to get responseJSON" }; - my %validTargets = map { $_ => 1 } @{$survey->surveyJSON->getGotoTargets}; my $surveyOrder = $rJSON->surveyOrder; my $surveyOrderIndexByVariableName = $rJSON->surveyOrderIndexByVariableName; @@ -371,28 +367,24 @@ sub _setup { # Setup any fake data the user wants prior to the test if ($setup && ref $setup eq 'HASH') { - my %existingTags = %{$rJSON->tags}; - # Process tags - # N.B. Make sure we add to existing tags instead of overwriting + my %tags; if (ref $setup->{tag} eq 'HASH') { - # already a hash, so store it right away - $rJSON->tags( {%existingTags, %{$setup->{tag}} }); + %tags = %{$setup->{tag}}; } elsif (ref $setup->{tag} eq 'ARRAY') { - # turn array into hash before storing it - my $tags; for my $tag (@{$setup->{tag}}) { if (ref $tag eq 'HASH') { # Individual item is a single key/value hash my ($key, $value) = %$tag; - $tags->{$key} = $value; + $tags{$key} = $value; } else { # Individual item is a string, default to boolean truth flag - $tags->{$tag} = 1; # default to 1 + $tags{$tag} = 1; # default to 1 } } - $rJSON->tags( {%existingTags, %$tags }); } + # N.B. Make sure we add to existing tags instead of overwriting + @{$rJSON->tags}{keys %tags} = values %tags; } } diff --git a/www/extras/wobject/Survey/administersurvey.js b/www/extras/wobject/Survey/administersurvey.js index df1321c1b..512c48d9d 100644 --- a/www/extras/wobject/Survey/administersurvey.js +++ b/www/extras/wobject/Survey/administersurvey.js @@ -186,42 +186,59 @@ if (typeof Survey === "undefined") { anim.setAttribute = setAttr; anim.animate(); } - function numberHandler(event, objs){ var keycode = event.keyCode; - var value = this.value; + var value = parseFloat(this.value, 10); - //if starting a negative number, don't do anything - if(value == '' || value == "-"){return;} - - var step = objs.step ? objs.step : 1; - - if(!value){this.value = objs.min ? objs.min : 0;} - if(value % step > 0){ - this.value = +value + value % step; - } + // Keep a record of the original value entered + var originalValue = value; + + // Get the constraints + var min = parseFloat(objs.min, 10); + var max = parseFloat(objs.max, 10); + var step = parseFloat(objs.step, 10); + + // Response to up/down arrow keys + if (keycode == 38 || keycode == 40) { + // start at zero if we don't have a valid number + if (!YAHOO.lang.isNumber(value)) { + value = 0; + } - if(objs.min != '' && +value < +objs.min){ - this.value = objs.min; + // Default to 1 for increment steps + step = step ? step : 1; + + if (keycode == 38){ // up + value += step; + } + if (keycode == 40){ // down + value -= step; + } + } else { + // Apart from when we respond to up/down requests, if the input + // isn't a valid number it's best if we do nothing - the user + // might be half-way through entering something, and + // besides, validation will take care of it for us later + if (!YAHOO.lang.isNumber(value)) { + return; + } } - - else if(objs.max != '' && +value > objs.max){this.value = objs.max;} - else if(+keycode == 40){//key down - if(objs.min == ''){ - this.value = value - step; - } - else if((value - step) >= +objs.min){ - this.value = value - step; - } - }else if(+keycode == 38){//key up - if(objs.max == ''){ - this.value = value + step; - } - if(value + step <= objs.max){ - this.value = value + step; - } + + // Enforce max/min constraints + if (YAHOO.lang.isNumber(min) && value < min){ + value = min; + } + if (YAHOO.lang.isNumber(max) && value > max){ + value = max; + } + + // Only modify the value if the new numeric value + // is different from the original parsed value + // (so that "0.000" doesn't get turned into "0" etc..) + if (value != originalValue) { + this.value = value; } } @@ -733,7 +750,7 @@ if (typeof Survey === "undefined") { if (toValidate[q.id]) { toValidate[q.id].answers[q.answers[x1].id] = {'min':q.answers[x1].min,'max':q.answers[x1].max,'step':q.answers[x1].step}; } - YAHOO.util.Event.addListener(q.answers[x1].id, "keyup", numberHandler, q.answers[x1]); + YAHOO.util.Event.addListener(q.answers[x1].id, "keydown", numberHandler, q.answers[x1]); } } continue;