Merge branch 'master' into survey

This commit is contained in:
Patrick Donelan 2008-12-09 00:28:25 +00:00
commit 7a8398c8d5
22 changed files with 544 additions and 149 deletions

View file

@ -3,6 +3,10 @@
- fixed #8774: Forum Rich Edit no longer supports indent/outdent
- fixed #4173: fieldnames in profilefields can contain spaces
- fixed #8811: Bug Tracker: Formatting is bad for the resolution form.
- fixed #9235: Image Bug in rich text editor.
- fixed #9219: Thingy After Save Search This Thing not showing all rows (SDH Consulting Group)
- fixed #9231: Singleton workflows should not report an error when an attempt is made to run them again
- fixed #9244: i18n for colin
7.6.5
- security: A problem was discovered and fixed in which users could email executable attachments to a collaboration system and then when viewed online, could execute them.

View file

@ -184,6 +184,8 @@ sub assetExists {
Verifies that the user has the privileges necessary to add this type of asset. Return a boolean.
A class method.
=head3 session
The session variable.

View file

@ -426,7 +426,7 @@ sub setRatings {
foreach my $category (keys %{$self->getParent->getCategories}) {
if ($ratings->{$category}) {
$db->write("insert into MatrixListing_rating
(userId, category, rating, timeStamp, listingId, ipAddress, matrixId) values (?,?,?,?,?,?,?)",
(userId, category, rating, timeStamp, listingId, ipAddress, assetId) values (?,?,?,?,?,?,?)",
[$session->user->userId,$category,$ratings->{$category},$session->datetime->time(),$self->getId,
$session->env->get("HTTP_X_FORWARDED_FOR"),$matrixId]);
}
@ -439,7 +439,7 @@ sub setRatings {
my $median = $db->quickScalar("select rating $sql limit $half,$half",[$self->getId,$category]);
$db->write("replace into MatrixListing_ratingSummary
(listingId, category, meanValue, medianValue, countValue, matrixId)
(listingId, category, meanValue, medianValue, countValue, assetId)
values (?,?,?,?,?,?)",[$self->getId,$category,$mean,$median,$count,$matrixId]);
}
return undef;
@ -482,8 +482,9 @@ sub view {
my $self = shift;
my $hasRated = shift || $self->hasRated;
my $emailSent = shift;
my $db = $self->session->db;
my $i18n = WebGUI::International->new($self->session, "Asset_Matrix");
my $session = $self->session;
my $db = $session->db;
my $i18n = WebGUI::International->new($self->session, "Asset_MatrixListing");
my @categories = keys %{$self->getParent->getCategories};
# Increment views before getting template var hash so that the views tmpl_var has the incremented value.
@ -497,7 +498,7 @@ sub view {
$var->{comments} = $self->getFormattedComments();
$var->{productName} = $var->{title};
$var->{lastUpdated_epoch} = $self->get('lastUpdated');
$var->{lastUpdated_date} = $self->session->datetime->epochToHuman($self->get('lastUpdated'),"%z");
$var->{lastUpdated_date} = $session->datetime->epochToHuman($self->get('lastUpdated'),"%z");
$var->{manufacturerUrl_click} = $self->getUrl("func=click;manufacturer=1");
$var->{productUrl_click} = $self->getUrl("func=click");
@ -532,7 +533,7 @@ sub view {
foreach my $category (@categories) {
my $attributes;
my @attribute_loop;
my $categoryLoopName = $self->session->url->urlize($category)."_loop";
my $categoryLoopName = $session->url->urlize($category)."_loop";
$attributes = $db->read("select * from Matrix_attribute as a
left join MatrixListing_attribute as l on (a.attributeId = l.attributeId and l.matrixListingId = ?)
where category =? and a.assetId = ?",
@ -540,7 +541,7 @@ sub view {
while (my $attribute = $attributes->hashRef) {
$attribute->{label} = $attribute->{name};
if ($attribute->{fieldType} eq 'MatrixCompare'){
$attribute->{value} = WebGUI::Form::MatrixCompare->new($self->session,$attribute)->getValueAsHtml;
$attribute->{value} = WebGUI::Form::MatrixCompare->new($session,$attribute)->getValueAsHtml;
}
push(@attribute_loop,$attribute);
}
@ -554,7 +555,7 @@ sub view {
# Screenshots
if ($var->{screenshots}) {
my $file = WebGUI::Form::File->new($self->session,{ value=>$var->{screenshots} });
my $file = WebGUI::Form::File->new($session,{ value=>$var->{screenshots} });
my $storage = $file->getStorageLocation;
my @files;
@files = @{ $storage->getFiles } if (defined $storage);
@ -631,11 +632,11 @@ pluginspage="http://www.macromedia.com/go/getflashplayer" />
<th>".$i18n->get('median label')."</th>
<th>".$i18n->get('count label')."</th></tr>\n";
my $ratingForm = WebGUI::HTMLForm->new($self->session,
my $ratingForm = WebGUI::HTMLForm->new($session,
-extras =>'class="content"',
-tableExtras=>'class="content"'
);
$ratingForm = WebGUI::HTMLForm->new($self->session,
$ratingForm = WebGUI::HTMLForm->new($session,
-extras =>'class="ratingForm"',
-tableExtras=>'class="ratingForm"'
);
@ -664,9 +665,9 @@ pluginspage="http://www.macromedia.com/go/getflashplayer" />
$ratingForm->submit(
-extras =>'class="ratingForm"',
-value =>$i18n->get('rate submit label'),
-label =>'<a href="'.$self->getUrl("func=rate").'">'.$i18n->get('show ratings').'</a>'
-label =>'<a href="'.$self->getUrl("showRatings=1").'">'.$i18n->get('show ratings').'</a>'
);
if ($hasRated) {
if ($hasRated || $session->form->process('showRatings')) {
$var->{ratings} = $ratingsTable;
} else {
$var->{ratings} = $ratingForm->print;
@ -674,7 +675,7 @@ pluginspage="http://www.macromedia.com/go/getflashplayer" />
# Mail form
my $mailForm = WebGUI::HTMLForm->new($self->session,
my $mailForm = WebGUI::HTMLForm->new($session,
-extras =>'class="content"',
-tableExtras=>'class="content"'
);
@ -688,7 +689,7 @@ pluginspage="http://www.macromedia.com/go/getflashplayer" />
$mailForm->email(
-extras =>'class="content"',
-name =>"from",
-value =>$self->session->user->profileField("email"),
-value =>$session->user->profileField("email"),
-label =>$i18n->get('your email label'),
);
$mailForm->selectBox(

View file

@ -361,7 +361,8 @@ sub getCompareForm {
$maxComparisons = $self->get('maxComparisonsPrivileged');
}
$form .= "\n<script type='text/javascript'>\n".
'var maxComparisons = '.$maxComparisons.';'.
'var maxComparisons = '.$maxComparisons.";\n".
"var matrixUrl = '".$self->getUrl."';\n".
"\n</script>\n";
return $form;
}
@ -449,7 +450,7 @@ sub view {
'text/javascript'});
$self->session->style->setScript($self->session->url->extras('wobject/Matrix/matrix.js'), {type =>
'text/javascript'});
my $var = $self->get;
$var->{isLoggedIn} = ($self->session->user->userId ne "1");
$var->{addMatrixListing_url} = $self->getUrl('func=add;class=WebGUI::Asset::MatrixListing');
@ -457,7 +458,7 @@ sub view {
$var->{exportAttributes_url} = $self->getUrl('func=exportAttributes');
$var->{listAttributes_url} = $self->getUrl('func=listAttributes');
$var->{search_url} = $self->getUrl('func=search');
# Get the MatrixListing with the most views as an object using getLineage.
my ($bestViews_listing) = @{ $self->getLineage(['descendants'], {
includeOnlyClasses => ['WebGUI::Asset::MatrixListing'],
@ -674,6 +675,7 @@ sub www_compare {
'var listingIds = new Array('.join(", ",map {'"'.$_.'"'} @listingIds).");\n".
'var responseFields = new Array("attributeId", "name", "fieldType", "checked", '.join(", ",map {'"'.$_.'"'} @responseFields).");\n".
"var maxComparisons = ".$maxComparisons.";\n".
"var matrixUrl = '".$self->getUrl."';\n".
"</script>";
return $self->processStyle($self->processTemplate($var,$self->get("compareTemplateId")));
@ -903,12 +905,12 @@ sub www_getCompareFormData {
my $session = $self->session;
my $form = $session->form;
my $sort = shift || $session->scratch->get('matrixSort') || $self->get('defaultSort');
my $sortDirection = ' asc';
my $sortDirection = ' desc';
=cut
if ( WebGUI::Utility::isIn($sort, qw(revisionDate score)) ) {
$sortDirection = " desc";
}
=cut
my @results;
my @listingIds = $self->session->form->checkList("listingId");
@ -983,7 +985,7 @@ assetData.revisionDate
}
}
$result->{assetId} =~ s/-/_____/g;
$result->{url} = "/".$result->{url};
$result->{url} = $session->url->gateway($result->{url});
}
my $jsonOutput;

View file

@ -718,7 +718,7 @@ sub www_loadQuestions {
$self->session->log->debug('No responseId, surveyEnd');
return $self->surveyEnd();
}
if($self->response->hasTimedOut()){
if($self->response->hasTimedOut($self->get('timeLimit'))){
$self->session->log->debug('Response hasTimedOut, surveyEnd');
return $self->surveyEnd();
}

View file

@ -1,9 +1,59 @@
package WebGUI::Asset::Wobject::Survey::ResponseJSON;
=head1 LEGAL
-------------------------------------------------------------------
WebGUI is Copyright 2001-2008 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
-------------------------------------------------------------------
=head1 NAME
Package WebGUI::Asset::Wobject::Survey::ResponseJSON
=head1 DESCRIPTION
Helper class for WebGUI::Asset::Wobject::Survey. It manages data
from the user, sets the order of questions and answers in the survey,
based on forks, and gotos, and also handles expiring the survey
due to time limits.
This package is not intended to be used by any other Asset in WebGUI.
=cut
use strict;
use JSON;
use Data::Dumper;
=head2 new ( $json, $log, $survey )
Object constructor.
=head3 $json
Pass in some JSON to be serialized into a data structure. Useful JSON would
contain a hash with "startTime", "surveyOrder", "responses", "lastReponse"
and "questionsAnswered" keys, with appropriate values.
=head3 $log
The session logger, from $session->log. The class needs nothing else from the
session object.
=head3 $survey
A WebGUI::Asset::Wobject::Survey::SurveyJSON object that represents the current
survey.
=cut
sub new {
my $class = shift;
my $json = shift;
@ -28,9 +78,11 @@ sub new {
=head2 createSurveyOrder ( SurveyJSON, [address,address] )
This creates the order for the survey which will change after every fork.
The survey order is to precreate random questions and answers, which also leaves a record or what the user was presented with.
Forks are passed in to show where to branch the new order.
This creates the order for the survey which will change after every fork. The survey
order is to precreate random questions and answers, which also leaves a record or what
the user was presented with. Forks are passed in to show where to branch the new order.
If questions and/or answers were set to be randomized, it is handled in here.
=cut
@ -91,7 +143,8 @@ sub freeze {
sub hasTimedOut{
my $self=shift;
return 1 if($self->{startTime} + ($self->{timeLimit} * 60) < time() and $self->{timeLimit} > 0);
my $limit = shift;
return 1 if($self->{startTime} + ($limit * 60) < time() and $limit > 0);
return 0;
}
@ -149,14 +202,15 @@ sub recordResponses {
#These were just submitted from the user, so we need to see what and how they were (un)answered.
my $questions = $self->nextQuestions();
my $qAnswered = 1;
my $sterminal = 0;
my $terminal = 0;
my $terminalUrl;
my $goto;
#my $section = $self->survey->section([$questions->[0]->{sid}]);
my $section = $self->currentSection();
my $section = $self->nextSection();#which gets the current section for the just submitted questions. IE, current response pointer has not moved forward for these questions
if ( $section->{terminal} ) {
$terminal = 1;
$sterminal = 1;
$terminalUrl = $section->{terminalUrl};
}
@ -210,6 +264,11 @@ sub recordResponses {
else {
$terminal = 0;
}
if($sterminal and $self->nextSection != $self->currentSection){
$terminal = 1;
}
return [ $terminal, $terminalUrl ];
} ## end sub recordResponses

View file

@ -29,7 +29,8 @@ Asset in WebGUI.
use strict;
use JSON;
use Clone qw/clone/;
#use Clone qw/clone/;
use Storable qw/dclone/;
=head2 new ( $json, $log )
@ -37,8 +38,8 @@ Object constructor.
=head3 $json
Pass in some JSON to be serialized into a data structure. At the very least, you
must pass in the "null" JSON string, '{}'.
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
@ -238,13 +239,13 @@ question in a section. Returns that answer.
sub getObject {
my ( $self, $address ) = @_;
if ( @$address == 1 ) {
return clone $self->{sections}->[ $address->[0] ];
return dclone $self->{sections}->[ $address->[0] ];
}
elsif ( @$address == 2 ) {
return clone $self->{sections}->[ $address->[0] ]->{questions}->[ $address->[1] ];
return dclone $self->{sections}->[ $address->[0] ]->{questions}->[ $address->[1] ];
}
else {
return clone $self->{sections}->[ $address->[0] ]->{questions}->[ $address->[1] ]->{answers}->[ $address->[2] ];
return dclone $self->{sections}->[ $address->[0] ]->{questions}->[ $address->[1] ]->{answers}->[ $address->[2] ];
}
}
@ -575,13 +576,13 @@ Nothing happens. It is not allowed to duplicate answers.
sub copy {
my ( $self, $address ) = @_;
if ( @$address == 1 ) {
my $newSection = clone $self->section($address);
my $newSection = dclone $self->section($address);
push( @{ $self->sections }, $newSection );
$address->[0] = $#{ $self->sections };
return $address;
}
elsif ( @$address == 2 ) {
my $newQuestion = clone $self->question($address);
my $newQuestion = dclone $self->question($address);
push( @{ $self->questions($address) }, $newQuestion );
$address->[1] = $#{ $self->questions($address) };
return $address;

View file

@ -3090,7 +3090,10 @@ sequenceNumber');
}
$query .= join(", ",map {$dbh->quote_identifier('field_'.$_->{fieldId})} @displayInSearchFields);
$query .= " from ".$dbh->quote_identifier("Thingy_".$thingId);
$query .= " where ".join(" and ",@constraints) if (scalar(@constraints) > 0);
if($session->form->process('func') eq 'search'){
# Don't add constraints when the search screen is displayed as an 'after save' option.
$query .= " where ".join(" and ",@constraints) if (scalar(@constraints) > 0);
}
if ($orderBy){
$query .= " order by ".$dbh->quote_identifier("field_".$orderBy);
}

View file

@ -291,6 +291,13 @@ sub www_runCronJob {
priority => $task->get("priority"),
});
if ( !$instance ) {
if ($session->stow->get('singletonWorkflowClash')) {
$session->errorHandler->warn(
"Could not create workflow instance for workflowId '" . $task->get( "workflowId" )
. "': It is a singleton workflow and is still running from the last invocation."
);
return "done";
}
$session->errorHandler->error(
"Could not create workflow instance for workflowId '" . $task->get( "workflowId" )
. "': The result was undefined"

View file

@ -73,8 +73,10 @@ sub create {
$sql .= ' and parameters IS NULL';
}
my ($count) = $session->db->quickArray($sql,$placeHolders);
$session->stow->set('singletonWorkflowClash', 0);
if ($isSingleton && $count) {
$session->log->info("An instance of singleton workflow $properties->{workflowId} already exists, not creating a new one");
$session->stow->set('singletonWorkflowClash', 1);
return undef
}

View file

@ -75,8 +75,8 @@ our $I18N = {
},
'inbox manage invitations template hoverHelp' => {
message => q|Choose the template to user for managing invitations|,
lastUpdated => 1119068809
message => q|Choose the template to use for managing invitations|,
lastUpdated => 1228773936
},
'invitation confirm message template label' => {

View file

@ -5,8 +5,8 @@ our $I18N = {
'title' => {
message => q{Profile},
lastUpdated => 1225724810,
context => q{Tab label for Profile Account pluggin},
lastUpdated => 1228764827,
context => q{Tab label for Profile Account plugin},
},
'profile style template label' => {
@ -15,7 +15,7 @@ our $I18N = {
},
'profile style template hoverHelp' => {
message => q|Select a style template from the list to enclose the inbox in.|,
message => q|Select a style template from the list to enclose the profile in.|,
lastUpdated => 1119068809
},
@ -25,8 +25,8 @@ our $I18N = {
},
'profile layout template hoverHelp' => {
message => q{Choose a layout from the list to display the various account pluggins that are editable by the current user as well as the contents of the one currently chosen},
lastUpdated => 1119068809
message => q{Choose a layout from the list to display the various account plugins that are usable by the current user as well as the contents of the plugin currently chosen.},
lastUpdated => 1228773692
},
'profile view template label' => {
@ -35,7 +35,7 @@ our $I18N = {
},
'profile view template hoverHelp' => {
message => q|Choose the main template for viewing a profile|,
message => q|Choose the main template for viewing a profile.|,
lastUpdated => 1119068809
},
@ -55,7 +55,7 @@ our $I18N = {
},
'profile edit layout template hoverHelp' => {
message => q{Choose a layout from the list to display the various account pluggins that are viewable by others as well as the contents of the one currently chosen},
message => q{Choose a layout from the list to display the user's profile for editing.},
lastUpdated => 1119068809
},

View file

@ -780,47 +780,6 @@ listing,|,
lastUpdated => 0,
},
'your email label' => {
message => q|Your Email Address|,
lastUpdated => 0,
},
'report error label' => {
message => q|Report an error.|,
lastUpdated => 0,
},
'general comment label' => {
message => q|General comment.|,
lastUpdated => 0,
},
'request type label' => {
message => q|Type of Request|,
lastUpdated => 0,
},
'comment label' => {
message => q|Comment|,
lastUpdated => 0,
},
'send button label' => {
message => q|Send...|,
lastUpdated => 0,
},
'show ratings' => {
message => q|Show Ratings|,
lastUpdated => 0,
},
'rate submit label' => {
message => q|Rate|,
lastUpdated => 0,
},
'no copy' => {
message => q|This asset may not be copied.|,
lastUpdated => 1133758944,

View file

@ -153,6 +153,47 @@ this listing.|,
lastUpdated => 0,
},
'your email label' => {
message => q|Your Email Address|,
lastUpdated => 0,
},
'report error label' => {
message => q|Report an error.|,
lastUpdated => 0,
},
'general comment label' => {
message => q|General comment.|,
lastUpdated => 0,
},
'request type label' => {
message => q|Type of Request|,
lastUpdated => 0,
},
'comment label' => {
message => q|Comment|,
lastUpdated => 0,
},
'send button label' => {
message => q|Send...|,
lastUpdated => 0,
},
'show ratings' => {
message => q|Show Ratings|,
lastUpdated => 0,
},
'rate submit label' => {
message => q|Rate|,
lastUpdated => 0,
},
};
1;

View file

@ -13,7 +13,8 @@ use Data::Dumper;
use WebGUI::Test; # Must use this before any other WebGUI modules
use WebGUI::Session;
use JSON;
use Clone qw/clone/;
#use Clone qw/clone/;
use Storable qw/dclone/;
#----------------------------------------------------------------------------
# Init
@ -21,13 +22,12 @@ my $session = WebGUI::Test->session;
#----------------------------------------------------------------------------
# Tests
my $tests = 87;
my $tests = 96;
plan tests => $tests + 1 + 3;
#----------------------------------------------------------------------------
# put your tests here
####################################################
#
# buildSectionSkeleton
@ -129,18 +129,9 @@ skip $tests, "Unable to load SurveyJSON" unless $usedOk;
$surveyJSON = WebGUI::Asset::Wobject::Survey::SurveyJSON->new('{}', $session->log);
isa_ok($surveyJSON, 'WebGUI::Asset::Wobject::Survey::SurveyJSON');
####################################################
#
# log
#
####################################################
WebGUI::Test->interceptLogging;
my $logger = $surveyJSON->log("Everyone in here is innocent");
is ($WebGUI::Test::logger_warns, undef, 'Did not log a warn');
is ($WebGUI::Test::logger_info, undef, 'Did not log an info');
is ($WebGUI::Test::logger_error, "Everyone in here is innocent", 'Logged an error');
my $sJSON2 = WebGUI::Asset::Wobject::Survey::SurveyJSON->new(undef, $session->log);
isa_ok($sJSON2, 'WebGUI::Asset::Wobject::Survey::SurveyJSON', 'even with absolutely no JSON');
undef $sJSON2;
####################################################
#
@ -204,6 +195,23 @@ lives_ok
}
'new handles wide characters';
$sJSON2 = WebGUI::Asset::Wobject::Survey::SurveyJSON->new(
'{ "sections" : [ { "type" : "section" } ], "survey" : {} }',
$session->log,
);
cmp_deeply(
$sJSON2->sections,
[
{
type => 'section',
},
],
'new: If the JSON has a section, a new one will not be added',
);
undef $sJSON2;
####################################################
#
# freeze
@ -435,8 +443,9 @@ my $section1 = $surveyJSON->getObject([2]);
cmp_deeply(
$section1,
superhashof({
type => 'section',
title => 'Section 1',
type => 'section',
title => 'Section 1',
questions => [],
}),
'getObject: Retrieved correct section'
);
@ -496,16 +505,17 @@ cmp_deeply(
$section->{title} = 'Section 1';
$surveyJSON->update([1], $section );
}
##Update the title to make it clearer.
$surveyJSON->section([2])->{title} = 'Section 2';
##And give it a question
$surveyJSON->newObject([2]);
cmp_deeply(
summarizeSectionSkeleton($surveyJSON),
[
{
title => 'Section 0',
questions => [
{
text => 'Question 0-0',
answers => [],
},
{ text => 'Question 0-0', answers => [], },
{
text => 'Question 0-1',
answers => [
@ -520,10 +530,7 @@ cmp_deeply(
},
],
},
{
text => 'Question 0-2',
answers => [],
},
{ text => 'Question 0-2', answers => [], },
],
},
{
@ -536,8 +543,13 @@ cmp_deeply(
],
},
{
title => 'Section 1',
questions => [],
title => 'Section 2',
questions => [
{
text => '',
answers => [],
},
],
},
],
'Update: updated a section'
@ -548,8 +560,9 @@ my $question1 = $surveyJSON->getObject([1, 0]);
cmp_deeply(
$question1,
superhashof({
type => 'question',
text => 'Question 0+-0',
type => 'question',
text => 'Question 0+-0',
answers => [],
}),
'getObject: Retrieved correct question'
);
@ -600,6 +613,106 @@ cmp_deeply(
'remove: Remove an answer'
);
$surveyJSON->remove([0]),
cmp_deeply(
$surveyJSON->getObject([0]),
superhashof({
type => 'section',
title => 'Section 0',
}),
'remove: Cannot remove the first section, by default'
);
my $sectionAddress = $surveyJSON->newObject([]);
cmp_deeply(
$surveyJSON->sections,
[
superhashof({
type => 'section',
title => 'Section 0',
questions => ignore(),
}),
superhashof({
type => 'section',
title => 'Section 1',
questions => ignore(),
}),
superhashof({
type => 'section',
title => 'Section 2',
questions => ignore(),
}),
superhashof({
type => 'section',
title => 'NEW SECTION',
questions => ignore(),
}),
],
'Added new section for testing remove'
);
$surveyJSON->remove($sectionAddress),
cmp_deeply(
$surveyJSON->sections,
[
superhashof({
type => 'section',
title => 'Section 0',
questions => ignore(),
}),
superhashof({
type => 'section',
title => 'Section 1',
questions => ignore(),
}),
superhashof({
type => 'section',
title => 'Section 2',
questions => ignore(),
}),
],
'remove: Removed a section'
);
$surveyJSON->newObject([2]);
cmp_deeply(
$surveyJSON->getObject([2]),
#$surveyJSON->section([2]),
superhashof({
title => 'Section 2',
type => 'section',
questions => [
superhashof({
text => '',
type => 'question',
}),
superhashof({
text => '',
type => 'question',
}),
],
}),
'Added a question to section 2 to test removing it'
);
$surveyJSON->remove([2,0]);
cmp_deeply(
$surveyJSON->getObject([2]),
superhashof({
title => 'Section 2',
type => 'section',
questions => [
superhashof({
text => '',
type => 'question',
}),
],
}),
'remove: removed a question'
);
####################################################
#
# copy
@ -659,8 +772,13 @@ cmp_deeply(
],
},
{
title => 'Section 1',
questions => [],
title => 'Section 2',
questions => [
{
text => '',
answers => [],
},
],
},
],
'copy: copied a question with answers'
@ -716,16 +834,19 @@ cmp_deeply(
],
},
{
title => 'Section 1',
questions => [],
title => 'Section 2',
questions => [
{
text => '',
answers => [],
},
],
},
],
'copy: copies safe references for a question'
);
##Now, try a section copy.
##Update the title to make the copying clear.
$surveyJSON->section([2])->{title} = 'Section 2';
$stompedAddress = [1];
$returnedAddress = $surveyJSON->copy($stompedAddress);
is_deeply($returnedAddress, [3], 'Added a section');
@ -779,7 +900,12 @@ cmp_deeply(
},
{
title => 'Section 2',
questions => [],
questions => [
{
text => '',
answers => [],
},
],
},
{
title => 'Section 1',
@ -826,7 +952,15 @@ cmp_deeply(
{ text => 'Question 1-0', answers => [], },
],
},
{ title => 'Section 2', questions => [], },
{
title => 'Section 2',
questions => [
{
text => '',
answers => [],
},
],
},
{
title => 'Section 3',
questions => [
@ -841,6 +975,89 @@ cmp_deeply(
$surveyJSON->question([0, 3])->{text} = 'Question 0-3';
$surveyJSON->answer([0, 3, 1])->{text} = 'Answer 0-3-1';
##Now, try copying the last section.
$surveyJSON->copy([3]);
cmp_deeply(
summarizeSectionSkeleton($surveyJSON),
[
{
title => 'Section 0',
questions => [
{
text => 'Question 0-0',
answers => [],
},
{
text => 'Question 0-1',
answers => [
{
text => 'Answer 0-1-0',
},
{
text => 'Answer 0-1-1',
},
],
},
{
text => 'Question 0-2',
answers => [],
},
{
text => 'Question 0-3',
answers => [
{
text => 'Answer 0-3-0',
},
{
text => 'Answer 0-3-1',
},
],
},
],
},
{
title => 'Section 1',
questions => [
{
text => 'Question 1-0',
answers => [],
},
],
},
{
title => 'Section 2',
questions => [
{
text => '',
answers => [],
},
],
},
{
title => 'Section 3',
questions => [
{
text => 'Question 3-0',
answers => [],
},
],
},
{
title => 'Section 3',
questions => [
{
text => 'Question 3-0',
answers => [],
},
],
},
],
'copy: copied last section'
);
$surveyJSON->remove([4]);
cmp_deeply(
summarizeSectionSkeleton($surveyJSON),
[
@ -875,7 +1092,13 @@ cmp_deeply(
],
},
{
title => 'Section 2', questions => [],
title => 'Section 2',
questions => [
{
text => '',
answers => [],
},
],
},
{
title => 'Section 3',
@ -984,12 +1207,16 @@ cmp_deeply(
type => 'section',
text => 'Section 2',
},
{
type => 'question',
text => '',
},
{
type => 'section',
text => 'Section 3',
},
],
'getDragDropList: list of sections, no questions'
'getDragDropList: FIXME: list of sections, no questions'
);
####################################################
@ -1226,6 +1453,37 @@ cmp_deeply(
'addAnswersToQuestion: setup verbatims on two answers'
);
$surveyJSON->question([3,0])->{answers} = [];
$surveyJSON->addAnswersToQuestion( [3,0],
[ qw[ one two three ] ],
{ 1 => 0 }
);
cmp_deeply(
$surveyJSON->question([3,0]),
superhashof({
answers => [
superhashof({
text => 'one',
verbatim => 0,
recordedAnswer => 1,
}),
superhashof({
text => 'two',
verbatim => 0,
recordedAnswer => 2,
}),
superhashof({
text => 'three',
verbatim => 0,
recordedAnswer => 3,
}),
],
}),
'addAnswersToQuestion: verbatims have to exist, and be true'
);
####################################################
#
# updateQuestionAnswers
@ -1745,6 +2003,19 @@ cmp_deeply(
'updateQuestionAnswers: Dual Slider - Range'
);
####################################################
#
# log
#
####################################################
WebGUI::Test->interceptLogging;
my $logger = $surveyJSON->log("Everyone in here is innocent");
is ($WebGUI::Test::logger_warns, undef, 'Did not log a warn');
is ($WebGUI::Test::logger_info, undef, 'Did not log an info');
is ($WebGUI::Test::logger_error, "Everyone in here is innocent", 'Logged an error');
}
####################################################
@ -1792,13 +2063,13 @@ sub buildSectionSkeleton {
my $sections = [];
my ($bareSection, $bareQuestion, $bareAnswer) = getBareSkeletons();
foreach my $questionSpec ( @{ $spec } ) {
my $section = clone $bareSection;
my $section = dclone $bareSection;
push @{ $sections }, $section;
foreach my $answers ( @{$questionSpec} ) {
my $question = clone $bareQuestion;
my $question = dclone $bareQuestion;
push @{ $section->{questions} }, $question;
while ($answers-- > 0) {
my $answer = clone $bareAnswer;
my $answer = dclone $bareAnswer;
push @{ $question->{answers} }, $answer;
}
}

View file

@ -43,10 +43,10 @@ var WGInsertImageDialog = {
img += ' hspace="' + parseInt(form.imagehspace.value) + '"';
}
if (form.imagevspace.value != "") {
img += ' vspace="' + parseInt(form.imagevspace.value) + "'";
img += ' vspace="' + parseInt(form.imagevspace.value) + '"';
}
if (form.imageborder.value != "") {
img += ' border="' + parseInt(form.imageborder.value) + "'";
img += ' border="' + parseInt(form.imageborder.value) + '"';
}
if (form.imagealign.value != "") {
img += ' align="' + form.imagealign.value + '"';

View file

@ -22,13 +22,13 @@ YAHOO.util.Event.addListener(window, "load", function() {
];
var uri = "func=getCompareFormData";
if(typeof(listingIds) != 'undefined'){
for (var i = 0; i < listingIds.length; i++) {
uri = uri+';listingId='+listingIds[i];
}
if(typeof(listingIds) != 'undefined'){
for (var i = 0; i < listingIds.length; i++) {
uri = uri+';listingId='+listingIds[i];
}
}
this.myDataSource = new YAHOO.util.DataSource("?");
this.myDataSource = new YAHOO.util.DataSource(matrixUrl + "?");
this.myDataSource.responseType = YAHOO.util.DataSource.TYPE_JSON;
this.myDataSource.connXhrMode = "queueRequests";
this.myDataSource.responseSchema = {
@ -47,25 +47,25 @@ YAHOO.util.Event.addListener(window, "load", function() {
var btnSortByViews = new YAHOO.widget.Button("sortByViews");
btnSortByViews.on("click", function(e) {
this.myDataTable.sortColumn(this.myDataTable.getColumn(2));
var request = YAHOO.util.Connect.asyncRequest('POST', "?func=setSort;sort=views");
var request = YAHOO.util.Connect.asyncRequest('POST', matrixUrl + "?func=setSort;sort=views");
},this,true);
var btnSortByClicks = new YAHOO.widget.Button("sortByClicks");
btnSortByClicks.on("click", function(e) {
this.myDataTable.sortColumn(this.myDataTable.getColumn(3));
var request = YAHOO.util.Connect.asyncRequest('POST', "?func=setSort;sort=clicks");
var request = YAHOO.util.Connect.asyncRequest('POST', matrixUrl + "?func=setSort;sort=clicks");
},this,true);
var btnSortByCompares = new YAHOO.widget.Button("sortByCompares");
btnSortByCompares.on("click", function(e) {
this.myDataTable.sortColumn(this.myDataTable.getColumn(4));
var request = YAHOO.util.Connect.asyncRequest('POST', "?func=setSort;sort=compares");
var request = YAHOO.util.Connect.asyncRequest('POST', matrixUrl + "?func=setSort;sort=compares");
},this,true);
var btnSortByUpdated = new YAHOO.widget.Button("sortByUpdated");
btnSortByUpdated.on("click", function(e) {
this.myDataTable.sortColumn(this.myDataTable.getColumn(5));
var request = YAHOO.util.Connect.asyncRequest('POST', "?func=setSort;sort=lastUpdated");
var request = YAHOO.util.Connect.asyncRequest('POST', matrixUrl + "?func=setSort;sort=lastUpdated");
},this,true);
var myCallback = function() {
@ -77,6 +77,15 @@ YAHOO.util.Event.addListener(window, "load", function() {
btnCompare.on("click", function(e) {
window.document.forms['doCompare'].submit();
},this,true);
var btnCompare2 = new YAHOO.widget.Button("compare2",{disabled:true,id:"compareButton2"});
btnCompare2.on("click", function(e) {
window.document.forms['doCompare'].submit();
},this,true);
var btnSearch = new YAHOO.widget.Button("search");
btnSearch.on("click", function(e) {
window.location.href = matrixUrl + '?func=search';
},this,true);
window.compareDataTable = this.myDataTable;
@ -92,8 +101,10 @@ YAHOO.util.Event.addListener(window, "load", function() {
}
if (checked > 1 && checked < maxComparisons){
btnCompare.set("disabled",false);
btnCompare2.set("disabled",false);
}else{
btnCompare.set("disabled",true);
btnCompare2.set("disabled",true);
}
var elements = window.compareDataTable.getRecordSet().getRecords();
for(j=0; j<elements.length; j++){

View file

@ -55,6 +55,9 @@ YAHOO.util.Event.addListener(window, "load", function() {
var myDataTable = new YAHOO.widget.DataTable("compareList", myColumnDefs,
this.myDataSource, {initialRequest:uri});
window.removeListing = function(key) {
myDataTable.hideColumn(myDataTable.removeColumn(key));
}
this.myDataSource.doBeforeParseData = function (oRequest, oFullResponse) {
myDataTable.getRecordSet().reset();
@ -72,6 +75,7 @@ YAHOO.util.Event.addListener(window, "load", function() {
for (var i = 0; i < len; i++) {
var c = oFullResponse.ColumnDefs[i];
oFullResponse.ColumnDefs[i].label = oFullResponse.ColumnDefs[i].label + "<a href='javascript:removeListing(\""+oFullResponse.ColumnDefs[i].key+"\")'><img src='/extras/toolbar/bullet/delete.gif' border='0'></a>"
myDataTable.insertColumn(c);
}
}
@ -91,8 +95,8 @@ YAHOO.util.Event.addListener(window, "load", function() {
var btnCompare = new YAHOO.widget.Button("compare",{disabled:true,id:"compareButton"});
btnCompare.on("click", function(e) {
var uri = "func=getCompareListData";
var compareCheckBoxes = YAHOO.util.Dom.getElementsByClassName('compareCheckBox','input');
var uri = "func=getCompareListData";
for (var i = compareCheckBoxes.length; i--; ) {
if(compareCheckBoxes[i].checked == true){
uri = uri+';listingId='+compareCheckBoxes[i].value;
@ -101,6 +105,23 @@ YAHOO.util.Event.addListener(window, "load", function() {
this.myDataSource.sendRequest(uri,callback2);
},this,true);
var btnCompare2 = new YAHOO.widget.Button("compare2",{disabled:true,id:"compareButton2"});
btnCompare2.on("click", function(e) {
var compareCheckBoxes = YAHOO.util.Dom.getElementsByClassName('compareCheckBox','input');
var uri = "func=getCompareListData";
for (var i = compareCheckBoxes.length; i--; ) {
if(compareCheckBoxes[i].checked == true){
uri = uri+';listingId='+compareCheckBoxes[i].value;
}
}
this.myDataSource.sendRequest(uri,callback2);
},this,true);
var btnSearch = new YAHOO.widget.Button("search");
btnSearch.on("click", function(e) {
window.location.href = matrixUrl + '?func=search';
},this,true);
window.compareFormButton = function() {
var compareCheckBoxes = YAHOO.util.Dom.getElementsByClassName('compareCheckBox','input');
var checked = 0;
@ -111,8 +132,10 @@ YAHOO.util.Event.addListener(window, "load", function() {
}
if (checked > 1 && checked < maxComparisons){
btnCompare.set("disabled",false);
btnCompare2.set("disabled",false);
}else{
btnCompare.set("disabled",true);
btnCompare2.set("disabled",true);
}
}

View file

@ -16,10 +16,7 @@ YAHOO.util.Event.addListener(window, "load", function() {
var myColumnDefs = [
{key:"assetId",label:"",sortable:false, formatter:this.formatCheckBox},
{key:"title", label:"Name", sortable:true, formatter:this.formatUrl},
{key:"views", sortable:true},
{key:"clicks", sortable:true},
{key:"compares", sortable:true}
{key:"title", label:"Name", sortable:true, formatter:this.formatUrl}
];
var uri = "func=getCompareFormData";
@ -34,7 +31,7 @@ YAHOO.util.Event.addListener(window, "load", function() {
this.myDataSource.connXhrMode = "queueRequests";
this.myDataSource.responseSchema = {
resultsList: "ResultSet.Result",
fields: ["title","views","clicks","compares","checked","url","assetId"]
fields: ["title","checked","url","assetId"]
};
var myDataTable = new YAHOO.widget.DataTable("compareForm", myColumnDefs,

View file

@ -5,7 +5,7 @@ if (typeof Survey == "undefined") {
Survey.Data = new function(){
var lastDataSet = {};
var focus;
var lastId = -1;
this.dragDrop = function(did){
var type;
@ -46,6 +46,14 @@ YAHOO.log(first.id+' '+data.id);
this.loadData = function(d){
focus = d.address;//What is the current highlighted item.
var showEdit = 1;
if(lastId.toString() == d.address.toString()){
showEdit = 0;
lastId = -1;
}else{
lastId = d.address;
}
console.log(d.address);
document.getElementById('sections').innerHTML=d.ddhtml;
//add event handlers for if a tag is clicked
@ -72,7 +80,11 @@ YAHOO.log('adding handler for '+ d.ids[x]);
button.on("click", this.addAnswer,d.buttons['answer']);
}
this.loadObjectEdit(d.edithtml,d.type);
if(showEdit == 1){
this.loadObjectEdit(d.edithtml,d.type);
}else{
document.getElementById('edit').innerHTML = "";
}
lastDataSet = d;
}