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.283 -r1.7.2.284
--- openacs-4/packages/xowf/tcl/test-item-procs.tcl 4 Oct 2023 13:22:21 -0000 1.7.2.283
+++ openacs-4/packages/xowf/tcl/test-item-procs.tcl 24 Nov 2023 13:49:48 -0000 1.7.2.284
@@ -1535,6 +1535,80 @@
}
return 1
}
+
+ #----------------------------------------------------------------------
+ # Class: AssessmentInterface
+ # Method: render_export_links
+ #----------------------------------------------------------------------
+ :method export_links {
+ {-examWf:object}
+ {-filter_form_ids:integer,0..n ""}
+ {-b_aggregate:boolean false}
+ } {
+ #
+ # Creates export links and markup
+ #
+ # @return HTML
+ #
+
+ set export_formats {
+ cvs
+ }
+ if {[::namespace which ::ooxml::xl_write] ne ""} {
+ lappend export_formats xls
+ }
+
+ #case: specific question
+ if {$filter_form_ids ne "" && [string is integer $filter_form_ids]} {
+ #check if this id has entries
+ set results [::xowf::test_item::answer_manager get_exam_results -obj $examWf results]
+ set fos_exists 0
+ foreach {user answers} $results {
+ foreach {qn attributes} $answers {
+ if {[dict exists $attributes question_id] &&
+ [dict get $attributes question_id] eq $filter_form_ids} {
+ set fos_exists 1
+ }
+ }
+ }
+ if {!$fos_exists} {return}
+ foreach format $export_formats {
+ set href [$examWf pretty_link -query [export_vars {
+ {m exam-results} {onlygrades 0} {format $format} {per-question 1} {fos $filter_form_ids}
+ }]]
+ append HTML [subst {
+
#xowf.export_results_title#:
+ [string toupper $format]
+ }]
+ }
+ return [template::adp_parse_tags $HTML]
+ }
+ #case: aggregated view
+ if {$b_aggregate} {
+ foreach format $export_formats {
+ set href [$examWf pretty_link -query [export_vars {
+ {m exam-results} {onlygrades 0} {format $format} {per-question 0}
+ }]]
+ append HTML [subst {
+
#xowf.export_results#:
+ [string toupper $format]
+ }]
+ }
+ return [template::adp_parse_tags $HTML]
+ }
+ #default case: all questions
+ foreach format $export_formats {
+ set href_export [$examWf pretty_link -query [export_vars {
+ {m exam-results} {onlygrades 0} {format $format} {per-question 1}
+ }]]
+ append HTML [subst {
+
#xowf.export_results_title#:
+ [string toupper $format]
+
}]
+ }
+ return [template::adp_parse_tags $HTML]
+ }
+
}
}
@@ -3260,6 +3334,65 @@
#----------------------------------------------------------------------
# Class: Answer_manager
+ # Method: render_filter_bar
+ #----------------------------------------------------------------------
+ :method render_filter_bar {
+ {-examWf:object}
+ {-filter_form_ids:integer,0..n ""}
+ {-revision_id:integer,0..1 ""}
+ {-filter_submission_id:integer,0..1 ""}
+ {-orderby:token "online-exam-userName"}
+ } {
+ #
+ # Render a bar to filter, sort and export exam submissions.
+ #
+ # @return HTML
+ #
+ template::add_event_listener \
+ -id search-question \
+ -event submit \
+ -preventdefault=true \
+ -script "handleSearch();"
+
+ template::add_event_listener \
+ -id search-content \
+ -event change \
+ -preventdefault=true \
+ -script "handleSearch();"
+
+ template::head::add_javascript -order 100 -src "/resources/xowf/inclass-exam.js"
+
+ set HTML [subst {
+
+
+ [template::collect_body_scripts]
+ }]
+
+ set sort_baseurl [$examWf pretty_link]?m=print-answers&fos=$filter_form_ids&rid=$revision_id&id=$filter_submission_id
+
+ append HTML [subst {
+
+ }]
+ append HTML [:export_links -examWf $examWf -filter_form_ids $filter_form_ids -b_aggregate true]
+
+ return $HTML
+ }
+
+ #----------------------------------------------------------------------
+ # Class: Answer_manager
# Method: render_full_submission_form
#----------------------------------------------------------------------
:method render_full_submission_form {
@@ -4033,6 +4166,20 @@
set do_stream [expr {[llength [$items children]] > 100}]
set HTML [:render_print_button]
+
+ if {!$as_student} {
+ #
+ # When rendering for teachers, we offer the possibility for to
+ # sort, filter and export submissions.
+ #
+ append HTML [:render_filter_bar \
+ -examWf $examWf \
+ -filter_form_ids $filter_form_ids \
+ -revision_id $revision_id \
+ -filter_submission_id $filter_submission_id \
+ -orderby $orderby]
+ }
+
::xo::cc set_parameter template_file view-plain-master
::xo::cc set_parameter MenuBar 0
@@ -4535,12 +4682,66 @@
-type [ad_decode $att achieved real achievable real grade integer dictionary] \
$att
+ #
+ # XLS export requires OOXML
+ #
+ # See https://fossil.sowaswie.de/ooxml/index
+ #
+ if {$format eq "xls" &&
+ [::namespace which ::ooxml::xl_write] eq ""} {
+ set format csv
+ }
+
if {$reply} {
switch $format {
html {
ns_return 200 "text/html; charset=utf-8" [$t asHTML]
ad_script_abort
}
+ xls {
+ set s [::ooxml::xl_write new]
+ set sheet [$s worksheet {1}]
+ set decimal [lc_get "decimal_point"]
+ set doublestyle [$s style -numfmt [$s numberformat -decimal -format "#${decimal}##"]]
+ set stringstyle [$s style -numfmt [$s numberformat -string]]
+ set datestyle [$s style -numfmt [$s numberformat -date]]
+ set cellformat {}
+
+ #iterate cols of table
+ $s row $sheet
+ set displayColumns [lmap column [${t}::__columns children] {
+ if {[$column exists no_csv]} continue
+ if {[$column istype ::xo::Table::BulkAction]} continue
+ if {[$column istype ::xo::Table::HiddenField]} continue
+ set column
+ }]
+ foreach column $displayColumns {
+ if {[$column name] in {"achieved" "achievable" "percentage"}} {
+ lappend cellformat double
+ } else {
+ lappend cellformat string
+ }
+ set label [$column label]
+ if {[regexp {^#([a-zA-Z0-9_:-]+\.[a-zA-Z0-9_:-]+)#$} $label _ message_key]} {
+ set label [_ $message_key]
+ }
+ set value [string map {\" \\\" \n \r} $label]
+ $s cell $sheet $value
+ }
+ #iterate row content
+ foreach row [$t children] {
+ $s row $sheet
+ set i 0
+ foreach column $displayColumns {
+ set value [string map {\" \\\" \n \r} [$row set [$column set name]]]
+ set format [lindex $cellformat $i]
+ $s cell $sheet $value -style [set [set format]style]
+ incr i
+ }
+ }
+ $s write results.xlsx
+ ad_script_abort
+ }
default {set result [$t write_csv]}
}
} else {