@@ -11,7 +11,10 @@ const buttonIDs = ['#regrade-selected', '#delete-selected', '#download-selected'
1111let tweaks = [ ] ;
1212let currentPage = 0 ;
1313$ ( document ) . ready ( function ( ) {
14- var submission_info = { }
14+ var submission_info = { } ;
15+ var selectedStudentCids = [ ] ;
16+ var selectedSubmissions = [ ] ;
17+ var submissions_to_cud = { } ; // Build dynamically from server data
1518 const EditTweakButton = ( totalSum ) => {
1619 if ( totalSum == null ) {
1720 return `
@@ -70,7 +73,7 @@ $(document).ready(function() {
7073 $ ( document ) . ready ( function ( ) {
7174 $ ( '.modal' ) . modal ( ) ;
7275
73- $ ( '.score-details' ) . on ( 'click' , function ( ) {
76+ $ ( document ) . on ( 'click' , '.score-details ', function ( ) {
7477 // Get the email
7578 const course_user_datum_id = $ ( this ) . data ( 'cuid' ) ;
7679 const email = $ ( this ) . data ( 'email' ) ;
@@ -105,9 +108,9 @@ $(document).ready(function() {
105108 tweaks = [ ] ;
106109
107110 const submissions_body = data . submissions . map ( ( submission ) => {
108- const Tweak = new AutolabComponent ( `tweak-value-${ submission . id } ` , { amount : null } ) ;
111+ const Tweak = new AutolabComponent ( `tweak-value-${ submission . id } ` , { amount : null } ) ;
109112 Tweak . template = function ( ) {
110- return EditTweakButton ( this . state . amount ) ;
113+ return EditTweakButton ( this . state . amount ) ;
111114 }
112115 tweaks . push ( { tweak : Tweak , submission_id : submission . id , submission} ) ;
113116
@@ -118,21 +121,21 @@ $(document).ready(function() {
118121
119122 // Convert to human readable date with timezone
120123 const human_readable_created_at =
121- moment ( submission . created_at ) . format ( 'MMM Do YY, h:mma z UTC Z' ) ;
124+ moment ( submission . created_at ) . format ( 'MMM Do YY, h:mma z UTC Z' ) ;
122125
123126 const view_button = submission . filename ?
124- `<div class="submissions-center-icons">
127+ `<div class="submissions-center-icons">
125128 <a href="submissions/${ submission . id } /view"
126129 title="View the file for this submission"
127130 class="btn small">
128131 <i class='material-icons'>zoom_in</i>
129132 </a>
130133 <p>View Source</p>
131134 </div>`
132- : "None" ;
135+ : "None" ;
133136
134137 const download_button =
135- / t e x t / . test ( submission . detected_mime_type ) ?
138+ / t e x t / . test ( submission . detected_mime_type ) ?
136139 `<div class="submissions-center-icons">
137140 <a href="submissions/${ submission . id } /download?forceMime=text/plain"
138141 title="Download as text/plain"
@@ -160,16 +163,15 @@ $(document).ready(function() {
160163 <td class="submissions-td">
161164 ${ submission . total }
162165 </td>
163- ${ submission . problems .
164- map ( ( problem ) =>
165- `<td class="submissions-td">
166+ ${ submission . problems . map ( ( problem ) =>
167+ `<td class="submissions-td">
166168 ${ data . scores [ submission . id ] ?. [ problem . id ] ?. [ 'score' ] !== undefined
167- ? `<a href="viewFeedback?submission_id=${ submission . id } &feedback=${ problem . id } ">
169+ ? `<a href="viewFeedback?submission_id=${ submission . id } &feedback=${ problem . id } ">
168170 ${ data . scores [ submission . id ] [ problem . id ] [ 'score' ] . toFixed ( 1 ) }
169171 </a>`
170- : "-" }
172+ : "-" }
171173 </td>`
172- ) . join ( '' ) }
174+ ) . join ( '' ) }
173175 <td class="submissions-td">
174176 ${ submission . late_penalty }
175177 </td>
@@ -185,7 +187,7 @@ $(document).ready(function() {
185187 } ) . join ( '' ) ;
186188
187189 const submissions_table =
188- ` <p>Click on non-autograded problem scores to edit or leave a comment. </p>
190+ ` <p>Click on non-autograded problem scores to edit or leave a comment. </p>
189191 <table class="prettyBorder" id="score-details-table">
190192 <thead>
191193 <tr>
@@ -211,10 +213,10 @@ $(document).ready(function() {
211213 "order" : [ [ 0 , "desc" ] ] ,
212214 "paging" : false ,
213215 "info" : false ,
214- "searching" : false , } ) ;
216+ "searching" : false ,
217+ } ) ;
215218
216219 return data . submissions ;
217-
218220 } ) . then ( ( submissions ) => {
219221 $ ( '.tweak-button' ) . on ( 'click' , selectTweak ( submissions ) ) ;
220222 } ) . catch ( ( err ) => {
@@ -229,48 +231,94 @@ $(document).ready(function() {
229231 } ) ;
230232 } ) ;
231233
232- var selectedStudentCids = [ ] ;
233- var selectedSubmissions = [ ] ;
234-
234+ // Initialize DataTable with server-side processing
235235 var table = $ ( '#submissions' ) . DataTable ( {
236- 'dom' : 'f<"selected-buttons">rtip' , // show buttons, search, table
237- 'paging' : true ,
238- 'createdRow' : completeRow ,
239- 'sPaginationType' : 'full_numbers' ,
240- 'pageLength' : 100 ,
241- 'info' : true ,
242- 'deferRender' : true ,
236+ dom : 'f<"selected-buttons">rtip' ,
237+ processing : true ,
238+ serverSide : true ,
239+ ajax : {
240+ url : window . location . pathname + '.json' ,
241+ type : 'GET' ,
242+ dataSrc : function ( json ) {
243+ json . data . forEach ( row => {
244+ submissions_to_cud [ row [ 7 ] ] = row [ 8 ] ;
245+ } ) ;
246+ return json . data ;
247+ } ,
248+ error : function ( xhr , error , code ) {
249+ console . error ( 'DataTables error:' , error , code ) ;
250+ }
251+ } ,
252+ columns : [
253+ {
254+ data : null , orderable : false , className : 'submissions-td submissions-checkbox' ,
255+ render : function ( data , type , row , meta ) {
256+ return `<div><label class="submissions-cbox-label"><input class="cbox" type="checkbox" id="cbox-${ row [ 7 ] } "><span></span></label></div>` ;
257+ }
258+ } ,
259+ {
260+ data : 1 , className : 'submissions-td' ,
261+ render : function ( data , type , row , meta ) {
262+ var excusedLabel = data . excused ? '<a class="submissions-excused-label" title="Click to unexcuse this student">EXCUSED</a>' : '' ;
263+ return `<div class="submissions-name">${ data . name || '' } ${ excusedLabel } </div>${ data . email } ` ;
264+ }
265+ } ,
266+ { data : 2 , className : 'submissions-td' } ,
267+ {
268+ data : 3 , className : 'submissions-td' ,
269+ render : function ( data , type , row , meta ) {
270+ var score = data . score != null ? data . score : '-' ;
271+ return `<div class="submissions-score-align"><div class="score-num">${ score } </div><div class="score-icon"><a class="modal-trigger score-details" data-email="${ data . email } " data-cuid="${ data . cud_id } "><i class="material-icons submissions-score-icon">zoom_in</i></a></div></div>` ;
272+ }
273+ } ,
274+ { data : 4 , className : 'submissions-td' , render : d => `<span class="moment-date-time">${ d } </span>` } ,
275+ {
276+ data : 5 ,
277+ orderable : false ,
278+ className : 'submissions-td' ,
279+ render : d => d . has_file ? `<div class="submissions-center-icons"><a href="submissions/${ d . submission_id } /view" title="View the file for this submission" class="btn small"><i class='material-icons'>zoom_in</i></a><p>View File</p></div>` : 'None'
280+ } ,
281+ {
282+ data : 6 , orderable : false , className : 'submissions-td exclude-click' , render : function ( data , row ) {
283+ var regradeBtn = data . is_autograded ? `<div class="submissions-center-icons"><a href="regradeBatch?submission_ids[]=${ data . submission_id } " data-method="post" title="Regrade this submission" class="btn small"><i class='material-icons'>autorenew</i></a><p>Regrade</p></div>` : '' ;
284+ return `${ regradeBtn } <div class="submissions-center-icons"><a href="submissions/${ data . submission_id } /destroyConfirm" title="Destroy this submission forever" class="btn small"><i class='material-icons'>delete_outline</i></a><p>Delete</p></div>` ;
285+ }
286+ } ,
287+ { data : 7 , visible : false } ,
288+ { data : 8 , visible : false }
289+ ] ,
290+ pageLength : 100 ,
291+ lengthMenu : [ [ 25 , 50 , 100 , 200 ] , [ 25 , 50 , 100 , 200 ] ] ,
292+ order : [ [ 4 , 'desc' ] ] ,
293+ createdRow : function ( row , data ) {
294+ var submissionId = data [ 7 ] ;
295+ $ ( row ) . attr ( 'id' , 'row-' + submissionId ) . attr ( 'data-submission-id' , submissionId ) . addClass ( 'submission-row' ) ;
296+ } ,
297+ drawCallback : function ( ) {
298+ $ ( '#submissions tbody .cbox' ) . each ( function ( ) {
299+ var submissionId = parseInt ( $ ( this ) . attr ( 'id' ) . replace ( 'cbox-' , '' ) , 10 ) ;
300+ $ ( this ) . prop ( 'checked' , selectedSubmissions . includes ( submissionId ) ) ;
301+ if ( selectedSubmissions . includes ( submissionId ) ) $ ( this ) . closest ( 'tr' ) . addClass ( 'selected' ) ;
302+ } ) ;
303+ updateSelectAllCheckbox ( ) ;
304+ }
243305 } ) ;
244306
245- // Check if the table is empty
246- if ( table . data ( ) . count ( ) === 0 ) {
247- $ ( '#submissions' ) . closest ( '.dataTables_wrapper' ) . hide ( ) ; // Hide the table and its controls
248- $ ( '#no-data-message' ) . show ( ) ; // Optionally show a custom message
249- } else {
250- $ ( '#no-data-message' ) . hide ( ) ; // Hide custom message when there is data
251- }
252-
253- function completeRow ( row , data , index ) {
254- var submission = additional_data [ index ] ;
255- $ ( row ) . attr ( 'data-submission-id' , submission [ 'submission-id' ] ) ;
256- }
257-
258- $ ( 'thead' ) . on ( 'click' , function ( e ) {
259- if ( currentPage < 0 ) {
260- currentPage = 0
261- }
262- if ( currentPage > table . page . info ( ) . pages ) {
263- currentPage = table . page . info ( ) . pages - 1
264- }
265- table . page ( currentPage ) . draw ( false ) ;
266- } )
267307
268308 // Listen for select-all checkbox click
269309 $ ( '#cbox-select-all' ) . on ( 'click' , async function ( e ) {
270310 var selectAll = $ ( this ) . is ( ':checked' ) ;
271311 await toggleAllRows ( selectAll ) ;
272312 } ) ;
273313
314+ function updateSelectAllCheckbox ( ) {
315+ var allChecked = true , anyChecked = false ;
316+ $ ( '#submissions tbody .cbox' ) . each ( function ( ) {
317+ if ( $ ( this ) . prop ( 'checked' ) ) anyChecked = true ; else allChecked = false ;
318+ } ) ;
319+ $ ( '#cbox-select-all' ) . prop ( 'checked' , allChecked && anyChecked ) ;
320+ }
321+
274322 // Function to toggle all checkboxes
275323 function toggleAllRows ( selectAll ) {
276324 $ ( '#submissions tbody .cbox' ) . each ( function ( ) {
@@ -297,21 +345,17 @@ $(document).ready(function() {
297345 var downloadHTML = $ ( '#download-batch-html' ) . html ( ) ;
298346 var excuseHTML = $ ( '#excuse-batch-html' ) . html ( ) ;
299347 $ ( 'div.selected-buttons' ) . html ( `<div id='selected-buttons'>${ regradeHTML } ${ deleteHTML } ${ downloadHTML } ${ excuseHTML } </div>` ) ;
300-
301- // add ids to each selected button
302348 $ ( '#selected-buttons > a' ) . each ( function ( ) {
303349 let idText = this . title . split ( ' ' ) [ 0 ] . toLowerCase ( ) + '-selected' ;
304350 this . setAttribute ( 'id' , idText ) ;
305351 } ) ;
306-
307352 if ( ! is_autograded ) {
308353 $ ( '#regrade-selected' ) . hide ( ) ;
309354 $ ( '#regrade-all-html' ) . hide ( ) ;
310355 }
311356
312- // base URLs for selected buttons
313357 var baseURLs = { } ;
314- buttonIDs . forEach ( function ( id ) {
358+ buttonIDs . forEach ( function ( id ) {
315359 baseURLs [ id ] = $ ( id ) . prop ( 'href' ) ;
316360 } ) ;
317361
@@ -374,7 +418,6 @@ $(document).ready(function() {
374418 }
375419 } ) ;
376420 } ) ;
377-
378421 function changeButtonStates ( state ) {
379422 buttonIDs . forEach ( ( id ) => {
380423 const button = $ ( id ) ;
@@ -396,14 +439,13 @@ $(document).ready(function() {
396439 return ;
397440 }
398441 $ ( document ) . off ( "click" , id ) . on ( "click" , id , function ( event ) {
399- console . log ( `${ id } button clicked` ) ;
400442 event . preventDefault ( ) ;
401443 if ( selectedSubmissions . length === 0 ) {
402444 alert ( "No submissions selected." ) ;
403445 return ;
404446 }
405447 const endpoint = manage_submissions_endpoints [ id . replace ( "#" , "" ) ] ;
406- const requestData = { submission_ids : selectedSubmissions } ;
448+ const requestData = { submission_ids : selectedSubmissions } ;
407449 if ( id === "#delete-selected" ) {
408450 if ( ! confirm ( "Deleting will delete all checked submissions and cannot be undone. Are you sure you want to delete these submissions?" ) ) {
409451 return ;
@@ -457,6 +499,8 @@ $(document).ready(function() {
457499
458500 // SELECTING STUDENT CHECKBOXES
459501 function toggleRow ( submissionId , forceSelect = null ) {
502+ console . log ( 'toggleRow called:' , submissionId , 'forceSelect:' , forceSelect ) ;
503+ console . log ( 'selectedSubmissions before:' , [ ...selectedSubmissions ] ) ;
460504 var selectedCid = submissions_to_cud [ submissionId ] ;
461505 const isSelected = selectedSubmissions . includes ( submissionId ) ;
462506 const shouldSelect = forceSelect !== null ? forceSelect : ! isSelected ;
@@ -489,6 +533,8 @@ $(document).ready(function() {
489533 $ ( '#cbox-select-all' ) . prop ( 'checked' , numericSelectedSubmissions . length === $ ( '#submissions tbody .cbox' ) . length ) ;
490534 updateSelectedCount ( numericSelectedSubmissions ) ;
491535 changeButtonStates ( disableButtons ) ;
536+ console . log ( 'selectedSubmissions after:' , [ ...selectedSubmissions ] ) ;
537+ console . log ( 'Checkbox state:' , $ ( '#cbox-' + submissionId ) . prop ( 'checked' ) ) ;
492538 }
493539
494540 $ ( '#submissions' ) . on ( 'click' , '.exclude-click i' , function ( e ) {
0 commit comments