11import Handsontable from "handsontable" ;
2- import 'handsontable/dist/handsontable.full.css' ;
2+ // import 'handsontable/dist/handsontable.full.css';
33import initSqlJs from "sql.js/dist/sql-wasm.js" ;
44import RunestoneBase from "../../common/js/runestonebase.js" ;
55
@@ -13,8 +13,8 @@ import "codemirror/mode/javascript/javascript.js";
1313import "codemirror/mode/sql/sql.js" ;
1414import "codemirror/mode/clike/clike.js" ;
1515import "codemirror/mode/octave/octave.js" ;
16- import "./../css/activecode.css" ;
17- import "codemirror/lib/codemirror.css" ;
16+ // import "./../../activecode /css/activecode.css";
17+ // import "codemirror/lib/codemirror.css";
1818
1919// copied from activecode
2020// Used by Skulpt.
@@ -24,9 +24,14 @@ window.vegaEmbed = embed;
2424
2525var allDburls = { } ;
2626
27+ export var hpList ;
28+ // Dictionary that contains all instances of horizontal Parsons problem objects
29+ if ( hpList === undefined ) hpList = { } ;
30+
2731export default class SQLHParons extends RunestoneBase {
2832 constructor ( opts ) {
2933 super ( opts ) ;
34+ console . log ( 'hparsons sql constructor' )
3035 // copied from activecode
3136 var suffStart ;
3237 var orig = $ ( opts . orig ) . find ( "textarea" ) [ 0 ] ;
@@ -182,6 +187,155 @@ export default class SQLHParons extends RunestoneBase {
182187 }
183188 } ) ;
184189 }
190+
191+ // copied from activecode
192+ async runButtonHandler ( ) {
193+ // Disable the run button until the run is finished.
194+ this . runButton . disabled = true ;
195+ try {
196+ await this . runProg ( ) ;
197+ } catch ( e ) {
198+ console . log ( `there was an error ${ e } running the code` ) ;
199+ }
200+ if ( this . logResults ) {
201+ this . logCurrentAnswer ( ) ;
202+ }
203+ this . renderFeedback ( ) ;
204+ // The run is finished; re-enable the button.
205+ this . runButton . disabled = false ;
206+ }
207+
208+ // copied from activecode
209+ addHistoryButton ( ctrlDiv ) {
210+ let butt = document . createElement ( "button" ) ;
211+ $ ( butt ) . text ( $ . i18n ( "msg_activecode_load_history" ) ) ;
212+ $ ( butt ) . addClass ( "btn btn-default" ) ;
213+ $ ( butt ) . attr ( "type" , "button" ) ;
214+ ctrlDiv . appendChild ( butt ) ;
215+ this . histButton = butt ;
216+ $ ( butt ) . click ( this . addHistoryScrubber . bind ( this ) ) ;
217+ if ( this . graderactive ) {
218+ this . addHistoryScrubber ( true ) ;
219+ }
220+ }
221+
222+ // copied from activecode
223+ // _`addHistoryScrubber`
224+ // ---------------------
225+ // Activecode -- If the code has not changed wrt the scrubber position value then don't save the code or reposition the scrubber
226+ // -- still call runlog, but add a parameter to not save the code
227+ // add an initial load history button
228+ // if there is no edit then there is no append to_save (True/False)
229+ async addHistoryScrubber ( pos_last ) {
230+ let response ;
231+ var reqData = {
232+ acid : this . divid ,
233+ } ;
234+ if ( this . sid !== undefined ) {
235+ reqData [ "sid" ] = this . sid ;
236+ }
237+ console . log ( "before get hist" ) ;
238+ if (
239+ eBookConfig . practice_mode ||
240+ ( this . isTimed && ! this . assessmentTaken )
241+ ) {
242+ // If this is timed and already taken we should restore history info
243+ this . renderScrubber ( ) ;
244+ } else {
245+ let request = new Request ( `${ eBookConfig . new_server_prefix } /assessment/gethist` , {
246+ method : "POST" ,
247+ headers : this . jsonHeaders ,
248+ body : JSON . stringify ( reqData ) ,
249+ } ) ;
250+ try {
251+ response = await fetch ( request ) ;
252+ let data = await response . json ( ) ;
253+ if ( ! response . ok ) {
254+ throw new Error ( `Failed to get the history data: ${ data . detail } ` ) ;
255+ }
256+ data = data . detail ;
257+ if ( data . history !== undefined ) {
258+ this . history = this . history . concat ( data . history ) ;
259+ for ( let t in data . timestamps ) {
260+ this . timestamps . push (
261+ new Date ( data . timestamps [ t ] ) . toLocaleString ( )
262+ ) ;
263+ }
264+ }
265+ } catch ( e ) {
266+ console . log ( `unable to fetch history: ${ e } ` ) ;
267+ }
268+ this . renderScrubber ( pos_last ) ;
269+ }
270+ return "success" ;
271+ }
272+
273+ renderScrubber ( pos_last ) {
274+ console . log ( "making a new scrubber" ) ;
275+ var scrubberDiv = document . createElement ( "div" ) ;
276+ $ ( scrubberDiv ) . css ( "display" , "inline-block" ) ;
277+ $ ( scrubberDiv ) . css ( "margin-left" , "10px" ) ;
278+ $ ( scrubberDiv ) . css ( "margin-right" , "10px" ) ;
279+ $ ( scrubberDiv ) . css ( {
280+ "min-width" : "200px" ,
281+ "max-width" : "300px" ,
282+ } ) ;
283+ var scrubber = document . createElement ( "div" ) ;
284+ this . timestampP = document . createElement ( "span" ) ;
285+ this . slideit = function ( ) {
286+ this . editor . setValue ( this . history [ $ ( scrubber ) . slider ( "value" ) ] ) ;
287+ var curVal = this . timestamps [ $ ( scrubber ) . slider ( "value" ) ] ;
288+ let pos = $ ( scrubber ) . slider ( "value" ) ;
289+ let outOf = this . history . length ;
290+ $ ( this . timestampP ) . text ( `${ curVal } - ${ pos + 1 } of ${ outOf } ` ) ;
291+ this . logBookEvent ( {
292+ event : "activecode" ,
293+ act : "slide:" + curVal ,
294+ div_id : this . divid ,
295+ } ) ;
296+ } ;
297+ $ ( scrubber ) . slider ( {
298+ max : this . history . length - 1 ,
299+ value : this . history . length - 1 ,
300+ } ) ;
301+ $ ( scrubber ) . css ( "margin" , "10px" ) ;
302+ $ ( scrubber ) . on ( "slide" , this . slideit . bind ( this ) ) ;
303+ $ ( scrubber ) . on ( "slidechange" , this . slideit . bind ( this ) ) ;
304+ scrubberDiv . appendChild ( scrubber ) ;
305+ scrubberDiv . appendChild ( this . timestampP ) ;
306+ // If there is a deadline set then position the scrubber at the last submission
307+ // prior to the deadline
308+ if ( this . deadline ) {
309+ let i = 0 ;
310+ let done = false ;
311+ while ( i < this . history . length && ! done ) {
312+ if ( new Date ( this . timestamps [ i ] ) > this . deadline ) {
313+ done = true ;
314+ } else {
315+ i += 1 ;
316+ }
317+ }
318+ i = i - 1 ;
319+ scrubber . value = Math . max ( i , 0 ) ;
320+ this . editor . setValue ( this . history [ scrubber . value ] ) ;
321+ $ ( scrubber ) . slider ( "value" , scrubber . value ) ;
322+ } else if ( pos_last ) {
323+ scrubber . value = this . history . length - 1 ;
324+ this . editor . setValue ( this . history [ scrubber . value ] ) ;
325+ } else {
326+ scrubber . value = 0 ;
327+ }
328+ let pos = $ ( scrubber ) . slider ( "value" ) ;
329+ let outOf = this . history . length ;
330+ let ts = this . timestamps [ $ ( scrubber ) . slider ( "value" ) ] ;
331+ $ ( this . timestampP ) . text ( `${ ts } - ${ pos + 1 } of ${ outOf } ` ) ;
332+ $ ( this . histButton ) . remove ( ) ;
333+ this . histButton = null ;
334+ this . historyScrubber = scrubber ;
335+ $ ( scrubberDiv ) . insertAfter ( this . runButton ) ;
336+ } // end definition of helper
337+
338+
185339 // copied from activecode
186340 createEditor ( index ) {
187341 this . outerDiv = document . createElement ( "div" ) ;
@@ -344,7 +498,8 @@ export default class SQLHParons extends RunestoneBase {
344498 $ ( butt ) . addClass ( "btn btn-success run-button" ) ;
345499 ctrlDiv . appendChild ( butt ) ;
346500 this . runButton = butt ;
347- console . log ( "adding click function for run" ) ;
501+ console . log ( butt ) ;
502+ console . log ( "adding click function for run in sql" ) ;
348503 this . runButton . onclick = this . runButtonHandler . bind ( this ) ;
349504 $ ( butt ) . attr ( "type" , "button" ) ;
350505
@@ -527,12 +682,41 @@ export default class SQLHParons extends RunestoneBase {
527682 return Promise . resolve ( "done" ) ;
528683 }
529684
685+ // copied from anctivecode
686+ async buildProg ( useSuffix ) {
687+ // assemble code from prefix, suffix, and editor for running.
688+ var pretext ;
689+ var prog = this . editor . getValue ( ) + "\n" ;
690+ if ( this . prefix ) {
691+ prog = this . prefix + prog ;
692+ }
693+ this . pretext = "" ;
694+ this . pretextLines = 0 ;
695+ this . progLines = prog . match ( / \n / g) . length + 1 ;
696+ if ( this . includes ) {
697+ // iterate over the includes, in-order prepending to prog
698+ pretext = "" ;
699+ for ( var x = 0 ; x < this . includes . length ; x ++ ) {
700+ let iCode = await this . getIncludedCode ( this . includes [ x ] ) ;
701+ pretext = pretext + iCode + "\n" ;
702+ }
703+ this . pretext = pretext ;
704+ if ( this . pretext ) {
705+ this . pretextLines = ( this . pretext . match ( / \n / g) || "" ) . length ;
706+ }
707+ prog = pretext + prog ;
708+ }
709+ if ( useSuffix && this . suffix ) {
710+ prog = prog + this . suffix ;
711+ }
712+ return Promise . resolve ( prog ) ;
713+ }
530714 async logCurrentAnswer ( sid ) {
531715 let data = {
532716 div_id : this . divid ,
533717 code : this . editor . getValue ( ) ,
534718 language : this . language ,
535- errinfo : this . results [ this . results . length - 1 ] . status ,
719+ // errinfo: this.results[this.results.length - 1].status,
536720 to_save : this . saveCode ,
537721 prefix : this . pretext ,
538722 suffix : this . suffix ,
@@ -679,7 +863,7 @@ function createTable(tableData, container, maxHeight) {
679863== execute our code on them ==
680864=================================*/
681865$ ( document ) . bind ( "runestone:login-complete" , function ( ) {
682- $ ( "[data-component=sqlhparsons ]" ) . each ( function ( ) {
866+ $ ( "[data-component=hparsons ]" ) . each ( function ( ) {
683867 if ( $ ( this ) . closest ( "[data-component=timedAssessment]" ) . length == 0 ) {
684868 // If this element exists within a timed component, don't render it here
685869 // try {
0 commit comments