Index: openacs-4/packages/xowf/xowf.info =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xowf/xowf.info,v diff -u -r1.12.2.97 -r1.12.2.98 --- openacs-4/packages/xowf/xowf.info 27 Nov 2022 17:25:29 -0000 1.12.2.97 +++ openacs-4/packages/xowf/xowf.info 15 Dec 2022 19:28:20 -0000 1.12.2.98 @@ -10,15 +10,15 @@ t xowf - + Gustaf Neumann XoWiki Content Flow - an XoWiki based workflow system implementing state-based behavior of wiki pages and forms 2021-09-15 WU Vienna BSD-Style 2 - + Index: openacs-4/packages/xowf/catalog/xowf.de_DE.ISO-8859-1.xml =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xowf/catalog/xowf.de_DE.ISO-8859-1.xml,v diff -u -r1.2.2.83 -r1.2.2.84 --- openacs-4/packages/xowf/catalog/xowf.de_DE.ISO-8859-1.xml 28 Oct 2022 12:52:41 -0000 1.2.2.83 +++ openacs-4/packages/xowf/catalog/xowf.de_DE.ISO-8859-1.xml 15 Dec 2022 19:28:20 -0000 1.2.2.84 @@ -2,6 +2,7 @@ Erreichte Punkte + Erreichbare Punkte Ausschneiden und Einf�gen erlaubt Darf der Studierende in mehrzeiligen Textfeldern Ausschneiden und Einf�gen verwenden? Alternative @@ -45,6 +46,8 @@ Automatische Einsicht nicht m�glich. Automatische Einsicht m�glich. Zusammenfassung + Pr�fungsstatistik nach Teilnehmern + Pr�fungsstatistik nach Beispielen Zeitfenster f�r Pr�fung Optionales automatisches Freischalten/Schlie�en der Pr�fung. Auch wenn das Zeitfenster aktiviert ist, kann die Pr�fung manuell freigeschaltet/geschlossen werden. Beispiel @@ -54,6 +57,9 @@ Single-Choice-�bung Exportiere Ergebnisse Exportiere Ergebnisse und Kommentare pro Frage + Exportiere Punkte + Exportiere Noten + Exportiere Punkte und Noten Feedback Feedback richtig Feedback falsch @@ -169,6 +175,7 @@ Bitte beantworten Sie Punkt Punkte + Punkte und Noten Pool-Frage Fragenpool Fragentypen @@ -183,6 +190,7 @@ Detailangaben, welche Funktionen der Online-Beaufsichtigung genutzt werden sollen Aufnahmen speichern Speichere die Aufnahmen der Teilnehmer + Prozent Frage Fragenenstellungen Fragenauswahl Index: openacs-4/packages/xowf/catalog/xowf.en_US.ISO-8859-1.xml =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xowf/catalog/xowf.en_US.ISO-8859-1.xml,v diff -u -r1.2.2.89 -r1.2.2.90 --- openacs-4/packages/xowf/catalog/xowf.en_US.ISO-8859-1.xml 27 Nov 2022 17:25:29 -0000 1.2.2.89 +++ openacs-4/packages/xowf/catalog/xowf.en_US.ISO-8859-1.xml 15 Dec 2022 19:28:20 -0000 1.2.2.90 @@ -1,6 +1,7 @@ + Achievable Points Achieved Points Allow Cut and Paste Is the student allowed to use cut and paste in multiline text fields? @@ -53,6 +54,8 @@ Automated exam review not possible Automated exam review possible Summary + Exam Statistics per Participant + Exam Statistics per Question Exam Time Window Optional time window for automatically open/close exam. When these values are set, manual opening and closing of the exam is still possible. Exercise @@ -61,7 +64,10 @@ Open Text Exercise Single Choice Exercise Export Results - Export results and comments per question + Export Results and Comments per Question + Export Points + Export Grades + Export Points and Grades Feedback Feedback Correct Feedback Incorrect @@ -185,10 +191,12 @@ %achievedPoints% (rounded %achievedPointsRounded%) of possible %totalPoints% points, %percentage%%, grade: %grade% Participant Participants + Percentage participants answered this question Please answer Point Points + Points and Grades Pool Question Pool Folder Item Types Index: openacs-4/packages/xowf/lib/inclass-exam.wf =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xowf/lib/inclass-exam.wf,v diff -u -r1.1.2.103 -r1.1.2.104 --- openacs-4/packages/xowf/lib/inclass-exam.wf 21 Nov 2022 19:46:19 -0000 1.1.2.103 +++ openacs-4/packages/xowf/lib/inclass-exam.wf 15 Dec 2022 19:28:20 -0000 1.1.2.104 @@ -43,17 +43,17 @@ # The policy has to allow the following methods on FormPages: # # - "answer" (for students), -# - "proctor" (for students), -# - "view-my-exam" (for students), +# - "delete" (for lecturers), # - "edit" (for students), +# - "exam-results" (for lecturers), # - "poll" (for lecturers), # - "print-answers" (for lecturers), -# - "print-answer-table" (for lecturers), # - "print-participants" (for lecturers), +# - "proctor" (for students), +# - "qrcode" (for lecturers) # - "question-summary" (for lecturers), -# - "delete" (for lecturers), # - "toggle-publish-status" (for lecturers), -# - "qrcode" (for lecturers) +# - "view-my-exam" (for students), # # Gustaf Neumann, Feb 2012-2021 ######################################################################## @@ -264,8 +264,10 @@ # } - set answers [$obj AM get_answer_attributes $wf] - + set answers [:AM get_answer_attributes $wf] + set results [:AM get_exam_results -obj $obj results] + set autograded [dict get $combined_form_info autograde] + set grading_scheme_name [$obj property grading] # # Per default, the entries are disabled. When there are answers, # these will be enabled. @@ -275,15 +277,23 @@ listing {obj $wf m list label #xowf.online-exam-exam_instances# icon list} participants {obj $obj m print-participants label #xowf.Participants# icon user} protocol {obj $obj m print-answers label #xowf.online-exam-protocol# icon list-alt} - results {obj $obj m print-answer-table label #xowf.online-exam-results-table# icon th-list} + grades {obj $obj m exam-results label #xowf.Points_and_grades# icon graph-up-arrow} }] if {![acs_user::site_wide_admin_p -user_id [::xo::cc user_id]]} { dict unset md listing } - dict unset md results ;# deactivate results for now - #ns_log notice ALL=$text + ns_log notice "ANSWERS grading_scheme_name $grading_scheme_name $answers resultsNr [llength $results], autograde [dict get $combined_form_info autograde]" + # + # We assume here that when we have results, we have also some points. + # + if {[llength $results] == 0} { + dict unset md grades + } elseif {$grading_scheme_name in {"" "none"}} { + dict set grades label "Points" + } + #ns_log notice ALL=$text set menu "
    \n" dict for {name d} $md { set href [[dict get $d obj] pretty_link -query m=[dict get $d m]] @@ -455,45 +465,6 @@ } ######################################################################## - # web-callable method "print-answer-table" - # - # Print the answers in a tabular form. - # - :proc www-print-answer-table {} { - set HTML "" - set withAnswerColumns [${:package_id} query_parameter with_answers:boolean 0] - - set wf [:AM get_answer_wf [self]] - if {$wf ne ""} { - #set form_info [:QM combined_question_form -with_numbers [self]] - - set items [:AM get_wf_instances $wf] - set items2 [$items deep_copy] - foreach i [$items2 children] { - $i set online-exam-userName [acs_user::get_element -user_id [$i creation_user] -element username] - $i set online-exam-fullName [::xo::get_user_name [$i creation_user]] - } - set HTML [:AM results_table \ - -package_id ${:package_id} \ - -items $items2 \ - -state * \ - -with_answers $withAnswerColumns \ - [self]] - $items2 destroy - } - if {$HTML eq ""} { - set HTML "#xowiki.no_data#" - } else { - set HTML "

    #xowf.online-exam-results-table#

    $HTML" - } - set return_url [[$wf package_id] query_parameter local_return_url:localurl [:pretty_link]] - append HTML "

    #xowiki.back#

    \n" - - xo::Page requireCSS /resources/xowf/test-item.css - :www-view $HTML - } - - ######################################################################## # web-callable method "print-participants" # # Print participants in a tabular form. @@ -554,18 +525,144 @@ ######################################################################## # web-callable method "exam-results" # - # export results as CSV table + # Print results (grades, statistics) for a lecturer. # :proc www-exam-results {} { - #set manual_gradings [:property manual_gradings] - set manual_gradings [:AM get_exam_results -obj [self] manual_gradings] - #set results [:property __results] + set form_info [:QM combined_question_form [self]] + set autograde [dict get $form_info autograde] + set orderby [:query_parameter orderby:token "participant,desc"] + set format [:query_parameter format:alpha ""] + set perQuestion [:query_parameter per-question:boolean 0] + + set grading_scheme_name [:property grading] + if {$grading_scheme_name eq ""} { + set grading_scheme_name none + } + set gradingScheme [:AM grading_scheme -examWf [self] -grading $grading_scheme_name] + set withGrades [expr {$gradingScheme ne "::xowf::test_item::grading::none"}] + + set return_url [:query_parameter local_return_url:localurl [:pretty_link]] + set backButtonHTML "

    #xowiki.back#

    \n" + set results [:AM get_exam_results -obj [self] results] - :AM results_export -reply -manual_gradings $manual_gradings $results - ad_script_abort + if {[llength $results] eq 0} { + # + # Actually, the link leading to this result should not be + # active. The message is just for cases of URL hacking. + # + return [:www-view "

    No submission results available.$backButtonHTML"] + } + set manual_gradings [:AM get_exam_results -obj [self] manual_gradings] + + if {$format eq "csv"} { + return [:AM exam_results \ + -format csv \ + -reply \ + -orderby $orderby \ + -only_grades [:query_parameter onlygrades:boolean true] \ + -gradingScheme [expr {$perQuestion ? "" : $gradingScheme}] \ + -manual_gradings $manual_gradings \ + $results] + + #:AM exam_results -reply -manual_gradings $manual_gradings $results + + } + + set statistics [:AM get_exam_results -obj [self] statistics] + + # + # We have to following options: + # - perParticipant with grades + # - perParticipant without grades + # - perQuestion (always without grades, since this includes as well the statistics per alternative) + # + set HTML "" + if {0} { + set HTML [subst { +

    +        autograde $autograde
    +        manual_gradings $manual_gradings
    +        results $results
    +        statistics $statistics
    +      }]
    +      append HTML \n\nper_question\n[:AM exam_results -manual_gradings $manual_gradings $results]
    +      append HTML \nper_student\n[:AM exam_results -gradingScheme $gradingScheme \
    +                                      -manual_gradings $manual_gradings $results]
    +      append HTML 
    + } + if {$perQuestion} { + append HTML \ + "

    #xowf.exam_statistics_question#

    \n" \ + [:AM exam_results -format html \ + -manual_gradings $manual_gradings \ + $results] + set exportQuestionResultsURL [ad_return_url {{format csv} {onlygrades 0}}] + set perParticipantURL [ns_conn url]?[::xo::update_query [ns_conn query] per-question 0] + set buttonsHTML [subst {

    +


    + #xowf.export_results_title# + + #xowf.exam_statistics_participant#

    + }] + } else { + append HTML \ + "

    #xowf.exam_statistics_participant#

    " \ + "

    #xowf.Grading-Scheme#: [$gradingScheme cget -title]\n" \ + [:AM exam_results -format html \ + -orderby $orderby \ + -gradingScheme $gradingScheme \ + -manual_gradings $manual_gradings \ + $results] + set exportPointGradesURL [ad_return_url {{format csv} {onlygrades 0}}] + + if {$withGrades} { + # + # Only grades as table + # + #append HTML [:AM exam_results -format html \ + # -orderby $orderby \ + # -only_grades true \ + # -gradingScheme $gradingScheme \ + # -manual_gradings $manual_gradings \ + # $results] + append HTML [:AM exam_results -format chart \ + -orderby $orderby \ + -only_grades true \ + -gradingScheme $gradingScheme \ + -manual_gradings $manual_gradings \ + $results] + set exportGradesURL [ad_return_url {{format csv}}] + set buttonsHTML [subst { +


    + #xowf.export_grades_title# + + #xowf.export_points_and_grades_title# + }] + } else { + set buttonsHTML [subst { + + #xowf.export_points_title# + }] + } + set perQuestionURL [ns_conn url]?[::xo::update_query [ns_conn query] per-question 1] + append buttonsHTML [subst { + + #xowf.exam_statistics_question#

    + }] + } + + if {$HTML eq ""} { + set HTML "#xowiki.no_data#" + } else { + append HTML $buttonsHTML + } + append HTML $backButtonHTML + + :www-view $HTML } + ######################################################################## # web-callable method "print-answers" # @@ -610,8 +707,6 @@ } } - - ######################################################################## # web-callable method "answer" # @@ -776,7 +871,8 @@ :proc www-blank-inputs {} { # # Analyze the student submissions an find situations, where input - # is "cleared" between revisions. + # is "cleared" between revisions. This method is primarily for + # debugging purposes. # template::head::add_link -rel stylesheet -href /resources/xowf/test-item.css set HTML [:AM render_answers_with_edit_history [self]] @@ -881,25 +977,25 @@ set last_instance_attributes ${:instance_attributes} set field_names_with_child_components [lmap f [::xowiki::formfield::child_components $form_fields] {$f name}] #ns_log notice "\nORIG $field_names \NEW $field_names_with_child_components" - + lassign [:get_form_data -field_names $field_names_with_child_components $form_fields] validation_errors category_ids if {$validation_errors == 0} { if {$last_instance_attributes eq ${:instance_attributes}} { ns_log notice "UPDATE CONFIG ... nothing has changed" } else { ns_log notice "UPDATE CONFIG ... no validation_errors -> SAVE" - + :update_attribute_from_slot [:find_slot instance_attributes] ${:instance_attributes} - + if {[dict exists $last_instance_attributes time_window]} { set old_time_window [dict get $last_instance_attributes time_window] - set new_time_window [dict get ${:instance_attributes} time_window] + set new_time_window [dict get ${:instance_attributes} time_window] if {$old_time_window ne $new_time_window} { ns_log notice "UPDATE CONFIG time_window $new_time_window" :AM time_window_setup [self] -time_window $new_time_window ns_log notice "UPDATE CONFIG time_window $new_time_window DONE" } - } + } } ns_return 200 text/plain OK } else { Index: openacs-4/packages/xowf/tcl/grading-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xowf/tcl/grading-procs.tcl,v diff -u -r1.1.2.3 -r1.1.2.4 --- openacs-4/packages/xowf/tcl/grading-procs.tcl 12 Sep 2022 14:18:12 -0000 1.1.2.3 +++ openacs-4/packages/xowf/tcl/grading-procs.tcl 15 Dec 2022 19:28:21 -0000 1.1.2.4 @@ -86,7 +86,7 @@ return $grade } - :method complete_dict {achieved_points} { + :public method grading_dict {achieved_points} { # Important dict members of "achieved_points": # - achievedPoints: points that the student has achieved in her exam @@ -115,9 +115,9 @@ } { set achievablePoints 0 set achievedPoints 0 - #ns_log notice "RECALC in complete_dict " + #ns_log notice "RECALC in grading_dict " foreach detail [dict get $achieved_points details] { - #ns_log notice "RECALC in complete_dict '$detail'" + #ns_log notice "RECALC in grading_dict '$detail'" set achievedPoints [expr {$achievedPoints + [dict get $detail achieved]}] set achievablePoints [expr {$achievablePoints + [dict get $detail achievable]}] } @@ -157,7 +157,7 @@ # Return a dict containing the members "panel" and "csv" # depending on the type of rounding options # - set achieved_points [:complete_dict $achieved_points] + set achieved_points [:grading_dict $achieved_points] set grade [:grade -achieved_points $achieved_points] dict with achieved_points { return [list panel [_ xowf.panel_[namespace tail [:info class]]] csv [subst ${:csv}]] @@ -179,7 +179,7 @@ # Return a numeric grade for an exam submission based on rounded # points. On invalid data, return 0. # - set achieved_points [:complete_dict $achieved_points] + set achieved_points [:grading_dict $achieved_points] dict with achieved_points { return [:calc_grade -points $achievedPointsRounded -achievable_points $totalPoints] } @@ -200,7 +200,7 @@ # Return a numeric grade for an exam submission based on rounded # percentage. On invalid data, return 0. # - set achieved_points [:complete_dict $achieved_points] + set achieved_points [:grading_dict $achieved_points] if {[dict exists $achieved_points achievedPoints]} { dict with achieved_points { return [:calc_grade -percentage $percentageRounded] @@ -224,7 +224,7 @@ # special rounding (2 digits). On invalid data, return 0. # if {[dict exists $achieved_points achievedPoints]} { - set achieved_points [:complete_dict $achieved_points] + set achieved_points [:grading_dict $achieved_points] dict with achieved_points { return [:calc_grade -percentage $percentage] } Index: openacs-4/packages/xowf/tcl/test-item-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xowf/tcl/test-item-procs.tcl,v diff -u -r1.7.2.260 -r1.7.2.261 --- openacs-4/packages/xowf/tcl/test-item-procs.tcl 6 Dec 2022 12:43:39 -0000 1.7.2.260 +++ openacs-4/packages/xowf/tcl/test-item-procs.tcl 15 Dec 2022 19:28:21 -0000 1.7.2.261 @@ -1730,8 +1730,9 @@ # # - marked_results # - answers_panel - # - results_table + # - exam_results # - grading_table + # - grading_scheme # - grade # - participants_table # @@ -3862,10 +3863,10 @@ # Class: Answer_manager # Method: grading_scheme #---------------------------------------------------------------------- - :method grading_scheme { + :public method grading_scheme { {-examWf:object,required} {-grading:token,0..n ""} - {-total_points} + {-total_points 100} } { # # Return the grading scheme object based on the provided short @@ -3882,6 +3883,10 @@ # # @return fully qualified grading scheme object # + + # + # When not grading is provided, this muse be a legacy question. + # if {$grading eq ""} { #set grading [expr {$total_points < 40 ? "round-none" : "round-points"}] set grading "none" @@ -3893,6 +3898,8 @@ # # Maybe we have to load this grading scheme... # + #ns_log notice "grading_scheme_name load loaded yet: '$grading'" + #::xo::show_stack ::xowf::test_item::grading::load_grading_schemes \ -package_id [$examWf package_id] \ -parent_id [$examWf parent_id] @@ -4125,7 +4132,7 @@ #set manual_gradings [$examWf property manual_gradings] #set manual_gradings [:get_exam_results -obj $examWf manual_gradings] #append HTML
    $manual_gradings
    - #append HTML
    [:results_export -manual_gradings $manual_gradings $results]
    + #append HTML
    [:exam_results -manual_gradings $manual_gradings $results]
    } if {$create_zip_file} { @@ -4283,18 +4290,162 @@ } } + :method "result_table per_question" { + {-manual_gradings "" } + results_dict + } { + set table [::xowiki::TableWidget new \ + -name results \ + -columns { + Field create participant -label #xowf.participant# \ + -orderby participant + Field create question -label #xowf.question# + Field create achieved -label #xowf.Achieved_points# \ + -orderby achieved -html {align right} + Field create achievable -label #xowf.Achievable_points# \ + -orderby achievable -html {align right} + Field create comment -label #xowf.feedback# + }] + foreach user_id [dict keys $results_dict] { + set manual_grading [:dict_value $manual_gradings $user_id] + set participant [acs_user::get_element -user_id $user_id -element username] + foreach qn [dict keys [dict get $results_dict $user_id]] { + set achievable [dict get $results_dict $user_id $qn achievable] + set achieved [dict get $results_dict $user_id $qn achieved] + $table add \ + -participant $participant \ + -question [string trimright $qn _] \ + -achievable $achievable \ + -achieved [format %.2f $achieved] \ + -comment [:dict_value [:dict_value $manual_grading $qn] comment] + } + } + return $table + } + + :method "result_table per_participant" { + {-manual_gradings ""} + {-gradingScheme} + {-only_grades:boolean false} + results_dict + } { + ns_log notice "per_participant gradingScheme $gradingScheme" + # + # In case "only_grades" is specified, hide field "achieved". + # + set fieldType [expr {$only_grades ? "HiddenField" : "Field"}] + set fieldTypeGrade [expr {$gradingScheme eq "::xowf::test_item::grading::none" + ? "HiddenField" + : "Field"}] + set grade_dict {} + set table \ + [::xowiki::TableWidget new \ + -name results \ + -columns [subst { + Field create participant -label #xowf.participant# \ + -orderby participant + $fieldType create achieved -label #xowf.Achieved_points# \ + -orderby achieved -html {align right} + HiddenField create achievable -label #xowf.Achievable_points# \ + -orderby achievable -html {align right} + $fieldType create percentage -label #xowf.Percentage# \ + -orderby percentage -html {align right} + $fieldTypeGrade create grade -label #xowf.Grade# \ + -orderby grade -html {align right} + }]] + #ns_log notice "We have in results_dict the following users: [dict keys $results_dict]" + foreach {user_id properties} $results_dict { + if {[llength $properties] == 0} { + # + # The user has not seen any exercises, probably in "initial" + # state, ignore it. + # + continue + } + set manual_grading [:dict_value $manual_gradings $user_id] + set achievedPoints 0.0 + set achievablePoints 0.0 + set participant [acs_user::get_element -user_id $user_id -element username] + foreach qn [dict keys [dict get $results_dict $user_id]] { + set achievable [dict get $results_dict $user_id $qn achievable] + # + # Respect manual_grading, since these are eagerly updated + # via exam protocol. + # + set achieved [:dict_value [:dict_value $manual_grading $qn] achieved] + if {$achieved eq ""} { + set achieved [dict get $results_dict $user_id $qn achieved] + } + + # + # When a participant has not done yet this exercise, the + # value might be empty. + # + if {$achieved eq ""} { + set achieved 0 + } + set achievedPoints [expr {$achievedPoints + $achieved}] + set achievablePoints [expr {$achievablePoints + $achievable}] + } + set gradingDict [$gradingScheme grading_dict [list achievedPoints $achievedPoints \ + achievablePoints $achievablePoints \ + totalPoints $achievablePoints]] + #ns_log notice "COMPLETED DICT $gradingDict" + set grade [$gradingScheme grade -achieved_points $gradingDict] + dict incr grade_dict $grade + + set l [::xo::Table::Line new] + $table add \ + -participant $participant \ + -achievable $achievablePoints \ + -achieved [dict get $gradingDict achievedPoints] \ + -percentage [dict get $gradingDict percentageRounded] \ + -grade $grade + + } + $table set __grade_dict $grade_dict + return $table + } + #---------------------------------------------------------------------- # Class: Answer_manager - # Method: results_export + # Method: exam_results #---------------------------------------------------------------------- - :public method results_export { + :public method exam_results { {-manual_gradings "" } + {-gradingScheme ""} + {-only_grades:boolean false} {-reply:switch false} + {-format csv} + {-orderby "participant,desc"} results_dict } { # - # Exports results as csv + # Return results either as HTML table, as HTML chart or as + # csv. When "reply" is set. the result is returned directly to + # the browser (for downloading). # + # When "gradingScheme" is empty, this method returns the + # following fields: + # + # participant, question, achieved_points, achievable points, comment + # + # When the "gradingScheme" is specified the results are + # per-participant. In this cases, when the "gradingScheme" is + # "....::none", the fields are + # + # participant, achieved, percentage + # + # otherwise the grade and rounding of achieved points and + # percentage are exported based on the rules of the grading + # scheme. + # + # participant, achieved, percentage, grade + # + # When additionally "only_grades" is specified, just participant + # and grad are returned/exported. + # + # @param gradingScheme needed for reporting grades, can be empty # @param reply when false, csv will be returned as text, when # true, it will be returned as response to the # browser. @@ -4303,34 +4454,43 @@ # # @return csv as value or as response to the client # - set t [::xo::Table new -volatile \ - -name results \ - -columns { - Field create participant -label participant - Field create query_name -label query_name - Field create achieved -label achieved - Field create achievable -label achievable - Field create comment -label comment - }] - foreach user_id [dict keys $results_dict] { - set manual_grading [:dict_value $manual_gradings $user_id] - foreach qn [dict keys [dict get $results_dict $user_id]] { - set l [::xo::Table::Line new] - $t add \ - -participant [acs_user::get_element \ - -user_id $user_id \ - -element username] \ - -query_name [string trimright $qn _] \ - -achievable [dict get $results_dict $user_id $qn achievable] \ - -achieved [dict get $results_dict $user_id $qn achieved] \ - -comment [:dict_value [:dict_value $manual_grading $qn] comment] - } + set result "" + if {$gradingScheme eq ""} { + set t [:result_table per_question \ + -manual_gradings $manual_gradings \ + $results_dict] + } else { + set t [:result_table per_participant \ + -gradingScheme $gradingScheme \ + -only_grades $only_grades \ + -manual_gradings $manual_gradings \ + $results_dict] } + + lassign [split $orderby ,] att order + + $t orderby \ + -order [expr {$order eq "asc" ? "increasing" : "decreasing"}] \ + -type [ad_decode $att achieved real achievable real grade integer dictionary] \ + $att + if {$reply} { - $t write_csv + switch $format { + html { + ns_return 200 "text/html; charset=utf-8" [$t asHTML] + ad_script_abort + } + default {set result [$t write_csv]} + } } else { - $t format_csv + switch $format { + chart {set result [:grading_table [$t set __grade_dict]]} + html {set result [$t asHTML]} + default {set result [$t format_csv]} + } } + $t destroy + return $result } #---------------------------------------------------------------------- @@ -4348,7 +4508,8 @@ "\n" set nrGrades 0 foreach v [dict values $grade_dict] { incr nrGrades $v} - foreach k [lsort [dict keys $grade_dict]] { + set grades [lsort [dict keys $grade_dict]] + foreach k $grades { set count [dict get $grade_dict $k] set countPercentage [format %.2f [expr {$count *100.0 / $nrGrades}]] append gradingTable \ @@ -4358,7 +4519,35 @@ style="width:$countPercentage%">$countPercentage%\n } - append gradingTable "\n
    $csv
    \n" + append gradingTable "\n" + if {$csv ne "" } { + append gradingTable "
    $csv
    \n" + } + + if {[template::head::can_resolve_urn urn:ad:js:highcharts]} { + # + # The highcharts package is available + # + template::add_body_script -src urn:ad:js:highcharts + set graphID pie-[incr ::__xotcl_highcharts_pie] + append gradingTable "
    \n" + set data "" + foreach k $grades { + set count [dict get $grade_dict $k] + set countPercentage [format %.2f [expr {$count *100.0 / $nrGrades}]] + lappend data [subst {{name:'$k', y: $countPercentage}}] + } + set gradeLabel [_ xowf.Grade] + template::add_body_script -script [subst [ns_trim { + Highcharts.chart('$graphID', { + chart: {type: 'pie'}, + plotOptions: {pie: {size: 200}, series: {dataLabels: {enabled: true, format: '$gradeLabel {point.name}: {point.y:.1f}%'} }}, + title: {text: ''}, + credits: {enabled: true }, + series: \[{name: 'Percentage', data: \[ [join $data ,] \]}\] + }); + }]] + } return $gradingTable } @@ -4377,7 +4566,8 @@ } { # # Render the results in format of a table and return HTML. - # Currently deactivated. + # Currently mostly deactivated (but potentially called by + # online-exam.wf and topic-assignment.wf). # #set form_info [:combined_question_form -with_numbers $wf] @@ -6873,7 +7063,8 @@ # set results [:AM get_exam_results -obj $obj results] if {$results ne ""} { - set href [$obj pretty_link -query m=exam-results] + #https://localhost:8443/xowf/online-exam/inclass-exam1?per-question=1&m=print-statistics&format=csv&onlygrades=0 + set href [$obj pretty_link -query m=exam-results&format=csv&per-question=1] set results_summary [subst {

    #xowf.export_results#: @@ -7592,7 +7783,7 @@ # activities. # # - # Policy for creating and publishing of exams. + # Policy for lecturers (creating and publishing of exams) # test-item-policy-publish contains { Class create FormPage -array set require_permission {