diff --git a/.gitignore b/.gitignore
index fda9bb65ba..dcf19fe148 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,6 +9,8 @@ courses.dist
library-directory-tree.json
library-subject-tree.json
textbook-tree.json
+development.yml
+production.yml
*~
!tmp/README
!htdocs/tmp/README
diff --git a/bin/OPL-update b/bin/OPL-update
index f7b1a924ac..be342e7502 100755
--- a/bin/OPL-update
+++ b/bin/OPL-update
@@ -11,7 +11,7 @@
# 1) The OPL downloaded to your machine (the .pg files)
# 2) The environment variable WEBWORK_ROOT needs to be
# correctly defined (as with other scripts here).
-# 3) Configuration for the OPL in site.conf needs to be
+# 3) Configuration for the OPL in localOverrides.conf needs to be
# done (basically just setting the path to the OPL files).
#use strict;
@@ -406,7 +406,7 @@ if(open(IN, "$libraryRoot/Textbooks")) {
close(IN);
} else {
print "Textbooks file was not found in library $libraryRoot. If the path to the problem library doesn't seem
- correct, make modifications in webwork2/conf/site.conf (\$problemLibrary{root}). If that is correct then
+ correct, make modifications in webwork2/conf/localOverrides.conf (\$problemLibrary{root}). If that is correct then
updating from git should download the Textbooks file.\n";
}
#### End of textbooks
diff --git a/conf/defaults.config b/conf/defaults.config
index 7e9191eebc..3621ae3f77 100644
--- a/conf/defaults.config
+++ b/conf/defaults.config
@@ -1356,15 +1356,15 @@ $ConfigValues = [
type => 'popuplist'
},
{ var => 'pg{specialPGEnvironmentVars}{DragMath}',
- doc => 'Use DragMath editor for answer entry',
- doc2 => 'Set to true to display pencil DragMath equation editor next to each answer box',
- type => 'boolean'
- },
- { var => 'pg{specialPGEnvironmentVars}{MathView}',
- doc => 'Use MathView editor for answer entry',
- doc2 => 'Set to true to display MathView equation editor icon next to each answer box',
- type => 'boolean'
- },
+ doc => 'Use DragMath editor for answer entry',
+ doc2 => 'Set to true to display pencil DragMath equation editor next to each answer box',
+ type => 'boolean'
+ },
+ { var => 'pg{specialPGEnvironmentVars}{MathView}',
+ doc => 'Use MathView editor for answer entry',
+ doc2 => 'Set to true to display MathView equation editor icon next to each answer box',
+ type => 'boolean'
+ },
{ var => 'pg{options}{showEvaluatedAnswers}',
doc => 'Display the evaluated student answer',
doc2 => 'Set to true to display the "Entered" column which automatically shows the evaluated student answer, e.g. 1 if student input is sin(pi/2). If this is set to false, e.g. to save space in the response area, the student can still see their evaluated answer by hovering the mouse pointer over the typeset version of their answer.',
@@ -1399,7 +1399,7 @@ $ConfigValues = [
type => boolean
},
{ var => 'pg{ansEvalDefaults}{reducedScoringPeriod}',
- doc => 'Length of Reduced Scoring Period in minutes',
+ doc => 'Default Length of the Reduced Scoring Period',
doc2 => 'The Reduced Scoring Period is a period before the due date during which all additional work done by the student counts at a reduced rate. Here is where you set the default length of this period in minutes. This sets the default Reduced Scoring date, which can be changed on a per set basis. If the Reduced Scoring is enabled and if it is after the reduced scoring date, but before the due date, a message like "This assignment has a Reduced Scoring Period that begins 11/08/2009 at 06:17pm EST and ends on the due date, 11/10/2009 at 06:17pm EST. During this period all additional work done counts 50% of the original." will be displayed.' ,
type => 'number'
},
@@ -1428,32 +1428,32 @@ $ConfigValues = [
values => [qw(1 0.95 0.9 0.85 0.8 0.75 0.7 0.65 0.6 0.55 0.5 0.45 0.4 0.35 0.3 0.25 0.2 0.15 0.1)],
type => 'popuplist'
},
- { var => 'pg{timeAssignDue}',
+ { var => 'pg{timeAssignDue}',
doc => 'Time that the Assignment is Due',
doc2 => 'The time of the day that the assignment is due. This can be changed on an individual basis, but WeBWorK will use this value for default when a date is set.',
type => 'text'
},
{ var => 'pg{assignOpenPriorToDue}',
doc => 'Amount of Time (in minutes) before Due Date that the Assignment is Open',
- doc2 => 'The amount of time (in minutes) before the due date when the assignment is opened.',
- type => 'number'
+ doc2 => 'The amount of time (in minutes) before the due date when the assignment is opened.',
+ type => 'number'
},
{ var => 'pg{answersOpenAfterDueDate}',
doc => 'Amount of Time (in minutes) after Due Date that Answers are Open',
doc2 => 'The amount of time (in minutes) after the due date that the Answers are available to student to view.',
- type => 'number'
+ type => 'number'
},
- { var => 'pg{options}{enableShowMeAnother}',
- doc => 'Enable Show Me Another button',
- doc2 => 'Enables use of the Show Me Another button, which offers the student a newly-seeded version of the current problem, complete with solution (if it exists for that problem).',
- type => 'boolean'
- },
- { var => 'pg{options}{showMeAnotherMaxReps}',
- doc => 'Maximum times Show me Another can be used per problem (-1 => unlimited)',
- doc2 => 'The Maximum number of times Show me Another can be used per problem by a student. If set to -1 then there is no limit to the number of times that Show Me Another can be used.',
- type => 'number'
- },
- { var => 'pg{options}{showMeAnother}',
+ { var => 'pg{options}{enableShowMeAnother}',
+ doc => 'Enable Show Me Another button',
+ doc2 => 'Enables use of the Show Me Another button, which offers the student a newly-seeded version of the current problem, complete with solution (if it exists for that problem).',
+ type => 'boolean'
+ },
+ { var => 'pg{options}{showMeAnotherMaxReps}',
+ doc => 'Maximum times Show me Another can be used per problem (-1 => unlimited)',
+ doc2 => 'The Maximum number of times Show me Another can be used per problem by a student. If set to -1 then there is no limit to the number of times that Show Me Another can be used.',
+ type => 'number'
+ },
+ { var => 'pg{options}{showMeAnother}',
doc => 'List of options for Show Me Another button',
doc2 => '
- SMAcheckAnswers: enables the Check Answers button for the new problem when Show Me Another is clicked
- SMAshowSolutions: shows walk-through solution for the new problem when Show Me Another is clicked; a check is done first to make sure that a solution exists
- SMAshowCorrect: correct answers for the new problem can be viewed when Show Me Another is clicked; note that SMAcheckAnswers needs to be enabled at the same time
- SMAshowHints: show hints for the new problem (assuming they exist)
Note: there is very little point enabling the button unless you check at least one of these options - the students would simply see a new version that they can not attempt or learn from.',
min => 0,
diff --git a/webwork3/bin/app.pl b/webwork3/bin/app.pl
index 84b9e0b037..a214cd6189 100755
--- a/webwork3/bin/app.pl
+++ b/webwork3/bin/app.pl
@@ -23,10 +23,10 @@
hook 'before' => sub {
- for my $key (keys(%{request->params})){
- my $value = defined(params->{$key}) ? params->{$key} : '';
- debug($key . " : " . $value);
- }
+ # for my $key (keys(%{request->params})){
+ # my $value = defined(params->{$key}) ? params->{$key} : '';
+ # debug($key . " : " . $value);
+ # }
};
diff --git a/webwork3/lib/Routes/ProblemSets.pm b/webwork3/lib/Routes/ProblemSets.pm
index c796b264d6..8b187e3d02 100644
--- a/webwork3/lib/Routes/ProblemSets.pm
+++ b/webwork3/lib/Routes/ProblemSets.pm
@@ -9,7 +9,7 @@ package ProblemSets;
use strict;
use warnings;
use Dancer ':syntax';
-use Utils::Convert qw/convertObjectToHash convertArrayOfObjectsToHash/;
+use Utils::Convert qw/convertObjectToHash convertArrayOfObjectsToHash convertBooleans/;
use Utils::ProblemSets qw/reorderProblems addGlobalProblems addUserSet addUserProblems deleteProblems createNewUserProblem/;
use WeBWorK::Utils qw/parseDateTime decodeAnswers/;
use Array::Utils qw(array_minus);
@@ -17,10 +17,10 @@ use Routes::Authentication qw/checkPermissions setCourseEnvironment/;
use Utils::CourseUtils qw/getCourseSettings/;
use Dancer::Plugin::Database;
use Dancer::Plugin::Ajax;
-use List::Util qw(first max );
+use List::Util qw/first max/;
-our @set_props = qw/set_id set_header hardcopy_header open_date due_date answer_date visible enable_reduced_scoring assignment_type attempts_per_version time_interval versions_per_interval version_time_limit version_creation_time version_last_attempt_time problem_randorder hide_score hide_score_by_problem hide_work time_limit_cap restrict_ip relax_restrict_ip restricted_login_proctor/;
-our @user_set_props = qw/user_id set_id psvn set_header hardcopy_header open_date due_date answer_date visible enable_reduced_scoring assignment_type description restricted_release restricted_status attempts_per_version time_interval versions_per_interval version_time_limit version_creation_time problem_randorder version_last_attempt_time problems_per_page hide_score hide_score_by_problem hide_work time_limit_cap restrict_ip relax_restrict_ip restricted_login_proctor hide_hint/;
+our @set_props = qw/set_id set_header hardcopy_header open_date reduced_scoring_date due_date answer_date visible enable_reduced_scoring assignment_type attempts_per_version time_interval versions_per_interval version_time_limit version_creation_time version_last_attempt_time problem_randorder hide_score hide_score_by_problem hide_work time_limit_cap restrict_ip relax_restrict_ip restricted_login_proctor/;
+our @user_set_props = qw/user_id set_id psvn set_header hardcopy_header open_date reduced_scoring_date due_date answer_date visible enable_reduced_scoring assignment_type description restricted_release restricted_status attempts_per_version time_interval versions_per_interval version_time_limit version_creation_time problem_randorder version_last_attempt_time problems_per_page hide_score hide_score_by_problem hide_work time_limit_cap restrict_ip relax_restrict_ip restricted_login_proctor hide_hint/;
our @problem_props = qw/problem_id flags value max_attempts source_file/;
our @boolean_set_props = qw/visible enable_reduced_scoring/;
@@ -132,19 +132,16 @@ put '/courses/:course_id/sets/:set_id' => sub {
####
#
- # Set up the global set for either a add (if new) or put (if old)
+ # set all the parameters sent from the client as new properties.
#
##
-
+ my %allparams = params;
my $set = vars->{db}->getGlobalSet(params->{set_id});
-
- for my $key (@set_props) {
- $set->{$key} = params->{$key} if defined(params->{$key});
+ my $setFromClient = convertBooleans(\%allparams,\@boolean_set_props);
+ for my $key (@set_props){
+ $set->{$key} = $setFromClient->{$key};
}
-
-
- vars->{db}->putGlobalSet($set);
-
+ my $result = vars->{db}->putGlobalSet($set);
##
#
@@ -155,7 +152,6 @@ put '/courses/:course_id/sets/:set_id' => sub {
my @userNamesFromDB = vars->{db}->listSetUsers(params->{set_id});
my @usersToAdd = array_minus(@{params->{assigned_users}},@userNamesFromDB);
my @usersToDelete = array_minus(@userNamesFromDB,@{params->{assigned_users}});
- my @test2 = grep{ not $_ ~~ @userNamesFromDB } @{params->{assigned_users}};
for my $user(@usersToAdd){
addUserSet($user,params->{set_id});
@@ -180,18 +176,21 @@ put '/courses/:course_id/sets/:set_id' => sub {
addUserProblems(params->{set_id},params->{problems},params->{assigned_users});
+ ## why is this here? it doesn't do anything.
if (scalar(@usersToDelete)>0){
debug "Deleting users to set " . params->{set_id};
debug join("; ", @usersToDelete);
}
+ my $setFromDB = vars->{db}->getGlobalSet(params->{set_id});
- my $returnSet = convertObjectToHash($set,\@boolean_set_props);
+ my $returnSet = convertObjectToHash($setFromDB,\@boolean_set_props);
$returnSet->{assigned_users} = params->{assigned_users};
$returnSet->{problems} = convertArrayOfObjectsToHash(\@globalProblems);
+ $returnSet->{_id} = params->{set_id};
return $returnSet;
@@ -495,14 +494,13 @@ put '/courses/:course_id/users/:user_id/sets/:set_id' => sub {
for my $key (@user_set_props) {
my $globalValue = $globalSet->{$key} || "";
- # debug $key . " : " . $globalValue . " : " . params->{$key};
- # check to see if the value differs from the global value. If so, set it.
- $userSet->{$key} = params->{$key}
- if ((defined(params->{$key}) && $globalValue ne params->{$key}) || $key eq "psvn" || $key eq "user_id");
+ # check to see if the value differs from the global value. If so, set it else delete it.
+ $userSet->{$key} = params->{$key} if defined(params->{$key});
+ delete $userSet->{$key} if $globalValue eq $userSet->{$key} && $key ne "set_id";
+
}
vars->{db}->putUserSet($userSet);
-
return convertObjectToHash(vars->{db}->getMergedSet(params->{user_id},params->{set_id}),\@boolean_set_props);
};
diff --git a/webwork3/lib/Routes/Settings.pm b/webwork3/lib/Routes/Settings.pm
index a70c031250..1516a08aaf 100644
--- a/webwork3/lib/Routes/Settings.pm
+++ b/webwork3/lib/Routes/Settings.pm
@@ -63,18 +63,20 @@ get '/courses/:course_id/settings/:setting_id' => sub {
put '/courses/:course_id/settings/:setting_id' => sub {
- debug session;
-
if(session->{permission} < 10){send_error($PERMISSION_ERROR,403)}
- debug "in PUT /course/:course_id/settings/:setting_id";
-
+ #debug "in PUT /course/:course_id/settings/:setting_id";
+
my $ConfigValues = getCourseSettingsWW2();
foreach my $oneConfig (@$ConfigValues) {
foreach my $hash (@$oneConfig) {
if (ref($hash)=~/HASH/){
if ($hash->{var} eq params->{setting_id}){
- $hash->{value} = params->{value};
+ if($hash->{type} eq 'boolean'){
+ $hash->{value} = params->{value} ? 1 : 0;
+ } else {
+ $hash->{value} = params->{value};
+ }
return writeConfigToFile(vars->{ce},$hash);
}
}
@@ -161,7 +163,6 @@ sub writeConfigToFile {
chomp $line;
if ($line =~ /^\$/) {
my ($var,$value) = ($line =~ /^\$(.*)\s+=\s+(.*);$/);
- debug $var;
if ($var eq $config->{var}){
$fileoutput .= writeLine($config->{var},$config->{value});
$varFound = 1;
@@ -192,6 +193,9 @@ sub writeConfigToFile {
if ($writeFileErrors){
return {error=>$writeFileErrors};
} else {
+ if($config->{type} eq 'boolean'){
+ $config->{value} = $config->{value} ? JSON::true : JSON::false;
+ }
return $config;
}
}
diff --git a/webwork3/lib/Utils/Convert.pm b/webwork3/lib/Utils/Convert.pm
index a9c0da6613..d0f64792fa 100644
--- a/webwork3/lib/Utils/Convert.pm
+++ b/webwork3/lib/Utils/Convert.pm
@@ -4,8 +4,9 @@
package Utils::Convert;
use base qw(Exporter);
use JSON;
+use Data::Dumper;
our @EXPORT = ();
-our @EXPORT_OK = qw(convertObjectToHash convertArrayOfObjectsToHash);
+our @EXPORT_OK = qw(convertObjectToHash convertArrayOfObjectsToHash convertBooleans);
## This converts an array of objects to an array of Hashes
@@ -38,4 +39,15 @@ sub convertObjectToHash {
return $s;
}
+sub convertBooleans {
+ my ($obj,$boolean_props) = @_;
+
+ for my $key (@{$boolean_props}){
+ $obj->{$key} = $obj->{$key} ? 1: 0;
+ }
+
+ return $obj;
+}
+
+
return 1;
\ No newline at end of file
diff --git a/webwork3/public/css/course-manager.css b/webwork3/public/css/course-manager.css
index 5b7d492aa9..3626e12a69 100644
--- a/webwork3/public/css/course-manager.css
+++ b/webwork3/public/css/course-manager.css
@@ -26,7 +26,7 @@ a#view-header i {margin-left:1ex;}
.set-not-visible {font-style: italic;}
.set-visible {font-weight: bold;}
-.set-reduced-credit {color: rgb(217,115,52);}
+.set-reduced-scoring {color: rgb(217,115,52);}
.assign-set-name {cursor: pointer;}
diff --git a/webwork3/public/css/webwork.css b/webwork3/public/css/webwork.css
index 6210f0e021..3239b318b3 100644
--- a/webwork3/public/css/webwork.css
+++ b/webwork3/public/css/webwork.css
@@ -12,6 +12,8 @@ body { /* needed for the navigation bars top and bottom*/
.sortable-placeholder {border: 1px solid black; background-color: lightyellow;}
+.ui-datepicker {z-index: 1200 !important;} /* To ensure that it floats above the nav bar */
+
/* a wwdate is generally an input and we want to make it look like a span */
.wwdate { width: auto; border: none;}
@@ -76,7 +78,7 @@ border-top: solid 1px rgb(220, 220, 220);}
.assign-open {background-color: lightgreen;}
.assign-due {background-color: red;}
-.assign-reduced-credit {background-color: rgb(255,128,0);}
+.assign-reduced-scoring {background-color: rgb(255,128,0);}
.assign-not-visible {background-color: darkgray;}
diff --git a/webwork3/public/js/apps/CourseManager/CourseManager.js b/webwork3/public/js/apps/CourseManager/CourseManager.js
index c00c49ac82..50b448f996 100644
--- a/webwork3/public/js/apps/CourseManager/CourseManager.js
+++ b/webwork3/public/js/apps/CourseManager/CourseManager.js
@@ -14,7 +14,7 @@ var CourseManager = WebPage.extend({
initialize: function(){
WebPage.prototype.initialize.apply(this,{el: this.el});
_.bindAll(this, 'render', 'setMessages',"showProblemSetDetails","openCloseSidePane","stopActing",
- "changeView","changeSidePane","loadData","checkData","saveState","logout"); // include all functions that need the this object
+ "changeView","changeSidePane","loadData","checkData","saveState","logout","setDates"); // include all functions that need the this object
var self = this;
this.render();
@@ -123,6 +123,11 @@ var CourseManager = WebPage.extend({
this.changeView("Calendar",{});
}
+ // The following is useful in many different views, so is defined here.
+ // It adjusts dates to ensure that they aren't illegal.
+
+ this.problemSets.on("change:due_date change:reduced_scoring_date change:open_date change:answer_date",this.setDates);
+
this.navigationBar.on({
"change-view": this.changeView,
"logout": this.logout,
@@ -303,8 +308,104 @@ var CourseManager = WebPage.extend({
date: moment.unix(_set.get("due_date")).format("YYYY-MM-DD")}));
self.assignmentDateList.add(new AssignmentDate({type: "answer", problemSet: _set,
date: moment.unix(_set.get("answer_date")).format("YYYY-MM-DD")}));
+ if(self.settings.getSettingValue("pg{ansEvalDefaults}{enableReducedScoring}")
+ && parseInt(_set.get("reduced_scoring_date"))>0) {
+ self.assignmentDateList.add(new AssignmentDate({type: "reduced-scoring", problemSet: _set,
+ date: moment.unix(_set.get("reduced_scoring_date")).format("YYYY-MM-DD")}) );
+ }
});
},
+
+ // This ensures that dates selected from date pickers through the interface resets the dates around it
+ // to ensure that are no date errors.
+
+ setDates: function(model){
+ var self = this;
+
+ if(_(model.changed).keys().length>1){
+ return;
+ }
+ // convert all of the dates to Moment objects.
+ var oldUnixDates = model.pick("answer_date","due_date","reduced_scoring_date","open_date")
+ var oldMomentDates = _(oldUnixDates).chain().pairs().map(function(date){ return [date[0],moment.unix(date[1])];}).object().value();
+ // make sure that the dates are in integer form.
+ oldUnixDates = _(oldMomentDates).chain().pairs().map(function(date) { return [date[0],date[1].unix()]}).object().value();
+ var newMomentDates = _(oldUnixDates).chain().pairs().map(function(date){ return [date[0],moment.unix(date[1])];}).object().value();
+
+ if(model.changed["due_date"]){
+ if(oldMomentDates.due_date.isBefore(oldMomentDates.open_date)){
+ newMomentDates.open_date = moment(oldMomentDates.due_date);
+ }
+ if(oldMomentDates.due_date.isBefore(oldMomentDates.reduced_scoring_date)){
+ var oldDueDate = moment(oldMomentDates.due_date);
+ newMomentDates.reduced_scoring_date = oldDueDate.subtract("minutes",
+ self.settings.getSettingValue("pg{ansEvalDefaults}{reducedScoringPeriod}"));
+ if(newMomentDates.open_date.isAfter(newMomentDates.reduced_scoring_date)){
+ newMomentDates.open_date = moment(newMomentDates.reduced_scoring_date);
+ }
+ }
+ if(oldMomentDates.answer_date.isBefore(oldMomentDates.due_date)){
+ newMomentDates.answer_date = moment(newMomentDates.due_date);
+ }
+ }
+
+ if(model.changed["open_date"]){
+ if(oldMomentDates.open_date.isAfter(oldMomentDates.reduced_scoring_date)){
+ newMomentDates.reduced_scoring_date = moment(oldMomentDates.open_date);
+
+ if(newMomentDates.reduced_scoring_date.isAfter(newMomentDates.due_date)){
+ var oldRSDate = moment(newMomentDates.reduced_scoring_date);
+ newMomentDates.due_date = oldRSDate.add("minutes",
+ self.settings.getSettingValue("pg{ansEvalDefaults}{reducedScoringPeriod}"));
+ }
+ }
+ if(oldMomentDates.answer_date.isBefore(newMomentDates.due_date)){
+ newMomentDates.answer_date = moment(newMomentDates.due_date);
+ }
+ }
+
+ if(model.changed["reduced_scoring_date"]){
+ if(oldMomentDates.reduced_scoring_date.isBefore(oldMomentDates.open_date)){
+ newMomentDates.open_date = moment(oldMomentDates.reduced_scoring_date);
+ }
+
+ if(oldMomentDates.reduced_scoring_date.isAfter(oldMomentDates.due_date)){
+ var oldRSDate = moment(oldMomentDates.reduced_scoring_date);
+ newMomentDates.due_date = oldRSDate.add("minutes",
+ self.settings.getSettingValue("pg{ansEvalDefaults}{reducedScoringPeriod}"));
+ }
+
+ if(newMomentDates.due_date.isAfter(oldMomentDates.answer_date)){
+ newMomentDates.answer_date = moment(newMomentDates.due_date);
+ }
+ }
+
+ if(model.changed["answer_date"]){
+
+ if(oldMomentDates.answer_date.isBefore(oldMomentDates.due_date)){
+ newMomentDates.due_date = moment(oldMomentDates.answer_date);
+ }
+ if(oldMomentDates.answer_date.isBefore(oldMomentDates.reduced_scoring_date)){
+ var newDueDate = moment(newMomentDates.due_date);
+ newMomentDates.reduced_scoring_date = newDueDate.subtract("minutes",
+ self.settings.getSettingValue("pg{ansEvalDefaults}{reducedScoringPeriod}"));
+ }
+ if(oldMomentDates.answer_date.isBefore(oldMomentDates.open_date)){
+ newMomentDates.open_date = moment(newMomentDates.reduced_scoring_date);
+ }
+
+ }
+
+
+ // convert the moments back to unix time
+ var newUnixDates = _(newMomentDates).chain().pairs().map(function(date) {
+ return [date[0],date[1].unix()]}).object().value();
+ if(! _.isEqual(oldUnixDates,newUnixDates)){
+
+ model.set(newUnixDates);
+ }
+ }
+
});
diff --git a/webwork3/public/js/apps/CourseManager/main-views/AssignmentCalendar.js b/webwork3/public/js/apps/CourseManager/main-views/AssignmentCalendar.js
index 2c51076a58..ca75fd7719 100644
--- a/webwork3/public/js/apps/CourseManager/main-views/AssignmentCalendar.js
+++ b/webwork3/public/js/apps/CourseManager/main-views/AssignmentCalendar.js
@@ -18,22 +18,44 @@ define(['backbone', 'underscore', 'moment','views/MainView', 'views/CalendarView
initialize: function (options) {
var self = this;
CalendarView.prototype.initialize.call(this,options);
- _.bindAll(this,"render","renderDay","update");
+ _.bindAll(this,"render","renderDay","update","showHideAssigns");
this.problemSets.on({sync: this.render});
+
+ this.model = new DateTypeModel();
+ this.model.on({change: this.showHideAssigns})
return this;
},
render: function (){
- this.constructor.__super__.render.apply(this);
+ CalendarView.prototype.render.apply(this);
this.update();
this.$(".assign").popover({html: true});
this.$(".assign").truncate({width: 100});
// set up the calendar to scroll correctly
this.$(".calendar-container").height($(window).height()-160);
+ $('.show-date-types input, .show-date-types label').click(function(e) {
+ e.stopPropagation();
+ });
+
+ // show/hide the desired date types
+
+ if(this.settings.getSettingValue("pg{ansEvalDefaults}{enableReducedScoring}")){
+ this.$(".assign-reduced-scoring").removeClass("hidden");
+ } else {
+ this.$(".assign-reduced-scoring").addClass("hidden");
+ }
+
MainView.prototype.render.apply(this);
+ this.stickit();
return this;
},
+ bindings: {
+ ".show-open-date": "open_date",
+ ".show-due-date": "due_date",
+ ".show-reduced-scoring-date": "reduced_scoring_date",
+ ".show-answer-date": "answer_date"
+ },
renderDay: function (day){
var self = this;
var assignments = this.assignmentDates.where({date: day.model.format("YYYY-MM-DD")});
@@ -74,6 +96,8 @@ define(['backbone', 'underscore', 'moment','views/MainView', 'views/CalendarView
self.setDate($(ui.draggable).data("setname"),$(this).data("date"),"due_date");
} else if ($(ui.draggable).hasClass("assign-answer")){
self.setDate($(ui.draggable).data("setname"),$(this).data("date"),"answer_date");
+ } else if ($(ui.draggable).hasClass("assign-reduced-scoring")){
+ self.setDate($(ui.draggable).data("setname"),$(this).data("date"),"reduced_scoring_date");
}
}
@@ -81,11 +105,21 @@ define(['backbone', 'underscore', 'moment','views/MainView', 'views/CalendarView
// The following allows an assignment date (due, open) to be dropped on the calendar
- this.$(".assign-due,.assign-open,.assign-answer").draggable({
+ this.$(".assign-due,.assign-open,.assign-answer,.assign-reduced-scoring").draggable({
revert: true,
start: function () {$(this).popover("destroy")}
});
},
+ showHideAssigns: function(model){
+ _(_(model.changed).keys()).each(function(key){
+ var type = key.split(/_date/)[0].replace("_","-");
+ if(model.changed[key]){
+ $(".assign.assign-"+type).removeClass("hidden");
+ } else {
+ $(".assign.assign-"+type).addClass("hidden");
+ }
+ })
+ },
setDate: function(_setName,_date,type){ // sets the date in the form YYYY-MM-DD
var problemSet = this.problemSets.findWhere({set_id: _setName.toString()});
if(type==="all") {
@@ -98,5 +132,14 @@ define(['backbone', 'underscore', 'moment','views/MainView', 'views/CalendarView
});
+ var DateTypeModel = Backbone.Model.extend({
+ defaults: {
+ answer_date: true,
+ due_date: true,
+ reduced_scoring_date: true,
+ open_date: true
+ }
+ });
+
return AssignmentCalendar;
});
diff --git a/webwork3/public/js/apps/CourseManager/main-views/ProblemSetDetailView.js b/webwork3/public/js/apps/CourseManager/main-views/ProblemSetDetailView.js
index eafa24cdec..5d32ee8669 100644
--- a/webwork3/public/js/apps/CourseManager/main-views/ProblemSetDetailView.js
+++ b/webwork3/public/js/apps/CourseManager/main-views/ProblemSetDetailView.js
@@ -13,7 +13,6 @@ define(['backbone','underscore','views/MainView','views/ProblemSetView','models/
UserSetList, config){
var ProblemSetDetailsView = MainView.extend({
className: "set-detail-view",
- tagName: "div",
messageTemplate: _.template($("#problem-sets-manager-messages-template").html()),
initialize: function (options) {
MainView.prototype.initialize.call(this,options);
@@ -28,8 +27,9 @@ define(['backbone','underscore','views/MainView','views/ProblemSetView','models/
problemSetView : new ProblemSetView({problemSet: this.problemSet, settings: this.settings,
messageTemplate: this.messageTemplate}),
usersAssignedView : new AssignUsersView({problemSet: this.problemSet, users: this.users}),
- propertiesView : new DetailsView({users: this.users, problemSet: this.problemSet}),
- customizeUserAssignView : new CustomizeUserAssignView({users: this.users, problemSet: this.problemSet}),
+ propertiesView : new DetailsView({users: this.users, problemSet: this.problemSet, settings: this.settings}),
+ customizeUserAssignView : new CustomizeUserAssignView({users: this.users, problemSet: this.problemSet,
+ eventDispatcher: this.eventDispatcher, settings: this.settings}),
unassignUsersView: new UnassignUserView({users:this.users})
};
@@ -172,37 +172,66 @@ define(['backbone','underscore','views/MainView','views/ProblemSetView','models/
var DetailsView = Backbone.View.extend({
initialize: function (options) {
- _.bindAll(this,'render','setProblemSet');
+ _.bindAll(this,'render','setProblemSet',"showHideReducedScoringDate");
this.users = options.users;
+ this.settings = options.settings;
+
},
render: function () {
this.$el.html($("#set-properties-tab-template").html());
if(this.model){
+ this.showHideReducedScoringDate();
this.stickit();
}
return this;
},
- events: {"click .assign-all-users": "assignAllUsers"},
+ events: {
+ "click .assign-all-users": "assignAllUsers",
+ //"change .reduced-scoring": "showHideReducedScoringDate"
+ },
assignAllUsers: function(){
this.model.set({assigned_users: this.users.pluck("user_id")});
},
setProblemSet: function(_set) {
var self = this;
this.model = _set;
+ this.model.on("change:enable_reduced_scoring",this.render);
return this;
},
- bindings: { ".set-name" : "set_id",
- ".open-date" : "open_date",
- ".due-date" : "due_date",
- ".answer-date": "answer_date",
- ".prob-set-visible": "visible",
- ".reduced-credit": "enable_reduced_scoring",
- ".users-assigned": {
- observe: "assigned_users",
- onGet: function(value, options){ return value.length + "/" +this.users.size();}
- }
+ bindings: {
+ ".set-name" : "set_id",
+ ".open-date" : "open_date",
+ ".due-date" : "due_date",
+ ".answer-date": "answer_date",
+ ".prob-set-visible": "visible",
+ ".reduced-scoring": "enable_reduced_scoring",
+ ".reduced-scoring-date": "reduced_scoring_date",
+ ".users-assigned": {
+ observe: "assigned_users",
+ onGet: function(value, options){ return value.length + "/" +this.users.size();}
+ }
+ },
+ showHideReducedScoringDate: function(){
+ if(this.settings.getSettingValue("pg{ansEvalDefaults}{enableReducedScoring}") &&
+ this.model.get("enable_reduced_scoring")) { // show reduced credit field
+ this.$(".reduced-scoring-date").closest("tr").removeClass("hidden");
+
+ // fill in a reduced_scoring_date if the field is empty or 0.
+ if(this.model.get("reduced_scoring_date")=="" || this.model.get("reduced_scoring_date")==0){
+ var rcDate = moment.unix(this.model.get("due_date")).subtract("minutes",
+ this.settings.getSettingValue("pg{ansEvalDefaults}{reducedScoringPeriod}"));
+ this.model.set({reduced_scoring_date: rcDate.unix()});
}
+ } else {
+ this.$(".reduced-scoring-date").closest("tr").addClass("hidden");
+ }
+ if(this.settings.getSettingValue("pg{ansEvalDefaults}{enableReducedScoring}")){
+ this.$(".reduced-scoring").closest("tr").removeClass("hidden")
+ } else {
+ this.$(".reduced-scoring").closest("tr").addClass("hidden")
+ }
+ }
});
@@ -315,34 +344,48 @@ define(['backbone','underscore','views/MainView','views/ProblemSetView','models/
var CustomizeUserAssignView = Backbone.View.extend({
initialize: function(options){
_.bindAll(this,"render","updateTable","saveChanges","filter","buildCollection","setProblemSet");
- this.model = this.model = options.problemSet ? new ProblemSet(options.problemSet.attributes): null;
- this.users = options.users;
- this.tableSetup();
-
+ // this.model is a clone of the parent ProblemSet. It is used to save properties for multiple students.
+
+ this.model = options.problemSet ? new ProblemSet(options.problemSet.attributes): null;
+ _.extend(this,_(options).pick("users","settings","eventDispatcher"));
},
render: function () {
var self = this;
+ var reducedScoring = this.settings.getSettingValue("pg{ansEvalDefaults}{enableReducedScoring}")
+ && this.problemSet.get("enable_reduced_scoring");
+ this.tableSetup({show_reduced_scoring: reducedScoring});
this.$el.html($("#loading-usersets-template").html());
+
if (this.collection.size()>0){
this.$el.html($("#customize-assignment-template").html());
(this.userSetTable = new CollectionTableView({columnInfo: this.cols, collection: this.collection,
paginator: {showPaginator: false}, tablename: ".users-table"}))
.render().$el.addClass("table table-bordered table-condensed");
this.$el.append(this.userSetTable.el);
+
+ // show/hide the bottom row reduced-scoring
+ if(this.settings.getSettingValue("pg{ansEvalDefaults}{enableReducedScoring}")){
+ this.$(".reduced-scoring-date,.reduced-scoring-header").removeClass("hidden")
+ } else {
+ this.$(".reduced-scoring-date,.reduced-scoring-header").addClass("hidden")
+ }
+
this.stickit();
} else {
this.userSetList.fetch({success: function () {self.buildCollection(); self.render();}});
}
},
- events: {"change .show-section,.show-recitation": "updateTable",
+ events: {
+ "change .show-section,.show-recitation": "updateTable",
"click .save-changes": "saveChanges",
"keyup .search-box": "filter",
"change th[data-class-name='select-user'] input": "selectAllUsers"
},
bindings: { "#customize-problem-set-controls .open-date" : "open_date",
"#customize-problem-set-controls .due-date": "due_date",
- "#customize-problem-set-controls .answer-date": "answer_date"
+ "#customize-problem-set-controls .answer-date": "answer_date",
+ "#customize-problem-set-controls .reduced-scoring-date": "reduced_scoring_date"
},
selectAllUsers: function(evt){
$("table.users-table input[type='checkbox']").prop("checked", $(evt.target).prop("checked"));
@@ -363,7 +406,7 @@ define(['backbone','underscore','views/MainView','views/ProblemSetView','models/
_($(".select-user input:checked").siblings(".user-id").map(function(i,v) {
return self.userSetList.findWhere({user_id: $(v).val()});
})).each(function(_model){
- _model.set(self.model.pick("open_date","due_date","answer_date"));
+ _model.set(self.model.pick("open_date","due_date","answer_date","reduced_scoring_date"));
});
},
updateTable: function (){
@@ -390,8 +433,10 @@ define(['backbone','underscore','views/MainView','views/ProblemSetView','models/
model.set(self.users.findWhere({user_id: model.get("user_id")}).pick("section","recitation"));
});
this.collection.on({change: function(model){
+ console.log(moment.unix(model.get("reduced_scoring_date")).format("MM-DD-YYYY"));
self.userSetList.findWhere({user_id: model.get("user_id")}).set(model.pick("open_date","due_date","answer_date")).save();
}});
+ this.setMessages();
return this;
},
@@ -425,6 +470,36 @@ define(['backbone','underscore','views/MainView','views/ProblemSetView','models/
this.cols.push({name: "Recitation", key: "recitation", classname: "recitation", editable: false,
datatype: "string"});
}
+ if(opts && opts.show_reduced_scoring){
+ this.cols.splice(3,0,{name: "Reduced Scoring Date", key: "reduced_scoring_date",
+ classname: ["reduced-scoring-date","edit-datetime"], editable: true,
+ datatype: "integer"});
+ }
+ },
+ messageTemplate: _.template($("#customize-users-messages-template").html()),
+ setMessages: function(){
+ var self = this;
+ this.userSetList.on({
+ change: function(_set){
+ _set.changingAttributes=_.pick(_set._previousAttributes,_.keys(_set.changed));
+ },
+ sync: function(_set){
+ _(_set.changingAttributes||{}).chain().keys().each(function(key){
+ switch(key){
+ default:
+ var _old = key.match(/date$/) ? moment.unix(_set.changingAttributes[key]).format("MM/DD/YYYY [at] hh:mmA")
+ : _set.changingAttributes[key];
+ var _new = key.match(/date$/) ? moment.unix(_set.get(key)).format("MM/DD/YYYY [at] hh:mmA") : _set.get(key);
+ self.eventDispatcher.trigger("add-message",{type: "success",
+ short: self.messageTemplate(
+ {type:"set_saved",opts:{set_id:_set.get("set_id"), user_id: _set.get("user_id")}}),
+ text: self.messageTemplate({type:"set_saved_details",opts:{setname:_set.get("set_id"),
+ key: key, user_id: _set.get("user_id"),oldValue: _old, newValue: _new}})});
+ }
+ });
+ }
+ })
+
}
});
diff --git a/webwork3/public/js/apps/CourseManager/main-views/ProblemSetsManager.js b/webwork3/public/js/apps/CourseManager/main-views/ProblemSetsManager.js
index a05e5753f9..4f860ca660 100644
--- a/webwork3/public/js/apps/CourseManager/main-views/ProblemSetsManager.js
+++ b/webwork3/public/js/apps/CourseManager/main-views/ProblemSetsManager.js
@@ -12,20 +12,23 @@ define(['backbone', 'underscore','views/MainView', 'views/CollectionTableView','
var ProblemSetsManager = MainView.extend({
initialize: function (options) {
MainView.prototype.initialize.call(this,options);
- _.bindAll(this, 'render','addProblemSet','updateTable','filterProblemSets','clearFilterText'); // include all functions that need the this object
+ _.bindAll(this, 'render','addProblemSet','updateTable','filterProblemSets','clearFilterText',
+ 'hideShowReducedScoring'); // include all functions that need the this object
var self = this;
this.problemSets = options.problemSets;
this.users = options.users;
this.tableSetup();
- this.headerInfo = { template: "#allSets-header",
+ this.headerInfo = {
+ template: "#allSets-header",
events: {"click .add-problem-set-button": function () {
self.addProblemSet();
}}
};
this.problemSets.on("add",this.updateTable);
this.problemSets.on("remove",this.updateTable);
+ this.problemSets.on("change:enable_reduced_scoring",this.hideShowReducedScoring);
this.setMessages();
},
events: {
@@ -33,6 +36,16 @@ define(['backbone', 'underscore','views/MainView', 'views/CollectionTableView','
'keyup input.filter-text' : 'filterProblemSets',
'click button.clear-filter-button': 'clearFilterText',
},
+ hideShowReducedScoring: function(model){
+ if(model.get("enable_reduced_scoring") && model.get("reduced_scoring_date")===""){
+ var rcDate = moment.unix(model.get("due_date")).subtract(this.settings.getSettingValue("pg{ansEvalDefaults}{reducedScoringPeriod}"))
+ model.set({reduced_scoring_date: rcDate.unix()})
+ }
+ if(this.problemSetTable){
+ this.problemSetTable.refreshTable();
+ }
+ this.$(".set-id a").truncate({width: 120});
+ },
render: function () {
this.$el.html($("#problem-set-manager-template").html());
this.problemSetTable = new CollectionTableView({columnInfo: this.cols, collection: this.problemSets,
@@ -41,6 +54,15 @@ define(['backbone', 'underscore','views/MainView', 'views/CollectionTableView','
this.$el.append(this.problemSetTable.el);
this.problemSets.trigger("hide-show-all-sets","hide");
this.$(".set-id a").truncate({width: 120});
+
+ // hide reduced credit items when not enabled.
+ if(this.settings.getSettingValue("pg{ansEvalDefaults}{enableReducedScoring}")){
+ this.$("td:has(select.enable-reduced-scoring),td.reduced-scoring-date,th.enable-reduced-scoring,th.reduced-scoring-date")
+ .removeClass("hidden");
+ } else {
+ this.$("td:has(select.enable-reduced-scoring),td.reduced-scoring-date,th.enable-reduced-scoring,th.reduced-scoring-date")
+ .addClass("hidden");
+ }
MainView.prototype.render.apply(this);
return this;
},
@@ -95,8 +117,7 @@ define(['backbone', 'underscore','views/MainView', 'views/CollectionTableView','
stickit_options: {update: function($el, val, model, options) {
$el.html("" + val + "");
$el.children("a").on("click",function() {
- var set = self.problemSets.findWhere({set_id: $(this).data("setname")})
- set.trigger("show",set);
+ self.eventDispatcher.trigger("show-problem-set",$(this).data("setname"));
});}
}
},
@@ -122,6 +143,8 @@ define(['backbone', 'underscore','views/MainView', 'views/CollectionTableView','
{name: "Visible", key: "visible", classname: ["is-visible","yes-no-boolean-select"], datatype: "boolean"},
{name: "Open Date", key: "open_date", classname: ["open-date","edit-datetime"],
editable: false, datatype: "integer", use_contenteditable: false},
+ {name: "Red. Scoring Date", key: "reduced_scoring_date", classname: ["reduced-scoring-date","edit-datetime"],
+ editable: false, datatype: "integer", use_contenteditable: false},
{name: "Due Date", key: "due_date", classname: ["due-date","edit-datetime"],
editable: false, datatype: "integer", use_contenteditable: false},
{name: "Answer Date", key: "answer_date", classname: ["answer-date","edit-datetime"],
@@ -159,22 +182,25 @@ define(['backbone', 'underscore','views/MainView', 'views/CollectionTableView','
}});
},
- "change:due_date change:open_date change:answer_date": function(_set){
+ "change:due_date change:open_date change:answer_date change:reduced_scoring_date": function(_set){
self.assignmentDates.chain().filter(function(assign) {
return assign.get("problemSet").get("set_id")===_set.get("set_id");})
.each(function(assign){
- assign.set("date",moment.unix(assign.get("problemSet").get(assign.get("type")+"_date"))
+ assign.set("date",moment.unix(assign.get("problemSet").get(assign.get("type").replace("-","_")+"_date"))
.format("YYYY-MM-DD"));
});
},
"change:problems": function(_set){
_set.save();
},
- "set_date_error": function(opt){
+ "set_date_error": function(_opts, model){
self.eventDispatcher.trigger("add-message",{type: "danger",
- short: self.messageTemplate({type: "date_set_error", opts: {set_id: opt.set_id}}),
- text: self.messageTemplate({type: opt.type, opts: {set_id: opt.set_id}})
+ short: self.messageTemplate({type: "date_set_error", opts: _opts}),
+ text: self.messageTemplate({type: "date_set_error", opts: _opts})
});
+ _(model.changed).chain().keys().each(function(key) {
+ model.set(key,model.changingAttributes[key]);
+ })
},
change: function(_set){
_set.changingAttributes=_.pick(_set._previousAttributes,_.keys(_set.changed));
diff --git a/webwork3/public/js/apps/CourseManager/option-panes/ProblemSetListView.js b/webwork3/public/js/apps/CourseManager/option-panes/ProblemSetListView.js
index 52df5d5870..4382c0d258 100644
--- a/webwork3/public/js/apps/CourseManager/option-panes/ProblemSetListView.js
+++ b/webwork3/public/js/apps/CourseManager/option-panes/ProblemSetListView.js
@@ -157,9 +157,9 @@ function(Backbone, _,ProblemSetList,ProblemSet,config,SidePane,AssignmentCalenda
":el": { observe: ["enable_reduced_scoring","visible"],
update: function($el, vals, model, options) {
if(vals[0]==0){
- $el.removeClass("set-reduced-credit");
+ $el.removeClass("set-reduced-scoring");
} else {
- $el.addClass("set-reduced-credit");
+ $el.addClass("set-reduced-scoring");
}
if(vals[1]==0){
$el.removeClass("set-visible");
diff --git a/webwork3/public/js/apps/config.js b/webwork3/public/js/apps/config.js
index a04ba61c0b..f9f7be08d5 100644
--- a/webwork3/public/js/apps/config.js
+++ b/webwork3/public/js/apps/config.js
@@ -145,8 +145,13 @@ define(['backbone','underscore','moment','backbone-validation','stickit','jquery
Backbone.Stickit.addHandler({
selector: '.edit-datetime',
update: function($el, val, model, options){
- var theDate = moment.unix(val);
- $el.html(_.template($("#edit-date-time-template").html(),{date: theDate.format("MM/DD/YYYY")}));
+ //var theDate = moment.unix(val);
+ if(options.observe==="reduced_scoring_date" && ! model.get("enable_reduced_scoring")){
+ $el.html("");
+ } else {
+ $el.html(_.template($("#edit-date-time-template").html(),{date: moment.unix(val).format("MM/DD/YYYY")}));
+ }
+
var setDate = function(evt){
var newDate = moment(evt.data.$el.children(".wwdate").val(),"MM/DD/YYYY");
var theDate = moment.unix(evt.data.model.get(evt.data.options.observe));
@@ -177,7 +182,7 @@ define(['backbone','underscore','moment','backbone-validation','stickit','jquery
timeIcon.parent().on("click",".open-time-editor", function() {
timeIcon.popover("toggle");
});
- $el.children(".wwdate").datepicker();
+ $el.children(".wwdate").datepicker({changeMonth: true, changeYear: true});
},
updateMethod: 'html'
});
diff --git a/webwork3/public/js/models/ProblemSet.js b/webwork3/public/js/models/ProblemSet.js
index 02a2b3cfcb..6800715d0f 100644
--- a/webwork3/public/js/models/ProblemSet.js
+++ b/webwork3/public/js/models/ProblemSet.js
@@ -15,8 +15,9 @@ define(['backbone', 'underscore','moment','./ProblemList','./Problem','config'],
open_date: "",
due_date: "",
answer_date: "",
- visible: 0,
- enable_reduced_scoring: 0,
+ reduced_scoring_date: "",
+ visible: false,
+ enable_reduced_scoring: false,
assignment_type: "",
attempts_per_version: -1,
time_interval: 0,
@@ -40,6 +41,7 @@ define(['backbone', 'underscore','moment','./ProblemList','./Problem','config'],
open_date: "checkDates",
due_date: "checkDates",
answer_date: "checkDates",
+ reduced_scoring_date: "checkDates",
set_id: {
setNameValidator: 1 // uses your custom validator
}
@@ -123,16 +125,37 @@ define(['backbone', 'underscore','moment','./ProblemList','./Problem','config'],
checkDates: function(value, attr, computedState){
var openDate = moment.unix(computedState.open_date)
, dueDate = moment.unix(computedState.due_date)
- , answerDate = moment.unix(computedState.answer_date);
+ , answerDate = moment.unix(computedState.answer_date)
+ , reducedScoringDate = moment.unix(computedState.reduced_scoring_date);
- if(openDate.isAfter(dueDate)&&attr==="open_date"){ // only throw this error once
- this.trigger("set_date_error",{set_id: this.get("set_id"), type: "openDate_after_dueDate"});
+ // the following prevents the rest of the code from checking more than once per validation.
+ // since there are 4 fields that use this method for validation, it gets called 4 times.
+ this.numChecks = this.numChecks? this.numChecks+=1: 1;
+ if(this.numChecks==4){ delete this.numChecks;}
+ if(this.numChecks>1) { return;}
+
+ if(openDate.isAfter(dueDate)){
+ this.trigger("set_date_error",{type: "date_error", set_id: this.get("set_id"), date1: "open date",
+ date2: "due date"},this);
return "open date is after due date";
}
- if (dueDate.isAfter(answerDate)&&attr==="answer_date"){// only throw this error once
- this.trigger("set_date_error",{set_id: this.get("set_id"), type: "dueDate_after_answerDate"});
+ if (dueDate.isAfter(answerDate)){
+ this.trigger("set_date_error",{type: "date_error", set_id: this.get("set_id"), date1: "due date",
+ date2: "answer date"},this);
return "due date is after answer date";
}
+ if(computedState.enable_reduced_scoring==1){
+ if(reducedScoringDate.isAfter(dueDate)){
+ this.trigger("set_date_error",{type: "date_error", set_id: this.get("set_id"),
+ date1: "reduced scoring date", date2: "due date"},this);
+ return "reduced scoring date is after due date";
+ }
+ if(openDate.isAfter(reducedScoringDate)){
+ this.trigger("set_date_error",{type: "date_error", set_id: this.get("set_id"), date1: "open date",
+ date2: "reduced scoring date"},this);
+ return "due date is after reduced scoring date";
+ }
+ }
}
});
diff --git a/webwork3/public/js/models/UserSet.js b/webwork3/public/js/models/UserSet.js
index 0bb6eec8be..c1ee86798b 100644
--- a/webwork3/public/js/models/UserSet.js
+++ b/webwork3/public/js/models/UserSet.js
@@ -19,8 +19,8 @@ define(['backbone', 'underscore','config','models/ProblemSet','models/UserProble
open_date: "",
due_date: "",
answer_date: "",
- visible: "",
- enable_reduced_scoring: "",
+ visible: false,
+ enable_reduced_scoring: false,
assignment_type: "",
description: "",
restricted_release: "",
diff --git a/webwork3/public/js/views/CollectionTableView.js b/webwork3/public/js/views/CollectionTableView.js
index 14033b5e1d..25a703c260 100644
--- a/webwork3/public/js/views/CollectionTableView.js
+++ b/webwork3/public/js/views/CollectionTableView.js
@@ -79,11 +79,15 @@ define(['backbone', 'underscore','stickit'], function(Backbone, _){
_(this.columnInfo).each(function (col){
var className = _.isArray(col.classname)?col.classname[0] : col.classname;
- if(col.colHeader){
- headRow.append("" + col.colHeader + " | ");
- } else {
- headRow.append("" + col.name + " | ");
- }
+ var th = $("").addClass(className)
+ .html(col.colHeader? col.colHeader: col.name + "");
+ headRow.append(th);
+ // if(col.colHeader){
+
+ // headRow.append(" | " + col.colHeader + " | ");
+ // } else {
+ // headRow.append("" + col.name + " | ");
+ // }
});
this.updateTable();
@@ -186,6 +190,9 @@ define(['backbone', 'underscore','stickit'], function(Backbone, _){
}
});
},
+ refreshTable: function (){
+ _(this.rowViews).each(function(row){row.refresh();});
+ },
getRowCount: function () {
return (this.showFiltered)? this.filteredCollection.length : this.collection.length;
},
@@ -292,6 +299,9 @@ define(['backbone', 'underscore','stickit'], function(Backbone, _){
this.stickit();
}
},
+ refresh: function(){
+ this.stickit();
+ },
events: {
"keypress td[contenteditable='true']": "returnHit"
},
diff --git a/webwork3/views/main/calendar.tt b/webwork3/views/main/calendar.tt
index 19edb256f8..70fcf181ed 100644
--- a/webwork3/views/main/calendar.tt
+++ b/webwork3/views/main/calendar.tt
@@ -1,14 +1,51 @@
+
+
+
\ No newline at end of file
diff --git a/webwork3/views/main/problem_set_manager.tt b/webwork3/views/main/problem_set_manager.tt
index 73b522e957..63de8a86cc 100644
--- a/webwork3/views/main/problem_set_manager.tt
+++ b/webwork3/views/main/problem_set_manager.tt
@@ -50,7 +50,8 @@ var messages = {
+ ". The open date must come before the due date";},
dueDate_after_answerDate: function(opt){return "Error saving problem set " + opt.set_id
+ ". The due date must come before the answer date";},
- date_set_error: function(opt) { return "There was an error setting the date for " + opt.set_id},
+ date_set_error: function(opt) { return "The " + opt.date1 + " comes after " + opt.date2 + " for set "
+ + opt.set_id + "."},
set_saved: function(opt){ return "Set " + opt.setname + " saved.";},
set_saved_details: function(opt){return "The value of " + opt.key + " in problem set "
+ opt.setname + " has changed from " + opt.oldValue + " to " + opt.newValue + ".";},