1050 lines
29 KiB
Perl
1050 lines
29 KiB
Perl
package WebGUI::Asset::Wobject::Survey::SurveyJSON;
|
|
|
|
=head1 LEGAL
|
|
|
|
-------------------------------------------------------------------
|
|
WebGUI is Copyright 2001-2009 Plain Black Corporation.
|
|
-------------------------------------------------------------------
|
|
Please read the legal notices (docs/legal.txt) and the license
|
|
(docs/license.txt) that came with this distribution before using
|
|
this software.
|
|
-------------------------------------------------------------------
|
|
http://www.plainblack.com info@plainblack.com
|
|
-------------------------------------------------------------------
|
|
|
|
=cut
|
|
|
|
=head1 NAME
|
|
|
|
Package WebGUI::Asset::Wobject::Survey::SurveyJSON
|
|
|
|
=head1 DESCRIPTION
|
|
|
|
Helper class for WebGUI::Asset::Wobject::Survey. It handles
|
|
serializing and deserializing JSON data, and manages the data for
|
|
the Survey. This package is not intended to be used by any other
|
|
Asset in WebGUI.
|
|
|
|
=cut
|
|
|
|
use strict;
|
|
use JSON;
|
|
|
|
#use Clone qw/clone/;
|
|
use Storable qw/dclone/;
|
|
|
|
=head2 new ( $json, $log )
|
|
|
|
Object constructor.
|
|
|
|
=head3 $json
|
|
|
|
Pass in some JSON to be serialized into a data structure. Useful JSON would
|
|
be a hash with "survey" and "sections" keys with appropriate values.
|
|
|
|
=head3 $log
|
|
|
|
The session logger, from $session->log. The class needs nothing else from the
|
|
session object.
|
|
|
|
=cut
|
|
|
|
sub new {
|
|
my $class = shift;
|
|
my $json = shift;
|
|
my $log = shift;
|
|
my $self = {};
|
|
$self->{log} = $log;
|
|
my $temp = from_json($json) if defined $json;
|
|
$self->{sections} = defined $temp->{sections} ? $temp->{sections} : [];
|
|
$self->{survey} = defined $temp->{survey} ? $temp->{survey} : {};
|
|
bless( $self, $class );
|
|
|
|
if ( @{ $self->sections } == 0 ) {
|
|
$self->newObject( [] );
|
|
}
|
|
return $self;
|
|
} ## end sub new
|
|
|
|
=head2 freeze
|
|
|
|
Serializes the survey and sections data into JSON and returns the JSON.
|
|
|
|
=cut
|
|
|
|
sub freeze {
|
|
my $self = shift;
|
|
my %temp;
|
|
$temp{sections} = $self->{sections};
|
|
$temp{survey} = $self->{survey};
|
|
return to_json( \%temp );
|
|
}
|
|
|
|
=head2 newObject ( $address )
|
|
|
|
Add new, empty elements to the survey data structure. It returns $address,
|
|
modified to show what was added.
|
|
|
|
=head3 $address
|
|
|
|
An array ref. The number of elements array set what is added, and
|
|
where.
|
|
|
|
This method modifies $address. It also returns $address.
|
|
|
|
=over 4
|
|
|
|
=item empty
|
|
|
|
If the array ref is empty, a new section is added.
|
|
|
|
=item 1 element
|
|
|
|
If there's just 1 element, then that element is used as an index into
|
|
the array of sections, and a new question is added to that section.
|
|
|
|
=item 2 elements
|
|
|
|
If there are 2 elements, then the first element is an index into
|
|
section array, and the second element is an index into the questions
|
|
in that section. A new answer is added to the specified question in
|
|
the specified section.
|
|
|
|
=back
|
|
|
|
=cut
|
|
|
|
sub newObject {
|
|
my $self = shift;
|
|
my $address = shift;
|
|
if ( @$address == 0 ) {
|
|
push( @{ $self->sections }, $self->newSection() );
|
|
$address->[0] = $#{ $self->sections };
|
|
}
|
|
elsif ( @$address == 1 ) {
|
|
push( @{ $self->questions($address) }, $self->newQuestion($address) );
|
|
$$address[1] = $#{ $self->questions($address) };
|
|
}
|
|
elsif ( @$address == 2 ) {
|
|
push( @{ $self->answers($address) }, $self->newAnswer($address) );
|
|
$$address[2] = $#{ $self->answers($address) };
|
|
}
|
|
return $address;
|
|
} ## end sub newObject
|
|
|
|
#address is the array of objects currently selected in the edit screen
|
|
#data is the array of hash items for displaying
|
|
|
|
=head2 getDragDropList ( $address )
|
|
|
|
Get a subset of the entire data structure. It will be a list of all sections, along with
|
|
one question from a section with all its answers.
|
|
|
|
Returns an array reference. Each element of the array will have a subset of section information as
|
|
a hashref. This will contain two keys:
|
|
|
|
{
|
|
type => 'section',
|
|
text => the section's title
|
|
},
|
|
|
|
The questions for the referenced section will be included, like this:
|
|
|
|
{
|
|
type => 'question',
|
|
text => the question's text
|
|
},
|
|
|
|
All answers for the referenced question will also be in the array reference:
|
|
|
|
{
|
|
type => 'answer',
|
|
text => the answer's text
|
|
},
|
|
|
|
The sections, question and answer will be in depth-first order:
|
|
|
|
section, section, section, question, answer, answer, answer, section, section
|
|
|
|
=head3 $address
|
|
|
|
An array ref. Sets which question from a section will be listed, along with all
|
|
its answers. $address should ALWAYS have two elements.
|
|
|
|
=cut
|
|
|
|
sub getDragDropList {
|
|
my $self = shift;
|
|
my $address = shift;
|
|
my @data;
|
|
for ( my $i = 0; $i <= $#{ $self->sections }; $i++ ) {
|
|
push( @data, { text => $self->section( [$i] )->{title}, type => 'section' } );
|
|
if ( $address->[0] == $i ) {
|
|
|
|
for ( my $x = 0; $x <= $#{ $self->questions($address) }; $x++ ) {
|
|
push(
|
|
@data,
|
|
{ text => $self->question( [ $i, $x ] )->{text},
|
|
type => 'question'
|
|
}
|
|
);
|
|
if ( $address->[1] == $x ) {
|
|
for ( my $y = 0; $y <= $#{ $self->answers($address) }; $y++ ) {
|
|
push(
|
|
@data,
|
|
{ text => $self->answer( [ $i, $x, $y ] )->{text},
|
|
type => 'answer'
|
|
}
|
|
);
|
|
}
|
|
}
|
|
} ## end for ( my $x = 0; $x <= ...
|
|
} ## end if ( $address->[0] == ...
|
|
} ## end for ( my $i = 0; $i <= ...
|
|
return \@data;
|
|
} ## end sub getDragDropList
|
|
|
|
=head2 getObject ( $address )
|
|
|
|
Retrieve objects from the sections data structure by address.
|
|
|
|
=head3 $address
|
|
|
|
An array ref. The number of elements array set what is fetched.
|
|
|
|
=over 4
|
|
|
|
=item empty
|
|
|
|
If the array ref is empty, nothing is done.
|
|
|
|
=item 1 element
|
|
|
|
If there's just 1 element, returns the section with that index.
|
|
|
|
=item 2 elements
|
|
|
|
If there are 2 elements, then the first element is an index into
|
|
section array, and the second element is an index into the questions
|
|
in that section. Returns that question.
|
|
|
|
=item 3 elements
|
|
|
|
Three elements are enough to reference an answer, inside of a particular
|
|
question in a section. Returns that answer.
|
|
|
|
=back
|
|
|
|
=cut
|
|
|
|
sub getObject {
|
|
my ( $self, $address ) = @_;
|
|
if ( @$address == 1 ) {
|
|
return dclone $self->{sections}->[ $address->[0] ];
|
|
}
|
|
elsif ( @$address == 2 ) {
|
|
return dclone $self->{sections}->[ $address->[0] ]->{questions}->[ $address->[1] ];
|
|
}
|
|
else {
|
|
return dclone $self->{sections}->[ $address->[0] ]->{questions}->[ $address->[1] ]->{answers}
|
|
->[ $address->[2] ];
|
|
}
|
|
}
|
|
|
|
=head2 getSectionEditVars ( $address )
|
|
|
|
A dispatcher for getSectionEditVars, getQuestionEditVars and getAnswerEditVars. Uses $address
|
|
to figure out what has been requested, then invokes that method and returns the results
|
|
from it.
|
|
|
|
=head3 $address
|
|
|
|
An array ref. The number of elements determines whether edit vars are fetched for
|
|
sections, questions, or answers.
|
|
|
|
=cut
|
|
|
|
sub getEditVars {
|
|
my ( $self, $address ) = @_;
|
|
|
|
if ( @$address == 1 ) {
|
|
return $self->getSectionEditVars($address);
|
|
}
|
|
elsif ( @$address == 2 ) {
|
|
return $self->getQuestionEditVars($address);
|
|
}
|
|
elsif ( @$address == 3 ) {
|
|
return $self->getAnswerEditVars($address);
|
|
}
|
|
}
|
|
|
|
=head2 getSectionEditVars ( $address )
|
|
|
|
Get a safe copy of the variables for this section, to use for editing
|
|
purposes. Adds two variables, id, which is the index of this section,
|
|
and displayed_id, which is this question's index in a 1-based array
|
|
(versus the default, perl style, 0-based array).
|
|
|
|
It removes the questions array ref, and changes questionsPerPage from a single element, into
|
|
an array of hashrefs, which list the available questions per page and which one is currently
|
|
selected for this section.
|
|
|
|
=head3 $address
|
|
|
|
An array reference, specifying which question to fetch variables for.
|
|
|
|
=cut
|
|
|
|
sub getSectionEditVars {
|
|
my $self = shift;
|
|
my $address = shift;
|
|
my $object = $self->section($address);
|
|
my %var = %{$object};
|
|
$var{id} = $address->[0];
|
|
$var{displayed_id} = $address->[0] + 1;
|
|
delete $var{questions};
|
|
delete $var{questionsPerPage};
|
|
|
|
for ( 1 .. 20 ) {
|
|
|
|
# if($_ == $self->section($address)->{questionsPerPage}){
|
|
if ( $_ == $object->{questionsPerPage} ) {
|
|
push( @{ $var{questionsPerPage} }, { 'index', $_, 'selected', 1 } );
|
|
}
|
|
else {
|
|
push( @{ $var{questionsPerPage} }, { 'index', $_, 'selected', 0 } );
|
|
}
|
|
}
|
|
return \%var;
|
|
} ## end sub getSectionEditVars
|
|
|
|
=head2 getQuestionEditVars ( $address )
|
|
|
|
Get a safe copy of the variables for this question, to use for editing purposes. Adds
|
|
two variables, id, which is the indeces of the question's position in its parent's
|
|
section array joined by dashes '-', and displayed_id, which is this question's index
|
|
in a 1-based array (versus the default, perl style, 0-based array).
|
|
|
|
It removes the answers array ref, and changes questionType from a single element, into
|
|
an array of hashrefs, which list the available question types and which one is currently
|
|
selected for this question.
|
|
|
|
=head3 $address
|
|
|
|
An array reference, specifying which question to fetch variables for.
|
|
|
|
=cut
|
|
|
|
sub getQuestionEditVars {
|
|
my $self = shift;
|
|
my $address = shift;
|
|
my $object = $self->question($address);
|
|
my %var = %{$object};
|
|
$var{id} = $address->[0] . "-" . $address->[1];
|
|
$var{displayed_id} = $address->[1] + 1;
|
|
delete $var{answers};
|
|
delete $var{questionType};
|
|
my @types = $self->getValidQuestionTypes();
|
|
|
|
for (@types) {
|
|
if ( $_ eq $object->{questionType} ) {
|
|
push( @{ $var{questionType} }, { 'text', $_, 'selected', 1 } );
|
|
}
|
|
else {
|
|
push( @{ $var{questionType} }, { 'text', $_, 'selected', 0 } );
|
|
}
|
|
}
|
|
return \%var;
|
|
} ## end sub getQuestionEditVars
|
|
|
|
=head2 getValidQuestionTypes
|
|
|
|
A convenience method. Returns a list of question types. If you add a question
|
|
type to the Survey, you must handle it here, and also in updateQuestionAnswers
|
|
|
|
=cut
|
|
|
|
sub getValidQuestionTypes {
|
|
return (
|
|
'Agree/Disagree', 'Certainty', 'Concern', 'Confidence',
|
|
'Currency', 'Date', 'Date Range', 'Dual Slider - Range',
|
|
'Education', 'Effectiveness', 'Email', 'File Upload',
|
|
'Gender', 'Hidden', 'Ideology', 'Importance',
|
|
'Likelihood', 'Multi Slider - Allocate', 'Multiple Choice', 'Oppose/Support',
|
|
'Party', 'Phone Number', 'Race', 'Risk',
|
|
'Satisfaction', 'Scale', 'Security', 'Slider',
|
|
'Text', 'Text Date', 'Threat', 'True/False',
|
|
'Yes/No'
|
|
);
|
|
}
|
|
|
|
=head2 getAnswerEditVars ( $address )
|
|
|
|
Get a safe copy of the variables for this answer, to use for editing purposes. Adds
|
|
two variables, id, which is the indeces of the answer's position in its parent's question
|
|
and section arrays joined by dashes '-', and displayed_id, which is this answer's index
|
|
in a 1-based array (versus the default, perl style, 0-based array).
|
|
|
|
=head3 $address
|
|
|
|
An array reference, specifying which answer to fetch variables for.
|
|
|
|
=cut
|
|
|
|
sub getAnswerEditVars {
|
|
my $self = shift;
|
|
my $address = shift;
|
|
my $object = $self->answer($address);
|
|
my %var = %{$object};
|
|
$var{id} = $address->[0] . "-" . $address->[1] . "-" . $address->[2];
|
|
$var{displayed_id} = $address->[2] + 1;
|
|
return \%var;
|
|
}
|
|
|
|
=head2 update ( $address, $object )
|
|
|
|
Update new "objects" into the current data structure, or add new ones. It does not
|
|
return anything significant.
|
|
|
|
=head3 $address
|
|
|
|
An array ref. The number of elements array set what is updated.
|
|
|
|
=over 4
|
|
|
|
=item empty
|
|
|
|
If the array ref is empty, nothing is done.
|
|
|
|
=item 1 element
|
|
|
|
If there's just 1 element, then that element is used as an index into
|
|
the array of sections, and information from $object is used to replace
|
|
the properties of that section. If the select section does not exist, such
|
|
as by using an out of bounds array index, then a new section is appended
|
|
to the list of sections.
|
|
|
|
=item 2 elements
|
|
|
|
If there are 2 elements, then the first element is an index into
|
|
section array, and the second element is an index into the questions
|
|
in that section.
|
|
|
|
=item 3 elements
|
|
|
|
Three elements are enough to reference an answer, for a particular
|
|
question in a section.
|
|
|
|
=back
|
|
|
|
=head3 $object
|
|
|
|
A perl data structure. Note, that it is not checked for type, so it is
|
|
possible to add a "question" object into the list of section objects.
|
|
$object should never be a partial object, but contain all properties.
|
|
|
|
=cut
|
|
|
|
sub update {
|
|
my ( $self, $address, $ref ) = @_;
|
|
my $object;
|
|
my $newQuestion = 0;
|
|
if ( @$address == 1 ) {
|
|
$object = $self->section($address);
|
|
if ( !defined $object ) {
|
|
$object = $self->newSection();
|
|
push( @{ $self->sections }, $object );
|
|
}
|
|
}
|
|
elsif ( @$address == 2 ) {
|
|
$object = $self->question($address);
|
|
if ( !defined $object ) {
|
|
my $newQuestion = 1;
|
|
$object = $self->newQuestion();
|
|
push( @{ $self->questions($address) }, $object );
|
|
}
|
|
}
|
|
elsif ( @$address == 3 ) {
|
|
$object = $self->answer($address);
|
|
if ( !defined $object ) {
|
|
$object = $self->newAnswer();
|
|
push( @{ $self->answers($address) }, $object );
|
|
}
|
|
}
|
|
if ( @$address == 2 and !$newQuestion ) {
|
|
if ( $ref->{questionType} ne $self->question($address)->{questionType} ) {
|
|
$self->updateQuestionAnswers( $address, $ref->{questionType} );
|
|
}
|
|
}
|
|
for my $key ( keys %$ref ) {
|
|
$object->{$key} = $ref->{$key} if ( defined $$ref{$key} );
|
|
}
|
|
} ## end sub update
|
|
|
|
#determine what to add and add it.
|
|
# ref should contain all the information for the new
|
|
|
|
=head2 insertObject ( $object, $address )
|
|
|
|
Used to move existing objects in the current data structure. It does not
|
|
return anything significant.
|
|
|
|
=head3 $object
|
|
|
|
A perl data structure. Note, that it is not checked for homegeneity,
|
|
so it is possible to add a "question" object into the list of section
|
|
objects.
|
|
|
|
=head3 $address
|
|
|
|
An array ref. The number of elements array set what is added, and
|
|
where.
|
|
|
|
=over 4
|
|
|
|
=item empty
|
|
|
|
If the array ref is empty, nothing is done.
|
|
|
|
=item 1 element
|
|
|
|
If there's just 1 element, then that element is used as an index into
|
|
the array of sections, and $object is spliced into place right after
|
|
that index.
|
|
|
|
=item 2 elements
|
|
|
|
If there are 2 elements, then the first element is an index into
|
|
section array, and the second element is an index into the questions
|
|
in that section. $object is added right after that question.
|
|
|
|
=item 3 elements
|
|
|
|
Three elements are enough to reference an answer, inside of a particular
|
|
question in a section. $object is spliced in right after that answer.
|
|
|
|
=back
|
|
|
|
=cut
|
|
|
|
sub insertObject {
|
|
my ( $self, $object, $address ) = @_;
|
|
if ( @$address == 1 ) {
|
|
splice( @{ $self->sections($address) }, $$address[0] + 1, 0, $object );
|
|
}
|
|
elsif ( @$address == 2 ) {
|
|
splice( @{ $self->questions($address) }, $$address[1] + 1, 0, $object );
|
|
}
|
|
elsif ( @$address == 3 ) {
|
|
splice( @{ $self->answers($address) }, $$address[2] + 1, 0, $object );
|
|
}
|
|
|
|
}
|
|
|
|
=head2 copy ( $address )
|
|
|
|
Duplicate the structure pointed to by $address, and add it to the end of the list of
|
|
similar structures. copy returns $address with the last element changed to the highest
|
|
index in that array.
|
|
|
|
=head3 $address
|
|
|
|
An array ref. The number of elements array set what is added, and
|
|
where.
|
|
|
|
This method modifies $address.
|
|
|
|
=over 4
|
|
|
|
=item 1 element
|
|
|
|
If there's just 1 element, then the section with that index is duplicated
|
|
at the end of the array of sections.
|
|
|
|
=item 2 elements
|
|
|
|
If there are 2 elements, the question in the section that is indexed
|
|
will be duplicated and added to the end of the array of questions
|
|
in that section.
|
|
|
|
=item 3 elements, or more
|
|
|
|
Nothing happens. It is not allowed to duplicate answers.
|
|
|
|
=back
|
|
|
|
=cut
|
|
|
|
sub copy {
|
|
my ( $self, $address ) = @_;
|
|
if ( @$address == 1 ) {
|
|
my $newSection = dclone $self->section($address);
|
|
push( @{ $self->sections }, $newSection );
|
|
$address->[0] = $#{ $self->sections };
|
|
return $address;
|
|
}
|
|
elsif ( @$address == 2 ) {
|
|
my $newQuestion = dclone $self->question($address);
|
|
push( @{ $self->questions($address) }, $newQuestion );
|
|
$address->[1] = $#{ $self->questions($address) };
|
|
return $address;
|
|
}
|
|
}
|
|
|
|
=head2 remove ( $address, $movingOverride )
|
|
|
|
Delete the structure pointed to by $address.
|
|
|
|
=head3 $address
|
|
|
|
An array ref. The number of elements array set what is added, and
|
|
where.
|
|
|
|
This method modifies $address if it has 1 or more elements.
|
|
|
|
=over 4
|
|
|
|
=item 1 element
|
|
|
|
If there's just 1 element, then the section with that index is removed. Normally,
|
|
the first section, index 0, cannot be removed. See $movingOverride below.
|
|
|
|
=item 2 elements
|
|
|
|
If there are 2 elements, the question in the section is removed.
|
|
in that section.
|
|
|
|
=item 3 elements
|
|
|
|
Removes the answer in the specified question and section.
|
|
|
|
=back
|
|
|
|
=head3 $movingOverride
|
|
|
|
If $movingOverride is defined (meaning including 0 and ''), then the first section
|
|
is allowed to be removed.
|
|
|
|
=cut
|
|
|
|
sub remove {
|
|
my ( $self, $address, $movingOverride ) = @_;
|
|
if ( @$address == 1 ) {
|
|
splice( @{ $self->{sections} }, $$address[0], 1 )
|
|
if ( $$address[0] != 0 or defined $movingOverride ); #can't delete the first section
|
|
}
|
|
elsif ( @$address == 2 ) {
|
|
splice( @{ $self->questions($address) }, $$address[1], 1 );
|
|
}
|
|
elsif ( @$address == 3 ) {
|
|
splice( @{ $self->answers($address) }, $$address[2], 1 );
|
|
}
|
|
}
|
|
|
|
=head2 newSection
|
|
|
|
Returns a reference to a new, empty section.
|
|
|
|
=cut
|
|
|
|
sub newSection {
|
|
return {
|
|
text => '',
|
|
title => 'NEW SECTION', ##i18n
|
|
variable => '',
|
|
questionsPerPage => 5,
|
|
questionsOnSectionPage => 1,
|
|
randomizeQuestions => 0,
|
|
everyPageTitle => 1,
|
|
everyPageText => 1,
|
|
terminal => 0,
|
|
terminalUrl => '',
|
|
goto => '',
|
|
timeLimit => 0,
|
|
type => 'section',
|
|
questions => [],
|
|
};
|
|
}
|
|
|
|
=head2 newQuestion
|
|
|
|
Returns a reference to a new, empty question.
|
|
|
|
=cut
|
|
|
|
sub newQuestion {
|
|
return {
|
|
text => '',
|
|
variable => '',
|
|
allowComment => 0,
|
|
commentCols => 10,
|
|
commentRows => 5,
|
|
randomizeAnswers => 0,
|
|
questionType => 'Multiple Choice',
|
|
randomWords => '',
|
|
verticalDisplay => 0,
|
|
required => 0,
|
|
maxAnswers => 1,
|
|
value => 1,
|
|
textInButton => 0,
|
|
# terminal => 0,
|
|
# terminalUrl => '',
|
|
type => 'question',
|
|
answers => [],
|
|
};
|
|
}
|
|
|
|
=head2 newAnswer
|
|
|
|
Returns a reference to a new, empty answer.
|
|
|
|
=cut
|
|
|
|
sub newAnswer {
|
|
return {
|
|
text => '',
|
|
verbatim => 0,
|
|
textCols => 10,
|
|
textRows => 5,
|
|
goto => '',
|
|
recordedAnswer => '',
|
|
isCorrect => 1,
|
|
min => 1,
|
|
max => 10,
|
|
step => 1,
|
|
value => 1,
|
|
terminal => 0,
|
|
terminalUrl => '',
|
|
type => 'answer'
|
|
};
|
|
}
|
|
|
|
=head2 updateQuestionAnswers ($address, $type);
|
|
|
|
Add answers to a question, based on the requested type.
|
|
|
|
=head3 $address
|
|
|
|
Which question to add answers to.
|
|
|
|
=head3 $type
|
|
|
|
The question type to use to determine how many and what kind of answers
|
|
to add to the question.
|
|
|
|
=cut
|
|
|
|
sub updateQuestionAnswers {
|
|
my $self = shift;
|
|
my $address = shift;
|
|
my $type = shift;
|
|
|
|
my @addy = @{$address};
|
|
my $question = $self->question($address);
|
|
$question->{answers} = [];
|
|
|
|
if ( $type eq 'Date Range'
|
|
or $type eq 'Multi Slider - Allocate'
|
|
or $type eq 'Dual Slider - Range' )
|
|
{
|
|
push( @{ $question->{answers} }, $self->newAnswer() );
|
|
push( @{ $question->{answers} }, $self->newAnswer() );
|
|
}
|
|
elsif ( $type eq 'Currency' ) {
|
|
push( @{ $question->{answers} }, $self->newAnswer() );
|
|
$addy[2] = 0;
|
|
$self->update( \@addy, { 'text', 'Currency Amount:' } );
|
|
}
|
|
elsif ( $type eq 'Text Date' ) {
|
|
push( @{ $question->{answers} }, $self->newAnswer() );
|
|
$addy[2] = 0;
|
|
$self->update( \@addy, { 'text', 'Date:' } );
|
|
}
|
|
elsif ( $type eq 'Phone Number' ) {
|
|
push( @{ $question->{answers} }, $self->newAnswer() );
|
|
$addy[2] = 0;
|
|
$self->update( \@addy, { 'text', 'Phone Number:' } );
|
|
}
|
|
elsif ( $type eq 'Email' ) {
|
|
push( @{ $question->{answers} }, $self->newAnswer() );
|
|
$addy[2] = 0;
|
|
$self->update( \@addy, { 'text', 'Email:' } );
|
|
}
|
|
elsif ( $type eq 'Education' ) {
|
|
my @ans = (
|
|
'Elementary or some high school',
|
|
'High school/GED',
|
|
'Some college/vocational school',
|
|
'College graduate',
|
|
'Some graduate work',
|
|
'Master\'s degree',
|
|
'Doctorate (of any type)',
|
|
'Other degree (verbatim)'
|
|
);
|
|
$self->addAnswersToQuestion( \@addy, \@ans, { 7, 1 } );
|
|
}
|
|
elsif ( $type eq 'Party' ) {
|
|
my @ans
|
|
= ( 'Democratic party', 'Republican party (or GOP)', 'Independant party', 'Other party (verbatim)' );
|
|
$self->addAnswersToQuestion( \@addy, \@ans, { 3, 1 } );
|
|
}
|
|
elsif ( $type eq 'Race' ) {
|
|
my @ans = ( 'American Indian', 'Asian', 'Black', 'Hispanic', 'White non-Hispanic',
|
|
'Something else (verbatim)' );
|
|
$self->addAnswersToQuestion( \@addy, \@ans, { 5, 1 } );
|
|
}
|
|
elsif ( $type eq 'Ideology' ) {
|
|
my @ans = (
|
|
'Strongly liberal',
|
|
'Liberal',
|
|
'Somewhat liberal',
|
|
'Middle of the road',
|
|
'Slightly conservative',
|
|
'Conservative',
|
|
'Strongly conservative'
|
|
);
|
|
$self->addAnswersToQuestion( \@addy, \@ans, {} );
|
|
}
|
|
elsif ( $type eq 'Security' ) {
|
|
my @ans = ( 'Not at all secure', '', '', '', '', '', '', '', '', '', 'Extremely secure' );
|
|
$self->addAnswersToQuestion( \@addy, \@ans, {} );
|
|
}
|
|
elsif ( $type eq 'Threat' ) {
|
|
my @ans = ( 'No threat', '', '', '', '', '', '', '', '', '', 'Extreme threat' );
|
|
$self->addAnswersToQuestion( \@addy, \@ans, {} );
|
|
}
|
|
elsif ( $type eq 'Risk' ) {
|
|
my @ans = ( 'No risk', '', '', '', '', '', '', '', '', '', 'Extreme risk' );
|
|
$self->addAnswersToQuestion( \@addy, \@ans, {} );
|
|
}
|
|
elsif ( $type eq 'Concern' ) {
|
|
my @ans = ( 'Not at all concerned', '', '', '', '', '', '', '', '', '', 'Extremely concerned' );
|
|
$self->addAnswersToQuestion( \@addy, \@ans, {} );
|
|
}
|
|
elsif ( $type eq 'Effectiveness' ) {
|
|
my @ans = ( 'Not at all effective', '', '', '', '', '', '', '', '', '', 'Extremely effective' );
|
|
$self->addAnswersToQuestion( \@addy, \@ans, {} );
|
|
}
|
|
elsif ( $type eq 'Confidence' ) {
|
|
my @ans = ( 'Not at all confident', '', '', '', '', '', '', '', '', '', 'Extremely confident' );
|
|
$self->addAnswersToQuestion( \@addy, \@ans, {} );
|
|
}
|
|
elsif ( $type eq 'Satisfaction' ) {
|
|
my @ans = ( 'Not at all satisfied', '', '', '', '', '', '', '', '', '', 'Extremely satisfied' );
|
|
$self->addAnswersToQuestion( \@addy, \@ans, {} );
|
|
}
|
|
elsif ( $type eq 'Certainty' ) {
|
|
my @ans = ( 'Not at all certain', '', '', '', '', '', '', '', '', '', 'Extremely certain' );
|
|
$self->addAnswersToQuestion( \@addy, \@ans, {} );
|
|
}
|
|
elsif ( $type eq 'Likelihood' ) {
|
|
my @ans = ( 'Not at all likely', '', '', '', '', '', '', '', '', '', 'Extremely likely' );
|
|
$self->addAnswersToQuestion( \@addy, \@ans, {} );
|
|
}
|
|
elsif ( $type eq 'Importance' ) {
|
|
my @ans = ( 'Not at all important', '', '', '', '', '', '', '', '', '', 'Extremely important' );
|
|
$self->addAnswersToQuestion( \@addy, \@ans, {} );
|
|
}
|
|
elsif ( $type eq 'Oppose/Support' ) {
|
|
my @ans = ( 'Strongly oppose', '', '', '', '', '', 'Strongly support' );
|
|
$self->addAnswersToQuestion( \@addy, \@ans, {} );
|
|
}
|
|
elsif ( $type eq 'Agree/Disagree' ) {
|
|
my @ans = ( 'Strongly disagree', '', '', '', '', '', 'Strongly agree' );
|
|
$self->addAnswersToQuestion( \@addy, \@ans, {} );
|
|
}
|
|
elsif ( $type eq 'True/False' ) {
|
|
my @ans = ( 'True', 'False' );
|
|
$self->addAnswersToQuestion( \@addy, \@ans, {} );
|
|
}
|
|
elsif ( $type eq 'Yes/No' ) {
|
|
my @ans = ( 'Yes', 'No' );
|
|
$self->addAnswersToQuestion( \@addy, \@ans, {} );
|
|
}
|
|
elsif ( $type eq 'Gender' ) {
|
|
my @ans = ( 'Male', 'Female' );
|
|
$self->addAnswersToQuestion( \@addy, \@ans, {} );
|
|
}
|
|
else {
|
|
push( @{ $question->{answers} }, $self->newAnswer() );
|
|
}
|
|
} ## end sub updateQuestionAnswers
|
|
|
|
=head2 addAnswersToQuestion ($address, $answers, $verbatims)
|
|
|
|
Helper routine for updateQuestionAnswers. Adds an array of answers to a question.
|
|
|
|
=head3 $address
|
|
|
|
The address of the question to add answers to.
|
|
|
|
=head3 $answers
|
|
|
|
An array reference of answers to add. Each element will be assigned to the text field of
|
|
the answer that is created.
|
|
|
|
=head3 $verbatims
|
|
|
|
An hash reference. Each key is an index into the answers array. The value is a placeholder
|
|
for doing existance lookups. For each requested index, the verbatim flag in the answer is
|
|
set to true.
|
|
|
|
=cut
|
|
|
|
sub addAnswersToQuestion {
|
|
my $self = shift;
|
|
my $addy = shift;
|
|
my $ans = shift;
|
|
my $verbs = shift;
|
|
for ( 0 .. $#$ans ) {
|
|
push( @{ $self->question($addy)->{answers} }, $self->newAnswer() );
|
|
$$addy[2] = $_;
|
|
if ( exists $$verbs{$_} and $verbs->{$_} ) {
|
|
$self->update( $addy, { 'text', $$ans[$_], 'recordedAnswer', $_ + 1, 'verbatim', 1 } );
|
|
}
|
|
else {
|
|
$self->update( $addy, { 'text', $$ans[$_], 'recordedAnswer', $_ + 1 } );
|
|
}
|
|
}
|
|
} ## end sub addAnswersToQuestion
|
|
|
|
#------------------------------
|
|
#accessors and helpers
|
|
#------------------------------
|
|
|
|
=head2 sections
|
|
|
|
Returns a reference to all the sections in this object.
|
|
|
|
=cut
|
|
|
|
sub sections {
|
|
my $self = shift;
|
|
return $self->{sections};
|
|
}
|
|
|
|
=head2 section ($address)
|
|
|
|
Returns a reference to one section.
|
|
|
|
=head3 $address
|
|
|
|
An array ref. The first element of the array ref is the index of
|
|
the section whose questions will be returned.
|
|
|
|
=cut
|
|
|
|
sub section {
|
|
my $self = shift;
|
|
my $address = shift;
|
|
return $self->{sections}->[ $$address[0] ];
|
|
}
|
|
|
|
=head2 questions ($address)
|
|
|
|
Returns a reference to all the questions from a particular section.
|
|
|
|
=head3 $address
|
|
|
|
An array ref. The first element of the array ref is the index of
|
|
the section whose questions will be returned.
|
|
|
|
=cut
|
|
|
|
sub questions {
|
|
my $self = shift;
|
|
my $address = shift;
|
|
return $self->{sections}->[ $$address[0] ]->{questions};
|
|
}
|
|
|
|
=head2 question ($address)
|
|
|
|
Return a reference to one question from a particular section.
|
|
|
|
=head3 $address
|
|
|
|
An array ref. The first element of the array ref is the index of
|
|
the section. The second element is the index of the question in
|
|
that section.
|
|
|
|
=cut
|
|
|
|
sub question {
|
|
my $self = shift;
|
|
my $address = shift;
|
|
return $self->{sections}->[ $$address[0] ]->{questions}->[ $$address[1] ];
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 questionCount (){
|
|
|
|
Return the total number of questions in this survey.
|
|
|
|
=cut
|
|
|
|
sub questionCount {
|
|
my $self = shift;
|
|
my $count;
|
|
for ( my $s = 0; $s <= $#{ $self->sections() }; $s++ ) {
|
|
$count = $count + scalar @{$self->questions( [$s] )};
|
|
}
|
|
return $count;
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 answers ($address)
|
|
|
|
Return a reference to all answers from a particular question.
|
|
|
|
=head3 $address
|
|
|
|
An array ref. The first element of the array ref is the index of
|
|
the section. The second element is the index of the question in
|
|
that section. An array ref of anwers from that question will be
|
|
returned.
|
|
|
|
=cut
|
|
|
|
sub answers {
|
|
my $self = shift;
|
|
my $address = shift;
|
|
return $self->{sections}->[ $$address[0] ]->{questions}->[ $$address[1] ]->{answers};
|
|
}
|
|
|
|
=head2 answer ($address)
|
|
|
|
Return a reference to one answer from a particular question and section.
|
|
|
|
=head3 $address
|
|
|
|
An array ref. The first element of the array ref is the index of
|
|
the section. The second element is the index of the question in
|
|
that section. The third element is the index of the answer.
|
|
|
|
=cut
|
|
|
|
sub answer {
|
|
my $self = shift;
|
|
my $address = shift;
|
|
return $self->{sections}->[ $$address[0] ]->{questions}->[ $$address[1] ]->{answers}->[ $$address[2] ];
|
|
}
|
|
|
|
=head2 log ($message)
|
|
|
|
Logs an error message using the session logger.
|
|
|
|
=head3 $message
|
|
|
|
The message to log. It will be logged as type "error".
|
|
|
|
=cut
|
|
|
|
sub log {
|
|
my ( $self, $message ) = @_;
|
|
if ( defined $self->{log} ) {
|
|
$self->{log}->error($message);
|
|
}
|
|
}
|
|
1;
|